summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-06-18 04:44:53 +0200
committerLennart Poettering <lennart@poettering.net>2010-06-18 04:44:53 +0200
commiteb22ac37f3e07b9c49a3f8fdc8cc02631faabcb4 (patch)
tree2446c4f33cd0990c97e6088850c43ad4b266ce73
parent55293c152a0c8a8720461a26e2d6e24b5612d1f0 (diff)
systemctl: add /dev/initctl fallback
-rw-r--r--fixme4
-rw-r--r--src/automount.c2
-rw-r--r--src/systemctl.c41
-rw-r--r--src/util.c56
-rw-r--r--src/util.h3
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 <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");
}
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);