From bf2f40828ee26d3ba9185f29db596ee5d7b9cf61 Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Wed, 23 Dec 2015 14:06:31 -0600 Subject: [PATCH] Remove multicall binary structure from OpenRC This eliminates the need for the selinux-specific wrapper scrript we were installing in /lib*/rc/{bin,sbin}. --- src/includes/helpers.h | 17 ++ src/includes/rc-misc.h | 24 +- src/rc/Makefile | 133 ++++++--- src/rc/_usage.c | 32 ++- src/rc/_usage.h | 13 + src/rc/builtins.h | 34 --- src/rc/checkpath.c | 59 ++-- src/rc/do_e.c | 228 +++++++++++++++ src/rc/do_mark_service.c | 91 ++++++ src/rc/do_service.c | 78 ++++++ src/rc/do_value.c | 64 +++++ src/rc/fstabinfo.c | 55 ++-- src/rc/is_newer_than.c | 33 +++ src/rc/is_older_than.c | 34 +++ src/rc/mountinfo.c | 80 +++--- src/rc/openrc-run.c | 59 ++-- src/rc/rc-abort.c | 43 +++ src/rc/rc-applets.c | 557 ------------------------------------- src/rc/rc-depend.c | 72 +---- src/rc/rc-misc.c | 107 +++++++ src/rc/rc-selinux.c | 4 + src/rc/rc-service.c | 28 +- src/rc/rc-status.c | 86 ++---- src/rc/rc-update.c | 46 ++- src/rc/rc.c | 55 ++-- src/rc/shell_var.c | 41 +++ src/rc/start-stop-daemon.c | 133 ++++----- src/rc/swclock.c | 21 +- 28 files changed, 1160 insertions(+), 1067 deletions(-) delete mode 100644 src/rc/builtins.h create mode 100644 src/rc/do_e.c create mode 100644 src/rc/do_mark_service.c create mode 100644 src/rc/do_service.c create mode 100644 src/rc/do_value.c create mode 100644 src/rc/is_newer_than.c create mode 100644 src/rc/is_older_than.c create mode 100644 src/rc/rc-abort.c delete mode 100644 src/rc/rc-applets.c create mode 100644 src/rc/shell_var.c diff --git a/src/includes/helpers.h b/src/includes/helpers.h index c541f99a..1a00d3d0 100644 --- a/src/includes/helpers.h +++ b/src/includes/helpers.h @@ -53,6 +53,9 @@ } while (/* CONSTCOND */ 0) #endif +#include +#include + _unused static void *xmalloc (size_t size) { void *value = malloc(size); @@ -104,4 +107,18 @@ _unused static const char *basename_c(const char *path) return (path); } +_unused static bool exists(const char *pathname) +{ + struct stat buf; + + return (stat(pathname, &buf) == 0); +} + +_unused static bool existss(const char *pathname) +{ + struct stat buf; + + return (stat(pathname, &buf) == 0 && buf.st_size != 0); +} + #endif diff --git a/src/includes/rc-misc.h b/src/includes/rc-misc.h index 89d6336b..96166341 100644 --- a/src/includes/rc-misc.h +++ b/src/includes/rc-misc.h @@ -26,6 +26,7 @@ #include #include "helpers.h" +#include "rc.h" #define RC_LEVEL_BOOT "boot" #define RC_LEVEL_DEFAULT "default" @@ -41,20 +42,6 @@ #define RC_SVCDIR_STARTED RC_SVCDIR "/started" #define RC_SVCDIR_COLDPLUGGED RC_SVCDIR "/coldplugged" -_unused static bool exists(const char *pathname) -{ - struct stat buf; - - return (stat(pathname, &buf) == 0); -} - -_unused static bool existss(const char *pathname) -{ - struct stat buf; - - return (stat(pathname, &buf) == 0 && buf.st_size != 0); -} - char *rc_conf_value(const char *var); bool rc_conf_yesno(const char *var); void env_filter(void); @@ -78,4 +65,13 @@ const char *detect_prefix(void); const char *get_systype(void); const char *detect_container(void); const char *detect_vm(void); + +/* Handy function so we can wrap einfo around our deptree */ +RC_DEPTREE *_rc_deptree_load (int, int *); + +/* Test to see if we can see pid 1 or not */ +bool _rc_can_find_pids(void); + +RC_SERVICE lookup_service_state(const char *service); + #endif diff --git a/src/rc/Makefile b/src/rc/Makefile index 65b58113..1df26d86 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -1,8 +1,4 @@ -PROG= openrc -SRCS= checkpath.c fstabinfo.c mountinfo.c openrc-run.c \ - rc-applets.c rc-depend.c rc-logger.c \ - rc-misc.c rc-plugin.c rc-service.c rc-status.c rc-update.c \ - rc.c start-stop-daemon.c swclock.c +SRCS= rc.c rc-logger.c rc-misc.c rc-plugin.c ifeq (${MKSELINUX},yes) SRCS+= rc-selinux.c @@ -14,26 +10,26 @@ BINDIR= ${PREFIX}/bin SBINDIR= ${PREFIX}/sbin LINKDIR= ${LIBEXECDIR} -BINLINKS= rc-status -SBINLINKS= rc rc-service rc-update openrc-run runscript service \ - start-stop-daemon -RC_BINLINKS= 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 rc-depend \ - service_get_value service_set_value get_options save_options \ - shell_var is_newer_than is_older_than -RC_SBINLINKS= mark_service_starting mark_service_started \ +BINPROGS= rc-status +SBINPROGS = openrc openrc-run rc rc-service rc-update runscript service start-stop-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 \ rc-abort swclock -ALL_LINKS= ${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS} -CLEANFILES+= ${ALL_LINKS} +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 @@ -49,22 +45,6 @@ include ${MK}/termcap.mk LDADD+= ${LIBDL} ${LIBKVM} include ${MK}/pam.mk -# create symlinks to rc if not an SELINUX system, otherwise create a wrapper -# script to call rc with the proper name of the applet to execute. -# $1 is a list of the links -# $2 is the path+name of the target to link to (usually 'rc' or '/sbin/rc') -# $3 is the path where the links are created -define make-links - for x in $(1); do \ - if [ "${MKSELINUX}" = yes ]; then \ - printf '#!/bin/sh\nexec ${2} --applet %s "$$@"\n' $$x >${3}/$$x; \ - chmod ${BINMODE} ${3}/$$x; \ - else \ - ln -sf ${2} ${3}/$$x; \ - fi; \ - done; -endef - ${SRCS}: version.h .PHONY: version.h.tmp @@ -79,15 +59,13 @@ version.h: version.h.tmp install: all ${INSTALL} -d ${DESTDIR}${SBINDIR} - ${INSTALL} -m ${BINMODE} ${PROG} ${DESTDIR}${SBINDIR} + ${INSTALL} -m ${BINMODE} ${SBINPROGS} ${DESTDIR}${SBINDIR} ${INSTALL} -d ${DESTDIR}${BINDIR} - $(call make-links,${BINLINKS},${SBINDIR}/${PROG},${DESTDIR}${BINDIR}) - ${INSTALL} -d ${DESTDIR}${SBINDIR} - $(call make-links,${SBINLINKS},${SBINDIR}/${PROG},${DESTDIR}${SBINDIR}) + ${INSTALL} -m ${BINMODE} ${BINPROGS} ${DESTDIR}${BINDIR} ${INSTALL} -d ${DESTDIR}${LINKDIR}/bin - $(call make-links,${RC_BINLINKS},${SBINDIR}/${PROG},${DESTDIR}${LINKDIR}/bin) + ${INSTALL} -m ${BINMODE} ${RC_BINPROGS} ${DESTDIR}${LINKDIR}/bin ${INSTALL} -d ${DESTDIR}${LINKDIR}/sbin - $(call make-links, ${RC_SBINLINKS},${SBINDIR}/${PROG},${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; \ @@ -95,5 +73,70 @@ install: all check test:: -links: ${PROG} - $(call make-links,${ALL_LINKS},${PROG},.) +all: ${ALL_PROGS} + +checkpath: checkpath.o _usage.o rc-misc.o rc-selinux.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} + +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: 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 rc-selinux.o _usage.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + +openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o + ${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 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 + ${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} diff --git a/src/rc/_usage.c b/src/rc/_usage.c index e190eb40..f0c7f0fc 100644 --- a/src/rc/_usage.c +++ b/src/rc/_usage.c @@ -10,8 +10,12 @@ * except according to the terms contained in the LICENSE file. */ -#include "version.h" #include +#include +#include +#include "rc-misc.h" +#include "_usage.h" +#include "version.h" #if lint # define _noreturn @@ -22,7 +26,7 @@ # define _noreturn #endif -static void set_quiet_options(void) +void set_quiet_options(void) { static int qcount = 0; @@ -37,8 +41,7 @@ static void set_quiet_options(void) } } -_noreturn static void -show_version(void) +_noreturn void show_version(void) { const char *systype = NULL; @@ -56,8 +59,7 @@ show_version(void) exit(EXIT_SUCCESS); } -_noreturn static void -usage(int exit_status) +_noreturn void usage(int exit_status) { const char * const has_arg[] = { "", "", "[arg]" }; int i; @@ -67,15 +69,15 @@ usage(int exit_status) char *token; char val[4] = "-?,"; -#ifdef usagestring - printf(usagestring); -#else - printf("Usage: %s [options] ", applet); -#endif -#ifdef extraopts - printf(extraopts); -#endif - printf("\n\nOptions: [" getoptstring "]\n"); + 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 : "", diff --git a/src/rc/_usage.h b/src/rc/_usage.h index dc859098..fd20971b 100644 --- a/src/rc/_usage.h +++ b/src/rc/_usage.h @@ -10,6 +10,8 @@ * except according to the terms contained in the LICENSE file. */ +#include + #define getoptstring_COMMON "ChqVv" #define longopts_COMMON \ @@ -41,3 +43,14 @@ 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/builtins.h b/src/rc/builtins.h deleted file mode 100644 index ce2828f2..00000000 --- a/src/rc/builtins.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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/master/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/master/LICENSE - * This file may not be copied, modified, propagated, or distributed - * except according to the terms contained in the LICENSE file. - */ - -#include "queue.h" -#include "rc.h" - -int checkpath(int, char **); -int fstabinfo(int, char **); -int mountinfo(int, char **); -int openrc_run(int, char **); -int rc_depend(int, char **); -int rc_service(int, char **); -int rc_status(int, char **); -int rc_update(int, char **); -int runscript(int, char **); -int start_stop_daemon(int, char **); -int swclock(int, char **); - -void run_applets(int, char **); - -/* Handy function so we can wrap einfo around our deptree */ -RC_DEPTREE *_rc_deptree_load (int, int *); - -/* Test to see if we can see pid 1 or not */ -bool _rc_can_find_pids(void); diff --git a/src/rc/checkpath.c b/src/rc/checkpath.c index b5a85891..c44ffe8d 100644 --- a/src/rc/checkpath.c +++ b/src/rc/checkpath.c @@ -29,10 +29,10 @@ #include #include -#include "builtins.h" #include "einfo.h" #include "rc-misc.h" #include "rc-selinux.h" +#include "_usage.h" typedef enum { inode_unknown = 0, @@ -41,7 +41,32 @@ typedef enum { inode_fifo = 3, } inode_t; -extern const char *applet; +const char *applet = NULL; +const char *extraopts ="path1 [path2] [...]"; +const char *getoptstring = "dDfFpm:o:W" 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'}, + { "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)", + "Check whether the path is writable or not", + longopts_help_COMMON +}; +const char *usagestring = NULL; static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, inode_t type, bool trunc, bool chowner, bool selinux_on) @@ -187,34 +212,7 @@ static int parse_owner(struct passwd **user, struct group **group, return retval; } -#include "_usage.h" -#define extraopts "path1 [path2] [...]" -#define getoptstring "dDfFpm:o:W" getoptstring_COMMON -static 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'}, - { "writable", 0, NULL, 'W'}, - longopts_COMMON -}; -static 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)", - "Check whether the path is writable or not", - longopts_help_COMMON -}; -#include "_usage.c" - -int checkpath(int argc, char **argv) +int main(int argc, char **argv) { int opt; uid_t uid = geteuid(); @@ -229,6 +227,7 @@ int checkpath(int argc, char **argv) bool writable = false; bool selinux_on = false; + applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { diff --git a/src/rc/do_e.c b/src/rc/do_e.c new file mode 100644 index 00000000..426087e9 --- /dev/null +++ b/src/rc/do_e.c @@ -0,0 +1,228 @@ +/* + * 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/master/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/master/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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, CODE *codetab) +{ + 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 new file mode 100644 index 00000000..fea31eec --- /dev/null +++ b/src/rc/do_mark_service.c @@ -0,0 +1,91 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 new file mode 100644 index 00000000..3c39d35f --- /dev/null +++ b/src/rc/do_service.c @@ -0,0 +1,78 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + 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_can_find_pids() && + 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 new file mode 100644 index 00000000..a511afd9 --- /dev/null +++ b/src/rc/do_value.c @@ -0,0 +1,64 @@ +/* + * 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/master/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/master/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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.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 index b132c5c3..bd2372d6 100644 --- a/src/rc/fstabinfo.c +++ b/src/rc/fstabinfo.c @@ -55,11 +55,36 @@ # define ENT_PASS(_ent) ent->fs_passno #endif -#include "builtins.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 = "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 * @@ -129,30 +154,6 @@ do_mount(struct ENT *ent, bool remount) } } -#include "_usage.h" -#define getoptstring "MRbmop:t:" getoptstring_COMMON -static 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 -}; -static 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 -}; -#include "_usage.c" - #define OUTPUT_FILE (1 << 1) #define OUTPUT_MOUNTARGS (1 << 2) #define OUTPUT_OPTIONS (1 << 3) @@ -161,8 +162,7 @@ static const char * const longopts_help[] = { #define OUTPUT_MOUNT (1 << 6) #define OUTPUT_REMOUNT (1 << 7) -int -fstabinfo(int argc, char **argv) +int main(int argc, char **argv) { struct ENT *ent; int result = EXIT_SUCCESS; @@ -181,6 +181,7 @@ fstabinfo(int argc, char **argv) /* 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) { diff --git a/src/rc/is_newer_than.c b/src/rc/is_newer_than.c new file mode 100644 index 00000000..f1aa9d61 --- /dev/null +++ b/src/rc/is_newer_than.c @@ -0,0 +1,33 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include + +#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 new file mode 100644 index 00000000..87d56414 --- /dev/null +++ b/src/rc/is_older_than.c @@ -0,0 +1,34 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include + +#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/mountinfo.c b/src/rc/mountinfo.c index 2b8171df..10e3238d 100644 --- a/src/rc/mountinfo.c +++ b/src/rc/mountinfo.c @@ -39,13 +39,48 @@ #include #include -#include "builtins.h" #include "einfo.h" #include "queue.h" #include "rc.h" #include "rc-misc.h" +#include "_usage.h" -extern const char *applet; +const char *applet = NULL; +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, @@ -334,45 +369,7 @@ get_regex(const char *string) return reg; } -#include "_usage.h" -#define extraopts "[mount1] [mount2] ..." -#define getoptstring "f:F:n:N:o:O:p:P:iste:E:" getoptstring_COMMON -static 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 -}; -static 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 -}; -#include "_usage.c" - -int -mountinfo(int argc, char **argv) +int main(int argc, char **argv) { struct args args; regex_t *point_regex = NULL; @@ -390,6 +387,7 @@ mountinfo(int argc, char **argv) #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; diff --git a/src/rc/openrc-run.c b/src/rc/openrc-run.c index e414450d..757412a5 100644 --- a/src/rc/openrc-run.c +++ b/src/rc/openrc-run.c @@ -47,13 +47,13 @@ # include #endif -#include "builtins.h" #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" @@ -61,7 +61,29 @@ #define WAIT_TIMEOUT 60 /* seconds until we timeout */ #define WARN_TIMEOUT 10 /* warn about this every N seconds */ -static const char *applet; +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; @@ -1063,31 +1085,7 @@ service_plugable(void) return allow; } -#include "_usage.h" -#define getoptstring "dDsSvl:Z" getoptstring_COMMON -#define extraopts "stop | start | restart | describe | zap" -static 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 -}; -static 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 -}; -#include "_usage.c" - -int -openrc_run(int argc, char **argv) +int main(int argc, char **argv) { bool doneone = false; int retval, opt, depoptions = RC_DEP_TRACE; @@ -1396,10 +1394,3 @@ openrc_run(int argc, char **argv) return retval; } - -int -runscript(int argc, char **argv) -{ - ewarnv("runscript is deprecated; please use openrc-run instead."); - return (openrc_run(argc, argv)); -} diff --git a/src/rc/rc-abort.c b/src/rc/rc-abort.c new file mode 100644 index 00000000..c81abe71 --- /dev/null +++ b/src/rc/rc-abort.c @@ -0,0 +1,43 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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-applets.c b/src/rc/rc-applets.c deleted file mode 100644 index ed86a4d8..00000000 --- a/src/rc/rc-applets.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * rc-applets.c - * - * Handle multicall applets for use in our init scripts. - * Basically this makes us a lot faster for the most part, and removes - * any shell incompatabilities we might otherwise encounter. -*/ - -/* - * 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/master/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/master/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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "builtins.h" -#include "einfo.h" -#include "rc-misc.h" - -/* usecs to wait while we poll the file existance */ -#define WAIT_INTERVAL 20000000 -#define ONE_SECOND 690000000 - -/* Applet is first parsed in rc.c - no point in doing it again */ -extern const char *applet; - -static int -syslog_decode(char *name, CODE *codetab) -{ - 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; -} - -static int -do_e(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; - - /* Punt applet */ - 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; -} - -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, }, -}; - -static 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; -} - -static int -do_service(int argc, char **argv) -{ - bool ok = false; - char *service; - char *exec; - int idx; - RC_SERVICE state, bit; - - 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_can_find_pids() && - rc_service_daemons_crashed(service) && - errno != EACCES); - } else - eerrorx("%s: unknown applet", applet); - - return ok ? EXIT_SUCCESS : EXIT_FAILURE; -} - -static int -do_mark_service(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; */ - - 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; -} - -static int -do_value(int argc, char **argv) -{ - bool ok = false; - char *service = getenv("RC_SVCNAME"); - char *option; - - 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; -} - -static int -shell_var(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; -} - -static int -is_older_than(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; -} - -static int -is_newer_than(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; -} - -static int -is_runlevel_start(_unused int argc, _unused char **argv) -{ - return rc_runlevel_starting() ? 0 : 1; -} - -static int -is_runlevel_stop(_unused int argc, _unused char **argv) -{ - return rc_runlevel_stopping() ? 0 : 1; -} - -static int -rc_abort(_unused int argc, _unused char **argv) -{ - 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; -} - -static const struct { - const char * const name; - int (* const applet)(int argc, char **argv); -} applets[] = { -#define A(a) { #a, a } - A(fstabinfo), - A(mountinfo), - { "openrc-run", openrc_run, }, - { "rc-depend", rc_depend, }, - { "rc-service", rc_service, }, - { "rc-status", rc_status, }, - { "rc-update", rc_update, }, - { "service", rc_service, }, - { "update-rc", rc_update, }, - A(runscript), - { "start-stop-daemon", start_stop_daemon, }, - A(checkpath), - A(swclock), - A(shell_var), - A(is_older_than), - A(is_newer_than), - A(is_runlevel_start), - A(is_runlevel_stop), - { "rc-abort", rc_abort, }, - /* These are purely for init scripts and do not make sense as - * anything else */ - { "service_get_value", do_value, }, - { "service_set_value", do_value, }, - { "get_options", do_value, }, - { "save_options", do_value, }, -#undef A -}; - -void -run_applets(int argc, char **argv) -{ - size_t i; - - /* - * The "rc" applet is deprecated and should be referred to as - * "openrc", so output a warning. - */ - if (strcmp(applet, "rc") == 0) - ewarnv("The 'rc' applet is deprecated; please use 'openrc' instead."); - /* Bug 351712: We need an extra way to explicitly select an applet OTHER - * than trusting argv[0], as argv[0] is not going to be the applet value if - * we are doing SELinux context switching. For this, we allow calls such as - * 'rc --applet APPLET', and shift ALL of argv down by two array items. */ - if ((strcmp(applet, "rc") == 0 || strcmp(applet, "openrc") == 0) && - argc >= 3 && - (strcmp(argv[1],"--applet") == 0 || strcmp(argv[1], "-a") == 0)) { - applet = argv[2]; - argv += 2; - argc -= 2; - } - - for (i = 0; i < ARRAY_SIZE(applets); ++i) - if (!strcmp(applet, applets[i].name)) - exit(applets[i].applet(argc, argv)); - - if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) - exit(do_e(argc, argv)); - - if (strncmp(applet, "service_", strlen("service_")) == 0) - exit(do_service(argc, argv)); - - if (strncmp(applet, "mark_service_", strlen("mark_service_")) == 0) - exit(do_mark_service(argc, argv)); - - if (strcmp(applet, "rc") != 0 && strcmp(applet, "openrc") != 0) - eerrorx("%s: unknown applet", applet); -} diff --git a/src/rc/rc-depend.c b/src/rc/rc-depend.c index fdc6c332..51c6a5e1 100644 --- a/src/rc/rc-depend.c +++ b/src/rc/rc-depend.c @@ -31,70 +31,16 @@ #include #include -#include "builtins.h" #include "einfo.h" #include "queue.h" #include "rc.h" #include "rc-misc.h" - -extern const char *applet; - -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) { - stat(RC_DEPTREE_CACHE, &st); - 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(); -} - #include "_usage.h" -#define getoptstring "aot:suTF:" getoptstring_COMMON -static const struct option longopts[] = { + +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'}, @@ -104,7 +50,7 @@ static const struct option longopts[] = { { "deptree-file", 1, NULL, 'F'}, longopts_COMMON }; -static const char * const longopts_help[] = { +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", @@ -114,10 +60,9 @@ static const char * const longopts_help[] = { "File to load cached deptree from", longopts_help_COMMON }; -#include "_usage.c" +const char *usagestring = NULL; -int -rc_depend(int argc, char **argv) +int main(int argc, char **argv) { RC_STRINGLIST *list; RC_STRINGLIST *types; @@ -132,6 +77,7 @@ rc_depend(int argc, char **argv) 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) diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c index f2f4d9f0..6dfa4235 100644 --- a/src/rc/rc-misc.c +++ b/src/rc/rc-misc.c @@ -23,6 +23,7 @@ # include #endif +#include #include #include #include @@ -31,7 +32,9 @@ #include #include #include +#include #include +#include #include "einfo.h" #include "queue.h" @@ -488,3 +491,107 @@ const char *detect_vm(void) return NULL; } + +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) { + stat(RC_DEPTREE_CACHE, &st); + 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(); +} + +bool _rc_can_find_pids(void) +{ + RC_PIDLIST *pids; + RC_PID *pid; + RC_PID *pid2; + bool retval = false; + + if (geteuid() == 0) + return true; + + /* If we cannot see process 1, then we don't test to see if + * services crashed or not */ + pids = rc_find_pids(NULL, NULL, 0, 1); + if (pids) { + pid = LIST_FIRST(pids); + if (pid) { + retval = true; + while (pid) { + pid2 = LIST_NEXT(pid, entries); + free(pid); + pid = pid2; + } + } + free(pids); + } + return retval; +} + +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, }, +}; + +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; +} diff --git a/src/rc/rc-selinux.c b/src/rc/rc-selinux.c index ed89be1e..3e484a67 100644 --- a/src/rc/rc-selinux.c +++ b/src/rc/rc-selinux.c @@ -15,6 +15,8 @@ * except according to the terms contained in the LICENSE file. */ +#ifdef HAVE_SELINUX + #include #include #include @@ -384,3 +386,5 @@ out: free(run_init_t); free(curr_t); } + +#endif diff --git a/src/rc/rc-service.c b/src/rc/rc-service.c index 6b03767b..8e9da446 100644 --- a/src/rc/rc-service.c +++ b/src/rc/rc-service.c @@ -21,39 +21,36 @@ #include #include -#include "builtins.h" #include "einfo.h" #include "queue.h" #include "rc.h" #include "rc-misc.h" - -extern char *applet; - #include "_usage.h" -#define usagestring "" \ - "Usage: rc-service [options] [-i] ...\n" \ - " or: rc-service [options] -e \n" \ - " or: rc-service [options] -l\n" \ - " or: rc-service [options] -r " -#define getoptstring "e:ilr:" getoptstring_COMMON -static const struct option longopts[] = { + +const char *applet = NULL; +const char *extraopts = NULL; +const char *getoptstring = "e:ilr:" getoptstring_COMMON; +const struct option longopts[] = { { "exists", 1, NULL, 'e' }, { "ifexists", 0, NULL, 'i' }, { "list", 0, NULL, 'l' }, { "resolve", 1, NULL, 'r' }, longopts_COMMON }; -static const char * const longopts_help[] = { +const char * const longopts_help[] = { "tests if the service exists or not", "if the service exists then run the command", "list all available services", "resolve the service name to an init script", longopts_help_COMMON }; -#include "_usage.c" +const char *usagestring = "" \ + "Usage: rc-service [options] [-i] ...\n" \ + " or: rc-service [options] -e \n" \ + " or: rc-service [options] -l\n" \ + " or: rc-service [options] -r "; -int -rc_service(int argc, char **argv) +int main(int argc, char **argv) { int opt; char *service; @@ -61,6 +58,7 @@ rc_service(int argc, char **argv) RC_STRING *s; bool if_exists = false; + applet = basename_c(argv[0]); /* Ensure that we are only quiet when explicitly told to be */ unsetenv("EINFO_QUIET"); diff --git a/src/rc/rc-status.c b/src/rc/rc-status.c index b3f5d360..5018662e 100644 --- a/src/rc/rc-status.c +++ b/src/rc/rc-status.c @@ -21,13 +21,37 @@ #include #include -#include "builtins.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 = "aclrsu" getoptstring_COMMON; +const struct option longopts[] = { + {"all", 0, NULL, 'a'}, + {"crashed", 0, NULL, 'c'}, + {"list", 0, NULL, 'l'}, + {"runlevel", 0, NULL, 'r'}, + {"servicelist", 0, NULL, 's'}, + {"unused", 0, NULL, 'u'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Show services from all run levels", + "Show crashed services", + "Show list of run levels", + "Show the name of the current runlevel", + "Show service list", + "Show services not assigned to any runlevel", + longopts_help_COMMON +}; +const char *usagestring = "" \ + "Usage: rc-status [options] ...\n" \ + " or: rc-status [options] [-a | -c | -l | -r | -s | -u]"; -extern const char *applet; static bool test_crashed = false; static RC_DEPTREE *deptree; static RC_STRINGLIST *types; @@ -35,35 +59,6 @@ static RC_STRINGLIST *types; static RC_STRINGLIST *levels, *services, *tmp, *alist; static RC_STRINGLIST *sservices, *nservices, *needsme; -bool -_rc_can_find_pids(void) -{ - RC_PIDLIST *pids; - RC_PID *pid; - RC_PID *pid2; - bool retval = false; - - if (geteuid() == 0) - return true; - - /* If we cannot see process 1, then we don't test to see if - * services crashed or not */ - pids = rc_find_pids(NULL, NULL, 0, 1); - if (pids) { - pid = LIST_FIRST(pids); - if (pid) { - retval = true; - while (pid) { - pid2 = LIST_NEXT(pid, entries); - free(pid); - pid = pid2; - } - } - free(pids); - } - return retval; -} - static void print_level(const char *prefix, const char *level) { @@ -178,33 +173,7 @@ print_stacked_services(const char *runlevel) stackedlevels = NULL; } -#include "_usage.h" -#define usagestring "" \ - "Usage: rc-status [options] ...\n" \ - " or: rc-status [options] [-a | -c | -l | -r | -s | -u]" -#define getoptstring "aclrsu" getoptstring_COMMON -static const struct option longopts[] = { - {"all", 0, NULL, 'a'}, - {"crashed", 0, NULL, 'c'}, - {"list", 0, NULL, 'l'}, - {"runlevel", 0, NULL, 'r'}, - {"servicelist", 0, NULL, 's'}, - {"unused", 0, NULL, 'u'}, - longopts_COMMON -}; -static const char * const longopts_help[] = { - "Show services from all run levels", - "Show crashed services", - "Show list of run levels", - "Show the name of the current runlevel", - "Show service list", - "Show services not assigned to any runlevel", - longopts_help_COMMON -}; -#include "_usage.c" - -int -rc_status(int argc, char **argv) +int main(int argc, char **argv) { RC_STRING *s, *l, *t, *level; @@ -213,6 +182,7 @@ rc_status(int argc, char **argv) test_crashed = _rc_can_find_pids(); + applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) switch (opt) { diff --git a/src/rc/rc-update.c b/src/rc/rc-update.c index 77b7ae75..9bc1fe5b 100644 --- a/src/rc/rc-update.c +++ b/src/rc/rc-update.c @@ -24,13 +24,31 @@ #include #include -#include "builtins.h" #include "einfo.h" #include "queue.h" #include "rc.h" #include "rc-misc.h" +#include "_usage.h" -extern const char *applet; +const char *applet = NULL; +const char *extraopts = NULL; +const char *usagestring = "" \ + "Usage: rc-update [options] add [...]\n" \ + " or: rc-update [options] del [...]\n" \ + " or: rc-update [options] [show [...]]"; +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) @@ -182,32 +200,11 @@ show(RC_STRINGLIST *runlevels, bool verbose) rc_stringlist_free (services); } -#include "_usage.h" -#define usagestring "" \ - "Usage: rc-update [options] add [...]\n" \ - " or: rc-update [options] del [...]\n" \ - " or: rc-update [options] [show [...]]" -#define getoptstring "asu" getoptstring_COMMON -static const struct option longopts[] = { - { "all", 0, NULL, 'a' }, - { "stack", 0, NULL, 's' }, - { "update", 0, NULL, 'u' }, - longopts_COMMON -}; -static 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 -}; -#include "_usage.c" - #define DOADD (1 << 1) #define DODELETE (1 << 2) #define DOSHOW (1 << 3) -int -rc_update(int argc, char **argv) +int main(int argc, char **argv) { RC_DEPTREE *deptree; RC_STRINGLIST *runlevels; @@ -222,6 +219,7 @@ rc_update(int argc, char **argv) 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) { diff --git a/src/rc/rc.c b/src/rc/rc.c index a0b18865..87c4913f 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -45,7 +45,6 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; #include #include -#include "builtins.h" #include "einfo.h" #include "queue.h" #include "rc.h" @@ -54,6 +53,27 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; #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] []"; #define INITSH RC_LIBEXECDIR "/sh/init.sh" #define INITEARLYSH RC_LIBEXECDIR "/sh/init-early.sh" @@ -721,31 +741,7 @@ handle_bad_signal(int sig) } #endif -#include "_usage.h" -#define usagestring "" \ - "Usage: openrc [options] []" -#define getoptstring "a:no:s:S" getoptstring_COMMON -static const struct option longopts[] = { - { "applet", 1, NULL, 'a' }, - { "no-stop", 0, NULL, 'n' }, - { "override", 1, NULL, 'o' }, - { "service", 1, NULL, 's' }, - { "sys", 0, NULL, 'S' }, - longopts_COMMON -}; -static const char * const longopts_help[] = { - "runs the applet specified by the next argument", - "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 -}; -#include "_usage.c" - -int -main(int argc, char **argv) +int main(int argc, char **argv) { const char *bootlevel = NULL; char *newlevel = NULL; @@ -785,9 +781,6 @@ main(int argc, char **argv) if (!applet) eerrorx("arguments required"); - /* Run our built in applets. If we ran one, we don't return. */ - run_applets(argc, argv); - argc--; argv++; @@ -813,10 +806,6 @@ main(int argc, char **argv) longopts, (int *) 0)) != -1) { switch (opt) { - case 'a': - /* Do nothing, actual logic in run_applets, this - * is a placeholder */ - break; case 'n': nostop = true; break; diff --git a/src/rc/shell_var.c b/src/rc/shell_var.c new file mode 100644 index 00000000..a13f58e2 --- /dev/null +++ b/src/rc/shell_var.c @@ -0,0 +1,41 @@ +/* + * 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/master/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/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 8f973199..775bd7de 100644 --- a/src/rc/start-stop-daemon.c +++ b/src/rc/start-stop-daemon.c @@ -59,11 +59,75 @@ static struct pam_conv conv = { NULL, NULL}; #endif -#include "builtins.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 = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:" \ + getoptstring_COMMON; +const struct option longopts[] = { + { "ionice", 1, NULL, 'I'}, + { "stop", 0, NULL, 'K'}, + { "nicelevel", 1, NULL, 'N'}, + { "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'}, + { "progress", 0, NULL, 'P'}, + longopts_COMMON +}; +const char * const longopts_help[] = { + "Set an ionice class:data when starting", + "Stop daemon", + "Set a nicelevel 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", + "Print dots each second while waiting", + longopts_help_COMMON +}; +const char *usagestring = NULL; typedef struct scheduleitem { @@ -81,7 +145,6 @@ typedef struct scheduleitem TAILQ_HEAD(, scheduleitem) schedule; static char **nav; -extern const char *applet; static char *changeuser, *ch_root, *ch_dir; extern char **environ; @@ -567,70 +630,7 @@ expand_home(const char *home, const char *path) return nh; } -#include "_usage.h" -#define getoptstring "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:" getoptstring_COMMON -static const struct option longopts[] = { - { "ionice", 1, NULL, 'I'}, - { "stop", 0, NULL, 'K'}, - { "nicelevel", 1, NULL, 'N'}, - { "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'}, - { "progress", 0, NULL, 'P'}, - longopts_COMMON -}; -static const char * const longopts_help[] = { - "Set an ionice class:data when starting", - "Stop daemon", - "Set a nicelevel 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", - "Print dots each second while waiting", - longopts_help_COMMON -}; -#include "_usage.c" - -int -start_stop_daemon(int argc, char **argv) +int main(int argc, char **argv) { int devnull_fd = -1; #ifdef TIOCNOTTY @@ -686,6 +686,7 @@ start_stop_daemon(int argc, char **argv) char **margv; unsigned int start_wait = 0; + applet = basename_c(argv[0]); TAILQ_INIT(&schedule); #ifdef DEBUG_MEMORY atexit(cleanup); diff --git a/src/rc/swclock.c b/src/rc/swclock.c index 2c7e8b8e..4b62a460 100644 --- a/src/rc/swclock.c +++ b/src/rc/swclock.c @@ -25,40 +25,39 @@ #include #include #include +#include #include #include -#include "builtins.h" #include "einfo.h" #include "rc-misc.h" +#include "_usage.h" #define RC_SHUTDOWNTIME RC_SVCDIR "/shutdowntime" -extern const char *applet; - -#include "_usage.h" -#define extraopts "file" -#define getoptstring "sw" getoptstring_COMMON -static const struct option longopts[] = { +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 }; -static const char * const longopts_help[] = { +const char * const longopts_help[] = { "saves the time", "no error if no reference file", longopts_help_COMMON }; -#include "_usage.c" +const char *usagestring = NULL; -int -swclock(int argc, char **argv) +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) {