]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fstab-generator/fstab-generator.c
Update TODO
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
CommitLineData
6b1dc2bd
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <mntent.h>
24#include <errno.h>
25#include <string.h>
26#include <unistd.h>
27
28#include "log.h"
29#include "util.h"
30#include "unit-name.h"
31#include "path-util.h"
32#include "mount-setup.h"
33#include "special.h"
34#include "mkdir.h"
94734142 35#include "virt.h"
a5c32cff 36#include "fileio.h"
6b1dc2bd
LP
37
38static const char *arg_dest = "/tmp";
94734142 39static bool arg_enabled = true;
6b1dc2bd 40
6b1dc2bd
LP
41static int mount_find_pri(struct mntent *me, int *ret) {
42 char *end, *pri;
43 unsigned long r;
44
45 assert(me);
46 assert(ret);
47
48 pri = hasmntopt(me, "pri");
49 if (!pri)
50 return 0;
51
52 pri += 4;
53
54 errno = 0;
55 r = strtoul(pri, &end, 10);
8333c77e 56 if (errno > 0)
6b1dc2bd
LP
57 return -errno;
58
59 if (end == pri || (*end != ',' && *end != 0))
60 return -EINVAL;
61
62 *ret = (int) r;
63 return 1;
64}
65
66static int add_swap(const char *what, struct mntent *me) {
7fd1b19b
HH
67 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
68 _cleanup_fclose_ FILE *f = NULL;
4e82fe52 69 bool noauto;
6b1dc2bd
LP
70 int r, pri = -1;
71
72 assert(what);
73 assert(me);
74
75 r = mount_find_pri(me, &pri);
76 if (r < 0) {
77 log_error("Failed to parse priority");
78 return pri;
79 }
80
4e82fe52
TG
81 noauto = !!hasmntopt(me, "noauto");
82
6b1dc2bd 83 name = unit_name_from_path(what, ".swap");
d0aa9ce5
ZJS
84 if (!name)
85 return log_oom();
6b1dc2bd 86
b7def684 87 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
88 if (!unit)
89 return log_oom();
6b1dc2bd
LP
90
91 f = fopen(unit, "wxe");
92 if (!f) {
67ab5f76
TG
93 if (errno == EEXIST)
94 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
95 else
96 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 97 return -errno;
6b1dc2bd
LP
98 }
99
6b1dc2bd 100 fprintf(f,
64347fc2
TG
101 "# Automatically generated by systemd-fstab-generator\n\n"
102 "[Unit]\n"
4e82fe52 103 "SourcePath=/etc/fstab\n\n"
6b1dc2bd
LP
104 "[Swap]\n"
105 "What=%s\n",
106 what);
107
108 if (pri >= 0)
109 fprintf(f,
110 "Priority=%i\n",
111 pri);
112
113 fflush(f);
114 if (ferror(f)) {
40b8acd0 115 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 116 return -errno;
6b1dc2bd
LP
117 }
118
4e82fe52
TG
119 if (!noauto) {
120 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
121 if (!lnk)
122 return log_oom();
123
124 mkdir_parents_label(lnk, 0755);
125 if (symlink(unit, lnk) < 0) {
126 log_error("Failed to create symlink %s: %m", lnk);
127 return -errno;
128 }
129 }
130
d0aa9ce5 131 return 0;
6b1dc2bd
LP
132}
133
6b1dc2bd
LP
134static bool mount_is_network(struct mntent *me) {
135 assert(me);
136
137 return
138 hasmntopt(me, "_netdev") ||
139 fstype_is_network(me->mnt_type);
140}
141
3d22d1ab
TG
142static bool mount_in_initrd(struct mntent *me) {
143 assert(me);
144
145 return
146 hasmntopt(me, "x-initrd.mount") ||
147 streq(me->mnt_dir, "/usr");
148}
149
e8d2f6cd
LP
150static int add_mount(
151 const char *what,
152 const char *where,
153 const char *type,
154 const char *opts,
155 int passno,
156 bool noauto,
157 bool nofail,
158 bool automount,
e8d2f6cd 159 const char *post,
e8d2f6cd 160 const char *source) {
7fd1b19b 161 _cleanup_free_ char
d0aa9ce5
ZJS
162 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
163 *automount_name = NULL, *automount_unit = NULL;
7fd1b19b 164 _cleanup_fclose_ FILE *f = NULL;
6b1dc2bd
LP
165
166 assert(what);
167 assert(where);
5e398e54
TG
168 assert(type);
169 assert(opts);
170 assert(source);
6b1dc2bd 171
5e398e54 172 if (streq(type, "autofs"))
6b1dc2bd
LP
173 return 0;
174
175 if (!is_path(where)) {
176 log_warning("Mount point %s is not a valid path, ignoring.", where);
177 return 0;
178 }
179
180 if (mount_point_is_api(where) ||
181 mount_point_ignore(where))
182 return 0;
183
6b1dc2bd 184 name = unit_name_from_path(where, ".mount");
d0aa9ce5
ZJS
185 if (!name)
186 return log_oom();
6b1dc2bd 187
b7def684 188 unit = strjoin(arg_dest, "/", name, NULL);
d0aa9ce5
ZJS
189 if (!unit)
190 return log_oom();
6b1dc2bd
LP
191
192 f = fopen(unit, "wxe");
193 if (!f) {
67ab5f76
TG
194 if (errno == EEXIST)
195 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
196 else
197 log_error("Failed to create unit file %s: %m", unit);
d0aa9ce5 198 return -errno;
6b1dc2bd
LP
199 }
200
5e398e54
TG
201 fprintf(f,
202 "# Automatically generated by systemd-fstab-generator\n\n"
6b1dc2bd 203 "[Unit]\n"
80c3b720 204 "SourcePath=%s\n",
5e398e54 205 source);
6b1dc2bd 206
700e07ff 207 if (post && !noauto && !nofail && !automount)
6b1dc2bd
LP
208 fprintf(f,
209 "Before=%s\n",
210 post);
211
212 fprintf(f,
213 "\n"
214 "[Mount]\n"
215 "What=%s\n"
216 "Where=%s\n"
217 "Type=%s\n"
218 "FsckPassNo=%i\n",
219 what,
220 where,
5e398e54
TG
221 type,
222 passno);
6b1dc2bd 223
5e398e54
TG
224 if (!isempty(opts) &&
225 !streq(opts, "defaults"))
6b1dc2bd
LP
226 fprintf(f,
227 "Options=%s\n",
5e398e54
TG
228 opts);
229
6b1dc2bd
LP
230 fflush(f);
231 if (ferror(f)) {
40b8acd0 232 log_error("Failed to write unit file %s: %m", unit);
d0aa9ce5 233 return -errno;
6b1dc2bd
LP
234 }
235
236 if (!noauto) {
700e07ff
HH
237 if (post) {
238 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
239 if (!lnk)
240 return log_oom();
6b1dc2bd 241
700e07ff
HH
242 mkdir_parents_label(lnk, 0755);
243 if (symlink(unit, lnk) < 0) {
244 log_error("Failed to create symlink %s: %m", lnk);
245 return -errno;
246 }
6b1dc2bd 247 }
6b1dc2bd
LP
248 }
249
250 if (automount && !path_equal(where, "/")) {
251 automount_name = unit_name_from_path(where, ".automount");
01264ad1 252 if (!automount_name)
d0aa9ce5 253 return log_oom();
6b1dc2bd 254
b7def684 255 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
d0aa9ce5
ZJS
256 if (!automount_unit)
257 return log_oom();
6b1dc2bd
LP
258
259 fclose(f);
260 f = fopen(automount_unit, "wxe");
261 if (!f) {
40b8acd0 262 log_error("Failed to create unit file %s: %m", automount_unit);
d0aa9ce5 263 return -errno;
6b1dc2bd
LP
264 }
265
266 fprintf(f,
267 "# Automatically generated by systemd-fstab-generator\n\n"
268 "[Unit]\n"
80c3b720 269 "SourcePath=%s\n",
700e07ff
HH
270 source);
271
272 if (post)
273 fprintf(f,
274 "Before= %s\n",
275 post);
276
277 fprintf(f,
6b1dc2bd
LP
278 "[Automount]\n"
279 "Where=%s\n",
6b1dc2bd
LP
280 where);
281
282 fflush(f);
283 if (ferror(f)) {
40b8acd0 284 log_error("Failed to write unit file %s: %m", automount_unit);
d0aa9ce5 285 return -errno;
6b1dc2bd
LP
286 }
287
288 free(lnk);
b7def684 289 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
d0aa9ce5
ZJS
290 if (!lnk)
291 return log_oom();
6b1dc2bd 292
d2e54fae 293 mkdir_parents_label(lnk, 0755);
6b1dc2bd 294 if (symlink(automount_unit, lnk) < 0) {
40b8acd0 295 log_error("Failed to create symlink %s: %m", lnk);
d0aa9ce5 296 return -errno;
6b1dc2bd
LP
297 }
298 }
299
d0aa9ce5 300 return 0;
6b1dc2bd
LP
301}
302
3d22d1ab 303static int parse_fstab(const char *prefix, bool initrd) {
3d22d1ab 304 _cleanup_free_ char *fstab_path = NULL;
df3e57f5 305 FILE *f;
6b1dc2bd
LP
306 int r = 0;
307 struct mntent *me;
308
df3e57f5
LP
309 fstab_path = strjoin(strempty(prefix), "/etc/fstab", NULL);
310 if (!fstab_path)
311 return log_oom();
312
3d22d1ab 313 f = setmntent(fstab_path, "r");
6b1dc2bd
LP
314 if (!f) {
315 if (errno == ENOENT)
316 return 0;
317
1b036593 318 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
6b1dc2bd
LP
319 return -errno;
320 }
321
322 while ((me = getmntent(f))) {
7fd1b19b 323 _cleanup_free_ char *where = NULL, *what = NULL;
6b1dc2bd
LP
324 int k;
325
3d22d1ab
TG
326 if (initrd && !mount_in_initrd(me))
327 continue;
328
6b1dc2bd 329 what = fstab_node_to_udev_node(me->mnt_fsname);
1b036593 330 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
d0aa9ce5 331 if (!what || !where) {
0d0f0c50 332 r = log_oom();
6b1dc2bd
LP
333 goto finish;
334 }
335
ec6ceb18 336 if (is_path(where))
6b1dc2bd
LP
337 path_kill_slashes(where);
338
339 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
340
341 if (streq(me->mnt_type, "swap"))
342 k = add_swap(what, me);
5e398e54 343 else {
5073f89f 344 bool noauto, nofail, automount;
80c3b720 345 const char *post;
5e398e54
TG
346
347 noauto = !!hasmntopt(me, "noauto");
348 nofail = !!hasmntopt(me, "nofail");
349 automount =
350 hasmntopt(me, "comment=systemd.automount") ||
351 hasmntopt(me, "x-systemd.automount");
700e07ff
HH
352
353 if (initrd) {
354 post = SPECIAL_INITRD_FS_TARGET;
a87586a1 355 } else if (mount_in_initrd(me)) {
9e5f0f92 356 post = SPECIAL_INITRD_ROOT_FS_TARGET;
700e07ff 357 } else if (mount_is_network(me)) {
0c17fbce 358 post = SPECIAL_REMOTE_FS_TARGET;
700e07ff 359 } else {
0c17fbce 360 post = SPECIAL_LOCAL_FS_TARGET;
700e07ff 361 }
5e398e54
TG
362
363 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
e8d2f6cd 364 me->mnt_passno, noauto, nofail, automount,
5073f89f 365 post, fstab_path);
5e398e54 366 }
6b1dc2bd 367
6b1dc2bd
LP
368 if (k < 0)
369 r = k;
370 }
371
372finish:
373 endmntent(f);
374 return r;
375}
376
5e398e54 377static int parse_new_root_from_proc_cmdline(void) {
ac4785b0 378 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
80c39ad2 379 char *w, *state;
5e398e54
TG
380 int r;
381 size_t l;
21d1a678 382 bool noauto, nofail;
5e398e54
TG
383
384 r = read_one_line_file("/proc/cmdline", &line);
385 if (r < 0) {
386 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
387 return 0;
388 }
389
945d1442 390 opts = strdup("ro");
5e398e54 391 type = strdup("auto");
945d1442 392 if (!opts || !type)
5e398e54
TG
393 return log_oom();
394
b929bf04
TA
395 /* root= and roofstype= may occur more than once, the last instance should take precedence.
396 * In the case of multiple rootflags= the arguments should be concatenated */
5e398e54 397 FOREACH_WORD_QUOTED(w, l, line, state) {
80c39ad2 398 _cleanup_free_ char *word;
5e398e54
TG
399
400 word = strndup(w, l);
401 if (!word)
402 return log_oom();
403
404 else if (startswith(word, "root=")) {
405 free(what);
406 what = fstab_node_to_udev_node(word+5);
407 if (!what)
408 return log_oom();
409
410 } else if (startswith(word, "rootfstype=")) {
411 free(type);
412 type = strdup(word + 11);
413 if (!type)
414 return log_oom();
415
416 } else if (startswith(word, "rootflags=")) {
80c39ad2
LP
417 char *o;
418
419 o = strjoin(opts, ",", word + 10, NULL);
420 if (!o)
5e398e54
TG
421 return log_oom();
422
80c39ad2
LP
423 free(opts);
424 opts = o;
425
5e398e54 426 } else if (streq(word, "ro") || streq(word, "rw")) {
80c39ad2
LP
427 char *o;
428
429 o = strjoin(opts, ",", word, NULL);
430 if (!o)
5e398e54
TG
431 return log_oom();
432
80c39ad2
LP
433 free(opts);
434 opts = o;
533740e1 435 }
5e398e54
TG
436 }
437
21d1a678
WC
438 noauto = !!strstr(opts, "noauto");
439 nofail = !!strstr(opts, "nofail");
440
135b5212 441 if (!what) {
4e5ed9b6 442 log_debug("Could not find a root= entry on the kernel commandline.");
135b5212
HH
443 return 0;
444 }
5e398e54 445
135b5212
HH
446 if (what[0] != '/') {
447 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
448 return 0;
449 }
5e398e54 450
135b5212 451 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
21d1a678 452 r = add_mount(what, "/sysroot", type, opts, 0, noauto, nofail, false,
5073f89f 453 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
5e398e54 454
135b5212 455 return (r < 0) ? r : 0;
5e398e54
TG
456}
457
94734142 458static int parse_proc_cmdline(void) {
7fd1b19b 459 _cleanup_free_ char *line = NULL;
d0aa9ce5 460 char *w, *state;
94734142
LP
461 int r;
462 size_t l;
463
464 if (detect_container(NULL) > 0)
465 return 0;
466
467 r = read_one_line_file("/proc/cmdline", &line);
468 if (r < 0) {
469 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
470 return 0;
471 }
472
473 FOREACH_WORD_QUOTED(w, l, line, state) {
7fd1b19b 474 _cleanup_free_ char *word = NULL;
94734142
LP
475
476 word = strndup(w, l);
d0aa9ce5
ZJS
477 if (!word)
478 return log_oom();
94734142
LP
479
480 if (startswith(word, "fstab=")) {
481 r = parse_boolean(word + 6);
482 if (r < 0)
483 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
484 else
485 arg_enabled = r;
486
487 } else if (startswith(word, "rd.fstab=")) {
488
489 if (in_initrd()) {
ef53700c 490 r = parse_boolean(word + 9);
94734142 491 if (r < 0)
ef53700c 492 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
94734142
LP
493 else
494 arg_enabled = r;
495 }
496
497 } else if (startswith(word, "fstab.") ||
498 (in_initrd() && startswith(word, "rd.fstab."))) {
499
500 log_warning("Unknown kernel switch %s. Ignoring.", word);
501 }
94734142
LP
502 }
503
d0aa9ce5 504 return 0;
94734142
LP
505}
506
6b1dc2bd 507int main(int argc, char *argv[]) {
ac4785b0 508 int r = 0, k, l = 0;
6b1dc2bd 509
07719a21
LP
510 if (argc > 1 && argc != 4) {
511 log_error("This program takes three or no arguments.");
6b1dc2bd
LP
512 return EXIT_FAILURE;
513 }
514
515 if (argc > 1)
516 arg_dest = argv[1];
517
a6903061 518 log_set_target(LOG_TARGET_SAFE);
6b1dc2bd
LP
519 log_parse_environment();
520 log_open();
521
6b1dc2bd
LP
522 umask(0022);
523
94734142
LP
524 if (parse_proc_cmdline() < 0)
525 return EXIT_FAILURE;
526
ac4785b0
HH
527 if (in_initrd())
528 r = parse_new_root_from_proc_cmdline();
5e398e54 529
ac4785b0
HH
530 if (!arg_enabled)
531 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
532
df3e57f5 533 k = parse_fstab(NULL, false);
ac4785b0
HH
534
535 if (in_initrd())
536 l = parse_fstab("/sysroot", true);
6b1dc2bd 537
3d22d1ab 538 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
6b1dc2bd 539}