1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
30 #include "unit-name.h"
31 #include "path-util.h"
32 #include "mount-setup.h"
37 static const char *arg_dest = "/tmp";
38 static bool arg_enabled = true;
40 static int device_name(const char *path, char **unit) {
45 if (!is_device_path(path))
48 p = unit_name_from_path(path, ".device");
56 static int mount_find_pri(struct mntent *me, int *ret) {
63 pri = hasmntopt(me, "pri");
70 r = strtoul(pri, &end, 10);
74 if (end == pri || (*end != ',' && *end != 0))
81 static int add_swap(const char *what, struct mntent *me) {
82 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
90 r = mount_find_pri(me, &pri);
92 log_error("Failed to parse priority");
96 noauto = !!hasmntopt(me, "noauto");
97 nofail = !!hasmntopt(me, "nofail");
99 name = unit_name_from_path(what, ".swap");
105 unit = strjoin(arg_dest, "/", name, NULL);
111 f = fopen(unit, "wxe");
114 log_error("Failed to create unit file: %m");
118 fputs("# Automatically generated by systemd-fstab-generator\n\n"
120 "SourcePath=/etc/fstab\n"
121 "DefaultDependencies=no\n"
122 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
123 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
125 if (!noauto && !nofail)
126 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
141 log_error("Failed to write unit file: %m");
147 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
153 mkdir_parents_label(lnk, 0755);
154 if (symlink(unit, lnk) < 0) {
155 log_error("Failed to create symlink: %m");
160 r = device_name(what, &device);
166 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
172 mkdir_parents_label(lnk, 0755);
173 if (symlink(unit, lnk) < 0) {
174 log_error("Failed to create symlink: %m");
194 static bool mount_is_bind(struct mntent *me) {
198 hasmntopt(me, "bind") ||
199 streq(me->mnt_opts, "bind");
202 static bool mount_is_network(struct mntent *me) {
206 hasmntopt(me, "_netdev") ||
207 fstype_is_network(me->mnt_type);
210 static int add_mount(const char *what, const char *where, struct mntent *me) {
211 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
213 bool noauto, nofail, automount, isbind, isnetwork;
215 const char *post, *pre;
221 if (streq(me->mnt_type, "autofs"))
224 if (!is_path(where)) {
225 log_warning("Mount point %s is not a valid path, ignoring.", where);
229 if (mount_point_is_api(where) ||
230 mount_point_ignore(where))
233 isnetwork = mount_is_network(me);
234 isbind = mount_is_bind(me);
236 noauto = !!hasmntopt(me, "noauto");
237 nofail = !!hasmntopt(me, "nofail");
239 hasmntopt(me, "comment=systemd.automount") ||
240 hasmntopt(me, "x-systemd.automount");
243 post = SPECIAL_REMOTE_FS_TARGET;
244 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
246 post = SPECIAL_LOCAL_FS_TARGET;
247 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
250 name = unit_name_from_path(where, ".mount");
256 unit = strjoin(arg_dest, "/", name, NULL);
262 f = fopen(unit, "wxe");
265 log_error("Failed to create unit file: %m");
269 fputs("# Automatically generated by systemd-fstab-generator\n\n"
271 "SourcePath=/etc/fstab\n"
272 "DefaultDependencies=no\n", f);
274 if (!path_equal(where, "/"))
278 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
279 "Before=" SPECIAL_UMOUNT_TARGET "\n",
284 if (!noauto && !nofail && !automount)
301 if (!isempty(me->mnt_opts) &&
302 !streq(me->mnt_opts, "defaults"))
309 log_error("Failed to write unit file: %m");
315 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
321 mkdir_parents_label(lnk, 0755);
322 if (symlink(unit, lnk) < 0) {
323 log_error("Failed to create symlink: %m");
329 !path_equal(where, "/")) {
331 r = device_name(what, &device);
337 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
343 mkdir_parents_label(lnk, 0755);
344 if (symlink(unit, lnk) < 0) {
345 log_error("Failed to create symlink: %m");
353 if (automount && !path_equal(where, "/")) {
354 automount_name = unit_name_from_path(where, ".automount");
360 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
361 if (!automount_unit) {
367 f = fopen(automount_unit, "wxe");
370 log_error("Failed to create unit file: %m");
375 "# Automatically generated by systemd-fstab-generator\n\n"
377 "SourcePath=/etc/fstab\n"
378 "DefaultDependencies=no\n"
379 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
380 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
389 log_error("Failed to write unit file: %m");
395 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
401 mkdir_parents_label(lnk, 0755);
402 if (symlink(automount_unit, lnk) < 0) {
403 log_error("Failed to create symlink: %m");
418 free(automount_name);
419 free(automount_unit);
424 static int parse_fstab(void) {
430 f = setmntent("/etc/fstab", "r");
435 log_error("Failed to open /etc/fstab: %m");
439 while ((me = getmntent(f))) {
443 what = fstab_node_to_udev_node(me->mnt_fsname);
449 where = strdup(me->mnt_dir);
457 path_kill_slashes(where);
459 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
461 if (streq(me->mnt_type, "swap"))
462 k = add_swap(what, me);
464 k = add_mount(what, where, me);
478 static int parse_proc_cmdline(void) {
479 char *line, *w, *state;
483 if (detect_container(NULL) > 0)
486 r = read_one_line_file("/proc/cmdline", &line);
488 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
492 FOREACH_WORD_QUOTED(w, l, line, state) {
495 word = strndup(w, l);
501 if (startswith(word, "fstab=")) {
502 r = parse_boolean(word + 6);
504 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
508 } else if (startswith(word, "rd.fstab=")) {
511 r = parse_boolean(word + 6);
513 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
518 } else if (startswith(word, "fstab.") ||
519 (in_initrd() && startswith(word, "rd.fstab."))) {
521 log_warning("Unknown kernel switch %s. Ignoring.", word);
534 int main(int argc, char *argv[]) {
537 if (argc > 1 && argc != 4) {
538 log_error("This program takes three or no arguments.");
545 log_set_target(LOG_TARGET_SAFE);
546 log_parse_environment();
551 if (parse_proc_cmdline() < 0)
559 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;