2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "architecture.h"
25 #include "dissect-image.h"
26 #include "hexdecoct.h"
28 #include "loop-util.h"
29 #include "string-util.h"
35 } arg_action
= ACTION_DISSECT
;
36 static const char *arg_image
= NULL
;
37 static const char *arg_path
= NULL
;
38 static DissectImageFlags arg_flags
= DISSECT_IMAGE_REQUIRE_ROOT
|DISSECT_IMAGE_DISCARD_ON_LOOP
;
39 static void *arg_root_hash
= NULL
;
40 static size_t arg_root_hash_size
= 0;
42 static void help(void) {
43 printf("%s [OPTIONS...] IMAGE\n"
44 "%s [OPTIONS...] --mount IMAGE PATH\n"
45 "Dissect a file system OS image.\n\n"
46 " -h --help Show this help\n"
47 " --version Show package version\n"
48 " -m --mount Mount the image to the specified directory\n"
49 " -r --read-only Mount read-only\n"
50 " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
51 " --root-hash=HASH Specify root hash for verity\n",
52 program_invocation_short_name
,
53 program_invocation_short_name
);
56 static int parse_argv(int argc
, char *argv
[]) {
64 static const struct option options
[] = {
65 { "help", no_argument
, NULL
, 'h' },
66 { "version", no_argument
, NULL
, ARG_VERSION
},
67 { "mount", no_argument
, NULL
, 'm' },
68 { "read-only", no_argument
, NULL
, 'r' },
69 { "discard", required_argument
, NULL
, ARG_DISCARD
},
70 { "root-hash", required_argument
, NULL
, ARG_ROOT_HASH
},
79 while ((c
= getopt_long(argc
, argv
, "hmr", options
, NULL
)) >= 0) {
91 arg_action
= ACTION_MOUNT
;
95 arg_flags
|= DISSECT_IMAGE_READ_ONLY
;
99 DissectImageFlags flags
;
101 if (streq(optarg
, "disabled"))
103 else if (streq(optarg
, "loop"))
104 flags
= DISSECT_IMAGE_DISCARD_ON_LOOP
;
105 else if (streq(optarg
, "all"))
106 flags
= DISSECT_IMAGE_DISCARD_ON_LOOP
| DISSECT_IMAGE_DISCARD
;
107 else if (streq(optarg
, "crypt"))
108 flags
= DISSECT_IMAGE_DISCARD_ANY
;
110 log_error("Unknown --discard= parameter: %s", optarg
);
113 arg_flags
= (arg_flags
& ~DISSECT_IMAGE_DISCARD_ANY
) | flags
;
118 case ARG_ROOT_HASH
: {
122 r
= unhexmem(optarg
, strlen(optarg
), &p
, &l
);
124 return log_error_errno(r
, "Failed to parse root hash: %s", optarg
);
125 if (l
< sizeof(sd_id128_t
)) {
126 log_error("Root hash must be at least 128bit long: %s", optarg
);
133 arg_root_hash_size
= l
;
141 assert_not_reached("Unhandled option");
146 switch (arg_action
) {
149 if (optind
+ 1 != argc
) {
150 log_error("Expected a file path as only argument.");
154 arg_image
= argv
[optind
];
155 arg_flags
|= DISSECT_IMAGE_READ_ONLY
;
159 if (optind
+ 2 != argc
) {
160 log_error("Expected a file path and mount point path as only arguments.");
164 arg_image
= argv
[optind
];
165 arg_path
= argv
[optind
+ 1];
169 assert_not_reached("Unknown action.");
175 int main(int argc
, char *argv
[]) {
176 _cleanup_(loop_device_unrefp
) LoopDevice
*d
= NULL
;
177 _cleanup_(decrypted_image_unrefp
) DecryptedImage
*di
= NULL
;
178 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
181 log_parse_environment();
184 r
= parse_argv(argc
, argv
);
188 r
= loop_device_make_by_path(arg_image
, (arg_flags
& DISSECT_IMAGE_READ_ONLY
) ? O_RDONLY
: O_RDWR
, &d
);
190 log_error_errno(r
, "Failed to set up loopback device: %m");
194 if (!arg_root_hash
) {
195 r
= root_hash_load(arg_image
, &arg_root_hash
, &arg_root_hash_size
);
197 log_error_errno(r
, "Failed to read root hash file for %s: %m", arg_image
);
202 r
= dissect_image(d
->fd
, arg_root_hash
, arg_root_hash_size
, arg_flags
, &m
);
204 log_error_errno(r
, "Couldn't identify a suitable partition table or file system in %s.", arg_image
);
207 if (r
== -EADDRNOTAVAIL
) {
208 log_error_errno(r
, "No root partition for specified root hash found in %s.", arg_image
);
211 if (r
== -ENOTUNIQ
) {
212 log_error_errno(r
, "Multiple suitable root partitions found in image %s.", arg_image
);
216 log_error_errno(r
, "No suitable root partition found in image %s.", arg_image
);
219 if (r
== -EPROTONOSUPPORT
) {
220 log_error_errno(r
, "Device %s is loopback block device with partition scanning turned off, please turn it on.", arg_image
);
224 log_error_errno(r
, "Failed to dissect image: %m");
228 switch (arg_action
) {
230 case ACTION_DISSECT
: {
233 for (i
= 0; i
< _PARTITION_DESIGNATOR_MAX
; i
++) {
234 DissectedPartition
*p
= m
->partitions
+ i
;
240 printf("Found %s '%s' partition",
241 p
->rw
? "writable" : "read-only",
242 partition_designator_to_string(i
));
244 if (!sd_id128_is_null(p
->uuid
))
245 printf(" (UUID " SD_ID128_FORMAT_STR
")", SD_ID128_FORMAT_VAL(p
->uuid
));
248 printf(" of type %s", p
->fstype
);
250 if (p
->architecture
!= _ARCHITECTURE_INVALID
)
251 printf(" for %s", architecture_to_string(p
->architecture
));
253 k
= PARTITION_VERITY_OF(i
);
255 printf(" %s verity", m
->partitions
[k
].found
? "with" : "without");
258 printf(" on partition #%i", p
->partno
);
261 printf(" (%s)", p
->node
);
270 r
= dissected_image_decrypt_interactively(m
, NULL
, arg_root_hash
, arg_root_hash_size
, arg_flags
, &di
);
274 r
= dissected_image_mount(m
, arg_path
, arg_flags
);
276 log_error_errno(r
, "Failed to mount image: %m");
281 r
= decrypted_image_relinquish(di
);
283 log_error_errno(r
, "Failed to relinquish DM devices: %m");
288 loop_device_relinquish(d
);
292 assert_not_reached("Unknown action.");
297 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;