]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/dissect/dissect.c
dissect: add support for encrypted images
[thirdparty/systemd.git] / src / dissect / dissect.c
CommitLineData
a2ea3b2f
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2016 Lennart Poettering
5
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.
10
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.
15
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/>.
18***/
19
20#include <fcntl.h>
21#include <stdio.h>
22#include <getopt.h>
23
24#include "architecture.h"
25#include "dissect-image.h"
26#include "log.h"
27#include "loop-util.h"
28#include "string-util.h"
29#include "util.h"
30
31static enum {
32 ACTION_DISSECT,
33 ACTION_MOUNT,
34} arg_action = ACTION_DISSECT;
35static const char *arg_image = NULL;
36static const char *arg_path = NULL;
18b5886e 37static DissectImageFlags arg_flags = DISSECT_IMAGE_DISCARD_ON_LOOP;
a2ea3b2f
LP
38
39static void help(void) {
40 printf("%s [OPTIONS...] IMAGE\n"
41 "%s [OPTIONS...] --mount IMAGE PATH\n"
42 "Dissect a file system OS image.\n\n"
43 " -h --help Show this help\n"
44 " --version Show package version\n"
45 " -m --mount Mount the image to the specified directory\n"
18b5886e
LP
46 " -r --read-only Mount read-only\n"
47 " --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n",
a2ea3b2f
LP
48 program_invocation_short_name,
49 program_invocation_short_name);
50}
51
52static int parse_argv(int argc, char *argv[]) {
53
54 enum {
55 ARG_VERSION = 0x100,
18b5886e 56 ARG_DISCARD,
a2ea3b2f
LP
57 };
58
59 static const struct option options[] = {
60 { "help", no_argument, NULL, 'h' },
61 { "version", no_argument, NULL, ARG_VERSION },
62 { "mount", no_argument, NULL, 'm' },
63 { "read-only", no_argument, NULL, 'r' },
18b5886e 64 { "discard", required_argument, NULL, ARG_DISCARD },
a2ea3b2f
LP
65 {}
66 };
67
68 int c;
69
70 assert(argc >= 0);
71 assert(argv);
72
73 while ((c = getopt_long(argc, argv, "hmr", options, NULL)) >= 0) {
74
75 switch (c) {
76
77 case 'h':
78 help();
79 return 0;
80
81 case ARG_VERSION:
82 return version();
83
84 case 'm':
85 arg_action = ACTION_MOUNT;
86 break;
87
88 case 'r':
18b5886e
LP
89 arg_flags |= DISSECT_IMAGE_READ_ONLY;
90 break;
91
92 case ARG_DISCARD:
93 if (streq(optarg, "disabled"))
94 arg_flags &= ~(DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_DISCARD|DISSECT_IMAGE_DISCARD_ON_CRYPTO);
95 else if (streq(optarg, "loop"))
96 arg_flags = (arg_flags & ~(DISSECT_IMAGE_DISCARD|DISSECT_IMAGE_DISCARD_ON_CRYPTO)) | DISSECT_IMAGE_DISCARD_ON_LOOP;
97 else if (streq(optarg, "all"))
98 arg_flags = (arg_flags & ~(DISSECT_IMAGE_DISCARD_ON_CRYPTO)) | DISSECT_IMAGE_DISCARD_ON_LOOP | DISSECT_IMAGE_DISCARD;
99 else if (streq(optarg, "crypt"))
100 arg_flags |= DISSECT_IMAGE_DISCARD_ON_LOOP | DISSECT_IMAGE_DISCARD | DISSECT_IMAGE_DISCARD_ON_CRYPTO;
101 else {
102 log_error("Unknown --discard= parameter: %s", optarg);
103 return -EINVAL;
104 }
105
a2ea3b2f
LP
106 break;
107
108 case '?':
109 return -EINVAL;
110
111 default:
112 assert_not_reached("Unhandled option");
113 }
114
115 }
116
117 switch (arg_action) {
118
119 case ACTION_DISSECT:
120 if (optind + 1 != argc) {
121 log_error("Expected a file path as only argument.");
122 return -EINVAL;
123 }
124
125 arg_image = argv[optind];
18b5886e 126 arg_flags |= DISSECT_IMAGE_READ_ONLY;
a2ea3b2f
LP
127 break;
128
129 case ACTION_MOUNT:
130 if (optind + 2 != argc) {
131 log_error("Expected a file path and mount point path as only arguments.");
132 return -EINVAL;
133 }
134
135 arg_image = argv[optind];
136 arg_path = argv[optind + 1];
137 break;
138
139 default:
140 assert_not_reached("Unknown action.");
141 }
142
143 return 1;
144}
145
146int main(int argc, char *argv[]) {
147 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
18b5886e 148 _cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL;
a2ea3b2f
LP
149 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
150 int r;
151
152 log_parse_environment();
153 log_open();
154
155 r = parse_argv(argc, argv);
156 if (r <= 0)
157 goto finish;
158
18b5886e 159 r = loop_device_make_by_path(arg_image, (arg_flags & DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR, &d);
a2ea3b2f
LP
160 if (r < 0) {
161 log_error_errno(r, "Failed to set up loopback device: %m");
162 goto finish;
163 }
164
165 r = dissect_image(d->fd, &m);
166 if (r == -ENOPKG) {
167 log_error_errno(r, "Couldn't identify a suitable partition table or file system in %s.", arg_image);
168 goto finish;
169 }
170 if (r < 0) {
171 log_error_errno(r, "Failed to dissect image: %m");
172 goto finish;
173 }
174
175 switch (arg_action) {
176
177 case ACTION_DISSECT: {
178 unsigned i;
179
180 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
181 DissectedPartition *p = m->partitions + i;
182
183 if (!p->found)
184 continue;
185
186 printf("Found %s '%s' partition",
187 p->rw ? "writable" : "read-only",
188 partition_designator_to_string(i));
189
190 if (p->fstype)
191 printf(" of type %s", p->fstype);
192
193 if (p->architecture != _ARCHITECTURE_INVALID)
194 printf(" for %s", architecture_to_string(p->architecture));
195
196 if (p->partno >= 0)
197 printf(" on partition #%i", p->partno);
198
199 if (p->node)
200 printf(" (%s)", p->node);
201
202 putchar('\n');
203 }
204
205 break;
206 }
207
208 case ACTION_MOUNT:
18b5886e
LP
209 r = dissected_image_decrypt_interactively(m, NULL, arg_flags, &di);
210 if (r < 0)
211 goto finish;
212
213 r = dissected_image_mount(m, arg_path, arg_flags);
a2ea3b2f
LP
214 if (r < 0) {
215 log_error_errno(r, "Failed to mount image: %m");
216 goto finish;
217 }
218
18b5886e
LP
219 if (di) {
220 r = decrypted_image_relinquish(di);
221 if (r < 0) {
222 log_error_errno(r, "Failed to relinquish DM devices: %m");
223 goto finish;
224 }
225 }
226
a2ea3b2f
LP
227 loop_device_relinquish(d);
228 break;
229
230 default:
231 assert_not_reached("Unknown action.");
232 }
233
234finish:
235 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
236}