initctl.c revision 3143987f93120da696c2d363c34cacf9a82aea93
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/***
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen This file is part of systemd.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Copyright 2010 Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is free software; you can redistribute it and/or modify it
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen under the terms of the GNU Lesser General Public License as published by
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (at your option) any later version.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is distributed in the hope that it will be useful, but
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Lesser General Public License for more details.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen You should have received a copy of the GNU Lesser General Public License
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen***/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <sys/socket.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <sys/types.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <assert.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <time.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <string.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <stdio.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <unistd.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <sys/poll.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/epoll.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/un.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <fcntl.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <ctype.h>
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering#include <dbus/dbus.h>
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen#include <systemd/sd-daemon.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "log.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "list.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "initreq.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "special.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "dbus-common.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "def.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#define SERVER_FD_MAX 16
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersentypedef struct Fifo Fifo;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersentypedef struct Server {
99634696183dfabae20104e58157c69029a11594Tom Gundersen int epoll_fd;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen LIST_HEAD(Fifo, fifos);
99634696183dfabae20104e58157c69029a11594Tom Gundersen unsigned n_fifos;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen DBusConnection *bus;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen bool quit;
99634696183dfabae20104e58157c69029a11594Tom Gundersen} Server;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersenstruct Fifo {
99634696183dfabae20104e58157c69029a11594Tom Gundersen Server *server;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen int fd;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct init_request buffer;
99634696183dfabae20104e58157c69029a11594Tom Gundersen size_t bytes_read;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen LIST_FIELDS(Fifo, fifo);
99634696183dfabae20104e58157c69029a11594Tom Gundersen};
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic const char *translate_runlevel(int runlevel, bool *isolate) {
99634696183dfabae20104e58157c69029a11594Tom Gundersen static const struct {
99634696183dfabae20104e58157c69029a11594Tom Gundersen const int runlevel;
99634696183dfabae20104e58157c69029a11594Tom Gundersen const char *special;
99634696183dfabae20104e58157c69029a11594Tom Gundersen bool isolate;
99634696183dfabae20104e58157c69029a11594Tom Gundersen } table[] = {
99634696183dfabae20104e58157c69029a11594Tom Gundersen { '0', SPECIAL_POWEROFF_TARGET, false },
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen { '1', SPECIAL_RESCUE_TARGET, true },
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen { 's', SPECIAL_RESCUE_TARGET, true },
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen { 'S', SPECIAL_RESCUE_TARGET, true },
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen { '2', SPECIAL_RUNLEVEL2_TARGET, true },
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen { '3', SPECIAL_RUNLEVEL3_TARGET, true },
99634696183dfabae20104e58157c69029a11594Tom Gundersen { '4', SPECIAL_RUNLEVEL4_TARGET, true },
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen { '5', SPECIAL_RUNLEVEL5_TARGET, true },
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen { '6', SPECIAL_REBOOT_TARGET, false },
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen };
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen unsigned i;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen assert(isolate);
99634696183dfabae20104e58157c69029a11594Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen for (i = 0; i < ELEMENTSOF(table); i++)
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen if (table[i].runlevel == runlevel) {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen *isolate = table[i].isolate;
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen if (runlevel == '6' && kexec_loaded())
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poettering return SPECIAL_KEXEC_TARGET;
756775814cf69471f74ce853745bba69f2ba94efThomas Hindoe Paaboel Andersen return table[i].special;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen }
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen return NULL;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poetteringstatic void change_runlevel(Server *s, int runlevel) {
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering const char *target;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering DBusMessage *m = NULL, *reply = NULL;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering DBusError error;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering const char *mode;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering bool isolate = false;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(s);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen dbus_error_init(&error);
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!(target = translate_runlevel(runlevel, &isolate))) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_warning("Got request for unknown runlevel %c, ignoring.", runlevel);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (isolate)
1e2527a6fede996a429bd44b30a15e76ee293437Tom Gundersen mode = "isolate";
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen else
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen mode = "replace";
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_debug("Running request %s/start/%s", target, mode);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Could not allocate message.");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!dbus_message_append_args(m,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBUS_TYPE_STRING, &target,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBUS_TYPE_STRING, &mode,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen DBUS_TYPE_INVALID)) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Could not attach target and flag information to message.");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen goto finish;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt log_error("Failed to start unit: %s", bus_error_message(&error));
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt goto finish;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt }
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenfinish:
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (m)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_message_unref(m);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (reply)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_message_unref(reply);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen dbus_error_free(&error);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic void request_process(Server *s, const struct init_request *req) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert(s);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert(req);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering if (req->magic != INIT_MAGIC) {
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering log_error("Got initctl request with invalid magic. Ignoring.");
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering return;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering }
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen switch (req->cmd) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen case INIT_CMD_RUNLVL:
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (!isprint(req->runlevel))
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_error("Got invalid runlevel. Ignoring.");
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering else
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering switch (req->runlevel) {
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering /* we are async anyway, so just use kill for reexec/reload */
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering case 'u':
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering case 'U':
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (kill(1, SIGTERM) < 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering log_error("kill() failed: %m");
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering /* The bus connection will be
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering * terminated if PID 1 is reexecuted,
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering * hence let's just exit here, and
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * rely on that we'll be restarted on
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * the next request */
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen s->quit = true;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen break;
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering case 'q':
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen case 'Q':
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (kill(1, SIGHUP) < 0)
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen log_error("kill() failed: %m");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen break;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen default:
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen change_runlevel(s, req->runlevel);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering return;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen case INIT_CMD_POWERFAIL:
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen case INIT_CMD_POWERFAILNOW:
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen case INIT_CMD_POWEROK:
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!");
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt return;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering case INIT_CMD_CHANGECONS:
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_warning("Received console change initctl request. This is not implemented in systemd.");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen case INIT_CMD_SETENV:
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen case INIT_CMD_UNSETENV:
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_warning("Received environment initctl request. This is not implemented in systemd.");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen default:
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_warning("Received unknown initctl request. Ignoring.");
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic int fifo_process(Fifo *f) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen ssize_t l;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(f);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen errno = EIO;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if ((l = read(f->fd, ((uint8_t*) &f->buffer) + f->bytes_read, sizeof(f->buffer) - f->bytes_read)) <= 0) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (errno == EAGAIN)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen log_warning("Failed to read from fifo: %s", strerror(errno));
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return -1;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen f->bytes_read += l;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(f->bytes_read <= sizeof(f->buffer));
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (f->bytes_read == sizeof(f->buffer)) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen request_process(f->server, &f->buffer);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen f->bytes_read = 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen }
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersenstatic void fifo_free(Fifo *f) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen assert(f);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (f->server) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen assert(f->server->n_fifos > 0);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen f->server->n_fifos--;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen LIST_REMOVE(Fifo, fifo, f->server->fifos, f);
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (f->fd >= 0) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (f->server)
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen epoll_ctl(f->server->epoll_fd, EPOLL_CTL_DEL, f->fd, NULL);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen close_nointr_nofail(f->fd);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen free(f);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic void server_done(Server *s) {
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering assert(s);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen while (s->fifos)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fifo_free(s->fifos);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering if (s->epoll_fd >= 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen close_nointr_nofail(s->epoll_fd);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (s->bus) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_connection_flush(s->bus);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_connection_close(s->bus);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_connection_unref(s->bus);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen}
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int server_init(Server *s, unsigned n_sockets) {
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen unsigned i;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen DBusError error;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(s);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(n_sockets > 0);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_error_init(&error);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen zero(*s);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (s->epoll_fd < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to create epoll object: %s", strerror(errno));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen for (i = 0; i < n_sockets; i++) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct epoll_event ev;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen Fifo *f;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int fd;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fd = SD_LISTEN_FDS_START+i;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = sd_is_fifo(fd, NULL);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to determine file descriptor type: %s",
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen strerror(-r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!r) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Wrong file descriptor type.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -EINVAL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen f = new0(Fifo, 1);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!f) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -ENOMEM;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to create fifo object: %s",
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen strerror(errno));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering f->fd = -1;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen zero(ev);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen ev.events = EPOLLIN;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen ev.data.ptr = f;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -errno;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fifo_free(f);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to add fifo fd to epoll object: %s",
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen strerror(errno));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen f->fd = fd;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen LIST_PREPEND(Fifo, fifo, s->fifos, f);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen f->server = s;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen s->n_fifos ++;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (bus_connect(DBUS_BUS_SYSTEM, &s->bus, NULL, &error) < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to get D-Bus connection: %s",
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen bus_error_message(&error));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -EIO;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto fail;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenfail:
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen server_done(s);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dbus_error_free(&error);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int process_event(Server *s, struct epoll_event *ev) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen Fifo *f;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(s);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!(ev->events & EPOLLIN)) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_info("Got invalid event from epoll. (3)");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return -EIO;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen f = (Fifo*) ev->data.ptr;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if ((r = fifo_process(f)) < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_info("Got error on fifo: %s", strerror(-r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fifo_free(f);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return r;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return 0;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenint main(int argc, char *argv[]) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen Server server;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r = EXIT_FAILURE, n;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (getppid() != 1) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("This program should be invoked by init only.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return EXIT_FAILURE;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (argc > 1) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("This program does not take arguments.");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return EXIT_FAILURE;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_set_target(LOG_TARGET_AUTO);
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen log_parse_environment();
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_open();
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen umask(0022);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if ((n = sd_listen_fds(true)) < 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen return EXIT_FAILURE;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (n <= 0 || n > SERVER_FD_MAX) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("No or too many file descriptors passed.");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen return EXIT_FAILURE;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (server_init(&server, (unsigned) n) < 0)
1231c4d238844e77018caf5b5852f01d96373c47Tom Gundersen return EXIT_FAILURE;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_debug("systemd-initctl running as pid %lu", (unsigned long) getpid());
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen sd_notify(false,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen "READY=1\n"
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen "STATUS=Processing requests...");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen while (!server.quit) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen struct epoll_event event;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen int k;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if ((k = epoll_wait(server.epoll_fd,
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams &event, 1,
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams TIMEOUT_MSEC)) < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (errno == EINTR)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen continue;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("epoll_wait() failed: %s", strerror(errno));
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto fail;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (k <= 0)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen break;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (process_event(&server, &event) < 0)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto fail;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen r = EXIT_SUCCESS;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_debug("systemd-initctl stopped as pid %lu", (unsigned long) getpid());
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenfail:
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen sd_notify(false,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen "STATUS=Shutting down...");
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen server_done(&server);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen dbus_shutdown();
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen return r;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen}
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen