diff options
-rw-r--r-- | src/Makefile | 12 | ||||
-rw-r--r-- | src/_usage.c | 2 | ||||
-rw-r--r-- | src/einfo.h | 129 | ||||
-rw-r--r-- | src/librc-misc.c | 9 | ||||
-rw-r--r-- | src/librc-strlist.c | 6 | ||||
-rw-r--r-- | src/librc.c | 43 | ||||
-rw-r--r-- | src/rc-status.c | 7 | ||||
-rw-r--r-- | src/rc-update.c | 7 | ||||
-rw-r--r-- | src/rc.c | 11 | ||||
-rw-r--r-- | src/rc.h | 386 | ||||
-rw-r--r-- | src/runscript.c | 3 |
11 files changed, 465 insertions, 150 deletions
diff --git a/src/Makefile b/src/Makefile index 4807ed03..d657d9eb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -75,13 +75,13 @@ RC_BINLINKS = einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \ service_inactive service_wasinactive \ service_coldplugged \ is_runlevel_start is_runlevel_stop service_started_daemon \ - checkown fstabinfo mountinfo rc-depend + checkown fstabinfo mountinfo rc-depend \ + get_options save_options RC_SBINLINKS = mark_service_starting mark_service_inactive \ - mark_service_started \ - mark_service_stopping mark_service_stopped \ - mark_service_inactive mark_service_wasinactive \ - mark_service_coldplugged \ - get_options save_options rc-abort + mark_service_started mark_service_stopping \ + mark_service_stopped mark_service_inactive \ + mark_service_wasinactive mark_service_coldplugged \ + rc-abort BINLINKS = rc-status SBINLINKS = env-update rc-update runscript start-stop-daemon ALL_LINKS = $(sort $(BINLINKS) $(SBINLINKS) $(RC_BINLINKS) $(RC_SBINLINKS)) diff --git a/src/_usage.c b/src/_usage.c index 28f98150..66ae8df0 100644 --- a/src/_usage.c +++ b/src/_usage.c @@ -1,4 +1,4 @@ -/* +/*! * @file _usage.c * @brief standardize help/usage output across all our programs * @internal diff --git a/src/einfo.h b/src/einfo.h index dc07b903..94c99072 100644 --- a/src/einfo.h +++ b/src/einfo.h @@ -1,21 +1,31 @@ -/* - rc.h - Header file for external applications to get RC information. - Copyright 2007 Gentoo Foundation - Released under the GPLv2 - */ +/*! + * @file einfo.h + * @brief Describes how to interface with the einfo library + * + * Copyright 2007 Gentoo Foundation + * Released under the GPLv2 + */ #ifndef __EINFO_H__ #define __EINFO_H__ +#define EINFO_PRINTF +#define EINFO_XPRINTF +#define EEND_PRINTF + #ifdef __GNUC__ -# define EINFO_PRINTF(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two))) -# define EINFO_XPRINTF(_one, _two) __attribute__ ((__noreturn__, __format__ (__printf__, _one, _two))) +# undef EINFO_PRINTF +# undef EINFO_XPRINTF +# undef EEND_PRINTF +# define EINFO_PRINTF __attribute__ ((__format__ (__printf__, 1, 2))) +# define EINFO_XPRINTF __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2))) +# define EEND_PRINTF __attribute__ ((__format__ (__printf__, 2, 3))) #endif #include <sys/types.h> #include <stdbool.h> +/*! @brief Color types to use */ typedef enum { ecolor_good, @@ -26,46 +36,83 @@ typedef enum ecolor_normal } einfo_color_t; -/* We work out if the terminal supports colour or not through the use - of the TERM env var. We cache the reslt in a static bool, so - subsequent calls are very fast. - The n suffix means that a newline is NOT appended to the string - The v suffix means that we only print it when RC_VERBOSE=yes - 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 - */ +/*! @brief Returns the ASCII code for the color */ const char *ecolor (einfo_color_t); -void elog (int level, const char *fmt, ...) EINFO_PRINTF (2, 3); -int einfon (const char *fmt, ...) EINFO_PRINTF (1, 2); -int ewarnn (const char *fmt, ...) EINFO_PRINTF (1, 2); -int eerrorn (const char *fmt, ...) EINFO_PRINTF (1, 2); -int einfo (const char *fmt, ...) EINFO_PRINTF(1, 2); -int ewarn (const char *fmt, ...) EINFO_PRINTF (1, 2); -void ewarnx (const char *fmt, ...) EINFO_XPRINTF (1,2); -int eerror (const char *fmt, ...) EINFO_PRINTF (1,2); -void eerrorx (const char *fmt, ...) EINFO_XPRINTF (1,2); -int ebegin (const char *fmt, ...) EINFO_PRINTF (1, 2); -int eend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); -int ewend (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); + +/*! @brief Writes to syslog. */ +void elog (int level, const char *fmt, ...) EEND_PRINTF; + +/*! + * @brief Display informational messages. + * + * The einfo family of functions display messages in a consistent manner + * across Gentoo applications. Basically they prefix the message with + * " * ". If the terminal can handle color then we color the * based on + * the command used. Otherwise we are identical to the printf function. + * + * - einfo - green + * - ewarn - yellow + * - eerror - red + * + * The n suffix denotes that no new line should be printed. + * The v suffix means only print if RC_VERBOSE is yes. + */ +/*@{*/ +int einfon (const char *fmt, ...) EINFO_PRINTF; +int ewarnn (const char *fmt, ...) EINFO_PRINTF; +int eerrorn (const char *fmt, ...) EINFO_PRINTF; +int einfo (const char *fmt, ...) EINFO_PRINTF; +int ewarn (const char *fmt, ...) EINFO_PRINTF; +void ewarnx (const char *fmt, ...) EINFO_XPRINTF; +int eerror (const char *fmt, ...) EINFO_PRINTF; +void eerrorx (const char *fmt, ...) EINFO_XPRINTF; + +int einfovn (const char *fmt, ...) EINFO_PRINTF; +int ewarnvn (const char *fmt, ...) EINFO_PRINTF; +int ebeginvn (const char *fmt, ...) EINFO_PRINTF; +int eendvn (int retval, const char *fmt, ...) EEND_PRINTF; +int ewendvn (int retval, const char *fmt, ...) EEND_PRINTF; +int einfov (const char *fmt, ...) EINFO_PRINTF; +int ewarnv (const char *fmt, ...) EINFO_PRINTF; +/*@}*/ + +/*! @ingroup ebegin + * @brief Display informational messages that may take some time. + * + * Similar to einfo, but we add ... to the end of the message */ +/*@{*/ +int ebeginv (const char *fmt, ...) EINFO_PRINTF; +int ebegin (const char *fmt, ...) EINFO_PRINTF; +/*@}*/ + +/*! @ingroup eend + * @brief End an ebegin. + * + * If you ebegin, you should eend also. + * eend places [ ok ] or [ !! ] at the end of the terminal line depending on + * retval (0 or ok, anything else for !!) + * + * ebracket allows you to specifiy the position, color and message */ +/*@{*/ +int eend (int retval, const char *fmt, ...) EEND_PRINTF; +int ewend (int retval, const char *fmt, ...) EEND_PRINTF; void ebracket (int col, einfo_color_t color, const char *msg); + +int eendv (int retval, const char *fmt, ...) EEND_PRINTF; +int ewendv (int retval, const char *fmt, ...) EEND_PRINTF; +/*@}*/ + +/*! @ingroup eindent + * @brief Indents the einfo lines. + * + * For each indent you should outdent when done */ +/*@{*/ void eindent (void); void eoutdent (void); - -int einfovn (const char *fmt, ...) EINFO_PRINTF (1, 2); -int ewarnvn (const char *fmt, ...) EINFO_PRINTF (1, 2); -int ebeginvn (const char *fmt, ...) EINFO_PRINTF (1, 2); -int eendvn (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); -int ewendvn (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); -int einfov (const char *fmt, ...) EINFO_PRINTF (1, 2); -int ewarnv (const char *fmt, ...) EINFO_PRINTF (1, 2); -int ebeginv (const char *fmt, ...) EINFO_PRINTF (1, 2); -int eendv (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); -int ewendv (int retval, const char *fmt, ...) EINFO_PRINTF (2, 3); void eindentv (void); void eoutdentv (void); -/* Pointer to a string that is always prefixed to einfo/ewarn/error */ +/*! @brief Prefix each einfo line with something */ void eprefix (const char *prefix); #endif diff --git a/src/librc-misc.c b/src/librc-misc.c index ebf020e2..bd92e584 100644 --- a/src/librc-misc.c +++ b/src/librc-misc.c @@ -588,9 +588,10 @@ char **rc_make_env (void) bool has_net_fs_list = false; FILE *fp; char buffer[PATH_MAX]; + char *runlevel = rc_get_runlevel (); /* Don't trust environ for softlevel yet */ - snprintf (buffer, PATH_MAX, "%s.%s", RC_CONFIG, rc_get_runlevel()); + snprintf (buffer, PATH_MAX, "%s.%s", RC_CONFIG, runlevel); if (rc_exists (buffer)) config = rc_get_config (buffer); else @@ -632,10 +633,9 @@ char **rc_make_env (void) rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT); - p = rc_get_runlevel (); - i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1; + i = strlen ("RC_SOFTLEVEL=") + strlen (runlevel) + 1; line = rc_xmalloc (sizeof (char *) * i); - snprintf (line, i, "RC_SOFTLEVEL=%s", p); + snprintf (line, i, "RC_SOFTLEVEL=%s", runlevel); rc_strlist_add (&env, line); free (line); @@ -717,6 +717,7 @@ char **rc_make_env (void) free (line); } + free (runlevel); return (env); } librc_hidden_def(rc_make_env) diff --git a/src/librc-strlist.c b/src/librc-strlist.c index 14d08baa..9645acb0 100644 --- a/src/librc-strlist.c +++ b/src/librc-strlist.c @@ -135,7 +135,7 @@ int rc_strlist_delete (char ***list, const char *item) } librc_hidden_def(rc_strlist_delete) -int rc_strlist_join (char ***list1, char **list2) +char *rc_strlist_join (char ***list1, char **list2) { char **lst1 = *list1; char **newlist; @@ -143,7 +143,7 @@ int rc_strlist_join (char ***list1, char **list2) int j = 0; if (! list2) - return (0); + return (NULL); while (lst1 && lst1[i]) i++; @@ -164,7 +164,7 @@ int rc_strlist_join (char ***list1, char **list2) newlist[i] = NULL; *list1 = newlist; - return (0); + return (newlist[i == 0 ? 0 : i - 1]); } librc_hidden_def(rc_strlist_join) diff --git a/src/librc.c b/src/librc.c index f501719e..dd2e0b6b 100644 --- a/src/librc.c +++ b/src/librc.c @@ -65,24 +65,23 @@ librc_hidden_def(rc_get_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; + char buffer[RC_LINEBUFFER]; + char *runlevel = NULL; + + if ((fp = fopen (SOFTLEVEL, "r"))) { + if (fgets (buffer, PATH_MAX, fp)) { + int i = strlen (buffer) - 1; + if (buffer[i] == '\n') + buffer[i] = 0; + runlevel = rc_xstrdup (buffer); + } fclose (fp); - return (buffer); } - fclose (fp); - snprintf (buffer, sizeof (buffer), "sysinit"); - return (buffer); + if (! runlevel) + runlevel = rc_xstrdup (RC_LEVEL_SYSINIT); + + return (runlevel); } librc_hidden_def(rc_get_runlevel) @@ -452,31 +451,27 @@ bool rc_service_state (const char *service, const rc_service_state_t state) } librc_hidden_def(rc_service_state) -bool rc_get_service_option (const char *service, const char *option, - char *value) +char *rc_get_service_option (const char *service, const char *option) { FILE *fp; char buffer[RC_LINEBUFFER]; char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option, (char *) NULL); - bool retval = false; + char *value = NULL; 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); - } + if (fgets (buffer, RC_LINEBUFFER, fp)) + value = rc_xstrdup (buffer); fclose (fp); - retval = true; } } free (file); - return (retval); + return (value); } librc_hidden_def(rc_get_service_option) diff --git a/src/rc-status.c b/src/rc-status.c index f75bfb83..cd4a24f8 100644 --- a/src/rc-status.c +++ b/src/rc-status.c @@ -117,8 +117,11 @@ int rc_status (int argc, char **argv) while (optind < argc) rc_strlist_add (&levels, argv[optind++]); - if (! levels) - rc_strlist_add (&levels, rc_get_runlevel ()); + if (! levels) { + level = rc_get_runlevel (); + rc_strlist_add (&levels, level); + free (level); + } STRLIST_FOREACH (levels, level, i) { print_level (level); diff --git a/src/rc-update.c b/src/rc-update.c index fc9ef504..34f10b91 100644 --- a/src/rc-update.c +++ b/src/rc-update.c @@ -208,8 +208,11 @@ int rc_update (int argc, char **argv) eerror ("%s: service `%s' does not exist", applet, service); else { retval = EXIT_SUCCESS; - if (! runlevels) - rc_strlist_add (&runlevels, rc_get_runlevel ()); + if (! runlevels) { + runlevel = rc_get_runlevel (); + rc_strlist_add (&runlevels, runlevel); + free (runlevel); + } STRLIST_FOREACH (runlevels, runlevel, i) { if (action & DOADD) { if (! add (runlevel, service)) @@ -359,11 +359,12 @@ static int do_options (int argc, char **argv) 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); + char *option = rc_get_service_option (service, argv[0]); + if (option) { + printf ("%s", option); + free (option); + ok = true; + } } else if (strcmp (applet, "save_options") == 0) ok = rc_set_service_option (service, argv[0], argv[1]); else @@ -1,32 +1,45 @@ -/* - rc.h - Header file for external applications to get RC information. - Copyright 2007 Gentoo Foundation - Released under the GPLv2 - */ +/*! + * @file rc.h + * @brief Describes how to interface with the RC library + * @internal + * + * Copyright 2007 Gentoo Foundation + * Released under the GPLv2 + */ #ifndef __RC_H__ #define __RC_H__ -#define SENTINEL #ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC__MINOR ) +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC__MINOR) # if (GCC_VERSION >= 3005) -# undef SENTINEL # define SENTINEL __attribute__ ((__sentinel__)) # endif #endif +#ifndef SENTINEL +# define SENTINEL +#endif #include <sys/types.h> #include <stdbool.h> #include <stdio.h> -/* Special level names */ +/*! @name Reserved runlevel names */ #define RC_LEVEL_SYSINIT "sysinit" #define RC_LEVEL_SINGLE "single" #define RC_LEVEL_SHUTDOWN "shutdown" #define RC_LEVEL_REBOOT "reboot" +/*! @name rc_ls_dir options */ +/*! Ensure that an init.d service exists for each file returned */ +#define RC_LS_INITD 0x01 + +/*! @name RC + * A service can be given as a full path or just its name. + * If its just a name then we try to resolve the service to a full path. + * This should allow the use if local init.d directories in the future. */ + +/*! @brief States a service can be in */ typedef enum { rc_service_started, @@ -41,114 +54,272 @@ typedef enum rc_service_crashed } rc_service_state_t; +/*! Resolves a service name to its full path. + * @param service to check + * @return pointer to full path of service */ char *rc_resolve_service (const char *service); +/*! Checks if a service exists or not. + * @param service to check + * @return true if service exists, otherwise false */ bool rc_service_exists (const char *service); + +/*! Lists the extra options a service has + * @param service to load the options from + * @return NULL terminated string list of options */ char **rc_service_options (const char *service); + +/*! Returns a description of what the service and/or option does. + * @param service to check + * @param option to check (if NULL, service description) + * @return a newly allocated pointer to the description */ char *rc_service_description (const char *service, const char *option); + +/*! Checks if a service is in a runlevel + * @param service to check + * @param runlevel it should be in + * @return true if service is in the runlevel, otherwise false */ bool rc_service_in_runlevel (const char *service, const char *runlevel); + +/*! Checks if a service in in a state + * @param service to check + * @param state service should be in + * @return true if service is in the requested state, otherwise false */ bool rc_service_state (const char *service, rc_service_state_t state); + +/*! Marks the service state + * @param service to mark + * @param state service should be in + * @return true if service state change was successful, otherwise false */ bool rc_mark_service (const char *service, rc_service_state_t state); + +/*! Stop a service + * @param service to stop + * @return pid of service stopping process */ pid_t rc_stop_service (const char *service); + +/*! Start a service + * @param service to start + * @return pid of the service starting process */ pid_t rc_start_service (const char *service); + +/*! Wait for a process to finish + * @param pid to wait for + * @return exit status of the process */ int rc_waitpid (pid_t pid); + +/*! Schedule a service to be started when another service starts + * @param service that starts the scheduled service when started + * @param service_to_start service that will be started */ void rc_schedule_start_service (const char *service, const char *service_to_start); +/*! Return a NULL terminated list of services that are scheduled to start + * when the given service has started + * @param service to check + * @return NULL terminated list of services scheduled to start */ char **rc_services_scheduled_by (const char *service); + +/*! Clear the list of services scheduled to be started by this service + * @param service to clear */ void rc_schedule_clear (const char *service); + +/*! Wait for a service to finish + * @param service to wait for + * @return true if service finished before timeout, otherwise false */ bool rc_wait_service (const char *service); -bool rc_get_service_option (const char *service, const char *option, - char *value); + +/*! Return a saved value for a service + * @param service to check + * @param option to load + * @return saved value */ +char *rc_get_service_option (const char *service, const char *option); +/*! Save a persistent value for a service + * @param service to save for + * @param option to save + * @param value of the option + * @return true if saved, otherwise false */ bool rc_set_service_option (const char *service, const char *option, const char *value); +/*! Save the arguments to find a running daemon + * @param service to save arguments for + * @param exec that we started + * @param name of the process (optional) + * @param pidfile of the process (optional) + * @param started if true, add the arguments otherwise remove existing matching arguments */ void rc_set_service_daemon (const char *service, const char *exec, const char *name, const char *pidfile, bool started); +/*! Check if the service started the daemon + * @param service to check + * @param exec to check + * @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc) + * @return true if started by this service, otherwise false */ bool rc_service_started_daemon (const char *service, const char *exec, int indx); +/*! Check if the service is allowed to be hot/cold plugged + * @param service to check + * @return true if allowed, otherwise false */ bool rc_allow_plug (char *service); +/*! Return the current runlevel. + * @return the current runlevel */ char *rc_get_runlevel (void); +/*! Set the runlevel. + * This just changes the stored runlevel and does not start or stop any services. + * @param runlevel to store */ void rc_set_runlevel (const char *runlevel); + +/*! Checks if the runlevel exists or not + * @param runlevel to check + * @return true if the runlevel exists, otherwise false */ bool rc_runlevel_exists (const char *runlevel); + +/*! Return a NULL terminated list of runlevels + * @return a NULL terminated list of runlevels */ char **rc_get_runlevels (void); + +/*! Is the runlevel starting? + * @return true if yes, otherwise false */ bool rc_runlevel_starting (void); +/*! Is the runlevel stopping? + * @return true if yes, otherwise false */ bool rc_runlevel_stopping (void); + +/*! Add the service to the runlevel + * @param runlevel to add to + * @param service to add + * @return true if successful, otherwise false */ bool rc_service_add (const char *runlevel, const char *service); +/*! Remove the service from the runlevel + * @param runlevel to remove from + * @param service to remove + * @return true if sucessful, otherwise false */ bool rc_service_delete (const char *runlevel, const char *service); +/*! List the services in a runlevel + * @param runlevel to list + * @return NULL terminated list of services */ char **rc_services_in_runlevel (const char *runlevel); +/*! List the services in a state + * @param state to list + * @return NULL terminated list of services */ char **rc_services_in_state (rc_service_state_t state); +/*! List the services shceduled to start when this one does + * @param service to check + * @return NULL terminated list of services */ char **rc_services_scheduled (const char *service); -/* Find pids based on criteria - free the pointer returned after use */ +/*! Find processes based on criteria. + * All of these are optional. + * pid overrides anything else. + * If both exec and cmd are given then we ignore exec. + * @param exec to check for + * @param cmd to check for + * @param uid to check for + * @param pid to check for + * @return NULL terminated list of pids */ pid_t *rc_find_pids (const char *exec, const char *cmd, 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. */ +/*! Checks that all daemons started with start-stop-daemon by the service + * are still running. + * @param service to check + * @return true if all daemons started are still running, otherwise false */ bool rc_service_daemons_crashed (const char *service); -/* Dependency tree structs and functions. */ +/*! @name Dependency options + * These options can change the services found by the rc_get_depinfo and + * rc_get_depends functions. */ +/*! Trace provided services */ +#define RC_DEP_TRACE 0x01 +/*! Only use services added to runlevels */ +#define RC_DEP_STRICT 0x02 +/*! Runlevel is starting */ +#define RC_DEP_START 0x04 +/*! Runlevel is stopping */ +#define RC_DEP_STOP 0x08 + +/*! @name Dependencies + * We analyse each init script and cache the resultant dependency tree. + * This tree can be accessed using the below structures and functions. */ +/*! Singly linked list of dependency types that list the services the + * type is for */ typedef struct rc_deptype { + /*! ineed, iuse, iafter, etc */ char *type; + /*! NULL terminated list of services */ char **services; + /*! Next dependency type */ struct rc_deptype *next; } rc_deptype_t; +/*! Singly linked list of services and their dependencies */ typedef struct rc_depinfo { + /*! Name of service */ char *service; + /*! Dependencies */ rc_deptype_t *depends; + /*! Next service dependency type */ struct rc_depinfo *next; } rc_depinfo_t; - -/* Options for rc_dep_depends and rc_order_services. - When changing runlevels, you should use RC_DEP_START and RC_DEP_STOP for - the start and stop lists as we tweak the provided services for this. */ -#define RC_DEP_TRACE 0x01 -#define RC_DEP_STRICT 0x02 -#define RC_DEP_START 0x04 -#define RC_DEP_STOP 0x08 - +/*! Update the cached dependency tree if it's older than any init script, + * its configuration file or an external configuration file the init script + * has specified. + * @param force an update + * @return 0 if successful, otherwise -1 */ int rc_update_deptree (bool force); +/*! Load the cached dependency tree and return a pointer to it. + * This pointer should be freed with rc_free_deptree when done. + * @return pointer to the dependency tree */ rc_depinfo_t *rc_load_deptree (void); +/*! Get a services depedency information from a loaded tree + * @param deptree to search + * @param service to find + * @return service dependency information */ rc_depinfo_t *rc_get_depinfo (rc_depinfo_t *deptree, const char *service); +/*! Get a depenency type from the service dependency information + * @param depinfo service dependency to search + * @param type to find + * @return service dependency type information */ 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); -/* 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. */ +/*! List all the services that should be stoppned and then started, in order, + * for the given runlevel, including sysinit and boot services where + * approriate. + * @param deptree to search + * @param runlevel to change into + * @param options to pass + * @return NULL terminated list of services in order */ char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel, int options); - +/*! Free a deptree and its information + * @param deptree to free */ void rc_free_deptree (rc_depinfo_t *deptree); -/* Plugin handler - For each plugin loaded we will call it's _name_hook with the below - enum and either the runlevel name or service name. For example - int _splash_hook (rc_hook_t hook, const char *name); - Plugins are called when rc does something. This does not indicate an - end result and the plugin should use the above functions to query things - like service status. - The service hooks have extra ones - now and done. This is because after - start_in we may start other services before we start the service in - question. now shows we really will start the service now and done shows - when we have done it as may start scheduled services at this point. */ +/*! @name Plugins + * For each plugin loaded we will call rc_plugin_hook with the below + * enum and either the runlevel name or service name. + * + * Plugins are called when rc does something. This does not indicate an + * end result and the plugin should use the above functions to query things + * like service status. + * + * The service hooks have extra ones - now and done. This is because after + * start_in we may start other services before we start the service in + * question. now shows we really will start the service now and done shows + * when we have done it as may start scheduled services at this point. */ +/*! Points at which a plugin can hook into RC */ typedef enum { rc_hook_runlevel_stop_in = 1, rc_hook_runlevel_stop_out = 4, rc_hook_runlevel_start_in = 5, rc_hook_runlevel_start_out = 8, - /* We reserved a few numbers if we need rc_runlevel_stop_now and done */ - rc_hook_abort = 99, - /* We send the abort if an init script requests we abort and drop + /*! We send the abort if an init script requests we abort and drop * into single user mode if system not fully booted */ + rc_hook_abort = 99, rc_hook_service_stop_in = 101, rc_hook_service_stop_now, rc_hook_service_stop_done, @@ -159,53 +330,146 @@ typedef enum rc_hook_service_start_out } rc_hook_t; -/* Plugins should write FOO=BAR to this fd to set any environment variables - * they wish. At this time we only support the setting of one env var. */ +/*! Plugin entry point + * @param hook point + * @param name of runlevel or service + * @return 0 for success otherwise -1 */ +int rc_plugin_hook (rc_hook_t hook, const char *name); + +/*! Plugins should write FOO=BAR to this fd to set any environment + * variables they wish. Variables should be separated by NULLs. */ extern FILE *rc_environ_fd; -/* RC utility functions. - Although not directly related to RC in general, they are used by RC - itself and the supporting applications. */ +/*! @name Memory Allocation + * Ensure that if we cannot allocate the memory then we exit */ +/*@{*/ +/*! Allocate a block of memory + * @param size of memory to allocate + * @return pointer to memory */ void *rc_xmalloc (size_t size); +/*! Re-size a block of memory + * @param ptr to the block of memory to re-size + * @param size memory should be + * @return pointer to memory block */ void *rc_xrealloc (void *ptr, size_t size); +/*! Duplicate a NULL terminated string + * @param str to duplicate + * @return pointer to the new string */ char *rc_xstrdup (const char *str); +/*@}*/ -/* Concat paths adding '/' if needed. */ +/*! @name Utility + * Although not RC specific functions, they are used by the supporting + * applications */ +/*! Concatenate paths adding '/' if needed. The resultant pointer should be + * freed when finished with. + * @param path1 starting path + * @param paths NULL terminated list of paths to add + * @return pointer to the new path */ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL; - +/*! Check if an environment variable matches the given value + * @param variable to check + * @param value it should be + * @return true if it matches */ bool rc_is_env (const char *variable, const char *value); +/*! Check if the file exists or not + * @param pathname to check + * @return true if it exists, otherwise false */ bool rc_exists (const char *pathname); +/*! Check if the file is a real file + * @param pathname to check + * @return true if it's a real file, otherwise false */ bool rc_is_file (const char *pathname); +/*! Check if the file is a symbolic link or not + * @param pathname to check + * @return true if it's a symbolic link, otherwise false */ bool rc_is_link (const char *pathname); +/*! Check if the file is a directory or not + * @param pathname to check + * @return true if it's a directory, otherwise false */ bool rc_is_dir (const char *pathname); +/*! Check if the file is marked executable or not + * @param pathname to check + * @return true if it's marked executable, otherwise false */ bool rc_is_exec (const char *pathname); -#define RC_LS_INITD 0x01 +/*! Return a NULL terminted sorted list of the contents of the directory + * @param dir to list + * @param options any options to apply + * @return NULL terminated list */ char **rc_ls_dir (const char *dir, int options); +/*! Remove a directory + * @param pathname to remove + * @param top remove the top level directory too + * @return true if successful, otherwise false */ bool rc_rm_dir (const char *pathname, bool top); -/* Config file functions */ +/*! @name Configuration */ +/*! Return a NULL terminated list of non comment lines from a file. */ char **rc_get_list (const char *file); +/*! Return a NULL terminated list of key=value lines from a file. */ char **rc_get_config (const char *file); +/*! Return the value of the entry from a key=value list. */ char *rc_get_config_entry (char **list, const char *entry); -/* Make an environment list which filters out all unwanted values - and loads it up with our RC config */ +/*! Return a NULL terminated string list of variables allowed through + * from the current environemnt. */ char **rc_filter_env (void); +/*! Return a NULL terminated string list of enviroment variables made from + * our configuration files. */ char **rc_make_env (void); -/* Handy functions for dealing with string arrays of char ** */ +/*! @name String List functions + * Handy functions for dealing with string arrays of char **. + * It's safe to assume that any function here that uses char ** is a string + * list that can be manipulated with the below functions. Every string list + * should be released with a call to rc_strlist_free.*/ +/*! Duplicate the item, add it to end of the list and return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ char *rc_strlist_add (char ***list, const char *item); +/*! If the item does not exist in the list, duplicate it, add it to the + * list and then return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ char *rc_strlist_addu (char ***list, const char *item); +/*! Duplicate the item, add it to the list at the point based on locale and + * then return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ char *rc_strlist_addsort (char ***list, const char *item); +/*! Duplicate the item, add it to the list at the point based on C locale and + * then return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ char *rc_strlist_addsortc (char ***list, const char *item); +/*! If the item does not exist in the list, duplicate it, add it to the + * list based on locale and then return a pointer to it. + * @param list to add the item too + * @param item to add. + * @return pointer to newly added item */ char *rc_strlist_addsortu (char ***list, const char *item); +/*! Free the item and remove it from the list. Return 0 on success otherwise -1. + * @param list to add the item too + * @param item to add. + * @return 0 on success, otherwise -1 */ int rc_strlist_delete (char ***list, const char *item); -/* join moves items from list2 to list1, so list2 is empty - * on return. It still needs to be freed though. */ -int rc_strlist_join (char ***list1, char **list2); +/*! Moves the contents of list2 onto list1, so list2 is effectively emptied. + * Returns a pointer to the last item on the new list. + * @param list1 to append to + * @param list2 to move from + * @return pointer to the last item on the list */ +char *rc_strlist_join (char ***list1, char **list2); +/*! Reverses the contents of the list. + * @param list to reverse */ void rc_strlist_reverse (char **list); +/*! Frees each item on the list and the list itself. + * @param list to free */ void rc_strlist_free (char **list); #endif diff --git a/src/runscript.c b/src/runscript.c index 200d8d88..550653ab 100644 --- a/src/runscript.c +++ b/src/runscript.c @@ -307,6 +307,7 @@ static void cleanup (void) free (applet); free (prefix); free (service); + free (softlevel); } static int write_prefix (const char *buffer, size_t bytes, bool *prefixed) { @@ -1029,7 +1030,7 @@ int runscript (int argc, char **argv) } #endif - if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) { + if ((softlevel = rc_xstrdup (getenv ("RC_SOFTLEVEL"))) == NULL) { /* Ensure our environment is pure Also, add our configuration to it */ tmplist = rc_make_env(); |