diff options
author | Roy Marples <roy@marples.name> | 2008-03-16 17:00:56 +0000 |
---|---|---|
committer | Roy Marples <roy@marples.name> | 2008-03-16 17:00:56 +0000 |
commit | cb9da6a262b60255cd037f20b4cde3ab2c8a1e6a (patch) | |
tree | c5c57d5adedf009fdb02b53677e2cdf940bdb47c /src/librc | |
parent | 40e12f6ba026af9c24d5c3d8e36512719ed5faee (diff) |
Remove null terminated char ** lists in favour of RC_STRINGLIST, using TAILQ from queue(3). Refactor code style around the BSD KNF.
Diffstat (limited to 'src/librc')
-rw-r--r-- | src/librc/.gitignore | 4 | ||||
-rw-r--r-- | src/librc/Makefile | 2 | ||||
-rw-r--r-- | src/librc/librc-daemon.c | 438 | ||||
-rw-r--r-- | src/librc/librc-depend.c | 1012 | ||||
-rw-r--r-- | src/librc/librc-depend.h | 61 | ||||
-rw-r--r-- | src/librc/librc-misc.c | 123 | ||||
-rw-r--r-- | src/librc/librc-strlist.c | 230 | ||||
-rw-r--r-- | src/librc/librc.c | 843 | ||||
-rw-r--r-- | src/librc/librc.h | 16 | ||||
-rw-r--r-- | src/librc/rc.h | 200 | ||||
-rw-r--r-- | src/librc/rc.map | 15 |
11 files changed, 1277 insertions, 1667 deletions
diff --git a/src/librc/.gitignore b/src/librc/.gitignore index 5f6e3ee2..eab6c70e 100644 --- a/src/librc/.gitignore +++ b/src/librc/.gitignore @@ -3,12 +3,12 @@ librc.o librc-daemon.o librc-depend.o librc-misc.o -librc-strlist.o +librc-stringlist.o librc.So librc-daemon.So librc-depend.So librc-misc.So -librc-strlist.So +librc-stringlist.So librc.a librc.so.1 librc.so diff --git a/src/librc/Makefile b/src/librc/Makefile index 78c97ce8..15c396b3 100644 --- a/src/librc/Makefile +++ b/src/librc/Makefile @@ -4,7 +4,7 @@ include ${MK}/os.mk LIB= rc SHLIB_MAJOR= 1 SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \ - librc-strlist.c + librc-stringlist.c INCS= rc.h VERSION_MAP= rc.map diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c index ca23ed27..9ae4ac26 100644 --- a/src/librc/librc-daemon.c +++ b/src/librc/librc-daemon.c @@ -32,33 +32,33 @@ #include "librc.h" #if defined(__linux__) -static bool pid_is_cmd (pid_t pid, const char *cmd) +static bool pid_is_cmd(pid_t pid, const char *cmd) { char buffer[32]; FILE *fp; int c; - snprintf(buffer, sizeof (buffer), "/proc/%d/stat", pid); - if ((fp = fopen (buffer, "r")) == NULL) - return (false); + snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid); + if ((fp = fopen(buffer, "r")) == NULL) + return false; - while ((c = getc (fp)) != EOF && c != '(') + while ((c = getc(fp)) != EOF && c != '(') ; if (c != '(') { fclose(fp); - return (false); + return false; } - while ((c = getc (fp)) != EOF && c == *cmd) + while ((c = getc(fp)) != EOF && c == *cmd) cmd++; - fclose (fp); + fclose(fp); - return ((c == ')' && *cmd == '\0') ? true : false); + return (c == ')' && *cmd == '\0') ? true : false; } -static bool pid_is_exec (pid_t pid, const char *const *argv) +static bool pid_is_exec(pid_t pid, const char *const *argv) { char cmdline[32]; char buffer[PATH_MAX]; @@ -66,31 +66,30 @@ static bool pid_is_exec (pid_t pid, const char *const *argv) int fd = -1; int r; + /* Check it's the right binary */ snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); memset (buffer, 0, sizeof (buffer)); -#if 0 - if (readlink (cmdline, buffer, sizeof (buffer)) != -1) { - if (strcmp (exec, buffer) == 0) - return (true); + if (readlink(cmdline, buffer, sizeof(buffer)) != -1) { + if (strcmp(*argv, buffer) == 0) + return true; /* We should cater for deleted binaries too */ - if (strlen (buffer) > 10) { - p = buffer + (strlen (buffer) - 10); - if (strcmp (p, " (deleted)") == 0) { + if (strlen(buffer) > 10) { + p = buffer + (strlen(buffer) - 10); + if (strcmp(p, " (deleted)") == 0) { *p = 0; - if (strcmp (buffer, exec) == 0) - return (true); + if (strcmp(buffer, *argv) == 0) + return true; } } } -#endif - snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid); - if ((fd = open (cmdline, O_RDONLY)) < 0) - return (false); + snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid); + if ((fd = open(cmdline, O_RDONLY)) < 0) + return false; - r = read (fd, buffer, sizeof (buffer)); - close (fd); + r = read(fd, buffer, sizeof(buffer)); + close(fd); if (r == -1) return 0; @@ -98,18 +97,18 @@ static bool pid_is_exec (pid_t pid, const char *const *argv) buffer[r] = 0; p = buffer; while (*argv) { - if (strcmp (*argv, p) != 0) - return (false); + if (strcmp(*argv, p) != 0) + return false; argv++; - p += strlen (p) + 1; + p += strlen(p) + 1; if ((unsigned) (p - buffer) > sizeof (buffer)) - return (false); + return false; } - return (true); + return true; } -pid_t *rc_find_pids (const char *const *argv, const char *cmd, - uid_t uid, pid_t pid) +pid_t *rc_find_pids(const char *const *argv, const char *cmd, + uid_t uid, pid_t pid) { DIR *procdir; struct dirent *entry; @@ -122,8 +121,8 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, pid_t runscript_pid = 0; char *pp; - if ((procdir = opendir ("/proc")) == NULL) - return (NULL); + if ((procdir = opendir("/proc")) == NULL) + return NULL; /* We never match RC_RUNSCRIPT_PID if present so we avoid the below @@ -136,13 +135,13 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, nasty */ - if ((pp = getenv ("RC_RUNSCRIPT_PID"))) { - if (sscanf (pp, "%d", &runscript_pid) != 1) + if ((pp = getenv("RC_RUNSCRIPT_PID"))) { + if (sscanf(pp, "%d", &runscript_pid) != 1) runscript_pid = 0; } - while ((entry = readdir (procdir)) != NULL) { - if (sscanf (entry->d_name, "%d", &p) != 1) + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &p) != 1) continue; if (runscript_pid != 0 && runscript_pid == p) @@ -152,23 +151,23 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, continue; if (uid) { - snprintf (buffer, sizeof (buffer), "/proc/%d", p); - if (stat (buffer, &sb) != 0 || sb.st_uid != uid) + snprintf(buffer, sizeof(buffer), "/proc/%d", p); + if (stat(buffer, &sb) != 0 || sb.st_uid != uid) continue; } - if (cmd && ! pid_is_cmd (p, cmd)) + if (cmd && ! pid_is_cmd(p, cmd)) continue; - if (argv && ! cmd && ! pid_is_exec (p, (const char *const *)argv)) + if (argv && ! cmd && ! pid_is_exec(p, (const char *const *)argv)) continue; - tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); + tmp = realloc(pids, sizeof (pid_t) * (npids + 2)); if (! tmp) { - free (pids); - closedir (procdir); + free(pids); + closedir(procdir); errno = ENOMEM; - return (NULL); + return NULL; } pids = tmp; @@ -176,9 +175,9 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, pids[npids + 1] = 0; npids++; } - closedir (procdir); + closedir(procdir); - return (pids); + return pids; } librc_hidden_def(rc_find_pids) @@ -206,8 +205,8 @@ librc_hidden_def(rc_find_pids) # define _KVM_FLAGS O_RDONLY # endif -pid_t *rc_find_pids (const char *const *argv, const char *cmd, - uid_t uid, pid_t pid) +pid_t *rc_find_pids(const char *const *argv, const char *cmd, + uid_t uid, pid_t pid) { static kvm_t *kd = NULL; char errbuf[_POSIX2_LINE_MAX]; @@ -218,44 +217,45 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, char **pargv; pid_t *pids = NULL; pid_t *tmp; + pid_t p; const char *const *arg; int npids = 0; int match; - if ((kd = kvm_openfiles (_KVM_PATH, _KVM_PATH, - NULL, _KVM_FLAGS, errbuf)) == NULL) + if ((kd = kvm_openfiles(_KVM_PATH, _KVM_PATH, + NULL, _KVM_FLAGS, errbuf)) == NULL) { - fprintf (stderr, "kvm_open: %s\n", errbuf); - return (NULL); + fprintf(stderr, "kvm_open: %s\n", errbuf); + return NULL; } #ifdef _KVM_GETPROC2 - kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes); + kp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes); #else - kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes); + 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); + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); + kvm_close(kd); + return NULL; } for (i = 0; i < processes; i++) { - pid_t p = _GET_KINFO_PID (kp[i]); + p = _GET_KINFO_PID(kp[i]); if (pid != 0 && pid != p) continue; - if (uid != 0 && uid != _GET_KINFO_UID (kp[i])) + if (uid != 0 && uid != _GET_KINFO_UID(kp[i])) continue; if (cmd) { - if (! _GET_KINFO_COMM (kp[i]) || - strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0) + if (! _GET_KINFO_COMM(kp[i]) || + strcmp(cmd, _GET_KINFO_COMM(kp[i])) != 0) continue; } if (argv && *argv && ! cmd) { - pargv = _KVM_GETARGV (kd, &kp[i], pargc); + pargv = _KVM_GETARGV(kd, &kp[i], pargc); if (! pargv || ! *pargv) continue; @@ -263,7 +263,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, match = 1; while (*arg && *pargv) - if (strcmp (*arg++, *pargv++) != 0) { + if (strcmp(*arg++, *pargv++) != 0) { match = 0; break; } @@ -272,12 +272,12 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, continue; } - tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); + tmp = realloc(pids, sizeof(pid_t) * (npids + 2)); if (! tmp) { - free (pids); - kvm_close (kd); + free(pids); + kvm_close(kd); errno = ENOMEM; - return (NULL); + return NULL; } pids = tmp; @@ -285,9 +285,9 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd, pids[npids + 1] = 0; npids++; } - kvm_close (kd); + kvm_close(kd); - return (pids); + return pids; } librc_hidden_def(rc_find_pids) @@ -295,67 +295,72 @@ librc_hidden_def(rc_find_pids) # error "Platform not supported!" #endif -static bool _match_daemon (const char *path, const char *file, char **match) +static bool _match_daemon(const char *path, const char *file, + RC_STRINGLIST *match) { char *line; - char *ffile = rc_strcatpaths (path, file, (char *) NULL); + char *ffile = rc_strcatpaths(path, file, (char *) NULL); FILE *fp; + RC_STRING *m; - fp = fopen (ffile, "r"); - free (ffile); + fp = fopen(ffile, "r"); + free(ffile); if (! fp) - return (false); + return false; - while ((line = rc_getline (fp))) { - rc_strlist_delete (&match, line); - if (! match || !*match) + while ((line = rc_getline(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); - if (match && *match) - return (false); - return (true); + fclose(fp); + if (TAILQ_FIRST(match)) + return false; + return true; } -static char **_match_list (const char* const* argv, - const char *name, const char *pidfile) +static RC_STRINGLIST *_match_list(const char* const* argv, + const char *name, const char *pidfile) { - char **match = NULL; + RC_STRINGLIST *match = rc_stringlist_new(); int i = 0; size_t l; char *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_strlist_add (&match, m); - free (m); + 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 (name) { - l = strlen (name) + 6; - m = xmalloc (sizeof (char) * l); - snprintf (m, l, "name=%s", name); - rc_strlist_add (&match, m); - free (m); + l = strlen(name) + 6; + m = xmalloc(sizeof (char) * l); + snprintf(m, l, "name=%s", name); + 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_strlist_add (&match, m); + l = strlen(pidfile) + 9; + m = xmalloc(sizeof (char) * l); + snprintf(m, l, "pidfile=%s", pidfile); + rc_stringlist_add(match, m); free (m); } - return (match); + return match; } -bool rc_service_daemon_set (const char *service, const char *const *argv, - const char *name, const char *pidfile, - bool started) +bool rc_service_daemon_set(const char *service, const char *const *argv, + const char *name, const char *pidfile, bool started) { char *dirpath; char *file = NULL; @@ -364,123 +369,123 @@ bool rc_service_daemon_set (const char *service, const char *const *argv, bool retval = false; DIR *dp; struct dirent *d; - char **match = NULL; + RC_STRINGLIST *match; int i = 0; + char buffer[10]; + FILE *fp; - if (! (argv && *argv) && ! name && ! pidfile) { + if (!(argv && *argv) && ! name && ! pidfile) { errno = EINVAL; - return (false); + return false; } - dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", - basename_c (service), (char *) NULL); + dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", + basename_c(service), (char *) NULL); - match = _match_list (argv, name, pidfile); + match = _match_list(argv, name, pidfile); /* Regardless, erase any existing daemon info */ - if ((dp = opendir (dirpath))) { - while ((d = readdir (dp))) { + if ((dp = opendir(dirpath))) { + while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - file = rc_strcatpaths (dirpath, d->d_name, (char *) NULL); + file = rc_strcatpaths(dirpath, d->d_name, (char *) NULL); nfiles++; if (! oldfile) { - if (_match_daemon (dirpath, d->d_name, match)) { + if (_match_daemon(dirpath, d->d_name, match)) { unlink (file); oldfile = file; nfiles--; } } else { - rename (file, oldfile); - free (oldfile); + rename(file, oldfile); + free(oldfile); oldfile = file; } } - free (file); - closedir (dp); + free(file); + closedir(dp); } /* Now store our daemon info */ if (started) { - char buffer[10]; - FILE *fp; - - if (mkdir (dirpath, 0755) == 0 || errno == EEXIST) { - snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1); - file = rc_strcatpaths (dirpath, buffer, (char *) NULL); - if ((fp = fopen (file, "w"))) { + if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) { + snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1); + file = rc_strcatpaths(dirpath, buffer, (char *) NULL); + if ((fp = fopen(file, "w"))) { while (argv && argv[i]) { - fprintf (fp, "argv_%d=%s\n", i, argv[i]); + fprintf(fp, "argv_%d=%s\n", i, argv[i]); i++; } - fprintf (fp, "name="); + fprintf(fp, "name="); if (name) - fprintf (fp, "%s", name); - fprintf (fp, "\npidfile="); + fprintf(fp, "%s", name); + fprintf(fp, "\npidfile="); if (pidfile) - fprintf (fp, "%s", pidfile); - fprintf (fp, "\n"); - fclose (fp); + fprintf(fp, "%s", pidfile); + fprintf(fp, "\n"); + fclose(fp); retval = true; } - free (file); + free(file); } } else retval = true; - rc_strlist_free (match); - free (dirpath); + rc_stringlist_free(match); + free(dirpath); - return (retval); + return retval; } librc_hidden_def(rc_service_daemon_set) -bool rc_service_started_daemon (const char *service, const char *const *argv, - int indx) +bool +rc_service_started_daemon (const char *service, const char *const *argv, + int indx) { char *dirpath; char *file; size_t l; - char **match; + RC_STRINGLIST *match; bool retval = false; DIR *dp; struct dirent *d; - if (! service || ! (argv && *argv)) - return (false); + if (!service || !(argv && *argv)) + return false; - dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename_c (service), - (char *) NULL); + dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service), + (char *) NULL); - match = _match_list (argv, NULL, NULL); + match = _match_list(argv, NULL, NULL); if (indx > 0) { l = sizeof (char) * 10; - file = xmalloc (l); - snprintf (file, l, "%03d", indx); - retval = _match_daemon (dirpath, file, match); - free (file); + file = xmalloc(l); + snprintf(file, l, "%03d", indx); + retval = _match_daemon(dirpath, file, match); + free(file); } else { - if ((dp = opendir (dirpath))) { - while ((d = readdir (dp))) { + if ((dp = opendir(dirpath))) { + while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - retval = _match_daemon (dirpath, d->d_name, match); + retval = _match_daemon(dirpath, d->d_name, match); if (retval) break; } - closedir (dp); + closedir(dp); } } - free (dirpath); - rc_strlist_free (match); - return (retval); + free(dirpath); + rc_stringlist_free(match); + return retval; } librc_hidden_def(rc_service_started_daemon) -bool rc_service_daemons_crashed (const char *service) +bool rc_service_daemons_crashed(const char *service) { char *dirpath; DIR *dp; @@ -497,116 +502,123 @@ bool rc_service_daemons_crashed (const char *service) char *p; char *token; bool retval = false; + RC_STRINGLIST *list; + RC_STRING *s; + size_t i; - if (! service) - return (false); + dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service), + (char *) NULL); - dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename_c (service), - (char *) NULL); - - if (! (dp = opendir (dirpath))) { - free (dirpath); - return (false); + if (! (dp = opendir(dirpath))) { + free(dirpath); + return false; } - while ((d = readdir (dp))) { + while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - path = rc_strcatpaths (dirpath, d->d_name, (char *) NULL); - fp = fopen (path, "r"); - free (path); + path = rc_strcatpaths(dirpath, d->d_name, (char *) NULL); + fp = fopen(path, "r"); + free(path); if (! fp) break; - while ((line = rc_getline (fp))) { + list = rc_stringlist_new(); + + while ((line = rc_getline(fp))) { p = line; - if ((token = strsep (&p, "=")) == NULL || ! p) { - free (line); + if ((token = strsep(&p, "=")) == NULL || ! p) { + free(line); continue; } - if (strlen (p) == 0) { - free (line); + if (! *p) { + free(line); continue; } - if (strncmp (token, "argv_", 5) == 0) { - rc_strlist_add (&argv, p); - } else if (strcmp (token, "exec") == 0) { + if (strncmp(token, "argv_", 5) == 0) { + rc_stringlist_add(list, p); + } else if (strcmp(token, "exec") == 0) { if (exec) - free (exec); - exec = xstrdup (p); - } else if (strcmp (token, "name") == 0) { + free(exec); + exec = xstrdup(p); + } else if (strcmp(token, "name") == 0) { if (name) - free (name); - name = xstrdup (p); - } else if (strcmp (token, "pidfile") == 0) { + free(name); + name = xstrdup(p); + } else if (strcmp(token, "pidfile") == 0) { if (pidfile) - free (pidfile); - pidfile = xstrdup (p); + free(pidfile); + pidfile = xstrdup(p); } - free (line); + free(line); } - fclose (fp); + fclose(fp); pid = 0; if (pidfile) { - if (! exists (pidfile)) { + if (! exists(pidfile)) { retval = true; break; } - if ((fp = fopen (pidfile, "r")) == NULL) { + if ((fp = fopen(pidfile, "r")) == NULL) { retval = true; break; } - if (fscanf (fp, "%d", &pid) != 1) { + if (fscanf(fp, "%d", &pid) != 1) { fclose (fp); retval = true; break; } - fclose (fp); - free (pidfile); + fclose(fp); + free(pidfile); pidfile = NULL; /* We have the pid, so no need to match on name */ - rc_strlist_free (argv); - argv = NULL; + rc_stringlist_free(list); + list = NULL; free (exec); exec = NULL; free (name); name = NULL; - } - - if (exec && ! argv) { - rc_strlist_add (&argv, exec); - free (exec); + } else { + if (exec && ! TAILQ_FIRST(list)) { + rc_stringlist_add(list, exec); + } + free(exec); exec = NULL; - } - if ((pids = rc_find_pids ((const char *const *)argv, name, 0, pid)) == NULL) { - retval = true; - break; + /* 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'; } - free (pids); - rc_strlist_free (argv); + if ((pids = rc_find_pids((const char *const *)argv, name, 0, pid)) == NULL) + retval = true; + free(pids); + free(argv); argv = NULL; - free (exec); - exec = NULL; - free (name); + rc_stringlist_free(list); + free(name); name = NULL; + if (retval) + break; } - rc_strlist_free (argv); - free (exec); - free (name); - free (dirpath); - closedir (dp); + free(dirpath); + closedir(dp); - return (retval); + return retval; } librc_hidden_def(rc_service_daemons_crashed) diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 22470368..8617d753 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -37,31 +37,18 @@ static const char *bootlevel = NULL; -/* We use this so we can pass our char array through many functions */ -struct lhead -{ - char **list; -}; - -static void *xzalloc (size_t size) -{ - void *value = xmalloc (size); - memset (value, 0, size); - return (value); -} - -static char *get_shell_value (char *string) +static char *get_shell_value(char *string) { char *p = string; char *e; if (! string) - return (NULL); + return NULL; if (*p == '\'') p++; - e = p + strlen (p) - 1; + e = p + strlen(p) - 1; if (*e == '\n') *e-- = 0; if (*e == '\'') @@ -70,191 +57,184 @@ static char *get_shell_value (char *string) if (*p != 0) return p; - return (NULL); + return NULL; } -void rc_deptree_free (rc_depinfo_t *deptree) +void rc_deptree_free(RC_DEPTREE *deptree) { - rc_depinfo_t *di = deptree; + RC_DEPINFO *di; + RC_DEPINFO *di2; + RC_DEPTYPE *dt; + RC_DEPTYPE *dt2; + + if (! deptree) + return; + + di = STAILQ_FIRST(deptree); while (di) { - rc_depinfo_t *dip = di->next; - rc_deptype_t *dt = di->depends; - free (di->service); + di2 = STAILQ_NEXT(di, entries); + dt = STAILQ_FIRST(&di->depends); while (dt) { - rc_deptype_t *dtp = dt->next; - free (dt->type); - rc_strlist_free (dt->services); - free (dt); - dt = dtp; + dt2 = STAILQ_NEXT(dt, entries); + rc_stringlist_free(dt->services); + free(dt->type); + free(dt); + dt = dt2; } - free (di); - di = dip; + free(di->service); + free(di); + di = di2; } + free(deptree); } librc_hidden_def(rc_deptree_free) -static rc_depinfo_t *get_depinfo (const rc_depinfo_t *deptree, - const char *service) +static RC_DEPINFO *get_depinfo(const RC_DEPTREE *deptree, + const char *service) { - const rc_depinfo_t *di; - - if (! deptree || ! service) - return (NULL); + RC_DEPINFO *di; - for (di = deptree; di; di = di->next) - if (strcmp (di->service, service) == 0) - return ((rc_depinfo_t *)di); + STAILQ_FOREACH(di, deptree, entries) + if (strcmp(di->service, service) == 0) + return di; - return (NULL); + return NULL; } -static rc_deptype_t *get_deptype (const rc_depinfo_t *depinfo, - const char *type) +static RC_DEPTYPE *get_deptype(const RC_DEPINFO *depinfo, + const char *type) { - rc_deptype_t *dt; + RC_DEPTYPE *dt; - if (! depinfo || !type) - return (NULL); + STAILQ_FOREACH(dt, &depinfo->depends, entries) + if (strcmp(dt->type, type) == 0) + return dt; - for (dt = depinfo->depends; dt; dt = dt->next) - if (strcmp (dt->type, type) == 0) - return (dt); - - return (NULL); + return NULL; } -rc_depinfo_t *rc_deptree_load (void) +RC_DEPTREE *rc_deptree_load(void) { FILE *fp; - rc_depinfo_t *deptree = NULL; - rc_depinfo_t *depinfo = NULL; - rc_deptype_t *deptype = NULL; + RC_DEPTREE *deptree; + RC_DEPINFO *depinfo = NULL; + RC_DEPTYPE *deptype = NULL; char *line; char *type; char *p; char *e; int i; - if (! (fp = fopen (RC_DEPTREE, "r"))) - return (NULL); + if (!(fp = fopen(RC_DEPTREE_CACHE, "r"))) + return NULL; + + deptree = xmalloc(sizeof(*deptree)); + STAILQ_INIT(deptree); - while ((line = rc_getline (fp))) + while ((line = rc_getline(fp))) { p = line; - e = strsep (&p, "_"); - if (! e || strcmp (e, "depinfo") != 0) + e = strsep(&p, "_"); + if (! e || strcmp(e, "depinfo") != 0) goto next; e = strsep (&p, "_"); - if (! e || sscanf (e, "%d", &i) != 1) + if (! e || sscanf(e, "%d", &i) != 1) goto next; - if (! (type = strsep (&p, "_="))) + if (! (type = strsep(&p, "_="))) goto next; - if (strcmp (type, "service") == 0) + if (strcmp(type, "service") == 0) { /* Sanity */ - e = get_shell_value (p); + e = get_shell_value(p); if (! e || *e == '\0') goto next; - if (! deptree) - { - deptree = xzalloc (sizeof (*deptree)); - depinfo = deptree; - } - else - { - depinfo->next = xzalloc (sizeof (*depinfo->next)); - depinfo = depinfo->next; - } - depinfo->service = xstrdup (e); + depinfo = xmalloc(sizeof(*depinfo)); + STAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(e); + STAILQ_INSERT_TAIL(deptree, depinfo, entries); deptype = NULL; goto next; } - e = strsep (&p, "="); - if (! e || sscanf (e, "%d", &i) != 1) + e = strsep(&p, "="); + if (! e || sscanf(e, "%d", &i) != 1) goto next; /* Sanity */ - e = get_shell_value (p); + e = get_shell_value(p); if (! e || *e == '\0') goto next; - if (! deptype) - { - depinfo->depends = xzalloc (sizeof (*depinfo->depends)); - deptype = depinfo->depends; - } - else - if (strcmp (deptype->type, type) != 0) - { - deptype->next = xzalloc (sizeof (*deptype->next)); - deptype = deptype->next; - } - - if (! deptype->type) + if (! deptype || strcmp(deptype->type, type) != 0) { + deptype = xmalloc(sizeof(*deptype)); + deptype->services = rc_stringlist_new(); deptype->type = xstrdup (type); + STAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); + } - rc_strlist_addsort (&deptype->services, e); - + rc_stringlist_add(deptype->services, e); next: - free (line); + free(line); } - fclose (fp); - - return (deptree); + fclose(fp); + + return deptree; } librc_hidden_def(rc_deptree_load) -static bool valid_service (const char *runlevel, const char *service) +static bool valid_service(const char *runlevel, const char *service) { - rc_service_state_t state = rc_service_state (service); + RC_SERVICE state = rc_service_state(service); return ((strcmp (runlevel, bootlevel) != 0 && - rc_service_in_runlevel (service, bootlevel)) || - rc_service_in_runlevel (service, runlevel) || + rc_service_in_runlevel(service, bootlevel)) || + rc_service_in_runlevel(service, runlevel) || state & RC_SERVICE_COLDPLUGGED || state & RC_SERVICE_STARTED); } -static bool get_provided1 (const char *runlevel, struct lhead *providers, - rc_deptype_t *deptype, - const char *level, bool coldplugged, - rc_service_state_t state) +static bool get_provided1(const char *runlevel, RC_STRINGLIST *providers, + RC_DEPTYPE *deptype, + const char *level, bool coldplugged, + RC_SERVICE state) { - char *service; - int i; + 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); - STRLIST_FOREACH (deptype->services, service, i) - { - bool ok = true; - rc_service_state_t s = rc_service_state (service); if (level) - ok = rc_service_in_runlevel (service, level); + ok = rc_service_in_runlevel(svc, level); else if (coldplugged) - ok = (s & RC_SERVICE_COLDPLUGGED && - ! rc_service_in_runlevel (service, runlevel) && - ! rc_service_in_runlevel (service, bootlevel)); + ok = (st & RC_SERVICE_COLDPLUGGED && + ! rc_service_in_runlevel(svc, runlevel) && + ! rc_service_in_runlevel(svc, bootlevel)); if (! ok) continue; switch (state) { case RC_SERVICE_STARTED: - ok = (s & RC_SERVICE_STARTED); + ok = (st & RC_SERVICE_STARTED); break; case RC_SERVICE_INACTIVE: case RC_SERVICE_STARTING: case RC_SERVICE_STOPPING: - ok = (s & RC_SERVICE_STARTING || - s & RC_SERVICE_STOPPING || - s & RC_SERVICE_INACTIVE); + ok = (st & RC_SERVICE_STARTING || + st & RC_SERVICE_STOPPING || + st & RC_SERVICE_INACTIVE); break; default: break; @@ -264,10 +244,10 @@ static bool get_provided1 (const char *runlevel, struct lhead *providers, continue; retval = true; - rc_strlist_add (&providers->list, service); + rc_stringlist_add(providers, svc); } - return (retval); + return retval; } /* Work out if a service is provided by another service. @@ -279,50 +259,41 @@ static bool get_provided1 (const char *runlevel, struct lhead *providers, If there are any bugs in rc-depend, they will probably be here as provided dependancy can change depending on runlevel state. */ -static char **get_provided (const rc_depinfo_t *deptree, - const rc_depinfo_t *depinfo, - const char *runlevel, int options) +static RC_STRINGLIST *get_provided (const RC_DEPINFO *depinfo, + const char *runlevel, int options) { - rc_deptype_t *dt; - struct lhead providers; - char *service; - int i; + RC_DEPTYPE *dt; + RC_STRINGLIST *providers = rc_stringlist_new(); + RC_STRING *service; - if (! deptree || ! depinfo) - return (NULL); - - if (rc_service_exists (depinfo->service)) - return (NULL); - - dt = get_deptype (depinfo, "providedby"); + dt = get_deptype(depinfo, "providedby"); if (! dt) - return (NULL); + return providers; - memset (&providers, 0, sizeof (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) { - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_add (&providers.list, service); - - return (providers.list); + TAILQ_FOREACH(service, dt->services, entries) + rc_stringlist_add(providers, service->value); + return providers; } /* If we're strict or startng, then only use what we have in our * runlevel and bootlevel. If we starting then check cold-plugged too. */ if (options & RC_DEP_STRICT || options & RC_DEP_START) { - STRLIST_FOREACH (dt->services, service, i) - if (rc_service_in_runlevel (service, runlevel) || - rc_service_in_runlevel (service, bootlevel) || + + 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) & RC_SERVICE_COLDPLUGGED)) - rc_strlist_add (&providers.list, service); + rc_service_state(service->value) & RC_SERVICE_COLDPLUGGED)) + rc_stringlist_add(providers, service->value); - if (providers.list) - return (providers.list); + if (TAILQ_FIRST(providers)) + return providers; } /* OK, we're not strict or there were no services in our runlevel. @@ -333,225 +304,211 @@ static char **get_provided (const rc_depinfo_t *deptree, We apply this to our runlevel, coldplugged services, then bootlevel and finally any running.*/ #define DO \ - if (providers.list && providers.list[0] && providers.list[1]) \ - { \ - rc_strlist_free (providers.list); \ - return (NULL); \ - } \ - else if (providers.list) \ - return providers.list; \ + if (TAILQ_FIRST(providers)) { \ + if (TAILQ_NEXT(TAILQ_FIRST(providers), entries)) { \ + rc_stringlist_free(providers); \ + providers = rc_stringlist_new(); \ + } \ + return providers; \ + } /* Anything in the runlevel has to come first */ - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTING)) - return (providers.list); - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTING)) + return providers; + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) + return providers; /* Check coldplugged services */ - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTING)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTING)) + return providers; /* Check bootlevel if we're not in it */ if (bootlevel && strcmp (runlevel, bootlevel) != 0) { - if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTING)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTING)) + return providers; } /* Check coldplugged services */ - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STOPPED)) + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STOPPED)) { DO } /* Check manually started */ - if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, NULL, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTING)) - return (providers.list); + 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.list); + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) + return providers; if (bootlevel && (strcmp (runlevel, bootlevel) != 0) - && (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STOPPED))) - return (providers.list); + && (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STOPPED))) + return providers; /* Still nothing? OK, list all services */ - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_add (&providers.list, service); + TAILQ_FOREACH(service, dt->services, entries) + rc_stringlist_add(providers, service->value); - return (providers.list); + return providers; } -static void visit_service (const rc_depinfo_t *deptree, - const char * const *types, - struct lhead *sorted, struct lhead *visited, - const rc_depinfo_t *depinfo, +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) { - int i, j, k; - char *lp; - const char *item; - char *service; - rc_depinfo_t *di; - rc_deptype_t *dt; - char **provides; - char *svcname; - - if (! deptree || !sorted || !visited || !depinfo) - return; + 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 */ - STRLIST_FOREACH (visited->list, item, i) - if (strcmp (item, depinfo->service) == 0) + TAILQ_FOREACH(type, visited, entries) + if (strcmp(type->value, depinfo->service) == 0) return; /* Add ourselves as a visited service */ - rc_strlist_add (&visited->list, depinfo->service); + rc_stringlist_add(visited, depinfo->service); - STRLIST_FOREACH (types, item, i) + TAILQ_FOREACH(type, types, entries) { - if ((dt = get_deptype (depinfo, item))) - { - STRLIST_FOREACH (dt->services, service, j) + if (!(dt = get_deptype(depinfo, type->value))) + continue; + + TAILQ_FOREACH(service, dt->services, entries) { + if (! options & RC_DEP_TRACE || + strcmp(type->value, "iprovide") == 0) { - if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0) - { - rc_strlist_add (&sorted->list, service); - continue; - } + rc_stringlist_add(sorted, service->value); + continue; + } - di = get_depinfo (deptree, service); - if ((provides = get_provided (deptree, di, runlevel, options))) - { - STRLIST_FOREACH (provides, lp, k) - { - di = get_depinfo (deptree, lp); - if (di && (strcmp (item, "ineed") == 0 || - strcmp (item, "needsme") == 0 || - valid_service (runlevel, di->service))) - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - } - rc_strlist_free (provides); + 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 && + (strcmp(type->value, "ineed") == 0 || + strcmp(type->value, "needsme") == 0 || + valid_service(runlevel, di->service))) + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); } - else - if (di && (strcmp (item, "ineed") == 0 || - strcmp (item, "needsme") == 0 || - valid_service (runlevel, service))) - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); } + else if (di && + (strcmp(type->value, "ineed") == 0 || + strcmp(type->value, "needsme") == 0 || + valid_service(runlevel, service->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"))) + (dt = get_deptype(depinfo, "iprovide"))) { - STRLIST_FOREACH (dt->services, service, i) - { - if ((di = get_depinfo (deptree, service))) - if ((provides = get_provided (deptree, di, runlevel, options))) - { - STRLIST_FOREACH (provides, lp, j) - if (strcmp (lp, depinfo->service) == 0) - { - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - break; - } - rc_strlist_free (provides); + 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("SVCNAME"); - if (! svcname || strcmp (svcname, depinfo->service) != 0) - if (! get_deptype (depinfo, "providedby")) - rc_strlist_add (&sorted->list, depinfo->service); + if (! svcname || strcmp(svcname, depinfo->service) != 0) + if (! get_deptype(depinfo, "providedby")) + rc_stringlist_add(sorted, depinfo->service); } -char **rc_deptree_depend (const rc_depinfo_t *deptree, - const char *service, const char *type) +RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree, + const char *service, const char *type) { - rc_depinfo_t *di; - rc_deptype_t *dt; - char **svcs = NULL; - int i; - char *svc; + RC_DEPINFO *di; + RC_DEPTYPE *dt; + RC_STRINGLIST *svcs; + RC_STRING *svc; - if (! (di = get_depinfo (deptree, service)) || - ! (dt = get_deptype (di, type))) + if (!(di = get_depinfo(deptree, service)) || + ! (dt = get_deptype(di, type))) { errno = ENOENT; - return (NULL); + return NULL; } /* For consistency, we copy the array */ - STRLIST_FOREACH (dt->services, svc, i) - rc_strlist_add (&svcs, svc); + svcs = rc_stringlist_new(); + TAILQ_FOREACH(svc, dt->services, entries) + rc_stringlist_add(svcs, svc->value); - return (svcs); + return svcs; } librc_hidden_def(rc_deptree_depend) -char **rc_deptree_depends (const rc_depinfo_t *deptree, - const char *const *types, - const char *const *services, - const char *runlevel, int options) +RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree, + const RC_STRINGLIST *types, + const RC_STRINGLIST *services, + const char *runlevel, int options) { - struct lhead sorted; - struct lhead visited; - rc_depinfo_t *di; - const char *service; - int i; - - if (! deptree || ! services) - return (NULL); - - memset (&sorted, 0, sizeof (sorted)); - memset (&visited, 0, sizeof (visited)); + 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; - STRLIST_FOREACH (services, service, i) - { - if (! (di = get_depinfo (deptree, service))) { + TAILQ_FOREACH(service, services, entries) { + if (! (di = get_depinfo(deptree, service->value))) { errno = ENOENT; continue; } if (types) - visit_service (deptree, types, &sorted, &visited, + visit_service (deptree, types, sorted, visited, di, runlevel, options); } - rc_strlist_free (visited.list); - return (sorted.list); + rc_stringlist_free (visited); + return sorted; } librc_hidden_def(rc_deptree_depends) - static const char * const order_types[] = { "ineed", "iuse", "iafter", NULL }; -char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, - int options) +RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *deptree, + const char *runlevel, int options) { - char **list = NULL; - char **services = NULL; - bool reverse = false; - char **tmp = NULL; - - if (! runlevel) - return (NULL); + RC_STRINGLIST *list; + RC_STRINGLIST *list2; + RC_STRINGLIST *types; + RC_STRINGLIST *services; bootlevel = getenv ("RC_BOOTLEVEL"); if (! bootlevel) @@ -562,47 +519,48 @@ char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || strcmp (runlevel, RC_LEVEL_REBOOT) == 0) { - list = rc_services_in_state (RC_SERVICE_STARTED); + list = rc_services_in_state(RC_SERVICE_STARTED); - tmp = rc_services_in_state (RC_SERVICE_INACTIVE); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_state (RC_SERVICE_INACTIVE); + TAILQ_CONCAT(list, list2); + free(list2); - tmp = rc_services_in_state (RC_SERVICE_STARTING); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); - reverse = true; + list2 = rc_services_in_state (RC_SERVICE_STARTING); + TAILQ_CONCAT(list, list2); + free(list2); } else { list = rc_services_in_runlevel (runlevel); /* Add coldplugged services */ - tmp = rc_services_in_state (RC_SERVICE_COLDPLUGGED); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_state (RC_SERVICE_COLDPLUGGED); + TAILQ_CONCAT(list, list2); + free(list2); /* If we're not the boot runlevel then add that too */ if (strcmp (runlevel, bootlevel) != 0) { - tmp = rc_services_in_runlevel (bootlevel); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_runlevel (bootlevel); + TAILQ_CONCAT(list, list2); + free(list2); } } /* Now we have our lists, we need to pull in any dependencies and order them */ - services = rc_deptree_depends (deptree, order_types, (const char **) list, - runlevel, - RC_DEP_STRICT | RC_DEP_TRACE | options); - rc_strlist_free (list); + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iafter"); - if (reverse) - rc_strlist_reverse (services); + 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); + return services; } librc_hidden_def(rc_deptree_order) -bool rc_newer_than (const char *source, const char *target) +bool rc_newer_than(const char *source, const char *target) { struct stat buf; time_t mtime; @@ -613,38 +571,38 @@ bool rc_newer_than (const char *source, const char *target) int serrno = errno; /* We have to exist */ - if (stat (source, &buf) != 0) - return (false); + if (stat(source, &buf) != 0) + return false; mtime = buf.st_mtime; /* Of course we are newer than targets that don't exist such as broken symlinks */ - if (stat (target, &buf) != 0) - return (true); + if (stat(target, &buf) != 0) + return true; if (mtime < buf.st_mtime) - return (false); + return false; /* If not a dir then reset errno */ - if (! (dp = opendir (target))) { + if (! (dp = opendir(target))) { errno = serrno; - return (true); + return true; } /* Check if we're newer than all the entries in the dir */ - while ((d = readdir (dp))) { + while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - path = rc_strcatpaths (target, d->d_name, (char *) NULL); - newer = rc_newer_than (source, path); - free (path); + path = rc_strcatpaths(target, d->d_name, (char *) NULL); + newer = rc_newer_than(source, path); + free(path); if (! newer) break; } - closedir (dp); + closedir(dp); - return (newer); + return newer; } librc_hidden_def(rc_newer_than) @@ -652,12 +610,12 @@ typedef struct deppair { const char *depend; const char *addto; -} deppair_t; +} DEPPAIR; -static const deppair_t deppairs[] = { - { "ineed", "needsme" }, - { "iuse", "usesme" }, - { "iafter", "ibefore" }, +static const DEPPAIR deppairs[] = { + { "ineed", "needsme" }, + { "iuse", "usesme" }, + { "iafter", "ibefore" }, { "ibefore", "iafter" }, { "iprovide", "providedby" }, { NULL, NULL } @@ -679,168 +637,151 @@ static const char *const depdirs[] = NULL }; -bool rc_deptree_update_needed (void) +bool rc_deptree_update_needed(void) { bool newer = false; - char **config; - char *service; + 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)); + 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) || - ! rc_newer_than (RC_DEPTREE, RC_INITDIR) || - ! rc_newer_than (RC_DEPTREE, RC_CONFDIR) || + if (! existss(RC_DEPTREE_CACHE) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR) || #ifdef RC_PKG_INITDIR - ! rc_newer_than (RC_DEPTREE, RC_PKG_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR) || #endif #ifdef RC_PKG_CONFDIR - ! rc_newer_than (RC_DEPTREE, RC_PKG_CONFDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR) || #endif #ifdef RC_LOCAL_INITDIR - ! rc_newer_than (RC_DEPTREE, RC_LOCAL_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR) || #endif #ifdef RC_LOCAL_CONFDIR - ! rc_newer_than (RC_DEPTREE, RC_LOCAL_CONFDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR) || #endif - ! rc_newer_than (RC_DEPTREE, "/etc/rc.conf")) - return (true); + ! rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf")) + 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); - STRLIST_FOREACH (config, service, i) { - if (! rc_newer_than (RC_DEPTREE, service)) { + TAILQ_FOREACH(s, config, entries) { + if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) { newer = true; break; } } - rc_strlist_free (config); + rc_stringlist_free(config); - return (newer); + return newer; } librc_hidden_def(rc_deptree_update_needed) - /* This is a 5 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 saves the depinfo object to disk - */ -bool rc_deptree_update (void) +/* This is a 5 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 saves the depinfo object to disk + */ +bool rc_deptree_update(void) { + FILE *fp; + RC_DEPTREE *deptree; + RC_DEPTREE *providers; + RC_DEPINFO *depinfo = NULL; + RC_DEPINFO *depinfo_np; + RC_DEPINFO *di; + RC_DEPTYPE *deptype = NULL; + RC_DEPTYPE *dt; + RC_DEPTYPE *dt_np; + RC_STRINGLIST *config; + RC_STRING *s; + RC_STRING *s2; + RC_DEPTYPE *provide; + char *line; + char *depend; char *depends; char *service; char *type; - char *depend; - char **config = NULL; - int retval = true; - FILE *fp; - rc_depinfo_t *deptree = NULL; - rc_depinfo_t *depinfo; - rc_depinfo_t *di; - rc_depinfo_t *last_depinfo = NULL; - rc_deptype_t *deptype = NULL; - rc_deptype_t *dt; - rc_deptype_t *last_deptype = NULL; - char **removedp = NULL; - char *line; - size_t len; size_t i; - size_t j; size_t k; - bool already_added; - const char *sys = rc_sys (); + size_t len; + int retval = true; + const char *sys = rc_sys(); + char *nosys; /* Some init scripts need RC_LIBDIR to source stuff Ideally we should be setting our full env instead */ - if (! getenv ("RC_LIBDIR")) - setenv ("RC_LIBDIR", RC_LIBDIR, 0); + if (! getenv("RC_LIBDIR")) + setenv("RC_LIBDIR", RC_LIBDIR, 0); /* Phase 1 - source all init scripts and print dependencies */ - if (! (fp = popen (GENDEP, "r"))) - return (false); + if (! (fp = popen(GENDEP, "r"))) + return false; + + deptree = xmalloc(sizeof(*deptree)); + STAILQ_INIT(deptree); - while ((line = rc_getline (fp))) + config = rc_stringlist_new(); + + while ((line = rc_getline(fp))) { depends = line; - service = strsep (&depends, " "); + service = strsep(&depends, " "); if (! service || ! *service) goto next; - type = strsep (&depends, " "); + type = strsep(&depends, " "); - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - last_depinfo = depinfo; - if (depinfo->service && strcmp (depinfo->service, service) == 0) - break; - } - - if (! depinfo) - { - if (! last_depinfo) - deptree = depinfo = xzalloc (sizeof (*depinfo)); - else if (! last_depinfo->service) - depinfo = last_depinfo; - else - { - last_depinfo->next = xzalloc (sizeof (*last_depinfo->next)); - depinfo = last_depinfo->next; + if (! depinfo || strcmp(depinfo->service, service) != 0) { + deptype = NULL; + depinfo = get_depinfo(deptree, service); + if (! depinfo) { + depinfo = xmalloc(sizeof(*depinfo)); + STAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(service); + STAILQ_INSERT_TAIL(deptree, depinfo, entries); } - depinfo->service = xstrdup (service); } - + /* We may not have any depends */ if (! type || ! depends) goto next; /* Get the type */ - if (strcmp (type, "config") != 0) { - last_deptype = NULL; - for (deptype = depinfo->depends; deptype; deptype = deptype->next) - { - last_deptype = deptype; - if (strcmp (deptype->type, type) == 0) - break; - } - - if (! deptype) - { - if (! last_deptype) - { - depinfo->depends = xzalloc (sizeof (*depinfo->depends)); - deptype = depinfo->depends; - } - else - { - last_deptype->next = xzalloc (sizeof (*last_deptype->next)); - deptype = last_deptype->next; - } - deptype->type = xstrdup (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(); + STAILQ_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, " "))) + while ((depend = strsep(&depends, " "))) { if (depend[0] == 0) continue; - if (strcmp (type, "config") == 0) { - rc_strlist_addsort (&config, depend); + if (strcmp(type, "config") == 0) { + rc_stringlist_add(config, depend); continue; } /* .sh files are not init scripts */ - len = strlen (depend); + len = strlen(depend); if (len > 2 && depend[len - 3] == '.' && depend[len - 2] == 's' && @@ -849,171 +790,114 @@ bool rc_deptree_update (void) /* Remove our dependency if instructed */ if (depend[0] == '!') { - rc_strlist_delete (&deptype->services, depend + 1); + rc_stringlist_delete(deptype->services, depend + 1); continue; } - rc_strlist_addsort (&deptype->services, depend); + 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_strlist_delete (&dt->services, depend); + 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_strlist_delete (&dt->services, depend); + if ((dt = get_deptype(depinfo, "ibefore"))) + rc_stringlist_delete(dt->services, depend); } } next: - free (line); + free(line); } - pclose (fp); + 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) { - char *nosys; - - len = strlen (sys); - nosys = xmalloc (len + 3); + len = strlen(sys); + nosys = xmalloc(len + 3); nosys[0] = 'n'; nosys[1] = 'o'; for (i = 0; i < len; i++) - nosys[i + 2] = (char) tolower ((int) sys[i]); + nosys[i + 2] = (char) tolower((int) sys[i]); nosys[i + 2] = '\0'; - last_depinfo = NULL; - depinfo = deptree; - while (depinfo) { - bool removed = false; - if ((deptype = get_deptype (depinfo, "keyword"))) { - STRLIST_FOREACH (deptype->services, service, i) - if (strcmp (service, nosys) == 0) { - if (last_depinfo) - last_depinfo->next = depinfo->next; - else - deptree = depinfo->next; - removed = true; - break; + STAILQ_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) { + provide = get_deptype(depinfo, "iprovide"); + STAILQ_REMOVE(deptree, depinfo, rc_depinfo, entries); + STAILQ_FOREACH(di, deptree, entries) { + STAILQ_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)) { + STAILQ_REMOVE(&di->depends, dt, rc_deptype, entries); + free(dt->type); + free(dt->services); + free(dt); + } + } + } } - } - if (removed) { - dt = get_deptype (depinfo, "iprovide"); - if (dt) - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_addu (&removedp, service); - for (di = deptree; di; di = di->next) { - for (dt = di->depends; dt; dt = dt->next) - rc_strlist_delete (&dt->services, depinfo->service); - } - di = depinfo->next; - depinfo->next = NULL; - rc_deptree_free (depinfo); - depinfo = di; - } else { - last_depinfo = depinfo; - depinfo = depinfo->next; - } - } - free (nosys); } - /* Phase 3 - add our providors to the tree */ - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - if ((deptype = get_deptype (depinfo, "iprovide"))) - STRLIST_FOREACH (deptype->services, service, i) - { - for (di = deptree; di; di = di->next) - { - last_depinfo = di; - if (strcmp (di->service, service) == 0) + /* Phase 3 - add our providers to the tree */ + providers = xmalloc(sizeof(*providers)); + STAILQ_INIT(providers); + STAILQ_FOREACH(depinfo, deptree, entries) + if ((deptype = get_deptype(depinfo, "iprovide"))) + TAILQ_FOREACH(s, deptype->services, entries) { + STAILQ_FOREACH(di, providers, entries) + if (strcmp(di->service, s->value) == 0) break; - } - if (! di) - { - last_depinfo->next = xzalloc (sizeof (*last_depinfo->next)); - di = last_depinfo->next; - di->service = xstrdup (service); + if (! di) { + di = xmalloc(sizeof(*di)); + STAILQ_INIT(&di->depends); + di->service = xstrdup(s->value); + STAILQ_INSERT_TAIL(providers, di, entries); } } - } + STAILQ_CONCAT(deptree, providers); + free(providers); /* Phase 4 - backreference our depends */ - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - for (i = 0; deppairs[i].depend; i++) - { - deptype = get_deptype (depinfo, deppairs[i].depend); + STAILQ_FOREACH(depinfo, deptree, entries) + for (i = 0; deppairs[i].depend; i++) { + deptype = get_deptype(depinfo, deppairs[i].depend); if (! deptype) continue; - - STRLIST_FOREACH (deptype->services, service, j) - { - di = get_depinfo (deptree, service); - if (! di) - { + TAILQ_FOREACH(s, deptype->services, entries) { + di = get_depinfo(deptree, s->value); + if (! di) { if (strcmp (deptype->type, "ineed") == 0) - { - bool removed = false; - STRLIST_FOREACH (removedp, line, k) { - if (strcmp (line, service) == 0) { - removed = true; - break; - } - } - if (! removed) - fprintf (stderr, - "Service `%s' needs non existant service `%s'\n", - depinfo->service, service); - } + fprintf (stderr, + "Service `%s' needs non" + " existant service `%s'\n", + depinfo->service, s->value); continue; } - /* Add our deptype now */ - last_deptype = NULL; - for (dt = di->depends; dt; dt = dt->next) - { - last_deptype = dt; - if (strcmp (dt->type, deppairs[i].addto) == 0) - break; + dt = get_deptype(di, deppairs[i].addto); + if (! dt) { + dt = xmalloc(sizeof(*dt)); + dt->type = xstrdup(deppairs[i].addto); + dt->services = rc_stringlist_new(); + STAILQ_INSERT_TAIL(&di->depends, dt, entries); } - if (! dt) - { - if (! last_deptype) - { - di->depends = xzalloc (sizeof (*di->depends)); - dt = di->depends; - } - else - { - last_deptype->next = xzalloc (sizeof (*last_deptype->next)); - dt = last_deptype->next; - } - dt->type = xstrdup (deppairs[i].addto); - } - - already_added = false; - STRLIST_FOREACH (dt->services, service, k) - if (strcmp (service, depinfo->service) == 0) - { - already_added = true; - break; - } - - if (! already_added) - rc_strlist_addsort (&dt->services, depinfo->service); + rc_stringlist_add(dt->services, depinfo->service); } } - } /* Phase 5 - save to disk Now that we're purely in C, do we need to keep a shell parseable file? @@ -1021,49 +905,47 @@ next: 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, "w"))) { + if ((fp = fopen (RC_DEPTREE_CACHE, "w"))) { i = 0; - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - fprintf (fp, "depinfo_%zu_service='%s'\n", - i, depinfo->service); - for (deptype = depinfo->depends; deptype; deptype = deptype->next) - { + STAILQ_FOREACH(depinfo, deptree, entries) { + fprintf(fp, "depinfo_%zu_service='%s'\n", + i, depinfo->service); + STAILQ_FOREACH(deptype, &depinfo->depends, entries) { k = 0; - STRLIST_FOREACH (deptype->services, service, j) - { - fprintf (fp, - "depinfo_%zu_%s_%zu='%s'\n", - i, - deptype->type, - k, service); + TAILQ_FOREACH(s, deptype->services, entries) { + fprintf(fp, + "depinfo_%zu_%s_%zu='%s'\n", + i, deptype->type, k, s->value); k++; } } i++; } - fclose (fp); + fclose(fp); } else { - fprintf (stderr, "fopen `%s': %s\n", RC_DEPTREE, strerror (errno)); + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPTREE_CACHE, strerror(errno)); retval = false; } /* Save our external config files to disk */ - if (config) { - if ((fp = fopen (RC_DEPCONFIG, "w"))) { - STRLIST_FOREACH (config, service, i) - fprintf (fp, "%s\n", service); - fclose (fp); + 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)); + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPCONFIG, strerror(errno)); retval = false; } - rc_strlist_free (config); + rc_stringlist_free (config); + } else { + unlink(RC_DEPCONFIG); } - rc_strlist_free (removedp); - rc_deptree_free (deptree); + rc_deptree_free(deptree); - return (retval); + return retval; } librc_hidden_def(rc_deptree_update) diff --git a/src/librc/librc-depend.h b/src/librc/librc-depend.h deleted file mode 100644 index 737920e3..00000000 --- a/src/librc/librc-depend.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * librc-depend.h - * Internal header file for dependency structures - */ - -/* - * Copyright 2007-2008 Roy Marples - * All rights reserved - - * 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_DEPEND_H -#define _LIBRC_DEPEND_H - -/*! @name Dependency structures - * private to librc - rc.h exposes them just a pointers */ - -/*! Singly linked list of dependency types that list the services the - * type is for */ -typedef struct rc_deptype -{ - /*! ineed, iuse, iafter, etc */ - char *type; - /*! NULL terminated list of services */ - char **services; - /*! Next dependency type */ - struct rc_deptype *next; -} rc_deptype_t; - -/*! Singly linked list of services and their dependencies */ -typedef struct rc_depinfo -{ - /*! Name of service */ - char *service; - /*! Dependencies */ - rc_deptype_t *depends; - /*! Next service dependency type */ - struct rc_depinfo *next; -} rc_depinfo_t; - -#endif diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c index f08a7622..fac78e2a 100644 --- a/src/librc/librc-misc.c +++ b/src/librc/librc-misc.c @@ -35,14 +35,14 @@ bool rc_yesno (const char *value) { if (! value) { errno = ENOENT; - return (false); + return false; } if (strcasecmp (value, "yes") == 0 || strcasecmp (value, "y") == 0 || strcasecmp (value, "true") == 0 || strcasecmp (value, "1") == 0) - return (true); + return true; if (strcasecmp (value, "no") != 0 && strcasecmp (value, "n") != 0 && @@ -50,7 +50,7 @@ bool rc_yesno (const char *value) strcasecmp (value, "0") != 0) errno = EINVAL; - return (false); + return false; } librc_hidden_def(rc_yesno) @@ -64,7 +64,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) char *pathp; if (! path1 || ! paths) - return (NULL); + return NULL; length = strlen (path1) + strlen (paths) + 1; if (*paths != '/') @@ -101,7 +101,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) *pathp++ = 0; - return (path); + return path; } librc_hidden_def(rc_strcatpaths) @@ -113,7 +113,7 @@ char *rc_getline (FILE *fp) size_t last = 0; if (feof (fp)) - return (NULL); + return NULL; do { len += BUFSIZ; @@ -128,74 +128,78 @@ char *rc_getline (FILE *fp) if (*line && line[--last] == '\n') line[last] = '\0'; - return (line); + return line; } librc_hidden_def(rc_getline) -char **rc_config_list (const char *file) +RC_STRINGLIST *rc_config_list(const char *file) { FILE *fp; char *buffer; char *p; char *token; - char **list = NULL; + RC_STRINGLIST *list; - if (! (fp = fopen (file, "r"))) - return (NULL); + if (!(fp = fopen(file, "r"))) + return NULL; - while ((p = buffer = rc_getline (fp))) { + list = rc_stringlist_new(); + + while ((p = buffer = rc_getline(fp))) { /* Strip leading spaces/tabs */ while ((*p == ' ') || (*p == '\t')) p++; /* Get entry - we do not want comments */ - token = strsep (&p, "#"); - if (token && (strlen (token) > 1)) { + token = strsep(&p, "#"); + if (token && (strlen(token) > 1)) { /* If not variable assignment then skip */ - if (strchr (token, '=')) { + if (strchr(token, '=')) { /* Stip the newline if present */ - if (token[strlen (token) - 1] == '\n') - token[strlen (token) - 1] = 0; + if (token[strlen(token) - 1] == '\n') + token[strlen(token) - 1] = 0; - rc_strlist_add (&list, token); + rc_stringlist_add(list, token); } } - free (buffer); + free(buffer); } - fclose (fp); + fclose(fp); - return (list); + return list; } librc_hidden_def(rc_config_list) -char **rc_config_load (const char *file) +RC_STRINGLIST *rc_config_load(const char *file) { - char **list = NULL; - char **config = NULL; + RC_STRINGLIST *list = NULL; + RC_STRINGLIST *config = NULL; char *token; - char *line; - char *linep; - char *linetok; + RC_STRING *line; + RC_STRING *cline; size_t i = 0; - int j; bool replaced; char *entry; char *newline; + char *p; - list = rc_config_list (file); - STRLIST_FOREACH (list, line, j) { + config = rc_stringlist_new(); + + list = rc_config_list(file); + TAILQ_FOREACH(line, list, entries) { /* Get entry */ - if (! (token = strsep (&line, "="))) + p = line->value; + if (! (token = strsep(&p, "="))) continue; entry = xstrdup (token); /* Preserve shell coloring */ - if (*line == '$') - token = line; + if (*p == '$') + token = line->value; else do { /* Bash variables are usually quoted */ - token = strsep (&line, "\"\'"); + token = strsep(&p, "\"\'"); } while (token && *token == '\0'); /* Drop a newline if that's all we have */ @@ -205,57 +209,54 @@ char **rc_config_load (const char *file) token[i] = 0; i = strlen (entry) + strlen (token) + 2; - newline = xmalloc (sizeof (char) * i); - snprintf (newline, i, "%s=%s", entry, token); + 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); + 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 */ - STRLIST_FOREACH (config, line, i) { - char *tmp = xstrdup (line); - linep = tmp; - linetok = strsep (&linep, "="); - if (strcmp (linetok, entry) == 0) { + TAILQ_FOREACH(cline, config, entries) { + p = strchr(cline->value, '='); + if (p && strncmp(entry, cline->value, + (size_t) (p - cline->value)) == 0) + { /* We have a match now - to save time we directly replace it */ - free (config[i - 1]); - config[i - 1] = newline; + free(cline->value); + cline->value = newline; replaced = true; - free (tmp); break; } - free (tmp); } if (! replaced) { - rc_strlist_addsort (&config, newline); - free (newline); + rc_stringlist_add(config, newline); + free(newline); } - free (entry); + free(entry); } - rc_strlist_free (list); + rc_stringlist_free(list); - return (config); + return config; } librc_hidden_def(rc_config_load) -char *rc_config_value (const char *const *list, const char *entry) +char *rc_config_value(RC_STRINGLIST *list, const char *entry) { - const char *line; - int i; + RC_STRING *line; char *p; - STRLIST_FOREACH (list, line, i) { - p = strchr (line, '='); - if (p && strncmp (entry, line, (size_t) (p - line)) == 0) - return (p += 1); + TAILQ_FOREACH(line, list, entries) { + p = strchr(line->value, '='); + if (p && + strncmp(entry, line->value, (size_t)(p - line->value)) == 0) + return p += 1; } - return (NULL); + return NULL; } librc_hidden_def(rc_config_value) - diff --git a/src/librc/librc-strlist.c b/src/librc/librc-strlist.c deleted file mode 100644 index 9b622695..00000000 --- a/src/librc/librc-strlist.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - librc-strlist.h - String list functions for using char ** arrays - - Based on a previous implementation by Martin Schlemmer - */ - -/* - * Copyright 2007-2008 Roy Marples - * All rights reserved - - * 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 "librc.h" - -static char *_rc_strlist_add (char ***list, const char *item, bool uniq) -{ - char **newlist; - char **lst = *list; - int i = 0; - - if (! item) - return (NULL); - - while (lst && lst[i]) { - if (uniq && strcmp (lst[i], item) == 0) { - errno = EEXIST; - return (NULL); - } - i++; - } - - newlist = xrealloc (lst, sizeof (char *) * (i + 2)); - newlist[i] = xstrdup (item); - newlist[i + 1] = NULL; - - *list = newlist; - return (newlist[i]); -} - -char *rc_strlist_add (char ***list, const char *item) -{ - return (_rc_strlist_add (list, item, false)); -} -librc_hidden_def(rc_strlist_add) - -char *rc_strlist_addu (char ***list, const char *item) -{ - return (_rc_strlist_add (list, item, true)); -} -librc_hidden_def(rc_strlist_addu) - -static char *_rc_strlist_addsort (char ***list, const char *item, - int (*sortfunc) (const char *s1, - const char *s2), - bool uniq) -{ - char **newlist; - char **lst = *list; - int i = 0; - char *tmp1; - char *tmp2; - char *retval; - - if (! item) - return (NULL); - - while (lst && lst[i]) { - if (uniq && strcmp (lst[i], item) == 0) { - errno = EEXIST; - return (NULL); - } - i++; - } - - newlist = xrealloc (lst, sizeof (char *) * (i + 2)); - - if (! i) - newlist[i] = NULL; - newlist[i + 1] = NULL; - - i = 0; - while (newlist[i] && sortfunc (newlist[i], item) < 0) - i++; - - tmp1 = newlist[i]; - retval = newlist[i] = xstrdup (item); - do { - i++; - tmp2 = newlist[i]; - newlist[i] = tmp1; - tmp1 = tmp2; - } while (tmp1); - - *list = newlist; - return (retval); -} - -char *rc_strlist_addsort (char ***list, const char *item) -{ - return (_rc_strlist_addsort (list, item, strcoll, false)); -} -librc_hidden_def(rc_strlist_addsort) - -char *rc_strlist_addsortc (char ***list, const char *item) -{ - return (_rc_strlist_addsort (list, item, strcmp, false)); -} -librc_hidden_def(rc_strlist_addsortc) - -char *rc_strlist_addsortu (char ***list, const char *item) -{ - return (_rc_strlist_addsort (list, item, strcmp, true)); -} -librc_hidden_def(rc_strlist_addsortu) - -bool rc_strlist_delete (char ***list, const char *item) -{ - char **lst = *list; - int i = 0; - - if (!lst || ! item) - return (false); - - while (lst[i]) { - if (strcmp (lst[i], item) == 0) { - free (lst[i]); - do { - lst[i] = lst[i + 1]; - i++; - } while (lst[i]); - return (true); - } - i++; - } - - errno = ENOENT; - return (false); -} -librc_hidden_def(rc_strlist_delete) - -char *rc_strlist_join (char ***list1, char **list2) -{ - char **lst1 = *list1; - char **newlist; - int i = 0; - int j = 0; - - if (! list2) - return (NULL); - - while (lst1 && lst1[i]) - i++; - - while (list2[j]) - j++; - - newlist = xrealloc (lst1, sizeof (char *) * (i + j + 1)); - - j = 0; - while (list2[j]) { - newlist[i] = list2[j]; - /* Take the item off the 2nd list as it's only a shallow copy */ - list2[j] = NULL; - i++; - j++; - } - newlist[i] = NULL; - - *list1 = newlist; - return (newlist[i == 0 ? 0 : i - 1]); -} -librc_hidden_def(rc_strlist_join) - -void rc_strlist_reverse (char **list) -{ - char *item; - int i = 0; - int j = 0; - - if (! list) - return; - - while (list[j]) - j++; - j--; - - while (i < j && list[i] && list[j]) { - item = list[i]; - list[i] = list[j]; - list[j] = item; - i++; - j--; - } -} -librc_hidden_def(rc_strlist_reverse) - -void rc_strlist_free (char **list) -{ - int i = 0; - - if (! list) - return; - - while (list[i]) - free (list[i++]); - - free (list); -} -librc_hidden_def(rc_strlist_free) diff --git a/src/librc/librc.c b/src/librc/librc.c index 7344e375..301a388a 100644 --- a/src/librc/librc.c +++ b/src/librc/librc.c @@ -47,7 +47,7 @@ const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; FILE *rc_environ_fd = NULL; typedef struct rc_service_state_name { - rc_service_state_t state; + RC_SERVICE state; const char *name; } rc_service_state_name_t; @@ -68,49 +68,53 @@ static const rc_service_state_name_t rc_service_state_names[] = { #define LS_INITD 0x01 #define LS_DIR 0x02 -static char **ls_dir (const char *dir, int options) +static RC_STRINGLIST *ls_dir(const char *dir, int options) { DIR *dp; struct dirent *d; - char **list = NULL; + RC_STRINGLIST *list; struct stat buf; + size_t l; + char *file; + int r; - if ((dp = opendir (dir)) == NULL) - return (NULL); + if ((dp = opendir(dir)) == NULL) + return NULL; - while (((d = readdir (dp)) != NULL)) { + list = rc_stringlist_new(); + while (((d = readdir(dp)) != NULL)) { if (d->d_name[0] != '.') { if (options & LS_INITD) { - int l = strlen (d->d_name); - /* Check that our file really exists. * This is important as a service maybe in a runlevel, but * could also have been removed. */ - char *file = rc_strcatpaths (dir, d->d_name, NULL); - int ok = stat (file, &buf); - free (file); - if (ok != 0) + file = rc_strcatpaths(dir, d->d_name, NULL); + r = stat(file, &buf); + free(file); + 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)) + if (stat(d->d_name, &buf) == 0 && + ! S_ISDIR(buf.st_mode)) continue; } - rc_strlist_addsort (&list, d->d_name); + rc_stringlist_add(list, d->d_name); } } - closedir (dp); + closedir(dp); - return (list); + return list; } -static bool rm_dir (const char *pathname, bool top) +static bool rm_dir(const char *pathname, bool top) { DIR *dp; struct dirent *d; @@ -118,49 +122,49 @@ static bool rm_dir (const char *pathname, bool top) struct stat s; bool retval = true; - if ((dp = opendir (pathname)) == NULL) - return (false); + 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) { - free (tmp); - tmp = rc_strcatpaths (pathname, d->d_name, (char *) NULL); + while (((d = readdir(dp)) != NULL) && errno == 0) { + if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) { + free(tmp); + tmp = rc_strcatpaths(pathname, d->d_name, (char *) NULL); - if (stat (tmp, &s) != 0) { + if (stat(tmp, &s) != 0) { retval = false; break; } - if (S_ISDIR (s.st_mode)) { - if (! rm_dir (tmp, true)) + if (S_ISDIR(s.st_mode)) { + if (! rm_dir(tmp, true)) { retval = false; break; } } else { - if (unlink (tmp)) { + if (unlink(tmp)) { retval = false; break; } } } } - closedir (dp); - free (tmp); + closedir(dp); + free(tmp); if (! retval) - return (false); + return false; - if (top && rmdir (pathname) != 0) - return (false); + if (top && rmdir(pathname) != 0) + return false; - return (true); + 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) +static bool file_regex(const char *file, const char *regex) { FILE *fp; char *line; @@ -168,153 +172,153 @@ static bool file_regex (const char *file, const char *regex) bool retval = false; int result; - if (! (fp = fopen (file, "r"))) - return (false); + 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); + 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 ((line = rc_getline (fp))) { - if (regexec (&re, line, 0, NULL, 0) == 0) + while ((line = rc_getline(fp))) { + if (regexec(&re, line, 0, NULL, 0) == 0) retval = true; - free (line); + free(line); if (retval) break; } - fclose (fp); - regfree (&re); + fclose(fp); + regfree(&re); - return (retval); + return retval; } #endif -const char *rc_sys (void) +const char *rc_sys(void) { #ifdef PREFIX - return (RC_SYS_PREFIX); + return RC_SYS_PREFIX; #else #ifdef __FreeBSD__ int jailed = 0; - size_t len = sizeof (jailed); + size_t len = sizeof(jailed); - if (sysctlbyname ("security.jail.jailed", &jailed, &len, NULL, 0) == 0) + if (sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0) == 0) if (jailed == 1) - return (RC_SYS_JAIL); + return RC_SYS_JAIL; #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 (file_regex ("/proc/self/status", - "envID:[[:space:]]*[1-9]")) - return (RC_SYS_OPENVZ); + 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 (file_regex("/proc/self/status", + "envID:[[:space:]]*[1-9]")) + return RC_SYS_OPENVZ; #endif - return (NULL); + return NULL; #endif /* PREFIX */ } -static const char *rc_parse_service_state (rc_service_state_t state) +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 rc_service_state_names[i].name; } - return (NULL); + return NULL; } -bool rc_runlevel_starting (void) +bool rc_runlevel_starting(void) { - return (exists (RC_STARTING)); + return exists(RC_STARTING); } librc_hidden_def(rc_runlevel_starting) -bool rc_runlevel_stopping (void) +bool rc_runlevel_stopping(void) { - return (exists (RC_STOPPING)); + return exists(RC_STOPPING); } librc_hidden_def(rc_runlevel_stopping) -char **rc_runlevel_list (void) +RC_STRINGLIST *rc_runlevel_list(void) { - return (ls_dir (RC_RUNLEVELDIR, LS_DIR)); + return ls_dir(RC_RUNLEVELDIR, LS_DIR); } librc_hidden_def(rc_runlevel_list) -char *rc_runlevel_get (void) +char *rc_runlevel_get(void) { FILE *fp; char *runlevel = NULL; - if ((fp = fopen (SOFTLEVEL, "r"))) { - runlevel = xmalloc (sizeof (char) * PATH_MAX); - if (fgets (runlevel, PATH_MAX, fp)) { - int i = strlen (runlevel) - 1; + if ((fp = fopen(SOFTLEVEL, "r"))) { + runlevel = xmalloc(sizeof(char) * PATH_MAX); + if (fgets(runlevel, PATH_MAX, fp)) { + int i = strlen(runlevel) - 1; if (runlevel[i] == '\n') runlevel[i] = 0; } else *runlevel = '\0'; - fclose (fp); + fclose(fp); } if (! runlevel || ! *runlevel) { - free (runlevel); - runlevel = xstrdup (RC_LEVEL_SYSINIT); + free(runlevel); + runlevel = xstrdup(RC_LEVEL_SYSINIT); } - return (runlevel); + return runlevel; } librc_hidden_def(rc_runlevel_get) -bool rc_runlevel_set (const char *runlevel) +bool rc_runlevel_set(const char *runlevel) { - FILE *fp = fopen (SOFTLEVEL, "w"); + FILE *fp = fopen(SOFTLEVEL, "w"); if (! fp) - return (false); - fprintf (fp, "%s", runlevel); - fclose (fp); - return (true); + return false; + fprintf(fp, "%s", runlevel); + fclose(fp); + return true; } librc_hidden_def(rc_runlevel_set) -bool rc_runlevel_exists (const char *runlevel) +bool rc_runlevel_exists(const char *runlevel) { char *path; struct stat buf; bool retval = false; if (! runlevel) - return (false); + return false; - path = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL); - if (stat (path, &buf) == 0 && S_ISDIR (buf.st_mode)) + path = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL); + if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) retval = true; - free (path); - return (retval); + free(path); + return retval; } librc_hidden_def(rc_runlevel_exists) - /* Resolve a service name to it's full path */ -char *rc_service_resolve (const char *service) +/* Resolve a service name to it's full path */ +char *rc_service_resolve(const char *service) { char buffer[PATH_MAX]; char *file; @@ -322,53 +326,53 @@ char *rc_service_resolve (const char *service) struct stat buf; if (! service) - return (NULL); + return NULL; if (service[0] == '/') - return (xstrdup (service)); + return xstrdup(service); /* First check started services */ - file = rc_strcatpaths (RC_SVCDIR, "started", service, (char *) NULL); - if (lstat (file, &buf) || ! S_ISLNK (buf.st_mode)) { - free (file); - file = rc_strcatpaths (RC_SVCDIR, "inactive", service, (char *) NULL); - if (lstat (file, &buf) || ! S_ISLNK (buf.st_mode)) { - free (file); + file = rc_strcatpaths(RC_SVCDIR, "started", service, (char *) NULL); + if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { + free(file); + file = rc_strcatpaths(RC_SVCDIR, "inactive", service, (char *) NULL); + if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) { + free(file); file = NULL; } } - memset (buffer, 0, sizeof (buffer)); + memset(buffer, 0, sizeof(buffer)); /* Nope, so lets see if the user has written it */ #ifdef RC_LOCAL_INITDIR - snprintf (buffer, sizeof (buffer), RC_LOCAL_INITDIR "/%s", service); - if (stat (buffer, &buf) == 0) - return (xstrdup (buffer)); + snprintf(buffer, sizeof(buffer), RC_LOCAL_INITDIR "/%s", service); + if (stat(buffer, &buf) == 0) + return xstrdup(buffer); #endif if (file) { - r = readlink (file, buffer, sizeof (buffer)); - free (file); + r = readlink(file, buffer, sizeof(buffer)); + free(file); if (r > 0) - return (xstrdup (buffer)); + return xstrdup(buffer); } - snprintf (buffer, sizeof (buffer), RC_INITDIR "/%s", service); + snprintf(buffer, sizeof(buffer), RC_INITDIR "/%s", service); /* So we don't exist in /etc/init.d - check RC_PKG_INITDIR */ #ifdef RC_PKG_INITDIR - if (stat (buffer, &buf) != 0) { - snprintf (buffer, sizeof (buffer), RC_PKG_INITDIR "/%s", service); - if (stat (buffer, &buf) != 0) - return (NULL); + if (stat(buffer, &buf) != 0) { + snprintf(buffer, sizeof(buffer), RC_PKG_INITDIR "/%s", service); + if (stat(buffer, &buf) != 0) + return NULL; } #endif - return (xstrdup (buffer)); + return xstrdup(buffer); } librc_hidden_def(rc_service_resolve) -bool rc_service_exists (const char *service) +bool rc_service_exists(const char *service) { char *file; bool retval = false; @@ -376,59 +380,62 @@ bool rc_service_exists (const char *service) struct stat buf; if (! service) - return (false); + return false; - len = strlen (service); + len = strlen(service); /* .sh files are not init scripts */ if (len > 2 && service[len - 3] == '.' && service[len - 2] == 's' && service[len - 1] == 'h') - return (false); + return false; - if (! (file = rc_service_resolve (service))) - return (false); + if (! (file = rc_service_resolve(service))) + return false; - if (stat (file, &buf) == 0 && buf.st_mode & S_IXUGO) + if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO) retval = true; - free (file); - return (retval); + free(file); + return retval; } librc_hidden_def(rc_service_exists) #define OPTSTR ". '%s'; echo \"${opts}\"" -char **rc_service_extra_commands (const char *service) +RC_STRINGLIST *rc_service_extra_commands(const char *service) { char *svc; char *cmd = NULL; char *buffer = NULL; - char **commands = NULL; + RC_STRINGLIST *commands; 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"))) { - p = buffer = rc_getline (fp); - while ((token = strsep (&p, " "))) - rc_strlist_addsort (&commands, token); - pclose (fp); - free (buffer); - } - free (cmd); - return (commands); + if (! (svc = rc_service_resolve(service))) + return NULL; + + commands = rc_stringlist_new(); + + l = strlen(OPTSTR) + strlen(svc) + 1; + cmd = xmalloc(sizeof(char) * l); + snprintf(cmd, l, OPTSTR, svc); + free(svc); + + if ((fp = popen(cmd, "r"))) { + p = buffer = rc_getline(fp); + while ((token = strsep(&p, " "))) + 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 *rc_service_description(const char *service, const char *option) { char *svc; char *cmd; @@ -436,85 +443,90 @@ char *rc_service_description (const char *service, const char *option) FILE *fp; size_t l; - if (! (svc = rc_service_resolve (service))) - return (NULL); + 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"))) { - desc = rc_getline (fp); - pclose (fp); + 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"))) { + desc = rc_getline(fp); + pclose(fp); } - free (cmd); - return (desc); + free(cmd); + return desc; } librc_hidden_def(rc_service_description) -bool rc_service_in_runlevel (const char *service, const char *runlevel) +bool rc_service_in_runlevel(const char *service, const char *runlevel) { char *file; bool retval; if (! runlevel || ! service) - return (false); + return false; - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service), - (char *) NULL); - retval = exists (file); - free (file); + file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service), + (char *) NULL); + retval = exists(file); + free(file); - return (retval); + return retval; } librc_hidden_def(rc_service_in_runlevel) -bool rc_service_mark (const char *service, const rc_service_state_t state) +bool rc_service_mark(const char *service, const RC_SERVICE state) { char *file; int i = 0; int skip_state = -1; const char *base; - char *init = rc_service_resolve (service); + char *init = rc_service_resolve(service); bool skip_wasinactive = false; + int s; + char *was; + RC_STRINGLIST *dirs; + RC_STRING *dir; + int serrno; if (! init) - return (false); + return false; - base = basename_c (service); + base = basename_c(service); if (state != RC_SERVICE_STOPPED) { - if (! exists (init)) { - free (init); - return (false); + if (! exists(init)) { + free(init); + return false; } - file = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (state), base, - (char *) NULL); - if (exists (file)) - unlink (file); - i = symlink (init, file); - if (i != 0) { - free (file); - free (init); - return (false); + file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state (state), base, + (char *) NULL); + if (exists(file)) + unlink(file); + i = symlink(init, file); + if (i != 0) { + free(file); + free(init); + return false; } - free (file); + free(file); skip_state = state; } if (state == RC_SERVICE_COLDPLUGGED || state == RC_SERVICE_FAILED) { - free (init); - return (true); + free(init); + return true; } /* Remove any old states now */ for (i = 0; rc_service_state_names[i].name; i++) { - int s = rc_service_state_names[i].state; + s = rc_service_state_names[i].state; if ((s != skip_state && s != RC_SERVICE_STOPPED && @@ -522,24 +534,24 @@ bool rc_service_mark (const char *service, const rc_service_state_t state) s != RC_SERVICE_SCHEDULED) && (! skip_wasinactive || s != RC_SERVICE_WASINACTIVE)) { - file = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (s), base, - (char *) NULL); - if (exists (file)) { + file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(s), base, + (char *) NULL); + if (exists(file)) { if ((state == RC_SERVICE_STARTING || state == RC_SERVICE_STOPPING) && s == RC_SERVICE_INACTIVE) { - char *wasfile = rc_strcatpaths (RC_SVCDIR, - rc_parse_service_state (RC_SERVICE_WASINACTIVE), - base, (char *) NULL); + was = rc_strcatpaths(RC_SVCDIR, + rc_parse_service_state(RC_SERVICE_WASINACTIVE), + base, (char *) NULL); - symlink (init, wasfile); + symlink(init, was); skip_wasinactive = true; - free (wasfile); + free(was); } - unlink (file); + unlink(file); } - free (file); + free(file); } } @@ -548,126 +560,133 @@ bool rc_service_mark (const char *service, const rc_service_state_t state) state == RC_SERVICE_STOPPED || state == RC_SERVICE_INACTIVE) { - file = rc_strcatpaths (RC_SVCDIR, "exclusive", base, (char *) NULL); - unlink (file); - free (file); + file = rc_strcatpaths(RC_SVCDIR, "exclusive", base, (char *) NULL); + unlink(file); + free(file); } /* Remove any options and daemons the service may have stored */ if (state == RC_SERVICE_STOPPED) { - char *dir = rc_strcatpaths (RC_SVCDIR, "options", base, (char *) NULL); - rm_dir (dir, true); - free (dir); + file = rc_strcatpaths(RC_SVCDIR, "options", base, (char *) NULL); + rm_dir(file, true); + free(file); - dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL); - rm_dir (dir, true); - free (dir); + file = rc_strcatpaths(RC_SVCDIR, "daemons", base, (char *) NULL); + rm_dir(file, true); + free(file); - rc_service_schedule_clear (service); + rc_service_schedule_clear(service); } /* These are final states, so remove us from scheduled */ if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) { - char *sdir = rc_strcatpaths (RC_SVCDIR, "scheduled", (char *) NULL); - char **dirs = ls_dir (sdir, 0); - char *dir; - int serrno; + file = rc_strcatpaths(RC_SVCDIR, "scheduled", (char *) NULL); + dirs = ls_dir(file, 0); - STRLIST_FOREACH (dirs, dir, i) { - char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL); - file = rc_strcatpaths (bdir, base, (char *) NULL); - unlink (file); - free (file); + TAILQ_FOREACH(dir, dirs, entries) { + was = rc_strcatpaths(file, dir->value, base, (char *) NULL); + unlink(was); + free(was); /* Try and remove the dir - we don't care about errors */ + was = rc_strcatpaths(file, dir->value, (char *) NULL); serrno = errno; - rmdir (bdir); + rmdir(was); errno = serrno; - free (bdir); + free(was); } - rc_strlist_free (dirs); - free (sdir); + rc_stringlist_free(dirs); } - free (init); - return (true); + free(init); + return true; } librc_hidden_def(rc_service_mark) -rc_service_state_t rc_service_state (const char *service) +RC_SERVICE rc_service_state(const char *service) { int i; int state = RC_SERVICE_STOPPED; + char *file; + RC_STRINGLIST *dirs; + RC_STRING *dir; for (i = 0; rc_service_state_names[i].name; i++) { - char *file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i].name, - basename_c (service), (char*) NULL); - if (exists (file)) { + file = rc_strcatpaths(RC_SVCDIR, rc_service_state_names[i].name, + basename_c(service), (char*) NULL); + 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; } - free (file); + free(file); } if (state & RC_SERVICE_STOPPED) { - char **services = rc_services_scheduled_by (service); - if (services) { - state |= RC_SERVICE_SCHEDULED; - free (services); + dirs = ls_dir(RC_SVCDIR "/scheduled", 0); + TAILQ_FOREACH (dir, dirs, entries) { + file = rc_strcatpaths(RC_SVCDIR, "scheduled", + dir->value, + service, (char *) NULL); + if (exists(file)) + state |= RC_SERVICE_SCHEDULED; + free(file); + if (state & RC_SERVICE_SCHEDULED) + break; } + rc_stringlist_free(dirs); } - return (state); + return state; } librc_hidden_def(rc_service_state) -char *rc_service_value_get (const char *service, const char *option) +char *rc_service_value_get(const char *service, const char *option) { FILE *fp; char *line = NULL; - char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option, - (char *) NULL); + char *file = rc_strcatpaths(RC_SVCDIR, "options", service, option, + (char *) NULL); - if ((fp = fopen (file, "r"))) { - line = rc_getline (fp); - fclose (fp); + if ((fp = fopen(file, "r"))) { + line = rc_getline(fp); + fclose(fp); } - free (file); + free(file); - return (line); + return line; } librc_hidden_def(rc_service_value_get) -bool rc_service_value_set (const char *service, const char *option, - const char *value) +bool rc_service_value_set(const char *service, const char *option, + const char *value) { FILE *fp; - char *path = rc_strcatpaths (RC_SVCDIR, "options", service, (char *) NULL); - char *file = rc_strcatpaths (path, option, (char *) NULL); + char *path = rc_strcatpaths(RC_SVCDIR, "options", service, (char *) NULL); + char *file = rc_strcatpaths(path, option, (char *) NULL); bool retval = false; - if (mkdir (path, 0755) != 0 && errno != EEXIST) { - free (path); - free (file); - return (false); + if (mkdir(path, 0755) != 0 && errno != EEXIST) { + free(path); + free(file); + return false; } - if ((fp = fopen (file, "w"))) { + if ((fp = fopen(file, "w"))) { if (value) - fprintf (fp, "%s", value); - fclose (fp); + fprintf(fp, "%s", value); + fclose(fp); retval = true; } - free (path); - free (file); - return (retval); + free(path); + free(file); + return retval; } librc_hidden_def(rc_service_value_set) -static pid_t _exec_service (const char *service, const char *arg) +static pid_t _exec_service(const char *service, const char *arg) { char *file; char *fifo; @@ -676,92 +695,92 @@ static pid_t _exec_service (const char *service, const char *arg) sigset_t old; struct sigaction sa; - file = rc_service_resolve (service); - if (! exists (file)) { - rc_service_mark (service, RC_SERVICE_STOPPED); - free (file); - return (0); + file = rc_service_resolve(service); + if (! exists(file)) { + rc_service_mark(service, RC_SERVICE_STOPPED); + free(file); + return 0; } /* We create a fifo so that other services can wait until we complete */ - fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename_c (service), - (char *) NULL); + fifo = rc_strcatpaths(RC_SVCDIR, "exclusive", basename_c(service), + (char *) NULL); - if (mkfifo (fifo, 0600) != 0 && errno != EEXIST) { - free (fifo); - free (file); - return (-1); + if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) { + free(fifo); + free(file); + return -1; } /* We need to block signals until we have forked */ - memset (&sa, 0, sizeof (sa)); + memset(&sa, 0, sizeof (sa)); sa.sa_handler = SIG_DFL; - sigemptyset (&sa.sa_mask); - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &old); + sigemptyset(&sa.sa_mask); + sigfillset(&full); + sigprocmask(SIG_SETMASK, &full, &old); - if ((pid = fork ()) == 0) { + if ((pid = fork()) == 0) { /* Restore default handlers */ - sigaction (SIGCHLD, &sa, NULL); - sigaction (SIGHUP, &sa, NULL); - sigaction (SIGINT, &sa, NULL); - sigaction (SIGQUIT, &sa, NULL); - sigaction (SIGTERM, &sa, NULL); - sigaction (SIGUSR1, &sa, NULL); - sigaction (SIGWINCH, &sa, NULL); + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGWINCH, &sa, NULL); /* Unmask signals */ - sigprocmask (SIG_SETMASK, &old, NULL); + sigprocmask(SIG_SETMASK, &old, NULL); /* Safe to run now */ - execl (file, file, arg, (char *) NULL); - fprintf (stderr, "unable to exec `%s': %s\n", - file, strerror (errno)); - unlink (fifo); - _exit (EXIT_FAILURE); + execl(file, file, arg, (char *) NULL); + fprintf(stderr, "unable to exec `%s': %s\n", + file, strerror(errno)); + unlink(fifo); + _exit(EXIT_FAILURE); } if (pid == -1) - fprintf (stderr, "fork: %s\n", strerror (errno)); + fprintf(stderr, "fork: %s\n",strerror (errno)); - sigprocmask (SIG_SETMASK, &old, NULL); + sigprocmask(SIG_SETMASK, &old, NULL); - free (fifo); - free (file); + free(fifo); + free(file); - return (pid); + return pid; } -pid_t rc_service_stop (const char *service) +pid_t rc_service_stop(const char *service) { - rc_service_state_t state = rc_service_state (service); + RC_SERVICE state = rc_service_state(service); if (state & RC_SERVICE_FAILED) - return (-1); + return -1; if (state & RC_SERVICE_STOPPED) - return (0); + return 0; - return (_exec_service (service, "stop")); + return _exec_service(service, "stop"); } librc_hidden_def(rc_service_stop) -pid_t rc_service_start (const char *service) +pid_t rc_service_start(const char *service) { - rc_service_state_t state = rc_service_state (service); + RC_SERVICE state = rc_service_state(service); if (state & RC_SERVICE_FAILED) - return (-1); + return -1; if (! state & RC_SERVICE_STOPPED) - return (0); + return 0; - return (_exec_service (service, "start")); + return _exec_service(service, "start"); } librc_hidden_def(rc_service_start) -bool rc_service_schedule_start (const char *service, - const char *service_to_start) +bool rc_service_schedule_start(const char *service, + const char *service_to_start) { char *dir; char *init; @@ -769,162 +788,156 @@ bool rc_service_schedule_start (const char *service, bool retval; /* service may be a provided service, like net */ - if (! service || ! rc_service_exists (service_to_start)) - return (false); + if (! service || ! rc_service_exists(service_to_start)) + return false; - dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service), - (char *) NULL); - if (mkdir (dir, 0755) != 0 && errno != EEXIST) { - free (dir); - return (false); + dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), + (char *) NULL); + if (mkdir(dir, 0755) != 0 && errno != EEXIST) { + free(dir); + return false; } - init = rc_service_resolve (service_to_start); - file = rc_strcatpaths (dir, basename_c (service_to_start), (char *) NULL); - retval = (exists (file) || symlink (init, file) == 0); - free (init); - free (file); - free (dir); + init = rc_service_resolve(service_to_start); + file = rc_strcatpaths(dir, basename_c(service_to_start), (char *) NULL); + retval = (exists(file) || symlink(init, file) == 0); + free(init); + free(file); + free(dir); - return (retval); + return retval; } librc_hidden_def(rc_service_schedule_start) -bool rc_service_schedule_clear (const char *service) +bool rc_service_schedule_clear(const char *service) { - char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service), - (char *) NULL); + char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), + (char *) NULL); bool retval; - if (! (retval = rm_dir (dir, true)) && errno == ENOENT) + if (! (retval = rm_dir(dir, true)) && errno == ENOENT) retval = true; - free (dir); - return (retval); + free(dir); + return retval; } librc_hidden_def(rc_service_schedule_clear) - -char **rc_services_in_runlevel (const char *runlevel) +RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel) { char *dir; - char **list = NULL; + RC_STRINGLIST *list; if (! runlevel) { -#if defined(RC_PKG_INITDIR) || defined(RC_LOCAL_INITDIR) - int i; -#endif #ifdef RC_PKG_INITDIR - char **pkg = ls_dir (RC_PKG_INITDIR, LS_INITD); + RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD); #endif #ifdef RC_LOCAL_INITDIR - char **local = ls_dir (RC_LOCAL_INITDIR, LS_INITD); + RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD); #endif - list = ls_dir (RC_INITDIR, LS_INITD); + list = ls_dir(RC_INITDIR, LS_INITD); #ifdef RC_PKG_INITDIR - STRLIST_FOREACH (pkg, dir, i) - rc_strlist_addsortu (&list, dir); - rc_strlist_free (pkg); + if (pkg) { + TAILQ_CONCAT(list, pkg); + free(pkg); + } #endif #ifdef RC_LOCAL_DIR - STRLIST_FOREACH (local, dir, i) - rc_strlist_addsortu (&list, dir); - rc_strlist_free (local); + if (local) { + TAILQ_CONCAT(list, local); + free(local); + } #endif - return (list); + return list; } /* These special levels never contain any services */ - if (strcmp (runlevel, RC_LEVEL_SYSINIT) == 0 || - strcmp (runlevel, RC_LEVEL_SINGLE) == 0) - return (NULL); - - dir = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL); - list = ls_dir (dir, LS_INITD); - free (dir); - return (list); + if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 || + strcmp(runlevel, RC_LEVEL_SINGLE) == 0) { + list = rc_stringlist_new(); + return list; + } + + dir = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL); + list = ls_dir(dir, LS_INITD); + free(dir); + return list; } librc_hidden_def(rc_services_in_runlevel) -char **rc_services_in_state (rc_service_state_t state) +RC_STRINGLIST *rc_services_in_state(RC_SERVICE state) { - char *dir = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (state), - (char *) NULL); - char **list = NULL; + char *dir = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(state), + (char *) NULL); + RC_STRINGLIST *services; + RC_STRINGLIST *list; + RC_STRINGLIST *dirs; + RC_STRING *d; + char *p; if (state == RC_SERVICE_SCHEDULED) { - char **dirs = ls_dir (dir, 0); - char *d; - int i; - - STRLIST_FOREACH (dirs, d, i) { - char *p = rc_strcatpaths (dir, d, (char *) NULL); - char **entries = ls_dir (p, LS_INITD); - char *e; - int j; - - STRLIST_FOREACH (entries, e, j) - rc_strlist_addsortu (&list, e); - - if (entries) - free (entries); + dirs = ls_dir(dir, 0); + list = rc_stringlist_new(); + TAILQ_FOREACH(d, dirs, entries) { + p = rc_strcatpaths(dir, d->value, (char *) NULL); + services = ls_dir(p, LS_INITD); + free(p); + TAILQ_CONCAT(list, services); + free(services); } - - if (dirs) - free (dirs); + rc_stringlist_free(dirs); } else { - list = ls_dir (dir, LS_INITD); + list = ls_dir(dir, LS_INITD); } - free (dir); - return (list); + free(dir); + return list; } librc_hidden_def(rc_services_in_state) -bool rc_service_add (const char *runlevel, const char *service) +bool rc_service_add(const char *runlevel, const char *service) { bool retval; char *init; char *file; + char path[MAXPATHLEN] = { '\0' }; + char *p; - if (! rc_runlevel_exists (runlevel)) { + if (! rc_runlevel_exists(runlevel)) { errno = ENOENT; - return (false); + return false; } - if (rc_service_in_runlevel (service, runlevel)) { + if (rc_service_in_runlevel(service, runlevel)) { errno = EEXIST; - return (false); + return false; } - init = rc_service_resolve (service); + init = rc_service_resolve(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) { - char tmp[MAXPATHLEN] = { '\0' }; - char *p; - - p = realpath (dirname (init), tmp); - free (init); + p = realpath(dirname (init), path); + free(init); if (! *p) - return (false); + return false; - retval = (strcmp (tmp, RC_INITDIR) == 0); + retval = (strcmp(path, RC_INITDIR) == 0); if (! retval) { errno = EPERM; - return (false); + return false; } - init = rc_strcatpaths (RC_INITDIR, service, (char *) NULL); + init = rc_strcatpaths(RC_INITDIR, service, (char *) NULL); } - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service), - (char *) NULL); - retval = (symlink (init, file) == 0); - free (init); - free (file); - return (retval); + file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service), + (char *) NULL); + retval = (symlink(init, file) == 0); + free(init); + free(file); + return retval; } librc_hidden_def(rc_service_add) @@ -934,46 +947,46 @@ bool rc_service_delete (const char *runlevel, const char *service) bool retval = false; if (! runlevel || ! service) - return (false); + return false; - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service), + file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c(service), (char *) NULL); - if (unlink (file) == 0) + if (unlink(file) == 0) retval = true; - free (file); - return (retval); + free(file); + return retval; } librc_hidden_def(rc_service_delete) -char **rc_services_scheduled_by (const char *service) +RC_STRINGLIST *rc_services_scheduled_by(const char *service) { - char **dirs = ls_dir (RC_SVCDIR "/scheduled", 0); - char **list = NULL; - char *dir; - int i; + RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0); + RC_STRINGLIST *list; + RC_STRING *dir; + char *file; - STRLIST_FOREACH (dirs, dir, i) { - char *file = rc_strcatpaths (RC_SVCDIR, "scheduled", dir, service, - (char *) NULL); - if (exists (file)) - rc_strlist_add (&list, file); - free (file); + list = rc_stringlist_new(); + TAILQ_FOREACH (dir, dirs, entries) { + file = rc_strcatpaths(RC_SVCDIR, "scheduled", dir->value, + service, (char *) NULL); + if (exists(file)) + rc_stringlist_add(list, file); + free(file); } - rc_strlist_free (dirs); + rc_stringlist_free(dirs); - return (list); + return list; } librc_hidden_def(rc_services_scheduled_by) -char **rc_services_scheduled (const char *service) +RC_STRINGLIST *rc_services_scheduled(const char *service) { - char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service), - (char *) NULL); - char **list = NULL; + char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service), + (char *) NULL); + RC_STRINGLIST *list = ls_dir(dir, LS_INITD); - list = ls_dir (dir, LS_INITD); - free (dir); - return (list); + free(dir); + return list; } librc_hidden_def(rc_services_scheduled) diff --git a/src/librc/librc.h b/src/librc/librc.h index edbebafb..aaad7ccd 100644 --- a/src/librc/librc.h +++ b/src/librc/librc.h @@ -64,10 +64,8 @@ #include <kvm.h> #endif -#include "librc-depend.h" #include "rc.h" #include "rc-misc.h" -#include "strlist.h" #include "hidden-visibility.h" #define librc_hidden_proto(x) hidden_proto(x) @@ -115,15 +113,11 @@ librc_hidden_proto(rc_service_state) librc_hidden_proto(rc_service_value_get) librc_hidden_proto(rc_service_value_set) librc_hidden_proto(rc_strcatpaths) -librc_hidden_proto(rc_strlist_add) -librc_hidden_proto(rc_strlist_addu) -librc_hidden_proto(rc_strlist_addsort) -librc_hidden_proto(rc_strlist_addsortc) -librc_hidden_proto(rc_strlist_addsortu) -librc_hidden_proto(rc_strlist_delete) -librc_hidden_proto(rc_strlist_free) -librc_hidden_proto(rc_strlist_join) -librc_hidden_proto(rc_strlist_reverse) +librc_hidden_proto(rc_stringlist_add) +librc_hidden_proto(rc_stringlist_addu) +librc_hidden_proto(rc_stringlist_delete) +librc_hidden_proto(rc_stringlist_free) +librc_hidden_proto(rc_stringlist_sort) librc_hidden_proto(rc_yesno) #endif diff --git a/src/librc/rc.h b/src/librc/rc.h index 0b811f46..061959e7 100644 --- a/src/librc/rc.h +++ b/src/librc/rc.h @@ -32,15 +32,24 @@ # if (GCC_VERSION >= 3005) # define SENTINEL __attribute__ ((__sentinel__)) # endif +# define DEPRECATED __attribute__ ((deprecated)) #endif #ifndef SENTINEL # define SENTINEL #endif #include <sys/types.h> +#include <sys/queue.h> #include <stdbool.h> #include <stdio.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" @@ -49,30 +58,30 @@ /*! Return the current runlevel. * @return the current runlevel */ -char *rc_runlevel_get (void); +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 *runlevel); +bool rc_runlevel_exists(const char *); /*! Return a NULL terminated list of runlevels * @return a NULL terminated list of runlevels */ -char **rc_runlevel_list (void); +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 *runlevel); +bool rc_runlevel_set(const char *); /*! Is the runlevel starting? * @return true if yes, otherwise false */ -bool rc_runlevel_starting (void); +bool rc_runlevel_starting(void); /*! Is the runlevel stopping? * @return true if yes, otherwise false */ -bool rc_runlevel_stopping (void); +bool rc_runlevel_stopping(void); /*! @name RC * A service can be given as a full path or just its name. @@ -97,19 +106,19 @@ typedef enum RC_SERVICE_FAILED = 0x0200, RC_SERVICE_SCHEDULED = 0x0400, RC_SERVICE_WASINACTIVE = 0x0800 -} rc_service_state_t; +} 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 *runlevel, const char *service); +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 *runlevel, const char *service); +bool rc_service_delete(const char *, const char *); /*! Save the arguments to find a running daemon * @param service to save arguments for @@ -117,116 +126,113 @@ bool rc_service_delete (const char *runlevel, const char *service); * @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 *service, const char *const *argv, - const char *name, const char *pidfile, - bool started); +bool rc_service_daemon_set(const char *, const char *const *, const char *, 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 *service, const char *option); +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 *service); +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 *service, const char *runlevel); +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 *service, rc_service_state_t state); +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 */ -char **rc_service_extra_commands (const char *service); +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 *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 *service, - const char *service_to_start); +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 */ -char **rc_services_scheduled_by (const char *service); +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 *service); +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_state_t rc_service_state (const char *service); +RC_SERVICE rc_service_state(const char *); /*! Start a service * @param service to start * @return pid of the service starting process */ -pid_t rc_service_start (const char *service); +pid_t rc_service_start(const char *); /*! Stop a service * @param service to stop * @return pid of service stopping process */ -pid_t rc_service_stop (const char *service); +pid_t rc_service_stop(const char *); /*! Check if the service started the daemon * @param service to check * @param exec 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 *service, const char *const *argv, - int indx); +bool rc_service_started_daemon(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 *service, const char *option); +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 *service, const char *option, - const char *value); +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 */ -char **rc_services_in_runlevel (const char *runlevel); +RC_STRINGLIST *rc_services_in_runlevel(const char *); /*! List the services in a state * @param state to list * @return NULL terminated list of services */ -char **rc_services_in_state (rc_service_state_t state); +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 */ -char **rc_services_scheduled (const char *service); +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 *service); +bool rc_service_daemons_crashed(const char *); /*! @name System types * OpenRC can support some special sub system types, normally virtualization. @@ -238,7 +244,7 @@ bool rc_service_daemons_crashed (const char *service); #define RC_SYS_VSERVER "VSERVER" #define RC_SYS_XEN0 "XEN0" #define RC_SYS_XENU "XENU" -const char *rc_sys (void); +const char *rc_sys(void); /*! @name Dependency options * These options can change the services found by the rc_get_depinfo and @@ -256,40 +262,67 @@ const char *rc_sys (void); * We analyse each init script and cache the resultant dependency tree. * This tree can be accessed using the below functions. */ -#ifndef _IN_LIBRC +#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 */ + STAILQ_ENTRY(rc_deptype) entries; +} RC_DEPTYPE; + +/*! Singly linked list of services and their dependencies */ +typedef struct rc_depinfo +{ + /*! Name of service */ + char *service; + /*! Dependencies */ + STAILQ_HEAD(, rc_deptype) depends; + /*! List of entries */ + STAILQ_ENTRY(rc_depinfo) entries; +} RC_DEPINFO; + +typedef STAILQ_HEAD(,rc_depinfo) RC_DEPTREE; +#else /* Handles to internal structures */ -typedef void *rc_depinfo_t; +typedef void *RC_DEPTREE; #endif /*! Check to see if source is newer than target. * If target is a directory then we traverse it and it's children. * @return true if source is newer than target, otherwise false */ -bool rc_newer_than (const char *source, const char *target); +bool rc_newer_than(const char *, 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. * @return true if successful, otherwise false */ -bool rc_deptree_update (void); +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. * @return true if it needs updating, otherwise false */ -bool rc_deptree_update_needed (void); +bool rc_deptree_update_needed(void); /*! 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_depinfo_t *rc_deptree_load (void); +RC_DEPTREE *rc_deptree_load(void); /*! 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 */ -char **rc_deptree_depend (const rc_depinfo_t *deptree, - const char *type, const char *service); +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. @@ -298,10 +331,8 @@ char **rc_deptree_depend (const rc_depinfo_t *deptree, * @param services to check * @param options to pass * @return NULL terminated list of services in order */ -char **rc_deptree_depends (const rc_depinfo_t *deptree, - const char *const *types, - const char *const *services, const char *runlevel, - int options); +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 @@ -310,12 +341,11 @@ char **rc_deptree_depends (const rc_depinfo_t *deptree, * @param runlevel to change into * @param options to pass * @return NULL terminated list of services in order */ -char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, - int options); +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_depinfo_t *deptree); +void rc_deptree_free(RC_DEPTREE *); /*! @name Plugins * For each plugin loaded we will call rc_plugin_hook with the below @@ -347,13 +377,13 @@ typedef enum RC_HOOK_SERVICE_START_NOW = 106, RC_HOOK_SERVICE_START_DONE = 107, RC_HOOK_SERVICE_START_OUT = 108 -} rc_hook_t; +} 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_t hook, const char *name); +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. */ @@ -362,91 +392,64 @@ extern FILE *rc_environ_fd; /*! @name Configuration * These functions help to deal with shell based configuration files */ /*! Return a line from a file, stripping the trailing newline. */ -char *rc_getline (FILE *fp); +char *rc_getline(FILE *); /*! Return a NULL terminated list of non comment lines from a file. */ -char **rc_config_list (const char *file); +RC_STRINGLIST *rc_config_list(const char *); /*! Return a NULL terminated list of key=value lines from a file. */ -char **rc_config_load (const char *file); +RC_STRINGLIST *rc_config_load(const char *); /*! Return the value of the entry from a key=value list. */ -char *rc_config_value (const char *const *list, const char *entry); +char *rc_config_value(RC_STRINGLIST *, const char *); /*! Check if a variable is a boolean and return it's 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 *variable); +bool rc_yesno(const char *); /*! @name String List functions - * Handy functions for dealing with string arrays of char **. - * It's safe to assume that any function here that uses char ** is a string - * list that can be manipulated with the below functions. Every string list - * should be released with a call to rc_strlist_free. */ + * 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 */ -char *rc_strlist_add (char ***list, const char *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 */ -char *rc_strlist_addu (char ***list, const char *item); - -/*! Duplicate the item, add it to the list at the point based on locale and - * then return a pointer to it. - * @param list to add the item too - * @param item to add. - * @return pointer to newly added item */ -char *rc_strlist_addsort (char ***list, const char *item); - -/*! Duplicate the item, add it to the list at the point based on C locale and - * then return a pointer to it. - * @param list to add the item too - * @param item to add. - * @return pointer to newly added item */ -char *rc_strlist_addsortc (char ***list, const char *item); - -/*! If the item does not exist in the list, duplicate it, add it to the - * list based on locale and then return a pointer to it. - * @param list to add the item too - * @param item to add. - * @return pointer to newly added item */ -char *rc_strlist_addsortu (char ***list, const char *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_strlist_delete (char ***list, const char *item); - -/*! Moves the contents of list2 onto list1, so list2 is effectively emptied. - * Returns a pointer to the last item on the new list. - * @param list1 to append to - * @param list2 to move from - * @return pointer to the last item on the list */ -char *rc_strlist_join (char ***list1, char **list2); +bool rc_stringlist_delete(RC_STRINGLIST *, const char *); -/*! Reverses the contents of the list. - * @param list to reverse */ -void rc_strlist_reverse (char **list); +/*! 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_strlist_free (char **list); +void rc_stringlist_free(RC_STRINGLIST *); /*! Concatenate paths adding '/' if needed. The resultant pointer should be * freed when finished with. * @param path1 starting path * @param paths NULL terminated list of paths to add * @return pointer to the new path */ -char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL; +char *rc_strcatpaths(const char *, const char *, ...) SENTINEL; /*! Find processes based on criteria. * All of these are optional. @@ -457,7 +460,6 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL; * @param uid to check for * @param pid to check for * @return NULL terminated list of pids */ -pid_t *rc_find_pids (const char *const *argv, const char *cmd, - uid_t uid, pid_t pid); +pid_t *rc_find_pids(const char *const *, const char *, uid_t, pid_t); #endif diff --git a/src/librc/rc.map b/src/librc/rc.map index e5fd350b..8ad4e187 100644 --- a/src/librc/rc.map +++ b/src/librc/rc.map @@ -43,15 +43,12 @@ global: rc_service_value_get; rc_service_value_set; rc_strcatpaths; - rc_strlist_add; - rc_strlist_addu; - rc_strlist_addsort; - rc_strlist_addsortc; - rc_strlist_addsortu; - rc_strlist_delete; - rc_strlist_free; - rc_strlist_join; - rc_strlist_reverse; + rc_stringlist_add; + rc_stringlist_addu; + rc_stringlist_delete; + rc_stringlist_new; + rc_stringlist_sort; + rc_stringlist_free; rc_sys; rc_yesno; |