Remove null terminated char ** lists in favour of RC_STRINGLIST, using TAILQ from queue(3). Refactor code style around the BSD KNF.

This commit is contained in:
Roy Marples 2008-03-16 17:00:56 +00:00
parent 40e12f6ba0
commit cb9da6a262
41 changed files with 4675 additions and 5322 deletions

View File

@ -1,6 +1,6 @@
MAN3= einfo.3 \ MAN3= einfo.3 \
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \ rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
rc_runlevel.3 rc_service.3 rc_strcatpaths.3 rc_strlist.3 rc_runlevel.3 rc_service.3 rc_strcatpaths.3 rc_stringlist.3
MAN8= rc-status.8 rc-update.8 rc.8 runscript.8 start-stop-daemon.8 MAN8= rc-status.8 rc-update.8 rc.8 runscript.8 start-stop-daemon.8
# Handy macro to create symlinks # Handy macro to create symlinks

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Feb 22, 2008 .Dd Mar 16, 2008
.Dt EINFO 3 SMM .Dt EINFO 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -62,7 +62,7 @@ Enhanced Informatation output library (libeinfo, -leinfo)
.Ft int Fn ewend "int retval" "const char * restrict format" ... .Ft int Fn ewend "int retval" "const char * restrict format" ...
.Ft int Fn eendv "int retval" "const char * restrict format" ... .Ft int Fn eendv "int retval" "const char * restrict format" ...
.Ft int Fn ewendv "int retval" "const char * restrict format" ... .Ft int Fn ewendv "int retval" "const char * restrict format" ...
.Ft void Fn ebracket "int col" "einfo_color_t color" "const char * restrict msg" .Ft void Fn ebracket "int col" "ECOLOR color" "const char * restrict msg"
.Ft void Fn eindent void .Ft void Fn eindent void
.Ft void Fn eoutdent void .Ft void Fn eoutdent void
.Ft void Fn eindentv void .Ft void Fn eindentv void

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Jan 08, 2008 .Dd Mar 16, 2008
.Dt RC_CONFIG 3 SMM .Dt RC_CONFIG 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -33,8 +33,8 @@ Run Command library (librc, -lrc)
.Sh SYNOPSIS .Sh SYNOPSIS
.In rc.h .In rc.h
.Ft "char *" Fn rc_getline "FILE *fp" .Ft "char *" Fn rc_getline "FILE *fp"
.Ft "char **" Fn rc_config_list "const char *file" .Ft "RC_STRINGLIST *" Fn rc_config_list "const char *file"
.Ft "char **" Fn rc_config_load "const char *file" .Ft "RC_STRINGLIST *" Fn rc_config_load "const char *file"
.Ft "char *" Fn rc_config_value "const char *const *list" "const char *entry" .Ft "char *" Fn rc_config_value "const char *const *list" "const char *entry"
.Ft bool Fn rc_yesno "const char *value" .Ft bool Fn rc_yesno "const char *value"
.Sh DESCRIPTION .Sh DESCRIPTION
@ -61,7 +61,7 @@ found in
.Fa list . .Fa list .
.Pp .Pp
Each list should be freed using Each list should be freed using
.Fn rc_strlist_free .Fn rc_stringlist_free
when done. when done.
.Pp .Pp
.Fn rc_yesno .Fn rc_yesno
@ -76,7 +76,7 @@ is set to
.Va EINVAL . .Va EINVAL .
.Sh SEE ALSO .Sh SEE ALSO
.Xr malloc 3 , .Xr malloc 3 ,
.Xr rc_strlist_free 3 , .Xr rc_stringlist_free 3 ,
.Xr sh 1 .Xr sh 1
.Sh AUTHORS .Sh AUTHORS
.An "Roy Marples" Aq roy@marples.name .An "Roy Marples" Aq roy@marples.name

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Feb 22, 2008 .Dd Mar 16, 2008
.Dt RC_DEPTREE 3 SMM .Dt RC_DEPTREE 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -36,25 +36,25 @@ Run Command library (librc, -lrc)
.In rc.h .In rc.h
.Ft bool Fn rc_deptree_update void .Ft bool Fn rc_deptree_update void
.Ft bool Fn rc_deptree_update_needed void .Ft bool Fn rc_deptree_update_needed void
.Ft rc_depinfo_t Fn rc_deptree_load void .Ft RC_DEPTREE Fn rc_deptree_load void
.Ft "char **" Fo rc_deptree_depend .Ft "RC_STRINGLIST *" Fo rc_deptree_depend
.Fa "const rc_depinfo_t *deptree" .Fa "const RC_DEPTREE *deptree"
.Fa "const char *type" .Fa "const char *type"
.Fa "const char *service" .Fa "const char *service"
.Fc .Fc
.Ft bool Fo rc_deptree_depends .Ft bool Fo rc_deptree_depends
.Fa "const rc_depinfo_t *deptree" .Fa "const RC_DEPTREE *deptree"
.Fa "const char *const *types" .Fa "const char *const *types"
.Fa "const char *const *services" .Fa "const char *const *services"
.Fa "const char *runlevel" .Fa "const char *runlevel"
.Fa "int options" .Fa "int options"
.Fc .Fc
.Ft "char **" Fo rc_deptree_order .Ft "RC_STRINGLIST *" Fo rc_deptree_order
.Fa "const rc_depinfo_t *deptree" .Fa "const RC_DEPTREE *deptree"
.Fa "const char *runlevel" .Fa "const char *runlevel"
.Fa "int options" .Fa "int options"
.Fc .Fc
.Ft void Fn rc_deptree_free "rc_depinfo_t *deptree" .Ft void Fn rc_deptree_free "RC_DEPTREE *deptree"
.Sh DESCRIPTION .Sh DESCRIPTION
These functions provide a means of querying the dependencies of OpenRC These functions provide a means of querying the dependencies of OpenRC
services. services.
@ -100,15 +100,14 @@ only lists services actually needed or in the
.Va runlevel . .Va runlevel .
.Sh IMPLEMENTATION NOTES .Sh IMPLEMENTATION NOTES
Each function that returns Each function that returns
.Fr "char **" .Fr "RC_STRINGLIST *"
returns a malloced NULL terminated array of malloced NULL terminated strings, should be freed by calling
all of which need to be freed using .Fn rc_stringlist_free
.Fn rc_strlist_free
when done. when done.
.Sh SEE ALSO .Sh SEE ALSO
.Xr malloc 3 , .Xr malloc 3 ,
.Xr free 3 , .Xr free 3 ,
.Xr rc_strlist_free 3 , .Xr rc_stringlist_free 3 ,
.Xr runscript 8 .Xr runscript 8
.Sh AUTHORS .Sh AUTHORS
.An "Roy Marples" Aq roy@marples.name .An "Roy Marples" Aq roy@marples.name

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Feb 22, 2008 .Dd Mar 16, 2008
.Dt RC_PLUGIN_HOOK 3 SMM .Dt RC_PLUGIN_HOOK 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -32,7 +32,7 @@
Run Command library (librc, -lrc) Run Command library (librc, -lrc)
.Sh SYNOPSIS .Sh SYNOPSIS
.In rc.h .In rc.h
.Ft int Fn rc_plugin_hook "rc_hook_t hook" "const char *name" .Ft int Fn rc_plugin_hook "RC_HOOK hook" "const char *name"
.Sh DESCRIPTION .Sh DESCRIPTION
.Fn rc_plugin_hook .Fn rc_plugin_hook
is called for each shareable object found in is called for each shareable object found in

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Feb 22, 2008 .Dd Mar 16, 2008
.Dt RC_RUNLEVEL 3 SMM .Dt RC_RUNLEVEL 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -35,7 +35,7 @@ Run Command library (librc, -lrc)
.In rc.h .In rc.h
.Ft "char *" Fn rc_runlevel_get void .Ft "char *" Fn rc_runlevel_get void
.Ft bool Fn rc_runlevel_exists .Ft bool Fn rc_runlevel_exists
.Ft "char **" Fn rc_runlevel_list void .Ft "RC_STRINGLIST *" Fn rc_runlevel_list void
.Ft bool Fn rc_runlevel_set "const char *runlevel" .Ft bool Fn rc_runlevel_set "const char *runlevel"
.Ft bool Fn rc_runlevel_starting void .Ft bool Fn rc_runlevel_starting void
.Ft bool Fn rc_runlevel_stopping void .Ft bool Fn rc_runlevel_stopping void
@ -48,10 +48,9 @@ Each function that returns
returns a malloced NULL terminated string that should be freed when done. returns a malloced NULL terminated string that should be freed when done.
.Pp .Pp
Each function that returns Each function that returns
.Fr "char **" .Fr "RC_STRINGLIST *"
returns a malloced NULL terminated array of malloced NULL terminated strings, should by freed by calling
all of which need to be freed using .Fn rc_stringlist_free
.Fn rc_strlist_free
when done. when done.
.Sh FILES .Sh FILES
.Pa /etc/init.d/functions.sh .Pa /etc/init.d/functions.sh
@ -62,6 +61,6 @@ Rinse and repeat for the other verbose functions.
.Sh SEE ALSO .Sh SEE ALSO
.Xr malloc 3 , .Xr malloc 3 ,
.Xr free 3 .Xr free 3
.Xr rc_strlist_free 3 .Xr rc_stringlist_free 3
.Sh AUTHORS .Sh AUTHORS
.An "Roy Marples" Aq roy@marples.name .An "Roy Marples" Aq roy@marples.name

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd Feb 22, 2008 .Dd Mar 16, 2008
.Dt RC_SERVICE 3 SMM .Dt RC_SERVICE 3 SMM
.Os OpenRC .Os OpenRC
.Sh NAME .Sh NAME
@ -55,17 +55,17 @@ Run Command library (librc, -lrc)
.Fc .Fc
.Ft bool Fn rc_service_exists "const char *service" .Ft bool Fn rc_service_exists "const char *service"
.Ft bool Fn rc_service_in_runlevel "const char *service" "const char *runlevel" .Ft bool Fn rc_service_in_runlevel "const char *service" "const char *runlevel"
.Ft bool Fn rc_service_mark "const char *service" "rc_service_state_t state" .Ft bool Fn rc_service_mark "const char *service" "RC_SERVICE state"
.Ft "char **" Fn rc_service_extra_commands "const char *service" .Ft "RC_STRINGLIST *" Fn rc_service_extra_commands "const char *service"
.Ft bool Fn rc_service_plugable "const char *service" .Ft bool Fn rc_service_plugable "const char *service"
.Ft "char *" rc_service_resolve "const char *service" .Ft "char *" rc_service_resolve "const char *service"
.Ft bool Fo rc_service_schedule_start .Ft bool Fo rc_service_schedule_start
.Fa "const char *service" .Fa "const char *service"
.Fa "const char *service_to_start" .Fa "const char *service_to_start"
.Fc .Fc
.Ft "char **" Fn rc_services_scheduled_by "const char *service" .Ft "RC_STRINGLIST *" Fn rc_services_scheduled_by "const char *service"
.Ft bool Fn rc_service_schedule_clear "const char *service" .Ft bool Fn rc_service_schedule_clear "const char *service"
.Ft rc_service_state_t Fn rc_service_state "const char *service" .Ft RC_SERVICE Fn rc_service_state "const char *service"
.Ft pid_t Fn rc_service_start "const char *service" .Ft pid_t Fn rc_service_start "const char *service"
.Ft pid_t Fn rc_service_stop "const char *service" .Ft pid_t Fn rc_service_stop "const char *service"
.Ft bool Fo rc_service_started_daemon .Ft bool Fo rc_service_started_daemon
@ -79,9 +79,9 @@ Run Command library (librc, -lrc)
.Fa "const char *option" .Fa "const char *option"
.Fa "const char *value" .Fa "const char *value"
.Fc .Fc
.Ft "char **" Fn rc_services_in_runlevel "const char *runlevel" .Ft "RC_STRINGLIST *" Fn rc_services_in_runlevel "const char *runlevel"
.Ft "char **" Fn rc_services_in_state "rc_service_state_t state" .Ft "RC_STRINGLIST *" Fn rc_services_in_state "RC_SERVICE state"
.Ft "char **" Fn rc_services_scheduled "const char *service" .Ft "RC_STRINGLIST *" Fn rc_services_scheduled "const char *service"
.Ft bool Fn rc_service_daemons_crashed "const char *service" .Ft bool Fn rc_service_daemons_crashed "const char *service"
.Sh DESCRIPTION .Sh DESCRIPTION
These functions provide a means of querying OpenRC services to find out the These functions provide a means of querying OpenRC services to find out the
@ -222,10 +222,9 @@ Each function that returns
returns a malloced NULL terminated string that should be freed when done. returns a malloced NULL terminated string that should be freed when done.
.Pp .Pp
Each function that returns Each function that returns
.Fr "char **" .Fr "RC_STRINGLIST *"
returns a malloced NULL terminated array of malloced NULL terminated strings, should be freed using
all of which need to be freed using .Fn rc_stringlist_free
.Fn rc_strlist_free
when done. when done.
.Pp .Pp
When a function fails it should either return false or NULL and set When a function fails it should either return false or NULL and set
@ -238,7 +237,7 @@ normally holds the volatile state data for services on a RAM backed disk.
.Xr errno 3 , .Xr errno 3 ,
.Xr malloc 3 , .Xr malloc 3 ,
.Xr free 3 .Xr free 3
.Xr rc_strlist_free 3 , .Xr rc_stringlist_free 3 ,
.Xr start-stop-daemon 8 .Xr start-stop-daemon 8
.Sh AUTHORS .Sh AUTHORS
.An "Roy Marples" Aq roy@marples.name .An "Roy Marples" Aq roy@marples.name

View File

@ -1,104 +0,0 @@
.\" Copyright 2007-2008 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd Feb 22, 2008
.Dt RC_STRLIST 3 SMM
.Os OpenRC
.Sh NAME
.Nm rc_strlist_add , rc_strlist_addu , rc_strlist_addsort ,
.Nm rc_strlist_addsortc , rc_strlist_addsortu , rc_strlist_delete ,
.Nm rc_strlist_join , rc_strlist_reverse , rc_strlist_free
.Nd RC string list functions
.Sh LIBRARY
Run Command library (librc, -lrc)
.Sh SYNOPSIS
.In rc.h
.Ft "char *" Fn rc_strlist_add "char ***list" "const char *item"
.Ft "char *" Fn rc_strlist_addu "char ***list" "const char *item"
.Ft "char *" Fn rc_strlist_addsort "char ***list" "const char *item"
.Ft "char *" Fn rc_strlist_addsortc "char ***list" "const char *item"
.Ft "char *" Fn rc_strlist_addsortu "char ***list" "const char *item"
.Ft bool Fn rc_strlist_delete "char ***list" "const char *item"
.Ft "char *" Fn rc_strlist_join "char ***list1" "const char **list2"
.Ft void Fn rc_strlist_reverse "char **list"
.Ft void Fn rc_strlist_free "char **list"
.Sh DESCRIPTION
These functions provide an easy means of manipulating string lists without
the need for custom structures or non standard macros.
.Pp
.Fn rc_strlist_add
adds a malloced copy of
.Fa item
to
.Fa list ,
realloced to accomodate the new item. It returns a pointer to the new item on
success, or NULL on failure and sets
.Va errno
accordingly.
.Fn rc_strlist_addu
and
.Fn rc_strlist_addsortu
only work if
.Fa list
does not already contain
.Fa item .
.Fn rc_strlist_addsort
adds the item to the list in a lexically sorted position, using
.Nm strcoll ,
whereas
.Fn rc_strlist_addsortc
uses
.Nm strcmp .
.Pp
.Fn rc_strlist_delete
removes and frees
.Fa item
from
.Fa list ,
retuning true on success, otherwise false.
.Pp
.Fn rc_strlist_join
appends
.Fa list2
to the end of
.Fa list1
and returns a pointer to the last item on the new list.
.Pp
.Fn rc_strlist_reverse
reverses the items on
.Fa list .
.Pp
.Fn rc_strlist_free
frees each item on
.Fa list
and the
.Fa list
itself.
.Sh SEE ALSO
.Xr malloc 3 ,
.Xr free 3 ,
.Xr strcmp 3 ,
.Xr strcoll 3
.Sh AUTHORS
.An "Roy Marples" Aq roy@marples.name

View File

