]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
fstab-generator: remove redundancy in mount_is_bind
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
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"
35 #include "virt.h"
36
37 static const char *arg_dest = "/tmp";
38 static bool arg_enabled = true;
39
40 static int device_name(const char *path, char **unit) {
41 char *p;
42
43 assert(path);
44
45 if (!is_device_path(path))
46 return 0;
47
48 p = unit_name_from_path(path, ".device");
49 if (!p)
50 return log_oom();
51
52 *unit = p;
53 return 1;
54 }
55
56 static int mount_find_pri(struct mntent *me, int *ret) {
57 char *end, *pri;
58 unsigned long r;
59
60 assert(me);
61 assert(ret);
62
63 pri = hasmntopt(me, "pri");
64 if (!pri)
65 return 0;
66
67 pri += 4;
68
69 errno = 0;
70 r = strtoul(pri, &end, 10);
71 if (errno != 0)
72 return -errno;
73
74 if (end == pri || (*end != ',' && *end != 0))
75 return -EINVAL;
76
77 *ret = (int) r;
78 return 1;
79 }
80
81 static int add_swap(const char *what, struct mntent *me) {
82 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
83 FILE *f = NULL;
84 bool noauto, nofail;
85 int r, pri = -1;
86
87 assert(what);
88 assert(me);
89
90 r = mount_find_pri(me, &pri);
91 if (r < 0) {
92 log_error("Failed to parse priority");
93 return pri;
94 }
95
96 noauto = !!hasmntopt(me, "noauto");
97 nofail = !!hasmntopt(me, "nofail");
98
99 name = unit_name_from_path(what, ".swap");
100 if (!name) {
101 r = log_oom();
102 goto finish;
103 }
104
105 unit = strjoin(arg_dest, "/", name, NULL);
106 if (!unit) {
107 r = log_oom();
108 goto finish;
109 }
110
111 f = fopen(unit, "wxe");
112 if (!f) {
113 r = -errno;
114 log_error("Failed to create unit file %s: %m", unit);
115 goto finish;
116 }
117
118 fputs("# Automatically generated by systemd-fstab-generator\n\n"
119 "[Unit]\n"
120 "SourcePath=/etc/fstab\n"
121 "DefaultDependencies=no\n"
122 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
123 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
124
125 if (!noauto && !nofail)
126 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
127
128 fprintf(f,
129 "\n"
130 "[Swap]\n"
131 "What=%s\n",
132 what);
133
134 if (pri >= 0)
135 fprintf(f,
136 "Priority=%i\n",
137 pri);
138
139 fflush(f);
140 if (ferror(f)) {
141 log_error("Failed to write unit file %s: %m", unit);
142 r = -errno;
143 goto finish;
144 }
145
146 if (!noauto) {
147 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
148 if (!lnk) {
149 r = log_oom();
150 goto finish;
151 }
152
153 mkdir_parents_label(lnk, 0755);
154 if (symlink(unit, lnk) < 0) {
155 log_error("Failed to create symlink %s: %m", lnk);
156 r = -errno;
157 goto finish;
158 }
159
160 r = device_name(what, &device);
161 if (r < 0)
162 goto finish;
163
164 if (r > 0) {
165 free(lnk);
166 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
167 if (!lnk) {
168 r = log_oom();
169 goto finish;
170 }
171
172 mkdir_parents_label(lnk, 0755);
173 if (symlink(unit, lnk) < 0) {
174 log_error("Failed to create symlink %s: %m", lnk);
175 r = -errno;
176 goto finish;
177 }
178 }
179 }
180
181 r = 0;
182 finish:
183 if (f)
184 fclose(f);
185
186 free(unit);
187 free(lnk);
188 free(name);
189 free(device);
190
191 return r;
192 }
193
194 static bool mount_is_bind(struct mntent *me) {
195 assert(me);
196
197 return hasmntopt(me, "bind");
198 }
199
200 static bool mount_is_network(struct mntent *me) {
201 assert(me);
202
203 return
204 hasmntopt(me, "_netdev") ||
205 fstype_is_network(me->mnt_type);
206 }
207
208 static int add_mount(const char *what, const char *where, struct mntent *me) {
209 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
210 FILE *f = NULL;
211 bool noauto, nofail, automount, isbind, isnetwork;
212 int r;
213 const char *post, *pre;
214
215 assert(what);
216 assert(where);
217 assert(me);
218
219 if (streq(me->mnt_type, "autofs"))
220 return 0;
221
222 if (!is_path(where)) {
223 log_warning("Mount point %s is not a valid path, ignoring.", where);
224 return 0;
225 }
226
227 if (mount_point_is_api(where) ||
228 mount_point_ignore(where))
229 return 0;
230
231 isnetwork = mount_is_network(me);
232 isbind = mount_is_bind(me);
233
234 noauto = !!hasmntopt(me, "noauto");
235 nofail = !!hasmntopt(me, "nofail");
236 automount =
237 hasmntopt(me, "comment=systemd.automount") ||
238 hasmntopt(me, "x-systemd.automount");
239
240 if (isnetwork) {
241 post = SPECIAL_REMOTE_FS_TARGET;
242 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
243 } else {
244 post = SPECIAL_LOCAL_FS_TARGET;
245 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
246 }
247
248 name = unit_name_from_path(where, ".mount");
249 if (!name) {
250 r = log_oom();
251 goto finish;
252 }
253
254 unit = strjoin(arg_dest, "/", name, NULL);
255 if (!unit) {
256 r = log_oom();
257 goto finish;
258 }
259
260 f = fopen(unit, "wxe");
261 if (!f) {
262 r = -errno;
263 log_error("Failed to create unit file %s: %m", unit);
264 goto finish;
265 }
266
267 fputs("# Automatically generated by systemd-fstab-generator\n\n"
268 "[Unit]\n"
269 "SourcePath=/etc/fstab\n"
270 "DefaultDependencies=no\n", f);
271
272 if (!path_equal(where, "/"))
273 fprintf(f,
274 "After=%s\n"
275 "Wants=%s\n"
276 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
277 "Before=" SPECIAL_UMOUNT_TARGET "\n",
278 pre,
279 pre);
280
281
282 if (!noauto && !nofail && !automount)
283 fprintf(f,
284 "Before=%s\n",
285 post);
286
287 fprintf(f,
288 "\n"
289 "[Mount]\n"
290 "What=%s\n"
291 "Where=%s\n"
292 "Type=%s\n"
293 "FsckPassNo=%i\n",
294 what,
295 where,
296 me->mnt_type,
297 me->mnt_passno);
298
299 if (!isempty(me->mnt_opts) &&
300 !streq(me->mnt_opts, "defaults"))
301 fprintf(f,
302 "Options=%s\n",
303 me->mnt_opts);
304
305 fflush(f);
306 if (ferror(f)) {
307 log_error("Failed to write unit file %s: %m", unit);
308 r = -errno;
309 goto finish;
310 }
311
312 if (!noauto) {
313 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
314 if (!lnk) {
315 r = log_oom();
316 goto finish;
317 }
318
319 mkdir_parents_label(lnk, 0755);
320 if (symlink(unit, lnk) < 0) {
321 log_error("Failed to create symlink %s: %m", lnk);
322 r = -errno;
323 goto finish;
324 }
325
326 if (!isbind &&
327 !path_equal(where, "/")) {
328
329 r = device_name(what, &device);
330 if (r < 0)
331 goto finish;
332
333 if (r > 0) {
334 free(lnk);
335 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
336 if (!lnk) {
337 r = log_oom();
338 goto finish;
339 }
340
341 mkdir_parents_label(lnk, 0755);
342 if (symlink(unit, lnk) < 0) {
343 log_error("Failed to create symlink %s: %m", lnk);
344 r = -errno;
345 goto finish;
346 }
347 }
348 }
349 }
350
351 if (automount && !path_equal(where, "/")) {
352 automount_name = unit_name_from_path(where, ".automount");
353 if (!name) {
354 r = log_oom();
355 goto finish;
356 }
357
358 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
359 if (!automount_unit) {
360 r = log_oom();
361 goto finish;
362 }
363
364 fclose(f);
365 f = fopen(automount_unit, "wxe");
366 if (!f) {
367 r = -errno;
368 log_error("Failed to create unit file %s: %m", automount_unit);
369 goto finish;
370 }
371
372 fprintf(f,
373 "# Automatically generated by systemd-fstab-generator\n\n"
374 "[Unit]\n"
375 "SourcePath=/etc/fstab\n"
376 "DefaultDependencies=no\n"
377 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
378 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
379 "\n"
380 "[Automount]\n"
381 "Where=%s\n",
382 post,
383 where);
384
385 fflush(f);
386 if (ferror(f)) {
387 log_error("Failed to write unit file %s: %m", automount_unit);
388 r = -errno;
389 goto finish;
390 }
391
392 free(lnk);
393 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
394 if (!lnk) {
395 r = log_oom();
396 goto finish;
397 }
398
399 mkdir_parents_label(lnk, 0755);
400 if (symlink(automount_unit, lnk) < 0) {
401 log_error("Failed to create symlink %s: %m", lnk);
402 r = -errno;
403 goto finish;
404 }
405 }
406
407 r = 0;
408 finish:
409 if (f)
410 fclose(f);
411
412 free(unit);
413 free(lnk);
414 free(name);
415 free(device);
416 free(automount_name);
417 free(automount_unit);
418
419 return r;
420 }
421
422 static int parse_fstab(void) {
423 FILE *f;
424 int r = 0;
425 struct mntent *me;
426
427 errno = 0;
428 f = setmntent("/etc/fstab", "r");
429 if (!f) {
430 if (errno == ENOENT)
431 return 0;
432
433 log_error("Failed to open /etc/fstab: %m");
434 return -errno;
435 }
436
437 while ((me = getmntent(f))) {
438 char *where, *what;
439 int k;
440
441 what = fstab_node_to_udev_node(me->mnt_fsname);
442 if (!what) {
443 r = log_oom();
444 goto finish;
445 }
446
447 where = strdup(me->mnt_dir);
448 if (!where) {
449 r = log_oom();
450 free(what);
451 goto finish;
452 }
453
454 if (is_path(where))
455 path_kill_slashes(where);
456
457 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
458
459 if (streq(me->mnt_type, "swap"))
460 k = add_swap(what, me);
461 else
462 k = add_mount(what, where, me);
463
464 free(what);
465 free(where);
466
467 if (k < 0)
468 r = k;
469 }
470
471 finish:
472 endmntent(f);
473 return r;
474 }
475
476 static int parse_proc_cmdline(void) {
477 char *line, *w, *state;
478 int r;
479 size_t l;
480
481 if (detect_container(NULL) > 0)
482 return 0;
483
484 r = read_one_line_file("/proc/cmdline", &line);
485 if (r < 0) {
486 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
487 return 0;
488 }
489
490 FOREACH_WORD_QUOTED(w, l, line, state) {
491 char *word;
492
493 word = strndup(w, l);
494 if (!word) {
495 r = log_oom();
496 goto finish;
497 }
498
499 if (startswith(word, "fstab=")) {
500 r = parse_boolean(word + 6);
501 if (r < 0)
502 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
503 else
504 arg_enabled = r;
505
506 } else if (startswith(word, "rd.fstab=")) {
507
508 if (in_initrd()) {
509 r = parse_boolean(word + 6);
510 if (r < 0)
511 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
512 else
513 arg_enabled = r;
514 }
515
516 } else if (startswith(word, "fstab.") ||
517 (in_initrd() && startswith(word, "rd.fstab."))) {
518
519 log_warning("Unknown kernel switch %s. Ignoring.", word);
520 }
521
522 free(word);
523 }
524
525 r = 0;
526
527 finish:
528 free(line);
529 return r;
530 }
531
532 int main(int argc, char *argv[]) {
533 int r;
534
535 if (argc > 1 && argc != 4) {
536 log_error("This program takes three or no arguments.");
537 return EXIT_FAILURE;
538 }
539
540 if (argc > 1)
541 arg_dest = argv[1];
542
543 log_set_target(LOG_TARGET_SAFE);
544 log_parse_environment();
545 log_open();
546
547 umask(0022);
548
549 if (parse_proc_cmdline() < 0)
550 return EXIT_FAILURE;
551
552 if (!arg_enabled)
553 return EXIT_SUCCESS;
554
555 r = parse_fstab();
556
557 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
558 }