[sysprof/wip/chergert/path-resolver] podman: include image layers in overlay



commit e62d6a07a2fcdf194400e171b64a1f86239a07f6
Author: Christian Hergert <chergert redhat com>
Date:   Tue Sep 21 15:36:18 2021 -0700

    podman: include image layers in overlay
    
    We want the image layers so we can find the files in the base image
    correctly.

 src/libsysprof/sysprof-podman.c | 123 ++++++++++++++++++++++++++++++++++------
 1 file changed, 105 insertions(+), 18 deletions(-)
---
diff --git a/src/libsysprof/sysprof-podman.c b/src/libsysprof/sysprof-podman.c
index 2832f79..880bc6c 100644
--- a/src/libsysprof/sysprof-podman.c
+++ b/src/libsysprof/sysprof-podman.c
@@ -74,6 +74,7 @@ struct _SysprofPodman
 {
   JsonParser *containers_parser;
   JsonParser *layers_parser;
+  JsonParser *images_parser;
 };
 
 void
@@ -81,6 +82,7 @@ sysprof_podman_free (SysprofPodman *self)
 {
   g_clear_object (&self->containers_parser);
   g_clear_object (&self->layers_parser);
+  g_clear_object (&self->images_parser);
   g_slice_free (SysprofPodman, self);
 }
 
@@ -116,6 +118,22 @@ load_layers (SysprofPodman *self)
   json_parser_load_from_file (self->layers_parser, path, NULL);
 }
 
+static void
+load_images (SysprofPodman *self)
+{
+  g_autofree char *path = NULL;
+
+  g_assert (self != NULL);
+
+  path = g_build_filename (g_get_user_data_dir (),
+                           "containers",
+                           "storage",
+                           "overlay-images",
+                           "images.json",
+                           NULL);
+  json_parser_load_from_file (self->images_parser, path, NULL);
+}
+
 SysprofPodman *
 sysprof_podman_snapshot_current_user (void)
 {
@@ -124,17 +142,57 @@ sysprof_podman_snapshot_current_user (void)
   self = g_slice_new0 (SysprofPodman);
   self->containers_parser = json_parser_new ();
   self->layers_parser = json_parser_new ();
+  self->images_parser = json_parser_new ();
 
   load_containers (self);
   load_layers (self);
+  load_images (self);
 
   return self;
 }
 
+static const char *
+find_image_layer (JsonParser *parser,
+                  const char *image)
+{
+  JsonNode *root;
+  JsonArray *ar;
+  guint n_items;
+
+  g_assert (JSON_IS_PARSER (parser));
+  g_assert (image != NULL);
+
+  if (!(root = json_parser_get_root (parser)) ||
+      !JSON_NODE_HOLDS_ARRAY (root) ||
+      !(ar = json_node_get_array (root)))
+    return NULL;
+
+  n_items = json_array_get_length (ar);
+
+  for (guint i = 0; i < n_items; i++)
+    {
+      JsonObject *item = json_array_get_object_element (ar, i);
+      const char *id;
+      const char *layer;
+
+      if (item == NULL ||
+          !json_object_has_member (item, "id") ||
+          !json_object_has_member (item, "layer") ||
+          !(id = json_object_get_string_member (item, "id")) ||
+          strcmp (id, image) != 0 ||
+          !(layer = json_object_get_string_member (item, "layer")))
+        continue;
+
+      return layer;
+    }
+
+  return NULL;
+}
+
 static const char *
 find_parent_layer (JsonParser *parser,
                    const char *layer,
-                   GPtrArray  *seen)
+                   GHashTable *seen)
 {
   JsonNode *root;
   JsonArray *ar;
@@ -165,12 +223,8 @@ find_parent_layer (JsonParser *parser,
           !(parent = json_object_get_string_member (item, "parent")))
         continue;
 
-      /* Avoid cycles by checking if we've seen this parent */
-      for (guint j = 0; j < seen->len; j++)
-        {
-          if (strcmp (parent, g_ptr_array_index (seen, j)) == 0)
-            return NULL;
-        }
+      if (g_hash_table_contains (seen, parent))
+        return NULL;
 
       return parent;
     }
@@ -178,14 +232,35 @@ find_parent_layer (JsonParser *parser,
   return NULL;
 }
 
+static char *
+get_layer_dir (const char *layer)
+{
+  /* We don't use XDG data dir because this might be in a container
+   * or flatpak environment that doesn't match. And generally, it's
+   * always .local.
+   */
+  return g_build_filename (g_get_home_dir (),
+                           ".local",
+                           "share",
+                           "containers",
+                           "storage",
+                           "overlay",
+                           layer,
+                           "diff",
+                           NULL);
+}
+
 gchar **
 sysprof_podman_get_layers (SysprofPodman *self,
                            const char    *container)
 {
   const char *layer = NULL;
-  GPtrArray *layers;
+  const char *image = NULL;
+  GHashTable *layers;
   JsonNode *root;
   JsonArray *ar;
+  const char **keys;
+  char **ret;
   guint n_items;
 
   g_return_val_if_fail (self != NULL, NULL);
@@ -214,18 +289,30 @@ sysprof_podman_get_layers (SysprofPodman *self,
         continue;
 
       layer = item_layer;
+      image = json_object_get_string_member (item, "image");
       break;
     }
 
-  /* Now we need to try to locate the layer and all of the parents
-   * within the layers.json so that we populate from the most recent
-   * layer to those beneath it.
-   */
-  layers = g_ptr_array_new ();
-  g_ptr_array_add (layers, g_strdup (layer));
-  while ((layer = find_parent_layer (self->layers_parser, layer, layers)))
-    g_ptr_array_add (layers, g_strdup (layer));
-  g_ptr_array_add (layers, NULL);
+  layers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  /* Add all our known layers starting from current layer */
+  do
+    g_hash_table_add (layers, get_layer_dir (layer));
+  while ((layer = find_parent_layer (self->layers_parser, layer, layers)));
+
+  /* If an image was specified, add its layer */
+  if ((layer = find_image_layer (self->images_parser, image)))
+    {
+      do
+        g_hash_table_add (layers, get_layer_dir (layer));
+      while ((layer = find_parent_layer (self->layers_parser, layer, layers)));
+    }
+
+  keys = (const char **)g_hash_table_get_keys_as_array (layers, NULL);
+  ret = g_strdupv ((char **)keys);
+
+  g_hash_table_unref (layers);
+  g_free (keys);
 
-  return (char **)g_ptr_array_free (layers, FALSE);
+  return ret;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]