aboutsummaryrefslogtreecommitdiff
path: root/src/rc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rc')
-rw-r--r--src/rc/.gitignore66
-rw-r--r--src/rc/Makefile186
-rw-r--r--src/rc/_usage.c95
-rw-r--r--src/rc/_usage.h56
-rw-r--r--src/rc/broadcast.c211
-rw-r--r--src/rc/broadcast.h16
-rw-r--r--src/rc/checkpath.c452
-rw-r--r--src/rc/do_e.c228
-rw-r--r--src/rc/do_mark_service.c91
-rw-r--r--src/rc/do_service.c76
-rw-r--r--src/rc/do_value.c65
-rw-r--r--src/rc/fstabinfo.c339
-rw-r--r--src/rc/is_newer_than.c34
-rw-r--r--src/rc/is_older_than.c35
-rw-r--r--src/rc/kill_all.c260
-rw-r--r--src/rc/meson.build320
-rw-r--r--src/rc/mountinfo.c488
-rw-r--r--src/rc/openrc-init.c333
-rw-r--r--src/rc/openrc-run.c1436
-rw-r--r--src/rc/openrc-shutdown.c358
-rw-r--r--src/rc/rc-abort.c43
-rw-r--r--src/rc/rc-depend.c177
-rw-r--r--src/rc/rc-logger.c314
-rw-r--r--src/rc/rc-logger.h23
-rw-r--r--src/rc/rc-misc.c492
-rw-r--r--src/rc/rc-pipes.c56
-rw-r--r--src/rc/rc-pipes.h18
-rw-r--r--src/rc/rc-plugin.c245
-rw-r--r--src/rc/rc-plugin.h41
-rw-r--r--src/rc/rc-schedules.c433
-rw-r--r--src/rc/rc-schedules.h26
-rw-r--r--src/rc/rc-selinux.c417
-rw-r--r--src/rc/rc-selinux.h36
-rw-r--r--src/rc/rc-service.c171
-rw-r--r--src/rc/rc-status.c465
-rw-r--r--src/rc/rc-sysvinit.c102
-rw-r--r--src/rc/rc-sysvinit.h72
-rw-r--r--src/rc/rc-update.c353
-rw-r--r--src/rc/rc-wtmp.c51
-rw-r--r--src/rc/rc.c1118
-rw-r--r--src/rc/seedrng.c522
-rw-r--r--src/rc/shell_var.c41
-rw-r--r--src/rc/start-stop-daemon.c1205
-rw-r--r--src/rc/start-stop-daemon.pam6
-rw-r--r--src/rc/supervise-daemon.c1250
-rw-r--r--src/rc/supervise-daemon.pam6
-rw-r--r--src/rc/swclock.c106
47 files changed, 0 insertions, 12934 deletions
diff --git a/src/rc/.gitignore b/src/rc/.gitignore
deleted file mode 100644
index a43088aa..00000000
--- a/src/rc/.gitignore
+++ /dev/null
@@ -1,66 +0,0 @@
-version.h
-rc-status
-rc-service
-rc-update
-runscript
-service
-start-stop-daemon
-supervise-daemon
-einfon
-einfo
-ewarnn
-ewarn
-eerrorn
-eerror
-ebegin
-eend
-ewend
-eindent
-eoutdent
-esyslog
-eval_ecolors
-ewaitfile
-veinfo
-vewarn
-vebegin
-veend
-vewend
-veindent
-veoutdent
-service_starting
-service_started
-service_stopping
-service_stopped
-service_inactive
-service_wasinactive
-service_hotplugged
-service_started_daemon
-service_crashed
-checkpath
-fstabinfo
-mountinfo
-swclock
-rc-depend
-service_get_value
-service_set_value
-get_options
-save_options
-shell_var
-is_newer_than
-is_older_than
-mark_service_starting
-mark_service_started
-mark_service_stopping
-mark_service_stopped
-mark_service_inactive
-mark_service_wasinactive
-mark_service_hotplugged
-mark_service_failed
-mark_service_crashed
-rc-abort
-rc
-openrc
-openrc-init
-openrc-run
-openrc-shutdown
-kill_all
diff --git a/src/rc/Makefile b/src/rc/Makefile
deleted file mode 100644
index 306f6d8d..00000000
--- a/src/rc/Makefile
+++ /dev/null
@@ -1,186 +0,0 @@
-include ../../Makefile.inc
-MK= ../../mk
-include ${MK}/os.mk
-
-SRCS= checkpath.c do_e.c do_mark_service.c do_service.c \
- do_value.c fstabinfo.c is_newer_than.c is_older_than.c \
- mountinfo.c openrc-run.c rc-abort.c rc.c \
- rc-depend.c rc-logger.c rc-misc.c rc-pipes.c \
- rc-plugin.c rc-service.c rc-status.c rc-update.c \
- shell_var.c start-stop-daemon.c supervise-daemon.c swclock.c _usage.c
-
-ifeq (${MKSELINUX},yes)
-SRCS+= rc-selinux.c
-endif
-
-ifeq (${OS},Linux)
-SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-sysvinit.c broadcast.c \
- rc-wtmp.c seedrng.c
-endif
-
-CLEANFILES= version.h rc-selinux.o
-
-BINDIR= ${PREFIX}/bin
-SBINDIR= ${PREFIX}/sbin
-LINKDIR= ${LIBEXECDIR}
-
-BINPROGS= rc-status
-SBINPROGS = openrc openrc-run rc rc-service rc-update runscript \
- start-stop-daemon supervise-daemon
-RC_BINPROGS= einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
- eindent eoutdent esyslog eval_ecolors ewaitfile \
- veinfo vewarn vebegin veend vewend veindent veoutdent \
- checkpath fstabinfo mountinfo rc-depend \
- is_newer_than is_older_than \
- service_get_value service_set_value get_options save_options \
- service_starting service_started \
- service_stopping service_stopped \
- service_inactive service_wasinactive \
- service_hotplugged service_started_daemon service_crashed \
- shell_var
-RC_SBINPROGS= mark_service_starting mark_service_started \
- mark_service_stopping mark_service_stopped \
- mark_service_inactive mark_service_wasinactive \
- mark_service_hotplugged mark_service_failed \
- mark_service_crashed \
- rc-abort swclock
-
-ifeq (${OS},Linux)
-RC_BINPROGS+= kill_all
-RC_SBINPROGS+= seedrng
-SBINPROGS+= openrc-init openrc-shutdown
-endif
-
-ALL_PROGS= ${BINPROGS} ${SBINPROGS} ${RC_BINPROGS} ${RC_SBINPROGS}
-CLEANFILES+= ${ALL_PROGS}
-
-LOCAL_CPPFLAGS=-I../includes -I../librc -I../libeinfo
-LOCAL_LDFLAGS=-L../librc -L../libeinfo
-LDADD+= -lutil -lrc -leinfo
-
-include ${MK}/prog.mk
-include ${MK}/gitver.mk
-include ${MK}/cc.mk
-
-include ${MK}/termcap.mk
-LDADD+= ${LIBDL} ${LIBKVM}
-include ${MK}/pam.mk
-
-${SRCS}: version.h
-
-.PHONY: version.h.tmp
-version.h.tmp:
- echo "#define VERSION \"${VERSION}${GITVER}\"" >$@
- if test -n "${BRANDING}"; then \
- echo "#define BRANDING \"${BRANDING}\"" >> $@; \
- fi
-
-version.h: version.h.tmp
- cmp -s $@.tmp $@ && rm $@.tmp || mv $@.tmp $@
-
-install: all
- ${INSTALL} -d ${DESTDIR}${SBINDIR}
- ${INSTALL} -m ${BINMODE} ${SBINPROGS} ${DESTDIR}${SBINDIR}
- ${INSTALL} -d ${DESTDIR}${BINDIR}
- ${INSTALL} -m ${BINMODE} ${BINPROGS} ${DESTDIR}${BINDIR}
- ${INSTALL} -d ${DESTDIR}${LINKDIR}/bin
- ${INSTALL} -m ${BINMODE} ${RC_BINPROGS} ${DESTDIR}${LINKDIR}/bin
- ${INSTALL} -d ${DESTDIR}${LINKDIR}/sbin
- ${INSTALL} -m ${BINMODE} ${RC_SBINPROGS} ${DESTDIR}${LINKDIR}/sbin
- if test "${MKPAM}" = pam; then \
- ${INSTALL} -d ${DESTDIR}${PAMDIR}; \
- ${INSTALL} -m ${PAMMODE} start-stop-daemon.pam ${DESTDIR}${PAMDIR}/start-stop-daemon; \
- ${INSTALL} -m ${PAMMODE} supervise-daemon.pam ${DESTDIR}${PAMDIR}/supervise-daemon; \
- fi
-
-check test::
-
-all: ${ALL_PROGS}
-
-checkpath: checkpath.o _usage.o rc-misc.o
-ifeq (${MKSELINUX},yes)
-checkpath: rc-selinux.o
-endif
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-kill_all: kill_all.o _usage.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
-eindent eoutdent esyslog eval_ecolors ewaitfile \
-veinfo vewarn vebegin veend vewend veindent veoutdent: do_e.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-fstabinfo: fstabinfo.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-openrc-init: openrc-init.o rc-plugin.o rc-wtmp.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-is_newer_than: is_newer_than.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-is_older_than: is_older_than.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-mark_service_starting mark_service_started \
-mark_service_stopping mark_service_stopped \
-mark_service_inactive mark_service_wasinactive \
-mark_service_hotplugged mark_service_failed \
-mark_service_crashed: do_mark_service.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-mountinfo: mountinfo.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-openrc-shutdown: openrc-shutdown.o rc-misc.o _usage.o broadcast.o rc-wtmp.o rc-sysvinit.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o
-ifeq (${MKSELINUX},yes)
-openrc-run runscript: rc-selinux.o
-endif
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-rc-abort: rc-abort.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ -leinfo
-
-rc-depend: rc-depend.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-rc-status: rc-status.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-rc-service: rc-service.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-rc-update: rc-update.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-pipes.o rc-schedules.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-plugin.o rc-schedules.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-service_get_value service_set_value get_options save_options: do_value.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-service_starting service_started \
-service_stopping service_stopped \
-service_inactive service_wasinactive \
-service_hotplugged service_started_daemon \
-service_crashed: do_service.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-shell_var: shell_var.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^
-
-swclock: swclock.o _usage.o rc-misc.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
-
-seedrng: seedrng.o _usage.o
- ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD}
diff --git a/src/rc/_usage.c b/src/rc/_usage.c
deleted file mode 100644
index ed4c63e0..00000000
--- a/src/rc/_usage.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-#include "version.h"
-
-#if lint
-# define _noreturn
-#endif
-#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
-# define _noreturn __attribute__ ((__noreturn__))
-#else
-# define _noreturn
-#endif
-
-void set_quiet_options(void)
-{
- static int qcount = 0;
-
- qcount ++;
- switch (qcount) {
- case 1:
- setenv ("EINFO_QUIET", "YES", 1);
- break;
- case 2:
- setenv ("EERROR_QUIET", "YES", 1);
- break;
- }
-}
-
-_noreturn void show_version(void)
-{
- const char *systype = NULL;
-
- printf("%s (OpenRC", applet);
- if ((systype = rc_sys()))
- printf(" [%s]", systype);
- printf(") %s", VERSION);
-#ifdef BRANDING
- printf(" (%s)", BRANDING);
-#endif
- printf("\n");
- exit(EXIT_SUCCESS);
-}
-
-_noreturn void usage(int exit_status)
-{
- const char * const has_arg[] = { "", "<arg>", "[arg]" };
- int i;
- int len;
- char *lo;
- char *p;
- char *token;
- char val[4] = "-?,";
-
- if (usagestring)
- printf("%s", usagestring);
- else
- printf("Usage: %s [options] ", applet);
-
- if (extraopts)
- printf("%s", extraopts);
-
- printf("\n\nOptions: [ %s ]\n", getoptstring);
- for (i = 0; longopts[i].name; ++i) {
- val[1] = longopts[i].val;
- len = printf(" %3s --%s %s", isprint(longopts[i].val) ? val : "",
- longopts[i].name, has_arg[longopts[i].has_arg]);
-
- lo = p = xstrdup(longopts_help[i]);
- while ((token = strsep(&p, "\n"))) {
- len = 36 - len;
- if (len > 0)
- printf("%*s", len, "");
- puts(token);
- len = 0;
- }
- free(lo);
- }
- exit(exit_status);
-}
diff --git a/src/rc/_usage.h b/src/rc/_usage.h
deleted file mode 100644
index 62c131d4..00000000
--- a/src/rc/_usage.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <getopt.h>
-
-#define getoptstring_COMMON "ChqVv"
-
-#define longopts_COMMON \
- { "help", 0, NULL, 'h'}, \
- { "nocolor", 0, NULL, 'C'}, \
- { "version", 0, NULL, 'V'}, \
- { "verbose", 0, NULL, 'v'}, \
- { "quiet", 0, NULL, 'q'}, \
- { NULL, 0, NULL, 0 }
-
-#define longopts_help_COMMON \
- "Display this help output", \
- "Disable color output", \
- "Display software version", \
- "Run verbosely", \
- "Run quietly (repeat to suppress errors)"
-
-#define case_RC_COMMON_getopt_case_C setenv ("EINFO_COLOR", "NO", 1);
-#define case_RC_COMMON_getopt_case_h usage (EXIT_SUCCESS);
-#define case_RC_COMMON_getopt_case_V if (argc == 2) show_version();
-#define case_RC_COMMON_getopt_case_v setenv ("EINFO_VERBOSE", "YES", 1);
-#define case_RC_COMMON_getopt_case_q set_quiet_options();
-#define case_RC_COMMON_getopt_default usage (EXIT_FAILURE);
-
-#define case_RC_COMMON_GETOPT \
- case 'C': case_RC_COMMON_getopt_case_C; break; \
- case 'h': case_RC_COMMON_getopt_case_h; break; \
- case 'V': case_RC_COMMON_getopt_case_V; break; \
- case 'v': case_RC_COMMON_getopt_case_v; break; \
- case 'q': case_RC_COMMON_getopt_case_q; break; \
- default: case_RC_COMMON_getopt_default; break;
-
-extern const char *applet;
-extern const char *extraopts;
-extern const char getoptstring[];
-extern const struct option longopts[];
-extern const char * const longopts_help[];
-extern const char *usagestring;
-
-void set_quiet_options(void);
-void show_version(void);
-void usage(int exit_status);
diff --git a/src/rc/broadcast.c b/src/rc/broadcast.c
deleted file mode 100644
index 402a9fb9..00000000
--- a/src/rc/broadcast.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * broadcast.c
- * broadcast a message to every logged in user
- */
-
-/*
- * Copyright 2018 Sony Interactive Entertainment Inc.
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <utmp.h>
-#include <utmpx.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <paths.h>
-#include <sys/utsname.h>
-
-#include "broadcast.h"
-#include "helpers.h"
-
-#ifndef _PATH_DEV
-# define _PATH_DEV "/dev/"
-#endif
-
-static sigjmp_buf jbuf;
-
-/*
- * Alarm handler
- */
-/*ARGSUSED*/
-# ifdef __GNUC__
-static void handler(int arg __attribute__((unused)))
-# else
-static void handler(int arg)
-# endif
-{
- siglongjmp(jbuf, 1);
-}
-
-static void getuidtty(char **userp, char **ttyp)
-{
- struct passwd *pwd;
- uid_t uid;
- char *tty;
- static char uidbuf[32];
- char *ttynm = NULL;
-
- uid = getuid();
- if ((pwd = getpwuid(uid)) != NULL) {
- uidbuf[0] = 0;
- strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1);
- } else {
- if (uid)
- sprintf(uidbuf, "uid %d", (int) uid);
- else
- sprintf(uidbuf, "root");
- }
-
- if ((tty = ttyname(0)) != NULL) {
- const size_t plen = strlen(_PATH_DEV);
- if (strncmp(tty, _PATH_DEV, plen) == 0) {
- tty += plen;
- if (tty[0] == '/')
- tty++;
- }
- xasprintf(&ttynm, "(%s) ", tty);
- }
-
- *userp = uidbuf;
- *ttyp = ttynm;
-}
-
-/*
- * Check whether the given filename looks like a tty device.
- */
-static int file_isatty(const char *fname)
-{
- struct stat st;
- int major;
-
- if (stat(fname, &st) < 0)
- return 0;
-
- if (st.st_nlink != 1 || !S_ISCHR(st.st_mode))
- return 0;
-
- /*
- * It would be an impossible task to list all major/minors
- * of tty devices here, so we just exclude the obvious
- * majors of which just opening has side-effects:
- * printers and tapes.
- */
- major = major(st.st_dev);
- if (major == 1 || major == 2 || major == 6 || major == 9 ||
- major == 12 || major == 16 || major == 21 || major == 27 ||
- major == 37 || major == 96 || major == 97 || major == 206 ||
- major == 230)
- return 0;
- return 1;
-}
-
-/*
- * broadcast function.
- *
- * NB: Not multithread safe.
- */
-void broadcast(char *text)
-{
- char *tty;
- char *user;
- struct utsname name;
- time_t t;
- char *date;
- char *p;
- char *line = NULL;
- struct sigaction sa;
- int flags;
- char *term = NULL;
- struct utmpx *utmp;
- /*
- * These are set across the sigsetjmp call, so they can't be stored on
- * the stack, otherwise they might be clobbered.
- */
- static int fd;
- static FILE *tp;
-
- getuidtty(&user, &tty);
-
- /*
- * Get and report current hostname, to make it easier to find out
- * which machine is being shut down.
- */
- uname(&name);
-
- /* Get the time */
- time(&t);
- date = ctime(&t);
- p = strchr(date, '\n');
- if (p)
- *p = 0;
-
- xasprintf(&line, "\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n",
- user, name.nodename, tty, date);
- free(tty);
-
- /*
- * Fork to avoid hanging in a write()
- */
- if (fork() != 0)
- return;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = handler;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGALRM, &sa, NULL);
-
- setutxent();
-
- while ((utmp = getutxent()) != NULL) {
- if (utmp->ut_type != USER_PROCESS || utmp->ut_user[0] == 0)
- continue;
- if (strncmp(utmp->ut_line, _PATH_DEV, strlen(_PATH_DEV)) == 0)
- xasprintf(&term, "%s", utmp->ut_line);
- else
- xasprintf(&term, "%s%s", _PATH_DEV, utmp->ut_line);
- if (strstr(term, "/../")) {
- free(term);
- continue;
- }
-
- /*
- * Open it non-delay
- */
- if (sigsetjmp(jbuf, 1) == 0) {
- alarm(2);
- flags = O_WRONLY|O_NDELAY|O_NOCTTY;
- if (file_isatty(term) && (fd = open(term, flags)) >= 0) {
- if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) {
- fputs(line, tp);
- fputs(text, tp);
- fflush(tp);
- }
- }
- }
- alarm(0);
- if (fd >= 0)
- close(fd);
- if (tp != NULL)
- fclose(tp);
- free(term);
- }
- endutxent();
- free(line);
- exit(0);
-}
diff --git a/src/rc/broadcast.h b/src/rc/broadcast.h
deleted file mode 100644
index 2255fe67..00000000
--- a/src/rc/broadcast.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2018 Sony Interactive Entertainment Inc.
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef BROADCAST_H
-#define BROADCAST_H
-
-void broadcast(char *text);
-
-#endif
diff --git a/src/rc/checkpath.c b/src/rc/checkpath.c
deleted file mode 100644
index 550e7cea..00000000
--- a/src/rc/checkpath.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * checkpath.c
- * Checks for the existance of a file or directory and creates it
- * if necessary. It can also correct its ownership.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <grp.h>
-#include <libgen.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-selinux.h"
-#include "_usage.h"
-
-typedef enum {
- inode_unknown = 0,
- inode_file = 1,
- inode_dir = 2,
- inode_fifo = 3,
-} inode_t;
-
-const char *applet = NULL;
-const char *extraopts ="path1 [path2] [...]";
-const char getoptstring[] = "dDfFpm:o:sW" getoptstring_COMMON;
-const struct option longopts[] = {
- { "directory", 0, NULL, 'd'},
- { "directory-truncate", 0, NULL, 'D'},
- { "file", 0, NULL, 'f'},
- { "file-truncate", 0, NULL, 'F'},
- { "pipe", 0, NULL, 'p'},
- { "mode", 1, NULL, 'm'},
- { "owner", 1, NULL, 'o'},
- { "symlinks", 0, NULL, 's'},
- { "writable", 0, NULL, 'W'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Create a directory if not exists",
- "Create/empty directory",
- "Create a file if not exists",
- "Truncate file",
- "Create a named pipe (FIFO) if not exists",
- "Mode to check",
- "Owner to check (user:group)",
- "follow symbolic links (irrelivent on linux)",
- "Check whether the path is writable or not",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static int get_dirfd(char *path, bool symlinks)
-{
- char *ch;
- char *item;
- char *linkpath = NULL;
- char *path_dupe;
- char *str;
- int components = 0;
- int dirfd;
- int flags = 0;
- int new_dirfd;
- struct stat st;
- ssize_t linksize;
-
- if (!path || *path != '/')
- eerrorx("%s: empty or relative path", applet);
- dirfd = openat(dirfd, "/", O_RDONLY);
- if (dirfd == -1)
- eerrorx("%s: unable to open the root directory: %s",
- applet, strerror(errno));
- ch = path;
- while (*ch) {
- if (*ch == '/')
- components++;
- ch++;
- }
- path_dupe = xstrdup(path);
- item = strtok(path_dupe, "/");
-#ifdef O_PATH
- flags |= O_PATH;
-#endif
- if (!symlinks)
- flags |= O_NOFOLLOW;
- flags |= O_RDONLY;
- while (dirfd > 0 && item && components > 1) {
- str = xstrdup(linkpath ? linkpath : item);
- new_dirfd = openat(dirfd, str, flags);
- if (new_dirfd == -1)
- eerrorx("%s: %s: could not open %s: %s", applet, path, str,
- strerror(errno));
- if (fstat(new_dirfd, &st) == -1)
- eerrorx("%s: %s: unable to stat %s: %s", applet, path, item,
- strerror(errno));
- if (S_ISLNK(st.st_mode) ) {
- if (st.st_uid != 0)
- eerrorx("%s: %s: symbolic link %s not owned by root",
- applet, path, str);
- linksize = st.st_size+1;
- if (linkpath)
- free(linkpath);
- linkpath = xmalloc(linksize);
- memset(linkpath, 0, linksize);
- if (readlinkat(new_dirfd, "", linkpath, linksize) != st.st_size)
- eerrorx("%s: symbolic link destination changed", applet);
- /*
- * now follow the symlink.
- */
- close(new_dirfd);
- } else {
- /* now walk down the directory path */
- close(dirfd);
- dirfd = new_dirfd;
- free(linkpath);
- linkpath = NULL;
- item = strtok(NULL, "/");
- components--;
- }
- }
- free(path_dupe);
- free(linkpath);
- return dirfd;
-}
-
-static char *clean_path(char *path)
-{
- char *ch;
- char *ch2;
- char *str;
- str = xmalloc(strlen(path) + 1);
- ch = path;
- ch2 = str;
- while (true) {
- *ch2 = *ch;
- ch++;
- ch2++;
- if (!*(ch-1))
- break;
- while (*(ch - 1) == '/' && *ch == '/')
- ch++;
- }
- /* get rid of trailing / characters */
- while ((ch = strrchr(str, '/'))) {
- if (ch == str)
- break;
- if (!*(ch+1))
- *ch = 0;
- else
- break;
- }
- return str;
-}
-
-static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
- inode_t type, bool trunc, bool chowner, bool symlinks, bool selinux_on)
-{
- struct stat st;
- char *name = NULL;
- int dirfd;
- int fd;
- int flags;
- int r;
- int readfd;
- int readflags;
- int u;
-
- memset(&st, 0, sizeof(st));
- flags = O_CREAT|O_NDELAY|O_WRONLY|O_NOCTTY;
- readflags = O_NDELAY|O_NOCTTY|O_RDONLY;
-#ifdef O_CLOEXEC
- flags |= O_CLOEXEC;
- readflags |= O_CLOEXEC;
-#endif
-#ifdef O_NOFOLLOW
- flags |= O_NOFOLLOW;
- readflags |= O_NOFOLLOW;
-#endif
- if (trunc)
- flags |= O_TRUNC;
- xasprintf(&name, "%s", basename_c(path));
- dirfd = get_dirfd(path, symlinks);
- readfd = openat(dirfd, name, readflags);
- if (readfd == -1 || (type == inode_file && trunc)) {
- if (type == inode_file) {
- einfo("%s: creating file", path);
- if (!mode) /* 664 */
- mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
- u = umask(0);
- fd = openat(dirfd, name, flags, mode);
- umask(u);
- if (fd == -1) {
- eerror("%s: open: %s", applet, strerror(errno));
- return -1;
- }
- if (readfd != -1 && trunc)
- close(readfd);
- readfd = fd;
- } else if (type == inode_dir) {
- einfo("%s: creating directory", path);
- if (!mode) /* 775 */
- mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
- u = umask(0);
- /* We do not recursively create parents */
- r = mkdirat(dirfd, name, mode);
- umask(u);
- if (r == -1 && errno != EEXIST) {
- eerror("%s: mkdirat: %s", applet,
- strerror (errno));
- return -1;
- }
- readfd = openat(dirfd, name, readflags);
- if (readfd == -1) {
- eerror("%s: unable to open directory: %s", applet,
- strerror(errno));
- return -1;
- }
- } else if (type == inode_fifo) {
- einfo("%s: creating fifo", path);
- if (!mode) /* 600 */
- mode = S_IRUSR | S_IWUSR;
- u = umask(0);
- r = mkfifo(path, mode);
- umask(u);
- if (r == -1 && errno != EEXIST) {
- eerror("%s: mkfifo: %s", applet,
- strerror (errno));
- return -1;
- }
- readfd = openat(dirfd, name, readflags);
- if (readfd == -1) {
- eerror("%s: unable to open fifo: %s", applet,
- strerror(errno));
- return -1;
- }
- }
- }
- if (fstat(readfd, &st) != -1) {
- if (type != inode_dir && S_ISDIR(st.st_mode)) {
- eerror("%s: is a directory", path);
- close(readfd);
- return 1;
- }
- if (type != inode_file && S_ISREG(st.st_mode)) {
- eerror("%s: is a file", path);
- close(readfd);
- return 1;
- }
- if (type != inode_fifo && S_ISFIFO(st.st_mode)) {
- eerror("%s: is a fifo", path);
- close(readfd);
- return -1;
- }
-
- if (mode && (st.st_mode & 0777) != mode) {
- if ((type != inode_dir) && (st.st_nlink > 1)) {
- eerror("%s: chmod: Too many hard links to %s", applet, path);
- close(readfd);
- return -1;
- }
- if (S_ISLNK(st.st_mode)) {
- eerror("%s: chmod: %s %s", applet, path, " is a symbolic link");
- close(readfd);
- return -1;
- }
- einfo("%s: correcting mode", path);
- if (fchmod(readfd, mode)) {
- eerror("%s: chmod: %s", applet, strerror(errno));
- close(readfd);
- return -1;
- }
- }
-
- if (chowner && (st.st_uid != uid || st.st_gid != gid)) {
- if ((type != inode_dir) && (st.st_nlink > 1)) {
- eerror("%s: chown: %s %s", applet, "Too many hard links to", path);
- close(readfd);
- return -1;
- }
- if (S_ISLNK(st.st_mode)) {
- eerror("%s: chown: %s %s", applet, path, " is a symbolic link");
- close(readfd);
- return -1;
- }
- einfo("%s: correcting owner", path);
- if (fchown(readfd, uid, gid)) {
- eerror("%s: chown: %s", applet, strerror(errno));
- close(readfd);
- return -1;
- }
- }
- if (selinux_on)
- selinux_util_label(path);
- } else {
- eerror("fstat: %s: %s", path, strerror(errno));
- close(readfd);
- return -1;
- }
- close(readfd);
-
- return 0;
-}
-
-static int parse_owner(struct passwd **user, struct group **group,
- const char *owner)
-{
- char *u = xstrdup (owner);
- char *g = strchr (u, ':');
- int id = 0;
- int retval = 0;
-
- if (g)
- *g++ = '\0';
-
- if (user && *u) {
- if (sscanf(u, "%d", &id) == 1)
- *user = getpwuid((uid_t) id);
- else
- *user = getpwnam(u);
- if (*user == NULL)
- retval = -1;
- }
-
- if (group && g && *g) {
- if (sscanf(g, "%d", &id) == 1)
- *group = getgrgid((gid_t) id);
- else
- *group = getgrnam(g);
- if (*group == NULL)
- retval = -1;
- }
-
- free(u);
- return retval;
-}
-
-int main(int argc, char **argv)
-{
- int opt;
- uid_t uid = geteuid();
- gid_t gid = getgid();
- mode_t mode = 0;
- struct passwd *pw = NULL;
- struct group *gr = NULL;
- inode_t type = inode_unknown;
- int retval = EXIT_SUCCESS;
- bool trunc = false;
- bool chowner = false;
- bool symlinks = false;
- bool writable = false;
- bool selinux_on = false;
- char *path = NULL;
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'D':
- trunc = true;
- /* falls through */
- case 'd':
- type = inode_dir;
- break;
- case 'F':
- trunc = true;
- /* falls through */
- case 'f':
- type = inode_file;
- break;
- case 'p':
- type = inode_fifo;
- break;
- case 'm':
- if (parse_mode(&mode, optarg) != 0)
- eerrorx("%s: invalid mode `%s'",
- applet, optarg);
- break;
- case 'o':
- chowner = true;
- if (parse_owner(&pw, &gr, optarg) != 0)
- eerrorx("%s: owner `%s' not found",
- applet, optarg);
- break;
- case 's':
-#ifndef O_PATH
- symlinks = true;
-#endif
- break;
- case 'W':
- writable = true;
- break;
-
- case_RC_COMMON_GETOPT
- }
- }
-
- if (optind >= argc)
- usage(EXIT_FAILURE);
-
- if (writable && type != inode_unknown)
- eerrorx("%s: -W cannot be specified along with -d, -f or -p", applet);
-
- if (pw) {
- uid = pw->pw_uid;
- gid = pw->pw_gid;
- }
- if (gr)
- gid = gr->gr_gid;
-
- if (selinux_util_open() == 1)
- selinux_on = true;
-
- while (optind < argc) {
- path = clean_path(argv[optind]);
- if (writable)
- exit(!is_writable(path));
- if (do_check(path, uid, gid, mode, type, trunc, chowner,
- symlinks, selinux_on))
- retval = EXIT_FAILURE;
- optind++;
- free(path);
- }
-
- if (selinux_on)
- selinux_util_close();
-
- return retval;
-}
diff --git a/src/rc/do_e.c b/src/rc/do_e.c
deleted file mode 100644
index 1778efe4..00000000
--- a/src/rc/do_e.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#define SYSLOG_NAMES
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "helpers.h"
-
-/* usecs to wait while we poll the file existance */
-#define WAIT_INTERVAL 20000000
-
-const char *applet = NULL;
-
-static int syslog_decode(char *name, const CODE *codetab)
-{
- const CODE *c;
-
- if (isdigit((unsigned char)*name))
- return atoi(name);
-
- for (c = codetab; c->c_name; c++)
- if (!strcasecmp(name, c->c_name))
- return c->c_val;
-
- return -1;
-}
-
-int main(int argc, char **argv)
-{
- int retval = EXIT_SUCCESS;
- int i;
- size_t l = 0;
- char *message = NULL;
- char *p;
- int level = 0;
- struct timespec ts;
- struct timeval stop, now;
- int (*e) (const char *, ...) EINFO_PRINTF(1, 2) = NULL;
- int (*ee) (int, const char *, ...) EINFO_PRINTF(2, 3) = NULL;
-
- applet = basename_c(argv[0]);
- argc--;
- argv++;
-
- if (strcmp(applet, "eval_ecolors") == 0) {
- printf("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
- ecolor(ECOLOR_GOOD),
- ecolor(ECOLOR_WARN),
- ecolor(ECOLOR_BAD),
- ecolor(ECOLOR_HILITE),
- ecolor(ECOLOR_BRACKET),
- ecolor(ECOLOR_NORMAL));
- exit(EXIT_SUCCESS);
- }
-
- if (argc > 0) {
- if (strcmp(applet, "eend") == 0 ||
- strcmp(applet, "ewend") == 0 ||
- strcmp(applet, "veend") == 0 ||
- strcmp(applet, "vweend") == 0 ||
- strcmp(applet, "ewaitfile") == 0)
- {
- errno = 0;
- retval = (int)strtoimax(argv[0], &p, 0);
- if (!p || *p != '\0')
- errno = EINVAL;
- if (errno)
- retval = EXIT_FAILURE;
- else {
- argc--;
- argv++;
- }
- } else if (strcmp(applet, "esyslog") == 0 ||
- strcmp(applet, "elog") == 0) {
- p = strchr(argv[0], '.');
- if (!p ||
- (level = syslog_decode(p + 1, prioritynames)) == -1)
- eerrorx("%s: invalid log level `%s'", applet, argv[0]);
-
- if (argc < 3)
- eerrorx("%s: not enough arguments", applet);
-
- unsetenv("EINFO_LOG");
- setenv("EINFO_LOG", argv[1], 1);
-
- argc -= 2;
- argv += 2;
- }
- }
-
- if (strcmp(applet, "ewaitfile") == 0) {
- if (errno)
- eerrorx("%s: invalid timeout", applet);
- if (argc == 0)
- eerrorx("%s: not enough arguments", applet);
-
- gettimeofday(&stop, NULL);
- /* retval stores the timeout */
- stop.tv_sec += retval;
- ts.tv_sec = 0;
- ts.tv_nsec = WAIT_INTERVAL;
- for (i = 0; i < argc; i++) {
- ebeginv("Waiting for %s", argv[i]);
- for (;;) {
- if (exists(argv[i]))
- break;
- if (nanosleep(&ts, NULL) == -1)
- return EXIT_FAILURE;
- gettimeofday(&now, NULL);
- if (retval <= 0)
- continue;
- if (timercmp(&now, &stop, <))
- continue;
- eendv(EXIT_FAILURE,
- "timed out waiting for %s", argv[i]);
- return EXIT_FAILURE;
- }
- eendv(EXIT_SUCCESS, NULL);
- }
- return EXIT_SUCCESS;
- }
-
- if (argc > 0) {
- for (i = 0; i < argc; i++)
- l += strlen(argv[i]) + 1;
-
- message = xmalloc(l);
- p = message;
-
- for (i = 0; i < argc; i++) {
- if (i > 0)
- *p++ = ' ';
- l = strlen(argv[i]);
- memcpy(p, argv[i], l);
- p += l;
- }
- *p = 0;
- }
-
- if (strcmp(applet, "einfo") == 0)
- e = einfo;
- else if (strcmp(applet, "einfon") == 0)
- e = einfon;
- else if (strcmp(applet, "ewarn") == 0)
- e = ewarn;
- else if (strcmp(applet, "ewarnn") == 0)
- e = ewarnn;
- else if (strcmp(applet, "eerror") == 0) {
- e = eerror;
- retval = 1;
- } else if (strcmp(applet, "eerrorn") == 0) {
- e = eerrorn;
- retval = 1;
- } else if (strcmp(applet, "ebegin") == 0)
- e = ebegin;
- else if (strcmp(applet, "eend") == 0)
- ee = eend;
- else if (strcmp(applet, "ewend") == 0)
- ee = ewend;
- else if (strcmp(applet, "esyslog") == 0) {
- elog(retval, "%s", message);
- retval = 0;
- } else if (strcmp(applet, "veinfo") == 0)
- e = einfov;
- else if (strcmp(applet, "veinfon") == 0)
- e = einfovn;
- else if (strcmp(applet, "vewarn") == 0)
- e = ewarnv;
- else if (strcmp(applet, "vewarnn") == 0)
- e = ewarnvn;
- else if (strcmp(applet, "vebegin") == 0)
- e = ebeginv;
- else if (strcmp(applet, "veend") == 0)
- ee = eendv;
- else if (strcmp(applet, "vewend") == 0)
- ee = ewendv;
- else if (strcmp(applet, "eindent") == 0)
- eindent();
- else if (strcmp(applet, "eoutdent") == 0)
- eoutdent();
- else if (strcmp(applet, "veindent") == 0)
- eindentv();
- else if (strcmp(applet, "veoutdent") == 0)
- eoutdentv();
- else {
- eerror("%s: unknown applet", applet);
- retval = EXIT_FAILURE;
- }
-
- if (message) {
- if (e)
- e("%s", message);
- else if (ee)
- ee(retval, "%s", message);
- } else {
- if (e)
- e(NULL);
- else if (ee)
- ee(retval, NULL);
- }
-
- free(message);
- return retval;
-}
diff --git a/src/rc/do_mark_service.c b/src/rc/do_mark_service.c
deleted file mode 100644
index d7b2658a..00000000
--- a/src/rc/do_mark_service.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-
-const char *applet = NULL;
-
-int main(int argc, char **argv)
-{
- bool ok = false;
- char *svcname = getenv("RC_SVCNAME");
- char *service = NULL;
- char *openrc_pid;
- /* char *mtime; */
- pid_t pid;
- RC_SERVICE bit;
- /* size_t l; */
-
- applet = basename_c(argv[0]);
- if (argc > 1)
- service = argv[1];
- else
- service = svcname;
-
- if (service == NULL || *service == '\0')
- eerrorx("%s: no service specified", applet);
-
- if (!strncmp(applet, "mark_", 5) &&
- (bit = lookup_service_state(applet + 5)))
- ok = rc_service_mark(service, bit);
- else
- eerrorx("%s: unknown applet", applet);
-
- /* If we're marking ourselves then we need to inform our parent
- openrc-run process so they do not mark us based on our exit code */
- /*
- * FIXME: svcname and service are almost always equal except called from a
- * shell with just argv[1] - So that doesn't seem to do what Roy initially
- * expected.
- * See 20120424041423.GA23657@odin.qasl.de (Tue, 24 Apr 2012 06:14:23 +0200,
- * openrc@gentoo.org).
- */
- if (ok && svcname && strcmp(svcname, service) == 0) {
- openrc_pid = getenv("RC_OPENRC_PID");
- if (openrc_pid && sscanf(openrc_pid, "%d", &pid) == 1)
- if (kill(pid, SIGHUP) != 0)
- eerror("%s: failed to signal parent %d: %s",
- applet, pid, strerror(errno));
-
- /* Remove the exclusive time test. This ensures that it's not
- in control as well */
- /*
- l = strlen(RC_SVCDIR "/exclusive") + strlen(svcname) +
- strlen(openrc_pid) + 4;
- mtime = xmalloc(l);
- snprintf(mtime, l, RC_SVCDIR "/exclusive/%s.%s",
- svcname, openrc_pid);
- if (exists(mtime) && unlink(mtime) != 0)
- eerror("%s: unlink: %s", applet, strerror(errno));
- free(mtime);
- */
- }
-
- return ok ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/src/rc/do_service.c b/src/rc/do_service.c
deleted file mode 100644
index eca498a6..00000000
--- a/src/rc/do_service.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-
-const char *applet = NULL;
-
-int main(int argc, char **argv)
-{
- bool ok = false;
- char *service;
- char *exec;
- int idx = 0;
- RC_SERVICE state, bit;
-
- applet = basename_c(argv[0]);
- if (argc > 1)
- service = argv[1];
- else
- service = getenv("RC_SVCNAME");
-
- if (service == NULL || *service == '\0')
- eerrorx("%s: no service specified", applet);
-
- state = rc_service_state(service);
- bit = lookup_service_state(applet);
- if (bit) {
- ok = (state & bit);
- } else if (strcmp(applet, "service_started_daemon") == 0) {
- service = getenv("RC_SVCNAME");
- exec = argv[1];
- if (argc > 3) {
- service = argv[1];
- exec = argv[2];
- sscanf(argv[3], "%d", &idx);
- } else if (argc == 3) {
- if (sscanf(argv[2], "%d", &idx) != 1) {
- service = argv[1];
- exec = argv[2];
- }
- }
- ok = rc_service_started_daemon(service, exec, NULL, idx);
-
- } else if (strcmp(applet, "service_crashed") == 0) {
- ok = ( rc_service_daemons_crashed(service) && errno != EACCES);
- } else
- eerrorx("%s: unknown applet", applet);
-
- return ok ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/src/rc/do_value.c b/src/rc/do_value.c
deleted file mode 100644
index 9ec5facf..00000000
--- a/src/rc/do_value.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2016 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#define SYSLOG_NAMES
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-
-const char *applet = NULL;
-
-int main(int argc, char **argv)
-{
- bool ok = false;
- char *service = getenv("RC_SVCNAME");
- char *option;
-
- applet = basename_c(argv[0]);
- if (service == NULL)
- eerrorx("%s: no service specified", applet);
-
- if (argc < 2 || !argv[1] || *argv[1] == '\0')
- eerrorx("%s: no option specified", applet);
-
- if (strcmp(applet, "service_get_value") == 0 ||
- strcmp(applet, "get_options") == 0)
- {
- option = rc_service_value_get(service, argv[1]);
- if (option) {
- printf("%s", option);
- free(option);
- ok = true;
- }
- } else if (strcmp(applet, "service_set_value") == 0 ||
- strcmp(applet, "save_options") == 0)
- ok = rc_service_value_set(service, argv[1], argv[2]);
- else
- eerrorx("%s: unknown applet", applet);
-
- return ok ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/src/rc/fstabinfo.c b/src/rc/fstabinfo.c
deleted file mode 100644
index 2a1a12ea..00000000
--- a/src/rc/fstabinfo.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * fstabinfo.c
- * Gets information about /etc/fstab.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-/* Yay for linux and its non liking of POSIX functions.
- Okay, we could use getfsent but the man page says use getmntent instead
- AND we don't have getfsent on uclibc or dietlibc for some odd reason. */
-#ifdef __linux__
-# define HAVE_GETMNTENT
-# include <mntent.h>
-# define ENT mntent
-# define START_ENT fp = setmntent ("/etc/fstab", "r");
-# define GET_ENT getmntent (fp)
-# define GET_ENT_FILE(_name) getmntfile (_name)
-# define END_ENT endmntent (fp)
-# define ENT_BLOCKDEVICE(_ent) (_ent)->mnt_fsname
-# define ENT_FILE(_ent) (_ent)->mnt_dir
-# define ENT_TYPE(_ent) (_ent)->mnt_type
-# define ENT_OPTS(_ent) (_ent)->mnt_opts
-# define ENT_PASS(_ent) (_ent)->mnt_passno
-#else
-# define HAVE_GETFSENT
-# include <fstab.h>
-# define ENT fstab
-# define START_ENT
-# define GET_ENT getfsent ()
-# define GET_ENT_FILE(_name) getfsfile (_name)
-# define END_ENT endfsent ()
-# define ENT_BLOCKDEVICE(_ent) (_ent)->fs_spec
-# define ENT_TYPE(_ent) (_ent)->fs_vfstype
-# define ENT_FILE(_ent) (_ent)->fs_file
-# define ENT_OPTS(_ent) (_ent)->fs_mntops
-# define ENT_PASS(_ent) (_ent)->fs_passno
-#endif
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "MRbmop:t:" getoptstring_COMMON;
-const struct option longopts[] = {
- { "mount", 0, NULL, 'M' },
- { "remount", 0, NULL, 'R' },
- { "blockdevice", 0, NULL, 'b' },
- { "mountargs", 0, NULL, 'm' },
- { "options", 0, NULL, 'o' },
- { "passno", 1, NULL, 'p' },
- { "fstype", 1, NULL, 't' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Mounts the filesytem from the mountpoint",
- "Remounts the filesystem based on the information in fstab",
- "Extract the block device",
- "Show arguments needed to mount the entry",
- "Extract the options field",
- "Extract or query the pass number field",
- "List entries with matching file system type",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-#ifdef HAVE_GETMNTENT
-static struct mntent *
-getmntfile(const char *file)
-{
- struct mntent *ent;
- FILE *fp;
-
- START_ENT;
- while ((ent = getmntent(fp)))
- if (strcmp(file, ent->mnt_dir) == 0)
- break;
- END_ENT;
-
- return ent;
-}
-#endif
-
-extern const char *applet;
-
-static int
-do_mount(struct ENT *ent, bool remount)
-{
- char *argv[10];
- pid_t pid;
- int status;
-
- argv[0] = UNCONST("mount");
- argv[1] = UNCONST("-o");
- argv[2] = ENT_OPTS(ent);
- argv[3] = UNCONST("-t");
- argv[4] = ENT_TYPE(ent);
- if (!remount) {
- argv[5] = ENT_BLOCKDEVICE(ent);
- argv[6] = ENT_FILE(ent);
- argv[7] = NULL;
- } else {
-#ifdef __linux__
- argv[5] = UNCONST("-o");
- argv[6] = UNCONST("remount");
- argv[7] = ENT_BLOCKDEVICE(ent);
- argv[8] = ENT_FILE(ent);
- argv[9] = NULL;
-#else
- argv[5] = UNCONST("-u");
- argv[6] = ENT_BLOCKDEVICE(ent);
- argv[7] = ENT_FILE(ent);
- argv[8] = NULL;
-#endif
- }
- switch (pid = vfork()) {
- case -1:
- eerrorx("%s: vfork: %s", applet, strerror(errno));
- /* NOTREACHED */
- case 0:
- execvp(argv[0], argv);
- eerror("%s: execvp: %s", applet, strerror(errno));
- _exit(EXIT_FAILURE);
- /* NOTREACHED */
- default:
- waitpid(pid, &status, 0);
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else
- return -1;
- /* NOTREACHED */
- }
-}
-
-#define OUTPUT_FILE (1 << 1)
-#define OUTPUT_MOUNTARGS (1 << 2)
-#define OUTPUT_OPTIONS (1 << 3)
-#define OUTPUT_PASSNO (1 << 4)
-#define OUTPUT_BLOCKDEV (1 << 5)
-#define OUTPUT_MOUNT (1 << 6)
-#define OUTPUT_REMOUNT (1 << 7)
-
-int main(int argc, char **argv)
-{
- struct ENT *ent;
- int result = EXIT_SUCCESS;
- char *token;
- int i, p;
- int opt;
- int output = OUTPUT_FILE;
- RC_STRINGLIST *files = rc_stringlist_new();
- RC_STRING *file, *file_np;
- bool filtered = false;
-
-#ifdef HAVE_GETMNTENT
- FILE *fp;
-#endif
-
- /* fail if there is no /etc/fstab */
- if (!exists("/etc/fstab"))
- eerrorx("/etc/fstab does not exist");
- /* Ensure that we are only quiet when explicitly told to be */
- unsetenv("EINFO_QUIET");
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'M':
- output = OUTPUT_MOUNT;
- break;
- case 'R':
- output = OUTPUT_REMOUNT;
- break;
- case 'b':
- output = OUTPUT_BLOCKDEV;
- break;
- case 'o':
- output = OUTPUT_OPTIONS;
- break;
- case 'm':
- output = OUTPUT_MOUNTARGS;
- break;
-
- case 'p':
- switch (optarg[0]) {
- case '=':
- case '<':
- case '>':
- if (sscanf(optarg + 1, "%d", &i) != 1)
- eerrorx("%s: invalid passno %s",
- argv[0], optarg + 1);
-
- filtered = true;
- opt = optarg[0];
- START_ENT;
- while ((ent = GET_ENT)) {
- if (strcmp(ENT_FILE(ent), "none") == 0)
- continue;
- p = ENT_PASS(ent);
- if ((opt == '=' && i == p) ||
- (opt == '<' && i > p && p != 0) ||
- (opt == '>' && i < p && p != 0))
- rc_stringlist_add(files,
- ENT_FILE(ent));
- }
- END_ENT;
- break;
-
- default:
- rc_stringlist_add(files, optarg);
- output = OUTPUT_PASSNO;
- break;
- }
- break;
-
- case 't':
- filtered = true;
- while ((token = strsep(&optarg, ","))) {
- START_ENT;
- while ((ent = GET_ENT))
- if (strcmp(token, ENT_TYPE(ent)) == 0)
- rc_stringlist_add(files,
- ENT_FILE(ent));
- END_ENT;
- }
- break;
-
- case_RC_COMMON_GETOPT
- }
- }
-
- if (optind < argc) {
- if (TAILQ_FIRST(files)) {
- TAILQ_FOREACH_SAFE(file, files, entries, file_np) {
- for (i = optind; i < argc; i++)
- if (strcmp(argv[i], file->value) == 0)
- break;
- if (i >= argc)
- rc_stringlist_delete(files,
- file->value);
- }
- } else {
- while (optind < argc)
- rc_stringlist_add(files, argv[optind++]);
- }
- } else if (!filtered) {
- START_ENT;
- while ((ent = GET_ENT))
- rc_stringlist_add(files, ENT_FILE(ent));
- END_ENT;
-
- if (!TAILQ_FIRST(files))
- eerrorx("%s: empty fstab", argv[0]);
- }
-
- if (!TAILQ_FIRST(files)) {
- rc_stringlist_free(files);
- return (EXIT_FAILURE);
- }
-
- /* Ensure we always display something */
- START_ENT;
- TAILQ_FOREACH(file, files, entries) {
- if (!(ent = GET_ENT_FILE(file->value))) {
- result = EXIT_FAILURE;
- continue;
- }
-
- /* mount or remount? */
- switch (output) {
- case OUTPUT_MOUNT:
- result += do_mount(ent, false);
- break;
-
- case OUTPUT_REMOUNT:
- result += do_mount(ent, true);
- break;
- }
-
- /* No point in outputting if quiet */
- if (rc_yesno(getenv("EINFO_QUIET")))
- continue;
-
- switch (output) {
- case OUTPUT_BLOCKDEV:
- printf("%s\n", ENT_BLOCKDEVICE(ent));
- break;
-
- case OUTPUT_MOUNTARGS:
- printf("-o %s -t %s %s %s\n",
- ENT_OPTS(ent),
- ENT_TYPE(ent),
- ENT_BLOCKDEVICE(ent),
- file->value);
- break;
-
- case OUTPUT_OPTIONS:
- printf("%s\n", ENT_OPTS(ent));
- break;
-
- case OUTPUT_FILE:
- printf("%s\n", file->value);
- break;
-
- case OUTPUT_PASSNO:
- printf("%d\n", ENT_PASS(ent));
- break;
- }
- }
- END_ENT;
-
- rc_stringlist_free(files);
- exit(result);
- /* NOTREACHED */
-}
diff --git a/src/rc/is_newer_than.c b/src/rc/is_newer_than.c
deleted file mode 100644
index 957ecbf4..00000000
--- a/src/rc/is_newer_than.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2016 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "rc.h"
-#include "rc-misc.h"
-
-int main(int argc, char **argv)
-{
- int i;
-
- if (argc < 3)
- return EXIT_FAILURE;
-
- /* This test is correct as it's not present in baselayout */
- for (i = 2; i < argc; ++i)
- if (!rc_newer_than(argv[1], argv[i], NULL, NULL))
- return EXIT_FAILURE;
-
- return EXIT_SUCCESS;
-}
diff --git a/src/rc/is_older_than.c b/src/rc/is_older_than.c
deleted file mode 100644
index c9e25f30..00000000
--- a/src/rc/is_older_than.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2016 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "rc.h"
-#include "rc-misc.h"
-
-int main(int argc, char **argv)
-{
- int i;
-
- if (argc < 3)
- return EXIT_FAILURE;
-
- /* This test is perverted - historically the baselayout function
- * returns 0 on *failure*, which is plain wrong */
- for (i = 2; i < argc; ++i)
- if (!rc_newer_than(argv[1], argv[i], NULL, NULL))
- return EXIT_SUCCESS;
-
- return EXIT_FAILURE;
-}
diff --git a/src/rc/kill_all.c b/src/rc/kill_all.c
deleted file mode 100644
index 551572b7..00000000
--- a/src/rc/kill_all.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * kill_all.c
- * Sends a signal to all processes on the system.
- */
-
-/*
- * Copyright (c) 2017 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-
-#include <dirent.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = "[signal number]";
-const char getoptstring[] = "do:" getoptstring_COMMON;
-const struct option longopts[] = {
- { "dry-run", 0, NULL, 'd' },
- { "omit", 1, NULL, 'o' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "print what would be done",
- "omit this pid (can be repeated)",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static int mount_proc(void)
-{
- pid_t pid;
- pid_t rc;
- int status;
-
- if (exists("/proc/version"))
- return 0;
- pid = fork();
- switch (pid) {
- case -1:
- syslog(LOG_ERR, "Unable to fork");
- return -1;
- break;
- case 0:
- /* attempt to mount /proc */
- execlp("mount", "mount", "-t", "proc", "proc", "/proc", NULL);
- syslog(LOG_ERR, "Unable to execute mount");
- exit(1);
- break;
- default:
- /* wait for child process */
- while ((rc = wait(&status)) != pid)
- if (rc < 0 && errno == ECHILD)
- break;
- if (rc != pid || WEXITSTATUS(status) != 0)
- syslog(LOG_ERR, "mount returned non-zero exit status");
- break;
- }
- if (!exists("/proc/version")) {
- syslog(LOG_ERR, "Could not mount /proc");
- return -1;
- }
- return 0;
-}
-
-static bool is_user_process(pid_t pid)
-{
- char *buf = NULL;
- FILE *fp;
- char *path = NULL;
- pid_t temp_pid;
- size_t size;
- bool user_process = true;
-
- while (pid >0 && user_process) {
- if (pid == 2) {
- user_process = false;
- continue;
- }
- xasprintf(&path, "/proc/%d/status", pid);
- fp = fopen(path, "r");
- free(path);
- /*
- * if we could not open the file, the process disappeared, which
- * leaves us no way to determine for sure whether it was a user
- * process or kernel thread, so we say it is a kernel thread to
- * avoid accidentally killing it.
- */
- if (!fp) {
- user_process = false;
- continue;
- }
- temp_pid = -1;
- while (!feof(fp)) {
- buf = NULL;
- if (getline(&buf, &size, fp) != -1) {
- sscanf(buf, "PPid: %d", &temp_pid);
- free(buf);
- } else {
- free(buf);
- break;
- }
- }
- fclose(fp);
- if (temp_pid == -1) {
- syslog(LOG_ERR, "Unable to read pid from /proc/%d/status", pid);
- user_process = false;
- continue;
- }
- pid = temp_pid;
- }
- return user_process;
-}
-
-static int signal_processes(int sig, RC_STRINGLIST *omits, bool dryrun)
-{
- sigset_t signals;
- sigset_t oldsigs;
- DIR *dir;
- struct dirent *d;
- char *buf = NULL;
- pid_t pid;
- int sendcount = 0;
-
- kill(-1, SIGSTOP);
- sigfillset(&signals);
- sigemptyset(&oldsigs);
- sigprocmask(SIG_SETMASK, &signals, &oldsigs);
- /*
- * Open the /proc directory.
- * CWD must be /proc to avoid problems if / is affected by the killing
- * (i.e. depends on fuse).
- */
- if (chdir("/proc") == -1) {
- syslog(LOG_ERR, "chdir /proc failed");
- sigprocmask(SIG_SETMASK, &oldsigs, NULL);
- kill(-1, SIGCONT);
- return -1;
- }
- dir = opendir(".");
- if (!dir) {
- syslog(LOG_ERR, "cannot opendir(/proc)");
- sigprocmask(SIG_SETMASK, &oldsigs, NULL);
- kill(-1, SIGCONT);
- return -1;
- }
-
- /* Walk through the directory. */
- while ((d = readdir(dir)) != NULL) {
- /* Is this a process? */
- pid = (pid_t) atoi(d->d_name);
- if (pid == 0)
- continue;
-
- /* Is this a process we have been requested to omit? */
- if (buf) {
- free(buf);
- buf = NULL;
- }
- xasprintf(&buf, "%d", pid);
- if (rc_stringlist_find(omits, buf))
- continue;
-
- /* Is this process in our session? */
- if (getsid(getpid()) == getsid(pid))
- continue;
-
- /* Is this a kernel thread? */
- if (!is_user_process(pid))
- continue;
-
- if (dryrun)
- einfo("Would send signal %d to process %d", sig, pid);
- else if (kill(pid, sig) == 0)
- sendcount++;
- }
- closedir(dir);
- sigprocmask(SIG_SETMASK, &oldsigs, NULL);
- kill(-1, SIGCONT);
- return sendcount;
-}
-
-int main(int argc, char **argv)
-{
- char *arg = NULL;
- int opt;
- bool dryrun = false;
- RC_STRINGLIST *omits = rc_stringlist_new();
- int sig = SIGKILL;
- char *here;
- char *token;
-
- /* Ensure that we are only quiet when explicitly told to be */
- unsetenv("EINFO_QUIET");
-
- applet = basename_c(argv[0]);
- rc_stringlist_addu(omits, "1");
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'd':
- dryrun = true;
- break;
- case 'o':
- here = optarg;
- while ((token = strsep(&here, ",;:"))) {
- if ((pid_t) atoi(token) > 0)
- rc_stringlist_addu(omits, token);
- else {
- eerror("Invalid omit pid value %s", token);
- usage(EXIT_FAILURE);
- }
- }
- break;
- case_RC_COMMON_GETOPT
- }
- }
-
- if (argc > optind) {
- arg = argv[optind];
- sig = atoi(arg);
- if (sig <= 0 || sig > 31) {
- rc_stringlist_free(omits);
- eerror("Invalid signal %s", arg);
- usage(EXIT_FAILURE);
- }
- }
-
- openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON);
- if (mount_proc() != 0) {
- rc_stringlist_free(omits);
- eerrorx("Unable to mount /proc file system");
- }
- signal_processes(sig, omits, dryrun);
- rc_stringlist_free(omits);
- return 0;
-}
diff --git a/src/rc/meson.build b/src/rc/meson.build
deleted file mode 100644
index edea4a16..00000000
--- a/src/rc/meson.build
+++ /dev/null
@@ -1,320 +0,0 @@
-rc_misc_c = files([
- 'rc-misc.c',
- ])
-
-rc_plugin_c = files([
- 'rc-plugin.c',
- ])
-
-rc_schedules_c = files([
- 'rc-schedules.c',
- ])
-
-usage_c = files([
- '_usage.c',
- ])
-
-if selinux_dep.found()
- rc_selinux_c = files([
- 'rc-selinux.c',
- ])
-else
- rc_selinux_c = []
-endif
-
-rc_wtmp_c = files([
- 'rc-wtmp.c',
- ])
-
-executable('rc-status',
- ['rc-status.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- link_with: [libeinfo, librc],
- dependencies: [util_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: bindir)
-
-executable('openrc',
- ['rc.c', 'rc-logger.c', rc_misc_c, rc_plugin_c, usage_c,
- version_h],
- c_args : cc_branding_flags,
- link_with: [libeinfo, librc],
- dependencies: [dl_dep, util_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('openrc-run',
- ['openrc-run.c', rc_misc_c, rc_plugin_c, usage_c,
- rc_selinux_c, version_h],
- c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_selinux_flags],
- link_with: [libeinfo, librc],
- dependencies: [audit_dep, dl_dep, pam_dep, pam_misc_dep, selinux_dep, util_dep, crypt_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('rc',
- ['rc.c', 'rc-logger.c', rc_misc_c, rc_plugin_c, usage_c, version_h],
- c_args : cc_branding_flags,
- link_with: [libeinfo, librc],
- dependencies: [dl_dep, util_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('rc-service',
- ['rc-service.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- link_with: [libeinfo, librc],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('rc-update',
- ['rc-update.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- link_with: [libeinfo, librc],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('runscript',
- ['openrc-run.c', rc_misc_c, usage_c, 'rc-plugin.c',
- rc_selinux_c, version_h],
- c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_selinux_flags],
- link_with: [libeinfo, librc],
- dependencies: [audit_dep, dl_dep, pam_dep, pam_misc_dep, util_dep, selinux_dep, crypt_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-executable('start-stop-daemon',
- ['start-stop-daemon.c', 'rc-pipes.c', rc_misc_c, rc_schedules_c,
- rc_selinux_c, usage_c, version_h],
- c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_cap_flags, cc_selinux_flags],
- link_with: [libeinfo, librc],
- dependencies: [audit_dep, dl_dep, pam_dep, cap_dep, pam_misc_dep, util_dep, selinux_dep, crypt_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-if get_option('pam')
- install_data('start-stop-daemon.pam',
- rename : 'start-stop-daemon',
- install_dir : pamdir)
-endif
-
-executable('supervise-daemon',
- ['supervise-daemon.c', rc_misc_c, rc_plugin_c, rc_schedules_c,
- usage_c, version_h],
- c_args : [cc_branding_flags, cc_pam_flags, cc_cap_flags, cc_selinux_flags],
- link_with: [libeinfo, librc],
- dependencies: [dl_dep, pam_dep, cap_dep, util_dep, selinux_dep],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- install: true,
- install_dir: sbindir)
-
-if get_option('pam')
- install_data('supervise-daemon.pam',
- rename : 'supervise-daemon',
- install_dir : pamdir)
-endif
-
-if os == 'Linux'
- executable('openrc-init',
- ['openrc-init.c', rc_plugin_c, rc_wtmp_c, version_h],
- c_args : cc_selinux_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- dependencies: [dl_dep, selinux_dep],
- install: true,
- install_dir: sbindir)
-
- executable('openrc-shutdown',
- ['openrc-shutdown.c', 'broadcast.c', 'rc-sysvinit.c', rc_misc_c,
- usage_c, rc_wtmp_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: sbindir)
-endif
-
-einfo_execs = [
- 'einfon',
- 'einfo',
- 'ewarnn',
- 'ewarn',
- 'eerrorn',
- 'eerror',
- 'ebegin',
- 'eend',
- 'ewend',
- 'eindent',
- 'eoutdent',
- 'esyslog',
- 'eval_ecolors',
- 'ewaitfile',
- 'veinfo',
- 'vewarn',
- 'vebegin',
- 'veend',
- 'vewend',
- 'veindent',
- 'veoutdent',
- ]
-
-foreach exec: einfo_execs
- executable(exec,
- ['do_e.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-endforeach
-
-executable('checkpath',
- ['checkpath.c', rc_misc_c, usage_c, rc_selinux_c,
- version_h],
- c_args : [cc_audit_flags, cc_branding_flags, cc_pam_flags, cc_selinux_flags],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- dependencies: [audit_dep, pam_dep, pam_misc_dep, selinux_dep, crypt_dep],
- install: true,
- install_dir: rc_bindir)
-
-executable('fstabinfo',
- ['fstabinfo.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-
-executable('mountinfo',
- ['mountinfo.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-
-executable('rc-depend',
- ['rc-depend.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-
-executable('is_newer_than',
- ['is_newer_than.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-
-executable('is_older_than',
- ['is_older_than.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-
-service_execs = [
- 'service_starting',
- 'service_started',
- 'service_stopping',
- 'service_stopped',
- 'service_inactive',
- 'service_wasinactive',
- 'service_hotplugged',
- 'service_started_daemon',
- 'service_crashed',
- ]
-
-foreach exec : service_execs
- executable(exec,
- ['do_service.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-endforeach
-
-value_execs = [
- 'service_get_value',
- 'service_set_value',
- 'get_options',
- 'save_options',
- ]
-
-foreach exec : value_execs
- executable(exec,
- ['do_value.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_bindir)
-endforeach
-
-if os == 'Linux'
- executable('kill_all',
- ['kill_all.c', usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo,librc],
- install: true,
- install_dir: rc_bindir)
-
- executable('seedrng',
- ['seedrng.c', usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo, librc],
- install: true,
- install_dir: rc_sbindir)
-endif
-
-executable('shell_var',
- ['shell_var.c'],
- install: true,
- install_dir: rc_bindir)
-
-mark_service_execs = [
- 'mark_service_starting',
- 'mark_service_started',
- 'mark_service_stopping',
- 'mark_service_stopped',
- 'mark_service_inactive',
- 'mark_service_wasinactive',
- 'mark_service_hotplugged',
- 'mark_service_failed',
- 'mark_service_crashed',
- ]
-
-foreach exec : mark_service_execs
- executable(exec,
- ['do_mark_service.c', rc_misc_c, version_h],
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo,librc],
- install: true,
- install_dir: rc_sbindir)
-endforeach
-
-executable('rc-abort',
- 'rc-abort.c',
- include_directories: [einfo_incdir],
- link_with: [libeinfo],
- install: true,
- install_dir: rc_sbindir)
-
-executable('swclock',
- ['swclock.c', rc_misc_c, usage_c, version_h],
- c_args : cc_branding_flags,
- include_directories: [incdir, einfo_incdir, rc_incdir],
- link_with: [libeinfo,librc],
- install: true,
- install_dir: rc_sbindir)
diff --git a/src/rc/mountinfo.c b/src/rc/mountinfo.c
deleted file mode 100644
index 6652760d..00000000
--- a/src/rc/mountinfo.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * mountinfo.c
- * Obtains information about mounted filesystems.
- */
-
-/*
- * Copyright 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-
-#if defined(__DragonFly__) || defined(__FreeBSD__)
-# include <sys/ucred.h>
-# include <sys/mount.h>
-# define F_FLAGS f_flags
-#elif defined(BSD) && !defined(__GNU__)
-# include <sys/statvfs.h>
-# define statfs statvfs
-# define F_FLAGS f_flag
-#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \
- defined(__GLIBC__)) || defined(__GNU__)
-# include <mntent.h>
-#endif
-
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *procmounts = "/proc/mounts";
-const char *extraopts = "[mount1] [mount2] ...";
-const char getoptstring[] = "f:F:n:N:o:O:p:P:iste:E:" getoptstring_COMMON;
-const struct option longopts[] = {
- { "fstype-regex", 1, NULL, 'f'},
- { "skip-fstype-regex", 1, NULL, 'F'},
- { "node-regex", 1, NULL, 'n'},
- { "skip-node-regex", 1, NULL, 'N'},
- { "options-regex", 1, NULL, 'o'},
- { "skip-options-regex", 1, NULL, 'O'},
- { "point-regex", 1, NULL, 'p'},
- { "skip-point-regex", 1, NULL, 'P'},
- { "options", 0, NULL, 'i'},
- { "fstype", 0, NULL, 's'},
- { "node", 0, NULL, 't'},
- { "netdev", 0, NULL, 'e'},
- { "nonetdev", 0, NULL, 'E'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "fstype regex to find",
- "fstype regex to skip",
- "node regex to find",
- "node regex to skip",
- "options regex to find",
- "options regex to skip",
- "point regex to find",
- "point regex to skip",
- "print options",
- "print fstype",
- "print node",
- "is it a network device",
- "is it not a network device",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-typedef enum {
- mount_from,
- mount_to,
- mount_fstype,
- mount_options
-} mount_type;
-
-typedef enum {
- net_ignore,
- net_yes,
- net_no
-} net_opts;
-
-struct args {
- regex_t *node_regex;
- regex_t *skip_node_regex;
- regex_t *fstype_regex;
- regex_t *skip_fstype_regex;
- regex_t *options_regex;
- regex_t *skip_options_regex;
- RC_STRINGLIST *mounts;
- mount_type mount_type;
- net_opts netdev;
-};
-
-static int
-process_mount(RC_STRINGLIST *list, struct args *args,
- char *from, char *to, char *fstype, char *options,
- int netdev)
-{
- char *p;
- RC_STRING *s;
-
- errno = ENOENT;
-
-#ifdef __linux__
- /* Skip the really silly rootfs */
- if (strcmp(fstype, "rootfs") == 0)
- return -1;
-#endif
-
- if (args->netdev == net_yes &&
- (netdev != -1 || TAILQ_FIRST(args->mounts)))
- {
- if (netdev != 0)
- return 1;
- } else if (args->netdev == net_no &&
- (netdev != -1 || TAILQ_FIRST(args->mounts)))
- {
- if (netdev != 1)
- return 1;
- } else {
- if (args->node_regex &&
- regexec(args->node_regex, from, 0, NULL, 0) != 0)
- return 1;
- if (args->skip_node_regex &&
- regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
- return 1;
-
- if (args->fstype_regex &&
- regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
- return -1;
- if (args->skip_fstype_regex &&
- regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
- return -1;
-
- if (args->options_regex &&
- regexec(args->options_regex, options, 0, NULL, 0) != 0)
- return -1;
- if (args->skip_options_regex &&
- regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
- return -1;
- }
-
- if (TAILQ_FIRST(args->mounts)) {
- TAILQ_FOREACH(s, args->mounts, entries)
- if (strcmp(s->value, to) == 0)
- break;
- if (!s)
- return -1;
- }
-
- switch (args->mount_type) {
- case mount_from:
- p = from;
- break;
- case mount_to:
- p = to;
- break;
- case mount_fstype:
- p = fstype;
- break;
- case mount_options:
- p = options;
- break;
- default:
- p = NULL;
- errno = EINVAL;
- break;
- }
-
- if (p) {
- errno = 0;
- rc_stringlist_add(list, p);
- return 0;
- }
-
- return -1;
-}
-
-#if defined(BSD) && !defined(__GNU__)
-
-/* Translate the mounted options to english
- * This is taken directly from FreeBSD mount.c */
-static struct opt {
- int o_opt;
- const char *o_name;
-} optnames[] = {
- { MNT_ASYNC, "asynchronous" },
- { MNT_EXPORTED, "NFS exported" },
- { MNT_LOCAL, "local" },
- { MNT_NOATIME, "noatime" },
- { MNT_NOEXEC, "noexec" },
- { MNT_NOSUID, "nosuid" },
-#ifdef MNT_NOSYMFOLLOW
- { MNT_NOSYMFOLLOW, "nosymfollow" },
-#endif
- { MNT_QUOTA, "with quotas" },
- { MNT_RDONLY, "read-only" },
- { MNT_SYNCHRONOUS, "synchronous" },
- { MNT_UNION, "union" },
-#ifdef MNT_NOCLUSTERR
- { MNT_NOCLUSTERR, "noclusterr" },
-#endif
-#ifdef MNT_NOCLUSTERW
- { MNT_NOCLUSTERW, "noclusterw" },
-#endif
-#ifdef MNT_SUIDDIR
- { MNT_SUIDDIR, "suiddir" },
-#endif
- { MNT_SOFTDEP, "soft-updates" },
-#ifdef MNT_MULTILABEL
- { MNT_MULTILABEL, "multilabel" },
-#endif
-#ifdef MNT_ACLS
- { MNT_ACLS, "acls" },
-#endif
-#ifdef MNT_GJOURNAL
- { MNT_GJOURNAL, "gjournal" },
-#endif
- { 0, NULL }
-};
-
-static RC_STRINGLIST *
-find_mounts(struct args *args)
-{
- struct statfs *mnts;
- int nmnts;
- int i;
- RC_STRINGLIST *list;
- char *options = NULL;
- uint64_t flags;
- struct opt *o;
- int netdev;
- char *tmp;
-
- if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
- eerrorx("getmntinfo: %s", strerror (errno));
-
- list = rc_stringlist_new();
- for (i = 0; i < nmnts; i++) {
- netdev = 0;
- flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK;
- for (o = optnames; flags && o->o_opt; o++) {
- if (flags & o->o_opt) {
- if (o->o_opt == MNT_LOCAL)
- netdev = 1;
- if (!options)
- options = xstrdup(o->o_name);
- else {
- xasprintf(&tmp, "%s,%s", options, o->o_name);
- free(options);
- options = tmp;
- }
- }
- flags &= ~o->o_opt;
- }
-
- process_mount(list, args,
- mnts[i].f_mntfromname,
- mnts[i].f_mntonname,
- mnts[i].f_fstypename,
- options,
- netdev);
-
- free(options);
- options = NULL;
- }
-
- return list;
-}
-
-#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \
- defined(__GLIBC__)) || defined(__GNU__)
-static struct mntent *
-getmntfile(const char *file)
-{
- struct mntent *ent = NULL;
- FILE *fp;
-
- if (!exists("/etc/fstab"))
- return NULL;
-
- fp = setmntent("/etc/fstab", "r");
- while ((ent = getmntent(fp)))
- if (strcmp(file, ent->mnt_dir) == 0)
- break;
- endmntent(fp);
-
- return ent;
-}
-
-static RC_STRINGLIST *
-find_mounts(struct args *args)
-{
- FILE *fp;
- char *buffer;
- size_t size;
- char *p;
- char *from;
- char *to;
- char *fst;
- char *opts;
- struct mntent *ent;
- int netdev;
- RC_STRINGLIST *list;
-
- if ((fp = fopen(procmounts, "r")) == NULL)
- eerrorx("getmntinfo: %s", strerror(errno));
-
- list = rc_stringlist_new();
-
- buffer = NULL;
- while (getline(&buffer, &size, fp) != -1) {
- netdev = -1;
- p = buffer;
- from = strsep(&p, " ");
- to = strsep(&p, " ");
- fst = strsep(&p, " ");
- opts = strsep(&p, " ");
-
- if ((ent = getmntfile(to))) {
- if (strstr(ent->mnt_opts, "_netdev"))
- netdev = 0;
- else
- netdev = 1;
- }
-
- process_mount(list, args, from, to, fst, opts, netdev);
- free(buffer);
- buffer = NULL;
- }
- free(buffer);
- fclose(fp);
-
- return list;
-}
-
-#else
-# error "Operating system not supported!"
-#endif
-
-static regex_t *
-get_regex(const char *string)
-{
- regex_t *reg = xmalloc(sizeof (*reg));
- int result;
- char buffer[256];
-
- if ((result = regcomp(reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
- {
- regerror(result, reg, buffer, sizeof(buffer));
- eerrorx("%s: invalid regex `%s'", applet, buffer);
- }
-
- return reg;
-}
-
-int main(int argc, char **argv)
-{
- struct args args;
- regex_t *point_regex = NULL;
- regex_t *skip_point_regex = NULL;
- RC_STRINGLIST *nodes;
- RC_STRING *s;
- char *real_path = NULL;
- int opt;
- int result;
- char *this_path;
-
-#define DO_REG(_var) \
- if (_var) free(_var); \
- _var = get_regex(optarg);
-#define REG_FREE(_var) \
- if (_var) { regfree(_var); free(_var); }
-
- applet = basename_c(argv[0]);
- memset (&args, 0, sizeof(args));
- args.mount_type = mount_to;
- args.netdev = net_ignore;
- args.mounts = rc_stringlist_new();
-
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'e':
- args.netdev = net_yes;
- break;
- case 'E':
- args.netdev = net_no;
- break;
- case 'f':
- DO_REG(args.fstype_regex);
- break;
- case 'F':
- DO_REG(args.skip_fstype_regex);
- break;
- case 'n':
- DO_REG(args.node_regex);
- break;
- case 'N':
- DO_REG(args.skip_node_regex);
- break;
- case 'o':
- DO_REG(args.options_regex);
- break;
- case 'O':
- DO_REG(args.skip_options_regex);
- break;
- case 'p':
- DO_REG(point_regex);
- break;
- case 'P':
- DO_REG(skip_point_regex);
- break;
- case 'i':
- args.mount_type = mount_options;
- break;
- case 's':
- args.mount_type = mount_fstype;
- break;
- case 't':
- args.mount_type = mount_from;
- break;
-
- case_RC_COMMON_GETOPT
- }
- }
-
- while (optind < argc) {
- if (argv[optind][0] != '/')
- eerrorx("%s: `%s' is not a mount point",
- argv[0], argv[optind]);
- this_path = argv[optind++];
- real_path = realpath(this_path, NULL);
- if (real_path)
- this_path = real_path;
- rc_stringlist_add(args.mounts, this_path);
- free(real_path);
- real_path = NULL;
- }
- nodes = find_mounts(&args);
- rc_stringlist_free(args.mounts);
-
- REG_FREE(args.fstype_regex);
- REG_FREE(args.skip_fstype_regex);
- REG_FREE(args.node_regex);
- REG_FREE(args.skip_node_regex);
- REG_FREE(args.options_regex);
- REG_FREE(args.skip_options_regex);
-
- result = EXIT_FAILURE;
-
- /* We should report the mounts in reverse order to ease unmounting */
- TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) {
- if (point_regex &&
- regexec(point_regex, s->value, 0, NULL, 0) != 0)
- continue;
- if (skip_point_regex &&
- regexec(skip_point_regex, s->value, 0, NULL, 0) == 0)
- continue;
- if (!rc_yesno(getenv("EINFO_QUIET")))
- printf("%s\n", s->value);
- result = EXIT_SUCCESS;
- }
- rc_stringlist_free(nodes);
-
- REG_FREE(point_regex);
- REG_FREE(skip_point_regex);
-
- return result;
-}
diff --git a/src/rc/openrc-init.c b/src/rc/openrc-init.c
deleted file mode 100644
index 5bc53434..00000000
--- a/src/rc/openrc-init.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * openrc-init.c
- * This is the init process (pid 1) for OpenRC.
- *
- * This is based on code written by James Hammons <jlhamm@acm.org>, so
- * I would like to publically thank him for his work.
- */
-
-/*
- * Copyright (c) 2017 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/reboot.h>
-#include <sys/wait.h>
-
-#ifdef HAVE_SELINUX
-# include <selinux/selinux.h>
-#endif
-
-#include "helpers.h"
-#include "rc.h"
-#include "rc-plugin.h"
-#include "rc-wtmp.h"
-#include "version.h"
-
-static const char *path_default = "/sbin:/usr/sbin:/bin:/usr/bin";
-static const char *rc_default_runlevel = "default";
-
-static void do_openrc(const char *runlevel)
-{
- pid_t pid;
- sigset_t all_signals;
- sigset_t our_signals;
-
- sigfillset(&all_signals);
- /* block all signals */
- sigprocmask(SIG_BLOCK, &all_signals, &our_signals);
- pid = fork();
- switch (pid) {
- case -1:
- perror("fork");
- exit(1);
- break;
- case 0:
- setsid();
- /* unblock all signals */
- sigprocmask(SIG_UNBLOCK, &all_signals, NULL);
- printf("Starting %s runlevel\n", runlevel);
- execlp("openrc", "openrc", runlevel, NULL);
- perror("exec");
- exit(1);
- break;
- default:
- /* restore our signal mask */
- sigprocmask(SIG_SETMASK, &our_signals, NULL);
- while (waitpid(pid, NULL, 0) != pid)
- if (errno == ECHILD)
- break;
- break;
- }
-}
-
-static void init(const char *default_runlevel)
-{
- const char *runlevel = NULL;
- do_openrc("sysinit");
- do_openrc("boot");
- if (default_runlevel)
- runlevel = default_runlevel;
- else
- runlevel = rc_conf_value("rc_default_runlevel");
- if (!runlevel)
- runlevel = rc_default_runlevel;
- if (!rc_runlevel_exists(runlevel)) {
- printf("%s is an invalid runlevel\n", runlevel);
- runlevel = rc_default_runlevel;
- }
- do_openrc(runlevel);
- log_wtmp("reboot", "~~", 0, RUN_LVL, "~~");
-}
-
-static void handle_reexec(char *my_name)
-{
- execlp(my_name, my_name, "reexec", NULL);
- return;
-}
-
-static void handle_shutdown(const char *runlevel, int cmd)
-{
- struct timespec ts;
-
- do_openrc(runlevel);
- printf("Sending the final term signal\n");
- kill(-1, SIGTERM);
- ts.tv_sec = 3;
- ts.tv_nsec = 0;
- nanosleep(&ts, NULL);
- printf("Sending the final kill signal\n");
- kill(-1, SIGKILL);
- sync();
- reboot(cmd);
-}
-
-static void run_program(const char *prog)
-{
- sigset_t full;
- sigset_t old;
- pid_t pid;
-
- /* We need to block signals until we have forked */
- sigfillset(&full);
- sigprocmask(SIG_SETMASK, &full, &old);
- pid = fork();
- if (pid == -1) {
- perror("init");
- return;
- }
- if (pid == 0) {
- /* Unmask signals */
- sigprocmask(SIG_SETMASK, &old, NULL);
- execl(prog, prog, (char *)NULL);
- perror("init");
- exit(1);
- }
- /* Unmask signals and wait for child */
- sigprocmask(SIG_SETMASK, &old, NULL);
- if (rc_waitpid(pid) == -1)
- perror("init");
-}
-
-static void open_shell(void)
-{
- const char *shell;
- struct passwd *pw;
-
-#ifdef __linux__
- const char *sys = rc_sys();
-
- /* VSERVER systems cannot really drop to shells */
- if (sys && strcmp(sys, RC_SYS_VSERVER) == 0)
- {
- execlp("halt", "halt", "-f", (char *) NULL);
- perror("init");
- return;
- }
-#endif
-
- shell = rc_conf_value("rc_shell");
- /* No shell set, so obey env, then passwd, then default to /bin/sh */
- if (!shell) {
- shell = getenv("SHELL");
- if (!shell) {
- pw = getpwuid(getuid());
- if (pw)
- shell = pw->pw_shell;
- if (!shell)
- shell = "/bin/sh";
- }
- }
- run_program(shell);
-}
-
-static void handle_single(void)
-{
- do_openrc("single");
-}
-
-static void reap_zombies(void)
-{
- pid_t pid;
-
- for (;;) {
- pid = waitpid(-1, NULL, WNOHANG);
- if (pid == 0)
- break;
- else if (pid == -1) {
- if (errno == ECHILD)
- break;
- perror("waitpid");
- continue;
- }
- }
-}
-
-static void signal_handler(int sig)
-{
- switch (sig) {
- case SIGINT:
- handle_shutdown("reboot", RB_AUTOBOOT);
- break;
- case SIGTERM:
-#ifdef SIGPWR
- case SIGPWR:
-#endif
- handle_shutdown("shutdown", RB_HALT_SYSTEM);
- break;
- case SIGCHLD:
- reap_zombies();
- break;
- default:
- printf("Unknown signal received, %d\n", sig);
- break;
- }
-}
-
-int main(int argc, char **argv)
-{
- char *default_runlevel;
- char buf[2048];
- int count;
- FILE *fifo;
- bool reexec = false;
- sigset_t signals;
- struct sigaction sa;
-#ifdef HAVE_SELINUX
- int enforce = 0;
-#endif
-
- if (getpid() != 1)
- return 1;
-
-#ifdef HAVE_SELINUX
- if (getenv("SELINUX_INIT") == NULL) {
- if (is_selinux_enabled() != 1) {
- if (selinux_init_load_policy(&enforce) == 0) {
- putenv("SELINUX_INIT=YES");
- execv(argv[0], argv);
- } else {
- if (enforce > 0) {
- /*
- * SELinux in enforcing mode but load_policy failed
- * At this point, we probably can't open /dev/console,
- * so log() won't work
- */
- fprintf(stderr,"Unable to load SELinux Policy.\n");
- fprintf(stderr,"Machine is in enforcing mode.\n");
- fprintf(stderr,"Halting now.\n");
- exit(1);
- }
- }
- }
- }
-#endif
-
- printf("OpenRC init version %s starting\n", VERSION);
-
- if (argc > 1)
- default_runlevel = argv[1];
- else
- default_runlevel = NULL;
-
- if (default_runlevel && strcmp(default_runlevel, "reexec") == 0)
- reexec = true;
-
- /* block all signals we do not handle */
- sigfillset(&signals);
- sigdelset(&signals, SIGCHLD);
- sigdelset(&signals, SIGINT);
- sigdelset(&signals, SIGTERM);
-#ifdef SIGPWR
- sigdelset(&signals, SIGPWR);
-#endif
- sigprocmask(SIG_SETMASK, &signals, NULL);
-
- /* install signal handler */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = signal_handler;
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
-#ifdef SIGPWR
- sigaction(SIGPWR, &sa, NULL);
-#endif
- reboot(RB_DISABLE_CAD);
-
- /* set default path */
- setenv("PATH", path_default, 1);
-
- if (!reexec)
- init(default_runlevel);
-
- if (mkfifo(RC_INIT_FIFO, 0600) == -1 && errno != EEXIST)
- perror("mkfifo");
-
- for (;;) {
- /* This will block until a command is sent down the pipe... */
- fifo = fopen(RC_INIT_FIFO, "r");
- if (!fifo) {
- if (errno != EINTR)
- perror("fopen");
- continue;
- }
- count = fread(buf, 1, sizeof(buf) - 1, fifo);
- buf[count] = 0;
- fclose(fifo);
- printf("PID1: Received \"%s\" from FIFO...\n", buf);
- if (strcmp(buf, "halt") == 0)
- handle_shutdown("shutdown", RB_HALT_SYSTEM);
- else if (strcmp(buf, "kexec") == 0)
- handle_shutdown("reboot", RB_KEXEC);
- else if (strcmp(buf, "poweroff") == 0)
- handle_shutdown("shutdown", RB_POWER_OFF);
- else if (strcmp(buf, "reboot") == 0)
- handle_shutdown("reboot", RB_AUTOBOOT);
- else if (strcmp(buf, "reexec") == 0)
- handle_reexec(argv[0]);
- else if (strcmp(buf, "single") == 0) {
- handle_single();
- open_shell();
- init(default_runlevel);
- }
- }
- return 0;
-}
diff --git a/src/rc/openrc-run.c b/src/rc/openrc-run.c
deleted file mode 100644
index ff9659a3..00000000
--- a/src/rc/openrc-run.c
+++ /dev/null
@@ -1,1436 +0,0 @@
-/*
- * openrc-run.c
- * Handle launching of init scripts.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fnmatch.h>
-#include <getopt.h>
-#include <libgen.h>
-#include <limits.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <time.h>
-#include <unistd.h>
-
-#if defined(__linux__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) \
- || defined(__GNU__)
-# include <pty.h>
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-# include <util.h>
-#else
-# include <libutil.h>
-#endif
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-#include "rc-selinux.h"
-#include "_usage.h"
-
-#define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
-
-#define WAIT_INTERVAL 20000000 /* usecs to poll the lock file */
-#define WAIT_TIMEOUT 60 /* seconds until we timeout */
-#define WARN_TIMEOUT 10 /* warn about this every N seconds */
-
-const char *applet = NULL;
-const char *extraopts = "stop | start | restart | describe | zap";
-const char getoptstring[] = "dDsSvl:Z" getoptstring_COMMON;
-const struct option longopts[] = {
- { "debug", 0, NULL, 'd'},
- { "dry-run", 0, NULL, 'Z'},
- { "ifstarted", 0, NULL, 's'},
- { "ifstopped", 0, NULL, 'S'},
- { "nodeps", 0, NULL, 'D'},
- { "lockfd", 1, NULL, 'l'},
- longopts_COMMON
-};
-const char *const longopts_help[] = {
- "set xtrace when running the script",
- "show what would be done",
- "only run commands when started",
- "only run commands when stopped",
- "ignore dependencies",
- "fd of the exclusive lock from rc",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static char *service, *runlevel, *ibsave, *prefix;
-static RC_DEPTREE *deptree;
-static RC_STRINGLIST *applet_list, *services, *tmplist;
-static RC_STRINGLIST *restart_services;
-static RC_STRINGLIST *need_services;
-static RC_STRINGLIST *use_services;
-static RC_STRINGLIST *want_services;
-static RC_HOOK hook_out;
-static int exclusive_fd = -1, master_tty = -1;
-static bool sighup, in_background, deps, dry_run;
-static pid_t service_pid;
-static int signal_pipe[2] = { -1, -1 };
-
-static RC_STRINGLIST *deptypes_b; /* broken deps */
-static RC_STRINGLIST *deptypes_n; /* needed deps */
-static RC_STRINGLIST *deptypes_nw; /* need+want deps */
-static RC_STRINGLIST *deptypes_nwu; /* need+want+use deps */
-static RC_STRINGLIST *deptypes_nwua; /* need+want+use+after deps */
-static RC_STRINGLIST *deptypes_m; /* needed deps for stopping */
-static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */
-
-static void
-handle_signal(int sig)
-{
- int serrno = errno;
- char *signame = NULL;
- struct winsize ws;
-
- switch (sig) {
- case SIGHUP:
- sighup = true;
- break;
-
- case SIGCHLD:
- if (signal_pipe[1] > -1) {
- if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
- eerror("%s: send: %s",
- service, strerror(errno));
- } else
- rc_waitpid(-1);
- break;
-
- case SIGWINCH:
- if (master_tty >= 0) {
- ioctl(fileno(stdout), TIOCGWINSZ, &ws);
- ioctl(master_tty, TIOCSWINSZ, &ws);
- }
- break;
-
- case SIGINT:
- if (!signame)
- xasprintf(&signame, "SIGINT");
- /* FALLTHROUGH */
- case SIGTERM:
- if (!signame)
- xasprintf(&signame, "SIGTERM");
- /* FALLTHROUGH */
- case SIGQUIT:
- if (!signame)
- xasprintf(&signame, "SIGQUIT");
- /* Send the signal to our children too */
- if (service_pid > 0)
- kill(service_pid, sig);
- eerror("%s: caught %s, aborting", applet, signame);
- free(signame);
- exit(EXIT_FAILURE);
- /* NOTREACHED */
-
- default:
- eerror("%s: caught unknown signal %d", applet, sig);
- }
-
- /* Restore errno */
- errno = serrno;
-}
-
-static void
-unhotplug()
-{
- char *file = NULL;
-
- xasprintf(&file, RC_SVCDIR "/hotplugged/%s", applet);
- if (exists(file) && unlink(file) != 0)
- eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
- free(file);
-}
-
-static void
-start_services(RC_STRINGLIST *list)
-{
- RC_STRING *svc;
- RC_SERVICE state = rc_service_state (service);
-
- if (!list)
- return;
-
- if (state & RC_SERVICE_INACTIVE ||
- state & RC_SERVICE_WASINACTIVE ||
- state & RC_SERVICE_STARTING ||
- state & RC_SERVICE_STARTED)
- {
- TAILQ_FOREACH(svc, list, entries) {
- if (!(rc_service_state(svc->value) &
- RC_SERVICE_STOPPED))
- continue;
- if (state & RC_SERVICE_INACTIVE ||
- state & RC_SERVICE_WASINACTIVE)
- {
- rc_service_schedule_start(service,
- svc->value);
- ewarn("WARNING: %s will start when %s has started",
- svc->value, applet);
- } else
- service_start(svc->value);
- }
- }
-}
-
-static void
-restore_state(void)
-{
- RC_SERVICE state;
-
- if (rc_in_plugin || exclusive_fd == -1)
- return;
- state = rc_service_state(applet);
- if (state & RC_SERVICE_STOPPING) {
- if (state & RC_SERVICE_WASINACTIVE)
- rc_service_mark(applet, RC_SERVICE_INACTIVE);
- else
- rc_service_mark(applet, RC_SERVICE_STARTED);
- if (rc_runlevel_stopping())
- rc_service_mark(applet, RC_SERVICE_FAILED);
- } else if (state & RC_SERVICE_STARTING) {
- if (state & RC_SERVICE_WASINACTIVE)
- rc_service_mark(applet, RC_SERVICE_INACTIVE);
- else
- rc_service_mark(applet, RC_SERVICE_STOPPED);
- if (rc_runlevel_starting())
- rc_service_mark(applet, RC_SERVICE_FAILED);
- }
- exclusive_fd = svc_unlock(applet, exclusive_fd);
-}
-
-static void
-cleanup(void)
-{
- restore_state();
-
- if (!rc_in_plugin) {
- if (hook_out) {
- rc_plugin_run(hook_out, applet);
- if (hook_out == RC_HOOK_SERVICE_START_DONE)
- rc_plugin_run(RC_HOOK_SERVICE_START_OUT,
- applet);
- else if (hook_out == RC_HOOK_SERVICE_STOP_DONE)
- rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT,
- applet);
- }
-
- if (restart_services)
- start_services(restart_services);
- }
-
- rc_plugin_unload();
-
- rc_stringlist_free(deptypes_b);
- rc_stringlist_free(deptypes_n);
- rc_stringlist_free(deptypes_nw);
- rc_stringlist_free(deptypes_nwu);
- rc_stringlist_free(deptypes_nwua);
- rc_stringlist_free(deptypes_m);
- rc_stringlist_free(deptypes_mwua);
- rc_deptree_free(deptree);
- rc_stringlist_free(restart_services);
- rc_stringlist_free(need_services);
- rc_stringlist_free(use_services);
- rc_stringlist_free(want_services);
- rc_stringlist_free(services);
- rc_stringlist_free(applet_list);
- rc_stringlist_free(tmplist);
- free(ibsave);
- free(service);
- free(prefix);
- free(runlevel);
-}
-
-/* Buffer and lock all output messages so that we get readable content */
-/* FIXME: Use a dynamic lock file that contains the tty/pts as well.
- * For example openrc-pts8.lock or openrc-tty1.lock.
- * Using a static lock file makes no sense, esp. in multi-user environments.
- * Why don't we use (f)printf, as it is thread-safe through POSIX already?
- * Bug: 360013
- */
-static int
-write_prefix(const char *buffer, size_t bytes, bool *prefixed)
-{
- size_t i, j;
- const char *ec = ecolor(ECOLOR_HILITE);
- const char *ec_normal = ecolor(ECOLOR_NORMAL);
- ssize_t ret = 0;
- int fd = fileno(stdout), lock_fd = -1;
-
- /*
- * Lock the prefix.
- * open() may fail here when running as user, as RC_SVCDIR may not be writable.
- */
- lock_fd = open(PREFIX_LOCK, O_WRONLY | O_CREAT, 0664);
-
- if (lock_fd != -1) {
- while (flock(lock_fd, LOCK_EX) != 0) {
- if (errno != EINTR) {
- ewarnv("flock() failed: %s", strerror(errno));
- break;
- }
- }
- }
- else
- ewarnv("Couldn't open the prefix lock, please make sure you have enough permissions");
-
- for (i = 0; i < bytes; i++) {
- /* We don't prefix eend calls (cursor up) */
- if (buffer[i] == '\033' && !*prefixed) {
- for (j = i + 1; j < bytes; j++) {
- if (buffer[j] == 'A')
- *prefixed = true;
- if (isalpha((unsigned int)buffer[j]))
- break;
- }
- }
-
- if (!*prefixed) {
- ret += write(fd, ec, strlen(ec));
- ret += write(fd, prefix, strlen(prefix));
- ret += write(fd, ec_normal, strlen(ec_normal));
- ret += write(fd, "|", 1);
- *prefixed = true;
- }
-
- if (buffer[i] == '\n')
- *prefixed = false;
- ret += write(fd, buffer + i, 1);
- }
-
- /* Release the lock */
- close(lock_fd);
-
- return ret;
-}
-
-static int
-svc_exec(const char *arg1, const char *arg2)
-{
- int ret, fdout = fileno(stdout);
- struct termios tt;
- struct winsize ws;
- int i;
- int flags = 0;
- struct pollfd fd[2];
- int s;
- char *buffer;
- size_t bytes;
- bool prefixed = false;
- int slave_tty;
- sigset_t sigchldmask;
- sigset_t oldmask;
-
- /* Setup our signal pipe */
- if (pipe(signal_pipe) == -1)
- eerrorx("%s: pipe: %s", service, applet);
- for (i = 0; i < 2; i++)
- if ((flags = fcntl(signal_pipe[i], F_GETFD, 0) == -1 ||
- fcntl(signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) == -1))
- eerrorx("%s: fcntl: %s", service, strerror(errno));
-
- /* Open a pty for our prefixed output
- * We do this instead of mapping pipes to stdout, stderr so that
- * programs can tell if they're attached to a tty or not.
- * The only loss is that we can no longer tell the difference
- * between the childs stdout or stderr */
- master_tty = slave_tty = -1;
- if (prefix && isatty(fdout)) {
- tcgetattr(fdout, &tt);
- ioctl(fdout, TIOCGWINSZ, &ws);
-
- /* If the below call fails due to not enough ptys then we don't
- * prefix the output, but we still work */
- openpty(&master_tty, &slave_tty, NULL, &tt, &ws);
- if (master_tty >= 0 &&
- (flags = fcntl(master_tty, F_GETFD, 0)) == 0)
- fcntl(master_tty, F_SETFD, flags | FD_CLOEXEC);
-
- if (slave_tty >=0 &&
- (flags = fcntl(slave_tty, F_GETFD, 0)) == 0)
- fcntl(slave_tty, F_SETFD, flags | FD_CLOEXEC);
- }
-
- service_pid = fork();
- if (service_pid == -1)
- eerrorx("%s: fork: %s", service, strerror(errno));
- if (service_pid == 0) {
- if (slave_tty >= 0) {
- dup2(slave_tty, STDOUT_FILENO);
- dup2(slave_tty, STDERR_FILENO);
- }
-
- if (exists(RC_SVCDIR "/openrc-run.sh")) {
- if (arg2)
- einfov("Executing: %s %s %s %s %s",
- RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh",
- service, arg1, arg2);
- else
- einfov("Executing: %s %s %s %s",
- RC_SVCDIR "/openrc-run.sh", RC_SVCDIR "/openrc-run.sh",
- service, arg1);
- execl(RC_SVCDIR "/openrc-run.sh",
- RC_SVCDIR "/openrc-run.sh",
- service, arg1, arg2, (char *) NULL);
- eerror("%s: exec `" RC_SVCDIR "/openrc-run.sh': %s",
- service, strerror(errno));
- _exit(EXIT_FAILURE);
- } else {
- if (arg2)
- einfov("Executing: %s %s %s %s %s",
- RC_LIBEXECDIR "/sh/openrc-run.sh",
- RC_LIBEXECDIR "/sh/openrc-run.sh",
- service, arg1, arg2);
- else
- einfov("Executing: %s %s %s %s",
- RC_LIBEXECDIR "/sh/openrc-run.sh",
- RC_LIBEXECDIR "/sh/openrc-run.sh",
- service, arg1);
- execl(RC_LIBEXECDIR "/sh/openrc-run.sh",
- RC_LIBEXECDIR "/sh/openrc-run.sh",
- service, arg1, arg2, (char *) NULL);
- eerror("%s: exec `" RC_LIBEXECDIR "/sh/openrc-run.sh': %s",
- service, strerror(errno));
- _exit(EXIT_FAILURE);
- }
- }
-
- buffer = xmalloc(sizeof(char) * BUFSIZ);
- fd[0].fd = signal_pipe[0];
- fd[0].events = fd[1].events = POLLIN;
- fd[0].revents = fd[1].revents = 0;
- if (master_tty >= 0) {
- fd[1].fd = master_tty;
- fd[1].events = POLLIN;
- fd[1].revents = 0;
- }
-
- for (;;) {
- if ((s = poll(fd, master_tty >= 0 ? 2 : 1, -1)) == -1) {
- if (errno != EINTR) {
- eerror("%s: poll: %s",
- service, strerror(errno));
- break;
- }
- }
-
- if (s > 0) {
- if (fd[1].revents & (POLLIN | POLLHUP)) {
- bytes = read(master_tty, buffer, BUFSIZ);
- write_prefix(buffer, bytes, &prefixed);
- }
-
- /* Only SIGCHLD signals come down this pipe */
- if (fd[0].revents & (POLLIN | POLLHUP))
- break;
- }
- }
-
- free(buffer);
-
- sigemptyset (&sigchldmask);
- sigaddset (&sigchldmask, SIGCHLD);
- sigprocmask (SIG_BLOCK, &sigchldmask, &oldmask);
-
- close(signal_pipe[0]);
- close(signal_pipe[1]);
- signal_pipe[0] = signal_pipe[1] = -1;
-
- sigprocmask (SIG_SETMASK, &oldmask, NULL);
-
- if (master_tty >= 0) {
- /* Why did we do this? */
- /* signal (SIGWINCH, SIG_IGN); */
- close(master_tty);
- master_tty = -1;
- }
-
- ret = rc_waitpid(service_pid);
- ret = WEXITSTATUS(ret);
- if (ret != 0 && errno == ECHILD)
- /* killall5 -9 could cause this */
- ret = 0;
- service_pid = 0;
-
- return ret;
-}
-
-static bool
-svc_wait(const char *svc)
-{
- char *file = NULL;
- int fd;
- bool forever = false;
- RC_STRINGLIST *keywords;
- struct timespec interval, timeout, warn;
-
- /* Some services don't have a timeout, like fsck */
- keywords = rc_deptree_depend(deptree, svc, "keyword");
- if (rc_stringlist_find(keywords, "-timeout") ||
- rc_stringlist_find(keywords, "notimeout"))
- forever = true;
- rc_stringlist_free(keywords);
-
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", basename_c(svc));
-
- interval.tv_sec = 0;
- interval.tv_nsec = WAIT_INTERVAL;
- timeout.tv_sec = WAIT_TIMEOUT;
- timeout.tv_nsec = 0;
- warn.tv_sec = WARN_TIMEOUT;
- warn.tv_nsec = 0;
- for (;;) {
- fd = open(file, O_RDONLY | O_NONBLOCK);
- if (fd != -1) {
- if (flock(fd, LOCK_SH | LOCK_NB) == 0) {
- close(fd);
- free(file);
- return true;
- }
- close(fd);
- }
- if (errno == ENOENT) {
- free(file);
- return true;
- }
- if (errno != EWOULDBLOCK) {
- eerror("%s: open `%s': %s", applet, file,
- strerror(errno));
- free(file);
- exit(EXIT_FAILURE);
- }
- if (nanosleep(&interval, NULL) == -1) {
- if (errno != EINTR)
- goto finish;
- }
- if (!forever) {
- timespecsub(&timeout, &interval, &timeout);
- if (timeout.tv_sec <= 0)
- goto finish;
- timespecsub(&warn, &interval, &warn);
- if (warn.tv_sec <= 0) {
- ewarn("%s: waiting for %s (%d seconds)",
- applet, svc, (int)timeout.tv_sec);
- warn.tv_sec = WARN_TIMEOUT;
- warn.tv_nsec = 0;
- }
- }
- }
-finish:
- free(file);
- return false;
-}
-
-static void
-get_started_services(void)
-{
- RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
-
- rc_stringlist_free(restart_services);
- restart_services = rc_services_in_state(RC_SERVICE_STARTED);
- TAILQ_CONCAT(restart_services, tmp, entries);
- free(tmp);
-}
-
-static void
-setup_deptypes(void)
-{
- deptypes_b = rc_stringlist_new();
- rc_stringlist_add(deptypes_b, "broken");
-
- deptypes_n = rc_stringlist_new();
- rc_stringlist_add(deptypes_n, "ineed");
-
- deptypes_nw = rc_stringlist_new();
- rc_stringlist_add(deptypes_nw, "ineed");
- rc_stringlist_add(deptypes_nw, "iwant");
-
- deptypes_nwu = rc_stringlist_new();
- rc_stringlist_add(deptypes_nwu, "ineed");
- rc_stringlist_add(deptypes_nwu, "iwant");
- rc_stringlist_add(deptypes_nwu, "iuse");
-
- deptypes_nwua = rc_stringlist_new();
- rc_stringlist_add(deptypes_nwua, "ineed");
- rc_stringlist_add(deptypes_nwua, "iwant");
- rc_stringlist_add(deptypes_nwua, "iuse");
- rc_stringlist_add(deptypes_nwua, "iafter");
-
- deptypes_m = rc_stringlist_new();
- rc_stringlist_add(deptypes_m, "needsme");
-
- deptypes_mwua = rc_stringlist_new();
- rc_stringlist_add(deptypes_mwua, "needsme");
- rc_stringlist_add(deptypes_mwua, "wantsme");
- rc_stringlist_add(deptypes_mwua, "usesme");
- rc_stringlist_add(deptypes_mwua, "beforeme");
-}
-
-static void
-svc_start_check(void)
-{
- RC_SERVICE state;
-
- state = rc_service_state(service);
-
- if (in_background) {
- if (!(state & (RC_SERVICE_INACTIVE | RC_SERVICE_STOPPED)))
- exit(EXIT_FAILURE);
- if (rc_yesno(getenv("IN_HOTPLUG")))
- rc_service_mark(service, RC_SERVICE_HOTPLUGGED);
- if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0)
- ewarnx("WARNING: %s will be started in the"
- " next runlevel", applet);
- }
-
- if (exclusive_fd == -1)
- exclusive_fd = svc_lock(applet);
- if (exclusive_fd == -1) {
- if (errno == EACCES)
- eerrorx("%s: superuser access required", applet);
- if (state & RC_SERVICE_STOPPING)
- ewarnx("WARNING: %s is stopping", applet);
- else
- ewarnx("WARNING: %s is already starting", applet);
- }
- fcntl(exclusive_fd, F_SETFD,
- fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC);
-
- if (state & RC_SERVICE_STARTED) {
- ewarn("WARNING: %s has already been started", applet);
- exit(EXIT_SUCCESS);
- }
- else if (state & RC_SERVICE_INACTIVE && !in_background)
- ewarnx("WARNING: %s has already started, but is inactive",
- applet);
-
- rc_service_mark(service, RC_SERVICE_STARTING);
- hook_out = RC_HOOK_SERVICE_START_OUT;
- rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet);
-}
-
-static void
-svc_start_deps(void)
-{
- bool first;
- RC_STRING *svc, *svc2;
- RC_SERVICE state;
- int depoptions = RC_DEP_TRACE, n;
- size_t len;
- char *p, *tmp;
- pid_t pid;
-
- errno = 0;
- if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT)
- depoptions |= RC_DEP_STRICT;
-
- if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL))
- eerrorx("failed to load deptree");
- if (!deptypes_b)
- setup_deptypes();
-
- services = rc_deptree_depends(deptree, deptypes_b, applet_list,
- runlevel, 0);
- if (TAILQ_FIRST(services)) {
- eerrorn("ERROR: %s needs service(s) ", applet);
- first = true;
- TAILQ_FOREACH(svc, services, entries) {
- if (first)
- first = false;
- else
- fprintf(stderr, ", ");
- fprintf(stderr, "%s", svc->value);
- }
- fprintf(stderr, "\n");
- exit(EXIT_FAILURE);
- }
- rc_stringlist_free(services);
- services = NULL;
-
- need_services = rc_deptree_depends(deptree, deptypes_n,
- applet_list, runlevel, depoptions);
- want_services = rc_deptree_depends(deptree, deptypes_nw,
- applet_list, runlevel, depoptions);
- use_services = rc_deptree_depends(deptree, deptypes_nwu,
- applet_list, runlevel, depoptions);
-
- if (!rc_runlevel_starting()) {
- TAILQ_FOREACH(svc, use_services, entries) {
- state = rc_service_state(svc->value);
- /* Don't stop failed services again.
- * If you remove this check, ensure that the
- * exclusive file isn't created. */
- if (state & RC_SERVICE_FAILED &&
- rc_runlevel_starting())
- continue;
- if (state & RC_SERVICE_STOPPED) {
- if (dry_run) {
- printf(" %s", svc->value);
- continue;
- }
- pid = service_start(svc->value);
- if (!rc_conf_yesno("rc_parallel"))
- rc_waitpid(pid);
- }
- }
- }
-
- if (dry_run)
- return;
-
- /* Now wait for them to start */
- services = rc_deptree_depends(deptree, deptypes_nwua, applet_list,
- runlevel, depoptions);
- /* We use tmplist to hold our scheduled by list */
- tmplist = rc_stringlist_new();
- TAILQ_FOREACH(svc, services, entries) {
- state = rc_service_state(svc->value);
- if (state & RC_SERVICE_STARTED)
- continue;
-
- /* Don't wait for services which went inactive but are
- * now in starting state which we are after */
- if (state & RC_SERVICE_STARTING &&
- state & RC_SERVICE_WASINACTIVE)
- {
- if (!rc_stringlist_find(need_services, svc->value) &&
- !rc_stringlist_find(want_services, svc->value) &&
- !rc_stringlist_find(use_services, svc->value))
- continue;
- }
-
- if (!svc_wait(svc->value))
- eerror("%s: timed out waiting for %s",
- applet, svc->value);
- state = rc_service_state(svc->value);
- if (state & RC_SERVICE_STARTED)
- continue;
- if (rc_stringlist_find(need_services, svc->value)) {
- if (state & RC_SERVICE_INACTIVE ||
- state & RC_SERVICE_WASINACTIVE)
- {
- rc_stringlist_add(tmplist, svc->value);
- } else if (!TAILQ_FIRST(tmplist))
- eerrorx("ERROR: cannot start %s as"
- " %s would not start",
- applet, svc->value);
- }
- }
-
- if (TAILQ_FIRST(tmplist)) {
- /* Set the state now, then unlink our exclusive so that
- our scheduled list is preserved */
- rc_service_mark(service, RC_SERVICE_STOPPED);
-
- rc_stringlist_free(use_services);
- use_services = NULL;
- len = 0;
- n = 0;
- TAILQ_FOREACH(svc, tmplist, entries) {
- rc_service_schedule_start(svc->value, service);
- use_services = rc_deptree_depend(deptree,
- "iprovide", svc->value);
- TAILQ_FOREACH(svc2, use_services, entries)
- rc_service_schedule_start(svc2->value, service);
- rc_stringlist_free(use_services);
- use_services = NULL;
- len += strlen(svc->value) + 2;
- n++;
- }
-
- len += 5;
- tmp = p = xmalloc(sizeof(char) * len);
- TAILQ_FOREACH(svc, tmplist, entries) {
- if (p != tmp)
- p += snprintf(p, len, ", ");
- p += snprintf(p, len - (p - tmp),
- "%s", svc->value);
- }
- rc_stringlist_free(tmplist);
- tmplist = NULL;
- ewarnx("WARNING: %s will start when %s has started", applet, tmp);
- free(tmp);
- }
-
- rc_stringlist_free(tmplist);
- tmplist = NULL;
- rc_stringlist_free(services);
- services = NULL;
-}
-
-static void svc_start_real()
-{
- bool started;
- RC_STRING *svc, *svc2;
-
- if (ibsave)
- setenv("IN_BACKGROUND", ibsave, 1);
- hook_out = RC_HOOK_SERVICE_START_DONE;
- rc_plugin_run(RC_HOOK_SERVICE_START_NOW, applet);
- started = (svc_exec("start", NULL) == 0);
- if (ibsave)
- unsetenv("IN_BACKGROUND");
-
- if (rc_service_state(service) & RC_SERVICE_INACTIVE)
- ewarnx("WARNING: %s has started, but is inactive", applet);
- else if (!started)
- eerrorx("ERROR: %s failed to start", applet);
-
- rc_service_mark(service, RC_SERVICE_STARTED);
- exclusive_fd = svc_unlock(applet, exclusive_fd);
- hook_out = RC_HOOK_SERVICE_START_OUT;
- rc_plugin_run(RC_HOOK_SERVICE_START_DONE, applet);
-
- /* Now start any scheduled services */
- services = rc_services_scheduled(service);
- TAILQ_FOREACH(svc, services, entries)
- if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
- service_start(svc->value);
- rc_stringlist_free(services);
- services = NULL;
-
- /* Do the same for any services we provide */
- if (deptree) {
- tmplist = rc_deptree_depend(deptree, "iprovide", applet);
- TAILQ_FOREACH(svc, tmplist, entries) {
- services = rc_services_scheduled(svc->value);
- TAILQ_FOREACH(svc2, services, entries)
- if (rc_service_state(svc2->value) &
- RC_SERVICE_STOPPED)
- service_start(svc2->value);
- rc_stringlist_free(services);
- services = NULL;
- }
- rc_stringlist_free(tmplist);
- tmplist = NULL;
- }
-
- hook_out = 0;
- rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet);
-}
-
-static void
-svc_start(void)
-{
- if (dry_run)
- einfon("start:");
- else
- svc_start_check();
- if (deps)
- svc_start_deps();
- if (dry_run)
- printf(" %s\n", applet);
- else
- svc_start_real();
-}
-
-static int
-svc_stop_check(RC_SERVICE *state)
-{
- *state = rc_service_state(service);
-
- if (rc_runlevel_stopping() && *state & RC_SERVICE_FAILED)
- exit(EXIT_FAILURE);
-
- if (in_background &&
- !(*state & RC_SERVICE_STARTED) &&
- !(*state & RC_SERVICE_INACTIVE))
- exit(EXIT_FAILURE);
-
- if (exclusive_fd == -1)
- exclusive_fd = svc_lock(applet);
- if (exclusive_fd == -1) {
- if (errno == EACCES)
- eerrorx("%s: superuser access required", applet);
- if (*state & RC_SERVICE_STOPPING)
- ewarnx("WARNING: %s is already stopping", applet);
- eerrorx("ERROR: %s stopped by something else", applet);
- }
- fcntl(exclusive_fd, F_SETFD,
- fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC);
-
- if (*state & RC_SERVICE_STOPPED) {
- ewarn("WARNING: %s is already stopped", applet);
- return 1;
- }
-
- rc_service_mark(service, RC_SERVICE_STOPPING);
- hook_out = RC_HOOK_SERVICE_STOP_OUT;
- rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet);
-
- if (!rc_runlevel_stopping()) {
- if (rc_service_in_runlevel(service, RC_LEVEL_SYSINIT))
- ewarn("WARNING: you are stopping a sysinit service");
- else if (rc_service_in_runlevel(service, RC_LEVEL_BOOT))
- ewarn("WARNING: you are stopping a boot service");
- }
-
- return 0;
-}
-
-static void
-svc_stop_deps(RC_SERVICE state)
-{
- int depoptions = RC_DEP_TRACE;
- RC_STRING *svc;
- pid_t pid;
-
- if (state & RC_SERVICE_WASINACTIVE)
- return;
-
- errno = 0;
- if (rc_conf_yesno("rc_depend_strict") || errno == ENOENT)
- depoptions |= RC_DEP_STRICT;
-
- if (!deptree && ((deptree = _rc_deptree_load(0, NULL)) == NULL))
- eerrorx("failed to load deptree");
-
- if (!deptypes_m)
- setup_deptypes();
-
- services = rc_deptree_depends(deptree, deptypes_m, applet_list,
- runlevel, depoptions);
- tmplist = rc_stringlist_new();
- TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
- state = rc_service_state(svc->value);
- /* Don't stop failed services again.
- * If you remove this check, ensure that the
- * exclusive file isn't created. */
- if (state & RC_SERVICE_FAILED &&
- rc_runlevel_stopping())
- continue;
- if (state & RC_SERVICE_STARTED ||
- state & RC_SERVICE_INACTIVE)
- {
- if (dry_run) {
- printf(" %s", svc->value);
- continue;
- }
- svc_wait(svc->value);
- state = rc_service_state(svc->value);
- if (state & RC_SERVICE_STARTED ||
- state & RC_SERVICE_INACTIVE)
- {
- pid = service_stop(svc->value);
- if (!rc_conf_yesno("rc_parallel"))
- rc_waitpid(pid);
- rc_stringlist_add(tmplist, svc->value);
- }
- }
- }
- rc_stringlist_free(services);
- services = NULL;
- if (dry_run)
- return;
-
- TAILQ_FOREACH(svc, tmplist, entries) {
- if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
- continue;
- svc_wait(svc->value);
- if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
- continue;
- if (rc_runlevel_stopping()) {
- /* If shutting down, we should stop even
- * if a dependant failed */
- if (runlevel &&
- (strcmp(runlevel,
- RC_LEVEL_SHUTDOWN) == 0 ||
- strcmp(runlevel,
- RC_LEVEL_SINGLE) == 0))
- continue;
- rc_service_mark(service, RC_SERVICE_FAILED);
- }
- eerrorx("ERROR: cannot stop %s as %s "
- "is still up", applet, svc->value);
- }
- rc_stringlist_free(tmplist);
- tmplist = NULL;
-
- /* We now wait for other services that may use us and are
- * stopping. This is important when a runlevel stops */
- services = rc_deptree_depends(deptree, deptypes_mwua, applet_list,
- runlevel, depoptions);
- TAILQ_FOREACH(svc, services, entries) {
- if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
- continue;
- svc_wait(svc->value);
- }
- rc_stringlist_free(services);
- services = NULL;
-}
-
-static void
-svc_stop_real(void)
-{
- bool stopped;
-
- /* If we're stopping localmount, set LC_ALL=C so that
- * bash doesn't load anything blocking the unmounting of /usr */
- if (strcmp(applet, "localmount") == 0)
- setenv("LC_ALL", "C", 1);
-
- if (ibsave)
- setenv("IN_BACKGROUND", ibsave, 1);
- hook_out = RC_HOOK_SERVICE_STOP_DONE;
- rc_plugin_run(RC_HOOK_SERVICE_STOP_NOW, applet);
- stopped = (svc_exec("stop", NULL) == 0);
- if (ibsave)
- unsetenv("IN_BACKGROUND");
-
- if (!stopped)
- eerrorx("ERROR: %s failed to stop", applet);
-
- if (in_background)
- rc_service_mark(service, RC_SERVICE_INACTIVE);
- else
- rc_service_mark(service, RC_SERVICE_STOPPED);
-
- hook_out = RC_HOOK_SERVICE_STOP_OUT;
- rc_plugin_run(RC_HOOK_SERVICE_STOP_DONE, applet);
- hook_out = 0;
- rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet);
-}
-
-static int
-svc_stop(void)
-{
- RC_SERVICE state;
-
- state = 0;
- if (dry_run)
- einfon("stop:");
- else
- if (svc_stop_check(&state) == 1)
- return 1; /* Service has been stopped already */
- if (deps)
- svc_stop_deps(state);
- if (dry_run)
- printf(" %s\n", applet);
- else
- svc_stop_real();
-
- return 0;
-}
-
-static void
-svc_restart(void)
-{
- /* This is hairly and a better way needs to be found I think!
- * The issue is this - openvpn need net and dns. net can restart
- * dns via resolvconf, so you could have openvpn trying to restart
- * dnsmasq which in turn is waiting on net which in turn is waiting
- * on dnsmasq.
- * The work around is for resolvconf to restart its services with
- * --nodeps which means just that.
- * The downside is that there is a small window when our status is
- * invalid.
- * One workaround would be to introduce a new status,
- * or status locking. */
- if (!deps) {
- RC_SERVICE state = rc_service_state(service);
- if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
- svc_exec("stop", "start");
- else
- svc_exec("start", NULL);
- return;
- }
-
- if (!(rc_service_state(service) & RC_SERVICE_STOPPED)) {
- get_started_services();
- svc_stop();
- if (dry_run)
- ewarn("Cannot calculate restart start dependencies"
- " on a dry-run");
- }
-
- svc_start();
- start_services(restart_services);
- rc_stringlist_free(restart_services);
- restart_services = NULL;
-}
-
-static bool
-service_plugable(void)
-{
- char *list, *p, *token;
- bool allow = true, truefalse;
- char *match = rc_conf_value("rc_hotplug");
-
- if (!match)
- match = rc_conf_value("rc_plug_services");
- if (!match)
- return false;
-
- list = xstrdup(match);
- p = list;
- while ((token = strsep(&p, " "))) {
- if (token[0] == '!') {
- truefalse = false;
- token++;
- } else
- truefalse = true;
-
- if (fnmatch(token, applet, 0) == 0) {
- allow = truefalse;
- break;
- }
- }
- free(list);
- return allow;
-}
-
-int main(int argc, char **argv)
-{
- bool doneone = false;
- bool runscript = false;
- int retval, opt, depoptions = RC_DEP_TRACE;
- RC_STRING *svc;
- char *path = NULL;
- char *lnk = NULL;
- char *dir, *save = NULL, *saveLnk = NULL;
- char *pidstr = NULL;
- size_t l = 0, ll;
- const char *file;
- struct stat stbuf;
-
- /* Show help if insufficient args */
- if (argc < 2 || !exists(argv[1])) {
- fprintf(stderr, "openrc-run should not be run directly\n");
- exit(EXIT_FAILURE);
- }
-
- applet = basename_c(argv[0]);
- if (strcmp(applet, "runscript") == 0)
- runscript = true;
-
- if (stat(argv[1], &stbuf) != 0) {
- fprintf(stderr, "openrc-run `%s': %s\n",
- argv[1], strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- atexit(cleanup);
-
- /* We need to work out the real full path to our service.
- * This works fine, provided that we ONLY allow multiplexed services
- * to exist in the same directory as the master link.
- * Also, the master link as to be a real file in the init dir. */
- path = realpath(argv[1], NULL);
- if (!path) {
- fprintf(stderr, "realpath: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- lnk = xmalloc(4096);
- memset(lnk, 0, 4096);
- if (readlink(argv[1], lnk, 4096-1)) {
- dir = dirname(path);
- if (strchr(lnk, '/')) {
- save = xstrdup(dir);
- saveLnk = xstrdup(lnk);
- dir = dirname(saveLnk);
- if (strcmp(dir, save) == 0)
- file = basename_c(argv[1]);
- else
- file = basename_c(lnk);
- dir = save;
- } else
- file = basename_c(argv[1]);
- ll = strlen(dir) + strlen(file) + 2;
- xasprintf(&service, "%s/%s", dir, file);
- if (stat(service, &stbuf) != 0) {
- free(service);
- service = xstrdup(lnk);
- }
- free(save);
- free(saveLnk);
- }
- free(lnk);
- if (!service)
- service = xstrdup(path);
- applet = basename_c(service);
-
- if (argc < 3)
- usage(EXIT_FAILURE);
-
- /* Change dir to / to ensure all init scripts don't use stuff in pwd */
- if (chdir("/") == -1)
- eerror("chdir: %s", strerror(errno));
-
- if ((runlevel = xstrdup(getenv("RC_RUNLEVEL"))) == NULL) {
- env_filter();
- env_config();
- runlevel = rc_runlevel_get();
- }
-
- setenv("EINFO_LOG", service, 1);
- setenv("RC_SVCNAME", applet, 1);
-
- /* Set an env var so that we always know our pid regardless of any
- subshells the init script may create so that our mark_service_*
- functions can always instruct us of this change */
- xasprintf(&pidstr, "%d", (int) getpid());
- setenv("RC_OPENRC_PID", pidstr, 1);
- /*
- * RC_RUNSCRIPT_PID is deprecated, but we will keep it for a while
- * for safety.
- */
- setenv("RC_RUNSCRIPT_PID", pidstr, 1);
-
- /* eprefix is kinda klunky, but it works for our purposes */
- if (rc_conf_yesno("rc_parallel")) {
- /* Get the longest service name */
- services = rc_services_in_runlevel(NULL);
- TAILQ_FOREACH(svc, services, entries) {
- ll = strlen(svc->value);
- if (ll > l)
- l = ll;
- }
- rc_stringlist_free(services);
- services = NULL;
- ll = strlen(applet);
- if (ll > l)
- l = ll;
-
- /* Make our prefix string */
- prefix = xmalloc(sizeof(char) * l + 1);
- memcpy(prefix, applet, ll);
- memset(prefix + ll, ' ', l - ll);
- memset(prefix + l, 0, 1);
- eprefix(prefix);
- }
-
- /* Ok, we are ready to go, so setup selinux if applicable */
- selinux_setup(argv);
-
- deps = true;
-
- /* Punt the first arg as its our service name */
- argc--;
- argv++;
-
- /* Right then, parse any options there may be */
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *)0)) != -1)
- switch (opt) {
- case 'd':
- setenv("RC_DEBUG", "YES", 1);
- break;
- case 'l':
- exclusive_fd = atoi(optarg);
- fcntl(exclusive_fd, F_SETFD,
- fcntl(exclusive_fd, F_GETFD, 0) | FD_CLOEXEC);
- break;
- case 's':
- if (!(rc_service_state(service) & RC_SERVICE_STARTED))
- exit(EXIT_FAILURE);
- break;
- case 'S':
- if (!(rc_service_state(service) & RC_SERVICE_STOPPED))
- exit(EXIT_FAILURE);
- break;
- case 'D':
- deps = false;
- break;
- case 'Z':
- dry_run = true;
- break;
- case_RC_COMMON_GETOPT
- }
-
- if (rc_yesno(getenv("RC_NODEPS")))
- deps = false;
-
- /* If we're changing runlevels and not called by rc then we cannot
- work with any dependencies */
- if (deps && getenv("RC_PID") == NULL &&
- (rc_runlevel_starting() || rc_runlevel_stopping()))
- deps = false;
-
- /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
- that is being called and not any dependents */
- if (getenv("IN_BACKGROUND")) {
- ibsave = xstrdup(getenv("IN_BACKGROUND"));
- in_background = rc_yesno(ibsave);
- unsetenv("IN_BACKGROUND");
- }
-
- if (rc_yesno(getenv("IN_DRYRUN")))
- dry_run = true;
- if (rc_yesno(getenv("IN_HOTPLUG"))) {
- if (!service_plugable())
- eerrorx("%s: not allowed to be hotplugged", applet);
- in_background = true;
- }
-
- /* Setup a signal handler */
- signal_setup(SIGHUP, handle_signal);
- signal_setup(SIGINT, handle_signal);
- signal_setup(SIGQUIT, handle_signal);
- signal_setup(SIGTERM, handle_signal);
- signal_setup(SIGCHLD, handle_signal);
-
- /* Load our plugins */
- rc_plugin_load();
-
- applet_list = rc_stringlist_new();
- rc_stringlist_add(applet_list, applet);
-
- if (runscript)
- ewarn("%s uses runscript, please convert to openrc-run.", service);
-
- /* Now run each option */
- retval = EXIT_SUCCESS;
- while (optind < argc) {
- optarg = argv[optind++];
-
- /* Abort on a sighup here */
- if (sighup)
- exit (EXIT_FAILURE);
-
- /* Export the command we're running.
- This is important as we stamp on the restart function now but
- some start/stop routines still need to behave differently if
- restarting. */
- unsetenv("RC_CMD");
- setenv("RC_CMD", optarg, 1);
-
- doneone = true;
-
- if (strcmp(optarg, "describe") == 0 ||
- strcmp(optarg, "help") == 0 ||
- strcmp(optarg, "depend") == 0)
- {
- save = prefix;
- eprefix(NULL);
- prefix = NULL;
- svc_exec(optarg, NULL);
- eprefix(save);
- prefix = save;
- } else if (strcmp(optarg, "ineed") == 0 ||
- strcmp(optarg, "iuse") == 0 ||
- strcmp(optarg, "iwant") == 0 ||
- strcmp(optarg, "needsme") == 0 ||
- strcmp(optarg, "usesme") == 0 ||
- strcmp(optarg, "wantsme") == 0 ||
- strcmp(optarg, "iafter") == 0 ||
- strcmp(optarg, "ibefore") == 0 ||
- strcmp(optarg, "iprovide") == 0)
- {
- errno = 0;
- if (rc_conf_yesno("rc_depend_strict") ||
- errno == ENOENT)
- depoptions |= RC_DEP_STRICT;
-
- if (!deptree &&
- ((deptree = _rc_deptree_load(0, NULL)) == NULL))
- eerrorx("failed to load deptree");
-
- tmplist = rc_stringlist_new();
- rc_stringlist_add(tmplist, optarg);
- services = rc_deptree_depends(deptree, tmplist,
- applet_list,
- runlevel, depoptions);
- rc_stringlist_free(tmplist);
- tmplist = NULL;
- TAILQ_FOREACH(svc, services, entries)
- printf("%s ", svc->value);
- printf ("\n");
- rc_stringlist_free(services);
- services = NULL;
- } else if (strcmp (optarg, "status") == 0) {
- save = prefix;
- eprefix(NULL);
- prefix = NULL;
- retval = svc_exec("status", NULL);
- } else {
- if (strcmp(optarg, "conditionalrestart") == 0 ||
- strcmp(optarg, "condrestart") == 0)
- {
- if (rc_service_state(service) &
- RC_SERVICE_STARTED)
- svc_restart();
- } else if (strcmp(optarg, "restart") == 0) {
- svc_restart();
- } else if (strcmp(optarg, "start") == 0) {
- svc_start();
- } else if (strcmp(optarg, "stop") == 0 || strcmp(optarg, "pause") == 0) {
- if (strcmp(optarg, "pause") == 0) {
- ewarn("WARNING: 'pause' is deprecated; please use '--nodeps stop'");
- deps = false;
- }
- if (deps && in_background)
- get_started_services();
- if (svc_stop() == 1)
- continue; /* Service has been stopped already */
- if (deps) {
- if (!in_background &&
- !rc_runlevel_stopping() &&
- rc_service_state(service) &
- RC_SERVICE_STOPPED)
- unhotplug();
-
- if (in_background &&
- rc_service_state(service) &
- RC_SERVICE_INACTIVE)
- {
- TAILQ_FOREACH(svc,
- restart_services,
- entries)
- if (rc_service_state(svc->value) &
- RC_SERVICE_STOPPED)
- rc_service_schedule_start(service, svc->value);
- }
- }
- } else if (strcmp(optarg, "zap") == 0) {
- einfo("Manually resetting %s to stopped state",
- applet);
- if (!rc_service_mark(applet,
- RC_SERVICE_STOPPED))
- eerrorx("rc_service_mark: %s",
- strerror(errno));
- unhotplug();
- } else
- retval = svc_exec(optarg, NULL);
-
- /* We should ensure this list is empty after
- * an action is done */
- rc_stringlist_free(restart_services);
- restart_services = NULL;
- }
-
- if (!doneone)
- usage(EXIT_FAILURE);
- }
-
- return retval;
-}
diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c
deleted file mode 100644
index 750946f5..00000000
--- a/src/rc/openrc-shutdown.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * openrc-shutdown.c
- * If you are using OpenRC's provided init, this will shut down or
- * reboot your system.
- *
- * This is based on code written by James Hammons <jlhamm@acm.org>, so
- * I would like to publically thank him for his work.
- */
-
-/*
- * Copyright 2017 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <getopt.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-
-#include "broadcast.h"
-#include "einfo.h"
-#include "rc.h"
-#include "helpers.h"
-#include "rc-misc.h"
-#include "rc-sysvinit.h"
-#include "rc-wtmp.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "cdDfFHKpRrsw" getoptstring_COMMON;
-const struct option longopts[] = {
- { "cancel", no_argument, NULL, 'c'},
- { "no-write", no_argument, NULL, 'd'},
- { "dry-run", no_argument, NULL, 'D'},
- { "halt", no_argument, NULL, 'H'},
- { "kexec", no_argument, NULL, 'K'},
- { "poweroff", no_argument, NULL, 'p'},
- { "reexec", no_argument, NULL, 'R'},
- { "reboot", no_argument, NULL, 'r'},
- { "single", no_argument, NULL, 's'},
- { "write-only", no_argument, NULL, 'w'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "cancel a pending shutdown",
- "do not write wtmp record",
- "print actions instead of executing them",
- "halt the system",
- "reboot the system using kexec",
- "power off the system",
- "re-execute init (use after upgrading)",
- "reboot the system",
- "single user mode",
- "write wtmp boot record and exit",
- longopts_help_COMMON
-};
-const char *usagestring = "" \
- "Usage: openrc-shutdown -c | --cancel\n" \
- " or: openrc-shutdown -R | --reexec\n" \
- " or: openrc-shutdown -w | --write-only\n" \
- " or: openrc-shutdown -H | --halt time\n" \
- " or: openrc-shutdown -K | --kexec time\n" \
- " or: openrc-shutdown -p | --poweroff time\n" \
- " or: openrc-shutdown -r | --reboot time\n" \
- " or: openrc-shutdown -s | --single time";
-const char *exclusive = "Select one of "
- "--cancel, --halt, --kexec, --poweroff, --reexec, --reboot, --single or \n"
- "--write-only";
-const char *nologin_file = RC_SYSCONFDIR"/nologin";
-const char *shutdown_pid = "/run/openrc-shutdown.pid";
-
-static bool do_cancel = false;
-static bool do_dryrun = false;
-static bool do_halt = false;
-static bool do_kexec = false;
-static bool do_poweroff = false;
-static bool do_reboot = false;
-static bool do_reexec = false;
-static bool do_single = false;
-static bool do_wtmp = true;
-static bool do_wtmp_only = false;
-
-static void cancel_shutdown(void)
-{
- pid_t pid;
-
- pid = get_pid(applet, shutdown_pid);
- if (pid <= 0)
- eerrorx("%s: Unable to cancel shutdown", applet);
-
- if (kill(pid, SIGTERM) != -1)
- einfo("%s: shutdown canceled", applet);
- else
- eerrorx("%s: Unable to cancel shutdown", applet);
-}
-
-/*
- * Create the nologin file.
- */
-static void create_nologin(int mins)
-{
- FILE *fp;
- time_t t;
-
- time(&t);
- t += 60 * mins;
-
- if ((fp = fopen(nologin_file, "w")) != NULL) {
- fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
- fclose(fp);
- }
-}
-
-/*
- * Send a command to our init
- */
-static void send_cmd(const char *cmd)
-{
- FILE *fifo;
- size_t ignored;
-
- if (do_dryrun) {
- einfo("Would send %s to init", cmd);
- return;
- }
- if (do_wtmp && (do_halt || do_kexec || do_reboot || do_poweroff))
- log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
- fifo = fopen(RC_INIT_FIFO, "w");
- if (!fifo) {
- perror("fopen");
- return;
- }
-
- ignored = fwrite(cmd, 1, strlen(cmd), fifo);
- if (ignored != strlen(cmd))
- printf("Error writing to init fifo\n");
- fclose(fifo);
-}
-
-/*
- * sleep without being interrupted.
- * The idea for this code came from sysvinit.
- */
-static void sleep_no_interrupt(int seconds)
-{
- struct timespec duration;
- struct timespec remaining;
-
- duration.tv_sec = seconds;
- duration.tv_nsec = 0;
-
- while (nanosleep(&duration, &remaining) < 0 && errno == EINTR)
- duration = remaining;
-}
-
-static void stop_shutdown(int sig)
-{
- (void) sig;
- unlink(nologin_file);
- unlink(shutdown_pid);
-einfo("Shutdown canceled");
-exit(0);
-}
-
-int main(int argc, char **argv)
-{
- char *ch = NULL;
- int opt;
- int cmd_count = 0;
- int hour = 0;
- int min = 0;
- int shutdown_delay = 0;
- struct sigaction sa;
- struct tm *lt;
- time_t tv;
- bool need_warning = false;
- char *msg = NULL;
- char *state = NULL;
- char *time_arg = NULL;
- FILE *fp;
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'c':
- do_cancel = true;
- cmd_count++;
- break;
- case 'd':
- do_wtmp = false;
- break;
- case 'D':
- do_dryrun = true;
- break;
- case 'H':
- do_halt = true;
- xasprintf(&state, "%s", "halt");
- cmd_count++;
- break;
- case 'K':
- do_kexec = true;
- xasprintf(&state, "%s", "reboot");
- cmd_count++;
- break;
- case 'p':
- do_poweroff = true;
- xasprintf(&state, "%s", "power off");
- cmd_count++;
- break;
- case 'R':
- do_reexec = true;
- cmd_count++;
- break;
- case 'r':
- do_reboot = true;
- xasprintf(&state, "%s", "reboot");
- cmd_count++;
- break;
- case 's':
- do_single = true;
- xasprintf(&state, "%s", "go down for maintenance");
- cmd_count++;
- break;
- case 'w':
- do_wtmp_only = true;
- cmd_count++;
- break;
- case_RC_COMMON_GETOPT
- }
- }
- if (geteuid() != 0)
- eerrorx("%s: you must be root\n", applet);
- if (cmd_count != 1) {
- eerror("%s: %s\n", applet, exclusive);
- usage(EXIT_FAILURE);
- }
-
- if (do_cancel) {
- cancel_shutdown();
- exit(EXIT_SUCCESS);
- } else if (do_reexec) {
- send_cmd("reexec");
- exit(EXIT_SUCCESS);
- } else if (do_wtmp_only) {
- log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
- exit(EXIT_SUCCESS);
- }
-
- if (optind >= argc) {
- eerror("%s: No shutdown time specified", applet);
- usage(EXIT_FAILURE);
- }
- time_arg = argv[optind];
- if (*time_arg == '+')
- time_arg++;
- if (strcasecmp(time_arg, "now") == 0)
- strcpy(time_arg, "0");
- for (ch=time_arg; *ch; ch++)
- if ((*ch < '0' || *ch > '9') && *ch != ':') {
- eerror("%s: invalid time %s", applet, time_arg);
- usage(EXIT_FAILURE);
- }
- if (strchr(time_arg, ':')) {
- if ((sscanf(time_arg, "%2d:%2d", &hour, &min) != 2) ||
- (hour > 23) || (min > 59)) {
- eerror("%s: invalid time %s", applet, time_arg);
- usage(EXIT_FAILURE);
- }
- time(&tv);
- lt = localtime(&tv);
- shutdown_delay = (hour * 60 + min) - (lt->tm_hour * 60 + lt->tm_min);
- if (shutdown_delay < 0)
- shutdown_delay += 1440;
- } else {
- shutdown_delay = atoi(time_arg);
- }
-
- fp = fopen(shutdown_pid, "w");
- if (!fp)
- eerrorx("%s: fopen `%s': %s", applet, shutdown_pid, strerror(errno));
- fprintf(fp, "%d\n", getpid());
- fclose(fp);
-
- openlog(applet, LOG_PID, LOG_DAEMON);
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = stop_shutdown;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- while (shutdown_delay > 0) {
- need_warning = false;
- if (shutdown_delay > 180)
- need_warning = (shutdown_delay % 60 == 0);
- else if (shutdown_delay > 60)
- need_warning = (shutdown_delay % 30 == 0);
- else if (shutdown_delay > 10)
- need_warning = (shutdown_delay % 15 == 0);
- else
- need_warning = true;
- if (shutdown_delay <= 5)
- create_nologin(shutdown_delay);
- if (need_warning) {
- xasprintf(&msg, "\rThe system will %s in %d minutes\r\n",
- state, shutdown_delay);
- broadcast(msg);
- free(msg);
- }
- sleep_no_interrupt(60);
- shutdown_delay--;
- }
- xasprintf(&msg, "\rThe system will %s now\r\n", state);
- broadcast(msg);
- syslog(LOG_NOTICE, "The system will %s now", state);
- unlink(nologin_file);
- unlink(shutdown_pid);
- if (do_halt) {
- if (exists("/run/initctl")) {
- sysvinit_setenv("INIT_HALT", "HALT");
- sysvinit_runlevel('0');
- } else
- send_cmd("halt");
- } else if (do_kexec)
- send_cmd("kexec");
- else if (do_poweroff) {
- if (exists("/run/initctl")) {
- sysvinit_setenv("INIT_HALT", "POWEROFF");
- sysvinit_runlevel('0');
- } else
- send_cmd("poweroff");
- } else if (do_reboot) {
- if (exists("/run/initctl"))
- sysvinit_runlevel('6');
- else
- send_cmd("reboot");
- } else if (do_single) {
- if (exists("/run/initctl"))
- sysvinit_runlevel('S');
- else
- send_cmd("single");
- }
- return 0;
-}
diff --git a/src/rc/rc-abort.c b/src/rc/rc-abort.c
deleted file mode 100644
index 39a22c94..00000000
--- a/src/rc/rc-abort.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <errno.h>
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "einfo.h"
-
-int main(void)
-{
- const char *p = getenv("RC_PID");
- int pid;
-
- if (p && sscanf(p, "%d", &pid) == 1) {
- if (kill(pid, SIGUSR1) != 0)
- eerrorx("rc-abort: failed to signal parent %d: %s",
- pid, strerror(errno));
- return EXIT_SUCCESS;
- }
-
- return EXIT_FAILURE;
-}
diff --git a/src/rc/rc-depend.c b/src/rc/rc-depend.c
deleted file mode 100644
index 80754872..00000000
--- a/src/rc/rc-depend.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * rc-depend
- * rc service dependency and ordering
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "aot:suTF:" getoptstring_COMMON;
-const struct option longopts[] = {
- { "starting", 0, NULL, 'a'},
- { "stopping", 0, NULL, 'o'},
- { "type", 1, NULL, 't'},
- { "notrace", 0, NULL, 'T'},
- { "strict", 0, NULL, 's'},
- { "update", 0, NULL, 'u'},
- { "deptree-file", 1, NULL, 'F'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Order services as if runlevel is starting",
- "Order services as if runlevel is stopping",
- "Type(s) of dependency to list",
- "Don't trace service dependencies",
- "Only use what is in the runlevels",
- "Force an update of the dependency tree",
- "File to load cached deptree from",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-int main(int argc, char **argv)
-{
- RC_STRINGLIST *list;
- RC_STRINGLIST *types;
- RC_STRINGLIST *services;
- RC_STRINGLIST *depends;
- RC_STRING *s;
- RC_DEPTREE *deptree = NULL;
- int options = RC_DEP_TRACE, update = 0;
- bool first = true;
- char *runlevel = xstrdup(getenv("RC_RUNLEVEL"));
- int opt;
- char *token;
- char *deptree_file = NULL;
-
- applet = basename_c(argv[0]);
- types = rc_stringlist_new();
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'a':
- options |= RC_DEP_START;
- break;
- case 'o':
- options |= RC_DEP_STOP;
- break;
- case 's':
- options |= RC_DEP_STRICT;
- break;
- case 't':
- while ((token = strsep(&optarg, ",")))
- rc_stringlist_add(types, token);
- break;
- case 'u':
- update = 1;
- break;
- case 'T':
- options &= RC_DEP_TRACE;
- break;
- case 'F':
- deptree_file = xstrdup(optarg);
- break;
-
- case_RC_COMMON_GETOPT
- }
- }
-
- if (deptree_file) {
- if (!(deptree = rc_deptree_load_file(deptree_file)))
- eerrorx("failed to load deptree");
- } else {
- if (!(deptree = _rc_deptree_load(update, NULL)))
- eerrorx("failed to load deptree");
- }
-
- if (!runlevel)
- runlevel = rc_runlevel_get();
-
- services = rc_stringlist_new();
- while (optind < argc) {
- list = rc_stringlist_new();
- rc_stringlist_add(list, argv[optind]);
- errno = 0;
- depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
- if (!depends && errno == ENOENT)
- eerror("no dependency info for service `%s'",
- argv[optind]);
- else
- rc_stringlist_add(services, argv[optind]);
-
- rc_stringlist_free(depends);
- rc_stringlist_free(list);
- optind++;
- }
- if (!TAILQ_FIRST(services)) {
- rc_stringlist_free(services);
- rc_stringlist_free(types);
- rc_deptree_free(deptree);
- free(runlevel);
- if (update)
- return EXIT_SUCCESS;
- eerrorx("no services specified");
- }
-
- /* If we don't have any types, then supply some defaults */
- if (!TAILQ_FIRST(types)) {
- rc_stringlist_add(types, "ineed");
- rc_stringlist_add(types, "iuse");
- }
-
- depends = rc_deptree_depends(deptree, types, services,
- runlevel, options);
-
- if (TAILQ_FIRST(depends)) {
- TAILQ_FOREACH(s, depends, entries) {
- if (first)
- first = false;
- else
- printf (" ");
- printf ("%s", s->value);
-
- }
- printf ("\n");
- }
-
- rc_stringlist_free(types);
- rc_stringlist_free(services);
- rc_stringlist_free(depends);
- rc_deptree_free(deptree);
- free(runlevel);
- return EXIT_SUCCESS;
-}
diff --git a/src/rc/rc-logger.c b/src/rc/rc-logger.c
deleted file mode 100644
index 4b1b9189..00000000
--- a/src/rc/rc-logger.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * rc-logger.c
- * Spawns a logging daemon to capture stdout and stderr so we can log
- * them to a buffer and/or files.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <time.h>
-#include <unistd.h>
-
-#if defined(__linux__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) \
- || defined(__GNU__)
-# include <pty.h>
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
-# include <util.h>
-#else
-# include <libutil.h>
-#endif
-
-#include "einfo.h"
-#include "rc-logger.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-
-#define TMPLOG RC_SVCDIR "/rc.log"
-#define DEFAULTLOG "/var/log/rc.log"
-
-static int signal_pipe[2] = { -1, -1 };
-static int fd_stdout = -1;
-static int fd_stderr = -1;
-static const char *runlevel = NULL;
-static bool in_escape = false;
-static bool in_term = false;
-
-static char *logbuf = NULL;
-static size_t logbuf_size = 0;
-static size_t logbuf_len = 0;
-
-pid_t rc_logger_pid = -1;
-int rc_logger_tty = -1;
-bool rc_in_logger = false;
-
-static void
-write_log(int logfd, const char *buffer, size_t bytes)
-{
- const char *p = buffer;
-
- while ((size_t)(p - buffer) < bytes) {
- switch (*p) {
- case '\r':
- goto cont;
- case '\033':
- in_escape = true;
- in_term = false;
- goto cont;
- case '\n':
- in_escape = in_term = false;
- break;
- case '[':
- if (in_escape)
- in_term = true;
- break;
- }
-
- if (!in_escape) {
- if (!isprint((int) *p) && *p != '\n')
- goto cont;
- if (write(logfd, p++, 1) == -1)
- eerror("write: %s", strerror(errno));
- continue;
- }
-
- if (!in_term || isalpha((unsigned char)*p))
- in_escape = in_term = false;
-cont:
- p++;
- }
-}
-
-static void
-write_time(FILE *f, const char *s)
-{
- time_t now = time(NULL);
- struct tm *tm = localtime(&now);
-
- fprintf(f, "\nrc %s logging %s at %s\n", runlevel, s, asctime(tm));
- fflush(f);
-}
-
-void
-rc_logger_close(void)
-{
- int sig = SIGTERM;
-
- if (signal_pipe[1] > -1) {
- if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
- eerror("write: %s", strerror(errno));
- close(signal_pipe[1]);
- signal_pipe[1] = -1;
- }
-
- if (rc_logger_pid > 0)
- waitpid(rc_logger_pid, 0, 0);
-
- if (fd_stdout > -1)
- dup2(fd_stdout, STDOUT_FILENO);
- if (fd_stderr > -1)
- dup2(fd_stderr, STDERR_FILENO);
-}
-
-void
-rc_logger_open(const char *level)
-{
- int slave_tty;
- struct termios tt;
- struct winsize ws;
- char buffer[BUFSIZ];
- struct pollfd fd[2];
- int s = 0;
- size_t bytes;
- int i;
- FILE *log = NULL;
- FILE *plog = NULL;
- const char *logfile;
- int log_error = 0;
-
- if (!rc_conf_yesno("rc_logger"))
- return;
-
- if (pipe(signal_pipe) == -1)
- eerrorx("pipe: %s", strerror(errno));
- for (i = 0; i < 2; i++)
- if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 ||
- fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1))
- eerrorx("fcntl: %s", strerror (errno));
-
- if (isatty(STDOUT_FILENO)) {
- tcgetattr(STDOUT_FILENO, &tt);
- ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
- if (openpty(&rc_logger_tty, &slave_tty, NULL, &tt, &ws))
- return;
- } else
- if (openpty(&rc_logger_tty, &slave_tty, NULL, NULL, NULL))
- return;
-
- if ((s = fcntl(rc_logger_tty, F_GETFD, 0)) == 0)
- fcntl(rc_logger_tty, F_SETFD, s | FD_CLOEXEC);
-
- if ((s = fcntl(slave_tty, F_GETFD, 0)) == 0)
- fcntl(slave_tty, F_SETFD, s | FD_CLOEXEC);
-
- rc_logger_pid = fork();
- switch (rc_logger_pid) {
- case -1:
- eerror("fork: %s", strerror(errno));
- break;
- case 0:
- rc_in_logger = true;
- close(signal_pipe[1]);
- signal_pipe[1] = -1;
-
- runlevel = level;
- if ((log = fopen(TMPLOG, "ae")))
- write_time(log, "started");
- else {
- free(logbuf);
- logbuf_size = BUFSIZ * 10;
- logbuf = xmalloc(sizeof (char) * logbuf_size);
- logbuf_len = 0;
- }
-
- fd[0].fd = signal_pipe[0];
- fd[0].events = fd[1].events = POLLIN;
- fd[0].revents = fd[1].revents = 0;
- if (rc_logger_tty >= 0)
- fd[1].fd = rc_logger_tty;
- for (;;) {
- if ((s = poll(fd,
- rc_logger_tty >= 0 ? 2 : 1, -1)) == -1)
- {
- eerror("poll: %s", strerror(errno));
- break;
- } else if (s == 0)
- continue;
-
- if (fd[1].revents & (POLLIN | POLLHUP)) {
- memset(buffer, 0, BUFSIZ);
- bytes = read(rc_logger_tty, buffer, BUFSIZ);
- if (write(STDOUT_FILENO, buffer, bytes) == -1)
- eerror("write: %s", strerror(errno));
-
- if (log)
- write_log(fileno (log), buffer, bytes);
- else {
- if (logbuf_size - logbuf_len < bytes) {
- logbuf_size += BUFSIZ * 10;
- logbuf = xrealloc(logbuf,
- sizeof(char ) *
- logbuf_size);
- }
-
- memcpy(logbuf + logbuf_len,
- buffer, bytes);
- logbuf_len += bytes;
- }
- }
-
- /* Only SIGTERMS signals come down this pipe */
- if (fd[0].revents & (POLLIN | POLLHUP))
- break;
- }
- if (logbuf) {
- if ((log = fopen(TMPLOG, "ae"))) {
- write_time(log, "started");
- write_log(fileno(log), logbuf, logbuf_len);
- }
- free(logbuf);
- }
- if (log) {
- write_time(log, "stopped");
- fclose(log);
- }
-
- /* Append the temporary log to the real log */
- logfile = rc_conf_value("rc_log_path");
- if (logfile == NULL)
- logfile = DEFAULTLOG;
- if (!strcmp(logfile, TMPLOG)) {
- eerror("Cowardly refusing to concatenate a logfile into itself.");
- eerrorx("Please change rc_log_path to something other than %s to get rid of this message", TMPLOG);
- }
-
- if ((plog = fopen(logfile, "ae"))) {
- if ((log = fopen(TMPLOG, "re"))) {
- while ((bytes = fread(buffer, sizeof(*buffer), BUFSIZ, log)) > 0) {
- if (fwrite(buffer, sizeof(*buffer), bytes, plog) < bytes) {
- log_error = 1;
- eerror("Error: write(%s) failed: %s", logfile, strerror(errno));
- break;
- }
- }
- fclose(log);
- } else {
- log_error = 1;
- eerror("Error: fopen(%s) failed: %s", TMPLOG, strerror(errno));
- }
-
- fclose(plog);
- } else {
- /*
- * logfile or its basedir may be read-only during sysinit and
- * shutdown so skip the error in this case
- */
- if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0))) {
- log_error = 1;
- eerror("Error: fopen(%s) failed: %s", logfile, strerror(errno));
- }
- }
-
- /* Try to keep the temporary log in case of errors */
- if (!log_error) {
- if (errno != EROFS && ((strcmp(level, RC_LEVEL_SHUTDOWN) != 0) && (strcmp(level, RC_LEVEL_SYSINIT) != 0)))
- if (unlink(TMPLOG) == -1)
- eerror("Error: unlink(%s) failed: %s", TMPLOG, strerror(errno));
- } else if (exists(TMPLOG))
- eerrorx("Warning: temporary logfile left behind: %s", TMPLOG);
-
- exit(0);
- /* NOTREACHED */
-
- default:
- setpgid(rc_logger_pid, 0);
- fd_stdout = dup(STDOUT_FILENO);
- fd_stderr = dup(STDERR_FILENO);
- if ((s = fcntl(fd_stdout, F_GETFD, 0)) == 0)
- fcntl(fd_stdout, F_SETFD, s | FD_CLOEXEC);
-
- if ((s = fcntl(fd_stderr, F_GETFD, 0)) == 0)
- fcntl(fd_stderr, F_SETFD, s | FD_CLOEXEC);
- dup2(slave_tty, STDOUT_FILENO);
- dup2(slave_tty, STDERR_FILENO);
- if (slave_tty != STDIN_FILENO &&
- slave_tty != STDOUT_FILENO &&
- slave_tty != STDERR_FILENO)
- close(slave_tty);
- close(signal_pipe[0]);
- signal_pipe[0] = -1;
- break;
- }
-}
diff --git a/src/rc/rc-logger.h b/src/rc/rc-logger.h
deleted file mode 100644
index 52ca9717..00000000
--- a/src/rc/rc-logger.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef RC_LOGGER_H
-#define RC_LOGGER_H
-
-extern pid_t rc_logger_pid;
-extern int rc_logger_tty;
-extern bool rc_in_logger;
-
-void rc_logger_open(const char *runlevel);
-void rc_logger_close(void);
-
-#endif
diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c
deleted file mode 100644
index 1ca51e72..00000000
--- a/src/rc/rc-misc.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * rc-misc.c
- * rc misc functions
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/file.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-
-#ifdef __linux__
-# include <sys/sysinfo.h>
-#endif
-
-#include <sys/time.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "version.h"
-
-extern char **environ;
-
-bool
-rc_conf_yesno(const char *setting)
-{
- return rc_yesno(rc_conf_value (setting));
-}
-
-static const char *const env_whitelist[] = {
- "EERROR_QUIET", "EINFO_QUIET",
- "IN_BACKGROUND", "IN_DRYRUN", "IN_HOTPLUG",
- "RC_DEBUG", "RC_NODEPS",
- "LANG", "LC_MESSAGES", "TERM",
- "EINFO_COLOR", "EINFO_VERBOSE",
- NULL
-};
-
-void
-env_filter(void)
-{
- RC_STRINGLIST *env_allow;
- RC_STRINGLIST *profile;
- RC_STRINGLIST *env_list;
- RC_STRING *env;
- char *e;
- size_t i = 0;
-
- /* Add the user defined list of vars */
- env_allow = rc_stringlist_split(rc_conf_value("rc_env_allow"), " ");
- /*
- * If '*' is an entry in rc_env_allow, do nothing as we are to pass
- * through all environment variables.
- */
- if (rc_stringlist_find(env_allow, "*"))
- return;
- profile = rc_config_load(RC_PROFILE_ENV);
-
- /* Copy the env and work from this so we can manipulate it safely */
- env_list = rc_stringlist_new();
- while (environ && environ[i]) {
- env = rc_stringlist_add(env_list, environ[i++]);
- e = strchr(env->value, '=');
- if (e)
- *e = '\0';
- }
-
- TAILQ_FOREACH(env, env_list, entries) {
- /* Check the whitelist */
- for (i = 0; env_whitelist[i]; i++) {
- if (strcmp(env_whitelist[i], env->value) == 0)
- break;
- }
- if (env_whitelist[i])
- continue;
-
- /* Check our user defined list */
- if (rc_stringlist_find(env_allow, env->value))
- continue;
-
- /* OK, not allowed! */
- unsetenv(env->value);
- }
-
- /* Now add anything missing from the profile */
- TAILQ_FOREACH(env, profile, entries) {
- e = strchr(env->value, '=');
- *e = '\0';
- if (!getenv(env->value))
- setenv(env->value, e + 1, 1);
- }
-
- rc_stringlist_free(env_list);
- rc_stringlist_free(env_allow);
- rc_stringlist_free(profile);
-}
-
-void
-env_config(void)
-{
- size_t pplen = strlen(RC_PATH_PREFIX);
- char *path;
- char *p;
- char *e;
- size_t l;
- struct utsname uts;
- FILE *fp;
- char *token;
- char *np;
- char *npp;
- char *tok;
- const char *sys = rc_sys();
- char *buffer = NULL;
- size_t size = 0;
-
- /* Ensure our PATH is prefixed with the system locations first
- for a little extra security */
- path = getenv("PATH");
- if (!path)
- setenv("PATH", RC_PATH_PREFIX, 1);
- else if (strncmp (RC_PATH_PREFIX, path, pplen) != 0) {
- l = strlen(path) + pplen + 3;
- e = p = xmalloc(sizeof(char) * l);
- p += snprintf(p, l, "%s", RC_PATH_PREFIX);
-
- /* Now go through the env var and only add bits not in our
- * PREFIX */
- while ((token = strsep(&path, ":"))) {
- np = npp = xstrdup(RC_PATH_PREFIX);
- while ((tok = strsep(&npp, ":")))
- if (strcmp(tok, token) == 0)
- break;
- if (!tok)
- p += snprintf(p, l - (p - e), ":%s", token);
- free (np);
- }
- *p++ = '\0';
- unsetenv("PATH");
- setenv("PATH", e, 1);
- free(e);
- }
-
- setenv("RC_VERSION", VERSION, 1);
- setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 1);
- setenv("RC_SVCDIR", RC_SVCDIR, 1);
- setenv("RC_TMPDIR", RC_SVCDIR "/tmp", 1);
- setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1);
- e = rc_runlevel_get();
- setenv("RC_RUNLEVEL", e, 1);
- free(e);
-
- if ((fp = fopen(RC_KRUNLEVEL, "r"))) {
- if (getline(&buffer, &size, fp) != -1) {
- l = strlen (buffer) - 1;
- if (buffer[l] == '\n')
- buffer[l] = 0;
- setenv("RC_DEFAULTLEVEL", buffer, 1);
- }
- fclose(fp);
- } else
- setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1);
-
- free(buffer);
- if (sys)
- setenv("RC_SYS", sys, 1);
-
-#ifdef PREFIX
- setenv("RC_PREFIX", RC_PREFIX, 1);
-#endif
-
- /* Some scripts may need to take a different code path if
- Linux/FreeBSD, etc
- To save on calling uname, we store it in an environment variable */
- if (uname(&uts) == 0)
- setenv("RC_UNAME", uts.sysname, 1);
-
- /* Be quiet or verbose as necessary */
- if (rc_conf_yesno("rc_quiet"))
- setenv("EINFO_QUIET", "YES", 1);
- if (rc_conf_yesno("rc_verbose"))
- setenv("EINFO_VERBOSE", "YES", 1);
-
- errno = 0;
- if ((!rc_conf_yesno("rc_color") && errno == 0) ||
- rc_conf_yesno("rc_nocolor"))
- setenv("EINFO_COLOR", "NO", 1);
-}
-
-int
-signal_setup(int sig, void (*handler)(int))
-{
- struct sigaction sa;
-
- memset(&sa, 0, sizeof (sa));
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = handler;
- return sigaction(sig, &sa, NULL);
-}
-
-int
-signal_setup_restart(int sig, void (*handler)(int))
-{
- struct sigaction sa;
-
- memset(&sa, 0, sizeof (sa));
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = handler;
- sa.sa_flags = SA_RESTART;
- return sigaction(sig, &sa, NULL);
-}
-
-int
-svc_lock(const char *applet)
-{
- char *file = NULL;
- int fd;
-
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
- fd = open(file, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
- free(file);
- if (fd == -1)
- return -1;
- if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
- eerror("Call to flock failed: %s", strerror(errno));
- close(fd);
- return -1;
- }
- return fd;
-}
-
-int
-svc_unlock(const char *applet, int fd)
-{
- char *file = NULL;
-
- xasprintf(&file, RC_SVCDIR "/exclusive/%s", applet);
- close(fd);
- unlink(file);
- free(file);
- return -1;
-}
-
-pid_t
-exec_service(const char *service, const char *arg)
-{
- char *file, sfd[32];
- int fd;
- pid_t pid = -1;
- sigset_t full;
- sigset_t old;
- struct sigaction sa;
-
- fd = svc_lock(basename_c(service));
- if (fd == -1)
- return -1;
-
- file = rc_service_resolve(service);
- if (!exists(file)) {
- rc_service_mark(service, RC_SERVICE_STOPPED);
- svc_unlock(basename_c(service), fd);
- free(file);
- return 0;
- }
- snprintf(sfd, sizeof(sfd), "%d", fd);
-
- /* We need to block signals until we have forked */
- memset(&sa, 0, sizeof (sa));
- sa.sa_handler = SIG_DFL;
- sigemptyset(&sa.sa_mask);
- sigfillset(&full);
- sigprocmask(SIG_SETMASK, &full, &old);
-
- if ((pid = fork()) == 0) {
- /* Restore default handlers */
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGUSR1, &sa, NULL);
- sigaction(SIGWINCH, &sa, NULL);
-
- /* Unmask signals */
- sigprocmask(SIG_SETMASK, &old, NULL);
-
- /* Safe to run now */
- execl(file, file, "--lockfd", sfd, arg, (char *) NULL);
- fprintf(stderr, "unable to exec `%s': %s\n",
- file, strerror(errno));
- svc_unlock(basename_c(service), fd);
- _exit(EXIT_FAILURE);
- }
-
- if (pid == -1) {
- fprintf(stderr, "fork: %s\n",strerror (errno));
- svc_unlock(basename_c(service), fd);
- } else
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
-
- sigprocmask(SIG_SETMASK, &old, NULL);
- free(file);
- return pid;
-}
-
-int
-parse_mode(mode_t *mode, char *text)
-{
- char *p;
- unsigned long l;
-
- /* Check for a numeric mode */
- if ((*text - '0') < 8) {
- l = strtoul(text, &p, 8);
- if (*p || l > 07777U) {
- errno = EINVAL;
- return -1;
- }
- *mode = (mode_t) l;
- return 0;
- }
-
- /* We currently don't check g+w type stuff */
- errno = EINVAL;
- return -1;
-}
-
-int
-is_writable(const char *path)
-{
- if (access(path, W_OK) == 0)
- return 1;
-
- return 0;
-}
-
-RC_DEPTREE * _rc_deptree_load(int force, int *regen)
-{
- int fd;
- int retval;
- int serrno = errno;
- int merrno;
- time_t t;
- char file[PATH_MAX];
- struct stat st;
- struct utimbuf ut;
- FILE *fp;
-
- t = 0;
- if (rc_deptree_update_needed(&t, file) || force != 0) {
- /* Test if we have permission to update the deptree */
- fd = open(RC_DEPTREE_CACHE, O_WRONLY);
- merrno = errno;
- errno = serrno;
- if (fd == -1 && merrno == EACCES)
- return rc_deptree_load();
- close(fd);
-
- if (regen)
- *regen = 1;
- ebegin("Caching service dependencies");
- retval = rc_deptree_update() ? 0 : -1;
- eend (retval, "Failed to update the dependency tree");
-
- if (retval == 0) {
- if (stat(RC_DEPTREE_CACHE, &st) != 0) {
- eerror("stat(%s): %s", RC_DEPTREE_CACHE, strerror(errno));
- return NULL;
- }
- if (st.st_mtime < t) {
- eerror("Clock skew detected with `%s'", file);
- eerrorn("Adjusting mtime of `" RC_DEPTREE_CACHE
- "' to %s", ctime(&t));
- fp = fopen(RC_DEPTREE_SKEWED, "w");
- if (fp != NULL) {
- fprintf(fp, "%s\n", file);
- fclose(fp);
- }
- ut.actime = t;
- ut.modtime = t;
- utime(RC_DEPTREE_CACHE, &ut);
- } else {
- if (exists(RC_DEPTREE_SKEWED))
- unlink(RC_DEPTREE_SKEWED);
- }
- }
- if (force == -1 && regen != NULL)
- *regen = retval;
- }
- return rc_deptree_load();
-}
-
-static const struct {
- const char * const name;
- RC_SERVICE bit;
-} service_bits[] = {
- { "service_started", RC_SERVICE_STARTED, },
- { "service_stopped", RC_SERVICE_STOPPED, },
- { "service_inactive", RC_SERVICE_INACTIVE, },
- { "service_starting", RC_SERVICE_STARTING, },
- { "service_stopping", RC_SERVICE_STOPPING, },
- { "service_hotplugged", RC_SERVICE_HOTPLUGGED, },
- { "service_wasinactive", RC_SERVICE_WASINACTIVE, },
- { "service_failed", RC_SERVICE_FAILED, },
- { "service_crashed", RC_SERVICE_CRASHED, },
-};
-
-RC_SERVICE lookup_service_state(const char *service)
-{
- size_t i;
- for (i = 0; i < ARRAY_SIZE(service_bits); ++i)
- if (!strcmp(service, service_bits[i].name))
- return service_bits[i].bit;
- return 0;
-}
-
-void from_time_t(char *time_string, time_t tv)
-{
- strftime(time_string, 20, "%Y-%m-%d %H:%M:%S", localtime(&tv));
-}
-
-time_t to_time_t(char *timestring)
-{
- int check = 0;
- int year = 0;
- int month = 0;
- int day = 0;
- int hour = 0;
- int min = 0;
- int sec = 0;
- struct tm breakdown = {0};
- time_t result = -1;
-
- check = sscanf(timestring, "%4d-%2d-%2d %2d:%2d:%2d",
- &year, &month, &day, &hour, &min, &sec);
- if (check == 6) {
- breakdown.tm_year = year - 1900; /* years since 1900 */
- breakdown.tm_mon = month - 1;
- breakdown.tm_mday = day;
- breakdown.tm_hour = hour;
- breakdown.tm_min = min;
- breakdown.tm_sec = sec;
- breakdown.tm_isdst = -1;
- result = mktime(&breakdown);
- }
- return result;
-}
-
-pid_t get_pid(const char *applet,const char *pidfile)
-{
- FILE *fp;
- pid_t pid;
-
- if (!pidfile)
- return -1;
-
- if ((fp = fopen(pidfile, "r")) == NULL) {
- ewarnv("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
- return -1;
- }
-
- if (fscanf(fp, "%d", &pid) != 1) {
- ewarnv("%s: no pid found in `%s'", applet, pidfile);
- fclose(fp);
- return -1;
- }
-
- fclose(fp);
-
- return pid;
-}
diff --git a/src/rc/rc-pipes.c b/src/rc/rc-pipes.c
deleted file mode 100644
index b4e60e03..00000000
--- a/src/rc/rc-pipes.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * rc-pipes.c
- * Helper to handle spawning processes and connecting them to pipes.
- */
-
-/*
- * Copyright (c) 2018 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "rc-pipes.h"
-
-static const int pipe_read_end = 0;
-static const int pipe_write_end = 1;
-
-/*
- * Starts a command with stdin redirected from a pipe
- * Returns the write end of the pipe or -1
- */
-int rc_pipe_command(char *cmd)
-{
- int pfd[2];
- pid_t pid;
-
- if (pipe(pfd) < 0)
- return -1;
-
- pid = fork();
- if (pid > 0) {
- /* parent */
- close(pfd[pipe_read_end]);
- return pfd[pipe_write_end];
- } else if (pid == 0) {
- /* child */
- close(pfd[pipe_write_end]);
- if (pfd[pipe_read_end] != STDIN_FILENO) {
- if (dup2(pfd[pipe_read_end], STDIN_FILENO) < 0)
- exit(1);
- close(pfd[pipe_read_end]);
- }
- execl("/bin/sh", "sh", "-c", cmd, NULL);
- exit(1);
- }
- return -1;
-}
diff --git a/src/rc/rc-pipes.h b/src/rc/rc-pipes.h
deleted file mode 100644
index 861963b7..00000000
--- a/src/rc/rc-pipes.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2018 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef RC_PIPES_H
-#define RC_PIPES_H
-
-int rc_pipe_command(char *cmd);
-
-#endif
diff --git a/src/rc/rc-plugin.c b/src/rc/rc-plugin.c
deleted file mode 100644
index 76995866..00000000
--- a/src/rc/rc-plugin.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * rc-plugin.c
- * Simple plugin handler
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-
-#define RC_PLUGIN_HOOK "rc_plugin_hook"
-
-bool rc_in_plugin = false;
-
-typedef struct plugin
-{
- char *name;
- void *handle;
- int (*hook)(RC_HOOK, const char *);
- TAILQ_ENTRY(plugin) entries;
-} PLUGIN;
-TAILQ_HEAD(, plugin) plugins;
-
-#ifndef __FreeBSD__
-dlfunc_t
-dlfunc(void * __restrict handle, const char * __restrict symbol)
-{
- union {
- void *d;
- dlfunc_t f;
- } rv;
-
- rv.d = dlsym(handle, symbol);
- return rv.f;
-}
-#endif
-
-void
-rc_plugin_load(void)
-{
- DIR *dp;
- struct dirent *d;
- PLUGIN *plugin;
- char *file = NULL;
- void *h;
- int (*fptr)(RC_HOOK, const char *);
-
- /* Don't load plugins if we're in one */
- if (rc_in_plugin)
- return;
-
- TAILQ_INIT(&plugins);
-
- if (!(dp = opendir(RC_PLUGINDIR)))
- return;
-
- while ((d = readdir(dp))) {
- if (d->d_name[0] == '.')
- continue;
-
- xasprintf(&file, RC_PLUGINDIR "/%s", d->d_name);
- h = dlopen(file, RTLD_LAZY);
- free(file);
- if (h == NULL) {
- eerror("dlopen: %s", dlerror());
- continue;
- }
-
- fptr = (int (*)(RC_HOOK, const char *))
- dlfunc(h, RC_PLUGIN_HOOK);
- if (fptr == NULL) {
- eerror("%s: cannot find symbol `%s'",
- d->d_name, RC_PLUGIN_HOOK);
- dlclose(h);
- } else {
- plugin = xmalloc(sizeof(*plugin));
- plugin->name = xstrdup(d->d_name);
- plugin->handle = h;
- plugin->hook = fptr;
- TAILQ_INSERT_TAIL(&plugins, plugin, entries);
- }
- }
- closedir(dp);
-}
-
-int
-rc_waitpid(pid_t pid)
-{
- int status;
-
- while (waitpid(pid, &status, 0) == -1) {
- if (errno != EINTR) {
- status = -1;
- break;
- }
- }
- return status;
-}
-
-void
-rc_plugin_run(RC_HOOK hook, const char *value)
-{
- PLUGIN *plugin;
- struct sigaction sa;
- sigset_t empty;
- sigset_t full;
- sigset_t old;
- int i;
- int flags;
- int pfd[2];
- pid_t pid;
- char *buffer;
- char *token;
- char *p;
- ssize_t nr;
- int retval;
-
- /* Don't run plugins if we're in one */
- if (rc_in_plugin)
- return;
-
- /* We need to block signals until we have forked */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigemptyset(&sa.sa_mask);
- sigemptyset(&empty);
- sigfillset(&full);
-
- TAILQ_FOREACH(plugin, &plugins, entries) {
- /* We create a pipe so that plugins can affect our environment
- * vars, which in turn influence our scripts. */
- if (pipe(pfd) == -1) {
- eerror("pipe: %s", strerror(errno));
- return;
- }
-
- /* Stop any scripts from inheriting us.
- * This is actually quite important as without this, the splash
- * plugin will probably hang when running in silent mode. */
- for (i = 0; i < 2; i++)
- if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
- fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
- eerror("fcntl: %s", strerror(errno));
-
- sigprocmask(SIG_SETMASK, &full, &old);
-
- /* We run the plugin in a new process so we never crash
- * or otherwise affected by it */
- if ((pid = fork()) == -1) {
- eerror("fork: %s", strerror(errno));
- break;
- }
-
- if (pid == 0) {
- /* Restore default handlers */
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGUSR1, &sa, NULL);
- sigaction(SIGWINCH, &sa, NULL);
- sigprocmask(SIG_SETMASK, &old, NULL);
-
- rc_in_plugin = true;
- close(pfd[0]);
- rc_environ_fd = fdopen(pfd[1], "w");
- retval = plugin->hook(hook, value);
- fclose(rc_environ_fd);
- rc_environ_fd = NULL;
-
- /* Just in case the plugin sets this to false */
- rc_in_plugin = true;
- exit(retval);
- }
-
- sigprocmask(SIG_SETMASK, &old, NULL);
- close(pfd[1]);
- buffer = xmalloc(sizeof(char) * BUFSIZ);
- memset(buffer, 0, BUFSIZ);
-
- while ((nr = read(pfd[0], buffer, BUFSIZ)) > 0) {
- p = buffer;
- while (*p && p - buffer < nr) {
- token = strsep(&p, "=");
- if (token) {
- unsetenv(token);
- if (*p) {
- setenv(token, p, 1);
- p += strlen(p) + 1;
- } else
- p++;
- }
- }
- }
-
- free(buffer);
- close(pfd[0]);
-
- rc_waitpid(pid);
- }
-}
-
-void
-rc_plugin_unload(void)
-{
- PLUGIN *plugin = TAILQ_FIRST(&plugins);
- PLUGIN *next;
-
- while (plugin) {
- next = TAILQ_NEXT(plugin, entries);
- dlclose(plugin->handle);
- free(plugin->name);
- free(plugin);
- plugin = next;
- }
- TAILQ_INIT(&plugins);
-}
diff --git a/src/rc/rc-plugin.h b/src/rc/rc-plugin.h
deleted file mode 100644
index 8422adec..00000000
--- a/src/rc/rc-plugin.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * rc-plugin.h
- * Private instructions to use plugins
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef __LIBRC_PLUGIN_H__
-#define __LIBRC_PLUGIN_H__
-
-/* A simple flag to say if we're in a plugin proccess or not.
- * Mainly used in atexit code. */
-extern bool rc_in_plugin;
-
-int rc_waitpid(pid_t pid);
-void rc_plugin_load(void);
-void rc_plugin_unload(void);
-void rc_plugin_run(RC_HOOK, const char *value);
-
-/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */
-#if !defined(__FreeBSD__) && !defined(__DragonFly__)
-struct __dlfunc_arg {
- int __dlfunc_dummy;
-};
-
-typedef void (*dlfunc_t)(struct __dlfunc_arg);
-
-dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol);
-#endif
-
-#endif
diff --git a/src/rc/rc-schedules.c b/src/rc/rc-schedules.c
deleted file mode 100644
index 5938086d..00000000
--- a/src/rc/rc-schedules.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * The functions in this file control the stopping of daemons by
- * start-stop-daemon and supervise-daemon.
- */
-
-/*
- * Copyright (c) 2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-/* nano seconds */
-#define POLL_INTERVAL 20000000
-#define WAIT_PIDFILE 500000000
-#define ONE_SECOND 1000000000
-#define ONE_MS 1000000
-
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-schedules.h"
-#include "helpers.h"
-
-typedef struct scheduleitem {
- enum {
- SC_TIMEOUT,
- SC_SIGNAL,
- SC_GOTO,
- SC_FOREVER,
- } type;
- int value;
- struct scheduleitem *gotoitem;
- TAILQ_ENTRY(scheduleitem) entries;
-} SCHEDULEITEM;
-
-static TAILQ_HEAD(, scheduleitem) schedule;
-
-void free_schedulelist(void)
-{
- SCHEDULEITEM *s1 = TAILQ_FIRST(&schedule);
- SCHEDULEITEM *s2;
-
- while (s1) {
- s2 = TAILQ_NEXT(s1, entries);
- free(s1);
- s1 = s2;
- }
- TAILQ_INIT(&schedule);
-}
-
-int parse_signal(const char *applet, const char *sig)
-{
- typedef struct signalpair
- {
- const char *name;
- int signal;
- } SIGNALPAIR;
-
-#define signalpair_item(name) { #name, SIG##name },
-
- static const SIGNALPAIR signallist[] = {
- signalpair_item(HUP)
- signalpair_item(INT)
- signalpair_item(QUIT)
- signalpair_item(ILL)
- signalpair_item(TRAP)
- signalpair_item(ABRT)
- signalpair_item(BUS)
- signalpair_item(FPE)
- signalpair_item(KILL)
- signalpair_item(USR1)
- signalpair_item(SEGV)
- signalpair_item(USR2)
- signalpair_item(PIPE)
- signalpair_item(ALRM)
- signalpair_item(TERM)
- signalpair_item(CHLD)
- signalpair_item(CONT)
- signalpair_item(STOP)
- signalpair_item(TSTP)
- signalpair_item(TTIN)
- signalpair_item(TTOU)
- signalpair_item(URG)
- signalpair_item(XCPU)
- signalpair_item(XFSZ)
- signalpair_item(VTALRM)
- signalpair_item(PROF)
-#ifdef SIGWINCH
- signalpair_item(WINCH)
-#endif
-#ifdef SIGIO
- signalpair_item(IO)
-#endif
-#ifdef SIGPWR
- signalpair_item(PWR)
-#endif
- signalpair_item(SYS)
- { "NULL", 0 },
- };
-
- unsigned int i = 0;
- const char *s;
-
- if (!sig || *sig == '\0')
- return -1;
-
- if (sscanf(sig, "%u", &i) == 1) {
- if (i < NSIG)
- return i;
- eerrorx("%s: `%s' is not a valid signal", applet, sig);
- }
-
- if (strncmp(sig, "SIG", 3) == 0)
- s = sig + 3;
- else
- s = NULL;
-
- for (i = 0; i < ARRAY_SIZE(signallist); ++i)
- if (strcmp(sig, signallist[i].name) == 0 ||
- (s && strcmp(s, signallist[i].name) == 0))
- return signallist[i].signal;
-
- eerrorx("%s: `%s' is not a valid signal", applet, sig);
- /* NOTREACHED */
-}
-
-static SCHEDULEITEM *parse_schedule_item(const char *applet, const char *string)
-{
- const char *after_hyph;
- int sig;
- SCHEDULEITEM *item = xmalloc(sizeof(*item));
-
- item->value = 0;
- item->gotoitem = NULL;
- if (strcmp(string,"forever") == 0)
- item->type = SC_FOREVER;
- else if (isdigit((unsigned char)string[0])) {
- item->type = SC_TIMEOUT;
- errno = 0;
- if (sscanf(string, "%d", &item->value) != 1)
- eerrorx("%s: invalid timeout value in schedule `%s'",
- applet, string);
- } else if ((after_hyph = string + (string[0] == '-')) &&
- ((sig = parse_signal(applet, after_hyph)) != -1))
- {
- item->type = SC_SIGNAL;
- item->value = (int)sig;
- } else
- eerrorx("%s: invalid schedule item `%s'", applet, string);
-
- return item;
-}
-
-void parse_schedule(const char *applet, const char *string, int timeout)
-{
- char buffer[20];
- const char *slash;
- int count = 0;
- SCHEDULEITEM *repeatat = NULL;
- size_t len;
- SCHEDULEITEM *item;
-
- TAILQ_INIT(&schedule);
- if (string)
- for (slash = string; *slash; slash++)
- if (*slash == '/')
- count++;
-
- free_schedulelist();
-
- if (count == 0) {
- item = xmalloc(sizeof(*item));
- item->type = SC_SIGNAL;
- item->value = timeout;
- item->gotoitem = NULL;
- TAILQ_INSERT_TAIL(&schedule, item, entries);
-
- item = xmalloc(sizeof(*item));
- item->type = SC_TIMEOUT;
- item->gotoitem = NULL;
- TAILQ_INSERT_TAIL(&schedule, item, entries);
- if (string) {
- if (sscanf(string, "%d", &item->value) != 1)
- eerrorx("%s: invalid timeout in schedule",
- applet);
- } else
- item->value = 5;
-
- return;
- }
-
- while (string != NULL) {
- if ((slash = strchr(string, '/')))
- len = slash - string;
- else
- len = strlen(string);
-
- if (len >= (ptrdiff_t)sizeof(buffer))
- eerrorx("%s: invalid schedule item, far too long",
- applet);
-
- memcpy(buffer, string, len);
- buffer[len] = 0;
- string = slash ? slash + 1 : NULL;
-
- item = parse_schedule_item(applet, buffer);
- TAILQ_INSERT_TAIL(&schedule, item, entries);
- if (item->type == SC_FOREVER) {
- if (repeatat)
- eerrorx("%s: invalid schedule, `forever' "
- "appears more than once", applet);
-
- repeatat = item;
- continue;
- }
- }
-
- if (repeatat) {
- item = xmalloc(sizeof(*item));
- item->type = SC_GOTO;
- item->value = 0;
- item->gotoitem = repeatat;
- TAILQ_INSERT_TAIL(&schedule, item, entries);
- }
-
- return;
-}
-
-/* return number of processes killed, -1 on error */
-int do_stop(const char *applet, const char *exec, const char *const *argv,
- pid_t pid, uid_t uid,int sig, bool test, bool quiet)
-{
- RC_PIDLIST *pids;
- RC_PID *pi;
- RC_PID *np;
- bool killed;
- int nkilled = 0;
-
- if (pid > 0)
- pids = rc_find_pids(NULL, NULL, 0, pid);
- else
- pids = rc_find_pids(exec, argv, uid, 0);
-
- if (!pids)
- return 0;
-
- LIST_FOREACH_SAFE(pi, pids, entries, np) {
- if (test) {
- einfo("Would send signal %d to PID %d", sig, pi->pid);
- nkilled++;
- } else {
- if (sig) {
- syslog(LOG_DEBUG, "Sending signal %d to PID %d", sig, pi->pid);
- if (!quiet)
- ebeginv("Sending signal %d to PID %d", sig, pi->pid);
- }
- errno = 0;
- killed = (kill(pi->pid, sig) == 0 ||
- errno == ESRCH ? true : false);
- if (!quiet)
- eendv(killed ? 0 : 1,
- "%s: failed to send signal %d to PID %d: %s",
- applet, sig, pi->pid, strerror(errno));
- else if (!killed)
- syslog(LOG_ERR, "Failed to send signal %d to PID %d: %s",
- sig, pi->pid, strerror(errno));
- if (!killed) {
- nkilled = -1;
- } else {
- if (nkilled != -1)
- nkilled++;
- }
- }
- free(pi);
- }
-
- free(pids);
- return nkilled;
-}
-
-int run_stop_schedule(const char *applet,
- const char *exec, const char *const *argv,
- pid_t pid, uid_t uid,
- bool test, bool progress, bool quiet)
-{
- SCHEDULEITEM *item = TAILQ_FIRST(&schedule);
- int nkilled = 0;
- int tkilled = 0;
- int nrunning = 0;
- long nloops, nsecs;
- struct timespec ts;
- const char *const *p;
- bool progressed = false;
-
- if (!(pid > 0 || exec || uid || (argv && *argv)))
- return 0;
-
- if (exec) {
- einfov("Will stop %s", exec);
- syslog(LOG_DEBUG, "Will stop %s", exec);
- }
- if (pid > 0) {
- einfov("Will stop PID %d", pid);
- syslog(LOG_DEBUG, "Will stop PID %d", pid);
- }
- if (uid) {
- einfov("Will stop processes owned by UID %d", uid);
- syslog(LOG_DEBUG, "Will stop processes owned by UID %d", uid);
- }
- if (argv && *argv) {
- einfovn("Will stop processes of `");
- if (rc_yesno(getenv("EINFO_VERBOSE"))) {
- for (p = argv; p && *p; p++) {
- if (p != argv)
- printf(" ");
- printf("%s", *p);
- }
- printf("'\n");
- }
- }
-
- while (item) {
- switch (item->type) {
- case SC_GOTO:
- item = item->gotoitem;
- continue;
-
- case SC_SIGNAL:
- nrunning = 0;
- nkilled = do_stop(applet, exec, argv, pid, uid, item->value, test,
- quiet);
- if (nkilled == 0) {
- if (tkilled == 0) {
- if (progressed)
- printf("\n");
- eerror("%s: no matching processes found", applet);
- }
- return tkilled;
- }
- else if (nkilled == -1)
- return 0;
-
- tkilled += nkilled;
- break;
- case SC_FOREVER:
- case SC_TIMEOUT:
- if (item->type == SC_TIMEOUT && item->value < 1) {
- item = NULL;
- break;
- }
-
- ts.tv_sec = 0;
- ts.tv_nsec = POLL_INTERVAL;
-
- for (nsecs = 0; item->type == SC_FOREVER || nsecs < item->value; nsecs++) {
- for (nloops = 0;
- nloops < ONE_SECOND / POLL_INTERVAL;
- nloops++)
- {
- if ((nrunning = do_stop(applet, exec, argv,
- pid, uid, 0, test, quiet)) == 0)
- return 0;
-
-
- if (nanosleep(&ts, NULL) == -1) {
- if (progressed) {
- printf("\n");
- progressed = false;
- }
- if (errno != EINTR) {
- eerror("%s: nanosleep: %s",
- applet, strerror(errno));
- return 0;
- }
- }
- }
- if (progress) {
- printf(".");
- fflush(stdout);
- progressed = true;
- }
- }
- break;
- default:
- if (progressed) {
- printf("\n");
- progressed = false;
- }
- eerror("%s: invalid schedule item `%d'",
- applet, item->type);
- return 0;
- }
-
- if (item)
- item = TAILQ_NEXT(item, entries);
- }
-
- if (test || (tkilled > 0 && nrunning == 0))
- return nkilled;
-
- if (progressed)
- printf("\n");
- if (!quiet) {
- if (nrunning == 1)
- eerror("%s: %d process refused to stop", applet, nrunning);
- else
- eerror("%s: %d process(es) refused to stop", applet, nrunning);
- }
-
- return -nrunning;
-}
diff --git a/src/rc/rc-schedules.h b/src/rc/rc-schedules.h
deleted file mode 100644
index 5fb9e526..00000000
--- a/src/rc/rc-schedules.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef __RC_SCHEDULES_H
-#define __RC_SCHEDULES_H
-
-void free_schedulelist(void);
-int parse_signal(const char *applet, const char *sig);
-void parse_schedule(const char *applet, const char *string, int timeout);
-int do_stop(const char *applet, const char *exec, const char *const *argv,
- pid_t pid, uid_t uid,int sig, bool test, bool quiet);
-int run_stop_schedule(const char *applet,
- const char *exec, const char *const *argv,
- pid_t pid, uid_t uid,
- bool test, bool progress, bool quiet);
-
-#endif
diff --git a/src/rc/rc-selinux.c b/src/rc/rc-selinux.c
deleted file mode 100644
index 8364a5f0..00000000
--- a/src/rc/rc-selinux.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * rc-selinux.c
- * SELinux helpers to get and set contexts.
- */
-
-/*
- * Copyright (c) 2014-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <stddef.h>
-#include <errno.h>
-#include <dlfcn.h>
-#include <ctype.h>
-#include <limits.h>
-#include <pwd.h>
-#include <unistd.h>
-
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#include <selinux/get_default_type.h>
-#include <selinux/context.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-#include "rc-selinux.h"
-
-/* the context files for selinux */
-#define INITRC_FILE "initrc_context"
-
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-/* PAM or shadow for authentication */
-#ifdef HAVE_PAM
-# define PAM_SERVICE_NAME "run_init" /* the name of this program for PAM */
-# include <security/pam_appl.h>
-# include <security/pam_misc.h>
-#else
-# define PASSWORD_PROMPT "Password:"
-# include <crypt.h>
-# include <shadow.h>
-# include <string.h>
-#endif
-
-
-/* The handle for the fcontext lookups */
-static struct selabel_handle *hnd = NULL;
-
-int selinux_util_label(const char *path)
-{
- int retval = 0;
- int enforce;
- struct stat st;
- char *con;
-
- enforce = security_getenforce();
- if (retval < 0)
- return retval;
-
- if (!hnd)
- return (enforce) ? -1 : 0;
-
- retval = lstat(path, &st);
- if (retval < 0) {
- if (errno == ENOENT)
- return 0;
- return (enforce) ? -1 : 0;
- }
-
- /* lookup the context */
- retval = selabel_lookup_raw(hnd, &con, path, st.st_mode);
- if (retval < 0) {
- if (errno == ENOENT)
- return 0;
- return (enforce) ? -1 : 0;
- }
-
- /* apply the context */
- retval = lsetfilecon(path, con);
- freecon(con);
- if (retval < 0) {
- if (errno == ENOENT)
- return 0;
- if (errno == ENOTSUP)
- return 0;
- return (enforce) ? -1 : 0;
- }
-
- return 0;
-}
-
-/*
- * Open the label handle
- * returns 1 on success, 0 if no selinux, negative on error
- */
-int selinux_util_open(void)
-{
- int retval = 0;
-
- retval = is_selinux_enabled();
- if (retval <= 0)
- return retval;
-
- hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
- if (!hnd)
- return -2;
-
- return 1;
-}
-
-/*
- * Close the label handle
- * returns 1 on success, 0 if no selinux, negative on error
- */
-int selinux_util_close(void)
-{
- int retval = 0;
-
- retval = is_selinux_enabled();
- if (retval <= 0)
- return retval;
-
- if (hnd) {
- selabel_close(hnd);
- hnd = NULL;
- }
-
- return 0;
-}
-
-/*
- * This will check the users password and return 0 on success or -1 on fail
- *
- * We ask for the password to make sure it is intended vs run by malicious software.
- * Actual authorization is covered by the policy itself.
- */
-static int check_password(char *username)
-{
- int ret = 1;
-#ifdef HAVE_PAM
- pam_handle_t *pamh;
- int pam_err = 0;
- const struct pam_conv pconv = {
- misc_conv,
- NULL
- };
-
- pam_err = pam_start(PAM_SERVICE_NAME, username, &pconv, &pamh);
- if (pam_err != PAM_SUCCESS) {
- ret = -1;
- goto outpam;
- }
-
- pam_err = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK);
- if (pam_err != PAM_SUCCESS) {
- ret = -1;
- goto outpam;
- }
-
- ret = 0;
-outpam:
- pam_end(pamh, pam_err);
- pamh = NULL;
-
-#else /* authenticating via /etc/shadow instead */
- struct spwd *spw;
- char *password;
- char *attempt;
-
- spw = getspnam(username);
- if (!spw) {
- eerror("Failed to read shadow entry");
- ret = -1;
- goto outshadow;
- }
-
- attempt = getpass(PASSWORD_PROMPT);
- if (!attempt) {
- ret = -1;
- goto outshadow;
- }
-
- if (*spw->sp_pwdp == '\0' && *attempt == '\0') {
- ret = -1;
- goto outshadow;
- }
-
- /* salt must be at least two characters long */
- if (!(spw->sp_pwdp[0] && spw->sp_pwdp[1])) {
- ret = -1;
- goto outshadow;
- }
-
- /* encrypt the password attempt */
- password = crypt(attempt, spw->sp_pwdp);
-
- if (password && strcmp(password, spw->sp_pwdp) == 0)
- ret = 0;
- else
- ret = -1;
-outshadow:
-#endif
- return ret;
-}
-
-/* Authenticates the user, returns 0 on success, 1 on fail */
-static int check_auth()
-{
- struct passwd *pw;
- uid_t uid;
-
-#ifdef HAVE_AUDIT
- uid = audit_getloginuid();
- if (uid == (uid_t) -1)
- uid = getuid();
-#else
- uid = getuid();
-#endif
-
- pw = getpwuid(uid);
- if (!pw) {
- eerror("cannot find your entry in the passwd file.");
- return (-1);
- }
-
- printf("Authenticating %s.\n", pw->pw_name);
-
- /* do the actual check */
- if (check_password(pw->pw_name) == 0) {
- return 0;
- }
-
- eerrorx("Authentication failed for %s", pw->pw_name);
- return 1;
-}
-
-/*
- * Read the context from the given context file. context must be free'd by the user.
- */
-static int read_context_file(const char *filename, char **context)
-{
- int ret = -1;
- FILE *fp;
- char *filepath = NULL;
- char *line = NULL;
- char *p;
- char *p2;
- size_t len = 0;
- ssize_t read;
-
- xasprintf(&filepath, "%s/%s", selinux_contexts_path(), filename);
-
- fp = fopen(filepath, "r");
- if (fp == NULL) {
- eerror("Failed to open context file: %s", filename);
- free(filepath);
- return -1;
- }
-
- while ((read = getline(&line, &len, fp)) != -1) {
- /* cut off spaces before the string */
- p = line;
- while (isspace(*p) && *p != '\0')
- p++;
-
- /* empty string, skip */
- if (*p == '\0')
- continue;
-
- /* cut off spaces after the string */
- p2 = p;
- while (!isspace(*p2) && *p2 != '\0')
- p2++;
- *p2 = '\0';
-
- *context = xstrdup(p);
- ret = 0;
- break;
- }
-
- free(line);
- free(filepath);
- fclose(fp);
- return ret;
-}
-
-static int read_run_init_context(char **context)
-{
- int ret = -1;
- RC_STRINGLIST *list;
- char *value = NULL;
-
- list = rc_config_list(selinux_openrc_contexts_path());
- if (list == NULL)
- return ret;
-
- value = rc_config_value(list, "run_init");
- if (value != NULL && strlen(value) > 0) {
- *context = xstrdup(value);
- ret = 0;
- }
-
- rc_stringlist_free(list);
- return ret;
-}
-
-void selinux_setup(char **argv)
-{
- char *new_context = NULL;
- char *curr_context = NULL;
- context_t curr_con;
- char *curr_t = NULL;
- char *run_init_t = NULL;
-
- /* Return, if selinux is disabled. */
- if (is_selinux_enabled() < 1) {
- return;
- }
-
- if (read_run_init_context(&run_init_t) != 0) {
- /* assume a reasonable default, rather than bailing out */
- run_init_t = xstrdup("run_init_t");
- ewarn("Assuming SELinux run_init type is %s", run_init_t);
- }
-
- /* Get our current context. */
- if (getcon(&curr_context) < 0) {
- if (errno == ENOENT) {
- /* should only hit this if proc is not mounted. this
- * happens on Gentoo right after init starts, when
- * the init script processing starts.
- */
- goto out;
- } else {
- perror("getcon");
- exit(1);
- }
- }
-
- /* extract the type from the context */
- curr_con = context_new(curr_context);
- if (!curr_con) {
- free(curr_context);
- goto out;
- }
-
- curr_t = xstrdup(context_type_get(curr_con));
- if (!curr_t) {
- context_free(curr_con);
- free(curr_context);
- goto out;
- }
-
- /* dont need them anymore so free() now */
- context_free(curr_con);
- free(curr_context);
-
- /* if we are not in the run_init domain, we should not do anything */
- if (strncmp(run_init_t, curr_t, strlen(run_init_t)) != 0) {
- goto out;
- }
-
- free(curr_t);
- free(run_init_t);
-
- if (check_auth() != 0) {
- eerrorx("Authentication failed.");
- }
-
- /* Get the context for the script to be run in. */
- if (read_context_file(INITRC_FILE, &new_context) != 0) {
- /* assume a reasonable default, rather than bailing out */
- new_context = xstrdup("system_u:system_r:initrc_t");
- ewarn("Assuming SELinux initrc context is %s", new_context);
- }
-
- /* Set the new context */
- if (setexeccon(new_context) < 0) {
- eerrorx("Could not set SELinux exec context to %s.", new_context);
- }
-
- free(new_context);
-
- /*
- * exec will recycle ptys so try and use open_init_pty if it exists
- * which will open the pty with initrc_devpts_t, if it doesnt exist,
- * fall back to plain exec
- */
- if (!access("/usr/sbin/open_init_pty", X_OK)) {
- if (execvp("/usr/sbin/open_init_pty", argv)) {
- perror("execvp");
- exit(-1);
- }
- } else if (execvp(argv[1], argv + 1)) {
- perror("execvp");
- exit(-1);
- }
-
-out:
- free(run_init_t);
- free(curr_t);
-}
diff --git a/src/rc/rc-selinux.h b/src/rc/rc-selinux.h
deleted file mode 100644
index 627c87bc..00000000
--- a/src/rc/rc-selinux.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef RC_SELINUX_UTIL_H
-#define RC_SELINUX_UTIL_H
-
-#ifdef HAVE_SELINUX
-
-int selinux_util_open(void);
-int selinux_util_label(const char *path);
-int selinux_util_close(void);
-
-void selinux_setup(char **argv);
-
-#else
-
-/* always return false for selinux_util_open() */
-#define selinux_util_open() (0)
-#define selinux_util_label(x) do { } while (0)
-#define selinux_util_close() do { } while (0)
-
-#define selinux_setup(x) do { } while (0)
-
-#endif
-
-
-#endif
diff --git a/src/rc/rc-service.c b/src/rc/rc-service.c
deleted file mode 100644
index 44651cc6..00000000
--- a/src/rc/rc-service.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * rc-service.c
- * Finds all OpenRC services
- */
-
-/*
- * Copyright (c) 2008-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "cdDe:ilr:INsSZ" getoptstring_COMMON;
-const struct option longopts[] = {
- { "debug", 0, NULL, 'd' },
- { "nodeps", 0, NULL, 'D' },
- { "exists", 1, NULL, 'e' },
- { "ifcrashed", 0, NULL, 'c' },
- { "ifexists", 0, NULL, 'i' },
- { "ifinactive", 0, NULL, 'I' },
- { "ifnotstarted", 0, NULL, 'N' },
- { "ifstarted", 0, NULL, 's' },
- { "ifstopped", 0, NULL, 'S' },
- { "list", 0, NULL, 'l' },
- { "resolve", 1, NULL, 'r' },
- { "dry-run", 0, NULL, 'Z' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "set xtrace when running the command",
- "ignore dependencies",
- "tests if the service exists or not",
- "if the service is crashed run the command",
- "if the service exists run the command",
- "if the service is inactive run the command",
- "if the service is not started run the command",
- "if the service is started run the command",
- "if the service is stopped run the command",
- "list all available services",
- "resolve the service name to an init script",
- "dry run (show what would happen)",
- longopts_help_COMMON
-};
-const char *usagestring = "" \
- "Usage: rc-service [options] [-i] <service> <cmd>...\n" \
- " or: rc-service [options] -e <service>\n" \
- " or: rc-service [options] -l\n" \
- " or: rc-service [options] -r <service>";
-
-int main(int argc, char **argv)
-{
- int opt;
- char *service;
- RC_STRINGLIST *list;
- RC_STRING *s;
- RC_SERVICE state;
- bool if_crashed = false;
- bool if_exists = false;
- bool if_inactive = false;
- bool if_notstarted = false;
- bool if_started = false;
- bool if_stopped = false;
-
- applet = basename_c(argv[0]);
- /* Ensure that we are only quiet when explicitly told to be */
- unsetenv("EINFO_QUIET");
-
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'd':
- setenv("RC_DEBUG", "yes", 1);
- break;
- case 'D':
- setenv("RC_NODEPS", "yes", 1);
- break;
- case 'e':
- service = rc_service_resolve(optarg);
- opt = service ? EXIT_SUCCESS : EXIT_FAILURE;
- free(service);
- return opt;
- /* NOTREACHED */
- case 'c':
- if_crashed = true;
- break;
- case 'i':
- if_exists = true;
- break;
- case 'I':
- if_inactive = true;
- break;
- case 'N':
- if_notstarted = true;
- break;
- case 'l':
- list = rc_services_in_runlevel(NULL);
- if (TAILQ_FIRST(list) == NULL)
- return EXIT_FAILURE;
- rc_stringlist_sort(&list);
- TAILQ_FOREACH(s, list, entries)
- printf("%s\n", s->value);
- rc_stringlist_free(list);
- return EXIT_SUCCESS;
- /* NOTREACHED */
- case 'r':
- service = rc_service_resolve(optarg);
- if (service == NULL)
- return EXIT_FAILURE;
- printf("%s\n", service);
- free(service);
- return EXIT_SUCCESS;
- /* NOTREACHED */
- case 's':
- if_started = true;
- break;
- case 'S':
- if_stopped = true;
- break;
- case 'Z':
- setenv("IN_DRYRUN", "yes", 1);
- break;
-
- case_RC_COMMON_GETOPT
- }
- }
-
- argc -= optind;
- argv += optind;
- if (*argv == NULL)
- eerrorx("%s: you need to specify a service", applet);
- if ((service = rc_service_resolve(*argv)) == NULL) {
- if (if_exists)
- return 0;
- eerrorx("%s: service `%s' does not exist", applet, *argv);
- }
- state = rc_service_state(*argv);
- if (if_crashed && !(rc_service_daemons_crashed(*argv) && errno != EACCES))
- return 0;
- if (if_inactive && !(state & RC_SERVICE_INACTIVE))
- return 0;
- if (if_notstarted && (state & RC_SERVICE_STARTED))
- return 0;
- if (if_started && !(state & RC_SERVICE_STARTED))
- return 0;
- if (if_stopped && !(state & RC_SERVICE_STOPPED))
- return 0;
- *argv = service;
- execv(*argv, argv);
- eerrorx("%s: %s", applet, strerror(errno));
- /* NOTREACHED */
-}
diff --git a/src/rc/rc-status.c b/src/rc/rc-status.c
deleted file mode 100644
index 7eb152ec..00000000
--- a/src/rc/rc-status.c
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * rc-status.c
- * Display the status of the services in runlevels
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-enum format_t {
- FORMAT_DEFAULT,
- FORMAT_INI,
-};
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "acf:lmrsSu" getoptstring_COMMON;
-const struct option longopts[] = {
- {"all", 0, NULL, 'a'},
- {"crashed", 0, NULL, 'c'},
- {"format", 1, NULL, 'f'},
- {"list", 0, NULL, 'l'},
- {"manual", 0, NULL, 'm'},
- {"runlevel", 0, NULL, 'r'},
- {"servicelist", 0, NULL, 's'},
- {"supervised", 0, NULL, 'S'},
- {"unused", 0, NULL, 'u'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Show services from all run levels",
- "Show crashed services",
- "format status to be parsable (currently arg must be ini)",
- "Show list of run levels",
- "Show manually started services",
- "Show the name of the current runlevel",
- "Show service list",
- "show supervised services",
- "Show services not assigned to any runlevel",
- longopts_help_COMMON
-};
-const char *usagestring = "" \
- "Usage: rc-status [options] -f ini <runlevel>...\n" \
- " or: rc-status [options] [-a | -c | -l | -m | -r | -s | -u]";
-
-static RC_DEPTREE *deptree;
-static RC_STRINGLIST *types;
-
-static RC_STRINGLIST *levels, *services, *tmp, *alist;
-static RC_STRINGLIST *sservices, *nservices, *needsme;
-
-static void print_level(const char *prefix, const char *level,
- enum format_t format)
-{
- switch (format) {
- case FORMAT_DEFAULT:
- if (prefix)
- printf("%s ", prefix);
- printf ("Runlevel: ");
- if (isatty(fileno(stdout)))
- printf("%s%s%s\n",
- ecolor(ECOLOR_HILITE), level, ecolor(ECOLOR_NORMAL));
- else
- printf("%s\n", level);
- break;
- case FORMAT_INI:
- printf("%s", "[");
- if (prefix)
- printf("%s ", prefix);
- printf("%s]\n", level);
- break;
- }
-}
-
-static char *get_uptime(const char *service)
-{
- RC_SERVICE state = rc_service_state(service);
- char *start_count;
- char *start_time_string;
- time_t start_time;
- int64_t diff_days;
- int64_t diff_hours;
- int64_t diff_mins;
- int64_t diff_secs;
- char *uptime = NULL;
-
- if (state & RC_SERVICE_STARTED) {
- start_count = rc_service_value_get(service, "start_count");
- start_time_string = rc_service_value_get(service, "start_time");
- if (start_count && start_time_string) {
- start_time = to_time_t(start_time_string);
- diff_secs = (int64_t) difftime(time(NULL), start_time);
- diff_days = diff_secs / 86400;
- diff_secs = diff_secs % 86400;
- diff_hours = diff_secs / 3600;
- diff_secs = diff_secs % 3600;
- diff_mins = diff_secs / 60;
- diff_secs = diff_secs % 60;
- if (diff_days > 0)
- xasprintf(&uptime,
- "%"PRId64" day(s) %02"PRId64":%02"PRId64":%02"PRId64" (%s)",
- diff_days, diff_hours, diff_mins, diff_secs,
- start_count);
- else
- xasprintf(&uptime,
- "%02"PRId64":%02"PRId64":%02"PRId64" (%s)",
- diff_hours, diff_mins, diff_secs, start_count);
- }
- }
- return uptime;
-}
-
-static void print_service(const char *service, enum format_t format)
-{
- char *status = NULL;
- char *uptime = NULL;
- char *child_pid = NULL;
- char *start_time = NULL;
- int cols;
- const char *c = ecolor(ECOLOR_GOOD);
- RC_SERVICE state = rc_service_state(service);
- ECOLOR color = ECOLOR_BAD;
-
- if (state & RC_SERVICE_STOPPING)
- xasprintf(&status, "stopping ");
- else if (state & RC_SERVICE_STARTING) {
- xasprintf(&status, "starting ");
- color = ECOLOR_WARN;
- } else if (state & RC_SERVICE_INACTIVE) {
- xasprintf(&status, "inactive ");
- color = ECOLOR_WARN;
- } else if (state & RC_SERVICE_STARTED) {
- errno = 0;
- if (rc_service_daemons_crashed(service) && errno != EACCES)
- {
- child_pid = rc_service_value_get(service, "child_pid");
- start_time = rc_service_value_get(service, "start_time");
- if (start_time && child_pid)
- xasprintf(&status, " unsupervised ");
- else
- xasprintf(&status, " crashed ");
- free(child_pid);
- free(start_time);
- } else {
- uptime = get_uptime(service);
- if (uptime) {
- xasprintf(&status, " started %s", uptime);
- free(uptime);
- } else
- xasprintf(&status, " started ");
- color = ECOLOR_GOOD;
- }
- } else if (state & RC_SERVICE_SCHEDULED) {
- xasprintf(&status, "scheduled");
- color = ECOLOR_WARN;
- } else if (state & RC_SERVICE_FAILED) {
- xasprintf(&status, "failed");
- color = ECOLOR_WARN;
- } else
- xasprintf(&status, " stopped ");
-
- errno = 0;
- switch (format) {
- case FORMAT_DEFAULT:
- cols = printf(" %s", service);
- if (c && *c && isatty(fileno(stdout)))
- printf("\n");
- ebracket(cols, color, status);
- break;
- case FORMAT_INI:
- printf("%s = %s\n", service, status);
- break;
- }
- free(status);
-}
-
-static void print_services(const char *runlevel, RC_STRINGLIST *svcs,
- enum format_t format)
-{
- RC_STRINGLIST *l = NULL;
- RC_STRING *s;
- char *r = NULL;
-
- if (!svcs)
- return;
- if (!deptree)
- deptree = _rc_deptree_load(0, NULL);
- if (!deptree) {
- TAILQ_FOREACH(s, svcs, entries)
- if (!runlevel ||
- rc_service_in_runlevel(s->value, runlevel))
- print_service(s->value, format);
- return;
- }
- if (!types) {
- types = rc_stringlist_new();
- rc_stringlist_add(types, "ineed");
- rc_stringlist_add(types, "iuse");
- rc_stringlist_add(types, "iafter");
- }
- if (!runlevel)
- r = rc_runlevel_get();
- l = rc_deptree_depends(deptree, types, svcs, r ? r : runlevel,
- RC_DEP_STRICT | RC_DEP_TRACE | RC_DEP_START);
- free(r);
- if (!l)
- return;
- TAILQ_FOREACH(s, l, entries) {
- if (!rc_stringlist_find(svcs, s->value))
- continue;
- if (!runlevel || rc_service_in_runlevel(s->value, runlevel))
- print_service(s->value, format);
- }
- rc_stringlist_free(l);
-}
-
-static void print_stacked_services(const char *runlevel, enum format_t format)
-{
- RC_STRINGLIST *stackedlevels, *servicelist;
- RC_STRING *stackedlevel;
-
- stackedlevels = rc_runlevel_stacks(runlevel);
- TAILQ_FOREACH(stackedlevel, stackedlevels, entries) {
- if (rc_stringlist_find(levels, stackedlevel->value) != NULL)
- continue;
- print_level("Stacked", stackedlevel->value, format);
- servicelist = rc_services_in_runlevel(stackedlevel->value);
- print_services(stackedlevel->value, servicelist, format);
- rc_stringlist_free(servicelist);
- }
- rc_stringlist_free(stackedlevels);
- stackedlevels = NULL;
-}
-
-int main(int argc, char **argv)
-{
- RC_SERVICE state;
- RC_STRING *s, *l, *t, *level;
- enum format_t format = FORMAT_DEFAULT;
- bool levels_given = false;
- bool show_all = false;
- char *p, *runlevel = NULL;
- int opt, retval = 0;
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring, longopts,
- (int *) 0)) != -1)
- switch (opt) {
- case 'a':
- show_all = true;
- levels = rc_runlevel_list();
- break;
- case 'c':
- services = rc_services_in_state(RC_SERVICE_STARTED);
- retval = 1;
- TAILQ_FOREACH(s, services, entries)
- if (rc_service_daemons_crashed(s->value)) {
- printf("%s\n", s->value);
- retval = 0;
- }
- goto exit;
- /* NOTREACHED */
- case 'f':
- if (strcasecmp(optarg, "ini") == 0) {
- format = FORMAT_INI;
- setenv("EINFO_QUIET", "YES", 1);
- } else
- eerrorx("%s: invalid argument to --format switch\n", applet);
- break;
- case 'l':
- levels = rc_runlevel_list();
- TAILQ_FOREACH(l, levels, entries)
- printf("%s\n", l->value);
- goto exit;
- case 'm':
- services = rc_services_in_runlevel(NULL);
- levels = rc_runlevel_list();
- TAILQ_FOREACH_SAFE(s, services, entries, t) {
- TAILQ_FOREACH(l, levels, entries)
- if (rc_service_in_runlevel(s->value, l->value)) {
- TAILQ_REMOVE(services, s, entries);
- free(s->value);
- free(s);
- break;
- }
- }
- TAILQ_FOREACH_SAFE(s, services, entries, t)
- if (rc_service_state(s->value) &
- (RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)) {
- TAILQ_REMOVE(services, s, entries);
- free(s->value);
- free(s);
- }
- print_services(NULL, services, FORMAT_DEFAULT);
- goto exit;
- case 'r':
- runlevel = rc_runlevel_get();
- printf("%s\n", runlevel);
- goto exit;
- /* NOTREACHED */
- case 'S':
- services = rc_services_in_state(RC_SERVICE_STARTED);
- TAILQ_FOREACH_SAFE(s, services, entries, t)
- if (!rc_service_value_get(s->value, "child_pid"))
- TAILQ_REMOVE(services, s, entries);
- print_services(NULL, services, FORMAT_DEFAULT);
- goto exit;
- /* NOTREACHED */
- case 's':
- services = rc_services_in_runlevel(NULL);
- print_services(NULL, services, FORMAT_DEFAULT);
- goto exit;
- /* NOTREACHED */
- case 'u':
- services = rc_services_in_runlevel(NULL);
- levels = rc_runlevel_list();
- TAILQ_FOREACH_SAFE(s, services, entries, t) {
- TAILQ_FOREACH(l, levels, entries)
- if (rc_service_in_runlevel(s->value, l->value)) {
- TAILQ_REMOVE(services, s, entries);
- free(s->value);
- free(s);
- break;
- }
- }
- print_services(NULL, services, FORMAT_DEFAULT);
- goto exit;
- /* NOTREACHED */
-
- case_RC_COMMON_GETOPT
- }
-
- if (!levels)
- levels = rc_stringlist_new();
- opt = (optind < argc) ? 0 : 1;
- while (optind < argc) {
- if (rc_runlevel_exists(argv[optind])) {
- levels_given = true;
- rc_stringlist_add(levels, argv[optind++]);
- opt++;
- } else
- eerror("runlevel `%s' does not exist", argv[optind++]);
- }
- if (opt == 0)
- exit(EXIT_FAILURE);
- if (!TAILQ_FIRST(levels)) {
- runlevel = rc_runlevel_get();
- rc_stringlist_add(levels, runlevel);
- }
-
- /* Output the services in the order in which they would start */
- deptree = _rc_deptree_load(0, NULL);
-
- TAILQ_FOREACH(l, levels, entries) {
- print_level(NULL, l->value, format);
- services = rc_services_in_runlevel(l->value);
- print_services(l->value, services, format);
- print_stacked_services(l->value, format);
- rc_stringlist_free(nservices);
- nservices = NULL;
- rc_stringlist_free(services);
- services = NULL;
- }
-
- if (show_all || !levels_given) {
- /* Show hotplugged services */
- print_level("Dynamic", "hotplugged", format);
- services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);
- print_services(NULL, services, format);
- rc_stringlist_free(services);
- services = NULL;
-
- /* Show manually started and unassigned depended services */
- if (show_all) {
- rc_stringlist_free(levels);
- levels = rc_stringlist_new();
- if (!runlevel)
- runlevel = rc_runlevel_get();
- rc_stringlist_add(levels, runlevel);
- }
- rc_stringlist_add(levels, RC_LEVEL_SYSINIT);
- rc_stringlist_add(levels, RC_LEVEL_BOOT);
- services = rc_services_in_runlevel(NULL);
- sservices = rc_stringlist_new();
- TAILQ_FOREACH(l, levels, entries) {
- nservices = rc_services_in_runlevel_stacked(l->value);
- TAILQ_CONCAT(sservices, nservices, entries);
- free(nservices);
- }
- TAILQ_FOREACH_SAFE(s, services, entries, t) {
- state = rc_service_state(s->value);
- if ((rc_stringlist_find(sservices, s->value) ||
- (state & ( RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)))) {
- if (!(state & RC_SERVICE_FAILED)) {
- TAILQ_REMOVE(services, s, entries);
- free(s->value);
- free(s);
- }
- }
- }
- needsme = rc_stringlist_new();
- rc_stringlist_add(needsme, "needsme");
- rc_stringlist_add(needsme, "wantsme");
- nservices = rc_stringlist_new();
- alist = rc_stringlist_new();
- l = rc_stringlist_add(alist, "");
- p = l->value;
- TAILQ_FOREACH(level, levels, entries) {
- TAILQ_FOREACH_SAFE(s, services, entries, t) {
- l->value = s->value;
- setenv("RC_SVCNAME", l->value, 1);
- tmp = rc_deptree_depends(deptree, needsme, alist, level->value, RC_DEP_TRACE);
- if (TAILQ_FIRST(tmp)) {
- TAILQ_REMOVE(services, s, entries);
- TAILQ_INSERT_TAIL(nservices, s, entries);
- }
- rc_stringlist_free(tmp);
- }
- }
- l->value = p;
- /*
- * we are unsetting RC_SVCNAME because last loaded service will not
- * be added to the list
- */
- unsetenv("RC_SVCNAME");
- print_level("Dynamic", "needed/wanted", format);
- print_services(NULL, nservices, format);
- print_level("Dynamic", "manual", format);
- print_services(NULL, services, format);
- }
-
-exit:
- free(runlevel);
- rc_stringlist_free(alist);
- rc_stringlist_free(needsme);
- rc_stringlist_free(sservices);
- rc_stringlist_free(nservices);
- rc_stringlist_free(services);
- rc_stringlist_free(types);
- rc_stringlist_free(levels);
- rc_deptree_free(deptree);
-
- return retval;
-}
diff --git a/src/rc/rc-sysvinit.c b/src/rc/rc-sysvinit.c
deleted file mode 100644
index 8d258b63..00000000
--- a/src/rc/rc-sysvinit.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * rc-sysvinit.c
- * Helper to send a runlevel change to sysvinit
- */
-
-/*
- * Copyright (c) 2019 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "einfo.h"
-#include "rc-sysvinit.h"
-
-static void sysvinit_send_cmd(struct init_request *request)
-{
- int fd;
- char *p;
- size_t bytes;
- ssize_t r;
-
- fd = open("/run/initctl", O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- if (errno != ENOENT)
- eerror("Failed to open initctl fifo: %s", strerror(errno));
- return;
- }
- p = (char *) request;
- bytes = sizeof(*request);
- do {
- r = write(fd, p, bytes);
- if (r < 0) {
- if ((errno == EAGAIN) || (errno == EINTR))
- continue;
- eerror("Failed to write to /run/initctl: %s", strerror(errno));
- return;
- }
- p += r;
- bytes -= r;
- } while (bytes > 0);
-}
-
-void sysvinit_runlevel(char rl)
-{
- struct init_request request;
-
- if (!rl)
- return;
-
- request = (struct init_request) {
- .magic = INIT_MAGIC,
- .sleeptime = 0,
- .cmd = INIT_CMD_RUNLVL,
- .runlevel = rl,
- };
- sysvinit_send_cmd(&request);
- return;
-}
-
-/*
- * Set environment variables in the init process.
- */
-void sysvinit_setenv(const char *name, const char *value)
-{
- struct init_request request;
- size_t nl;
- size_t vl;
-
- memset(&request, 0, sizeof(request));
- request.magic = INIT_MAGIC;
- request.cmd = INIT_CMD_SETENV;
- nl = strlen(name);
- if (value)
- vl = strlen(value);
-else
- vl = 0;
-
- if (nl + vl + 3 >= (int)sizeof(request.i.data))
- return;
-
- memcpy(request.i.data, name, nl);
- if (value) {
- request.i.data[nl] = '=';
- memcpy(request.i.data + nl + 1, value, vl);
- }
- sysvinit_send_cmd(&request);
- return;
-}
diff --git a/src/rc/rc-sysvinit.h b/src/rc/rc-sysvinit.h
deleted file mode 100644
index 6142cdd6..00000000
--- a/src/rc/rc-sysvinit.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * rc-sysvinit.h - Interface to communicate with sysvinit via /run/initctl.
- */
-
-/*
- * Copyright (c) 2019 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#ifndef _RC_SYSVINIT_H
-#define _RC_SYSVINIT_H
-
-/*
- * The #defines and structures below are taken from initreq.h in
- * sysvinit and must be used by any program wishing to communicate with
- * it.
- */
-
-#define INIT_MAGIC 0x03091969
-#define INIT_CMD_START 0
-#define INIT_CMD_RUNLVL 1
-#define INIT_CMD_POWERFAIL 2
-#define INIT_CMD_POWERFAILNOW 3
-#define INIT_CMD_POWEROK 4
-#define INIT_CMD_BSD 5
-#define INIT_CMD_SETENV 6
-#define INIT_CMD_UNSETENV 7
-
-/*
- * This is what BSD 4.4 uses when talking to init.
- * Linux doesn't use this right now.
- */
-struct init_request_bsd {
- char gen_id[8]; /* Beats me.. telnetd uses "fe" */
- char tty_id[16]; /* Tty name minus /dev/tty */
- char host[64]; /* Hostname */
- char term_type[16]; /* Terminal type */
- int signal; /* Signal to send */
- int pid; /* Process to send to */
- char exec_name[128]; /* Program to execute */
- char reserved[128]; /* For future expansion. */
-};
-
-/*
- * Because of legacy interfaces, "runlevel" and "sleeptime"
- * aren't in a seperate struct in the union.
- *
- * The weird sizes are because init expects the whole
- * struct to be 384 bytes.
- */
-struct init_request {
- int magic; /* Magic number */
- int cmd; /* What kind of request */
- int runlevel; /* Runlevel to change to */
- int sleeptime; /* Time between TERM and KILL */
- union {
- struct init_request_bsd bsd;
- char data[368];
- } i;
-};
-
-void sysvinit_runlevel(char rl);
-void sysvinit_setenv(const char *name, const char *value);
-
-#endif
diff --git a/src/rc/rc-update.c b/src/rc/rc-update.c
deleted file mode 100644
index d6dbf240..00000000
--- a/src/rc/rc-update.c
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * rc-update
- * Manage init scripts and runlevels
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char *usagestring = "" \
- "Usage: rc-update [options] add <service> [<runlevel>...]\n" \
- " or: rc-update [options] del <service> [<runlevel>...]\n" \
- " or: rc-update [options] [show [<runlevel>...]]";
-const char getoptstring[] = "asu" getoptstring_COMMON;
-const struct option longopts[] = {
- { "all", 0, NULL, 'a' },
- { "stack", 0, NULL, 's' },
- { "update", 0, NULL, 'u' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Process all runlevels",
- "Stack a runlevel instead of a service",
- "Force an update of the dependency tree",
- longopts_help_COMMON
-};
-
-/* Return the number of changes made:
- * -1 = no changes (error)
- * 0 = no changes (nothing to do)
- * 1+ = number of runlevels updated
- */
-static int
-add(const char *runlevel, const char *service)
-{
- int retval = -1;
-
- if (!rc_service_exists(service)) {
- if (errno == ENOEXEC)
- eerror("%s: service `%s' is not executable",
- applet, service);
- else
- eerror("%s: service `%s' does not exist",
- applet, service);
- } else if (rc_service_in_runlevel(service, runlevel)) {
- einfo("%s: %s already installed in runlevel `%s'; skipping",
- applet, service, runlevel);
- retval = 0;
- } else if (rc_service_add(runlevel, service)) {
- einfo("service %s added to runlevel %s", service, runlevel);
- retval = 1;
- } else
- eerror("%s: failed to add service `%s' to runlevel `%s': %s",
- applet, service, runlevel, strerror (errno));
-
- return retval;
-}
-
-static int
-delete(const char *runlevel, const char *service)
-{
- int retval = -1;
-
- errno = 0;
- if (rc_service_delete(runlevel, service)) {
- einfo("service %s removed from runlevel %s",
- service, runlevel);
- return 1;
- }
-
- if (errno == ENOENT)
- eerror("%s: service `%s' is not in the runlevel `%s'",
- applet, service, runlevel);
- else
- eerror("%s: failed to remove service `%s' from runlevel `%s': %s",
- applet, service, runlevel, strerror (errno));
-
- return retval;
-}
-
-static int
-addstack(const char *runlevel, const char *stack)
-{
- if (!rc_runlevel_exists(runlevel)) {
- eerror("%s: runlevel `%s' does not exist", applet, runlevel);
- return -1;
- }
- if (!rc_runlevel_exists(stack)) {
- eerror("%s: runlevel `%s' does not exist", applet, stack);
- return -1;
- }
- if (strcmp(runlevel, stack) == 0) {
- eerror("%s: cannot stack `%s' onto itself", applet, stack);
- return -1;
- }
- if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
- strcmp(stack, RC_LEVEL_SYSINIT) == 0 ||
- strcmp(runlevel, RC_LEVEL_BOOT) == 0 ||
- strcmp(stack, RC_LEVEL_BOOT) == 0 ||
- strcmp(runlevel, RC_LEVEL_SINGLE) == 0 ||
- strcmp(stack, RC_LEVEL_SINGLE) == 0 ||
- strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
- strcmp(stack, RC_LEVEL_SHUTDOWN) == 0)
- {
- eerror("%s: cannot stack the %s runlevel",
- applet, RC_LEVEL_SYSINIT);
- return -1;
- }
- if (!rc_runlevel_stack(runlevel, stack)) {
- eerror("%s: failed to stack `%s' to `%s': %s",
- applet, stack, runlevel, strerror(errno));
- return -1;
- }
- einfo("runlevel %s added to runlevel %s", stack, runlevel);
- return 1;
-}
-
-static int
-delstack(const char *runlevel, const char *stack)
-{
- if (rc_runlevel_unstack(runlevel, stack)) {
- einfo("runlevel %s removed from runlevel %s", stack, runlevel);
- return 1;
- }
-
- if (errno == ENOENT)
- eerror("%s: runlevel `%s' is not in the runlevel `%s'",
- applet, stack, runlevel);
- else
- eerror("%s: failed to remove runlevel `%s' from runlevel `%s': %s",
- applet, stack, runlevel, strerror (errno));
-
- return -1;
-}
-
-static void
-show(RC_STRINGLIST *runlevels, bool verbose)
-{
- RC_STRINGLIST *services = rc_services_in_runlevel(NULL);
- RC_STRING *service;
- RC_STRING *runlevel;
- RC_STRINGLIST *in;
- bool inone;
- char *buffer = NULL;
- size_t l;
-
- rc_stringlist_sort(&services);
- TAILQ_FOREACH(service, services, entries) {
- in = rc_stringlist_new();
- inone = false;
-
- TAILQ_FOREACH(runlevel, runlevels, entries) {
- if (rc_service_in_runlevel(service->value,
- runlevel->value))
- {
- rc_stringlist_add(in, runlevel->value);
- inone = true;
- } else {
- l = strlen(runlevel->value);
- buffer = xmalloc(l+1);
- memset (buffer, ' ', l);
- buffer[l] = 0;
- rc_stringlist_add (in, buffer);
- free(buffer);
- }
- }
-
- if (inone || verbose) {
- printf(" %20s |", service->value);
- TAILQ_FOREACH(runlevel, in, entries)
- printf (" %s", runlevel->value);
- printf ("\n");
- }
- rc_stringlist_free(in);
- }
-
- rc_stringlist_free (services);
-}
-
-#define DOADD (1 << 1)
-#define DODELETE (1 << 2)
-#define DOSHOW (1 << 3)
-
-int main(int argc, char **argv)
-{
- RC_DEPTREE *deptree;
- RC_STRINGLIST *runlevels;
- RC_STRING *runlevel;
- char *service = NULL;
- char *p;
- int action = 0;
- bool verbose = false, stack = false, all_runlevels = false;
- int opt;
- int retval = EXIT_FAILURE;
- int num_updated = 0;
- int (*actfunc)(const char *, const char *);
- int ret;
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *)0)) != -1)
- switch (opt) {
- case 'a':
- all_runlevels = true;
- break;
- case 's':
- stack = true;
- break;
- case 'u':
- deptree = _rc_deptree_load(-1, &ret);
- if (deptree)
- rc_deptree_free(deptree);
- return ret;
- case_RC_COMMON_GETOPT
- }
-
- verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
-
- if ((action & DOSHOW && action != DOSHOW) ||
- (action & DOADD && action != DOADD) ||
- (action & DODELETE && action != DODELETE))
- eerrorx("%s: cannot mix commands", applet);
-
- /* We need to be backwards compatible */
- if (optind < argc) {
- if (strcmp(argv[optind], "add") == 0)
- action = DOADD;
- else if (strcmp(argv[optind], "delete") == 0 ||
- strcmp(argv[optind], "del") == 0)
- action = DODELETE;
- else if (strcmp(argv[optind], "show") == 0)
- action = DOSHOW;
- if (action)
- optind++;
- else
- eerrorx("%s: invalid command `%s'",
- applet, argv[optind]);
- }
- if (!action)
- action = DOSHOW;
-
- runlevels = rc_stringlist_new();
-
- if (optind >= argc) {
- if (!(action & DOSHOW))
- eerrorx("%s: no service specified", applet);
- } else {
- service = argv[optind];
- optind++;
-
- while (optind < argc)
- if (rc_runlevel_exists(argv[optind]))
- rc_stringlist_add(runlevels, argv[optind++]);
- else {
- rc_stringlist_free(runlevels);
- eerrorx ("%s: `%s' is not a valid runlevel",
- applet, argv[optind]);
- }
- }
-
- retval = EXIT_SUCCESS;
- if (action & DOSHOW) {
- if (service)
- rc_stringlist_add(runlevels, service);
- if (!TAILQ_FIRST(runlevels)) {
- free(runlevels);
- runlevels = rc_runlevel_list();
- }
-
- rc_stringlist_sort(&runlevels);
- show (runlevels, verbose);
- } else {
- if (!service)
- eerror ("%s: no service specified", applet);
- else {
- if (action & DOADD) {
- if (all_runlevels) {
- rc_stringlist_free(runlevels);
- eerrorx("%s: the -a option is invalid with add", applet);
- }
- actfunc = stack ? addstack : add;
- } else if (action & DODELETE) {
- actfunc = stack ? delstack : delete;
- } else {
- rc_stringlist_free(runlevels);
- eerrorx("%s: invalid action", applet);
- }
-
- if (!TAILQ_FIRST(runlevels)) {
- if (all_runlevels) {
- free(runlevels);
- runlevels = rc_runlevel_list();
- } else {
- p = rc_runlevel_get();
- rc_stringlist_add(runlevels, p);
- free(p);
- }
- }
-
- if (!TAILQ_FIRST(runlevels)) {
- free(runlevels);
- eerrorx("%s: no runlevels found", applet);
- }
-
- TAILQ_FOREACH(runlevel, runlevels, entries) {
- if (!rc_runlevel_exists(runlevel->value)) {
- eerror ("%s: runlevel `%s' does not exist",
- applet, runlevel->value);
- continue;
- }
-
- ret = actfunc(runlevel->value, service);
- if (ret < 0)
- retval = EXIT_FAILURE;
- num_updated += ret;
- }
-
- if (retval == EXIT_SUCCESS &&
- num_updated == 0 && action & DODELETE)
- ewarnx("%s: service `%s' not found in any"
- " of the specified runlevels",
- applet, service);
- }
- }
-
- rc_stringlist_free(runlevels);
- return retval;
-}
diff --git a/src/rc/rc-wtmp.c b/src/rc/rc-wtmp.c
deleted file mode 100644
index 42e228d0..00000000
--- a/src/rc/rc-wtmp.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * rc-wtmp.c
- * This file contains routines to deal with the wtmp file.
- */
-
-/*
- * Copyright 2017 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-
-#include "rc-wtmp.h"
-
-void log_wtmp(const char *user, const char *id, pid_t pid, int type,
- const char *line)
-{
- struct timeval tv;
- struct utmp utmp;
- struct utsname uname_buf;
-
- memset(&utmp, 0, sizeof(utmp));
- gettimeofday(&tv, NULL);
- utmp.ut_tv.tv_sec = tv.tv_sec;
- utmp.ut_tv.tv_usec = tv.tv_usec;
- utmp.ut_pid = pid;
- utmp.ut_type = type;
- strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
- strncpy(utmp.ut_id , id , sizeof(utmp.ut_id ));
- strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
-
- /* Put the OS version in place of the hostname */
- if (uname(&uname_buf) == 0)
- strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host));
-
- updwtmp(WTMP_FILE, &utmp);
-}
diff --git a/src/rc/rc.c b/src/rc/rc.c
deleted file mode 100644
index 53c75bb6..00000000
--- a/src/rc/rc.c
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- * rc.c
- * rc - manager for init scripts which control the startup, shutdown
- * and the running of daemons.
- *
- * Also a multicall binary for various commands that can be used in shell
- * scripts to query service state, mark service state and provide the
- * einfo family of informational functions.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <libgen.h>
-#include <limits.h>
-#include <pwd.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <strings.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-logger.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-
-#include "version.h"
-#include "_usage.h"
-
-const char *extraopts = NULL;
-const char getoptstring[] = "a:no:s:S" getoptstring_COMMON;
-const struct option longopts[] = {
- { "no-stop", 0, NULL, 'n' },
- { "override", 1, NULL, 'o' },
- { "service", 1, NULL, 's' },
- { "sys", 0, NULL, 'S' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "do not stop any services",
- "override the next runlevel to change into\n",
- "when leaving single user or boot runlevels",
- "runs the service specified with the rest\nof the arguments",
- "output the RC system type, if any",
- longopts_help_COMMON
-};
-const char *usagestring = "" \
- "Usage: openrc [options] [<runlevel>]";
-
-#define INITSH RC_LIBEXECDIR "/sh/init.sh"
-#define INITEARLYSH RC_LIBEXECDIR "/sh/init-early.sh"
-
-#define INTERACTIVE RC_SVCDIR "/interactive"
-
-#define DEVBOOT "/dev/.rcboot"
-
-const char *applet = NULL;
-static RC_STRINGLIST *main_hotplugged_services;
-static RC_STRINGLIST *main_stop_services;
-static RC_STRINGLIST *main_start_services;
-static RC_STRINGLIST *main_types_nw;
-static RC_STRINGLIST *main_types_nwua;
-static RC_DEPTREE *main_deptree;
-static char *runlevel;
-static RC_HOOK hook_out;
-
-struct termios *termios_orig = NULL;
-
-RC_PIDLIST service_pids;
-
-static void
-clean_failed(void)
-{
- DIR *dp;
- struct dirent *d;
- char *path;
-
- /* Clean the failed services state dir now */
- if ((dp = opendir(RC_SVCDIR "/failed"))) {
- while ((d = readdir(dp))) {
- if (d->d_name[0] == '.' &&
- (d->d_name[1] == '\0' ||
- (d->d_name[1] == '.' && d->d_name[2] == '\0')))
- continue;
-
- xasprintf(&path, RC_SVCDIR "/failed/%s", d->d_name);
- if (unlink(path))
- eerror("%s: unlink `%s': %s",
- applet, path, strerror(errno));
- free(path);
- }
- closedir(dp);
- }
-}
-
-static void
-cleanup(void)
-{
- RC_PID *p1 = LIST_FIRST(&service_pids);
- RC_PID *p2;
-
- if (!rc_in_logger && !rc_in_plugin &&
- applet && (strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0))
- {
- if (hook_out)
- rc_plugin_run(hook_out, runlevel);
-
- rc_plugin_unload();
-
- if (termios_orig) {
- tcsetattr(STDIN_FILENO, TCSANOW, termios_orig);
- free(termios_orig);
- }
-
- /* Clean runlevel start, stop markers */
- rmdir(RC_STARTING);
- rmdir(RC_STOPPING);
- clean_failed();
- rc_logger_close();
- }
-
- while (p1) {
- p2 = LIST_NEXT(p1, entries);
- free(p1);
- p1 = p2;
- }
-
- rc_stringlist_free(main_hotplugged_services);
- rc_stringlist_free(main_stop_services);
- rc_stringlist_free(main_start_services);
- rc_stringlist_free(main_types_nw);
- rc_stringlist_free(main_types_nwua);
- rc_deptree_free(main_deptree);
- free(runlevel);
-}
-
-static char
-read_key(bool block)
-{
- struct termios termios;
- char c = 0;
- int fd = STDIN_FILENO;
-
- if (!isatty(fd))
- return false;
-
- /* Now save our terminal settings. We need to restore them at exit as
- we will be changing it for non-blocking reads for Interactive */
- if (!termios_orig) {
- termios_orig = xmalloc(sizeof(*termios_orig));
- tcgetattr(fd, termios_orig);
- }
-
- tcgetattr(fd, &termios);
- termios.c_lflag &= ~(ICANON | ECHO);
- if (block)
- termios.c_cc[VMIN] = 1;
- else {
- termios.c_cc[VMIN] = 0;
- termios.c_cc[VTIME] = 0;
- }
- tcsetattr(fd, TCSANOW, &termios);
- if (read(fd, &c, 1) == -1)
- eerror("read: %s", strerror(errno));
- tcsetattr(fd, TCSANOW, termios_orig);
- return c;
-}
-
-static bool
-want_interactive(void)
-{
- char c;
- static bool gotinteractive;
- static bool interactive;
-
- if (rc_yesno(getenv("EINFO_QUIET")))
- return false;
- if (!gotinteractive) {
- gotinteractive = true;
- interactive = rc_conf_yesno("rc_interactive");
- }
- if (!interactive)
- return false;
- c = read_key(false);
- return (c == 'I' || c == 'i') ? true : false;
-}
-
-static void
-mark_interactive(void)
-{
- FILE *fp = fopen(INTERACTIVE, "w");
- if (fp)
- fclose(fp);
-}
-
-static void
-run_program(const char *prog)
-{
- struct sigaction sa;
- sigset_t full;
- sigset_t old;
- pid_t pid;
-
- /* We need to block signals until we have forked */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigemptyset(&sa.sa_mask);
- sigfillset(&full);
- sigprocmask(SIG_SETMASK, &full, &old);
- pid = fork();
-
- if (pid == -1)
- eerrorx("%s: fork: %s", applet, strerror(errno));
- if (pid == 0) {
- /* Restore default handlers */
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGUSR1, &sa, NULL);
- sigaction(SIGWINCH, &sa, NULL);
-
- /* Unmask signals */
- sigprocmask(SIG_SETMASK, &old, NULL);
-
- if (termios_orig)
- tcsetattr(STDIN_FILENO, TCSANOW, termios_orig);
-
- execl(prog, prog, (char *)NULL);
- eerror("%s: unable to exec `%s': %s", applet, prog,
- strerror(errno));
- _exit(EXIT_FAILURE);
- }
-
- /* Unmask signals and wait for child */
- sigprocmask(SIG_SETMASK, &old, NULL);
- if (rc_waitpid(pid) == -1)
- eerrorx("%s: failed to exec `%s'", applet, prog);
-}
-
-static void
-open_shell(void)
-{
- const char *shell;
- struct passwd *pw;
-
-#ifdef __linux__
- const char *sys = rc_sys();
-
- /* VSERVER systems cannot really drop to shells */
- if (sys && strcmp(sys, RC_SYS_VSERVER) == 0)
- {
- execlp("halt", "halt", "-f", (char *) NULL);
- eerrorx("%s: unable to exec `halt -f': %s",
- applet, strerror(errno));
- }
-#endif
-
- shell = rc_conf_value("rc_shell");
- /* No shell set, so obey env, then passwd, then default to /bin/sh */
- if (shell == NULL) {
- shell = getenv("SHELL");
- if (shell == NULL) {
- pw = getpwuid(getuid());
- if (pw)
- shell = pw->pw_shell;
- if (shell == NULL)
- shell = "/bin/sh";
- }
- }
- run_program(shell);
-}
-
-static bool
-set_krunlevel(const char *level)
-{
- FILE *fp;
-
- if (!level ||
- strcmp(level, getenv ("RC_BOOTLEVEL")) == 0 ||
- strcmp(level, RC_LEVEL_SINGLE) == 0 ||
- strcmp(level, RC_LEVEL_SYSINIT) == 0)
- {
- if (exists(RC_KRUNLEVEL) &&
- unlink(RC_KRUNLEVEL) != 0)
- eerror("unlink `%s': %s", RC_KRUNLEVEL,
- strerror(errno));
- return false;
- }
-
- if (!(fp = fopen(RC_KRUNLEVEL, "w"))) {
- eerror("fopen `%s': %s", RC_KRUNLEVEL, strerror(errno));
- return false;
- }
-
- fprintf(fp, "%s", level);
- fclose(fp);
- return true;
-}
-
-static char *get_krunlevel(void)
-{
- char *buffer = NULL;
- FILE *fp;
- size_t i = 0;
-
- if (!exists(RC_KRUNLEVEL))
- return NULL;
- if (!(fp = fopen(RC_KRUNLEVEL, "r"))) {
- eerror("fopen `%s': %s", RC_KRUNLEVEL, strerror(errno));
- return NULL;
- }
-
- if (getline(&buffer, &i, fp) != -1) {
- i = strlen(buffer);
- if (buffer[i - 1] == '\n')
- buffer[i - 1] = 0;
- }
- fclose(fp);
- return buffer;
-}
-
-static void
-add_pid(pid_t pid)
-{
- RC_PID *p = xmalloc(sizeof(*p));
- p->pid = pid;
- LIST_INSERT_HEAD(&service_pids, p, entries);
-}
-
-static void
-remove_pid(pid_t pid)
-{
- RC_PID *p;
-
- LIST_FOREACH(p, &service_pids, entries)
- if (p->pid == pid) {
- LIST_REMOVE(p, entries);
- free(p);
- return;
- }
-}
-
-static void
-wait_for_services(void)
-{
- for (;;) {
- while (waitpid(0, 0, 0) != -1)
- ;
- if (errno != EINTR)
- break;
- }
-}
-
-static void
-handle_signal(int sig)
-{
- int serrno = errno;
- char *signame = NULL;
- pid_t pid;
- RC_PID *pi;
- int status = 0;
- struct winsize ws;
- sigset_t sset;
-
- switch (sig) {
- case SIGCHLD:
- do {
- pid = waitpid(-1, &status, WNOHANG);
- if (pid < 0) {
- if (errno != ECHILD)
- eerror("waitpid: %s", strerror(errno));
- return;
- }
- } while (!WIFEXITED(status) && !WIFSIGNALED(status));
-
- /* Remove that pid from our list */
- if (pid > 0)
- remove_pid(pid);
- break;
-
- case SIGWINCH:
- if (rc_logger_tty >= 0) {
- ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
- ioctl(rc_logger_tty, TIOCSWINSZ, &ws);
- }
- break;
-
- case SIGINT:
- if (!signame)
- xasprintf(&signame, "SIGINT");
- /* FALLTHROUGH */
- case SIGTERM:
- if (!signame)
- xasprintf(&signame, "SIGTERM");
- /* FALLTHROUGH */
- case SIGQUIT:
- if (!signame)
- xasprintf(&signame, "SIGQUIT");
- eerrorx("%s: caught %s, aborting", applet, signame);
- /* NOTREACHED */
- case SIGUSR1:
- eerror("rc: Aborting!");
-
- /* Block child signals */
- sigemptyset(&sset);
- sigaddset(&sset, SIGCHLD);
- sigprocmask(SIG_BLOCK, &sset, NULL);
-
- /* Kill any running services we have started */
- LIST_FOREACH(pi, &service_pids, entries)
- kill(pi->pid, SIGTERM);
-
- /* Notify plugins we are aborting */
- rc_plugin_run(RC_HOOK_ABORT, NULL);
-
- exit(EXIT_FAILURE);
- /* NOTREACHED */
-
- default:
- eerror("%s: caught unknown signal %d", applet, sig);
- }
-
- /* Restore errno */
- errno = serrno;
-}
-
-static void
-do_sysinit()
-{
- struct utsname uts;
- const char *sys;
-
- /* exec init-early.sh if it exists
- * This should just setup the console to use the correct
- * font. Maybe it should setup the keyboard too? */
- if (exists(INITEARLYSH))
- run_program(INITEARLYSH);
-
- uname(&uts);
- printf("\n %sOpenRC %s" VERSION "%s is starting up %s",
- ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE),
- ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET));
-#ifdef BRANDING
- printf(BRANDING " (%s)", uts.machine);
-#else
- printf("%s %s (%s)",
- uts.sysname,
- uts.release,
- uts.machine);
-#endif
-
- if ((sys = rc_sys()))
- printf(" [%s]", sys);
-
- printf("%s\n\n", ecolor(ECOLOR_NORMAL));
-
- if (!rc_yesno(getenv ("EINFO_QUIET")) &&
- rc_conf_yesno("rc_interactive"))
- printf("Press %sI%s to enter interactive boot mode\n\n",
- ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL));
-
- setenv("RC_RUNLEVEL", RC_LEVEL_SYSINIT, 1);
- run_program(INITSH);
-
- /* init may have mounted /proc so we can now detect or real
- * sys */
- if ((sys = rc_sys()))
- setenv("RC_SYS", sys, 1);
- /* force an update of the dependency tree */
- if ((main_deptree = _rc_deptree_load(1, NULL)) == NULL)
- eerrorx("failed to load deptree");
-}
-
-static bool
-runlevel_config(const char *service, const char *level)
-{
- char *init = rc_service_resolve(service);
- char *conf, *dir;
- bool retval;
-
- dir = dirname(init);
- dir = dirname(init);
- xasprintf(&conf, "%s/conf.d/%s.%s", dir, service, level);
- retval = exists(conf);
- free(conf);
- free(init);
- return retval;
-}
-
-static void
-do_stop_services(RC_STRINGLIST *types_nw, RC_STRINGLIST *start_services,
- const RC_STRINGLIST *stop_services, const RC_DEPTREE *deptree,
- const char *newlevel, bool parallel, bool going_down)
-{
- pid_t pid;
- RC_STRING *service, *svc1, *svc2;
- RC_STRINGLIST *deporder, *tmplist, *kwords;
- RC_SERVICE state;
- RC_STRINGLIST *nostop;
- bool crashed, nstop;
-
- if (!types_nw) {
- types_nw = rc_stringlist_new();
- rc_stringlist_add(types_nw, "needsme");
- rc_stringlist_add(types_nw, "wantsme");
- }
-
- crashed = rc_conf_yesno("rc_crashed_stop");
-
- nostop = rc_stringlist_split(rc_conf_value("rc_nostop"), " ");
- TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries)
- {
- state = rc_service_state(service->value);
- if (state & RC_SERVICE_STOPPED || state & RC_SERVICE_FAILED)
- continue;
-
- /* Sometimes we don't ever want to stop a service. */
- if (rc_stringlist_find(nostop, service->value)) {
- rc_service_mark(service->value, RC_SERVICE_FAILED);
- continue;
- }
- kwords = rc_deptree_depend(deptree, service->value, "keyword");
- if (rc_stringlist_find(kwords, "-stop") ||
- rc_stringlist_find(kwords, "nostop") ||
- (going_down &&
- (rc_stringlist_find(kwords, "-shutdown") ||
- rc_stringlist_find(kwords, "noshutdown"))))
- nstop = true;
- else
- nstop = false;
- rc_stringlist_free(kwords);
- if (nstop) {
- rc_service_mark(service->value, RC_SERVICE_FAILED);
- continue;
- }
-
- /* If the service has crashed, skip futher checks and just stop
- it */
- if (crashed &&
- rc_service_daemons_crashed(service->value))
- goto stop;
-
- /* If we're in the start list then don't bother stopping us */
- svc1 = rc_stringlist_find(start_services, service->value);
- if (svc1) {
- if (newlevel && strcmp(runlevel, newlevel) != 0) {
- /* So we're in the start list. But we should
- * be stopped if we have a runlevel
- * configuration file for either the current
- * or next so we use the correct one. */
- if (!runlevel_config(service->value,runlevel) &&
- !runlevel_config(service->value,newlevel))
- continue;
- }
- else
- continue;
- }
-
- /* We got this far. Last check is to see if any any service
- * that going to be started depends on us */
- if (!svc1) {
- tmplist = rc_stringlist_new();
- rc_stringlist_add(tmplist, service->value);
- deporder = rc_deptree_depends(deptree, types_nw,
- tmplist, newlevel ? newlevel : runlevel,
- RC_DEP_STRICT | RC_DEP_TRACE);
- rc_stringlist_free(tmplist);
- svc2 = NULL;
- TAILQ_FOREACH(svc1, deporder, entries) {
- svc2 = rc_stringlist_find(start_services,
- svc1->value);
- if (svc2)
- break;
- }
- rc_stringlist_free(deporder);
-
- if (svc2)
- continue;
- }
-
-stop:
- /* After all that we can finally stop the blighter! */
- pid = service_stop(service->value);
- if (pid > 0) {
- add_pid(pid);
- if (!parallel) {
- rc_waitpid(pid);
- remove_pid(pid);
- }
- }
- }
-
- rc_stringlist_free(nostop);
-}
-
-static void
-do_start_services(const RC_STRINGLIST *start_services, bool parallel)
-{
- RC_STRING *service;
- pid_t pid;
- bool interactive = false;
- RC_SERVICE state;
- bool crashed = false;
-
- if (!rc_yesno(getenv("EINFO_QUIET")))
- interactive = exists(INTERACTIVE);
- errno = 0;
- crashed = rc_conf_yesno("rc_crashed_start");
- if (errno == ENOENT)
- crashed = true;
-
- TAILQ_FOREACH(service, start_services, entries) {
- state = rc_service_state(service->value);
- if (state & RC_SERVICE_FAILED)
- continue;
- if (!(state & RC_SERVICE_STOPPED)) {
- if (crashed &&
- rc_service_daemons_crashed(service->value))
- rc_service_mark(service->value,
- RC_SERVICE_STOPPED);
- else
- continue;
- }
- if (!interactive)
- interactive = want_interactive();
-
- if (interactive) {
- interactive_retry:
- printf("\n");
- einfo("About to start the service %s",
- service->value);
- eindent();
- einfo("1) Start the service\t\t2) Skip the service");
- einfo("3) Continue boot process\t\t4) Exit to shell");
- eoutdent();
- interactive_option:
- switch (read_key(true)) {
- case '1': break;
- case '2': continue;
- case '3': interactive = false; break;
- case '4': open_shell(); goto interactive_retry;
- default: goto interactive_option;
- }
- }
-
- pid = service_start(service->value);
- if (pid == -1)
- break;
- /* Remember the pid if we're running in parallel */
- if (pid > 0) {
- add_pid(pid);
- if (!parallel) {
- rc_waitpid(pid);
- remove_pid(pid);
- }
- }
- }
-
- /* Store our interactive status for boot */
- if (interactive &&
- (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
- strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0))
- mark_interactive();
- else {
- if (exists(INTERACTIVE))
- unlink(INTERACTIVE);
- }
-
-}
-
-#ifdef RC_DEBUG
-static void
-handle_bad_signal(int sig)
-{
- char pid[10];
- int status;
- pid_t crashed_pid = getpid();
-
- switch (fork()) {
- case -1:
- _exit(sig);
- /* NOTREACHED */
- case 0:
- sprintf(pid, "%i", crashed_pid);
- printf("\nAuto launching gdb!\n\n");
- _exit(execlp("gdb", "gdb", "--quiet", "--pid", pid,
- "-ex", "bt full", NULL));
- /* NOTREACHED */
- default:
- wait(&status);
- }
- _exit(1);
- /* NOTREACHED */
-}
-#endif
-
-int main(int argc, char **argv)
-{
- const char *bootlevel = NULL;
- char *newlevel = NULL;
- const char *systype = NULL;
- RC_STRINGLIST *deporder = NULL;
- RC_STRINGLIST *tmplist;
- RC_STRING *service;
- bool going_down = false;
- int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
- char *krunlevel = NULL;
- char *pidstr = NULL;
- int opt;
- bool parallel;
- int regen = 0;
- bool nostop = false;
-#ifdef __linux__
- char *proc;
- char *p;
- char *token;
-#endif
-
-#ifdef RC_DEBUG
- signal_setup(SIGBUS, handle_bad_signal);
- signal_setup(SIGILL, handle_bad_signal);
- signal_setup(SIGSEGV, handle_bad_signal);
-#endif
-
- applet = basename_c(argv[0]);
- LIST_INIT(&service_pids);
- atexit(cleanup);
- if (!applet)
- eerrorx("arguments required");
-
- argc--;
- argv++;
-
- /* Change dir to / to ensure all scripts don't use stuff in pwd */
- if (chdir("/") == -1)
- eerror("chdir: %s", strerror(errno));
-
- /* Ensure our environment is pure
- * Also, add our configuration to it */
- env_filter();
- env_config();
-
- /* complain about old configuration settings if they exist */
- if (exists(RC_CONF_OLD)) {
- ewarn("%s still exists on your system and should be removed.",
- RC_CONF_OLD);
- ewarn("Please migrate to the appropriate settings in %s", RC_CONF);
- }
-
- argc++;
- argv--;
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 'n':
- nostop = true;
- break;
- case 'o':
- if (*optarg == '\0')
- optarg = NULL;
- if (!rc_runlevel_exists(optarg)) {
- eerror("runlevel `%s' does not exist", optarg);
- exit(EXIT_FAILURE);
- }
- if (!set_krunlevel(optarg))
- exit(EXIT_FAILURE);
- einfo("Overriding next runlevel to %s", optarg);
- exit(EXIT_SUCCESS);
- /* NOTREACHED */
- case 's':
- newlevel = rc_service_resolve(optarg);
- if (!newlevel)
- eerrorx("%s: service `%s' does not exist",
- applet, optarg);
- argv += optind - 1;
- *argv = newlevel;
- execv(*argv, argv);
- eerrorx("%s: %s", applet, strerror(errno));
- /* NOTREACHED */
- case 'S':
- systype = rc_sys();
- if (systype)
- printf("%s\n", systype);
- exit(EXIT_SUCCESS);
- /* NOTREACHED */
- case_RC_COMMON_GETOPT
- }
- }
-
- if (strcmp(applet, "rc") == 0)
- ewarn("rc is deprecated, please use openrc instead.");
- newlevel = argv[optind++];
- /* To make life easier, we only have the shutdown runlevel as
- * nothing really needs to know that we're rebooting.
- * But for those that do, you can test against RC_REBOOT. */
- if (newlevel) {
- if (strcmp(newlevel, "reboot") == 0) {
- newlevel = UNCONST(RC_LEVEL_SHUTDOWN);
- setenv("RC_REBOOT", "YES", 1);
- }
- }
-
- /* Enable logging */
- setenv("EINFO_LOG", "openrc", 1);
-
- /* Export our PID */
- xasprintf(&pidstr, "%d", getpid());
- setenv("RC_PID", pidstr, 1);
- free(pidstr);
-
- /* Create a list of all services which should be started for the new or
- * current runlevel including those in boot, sysinit and hotplugged
- * runlevels. Clearly, some of these will already be started so we
- * won't actually be starting them all.
- */
- bootlevel = getenv("RC_BOOTLEVEL");
- runlevel = rc_runlevel_get();
-
- rc_logger_open(newlevel ? newlevel : runlevel);
-
- /* Setup a signal handler */
- signal_setup(SIGINT, handle_signal);
- signal_setup(SIGQUIT, handle_signal);
- signal_setup(SIGTERM, handle_signal);
- signal_setup(SIGUSR1, handle_signal);
- signal_setup(SIGWINCH, handle_signal);
-
- /* Run any special sysinit foo */
- if (newlevel && strcmp(newlevel, RC_LEVEL_SYSINIT) == 0) {
- do_sysinit();
- free(runlevel);
- runlevel = rc_runlevel_get();
- }
-
- rc_plugin_load();
-
- /* Now we start handling our children */
- signal_setup(SIGCHLD, handle_signal);
-
- if (newlevel &&
- (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
- strcmp(newlevel, RC_LEVEL_SINGLE) == 0))
- {
- going_down = true;
- if (!exists(RC_KRUNLEVEL))
- set_krunlevel(runlevel);
- rc_runlevel_set(newlevel);
- setenv("RC_RUNLEVEL", newlevel, 1);
- setenv("RC_GOINGDOWN", "YES", 1);
- } else {
- /* We should not use krunevel in sysinit or boot runlevels */
- if (!newlevel ||
- (strcmp(newlevel, RC_LEVEL_SYSINIT) != 0 &&
- strcmp(newlevel, getenv("RC_BOOTLEVEL")) != 0))
- {
- krunlevel = get_krunlevel();
- if (krunlevel) {
- newlevel = krunlevel;
- set_krunlevel(NULL);
- }
- }
-
- if (newlevel) {
- if (strcmp(runlevel, newlevel) != 0 &&
- !rc_runlevel_exists(newlevel))
- eerrorx("%s: not a valid runlevel", newlevel);
-
-#ifdef __linux__
- if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0) {
- /* If we requested a runlevel, save it now */
- p = rc_proc_getent("rc_runlevel");
- if (p == NULL)
- p = rc_proc_getent("softlevel");
- if (p != NULL) {
- set_krunlevel(p);
- free(p);
- }
- }
-#endif
- }
- }
-
- if (going_down) {
-#ifdef __FreeBSD__
- /* FIXME: we shouldn't have todo this */
- /* For some reason, wait_for_services waits for the logger
- * proccess to finish as well, but only on FreeBSD.
- * We cannot allow this so we stop logging now. */
- rc_logger_close();
-#endif
-
- rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_IN, newlevel);
- } else {
- rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_IN, runlevel);
- }
- hook_out = RC_HOOK_RUNLEVEL_STOP_OUT;
-
- /* Check if runlevel is valid if we're changing */
- if (newlevel && strcmp(runlevel, newlevel) != 0 && !going_down) {
- if (!rc_runlevel_exists(newlevel))
- eerrorx("%s: is not a valid runlevel", newlevel);
- }
-
- /* Load our deptree */
- if ((main_deptree = _rc_deptree_load(0, &regen)) == NULL)
- eerrorx("failed to load deptree");
- if (exists(RC_DEPTREE_SKEWED))
- ewarn("WARNING: clock skew detected!");
-
- /* Clean the failed services state dir */
- clean_failed();
-
- if (mkdir(RC_STOPPING, 0755) != 0) {
- if (errno == EACCES)
- eerrorx("%s: superuser access required", applet);
- eerrorx("%s: failed to create stopping dir `%s': %s",
- applet, RC_STOPPING, strerror(errno));
- }
-
- /* Create a list of all services which we could stop (assuming
- * they won't be active in the new or current runlevel) including
- * all those services which have been started, are inactive or
- * are currently starting. Clearly, some of these will be listed
- * in the new or current runlevel so we won't actually be stopping
- * them all.
- */
- main_stop_services = rc_services_in_state(RC_SERVICE_STARTED);
- tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
- TAILQ_CONCAT(main_stop_services, tmplist, entries);
- free(tmplist);
- tmplist = rc_services_in_state(RC_SERVICE_STARTING);
- TAILQ_CONCAT(main_stop_services, tmplist, entries);
- free(tmplist);
- if (main_stop_services)
- rc_stringlist_sort(&main_stop_services);
-
- main_types_nwua = rc_stringlist_new();
- rc_stringlist_add(main_types_nwua, "ineed");
- rc_stringlist_add(main_types_nwua, "iwant");
- rc_stringlist_add(main_types_nwua, "iuse");
- rc_stringlist_add(main_types_nwua, "iafter");
-
- if (main_stop_services) {
- tmplist = rc_deptree_depends(main_deptree, main_types_nwua, main_stop_services,
- runlevel, depoptions | RC_DEP_STOP);
- rc_stringlist_free(main_stop_services);
- main_stop_services = tmplist;
- }
-
- /* Create a list of all services which should be started for the new or
- * current runlevel including those in boot, sysinit and hotplugged
- * runlevels. Clearly, some of these will already be started so we
- * won't actually be starting them all.
- */
- main_hotplugged_services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);
- main_start_services = rc_services_in_runlevel_stacked(newlevel ?
- newlevel : runlevel);
- if (strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
- strcmp(newlevel ? newlevel : runlevel, RC_LEVEL_SYSINIT) != 0)
- {
- tmplist = rc_services_in_runlevel(RC_LEVEL_SYSINIT);
- TAILQ_CONCAT(main_start_services, tmplist, entries);
- free(tmplist);
- /* If we are NOT headed for the single-user runlevel... */
- if (strcmp(newlevel ? newlevel : runlevel,
- RC_LEVEL_SINGLE) != 0)
- {
- /* If we are NOT headed for the boot runlevel... */
- if (strcmp(newlevel ? newlevel : runlevel,
- bootlevel) != 0)
- {
- tmplist = rc_services_in_runlevel(bootlevel);
- TAILQ_CONCAT(main_start_services, tmplist, entries);
- free(tmplist);
- }
- if (main_hotplugged_services) {
- TAILQ_FOREACH(service, main_hotplugged_services,
- entries)
- rc_stringlist_addu(main_start_services,
- service->value);
- }
- }
- }
-
- parallel = rc_conf_yesno("rc_parallel");
-
- /* Now stop the services that shouldn't be running */
- if (main_stop_services && !nostop)
- do_stop_services(main_types_nw, main_start_services, main_stop_services, main_deptree, newlevel, parallel, going_down);
-
- /* Wait for our services to finish */
- wait_for_services();
-
- /* Notify the plugins we have finished */
- rc_plugin_run(RC_HOOK_RUNLEVEL_STOP_OUT,
- going_down ? newlevel : runlevel);
- hook_out = 0;
-
- rmdir(RC_STOPPING);
-
- /* Store the new runlevel */
- if (newlevel) {
- rc_runlevel_set(newlevel);
- free(runlevel);
- runlevel = xstrdup(newlevel);
- setenv("RC_RUNLEVEL", runlevel, 1);
- }
-
-#ifdef __linux__
- /* We can't log beyond this point as the shutdown runlevel
- * will mount / readonly. */
- if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0)
- rc_logger_close();
-#endif
-
- mkdir(RC_STARTING, 0755);
- rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, runlevel);
- hook_out = RC_HOOK_RUNLEVEL_START_OUT;
-
- /* Re-add our hotplugged services if they stopped */
- if (main_hotplugged_services)
- TAILQ_FOREACH(service, main_hotplugged_services, entries)
- rc_service_mark(service->value, RC_SERVICE_HOTPLUGGED);
-
-#ifdef __linux__
- /* If the "noinit" parameter was passed on the kernel command line then
- * mark the specified services as started so they will not be started
- * by us. */
- proc = p = rc_proc_getent("noinit");
- if (proc) {
- while ((token = strsep(&p, ",")))
- rc_service_mark(token, RC_SERVICE_STARTED);
- free(proc);
- }
-#endif
-
- /* If we have a list of services to start then... */
- if (main_start_services) {
- /* Get a list of the chained runlevels which compose the target runlevel */
- RC_STRINGLIST *runlevel_chain = rc_runlevel_stacks(runlevel);
-
- /* Loop through them in reverse order. */
- RC_STRING *rlevel;
- TAILQ_FOREACH_REVERSE(rlevel, runlevel_chain, rc_stringlist, entries)
- {
- /* Get a list of all the services in that runlevel */
- RC_STRINGLIST *run_services = rc_services_in_runlevel(rlevel->value);
-
- /* Start those services. */
- rc_stringlist_sort(&run_services);
- deporder = rc_deptree_depends(main_deptree, main_types_nwua, run_services, rlevel->value, depoptions | RC_DEP_START);
- rc_stringlist_free(run_services);
- run_services = deporder;
- do_start_services(run_services, parallel);
-
- /* Wait for our services to finish */
- wait_for_services();
-
- /* Free the list of services, we're done with it. */
- rc_stringlist_free(run_services);
- }
- rc_stringlist_free(runlevel_chain);
- }
-
-#ifdef __linux__
- /* If the "noinit" parameter was passed on the kernel command line then
- * mark the specified services as stopped so that our records reflect
- * reality. */
- proc = p = rc_proc_getent("noinit");
- if (proc) {
- while ((token = strsep(&p, ",")))
- rc_service_mark(token, RC_SERVICE_STOPPED);
- free(proc);
- }
-
-#endif
-
- rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
- hook_out = 0;
-
- /* If we're in the boot runlevel and we regenerated our dependencies
- * we need to delete them so that they are regenerated again in the
- * default runlevel as they may depend on things that are now
- * available */
- if (regen && strcmp(runlevel, bootlevel) == 0)
- unlink(RC_DEPTREE_CACHE);
-
- return EXIT_SUCCESS;
-}
diff --git a/src/rc/seedrng.c b/src/rc/seedrng.c
deleted file mode 100644
index 95fb947d..00000000
--- a/src/rc/seedrng.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * seedrng.c
- * Seed kernel RNG from seed file, based on code from:
- * https://git.zx2c4.com/seedrng/about/
- */
-
-/*
- * Copyright (c) 2022 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <linux/random.h>
-#include <sys/random.h>
-#include <sys/ioctl.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <poll.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
-#include <endian.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "rc.h"
-#include "einfo.h"
-#include "helpers.h"
-#include "_usage.h"
-
-#ifndef GRND_INSECURE
-#define GRND_INSECURE 0x0004 /* Apparently some headers don't ship with this yet. */
-#endif
-
-/* Use long option value that is out of range for 8 bit getopt values.
- * The exact enum value is internal and can freely change, so we keep the
- * options sorted.
- */
-enum long_opts {
- /* This has to come first so following values stay in the 0x100+ range. */
- LONGOPT_BASE = 0x100,
- LONGOPT_LOCK_FILE,
- LONGOPT_SEED_DIR,
- LONGOPT_SKIP_CREDIT,
-};
-
-const char *applet = NULL;
-const char *extraopts =NULL;
-const char getoptstring[] = getoptstring_COMMON;
-const struct option longopts[] = {
- { "lock-file", 1, NULL, LONGOPT_LOCK_FILE },
- { "seed-dir", 1, NULL, LONGOPT_SEED_DIR },
- { "skip-credit", 0, NULL, LONGOPT_SKIP_CREDIT },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "lock file",
- "directory for seed files",
- "skip credit",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static char *lock_file = NULL;
-static char *seed_dir = NULL;
-static char *creditable_seed = NULL;
-static char *non_creditable_seed = NULL;
-
-enum blake2s_lengths {
- BLAKE2S_BLOCK_LEN = 64,
- BLAKE2S_HASH_LEN = 32,
- BLAKE2S_KEY_LEN = 32
-};
-
-enum seedrng_lengths {
- MAX_SEED_LEN = 512,
- MIN_SEED_LEN = BLAKE2S_HASH_LEN
-};
-
-struct blake2s_state {
- uint32_t h[8];
- uint32_t t[2];
- uint32_t f[2];
- uint8_t buf[BLAKE2S_BLOCK_LEN];
- unsigned int buflen;
- unsigned int outlen;
-};
-
-#define le32_to_cpup(a) le32toh(*(a))
-#define cpu_to_le32(a) htole32(a)
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-#ifndef DIV_ROUND_UP
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-#endif
-
-static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = cpu_to_le32(*buf);
- ++buf;
- }
-}
-
-static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
-{
- while (words--) {
- *buf = le32_to_cpup(buf);
- ++buf;
- }
-}
-
-static inline uint32_t ror32(uint32_t word, unsigned int shift)
-{
- return (word >> (shift & 31)) | (word << ((-shift) & 31));
-}
-
-static const uint32_t blake2s_iv[8] = {
- 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
- 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
-};
-
-static const uint8_t blake2s_sigma[10][16] = {
- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
- { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
- { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
- { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
- { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
- { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
- { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
- { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
- { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
- { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
-};
-
-static void blake2s_set_lastblock(struct blake2s_state *state)
-{
- state->f[0] = -1;
-}
-
-static void blake2s_increment_counter(struct blake2s_state *state, const uint32_t inc)
-{
- state->t[0] += inc;
- state->t[1] += (state->t[0] < inc);
-}
-
-static void blake2s_init_param(struct blake2s_state *state, const uint32_t param)
-{
- int i;
-
- memset(state, 0, sizeof(*state));
- for (i = 0; i < 8; ++i)
- state->h[i] = blake2s_iv[i];
- state->h[0] ^= param;
-}
-
-static void blake2s_init(struct blake2s_state *state, const size_t outlen)
-{
- blake2s_init_param(state, 0x01010000 | outlen);
- state->outlen = outlen;
-}
-
-static void blake2s_compress(struct blake2s_state *state, const uint8_t *block, size_t nblocks, const uint32_t inc)
-{
- uint32_t m[16];
- uint32_t v[16];
- int i;
-
- while (nblocks > 0) {
- blake2s_increment_counter(state, inc);
- memcpy(m, block, BLAKE2S_BLOCK_LEN);
- le32_to_cpu_array(m, ARRAY_SIZE(m));
- memcpy(v, state->h, 32);
- v[ 8] = blake2s_iv[0];
- v[ 9] = blake2s_iv[1];
- v[10] = blake2s_iv[2];
- v[11] = blake2s_iv[3];
- v[12] = blake2s_iv[4] ^ state->t[0];
- v[13] = blake2s_iv[5] ^ state->t[1];
- v[14] = blake2s_iv[6] ^ state->f[0];
- v[15] = blake2s_iv[7] ^ state->f[1];
-
-#define G(r, i, a, b, c, d) do { \
- a += b + m[blake2s_sigma[r][2 * i + 0]]; \
- d = ror32(d ^ a, 16); \
- c += d; \
- b = ror32(b ^ c, 12); \
- a += b + m[blake2s_sigma[r][2 * i + 1]]; \
- d = ror32(d ^ a, 8); \
- c += d; \
- b = ror32(b ^ c, 7); \
-} while (0)
-
-#define ROUND(r) do { \
- G(r, 0, v[0], v[ 4], v[ 8], v[12]); \
- G(r, 1, v[1], v[ 5], v[ 9], v[13]); \
- G(r, 2, v[2], v[ 6], v[10], v[14]); \
- G(r, 3, v[3], v[ 7], v[11], v[15]); \
- G(r, 4, v[0], v[ 5], v[10], v[15]); \
- G(r, 5, v[1], v[ 6], v[11], v[12]); \
- G(r, 6, v[2], v[ 7], v[ 8], v[13]); \
- G(r, 7, v[3], v[ 4], v[ 9], v[14]); \
-} while (0)
- ROUND(0);
- ROUND(1);
- ROUND(2);
- ROUND(3);
- ROUND(4);
- ROUND(5);
- ROUND(6);
- ROUND(7);
- ROUND(8);
- ROUND(9);
-
-#undef G
-#undef ROUND
-
- for (i = 0; i < 8; ++i)
- state->h[i] ^= v[i] ^ v[i + 8];
-
- block += BLAKE2S_BLOCK_LEN;
- --nblocks;
- }
-}
-
-static void blake2s_update(struct blake2s_state *state, const void *inp, size_t inlen)
-{
- const size_t fill = BLAKE2S_BLOCK_LEN - state->buflen;
- const uint8_t *in = inp;
-
- if (!inlen)
- return;
- if (inlen > fill) {
- memcpy(state->buf + state->buflen, in, fill);
- blake2s_compress(state, state->buf, 1, BLAKE2S_BLOCK_LEN);
- state->buflen = 0;
- in += fill;
- inlen -= fill;
- }
- if (inlen > BLAKE2S_BLOCK_LEN) {
- const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_LEN);
- blake2s_compress(state, in, nblocks - 1, BLAKE2S_BLOCK_LEN);
- in += BLAKE2S_BLOCK_LEN * (nblocks - 1);
- inlen -= BLAKE2S_BLOCK_LEN * (nblocks - 1);
- }
- memcpy(state->buf + state->buflen, in, inlen);
- state->buflen += inlen;
-}
-
-static void blake2s_final(struct blake2s_state *state, uint8_t *out)
-{
- blake2s_set_lastblock(state);
- memset(state->buf + state->buflen, 0, BLAKE2S_BLOCK_LEN - state->buflen);
- blake2s_compress(state, state->buf, 1, state->buflen);
- cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
- memcpy(out, state->h, state->outlen);
-}
-
-static size_t determine_optimal_seed_len(void)
-{
- size_t ret = 0;
- char poolsize_str[11] = { 0 };
- int fd = open("/proc/sys/kernel/random/poolsize", O_RDONLY);
-
- if (fd < 0 || read(fd, poolsize_str, sizeof(poolsize_str) - 1) < 0) {
- ewarn("%s: Unable to determine pool size, falling back to %u bits: %s",
- applet, MIN_SEED_LEN * 8, strerror(errno));
- ret = MIN_SEED_LEN;
- } else
- ret = DIV_ROUND_UP(strtoul(poolsize_str, NULL, 10), 8);
- if (fd >= 0)
- close(fd);
- if (ret < MIN_SEED_LEN)
- ret = MIN_SEED_LEN;
- else if (ret > MAX_SEED_LEN)
- ret = MAX_SEED_LEN;
- return ret;
-}
-
-static int read_new_seed(uint8_t *seed, size_t len, bool *is_creditable)
-{
- ssize_t ret;
- int urandom_fd;
-
- *is_creditable = false;
- ret = getrandom(seed, len, GRND_NONBLOCK);
- if (ret == (ssize_t)len) {
- *is_creditable = true;
- return 0;
- }
- if (ret == -1 && errno == ENOSYS) {
- struct pollfd random_fd = {
- .fd = open("/dev/random", O_RDONLY),
- .events = POLLIN
- };
- if (random_fd.fd < 0)
- return -errno;
- *is_creditable = poll(&random_fd, 1, 0) == 1;
- close(random_fd.fd);
- } else if (getrandom(seed, len, GRND_INSECURE) == (ssize_t)len)
- return 0;
- urandom_fd = open("/dev/urandom", O_RDONLY);
- if (urandom_fd < 0)
- return -errno;
- ret = read(urandom_fd, seed, len);
- if (ret == (ssize_t)len)
- ret = 0;
- else
- ret = -errno ? -errno : -EIO;
- close(urandom_fd);
- return ret;
-}
-
-static int seed_rng(uint8_t *seed, size_t len, bool credit)
-{
- struct {
- int entropy_count;
- int buf_size;
- uint8_t buffer[MAX_SEED_LEN];
- } req = {
- .entropy_count = credit ? len * 8 : 0,
- .buf_size = len
- };
- int random_fd, ret;
-
- if (len > sizeof(req.buffer))
- return -EFBIG;
- memcpy(req.buffer, seed, len);
-
- random_fd = open("/dev/random", O_RDWR);
- if (random_fd < 0)
- return -errno;
- ret = ioctl(random_fd, RNDADDENTROPY, &req);
- if (ret)
- ret = -errno ? -errno : -EIO;
- close(random_fd);
- return ret;
-}
-
-static int seed_from_file_if_exists(const char *filename, bool credit, struct blake2s_state *hash)
-{
- uint8_t seed[MAX_SEED_LEN];
- ssize_t seed_len;
- int fd, dfd, ret = 0;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0 && errno == ENOENT)
- return 0;
- else if (fd < 0) {
- ret = -errno;
- eerror("%s: Unable to open seed file: %s", applet, strerror(errno));
- return ret;
- }
- dfd = open(seed_dir, O_DIRECTORY | O_RDONLY);
- if (dfd < 0) {
- ret = -errno;
- close(fd);
- eerror("%s: Unable to open seed directory: %s", applet, strerror(errno));
- return ret;
- }
- seed_len = read(fd, seed, sizeof(seed));
- if (seed_len < 0) {
- ret = -errno;
- eerror("%s: Unable to read seed file: %s", applet, strerror(errno));
- }
- close(fd);
- if (ret) {
- close(dfd);
- return ret;
- }
- if ((unlink(filename) < 0 || fsync(dfd) < 0) && seed_len) {
- ret = -errno;
- eerror("%s: Unable to remove seed after reading, so not seeding: %s",
- applet, strerror(errno));
- }
- close(dfd);
- if (ret)
- return ret;
- if (!seed_len)
- return 0;
-
- blake2s_update(hash, &seed_len, sizeof(seed_len));
- blake2s_update(hash, seed, seed_len);
-
- einfo("Seeding %zd bits %s crediting", seed_len * 8, credit ? "and" : "without");
- ret = seed_rng(seed, seed_len, credit);
- if (ret < 0)
- eerror("%s: Unable to seed: %s", applet, strerror(-ret));
- return ret;
-}
-
-static void populate_global_paths(void)
-{
- if (!lock_file)
- lock_file = xstrdup("/var/run/seedrng.lock");
- if (!seed_dir)
- seed_dir = xstrdup("/var/lib/seedrng");
- xasprintf(&creditable_seed, "%s/seed.credit", seed_dir);
- xasprintf(&non_creditable_seed, "%s/seed.no-credit", seed_dir);
-}
-
-static void cleanup(void)
-{
- free(lock_file);
- free(seed_dir);
- free(creditable_seed);
- free(non_creditable_seed);
-}
-
-int main(int argc, char **argv)
-{
- int opt;
- static const char seedrng_prefix[] = "SeedRNG v1 Old+New Prefix";
- static const char seedrng_failure[] = "SeedRNG v1 No New Seed Failure";
- int ret, fd = -1, lock, program_ret = 0;
- uint8_t new_seed[MAX_SEED_LEN];
- size_t new_seed_len;
- bool new_seed_creditable;
- struct timespec realtime = { 0 }, boottime = { 0 };
- struct blake2s_state hash;
- bool skip_credit = false;
-
- atexit(cleanup);
- applet = basename_c(argv[0]);
- if (geteuid())
- eerrorx("%s: superuser access is required", applet);
- umask(0077);
-
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case LONGOPT_LOCK_FILE:
- if (!lock_file)
- lock_file = xstrdup(optarg);
- break;
- case LONGOPT_SEED_DIR:
- if (!seed_dir)
- seed_dir = xstrdup(optarg);
- break;
- case LONGOPT_SKIP_CREDIT:
- skip_credit = true;
- break;
- case_RC_COMMON_GETOPT
- }
- }
- populate_global_paths();
- blake2s_init(&hash, BLAKE2S_HASH_LEN);
- blake2s_update(&hash, seedrng_prefix, strlen(seedrng_prefix));
- clock_gettime(CLOCK_REALTIME, &realtime);
- clock_gettime(CLOCK_BOOTTIME, &boottime);
- blake2s_update(&hash, &realtime, sizeof(realtime));
- blake2s_update(&hash, &boottime, sizeof(boottime));
-
- if (mkdir(seed_dir, 0700) < 0 && errno != EEXIST)
- eerrorx("%s: Unable to create \"%s\" directory: %s",
- applet, seed_dir, strerror(errno));
-
- lock = open(lock_file, O_WRONLY | O_CREAT, 0000);
- if (lock < 0 || flock(lock, LOCK_EX) < 0) {
- eerror("%s: Unable to open lock file: %s", applet, strerror(errno));
- program_ret = 1;
- goto out;
- }
-
- ret = seed_from_file_if_exists(non_creditable_seed, false, &hash);
- if (ret < 0)
- program_ret |= 1 << 1;
- ret = seed_from_file_if_exists(creditable_seed, !skip_credit, &hash);
- if (ret < 0)
- program_ret |= 1 << 2;
-
- new_seed_len = determine_optimal_seed_len();
- ret = read_new_seed(new_seed, new_seed_len, &new_seed_creditable);
- if (ret < 0) {
- eerror("%s: Unable to read new seed: %s", applet, strerror(-ret));
- new_seed_len = BLAKE2S_HASH_LEN;
- strncpy((char *)new_seed, seedrng_failure, new_seed_len);
- program_ret |= 1 << 3;
- }
- blake2s_update(&hash, &new_seed_len, sizeof(new_seed_len));
- blake2s_update(&hash, new_seed, new_seed_len);
- blake2s_final(&hash, new_seed + new_seed_len - BLAKE2S_HASH_LEN);
-
- einfo("Saving %zu bits of %s seed for next boot", new_seed_len * 8, new_seed_creditable ? "creditable" : "non-creditable");
- fd = open(non_creditable_seed, O_WRONLY | O_CREAT | O_TRUNC, 0400);
- if (fd < 0) {
- eerror("%s: Unable to open seed file for writing: %s",
- applet, strerror(errno));
- program_ret |= 1 << 4;
- goto out;
- }
- if (write(fd, new_seed, new_seed_len) != (ssize_t)new_seed_len || fsync(fd) < 0) {
- eerror("%s: Unable to write seed file: %s", applet, strerror(errno));
- program_ret |= 1 << 5;
- goto out;
- }
- if (new_seed_creditable && rename(non_creditable_seed, creditable_seed) < 0) {
- ewarn("%s: Unable to make new seed creditable: %s",
- applet, strerror(errno));
- program_ret |= 1 << 6;
- }
-out:
- if (fd >= 0)
- close(fd);
- if (lock >= 0)
- close(lock);
- return program_ret;
-}
diff --git a/src/rc/shell_var.c b/src/rc/shell_var.c
deleted file mode 100644
index 70750245..00000000
--- a/src/rc/shell_var.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <errno.h>
-#include <ctype.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-int main(int argc, char **argv)
-{
- int i;
- char *p;
- int c;
-
- for (i = 1; i < argc; i++) {
- p = argv[i];
- if (i != 1)
- putchar(' ');
- while (*p) {
- c = (unsigned char)*p++;
- if (!isalnum(c))
- c = '_';
- putchar(c);
- }
- }
- putchar('\n');
- return EXIT_SUCCESS;
-}
diff --git a/src/rc/start-stop-daemon.c b/src/rc/start-stop-daemon.c
deleted file mode 100644
index db97f3b3..00000000
--- a/src/rc/start-stop-daemon.c
+++ /dev/null
@@ -1,1205 +0,0 @@
-/*
- start-stop-daemon
- * Starts, stops, tests and signals daemons
- *
- * This is essentially a ground up re-write of Debians
- * start-stop-daemon for cleaner code and to integrate into our RC
- * system so we can monitor daemons a little.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#define ONE_MS 1000000
-
-#ifdef __linux__
-/* For extra SCHED_* defines. */
-# define _GNU_SOURCE
-#endif
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <termios.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#ifdef __linux__
-#include <sys/syscall.h> /* For io priority */
-#include <sys/prctl.h> /* For prctl */
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <grp.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#ifdef HAVE_PAM
-#include <security/pam_appl.h>
-
-/* We are not supporting authentication conversations */
-static struct pam_conv conv = { NULL, NULL};
-#endif
-
-#ifdef HAVE_CAP
-#include <sys/capability.h>
-#endif
-
-#include <sched.h>
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-pipes.h"
-#include "rc-schedules.h"
-#include "_usage.h"
-#include "helpers.h"
-
-/* Use long option value that is out of range for 8 bit getopt values.
- * The exact enum value is internal and can freely change, so we keep the
- * options sorted.
- */
-enum {
- /* This has to come first so following values stay in the 0x100+ range. */
- LONGOPT_BASE = 0x100,
-
- LONGOPT_CAPABILITIES,
- LONGOPT_OOM_SCORE_ADJ,
- LONGOPT_NO_NEW_PRIVS,
- LONGOPT_SCHEDULER,
- LONGOPT_SCHEDULER_PRIO,
- LONGOPT_SECBITS,
-};
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:3:4:" \
- getoptstring_COMMON;
-const struct option longopts[] = {
- { "capabilities", 1, NULL, LONGOPT_CAPABILITIES},
- { "secbits", 1, NULL, LONGOPT_SECBITS},
- { "no-new-privs", 0, NULL, LONGOPT_NO_NEW_PRIVS},
- { "ionice", 1, NULL, 'I'},
- { "stop", 0, NULL, 'K'},
- { "nicelevel", 1, NULL, 'N'},
- { "oom-score-adj",1, NULL, LONGOPT_OOM_SCORE_ADJ},
- { "retry", 1, NULL, 'R'},
- { "start", 0, NULL, 'S'},
- { "startas", 1, NULL, 'a'},
- { "background", 0, NULL, 'b'},
- { "chuid", 1, NULL, 'c'},
- { "chdir", 1, NULL, 'd'},
- { "env", 1, NULL, 'e'},
- { "umask", 1, NULL, 'k'},
- { "group", 1, NULL, 'g'},
- { "interpreted", 0, NULL, 'i'},
- { "make-pidfile", 0, NULL, 'm'},
- { "name", 1, NULL, 'n'},
- { "oknodo", 0, NULL, 'o'},
- { "pidfile", 1, NULL, 'p'},
- { "signal", 1, NULL, 's'},
- { "test", 0, NULL, 't'},
- { "user", 1, NULL, 'u'},
- { "chroot", 1, NULL, 'r'},
- { "wait", 1, NULL, 'w'},
- { "exec", 1, NULL, 'x'},
- { "stdout", 1, NULL, '1'},
- { "stderr", 1, NULL, '2'},
- { "stdout-logger",1, NULL, '3'},
- { "stderr-logger",1, NULL, '4'},
- { "progress", 0, NULL, 'P'},
- { "scheduler", 1, NULL, LONGOPT_SCHEDULER},
- { "scheduler-priority", 1, NULL, LONGOPT_SCHEDULER_PRIO},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "Set the inheritable, ambient and bounding capabilities",
- "Set the security-bits for the program",
- "Set the No New Privs flag for the program",
- "Set an ionice class:data when starting",
- "Stop daemon",
- "Set a nicelevel when starting",
- "Set OOM score adjustment when starting",
- "Retry schedule to use when stopping",
- "Start daemon",
- "deprecated, use --exec or --name",
- "Force daemon to background",
- "deprecated, use --user",
- "Change the PWD",
- "Set an environment string",
- "Set the umask for the daemon",
- "Change the process group",
- "Match process name by interpreter",
- "Create a pidfile",
- "Match process name",
- "deprecated",
- "Match pid found in this file",
- "Send a different signal",
- "Test actions, don't do them",
- "Change the process user",
- "Chroot to this directory",
- "Milliseconds to wait for daemon start",
- "Binary to start/stop",
- "Redirect stdout to file",
- "Redirect stderr to file",
- "Redirect stdout to process",
- "Redirect stderr to process",
- "Print dots each second while waiting",
- "Set process scheduler",
- "Set process scheduler priority",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static char **nav;
-
-static char *changeuser, *ch_root, *ch_dir;
-
-extern char **environ;
-
-#if !defined(SYS_ioprio_set) && defined(__NR_ioprio_set)
-# define SYS_ioprio_set __NR_ioprio_set
-#endif
-#if !defined(__DragonFly__)
-static inline int ioprio_set(int which _unused,
- int who _unused,
- int ioprio _unused)
-{
-#ifdef SYS_ioprio_set
- return syscall(SYS_ioprio_set, which, who, ioprio);
-#else
- return 0;
-#endif
-}
-#endif
-
-static void
-cleanup(void)
-{
- free(changeuser);
- free(nav);
- free_schedulelist();
-}
-
-static void
-handle_signal(int sig)
-{
- int status;
- int serrno = errno;
- char *signame = NULL;
-
- switch (sig) {
- case SIGINT:
- if (!signame)
- xasprintf(&signame, "SIGINT");
- /* FALLTHROUGH */
- case SIGTERM:
- if (!signame)
- xasprintf(&signame, "SIGTERM");
- /* FALLTHROUGH */
- case SIGQUIT:
- if (!signame)
- xasprintf(&signame, "SIGQUIT");
- eerrorx("%s: caught %s, aborting", applet, signame);
- /* NOTREACHED */
-
- case SIGCHLD:
- for (;;) {
- if (waitpid(-1, &status, WNOHANG) < 0) {
- if (errno != ECHILD)
- eerror("%s: waitpid: %s",
- applet, strerror(errno));
- break;
- }
- }
- break;
-
- default:
- eerror("%s: caught unknown signal %d", applet, sig);
- }
-
- /* free signame */
- free(signame);
-
- /* Restore errno */
- errno = serrno;
-}
-
-static char *
-expand_home(const char *home, const char *path)
-{
- char *opath, *ppath, *p, *nh;
- struct passwd *pw;
-
- if (!path || *path != '~')
- return xstrdup(path);
-
- opath = ppath = xstrdup(path);
- if (ppath[1] != '/' && ppath[1] != '\0') {
- p = strchr(ppath + 1, '/');
- if (p)
- *p = '\0';
- pw = getpwnam(ppath + 1);
- if (pw) {
- home = pw->pw_dir;
- ppath = p;
- if (ppath)
- *ppath = '/';
- } else
- home = NULL;
- } else
- ppath++;
-
- if (!home) {
- free(opath);
- return xstrdup(path);
- }
- if (!ppath) {
- free(opath);
- return xstrdup(home);
- }
-
- xasprintf(&nh, "%s%s", home, ppath);
- free(opath);
- return nh;
-}
-
-int main(int argc, char **argv)
-{
- int devnull_fd = -1;
-#ifdef TIOCNOTTY
- int tty_fd = -1;
-#endif
-
-#ifdef HAVE_PAM
- pam_handle_t *pamh = NULL;
- int pamr;
- const char *const *pamenv = NULL;
-#endif
-
- int opt;
- size_t size = 0;
- bool start = false;
- bool stop = false;
- bool oknodo = false;
- bool test = false;
- char *exec = NULL;
- char *startas = NULL;
- char *name = NULL;
- char *pidfile = NULL;
- char *retry = NULL;
- int sig = -1;
- int nicelevel = INT_MIN, ionicec = -1, ioniced = 0;
- int oom_score_adj = INT_MIN;
- bool background = false;
- bool makepidfile = false;
- bool interpreted = false;
- bool progress = false;
- uid_t uid = 0;
- gid_t gid = 0;
- char *home = NULL;
- int tid = 0;
- char *redirect_stderr = NULL;
- char *redirect_stdout = NULL;
- char *stderr_process = NULL;
- char *stdout_process = NULL;
- int stdin_fd;
- int stdout_fd;
- int stderr_fd;
- pid_t pid, spid;
- RC_PIDLIST *pids;
- int i;
- char *svcname = getenv("RC_SVCNAME");
- RC_STRINGLIST *env_list;
- RC_STRING *env;
- char *tmp, *newpath, *np;
- char *p;
- char *token;
- char *exec_file = NULL;
- struct passwd *pw;
- struct group *gr;
- char *line = NULL;
- FILE *fp;
- size_t len;
- mode_t numask = 022;
- char **margv;
- unsigned int start_wait = 0;
- const char *scheduler = NULL;
- int sched_prio = -1;
-#ifdef HAVE_CAP
- cap_iab_t cap_iab = NULL;
- unsigned secbits = 0;
-#endif
-#ifdef PR_SET_NO_NEW_PRIVS
- bool no_new_privs = false;
-#endif
-
- applet = basename_c(argv[0]);
- atexit(cleanup);
-
- signal_setup(SIGINT, handle_signal);
- signal_setup(SIGQUIT, handle_signal);
- signal_setup(SIGTERM, handle_signal);
-
- if ((tmp = getenv("SSD_NICELEVEL")))
- if (sscanf(tmp, "%d", &nicelevel) != 1)
- eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
- applet, tmp);
- if ((tmp = getenv("SSD_IONICELEVEL"))) {
- int n = sscanf(tmp, "%d:%d", &ionicec, &ioniced);
- if (n != 1 && n != 2)
- eerror("%s: invalid ionice level `%s' (SSD_IONICELEVEL)",
- applet, tmp);
- if (ionicec == 0)
- ioniced = 0;
- else if (ionicec == 3)
- ioniced = 7;
- ionicec <<= 13; /* class shift */
- }
- if ((tmp = getenv("SSD_OOM_SCORE_ADJ")))
- if (sscanf(tmp, "%d", &oom_score_adj) != 1)
- eerror("%s: invalid oom_score_adj `%s' (SSD_OOM_SCORE_ADJ)",
- applet, tmp);
-
- /* Get our user name and initial dir */
- p = getenv("USER");
- home = getenv("HOME");
- if (home == NULL || p == NULL) {
- pw = getpwuid(getuid());
- if (pw != NULL) {
- if (p == NULL)
- setenv("USER", pw->pw_name, 1);
- if (home == NULL) {
- setenv("HOME", pw->pw_dir, 1);
- home = pw->pw_dir;
- }
- }
- }
-
- while ((opt = getopt_long(argc, argv, getoptstring, longopts,
- (int *) 0)) != -1)
- switch (opt) {
- case LONGOPT_CAPABILITIES:
-#ifdef HAVE_CAP
- cap_iab = cap_iab_from_text(optarg);
- if (cap_iab == NULL)
- eerrorx("Could not parse iab: %s", strerror(errno));
-#else
- eerrorx("Capabilities support not enabled");
-#endif
- break;
-
- case LONGOPT_SECBITS:
-#ifdef HAVE_CAP
- if (*optarg == '\0')
- eerrorx("Secbits are empty");
-
- tmp = NULL;
- secbits = strtoul(optarg, &tmp, 0);
- if (*tmp != '\0')
- eerrorx("Could not parse secbits: invalid char %c", *tmp);
-#else
- eerrorx("Capabilities support not enabled");
-#endif
- break;
-
- case LONGOPT_NO_NEW_PRIVS:
-#ifdef PR_SET_NO_NEW_PRIVS
- no_new_privs = true;
-#else
- eerrorx("The No New Privs flag is only supported by Linux (since 3.5)");
-#endif
- break;
-
- case 'I': /* --ionice */
- if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
- eerrorx("%s: invalid ionice `%s'",
- applet, optarg);
- if (ionicec == 0)
- ioniced = 0;
- else if (ionicec == 3)
- ioniced = 7;
- ionicec <<= 13; /* class shift */
- break;
-
- case 'K': /* --stop */
- stop = true;
- break;
-
- case 'N': /* --nice */
- if (sscanf(optarg, "%d", &nicelevel) != 1)
- eerrorx("%s: invalid nice level `%s'",
- applet, optarg);
- break;
-
- case LONGOPT_OOM_SCORE_ADJ: /* --oom-score-adj */
- if (sscanf(optarg, "%d", &oom_score_adj) != 1)
- eerrorx("%s: invalid oom-score-adj `%s'",
- applet, optarg);
- break;
-
- case 'P': /* --progress */
- progress = true;
- break;
-
- case 'R': /* --retry <schedule>|<timeout> */
- retry = optarg;
- break;
-
- case 'S': /* --start */
- start = true;
- break;
-
- case 'b': /* --background */
- background = true;
- break;
-
- case 'c': /* --chuid <username>|<uid> */
- /* DEPRECATED */
- ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead");
- /* falls through */
- case 'u': /* --user <username>|<uid> */
- {
- char dummy[2];
- p = optarg;
- tmp = strsep(&p, ":");
- changeuser = xstrdup(tmp);
- if (sscanf(tmp, "%d%1s", &tid, dummy) != 1)
- pw = getpwnam(tmp);
- else
- pw = getpwuid((uid_t)tid);
-
- if (pw == NULL)
- eerrorx("%s: user `%s' not found",
- applet, tmp);
- uid = pw->pw_uid;
- home = pw->pw_dir;
- unsetenv("HOME");
- if (pw->pw_dir)
- setenv("HOME", pw->pw_dir, 1);
- unsetenv("USER");
- if (pw->pw_name)
- setenv("USER", pw->pw_name, 1);
- if (gid == 0)
- gid = pw->pw_gid;
-
- if (p) {
- tmp = strsep (&p, ":");
- if (sscanf(tmp, "%d%1s", &tid, dummy) != 1)
- gr = getgrnam(tmp);
- else
- gr = getgrgid((gid_t) tid);
-
- if (gr == NULL)
- eerrorx("%s: group `%s'"
- " not found",
- applet, tmp);
- gid = gr->gr_gid;
- }
- }
- break;
-
- case 'd': /* --chdir /new/dir */
- ch_dir = optarg;
- break;
-
- case 'e': /* --env */
- putenv(optarg);
- break;
-
- case 'g': /* --group <group>|<gid> */
- if (sscanf(optarg, "%d", &tid) != 1)
- gr = getgrnam(optarg);
- else
- gr = getgrgid((gid_t)tid);
- if (gr == NULL)
- eerrorx("%s: group `%s' not found",
- applet, optarg);
- gid = gr->gr_gid;
- break;
-
- case 'i': /* --interpreted */
- interpreted = true;
- break;
-
- case 'k':
- if (parse_mode(&numask, optarg))
- eerrorx("%s: invalid mode `%s'",
- applet, optarg);
- break;
-
- case 'm': /* --make-pidfile */
- makepidfile = true;
- break;
-
- case 'n': /* --name <process-name> */
- name = optarg;
- break;
-
- case 'o': /* --oknodo */
- /* DEPRECATED */
- ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future");
- oknodo = true;
- break;
-
- case 'p': /* --pidfile <pid-file> */
- pidfile = optarg;
- break;
-
- case 's': /* --signal <signal> */
- sig = parse_signal(applet, optarg);
- break;
-
- case 't': /* --test */
- test = true;
- break;
-
- case 'r': /* --chroot /new/root */
- ch_root = optarg;
- break;
-
- case 'a': /* --startas <name> */
- /* DEPRECATED */
- ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead");
- startas = optarg;
- break;
- case 'w':
- if (sscanf(optarg, "%u", &start_wait) != 1)
- eerrorx("%s: `%s' not a number",
- applet, optarg);
- break;
- case 'x': /* --exec <executable> */
- exec = optarg;
- break;
-
- case '1': /* --stdout /path/to/stdout.lgfile */
- redirect_stdout = optarg;
- break;
-
- case '2': /* --stderr /path/to/stderr.logfile */
- redirect_stderr = optarg;
- break;
-
- case '3': /* --stdout-logger "command to run for stdout logging" */
- stdout_process = optarg;
- break;
-
- case '4': /* --stderr-logger "command to run for stderr logging" */
- stderr_process = optarg;
- break;
-
- case LONGOPT_SCHEDULER: /* --scheduler "Process scheduler policy" */
- scheduler = optarg;
- break;
-
- case LONGOPT_SCHEDULER_PRIO: /* --scheduler-priority "Process scheduler priority" */
- sscanf(optarg, "%d", &sched_prio);
- break;
-
- case_RC_COMMON_GETOPT
- }
-
- endpwent();
- argc -= optind;
- argv += optind;
-
- /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
- * instead of forcing --stop --oknodo as well */
- if (!start &&
- !stop &&
- sig != SIGINT &&
- sig != SIGTERM &&
- sig != SIGQUIT &&
- sig != SIGKILL)
- oknodo = true;
-
- if (!exec)
- exec = startas;
- else if (!name)
- name = startas;
-
- if (!exec) {
- exec = *argv;
- if (!exec)
- exec = name;
- if (name && start)
- *argv = name;
- } else if (name) {
- *--argv = name;
- ++argc;
- } else if (exec) {
- *--argv = exec;
- ++argc;
- };
-
- if (stop || sig != -1) {
- if (sig == -1)
- sig = SIGTERM;
- if (!*argv && !pidfile && !name && !uid)
- eerrorx("%s: --stop needs --exec, --pidfile,"
- " --name or --user", applet);
- if (background)
- eerrorx("%s: --background is only relevant with"
- " --start", applet);
- if (makepidfile)
- eerrorx("%s: --make-pidfile is only relevant with"
- " --start", applet);
- if (redirect_stdout || redirect_stderr)
- eerrorx("%s: --stdout and --stderr are only relevant"
- " with --start", applet);
- if (stdout_process || stderr_process)
- eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
- " with --start", applet);
- if (start_wait)
- ewarn("using --wait with --stop has no effect,"
- " use --retry instead");
- } else {
- if (!exec)
- eerrorx("%s: nothing to start", applet);
- if (makepidfile && !pidfile)
- eerrorx("%s: --make-pidfile is only relevant with"
- " --pidfile", applet);
- if ((redirect_stdout || redirect_stderr) && !background)
- eerrorx("%s: --stdout and --stderr are only relevant"
- " with --background", applet);
- if ((stdout_process || stderr_process) && !background)
- eerrorx("%s: --stdout-logger and --stderr-logger are only relevant"
- " with --background", applet);
- if (redirect_stdout && stdout_process)
- eerrorx("%s: do not use --stdout and --stdout-logger together",
- applet);
- if (redirect_stderr && stderr_process)
- eerrorx("%s: do not use --stderr and --stderr-logger together",
- applet);
- }
-
- /* Expand ~ */
- if (ch_dir && *ch_dir == '~')
- ch_dir = expand_home(home, ch_dir);
- if (ch_root && *ch_root == '~')
- ch_root = expand_home(home, ch_root);
- if (exec) {
- if (*exec == '~')
- exec = expand_home(home, exec);
-
- /* Validate that the binary exists if we are starting */
- if (*exec == '/' || *exec == '.') {
- /* Full or relative path */
- if (ch_root)
- xasprintf(&exec_file, "%s/%s", ch_root, exec);
- else
- xasprintf(&exec_file, "%s", exec);
- } else {
- /* Something in $PATH */
- p = tmp = xstrdup(getenv("PATH"));
- exec_file = NULL;
- while ((token = strsep(&p, ":"))) {
- if (ch_root)
- xasprintf(&exec_file, "%s/%s/%s", ch_root, token, exec);
- else
- xasprintf(&exec_file, "%s/%s", token, exec);
- if (exec_file && exists(exec_file))
- break;
- free(exec_file);
- exec_file = NULL;
- }
- free(tmp);
- }
- }
- if (start && !exists(exec_file)) {
- eerror("%s: %s does not exist", applet,
- exec_file ? exec_file : exec);
- free(exec_file);
- exit(EXIT_FAILURE);
- }
- if (start && retry)
- ewarn("using --retry with --start has no effect,"
- " use --wait instead");
-
- /* If we don't have a pidfile we should check if it's interpreted
- * or not. If it we, we need to pass the interpreter through
- * to our daemon calls to find it correctly. */
- if (interpreted && !pidfile) {
- fp = fopen(exec_file, "r");
- if (fp) {
- line = NULL;
- if (getline(&line, &size, fp) == -1)
- eerrorx("%s: %s", applet, strerror(errno));
- p = line;
- fclose(fp);
- if (p != NULL && line[0] == '#' && line[1] == '!') {
- p = line + 2;
- /* Strip leading spaces */
- while (*p == ' ' || *p == '\t')
- p++;
- /* Remove the trailing newline */
- len = strlen(p) - 1;
- if (p[len] == '\n')
- p[len] = '\0';
- token = strsep(&p, " ");
- free(exec_file);
- xasprintf(&exec_file, "%s", token);
- opt = 0;
- for (nav = argv; *nav; nav++)
- opt++;
- nav = xmalloc(sizeof(char *) * (opt + 3));
- nav[0] = exec_file;
- len = 1;
- if (p)
- nav[len++] = p;
- for (i = 0; i < opt; i++)
- nav[i + len] = argv[i];
- nav[i + len] = NULL;
- }
- }
- }
- margv = nav ? nav : argv;
-
- if (stop || sig != -1) {
- if (sig == -1)
- sig = SIGTERM;
- if (!stop)
- oknodo = true;
- if (retry)
- parse_schedule(applet, retry, sig);
- else if (test || oknodo)
- parse_schedule(applet, "0", sig);
- else
- parse_schedule(applet, NULL, sig);
- if (pidfile) {
- pid = get_pid(applet, pidfile);
- if (pid == -1 && errno != ENOENT)
- exit(EXIT_FAILURE);
- } else {
- pid = 0;
- }
- i = run_stop_schedule(applet, exec, (const char *const *)margv,
- pid, uid, test, progress, false);
-
- if (i < 0)
- /* We failed to stop something */
- exit(EXIT_FAILURE);
- if (test || oknodo)
- return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-
- /* Even if we have not actually killed anything, we should
- * remove information about it as it may have unexpectedly
- * crashed out. We should also return success as the end
- * result would be the same. */
- if (pidfile && exists(pidfile))
- unlink(pidfile);
- if (svcname)
- rc_service_daemon_set(svcname, exec,
- (const char *const *)argv,
- pidfile, false);
- exit(EXIT_SUCCESS);
- }
-
- if (pidfile)
- pid = get_pid(applet, pidfile);
- else
- pid = 0;
-
- if (pid)
- pids = rc_find_pids(NULL, NULL, 0, pid);
- else
- pids = rc_find_pids(exec, (const char * const *) argv, uid, 0);
- if (pids)
- eerrorx("%s: %s is already running", applet, exec);
-
- free(pids);
- if (test) {
- if (rc_yesno(getenv("EINFO_QUIET")))
- exit (EXIT_SUCCESS);
-
- einfon("Would start");
- while (argc-- > 0)
- printf(" %s", *argv++);
- printf("\n");
- eindent();
- if (uid != 0)
- einfo("as user id %d", uid);
- if (gid != 0)
- einfo("as group id %d", gid);
- if (ch_root)
- einfo("in root `%s'", ch_root);
- if (ch_dir)
- einfo("in dir `%s'", ch_dir);
- if (nicelevel != 0)
- einfo("with a priority of %d", nicelevel);
- if (name)
- einfo ("with a process name of %s", name);
- eoutdent();
- exit(EXIT_SUCCESS);
- }
-
- ebeginv("Detaching to start `%s'", exec);
- eindentv();
-
- /* Remove existing pidfile */
- if (pidfile)
- unlink(pidfile);
-
- if (background)
- signal_setup(SIGCHLD, handle_signal);
-
- if ((pid = fork()) == -1)
- eerrorx("%s: fork: %s", applet, strerror(errno));
-
- /* Child process - lets go! */
- if (pid == 0) {
- pid_t mypid = getpid();
- umask(numask);
-
-#ifdef TIOCNOTTY
- tty_fd = open("/dev/tty", O_RDWR);
-#endif
-
- devnull_fd = open("/dev/null", O_RDWR);
-
- if (nicelevel != INT_MIN) {
- if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1)
- eerrorx("%s: setpriority %d: %s",
- applet, nicelevel,
- strerror(errno));
- }
-
- if (ionicec != -1 &&
- ioprio_set(1, mypid, ionicec | ioniced) == -1)
- eerrorx("%s: ioprio_set %d %d: %s", applet,
- ionicec, ioniced, strerror(errno));
-
- if (oom_score_adj != INT_MIN) {
- fp = fopen("/proc/self/oom_score_adj", "w");
- if (!fp)
- eerrorx("%s: oom_score_adj %d: %s", applet,
- oom_score_adj, strerror(errno));
- fprintf(fp, "%d\n", oom_score_adj);
- fclose(fp);
- }
-
- if (ch_root && chroot(ch_root) < 0)
- eerrorx("%s: chroot `%s': %s",
- applet, ch_root, strerror(errno));
-
- if (ch_dir && chdir(ch_dir) < 0)
- eerrorx("%s: chdir `%s': %s",
- applet, ch_dir, strerror(errno));
-
- if (makepidfile && pidfile) {
- fp = fopen(pidfile, "w");
- if (!fp)
- eerrorx("%s: fopen `%s': %s", applet, pidfile,
- strerror(errno));
- fprintf(fp, "%d\n", mypid);
- fclose(fp);
- }
-
-#ifdef HAVE_PAM
- if (changeuser != NULL) {
- pamr = pam_start("start-stop-daemon",
- changeuser, &conv, &pamh);
-
- if (pamr == PAM_SUCCESS)
- pamr = pam_acct_mgmt(pamh, PAM_SILENT);
- if (pamr == PAM_SUCCESS)
- pamr = pam_open_session(pamh, PAM_SILENT);
- if (pamr != PAM_SUCCESS)
- eerrorx("%s: pam error: %s",
- applet, pam_strerror(pamh, pamr));
- }
-#endif
-
- if (gid && setgid(gid))
- eerrorx("%s: unable to set groupid to %d",
- applet, gid);
- if (changeuser && initgroups(changeuser, gid))
- eerrorx("%s: initgroups (%s, %d)",
- applet, changeuser, gid);
-#ifdef HAVE_CAP
- if (uid && cap_setuid(uid))
-#else
- if (uid && setuid(uid))
-#endif
- eerrorx ("%s: unable to set userid to %d",
- applet, uid);
-
- /* Close any fd's to the passwd database */
- endpwent();
-
-#ifdef HAVE_CAP
- if (cap_iab != NULL) {
- i = cap_iab_set_proc(cap_iab);
-
- if (cap_free(cap_iab) != 0)
- eerrorx("Could not releasable memory: %s", strerror(errno));
-
- if (i != 0)
- eerrorx("Could not set iab: %s", strerror(errno));
- }
-
- if (secbits != 0) {
- if (cap_set_secbits(secbits) < 0)
- eerrorx("Could not set securebits to 0x%x: %s", secbits, strerror(errno));
- }
-#endif
-
-#ifdef PR_SET_NO_NEW_PRIVS
- if (no_new_privs) {
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
- eerrorx("Could not set No New Privs flag: %s", strerror(errno));
- }
-#endif
-
-
-#ifdef TIOCNOTTY
- ioctl(tty_fd, TIOCNOTTY, 0);
- close(tty_fd);
-#endif
-
- /* Clean the environment of any RC_ variables */
- env_list = rc_stringlist_new();
- i = 0;
- while (environ[i])
- rc_stringlist_add(env_list, environ[i++]);
-
-#ifdef HAVE_PAM
- if (changeuser != NULL) {
- pamenv = (const char *const *)pam_getenvlist(pamh);
- if (pamenv) {
- while (*pamenv) {
- /* Don't add strings unless they set a var */
- if (strchr(*pamenv, '='))
- putenv(xstrdup(*pamenv));
- else
- unsetenv(*pamenv);
- pamenv++;
- }
- }
- }
-#endif
-
- TAILQ_FOREACH(env, env_list, entries) {
- if ((strncmp(env->value, "RC_", 3) == 0 &&
- strncmp(env->value, "RC_SERVICE=", 11) != 0 &&
- strncmp(env->value, "RC_SVCNAME=", 11) != 0) ||
- strncmp(env->value, "SSD_NICELEVEL=", 14) == 0 ||
- strncmp(env->value, "SSD_IONICELEVEL=", 16) == 0 ||
- strncmp(env->value, "SSD_OOM_SCORE_ADJ=", 18) == 0)
- {
- p = strchr(env->value, '=');
- *p = '\0';
- unsetenv(env->value);
- continue;
- }
- }
- rc_stringlist_free(env_list);
-
- /* For the path, remove the rcscript bin dir from it */
- if ((token = getenv("PATH"))) {
- len = strlen(token);
- newpath = np = xmalloc(len + 1);
- while (token && *token) {
- p = strchr(token, ':');
- if (p) {
- *p++ = '\0';
- while (*p == ':')
- p++;
- }
- if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
- strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
- {
- len = strlen(token);
- if (np != newpath)
- *np++ = ':';
- memcpy(np, token, len);
- np += len;
- }
- token = p;
- }
- *np = '\0';
- unsetenv("PATH");
- setenv("PATH", newpath, 1);
- }
-
- stdin_fd = devnull_fd;
- stdout_fd = devnull_fd;
- stderr_fd = devnull_fd;
- if (redirect_stdout) {
- if ((stdout_fd = open(redirect_stdout,
- O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
- eerrorx("%s: unable to open the logfile"
- " for stdout `%s': %s",
- applet, redirect_stdout, strerror(errno));
- }else if (stdout_process) {
- stdout_fd = rc_pipe_command(stdout_process);
- if (stdout_fd == -1)
- eerrorx("%s: unable to open the logging process"
- " for stdout `%s': %s",
- applet, stdout_process, strerror(errno));
- }
- if (redirect_stderr) {
- if ((stderr_fd = open(redirect_stderr,
- O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
- eerrorx("%s: unable to open the logfile"
- " for stderr `%s': %s",
- applet, redirect_stderr, strerror(errno));
- }else if (stderr_process) {
- stderr_fd = rc_pipe_command(stderr_process);
- if (stderr_fd == -1)
- eerrorx("%s: unable to open the logging process"
- " for stderr `%s': %s",
- applet, stderr_process, strerror(errno));
- }
-
- if (background)
- dup2(stdin_fd, STDIN_FILENO);
- if (background || redirect_stdout || stdout_process
- || rc_yesno(getenv("EINFO_QUIET")))
- dup2(stdout_fd, STDOUT_FILENO);
- if (background || redirect_stderr || stderr_process
- || rc_yesno(getenv("EINFO_QUIET")))
- dup2(stderr_fd, STDERR_FILENO);
-
- for (i = getdtablesize() - 1; i >= 3; --i)
- close(i);
-
- if (scheduler != NULL) {
- int scheduler_index;
- struct sched_param sched = {.sched_priority = sched_prio};
- if (strcmp(scheduler, "fifo") == 0)
- scheduler_index = SCHED_FIFO;
- else if (strcmp(scheduler, "rr") == 0)
- scheduler_index = SCHED_RR;
- else if (strcmp(scheduler, "other") == 0)
- scheduler_index = SCHED_OTHER;
-#ifdef SCHED_BATCH
- else if (strcmp(scheduler, "batch") == 0)
- scheduler_index = SCHED_BATCH;
-#endif
-#ifdef SCHED_IDLE
- else if (strcmp(scheduler, "idle") == 0)
- scheduler_index = SCHED_IDLE;
-#endif
- else if (sscanf(scheduler, "%d", &scheduler_index) != 1)
- eerrorx("Unknown scheduler: %s", scheduler);
-
- if (sched_prio == -1)
- sched.sched_priority = sched_get_priority_min(scheduler_index);
-
- if (sched_setscheduler(mypid, scheduler_index, &sched))
- eerrorx("Failed to set scheduler: %s", strerror(errno));
- } else if (sched_prio != -1) {
- const struct sched_param sched = {.sched_priority = sched_prio};
- if (sched_setparam(mypid, &sched))
- eerrorx("Failed to set scheduler parameters: %s", strerror(errno));
- }
-
- setsid();
- execvp(exec, argv);
-#ifdef HAVE_PAM
- if (changeuser != NULL && pamr == PAM_SUCCESS)
- pam_close_session(pamh, PAM_SILENT);
-#endif
- eerrorx("%s: failed to exec `%s': %s",
- applet, exec,strerror(errno));
- }
-
- /* Parent process */
- if (!background) {
- /* As we're not backgrounding the process, wait for our pid
- * to return */
- i = 0;
- spid = pid;
-
- do {
- pid = waitpid(spid, &i, 0);
- if (pid < 1) {
- eerror("waitpid %d: %s",
- spid, strerror(errno));
- return -1;
- }
- } while (!WIFEXITED(i) && !WIFSIGNALED(i));
- if (!WIFEXITED(i) || WEXITSTATUS(i) != 0) {
- eerror("%s: failed to start `%s'", applet, exec);
- exit(EXIT_FAILURE);
- }
- pid = spid;
- }
-
- /* Wait a little bit and check that process is still running
- We do this as some badly written daemons fork and then barf */
- if (start_wait == 0 &&
- ((p = getenv("SSD_STARTWAIT")) ||
- (p = rc_conf_value("rc_start_wait"))))
- {
- if (sscanf(p, "%u", &start_wait) != 1)
- start_wait = 0;
- }
-
- if (start_wait > 0) {
- struct timespec ts;
- bool alive = false;
-
- ts.tv_sec = start_wait / 1000;
- ts.tv_nsec = (start_wait % 1000) * ONE_MS;
- if (nanosleep(&ts, NULL) == -1) {
- if (errno != EINTR) {
- eerror("%s: nanosleep: %s",
- applet, strerror(errno));
- return 0;
- }
- }
- if (background) {
- if (kill(pid, 0) == 0)
- alive = true;
- } else {
- if (pidfile) {
- pid = get_pid(applet, pidfile);
- if (pid == -1) {
- eerrorx("%s: did not "
- "create a valid"
- " pid in `%s'",
- applet, pidfile);
- }
- } else
- pid = 0;
- if (do_stop(applet, exec, (const char *const *)margv,
- pid, uid, 0, test, false) > 0)
- alive = true;
- }
-
- if (!alive)
- eerrorx("%s: %s died", applet, exec);
- }
-
- if (svcname)
- rc_service_daemon_set(svcname, exec,
- (const char *const *)margv, pidfile, true);
-
- exit(EXIT_SUCCESS);
- /* NOTREACHED */
-}
diff --git a/src/rc/start-stop-daemon.pam b/src/rc/start-stop-daemon.pam
deleted file mode 100644
index a1bada22..00000000
--- a/src/rc/start-stop-daemon.pam
+++ /dev/null
@@ -1,6 +0,0 @@
-#%PAM-1.0
-
-auth required pam_permit.so
-account required pam_permit.so
-password required pam_deny.so
-session optional pam_limits.so
diff --git a/src/rc/supervise-daemon.c b/src/rc/supervise-daemon.c
deleted file mode 100644
index 93deedcd..00000000
--- a/src/rc/supervise-daemon.c
+++ /dev/null
@@ -1,1250 +0,0 @@
-/*
- * supervise-daemon
- * This is a supervisor for daemons.
- * It will start a deamon and make sure it restarts if it crashes.
- */
-
-/*
- * Copyright (c) 2016 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-/* nano seconds */
-#define POLL_INTERVAL 20000000
-#define WAIT_PIDFILE 500000000
-#define ONE_SECOND 1000000000
-#define ONE_MS 1000000
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <termios.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#ifdef __linux__
-#include <sys/syscall.h> /* For io priority */
-#include <sys/prctl.h> /* For prctl */
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <grp.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <time.h>
-#include <unistd.h>
-
-#ifdef HAVE_PAM
-#include <security/pam_appl.h>
-
-/* We are not supporting authentication conversations */
-static struct pam_conv conv = { NULL, NULL};
-#endif
-
-#ifdef HAVE_CAP
-#include <sys/capability.h>
-#endif
-
-#include "einfo.h"
-#include "queue.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "rc-plugin.h"
-#include "rc-schedules.h"
-#include "_usage.h"
-#include "helpers.h"
-
-/* Use long option value that is out of range for 8 bit getopt values.
- * The exact enum value is internal and can freely change, so we keep the
- * options sorted.
- */
-enum {
- /* This has to come first so following values stay in the 0x100+ range. */
- LONGOPT_BASE = 0x100,
-
- LONGOPT_CAPABILITIES,
- LONGOPT_OOM_SCORE_ADJ,
- LONGOPT_NO_NEW_PRIVS,
- LONGOPT_SECBITS,
-};
-
-const char *applet = NULL;
-const char *extraopts = NULL;
-const char getoptstring[] = "A:a:D:d:e:g:H:I:Kk:m:N:p:R:r:s:Su:1:2:3" \
- getoptstring_COMMON;
-const struct option longopts[] = {
- { "healthcheck-timer", 1, NULL, 'a'},
- { "healthcheck-delay", 1, NULL, 'A'},
- { "capabilities", 1, NULL, LONGOPT_CAPABILITIES},
- { "secbits", 1, NULL, LONGOPT_SECBITS},
- { "no-new-privs", 0, NULL, LONGOPT_NO_NEW_PRIVS},
- { "respawn-delay", 1, NULL, 'D'},
- { "chdir", 1, NULL, 'd'},
- { "env", 1, NULL, 'e'},
- { "group", 1, NULL, 'g'},
- { "ionice", 1, NULL, 'I'},
- { "stop", 0, NULL, 'K'},
- { "umask", 1, NULL, 'k'},
- { "respawn-max", 1, NULL, 'm'},
- { "nicelevel", 1, NULL, 'N'},
- { "oom-score-adj",1, NULL, LONGOPT_OOM_SCORE_ADJ},
- { "pidfile", 1, NULL, 'p'},
- { "respawn-period", 1, NULL, 'P'},
- { "retry", 1, NULL, 'R'},
- { "chroot", 1, NULL, 'r'},
- { "signal", 1, NULL, 's'},
- { "start", 0, NULL, 'S'},
- { "user", 1, NULL, 'u'},
- { "stdout", 1, NULL, '1'},
- { "stderr", 1, NULL, '2'},
- { "reexec", 0, NULL, '3'},
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "set an initial health check delay",
- "set a health check timer",
- "Set the inheritable, ambient and bounding capabilities",
- "Set the security-bits for the program",
- "Set the No New Privs flag for the program",
- "Set a respawn delay",
- "Change the PWD",
- "Set an environment string",
- "Change the process group",
- "Set an ionice class:data when starting",
- "Stop daemon",
- "Set the umask for the daemon",
- "set maximum number of respawn attempts",
- "Set a nicelevel when starting",
- "Set OOM score adjustment when starting",
- "Match pid found in this file",
- "Set respawn time period",
- "Retry schedule to use when stopping",
- "Chroot to this directory",
- "Send a signal to the daemon",
- "Start daemon",
- "Change the process user",
- "Redirect stdout to file",
- "Redirect stderr to file",
- "reexec (used internally)",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-static int healthcheckdelay = 0;
-static int healthchecktimer = 0;
-static volatile sig_atomic_t do_healthcheck = 0;
-static volatile sig_atomic_t exiting = 0;
-static int nicelevel = INT_MIN;
-static int ionicec = -1;
-static int ioniced = 0;
-static int oom_score_adj = INT_MIN;
-static char *changeuser, *ch_root, *ch_dir;
-static uid_t uid = 0;
-static gid_t gid = 0;
-static int devnull_fd = -1;
-static int stdin_fd;
-static int stdout_fd;
-static int stderr_fd;
-static char *redirect_stderr = NULL;
-static char *redirect_stdout = NULL;
-#ifdef TIOCNOTTY
-static int tty_fd = -1;
-#endif
-static pid_t child_pid;
-static int respawn_count = 0;
-static int respawn_delay = 0;
-static int respawn_max = 10;
-static int respawn_period = 0;
-static char *fifopath = NULL;
-static int fifo_fd = 0;
-static char *pidfile = NULL;
-static char *svcname = NULL;
-static bool verbose = false;
-#ifdef HAVE_CAP
-static cap_iab_t cap_iab = NULL;
-static unsigned secbits = 0;
-#endif
-#ifdef PR_SET_NO_NEW_PRIVS
-static bool no_new_privs = false;
-#endif
-
-extern char **environ;
-
-#if !defined(SYS_ioprio_set) && defined(__NR_ioprio_set)
-# define SYS_ioprio_set __NR_ioprio_set
-#endif
-#if !defined(__DragonFly__)
-static inline int ioprio_set(int which _unused, int who _unused,
- int ioprio _unused)
-{
-#ifdef SYS_ioprio_set
- return syscall(SYS_ioprio_set, which, who, ioprio);
-#else
- return 0;
-#endif
-}
-#endif
-
-static void cleanup(void)
-{
- free(changeuser);
-}
-
-static void re_exec_supervisor(void)
-{
- syslog(LOG_WARNING, "Re-executing for %s", svcname);
- execlp("supervise-daemon", "supervise-daemon", svcname, "--reexec",
- (char *) NULL);
- syslog(LOG_ERR, "Unable to execute supervise-daemon: %s",
- strerror(errno));
- exit(EXIT_FAILURE);
-}
-
-static void handle_signal(int sig)
-{
- int serrno = errno;
- pid_t pid;
-
- switch (sig) {
- case SIGALRM:
- do_healthcheck = 1;
- break;
- case SIGCHLD:
- if (exiting)
- while (waitpid((pid_t)(-1), NULL, WNOHANG) > 0) {}
- else {
- while ((pid = waitpid((pid_t)(-1), NULL, WNOHANG|WNOWAIT)) > 0) {
- if (pid == child_pid)
- break;
- pid = waitpid(pid, NULL, WNOHANG);
- }
- }
- break;
- case SIGTERM:
- exiting = 1;
- break;
- default:
- syslog(LOG_WARNING, "caught signal %d", sig);
- re_exec_supervisor();
- }
- /* Restore errno */
- errno = serrno;
-}
-
-static char * expand_home(const char *home, const char *path)
-{
- char *opath, *ppath, *p, *nh;
- struct passwd *pw;
-
- if (!path || *path != '~')
- return xstrdup(path);
-
- opath = ppath = xstrdup(path);
- if (ppath[1] != '/' && ppath[1] != '\0') {
- p = strchr(ppath + 1, '/');
- if (p)
- *p = '\0';
- pw = getpwnam(ppath + 1);
- if (pw) {
- home = pw->pw_dir;
- ppath = p;
- if (ppath)
- *ppath = '/';
- } else
- home = NULL;
- } else
- ppath++;
-
- if (!home) {
- free(opath);
- return xstrdup(path);
- }
- if (!ppath) {
- free(opath);
- return xstrdup(home);
- }
-
- xasprintf(&nh, "%s%s", home, ppath);
- free(opath);
- return nh;
-}
-
-static char *make_cmdline(char **argv)
-{
- char **c;
- char *cmdline = NULL;
- size_t len = 0;
-
- for (c = argv; c && *c; c++)
- len += (strlen(*c) + 1);
- cmdline = xmalloc(len+1);
- memset(cmdline, 0, len+1);
- for (c = argv; c && *c; c++) {
- strcat(cmdline, *c);
- strcat(cmdline, " ");
- }
- return cmdline;
-}
-
-static pid_t exec_command(const char *cmd)
-{
- char *file;
- pid_t pid = -1;
- sigset_t full;
- sigset_t old;
- struct sigaction sa;
-
- file = rc_service_resolve(svcname);
- if (!exists(file)) {
- free(file);
- return 0;
- }
-
- /* We need to block signals until we have forked */
- memset(&sa, 0, sizeof (sa));
- sa.sa_handler = SIG_DFL;
- sigemptyset(&sa.sa_mask);
- sigfillset(&full);
- sigprocmask(SIG_SETMASK, &full, &old);
-
- pid = fork();
- if (pid == 0) {
- /* Restore default handlers */
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- sigaction(SIGUSR1, &sa, NULL);
- sigaction(SIGWINCH, &sa, NULL);
-
- /* Unmask signals */
- sigprocmask(SIG_SETMASK, &old, NULL);
-
- /* Safe to run now */
- execl(file, file, cmd, (char *) NULL);
- syslog(LOG_ERR, "unable to exec `%s': %s\n",
- file, strerror(errno));
- _exit(EXIT_FAILURE);
- }
-
- if (pid == -1)
- syslog(LOG_ERR, "fork: %s\n",strerror (errno));
-
- sigprocmask(SIG_SETMASK, &old, NULL);
- free(file);
- return pid;
-}
-
-static void child_process(char *exec, char **argv)
-{
- RC_STRINGLIST *env_list;
- RC_STRING *env;
- int i;
- char *p;
- char *token;
- size_t len;
- char *newpath;
- char *np;
- char *cmdline = NULL;
- time_t start_time;
- char start_count_string[20];
- char start_time_string[20];
- FILE *fp;
-
-#ifdef HAVE_PAM
- pam_handle_t *pamh = NULL;
- int pamr;
- const char *const *pamenv = NULL;
-#endif
-
- setsid();
-
- if (svcname) {
- start_time = time(NULL);
- from_time_t(start_time_string, start_time);
- rc_service_value_set(svcname, "start_time", start_time_string);
- sprintf(start_count_string, "%i", respawn_count);
- rc_service_value_set(svcname, "start_count", start_count_string);
- sprintf(start_count_string, "%d", getpid());
- rc_service_value_set(svcname, "child_pid", start_count_string);
- }
-
- if (nicelevel != INT_MIN) {
- if (setpriority(PRIO_PROCESS, getpid(), nicelevel) == -1)
- eerrorx("%s: setpriority %d: %s", applet, nicelevel,
- strerror(errno));
- }
-
- if (ionicec != -1 && ioprio_set(1, getpid(), ionicec | ioniced) == -1)
- eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced,
- strerror(errno));
-
- if (oom_score_adj != INT_MIN) {
- fp = fopen("/proc/self/oom_score_adj", "w");
- if (!fp)
- eerrorx("%s: oom_score_adj %d: %s", applet,
- oom_score_adj, strerror(errno));
- fprintf(fp, "%d\n", oom_score_adj);
- fclose(fp);
- }
-
- if (ch_root && chroot(ch_root) < 0)
- eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno));
-
- if (ch_dir && chdir(ch_dir) < 0)
- eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));
-
-#ifdef HAVE_PAM
- if (changeuser != NULL) {
- pamr = pam_start("supervise-daemon",
- changeuser, &conv, &pamh);
-
- if (pamr == PAM_SUCCESS)
- pamr = pam_acct_mgmt(pamh, PAM_SILENT);
- if (pamr == PAM_SUCCESS)
- pamr = pam_open_session(pamh, PAM_SILENT);
- if (pamr != PAM_SUCCESS)
- eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr));
- }
-#endif
-
- if (gid && setgid(gid))
- eerrorx("%s: unable to set groupid to %d", applet, gid);
- if (changeuser && initgroups(changeuser, gid))
- eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid);
-#ifdef HAVE_CAP
- if (uid && cap_setuid(uid))
-#else
- if (uid && setuid(uid))
-#endif
- eerrorx ("%s: unable to set userid to %d", applet, uid);
-
- /* Close any fd's to the passwd database */
- endpwent();
-
-#ifdef HAVE_CAP
- if (cap_iab != NULL) {
- i = cap_iab_set_proc(cap_iab);
-
- if (cap_free(cap_iab) != 0)
- eerrorx("Could not releasable memory: %s", strerror(errno));
-
- if (i != 0)
- eerrorx("Could not set iab: %s", strerror(errno));
- }
-
- if (secbits != 0) {
- if (cap_set_secbits(secbits) < 0)
- eerrorx("Could not set securebits to 0x%x: %s", secbits, strerror(errno));
- }
-#endif
-
-#ifdef PR_SET_NO_NEW_PRIVS
- if (no_new_privs) {
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
- eerrorx("Could not set No New Privs flag: %s", strerror(errno));
- }
-#endif
-
- /* remove the controlling tty */
-#ifdef TIOCNOTTY
- ioctl(tty_fd, TIOCNOTTY, 0);
- close(tty_fd);
-#endif
-
- /* Clean the environment of any RC_ variables */
- env_list = rc_stringlist_new();
- i = 0;
- while (environ[i])
- rc_stringlist_add(env_list, environ[i++]);
-
-#ifdef HAVE_PAM
- if (changeuser != NULL) {
- pamenv = (const char *const *)pam_getenvlist(pamh);
- if (pamenv) {
- while (*pamenv) {
- /* Don't add strings unless they set a var */
- if (strchr(*pamenv, '='))
- putenv(xstrdup(*pamenv));
- else
- unsetenv(*pamenv);
- pamenv++;
- }
- }
- }
-#endif
-
- TAILQ_FOREACH(env, env_list, entries) {
- if ((strncmp(env->value, "RC_", 3) == 0 &&
- strncmp(env->value, "RC_SERVICE=", 11) != 0 &&
- strncmp(env->value, "RC_SVCNAME=", 11) != 0) ||
- strncmp(env->value, "SSD_NICELEVEL=", 14) == 0 ||
- strncmp(env->value, "SSD_IONICELEVEL=", 16) == 0 ||
- strncmp(env->value, "SSD_OOM_SCORE_ADJ=", 18) == 0)
- {
- p = strchr(env->value, '=');
- *p = '\0';
- unsetenv(env->value);
- continue;
- }
- }
- rc_stringlist_free(env_list);
-
- /* For the path, remove the rcscript bin dir from it */
- if ((token = getenv("PATH"))) {
- len = strlen(token);
- newpath = np = xmalloc(len + 1);
- while (token && *token) {
- p = strchr(token, ':');
- if (p) {
- *p++ = '\0';
- while (*p == ':')
- p++;
- }
- if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 &&
- strcmp(token, RC_LIBEXECDIR "/sbin") != 0)
- {
- len = strlen(token);
- if (np != newpath)
- *np++ = ':';
- memcpy(np, token, len);
- np += len;
- }
- token = p;
- }
- *np = '\0';
- unsetenv("PATH");
- setenv("PATH", newpath, 1);
- }
-
- stdin_fd = devnull_fd;
- stdout_fd = devnull_fd;
- stderr_fd = devnull_fd;
- if (redirect_stdout) {
- if ((stdout_fd = open(redirect_stdout,
- O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR)) == -1)
- eerrorx("%s: unable to open the logfile"
- " for stdout `%s': %s",
- applet, redirect_stdout, strerror(errno));
- }
- if (redirect_stderr) {
- if ((stderr_fd = open(redirect_stderr,
- O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR)) == -1)
- eerrorx("%s: unable to open the logfile"
- " for stderr `%s': %s",
- applet, redirect_stderr, strerror(errno));
- }
-
- dup2(stdin_fd, STDIN_FILENO);
- if (redirect_stdout || rc_yesno(getenv("EINFO_QUIET")))
- dup2(stdout_fd, STDOUT_FILENO);
- if (redirect_stderr || rc_yesno(getenv("EINFO_QUIET")))
- dup2(stderr_fd, STDERR_FILENO);
-
- for (i = getdtablesize() - 1; i >= 3; --i)
- fcntl(i, F_SETFD, FD_CLOEXEC);
- cmdline = make_cmdline(argv);
- syslog(LOG_INFO, "Child command line: %s", cmdline);
- free(cmdline);
- execvp(exec, argv);
-
-#ifdef HAVE_PAM
- if (changeuser != NULL && pamr == PAM_SUCCESS)
- pam_close_session(pamh, PAM_SILENT);
-#endif
- eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno));
-}
-
-static void supervisor(char *exec, char **argv)
-{
- FILE *fp;
- char buf[2048];
- char cmd[2048];
- int count;
- int failing;
- int health_status;
- int healthcheck_respawn;
- int i;
- int nkilled;
- int sig_send;
- pid_t health_pid;
- pid_t wait_pid;
- sigset_t old_signals;
- sigset_t signals;
- struct sigaction sa;
- struct timespec ts;
- time_t respawn_now= 0;
- time_t first_spawn= 0;
-
- /* block all signals we do not handle */
- sigfillset(&signals);
- sigdelset(&signals, SIGALRM);
- sigdelset(&signals, SIGCHLD);
- sigdelset(&signals, SIGTERM);
- sigprocmask(SIG_SETMASK, &signals, &old_signals);
-
- /* install signal handler */
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = handle_signal;
- sigaction(SIGALRM, &sa, NULL);
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
-
- fp = fopen(pidfile, "w");
- if (!fp)
- eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
- fprintf(fp, "%d\n", getpid());
- fclose(fp);
-
- if (svcname)
- rc_service_daemon_set(svcname, exec, (const char * const *) argv,
- pidfile, true);
-
- /* remove the controlling tty */
-#ifdef TIOCNOTTY
- ioctl(tty_fd, TIOCNOTTY, 0);
- close(tty_fd);
-#endif
-
- /*
- * Supervisor main loop
- */
- if (healthcheckdelay)
- alarm(healthcheckdelay);
- else if (healthchecktimer)
- alarm(healthchecktimer);
- failing = 0;
- while (!exiting) {
- healthcheck_respawn = 0;
- fifo_fd = open(fifopath, O_RDONLY);
- if (fifo_fd > 0) {
- memset(buf, 0, sizeof(buf));
- count = read(fifo_fd, buf, sizeof(buf) - 1);
- close(fifo_fd);
- if (count != -1)
- buf[count] = 0;
- if (count == 0)
- continue;
- if (verbose)
- syslog(LOG_DEBUG, "Received %s from fifo", buf);
- if (strncasecmp(buf, "sig", 3) == 0) {
- if ((sscanf(buf, "%s %d", cmd, &sig_send) == 2)
- && (sig_send >= 0 && sig_send < NSIG)) {
- syslog(LOG_INFO, "Sending signal %d to %d", sig_send,
- child_pid);
- if (kill(child_pid, sig_send) == -1)
- syslog(LOG_ERR, "Unable to send signal %d to %d",
- sig_send, child_pid);
- }
- }
- continue;
- }
- if (do_healthcheck) {
- do_healthcheck = 0;
- alarm(0);
- if (verbose)
- syslog(LOG_DEBUG, "running health check for %s", svcname);
- health_pid = exec_command("healthcheck");
- health_status = rc_waitpid(health_pid);
- if (WIFEXITED(health_status) && WEXITSTATUS(health_status) == 0)
- alarm(healthchecktimer);
- else {
- syslog(LOG_WARNING, "health check for %s failed", svcname);
- health_pid = exec_command("unhealthy");
- rc_waitpid(health_pid);
- syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
- nkilled = run_stop_schedule(applet, NULL, NULL, child_pid, 0,
- false, false, true);
- if (nkilled < 0)
- syslog(LOG_INFO, "Unable to kill %d: %s",
- child_pid, strerror(errno));
- else
- healthcheck_respawn = 1;
- }
- }
- if (exiting) {
- alarm(0);
- syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid);
- nkilled = run_stop_schedule(applet, NULL, NULL, child_pid, 0,
- false, false, true);
- if (nkilled > 0)
- syslog(LOG_INFO, "killed %d processes", nkilled);
- continue;
- }
- wait_pid = waitpid(child_pid, &i, WNOHANG);
- if (wait_pid == child_pid) {
- if (WIFEXITED(i))
- syslog(LOG_WARNING, "%s, pid %d, exited with return code %d",
- exec, child_pid, WEXITSTATUS(i));
- else if (WIFSIGNALED(i))
- syslog(LOG_WARNING, "%s, pid %d, terminated by signal %d",
- exec, child_pid, WTERMSIG(i));
- }
- if (wait_pid == child_pid || healthcheck_respawn) {
- do_healthcheck = 0;
- healthcheck_respawn = 0;
- alarm(0);
- respawn_now = time(NULL);
- if (first_spawn == 0)
- first_spawn = respawn_now;
- if ((respawn_period > 0)
- && (respawn_now - first_spawn > respawn_period)) {
- respawn_count = 0;
- first_spawn = 0;
- } else
- respawn_count++;
- if (respawn_max > 0 && respawn_count > respawn_max) {
- syslog(LOG_WARNING, "respawned \"%s\" too many times, exiting",
- exec);
- exiting = 1;
- failing = 1;
- continue;
- }
- ts.tv_sec = respawn_delay;
- ts.tv_nsec = 0;
- nanosleep(&ts, NULL);
- if (exiting)
- continue;
- child_pid = fork();
- if (child_pid == -1) {
- syslog(LOG_ERR, "%s: fork: %s", applet, strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (child_pid == 0) {
- sigprocmask(SIG_SETMASK, &old_signals, NULL);
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
- sigaction(SIGALRM, &sa, NULL);
- sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- child_process(exec, argv);
- }
- if (healthcheckdelay)
- alarm(healthcheckdelay);
- else if (healthchecktimer)
- alarm(healthchecktimer);
- }
- }
-
- if (svcname) {
- rc_service_daemon_set(svcname, exec, (const char *const *)argv,
- pidfile, false);
- rc_service_value_set(svcname, "child_pid", NULL);
- rc_service_mark(svcname, RC_SERVICE_STOPPED);
- if (failing)
- rc_service_mark(svcname, RC_SERVICE_FAILED);
- }
- if (pidfile && exists(pidfile))
- unlink(pidfile);
- if (fifopath && exists(fifopath))
- unlink(fifopath);
- exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char **argv)
-{
- int opt;
- char **c;
- int x;
- bool start = false;
- bool stop = false;
- bool reexec = false;
- bool sendsig = false;
- char *exec = NULL;
- char *retry = NULL;
- int sig = SIGTERM;
- char *home = NULL;
- int tid = 0;
- pid_t pid;
- char *tmp;
- char *p;
- char *token;
- int i;
- int n;
- char *exec_file = NULL;
- char *varbuf = NULL;
- struct timespec ts;
- struct passwd *pw;
- struct group *gr;
- FILE *fp;
- mode_t numask = 022;
- int child_argc = 0;
- char **child_argv = NULL;
- char *str = NULL;
- char *cmdline = NULL;
-
- applet = basename_c(argv[0]);
- atexit(cleanup);
- svcname = getenv("RC_SVCNAME");
- if (!svcname)
- eerrorx("%s: The RC_SVCNAME environment variable is not set", applet);
- openlog(applet, LOG_PID, LOG_DAEMON);
-
- if (argc <= 1 || strcmp(argv[1], svcname))
- eerrorx("%s: the first argument is %s and must be %s",
- applet, argv[1], svcname);
-
- if ((tmp = getenv("SSD_NICELEVEL")))
- if (sscanf(tmp, "%d", &nicelevel) != 1)
- eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
- applet, tmp);
- if ((tmp = getenv("SSD_IONICELEVEL"))) {
- int n = sscanf(tmp, "%d:%d", &ionicec, &ioniced);
- if (n != 1 && n != 2)
- eerror("%s: invalid ionice level `%s' (SSD_IONICELEVEL)",
- applet, tmp);
- if (ionicec == 0)
- ioniced = 0;
- else if (ionicec == 3)
- ioniced = 7;
- ionicec <<= 13; /* class shift */
- }
- if ((tmp = getenv("SSD_OOM_SCORE_ADJ")))
- if (sscanf(tmp, "%d", &oom_score_adj) != 1)
- eerror("%s: invalid oom_score_adj `%s' (SSD_OOM_SCORE_ADJ)",
- applet, tmp);
-
- /* Get our user name and initial dir */
- p = getenv("USER");
- home = getenv("HOME");
- if (home == NULL || p == NULL) {
- pw = getpwuid(getuid());
- if (pw != NULL) {
- if (p == NULL)
- setenv("USER", pw->pw_name, 1);
- if (home == NULL) {
- setenv("HOME", pw->pw_dir, 1);
- home = pw->pw_dir;
- }
- }
- }
-
- cmdline = make_cmdline(argv);
- if (svcname) {
- argc--;
- argv++;
- }
- while ((opt = getopt_long(argc, argv, getoptstring, longopts,
- (int *) 0)) != -1)
- switch (opt) {
- case 'a': /* --healthcheck-timer <time> */
- if (sscanf(optarg, "%d", &healthchecktimer) != 1 || healthchecktimer < 1)
- eerrorx("%s: invalid health check timer %s", applet, optarg);
- break;
-
- case 'A': /* --healthcheck-delay <time> */
- if (sscanf(optarg, "%d", &healthcheckdelay) != 1 || healthcheckdelay < 1)
- eerrorx("%s: invalid health check delay %s", applet, optarg);
- break;
-
- case LONGOPT_CAPABILITIES:
-#ifdef HAVE_CAP
- cap_iab = cap_iab_from_text(optarg);
- if (cap_iab == NULL)
- eerrorx("Could not parse iab: %s", strerror(errno));
-#else
- eerrorx("Capabilities support not enabled");
-#endif
- break;
-
- case LONGOPT_SECBITS:
-#ifdef HAVE_CAP
- if (*optarg == '\0')
- eerrorx("Secbits are empty");
-
- tmp = NULL;
- secbits = strtoul(optarg, &tmp, 0);
- if (*tmp != '\0')
- eerrorx("Could not parse secbits: invalid char %c", *tmp);
-#else
- eerrorx("Capabilities support not enabled");
-#endif
- break;
-
- case LONGOPT_NO_NEW_PRIVS:
-#ifdef PR_SET_NO_NEW_PRIVS
- no_new_privs = true;
-#else
- eerrorx("The No New Privs flag is only supported by Linux (since 3.5)");
-#endif
- break;
-
- case 'D': /* --respawn-delay time */
- n = sscanf(optarg, "%d", &respawn_delay);
- if (n != 1 || respawn_delay < 1)
- eerrorx("Invalid respawn-delay value '%s'", optarg);
- break;
-
- case 'I': /* --ionice */
- if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0)
- eerrorx("%s: invalid ionice `%s'",
- applet, optarg);
- if (ionicec == 0)
- ioniced = 0;
- else if (ionicec == 3)
- ioniced = 7;
- ionicec <<= 13; /* class shift */
- break;
-
- case 'K': /* --stop */
- stop = true;
- break;
-
- case 'N': /* --nice */
- if (sscanf(optarg, "%d", &nicelevel) != 1)
- eerrorx("%s: invalid nice level `%s'",
- applet, optarg);
- break;
-
- case LONGOPT_OOM_SCORE_ADJ: /* --oom-score-adj */
- if (sscanf(optarg, "%d", &oom_score_adj) != 1)
- eerrorx("%s: invalid oom-score-adj `%s'",
- applet, optarg);
- break;
-
- case 'P': /* --respawn-period time */
- n = sscanf(optarg, "%d", &respawn_period);
- if (n != 1 || respawn_period < 1)
- eerrorx("Invalid respawn-period value '%s'", optarg);
- break;
-
- case 's': /* --signal */
- sig = parse_signal(applet, optarg);
- sendsig = true;
- break;
- case 'S': /* --start */
- start = true;
- break;
-
- case 'd': /* --chdir /new/dir */
- ch_dir = optarg;
- break;
-
- case 'e': /* --env */
- putenv(optarg);
- break;
-
- case 'g': /* --group <group>|<gid> */
- if (sscanf(optarg, "%d", &tid) != 1)
- gr = getgrnam(optarg);
- else
- gr = getgrgid((gid_t)tid);
- if (gr == NULL)
- eerrorx("%s: group `%s' not found",
- applet, optarg);
- gid = gr->gr_gid;
- break;
-
- case 'H': /* --healthcheck-timer <minutes> */
- if (sscanf(optarg, "%d", &healthchecktimer) != 1 || healthchecktimer < 1)
- eerrorx("%s: invalid health check timer %s", applet, optarg);
- break;
-
- case 'k':
- if (parse_mode(&numask, optarg))
- eerrorx("%s: invalid mode `%s'",
- applet, optarg);
- break;
-
- case 'm': /* --respawn-max count */
- n = sscanf(optarg, "%d", &respawn_max);
- if (n != 1 || respawn_max < 0)
- eerrorx("Invalid respawn-max value '%s'", optarg);
- break;
-
- case 'p': /* --pidfile <pid-file> */
- pidfile = optarg;
- break;
-
- case 'R': /* --retry <schedule>|timeout */
- retry = optarg;
- break;
- case 'r': /* --chroot /new/root */
- ch_root = optarg;
- break;
-
- case 'u': /* --user <username>|<uid> */
- {
- char dummy[2];
- p = optarg;
- tmp = strsep(&p, ":");
- changeuser = xstrdup(tmp);
- if (sscanf(tmp, "%d%1s", &tid, dummy) != 1)
- pw = getpwnam(tmp);
- else
- pw = getpwuid((uid_t)tid);
-
- if (pw == NULL)
- eerrorx("%s: user `%s' not found",
- applet, tmp);
- uid = pw->pw_uid;
- home = pw->pw_dir;
- unsetenv("HOME");
- if (pw->pw_dir)
- setenv("HOME", pw->pw_dir, 1);
- unsetenv("USER");
- if (pw->pw_name)
- setenv("USER", pw->pw_name, 1);
- if (gid == 0)
- gid = pw->pw_gid;
-
- if (p) {
- tmp = strsep (&p, ":");
- if (sscanf(tmp, "%d%1s", &tid, dummy) != 1)
- gr = getgrnam(tmp);
- else
- gr = getgrgid((gid_t) tid);
-
- if (gr == NULL)
- eerrorx("%s: group `%s'"
- " not found",
- applet, tmp);
- gid = gr->gr_gid;
- }
- }
- break;
-
- case '1': /* --stdout /path/to/stdout.lgfile */
- redirect_stdout = optarg;
- break;
-
- case '2': /* --stderr /path/to/stderr.logfile */
- redirect_stderr = optarg;
- break;
- case '3': /* --reexec */
- reexec = true;
- break;
-
- case_RC_COMMON_GETOPT
- }
-
- verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
- endpwent();
- argc -= optind;
- argv += optind;
- exec = *argv;
-
- /* Expand ~ */
- if (ch_dir && *ch_dir == '~')
- ch_dir = expand_home(home, ch_dir);
- if (ch_root && *ch_root == '~')
- ch_root = expand_home(home, ch_root);
-
- umask(numask);
- if (!pidfile)
- xasprintf(&pidfile, "/var/run/supervise-%s.pid", svcname);
- xasprintf(&fifopath, "%s/supervise-%s.ctl", RC_SVCDIR, svcname);
- if (mkfifo(fifopath, 0600) == -1 && errno != EEXIST)
- eerrorx("%s: unable to create control fifo: %s",
- applet, strerror(errno));
-
- if (reexec) {
- str = rc_service_value_get(svcname, "argc");
- sscanf(str, "%d", &child_argc);
- child_argv = xmalloc((child_argc + 1) * sizeof(char *));
- memset(child_argv, 0, (child_argc + 1) * sizeof(char *));
- for (x = 0; x < child_argc; x++) {
- xasprintf(&varbuf, "argv_%d", x);
- str = rc_service_value_get(svcname, varbuf);
- child_argv[x] = str;
- free(varbuf);
- varbuf = NULL;
- }
- free(str);
- str = rc_service_value_get(svcname, "child_pid");
- sscanf(str, "%d", &child_pid);
- free(str);
- exec = rc_service_value_get(svcname, "exec");
- pidfile = rc_service_value_get(svcname, "pidfile");
- retry = rc_service_value_get(svcname, "retry");
- if (retry) {
- parse_schedule(applet, retry, sig);
- rc_service_value_set(svcname, "retry", retry);
- } else
- parse_schedule(applet, NULL, sig);
-
- str = rc_service_value_get(svcname, "respawn_delay");
- sscanf(str, "%d", &respawn_delay);
- str = rc_service_value_get(svcname, "respawn_max");
- sscanf(str, "%d", &respawn_max);
- supervisor(exec, child_argv);
- } else if (start) {
- if (exec) {
- if (*exec == '~')
- exec = expand_home(home, exec);
-
- /* Validate that the binary exists if we are starting */
- if (*exec == '/' || *exec == '.') {
- /* Full or relative path */
- if (ch_root)
- xasprintf(&exec_file, "%s/%s", ch_root, exec);
- else
- xasprintf(&exec_file, "%s", exec);
- } else {
- /* Something in $PATH */
- p = tmp = xstrdup(getenv("PATH"));
- exec_file = NULL;
- while ((token = strsep(&p, ":"))) {
- if (ch_root)
- xasprintf(&exec_file, "%s/%s/%s", ch_root, token, exec);
- else
- xasprintf(&exec_file, "%s/%s", token, exec);
- if (exec_file && exists(exec_file))
- break;
- free(exec_file);
- exec_file = NULL;
- }
- free(tmp);
- }
- if (!exists(exec_file)) {
- eerror("%s: %s does not exist", applet,
- exec_file ? exec_file : exec);
- free(exec_file);
- exit(EXIT_FAILURE);
- }
- } else
- eerrorx("%s: nothing to start", applet);
-
- pid = get_pid(applet, pidfile);
- if (pid != -1)
- if (do_stop(applet, exec, (const char * const *)argv, pid, uid,
- 0, false, true) > 0)
- eerrorx("%s: %s is already running", applet, exec);
-
- if (respawn_period > 0 && respawn_delay * respawn_max > respawn_period)
- ewarn("%s: Please increase the value of --respawn-period to more "
- "than %d to avoid infinite respawning", applet,
- respawn_delay * respawn_max);
-
- if (retry) {
- parse_schedule(applet, retry, sig);
- rc_service_value_set(svcname, "retry", retry);
- } else
- parse_schedule(applet, NULL, sig);
-
- einfov("Detaching to start `%s'", exec);
- syslog(LOG_INFO, "Supervisor command line: %s", cmdline);
- free(cmdline);
- cmdline = NULL;
-
- /* Remove existing pidfile */
- if (pidfile)
- unlink(pidfile);
-
- /* Make sure we can write a pid file */
- fp = fopen(pidfile, "w");
- if (!fp)
- eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
- fclose(fp);
-
- rc_service_value_set(svcname, "pidfile", pidfile);
- varbuf = NULL;
- xasprintf(&varbuf, "%i", respawn_delay);
- rc_service_value_set(svcname, "respawn_delay", varbuf);
- free(varbuf);
- xasprintf(&varbuf, "%i", respawn_max);
- rc_service_value_set(svcname, "respawn_max", varbuf);
- free(varbuf);
- xasprintf(&varbuf, "%i", respawn_period);
- rc_service_value_set(svcname, "respawn_period", varbuf);
- free(varbuf);
- child_pid = fork();
- if (child_pid == -1)
- eerrorx("%s: fork: %s", applet, strerror(errno));
- if (child_pid != 0)
- /* first parent process, do nothing. */
- exit(EXIT_SUCCESS);
-#ifdef TIOCNOTTY
- tty_fd = open("/dev/tty", O_RDWR);
-#endif
- devnull_fd = open("/dev/null", O_RDWR);
- dup2(devnull_fd, STDIN_FILENO);
- dup2(devnull_fd, STDOUT_FILENO);
- dup2(devnull_fd, STDERR_FILENO);
- child_pid = fork();
- if (child_pid == -1)
- eerrorx("%s: fork: %s", applet, strerror(errno));
- else if (child_pid != 0) {
- c = argv;
- x = 0;
- while (c && *c) {
- varbuf = NULL;
- xasprintf(&varbuf, "argv_%-d",x);
- rc_service_value_set(svcname, varbuf, *c);
- free(varbuf);
- varbuf = NULL;
- x++;
- c++;
- }
- xasprintf(&varbuf, "%d", x);
- rc_service_value_set(svcname, "argc", varbuf);
- free(varbuf);
- rc_service_value_set(svcname, "exec", exec);
- supervisor(exec, argv);
- } else
- child_process(exec, argv);
- } else if (stop) {
- pid = get_pid(applet, pidfile);
- if (pid != -1) {
- i = kill(pid, SIGTERM);
- if (i != 0)
- /* We failed to send the signal */
- ewarn("Unable to shut down the supervisor");
- else {
- /* wait for the supervisor to go down */
- while (kill(pid, 0) == 0) {
- ts.tv_sec = 0;
- ts.tv_nsec = 1;
- nanosleep(&ts, NULL);
- }
- }
- }
-
- /* Even if we have not actually killed anything, we should
- * remove information about it as it may have unexpectedly
- * crashed out. We should also return success as the end
- * result would be the same. */
- if (pidfile && exists(pidfile))
- unlink(pidfile);
- if (svcname) {
- rc_service_daemon_set(svcname, exec,
- (const char *const *)argv,
- pidfile, false);
- rc_service_mark(svcname, RC_SERVICE_STOPPED);
- }
- exit(EXIT_SUCCESS);
- } else if (sendsig) {
- fifo_fd = open(fifopath, O_WRONLY |O_NONBLOCK);
- if (fifo_fd < 0)
- eerrorx("%s: unable to open control fifo %s", applet, strerror(errno));
- xasprintf(&str, "sig %d", sig);
- x = write(fifo_fd, str, strlen(str));
- if (x == -1) {
- free(tmp);
- eerrorx("%s: error writing to control fifo: %s", applet,
- strerror(errno));
- }
- free(tmp);
- exit(EXIT_SUCCESS);
- }
-}
diff --git a/src/rc/supervise-daemon.pam b/src/rc/supervise-daemon.pam
deleted file mode 100644
index a1bada22..00000000
--- a/src/rc/supervise-daemon.pam
+++ /dev/null
@@ -1,6 +0,0 @@
-#%PAM-1.0
-
-auth required pam_permit.so
-account required pam_permit.so
-password required pam_deny.so
-session optional pam_limits.so
diff --git a/src/rc/swclock.c b/src/rc/swclock.c
deleted file mode 100644
index 7f63d680..00000000
--- a/src/rc/swclock.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * swclock.c
- * Sets the system time from the mtime of the given file.
- * This is useful for systems who do not have a working RTC and rely on ntp.
- * OpenRC relies on the correct system time for a lot of operations
- * so this is needed quite early.
- */
-
-/*
- * Copyright (c) 2007-2015 The OpenRC Authors.
- * See the Authors file at the top-level directory of this distribution and
- * https://github.com/OpenRC/openrc/blob/HEAD/AUTHORS
- *
- * This file is part of OpenRC. It is subject to the license terms in
- * the LICENSE file found in the top-level directory of this
- * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE
- * This file may not be copied, modified, propagated, or distributed
- * except according to the terms contained in the LICENSE file.
- */
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <utime.h>
-
-#include "einfo.h"
-#include "rc.h"
-#include "rc-misc.h"
-#include "_usage.h"
-
-#define RC_SHUTDOWNTIME RC_SVCDIR "/shutdowntime"
-
-const char *applet = NULL;
-const char *extraopts = "file";
-const char getoptstring[] = "sw" getoptstring_COMMON;
-const struct option longopts[] = {
- { "save", 0, NULL, 's' },
- { "warn", 0, NULL, 'w' },
- longopts_COMMON
-};
-const char * const longopts_help[] = {
- "saves the time",
- "no error if no reference file",
- longopts_help_COMMON
-};
-const char *usagestring = NULL;
-
-int main(int argc, char **argv)
-{
- int opt, sflag = 0, wflag = 0;
- const char *file = RC_SHUTDOWNTIME;
- struct stat sb;
- struct timeval tv;
-
- applet = basename_c(argv[0]);
- while ((opt = getopt_long(argc, argv, getoptstring,
- longopts, (int *) 0)) != -1)
- {
- switch (opt) {
- case 's':
- sflag = 1;
- break;
- case 'w':
- wflag = 1;
- break;
- case_RC_COMMON_GETOPT
- }
- }
-
- if (optind < argc)
- file = argv[optind++];
-
- if (sflag) {
- if (stat(file, &sb) == -1) {
- opt = open(file, O_WRONLY | O_CREAT, 0644);
- if (opt == -1)
- eerrorx("swclock: open: %s", strerror(errno));
- close(opt);
- } else
- if (utime(file, NULL) == -1)
- eerrorx("swclock: utime: %s", strerror(errno));
- return 0;
- }
-
- if (stat(file, &sb) == -1) {
- if (wflag != 0 && errno == ENOENT)
- ewarn("swclock: `%s': %s", file, strerror(errno));
- else
- eerrorx("swclock: `%s': %s", file, strerror(errno));
- return 0;
- }
-
- tv.tv_sec = sb.st_mtime;
- tv.tv_usec = 0;
-
- if (settimeofday(&tv, NULL) == -1)
- eerrorx("swclock: settimeofday: %s", strerror(errno));
-
- return 0;
-}