chiark / gitweb /
enable localization for common *ctl commands
[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, /usr and all API VFS */
83                 if (!mount_point_is_api(me->mnt_dir) &&
84                     !path_equal(me->mnt_dir, "/") &&
85                     !path_equal(me->mnt_dir, "/usr"))
86                         continue;
87
88                 log_debug("Remounting %s", me->mnt_dir);
89
90                 pid = fork();
91                 if (pid < 0) {
92                         log_error("Failed to fork: %m");
93                         ret = EXIT_FAILURE;
94                         continue;
95                 }
96
97                 if (pid == 0) {
98                         const char *arguments[5];
99                         /* Child */
100
101                         arguments[0] = "/bin/mount";
102                         arguments[1] = me->mnt_dir;
103                         arguments[2] = "-o";
104                         arguments[3] = "remount";
105                         arguments[4] = NULL;
106
107                         execv("/bin/mount", (char **) arguments);
108
109                         log_error("Failed to execute /bin/mount: %m");
110                         _exit(EXIT_FAILURE);
111                 }
112
113                 /* Parent */
114
115                 s = strdup(me->mnt_dir);
116                 if (!s) {
117                         log_oom();
118                         ret = EXIT_FAILURE;
119                         continue;
120                 }
121
122
123                 k = hashmap_put(pids, UINT_TO_PTR(pid), s);
124                 if (k < 0) {
125                         log_error("Failed to add PID to set: %s", strerror(-k));
126                         ret = EXIT_FAILURE;
127                         continue;
128                 }
129         }
130
131         while (!hashmap_isempty(pids)) {
132                 siginfo_t si;
133                 char *s;
134
135                 zero(si);
136                 if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
137
138                         if (errno == EINTR)
139                                 continue;
140
141                         log_error("waitid() failed: %m");
142                         ret = EXIT_FAILURE;
143                         break;
144                 }
145
146                 s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
147                 if (s) {
148                         if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
149                                 if (si.si_code == CLD_EXITED)
150                                         log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status);
151                                 else
152                                         log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status));
153
154                                 ret = EXIT_FAILURE;
155                         }
156
157                         free(s);
158                 }
159         }
160
161 finish:
162
163         if (pids)
164                 hashmap_free_free(pids);
165
166         if (f)
167                 endmntent(f);
168
169         return ret;
170 }