chiark / gitweb /
ef68e506e5097da4628acad62cb5af547a800042
[elogind.git] / src / remount-fs / remount-fs.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 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 <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <mntent.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "path-util.h"
33 #include "set.h"
34 #include "mount-setup.h"
35 #include "exit-status.h"
36
37 /* Goes through /etc/fstab and remounts all API file systems, applying
38  * options that are in /etc/fstab that systemd might not have
39  * respected */
40
41 int main(int argc, char *argv[]) {
42         int ret = EXIT_FAILURE;
43         FILE *f = NULL;
44         struct mntent* me;
45         Hashmap *pids = NULL;
46
47         if (argc > 1) {
48                 log_error("This program takes no argument.");
49                 return EXIT_FAILURE;
50         }
51
52         log_set_target(LOG_TARGET_AUTO);
53         log_parse_environment();
54         log_open();
55
56         umask(0022);
57
58         f = setmntent("/etc/fstab", "r");
59         if (!f) {
60                 if (errno == ENOENT) {
61                         ret = EXIT_SUCCESS;
62                         goto finish;
63                 }
64
65                 log_error("Failed to open /etc/fstab: %m");
66                 goto finish;
67         }
68
69         pids = hashmap_new(trivial_hash_func, trivial_compare_func);
70         if (!pids) {
71                 log_error("Failed to allocate set");
72                 goto finish;
73         }
74
75         ret = EXIT_SUCCESS;
76
77         while ((me = getmntent(f))) {
78                 pid_t pid;
79                 int k;
80                 char *s;
81
82                 /* Remount the root fs and all API VFS */
83                 if (!mount_point_is_api(me->mnt_dir) &&
84                     !path_equal(me->mnt_dir, "/"))
85                         continue;
86
87                 log_debug("Remounting %s", me->mnt_dir);
88
89                 pid = fork();
90                 if (pid < 0) {
91                         log_error("Failed to fork: %m");
92                         ret = EXIT_FAILURE;
93                         continue;
94                 }
95
96                 if (pid == 0) {
97                         const char *arguments[5];
98                         /* Child */
99
100                         arguments[0] = "/bin/mount";
101                         arguments[1] = me->mnt_dir;
102                         arguments[2] = "-o";
103                         arguments[3] = "remount";
104                         arguments[4] = NULL;
105
106                         execv("/bin/mount", (char **) arguments);
107
108                         log_error("Failed to execute /bin/mount: %m");
109                         _exit(EXIT_FAILURE);
110                 }
111
112                 /* Parent */
113
114                 s = strdup(me->mnt_dir);
115                 if (!s) {
116                         log_error("Out of memory.");
117                         ret = EXIT_FAILURE;
118                         continue;
119                 }
120
121
122                 k = hashmap_put(pids, UINT_TO_PTR(pid), s);
123                 if (k < 0) {
124                         log_error("Failed to add PID to set: %s", strerror(-k));
125                         ret = EXIT_FAILURE;
126                         continue;
127                 }
128         }
129
130         while (!hashmap_isempty(pids)) {
131                 siginfo_t si;
132                 char *s;
133
134                 zero(si);
135                 if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
136
137                         if (errno == EINTR)
138                                 continue;
139
140                         log_error("waitid() failed: %m");
141                         ret = EXIT_FAILURE;
142                         break;
143                 }
144
145                 s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
146                 if (s) {
147                         if (!is_clean_exit(si.si_code, si.si_status)) {
148                                 if (si.si_code == CLD_EXITED)
149                                         log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status);
150                                 else
151                                         log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status));
152
153                                 ret = EXIT_FAILURE;
154                         }
155
156                         free(s);
157                 }
158         }
159
160 finish:
161
162         if (pids)
163                 hashmap_free_free(pids);
164
165         if (f)
166                 endmntent(f);
167
168         return ret;
169 }