]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/fsck/fsck.c
sysv-generator test: Fix assertion
[thirdparty/systemd.git] / src / fsck / fsck.c
CommitLineData
3d20ed6d
LP
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
f1f0198c 7 Copyright 2014 Holger Hans Peter Freyther
3d20ed6d
LP
8
9 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
3d20ed6d
LP
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 17 Lesser General Public License for more details.
3d20ed6d 18
5430f7f2 19 You should have received a copy of the GNU Lesser General Public License
3d20ed6d
LP
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
23#include <stdio.h>
24#include <stdbool.h>
3d20ed6d
LP
25#include <errno.h>
26#include <unistd.h>
a84f5192 27#include <fcntl.h>
27d340c7 28#include <sys/file.h>
ac6e2f0d 29#include <sys/stat.h>
3d20ed6d 30
0c842e0a 31#include "sd-bus.h"
9102fdc5 32#include "sd-device.h"
3d20ed6d
LP
33
34#include "util.h"
0b452006 35#include "process-util.h"
3d20ed6d 36#include "special.h"
0c842e0a
TG
37#include "bus-util.h"
38#include "bus-error.h"
96aad8d1 39#include "bus-common-errors.h"
9102fdc5 40#include "device-util.h"
eb66db55 41#include "path-util.h"
ac6e2f0d
DR
42#include "socket-util.h"
43#include "fsckd/fsckd.h"
3d20ed6d
LP
44
45static bool arg_skip = false;
46static bool arg_force = false;
f1f0198c 47static const char *arg_repair = "-a";
3d20ed6d 48
80cfe9e1 49static void start_target(const char *target) {
0c842e0a 50 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
24996861 51 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
0c842e0a 52 int r;
3d20ed6d
LP
53
54 assert(target);
55
0f8bd8de 56 r = bus_open_system_systemd(&bus);
0c842e0a 57 if (r < 0) {
da927ba9 58 log_error_errno(r, "Failed to get D-Bus connection: %m");
0c842e0a 59 return;
3d20ed6d
LP
60 }
61
0c842e0a 62 log_info("Running request %s/start/replace", target);
3d20ed6d 63
90bb85e1 64 /* Start these units only if we can replace base.target with it */
0c842e0a
TG
65 r = sd_bus_call_method(bus,
66 "org.freedesktop.systemd1",
67 "/org/freedesktop/systemd1",
68 "org.freedesktop.systemd1.Manager",
69 "StartUnitReplace",
70 &error,
71 NULL,
72 "sss", "basic.target", target, "replace");
3d20ed6d 73
5220a6f3
LP
74 /* Don't print a warning if we aren't called during startup */
75 if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
76 log_error("Failed to start unit: %s", bus_error_message(&error, -r));
3d20ed6d
LP
77}
78
059cb385
LP
79static int parse_proc_cmdline_item(const char *key, const char *value) {
80
81 if (streq(key, "fsck.mode") && value) {
82
83 if (streq(value, "auto"))
84 arg_force = arg_skip = false;
85 else if (streq(value, "force"))
86 arg_force = true;
87 else if (streq(value, "skip"))
88 arg_skip = true;
89 else
85013844
LP
90 log_warning("Invalid fsck.mode= parameter '%s'. Ignoring.", value);
91
f1f0198c
HHPF
92 } else if (streq(key, "fsck.repair") && value) {
93
94 if (streq(value, "preen"))
95 arg_repair = "-a";
96 else if (streq(value, "yes"))
97 arg_repair = "-y";
98 else if (streq(value, "no"))
99 arg_repair = "-n";
100 else
85013844
LP
101 log_warning("Invalid fsck.repair= parameter '%s'. Ignoring.", value);
102 }
103
32f992a5 104#ifdef HAVE_SYSV_COMPAT
059cb385
LP
105 else if (streq(key, "fastboot") && !value) {
106 log_warning("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
141a79f4 107 arg_skip = true;
85013844 108
059cb385
LP
109 } else if (streq(key, "forcefsck") && !value) {
110 log_warning("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line.");
141a79f4 111 arg_force = true;
3d20ed6d 112 }
141a79f4 113#endif
3d20ed6d 114
3d20ed6d
LP
115 return 0;
116}
117
118static void test_files(void) {
85013844 119
32f992a5
LP
120#ifdef HAVE_SYSV_COMPAT
121 if (access("/fastboot", F_OK) >= 0) {
122 log_error("Please pass 'fsck.mode=skip' on the kernel command line rather than creating /fastboot on the root file system.");
3d20ed6d 123 arg_skip = true;
32f992a5 124 }
3d20ed6d 125
32f992a5
LP
126 if (access("/forcefsck", F_OK) >= 0) {
127 log_error("Please pass 'fsck.mode=force' on the kernel command line rather than creating /forcefsck on the root file system.");
3d20ed6d 128 arg_force = true;
32f992a5
LP
129 }
130#endif
27d340c7 131
27d340c7
LP
132}
133
07f9a21b 134static int process_progress(int fd, pid_t fsck_pid, dev_t device_num) {
ac6e2f0d
DR
135 _cleanup_fclose_ FILE *f = NULL;
136 usec_t last = 0;
137 _cleanup_close_ int fsckd_fd = -1;
138 static const union sockaddr_union sa = {
139 .un.sun_family = AF_UNIX,
140 .un.sun_path = FSCKD_SOCKET_PATH,
27d340c7
LP
141 };
142
ac6e2f0d
DR
143 fsckd_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
144 if (fsckd_fd < 0)
145 return log_warning_errno(errno, "Cannot open fsckd socket, we won't report fsck progress: %m");
146 if (connect(fsckd_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
147 return log_warning_errno(errno, "Cannot connect to fsckd socket, we won't report fsck progress: %m");
27d340c7
LP
148
149 f = fdopen(fd, "r");
ac6e2f0d
DR
150 if (!f)
151 return log_warning_errno(errno, "Cannot connect to fsck, we won't report fsck progress: %m");
27d340c7
LP
152
153 while (!feof(f)) {
ac6e2f0d 154 int pass;
07f9a21b 155 size_t buflen;
ac6e2f0d 156 size_t cur, max;
07f9a21b 157 ssize_t r;
27d340c7 158 usec_t t;
ac6e2f0d
DR
159 _cleanup_free_ char *device = NULL;
160 FsckProgress progress;
07f9a21b 161 FsckdMessage fsckd_message;
27d340c7 162
1bc48c04 163 if (fscanf(f, "%i %zu %zu %ms", &pass, &cur, &max, &device) != 4)
27d340c7
LP
164 break;
165
27d340c7
LP
166 /* Only update once every 50ms */
167 t = now(CLOCK_MONOTONIC);
e375825d 168 if (last + 50 * USEC_PER_MSEC > t)
27d340c7 169 continue;
27d340c7
LP
170
171 last = t;
172
ac6e2f0d
DR
173 /* send progress to fsckd */
174 progress.devnum = device_num;
175 progress.cur = cur;
176 progress.max = max;
177 progress.pass = pass;
27d340c7 178
07f9a21b
DR
179 r = send(fsckd_fd, &progress, sizeof(FsckProgress), 0);
180 if (r < 0 || (size_t) r < sizeof(FsckProgress))
ac6e2f0d 181 log_warning_errno(errno, "Cannot communicate fsck progress to fsckd: %m");
07f9a21b
DR
182
183 /* get fsckd requests, only read when we have coherent size data */
184 r = ioctl(fsckd_fd, FIONREAD, &buflen);
185 if (r == 0 && (size_t) buflen >= sizeof(FsckdMessage)) {
186 r = recv(fsckd_fd, &fsckd_message, sizeof(FsckdMessage), 0);
187 if (r > 0 && fsckd_message.cancel == 1) {
188 log_info("Request to cancel fsck from fsckd");
189 kill(fsck_pid, SIGTERM);
190 }
191 }
27d340c7
LP
192 }
193
27d340c7 194 return 0;
3d20ed6d
LP
195}
196
197int main(int argc, char *argv[]) {
27d340c7 198 const char *cmdline[9];
3d20ed6d
LP
199 int i = 0, r = EXIT_FAILURE, q;
200 pid_t pid;
07f9a21b 201 int progress_rc;
3d20ed6d 202 siginfo_t status;
9102fdc5 203 _cleanup_device_unref_ sd_device *dev = NULL;
94192cda 204 const char *device, *type;
dc8e15c2 205 bool root_directory;
1952708a 206 _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 };
5ffa8c81 207 char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1];
94192cda 208 struct stat st;
3d20ed6d 209
a9e1f5ec
LP
210 if (argc > 2) {
211 log_error("This program expects one or no arguments.");
3d20ed6d
LP
212 return EXIT_FAILURE;
213 }
214
27d340c7 215 log_set_target(LOG_TARGET_AUTO);
3d20ed6d
LP
216 log_parse_environment();
217 log_open();
218
4c12626c
LP
219 umask(0022);
220
b5884878
LP
221 q = parse_proc_cmdline(parse_proc_cmdline_item);
222 if (q < 0)
da927ba9 223 log_warning_errno(q, "Failed to parse kernel command line, ignoring: %m");
b5884878 224
3d20ed6d
LP
225 test_files();
226
566690fd
LP
227 if (!arg_force && arg_skip) {
228 r = 0;
229 goto finish;
230 }
a9e1f5ec 231
dc8e15c2 232 if (argc > 1) {
a9e1f5ec 233 device = argv[1];
dc8e15c2 234 root_directory = false;
94192cda
ZJS
235
236 if (stat(device, &st) < 0) {
566690fd
LP
237 r = log_error_errno(errno, "Failed to stat '%s': %m", device);
238 goto finish;
94192cda
ZJS
239 }
240
9102fdc5
TG
241 r = sd_device_new_from_devnum(&dev, 'b', st.st_rdev);
242 if (r < 0) {
243 log_error_errno(r, "Failed to detect device %s: %m", device);
566690fd 244 goto finish;
94192cda 245 }
dc8e15c2 246 } else {
a84f5192 247 struct timespec times[2];
3d20ed6d 248
a9e1f5ec
LP
249 /* Find root device */
250
251 if (stat("/", &st) < 0) {
566690fd
LP
252 r = log_error_errno(errno, "Failed to stat() the root directory: %m");
253 goto finish;
a9e1f5ec
LP
254 }
255
256 /* Virtual root devices don't need an fsck */
566690fd
LP
257 if (major(st.st_dev) == 0) {
258 log_debug("Root directory is virtual, skipping check.");
259 r = 0;
260 goto finish;
261 }
a9e1f5ec 262
a84f5192
KS
263 /* check if we are already writable */
264 times[0] = st.st_atim;
265 times[1] = st.st_mtim;
266 if (utimensat(AT_FDCWD, "/", times, 0) == 0) {
cf1a1055 267 log_info("Root directory is writable, skipping check.");
566690fd
LP
268 r = 0;
269 goto finish;
a84f5192
KS
270 }
271
9102fdc5
TG
272 r = sd_device_new_from_devnum(&dev, 'b', st.st_dev);
273 if (r < 0) {
274 log_error_errno(r, "Failed to detect root device: %m");
566690fd 275 goto finish;
a9e1f5ec
LP
276 }
277
9102fdc5
TG
278 r = sd_device_get_devname(dev, &device);
279 if (r < 0) {
280 log_error_errno(r, "Failed to detect device node of root directory: %m");
566690fd
LP
281 r = -ENXIO;
282 goto finish;
3e33a44a 283 }
dc8e15c2
LP
284
285 root_directory = true;
3d20ed6d
LP
286 }
287
9102fdc5
TG
288 r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
289 if (r >= 0) {
eb66db55 290 r = fsck_exists(type);
571d0134
LP
291 if (r == -ENOENT) {
292 log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
566690fd
LP
293 r = 0;
294 goto finish;
571d0134 295 } else if (r < 0)
da927ba9 296 log_warning_errno(r, "fsck.%s cannot be used for %s: %m", type, device);
94192cda
ZJS
297 }
298
19e887e7 299 if (pipe(progress_pipe) < 0) {
566690fd
LP
300 r = log_error_errno(errno, "pipe(): %m");
301 goto finish;
19e887e7 302 }
27d340c7 303
3d20ed6d 304 cmdline[i++] = "/sbin/fsck";
f1f0198c 305 cmdline[i++] = arg_repair;
3d20ed6d 306 cmdline[i++] = "-T";
c343be28
KS
307
308 /*
48d3e8d0
KZ
309 * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files.
310 * The previous versions use flock for the device and conflict with
311 * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5
c343be28 312 */
48d3e8d0 313 cmdline[i++] = "-l";
dc8e15c2
LP
314
315 if (!root_directory)
316 cmdline[i++] = "-M";
3d20ed6d
LP
317
318 if (arg_force)
319 cmdline[i++] = "-f";
320
576a13ea
ZJS
321 xsprintf(dash_c, "-C%i", progress_pipe[1]);
322 cmdline[i++] = dash_c;
27d340c7 323
a9e1f5ec 324 cmdline[i++] = device;
3d20ed6d
LP
325 cmdline[i++] = NULL;
326
27d340c7
LP
327 pid = fork();
328 if (pid < 0) {
566690fd 329 r = log_error_errno(errno, "fork(): %m");
3d20ed6d
LP
330 goto finish;
331 } else if (pid == 0) {
332 /* Child */
1952708a 333 progress_pipe[0] = safe_close(progress_pipe[0]);
3d20ed6d
LP
334 execv(cmdline[0], (char**) cmdline);
335 _exit(8); /* Operational error */
336 }
337
03e334a1 338 progress_pipe[1] = safe_close(progress_pipe[1]);
27d340c7 339
576a13ea
ZJS
340 progress_rc = process_progress(progress_pipe[0], pid, st.st_rdev);
341 progress_pipe[0] = -1;
27d340c7 342
566690fd
LP
343 r = wait_for_terminate(pid, &status);
344 if (r < 0) {
345 log_error_errno(r, "waitid(): %m");
3d20ed6d
LP
346 goto finish;
347 }
348
07f9a21b 349 if (status.si_code != CLD_EXITED || (status.si_status & ~1) || progress_rc != 0) {
3d20ed6d 350
07f9a21b
DR
351 /* cancel will kill fsck (but process_progress returns 0) */
352 if ((progress_rc != 0 && status.si_code == CLD_KILLED) || status.si_code == CLD_DUMPED)
a9e1f5ec
LP
353 log_error("fsck terminated by signal %s.", signal_to_string(status.si_status));
354 else if (status.si_code == CLD_EXITED)
355 log_error("fsck failed with error code %i.", status.si_status);
07f9a21b 356 else if (progress_rc != 0)
a9e1f5ec 357 log_error("fsck failed due to unknown reason.");
3d20ed6d 358
566690fd
LP
359 r = -EINVAL;
360
a4c24ff7 361 if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory)
3d20ed6d 362 /* System should be rebooted. */
80cfe9e1 363 start_target(SPECIAL_REBOOT_TARGET);
a4c24ff7 364 else if (status.si_code == CLD_EXITED && (status.si_status & 6))
3d20ed6d 365 /* Some other problem */
80cfe9e1 366 start_target(SPECIAL_EMERGENCY_TARGET);
a4c24ff7 367 else {
566690fd 368 r = 0;
07f9a21b
DR
369 if (progress_rc != 0)
370 log_warning("Ignoring error.");
a4c24ff7 371 }
3d20ed6d
LP
372
373 } else
566690fd 374 r = 0;
3d20ed6d 375
a9e1f5ec 376 if (status.si_code == CLD_EXITED && (status.si_status & 1))
2b583ce6 377 touch("/run/systemd/quotacheck");
3d20ed6d
LP
378
379finish:
566690fd 380 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
3d20ed6d 381}