From 94f099d8132da7987a5dbe930dadf31aaded9a11 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Sep 2015 17:04:43 +0200 Subject: systemctl: make "systemctl is-system-running" return "offline" if we are not booted with systemd This sounds like the better place to expose this than in "systemd-notify --booted". Also document the so far undocumented "unknown" state the command might return. And rearrange the table of states documented to be more like the one for "is-running". Also, don't document the precise exit code of this function, just say errors are reported != 0 or > 0... --- man/systemctl.xml | 50 +++++++++++++++++++++++++++++++++++++------------- man/systemd-notify.xml | 7 ++++++- 2 files changed, 43 insertions(+), 14 deletions(-) (limited to 'man') diff --git a/man/systemctl.xml b/man/systemctl.xml index c1359d1678..9e9ba5a5b6 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1120,9 +1120,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service - Printed string - Meaning - Return value + Name + Description + Exit Code @@ -1137,7 +1137,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service linked Made available through a symlink to the unit file (permanently or just in /run). - 1 + > 0 linked-runtime @@ -1145,7 +1145,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service masked Disabled entirely (permanently or just in /run). - 1 + > 0 masked-runtime @@ -1163,7 +1163,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service disabled Unit file is not enabled. - 1 + > 0 @@ -1474,22 +1474,25 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service Checks whether the system is operational. This - returns success when the system is fully up and running, - meaning not in startup, shutdown or maintenance - mode. Failure is returned otherwise. In addition, the + returns success (exit code 0) when the system is fully up + and running, specifically not in startup, shutdown or + maintenance mode, and with no failed services. Failure is + returned otherwise (exit code non-zero). In addition, the current state is printed in a short string to standard output, see table below. Use to suppress this output. - Manager Operational States - - - + <command>is-system-running</command> output + + + + Name Description + Exit Code @@ -1499,32 +1502,53 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service basic.target is reached or the maintenance state entered. + > 0 starting Late bootup, before the job queue becomes idle for the first time, or one of the rescue targets are reached. + > 0 running The system is fully operational. + 0 degraded The system is operational but one or more units failed. + > 0 maintenance The rescue or emergency target is active. + > 0 stopping The manager is shutting down. + > 0 + + + offline + The manager is not + running. Specifically, this is the operational + state if an incompatible program is running as + system manager (PID 1). + > 0 + + + unknown + The operational state could not be + determined, due to lack of resources or another + error cause. + > 0 diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 06d5ae5319..5832cc6759 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -124,7 +124,12 @@ systemd, non-zero otherwise. If this option is passed, no message is sent. This option is hence unrelated to the other options. For details about the semantics of this option, see - sd_booted3. + sd_booted3. An + alternative way to check for this state is to call + systemctl1 + with the is-system-running command. It will + return offline if the system was not booted + with systemd. -- cgit v1.2.3-54-g00ecf From 4a9b1dd4ad38e54e6b7df99fe3366ceddd1fa572 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Sep 2015 19:36:21 +0200 Subject: machine-id-commit: merge machine-id-commit functionality into machine-id-setup And remove machine-id-commit as separate binary. There's really no point in keeping this separate, as the sources are pretty much identical, and have pretty identical interfaces. Let's unify this in one binary. Given that machine-id-commit was a private binary of systemd (shipped in /usr/lib/) removing the tool is not an API break. While we are at it, improve the documentation of the command substantially. --- .gitignore | 1 - Makefile-man.am | 2 - Makefile.am | 16 +--- man/machine-id.xml | 2 +- man/systemd-machine-id-commit.service.xml | 57 ++++++------- man/systemd-machine-id-commit.xml | 123 --------------------------- man/systemd-machine-id-setup.xml | 100 ++++++++++++++++------ src/machine-id-commit/Makefile | 1 - src/machine-id-commit/machine-id-commit.c | 105 ----------------------- src/machine-id-setup/machine-id-setup-main.c | 22 ++++- units/systemd-machine-id-commit.service.in | 2 +- 11 files changed, 123 insertions(+), 308 deletions(-) delete mode 100644 man/systemd-machine-id-commit.xml delete mode 120000 src/machine-id-commit/Makefile delete mode 100644 src/machine-id-commit/machine-id-commit.c (limited to 'man') diff --git a/.gitignore b/.gitignore index 605d109dfa..6149b01c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -96,7 +96,6 @@ /systemd-kmsg-syslogd /systemd-localed /systemd-logind -/systemd-machine-id-commit /systemd-machine-id-setup /systemd-machined /systemd-modules-load diff --git a/Makefile-man.am b/Makefile-man.am index 7dd014116f..49586fe04c 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -102,7 +102,6 @@ MANPAGES += \ man/systemd-inhibit.1 \ man/systemd-initctl.service.8 \ man/systemd-journald.service.8 \ - man/systemd-machine-id-commit.1 \ man/systemd-machine-id-commit.service.8 \ man/systemd-machine-id-setup.1 \ man/systemd-notify.1 \ @@ -2351,7 +2350,6 @@ EXTRA_DIST += \ man/systemd-localed.service.xml \ man/systemd-logind.service.xml \ man/systemd-machine-id-commit.service.xml \ - man/systemd-machine-id-commit.xml \ man/systemd-machine-id-setup.xml \ man/systemd-machined.service.xml \ man/systemd-modules-load.service.xml \ diff --git a/Makefile.am b/Makefile.am index e9ad72333b..6ddc0b74f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -397,7 +397,6 @@ rootlibexec_PROGRAMS = \ systemd-remount-fs \ systemd-reply-password \ systemd-fsck \ - systemd-machine-id-commit \ systemd-ac-power \ systemd-sysctl \ systemd-sleep \ @@ -2331,6 +2330,9 @@ systemd_machine_id_setup_SOURCES = \ systemd_machine_id_setup_LDADD = \ libshared.la +SYSINIT_TARGET_WANTS += \ + systemd-machine-id-commit.service + # ------------------------------------------------------------------------------ systemd_sysctl_SOURCES = \ src/sysctl/sysctl.c @@ -2352,18 +2354,6 @@ systemd_fsck_SOURCES = \ systemd_fsck_LDADD = \ libshared.la -# ------------------------------------------------------------------------------ -systemd_machine_id_commit_SOURCES = \ - src/machine-id-commit/machine-id-commit.c \ - src/core/machine-id-setup.c \ - src/core/machine-id-setup.h - -systemd_machine_id_commit_LDADD = \ - libshared.la - -SYSINIT_TARGET_WANTS += \ - systemd-machine-id-commit.service - # ------------------------------------------------------------------------------ systemd_ac_power_SOURCES = \ src/ac-power/ac-power.c diff --git a/man/machine-id.xml b/man/machine-id.xml index 92d67a3869..8ce9c46ff1 100644 --- a/man/machine-id.xml +++ b/man/machine-id.xml @@ -63,7 +63,7 @@ The machine ID is usually generated from a random source during system installation and stays constant for all subsequent boots. Optionally, for stateless systems, it is generated during - runtime at boot if it is found to be empty. + runtime at early boot if it is found to be empty. The machine ID does not change based on user configuration or when hardware is replaced. diff --git a/man/systemd-machine-id-commit.service.xml b/man/systemd-machine-id-commit.service.xml index 7c8fc0874e..10f36b3008 100644 --- a/man/systemd-machine-id-commit.service.xml +++ b/man/systemd-machine-id-commit.service.xml @@ -42,55 +42,50 @@ systemd-machine-id-commit.service - Commit transient machine-id to disk + Commit a transient machine-id to disk systemd-machine-id-commit.service - /usr/lib/systemd/systemd-machine-id-commit Description - systemd-machine-id-commit.service is a - service responsible for committing any transient - /etc/machine-id file to a writable file + systemd-machine-id-commit.service is an + early-boot service responsible for committing transient + /etc/machine-id files to a writable disk file system. See machine-id5 - for more information about this file. - - This service is started shortly after - local-fs.target if - /etc/machine-id is an independent mount point - (probably a tmpfs one) and /etc is writable. - systemd-machine-id-commit will then write - current machine ID to disk and unmount the transient + for more information about machine IDs. + + This service is started after + local-fs.target in case + /etc/machine-id is a mount point of its own + (usually from a memory file system such as + tmpfs) and /etc is writable. The service will + invoke systemd-machine-id-setup --commit, which + writes the current transient machine ID to disk and unmount the /etc/machine-id file in a race-free manner to - ensure that file is always valid for other processes. - - Note that the traditional way to initialize the machine ID - in /etc/machine-id is to use - systemd-machine-id-setup by system installer - tools. You can also use - systemd-firstboot1 - to initialize the machine ID on mounted (but not booted) system - images. The main use case for that service is - /etc/machine-id being an empty file at boot - and initrd chaining to systemd giving it a read only file system - that will be turned read-write later during the boot - process. - - There is no consequence if that service fails other than a - newer machine-id will be generated during next system boot. - + ensure that file is always valid and accessible for other + processes. See + systemd-machine-id-setup1 + for details. + + The main use case of this service are systems where + /etc/machine-id is read-only and initially + not initialized. In this case the system manager will generate a + transient machine ID file on a memory file system, and mount it + over /etc/machine-id, during the early boot + phase. This service is then invoked in a later boot phase, as soon + as /etc has been remounted writable and the + ID may thus be committed to disk to make it permanent. See Also systemd1, - systemd-machine-id-commit1, systemd-machine-id-setup1, machine-id5, systemd-firstboot1 diff --git a/man/systemd-machine-id-commit.xml b/man/systemd-machine-id-commit.xml deleted file mode 100644 index d216aa0745..0000000000 --- a/man/systemd-machine-id-commit.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - systemd-machine-id-commit - systemd - - - - Developer - Didier - Roche - didrocks@ubuntu.com - - - - - - systemd-machine-id-commit - 1 - - - - systemd-machine-id-commit - Commit transient machine ID to /etc/machine-id - - - - - systemd-machine-id-commit - - - - - Description - - systemd-machine-id-commit may be used to - write on disk any transient machine ID mounted as a temporary file - system in /etc/machine-id at boot time. See - machine-id5 - for more information about this file. - - This tool will execute no operation if - /etc/machine-id doesn't contain any valid - machine ID, isn't mounted as an independent temporary file system, - or /etc is read-only. If those conditions are - met, it will then write current machine ID to disk and unmount the - transient /etc/machine-id file in a race-free - manner to ensure that this file is always valid for other - processes. - - Note that the traditional way to initialize the machine ID - in /etc/machine-id is to use - systemd-machine-id-setup by system installer - tools. You can also use - systemd-firstboot1 - to initialize the machine ID on mounted (but not booted) system - images. - - - - Options - - The following options are understood: - - - - - Takes a directory path - as an argument. All paths will be - prefixed with the given alternate - root path, - including config search paths. - - - - - - - - - - Exit status - - On success, 0 is returned, a non-zero failure code - otherwise. - - - - See Also - - systemd1, - systemd-machine-id-commit.service8, - systemd-machine-id-setup1, - machine-id5, - systemd-firstboot1 - - - - diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml index 182717f524..efcf408332 100644 --- a/man/systemd-machine-id-setup.xml +++ b/man/systemd-machine-id-setup.xml @@ -1,4 +1,4 @@ - + @@ -35,6 +35,12 @@ Poettering lennart@poettering.net + + Developer + Didier + Roche + didrocks@ubuntu.com + @@ -59,30 +65,43 @@ systemd-machine-id-setup may be used by system installer tools to initialize the machine ID stored in - /etc/machine-id at install time with a - randomly generated ID. See + /etc/machine-id at install time, with a + provisioned or randomly generated ID. See machine-id5 for more information about this file. - This tool will execute no operation if - /etc/machine-id is already - initialized. - - If a valid D-Bus machine ID is already configured for the - system, the D-Bus machine ID is copied and used to initialize the - machine ID in /etc/machine-id. - - If run inside a KVM virtual machine and a UUID is passed via - the option, this UUID is used to initialize - the machine ID instead of a randomly generated one. The caller - must ensure that the UUID passed is sufficiently unique and is - different for every booted instanced of the VM. - - Similar, if run inside a Linux container environment and a - UUID is set for the container this is used to initialize the - machine ID. For details see the documentation of the Container - Interface. + If the tool is invoked without the + switch /etc/machine-id is initialized with a + valid, new machined ID if it is missing or empty. The new machine + ID will be acquired in the following fashion: + + + If a valid D-Bus machine ID is already + configured for the system, the D-Bus machine ID is copied and + used to initialize the machine ID in + /etc/machine-id. + + If run inside a KVM virtual machine and a UUID + is was configured (via the + option), this UUID is used to initialize the machine ID. The + caller must ensure that the UUID passed is sufficiently unique + and is different for every booted instance of the + VM. + + Similar, if run inside a Linux container + environment and a UUID is configured for the container this is + used to initialize the machine ID. For details see the + documentation of the Container + Interface. + + Otherwise a new ID is randomly + generated. + + + The switch may be used to commit a + transient machined ID to disk, making it persistent. For details, + see below. Use systemd-firstboot1 @@ -97,13 +116,41 @@ The following options are understood: + - Takes a directory path as an argument. All - paths will be prefixed with the given alternate - root path, including config search - paths. + Takes a directory path as argument. All paths + operated will be prefixed with the given alternate + root path, including the path for + /etc/machine-id itself. + + + + Commit a transient machine ID to disk. This + command may be used to convert a transient machine ID into a + persistent one. A transient machine ID file is one that was + bind mounted from a memory file system (usually + tmpfs) to + /etc/machine-id during the early phase of + the boot process. This may happen because + /etc is initially read-only and was + missing a valid machine ID file at that point. + + This command will execute no operation if + /etc/machine-id is not mounted from a + memory file system, or if /etc is + read-only. The command will write the current transient + machine ID to disk and unmount the + /etc/machine-id mount point in a + race-free manner to ensure that this file is always valid and + accessible for other processes. + + This command is primarily used by the + systemd-machine-id-commit.service8 + early-boot service. + + @@ -122,6 +169,7 @@ systemd1, machine-id5, + systemd-machine-id-commit.service8, dbus-uuidgen1, systemd-firstboot1 diff --git a/src/machine-id-commit/Makefile b/src/machine-id-commit/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/machine-id-commit/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile \ No newline at end of file diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c deleted file mode 100644 index ec3d7f8f97..0000000000 --- a/src/machine-id-commit/machine-id-commit.c +++ /dev/null @@ -1,105 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Didier Roche - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include - -#include "log.h" -#include "machine-id-setup.h" -#include "util.h" - -static const char *arg_root = NULL; - -static void help(void) { - printf("%s [OPTIONS...]\n\n" - "Commit a transient /etc/machine-id on disk if writable.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --root=ROOT Filesystem root\n", - program_invocation_short_name); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ROOT, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "root", required_argument, NULL, ARG_ROOT }, - {} - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - return version(); - - case ARG_ROOT: - arg_root = optarg; - break; - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - if (optind < argc) { - log_error("Extraneous arguments"); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = machine_id_commit(arg_root); - -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index e5606c9a03..a9c4e3fadf 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -28,15 +28,17 @@ #include "machine-id-setup.h" #include "util.h" -static const char *arg_root = ""; +static const char *arg_root = NULL; +static bool arg_commit = false; static void help(void) { printf("%s [OPTIONS...]\n\n" "Initialize /etc/machine-id from a random source.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " --root=ROOT Filesystem root\n", - program_invocation_short_name); + " --root=ROOT Filesystem root\n" + " --commit Commit transient ID\n" + , program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { @@ -44,12 +46,14 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_ROOT, + ARG_COMMIT, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "root", required_argument, NULL, ARG_ROOT }, + { "commit", no_argument, NULL, ARG_COMMIT }, {} }; @@ -73,6 +77,10 @@ static int parse_argv(int argc, char *argv[]) { arg_root = optarg; break; + case ARG_COMMIT: + arg_commit = true; + break; + case '?': return -EINVAL; @@ -98,5 +106,11 @@ int main(int argc, char *argv[]) { if (r <= 0) return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - return machine_id_setup(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + if (arg_commit) + r = machine_id_commit(arg_root); + else + r = machine_id_setup(arg_root); + + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/units/systemd-machine-id-commit.service.in b/units/systemd-machine-id-commit.service.in index cccbf7b626..1f3f5da0f3 100644 --- a/units/systemd-machine-id-commit.service.in +++ b/units/systemd-machine-id-commit.service.in @@ -18,5 +18,5 @@ ConditionPathIsMountPoint=/etc/machine-id [Service] Type=oneshot RemainAfterExit=yes -ExecStart=@rootlibexecdir@/systemd-machine-id-commit +ExecStart=@rootbindir@/systemd-machine-id-setup --commit TimeoutSec=30s -- cgit v1.2.3-54-g00ecf From 0521e286fc34d1ab58edc1a3fab7b8285c4b36e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Sep 2015 19:40:51 +0200 Subject: man: also properly indent our examples to 8ch --- man/systemd-notify.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 5832cc6759..71d501f435 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -161,12 +161,12 @@ mkfifo /tmp/waldo systemd-notify --ready --status="Waiting for data..." while : ; do - read a < /tmp/waldo - systemd-notify --status="Processing $a" + read a < /tmp/waldo + systemd-notify --status="Processing $a" - # Do something with $a ... + # Do something with $a ... - systemd-notify --status="Waiting for data..." + systemd-notify --status="Waiting for data..." done -- cgit v1.2.3-54-g00ecf From 5f5d8eab1f2f5f5e088bc301533b3e4636de96c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Sep 2015 19:46:23 +0200 Subject: core: allow setting WorkingDirectory= to the special value ~ If set to ~ the working directory is set to the home directory of the user configured in User=. This change also exposes the existing switch for the working directory that allowed making missing working directories non-fatal. This also changes "machinectl shell" to make use of this to ensure that the invoked shell is by default in the user's home directory. Fixes #1268. --- man/systemd.exec.xml | 23 +++--- src/core/dbus-execute.c | 87 ++++++++++++++++++----- src/core/execute.c | 21 +++--- src/core/execute.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 129 +++++++++++++++++++++++++--------- src/core/load-fragment.h | 1 + src/machine/machine-dbus.c | 5 +- 8 files changed, 197 insertions(+), 72 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 7633948645..d3f56fee40 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -84,22 +84,27 @@ WorkingDirectory= - Takes an absolute directory path. Sets the - working directory for executed processes. If not set, defaults - to the root directory when systemd is running as a system - instance and the respective user's home directory if run as - user. + Takes an absolute directory path, or the + special value ~. Sets the working directory + for executed processes. If set to ~ the + home directory of the user specified in + User= is used. If not set, defaults to the + root directory when systemd is running as a system instance + and the respective user's home directory if run as user. If + the setting is prefixed with the - + character, a missing working directory is not considered + fatal. RootDirectory= Takes an absolute directory path. Sets the - root directory for executed processes, with the - chroot2 + root directory for executed processes, with the chroot2 system call. If this is used, it must be ensured that the - process and all its auxiliary files are available in the - chroot() jail. + process binary and all its auxiliary files are available in + the chroot() jail. diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 868c8cc05a..adf613d328 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -595,6 +595,33 @@ static int property_get_address_families( return sd_bus_message_close_container(reply); } +static int property_get_working_directory( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + const char *wd; + + assert(bus); + assert(reply); + assert(c); + + if (c->working_directory_home) + wd = "~"; + else + wd = c->working_directory; + + if (c->working_directory_missing_ok) + wd = strjoina("!", wd); + + return sd_bus_message_append(reply, "s", wd); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), @@ -616,7 +643,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -847,8 +874,7 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, - "TTYPath", "WorkingDirectory", "RootDirectory")) { + } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) { const char *s; r = sd_bus_message_read(message, "s", &s); @@ -859,24 +885,51 @@ int bus_exec_context_set_transient_property( return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name); if (mode != UNIT_CHECK) { - char *t; + if (streq(name, "TTYPath")) + r = free_and_strdup(&c->tty_path, s); + else { + assert(streq(name, "RootDirectory")); + r = free_and_strdup(&c->root_directory, s); + } + if (r < 0) + return r; - t = strdup(s); - if (!t) - return -ENOMEM; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } - if (streq(name, "TTYPath")) { - free(c->tty_path); - c->tty_path = t; - } else if (streq(name, "WorkingDirectory")) { - free(c->working_directory); - c->working_directory = t; - } else if (streq(name, "RootDirectory")) { - free(c->root_directory); - c->root_directory = t; + return 1; + + } else if (streq(name, "WorkingDirectory")) { + const char *s; + bool missing_ok; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + if (s[0] == '-') { + missing_ok = true; + s++; + } else + missing_ok = false; + + if (!streq(s, "~") && !path_is_absolute(s)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'"); + + if (mode != UNIT_CHECK) { + if (streq(s, "~")) { + c->working_directory = mfree(c->working_directory); + c->working_directory_home = true; + } else { + r = free_and_strdup(&c->working_directory, s); + if (r < 0) + return r; + + c->working_directory_home = false; } - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + c->working_directory_missing_ok = missing_ok; + unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s); } return 1; diff --git a/src/core/execute.c b/src/core/execute.c index 7796c07fcf..137a176c18 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1325,7 +1325,7 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; - const char *username = NULL, *home = NULL, *shell = NULL; + const char *username = NULL, *home = NULL, *shell = NULL, *wd; unsigned n_dont_close = 0; int dont_close[n_fds + 4]; uid_t uid = UID_INVALID; @@ -1698,6 +1698,13 @@ static int exec_child( } } + if (context->working_directory_home) + wd = home; + else if (context->working_directory) + wd = context->working_directory; + else + wd = "/"; + if (params->apply_chroot) { if (!needs_mount_namespace && context->root_directory) if (chroot(context->root_directory) < 0) { @@ -1705,21 +1712,15 @@ static int exec_child( return -errno; } - if (chdir(context->working_directory ?: "/") < 0 && + if (chdir(wd) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; return -errno; } } else { - _cleanup_free_ char *d = NULL; - - if (asprintf(&d, "%s/%s", - context->root_directory ?: "", - context->working_directory ?: "") < 0) { - *exit_status = EXIT_MEMORY; - return -ENOMEM; - } + const char *d; + d = strjoina(strempty(context->root_directory), "/", strempty(wd)); if (chdir(d) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; diff --git a/src/core/execute.h b/src/core/execute.h index a750246a89..2c93044748 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -103,6 +103,7 @@ struct ExecContext { struct rlimit *rlimit[_RLIMIT_MAX]; char *working_directory, *root_directory; bool working_directory_missing_ok; + bool working_directory_home; mode_t umask; int oom_score_adjust; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fd293d8287..27159aa4c7 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -17,7 +17,7 @@ struct ConfigPerfItem; %% m4_dnl Define the context options only once m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', -`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) +`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context) $1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) $1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) $1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a13f42b5e0..7045c31f2e 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -20,44 +20,42 @@ along with systemd; If not, see . ***/ -#include #include -#include #include -#include #include -#include +#include +#include +#include #include - +#include #ifdef HAVE_SECCOMP #include #endif -#include "unit.h" -#include "strv.h" +#include "af-list.h" +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cap-list.h" +#include "cgroup.h" #include "conf-parser.h" -#include "load-fragment.h" -#include "log.h" +#include "env-util.h" +#include "errno-list.h" #include "ioprio.h" -#include "securebits.h" +#include "log.h" #include "missing.h" -#include "unit-name.h" -#include "unit-printf.h" -#include "utf8.h" #include "path-util.h" -#include "env-util.h" -#include "cgroup.h" -#include "bus-util.h" -#include "bus-error.h" -#include "errno-list.h" -#include "af-list.h" -#include "cap-list.h" -#include "signal-util.h" -#include "bus-internal.h" - #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "securebits.h" +#include "signal-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "load-fragment.h" int config_parse_warn_compat( const char *unit, @@ -195,16 +193,17 @@ int config_parse_unit_strv_printf(const char *unit, k ? k : rvalue, data, userdata); } -int config_parse_unit_path_printf(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_path_printf( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { _cleanup_free_ char *k = NULL; Unit *u = userdata; @@ -1846,6 +1845,70 @@ int config_parse_bus_endpoint_policy( return bus_endpoint_add_policy(c->bus_endpoint, name, access); } +int config_parse_working_directory( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool missing_ok; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(c); + assert(u); + + if (rvalue[0] == '-') { + missing_ok = true; + rvalue++; + } else + missing_ok = false; + + if (streq(rvalue, "~")) { + c->working_directory_home = true; + c->working_directory = mfree(c->working_directory); + } else { + _cleanup_free_ char *k = NULL; + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue); + return 0; + } + + path_kill_slashes(k); + + if (!utf8_is_valid(k)) { + log_invalid_utf8(unit, LOG_ERR, filename, line, 0, rvalue); + return 0; + } + + if (!path_is_absolute(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue); + return 0; + } + + free(c->working_directory); + c->working_directory = k; + k = NULL; + + c->working_directory_home = false; + } + + c->working_directory_missing_ok = missing_ok; + return 0; +} + int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 5d0a09249f..6ee7c71bc4 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -106,6 +106,7 @@ int config_parse_protect_home(const char* unit, const char *filename, unsigned l int config_parse_protect_system(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index b010c90989..21026829a9 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -735,7 +735,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu description = strjoina("Shell for User ", isempty(user) ? "root" : user); r = sd_bus_message_append(tm, - "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", + "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", "Description", "s", description, "StandardInput", "s", "tty", "StandardOutput", "s", "tty", @@ -748,7 +748,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu "TTYReset", "b", true, "UtmpIdentifier", "s", utmp_id, "UtmpMode", "s", "user", - "PAMName", "s", "login"); + "PAMName", "s", "login", + "WorkingDirectory", "s", "-~"); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From b9e74c399458a1146894ce371e7d85c60658110c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 Sep 2015 23:13:06 +0200 Subject: core: rework crash handling This introduces a new systemd.crash_reboot=1 kernel command line option that triggers a reboot after crashing. This also cleans up crash VT handling. Specifically, it cleans up the configuration setting, to be between 1..63 or a boolean. This is to replace the previous logic where "-1" meant disabled. We continue to accept that setting, but only document the boolean syntax instead. This also brings the documentation of the default settings in sync with what actually happens. The CrashChVT= configuration file setting is renamed to CrashChangeVT=, following our usual logic of not abbreviating unnecessarily. The old setting stays support for compat reasons. Fixes #1300 --- man/kernel-command-line.xml | 3 +- man/systemd-system.conf.xml | 3 +- man/systemd.xml | 104 +++++++++++++++++++-------- src/basic/terminal-util.c | 2 +- src/core/main.c | 166 +++++++++++++++++++++++++++++++++++--------- src/core/shutdown.c | 1 - src/core/system.conf | 5 +- 7 files changed, 217 insertions(+), 67 deletions(-) (limited to 'man') diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index eb73727027..2f81746b5e 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -79,8 +79,9 @@ systemd.unit= rd.systemd.unit= systemd.dump_core= - systemd.crash_shell= systemd.crash_chvt= + systemd.crash_shell= + systemd.crash_reboot= systemd.confirm_spawn= systemd.show_status= systemd.log_target= diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index a4ba0959ea..56db9ff17e 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -90,9 +90,10 @@ LogColor= LogLocation= DumpCore=yes + CrashChangeVT=no CrashShell=no + CrashReboot=no ShowStatus=yes - CrashChVT=1 DefaultStandardOutput=journal DefaultStandardError=inherit diff --git a/man/systemd.xml b/man/systemd.xml index 479f55de76..9e927c3204 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -1,4 +1,4 @@ - + @@ -131,17 +131,48 @@ - Dump core on crash. This switch has no effect - when run as user instance. + Enable core dumping on crash. This switch has + no effect when running as user instance. This setting may also + be enabled during boot on the kernel command line via the + systemd.dump_core= option, see + below. + + + VT + + Switch to a specific virtual console (VT) on + crash. Takes a positive integer in the range 1..63, or a + boolean argument. If an integer is passed, selects which VT to + switch to. If yes, the VT kernel messages + are written to is selected. If no, no VT + switch is attempted. This switch has no effect when running as + user instance. This setting may also be enabled during boot, + on the kernel command line via the + systemd.crash_vt= option, see + below. + + - Run shell on - crash. This switch has no effect when - run as user - instance. + Run a shell on crash. This switch has no + effect when running as user instance. This setting may also be + enabled during boot, on the kernel command line via the + systemd.crash_shell= option, see + below. + + + + + Automatically reboot the system on crash. This + switch has no effect when running as user instance. This + setting may also be enabled during boot, on the kernel command + line via the systemd.crash_reboot= option, + see below. + + @@ -854,50 +885,67 @@ systemd.dump_core= Takes a boolean argument. If - , systemd dumps core when it crashes. - Otherwise, no core dump is created. Defaults to - . + , the systemd manager (PID 1) dumps core + when it crashes. Otherwise, no core dump is created. Defaults + to . + + + + systemd.crash_chvt= + + Takes a positive integer, or a boolean + argument. If a positive integer (in the range 1..63) is + specified the system manager (PID 1) will activate the specified + virtual terminal (VT) when it crashes. Defaults to + no, meaning that no such switch is + attempted. If set to yes the VT the + kernel messages are written to is selected. systemd.crash_shell= Takes a boolean argument. If - , systemd spawns a shell when it crashes. - Otherwise, no shell is spawned. Defaults to - , for security reasons, as the shell is - not protected by any password + , the system manager (PID 1) spawns a + shell when it crashes, after a 10s delay. Otherwise, no shell + is spawned. Defaults to , for security + reasons, as the shell is not protected by password authentication. - systemd.crash_chvt= + systemd.crash_reboot= - Takes an integer argument. If positive systemd - activates the specified virtual terminal when it crashes. - Defaults to -1. + Takes a boolean argument. If + , the system manager (PID 1) will reboot + the machine automatically when it crashes, after a 10s delay. + Otherwise, the system will hang indefinitely. Defaults to + , in order to avoid a reboot loop. If + combined with systemd.crash_shell=, it is + first attempted to invoke a shell, and if this is not + successful the system is rebooted. systemd.confirm_spawn= Takes a boolean argument. If - , asks for confirmation when spawning - processes. Defaults to - . + , the system manager (PID 1) asks for + confirmation when spawning processes. Defaults to + . systemd.show_status= Takes a boolean argument or the constant - auto. If , shows - terse service status updates on the console during bootup. - auto behaves like - until a service fails or there is a significant delay in boot. - Defaults to , unless - is passed as kernel command line option - in which case it defaults to + auto. If , the + systemd manager (PID 1) shows terse service status updates on + the console during bootup. auto behaves + like until a service fails or there is + a significant delay in boot. Defaults to + , unless is passed + as kernel command line option in which case it defaults to auto. diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index dd3d525854..287e0dfa13 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -48,7 +48,7 @@ int chvt(int vt) { if (fd < 0) return -errno; - if (vt < 0) { + if (vt <= 0) { int tiocl[2] = { TIOCL_GETKMSGREDIRECT, 0 diff --git a/src/core/main.c b/src/core/main.c index 9634feb8a6..bac2043281 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #ifdef HAVE_SECCOMP @@ -87,8 +88,9 @@ static enum { static char *arg_default_unit = NULL; static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; static bool arg_dump_core = true; -static bool arg_crash_shell = false; static int arg_crash_chvt = -1; +static bool arg_crash_shell = false; +static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; @@ -123,6 +125,21 @@ static void pager_open_if_enabled(void) { pager_open(false); } +noreturn static void freeze_or_reboot(void) { + + if (arg_crash_reboot) { + log_notice("Rebooting in 10s..."); + (void) sleep(10); + + log_notice("Rebooting now..."); + (void) reboot(RB_AUTOBOOT); + log_emergency_errno(errno, "Failed to reboot: %m"); + } + + log_emergency("Freezing execution."); + freeze(); +} + noreturn static void crash(int sig) { if (getpid() != 1) @@ -188,7 +205,7 @@ noreturn static void crash(int sig) { } } - if (arg_crash_chvt) + if (arg_crash_chvt >= 0) (void) chvt(arg_crash_chvt); if (arg_crash_shell) { @@ -198,7 +215,7 @@ noreturn static void crash(int sig) { }; pid_t pid; - log_info("Executing crash shell in 10s..."); + log_notice("Executing crash shell in 10s..."); (void) sleep(10); /* Let the kernel reap children for us */ @@ -208,17 +225,20 @@ noreturn static void crash(int sig) { if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { + (void) setsid(); (void) make_console_stdio(); (void) execle("/bin/sh", "/bin/sh", NULL, environ); log_emergency_errno(errno, "execle() failed: %m"); + freeze_or_reboot(); _exit(EXIT_FAILURE); - } else - log_info("Successfully spawned crash shell as PID "PID_FMT".", pid); + } else { + log_info("Spawned crash shell as PID "PID_FMT".", pid); + freeze(); + } } - log_emergency("Freezing execution."); - freeze(); + freeze_or_reboot(); } static void install_crash_handler(void) { @@ -252,6 +272,24 @@ static int console_setup(void) { return 0; } +static int parse_crash_chvt(const char *value) { + int b; + + if (safe_atoi(value, &arg_crash_chvt) >= 0) + return 0; + + b = parse_boolean(value); + if (b < 0) + return b; + + if (b > 0) + arg_crash_chvt = 0; /* switch to where kmsg goes */ + else + arg_crash_chvt = -1; /* turn off switching */ + + return 0; +} + static int parse_proc_cmdline_item(const char *key, const char *value) { static const char * const rlmap[] = { @@ -290,6 +328,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_dump_core = r; + } else if (streq(key, "systemd.crash_chvt") && value) { + + if (parse_crash_chvt(value) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + } else if (streq(key, "systemd.crash_shell") && value) { r = parse_boolean(value); @@ -298,12 +341,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_crash_shell = r; - } else if (streq(key, "systemd.crash_chvt") && value) { + } else if (streq(key, "systemd.crash_reboot") && value) { - if (safe_atoi(value, &r) < 0) - log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + r = parse_boolean(value); + if (r < 0) + log_warning("Failed to parse crash reboot switch %s. Ignoring.", value); else - arg_crash_chvt = r; + arg_crash_reboot = r; } else if (streq(key, "systemd.confirm_spawn") && value) { @@ -461,6 +505,34 @@ static int config_parse_show_status( return 0; } +static int config_parse_crash_chvt( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_crash_chvt(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue); + return 0; + } + + return 0; +} + static int config_parse_join_controllers(const char *unit, const char *filename, unsigned line, @@ -571,9 +643,11 @@ static int parse_config_file(void) { { "Manager", "LogColor", config_parse_color, 0, NULL }, { "Manager", "LogLocation", config_parse_location, 0, NULL }, { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL }, + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL }, { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, - { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, @@ -661,7 +735,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION, ARG_DUMP_CONFIGURATION_ITEMS, ARG_DUMP_CORE, + ARG_CRASH_CHVT, ARG_CRASH_SHELL, + ARG_CRASH_REBOOT, ARG_CONFIRM_SPAWN, ARG_SHOW_STATUS, ARG_DESERIALIZE, @@ -684,7 +760,9 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, { "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, + { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, + { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, @@ -802,21 +880,42 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DUMP_CORE: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse dump core boolean %s.", optarg); - return r; + if (!optarg) + arg_dump_core = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg); + arg_dump_core = r; } - arg_dump_core = r; + break; + + case ARG_CRASH_CHVT: + r = parse_crash_chvt(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg); break; case ARG_CRASH_SHELL: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse crash shell boolean %s.", optarg); - return r; + if (!optarg) + arg_crash_shell = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_shell = r; + } + break; + + case ARG_CRASH_REBOOT: + if (!optarg) + arg_crash_reboot = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_reboot = r; } - arg_crash_shell = r; break; case ARG_CONFIRM_SPAWN: @@ -846,17 +945,16 @@ static int parse_argv(int argc, char *argv[]) { r = safe_atoi(optarg, &fd); if (r < 0 || fd < 0) { log_error("Failed to parse deserialize option %s.", optarg); - return r < 0 ? r : -EINVAL; + return -EINVAL; } - fd_cloexec(fd, true); + (void) fd_cloexec(fd, true); f = fdopen(fd, "r"); if (!f) return log_error_errno(errno, "Failed to open serialization fd: %m"); safe_fclose(arg_serialization); - arg_serialization = f; break; @@ -916,14 +1014,16 @@ static int help(void) { " --unit=UNIT Set default unit\n" " --system Run a system instance, even if PID != 1\n" " --user Run a user instance\n" - " --dump-core[=0|1] Dump core on crash\n" - " --crash-shell[=0|1] Run shell on crash\n" - " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n" - " --show-status[=0|1] Show status updates on the console during bootup\n" + " --dump-core[=BOOL] Dump core on crash\n" + " --crash-vt=NR Change to specified VT on crash\n" + " --crash-reboot[=BOOL] Reboot on crash\n" + " --crash-shell[=BOOL] Run shell on crash\n" + " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n" + " --show-status[=BOOL] Show status updates on the console during bootup\n" " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n" " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" - " --log-color[=0|1] Highlight important log messages\n" - " --log-location[=0|1] Include code location in log messages\n" + " --log-color[=BOOL] Highlight important log messages\n" + " --log-location[=BOOL] Include code location in log messages\n" " --default-standard-output= Set default standard output for services\n" " --default-standard-error= Set default standard error output for services\n", program_invocation_short_name); @@ -1032,7 +1132,7 @@ static void test_mtab(void) { log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " "This is not supported anymore. " "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); - freeze(); + freeze_or_reboot(); } static void test_usr(void) { @@ -1964,7 +2064,7 @@ finish: manager_status_printf(NULL, STATUS_TYPE_EMERGENCY, ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL, "%s, freezing.", error_message); - freeze(); + freeze_or_reboot(); } return retval; diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 5296efce1d..27c581d9c1 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -430,6 +430,5 @@ int main(int argc, char *argv[]) { error: log_emergency_errno(r, "Critical error while doing system shutdown: %m"); - freeze(); } diff --git a/src/core/system.conf b/src/core/system.conf index 231609033b..c30c595413 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -17,9 +17,10 @@ #LogColor=yes #LogLocation=no #DumpCore=yes -#CrashShell=no #ShowStatus=yes -#CrashChVT=1 +#CrashChangeVT=no +#CrashShell=no +#CrashReboot=no #CPUAffinity=1 2 #JoinControllers=cpu,cpuacct net_cls,net_prio #RuntimeWatchdogSec=0 -- cgit v1.2.3-54-g00ecf