@ -56,7 +56,7 @@
#define RC_LIBDIR RC_PREFIX "/" LIB "/rc" #define RC_LIBDIR RC_PREFIX "/" LIB "/rc"
#define RC_SVCDIR RC_LIBDIR "/init.d" #define RC_SVCDIR RC_LIBDIR "/init.d"
#define RC_DEPTREE RC_SVCDIR "/deptree" #define RC_DEPTREE_CACHE RC_SVCDIR "/deptree"
#define RC_RUNLEVELDIR RC_PREFIX SYSCONFDIR "/runlevels" #define RC_RUNLEVELDIR RC_PREFIX SYSCONFDIR "/runlevels"
#define RC_INITDIR RC_PREFIX SYSCONFDIR "/init.d" #define RC_INITDIR RC_PREFIX SYSCONFDIR "/init.d"
#define RC_CONFDIR RC_PREFIX SYSCONFDIR "/conf.d" #define RC_CONFDIR RC_PREFIX SYSCONFDIR "/conf.d"
@ -98,9 +98,46 @@
# define _unused # define _unused
#endif #endif
/* Some libc implemntations don't have these */
#ifndef STAILQ_CONCAT
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#endif
#ifndef TAILQ_CONCAT
#define TAILQ_CONCAT(head1, head2) do { \
if (!TAILQ_EMPTY((head2))) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
#endif
#ifndef STAILQ_FOREACH_SAFE
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
#ifndef TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
_unused static void *xmalloc (size_t size) _unused static void *xmalloc (size_t size)
{ {
void *value = malloc (size); void *value = malloc(size);
if (value) if (value)
return (value); return (value);
@ -109,9 +146,9 @@ _unused static void *xmalloc (size_t size)
/* NOTREACHED */ /* NOTREACHED */
} }
_unused static void *xrealloc (void *ptr, size_t size) _unused static void *xrealloc(void *ptr, size_t size)
{ {
void *value = realloc (ptr, size); void *value = realloc(ptr, size);
if (value) if (value)
return (value); return (value);
@ -120,14 +157,14 @@ _unused static void *xrealloc (void *ptr, size_t size)
/* NOTREACHED */ /* NOTREACHED */
} }
_unused static char *xstrdup (const char *str) _unused static char *xstrdup(const char *str)
{ {
char *value; char *value;
if (! str) if (! str)
return (NULL); return (NULL);
value = strdup (str); value = strdup(str);
if (value) if (value)
return (value); return (value);
@ -138,32 +175,32 @@ _unused static char *xstrdup (const char *str)
#undef ERRX #undef ERRX
_unused static bool exists (const char *pathname) _unused static bool exists(const char *pathname)
{ {
struct stat buf; struct stat buf;
return (stat (pathname, &buf) == 0); return (stat(pathname, &buf) == 0);
} }
_unused static bool existss (const char *pathname) _unused static bool existss(const char *pathname)
{ {
struct stat buf; struct stat buf;
return (stat (pathname, &buf) == 0 && buf.st_size != 0); return (stat(pathname, &buf) == 0 && buf.st_size != 0);
} }
char *rc_conf_value (const char *var); char *rc_conf_value(const char *var);
bool rc_conf_yesno (const char *var); bool rc_conf_yesno(const char *var);
char **env_filter (void); void env_filter(void);
char **env_config (void); void env_config(void);
bool service_plugable (const char *service); bool service_plugable(const char *service);
int signal_setup (int sig, void (*handler)(int)); int signal_setup(int sig, void (*handler)(int));
/* basename_c never modifies the argument. As such, if there is a trailing /* basename_c never modifies the argument. As such, if there is a trailing
* slash then an empty string is returned. */ * slash then an empty string is returned. */
_unused static const char *basename_c (const char *path) _unused static const char *basename_c(const char *path)
{ {
const char *slash = strrchr (path, '/'); const char *slash = strrchr(path, '/');
if (slash) if (slash)
return (++slash); return (++slash);

View File

@ -1,48 +0,0 @@
/*
strlist.h
String list macros for making char ** arrays
Based on a previous implementation by Martin Schlemmer
*/
/*
* Copyright 2007-2008 Roy Marples
* All rights reserved
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __STRLIST_H__
#define __STRLIST_H__
/* FIXME: We should replace the macro with an rc_strlist_foreach
function, but I'm unsure how to go about this. */
/* Step through each entry in the string list, setting '_pos' to the
beginning of the entry. '_counter' is used by the macro as index,
but should not be used by code as index (or if really needed, then
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++]))
#endif /* __STRLIST_H__ */

View File

@ -54,19 +54,19 @@
/*! @brief Color types to use */ /*! @brief Color types to use */
typedef enum typedef enum
{ {
ECOLOR_NORMAL = 1, ECOLOR_NORMAL = 1,
ECOLOR_GOOD = 2, ECOLOR_GOOD = 2,
ECOLOR_WARN = 3, ECOLOR_WARN = 3,
ECOLOR_BAD = 4, ECOLOR_BAD = 4,
ECOLOR_HILITE = 5, ECOLOR_HILITE = 5,
ECOLOR_BRACKET = 6 ECOLOR_BRACKET = 6
} einfo_color_t; } ECOLOR;
/*! @brief Returns the ASCII code for the color */ /*! @brief Returns the ASCII code for the color */
const char *ecolor (einfo_color_t); const char *ecolor(ECOLOR);
/*! @brief Writes to syslog. */ /*! @brief Writes to syslog. */
void elog (int __level, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; void elog(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
/*! /*!
* @brief Display informational messages. * @brief Display informational messages.
@ -84,22 +84,22 @@ void elog (int __level, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
* The v suffix means only print if EINFO_VERBOSE is yes. * The v suffix means only print if EINFO_VERBOSE is yes.
*/ */
/*@{*/ /*@{*/
int einfon (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int einfon(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ewarnn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ewarnn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int eerrorn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int eerrorn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int einfo (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int einfo(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ewarn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ewarn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
void ewarnx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF; void ewarnx(const char * __EINFO_RESTRICT, ...) __EINFO_XPRINTF;
int eerror (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int eerror(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
void eerrorx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF; void eerrorx(const char * __EINFO_RESTRICT, ...) __EINFO_XPRINTF;
int einfovn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int einfovn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ewarnvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ewarnvn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ebeginvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ebeginvn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int eendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int eendvn(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
int ewendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int ewendvn(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
int einfov (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int einfov(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ewarnv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ewarnv(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
/*@}*/ /*@}*/
/*! @ingroup ebegin /*! @ingroup ebegin
@ -107,8 +107,8 @@ int ewarnv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
* *
* Similar to einfo, but we add ... to the end of the message */ * Similar to einfo, but we add ... to the end of the message */
/*@{*/ /*@{*/
int ebeginv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ebeginv(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
int ebegin (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; int ebegin(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
/*@}*/ /*@}*/
/*! @ingroup eend /*! @ingroup eend
@ -120,12 +120,12 @@ int ebegin (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
* *
* ebracket allows you to specifiy the position, color and message */ * ebracket allows you to specifiy the position, color and message */
/*@{*/ /*@{*/
int eend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int eend(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
int ewend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int ewend(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
void ebracket (int __col, einfo_color_t __color, const char * __EINFO_RESTRICT __msg); void ebracket(int, ECOLOR, const char * __EINFO_RESTRICT);
int eendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int eendv(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
int ewendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; int ewendv(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
/*@}*/ /*@}*/
/*! @ingroup eindent /*! @ingroup eindent
@ -133,12 +133,12 @@ int ewendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINT
* *
* For each indent you should outdent when done */ * For each indent you should outdent when done */
/*@{*/ /*@{*/
void eindent (void); void eindent(void);
void eoutdent (void); void eoutdent(void);
void eindentv (void); void eindentv(void);
void eoutdentv (void); void eoutdentv(void);
/*! @brief Prefix each einfo line with something */ /*! @brief Prefix each einfo line with something */
void eprefix (const char * __EINFO_RESTRICT __prefix); void eprefix(const char * __EINFO_RESTRICT);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,12 @@ librc.o
librc-daemon.o librc-daemon.o
librc-depend.o librc-depend.o
librc-misc.o librc-misc.o
librc-strlist.o librc-stringlist.o
librc.So librc.So
librc-daemon.So librc-daemon.So
librc-depend.So librc-depend.So
librc-misc.So librc-misc.So
librc-strlist.So librc-stringlist.So
librc.a librc.a
librc.so.1 librc.so.1
librc.so librc.so

View File

@ -4,7 +4,7 @@ include ${MK}/os.mk
LIB= rc LIB= rc
SHLIB_MAJOR= 1 SHLIB_MAJOR= 1
SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \ SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \
librc-strlist.c librc-stringlist.c
INCS= rc.h INCS= rc.h
VERSION_MAP= rc.map VERSION_MAP= rc.map

View File

@ -32,33 +32,33 @@
#include "librc.h" #include "librc.h"
#if defined(__linux__) #if defined(__linux__)
static bool pid_is_cmd (pid_t pid, const char *cmd) static bool pid_is_cmd(pid_t pid, const char *cmd)
{ {
char buffer[32]; char buffer[32];
FILE *fp; FILE *fp;
int c; int c;
snprintf(buffer, sizeof (buffer), "/proc/%d/stat", pid); snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
if ((fp = fopen (buffer, "r")) == NULL) if ((fp = fopen(buffer, "r")) == NULL)
return (false); return false;
while ((c = getc (fp)) != EOF && c != '(') while ((c = getc(fp)) != EOF && c != '(')
; ;
if (c != '(') { if (c != '(') {
fclose(fp); fclose(fp);
return (false); return false;
} }
while ((c = getc (fp)) != EOF && c == *cmd) while ((c = getc(fp)) != EOF && c == *cmd)
cmd++; cmd++;
fclose (fp); fclose(fp);
return ((c == ')' && *cmd == '\0') ? true : false); return (c == ')' && *cmd == '\0') ? true : false;
} }
static bool pid_is_exec (pid_t pid, const char *const *argv) static bool pid_is_exec(pid_t pid, const char *const *argv)
{ {
char cmdline[32]; char cmdline[32];
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@ -66,31 +66,30 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
int fd = -1; int fd = -1;
int r; int r;
/* Check it's the right binary */
snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
memset (buffer, 0, sizeof (buffer)); memset (buffer, 0, sizeof (buffer));
#if 0 if (readlink(cmdline, buffer, sizeof(buffer)) != -1) {
if (readlink (cmdline, buffer, sizeof (buffer)) != -1) { if (strcmp(*argv, buffer) == 0)
if (strcmp (exec, buffer) == 0) return true;
return (true);
/* We should cater for deleted binaries too */ /* We should cater for deleted binaries too */
if (strlen (buffer) > 10) { if (strlen(buffer) > 10) {
p = buffer + (strlen (buffer) - 10); p = buffer + (strlen(buffer) - 10);
if (strcmp (p, " (deleted)") == 0) { if (strcmp(p, " (deleted)") == 0) {
*p = 0; *p = 0;
if (strcmp (buffer, exec) == 0) if (strcmp(buffer, *argv) == 0)
return (true); return true;
} }
} }
} }
#endif
snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid); snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
if ((fd = open (cmdline, O_RDONLY)) < 0) if ((fd = open(cmdline, O_RDONLY)) < 0)
return (false); return false;
r = read (fd, buffer, sizeof (buffer)); r = read(fd, buffer, sizeof(buffer));
close (fd); close(fd);
if (r == -1) if (r == -1)
return 0; return 0;
@ -98,18 +97,18 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
buffer[r] = 0; buffer[r] = 0;
p = buffer; p = buffer;
while (*argv) { while (*argv) {
if (strcmp (*argv, p) != 0) if (strcmp(*argv, p) != 0)
return (false); return false;
argv++; argv++;
p += strlen (p) + 1; p += strlen(p) + 1;
if ((unsigned) (p - buffer) > sizeof (buffer)) if ((unsigned) (p - buffer) > sizeof (buffer))
return (false); return false;
} }
return (true); return true;
} }
pid_t *rc_find_pids (const char *const *argv, const char *cmd, pid_t *rc_find_pids(const char *const *argv, const char *cmd,
uid_t uid, pid_t pid) uid_t uid, pid_t pid)
{ {
DIR *procdir; DIR *procdir;
struct dirent *entry; struct dirent *entry;
@ -122,8 +121,8 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
pid_t runscript_pid = 0; pid_t runscript_pid = 0;
char *pp; char *pp;
if ((procdir = opendir ("/proc")) == NULL) if ((procdir = opendir("/proc")) == NULL)
return (NULL); return NULL;
/* /*
We never match RC_RUNSCRIPT_PID if present so we avoid the below We never match RC_RUNSCRIPT_PID if present so we avoid the below
@ -136,13 +135,13 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
nasty nasty
*/ */
if ((pp = getenv ("RC_RUNSCRIPT_PID"))) { if ((pp = getenv("RC_RUNSCRIPT_PID"))) {
if (sscanf (pp, "%d", &runscript_pid) != 1) if (sscanf(pp, "%d", &runscript_pid) != 1)
runscript_pid = 0; runscript_pid = 0;
} }
while ((entry = readdir (procdir)) != NULL) { while ((entry = readdir(procdir)) != NULL) {
if (sscanf (entry->d_name, "%d", &p) != 1) if (sscanf(entry->d_name, "%d", &p) != 1)
continue; continue;
if (runscript_pid != 0 && runscript_pid == p) if (runscript_pid != 0 && runscript_pid == p)
@ -152,23 +151,23 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
continue; continue;
if (uid) { if (uid) {
snprintf (buffer, sizeof (buffer), "/proc/%d", p); snprintf(buffer, sizeof(buffer), "/proc/%d", p);
if (stat (buffer, &sb) != 0 || sb.st_uid != uid) if (stat(buffer, &sb) != 0 || sb.st_uid != uid)
continue; continue;
} }
if (cmd && ! pid_is_cmd (p, cmd)) if (cmd && ! pid_is_cmd(p, cmd))
continue; continue;
if (argv && ! cmd && ! pid_is_exec (p, (const char *const *)argv)) if (argv && ! cmd && ! pid_is_exec(p, (const char *const *)argv))
continue; continue;
tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); tmp = realloc(pids, sizeof (pid_t) * (npids + 2));
if (! tmp) { if (! tmp) {
free (pids); free(pids);
closedir (procdir); closedir(procdir);
errno = ENOMEM; errno = ENOMEM;
return (NULL); return NULL;
} }
pids = tmp; pids = tmp;
@ -176,9 +175,9 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
pids[npids + 1] = 0; pids[npids + 1] = 0;
npids++; npids++;
} }
closedir (procdir); closedir(procdir);
return (pids); return pids;
} }
librc_hidden_def(rc_find_pids) librc_hidden_def(rc_find_pids)
@ -206,8 +205,8 @@ librc_hidden_def(rc_find_pids)
# define _KVM_FLAGS O_RDONLY # define _KVM_FLAGS O_RDONLY
# endif # endif
pid_t *rc_find_pids (const char *const *argv, const char *cmd, pid_t *rc_find_pids(const char *const *argv, const char *cmd,
uid_t uid, pid_t pid) uid_t uid, pid_t pid)
{ {
static kvm_t *kd = NULL; static kvm_t *kd = NULL;
char errbuf[_POSIX2_LINE_MAX]; char errbuf[_POSIX2_LINE_MAX];
@ -218,44 +217,45 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
char **pargv; char **pargv;
pid_t *pids = NULL; pid_t *pids = NULL;
pid_t *tmp; pid_t *tmp;
pid_t p;
const char *const *arg; const char *const *arg;
int npids = 0; int npids = 0;
int match; int match;
if ((kd = kvm_openfiles (_KVM_PATH, _KVM_PATH, if ((kd = kvm_openfiles(_KVM_PATH, _KVM_PATH,
NULL, _KVM_FLAGS, errbuf)) == NULL) NULL, _KVM_FLAGS, errbuf)) == NULL)
{ {
fprintf (stderr, "kvm_open: %s\n", errbuf); fprintf(stderr, "kvm_open: %s\n", errbuf);
return (NULL); return NULL;
} }
#ifdef _KVM_GETPROC2 #ifdef _KVM_GETPROC2
kp = kvm_getproc2 (kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes); kp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(*kp), &processes);
#else #else
kp = kvm_getprocs (kd, KERN_PROC_PROC, 0, &processes); kp = kvm_getprocs(kd, KERN_PROC_PROC, 0, &processes);
#endif #endif
if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) { if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) {
fprintf (stderr, "kvm_getprocs: %s\n", kvm_geterr (kd)); fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd));
kvm_close (kd); kvm_close(kd);
return (NULL); return NULL;
} }
for (i = 0; i < processes; i++) { for (i = 0; i < processes; i++) {
pid_t p = _GET_KINFO_PID (kp[i]); p = _GET_KINFO_PID(kp[i]);
if (pid != 0 && pid != p) if (pid != 0 && pid != p)
continue; continue;
if (uid != 0 && uid != _GET_KINFO_UID (kp[i])) if (uid != 0 && uid != _GET_KINFO_UID(kp[i]))
continue; continue;
if (cmd) { if (cmd) {
if (! _GET_KINFO_COMM (kp[i]) || if (! _GET_KINFO_COMM(kp[i]) ||
strcmp (cmd, _GET_KINFO_COMM (kp[i])) != 0) strcmp(cmd, _GET_KINFO_COMM(kp[i])) != 0)
continue; continue;
} }
if (argv && *argv && ! cmd) { if (argv && *argv && ! cmd) {
pargv = _KVM_GETARGV (kd, &kp[i], pargc); pargv = _KVM_GETARGV(kd, &kp[i], pargc);
if (! pargv || ! *pargv) if (! pargv || ! *pargv)
continue; continue;
@ -263,7 +263,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
match = 1; match = 1;
while (*arg && *pargv) while (*arg && *pargv)
if (strcmp (*arg++, *pargv++) != 0) { if (strcmp(*arg++, *pargv++) != 0) {
match = 0; match = 0;
break; break;
} }
@ -272,12 +272,12 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
continue; continue;
} }
tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); tmp = realloc(pids, sizeof(pid_t) * (npids + 2));
if (! tmp) { if (! tmp) {
free (pids); free(pids);
kvm_close (kd); kvm_close(kd);
errno = ENOMEM; errno = ENOMEM;
return (NULL); return NULL;
} }
pids = tmp; pids = tmp;
@ -285,9 +285,9 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
pids[npids + 1] = 0; pids[npids + 1] = 0;
npids++; npids++;
} }
kvm_close (kd); kvm_close(kd);
return (pids); return pids;
} }
librc_hidden_def(rc_find_pids) librc_hidden_def(rc_find_pids)
@ -295,67 +295,72 @@ librc_hidden_def(rc_find_pids)
# error "Platform not supported!" # error "Platform not supported!"
#endif #endif
static bool _match_daemon (const char *path, const char *file, char **match) static bool _match_daemon(const char *path, const char *file,
RC_STRINGLIST *match)
{ {
char *line; char *line;
char *ffile = rc_strcatpaths (path, file, (char *) NULL); char *ffile = rc_strcatpaths(path, file, (char *) NULL);
FILE *fp; FILE *fp;
RC_STRING *m;
fp = fopen (ffile, "r"); fp = fopen(ffile, "r");
free (ffile); free(ffile);
if (! fp) if (! fp)
return (false); return false;
while ((line = rc_getline (fp))) { while ((line = rc_getline(fp))) {
rc_strlist_delete (&match, line); TAILQ_FOREACH(m, match, entries)
if (! match || !*match) if (strcmp(line, m->value) == 0) {
TAILQ_REMOVE(match, m, entries);
break;
}
if (! TAILQ_FIRST(match))
break; break;
} }
fclose (fp); fclose(fp);
if (match && *match) if (TAILQ_FIRST(match))
return (false); return false;
return (true); return true;
} }
static char **_match_list (const char* const* argv, static RC_STRINGLIST *_match_list(const char* const* argv,
const char *name, const char *pidfile) const char *name, const char *pidfile)
{ {
char **match = NULL; RC_STRINGLIST *match = rc_stringlist_new();
int i = 0; int i = 0;
size_t l; size_t l;
char *m; char *m;
while (argv && argv[i]) { while (argv && argv[i]) {
l = strlen (*argv) + strlen ("argv_=") + 16; l = strlen(*argv) + strlen("argv_=") + 16;
m = xmalloc (sizeof (char) * l); m = xmalloc(sizeof(char) * l);
snprintf (m, l, "argv_0=%s", argv[i++]); snprintf(m, l, "argv_0=%s", argv[i++]);
rc_strlist_add (&match, m); rc_stringlist_add(match, m);
free (m); free(m);
} }
if (name) { if (name) {
l = strlen (name) + 6; l = strlen(name) + 6;
m = xmalloc (sizeof (char) * l); m = xmalloc(sizeof (char) * l);
snprintf (m, l, "name=%s", name); snprintf(m, l, "name=%s", name);
rc_strlist_add (&match, m); rc_stringlist_add(match, m);
free (m); free(m);
} }
if (pidfile) { if (pidfile) {
l = strlen (pidfile) + 9; l = strlen(pidfile) + 9;
m = xmalloc (sizeof (char) * l); m = xmalloc(sizeof (char) * l);
snprintf (m, l, "pidfile=%s", pidfile); snprintf(m, l, "pidfile=%s", pidfile);
rc_strlist_add (&match, m); rc_stringlist_add(match, m);
free (m); free (m);
} }
return (match); return match;
} }
bool rc_service_daemon_set (const char *service, const char *const *argv, bool rc_service_daemon_set(const char *service, const char *const *argv,
const char *name, const char *pidfile, const char *name, const char *pidfile, bool started)
bool started)
{ {
char *dirpath; char *dirpath;
char *file = NULL; char *file = NULL;
@ -364,123 +369,123 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
bool retval = false; bool retval = false;
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
char **match = NULL; RC_STRINGLIST *match;
int i = 0; int i = 0;
char buffer[10];
FILE *fp;
if (! (argv && *argv) && ! name && ! pidfile) { if (!(argv && *argv) && ! name && ! pidfile) {
errno = EINVAL; errno = EINVAL;
return (false); return false;
} }
dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", dirpath = rc_strcatpaths(RC_SVCDIR, "daemons",
basename_c (service), (char *) NULL); basename_c(service), (char *) NULL);
match = _match_list (argv, name, pidfile); match = _match_list(argv, name, pidfile);
/* Regardless, erase any existing daemon info */ /* Regardless, erase any existing daemon info */
if ((dp = opendir (dirpath))) { if ((dp = opendir(dirpath))) {
while ((d = readdir (dp))) { while ((d = readdir(dp))) {
if (d->d_name[0] == '.') if (d->d_name[0] == '.')
continue; continue;
file = rc_strcatpaths (dirpath, d->d_name, (char *) NULL); file = rc_strcatpaths(dirpath, d->d_name, (char *) NULL);
nfiles++; nfiles++;
if (! oldfile) { if (! oldfile) {
if (_match_daemon (dirpath, d->d_name, match)) { if (_match_daemon(dirpath, d->d_name, match)) {
unlink (file); unlink (file);
oldfile = file; oldfile = file;
nfiles--; nfiles--;
} }
} else { } else {
rename (file, oldfile); rename(file, oldfile);
free (oldfile); free(oldfile);
oldfile = file; oldfile = file;
} }
} }
free (file); free(file);
closedir (dp); closedir(dp);
} }
/* Now store our daemon info */ /* Now store our daemon info */
if (started) { if (started) {
char buffer[10]; if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
FILE *fp; snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1);
file = rc_strcatpaths(dirpath, buffer, (char *) NULL);
if (mkdir (dirpath, 0755) == 0 || errno == EEXIST) { if ((fp = fopen(file, "w"))) {
snprintf (buffer, sizeof (buffer), "%03d", nfiles + 1);
file = rc_strcatpaths (dirpath, buffer, (char *) NULL);
if ((fp = fopen (file, "w"))) {
while (argv && argv[i]) { while (argv && argv[i]) {
fprintf (fp, "argv_%d=%s\n", i, argv[i]); fprintf(fp, "argv_%d=%s\n", i, argv[i]);
i++; i++;
} }
fprintf (fp, "name="); fprintf(fp, "name=");
if (name) if (name)
fprintf (fp, "%s", name); fprintf(fp, "%s", name);
fprintf (fp, "\npidfile="); fprintf(fp, "\npidfile=");
if (pidfile) if (pidfile)
fprintf (fp, "%s", pidfile); fprintf(fp, "%s", pidfile);
fprintf (fp, "\n"); fprintf(fp, "\n");
fclose (fp); fclose(fp);
retval = true; retval = true;
} }
free (file); free(file);
} }
} else } else
retval = true; retval = true;
rc_strlist_free (match); rc_stringlist_free(match);
free (dirpath); free(dirpath);
return (retval); return retval;
} }
librc_hidden_def(rc_service_daemon_set) librc_hidden_def(rc_service_daemon_set)
bool rc_service_started_daemon (const char *service, const char *const *argv, bool
int indx) rc_service_started_daemon (const char *service, const char *const *argv,
int indx)
{ {
char *dirpath; char *dirpath;
char *file; char *file;
size_t l; size_t l;
char **match; RC_STRINGLIST *match;
bool retval = false; bool retval = false;
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
if (! service || ! (argv && *argv)) if (!service || !(argv && *argv))
return (false); return false;
dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename_c (service), dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
(char *) NULL); (char *) NULL);
match = _match_list (argv, NULL, NULL); match = _match_list(argv, NULL, NULL);
if (indx > 0) { if (indx > 0) {
l = sizeof (char) * 10; l = sizeof (char) * 10;
file = xmalloc (l); file = xmalloc(l);
snprintf (file, l, "%03d", indx); snprintf(file, l, "%03d", indx);
retval = _match_daemon (dirpath, file, match); retval = _match_daemon(dirpath, file, match);
free (file); free(file);
} else { } else {
if ((dp = opendir (dirpath))) { if ((dp = opendir(dirpath))) {
while ((d = readdir (dp))) { while ((d = readdir(dp))) {
if (d->d_name[0] == '.') if (d->d_name[0] == '.')
continue; continue;
retval = _match_daemon (dirpath, d->d_name, match); retval = _match_daemon(dirpath, d->d_name, match);
if (retval) if (retval)
break; break;
} }
closedir (dp); closedir(dp);
} }
} }
free (dirpath); free(dirpath);
rc_strlist_free (match); rc_stringlist_free(match);
return (retval); return retval;
} }
librc_hidden_def(rc_service_started_daemon) librc_hidden_def(rc_service_started_daemon)
bool rc_service_daemons_crashed (const char *service) bool rc_service_daemons_crashed(const char *service)
{ {
char *dirpath; char *dirpath;
DIR *dp; DIR *dp;
@ -497,116 +502,123 @@ bool rc_service_daemons_crashed (const char *service)
char *p; char *p;
char *token; char *token;
bool retval = false; bool retval = false;
RC_STRINGLIST *list;
RC_STRING *s;
size_t i;
if (! service) dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
return (false); (char *) NULL);
dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename_c (service), if (! (dp = opendir(dirpath))) {
(char *) NULL); free(dirpath);
return false;
if (! (dp = opendir (dirpath))) {
free (dirpath);
return (false);
} }
while ((d = readdir (dp))) { while ((d = readdir(dp))) {
if (d->d_name[0] == '.') if (d->d_name[0] == '.')
continue; continue;
path = rc_strcatpaths (dirpath, d->d_name, (char *) NULL); path = rc_strcatpaths(dirpath, d->d_name, (char *) NULL);
fp = fopen (path, "r"); fp = fopen(path, "r");
free (path); free(path);
if (! fp) if (! fp)
break; break;
while ((line = rc_getline (fp))) { list = rc_stringlist_new();
while ((line = rc_getline(fp))) {
p = line; p = line;
if ((token = strsep (&p, "=")) == NULL || ! p) { if ((token = strsep(&p, "=")) == NULL || ! p) {
free (line); free(line);
continue; continue;
} }
if (strlen (p) == 0) { if (! *p) {
free (line); free(line);
continue; continue;
} }
if (strncmp (token, "argv_", 5) == 0) { if (strncmp(token, "argv_", 5) == 0) {
rc_strlist_add (&argv, p); rc_stringlist_add(list, p);
} else if (strcmp (token, "exec") == 0) { } else if (strcmp(token, "exec") == 0) {
if (exec) if (exec)
free (exec); free(exec);
exec = xstrdup (p); exec = xstrdup(p);
} else if (strcmp (token, "name") == 0) { } else if (strcmp(token, "name") == 0) {
if (name) if (name)
free (name); free(name);
name = xstrdup (p); name = xstrdup(p);
} else if (strcmp (token, "pidfile") == 0) { } else if (strcmp(token, "pidfile") == 0) {
if (pidfile) if (pidfile)
free (pidfile); free(pidfile);
pidfile = xstrdup (p); pidfile = xstrdup(p);
} }
free (line); free(line);
} }
fclose (fp); fclose(fp);
pid = 0; pid = 0;
if (pidfile) { if (pidfile) {
if (! exists (pidfile)) { if (! exists(pidfile)) {
retval = true; retval = true;
break; break;
} }
if ((fp = fopen (pidfile, "r")) == NULL) { if ((fp = fopen(pidfile, "r")) == NULL) {
retval = true; retval = true;
break; break;
} }
if (fscanf (fp, "%d", &pid) != 1) { if (fscanf(fp, "%d", &pid) != 1) {
fclose (fp); fclose (fp);
retval = true; retval = true;
break; break;
} }
fclose (fp); fclose(fp);
free (pidfile); free(pidfile);
pidfile = NULL; pidfile = NULL;
/* We have the pid, so no need to match on name */ /* We have the pid, so no need to match on name */
rc_strlist_free (argv); rc_stringlist_free(list);
argv = NULL; list = NULL;
free (exec); free (exec);
exec = NULL; exec = NULL;
free (name); free (name);
name = NULL; name = NULL;
} } else {
if (exec && ! TAILQ_FIRST(list)) {
if (exec && ! argv) { rc_stringlist_add(list, exec);
rc_strlist_add (&argv, exec); }
free (exec); free(exec);
exec = NULL; exec = NULL;
/* We need to flatten our linked list into an array */
i = 0;
TAILQ_FOREACH(s, list, entries)
i++;
argv = xmalloc(sizeof(char *) * (i + 1));
i = 0;
TAILQ_FOREACH(s, list, entries)
argv[i++] = s->value;
argv[i] = '\0';
} }
if ((pids = rc_find_pids ((const char *const *)argv, name, 0, pid)) == NULL) { if ((pids = rc_find_pids((const char *const *)argv, name, 0, pid)) == NULL)
retval = true; retval = true;
break; free(pids);
} free(argv);
free (pids);
rc_strlist_free (argv);
argv = NULL; argv = NULL;
free (exec); rc_stringlist_free(list);
exec = NULL; free(name);
free (name);
name = NULL; name = NULL;
if (retval)
break;
} }
rc_strlist_free (argv); free(dirpath);
free (exec); closedir(dp);
free (name);
free (dirpath);
closedir (dp);
return (retval); return retval;
} }
librc_hidden_def(rc_service_daemons_crashed) librc_hidden_def(rc_service_daemons_crashed)

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
/*
* librc-depend.h
* Internal header file for dependency structures
*/
/*
* Copyright 2007-2008 Roy Marples
* All rights reserved
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _LIBRC_DEPEND_H
#define _LIBRC_DEPEND_H
/*! @name Dependency structures
* private to librc - rc.h exposes them just a pointers */
/*! Singly linked list of dependency types that list the services the
* type is for */
typedef struct rc_deptype
{
/*! ineed, iuse, iafter, etc */
char *type;
/*! NULL terminated list of services */
char **services;
/*! Next dependency type */
struct rc_deptype *next;
} rc_deptype_t;
/*! Singly linked list of services and their dependencies */
typedef struct rc_depinfo
{
/*! Name of service */
char *service;
/*! Dependencies */
rc_deptype_t *depends;
/*! Next service dependency type */
struct rc_depinfo *next;
} rc_depinfo_t;
#endif

View File

@ -35,14 +35,14 @@ bool rc_yesno (const char *value)
{ {
if (! value) { if (! value) {
errno = ENOENT; errno = ENOENT;
return (false); return false;
} }
if (strcasecmp (value, "yes") == 0 || if (strcasecmp (value, "yes") == 0 ||
strcasecmp (value, "y") == 0 || strcasecmp (value, "y") == 0 ||
strcasecmp (value, "true") == 0 || strcasecmp (value, "true") == 0 ||
strcasecmp (value, "1") == 0) strcasecmp (value, "1") == 0)
return (true); return true;
if (strcasecmp (value, "no") != 0 && if (strcasecmp (value, "no") != 0 &&
strcasecmp (value, "n") != 0 && strcasecmp (value, "n") != 0 &&
@ -50,7 +50,7 @@ bool rc_yesno (const char *value)
strcasecmp (value, "0") != 0) strcasecmp (value, "0") != 0)
errno = EINVAL; errno = EINVAL;
return (false); return false;
} }
librc_hidden_def(rc_yesno) librc_hidden_def(rc_yesno)
@ -64,7 +64,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...)
char *pathp; char *pathp;
if (! path1 || ! paths) if (! path1 || ! paths)
return (NULL); return NULL;
length = strlen (path1) + strlen (paths) + 1; length = strlen (path1) + strlen (paths) + 1;
if (*paths != '/') if (*paths != '/')
@ -101,7 +101,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...)
*pathp++ = 0; *pathp++ = 0;
return (path); return path;
} }
librc_hidden_def(rc_strcatpaths) librc_hidden_def(rc_strcatpaths)
@ -113,7 +113,7 @@ char *rc_getline (FILE *fp)
size_t last = 0; size_t last = 0;
if (feof (fp)) if (feof (fp))
return (NULL); return NULL;
do { do {
len += BUFSIZ; len += BUFSIZ;
@ -128,74 +128,78 @@ char *rc_getline (FILE *fp)
if (*line && line[--last] == '\n') if (*line && line[--last] == '\n')
line[last] = '\0'; line[last] = '\0';
return (line); return line;
} }
librc_hidden_def(rc_getline) librc_hidden_def(rc_getline)
char **rc_config_list (const char *file) RC_STRINGLIST *rc_config_list(const char *file)
{ {
FILE *fp; FILE *fp;
char *buffer; char *buffer;
char *p; char *p;
char *token; char *token;
char **list = NULL; RC_STRINGLIST *list;
if (! (fp = fopen (file, "r"))) if (!(fp = fopen(file, "r")))
return (NULL); return NULL;
while ((p = buffer = rc_getline (fp))) { list = rc_stringlist_new();
while ((p = buffer = rc_getline(fp))) {
/* Strip leading spaces/tabs */ /* Strip leading spaces/tabs */
while ((*p == ' ') || (*p == '\t')) while ((*p == ' ') || (*p == '\t'))
p++; p++;
/* Get entry - we do not want comments */ /* Get entry - we do not want comments */
token = strsep (&p, "#"); token = strsep(&p, "#");
if (token && (strlen (token) > 1)) { if (token && (strlen(token) > 1)) {
/* If not variable assignment then skip */ /* If not variable assignment then skip */
if (strchr (token, '=')) { if (strchr(token, '=')) {
/* Stip the newline if present */ /* Stip the newline if present */
if (token[strlen (token) - 1] == '\n') if (token[strlen(token) - 1] == '\n')
token[strlen (token) - 1] = 0; token[strlen(token) - 1] = 0;
rc_strlist_add (&list, token); rc_stringlist_add(list, token);
} }
} }
free (buffer); free(buffer);
} }
fclose (fp); fclose(fp);
return (list); return list;
} }
librc_hidden_def(rc_config_list) librc_hidden_def(rc_config_list)
char **rc_config_load (const char *file) RC_STRINGLIST *rc_config_load(const char *file)
{ {
char **list = NULL; RC_STRINGLIST *list = NULL;
char **config = NULL; RC_STRINGLIST *config = NULL;
char *token; char *token;
char *line; RC_STRING *line;
char *linep; RC_STRING *cline;
char *linetok;
size_t i = 0; size_t i = 0;
int j;
bool replaced; bool replaced;
char *entry; char *entry;
char *newline; char *newline;
char *p;
list = rc_config_list (file); config = rc_stringlist_new();
STRLIST_FOREACH (list, line, j) {
list = rc_config_list(file);
TAILQ_FOREACH(line, list, entries) {
/* Get entry */ /* Get entry */
if (! (token = strsep (&line, "="))) p = line->value;
if (! (token = strsep(&p, "=")))
continue; continue;
entry = xstrdup (token); entry = xstrdup (token);
/* Preserve shell coloring */ /* Preserve shell coloring */
if (*line == '$') if (*p == '$')
token = line; token = line->value;
else else
do { do {
/* Bash variables are usually quoted */ /* Bash variables are usually quoted */
token = strsep (&line, "\"\'"); token = strsep(&p, "\"\'");
} while (token && *token == '\0'); } while (token && *token == '\0');
/* Drop a newline if that's all we have */ /* Drop a newline if that's all we have */
@ -205,57 +209,54 @@ char **rc_config_load (const char *file)
token[i] = 0; token[i] = 0;
i = strlen (entry) + strlen (token) + 2; i = strlen (entry) + strlen (token) + 2;
newline = xmalloc (sizeof (char) * i); newline = xmalloc(sizeof(char) * i);
snprintf (newline, i, "%s=%s", entry, token); snprintf(newline, i, "%s=%s", entry, token);
} else { } else {
i = strlen (entry) + 2; i = strlen (entry) + 2;
newline = xmalloc (sizeof (char) * i); newline = xmalloc(sizeof(char) * i);
snprintf (newline, i, "%s=", entry); snprintf(newline, i, "%s=", entry);
} }
replaced = false; replaced = false;
/* In shells the last item takes precedence, so we need to remove /* In shells the last item takes precedence, so we need to remove
any prior values we may already have */ any prior values we may already have */
STRLIST_FOREACH (config, line, i) { TAILQ_FOREACH(cline, config, entries) {
char *tmp = xstrdup (line); p = strchr(cline->value, '=');
linep = tmp; if (p && strncmp(entry, cline->value,
linetok = strsep (&linep, "="); (size_t) (p - cline->value)) == 0)
if (strcmp (linetok, entry) == 0) { {
/* We have a match now - to save time we directly replace it */ /* We have a match now - to save time we directly replace it */
free (config[i - 1]); free(cline->value);
config[i - 1] = newline; cline->value = newline;
replaced = true; replaced = true;
free (tmp);
break; break;
} }
free (tmp);
} }
if (! replaced) { if (! replaced) {
rc_strlist_addsort (&config, newline); rc_stringlist_add(config, newline);
free (newline); free(newline);
} }
free (entry); free(entry);
} }
rc_strlist_free (list); rc_stringlist_free(list);
return (config); return config;
} }
librc_hidden_def(rc_config_load) librc_hidden_def(rc_config_load)
char *rc_config_value (const char *const *list, const char *entry) char *rc_config_value(RC_STRINGLIST *list, const char *entry)
{ {
const char *line; RC_STRING *line;
int i;
char *p; char *p;
STRLIST_FOREACH (list, line, i) { TAILQ_FOREACH(line, list, entries) {
p = strchr (line, '='); p = strchr(line->value, '=');
if (p && strncmp (entry, line, (size_t) (p - line)) == 0) if (p &&
return (p += 1); strncmp(entry, line->value, (size_t)(p - line->value)) == 0)
return p += 1;
} }
return (NULL); return NULL;
} }
librc_hidden_def(rc_config_value) librc_hidden_def(rc_config_value)

View File

@ -1,230 +0,0 @@
/*
librc-strlist.h
String list functions for using char ** arrays
Based on a previous implementation by Martin Schlemmer
*/
/*
* Copyright 2007-2008 Roy Marples
* All rights reserved
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "librc.h"
static char *_rc_strlist_add (char ***list, const char *item, bool uniq)
{
char **newlist;
char **lst = *list;
int i = 0;
if (! item)
return (NULL);
while (lst && lst[i]) {
if (uniq && strcmp (lst[i], item) == 0) {
errno = EEXIST;
return (NULL);
}
i++;
}
newlist = xrealloc (lst, sizeof (char *) * (i + 2));
newlist[i] = xstrdup (item);
newlist[i + 1] = NULL;
*list = newlist;
return (newlist[i]);
}
char *rc_strlist_add (char ***list, const char *item)
{
return (_rc_strlist_add (list, item, false));
}
librc_hidden_def(rc_strlist_add)
char *rc_strlist_addu (char ***list, const char *item)
{
return (_rc_strlist_add (list, item, true));
}
librc_hidden_def(rc_strlist_addu)
static char *_rc_strlist_addsort (char ***list, const char *item,
int (*sortfunc) (const char *s1,
const char *s2),
bool uniq)
{
char **newlist;
char **lst = *list;
int i = 0;
char *tmp1;
char *tmp2;
char *retval;
if (! item)
return (NULL);
while (lst && lst[i]) {
if (uniq && strcmp (lst[i], item) == 0) {
errno = EEXIST;
return (NULL);
}
i++;
}
newlist = xrealloc (lst, sizeof (char *) * (i + 2));
if (! i)
newlist[i] = NULL;
newlist[i + 1] = NULL;
i = 0;
while (newlist[i] && sortfunc (newlist[i], item) < 0)
i++;
tmp1 = newlist[i];
retval = newlist[i] = xstrdup (item);
do {
i++;
tmp2 = newlist[i];
newlist[i] = tmp1;
tmp1 = tmp2;
} while (tmp1);
*list = newlist;
return (retval);
}
char *rc_strlist_addsort (char ***list, const char *item)
{
return (_rc_strlist_addsort (list, item, strcoll, false));
}
librc_hidden_def(rc_strlist_addsort)
char *rc_strlist_addsortc (char ***list, const char *item)
{
return (_rc_strlist_addsort (list, item, strcmp, false));
}
librc_hidden_def(rc_strlist_addsortc)
char *rc_strlist_addsortu (char ***list, const char *item)
{
return (_rc_strlist_addsort (list, item, strcmp, true));
}
librc_hidden_def(rc_strlist_addsortu)
bool rc_strlist_delete (char ***list, const char *item)
{
char **lst = *list;
int i = 0;
if (!lst || ! item)
return (false);
while (lst[i]) {
if (strcmp (lst[i], item) == 0) {
free (lst[i]);
do {
lst[i] = lst[i + 1];
i++;
} while (lst[i]);
return (true);
}
i++;
}
errno = ENOENT;
return (false);
}
librc_hidden_def(rc_strlist_delete)
char *rc_strlist_join (char ***list1, char **list2)
{
char **lst1 = *list1;
char **newlist;
int i = 0;
int j = 0;
if (! list2)
return (NULL);
while (lst1 && lst1[i])
i++;
while (list2[j])
j++;
newlist = xrealloc (lst1, sizeof (char *) * (i + j + 1));
j = 0;
while (list2[j]) {
newlist[i] = list2[j];
/* Take the item off the 2nd list as it's only a shallow copy */
list2[j] = NULL;
i++;
j++;
}
newlist[i] = NULL;
*list1 = newlist;
return (newlist[i == 0 ? 0 : i - 1]);
}
librc_hidden_def(rc_strlist_join)
void rc_strlist_reverse (char **list)
{
char *item;
int i = 0;
int j = 0;
if (! list)
return;
while (list[j])
j++;
j--;
while (i < j && list[i] && list[j]) {
item = list[i];
list[i] = list[j];
list[j] = item;
i++;
j--;
}
}
librc_hidden_def(rc_strlist_reverse)
void rc_strlist_free (char **list)
{
int i = 0;
if (! list)
return;
while (list[i])
free (list[i++]);
free (list);
}
librc_hidden_def(rc_strlist_free)

