diff options
Diffstat (limited to 'src/initctl/initctl.c')
-rw-r--r-- | src/initctl/initctl.c | 451 |
1 files changed, 0 insertions, 451 deletions
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c deleted file mode 100644 index 0eb008d9e6..0000000000 --- a/src/initctl/initctl.c +++ /dev/null @@ -1,451 +0,0 @@ -/*-*- 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 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 <http://www.gnu.org/licenses/>. -***/ - -#include <sys/socket.h> -#include <sys/types.h> -#include <assert.h> -#include <time.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <sys/poll.h> -#include <sys/epoll.h> -#include <sys/un.h> -#include <fcntl.h> -#include <ctype.h> - -#include <dbus/dbus.h> -#include <systemd/sd-daemon.h> - -#include "util.h" -#include "log.h" -#include "list.h" -#include "initreq.h" -#include "special.h" -#include "dbus-common.h" -#include "def.h" - -#define SERVER_FD_MAX 16 -#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) - -typedef struct Fifo Fifo; - -typedef struct Server { - int epoll_fd; - - LIST_HEAD(Fifo, fifos); - unsigned n_fifos; - - DBusConnection *bus; - - bool quit; -} Server; - -struct Fifo { - Server *server; - - int fd; - - struct init_request buffer; - size_t bytes_read; - - LIST_FIELDS(Fifo, fifo); -}; - -static const char *translate_runlevel(int runlevel, bool *isolate) { - static const struct { - const int runlevel; - const char *special; - bool isolate; - } table[] = { - { '0', SPECIAL_POWEROFF_TARGET, false }, - { '1', SPECIAL_RESCUE_TARGET, true }, - { 's', SPECIAL_RESCUE_TARGET, true }, - { 'S', SPECIAL_RESCUE_TARGET, true }, - { '2', SPECIAL_RUNLEVEL2_TARGET, true }, - { '3', SPECIAL_RUNLEVEL3_TARGET, true }, - { '4', SPECIAL_RUNLEVEL4_TARGET, true }, - { '5', SPECIAL_RUNLEVEL5_TARGET, true }, - { '6', SPECIAL_REBOOT_TARGET, false }, - }; - - unsigned i; - - assert(isolate); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (table[i].runlevel == runlevel) { - *isolate = table[i].isolate; - if (runlevel == '6' && kexec_loaded()) - return SPECIAL_KEXEC_TARGET; - return table[i].special; - } - - return NULL; -} - -static void change_runlevel(Server *s, int runlevel) { - const char *target; - DBusMessage *m = NULL, *reply = NULL; - DBusError error; - const char *mode; - bool isolate = false; - - assert(s); - - dbus_error_init(&error); - - if (!(target = translate_runlevel(runlevel, &isolate))) { - log_warning("Got request for unknown runlevel %c, ignoring.", runlevel); - goto finish; - } - - if (isolate) - mode = "isolate"; - else - mode = "replace"; - - log_debug("Running request %s/start/%s", target, mode); - - if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) { - log_error("Could not allocate message."); - goto finish; - } - - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &target, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { - log_error("Could not attach target and flag information to message."); - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) { - log_error("Failed to start unit: %s", bus_error_message(&error)); - goto finish; - } - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - dbus_error_free(&error); -} - -static void request_process(Server *s, const struct init_request *req) { - assert(s); - assert(req); - - if (req->magic != INIT_MAGIC) { - log_error("Got initctl request with invalid magic. Ignoring."); - return; - } - - switch (req->cmd) { - - case INIT_CMD_RUNLVL: - if (!isprint(req->runlevel)) - log_error("Got invalid runlevel. Ignoring."); - else - switch (req->runlevel) { - - /* we are async anyway, so just use kill for reexec/reload */ - case 'u': - case 'U': - if (kill(1, SIGTERM) < 0) - log_error("kill() failed: %m"); - - /* The bus connection will be - * terminated if PID 1 is reexecuted, - * hence let's just exit here, and - * rely on that we'll be restarted on - * the next request */ - s->quit = true; - break; - - case 'q': - case 'Q': - if (kill(1, SIGHUP) < 0) - log_error("kill() failed: %m"); - break; - - default: - change_runlevel(s, req->runlevel); - } - return; - - case INIT_CMD_POWERFAIL: - case INIT_CMD_POWERFAILNOW: - case INIT_CMD_POWEROK: - log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!"); - return; - - case INIT_CMD_CHANGECONS: - log_warning("Received console change initctl request. This is not implemented in systemd."); - return; - - case INIT_CMD_SETENV: - case INIT_CMD_UNSETENV: - log_warning("Received environment initctl request. This is not implemented in systemd."); - return; - - default: - log_warning("Received unknown initctl request. Ignoring."); - return; - } -} - -static int fifo_process(Fifo *f) { - ssize_t l; - - assert(f); - - errno = EIO; - if ((l = read(f->fd, ((uint8_t*) &f->buffer) + f->bytes_read, sizeof(f->buffer) - f->bytes_read)) <= 0) { - - if (errno == EAGAIN) - return 0; - - log_warning("Failed to read from fifo: %s", strerror(errno)); - return -1; - } - - f->bytes_read += l; - assert(f->bytes_read <= sizeof(f->buffer)); - - if (f->bytes_read == sizeof(f->buffer)) { - request_process(f->server, &f->buffer); - f->bytes_read = 0; - } - - return 0; -} - -static void fifo_free(Fifo *f) { - assert(f); - - if (f->server) { - assert(f->server->n_fifos > 0); - f->server->n_fifos--; - LIST_REMOVE(Fifo, fifo, f->server->fifos, f); - } - - if (f->fd >= 0) { - if (f->server) - epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL); - - close_nointr_nofail(f->fd); - } - - free(f); -} - -static void server_done(Server *s) { - assert(s); - - while (s->fifos) - fifo_free(s->fifos); - - if (s->epoll_fd >= 0) - close_nointr_nofail(s->epoll_fd); - - if (s->bus) { - dbus_connection_flush(s->bus); - dbus_connection_close(s->bus); - dbus_connection_unref(s->bus); - } -} - -static int server_init(Server *s, unsigned n_sockets) { - int r; - unsigned i; - DBusError error; - - assert(s); - assert(n_sockets > 0); - - dbus_error_init(&error); - - zero(*s); - - if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) { - r = -errno; - log_error("Failed to create epoll object: %s", strerror(errno)); - goto fail; - } - - for (i = 0; i < n_sockets; i++) { - struct epoll_event ev; - Fifo *f; - int fd; - - fd = SD_LISTEN_FDS_START+i; - - if ((r = sd_is_fifo(fd, NULL)) < 0) { - log_error("Failed to determine file descriptor type: %s", strerror(-r)); - goto fail; - } - - if (!r) { - log_error("Wrong file descriptor type."); - r = -EINVAL; - goto fail; - } - - if (!(f = new0(Fifo, 1))) { - r = -ENOMEM; - log_error("Failed to create fifo object: %s", strerror(errno)); - goto fail; - } - - f->fd = -1; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = f; - if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { - r = -errno; - fifo_free(f); - log_error("Failed to add fifo fd to epoll object: %s", strerror(errno)); - goto fail; - } - - f->fd = fd; - LIST_PREPEND(Fifo, fifo, s->fifos, f); - f->server = s; - s->n_fifos ++; - } - - if (bus_connect(DBUS_BUS_SYSTEM, &s->bus, NULL, &error) < 0) { - log_error("Failed to get D-Bus connection: %s", bus_error_message(&error)); - goto fail; - } - - return 0; - -fail: - server_done(s); - - dbus_error_free(&error); - return r; -} - -static int process_event(Server *s, struct epoll_event *ev) { - int r; - Fifo *f; - - assert(s); - - if (!(ev->events & EPOLLIN)) { - log_info("Got invalid event from epoll. (3)"); - return -EIO; - } - - f = (Fifo*) ev->data.ptr; - - if ((r = fifo_process(f)) < 0) { - log_info("Got error on fifo: %s", strerror(-r)); - fifo_free(f); - return r; - } - - return 0; -} - -int main(int argc, char *argv[]) { - Server server; - int r = EXIT_FAILURE, n; - - if (getppid() != 1) { - log_error("This program should be invoked by init only."); - return EXIT_FAILURE; - } - - if (argc > 1) { - log_error("This program does not take arguments."); - return EXIT_FAILURE; - } - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - umask(0022); - - if ((n = sd_listen_fds(true)) < 0) { - log_error("Failed to read listening file descriptors from environment: %s", strerror(-r)); - return EXIT_FAILURE; - } - - if (n <= 0 || n > SERVER_FD_MAX) { - log_error("No or too many file descriptors passed."); - return EXIT_FAILURE; - } - - if (server_init(&server, (unsigned) n) < 0) - return EXIT_FAILURE; - - log_debug("systemd-initctl running as pid %lu", (unsigned long) getpid()); - - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - - while (!server.quit) { - struct epoll_event event; - int k; - - if ((k = epoll_wait(server.epoll_fd, - &event, 1, - TIMEOUT_MSEC)) < 0) { - - if (errno == EINTR) - continue; - - log_error("epoll_wait() failed: %s", strerror(errno)); - goto fail; - } - - if (k <= 0) - break; - - if (process_event(&server, &event) < 0) - goto fail; - } - - r = EXIT_SUCCESS; - - log_debug("systemd-initctl stopped as pid %lu", (unsigned long) getpid()); - -fail: - sd_notify(false, - "STATUS=Shutting down..."); - - server_done(&server); - - dbus_shutdown(); - - return r; -} |