diff options
| author | William Hubbs <w.d.hubbs@gmail.com> | 2014-12-03 10:13:41 -0600 |
|---|---|---|
| committer | William Hubbs <w.d.hubbs@gmail.com> | 2014-12-03 10:13:41 -0600 |
| commit | 1267025fb76af18e31b2c7de16606abbb9b87ea3 (patch) | |
| tree | 8cc3a36b1dd7e1438d05a293cae8eac572126a7c /src/librc | |
| parent | 30cc3cdb76a66c7c0f89a52db4e5cff77b570e31 (diff) | |
initial commitorigin/gh-pagesgithub/gh-pages
Diffstat (limited to 'src/librc')
| -rw-r--r-- | src/librc/.gitignore | 2 | ||||
| -rw-r--r-- | src/librc/Makefile | 48 | ||||
| -rw-r--r-- | src/librc/librc-daemon.c | 645 | ||||
| -rw-r--r-- | src/librc/librc-depend.c | 1054 | ||||
| -rw-r--r-- | src/librc/librc-misc.c | 425 | ||||
| -rw-r--r-- | src/librc/librc-stringlist.c | 164 | ||||
| -rw-r--r-- | src/librc/librc.c | 1061 | ||||
| -rw-r--r-- | src/librc/librc.h | 137 | ||||
| -rw-r--r-- | src/librc/rc.h.in | 619 | ||||
| -rw-r--r-- | src/librc/rc.map | 68 |
10 files changed, 0 insertions, 4223 deletions
diff --git a/src/librc/.gitignore b/src/librc/.gitignore deleted file mode 100644 index e7fafe8c..00000000 --- a/src/librc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -librc.so.1 -rc.h diff --git a/src/librc/Makefile b/src/librc/Makefile deleted file mode 100644 index 73075608..00000000 --- a/src/librc/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -LIB= rc -SHLIB_MAJOR= 1 -SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \ - librc-stringlist.c -INCS= rc.h -VERSION_MAP= rc.map - -LDADD+= ${LIBKVM} - -CPPFLAGS+= -I../includes - -MK= ../../mk -include ${MK}/lib.mk -include ${MK}/cc.mk - -# Massage our header file for our dirs -SED_CMD= -e 's:@PREFIX@:${PREFIX}:g' -SED_CMD+= -e 's:@LIB@:${LIBNAME}:g' -SED_CMD+= -e 's:@SYSCONFDIR@:${SYSCONFDIR}:g' -SED_CMD+= -e 's:@LIBEXECDIR@:${LIBEXECDIR}:g' -SED_CMD+= -e 's:@BINDIR@:${BINDIR}:g' -SED_CMD+= -e 's:@SBINDIR@:${SBINDIR}:g' - -_PKG_PREFIX= -e 's:.*@PKG_PREFIX@.*:\#undef RC_PKG_PREFIX:g' -ifneq (${PKG_PREFIX},) -ifneq (${PKG_PREFIX},/) -ifneq (${PKG_PREFIX},${PREFIX}) -_PKG_PREFIX= -e 's:@PKG_PREFIX@:${PKG_PREFIX}:g' -endif -endif -endif -SED_CMD+= ${_PKG_PREFIX} - -_LCL_PREFIX= -e 's:@LOCAL_PREFIX@::g' -ifneq (${LOCAL_PREFIX},) -ifneq (${LOCAL_PREFIX},/) -ifneq (${LOCAL_PREFIX},${PREFIX}) -_LCL_PREFIX= -e 's:@LOCAL_PREFIX@:${LOCAL_PREFIX}:g' -endif -endif -endif -SED_CMD+= ${_LCL_PREFIX} - -%.h: %.h.in - ${SED} ${SED_CMD} $< > $@ -${SRCS}: rc.h - -CLEANFILES+= rc.h diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c deleted file mode 100644 index 02aff5a9..00000000 --- a/src/librc/librc-daemon.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - librc-daemon - Finds PID for given daemon criteria -*/ - -/* - * Copyright (c) 2007-2009 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. - */ - -#include "queue.h" -#include "librc.h" - -#if defined(__linux__) || (defined (__FreeBSD_kernel__) && defined(__GLIBC__)) -static bool -pid_is_exec(pid_t pid, const char *exec) -{ - char buffer[32]; - FILE *fp; - int c; - bool retval = false; - - exec = basename_c(exec); - snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid); - if ((fp = fopen(buffer, "r"))) { - while ((c = getc(fp)) != EOF && c != '(') - ; - if (c == '(') { - while ((c = getc(fp)) != EOF && c == *exec) - exec++; - if (c == ')' && *exec == '\0') - retval = true; - } - fclose(fp); - } - return retval; -} - -static bool -pid_is_argv(pid_t pid, const char *const *argv) -{ - char cmdline[32]; - int fd; - char buffer[PATH_MAX]; - char *p; - ssize_t bytes; - - snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid); - if ((fd = open(cmdline, O_RDONLY)) < 0) - return false; - bytes = read(fd, buffer, sizeof(buffer)); - close(fd); - if (bytes == -1) - return false; - - buffer[bytes] = '\0'; - p = buffer; - while (*argv) { - if (strcmp(*argv, p) != 0) - return false; - argv++; - p += strlen(p) + 1; - if ((unsigned)(p - buffer) > sizeof(buffer)) - return false; - } - return true; -} - -RC_PIDLIST * -rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) -{ - DIR *procdir; - struct dirent *entry; - FILE *fp; - bool container_pid = false; - bool openvz_host = false; - char *line = NULL; - size_t len = 0; - pid_t p; - char buffer[PATH_MAX]; - struct stat sb; - pid_t runscript_pid = 0; - char *pp; - RC_PIDLIST *pids = NULL; - RC_PID *pi; - - if ((procdir = opendir("/proc")) == NULL) - return NULL; - - /* - We never match RC_RUNSCRIPT_PID if present so we avoid the below - scenario - - /etc/init.d/ntpd stop does - start-stop-daemon --stop --name ntpd - catching /etc/init.d/ntpd stop - - nasty - */ - - if ((pp = getenv("RC_RUNSCRIPT_PID"))) { - if (sscanf(pp, "%d", &runscript_pid) != 1) - runscript_pid = 0; - } - - /* - If /proc/self/status contains EnvID: 0, then we are an OpenVZ host, - and we will need to filter out processes that are inside containers - from our list of pids. - */ - - if (exists("/proc/self/status")) { - fp = fopen("/proc/self/status", "r"); - if (fp) { - while (! feof(fp)) { - rc_getline(&line, &len, fp); - if (strncmp(line, "envID:\t0", 8) == 0) { - openvz_host = true; - break; - } - } - fclose(fp); - } - } - - while ((entry = readdir(procdir)) != NULL) { - if (sscanf(entry->d_name, "%d", &p) != 1) - continue; - if (runscript_pid != 0 && runscript_pid == p) - continue; - if (pid != 0 && pid != p) - continue; - if (uid) { - snprintf(buffer, sizeof(buffer), "/proc/%d", p); - if (stat(buffer, &sb) != 0 || sb.st_uid != uid) - continue; - } - if (exec && !pid_is_exec(p, exec)) - continue; - if (argv && - !pid_is_argv(p, (const char *const *)argv)) - continue; - /* If this is an OpenVZ host, filter out container processes */ - if (openvz_host) { - snprintf(buffer, sizeof(buffer), "/proc/%d/status", p); - if (exists(buffer)) { - fp = fopen(buffer, "r"); - if (! fp) - continue; - while (! feof(fp)) { - rc_getline(&line, &len, fp); - if (strncmp(line, "envID:", 6) == 0) { - container_pid = ! (strncmp(line, "envID:\t0", 8) == 0); - break; - } - } - fclose(fp); - } - } - if (container_pid) - continue; - if (!pids) { - pids = xmalloc(sizeof(*pids)); - LIST_INIT(pids); - } - pi = xmalloc(sizeof(*pi)); - pi->pid = p; - LIST_INSERT_HEAD(pids, pi, entries); - } - if (line != NULL) - free(line); - closedir(procdir); - return pids; -} -librc_hidden_def(rc_find_pids) - -#elif BSD - -# if defined(__NetBSD__) || defined(__OpenBSD__) -# define _KVM_GETPROC2 -# define _KINFO_PROC kinfo_proc2 -# define _KVM_GETARGV kvm_getargv2 -# define _GET_KINFO_UID(kp) (kp.p_ruid) -# define _GET_KINFO_COMM(kp) (kp.p_comm) -# define _GET_KINFO_PID(kp) (kp.p_pid) -# define _KVM_PATH NULL -# define _KVM_FLAGS KVM_NO_FILES -# else -# ifndef KERN_PROC_PROC -# define KERN_PROC_PROC KERN_PROC_ALL -# endif -# define _KINFO_PROC kinfo_proc -# define _KVM_GETARGV kvm_getargv -# if defined(__DragonFly__) -# define _GET_KINFO_UID(kp) (kp.kp_ruid) -# define _GET_KINFO_COMM(kp) (kp.kp_comm) -# define _GET_KINFO_PID(kp) (kp.kp_pid) -# else -# define _GET_KINFO_UID(kp) (kp.ki_ruid) -# define _GET_KINFO_COMM(kp) (kp.ki_comm) -# define _GET_KINFO_PID(kp) (kp.ki_pid) -# endif -# define _KVM_PATH _PATH_DEVNULL -# define _KVM_FLAGS O_RDONLY -# endif - -RC_PIDLIST * -rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) -{ - static kvm_t *kd = NULL; - char errbuf[_POSIX2_LINE_MAX]; - struct _KINFO_PROC *kp; - int i; - int processes = 0; - int pargc = 0; - char **pargv; - RC_PIDLIST *pids = NULL; - RC_PID *pi; - pid_t p; - const char *const *arg; - int match; - - if ((kd = kvm_openfiles(_KVM_PATH, _KVM_PATH, - NULL, _KVM_FLAGS, errbuf)) == NULL) - { - fprintf(stderr, "kvm_open: %s\n", errbuf); - return NULL; - } - -#ifdef _KVM_GETPROC2 - kp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes); -#else - kp = kvm_getprocs(kd, KERN_PROC_PROC, 0, &processes); -#endif - if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) { - fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); - kvm_close(kd); - return NULL; - } - - if (exec) - exec = basename_c(exec); - for (i = 0; i < processes; i++) { - p = _GET_KINFO_PID(kp[i]); - if (pid != 0 && pid != p) - continue; - if (uid != 0 && uid != _GET_KINFO_UID(kp[i])) - continue; - if (exec) { - if (!_GET_KINFO_COMM(kp[i]) || - strcmp(exec, _GET_KINFO_COMM(kp[i])) != 0) - continue; - } - if (argv && *argv) { - pargv = _KVM_GETARGV(kd, &kp[i], pargc); - if (!pargv || !*pargv) - continue; - arg = argv; - match = 1; - while (*arg && *pargv) - if (strcmp(*arg++, *pargv++) != 0) { - match = 0; - break; - } - if (!match) - continue; - } - if (!pids) { - pids = xmalloc(sizeof(*pids)); - LIST_INIT(pids); - } - pi = xmalloc(sizeof(*pi)); - pi->pid = p; - LIST_INSERT_HEAD(pids, pi, entries); - } - kvm_close(kd); - - return pids; -} -librc_hidden_def(rc_find_pids) - -#else -# error "Platform not supported!" -#endif - -static bool -_match_daemon(const char *path, const char *file, RC_STRINGLIST *match) -{ - char *line = NULL; - size_t len = 0; - char ffile[PATH_MAX]; - FILE *fp; - RC_STRING *m; - - snprintf(ffile, sizeof(ffile), "%s/%s", path, file); - fp = fopen(ffile, "r"); - - if (!fp) - return false; - - while ((rc_getline(&line, &len, fp))) { - TAILQ_FOREACH(m, match, entries) - if (strcmp(line, m->value) == 0) { - TAILQ_REMOVE(match, m, entries); - break; - } - if (!TAILQ_FIRST(match)) - break; - } - fclose(fp); - free(line); - if (TAILQ_FIRST(match)) - return false; - return true; -} - -static RC_STRINGLIST * -_match_list(const char *exec, const char *const *argv, const char *pidfile) -{ - RC_STRINGLIST *match = rc_stringlist_new(); - int i = 0; - size_t l; - char *m; - - if (exec) { - l = strlen(exec) + 6; - m = xmalloc(sizeof(char) * l); - snprintf(m, l, "exec=%s", exec); - rc_stringlist_add(match, m); - free(m); - } - - while (argv && argv[i]) { - l = strlen(*argv) + strlen("argv_=") + 16; - m = xmalloc(sizeof(char) * l); - snprintf(m, l, "argv_0=%s", argv[i++]); - rc_stringlist_add(match, m); - free(m); - } - - if (pidfile) { - l = strlen(pidfile) + 9; - m = xmalloc(sizeof(char) * l); - snprintf(m, l, "pidfile=%s", pidfile); - rc_stringlist_add(match, m); - free(m); - } - - return match; -} - -bool -rc_service_daemon_set(const char *service, const char *exec, - const char *const *argv, - const char *pidfile, bool started) -{ - char dirpath[PATH_MAX]; - char file[PATH_MAX]; - int nfiles = 0; - char oldfile[PATH_MAX] = { '\0' }; - bool retval = false; - DIR *dp; - struct dirent *d; - RC_STRINGLIST *match; - int i = 0; - FILE *fp; - - if (!exec && !pidfile) { - errno = EINVAL; - return false; - } - - snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", - basename_c(service)); - - /* Regardless, erase any existing daemon info */ - if ((dp = opendir(dirpath))) { - match = _match_list(exec, argv, pidfile); - while ((d = readdir(dp))) { - if (d->d_name[0] == '.') - continue; - - snprintf(file, sizeof(file), "%s/%s", - dirpath, d->d_name); - nfiles++; - - if (!*oldfile) { - if (_match_daemon(dirpath, d->d_name, match)) { - unlink(file); - strlcpy(oldfile, file, sizeof(oldfile)); - nfiles--; - } - } else { - rename(file, oldfile); - strlcpy(oldfile, file, sizeof(oldfile)); - } - } - closedir(dp); - rc_stringlist_free(match); - } - - /* Now store our daemon info */ - if (started) { - if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) { - snprintf(file, sizeof(file), "%s/%03d", - dirpath, nfiles + 1); - if ((fp = fopen(file, "w"))) { - fprintf(fp, "exec="); - if (exec) - fprintf(fp, "%s", exec); - while (argv && argv[i]) { - fprintf(fp, "\nargv_%d=%s", i, argv[i]); - i++; - } - fprintf(fp, "\npidfile="); - if (pidfile) - fprintf(fp, "%s", pidfile); - fprintf(fp, "\n"); - fclose(fp); - retval = true; - } - } - } else - retval = true; - - return retval; -} -librc_hidden_def(rc_service_daemon_set) - -bool -rc_service_started_daemon(const char *service, - const char *exec, const char *const *argv, int indx) -{ - char dirpath[PATH_MAX]; - char file[16]; - RC_STRINGLIST *match; - bool retval = false; - DIR *dp; - struct dirent *d; - - if (!service || !exec) - return false; - - snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", - basename_c(service)); - match = _match_list(exec, argv, NULL); - - if (indx > 0) { - snprintf(file, sizeof(file), "%03d", indx); - retval = _match_daemon(dirpath, file, match); - } else { - if ((dp = opendir(dirpath))) { - while ((d = readdir(dp))) { - if (d->d_name[0] == '.') - continue; - retval = _match_daemon(dirpath, d->d_name, match); - if (retval) - break; - } - closedir(dp); - } - } - - rc_stringlist_free(match); - return retval; -} -librc_hidden_def(rc_service_started_daemon) - -bool -rc_service_daemons_crashed(const char *service) -{ - char dirpath[PATH_MAX]; - DIR *dp; - struct dirent *d; - char *path = dirpath; - FILE *fp; - char *line = NULL; - size_t len = 0; - char **argv = NULL; - char *exec = NULL; - char *name = NULL; - char *pidfile = NULL; - pid_t pid = 0; - RC_PIDLIST *pids; - RC_PID *p1; - RC_PID *p2; - char *p; - char *token; - bool retval = false; - RC_STRINGLIST *list = NULL; - RC_STRING *s; - size_t i; - - path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", - basename_c(service)); - - if (!(dp = opendir(dirpath))) - return false; - - while ((d = readdir(dp))) { - if (d->d_name[0] == '.') - continue; - - snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s", - d->d_name); - fp = fopen(dirpath, "r"); - if (!fp) - break; - - while ((rc_getline(&line, &len, fp))) { - p = line; - if ((token = strsep(&p, "=")) == NULL || !p) - continue; - - if (!*p) - continue; - - if (strcmp(token, "exec") == 0) { - if (exec) - free(exec); - exec = xstrdup(p); - } else if (strncmp(token, "argv_", 5) == 0) { - if (!list) - list = rc_stringlist_new(); - rc_stringlist_add(list, p); - } else if (strcmp(token, "name") == 0) { - if (name) - free(name); - name = xstrdup(p); - } else if (strcmp(token, "pidfile") == 0) { - pidfile = xstrdup(p); - break; - } - } - fclose(fp); - - char *ch_root = rc_service_value_get(basename_c(service), "chroot"); - char *spidfile = pidfile; - if (ch_root && pidfile) { - spidfile = xmalloc(strlen(ch_root) + strlen(pidfile) + 1); - strcpy(spidfile, ch_root); - strcat(spidfile, pidfile); - } - - pid = 0; - if (spidfile) { - retval = true; - if ((fp = fopen(spidfile, "r"))) { - if (fscanf(fp, "%d", &pid) == 1) - retval = false; - fclose(fp); - } - free(spidfile); - spidfile = NULL; - if (ch_root) { - free(pidfile); - pidfile = NULL; - } - - /* We have the pid, so no need to match - on exec or name */ - free(exec); - exec = NULL; - free(name); - name = NULL; - } else { - if (exec) { - if (!list) - list = rc_stringlist_new(); - if (!TAILQ_FIRST(list)) - rc_stringlist_add(list, exec); - - free(exec); - exec = NULL; - } - - if (list) { - /* We need to flatten our linked list - into an array */ - i = 0; - TAILQ_FOREACH(s, list, entries) - i++; - argv = xmalloc(sizeof(char *) * (i + 1)); - i = 0; - TAILQ_FOREACH(s, list, entries) - argv[i++] = s->value; - argv[i] = '\0'; - } - } - - if (!retval) { - if (pid != 0) { - if (kill(pid, 0) == -1 && errno == ESRCH) - retval = true; - } else if ((pids = rc_find_pids(exec, - (const char *const *)argv, - 0, pid))) - { - p1 = LIST_FIRST(pids); - while (p1) { - p2 = LIST_NEXT(p1, entries); - free(p1); - p1 = p2; - } - free(pids); - } else - retval = true; - } - rc_stringlist_free(list); - list = NULL; - free(argv); - argv = NULL; - free(exec); - exec = NULL; - free(name); - name = NULL; - if (retval) - break; - } - closedir(dp); - free(line); - - return retval; -} -librc_hidden_def(rc_service_daemons_crashed) diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c deleted file mode 100644 index d7a8ae14..00000000 --- a/src/librc/librc-depend.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - librc-depend - rc service dependency and ordering - */ - -/* - * Copyright (c) 2007-2009 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. - */ - -#include <sys/utsname.h> - -#include "queue.h" -#include "librc.h" - -#define GENDEP RC_LIBEXECDIR "/sh/gendepends.sh" - -#define RC_DEPCONFIG RC_SVCDIR "/depconfig" - -static const char *bootlevel = NULL; - -static char * -get_shell_value(char *string) -{ - char *p = string; - char *e; - - if (! string) - return NULL; - - if (*p == '\'') - p++; - - e = p + strlen(p) - 1; - if (*e == '\n') - *e-- = 0; - if (*e == '\'') - *e-- = 0; - - if (*p != 0) - return p; - - return NULL; -} - -void -rc_deptree_free(RC_DEPTREE *deptree) -{ - RC_DEPINFO *di; - RC_DEPINFO *di2; - RC_DEPTYPE *dt; - RC_DEPTYPE *dt2; - - if (!deptree) - return; - - di = TAILQ_FIRST(deptree); - while (di) { - di2 = TAILQ_NEXT(di, entries); - dt = TAILQ_FIRST(&di->depends); - while (dt) { - dt2 = TAILQ_NEXT(dt, entries); - rc_stringlist_free(dt->services); - free(dt->type); - free(dt); - dt = dt2; - } - free(di->service); - free(di); - di = di2; - } - free(deptree); -} -librc_hidden_def(rc_deptree_free) - -static RC_DEPINFO * -get_depinfo(const RC_DEPTREE *deptree, const char *service) -{ - RC_DEPINFO *di; - - TAILQ_FOREACH(di, deptree, entries) - if (strcmp(di->service, service) == 0) - return di; - return NULL; -} - -static RC_DEPTYPE * -get_deptype(const RC_DEPINFO *depinfo, const char *type) -{ - RC_DEPTYPE *dt; - - TAILQ_FOREACH(dt, &depinfo->depends, entries) - if (strcmp(dt->type, type) == 0) - return dt; - return NULL; -} - -RC_DEPTREE * -rc_deptree_load(void) { - return rc_deptree_load_file(RC_DEPTREE_CACHE); -} -librc_hidden_def(rc_deptree_load) - -RC_DEPTREE * -rc_deptree_load_file(const char *deptree_file) -{ - FILE *fp; - RC_DEPTREE *deptree; - RC_DEPINFO *depinfo = NULL; - RC_DEPTYPE *deptype = NULL; - char *line = NULL; - size_t len = 0; - char *type; - char *p; - char *e; - int i; - - if (!(fp = fopen(deptree_file, "r"))) - return NULL; - - deptree = xmalloc(sizeof(*deptree)); - TAILQ_INIT(deptree); - while ((rc_getline(&line, &len, fp))) - { - p = line; - e = strsep(&p, "_"); - if (!e || strcmp(e, "depinfo") != 0) - continue; - e = strsep(&p, "_"); - if (!e || sscanf(e, "%d", &i) != 1) - continue; - if (!(type = strsep(&p, "_="))) - continue; - if (strcmp(type, "service") == 0) { - /* Sanity */ - e = get_shell_value(p); - if (! e || *e == '\0') - continue; - depinfo = xmalloc(sizeof(*depinfo)); - TAILQ_INIT(&depinfo->depends); - depinfo->service = xstrdup(e); - TAILQ_INSERT_TAIL(deptree, depinfo, entries); - deptype = NULL; - continue; - } - e = strsep(&p, "="); - if (!e || sscanf(e, "%d", &i) != 1) - continue; - /* Sanity */ - e = get_shell_value(p); - if (!e || *e == '\0') - continue; - if (!deptype || strcmp(deptype->type, type) != 0) { - deptype = xmalloc(sizeof(*deptype)); - deptype->services = rc_stringlist_new(); - deptype->type = xstrdup(type); - TAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); - } - rc_stringlist_add(deptype->services, e); - } - fclose(fp); - free(line); - - return deptree; -} -librc_hidden_def(rc_deptree_load_file) - -static bool -valid_service(const char *runlevel, const char *service, const char *type) -{ - RC_SERVICE state; - - if (!runlevel || - strcmp(type, "ineed") == 0 || - strcmp(type, "needsme") == 0) - return true; - - if (rc_service_in_runlevel(service, runlevel)) - return true; - if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0) - return false; - if (strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 && - strcmp(type, "iafter") == 0) - return false; - if (strcmp(runlevel, bootlevel) != 0) { - if (rc_service_in_runlevel(service, bootlevel)) - return true; - } - - state = rc_service_state(service); - if (state & RC_SERVICE_HOTPLUGGED || - state & RC_SERVICE_STARTED) - return true; - - return false; -} - -static bool -get_provided1(const char *runlevel, RC_STRINGLIST *providers, - RC_DEPTYPE *deptype, const char *level, - bool hotplugged, RC_SERVICE state) -{ - RC_STRING *service; - RC_SERVICE st; - bool retval = false; - bool ok; - const char *svc; - - TAILQ_FOREACH(service, deptype->services, entries) { - ok = true; - svc = service->value; - st = rc_service_state(svc); - - if (level) - ok = rc_service_in_runlevel(svc, level); - else if (hotplugged) - ok = (st & RC_SERVICE_HOTPLUGGED && - !rc_service_in_runlevel(svc, runlevel) && - !rc_service_in_runlevel(svc, bootlevel)); - if (!ok) - continue; - switch (state) { - case RC_SERVICE_STARTED: - ok = (st & RC_SERVICE_STARTED); - break; - case RC_SERVICE_INACTIVE: - case RC_SERVICE_STARTING: - case RC_SERVICE_STOPPING: - ok = (st & RC_SERVICE_STARTING || - st & RC_SERVICE_STOPPING || - st & RC_SERVICE_INACTIVE); - break; - default: - break; - } - if (!ok) - continue; - retval = true; - rc_stringlist_add(providers, svc); - } - - return retval; -} - -/* Work out if a service is provided by another service. - For example metalog provides logger. - We need to be able to handle syslogd providing logger too. - We do this by checking whats running, then what's starting/stopping, - then what's run in the runlevels and finally alphabetical order. - - If there are any bugs in rc-depend, they will probably be here as - provided dependancy can change depending on runlevel state. - */ -static RC_STRINGLIST * -get_provided(const RC_DEPINFO *depinfo, const char *runlevel, int options) -{ - RC_DEPTYPE *dt; - RC_STRINGLIST *providers = rc_stringlist_new(); - RC_STRING *service; - - dt = get_deptype(depinfo, "providedby"); - if (!dt) - return providers; - - /* If we are stopping then all depends are true, regardless of state. - This is especially true for net services as they could force a restart - of the local dns resolver which may depend on net. */ - if (options & RC_DEP_STOP) { - TAILQ_FOREACH(service, dt->services, entries) - rc_stringlist_add(providers, service->value); - return providers; - } - - /* If we're strict or starting, then only use what we have in our - * runlevel and bootlevel. If we starting then check hotplugged too. */ - if (options & RC_DEP_STRICT || options & RC_DEP_START) { - TAILQ_FOREACH(service, dt->services, entries) - if (rc_service_in_runlevel(service->value, runlevel) || - rc_service_in_runlevel(service->value, bootlevel) || - (options & RC_DEP_START && - rc_service_state(service->value) & RC_SERVICE_HOTPLUGGED)) - rc_stringlist_add(providers, service->value); - if (TAILQ_FIRST(providers)) - return providers; - } - - /* OK, we're not strict or there were no services in our runlevel. - * This is now where the logic gets a little fuzzy :) - * If there is >1 running service then we return NULL. - * We do this so we don't hang around waiting for inactive services and - * our need has already been satisfied as it's not strict. - * We apply this to these states in order:- - * started, starting | stopping | inactive, stopped - * Our sub preference in each of these is in order:- - * runlevel, hotplugged, bootlevel, any - */ -#define DO \ - if (TAILQ_FIRST(providers)) { \ - if (TAILQ_NEXT(TAILQ_FIRST(providers), entries)) { \ - rc_stringlist_free(providers); \ - providers = rc_stringlist_new(); \ - } \ - return providers; \ - } - - /* Anything running has to come first */ - if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTED)) - { DO } - if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STARTED)) - { DO } - if (bootlevel && strcmp(runlevel, bootlevel) != 0 && - get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTED)) - { DO } - if (get_provided1(runlevel, providers, dt, NULL, false, RC_SERVICE_STARTED)) - { DO } - - /* Check starting services */ - if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTING)) - return providers; - if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STARTING)) - return providers; - if (bootlevel && strcmp(runlevel, bootlevel) != 0 && - get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTING)) - return providers; - if (get_provided1(runlevel, providers, dt, NULL, false, RC_SERVICE_STARTING)) - return providers; - - /* Nothing started then. OK, lets get the stopped services */ - if (get_provided1(runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) - return providers; - if (get_provided1(runlevel, providers, dt, NULL, true, RC_SERVICE_STOPPED)) - { DO } - if (bootlevel && (strcmp(runlevel, bootlevel) != 0) && - get_provided1(runlevel, providers, dt, bootlevel, false, RC_SERVICE_STOPPED)) - return providers; - - /* Still nothing? OK, list our first provided service. */ - service = TAILQ_FIRST(dt->services); - if (service != NULL) - rc_stringlist_add(providers, service->value); - - return providers; -} - -static void -visit_service(const RC_DEPTREE *deptree, - const RC_STRINGLIST *types, - RC_STRINGLIST *sorted, - RC_STRINGLIST *visited, - const RC_DEPINFO *depinfo, - const char *runlevel, int options) -{ - RC_STRING *type; - RC_STRING *service; - RC_DEPTYPE *dt; - RC_DEPINFO *di; - RC_STRINGLIST *provided; - RC_STRING *p; - const char *svcname; - - /* Check if we have already visited this service or not */ - TAILQ_FOREACH(type, visited, entries) - if (strcmp(type->value, depinfo->service) == 0) - return; - /* Add ourselves as a visited service */ - rc_stringlist_add(visited, depinfo->service); - - TAILQ_FOREACH(type, types, entries) - { - if (!(dt = get_deptype(depinfo, type->value))) - continue; - - TAILQ_FOREACH(service, dt->services, entries) { - if (!(options & RC_DEP_TRACE) || - strcmp(type->value, "iprovide") == 0) - { - rc_stringlist_add(sorted, service->value); - continue; - } - - if (!(di = get_depinfo(deptree, service->value))) - continue; - provided = get_provided(di, runlevel, options); - - if (TAILQ_FIRST(provided)) { - TAILQ_FOREACH(p, provided, entries) { - di = get_depinfo(deptree, p->value); - if (di && valid_service(runlevel, di->service, type->value)) - visit_service(deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - } - } - else if (di && valid_service(runlevel, service->value, type->value)) - visit_service(deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - - rc_stringlist_free(provided); - } - } - - /* Now visit the stuff we provide for */ - if (options & RC_DEP_TRACE && - (dt = get_deptype(depinfo, "iprovide"))) - { - TAILQ_FOREACH(service, dt->services, entries) { - if (!(di = get_depinfo(deptree, service->value))) - continue; - provided = get_provided(di, runlevel, options); - TAILQ_FOREACH(p, provided, entries) - if (strcmp(p->value, depinfo->service) == 0) { - visit_service(deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - break; - } - rc_stringlist_free(provided); - } - } - - /* We've visited everything we need, so add ourselves unless we - are also the service calling us or we are provided by something */ - svcname = getenv("RC_SVCNAME"); - if (!svcname || strcmp(svcname, depinfo->service) != 0) { - if (!get_deptype(depinfo, "providedby")) - rc_stringlist_add(sorted, depinfo->service); - } -} - -RC_STRINGLIST * -rc_deptree_depend(const RC_DEPTREE *deptree, - const char *service, const char *type) -{ - RC_DEPINFO *di; - RC_DEPTYPE *dt; - RC_STRINGLIST *svcs; - RC_STRING *svc; - - svcs = rc_stringlist_new(); - if (!(di = get_depinfo(deptree, service)) || - !(dt = get_deptype(di, type))) - { - errno = ENOENT; - return svcs; - } - - /* For consistency, we copy the array */ - TAILQ_FOREACH(svc, dt->services, entries) - rc_stringlist_add(svcs, svc->value); - return svcs; -} -librc_hidden_def(rc_deptree_depend) - -RC_STRINGLIST * -rc_deptree_depends(const RC_DEPTREE *deptree, - const RC_STRINGLIST *types, - const RC_STRINGLIST *services, - const char *runlevel, int options) -{ - RC_STRINGLIST *sorted = rc_stringlist_new(); - RC_STRINGLIST *visited = rc_stringlist_new(); - RC_DEPINFO *di; - const RC_STRING *service; - - bootlevel = getenv("RC_BOOTLEVEL"); - if (!bootlevel) - bootlevel = RC_LEVEL_BOOT; - TAILQ_FOREACH(service, services, entries) { - if (!(di = get_depinfo(deptree, service->value))) { - errno = ENOENT; - continue; - } - if (types) - visit_service(deptree, types, sorted, visited, - di, runlevel, options); - } - rc_stringlist_free(visited); - return sorted; -} -librc_hidden_def(rc_deptree_depends) - -RC_STRINGLIST * -rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options) -{ - RC_STRINGLIST *list; - RC_STRINGLIST *list2; - RC_STRINGLIST *types; - RC_STRINGLIST *services; - - bootlevel = getenv("RC_BOOTLEVEL"); - if (! bootlevel) - bootlevel = RC_LEVEL_BOOT; - - /* When shutting down, list all running services */ - if (strcmp(runlevel, RC_LEVEL_SINGLE) == 0 || - strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0) - { - list = rc_services_in_state(RC_SERVICE_STARTED); - list2 = rc_services_in_state(RC_SERVICE_INACTIVE); - TAILQ_CONCAT(list, list2, entries); - free(list2); - list2 = rc_services_in_state(RC_SERVICE_STARTING); - TAILQ_CONCAT(list, list2, entries); - free(list2); - } else { - list = rc_services_in_runlevel(RC_LEVEL_SYSINIT); - if (strcmp(runlevel, RC_LEVEL_SYSINIT) != 0) { - list2 = rc_services_in_runlevel(runlevel); - TAILQ_CONCAT(list, list2, entries); - free(list2); - list2 = rc_services_in_state(RC_SERVICE_HOTPLUGGED); - TAILQ_CONCAT(list, list2, entries); - free(list2); - /* If we're not the boot runlevel then add that too */ - if (strcmp(runlevel, bootlevel) != 0) { - list2 = rc_services_in_runlevel(bootlevel); - TAILQ_CONCAT(list, list2, entries); - free(list2); - } - } - } - - /* Now we have our lists, we need to pull in any dependencies - and order them */ - types = rc_stringlist_new(); - rc_stringlist_add(types, "ineed"); - rc_stringlist_add(types, "iuse"); - rc_stringlist_add(types, "iafter"); - services = rc_deptree_depends(deptree, types, list, runlevel, - RC_DEP_STRICT | RC_DEP_TRACE | options); - rc_stringlist_free(list); - rc_stringlist_free(types); - return services; -} -librc_hidden_def(rc_deptree_order) - -static bool -mtime_check(const char *source, const char *target, bool newer, - time_t *rel, char *file) -{ - struct stat buf; - time_t mtime; - bool retval = true; - DIR *dp; - struct dirent *d; - char path[PATH_MAX]; - int serrno = errno; - - /* We have to exist */ - if (stat(source, &buf) != 0) - return false; - mtime = buf.st_mtime; - - /* If target does not exist, return true to mimic shell test */ - if (stat(target, &buf) != 0) - return true; - - if (newer) { - if (mtime < buf.st_mtime) { - if (rel == NULL) - return false; - retval = false; - } - if (rel != NULL) { - if (*rel < buf.st_mtime) { - if (file) - strlcpy(file, target, PATH_MAX); - *rel = buf.st_mtime; - } - } - } else { - if (mtime > buf.st_mtime) { - if (rel == NULL) - return false; - retval = false; - } - if (rel != NULL) { - if (*rel > buf.st_mtime) { - if (file) - strlcpy(file, target, PATH_MAX); - *rel = buf.st_mtime; - } - } - } - - /* If not a dir then reset errno */ - if (!(dp = opendir(target))) { - errno = serrno; - return retval; - } - - /* Check all the entries in the dir */ - while ((d = readdir(dp))) { - if (d->d_name[0] == '.') - continue; - snprintf(path, sizeof(path), "%s/%s", target, d->d_name); - if (!mtime_check(source, path, newer, rel, file)) { - retval = false; - if (rel == NULL) - break; - } - } - closedir(dp); - return retval; -} - -bool -rc_newer_than(const char *source, const char *target, - time_t *newest, char *file) -{ - - return mtime_check(source, target, true, newest, file); -} -librc_hidden_def(rc_newer_than) - -bool -rc_older_than(const char *source, const char *target, - time_t *oldest, char *file) -{ - return mtime_check(source, target, false, oldest, file); -} -librc_hidden_def(rc_older_than) - -typedef struct deppair -{ - const char *depend; - const char *addto; -} DEPPAIR; - -static const DEPPAIR deppairs[] = { - { "ineed", "needsme" }, - { "iuse", "usesme" }, - { "iafter", "ibefore" }, - { "ibefore", "iafter" }, - { "iprovide", "providedby" }, - { NULL, NULL } -}; - -static const char *const depdirs[] = -{ - RC_SVCDIR, - RC_SVCDIR "/starting", - RC_SVCDIR "/started", - RC_SVCDIR "/stopping", - RC_SVCDIR "/inactive", - RC_SVCDIR "/wasinactive", - RC_SVCDIR "/failed", - RC_SVCDIR "/hotplugged", - RC_SVCDIR "/daemons", - RC_SVCDIR "/options", - RC_SVCDIR "/exclusive", - RC_SVCDIR "/scheduled", - RC_SVCDIR "/tmp", - NULL -}; - -bool -rc_deptree_update_needed(time_t *newest, char *file) -{ - bool newer = false; - RC_STRINGLIST *config; - RC_STRING *s; - int i; - - /* Create base directories if needed */ - for (i = 0; depdirs[i]; i++) - if (mkdir(depdirs[i], 0755) != 0 && errno != EEXIST) - fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror(errno)); - - /* Quick test to see if anything we use has changed and we have - * data in our deptree */ - if (!existss(RC_DEPTREE_CACHE)) - return true; - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR, newest, file)) - return true; - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR, newest, file)) - return true; -#ifdef RC_PKG_INITDIR - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR, newest, file)) - return true; -#endif -#ifdef RC_PKG_CONFDIR - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR, newest, file)) - return true; -#endif -#ifdef RC_LOCAL_INITDIR - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR, newest, file)) - return true; -#endif -#ifdef RC_LOCAL_CONFDIR - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR, newest, file)) - return true; -#endif - if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONF, newest, file)) - return true; - - /* Some init scripts dependencies change depending on config files - * outside of baselayout, like syslog-ng, so we check those too. */ - config = rc_config_list(RC_DEPCONFIG); - TAILQ_FOREACH(s, config, entries) { - if (!rc_newer_than(RC_DEPTREE_CACHE, s->value, newest, file)) { - newer = true; - break; - } - } - rc_stringlist_free(config); - return newer; -} -librc_hidden_def(rc_deptree_update_needed) - -/* This is a 6 phase operation - Phase 1 is a shell script which loads each init script and config in turn - and echos their dependency info to stdout - Phase 2 takes that and populates a depinfo object with that data - Phase 3 adds any provided services to the depinfo object - Phase 4 scans that depinfo object and puts in backlinks - Phase 5 removes broken before dependencies - Phase 6 saves the depinfo object to disk - */ -bool -rc_deptree_update(void) -{ - FILE *fp; - RC_DEPTREE *deptree, *providers; - RC_DEPINFO *depinfo = NULL, *depinfo_np, *di; - RC_DEPTYPE *deptype = NULL, *dt_np, *dt, *provide; - RC_STRINGLIST *config, *types, *sorted, *visited; - RC_STRING *s, *s2, *s2_np, *s3, *s4; - char *line = NULL; - size_t len = 0; - char *depend, *depends, *service, *type, *nosys, *onosys; - size_t i, k, l; - bool retval = true; - const char *sys = rc_sys(); - struct utsname uts; - - /* Some init scripts need RC_LIBEXECDIR to source stuff - Ideally we should be setting our full env instead */ - if (!getenv("RC_LIBEXECDIR")) - setenv("RC_LIBEXECDIR", RC_LIBEXECDIR, 0); - - if (uname(&uts) == 0) - setenv("RC_UNAME", uts.sysname, 1); - /* Phase 1 - source all init scripts and print dependencies */ - if (!(fp = popen(GENDEP, "r"))) - return false; - - deptree = xmalloc(sizeof(*deptree)); - TAILQ_INIT(deptree); - config = rc_stringlist_new(); - while ((rc_getline(&line, &len, fp))) - { - depends = line; - service = strsep(&depends, " "); - if (!service || !*service) - continue; - - type = strsep(&depends, " "); - if (!depinfo || strcmp(depinfo->service, service) != 0) { - deptype = NULL; - depinfo = get_depinfo(deptree, service); - if (!depinfo) { - depinfo = xmalloc(sizeof(*depinfo)); - TAILQ_INIT(&depinfo->depends); - depinfo->service = xstrdup(service); - TAILQ_INSERT_TAIL(deptree, depinfo, entries); - } - } - - /* We may not have any depends */ - if (!type || !depends) - continue; - - /* Get the type */ - if (strcmp(type, "config") != 0) { - if (!deptype || strcmp(deptype->type, type) != 0) - deptype = get_deptype(depinfo, type); - if (!deptype) { - deptype = xmalloc(sizeof(*deptype)); - deptype->type = xstrdup(type); - deptype->services = rc_stringlist_new(); - TAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); - } - } - - /* Now add each depend to our type. - We do this individually so we handle multiple spaces gracefully */ - while ((depend = strsep(&depends, " "))) - { - if (depend[0] == 0) - continue; - - if (strcmp(type, "config") == 0) { - rc_stringlist_addu(config, depend); - continue; - } - - /* Don't provide ourself */ - if (strcmp(type, "iprovide") == 0 && - strcmp(depend, service) == 0) - continue; - - /* .sh files are not init scripts */ - l = strlen(depend); - if (l > 2 && - depend[l - 3] == '.' && - depend[l - 2] == 's' && - depend[l - 1] == 'h') - continue; - - /* Remove our dependency if instructed */ - if (depend[0] == '!') { - rc_stringlist_delete(deptype->services, depend + 1); - continue; - } - - rc_stringlist_add(deptype->services, depend); - - /* We need to allow `after *; before local;` to work. - * Conversely, we need to allow 'before *; after modules' also */ - /* If we're before something, remove us from the after list */ - if (strcmp(type, "ibefore") == 0) { - if ((dt = get_deptype(depinfo, "iafter"))) - rc_stringlist_delete(dt->services, depend); - } - /* If we're after something, remove us from the before list */ - if (strcmp(type, "iafter") == 0 || - strcmp(type, "ineed") == 0 || - strcmp(type, "iuse") == 0) { - if ((dt = get_deptype(depinfo, "ibefore"))) - rc_stringlist_delete(dt->services, depend); - } - } - } - free(line); - pclose(fp); - - /* Phase 2 - if we're a special system, remove services that don't - * work for them. This doesn't stop them from being run directly. */ - if (sys) { - len = strlen(sys); - nosys = xmalloc(len + 2); - nosys[0] = '-'; - for (i = 0; i < len; i++) - nosys[i + 1] = (char)tolower((unsigned char)sys[i]); - nosys[i + 1] = '\0'; - - onosys = xmalloc(len + 3); - onosys[0] = 'n'; - onosys[1] = 'o'; - for (i = 0; i < len; i++) - onosys[i + 2] = (char)tolower((unsigned char)sys[i]); - onosys[i + 2] = '\0'; - - TAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_np) - if ((deptype = get_deptype(depinfo, "keyword"))) - TAILQ_FOREACH(s, deptype->services, entries) - if (strcmp(s->value, nosys) == 0 || - strcmp(s->value, onosys) == 0) - { - provide = get_deptype(depinfo, "iprovide"); - TAILQ_REMOVE(deptree, depinfo, entries); - TAILQ_FOREACH(di, deptree, entries) { - TAILQ_FOREACH_SAFE(dt, &di->depends, entries, dt_np) { - rc_stringlist_delete(dt->services, depinfo->service); - if (provide) - TAILQ_FOREACH(s2, provide->services, entries) - rc_stringlist_delete(dt->services, s2->value); - if (!TAILQ_FIRST(dt->services)) { - TAILQ_REMOVE(&di->depends, dt, entries); - free(dt->type); - free(dt->services); - free(dt); - } - } - } - } - free(nosys); - free(onosys); - } - - /* Phase 3 - add our providers to the tree */ - providers = xmalloc(sizeof(*providers)); - TAILQ_INIT(providers); - TAILQ_FOREACH(depinfo, deptree, entries) - if ((deptype = get_deptype(depinfo, "iprovide"))) - TAILQ_FOREACH(s, deptype->services, entries) { - TAILQ_FOREACH(di, providers, entries) - if (strcmp(di->service, s->value) == 0) - break; - if (!di) { - di = xmalloc(sizeof(*di)); - TAILQ_INIT(&di->depends); - di->service = xstrdup(s->value); - TAILQ_INSERT_TAIL(providers, di, entries); - } - } - TAILQ_CONCAT(deptree, providers, entries); - free(providers); - - /* Phase 4 - backreference our depends */ - TAILQ_FOREACH(depinfo, deptree, entries) - for (i = 0; deppairs[i].depend; i++) { - deptype = get_deptype(depinfo, deppairs[i].depend); - if (!deptype) - continue; - TAILQ_FOREACH(s, deptype->services, entries) { - di = get_depinfo(deptree, s->value); - if (!di) { - if (strcmp(deptype->type, "ineed") == 0) { - fprintf(stderr, - "Service `%s' needs non" - " existent service `%s'\n", - depinfo->service, s->value); - dt = get_deptype(depinfo, "broken"); - if (!dt) { - dt = xmalloc(sizeof(*dt)); - dt->type = xstrdup("broken"); - dt->services = rc_stringlist_new(); - TAILQ_INSERT_TAIL(&depinfo->depends, dt, entries); - } - rc_stringlist_addu(dt->services, s->value); - } - continue; - } - - dt = get_deptype(di, deppairs[i].addto); - if (!dt) { - dt = xmalloc(sizeof(*dt)); - dt->type = xstrdup(deppairs[i].addto); - dt->services = rc_stringlist_new(); - TAILQ_INSERT_TAIL(&di->depends, dt, entries); - } - rc_stringlist_addu(dt->services, depinfo->service); - } - } - - - /* Phase 5 - Remove broken before directives */ - types = rc_stringlist_new(); - rc_stringlist_add(types, "ineed"); - rc_stringlist_add(types, "iuse"); - rc_stringlist_add(types, "iafter"); - TAILQ_FOREACH(depinfo, deptree, entries) { - deptype = get_deptype(depinfo, "ibefore"); - if (!deptype) - continue; - sorted = rc_stringlist_new(); - visited = rc_stringlist_new(); - visit_service(deptree, types, sorted, visited, depinfo, - NULL, 0); - rc_stringlist_free(visited); - TAILQ_FOREACH_SAFE(s2, deptype->services, entries, s2_np) { - TAILQ_FOREACH(s3, sorted, entries) { - di = get_depinfo(deptree, s3->value); - if (!di) - continue; - if (strcmp(s2->value, s3->value) == 0) { - dt = get_deptype(di, "iafter"); - if (dt) - rc_stringlist_delete(dt->services, depinfo->service); - break; - } - dt = get_deptype(di, "iprovide"); - if (!dt) - continue; - TAILQ_FOREACH(s4, dt->services, entries) { - if (strcmp(s4->value, s2->value) == 0) - break; - } - if (s4) { - di = get_depinfo(deptree, s4->value); - if (di) { - dt = get_deptype(di, "iafter"); - if (dt) - rc_stringlist_delete(dt->services, depinfo->service); - } - break; - } - } - if (s3) - rc_stringlist_delete(deptype->services, s2->value); - } - rc_stringlist_free(sorted); - } - rc_stringlist_free(types); - - /* Phase 6 - save to disk - Now that we're purely in C, do we need to keep a shell parseable file? - I think yes as then it stays human readable - This works and should be entirely shell parseable provided that depend - names don't have any non shell variable characters in - */ - if ((fp = fopen(RC_DEPTREE_CACHE, "w"))) { - i = 0; - TAILQ_FOREACH(depinfo, deptree, entries) { - fprintf(fp, "depinfo_%zu_service='%s'\n", - i, depinfo->service); - TAILQ_FOREACH(deptype, &depinfo->depends, entries) { - k = 0; - TAILQ_FOREACH(s, deptype->services, entries) { - fprintf(fp, - "depinfo_%zu_%s_%zu='%s'\n", - i, deptype->type, k, s->value); - k++; - } - } - i++; - } - fclose(fp); - } else { - fprintf(stderr, "fopen `%s': %s\n", - RC_DEPTREE_CACHE, strerror(errno)); - retval = false; - } - - /* Save our external config files to disk */ - if (TAILQ_FIRST(config)) { - if ((fp = fopen(RC_DEPCONFIG, "w"))) { - TAILQ_FOREACH(s, config, entries) - fprintf(fp, "%s\n", s->value); - fclose(fp); - } else { - fprintf(stderr, "fopen `%s': %s\n", - RC_DEPCONFIG, strerror(errno)); - retval = false; - } - } else { - unlink(RC_DEPCONFIG); - } - - rc_stringlist_free(config); - rc_deptree_free(deptree); - return retval; -} -librc_hidden_def(rc_deptree_update) diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c deleted file mode 100644 index 2e9de801..00000000 --- a/src/librc/librc-misc.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - rc-misc.c - rc misc 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. - */ - -#include "queue.h" -#include "librc.h" - -bool -rc_yesno(const char *value) -{ - if (!value) { - errno = ENOENT; - return false; - } - - if (strcasecmp(value, "yes") == 0 || - strcasecmp(value, "y") == 0 || - strcasecmp(value, "true") == 0 || - strcasecmp(value, "1") == 0) - return true; - - if (strcasecmp(value, "no") != 0 && - strcasecmp(value, "n") != 0 && - strcasecmp(value, "false") != 0 && - strcasecmp(value, "0") != 0) - errno = EINVAL; - - return false; -} -librc_hidden_def(rc_yesno) - - -/** - * Read the entire @file into the buffer and set @len to the - * size of the buffer when finished. For C strings, this will - * be strlen(buffer) + 1. - * Don't forget to free the buffer afterwards! - */ -bool -rc_getfile(const char *file, char **buffer, size_t *len) -{ - bool ret = false; - FILE *fp; - int fd; - struct stat st; - size_t done, left; - - fp = fopen(file, "re"); - if (!fp) - return false; - - /* assume fileno() never fails */ - fd = fileno(fp); - - if (fstat(fd, &st)) - goto finished; - - left = st.st_size; - *len = left + 1; /* NUL terminator */ - *buffer = xrealloc(*buffer, *len); - while (left) { - done = fread(*buffer, sizeof(*buffer[0]), left, fp); - if (done == 0 && ferror(fp)) - goto finished; - left -= done; - } - ret = true; - - finished: - if (!ret) { - free(*buffer); - *len = 0; - } else - (*buffer)[*len - 1] = '\0'; - fclose(fp); - return ret; -} -librc_hidden_def(rc_getfile) - -ssize_t -rc_getline(char **line, size_t *len, FILE *fp) -{ - char *p; - size_t last = 0; - - while (!feof(fp)) { - if (*line == NULL || last != 0) { - *len += BUFSIZ; - *line = xrealloc(*line, *len); - } - p = *line + last; - memset(p, 0, BUFSIZ); - if (fgets(p, BUFSIZ, fp) == NULL) - break; - last += strlen(p); - if (last && (*line)[last - 1] == '\n') { - (*line)[last - 1] = '\0'; - break; - } - } - return last; -} -librc_hidden_def(rc_getline) - -char * -rc_proc_getent(const char *ent) -{ -#ifdef __linux__ - FILE *fp; - char *proc, *p, *value = NULL; - size_t i, len; - - if (!exists("/proc/cmdline")) - return NULL; - - if (!(fp = fopen("/proc/cmdline", "r"))) - return NULL; - - proc = NULL; - i = 0; - if (rc_getline(&proc, &i, fp) == -1 || proc == NULL) - return NULL; - - if (proc != NULL) { - len = strlen(ent); - - while ((p = strsep(&proc, " "))) { - if (strncmp(ent, p, len) == 0 && (p[len] == '\0' || p[len] == ' ' || p[len] == '=')) { - p += len; - - if (*p == '=') - p++; - - value = xstrdup(p); - } - } - } - - if (!value) - errno = ENOENT; - - fclose(fp); - free(proc); - - return value; -#else - return NULL; -#endif -} -librc_hidden_def(rc_proc_getent) - -RC_STRINGLIST * -rc_config_list(const char *file) -{ - FILE *fp; - char *buffer = NULL; - size_t len = 0; - char *p; - char *token; - RC_STRINGLIST *list = rc_stringlist_new(); - - if (!(fp = fopen(file, "r"))) - return list; - - while ((rc_getline(&buffer, &len, fp))) { - p = buffer; - /* Strip leading spaces/tabs */ - while ((*p == ' ') || (*p == '\t')) - p++; - - /* Get entry - we do not want comments */ - token = strsep(&p, "#"); - if (token && (strlen(token) > 1)) { - /* If not variable assignment then skip */ - if (strchr(token, '=')) { - /* Stip the newline if present */ - if (token[strlen(token) - 1] == '\n') - token[strlen(token) - 1] = 0; - - rc_stringlist_add(list, token); - } - } - } - fclose(fp); - free(buffer); - - return list; -} -librc_hidden_def(rc_config_list) - -/* - * Override some specific rc.conf options on the kernel command line - */ -#ifdef __linux__ -static RC_STRINGLIST *rc_config_override(RC_STRINGLIST *config) -{ - RC_STRINGLIST *overrides; - RC_STRING *cline, *override, *config_np; - char *tmp = NULL; - char *value = NULL; - size_t varlen = 0; - size_t len = 0; - - overrides = rc_stringlist_new(); - - /* A list of variables which may be overridden on the kernel command line */ - rc_stringlist_add(overrides, "rc_parallel"); - - TAILQ_FOREACH(override, overrides, entries) { - varlen = strlen(override->value); - value = rc_proc_getent(override->value); - - /* No need to continue if there's nothing to override */ - if (!value) { - free(value); - continue; - } - - if (value != NULL) { - len = varlen + strlen(value) + 2; - tmp = xmalloc(sizeof(char) * len); - snprintf(tmp, len, "%s=%s", override->value, value); - } - - /* - * Whenever necessary remove the old config entry first to prevent - * duplicates - */ - TAILQ_FOREACH_SAFE(cline, config, entries, config_np) { - if (strncmp(override->value, cline->value, varlen) == 0 - && cline->value[varlen] == '=') { - rc_stringlist_delete(config, cline->value); - break; - } - } - - /* Add the option (var/value) to the current config */ - rc_stringlist_add(config, tmp); - - free(tmp); - free(value); - } - - rc_stringlist_free(overrides); - return config; -} -#endif - -RC_STRINGLIST * -rc_config_load(const char *file) -{ - RC_STRINGLIST *list; - RC_STRINGLIST *config; - char *token; - RC_STRING *line; - RC_STRING *cline; - size_t i = 0; - bool replaced; - char *entry; - char *newline; - char *p; - - list = rc_config_list(file); - config = rc_stringlist_new(); - TAILQ_FOREACH(line, list, entries) { - /* Get entry */ - p = line->value; - if (! p) - continue; - if (strncmp(p, "export ", 7) == 0) - p += 7; - if (! (token = strsep(&p, "="))) - continue; - - entry = xstrdup(token); - /* Preserve shell coloring */ - if (*p == '$') - token = line->value; - else - do { - /* Bash variables are usually quoted */ - token = strsep(&p, "\"\'"); - } while (token && *token == '\0'); - - /* Drop a newline if that's all we have */ - if (token) { - i = strlen(token) - 1; - if (token[i] == '\n') - token[i] = 0; - - i = strlen(entry) + strlen(token) + 2; - newline = xmalloc(sizeof(char) * i); - snprintf(newline, i, "%s=%s", entry, token); - } else { - i = strlen(entry) + 2; - newline = xmalloc(sizeof(char) * i); - snprintf(newline, i, "%s=", entry); - } - - replaced = false; - /* In shells the last item takes precedence, so we need to remove - any prior values we may already have */ - TAILQ_FOREACH(cline, config, entries) { - i = strlen(entry); - if (strncmp(entry, cline->value, i) == 0 && cline->value[i] == '=') { - /* We have a match now - to save time we directly replace it */ - free(cline->value); - cline->value = newline; - replaced = true; - break; - } - } - - if (!replaced) { - rc_stringlist_add(config, newline); - free(newline); - } - free(entry); - } - rc_stringlist_free(list); - -#ifdef __linux__ - /* Only override rc.conf settings */ - if (strcmp(file, RC_CONF) == 0) { - config = rc_config_override(config); - } -#endif - - return config; -} -librc_hidden_def(rc_config_load) - -char * -rc_config_value(RC_STRINGLIST *list, const char *entry) -{ - RC_STRING *line; - char *p; - size_t len; - - len = strlen(entry); - TAILQ_FOREACH(line, list, entries) { - p = strchr(line->value, '='); - if (p != NULL) { - if (strncmp(entry, line->value, len) == 0 && line->value[len] == '=') - return ++p; - } - } - return NULL; -} -librc_hidden_def(rc_config_value) - -/* Global for caching the strings loaded from rc.conf to avoid reparsing for - * each rc_conf_value call */ -static RC_STRINGLIST *rc_conf = NULL; - -char * -rc_conf_value(const char *setting) -{ - RC_STRINGLIST *old; - RC_STRING *s; - char *p; - - if (! rc_conf) { - rc_conf = rc_config_load(RC_CONF); -#ifdef DEBUG_MEMORY - atexit(_free_rc_conf); -#endif - - /* Support old configs. */ - if (exists(RC_CONF_OLD)) { - old = rc_config_load(RC_CONF_OLD); - TAILQ_CONCAT(rc_conf, old, entries); -#ifdef DEBUG_MEMORY - free(old); -#endif - } - - /* Convert old uppercase to lowercase */ - TAILQ_FOREACH(s, rc_conf, entries) { - p = s->value; - while (p && *p && *p != '=') { - if (isupper((unsigned char)*p)) - *p = tolower((unsigned char)*p); - p++; - } - } - } - - return rc_config_value(rc_conf, setting); -} -librc_hidden_def(rc_conf_value) - -#ifdef DEBUG_MEMORY -static void -_free_rc_conf(void) -{ - rc_stringlist_free(rc_conf); -} -#endif diff --git a/src/librc/librc-stringlist.c b/src/librc/librc-stringlist.c deleted file mode 100644 index bf8d3f40..00000000 --- a/src/librc/librc-stringlist.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - librc-strlist.h - String list functions to make using queue(3) a little easier. -*/ - -/* - * 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. - */ - -#include "queue.h" -#include "librc.h" - -RC_STRINGLIST * -rc_stringlist_new(void) -{ - RC_STRINGLIST *l = xmalloc(sizeof(*l)); - TAILQ_INIT(l); - return l; -} -librc_hidden_def(rc_stringlist_new) - -RC_STRING * -rc_stringlist_add(RC_STRINGLIST *list, const char *value) -{ - RC_STRING *s = xmalloc(sizeof(*s)); - - s->value = xstrdup(value); - TAILQ_INSERT_TAIL(list, s, entries); - return s; -} -librc_hidden_def(rc_stringlist_add) - -RC_STRING * -rc_stringlist_addu(RC_STRINGLIST *list, const char *value) -{ - RC_STRING *s; - - TAILQ_FOREACH(s, list, entries) - if (strcmp(s->value, value) == 0) { - errno = EEXIST; - return NULL; - } - - return rc_stringlist_add(list, value); -} -librc_hidden_def(rc_stringlist_addu) - -bool -rc_stringlist_delete(RC_STRINGLIST *list, const char *value) -{ - RC_STRING *s; - - TAILQ_FOREACH(s, list, entries) - if (strcmp(s->value, value) == 0) { - TAILQ_REMOVE(list, s, entries); - free(s->value); - free(s); - return true; - } - - errno = EEXIST; - return false; -} -librc_hidden_def(rc_stringlist_delete) - -RC_STRING * -rc_stringlist_find(RC_STRINGLIST *list, const char *value) -{ - RC_STRING *s; - - if (list) { - TAILQ_FOREACH(s, list, entries) - if (strcmp(s->value, value) == 0) - return s; - } - return NULL; -} -librc_hidden_def(rc_stringlist_find) - -RC_STRINGLIST * -rc_stringlist_split(const char *value, const char *sep) -{ - RC_STRINGLIST *list = rc_stringlist_new(); - char *d = xstrdup(value); - char *p = d, *token; - - while ((token = strsep(&p, sep))) - rc_stringlist_add(list, token); - free(d); - - return list; -} -librc_hidden_def(rc_stringlist_split) - -void -rc_stringlist_sort(RC_STRINGLIST **list) -{ - RC_STRINGLIST *l = *list; - RC_STRINGLIST *new = rc_stringlist_new(); - RC_STRING *s; - RC_STRING *sn; - RC_STRING *n; - RC_STRING *last; - - TAILQ_FOREACH_SAFE(s, l, entries, sn) { - TAILQ_REMOVE(l, s, entries); - last = NULL; - TAILQ_FOREACH(n, new, entries) { - if (strcmp(s->value, n->value) < 0) - break; - last = n; - } - if (last) - TAILQ_INSERT_AFTER(new, last, s, entries); - else - TAILQ_INSERT_HEAD(new, s, entries); - } - - /* Now we've sorted the list, copy across the new head */ - free(l); - *list = new; -} -librc_hidden_def(rc_stringlist_sort) - -void -rc_stringlist_free(RC_STRINGLIST *list) -{ - RC_STRING *s1; - RC_STRING *s2; - - if (!list) - return; - - s1 = TAILQ_FIRST(list); - while (s1) { - s2 = TAILQ_NEXT(s1, entries); - free(s1->value); - free(s1); - s1 = s2; - } - free(list); -} -librc_hidden_def(rc_stringlist_free) 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) diff --git a/src/librc/librc.h b/src/librc/librc.h deleted file mode 100644 index 0824eba7..00000000 --- a/src/librc/librc.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * librc.h - * Internal header file to setup build env for files in librc.so - */ - -/* - * 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. - */ - -#ifndef _LIBRC_H_ -#define _LIBRC_H_ - -#define _IN_LIBRC - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/wait.h> - -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <libgen.h> -#include <limits.h> -#include <paths.h> -#include <regex.h> -#include <signal.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <time.h> -#include <unistd.h> - -#if defined(BSD) && !defined(__GNU__) -#include <sys/param.h> -#include <sys/user.h> -#include <sys/sysctl.h> -#include <kvm.h> -#else -#include <sys/param.h> -#endif - -#include "rc.h" -#include "rc-misc.h" - -#include "hidden-visibility.h" -#define librc_hidden_proto(x) hidden_proto(x) -#define librc_hidden_def(x) hidden_def(x) - -librc_hidden_proto(rc_conf_value) -librc_hidden_proto(rc_config_list) -librc_hidden_proto(rc_config_load) -librc_hidden_proto(rc_config_value) -librc_hidden_proto(rc_deptree_depend) -librc_hidden_proto(rc_deptree_depends) -librc_hidden_proto(rc_deptree_free) -librc_hidden_proto(rc_deptree_load) -librc_hidden_proto(rc_deptree_load_file) -librc_hidden_proto(rc_deptree_order) -librc_hidden_proto(rc_deptree_update) -librc_hidden_proto(rc_deptree_update_needed) -librc_hidden_proto(rc_find_pids) -librc_hidden_proto(rc_getfile) -librc_hidden_proto(rc_getline) -librc_hidden_proto(rc_newer_than) -librc_hidden_proto(rc_proc_getent) -librc_hidden_proto(rc_older_than) -librc_hidden_proto(rc_runlevel_exists) -librc_hidden_proto(rc_runlevel_get) -librc_hidden_proto(rc_runlevel_list) -librc_hidden_proto(rc_runlevel_set) -librc_hidden_proto(rc_runlevel_stack) -librc_hidden_proto(rc_runlevel_stacks) -librc_hidden_proto(rc_runlevel_starting) -librc_hidden_proto(rc_runlevel_stopping) -librc_hidden_proto(rc_runlevel_unstack) -librc_hidden_proto(rc_service_add) -librc_hidden_proto(rc_service_daemons_crashed) -librc_hidden_proto(rc_service_daemon_set) -librc_hidden_proto(rc_service_delete) -librc_hidden_proto(rc_service_description) -librc_hidden_proto(rc_service_exists) -librc_hidden_proto(rc_service_extra_commands) -librc_hidden_proto(rc_service_in_runlevel) -librc_hidden_proto(rc_service_mark) -librc_hidden_proto(rc_service_resolve) -librc_hidden_proto(rc_service_schedule_clear) -librc_hidden_proto(rc_service_schedule_start) -librc_hidden_proto(rc_services_in_runlevel) -librc_hidden_proto(rc_services_in_runlevel_stacked) -librc_hidden_proto(rc_services_in_state) -librc_hidden_proto(rc_services_scheduled) -librc_hidden_proto(rc_services_scheduled_by) -librc_hidden_proto(rc_service_started_daemon) -librc_hidden_proto(rc_service_state) -librc_hidden_proto(rc_service_value_get) -librc_hidden_proto(rc_service_value_set) -librc_hidden_proto(rc_stringlist_add) -librc_hidden_proto(rc_stringlist_addu) -librc_hidden_proto(rc_stringlist_delete) -librc_hidden_proto(rc_stringlist_find) -librc_hidden_proto(rc_stringlist_free) -librc_hidden_proto(rc_stringlist_new) -librc_hidden_proto(rc_stringlist_split) -librc_hidden_proto(rc_stringlist_sort) -librc_hidden_proto(rc_sys) -librc_hidden_proto(rc_sys_v1) -librc_hidden_proto(rc_sys_v2) -librc_hidden_proto(rc_yesno) - -#endif diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in deleted file mode 100644 index 58d8eb57..00000000 --- a/src/librc/rc.h.in +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Copyright (c) 2007-2009 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. - */ - -#ifndef __RC_H__ -#define __RC_H__ - -#include <sys/types.h> -#include <stdbool.h> -#include <stdio.h> - -/* __BEGIN_DECLS */ -#ifdef __cplusplus -extern "C" { -#endif - -#define RC_PREFIX "@PREFIX@" -#define RC_SYSCONFDIR "@SYSCONFDIR@" -#define RC_LIBDIR "@PREFIX@/@LIB@/rc" -#define RC_LIBEXECDIR "@LIBEXECDIR@" -#if defined(PREFIX) -#define RC_SVCDIR RC_LIBEXECDIR "/init.d" -#elif defined(__linux__) || (defined(__FreeBSD_kernel__) && \ - defined(__GLIBC__)) || defined(__GNU__) -#define RC_SVCDIR "/run/openrc" -#else -#define RC_SVCDIR RC_LIBEXECDIR "/init.d" -#endif -#define RC_RUNLEVELDIR RC_SYSCONFDIR "/runlevels" -#define RC_INITDIR RC_SYSCONFDIR "/init.d" -#define RC_CONFDIR RC_SYSCONFDIR "/conf.d" -#define RC_PLUGINDIR RC_LIBDIR "/plugins" - -#define RC_PROFILE_ENV RC_SYSCONFDIR "/profile.env" -#define RC_SYS_WHITELIST RC_LIBEXECDIR "/conf.d/env_whitelist" -#define RC_USR_WHITELIST RC_SYSCONFDIR "/conf.d/env_whitelist" -#define RC_CONF RC_SYSCONFDIR "/rc.conf" -#define RC_CONF_OLD RC_SYSCONFDIR "/conf.d/rc" - -#define RC_PATH_PREFIX RC_LIBEXECDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin" - -/* PKG_PREFIX is where packages are installed if different from the base OS - * On Gentoo this is normally unset, on FreeBSD /usr/local and on NetBSD - * /usr/pkg. */ -#define RC_PKG_PREFIX "@PKG_PREFIX@" -#ifdef RC_PKG_PREFIX -# define RC_PKG_INITDIR RC_PKG_PREFIX "/etc/init.d" -# define RC_PKG_CONFDIR RC_PKG_PREFIX "/etc/conf.d" -#endif - -/* LOCAL_PREFIX is for user written stuff, which the base OS and package - * manger don't touch. */ -#define RC_LOCAL_PREFIX "@LOCAL_PREFIX@" -#ifdef RC_LOCAL_PREFIX -# define RC_LOCAL_INITDIR RC_LOCAL_PREFIX "/etc/init.d" -# define RC_LOCAL_CONFDIR RC_LOCAL_PREFIX "/etc/conf.d" -#endif - -#ifndef _SYS_QUEUE_H_ - -/* - * The following are copied directly from our imported queue.h. - */ - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * Tail queue definitions. - */ -#define _TAILQ_HEAD(name, type, qual) \ -struct name { \ - qual type *tqh_first; /* first element */ \ - qual type *qual *tqh_last; /* addr of last next element */ \ -} -#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) - -#define TAILQ_HEAD_INITIALIZER(head) \ - { TAILQ_END(head), &(head).tqh_first } - -#define _TAILQ_ENTRY(type, qual) \ -struct { \ - qual type *tqe_next; /* next element */ \ - qual type *qual *tqe_prev; /* address of previous next element */\ -} -#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) - -#endif /* _SYS_QUEUE_H_ */ - -/* A doubly linked list using queue(3) for ease of use */ -typedef struct rc_string { - char *value; - TAILQ_ENTRY(rc_string) entries; -} RC_STRING; -typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST; - -/*! @name Reserved runlevel names */ -#define RC_LEVEL_SYSINIT "sysinit" -#define RC_LEVEL_SINGLE "single" -#define RC_LEVEL_SHUTDOWN "shutdown" - -/*! Return the current runlevel. - * @return the current runlevel */ -char *rc_runlevel_get(void); - -/*! Checks if the runlevel exists or not - * @param runlevel to check - * @return true if the runlevel exists, otherwise false */ -bool rc_runlevel_exists(const char *); - -/*! Stack a runlevel onto another - * @param runlevel to stack onto - * @param runlevel being stacked - * @return true if successful, otherwise false */ -bool rc_runlevel_stack(const char *, const char *); - -/*! Unstack a runlevel from another - * @param runlevel to unstack from - * @param runlevel being unstacked - * @return true if successful, otherwise false */ -bool rc_runlevel_unstack(const char *, const char *); - -/*! Return a NULL terminated list of runlevel stacks in the runlevels - * @return a NULL terminated list of runlevels */ -RC_STRINGLIST *rc_runlevel_stacks(const char *); - -/*! Return a NULL terminated list of runlevels - * @return a NULL terminated list of runlevels */ -RC_STRINGLIST *rc_runlevel_list(void); - -/*! Set the runlevel. - * This just changes the stored runlevel and does not start or stop any - * services. - * @param runlevel to store */ -bool rc_runlevel_set(const char *); - -/*! Is the runlevel starting? - * @return true if yes, otherwise false */ -bool rc_runlevel_starting(void); - -/*! Is the runlevel stopping? - * @return true if yes, otherwise false */ -bool rc_runlevel_stopping(void); - -/*! @name RC - * A service can be given as a full path or just its name. - * If it's just a name then we try to resolve the service to a full path. - * This should allow the use if local init.d directories in the future. */ - -/*! @brief States a service can be in */ -typedef enum -{ - /* These are actual states - * The service has to be in one only at all times */ - RC_SERVICE_STOPPED = 0x0001, - RC_SERVICE_STARTED = 0x0002, - RC_SERVICE_STOPPING = 0x0004, - RC_SERVICE_STARTING = 0x0008, - RC_SERVICE_INACTIVE = 0x0010, - - /* Service may or may not have been hotplugged */ - RC_SERVICE_HOTPLUGGED = 0x0100, - - /* Optional states service could also be in */ - RC_SERVICE_FAILED = 0x0200, - RC_SERVICE_SCHEDULED = 0x0400, - RC_SERVICE_WASINACTIVE = 0x0800 -} RC_SERVICE; - -/*! Add the service to the runlevel - * @param runlevel to add to - * @param service to add - * @return true if successful, otherwise false */ -bool rc_service_add(const char *, const char *); - -/*! Remove the service from the runlevel - * @param runlevel to remove from - * @param service to remove - * @return true if sucessful, otherwise false */ -bool rc_service_delete(const char *, const char *); - -/*! Save the arguments to find a running daemon - * @param service to save arguments for - * @param exec that we started - * @param name of the process (optional) - * @param pidfile of the process (optional) - * @param started if true, add the arguments otherwise remove existing matching arguments */ -bool rc_service_daemon_set(const char *, const char *, const char *const *, const char *, - bool); - -/*! Returns a description of what the service and/or option does. - * @param service to check - * @param option to check (if NULL, service description) - * @return a newly allocated pointer to the description */ -char *rc_service_description(const char *, const char *); - -/*! Checks if a service exists or not. - * @param service to check - * @return true if service exists, otherwise false */ -bool rc_service_exists(const char *); - -/*! Checks if a service is in a runlevel - * @param service to check - * @param runlevel it should be in - * @return true if service is in the runlevel, otherwise false */ -bool rc_service_in_runlevel(const char *, const char *); - -/*! Marks the service state - * @param service to mark - * @param state service should be in - * @return true if service state change was successful, otherwise false */ -bool rc_service_mark(const char *, RC_SERVICE); - -/*! Lists the extra commands a service has - * @param service to load the commands from - * @return NULL terminated string list of commands */ -RC_STRINGLIST *rc_service_extra_commands(const char *); - -/*! Resolves a service name to its full path. - * @param service to check - * @return pointer to full path of service */ -char *rc_service_resolve(const char *); - -/*! Schedule a service to be started when another service starts - * @param service that starts the scheduled service when started - * @param service_to_start service that will be started */ -bool rc_service_schedule_start(const char *, const char *); - -/*! Return a NULL terminated list of services that are scheduled to start - * when the given service has started - * @param service to check - * @return NULL terminated list of services scheduled to start */ -RC_STRINGLIST *rc_services_scheduled_by(const char *); - -/*! Clear the list of services scheduled to be started by this service - * @param service to clear - * @return true if no errors, otherwise false */ -bool rc_service_schedule_clear(const char *); - -/*! Checks if a service in in a state - * @param service to check - * @return state of the service */ -RC_SERVICE rc_service_state(const char *); - -/*! Check if the service started the daemon - * @param service to check - * @param exec to check - * @param argv to check - * @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc) - * @return true if started by this service, otherwise false */ -bool rc_service_started_daemon(const char *, const char *, - const char *const *, int); - -/*! Return a saved value for a service - * @param service to check - * @param option to load - * @return saved value */ -char *rc_service_value_get(const char *, const char *); - -/*! Save a persistent value for a service - * @param service to save for - * @param option to save - * @param value of the option - * @return true if saved, otherwise false */ -bool rc_service_value_set(const char *, const char *, const char *); - -/*! List the services in a runlevel - * @param runlevel to list - * @return NULL terminated list of services */ -RC_STRINGLIST *rc_services_in_runlevel(const char *); - -/*! List the stacked services in a runlevel - * @param runlevel to list - * @return NULL terminated list of services */ -RC_STRINGLIST *rc_services_in_runlevel_stacked(const char *); - -/*! List the services in a state - * @param state to list - * @return NULL terminated list of services */ -RC_STRINGLIST *rc_services_in_state(RC_SERVICE); - -/*! List the services shceduled to start when this one does - * @param service to check - * @return NULL terminated list of services */ -RC_STRINGLIST *rc_services_scheduled(const char *); - -/*! Checks that all daemons started with start-stop-daemon by the service - * are still running. - * @param service to check - * @return true if all daemons started are still running, otherwise false */ -bool rc_service_daemons_crashed(const char *); - -/*! @name System types - * OpenRC can support some special sub system types, normally virtualization. - * Some services cannot work in these systems, or we do something else. */ -#define RC_SYS_JAIL "JAIL" -#define RC_SYS_OPENVZ "OPENVZ" -#define RC_SYS_LXC "LXC" -#define RC_SYS_PREFIX "PREFIX" -#define RC_SYS_UML "UML" -#define RC_SYS_VSERVER "VSERVER" -#define RC_SYS_XEN0 "XEN0" -#define RC_SYS_XENU "XENU" - -/*! Returns the type of subsystem - * @return string from RC_SYS_* types or NULL if none detected */ -const char *rc_sys(void); - -/*! Returns the type of subsystem using old automatic code - * @return string from RC_SYS_* types or NULL if none detected */ -const char *rc_sys_v1(void); - -/*! Returns the type of subsystem using new rc.conf rc_sys value - * @return string from RC_SYS_* types or NULL if none detected */ -const char *rc_sys_v2(void); - -/*! @name Dependency options - * These options can change the services found by the rc_get_depinfo and - * rc_get_depends functions. */ -/*! Trace provided services */ -#define RC_DEP_TRACE (1<<0) -/*! Only use services added to runlevels */ -#define RC_DEP_STRICT (1<<1) -/*! Runlevel is starting */ -#define RC_DEP_START (1<<2) -/*! Runlevel is stopping */ -#define RC_DEP_STOP (1<<3) - -/*! @name Dependencies - * We analyse each init script and cache the resultant dependency tree. - * This tree can be accessed using the below functions. */ - -#ifdef _IN_LIBRC -/*! @name Dependency structures - * private to librc */ - -/*! Singly linked list of dependency types that list the services the - * type is for */ -typedef struct rc_deptype -{ - /*! ineed, iuse, iafter, etc */ - char *type; - /*! list of services */ - RC_STRINGLIST *services; - /*! list of types */ - TAILQ_ENTRY(rc_deptype) entries; -} RC_DEPTYPE; - -/*! Singly linked list of services and their dependencies */ -typedef struct rc_depinfo -{ - /*! Name of service */ - char *service; - /*! Dependencies */ - TAILQ_HEAD(, rc_deptype) depends; - /*! List of entries */ - TAILQ_ENTRY(rc_depinfo) entries; -} RC_DEPINFO; - -typedef TAILQ_HEAD(,rc_depinfo) RC_DEPTREE; -#else -/* Handles to internal structures */ -typedef void *RC_DEPTREE; -#endif - -/*! Check to see if source is newer than target. - * If target is a directory then we traverse it and its children. - * @param source - * @param target - * @param mtime of newest target - * @param filename of the newest target (needs mtime param) - * @return true if source is newer than target, otherwise false */ -bool rc_newer_than(const char *, const char *, time_t *, char *); - -/*! Check to see if source is older than target. - * If target is a directory then we traverse it and its children. - * @param source - * @param target - * @param mtime of oldest target - * @param filename of the oldest target (needs mtime param) - * @return true if source is older than target, otherwise false */ -bool rc_older_than(const char *, const char *, time_t *, char *); - -/*! Read variables/values from /proc/cmdline - * @param value - * @return pointer to the value, otherwise NULL */ -char *rc_proc_getent(const char *); - -/*! Update the cached dependency tree if it's older than any init script, - * its configuration file or an external configuration file the init script - * has specified. - * time_t returns the time of the newest file that the dependency tree - * will be checked against. - * @return true if successful, otherwise false */ -bool rc_deptree_update(void); - -/*! Check if the cached dependency tree is older than any init script, - * its configuration file or an external configuration file the init script - * has specified. - * @param mtime of newest file - * @param buffer of PATH_MAX to store newest file - * @return true if it needs updating, otherwise false */ -bool rc_deptree_update_needed(time_t *, char *); - -/*! Load the cached dependency tree and return a pointer to it. - * This pointer should be freed with rc_deptree_free when done. - * @return pointer to the dependency tree */ -RC_DEPTREE *rc_deptree_load(void); - -/*! Load a cached dependency tree from the specified file and return a pointer - * to it. This pointer should be freed with rc_deptree_free when done. - * @return pointer to the dependency tree */ -RC_DEPTREE *rc_deptree_load_file(const char *); - -/*! List the depend for the type of service - * @param deptree to search - * @param type to use (keywords, etc) - * @param service to check - * @return NULL terminated list of services in order */ -RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *, const char *, const char *); - -/*! List all the services in order that the given services have - * for the given types and options. - * @param deptree to search - * @param types to use (ineed, iuse, etc) - * @param services to check - * @param options to pass - * @return NULL terminated list of services in order */ -RC_STRINGLIST *rc_deptree_depends(const RC_DEPTREE *, const RC_STRINGLIST *, - const RC_STRINGLIST *, const char *, int); - -/*! List all the services that should be stoppned and then started, in order, - * for the given runlevel, including sysinit and boot services where - * approriate. - * @param deptree to search - * @param runlevel to change into - * @param options to pass - * @return NULL terminated list of services in order */ -RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *, const char *, int); - -/*! Free a deptree and its information - * @param deptree to free */ -void rc_deptree_free(RC_DEPTREE *); - -/*! @name Plugins - * For each plugin loaded we will call rc_plugin_hook with the below - * enum and either the runlevel name or service name. - * - * Plugins are called when rc does something. This does not indicate an - * end result and the plugin should use the above functions to query things - * like service status. - * - * The service hooks have extra ones - now and done. This is because after - * start_in we may start other services before we start the service in - * question. now shows we really will start the service now and done shows - * when we have done it as may start scheduled services at this point. */ -/*! Points at which a plugin can hook into RC */ -typedef enum -{ - RC_HOOK_RUNLEVEL_STOP_IN = 1, - RC_HOOK_RUNLEVEL_STOP_OUT = 4, - RC_HOOK_RUNLEVEL_START_IN = 5, - RC_HOOK_RUNLEVEL_START_OUT = 8, - /*! We send the abort if an init script requests we abort and drop - * into single user mode if system not fully booted */ - RC_HOOK_ABORT = 99, - RC_HOOK_SERVICE_STOP_IN = 101, - RC_HOOK_SERVICE_STOP_NOW = 102, - RC_HOOK_SERVICE_STOP_DONE = 103, - RC_HOOK_SERVICE_STOP_OUT = 104, - RC_HOOK_SERVICE_START_IN = 105, - RC_HOOK_SERVICE_START_NOW = 106, - RC_HOOK_SERVICE_START_DONE = 107, - RC_HOOK_SERVICE_START_OUT = 108 -} RC_HOOK; - -/*! Plugin entry point - * @param hook point - * @param name of runlevel or service - * @return 0 for success otherwise -1 */ -int rc_plugin_hook(RC_HOOK, const char *); - -/*! Plugins should write FOO=BAR to this fd to set any environment - * variables they wish. Variables should be separated by NULLs. */ -extern FILE *rc_environ_fd; - - -/*! Return a NULL terminated list of non comment lines from a file. */ -RC_STRINGLIST *rc_config_list(const char *); - -/*! Return a NULL terminated list of key=value lines from a file. */ -RC_STRINGLIST *rc_config_load(const char *); - -/*! Return the value of the entry from a key=value list. */ -char *rc_config_value(RC_STRINGLIST *, const char *); - -/*! Return the value of the entry from rc.conf. */ -char *rc_conf_value(const char *); - -/*! Check if a variable is a boolean and return its value. - * If variable is not a boolean then we set errno to be ENOENT when it does - * not exist or EINVAL if it's not a boolean. - * @param variable to check - * @return true if it matches true, yes or 1, false if otherwise. */ -bool rc_yesno(const char *); - -/*! @name String List functions - * Every string list should be released with a call to rc_stringlist_free. */ - -/*! Create a new stringlinst - * @return pointer to new list */ -RC_STRINGLIST *rc_stringlist_new(void); - -/*! Duplicate the item, add it to end of the list and return a pointer to it. - * @param list to add the item too - * @param item to add. - * @return pointer to newly added item */ -RC_STRING *rc_stringlist_add(RC_STRINGLIST *, const char *); - -/*! If the item does not exist in the list, duplicate it, add it to the - * list and then return a pointer to it. - * @param list to add the item too - * @param item to add. - * @return pointer to newly added item */ -RC_STRING *rc_stringlist_addu(RC_STRINGLIST *, const char *); - -/*! Free the item and remove it from the list. Return 0 on success otherwise -1. - * @param list to add the item too - * @param item to add. - * @return true on success, otherwise false */ -bool rc_stringlist_delete(RC_STRINGLIST *, const char *); - -/*! Find the item on the list. - * @param list to search - * @param item to find. - * @return pointer to item */ -RC_STRING *rc_stringlist_find(RC_STRINGLIST *, const char *); - -/*! Split a string into a stringlist based on separator. - * @param string to split - * @param separator - * @return new list */ -RC_STRINGLIST *rc_stringlist_split(const char *, const char *); - - -/*! Sort the list according to C locale - * @param list to sort */ -void rc_stringlist_sort(RC_STRINGLIST **); - -/*! Frees each item on the list and the list itself. - * @param list to free */ -void rc_stringlist_free(RC_STRINGLIST *); - -typedef struct rc_pid -{ - pid_t pid; - LIST_ENTRY(rc_pid) entries; -} RC_PID; -typedef LIST_HEAD(rc_pidlist, rc_pid) RC_PIDLIST; - -/*! Find processes based on criteria. - * All of these are optional. - * pid overrides anything else. - * If both exec and cmd are given then we ignore exec. - * @param exec to check for - * @param argv to check for - * @param uid to check for - * @param pid to check for - * @return NULL terminated list of pids */ -RC_PIDLIST *rc_find_pids(const char *, const char *const *, uid_t, pid_t); - -/* Basically the same as rc_getline() below, it just returns multiple lines */ -bool rc_getfile(const char *, char **, size_t *); - -/* getline is a handy glibc function that not all libcs have, so - * we have our own */ -ssize_t rc_getline(char **, size_t *, FILE *); - -/* __END_DECLS */ -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/librc/rc.map b/src/librc/rc.map deleted file mode 100644 index 2aa58dea..00000000 --- a/src/librc/rc.map +++ /dev/null @@ -1,68 +0,0 @@ -RC_1.0 { -global: - rc_conf_value; - rc_config_list; - rc_config_load; - rc_config_value; - rc_deptree_depend; - rc_deptree_depends; - rc_deptree_free; - rc_deptree_load; - rc_deptree_load_file; - rc_deptree_order; - rc_deptree_update; - rc_deptree_update_needed; - rc_environ_fd; - rc_find_pids; - rc_getfile; - rc_getline; - rc_newer_than; - rc_older_than; - rc_proc_getent; - rc_runlevel_exists; - rc_runlevel_get; - rc_runlevel_list; - rc_runlevel_set; - rc_runlevel_stack; - rc_runlevel_stacks; - rc_runlevel_starting; - rc_runlevel_stopping; - rc_runlevel_unstack; - rc_service_add; - rc_service_daemons_crashed; - rc_service_daemon_set; - rc_service_delete; - rc_service_description; - rc_service_exists; - rc_service_extra_commands; - rc_service_in_runlevel; - rc_service_mark; - rc_service_options; - rc_service_resolve; - rc_service_schedule_clear; - rc_service_schedule_start; - rc_services_in_runlevel; - rc_services_in_runlevel_stacked; - rc_services_in_state; - rc_services_scheduled; - rc_services_scheduled_by; - rc_service_started_daemon; - rc_service_state; - rc_service_value_get; - rc_service_value_set; - rc_stringlist_add; - rc_stringlist_addu; - rc_stringlist_delete; - rc_stringlist_find; - rc_stringlist_split; - rc_stringlist_new; - rc_stringlist_sort; - rc_stringlist_free; - rc_sys; - rc_sys_v1; - rc_sys_v2; - rc_yesno; - -local: - *; -}; |
