From e6674b2caee26d2421215d29977cb91d5731ec8a Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Wed, 11 Apr 2007 12:44:47 +0000 Subject: Cuddle up to LKML C style --- src/einfo.h | 14 +- src/env-update.c | 392 +++++---- src/fstabinfo.c | 162 ++-- src/libeinfo.c | 1180 +++++++++++++-------------- src/librc-daemon.c | 974 +++++++++++----------- src/librc-misc.c | 1159 +++++++++++++-------------- src/librc-strlist.c | 188 +++-- src/librc.c | 1251 ++++++++++++++--------------- src/mountinfo.c | 386 +++++---- src/rc-depend.c | 182 ++--- src/rc-plugin.c | 157 ++-- src/rc-status.c | 197 +++-- src/rc-update.c | 255 +++--- src/rc.c | 2048 +++++++++++++++++++++++------------------------ src/rc.h | 76 +- src/runscript.c | 1851 ++++++++++++++++++++---------------------- src/start-stop-daemon.c | 1793 ++++++++++++++++++++--------------------- src/strlist.h | 4 +- 18 files changed, 5884 insertions(+), 6385 deletions(-) diff --git a/src/einfo.h b/src/einfo.h index d274eefc..29f831a2 100644 --- a/src/einfo.h +++ b/src/einfo.h @@ -18,12 +18,12 @@ typedef enum { - einfo_good, - einfo_warn, - einfo_bad, - einfo_hilite, - einfo_bracket, - einfo_normal + einfo_good, + einfo_warn, + einfo_bad, + einfo_hilite, + einfo_bracket, + einfo_normal } einfo_color_t; /* Colour codes used by the below functions. */ @@ -50,7 +50,7 @@ typedef enum NOTE We use the v suffix here so we can add veinfo for va_list in the future, but veinfo is used by shell scripts as they don't have the va_list concept -*/ + */ bool colour_terminal (void); int einfon (const char *fmt, ...) EINFO_PRINTF (1, 2); int ewarnn (const char *fmt, ...) EINFO_PRINTF (1, 2); diff --git a/src/env-update.c b/src/env-update.c index 1df55386..9ddeae02 100644 --- a/src/env-update.c +++ b/src/env-update.c @@ -5,7 +5,8 @@ Copyright 2007 Gentoo Foundation Released under the GPLv2 - */ + +*/ #include #include @@ -26,221 +27,206 @@ #define LDSOCONF "/etc/ld.so.conf" #define NOTICE "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" \ - "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" \ -"# GO INTO %s NOT %s\n\n" + "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" \ + "# GO INTO %s NOT %s\n\n" #define LDNOTICE "# ld.so.conf autogenerated by env-update; make all\n" \ - "# changes to contents of /etc/env.d directory\n" - -static const char *specials[] = -{ - "ADA_INCLUDE_PATH", - "ADA_OBJECTS_PATH", - "CLASSPATH", - "INFOPATH", - "KDEDIRS", - "LDPATH", - "MANPATH", - "PATH", - "PKG_CONFIG_PATH", - "PRELINK_PATH", - "PRELINK_PATH_MASK", - "PYTHONPATH", - "ROOTPATH", - NULL + "# changes to contents of /etc/env.d directory\n" + +static const char *specials[] = { + "ADA_INCLUDE_PATH", + "ADA_OBJECTS_PATH", + "CLASSPATH", + "INFOPATH", + "KDEDIRS", + "LDPATH", + "MANPATH", + "PATH", + "PKG_CONFIG_PATH", + "PRELINK_PATH", + "PRELINK_PATH_MASK", + "PYTHONPATH", + "ROOTPATH", + NULL }; -static const char *special_spaces[] = -{ - "CONFIG_PROTECT", - "CONFIG_PROTECT_MASK", - NULL, +static const char *special_spaces[] = { + "CONFIG_PROTECT", + "CONFIG_PROTECT_MASK", + NULL, }; static char *applet = NULL; int main (int argc, char **argv) { - char **files = rc_ls_dir (NULL, ENVDIR, 0); - char *file; - char **envs = NULL; - char *env; - int i = 0; - FILE *fp; - bool ld = true; - char *ldent; - char **ldents = NULL; - int nents = 0; - - applet = argv[0]; - - if (! files) - eerrorx ("%s: no files in " ENVDIR " to process", applet); - - STRLIST_FOREACH (files, file, i) - { - char *path = rc_strcatpaths (ENVDIR, file, (char *) NULL); - char **entries = NULL; - char *entry; - int j; - - if (! rc_is_dir (path)) - entries = rc_get_config (NULL, path); - free (path); - - STRLIST_FOREACH (entries, entry, j) - { - char *tmpent = rc_xstrdup (entry); - char *value = tmpent; - char *var = strsep (&value, "="); - int k; - bool isspecial = false; - bool isspecial_spaced = false; - bool replaced = false; - - for (k = 0; special_spaces[k]; k++) - if (strcmp (special_spaces[k], var) == 0) - { - isspecial = true; - isspecial_spaced = true; - break; - } - - if (! isspecial) - { - for (k = 0; specials[k]; k++) - if (strcmp (specials[k], var) == 0) - { - isspecial = true; - break; - } - } - - /* Skip blank vars */ - if (isspecial && - (! value || strlen (value)) == 0) - { - free (tmpent); - continue; - } - - STRLIST_FOREACH (envs, env, k) - { - char *tmpenv = rc_xstrdup (env); - char *tmpvalue = tmpenv; - char *tmpentry = strsep (&tmpvalue, "="); - - if (strcmp (tmpentry, var) == 0) - { - if (isspecial) - { - int len = strlen (envs[k - 1]) + strlen (entry) + 1; - envs[k - 1] = rc_xrealloc (envs[k - 1], len); - snprintf (envs[k - 1] + strlen (envs[k - 1]), len, - "%s%s", isspecial_spaced ? " " : ":", value); - } - else - { - free (envs[k - 1]); - envs[k - 1] = strdup (entry); - } - replaced = true; - } - free (tmpenv); - - if (replaced) - break; - } - - if (! replaced) - envs = rc_strlist_addsort (envs, entry); - - free (tmpent); - } - } - - if ((fp = fopen (PROFILE_ENV, "w")) == NULL) - eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno)); - fprintf (fp, NOTICE, "/etc/profile", PROFILE_ENV); - STRLIST_FOREACH (envs, env, i) - { - char *tmpent = rc_xstrdup (env); - char *value = tmpent; - char *var = strsep (&value, "="); - if (strcmp (var, "LDPATH") != 0) - fprintf (fp, "export %s='%s'\n", var, value); - free (tmpent); - } - fclose (fp); - - if ((fp = fopen (CSH_ENV, "w")) == NULL) - eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno)); - fprintf (fp, NOTICE, "/etc/csh.cshrc", PROFILE_ENV); - STRLIST_FOREACH (envs, env, i) - { - char *tmpent = rc_xstrdup (env); - char *value = tmpent; - char *var = strsep (&value, "="); - if (strcmp (var, "LDPATH") != 0) - fprintf (fp, "setenv %s '%s'\n", var, value); - free (tmpent); - } - fclose (fp); - - ldent = rc_get_config_entry (envs, "LDPATH"); - - if (! ldent || - (argc > 1 && argv[1] && strcmp (argv[1], "--no-ldconfig") == 0)) - { - free (envs); - return (EXIT_SUCCESS); - } - - while ((file = strsep (&ldent, ":"))) - { - if (strlen (file) == 0) - continue; - - ldents = rc_strlist_add (ldents, file); - nents++; - } - - /* Update ld.so.conf only if different */ - if (rc_exists (LDSOCONF)) - { - char **lines = rc_get_list (NULL, LDSOCONF); - char *line; - ld = false; - STRLIST_FOREACH (lines, line, i) - if (i > nents || strcmp (line, ldents[i - 1]) != 0) - { - ld = true; - break; - } - if (i - 1 != nents) - ld = true; - } - - if (ld) - { - int retval = 0; - - if ((fp = fopen (LDSOCONF, "w")) == NULL) - eerrorx ("%s: fopen `%s': %s", applet, LDSOCONF, strerror (errno)); - fprintf (fp, LDNOTICE); - STRLIST_FOREACH (ldents, ldent, i) - fprintf (fp, "%s\n", ldent); - fclose (fp); + char **files = rc_ls_dir (NULL, ENVDIR, 0); + char *file; + char **envs = NULL; + char *env; + int i = 0; + FILE *fp; + bool ld = true; + char *ldent; + char **ldents = NULL; + int nents = 0; + + applet = argv[0]; + + if (! files) + eerrorx ("%s: no files in " ENVDIR " to process", applet); + + STRLIST_FOREACH (files, file, i) { + char *path = rc_strcatpaths (ENVDIR, file, (char *) NULL); + char **entries = NULL; + char *entry; + int j; + + if (! rc_is_dir (path)) + entries = rc_get_config (NULL, path); + free (path); + + STRLIST_FOREACH (entries, entry, j) { + char *tmpent = rc_xstrdup (entry); + char *value = tmpent; + char *var = strsep (&value, "="); + int k; + bool isspecial = false; + bool isspecial_spaced = false; + bool replaced = false; + + for (k = 0; special_spaces[k]; k++) + if (strcmp (special_spaces[k], var) == 0) { + isspecial = true; + isspecial_spaced = true; + break; + } + + if (! isspecial) { + for (k = 0; specials[k]; k++) + if (strcmp (specials[k], var) == 0) { + isspecial = true; + break; + } + } + + /* Skip blank vars */ + if (isspecial && + (! value || strlen (value)) == 0) + { + free (tmpent); + continue; + } + + STRLIST_FOREACH (envs, env, k) { + char *tmpenv = rc_xstrdup (env); + char *tmpvalue = tmpenv; + char *tmpentry = strsep (&tmpvalue, "="); + + if (strcmp (tmpentry, var) == 0) { + if (isspecial) { + int len = strlen (envs[k - 1]) + strlen (entry) + 1; + envs[k - 1] = rc_xrealloc (envs[k - 1], len); + snprintf (envs[k - 1] + strlen (envs[k - 1]), len, + "%s%s", isspecial_spaced ? " " : ":", value); + } else { + free (envs[k - 1]); + envs[k - 1] = strdup (entry); + } + replaced = true; + } + free (tmpenv); + + if (replaced) + break; + } + + if (! replaced) + envs = rc_strlist_addsort (envs, entry); + + free (tmpent); + } + } + + if ((fp = fopen (PROFILE_ENV, "w")) == NULL) + eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno)); + fprintf (fp, NOTICE, "/etc/profile", PROFILE_ENV); + + STRLIST_FOREACH (envs, env, i) { + char *tmpent = rc_xstrdup (env); + char *value = tmpent; + char *var = strsep (&value, "="); + if (strcmp (var, "LDPATH") != 0) + fprintf (fp, "export %s='%s'\n", var, value); + free (tmpent); + } + fclose (fp); + + if ((fp = fopen (CSH_ENV, "w")) == NULL) + eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno)); + fprintf (fp, NOTICE, "/etc/csh.cshrc", PROFILE_ENV); + + STRLIST_FOREACH (envs, env, i) { + char *tmpent = rc_xstrdup (env); + char *value = tmpent; + char *var = strsep (&value, "="); + if (strcmp (var, "LDPATH") != 0) + fprintf (fp, "setenv %s '%s'\n", var, value); + free (tmpent); + } + fclose (fp); + + ldent = rc_get_config_entry (envs, "LDPATH"); + + if (! ldent || + (argc > 1 && argv[1] && strcmp (argv[1], "--no-ldconfig") == 0)) + { + free (envs); + return (EXIT_SUCCESS); + } + + while ((file = strsep (&ldent, ":"))) { + if (strlen (file) == 0) + continue; + + ldents = rc_strlist_add (ldents, file); + nents++; + } + + /* Update ld.so.conf only if different */ + if (rc_exists (LDSOCONF)) { + char **lines = rc_get_list (NULL, LDSOCONF); + char *line; + ld = false; + STRLIST_FOREACH (lines, line, i) + if (i > nents || strcmp (line, ldents[i - 1]) != 0) + { + ld = true; + break; + } + if (i - 1 != nents) + ld = true; + } + + if (ld) { + int retval = 0; + + if ((fp = fopen (LDSOCONF, "w")) == NULL) + eerrorx ("%s: fopen `%s': %s", applet, LDSOCONF, strerror (errno)); + fprintf (fp, LDNOTICE); + STRLIST_FOREACH (ldents, ldent, i) + fprintf (fp, "%s\n", ldent); + fclose (fp); #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - ebegin ("Regenerating /var/run/ld-elf.so.hints"); - retval = system ("/sbin/ldconfig -elf -i '" LDSOCONF "'"); + ebegin ("Regenerating /var/run/ld-elf.so.hints"); + retval = system ("/sbin/ldconfig -elf -i '" LDSOCONF "'"); #else - ebegin ("Regenerating /etc/ld.so.cache"); - retval = system ("/sbin/ldconfig"); + ebegin ("Regenerating /etc/ld.so.cache"); + retval = system ("/sbin/ldconfig"); #endif - eend (retval, NULL); - } + eend (retval, NULL); + } - return(EXIT_SUCCESS); + return(EXIT_SUCCESS); } diff --git a/src/fstabinfo.c b/src/fstabinfo.c index de37383b..f435d5a7 100644 --- a/src/fstabinfo.c +++ b/src/fstabinfo.c @@ -43,104 +43,96 @@ #ifdef HAVE_GETMNTENT static struct mntent *getmntfile (FILE *fp, const char *file) { - struct mntent *ent; + struct mntent *ent; - while ((ent = getmntent (fp))) - if (strcmp (file, ent->mnt_dir) == 0) - return (ent); + while ((ent = getmntent (fp))) + if (strcmp (file, ent->mnt_dir) == 0) + return (ent); - return (NULL); + return (NULL); } #endif int main (int argc, char **argv) { - int i; + int i; #ifdef HAVE_GETMNTENT - FILE *fp; - struct mntent *ent; + FILE *fp; + struct mntent *ent; #else - struct fstab *ent; + struct fstab *ent; #endif - int result = EXIT_FAILURE; - char *p; - char *token; - int n = 0; + int result = EXIT_FAILURE; + char *p; + char *token; + int n = 0; - for (i = 1; i < argc; i++) - { + for (i = 1; i < argc; i++) { #ifdef HAVE_GETMNTENT - fp = setmntent ("/etc/fstab", "r"); + fp = setmntent ("/etc/fstab", "r"); #endif - if (strcmp (argv[i], "--fstype") == 0 && i + 1 < argc) - { - i++; - p = argv[i]; - while ((token = strsep (&p, ","))) - while ((ent = GET_ENT)) - if (strcmp (token, ENT_TYPE (ent)) == 0) - printf ("%s\n", ENT_FILE (ent)); - result = EXIT_SUCCESS; - } - - if (strcmp (argv[i], "--mount-cmd") == 0 && i + 1 < argc) - { - i++; - if ((ent = GET_ENT_FILE (argv[i])) == NULL) - continue; - printf ("-o %s -t %s %s %s\n", ENT_OPTS (ent), ENT_TYPE (ent), - ENT_DEVICE (ent), ENT_FILE (ent)); - result = EXIT_SUCCESS; - } - - if (strcmp (argv[i], "--opts") == 0 && i + 1 < argc) - { - i++; - if ((ent = GET_ENT_FILE (argv[i])) == NULL) - continue; - printf ("%s\n", ENT_OPTS (ent)); - result = EXIT_SUCCESS; - } - - if (strcmp (argv[i], "--passno") == 0 && i + 1 < argc) - { - i++; - switch (argv[i][0]) - { - case '=': - case '<': - case '>': - if (sscanf (argv[i] + 1, "%d", &n) != 1) - eerrorx ("%s: invalid passno %s", argv[0], argv[i] + 1); - - while ((ent = GET_ENT)) - { - if (((argv[i][0] == '=' && n == ENT_PASS (ent)) || - (argv[i][0] == '<' && n > ENT_PASS (ent)) || - (argv[i][0] == '>' && n < ENT_PASS (ent))) && - strcmp (ENT_FILE (ent), "none") != 0) - printf ("%s\n", ENT_FILE (ent)); - } - - default: - if ((ent = GET_ENT_FILE (argv[i])) == NULL) - continue; - printf ("%d\n", ENT_PASS (ent)); - result = EXIT_SUCCESS; - } - } - - END_ENT; - - if (result != EXIT_SUCCESS) - { - eerror ("%s: unknown option `%s'", basename (argv[0]), argv[i]); - break; - } - - } - - exit (result); + if (strcmp (argv[i], "--fstype") == 0 && i + 1 < argc) { + i++; + p = argv[i]; + while ((token = strsep (&p, ","))) + while ((ent = GET_ENT)) + if (strcmp (token, ENT_TYPE (ent)) == 0) + printf ("%s\n", ENT_FILE (ent)); + result = EXIT_SUCCESS; + } + + if (strcmp (argv[i], "--mount-cmd") == 0 && i + 1 < argc) { + i++; + if ((ent = GET_ENT_FILE (argv[i])) == NULL) + continue; + printf ("-o %s -t %s %s %s\n", ENT_OPTS (ent), ENT_TYPE (ent), + ENT_DEVICE (ent), ENT_FILE (ent)); + result = EXIT_SUCCESS; + } + + if (strcmp (argv[i], "--opts") == 0 && i + 1 < argc) { + i++; + if ((ent = GET_ENT_FILE (argv[i])) == NULL) + continue; + printf ("%s\n", ENT_OPTS (ent)); + result = EXIT_SUCCESS; + } + + if (strcmp (argv[i], "--passno") == 0 && i + 1 < argc) { + i++; + switch (argv[i][0]) { + case '=': + case '<': + case '>': + if (sscanf (argv[i] + 1, "%d", &n) != 1) + eerrorx ("%s: invalid passno %s", argv[0], argv[i] + 1); + + while ((ent = GET_ENT)) { + if (((argv[i][0] == '=' && n == ENT_PASS (ent)) || + (argv[i][0] == '<' && n > ENT_PASS (ent)) || + (argv[i][0] == '>' && n < ENT_PASS (ent))) && + strcmp (ENT_FILE (ent), "none") != 0) + printf ("%s\n", ENT_FILE (ent)); + } + + default: + if ((ent = GET_ENT_FILE (argv[i])) == NULL) + continue; + printf ("%d\n", ENT_PASS (ent)); + result = EXIT_SUCCESS; + } + } + + END_ENT; + + if (result != EXIT_SUCCESS) { + eerror ("%s: unknown option `%s'", basename (argv[0]), argv[i]); + break; + } + + } + + exit (result); } diff --git a/src/libeinfo.c b/src/libeinfo.c index 31c588f1..ebcddaa5 100644 --- a/src/libeinfo.c +++ b/src/libeinfo.c @@ -40,860 +40,818 @@ /* A cheat sheet of colour capable terminals This is taken from DIR_COLORS from GNU coreutils We embed it here as we shouldn't depend on coreutils */ -static const char *colour_terms[] = -{ - "Eterm", - "ansi", - "color-xterm", - "con132x25", - "con132x30", - "con132x43", - "con132x60", - "con80x25", - "con80x28", - "con80x30", - "con80x43", - "con80x50", - "con80x60", - "cons25", - "console", - "cygwin", - "dtterm", - "gnome", - "konsole", - "kterm", - "linux", - "linux-c", - "mach-color", - "mlterm", - "putty", - "rxvt", - "rxvt-cygwin", - "rxvt-cygwin-native", - "rxvt-unicode", - "screen", - "screen-bce", - "screen-w", - "screen.linux", - "vt100", - "xterm", - "xterm-256color", - "xterm-color", - "xterm-debian", - NULL +static const char *colour_terms[] = { + "Eterm", + "ansi", + "color-xterm", + "con132x25", + "con132x30", + "con132x43", + "con132x60", + "con80x25", + "con80x28", + "con80x30", + "con80x43", + "con80x50", + "con80x60", + "cons25", + "console", + "cygwin", + "dtterm", + "gnome", + "konsole", + "kterm", + "linux", + "linux-c", + "mach-color", + "mlterm", + "putty", + "rxvt", + "rxvt-cygwin", + "rxvt-cygwin-native", + "rxvt-unicode", + "screen", + "screen-bce", + "screen-w", + "screen.linux", + "vt100", + "xterm", + "xterm-256color", + "xterm-color", + "xterm-debian", + NULL }; static bool is_env (const char *var, const char *val) { - char *v; + char *v; - if (! var) - return (false); + if (! var) + return (false); - v = getenv (var); - if (! v) - return (val ? false : true); + v = getenv (var); + if (! v) + return (val ? false : true); - return (strcasecmp (v, val) ? false : true); + return (strcasecmp (v, val) ? false : true); } bool colour_terminal (void) { - static int in_colour = -1; - int i = 0; - char *term; + static int in_colour = -1; + int i = 0; + char *term; - if (in_colour == 0) - return (false); - if (in_colour == 1) - return (true); + if (in_colour == 0) + return (false); + if (in_colour == 1) + return (true); - term = getenv ("TERM"); - /* If $TERM isn't set then the chances are we're in single user mode */ - if (! term) - return (true); + term = getenv ("TERM"); + /* If $TERM isn't set then the chances are we're in single user mode */ + if (! term) + return (true); - while (colour_terms[i]) - { - if (strcmp (colour_terms[i], term) == 0) - { - in_colour = 1; - return (true); - } - i++; - } + while (colour_terms[i]) { + if (strcmp (colour_terms[i], term) == 0) { + in_colour = 1; + return (true); + } + i++; + } - in_colour = 0; - return (false); + in_colour = 0; + return (false); } static int get_term_columns (void) { #ifdef TIOCGSIZE /* BSD */ - struct ttysize ts; + struct ttysize ts; - if (ioctl(0, TIOCGSIZE, &ts) == 0) - return (ts.ts_cols); + if (ioctl(0, TIOCGSIZE, &ts) == 0) + return (ts.ts_cols); #elif TIOCGWINSZ /* Linux */ - struct winsize ws; + struct winsize ws; - if (ioctl(0, TIOCGWINSZ, &ws) == 0) - return (ws.ws_col); + if (ioctl(0, TIOCGWINSZ, &ws) == 0) + return (ws.ws_col); #endif - return (DEFAULT_COLS); + return (DEFAULT_COLS); } static int ebuffer (const char *cmd, int retval, const char *fmt, va_list ap) { - char *file = getenv ("RC_EBUFFER"); - FILE *fp; - char buffer[RC_LINEBUFFER]; - int l = 1; + char *file = getenv ("RC_EBUFFER"); + FILE *fp; + char buffer[RC_LINEBUFFER]; + int l = 1; - if (! file || ! cmd || strlen (cmd) < 4) - return (0); + if (! file || ! cmd || strlen (cmd) < 4) + return (0); - if (! (fp = fopen (file, "a"))) - { - fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno)); - return (0); - } + if (! (fp = fopen (file, "a"))) { + fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno)); + return (0); + } - fprintf (fp, "%s %d ", cmd, retval); + fprintf (fp, "%s %d ", cmd, retval); - if (fmt) - { - va_list apc; - va_copy (apc, ap); - l = vsnprintf (buffer, sizeof (buffer), fmt, apc); - fprintf (fp, "%d %s\n", l, buffer); - va_end (apc); - } - else - fprintf (fp, "0\n"); + if (fmt) { + va_list apc; + va_copy (apc, ap); + l = vsnprintf (buffer, sizeof (buffer), fmt, apc); + fprintf (fp, "%d %s\n", l, buffer); + va_end (apc); + } else + fprintf (fp, "0\n"); - fclose (fp); - return (l); + fclose (fp); + return (l); } typedef struct func { - const char *name; - int (*efunc) (const char *fmt, ...); - int (*eefunc) (int retval, const char *fmt, ...); - void (*eind) (void); + const char *name; + int (*efunc) (const char *fmt, ...); + int (*eefunc) (int retval, const char *fmt, ...); + void (*eind) (void); } func_t; static const func_t funcmap[] = { - { "einfon", &einfon, NULL, NULL }, - { "ewarnn", &ewarnn, NULL, NULL}, - { "eerrorn", &eerrorn, NULL, NULL}, - { "einfo", &einfo, NULL, NULL }, - { "ewarn", &ewarn, NULL, NULL }, - { "eerror", &eerror, NULL, NULL }, - { "ebegin", &ebegin, NULL, NULL }, - { "eend", NULL, &eend, NULL }, - { "ewend", NULL, &ewend, NULL }, - { "eindent", NULL, NULL, &eindent }, - { "eoutdent", NULL, NULL, &eoutdent }, - { "einfovn", &einfovn, NULL, NULL }, - { "ewarnvn", &ewarnvn, NULL, NULL }, - { "einfov", &einfov, NULL, NULL }, - { "ewarnv", &ewarnv, NULL, NULL }, - { "ebeginv", &ebeginv, NULL, NULL }, - { "eendv", NULL, &eendv, NULL }, - { "ewendv", NULL, &ewendv, NULL }, - { "eindentv" ,NULL, NULL, &eindentv }, - { "eoutdentv", NULL, NULL, &eoutdentv }, - { NULL, NULL, NULL, NULL }, + { "einfon", &einfon, NULL, NULL }, + { "ewarnn", &ewarnn, NULL, NULL}, + { "eerrorn", &eerrorn, NULL, NULL}, + { "einfo", &einfo, NULL, NULL }, + { "ewarn", &ewarn, NULL, NULL }, + { "eerror", &eerror, NULL, NULL }, + { "ebegin", &ebegin, NULL, NULL }, + { "eend", NULL, &eend, NULL }, + { "ewend", NULL, &ewend, NULL }, + { "eindent", NULL, NULL, &eindent }, + { "eoutdent", NULL, NULL, &eoutdent }, + { "einfovn", &einfovn, NULL, NULL }, + { "ewarnvn", &ewarnvn, NULL, NULL }, + { "einfov", &einfov, NULL, NULL }, + { "ewarnv", &ewarnv, NULL, NULL }, + { "ebeginv", &ebeginv, NULL, NULL }, + { "eendv", NULL, &eendv, NULL }, + { "ewendv", NULL, &ewendv, NULL }, + { "eindentv" ,NULL, NULL, &eindentv }, + { "eoutdentv", NULL, NULL, &eoutdentv }, + { NULL, NULL, NULL, NULL }, }; void eflush (void) { - FILE *fp; - char *file = getenv ("RC_EBUFFER"); - char buffer[RC_LINEBUFFER]; - char *cmd; - int retval = 0; - int length = 0; - char *token; - char *p; - struct stat buf; - pid_t pid; - char newfile[PATH_MAX]; - int i = 1; - - if (! file|| (stat (file, &buf) != 0)) - { - errno = 0; - return; - } - - /* Find a unique name for our file */ - while (true) - { - snprintf (newfile, sizeof (newfile), "%s.%d", file, i); - if (stat (newfile, &buf) != 0) - { - if (rename (file, newfile)) - fprintf (stderr, "rename `%s' `%s': %s\n", file, newfile, - strerror (errno)); - break; - } - i++; - } - - /* We fork a child process here so we don't hold anything up */ - if ((pid = fork ()) == -1) - { - fprintf (stderr, "fork: %s", strerror (errno)); - return; - } - - if (pid != 0) - return; - - /* Spin until we can lock the ebuffer */ - while (true) - { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 20000; - select (0, NULL, NULL, NULL, &tv); - errno = 0; - if (link (newfile, EBUFFER_LOCK) == 0) - break; - if (errno != EEXIST) - fprintf (stderr, "link `%s' `%s': %s\n", newfile, EBUFFER_LOCK, - strerror (errno)); - } - - if (! (fp = fopen (newfile, "r"))) - { - fprintf (stderr, "fopen `%s': %s\n", newfile, strerror (errno)); - return; - } - - unsetenv ("RC_EBUFFER"); - - memset (buffer, 0, RC_LINEBUFFER); - while (fgets (buffer, RC_LINEBUFFER, fp)) - { - i = strlen (buffer) - 1; - if (i < 1) - continue; - - if (buffer[i] == '\n') - buffer[i] = 0; - - p = buffer; - cmd = strsep (&p, " "); - token = strsep (&p, " "); - if (sscanf (token, "%d", &retval) != 1) - { - fprintf (stderr, "eflush `%s': not a number", token); - continue; - } - token = strsep (&p, " "); - if (sscanf (token, "%d", &length) != 1) - { - fprintf (stderr, "eflush `%s': not a number", token); - continue; - } - - i = 0; - while (funcmap[i].name) - { - if (strcmp (funcmap[i].name, cmd) == 0) - { - if (funcmap[i].efunc) - { - if (p) - funcmap[i].efunc ("%s", p); - else - funcmap[i].efunc (NULL, NULL); - } - else if (funcmap[i].eefunc) - { - if (p) - funcmap[i].eefunc (retval, "%s", p); - else - funcmap[i].eefunc (retval, NULL, NULL); - } - else if (funcmap[i].eind) - funcmap[i].eind (); - else - fprintf (stderr, "eflush `%s': no function defined\n", cmd); - break; - } - i++; - } - - if (! funcmap[i].name) - fprintf (stderr, "eflush `%s': invalid function\n", cmd); - } - fclose (fp); - - if (unlink (EBUFFER_LOCK)) - fprintf (stderr, "unlink `%s': %s", EBUFFER_LOCK, strerror (errno)); - - if (unlink (newfile)) - fprintf (stderr, "unlink `%s': %s", newfile, strerror (errno)); - - _exit (EXIT_SUCCESS); -} - -#define EBUFFER(_cmd, _retval, _fmt, _ap) \ -{ \ - int _i = ebuffer (_cmd, _retval, _fmt, _ap); \ - if (_i) \ - return (_i); \ + FILE *fp; + char *file = getenv ("RC_EBUFFER"); + char buffer[RC_LINEBUFFER]; + char *cmd; + int retval = 0; + int length = 0; + char *token; + char *p; + struct stat buf; + pid_t pid; + char newfile[PATH_MAX]; + int i = 1; + + if (! file|| (stat (file, &buf) != 0)) { + errno = 0; + return; + } + + /* Find a unique name for our file */ + while (true) { + snprintf (newfile, sizeof (newfile), "%s.%d", file, i); + if (stat (newfile, &buf) != 0) { + if (rename (file, newfile)) + fprintf (stderr, "rename `%s' `%s': %s\n", file, newfile, + strerror (errno)); + break; + } + i++; + } + + /* We fork a child process here so we don't hold anything up */ + if ((pid = fork ()) == -1) { + fprintf (stderr, "fork: %s", strerror (errno)); + return; + } + + if (pid != 0) + return; + + /* Spin until we can lock the ebuffer */ + while (true) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 20000; + select (0, NULL, NULL, NULL, &tv); + errno = 0; + if (link (newfile, EBUFFER_LOCK) == 0) + break; + if (errno != EEXIST) + fprintf (stderr, "link `%s' `%s': %s\n", newfile, EBUFFER_LOCK, + strerror (errno)); + } + + if (! (fp = fopen (newfile, "r"))) { + fprintf (stderr, "fopen `%s': %s\n", newfile, strerror (errno)); + return; + } + + unsetenv ("RC_EBUFFER"); + + memset (buffer, 0, RC_LINEBUFFER); + while (fgets (buffer, RC_LINEBUFFER, fp)) { + i = strlen (buffer) - 1; + if (i < 1) + continue; + + if (buffer[i] == '\n') + buffer[i] = 0; + + p = buffer; + cmd = strsep (&p, " "); + token = strsep (&p, " "); + if (sscanf (token, "%d", &retval) != 1) { + fprintf (stderr, "eflush `%s': not a number", token); + continue; + } + token = strsep (&p, " "); + if (sscanf (token, "%d", &length) != 1) { + fprintf (stderr, "eflush `%s': not a number", token); + continue; + } + + i = 0; + while (funcmap[i].name) { + if (strcmp (funcmap[i].name, cmd) == 0) { + if (funcmap[i].efunc) { + if (p) + funcmap[i].efunc ("%s", p); + else + funcmap[i].efunc (NULL, NULL); + } else if (funcmap[i].eefunc) { + if (p) + funcmap[i].eefunc (retval, "%s", p); + else + funcmap[i].eefunc (retval, NULL, NULL); + } else if (funcmap[i].eind) + funcmap[i].eind (); + else + fprintf (stderr, "eflush `%s': no function defined\n", cmd); + break; + } + i++; + } + + if (! funcmap[i].name) + fprintf (stderr, "eflush `%s': invalid function\n", cmd); + } + fclose (fp); + + if (unlink (EBUFFER_LOCK)) + fprintf (stderr, "unlink `%s': %s", EBUFFER_LOCK, strerror (errno)); + + if (unlink (newfile)) + fprintf (stderr, "unlink `%s': %s", newfile, strerror (errno)); + + _exit (EXIT_SUCCESS); +} + +#define EBUFFER(_cmd, _retval, _fmt, _ap) { \ + int _i = ebuffer (_cmd, _retval, _fmt, _ap); \ + if (_i) \ + return (_i); \ } static void elog (int level, const char *fmt, va_list ap) { - char *e = getenv ("RC_ELOG"); - va_list apc; + char *e = getenv ("RC_ELOG"); + va_list apc; - if (fmt && e) - { - closelog (); - openlog (e, LOG_PID, LOG_DAEMON); - va_copy (apc, ap); - vsyslog (level, fmt, apc); - va_end (apc); - closelog (); - } + if (fmt && e) { + closelog (); + openlog (e, LOG_PID, LOG_DAEMON); + va_copy (apc, ap); + vsyslog (level, fmt, apc); + va_end (apc); + closelog (); + } } + static int _eindent (FILE *stream) { - char *env = getenv ("RC_EINDENT"); - int amount = 0; - char indent[INDENT_MAX]; + char *env = getenv ("RC_EINDENT"); + int amount = 0; + char indent[INDENT_MAX]; - if (env) - { - errno = 0; - amount = strtol (env, NULL, 0); - if (errno != 0 || amount < 0) - amount = 0; - else if (amount > INDENT_MAX) - amount = INDENT_MAX; + if (env) { + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0 || amount < 0) + amount = 0; + else if (amount > INDENT_MAX) + amount = INDENT_MAX; - if (amount > 0) - memset (indent, ' ', amount); - } + if (amount > 0) + memset (indent, ' ', amount); + } - /* Terminate it */ - memset (indent + amount, 0, 1); + /* Terminate it */ + memset (indent + amount, 0, 1); - return (fprintf (stream, "%s", indent)); + return (fprintf (stream, "%s", indent)); } #define EINFOVN(_file, _colour) \ - if (colour_terminal ()) \ + if (colour_terminal ()) \ fprintf (_file, " " _colour "*" EINFO_NORMAL " "); \ else \ fprintf (_file, " * "); \ retval += _eindent (_file); \ { \ - va_list _ap; \ - va_copy (_ap, ap); \ - retval += vfprintf (_file, fmt, _ap) + 3; \ - va_end (_ap); \ + va_list _ap; \ + va_copy (_ap, ap); \ + retval += vfprintf (_file, fmt, _ap) + 3; \ + va_end (_ap); \ } \ if (colour_terminal ()) \ fprintf (_file, "\033[K"); static int _einfovn (const char *fmt, va_list ap) { - int retval = 0; + int retval = 0; - EINFOVN (stdout, EINFO_GOOD); - return (retval); + EINFOVN (stdout, EINFO_GOOD); + return (retval); } static int _ewarnvn (const char *fmt, va_list ap) { - int retval = 0; + int retval = 0; - EINFOVN (stdout, EINFO_WARN); - return (retval); + EINFOVN (stdout, EINFO_WARN); + return (retval); } static int _eerrorvn (const char *fmt, va_list ap) { - int retval = 0; + int retval = 0; - EINFOVN (stderr, EINFO_BAD); - return (retval); + EINFOVN (stderr, EINFO_BAD); + return (retval); } int einfon (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt || is_env ("RC_QUIET", "yes")) - return (0); + if (! fmt || is_env ("RC_QUIET", "yes")) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("einfon", 0, fmt, ap))) - retval = _einfovn (fmt, ap); - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("einfon", 0, fmt, ap))) + retval = _einfovn (fmt, ap); + va_end (ap); - return (retval); + return (retval); } int ewarnn (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt || is_env ("RC_QUIET", "yes")) - return (0); + if (! fmt || is_env ("RC_QUIET", "yes")) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("ewarnn", 0, fmt, ap))) - retval = _ewarnvn (fmt, ap); - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("ewarnn", 0, fmt, ap))) + retval = _ewarnvn (fmt, ap); + va_end (ap); - return (retval); + return (retval); } int eerrorn (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - va_start (ap, fmt); - if (! (retval = ebuffer ("eerrorn", 0, fmt, ap))) - retval = _eerrorvn (fmt, ap); - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("eerrorn", 0, fmt, ap))) + retval = _eerrorvn (fmt, ap); + va_end (ap); - return (retval); + return (retval); } int einfo (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt || is_env ("RC_QUIET", "yes")) - return (0); + if (! fmt || is_env ("RC_QUIET", "yes")) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("einfo", 0, fmt, ap))) - { - retval = _einfovn (fmt, ap); - retval += printf ("\n"); - } - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("einfo", 0, fmt, ap))) { + retval = _einfovn (fmt, ap); + retval += printf ("\n"); + } + va_end (ap); - return (retval); + return (retval); } int ewarn (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt || is_env ("RC_QUIET", "yes")) - return (0); + if (! fmt || is_env ("RC_QUIET", "yes")) + return (0); - va_start (ap, fmt); - elog (LOG_WARNING, fmt, ap); - if (! (retval = ebuffer ("ewarn", 0, fmt, ap))) - { - retval = _ewarnvn (fmt, ap); - retval += printf ("\n"); - } - va_end (ap); + va_start (ap, fmt); + elog (LOG_WARNING, fmt, ap); + if (! (retval = ebuffer ("ewarn", 0, fmt, ap))) { + retval = _ewarnvn (fmt, ap); + retval += printf ("\n"); + } + va_end (ap); - return (retval); + return (retval); } void ewarnx (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (fmt && ! is_env ("RC_QUIET", "yes")) - { - va_start (ap, fmt); - elog (LOG_WARNING, fmt, ap); - retval = _ewarnvn (fmt, ap); - va_end (ap); - retval += printf ("\n"); - } - exit (EXIT_FAILURE); + if (fmt && ! is_env ("RC_QUIET", "yes")) { + va_start (ap, fmt); + elog (LOG_WARNING, fmt, ap); + retval = _ewarnvn (fmt, ap); + va_end (ap); + retval += printf ("\n"); + } + exit (EXIT_FAILURE); } int eerror (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - elog (LOG_ERR, fmt, ap); - retval = _eerrorvn (fmt, ap); - va_end (ap); - retval += fprintf (stderr, "\n"); + va_start (ap, fmt); + elog (LOG_ERR, fmt, ap); + retval = _eerrorvn (fmt, ap); + va_end (ap); + retval += fprintf (stderr, "\n"); - return (retval); + return (retval); } void eerrorx (const char *fmt, ...) { - va_list ap; + va_list ap; - if (fmt) - { - va_start (ap, fmt); - elog (LOG_ERR, fmt, ap); - _eerrorvn (fmt, ap); - va_end (ap); - printf ("\n"); - } - exit (EXIT_FAILURE); + if (fmt) { + va_start (ap, fmt); + elog (LOG_ERR, fmt, ap); + _eerrorvn (fmt, ap); + va_end (ap); + printf ("\n"); + } + exit (EXIT_FAILURE); } int ebegin (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - if (! fmt || is_env ("RC_QUIET", "yes")) - return (0); + if (! fmt || is_env ("RC_QUIET", "yes")) + return (0); - va_start (ap, fmt); - if ((retval = ebuffer ("ebegin", 0, fmt, ap))) - { - va_end (ap); - return (retval); - } + va_start (ap, fmt); + if ((retval = ebuffer ("ebegin", 0, fmt, ap))) { + va_end (ap); + return (retval); + } - retval = _einfovn (fmt, ap); - va_end (ap); - retval += printf (" ..."); - if (colour_terminal ()) - retval += printf ("\n"); + retval = _einfovn (fmt, ap); + va_end (ap); + retval += printf (" ..."); + if (colour_terminal ()) + retval += printf ("\n"); - return (retval); + return (retval); } static void _eend (int col, einfo_color_t color, const char *msg) { - FILE *fp = stdout; - int i; - int cols; - - if (! msg) - return; - - if (color == einfo_bad) - fp = stderr; - - cols = get_term_columns () - (strlen (msg) + 6); - - if (cols > 0 && colour_terminal ()) - { - fprintf (fp, "\033[A\033[%dC %s[ ", cols, EINFO_BRACKET); - switch (color) - { - case einfo_good: - fprintf (fp, EINFO_GOOD); - break; - case einfo_warn: - fprintf (fp, EINFO_WARN); - break; - case einfo_bad: - fprintf (fp, EINFO_BAD); - break; - case einfo_hilite: - fprintf (fp, EINFO_HILITE); - break; - case einfo_bracket: - fprintf (fp, EINFO_BRACKET); - break; - case einfo_normal: - fprintf (fp, EINFO_NORMAL); - break; - } - fprintf (fp, "%s%s ]%s\n", msg, EINFO_BRACKET, EINFO_NORMAL); - } - else - { - for (i = -1; i < cols - col; i++) - fprintf (fp, " "); - fprintf (fp, "[ %s ]\n", msg); - } + FILE *fp = stdout; + int i; + int cols; + + if (! msg) + return; + + if (color == einfo_bad) + fp = stderr; + + cols = get_term_columns () - (strlen (msg) + 6); + + if (cols > 0 && colour_terminal ()) { + fprintf (fp, "\033[A\033[%dC %s[ ", cols, EINFO_BRACKET); + switch (color) { + case einfo_good: + fprintf (fp, EINFO_GOOD); + break; + case einfo_warn: + fprintf (fp, EINFO_WARN); + break; + case einfo_bad: + fprintf (fp, EINFO_BAD); + break; + case einfo_hilite: + fprintf (fp, EINFO_HILITE); + break; + case einfo_bracket: + fprintf (fp, EINFO_BRACKET); + break; + case einfo_normal: + fprintf (fp, EINFO_NORMAL); + break; + } + fprintf (fp, "%s%s ]%s\n", msg, EINFO_BRACKET, EINFO_NORMAL); + } else { + for (i = -1; i < cols - col; i++) + fprintf (fp, " "); + fprintf (fp, "[ %s ]\n", msg); + } } static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap) { - int col = 0; - FILE *fp; - va_list apc; - int eb; - - if (fmt) - { - va_copy (apc, ap); - eb = ebuffer (cmd, retval, fmt, apc); - va_end (apc); - if (eb) - return (retval); - } - - if (fmt && retval != 0) - { - va_copy (apc, ap); - if (strcmp (cmd, "ewend") == 0) - { - col = _ewarnvn (fmt, apc); - fp = stdout; - } - else - { - col = _eerrorvn (fmt, apc); - fp = stderr; - } - va_end (apc); - if (colour_terminal ()) - fprintf (fp, "\n"); - } - - _eend (col, retval == 0 ? einfo_good : einfo_bad, retval == 0 ? OK : NOT_OK); - return (retval); + int col = 0; + FILE *fp; + va_list apc; + int eb; + + if (fmt) { + va_copy (apc, ap); + eb = ebuffer (cmd, retval, fmt, apc); + va_end (apc); + if (eb) + return (retval); + } + + if (fmt && retval != 0) { + va_copy (apc, ap); + if (strcmp (cmd, "ewend") == 0) { + col = _ewarnvn (fmt, apc); + fp = stdout; + } else { + col = _eerrorvn (fmt, apc); + fp = stderr; + } + va_end (apc); + if (colour_terminal ()) + fprintf (fp, "\n"); + } + + _eend (col, retval == 0 ? einfo_good : einfo_bad, retval == 0 ? OK : NOT_OK); + return (retval); } int eend (int retval, const char *fmt, ...) { - va_list ap; + va_list ap; - if (is_env ("RC_QUIET", "yes")) - return (retval); + if (is_env ("RC_QUIET", "yes")) + return (retval); - va_start (ap, fmt); - _do_eend ("eend", retval, fmt, ap); - va_end (ap); + va_start (ap, fmt); + _do_eend ("eend", retval, fmt, ap); + va_end (ap); - return (retval); + return (retval); } int ewend (int retval, const char *fmt, ...) { - va_list ap; + va_list ap; - if (is_env ("RC_QUIET", "yes")) - return (retval); + if (is_env ("RC_QUIET", "yes")) + return (retval); - va_start (ap, fmt); - _do_eend ("ewend", retval, fmt, ap); - va_end (ap); + va_start (ap, fmt); + _do_eend ("ewend", retval, fmt, ap); + va_end (ap); - return (retval); + return (retval); } void ebracket (int col, einfo_color_t color, const char *msg) { - _eend (col, color, msg); + _eend (col, color, msg); } void eindent (void) { - char *env = getenv ("RC_EINDENT"); - int amount = 0; - char num[10]; + char *env = getenv ("RC_EINDENT"); + int amount = 0; + char num[10]; - if (ebuffer ("eindent", 0, NULL, NULL)) - return; + if (ebuffer ("eindent", 0, NULL, NULL)) + return; - if (env) - { - errno = 0; - amount = strtol (env, NULL, 0); - if (errno != 0) - amount = 0; - } + if (env) { + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0) + amount = 0; + } - amount += INDENT_WIDTH; - if (amount > INDENT_MAX) - amount = INDENT_MAX; + amount += INDENT_WIDTH; + if (amount > INDENT_MAX) + amount = INDENT_MAX; - snprintf (num, 10, "%08d", amount); - setenv ("RC_EINDENT", num, 1); + snprintf (num, 10, "%08d", amount); + setenv ("RC_EINDENT", num, 1); } void eoutdent (void) { - char *env = getenv ("RC_EINDENT"); - int amount = 0; - char num[10]; + char *env = getenv ("RC_EINDENT"); + int amount = 0; + char num[10]; - if (ebuffer ("eoutdent", 0, NULL, NULL)) - return; + if (ebuffer ("eoutdent", 0, NULL, NULL)) + return; - if (! env) - return; + if (! env) + return; - errno = 0; - amount = strtol (env, NULL, 0); - if (errno != 0) - amount = 0; - else - amount -= INDENT_WIDTH; + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0) + amount = 0; + else + amount -= INDENT_WIDTH; - if (amount <= 0) - unsetenv ("RC_EINDENT"); - else - { - snprintf (num, 10, "%08d", amount); - setenv ("RC_EINDENT", num, 1); - } + if (amount <= 0) + unsetenv ("RC_EINDENT"); + else { + snprintf (num, 10, "%08d", amount); + setenv ("RC_EINDENT", num, 1); + } } int einfovn (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("einfovn", 0, fmt, ap))) - retval = _einfovn (fmt, ap); - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("einfovn", 0, fmt, ap))) + retval = _einfovn (fmt, ap); + va_end (ap); - return (retval); + return (retval); } int ewarnvn (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("ewarnvn", 0, fmt, ap))) - retval = _ewarnvn (fmt, ap); - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("ewarnvn", 0, fmt, ap))) + retval = _ewarnvn (fmt, ap); + va_end (ap); - return (retval); + return (retval); } int einfov (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("einfov", 0, fmt, ap))) - { - retval = _einfovn (fmt, ap); - retval += printf ("\n"); - } - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("einfov", 0, fmt, ap))) { + retval = _einfovn (fmt, ap); + retval += printf ("\n"); + } + va_end (ap); - return (retval); + return (retval); } int ewarnv (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("ewarnv", 0, fmt, ap))) - { - retval = _ewarnvn (fmt, ap); - retval += printf ("\n"); - } - va_end (ap); - retval += printf ("\n"); + va_start (ap, fmt); + if (! (retval = ebuffer ("ewarnv", 0, fmt, ap))) { + retval = _ewarnvn (fmt, ap); + retval += printf ("\n"); + } + va_end (ap); + retval += printf ("\n"); - return (retval); + return (retval); } int ebeginv (const char *fmt, ...) { - int retval; - va_list ap; + int retval; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - if (! fmt) - return (0); + if (! fmt) + return (0); - va_start (ap, fmt); - if (! (retval = ebuffer ("ebeginv", 0, fmt, ap))) - { - retval = _einfovn (fmt, ap); - retval += printf (" ..."); - if (colour_terminal ()) - retval += printf ("\n"); - } - va_end (ap); + va_start (ap, fmt); + if (! (retval = ebuffer ("ebeginv", 0, fmt, ap))) { + retval = _einfovn (fmt, ap); + retval += printf (" ..."); + if (colour_terminal ()) + retval += printf ("\n"); + } + va_end (ap); - return (retval); + return (retval); } int eendv (int retval, const char *fmt, ...) { - va_list ap; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - va_start (ap, fmt); - _do_eend ("eendv", retval, fmt, ap); - va_end (ap); + va_start (ap, fmt); + _do_eend ("eendv", retval, fmt, ap); + va_end (ap); - return (retval); + return (retval); } int ewendv (int retval, const char *fmt, ...) { - va_list ap; + va_list ap; - CHECK_VERBOSE; + CHECK_VERBOSE; - va_start (ap, fmt); - _do_eend ("ewendv", retval, fmt, ap); - va_end (ap); + va_start (ap, fmt); + _do_eend ("ewendv", retval, fmt, ap); + va_end (ap); - return (retval); + return (retval); } void eindentv (void) { - if (is_env ("RC_VERBOSE", "yes")) - eindent (); + if (is_env ("RC_VERBOSE", "yes")) + eindent (); } void eoutdentv (void) { - if (is_env ("RC_VERBOSE", "yes")) - eoutdent (); + if (is_env ("RC_VERBOSE", "yes")) + eoutdent (); } diff --git a/src/librc-daemon.c b/src/librc-daemon.c index 3add7e4c..240ca6ed 100644 --- a/src/librc-daemon.c +++ b/src/librc-daemon.c @@ -9,7 +9,7 @@ #include #if defined(__DragonFly__) || defined(__FreeBSD__) || \ - defined(__NetBSD__) || defined (__OpenBSD__) + defined(__NetBSD__) || defined (__OpenBSD__) #include #include #include @@ -37,150 +37,143 @@ #if defined(__linux__) static bool pid_is_cmd (pid_t pid, const char *cmd) { - char buffer[32]; - FILE *fp; - int c; + 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); - } + if (c != '(') { + fclose(fp); + return (false); + } - while ((c = getc (fp)) != EOF && c == *cmd) - 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 *exec) { - char cmdline[32]; - char buffer[PATH_MAX]; - char *p; - int fd = -1; - int r; - - snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); - memset (buffer, 0, sizeof (buffer)); - if (readlink (cmdline, buffer, sizeof (buffer)) != -1) - { - if (strcmp (exec, 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) - { - *p = 0; - if (strcmp (buffer, exec) == 0) - return (true); - } - } - } - - 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); - - if (r == -1) - return 0; - - buffer[r] = 0; - return (strcmp (exec, buffer) == 0 ? true : false); + char cmdline[32]; + char buffer[PATH_MAX]; + char *p; + int fd = -1; + int r; + + snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); + memset (buffer, 0, sizeof (buffer)); + if (readlink (cmdline, buffer, sizeof (buffer)) != -1) { + if (strcmp (exec, 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) { + *p = 0; + if (strcmp (buffer, exec) == 0) + return (true); + } + } + } + + 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); + + if (r == -1) + return 0; + + buffer[r] = 0; + return (strcmp (exec, buffer) == 0 ? true : false); } pid_t *rc_find_pids (const char *exec, const char *cmd, - uid_t uid, pid_t pid) + uid_t uid, pid_t pid) { - DIR *procdir; - struct dirent *entry; - int npids = 0; - int foundany = false; - pid_t p; - pid_t *pids = NULL; - char buffer[PATH_MAX]; - struct stat sb; - pid_t runscript_pid = 0; - char *pp; - - if ((procdir = opendir ("/proc")) == NULL) - eerrorx ("opendir `/proc': %s", strerror (errno)); - - /* - We never match RC_RUNSCRIPT_PID if present so we avoid the below - scenario - - /etc/init.d/ntpd stop does - start-stop-daemon --stop --name ntpd - catching /etc/init.d/ntpd stop - - nasty - */ - - if ((pp = getenv ("RC_RUNSCRIPT_PID"))) - { - if (sscanf (pp, "%d", &runscript_pid) != 1) - runscript_pid = 0; - } - - while ((entry = readdir (procdir)) != NULL) - { - if (sscanf (entry->d_name, "%d", &p) != 1) - continue; - foundany = true; - - if (runscript_pid != 0 && runscript_pid == p) - continue; - - if (pid != 0 && pid != p) - continue; - - if (uid) - { - snprintf (buffer, sizeof (buffer), "/proc/%d", pid); - if (stat (buffer, &sb) != 0 || sb.st_uid != uid) - continue; - } - - if (cmd && ! pid_is_cmd (p, cmd)) - continue; - - if (exec && ! cmd && ! pid_is_exec (p, exec)) - continue; - - pids = realloc (pids, sizeof (pid_t) * (npids + 2)); - if (! pids) - eerrorx ("memory exhausted"); - - pids[npids] = p; - pids[npids + 1] = 0; - npids++; - } - closedir (procdir); - - if (! foundany) - eerrorx ("nothing in /proc"); - - return (pids); + DIR *procdir; + struct dirent *entry; + int npids = 0; + int foundany = false; + pid_t p; + pid_t *pids = NULL; + char buffer[PATH_MAX]; + struct stat sb; + pid_t runscript_pid = 0; + char *pp; + + if ((procdir = opendir ("/proc")) == NULL) + eerrorx ("opendir `/proc': %s", strerror (errno)); + + /* + We never match RC_RUNSCRIPT_PID if present so we avoid the below + scenario + + /etc/init.d/ntpd stop does + start-stop-daemon --stop --name ntpd + catching /etc/init.d/ntpd stop + + nasty + */ + + if ((pp = getenv ("RC_RUNSCRIPT_PID"))) { + if (sscanf (pp, "%d", &runscript_pid) != 1) + runscript_pid = 0; + } + + while ((entry = readdir (procdir)) != NULL) { + if (sscanf (entry->d_name, "%d", &p) != 1) + continue; + foundany = true; + + if (runscript_pid != 0 && runscript_pid == p) + continue; + + if (pid != 0 && pid != p) + continue; + + if (uid) { + snprintf (buffer, sizeof (buffer), "/proc/%d", pid); + if (stat (buffer, &sb) != 0 || sb.st_uid != uid) + continue; + } + + if (cmd && ! pid_is_cmd (p, cmd)) + continue; + + if (exec && ! cmd && ! pid_is_exec (p, exec)) + continue; + + pids = realloc (pids, sizeof (pid_t) * (npids + 2)); + if (! pids) + eerrorx ("memory exhausted"); + + pids[npids] = p; + pids[npids + 1] = 0; + npids++; + } + closedir (procdir); + + if (! foundany) + eerrorx ("nothing in /proc"); + + return (pids); } #elif defined(__DragonFly__) || defined(__FreeBSD__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) + defined(__NetBSD__) || defined(__OpenBSD__) # if defined(__DragonFly__) || defined(__FreeBSD__) # ifndef KERN_PROC_PROC @@ -200,63 +193,60 @@ pid_t *rc_find_pids (const char *exec, const char *cmd, # endif pid_t *rc_find_pids (const char *exec, const char *cmd, - uid_t uid, pid_t pid) + uid_t uid, pid_t pid) { - static kvm_t *kd = NULL; - char errbuf[_POSIX2_LINE_MAX]; - struct _KINFO_PROC *kp; - int i; - int processes = 0; - int argc = 0; - char **argv; - pid_t *pids = NULL; - int npids = 0; - - if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) - eerrorx ("kvm_open: %s", errbuf); + static kvm_t *kd = NULL; + char errbuf[_POSIX2_LINE_MAX]; + struct _KINFO_PROC *kp; + int i; + int processes = 0; + int argc = 0; + char **argv; + pid_t *pids = NULL; + int npids = 0; + + if ((kd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) + eerrorx ("kvm_open: %s", errbuf); #if defined(__DragonFly__) || defined( __FreeBSD__) - kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes); + kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes); #else - kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), - &processes); + kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), + &processes); #endif - for (i = 0; i < processes; i++) - { - pid_t p = _GET_KINFO_PID (kp[i]); - if (pid != 0 && pid != p) - continue; - - 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) - continue; - } - - if (exec && ! cmd) - { - if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv) - continue; - - if (strcmp (*argv, exec) != 0) - continue; - } - - pids = realloc (pids, sizeof (pid_t) * (npids + 2)); - if (! pids) - eerrorx ("memory exhausted"); - - pids[npids] = p; - pids[npids + 1] = 0; - npids++; - } - kvm_close(kd); - - return (pids); + for (i = 0; i < processes; i++) { + pid_t p = _GET_KINFO_PID (kp[i]); + if (pid != 0 && pid != p) + continue; + + 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) + continue; + } + + if (exec && ! cmd) { + if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv) + continue; + + if (strcmp (*argv, exec) != 0) + continue; + } + + pids = realloc (pids, sizeof (pid_t) * (npids + 2)); + if (! pids) + eerrorx ("memory exhausted"); + + pids[npids] = p; + pids[npids + 1] = 0; + npids++; + } + kvm_close(kd); + + return (pids); } #else @@ -264,349 +254,309 @@ pid_t *rc_find_pids (const char *exec, const char *cmd, #endif static bool _match_daemon (const char *path, const char *file, - const char *mexec, const char *mname, - const char *mpidfile) + const char *mexec, const char *mname, + const char *mpidfile) { - char buffer[RC_LINEBUFFER]; - char *ffile = rc_strcatpaths (path, file, (char *) NULL); - FILE *fp; - int lc = 0; - int m = 0; - - if (! rc_exists (ffile)) - { - free (ffile); - return (false); - } - - if ((fp = fopen (ffile, "r")) == NULL) - { - eerror ("fopen `%s': %s", ffile, strerror (errno)); - free (ffile); - return (false); - } - - if (! mname) - m += 10; - if (! mpidfile) - m += 100; - - memset (buffer, 0, sizeof (buffer)); - while ((fgets (buffer, RC_LINEBUFFER, fp))) - { - int lb = strlen (buffer) - 1; - if (buffer[lb] == '\n') - buffer[lb] = 0; - - if (strcmp (buffer, mexec) == 0) - m += 1; - else if (mname && strcmp (buffer, mname) == 0) - m += 10; - else if (mpidfile && strcmp (buffer, mpidfile) == 0) - m += 100; - - if (m == 111) - break; - - lc++; - if (lc > 5) - break; - } - fclose (fp); - free (ffile); - - return (m == 111 ? true : false); + char buffer[RC_LINEBUFFER]; + char *ffile = rc_strcatpaths (path, file, (char *) NULL); + FILE *fp; + int lc = 0; + int m = 0; + + if (! rc_exists (ffile)) { + free (ffile); + return (false); + } + + if ((fp = fopen (ffile, "r")) == NULL) { + eerror ("fopen `%s': %s", ffile, strerror (errno)); + free (ffile); + return (false); + } + + if (! mname) + m += 10; + if (! mpidfile) + m += 100; + + memset (buffer, 0, sizeof (buffer)); + while ((fgets (buffer, RC_LINEBUFFER, fp))) { + int lb = strlen (buffer) - 1; + if (buffer[lb] == '\n') + buffer[lb] = 0; + + if (strcmp (buffer, mexec) == 0) + m += 1; + else if (mname && strcmp (buffer, mname) == 0) + m += 10; + else if (mpidfile && strcmp (buffer, mpidfile) == 0) + m += 100; + + if (m == 111) + break; + + lc++; + if (lc > 5) + break; + } + fclose (fp); + free (ffile); + + return (m == 111 ? true : false); } void rc_set_service_daemon (const char *service, const char *exec, - const char *name, const char *pidfile, - bool started) + const char *name, const char *pidfile, + bool started) { - char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), - (char *) NULL); - char **files = NULL; - char *file; - char *ffile = NULL; - int i; - char *mexec; - char *mname; - char *mpidfile; - int nfiles = 0; - - if (! exec && ! name && ! pidfile) - return; - - if (exec) - { - i = strlen (exec) + 6; - mexec = rc_xmalloc (sizeof (char *) * i); - snprintf (mexec, i, "exec=%s", exec); - } - else - mexec = strdup ("exec="); - - if (name) - { - i = strlen (name) + 6; - mname = rc_xmalloc (sizeof (char *) * i); - snprintf (mname, i, "name=%s", name); - } - else - mname = strdup ("name="); - - if (pidfile) - { - i = strlen (pidfile) + 9; - mpidfile = rc_xmalloc (sizeof (char *) * i); - snprintf (mpidfile, i, "pidfile=%s", pidfile); - } - else - mpidfile = strdup ("pidfile="); - - /* Regardless, erase any existing daemon info */ - if (rc_is_dir (dirpath)) - { - char *oldfile = NULL; - files = rc_ls_dir (NULL, dirpath, 0); - STRLIST_FOREACH (files, file, i) - { - ffile = rc_strcatpaths (dirpath, file, (char *) NULL); - nfiles++; - - if (! oldfile) - { - if (_match_daemon (dirpath, file, mexec, mname, mpidfile)) - { - unlink (ffile); - oldfile = ffile; - nfiles--; - } - } - else - { - rename (ffile, oldfile); - free (oldfile); - oldfile = ffile; - } - } - if (ffile) - free (ffile); - free (files); - } - - /* Now store our daemon info */ - if (started) - { - char buffer[10]; - FILE *fp; - - if (! rc_is_dir (dirpath)) - if (mkdir (dirpath, 0755) != 0) - eerror ("mkdir `%s': %s", dirpath, strerror (errno)); - - snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1); - file = rc_strcatpaths (dirpath, buffer, (char *) NULL); - if ((fp = fopen (file, "w")) == NULL) - eerror ("fopen `%s': %s", file, strerror (errno)); - else - { - fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile); - fclose (fp); - } - free (file); - } - - free (mexec); - free (mname); - free (mpidfile); - free (dirpath); + char *dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), + (char *) NULL); + char **files = NULL; + char *file; + char *ffile = NULL; + int i; + char *mexec; + char *mname; + char *mpidfile; + int nfiles = 0; + + if (! exec && ! name && ! pidfile) + return; + + if (exec) { + i = strlen (exec) + 6; + mexec = rc_xmalloc (sizeof (char *) * i); + snprintf (mexec, i, "exec=%s", exec); + } else + mexec = strdup ("exec="); + + if (name) { + i = strlen (name) + 6; + mname = rc_xmalloc (sizeof (char *) * i); + snprintf (mname, i, "name=%s", name); + } else + mname = strdup ("name="); + + if (pidfile) { + i = strlen (pidfile) + 9; + mpidfile = rc_xmalloc (sizeof (char *) * i); + snprintf (mpidfile, i, "pidfile=%s", pidfile); + } else + mpidfile = strdup ("pidfile="); + + /* Regardless, erase any existing daemon info */ + if (rc_is_dir (dirpath)) { + char *oldfile = NULL; + files = rc_ls_dir (NULL, dirpath, 0); + STRLIST_FOREACH (files, file, i) { + ffile = rc_strcatpaths (dirpath, file, (char *) NULL); + nfiles++; + + if (! oldfile) { + if (_match_daemon (dirpath, file, mexec, mname, mpidfile)) { + unlink (ffile); + oldfile = ffile; + nfiles--; + } + } else { + rename (ffile, oldfile); + free (oldfile); + oldfile = ffile; + } + } + if (ffile) + free (ffile); + free (files); + } + + /* Now store our daemon info */ + if (started) { + char buffer[10]; + FILE *fp; + + if (! rc_is_dir (dirpath)) + if (mkdir (dirpath, 0755) != 0) + eerror ("mkdir `%s': %s", dirpath, strerror (errno)); + + snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1); + file = rc_strcatpaths (dirpath, buffer, (char *) NULL); + if ((fp = fopen (file, "w")) == NULL) + eerror ("fopen `%s': %s", file, strerror (errno)); + else { + fprintf (fp, "%s\n%s\n%s\n", mexec, mname, mpidfile); + fclose (fp); + } + free (file); + } + + free (mexec); + free (mname); + free (mpidfile); + free (dirpath); } bool rc_service_started_daemon (const char *service, const char *exec, - int indx) + int indx) { - char *dirpath; - char *file; - int i; - char *mexec; - bool retval = false; - - if (! service || ! exec) - return (false); - - dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), - (char *) NULL); - if (! rc_is_dir (dirpath)) - { - free (dirpath); - return (false); - } - - i = strlen (exec) + 6; - mexec = rc_xmalloc (sizeof (char *) * i); - snprintf (mexec, i, "exec=%s", exec); - - if (indx > 0) - { - int len = sizeof (char *) * 10; - file = rc_xmalloc (len); - snprintf (file, len, "%03d", indx); - retval = _match_daemon (dirpath, file, mexec, NULL, NULL); - free (file); - } - else - { - char **files = rc_ls_dir (NULL, dirpath, 0); - STRLIST_FOREACH (files, file, i) - { - retval = _match_daemon (dirpath, file, mexec, NULL, NULL); - if (retval) - break; - } - free (files); - } - - free (mexec); - return (retval); + char *dirpath; + char *file; + int i; + char *mexec; + bool retval = false; + + if (! service || ! exec) + return (false); + + dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), + (char *) NULL); + if (! rc_is_dir (dirpath)) { + free (dirpath); + return (false); + } + + i = strlen (exec) + 6; + mexec = rc_xmalloc (sizeof (char *) * i); + snprintf (mexec, i, "exec=%s", exec); + + if (indx > 0) { + int len = sizeof (char *) * 10; + file = rc_xmalloc (len); + snprintf (file, len, "%03d", indx); + retval = _match_daemon (dirpath, file, mexec, NULL, NULL); + free (file); + } else { + char **files = rc_ls_dir (NULL, dirpath, 0); + STRLIST_FOREACH (files, file, i) { + retval = _match_daemon (dirpath, file, mexec, NULL, NULL); + if (retval) + break; + } + free (files); + } + + free (mexec); + return (retval); } bool rc_service_daemons_crashed (const char *service) { - char *dirpath; - char **files; - char *file; - char *path; - int i; - FILE *fp; - char buffer[RC_LINEBUFFER]; - char *exec = NULL; - char *name = NULL; - char *pidfile = NULL; - pid_t pid = 0; - pid_t *pids = NULL; - char *p; - char *token; - bool retval = false; - - if (! service) - return (false); - - dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), - (char *) NULL); - if (! rc_is_dir (dirpath)) - { - free (dirpath); - return (false); - } - - memset (buffer, 0, sizeof (buffer)); - files = rc_ls_dir (NULL, dirpath, 0); - STRLIST_FOREACH (files, file, i) - { - path = rc_strcatpaths (dirpath, file, (char *) NULL); - fp = fopen (path, "r"); - free (path); - if (! fp) - { - eerror ("fopen `%s': %s", file, strerror (errno)); - continue; - } - - while ((fgets (buffer, RC_LINEBUFFER, fp))) - { - int lb = strlen (buffer) - 1; - if (buffer[lb] == '\n') - buffer[lb] = 0; - - p = buffer; - if ((token = strsep (&p, "=")) == NULL || ! p) - continue; - - if (strlen (p) == 0) - continue; - - if (strcmp (token, "exec") == 0) - { - if (exec) - free (exec); - exec = strdup (p); - } - else if (strcmp (token, "name") == 0) - { - if (name) - free (name); - name = strdup (p); - } - else if (strcmp (token, "pidfile") == 0) - { - if (pidfile) - free (pidfile); - pidfile = strdup (p); - } - } - fclose (fp); - - pid = 0; - if (pidfile) - { - if (! rc_exists (pidfile)) - { - retval = true; - break; - } - - if ((fp = fopen (pidfile, "r")) == NULL) - { - eerror ("fopen `%s': %s", pidfile, strerror (errno)); - retval = true; - break; - } - - if (fscanf (fp, "%d", &pid) != 1) - { - eerror ("no pid found in `%s'", pidfile); - fclose (fp); - retval = true; - break; - } - - fclose (fp); - free (pidfile); - pidfile = NULL; - } - - if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) - { - retval = true; - break; - } - free (pids); - - if (exec) - { - free (exec); - exec = NULL; - } - if (name) - { - free (name); - name = NULL; - } - } - - if (exec) - { - free (exec); - exec = NULL; - } - if (name) - { - free (name); - name = NULL; - } - - free (dirpath); - rc_strlist_free (files); - - return (retval); + char *dirpath; + char **files; + char *file; + char *path; + int i; + FILE *fp; + char buffer[RC_LINEBUFFER]; + char *exec = NULL; + char *name = NULL; + char *pidfile = NULL; + pid_t pid = 0; + pid_t *pids = NULL; + char *p; + char *token; + bool retval = false; + + if (! service) + return (false); + + dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename (service), + (char *) NULL); + if (! rc_is_dir (dirpath)) { + free (dirpath); + return (false); + } + + memset (buffer, 0, sizeof (buffer)); + files = rc_ls_dir (NULL, dirpath, 0); + STRLIST_FOREACH (files, file, i) { + path = rc_strcatpaths (dirpath, file, (char *) NULL); + fp = fopen (path, "r"); + free (path); + if (! fp) { + eerror ("fopen `%s': %s", file, strerror (errno)); + continue; + } + + while ((fgets (buffer, RC_LINEBUFFER, fp))) { + int lb = strlen (buffer) - 1; + if (buffer[lb] == '\n') + buffer[lb] = 0; + + p = buffer; + if ((token = strsep (&p, "=")) == NULL || ! p) + continue; + + if (strlen (p) == 0) + continue; + + if (strcmp (token, "exec") == 0) { + if (exec) + free (exec); + exec = strdup (p); + } else if (strcmp (token, "name") == 0) { + if (name) + free (name); + name = strdup (p); + } else if (strcmp (token, "pidfile") == 0) { + if (pidfile) + free (pidfile); + pidfile = strdup (p); + } + } + fclose (fp); + + pid = 0; + if (pidfile) { + if (! rc_exists (pidfile)) { + retval = true; + break; + } + + if ((fp = fopen (pidfile, "r")) == NULL) { + eerror ("fopen `%s': %s", pidfile, strerror (errno)); + retval = true; + break; + } + + if (fscanf (fp, "%d", &pid) != 1) { + eerror ("no pid found in `%s'", pidfile); + fclose (fp); + retval = true; + break; + } + + fclose (fp); + free (pidfile); + pidfile = NULL; + } + + if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) { + retval = true; + break; + } + free (pids); + + if (exec) { + free (exec); + exec = NULL; + } + if (name) { + free (name); + name = NULL; + } + } + + if (exec) { + free (exec); + exec = NULL; + } + if (name) { + free (name); + name = NULL; + } + + free (dirpath); + rc_strlist_free (files); + + return (retval); } diff --git a/src/librc-misc.c b/src/librc-misc.c index 39b003ba..55a9ac19 100644 --- a/src/librc-misc.c +++ b/src/librc-misc.c @@ -38,715 +38,666 @@ void *rc_xcalloc (size_t n, size_t size) { - void *value = calloc (n, size); + void *value = calloc (n, size); - if (value) - return value; + if (value) + return value; - ERRX + ERRX } void *rc_xmalloc (size_t size) { - void *value = malloc (size); + void *value = malloc (size); - if (value) - return (value); + if (value) + return (value); - ERRX + ERRX } void *rc_xrealloc (void *ptr, size_t size) { - void *value = realloc (ptr, size); + void *value = realloc (ptr, size); - if (value) - return (value); + if (value) + return (value); - ERRX + ERRX } char *rc_xstrdup (const char *str) { - char *value; + char *value; - if (! str) - return (NULL); + if (! str) + return (NULL); - value = strdup (str); + value = strdup (str); - if (value) - return (value); + if (value) + return (value); - ERRX + ERRX } bool rc_is_env (const char *var, const char *val) { - char *v; + char *v; - if (! var) - return (false); + if (! var) + return (false); - v = getenv (var); - if (! v) - return (val == NULL ? true : false); + v = getenv (var); + if (! v) + return (val == NULL ? true : false); - return (strcasecmp (v, val) == 0 ? true : false); + return (strcasecmp (v, val) == 0 ? true : false); } char *rc_strcatpaths (const char *path1, const char *paths, ...) { - va_list ap; - int length; - int i; - char *p; - char *path; - char *pathp; - - if (! path1 || ! paths) - return (NULL); - - length = strlen (path1) + strlen (paths) + 3; - i = 0; - va_start (ap, paths); - while ((p = va_arg (ap, char *)) != NULL) - length += strlen (p) + 1; - va_end (ap); - - path = rc_xmalloc (length); - memset (path, 0, length); - memcpy (path, path1, strlen (path1)); - pathp = path + strlen (path1) - 1; - if (*pathp != '/') - { - pathp++; - *pathp++ = '/'; - } - else - pathp++; - memcpy (pathp, paths, strlen (paths)); - pathp += strlen (paths); - - va_start (ap, paths); - while ((p = va_arg (ap, char *)) != NULL) - { - if (*pathp != '/') - *pathp++ = '/'; - i = strlen (p); - memcpy (pathp, p, i); - pathp += i; - } - va_end (ap); - - *pathp++ = 0; - - return (path); + va_list ap; + int length; + int i; + char *p; + char *path; + char *pathp; + + if (! path1 || ! paths) + return (NULL); + + length = strlen (path1) + strlen (paths) + 3; + i = 0; + va_start (ap, paths); + while ((p = va_arg (ap, char *)) != NULL) + length += strlen (p) + 1; + va_end (ap); + + path = rc_xmalloc (length); + memset (path, 0, length); + memcpy (path, path1, strlen (path1)); + pathp = path + strlen (path1) - 1; + if (*pathp != '/') { + pathp++; + *pathp++ = '/'; + } + else + pathp++; + memcpy (pathp, paths, strlen (paths)); + pathp += strlen (paths); + + va_start (ap, paths); + while ((p = va_arg (ap, char *)) != NULL) { + if (*pathp != '/') + *pathp++ = '/'; + i = strlen (p); + memcpy (pathp, p, i); + pathp += i; + } + va_end (ap); + + *pathp++ = 0; + + return (path); } bool rc_exists (const char *pathname) { - struct stat buf; + struct stat buf; - if (! pathname) - return (false); + if (! pathname) + return (false); - if (stat (pathname, &buf) == 0) - return (true); + if (stat (pathname, &buf) == 0) + return (true); - errno = 0; - return (false); + errno = 0; + return (false); } bool rc_is_file (const char *pathname) { - struct stat buf; + struct stat buf; - if (! pathname) - return (false); + if (! pathname) + return (false); - if (stat (pathname, &buf) == 0) - return (S_ISREG (buf.st_mode)); + if (stat (pathname, &buf) == 0) + return (S_ISREG (buf.st_mode)); - errno = 0; - return (false); + errno = 0; + return (false); } bool rc_is_dir (const char *pathname) { - struct stat buf; + struct stat buf; - if (! pathname) - return (false); + if (! pathname) + return (false); - if (stat (pathname, &buf) == 0) - return (S_ISDIR (buf.st_mode)); + if (stat (pathname, &buf) == 0) + return (S_ISDIR (buf.st_mode)); - errno = 0; - return (false); + errno = 0; + return (false); } bool rc_is_link (const char *pathname) { - struct stat buf; + struct stat buf; - if (! pathname) - return (false); + if (! pathname) + return (false); - if (lstat (pathname, &buf) == 0) - return (S_ISLNK (buf.st_mode)); + if (lstat (pathname, &buf) == 0) + return (S_ISLNK (buf.st_mode)); - errno = 0; - return (false); + errno = 0; + return (false); } bool rc_is_exec (const char *pathname) { - struct stat buf; + struct stat buf; - if (! pathname) - return (false); + if (! pathname) + return (false); - if (lstat (pathname, &buf) == 0) - return (buf.st_mode & S_IXUGO); + if (lstat (pathname, &buf) == 0) + return (buf.st_mode & S_IXUGO); - errno = 0; - return (false); + errno = 0; + return (false); } char **rc_ls_dir (char **list, const char *dir, int options) { - DIR *dp; - struct dirent *d; - - if (! dir) - return (list); - - if ((dp = opendir (dir)) == NULL) - { - eerror ("failed to opendir `%s': %s", dir, strerror (errno)); - return (list); - } - - errno = 0; - while (((d = readdir (dp)) != NULL) && errno == 0) - { - if (d->d_name[0] != '.') - { - if (options & RC_LS_INITD) - { - int l = strlen (d->d_name); - char *init = rc_strcatpaths (RC_INITDIR, d->d_name, - (char *) NULL); - bool ok = rc_exists (init); - free (init); - if (! ok) - continue; - - /* .sh files are not init scripts */ - if (l > 2 && d->d_name[l - 3] == '.' && - d->d_name[l - 2] == 's' && - d->d_name[l - 1] == 'h') - continue; - } - list = rc_strlist_addsort (list, d->d_name); - } - } - closedir (dp); - - if (errno != 0) - { - eerror ("failed to readdir `%s': %s", dir, strerror (errno)); - rc_strlist_free (list); - return (NULL); - } - - return (list); + DIR *dp; + struct dirent *d; + + if (! dir) + return (list); + + if ((dp = opendir (dir)) == NULL) { + eerror ("failed to opendir `%s': %s", dir, strerror (errno)); + return (list); + } + + errno = 0; + while (((d = readdir (dp)) != NULL) && errno == 0) { + if (d->d_name[0] != '.') { + if (options & RC_LS_INITD) { + int l = strlen (d->d_name); + char *init = rc_strcatpaths (RC_INITDIR, d->d_name, + (char *) NULL); + bool ok = rc_exists (init); + free (init); + if (! ok) + continue; + + /* .sh files are not init scripts */ + if (l > 2 && d->d_name[l - 3] == '.' && + d->d_name[l - 2] == 's' && + d->d_name[l - 1] == 'h') + continue; + } + list = rc_strlist_addsort (list, d->d_name); + } + } + closedir (dp); + + if (errno != 0) { + eerror ("failed to readdir `%s': %s", dir, strerror (errno)); + rc_strlist_free (list); + return (NULL); + } + + return (list); } bool rc_rm_dir (const char *pathname, bool top) { - DIR *dp; - struct dirent *d; - - if (! pathname) - return (false); - - if ((dp = opendir (pathname)) == NULL) - { - eerror ("failed to opendir `%s': %s", pathname, strerror (errno)); - return (false); - } - - errno = 0; - while (((d = readdir (dp)) != NULL) && errno == 0) - { - if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) - { - char *tmp = rc_strcatpaths (pathname, d->d_name, (char *) NULL); - if (d->d_type == DT_DIR) - { - if (! rc_rm_dir (tmp, true)) - { - free (tmp); - closedir (dp); - return (false); - } - } - else - { - if (unlink (tmp)) - { - eerror ("failed to unlink `%s': %s", tmp, strerror (errno)); - free (tmp); - closedir (dp); - return (false); - } - } - free (tmp); - } - } - if (errno != 0) - eerror ("failed to readdir `%s': %s", pathname, strerror (errno)); - closedir (dp); - - if (top && rmdir (pathname) != 0) - { - eerror ("failed to rmdir `%s': %s", pathname, strerror (errno)); - return false; - } - - return (true); + DIR *dp; + struct dirent *d; + + if (! pathname) + return (false); + + if ((dp = opendir (pathname)) == NULL) { + eerror ("failed to opendir `%s': %s", pathname, strerror (errno)); + return (false); + } + + errno = 0; + while (((d = readdir (dp)) != NULL) && errno == 0) { + if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) { + char *tmp = rc_strcatpaths (pathname, d->d_name, (char *) NULL); + if (d->d_type == DT_DIR) { + if (! rc_rm_dir (tmp, true)) + { + free (tmp); + closedir (dp); + return (false); + } + } else { + if (unlink (tmp)) { + eerror ("failed to unlink `%s': %s", tmp, strerror (errno)); + free (tmp); + closedir (dp); + return (false); + } + } + free (tmp); + } + } + if (errno != 0) + eerror ("failed to readdir `%s': %s", pathname, strerror (errno)); + closedir (dp); + + if (top && rmdir (pathname) != 0) { + eerror ("failed to rmdir `%s': %s", pathname, strerror (errno)); + return false; + } + + return (true); } char **rc_get_config (char **list, const char *file) { - FILE *fp; - char buffer[RC_LINEBUFFER]; - char *p; - char *token; - char *line; - char *linep; - char *linetok; - int i = 0; - bool replaced; - char *entry; - char *newline; - - if (! (fp = fopen (file, "r"))) - { - ewarn ("load_config_file `%s': %s", file, strerror (errno)); - return (list); - } - - while (fgets (buffer, RC_LINEBUFFER, fp)) - { - p = buffer; - - /* Strip leading spaces/tabs */ - while ((*p == ' ') || (*p == '\t')) - p++; - - if (! p || strlen (p) < 3 || p[0] == '#') - continue; - - /* Get entry */ - token = strsep (&p, "="); - if (! token) - continue; - - entry = rc_xstrdup (token); - - do - { - /* Bash variables are usually quoted */ - token = strsep (&p, "\"\'"); - } - while ((token) && (strlen (token) == 0)); - - /* Drop a newline if that's all we have */ - i = strlen (token) - 1; - if (token[i] == 10) - token[i] = 0; - - i = strlen (entry) + strlen (token) + 2; - newline = rc_xmalloc (i); - snprintf (newline, i, "%s=%s", entry, token); - - replaced = false; - /* In shells the last item takes precedence, so we need to remove - any prior values we may already have */ - STRLIST_FOREACH (list, line, i) - { - char *tmp = rc_xstrdup (line); - linep = tmp; - linetok = strsep (&linep, "="); - if (strcmp (linetok, entry) == 0) - { - /* We have a match now - to save time we directly replace it */ - free (list[i - 1]); - list[i - 1] = newline; - replaced = true; - free (tmp); - break; - } - free (tmp); - } - - if (! replaced) - { - list = rc_strlist_addsort (list, newline); - free (newline); - } - free (entry); - } - fclose (fp); - - return (list); + FILE *fp; + char buffer[RC_LINEBUFFER]; + char *p; + char *token; + char *line; + char *linep; + char *linetok; + int i = 0; + bool replaced; + char *entry; + char *newline; + + if (! (fp = fopen (file, "r"))) { + ewarn ("load_config_file `%s': %s", file, strerror (errno)); + return (list); + } + + while (fgets (buffer, RC_LINEBUFFER, fp)) { + p = buffer; + + /* Strip leading spaces/tabs */ + while ((*p == ' ') || (*p == '\t')) + p++; + + if (! p || strlen (p) < 3 || p[0] == '#') + continue; + + /* Get entry */ + token = strsep (&p, "="); + if (! token) + continue; + + entry = rc_xstrdup (token); + + do { + /* Bash variables are usually quoted */ + token = strsep (&p, "\"\'"); + } while ((token) && (strlen (token) == 0)); + + /* Drop a newline if that's all we have */ + i = strlen (token) - 1; + if (token[i] == 10) + token[i] = 0; + + i = strlen (entry) + strlen (token) + 2; + newline = rc_xmalloc (i); + snprintf (newline, i, "%s=%s", entry, token); + + replaced = false; + /* In shells the last item takes precedence, so we need to remove + any prior values we may already have */ + STRLIST_FOREACH (list, line, i) { + char *tmp = rc_xstrdup (line); + linep = tmp; + linetok = strsep (&linep, "="); + if (strcmp (linetok, entry) == 0) { + /* We have a match now - to save time we directly replace it */ + free (list[i - 1]); + list[i - 1] = newline; + replaced = true; + free (tmp); + break; + } + free (tmp); + } + + if (! replaced) { + list = rc_strlist_addsort (list, newline); + free (newline); + } + free (entry); + } + fclose (fp); + + return (list); } char *rc_get_config_entry (char **list, const char *entry) { - char *line; - int i; - char *p; - - STRLIST_FOREACH (list, line, i) - { - p = strchr (line, '='); - if (p && strncmp (entry, line, p - line) == 0) - return (p += 1); - } - - return (NULL); + char *line; + int i; + char *p; + + STRLIST_FOREACH (list, line, i) { + p = strchr (line, '='); + if (p && strncmp (entry, line, p - line) == 0) + return (p += 1); + } + + return (NULL); } char **rc_get_list (char **list, const char *file) { - FILE *fp; - char buffer[RC_LINEBUFFER]; - char *p; - char *token; - - if (! (fp = fopen (file, "r"))) - { - ewarn ("rc_get_list `%s': %s", file, strerror (errno)); - return (list); - } - - while (fgets (buffer, RC_LINEBUFFER, fp)) - { - p = buffer; - - /* Strip leading spaces/tabs */ - while ((*p == ' ') || (*p == '\t')) - p++; - - /* Get entry - we do not want comments */ - token = strsep (&p, "#"); - if (token && (strlen (token) > 1)) - { - /* Stip the newline if present */ - if (token[strlen (token) - 1] == '\n') - token[strlen (token) - 1] = 0; - - list = rc_strlist_add (list, token); - } - } - fclose (fp); - - return (list); + FILE *fp; + char buffer[RC_LINEBUFFER]; + char *p; + char *token; + + if (! (fp = fopen (file, "r"))) { + ewarn ("rc_get_list `%s': %s", file, strerror (errno)); + return (list); + } + + while (fgets (buffer, RC_LINEBUFFER, fp)) { + p = buffer; + + /* Strip leading spaces/tabs */ + while ((*p == ' ') || (*p == '\t')) + p++; + + /* Get entry - we do not want comments */ + token = strsep (&p, "#"); + if (token && (strlen (token) > 1)) { + /* Stip the newline if present */ + if (token[strlen (token) - 1] == '\n') + token[strlen (token) - 1] = 0; + + list = rc_strlist_add (list, token); + } + } + fclose (fp); + + return (list); } char **rc_filter_env (void) { - char **env = NULL; - char **whitelist = NULL; - char *env_name = NULL; - char **profile = NULL; - int count = 0; - bool got_path = false; - char *env_var; - int env_len; - char *p; - char *token; - char *sep; - char *e; - int pplen = strlen (PATH_PREFIX); - - whitelist = rc_get_list (whitelist, SYS_WHITELIST); - if (! whitelist) - ewarn ("system environment whitelist (" SYS_WHITELIST ") missing"); - - whitelist = rc_get_list (whitelist, USR_WHITELIST); - - if (! whitelist) - return (NULL); - - if (rc_is_file (PROFILE_ENV)) - profile = rc_get_config (profile, PROFILE_ENV); - - STRLIST_FOREACH (whitelist, env_name, count) - { - char *space = strchr (env_name, ' '); - if (space) - *space = 0; - - env_var = getenv (env_name); - - if (! env_var && profile) - { - env_len = strlen (env_name) + strlen ("export ") + 1; - p = rc_xmalloc (sizeof (char *) * env_len); - snprintf (p, env_len, "export %s", env_name); - env_var = rc_get_config_entry (profile, p); - free (p); - } - - if (! env_var) - continue; - - /* Ensure our PATH is prefixed with the system locations first - for a little extra security */ - if (strcmp (env_name, "PATH") == 0 && - strncmp (PATH_PREFIX, env_var, pplen) != 0) - { - got_path = true; - env_len = strlen (env_name) + strlen (env_var) + pplen + 2; - e = p = rc_xmalloc (sizeof (char *) * env_len); - p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX); - - /* Now go through the env var and only add bits not in our PREFIX */ - sep = env_var; - while ((token = strsep (&sep, ":"))) - { - char *np = strdup (PATH_PREFIX); - char *npp = np; - char *tok = NULL; - while ((tok = strsep (&npp, ":"))) - if (strcmp (tok, token) == 0) - break; - if (! tok) - p += snprintf (p, env_len - (p - e), ":%s", token); - free (np); - } - *p++ = 0; - } - else - { - env_len = strlen (env_name) + strlen (env_var) + 2; - e = rc_xmalloc (sizeof (char *) * env_len); - snprintf (e, env_len, "%s=%s", env_name, env_var); - } - - env = rc_strlist_add (env, e); - free (e); - } - - /* We filtered the env but didn't get a PATH? Very odd. - However, we do need a path, so use a default. */ - if (! got_path) - { - env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2; - p = rc_xmalloc (sizeof (char *) * env_len); - snprintf (p, env_len, "PATH=%s", PATH_PREFIX); - env = rc_strlist_add (env, p); - free (p); - } - - rc_strlist_free (whitelist); - rc_strlist_free (profile); - - return (env); + char **env = NULL; + char **whitelist = NULL; + char *env_name = NULL; + char **profile = NULL; + int count = 0; + bool got_path = false; + char *env_var; + int env_len; + char *p; + char *token; + char *sep; + char *e; + int pplen = strlen (PATH_PREFIX); + + whitelist = rc_get_list (whitelist, SYS_WHITELIST); + if (! whitelist) + ewarn ("system environment whitelist (" SYS_WHITELIST ") missing"); + + whitelist = rc_get_list (whitelist, USR_WHITELIST); + + if (! whitelist) + return (NULL); + + if (rc_is_file (PROFILE_ENV)) + profile = rc_get_config (profile, PROFILE_ENV); + + STRLIST_FOREACH (whitelist, env_name, count) { + char *space = strchr (env_name, ' '); + if (space) + *space = 0; + + env_var = getenv (env_name); + + if (! env_var && profile) { + env_len = strlen (env_name) + strlen ("export ") + 1; + p = rc_xmalloc (sizeof (char *) * env_len); + snprintf (p, env_len, "export %s", env_name); + env_var = rc_get_config_entry (profile, p); + free (p); + } + + if (! env_var) + continue; + + /* Ensure our PATH is prefixed with the system locations first + for a little extra security */ + if (strcmp (env_name, "PATH") == 0 && + strncmp (PATH_PREFIX, env_var, pplen) != 0) + { + got_path = true; + env_len = strlen (env_name) + strlen (env_var) + pplen + 2; + e = p = rc_xmalloc (sizeof (char *) * env_len); + p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX); + + /* Now go through the env var and only add bits not in our PREFIX */ + sep = env_var; + while ((token = strsep (&sep, ":"))) { + char *np = strdup (PATH_PREFIX); + char *npp = np; + char *tok = NULL; + while ((tok = strsep (&npp, ":"))) + if (strcmp (tok, token) == 0) + break; + if (! tok) + p += snprintf (p, env_len - (p - e), ":%s", token); + free (np); + } + *p++ = 0; + } else { + env_len = strlen (env_name) + strlen (env_var) + 2; + e = rc_xmalloc (sizeof (char *) * env_len); + snprintf (e, env_len, "%s=%s", env_name, env_var); + } + + env = rc_strlist_add (env, e); + free (e); + } + + /* We filtered the env but didn't get a PATH? Very odd. + However, we do need a path, so use a default. */ + if (! got_path) { + env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2; + p = rc_xmalloc (sizeof (char *) * env_len); + snprintf (p, env_len, "PATH=%s", PATH_PREFIX); + env = rc_strlist_add (env, p); + free (p); + } + + rc_strlist_free (whitelist); + rc_strlist_free (profile); + + return (env); } /* Other systems may need this at some point, but for now it's Linux only */ #ifdef __linux__ static bool file_regex (const char *file, const char *regex) { - FILE *fp; - char buffer[RC_LINEBUFFER]; - regex_t re; - bool retval = false; - int result; - - if (! rc_exists (file)) - return (false); - - if (! (fp = fopen (file, "r"))) - { - ewarn ("file_regex `%s': %s", file, strerror (errno)); - return (false); - } - - if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) - { - fclose (fp); - regerror (result, &re, buffer, sizeof (buffer)); - eerror ("file_regex: %s", buffer); - return (false); - } - - while (fgets (buffer, RC_LINEBUFFER, fp)) - { - if (regexec (&re, buffer, 0, NULL, 0) == 0) - { - retval = true; - break; - } - } - fclose (fp); - regfree (&re); - - return (retval); + FILE *fp; + char buffer[RC_LINEBUFFER]; + regex_t re; + bool retval = false; + int result; + + if (! rc_exists (file)) + return (false); + + if (! (fp = fopen (file, "r"))) { + ewarn ("file_regex `%s': %s", file, strerror (errno)); + return (false); + } + + if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) { + fclose (fp); + regerror (result, &re, buffer, sizeof (buffer)); + eerror ("file_regex: %s", buffer); + return (false); + } + + while (fgets (buffer, RC_LINEBUFFER, fp)) { + if (regexec (&re, buffer, 0, NULL, 0) == 0) + { + retval = true; + break; + } + } + fclose (fp); + regfree (&re); + + return (retval); } #endif char **rc_config_env (char **env) { - char *line; - int i; - char *p; - char **config = rc_get_config (NULL, RC_CONFIG); - char *e; - char sys[6]; - struct utsname uts; - bool has_net_fs_list = false; - FILE *fp; - char buffer[PATH_MAX]; - - STRLIST_FOREACH (config, line, i) - { - p = strchr (line, '='); - if (! p) - continue; - - *p = 0; - e = getenv (line); - if (! e) - { - *p = '='; - env = rc_strlist_add (env, line); - } - else - { - int len = strlen (line) + strlen (e) + 2; - char *new = rc_xmalloc (sizeof (char *) * len); - snprintf (new, len, "%s=%s", line, e); - env = rc_strlist_add (env, new); - free (new); - } - } - rc_strlist_free (config); - - /* One char less to drop the trailing / */ - i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR); - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR); - env = rc_strlist_add (env, line); - free (line); - - /* One char less to drop the trailing / */ - i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR); - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR); - env = rc_strlist_add (env, line); - free (line); - - env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT); - - p = rc_get_runlevel (); - i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1; - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_SOFTLEVEL=%s", p); - env = rc_strlist_add (env, line); - free (line); - - if (rc_exists (RC_SVCDIR "ksoftlevel")) - { - if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) - eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", - strerror (errno)); - else - { - memset (buffer, 0, sizeof (buffer)); - if (fgets (buffer, sizeof (buffer), fp)) - { - i = strlen (buffer) - 1; - if (buffer[i] == '\n') - buffer[i] = 0; - i += strlen ("RC_DEFAULTLEVEL=") + 2; - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer); - env = rc_strlist_add (env, line); - free (line); - } - fclose (fp); - } - } - else - env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT); - - memset (sys, 0, sizeof (sys)); - - /* Linux can run some funky stuff like Xen, VServer, UML, etc - We store this special system in RC_SYS so our scripts run fast */ + char *line; + int i; + char *p; + char **config = rc_get_config (NULL, RC_CONFIG); + char *e; + char sys[6]; + struct utsname uts; + bool has_net_fs_list = false; + FILE *fp; + char buffer[PATH_MAX]; + + STRLIST_FOREACH (config, line, i) { + p = strchr (line, '='); + if (! p) + continue; + + *p = 0; + e = getenv (line); + if (! e) { + *p = '='; + env = rc_strlist_add (env, line); + } else { + int len = strlen (line) + strlen (e) + 2; + char *new = rc_xmalloc (sizeof (char *) * len); + snprintf (new, len, "%s=%s", line, e); + env = rc_strlist_add (env, new); + free (new); + } + } + rc_strlist_free (config); + + /* One char less to drop the trailing / */ + i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR); + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR); + env = rc_strlist_add (env, line); + free (line); + + /* One char less to drop the trailing / */ + i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR); + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR); + env = rc_strlist_add (env, line); + free (line); + + env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT); + + p = rc_get_runlevel (); + i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1; + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_SOFTLEVEL=%s", p); + env = rc_strlist_add (env, line); + free (line); + + if (rc_exists (RC_SVCDIR "ksoftlevel")) { + if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) + eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", + strerror (errno)); + else { + memset (buffer, 0, sizeof (buffer)); + if (fgets (buffer, sizeof (buffer), fp)) { + i = strlen (buffer) - 1; + if (buffer[i] == '\n') + buffer[i] = 0; + i += strlen ("RC_DEFAULTLEVEL=") + 2; + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer); + env = rc_strlist_add (env, line); + free (line); + } + fclose (fp); + } + } else + env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT); + + memset (sys, 0, sizeof (sys)); + + /* Linux can run some funky stuff like Xen, VServer, UML, etc + We store this special system in RC_SYS so our scripts run fast */ #ifdef __linux__ - if (rc_is_dir ("/proc/xen")) - { - fp = fopen ("/proc/xen/capabilities", "r"); - if (fp) - { - fclose (fp); - if (file_regex ("/proc/xen/capabilities", "control_d")) - snprintf (sys, sizeof (sys), "XENU"); - } - if (! sys) - snprintf (sys, sizeof (sys), "XEN0"); - } - else if (file_regex ("/proc/cpuinfo", "UML")) - snprintf (sys, sizeof (sys), "UML"); - else if (file_regex ("/proc/self/status", - "(s_context|VxID|envID):[[:space:]]*[1-9]")) - snprintf (sys, sizeof (sys), "VPS"); + if (rc_is_dir ("/proc/xen")) { + fp = fopen ("/proc/xen/capabilities", "r"); + if (fp) { + fclose (fp); + if (file_regex ("/proc/xen/capabilities", "control_d")) + snprintf (sys, sizeof (sys), "XENU"); + } + if (! sys) + snprintf (sys, sizeof (sys), "XEN0"); + } else if (file_regex ("/proc/cpuinfo", "UML")) + snprintf (sys, sizeof (sys), "UML"); + else if (file_regex ("/proc/self/status", + "(s_context|VxID|envID):[[:space:]]*[1-9]")) + snprintf (sys, sizeof (sys), "VPS"); #endif - /* Only add a NET_FS list if not defined */ - STRLIST_FOREACH (env, line, i) - if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) - { - has_net_fs_list = true; - break; - } - if (! has_net_fs_list) - { - i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1; - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT); - env = rc_strlist_add (env, line); - free (line); - } - - if (sys[0]) - { - i = strlen ("RC_SYS=") + strlen (sys) + 2; - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_SYS=%s", sys); - env = rc_strlist_add (env, line); - free (line); - } - - /* Some scripts may need to take a different code path if Linux/FreeBSD, etc - To save on calling uname, we store it in an environment variable */ - if (uname (&uts) == 0) - { - i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2; - line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_UNAME=%s", uts.sysname); - env = rc_strlist_add (env, line); - free (line); - } - - return (env); + /* Only add a NET_FS list if not defined */ + STRLIST_FOREACH (env, line, i) + if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) { + has_net_fs_list = true; + break; + } + + if (! has_net_fs_list) { + i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1; + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT); + env = rc_strlist_add (env, line); + free (line); + } + + if (sys[0]) { + i = strlen ("RC_SYS=") + strlen (sys) + 2; + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_SYS=%s", sys); + env = rc_strlist_add (env, line); + free (line); + } + + /* Some scripts may need to take a different code path if Linux/FreeBSD, etc + To save on calling uname, we store it in an environment variable */ + if (uname (&uts) == 0) { + i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2; + line = rc_xmalloc (sizeof (char *) * i); + snprintf (line, i, "RC_UNAME=%s", uts.sysname); + env = rc_strlist_add (env, line); + free (line); + } + + return (env); } diff --git a/src/librc-strlist.c b/src/librc-strlist.c index 2fcf0b95..b6ba80ac 100644 --- a/src/librc-strlist.c +++ b/src/librc-strlist.c @@ -16,136 +16,130 @@ char **rc_strlist_add (char **list, const char *item) { - char **newlist; - int i = 0; + char **newlist; + int i = 0; - if (! item) - return (list); + if (! item) + return (list); - while (list && list[i]) - i++; + while (list && list[i]) + i++; - newlist = rc_xrealloc (list, sizeof (char *) * (i + 2)); - newlist[i] = rc_xstrdup (item); - newlist[i + 1] = NULL; + newlist = rc_xrealloc (list, sizeof (char *) * (i + 2)); + newlist[i] = rc_xstrdup (item); + newlist[i + 1] = NULL; - return (newlist); + return (newlist); } static char **_rc_strlist_addsort (char **list, const char *item, - int (*sortfunc) (const char *s1, - const char *s2), - bool uniq) + int (*sortfunc) (const char *s1, + const char *s2), + bool uniq) { - char **newlist; - int i = 0; - char *tmp1; - char *tmp2; - - if (! item) - return (list); - - while (list && list[i]) - { - if (uniq && strcmp (list[i], item) == 0) - return (list); - i++; - } - - newlist = rc_xrealloc (list, 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]; - newlist[i] = rc_xstrdup (item); - do - { - i++; - tmp2 = newlist[i]; - newlist[i] = tmp1; - tmp1 = tmp2; - } while (tmp1); - - return (newlist); + char **newlist; + int i = 0; + char *tmp1; + char *tmp2; + + if (! item) + return (list); + + while (list && list[i]) { + if (uniq && strcmp (list[i], item) == 0) + return (list); + i++; + } + + newlist = rc_xrealloc (list, 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]; + newlist[i] = rc_xstrdup (item); + do { + i++; + tmp2 = newlist[i]; + newlist[i] = tmp1; + tmp1 = tmp2; + } while (tmp1); + + return (newlist); } char **rc_strlist_addsort (char **list, const char *item) { - return (_rc_strlist_addsort (list, item, strcoll, false)); + return (_rc_strlist_addsort (list, item, strcoll, false)); } char **rc_strlist_addsortc (char **list, const char *item) { - return (_rc_strlist_addsort (list, item, strcmp, false)); + return (_rc_strlist_addsort (list, item, strcmp, false)); } char **rc_strlist_addsortu (char **list, const char *item) { - return (_rc_strlist_addsort (list, item, strcmp, true)); + return (_rc_strlist_addsort (list, item, strcmp, true)); } char **rc_strlist_delete (char **list, const char *item) { - int i = 0; - - if (!list || ! item) - return (list); - - while (list[i]) - if (! strcmp (list[i], item)) - { - free (list[i]); - do - { - list[i] = list[i + 1]; - i++; - } while (list[i]); - } - - return (list); + int i = 0; + + if (!list || ! item) + return (list); + + while (list[i]) + if (! strcmp (list[i], item)) { + free (list[i]); + do { + list[i] = list[i + 1]; + i++; + } while (list[i]); + } + + return (list); } 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--; - } + 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--; + } } void rc_strlist_free (char **list) { - int i = 0; + int i = 0; - if (! list) - return; + if (! list) + return; - while (list[i]) - { - free (list[i]); - list[i++] = NULL; - } + while (list[i]) { + free (list[i]); + list[i++] = NULL; + } - free (list); + free (list); } diff --git a/src/librc.c b/src/librc.c index a34702d4..1ea95c6f 100644 --- a/src/librc.c +++ b/src/librc.c @@ -39,777 +39,730 @@ #define SOFTLEVEL RC_SVCDIR "softlevel" static const char *rc_service_state_names[] = { - "started", - "stopped", - "starting", - "stopping", - "inactive", - "wasinactive", - "coldplugged", - "failed", - "scheduled", - NULL + "started", + "stopped", + "starting", + "stopping", + "inactive", + "wasinactive", + "coldplugged", + "failed", + "scheduled", + NULL }; bool rc_runlevel_starting (void) { - return (rc_is_dir (RC_SVCDIR "softscripts.old")); + return (rc_is_dir (RC_SVCDIR "softscripts.old")); } bool rc_runlevel_stopping (void) { - return (rc_is_dir (RC_SVCDIR "softscripts.new")); + return (rc_is_dir (RC_SVCDIR "softscripts.new")); } char **rc_get_runlevels (void) { - char **dirs = rc_ls_dir (NULL, RC_RUNLEVELDIR, 0); - char **runlevels = NULL; - int i; - char *dir; - - STRLIST_FOREACH (dirs, dir, i) - { - char *path = rc_strcatpaths (RC_RUNLEVELDIR, dir, (char *) NULL); - if (rc_is_dir (path)) - runlevels = rc_strlist_addsort (runlevels, dir); - free (path); - } - rc_strlist_free (dirs); - - return (runlevels); + char **dirs = rc_ls_dir (NULL, RC_RUNLEVELDIR, 0); + char **runlevels = NULL; + int i; + char *dir; + + STRLIST_FOREACH (dirs, dir, i) { + char *path = rc_strcatpaths (RC_RUNLEVELDIR, dir, (char *) NULL); + if (rc_is_dir (path)) + runlevels = rc_strlist_addsort (runlevels, dir); + free (path); + } + rc_strlist_free (dirs); + + return (runlevels); } char *rc_get_runlevel (void) { - FILE *fp; - static char buffer [PATH_MAX]; - - if (! (fp = fopen (SOFTLEVEL, "r"))) - { - snprintf (buffer, sizeof (buffer), "sysinit"); - return (buffer); - } - - if (fgets (buffer, PATH_MAX, fp)) - { - int i = strlen (buffer) - 1; - if (buffer[i] == '\n') - buffer[i] = 0; - fclose (fp); - return (buffer); - } - - fclose (fp); - snprintf (buffer, sizeof (buffer), "sysinit"); - return (buffer); + FILE *fp; + static char buffer [PATH_MAX]; + + if (! (fp = fopen (SOFTLEVEL, "r"))) { + snprintf (buffer, sizeof (buffer), "sysinit"); + return (buffer); + } + + if (fgets (buffer, PATH_MAX, fp)) { + int i = strlen (buffer) - 1; + if (buffer[i] == '\n') + buffer[i] = 0; + fclose (fp); + return (buffer); + } + + fclose (fp); + snprintf (buffer, sizeof (buffer), "sysinit"); + return (buffer); } void rc_set_runlevel (const char *runlevel) { - FILE *fp = fopen (SOFTLEVEL, "w"); - if (! fp) - eerrorx ("failed to open `" SOFTLEVEL "': %s", strerror (errno)); - fprintf (fp, "%s", runlevel); - fclose (fp); + FILE *fp = fopen (SOFTLEVEL, "w"); + if (! fp) + eerrorx ("failed to open `" SOFTLEVEL "': %s", strerror (errno)); + fprintf (fp, "%s", runlevel); + fclose (fp); } bool rc_runlevel_exists (const char *runlevel) { - char *path; - bool retval; + char *path; + bool retval; - if (! runlevel) - return (false); + if (! runlevel) + return (false); - path = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL); - retval = rc_is_dir (path); - free (path); - return (retval); + path = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL); + retval = rc_is_dir (path); + free (path); + return (retval); } /* Resolve a service name to it's full path */ char *rc_resolve_service (const char *service) { - char buffer[PATH_MAX]; - char *file; - int r = 0; - - if (! service) - return (NULL); - - if (service[0] == '/') - return (strdup (service)); - - file = rc_strcatpaths (RC_SVCDIR, "started", service, (char *) NULL); - if (! rc_is_link (file)) - { - free (file); - file = rc_strcatpaths (RC_SVCDIR, "inactive", service, (char *) NULL); - if (! rc_is_link (file)) - { - free (file); - file = NULL; - } - } - - memset (buffer, 0, sizeof (buffer)); - if (file) - { - r = readlink (file, buffer, sizeof (buffer)); - free (file); - if (r > 0) - return strdup (buffer); - } - - snprintf (buffer, sizeof (buffer), RC_INITDIR "%s", service); - return (strdup (buffer)); + char buffer[PATH_MAX]; + char *file; + int r = 0; + + if (! service) + return (NULL); + + if (service[0] == '/') + return (strdup (service)); + + file = rc_strcatpaths (RC_SVCDIR, "started", service, (char *) NULL); + if (! rc_is_link (file)) { + free (file); + file = rc_strcatpaths (RC_SVCDIR, "inactive", service, (char *) NULL); + if (! rc_is_link (file)) { + free (file); + file = NULL; + } + } + + memset (buffer, 0, sizeof (buffer)); + if (file) { + r = readlink (file, buffer, sizeof (buffer)); + free (file); + if (r > 0) + return strdup (buffer); + } + + snprintf (buffer, sizeof (buffer), RC_INITDIR "%s", service); + return (strdup (buffer)); } bool rc_service_exists (const char *service) { - char *file; - bool retval = false; - int len; - - if (! service) - return (false); - - len = strlen (service); - - /* .sh files are not init scripts */ - if (len > 2 && service[len - 3] == '.' && - service[len - 2] == 's' && - service[len - 1] == 'h') - return (false); - - file = rc_resolve_service (service); - if (rc_exists (file)) - retval = rc_is_exec (file); - free (file); - return (retval); + char *file; + bool retval = false; + int len; + + if (! service) + return (false); + + len = strlen (service); + + /* .sh files are not init scripts */ + if (len > 2 && service[len - 3] == '.' && + service[len - 2] == 's' && + service[len - 1] == 'h') + return (false); + + file = rc_resolve_service (service); + if (rc_exists (file)) + retval = rc_is_exec (file); + free (file); + return (retval); } bool rc_service_in_runlevel (const char *service, const char *runlevel) { - char *file; - bool retval; + char *file; + bool retval; - if (! runlevel || ! service) - return (false); + if (! runlevel || ! service) + return (false); - if (! rc_service_exists (service)) - return (false); + if (! rc_service_exists (service)) + return (false); - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), - (char *) NULL); - retval = rc_exists (file); - free (file); + file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), + (char *) NULL); + retval = rc_exists (file); + free (file); - return (retval); + return (retval); } bool rc_mark_service (const char *service, const rc_service_state_t state) { - char *file; - int i = 0; - int skip_state = -1; - char *base; - char *init = rc_resolve_service (service); - bool skip_wasinactive = false; - - if (! service) - return (false); - - base = basename (service); - - if (state != rc_service_stopped) - { - if (! rc_is_file(init)) - { - free (init); - return (false); - } - - file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], base, - (char *) NULL); - if (rc_exists (file)) - unlink (file); - i = symlink (init, file); - if (i != 0) - { - free (file); - free (init); - einfo ("%d %s %s", state, rc_service_state_names[state], base); - eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno)); - return (false); - } - - free (file); - skip_state = state; - } - - if (state == rc_service_coldplugged) - { - free (init); - return (true); - } - - /* Remove any old states now */ - i = 0; - while (rc_service_state_names[i]) - { - if ((i != skip_state && - i != rc_service_stopped && - i != rc_service_coldplugged && - i != rc_service_scheduled && - i != rc_service_crashed) && - (! skip_wasinactive || i != rc_service_wasinactive)) - { - file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i], base, - (char *) NULL); - if (rc_exists (file)) - { - if ((state == rc_service_starting || - state == rc_service_stopping) && - i == rc_service_inactive) - { - char *wasfile = rc_strcatpaths (RC_SVCDIR, - rc_service_state_names[rc_service_wasinactive], - base, (char *) NULL); - - if (symlink (init, wasfile) != 0) - eerror ("symlink `%s' to `%s': %s", init, wasfile, - strerror (errno)); - - skip_wasinactive = true; - free (wasfile); - } - - errno = 0; - if (unlink (file) != 0 && errno != ENOENT) - eerror ("failed to delete `%s': %s", file, - strerror (errno)); - } - free (file); - } - i++; - } - - /* Remove the exclusive state if we're inactive */ - if (state == rc_service_started || - state == rc_service_stopped || - state == rc_service_inactive) - { - file = rc_strcatpaths (RC_SVCDIR, "exclusive", base, (char *) NULL); - if (rc_exists (file)) - if (unlink (file) != 0) - eerror ("unlink `%s': %s", file, strerror (errno)); - 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); - - if (rc_is_dir (dir)) - rc_rm_dir (dir, true); - free (dir); - - dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL); - if (rc_is_dir (dir)) - rc_rm_dir (dir, true); - free (dir); - - rc_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 = rc_ls_dir (NULL, sdir, 0); - char *dir; - int serrno; - - STRLIST_FOREACH (dirs, dir, i) - { - char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL); - file = rc_strcatpaths (bdir, base, (char *) NULL); - if (rc_exists (file)) - if (unlink (file) != 0) - eerror ("unlink `%s': %s", file, strerror (errno)); - free (file); - - /* Try and remove the dir - we don't care about errors */ - serrno = errno; - rmdir (bdir); - errno = serrno; - free (bdir); - } - rc_strlist_free (dirs); - free (sdir); - } - - free (init); - return (true); + char *file; + int i = 0; + int skip_state = -1; + char *base; + char *init = rc_resolve_service (service); + bool skip_wasinactive = false; + + if (! service) + return (false); + + base = basename (service); + + if (state != rc_service_stopped) { + if (! rc_is_file(init)) { + free (init); + return (false); + } + + file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], base, + (char *) NULL); + if (rc_exists (file)) + unlink (file); + i = symlink (init, file); + if (i != 0) { + free (file); + free (init); + einfo ("%d %s %s", state, rc_service_state_names[state], base); + eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno)); + return (false); + } + + free (file); + skip_state = state; + } + + if (state == rc_service_coldplugged) { + free (init); + return (true); + } + + /* Remove any old states now */ + i = 0; + while (rc_service_state_names[i]) { + if ((i != skip_state && + i != rc_service_stopped && + i != rc_service_coldplugged && + i != rc_service_scheduled && + i != rc_service_crashed) && + (! skip_wasinactive || i != rc_service_wasinactive)) + { + file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i], base, + (char *) NULL); + if (rc_exists (file)) { + if ((state == rc_service_starting || + state == rc_service_stopping) && + i == rc_service_inactive) + { + char *wasfile = rc_strcatpaths (RC_SVCDIR, + rc_service_state_names[rc_service_wasinactive], + base, (char *) NULL); + + if (symlink (init, wasfile) != 0) + eerror ("symlink `%s' to `%s': %s", init, wasfile, + strerror (errno)); + + skip_wasinactive = true; + free (wasfile); + } + + errno = 0; + if (unlink (file) != 0 && errno != ENOENT) + eerror ("failed to delete `%s': %s", file, + strerror (errno)); + } + free (file); + } + i++; + } + + /* Remove the exclusive state if we're inactive */ + if (state == rc_service_started || + state == rc_service_stopped || + state == rc_service_inactive) + { + file = rc_strcatpaths (RC_SVCDIR, "exclusive", base, (char *) NULL); + if (rc_exists (file)) + if (unlink (file) != 0) + eerror ("unlink `%s': %s", file, strerror (errno)); + 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); + + if (rc_is_dir (dir)) + rc_rm_dir (dir, true); + free (dir); + + dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL); + if (rc_is_dir (dir)) + rc_rm_dir (dir, true); + free (dir); + + rc_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 = rc_ls_dir (NULL, sdir, 0); + char *dir; + int serrno; + + STRLIST_FOREACH (dirs, dir, i) { + char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL); + file = rc_strcatpaths (bdir, base, (char *) NULL); + if (rc_exists (file)) + if (unlink (file) != 0) + eerror ("unlink `%s': %s", file, strerror (errno)); + free (file); + + /* Try and remove the dir - we don't care about errors */ + serrno = errno; + rmdir (bdir); + errno = serrno; + free (bdir); + } + rc_strlist_free (dirs); + free (sdir); + } + + free (init); + return (true); } bool rc_service_state (const char *service, const rc_service_state_t state) { - char *file; - bool retval; - - /* If the init script does not exist then we are stopped */ - if (! rc_service_exists (service)) - return (state == rc_service_stopped ? true : false); - - /* We check stopped state by not being in any of the others */ - if (state == rc_service_stopped) - return ( ! (rc_service_state (service, rc_service_started) || - rc_service_state (service, rc_service_starting) || - rc_service_state (service, rc_service_stopping) || - rc_service_state (service, rc_service_inactive))); - - /* The crashed state and scheduled states are virtual */ - if (state == rc_service_crashed) - return (rc_service_daemons_crashed (service)); - else if (state == rc_service_scheduled) - { - char **services = rc_services_scheduled_by (service); - retval = (services); - if (services) - free (services); - return (retval); - } - - /* Now we just check if a file by the service name rc_exists - in the state dir */ - file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], - basename (service), (char*) NULL); - retval = rc_exists (file); - free (file); - return (retval); + char *file; + bool retval; + + /* If the init script does not exist then we are stopped */ + if (! rc_service_exists (service)) + return (state == rc_service_stopped ? true : false); + + /* We check stopped state by not being in any of the others */ + if (state == rc_service_stopped) + return ( ! (rc_service_state (service, rc_service_started) || + rc_service_state (service, rc_service_starting) || + rc_service_state (service, rc_service_stopping) || + rc_service_state (service, rc_service_inactive))); + + /* The crashed state and scheduled states are virtual */ + if (state == rc_service_crashed) + return (rc_service_daemons_crashed (service)); + else if (state == rc_service_scheduled) { + char **services = rc_services_scheduled_by (service); + retval = (services); + if (services) + free (services); + return (retval); + } + + /* Now we just check if a file by the service name rc_exists + in the state dir */ + file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], + basename (service), (char*) NULL); + retval = rc_exists (file); + free (file); + return (retval); } bool rc_get_service_option (const char *service, const char *option, - char *value) + char *value) { - FILE *fp; - char buffer[RC_LINEBUFFER]; - char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option, - (char *) NULL); - bool retval = false; - - if (rc_exists (file)) - { - if ((fp = fopen (file, "r")) == NULL) - eerror ("fopen `%s': %s", file, strerror (errno)); - else - { - memset (buffer, 0, sizeof (buffer)); - while (fgets (buffer, RC_LINEBUFFER, fp)) - { - memcpy (value, buffer, strlen (buffer)); - value += strlen (buffer); - } - fclose (fp); - retval = true; - } - } - - free (file); - return (retval); + FILE *fp; + char buffer[RC_LINEBUFFER]; + char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option, + (char *) NULL); + bool retval = false; + + if (rc_exists (file)) { + if ((fp = fopen (file, "r")) == NULL) + eerror ("fopen `%s': %s", file, strerror (errno)); + else { + memset (buffer, 0, sizeof (buffer)); + while (fgets (buffer, RC_LINEBUFFER, fp)) { + memcpy (value, buffer, strlen (buffer)); + value += strlen (buffer); + } + fclose (fp); + retval = true; + } + } + + free (file); + return (retval); } bool rc_set_service_option (const char *service, const char *option, - const char *value) + const char *value) { - FILE *fp; - char *path = rc_strcatpaths (RC_SVCDIR, "options", service, (char *) NULL); - char *file = rc_strcatpaths (path, option, (char *) NULL); - bool retval = false; - - if (! rc_is_dir (path)) - { - if (mkdir (path, 0755) != 0) - { - eerror ("mkdir `%s': %s", path, strerror (errno)); - free (path); - free (file); - return (false); - } - } - - if ((fp = fopen (file, "w")) == NULL) - eerror ("fopen `%s': %s", file, strerror (errno)); - else - { - if (value) - fprintf (fp, "%s", value); - fclose (fp); - retval = true; - } - - free (path); - free (file); - return (retval); + FILE *fp; + char *path = rc_strcatpaths (RC_SVCDIR, "options", service, (char *) NULL); + char *file = rc_strcatpaths (path, option, (char *) NULL); + bool retval = false; + + if (! rc_is_dir (path)) { + if (mkdir (path, 0755) != 0) { + eerror ("mkdir `%s': %s", path, strerror (errno)); + free (path); + free (file); + return (false); + } + } + + if ((fp = fopen (file, "w")) == NULL) + eerror ("fopen `%s': %s", file, strerror (errno)); + else { + if (value) + fprintf (fp, "%s", value); + fclose (fp); + retval = true; + } + + free (path); + free (file); + return (retval); } static pid_t _exec_service (const char *service, const char *arg) { - char *file; - char *fifo; - pid_t pid = -1; - pid_t savedpid; - int status; - - file = rc_resolve_service (service); - if (! rc_is_file (file)) - { - rc_mark_service (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 (service), - (char *) NULL); - - if (mkfifo (fifo, 0600) != 0 && errno != EEXIST) - { - eerror ("unable to create fifo `%s': %s", fifo, strerror (errno)); - free (fifo); - free (file); - return (-1); - } - - if ((pid = fork ()) == 0) - { - char *myarg = strdup (arg); - int e = 0; - execl (file, file, myarg, (char *) NULL); - e = errno; - free (myarg); - unlink (fifo); - free (fifo); - eerrorx ("unable to exec `%s': %s", file, strerror (errno)); - } - - free (fifo); - free (file); - - if (pid == -1) - { - eerror ("unable to fork: %s", strerror (errno)); - return (pid); - } - - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - return (pid); - - savedpid = pid; - errno = 0; - do - { - pid = waitpid (savedpid, &status, 0); - if (pid < 0) - { - if (errno != ECHILD) - eerror ("waitpid %d: %s", savedpid, strerror (errno)); - return (-1); - } - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - return (0); + char *file; + char *fifo; + pid_t pid = -1; + pid_t savedpid; + int status; + + file = rc_resolve_service (service); + if (! rc_is_file (file)) { + rc_mark_service (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 (service), + (char *) NULL); + + if (mkfifo (fifo, 0600) != 0 && errno != EEXIST) { + eerror ("unable to create fifo `%s': %s", fifo, strerror (errno)); + free (fifo); + free (file); + return (-1); + } + + if ((pid = fork ()) == 0) { + char *myarg = strdup (arg); + int e = 0; + execl (file, file, myarg, (char *) NULL); + e = errno; + free (myarg); + unlink (fifo); + free (fifo); + eerrorx ("unable to exec `%s': %s", file, strerror (errno)); + } + + free (fifo); + free (file); + + if (pid == -1) { + eerror ("unable to fork: %s", strerror (errno)); + return (pid); + } + + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) + return (pid); + + savedpid = pid; + errno = 0; + do { + pid = waitpid (savedpid, &status, 0); + if (pid < 0) { + if (errno != ECHILD) + eerror ("waitpid %d: %s", savedpid, strerror (errno)); + return (-1); + } + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + return (0); } pid_t rc_stop_service (const char *service) { - if (rc_service_state (service, rc_service_stopped)) - return (0); + if (rc_service_state (service, rc_service_stopped)) + return (0); - return (_exec_service (service, "stop")); + return (_exec_service (service, "stop")); } pid_t rc_start_service (const char *service) { - if (! rc_service_state (service, rc_service_stopped)) - return (0); + if (! rc_service_state (service, rc_service_stopped)) + return (0); - return (_exec_service (service, "start")); + return (_exec_service (service, "start")); } void rc_schedule_start_service (const char *service, - const char *service_to_start) + const char *service_to_start) { - char *dir; - char *init; - char *file; - - /* service may be a provided service, like net */ - if (! service || ! rc_service_exists (service_to_start)) - return; - - dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), - (char *) NULL); - if (! rc_is_dir (dir)) - if (mkdir (dir, 0755) != 0) - { - eerror ("mkdir `%s': %s", dir, strerror (errno)); - free (dir); - return; - } - - init = rc_resolve_service (service_to_start); - file = rc_strcatpaths (dir, basename (service_to_start), (char *) NULL); - if (! rc_exists (file) && symlink (init, file) != 0) - eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno)); - - free (init); - free (file); - free (dir); + char *dir; + char *init; + char *file; + + /* service may be a provided service, like net */ + if (! service || ! rc_service_exists (service_to_start)) + return; + + dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), + (char *) NULL); + if (! rc_is_dir (dir)) + if (mkdir (dir, 0755) != 0) { + eerror ("mkdir `%s': %s", dir, strerror (errno)); + free (dir); + return; + } + + init = rc_resolve_service (service_to_start); + file = rc_strcatpaths (dir, basename (service_to_start), (char *) NULL); + if (! rc_exists (file) && symlink (init, file) != 0) + eerror ("symlink `%s' to `%s': %s", init, file, strerror (errno)); + + free (init); + free (file); + free (dir); } void rc_schedule_clear (const char *service) { - char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), - (char *) NULL); + char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), + (char *) NULL); - if (rc_is_dir (dir)) - rc_rm_dir (dir, true); - free (dir); + if (rc_is_dir (dir)) + rc_rm_dir (dir, true); + free (dir); } bool rc_wait_service (const char *service) { - char *fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename (service), - (char *) NULL); - struct timeval tv; - struct timeval stopat; - struct timeval now; - bool retval = false; - - if (gettimeofday (&stopat, NULL) != 0) - { - eerror ("gettimeofday: %s", strerror (errno)); - return (false); - } - stopat.tv_sec += WAIT_MAX; - - while (true) - { - if (! rc_exists (fifo)) - { - retval = true; - break; - } - - tv.tv_sec = 0; - tv.tv_usec = WAIT_INTERVAL; - if (select (0, 0, 0, 0, &tv) < 0) - { - if (errno != EINTR) - eerror ("select: %s",strerror (errno)); - break; - } - - /* Don't hang around forever */ - if (gettimeofday (&now, NULL) != 0) - { - eerror ("gettimeofday: %s", strerror (errno)); - break; - } - if (timercmp (&now, &stopat, >)) - break; - } - - free (fifo); - return (retval); + char *fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename (service), + (char *) NULL); + struct timeval tv; + struct timeval stopat; + struct timeval now; + bool retval = false; + + if (gettimeofday (&stopat, NULL) != 0) { + eerror ("gettimeofday: %s", strerror (errno)); + return (false); + } + stopat.tv_sec += WAIT_MAX; + + while (true) { + if (! rc_exists (fifo)) { + retval = true; + break; + } + + tv.tv_sec = 0; + tv.tv_usec = WAIT_INTERVAL; + if (select (0, 0, 0, 0, &tv) < 0) { + if (errno != EINTR) + eerror ("select: %s",strerror (errno)); + break; + } + + /* Don't hang around forever */ + if (gettimeofday (&now, NULL) != 0) { + eerror ("gettimeofday: %s", strerror (errno)); + break; + } + + if (timercmp (&now, &stopat, >)) + break; + } + + free (fifo); + return (retval); } char **rc_services_in_runlevel (const char *runlevel) { - char *dir; - char **list = NULL; + char *dir; + char **list = NULL; - if (! runlevel) - return (rc_ls_dir (NULL, RC_INITDIR, RC_LS_INITD)); + if (! runlevel) + return (rc_ls_dir (NULL, RC_INITDIR, RC_LS_INITD)); - /* These special levels never contain any services */ - if (strcmp (runlevel, RC_LEVEL_SYSINIT) == 0 || - strcmp (runlevel, RC_LEVEL_SINGLE) == 0) - return (NULL); + /* 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); - if (! rc_is_dir (dir)) - eerror ("runlevel `%s' does not exist", runlevel); - else - list = rc_ls_dir (list, dir, RC_LS_INITD); + dir = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL); + if (! rc_is_dir (dir)) + eerror ("runlevel `%s' does not exist", runlevel); + else + list = rc_ls_dir (list, dir, RC_LS_INITD); - free (dir); - return (list); + free (dir); + return (list); } char **rc_services_in_state (rc_service_state_t state) { - char *dir = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], - (char *) NULL); - char **list = NULL; - - if (state == rc_service_scheduled) - { - char **dirs = rc_ls_dir (NULL, dir, 0); - char *d; - int i; - - STRLIST_FOREACH (dirs, d, i) - { - char *p = rc_strcatpaths (dir, d, (char *) NULL); - char **entries = rc_ls_dir (NULL, p, RC_LS_INITD); - char *e; - int j; - - STRLIST_FOREACH (entries, e, j) - list = rc_strlist_addsortu (list, e); - - if (entries) - free (entries); - } - - if (dirs) - free (dirs); - } - else - { - if (rc_is_dir (dir)) - list = rc_ls_dir (list, dir, RC_LS_INITD); - } - - free (dir); - return (list); + char *dir = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[state], + (char *) NULL); + char **list = NULL; + + if (state == rc_service_scheduled) { + char **dirs = rc_ls_dir (NULL, dir, 0); + char *d; + int i; + + STRLIST_FOREACH (dirs, d, i) { + char *p = rc_strcatpaths (dir, d, (char *) NULL); + char **entries = rc_ls_dir (NULL, p, RC_LS_INITD); + char *e; + int j; + + STRLIST_FOREACH (entries, e, j) + list = rc_strlist_addsortu (list, e); + + if (entries) + free (entries); + } + + if (dirs) + free (dirs); + } else { + if (rc_is_dir (dir)) + list = rc_ls_dir (list, dir, RC_LS_INITD); + } + + free (dir); + return (list); } bool rc_service_add (const char *runlevel, const char *service) { - bool retval; - char *init; - char *file; - - if (! rc_runlevel_exists (runlevel)) - { - errno = ENOENT; - return (false); - } - - if (rc_service_in_runlevel (service, runlevel)) - { - errno = EEXIST; - return (false); - } - - init = rc_resolve_service (service); - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), - (char *) NULL); - retval = (symlink (init, file) == 0); - free (init); - free (file); - return (retval); + bool retval; + char *init; + char *file; + + if (! rc_runlevel_exists (runlevel)) { + errno = ENOENT; + return (false); + } + + if (rc_service_in_runlevel (service, runlevel)) { + errno = EEXIST; + return (false); + } + + init = rc_resolve_service (service); + file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), + (char *) NULL); + retval = (symlink (init, file) == 0); + free (init); + free (file); + return (retval); } bool rc_service_delete (const char *runlevel, const char *service) { - char *file; - bool retval = false; + char *file; + bool retval = false; - if (! runlevel || ! service) - return (false); + if (! runlevel || ! service) + return (false); - file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), - (char *) NULL); - if (unlink (file) == 0) - retval = true; + file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (service), + (char *) NULL); + if (unlink (file) == 0) + retval = true; - free (file); - return (retval); + free (file); + return (retval); } char **rc_services_scheduled_by (const char *service) { - char **dirs = rc_ls_dir (NULL, RC_SVCDIR "scheduled", 0); - char **list = NULL; - char *dir; - int i; - - STRLIST_FOREACH (dirs, dir, i) - { - char *file = rc_strcatpaths (RC_SVCDIR "scheduled", dir, service, - (char *) NULL); - if (rc_exists (file)) - list = rc_strlist_add (list, file); - free (file); - } - rc_strlist_free (dirs); - - return (list); + char **dirs = rc_ls_dir (NULL, RC_SVCDIR "scheduled", 0); + char **list = NULL; + char *dir; + int i; + + STRLIST_FOREACH (dirs, dir, i) { + char *file = rc_strcatpaths (RC_SVCDIR "scheduled", dir, service, + (char *) NULL); + if (rc_exists (file)) + list = rc_strlist_add (list, file); + free (file); + } + rc_strlist_free (dirs); + + return (list); } char **rc_services_scheduled (const char *service) { - char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), - (char *) NULL); - char **list = NULL; + char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename (service), + (char *) NULL); + char **list = NULL; - if (rc_is_dir (dir)) - list = rc_ls_dir (list, dir, RC_LS_INITD); + if (rc_is_dir (dir)) + list = rc_ls_dir (list, dir, RC_LS_INITD); - free (dir); - return (list); + free (dir); + return (list); } bool rc_allow_plug (char *service) { - char *list; - char *p; - char *star; - char *token; - bool allow = true; - char *match = getenv ("RC_PLUG_SERVICES"); - if (! match) - return true; - - list = strdup (match); - p = list; - while ((token = strsep (&p, " "))) - { - bool truefalse = true; - if (token[0] == '!') - { - truefalse = false; - token++; - } - - star = strchr (token, '*'); - if (star) - { - if (strncmp (service, token, star - token) == 0) - { - allow = truefalse; - break; - } - } - else - { - if (strcmp (service, token) == 0) - { - allow = truefalse; - break; - } - } - } - - free (list); - return (allow); + char *list; + char *p; + char *star; + char *token; + bool allow = true; + char *match = getenv ("RC_PLUG_SERVICES"); + if (! match) + return true; + + list = strdup (match); + p = list; + while ((token = strsep (&p, " "))) { + bool truefalse = true; + if (token[0] == '!') { + truefalse = false; + token++; + } + + star = strchr (token, '*'); + if (star) { + if (strncmp (service, token, star - token) == 0) { + allow = truefalse; + break; + } + } else { + if (strcmp (service, token) == 0) { + allow = truefalse; + break; + } + } + } + + free (list); + return (allow); } diff --git a/src/mountinfo.c b/src/mountinfo.c index c5dc60ff..1e15de4b 100644 --- a/src/mountinfo.c +++ b/src/mountinfo.c @@ -28,104 +28,98 @@ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) static char **find_mounts (regex_t *node_regex, regex_t *fstype_regex, - char **mounts, bool list_nodes, bool list_fstype) + char **mounts, bool list_nodes, bool list_fstype) { - struct statfs *mnts; - int nmnts; - int i; - char **list = NULL; - - if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0) - eerrorx ("getmntinfo: %s", strerror (errno)); - - for (i = 0; i < nmnts; i++) - { - if (node_regex && - regexec (node_regex, mnts[i].f_mntfromname, 0, NULL, 0) != 0) - continue; - if (fstype_regex && - regexec (fstype_regex, mnts[i].f_fstypename, 0, NULL, 0) != 0) - continue; - - if (mounts) - { - bool found = false; - int j; - char *mnt; - STRLIST_FOREACH (mounts, mnt, j) - if (strcmp (mnt, mnts[i].f_mntonname) == 0) - { - found = true; - break; - } - if (! found) - continue; - } - - list = rc_strlist_addsortc (list, list_nodes ? - mnts[i].f_mntfromname : - list_fstype ? mnts[i].f_fstypename : - mnts[i].f_mntonname); - } - - return (list); + struct statfs *mnts; + int nmnts; + int i; + char **list = NULL; + + if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0) + eerrorx ("getmntinfo: %s", strerror (errno)); + + for (i = 0; i < nmnts; i++) { + if (node_regex && + regexec (node_regex, mnts[i].f_mntfromname, 0, NULL, 0) != 0) + continue; + if (fstype_regex && + regexec (fstype_regex, mnts[i].f_fstypename, 0, NULL, 0) != 0) + continue; + + if (mounts) { + bool found = false; + int j; + char *mnt; + STRLIST_FOREACH (mounts, mnt, j) + if (strcmp (mnt, mnts[i].f_mntonname) == 0) { + found = true; + break; + } + if (! found) + continue; + } + + list = rc_strlist_addsortc (list, list_nodes ? + mnts[i].f_mntfromname : + list_fstype ? mnts[i].f_fstypename : + mnts[i].f_mntonname); + } + + return (list); } #elif defined (__linux__) static char **find_mounts (regex_t *node_regex, regex_t *fstype_regex, - char **mounts, bool list_nodes, bool list_fstype) + char **mounts, bool list_nodes, bool list_fstype) { - FILE *fp; - char buffer[PATH_MAX * 3]; - char *p; - char *from; - char *to; - char *fstype; - char **list = NULL; - - if ((fp = fopen ("/proc/mounts", "r")) == NULL) - eerrorx ("getmntinfo: %s", strerror (errno)); - - while (fgets (buffer, sizeof (buffer), fp)) - { - p = buffer; - from = strsep (&p, " "); - if (node_regex && - regexec (node_regex, from, 0, NULL, 0) != 0) - continue; - - to = strsep (&p, " "); - fstype = strsep (&p, " "); - /* Skip the really silly rootfs */ - if (strcmp (fstype, "rootfs") == 0) - continue; - if (fstype_regex && - regexec (fstype_regex, fstype, 0, NULL, 0) != 0) - continue; - - if (mounts) - { - bool found = false; - int j; - char *mnt; - STRLIST_FOREACH (mounts, mnt, j) - if (strcmp (mnt, to) == 0) - { - found = true; - break; - } - if (! found) - continue; - } - - list = rc_strlist_addsortc (list, - list_nodes ? - list_fstype ? fstype : - from : to); - } - fclose (fp); - - return (list); + FILE *fp; + char buffer[PATH_MAX * 3]; + char *p; + char *from; + char *to; + char *fstype; + char **list = NULL; + + if ((fp = fopen ("/proc/mounts", "r")) == NULL) + eerrorx ("getmntinfo: %s", strerror (errno)); + + while (fgets (buffer, sizeof (buffer), fp)) { + p = buffer; + from = strsep (&p, " "); + if (node_regex && + regexec (node_regex, from, 0, NULL, 0) != 0) + continue; + + to = strsep (&p, " "); + fstype = strsep (&p, " "); + /* Skip the really silly rootfs */ + if (strcmp (fstype, "rootfs") == 0) + continue; + if (fstype_regex && + regexec (fstype_regex, fstype, 0, NULL, 0) != 0) + continue; + + if (mounts) { + bool found = false; + int j; + char *mnt; + STRLIST_FOREACH (mounts, mnt, j) + if (strcmp (mnt, to) == 0) { + found = true; + break; + } + if (! found) + continue; + } + + list = rc_strlist_addsortc (list, + list_nodes ? + list_fstype ? fstype : + from : to); + } + fclose (fp); + + return (list); } #else @@ -134,113 +128,105 @@ static char **find_mounts (regex_t *node_regex, regex_t *fstype_regex, int main (int argc, char **argv) { - int i; - regex_t *fstype_regex = NULL; - regex_t *node_regex = NULL; - regex_t *skip_regex = NULL; - char **nodes = NULL; - char *node; - int result; - char buffer[256]; - bool list_nodes = false; - bool list_fstype = false; - bool reverse = false; - char **mounts = NULL; - - for (i = 1; i < argc; i++) - { - if (strcmp (argv[i], "--fstype-regex") == 0 && (i + 1 < argc)) - { - i++; - if (fstype_regex) - free (fstype_regex); - fstype_regex = rc_xmalloc (sizeof (regex_t)); - if ((result = regcomp (fstype_regex, argv[i], - REG_EXTENDED | REG_NOSUB)) != 0) - { - regerror (result, fstype_regex, buffer, sizeof (buffer)); - eerrorx ("%s: invalid regex `%s'", argv[0], buffer); - } - continue; - } - - if (strcmp (argv[i], "--node-regex") == 0 && (i + 1 < argc)) - { - i++; - if (node_regex) - free (node_regex); - node_regex = rc_xmalloc (sizeof (regex_t)); - if ((result = regcomp (node_regex, argv[i], - REG_EXTENDED | REG_NOSUB)) != 0) - { - regerror (result, node_regex, buffer, sizeof (buffer)); - eerrorx ("%s: invalid regex `%s'", argv[0], buffer); - } - continue; - } - - if (strcmp (argv[i], "--skip-regex") == 0 && (i + 1 < argc)) - { - i++; - if (skip_regex) - free (skip_regex); - skip_regex = rc_xmalloc (sizeof (regex_t)); - if ((result = regcomp (skip_regex, argv[i], - REG_EXTENDED | REG_NOSUB)) != 0) - { - regerror (result, skip_regex, buffer, sizeof (buffer)); - eerrorx ("%s: invalid regex `%s'", argv[0], buffer); - } - continue; - } - - if (strcmp (argv[i], "--fstype") == 0) - { - list_fstype = true; - continue; - } - - if (strcmp (argv[i], "--node") == 0) - { - list_nodes = true; - continue; - } - if (strcmp (argv[i], "--reverse") == 0) - { - reverse = true; - continue; - } - - if (argv[i][0] != '/') - eerrorx ("%s: `%s' is not a mount point", argv[0], argv[i]); - - mounts = rc_strlist_add (mounts, argv[i]); - } - - nodes = find_mounts (node_regex, fstype_regex, mounts, - list_nodes, list_fstype); - - if (node_regex) - regfree (node_regex); - if (fstype_regex) - regfree (fstype_regex); - - if (reverse) - rc_strlist_reverse (nodes); - - result = EXIT_FAILURE; - STRLIST_FOREACH (nodes, node, i) - { - if (skip_regex && regexec (skip_regex, node, 0, NULL, 0) == 0) - continue; - printf ("%s\n", node); - result = EXIT_SUCCESS; - } - rc_strlist_free (nodes); - - if (skip_regex) - free (skip_regex); - - exit (result); + int i; + regex_t *fstype_regex = NULL; + regex_t *node_regex = NULL; + regex_t *skip_regex = NULL; + char **nodes = NULL; + char *node; + int result; + char buffer[256]; + bool list_nodes = false; + bool list_fstype = false; + bool reverse = false; + char **mounts = NULL; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--fstype-regex") == 0 && (i + 1 < argc)) { + i++; + if (fstype_regex) + free (fstype_regex); + fstype_regex = rc_xmalloc (sizeof (regex_t)); + if ((result = regcomp (fstype_regex, argv[i], + REG_EXTENDED | REG_NOSUB)) != 0) + { + regerror (result, fstype_regex, buffer, sizeof (buffer)); + eerrorx ("%s: invalid regex `%s'", argv[0], buffer); + } + continue; + } + + if (strcmp (argv[i], "--node-regex") == 0 && (i + 1 < argc)) { + i++; + if (node_regex) + free (node_regex); + node_regex = rc_xmalloc (sizeof (regex_t)); + if ((result = regcomp (node_regex, argv[i], + REG_EXTENDED | REG_NOSUB)) != 0) + { + regerror (result, node_regex, buffer, sizeof (buffer)); + eerrorx ("%s: invalid regex `%s'", argv[0], buffer); + } + continue; + } + + if (strcmp (argv[i], "--skip-regex") == 0 && (i + 1 < argc)) { + i++; + if (skip_regex) + free (skip_regex); + skip_regex = rc_xmalloc (sizeof (regex_t)); + if ((result = regcomp (skip_regex, argv[i], + REG_EXTENDED | REG_NOSUB)) != 0) + { + regerror (result, skip_regex, buffer, sizeof (buffer)); + eerrorx ("%s: invalid regex `%s'", argv[0], buffer); + } + continue; + } + + if (strcmp (argv[i], "--fstype") == 0) { + list_fstype = true; + continue; + } + + if (strcmp (argv[i], "--node") == 0) { + list_nodes = true; + continue; + } + if (strcmp (argv[i], "--reverse") == 0) { + reverse = true; + continue; + } + + if (argv[i][0] != '/') + eerrorx ("%s: `%s' is not a mount point", argv[0], argv[i]); + + mounts = rc_strlist_add (mounts, argv[i]); + } + + nodes = find_mounts (node_regex, fstype_regex, mounts, + list_nodes, list_fstype); + + if (node_regex) + regfree (node_regex); + if (fstype_regex) + regfree (fstype_regex); + + if (reverse) + rc_strlist_reverse (nodes); + + result = EXIT_FAILURE; + STRLIST_FOREACH (nodes, node, i) { + if (skip_regex && regexec (skip_regex, node, 0, NULL, 0) == 0) + continue; + printf ("%s\n", node); + result = EXIT_SUCCESS; + } + rc_strlist_free (nodes); + + if (skip_regex) + free (skip_regex); + + exit (result); } diff --git a/src/rc-depend.c b/src/rc-depend.c index c6d0356b..4c030fee 100644 --- a/src/rc-depend.c +++ b/src/rc-depend.c @@ -20,101 +20,89 @@ int main (int argc, char **argv) { - char **types = NULL; - char **services = NULL; - char **depends = NULL; - rc_depinfo_t *deptree = NULL; - rc_depinfo_t *di; - char *service; - int options = RC_DEP_TRACE; - bool first = true; - int i; - bool update = false; - char *runlevel = getenv ("RC_SOFTLEVEL"); - - if (! runlevel) - runlevel = rc_get_runlevel (); - - for (i = 1; i < argc; i++) - { - if (strcmp (argv[i], "--update") == 0) - { - if (! update) - { - rc_update_deptree (true); - update = true; - } - continue; - } - - if (strcmp (argv[i], "--strict") == 0) - { - options |= RC_DEP_STRICT; - continue; - } - - if (strcmp (argv[i], "--notrace") == 0) - { - options &= RC_DEP_TRACE; - continue; - } - - if (argv[i][0] == '-') - { - argv[i]++; - types = rc_strlist_add (types, argv[i]); - } - else - { - if ((deptree = rc_load_deptree ()) == NULL) - eerrorx ("failed to load deptree"); - - di = rc_get_depinfo (deptree, argv[i]); - if (! di) - eerror ("no dependency info for service `%s'", argv[i]); - else - services = rc_strlist_add (services, argv[i]); - } - } - - if (! services) - { - rc_strlist_free (types); - rc_free_deptree (deptree); - if (update) - return (EXIT_SUCCESS); - eerrorx ("no services specified"); - } - - /* If we don't have any types, then supply some defaults */ - if (! types) - { - types = rc_strlist_add (NULL, "ineed"); - rc_strlist_add (types, "iuse"); - } - - depends = rc_get_depends (deptree, types, services, runlevel, options); - - if (depends) - { - STRLIST_FOREACH (depends, service, i) - { - if (first) - first = false; - else - printf (" "); - - if (service) - printf ("%s", service); - - } - printf ("\n"); - } - - rc_strlist_free (types); - rc_strlist_free (services); - rc_strlist_free (depends); - rc_free_deptree (deptree); - - return (EXIT_SUCCESS); + char **types = NULL; + char **services = NULL; + char **depends = NULL; + rc_depinfo_t *deptree = NULL; + rc_depinfo_t *di; + char *service; + int options = RC_DEP_TRACE; + bool first = true; + int i; + bool update = false; + char *runlevel = getenv ("RC_SOFTLEVEL"); + + if (! runlevel) + runlevel = rc_get_runlevel (); + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--update") == 0) { + if (! update) { + rc_update_deptree (true); + update = true; + } + continue; + } + + if (strcmp (argv[i], "--strict") == 0) { + options |= RC_DEP_STRICT; + continue; + } + + if (strcmp (argv[i], "--notrace") == 0) { + options &= RC_DEP_TRACE; + continue; + } + + if (argv[i][0] == '-') { + argv[i]++; + types = rc_strlist_add (types, argv[i]); + } else { + if ((deptree = rc_load_deptree ()) == NULL) + eerrorx ("failed to load deptree"); + + di = rc_get_depinfo (deptree, argv[i]); + if (! di) + eerror ("no dependency info for service `%s'", argv[i]); + else + services = rc_strlist_add (services, argv[i]); + } + } + + if (! services) { + rc_strlist_free (types); + rc_free_deptree (deptree); + if (update) + return (EXIT_SUCCESS); + eerrorx ("no services specified"); + } + + /* If we don't have any types, then supply some defaults */ + if (! types) { + types = rc_strlist_add (NULL, "ineed"); + rc_strlist_add (types, "iuse"); + } + + depends = rc_get_depends (deptree, types, services, runlevel, options); + + if (depends) { + STRLIST_FOREACH (depends, service, i) { + if (first) + first = false; + else + printf (" "); + + if (service) + printf ("%s", service); + + } + printf ("\n"); + } + + rc_strlist_free (types); + rc_strlist_free (services); + rc_strlist_free (depends); + rc_free_deptree (deptree); + + return (EXIT_SUCCESS); } diff --git a/src/rc-plugin.c b/src/rc-plugin.c index f7cd3686..15ab149d 100644 --- a/src/rc-plugin.c +++ b/src/rc-plugin.c @@ -19,103 +19,94 @@ typedef struct plugin { - char *name; - void *handle; - int (*hook) (rc_hook_t hook, const char *name); - struct plugin *next; + char *name; + void *handle; + int (*hook) (rc_hook_t hook, const char *name); + struct plugin *next; } plugin_t; static plugin_t *plugins = NULL; void rc_plugin_load (void) { - char **files; - char *file; - int i; - plugin_t *plugin = plugins; - - /* Ensure some sanity here */ - rc_plugin_unload (); - - if (! rc_exists (RC_PLUGINDIR)) - return; - - files = rc_ls_dir (NULL, RC_PLUGINDIR, 0); - STRLIST_FOREACH (files, file, i) - { - char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL); - void *h = dlopen (p, RTLD_LAZY); - char *func; - void *f; - int len; - - if (! h) - { - eerror ("dlopen `%s': %s", p, dlerror ()); - free (p); - continue; - } - - func = file; - file = strsep (&func, "."); - len = strlen (file) + 7; - func = rc_xmalloc (sizeof (char *) * len); - snprintf (func, len, "_%s_hook", file); - - f = dlsym (h, func); - if (! f) - { - eerror ("`%s' does not expose the symbol `%s'", p, func); - dlclose (h); - } - else - { - if (plugin) - { - plugin->next = rc_xmalloc (sizeof (plugin_t)); - plugin = plugin->next; - } - else - plugin = plugins = rc_xmalloc (sizeof (plugin_t)); - - memset (plugin, 0, sizeof (plugin_t)); - plugin->name = strdup (file); - plugin->handle = h; - plugin->hook = f; - } - - free (func); - free (p); - } - - rc_strlist_free (files); + char **files; + char *file; + int i; + plugin_t *plugin = plugins; + + /* Ensure some sanity here */ + rc_plugin_unload (); + + if (! rc_exists (RC_PLUGINDIR)) + return; + + files = rc_ls_dir (NULL, RC_PLUGINDIR, 0); + STRLIST_FOREACH (files, file, i) { + char *p = rc_strcatpaths (RC_PLUGINDIR, file, NULL); + void *h = dlopen (p, RTLD_LAZY); + char *func; + void *f; + int len; + + if (! h) { + eerror ("dlopen `%s': %s", p, dlerror ()); + free (p); + continue; + } + + func = file; + file = strsep (&func, "."); + len = strlen (file) + 7; + func = rc_xmalloc (sizeof (char *) * len); + snprintf (func, len, "_%s_hook", file); + + f = dlsym (h, func); + if (! f) { + eerror ("`%s' does not expose the symbol `%s'", p, func); + dlclose (h); + } else { + if (plugin) { + plugin->next = rc_xmalloc (sizeof (plugin_t)); + plugin = plugin->next; + } else + plugin = plugins = rc_xmalloc (sizeof (plugin_t)); + + memset (plugin, 0, sizeof (plugin_t)); + plugin->name = strdup (file); + plugin->handle = h; + plugin->hook = f; + } + + free (func); + free (p); + } + + rc_strlist_free (files); } void rc_plugin_run (rc_hook_t hook, const char *value) { - plugin_t *plugin = plugins; + plugin_t *plugin = plugins; - while (plugin) - { - if (plugin->hook) - plugin->hook (hook, value); + while (plugin) { + if (plugin->hook) + plugin->hook (hook, value); - plugin = plugin->next; - } + plugin = plugin->next; + } } void rc_plugin_unload (void) { - plugin_t *plugin = plugins; - plugin_t *next; - - while (plugin) - { - next = plugin->next; - dlclose (plugin->handle); - free (plugin->name); - free (plugin); - plugin = next; - } - plugins = NULL; + plugin_t *plugin = plugins; + plugin_t *next; + + while (plugin) { + next = plugin->next; + dlclose (plugin->handle); + free (plugin->name); + free (plugin); + plugin = next; + } + plugins = NULL; } diff --git a/src/rc-status.c b/src/rc-status.c index f1ea52ee..0fcba811 100644 --- a/src/rc-status.c +++ b/src/rc-status.c @@ -18,125 +18,112 @@ static void print_level (char *level) { - printf ("Runlevel: "); - PEINFO_HILITE; - printf ("%s\n", level); - PEINFO_NORMAL; + printf ("Runlevel: "); + PEINFO_HILITE; + printf ("%s\n", level); + PEINFO_NORMAL; } static void print_service (char *service) { - char status[10]; - int cols = printf (" %s\n", service); - einfo_color_t color = einfo_bad; + char status[10]; + int cols = printf (" %s\n", service); + einfo_color_t color = einfo_bad; - if (rc_service_state (service, rc_service_stopping)) - snprintf (status, sizeof (status), "stopping "); - else if (rc_service_state (service, rc_service_starting)) - { - snprintf (status, sizeof (status), "starting "); - color = einfo_warn; - } - else if (rc_service_state (service, rc_service_inactive)) - { - snprintf (status, sizeof (status), "inactive "); - color = einfo_warn; - } - else if (geteuid () == 0 && rc_service_state (service, rc_service_crashed)) - snprintf (status, sizeof (status), " crashed "); - else if (rc_service_state (service, rc_service_started)) - { - snprintf (status, sizeof (status), " started "); - color = einfo_good; - } - else if (rc_service_state (service, rc_service_scheduled)) - { - snprintf (status, sizeof (status), "scheduled"); - color = einfo_warn; - } - else - snprintf (status, sizeof (status), " stopped "); - ebracket (cols, color, status); + if (rc_service_state (service, rc_service_stopping)) + snprintf (status, sizeof (status), "stopping "); + else if (rc_service_state (service, rc_service_starting)) { + snprintf (status, sizeof (status), "starting "); + color = einfo_warn; + } else if (rc_service_state (service, rc_service_inactive)) { + snprintf (status, sizeof (status), "inactive "); + color = einfo_warn; + } else if (geteuid () == 0 && rc_service_state (service, rc_service_crashed)) + snprintf (status, sizeof (status), " crashed "); + else if (rc_service_state (service, rc_service_started)) { + snprintf (status, sizeof (status), " started "); + color = einfo_good; + } else if (rc_service_state (service, rc_service_scheduled)) { + snprintf (status, sizeof (status), "scheduled"); + color = einfo_warn; + } else + snprintf (status, sizeof (status), " stopped "); + ebracket (cols, color, status); } int main (int argc, char **argv) { - char **levels = NULL; - char **services = NULL; - char *level; - char *service; - char c; - int option_index = 0; - int i; - int j; + char **levels = NULL; + char **services = NULL; + char *level; + char *service; + char c; + int option_index = 0; + int i; + int j; - const struct option longopts[] = - { - {"all", no_argument, NULL, 'a'}, - {"list", no_argument, NULL, 'l'}, - {"servicelist", no_argument, NULL, 's'}, - {"unused", no_argument, NULL, 'u'}, - {NULL, 0, NULL, 0} - }; + const struct option longopts[] = { + {"all", no_argument, NULL, 'a'}, + {"list", no_argument, NULL, 'l'}, + {"servicelist", no_argument, NULL, 's'}, + {"unused", no_argument, NULL, 'u'}, + {NULL, 0, NULL, 0} + }; - while ((c = getopt_long(argc, argv, "alsu", longopts, &option_index)) != -1) - switch (c) - { - case 'a': - levels = rc_get_runlevels (); - break; - case 'l': - levels = rc_get_runlevels (); - STRLIST_FOREACH (levels, level, i) - printf ("%s\n", level); - rc_strlist_free (levels); - exit (EXIT_SUCCESS); - case 's': - services = rc_services_in_runlevel (NULL); - STRLIST_FOREACH (services, service, i) - print_service (service); - rc_strlist_free (services); - exit (EXIT_SUCCESS); - case 'u': - services = rc_services_in_runlevel (NULL); - levels = rc_get_runlevels (); - STRLIST_FOREACH (services, service, i) - { - bool found = false; - STRLIST_FOREACH (levels, level, j) - if (rc_service_in_runlevel (service, level)) - { - found = true; - break; - } - if (! found) - print_service (service); - } - rc_strlist_free (levels); - rc_strlist_free (services); - exit (EXIT_SUCCESS); - case '?': - exit (EXIT_FAILURE); - default: - exit (EXIT_FAILURE); - } + while ((c = getopt_long(argc, argv, "alsu", longopts, &option_index)) != -1) + switch (c) { + case 'a': + levels = rc_get_runlevels (); + break; + case 'l': + levels = rc_get_runlevels (); + STRLIST_FOREACH (levels, level, i) + printf ("%s\n", level); + rc_strlist_free (levels); + exit (EXIT_SUCCESS); + case 's': + services = rc_services_in_runlevel (NULL); + STRLIST_FOREACH (services, service, i) + print_service (service); + rc_strlist_free (services); + exit (EXIT_SUCCESS); + case 'u': + services = rc_services_in_runlevel (NULL); + levels = rc_get_runlevels (); + STRLIST_FOREACH (services, service, i) { + bool found = false; + STRLIST_FOREACH (levels, level, j) + if (rc_service_in_runlevel (service, level)) { + found = true; + break; + } + if (! found) + print_service (service); + } + rc_strlist_free (levels); + rc_strlist_free (services); + exit (EXIT_SUCCESS); + case '?': + exit (EXIT_FAILURE); + default: + exit (EXIT_FAILURE); + } - while (optind < argc) - levels = rc_strlist_add (levels, argv[optind++]); + while (optind < argc) + levels = rc_strlist_add (levels, argv[optind++]); - if (! levels) - levels = rc_strlist_add (NULL, rc_get_runlevel ()); + if (! levels) + levels = rc_strlist_add (NULL, rc_get_runlevel ()); - STRLIST_FOREACH (levels, level, i) - { - print_level (level); - services = rc_services_in_runlevel (level); - STRLIST_FOREACH (services, service, j) - print_service (service); - rc_strlist_free (services); - } + STRLIST_FOREACH (levels, level, i) { + print_level (level); + services = rc_services_in_runlevel (level); + STRLIST_FOREACH (services, service, j) + print_service (service); + rc_strlist_free (services); + } - rc_strlist_free (levels); + rc_strlist_free (levels); - return (EXIT_SUCCESS); + return (EXIT_SUCCESS); } diff --git a/src/rc-update.c b/src/rc-update.c index 78054136..151cae6c 100644 --- a/src/rc-update.c +++ b/src/rc-update.c @@ -22,141 +22,130 @@ static char *applet = NULL; static bool add (const char *runlevel, const char *service) { - bool retval = true; - - if (! rc_runlevel_exists (runlevel)) - { - ewarn ("runlevel `%s' does not exist", runlevel); - return (false); - } - if (rc_service_in_runlevel (service, runlevel)) - { - ewarn ("%s already installed in runlevel `%s'; skipping", - service, runlevel); - return (false); - } - - if (rc_service_add (runlevel, service)) - einfo ("%s added to runlevel %s", service, runlevel); - else - { - eerror ("%s: failed to add service `%s' to runlevel `%s': %s", - applet, service, runlevel, strerror (errno)); - retval = false; - } - - return (retval); + bool retval = true; + + if (! rc_runlevel_exists (runlevel)) { + ewarn ("runlevel `%s' does not exist", runlevel); + return (false); + } + if (rc_service_in_runlevel (service, runlevel)) { + ewarn ("%s already installed in runlevel `%s'; skipping", + service, runlevel); + return (false); + } + + if (rc_service_add (runlevel, service)) + einfo ("%s added to runlevel %s", service, runlevel); + else { + eerror ("%s: failed to add service `%s' to runlevel `%s': %s", + applet, service, runlevel, strerror (errno)); + retval = false; + } + + return (retval); } int main (int argc, char **argv) { - int i; - int j; - char *service; - char **runlevels = NULL; - char *runlevel; - - applet = argv[0]; - if (argc < 2 || - strcmp (argv[1], "show") == 0 || - strcmp (argv[1], "-s") == 0) - { - bool verbose = false; - char **services = rc_services_in_runlevel (NULL); - - for (i = 2; i < argc; i++) - { - if (strcmp (argv[i], "--verbose") == 0 || - strcmp (argv[i], "-v") == 0) - verbose = true; - else - runlevels = rc_strlist_add (runlevels, argv[i]); - } - - if (! runlevels) - runlevels = rc_get_runlevels (); - - STRLIST_FOREACH (services, service, i) - { - char **in = NULL; - bool inone = false; - - STRLIST_FOREACH (runlevels, runlevel, j) - { - if (rc_service_in_runlevel (service, runlevel)) - { - in = rc_strlist_add (in, runlevel); - inone = true; - } - else - { - char buffer[PATH_MAX]; - memset (buffer, ' ', strlen (runlevel)); - buffer[strlen (runlevel)] = 0; - in = rc_strlist_add (in, buffer); - } - } - - if (! inone && ! verbose) - continue; - - printf (" %20s |", service); - STRLIST_FOREACH (in, runlevel, j) - printf (" %s", runlevel); - printf ("\n"); - } - - return (EXIT_SUCCESS); - } - - if (geteuid () != 0) - eerrorx ("%s: must be root to add or delete services from runlevels", - applet); - - if (! (service = argv[2])) - eerrorx ("%s: no service specified", applet); - - if (strcmp (argv[1], "add") == 0 || - strcmp (argv[1], "-a") == 0) - { - if (! service) - eerrorx ("%s: no service specified", applet); - if (! rc_service_exists (service)) - eerrorx ("%s: service `%s' does not exist", applet, service); - - if (argc < 4) - add (rc_get_runlevel (), service); - - for (i = 3; i < argc; i++) - add (argv[i], service); - - return (EXIT_SUCCESS); - } - - if (strcmp (argv[1], "delete") == 0 || - strcmp (argv[1], "del") == 0 || - strcmp (argv[1], "-d") == 0) - { - for (i = 3; i < argc; i++) - runlevels = rc_strlist_add (runlevels, argv[i]); - - if (! runlevels) - runlevels = rc_strlist_add (runlevels, rc_get_runlevel ()); - - STRLIST_FOREACH (runlevels, runlevel, i) - { - if (rc_service_in_runlevel (service, runlevel)) - { - if (rc_service_delete (runlevel, service)) - einfo ("%s removed from runlevel %s", service, runlevel); - else - eerror ("%s: failed to remove service `%s' from runlevel `%s': %s", - applet, service, runlevel, strerror (errno)); - } - } - - return (EXIT_SUCCESS); - } - - eerrorx ("%s: unknown command `%s'", applet, argv[1]); + int i; + int j; + char *service; + char **runlevels = NULL; + char *runlevel; + + applet = argv[0]; + if (argc < 2 || + strcmp (argv[1], "show") == 0 || + strcmp (argv[1], "-s") == 0) + { + bool verbose = false; + char **services = rc_services_in_runlevel (NULL); + + for (i = 2; i < argc; i++) { + if (strcmp (argv[i], "--verbose") == 0 || + strcmp (argv[i], "-v") == 0) + verbose = true; + else + runlevels = rc_strlist_add (runlevels, argv[i]); + } + + if (! runlevels) + runlevels = rc_get_runlevels (); + + STRLIST_FOREACH (services, service, i) { + char **in = NULL; + bool inone = false; + + STRLIST_FOREACH (runlevels, runlevel, j) { + if (rc_service_in_runlevel (service, runlevel)) { + in = rc_strlist_add (in, runlevel); + inone = true; + } else { + char buffer[PATH_MAX]; + memset (buffer, ' ', strlen (runlevel)); + buffer[strlen (runlevel)] = 0; + in = rc_strlist_add (in, buffer); + } + } + + if (! inone && ! verbose) + continue; + + printf (" %20s |", service); + STRLIST_FOREACH (in, runlevel, j) + printf (" %s", runlevel); + printf ("\n"); + } + + return (EXIT_SUCCESS); + } + + if (geteuid () != 0) + eerrorx ("%s: must be root to add or delete services from runlevels", + applet); + + if (! (service = argv[2])) + eerrorx ("%s: no service specified", applet); + + if (strcmp (argv[1], "add") == 0 || + strcmp (argv[1], "-a") == 0) + { + if (! service) + eerrorx ("%s: no service specified", applet); + if (! rc_service_exists (service)) + eerrorx ("%s: service `%s' does not exist", applet, service); + + if (argc < 4) + add (rc_get_runlevel (), service); + + for (i = 3; i < argc; i++) + add (argv[i], service); + + return (EXIT_SUCCESS); + } + + if (strcmp (argv[1], "delete") == 0 || + strcmp (argv[1], "del") == 0 || + strcmp (argv[1], "-d") == 0) + { + for (i = 3; i < argc; i++) + runlevels = rc_strlist_add (runlevels, argv[i]); + + if (! runlevels) + runlevels = rc_strlist_add (runlevels, rc_get_runlevel ()); + + STRLIST_FOREACH (runlevels, runlevel, i) { + if (rc_service_in_runlevel (service, runlevel)) { + if (rc_service_delete (runlevel, service)) + einfo ("%s removed from runlevel %s", service, runlevel); + else + eerror ("%s: failed to remove service `%s' from runlevel `%s': %s", + applet, service, runlevel, strerror (errno)); + } + } + + return (EXIT_SUCCESS); + } + + eerrorx ("%s: unknown command `%s'", applet, argv[1]); } diff --git a/src/rc.c b/src/rc.c index 5bfb3cfe..b5465d67 100644 --- a/src/rc.c +++ b/src/rc.c @@ -46,11 +46,9 @@ #define DEVBOOT "/dev/.rcboot" /* Cleanup anything in main */ -#define CHAR_FREE(_item) \ - if (_item) \ -{ \ - free (_item); \ - _item = NULL; \ +#define CHAR_FREE(_item) if (_item) { \ + free (_item); \ + _item = NULL; \ } extern char **environ; @@ -71,1142 +69,1066 @@ struct termios *termios_orig; static void cleanup (void) { - rc_plugin_unload (); - - if (termios_orig) - { - tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); - free (termios_orig); - } - - if (env) - rc_strlist_free (env); - if (newenv) - rc_strlist_free (newenv); - if (coldplugged_services) - rc_strlist_free (coldplugged_services); - if (stop_services) - rc_strlist_free (stop_services); - if (start_services) - rc_strlist_free (start_services); - if (deptree) - rc_free_deptree (deptree); - if (types) - rc_strlist_free (types); - if (mycmd) - free (mycmd); - if (myarg) - free (myarg); - - /* Clean runlevel start, stop markers */ - if (rc_is_dir (RC_SVCDIR "softscripts.new")) - rc_rm_dir (RC_SVCDIR "softscripts.new", true); - if (rc_is_dir (RC_SVCDIR "softscripts.old")) - rc_rm_dir (RC_SVCDIR "softscripts.old", true); - - if (applet) - free (applet); + rc_plugin_unload (); + + if (termios_orig) { + tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); + free (termios_orig); + } + + if (env) + rc_strlist_free (env); + if (newenv) + rc_strlist_free (newenv); + if (coldplugged_services) + rc_strlist_free (coldplugged_services); + if (stop_services) + rc_strlist_free (stop_services); + if (start_services) + rc_strlist_free (start_services); + if (deptree) + rc_free_deptree (deptree); + if (types) + rc_strlist_free (types); + if (mycmd) + free (mycmd); + if (myarg) + free (myarg); + + /* Clean runlevel start, stop markers */ + if (rc_is_dir (RC_SVCDIR "softscripts.new")) + rc_rm_dir (RC_SVCDIR "softscripts.new", true); + if (rc_is_dir (RC_SVCDIR "softscripts.old")) + rc_rm_dir (RC_SVCDIR "softscripts.old", true); + + if (applet) + free (applet); } static int do_e (int argc, char **argv) { - int retval = EXIT_SUCCESS; - int i; - int l = 0; - char *message = NULL; - char *p; - char *fmt = NULL; - - if (strcmp (applet, "eend") == 0 || - strcmp (applet, "ewend") == 0 || - strcmp (applet, "veend") == 0 || - strcmp (applet, "vweend") == 0) - { - if (argc > 0) - { - errno = 0; - retval = strtol (argv[0], NULL, 0); - if (errno != 0) - retval = EXIT_FAILURE; - else - { - argc--; - argv++; - } - } - else - retval = EXIT_FAILURE; - } - - if (argc > 0) - { - for (i = 0; i < argc; i++) - l += strlen (argv[i]) + 1; - - message = rc_xmalloc (l); - p = message; - - for (i = 0; i < argc; i++) - { - if (i > 0) - *p++ = ' '; - memcpy (p, argv[i], strlen (argv[i])); - p += strlen (argv[i]); - } - *p = 0; - } - - if (message) - fmt = strdup ("%s"); - - if (strcmp (applet, "einfo") == 0) - einfo (fmt, message); - else if (strcmp (applet, "einfon") == 0) - einfon (fmt, message); - else if (strcmp (applet, "ewarn") == 0) - ewarn (fmt, message); - else if (strcmp (applet, "ewarnn") == 0) - ewarnn (fmt, message); - else if (strcmp (applet, "eerror") == 0) - { - eerror (fmt, message); - retval = 1; - } - else if (strcmp (applet, "eerrorn") == 0) - { - eerrorn (fmt, message); - retval = 1; - } - else if (strcmp (applet, "ebegin") == 0) - ebegin (fmt, message); - else if (strcmp (applet, "eend") == 0) - eend (retval, fmt, message); - else if (strcmp (applet, "ewend") == 0) - ewend (retval, fmt, message); - else if (strcmp (applet, "veinfo") == 0) - einfov (fmt, message); - else if (strcmp (applet, "veinfon") == 0) - einfovn (fmt, message); - else if (strcmp (applet, "vewarn") == 0) - ewarnv (fmt, message); - else if (strcmp (applet, "vewarnn") == 0) - ewarnvn (fmt, message); - else if (strcmp (applet, "vebegin") == 0) - ebeginv (fmt, message); - else if (strcmp (applet, "veend") == 0) - eendv (retval, fmt, message); - else if (strcmp (applet, "vewend") == 0) - ewendv (retval, fmt, message); - else if (strcmp (applet, "eindent") == 0) - eindent (); - else if (strcmp (applet, "eoutdent") == 0) - eoutdent (); - else if (strcmp (applet, "veindent") == 0) - eindentv (); - else if (strcmp (applet, "veoutdent") == 0) - eoutdentv (); - else if (strcmp (applet, "eflush") == 0) - eflush (); - else - { - eerror ("%s: unknown applet", applet); - retval = EXIT_FAILURE; - } - - if (fmt) - free (fmt); - if (message) - free (message); - return (retval); + int retval = EXIT_SUCCESS; + int i; + int l = 0; + char *message = NULL; + char *p; + char *fmt = NULL; + + if (strcmp (applet, "eend") == 0 || + strcmp (applet, "ewend") == 0 || + strcmp (applet, "veend") == 0 || + strcmp (applet, "vweend") == 0) + { + if (argc > 0) { + errno = 0; + retval = strtol (argv[0], NULL, 0); + if (errno != 0) + retval = EXIT_FAILURE; + else { + argc--; + argv++; + } + } + else + retval = EXIT_FAILURE; + } + + if (argc > 0) { + for (i = 0; i < argc; i++) + l += strlen (argv[i]) + 1; + + message = rc_xmalloc (l); + p = message; + + for (i = 0; i < argc; i++) { + if (i > 0) + *p++ = ' '; + memcpy (p, argv[i], strlen (argv[i])); + p += strlen (argv[i]); + } + *p = 0; + } + + if (message) + fmt = strdup ("%s"); + + if (strcmp (applet, "einfo") == 0) + einfo (fmt, message); + else if (strcmp (applet, "einfon") == 0) + einfon (fmt, message); + else if (strcmp (applet, "ewarn") == 0) + ewarn (fmt, message); + else if (strcmp (applet, "ewarnn") == 0) + ewarnn (fmt, message); + else if (strcmp (applet, "eerror") == 0) { + eerror (fmt, message); + retval = 1; + } else if (strcmp (applet, "eerrorn") == 0) { + eerrorn (fmt, message); + retval = 1; + } else if (strcmp (applet, "ebegin") == 0) + ebegin (fmt, message); + else if (strcmp (applet, "eend") == 0) + eend (retval, fmt, message); + else if (strcmp (applet, "ewend") == 0) + ewend (retval, fmt, message); + else if (strcmp (applet, "veinfo") == 0) + einfov (fmt, message); + else if (strcmp (applet, "veinfon") == 0) + einfovn (fmt, message); + else if (strcmp (applet, "vewarn") == 0) + ewarnv (fmt, message); + else if (strcmp (applet, "vewarnn") == 0) + ewarnvn (fmt, message); + else if (strcmp (applet, "vebegin") == 0) + ebeginv (fmt, message); + else if (strcmp (applet, "veend") == 0) + eendv (retval, fmt, message); + else if (strcmp (applet, "vewend") == 0) + ewendv (retval, fmt, message); + else if (strcmp (applet, "eindent") == 0) + eindent (); + else if (strcmp (applet, "eoutdent") == 0) + eoutdent (); + else if (strcmp (applet, "veindent") == 0) + eindentv (); + else if (strcmp (applet, "veoutdent") == 0) + eoutdentv (); + else if (strcmp (applet, "eflush") == 0) + eflush (); + else { + eerror ("%s: unknown applet", applet); + retval = EXIT_FAILURE; + } + + if (fmt) + free (fmt); + if (message) + free (message); + return (retval); } static int do_service (int argc, char **argv) { - bool ok = false; - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no service specified", applet); - - if (strcmp (applet, "service_started") == 0) - ok = rc_service_state (argv[0], rc_service_started); - else if (strcmp (applet, "service_stopped") == 0) - ok = rc_service_state (argv[0], rc_service_stopped); - else if (strcmp (applet, "service_inactive") == 0) - ok = rc_service_state (argv[0], rc_service_inactive); - else if (strcmp (applet, "service_starting") == 0) - ok = rc_service_state (argv[0], rc_service_starting); - else if (strcmp (applet, "service_stopping") == 0) - ok = rc_service_state (argv[0], rc_service_stopping); - else if (strcmp (applet, "service_coldplugged") == 0) - ok = rc_service_state (argv[0], rc_service_coldplugged); - else if (strcmp (applet, "service_wasinactive") == 0) - ok = rc_service_state (argv[0], rc_service_wasinactive); - else if (strcmp (applet, "service_started_daemon") == 0) - { - int idx = 0; - if (argc > 2) - sscanf (argv[2], "%d", &idx); - exit (rc_service_started_daemon (argv[0], argv[1], idx) - ? 0 : 1); - } - else - eerrorx ("%s: unknown applet", applet); - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no service specified", applet); + + if (strcmp (applet, "service_started") == 0) + ok = rc_service_state (argv[0], rc_service_started); + else if (strcmp (applet, "service_stopped") == 0) + ok = rc_service_state (argv[0], rc_service_stopped); + else if (strcmp (applet, "service_inactive") == 0) + ok = rc_service_state (argv[0], rc_service_inactive); + else if (strcmp (applet, "service_starting") == 0) + ok = rc_service_state (argv[0], rc_service_starting); + else if (strcmp (applet, "service_stopping") == 0) + ok = rc_service_state (argv[0], rc_service_stopping); + else if (strcmp (applet, "service_coldplugged") == 0) + ok = rc_service_state (argv[0], rc_service_coldplugged); + else if (strcmp (applet, "service_wasinactive") == 0) + ok = rc_service_state (argv[0], rc_service_wasinactive); + else if (strcmp (applet, "service_started_daemon") == 0) { + int idx = 0; + if (argc > 2) + sscanf (argv[2], "%d", &idx); + exit (rc_service_started_daemon (argv[0], argv[1], idx) + ? 0 : 1); + } else + eerrorx ("%s: unknown applet", applet); + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static int do_mark_service (int argc, char **argv) { - bool ok = false; - char *svcname = getenv ("SVCNAME"); - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no service specified", applet); - - if (strcmp (applet, "mark_service_started") == 0) - ok = rc_mark_service (argv[0], rc_service_started); - else if (strcmp (applet, "mark_service_stopped") == 0) - ok = rc_mark_service (argv[0], rc_service_stopped); - else if (strcmp (applet, "mark_service_inactive") == 0) - ok = rc_mark_service (argv[0], rc_service_inactive); - else if (strcmp (applet, "mark_service_starting") == 0) - ok = rc_mark_service (argv[0], rc_service_starting); - else if (strcmp (applet, "mark_service_stopping") == 0) - ok = rc_mark_service (argv[0], rc_service_stopping); - else if (strcmp (applet, "mark_service_coldplugged") == 0) - ok = rc_mark_service (argv[0], rc_service_coldplugged); - else - eerrorx ("%s: unknown applet", applet); - - /* If we're marking ourselves then we need to inform our parent runscript - process so they do not mark us based on our exit code */ - if (ok && svcname && strcmp (svcname, argv[0]) == 0) - { - char *runscript_pid = getenv ("RC_RUNSCRIPT_PID"); - char *mtime; - pid_t pid = 0; - int l; - - if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1) - if (kill (pid, SIGHUP) != 0) - eerror ("%s: failed to signal parent %d: %s", - applet, pid, strerror (errno)); - - /* Remove the exclsive time test. This ensures that it's not - in control as well */ - l = strlen (RC_SVCDIR "exclusive") + - strlen (svcname) + - strlen (runscript_pid) + - 4; - mtime = rc_xmalloc (l); - snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s", - svcname, runscript_pid); - if (rc_exists (mtime) && unlink (mtime) != 0) - eerror ("%s: unlink: %s", applet, strerror (errno)); - free (mtime); - } - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + char *svcname = getenv ("SVCNAME"); + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no service specified", applet); + + if (strcmp (applet, "mark_service_started") == 0) + ok = rc_mark_service (argv[0], rc_service_started); + else if (strcmp (applet, "mark_service_stopped") == 0) + ok = rc_mark_service (argv[0], rc_service_stopped); + else if (strcmp (applet, "mark_service_inactive") == 0) + ok = rc_mark_service (argv[0], rc_service_inactive); + else if (strcmp (applet, "mark_service_starting") == 0) + ok = rc_mark_service (argv[0], rc_service_starting); + else if (strcmp (applet, "mark_service_stopping") == 0) + ok = rc_mark_service (argv[0], rc_service_stopping); + else if (strcmp (applet, "mark_service_coldplugged") == 0) + ok = rc_mark_service (argv[0], rc_service_coldplugged); + else + eerrorx ("%s: unknown applet", applet); + + /* If we're marking ourselves then we need to inform our parent runscript + process so they do not mark us based on our exit code */ + if (ok && svcname && strcmp (svcname, argv[0]) == 0) { + char *runscript_pid = getenv ("RC_RUNSCRIPT_PID"); + char *mtime; + pid_t pid = 0; + int l; + + if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1) + if (kill (pid, SIGHUP) != 0) + eerror ("%s: failed to signal parent %d: %s", + applet, pid, strerror (errno)); + + /* Remove the exclsive time test. This ensures that it's not + in control as well */ + l = strlen (RC_SVCDIR "exclusive") + + strlen (svcname) + + strlen (runscript_pid) + + 4; + mtime = rc_xmalloc (l); + snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s", + svcname, runscript_pid); + if (rc_exists (mtime) && unlink (mtime) != 0) + eerror ("%s: unlink: %s", applet, strerror (errno)); + free (mtime); + } + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static int do_options (int argc, char **argv) { - bool ok = false; - char *service = getenv ("SVCNAME"); - - if (! service) - eerrorx ("%s: no service specified", applet); - - if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) - eerrorx ("%s: no option specified", applet); - - if (strcmp (applet, "get_options") == 0) - { - char buffer[1024]; - memset (buffer, 0, 1024); - ok = rc_get_service_option (service, argv[0], buffer); - if (ok) - printf ("%s", buffer); - } - else if (strcmp (applet, "save_options") == 0) - ok = rc_set_service_option (service, argv[0], argv[1]); - else - eerrorx ("%s: unknown applet", applet); - - return (ok ? EXIT_SUCCESS : EXIT_FAILURE); + bool ok = false; + char *service = getenv ("SVCNAME"); + + if (! service) + eerrorx ("%s: no service specified", applet); + + if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0) + eerrorx ("%s: no option specified", applet); + + if (strcmp (applet, "get_options") == 0) { + char buffer[1024]; + memset (buffer, 0, 1024); + ok = rc_get_service_option (service, argv[0], buffer); + if (ok) + printf ("%s", buffer); + } else if (strcmp (applet, "save_options") == 0) + ok = rc_set_service_option (service, argv[0], argv[1]); + else + eerrorx ("%s: unknown applet", applet); + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static char read_key (bool block) { - struct termios termios; - char c = 0; - - if (! isatty (STDIN_FILENO)) - return (false); - - /* Now save our terminal settings. We need to restore them at exit as we - will be changing it for non-blocking reads for Interactive */ - if (! termios_orig) - { - termios_orig = rc_xmalloc (sizeof (struct termios)); - tcgetattr (STDIN_FILENO, termios_orig); - } - - tcgetattr (STDIN_FILENO, &termios); - termios.c_lflag &= ~(ICANON | ECHO); - if (block) - termios.c_cc[VMIN] = 1; - else - { - termios.c_cc[VMIN] = 0; - termios.c_cc[VTIME] = 0; - } - tcsetattr (STDIN_FILENO, TCSANOW, &termios); - - read (STDIN_FILENO, &c, 1); - - tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); - - return (c); + struct termios termios; + char c = 0; + + if (! isatty (STDIN_FILENO)) + return (false); + + /* Now save our terminal settings. We need to restore them at exit as we + will be changing it for non-blocking reads for Interactive */ + if (! termios_orig) { + termios_orig = rc_xmalloc (sizeof (struct termios)); + tcgetattr (STDIN_FILENO, termios_orig); + } + + tcgetattr (STDIN_FILENO, &termios); + termios.c_lflag &= ~(ICANON | ECHO); + if (block) + termios.c_cc[VMIN] = 1; + else { + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 0; + } + tcsetattr (STDIN_FILENO, TCSANOW, &termios); + + read (STDIN_FILENO, &c, 1); + + tcsetattr (STDIN_FILENO, TCSANOW, termios_orig); + + return (c); } static bool want_interactive (void) { - char c = read_key (false); - return ((c == 'I' || c == 'i') ? true : false); + char c = read_key (false); + return ((c == 'I' || c == 'i') ? true : false); } static void mark_interactive (void) { - FILE *fp = fopen (INTERACTIVE, "w"); - if (fp) - fclose (fp); + FILE *fp = fopen (INTERACTIVE, "w"); + if (fp) + fclose (fp); } static void sulogin (bool cont) { #ifdef __linux__ - if (cont) - { - int status = 0; - pid_t pid = fork(); - - if (pid == -1) - eerrorx ("%s: fork: %s", applet, strerror (errno)); - if (pid == 0) - { - newenv = rc_filter_env (); - mycmd = rc_xstrdup ("/sbin/sulogin"); - myarg = rc_xstrdup (getenv ("CONSOLE")); - execle (mycmd, mycmd, myarg, (char *) NULL, newenv); - eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); - } - waitpid (pid, &status, 0); - } - else - { - - newenv = rc_filter_env (); - mycmd = rc_xstrdup ("/sbin/sulogin"); - myarg = rc_xstrdup (getenv ("CONSOLE")); - execle (mycmd, mycmd, myarg, (char *) NULL, newenv); - eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); - } + if (cont) { + int status = 0; + pid_t pid = fork(); + + if (pid == -1) + eerrorx ("%s: fork: %s", applet, strerror (errno)); + if (pid == 0) { + newenv = rc_filter_env (); + mycmd = rc_xstrdup ("/sbin/sulogin"); + myarg = rc_xstrdup (getenv ("CONSOLE")); + execle (mycmd, mycmd, myarg, (char *) NULL, newenv); + eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); + } + waitpid (pid, &status, 0); + } else { + newenv = rc_filter_env (); + mycmd = rc_xstrdup ("/sbin/sulogin"); + myarg = rc_xstrdup (getenv ("CONSOLE")); + execle (mycmd, mycmd, myarg, (char *) NULL, newenv); + eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno)); + } #else - /* Appease gcc */ - cont = cont; - exit (EXIT_SUCCESS); + /* Appease gcc */ + exit (cont ? EXIT_FAILURE : EXIT_SUCCESS); #endif } static void set_ksoftlevel (const char *runlevel) { - FILE *fp; - - if (! runlevel || - strcmp (runlevel, RC_LEVEL_BOOT) == 0 || - strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || - strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) - { - if (rc_exists (RC_SVCDIR "ksoftlevel") && - unlink (RC_SVCDIR "ksoftlevel") != 0) - eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); - return; - } - - if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) - { - eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); - return; - } - - fprintf (fp, "%s", runlevel); - fclose (fp); + FILE *fp; + + if (! runlevel || + strcmp (runlevel, RC_LEVEL_BOOT) == 0 || + strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) + { + if (rc_exists (RC_SVCDIR "ksoftlevel") && + unlink (RC_SVCDIR "ksoftlevel") != 0) + eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); + return; + } + + if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) { + eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno)); + return; + } + + fprintf (fp, "%s", runlevel); + fclose (fp); } static void wait_for_services () { - int status = 0; - struct timeval tv; - while (wait (&status) != -1); - - /* Wait for a little bit to flush our ebuffer */ - tv.tv_usec = 50000; - tv.tv_sec = 0; - select (0, NULL, NULL, NULL, &tv); + int status = 0; + struct timeval tv; + while (wait (&status) != -1); + + /* Wait for a little bit to flush our ebuffer */ + tv.tv_usec = 50000; + tv.tv_sec = 0; + select (0, NULL, NULL, NULL, &tv); } static void handle_signal (int sig) { - int serrno = errno; - char signame[10] = { '\0' }; - - switch (sig) - { - case SIGINT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGINT"); - case SIGTERM: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGTERM"); - case SIGQUIT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGQUIT"); - eerrorx ("%s: caught %s, aborting", applet, signame); - - default: - eerror ("%s: caught unknown signal %d", applet, sig); - } - - /* Restore errno */ - errno = serrno; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGINT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGINT"); + case SIGTERM: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGTERM"); + case SIGQUIT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGQUIT"); + eerrorx ("%s: caught %s, aborting", applet, signame); + + default: + eerror ("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; } int main (int argc, char **argv) { - char *RUNLEVEL = NULL; - char *PREVLEVEL = NULL; - char *runlevel = NULL; - char *newlevel = NULL; - char *service = NULL; - char **deporder = NULL; - int i = 0; - int j = 0; - bool going_down = false; - bool interactive = false; - int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; - char ksoftbuffer [PATH_MAX]; - - if (argv[0]) - applet = strdup (basename (argv[0])); - - if (! applet) - eerrorx ("arguments required"); - - argc--; - argv++; - - /* Handle multicall stuff */ - if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) - exit (do_e (argc, argv)); - - if (strncmp (applet, "service_", strlen ("service_")) == 0) - exit (do_service (argc, argv)); - - if (strcmp (applet, "get_options") == 0 || - strcmp (applet, "save_options") == 0) - exit (do_options (argc, argv)); - - if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0) - exit (do_mark_service (argc, argv)); - - if (strcmp (applet, "is_runlevel_start") == 0) - exit (rc_runlevel_starting () ? 0 : 1); - else if (strcmp (applet, "is_runlevel_stop") == 0) - exit (rc_runlevel_stopping () ? 0 : 1); - else if (strcmp (applet, "color_terminal") == 0) - exit (colour_terminal () ? 0 : 1); - - if (strcmp (applet, "rc" ) != 0) - eerrorx ("%s: unknown applet", applet); - - /* OK, so we really are the main RC process - Only root should be able to run us */ - if (geteuid () != 0) - eerrorx ("%s: root access required", applet); - - atexit (cleanup); - newlevel = argv[0]; - - /* Setup a signal handler */ - signal (SIGINT, handle_signal); - signal (SIGQUIT, handle_signal); - signal (SIGTERM, handle_signal); - - /* Ensure our environment is pure - Also, add our configuration to it */ - env = rc_filter_env (); - env = rc_config_env (env); - - if (env) - { - char *p; + char *RUNLEVEL = NULL; + char *PREVLEVEL = NULL; + char *runlevel = NULL; + char *newlevel = NULL; + char *service = NULL; + char **deporder = NULL; + int i = 0; + int j = 0; + bool going_down = false; + bool interactive = false; + int depoptions = RC_DEP_STRICT | RC_DEP_TRACE; + char ksoftbuffer [PATH_MAX]; + + if (argv[0]) + applet = strdup (basename (argv[0])); + + if (! applet) + eerrorx ("arguments required"); + + argc--; + argv++; + + /* Handle multicall stuff */ + if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) + exit (do_e (argc, argv)); + + if (strncmp (applet, "service_", strlen ("service_")) == 0) + exit (do_service (argc, argv)); + + if (strcmp (applet, "get_options") == 0 || + strcmp (applet, "save_options") == 0) + exit (do_options (argc, argv)); + + if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0) + exit (do_mark_service (argc, argv)); + + if (strcmp (applet, "is_runlevel_start") == 0) + exit (rc_runlevel_starting () ? 0 : 1); + else if (strcmp (applet, "is_runlevel_stop") == 0) + exit (rc_runlevel_stopping () ? 0 : 1); + else if (strcmp (applet, "color_terminal") == 0) + exit (colour_terminal () ? 0 : 1); + + if (strcmp (applet, "rc" ) != 0) + eerrorx ("%s: unknown applet", applet); + + /* OK, so we really are the main RC process + Only root should be able to run us */ + if (geteuid () != 0) + eerrorx ("%s: root access required", applet); + + atexit (cleanup); + newlevel = argv[0]; + + /* Setup a signal handler */ + signal (SIGINT, handle_signal); + signal (SIGQUIT, handle_signal); + signal (SIGTERM, handle_signal); + + /* Ensure our environment is pure + Also, add our configuration to it */ + env = rc_filter_env (); + env = rc_config_env (env); + + if (env) { + char *p; #ifdef __linux__ - /* clearenv isn't portable, but there's no harm in using it - if we have it */ - clearenv (); + /* clearenv isn't portable, but there's no harm in using it + if we have it */ + clearenv (); #else - char *var; - /* No clearenv present here then. - We could manipulate environ directly ourselves, but it seems that - some kernels bitch about this according to the environ man pages - so we walk though environ and call unsetenv for each value. */ - while (environ[0]) - { - tmp = rc_xstrdup (environ[0]); - p = tmp; - var = strsep (&p, "="); - unsetenv (var); - free (tmp); - } - tmp = NULL; + char *var; + /* No clearenv present here then. + We could manipulate environ directly ourselves, but it seems that + some kernels bitch about this according to the environ man pages + so we walk though environ and call unsetenv for each value. */ + while (environ[0]) { + tmp = rc_xstrdup (environ[0]); + p = tmp; + var = strsep (&p, "="); + unsetenv (var); + free (tmp); + } + tmp = NULL; #endif - STRLIST_FOREACH (env, p, i) - if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0) - putenv (p); - - /* We don't free our list as that would be null in environ */ - } - - /* Enable logging */ - setenv ("RC_ELOG", "rc", 1); - - interactive = rc_exists (INTERACTIVE); - rc_plugin_load (); - - /* RUNLEVEL is set by sysvinit as is a magic number - RC_SOFTLEVEL is set by us and is the name for this magic number - even though all our userland documentation refers to runlevel */ - RUNLEVEL = getenv ("RUNLEVEL"); - PREVLEVEL = getenv ("PREVLEVEL"); - - if (RUNLEVEL && newlevel) - { - if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) - { - /* OK, we're either in runlevel 1 or single user mode */ - if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) - { - struct utsname uts; - pid_t pid; - pid_t wpid; - int status = 0; + STRLIST_FOREACH (env, p, i) + if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0) + putenv (p); + + /* We don't free our list as that would be null in environ */ + } + + /* Enable logging */ + setenv ("RC_ELOG", "rc", 1); + + interactive = rc_exists (INTERACTIVE); + rc_plugin_load (); + + /* RUNLEVEL is set by sysvinit as is a magic number + RC_SOFTLEVEL is set by us and is the name for this magic number + even though all our userland documentation refers to runlevel */ + RUNLEVEL = getenv ("RUNLEVEL"); + PREVLEVEL = getenv ("PREVLEVEL"); + + if (RUNLEVEL && newlevel) { + if (strcmp (RUNLEVEL, "S") == 0 || strcmp (RUNLEVEL, "1") == 0) { + /* OK, we're either in runlevel 1 or single user mode */ + if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0) { + struct utsname uts; + pid_t pid; + pid_t wpid; + int status = 0; #ifdef __linux__ - FILE *fp; + FILE *fp; #endif - uname (&uts); - - printf ("\n"); - PEINFO_GOOD; - printf (" Gentoo/%s; ", uts.sysname); - PEINFO_BRACKET; - printf ("http://www.gentoo.org/"); - PEINFO_NORMAL; - printf ("\n Copyright 1999-2007 Gentoo Foundation; " - "Distributed under the GPLv2\n\n"); - - printf ("Press "); - PEINFO_GOOD; - printf ("I"); - PEINFO_NORMAL; - printf (" to enter interactive boot mode\n\n"); - - setenv ("RC_SOFTLEVEL", newlevel, 1); - rc_plugin_run (rc_hook_runlevel_start_in, newlevel); - - if ((pid = fork ()) == -1) - eerrorx ("%s: fork: %s", applet, strerror (errno)); - - if (pid == 0) - { - mycmd = rc_xstrdup (INITSH); - execl (mycmd, mycmd, (char *) NULL); - eerrorx ("%s: unable to exec `" INITSH "': %s", - applet, strerror (errno)); - } - - do - { - wpid = waitpid (pid, &status, 0); - if (wpid < 1) - eerror ("waitpid: %s", strerror (errno)); - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0) - exit (EXIT_FAILURE); - - /* If we requested a softlevel, save it now */ + uname (&uts); + + printf ("\n"); + PEINFO_GOOD; + printf (" Gentoo/%s; ", uts.sysname); + PEINFO_BRACKET; + printf ("http://www.gentoo.org/"); + PEINFO_NORMAL; + printf ("\n Copyright 1999-2007 Gentoo Foundation; " + "Distributed under the GPLv2\n\n"); + + printf ("Press "); + PEINFO_GOOD; + printf ("I"); + PEINFO_NORMAL; + printf (" to enter interactive boot mode\n\n"); + + setenv ("RC_SOFTLEVEL", newlevel, 1); + rc_plugin_run (rc_hook_runlevel_start_in, newlevel); + + if ((pid = fork ()) == -1) + eerrorx ("%s: fork: %s", applet, strerror (errno)); + + if (pid == 0) { + mycmd = rc_xstrdup (INITSH); + execl (mycmd, mycmd, (char *) NULL); + eerrorx ("%s: unable to exec `" INITSH "': %s", + applet, strerror (errno)); + } + + do { + wpid = waitpid (pid, &status, 0); + if (wpid < 1) + eerror ("waitpid: %s", strerror (errno)); + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0) + exit (EXIT_FAILURE); + + /* If we requested a softlevel, save it now */ #ifdef __linux__ - set_ksoftlevel (NULL); - - if ((fp = fopen ("/proc/cmdline", "r"))) - { - char buffer[RC_LINEBUFFER]; - char *soft; - - memset (buffer, 0, sizeof (buffer)); - if (fgets (buffer, RC_LINEBUFFER, fp) && - (soft = strstr (buffer, "softlevel="))) - { - i = soft - buffer; - if (i == 0 || buffer[i - 1] == ' ') - { - char *level; - - /* Trim the trailing carriage return if present */ - i = strlen (buffer) - 1; - if (buffer[i] == '\n') - buffer[i] = 0; - - soft += strlen ("softlevel="); - level = strsep (&soft, " "); - set_ksoftlevel (level); - } - } - fclose (fp); - } + set_ksoftlevel (NULL); + + if ((fp = fopen ("/proc/cmdline", "r"))) { + char buffer[RC_LINEBUFFER]; + char *soft; + + memset (buffer, 0, sizeof (buffer)); + if (fgets (buffer, RC_LINEBUFFER, fp) && + (soft = strstr (buffer, "softlevel="))) + { + i = soft - buffer; + if (i == 0 || buffer[i - 1] == ' ') { + char *level; + + /* Trim the trailing carriage return if present */ + i = strlen (buffer) - 1; + if (buffer[i] == '\n') + buffer[i] = 0; + + soft += strlen ("softlevel="); + level = strsep (&soft, " "); + set_ksoftlevel (level); + } + } + fclose (fp); + } #endif - rc_plugin_run (rc_hook_runlevel_start_out, newlevel); + rc_plugin_run (rc_hook_runlevel_start_out, newlevel); - if (want_interactive ()) - mark_interactive (); + if (want_interactive ()) + mark_interactive (); - exit (EXIT_SUCCESS); - } + exit (EXIT_SUCCESS); + } #ifdef __linux__ - /* Parse the inittab file so we can work out the level to telinit */ - if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 && - strcmp (newlevel, RC_LEVEL_SINGLE) != 0) - { - char **inittab = rc_get_list (NULL, "/etc/inittab"); - char *line; - char *p; - char *token; - char lvl[2] = {0, 0}; - - STRLIST_FOREACH (inittab, line, i) - { - p = line; - token = strsep (&p, ":"); - if (! token || token[0] != 'l') - continue; - - if ((token = strsep (&p, ":")) == NULL) - continue; - - /* Snag the level */ - lvl[0] = token[0]; - - /* The name is spaced after this */ - if ((token = strsep (&p, " ")) == NULL) - continue; - - if ((token = strsep (&p, " ")) == NULL) - continue; - - if (strcmp (token, newlevel) == 0) - break; - } - rc_strlist_free (inittab); - - /* We have a level, so telinit into it */ - if (lvl[0] == 0) - { - eerrorx ("%s: couldn't find a runlevel called `%s'", - applet, newlevel); - } - else - { - mycmd = rc_xstrdup ("/sbin/telinit"); - myarg = rc_xstrdup (lvl); - execl (mycmd, mycmd, myarg, (char *) NULL); - eerrorx ("%s: unable to exec `/sbin/telinit': %s", - applet, strerror (errno)); - } - } + /* Parse the inittab file so we can work out the level to telinit */ + if (strcmp (newlevel, RC_LEVEL_BOOT) != 0 && + strcmp (newlevel, RC_LEVEL_SINGLE) != 0) + { + char **inittab = rc_get_list (NULL, "/etc/inittab"); + char *line; + char *p; + char *token; + char lvl[2] = {0, 0}; + + STRLIST_FOREACH (inittab, line, i) { + p = line; + token = strsep (&p, ":"); + if (! token || token[0] != 'l') + continue; + + if ((token = strsep (&p, ":")) == NULL) + continue; + + /* Snag the level */ + lvl[0] = token[0]; + + /* The name is spaced after this */ + if ((token = strsep (&p, " ")) == NULL) + continue; + + if ((token = strsep (&p, " ")) == NULL) + continue; + + if (strcmp (token, newlevel) == 0) + break; + } + rc_strlist_free (inittab); + + /* We have a level, so telinit into it */ + if (lvl[0] == 0) { + eerrorx ("%s: couldn't find a runlevel called `%s'", + applet, newlevel); + } else { + mycmd = rc_xstrdup ("/sbin/telinit"); + myarg = rc_xstrdup (lvl); + execl (mycmd, mycmd, myarg, (char *) NULL); + eerrorx ("%s: unable to exec `/sbin/telinit': %s", + applet, strerror (errno)); + } + } #endif - } - } - - /* Check we're in the runlevel requested, ie from - rc single - rc shutdown - rc reboot - */ - if (newlevel) - { - if (myarg) - { - free (myarg); - myarg = NULL; - } - - if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) - { - if (! RUNLEVEL || - (strcmp (RUNLEVEL, "S") != 0 && - strcmp (RUNLEVEL, "1") != 0)) - { - /* Remember the current runlevel for when we come back */ - set_ksoftlevel (runlevel); + } + } + + /* Check we're in the runlevel requested, ie from + rc single + rc shutdown + rc reboot + */ + if (newlevel) { + if (myarg) { + free (myarg); + myarg = NULL; + } + + if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) { + if (! RUNLEVEL || + (strcmp (RUNLEVEL, "S") != 0 && + strcmp (RUNLEVEL, "1") != 0)) + { + /* Remember the current runlevel for when we come back */ + set_ksoftlevel (runlevel); #ifdef __linux__ - mycmd = rc_xstrdup ("/sbin/telinit"); - myarg = rc_xstrdup ("S"); - execl (mycmd, mycmd, myarg, (char *) NULL); - eerrorx ("%s: unable to exec `/%s': %s", - mycmd, applet, strerror (errno)); + mycmd = rc_xstrdup ("/sbin/telinit"); + myarg = rc_xstrdup ("S"); + execl (mycmd, mycmd, myarg, (char *) NULL); + eerrorx ("%s: unable to exec `/%s': %s", + mycmd, applet, strerror (errno)); #else - if (kill (1, SIGTERM) != 0) - eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s", - applet, strerror (errno)); - exit (EXIT_SUCCESS); + if (kill (1, SIGTERM) != 0) + eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s", + applet, strerror (errno)); + exit (EXIT_SUCCESS); #endif - } - } - else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) - { - if (! RUNLEVEL || - strcmp (RUNLEVEL, "6") != 0) - { - mycmd = rc_xstrdup ("/sbin/shutdown"); - myarg = rc_xstrdup ("-r"); - tmp = rc_xstrdup ("now"); - execl (mycmd, mycmd, myarg, tmp, (char *) NULL); - eerrorx ("%s: unable to exec `%s': %s", - mycmd, applet, strerror (errno)); - } - } - else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) - { - if (! RUNLEVEL || - strcmp (RUNLEVEL, "0") != 0) - { - mycmd = rc_xstrdup ("/sbin/shutdown"); + } + } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) { + if (! RUNLEVEL || + strcmp (RUNLEVEL, "6") != 0) + { + mycmd = rc_xstrdup ("/sbin/shutdown"); + myarg = rc_xstrdup ("-r"); + tmp = rc_xstrdup ("now"); + execl (mycmd, mycmd, myarg, tmp, (char *) NULL); + eerrorx ("%s: unable to exec `%s': %s", + mycmd, applet, strerror (errno)); + } + } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) { + if (! RUNLEVEL || + strcmp (RUNLEVEL, "0") != 0) + { + mycmd = rc_xstrdup ("/sbin/shutdown"); #ifdef __linux__ - myarg = rc_xstrdup ("-h"); + myarg = rc_xstrdup ("-h"); #else - myarg = rc_xstrdup ("-p"); + myarg = rc_xstrdup ("-p"); #endif - tmp = rc_xstrdup ("now"); - execl (mycmd, mycmd, myarg, tmp, (char *) NULL); - eerrorx ("%s: unable to exec `%s': %s", - mycmd, applet, strerror (errno)); - } - } - } - - /* Export our current softlevel */ - runlevel = rc_get_runlevel (); - - /* If we're in the default runlevel and ksoftlevel exists, we should use - that instead */ - if (newlevel && - rc_exists (RC_SVCDIR "ksoftlevel") && - strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) - { - /* We should only use ksoftlevel if we were in single user mode - If not, we need to erase ksoftlevel now. */ - if (PREVLEVEL && - (strcmp (PREVLEVEL, "1") == 0 || - strcmp (PREVLEVEL, "S") == 0 || - strcmp (PREVLEVEL, "N") == 0)) - { - FILE *fp; - - if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) - eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", - strerror (errno)); - else - { - if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) - { - i = strlen (ksoftbuffer) - 1; - if (ksoftbuffer[i] == '\n') - ksoftbuffer[i] = 0; - newlevel = ksoftbuffer; - } - fclose (fp); - } - } - else - set_ksoftlevel (NULL); - } - - if (newlevel && - (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || - strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp (newlevel, RC_LEVEL_SINGLE) == 0)) - { - going_down = true; - rc_set_runlevel (newlevel); - setenv ("RC_SOFTLEVEL", newlevel, 1); - rc_plugin_run (rc_hook_runlevel_stop_in, newlevel); - } - else - { - rc_plugin_run (rc_hook_runlevel_stop_in, runlevel); - } - - /* Check if runlevel is valid if we're changing */ - if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) - { - tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL); - if (! rc_is_dir (tmp)) - eerrorx ("%s: is not a valid runlevel", newlevel); - CHAR_FREE (tmp); - } - - /* Load our deptree now */ - if ((deptree = rc_load_deptree ()) == NULL) - eerrorx ("failed to load deptree"); - - /* Clean the failed services state dir now */ - if (rc_is_dir (RC_SVCDIR "failed")) - rc_rm_dir (RC_SVCDIR "failed", false); - - mkdir (RC_SVCDIR "/softscripts.new", 0755); + tmp = rc_xstrdup ("now"); + execl (mycmd, mycmd, myarg, tmp, (char *) NULL); + eerrorx ("%s: unable to exec `%s': %s", + mycmd, applet, strerror (errno)); + } + } + } + + /* Export our current softlevel */ + runlevel = rc_get_runlevel (); + + /* If we're in the default runlevel and ksoftlevel exists, we should use + that instead */ + if (newlevel && + rc_exists (RC_SVCDIR "ksoftlevel") && + strcmp (newlevel, RC_LEVEL_DEFAULT) == 0) + { + /* We should only use ksoftlevel if we were in single user mode + If not, we need to erase ksoftlevel now. */ + if (PREVLEVEL && + (strcmp (PREVLEVEL, "1") == 0 || + strcmp (PREVLEVEL, "S") == 0 || + strcmp (PREVLEVEL, "N") == 0)) + { + FILE *fp; + + if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) + eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", + strerror (errno)); + else { + if (fgets (ksoftbuffer, sizeof (ksoftbuffer), fp)) { + i = strlen (ksoftbuffer) - 1; + if (ksoftbuffer[i] == '\n') + ksoftbuffer[i] = 0; + newlevel = ksoftbuffer; + } + fclose (fp); + } + } else + set_ksoftlevel (NULL); + } + + if (newlevel && + (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 || + strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp (newlevel, RC_LEVEL_SINGLE) == 0)) + { + going_down = true; + rc_set_runlevel (newlevel); + setenv ("RC_SOFTLEVEL", newlevel, 1); + rc_plugin_run (rc_hook_runlevel_stop_in, newlevel); + } else { + rc_plugin_run (rc_hook_runlevel_stop_in, runlevel); + } + + /* Check if runlevel is valid if we're changing */ + if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) { + tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL); + if (! rc_is_dir (tmp)) + eerrorx ("%s: is not a valid runlevel", newlevel); + CHAR_FREE (tmp); + } + + /* Load our deptree now */ + if ((deptree = rc_load_deptree ()) == NULL) + eerrorx ("failed to load deptree"); + + /* Clean the failed services state dir now */ + if (rc_is_dir (RC_SVCDIR "failed")) + rc_rm_dir (RC_SVCDIR "failed", false); + + mkdir (RC_SVCDIR "/softscripts.new", 0755); #ifdef __linux__ - /* udev likes to start services before we're ready when it does - its coldplugging thing. runscript knows when we're not ready so it - stores a list of coldplugged services in DEVBOOT for us to pick up - here when we are ready for them */ - if (rc_is_dir (DEVBOOT)) - { - start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD); - rc_rm_dir (DEVBOOT, true); - - STRLIST_FOREACH (start_services, service, i) - if (rc_allow_plug (service)) - rc_mark_service (service, rc_service_coldplugged); - /* We need to dump this list now. - This may seem redunant, but only Linux needs this and saves on - code bloat. */ - rc_strlist_free (start_services); - start_services = NULL; - } + /* udev likes to start services before we're ready when it does + its coldplugging thing. runscript knows when we're not ready so it + stores a list of coldplugged services in DEVBOOT for us to pick up + here when we are ready for them */ + if (rc_is_dir (DEVBOOT)) { + start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD); + rc_rm_dir (DEVBOOT, true); + + STRLIST_FOREACH (start_services, service, i) + if (rc_allow_plug (service)) + rc_mark_service (service, rc_service_coldplugged); + /* We need to dump this list now. + This may seem redunant, but only Linux needs this and saves on + code bloat. */ + rc_strlist_free (start_services); + start_services = NULL; + } #else - /* BSD's on the other hand populate /dev automagically and use devd. - The only downside of this approach and ours is that we have to hard code - the device node to the init script to simulate the coldplug into - runlevel for our dependency tree to work. */ - if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 && - (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || - strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) && - rc_is_env ("RC_COLDPLUG", "yes")) - { - /* The net interfaces are easy - they're all in net /dev/net :) */ - start_services = rc_ls_dir (NULL, "/dev/net", 0); - STRLIST_FOREACH (start_services, service, i) - { - j = (strlen ("net.") + strlen (service) + 1); - tmp = rc_xmalloc (sizeof (char *) * j); - snprintf (tmp, j, "net.%s", service); - if (rc_service_exists (tmp) && rc_allow_plug (tmp)) - rc_mark_service (tmp, rc_service_coldplugged); - CHAR_FREE (tmp); - } - rc_strlist_free (start_services); - - /* The mice are a little more tricky. - If we coldplug anything else, we'll probably do it here. */ - start_services = rc_ls_dir (NULL, "/dev", 0); - STRLIST_FOREACH (start_services, service, i) - { - if (strncmp (service, "psm", 3) == 0 || - strncmp (service, "ums", 3) == 0) - { - char *p = service + 3; - if (p && isdigit (*p)) - { - j = (strlen ("moused.") + strlen (service) + 1); - tmp = rc_xmalloc (sizeof (char *) * j); - snprintf (tmp, j, "moused.%s", service); - if (rc_service_exists (tmp) && rc_allow_plug (tmp)) - rc_mark_service (tmp, rc_service_coldplugged); - CHAR_FREE (tmp); - } - } - } - rc_strlist_free (start_services); - start_services = NULL; - } + /* BSD's on the other hand populate /dev automagically and use devd. + The only downside of this approach and ours is that we have to hard code + the device node to the init script to simulate the coldplug into + runlevel for our dependency tree to work. */ + if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0 && + (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 || + strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) && + rc_is_env ("RC_COLDPLUG", "yes")) + { + /* The net interfaces are easy - they're all in net /dev/net :) */ + start_services = rc_ls_dir (NULL, "/dev/net", 0); + STRLIST_FOREACH (start_services, service, i) { + j = (strlen ("net.") + strlen (service) + 1); + tmp = rc_xmalloc (sizeof (char *) * j); + snprintf (tmp, j, "net.%s", service); + if (rc_service_exists (tmp) && rc_allow_plug (tmp)) + rc_mark_service (tmp, rc_service_coldplugged); + CHAR_FREE (tmp); + } + rc_strlist_free (start_services); + + /* The mice are a little more tricky. + If we coldplug anything else, we'll probably do it here. */ + start_services = rc_ls_dir (NULL, "/dev", 0); + STRLIST_FOREACH (start_services, service, i) { + if (strncmp (service, "psm", 3) == 0 || + strncmp (service, "ums", 3) == 0) + { + char *p = service + 3; + if (p && isdigit (*p)) { + j = (strlen ("moused.") + strlen (service) + 1); + tmp = rc_xmalloc (sizeof (char *) * j); + snprintf (tmp, j, "moused.%s", service); + if (rc_service_exists (tmp) && rc_allow_plug (tmp)) + rc_mark_service (tmp, rc_service_coldplugged); + CHAR_FREE (tmp); + } + } + } + rc_strlist_free (start_services); + start_services = NULL; + } #endif - /* Build a list of all services to stop and then work out the - correct order for stopping them */ - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD); - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD); - stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD); - - types = rc_strlist_add (NULL, "ineed"); - types = rc_strlist_add (types, "iuse"); - types = rc_strlist_add (types, "iafter"); - deporder = rc_get_depends (deptree, types, stop_services, - runlevel, depoptions); - rc_strlist_free (stop_services); - rc_strlist_free (types); - stop_services = deporder; - deporder = NULL; - types = NULL; - rc_strlist_reverse (stop_services); - - /* Load our list of coldplugged services */ - coldplugged_services = rc_ls_dir (coldplugged_services, - RC_SVCDIR_COLDPLUGGED, RC_LS_INITD); - - /* Load our start services now. - We have different rules dependent on runlevel. */ - if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) - { - if (coldplugged_services) - { - einfon ("Device initiated services:"); - STRLIST_FOREACH (coldplugged_services, service, i) - { - printf (" %s", service); - start_services = rc_strlist_add (start_services, service); - } - printf ("\n"); - } - tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel, - (char *) NULL); - start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); - CHAR_FREE (tmp); - } - else - { - /* Store our list of coldplugged services */ - coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED, - RC_LS_INITD); - if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 && - strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && - strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) - { - /* We need to include the boot runlevel services if we're not in it */ - start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT, - RC_LS_INITD); - STRLIST_FOREACH (coldplugged_services, service, i) - start_services = rc_strlist_add (start_services, service); - - tmp = rc_strcatpaths (RC_RUNLEVELDIR, - newlevel ? newlevel : runlevel, (char *) NULL); - start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); - CHAR_FREE (tmp); - } - } - - /* Save out softlevel now */ - if (going_down) - rc_set_runlevel (newlevel); - - types = rc_strlist_add (NULL, "needsme"); - types = rc_strlist_add (types, "usesme"); - /* Now stop the services that shouldn't be running */ - STRLIST_FOREACH (stop_services, service, i) - { - bool found = false; - char *conf = NULL; - char **stopdeps = NULL; - char *svc1 = NULL; - char *svc2 = NULL; - int k; - - if (rc_service_state (service, rc_service_stopped)) - continue; - - /* We always stop the service when in these runlevels */ - if (going_down) - { - rc_stop_service (service); - continue; - } - - /* If we're in the start list then don't bother stopping us */ - STRLIST_FOREACH (start_services, svc1, j) - if (strcmp (svc1, service) == 0) - { - found = true; - break; - } - - /* Unless we would use a different config file */ - if (found) - { - int len; - if (! newlevel) - continue; - - len = strlen (service) + strlen (runlevel) + 2; - tmp = rc_xmalloc (sizeof (char *) * len); - snprintf (tmp, len, "%s.%s", service, runlevel); - conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); - found = rc_exists (conf); - CHAR_FREE (conf); - CHAR_FREE (tmp); - if (! found) - { - len = strlen (service) + strlen (newlevel) + 2; - tmp = rc_xmalloc (sizeof (char *) * len); - snprintf (tmp, len, "%s.%s", service, newlevel); - conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); - found = rc_exists (conf); - CHAR_FREE (conf); - CHAR_FREE (tmp); - if (!found) - continue; - } - } - else - /* Allow coldplugged services not to be in the runlevels list */ - { - if (rc_service_state (service, rc_service_coldplugged)) - continue; - } - - /* We got this far! Or last check is to see if any any service that - going to be started depends on us */ - stopdeps = rc_strlist_add (stopdeps, service); - deporder = rc_get_depends (deptree, types, stopdeps, - runlevel, RC_DEP_STRICT); - rc_strlist_free (stopdeps); - stopdeps = NULL; - found = false; - STRLIST_FOREACH (deporder, svc1, j) - { - STRLIST_FOREACH (start_services, svc2, k) - if (strcmp (svc1, svc2) == 0) - { - found = true; - break; - } - if (found) - break; - } - rc_strlist_free (deporder); - deporder = NULL; - - /* After all that we can finally stop the blighter! */ - if (! found) - rc_stop_service (service); - } - rc_strlist_free (types); - types = NULL; - - /* Wait for our services to finish */ - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - wait_for_services (); - - /* Notify the plugins we have finished */ - rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); - - rmdir (RC_SVCDIR "/softscripts.new"); - - /* Store the new runlevel */ - if (newlevel) - { - rc_set_runlevel (newlevel); - runlevel = newlevel; - setenv ("RC_SOFTLEVEL", runlevel, 1); - } - - /* Run the halt script if needed */ - if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp (runlevel, RC_LEVEL_REBOOT) == 0) - { - mycmd = rc_xstrdup (HALTSH); - myarg = rc_xstrdup (runlevel); - execl (mycmd, mycmd, myarg, (char *) NULL); - eerrorx ("%s: unable to exec `%s': %s", - applet, HALTSH, strerror (errno)); - } - - /* Single user is done now */ - if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) - { - if (rc_exists (INTERACTIVE)) - unlink (INTERACTIVE); - sulogin (false); - } - - mkdir (RC_SVCDIR "softscripts.old", 0755); - rc_plugin_run (rc_hook_runlevel_start_in, runlevel); - - /* Re-add our coldplugged services if they stopped */ - STRLIST_FOREACH (coldplugged_services, service, i) - rc_mark_service (service, rc_service_coldplugged); - - /* Order the services to start */ - types = rc_strlist_add (NULL, "ineed"); - types = rc_strlist_add (types, "iuse"); - types = rc_strlist_add (types, "iafter"); - deporder = rc_get_depends (deptree, types, start_services, - runlevel, depoptions); - rc_strlist_free (types); - types = NULL; - rc_strlist_free (start_services); - start_services = deporder; - deporder = NULL; - - STRLIST_FOREACH (start_services, service, i) - { - if (rc_service_state (service, rc_service_stopped)) - { - if (! interactive) - interactive = want_interactive (); - - if (interactive) - { + /* Build a list of all services to stop and then work out the + correct order for stopping them */ + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD); + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD); + stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD); + + types = rc_strlist_add (NULL, "ineed"); + types = rc_strlist_add (types, "iuse"); + types = rc_strlist_add (types, "iafter"); + deporder = rc_get_depends (deptree, types, stop_services, + runlevel, depoptions); + rc_strlist_free (stop_services); + rc_strlist_free (types); + stop_services = deporder; + deporder = NULL; + types = NULL; + rc_strlist_reverse (stop_services); + + /* Load our list of coldplugged services */ + coldplugged_services = rc_ls_dir (coldplugged_services, + RC_SVCDIR_COLDPLUGGED, RC_LS_INITD); + + /* Load our start services now. + We have different rules dependent on runlevel. */ + if (newlevel && strcmp (newlevel, RC_LEVEL_BOOT) == 0) { + if (coldplugged_services) { + einfon ("Device initiated services:"); + STRLIST_FOREACH (coldplugged_services, service, i) { + printf (" %s", service); + start_services = rc_strlist_add (start_services, service); + } + printf ("\n"); + } + tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel, + (char *) NULL); + start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); + CHAR_FREE (tmp); + } else { + /* Store our list of coldplugged services */ + coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED, + RC_LS_INITD); + if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 && + strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 && + strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0) + { + /* We need to include the boot runlevel services if we're not in it */ + start_services = rc_ls_dir (start_services, RC_RUNLEVELDIR RC_LEVEL_BOOT, + RC_LS_INITD); + STRLIST_FOREACH (coldplugged_services, service, i) + start_services = rc_strlist_add (start_services, service); + + tmp = rc_strcatpaths (RC_RUNLEVELDIR, + newlevel ? newlevel : runlevel, (char *) NULL); + start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD); + CHAR_FREE (tmp); + } + } + + /* Save out softlevel now */ + if (going_down) + rc_set_runlevel (newlevel); + + types = rc_strlist_add (NULL, "needsme"); + types = rc_strlist_add (types, "usesme"); + /* Now stop the services that shouldn't be running */ + STRLIST_FOREACH (stop_services, service, i) { + bool found = false; + char *conf = NULL; + char **stopdeps = NULL; + char *svc1 = NULL; + char *svc2 = NULL; + int k; + + if (rc_service_state (service, rc_service_stopped)) + continue; + + /* We always stop the service when in these runlevels */ + if (going_down) { + rc_stop_service (service); + continue; + } + + /* If we're in the start list then don't bother stopping us */ + STRLIST_FOREACH (start_services, svc1, j) + if (strcmp (svc1, service) == 0) { + found = true; + break; + } + + /* Unless we would use a different config file */ + if (found) { + int len; + if (! newlevel) + continue; + + len = strlen (service) + strlen (runlevel) + 2; + tmp = rc_xmalloc (sizeof (char *) * len); + snprintf (tmp, len, "%s.%s", service, runlevel); + conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); + found = rc_exists (conf); + CHAR_FREE (conf); + CHAR_FREE (tmp); + if (! found) { + len = strlen (service) + strlen (newlevel) + 2; + tmp = rc_xmalloc (sizeof (char *) * len); + snprintf (tmp, len, "%s.%s", service, newlevel); + conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL); + found = rc_exists (conf); + CHAR_FREE (conf); + CHAR_FREE (tmp); + if (!found) + continue; + } + } else { + /* Allow coldplugged services not to be in the runlevels list */ + if (rc_service_state (service, rc_service_coldplugged)) + continue; + } + + /* We got this far! Or last check is to see if any any service that + going to be started depends on us */ + stopdeps = rc_strlist_add (stopdeps, service); + deporder = rc_get_depends (deptree, types, stopdeps, + runlevel, RC_DEP_STRICT); + rc_strlist_free (stopdeps); + stopdeps = NULL; + found = false; + STRLIST_FOREACH (deporder, svc1, j) { + STRLIST_FOREACH (start_services, svc2, k) + if (strcmp (svc1, svc2) == 0) { + found = true; + break; + } + if (found) + break; + } + rc_strlist_free (deporder); + deporder = NULL; + + /* After all that we can finally stop the blighter! */ + if (! found) + rc_stop_service (service); + } + rc_strlist_free (types); + types = NULL; + + /* Wait for our services to finish */ + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) + wait_for_services (); + + /* Notify the plugins we have finished */ + rc_plugin_run (rc_hook_runlevel_stop_out, runlevel); + + rmdir (RC_SVCDIR "/softscripts.new"); + + /* Store the new runlevel */ + if (newlevel) { + rc_set_runlevel (newlevel); + runlevel = newlevel; + setenv ("RC_SOFTLEVEL", runlevel, 1); + } + + /* Run the halt script if needed */ + if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp (runlevel, RC_LEVEL_REBOOT) == 0) + { + mycmd = rc_xstrdup (HALTSH); + myarg = rc_xstrdup (runlevel); + execl (mycmd, mycmd, myarg, (char *) NULL); + eerrorx ("%s: unable to exec `%s': %s", + applet, HALTSH, strerror (errno)); + } + + /* Single user is done now */ + if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) { + if (rc_exists (INTERACTIVE)) + unlink (INTERACTIVE); + sulogin (false); + } + + mkdir (RC_SVCDIR "softscripts.old", 0755); + rc_plugin_run (rc_hook_runlevel_start_in, runlevel); + + /* Re-add our coldplugged services if they stopped */ + STRLIST_FOREACH (coldplugged_services, service, i) + rc_mark_service (service, rc_service_coldplugged); + + /* Order the services to start */ + types = rc_strlist_add (NULL, "ineed"); + types = rc_strlist_add (types, "iuse"); + types = rc_strlist_add (types, "iafter"); + deporder = rc_get_depends (deptree, types, start_services, + runlevel, depoptions); + rc_strlist_free (types); + types = NULL; + rc_strlist_free (start_services); + start_services = deporder; + deporder = NULL; + + STRLIST_FOREACH (start_services, service, i) { + if (rc_service_state (service, rc_service_stopped)) { + if (! interactive) + interactive = want_interactive (); + + if (interactive) { interactive_retry: - printf ("\n"); - einfo ("About to start the service %s", service); - eindent (); - einfo ("1) Start the service\t\t2) Skip the service"); - einfo ("3) Continue boot process\t\t4) Exit to shell"); - eoutdent (); + printf ("\n"); + einfo ("About to start the service %s", service); + eindent (); + einfo ("1) Start the service\t\t2) Skip the service"); + einfo ("3) Continue boot process\t\t4) Exit to shell"); + eoutdent (); interactive_option: - switch (read_key (true)) - { - case '1': break; - case '2': continue; - case '3': interactive = false; break; - case '4': sulogin (true); goto interactive_retry; - default: goto interactive_option; - } - } - rc_start_service (service); - } - } - - /* Wait for our services to finish */ - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - wait_for_services (); - - rc_plugin_run (rc_hook_runlevel_start_out, runlevel); - - /* Store our interactive status for boot */ - if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0) - mark_interactive (); - else - { - if (rc_exists (INTERACTIVE)) - unlink (INTERACTIVE); - } - - return (EXIT_SUCCESS); + switch (read_key (true)) { + case '1': break; + case '2': continue; + case '3': interactive = false; break; + case '4': sulogin (true); goto interactive_retry; + default: goto interactive_option; + } + } + rc_start_service (service); + } + } + + /* Wait for our services to finish */ + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) + wait_for_services (); + + rc_plugin_run (rc_hook_runlevel_start_out, runlevel); + + /* Store our interactive status for boot */ + if (interactive && strcmp (runlevel, RC_LEVEL_BOOT) == 0) + mark_interactive (); + else { + if (rc_exists (INTERACTIVE)) + unlink (INTERACTIVE); + } + + return (EXIT_SUCCESS); } diff --git a/src/rc.h b/src/rc.h index b6c8cdb1..ef05c4d8 100644 --- a/src/rc.h +++ b/src/rc.h @@ -25,16 +25,16 @@ typedef enum { - rc_service_started, - rc_service_stopped, - rc_service_starting, - rc_service_stopping, - rc_service_inactive, - rc_service_wasinactive, - rc_service_coldplugged, - rc_service_failed, - rc_service_scheduled, - rc_service_crashed + rc_service_started, + rc_service_stopped, + rc_service_starting, + rc_service_stopping, + rc_service_inactive, + rc_service_wasinactive, + rc_service_coldplugged, + rc_service_failed, + rc_service_scheduled, + rc_service_crashed } rc_service_state_t; char *rc_resolve_service (const char *service); @@ -45,19 +45,19 @@ bool rc_mark_service (const char *service, rc_service_state_t state); pid_t rc_stop_service (const char *service); pid_t rc_start_service (const char *service); void rc_schedule_start_service (const char *service, - const char *service_to_start); + const char *service_to_start); char **rc_services_scheduled_by (const char *service); void rc_schedule_clear (const char *service); bool rc_wait_service (const char *service); bool rc_get_service_option (const char *service, const char *option, - char *value); + char *value); bool rc_set_service_option (const char *service, const char *option, - const char *value); + const char *value); void rc_set_service_daemon (const char *service, const char *exec, - const char *name, const char *pidfile, - bool started); + const char *name, const char *pidfile, + bool started); bool rc_service_started_daemon (const char *service, const char *exec, - int indx); + int indx); bool rc_allow_plug (char *service); @@ -75,7 +75,7 @@ char **rc_services_scheduled (const char *service); /* Find pids based on criteria - free the pointer returned after use */ pid_t *rc_find_pids (const char *exec, const char *cmd, - uid_t uid, pid_t pid); + uid_t uid, pid_t pid); /* Checks that all daemons started with start-stop-daemon by the service are still running. If so, return false otherwise true. You should check that the service has been started before calling this. */ @@ -84,16 +84,16 @@ bool rc_service_daemons_crashed (const char *service); /* Dependency tree structs and functions. */ typedef struct rc_deptype { - char *type; - char **services; - struct rc_deptype *next; + char *type; + char **services; + struct rc_deptype *next; } rc_deptype_t; typedef struct rc_depinfo { - char *service; - rc_deptype_t *depends; - struct rc_depinfo *next; + char *service; + rc_deptype_t *depends; + struct rc_depinfo *next; } rc_depinfo_t; @@ -110,14 +110,14 @@ rc_depinfo_t *rc_load_deptree (void); rc_depinfo_t *rc_get_depinfo (rc_depinfo_t *deptree, const char *service); rc_deptype_t *rc_get_deptype (rc_depinfo_t *depinfo, const char *type); char **rc_get_depends (rc_depinfo_t *deptree, char **types, - char **services, const char *runlevel, int options); + char **services, const char *runlevel, int options); /* List all the services that should be started, in order, the the given runlevel, including sysinit and boot services where approriate. If reboot, shutdown or single are given then we list all the services we that we need to shutdown in order. */ char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel, - int options); + int options); void rc_free_deptree (rc_depinfo_t *deptree); @@ -134,19 +134,19 @@ void rc_free_deptree (rc_depinfo_t *deptree); when we have done it as may start scheduled services at this point. */ typedef enum { - rc_hook_runlevel_stop_in = 1, - rc_hook_runlevel_stop_out = 4, - rc_hook_runlevel_start_in = 5, - rc_hook_runlevel_start_out = 8, - /* We reserved a few numbers if we need rc_runlevel_stop_now and done */ - rc_hook_service_stop_in = 101, - rc_hook_service_stop_now, - rc_hook_service_stop_done, - rc_hook_service_stop_out, - rc_hook_service_start_in, - rc_hook_service_start_now, - rc_hook_service_start_done, - rc_hook_service_start_out + rc_hook_runlevel_stop_in = 1, + rc_hook_runlevel_stop_out = 4, + rc_hook_runlevel_start_in = 5, + rc_hook_runlevel_start_out = 8, + /* We reserved a few numbers if we need rc_runlevel_stop_now and done */ + rc_hook_service_stop_in = 101, + rc_hook_service_stop_now, + rc_hook_service_stop_done, + rc_hook_service_stop_out, + rc_hook_service_start_in, + rc_hook_service_start_now, + rc_hook_service_start_done, + rc_hook_service_start_out } rc_hook_t; /* RC utility functions. diff --git a/src/runscript.c b/src/runscript.c index a36b264e..76ecd586 100644 --- a/src/runscript.c +++ b/src/runscript.c @@ -65,1056 +65,977 @@ void setup_selinux (int argc, char **argv); #ifdef __linux__ void setup_selinux (int argc, char **argv) { - void *lib_handle = NULL; - - lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); - if (lib_handle) - { - /* FIXME: the below code generates the warning - ISO C forbids assignment between function pointer and 'void *' - which sucks ass + void *lib_handle = NULL; + + lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); + if (lib_handle) { + /* FIXME: the below code generates the warning + ISO C forbids assignment between function pointer and 'void *' + which sucks ass http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html */ - selinux_run_init_old = dlsym (lib_handle, "selinux_runscript"); - selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2"); - - /* Use new run_init if it rc_exists, else fall back to old */ - if (selinux_run_init_new) - selinux_run_init_new (argc, argv); - else if (selinux_run_init_old) - selinux_run_init_old (); - else - /* This shouldnt happen... probably corrupt lib */ - eerrorx ("run_init is missing from runscript_selinux.so!"); - } + selinux_run_init_old = dlsym (lib_handle, "selinux_runscript"); + selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2"); + + /* Use new run_init if it rc_exists, else fall back to old */ + if (selinux_run_init_new) + selinux_run_init_new (argc, argv); + else if (selinux_run_init_old) + selinux_run_init_old (); + else + /* This shouldnt happen... probably corrupt lib */ + eerrorx ("run_init is missing from runscript_selinux.so!"); + } } #endif static void handle_signal (int sig) { - pid_t pid; - int status; - int serrno = errno; - char signame[10] = { '\0' }; - - switch (sig) - { - case SIGHUP: - sighup = true; - break; - - case SIGCHLD: - do - { - pid = waitpid (-1, &status, WNOHANG); - if (pid < 0) - { - if (errno != ECHILD) - eerror ("waitpid: %s", strerror (errno)); - return; - } - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - break; - - case SIGINT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGINT"); - case SIGTERM: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGTERM"); - case SIGQUIT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGQUIT"); - eerrorx ("%s: caught %s, aborting", applet, signame); - - default: - eerror ("%s: caught unknown signal %d", applet, sig); - } - - /* Restore errno */ - errno = serrno; + pid_t pid; + int status; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGHUP: + sighup = true; + break; + + case SIGCHLD: + do { + pid = waitpid (-1, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + eerror ("waitpid: %s", strerror (errno)); + return; + } + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + break; + + case SIGINT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGINT"); + case SIGTERM: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGTERM"); + case SIGQUIT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGQUIT"); + eerrorx ("%s: caught %s, aborting", applet, signame); + + default: + eerror ("%s: caught unknown signal %d", applet, sig); + } + + /* Restore errno */ + errno = serrno; } static time_t get_mtime (const char *pathname, bool follow_link) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if (! pathname) - return (0); + if (! pathname) + return (0); - retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf); - if (! retval) - return (buf.st_mtime); + retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf); + if (! retval) + return (buf.st_mtime); - errno = 0; - return (0); + errno = 0; + return (0); } static bool in_control () { - char *path; - time_t mtime; - const char *tests[] = { "starting", "started", "stopping", - "inactive", "wasinactive", NULL }; - int i = 0; - - if (sighup) - return (false); - - if (! mtime_test || ! rc_exists (mtime_test)) - return (false); - - if (rc_service_state (applet, rc_service_stopped)) - return (false); - - if (! (mtime = get_mtime (mtime_test, false))) - return (false); - - while (tests[i]) - { - path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL); - if (rc_exists (path)) - { - time_t m = get_mtime (path, false); - if (mtime < m && m != 0) - { - free (path); - return (false); - } - } - free (path); - i++; - } - - return (true); + char *path; + time_t mtime; + const char *tests[] = { "starting", "started", "stopping", + "inactive", "wasinactive", NULL }; + int i = 0; + + if (sighup) + return (false); + + if (! mtime_test || ! rc_exists (mtime_test)) + return (false); + + if (rc_service_state (applet, rc_service_stopped)) + return (false); + + if (! (mtime = get_mtime (mtime_test, false))) + return (false); + + while (tests[i]) { + path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL); + if (rc_exists (path)) { + time_t m = get_mtime (path, false); + if (mtime < m && m != 0) { + free (path); + return (false); + } + } + free (path); + i++; + } + + return (true); } static void uncoldplug (char *service) { - char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", basename (service), - (char *) NULL); - if (rc_exists (cold) && unlink (cold) != 0) - eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno)); - free (cold); + char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", basename (service), + (char *) NULL); + if (rc_exists (cold) && unlink (cold) != 0) + eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno)); + free (cold); } static void cleanup (void) { - /* Flush our buffered output if any */ - eflush (); - - if (hook_out) - rc_plugin_run (hook_out, applet); - rc_plugin_unload (); - - if (deptree) - rc_free_deptree (deptree); - if (services) - rc_strlist_free (services); - if (types) - rc_strlist_free (types); - if (svclist) - rc_strlist_free (svclist); - if (providelist) - rc_strlist_free (providelist); - if (restart_services) - rc_strlist_free (restart_services); - if (need_services) - rc_strlist_free (need_services); - if (tmplist) - rc_strlist_free (tmplist); - if (mycmd) - free (mycmd); - if (myarg1) - free (myarg1); - if (myarg2) - free (myarg2); - if (ibsave) - free (ibsave); - - if (in_control ()) - { - if (rc_service_state (applet, rc_service_stopping)) - { - /* If the we're shutting down, do it cleanly */ - if ((softlevel && - rc_runlevel_stopping () && - (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 || - strcmp (softlevel, RC_LEVEL_REBOOT) == 0))) - rc_mark_service (applet, rc_service_stopped); - else if (rc_service_state (applet, rc_service_wasinactive)) - rc_mark_service (applet, rc_service_inactive); - else - rc_mark_service (applet, rc_service_started); - } - else if (rc_service_state (applet, rc_service_starting)) - { - if (rc_service_state (applet, rc_service_wasinactive)) - rc_mark_service (applet, rc_service_inactive); - else - rc_mark_service (applet, rc_service_stopped); - } - if (exclusive && rc_exists (exclusive)) - unlink (exclusive); - } - - if (env) - rc_strlist_free (env); - - if (mtime_test) - { - unlink (mtime_test); - free (mtime_test); - } - if (exclusive) - free (exclusive); - - if (applet) - free (applet); + /* Flush our buffered output if any */ + eflush (); + + if (hook_out) + rc_plugin_run (hook_out, applet); + rc_plugin_unload (); + + if (deptree) + rc_free_deptree (deptree); + if (services) + rc_strlist_free (services); + if (types) + rc_strlist_free (types); + if (svclist) + rc_strlist_free (svclist); + if (providelist) + rc_strlist_free (providelist); + if (restart_services) + rc_strlist_free (restart_services); + if (need_services) + rc_strlist_free (need_services); + if (tmplist) + rc_strlist_free (tmplist); + if (mycmd) + free (mycmd); + if (myarg1) + free (myarg1); + if (myarg2) + free (myarg2); + if (ibsave) + free (ibsave); + + if (in_control ()) { + if (rc_service_state (applet, rc_service_stopping)) { + /* If the we're shutting down, do it cleanly */ + if ((softlevel && + rc_runlevel_stopping () && + (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 || + strcmp (softlevel, RC_LEVEL_REBOOT) == 0))) + rc_mark_service (applet, rc_service_stopped); + else if (rc_service_state (applet, rc_service_wasinactive)) + rc_mark_service (applet, rc_service_inactive); + else + rc_mark_service (applet, rc_service_started); + } + else if (rc_service_state (applet, rc_service_starting)) + { + if (rc_service_state (applet, rc_service_wasinactive)) + rc_mark_service (applet, rc_service_inactive); + else + rc_mark_service (applet, rc_service_stopped); + } + if (exclusive && rc_exists (exclusive)) + unlink (exclusive); + } + + if (env) + rc_strlist_free (env); + + if (mtime_test) + { + unlink (mtime_test); + free (mtime_test); + } + if (exclusive) + free (exclusive); + + if (applet) + free (applet); } static bool svc_exec (const char *service, const char *arg1, const char *arg2) { - int status = 0; - pid_t pid; - - /* We need to disable our child signal handler now so we block - until our script returns. */ - signal (SIGCHLD, NULL); - - pid = fork(); - - if (pid == -1) - eerrorx ("%s: fork: %s", service, strerror (errno)); - if (pid == 0) - { - mycmd = rc_xstrdup (service); - myarg1 = rc_xstrdup (arg1); - if (arg2) - myarg2 = rc_xstrdup (arg2); - - if (rc_exists (RC_SVCDIR "runscript.sh")) - { - execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2, - (char *) NULL); - eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s", - service, strerror (errno)); - } - else - { - execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2, - (char *) NULL); - eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s", - service, strerror (errno)); - } - } - - do - { - if (waitpid (pid, &status, 0) < 0) - { - if (errno != ECHILD) - eerror ("waitpid: %s", strerror (errno)); - break; - } - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - /* Done, so restore the signal handler */ - signal (SIGCHLD, handle_signal); - - if (WIFEXITED (status)) - return (WEXITSTATUS (status) ? false : true); - - return (false); + int status = 0; + pid_t pid; + + /* We need to disable our child signal handler now so we block + until our script returns. */ + signal (SIGCHLD, NULL); + + pid = fork(); + + if (pid == -1) + eerrorx ("%s: fork: %s", service, strerror (errno)); + if (pid == 0) { + mycmd = rc_xstrdup (service); + myarg1 = rc_xstrdup (arg1); + if (arg2) + myarg2 = rc_xstrdup (arg2); + + if (rc_exists (RC_SVCDIR "runscript.sh")) { + execl (RC_SVCDIR "runscript.sh", mycmd, mycmd, myarg1, myarg2, + (char *) NULL); + eerrorx ("%s: exec `" RC_SVCDIR "runscript.sh': %s", + service, strerror (errno)); + } else { + execl (RC_LIBDIR "sh/runscript.sh", mycmd, mycmd, myarg1, myarg2, + (char *) NULL); + eerrorx ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s", + service, strerror (errno)); + } + } + + do { + if (waitpid (pid, &status, 0) < 0) { + if (errno != ECHILD) + eerror ("waitpid: %s", strerror (errno)); + break; + } + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + /* Done, so restore the signal handler */ + signal (SIGCHLD, handle_signal); + + if (WIFEXITED (status)) + return (WEXITSTATUS (status) ? false : true); + + return (false); } static rc_service_state_t svc_status (const char *service) { - char status[10]; - int (*e) (const char *fmt, ...) = &einfo; - - rc_service_state_t retval = rc_service_stopped; - - if (rc_service_state (service, rc_service_stopping)) - { - snprintf (status, sizeof (status), "stopping"); - e = &ewarn; - retval = rc_service_stopping; - } - else if (rc_service_state (service, rc_service_starting)) - { - snprintf (status, sizeof (status), "starting"); - e = &ewarn; - retval = rc_service_starting; - } - else if (rc_service_state (service, rc_service_inactive)) - { - snprintf (status, sizeof (status), "inactive"); - e = &ewarn; - retval = rc_service_inactive; - } - else if (rc_service_state (service, rc_service_crashed)) - { - snprintf (status, sizeof (status), "crashed"); - e = &eerror; - retval = rc_service_crashed; - } - else if (rc_service_state (service, rc_service_started)) - { - snprintf (status, sizeof (status), "started"); - retval = rc_service_started; - } - else - snprintf (status, sizeof (status), "stopped"); - - e ("status: %s", status); - return (retval); + char status[10]; + int (*e) (const char *fmt, ...) = &einfo; + + rc_service_state_t retval = rc_service_stopped; + + if (rc_service_state (service, rc_service_stopping)) { + snprintf (status, sizeof (status), "stopping"); + e = &ewarn; + retval = rc_service_stopping; + } else if (rc_service_state (service, rc_service_starting)) { + snprintf (status, sizeof (status), "starting"); + e = &ewarn; + retval = rc_service_starting; + } else if (rc_service_state (service, rc_service_inactive)) { + snprintf (status, sizeof (status), "inactive"); + e = &ewarn; + retval = rc_service_inactive; + } else if (rc_service_state (service, rc_service_crashed)) { + snprintf (status, sizeof (status), "crashed"); + e = &eerror; + retval = rc_service_crashed; + } else if (rc_service_state (service, rc_service_started)) { + snprintf (status, sizeof (status), "started"); + retval = rc_service_started; + } else + snprintf (status, sizeof (status), "stopped"); + + e ("status: %s", status); + return (retval); } static void make_exclusive (const char *service) { - char *path; - int i; - - /* We create a fifo so that other services can wait until we complete */ - if (! exclusive) - exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL); - - if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST && - (errno != EACCES || geteuid () == 0)) - eerrorx ("%s: unable to create fifo `%s': %s", - applet, exclusive, strerror (errno)); - - path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL); - i = strlen (path) + 16; - mtime_test = rc_xmalloc (sizeof (char *) * i); - snprintf (mtime_test, i, "%s.%d", path, getpid ()); - free (path); - - if (rc_exists (mtime_test) && unlink (mtime_test) != 0) - { - eerror ("%s: unlink `%s': %s", - applet, mtime_test, strerror (errno)); - free (mtime_test); - mtime_test = NULL; - return; - } - - if (symlink (service, mtime_test) != 0) - { - eerror ("%s: symlink `%s' to `%s': %s", - applet, service, mtime_test, strerror (errno)); - free (mtime_test); - mtime_test = NULL; - } + char *path; + int i; + + /* We create a fifo so that other services can wait until we complete */ + if (! exclusive) + exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL); + + if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST && + (errno != EACCES || geteuid () == 0)) + eerrorx ("%s: unable to create fifo `%s': %s", + applet, exclusive, strerror (errno)); + + path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL); + i = strlen (path) + 16; + mtime_test = rc_xmalloc (sizeof (char *) * i); + snprintf (mtime_test, i, "%s.%d", path, getpid ()); + free (path); + + if (rc_exists (mtime_test) && unlink (mtime_test) != 0) { + eerror ("%s: unlink `%s': %s", + applet, mtime_test, strerror (errno)); + free (mtime_test); + mtime_test = NULL; + return; + } + + if (symlink (service, mtime_test) != 0) { + eerror ("%s: symlink `%s' to `%s': %s", + applet, service, mtime_test, strerror (errno)); + free (mtime_test); + mtime_test = NULL; + } } static void unlink_mtime_test () { - if (unlink (mtime_test) != 0) - eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno)); - free (mtime_test); - mtime_test = NULL; + if (unlink (mtime_test) != 0) + eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno)); + free (mtime_test); + mtime_test = NULL; } static void get_started_services () { - char *service; - int i; + char *service; + int i; - rc_strlist_free (tmplist); - tmplist = rc_services_in_state (rc_service_inactive); + rc_strlist_free (tmplist); + tmplist = rc_services_in_state (rc_service_inactive); - rc_strlist_free (restart_services); - restart_services = rc_services_in_state (rc_service_started); + rc_strlist_free (restart_services); + restart_services = rc_services_in_state (rc_service_started); - STRLIST_FOREACH (tmplist, service, i) - restart_services = rc_strlist_addsort (restart_services, service); + STRLIST_FOREACH (tmplist, service, i) + restart_services = rc_strlist_addsort (restart_services, service); - rc_strlist_free (tmplist); - tmplist = NULL; + rc_strlist_free (tmplist); + tmplist = NULL; } static void svc_start (const char *service, bool deps) { - bool started; - bool background = false; - char *svc; - char *svc2; - int i; - int j; - int depoptions = RC_DEP_TRACE; - - rc_plugin_run (rc_hook_service_start_in, applet); - hook_out = rc_hook_service_start_out; - - if (rc_is_env ("RC_STRICT_DEPEND", "yes")) - depoptions |= RC_DEP_STRICT; - - if (rc_is_env ("IN_HOTPLUG", "1") || in_background) - { - if (! rc_service_state (service, rc_service_inactive)) - exit (EXIT_FAILURE); - background = true; - } - - if (rc_service_state (service, rc_service_started)) - ewarnx ("WARNING: %s has already been started", applet); - else if (rc_service_state (service, rc_service_starting)) - ewarnx ("WARNING: %s is already starting", applet); - else if (rc_service_state (service, rc_service_stopping)) - ewarnx ("WARNING: %s is stopping", applet); - else if (rc_service_state (service, rc_service_inactive) && ! background) - ewarnx ("WARNING: %s has already started, but is inactive", applet); - - if (! rc_mark_service (service, rc_service_starting)) - eerrorx ("ERROR: %s has been started by something else", applet); - - make_exclusive (service); - - if (deps) - { - if (! deptree && ((deptree = rc_load_deptree ()) == NULL)) - eerrorx ("failed to load deptree"); - - rc_strlist_free (types); - types = rc_strlist_add (NULL, "broken"); - rc_strlist_free (svclist); - svclist = rc_strlist_add (NULL, applet); - rc_strlist_free (services); - services = rc_get_depends (deptree, types, svclist, softlevel, 0); - if (services) - { - eerrorn ("ERROR: `%s' needs ", applet); - STRLIST_FOREACH (services, svc, i) - { - if (i > 0) - fprintf (stderr, ", "); - fprintf (stderr, "%s", svc); - } - exit (EXIT_FAILURE); - } - rc_strlist_free (services); - services = NULL; - - rc_strlist_free (types); - types = rc_strlist_add (NULL, "ineed"); - rc_strlist_free (need_services); - need_services = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - types = rc_strlist_add (types, "iuse"); - if (! rc_runlevel_starting ()) - { - services = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - STRLIST_FOREACH (services, svc, i) - if (rc_service_state (svc, rc_service_stopped)) - rc_start_service (svc); - - rc_strlist_free (services); - } - - /* Now wait for them to start */ - types = rc_strlist_add (types, "iafter"); - services = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - - /* We use tmplist to hold our scheduled by list */ - rc_strlist_free (tmplist); - tmplist = NULL; - - STRLIST_FOREACH (services, svc, i) - { - if (rc_service_state (svc, rc_service_started)) - continue; - if (! rc_wait_service (svc)) - eerror ("%s: timed out waiting for %s", applet, svc); - if (rc_service_state (svc, rc_service_started)) - continue; - - STRLIST_FOREACH (need_services, svc2, j) - if (strcmp (svc, svc2) == 0) - { - if (rc_service_state (svc, rc_service_inactive) || - rc_service_state (svc, rc_service_wasinactive)) - tmplist = rc_strlist_add (tmplist, svc); - else - eerrorx ("ERROR: cannot start %s as %s would not start", - applet, svc); - } - } - - if (tmplist) - { - int n = 0; - int len = 0; - char *p; - - /* Set the state now, then unlink our exclusive so that - our scheduled list is preserved */ - rc_mark_service (service, rc_service_stopped); - unlink_mtime_test (); - - rc_strlist_free (types); - types = rc_strlist_add (NULL, "iprovide"); - STRLIST_FOREACH (tmplist, svc, i) - { - rc_schedule_start_service (svc, service); - - rc_strlist_free (svclist); - svclist = rc_strlist_add (NULL, svc); - rc_strlist_free (providelist); - providelist = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - STRLIST_FOREACH (providelist, svc2, j) - rc_schedule_start_service (svc2, service); - - len += strlen (svc) + 2; - n++; - } - - len += 5; - tmp = rc_xmalloc (sizeof (char *) * len); - p = tmp; - STRLIST_FOREACH (tmplist, svc, i) - { - if (i > 1) - { - if (i == n - 1) - p += snprintf (p, len, " or "); - else - p += snprintf (p, len, ", "); - } - p += snprintf (p, len, "%s", svc); - } - ewarnx ("WARNING: %s is scheduled to start when %s has started", - applet, tmp); - } - - rc_strlist_free (services); - services = NULL; - rc_strlist_free (types); - types = NULL; - rc_strlist_free (svclist); - svclist = NULL; - } - - if (ibsave) - setenv ("IN_BACKGROUND", ibsave, 1); - rc_plugin_run (rc_hook_service_start_now, applet); - started = svc_exec (service, "start", NULL); - if (ibsave) - unsetenv ("IN_BACKGROUND"); - - if (in_control ()) - { - if (! started) - { - if (rc_service_state (service, rc_service_wasinactive)) - rc_mark_service (service, rc_service_inactive); - else - { - rc_mark_service (service, rc_service_stopped); - if (rc_runlevel_starting ()) - rc_mark_service (service, rc_service_failed); - } - rc_plugin_run (rc_hook_service_start_done, applet); - eerrorx ("ERROR: %s failed to start", applet); - } - rc_mark_service (service, rc_service_started); - unlink_mtime_test (); - rc_plugin_run (rc_hook_service_start_done, applet); - } - else - { - rc_plugin_run (rc_hook_service_start_done, applet); - if (rc_service_state (service, rc_service_inactive)) - ewarnx ("WARNING: %s has started, but is inactive", applet); - else - ewarnx ("WARNING: %s not under our control, aborting", applet); - } - - /* Now start any scheduled services */ - rc_strlist_free (services); - services = rc_services_scheduled (service); - STRLIST_FOREACH (services, svc, i) - if (rc_service_state (svc, rc_service_stopped)) - rc_start_service (svc); - rc_strlist_free (services); - services = NULL; - - /* Do the same for any services we provide */ - rc_strlist_free (types); - types = rc_strlist_add (NULL, "iprovide"); - rc_strlist_free (svclist); - svclist = rc_strlist_add (NULL, applet); - rc_strlist_free (tmplist); - tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions); - - STRLIST_FOREACH (tmplist, svc2, j) - { - rc_strlist_free (services); - services = rc_services_scheduled (svc2); - STRLIST_FOREACH (services, svc, i) - if (rc_service_state (svc, rc_service_stopped)) - rc_start_service (svc); - } - - hook_out = 0; - rc_plugin_run (rc_hook_service_start_out, applet); + bool started; + bool background = false; + char *svc; + char *svc2; + int i; + int j; + int depoptions = RC_DEP_TRACE; + + rc_plugin_run (rc_hook_service_start_in, applet); + hook_out = rc_hook_service_start_out; + + if (rc_is_env ("RC_STRICT_DEPEND", "yes")) + depoptions |= RC_DEP_STRICT; + + if (rc_is_env ("IN_HOTPLUG", "1") || in_background) { + if (! rc_service_state (service, rc_service_inactive)) + exit (EXIT_FAILURE); + background = true; + } + + if (rc_service_state (service, rc_service_started)) + ewarnx ("WARNING: %s has already been started", applet); + else if (rc_service_state (service, rc_service_starting)) + ewarnx ("WARNING: %s is already starting", applet); + else if (rc_service_state (service, rc_service_stopping)) + ewarnx ("WARNING: %s is stopping", applet); + else if (rc_service_state (service, rc_service_inactive) && ! background) + ewarnx ("WARNING: %s has already started, but is inactive", applet); + + if (! rc_mark_service (service, rc_service_starting)) + eerrorx ("ERROR: %s has been started by something else", applet); + + make_exclusive (service); + + if (deps) { + if (! deptree && ((deptree = rc_load_deptree ()) == NULL)) + eerrorx ("failed to load deptree"); + + rc_strlist_free (types); + types = rc_strlist_add (NULL, "broken"); + rc_strlist_free (svclist); + svclist = rc_strlist_add (NULL, applet); + rc_strlist_free (services); + services = rc_get_depends (deptree, types, svclist, softlevel, 0); + if (services) { + eerrorn ("ERROR: `%s' needs ", applet); + STRLIST_FOREACH (services, svc, i) { + if (i > 0) + fprintf (stderr, ", "); + fprintf (stderr, "%s", svc); + } + exit (EXIT_FAILURE); + } + rc_strlist_free (services); + services = NULL; + + rc_strlist_free (types); + types = rc_strlist_add (NULL, "ineed"); + rc_strlist_free (need_services); + need_services = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + types = rc_strlist_add (types, "iuse"); + if (! rc_runlevel_starting ()) { + services = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + STRLIST_FOREACH (services, svc, i) + if (rc_service_state (svc, rc_service_stopped)) + rc_start_service (svc); + + rc_strlist_free (services); + } + + /* Now wait for them to start */ + types = rc_strlist_add (types, "iafter"); + services = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + + /* We use tmplist to hold our scheduled by list */ + rc_strlist_free (tmplist); + tmplist = NULL; + + STRLIST_FOREACH (services, svc, i) { + if (rc_service_state (svc, rc_service_started)) + continue; + if (! rc_wait_service (svc)) + eerror ("%s: timed out waiting for %s", applet, svc); + if (rc_service_state (svc, rc_service_started)) + continue; + + STRLIST_FOREACH (need_services, svc2, j) + if (strcmp (svc, svc2) == 0) { + if (rc_service_state (svc, rc_service_inactive) || + rc_service_state (svc, rc_service_wasinactive)) + tmplist = rc_strlist_add (tmplist, svc); + else + eerrorx ("ERROR: cannot start %s as %s would not start", + applet, svc); + } + } + + if (tmplist) { + int n = 0; + int len = 0; + char *p; + + /* Set the state now, then unlink our exclusive so that + our scheduled list is preserved */ + rc_mark_service (service, rc_service_stopped); + unlink_mtime_test (); + + rc_strlist_free (types); + types = rc_strlist_add (NULL, "iprovide"); + STRLIST_FOREACH (tmplist, svc, i) { + rc_schedule_start_service (svc, service); + + rc_strlist_free (svclist); + svclist = rc_strlist_add (NULL, svc); + rc_strlist_free (providelist); + providelist = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + STRLIST_FOREACH (providelist, svc2, j) + rc_schedule_start_service (svc2, service); + + len += strlen (svc) + 2; + n++; + } + + len += 5; + tmp = rc_xmalloc (sizeof (char *) * len); + p = tmp; + STRLIST_FOREACH (tmplist, svc, i) { + if (i > 1) { + if (i == n - 1) + p += snprintf (p, len, " or "); + else + p += snprintf (p, len, ", "); + } + p += snprintf (p, len, "%s", svc); + } + ewarnx ("WARNING: %s is scheduled to start when %s has started", + applet, tmp); + } + + rc_strlist_free (services); + services = NULL; + rc_strlist_free (types); + types = NULL; + rc_strlist_free (svclist); + svclist = NULL; + } + + if (ibsave) + setenv ("IN_BACKGROUND", ibsave, 1); + rc_plugin_run (rc_hook_service_start_now, applet); + started = svc_exec (service, "start", NULL); + if (ibsave) + unsetenv ("IN_BACKGROUND"); + + if (in_control ()) { + if (! started) { + if (rc_service_state (service, rc_service_wasinactive)) + rc_mark_service (service, rc_service_inactive); + else { + rc_mark_service (service, rc_service_stopped); + if (rc_runlevel_starting ()) + rc_mark_service (service, rc_service_failed); + } + rc_plugin_run (rc_hook_service_start_done, applet); + eerrorx ("ERROR: %s failed to start", applet); + } + rc_mark_service (service, rc_service_started); + unlink_mtime_test (); + rc_plugin_run (rc_hook_service_start_done, applet); + } else { + rc_plugin_run (rc_hook_service_start_done, applet); + if (rc_service_state (service, rc_service_inactive)) + ewarnx ("WARNING: %s has started, but is inactive", applet); + else + ewarnx ("WARNING: %s not under our control, aborting", applet); + } + + /* Now start any scheduled services */ + rc_strlist_free (services); + services = rc_services_scheduled (service); + STRLIST_FOREACH (services, svc, i) + if (rc_service_state (svc, rc_service_stopped)) + rc_start_service (svc); + rc_strlist_free (services); + services = NULL; + + /* Do the same for any services we provide */ + rc_strlist_free (types); + types = rc_strlist_add (NULL, "iprovide"); + rc_strlist_free (svclist); + svclist = rc_strlist_add (NULL, applet); + rc_strlist_free (tmplist); + tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions); + + STRLIST_FOREACH (tmplist, svc2, j) { + rc_strlist_free (services); + services = rc_services_scheduled (svc2); + STRLIST_FOREACH (services, svc, i) + if (rc_service_state (svc, rc_service_stopped)) + rc_start_service (svc); + } + + hook_out = 0; + rc_plugin_run (rc_hook_service_start_out, applet); } static void svc_stop (const char *service, bool deps) { - bool stopped; - - hook_out = rc_hook_service_stop_out; - - if (rc_runlevel_stopping () && - rc_service_state (service, rc_service_failed)) - exit (EXIT_FAILURE); - - if (rc_is_env ("IN_HOTPLUG", "1") || in_background) - if (! rc_service_state (service, rc_service_started)) - exit (EXIT_FAILURE); - - if (rc_service_state (service, rc_service_stopped)) - ewarnx ("WARNING: %s is already stopped", applet); - else if (rc_service_state (service, rc_service_stopping)) - ewarnx ("WARNING: %s is already stopping", applet); - - if (! rc_mark_service (service, rc_service_stopping)) - eerrorx ("ERROR: %s has been stopped by something else", applet); - - make_exclusive (service); - - if (! rc_runlevel_stopping () && - rc_service_in_runlevel (service, RC_LEVEL_BOOT)) - ewarn ("WARNING: you are stopping a boot service"); - - if (deps || ! rc_service_state (service, rc_service_wasinactive)) - { - int depoptions = RC_DEP_TRACE; - char *svc; - int i; - - if (rc_is_env ("RC_STRICT_DEPEND", "yes")) - depoptions |= RC_DEP_STRICT; - - if (! deptree && ((deptree = rc_load_deptree ()) == NULL)) - eerrorx ("failed to load deptree"); - - rc_strlist_free (types); - types = rc_strlist_add (NULL, "needsme"); - rc_strlist_free (svclist); - svclist = rc_strlist_add (NULL, applet); - rc_strlist_free (tmplist); - tmplist = NULL; - rc_strlist_free (services); - services = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - rc_strlist_reverse (services); - STRLIST_FOREACH (services, svc, i) - { - if (rc_service_state (svc, rc_service_started) || - rc_service_state (svc, rc_service_inactive)) - { - rc_wait_service (svc); - if (rc_service_state (svc, rc_service_started) || - rc_service_state (svc, rc_service_inactive)) - { - rc_stop_service (svc); - tmplist = rc_strlist_add (tmplist, svc); - } - } - } - rc_strlist_free (services); - services = NULL; - - STRLIST_FOREACH (tmplist, svc, i) - { - if (rc_service_state (svc, rc_service_stopped)) - continue; - - /* We used to loop 3 times here - maybe re-do this if needed */ - rc_wait_service (svc); - if (! rc_service_state (svc, rc_service_stopped)) - { - if (rc_runlevel_stopping ()) - rc_mark_service (svc, rc_service_failed); - eerrorx ("ERROR: cannot stop %s as %s is still up", - applet, svc); - } - } - rc_strlist_free (tmplist); - tmplist = NULL; - - /* We now wait for other services that may use us and are stopping - This is important when a runlevel stops */ - types = rc_strlist_add (types, "usesme"); - types = rc_strlist_add (types, "ibefore"); - services = rc_get_depends (deptree, types, svclist, - softlevel, depoptions); - STRLIST_FOREACH (services, svc, i) - { - if (rc_service_state (svc, rc_service_stopped)) - continue; - rc_wait_service (svc); - } - - rc_strlist_free (services); - services = NULL; - rc_strlist_free (types); - types = NULL; - } - - if (ibsave) - setenv ("IN_BACKGROUND", ibsave, 1); - rc_plugin_run (rc_hook_service_stop_now, applet); - stopped = svc_exec (service, "stop", NULL); - if (ibsave) - unsetenv ("IN_BACKGROUND"); - - if (! in_control ()) - { - rc_plugin_run (rc_hook_service_stop_done, applet); - ewarnx ("WARNING: %s not under our control, aborting", applet); - } - - if (! stopped) - { - if (rc_service_state (service, rc_service_wasinactive)) - rc_mark_service (service, rc_service_inactive); - else - rc_mark_service (service, rc_service_started); - rc_plugin_run (rc_hook_service_stop_done, applet); - eerrorx ("ERROR: %s failed to stop", applet); - } - - if (in_background) - rc_mark_service (service, rc_service_inactive); - else - rc_mark_service (service, rc_service_stopped); - - unlink_mtime_test (); - rc_plugin_run (rc_hook_service_stop_done, applet); - hook_out = 0; - rc_plugin_run (rc_hook_service_stop_out, applet); + bool stopped; + + hook_out = rc_hook_service_stop_out; + + if (rc_runlevel_stopping () && + rc_service_state (service, rc_service_failed)) + exit (EXIT_FAILURE); + + if (rc_is_env ("IN_HOTPLUG", "1") || in_background) + if (! rc_service_state (service, rc_service_started)) + exit (EXIT_FAILURE); + + if (rc_service_state (service, rc_service_stopped)) + ewarnx ("WARNING: %s is already stopped", applet); + else if (rc_service_state (service, rc_service_stopping)) + ewarnx ("WARNING: %s is already stopping", applet); + + if (! rc_mark_service (service, rc_service_stopping)) + eerrorx ("ERROR: %s has been stopped by something else", applet); + + make_exclusive (service); + + if (! rc_runlevel_stopping () && + rc_service_in_runlevel (service, RC_LEVEL_BOOT)) + ewarn ("WARNING: you are stopping a boot service"); + + if (deps || ! rc_service_state (service, rc_service_wasinactive)) { + int depoptions = RC_DEP_TRACE; + char *svc; + int i; + + if (rc_is_env ("RC_STRICT_DEPEND", "yes")) + depoptions |= RC_DEP_STRICT; + + if (! deptree && ((deptree = rc_load_deptree ()) == NULL)) + eerrorx ("failed to load deptree"); + + rc_strlist_free (types); + types = rc_strlist_add (NULL, "needsme"); + rc_strlist_free (svclist); + svclist = rc_strlist_add (NULL, applet); + rc_strlist_free (tmplist); + tmplist = NULL; + rc_strlist_free (services); + services = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + rc_strlist_reverse (services); + STRLIST_FOREACH (services, svc, i) { + if (rc_service_state (svc, rc_service_started) || + rc_service_state (svc, rc_service_inactive)) + { + rc_wait_service (svc); + if (rc_service_state (svc, rc_service_started) || + rc_service_state (svc, rc_service_inactive)) + { + rc_stop_service (svc); + tmplist = rc_strlist_add (tmplist, svc); + } + } + } + rc_strlist_free (services); + services = NULL; + + STRLIST_FOREACH (tmplist, svc, i) { + if (rc_service_state (svc, rc_service_stopped)) + continue; + + /* We used to loop 3 times here - maybe re-do this if needed */ + rc_wait_service (svc); + if (! rc_service_state (svc, rc_service_stopped)) { + if (rc_runlevel_stopping ()) + rc_mark_service (svc, rc_service_failed); + eerrorx ("ERROR: cannot stop %s as %s is still up", + applet, svc); + } + } + rc_strlist_free (tmplist); + tmplist = NULL; + + /* We now wait for other services that may use us and are stopping + This is important when a runlevel stops */ + types = rc_strlist_add (types, "usesme"); + types = rc_strlist_add (types, "ibefore"); + services = rc_get_depends (deptree, types, svclist, + softlevel, depoptions); + STRLIST_FOREACH (services, svc, i) { + if (rc_service_state (svc, rc_service_stopped)) + continue; + rc_wait_service (svc); + } + + rc_strlist_free (services); + services = NULL; + rc_strlist_free (types); + types = NULL; + } + + if (ibsave) + setenv ("IN_BACKGROUND", ibsave, 1); + rc_plugin_run (rc_hook_service_stop_now, applet); + stopped = svc_exec (service, "stop", NULL); + if (ibsave) + unsetenv ("IN_BACKGROUND"); + + if (! in_control ()) { + rc_plugin_run (rc_hook_service_stop_done, applet); + ewarnx ("WARNING: %s not under our control, aborting", applet); + } + + if (! stopped) { + if (rc_service_state (service, rc_service_wasinactive)) + rc_mark_service (service, rc_service_inactive); + else + rc_mark_service (service, rc_service_started); + rc_plugin_run (rc_hook_service_stop_done, applet); + eerrorx ("ERROR: %s failed to stop", applet); + } + + if (in_background) + rc_mark_service (service, rc_service_inactive); + else + rc_mark_service (service, rc_service_stopped); + + unlink_mtime_test (); + rc_plugin_run (rc_hook_service_stop_done, applet); + hook_out = 0; + rc_plugin_run (rc_hook_service_stop_out, applet); } static void svc_restart (const char *service, bool deps) { - char *svc; - int i; - bool inactive = false; - - /* This is hairly and a better way needs to be found I think! - The issue is this - openvpn need net and dns. net can restart - dns via resolvconf, so you could have openvpn trying to restart dnsmasq - which in turn is waiting on net which in turn is waiting on dnsmasq. - The work around is for resolvconf to restart it's services with --nodeps - which means just that. The downside is that there is a small window when - our status is invalid. - One workaround would be to introduce a new status, or status locking. */ - if (! deps) - { - if (rc_service_state (service, rc_service_started) || - rc_service_state (service, rc_service_inactive)) - svc_exec (service, "stop", "start"); - else - svc_exec (service, "start", NULL); - return; - } - - if (! rc_service_state (service, rc_service_stopped)) - { - get_started_services (); - svc_stop (service, deps); - - /* Flush our buffered output if any */ - eflush (); - } - - svc_start (service, deps); - - inactive = rc_service_state (service, rc_service_inactive); - if (! inactive) - inactive = rc_service_state (service, rc_service_wasinactive); - - if (inactive || - rc_service_state (service, rc_service_starting) || - rc_service_state (service, rc_service_started)) - { - STRLIST_FOREACH (restart_services, svc, i) - { - if (rc_service_state (svc, rc_service_stopped)) - { - if (inactive) - { - rc_schedule_start_service (service, svc); - ewarn ("WARNING: %s is scheduled to started when %s has started", - svc, basename (service)); - } - else - rc_start_service (svc); - } - } - } + char *svc; + int i; + bool inactive = false; + + /* This is hairly and a better way needs to be found I think! + The issue is this - openvpn need net and dns. net can restart + dns via resolvconf, so you could have openvpn trying to restart dnsmasq + which in turn is waiting on net which in turn is waiting on dnsmasq. + The work around is for resolvconf to restart it's services with --nodeps + which means just that. The downside is that there is a small window when + our status is invalid. + One workaround would be to introduce a new status, or status locking. */ + if (! deps) { + if (rc_service_state (service, rc_service_started) || + rc_service_state (service, rc_service_inactive)) + svc_exec (service, "stop", "start"); + else + svc_exec (service, "start", NULL); + return; + } + + if (! rc_service_state (service, rc_service_stopped)) { + get_started_services (); + svc_stop (service, deps); + + /* Flush our buffered output if any */ + eflush (); + } + + svc_start (service, deps); + + inactive = rc_service_state (service, rc_service_inactive); + if (! inactive) + inactive = rc_service_state (service, rc_service_wasinactive); + + if (inactive || + rc_service_state (service, rc_service_starting) || + rc_service_state (service, rc_service_started)) + { + STRLIST_FOREACH (restart_services, svc, i) { + if (rc_service_state (svc, rc_service_stopped)) { + if (inactive) { + rc_schedule_start_service (service, svc); + ewarn ("WARNING: %s is scheduled to started when %s has started", + svc, basename (service)); + } else + rc_start_service (svc); + } + } + } } int main (int argc, char **argv) { - const char *service = argv[1]; - int i; - bool deps = true; - bool doneone = false; - char pid[16]; - int retval; - bool ifstarted = false; - - applet = strdup (basename (service)); - atexit (cleanup); - - /* Show help if insufficient args */ - if (argc < 3) - { - execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); - eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", - applet, strerror (errno)); - } + const char *service = argv[1]; + int i; + bool deps = true; + bool doneone = false; + char pid[16]; + int retval; + bool ifstarted = false; + + applet = strdup (basename (service)); + atexit (cleanup); + + /* Show help if insufficient args */ + if (argc < 3) { + execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); + eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", + applet, strerror (errno)); + } #ifdef __linux__ - /* coldplug events can trigger init scripts, but we don't want to run them - until after rc sysinit has completed so we punt them to the boot runlevel */ - if (rc_exists ("/dev/.rcsysinit")) - { - eerror ("%s: cannot run until sysvinit completes", applet); - if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST) - eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno)); - tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL); - symlink (service, tmp); - exit (EXIT_FAILURE); - } + /* coldplug events can trigger init scripts, but we don't want to run them + until after rc sysinit has completed so we punt them to the boot runlevel */ + if (rc_exists ("/dev/.rcsysinit")) { + eerror ("%s: cannot run until sysvinit completes", applet); + if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST) + eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno)); + tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL); + symlink (service, tmp); + exit (EXIT_FAILURE); + } #endif - if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) - { - /* Ensure our environment is pure - Also, add our configuration to it */ - env = rc_filter_env (); - env = rc_config_env (env); + if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) { + /* Ensure our environment is pure + Also, add our configuration to it */ + env = rc_filter_env (); + env = rc_config_env (env); - if (env) - { - char *p; + if (env) { + char *p; #ifdef __linux__ - /* clearenv isn't portable, but there's no harm in using it - if we have it */ - clearenv (); + /* clearenv isn't portable, but there's no harm in using it + if we have it */ + clearenv (); #else - char *var; - /* No clearenv present here then. - We could manipulate environ directly ourselves, but it seems that - some kernels bitch about this according to the environ man pages - so we walk though environ and call unsetenv for each value. */ - while (environ[0]) - { - tmp = rc_xstrdup (environ[0]); - p = tmp; - var = strsep (&p, "="); - unsetenv (var); - free (tmp); - } - tmp = NULL; + char *var; + /* No clearenv present here then. + We could manipulate environ directly ourselves, but it seems that + some kernels bitch about this according to the environ man pages + so we walk though environ and call unsetenv for each value. */ + while (environ[0]) { + tmp = rc_xstrdup (environ[0]); + p = tmp; + var = strsep (&p, "="); + unsetenv (var); + free (tmp); + } + tmp = NULL; #endif - STRLIST_FOREACH (env, p, i) - putenv (p); + STRLIST_FOREACH (env, p, i) + putenv (p); - /* We don't free our list as that would be null in environ */ - } + /* We don't free our list as that would be null in environ */ + } - softlevel = rc_get_runlevel (); + softlevel = rc_get_runlevel (); - /* If not called from RC or another service then don't be parallel */ - unsetenv ("RC_PARALLEL_STARTUP"); - } + /* If not called from RC or another service then don't be parallel */ + unsetenv ("RC_PARALLEL_STARTUP"); + } - setenv ("RC_ELOG", service, 1); - setenv ("SVCNAME", applet, 1); + setenv ("RC_ELOG", service, 1); + setenv ("SVCNAME", applet, 1); - /* Set an env var so that we always know our pid regardless of any - subshells the init script may create so that our mark_service_* - functions can always instruct us of this change */ - snprintf (pid, sizeof (pid), "%d", (int) getpid ()); - setenv ("RC_RUNSCRIPT_PID", pid, 1); + /* Set an env var so that we always know our pid regardless of any + subshells the init script may create so that our mark_service_* + functions can always instruct us of this change */ + snprintf (pid, sizeof (pid), "%d", (int) getpid ()); + setenv ("RC_RUNSCRIPT_PID", pid, 1); - if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) - { - char ebname[PATH_MAX]; - char *eb; + if (rc_is_env ("RC_PARALLEL_STARTUP", "yes")) { + char ebname[PATH_MAX]; + char *eb; - snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid); - eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL); - setenv ("RC_EBUFFER", eb, 1); - free (eb); - } + snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid); + eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL); + setenv ("RC_EBUFFER", eb, 1); + free (eb); + } - /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service - that is being called and not any dependents */ - if (getenv ("IN_BACKGROUND")) - { - in_background = rc_is_env ("IN_BACKGROUND", "true"); - ibsave = strdup (getenv ("IN_BACKGROUND")); - unsetenv ("IN_BACKGROUND"); - } + /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service + that is being called and not any dependents */ + if (getenv ("IN_BACKGROUND")) { + in_background = rc_is_env ("IN_BACKGROUND", "true"); + ibsave = strdup (getenv ("IN_BACKGROUND")); + unsetenv ("IN_BACKGROUND"); + } #ifdef __linux__ - /* Ok, we are ready to go, so setup selinux if applicable */ - setup_selinux (argc, argv); + /* Ok, we are ready to go, so setup selinux if applicable */ + setup_selinux (argc, argv); #endif - /* Right then, parse any options there may be */ - for (i = 2; i < argc; i++) - { - if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-') - continue; - - if (strcmp (argv[i], "--debug") == 0) - setenv ("RC_DEBUG", "yes", 1); - else if (strcmp (argv[i], "--help") == 0) - { - execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); - eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", - applet, strerror (errno)); - } - else if (strcmp (argv[i],"--ifstarted") == 0) - ifstarted = true; - else if (strcmp (argv[i], "--nocolour") == 0 || - strcmp (argv[i], "--nocolor") == 0) - setenv ("RC_NOCOLOR", "yes", 1); - else if (strcmp (argv[i], "--nodeps") == 0) - deps = false; - else if (strcmp (argv[i], "--quiet") == 0) - setenv ("RC_QUIET", "yes", 1); - else if (strcmp (argv[i], "--verbose") == 0) - setenv ("RC_VERBOSE", "yes", 1); - else if (strcmp (argv[i], "--version") == 0) - printf ("version me\n"); - else - eerror ("%s: unknown option `%s'", applet, argv[i]); - } - - if (ifstarted && ! rc_service_state (applet, rc_service_started)) - { - if (! rc_is_env("RC_QUIET", "yes")) - eerror ("ERROR: %s is not started", applet); - exit (EXIT_FAILURE); - } - - if (rc_is_env ("IN_HOTPLUG", "1")) - { - if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet)) - eerrorx ("%s: not allowed to be hotplugged", applet); - } - - /* Setup a signal handler */ - signal (SIGHUP, handle_signal); - signal (SIGINT, handle_signal); - signal (SIGQUIT, handle_signal); - signal (SIGTERM, handle_signal); - signal (SIGCHLD, handle_signal); - - /* Load our plugins */ - rc_plugin_load (); - - /* Now run each option */ - retval = EXIT_SUCCESS; - for (i = 2; i < argc; i++) - { - /* Abort on a sighup here */ - if (sighup) - exit (EXIT_FAILURE); - - if (strlen (argv[i]) < 2 || - (argv[i][0] == '-' && argv[i][1] == '-')) - continue; - - /* Export the command we're running. - This is important as we stamp on the restart function now but - some start/stop routines still need to behave differently if - restarting. */ - unsetenv ("RC_CMD"); - setenv ("RC_CMD", argv[i], 1); - - doneone = true; - if (strcmp (argv[i], "conditionalrestart") == 0 || - strcmp (argv[i], "condrestart") == 0) - { - if (rc_service_state (service, rc_service_started)) - svc_restart (service, deps); - } - else if (strcmp (argv[i], "restart") == 0) - svc_restart (service, deps); - else if (strcmp (argv[i], "start") == 0) - svc_start (service, deps); - else if (strcmp (argv[i], "status") == 0) - { - rc_service_state_t r = svc_status (service); - retval = (int) r; - } - else if (strcmp (argv[i], "stop") == 0) - { - if (in_background) - get_started_services (); - - svc_stop (service, deps); - - if (! in_background && - ! rc_runlevel_stopping () && - rc_service_state (service, rc_service_stopped)) - uncoldplug (applet); - - if (in_background && - rc_service_state (service, rc_service_inactive)) - { - char *svc; - int j; - STRLIST_FOREACH (restart_services, svc, j) - if (rc_service_state (svc, rc_service_stopped)) - rc_schedule_start_service (service, svc); - } - } - else if (strcmp (argv[i], "zap") == 0) - { - einfo ("Manually resetting %s to stopped state", applet); - rc_mark_service (applet, rc_service_stopped); - uncoldplug (applet); - } - else if (strcmp (argv[i], "help") == 0) - { - execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL); - eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", - applet, strerror (errno)); - } - else - svc_exec (service, argv[i], NULL); - - /* Flush our buffered output if any */ - eflush (); - - /* We should ensure this list is empty after an action is done */ - rc_strlist_free (restart_services); - restart_services = NULL; - } - - if (! doneone) - { - execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); - eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", - applet, strerror (errno)); - } - - return (retval); + /* Right then, parse any options there may be */ + for (i = 2; i < argc; i++) { + if (strlen (argv[i]) < 2 || argv[i][0] != '-' || argv[i][1] != '-') + continue; + + if (strcmp (argv[i], "--debug") == 0) + setenv ("RC_DEBUG", "yes", 1); + else if (strcmp (argv[i], "--help") == 0) { + execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); + eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", + applet, strerror (errno)); + } else if (strcmp (argv[i],"--ifstarted") == 0) + ifstarted = true; + else if (strcmp (argv[i], "--nocolour") == 0 || + strcmp (argv[i], "--nocolor") == 0) + setenv ("RC_NOCOLOR", "yes", 1); + else if (strcmp (argv[i], "--nodeps") == 0) + deps = false; + else if (strcmp (argv[i], "--quiet") == 0) + setenv ("RC_QUIET", "yes", 1); + else if (strcmp (argv[i], "--verbose") == 0) + setenv ("RC_VERBOSE", "yes", 1); + else if (strcmp (argv[i], "--version") == 0) + printf ("version me\n"); + else + eerror ("%s: unknown option `%s'", applet, argv[i]); + } + + if (ifstarted && ! rc_service_state (applet, rc_service_started)) { + if (! rc_is_env("RC_QUIET", "yes")) + eerror ("ERROR: %s is not started", applet); + exit (EXIT_FAILURE); + } + + if (rc_is_env ("IN_HOTPLUG", "1")) { + if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet)) + eerrorx ("%s: not allowed to be hotplugged", applet); + } + + /* Setup a signal handler */ + signal (SIGHUP, handle_signal); + signal (SIGINT, handle_signal); + signal (SIGQUIT, handle_signal); + signal (SIGTERM, handle_signal); + signal (SIGCHLD, handle_signal); + + /* Load our plugins */ + rc_plugin_load (); + + /* Now run each option */ + retval = EXIT_SUCCESS; + for (i = 2; i < argc; i++) { + /* Abort on a sighup here */ + if (sighup) + exit (EXIT_FAILURE); + + if (strlen (argv[i]) < 2 || + (argv[i][0] == '-' && argv[i][1] == '-')) + continue; + + /* Export the command we're running. + This is important as we stamp on the restart function now but + some start/stop routines still need to behave differently if + restarting. */ + unsetenv ("RC_CMD"); + setenv ("RC_CMD", argv[i], 1); + + doneone = true; + if (strcmp (argv[i], "conditionalrestart") == 0 || + strcmp (argv[i], "condrestart") == 0) + { + if (rc_service_state (service, rc_service_started)) + svc_restart (service, deps); + } + else if (strcmp (argv[i], "restart") == 0) + svc_restart (service, deps); + else if (strcmp (argv[i], "start") == 0) + svc_start (service, deps); + else if (strcmp (argv[i], "status") == 0) { + rc_service_state_t r = svc_status (service); + retval = (int) r; + } else if (strcmp (argv[i], "stop") == 0) { + if (in_background) + get_started_services (); + + svc_stop (service, deps); + + if (! in_background && + ! rc_runlevel_stopping () && + rc_service_state (service, rc_service_stopped)) + uncoldplug (applet); + + if (in_background && + rc_service_state (service, rc_service_inactive)) + { + char *svc; + int j; + STRLIST_FOREACH (restart_services, svc, j) + if (rc_service_state (svc, rc_service_stopped)) + rc_schedule_start_service (service, svc); + } + } else if (strcmp (argv[i], "zap") == 0) { + einfo ("Manually resetting %s to stopped state", applet); + rc_mark_service (applet, rc_service_stopped); + uncoldplug (applet); + } else if (strcmp (argv[i], "help") == 0) { + execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL); + eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", + applet, strerror (errno)); + }else + svc_exec (service, argv[i], NULL); + + /* Flush our buffered output if any */ + eflush (); + + /* We should ensure this list is empty after an action is done */ + rc_strlist_free (restart_services); + restart_services = NULL; + } + + if (! doneone) { + execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL); + eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s", + applet, strerror (errno)); + } + + return (retval); } diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c index 499543b9..384b72c6 100644 --- a/src/start-stop-daemon.c +++ b/src/start-stop-daemon.c @@ -46,16 +46,16 @@ static struct pam_conv conv = { NULL, NULL} ; typedef struct schedulelist { - enum - { - schedule_timeout, - schedule_signal, - schedule_goto, - schedule_forever - } type; - int value; - struct schedulelist *gotolist; - struct schedulelist *next; + enum + { + schedule_timeout, + schedule_signal, + schedule_goto, + schedule_forever + } type; + int value; + struct schedulelist *gotolist; + struct schedulelist *next; } schedulelist_t; static schedulelist_t *schedule; @@ -67,990 +67,921 @@ extern char **environ; static void free_schedulelist (schedulelist_t **list) { - schedulelist_t *here; - schedulelist_t *next; + schedulelist_t *here; + schedulelist_t *next; - for (here = *list; here; here = next) - { - next = here->next; - free (here); - } + for (here = *list; here; here = next) { + next = here->next; + free (here); + } - *list = NULL; + *list = NULL; } static void cleanup (void) { - if (changeuser) - free (changeuser); + if (changeuser) + free (changeuser); - if (schedule) - free_schedulelist (&schedule); + if (schedule) + free_schedulelist (&schedule); - if (newenv) - rc_strlist_free (newenv); + if (newenv) + rc_strlist_free (newenv); } static int parse_signal (const char *sig) { - typedef struct signalpair - { - const char *name; - int signal; - } signalpair_t; - - static const signalpair_t signallist[] = { - { "ABRT", SIGABRT }, - { "ALRM", SIGALRM }, - { "FPE", SIGFPE }, - { "HUP", SIGHUP }, - { "ILL", SIGILL }, - { "INT", SIGINT }, - { "KILL", SIGKILL }, - { "PIPE", SIGPIPE }, - { "QUIT", SIGQUIT }, - { "SEGV", SIGSEGV }, - { "TERM", SIGTERM }, - { "USR1", SIGUSR1 }, - { "USR2", SIGUSR2 }, - { "CHLD", SIGCHLD }, - { "CONT", SIGCONT }, - { "STOP", SIGSTOP }, - { "TSTP", SIGTSTP }, - { "TTIN", SIGTTIN }, - { "TTOU", SIGTTOU } - }; - - unsigned int i = 0; - char *s; - - if (! sig || strlen (sig) == 0) - return (-1); - - if (sscanf (sig, "%u", &i) == 1) - { - if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0])) - return (i); - eerrorx ("%s: `%s' is not a valid signal", progname, sig); - } - - if (strncmp (sig, "SIG", 3) == 0) - s = (char *) sig + 3; - else - s = NULL; - - for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++) - if (strcmp (sig, signallist[i].name) == 0 || - (s && strcmp (s, signallist[i].name) == 0)) - return (signallist[i].signal); - - eerrorx ("%s: `%s' is not a valid signal", progname, sig); + typedef struct signalpair + { + const char *name; + int signal; + } signalpair_t; + + static const signalpair_t signallist[] = { + { "ABRT", SIGABRT }, + { "ALRM", SIGALRM }, + { "FPE", SIGFPE }, + { "HUP", SIGHUP }, + { "ILL", SIGILL }, + { "INT", SIGINT }, + { "KILL", SIGKILL }, + { "PIPE", SIGPIPE }, + { "QUIT", SIGQUIT }, + { "SEGV", SIGSEGV }, + { "TERM", SIGTERM }, + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { "CHLD", SIGCHLD }, + { "CONT", SIGCONT }, + { "STOP", SIGSTOP }, + { "TSTP", SIGTSTP }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU } + }; + + unsigned int i = 0; + char *s; + + if (! sig || strlen (sig) == 0) + return (-1); + + if (sscanf (sig, "%u", &i) == 1) { + if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0])) + return (i); + eerrorx ("%s: `%s' is not a valid signal", progname, sig); + } + + if (strncmp (sig, "SIG", 3) == 0) + s = (char *) sig + 3; + else + s = NULL; + + for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++) + if (strcmp (sig, signallist[i].name) == 0 || + (s && strcmp (s, signallist[i].name) == 0)) + return (signallist[i].signal); + + eerrorx ("%s: `%s' is not a valid signal", progname, sig); } static void parse_schedule_item (schedulelist_t *item, const char *string) { - const char *after_hyph; - int sig; - - if (strcmp (string,"forever") == 0) - item->type = schedule_forever; - else if (isdigit (string[0])) - { - item->type = schedule_timeout; - errno = 0; - if (sscanf (string, "%d", &item->value) != 1) - eerrorx ("%s: invalid timeout value in schedule `%s'", progname, - string); - } - else if ((after_hyph = string + (string[0] == '-')) && - ((sig = parse_signal (after_hyph)) != -1)) - { - item->type = schedule_signal; - item->value = (int) sig; - } - else - eerrorx ("%s: invalid schedule item `%s'", progname, string); + const char *after_hyph; + int sig; + + if (strcmp (string,"forever") == 0) + item->type = schedule_forever; + else if (isdigit (string[0])) { + item->type = schedule_timeout; + errno = 0; + if (sscanf (string, "%d", &item->value) != 1) + eerrorx ("%s: invalid timeout value in schedule `%s'", progname, + string); + } else if ((after_hyph = string + (string[0] == '-')) && + ((sig = parse_signal (after_hyph)) != -1)) + { + item->type = schedule_signal; + item->value = (int) sig; + } + else + eerrorx ("%s: invalid schedule item `%s'", progname, string); } static void parse_schedule (const char *string, int default_signal) { - char buffer[20]; - const char *slash; - int count = 0; - schedulelist_t *repeatat = NULL; - ptrdiff_t len; - schedulelist_t *next; - - if (string) - for (slash = string; *slash; slash++) - if (*slash == '/') - count++; - - if (schedule) - free_schedulelist (&schedule); - - schedule = rc_xmalloc (sizeof (schedulelist_t)); - schedule->gotolist = NULL; - - if (count == 0) - { - schedule->type = schedule_signal; - schedule->value = default_signal; - schedule->next = rc_xmalloc (sizeof (schedulelist_t)); - next = schedule->next; - next->type = schedule_timeout; - next->gotolist = NULL; - if (string) - { - if (sscanf (string, "%d", &next->value) != 1) - eerrorx ("%s: invalid timeout value in schedule", progname); - } - else - next->value = 5; - next->next = NULL; - - return; - } - - next = schedule; - while (string != NULL) - { - if ((slash = strchr (string, '/'))) - len = slash - string; - else - len = strlen (string); - - if (len >= (ptrdiff_t) sizeof (buffer)) - eerrorx ("%s: invalid schedule item, far too long", progname); - - memcpy (buffer, string, len); - buffer[len] = 0; - string = slash ? slash + 1 : NULL; - - parse_schedule_item (next, buffer); - if (next->type == schedule_forever) - { - if (repeatat) - eerrorx ("%s: invalid schedule, `forever' appears more than once", - progname); - - repeatat = next; - continue; - } - - if (string) - { - next->next = rc_xmalloc (sizeof (schedulelist_t)); - next = next->next; - next->gotolist = NULL; - } - } - - if (repeatat) - { - next->next = rc_xmalloc (sizeof (schedulelist_t)); - next = next->next; - next->type = schedule_goto; - next->value = 0; - next->gotolist = repeatat; - } - - next->next = NULL; - return; + char buffer[20]; + const char *slash; + int count = 0; + schedulelist_t *repeatat = NULL; + ptrdiff_t len; + schedulelist_t *next; + + if (string) + for (slash = string; *slash; slash++) + if (*slash == '/') + count++; + + if (schedule) + free_schedulelist (&schedule); + + schedule = rc_xmalloc (sizeof (schedulelist_t)); + schedule->gotolist = NULL; + + if (count == 0) { + schedule->type = schedule_signal; + schedule->value = default_signal; + schedule->next = rc_xmalloc (sizeof (schedulelist_t)); + next = schedule->next; + next->type = schedule_timeout; + next->gotolist = NULL; + if (string) { + if (sscanf (string, "%d", &next->value) != 1) + eerrorx ("%s: invalid timeout value in schedule", progname); + } + else + next->value = 5; + next->next = NULL; + + return; + } + + next = schedule; + while (string != NULL) { + if ((slash = strchr (string, '/'))) + len = slash - string; + else + len = strlen (string); + + if (len >= (ptrdiff_t) sizeof (buffer)) + eerrorx ("%s: invalid schedule item, far too long", progname); + + memcpy (buffer, string, len); + buffer[len] = 0; + string = slash ? slash + 1 : NULL; + + parse_schedule_item (next, buffer); + if (next->type == schedule_forever) { + if (repeatat) + eerrorx ("%s: invalid schedule, `forever' appears more than once", + progname); + + repeatat = next; + continue; + } + + if (string) { + next->next = rc_xmalloc (sizeof (schedulelist_t)); + next = next->next; + next->gotolist = NULL; + } + } + + if (repeatat) { + next->next = rc_xmalloc (sizeof (schedulelist_t)); + next = next->next; + next->type = schedule_goto; + next->value = 0; + next->gotolist = repeatat; + } + + next->next = NULL; + return; } static pid_t get_pid (const char *pidfile, bool quiet) { - FILE *fp; - pid_t pid; - - if (! pidfile) - return (-1); - - if ((fp = fopen (pidfile, "r")) == NULL) - { - if (! quiet) - eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno)); - return (-1); - } - - if (fscanf (fp, "%d", &pid) != 1) - { - if (! quiet) - eerror ("%s: no pid found in `%s'", progname, pidfile); - fclose (fp); - return (-1); - } - fclose (fp); - - return (pid); + FILE *fp; + pid_t pid; + + if (! pidfile) + return (-1); + + if ((fp = fopen (pidfile, "r")) == NULL) { + if (! quiet) + eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno)); + return (-1); + } + + if (fscanf (fp, "%d", &pid) != 1) { + if (! quiet) + eerror ("%s: no pid found in `%s'", progname, pidfile); + fclose (fp); + return (-1); + } + fclose (fp); + + return (pid); } /* return number of processed killed, -1 on error */ static int do_stop (const char *exec, const char *cmd, - const char *pidfile, uid_t uid,int sig, - bool quiet, bool verbose, bool test) + const char *pidfile, uid_t uid,int sig, + bool quiet, bool verbose, bool test) { - pid_t *pids; - bool killed; - int nkilled = 0; - pid_t pid = 0; - int i; - - if (pidfile) - if ((pid = get_pid (pidfile, quiet)) == -1) - return (quiet ? 0 : -1); - - if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL) - return (0); - - for (i = 0; pids[i]; i++) - { - if (test) - { - if (! quiet) - einfo ("Would send signal %d to PID %d", sig, pids[i]); - nkilled++; - continue; - } - - if (verbose) - ebegin ("Sending signal %d to PID %d", sig, pids[i]); - errno = 0; - killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false); - if (! killed) - { - if (! quiet) - eerror ("%s: failed to send signal %d to PID %d: %s", - progname, sig, pids[i], strerror (errno)); - if (verbose) - eend (1, NULL); - nkilled = -1; - } - else - { - if (verbose) - eend (0, NULL); - if (nkilled != -1) - nkilled++; - } - } - - free (pids); - return (nkilled); + pid_t *pids; + bool killed; + int nkilled = 0; + pid_t pid = 0; + int i; + + if (pidfile) + if ((pid = get_pid (pidfile, quiet)) == -1) + return (quiet ? 0 : -1); + + if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL) + return (0); + + for (i = 0; pids[i]; i++) { + if (test) { + if (! quiet) + einfo ("Would send signal %d to PID %d", sig, pids[i]); + nkilled++; + continue; + } + + if (verbose) + ebegin ("Sending signal %d to PID %d", sig, pids[i]); + errno = 0; + killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false); + if (! killed) { + if (! quiet) + eerror ("%s: failed to send signal %d to PID %d: %s", + progname, sig, pids[i], strerror (errno)); + if (verbose) + eend (1, NULL); + nkilled = -1; + } else { + if (verbose) + eend (0, NULL); + if (nkilled != -1) + nkilled++; + } + } + + free (pids); + return (nkilled); } static int run_stop_schedule (const char *exec, const char *cmd, - const char *pidfile, uid_t uid, - bool quiet, bool verbose, bool test) + const char *pidfile, uid_t uid, + bool quiet, bool verbose, bool test) { - schedulelist_t *item = schedule; - int nkilled = 0; - int tkilled = 0; - int nrunning = 0; - struct timeval tv; - struct timeval now; - struct timeval stopat; - - if (verbose) - { - if (pidfile) - einfo ("Will stop PID in pidfile `%s'", pidfile); - if (uid) - einfo ("Will stop processes owned by UID %d", uid); - if (exec) - einfo ("Will stop processes of `%s'", exec); - if (cmd) - einfo ("Will stop processes called `%s'", cmd); - } - - while (item) - { - switch (item->type) - { - case schedule_goto: - item = item->gotolist; - continue; - - case schedule_signal: - nrunning = 0; - nkilled = do_stop (exec, cmd, pidfile, uid, item->value, - quiet, verbose, test); - if (nkilled == 0) - { - if (tkilled == 0) - { - if (! quiet) - eerror ("%s: no matching processes found", progname); - } - return (tkilled); - } - else if (nkilled == -1) - return (0); - - tkilled += nkilled; - break; - case schedule_timeout: - if (item->value < 1) - { - item = NULL; - break; - } - - if (gettimeofday (&stopat, NULL) != 0) - { - eerror ("%s: gettimeofday: %s", progname, strerror (errno)); - return (0); - } - - stopat.tv_sec += item->value; - while (1) - { - if ((nrunning = do_stop (exec, cmd, pidfile, - uid, 0, true, false, true)) == 0) - return (true); - - tv.tv_sec = 0; - tv.tv_usec = POLL_INTERVAL; - if (select (0, 0, 0, 0, &tv) < 0) - { - if (errno == EINTR) - eerror ("%s: caught an interupt", progname); - else - eerror ("%s: select: %s", progname, strerror (errno)); - return (0); - } - - if (gettimeofday (&now, NULL) != 0) - { - eerror ("%s: gettimeofday: %s", progname, strerror (errno)); - return (0); - } - if (timercmp (&now, &stopat, >)) - break; - } - break; - - default: - eerror ("%s: invalid schedule item `%d'", progname, item->type); - return (0); - } - - if (item) - item = item->next; - } - - if (test || (tkilled > 0 && nrunning == 0)) - return (nkilled); - - if (! quiet) - { - if (nrunning == 1) - eerror ("%s: %d process refused to stop", progname, nrunning); - else - eerror ("%s: %d process(es) refused to stop", progname, nrunning); - } - - return (-nrunning); + schedulelist_t *item = schedule; + int nkilled = 0; + int tkilled = 0; + int nrunning = 0; + struct timeval tv; + struct timeval now; + struct timeval stopat; + + if (verbose) { + if (pidfile) + einfo ("Will stop PID in pidfile `%s'", pidfile); + if (uid) + einfo ("Will stop processes owned by UID %d", uid); + if (exec) + einfo ("Will stop processes of `%s'", exec); + if (cmd) + einfo ("Will stop processes called `%s'", cmd); + } + + while (item) { + switch (item->type) { + case schedule_goto: + item = item->gotolist; + continue; + + case schedule_signal: + nrunning = 0; + nkilled = do_stop (exec, cmd, pidfile, uid, item->value, + quiet, verbose, test); + if (nkilled == 0) { + if (tkilled == 0) { + if (! quiet) + eerror ("%s: no matching processes found", progname); + } + return (tkilled); + } + else if (nkilled == -1) + return (0); + + tkilled += nkilled; + break; + case schedule_timeout: + if (item->value < 1) { + item = NULL; + break; + } + + if (gettimeofday (&stopat, NULL) != 0) { + eerror ("%s: gettimeofday: %s", progname, strerror (errno)); + return (0); + } + + stopat.tv_sec += item->value; + while (1) { + if ((nrunning = do_stop (exec, cmd, pidfile, + uid, 0, true, false, true)) == 0) + return (true); + + tv.tv_sec = 0; + tv.tv_usec = POLL_INTERVAL; + if (select (0, 0, 0, 0, &tv) < 0) { + if (errno == EINTR) + eerror ("%s: caught an interupt", progname); + else + eerror ("%s: select: %s", progname, strerror (errno)); + return (0); + } + + if (gettimeofday (&now, NULL) != 0) { + eerror ("%s: gettimeofday: %s", progname, strerror (errno)); + return (0); + } + if (timercmp (&now, &stopat, >)) + break; + } + break; + + default: + eerror ("%s: invalid schedule item `%d'", progname, item->type); + return (0); + } + + if (item) + item = item->next; + } + + if (test || (tkilled > 0 && nrunning == 0)) + return (nkilled); + + if (! quiet) { + if (nrunning == 1) + eerror ("%s: %d process refused to stop", progname, nrunning); + else + eerror ("%s: %d process(es) refused to stop", progname, nrunning); + } + + return (-nrunning); } static void handle_signal (int sig) { - int pid; - int status; - int serrno = errno; - char signame[10] = { '\0' }; - - switch (sig) - { - case SIGINT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGINT"); - case SIGTERM: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGTERM"); - case SIGQUIT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGQUIT"); - eerrorx ("%s: caught %s, aborting", progname, signame); - - case SIGCHLD: - while (1) - { - if ((pid = waitpid (-1, &status, WNOHANG)) < 0) - { - if (errno != ECHILD) - eerror ("%s: waitpid: %s", progname, strerror (errno)); - break; - } - } - break; - - default: - eerror ("%s: caught unknown signal %d", progname, sig); - } - - /* Restore errno */ - errno = serrno; + int pid; + int status; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGINT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGINT"); + case SIGTERM: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGTERM"); + case SIGQUIT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGQUIT"); + eerrorx ("%s: caught %s, aborting", progname, signame); + + case SIGCHLD: + while (1) { + if ((pid = waitpid (-1, &status, WNOHANG)) < 0) { + if (errno != ECHILD) + eerror ("%s: waitpid: %s", progname, strerror (errno)); + break; + } + } + break; + + default: + eerror ("%s: caught unknown signal %d", progname, sig); + } + + /* Restore errno */ + errno = serrno; } int main (int argc, char **argv) { - int devnull_fd = -1; + int devnull_fd = -1; #ifdef TIOCNOTTY - int tty_fd = -1; + int tty_fd = -1; #endif #ifdef HAVE_PAM - pam_handle_t *pamh = NULL; - int pamr; + pam_handle_t *pamh = NULL; + int pamr; #endif - static struct option longopts[] = { - { "stop", 0, NULL, 'K'}, - { "nicelevel", 1, NULL, 'N'}, - { "retry", 1, NULL, 'R'}, - { "start", 0, NULL, 'S'}, - { "background", 0, NULL, 'b'}, - { "chuid", 1, NULL, 'c'}, - { "chdir", 1, NULL, 'd'}, - { "group", 1, NULL, 'g'}, - { "make-pidfile", 0, NULL, 'm'}, - { "name", 1, NULL, 'n'}, - { "oknodo", 0, NULL, 'o'}, - { "pidfile", 1, NULL, 'p'}, - { "quiet", 0, NULL, 'q'}, - { "signal", 1, NULL, 's'}, - { "test", 0, NULL, 't'}, - { "user", 1, NULL, 'u'}, - { "chroot", 1, NULL, 'r'}, - { "verbose", 0, NULL, 'v'}, - { "exec", 1, NULL, 'x'}, - { "stdout", 1, NULL, '1'}, - { "stderr", 1, NULL, '2'}, - { NULL, 0, NULL, 0} - }; - int c; - bool start = false; - bool stop = false; - bool oknodo = false; - bool test = false; - bool quiet = false; - bool verbose = false; - char *exec = NULL; - char *cmd = NULL; - char *pidfile = NULL; - int sig = SIGTERM; - uid_t uid = 0; - int nicelevel = 0; - bool background = false; - bool makepidfile = false; - uid_t ch_uid = 0; - gid_t ch_gid = 0; - char *ch_root = NULL; - char *ch_dir = NULL; - int tid = 0; - char *redirect_stderr = NULL; - char *redirect_stdout = NULL; - int stdout_fd; - int stderr_fd; - pid_t pid; - struct timeval tv; - int i; - char *svcname = getenv ("SVCNAME"); - char *env; - - progname = argv[0]; - atexit (cleanup); - - signal (SIGINT, handle_signal); - signal (SIGQUIT, handle_signal); - signal (SIGTERM, handle_signal); - - while ((c = getopt_long (argc, argv, - "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", - longopts, (int *) 0)) != -1) - switch (c) - { - case 'K': /* --stop */ - stop = true; - break; - - case 'N': /* --nice */ - if (sscanf (optarg, "%d", &nicelevel) != 1) - eerrorx ("%s: invalid nice level `%s'", progname, optarg); - break; - - case 'R': /* --retry | */ - parse_schedule (optarg, sig); - break; - - case 'S': /* --start */ - start = true; - break; - - case 'b': /* --background */ - background = true; - break; - - case 'c': /* --chuid | */ - /* we copy the string just in case we need the - * argument later. */ - { - char *p = optarg; - char *cu = strsep (&p, ":"); - changeuser = strdup (cu); - if (sscanf (cu, "%d", &tid) != 1) - { - struct passwd *pw = getpwnam (cu); - if (! pw) - eerrorx ("%s: user `%s' not found", progname, cu); - ch_uid = pw->pw_uid; - } - else - ch_uid = tid; - if (p) - { - char *cg = strsep (&p, ":"); - if (sscanf (cg, "%d", &tid) != 1) - { - struct group *gr = getgrnam (cg); - if (! gr) - eerrorx ("%s: group `%s' not found", progname, cg); - ch_gid = gr->gr_gid; - } - else - ch_gid = tid; - } - } - break; - - case 'd': /* --chdir /new/dir */ - ch_dir = optarg; - break; - - case 'g': /* --group | */ - if (sscanf (optarg, "%d", &tid) != 1) - { - struct group *gr = getgrnam (optarg); - if (! gr) - eerrorx ("%s: group `%s' not found", progname, optarg); - ch_gid = gr->gr_gid; - } - else - ch_gid = tid; - break; - - case 'm': /* --make-pidfile */ - makepidfile = true; - break; - - case 'n': /* --name */ - cmd = optarg; - break; - - case 'o': /* --oknodo */ - oknodo = true; - break; - - case 'p': /* --pidfile */ - pidfile = optarg; - break; - - case 'q': /* --quiet */ - quiet = true; - break; - - case 's': /* --signal */ - sig = parse_signal (optarg); - break; - - case 't': /* --test */ - test = true; - break; - - case 'u': /* --user | */ - if (sscanf (optarg, "%d", &tid) != 1) - { - struct passwd *pw = getpwnam (optarg); - if (! pw) - eerrorx ("%s: user `%s' not found", progname, optarg); - uid = pw->pw_uid; - } - else - uid = tid; - break; - - case 'r': /* --chroot /new/root */ - ch_root = optarg; - break; - - case 'v': /* --verbose */ - verbose = true; - break; - - case 'x': /* --exec */ - exec = optarg; - break; - - case '1': /* --stdout /path/to/stdout.lgfile */ - redirect_stdout = optarg; - break; - - case '2': /* --stderr /path/to/stderr.logfile */ - redirect_stderr = optarg; - break; - - default: - exit (EXIT_FAILURE); - } - - /* Respect RC as well as how we are called */ - if (rc_is_env ("RC_QUIET", "yes") && ! verbose) - quiet = true; - - if (start == stop) - eerrorx ("%s: need one of --start or --stop", progname); - - if (start && ! exec) - eerrorx ("%s: --start needs --exec", progname); - - if (stop && ! exec && ! pidfile && ! cmd && ! uid) - eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname); - - if (makepidfile && ! pidfile) - eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname); - - if (background && ! start) - eerrorx ("%s: --background is only relevant with --start", progname); - - if ((redirect_stdout || redirect_stderr) && ! background) - eerrorx ("%s: --stdout and --stderr are only relevant with --background", - progname); - - argc -= optind; - argv += optind; - - /* Validate that the binary rc_exists if we are starting */ - if (exec && start) - { - char *tmp; - if (ch_root) - tmp = rc_strcatpaths (ch_root, exec, (char *) NULL); - else - tmp = exec; - if (! rc_is_file (tmp)) - { - eerror ("%s: %s does not exist", progname, tmp); - if (ch_root) - free (tmp); - exit (EXIT_FAILURE); - } - if (ch_root) - free (tmp); - } - - if (stop) - { - int result; - - if (! schedule) - { - if (test || oknodo) - parse_schedule ("0", sig); - else - parse_schedule (NULL, sig); - } - - result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); - if (test || oknodo) - return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); - if (result < 1) - exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); - - if (pidfile && rc_is_file (pidfile)) - unlink (pidfile); - - if (svcname) - rc_set_service_daemon (svcname, exec, cmd, pidfile, false); - - exit (EXIT_SUCCESS); - } - - if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) - eerrorx ("%s: %s is already running", progname, exec); - - if (test) - { - if (quiet) - exit (EXIT_SUCCESS); - - einfon ("Would start %s", exec); - while (argc-- > 0) - printf("%s ", *argv++); - printf ("\n"); - eindent (); - if (ch_uid != 0) - einfo ("as user %d", ch_uid); - if (ch_gid != 0) - einfo ("as group %d", ch_gid); - if (ch_root) - einfo ("in root `%s'", ch_root); - if (ch_dir) - einfo ("in dir `%s'", ch_dir); - if (nicelevel != 0) - einfo ("with a priority of %d", nicelevel); - eoutdent (); - exit (EXIT_SUCCESS); - } - - /* Ensure this is unset, so if the daemon does /etc/init.d/foo - Then we filter the environment accordingly */ - unsetenv ("RC_SOFTLEVEL"); - - if (verbose) - { - ebegin ("Detaching to start `%s'", exec); - eindent (); - } - - if (background) - signal (SIGCHLD, handle_signal); - - *--argv = exec; - if ((pid = fork ()) == -1) - eerrorx ("%s: fork: %s", progname, strerror (errno)); - - /* Child process - lets go! */ - if (pid == 0) - { - pid_t mypid = getpid (); + static struct option longopts[] = { + { "stop", 0, NULL, 'K'}, + { "nicelevel", 1, NULL, 'N'}, + { "retry", 1, NULL, 'R'}, + { "start", 0, NULL, 'S'}, + { "background", 0, NULL, 'b'}, + { "chuid", 1, NULL, 'c'}, + { "chdir", 1, NULL, 'd'}, + { "group", 1, NULL, 'g'}, + { "make-pidfile", 0, NULL, 'm'}, + { "name", 1, NULL, 'n'}, + { "oknodo", 0, NULL, 'o'}, + { "pidfile", 1, NULL, 'p'}, + { "quiet", 0, NULL, 'q'}, + { "signal", 1, NULL, 's'}, + { "test", 0, NULL, 't'}, + { "user", 1, NULL, 'u'}, + { "chroot", 1, NULL, 'r'}, + { "verbose", 0, NULL, 'v'}, + { "exec", 1, NULL, 'x'}, + { "stdout", 1, NULL, '1'}, + { "stderr", 1, NULL, '2'}, + { NULL, 0, NULL, 0} + }; + int c; + bool start = false; + bool stop = false; + bool oknodo = false; + bool test = false; + bool quiet = false; + bool verbose = false; + char *exec = NULL; + char *cmd = NULL; + char *pidfile = NULL; + int sig = SIGTERM; + uid_t uid = 0; + int nicelevel = 0; + bool background = false; + bool makepidfile = false; + uid_t ch_uid = 0; + gid_t ch_gid = 0; + char *ch_root = NULL; + char *ch_dir = NULL; + int tid = 0; + char *redirect_stderr = NULL; + char *redirect_stdout = NULL; + int stdout_fd; + int stderr_fd; + pid_t pid; + struct timeval tv; + int i; + char *svcname = getenv ("SVCNAME"); + char *env; + + progname = argv[0]; + atexit (cleanup); + + signal (SIGINT, handle_signal); + signal (SIGQUIT, handle_signal); + signal (SIGTERM, handle_signal); + + while ((c = getopt_long (argc, argv, + "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", + longopts, (int *) 0)) != -1) + switch (c) { + case 'K': /* --stop */ + stop = true; + break; + + case 'N': /* --nice */ + if (sscanf (optarg, "%d", &nicelevel) != 1) + eerrorx ("%s: invalid nice level `%s'", progname, optarg); + break; + + case 'R': /* --retry | */ + parse_schedule (optarg, sig); + break; + + case 'S': /* --start */ + start = true; + break; + + case 'b': /* --background */ + background = true; + break; + + case 'c': /* --chuid | */ + /* we copy the string just in case we need the + * argument later. */ + { + char *p = optarg; + char *cu = strsep (&p, ":"); + changeuser = strdup (cu); + if (sscanf (cu, "%d", &tid) != 1) { + struct passwd *pw = getpwnam (cu); + if (! pw) + eerrorx ("%s: user `%s' not found", progname, cu); + ch_uid = pw->pw_uid; + } else + ch_uid = tid; + if (p) { + char *cg = strsep (&p, ":"); + if (sscanf (cg, "%d", &tid) != 1) { + struct group *gr = getgrnam (cg); + if (! gr) + eerrorx ("%s: group `%s' not found", progname, cg); + ch_gid = gr->gr_gid; + } else + ch_gid = tid; + } + } + break; + + case 'd': /* --chdir /new/dir */ + ch_dir = optarg; + break; + + case 'g': /* --group | */ + if (sscanf (optarg, "%d", &tid) != 1) { + struct group *gr = getgrnam (optarg); + if (! gr) + eerrorx ("%s: group `%s' not found", progname, optarg); + ch_gid = gr->gr_gid; + } else + ch_gid = tid; + break; + + case 'm': /* --make-pidfile */ + makepidfile = true; + break; + + case 'n': /* --name */ + cmd = optarg; + break; + + case 'o': /* --oknodo */ + oknodo = true; + break; + + case 'p': /* --pidfile */ + pidfile = optarg; + break; + + case 'q': /* --quiet */ + quiet = true; + break; + + case 's': /* --signal */ + sig = parse_signal (optarg); + break; + + case 't': /* --test */ + test = true; + break; + + case 'u': /* --user | */ + if (sscanf (optarg, "%d", &tid) != 1) { + struct passwd *pw = getpwnam (optarg); + if (! pw) + eerrorx ("%s: user `%s' not found", progname, optarg); + uid = pw->pw_uid; + } else + uid = tid; + break; + + case 'r': /* --chroot /new/root */ + ch_root = optarg; + break; + + case 'v': /* --verbose */ + verbose = true; + break; + + case 'x': /* --exec */ + exec = optarg; + break; + + case '1': /* --stdout /path/to/stdout.lgfile */ + redirect_stdout = optarg; + break; + + case '2': /* --stderr /path/to/stderr.logfile */ + redirect_stderr = optarg; + break; + + default: + exit (EXIT_FAILURE); + } + + /* Respect RC as well as how we are called */ + if (rc_is_env ("RC_QUIET", "yes") && ! verbose) + quiet = true; + + if (start == stop) + eerrorx ("%s: need one of --start or --stop", progname); + + if (start && ! exec) + eerrorx ("%s: --start needs --exec", progname); + + if (stop && ! exec && ! pidfile && ! cmd && ! uid) + eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname); + + if (makepidfile && ! pidfile) + eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname); + + if (background && ! start) + eerrorx ("%s: --background is only relevant with --start", progname); + + if ((redirect_stdout || redirect_stderr) && ! background) + eerrorx ("%s: --stdout and --stderr are only relevant with --background", + progname); + + argc -= optind; + argv += optind; + + /* Validate that the binary rc_exists if we are starting */ + if (exec && start) { + char *tmp; + if (ch_root) + tmp = rc_strcatpaths (ch_root, exec, (char *) NULL); + else + tmp = exec; + if (! rc_is_file (tmp)) { + eerror ("%s: %s does not exist", progname, tmp); + if (ch_root) + free (tmp); + exit (EXIT_FAILURE); + } + if (ch_root) + free (tmp); + } + + if (stop) { + int result; + + if (! schedule) { + if (test || oknodo) + parse_schedule ("0", sig); + else + parse_schedule (NULL, sig); + } + + result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); + if (test || oknodo) + return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); + if (result < 1) + exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + + if (pidfile && rc_is_file (pidfile)) + unlink (pidfile); + + if (svcname) + rc_set_service_daemon (svcname, exec, cmd, pidfile, false); + + exit (EXIT_SUCCESS); + } + + if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) + eerrorx ("%s: %s is already running", progname, exec); + + if (test) { + if (quiet) + exit (EXIT_SUCCESS); + + einfon ("Would start %s", exec); + while (argc-- > 0) + printf("%s ", *argv++); + printf ("\n"); + eindent (); + if (ch_uid != 0) + einfo ("as user %d", ch_uid); + if (ch_gid != 0) + einfo ("as group %d", ch_gid); + if (ch_root) + einfo ("in root `%s'", ch_root); + if (ch_dir) + einfo ("in dir `%s'", ch_dir); + if (nicelevel != 0) + einfo ("with a priority of %d", nicelevel); + eoutdent (); + exit (EXIT_SUCCESS); + } + + /* Ensure this is unset, so if the daemon does /etc/init.d/foo + Then we filter the environment accordingly */ + unsetenv ("RC_SOFTLEVEL"); + + if (verbose) { + ebegin ("Detaching to start `%s'", exec); + eindent (); + } + + if (background) + signal (SIGCHLD, handle_signal); + + *--argv = exec; + if ((pid = fork ()) == -1) + eerrorx ("%s: fork: %s", progname, strerror (errno)); + + /* Child process - lets go! */ + if (pid == 0) { + pid_t mypid = getpid (); #ifdef TIOCNOTTY - tty_fd = open("/dev/tty", O_RDWR); + tty_fd = open("/dev/tty", O_RDWR); #endif - devnull_fd = open("/dev/null", O_RDWR); + devnull_fd = open("/dev/null", O_RDWR); - if (nicelevel) - { - if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1) - eerrorx ("%s: setpritory %d: %s", progname, nicelevel, - strerror(errno)); - } + if (nicelevel) { + if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1) + eerrorx ("%s: setpritory %d: %s", progname, nicelevel, + strerror(errno)); + } - if (ch_root && chroot (ch_root) < 0) - eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno)); + if (ch_root && chroot (ch_root) < 0) + eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno)); - if (ch_dir && chdir (ch_dir) < 0) - eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno)); + if (ch_dir && chdir (ch_dir) < 0) + eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno)); - if (makepidfile && pidfile) - { - FILE *fp = fopen (pidfile, "w"); - if (! fp) - eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror - (errno)); - fprintf (fp, "%d\n", mypid); - fclose (fp); - } + if (makepidfile && pidfile) { + FILE *fp = fopen (pidfile, "w"); + if (! fp) + eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror + (errno)); + fprintf (fp, "%d\n", mypid); + fclose (fp); + } #ifdef HAVE_PAM - if (changeuser != NULL) - pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh); - else - pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh); - - if (pamr == PAM_SUCCESS) - pamr = pam_authenticate (pamh, PAM_SILENT); - if (pamr == PAM_SUCCESS) - pamr = pam_acct_mgmt (pamh, PAM_SILENT); - if (pamr == PAM_SUCCESS) - pamr = pam_open_session (pamh, PAM_SILENT); - if (pamr != PAM_SUCCESS) - eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr)); + if (changeuser != NULL) + pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh); + else + pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh); + + if (pamr == PAM_SUCCESS) + pamr = pam_authenticate (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_acct_mgmt (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_open_session (pamh, PAM_SILENT); + if (pamr != PAM_SUCCESS) + eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr)); #endif - if ((ch_gid) && setgid(ch_gid)) - eerrorx ("%s: unable to set groupid to %d", progname, ch_gid); - if (changeuser && ch_gid) - if (initgroups (changeuser, ch_gid)) - eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid); - if (ch_uid && setuid (ch_uid)) - eerrorx ("%s: unable to set userid to %d", progname, ch_uid); - else - { - struct passwd *passwd = getpwuid (ch_uid); - if (passwd) - { - unsetenv ("HOME"); - if (passwd->pw_dir) - setenv ("HOME", passwd->pw_dir, 1); - unsetenv ("USER"); - if (passwd->pw_name) - setenv ("USER", passwd->pw_name, 1); - } - } - - /* Close any fd's to the passwd database */ - endpwent (); + if ((ch_gid) && setgid(ch_gid)) + eerrorx ("%s: unable to set groupid to %d", progname, ch_gid); + if (changeuser && ch_gid) + if (initgroups (changeuser, ch_gid)) + eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid); + if (ch_uid && setuid (ch_uid)) + eerrorx ("%s: unable to set userid to %d", progname, ch_uid); + else { + struct passwd *passwd = getpwuid (ch_uid); + if (passwd) { + unsetenv ("HOME"); + if (passwd->pw_dir) + setenv ("HOME", passwd->pw_dir, 1); + unsetenv ("USER"); + if (passwd->pw_name) + setenv ("USER", passwd->pw_name, 1); + } + } + + /* Close any fd's to the passwd database */ + endpwent (); #ifdef TIOCNOTTY - ioctl(tty_fd, TIOCNOTTY, 0); - close(tty_fd); + ioctl(tty_fd, TIOCNOTTY, 0); + close(tty_fd); #endif - /* Clean the environment of any RC_ variables */ - STRLIST_FOREACH (environ, env, i) - if (env && strncmp (env, "RC_", 3) != 0) - { - /* For the path character, remove the rcscript bin dir from it */ - if (strncmp (env, "PATH=" RC_LIBDIR "bin:", - strlen ("PATH=" RC_LIBDIR "bin:")) == 0) - { - char *path = env; - char *newpath; - int len; - path += strlen ("PATH=" RC_LIBDIR "bin:"); - len = sizeof (char *) * strlen (path) + 6; - newpath = rc_xmalloc (len); - snprintf (newpath, len, "PATH=%s", path); - newenv = rc_strlist_add (newenv, newpath); - free (newpath); - } - else - newenv = rc_strlist_add (newenv, env); - } - - umask (022); - - stdout_fd = devnull_fd; - stderr_fd = devnull_fd; - if (redirect_stdout) - { - if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, - S_IRUSR | S_IWUSR)) == -1) - eerrorx ("%s: unable to open the logfile for stdout `%s': %s", - progname, redirect_stdout, strerror (errno)); - } - if (redirect_stderr) - { - if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, - S_IRUSR | S_IWUSR)) == -1) - eerrorx ("%s: unable to open the logfile for stderr `%s': %s", - progname, redirect_stderr, strerror (errno)); - } - - dup2 (devnull_fd, STDIN_FILENO); - if (background) - { - dup2 (stdout_fd, STDOUT_FILENO); - dup2 (stderr_fd, STDERR_FILENO); - } - - for (i = getdtablesize () - 1; i >= 3; --i) - close(i); - - setsid (); - - execve (exec, argv, newenv); + /* Clean the environment of any RC_ variables */ + STRLIST_FOREACH (environ, env, i) + if (env && strncmp (env, "RC_", 3) != 0) { + /* For the path character, remove the rcscript bin dir from it */ + if (strncmp (env, "PATH=" RC_LIBDIR "bin:", + strlen ("PATH=" RC_LIBDIR "bin:")) == 0) + { + char *path = env; + char *newpath; + int len; + path += strlen ("PATH=" RC_LIBDIR "bin:"); + len = sizeof (char *) * strlen (path) + 6; + newpath = rc_xmalloc (len); + snprintf (newpath, len, "PATH=%s", path); + newenv = rc_strlist_add (newenv, newpath); + free (newpath); + } else + newenv = rc_strlist_add (newenv, env); + } + + umask (022); + + stdout_fd = devnull_fd; + stderr_fd = devnull_fd; + if (redirect_stdout) { + if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx ("%s: unable to open the logfile for stdout `%s': %s", + progname, redirect_stdout, strerror (errno)); + } + if (redirect_stderr) { + if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx ("%s: unable to open the logfile for stderr `%s': %s", + progname, redirect_stderr, strerror (errno)); + } + + if (background) { + /* Hmmm, some daemons may need stdin? */ + dup2 (devnull_fd, STDIN_FILENO); + dup2 (stdout_fd, STDOUT_FILENO); + dup2 (stderr_fd, STDERR_FILENO); + } + + for (i = getdtablesize () - 1; i >= 3; --i) + close(i); + + setsid (); + + execve (exec, argv, newenv); #ifdef HAVE_PAM - if (pamr == PAM_SUCCESS) - pam_close_session (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pam_close_session (pamh, PAM_SILENT); #endif - eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno)); - } - - /* Parent process */ - if (! background) - { - /* As we're not backgrounding the process, wait for our pid to return */ - int status = 0; - int savepid = pid; - - errno = 0; - do - { - pid = waitpid (savepid, &status, 0); - if (pid < 1) - { - eerror ("waitpid %d: %s", savepid, strerror (errno)); - return (-1); - } - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) - { - if (! quiet) - eerrorx ("%s: failed to started `%s'", progname, exec); - exit (EXIT_FAILURE); - } - - pid = savepid; - } - - /* Wait a little bit and check that process is still running - We do this as some badly written daemons fork and then barf */ - if (START_WAIT > 0) - { - struct timeval stopat; - struct timeval now; - - if (gettimeofday (&stopat, NULL) != 0) - eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); - - stopat.tv_usec += START_WAIT; - while (1) - { - bool alive = false; - - tv.tv_sec = 0; - tv.tv_usec = POLL_INTERVAL; - if (select (0, 0, 0, 0, &tv) < 0) - { - /* Let our signal handler handle the interupt */ - if (errno != EINTR) - eerrorx ("%s: select: %s", progname, strerror (errno)); - } - - if (gettimeofday (&now, NULL) != 0) - eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); - - /* This is knarly. - If we backgrounded then we know the exact pid. - Otherwise if we have a pidfile then it *may* know the exact pid. - Failing that, we'll have to query processes. - We sleep first as some programs like ntp like to fork, and write - their pidfile a LONG time later. */ - if (background) - { - if (kill (pid, 0) == 0) - alive = true; - } - else - { - if (pidfile && rc_exists (pidfile)) - { - if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0) - alive = true; - } - else - { - if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0) - alive = true; - } - } - - if (! alive) - eerrorx ("%s: %s died", progname, exec); - - if (timercmp (&now, &stopat, >)) - break; - } - } - - if (svcname) - rc_set_service_daemon (svcname, exec, cmd, pidfile, true); - - exit (EXIT_SUCCESS); + eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno)); + } + + /* Parent process */ + if (! background) { + /* As we're not backgrounding the process, wait for our pid to return */ + int status = 0; + int savepid = pid; + + errno = 0; + do { + pid = waitpid (savepid, &status, 0); + if (pid < 1) { + eerror ("waitpid %d: %s", savepid, strerror (errno)); + return (-1); + } + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) { + if (! quiet) + eerrorx ("%s: failed to started `%s'", progname, exec); + exit (EXIT_FAILURE); + } + + pid = savepid; + } + + /* Wait a little bit and check that process is still running + We do this as some badly written daemons fork and then barf */ + if (START_WAIT > 0) { + struct timeval stopat; + struct timeval now; + + if (gettimeofday (&stopat, NULL) != 0) + eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); + + stopat.tv_usec += START_WAIT; + while (1) { + bool alive = false; + + tv.tv_sec = 0; + tv.tv_usec = POLL_INTERVAL; + if (select (0, 0, 0, 0, &tv) < 0) { + /* Let our signal handler handle the interupt */ + if (errno != EINTR) + eerrorx ("%s: select: %s", progname, strerror (errno)); + } + + if (gettimeofday (&now, NULL) != 0) + eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); + + /* This is knarly. + If we backgrounded then we know the exact pid. + Otherwise if we have a pidfile then it *may* know the exact pid. + Failing that, we'll have to query processes. + We sleep first as some programs like ntp like to fork, and write + their pidfile a LONG time later. */ + if (background) { + if (kill (pid, 0) == 0) + alive = true; + } else { + if (pidfile && rc_exists (pidfile)) { + if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0) + alive = true; + } else { + if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0) + alive = true; + } + } + + if (! alive) + eerrorx ("%s: %s died", progname, exec); + + if (timercmp (&now, &stopat, >)) + break; + } + } + + if (svcname) + rc_set_service_daemon (svcname, exec, cmd, pidfile, true); + + exit (EXIT_SUCCESS); } diff --git a/src/strlist.h b/src/strlist.h index d3d54709..66dce13c 100644 --- a/src/strlist.h +++ b/src/strlist.h @@ -18,7 +18,7 @@ it should usually by +1 from what you expect, and should only be used in the scope of the macro) */ #define STRLIST_FOREACH(_list, _pos, _counter) \ - if ((_list) && _list[0] && ! (_counter = 0)) \ - while ((_pos = _list[_counter++])) + if ((_list) && _list[0] && ! (_counter = 0)) \ + while ((_pos = _list[_counter++])) #endif /* __STRLIST_H__ */ -- cgit v1.2.3