X Tutup
Skip to content

Commit a2ea3b2

Browse files
committed
dissect: add small "systemd-dissect" tool as wrapper around dissect-image.c
This adds a small tool that may be used to look into OS images, and mount them to any place. This is mostly a friendlier version of test-dissect-image.c. I am not sure this should really become a proper command of systemd, hence for now do not install it into bindir, but simply libexecdir. This tool is already pretty useful since you can mount image files with it, honouring the various partitions correctly. I figure this is going to become more interesting if the dissctor learns luks and verity support.
1 parent 9f3c7fc commit a2ea3b2

File tree

6 files changed

+234
-3
lines changed

6 files changed

+234
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
/systemd-debug-generator
6868
/systemd-delta
6969
/systemd-detect-virt
70+
/systemd-dissect
7071
/systemd-escape
7172
/systemd-export
7273
/systemd-firstboot

Makefile.am

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,11 @@ rootlibexec_PROGRAMS = \
404404
systemd-socket-proxyd \
405405
systemd-update-done
406406

407+
if HAVE_BLKID
408+
rootlibexec_PROGRAMS += \
409+
systemd-dissect
410+
endif
411+
407412
if HAVE_UTMP
408413
rootlibexec_PROGRAMS += \
409414
systemd-update-utmp
@@ -3073,6 +3078,13 @@ systemd_notify_SOURCES = \
30733078
systemd_notify_LDADD = \
30743079
libsystemd-shared.la
30753080

3081+
# ------------------------------------------------------------------------------
3082+
systemd_dissect_SOURCES = \
3083+
src/dissect/dissect.c
3084+
3085+
systemd_dissect_LDADD = \
3086+
libsystemd-shared.la
3087+
30763088
# ------------------------------------------------------------------------------
30773089
systemd_path_SOURCES = \
30783090
src/path/path.c

src/dissect/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../Makefile

src/dissect/dissect.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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+
31+
static enum {
32+
ACTION_DISSECT,
33+
ACTION_MOUNT,
34+
} arg_action = ACTION_DISSECT;
35+
static const char *arg_image = NULL;
36+
static const char *arg_path = NULL;
37+
static bool arg_read_only = false;
38+
39+
static 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"
46+
" -r --read-only Mount read-only\n",
47+
program_invocation_short_name,
48+
program_invocation_short_name);
49+
}
50+
51+
static int parse_argv(int argc, char *argv[]) {
52+
53+
enum {
54+
ARG_VERSION = 0x100,
55+
};
56+
57+
static const struct option options[] = {
58+
{ "help", no_argument, NULL, 'h' },
59+
{ "version", no_argument, NULL, ARG_VERSION },
60+
{ "mount", no_argument, NULL, 'm' },
61+
{ "read-only", no_argument, NULL, 'r' },
62+
{}
63+
};
64+
65+
int c;
66+
67+
assert(argc >= 0);
68+
assert(argv);
69+
70+
while ((c = getopt_long(argc, argv, "hmr", options, NULL)) >= 0) {
71+
72+
switch (c) {
73+
74+
case 'h':
75+
help();
76+
return 0;
77+
78+
case ARG_VERSION:
79+
return version();
80+
81+
case 'm':
82+
arg_action = ACTION_MOUNT;
83+
break;
84+
85+
case 'r':
86+
arg_read_only = true;
87+
break;
88+
89+
case '?':
90+
return -EINVAL;
91+
92+
default:
93+
assert_not_reached("Unhandled option");
94+
}
95+
96+
}
97+
98+
switch (arg_action) {
99+
100+
case ACTION_DISSECT:
101+
if (optind + 1 != argc) {
102+
log_error("Expected a file path as only argument.");
103+
return -EINVAL;
104+
}
105+
106+
arg_image = argv[optind];
107+
arg_read_only = true;
108+
break;
109+
110+
case ACTION_MOUNT:
111+
if (optind + 2 != argc) {
112+
log_error("Expected a file path and mount point path as only arguments.");
113+
return -EINVAL;
114+
}
115+
116+
arg_image = argv[optind];
117+
arg_path = argv[optind + 1];
118+
break;
119+
120+
default:
121+
assert_not_reached("Unknown action.");
122+
}
123+
124+
return 1;
125+
}
126+
127+
int main(int argc, char *argv[]) {
128+
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
129+
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
130+
int r;
131+
132+
log_parse_environment();
133+
log_open();
134+
135+
r = parse_argv(argc, argv);
136+
if (r <= 0)
137+
goto finish;
138+
139+
r = loop_device_make_by_path(arg_image, arg_read_only ? O_RDONLY : O_RDWR, &d);
140+
if (r < 0) {
141+
log_error_errno(r, "Failed to set up loopback device: %m");
142+
goto finish;
143+
}
144+
145+
r = dissect_image(d->fd, &m);
146+
if (r == -ENOPKG) {
147+
log_error_errno(r, "Couldn't identify a suitable partition table or file system in %s.", arg_image);
148+
goto finish;
149+
}
150+
if (r < 0) {
151+
log_error_errno(r, "Failed to dissect image: %m");
152+
goto finish;
153+
}
154+
155+
switch (arg_action) {
156+
157+
case ACTION_DISSECT: {
158+
unsigned i;
159+
160+
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
161+
DissectedPartition *p = m->partitions + i;
162+
163+
if (!p->found)
164+
continue;
165+
166+
printf("Found %s '%s' partition",
167+
p->rw ? "writable" : "read-only",
168+
partition_designator_to_string(i));
169+
170+
if (p->fstype)
171+
printf(" of type %s", p->fstype);
172+
173+
if (p->architecture != _ARCHITECTURE_INVALID)
174+
printf(" for %s", architecture_to_string(p->architecture));
175+
176+
if (p->partno >= 0)
177+
printf(" on partition #%i", p->partno);
178+
179+
if (p->node)
180+
printf(" (%s)", p->node);
181+
182+
putchar('\n');
183+
}
184+
185+
break;
186+
}
187+
188+
case ACTION_MOUNT:
189+
r = dissected_image_mount(m, arg_path,
190+
(arg_read_only ? DISSECTED_IMAGE_READ_ONLY : 0) |
191+
DISSECTED_IMAGE_DISCARD_ON_LOOP);
192+
if (r < 0) {
193+
log_error_errno(r, "Failed to mount image: %m");
194+
goto finish;
195+
}
196+
197+
loop_device_relinquish(d);
198+
break;
199+
200+
default:
201+
assert_not_reached("Unknown action.");
202+
}
203+
204+
finish:
205+
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
206+
}

