From eb22ac37f3e07b9c49a3f8fdc8cc02631faabcb4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Jun 2010 04:44:53 +0200 Subject: systemctl: add /dev/initctl fallback --- fixme | 4 +--- src/automount.c | 2 +- src/systemctl.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/util.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/util.h | 3 ++- 5 files changed, 95 insertions(+), 11 deletions(-) diff --git a/fixme b/fixme index 947ae0d144..709534b2eb 100644 --- a/fixme +++ b/fixme @@ -69,9 +69,7 @@ * install must understand templates -* shutdown must be able to do wall - -* upstart/initctl fallback in systemctl +* upstart fallback in systemctl Regularly: diff --git a/src/automount.c b/src/automount.c index 3d85605fb4..262a47da4e 100644 --- a/src/automount.c +++ b/src/automount.c @@ -708,7 +708,7 @@ static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { goto fail; } - if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet))) != sizeof(packet)) { + if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet), true)) != sizeof(packet)) { log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); goto fail; } diff --git a/src/systemctl.c b/src/systemctl.c index a41d7ea8bd..ec92504f42 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -37,6 +38,7 @@ #include "set.h" #include "utmp-wtmp.h" #include "special.h" +#include "initreq.h" static const char *arg_type = NULL; static bool arg_all = false; @@ -1897,8 +1899,40 @@ static int talk_upstart(DBusConnection *bus) { } static int talk_initctl(void) { - log_error("Talking initctl"); - return 0; + + static const char table[_ACTION_MAX] = { + [ACTION_HALT] = '0', + [ACTION_POWEROFF] = '0', + [ACTION_REBOOT] = '6', + [ACTION_RUNLEVEL2] = '2', + [ACTION_RUNLEVEL3] = '3', + [ACTION_RUNLEVEL4] = '4', + [ACTION_RUNLEVEL5] = '5', + [ACTION_RESCUE] = '1' + }; + + struct init_request request; + int r, fd; + + if (!table[arg_action]) + return 0; + + zero(request); + request.magic = INIT_MAGIC; + request.sleeptime = 0; + request.cmd = INIT_CMD_RUNLVL; + request.runlevel = table[arg_action]; + + if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) + return -errno; + + r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); + close_nointr_nofail(fd); + + if (r < 0) + return errno ? -errno : -EIO; + + return 1; } static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) { @@ -2148,6 +2182,7 @@ int main(int argc, char*argv[]) { case ACTION_RUNLEVEL5: case ACTION_RESCUE: case ACTION_EMERGENCY: + case ACTION_DEFAULT: retval = start_with_fallback(bus) < 0; break; @@ -2156,6 +2191,8 @@ int main(int argc, char*argv[]) { retval = reload_with_fallback(bus) < 0; break; + case ACTION_INVALID: + case ACTION_RUNLEVEL: default: assert_not_reached("Unknown action"); } diff --git a/src/util.c b/src/util.c index 0988675f09..2363ea27b2 100644 --- a/src/util.c +++ b/src/util.c @@ -1964,7 +1964,7 @@ int close_pipe(int p[]) { return a < 0 ? a : b; } -ssize_t loop_read(int fd, void *buf, size_t nbytes) { +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { uint8_t *p; ssize_t n = 0; @@ -1978,10 +1978,10 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes) { if ((k = read(fd, p, nbytes)) <= 0) { - if (errno == EINTR) + if (k < 0 && errno == EINTR) continue; - if (errno == EAGAIN) { + if (k < 0 && errno == EAGAIN && do_poll) { struct pollfd pollfd; zero(pollfd); @@ -2012,6 +2012,54 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes) { return n; } +ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + p = buf; + + while (nbytes > 0) { + ssize_t k; + + if ((k = write(fd, p, nbytes)) <= 0) { + + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + struct pollfd pollfd; + + zero(pollfd); + pollfd.fd = fd; + pollfd.events = POLLOUT; + + if (poll(&pollfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + + return n > 0 ? n : -errno; + } + + if (pollfd.revents != POLLOUT) + return n > 0 ? n : -EIO; + + continue; + } + + return n > 0 ? n : (k < 0 ? -errno : 0); + } + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + int path_is_mount_point(const char *t) { struct stat a, b; char *copy; @@ -2182,7 +2230,7 @@ unsigned long long random_ull(void) { if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) goto fallback; - r = loop_read(fd, &ull, sizeof(ull)); + r = loop_read(fd, &ull, sizeof(ull), true); close_nointr_nofail(fd); if (r != sizeof(ull)) diff --git a/src/util.h b/src/util.h index e371f0b9e5..14c28597ec 100644 --- a/src/util.h +++ b/src/util.h @@ -246,7 +246,8 @@ int sigaction_many(const struct sigaction *sa, ...); int close_pipe(int p[]); -ssize_t loop_read(int fd, void *buf, size_t nbytes); +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); int path_is_mount_point(const char *path); -- cgit v1.2.3-54-g00ecf