fsck.c revision 5220a6f3a1f5a7324898ecfe7649af254cf561a6
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/***
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering This file is part of systemd.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Copyright 2010 Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is free software; you can redistribute it and/or modify it
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering under the terms of the GNU Lesser General Public License as published by
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (at your option) any later version.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is distributed in the hope that it will be useful, but
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Lesser General Public License for more details.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering You should have received a copy of the GNU Lesser General Public License
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering***/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <stdio.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <stdbool.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <string.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <errno.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <unistd.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <fcntl.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <sys/file.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "sd-bus.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "libudev.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "special.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "bus-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "bus-error.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "bus-errors.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "virt.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "fileio.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "udev-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_skip = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_force = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_show_progress = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void start_target(const char *target) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_bus_unref_ sd_bus *bus = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(target);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = bus_open_system_systemd(&bus);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Failed to get D-Bus connection: %s", strerror(-r));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_info("Running request %s/start/replace", target);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Start these units only if we can replace base.target with it */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_bus_call_method(bus,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "org.freedesktop.systemd1",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "/org/freedesktop/systemd1",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "org.freedesktop.systemd1.Manager",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "StartUnitReplace",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering &error,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering NULL,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "sss", "basic.target", target, "replace");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Don't print a warning if we aren't called during startup */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Failed to start unit: %s", bus_error_message(&error, -r));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int parse_proc_cmdline(void) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *line, *w, *state;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering size_t l;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (detect_container(NULL) > 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = read_one_line_file("/proc/cmdline", &line);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering FOREACH_WORD_QUOTED(w, l, line, state) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (strneq(w, "fsck.mode=auto", l))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_force = arg_skip = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (strneq(w, "fsck.mode=force", l))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_force = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (strneq(w, "fsck.mode=skip", l))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_skip = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (startswith(w, "fsck"))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_warning("Invalid fsck parameter. Ignoring.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_SYSV_COMPAT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (strneq(w, "fastboot", l)) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_skip = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else if (strneq(w, "forcefsck", l)) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_force = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(line);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void test_files(void) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#ifdef HAVE_SYSV_COMPAT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (access("/fastboot", F_OK) >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Please pass 'fsck.mode=skip' on the kernel command line rather than creating /fastboot on the root file system.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_skip = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (access("/forcefsck", F_OK) >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Please pass 'fsck.mode=force' on the kernel command line rather than creating /forcefsck on the root file system.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_force = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#endif
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running())
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering arg_show_progress = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic double percent(int pass, unsigned long cur, unsigned long max) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Values stolen from e2fsck */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering static const int pass_table[] = {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering 0, 70, 90, 92, 95, 100
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering };
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (pass <= 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0.0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 100.0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return (double) pass_table[pass-1] +
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ((double) pass_table[pass] - (double) pass_table[pass-1]) *
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (double) cur / (double) max;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int process_progress(int fd) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering FILE *f, *console;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering usec_t last = 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering bool locked = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int clear = 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering f = fdopen(fd, "r");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!f) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering close_nointr_nofail(fd);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return -errno;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering console = fopen("/dev/console", "w");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!console) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fclose(f);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return -ENOMEM;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering while (!feof(f)) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int pass, m;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering unsigned long cur, max;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *device;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering double p;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering usec_t t;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering break;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Only show one progress counter at max */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!locked) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(device);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering continue;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering locked = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Only update once every 50ms */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering t = now(CLOCK_MONOTONIC);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (last + 50 * USEC_PER_MSEC > t) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(device);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering continue;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering last = t;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p = percent(pass, cur, max);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fflush(console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering free(device);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (m > clear)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering clear = m;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (clear > 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering unsigned j;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fputc('\r', console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (j = 0; j < (unsigned) clear; j++)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fputc(' ', console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fputc('\r', console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fflush(console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fclose(f);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fclose(console);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringint main(int argc, char *argv[]) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *cmdline[9];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int i = 0, r = EXIT_FAILURE, q;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering pid_t pid;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering siginfo_t status;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *device;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering bool root_directory;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int progress_pipe[2] = { -1, -1 };
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char dash_c[2+10+1];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (argc > 2) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("This program expects one or no arguments.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return EXIT_FAILURE;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_set_target(LOG_TARGET_AUTO);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_parse_environment();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_open();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering umask(0022);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering parse_proc_cmdline();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering test_files();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!arg_force && arg_skip)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (argc > 1) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering device = argv[1];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering root_directory = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct stat st;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct timespec times[2];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Find root device */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (stat("/", &st) < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Failed to stat() the root directory: %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Virtual root devices don't need an fsck */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (major(st.st_dev) == 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* check if we are already writable */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering times[0] = st.st_atim;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering times[1] = st.st_mtim;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (utimensat(AT_FDCWD, "/", times, 0) == 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_info("Root directory is writable, skipping check.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!(udev = udev_new())) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_oom();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!(udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev))) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Failed to detect root device.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!(device = udev_device_get_devnode(udev_device))) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("Failed to detect device node of root directory.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering root_directory = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (arg_show_progress)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (pipe(progress_pipe) < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("pipe(): %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "/sbin/fsck";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "-a";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "-T";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "-l";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!root_directory)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "-M";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (arg_force)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = "-f";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (progress_pipe[1] >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering snprintf(dash_c, sizeof(dash_c), "-C%i", progress_pipe[1]);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char_array_0(dash_c);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = dash_c;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = device;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering cmdline[i++] = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering pid = fork();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (pid < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("fork(): %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else if (pid == 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Child */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (progress_pipe[0] >= 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering close_nointr_nofail(progress_pipe[0]);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering execv(cmdline[0], (char**) cmdline);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _exit(8); /* Operational error */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (progress_pipe[1] >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering close_nointr_nofail(progress_pipe[1]);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering progress_pipe[1] = -1;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (progress_pipe[0] >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering process_progress(progress_pipe[0]);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering progress_pipe[0] = -1;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering q = wait_for_terminate(pid, &status);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (q < 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("waitid(): %s", strerror(-q));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering goto finish;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (status.si_code != CLD_EXITED || (status.si_status & ~1)) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("fsck terminated by signal %s.", signal_to_string(status.si_status));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (status.si_code == CLD_EXITED)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("fsck failed with error code %i.", status.si_status);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_error("fsck failed due to unknown reason.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* System should be rebooted. */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering start_target(SPECIAL_REBOOT_TARGET);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (status.si_code == CLD_EXITED && (status.si_status & 6))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* Some other problem */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering start_target(SPECIAL_EMERGENCY_TARGET);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = EXIT_SUCCESS;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_warning("Ignoring error.");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = EXIT_SUCCESS;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (status.si_code == CLD_EXITED && (status.si_status & 1))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering touch("/run/systemd/quotacheck");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringfinish:
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering close_pipe(progress_pipe);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return r;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering