mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-26 09:57:26 +03:00
systemctl: add support for delayed shutdown, similar to sysv in style
This commit is contained in:
parent
6e200d55ae
commit
f614480831
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
systemd-shutdownd
|
||||
systemd-random-seed
|
||||
systemd-update-utmp
|
||||
test-env-replace
|
||||
|
19
Makefile.am
19
Makefile.am
@ -71,7 +71,8 @@ rootlibexec_PROGRAMS = \
|
||||
systemd-cgroups-agent \
|
||||
systemd-initctl \
|
||||
systemd-update-utmp \
|
||||
systemd-random-seed
|
||||
systemd-random-seed \
|
||||
systemd-shutdownd
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
test-engine \
|
||||
@ -137,6 +138,7 @@ dist_systemunit_DATA = \
|
||||
units/dbus.target \
|
||||
units/systemd-initctl.socket \
|
||||
units/systemd-logger.socket \
|
||||
units/systemd-shutdownd.socket \
|
||||
units/dev-hugepages.automount \
|
||||
units/dev-hugepages.mount \
|
||||
units/dev-mqueue.automount \
|
||||
@ -161,6 +163,7 @@ nodist_systemunit_DATA = \
|
||||
units/multi-user.target \
|
||||
units/systemd-initctl.service \
|
||||
units/systemd-logger.service \
|
||||
units/systemd-shutdownd.service \
|
||||
units/systemd-update-utmp-runlevel.service \
|
||||
units/systemd-update-utmp-shutdown.service \
|
||||
units/systemd-random-seed-save.service \
|
||||
@ -182,6 +185,7 @@ EXTRA_DIST = \
|
||||
units/remote-fs.target.m4 \
|
||||
units/systemd-initctl.service.in \
|
||||
units/systemd-logger.service.in \
|
||||
units/systemd-shutdownd.service.in \
|
||||
units/systemd-update-utmp-runlevel.service.in \
|
||||
units/systemd-update-utmp-shutdown.service.in \
|
||||
units/systemd-random-seed-save.service.in \
|
||||
@ -346,7 +350,8 @@ EXTRA_DIST += \
|
||||
src/bus-errors.h \
|
||||
src/cgroup-show.h \
|
||||
src/utmp-wtmp.h \
|
||||
src/build.h
|
||||
src/build.h \
|
||||
src/shutdownd.h
|
||||
|
||||
MANPAGES = \
|
||||
man/systemd.1 \
|
||||
@ -529,6 +534,16 @@ systemd_random_seed_CFLAGS = \
|
||||
systemd_random_seed_LDADD = \
|
||||
libsystemd-basic.la
|
||||
|
||||
systemd_shutdownd_SOURCES = \
|
||||
src/sd-daemon.c \
|
||||
src/shutdownd.c
|
||||
|
||||
systemd_shutdownd_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
systemd_shutdownd_LDADD = \
|
||||
libsystemd-basic.la
|
||||
|
||||
systemd_cgroups_agent_SOURCES = \
|
||||
src/cgroups-agent.c \
|
||||
src/dbus-common.c
|
||||
|
@ -1786,7 +1786,7 @@ static int manager_process_notify_fd(Manager *m) {
|
||||
if (n >= 0)
|
||||
return -EIO;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
break;
|
||||
|
||||
return -errno;
|
||||
|
272
src/shutdownd.c
Normal file
272
src/shutdownd.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "shutdownd.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "sd-daemon.h"
|
||||
|
||||
static int read_packet(int fd, struct shutdownd_command *_c) {
|
||||
struct msghdr msghdr;
|
||||
struct iovec iovec;
|
||||
struct ucred *ucred;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
||||
} control;
|
||||
struct shutdownd_command c;
|
||||
ssize_t n;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(_c);
|
||||
|
||||
zero(iovec);
|
||||
iovec.iov_base = &c;
|
||||
iovec.iov_len = sizeof(c);
|
||||
|
||||
zero(control);
|
||||
zero(msghdr);
|
||||
msghdr.msg_iov = &iovec;
|
||||
msghdr.msg_iovlen = 1;
|
||||
msghdr.msg_control = &control;
|
||||
msghdr.msg_controllen = sizeof(control);
|
||||
|
||||
if ((n = recvmsg(fd, &msghdr, MSG_DONTWAIT)) <= 0) {
|
||||
if (n >= 0) {
|
||||
log_error("Short read");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
return 0;
|
||||
|
||||
log_error("recvmsg(): %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
|
||||
control.cmsghdr.cmsg_level != SOL_SOCKET ||
|
||||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
|
||||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
|
||||
log_warning("Received message without credentials. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
|
||||
if (ucred->uid != 0) {
|
||||
log_warning("Got request from unprivileged user. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n != sizeof(c)) {
|
||||
log_warning("Message has invaliud size. Ignoring");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*_c = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
enum {
|
||||
FD_SOCKET,
|
||||
FD_SHUTDOWN_TIMER,
|
||||
FD_NOLOGIN_TIMER,
|
||||
_FD_MAX
|
||||
};
|
||||
|
||||
int r = 4, n;
|
||||
int one = 1;
|
||||
unsigned n_fds = 1;
|
||||
struct shutdownd_command c;
|
||||
struct pollfd pollfd[_FD_MAX];
|
||||
bool exec_shutdown = false, unlink_nologin = false;
|
||||
|
||||
if (getppid() != 1) {
|
||||
log_error("This program should be invoked by init only.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
log_error("This program does not take arguments.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
|
||||
log_parse_environment();
|
||||
|
||||
if ((n = sd_listen_fds(true)) < 0) {
|
||||
log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (n != 1) {
|
||||
log_error("Need exactly one file descriptor.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
|
||||
log_error("SO_PASSCRED failed: %m");
|
||||
return 3;
|
||||
}
|
||||
|
||||
zero(c);
|
||||
zero(pollfd);
|
||||
|
||||
pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
|
||||
pollfd[FD_SOCKET].events = POLLIN;
|
||||
pollfd[FD_SHUTDOWN_TIMER].fd = -1;
|
||||
pollfd[FD_SHUTDOWN_TIMER].events = POLLIN;
|
||||
pollfd[FD_NOLOGIN_TIMER].fd = -1;
|
||||
pollfd[FD_NOLOGIN_TIMER].events = POLLIN;
|
||||
|
||||
log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
|
||||
|
||||
sd_notify(false,
|
||||
"READY=1\n"
|
||||
"STATUS=Processing requests...");
|
||||
|
||||
do {
|
||||
int k;
|
||||
|
||||
if (poll(pollfd, n_fds, -1) < 0) {
|
||||
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("poll(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SOCKET].revents) {
|
||||
|
||||
if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0)
|
||||
goto finish;
|
||||
else if (k > 0 && c.elapse > 0) {
|
||||
struct itimerspec its;
|
||||
char buf[27];
|
||||
|
||||
if (pollfd[FD_SHUTDOWN_TIMER].fd < 0)
|
||||
if ((pollfd[FD_SHUTDOWN_TIMER].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
|
||||
log_error("timerfd_create(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_NOLOGIN_TIMER].fd < 0)
|
||||
if ((pollfd[FD_NOLOGIN_TIMER].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
|
||||
log_error("timerfd_create(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Disallow logins 5 minutes prior to shutdown */
|
||||
zero(its);
|
||||
timespec_store(&its.it_value, c.elapse > 5*USEC_PER_MINUTE ? c.elapse - 5*USEC_PER_MINUTE : 0);
|
||||
if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
|
||||
log_error("timerfd_settime(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Shutdown after the specified time is reached */
|
||||
zero(its);
|
||||
timespec_store(&its.it_value, c.elapse);
|
||||
if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
|
||||
log_error("timerfd_settime(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_fds = 3;
|
||||
|
||||
ctime_r(&its.it_value.tv_sec, buf);
|
||||
|
||||
sd_notifyf(false,
|
||||
"STATUS=Shutting down at %s...",
|
||||
strstrip(buf));
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfd[FD_NOLOGIN_TIMER].fd >= 0 &&
|
||||
pollfd[FD_NOLOGIN_TIMER].revents) {
|
||||
int e;
|
||||
|
||||
if ((e = touch("/etc/nologin")) < 0)
|
||||
log_error("Failed to create /etc/nologin: %s", strerror(-e));
|
||||
else
|
||||
unlink_nologin = true;
|
||||
|
||||
/* Disarm nologin timer */
|
||||
close_nointr_nofail(pollfd[FD_NOLOGIN_TIMER].fd);
|
||||
pollfd[FD_NOLOGIN_TIMER].fd = -1;
|
||||
n_fds = 2;
|
||||
|
||||
}
|
||||
|
||||
if (pollfd[FD_SHUTDOWN_TIMER].fd >= 0 &&
|
||||
pollfd[FD_SHUTDOWN_TIMER].revents) {
|
||||
exec_shutdown = true;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} while (c.elapse > 0);
|
||||
|
||||
r = 0;
|
||||
|
||||
log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
|
||||
|
||||
finish:
|
||||
if (pollfd[FD_SOCKET].fd >= 0)
|
||||
close_nointr_nofail(pollfd[FD_SOCKET].fd);
|
||||
|
||||
if (pollfd[FD_SHUTDOWN_TIMER].fd >= 0)
|
||||
close_nointr_nofail(pollfd[FD_SHUTDOWN_TIMER].fd);
|
||||
|
||||
if (pollfd[FD_NOLOGIN_TIMER].fd >= 0)
|
||||
close_nointr_nofail(pollfd[FD_NOLOGIN_TIMER].fd);
|
||||
|
||||
if (exec_shutdown) {
|
||||
char sw[3];
|
||||
|
||||
sw[0] = '-';
|
||||
sw[1] = c.mode;
|
||||
sw[2] = 0;
|
||||
|
||||
execl(SYSTEMCTL_BINARY_PATH, "shutdown", sw, "now", NULL);
|
||||
log_error("Failed to execute /sbin/shutdown: %m");
|
||||
}
|
||||
|
||||
if (unlink_nologin)
|
||||
unlink("/etc/nologin");
|
||||
|
||||
sd_notify(false,
|
||||
"STATUS=Exiting...");
|
||||
|
||||
return r;
|
||||
}
|
35
src/shutdownd.h
Normal file
35
src/shutdownd.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooshutdowndhfoo
|
||||
#define fooshutdowndhfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 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
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
|
||||
_packed_ struct shutdownd_command {
|
||||
usec_t elapse;
|
||||
char mode; /* H, P, r, i.e. the switches usually passed to
|
||||
* shutdown to select whether to halt, power-off or
|
||||
* reboot the machine */
|
||||
};
|
||||
|
||||
#endif
|
@ -30,14 +30,16 @@
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct SocketAddress {
|
||||
union {
|
||||
union sockaddr_union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in in4;
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_storage storage;
|
||||
} sockaddr;
|
||||
};
|
||||
|
||||
typedef struct SocketAddress {
|
||||
union sockaddr_union sockaddr;
|
||||
|
||||
/* We store the size here explicitly due to the weird
|
||||
* sockaddr_un semantics for abstract sockets */
|
||||
|
160
src/systemctl.c
160
src/systemctl.c
@ -49,6 +49,7 @@
|
||||
#include "path-lookup.h"
|
||||
#include "conf-parser.h"
|
||||
#include "sd-daemon.h"
|
||||
#include "shutdownd.h"
|
||||
|
||||
static const char *arg_type = NULL;
|
||||
static char **arg_property = NULL;
|
||||
@ -68,6 +69,9 @@ static bool arg_full = false;
|
||||
static bool arg_force = false;
|
||||
static bool arg_defaults = false;
|
||||
static char **arg_wall = NULL;
|
||||
static usec_t arg_when = 0;
|
||||
static bool arg_skip_fsck = false;
|
||||
static bool arg_force_fsck = false;
|
||||
static enum action {
|
||||
ACTION_INVALID,
|
||||
ACTION_SYSTEMCTL,
|
||||
@ -84,6 +88,7 @@ static enum action {
|
||||
ACTION_RELOAD,
|
||||
ACTION_REEXEC,
|
||||
ACTION_RUNLEVEL,
|
||||
ACTION_CANCEL_SHUTDOWN,
|
||||
_ACTION_MAX
|
||||
} arg_action = ACTION_SYSTEMCTL;
|
||||
static enum dot {
|
||||
@ -3832,7 +3837,10 @@ static int shutdown_help(void) {
|
||||
" -r --reboot Reboot the machine\n"
|
||||
" -h Equivalent to --poweroff, overriden by --halt\n"
|
||||
" -k Don't halt/power-off/reboot, just send warnings\n"
|
||||
" --no-wall Don't send wall message before halt/power-off/reboot\n",
|
||||
" --no-wall Don't send wall message before halt/power-off/reboot\n"
|
||||
" -f Skip fsck on reboot\n"
|
||||
" -F Force fsck on reboot\n"
|
||||
" -c Cancel a pending shutdown\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
@ -4099,6 +4107,53 @@ static int halt_parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_time_spec(const char *t, usec_t *_u) {
|
||||
assert(t);
|
||||
assert(_u);
|
||||
|
||||
if (streq(t, "now"))
|
||||
*_u = 0;
|
||||
else if (t[0] == '+') {
|
||||
uint64_t u;
|
||||
|
||||
if (safe_atou64(t + 1, &u) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
|
||||
} else {
|
||||
char *e = NULL;
|
||||
long hour, minute;
|
||||
struct tm tm;
|
||||
time_t s;
|
||||
usec_t n;
|
||||
|
||||
errno = 0;
|
||||
hour = strtol(t, &e, 10);
|
||||
if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
|
||||
return -EINVAL;
|
||||
|
||||
minute = strtol(e+1, &e, 10);
|
||||
if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
|
||||
return -EINVAL;
|
||||
|
||||
n = now(CLOCK_REALTIME);
|
||||
s = (time_t) n / USEC_PER_SEC;
|
||||
assert_se(localtime_r(&s, &tm));
|
||||
|
||||
tm.tm_hour = (int) hour;
|
||||
tm.tm_min = (int) minute;
|
||||
|
||||
assert_se(s = mktime(&tm));
|
||||
|
||||
*_u = (usec_t) s * USEC_PER_SEC;
|
||||
|
||||
while (*_u <= n)
|
||||
*_u += USEC_PER_DAY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shutdown_parse_argv(int argc, char *argv[]) {
|
||||
|
||||
enum {
|
||||
@ -4115,12 +4170,12 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
|
||||
while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
|
||||
case ARG_HELP:
|
||||
@ -4157,6 +4212,18 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
|
||||
/* Compatibility nops */
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
arg_skip_fsck = true;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
arg_force_fsck = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
arg_action = ACTION_CANCEL_SHUTDOWN;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -4166,10 +4233,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind && !streq(argv[optind], "now"))
|
||||
log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
|
||||
if (argc > optind)
|
||||
if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) {
|
||||
log_error("Failed to parse time specification: %s", argv[optind]);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* We ignore the time argument */
|
||||
/* We skip the time argument */
|
||||
if (argc > optind + 1)
|
||||
arg_wall = argv + optind + 1;
|
||||
|
||||
@ -4624,6 +4694,62 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
|
||||
return verbs[i].dispatch(bus, argv + optind, left);
|
||||
}
|
||||
|
||||
static int send_shutdownd(usec_t t, char mode) {
|
||||
int fd = -1;
|
||||
struct msghdr msghdr;
|
||||
struct iovec iovec;
|
||||
union sockaddr_union sockaddr;
|
||||
struct ucred *ucred;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
||||
} control;
|
||||
struct shutdownd_command c;
|
||||
|
||||
zero(c);
|
||||
c.elapse = t;
|
||||
c.mode = mode;
|
||||
|
||||
if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0)
|
||||
return -errno;
|
||||
|
||||
zero(sockaddr);
|
||||
sockaddr.sa.sa_family = AF_UNIX;
|
||||
sockaddr.un.sun_path[0] = 0;
|
||||
strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
|
||||
|
||||
zero(iovec);
|
||||
iovec.iov_base = (char*) &c;
|
||||
iovec.iov_len = sizeof(c);
|
||||
|
||||
zero(control);
|
||||
control.cmsghdr.cmsg_level = SOL_SOCKET;
|
||||
control.cmsghdr.cmsg_type = SCM_CREDENTIALS;
|
||||
control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
|
||||
|
||||
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
|
||||
ucred->pid = getpid();
|
||||
ucred->uid = getuid();
|
||||
ucred->gid = getgid();
|
||||
|
||||
zero(msghdr);
|
||||
msghdr.msg_name = &sockaddr;
|
||||
msghdr.msg_namelen = sizeof(sa_family_t) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
|
||||
|
||||
msghdr.msg_iov = &iovec;
|
||||
msghdr.msg_iovlen = 1;
|
||||
msghdr.msg_control = &control;
|
||||
msghdr.msg_controllen = control.cmsghdr.cmsg_len;
|
||||
|
||||
if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
|
||||
close_nointr_nofail(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
close_nointr_nofail(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload_with_fallback(DBusConnection *bus) {
|
||||
|
||||
if (bus) {
|
||||
@ -4677,6 +4803,24 @@ static int halt_main(DBusConnection *bus) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (arg_force_fsck) {
|
||||
if ((r = touch("/forcefsck")) < 0)
|
||||
log_warning("Failed to create /forcefsck: %s", strerror(-r));
|
||||
} else if (arg_skip_fsck) {
|
||||
if ((r = touch("/fastboot")) < 0)
|
||||
log_warning("Failed to create /fastboot: %s", strerror(-r));
|
||||
}
|
||||
|
||||
if (arg_when > 0) {
|
||||
if ((r = send_shutdownd(arg_when,
|
||||
arg_action == ACTION_HALT ? 'H' :
|
||||
arg_action == ACTION_POWEROFF ? 'P' :
|
||||
'r')) < 0)
|
||||
log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_dry && !arg_immediate)
|
||||
return start_with_fallback(bus);
|
||||
|
||||
@ -4790,6 +4934,10 @@ int main(int argc, char*argv[]) {
|
||||
retval = reload_with_fallback(bus) < 0;
|
||||
break;
|
||||
|
||||
case ACTION_CANCEL_SHUTDOWN:
|
||||
retval = send_shutdownd(0, 0) < 0;
|
||||
break;
|
||||
|
||||
case ACTION_INVALID:
|
||||
case ACTION_RUNLEVEL:
|
||||
default:
|
||||
|
11
src/util.c
11
src/util.c
@ -2997,6 +2997,17 @@ void nss_disable_nscd(void) {
|
||||
log_debug("Cannot disable nscd.");
|
||||
}
|
||||
|
||||
int touch(const char *path) {
|
||||
int fd;
|
||||
|
||||
assert(path);
|
||||
|
||||
if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
|
||||
return -errno;
|
||||
|
||||
close_nointr_nofail(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
|
@ -338,6 +338,8 @@ char *ellipsize(const char *s, unsigned length, unsigned percent);
|
||||
|
||||
void nss_disable_nscd(void);
|
||||
|
||||
int touch(const char *path);
|
||||
|
||||
const char *ioprio_class_to_string(int i);
|
||||
int ioprio_class_from_string(const char *s);
|
||||
|
||||
|
1
units/.gitignore
vendored
1
units/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
systemd-shutdownd.service
|
||||
systemd-random-seed-load.service
|
||||
systemd-random-seed-save.service
|
||||
systemd-initctl.service
|
||||
|
@ -10,7 +10,6 @@
|
||||
[Unit]
|
||||
Description=systemd /dev/initctl Compatibility Socket
|
||||
DefaultDependencies=no
|
||||
After=sysinit.target
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
[Unit]
|
||||
Description=systemd Logging Daemon
|
||||
DefaultDependencies=no
|
||||
After=@SPECIAL_SYSLOG_SERVICE@
|
||||
|
||||
[Service]
|
||||
|
@ -9,9 +9,6 @@
|
||||
|
||||
[Unit]
|
||||
Description=systemd Logging Socket
|
||||
DefaultDependencies=no
|
||||
After=sysinit.target
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=@/org/freedesktop/systemd1/logger
|
||||
|
15
units/systemd-shutdownd.service.in
Normal file
15
units/systemd-shutdownd.service.in
Normal file
@ -0,0 +1,15 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# See systemd.special(7) for details
|
||||
|
||||
[Unit]
|
||||
Description=systemd Shutdown Daemon
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
ExecStart=@rootlibexecdir@/systemd-shutdownd
|
16
units/systemd-shutdownd.socket
Normal file
16
units/systemd-shutdownd.socket
Normal file
@ -0,0 +1,16 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# See systemd.special(7) for details
|
||||
|
||||
[Unit]
|
||||
Description=systemd Shutdown Socket
|
||||
DefaultDependencies=no
|
||||
Before=sockets.target
|
||||
|
||||
[Socket]
|
||||
ListenStream=@/org/freedesktop/systemd1/shutdownd
|
Loading…
x
Reference in New Issue
Block a user