File diff suppressed because it is too large Load Diff

View File

@ -64,10 +64,8 @@
#include <kvm.h> #include <kvm.h>
#endif #endif
#include "librc-depend.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
#include "hidden-visibility.h" #include "hidden-visibility.h"
#define librc_hidden_proto(x) hidden_proto(x) #define librc_hidden_proto(x) hidden_proto(x)
@ -115,15 +113,11 @@ librc_hidden_proto(rc_service_state)
librc_hidden_proto(rc_service_value_get) librc_hidden_proto(rc_service_value_get)
librc_hidden_proto(rc_service_value_set) librc_hidden_proto(rc_service_value_set)
librc_hidden_proto(rc_strcatpaths) librc_hidden_proto(rc_strcatpaths)
librc_hidden_proto(rc_strlist_add) librc_hidden_proto(rc_stringlist_add)
librc_hidden_proto(rc_strlist_addu) librc_hidden_proto(rc_stringlist_addu)
librc_hidden_proto(rc_strlist_addsort) librc_hidden_proto(rc_stringlist_delete)
librc_hidden_proto(rc_strlist_addsortc) librc_hidden_proto(rc_stringlist_free)
librc_hidden_proto(rc_strlist_addsortu) librc_hidden_proto(rc_stringlist_sort)
librc_hidden_proto(rc_strlist_delete)
librc_hidden_proto(rc_strlist_free)
librc_hidden_proto(rc_strlist_join)
librc_hidden_proto(rc_strlist_reverse)
librc_hidden_proto(rc_yesno) librc_hidden_proto(rc_yesno)
#endif #endif

View File

@ -32,15 +32,24 @@
# if (GCC_VERSION >= 3005) # if (GCC_VERSION >= 3005)
# define SENTINEL __attribute__ ((__sentinel__)) # define SENTINEL __attribute__ ((__sentinel__))
# endif # endif
# define DEPRECATED __attribute__ ((deprecated))
#endif #endif
#ifndef SENTINEL #ifndef SENTINEL
# define SENTINEL # define SENTINEL
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#include <sys/queue.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
/* A doubly linked list using queue(3) for ease of use */
typedef struct rc_string {
char *value;
TAILQ_ENTRY(rc_string) entries;
} RC_STRING;
typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST;
/*! @name Reserved runlevel names */ /*! @name Reserved runlevel names */
#define RC_LEVEL_SYSINIT "sysinit" #define RC_LEVEL_SYSINIT "sysinit"
#define RC_LEVEL_SINGLE "single" #define RC_LEVEL_SINGLE "single"
@ -49,30 +58,30 @@
/*! Return the current runlevel. /*! Return the current runlevel.
* @return the current runlevel */ * @return the current runlevel */
char *rc_runlevel_get (void); char *rc_runlevel_get(void);
/*! Checks if the runlevel exists or not /*! Checks if the runlevel exists or not
* @param runlevel to check * @param runlevel to check
* @return true if the runlevel exists, otherwise false */ * @return true if the runlevel exists, otherwise false */
bool rc_runlevel_exists (const char *runlevel); bool rc_runlevel_exists(const char *);
/*! Return a NULL terminated list of runlevels /*! Return a NULL terminated list of runlevels
* @return a NULL terminated list of runlevels */ * @return a NULL terminated list of runlevels */
char **rc_runlevel_list (void); RC_STRINGLIST *rc_runlevel_list(void);
/*! Set the runlevel. /*! Set the runlevel.
* This just changes the stored runlevel and does not start or stop any * This just changes the stored runlevel and does not start or stop any
* services. * services.
* @param runlevel to store */ * @param runlevel to store */
bool rc_runlevel_set (const char *runlevel); bool rc_runlevel_set(const char *);
/*! Is the runlevel starting? /*! Is the runlevel starting?
* @return true if yes, otherwise false */ * @return true if yes, otherwise false */
bool rc_runlevel_starting (void); bool rc_runlevel_starting(void);
/*! Is the runlevel stopping? /*! Is the runlevel stopping?
* @return true if yes, otherwise false */ * @return true if yes, otherwise false */
bool rc_runlevel_stopping (void); bool rc_runlevel_stopping(void);
/*! @name RC /*! @name RC
* A service can be given as a full path or just its name. * A service can be given as a full path or just its name.
@ -97,19 +106,19 @@ typedef enum
RC_SERVICE_FAILED = 0x0200, RC_SERVICE_FAILED = 0x0200,
RC_SERVICE_SCHEDULED = 0x0400, RC_SERVICE_SCHEDULED = 0x0400,
RC_SERVICE_WASINACTIVE = 0x0800 RC_SERVICE_WASINACTIVE = 0x0800
} rc_service_state_t; } RC_SERVICE;
/*! Add the service to the runlevel /*! Add the service to the runlevel
* @param runlevel to add to * @param runlevel to add to
* @param service to add * @param service to add
* @return true if successful, otherwise false */ * @return true if successful, otherwise false */
bool rc_service_add (const char *runlevel, const char *service); bool rc_service_add(const char *, const char *);
/*! Remove the service from the runlevel /*! Remove the service from the runlevel
* @param runlevel to remove from * @param runlevel to remove from
* @param service to remove * @param service to remove
* @return true if sucessful, otherwise false */ * @return true if sucessful, otherwise false */
bool rc_service_delete (const char *runlevel, const char *service); bool rc_service_delete(const char *, const char *);
/*! Save the arguments to find a running daemon /*! Save the arguments to find a running daemon
* @param service to save arguments for * @param service to save arguments for
@ -117,116 +126,113 @@ bool rc_service_delete (const char *runlevel, const char *service);
* @param name of the process (optional) * @param name of the process (optional)
* @param pidfile of the process (optional) * @param pidfile of the process (optional)
* @param started if true, add the arguments otherwise remove existing matching arguments */ * @param started if true, add the arguments otherwise remove existing matching arguments */
bool rc_service_daemon_set (const char *service, const char *const *argv, bool rc_service_daemon_set(const char *, const char *const *, const char *, const char *,
const char *name, const char *pidfile, bool);
bool started);
/*! Returns a description of what the service and/or option does. /*! Returns a description of what the service and/or option does.
* @param service to check * @param service to check
* @param option to check (if NULL, service description) * @param option to check (if NULL, service description)
* @return a newly allocated pointer to the description */ * @return a newly allocated pointer to the description */
char *rc_service_description (const char *service, const char *option); char *rc_service_description(const char *, const char *);
/*! Checks if a service exists or not. /*! Checks if a service exists or not.
* @param service to check * @param service to check
* @return true if service exists, otherwise false */ * @return true if service exists, otherwise false */
bool rc_service_exists (const char *service); bool rc_service_exists(const char *);
/*! Checks if a service is in a runlevel /*! Checks if a service is in a runlevel
* @param service to check * @param service to check
* @param runlevel it should be in * @param runlevel it should be in
* @return true if service is in the runlevel, otherwise false */ * @return true if service is in the runlevel, otherwise false */
bool rc_service_in_runlevel (const char *service, const char *runlevel); bool rc_service_in_runlevel(const char *, const char *);
/*! Marks the service state /*! Marks the service state
* @param service to mark * @param service to mark
* @param state service should be in * @param state service should be in
* @return true if service state change was successful, otherwise false */ * @return true if service state change was successful, otherwise false */
bool rc_service_mark (const char *service, rc_service_state_t state); bool rc_service_mark(const char *, RC_SERVICE);
/*! Lists the extra commands a service has /*! Lists the extra commands a service has
* @param service to load the commands from * @param service to load the commands from
* @return NULL terminated string list of commands */ * @return NULL terminated string list of commands */
char **rc_service_extra_commands (const char *service); RC_STRINGLIST *rc_service_extra_commands(const char *);
/*! Resolves a service name to its full path. /*! Resolves a service name to its full path.
* @param service to check * @param service to check
* @return pointer to full path of service */ * @return pointer to full path of service */
char *rc_service_resolve (const char *service); char *rc_service_resolve(const char *);
/*! Schedule a service to be started when another service starts /*! Schedule a service to be started when another service starts
* @param service that starts the scheduled service when started * @param service that starts the scheduled service when started
* @param service_to_start service that will be started */ * @param service_to_start service that will be started */
bool rc_service_schedule_start (const char *service, bool rc_service_schedule_start(const char *, const char *);
const char *service_to_start);
/*! Return a NULL terminated list of services that are scheduled to start /*! Return a NULL terminated list of services that are scheduled to start
* when the given service has started * when the given service has started
* @param service to check * @param service to check
* @return NULL terminated list of services scheduled to start */ * @return NULL terminated list of services scheduled to start */
char **rc_services_scheduled_by (const char *service); RC_STRINGLIST *rc_services_scheduled_by(const char *);
/*! Clear the list of services scheduled to be started by this service /*! Clear the list of services scheduled to be started by this service
* @param service to clear * @param service to clear
* @return true if no errors, otherwise false */ * @return true if no errors, otherwise false */
bool rc_service_schedule_clear (const char *service); bool rc_service_schedule_clear(const char *);
/*! Checks if a service in in a state /*! Checks if a service in in a state
* @param service to check * @param service to check
* @return state of the service */ * @return state of the service */
rc_service_state_t rc_service_state (const char *service); RC_SERVICE rc_service_state(const char *);
/*! Start a service /*! Start a service
* @param service to start * @param service to start
* @return pid of the service starting process */ * @return pid of the service starting process */
pid_t rc_service_start (const char *service); pid_t rc_service_start(const char *);
/*! Stop a service /*! Stop a service
* @param service to stop * @param service to stop
* @return pid of service stopping process */ * @return pid of service stopping process */
pid_t rc_service_stop (const char *service); pid_t rc_service_stop(const char *);
/*! Check if the service started the daemon /*! Check if the service started the daemon
* @param service to check * @param service to check
* @param exec to check * @param exec to check
* @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc) * @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc)
* @return true if started by this service, otherwise false */ * @return true if started by this service, otherwise false */
bool rc_service_started_daemon (const char *service, const char *const *argv, bool rc_service_started_daemon(const char *, const char *const *, int);
int indx);
/*! Return a saved value for a service /*! Return a saved value for a service
* @param service to check * @param service to check
* @param option to load * @param option to load
* @return saved value */ * @return saved value */
char *rc_service_value_get (const char *service, const char *option); char *rc_service_value_get(const char *, const char *);
/*! Save a persistent value for a service /*! Save a persistent value for a service
* @param service to save for * @param service to save for
* @param option to save * @param option to save
* @param value of the option * @param value of the option
* @return true if saved, otherwise false */ * @return true if saved, otherwise false */
bool rc_service_value_set (const char *service, const char *option, bool rc_service_value_set(const char *, const char *, const char *);
const char *value);
/*! List the services in a runlevel /*! List the services in a runlevel
* @param runlevel to list * @param runlevel to list
* @return NULL terminated list of services */ * @return NULL terminated list of services */
char **rc_services_in_runlevel (const char *runlevel); RC_STRINGLIST *rc_services_in_runlevel(const char *);
/*! List the services in a state /*! List the services in a state
* @param state to list * @param state to list
* @return NULL terminated list of services */ * @return NULL terminated list of services */
char **rc_services_in_state (rc_service_state_t state); RC_STRINGLIST *rc_services_in_state(RC_SERVICE);
/*! List the services shceduled to start when this one does /*! List the services shceduled to start when this one does
* @param service to check * @param service to check
* @return NULL terminated list of services */ * @return NULL terminated list of services */
char **rc_services_scheduled (const char *service); RC_STRINGLIST *rc_services_scheduled(const char *);
/*! Checks that all daemons started with start-stop-daemon by the service /*! Checks that all daemons started with start-stop-daemon by the service
* are still running. * are still running.
* @param service to check * @param service to check
* @return true if all daemons started are still running, otherwise false */ * @return true if all daemons started are still running, otherwise false */
bool rc_service_daemons_crashed (const char *service); bool rc_service_daemons_crashed(const char *);
/*! @name System types /*! @name System types
* OpenRC can support some special sub system types, normally virtualization. * OpenRC can support some special sub system types, normally virtualization.
@ -238,7 +244,7 @@ bool rc_service_daemons_crashed (const char *service);
#define RC_SYS_VSERVER "VSERVER" #define RC_SYS_VSERVER "VSERVER"
#define RC_SYS_XEN0 "XEN0" #define RC_SYS_XEN0 "XEN0"
#define RC_SYS_XENU "XENU" #define RC_SYS_XENU "XENU"
const char *rc_sys (void); const char *rc_sys(void);
/*! @name Dependency options /*! @name Dependency options
* These options can change the services found by the rc_get_depinfo and * These options can change the services found by the rc_get_depinfo and
@ -256,40 +262,67 @@ const char *rc_sys (void);
* We analyse each init script and cache the resultant dependency tree. * We analyse each init script and cache the resultant dependency tree.
* This tree can be accessed using the below functions. */ * This tree can be accessed using the below functions. */
#ifndef _IN_LIBRC #ifdef _IN_LIBRC
/*! @name Dependency structures
* private to librc */
/*! Singly linked list of dependency types that list the services the
* type is for */
typedef struct rc_deptype
{
/*! ineed, iuse, iafter, etc */
char *type;
/*! list of services */
RC_STRINGLIST *services;
/*! list of types */
STAILQ_ENTRY(rc_deptype) entries;
} RC_DEPTYPE;
/*! Singly linked list of services and their dependencies */
typedef struct rc_depinfo
{
/*! Name of service */
char *service;
/*! Dependencies */
STAILQ_HEAD(, rc_deptype) depends;
/*! List of entries */
STAILQ_ENTRY(rc_depinfo) entries;
} RC_DEPINFO;
typedef STAILQ_HEAD(,rc_depinfo) RC_DEPTREE;
#else
/* Handles to internal structures */ /* Handles to internal structures */
typedef void *rc_depinfo_t; typedef void *RC_DEPTREE;
#endif #endif
/*! Check to see if source is newer than target. /*! Check to see if source is newer than target.
* If target is a directory then we traverse it and it's children. * If target is a directory then we traverse it and it's children.
* @return true if source is newer than target, otherwise false */ * @return true if source is newer than target, otherwise false */
bool rc_newer_than (const char *source, const char *target); bool rc_newer_than(const char *, const char *);
/*! Update the cached dependency tree if it's older than any init script, /*! Update the cached dependency tree if it's older than any init script,
* its configuration file or an external configuration file the init script * its configuration file or an external configuration file the init script
* has specified. * has specified.
* @return true if successful, otherwise false */ * @return true if successful, otherwise false */
bool rc_deptree_update (void); bool rc_deptree_update(void);
/*! Check if the cached dependency tree is older than any init script, /*! Check if the cached dependency tree is older than any init script,
* its configuration file or an external configuration file the init script * its configuration file or an external configuration file the init script
* has specified. * has specified.
* @return true if it needs updating, otherwise false */ * @return true if it needs updating, otherwise false */
bool rc_deptree_update_needed (void); bool rc_deptree_update_needed(void);
/*! Load the cached dependency tree and return a pointer to it. /*! Load the cached dependency tree and return a pointer to it.
* This pointer should be freed with rc_deptree_free when done. * This pointer should be freed with rc_deptree_free when done.
* @return pointer to the dependency tree */ * @return pointer to the dependency tree */
rc_depinfo_t *rc_deptree_load (void); RC_DEPTREE *rc_deptree_load(void);
/*! List the depend for the type of service /*! List the depend for the type of service
* @param deptree to search * @param deptree to search
* @param type to use (keywords, etc) * @param type to use (keywords, etc)
* @param service to check * @param service to check
* @return NULL terminated list of services in order */ * @return NULL terminated list of services in order */
char **rc_deptree_depend (const rc_depinfo_t *deptree, RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *, const char *, const char *);
const char *type, const char *service);
/*! List all the services in order that the given services have /*! List all the services in order that the given services have
* for the given types and options. * for the given types and options.
@ -298,10 +331,8 @@ char **rc_deptree_depend (const rc_depinfo_t *deptree,
* @param services to check * @param services to check
* @param options to pass * @param options to pass
* @return NULL terminated list of services in order */ * @return NULL terminated list of services in order */
char **rc_deptree_depends (const rc_depinfo_t *deptree, RC_STRINGLIST *rc_deptree_depends(const RC_DEPTREE *, const RC_STRINGLIST *,
const char *const *types, const RC_STRINGLIST *, const char *, int);
const char *const *services, const char *runlevel,
int options);
/*! List all the services that should be stoppned and then started, 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 * for the given runlevel, including sysinit and boot services where
@ -310,12 +341,11 @@ char **rc_deptree_depends (const rc_depinfo_t *deptree,
* @param runlevel to change into * @param runlevel to change into
* @param options to pass * @param options to pass
* @return NULL terminated list of services in order */ * @return NULL terminated list of services in order */
char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *, const char *, int);
int options);
/*! Free a deptree and its information /*! Free a deptree and its information
* @param deptree to free */ * @param deptree to free */
void rc_deptree_free (rc_depinfo_t *deptree); void rc_deptree_free(RC_DEPTREE *);
/*! @name Plugins /*! @name Plugins
* For each plugin loaded we will call rc_plugin_hook with the below * For each plugin loaded we will call rc_plugin_hook with the below
@ -347,13 +377,13 @@ typedef enum
RC_HOOK_SERVICE_START_NOW = 106, RC_HOOK_SERVICE_START_NOW = 106,
RC_HOOK_SERVICE_START_DONE = 107, RC_HOOK_SERVICE_START_DONE = 107,
RC_HOOK_SERVICE_START_OUT = 108 RC_HOOK_SERVICE_START_OUT = 108
} rc_hook_t; } RC_HOOK;
/*! Plugin entry point /*! Plugin entry point
* @param hook point * @param hook point
* @param name of runlevel or service * @param name of runlevel or service
* @return 0 for success otherwise -1 */ * @return 0 for success otherwise -1 */
int rc_plugin_hook (rc_hook_t hook, const char *name); int rc_plugin_hook(RC_HOOK, const char *);
/*! Plugins should write FOO=BAR to this fd to set any environment /*! Plugins should write FOO=BAR to this fd to set any environment
* variables they wish. Variables should be separated by NULLs. */ * variables they wish. Variables should be separated by NULLs. */
@ -362,91 +392,64 @@ extern FILE *rc_environ_fd;
/*! @name Configuration /*! @name Configuration
* These functions help to deal with shell based configuration files */ * These functions help to deal with shell based configuration files */
/*! Return a line from a file, stripping the trailing newline. */ /*! Return a line from a file, stripping the trailing newline. */
char *rc_getline (FILE *fp); char *rc_getline(FILE *);
/*! Return a NULL terminated list of non comment lines from a file. */ /*! Return a NULL terminated list of non comment lines from a file. */
char **rc_config_list (const char *file); RC_STRINGLIST *rc_config_list(const char *);
/*! Return a NULL terminated list of key=value lines from a file. */ /*! Return a NULL terminated list of key=value lines from a file. */
char **rc_config_load (const char *file); RC_STRINGLIST *rc_config_load(const char *);
/*! Return the value of the entry from a key=value list. */ /*! Return the value of the entry from a key=value list. */
char *rc_config_value (const char *const *list, const char *entry); char *rc_config_value(RC_STRINGLIST *, const char *);
/*! Check if a variable is a boolean and return it's value. /*! Check if a variable is a boolean and return it's value.
* If variable is not a boolean then we set errno to be ENOENT when it does * If variable is not a boolean then we set errno to be ENOENT when it does
* not exist or EINVAL if it's not a boolean. * not exist or EINVAL if it's not a boolean.
* @param variable to check * @param variable to check
* @return true if it matches true, yes or 1, false if otherwise. */ * @return true if it matches true, yes or 1, false if otherwise. */
bool rc_yesno (const char *variable); bool rc_yesno(const char *);
/*! @name String List functions /*! @name String List functions
* Handy functions for dealing with string arrays of char **. * Every string list should be released with a call to rc_stringlist_free. */
* 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 /*! Create a new stringlinst
* should be released with a call to rc_strlist_free. */ * @return pointer to new list */
RC_STRINGLIST *rc_stringlist_new(void);
/*! Duplicate the item, add it to end of the list and return a pointer to it. /*! Duplicate the item, add it to end of the list and return a pointer to it.
* @param list to add the item too * @param list to add the item too
* @param item to add. * @param item to add.
* @return pointer to newly added item */ * @return pointer to newly added item */
char *rc_strlist_add (char ***list, const char *item); RC_STRING *rc_stringlist_add(RC_STRINGLIST *, const char *);
/*! If the item does not exist in the list, duplicate it, add it to the /*! If the item does not exist in the list, duplicate it, add it to the
* list and then return a pointer to it. * list and then return a pointer to it.
* @param list to add the item too * @param list to add the item too
* @param item to add. * @param item to add.
* @return pointer to newly added item */ * @return pointer to newly added item */
char *rc_strlist_addu (char ***list, const char *item); RC_STRING *rc_stringlist_addu(RC_STRINGLIST *, const char *);
/*! 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. /*! Free the item and remove it from the list. Return 0 on success otherwise -1.
* @param list to add the item too * @param list to add the item too
* @param item to add. * @param item to add.
* @return true on success, otherwise false */ * @return true on success, otherwise false */
bool rc_strlist_delete (char ***list, const char *item); bool rc_stringlist_delete(RC_STRINGLIST *, const char *);
/*! Moves the contents of list2 onto list1, so list2 is effectively emptied. /*! Sort the list according to C locale
* Returns a pointer to the last item on the new list. * @param list to sort */
* @param list1 to append to void rc_stringlist_sort(RC_STRINGLIST **);
* @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. /*! Frees each item on the list and the list itself.
* @param list to free */ * @param list to free */
void rc_strlist_free (char **list); void rc_stringlist_free(RC_STRINGLIST *);
/*! Concatenate paths adding '/' if needed. The resultant pointer should be /*! Concatenate paths adding '/' if needed. The resultant pointer should be
* freed when finished with. * freed when finished with.
* @param path1 starting path * @param path1 starting path
* @param paths NULL terminated list of paths to add * @param paths NULL terminated list of paths to add
* @return pointer to the new path */ * @return pointer to the new path */
char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL; char *rc_strcatpaths(const char *, const char *, ...) SENTINEL;
/*! Find processes based on criteria. /*! Find processes based on criteria.
* All of these are optional. * All of these are optional.
@ -457,7 +460,6 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL;
* @param uid to check for * @param uid to check for
* @param pid to check for * @param pid to check for
* @return NULL terminated list of pids */ * @return NULL terminated list of pids */
pid_t *rc_find_pids (const char *const *argv, const char *cmd, pid_t *rc_find_pids(const char *const *, const char *, uid_t, pid_t);
uid_t uid, pid_t pid);
#endif #endif

