1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "architecture.h"
8 #include "dissect-image.h"
11 #include "loop-util.h"
12 #include "main-func.h"
13 #include "string-util.h"
15 #include "user-util.h"
21 } arg_action
= ACTION_DISSECT
;
22 static const char *arg_image
= NULL
;
23 static const char *arg_path
= NULL
;
24 static DissectImageFlags arg_flags
= DISSECT_IMAGE_REQUIRE_ROOT
|DISSECT_IMAGE_DISCARD_ON_LOOP
;
25 static void *arg_root_hash
= NULL
;
26 static size_t arg_root_hash_size
= 0;
28 STATIC_DESTRUCTOR_REGISTER(arg_root_hash
, freep
);
30 static void help(void) {
31 printf("%s [OPTIONS...] IMAGE\n"
32 "%s [OPTIONS...] --mount IMAGE PATH\n"
33 "Dissect a file system OS image.\n\n"
34 " -h --help Show this help\n"
35 " --version Show package version\n"
36 " -m --mount Mount the image to the specified directory\n"
37 " -r --read-only Mount read-only\n"
38 " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
39 " --root-hash=HASH Specify root hash for verity\n",
40 program_invocation_short_name
,
41 program_invocation_short_name
);
44 static int parse_argv(int argc
, char *argv
[]) {
52 static const struct option options
[] = {
53 { "help", no_argument
, NULL
, 'h' },
54 { "version", no_argument
, NULL
, ARG_VERSION
},
55 { "mount", no_argument
, NULL
, 'm' },
56 { "read-only", no_argument
, NULL
, 'r' },
57 { "discard", required_argument
, NULL
, ARG_DISCARD
},
58 { "root-hash", required_argument
, NULL
, ARG_ROOT_HASH
},
67 while ((c
= getopt_long(argc
, argv
, "hmr", options
, NULL
)) >= 0) {
79 arg_action
= ACTION_MOUNT
;
83 arg_flags
|= DISSECT_IMAGE_READ_ONLY
;
87 DissectImageFlags flags
;
89 if (streq(optarg
, "disabled"))
91 else if (streq(optarg
, "loop"))
92 flags
= DISSECT_IMAGE_DISCARD_ON_LOOP
;
93 else if (streq(optarg
, "all"))
94 flags
= DISSECT_IMAGE_DISCARD_ON_LOOP
| DISSECT_IMAGE_DISCARD
;
95 else if (streq(optarg
, "crypt"))
96 flags
= DISSECT_IMAGE_DISCARD_ANY
;
98 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
99 "Unknown --discard= parameter: %s",
101 arg_flags
= (arg_flags
& ~DISSECT_IMAGE_DISCARD_ANY
) | flags
;
106 case ARG_ROOT_HASH
: {
110 r
= unhexmem(optarg
, strlen(optarg
), &p
, &l
);
112 return log_error_errno(r
, "Failed to parse root hash '%s': %m", optarg
);
113 if (l
< sizeof(sd_id128_t
)) {
114 log_error("Root hash must be at least 128bit long: %s", optarg
);
121 arg_root_hash_size
= l
;
129 assert_not_reached("Unhandled option");
134 switch (arg_action
) {
137 if (optind
+ 1 != argc
)
138 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
139 "Expected a file path as only argument.");
141 arg_image
= argv
[optind
];
142 arg_flags
|= DISSECT_IMAGE_READ_ONLY
;
146 if (optind
+ 2 != argc
)
147 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
148 "Expected a file path and mount point path as only arguments.");
150 arg_image
= argv
[optind
];
151 arg_path
= argv
[optind
+ 1];
155 assert_not_reached("Unknown action.");
161 static int run(int argc
, char *argv
[]) {
162 _cleanup_(loop_device_unrefp
) LoopDevice
*d
= NULL
;
163 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*di
= NULL
;
164 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
167 log_parse_environment();
170 r
= parse_argv(argc
, argv
);
174 r
= loop_device_make_by_path(arg_image
, (arg_flags
& DISSECT_IMAGE_READ_ONLY
) ? O_RDONLY
: O_RDWR
, &d
);
176 return log_error_errno(r
, "Failed to set up loopback device: %m");
178 if (!arg_root_hash
) {
179 r
= root_hash_load(arg_image
, &arg_root_hash
, &arg_root_hash_size
);
181 return log_error_errno(r
, "Failed to read root hash file for %s: %m", arg_image
);
184 r
= dissect_image_and_warn(d
->fd
, arg_image
, arg_root_hash
, arg_root_hash_size
, arg_flags
, &m
);
188 switch (arg_action
) {
190 case ACTION_DISSECT
: {
193 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
194 DissectedPartition
*p
= m
->partitions
+ i
;
200 printf("Found %s '%s' partition",
201 p
->rw
? "writable" : "read-only",
202 partition_designator_to_string(i
));
204 if (!sd_id128_is_null(p
->uuid
))
205 printf(" (UUID " SD_ID128_FORMAT_STR
")", SD_ID128_FORMAT_VAL(p
->uuid
));
208 printf(" of type %s", p
->fstype
);
210 if (p
->architecture
!= _ARCHITECTURE_INVALID
)
211 printf(" for %s", architecture_to_string(p
->architecture
));
213 k
= PARTITION_VERITY_OF(i
);
215 printf(" %s verity", m
->partitions
[k
].found
? "with" : "without");
218 printf(" on partition #%i", p
->partno
);
221 printf(" (%s)", p
->node
);
226 r
= dissected_image_acquire_metadata(m
);
228 return log_error_errno(r
, "Failed to acquire image metadata: %m");
231 printf(" Hostname: %s\n", m
->hostname
);
233 if (!sd_id128_is_null(m
->machine_id
))
234 printf("Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->machine_id
));
236 if (!strv_isempty(m
->machine_info
)) {
239 STRV_FOREACH_PAIR(p
, q
, m
->machine_info
)
241 p
== m
->machine_info
? "Mach. Info:" : " ",
245 if (!strv_isempty(m
->os_release
)) {
248 STRV_FOREACH_PAIR(p
, q
, m
->os_release
)
250 p
== m
->os_release
? "OS Release:" : " ",
258 r
= dissected_image_decrypt_interactively(m
, NULL
, arg_root_hash
, arg_root_hash_size
, arg_flags
, &di
);
262 r
= dissected_image_mount(m
, arg_path
, UID_INVALID
, arg_flags
);
264 return log_error_errno(r
, "Failed to mount image: %m");
267 r
= decrypted_image_relinquish(di
);
269 return log_error_errno(r
, "Failed to relinquish DM devices: %m");
272 loop_device_relinquish(d
);
276 assert_not_reached("Unknown action.");
282 DEFINE_MAIN_FUNCTION(run
);