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