src/shared/loop-util.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ LoopDevice* loop_device_unref(LoopDevice *d) {
129129

130130
if (d->fd >= 0) {
131131

132-
if (d->nr >= 0) {
132+
if (d->nr >= 0 && !d->relinquished) {
133133
if (ioctl(d->fd, LOOP_CLR_FD) < 0)
134134
log_debug_errno(errno, "Failed to clear loop device: %m");
135135

@@ -138,7 +138,7 @@ LoopDevice* loop_device_unref(LoopDevice *d) {
138138
safe_close(d->fd);
139139
}
140140

141-
if (d->nr >= 0) {
141+
if (d->nr >= 0 && !d->relinquished) {
142142
_cleanup_close_ int control = -1;
143143

144144
control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
@@ -155,3 +155,12 @@ LoopDevice* loop_device_unref(LoopDevice *d) {
155155

156156
return NULL;
157157
}
158+
159+
void loop_device_relinquish(LoopDevice *d) {
160+
assert(d);
161+
162+
/* Don't attempt to clean up the loop device anymore from this point on. Leave the clean-ing up to the kernel
163+
* itself, using the loop device "auto-clear" logic we already turned on when creating the device. */
164+
165+
d->relinquished = true;
166+
}

src/shared/loop-util.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ struct LoopDevice {
2929
int fd;
3030
int nr;
3131
char *node;
32+
bool relinquished;
3233
};
3334

3435
int loop_device_make(int fd, int open_flags, LoopDevice **ret);
3536
int loop_device_make_by_path(const char *path, int open_flags, LoopDevice **ret);
3637

3738
LoopDevice* loop_device_unref(LoopDevice *d);
38-
3939
DEFINE_TRIVIAL_CLEANUP_FUNC(LoopDevice*, loop_device_unref);
40+
41+
void loop_device_relinquish(LoopDevice *d);

0 commit comments

Comments
 (0)
X Tutup