diff options
Diffstat (limited to 'src/librc/librc.c')
| -rw-r--r-- | src/librc/librc.c | 1061 |
1 files changed, 0 insertions, 1061 deletions
diff --git a/src/librc/librc.c b/src/librc/librc.c deleted file mode 100644 index ca51aa61..00000000 --- a/src/librc/librc.c +++ /dev/null @@ -1,1061 +0,0 @@ -/* - librc - core RC functions -*/ - -/* - * Copyright (c) 2007-2008 Roy Marples <roy@marples.name> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; - -#include "queue.h" -#include "librc.h" -#ifdef __FreeBSD__ -# include <sys/sysctl.h> -#endif - -#define RC_RUNLEVEL RC_SVCDIR "/softlevel" - -#ifndef S_IXUGO -# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -#endif - -/* File stream used for plugins to write environ vars to */ -FILE *rc_environ_fd = NULL; - -typedef struct rc_service_state_name { - RC_SERVICE state; - const char *name; -} rc_service_state_name_t; - -/* We MUST list the states below 0x10 first - * The rest can be in any order */ -static const rc_service_state_name_t rc_service_state_names[] = { - { RC_SERVICE_STARTED, "started" }, - { RC_SERVICE_STOPPED, "stopped" }, - { RC_SERVICE_STARTING, "starting" }, - { RC_SERVICE_STOPPING, "stopping" }, - { RC_SERVICE_INACTIVE, "inactive" }, - { RC_SERVICE_WASINACTIVE, "wasinactive" }, - { RC_SERVICE_HOTPLUGGED, "hotplugged" }, - { RC_SERVICE_FAILED, "failed" }, - { RC_SERVICE_SCHEDULED, "scheduled"}, - { 0, NULL} -}; - -#define LS_INITD 0x01 -#define LS_DIR 0x02 -static RC_STRINGLIST * -ls_dir(const char *dir, int options) -{ - DIR *dp; - struct dirent *d; - RC_STRINGLIST *list = NULL; - struct stat buf; - size_t l; - char file[PATH_MAX]; - int r; - - list = rc_stringlist_new(); - if ((dp = opendir(dir)) == NULL) - return list; - while (((d = readdir(dp)) != NULL)) { - if (d->d_name[0] != '.') { - if (options & LS_INITD) { - /* Check that our file really exists. - * This is important as a service maybe in a - * runlevel, but could have been removed. */ - snprintf(file, sizeof(file), "%s/%s", - dir, d->d_name); - r = stat(file, &buf); - if (r != 0) - continue; - - /* .sh files are not init scripts */ - l = strlen(d->d_name); - if (l > 2 && d->d_name[l - 3] == '.' && - d->d_name[l - 2] == 's' && - d->d_name[l - 1] == 'h') - continue; - } - if (options & LS_DIR) { - if (stat(d->d_name, &buf) == 0 && - !S_ISDIR(buf.st_mode)) - continue; - } - rc_stringlist_add(list, d->d_name); - } - } - closedir(dp); - return list; -} - -static bool -rm_dir(const char *pathname, bool top) -{ - DIR *dp; - struct dirent *d; - char file[PATH_MAX]; - struct stat s; - bool retval = true; - - if ((dp = opendir(pathname)) == NULL) - return false; - - errno = 0; - while (((d = readdir(dp)) != NULL) && errno == 0) { - if (strcmp(d->d_name, ".") != 0 && - strcmp(d->d_name, "..") != 0) - { - snprintf(file, sizeof(file), - "%s/%s", pathname, d->d_name); - if (stat(file, &s) != 0) { - retval = false; - break; - } - if (S_ISDIR(s.st_mode)) { - if (!rm_dir(file, true)) - { - retval = false; - break; - } - } else { - if (unlink(file)) { - retval = false; - break; - } - } - } - } - closedir(dp); - - if (!retval) - return false; - - if (top && rmdir(pathname) != 0) - return false; - - return true; -} - -/* Other systems may need this at some point, but for now it's Linux only */ -#ifdef __linux__ -static bool -file_regex(const char *file, const char *regex) -{ - FILE *fp; - char *line = NULL; - size_t len = 0; - regex_t re; - bool retval = true; - int result; - - if (!(fp = fopen(file, "r"))) - return false; - - if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { - fclose(fp); - line = xmalloc(sizeof(char) * BUFSIZ); - regerror(result, &re, line, BUFSIZ); - fprintf(stderr, "file_regex: %s", line); - free(line); - return false; - } - - while ((rc_getline(&line, &len, fp))) { - char *str = line; - /* some /proc files have \0 separated content so we have to - loop through the 'line' */ - do { - if (regexec(&re, str, 0, NULL, 0) == 0) - goto found; - str += strlen(str) + 1; - /* len is the size of allocated buffer and we don't - want call regexec BUFSIZE times. find next str */ - while (str < line + len && *str == '\0') - str++; - } while (str < line + len); - } - retval = false; -found: - fclose(fp); - free(line); - regfree(&re); - - return retval; -} -#endif - -/* New sys identification code - * Not to be used for any binaries outside of openrc. */ -const char * -rc_sys_v2(void) -{ -#define __STRING_SWITCH(x) { char *__string_switch = x; if (false) {} -#define __STRING_CASE(y) else if (strcmp(__string_switch,y) == 0) -#define __STRING_SWITCH_END() } - char *systype = rc_conf_value("rc_sys"); - if (systype) { - char *s = systype; - /* Convert to uppercase */ - while (s && *s) { - if (islower((unsigned char) *s)) - *s = toupper((unsigned char) *s); - s++; - } - /* Now do detection */ - __STRING_SWITCH(systype) - __STRING_CASE(RC_SYS_PREFIX) { return RC_SYS_PREFIX; } -#ifdef __FreeBSD__ - __STRING_CASE(RC_SYS_JAIL) { return RC_SYS_JAIL; } -#endif /* __FreeBSD__ */ -#ifdef __NetBSD__ - __STRING_CASE(RC_SYS_XEN0) { return RC_SYS_XEN0; } - __STRING_CASE(RC_SYS_XENU) { return RC_SYS_XENU; } -#endif /* __NetBSD__ */ -#ifdef __linux__ - __STRING_CASE(RC_SYS_XEN0) { return RC_SYS_XEN0; } - __STRING_CASE(RC_SYS_XENU) { return RC_SYS_XENU; } - __STRING_CASE(RC_SYS_UML) { return RC_SYS_UML; } - __STRING_CASE(RC_SYS_VSERVER) { return RC_SYS_VSERVER; } - __STRING_CASE(RC_SYS_OPENVZ) { return RC_SYS_OPENVZ; } - __STRING_CASE(RC_SYS_LXC) { return RC_SYS_LXC; } -#endif /* __linux__ */ - __STRING_SWITCH_END() - } -#undef __STRING_SWITCH -#undef __STRING_CASE -#undef __STRING_SWITCH_END - return NULL; -} -librc_hidden_def(rc_sys_v2) - -/* Old sys identification code. - * Not to be used for any binaries outside of openrc. */ -const char * -rc_sys_v1(void) -{ -#ifdef PREFIX - return RC_SYS_PREFIX; -#else - -#ifdef __FreeBSD__ - int jailed = 0; - size_t len = sizeof(jailed); - - if (sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0) == 0) - if (jailed == 1) - return RC_SYS_JAIL; -#endif - -#ifdef __NetBSD__ - if (exists("/kern/xen/privcmd")) - return RC_SYS_XEN0; - if (exists("/kern/xen")) - return RC_SYS_XENU; -#endif - -#ifdef __linux__ - if (exists("/proc/xen")) { - if (file_regex("/proc/xen/capabilities", "control_d")) - return RC_SYS_XEN0; - return RC_SYS_XENU; - } else if (file_regex("/proc/cpuinfo", "UML")) - return RC_SYS_UML; - else if (file_regex("/proc/self/status", - "(s_context|VxID):[[:space:]]*[1-9]")) - return RC_SYS_VSERVER; - else if (exists("/proc/vz/veinfo") && !exists("/proc/vz/version")) - return RC_SYS_OPENVZ; - else if (file_regex("/proc/self/status", - "envID:[[:space:]]*[1-9]")) - return RC_SYS_OPENVZ; /* old test */ - else if (file_regex("/proc/1/environ", "container=lxc")) - return RC_SYS_LXC; -#endif - - return NULL; -#endif /* PREFIX */ -} -librc_hidden_def(rc_sys_v1) - -const char * -rc_sys(void) -{ - if (rc_conf_value("rc_sys")) { - return rc_sys_v2(); - } else { - return rc_sys_v1(); - } -} -librc_hidden_def(rc_sys) - -static const char * -rc_parse_service_state(RC_SERVICE state) -{ - int i; - - for (i = 0; rc_service_state_names[i].name; i++) { - if (rc_service_state_names[i].state == state) - return rc_service_state_names[i].name; - } - return NULL; -} - -/* Returns a list of all the chained runlevels used by the - * specified runlevel in dependency order, including the - * specified runlevel. */ -static void -get_runlevel_chain(const char *runlevel, RC_STRINGLIST *level_list) -{ - char path[PATH_MAX]; - RC_STRINGLIST *dirs; - RC_STRING *d, *dn; - - /* - * If we haven't been passed a runlevel or a level list, or - * if the passed runlevel doesn't exist then we're done already! - */ - if (!runlevel || !level_list || !rc_runlevel_exists(runlevel)) - return; - - /* - * We want to add this runlevel to the list but if - * it is already in the list it needs to go at the - * end again. - */ - if (rc_stringlist_find(level_list, runlevel)) - rc_stringlist_delete(level_list, runlevel); - rc_stringlist_add(level_list, runlevel); - - /* - * We can now do exactly the above procedure for our chained - * runlevels. - */ - snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); - dirs = ls_dir(path, LS_DIR); - TAILQ_FOREACH_SAFE(d, dirs, entries, dn) - get_runlevel_chain(d->value, level_list); -} - -bool -rc_runlevel_starting(void) -{ - return exists(RC_STARTING); -} -librc_hidden_def(rc_runlevel_starting) - -bool -rc_runlevel_stopping(void) -{ - return exists(RC_STOPPING); -} -librc_hidden_def(rc_runlevel_stopping) - -RC_STRINGLIST *rc_runlevel_list(void) -{ - return ls_dir(RC_RUNLEVELDIR, LS_DIR); -} -librc_hidden_def(rc_runlevel_list) - -char * -rc_runlevel_get(void) -{ - FILE *fp; - char *runlevel = NULL; - size_t i; - - if ((fp = fopen(RC_RUNLEVEL, "r"))) { - runlevel = xmalloc(sizeof(char) * PATH_MAX); - if (fgets(runlevel, PATH_MAX, fp)) { - i = strlen(runlevel) - 1; - if (runlevel[i] == '\n') - runlevel[i] = 0; - } else - *runlevel = '\0'; - fclose(fp); - } - - if (!runlevel || !*runlevel) { - free(runlevel); - runlevel = xstrdup(RC_LEVEL_SYSINIT); - } - - return runlevel; -} -librc_hidden_def(rc_runlevel_get) - -bool -rc_runlevel_set(const char *runlevel) -{ - FILE *fp = fopen(RC_RUNLEVEL, "w"); - - if (!fp) - return false; - fprintf(fp, "%s", runlevel); - fclose(fp); - return true; -} -librc_hidden_def(rc_runlevel_set) - -bool -rc_runlevel_exists(const char *runlevel) -{ - char path[PATH_MAX]; - struct stat buf; - - if (!runlevel || strcmp(runlevel, ".") == 0 || strcmp(runlevel, "..") == 0) - return false; - snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel); - if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) - return true; - return false; -} -librc_hidden_def(rc_runlevel_exists) - -bool -rc_runlevel_stack(const char *dst, const char *src) -{ - char d[PATH_MAX], s[PATH_MAX]; - - if (!rc_runlevel_exists(dst) || !rc_runlevel_exists(src)) - return false; - snprintf(s, sizeof(s), "../%s", src); - snprintf(d, sizeof(s), "%s/%s/%s", RC_RUNLEVELDIR, dst, src); - return (symlink(s, d) == 0 ? true : false); -} -librc_hidden_def(rc_runlevel_stack) - -bool -rc_runlevel_unstack(const char *dst, const char *src) -{ - char path[PATH_MAX]; - - snprintf(path, sizeof(path), "%s/%s/%s", RC_RUNLEVELDIR, dst, src); - return (unlink(path) == 0 ? true : false); -} -librc_hidden_def(rc_runlevel_unstack) - -RC_STRINGLIST * -rc_runlevel_stacks(const char *runlevel) -{ - RC_STRINGLIST *stack; - stack = rc_stringlist_new(); - get_runlevel_chain(runlevel, stack); - return stack; -} -librc_hidden_def(rc_runlevel_stacks) - -/* Resolve a service name to its full path */ -char * -rc_service_resolve(const char *service) -{ - char buffer[PATH_MAX]; - char file[PATH_MAX]; - int r; - struct stat buf; - - if (!service) - return NULL; - - if (service[0] == '/') - return xstrdup(service); - - /* First check started services */ - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", "started", service); - if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - "inactive", service); - if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) - *file = '\0'; - } - - if (*file) { - memset(buffer, 0, sizeof(buffer)); - r = readlink(file, buffer, sizeof(buffer)); - if (r > 0) - return xstrdup(buffer); - } - -#ifdef RC_LOCAL_INITDIR - /* Nope, so lets see if the user has written it */ - snprintf(file, sizeof(file), RC_LOCAL_INITDIR "/%s", service); - if (stat(file, &buf) == 0) - return xstrdup(file); -#endif - - /* System scripts take precedence over 3rd party ones */ - snprintf(file, sizeof(file), RC_INITDIR "/%s", service); - if (stat(file, &buf) == 0) - return xstrdup(file); - -#ifdef RC_PKG_INITDIR - /* Check RC_PKG_INITDIR */ - snprintf(file, sizeof(file), RC_PKG_INITDIR "/%s", service); - if (stat(file, &buf) == 0) - return xstrdup(file); -#endif - - return NULL; -} -librc_hidden_def(rc_service_resolve) - -bool -rc_service_exists(const char *service) -{ - char *file; - bool retval = false; - size_t len; - struct stat buf; - - if (!service) { - errno = EINVAL; - return false; - } - - len = strlen(service); - - /* .sh files are not init scripts */ - if (len > 2 && service[len - 3] == '.' && - service[len - 2] == 's' && - service[len - 1] == 'h') { - errno = EINVAL; - return false; - } - - if (!(file = rc_service_resolve(service))) { - errno = ENOENT; - return false; - } - - if (stat(file, &buf) == 0) { - if (buf.st_mode & S_IXUGO) - retval = true; - else - errno = ENOEXEC; - } - free(file); - return retval; -} -librc_hidden_def(rc_service_exists) - -#define OPTSTR \ -". '%s'; echo $extra_commands $extra_started_commands $extra_stopped_commands" - -RC_STRINGLIST * -rc_service_extra_commands(const char *service) -{ - char *svc; - char *cmd = NULL; - char *buffer = NULL; - size_t len = 0; - RC_STRINGLIST *commands = NULL; - char *token; - char *p; - FILE *fp; - size_t l; - - if (!(svc = rc_service_resolve(service))) - return NULL; - - l = strlen(OPTSTR) + strlen(svc) + 1; - cmd = xmalloc(sizeof(char) * l); - snprintf(cmd, l, OPTSTR, svc); - free(svc); - - if ((fp = popen(cmd, "r"))) { - rc_getline(&buffer, &len, fp); - p = buffer; - commands = rc_stringlist_new(); - - while ((token = strsep(&p, " "))) - if (token[0] != '\0') - rc_stringlist_add(commands, token); - - pclose(fp); - free(buffer); - } - - free(cmd); - return commands; -} -librc_hidden_def(rc_service_extra_commands) - -#define DESCSTR ". '%s'; echo \"${description%s%s}\"" -char * -rc_service_description(const char *service, const char *option) -{ - char *svc; - char *cmd; - char *desc = NULL; - size_t len = 0; - FILE *fp; - size_t l; - - if (!(svc = rc_service_resolve(service))) - return NULL; - - if (!option) - option = ""; - - l = strlen(DESCSTR) + strlen(svc) + strlen(option) + 2; - cmd = xmalloc(sizeof(char) * l); - snprintf(cmd, l, DESCSTR, svc, *option ? "_" : "", option); - free(svc); - if ((fp = popen(cmd, "r"))) { - rc_getline(&desc, &len, fp); - pclose(fp); - } - free(cmd); - return desc; -} -librc_hidden_def(rc_service_description) - -bool -rc_service_in_runlevel(const char *service, const char *runlevel) -{ - char file[PATH_MAX]; - - snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", - runlevel, basename_c(service)); - return exists(file); -} -librc_hidden_def(rc_service_in_runlevel) - -bool -rc_service_mark(const char *service, const RC_SERVICE state) -{ - char file[PATH_MAX]; - int i = 0; - int skip_state = -1; - const char *base; - char *init = rc_service_resolve(service); - bool skip_wasinactive = false; - int s; - char was[PATH_MAX]; - RC_STRINGLIST *dirs; - RC_STRING *dir; - int serrno; - - if (!init) - return false; - - base = basename_c(service); - if (state != RC_SERVICE_STOPPED) { - if (!exists(init)) { - free(init); - return false; - } - - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - rc_parse_service_state(state), base); - if (exists(file)) - unlink(file); - i = symlink(init, file); - if (i != 0) { - free(init); - return false; - } - skip_state = state; - } - - if (state == RC_SERVICE_HOTPLUGGED || state == RC_SERVICE_FAILED) { - free(init); - return true; - } - - /* Remove any old states now */ - for (i = 0; rc_service_state_names[i].name; i++) { - s = rc_service_state_names[i].state; - - if ((s != skip_state && - s != RC_SERVICE_STOPPED && - s != RC_SERVICE_HOTPLUGGED && - s != RC_SERVICE_SCHEDULED) && - (! skip_wasinactive || s != RC_SERVICE_WASINACTIVE)) - { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - rc_service_state_names[i].name, base); - if (exists(file)) { - if ((state == RC_SERVICE_STARTING || - state == RC_SERVICE_STOPPING) && - s == RC_SERVICE_INACTIVE) - { - snprintf(was, sizeof(was), - RC_SVCDIR "/%s/%s", - rc_parse_service_state(RC_SERVICE_WASINACTIVE), - base); - if (symlink(init, was) == -1) - return false; - skip_wasinactive = true; - } - if (unlink(file) == -1) { - free(init); - return false; - } - } - } - } - - /* Remove the exclusive state if we're inactive */ - if (state == RC_SERVICE_STARTED || - state == RC_SERVICE_STOPPED || - state == RC_SERVICE_INACTIVE) - { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - "exclusive", base); - unlink(file); - } - - /* Remove any options and daemons the service may have stored */ - if (state == RC_SERVICE_STOPPED) { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - "options", base); - rm_dir(file, true); - - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - "daemons", base); - rm_dir(file, true); - - rc_service_schedule_clear(service); - } - - /* These are final states, so remove us from scheduled */ - if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { - snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled"); - dirs = ls_dir(file, 0); - TAILQ_FOREACH(dir, dirs, entries) { - snprintf(was, sizeof(was), "%s/%s/%s", - file, dir->value, base); - unlink(was); - - /* Try and remove the dir; we don't care about errors */ - snprintf(was, sizeof(was), "%s/%s", file, dir->value); - serrno = errno; - rmdir(was); - errno = serrno; - } - rc_stringlist_free(dirs); - } - free(init); - return true; -} -librc_hidden_def(rc_service_mark) - -RC_SERVICE -rc_service_state(const char *service) -{ - int i; - int state = RC_SERVICE_STOPPED; - char file[PATH_MAX]; - RC_STRINGLIST *dirs; - RC_STRING *dir; - const char *base = basename_c(service); - - for (i = 0; rc_service_state_names[i].name; i++) { - snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", - rc_service_state_names[i].name, base); - if (exists(file)) { - if (rc_service_state_names[i].state <= 0x10) - state = rc_service_state_names[i].state; - else - state |= rc_service_state_names[i].state; - } - } - - if (state & RC_SERVICE_STOPPED) { - dirs = ls_dir(RC_SVCDIR "/scheduled", 0); - TAILQ_FOREACH(dir, dirs, entries) { - snprintf(file, sizeof(file), - RC_SVCDIR "/scheduled/%s/%s", - dir->value, service); - if (exists(file)) { - state |= RC_SERVICE_SCHEDULED; - break; - } - } - rc_stringlist_free(dirs); - } - - return state; -} -librc_hidden_def(rc_service_state) - -char * -rc_service_value_get(const char *service, const char *option) -{ - char *buffer = NULL; - size_t len = 0; - char file[PATH_MAX]; - - snprintf(file, sizeof(file), RC_SVCDIR "/options/%s/%s", - service, option); - rc_getfile(file, &buffer, &len); - - return buffer; -} -librc_hidden_def(rc_service_value_get) - -bool -rc_service_value_set(const char *service, const char *option, - const char *value) -{ - FILE *fp; - char file[PATH_MAX]; - char *p = file; - - p += snprintf(file, sizeof(file), RC_SVCDIR "/options/%s", service); - if (mkdir(file, 0755) != 0 && errno != EEXIST) - return false; - - snprintf(p, sizeof(file) - (p - file), "/%s", option); - if (!(fp = fopen(file, "w"))) - return false; - if (value) - fprintf(fp, "%s", value); - fclose(fp); - return true; -} -librc_hidden_def(rc_service_value_set) - - -bool -rc_service_schedule_start(const char *service, const char *service_to_start) -{ - char file[PATH_MAX]; - char *p = file; - char *init; - bool retval; - - /* service may be a provided service, like net */ - if (! service || ! rc_service_exists(service_to_start)) - return false; - - p += snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s", - basename_c(service)); - if (mkdir(file, 0755) != 0 && errno != EEXIST) - return false; - - init = rc_service_resolve(service_to_start); - snprintf(p, sizeof(file) - (p - file), - "/%s", basename_c(service_to_start)); - retval = (exists(file) || symlink(init, file) == 0); - free(init); - return retval; -} -librc_hidden_def(rc_service_schedule_start) - -bool -rc_service_schedule_clear(const char *service) -{ - char dir[PATH_MAX]; - - snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", - basename_c(service)); - if (!rm_dir(dir, true) && errno == ENOENT) - return true; - return false; -} -librc_hidden_def(rc_service_schedule_clear) - -RC_STRINGLIST * -rc_services_in_runlevel(const char *runlevel) -{ - char dir[PATH_MAX]; - RC_STRINGLIST *list = NULL; - - if (!runlevel) { -#ifdef RC_PKG_INITDIR - RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD); -#endif -#ifdef RC_LOCAL_INITDIR - RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD); -#endif - - list = ls_dir(RC_INITDIR, LS_INITD); - -#ifdef RC_PKG_INITDIR - TAILQ_CONCAT(list, pkg, entries); - free(pkg); -#endif -#ifdef RC_LOCAL_INITDIR - TAILQ_CONCAT(list, local, entries); - free(local); -#endif - return list; - } - - /* These special levels never contain any services */ - if (strcmp(runlevel, RC_LEVEL_SINGLE) != 0) { - snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel); - list = ls_dir(dir, LS_INITD); - } - if (!list) - list = rc_stringlist_new(); - return list; -} -librc_hidden_def(rc_services_in_runlevel) - -RC_STRINGLIST * -rc_services_in_runlevel_stacked(const char *runlevel) -{ - RC_STRINGLIST *list, *stacks, *sl; - RC_STRING *stack; - - list = rc_services_in_runlevel(runlevel); - stacks = rc_runlevel_stacks(runlevel); - TAILQ_FOREACH(stack, stacks, entries) { - sl = rc_services_in_runlevel(stack->value); - TAILQ_CONCAT(list, sl, entries); - free(sl); - } - return list; -} -librc_hidden_def(rc_services_in_runlevel_stacked) - -RC_STRINGLIST * -rc_services_in_state(RC_SERVICE state) -{ - RC_STRINGLIST *services; - RC_STRINGLIST *list; - RC_STRINGLIST *dirs; - RC_STRING *d; - char dir[PATH_MAX]; - char *p = dir; - - p += snprintf(dir, sizeof(dir), RC_SVCDIR "/%s", - rc_parse_service_state(state)); - - if (state != RC_SERVICE_SCHEDULED) - return ls_dir(dir, LS_INITD); - - dirs = ls_dir(dir, 0); - list = rc_stringlist_new(); - if (! dirs) - return list; - - TAILQ_FOREACH(d, dirs, entries) { - snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value); - services = ls_dir(dir, LS_INITD); - if (services) { - TAILQ_CONCAT(list, services, entries); - free(services); - } - } - rc_stringlist_free(dirs); - return list; -} -librc_hidden_def(rc_services_in_state) - -bool -rc_service_add(const char *runlevel, const char *service) -{ - bool retval; - char *init; - char file[PATH_MAX]; - char path[MAXPATHLEN] = { '\0' }; - char *p = NULL; - char binit[PATH_MAX]; - char *i; - - if (!rc_runlevel_exists(runlevel)) { - errno = ENOENT; - return false; - } - - if (rc_service_in_runlevel(service, runlevel)) { - errno = EEXIST; - return false; - } - - i = init = rc_service_resolve(service); - snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", - runlevel, basename_c(service)); - - /* We need to ensure that only things in /etc/init.d are added - * to the boot runlevel */ - if (strcmp(runlevel, RC_LEVEL_BOOT) == 0) { - p = realpath(dirname(init), path); - if (!*p) { - free(init); - return false; - } - if (strcmp(path, RC_INITDIR) != 0) { - free(init); - errno = EPERM; - return false; - } - snprintf(binit, sizeof(binit), RC_INITDIR "/%s", service); - i = binit; - } - - retval = (symlink(i, file) == 0); - free(init); - return retval; -} -librc_hidden_def(rc_service_add) - -bool -rc_service_delete(const char *runlevel, const char *service) -{ - char file[PATH_MAX]; - - snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s", - runlevel, basename_c(service)); - if (unlink(file) == 0) - return true; - return false; -} -librc_hidden_def(rc_service_delete) - -RC_STRINGLIST * -rc_services_scheduled_by(const char *service) -{ - RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); - RC_STRINGLIST *list = rc_stringlist_new(); - RC_STRING *dir; - char file[PATH_MAX]; - - TAILQ_FOREACH(dir, dirs, entries) { - snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s", - dir->value, service); - if (exists(file)) - rc_stringlist_add(list, file); - } - rc_stringlist_free(dirs); - return list; -} -librc_hidden_def(rc_services_scheduled_by) - -RC_STRINGLIST * -rc_services_scheduled(const char *service) -{ - char dir[PATH_MAX]; - - snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s", - basename_c(service)); - return ls_dir(dir, LS_INITD); -} -librc_hidden_def(rc_services_scheduled) |