View File

@ -43,15 +43,12 @@ global:
rc_service_value_get; rc_service_value_get;
rc_service_value_set; rc_service_value_set;
rc_strcatpaths; rc_strcatpaths;
rc_strlist_add; rc_stringlist_add;
rc_strlist_addu; rc_stringlist_addu;
rc_strlist_addsort; rc_stringlist_delete;
rc_strlist_addsortc; rc_stringlist_new;
rc_strlist_addsortu; rc_stringlist_sort;
rc_strlist_delete; rc_stringlist_free;
rc_strlist_free;
rc_strlist_join;
rc_strlist_reverse;
rc_sys; rc_sys;
rc_yesno; rc_yesno;

4
src/rc/.gitignore vendored
View File

@ -55,6 +55,7 @@ rc-abort
checkpath.o checkpath.o
fstabinfo.o fstabinfo.o
mountinfo.o mountinfo.o
start-stop-daemon.o
rc-applets.o rc-applets.o
rc-depend.o rc-depend.o
rc-logger.o rc-logger.o
@ -62,8 +63,7 @@ rc-misc.o
rc-plugin.o rc-plugin.o
rc-status.o rc-status.o
rc-update.o rc-update.o
rc.o
runscript.o runscript.o
start-stop-daemon.o rc.o
rc rc
.depend .depend

View File

@ -1,8 +1,8 @@
PROG= rc PROG= rc
SRCS= checkpath.c fstabinfo.c mountinfo.c \ SRCS= checkpath.c fstabinfo.c mountinfo.c start-stop-daemon.c \
rc-applets.c rc-depend.c rc-logger.c \ rc-applets.c rc-depend.c rc-logger.c \
rc-misc.c rc-plugin.c rc-status.c rc-update.c rc.c \ rc-misc.c rc-plugin.c rc-status.c rc-update.c \
runscript.c start-stop-daemon.c runscript.c rc.c
CLEANFILES= version.h CLEANFILES= version.h
@ -31,8 +31,9 @@ ALL_LINKS= ${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS}
CLEANFILES+= ${ALL_LINKS} CLEANFILES+= ${ALL_LINKS}
LDFLAGS+= -L../librc -L../libeinfo LDFLAGS+= -L../librc -L../libeinfo
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
LDADD+= -lutil -lrc -leinfo LDADD+= -lutil -lrc -leinfo
#CFLAGS+= -ggdb
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
MK= ../../mk MK= ../../mk
include ${MK}/cc.mk include ${MK}/cc.mk

View File

@ -33,35 +33,36 @@
# define _noreturn # define _noreturn
#endif #endif
_noreturn static void usage (int exit_status) _noreturn static void usage(int exit_status)
{ {
const char * const has_arg[] = { "", "<arg>", "[arg]" }; const char * const has_arg[] = { "", "<arg>", "[arg]" };
int i; int i;
int len;
char *lo;
char *p;
char *token;
#ifdef usagestring #ifdef usagestring
printf (usagestring); printf(usagestring);
#else #else
printf ("Usage: %s [options] ", applet); printf("Usage: %s [options] ", applet);
#endif #endif
#ifdef extraopts #ifdef extraopts
printf (extraopts); printf(extraopts);
#endif #endif
printf ("\n\nOptions: [" getoptstring "]\n"); printf("\n\nOptions: [" getoptstring "]\n");
for (i = 0; longopts[i].name; ++i) { for (i = 0; longopts[i].name; ++i) {
int len = printf (" -%c, --%s %s", longopts[i].val, longopts[i].name, len = printf(" -%c, --%s %s", longopts[i].val, longopts[i].name,
has_arg[longopts[i].has_arg]); has_arg[longopts[i].has_arg]);
char *lo = xstrdup (longopts_help[i]); lo = p = xstrdup(longopts_help[i]);
char *p = lo; while ((token = strsep(&p, "\n"))) {
char *token;
while ((token = strsep (&p, "\n"))) {
while (++len < 37) while (++len < 37)
printf (" "); printf(" ");
puts (token); puts(token);
len = 0; len = 0;
} }
free (lo); free(lo);
} }
exit (exit_status); exit(exit_status);
} }

View File

@ -38,4 +38,4 @@ int start_stop_daemon (int argc, char **argv);
void run_applets (int argc, char **argv); void run_applets (int argc, char **argv);
/* Handy function so we can wrap einfo around our deptree */ /* Handy function so we can wrap einfo around our deptree */
rc_depinfo_t *_rc_deptree_load (int *regen); RC_DEPTREE *_rc_deptree_load (int *regen);

View File

