diff options
Diffstat (limited to 'src/rc/rc-applets.c')
-rw-r--r-- | src/rc/rc-applets.c | 557 |
1 files changed, 0 insertions, 557 deletions
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 <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 "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); -} |