mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 16:37:19 +09:00
Merge pull request #25564 from poettering/dissect-discover
systemd-dissect: add simple "--discover" command
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user