@ -32,6 +32,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
@ -48,84 +49,84 @@
extern const char *applet; extern const char *applet;
static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file) static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, int file)
{ {
struct stat st; struct stat st;
int fd;
memset (&st, 0, sizeof (st)); if (stat(path, &st)) {
if (stat (path, &st)) {
if (file) { if (file) {
int fd; einfo("%s: creating file", path);
einfo ("%s: creating file", path); if ((fd = open(path, O_CREAT)) == -1) {
if ((fd = open (path, O_CREAT)) == -1) { eerror("%s: open: %s", applet, strerror(errno));
eerror ("%s: open: %s", applet, strerror (errno)); return -1;
return (-1);
} }
close (fd); close (fd);
} else { } else {
einfo ("%s: creating directory", path); einfo("%s: creating directory", path);
if (! mode) if (! mode)
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
if (mkdir (path, mode)) { if (mkdir(path, mode)) {
eerror ("%s: mkdir: %s", applet, strerror (errno)); eerror("%s: mkdir: %s", applet, strerror (errno));
return (-1); return -1;
} }
mode = 0; mode = 0;
} }
} else { } else {
if ((file && S_ISDIR (st.st_mode)) || if ((file && S_ISDIR(st.st_mode)) ||
(! file && ! S_ISDIR (st.st_mode))) (! file && ! S_ISDIR(st.st_mode)))
{ {
if (file) if (file)
eerror ("%s: is a directory", path); eerror("%s: is a directory", path);
else else
eerror ("%s: is a file", path); eerror("%s: is a file", path);
return (-1); return -1;
} }
} }
if (mode && (st.st_mode & 0777) != mode) { if (mode && (st.st_mode & 0777) != mode) {
einfo ("%s: correcting mode", applet); einfo("%s: correcting mode", applet);
if (chmod (path, mode)) { if (chmod(path, mode)) {
eerror ("%s: chmod: %s", applet, strerror (errno)); eerror("%s: chmod: %s", applet, strerror(errno));
return (-1); return -1;
} }
} }
if (st.st_uid != uid || st.st_gid != gid) { if (st.st_uid != uid || st.st_gid != gid) {
if (st.st_dev || st.st_ino) if (st.st_dev || st.st_ino)
einfo ("%s: correcting owner", path); einfo("%s: correcting owner", path);
if (chown (path, uid, gid)) { if (chown(path, uid, gid)) {
eerror ("%s: chown: %s", applet, strerror (errno)); eerror("%s: chown: %s", applet, strerror(errno));
return (-1); return -1;
} }
} }
return (0); return 0;
} }
/* Based on busybox */ /* Based on busybox */
static int parse_mode (mode_t *mode, char *text) static int parse_mode (mode_t *mode, char *text)
{ {
char *p;
unsigned long l;
/* Check for a numeric mode */ /* Check for a numeric mode */
if ((*text - '0') < 8) { if ((*text - '0') < 8) {
char *p; l = strtoul(text, &p, 8);
unsigned long l = strtoul (text, &p, 8);
if (*p || l > 07777U) { if (*p || l > 07777U) {
errno = EINVAL; errno = EINVAL;
return (-1); return -1;
} }
*mode = (mode_t) l; *mode = (mode_t) l;
return (0); return 0;
} }
/* We currently don't check g+w type stuff */ /* We currently don't check g+w type stuff */
errno = EINVAL; errno = EINVAL;
return (-1); return -1;
} }
static int parse_owner (struct passwd **user, struct group **group, static int parse_owner(struct passwd **user, struct group **group,
const char *owner) const char *owner)
{ {
char *u = xstrdup (owner); char *u = xstrdup (owner);
@ -137,25 +138,25 @@ static int parse_owner (struct passwd **user, struct group **group,
*g++ = '\0'; *g++ = '\0';
if (user && *u) { if (user && *u) {
if (sscanf (u, "%d", &id) == 1) if (sscanf(u, "%d", &id) == 1)
*user = getpwuid ((uid_t) id); *user = getpwuid((uid_t) id);
else else
*user = getpwnam (u); *user = getpwnam(u);
if (! *user) if (! *user)
retval = -1; retval = -1;
} }
if (group && g && *g) { if (group && g && *g) {
if (sscanf (g, "%d", &id) == 1) if (sscanf(g, "%d", &id) == 1)
*group = getgrgid ((gid_t) id); *group = getgrgid((gid_t) id);
else else
*group = getgrnam (g); *group = getgrnam(g);
if (! *group) if (! *group)
retval = -1; retval = -1;
} }
free (u); free(u);
return (retval); return retval;
} }
#include "_usage.h" #include "_usage.h"
@ -177,7 +178,7 @@ static const char * const longopts_help[] = {
}; };
#include "_usage.c" #include "_usage.c"
int checkpath (int argc, char **argv) int checkpath(int argc, char **argv)
{ {
int opt; int opt;
uid_t uid = geteuid(); uid_t uid = geteuid();
@ -188,33 +189,31 @@ int checkpath (int argc, char **argv)
bool file = 0; bool file = 0;
int retval = EXIT_SUCCESS; int retval = EXIT_SUCCESS;
while ((opt = getopt_long (argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *) 0)) != -1)
{ {
switch (opt) { switch (opt) {
case 'd': case 'd':
file = 0; file = 0;
break; break;
case 'f': case 'f':
file = 1; file = 1;
break; break;
case 'm': case 'm':
if (parse_mode (&mode, optarg) != 0) if (parse_mode(&mode, optarg) != 0)
eerrorx ("%s: invalid mode `%s'", eerrorx("%s: invalid mode `%s'", applet, optarg);
applet, optarg); break;
break; case 'o':
case 'o': if (parse_owner(&pw, &gr, optarg) != 0)
if (parse_owner (&pw, &gr, optarg) != 0) eerrorx("%s: owner `%s' not found", applet, optarg);
eerrorx ("%s: owner `%s' not found", break;
applet, optarg);
break;
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
} }
if (optind >= argc) if (optind >= argc)
usage (EXIT_FAILURE); usage(EXIT_FAILURE);
if (pw) { if (pw) {
uid = pw->pw_uid; uid = pw->pw_uid;
@ -224,11 +223,11 @@ int checkpath (int argc, char **argv)
gid = gr->gr_gid; gid = gr->gr_gid;
while (optind < argc) { while (optind < argc) {
if (do_check (argv[optind], uid, gid, mode, file)) if (do_check(argv[optind], uid, gid, mode, file))
retval = EXIT_FAILURE; retval = EXIT_FAILURE;
optind++; optind++;
} }
exit (retval); exit(retval);
/* NOTREACHED */ /* NOTREACHED */
} }

View File

@ -30,6 +30,7 @@
*/ */
#include <sys/wait.h> #include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <stdio.h> #include <stdio.h>
@ -72,27 +73,26 @@
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
#ifdef HAVE_GETMNTENT #ifdef HAVE_GETMNTENT
static struct mntent *getmntfile (const char *file) static struct mntent *getmntfile(const char *file)
{ {
struct mntent *ent = NULL; struct mntent *ent;
FILE *fp; FILE *fp;
START_ENT; START_ENT;
while ((ent = getmntent (fp))) while ((ent = getmntent(fp)))
if (strcmp (file, ent->mnt_dir) == 0) if (strcmp(file, ent->mnt_dir) == 0)
break; break;
END_ENT; END_ENT;
return (ent); return ent;
} }
#endif #endif
extern const char *applet; extern const char *applet;
static int do_mount (struct ENT *ent) static int do_mount(struct ENT *ent)
{ {
char *argv[8]; char *argv[8];
pid_t pid; pid_t pid;
@ -100,29 +100,27 @@ static int do_mount (struct ENT *ent)
argv[0] = (char *) "mount"; argv[0] = (char *) "mount";
argv[1] = (char *) "-o"; argv[1] = (char *) "-o";
argv[2] = ENT_OPTS (*ent); argv[2] = ENT_OPTS(*ent);
argv[3] = (char *) "-t"; argv[3] = (char *) "-t";
argv[4] = ENT_TYPE (*ent); argv[4] = ENT_TYPE(*ent);
argv[5] = ENT_BLOCKDEVICE (*ent); argv[5] = ENT_BLOCKDEVICE(*ent);
argv[6] = ENT_FILE (*ent); argv[6] = ENT_FILE(*ent);
argv[7] = NULL; argv[7] = NULL;
switch (pid = vfork()) { switch (pid = vfork()) {
case -1: case -1:
eerrorx ("%s: vfork: %s", applet, eerrorx("%s: vfork: %s", applet, strerror(errno));
strerror (errno));
/* NOTREACHED */ /* NOTREACHED */
case 0: case 0:
execvp (argv[0], argv); execvp(argv[0], argv);
eerror ("%s: execv: %s", applet, eerror("%s: execv: %s", applet, strerror(errno));
strerror (errno));
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
/* NOTREACHED */ /* NOTREACHED */
default: default:
waitpid (pid, &status, 0); waitpid(pid, &status, 0);
if (WIFEXITED (status)) if (WIFEXITED(status))
return (WEXITSTATUS(status)); return WEXITSTATUS(status);
else else
return (-1); return -1;
/* NOTREACHED */ /* NOTREACHED */
} }
} }
@ -155,7 +153,7 @@ static const char * const longopts_help[] = {
#define OUTPUT_BLOCKDEV (1 << 5) #define OUTPUT_BLOCKDEV (1 << 5)
#define OUTPUT_MOUNT (1 << 6) #define OUTPUT_MOUNT (1 << 6)
int fstabinfo (int argc, char **argv) int fstabinfo(int argc, char **argv)
{ {
struct ENT *ent; struct ENT *ent;
int result = EXIT_SUCCESS; int result = EXIT_SUCCESS;
@ -163,8 +161,8 @@ int fstabinfo (int argc, char **argv)
int i; int i;
int opt; int opt;
int output = OUTPUT_FILE; int output = OUTPUT_FILE;
char **files = NULL; RC_STRINGLIST *files = rc_stringlist_new();
char *file; RC_STRING *file;
bool filtered = false; bool filtered = false;
#ifdef HAVE_GETMNTENT #ifdef HAVE_GETMNTENT
@ -172,125 +170,126 @@ int fstabinfo (int argc, char **argv)
#endif #endif
/* Ensure that we are only quiet when explicitly told to be */ /* Ensure that we are only quiet when explicitly told to be */
unsetenv ("EINFO_QUIET"); unsetenv("EINFO_QUIET");
while ((opt = getopt_long (argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *) 0)) != -1)
{ {
switch (opt) { switch (opt) {
case 'M': case 'M':
output = OUTPUT_MOUNT; output = OUTPUT_MOUNT;
break; break;
case 'b': case 'b':
output = OUTPUT_BLOCKDEV; output = OUTPUT_BLOCKDEV;
break; break;
case 'o': case 'o':
output = OUTPUT_OPTIONS; output = OUTPUT_OPTIONS;
break; break;
case 'm': case 'm':
output = OUTPUT_MOUNTARGS; output = OUTPUT_MOUNTARGS;
break; break;
case 'p': case 'p':
switch (optarg[0]) { switch (optarg[0]) {
case '=': case '=':
case '<': case '<':
case '>': case '>':
if (sscanf (optarg + 1, "%d", &i) != 1) if (sscanf(optarg + 1, "%d", &i) != 1)
eerrorx ("%s: invalid passno %s", argv[0], optarg + 1); eerrorx("%s: invalid passno %s",
argv[0], optarg + 1);
filtered = true;
START_ENT;
while ((ent = GET_ENT)) {
if (((optarg[0] == '=' && i == ENT_PASS (ent)) ||
(optarg[0] == '<' && i > ENT_PASS (ent)) ||
(optarg[0] == '>' && i < ENT_PASS (ent))) &&
strcmp (ENT_FILE (ent), "none") != 0)
rc_strlist_add (&files, ENT_FILE (ent));
}
END_ENT;
break;
default:
rc_strlist_add (&files, optarg);
output = OUTPUT_PASSNO;
break;
}
break;
case 't':
filtered = true; filtered = true;
while ((token = strsep (&optarg, ","))) { START_ENT;
START_ENT; while ((ent = GET_ENT)) {
while ((ent = GET_ENT)) if (((optarg[0] == '=' && i == ENT_PASS(ent)) ||
if (strcmp (token, ENT_TYPE (ent)) == 0) (optarg[0] == '<' && i > ENT_PASS(ent)) ||
rc_strlist_add (&files, ENT_FILE (ent)); (optarg[0] == '>' && i < ENT_PASS(ent))) &&
END_ENT; strcmp(ENT_FILE(ent), "none") != 0)
rc_stringlist_add(files, ENT_FILE(ent));
} }
END_ENT;
break; break;
case_RC_COMMON_GETOPT default:
rc_stringlist_add(files, optarg);
output = OUTPUT_PASSNO;
break;
}
break;
case 't':
filtered = true;
while ((token = strsep(&optarg, ","))) {
START_ENT;
while ((ent = GET_ENT))
if (strcmp(token, ENT_TYPE(ent)) == 0)
rc_stringlist_add(files, ENT_FILE(ent));
END_ENT;
}
break;
case_RC_COMMON_GETOPT
} }
} }
while (optind < argc) if (optind < argc) {
rc_strlist_add (&files, argv[optind++]); while (optind < argc)
rc_stringlist_add(files, argv[optind++]);
if (! files && ! filtered) { } else if (! filtered) {
START_ENT; START_ENT;
while ((ent = GET_ENT)) while ((ent = GET_ENT))
rc_strlist_add (&files, ENT_FILE (ent)); rc_stringlist_add(files, ENT_FILE(ent));
END_ENT; END_ENT;
if (! files) if (! TAILQ_FIRST(files))
eerrorx ("%s: emtpy fstab", argv[0]); eerrorx("%s: emtpy fstab", argv[0]);
} }
/* Ensure we always display something */ /* Ensure we always display something */
START_ENT; START_ENT;
STRLIST_FOREACH (files, file, i) { TAILQ_FOREACH(file, files, entries) {
if (! (ent = GET_ENT_FILE (file))) { if (! (ent = GET_ENT_FILE(file->value))) {
result = EXIT_FAILURE; result = EXIT_FAILURE;
continue; continue;
} }
/* No point in outputting if quiet */ /* No point in outputting if quiet */
if (rc_yesno (getenv ("EINFO_QUIET"))) if (rc_yesno(getenv("EINFO_QUIET")))
continue; continue;
switch (output) { switch (output) {
case OUTPUT_BLOCKDEV: case OUTPUT_BLOCKDEV:
printf ("%s\n", ENT_BLOCKDEVICE (ent)); printf("%s\n", ENT_BLOCKDEVICE(ent));
break; break;
case OUTPUT_MOUNT: case OUTPUT_MOUNT:
result += do_mount (ent); result += do_mount(ent);
break; break;
case OUTPUT_MOUNTARGS: case OUTPUT_MOUNTARGS:
printf ("-o %s -t %s %s %s\n", printf("-o %s -t %s %s %s\n",
ENT_OPTS (ent), ENT_OPTS(ent),
ENT_TYPE (ent), ENT_TYPE(ent),
ENT_BLOCKDEVICE (ent), ENT_BLOCKDEVICE(ent),
file); file->value);
break; break;
case OUTPUT_OPTIONS: case OUTPUT_OPTIONS:
printf ("%s\n", ENT_OPTS (ent)); printf("%s\n", ENT_OPTS(ent));
break; break;
case OUTPUT_FILE: case OUTPUT_FILE:
printf ("%s\n", file); printf("%s\n", file->value);
break; break;
case OUTPUT_PASSNO: case OUTPUT_PASSNO:
printf ("%d\n", ENT_PASS (ent)); printf("%d\n", ENT_PASS(ent));
break; break;
} }
} }
END_ENT; END_ENT;
rc_strlist_free (files); rc_stringlist_free(files);
exit (result); exit(result);
/* NOTREACHED */ /* NOTREACHED */
} }

View File

@ -47,16 +47,15 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <limits.h> #include <limits.h>
#include <regex.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <regex.h>
#include "builtins.h" #include "builtins.h"
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
extern const char *applet; extern const char *applet;
@ -80,93 +79,93 @@ struct args {
regex_t *skip_fstype_regex; regex_t *skip_fstype_regex;
regex_t *options_regex; regex_t *options_regex;
regex_t *skip_options_regex; regex_t *skip_options_regex;
char **mounts; RC_STRINGLIST *mounts;
mount_type mount_type; mount_type mount_type;
net_opts netdev; net_opts netdev;
}; };
static int process_mount (char ***list, struct args *args, static int process_mount(RC_STRINGLIST *list, struct args *args,
char *from, char *to, char *fstype, char *options, char *from, char *to, char *fstype, char *options,
int netdev) int netdev)
{ {
char *p; char *p;
RC_STRING *s;
errno = ENOENT; errno = ENOENT;
#ifdef __linux__ #ifdef __linux__
/* Skip the really silly rootfs */ /* Skip the really silly rootfs */
if (strcmp (fstype, "rootfs") == 0) if (strcmp(fstype, "rootfs") == 0)
return (-1); return -1;
#endif #endif
if (args->netdev == net_yes && (netdev != -1 || args->mounts)) { if (args->netdev == net_yes &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 0) if (netdev != 0)
return (1); return 1;
} else if (args->netdev == net_no && (netdev != -1 || args->mounts)) { } else if (args->netdev == net_no &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 1) if (netdev != 1)
return (1); return 1;
} else { } else {
if (args->node_regex && if (args->node_regex &&
regexec (args->node_regex, from, 0, NULL, 0) != 0) regexec(args->node_regex, from, 0, NULL, 0) != 0)
return (1); return 1;
if (args->skip_node_regex && if (args->skip_node_regex &&
regexec (args->skip_node_regex, from, 0, NULL, 0) == 0) regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
return (1); return 1;
if (args->fstype_regex && if (args->fstype_regex &&
regexec (args->fstype_regex, fstype, 0, NULL, 0) != 0) regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
return (-1); return -1;
if (args->skip_fstype_regex && if (args->skip_fstype_regex &&
regexec (args->skip_fstype_regex, fstype, 0, NULL, 0) == 0) regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return (-1); return -1;
if (args->options_regex && if (args->options_regex &&
regexec (args->options_regex, options, 0, NULL, 0) != 0) regexec(args->options_regex, options, 0, NULL, 0) != 0)
return (-1); return -1;
if (args->skip_options_regex && if (args->skip_options_regex &&
regexec (args->skip_options_regex, options, 0, NULL, 0) == 0) regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
return (-1); return -1;
} }
if (args->mounts) { if (TAILQ_FIRST(args->mounts)) {
bool found = false; TAILQ_FOREACH(s, args->mounts, entries)
int j; if (strcmp(s->value, to) == 0)
char *mnt;
STRLIST_FOREACH (args->mounts, mnt, j)
if (strcmp (mnt, to) == 0) {
found = true;
break; break;
} if (! s)
if (! found) return -1;
return (-1);
} }
switch (args->mount_type) { switch (args->mount_type) {
case mount_from: case mount_from:
p = from; p = from;
break; break;
case mount_to: case mount_to:
p = to; p = to;
break; break;
case mount_fstype: case mount_fstype:
p = fstype; p = fstype;
break; break;
case mount_options: case mount_options:
p = options; p = options;
break; break;
default: default:
p = NULL; p = NULL;
errno = EINVAL; errno = EINVAL;
break; break;
} }
if (p) { if (p) {
errno = 0; errno = 0;
rc_strlist_addsortc (list, p); rc_stringlist_add(list, p);
return (0); return 0;
} }
return (-1); return -1;
} }
#ifdef BSD #ifdef BSD
@ -212,70 +211,73 @@ static struct opt {
{ 0, NULL } { 0, NULL }
}; };
static char **find_mounts (struct args *args) static RC_STRINGLIST *find_mounts(struct args *args)
{ {
struct statfs *mnts; struct statfs *mnts;
int nmnts; int nmnts;
int i; int i;
char **list = NULL; RC_STRINGLIST *list;
char *options = NULL; char *options = NULL;
uint64_t flags; uint64_t flags;
struct opt *o; struct opt *o;
int netdev;
char *tmp;
size_t l;
if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0) if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
eerrorx ("getmntinfo: %s", strerror (errno)); eerrorx("getmntinfo: %s", strerror (errno));
list = rc_stringlist_new();
for (i = 0; i < nmnts; i++) { for (i = 0; i < nmnts; i++) {
int netdev = 0; netdev = 0;
flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK; flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK;
for (o = optnames; flags && o->o_opt; o++) { for (o = optnames; flags && o->o_opt; o++) {
if (flags & o->o_opt) { if (flags & o->o_opt) {
if (o->o_opt == MNT_LOCAL) if (o->o_opt == MNT_LOCAL)
netdev = 1; netdev = 1;
if (! options) if (! options)
options = xstrdup (o->o_name); options = xstrdup(o->o_name);
else { else {
char *tmp = NULL; l = strlen(options) + strlen(o->o_name) + 2;
size_t l = strlen (options) + strlen (o->o_name) + 2; tmp = xmalloc(sizeof (char) * l);
tmp = xmalloc (sizeof (char) * l); snprintf(tmp, l, "%s,%s", options, o->o_name);
snprintf (tmp, l, "%s,%s", options, o->o_name); free(options);
free (options);
options = tmp; options = tmp;
} }
} }
flags &= ~o->o_opt; flags &= ~o->o_opt;
} }
process_mount (&list, args, process_mount(list, args,
mnts[i].f_mntfromname, mnts[i].f_mntfromname,
mnts[i].f_mntonname, mnts[i].f_mntonname,
mnts[i].f_fstypename, mnts[i].f_fstypename,
options, options,
netdev); netdev);
free (options); free(options);
options = NULL; options = NULL;
} }
return (list); return list;
} }
#elif defined (__linux__) #elif defined (__linux__)
static struct mntent *getmntfile (const char *file) static struct mntent *getmntfile(const char *file)
{ {
struct mntent *ent = NULL; struct mntent *ent = NULL;
FILE *fp; FILE *fp;
fp = setmntent ("/etc/fstab", "r"); fp = setmntent("/etc/fstab", "r");
while ((ent = getmntent (fp))) while ((ent = getmntent(fp)))
if (strcmp (file, ent->mnt_dir) == 0) if (strcmp(file, ent->mnt_dir) == 0)
break; break;
endmntent (fp); endmntent(fp);
return (ent); return ent;
} }
static char **find_mounts (struct args *args) static RC_STRINGLIST *find_mounts(struct args *args)
{ {
FILE *fp; FILE *fp;
char *buffer; char *buffer;
@ -284,52 +286,54 @@ static char **find_mounts (struct args *args)
char *to; char *to;
char *fst; char *fst;
char *opts; char *opts;
char **list = NULL;
struct mntent *ent; struct mntent *ent;
int netdev; int netdev;
RC_STRINGLIST *list;
if ((fp = fopen ("/proc/mounts", "r")) == NULL) if ((fp = fopen("/proc/mounts", "r")) == NULL)
eerrorx ("getmntinfo: %s", strerror (errno)); eerrorx("getmntinfo: %s", strerror(errno));
buffer = xmalloc (sizeof (char) * PATH_MAX * 3); list = rc_stringlist_new();
while (fgets (buffer, PATH_MAX * 3, fp)) {
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
while (fgets(buffer, PATH_MAX * 3, fp)) {
netdev = -1; netdev = -1;
p = buffer; p = buffer;
from = strsep (&p, " "); from = strsep(&p, " ");
to = strsep (&p, " "); to = strsep(&p, " ");
fst = strsep (&p, " "); fst = strsep(&p, " ");
opts = strsep (&p, " "); opts = strsep(&p, " ");
if ((ent = getmntfile (to))) { if ((ent = getmntfile(to))) {
if (strstr (ent->mnt_opts, "_netdev")) if (strstr(ent->mnt_opts, "_netdev"))
netdev = 0; netdev = 0;
} }
process_mount (&list, args, from, to, fst, opts, netdev); process_mount(list, args, from, to, fst, opts, netdev);
} }
free (buffer); free(buffer);
fclose (fp); fclose(fp);
return (list); return list;
} }
#else #else
# error "Operating system not supported!" # error "Operating system not supported!"
#endif #endif
static regex_t *get_regex (const char *string) static regex_t *get_regex(const char *string)
{ {
regex_t *reg = xmalloc (sizeof (*reg)); regex_t *reg = xmalloc(sizeof (*reg));
int result; int result;
char buffer[256]; char buffer[256];
if ((result = regcomp (reg, string, REG_EXTENDED | REG_NOSUB)) != 0) if ((result = regcomp(reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
{ {
regerror (result, reg, buffer, sizeof (buffer)); regerror(result, reg, buffer, sizeof(buffer));
eerrorx ("%s: invalid regex `%s'", applet, buffer); eerrorx("%s: invalid regex `%s'", applet, buffer);
} }
return (reg); return reg;
} }
#include "_usage.h" #include "_usage.h"
@ -347,7 +351,7 @@ static const struct option longopts[] = {
{ "options", 0, NULL, 'i'}, { "options", 0, NULL, 'i'},
{ "fstype", 0, NULL, 's'}, { "fstype", 0, NULL, 's'},
{ "node", 0, NULL, 't'}, { "node", 0, NULL, 't'},
{ "netdev", 0, NULL, 'e'}, { "netdev", 0, NULL, 'e'},
{ "nonetdev", 0, NULL, 'E'}, { "nonetdev", 0, NULL, 'E'},
longopts_COMMON longopts_COMMON
}; };
@ -369,112 +373,113 @@ static const char * const longopts_help[] = {
}; };
#include "_usage.c" #include "_usage.c"
int mountinfo (int argc, char **argv) int mountinfo(int argc, char **argv)
{ {
int i;
struct args args; struct args args;
regex_t *point_regex = NULL; regex_t *point_regex = NULL;
regex_t *skip_point_regex = NULL; regex_t *skip_point_regex = NULL;
char **nodes = NULL; RC_STRINGLIST *nodes;
char *n; RC_STRING *s;
int opt; int opt;
int result; int result;
bool quiet; bool quiet;
/* Ensure that we are only quiet when explicitly told to be */ /* Ensure that we are only quiet when explicitly told to be */
unsetenv ("EINFO_QUIET"); unsetenv("EINFO_QUIET");
#define DO_REG(_var) \ #define DO_REG(_var) \
if (_var) free (_var); \ if (_var) free(_var); \
_var = get_regex (optarg); _var = get_regex(optarg);
#define REG_FREE(_var) \ #define REG_FREE(_var) \
if (_var) { regfree (_var); free (_var); } if (_var) { regfree(_var); free(_var); }
memset (&args, 0, sizeof (args)); memset (&args, 0, sizeof(args));
args.mount_type = mount_to; args.mount_type = mount_to;
args.netdev = net_ignore; args.netdev = net_ignore;
args.mounts = rc_stringlist_new();
while ((opt = getopt_long (argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *) 0)) != -1)
{ {
switch (opt) { switch (opt) {
case 'e': case 'e':
args.netdev = net_yes; args.netdev = net_yes;
break; break;
case 'E': case 'E':
args.netdev = net_no; args.netdev = net_no;
break; break;
case 'f': case 'f':
DO_REG (args.fstype_regex); DO_REG(args.fstype_regex);
break; break;
case 'F': case 'F':
DO_REG (args.skip_fstype_regex); DO_REG(args.skip_fstype_regex);
break; break;
case 'n': case 'n':
DO_REG (args.node_regex); DO_REG(args.node_regex);
break; break;
case 'N': case 'N':
DO_REG (args.skip_node_regex); DO_REG(args.skip_node_regex);
break; break;
case 'o': case 'o':
DO_REG (args.options_regex); DO_REG(args.options_regex);
break; break;
case 'O': case 'O':
DO_REG (args.skip_options_regex); DO_REG(args.skip_options_regex);
break; break;
case 'p': case 'p':
DO_REG (point_regex); DO_REG(point_regex);
break; break;
case 'P': case 'P':
DO_REG (skip_point_regex); DO_REG(skip_point_regex);
break; break;
case 'i': case 'i':
args.mount_type = mount_options; args.mount_type = mount_options;
break; break;
case 's': case 's':
args.mount_type = mount_fstype; args.mount_type = mount_fstype;
break; break;
case 't': case 't':
args.mount_type = mount_from; args.mount_type = mount_from;
break; break;
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
} }
while (optind < argc) { while (optind < argc) {
if (argv[optind][0] != '/') if (argv[optind][0] != '/')
eerrorx ("%s: `%s' is not a mount point", argv[0], argv[optind]); eerrorx("%s: `%s' is not a mount point", argv[0], argv[optind]);
rc_strlist_add (&args.mounts, argv[optind++]); rc_stringlist_add(args.mounts, argv[optind++]);
} }
nodes = find_mounts(&args);
rc_stringlist_free(args.mounts);
rc_stringlist_sort(&nodes);
nodes = find_mounts (&args); REG_FREE(args.fstype_regex);
REG_FREE(args.skip_fstype_regex);
REG_FREE (args.fstype_regex); REG_FREE(args.node_regex);
REG_FREE (args.skip_fstype_regex); REG_FREE(args.skip_node_regex);
REG_FREE (args.node_regex); REG_FREE(args.options_regex);
REG_FREE (args.skip_node_regex); REG_FREE(args.skip_options_regex);
REG_FREE (args.options_regex);
REG_FREE (args.skip_options_regex);
rc_strlist_reverse (nodes);
result = EXIT_FAILURE; result = EXIT_FAILURE;
quiet = rc_yesno (getenv ("EINFO_QUIET")); quiet = rc_yesno(getenv("EINFO_QUIET"));
STRLIST_FOREACH (nodes, n, i) { TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) {
if (point_regex && regexec (point_regex, n, 0, NULL, 0) != 0) if (point_regex &&
regexec(point_regex, s->value, 0, NULL, 0) != 0)
continue; continue;
if (skip_point_regex && regexec (skip_point_regex, n, 0, NULL, 0) == 0) if (skip_point_regex &&
regexec(skip_point_regex, s->value, 0, NULL, 0) == 0)
continue; continue;
if (! quiet) if (! quiet)
printf ("%s\n", n); printf("%s\n", s->value);
result = EXIT_SUCCESS; result = EXIT_SUCCESS;
} }
rc_strlist_free (nodes); rc_stringlist_free(nodes);
REG_FREE (point_regex); REG_FREE(point_regex);
REG_FREE (skip_point_regex); REG_FREE(skip_point_regex);
exit (result); exit(result);
/* NOTREACHED */ /* NOTREACHED */
} }

View File

@ -35,6 +35,7 @@
#define SYSLOG_NAMES #define SYSLOG_NAMES
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <inttypes.h> #include <inttypes.h>
@ -49,26 +50,25 @@
#include "builtins.h" #include "builtins.h"
#include "einfo.h" #include "einfo.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
/* Applet is first parsed in rc.c - no point in doing it again */ /* Applet is first parsed in rc.c - no point in doing it again */
extern const char *applet; extern const char *applet;
static int syslog_decode (char *name, CODE *codetab) static int syslog_decode(char *name, CODE *codetab)
{ {
CODE *c; CODE *c;
if (isdigit ((int) *name)) if (isdigit((int) *name))
return (atoi (name)); return atoi(name);
for (c = codetab; c->c_name; c++) for (c = codetab; c->c_name; c++)
if (! strcasecmp (name, c->c_name)) if (! strcasecmp(name, c->c_name))
return (c->c_val); return c->c_val;
return (-1); return -1;
} }
static int do_e (int argc, char **argv) static int do_e(int argc, char **argv)
{ {
int retval = EXIT_SUCCESS; int retval = EXIT_SUCCESS;
int i; int i;
@ -82,42 +82,42 @@ static int do_e (int argc, char **argv)
argc--; argc--;
argv++; argv++;
if (strcmp (applet, "eval_ecolors") == 0) { if (strcmp(applet, "eval_ecolors") == 0) {
printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n", printf("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
ecolor (ECOLOR_GOOD), ecolor(ECOLOR_GOOD),
ecolor (ECOLOR_WARN), ecolor(ECOLOR_WARN),
ecolor (ECOLOR_BAD), ecolor(ECOLOR_BAD),
ecolor (ECOLOR_HILITE), ecolor(ECOLOR_HILITE),
ecolor (ECOLOR_BRACKET), ecolor(ECOLOR_BRACKET),
ecolor (ECOLOR_NORMAL)); ecolor(ECOLOR_NORMAL));
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
if (argc > 0) { if (argc > 0) {
if (strcmp (applet, "eend") == 0 || if (strcmp(applet, "eend") == 0 ||
strcmp (applet, "ewend") == 0 || strcmp(applet, "ewend") == 0 ||
strcmp (applet, "veend") == 0 || strcmp(applet, "veend") == 0 ||
strcmp (applet, "vweend") == 0) strcmp(applet, "vweend") == 0)
{ {
errno = 0; errno = 0;
retval = (int) strtoimax (argv[0], NULL, 0); retval = (int) strtoimax(argv[0], NULL, 0);
if (errno != 0) if (errno != 0)
retval = EXIT_FAILURE; retval = EXIT_FAILURE;
else { else {
argc--; argc--;
argv++; argv++;
} }
} else if (strcmp (applet, "esyslog") == 0 || } else if (strcmp(applet, "esyslog") == 0 ||
strcmp (applet, "elog") == 0) { strcmp(applet, "elog") == 0) {
char *dot = strchr (argv[0], '.'); p = strchr(argv[0], '.');
if ((level = syslog_decode (dot + 1, prioritynames)) == -1) if ((level = syslog_decode(p + 1, prioritynames)) == -1)
eerrorx ("%s: invalid log level `%s'", applet, argv[0]); eerrorx("%s: invalid log level `%s'", applet, argv[0]);
if (argc < 3) if (argc < 3)
eerrorx ("%s: not enough arguments", applet); eerrorx("%s: not enough arguments", applet);
unsetenv ("EINFO_LOG"); unsetenv("EINFO_LOG");
setenv ("EINFO_LOG", argv[1], 1); setenv("EINFO_LOG", argv[1], 1);
argc -= 2; argc -= 2;
argv += 2; argv += 2;
@ -126,16 +126,17 @@ static int do_e (int argc, char **argv)
if (argc > 0) { if (argc > 0) {
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
l += strlen (argv[i]) + 1; l += strlen(argv[i]) + 1;
message = xmalloc (l); message = xmalloc(l);
p = message; p = message;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (i > 0) if (i > 0)
*p++ = ' '; *p++ = ' ';
memcpy (p, argv[i], strlen (argv[i])); l = strlen(argv[i]);
p += strlen (argv[i]); memcpy(p, argv[i], l);
p += l;
} }
*p = 0; *p = 0;
} }
@ -143,300 +144,302 @@ static int do_e (int argc, char **argv)
if (! message) if (! message)
fmt = ""; fmt = "";
if (strcmp (applet, "einfo") == 0) if (strcmp(applet, "einfo") == 0)
einfo (fmt, message); einfo(fmt, message);
else if (strcmp (applet, "einfon") == 0) else if (strcmp(applet, "einfon") == 0)
einfon (fmt, message); einfon(fmt, message);
else if (strcmp (applet, "ewarn") == 0) else if (strcmp(applet, "ewarn") == 0)
ewarn (fmt, message); ewarn(fmt, message);
else if (strcmp (applet, "ewarnn") == 0) else if (strcmp(applet, "ewarnn") == 0)
ewarnn (fmt, message); ewarnn(fmt, message);
else if (strcmp (applet, "eerror") == 0) { else if (strcmp(applet, "eerror") == 0) {
eerror (fmt, message); eerror(fmt, message);
retval = 1; retval = 1;
} else if (strcmp (applet, "eerrorn") == 0) { } else if (strcmp(applet, "eerrorn") == 0) {
eerrorn (fmt, message); eerrorn(fmt, message);
retval = 1; retval = 1;
} else if (strcmp (applet, "ebegin") == 0) } else if (strcmp(applet, "ebegin") == 0)
ebegin (fmt, message); ebegin(fmt, message);
else if (strcmp (applet, "eend") == 0) else if (strcmp(applet, "eend") == 0)
eend (retval, fmt, message); eend(retval, fmt, message);
else if (strcmp (applet, "ewend") == 0) else if (strcmp(applet, "ewend") == 0)
ewend (retval, fmt, message); ewend(retval, fmt, message);
else if (strcmp (applet, "esyslog") == 0) else if (strcmp(applet, "esyslog") == 0)
elog (level, fmt, message); elog(level, fmt, message);
else if (strcmp (applet, "veinfo") == 0) else if (strcmp(applet, "veinfo") == 0)
einfov (fmt, message); einfov(fmt, message);
else if (strcmp (applet, "veinfon") == 0) else if (strcmp(applet, "veinfon") == 0)
einfovn (fmt, message); einfovn(fmt, message);
else if (strcmp (applet, "vewarn") == 0) else if (strcmp(applet, "vewarn") == 0)
ewarnv (fmt, message); ewarnv(fmt, message);
else if (strcmp (applet, "vewarnn") == 0) else if (strcmp(applet, "vewarnn") == 0)
ewarnvn (fmt, message); ewarnvn(fmt, message);
else if (strcmp (applet, "vebegin") == 0) else if (strcmp(applet, "vebegin") == 0)
ebeginv (fmt, message); ebeginv(fmt, message);
else if (strcmp (applet, "veend") == 0) else if (strcmp(applet, "veend") == 0)
eendv (retval, fmt, message); eendv(retval, fmt, message);
else if (strcmp (applet, "vewend") == 0) else if (strcmp(applet, "vewend") == 0)
ewendv (retval, fmt, message); ewendv(retval, fmt, message);
else if (strcmp (applet, "eindent") == 0) else if (strcmp(applet, "eindent") == 0)
eindent (); eindent();
else if (strcmp (applet, "eoutdent") == 0) else if (strcmp(applet, "eoutdent") == 0)
eoutdent (); eoutdent();
else if (strcmp (applet, "veindent") == 0) else if (strcmp(applet, "veindent") == 0)
eindentv (); eindentv();
else if (strcmp (applet, "veoutdent") == 0) else if (strcmp(applet, "veoutdent") == 0)
eoutdentv (); eoutdentv();
else { else {
eerror ("%s: unknown applet", applet); eerror("%s: unknown applet", applet);
retval = EXIT_FAILURE; retval = EXIT_FAILURE;
} }
free (message); free(message);
return (retval); return retval;
} }
static int do_service (int argc, char **argv) static int do_service(int argc, char **argv)
{ {
bool ok = false; bool ok = false;
char *service = NULL; char *service = NULL;
int idx = 0;
char *d[] = { NULL, NULL };
if (argc > 1) if (argc > 1)
service = argv[1]; service = argv[1];
else else
service = getenv ("SVCNAME"); service = getenv("SVCNAME");
if (! service || *service == '\0') if (! service || *service == '\0')
eerrorx ("%s: no service specified", applet); eerrorx("%s: no service specified", applet);
if (strcmp (applet, "service_started") == 0) if (strcmp(applet, "service_started") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STARTED); ok = (rc_service_state(service) & RC_SERVICE_STARTED);
else if (strcmp (applet, "service_stopped") == 0) else if (strcmp(applet, "service_stopped") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STOPPED); ok = (rc_service_state(service) & RC_SERVICE_STOPPED);
else if (strcmp (applet, "service_inactive") == 0) else if (strcmp(applet, "service_inactive") == 0)
ok = (rc_service_state (service) & RC_SERVICE_INACTIVE); ok = (rc_service_state(service) & RC_SERVICE_INACTIVE);
else if (strcmp (applet, "service_starting") == 0) else if (strcmp(applet, "service_starting") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STARTING); ok = (rc_service_state(service) & RC_SERVICE_STARTING);
else if (strcmp (applet, "service_stopping") == 0) else if (strcmp(applet, "service_stopping") == 0)
ok = (rc_service_state (service) & RC_SERVICE_STOPPING); ok = (rc_service_state(service) & RC_SERVICE_STOPPING);
else if (strcmp (applet, "service_coldplugged") == 0) else if (strcmp(applet, "service_coldplugged") == 0)
ok = (rc_service_state (service) & RC_SERVICE_COLDPLUGGED); ok = (rc_service_state(service) & RC_SERVICE_COLDPLUGGED);
else if (strcmp (applet, "service_wasinactive") == 0) else if (strcmp(applet, "service_wasinactive") == 0)
ok = (rc_service_state (service) & RC_SERVICE_WASINACTIVE); ok = (rc_service_state(service) & RC_SERVICE_WASINACTIVE);
else if (strcmp (applet, "service_started_daemon") == 0) { else if (strcmp(applet, "service_started_daemon") == 0) {
int idx = 0; d[0] = argv[1];
char *d[] = { argv[1], NULL };
service = getenv ("SVCNAME"); service = getenv("SVCNAME");
if (argc > 3) { if (argc > 3) {
service = argv[1]; service = argv[1];
d[0] = argv[2]; d[0] = argv[2];
sscanf (argv[3], "%d", &idx); sscanf(argv[3], "%d", &idx);
} else if (argc == 3) { } else if (argc == 3) {
if (sscanf (argv[2], "%d", &idx) != 1) { if (sscanf(argv[2], "%d", &idx) != 1) {
service = argv[1]; service = argv[1];
*d = argv[2]; d[0] = argv[2];
} }
} }
ok = rc_service_started_daemon (service, ok = rc_service_started_daemon(service,
(const char * const *)d, idx); (const char * const *)d, idx);
} else } else
eerrorx ("%s: unknown applet", applet); eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE); return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} }
static int do_mark_service (int argc, char **argv) static int do_mark_service(int argc, char **argv)
{ {
bool ok = false; bool ok = false;
char *svcname = getenv ("SVCNAME"); char *svcname = getenv("SVCNAME");
char *service = NULL; char *service = NULL;
char *runscript_pid;
char *mtime;
pid_t pid;
size_t l;
if (argc > 1) if (argc > 1)
service = argv[1]; service = argv[1];
else else
service = getenv ("SVCNAME"); service = getenv("SVCNAME");
if (! service || *service == '\0') if (! service || *service == '\0')
eerrorx ("%s: no service specified", applet); eerrorx("%s: no service specified", applet);
if (strcmp (applet, "mark_service_started") == 0) if (strcmp(applet, "mark_service_started") == 0)
ok = rc_service_mark (service, RC_SERVICE_STARTED); ok = rc_service_mark(service, RC_SERVICE_STARTED);
else if (strcmp (applet, "mark_service_stopped") == 0) else if (strcmp(applet, "mark_service_stopped") == 0)
ok = rc_service_mark (service, RC_SERVICE_STOPPED); ok = rc_service_mark(service, RC_SERVICE_STOPPED);
else if (strcmp (applet, "mark_service_inactive") == 0) else if (strcmp(applet, "mark_service_inactive") == 0)
ok = rc_service_mark (service, RC_SERVICE_INACTIVE); ok = rc_service_mark(service, RC_SERVICE_INACTIVE);
else if (strcmp (applet, "mark_service_starting") == 0) else if (strcmp(applet, "mark_service_starting") == 0)
ok = rc_service_mark (service, RC_SERVICE_STARTING); ok = rc_service_mark(service, RC_SERVICE_STARTING);
else if (strcmp (applet, "mark_service_stopping") == 0) else if (strcmp(applet, "mark_service_stopping") == 0)
ok = rc_service_mark (service, RC_SERVICE_STOPPING); ok = rc_service_mark(service, RC_SERVICE_STOPPING);
else if (strcmp (applet, "mark_service_coldplugged") == 0) else if (strcmp(applet, "mark_service_coldplugged") == 0)
ok = rc_service_mark (service, RC_SERVICE_COLDPLUGGED); ok = rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
else if (strcmp (applet, "mark_service_failed") == 0) else if (strcmp(applet, "mark_service_failed") == 0)
ok = rc_service_mark (service, RC_SERVICE_FAILED); ok = rc_service_mark(service, RC_SERVICE_FAILED);
else else
eerrorx ("%s: unknown applet", applet); eerrorx("%s: unknown applet", applet);
/* If we're marking ourselves then we need to inform our parent runscript /* 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 */ process so they do not mark us based on our exit code */
if (ok && svcname && strcmp (svcname, service) == 0) { if (ok && svcname && strcmp(svcname, service) == 0) {
char *runscript_pid = getenv ("RC_RUNSCRIPT_PID"); runscript_pid = getenv("RC_RUNSCRIPT_PID");
char *mtime; if (runscript_pid && sscanf(runscript_pid, "%d", &pid) == 1)
pid_t pid = 0; if (kill(pid, SIGHUP) != 0)
size_t l; eerror("%s: failed to signal parent %d: %s",
applet, pid, strerror(errno));
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 exclusive time test. This ensures that it's not /* Remove the exclusive time test. This ensures that it's not
in control as well */ in control as well */
l = strlen (RC_SVCDIR "exclusive") + l = strlen(RC_SVCDIR "exclusive") + strlen(svcname) +
strlen (svcname) + strlen(runscript_pid) + 4;
strlen (runscript_pid) + mtime = xmalloc(l);
4; snprintf(mtime, l, RC_SVCDIR "exclusive/%s.%s",
mtime = xmalloc (l); svcname, runscript_pid);
snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s", if (exists(mtime) && unlink(mtime) != 0)
svcname, runscript_pid); eerror("%s: unlink: %s", applet, strerror(errno));
if (exists (mtime) && unlink (mtime) != 0) free(mtime);
eerror ("%s: unlink: %s", applet, strerror (errno));
free (mtime);
} }
return (ok ? EXIT_SUCCESS : EXIT_FAILURE); return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} }
static int do_value (int argc, char **argv) static int do_value(int argc, char **argv)
{ {
bool ok = false; bool ok = false;
char *service = getenv ("SVCNAME"); char *service = getenv("SVCNAME");
char *option;
if (! service) if (! service)
eerrorx ("%s: no service specified", applet); eerrorx("%s: no service specified", applet);
if (argc < 2 || ! argv[1] || *argv[1] == '\0') if (argc < 2 || ! argv[1] || *argv[1] == '\0')
eerrorx ("%s: no option specified", applet); eerrorx("%s: no option specified", applet);
if (strcmp (applet, "service_get_value") == 0 || if (strcmp(applet, "service_get_value") == 0 ||
strcmp (applet, "get_options") == 0) strcmp(applet, "get_options") == 0)
{ {
char *option = rc_service_value_get (service, argv[1]); option = rc_service_value_get(service, argv[1]);
if (option) { if (option) {
printf ("%s", option); printf("%s", option);
free (option); free(option);
ok = true; ok = true;
} }
} else if (strcmp (applet, "service_set_value") == 0 || } else if (strcmp(applet, "service_set_value") == 0 ||
strcmp (applet, "save_options") == 0) strcmp(applet, "save_options") == 0)
ok = rc_service_value_set (service, argv[1], argv[2]); ok = rc_service_value_set(service, argv[1], argv[2]);
else else
eerrorx ("%s: unknown applet", applet); eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE); return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} }
static int do_shell_var (int argc, char **argv) static int do_shell_var(int argc, char **argv)
{ {
int i; int i;
char *p;
int c;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
char *p = argv[i]; p = argv[i];
if (i != 1) if (i != 1)
putchar (' '); putchar(' ');
while (*p) { while (*p) {
char c = *p++; c = *p++;
if (! isalnum ((int) c)) if (! isalnum(c))
c = '_'; c = '_';
putchar (c); putchar(c);
} }
} }
putchar ('\n'); putchar('\n');
return (EXIT_SUCCESS); return EXIT_SUCCESS;
} }
void run_applets (int argc, char **argv) void run_applets(int argc, char **argv)
{ {
int i = 2;
bool match = false;
char *p;
pid_t pid = 0;
/* These are designed to be applications in their own right */ /* These are designed to be applications in their own right */
if (strcmp (applet, "fstabinfo") == 0) if (strcmp(applet, "fstabinfo") == 0)
exit (fstabinfo (argc, argv)); exit(fstabinfo(argc, argv));
else if (strcmp (applet, "mountinfo") == 0) else if (strcmp(applet, "mountinfo") == 0)
exit (mountinfo (argc, argv)); exit(mountinfo(argc, argv));
else if (strcmp (applet, "rc-depend") == 0) else if (strcmp(applet, "rc-depend") == 0)
exit (rc_depend (argc, argv)); exit(rc_depend(argc, argv));
else if (strcmp (applet, "rc-status") == 0) else if (strcmp(applet, "rc-status") == 0)
exit (rc_status (argc, argv)); exit(rc_status(argc, argv));
else if (strcmp (applet, "rc-update") == 0 || else if (strcmp(applet, "rc-update") == 0 ||
strcmp (applet, "update-rc") == 0) strcmp(applet, "update-rc") == 0)
exit (rc_update (argc, argv)); exit(rc_update(argc, argv));
else if (strcmp (applet, "runscript") == 0) else if (strcmp(applet, "runscript") == 0)
exit (runscript (argc, argv)); exit(runscript(argc, argv));
else if (strcmp (applet, "start-stop-daemon") == 0) else if (strcmp(applet, "start-stop-daemon") == 0)
exit (start_stop_daemon (argc, argv)); exit(start_stop_daemon(argc, argv));
else if (strcmp (applet, "checkpath") == 0) else if (strcmp (applet, "checkpath") == 0)
exit (checkpath (argc, argv)); exit(checkpath(argc, argv));
/* These could also be applications in their own right */ /* These could also be applications in their own right */
if (strcmp (applet, "shell_var") == 0) if (strcmp(applet, "shell_var") == 0)
exit (do_shell_var (argc, argv)); exit(do_shell_var(argc, argv));
if (strcmp (applet, "is_newer_than") == 0 || if (strcmp(applet, "is_newer_than") == 0 ||
strcmp (applet, "is_older_than") == 0) strcmp(applet, "is_older_than") == 0)
{ {
bool match = false;
int i = 2;
if (argc < 3) if (argc < 3)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
if (strcmp (applet, "is_newer_than") == 0) if (strcmp(applet, "is_newer_than") == 0)
match = true; match = true;
while (i < argc) { while (i < argc) {
if (rc_newer_than (argv[1], argv[i++]) != match) if (rc_newer_than(argv[1], argv[i++]) != match)
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
}; };
if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e')) if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
exit (do_e (argc, argv)); exit(do_e(argc, argv));
/* These are purely for init scripts and do not make sense as /* These are purely for init scripts and do not make sense as
* anything else */ * anything else */
if (strcmp (applet, "service_get_value") == 0 || if (strcmp(applet, "service_get_value") == 0 ||
strcmp (applet, "service_set_value") == 0 || strcmp(applet, "service_set_value") == 0 ||
strcmp (applet, "get_options") == 0 || strcmp(applet, "get_options") == 0 ||
strcmp (applet, "save_options") == 0) strcmp(applet, "save_options") == 0)
exit (do_value (argc, argv)); exit(do_value(argc, argv));
if (strncmp (applet, "service_", strlen ("service_")) == 0) if (strncmp(applet, "service_", strlen("service_")) == 0)
exit (do_service (argc, argv)); exit(do_service(argc, argv));
if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0) if (strncmp(applet, "mark_service_", strlen("mark_service_")) == 0)
exit (do_mark_service (argc, argv)); exit(do_mark_service(argc, argv));
if (strcmp (applet, "is_runlevel_start") == 0) if (strcmp(applet, "is_runlevel_start") == 0)
exit (rc_runlevel_starting () ? 0 : 1); exit(rc_runlevel_starting() ? 0 : 1);
else if (strcmp (applet, "is_runlevel_stop") == 0) else if (strcmp (applet, "is_runlevel_stop") == 0)
exit (rc_runlevel_stopping () ? 0 : 1); exit(rc_runlevel_stopping() ? 0 : 1);
if (strcmp (applet, "rc-abort") == 0) { if (strcmp(applet, "rc-abort") == 0) {
char *p = getenv ("RC_PID"); p = getenv("RC_PID");
pid_t pid = 0; if (p && sscanf(p, "%d", &pid) == 1) {
if (kill(pid, SIGUSR1) != 0)
if (p && sscanf (p, "%d", &pid) == 1) { eerrorx("rc-abort: failed to signal parent %d: %s",
if (kill (pid, SIGUSR1) != 0) pid, strerror(errno));
eerrorx ("rc-abort: failed to signal parent %d: %s", exit(EXIT_SUCCESS);
pid, strerror (errno));
exit (EXIT_SUCCESS);
} }
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (strcmp (applet, "rc" ) != 0) if (strcmp(applet, "rc") != 0)
eerrorx ("%s: unknown applet", applet); eerrorx("%s: unknown applet", applet);
} }

View File

@ -45,34 +45,33 @@
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
extern const char *applet; extern const char *applet;
rc_depinfo_t *_rc_deptree_load (int *regen) { RC_DEPTREE *_rc_deptree_load(int *regen) {
if (rc_deptree_update_needed ()) { int fd;
int fd; int retval;
int retval; int serrno = errno;
int serrno = errno; int merrno;
int merrno;
if (rc_deptree_update_needed()) {
/* Test if we have permission to update the deptree */ /* Test if we have permission to update the deptree */
fd = open (RC_DEPTREE, O_WRONLY); fd = open(RC_DEPTREE_CACHE, O_WRONLY);
merrno = errno; merrno = errno;
errno = serrno; errno = serrno;
if (fd == -1 && merrno == EACCES) if (fd == -1 && merrno == EACCES)
return (rc_deptree_load ()); return rc_deptree_load();
close (fd); close(fd);
if (regen) if (regen)
*regen = 1; *regen = 1;
ebegin ("Caching service dependencies"); ebegin("Caching service dependencies");
retval = rc_deptree_update (); retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree"); eend (retval ? 0 : -1, "Failed to update the dependency tree");
} }
return (rc_deptree_load ()); return rc_deptree_load();
} }
#include "_usage.h" #include "_usage.h"
@ -97,117 +96,114 @@ static const char * const longopts_help[] = {
}; };
#include "_usage.c" #include "_usage.c"
int rc_depend (int argc, char **argv) int rc_depend(int argc, char **argv)
{ {
char **types = NULL; RC_STRINGLIST *list;
char **services = NULL; RC_STRINGLIST *types;
char **depends = NULL; RC_STRINGLIST *services;
char **list; RC_STRINGLIST *depends;
rc_depinfo_t *deptree = NULL; RC_STRING *s;
char *service; RC_DEPTREE *deptree = NULL;
int options = RC_DEP_TRACE; int options = RC_DEP_TRACE;
bool first = true; bool first = true;
int i;
bool update = false; bool update = false;
char *runlevel = xstrdup( getenv ("RC_SOFTLEVEL")); char *runlevel = xstrdup(getenv("RC_SOFTLEVEL"));
int opt; int opt;
char *token; char *token;
while ((opt = getopt_long (argc, argv, getoptstring, types = rc_stringlist_new();
longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{ {
switch (opt) { switch (opt) {
case 'a': case 'a':
options |= RC_DEP_START; options |= RC_DEP_START;
break; break;
case 'o': case 'o':
options |= RC_DEP_STOP; options |= RC_DEP_STOP;
break; break;
case 's': case 's':
options |= RC_DEP_STRICT; options |= RC_DEP_STRICT;
break; break;
case 't': case 't':
while ((token = strsep (&optarg, ","))) while ((token = strsep(&optarg, ",")))
rc_strlist_addu (&types, token); rc_stringlist_add(types, token);
break; break;
case 'u': case 'u':
update = true; update = true;
break; break;
case 'T': case 'T':
options &= RC_DEP_TRACE; options &= RC_DEP_TRACE;
break; break;
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
} }
if (update) { if (update) {
bool u = false; ebegin("Caching service dependencies");
ebegin ("Caching service dependencies"); update = rc_deptree_update();
u = rc_deptree_update (); eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
eend (u ? 0 : -1, "%s: %s", applet, strerror (errno)); if (! update)
if (! u) eerrorx("Failed to update the dependency tree");
eerrorx ("Failed to update the dependency tree");
} }
if (! (deptree = _rc_deptree_load (NULL))) if (! (deptree = _rc_deptree_load(NULL)))
eerrorx ("failed to load deptree"); eerrorx("failed to load deptree");
if (! runlevel) if (! runlevel)
runlevel = rc_runlevel_get (); runlevel = rc_runlevel_get();
services = rc_stringlist_new();
while (optind < argc) { while (optind < argc) {
list = NULL; list = rc_stringlist_new();
rc_strlist_add (&list, argv[optind]); rc_stringlist_add(list, argv[optind]);
errno = 0; errno = 0;
depends = rc_deptree_depends (deptree, NULL, (const char **) list, depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
runlevel, 0);
if (! depends && errno == ENOENT) if (! depends && errno == ENOENT)
eerror ("no dependency info for service `%s'", argv[optind]); eerror("no dependency info for service `%s'", argv[optind]);
else else
rc_strlist_add (&services, argv[optind]); rc_stringlist_add(services, argv[optind]);
rc_strlist_free (depends); rc_stringlist_free(depends);
rc_strlist_free (list); rc_stringlist_free(list);
optind++; optind++;
} }
if (! TAILQ_FIRST(services)) {
if (! services) { rc_stringlist_free(services);
rc_strlist_free (types); rc_stringlist_free(types);
rc_deptree_free (deptree); rc_deptree_free(deptree);
free (runlevel); free(runlevel);
if (update) if (update)
return (EXIT_SUCCESS); return EXIT_SUCCESS;
eerrorx ("no services specified"); eerrorx("no services specified");
} }
/* If we don't have any types, then supply some defaults */ /* If we don't have any types, then supply some defaults */
if (! types) { if (! TAILQ_FIRST(types)) {
rc_strlist_add (&types, "ineed"); rc_stringlist_add(types, "ineed");
rc_strlist_add (&types, "iuse"); rc_stringlist_add(types, "iuse");
} }
depends = rc_deptree_depends (deptree, (const char **) types, depends = rc_deptree_depends(deptree, types, services, runlevel, options);
(const char **) services, runlevel, options);
if (depends) { if (TAILQ_FIRST(depends)) {
STRLIST_FOREACH (depends, service, i) { TAILQ_FOREACH(s, depends, entries) {
if (first) if (first)
first = false; first = false;
else else
printf (" "); printf (" ");
printf ("%s", s->value);
if (service)
printf ("%s", service);
} }
printf ("\n"); printf ("\n");
} }
rc_strlist_free (types); rc_stringlist_free(types);
rc_strlist_free (services); rc_stringlist_free(services);
rc_strlist_free (depends); rc_stringlist_free(depends);
rc_deptree_free (deptree); rc_deptree_free(deptree);
free (runlevel); free(runlevel);
return (EXIT_SUCCESS); return EXIT_SUCCESS;
} }

View File

@ -33,6 +33,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
@ -76,67 +77,67 @@ pid_t rc_logger_pid = -1;
int rc_logger_tty = -1; int rc_logger_tty = -1;
bool rc_in_logger = false; bool rc_in_logger = false;
static void write_log (int logfd, const char *buffer, size_t bytes) static void write_log(int logfd, const char *buffer, size_t bytes)
{ {
const char *p = buffer; const char *p = buffer;
while ((size_t) (p - buffer) < bytes) { while ((size_t) (p - buffer) < bytes) {
switch (*p) { switch (*p) {
case '\r': case '\r':
goto cont; goto cont;
case '\033': case '\033':
in_escape = true; in_escape = true;
in_term = false; in_term = false;
goto cont; goto cont;
case '\n': case '\n':
in_escape = in_term = false; in_escape = in_term = false;
break; break;
case '[': case '[':
if (in_escape) if (in_escape)
in_term = true; in_term = true;
break; break;
} }
if (! in_escape) { if (! in_escape) {
write (logfd, p++, 1); write(logfd, p++, 1);
continue; continue;
} }
if (! in_term || isalpha ((int) *p)) if (! in_term || isalpha((int) *p))
in_escape = in_term = false; in_escape = in_term = false;
cont: cont:
p++; p++;
} }
} }
static void write_time(FILE *f, const char *s)
static void write_time (FILE *f, const char *s)
{ {
time_t now = time (NULL); time_t now = time(NULL);
struct tm *tm = localtime (&now); struct tm *tm = localtime(&now);
fprintf (f, "\nrc %s logging %s at %s\n", runlevel, s, asctime (tm)); fprintf(f, "\nrc %s logging %s at %s\n", runlevel, s, asctime(tm));
fflush (f); fflush(f);
} }
void rc_logger_close () void rc_logger_close(void)
{ {
int sig = SIGTERM;
if (signal_pipe[1] > -1) { if (signal_pipe[1] > -1) {
int sig = SIGTERM; write(signal_pipe[1], &sig, sizeof(sig));
write (signal_pipe[1], &sig, sizeof (sig)); close(signal_pipe[1]);
close (signal_pipe[1]);
signal_pipe[1] = -1; signal_pipe[1] = -1;
} }
if (rc_logger_pid > 0) if (rc_logger_pid > 0)
waitpid (rc_logger_pid, 0, 0); waitpid(rc_logger_pid, 0, 0);
if (fd_stdout > -1) if (fd_stdout > -1)
dup2 (fd_stdout, STDOUT_FILENO); dup2(fd_stdout, STDOUT_FILENO);
if (fd_stderr > -1) if (fd_stderr > -1)
dup2 (fd_stderr, STDERR_FILENO); dup2(fd_stderr, STDERR_FILENO);
} }
void rc_logger_open (const char *level) void rc_logger_open(const char *level)
{ {
int slave_tty; int slave_tty;
struct termios tt; struct termios tt;
@ -149,125 +150,127 @@ void rc_logger_open (const char *level)
int i; int i;
FILE *log = NULL; FILE *log = NULL;
if (! isatty (STDOUT_FILENO)) if (! isatty(STDOUT_FILENO))
return; return;
if (! rc_conf_yesno ("rc_logger")) if (! rc_conf_yesno("rc_logger"))
return; return;
if (pipe (signal_pipe) == -1) if (pipe(signal_pipe) == -1)
eerrorx ("pipe: %s", strerror (errno)); eerrorx("pipe: %s", strerror(errno));
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 || if ((s = fcntl (signal_pipe[i], F_GETFD, 0) == -1 ||
fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1)) fcntl (signal_pipe[i], F_SETFD, s | FD_CLOEXEC) == -1))
eerrorx ("fcntl: %s", strerror (errno)); eerrorx("fcntl: %s", strerror (errno));
tcgetattr (STDOUT_FILENO, &tt); tcgetattr(STDOUT_FILENO, &tt);
ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws); ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
/* /dev/pts may not be available yet */ /* /dev/pts may not be available yet */
if (openpty (&rc_logger_tty, &slave_tty, NULL, &tt, &ws)) if (openpty(&rc_logger_tty, &slave_tty, NULL, &tt, &ws))
return; return;
if ((s = fcntl (rc_logger_tty, F_GETFD, 0)) == 0) if ((s = fcntl(rc_logger_tty, F_GETFD, 0)) == 0)
fcntl (rc_logger_tty, F_SETFD, s | FD_CLOEXEC); fcntl(rc_logger_tty, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl (slave_tty, F_GETFD, 0)) == 0) if ((s = fcntl(slave_tty, F_GETFD, 0)) == 0)
fcntl (slave_tty, F_SETFD, s | FD_CLOEXEC); fcntl(slave_tty, F_SETFD, s | FD_CLOEXEC);
rc_logger_pid = fork (); rc_logger_pid = fork();
switch (rc_logger_pid) { switch (rc_logger_pid) {
case -1: case -1:
eerror ("forkpty: %s", strerror (errno)); eerror("fork: %s", strerror(errno));
break; break;
case 0: case 0:
rc_in_logger = true; rc_in_logger = true;
close (signal_pipe[1]); close(signal_pipe[1]);
signal_pipe[1] = -1; signal_pipe[1] = -1;
runlevel = level; runlevel = level;
if ((log = fopen (LOGFILE, "a"))) if ((log = fopen(LOGFILE, "a")))
write_time (log, "started"); write_time(log, "started");
else { else {
free (logbuf); free(logbuf);
logbuf_size = BUFSIZ * 10; logbuf_size = BUFSIZ * 10;
logbuf = xmalloc (sizeof (char) * logbuf_size); logbuf = xmalloc(sizeof (char) * logbuf_size);
logbuf_len = 0; logbuf_len = 0;
}
buffer = xmalloc(sizeof (char) * BUFSIZ);
selfd = rc_logger_tty > signal_pipe[0] ? rc_logger_tty : signal_pipe[0];
for (;;) {
FD_ZERO(&rset);
FD_SET(rc_logger_tty, &rset);
FD_SET(signal_pipe[0], &rset);
if ((s = select(selfd + 1, &rset, NULL, NULL, NULL)) == -1) {
eerror("select: %s", strerror(errno));
break;
} }
buffer = xmalloc (sizeof (char) * BUFSIZ); if (s > 0) {
selfd = rc_logger_tty > signal_pipe[0] ? rc_logger_tty : signal_pipe[0]; if (FD_ISSET(rc_logger_tty, &rset)) {
for (;;) { memset(buffer, 0, BUFSIZ);
FD_ZERO (&rset); bytes = read(rc_logger_tty, buffer, BUFSIZ);
FD_SET (rc_logger_tty, &rset); write(STDOUT_FILENO, buffer, bytes);
FD_SET (signal_pipe[0], &rset);
if ((s = select (selfd + 1, &rset, NULL, NULL, NULL)) == -1) { if (log)
eerror ("select: %s", strerror (errno)); write_log(fileno (log), buffer, bytes);
break; else {
} if (logbuf_size - logbuf_len < bytes) {
logbuf_size += BUFSIZ * 10;
if (s > 0) { logbuf = xrealloc(logbuf,
if (FD_ISSET (rc_logger_tty, &rset)) { sizeof(char ) *
memset (buffer, 0, BUFSIZ); logbuf_size);
bytes = read (rc_logger_tty, buffer, BUFSIZ);
write (STDOUT_FILENO, buffer, bytes);
if (log)
write_log (fileno (log), buffer, bytes);
else {
if (logbuf_size - logbuf_len < bytes) {
logbuf_size += BUFSIZ * 10;
logbuf = xrealloc (logbuf, sizeof (char ) *
logbuf_size);
}
memcpy (logbuf + logbuf_len, buffer, bytes);
logbuf_len += bytes;
} }
memcpy(logbuf + logbuf_len, buffer, bytes);
logbuf_len += bytes;
} }
/* Only SIGTERMS signals come down this pipe */
if (FD_ISSET (signal_pipe[0], &rset))
break;
} }
}
free (buffer);
if (logbuf) {
if ((log = fopen (LOGFILE, "a"))) {
write_time (log, "started");
write_log (fileno (log), logbuf, logbuf_len);
}
free (logbuf);
}
if (log) {
write_time (log, "stopped");
fclose (log);
}
/* Try and cat our new logfile to a more permament location and then /* Only SIGTERMS signals come down this pipe */
* punt it */ if (FD_ISSET(signal_pipe[0], &rset))
system (MOVELOG); break;
}
}
free(buffer);
if (logbuf) {
if ((log = fopen(LOGFILE, "a"))) {
write_time(log, "started");
write_log(fileno(log), logbuf, logbuf_len);
}
free(logbuf);
}
if (log) {
write_time(log, "stopped");
fclose(log);
}
exit (0); /* Try and cat our new logfile to a more permament location and then
/* NOTREACHED */ * punt it */
default: system(MOVELOG);
setpgid (rc_logger_pid, 0);
fd_stdout = dup (STDOUT_FILENO);
fd_stderr = dup (STDERR_FILENO);
if ((s = fcntl (fd_stdout, F_GETFD, 0)) == 0)
fcntl (fd_stdout, F_SETFD, s | FD_CLOEXEC);
if ((s = fcntl (fd_stderr, F_GETFD, 0)) == 0) exit(0);
fcntl (fd_stderr, F_SETFD, s | FD_CLOEXEC); /* NOTREACHED */
dup2 (slave_tty, STDOUT_FILENO);
dup2 (slave_tty, STDERR_FILENO); default:
if (slave_tty != STDIN_FILENO && setpgid(rc_logger_pid, 0);
slave_tty != STDOUT_FILENO && fd_stdout = dup(STDOUT_FILENO);
slave_tty != STDERR_FILENO) fd_stderr = dup(STDERR_FILENO);
close (slave_tty); if ((s = fcntl(fd_stdout, F_GETFD, 0)) == 0)
close (signal_pipe[0]); fcntl(fd_stdout, F_SETFD, s | FD_CLOEXEC);
signal_pipe[0] = -1;
break; if ((s = fcntl(fd_stderr, F_GETFD, 0)) == 0)
fcntl(fd_stderr, F_SETFD, s | FD_CLOEXEC);
dup2(slave_tty, STDOUT_FILENO);
dup2(slave_tty, STDERR_FILENO);
if (slave_tty != STDIN_FILENO &&
slave_tty != STDOUT_FILENO &&
slave_tty != STDERR_FILENO)
close(slave_tty);
close(signal_pipe[0]);
signal_pipe[0] = -1;
break;
} }
} }

View File

@ -30,13 +30,13 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/utsname.h>
#ifdef __linux__ #ifdef __linux__
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include <regex.h> #include <regex.h>
#endif #endif
#include <sys/utsname.h>
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <signal.h> #include <signal.h>
@ -47,7 +47,6 @@
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
#define PROFILE_ENV SYSCONFDIR "/profile.env" #define PROFILE_ENV SYSCONFDIR "/profile.env"
#define SYS_WHITELIST RC_LIBDIR "/conf.d/env_whitelist" #define SYS_WHITELIST RC_LIBDIR "/conf.d/env_whitelist"
@ -57,314 +56,253 @@
#define PATH_PREFIX RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin" #define PATH_PREFIX RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
static char **rc_conf = NULL; static RC_STRINGLIST *rc_conf = NULL;
static void _free_rc_conf (void) extern char** environ;
static void _free_rc_conf(void)
{ {
rc_strlist_free (rc_conf); rc_stringlist_free(rc_conf);
} }
char *rc_conf_value (const char *setting) char *rc_conf_value(const char *setting)
{ {
if (! rc_conf) { RC_STRINGLIST *old;
char *line; RC_STRING *s;
int i; char *p;
rc_conf = rc_config_load (RC_CONF); if (! rc_conf) {
atexit (_free_rc_conf); rc_conf = rc_config_load(RC_CONF);
atexit(_free_rc_conf);
/* Support old configs */ /* Support old configs */
if (exists (RC_CONF_OLD)) { if (exists(RC_CONF_OLD)) {
char **old = rc_config_load (RC_CONF_OLD); old = rc_config_load(RC_CONF_OLD);
rc_strlist_join (&rc_conf, old); if (old) {
rc_strlist_free (old); TAILQ_CONCAT(rc_conf, old);
free(old);
}
} }
/* Convert old uppercase to lowercase */ /* Convert old uppercase to lowercase */
STRLIST_FOREACH (rc_conf, line, i) { TAILQ_FOREACH(s, rc_conf, entries) {
char *p = line; p = s->value;
while (p && *p && *p != '=') { while (p && *p && *p != '=') {
if (isupper ((int) *p)) if (isupper((int) *p))
*p = tolower ((int) *p); *p = tolower((int) *p);
p++; p++;
} }
} }
} }
return (rc_config_value ((const char *const *)rc_conf, setting)); return rc_config_value(rc_conf, setting);
} }
bool rc_conf_yesno (const char *setting) bool rc_conf_yesno(const char *setting)
{ {
return (rc_yesno (rc_conf_value (setting))); return rc_yesno(rc_conf_value (setting));
} }
char **env_filter (void) static const char *const env_whitelist[] = {
"PATH", "SHELL", "USER", "HOME", "TERM",
"LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
"LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS",
"LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", "LC_ALL",
"INIT_HALT", "INIT_VERSION", "RUNLEVEL", "PREVLEVEL", "CONSOLE",
"IN_HOTPLUG", "IN_BACKGROUND", "RC_INTERFACE_KEEP_CONFIG",
NULL
};
void env_filter(void)
{ {
char **env = NULL; RC_STRINGLIST *env_allow;
char **whitelist = NULL; RC_STRINGLIST *profile = NULL;
char *env_name = NULL; RC_STRINGLIST *env_list;
char **profile = NULL; RC_STRING *env;
int count = 0; RC_STRING *s;
bool got_path = false; char *env_name;
char *env_var;
size_t env_len;
char *token;
char *sep;
char *e; char *e;
char *p; char *token;
size_t pplen = strlen (PATH_PREFIX); size_t i = 0;
/* Init a system whitelist, start with shell vars we need */
rc_strlist_add (&whitelist, "PATH");
rc_strlist_add (&whitelist, "SHELL");
rc_strlist_add (&whitelist, "USER");
rc_strlist_add (&whitelist, "HOME");
rc_strlist_add (&whitelist, "TERM");
/* Add Language vars */
rc_strlist_add (&whitelist, "LANG");
rc_strlist_add (&whitelist, "LC_CTYPE");
rc_strlist_add (&whitelist, "LC_NUMERIC");
rc_strlist_add (&whitelist, "LC_TIME");
rc_strlist_add (&whitelist, "LC_COLLATE");
rc_strlist_add (&whitelist, "LC_MONETARY");
rc_strlist_add (&whitelist, "LC_MESSAGES");
rc_strlist_add (&whitelist, "LC_PAPER");
rc_strlist_add (&whitelist, "LC_NAME");
rc_strlist_add (&whitelist, "LC_ADDRESS");
rc_strlist_add (&whitelist, "LC_TELEPHONE");
rc_strlist_add (&whitelist, "LC_MEASUREMENT");
rc_strlist_add (&whitelist, "LC_IDENTIFICATION");
rc_strlist_add (&whitelist, "LC_ALL");
/* Allow rc to override library path */
rc_strlist_add (&whitelist, "LD_LIBRARY_PATH");
/* We need to know sysvinit stuff - we emulate this for BSD too */
rc_strlist_add (&whitelist, "INIT_HALT");
rc_strlist_add (&whitelist, "INIT_VERSION");
rc_strlist_add (&whitelist, "RUNLEVEL");
rc_strlist_add (&whitelist, "PREVLEVEL");
rc_strlist_add (&whitelist, "CONSOLE");
/* Hotplug and daemon vars */
rc_strlist_add (&whitelist, "IN_HOTPLUG");
rc_strlist_add (&whitelist, "IN_BACKGROUND");
rc_strlist_add (&whitelist, "RC_INTERFACE_KEEP_CONFIG");
/* Add the user defined list of vars */ /* Add the user defined list of vars */
e = env_name = xstrdup (rc_conf_value ("rc_env_allow")); env_allow = rc_stringlist_new();
while ((token = strsep (&e, " "))) { e = env_name = xstrdup(rc_conf_value ("rc_env_allow"));
while ((token = strsep(&e, " "))) {
if (token[0] == '*') { if (token[0] == '*') {
free (env_name); free(env_name);
return (NULL); rc_stringlist_free(env_allow);
return;
} }
rc_strlist_add (&whitelist, token); rc_stringlist_add(env_allow, token);
} }
free (env_name); free(env_name);
if (exists (PROFILE_ENV)) if (exists(PROFILE_ENV))
profile = rc_config_load (PROFILE_ENV); profile = rc_config_load(PROFILE_ENV);
STRLIST_FOREACH (whitelist, env_name, count) { /* Copy the env and work from this so we can remove safely */
char *space = strchr (env_name, ' '); env_list = rc_stringlist_new();
if (space) while (environ[i])
*space = 0; rc_stringlist_add(env_list, environ[i++]);
env_var = getenv (env_name); TAILQ_FOREACH(env, env_list, entries) {
/* Check the whitelist */
if (! env_var && profile) { i = 0;
env_len = strlen (env_name) + strlen ("export ") + 1; while (env_whitelist[i]) {
p = xmalloc (sizeof (char) * env_len); if (strcmp(env_whitelist[i++], env->value))
snprintf (p, env_len, "export %s", env_name); break;
env_var = rc_config_value ((const char *const *) profile, p);
free (p);
} }
if (env_whitelist[i])
if (! env_var)
continue; continue;
/* Ensure our PATH is prefixed with the system locations first /* Check our user defined list */
for a little extra security */ TAILQ_FOREACH(s, env_allow, entries)
if (strcmp (env_name, "PATH") == 0 && if (strcmp(s->value, env->value) == 0)
strncmp (PATH_PREFIX, env_var, pplen) != 0) break;
{ if (s)
got_path = true; continue;
env_len = strlen (env_name) + strlen (env_var) + pplen + 3;
e = p = 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 */ /* Now check our profile */
sep = env_var;
while ((token = strsep (&sep, ":"))) {
char *np = xstrdup (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 = xmalloc (sizeof (char) * env_len);
snprintf (e, env_len, "%s=%s", env_name, env_var);
}
rc_strlist_add (&env, e); /* OK, not allowed! */
free (e); e = strchr(env->value, '=');
*e = '\0';
unsetenv(env->value);
} }
rc_stringlist_free(env_list);
/* We filtered the env but didn't get a PATH? Very odd. rc_stringlist_free(env_allow);
However, we do need a path, so use a default. */ rc_stringlist_free(profile);
if (! got_path) {
env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 1;
e = xmalloc (sizeof (char) * env_len);
snprintf (e, env_len, "PATH=%s", PATH_PREFIX);
rc_strlist_add (&env, e);
free (e);
}
rc_strlist_free (whitelist);
rc_strlist_free (profile);
return (env);
} }
char **env_config (void) void env_config(void)
{ {
char **env = NULL; size_t pplen = strlen(PATH_PREFIX);
char *line; char *path;
char *p;
char *e;
size_t l; size_t l;
const char *sys = rc_sys ();
struct utsname uts; struct utsname uts;
FILE *fp; FILE *fp;
char *token;
char *np;
char *npp;
char *tok;
const char *sys = rc_sys();
char buffer[PATH_MAX]; char buffer[PATH_MAX];
char *runlevel = rc_runlevel_get ();
/* One char less to drop the trailing / */ /* Ensure our PATH is prefixed with the system locations first
l = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1; for a little extra security */
line = xmalloc (sizeof (char) * l); path = getenv("PATH");
snprintf (line, l, "RC_LIBDIR=" RC_LIBDIR); if (! path)
rc_strlist_add (&env, line); setenv("PATH", PATH_PREFIX, 1);
free (line); else if (strncmp (PATH_PREFIX, path, pplen) != 0) {
l = strlen(path) + pplen + 3;
e = p = xmalloc(sizeof(char) * l);
p += snprintf(p, l, "%s", PATH_PREFIX);
/* One char less to drop the trailing / */ /* Now go through the env var and only add bits not in our PREFIX */
l = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1; while ((token = strsep(&path, ":"))) {
line = xmalloc (sizeof (char) * l); np = npp = xstrdup(PATH_PREFIX);
snprintf (line, l, "RC_SVCDIR=" RC_SVCDIR); while ((tok = strsep(&npp, ":")))
rc_strlist_add (&env, line); if (strcmp(tok, token) == 0)
free (line); break;
if (! tok)
p += snprintf(p, l - (p - e), ":%s", token);
free (np);
}
*p++ = '\0';
unsetenv("PATH");
setenv("PATH", e, 1);
free(e);
}
rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT); setenv("RC_LIBDIR", RC_LIBDIR, 1);
setenv("RC_SVCDIR", RC_SVCDIR, 1);
setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1);
e = rc_runlevel_get();
setenv("RC_RUNLEVEL", e, 1);
free(e);
l = strlen ("RC_SOFTLEVEL=") + strlen (runlevel) + 1; if ((fp = fopen(RC_KSOFTLEVEL, "r"))) {
line = xmalloc (sizeof (char) * l); memset(buffer, 0, sizeof (buffer));
snprintf (line, l, "RC_SOFTLEVEL=%s", runlevel); if (fgets(buffer, sizeof (buffer), fp)) {
rc_strlist_add (&env, line);
free (line);
if ((fp = fopen (RC_KSOFTLEVEL, "r"))) {
memset (buffer, 0, sizeof (buffer));
if (fgets (buffer, sizeof (buffer), fp)) {
l = strlen (buffer) - 1; l = strlen (buffer) - 1;
if (buffer[l] == '\n') if (buffer[l] == '\n')
buffer[l] = 0; buffer[l] = 0;
l += strlen ("RC_DEFAULTLEVEL=") + 2; setenv("RC_DEFAULTLEVEL", buffer, 1);
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_DEFAULTLEVEL=%s", buffer);
rc_strlist_add (&env, line);
free (line);
} }
fclose (fp); fclose(fp);
} else } else
rc_strlist_add (&env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT); setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1);
if (sys) { if (sys)
l = strlen ("RC_SYS=") + strlen (sys) + 2; setenv("RC_SYS", sys, 1);
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_SYS=%s", sys);
rc_strlist_add (&env, line);
free (line);
}
/* Some scripts may need to take a different code path if Linux/FreeBSD, etc /* 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 */ To save on calling uname, we store it in an environment variable */
if (uname (&uts) == 0) { if (uname(&uts) == 0)
l = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2; setenv("RC_UNAME", uts.sysname, 1);
line = xmalloc (sizeof (char) * l);
snprintf (line, l, "RC_UNAME=%s", uts.sysname);
rc_strlist_add (&env, line);
free (line);
}
/* Be quiet or verbose as necessary */ /* Be quiet or verbose as necessary */
if (rc_conf_yesno ("rc_quiet")) if (rc_conf_yesno("rc_quiet"))
rc_strlist_add (&env, "EINFO_QUIET=YES"); setenv("EINFO_QUIET", "YES", 1);
if (rc_conf_yesno ("rc_verbose")) if (rc_conf_yesno("rc_verbose"))
rc_strlist_add (&env, "EINFO_VERBOSE=YES"); setenv("EINFO_VERBOSE", "YES", 1);
errno = 0; errno = 0;
if ((! rc_conf_yesno ("rc_color") && errno == 0) || if ((! rc_conf_yesno("rc_color") && errno == 0) ||
rc_conf_yesno ("rc_nocolor")) rc_conf_yesno("rc_nocolor"))
rc_strlist_add (&env, "EINFO_COLOR=NO"); setenv("EINFO_COLOR", "NO", 1);
free (runlevel);
return (env);
} }
bool service_plugable (const char *service) bool service_plugable(const char *service)
{ {
char *list; char *list;
char *p; char *p;
char *star; char *star;
char *token; char *token;
bool allow = true; bool allow = true;
char *match = rc_conf_value ("rc_plug_services"); char *match = rc_conf_value("rc_plug_services");
bool truefalse;
if (! match) if (! match)
return (true); return true;
list = xstrdup (match); list = xstrdup(match);
p = list; p = list;
while ((token = strsep (&p, " "))) { while ((token = strsep(&p, " "))) {
bool truefalse = true;
if (token[0] == '!') { if (token[0] == '!') {
truefalse = false; truefalse = false;
token++; token++;
} } else
truefalse = true;
star = strchr (token, '*'); star = strchr(token, '*');
if (star) { if (star) {
if (strncmp (service, token, (size_t) (star - token)) if (strncmp(service, token, (size_t)(star - token)) == 0)
== 0)
{ {
allow = truefalse; allow = truefalse;
break; break;
} }
} else { } else {
if (strcmp (service, token) == 0) { if (strcmp(service, token) == 0) {
allow = truefalse; allow = truefalse;
break; break;
} }
} }
} }
free (list); free(list);
return (allow); return allow;
} }
int signal_setup (int sig, void (*handler)(int)) int signal_setup(int sig, void (*handler)(int))
{ {
struct sigaction sa; struct sigaction sa;
memset (&sa, 0, sizeof (sa)); memset(&sa, 0, sizeof (sa));
sigemptyset (&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_handler = handler; sa.sa_handler = handler;
return (sigaction (sig, &sa, NULL)); return sigaction(sig, &sa, NULL);
} }

View File

@ -31,6 +31,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <dirent.h> #include <dirent.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <errno.h> #include <errno.h>
@ -46,7 +47,6 @@
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "rc-plugin.h" #include "rc-plugin.h"
#include "strlist.h"
#define RC_PLUGIN_HOOK "rc_plugin_hook" #define RC_PLUGIN_HOOK "rc_plugin_hook"
@ -56,129 +56,117 @@ typedef struct plugin
{ {
char *name; char *name;
void *handle; void *handle;
int (*hook) (rc_hook_t, const char *); int (*hook)(RC_HOOK, const char *);
struct plugin *next; STAILQ_ENTRY(plugin) entries;
} plugin_t; } PLUGIN;
STAILQ_HEAD(, plugin) plugins;
static plugin_t *plugins = NULL;
#ifndef __FreeBSD__ #ifndef __FreeBSD__
dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol) dlfunc_t dlfunc(void * __restrict handle, const char * __restrict symbol)
{ {
union { union {
void *d; void *d;
dlfunc_t f; dlfunc_t f;
} rv; } rv;
rv.d = dlsym (handle, symbol); rv.d = dlsym(handle, symbol);
return (rv.f); return rv.f;
} }
#endif #endif
void rc_plugin_load (void) void rc_plugin_load(void)
{ {
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
plugin_t *plugin = plugins; PLUGIN *plugin;
char *p; char *p;
void *h; void *h;
int (*fptr) (rc_hook_t, const char *); int (*fptr)(RC_HOOK, const char *);
/* Don't load plugins if we're in one */ /* Don't load plugins if we're in one */
if (rc_in_plugin) if (rc_in_plugin)
return; return;
/* Ensure some sanity here */ STAILQ_INIT(&plugins);
rc_plugin_unload ();
if (! (dp = opendir (RC_PLUGINDIR))) if (! (dp = opendir(RC_PLUGINDIR)))
return; return;
while ((d = readdir (dp))) { while ((d = readdir(dp))) {
if (d->d_name[0] == '.') if (d->d_name[0] == '.')
continue; continue;
p = rc_strcatpaths (RC_PLUGINDIR, d->d_name, NULL); p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL);
h = dlopen (p, RTLD_LAZY); h = dlopen(p, RTLD_LAZY);
free (p); free(p);
if (! h) { if (! h) {
eerror ("dlopen: %s", dlerror ()); eerror("dlopen: %s", dlerror());
continue; continue;
} }
fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, RC_PLUGIN_HOOK); fptr = (int (*)(RC_HOOK, const char*))dlfunc(h, RC_PLUGIN_HOOK);
if (! fptr) { if (! fptr) {
eerror ("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK); eerror("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
dlclose (h); dlclose(h);
} else { } else {
if (plugin) { plugin = xmalloc(sizeof(*plugin));
plugin->next = xmalloc (sizeof (*plugin->next)); plugin->name = xstrdup(d->d_name);
plugin = plugin->next;
} else
plugin = plugins = xmalloc (sizeof (*plugin));
plugin->name = xstrdup (d->d_name);
plugin->handle = h; plugin->handle = h;
plugin->hook = fptr; plugin->hook = fptr;
plugin->next = NULL; STAILQ_INSERT_TAIL(&plugins, plugin, entries);
} }
} }
closedir (dp); closedir(dp);
} }
int rc_waitpid (pid_t pid) int rc_waitpid(pid_t pid)
{ {
int status = 0; int status = 0;
pid_t savedpid = pid; pid_t savedpid = pid;
int retval = -1; int retval = -1;
errno = 0; errno = 0;
while ((pid = waitpid (savedpid, &status, 0)) > 0) { while ((pid = waitpid(savedpid, &status, 0)) > 0) {
if (pid == savedpid) if (pid == savedpid)
retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE; retval = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
} }
return (retval); return retval;
} }
void rc_plugin_run (rc_hook_t hook, const char *value) void rc_plugin_run(RC_HOOK hook, const char *value)
{ {
plugin_t *plugin = plugins; PLUGIN *plugin;
struct sigaction sa; struct sigaction sa;
sigset_t empty; sigset_t empty;
sigset_t full; sigset_t full;
sigset_t old; sigset_t old;
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
int retval;
/* Don't run plugins if we're in one */ /* Don't run plugins if we're in one */
if (rc_in_plugin) if (rc_in_plugin)
return; return;
/* We need to block signals until we have forked */ /* We need to block signals until we have forked */
memset (&sa, 0, sizeof (sa)); memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask); sigemptyset(&sa.sa_mask);
sigemptyset (&empty); sigemptyset(&empty);
sigfillset (&full); sigfillset(&full);
while (plugin) {
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
if (! plugin->hook) {
plugin = plugin->next;
continue;
}
STAILQ_FOREACH(plugin, &plugins, entries) {
/* We create a pipe so that plugins can affect our environment /* We create a pipe so that plugins can affect our environment
* vars, which in turn influence our scripts. */ * vars, which in turn influence our scripts. */
if (pipe (pfd) == -1) { if (pipe(pfd) == -1) {
eerror ("pipe: %s", strerror (errno)); eerror("pipe: %s", strerror(errno));
return; return;
} }
@ -188,81 +176,78 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 || if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0) fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
eerror ("fcntl: %s", strerror (errno)); eerror("fcntl: %s", strerror(errno));
sigprocmask (SIG_SETMASK, &full, &old); sigprocmask(SIG_SETMASK, &full, &old);
/* We run the plugin in a new process so we never crash /* We run the plugin in a new process so we never crash
* or otherwise affected by it */ * or otherwise affected by it */
if ((pid = fork ()) == -1) { if ((pid = fork()) == -1) {
eerror ("fork: %s", strerror (errno)); eerror("fork: %s", strerror(errno));
break; break;
} }
if (pid == 0) { if (pid == 0) {
int retval;
/* Restore default handlers */ /* Restore default handlers */
sigaction (SIGCHLD, &sa, NULL); sigaction(SIGCHLD, &sa, NULL);
sigaction (SIGHUP, &sa, NULL); sigaction(SIGHUP, &sa, NULL);
sigaction (SIGINT, &sa, NULL); sigaction(SIGINT, &sa, NULL);
sigaction (SIGQUIT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL); sigaction(SIGTERM, &sa, NULL);
sigaction (SIGUSR1, &sa, NULL); sigaction(SIGUSR1, &sa, NULL);
sigaction (SIGWINCH, &sa, NULL); sigaction(SIGWINCH, &sa, NULL);
sigprocmask (SIG_SETMASK, &old, NULL); sigprocmask(SIG_SETMASK, &old, NULL);
rc_in_plugin = true; rc_in_plugin = true;
close (pfd[0]); close(pfd[0]);
rc_environ_fd = fdopen (pfd[1], "w"); rc_environ_fd = fdopen(pfd[1], "w");
retval = plugin->hook (hook, value); retval = plugin->hook(hook, value);
fclose (rc_environ_fd); fclose(rc_environ_fd);
rc_environ_fd = NULL; rc_environ_fd = NULL;
/* Just in case the plugin sets this to false */ /* Just in case the plugin sets this to false */
rc_in_plugin = true; rc_in_plugin = true;
exit (retval); exit(retval);
} }
sigprocmask (SIG_SETMASK, &old, NULL); sigprocmask(SIG_SETMASK, &old, NULL);
close (pfd[1]); close(pfd[1]);
buffer = xmalloc (sizeof (char) * BUFSIZ); buffer = xmalloc(sizeof(char) * BUFSIZ);
memset (buffer, 0, BUFSIZ); memset(buffer, 0, BUFSIZ);
while ((nr = read (pfd[0], buffer, BUFSIZ)) > 0) { while ((nr = read(pfd[0], buffer, BUFSIZ)) > 0) {
p = buffer; p = buffer;
while (*p && p - buffer < nr) { while (*p && p - buffer < nr) {
token = strsep (&p, "="); token = strsep(&p, "=");
if (token) { if (token) {
unsetenv (token); unsetenv(token);
if (*p) { if (*p) {
setenv (token, p, 1); setenv(token, p, 1);
p += strlen (p) + 1; p += strlen(p) + 1;
} else } else
p++; p++;
} }
} }
} }
free (buffer); free(buffer);
close (pfd[0]); close(pfd[0]);
rc_waitpid (pid); rc_waitpid(pid);
plugin = plugin->next;
} }
} }
void rc_plugin_unload (void) void rc_plugin_unload(void)
{ {
plugin_t *plugin = plugins; PLUGIN *plugin = STAILQ_FIRST(&plugins);
plugin_t *next; PLUGIN *next;
while (plugin) { while (plugin) {
next = plugin->next; next = STAILQ_NEXT(plugin, entries);
dlclose (plugin->handle); dlclose(plugin->handle);
free (plugin->name); free(plugin->name);
free (plugin); free(plugin);
plugin = next; plugin = next;
} }
plugins = NULL; STAILQ_INIT(&plugins);
} }

