chiark / gitweb /
systemctl: add /dev/initctl fallback
authorLennart Poettering <lennart@poettering.net>
Fri, 18 Jun 2010 02:44:53 +0000 (04:44 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 18 Jun 2010 02:44:53 +0000 (04:44 +0200)
fixme
src/automount.c
src/systemctl.c
src/util.c
src/util.h

diff --git a/fixme b/fixme
index 947ae0d..709534b 100644 (file)
--- 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:
 
index 3d85605..262a47d 100644 (file)
@@ -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;
         }
index a41d7ea..ec92504 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/ioctl.h>
 #include <termios.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include <dbus/dbus.h>
 
@@ -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");
         }
index 0988675..2363ea2 100644 (file)
@@ -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))
index e371f0b..14c2859 100644 (file)
@@ -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);