chiark / gitweb /
Revert "cgroup.c: check return value of unit_realize_cgroup_now()"
[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                 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, NULL)) {
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 }