View File

@ -36,10 +36,10 @@
* Mainly used in atexit code. */ * Mainly used in atexit code. */
extern bool rc_in_plugin; extern bool rc_in_plugin;
int rc_waitpid (pid_t pid); int rc_waitpid(pid_t pid);
void rc_plugin_load (); void rc_plugin_load(void);
void rc_plugin_unload (); void rc_plugin_unload(void);
void rc_plugin_run (rc_hook_t, const char *value); void rc_plugin_run(RC_HOOK, const char *value);
/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */ /* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */
#ifndef __FreeBSD__ #ifndef __FreeBSD__
@ -47,7 +47,7 @@ struct __dlfunc_arg {
int __dlfunc_dummy; int __dlfunc_dummy;
}; };
typedef void (*dlfunc_t) (struct __dlfunc_arg); typedef void (*dlfunc_t)(struct __dlfunc_arg);
dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol); dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol);
#endif #endif

View File

@ -39,57 +39,56 @@
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
extern const char *applet; extern const char *applet;
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL }; static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
static void print_level (char *level) static void print_level(char *level)
{ {
printf ("Runlevel: "); printf ("Runlevel: ");
if (isatty (fileno (stdout))) if (isatty(fileno(stdout)))
printf ("%s%s%s\n", printf("%s%s%s\n",
ecolor (ECOLOR_HILITE), ecolor(ECOLOR_HILITE),
level, level,
ecolor (ECOLOR_NORMAL)); ecolor(ECOLOR_NORMAL));
else else
printf ("%s\n", level); printf("%s\n", level);
} }
static void print_service (char *service) static void print_service(char *service)
{ {
char status[10]; char status[10];
int cols = printf (" %s", service); int cols = printf(" %s", service);
const char *c = ecolor (ECOLOR_GOOD); const char *c = ecolor(ECOLOR_GOOD);
rc_service_state_t state = rc_service_state (service); RC_SERVICE state = rc_service_state(service);
einfo_color_t color = ECOLOR_BAD; ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING) if (state & RC_SERVICE_STOPPING)
snprintf (status, sizeof (status), "stopping "); snprintf(status, sizeof(status), "stopping ");
else if (state & RC_SERVICE_STARTING) { else if (state & RC_SERVICE_STARTING) {
snprintf (status, sizeof (status), "starting "); snprintf(status, sizeof(status), "starting ");
color = ECOLOR_WARN; color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) { } else if (state & RC_SERVICE_INACTIVE) {
snprintf (status, sizeof (status), "inactive "); snprintf(status, sizeof(status), "inactive ");
color = ECOLOR_WARN; color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) { } else if (state & RC_SERVICE_STARTED) {
if (geteuid () == 0 && rc_service_daemons_crashed (service)) if (rc_service_daemons_crashed(service))
snprintf (status, sizeof (status), " crashed "); snprintf(status, sizeof(status), " crashed ");
else { else {
snprintf (status, sizeof (status), " started "); snprintf(status, sizeof(status), " started ");
color = ECOLOR_GOOD; color = ECOLOR_GOOD;
} }
} else if (state & RC_SERVICE_SCHEDULED) { } else if (state & RC_SERVICE_SCHEDULED) {
snprintf (status, sizeof (status), "scheduled"); snprintf(status, sizeof(status), "scheduled");
color = ECOLOR_WARN; color = ECOLOR_WARN;
} else } else
snprintf (status, sizeof (status), " stopped "); snprintf(status, sizeof(status), " stopped ");
errno = 0; errno = 0;
if (c && *c && isatty (fileno (stdout))) if (c && *c && isatty(fileno(stdout)))
printf ("\n"); printf("\n");
ebracket (cols, color, status); ebracket(cols, color, status);
} }
#include "_usage.h" #include "_usage.h"
@ -115,99 +114,100 @@ static const char * const longopts_help[] = {
int rc_status (int argc, char **argv) int rc_status (int argc, char **argv)
{ {
rc_depinfo_t *deptree = NULL; RC_DEPTREE *deptree = NULL;
char **levels = NULL; RC_STRINGLIST *levels = NULL;
char **services = NULL; RC_STRINGLIST *services;
char **ordered = NULL; RC_STRINGLIST *types = NULL;
char *level; RC_STRINGLIST *ordered;
char *service; RC_STRING *s;
RC_STRING *l;
char *p;
int opt; int opt;
int i;
int j;
int depopts = RC_DEP_STRICT | RC_DEP_START | RC_DEP_TRACE; int depopts = RC_DEP_STRICT | RC_DEP_START | RC_DEP_TRACE;
while ((opt = getopt_long (argc, argv, getoptstring, longopts, while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1) (int *) 0)) != -1)
switch (opt) { switch (opt) {
case 'a': case 'a':
levels = rc_runlevel_list (); levels = rc_runlevel_list();
break; break;
case 'l': case 'l':
levels = rc_runlevel_list (); levels = rc_runlevel_list();
STRLIST_FOREACH (levels, level, i) TAILQ_FOREACH (l, levels, entries)
printf ("%s\n", level); printf("%s\n", l->value);
rc_strlist_free (levels); rc_stringlist_free(levels);
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
/* NOTREACHED */ /* NOTREACHED */
case 'r': case 'r':
level = rc_runlevel_get (); p = rc_runlevel_get ();
printf ("%s\n", level); printf("%s\n", p);
free (level); free(p);
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
/* NOTREACHED */ /* NOTREACHED */
case 's': case 's':
services = rc_services_in_runlevel (NULL); services = rc_services_in_runlevel(NULL);
STRLIST_FOREACH (services, service, i) TAILQ_FOREACH(s, services, entries)
print_service (service); print_service(s->value);
rc_strlist_free (services); rc_stringlist_free(services);
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
/* NOTREACHED */ /* NOTREACHED */
case 'u': case 'u':
services = rc_services_in_runlevel (NULL); services = rc_services_in_runlevel(NULL);
levels = rc_runlevel_list (); levels = rc_runlevel_list();
STRLIST_FOREACH (services, service, i) { TAILQ_FOREACH(s, services, entries) {
bool found = false; TAILQ_FOREACH(l, levels, entries)
STRLIST_FOREACH (levels, level, j) if (rc_service_in_runlevel(s->value, l->value))
if (rc_service_in_runlevel (service, level)) { break;
found = true; if (! l)
break; print_service(s->value);
} }
if (! found) rc_stringlist_free(levels);
print_service (service); rc_stringlist_free(services);
} exit (EXIT_SUCCESS);
rc_strlist_free (levels); /* NOTREACHED */
rc_strlist_free (services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
if (! levels)
levels = rc_stringlist_new();
while (optind < argc) while (optind < argc)
rc_strlist_add (&levels, argv[optind++]); rc_stringlist_add(levels, argv[optind++]);
if (! TAILQ_FIRST(levels)) {
if (! levels) { p = rc_runlevel_get();
level = rc_runlevel_get (); rc_stringlist_add(levels, p);
rc_strlist_add (&levels, level); free(p);
free (level);
} }
/* Output the services in the order in which they would start */ /* Output the services in the order in which they would start */
if (geteuid () == 0) deptree = _rc_deptree_load(NULL);
deptree = _rc_deptree_load (NULL);
else
deptree = rc_deptree_load ();
STRLIST_FOREACH (levels, level, i) { TAILQ_FOREACH(l, levels, entries) {
print_level (level); print_level(l->value);
services = rc_services_in_runlevel (level); services = rc_services_in_runlevel(l->value);
if (deptree) { if (deptree) {
ordered = rc_deptree_depends (deptree, types_nua, if (! types) {
(const char **) services, types = rc_stringlist_new();
level, depopts); rc_stringlist_add(types, "ineed");
rc_strlist_free (services); rc_stringlist_add(types, "iuse");
rc_stringlist_add(types, "iafter");
}
ordered = rc_deptree_depends(deptree, types, services,
l->value, depopts);
rc_stringlist_free(services);
services = ordered; services = ordered;
ordered = NULL; ordered = NULL;
} }
STRLIST_FOREACH (services, service, j) TAILQ_FOREACH(s, services, entries)
if (rc_service_in_runlevel (service, level)) if (rc_service_in_runlevel(s->value, l->value))
print_service (service); print_service(s->value);
rc_strlist_free (services); rc_stringlist_free(services);
} }
rc_strlist_free (levels); rc_stringlist_free(types);
rc_deptree_free (deptree); rc_stringlist_free(levels);
rc_deptree_free(deptree);
exit (EXIT_SUCCESS); exit(EXIT_SUCCESS);
/* NOTREACHED */ /* NOTREACHED */
} }

View File

@ -42,7 +42,6 @@
#include "einfo.h" #include "einfo.h"
#include "rc.h" #include "rc.h"
#include "rc-misc.h" #include "rc-misc.h"
#include "strlist.h"
extern const char *applet; extern const char *applet;
@ -68,7 +67,7 @@ static int add (const char *runlevel, const char *service)
eerror ("%s: failed to add service `%s' to runlevel `%s': %s", eerror ("%s: failed to add service `%s' to runlevel `%s': %s",
applet, service, runlevel, strerror (errno)); applet, service, runlevel, strerror (errno));
return (retval); return retval;
} }
static int delete (const char *runlevel, const char *service) static int delete (const char *runlevel, const char *service)
@ -88,44 +87,47 @@ static int delete (const char *runlevel, const char *service)
eerror ("%s: failed to remove service `%s' from runlevel `%s': %s", eerror ("%s: failed to remove service `%s' from runlevel `%s': %s",
applet, service, runlevel, strerror (errno)); applet, service, runlevel, strerror (errno));
return (retval); return retval;
} }
static void show (char **runlevels, bool verbose) static void show (RC_STRINGLIST *runlevels, bool verbose)
{ {
char *service; RC_STRINGLIST *services = rc_services_in_runlevel(NULL);
char **services = rc_services_in_runlevel (NULL); RC_STRING *service;
char *runlevel; RC_STRING *runlevel;
int i; RC_STRINGLIST *in;
int j; bool inone;
char buffer[PATH_MAX];
size_t l;
STRLIST_FOREACH (services, service, i) { TAILQ_FOREACH(service, services, entries) {
char **in = NULL; in = rc_stringlist_new();
bool inone = false; inone = false;
STRLIST_FOREACH (runlevels, runlevel, j) { TAILQ_FOREACH(runlevel, runlevels, entries) {
if (rc_service_in_runlevel (service, runlevel)) { if (rc_service_in_runlevel(service->value,
rc_strlist_add (&in, runlevel); runlevel->value))
{
rc_stringlist_add(in, runlevel->value);
inone = true; inone = true;
} else { } else {
char buffer[PATH_MAX]; l = strlen(runlevel->value);
memset (buffer, ' ', strlen (runlevel)); memset (buffer, ' ', l);
buffer[strlen (runlevel)] = 0; buffer[l] = 0;
rc_strlist_add (&in, buffer); rc_stringlist_add (in, buffer);
} }
} }
if (! inone && ! verbose) if (inone || verbose) {
continue; printf(" %20s |", service->value);
TAILQ_FOREACH(runlevel, in, entries)
printf (" %20s |", service); printf (" %s", runlevel->value);
STRLIST_FOREACH (in, runlevel, j) printf ("\n");
printf (" %s", runlevel); }
printf ("\n"); rc_stringlist_free(in);
rc_strlist_free (in);
} }
rc_strlist_free (services); rc_stringlist_free (services);
} }
#include "_usage.h" #include "_usage.h"
@ -146,111 +148,124 @@ static const char * const longopts_help[] = {
#define DODELETE (1 << 2) #define DODELETE (1 << 2)
#define DOSHOW (1 << 3) #define DOSHOW (1 << 3)
int rc_update (int argc, char **argv) int rc_update(int argc, char **argv)
{ {
int i; RC_STRINGLIST *runlevels;
RC_STRING *runlevel;
char *service = NULL; char *service = NULL;
char **runlevels = NULL; char *p;
char *runlevel;
int action = 0; int action = 0;
bool verbose = false; bool verbose = false;
int opt; int opt;
int retval = EXIT_FAILURE; int retval = EXIT_FAILURE;
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
while ((opt = getopt_long (argc, argv, getoptstring, while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1) longopts, (int *) 0)) != -1)
{
switch (opt) { switch (opt) {
case_RC_COMMON_GETOPT case_RC_COMMON_GETOPT
} }
}
verbose = rc_yesno (getenv ("EINFO_VERBOSE")); verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
if ((action & DOSHOW && action != DOSHOW) || if ((action & DOSHOW && action != DOSHOW) ||
(action & DOADD && action != DOADD) || (action & DOADD && action != DOADD) ||
(action & DODELETE && action != DODELETE)) (action & DODELETE && action != DODELETE))
eerrorx ("%s: cannot mix commands", applet); eerrorx("%s: cannot mix commands", applet);
/* We need to be backwards compatible */ /* We need to be backwards compatible */
if (optind < argc) { if (optind < argc) {
if (strcmp (argv[optind], "add") == 0) if (strcmp(argv[optind], "add") == 0)
action = DOADD; action = DOADD;
else if (strcmp (argv[optind], "delete") == 0 || else if (strcmp(argv[optind], "delete") == 0 ||
strcmp (argv[optind], "del") == 0) strcmp(argv[optind], "del") == 0)
action = DODELETE; action = DODELETE;
else if (strcmp (argv[optind], "show") == 0) else if (strcmp(argv[optind], "show") == 0)
action = DOSHOW; action = DOSHOW;
if (action) if (action)
optind++; optind++;
else else
eerrorx ("%s: invalid command `%s'", applet, argv[optind]); eerrorx("%s: invalid command `%s'", applet, argv[optind]);
} }
if (! action) if (! action)
action = DOSHOW; action = DOSHOW;
runlevels = rc_stringlist_new();
if (optind >= argc) { if (optind >= argc) {
if (! action & DOSHOW) if (! action & DOSHOW)
eerrorx ("%s: no service specified", applet); eerrorx("%s: no service specified", applet);
} else { } else {
service = argv[optind]; service = argv[optind];
optind++; optind++;
while (optind < argc) while (optind < argc)
if (rc_runlevel_exists (argv[optind])) if (rc_runlevel_exists(argv[optind]))
rc_strlist_add (&runlevels, argv[optind++]); rc_stringlist_add(runlevels, argv[optind++]);
else { else {
rc_strlist_free (runlevels); rc_stringlist_free(runlevels);
eerrorx ("%s: `%s' is not a valid runlevel", applet, argv[optind]); eerrorx ("%s: `%s' is not a valid runlevel",
applet, argv[optind]);
} }
} }
retval = EXIT_SUCCESS; retval = EXIT_SUCCESS;
if (action & DOSHOW) { if (action & DOSHOW) {
if (service) if (service)
rc_strlist_add (&runlevels, service); rc_stringlist_add(runlevels, service);
if (! runlevels) if (! TAILQ_FIRST(runlevels)) {
runlevels = rc_runlevel_list (); free(runlevels);
runlevels = rc_runlevel_list();
}
show (runlevels, verbose); show (runlevels, verbose);
} else { } else {
if (! service) if (! service)
eerror ("%s: no service specified", applet); eerror ("%s: no service specified", applet);
else { else {
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
if (action & DOADD) { if (action & DOADD) {
actfunc = add; actfunc = add;
} else if (action & DODELETE) { } else if (action & DODELETE) {
actfunc = delete; actfunc = delete;
} else } else {
rc_stringlist_free(runlevels);
eerrorx ("%s: invalid action", applet); eerrorx ("%s: invalid action", applet);
}
if (! runlevels) if (! TAILQ_FIRST(runlevels)) {
rc_strlist_add (&runlevels, rc_runlevel_get ()); p = rc_runlevel_get();
rc_stringlist_add(runlevels, p);
free(p);
}
if (! runlevels) if (! TAILQ_FIRST(runlevels)) {
free(runlevels);
eerrorx ("%s: no runlevels found", applet); eerrorx ("%s: no runlevels found", applet);
}
STRLIST_FOREACH (runlevels, runlevel, i) { TAILQ_FOREACH (runlevel, runlevels, entries) {
if (! rc_runlevel_exists (runlevel)) { if (! rc_runlevel_exists(runlevel->value)) {
eerror ("%s: runlevel `%s' does not exist", applet, runlevel); eerror ("%s: runlevel `%s' does not exist",
applet, runlevel->value);
continue; continue;
} }
ret = actfunc (runlevel, service); ret = actfunc(runlevel->value, service);
if (ret < 0) if (ret < 0)
retval = EXIT_FAILURE; retval = EXIT_FAILURE;
num_updated += ret; num_updated += ret;
} }
if (retval == EXIT_SUCCESS && num_updated == 0 && action & DODELETE) if (retval == EXIT_SUCCESS &&
ewarnx ("%s: service `%s' not found in any of the specified runlevels", applet, service); num_updated == 0 && action & DODELETE)
ewarnx("%s: service `%s' not found in any"
" of the specified runlevels",
applet, service);
} }
} }
rc_strlist_free (runlevels); rc_stringlist_free(runlevels);
return (retval); return retval;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff