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