Merge pull request #25564 from poettering/dissect-discover

systemd-dissect: add simple "--discover" command
This commit is contained in:
Yu Watanabe
2022-12-08 12:29:07 +09:00
committed by GitHub
5 changed files with 112 additions and 7 deletions

View File

@@ -230,6 +230,17 @@
operation begins.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--discover</option></term>
<listitem><para>Show a list of DDIs in well known directories. This will show machine, portable
service and system extension disk images in the usual directories
<filename>/usr/lib/machines/</filename>, <filename>/usr/lib/portables/</filename>,
<filename>/usr/lib/extensions/</filename>, <filename>/var/lib/machines/</filename>,
<filename>/var/lib/portables/</filename>, <filename>/var/lib/extensions/</filename> and so
on.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@@ -17,6 +17,7 @@
#include "copy.h"
#include "device-util.h"
#include "devnum-util.h"
#include "discover-image.h"
#include "dissect-image.h"
#include "env-util.h"
#include "escape.h"
@@ -56,6 +57,7 @@ static enum {
ACTION_WITH,
ACTION_COPY_FROM,
ACTION_COPY_TO,
ACTION_DISCOVER,
} arg_action = ACTION_DISSECT;
static const char *arg_image = NULL;
static const char *arg_path = NULL;
@@ -128,6 +130,7 @@ static int help(void) {
" --with Mount, run command, unmount\n"
" -x --copy-from Copy files from image to host\n"
" -a --copy-to Copy files from host to image\n"
" --discover Discover DDIs in well known directories\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -199,6 +202,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_RMDIR,
ARG_JSON,
ARG_MTREE,
ARG_DISCOVER,
};
static const struct option options[] = {
@@ -223,6 +227,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "copy-from", no_argument, NULL, 'x' },
{ "copy-to", no_argument, NULL, 'a' },
{ "json", required_argument, NULL, ARG_JSON },
{ "discover", no_argument, NULL, ARG_DISCOVER },
{}
};
@@ -400,6 +405,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_DISCOVER:
arg_action = ACTION_DISCOVER;
break;
case '?':
return -EINVAL;
@@ -491,6 +500,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ACTION_DISCOVER:
if (optind != argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected no argument.");
break;
default:
assert_not_reached();
}
@@ -1325,6 +1341,54 @@ static int action_with(DissectedImage *m, LoopDevice *d) {
return rcode;
}
static int action_discover(void) {
_cleanup_(hashmap_freep) Hashmap *images = NULL;
_cleanup_(table_unrefp) Table *t = NULL;
Image *img;
int r;
images = hashmap_new(&image_hash_ops);
if (!images)
return log_oom();
for (ImageClass cl = 0; cl < _IMAGE_CLASS_MAX; cl++) {
r = image_discover(cl, NULL, images);
if (r < 0)
return log_error_errno(r, "Failed to discover images: %m");
}
if ((arg_json_format_flags & JSON_FORMAT_OFF) && hashmap_isempty(images)) {
log_info("No images found.");
return 0;
}
t = table_new("name", "type", "class", "ro", "path", "time", "usage");
if (!t)
return log_oom();
HASHMAP_FOREACH(img, images) {
if (!IN_SET(img->type, IMAGE_RAW, IMAGE_BLOCK))
continue;
r = table_add_many(
t,
TABLE_STRING, img->name,
TABLE_STRING, image_type_to_string(img->type),
TABLE_STRING, image_class_to_string(img->class),
TABLE_BOOLEAN, img->read_only,
TABLE_PATH, img->path,
TABLE_TIMESTAMP, img->mtime != 0 ? img->mtime : img->crtime,
TABLE_SIZE, img->usage);
if (r < 0)
return table_log_add_error(r);
}
(void) table_set_sort(t, (size_t) 0);
return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
}
static int run(int argc, char *argv[]) {
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
@@ -1338,6 +1402,8 @@ static int run(int argc, char *argv[]) {
if (arg_action == ACTION_UMOUNT)
return action_umount(arg_path);
if (arg_action == ACTION_DISCOVER)
return action_discover();
r = verity_settings_load(
&arg_verity_settings,

View File

@@ -123,6 +123,7 @@ static char *image_roothash_path(Image *image) {
static int image_new(
ImageType t,
ImageClass c,
const char *pretty,
const char *path,
const char *filename,
@@ -146,6 +147,7 @@ static int image_new(
*i = (Image) {
.n_ref = 1,
.type = t,
.class = c,
.read_only = read_only,
.crtime = crtime,
.mtime = mtime,
@@ -203,6 +205,7 @@ static int extract_pretty(const char *path, const char *suffix, char **ret) {
}
static int image_make(
ImageClass c,
const char *pretty,
int dfd,
const char *path,
@@ -278,6 +281,7 @@ static int image_make(
return r;
r = image_new(IMAGE_SUBVOLUME,
c,
pretty,
path,
filename,
@@ -314,6 +318,7 @@ static int image_make(
/* It's just a normal directory. */
r = image_new(IMAGE_DIRECTORY,
c,
pretty,
path,
filename,
@@ -345,6 +350,7 @@ static int image_make(
}
r = image_new(IMAGE_RAW,
c,
pretty,
path,
filename,
@@ -405,6 +411,7 @@ static int image_make(
}
r = image_new(IMAGE_BLOCK,
c,
pretty,
path,
filename,
@@ -475,13 +482,13 @@ int image_find(ImageClass class,
if (!S_ISREG(st.st_mode))
continue;
r = image_make(name, dirfd(d), resolved, raw, &st, ret);
r = image_make(class, name, dirfd(d), resolved, raw, &st, ret);
} else {
if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode))
continue;
r = image_make(name, dirfd(d), resolved, name, &st, ret);
r = image_make(class, name, dirfd(d), resolved, name, &st, ret);
}
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue;
@@ -495,7 +502,7 @@ int image_find(ImageClass class,
}
if (class == IMAGE_MACHINE && streq(name, ".host")) {
r = image_make(".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret);
r = image_make(class, ".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret);
if (r < 0)
return r;
@@ -515,9 +522,9 @@ int image_from_path(const char *path, Image **ret) {
* overridden by another, different image earlier in the search path */
if (path_equal(path, "/"))
return image_make(".host", AT_FDCWD, NULL, "/", NULL, ret);
return image_make(IMAGE_MACHINE, ".host", AT_FDCWD, NULL, "/", NULL, ret);
return image_make(NULL, AT_FDCWD, NULL, path, NULL, ret);
return image_make(_IMAGE_CLASS_INVALID, NULL, AT_FDCWD, NULL, path, NULL, ret);
}
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) {
@@ -591,7 +598,7 @@ int image_discover(
if (hashmap_contains(h, pretty))
continue;
r = image_make(pretty, dirfd(d), resolved, de->d_name, &st, &image);
r = image_make(class, pretty, dirfd(d), resolved, de->d_name, &st, &image);
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue;
if (r < 0)
@@ -610,7 +617,7 @@ int image_discover(
if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
_cleanup_(image_unrefp) Image *image = NULL;
r = image_make(".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image);
r = image_make(IMAGE_MACHINE, ".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image);
if (r < 0)
return r;
@@ -1303,3 +1310,11 @@ static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);
static const char* const image_class_table[_IMAGE_CLASS_MAX] = {
[IMAGE_MACHINE] = "machine",
[IMAGE_PORTABLE] = "portable",
[IMAGE_EXTENSION] = "extension",
};
DEFINE_STRING_TABLE_LOOKUP(image_class, ImageClass);

View File

@@ -34,6 +34,7 @@ typedef struct Image {
unsigned n_ref;
ImageType type;
ImageClass class;
char *name;
char *path;
bool read_only;
@@ -76,6 +77,9 @@ int image_read_only(Image *i, bool b);
const char* image_type_to_string(ImageType t) _const_;
ImageType image_type_from_string(const char *s) _pure_;
const char* image_class_to_string(ImageClass cl) _const_;
ImageClass image_class_from_string(const char *s) _pure_;
int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
int image_name_lock(const char *name, int operation, LockFile *ret);

View File

@@ -409,6 +409,15 @@ systemd-sysext unmerge
rmdir /etc/extensions/app-nodistro
rm /var/lib/extensions/app-nodistro.raw
mkdir -p /run/machines /run/portables /run/extensions
touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
systemd-dissect --discover --json=short > /tmp/discover.json
grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json
grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json
grep -q -F '{"name":"c","type":"raw","class":"extension","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
echo OK >/testok
exit 0