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:
@ -1,6 +1,6 @@
|
||||
MAN3= einfo.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
|
||||
|
||||
# Handy macro to create symlinks
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Feb 22, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt EINFO 3 SMM
|
||||
.Os OpenRC
|
||||
.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 eendv "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 eoutdent void
|
||||
.Ft void Fn eindentv void
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Jan 08, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt RC_CONFIG 3 SMM
|
||||
.Os OpenRC
|
||||
.Sh NAME
|
||||
@ -33,8 +33,8 @@ Run Command library (librc, -lrc)
|
||||
.Sh SYNOPSIS
|
||||
.In rc.h
|
||||
.Ft "char *" Fn rc_getline "FILE *fp"
|
||||
.Ft "char **" Fn rc_config_list "const char *file"
|
||||
.Ft "char **" Fn rc_config_load "const char *file"
|
||||
.Ft "RC_STRINGLIST *" Fn rc_config_list "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 bool Fn rc_yesno "const char *value"
|
||||
.Sh DESCRIPTION
|
||||
@ -61,7 +61,7 @@ found in
|
||||
.Fa list .
|
||||
.Pp
|
||||
Each list should be freed using
|
||||
.Fn rc_strlist_free
|
||||
.Fn rc_stringlist_free
|
||||
when done.
|
||||
.Pp
|
||||
.Fn rc_yesno
|
||||
@ -76,7 +76,7 @@ is set to
|
||||
.Va EINVAL .
|
||||
.Sh SEE ALSO
|
||||
.Xr malloc 3 ,
|
||||
.Xr rc_strlist_free 3 ,
|
||||
.Xr rc_stringlist_free 3 ,
|
||||
.Xr sh 1
|
||||
.Sh AUTHORS
|
||||
.An "Roy Marples" Aq roy@marples.name
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Feb 22, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt RC_DEPTREE 3 SMM
|
||||
.Os OpenRC
|
||||
.Sh NAME
|
||||
@ -36,25 +36,25 @@ Run Command library (librc, -lrc)
|
||||
.In rc.h
|
||||
.Ft bool Fn rc_deptree_update void
|
||||
.Ft bool Fn rc_deptree_update_needed void
|
||||
.Ft rc_depinfo_t Fn rc_deptree_load void
|
||||
.Ft "char **" Fo rc_deptree_depend
|
||||
.Fa "const rc_depinfo_t *deptree"
|
||||
.Ft RC_DEPTREE Fn rc_deptree_load void
|
||||
.Ft "RC_STRINGLIST *" Fo rc_deptree_depend
|
||||
.Fa "const RC_DEPTREE *deptree"
|
||||
.Fa "const char *type"
|
||||
.Fa "const char *service"
|
||||
.Fc
|
||||
.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 *services"
|
||||
.Fa "const char *runlevel"
|
||||
.Fa "int options"
|
||||
.Fc
|
||||
.Ft "char **" Fo rc_deptree_order
|
||||
.Fa "const rc_depinfo_t *deptree"
|
||||
.Ft "RC_STRINGLIST *" Fo rc_deptree_order
|
||||
.Fa "const RC_DEPTREE *deptree"
|
||||
.Fa "const char *runlevel"
|
||||
.Fa "int options"
|
||||
.Fc
|
||||
.Ft void Fn rc_deptree_free "rc_depinfo_t *deptree"
|
||||
.Ft void Fn rc_deptree_free "RC_DEPTREE *deptree"
|
||||
.Sh DESCRIPTION
|
||||
These functions provide a means of querying the dependencies of OpenRC
|
||||
services.
|
||||
@ -100,15 +100,14 @@ only lists services actually needed or in the
|
||||
.Va runlevel .
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
Each function that returns
|
||||
.Fr "char **"
|
||||
returns a malloced NULL terminated array of malloced NULL terminated strings,
|
||||
all of which need to be freed using
|
||||
.Fn rc_strlist_free
|
||||
.Fr "RC_STRINGLIST *"
|
||||
should be freed by calling
|
||||
.Fn rc_stringlist_free
|
||||
when done.
|
||||
.Sh SEE ALSO
|
||||
.Xr malloc 3 ,
|
||||
.Xr free 3 ,
|
||||
.Xr rc_strlist_free 3 ,
|
||||
.Xr rc_stringlist_free 3 ,
|
||||
.Xr runscript 8
|
||||
.Sh AUTHORS
|
||||
.An "Roy Marples" Aq roy@marples.name
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Feb 22, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt RC_PLUGIN_HOOK 3 SMM
|
||||
.Os OpenRC
|
||||
.Sh NAME
|
||||
@ -32,7 +32,7 @@
|
||||
Run Command library (librc, -lrc)
|
||||
.Sh SYNOPSIS
|
||||
.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
|
||||
.Fn rc_plugin_hook
|
||||
is called for each shareable object found in
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Feb 22, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt RC_RUNLEVEL 3 SMM
|
||||
.Os OpenRC
|
||||
.Sh NAME
|
||||
@ -35,7 +35,7 @@ Run Command library (librc, -lrc)
|
||||
.In rc.h
|
||||
.Ft "char *" Fn rc_runlevel_get void
|
||||
.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_starting 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.
|
||||
.Pp
|
||||
Each function that returns
|
||||
.Fr "char **"
|
||||
returns a malloced NULL terminated array of malloced NULL terminated strings,
|
||||
all of which need to be freed using
|
||||
.Fn rc_strlist_free
|
||||
.Fr "RC_STRINGLIST *"
|
||||
should by freed by calling
|
||||
.Fn rc_stringlist_free
|
||||
when done.
|
||||
.Sh FILES
|
||||
.Pa /etc/init.d/functions.sh
|
||||
@ -62,6 +61,6 @@ Rinse and repeat for the other verbose functions.
|
||||
.Sh SEE ALSO
|
||||
.Xr malloc 3 ,
|
||||
.Xr free 3
|
||||
.Xr rc_strlist_free 3
|
||||
.Xr rc_stringlist_free 3
|
||||
.Sh AUTHORS
|
||||
.An "Roy Marples" Aq roy@marples.name
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd Feb 22, 2008
|
||||
.Dd Mar 16, 2008
|
||||
.Dt RC_SERVICE 3 SMM
|
||||
.Os OpenRC
|
||||
.Sh NAME
|
||||
@ -55,17 +55,17 @@ Run Command library (librc, -lrc)
|
||||
.Fc
|
||||
.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_mark "const char *service" "rc_service_state_t state"
|
||||
.Ft "char **" Fn rc_service_extra_commands "const char *service"
|
||||
.Ft bool Fn rc_service_mark "const char *service" "RC_SERVICE state"
|
||||
.Ft "RC_STRINGLIST *" Fn rc_service_extra_commands "const char *service"
|
||||
.Ft bool Fn rc_service_plugable "const char *service"
|
||||
.Ft "char *" rc_service_resolve "const char *service"
|
||||
.Ft bool Fo rc_service_schedule_start
|
||||
.Fa "const char *service"
|
||||
.Fa "const char *service_to_start"
|
||||
.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 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_stop "const char *service"
|
||||
.Ft bool Fo rc_service_started_daemon
|
||||
@ -79,9 +79,9 @@ Run Command library (librc, -lrc)
|
||||
.Fa "const char *option"
|
||||
.Fa "const char *value"
|
||||
.Fc
|
||||
.Ft "char **" Fn rc_services_in_runlevel "const char *runlevel"
|
||||
.Ft "char **" Fn rc_services_in_state "rc_service_state_t state"
|
||||
.Ft "char **" Fn rc_services_scheduled "const char *service"
|
||||
.Ft "RC_STRINGLIST *" Fn rc_services_in_runlevel "const char *runlevel"
|
||||
.Ft "RC_STRINGLIST *" Fn rc_services_in_state "RC_SERVICE state"
|
||||
.Ft "RC_STRINGLIST *" Fn rc_services_scheduled "const char *service"
|
||||
.Ft bool Fn rc_service_daemons_crashed "const char *service"
|
||||
.Sh DESCRIPTION
|
||||
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.
|
||||
.Pp
|
||||
Each function that returns
|
||||
.Fr "char **"
|
||||
returns a malloced NULL terminated array of malloced NULL terminated strings,
|
||||
all of which need to be freed using
|
||||
.Fn rc_strlist_free
|
||||
.Fr "RC_STRINGLIST *"
|
||||
should be freed using
|
||||
.Fn rc_stringlist_free
|
||||
when done.
|
||||
.Pp
|
||||
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 malloc 3 ,
|
||||
.Xr free 3
|
||||
.Xr rc_strlist_free 3 ,
|
||||
.Xr rc_stringlist_free 3 ,
|
||||
.Xr start-stop-daemon 8
|
||||
.Sh AUTHORS
|
||||
.An "Roy Marples" Aq roy@marples.name
|
||||
|
104
man/rc_strlist.3
104
man/rc_strlist.3
@ -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
|
@ -56,7 +56,7 @@
|
||||
|
||||
#define RC_LIBDIR RC_PREFIX "/" LIB "/rc"
|
||||
#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_INITDIR RC_PREFIX SYSCONFDIR "/init.d"
|
||||
#define RC_CONFDIR RC_PREFIX SYSCONFDIR "/conf.d"
|
||||
@ -98,6 +98,43 @@
|
||||
# define _unused
|
||||
#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)
|
||||
{
|
||||
void *value = malloc(size);
|
||||
@ -154,8 +191,8 @@ _unused static bool existss (const char *pathname)
|
||||
|
||||
char *rc_conf_value(const char *var);
|
||||
bool rc_conf_yesno(const char *var);
|
||||
char **env_filter (void);
|
||||
char **env_config (void);
|
||||
void env_filter(void);
|
||||
void env_config(void);
|
||||
bool service_plugable(const char *service);
|
||||
int signal_setup(int sig, void (*handler)(int));
|
||||
|
||||
|
@ -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__ */
|
@ -60,13 +60,13 @@ typedef enum
|
||||
ECOLOR_BAD = 4,
|
||||
ECOLOR_HILITE = 5,
|
||||
ECOLOR_BRACKET = 6
|
||||
} einfo_color_t;
|
||||
} ECOLOR;
|
||||
|
||||
/*! @brief Returns the ASCII code for the color */
|
||||
const char *ecolor (einfo_color_t);
|
||||
const char *ecolor(ECOLOR);
|
||||
|
||||
/*! @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.
|
||||
@ -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.
|
||||
*/
|
||||
/*@{*/
|
||||
int einfon (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ewarnn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int eerrorn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int einfo (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ewarn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
void ewarnx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF;
|
||||
int eerror (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
void eerrorx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF;
|
||||
int einfon(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ewarnn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int eerrorn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int einfo(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ewarn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
void ewarnx(const char * __EINFO_RESTRICT, ...) __EINFO_XPRINTF;
|
||||
int eerror(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
void eerrorx(const char * __EINFO_RESTRICT, ...) __EINFO_XPRINTF;
|
||||
|
||||
int einfovn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ewarnvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ebeginvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int eendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
int ewendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
int einfov (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ewarnv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int einfovn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ewarnvn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ebeginvn(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int eendvn(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
int ewendvn(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
int einfov(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ewarnv(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
/*@}*/
|
||||
|
||||
/*! @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 */
|
||||
/*@{*/
|
||||
int ebeginv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ebegin (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF;
|
||||
int ebeginv(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
int ebegin(const char * __EINFO_RESTRICT, ...) __EINFO_PRINTF;
|
||||
/*@}*/
|
||||
|
||||
/*! @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 */
|
||||
/*@{*/
|
||||
int eend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
int ewend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
void ebracket (int __col, einfo_color_t __color, const char * __EINFO_RESTRICT __msg);
|
||||
int eend(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
int ewend(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
void ebracket(int, ECOLOR, const char * __EINFO_RESTRICT);
|
||||
|
||||
int eendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
int ewendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF;
|
||||
int eendv(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
int ewendv(int, const char * __EINFO_RESTRICT, ...) __EEND_PRINTF;
|
||||
/*@}*/
|
||||
|
||||
/*! @ingroup eindent
|
||||
@ -139,6 +139,6 @@ void eindentv (void);
|
||||
void eoutdentv(void);
|
||||
|
||||
/*! @brief Prefix each einfo line with something */
|
||||
void eprefix (const char * __EINFO_RESTRICT __prefix);
|
||||
void eprefix(const char * __EINFO_RESTRICT);
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@ const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
@ -52,6 +53,7 @@ const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
|
||||
#include "einfo.h"
|
||||
#include "hidden-visibility.h"
|
||||
|
||||
hidden_proto(ecolor)
|
||||
hidden_proto(ebegin)
|
||||
hidden_proto(ebeginv)
|
||||
@ -119,7 +121,7 @@ static const char *_eprefix = NULL;
|
||||
/* Buffers and structures to hold the final colours */
|
||||
static char ebuffer[100];
|
||||
struct ecolor {
|
||||
einfo_color_t color;
|
||||
ECOLOR color;
|
||||
int def;
|
||||
const char *name;
|
||||
};
|
||||
@ -210,7 +212,7 @@ static size_t strlcat (char *dst, const char *src, size_t size)
|
||||
src_n = size - dst_n;
|
||||
|
||||
if (src_n == 0)
|
||||
return (dst_n + strlen (src));
|
||||
return dst_n + strlen(src);
|
||||
|
||||
while (*s != '\0') {
|
||||
if (src_n != 1) {
|
||||
@ -221,7 +223,7 @@ static size_t strlcat (char *dst, const char *src, size_t size)
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return (dst_n + (s - src));
|
||||
return dst_n + (s - src);
|
||||
}
|
||||
|
||||
static size_t strlcpy(char *dst, const char *src, size_t size)
|
||||
@ -241,7 +243,7 @@ static size_t strlcpy (char *dst, const char *src, size_t size)
|
||||
while (*src++);
|
||||
}
|
||||
|
||||
return (src - s - 1);
|
||||
return src - s - 1;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
@ -250,7 +252,7 @@ static bool yesno (const char *value)
|
||||
{
|
||||
if (! value) {
|
||||
errno = ENOENT;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcasecmp(value, "yes") == 0 ||
|
||||
@ -258,7 +260,7 @@ static bool yesno (const char *value)
|
||||
strcasecmp(value, "true") == 0 ||
|
||||
strcasecmp(value, "on") == 0 ||
|
||||
strcasecmp(value, "1") == 0)
|
||||
return (true);
|
||||
return true;
|
||||
|
||||
if (strcasecmp(value, "no") != 0 &&
|
||||
strcasecmp(value, "n") != 0 &&
|
||||
@ -267,7 +269,7 @@ static bool yesno (const char *value)
|
||||
strcasecmp(value, "0") != 0)
|
||||
errno = EINVAL;
|
||||
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool noyes(const char *value)
|
||||
@ -282,17 +284,17 @@ static bool noyes (const char *value)
|
||||
errno = serrno;
|
||||
}
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool is_quiet()
|
||||
static bool is_quiet(void)
|
||||
{
|
||||
return (yesno (getenv ("EINFO_QUIET")));
|
||||
return yesno(getenv("EINFO_QUIET"));
|
||||
}
|
||||
|
||||
static bool is_verbose()
|
||||
static bool is_verbose(void)
|
||||
{
|
||||
return (yesno (getenv ("EINFO_VERBOSE")));
|
||||
return yesno(getenv ("EINFO_VERBOSE"));
|
||||
}
|
||||
|
||||
/* Fake tgoto call - very crapy, but works for our needs */
|
||||
@ -302,7 +304,7 @@ static char *tgoto (const char *cap, int a, int b)
|
||||
static char buf[20];
|
||||
|
||||
snprintf(buf, sizeof(buf), cap, b, a);
|
||||
return (buf);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -322,22 +324,22 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
|
||||
unsigned int i = 0;
|
||||
|
||||
if (f && ! isatty(fileno(f)))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (noyes(getenv("EINFO_COLOR")))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (in_colour == 0)
|
||||
return (false);
|
||||
return false;
|
||||
if (in_colour == 1)
|
||||
return (true);
|
||||
return true;
|
||||
|
||||
term_is_cons25 = false;
|
||||
|
||||
if (! term) {
|
||||
term = getenv("TERM");
|
||||
if (! term)
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(term, "cons25") == 0)
|
||||
@ -372,7 +374,7 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
|
||||
|
||||
if (in_colour != 1) {
|
||||
in_colour = 0;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (! _af)
|
||||
@ -392,7 +394,7 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
|
||||
|
||||
if (! _af || ! _ce || ! _me || !_md || ! _up) {
|
||||
in_colour = 0;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Many termcap databases don't have ch or RI even though they
|
||||
@ -447,15 +449,15 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
|
||||
ecolors_str[i] = &nullstr;
|
||||
}
|
||||
|
||||
_GET_CAP (tmp, _ce)
|
||||
_ASSIGN_CAP (flush)
|
||||
_GET_CAP(tmp, _ce);
|
||||
_ASSIGN_CAP(flush);
|
||||
_GET_CAP(tmp, _up);
|
||||
_ASSIGN_CAP(up);
|
||||
strlcpy(tmp, _ch, sizeof(tmp));
|
||||
_ASSIGN_CAP(goto_column);
|
||||
|
||||
in_colour = 1;
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_term_columns(FILE * __EINFO_RESTRICT stream)
|
||||
@ -468,13 +470,13 @@ static int get_term_columns (FILE * __EINFO_RESTRICT stream)
|
||||
if (env) {
|
||||
i = strtoimax(env, &p, 10);
|
||||
if (! *p)
|
||||
return (i);
|
||||
return i;
|
||||
}
|
||||
|
||||
if (ioctl(fileno(stream), TIOCGWINSZ, &ws) == 0)
|
||||
return (ws.ws_col);
|
||||
return ws.ws_col;
|
||||
|
||||
return (DEFAULT_COLS);
|
||||
return DEFAULT_COLS;
|
||||
}
|
||||
|
||||
void eprefix(const char *__EINFO_RESTRICT prefix)
|
||||
@ -528,26 +530,26 @@ static int _eindent (FILE * __EINFO_RESTRICT stream)
|
||||
|
||||
/* Terminate it */
|
||||
memset(indent + amount, 0, 1);
|
||||
return (fprintf (stream, "%s", indent));
|
||||
return fprintf(stream, "%s", indent);
|
||||
}
|
||||
|
||||
static const char *_ecolor (FILE * __EINFO_RESTRICT f, einfo_color_t color)
|
||||
static const char *_ecolor(FILE * __EINFO_RESTRICT f, ECOLOR color)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (! colour_terminal(f))
|
||||
return ("");
|
||||
return "";
|
||||
|
||||
for (i = 0; i < sizeof(ecolors) / sizeof(ecolors[0]); i++) {
|
||||
if (ecolors[i].color == color)
|
||||
return (ecolors_str[i]);
|
||||
return ecolors_str[i];
|
||||
}
|
||||
|
||||
return ("");
|
||||
return "";
|
||||
}
|
||||
hidden_def(ecolor)
|
||||
|
||||
const char *ecolor (einfo_color_t color)
|
||||
const char *ecolor(ECOLOR color)
|
||||
{
|
||||
FILE *f = stdout;
|
||||
|
||||
@ -561,7 +563,7 @@ const char *ecolor (einfo_color_t color)
|
||||
}
|
||||
}
|
||||
|
||||
return (_ecolor (f, color));
|
||||
return _ecolor(f, color);
|
||||
}
|
||||
|
||||
#define LASTCMD(_cmd) { \
|
||||
@ -594,7 +596,7 @@ static int _einfovn (const char *__EINFO_RESTRICT fmt, va_list ap)
|
||||
int retval = 0;
|
||||
|
||||
EINFOVN(stdout, ECOLOR_GOOD);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int _ewarnvn(const char *__EINFO_RESTRICT fmt, va_list ap)
|
||||
@ -602,7 +604,7 @@ static int _ewarnvn (const char *__EINFO_RESTRICT fmt, va_list ap)
|
||||
int retval = 0;
|
||||
|
||||
EINFOVN(stderr, ECOLOR_WARN);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int _eerrorvn(const char *__EINFO_RESTRICT fmt, va_list ap)
|
||||
@ -610,7 +612,7 @@ static int _eerrorvn (const char *__EINFO_RESTRICT fmt, va_list ap)
|
||||
int retval = 0;
|
||||
|
||||
EINFOVN(stderr, ECOLOR_BAD);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int einfon(const char *__EINFO_RESTRICT fmt, ...)
|
||||
@ -619,7 +621,7 @@ int einfon (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || is_quiet())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -627,7 +629,7 @@ int einfon (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("einfon");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(einfon)
|
||||
|
||||
@ -637,7 +639,7 @@ int ewarnn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || is_quiet())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _ewarnvn(fmt, ap);
|
||||
@ -645,7 +647,7 @@ int ewarnn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewarnn");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewarnn)
|
||||
|
||||
@ -660,7 +662,7 @@ int eerrorn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("errorn");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(eerrorn)
|
||||
|
||||
@ -670,7 +672,7 @@ int einfo (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || is_quiet())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -679,7 +681,7 @@ int einfo (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("einfo");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(einfo)
|
||||
|
||||
@ -689,7 +691,7 @@ int ewarn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || is_quiet())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
elogv(LOG_WARNING, fmt, ap);
|
||||
@ -699,7 +701,7 @@ int ewarn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewarn");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewarn)
|
||||
|
||||
@ -725,7 +727,7 @@ int eerror (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
elogv(LOG_ERR, fmt, ap);
|
||||
@ -735,7 +737,7 @@ int eerror (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("eerror");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(eerror)
|
||||
|
||||
@ -761,7 +763,7 @@ int ebegin (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || is_quiet())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -772,11 +774,11 @@ int ebegin (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ebegin");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ebegin)
|
||||
|
||||
static void _eend (FILE * __EINFO_RESTRICT fp, int col, einfo_color_t color,
|
||||
static void _eend(FILE * __EINFO_RESTRICT fp, int col, ECOLOR color,
|
||||
const char *msg)
|
||||
{
|
||||
int i;
|
||||
@ -831,7 +833,7 @@ static int _do_eend (const char *cmd, int retval, const char *__EINFO_RESTRICT f
|
||||
_eend(fp, col,
|
||||
retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD,
|
||||
retval == 0 ? OK : NOT_OK);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int eend(int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
@ -839,7 +841,7 @@ int eend (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (is_quiet())
|
||||
return (retval);
|
||||
return retval;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_do_eend("eend", retval, fmt, ap);
|
||||
@ -847,7 +849,7 @@ int eend (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("eend");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(eend)
|
||||
|
||||
@ -856,7 +858,7 @@ int ewend (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (is_quiet())
|
||||
return (retval);
|
||||
return retval;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_do_eend("ewend", retval, fmt, ap);
|
||||
@ -864,11 +866,11 @@ int ewend (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewend");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewend)
|
||||
|
||||
void ebracket (int col, einfo_color_t color, const char *msg)
|
||||
void ebracket(int col, ECOLOR color, const char *msg)
|
||||
{
|
||||
_eend(stdout, col, color, msg);
|
||||
}
|
||||
@ -929,7 +931,7 @@ int einfovn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || ! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -937,7 +939,7 @@ int einfovn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("einfovn");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(einfovn)
|
||||
|
||||
@ -947,7 +949,7 @@ int ewarnvn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || ! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _ewarnvn(fmt, ap);
|
||||
@ -955,7 +957,7 @@ int ewarnvn (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewarnvn");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewarnvn)
|
||||
|
||||
@ -965,7 +967,7 @@ int einfov (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || ! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -974,7 +976,7 @@ int einfov (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("einfov");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(einfov)
|
||||
|
||||
@ -984,7 +986,7 @@ int ewarnv (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || ! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _ewarnvn(fmt, ap);
|
||||
@ -993,7 +995,7 @@ int ewarnv (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewarnv");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewarnv)
|
||||
|
||||
@ -1003,7 +1005,7 @@ int ebeginv (const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! fmt || ! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
retval = _einfovn(fmt, ap);
|
||||
@ -1014,7 +1016,7 @@ int ebeginv (const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ebeginv");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ebeginv)
|
||||
|
||||
@ -1023,7 +1025,7 @@ int eendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_do_eend("eendv", retval, fmt, ap);
|
||||
@ -1031,7 +1033,7 @@ int eendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("eendv");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(eendv)
|
||||
|
||||
@ -1040,7 +1042,7 @@ int ewendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
if (! is_verbose())
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_do_eend("ewendv", retval, fmt, ap);
|
||||
@ -1048,7 +1050,7 @@ int ewendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
|
||||
|
||||
LASTCMD("ewendv");
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
hidden_def(ewendv)
|
||||
|
||||
|
4
src/librc/.gitignore
vendored
4
src/librc/.gitignore
vendored
@ -3,12 +3,12 @@ librc.o
|
||||
librc-daemon.o
|
||||
librc-depend.o
|
||||
librc-misc.o
|
||||
librc-strlist.o
|
||||
librc-stringlist.o
|
||||
librc.So
|
||||
librc-daemon.So
|
||||
librc-depend.So
|
||||
librc-misc.So
|
||||
librc-strlist.So
|
||||
librc-stringlist.So
|
||||
librc.a
|
||||
librc.so.1
|
||||
librc.so
|
||||
|
@ -4,7 +4,7 @@ include ${MK}/os.mk
|
||||
LIB= rc
|
||||
SHLIB_MAJOR= 1
|
||||
SRCS= librc.c librc-daemon.c librc-depend.c librc-misc.c \
|
||||
librc-strlist.c
|
||||
librc-stringlist.c
|
||||
INCS= rc.h
|
||||
VERSION_MAP= rc.map
|
||||
|
||||
|
@ -40,14 +40,14 @@ static bool pid_is_cmd (pid_t pid, const char *cmd)
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
|
||||
if ((fp = fopen(buffer, "r")) == NULL)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
while ((c = getc(fp)) != EOF && c != '(')
|
||||
;
|
||||
|
||||
if (c != '(') {
|
||||
fclose(fp);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((c = getc(fp)) != EOF && c == *cmd)
|
||||
@ -55,7 +55,7 @@ static bool pid_is_cmd (pid_t pid, const char *cmd)
|
||||
|
||||
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)
|
||||
@ -66,28 +66,27 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
|
||||
int fd = -1;
|
||||
int r;
|
||||
|
||||
/* Check it's the right binary */
|
||||
snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
#if 0
|
||||
if (readlink(cmdline, buffer, sizeof(buffer)) != -1) {
|
||||
if (strcmp (exec, buffer) == 0)
|
||||
return (true);
|
||||
if (strcmp(*argv, buffer) == 0)
|
||||
return true;
|
||||
|
||||
/* We should cater for deleted binaries too */
|
||||
if (strlen(buffer) > 10) {
|
||||
p = buffer + (strlen(buffer) - 10);
|
||||
if (strcmp(p, " (deleted)") == 0) {
|
||||
*p = 0;
|
||||
if (strcmp (buffer, exec) == 0)
|
||||
return (true);
|
||||
if (strcmp(buffer, *argv) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
|
||||
if ((fd = open(cmdline, O_RDONLY)) < 0)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
r = read(fd, buffer, sizeof(buffer));
|
||||
close(fd);
|
||||
@ -99,13 +98,13 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
|
||||
p = buffer;
|
||||
while (*argv) {
|
||||
if (strcmp(*argv, p) != 0)
|
||||
return (false);
|
||||
return false;
|
||||
argv++;
|
||||
p += strlen(p) + 1;
|
||||
if ((unsigned) (p - buffer) > sizeof (buffer))
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
pid_t *rc_find_pids(const char *const *argv, const char *cmd,
|
||||
@ -123,7 +122,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
char *pp;
|
||||
|
||||
if ((procdir = opendir("/proc")) == NULL)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
We never match RC_RUNSCRIPT_PID if present so we avoid the below
|
||||
@ -168,7 +167,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
free(pids);
|
||||
closedir(procdir);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
pids = tmp;
|
||||
|
||||
@ -178,7 +177,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
}
|
||||
closedir(procdir);
|
||||
|
||||
return (pids);
|
||||
return pids;
|
||||
}
|
||||
librc_hidden_def(rc_find_pids)
|
||||
|
||||
@ -218,6 +217,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
char **pargv;
|
||||
pid_t *pids = NULL;
|
||||
pid_t *tmp;
|
||||
pid_t p;
|
||||
const char *const *arg;
|
||||
int npids = 0;
|
||||
int match;
|
||||
@ -226,7 +226,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
NULL, _KVM_FLAGS, errbuf)) == NULL)
|
||||
{
|
||||
fprintf(stderr, "kvm_open: %s\n", errbuf);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _KVM_GETPROC2
|
||||
@ -237,11 +237,11 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) {
|
||||
fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd));
|
||||
kvm_close(kd);
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < processes; i++) {
|
||||
pid_t p = _GET_KINFO_PID (kp[i]);
|
||||
p = _GET_KINFO_PID(kp[i]);
|
||||
if (pid != 0 && pid != p)
|
||||
continue;
|
||||
|
||||
@ -277,7 +277,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
free(pids);
|
||||
kvm_close(kd);
|
||||
errno = ENOMEM;
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
pids = tmp;
|
||||
|
||||
@ -287,7 +287,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
}
|
||||
kvm_close(kd);
|
||||
|
||||
return (pids);
|
||||
return pids;
|
||||
}
|
||||
librc_hidden_def(rc_find_pids)
|
||||
|
||||
@ -295,33 +295,39 @@ librc_hidden_def(rc_find_pids)
|
||||
# error "Platform not supported!"
|
||||
#endif
|
||||
|
||||
static bool _match_daemon (const char *path, const char *file, char **match)
|
||||
static bool _match_daemon(const char *path, const char *file,
|
||||
RC_STRINGLIST *match)
|
||||
{
|
||||
char *line;
|
||||
char *ffile = rc_strcatpaths(path, file, (char *) NULL);
|
||||
FILE *fp;
|
||||
RC_STRING *m;
|
||||
|
||||
fp = fopen(ffile, "r");
|
||||
free(ffile);
|
||||
|
||||
if (! fp)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
while ((line = rc_getline(fp))) {
|
||||
rc_strlist_delete (&match, line);
|
||||
if (! match || !*match)
|
||||
TAILQ_FOREACH(m, match, entries)
|
||||
if (strcmp(line, m->value) == 0) {
|
||||
TAILQ_REMOVE(match, m, entries);
|
||||
break;
|
||||
}
|
||||
if (! TAILQ_FIRST(match))
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
if (match && *match)
|
||||
return (false);
|
||||
return (true);
|
||||
if (TAILQ_FIRST(match))
|
||||
return false;
|
||||
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)
|
||||
{
|
||||
char **match = NULL;
|
||||
RC_STRINGLIST *match = rc_stringlist_new();
|
||||
int i = 0;
|
||||
size_t l;
|
||||
char *m;
|
||||
@ -330,7 +336,7 @@ static char **_match_list (const char* const* argv,
|
||||
l = strlen(*argv) + strlen("argv_=") + 16;
|
||||
m = xmalloc(sizeof(char) * l);
|
||||
snprintf(m, l, "argv_0=%s", argv[i++]);
|
||||
rc_strlist_add (&match, m);
|
||||
rc_stringlist_add(match, m);
|
||||
free(m);
|
||||
}
|
||||
|
||||
@ -338,7 +344,7 @@ static char **_match_list (const char* const* argv,
|
||||
l = strlen(name) + 6;
|
||||
m = xmalloc(sizeof (char) * l);
|
||||
snprintf(m, l, "name=%s", name);
|
||||
rc_strlist_add (&match, m);
|
||||
rc_stringlist_add(match, m);
|
||||
free(m);
|
||||
}
|
||||
|
||||
@ -346,16 +352,15 @@ static char **_match_list (const char* const* argv,
|
||||
l = strlen(pidfile) + 9;
|
||||
m = xmalloc(sizeof (char) * l);
|
||||
snprintf(m, l, "pidfile=%s", pidfile);
|
||||
rc_strlist_add (&match, m);
|
||||
rc_stringlist_add(match, m);
|
||||
free (m);
|
||||
}
|
||||
|
||||
return (match);
|
||||
return match;
|
||||
}
|
||||
|
||||
bool rc_service_daemon_set(const char *service, const char *const *argv,
|
||||
const char *name, const char *pidfile,
|
||||
bool started)
|
||||
const char *name, const char *pidfile, bool started)
|
||||
{
|
||||
char *dirpath;
|
||||
char *file = NULL;
|
||||
@ -364,12 +369,14 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
|
||||
bool retval = false;
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
char **match = NULL;
|
||||
RC_STRINGLIST *match;
|
||||
int i = 0;
|
||||
char buffer[10];
|
||||
FILE *fp;
|
||||
|
||||
if (!(argv && *argv) && ! name && ! pidfile) {
|
||||
errno = EINVAL;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons",
|
||||
@ -403,9 +410,6 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
|
||||
|
||||
/* Now store our daemon info */
|
||||
if (started) {
|
||||
char buffer[10];
|
||||
FILE *fp;
|
||||
|
||||
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
|
||||
snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1);
|
||||
file = rc_strcatpaths(dirpath, buffer, (char *) NULL);
|
||||
@ -429,26 +433,27 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
|
||||
} else
|
||||
retval = true;
|
||||
|
||||
rc_strlist_free (match);
|
||||
rc_stringlist_free(match);
|
||||
free(dirpath);
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_daemon_set)
|
||||
|
||||
bool rc_service_started_daemon (const char *service, const char *const *argv,
|
||||
bool
|
||||
rc_service_started_daemon (const char *service, const char *const *argv,
|
||||
int indx)
|
||||
{
|
||||
char *dirpath;
|
||||
char *file;
|
||||
size_t l;
|
||||
char **match;
|
||||
RC_STRINGLIST *match;
|
||||
bool retval = false;
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
|
||||
if (!service || !(argv && *argv))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
|
||||
(char *) NULL);
|
||||
@ -475,8 +480,8 @@ bool rc_service_started_daemon (const char *service, const char *const *argv,
|
||||
}
|
||||
|
||||
free(dirpath);
|
||||
rc_strlist_free (match);
|
||||
return (retval);
|
||||
rc_stringlist_free(match);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_started_daemon)
|
||||
|
||||
@ -497,16 +502,16 @@ bool rc_service_daemons_crashed (const char *service)
|
||||
char *p;
|
||||
char *token;
|
||||
bool retval = false;
|
||||
|
||||
if (! service)
|
||||
return (false);
|
||||
RC_STRINGLIST *list;
|
||||
RC_STRING *s;
|
||||
size_t i;
|
||||
|
||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
|
||||
(char *) NULL);
|
||||
|
||||
if (! (dp = opendir(dirpath))) {
|
||||
free(dirpath);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((d = readdir(dp))) {
|
||||
@ -519,6 +524,8 @@ bool rc_service_daemons_crashed (const char *service)
|
||||
if (! fp)
|
||||
break;
|
||||
|
||||
list = rc_stringlist_new();
|
||||
|
||||
while ((line = rc_getline(fp))) {
|
||||
p = line;
|
||||
if ((token = strsep(&p, "=")) == NULL || ! p) {
|
||||
@ -526,13 +533,13 @@ bool rc_service_daemons_crashed (const char *service)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen (p) == 0) {
|
||||
if (! *p) {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(token, "argv_", 5) == 0) {
|
||||
rc_strlist_add (&argv, p);
|
||||
rc_stringlist_add(list, p);
|
||||
} else if (strcmp(token, "exec") == 0) {
|
||||
if (exec)
|
||||
free(exec);
|
||||
@ -573,40 +580,45 @@ bool rc_service_daemons_crashed (const char *service)
|
||||
pidfile = NULL;
|
||||
|
||||
/* We have the pid, so no need to match on name */
|
||||
rc_strlist_free (argv);
|
||||
argv = NULL;
|
||||
rc_stringlist_free(list);
|
||||
list = NULL;
|
||||
free (exec);
|
||||
exec = NULL;
|
||||
free (name);
|
||||
name = NULL;
|
||||
} else {
|
||||
if (exec && ! TAILQ_FIRST(list)) {
|
||||
rc_stringlist_add(list, exec);
|
||||
}
|
||||
|
||||
if (exec && ! argv) {
|
||||
rc_strlist_add (&argv, exec);
|
||||
free(exec);
|
||||
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;
|
||||
free(pids);
|
||||
free(argv);
|
||||
argv = NULL;
|
||||
rc_stringlist_free(list);
|
||||
free(name);
|
||||
name = NULL;
|
||||
if (retval)
|
||||
break;
|
||||
}
|
||||
free (pids);
|
||||
|
||||
rc_strlist_free (argv);
|
||||
argv = NULL;
|
||||
free (exec);
|
||||
exec = NULL;
|
||||
free (name);
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
rc_strlist_free (argv);
|
||||
free (exec);
|
||||
free (name);
|
||||
free(dirpath);
|
||||
closedir(dp);
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_daemons_crashed)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -35,14 +35,14 @@ bool rc_yesno (const char *value)
|
||||
{
|
||||
if (! value) {
|
||||
errno = ENOENT;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcasecmp (value, "yes") == 0 ||
|
||||
strcasecmp (value, "y") == 0 ||
|
||||
strcasecmp (value, "true") == 0 ||
|
||||
strcasecmp (value, "1") == 0)
|
||||
return (true);
|
||||
return true;
|
||||
|
||||
if (strcasecmp (value, "no") != 0 &&
|
||||
strcasecmp (value, "n") != 0 &&
|
||||
@ -50,7 +50,7 @@ bool rc_yesno (const char *value)
|
||||
strcasecmp (value, "0") != 0)
|
||||
errno = EINVAL;
|
||||
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
librc_hidden_def(rc_yesno)
|
||||
|
||||
@ -64,7 +64,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...)
|
||||
char *pathp;
|
||||
|
||||
if (! path1 || ! paths)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
length = strlen (path1) + strlen (paths) + 1;
|
||||
if (*paths != '/')
|
||||
@ -101,7 +101,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...)
|
||||
|
||||
*pathp++ = 0;
|
||||
|
||||
return (path);
|
||||
return path;
|
||||
}
|
||||
librc_hidden_def(rc_strcatpaths)
|
||||
|
||||
@ -113,7 +113,7 @@ char *rc_getline (FILE *fp)
|
||||
size_t last = 0;
|
||||
|
||||
if (feof (fp))
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
do {
|
||||
len += BUFSIZ;
|
||||
@ -128,20 +128,22 @@ char *rc_getline (FILE *fp)
|
||||
if (*line && line[--last] == '\n')
|
||||
line[last] = '\0';
|
||||
|
||||
return (line);
|
||||
return line;
|
||||
}
|
||||
librc_hidden_def(rc_getline)
|
||||
|
||||
char **rc_config_list (const char *file)
|
||||
RC_STRINGLIST *rc_config_list(const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
char *p;
|
||||
char *token;
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *list;
|
||||
|
||||
if (!(fp = fopen(file, "r")))
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
list = rc_stringlist_new();
|
||||
|
||||
while ((p = buffer = rc_getline(fp))) {
|
||||
/* Strip leading spaces/tabs */
|
||||
@ -157,45 +159,47 @@ char **rc_config_list (const char *file)
|
||||
if (token[strlen(token) - 1] == '\n')
|
||||
token[strlen(token) - 1] = 0;
|
||||
|
||||
rc_strlist_add (&list, token);
|
||||
rc_stringlist_add(list, token);
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
librc_hidden_def(rc_config_list)
|
||||
|
||||
char **rc_config_load (const char *file)
|
||||
RC_STRINGLIST *rc_config_load(const char *file)
|
||||
{
|
||||
char **list = NULL;
|
||||
char **config = NULL;
|
||||
RC_STRINGLIST *list = NULL;
|
||||
RC_STRINGLIST *config = NULL;
|
||||
char *token;
|
||||
char *line;
|
||||
char *linep;
|
||||
char *linetok;
|
||||
RC_STRING *line;
|
||||
RC_STRING *cline;
|
||||
size_t i = 0;
|
||||
int j;
|
||||
bool replaced;
|
||||
char *entry;
|
||||
char *newline;
|
||||
char *p;
|
||||
|
||||
config = rc_stringlist_new();
|
||||
|
||||
list = rc_config_list(file);
|
||||
STRLIST_FOREACH (list, line, j) {
|
||||
TAILQ_FOREACH(line, list, entries) {
|
||||
/* Get entry */
|
||||
if (! (token = strsep (&line, "=")))
|
||||
p = line->value;
|
||||
if (! (token = strsep(&p, "=")))
|
||||
continue;
|
||||
|
||||
entry = xstrdup (token);
|
||||
/* Preserve shell coloring */
|
||||
if (*line == '$')
|
||||
token = line;
|
||||
if (*p == '$')
|
||||
token = line->value;
|
||||
else
|
||||
do {
|
||||
/* Bash variables are usually quoted */
|
||||
token = strsep (&line, "\"\'");
|
||||
token = strsep(&p, "\"\'");
|
||||
} while (token && *token == '\0');
|
||||
|
||||
/* Drop a newline if that's all we have */
|
||||
@ -216,46 +220,43 @@ char **rc_config_load (const char *file)
|
||||
replaced = false;
|
||||
/* In shells the last item takes precedence, so we need to remove
|
||||
any prior values we may already have */
|
||||
STRLIST_FOREACH (config, line, i) {
|
||||
char *tmp = xstrdup (line);
|
||||
linep = tmp;
|
||||
linetok = strsep (&linep, "=");
|
||||
if (strcmp (linetok, entry) == 0) {
|
||||
TAILQ_FOREACH(cline, config, entries) {
|
||||
p = strchr(cline->value, '=');
|
||||
if (p && strncmp(entry, cline->value,
|
||||
(size_t) (p - cline->value)) == 0)
|
||||
{
|
||||
/* We have a match now - to save time we directly replace it */
|
||||
free (config[i - 1]);
|
||||
config[i - 1] = newline;
|
||||
free(cline->value);
|
||||
cline->value = newline;
|
||||
replaced = true;
|
||||
free (tmp);
|
||||
break;
|
||||
}
|
||||
free (tmp);
|
||||
}
|
||||
|
||||
if (! replaced) {
|
||||
rc_strlist_addsort (&config, newline);
|
||||
rc_stringlist_add(config, newline);
|
||||
free(newline);
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
rc_strlist_free (list);
|
||||
rc_stringlist_free(list);
|
||||
|
||||
return (config);
|
||||
return config;
|
||||
}
|
||||
librc_hidden_def(rc_config_load)
|
||||
|
||||
char *rc_config_value (const char *const *list, const char *entry)
|
||||
char *rc_config_value(RC_STRINGLIST *list, const char *entry)
|
||||
{
|
||||
const char *line;
|
||||
int i;
|
||||
RC_STRING *line;
|
||||
char *p;
|
||||
|
||||
STRLIST_FOREACH (list, line, i) {
|
||||
p = strchr (line, '=');
|
||||
if (p && strncmp (entry, line, (size_t) (p - line)) == 0)
|
||||
return (p += 1);
|
||||
TAILQ_FOREACH(line, list, entries) {
|
||||
p = strchr(line->value, '=');
|
||||
if (p &&
|
||||
strncmp(entry, line->value, (size_t)(p - line->value)) == 0)
|
||||
return p += 1;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
librc_hidden_def(rc_config_value)
|
||||
|
||||
|
@ -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)
|
@ -47,7 +47,7 @@ const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
FILE *rc_environ_fd = NULL;
|
||||
|
||||
typedef struct rc_service_state_name {
|
||||
rc_service_state_t state;
|
||||
RC_SERVICE state;
|
||||
const char *name;
|
||||
} rc_service_state_name_t;
|
||||
|
||||
@ -68,46 +68,50 @@ static const rc_service_state_name_t rc_service_state_names[] = {
|
||||
|
||||
#define LS_INITD 0x01
|
||||
#define LS_DIR 0x02
|
||||
static char **ls_dir (const char *dir, int options)
|
||||
static RC_STRINGLIST *ls_dir(const char *dir, int options)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *list;
|
||||
struct stat buf;
|
||||
size_t l;
|
||||
char *file;
|
||||
int r;
|
||||
|
||||
if ((dp = opendir(dir)) == NULL)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
list = rc_stringlist_new();
|
||||
while (((d = readdir(dp)) != NULL)) {
|
||||
if (d->d_name[0] != '.') {
|
||||
if (options & LS_INITD) {
|
||||
int l = strlen (d->d_name);
|
||||
|
||||
/* Check that our file really exists.
|
||||
* This is important as a service maybe in a runlevel, but
|
||||
* could also have been removed. */
|
||||
char *file = rc_strcatpaths (dir, d->d_name, NULL);
|
||||
int ok = stat (file, &buf);
|
||||
file = rc_strcatpaths(dir, d->d_name, NULL);
|
||||
r = stat(file, &buf);
|
||||
free(file);
|
||||
if (ok != 0)
|
||||
if (r != 0)
|
||||
continue;
|
||||
|
||||
/* .sh files are not init scripts */
|
||||
l = strlen(d->d_name);
|
||||
if (l > 2 && d->d_name[l - 3] == '.' &&
|
||||
d->d_name[l - 2] == 's' &&
|
||||
d->d_name[l - 1] == 'h')
|
||||
continue;
|
||||
}
|
||||
if (options & LS_DIR) {
|
||||
if (stat (d->d_name, &buf) == 0 && ! S_ISDIR (buf.st_mode))
|
||||
if (stat(d->d_name, &buf) == 0 &&
|
||||
! S_ISDIR(buf.st_mode))
|
||||
continue;
|
||||
}
|
||||
rc_strlist_addsort (&list, d->d_name);
|
||||
rc_stringlist_add(list, d->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
|
||||
static bool rm_dir(const char *pathname, bool top)
|
||||
@ -119,7 +123,7 @@ static bool rm_dir (const char *pathname, bool top)
|
||||
bool retval = true;
|
||||
|
||||
if ((dp = opendir(pathname)) == NULL)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
errno = 0;
|
||||
while (((d = readdir(dp)) != NULL) && errno == 0) {
|
||||
@ -150,12 +154,12 @@ static bool rm_dir (const char *pathname, bool top)
|
||||
free(tmp);
|
||||
|
||||
if (! retval)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (top && rmdir(pathname) != 0)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Other systems may need this at some point, but for now it's Linux only */
|
||||
@ -169,7 +173,7 @@ static bool file_regex (const char *file, const char *regex)
|
||||
int result;
|
||||
|
||||
if (! (fp = fopen(file, "r")))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
|
||||
fclose(fp);
|
||||
@ -177,7 +181,7 @@ static bool file_regex (const char *file, const char *regex)
|
||||
regerror(result, &re, line, BUFSIZ);
|
||||
fprintf(stderr, "file_regex: %s", line);
|
||||
free(line);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((line = rc_getline(fp))) {
|
||||
@ -190,7 +194,7 @@ static bool file_regex (const char *file, const char *regex)
|
||||
fclose(fp);
|
||||
regfree(&re);
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -198,7 +202,7 @@ static bool file_regex (const char *file, const char *regex)
|
||||
const char *rc_sys(void)
|
||||
{
|
||||
#ifdef PREFIX
|
||||
return (RC_SYS_PREFIX);
|
||||
return RC_SYS_PREFIX;
|
||||
#else
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
@ -207,55 +211,55 @@ const char *rc_sys (void)
|
||||
|
||||
if (sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0) == 0)
|
||||
if (jailed == 1)
|
||||
return (RC_SYS_JAIL);
|
||||
return RC_SYS_JAIL;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
if (exists("/proc/xen")) {
|
||||
if (file_regex("/proc/xen/capabilities", "control_d"))
|
||||
return (RC_SYS_XEN0);
|
||||
return (RC_SYS_XENU);
|
||||
return RC_SYS_XEN0;
|
||||
return RC_SYS_XENU;
|
||||
} else if (file_regex("/proc/cpuinfo", "UML"))
|
||||
return (RC_SYS_UML);
|
||||
return RC_SYS_UML;
|
||||
else if (file_regex("/proc/self/status",
|
||||
"(s_context|VxID):[[:space:]]*[1-9]"))
|
||||
return (RC_SYS_VSERVER);
|
||||
return RC_SYS_VSERVER;
|
||||
else if (file_regex("/proc/self/status",
|
||||
"envID:[[:space:]]*[1-9]"))
|
||||
return (RC_SYS_OPENVZ);
|
||||
return RC_SYS_OPENVZ;
|
||||
#endif
|
||||
|
||||
return (NULL);
|
||||
return NULL;
|
||||
#endif /* PREFIX */
|
||||
}
|
||||
|
||||
static const char *rc_parse_service_state (rc_service_state_t state)
|
||||
static const char *rc_parse_service_state(RC_SERVICE state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; rc_service_state_names[i].name; i++) {
|
||||
if (rc_service_state_names[i].state == state)
|
||||
return (rc_service_state_names[i].name);
|
||||
return rc_service_state_names[i].name;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool rc_runlevel_starting(void)
|
||||
{
|
||||
return (exists (RC_STARTING));
|
||||
return exists(RC_STARTING);
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_starting)
|
||||
|
||||
bool rc_runlevel_stopping(void)
|
||||
{
|
||||
return (exists (RC_STOPPING));
|
||||
return exists(RC_STOPPING);
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_stopping)
|
||||
|
||||
char **rc_runlevel_list (void)
|
||||
RC_STRINGLIST *rc_runlevel_list(void)
|
||||
{
|
||||
return (ls_dir (RC_RUNLEVELDIR, LS_DIR));
|
||||
return ls_dir(RC_RUNLEVELDIR, LS_DIR);
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_list)
|
||||
|
||||
@ -280,7 +284,7 @@ char *rc_runlevel_get (void)
|
||||
runlevel = xstrdup(RC_LEVEL_SYSINIT);
|
||||
}
|
||||
|
||||
return (runlevel);
|
||||
return runlevel;
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_get)
|
||||
|
||||
@ -289,10 +293,10 @@ bool rc_runlevel_set (const char *runlevel)
|
||||
FILE *fp = fopen(SOFTLEVEL, "w");
|
||||
|
||||
if (! fp)
|
||||
return (false);
|
||||
return false;
|
||||
fprintf(fp, "%s", runlevel);
|
||||
fclose(fp);
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_set)
|
||||
|
||||
@ -303,13 +307,13 @@ bool rc_runlevel_exists (const char *runlevel)
|
||||
bool retval = false;
|
||||
|
||||
if (! runlevel)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
path = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
|
||||
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
|
||||
retval = true;
|
||||
free(path);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_runlevel_exists)
|
||||
|
||||
@ -322,10 +326,10 @@ char *rc_service_resolve (const char *service)
|
||||
struct stat buf;
|
||||
|
||||
if (! service)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
if (service[0] == '/')
|
||||
return (xstrdup (service));
|
||||
return xstrdup(service);
|
||||
|
||||
/* First check started services */
|
||||
file = rc_strcatpaths(RC_SVCDIR, "started", service, (char *) NULL);
|
||||
@ -344,14 +348,14 @@ char *rc_service_resolve (const char *service)
|
||||
#ifdef RC_LOCAL_INITDIR
|
||||
snprintf(buffer, sizeof(buffer), RC_LOCAL_INITDIR "/%s", service);
|
||||
if (stat(buffer, &buf) == 0)
|
||||
return (xstrdup (buffer));
|
||||
return xstrdup(buffer);
|
||||
#endif
|
||||
|
||||
if (file) {
|
||||
r = readlink(file, buffer, sizeof(buffer));
|
||||
free(file);
|
||||
if (r > 0)
|
||||
return (xstrdup (buffer));
|
||||
return xstrdup(buffer);
|
||||
}
|
||||
snprintf(buffer, sizeof(buffer), RC_INITDIR "/%s", service);
|
||||
|
||||
@ -360,11 +364,11 @@ char *rc_service_resolve (const char *service)
|
||||
if (stat(buffer, &buf) != 0) {
|
||||
snprintf(buffer, sizeof(buffer), RC_PKG_INITDIR "/%s", service);
|
||||
if (stat(buffer, &buf) != 0)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return (xstrdup (buffer));
|
||||
return xstrdup(buffer);
|
||||
}
|
||||
librc_hidden_def(rc_service_resolve)
|
||||
|
||||
@ -376,7 +380,7 @@ bool rc_service_exists (const char *service)
|
||||
struct stat buf;
|
||||
|
||||
if (! service)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
len = strlen(service);
|
||||
|
||||
@ -384,46 +388,49 @@ bool rc_service_exists (const char *service)
|
||||
if (len > 2 && service[len - 3] == '.' &&
|
||||
service[len - 2] == 's' &&
|
||||
service[len - 1] == 'h')
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (! (file = rc_service_resolve(service)))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO)
|
||||
retval = true;
|
||||
free(file);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_exists)
|
||||
|
||||
#define OPTSTR ". '%s'; echo \"${opts}\""
|
||||
char **rc_service_extra_commands (const char *service)
|
||||
RC_STRINGLIST *rc_service_extra_commands(const char *service)
|
||||
{
|
||||
char *svc;
|
||||
char *cmd = NULL;
|
||||
char *buffer = NULL;
|
||||
char **commands = NULL;
|
||||
RC_STRINGLIST *commands;
|
||||
char *token;
|
||||
char *p;
|
||||
FILE *fp;
|
||||
size_t l;
|
||||
|
||||
if (! (svc = rc_service_resolve(service)))
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
commands = rc_stringlist_new();
|
||||
|
||||
l = strlen(OPTSTR) + strlen(svc) + 1;
|
||||
cmd = xmalloc(sizeof(char) * l);
|
||||
snprintf(cmd, l, OPTSTR, svc);
|
||||
free(svc);
|
||||
|
||||
if ((fp = popen(cmd, "r"))) {
|
||||
p = buffer = rc_getline(fp);
|
||||
while ((token = strsep(&p, " ")))
|
||||
rc_strlist_addsort (&commands, token);
|
||||
rc_stringlist_add(commands, token);
|
||||
pclose(fp);
|
||||
free(buffer);
|
||||
}
|
||||
free(cmd);
|
||||
return (commands);
|
||||
return commands;
|
||||
}
|
||||
librc_hidden_def(rc_service_extra_commands)
|
||||
|
||||
@ -437,7 +444,7 @@ char *rc_service_description (const char *service, const char *option)
|
||||
size_t l;
|
||||
|
||||
if (! (svc = rc_service_resolve(service)))
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
if (! option)
|
||||
option = "";
|
||||
@ -451,7 +458,7 @@ char *rc_service_description (const char *service, const char *option)
|
||||
pclose(fp);
|
||||
}
|
||||
free(cmd);
|
||||
return (desc);
|
||||
return desc;
|
||||
}
|
||||
librc_hidden_def(rc_service_description)
|
||||
|
||||
@ -461,18 +468,18 @@ bool rc_service_in_runlevel (const char *service, const char *runlevel)
|
||||
bool retval;
|
||||
|
||||
if (! runlevel || ! service)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service),
|
||||
(char *) NULL);
|
||||
retval = exists(file);
|
||||
free(file);
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_in_runlevel)
|
||||
|
||||
bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
bool rc_service_mark(const char *service, const RC_SERVICE state)
|
||||
{
|
||||
char *file;
|
||||
int i = 0;
|
||||
@ -480,16 +487,21 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
const char *base;
|
||||
char *init = rc_service_resolve(service);
|
||||
bool skip_wasinactive = false;
|
||||
int s;
|
||||
char *was;
|
||||
RC_STRINGLIST *dirs;
|
||||
RC_STRING *dir;
|
||||
int serrno;
|
||||
|
||||
if (! init)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
base = basename_c(service);
|
||||
|
||||
if (state != RC_SERVICE_STOPPED) {
|
||||
if (! exists(init)) {
|
||||
free(init);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state (state), base,
|
||||
@ -500,7 +512,7 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
if (i != 0) {
|
||||
free(file);
|
||||
free(init);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(file);
|
||||
@ -509,12 +521,12 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
|
||||
if (state == RC_SERVICE_COLDPLUGGED || state == RC_SERVICE_FAILED) {
|
||||
free(init);
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Remove any old states now */
|
||||
for (i = 0; rc_service_state_names[i].name; i++) {
|
||||
int s = rc_service_state_names[i].state;
|
||||
s = rc_service_state_names[i].state;
|
||||
|
||||
if ((s != skip_state &&
|
||||
s != RC_SERVICE_STOPPED &&
|
||||
@ -529,13 +541,13 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
state == RC_SERVICE_STOPPING) &&
|
||||
s == RC_SERVICE_INACTIVE)
|
||||
{
|
||||
char *wasfile = rc_strcatpaths (RC_SVCDIR,
|
||||
was = rc_strcatpaths(RC_SVCDIR,
|
||||
rc_parse_service_state(RC_SERVICE_WASINACTIVE),
|
||||
base, (char *) NULL);
|
||||
|
||||
symlink (init, wasfile);
|
||||
symlink(init, was);
|
||||
skip_wasinactive = true;
|
||||
free (wasfile);
|
||||
free(was);
|
||||
}
|
||||
unlink(file);
|
||||
}
|
||||
@ -555,52 +567,52 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
|
||||
|
||||
/* Remove any options and daemons the service may have stored */
|
||||
if (state == RC_SERVICE_STOPPED) {
|
||||
char *dir = rc_strcatpaths (RC_SVCDIR, "options", base, (char *) NULL);
|
||||
rm_dir (dir, true);
|
||||
free (dir);
|
||||
file = rc_strcatpaths(RC_SVCDIR, "options", base, (char *) NULL);
|
||||
rm_dir(file, true);
|
||||
free(file);
|
||||
|
||||
dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL);
|
||||
rm_dir (dir, true);
|
||||
free (dir);
|
||||
file = rc_strcatpaths(RC_SVCDIR, "daemons", base, (char *) NULL);
|
||||
rm_dir(file, true);
|
||||
free(file);
|
||||
|
||||
rc_service_schedule_clear(service);
|
||||
}
|
||||
|
||||
/* These are final states, so remove us from scheduled */
|
||||
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
|
||||
char *sdir = rc_strcatpaths (RC_SVCDIR, "scheduled", (char *) NULL);
|
||||
char **dirs = ls_dir (sdir, 0);
|
||||
char *dir;
|
||||
int serrno;
|
||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled", (char *) NULL);
|
||||
dirs = ls_dir(file, 0);
|
||||
|
||||
STRLIST_FOREACH (dirs, dir, i) {
|
||||
char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL);
|
||||
file = rc_strcatpaths (bdir, base, (char *) NULL);
|
||||
unlink (file);
|
||||
free (file);
|
||||
TAILQ_FOREACH(dir, dirs, entries) {
|
||||
was = rc_strcatpaths(file, dir->value, base, (char *) NULL);
|
||||
unlink(was);
|
||||
free(was);
|
||||
|
||||
/* Try and remove the dir - we don't care about errors */
|
||||
was = rc_strcatpaths(file, dir->value, (char *) NULL);
|
||||
serrno = errno;
|
||||
rmdir (bdir);
|
||||
rmdir(was);
|
||||
errno = serrno;
|
||||
free (bdir);
|
||||
free(was);
|
||||
}
|
||||
rc_strlist_free (dirs);
|
||||
free (sdir);
|
||||
rc_stringlist_free(dirs);
|
||||
}
|
||||
|
||||
free(init);
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
librc_hidden_def(rc_service_mark)
|
||||
|
||||
rc_service_state_t rc_service_state (const char *service)
|
||||
RC_SERVICE rc_service_state(const char *service)
|
||||
{
|
||||
int i;
|
||||
int state = RC_SERVICE_STOPPED;
|
||||
char *file;
|
||||
RC_STRINGLIST *dirs;
|
||||
RC_STRING *dir;
|
||||
|
||||
for (i = 0; rc_service_state_names[i].name; i++) {
|
||||
char *file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i].name,
|
||||
file = rc_strcatpaths(RC_SVCDIR, rc_service_state_names[i].name,
|
||||
basename_c(service), (char*) NULL);
|
||||
if (exists(file)) {
|
||||
if (rc_service_state_names[i].state <= 0x10)
|
||||
@ -612,14 +624,21 @@ rc_service_state_t rc_service_state (const char *service)
|
||||
}
|
||||
|
||||
if (state & RC_SERVICE_STOPPED) {
|
||||
char **services = rc_services_scheduled_by (service);
|
||||
if (services) {
|
||||
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
||||
TAILQ_FOREACH (dir, dirs, entries) {
|
||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled",
|
||||
dir->value,
|
||||
service, (char *) NULL);
|
||||
if (exists(file))
|
||||
state |= RC_SERVICE_SCHEDULED;
|
||||
free (services);
|
||||
free(file);
|
||||
if (state & RC_SERVICE_SCHEDULED)
|
||||
break;
|
||||
}
|
||||
rc_stringlist_free(dirs);
|
||||
}
|
||||
|
||||
return (state);
|
||||
return state;
|
||||
}
|
||||
librc_hidden_def(rc_service_state)
|
||||
|
||||
@ -636,7 +655,7 @@ char *rc_service_value_get (const char *service, const char *option)
|
||||
}
|
||||
free(file);
|
||||
|
||||
return (line);
|
||||
return line;
|
||||
}
|
||||
librc_hidden_def(rc_service_value_get)
|
||||
|
||||
@ -651,7 +670,7 @@ bool rc_service_value_set (const char *service, const char *option,
|
||||
if (mkdir(path, 0755) != 0 && errno != EEXIST) {
|
||||
free(path);
|
||||
free(file);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((fp = fopen(file, "w"))) {
|
||||
@ -663,7 +682,7 @@ bool rc_service_value_set (const char *service, const char *option,
|
||||
|
||||
free(path);
|
||||
free(file);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_value_set)
|
||||
|
||||
@ -680,7 +699,7 @@ static pid_t _exec_service (const char *service, const char *arg)
|
||||
if (! exists(file)) {
|
||||
rc_service_mark(service, RC_SERVICE_STOPPED);
|
||||
free(file);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We create a fifo so that other services can wait until we complete */
|
||||
@ -690,7 +709,7 @@ static pid_t _exec_service (const char *service, const char *arg)
|
||||
if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) {
|
||||
free(fifo);
|
||||
free(file);
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We need to block signals until we have forked */
|
||||
@ -729,34 +748,34 @@ static pid_t _exec_service (const char *service, const char *arg)
|
||||
free(fifo);
|
||||
free(file);
|
||||
|
||||
return (pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
pid_t rc_service_stop(const char *service)
|
||||
{
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
|
||||
if (state & RC_SERVICE_FAILED)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if (state & RC_SERVICE_STOPPED)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
return (_exec_service (service, "stop"));
|
||||
return _exec_service(service, "stop");
|
||||
}
|
||||
librc_hidden_def(rc_service_stop)
|
||||
|
||||
pid_t rc_service_start(const char *service)
|
||||
{
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
|
||||
if (state & RC_SERVICE_FAILED)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if (! state & RC_SERVICE_STOPPED)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
return (_exec_service (service, "start"));
|
||||
return _exec_service(service, "start");
|
||||
}
|
||||
librc_hidden_def(rc_service_start)
|
||||
|
||||
@ -770,13 +789,13 @@ bool rc_service_schedule_start (const char *service,
|
||||
|
||||
/* service may be a provided service, like net */
|
||||
if (! service || ! rc_service_exists(service_to_start))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
|
||||
(char *) NULL);
|
||||
if (mkdir(dir, 0755) != 0 && errno != EEXIST) {
|
||||
free(dir);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
init = rc_service_resolve(service_to_start);
|
||||
@ -786,7 +805,7 @@ bool rc_service_schedule_start (const char *service,
|
||||
free(file);
|
||||
free(dir);
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_schedule_start)
|
||||
|
||||
@ -799,86 +818,81 @@ bool rc_service_schedule_clear (const char *service)
|
||||
if (! (retval = rm_dir(dir, true)) && errno == ENOENT)
|
||||
retval = true;
|
||||
free(dir);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_schedule_clear)
|
||||
|
||||
|
||||
char **rc_services_in_runlevel (const char *runlevel)
|
||||
RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
|
||||
{
|
||||
char *dir;
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *list;
|
||||
|
||||
if (! runlevel) {
|
||||
#if defined(RC_PKG_INITDIR) || defined(RC_LOCAL_INITDIR)
|
||||
int i;
|
||||
#endif
|
||||
#ifdef RC_PKG_INITDIR
|
||||
char **pkg = ls_dir (RC_PKG_INITDIR, LS_INITD);
|
||||
RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD);
|
||||
#endif
|
||||
#ifdef RC_LOCAL_INITDIR
|
||||
char **local = ls_dir (RC_LOCAL_INITDIR, LS_INITD);
|
||||
RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD);
|
||||
#endif
|
||||
|
||||
list = ls_dir(RC_INITDIR, LS_INITD);
|
||||
|
||||
#ifdef RC_PKG_INITDIR
|
||||
STRLIST_FOREACH (pkg, dir, i)
|
||||
rc_strlist_addsortu (&list, dir);
|
||||
rc_strlist_free (pkg);
|
||||
if (pkg) {
|
||||
TAILQ_CONCAT(list, pkg);
|
||||
free(pkg);
|
||||
}
|
||||
#endif
|
||||
#ifdef RC_LOCAL_DIR
|
||||
STRLIST_FOREACH (local, dir, i)
|
||||
rc_strlist_addsortu (&list, dir);
|
||||
rc_strlist_free (local);
|
||||
if (local) {
|
||||
TAILQ_CONCAT(list, local);
|
||||
free(local);
|
||||
}
|
||||
#endif
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/* These special levels never contain any services */
|
||||
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
|
||||
strcmp (runlevel, RC_LEVEL_SINGLE) == 0)
|
||||
return (NULL);
|
||||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
|
||||
list = rc_stringlist_new();
|
||||
return list;
|
||||
}
|
||||
|
||||
dir = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
|
||||
list = ls_dir(dir, LS_INITD);
|
||||
free(dir);
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
librc_hidden_def(rc_services_in_runlevel)
|
||||
|
||||
char **rc_services_in_state (rc_service_state_t state)
|
||||
RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
|
||||
{
|
||||
char *dir = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(state),
|
||||
(char *) NULL);
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *services;
|
||||
RC_STRINGLIST *list;
|
||||
RC_STRINGLIST *dirs;
|
||||
RC_STRING *d;
|
||||
char *p;
|
||||
|
||||
if (state == RC_SERVICE_SCHEDULED) {
|
||||
char **dirs = ls_dir (dir, 0);
|
||||
char *d;
|
||||
int i;
|
||||
|
||||
STRLIST_FOREACH (dirs, d, i) {
|
||||
char *p = rc_strcatpaths (dir, d, (char *) NULL);
|
||||
char **entries = ls_dir (p, LS_INITD);
|
||||
char *e;
|
||||
int j;
|
||||
|
||||
STRLIST_FOREACH (entries, e, j)
|
||||
rc_strlist_addsortu (&list, e);
|
||||
|
||||
if (entries)
|
||||
free (entries);
|
||||
dirs = ls_dir(dir, 0);
|
||||
list = rc_stringlist_new();
|
||||
TAILQ_FOREACH(d, dirs, entries) {
|
||||
p = rc_strcatpaths(dir, d->value, (char *) NULL);
|
||||
services = ls_dir(p, LS_INITD);
|
||||
free(p);
|
||||
TAILQ_CONCAT(list, services);
|
||||
free(services);
|
||||
}
|
||||
|
||||
if (dirs)
|
||||
free (dirs);
|
||||
rc_stringlist_free(dirs);
|
||||
} else {
|
||||
list = ls_dir(dir, LS_INITD);
|
||||
}
|
||||
|
||||
free(dir);
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
librc_hidden_def(rc_services_in_state)
|
||||
|
||||
@ -887,15 +901,17 @@ bool rc_service_add (const char *runlevel, const char *service)
|
||||
bool retval;
|
||||
char *init;
|
||||
char *file;
|
||||
char path[MAXPATHLEN] = { '\0' };
|
||||
char *p;
|
||||
|
||||
if (! rc_runlevel_exists(runlevel)) {
|
||||
errno = ENOENT;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rc_service_in_runlevel(service, runlevel)) {
|
||||
errno = EEXIST;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
init = rc_service_resolve(service);
|
||||
@ -903,18 +919,15 @@ bool rc_service_add (const char *runlevel, const char *service)
|
||||
/* We need to ensure that only things in /etc/init.d are added
|
||||
* to the boot runlevel */
|
||||
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) {
|
||||
char tmp[MAXPATHLEN] = { '\0' };
|
||||
char *p;
|
||||
|
||||
p = realpath (dirname (init), tmp);
|
||||
p = realpath(dirname (init), path);
|
||||
free(init);
|
||||
if (! *p)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
retval = (strcmp (tmp, RC_INITDIR) == 0);
|
||||
retval = (strcmp(path, RC_INITDIR) == 0);
|
||||
if (! retval) {
|
||||
errno = EPERM;
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
init = rc_strcatpaths(RC_INITDIR, service, (char *) NULL);
|
||||
}
|
||||
@ -924,7 +937,7 @@ bool rc_service_add (const char *runlevel, const char *service)
|
||||
retval = (symlink(init, file) == 0);
|
||||
free(init);
|
||||
free(file);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_add)
|
||||
|
||||
@ -934,7 +947,7 @@ bool rc_service_delete (const char *runlevel, const char *service)
|
||||
bool retval = false;
|
||||
|
||||
if (! runlevel || ! service)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c(service),
|
||||
(char *) NULL);
|
||||
@ -942,38 +955,38 @@ bool rc_service_delete (const char *runlevel, const char *service)
|
||||
retval = true;
|
||||
|
||||
free(file);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
librc_hidden_def(rc_service_delete)
|
||||
|
||||
char **rc_services_scheduled_by (const char *service)
|
||||
RC_STRINGLIST *rc_services_scheduled_by(const char *service)
|
||||
{
|
||||
char **dirs = ls_dir (RC_SVCDIR "/scheduled", 0);
|
||||
char **list = NULL;
|
||||
char *dir;
|
||||
int i;
|
||||
RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
||||
RC_STRINGLIST *list;
|
||||
RC_STRING *dir;
|
||||
char *file;
|
||||
|
||||
STRLIST_FOREACH (dirs, dir, i) {
|
||||
char *file = rc_strcatpaths (RC_SVCDIR, "scheduled", dir, service,
|
||||
(char *) NULL);
|
||||
list = rc_stringlist_new();
|
||||
TAILQ_FOREACH (dir, dirs, entries) {
|
||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled", dir->value,
|
||||
service, (char *) NULL);
|
||||
if (exists(file))
|
||||
rc_strlist_add (&list, file);
|
||||
rc_stringlist_add(list, file);
|
||||
free(file);
|
||||
}
|
||||
rc_strlist_free (dirs);
|
||||
rc_stringlist_free(dirs);
|
||||
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
librc_hidden_def(rc_services_scheduled_by)
|
||||
|
||||
char **rc_services_scheduled (const char *service)
|
||||
RC_STRINGLIST *rc_services_scheduled(const char *service)
|
||||
{
|
||||
char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
|
||||
(char *) NULL);
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *list = ls_dir(dir, LS_INITD);
|
||||
|
||||
list = ls_dir (dir, LS_INITD);
|
||||
free(dir);
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
librc_hidden_def(rc_services_scheduled)
|
||||
|
@ -64,10 +64,8 @@
|
||||
#include <kvm.h>
|
||||
#endif
|
||||
|
||||
#include "librc-depend.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#include "hidden-visibility.h"
|
||||
#define librc_hidden_proto(x) hidden_proto(x)
|
||||
@ -115,15 +113,11 @@ librc_hidden_proto(rc_service_state)
|
||||
librc_hidden_proto(rc_service_value_get)
|
||||
librc_hidden_proto(rc_service_value_set)
|
||||
librc_hidden_proto(rc_strcatpaths)
|
||||
librc_hidden_proto(rc_strlist_add)
|
||||
librc_hidden_proto(rc_strlist_addu)
|
||||
librc_hidden_proto(rc_strlist_addsort)
|
||||
librc_hidden_proto(rc_strlist_addsortc)
|
||||
librc_hidden_proto(rc_strlist_addsortu)
|
||||
librc_hidden_proto(rc_strlist_delete)
|
||||
librc_hidden_proto(rc_strlist_free)
|
||||
librc_hidden_proto(rc_strlist_join)
|
||||
librc_hidden_proto(rc_strlist_reverse)
|
||||
librc_hidden_proto(rc_stringlist_add)
|
||||
librc_hidden_proto(rc_stringlist_addu)
|
||||
librc_hidden_proto(rc_stringlist_delete)
|
||||
librc_hidden_proto(rc_stringlist_free)
|
||||
librc_hidden_proto(rc_stringlist_sort)
|
||||
librc_hidden_proto(rc_yesno)
|
||||
|
||||
#endif
|
||||
|
188
src/librc/rc.h
188
src/librc/rc.h
@ -32,15 +32,24 @@
|
||||
# if (GCC_VERSION >= 3005)
|
||||
# define SENTINEL __attribute__ ((__sentinel__))
|
||||
# endif
|
||||
# define DEPRECATED __attribute__ ((deprecated))
|
||||
#endif
|
||||
#ifndef SENTINEL
|
||||
# define SENTINEL
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* A doubly linked list using queue(3) for ease of use */
|
||||
typedef struct rc_string {
|
||||
char *value;
|
||||
TAILQ_ENTRY(rc_string) entries;
|
||||
} RC_STRING;
|
||||
typedef TAILQ_HEAD(rc_stringlist, rc_string) RC_STRINGLIST;
|
||||
|
||||
/*! @name Reserved runlevel names */
|
||||
#define RC_LEVEL_SYSINIT "sysinit"
|
||||
#define RC_LEVEL_SINGLE "single"
|
||||
@ -54,17 +63,17 @@ char *rc_runlevel_get (void);
|
||||
/*! Checks if the runlevel exists or not
|
||||
* @param runlevel to check
|
||||
* @return true if the runlevel exists, otherwise false */
|
||||
bool rc_runlevel_exists (const char *runlevel);
|
||||
bool rc_runlevel_exists(const char *);
|
||||
|
||||
/*! Return a NULL terminated list of runlevels
|
||||
* @return a NULL terminated list of runlevels */
|
||||
char **rc_runlevel_list (void);
|
||||
RC_STRINGLIST *rc_runlevel_list(void);
|
||||
|
||||
/*! Set the runlevel.
|
||||
* This just changes the stored runlevel and does not start or stop any
|
||||
* services.
|
||||
* @param runlevel to store */
|
||||
bool rc_runlevel_set (const char *runlevel);
|
||||
bool rc_runlevel_set(const char *);
|
||||
|
||||
/*! Is the runlevel starting?
|
||||
* @return true if yes, otherwise false */
|
||||
@ -97,19 +106,19 @@ typedef enum
|
||||
RC_SERVICE_FAILED = 0x0200,
|
||||
RC_SERVICE_SCHEDULED = 0x0400,
|
||||
RC_SERVICE_WASINACTIVE = 0x0800
|
||||
} rc_service_state_t;
|
||||
} RC_SERVICE;
|
||||
|
||||
/*! Add the service to the runlevel
|
||||
* @param runlevel to add to
|
||||
* @param service to add
|
||||
* @return true if successful, otherwise false */
|
||||
bool rc_service_add (const char *runlevel, const char *service);
|
||||
bool rc_service_add(const char *, const char *);
|
||||
|
||||
/*! Remove the service from the runlevel
|
||||
* @param runlevel to remove from
|
||||
* @param service to remove
|
||||
* @return true if sucessful, otherwise false */
|
||||
bool rc_service_delete (const char *runlevel, const char *service);
|
||||
bool rc_service_delete(const char *, const char *);
|
||||
|
||||
/*! Save the arguments to find a running daemon
|
||||
* @param service to save arguments for
|
||||
@ -117,116 +126,113 @@ bool rc_service_delete (const char *runlevel, const char *service);
|
||||
* @param name of the process (optional)
|
||||
* @param pidfile of the process (optional)
|
||||
* @param started if true, add the arguments otherwise remove existing matching arguments */
|
||||
bool rc_service_daemon_set (const char *service, const char *const *argv,
|
||||
const char *name, const char *pidfile,
|
||||
bool started);
|
||||
bool rc_service_daemon_set(const char *, const char *const *, const char *, const char *,
|
||||
bool);
|
||||
|
||||
/*! Returns a description of what the service and/or option does.
|
||||
* @param service to check
|
||||
* @param option to check (if NULL, service description)
|
||||
* @return a newly allocated pointer to the description */
|
||||
char *rc_service_description (const char *service, const char *option);
|
||||
char *rc_service_description(const char *, const char *);
|
||||
|
||||
/*! Checks if a service exists or not.
|
||||
* @param service to check
|
||||
* @return true if service exists, otherwise false */
|
||||
bool rc_service_exists (const char *service);
|
||||
bool rc_service_exists(const char *);
|
||||
|
||||
/*! Checks if a service is in a runlevel
|
||||
* @param service to check
|
||||
* @param runlevel it should be in
|
||||
* @return true if service is in the runlevel, otherwise false */
|
||||
bool rc_service_in_runlevel (const char *service, const char *runlevel);
|
||||
bool rc_service_in_runlevel(const char *, const char *);
|
||||
|
||||
/*! Marks the service state
|
||||
* @param service to mark
|
||||
* @param state service should be in
|
||||
* @return true if service state change was successful, otherwise false */
|
||||
bool rc_service_mark (const char *service, rc_service_state_t state);
|
||||
bool rc_service_mark(const char *, RC_SERVICE);
|
||||
|
||||
/*! Lists the extra commands a service has
|
||||
* @param service to load the commands from
|
||||
* @return NULL terminated string list of commands */
|
||||
char **rc_service_extra_commands (const char *service);
|
||||
RC_STRINGLIST *rc_service_extra_commands(const char *);
|
||||
|
||||
/*! Resolves a service name to its full path.
|
||||
* @param service to check
|
||||
* @return pointer to full path of service */
|
||||
char *rc_service_resolve (const char *service);
|
||||
char *rc_service_resolve(const char *);
|
||||
|
||||
/*! Schedule a service to be started when another service starts
|
||||
* @param service that starts the scheduled service when started
|
||||
* @param service_to_start service that will be started */
|
||||
bool rc_service_schedule_start (const char *service,
|
||||
const char *service_to_start);
|
||||
bool rc_service_schedule_start(const char *, const char *);
|
||||
|
||||
/*! Return a NULL terminated list of services that are scheduled to start
|
||||
* when the given service has started
|
||||
* @param service to check
|
||||
* @return NULL terminated list of services scheduled to start */
|
||||
char **rc_services_scheduled_by (const char *service);
|
||||
RC_STRINGLIST *rc_services_scheduled_by(const char *);
|
||||
|
||||
/*! Clear the list of services scheduled to be started by this service
|
||||
* @param service to clear
|
||||
* @return true if no errors, otherwise false */
|
||||
bool rc_service_schedule_clear (const char *service);
|
||||
bool rc_service_schedule_clear(const char *);
|
||||
|
||||
/*! Checks if a service in in a state
|
||||
* @param service to check
|
||||
* @return state of the service */
|
||||
rc_service_state_t rc_service_state (const char *service);
|
||||
RC_SERVICE rc_service_state(const char *);
|
||||
|
||||
/*! Start a service
|
||||
* @param service to start
|
||||
* @return pid of the service starting process */
|
||||
pid_t rc_service_start (const char *service);
|
||||
pid_t rc_service_start(const char *);
|
||||
|
||||
/*! Stop a service
|
||||
* @param service to stop
|
||||
* @return pid of service stopping process */
|
||||
pid_t rc_service_stop (const char *service);
|
||||
pid_t rc_service_stop(const char *);
|
||||
|
||||
/*! Check if the service started the daemon
|
||||
* @param service to check
|
||||
* @param exec to check
|
||||
* @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc)
|
||||
* @return true if started by this service, otherwise false */
|
||||
bool rc_service_started_daemon (const char *service, const char *const *argv,
|
||||
int indx);
|
||||
bool rc_service_started_daemon(const char *, const char *const *, int);
|
||||
|
||||
/*! Return a saved value for a service
|
||||
* @param service to check
|
||||
* @param option to load
|
||||
* @return saved value */
|
||||
char *rc_service_value_get (const char *service, const char *option);
|
||||
char *rc_service_value_get(const char *, const char *);
|
||||
|
||||
/*! Save a persistent value for a service
|
||||
* @param service to save for
|
||||
* @param option to save
|
||||
* @param value of the option
|
||||
* @return true if saved, otherwise false */
|
||||
bool rc_service_value_set (const char *service, const char *option,
|
||||
const char *value);
|
||||
bool rc_service_value_set(const char *, const char *, const char *);
|
||||
|
||||
/*! List the services in a runlevel
|
||||
* @param runlevel to list
|
||||
* @return NULL terminated list of services */
|
||||
char **rc_services_in_runlevel (const char *runlevel);
|
||||
RC_STRINGLIST *rc_services_in_runlevel(const char *);
|
||||
|
||||
/*! List the services in a state
|
||||
* @param state to list
|
||||
* @return NULL terminated list of services */
|
||||
char **rc_services_in_state (rc_service_state_t state);
|
||||
RC_STRINGLIST *rc_services_in_state(RC_SERVICE);
|
||||
|
||||
/*! List the services shceduled to start when this one does
|
||||
* @param service to check
|
||||
* @return NULL terminated list of services */
|
||||
char **rc_services_scheduled (const char *service);
|
||||
RC_STRINGLIST *rc_services_scheduled(const char *);
|
||||
|
||||
/*! Checks that all daemons started with start-stop-daemon by the service
|
||||
* are still running.
|
||||
* @param service to check
|
||||
* @return true if all daemons started are still running, otherwise false */
|
||||
bool rc_service_daemons_crashed (const char *service);
|
||||
bool rc_service_daemons_crashed(const char *);
|
||||
|
||||
/*! @name System types
|
||||
* OpenRC can support some special sub system types, normally virtualization.
|
||||
@ -256,15 +262,43 @@ const char *rc_sys (void);
|
||||
* We analyse each init script and cache the resultant dependency tree.
|
||||
* This tree can be accessed using the below functions. */
|
||||
|
||||
#ifndef _IN_LIBRC
|
||||
#ifdef _IN_LIBRC
|
||||
/*! @name Dependency structures
|
||||
* private to librc */
|
||||
|
||||
/*! Singly linked list of dependency types that list the services the
|
||||
* type is for */
|
||||
typedef struct rc_deptype
|
||||
{
|
||||
/*! ineed, iuse, iafter, etc */
|
||||
char *type;
|
||||
/*! list of services */
|
||||
RC_STRINGLIST *services;
|
||||
/*! list of types */
|
||||
STAILQ_ENTRY(rc_deptype) entries;
|
||||
} RC_DEPTYPE;
|
||||
|
||||
/*! Singly linked list of services and their dependencies */
|
||||
typedef struct rc_depinfo
|
||||
{
|
||||
/*! Name of service */
|
||||
char *service;
|
||||
/*! Dependencies */
|
||||
STAILQ_HEAD(, rc_deptype) depends;
|
||||
/*! List of entries */
|
||||
STAILQ_ENTRY(rc_depinfo) entries;
|
||||
} RC_DEPINFO;
|
||||
|
||||
typedef STAILQ_HEAD(,rc_depinfo) RC_DEPTREE;
|
||||
#else
|
||||
/* Handles to internal structures */
|
||||
typedef void *rc_depinfo_t;
|
||||
typedef void *RC_DEPTREE;
|
||||
#endif
|
||||
|
||||
/*! Check to see if source is newer than target.
|
||||
* If target is a directory then we traverse it and it's children.
|
||||
* @return true if source is newer than target, otherwise false */
|
||||
bool rc_newer_than (const char *source, const char *target);
|
||||
bool rc_newer_than(const char *, const char *);
|
||||
|
||||
/*! Update the cached dependency tree if it's older than any init script,
|
||||
* its configuration file or an external configuration file the init script
|
||||
@ -281,15 +315,14 @@ bool rc_deptree_update_needed (void);
|
||||
/*! Load the cached dependency tree and return a pointer to it.
|
||||
* This pointer should be freed with rc_deptree_free when done.
|
||||
* @return pointer to the dependency tree */
|
||||
rc_depinfo_t *rc_deptree_load (void);
|
||||
RC_DEPTREE *rc_deptree_load(void);
|
||||
|
||||
/*! List the depend for the type of service
|
||||
* @param deptree to search
|
||||
* @param type to use (keywords, etc)
|
||||
* @param service to check
|
||||
* @return NULL terminated list of services in order */
|
||||
char **rc_deptree_depend (const rc_depinfo_t *deptree,
|
||||
const char *type, const char *service);
|
||||
RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *, const char *, const char *);
|
||||
|
||||
/*! List all the services in order that the given services have
|
||||
* for the given types and options.
|
||||
@ -298,10 +331,8 @@ char **rc_deptree_depend (const rc_depinfo_t *deptree,
|
||||
* @param services to check
|
||||
* @param options to pass
|
||||
* @return NULL terminated list of services in order */
|
||||
char **rc_deptree_depends (const rc_depinfo_t *deptree,
|
||||
const char *const *types,
|
||||
const char *const *services, const char *runlevel,
|
||||
int options);
|
||||
RC_STRINGLIST *rc_deptree_depends(const RC_DEPTREE *, const RC_STRINGLIST *,
|
||||
const RC_STRINGLIST *, const char *, int);
|
||||
|
||||
/*! List all the services that should be stoppned and then started, in order,
|
||||
* for the given runlevel, including sysinit and boot services where
|
||||
@ -310,12 +341,11 @@ char **rc_deptree_depends (const rc_depinfo_t *deptree,
|
||||
* @param runlevel to change into
|
||||
* @param options to pass
|
||||
* @return NULL terminated list of services in order */
|
||||
char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel,
|
||||
int options);
|
||||
RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *, const char *, int);
|
||||
|
||||
/*! Free a deptree and its information
|
||||
* @param deptree to free */
|
||||
void rc_deptree_free (rc_depinfo_t *deptree);
|
||||
void rc_deptree_free(RC_DEPTREE *);
|
||||
|
||||
/*! @name Plugins
|
||||
* For each plugin loaded we will call rc_plugin_hook with the below
|
||||
@ -347,13 +377,13 @@ typedef enum
|
||||
RC_HOOK_SERVICE_START_NOW = 106,
|
||||
RC_HOOK_SERVICE_START_DONE = 107,
|
||||
RC_HOOK_SERVICE_START_OUT = 108
|
||||
} rc_hook_t;
|
||||
} RC_HOOK;
|
||||
|
||||
/*! Plugin entry point
|
||||
* @param hook point
|
||||
* @param name of runlevel or service
|
||||
* @return 0 for success otherwise -1 */
|
||||
int rc_plugin_hook (rc_hook_t hook, const char *name);
|
||||
int rc_plugin_hook(RC_HOOK, const char *);
|
||||
|
||||
/*! Plugins should write FOO=BAR to this fd to set any environment
|
||||
* variables they wish. Variables should be separated by NULLs. */
|
||||
@ -362,91 +392,64 @@ extern FILE *rc_environ_fd;
|
||||
/*! @name Configuration
|
||||
* These functions help to deal with shell based configuration files */
|
||||
/*! Return a line from a file, stripping the trailing newline. */
|
||||
char *rc_getline (FILE *fp);
|
||||
char *rc_getline(FILE *);
|
||||
|
||||
/*! Return a NULL terminated list of non comment lines from a file. */
|
||||
char **rc_config_list (const char *file);
|
||||
RC_STRINGLIST *rc_config_list(const char *);
|
||||
|
||||
/*! Return a NULL terminated list of key=value lines from a file. */
|
||||
char **rc_config_load (const char *file);
|
||||
RC_STRINGLIST *rc_config_load(const char *);
|
||||
|
||||
/*! Return the value of the entry from a key=value list. */
|
||||
char *rc_config_value (const char *const *list, const char *entry);
|
||||
char *rc_config_value(RC_STRINGLIST *, const char *);
|
||||
|
||||
/*! Check if a variable is a boolean and return it's value.
|
||||
* If variable is not a boolean then we set errno to be ENOENT when it does
|
||||
* not exist or EINVAL if it's not a boolean.
|
||||
* @param variable to check
|
||||
* @return true if it matches true, yes or 1, false if otherwise. */
|
||||
bool rc_yesno (const char *variable);
|
||||
bool rc_yesno(const char *);
|
||||
|
||||
/*! @name String List functions
|
||||
* Handy functions for dealing with string arrays of char **.
|
||||
* It's safe to assume that any function here that uses char ** is a string
|
||||
* list that can be manipulated with the below functions. Every string list
|
||||
* should be released with a call to rc_strlist_free. */
|
||||
* Every string list should be released with a call to rc_stringlist_free. */
|
||||
|
||||
/*! Create a new stringlinst
|
||||
* @return pointer to new list */
|
||||
RC_STRINGLIST *rc_stringlist_new(void);
|
||||
|
||||
/*! Duplicate the item, add it to end of the list and return a pointer to it.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return pointer to newly added item */
|
||||
char *rc_strlist_add (char ***list, const char *item);
|
||||
RC_STRING *rc_stringlist_add(RC_STRINGLIST *, const char *);
|
||||
|
||||
/*! If the item does not exist in the list, duplicate it, add it to the
|
||||
* list and then return a pointer to it.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return pointer to newly added item */
|
||||
char *rc_strlist_addu (char ***list, const char *item);
|
||||
|
||||
/*! Duplicate the item, add it to the list at the point based on locale and
|
||||
* then return a pointer to it.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return pointer to newly added item */
|
||||
char *rc_strlist_addsort (char ***list, const char *item);
|
||||
|
||||
/*! Duplicate the item, add it to the list at the point based on C locale and
|
||||
* then return a pointer to it.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return pointer to newly added item */
|
||||
char *rc_strlist_addsortc (char ***list, const char *item);
|
||||
|
||||
/*! If the item does not exist in the list, duplicate it, add it to the
|
||||
* list based on locale and then return a pointer to it.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return pointer to newly added item */
|
||||
char *rc_strlist_addsortu (char ***list, const char *item);
|
||||
RC_STRING *rc_stringlist_addu(RC_STRINGLIST *, const char *);
|
||||
|
||||
/*! Free the item and remove it from the list. Return 0 on success otherwise -1.
|
||||
* @param list to add the item too
|
||||
* @param item to add.
|
||||
* @return true on success, otherwise false */
|
||||
bool rc_strlist_delete (char ***list, const char *item);
|
||||
bool rc_stringlist_delete(RC_STRINGLIST *, const char *);
|
||||
|
||||
/*! Moves the contents of list2 onto list1, so list2 is effectively emptied.
|
||||
* Returns a pointer to the last item on the new list.
|
||||
* @param list1 to append to
|
||||
* @param list2 to move from
|
||||
* @return pointer to the last item on the list */
|
||||
char *rc_strlist_join (char ***list1, char **list2);
|
||||
|
||||
/*! Reverses the contents of the list.
|
||||
* @param list to reverse */
|
||||
void rc_strlist_reverse (char **list);
|
||||
/*! Sort the list according to C locale
|
||||
* @param list to sort */
|
||||
void rc_stringlist_sort(RC_STRINGLIST **);
|
||||
|
||||
/*! Frees each item on the list and the list itself.
|
||||
* @param list to free */
|
||||
void rc_strlist_free (char **list);
|
||||
void rc_stringlist_free(RC_STRINGLIST *);
|
||||
|
||||
/*! Concatenate paths adding '/' if needed. The resultant pointer should be
|
||||
* freed when finished with.
|
||||
* @param path1 starting path
|
||||
* @param paths NULL terminated list of paths to add
|
||||
* @return pointer to the new path */
|
||||
char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL;
|
||||
char *rc_strcatpaths(const char *, const char *, ...) SENTINEL;
|
||||
|
||||
/*! Find processes based on criteria.
|
||||
* All of these are optional.
|
||||
@ -457,7 +460,6 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL;
|
||||
* @param uid to check for
|
||||
* @param pid to check for
|
||||
* @return NULL terminated list of pids */
|
||||
pid_t *rc_find_pids (const char *const *argv, const char *cmd,
|
||||
uid_t uid, pid_t pid);
|
||||
pid_t *rc_find_pids(const char *const *, const char *, uid_t, pid_t);
|
||||
|
||||
#endif
|
||||
|
@ -43,15 +43,12 @@ global:
|
||||
rc_service_value_get;
|
||||
rc_service_value_set;
|
||||
rc_strcatpaths;
|
||||
rc_strlist_add;
|
||||
rc_strlist_addu;
|
||||
rc_strlist_addsort;
|
||||
rc_strlist_addsortc;
|
||||
rc_strlist_addsortu;
|
||||
rc_strlist_delete;
|
||||
rc_strlist_free;
|
||||
rc_strlist_join;
|
||||
rc_strlist_reverse;
|
||||
rc_stringlist_add;
|
||||
rc_stringlist_addu;
|
||||
rc_stringlist_delete;
|
||||
rc_stringlist_new;
|
||||
rc_stringlist_sort;
|
||||
rc_stringlist_free;
|
||||
rc_sys;
|
||||
rc_yesno;
|
||||
|
||||
|
4
src/rc/.gitignore
vendored
4
src/rc/.gitignore
vendored
@ -55,6 +55,7 @@ rc-abort
|
||||
checkpath.o
|
||||
fstabinfo.o
|
||||
mountinfo.o
|
||||
start-stop-daemon.o
|
||||
rc-applets.o
|
||||
rc-depend.o
|
||||
rc-logger.o
|
||||
@ -62,8 +63,7 @@ rc-misc.o
|
||||
rc-plugin.o
|
||||
rc-status.o
|
||||
rc-update.o
|
||||
rc.o
|
||||
runscript.o
|
||||
start-stop-daemon.o
|
||||
rc.o
|
||||
rc
|
||||
.depend
|
||||
|
@ -1,8 +1,8 @@
|
||||
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-misc.c rc-plugin.c rc-status.c rc-update.c rc.c \
|
||||
runscript.c start-stop-daemon.c
|
||||
rc-misc.c rc-plugin.c rc-status.c rc-update.c \
|
||||
runscript.c rc.c
|
||||
|
||||
CLEANFILES= version.h
|
||||
|
||||
@ -31,8 +31,9 @@ ALL_LINKS= ${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS}
|
||||
CLEANFILES+= ${ALL_LINKS}
|
||||
|
||||
LDFLAGS+= -L../librc -L../libeinfo
|
||||
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
|
||||
LDADD+= -lutil -lrc -leinfo
|
||||
#CFLAGS+= -ggdb
|
||||
#LDFLAGS+= -Wl,--rpath=../librc -Wl,--rpath=../libeinfo
|
||||
|
||||
MK= ../../mk
|
||||
include ${MK}/cc.mk
|
||||
|
@ -37,6 +37,10 @@ _noreturn static void usage (int exit_status)
|
||||
{
|
||||
const char * const has_arg[] = { "", "<arg>", "[arg]" };
|
||||
int i;
|
||||
int len;
|
||||
char *lo;
|
||||
char *p;
|
||||
char *token;
|
||||
|
||||
#ifdef usagestring
|
||||
printf(usagestring);
|
||||
@ -48,13 +52,10 @@ _noreturn static void usage (int exit_status)
|
||||
#endif
|
||||
printf("\n\nOptions: [" getoptstring "]\n");
|
||||
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]);
|
||||
|
||||
char *lo = xstrdup (longopts_help[i]);
|
||||
char *p = lo;
|
||||
char *token;
|
||||
|
||||
lo = p = xstrdup(longopts_help[i]);
|
||||
while ((token = strsep(&p, "\n"))) {
|
||||
while (++len < 37)
|
||||
printf(" ");
|
||||
|
@ -38,4 +38,4 @@ int start_stop_daemon (int argc, char **argv);
|
||||
void run_applets (int argc, char **argv);
|
||||
|
||||
/* 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);
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
@ -51,16 +52,14 @@ extern const char *applet;
|
||||
static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, int file)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
memset (&st, 0, sizeof (st));
|
||||
int fd;
|
||||
|
||||
if (stat(path, &st)) {
|
||||
if (file) {
|
||||
int fd;
|
||||
einfo("%s: creating file", path);
|
||||
if ((fd = open(path, O_CREAT)) == -1) {
|
||||
eerror("%s: open: %s", applet, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
close (fd);
|
||||
} else {
|
||||
@ -69,7 +68,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
|
||||
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
|
||||
if (mkdir(path, mode)) {
|
||||
eerror("%s: mkdir: %s", applet, strerror (errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
mode = 0;
|
||||
}
|
||||
@ -81,7 +80,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
|
||||
eerror("%s: is a directory", path);
|
||||
else
|
||||
eerror("%s: is a file", path);
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +88,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
|
||||
einfo("%s: correcting mode", applet);
|
||||
if (chmod(path, mode)) {
|
||||
eerror("%s: chmod: %s", applet, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,31 +97,33 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
|
||||
einfo("%s: correcting owner", path);
|
||||
if (chown(path, uid, gid)) {
|
||||
eerror("%s: chown: %s", applet, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Based on busybox */
|
||||
static int parse_mode (mode_t *mode, char *text)
|
||||
{
|
||||
char *p;
|
||||
unsigned long l;
|
||||
|
||||
/* Check for a numeric mode */
|
||||
if ((*text - '0') < 8) {
|
||||
char *p;
|
||||
unsigned long l = strtoul (text, &p, 8);
|
||||
l = strtoul(text, &p, 8);
|
||||
if (*p || l > 07777U) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
*mode = (mode_t) l;
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We currently don't check g+w type stuff */
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_owner(struct passwd **user, struct group **group,
|
||||
@ -155,7 +156,7 @@ static int parse_owner (struct passwd **user, struct group **group,
|
||||
}
|
||||
|
||||
free(u);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
@ -200,13 +201,11 @@ int checkpath (int argc, char **argv)
|
||||
break;
|
||||
case 'm':
|
||||
if (parse_mode(&mode, optarg) != 0)
|
||||
eerrorx ("%s: invalid mode `%s'",
|
||||
applet, optarg);
|
||||
eerrorx("%s: invalid mode `%s'", applet, optarg);
|
||||
break;
|
||||
case 'o':
|
||||
if (parse_owner(&pw, &gr, optarg) != 0)
|
||||
eerrorx ("%s: owner `%s' not found",
|
||||
applet, optarg);
|
||||
eerrorx("%s: owner `%s' not found", applet, optarg);
|
||||
break;
|
||||
|
||||
case_RC_COMMON_GETOPT
|
||||
|
@ -30,6 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
@ -72,12 +73,11 @@
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#ifdef HAVE_GETMNTENT
|
||||
static struct mntent *getmntfile(const char *file)
|
||||
{
|
||||
struct mntent *ent = NULL;
|
||||
struct mntent *ent;
|
||||
FILE *fp;
|
||||
|
||||
START_ENT;
|
||||
@ -86,7 +86,7 @@ static struct mntent *getmntfile (const char *file)
|
||||
break;
|
||||
END_ENT;
|
||||
|
||||
return (ent);
|
||||
return ent;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -108,21 +108,19 @@ static int do_mount (struct ENT *ent)
|
||||
argv[7] = NULL;
|
||||
switch (pid = vfork()) {
|
||||
case -1:
|
||||
eerrorx ("%s: vfork: %s", applet,
|
||||
strerror (errno));
|
||||
eerrorx("%s: vfork: %s", applet, strerror(errno));
|
||||
/* NOTREACHED */
|
||||
case 0:
|
||||
execvp(argv[0], argv);
|
||||
eerror ("%s: execv: %s", applet,
|
||||
strerror (errno));
|
||||
eerror("%s: execv: %s", applet, strerror(errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
waitpid(pid, &status, 0);
|
||||
if (WIFEXITED(status))
|
||||
return (WEXITSTATUS(status));
|
||||
return WEXITSTATUS(status);
|
||||
else
|
||||
return (-1);
|
||||
return -1;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
@ -163,8 +161,8 @@ int fstabinfo (int argc, char **argv)
|
||||
int i;
|
||||
int opt;
|
||||
int output = OUTPUT_FILE;
|
||||
char **files = NULL;
|
||||
char *file;
|
||||
RC_STRINGLIST *files = rc_stringlist_new();
|
||||
RC_STRING *file;
|
||||
bool filtered = false;
|
||||
|
||||
#ifdef HAVE_GETMNTENT
|
||||
@ -197,7 +195,8 @@ int fstabinfo (int argc, char **argv)
|
||||
case '<':
|
||||
case '>':
|
||||
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;
|
||||
@ -206,13 +205,13 @@ int fstabinfo (int argc, char **argv)
|
||||
(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));
|
||||
rc_stringlist_add(files, ENT_FILE(ent));
|
||||
}
|
||||
END_ENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc_strlist_add (&files, optarg);
|
||||
rc_stringlist_add(files, optarg);
|
||||
output = OUTPUT_PASSNO;
|
||||
break;
|
||||
}
|
||||
@ -224,7 +223,7 @@ int fstabinfo (int argc, char **argv)
|
||||
START_ENT;
|
||||
while ((ent = GET_ENT))
|
||||
if (strcmp(token, ENT_TYPE(ent)) == 0)
|
||||
rc_strlist_add (&files, ENT_FILE (ent));
|
||||
rc_stringlist_add(files, ENT_FILE(ent));
|
||||
END_ENT;
|
||||
}
|
||||
break;
|
||||
@ -233,23 +232,23 @@ int fstabinfo (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
while (optind < argc)
|
||||
rc_strlist_add (&files, argv[optind++]);
|
||||
|
||||
if (! files && ! filtered) {
|
||||
rc_stringlist_add(files, argv[optind++]);
|
||||
} else if (! filtered) {
|
||||
START_ENT;
|
||||
while ((ent = GET_ENT))
|
||||
rc_strlist_add (&files, ENT_FILE (ent));
|
||||
rc_stringlist_add(files, ENT_FILE(ent));
|
||||
END_ENT;
|
||||
|
||||
if (! files)
|
||||
if (! TAILQ_FIRST(files))
|
||||
eerrorx("%s: emtpy fstab", argv[0]);
|
||||
}
|
||||
|
||||
/* Ensure we always display something */
|
||||
START_ENT;
|
||||
STRLIST_FOREACH (files, file, i) {
|
||||
if (! (ent = GET_ENT_FILE (file))) {
|
||||
TAILQ_FOREACH(file, files, entries) {
|
||||
if (! (ent = GET_ENT_FILE(file->value))) {
|
||||
result = EXIT_FAILURE;
|
||||
continue;
|
||||
}
|
||||
@ -272,7 +271,7 @@ int fstabinfo (int argc, char **argv)
|
||||
ENT_OPTS(ent),
|
||||
ENT_TYPE(ent),
|
||||
ENT_BLOCKDEVICE(ent),
|
||||
file);
|
||||
file->value);
|
||||
break;
|
||||
|
||||
case OUTPUT_OPTIONS:
|
||||
@ -280,7 +279,7 @@ int fstabinfo (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case OUTPUT_FILE:
|
||||
printf ("%s\n", file);
|
||||
printf("%s\n", file->value);
|
||||
break;
|
||||
|
||||
case OUTPUT_PASSNO:
|
||||
@ -290,7 +289,7 @@ int fstabinfo (int argc, char **argv)
|
||||
}
|
||||
END_ENT;
|
||||
|
||||
rc_strlist_free (files);
|
||||
rc_stringlist_free(files);
|
||||
exit(result);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
@ -47,16 +47,15 @@
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
extern const char *applet;
|
||||
|
||||
@ -80,65 +79,65 @@ struct args {
|
||||
regex_t *skip_fstype_regex;
|
||||
regex_t *options_regex;
|
||||
regex_t *skip_options_regex;
|
||||
char **mounts;
|
||||
RC_STRINGLIST *mounts;
|
||||
mount_type mount_type;
|
||||
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,
|
||||
int netdev)
|
||||
{
|
||||
char *p;
|
||||
RC_STRING *s;
|
||||
|
||||
errno = ENOENT;
|
||||
|
||||
#ifdef __linux__
|
||||
/* Skip the really silly rootfs */
|
||||
if (strcmp(fstype, "rootfs") == 0)
|
||||
return (-1);
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if (args->netdev == net_yes && (netdev != -1 || args->mounts)) {
|
||||
if (args->netdev == net_yes &&
|
||||
(netdev != -1 || TAILQ_FIRST(args->mounts)))
|
||||
{
|
||||
if (netdev != 0)
|
||||
return (1);
|
||||
} else if (args->netdev == net_no && (netdev != -1 || args->mounts)) {
|
||||
return 1;
|
||||
} else if (args->netdev == net_no &&
|
||||
(netdev != -1 || TAILQ_FIRST(args->mounts)))
|
||||
{
|
||||
if (netdev != 1)
|
||||
return (1);
|
||||
return 1;
|
||||
} else {
|
||||
if (args->node_regex &&
|
||||
regexec(args->node_regex, from, 0, NULL, 0) != 0)
|
||||
return (1);
|
||||
return 1;
|
||||
if (args->skip_node_regex &&
|
||||
regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
|
||||
return (1);
|
||||
return 1;
|
||||
|
||||
if (args->fstype_regex &&
|
||||
regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
|
||||
return (-1);
|
||||
return -1;
|
||||
if (args->skip_fstype_regex &&
|
||||
regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if (args->options_regex &&
|
||||
regexec(args->options_regex, options, 0, NULL, 0) != 0)
|
||||
return (-1);
|
||||
return -1;
|
||||
if (args->skip_options_regex &&
|
||||
regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args->mounts) {
|
||||
bool found = false;
|
||||
int j;
|
||||
char *mnt;
|
||||
STRLIST_FOREACH (args->mounts, mnt, j)
|
||||
if (strcmp (mnt, to) == 0) {
|
||||
found = true;
|
||||
if (TAILQ_FIRST(args->mounts)) {
|
||||
TAILQ_FOREACH(s, args->mounts, entries)
|
||||
if (strcmp(s->value, to) == 0)
|
||||
break;
|
||||
}
|
||||
if (! found)
|
||||
return (-1);
|
||||
if (! s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (args->mount_type) {
|
||||
@ -162,11 +161,11 @@ static int process_mount (char ***list, struct args *args,
|
||||
|
||||
if (p) {
|
||||
errno = 0;
|
||||
rc_strlist_addsortc (list, p);
|
||||
return (0);
|
||||
rc_stringlist_add(list, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef BSD
|
||||
@ -212,21 +211,25 @@ static struct opt {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static char **find_mounts (struct args *args)
|
||||
static RC_STRINGLIST *find_mounts(struct args *args)
|
||||
{
|
||||
struct statfs *mnts;
|
||||
int nmnts;
|
||||
int i;
|
||||
char **list = NULL;
|
||||
RC_STRINGLIST *list;
|
||||
char *options = NULL;
|
||||
uint64_t flags;
|
||||
struct opt *o;
|
||||
int netdev;
|
||||
char *tmp;
|
||||
size_t l;
|
||||
|
||||
if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
|
||||
eerrorx("getmntinfo: %s", strerror (errno));
|
||||
|
||||
list = rc_stringlist_new();
|
||||
for (i = 0; i < nmnts; i++) {
|
||||
int netdev = 0;
|
||||
netdev = 0;
|
||||
flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK;
|
||||
for (o = optnames; flags && o->o_opt; o++) {
|
||||
if (flags & o->o_opt) {
|
||||
@ -235,8 +238,7 @@ static char **find_mounts (struct args *args)
|
||||
if (! options)
|
||||
options = xstrdup(o->o_name);
|
||||
else {
|
||||
char *tmp = NULL;
|
||||
size_t l = strlen (options) + strlen (o->o_name) + 2;
|
||||
l = strlen(options) + strlen(o->o_name) + 2;
|
||||
tmp = xmalloc(sizeof (char) * l);
|
||||
snprintf(tmp, l, "%s,%s", options, o->o_name);
|
||||
free(options);
|
||||
@ -246,7 +248,7 @@ static char **find_mounts (struct args *args)
|
||||
flags &= ~o->o_opt;
|
||||
}
|
||||
|
||||
process_mount (&list, args,
|
||||
process_mount(list, args,
|
||||
mnts[i].f_mntfromname,
|
||||
mnts[i].f_mntonname,
|
||||
mnts[i].f_fstypename,
|
||||
@ -257,7 +259,7 @@ static char **find_mounts (struct args *args)
|
||||
options = NULL;
|
||||
}
|
||||
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
|
||||
#elif defined (__linux__)
|
||||
@ -272,10 +274,10 @@ static struct mntent *getmntfile (const char *file)
|
||||
break;
|
||||
endmntent(fp);
|
||||
|
||||
return (ent);
|
||||
return ent;
|
||||
}
|
||||
|
||||
static char **find_mounts (struct args *args)
|
||||
static RC_STRINGLIST *find_mounts(struct args *args)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
@ -284,13 +286,15 @@ static char **find_mounts (struct args *args)
|
||||
char *to;
|
||||
char *fst;
|
||||
char *opts;
|
||||
char **list = NULL;
|
||||
struct mntent *ent;
|
||||
int netdev;
|
||||
RC_STRINGLIST *list;
|
||||
|
||||
if ((fp = fopen("/proc/mounts", "r")) == NULL)
|
||||
eerrorx("getmntinfo: %s", strerror(errno));
|
||||
|
||||
list = rc_stringlist_new();
|
||||
|
||||
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
|
||||
while (fgets(buffer, PATH_MAX * 3, fp)) {
|
||||
netdev = -1;
|
||||
@ -305,12 +309,12 @@ static char **find_mounts (struct args *args)
|
||||
netdev = 0;
|
||||
}
|
||||
|
||||
process_mount (&list, args, from, to, fst, opts, netdev);
|
||||
process_mount(list, args, from, to, fst, opts, netdev);
|
||||
}
|
||||
free(buffer);
|
||||
fclose(fp);
|
||||
|
||||
return (list);
|
||||
return list;
|
||||
}
|
||||
|
||||
#else
|
||||
@ -329,7 +333,7 @@ static regex_t *get_regex (const char *string)
|
||||
eerrorx("%s: invalid regex `%s'", applet, buffer);
|
||||
}
|
||||
|
||||
return (reg);
|
||||
return reg;
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
@ -371,12 +375,11 @@ static const char * const longopts_help[] = {
|
||||
|
||||
int mountinfo(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
struct args args;
|
||||
regex_t *point_regex = NULL;
|
||||
regex_t *skip_point_regex = NULL;
|
||||
char **nodes = NULL;
|
||||
char *n;
|
||||
RC_STRINGLIST *nodes;
|
||||
RC_STRING *s;
|
||||
int opt;
|
||||
int result;
|
||||
bool quiet;
|
||||
@ -393,6 +396,7 @@ int mountinfo (int argc, char **argv)
|
||||
memset (&args, 0, sizeof(args));
|
||||
args.mount_type = mount_to;
|
||||
args.netdev = net_ignore;
|
||||
args.mounts = rc_stringlist_new();
|
||||
|
||||
while ((opt = getopt_long(argc, argv, getoptstring,
|
||||
longopts, (int *) 0)) != -1)
|
||||
@ -445,10 +449,11 @@ int mountinfo (int argc, char **argv)
|
||||
while (optind < argc) {
|
||||
if (argv[optind][0] != '/')
|
||||
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);
|
||||
|
||||
REG_FREE(args.fstype_regex);
|
||||
REG_FREE(args.skip_fstype_regex);
|
||||
@ -457,20 +462,20 @@ int mountinfo (int argc, char **argv)
|
||||
REG_FREE(args.options_regex);
|
||||
REG_FREE(args.skip_options_regex);
|
||||
|
||||
rc_strlist_reverse (nodes);
|
||||
|
||||
result = EXIT_FAILURE;
|
||||
quiet = rc_yesno(getenv("EINFO_QUIET"));
|
||||
STRLIST_FOREACH (nodes, n, i) {
|
||||
if (point_regex && regexec (point_regex, n, 0, NULL, 0) != 0)
|
||||
TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) {
|
||||
if (point_regex &&
|
||||
regexec(point_regex, s->value, 0, NULL, 0) != 0)
|
||||
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;
|
||||
if (! quiet)
|
||||
printf ("%s\n", n);
|
||||
printf("%s\n", s->value);
|
||||
result = EXIT_SUCCESS;
|
||||
}
|
||||
rc_strlist_free (nodes);
|
||||
rc_stringlist_free(nodes);
|
||||
|
||||
REG_FREE(point_regex);
|
||||
REG_FREE(skip_point_regex);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define SYSLOG_NAMES
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
@ -49,7 +50,6 @@
|
||||
#include "builtins.h"
|
||||
#include "einfo.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
/* Applet is first parsed in rc.c - no point in doing it again */
|
||||
extern const char *applet;
|
||||
@ -59,13 +59,13 @@ static int syslog_decode (char *name, CODE *codetab)
|
||||
CODE *c;
|
||||
|
||||
if (isdigit((int) *name))
|
||||
return (atoi (name));
|
||||
return atoi(name);
|
||||
|
||||
for (c = codetab; c->c_name; c++)
|
||||
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)
|
||||
@ -109,8 +109,8 @@ static int do_e (int argc, char **argv)
|
||||
}
|
||||
} else if (strcmp(applet, "esyslog") == 0 ||
|
||||
strcmp(applet, "elog") == 0) {
|
||||
char *dot = strchr (argv[0], '.');
|
||||
if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
|
||||
p = strchr(argv[0], '.');
|
||||
if ((level = syslog_decode(p + 1, prioritynames)) == -1)
|
||||
eerrorx("%s: invalid log level `%s'", applet, argv[0]);
|
||||
|
||||
if (argc < 3)
|
||||
@ -134,8 +134,9 @@ static int do_e (int argc, char **argv)
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (i > 0)
|
||||
*p++ = ' ';
|
||||
memcpy (p, argv[i], strlen (argv[i]));
|
||||
p += strlen (argv[i]);
|
||||
l = strlen(argv[i]);
|
||||
memcpy(p, argv[i], l);
|
||||
p += l;
|
||||
}
|
||||
*p = 0;
|
||||
}
|
||||
@ -193,13 +194,15 @@ static int do_e (int argc, char **argv)
|
||||
}
|
||||
|
||||
free(message);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int do_service(int argc, char **argv)
|
||||
{
|
||||
bool ok = false;
|
||||
char *service = NULL;
|
||||
int idx = 0;
|
||||
char *d[] = { NULL, NULL };
|
||||
|
||||
if (argc > 1)
|
||||
service = argv[1];
|
||||
@ -224,8 +227,7 @@ static int do_service (int argc, char **argv)
|
||||
else if (strcmp(applet, "service_wasinactive") == 0)
|
||||
ok = (rc_service_state(service) & RC_SERVICE_WASINACTIVE);
|
||||
else if (strcmp(applet, "service_started_daemon") == 0) {
|
||||
int idx = 0;
|
||||
char *d[] = { argv[1], NULL };
|
||||
d[0] = argv[1];
|
||||
|
||||
service = getenv("SVCNAME");
|
||||
if (argc > 3) {
|
||||
@ -235,7 +237,7 @@ static int do_service (int argc, char **argv)
|
||||
} else if (argc == 3) {
|
||||
if (sscanf(argv[2], "%d", &idx) != 1) {
|
||||
service = argv[1];
|
||||
*d = argv[2];
|
||||
d[0] = argv[2];
|
||||
}
|
||||
}
|
||||
ok = rc_service_started_daemon(service,
|
||||
@ -244,7 +246,7 @@ static int do_service (int argc, char **argv)
|
||||
} else
|
||||
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)
|
||||
@ -252,6 +254,10 @@ static int do_mark_service (int argc, char **argv)
|
||||
bool ok = false;
|
||||
char *svcname = getenv("SVCNAME");
|
||||
char *service = NULL;
|
||||
char *runscript_pid;
|
||||
char *mtime;
|
||||
pid_t pid;
|
||||
size_t l;
|
||||
|
||||
if (argc > 1)
|
||||
service = argv[1];
|
||||
@ -281,11 +287,7 @@ static int do_mark_service (int argc, char **argv)
|
||||
/* If we're marking ourselves then we need to inform our parent runscript
|
||||
process so they do not mark us based on our exit code */
|
||||
if (ok && svcname && strcmp(svcname, service) == 0) {
|
||||
char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
|
||||
char *mtime;
|
||||
pid_t pid = 0;
|
||||
size_t l;
|
||||
|
||||
runscript_pid = getenv("RC_RUNSCRIPT_PID");
|
||||
if (runscript_pid && sscanf(runscript_pid, "%d", &pid) == 1)
|
||||
if (kill(pid, SIGHUP) != 0)
|
||||
eerror("%s: failed to signal parent %d: %s",
|
||||
@ -293,10 +295,8 @@ static int do_mark_service (int argc, char **argv)
|
||||
|
||||
/* Remove the exclusive time test. This ensures that it's not
|
||||
in control as well */
|
||||
l = strlen (RC_SVCDIR "exclusive") +
|
||||
strlen (svcname) +
|
||||
strlen (runscript_pid) +
|
||||
4;
|
||||
l = strlen(RC_SVCDIR "exclusive") + strlen(svcname) +
|
||||
strlen(runscript_pid) + 4;
|
||||
mtime = xmalloc(l);
|
||||
snprintf(mtime, l, RC_SVCDIR "exclusive/%s.%s",
|
||||
svcname, runscript_pid);
|
||||
@ -305,13 +305,14 @@ static int do_mark_service (int argc, char **argv)
|
||||
free(mtime);
|
||||
}
|
||||
|
||||
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int do_value(int argc, char **argv)
|
||||
{
|
||||
bool ok = false;
|
||||
char *service = getenv("SVCNAME");
|
||||
char *option;
|
||||
|
||||
if (! service)
|
||||
eerrorx("%s: no service specified", applet);
|
||||
@ -322,7 +323,7 @@ static int do_value (int argc, char **argv)
|
||||
if (strcmp(applet, "service_get_value") == 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) {
|
||||
printf("%s", option);
|
||||
free(option);
|
||||
@ -334,34 +335,41 @@ static int do_value (int argc, char **argv)
|
||||
else
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *p = argv[i];
|
||||
p = argv[i];
|
||||
|
||||
if (i != 1)
|
||||
putchar(' ');
|
||||
|
||||
while (*p) {
|
||||
char c = *p++;
|
||||
if (! isalnum ((int) c))
|
||||
c = *p++;
|
||||
if (! isalnum(c))
|
||||
c = '_';
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
if (strcmp(applet, "fstabinfo") == 0)
|
||||
exit(fstabinfo(argc, argv));
|
||||
@ -388,9 +396,6 @@ void run_applets (int argc, char **argv)
|
||||
if (strcmp(applet, "is_newer_than") == 0 ||
|
||||
strcmp(applet, "is_older_than") == 0)
|
||||
{
|
||||
bool match = false;
|
||||
int i = 2;
|
||||
|
||||
if (argc < 3)
|
||||
exit (EXIT_FAILURE);
|
||||
if (strcmp(applet, "is_newer_than") == 0)
|
||||
@ -425,9 +430,7 @@ void run_applets (int argc, char **argv)
|
||||
exit(rc_runlevel_stopping() ? 0 : 1);
|
||||
|
||||
if (strcmp(applet, "rc-abort") == 0) {
|
||||
char *p = getenv ("RC_PID");
|
||||
pid_t pid = 0;
|
||||
|
||||
p = getenv("RC_PID");
|
||||
if (p && sscanf(p, "%d", &pid) == 1) {
|
||||
if (kill(pid, SIGUSR1) != 0)
|
||||
eerrorx("rc-abort: failed to signal parent %d: %s",
|
||||
|
@ -45,23 +45,22 @@
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
extern const char *applet;
|
||||
|
||||
rc_depinfo_t *_rc_deptree_load (int *regen) {
|
||||
if (rc_deptree_update_needed ()) {
|
||||
RC_DEPTREE *_rc_deptree_load(int *regen) {
|
||||
int fd;
|
||||
int retval;
|
||||
int serrno = errno;
|
||||
int merrno;
|
||||
|
||||
if (rc_deptree_update_needed()) {
|
||||
/* Test if we have permission to update the deptree */
|
||||
fd = open (RC_DEPTREE, O_WRONLY);
|
||||
fd = open(RC_DEPTREE_CACHE, O_WRONLY);
|
||||
merrno = errno;
|
||||
errno = serrno;
|
||||
if (fd == -1 && merrno == EACCES)
|
||||
return (rc_deptree_load ());
|
||||
return rc_deptree_load();
|
||||
close(fd);
|
||||
|
||||
if (regen)
|
||||
@ -72,7 +71,7 @@ rc_depinfo_t *_rc_deptree_load (int *regen) {
|
||||
eend (retval ? 0 : -1, "Failed to update the dependency tree");
|
||||
}
|
||||
|
||||
return (rc_deptree_load ());
|
||||
return rc_deptree_load();
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
@ -99,20 +98,21 @@ static const char * const longopts_help[] = {
|
||||
|
||||
int rc_depend(int argc, char **argv)
|
||||
{
|
||||
char **types = NULL;
|
||||
char **services = NULL;
|
||||
char **depends = NULL;
|
||||
char **list;
|
||||
rc_depinfo_t *deptree = NULL;
|
||||
char *service;
|
||||
RC_STRINGLIST *list;
|
||||
RC_STRINGLIST *types;
|
||||
RC_STRINGLIST *services;
|
||||
RC_STRINGLIST *depends;
|
||||
RC_STRING *s;
|
||||
RC_DEPTREE *deptree = NULL;
|
||||
int options = RC_DEP_TRACE;
|
||||
bool first = true;
|
||||
int i;
|
||||
bool update = false;
|
||||
char *runlevel = xstrdup(getenv("RC_SOFTLEVEL"));
|
||||
int opt;
|
||||
char *token;
|
||||
|
||||
types = rc_stringlist_new();
|
||||
|
||||
while ((opt = getopt_long(argc, argv, getoptstring,
|
||||
longopts, (int *) 0)) != -1)
|
||||
{
|
||||
@ -128,7 +128,7 @@ int rc_depend (int argc, char **argv)
|
||||
break;
|
||||
case 't':
|
||||
while ((token = strsep(&optarg, ",")))
|
||||
rc_strlist_addu (&types, token);
|
||||
rc_stringlist_add(types, token);
|
||||
break;
|
||||
case 'u':
|
||||
update = true;
|
||||
@ -142,11 +142,10 @@ int rc_depend (int argc, char **argv)
|
||||
}
|
||||
|
||||
if (update) {
|
||||
bool u = false;
|
||||
ebegin("Caching service dependencies");
|
||||
u = rc_deptree_update ();
|
||||
eend (u ? 0 : -1, "%s: %s", applet, strerror (errno));
|
||||
if (! u)
|
||||
update = rc_deptree_update();
|
||||
eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
|
||||
if (! update)
|
||||
eerrorx("Failed to update the dependency tree");
|
||||
}
|
||||
|
||||
@ -156,58 +155,55 @@ int rc_depend (int argc, char **argv)
|
||||
if (! runlevel)
|
||||
runlevel = rc_runlevel_get();
|
||||
|
||||
services = rc_stringlist_new();
|
||||
while (optind < argc) {
|
||||
list = NULL;
|
||||
rc_strlist_add (&list, argv[optind]);
|
||||
list = rc_stringlist_new();
|
||||
rc_stringlist_add(list, argv[optind]);
|
||||
errno = 0;
|
||||
depends = rc_deptree_depends (deptree, NULL, (const char **) list,
|
||||
runlevel, 0);
|
||||
depends = rc_deptree_depends(deptree, NULL, list, runlevel, 0);
|
||||
if (! depends && errno == ENOENT)
|
||||
eerror("no dependency info for service `%s'", argv[optind]);
|
||||
else
|
||||
rc_strlist_add (&services, argv[optind]);
|
||||
rc_stringlist_add(services, argv[optind]);
|
||||
|
||||
rc_strlist_free (depends);
|
||||
rc_strlist_free (list);
|
||||
rc_stringlist_free(depends);
|
||||
rc_stringlist_free(list);
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (! services) {
|
||||
rc_strlist_free (types);
|
||||
if (! TAILQ_FIRST(services)) {
|
||||
rc_stringlist_free(services);
|
||||
rc_stringlist_free(types);
|
||||
rc_deptree_free(deptree);
|
||||
free(runlevel);
|
||||
if (update)
|
||||
return (EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
eerrorx("no services specified");
|
||||
}
|
||||
|
||||
/* If we don't have any types, then supply some defaults */
|
||||
if (! types) {
|
||||
rc_strlist_add (&types, "ineed");
|
||||
rc_strlist_add (&types, "iuse");
|
||||
if (! TAILQ_FIRST(types)) {
|
||||
rc_stringlist_add(types, "ineed");
|
||||
rc_stringlist_add(types, "iuse");
|
||||
}
|
||||
|
||||
depends = rc_deptree_depends (deptree, (const char **) types,
|
||||
(const char **) services, runlevel, options);
|
||||
depends = rc_deptree_depends(deptree, types, services, runlevel, options);
|
||||
|
||||
if (depends) {
|
||||
STRLIST_FOREACH (depends, service, i) {
|
||||
if (TAILQ_FIRST(depends)) {
|
||||
TAILQ_FOREACH(s, depends, entries) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
printf (" ");
|
||||
|
||||
if (service)
|
||||
printf ("%s", service);
|
||||
printf ("%s", s->value);
|
||||
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
rc_strlist_free (types);
|
||||
rc_strlist_free (services);
|
||||
rc_strlist_free (depends);
|
||||
rc_stringlist_free(types);
|
||||
rc_stringlist_free(services);
|
||||
rc_stringlist_free(depends);
|
||||
rc_deptree_free(deptree);
|
||||
free(runlevel);
|
||||
return (EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@ -108,7 +109,6 @@ cont:
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_time(FILE *f, const char *s)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
@ -118,10 +118,11 @@ static void write_time (FILE *f, const char *s)
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
void rc_logger_close ()
|
||||
void rc_logger_close(void)
|
||||
{
|
||||
if (signal_pipe[1] > -1) {
|
||||
int sig = SIGTERM;
|
||||
|
||||
if (signal_pipe[1] > -1) {
|
||||
write(signal_pipe[1], &sig, sizeof(sig));
|
||||
close(signal_pipe[1]);
|
||||
signal_pipe[1] = -1;
|
||||
@ -178,7 +179,7 @@ void rc_logger_open (const char *level)
|
||||
rc_logger_pid = fork();
|
||||
switch (rc_logger_pid) {
|
||||
case -1:
|
||||
eerror ("forkpty: %s", strerror (errno));
|
||||
eerror("fork: %s", strerror(errno));
|
||||
break;
|
||||
case 0:
|
||||
rc_in_logger = true;
|
||||
@ -218,7 +219,8 @@ void rc_logger_open (const char *level)
|
||||
else {
|
||||
if (logbuf_size - logbuf_len < bytes) {
|
||||
logbuf_size += BUFSIZ * 10;
|
||||
logbuf = xrealloc (logbuf, sizeof (char ) *
|
||||
logbuf = xrealloc(logbuf,
|
||||
sizeof(char ) *
|
||||
logbuf_size);
|
||||
}
|
||||
|
||||
@ -251,6 +253,7 @@ void rc_logger_open (const char *level)
|
||||
|
||||
exit(0);
|
||||
/* NOTREACHED */
|
||||
|
||||
default:
|
||||
setpgid(rc_logger_pid, 0);
|
||||
fd_stdout = dup(STDOUT_FILENO);
|
||||
|
302
src/rc/rc-misc.c
302
src/rc/rc-misc.c
@ -30,13 +30,13 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
@ -47,7 +47,6 @@
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#define PROFILE_ENV SYSCONFDIR "/profile.env"
|
||||
#define SYS_WHITELIST RC_LIBDIR "/conf.d/env_whitelist"
|
||||
@ -57,32 +56,37 @@
|
||||
|
||||
#define PATH_PREFIX RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
|
||||
|
||||
static char **rc_conf = NULL;
|
||||
static RC_STRINGLIST *rc_conf = NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
if (! rc_conf) {
|
||||
char *line;
|
||||
int i;
|
||||
RC_STRINGLIST *old;
|
||||
RC_STRING *s;
|
||||
char *p;
|
||||
|
||||
if (! rc_conf) {
|
||||
rc_conf = rc_config_load(RC_CONF);
|
||||
atexit(_free_rc_conf);
|
||||
|
||||
/* Support old configs */
|
||||
if (exists(RC_CONF_OLD)) {
|
||||
char **old = rc_config_load (RC_CONF_OLD);
|
||||
rc_strlist_join (&rc_conf, old);
|
||||
rc_strlist_free (old);
|
||||
old = rc_config_load(RC_CONF_OLD);
|
||||
if (old) {
|
||||
TAILQ_CONCAT(rc_conf, old);
|
||||
free(old);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert old uppercase to lowercase */
|
||||
STRLIST_FOREACH (rc_conf, line, i) {
|
||||
char *p = line;
|
||||
TAILQ_FOREACH(s, rc_conf, entries) {
|
||||
p = s->value;
|
||||
while (p && *p && *p != '=') {
|
||||
if (isupper((int) *p))
|
||||
*p = tolower((int) *p);
|
||||
@ -91,182 +95,134 @@ char *rc_conf_value (const char *setting)
|
||||
}
|
||||
}
|
||||
|
||||
return (rc_config_value ((const char *const *)rc_conf, setting));
|
||||
return rc_config_value(rc_conf, 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;
|
||||
char **whitelist = NULL;
|
||||
char *env_name = NULL;
|
||||
char **profile = NULL;
|
||||
int count = 0;
|
||||
bool got_path = false;
|
||||
char *env_var;
|
||||
size_t env_len;
|
||||
char *token;
|
||||
char *sep;
|
||||
RC_STRINGLIST *env_allow;
|
||||
RC_STRINGLIST *profile = NULL;
|
||||
RC_STRINGLIST *env_list;
|
||||
RC_STRING *env;
|
||||
RC_STRING *s;
|
||||
char *env_name;
|
||||
char *e;
|
||||
char *p;
|
||||
size_t pplen = strlen (PATH_PREFIX);
|
||||
|
||||
/* 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");
|
||||
char *token;
|
||||
size_t i = 0;
|
||||
|
||||
/* Add the user defined list of vars */
|
||||
env_allow = rc_stringlist_new();
|
||||
e = env_name = xstrdup(rc_conf_value ("rc_env_allow"));
|
||||
while ((token = strsep(&e, " "))) {
|
||||
if (token[0] == '*') {
|
||||
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);
|
||||
|
||||
if (exists(PROFILE_ENV))
|
||||
profile = rc_config_load(PROFILE_ENV);
|
||||
|
||||
STRLIST_FOREACH (whitelist, env_name, count) {
|
||||
char *space = strchr (env_name, ' ');
|
||||
if (space)
|
||||
*space = 0;
|
||||
/* Copy the env and work from this so we can remove safely */
|
||||
env_list = rc_stringlist_new();
|
||||
while (environ[i])
|
||||
rc_stringlist_add(env_list, environ[i++]);
|
||||
|
||||
env_var = getenv (env_name);
|
||||
TAILQ_FOREACH(env, env_list, entries) {
|
||||
/* Check the whitelist */
|
||||
i = 0;
|
||||
while (env_whitelist[i]) {
|
||||
if (strcmp(env_whitelist[i++], env->value))
|
||||
break;
|
||||
}
|
||||
if (env_whitelist[i])
|
||||
continue;
|
||||
|
||||
if (! env_var && profile) {
|
||||
env_len = strlen (env_name) + strlen ("export ") + 1;
|
||||
p = xmalloc (sizeof (char) * env_len);
|
||||
snprintf (p, env_len, "export %s", env_name);
|
||||
env_var = rc_config_value ((const char *const *) profile, p);
|
||||
free (p);
|
||||
/* Check our user defined list */
|
||||
TAILQ_FOREACH(s, env_allow, entries)
|
||||
if (strcmp(s->value, env->value) == 0)
|
||||
break;
|
||||
if (s)
|
||||
continue;
|
||||
|
||||
/* Now check our profile */
|
||||
|
||||
/* OK, not allowed! */
|
||||
e = strchr(env->value, '=');
|
||||
*e = '\0';
|
||||
unsetenv(env->value);
|
||||
}
|
||||
rc_stringlist_free(env_list);
|
||||
rc_stringlist_free(env_allow);
|
||||
rc_stringlist_free(profile);
|
||||
}
|
||||
|
||||
if (! env_var)
|
||||
continue;
|
||||
void env_config(void)
|
||||
{
|
||||
size_t pplen = strlen(PATH_PREFIX);
|
||||
char *path;
|
||||
char *p;
|
||||
char *e;
|
||||
size_t l;
|
||||
struct utsname uts;
|
||||
FILE *fp;
|
||||
char *token;
|
||||
char *np;
|
||||
char *npp;
|
||||
char *tok;
|
||||
const char *sys = rc_sys();
|
||||
char buffer[PATH_MAX];
|
||||
|
||||
/* Ensure our PATH is prefixed with the system locations first
|
||||
for a little extra security */
|
||||
if (strcmp (env_name, "PATH") == 0 &&
|
||||
strncmp (PATH_PREFIX, env_var, pplen) != 0)
|
||||
{
|
||||
got_path = true;
|
||||
env_len = strlen (env_name) + strlen (env_var) + pplen + 3;
|
||||
e = p = xmalloc (sizeof (char) * env_len);
|
||||
p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
|
||||
path = getenv("PATH");
|
||||
if (! path)
|
||||
setenv("PATH", PATH_PREFIX, 1);
|
||||
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);
|
||||
|
||||
/* Now go through the env var and only add bits not in our PREFIX */
|
||||
sep = env_var;
|
||||
while ((token = strsep (&sep, ":"))) {
|
||||
char *np = xstrdup (PATH_PREFIX);
|
||||
char *npp = np;
|
||||
char *tok = NULL;
|
||||
while ((token = strsep(&path, ":"))) {
|
||||
np = npp = xstrdup(PATH_PREFIX);
|
||||
while ((tok = strsep(&npp, ":")))
|
||||
if (strcmp(tok, token) == 0)
|
||||
break;
|
||||
if (! tok)
|
||||
p += snprintf (p, env_len - (p - e), ":%s", token);
|
||||
p += snprintf(p, l - (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);
|
||||
*p++ = '\0';
|
||||
unsetenv("PATH");
|
||||
setenv("PATH", e, 1);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* We filtered the env but didn't get a PATH? Very odd.
|
||||
However, we do need a path, so use a default. */
|
||||
if (! got_path) {
|
||||
env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 1;
|
||||
e = xmalloc (sizeof (char) * env_len);
|
||||
snprintf (e, env_len, "PATH=%s", PATH_PREFIX);
|
||||
rc_strlist_add (&env, e);
|
||||
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);
|
||||
}
|
||||
|
||||
rc_strlist_free (whitelist);
|
||||
rc_strlist_free (profile);
|
||||
|
||||
return (env);
|
||||
}
|
||||
|
||||
char **env_config (void)
|
||||
{
|
||||
char **env = NULL;
|
||||
char *line;
|
||||
size_t l;
|
||||
const char *sys = rc_sys ();
|
||||
struct utsname uts;
|
||||
FILE *fp;
|
||||
char buffer[PATH_MAX];
|
||||
char *runlevel = rc_runlevel_get ();
|
||||
|
||||
/* One char less to drop the trailing / */
|
||||
l = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_LIBDIR=" RC_LIBDIR);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
|
||||
/* One char less to drop the trailing / */
|
||||
l = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_SVCDIR=" RC_SVCDIR);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
|
||||
rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
|
||||
|
||||
l = strlen ("RC_SOFTLEVEL=") + strlen (runlevel) + 1;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_SOFTLEVEL=%s", runlevel);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
|
||||
if ((fp = fopen(RC_KSOFTLEVEL, "r"))) {
|
||||
memset(buffer, 0, sizeof (buffer));
|
||||
@ -274,47 +230,30 @@ char **env_config (void)
|
||||
l = strlen (buffer) - 1;
|
||||
if (buffer[l] == '\n')
|
||||
buffer[l] = 0;
|
||||
l += strlen ("RC_DEFAULTLEVEL=") + 2;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_DEFAULTLEVEL=%s", buffer);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
setenv("RC_DEFAULTLEVEL", buffer, 1);
|
||||
}
|
||||
fclose(fp);
|
||||
} else
|
||||
rc_strlist_add (&env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
|
||||
setenv("RC_DEFAULTLEVEL", RC_LEVEL_DEFAULT, 1);
|
||||
|
||||
if (sys) {
|
||||
l = strlen ("RC_SYS=") + strlen (sys) + 2;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_SYS=%s", sys);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
}
|
||||
if (sys)
|
||||
setenv("RC_SYS", sys, 1);
|
||||
|
||||
/* Some scripts may need to take a different code path if Linux/FreeBSD, etc
|
||||
To save on calling uname, we store it in an environment variable */
|
||||
if (uname (&uts) == 0) {
|
||||
l = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
|
||||
line = xmalloc (sizeof (char) * l);
|
||||
snprintf (line, l, "RC_UNAME=%s", uts.sysname);
|
||||
rc_strlist_add (&env, line);
|
||||
free (line);
|
||||
}
|
||||
if (uname(&uts) == 0)
|
||||
setenv("RC_UNAME", uts.sysname, 1);
|
||||
|
||||
/* Be quiet or verbose as necessary */
|
||||
if (rc_conf_yesno("rc_quiet"))
|
||||
rc_strlist_add (&env, "EINFO_QUIET=YES");
|
||||
setenv("EINFO_QUIET", "YES", 1);
|
||||
if (rc_conf_yesno("rc_verbose"))
|
||||
rc_strlist_add (&env, "EINFO_VERBOSE=YES");
|
||||
setenv("EINFO_VERBOSE", "YES", 1);
|
||||
|
||||
errno = 0;
|
||||
if ((! rc_conf_yesno("rc_color") && errno == 0) ||
|
||||
rc_conf_yesno("rc_nocolor"))
|
||||
rc_strlist_add (&env, "EINFO_COLOR=NO");
|
||||
|
||||
free (runlevel);
|
||||
return (env);
|
||||
setenv("EINFO_COLOR", "NO", 1);
|
||||
}
|
||||
|
||||
bool service_plugable(const char *service)
|
||||
@ -325,24 +264,23 @@ bool service_plugable (const char *service)
|
||||
char *token;
|
||||
bool allow = true;
|
||||
char *match = rc_conf_value("rc_plug_services");
|
||||
bool truefalse;
|
||||
|
||||
if (! match)
|
||||
return (true);
|
||||
return true;
|
||||
|
||||
list = xstrdup(match);
|
||||
p = list;
|
||||
while ((token = strsep(&p, " "))) {
|
||||
bool truefalse = true;
|
||||
|
||||
if (token[0] == '!') {
|
||||
truefalse = false;
|
||||
token++;
|
||||
}
|
||||
} else
|
||||
truefalse = true;
|
||||
|
||||
star = strchr(token, '*');
|
||||
if (star) {
|
||||
if (strncmp (service, token, (size_t) (star - token))
|
||||
== 0)
|
||||
if (strncmp(service, token, (size_t)(star - token)) == 0)
|
||||
{
|
||||
allow = truefalse;
|
||||
break;
|
||||
@ -356,7 +294,7 @@ bool service_plugable (const char *service)
|
||||
}
|
||||
|
||||
free(list);
|
||||
return (allow);
|
||||
return allow;
|
||||
}
|
||||
|
||||
int signal_setup(int sig, void (*handler)(int))
|
||||
@ -366,5 +304,5 @@ int signal_setup (int sig, void (*handler)(int))
|
||||
memset(&sa, 0, sizeof (sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler = handler;
|
||||
return (sigaction (sig, &sa, NULL));
|
||||
return sigaction(sig, &sa, NULL);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
@ -46,7 +47,6 @@
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "rc-plugin.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#define RC_PLUGIN_HOOK "rc_plugin_hook"
|
||||
|
||||
@ -56,11 +56,10 @@ typedef struct plugin
|
||||
{
|
||||
char *name;
|
||||
void *handle;
|
||||
int (*hook) (rc_hook_t, const char *);
|
||||
struct plugin *next;
|
||||
} plugin_t;
|
||||
|
||||
static plugin_t *plugins = NULL;
|
||||
int (*hook)(RC_HOOK, const char *);
|
||||
STAILQ_ENTRY(plugin) entries;
|
||||
} PLUGIN;
|
||||
STAILQ_HEAD(, plugin) plugins;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
dlfunc_t dlfunc(void * __restrict handle, const char * __restrict symbol)
|
||||
@ -71,7 +70,7 @@ dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
|
||||
} rv;
|
||||
|
||||
rv.d = dlsym(handle, symbol);
|
||||
return (rv.f);
|
||||
return rv.f;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -79,17 +78,16 @@ void rc_plugin_load (void)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
plugin_t *plugin = plugins;
|
||||
PLUGIN *plugin;
|
||||
char *p;
|
||||
void *h;
|
||||
int (*fptr) (rc_hook_t, const char *);
|
||||
int (*fptr)(RC_HOOK, const char *);
|
||||
|
||||
/* Don't load plugins if we're in one */
|
||||
if (rc_in_plugin)
|
||||
return;
|
||||
|
||||
/* Ensure some sanity here */
|
||||
rc_plugin_unload ();
|
||||
STAILQ_INIT(&plugins);
|
||||
|
||||
if (! (dp = opendir(RC_PLUGINDIR)))
|
||||
return;
|
||||
@ -106,21 +104,16 @@ void rc_plugin_load (void)
|
||||
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) {
|
||||
eerror("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
|
||||
dlclose(h);
|
||||
} else {
|
||||
if (plugin) {
|
||||
plugin->next = xmalloc (sizeof (*plugin->next));
|
||||
plugin = plugin->next;
|
||||
} else
|
||||
plugin = plugins = xmalloc (sizeof (*plugin));
|
||||
|
||||
plugin = xmalloc(sizeof(*plugin));
|
||||
plugin->name = xstrdup(d->d_name);
|
||||
plugin->handle = h;
|
||||
plugin->hook = fptr;
|
||||
plugin->next = NULL;
|
||||
STAILQ_INSERT_TAIL(&plugins, plugin, entries);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
@ -138,16 +131,25 @@ int rc_waitpid (pid_t pid)
|
||||
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;
|
||||
sigset_t empty;
|
||||
sigset_t full;
|
||||
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 */
|
||||
if (rc_in_plugin)
|
||||
@ -160,21 +162,7 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
|
||||
sigemptyset(&empty);
|
||||
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
|
||||
* vars, which in turn influence our scripts. */
|
||||
if (pipe(pfd) == -1) {
|
||||
@ -200,8 +188,6 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
int retval;
|
||||
|
||||
/* Restore default handlers */
|
||||
sigaction(SIGCHLD, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
@ -248,21 +234,20 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
|
||||
close(pfd[0]);
|
||||
|
||||
rc_waitpid(pid);
|
||||
plugin = plugin->next;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_plugin_unload(void)
|
||||
{
|
||||
plugin_t *plugin = plugins;
|
||||
plugin_t *next;
|
||||
PLUGIN *plugin = STAILQ_FIRST(&plugins);
|
||||
PLUGIN *next;
|
||||
|
||||
while (plugin) {
|
||||
next = plugin->next;
|
||||
next = STAILQ_NEXT(plugin, entries);
|
||||
dlclose(plugin->handle);
|
||||
free(plugin->name);
|
||||
free(plugin);
|
||||
plugin = next;
|
||||
}
|
||||
plugins = NULL;
|
||||
STAILQ_INIT(&plugins);
|
||||
}
|
||||
|
@ -37,9 +37,9 @@
|
||||
extern bool rc_in_plugin;
|
||||
|
||||
int rc_waitpid(pid_t pid);
|
||||
void rc_plugin_load ();
|
||||
void rc_plugin_unload ();
|
||||
void rc_plugin_run (rc_hook_t, const char *value);
|
||||
void rc_plugin_load(void);
|
||||
void rc_plugin_unload(void);
|
||||
void rc_plugin_run(RC_HOOK, const char *value);
|
||||
|
||||
/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */
|
||||
#ifndef __FreeBSD__
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
extern const char *applet;
|
||||
|
||||
@ -62,8 +61,8 @@ static void print_service (char *service)
|
||||
char status[10];
|
||||
int cols = printf(" %s", service);
|
||||
const char *c = ecolor(ECOLOR_GOOD);
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
einfo_color_t color = ECOLOR_BAD;
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
ECOLOR color = ECOLOR_BAD;
|
||||
|
||||
if (state & RC_SERVICE_STOPPING)
|
||||
snprintf(status, sizeof(status), "stopping ");
|
||||
@ -74,7 +73,7 @@ static void print_service (char *service)
|
||||
snprintf(status, sizeof(status), "inactive ");
|
||||
color = ECOLOR_WARN;
|
||||
} 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 ");
|
||||
else {
|
||||
snprintf(status, sizeof(status), " started ");
|
||||
@ -115,15 +114,15 @@ static const char * const longopts_help[] = {
|
||||
|
||||
int rc_status (int argc, char **argv)
|
||||
{
|
||||
rc_depinfo_t *deptree = NULL;
|
||||
char **levels = NULL;
|
||||
char **services = NULL;
|
||||
char **ordered = NULL;
|
||||
char *level;
|
||||
char *service;
|
||||
RC_DEPTREE *deptree = NULL;
|
||||
RC_STRINGLIST *levels = NULL;
|
||||
RC_STRINGLIST *services;
|
||||
RC_STRINGLIST *types = NULL;
|
||||
RC_STRINGLIST *ordered;
|
||||
RC_STRING *s;
|
||||
RC_STRING *l;
|
||||
char *p;
|
||||
int opt;
|
||||
int i;
|
||||
int j;
|
||||
int depopts = RC_DEP_STRICT | RC_DEP_START | RC_DEP_TRACE;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
|
||||
@ -134,78 +133,79 @@ int rc_status (int argc, char **argv)
|
||||
break;
|
||||
case 'l':
|
||||
levels = rc_runlevel_list();
|
||||
STRLIST_FOREACH (levels, level, i)
|
||||
printf ("%s\n", level);
|
||||
rc_strlist_free (levels);
|
||||
TAILQ_FOREACH (l, levels, entries)
|
||||
printf("%s\n", l->value);
|
||||
rc_stringlist_free(levels);
|
||||
exit(EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
case 'r':
|
||||
level = rc_runlevel_get ();
|
||||
printf ("%s\n", level);
|
||||
free (level);
|
||||
p = rc_runlevel_get ();
|
||||
printf("%s\n", p);
|
||||
free(p);
|
||||
exit(EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
case 's':
|
||||
services = rc_services_in_runlevel(NULL);
|
||||
STRLIST_FOREACH (services, service, i)
|
||||
print_service (service);
|
||||
rc_strlist_free (services);
|
||||
TAILQ_FOREACH(s, services, entries)
|
||||
print_service(s->value);
|
||||
rc_stringlist_free(services);
|
||||
exit (EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
case 'u':
|
||||
services = rc_services_in_runlevel(NULL);
|
||||
levels = rc_runlevel_list();
|
||||
STRLIST_FOREACH (services, service, i) {
|
||||
bool found = false;
|
||||
STRLIST_FOREACH (levels, level, j)
|
||||
if (rc_service_in_runlevel (service, level)) {
|
||||
found = true;
|
||||
TAILQ_FOREACH(s, services, entries) {
|
||||
TAILQ_FOREACH(l, levels, entries)
|
||||
if (rc_service_in_runlevel(s->value, l->value))
|
||||
break;
|
||||
if (! l)
|
||||
print_service(s->value);
|
||||
}
|
||||
if (! found)
|
||||
print_service (service);
|
||||
}
|
||||
rc_strlist_free (levels);
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free(levels);
|
||||
rc_stringlist_free(services);
|
||||
exit (EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
|
||||
case_RC_COMMON_GETOPT
|
||||
}
|
||||
|
||||
if (! levels)
|
||||
levels = rc_stringlist_new();
|
||||
while (optind < argc)
|
||||
rc_strlist_add (&levels, argv[optind++]);
|
||||
|
||||
if (! levels) {
|
||||
level = rc_runlevel_get ();
|
||||
rc_strlist_add (&levels, level);
|
||||
free (level);
|
||||
rc_stringlist_add(levels, argv[optind++]);
|
||||
if (! TAILQ_FIRST(levels)) {
|
||||
p = rc_runlevel_get();
|
||||
rc_stringlist_add(levels, p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* Output the services in the order in which they would start */
|
||||
if (geteuid () == 0)
|
||||
deptree = _rc_deptree_load(NULL);
|
||||
else
|
||||
deptree = rc_deptree_load ();
|
||||
|
||||
STRLIST_FOREACH (levels, level, i) {
|
||||
print_level (level);
|
||||
services = rc_services_in_runlevel (level);
|
||||
TAILQ_FOREACH(l, levels, entries) {
|
||||
print_level(l->value);
|
||||
services = rc_services_in_runlevel(l->value);
|
||||
if (deptree) {
|
||||
ordered = rc_deptree_depends (deptree, types_nua,
|
||||
(const char **) services,
|
||||
level, depopts);
|
||||
rc_strlist_free (services);
|
||||
if (! types) {
|
||||
types = rc_stringlist_new();
|
||||
rc_stringlist_add(types, "ineed");
|
||||
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;
|
||||
ordered = NULL;
|
||||
}
|
||||
STRLIST_FOREACH (services, service, j)
|
||||
if (rc_service_in_runlevel (service, level))
|
||||
print_service (service);
|
||||
rc_strlist_free (services);
|
||||
TAILQ_FOREACH(s, services, entries)
|
||||
if (rc_service_in_runlevel(s->value, l->value))
|
||||
print_service(s->value);
|
||||
rc_stringlist_free(services);
|
||||
}
|
||||
|
||||
rc_strlist_free (levels);
|
||||
rc_stringlist_free(types);
|
||||
rc_stringlist_free(levels);
|
||||
rc_deptree_free(deptree);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
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",
|
||||
applet, service, runlevel, strerror (errno));
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
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",
|
||||
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;
|
||||
char **services = rc_services_in_runlevel (NULL);
|
||||
char *runlevel;
|
||||
int i;
|
||||
int j;
|
||||
RC_STRINGLIST *services = rc_services_in_runlevel(NULL);
|
||||
RC_STRING *service;
|
||||
RC_STRING *runlevel;
|
||||
RC_STRINGLIST *in;
|
||||
bool inone;
|
||||
char buffer[PATH_MAX];
|
||||
size_t l;
|
||||
|
||||
STRLIST_FOREACH (services, service, i) {
|
||||
char **in = NULL;
|
||||
bool inone = false;
|
||||
TAILQ_FOREACH(service, services, entries) {
|
||||
in = rc_stringlist_new();
|
||||
inone = false;
|
||||
|
||||
STRLIST_FOREACH (runlevels, runlevel, j) {
|
||||
if (rc_service_in_runlevel (service, runlevel)) {
|
||||
rc_strlist_add (&in, runlevel);
|
||||
TAILQ_FOREACH(runlevel, runlevels, entries) {
|
||||
if (rc_service_in_runlevel(service->value,
|
||||
runlevel->value))
|
||||
{
|
||||
rc_stringlist_add(in, runlevel->value);
|
||||
inone = true;
|
||||
} else {
|
||||
char buffer[PATH_MAX];
|
||||
memset (buffer, ' ', strlen (runlevel));
|
||||
buffer[strlen (runlevel)] = 0;
|
||||
rc_strlist_add (&in, buffer);
|
||||
l = strlen(runlevel->value);
|
||||
memset (buffer, ' ', l);
|
||||
buffer[l] = 0;
|
||||
rc_stringlist_add (in, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (! inone && ! verbose)
|
||||
continue;
|
||||
|
||||
printf (" %20s |", service);
|
||||
STRLIST_FOREACH (in, runlevel, j)
|
||||
printf (" %s", runlevel);
|
||||
if (inone || verbose) {
|
||||
printf(" %20s |", service->value);
|
||||
TAILQ_FOREACH(runlevel, in, entries)
|
||||
printf (" %s", runlevel->value);
|
||||
printf ("\n");
|
||||
rc_strlist_free (in);
|
||||
}
|
||||
rc_stringlist_free(in);
|
||||
}
|
||||
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free (services);
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
@ -148,22 +150,23 @@ static const char * const longopts_help[] = {
|
||||
|
||||
int rc_update(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
RC_STRINGLIST *runlevels;
|
||||
RC_STRING *runlevel;
|
||||
char *service = NULL;
|
||||
char **runlevels = NULL;
|
||||
char *runlevel;
|
||||
char *p;
|
||||
int action = 0;
|
||||
bool verbose = false;
|
||||
int opt;
|
||||
int retval = EXIT_FAILURE;
|
||||
int num_updated = 0;
|
||||
int (*actfunc)(const char *, const char *);
|
||||
int ret;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, getoptstring,
|
||||
longopts, (int *) 0)) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case_RC_COMMON_GETOPT
|
||||
}
|
||||
}
|
||||
|
||||
verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
|
||||
|
||||
@ -189,6 +192,8 @@ int rc_update (int argc, char **argv)
|
||||
if (! action)
|
||||
action = DOSHOW;
|
||||
|
||||
runlevels = rc_stringlist_new();
|
||||
|
||||
if (optind >= argc) {
|
||||
if (! action & DOSHOW)
|
||||
eerrorx("%s: no service specified", applet);
|
||||
@ -198,59 +203,69 @@ int rc_update (int argc, char **argv)
|
||||
|
||||
while (optind < argc)
|
||||
if (rc_runlevel_exists(argv[optind]))
|
||||
rc_strlist_add (&runlevels, argv[optind++]);
|
||||
rc_stringlist_add(runlevels, argv[optind++]);
|
||||
else {
|
||||
rc_strlist_free (runlevels);
|
||||
eerrorx ("%s: `%s' is not a valid runlevel", applet, argv[optind]);
|
||||
rc_stringlist_free(runlevels);
|
||||
eerrorx ("%s: `%s' is not a valid runlevel",
|
||||
applet, argv[optind]);
|
||||
}
|
||||
}
|
||||
|
||||
retval = EXIT_SUCCESS;
|
||||
if (action & DOSHOW) {
|
||||
if (service)
|
||||
rc_strlist_add (&runlevels, service);
|
||||
if (! runlevels)
|
||||
rc_stringlist_add(runlevels, service);
|
||||
if (! TAILQ_FIRST(runlevels)) {
|
||||
free(runlevels);
|
||||
runlevels = rc_runlevel_list();
|
||||
}
|
||||
|
||||
show (runlevels, verbose);
|
||||
} else {
|
||||
if (! service)
|
||||
eerror ("%s: no service specified", applet);
|
||||
else {
|
||||
int num_updated = 0;
|
||||
int (*actfunc)(const char *, const char *);
|
||||
int ret;
|
||||
|
||||
if (action & DOADD) {
|
||||
actfunc = add;
|
||||
} else if (action & DODELETE) {
|
||||
actfunc = delete;
|
||||
} else
|
||||
} else {
|
||||
rc_stringlist_free(runlevels);
|
||||
eerrorx ("%s: invalid action", applet);
|
||||
}
|
||||
|
||||
if (! runlevels)
|
||||
rc_strlist_add (&runlevels, rc_runlevel_get ());
|
||||
if (! TAILQ_FIRST(runlevels)) {
|
||||
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);
|
||||
}
|
||||
|
||||
STRLIST_FOREACH (runlevels, runlevel, i) {
|
||||
if (! rc_runlevel_exists (runlevel)) {
|
||||
eerror ("%s: runlevel `%s' does not exist", applet, runlevel);
|
||||
TAILQ_FOREACH (runlevel, runlevels, entries) {
|
||||
if (! rc_runlevel_exists(runlevel->value)) {
|
||||
eerror ("%s: runlevel `%s' does not exist",
|
||||
applet, runlevel->value);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = actfunc (runlevel, service);
|
||||
ret = actfunc(runlevel->value, service);
|
||||
if (ret < 0)
|
||||
retval = EXIT_FAILURE;
|
||||
num_updated += ret;
|
||||
}
|
||||
|
||||
if (retval == EXIT_SUCCESS && num_updated == 0 && action & DODELETE)
|
||||
ewarnx ("%s: service `%s' not found in any of the specified runlevels", applet, service);
|
||||
if (retval == EXIT_SUCCESS &&
|
||||
num_updated == 0 && action & DODELETE)
|
||||
ewarnx("%s: service `%s' not found in any"
|
||||
" of the specified runlevels",
|
||||
applet, service);
|
||||
}
|
||||
}
|
||||
|
||||
rc_strlist_free (runlevels);
|
||||
return (retval);
|
||||
rc_stringlist_free(runlevels);
|
||||
return retval;
|
||||
}
|
||||
|
464
src/rc/rc.c
464
src/rc/rc.c
@ -42,10 +42,18 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* So we can coldplug net devices */
|
||||
#ifdef BSD
|
||||
# include <sys/socket.h>
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@ -56,19 +64,12 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* So we can coldplug net devices */
|
||||
#ifdef BSD
|
||||
# include <sys/socket.h>
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-logger.h"
|
||||
#include "rc-misc.h"
|
||||
#include "rc-plugin.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
@ -83,39 +84,27 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
|
||||
|
||||
#define DEVBOOT "/dev/.rcboot"
|
||||
|
||||
/* Cleanup anything in main */
|
||||
#define CHAR_FREE(_item) if (_item) { \
|
||||
free (_item); \
|
||||
_item = NULL; \
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static char *RUNLEVEL = NULL;
|
||||
static char *PREVLEVEL = NULL;
|
||||
|
||||
const char *applet = NULL;
|
||||
static char *runlevel = NULL;
|
||||
static char **env = NULL;
|
||||
static char **newenv = NULL;
|
||||
static char **coldplugged_services = NULL;
|
||||
static char **stop_services = NULL;
|
||||
static char **start_services = NULL;
|
||||
static rc_depinfo_t *deptree = NULL;
|
||||
static rc_hook_t hook_out = 0;
|
||||
static char *tmp = NULL;
|
||||
static RC_STRINGLIST *coldplugged_services = NULL;
|
||||
static RC_STRINGLIST *stop_services = NULL;
|
||||
static RC_STRINGLIST *start_services = NULL;
|
||||
static RC_STRINGLIST *types_n = NULL;
|
||||
static RC_STRINGLIST *types_nua = NULL;
|
||||
static RC_DEPTREE *deptree = NULL;
|
||||
static RC_HOOK hook_out = 0;
|
||||
|
||||
struct termios *termios_orig = NULL;
|
||||
|
||||
typedef struct pidlist
|
||||
typedef struct piditem
|
||||
{
|
||||
pid_t pid;
|
||||
struct pidlist *next;
|
||||
} pidlist_t;
|
||||
static pidlist_t *service_pids = NULL;
|
||||
|
||||
static const char *const types_n[] = { "needsme", NULL };
|
||||
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
|
||||
LIST_ENTRY(piditem) entries;
|
||||
} PIDITEM;
|
||||
LIST_HEAD(, piditem) service_pids;
|
||||
|
||||
static void clean_failed(void)
|
||||
{
|
||||
@ -149,7 +138,8 @@ static void clean_failed (void)
|
||||
static void cleanup(void)
|
||||
{
|
||||
if (applet && strcmp(applet, "rc") == 0) {
|
||||
pidlist_t *pl = service_pids;
|
||||
PIDITEM *p1 = LIST_FIRST(&service_pids);
|
||||
PIDITEM *p2;
|
||||
|
||||
if (hook_out)
|
||||
rc_plugin_run(hook_out, runlevel);
|
||||
@ -161,17 +151,17 @@ static void cleanup (void)
|
||||
free(termios_orig);
|
||||
}
|
||||
|
||||
while (pl) {
|
||||
pidlist_t *p = pl->next;
|
||||
free (pl);
|
||||
pl = p;
|
||||
while (p1) {
|
||||
p2 = LIST_NEXT(p1, entries);
|
||||
free(p1);
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
rc_strlist_free (env);
|
||||
rc_strlist_free (newenv);
|
||||
rc_strlist_free (coldplugged_services);
|
||||
rc_strlist_free (stop_services);
|
||||
rc_strlist_free (start_services);
|
||||
rc_stringlist_free(coldplugged_services);
|
||||
rc_stringlist_free(stop_services);
|
||||
rc_stringlist_free(start_services);
|
||||
rc_stringlist_free(types_n);
|
||||
rc_stringlist_free(types_nua);
|
||||
rc_deptree_free(deptree);
|
||||
|
||||
/* Clean runlevel start, stop markers */
|
||||
@ -197,11 +187,11 @@ static char *proc_getent (const char *ent)
|
||||
int i;
|
||||
|
||||
if (! exists("/proc/cmdline"))
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
if (! (fp = fopen("/proc/cmdline", "r"))) {
|
||||
eerror("failed to open `/proc/cmdline': %s", strerror(errno));
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((proc = rc_getline(fp)) &&
|
||||
@ -219,7 +209,7 @@ static char *proc_getent (const char *ent)
|
||||
free(proc);
|
||||
fclose(fp);
|
||||
|
||||
return (value);
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -230,7 +220,7 @@ static char read_key (bool block)
|
||||
int fd = fileno(stdin);
|
||||
|
||||
if (! isatty(fd))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
/* Now save our terminal settings. We need to restore them at exit as we
|
||||
* will be changing it for non-blocking reads for Interactive */
|
||||
@ -253,7 +243,7 @@ static char read_key (bool block)
|
||||
|
||||
tcsetattr(fd, TCSANOW, termios_orig);
|
||||
|
||||
return (c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static bool want_interactive(void)
|
||||
@ -263,23 +253,23 @@ static bool want_interactive (void)
|
||||
static bool interactive;
|
||||
|
||||
if (rc_yesno(getenv("EINFO_QUIET")))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (PREVLEVEL &&
|
||||
strcmp(PREVLEVEL, "N") != 0 &&
|
||||
strcmp(PREVLEVEL, "S") != 0 &&
|
||||
strcmp(PREVLEVEL, "1") != 0)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (! gotinteractive) {
|
||||
gotinteractive = true;
|
||||
interactive = rc_conf_yesno("rc_interactive");
|
||||
}
|
||||
if (! interactive)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
c = read_key(false);
|
||||
return ((c == 'I' || c == 'i') ? true : false);
|
||||
return (c == 'I' || c == 'i') ? true : false;
|
||||
}
|
||||
|
||||
static void mark_interactive(void)
|
||||
@ -302,17 +292,17 @@ static void sulogin (bool cont)
|
||||
/* VSERVER and OPENVZ systems cannot do a sulogin */
|
||||
if (sys && (strcmp(sys, "VSERVER") == 0 || strcmp(sys, "OPENVZ") == 0)) {
|
||||
execl("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
|
||||
eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
|
||||
eerrorx("%s: unable to exec `/sbin/halt': %s",
|
||||
applet, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
newenv = env_filter ();
|
||||
|
||||
if (! cont) {
|
||||
rc_logger_close();
|
||||
#ifdef __linux__
|
||||
execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
|
||||
eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
|
||||
execl("/sbin/sulogin", "/sbin/sulogin", (char *) NULL);
|
||||
eerrorx("%s: unable to exec `/sbin/sulogin': %s",
|
||||
applet, strerror(errno));
|
||||
#else
|
||||
exit(EXIT_SUCCESS);
|
||||
#endif
|
||||
@ -345,11 +335,11 @@ static void sulogin (bool cont)
|
||||
tcsetattr(fileno(stdin), TCSANOW, termios_orig);
|
||||
|
||||
#ifdef __linux__
|
||||
execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
|
||||
execl(SULOGIN, SULOGIN, (char *) NULL);
|
||||
eerror("%s: unable to exec `%s': %s", applet, SULOGIN,
|
||||
strerror(errno));
|
||||
#else
|
||||
execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
|
||||
execl("/bin/sh", "/bin/sh", (char *) NULL);
|
||||
eerror("%s: unable to exec `/bin/sh': %s", applet,
|
||||
strerror(errno));
|
||||
#endif
|
||||
@ -382,17 +372,17 @@ static bool set_ksoftlevel (const char *level)
|
||||
if (exists(RC_KSOFTLEVEL) &&
|
||||
unlink(RC_KSOFTLEVEL) != 0)
|
||||
eerror("unlink `%s': %s", RC_KSOFTLEVEL, strerror(errno));
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! (fp = fopen(RC_KSOFTLEVEL, "w"))) {
|
||||
eerror("fopen `%s': %s", RC_KSOFTLEVEL, strerror(errno));
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(fp, "%s", level);
|
||||
fclose(fp);
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_ksoftlevel(char *buffer, int buffer_len)
|
||||
@ -401,11 +391,11 @@ static int get_ksoftlevel (char *buffer, int buffer_len)
|
||||
int i = 0;
|
||||
|
||||
if (! exists(RC_KSOFTLEVEL))
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
if (! (fp = fopen(RC_KSOFTLEVEL, "r"))) {
|
||||
eerror("fopen `%s': %s", RC_KSOFTLEVEL, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fgets(buffer, buffer_len, fp)) {
|
||||
@ -415,42 +405,29 @@ static int get_ksoftlevel (char *buffer, int buffer_len)
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return (i);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void add_pid(pid_t pid)
|
||||
{
|
||||
pidlist_t *sp = service_pids;
|
||||
if (sp) {
|
||||
while (sp->next)
|
||||
sp = sp->next;
|
||||
sp->next = xmalloc (sizeof (*sp->next));
|
||||
sp = sp->next;
|
||||
} else
|
||||
sp = service_pids = xmalloc (sizeof (*sp));
|
||||
memset (sp, 0, sizeof (*sp));
|
||||
sp->pid = pid;
|
||||
PIDITEM *p = xmalloc(sizeof(*p));
|
||||
p->pid = pid;
|
||||
LIST_INSERT_HEAD(&service_pids, p, entries);
|
||||
}
|
||||
|
||||
static void remove_pid(pid_t pid)
|
||||
{
|
||||
pidlist_t *last = NULL;
|
||||
pidlist_t *pl;
|
||||
PIDITEM *p;
|
||||
|
||||
for (pl = service_pids; pl; pl = pl->next) {
|
||||
if (pl->pid == pid) {
|
||||
if (last)
|
||||
last->next = pl->next;
|
||||
else
|
||||
service_pids = pl->next;
|
||||
free (pl);
|
||||
break;
|
||||
}
|
||||
last = pl;
|
||||
LIST_FOREACH(p, &service_pids, entries)
|
||||
if (p->pid == pid) {
|
||||
LIST_REMOVE(p, entries);
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_services ()
|
||||
static void wait_for_services(void)
|
||||
{
|
||||
while (waitpid(0, 0, 0) != -1);
|
||||
}
|
||||
@ -459,8 +436,8 @@ static void handle_signal (int sig)
|
||||
{
|
||||
int serrno = errno;
|
||||
char signame[10] = { '\0' };
|
||||
pidlist_t *pl;
|
||||
pid_t pid;
|
||||
PIDITEM *pi;
|
||||
int status = 0;
|
||||
struct winsize ws;
|
||||
sigset_t sset;
|
||||
@ -510,8 +487,8 @@ static void handle_signal (int sig)
|
||||
sigprocmask(SIG_BLOCK, &sset, NULL);
|
||||
|
||||
/* Kill any running services we have started */
|
||||
for (pl = service_pids; pl; pl = pl->next)
|
||||
kill (pl->pid, SIGTERM);
|
||||
LIST_FOREACH(pi, &service_pids, entries)
|
||||
kill(pi->pid, SIGTERM);
|
||||
|
||||
/* Notify plugins we are aborting */
|
||||
rc_plugin_run(RC_HOOK_ABORT, NULL);
|
||||
@ -540,6 +517,7 @@ static void run_script (const char *script)
|
||||
{
|
||||
int status = 0;
|
||||
pid_t pid = vfork();
|
||||
pid_t wpid;
|
||||
|
||||
if (pid < 0)
|
||||
eerrorx("%s: vfork: %s", applet, strerror(errno));
|
||||
@ -551,7 +529,7 @@ static void run_script (const char *script)
|
||||
}
|
||||
|
||||
do {
|
||||
pid_t wpid = waitpid (pid, &status, 0);
|
||||
wpid = waitpid(pid, &status, 0);
|
||||
if (wpid < 1)
|
||||
eerror("waitpid: %s", strerror(errno));
|
||||
} while (! WIFEXITED(status) && ! WIFSIGNALED(status));
|
||||
@ -562,14 +540,15 @@ static void run_script (const char *script)
|
||||
|
||||
static void do_coldplug(void)
|
||||
{
|
||||
size_t s;
|
||||
int i;
|
||||
size_t l;
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
char *service;
|
||||
RC_STRING *s;
|
||||
#ifdef BSD
|
||||
struct ifaddrs *ifap;
|
||||
struct ifaddrs *ifa;
|
||||
char *p;
|
||||
#endif
|
||||
|
||||
if (! rc_conf_yesno("rc_coldplug") && errno != ENOENT)
|
||||
@ -585,13 +564,13 @@ static void do_coldplug (void)
|
||||
if (ifa->ifa_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
|
||||
s = strlen ("net.") + strlen (ifa->ifa_name) + 1;
|
||||
tmp = xmalloc (sizeof (char) * s);
|
||||
snprintf (tmp, s, "net.%s", ifa->ifa_name);
|
||||
if (rc_service_exists (tmp) &&
|
||||
service_plugable (tmp))
|
||||
rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
|
||||
CHAR_FREE (tmp);
|
||||
l = strlen("net.") + strlen(ifa->ifa_name) + 1;
|
||||
service = xmalloc(sizeof (char) * l);
|
||||
snprintf(service, l, "net.%s", ifa->ifa_name);
|
||||
if (rc_service_exists(service) &&
|
||||
service_plugable(service))
|
||||
rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
|
||||
free(service);
|
||||
}
|
||||
freeifaddrs (ifap);
|
||||
}
|
||||
@ -603,15 +582,15 @@ static void do_coldplug (void)
|
||||
if (strncmp(d->d_name, "psm", 3) == 0 ||
|
||||
strncmp(d->d_name, "ums", 3) == 0)
|
||||
{
|
||||
char *p = d->d_name + 3;
|
||||
p = d->d_name + 3;
|
||||
if (p && isdigit((int) *p)) {
|
||||
s = strlen ("moused.") + strlen (d->d_name) + 1;
|
||||
tmp = xmalloc (sizeof (char) * s);
|
||||
snprintf (tmp, s, "moused.%s", d->d_name);
|
||||
if (rc_service_exists (tmp) &&
|
||||
service_plugable (tmp))
|
||||
rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
|
||||
CHAR_FREE (tmp);
|
||||
l = strlen("moused.") + strlen(d->d_name) + 1;
|
||||
service = xmalloc(sizeof(char) * l);
|
||||
snprintf (service, l, "moused.%s", d->d_name);
|
||||
if (rc_service_exists (service) &&
|
||||
service_plugable (service))
|
||||
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
|
||||
free(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -635,15 +614,13 @@ static void do_coldplug (void)
|
||||
service_plugable(d->d_name))
|
||||
rc_service_mark(d->d_name, RC_SERVICE_COLDPLUGGED);
|
||||
|
||||
s = strlen (DEVBOOT "/") + strlen (d->d_name) + 1;
|
||||
tmp = xmalloc (sizeof (char) * s);
|
||||
snprintf (tmp, s, DEVBOOT "/%s", d->d_name);
|
||||
if (tmp) {
|
||||
if (unlink (tmp))
|
||||
eerror ("%s: unlink `%s': %s", applet, tmp,
|
||||
l = strlen(DEVBOOT "/") + strlen(d->d_name) + 1;
|
||||
service = xmalloc(sizeof (char) * l);
|
||||
snprintf(service, l, DEVBOOT "/%s", d->d_name);
|
||||
if (unlink(service))
|
||||
eerror("%s: unlink `%s': %s", applet, service,
|
||||
strerror(errno));
|
||||
free (tmp);
|
||||
}
|
||||
free(service);
|
||||
}
|
||||
closedir(dp);
|
||||
rmdir(DEVBOOT);
|
||||
@ -656,11 +633,29 @@ static void do_coldplug (void)
|
||||
/* Load our list of coldplugged services and display them */
|
||||
einfon("Device initiated services:%s", ecolor(ECOLOR_HILITE));
|
||||
coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
|
||||
STRLIST_FOREACH (coldplugged_services, service, i)
|
||||
printf (" %s", service);
|
||||
TAILQ_FOREACH(s, coldplugged_services, entries)
|
||||
printf(" %s", s->value);
|
||||
printf ("%s\n", ecolor(ECOLOR_NORMAL));
|
||||
}
|
||||
|
||||
static bool runlevel_config(const char *service, const char *level)
|
||||
{
|
||||
char *init = rc_service_resolve(service);
|
||||
char *conf;
|
||||
size_t l;
|
||||
bool retval;
|
||||
|
||||
init = dirname(init);
|
||||
init = dirname(init);
|
||||
l = strlen(init) + strlen(level) + strlen(service) + 10;
|
||||
conf = xmalloc(sizeof(char) * l);
|
||||
snprintf(conf, l, "%s/conf.d/%s.%s", init, service, level);
|
||||
retval = exists(conf);
|
||||
free(conf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
#define getoptstring "o:" getoptstring_COMMON
|
||||
static const struct option longopts[] = {
|
||||
@ -678,11 +673,9 @@ int main (int argc, char **argv)
|
||||
const char *bootlevel = NULL;
|
||||
const char *sys = rc_sys();
|
||||
char *newlevel = NULL;
|
||||
char *service = NULL;
|
||||
char **deporder = NULL;
|
||||
char **tmplist;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
RC_STRINGLIST *deporder = NULL;
|
||||
RC_STRINGLIST *tmplist;
|
||||
RC_STRING *service;
|
||||
bool going_down = false;
|
||||
bool interactive = false;
|
||||
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
|
||||
@ -692,8 +685,18 @@ int main (int argc, char **argv)
|
||||
bool parallel;
|
||||
int regen = 0;
|
||||
pid_t pid;
|
||||
RC_STRING *svc1;
|
||||
RC_STRING *svc2 = NULL;
|
||||
struct utsname uts;
|
||||
#ifdef __linux__
|
||||
char *cmd;
|
||||
char *proc;
|
||||
char *p;
|
||||
char *token;
|
||||
#endif
|
||||
|
||||
applet = basename_c(argv[0]);
|
||||
LIST_INIT(&service_pids);
|
||||
atexit(cleanup);
|
||||
if (! applet)
|
||||
eerrorx("arguments required");
|
||||
@ -727,40 +730,8 @@ int main (int argc, char **argv)
|
||||
|
||||
/* Ensure our environment is pure
|
||||
* Also, add our configuration to it */
|
||||
env = env_filter ();
|
||||
tmplist = env_config ();
|
||||
rc_strlist_join (&env, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
|
||||
if (env) {
|
||||
char *p;
|
||||
|
||||
#ifdef __linux__
|
||||
/* clearenv isn't portable, but there's no harm in using it
|
||||
* if we have it */
|
||||
clearenv ();
|
||||
#else
|
||||
char *var;
|
||||
/* No clearenv present here then.
|
||||
* We could manipulate environ directly ourselves, but it seems that
|
||||
* some kernels bitch about this according to the environ man pages
|
||||
* so we walk though environ and call unsetenv for each value. */
|
||||
while (environ[0]) {
|
||||
tmp = xstrdup (environ[0]);
|
||||
p = tmp;
|
||||
var = strsep (&p, "=");
|
||||
unsetenv (var);
|
||||
free (tmp);
|
||||
}
|
||||
tmp = NULL;
|
||||
#endif
|
||||
|
||||
STRLIST_FOREACH (env, p, i)
|
||||
if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
|
||||
putenv (p);
|
||||
|
||||
/* We don't free our list as that would be null in environ */
|
||||
}
|
||||
env_filter();
|
||||
env_config();
|
||||
|
||||
argc++;
|
||||
argv--;
|
||||
@ -817,12 +788,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
||||
struct utsname uts;
|
||||
/* OK, we're either in runlevel 1 or single user mode */
|
||||
#ifdef __linux__
|
||||
char *cmd;
|
||||
#endif
|
||||
|
||||
/* exec init-early.sh if it exists
|
||||
* This should just setup the console to use the correct
|
||||
@ -945,7 +911,7 @@ int main (int argc, char **argv)
|
||||
{
|
||||
going_down = true;
|
||||
rc_runlevel_set(newlevel);
|
||||
setenv ("RC_SOFTLEVEL", newlevel, 1);
|
||||
setenv("RC_RUNLEVEL", newlevel, 1);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/* FIXME: we shouldn't have todo this */
|
||||
@ -977,30 +943,33 @@ int main (int argc, char **argv)
|
||||
if (mkdir(RC_STOPPING, 0755) != 0) {
|
||||
if (errno == EACCES)
|
||||
eerrorx("%s: superuser access required", applet);
|
||||
eerrorx ("%s: failed to create stopping dir: %s",
|
||||
applet, strerror (errno));
|
||||
eerrorx("%s: failed to create stopping dir `%s': %s",
|
||||
applet, RC_STOPPING, strerror(errno));
|
||||
}
|
||||
|
||||
/* Build a list of all services to stop and then work out the
|
||||
* correct order for stopping them */
|
||||
stop_services = rc_services_in_state (RC_SERVICE_STARTING);
|
||||
|
||||
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||
rc_strlist_join (&stop_services, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
TAILQ_CONCAT(stop_services, tmplist);
|
||||
free(tmplist);
|
||||
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
|
||||
TAILQ_CONCAT(stop_services, tmplist);
|
||||
free(tmplist);
|
||||
rc_stringlist_sort(&stop_services);
|
||||
|
||||
tmplist = rc_services_in_state (RC_SERVICE_STARTED);
|
||||
rc_strlist_join (&stop_services, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
types_n = rc_stringlist_new();
|
||||
rc_stringlist_add(types_n, "needsme");
|
||||
|
||||
deporder = rc_deptree_depends (deptree, types_nua,
|
||||
(const char **) stop_services,
|
||||
types_nua = rc_stringlist_new();
|
||||
rc_stringlist_add(types_nua, "ineed");
|
||||
rc_stringlist_add(types_nua, "iuse");
|
||||
rc_stringlist_add(types_nua, "iafter");
|
||||
|
||||
tmplist = rc_deptree_depends(deptree, types_nua, stop_services,
|
||||
runlevel, depoptions | RC_DEP_STOP);
|
||||
|
||||
rc_strlist_free (stop_services);
|
||||
stop_services = deporder;
|
||||
deporder = NULL;
|
||||
rc_strlist_reverse (stop_services);
|
||||
rc_stringlist_free(stop_services);
|
||||
stop_services = tmplist;
|
||||
|
||||
/* Load our list of coldplugged services */
|
||||
coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
|
||||
@ -1012,12 +981,12 @@ int main (int argc, char **argv)
|
||||
start_services = rc_services_in_runlevel(bootlevel);
|
||||
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
|
||||
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
|
||||
rc_strlist_join (&start_services, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
TAILQ_CONCAT(start_services, tmplist);
|
||||
free(tmplist);
|
||||
}
|
||||
|
||||
STRLIST_FOREACH (coldplugged_services, service, i)
|
||||
rc_strlist_add (&start_services, service);
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_stringlist_addu(start_services, service->value);
|
||||
}
|
||||
|
||||
/* Save our softlevel now */
|
||||
@ -1027,87 +996,61 @@ int main (int argc, char **argv)
|
||||
parallel = rc_conf_yesno("rc_parallel");
|
||||
|
||||
/* Now stop the services that shouldn't be running */
|
||||
STRLIST_FOREACH (stop_services, service, i) {
|
||||
bool found = false;
|
||||
char *conf = NULL;
|
||||
char **stopdeps = NULL;
|
||||
char *svc1 = NULL;
|
||||
char *svc2 = NULL;
|
||||
int k;
|
||||
|
||||
if (rc_service_state (service) & RC_SERVICE_STOPPED)
|
||||
TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) {
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
|
||||
/* We always stop the service when in these runlevels */
|
||||
if (going_down) {
|
||||
pid = rc_service_stop (service);
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0 && ! parallel)
|
||||
rc_waitpid(pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're in the start list then don't bother stopping us */
|
||||
STRLIST_FOREACH (start_services, svc1, j)
|
||||
if (strcmp (svc1, service) == 0) {
|
||||
found = true;
|
||||
TAILQ_FOREACH(svc1, start_services, entries)
|
||||
if (strcmp (svc1->value, service->value) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unless we would use a different config file */
|
||||
if (found) {
|
||||
size_t len;
|
||||
if (! newlevel)
|
||||
continue;
|
||||
|
||||
len = strlen (service) + strlen (runlevel) + 2;
|
||||
tmp = xmalloc (sizeof (char) * len);
|
||||
snprintf (tmp, len, "%s.%s", service, runlevel);
|
||||
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
|
||||
found = exists (conf);
|
||||
CHAR_FREE (conf);
|
||||
CHAR_FREE (tmp);
|
||||
if (! found) {
|
||||
len = strlen (service) + strlen (newlevel) + 2;
|
||||
tmp = xmalloc (sizeof (char) * len);
|
||||
snprintf (tmp, len, "%s.%s", service, newlevel);
|
||||
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
|
||||
found = exists (conf);
|
||||
CHAR_FREE (conf);
|
||||
CHAR_FREE (tmp);
|
||||
if (!found)
|
||||
if (svc1) {
|
||||
if (newlevel && strcmp(runlevel, newlevel) != 0) {
|
||||
/* So we're in the start list. But we should
|
||||
* be stopped if we have a runlevel
|
||||
* configuration file for either the current
|
||||
* or next so we use the correct one. */
|
||||
if (! runlevel_config(service->value, runlevel) &&
|
||||
! runlevel_config(service->value, newlevel))
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* Allow coldplugged services not to be in the runlevels list */
|
||||
if (rc_service_state (service) & RC_SERVICE_COLDPLUGGED)
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We got this far! Or last check is to see if any any service that
|
||||
* going to be started depends on us */
|
||||
rc_strlist_add (&stopdeps, service);
|
||||
deporder = rc_deptree_depends (deptree, types_n,
|
||||
(const char **) stopdeps,
|
||||
/* We got this far! Or last check is to see if any any service
|
||||
* that going to be started depends on us */
|
||||
if (! svc1) {
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, service->value);
|
||||
deporder = rc_deptree_depends(deptree, types_n, tmplist,
|
||||
runlevel, RC_DEP_STRICT);
|
||||
rc_strlist_free (stopdeps);
|
||||
stopdeps = NULL;
|
||||
found = false;
|
||||
STRLIST_FOREACH (deporder, svc1, j) {
|
||||
STRLIST_FOREACH (start_services, svc2, k)
|
||||
if (strcmp (svc1, svc2) == 0) {
|
||||
found = true;
|
||||
rc_stringlist_free(tmplist);
|
||||
svc2 = NULL;
|
||||
TAILQ_FOREACH (svc1, deporder, entries) {
|
||||
TAILQ_FOREACH(svc2, start_services, entries)
|
||||
if (strcmp (svc1->value, svc2->value) == 0)
|
||||
break;
|
||||
if (svc2)
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
rc_stringlist_free(deporder);
|
||||
|
||||
if (svc2)
|
||||
continue;
|
||||
}
|
||||
rc_strlist_free (deporder);
|
||||
deporder = NULL;
|
||||
|
||||
/* After all that we can finally stop the blighter! */
|
||||
if (! found) {
|
||||
pid = rc_service_stop (service);
|
||||
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0) {
|
||||
add_pid(pid);
|
||||
if (! parallel) {
|
||||
@ -1116,7 +1059,6 @@ int main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for our services to finish */
|
||||
wait_for_services();
|
||||
@ -1132,7 +1074,7 @@ int main (int argc, char **argv)
|
||||
rc_runlevel_set(newlevel);
|
||||
free(runlevel);
|
||||
runlevel = xstrdup(newlevel);
|
||||
setenv ("RC_SOFTLEVEL", runlevel, 1);
|
||||
setenv("RC_RUNLEVEL", runlevel, 1);
|
||||
}
|
||||
|
||||
/* Run the halt script if needed */
|
||||
@ -1157,40 +1099,38 @@ int main (int argc, char **argv)
|
||||
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
||||
|
||||
/* Re-add our coldplugged services if they stopped */
|
||||
STRLIST_FOREACH (coldplugged_services, service, i)
|
||||
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
|
||||
|
||||
/* Order the services to start */
|
||||
deporder = rc_deptree_depends (deptree, types_nua,
|
||||
(const char **) start_services,
|
||||
rc_stringlist_sort(&start_services);
|
||||
deporder = rc_deptree_depends(deptree, types_nua, start_services,
|
||||
runlevel, depoptions | RC_DEP_START);
|
||||
rc_strlist_free (start_services);
|
||||
rc_stringlist_free(start_services);
|
||||
start_services = deporder;
|
||||
deporder = NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
/* mark any services skipped as started */
|
||||
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
|
||||
if ((service = proc_getent ("noinitd"))) {
|
||||
char *p = service;
|
||||
char *token;
|
||||
|
||||
proc = p = proc_getent("noinitd");
|
||||
if (proc) {
|
||||
while ((token = strsep(&p, ",")))
|
||||
rc_service_mark(token, RC_SERVICE_STARTED);
|
||||
free (service);
|
||||
free(proc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STRLIST_FOREACH (start_services, service, i) {
|
||||
if (rc_service_state (service) & RC_SERVICE_STOPPED) {
|
||||
TAILQ_FOREACH(service, start_services, entries) {
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED) {
|
||||
if (! interactive)
|
||||
interactive = want_interactive();
|
||||
|
||||
if (interactive) {
|
||||
interactive_retry:
|
||||
printf("\n");
|
||||
einfo ("About to start the service %s", service);
|
||||
einfo("About to start the service %s",
|
||||
service->value);
|
||||
eindent();
|
||||
einfo("1) Start the service\t\t2) Skip the service");
|
||||
einfo("3) Continue boot process\t\t4) Exit to shell");
|
||||
@ -1205,7 +1145,7 @@ interactive_option:
|
||||
}
|
||||
}
|
||||
|
||||
pid = rc_service_start (service);
|
||||
pid = rc_service_start(service->value);
|
||||
|
||||
/* Remember the pid if we're running in parallel */
|
||||
if (pid > 0) {
|
||||
@ -1228,13 +1168,11 @@ interactive_option:
|
||||
#ifdef __linux__
|
||||
/* mark any services skipped as stopped */
|
||||
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
|
||||
if ((service = proc_getent ("noinitd"))) {
|
||||
char *p = service;
|
||||
char *token;
|
||||
|
||||
proc = p = proc_getent("noinitd");
|
||||
if (proc) {
|
||||
while ((token = strsep(&p, ",")))
|
||||
rc_service_mark(token, RC_SERVICE_STOPPED);
|
||||
free (service);
|
||||
free(proc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1251,8 +1189,8 @@ interactive_option:
|
||||
* we need to delete them so that they are regenerated again in the
|
||||
* default runlevel as they may depend on things that are now available */
|
||||
if (regen && strcmp(runlevel, bootlevel) == 0)
|
||||
unlink (RC_DEPTREE);
|
||||
unlink(RC_DEPTREE_CACHE);
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -60,7 +61,6 @@
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "rc-plugin.h"
|
||||
#include "strlist.h"
|
||||
|
||||
#define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
|
||||
|
||||
@ -75,39 +75,33 @@
|
||||
#define ONE_SECOND 1000000000
|
||||
|
||||
static const char *applet = NULL;
|
||||
static char **applet_list = NULL;
|
||||
static RC_STRINGLIST *applet_list = NULL;
|
||||
static RC_STRINGLIST *restart_services = NULL;
|
||||
static RC_STRINGLIST *need_services = NULL;
|
||||
static RC_STRINGLIST *use_services = NULL;
|
||||
static RC_STRINGLIST *services = NULL;
|
||||
static RC_STRINGLIST *tmplist = NULL;
|
||||
static char *service = NULL;
|
||||
static char *exclusive = NULL;
|
||||
static char *mtime_test = NULL;
|
||||
static rc_depinfo_t *deptree = NULL;
|
||||
static char **services = NULL;
|
||||
static char **tmplist = NULL;
|
||||
static char **providelist = NULL;
|
||||
static char **restart_services = NULL;
|
||||
static char **need_services = NULL;
|
||||
static char **use_services = NULL;
|
||||
static char **env = NULL;
|
||||
static char *tmp = NULL;
|
||||
static char *softlevel = NULL;
|
||||
static RC_DEPTREE *deptree = NULL;
|
||||
static char *runlevel = NULL;
|
||||
static bool sighup = false;
|
||||
static char *ibsave = NULL;
|
||||
static bool in_background = false;
|
||||
static rc_hook_t hook_out = 0;
|
||||
static RC_HOOK hook_out = 0;
|
||||
static pid_t service_pid = 0;
|
||||
static char *prefix = NULL;
|
||||
static bool prefix_locked = false;
|
||||
static int signal_pipe[2] = { -1, -1 };
|
||||
static int master_tty = -1;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static const char *const types_b[] = { "broken", NULL };
|
||||
static const char *const types_n[] = { "ineed", NULL };
|
||||
static const char *const types_nu[] = { "ineed", "iuse", NULL };
|
||||
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
|
||||
|
||||
static const char *const types_m[] = { "needsme", NULL };
|
||||
static const char *const types_mua[] = { "needsme", "usesme", "beforeme", NULL };
|
||||
static RC_STRINGLIST *types_b = NULL;
|
||||
static RC_STRINGLIST *types_n = NULL;
|
||||
static RC_STRINGLIST *types_nu = NULL;
|
||||
static RC_STRINGLIST *types_nua = NULL;
|
||||
static RC_STRINGLIST *types_m = NULL;
|
||||
static RC_STRINGLIST *types_mua = NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
static void (*selinux_run_init_old)(void);
|
||||
@ -203,50 +197,52 @@ static time_t get_mtime (const char *pathname, bool follow_link)
|
||||
int retval;
|
||||
|
||||
if (! pathname)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
|
||||
if (! retval)
|
||||
return (buf.st_mtime);
|
||||
return buf.st_mtime;
|
||||
|
||||
errno = 0;
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const tests[] = {
|
||||
"starting", "started", "stopping", "inactive", "wasinactive", NULL
|
||||
};
|
||||
static bool in_control()
|
||||
{
|
||||
char *path;
|
||||
time_t m;
|
||||
time_t mtime;
|
||||
const char *tests[] = { "starting", "started", "stopping",
|
||||
"inactive", "wasinactive", NULL };
|
||||
int i = 0;
|
||||
|
||||
if (sighup)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (! mtime_test || ! exists(mtime_test))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (rc_service_state(applet) & RC_SERVICE_STOPPED)
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
if (! (mtime = get_mtime(mtime_test, false)))
|
||||
return (false);
|
||||
return false;
|
||||
|
||||
while (tests[i]) {
|
||||
path = rc_strcatpaths(RC_SVCDIR, tests[i], applet, (char *) NULL);
|
||||
if (exists(path)) {
|
||||
time_t m = get_mtime (path, false);
|
||||
m = get_mtime(path, false);
|
||||
if (mtime < m && m != 0) {
|
||||
free(path);
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
i++;
|
||||
}
|
||||
|
||||
return (true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void uncoldplug()
|
||||
@ -257,10 +253,9 @@ static void uncoldplug ()
|
||||
free(cold);
|
||||
}
|
||||
|
||||
static void start_services (char **list) {
|
||||
char *svc;
|
||||
int i;
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
static void start_services(RC_STRINGLIST *list) {
|
||||
RC_STRING *svc;
|
||||
RC_SERVICE state = rc_service_state (service);
|
||||
|
||||
if (! list)
|
||||
return;
|
||||
@ -270,16 +265,17 @@ static void start_services (char **list) {
|
||||
state & RC_SERVICE_STARTING ||
|
||||
state & RC_SERVICE_STARTED)
|
||||
{
|
||||
STRLIST_FOREACH (list, svc, i) {
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED) {
|
||||
TAILQ_FOREACH(svc, list, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
||||
if (state & RC_SERVICE_INACTIVE ||
|
||||
state & RC_SERVICE_WASINACTIVE)
|
||||
{
|
||||
rc_service_schedule_start (service, svc);
|
||||
ewarn ("WARNING: %s is scheduled to started when %s has started",
|
||||
svc, applet);
|
||||
rc_service_schedule_start(service, svc->value);
|
||||
ewarn("WARNING: %s is scheduled to started"
|
||||
" when %s has started",
|
||||
svc->value, applet);
|
||||
} else
|
||||
rc_service_start (svc);
|
||||
rc_service_start(svc->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -287,14 +283,13 @@ static void start_services (char **list) {
|
||||
|
||||
static void restore_state(void)
|
||||
{
|
||||
rc_service_state_t state;
|
||||
RC_SERVICE state;
|
||||
|
||||
if (rc_in_plugin || ! in_control())
|
||||
return;
|
||||
|
||||
state = rc_service_state(applet);
|
||||
if (state & RC_SERVICE_STOPPING) {
|
||||
|
||||
if (state & RC_SERVICE_WASINACTIVE)
|
||||
rc_service_mark(applet, RC_SERVICE_INACTIVE);
|
||||
else
|
||||
@ -335,18 +330,23 @@ static void cleanup (void)
|
||||
start_services(restart_services);
|
||||
}
|
||||
|
||||
rc_stringlist_free(types_b);
|
||||
rc_stringlist_free(types_n);
|
||||
rc_stringlist_free(types_nu);
|
||||
rc_stringlist_free(types_nua);
|
||||
rc_stringlist_free(types_m);
|
||||
rc_stringlist_free(types_mua);
|
||||
|
||||
rc_plugin_unload();
|
||||
rc_deptree_free(deptree);
|
||||
rc_strlist_free (services);
|
||||
rc_strlist_free (providelist);
|
||||
rc_strlist_free (need_services);
|
||||
rc_strlist_free (use_services);
|
||||
rc_strlist_free (restart_services);
|
||||
rc_strlist_free (applet_list);
|
||||
rc_strlist_free (tmplist);
|
||||
free (ibsave);
|
||||
|
||||
rc_strlist_free (env);
|
||||
rc_stringlist_free(restart_services);
|
||||
rc_stringlist_free(need_services);
|
||||
rc_stringlist_free(use_services);
|
||||
rc_stringlist_free(services);
|
||||
rc_stringlist_free(applet_list);
|
||||
rc_stringlist_free(tmplist);
|
||||
free (ibsave);
|
||||
|
||||
if (mtime_test)
|
||||
{
|
||||
@ -357,7 +357,7 @@ static void cleanup (void)
|
||||
free(exclusive);
|
||||
free(service);
|
||||
free(prefix);
|
||||
free (softlevel);
|
||||
free(runlevel);
|
||||
}
|
||||
|
||||
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
|
||||
@ -385,7 +385,7 @@ static int write_prefix (const char *buffer, size_t bytes, bool *prefixed) {
|
||||
ret += write(fd, buffer + i, 1);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool svc_exec(const char *arg1, const char *arg2)
|
||||
@ -501,34 +501,32 @@ static bool svc_exec (const char *arg1, const char *arg2)
|
||||
execok = rc_waitpid(service_pid) == 0 ? true : false;
|
||||
service_pid = 0;
|
||||
|
||||
return (execok);
|
||||
return execok;
|
||||
}
|
||||
|
||||
static bool svc_wait (rc_depinfo_t *depinfo, const char *svc)
|
||||
static bool svc_wait(const char *svc)
|
||||
{
|
||||
char *s;
|
||||
char *fifo;
|
||||
char fifo[PATH_MAX];
|
||||
struct timespec ts;
|
||||
int nloops = WAIT_MAX * (ONE_SECOND / WAIT_INTERVAL);
|
||||
bool retval = false;
|
||||
bool forever = false;
|
||||
char **keywords = NULL;
|
||||
int i;
|
||||
|
||||
if (! service)
|
||||
return (false);
|
||||
RC_STRINGLIST *keywords;
|
||||
RC_STRING *s;
|
||||
|
||||
/* Some services don't have a timeout, like fsck */
|
||||
keywords = rc_deptree_depend (depinfo, svc, "keyword");
|
||||
STRLIST_FOREACH (keywords, s, i) {
|
||||
if (strcmp (s, "notimeout") == 0) {
|
||||
keywords = rc_deptree_depend(deptree, svc, "keyword");
|
||||
if (keywords) {
|
||||
TAILQ_FOREACH(s, keywords, entries) {
|
||||
if (strcmp (s->value, "notimeout") == 0) {
|
||||
forever = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc_strlist_free (keywords);
|
||||
rc_stringlist_free (keywords);
|
||||
}
|
||||
|
||||
fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename_c (svc), (char *) NULL);
|
||||
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", basename_c(svc));
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = WAIT_INTERVAL;
|
||||
|
||||
@ -549,16 +547,14 @@ static bool svc_wait (rc_depinfo_t *depinfo, const char *svc)
|
||||
|
||||
if (! exists(fifo))
|
||||
retval = true;
|
||||
free (fifo);
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static rc_service_state_t svc_status ()
|
||||
static RC_SERVICE svc_status(void)
|
||||
{
|
||||
char status[10];
|
||||
int (*e) (const char *fmt, ...) = &einfo;
|
||||
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
|
||||
if (state & RC_SERVICE_STOPPING) {
|
||||
snprintf(status, sizeof(status), "stopping");
|
||||
@ -570,7 +566,7 @@ static rc_service_state_t svc_status ()
|
||||
snprintf(status, sizeof(status), "inactive");
|
||||
e = &ewarn;
|
||||
} 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");
|
||||
e = &eerror;
|
||||
} else
|
||||
@ -579,10 +575,10 @@ static rc_service_state_t svc_status ()
|
||||
snprintf(status, sizeof(status), "stopped");
|
||||
|
||||
e("status: %s", status);
|
||||
return (state);
|
||||
return state;
|
||||
}
|
||||
|
||||
static void make_exclusive ()
|
||||
static void make_exclusive(void)
|
||||
{
|
||||
char *path;
|
||||
size_t l;
|
||||
@ -618,7 +614,7 @@ static void make_exclusive ()
|
||||
}
|
||||
}
|
||||
|
||||
static void unlink_mtime_test ()
|
||||
static void unlink_mtime_test(void)
|
||||
{
|
||||
if (unlink(mtime_test) != 0)
|
||||
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
|
||||
@ -626,27 +622,54 @@ static void unlink_mtime_test ()
|
||||
mtime_test = NULL;
|
||||
}
|
||||
|
||||
static void get_started_services ()
|
||||
static void get_started_services(void)
|
||||
{
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
|
||||
rc_strlist_free (restart_services);
|
||||
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||
rc_stringlist_free(restart_services);
|
||||
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||
rc_strlist_join (&restart_services, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = NULL;
|
||||
TAILQ_CONCAT(restart_services, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void setup_types(void)
|
||||
{
|
||||
types_b = rc_stringlist_new();
|
||||
rc_stringlist_add(types_b, "broken");
|
||||
|
||||
types_n = rc_stringlist_new();
|
||||
rc_stringlist_add(types_n, "ineed");
|
||||
|
||||
types_nu = rc_stringlist_new();
|
||||
rc_stringlist_add(types_nu, "ineed");
|
||||
rc_stringlist_add(types_nu, "iuse");
|
||||
|
||||
types_nua = rc_stringlist_new();
|
||||
rc_stringlist_add(types_nua, "ineed");
|
||||
rc_stringlist_add(types_nua, "iuse");
|
||||
rc_stringlist_add(types_nua, "iafter");
|
||||
|
||||
types_m = rc_stringlist_new();
|
||||
rc_stringlist_add(types_m, "needsme");
|
||||
|
||||
types_mua = rc_stringlist_new();
|
||||
rc_stringlist_add(types_mua, "needsme");
|
||||
rc_stringlist_add(types_mua, "usesme");
|
||||
rc_stringlist_add(types_mua, "beforeme");
|
||||
}
|
||||
|
||||
static void svc_start(bool deps)
|
||||
{
|
||||
bool started;
|
||||
bool background = false;
|
||||
char *svc;
|
||||
char *svc2;
|
||||
int i;
|
||||
int j;
|
||||
RC_STRING *svc;
|
||||
RC_STRING *svc2;
|
||||
int depoptions = RC_DEP_TRACE;
|
||||
rc_service_state_t state;
|
||||
RC_SERVICE state;
|
||||
bool first;
|
||||
int n;
|
||||
size_t len;
|
||||
char *p;
|
||||
char *tmp;
|
||||
|
||||
state = rc_service_state(service);
|
||||
|
||||
@ -673,7 +696,7 @@ static void svc_start (bool deps)
|
||||
eerrorx("ERROR: %s has been started by something else", applet);
|
||||
}
|
||||
|
||||
make_exclusive (service);
|
||||
make_exclusive();
|
||||
|
||||
hook_out = RC_HOOK_SERVICE_START_OUT;
|
||||
rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet);
|
||||
@ -685,52 +708,48 @@ static void svc_start (bool deps)
|
||||
if (! deptree && ((deptree = _rc_deptree_load (NULL)) == NULL))
|
||||
eerrorx("failed to load deptree");
|
||||
|
||||
rc_strlist_free (services);
|
||||
services = rc_deptree_depends (deptree, types_b,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, 0);
|
||||
if (services) {
|
||||
if (! types_b)
|
||||
setup_types();
|
||||
|
||||
services = rc_deptree_depends(deptree, types_b, applet_list,
|
||||
runlevel, 0);
|
||||
if (TAILQ_FIRST(services)) {
|
||||
eerrorn ("ERROR: `%s' needs ", applet);
|
||||
STRLIST_FOREACH (services, svc, i) {
|
||||
if (i > 0)
|
||||
first = true;
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
fprintf(stderr, ", ");
|
||||
fprintf (stderr, "%s", svc);
|
||||
fprintf(stderr, "%s", svc->value);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
|
||||
rc_strlist_free (need_services);
|
||||
need_services = rc_deptree_depends (deptree, types_n,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
need_services = rc_deptree_depends(deptree, types_n, applet_list,
|
||||
runlevel, depoptions);
|
||||
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
|
||||
runlevel, depoptions);
|
||||
|
||||
rc_strlist_free (use_services);
|
||||
use_services = rc_deptree_depends (deptree, types_nu,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
|
||||
if (! rc_runlevel_starting ()) {
|
||||
STRLIST_FOREACH (use_services, svc, i)
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED) {
|
||||
pid_t pid = rc_service_start (svc);
|
||||
if (! rc_runlevel_starting())
|
||||
TAILQ_FOREACH(svc, use_services, entries)
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
||||
pid_t pid = rc_service_start(svc->value);
|
||||
if (! rc_conf_yesno("rc_parallel"))
|
||||
rc_waitpid(pid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now wait for them to start */
|
||||
services = rc_deptree_depends (deptree, types_nua,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
services = rc_deptree_depends(deptree, types_nua, applet_list,
|
||||
runlevel, depoptions);
|
||||
|
||||
/* We use tmplist to hold our scheduled by list */
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = NULL;
|
||||
tmplist = rc_stringlist_new();
|
||||
|
||||
STRLIST_FOREACH (services, svc, i) {
|
||||
rc_service_state_t svcs = rc_service_state (svc);
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED)
|
||||
continue;
|
||||
|
||||
@ -738,71 +757,70 @@ static void svc_start (bool deps)
|
||||
* starting state which we are after */
|
||||
if (svcs & RC_SERVICE_STARTING &&
|
||||
svcs & RC_SERVICE_WASINACTIVE) {
|
||||
bool use = false;
|
||||
STRLIST_FOREACH (use_services, svc2, j)
|
||||
if (strcmp (svc, svc2) == 0) {
|
||||
use = true;
|
||||
TAILQ_FOREACH(svc2, use_services, entries) {
|
||||
if (strcmp (svc->value, svc2->value) == 0)
|
||||
break;
|
||||
}
|
||||
if (! use)
|
||||
if (! svc2)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! svc_wait (deptree, svc))
|
||||
eerror ("%s: timed out waiting for %s", applet, svc);
|
||||
if ((svcs = rc_service_state (svc)) & RC_SERVICE_STARTED)
|
||||
if (! svc_wait(svc->value))
|
||||
eerror ("%s: timed out waiting for %s",
|
||||
applet, svc->value);
|
||||
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
|
||||
continue;
|
||||
|
||||
STRLIST_FOREACH (need_services, svc2, j)
|
||||
if (strcmp (svc, svc2) == 0) {
|
||||
TAILQ_FOREACH(svc2, need_services, entries) {
|
||||
if (strcmp (svc->value, svc2->value) == 0) {
|
||||
if (svcs & RC_SERVICE_INACTIVE ||
|
||||
svcs & RC_SERVICE_WASINACTIVE)
|
||||
rc_strlist_add (&tmplist, svc);
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
else
|
||||
eerrorx ("ERROR: cannot start %s as %s would not start",
|
||||
applet, svc);
|
||||
eerrorx("ERROR: cannot start %s as"
|
||||
" %s would not start",
|
||||
applet, svc->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmplist) {
|
||||
int n = 0;
|
||||
size_t len = 0;
|
||||
char *p;
|
||||
|
||||
if (TAILQ_FIRST(tmplist)) {
|
||||
/* Set the state now, then unlink our exclusive so that
|
||||
our scheduled list is preserved */
|
||||
rc_service_mark(service, RC_SERVICE_STOPPED);
|
||||
unlink_mtime_test();
|
||||
|
||||
STRLIST_FOREACH (tmplist, svc, i) {
|
||||
rc_service_schedule_start (svc, service);
|
||||
rc_strlist_free (providelist);
|
||||
providelist = rc_deptree_depend (deptree, "iprovide", svc);
|
||||
STRLIST_FOREACH (providelist, svc2, j)
|
||||
rc_service_schedule_start (svc2, service);
|
||||
|
||||
len += strlen (svc) + 2;
|
||||
rc_stringlist_free(use_services);
|
||||
use_services = NULL;
|
||||
len = 0;
|
||||
n = 0;
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
rc_service_schedule_start(svc->value, service);
|
||||
use_services = rc_deptree_depend(deptree, "iprovide",
|
||||
svc->value);
|
||||
TAILQ_FOREACH (svc2, use_services, entries)
|
||||
rc_service_schedule_start(svc2->value, service);
|
||||
rc_stringlist_free(use_services);
|
||||
use_services = NULL;
|
||||
len += strlen(svc->value) + 2;
|
||||
n++;
|
||||
}
|
||||
|
||||
len += 5;
|
||||
tmp = xmalloc (sizeof (char) * len);
|
||||
p = tmp;
|
||||
STRLIST_FOREACH (tmplist, svc, i) {
|
||||
if (i > 1) {
|
||||
if (i == n)
|
||||
p += snprintf (p, len, " or ");
|
||||
else
|
||||
tmp = p = xmalloc(sizeof(char) * len);
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
if (p != tmp)
|
||||
p += snprintf(p, len, ", ");
|
||||
p += snprintf(p, len, "%s", svc->value);
|
||||
}
|
||||
p += snprintf (p, len, "%s", svc);
|
||||
}
|
||||
free(tmp);
|
||||
ewarnx("WARNING: %s is scheduled to start when %s has started",
|
||||
applet, tmp);
|
||||
}
|
||||
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
}
|
||||
|
||||
if (ibsave)
|
||||
@ -832,24 +850,30 @@ static void svc_start (bool deps)
|
||||
unlink(exclusive);
|
||||
|
||||
/* Now start any scheduled services */
|
||||
rc_strlist_free (services);
|
||||
services = rc_services_scheduled(service);
|
||||
STRLIST_FOREACH (services, svc, i)
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
|
||||
rc_service_start (svc);
|
||||
rc_strlist_free (services);
|
||||
if (services) {
|
||||
TAILQ_FOREACH(svc, services, entries)
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
rc_service_start(svc->value);
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
}
|
||||
|
||||
/* Do the same for any services we provide */
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = rc_deptree_depend(deptree, "iprovide", applet);
|
||||
|
||||
STRLIST_FOREACH (tmplist, svc2, j) {
|
||||
rc_strlist_free (services);
|
||||
services = rc_services_scheduled (svc2);
|
||||
STRLIST_FOREACH (services, svc, i)
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
|
||||
rc_service_start (svc);
|
||||
if (tmplist) {
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
services = rc_services_scheduled(svc->value);
|
||||
if (services) {
|
||||
TAILQ_FOREACH(svc2, services, entries)
|
||||
if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED)
|
||||
rc_service_start(svc2->value);
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
}
|
||||
}
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
}
|
||||
|
||||
hook_out = 0;
|
||||
@ -859,7 +883,9 @@ static void svc_start (bool deps)
|
||||
static void svc_stop(bool deps)
|
||||
{
|
||||
bool stopped;
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
int depoptions = RC_DEP_TRACE;
|
||||
RC_STRING *svc;
|
||||
|
||||
if (rc_runlevel_stopping() &&
|
||||
state & RC_SERVICE_FAILED)
|
||||
@ -882,7 +908,7 @@ static void svc_stop (bool deps)
|
||||
eerrorx("ERROR: %s has been stopped by something else", applet);
|
||||
}
|
||||
|
||||
make_exclusive (service);
|
||||
make_exclusive();
|
||||
|
||||
hook_out = RC_HOOK_SERVICE_STOP_OUT;
|
||||
rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet);
|
||||
@ -892,9 +918,6 @@ static void svc_stop (bool deps)
|
||||
ewarn ("WARNING: you are stopping a boot service");
|
||||
|
||||
if (deps && ! (state & RC_SERVICE_WASINACTIVE)) {
|
||||
int depoptions = RC_DEP_TRACE;
|
||||
char *svc;
|
||||
int i;
|
||||
|
||||
if (rc_conf_yesno("rc_depend_strict"))
|
||||
depoptions |= RC_DEP_STRICT;
|
||||
@ -902,69 +925,67 @@ static void svc_stop (bool deps)
|
||||
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
|
||||
eerrorx ("failed to load deptree");
|
||||
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = NULL;
|
||||
rc_strlist_free (services);
|
||||
services = rc_deptree_depends (deptree, types_m,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
rc_strlist_reverse (services);
|
||||
STRLIST_FOREACH (services, svc, i) {
|
||||
rc_service_state_t svcs = rc_service_state (svc);
|
||||
if (! types_m)
|
||||
setup_types();
|
||||
|
||||
tmplist = rc_stringlist_new();
|
||||
services = rc_deptree_depends(deptree, types_m, applet_list,
|
||||
runlevel, depoptions);
|
||||
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED ||
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
svc_wait (deptree, svc);
|
||||
svcs = rc_service_state (svc);
|
||||
svc_wait(svc->value);
|
||||
svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED ||
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
pid_t pid = rc_service_stop (svc);
|
||||
pid_t pid = rc_service_stop(svc->value);
|
||||
if (! rc_conf_yesno("rc_parallel"))
|
||||
rc_waitpid(pid);
|
||||
rc_strlist_add (&tmplist, svc);
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
|
||||
STRLIST_FOREACH (tmplist, svc, i) {
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
|
||||
/* We used to loop 3 times here - maybe re-do this if needed */
|
||||
svc_wait (deptree, svc);
|
||||
if (! (rc_service_state (svc) & RC_SERVICE_STOPPED)) {
|
||||
svc_wait(svc->value);
|
||||
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
|
||||
if (rc_runlevel_stopping()) {
|
||||
/* If shutting down, we should stop even if a dependant failed */
|
||||
if (softlevel &&
|
||||
(strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
||||
strcmp (softlevel, RC_LEVEL_REBOOT) == 0 ||
|
||||
strcmp (softlevel, RC_LEVEL_SINGLE) == 0))
|
||||
/* If shutting down, we should stop even
|
||||
* if a dependant failed */
|
||||
if (runlevel &&
|
||||
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
|
||||
continue;
|
||||
rc_service_mark(service, RC_SERVICE_FAILED);
|
||||
}
|
||||
|
||||
eerrorx("ERROR: cannot stop %s as %s is still up",
|
||||
applet, svc);
|
||||
applet, svc->value);
|
||||
}
|
||||
}
|
||||
rc_strlist_free (tmplist);
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
|
||||
/* We now wait for other services that may use us and are stopping
|
||||
This is important when a runlevel stops */
|
||||
services = rc_deptree_depends (deptree, types_mua,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
STRLIST_FOREACH (services, svc, i) {
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
|
||||
services = rc_deptree_depends(deptree, types_mua, applet_list,
|
||||
runlevel, depoptions);
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
svc_wait (deptree, svc);
|
||||
svc_wait(svc->value);
|
||||
}
|
||||
|
||||
rc_strlist_free (services);
|
||||
rc_stringlist_free (services);
|
||||
services = NULL;
|
||||
}
|
||||
|
||||
@ -1012,7 +1033,7 @@ static void svc_restart (bool deps)
|
||||
our status is invalid.
|
||||
One workaround would be to introduce a new status, or status locking. */
|
||||
if (! deps) {
|
||||
rc_service_state_t state = rc_service_state (service);
|
||||
RC_SERVICE state = rc_service_state(service);
|
||||
if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
|
||||
svc_exec("stop", "start");
|
||||
else
|
||||
@ -1027,7 +1048,7 @@ static void svc_restart (bool deps)
|
||||
|
||||
svc_start(deps);
|
||||
start_services(restart_services);
|
||||
rc_strlist_free (restart_services);
|
||||
rc_stringlist_free(restart_services);
|
||||
restart_services = NULL;
|
||||
}
|
||||
|
||||
@ -1050,13 +1071,17 @@ static const char * const longopts_help[] = {
|
||||
|
||||
int runscript(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
bool deps = true;
|
||||
bool doneone = false;
|
||||
char pid[16];
|
||||
int retval;
|
||||
int opt;
|
||||
char *svc;
|
||||
RC_STRING *svc;
|
||||
char dir[PATH_MAX];
|
||||
size_t l = 0;
|
||||
size_t ll;
|
||||
char *save;
|
||||
int depoptions = RC_DEP_TRACE;
|
||||
|
||||
/* Show help if insufficient args */
|
||||
if (argc < 2 || ! exists(argv[1])) {
|
||||
@ -1071,11 +1096,10 @@ int runscript (int argc, char **argv)
|
||||
if (*argv[1] == '/')
|
||||
service = xstrdup(argv[1]);
|
||||
else {
|
||||
char d[PATH_MAX];
|
||||
getcwd (d, sizeof (d));
|
||||
i = strlen (d) + strlen (argv[1]) + 2;
|
||||
service = xmalloc (sizeof (char) * i);
|
||||
snprintf (service, i, "%s/%s", d, argv[1]);
|
||||
getcwd(dir, sizeof(dir));
|
||||
l = strlen(dir) + strlen(argv[1]) + 2;
|
||||
service = xmalloc(sizeof (char) * l);
|
||||
snprintf(service, l, "%s/%s", dir, argv[1]);
|
||||
}
|
||||
|
||||
atexit(cleanup);
|
||||
@ -1090,50 +1114,16 @@ int runscript (int argc, char **argv)
|
||||
eerror("%s: cannot run until sysvinit completes", applet);
|
||||
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
|
||||
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
|
||||
tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
|
||||
symlink (service, tmp);
|
||||
prefix = rc_strcatpaths("/dev/.rcboot", applet, (char *) NULL);
|
||||
symlink(service, prefix);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((softlevel = xstrdup (getenv ("RC_SOFTLEVEL"))) == NULL) {
|
||||
/* Ensure our environment is pure
|
||||
Also, add our configuration to it */
|
||||
char *p;
|
||||
env = env_filter ();
|
||||
|
||||
if (env) {
|
||||
|
||||
#ifdef __linux__
|
||||
/* clearenv isn't portable, but there's no harm in using it
|
||||
if we have it */
|
||||
clearenv ();
|
||||
#else
|
||||
char *var;
|
||||
/* No clearenv present here then.
|
||||
We could manipulate environ directly ourselves, but it seems that
|
||||
some kernels bitch about this according to the environ man pages
|
||||
so we walk though environ and call unsetenv for each value. */
|
||||
while (environ[0]) {
|
||||
tmp = xstrdup (environ[0]);
|
||||
p = tmp;
|
||||
var = strsep (&p, "=");
|
||||
unsetenv (var);
|
||||
free (tmp);
|
||||
}
|
||||
tmp = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
tmplist = env_config ();
|
||||
rc_strlist_join (&env, tmplist);
|
||||
rc_strlist_free (tmplist);
|
||||
tmplist = NULL;
|
||||
STRLIST_FOREACH (env, p, i)
|
||||
putenv (p);
|
||||
/* We don't free our list as that would be null in environ */
|
||||
|
||||
softlevel = rc_runlevel_get ();
|
||||
if ((runlevel = xstrdup (getenv ("RC_RUNLEVEL"))) == NULL) {
|
||||
env_filter();
|
||||
env_config();
|
||||
runlevel = rc_runlevel_get();
|
||||
}
|
||||
|
||||
setenv("EINFO_LOG", service, 1);
|
||||
@ -1147,13 +1137,10 @@ int runscript (int argc, char **argv)
|
||||
|
||||
/* eprefix is kinda klunky, but it works for our purposes */
|
||||
if (rc_conf_yesno("rc_parallel")) {
|
||||
size_t l = 0;
|
||||
size_t ll;
|
||||
|
||||
/* Get the longest service name */
|
||||
services = rc_services_in_runlevel(NULL);
|
||||
STRLIST_FOREACH (services, svc, i) {
|
||||
ll = strlen (svc);
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
ll = strlen(svc->value);
|
||||
if (ll > l)
|
||||
l = ll;
|
||||
}
|
||||
@ -1177,8 +1164,7 @@ int runscript (int argc, char **argv)
|
||||
argv++;
|
||||
|
||||
/* Right then, parse any options there may be */
|
||||
while ((opt = getopt_long (argc, argv, getoptstring,
|
||||
longopts, (int *) 0)) != -1)
|
||||
while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1)
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
setenv("RC_DEBUG", "yes", 1);
|
||||
@ -1216,6 +1202,9 @@ int runscript (int argc, char **argv)
|
||||
/* Load our plugins */
|
||||
rc_plugin_load();
|
||||
|
||||
applet_list = rc_stringlist_new();
|
||||
rc_stringlist_add(applet_list, applet);
|
||||
|
||||
/* Now run each option */
|
||||
retval = EXIT_SUCCESS;
|
||||
while (optind < argc) {
|
||||
@ -1233,13 +1222,11 @@ int runscript (int argc, char **argv)
|
||||
setenv("RC_CMD", optarg, 1);
|
||||
|
||||
doneone = true;
|
||||
rc_strlist_add (&applet_list, applet);
|
||||
|
||||
if (strcmp (optarg, "describe") == 0 ||
|
||||
strcmp (optarg, "help") == 0)
|
||||
{
|
||||
char *save = prefix;
|
||||
|
||||
save = prefix;
|
||||
eprefix(NULL);
|
||||
prefix = NULL;
|
||||
svc_exec(optarg, NULL);
|
||||
@ -1252,27 +1239,26 @@ int runscript (int argc, char **argv)
|
||||
strcmp(optarg, "ibefore") == 0 ||
|
||||
strcmp(optarg, "iprovide") == 0)
|
||||
{
|
||||
int depoptions = RC_DEP_TRACE;
|
||||
|
||||
if (rc_conf_yesno("rc_depend_strict"))
|
||||
depoptions |= RC_DEP_STRICT;
|
||||
|
||||
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
|
||||
eerrorx("failed to load deptree");
|
||||
|
||||
rc_strlist_free (services);
|
||||
rc_strlist_free (tmplist);
|
||||
rc_strlist_add (&tmplist, optarg);
|
||||
services = rc_deptree_depends (deptree,
|
||||
(const char * const *) tmplist,
|
||||
(const char * const *) applet_list,
|
||||
softlevel, depoptions);
|
||||
STRLIST_FOREACH (services, svc, i)
|
||||
printf ("%s%s", i == 1 ? "" : " ", svc);
|
||||
if (services)
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, optarg);
|
||||
services = rc_deptree_depends(deptree, tmplist, applet_list,
|
||||
runlevel, depoptions);
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
TAILQ_FOREACH(svc, services, entries)
|
||||
printf("%s ", svc->value);
|
||||
if (TAILQ_FIRST(services))
|
||||
printf ("\n");
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
} else if (strcmp (optarg, "status") == 0) {
|
||||
rc_service_state_t r = svc_status (service);
|
||||
RC_SERVICE r = svc_status();
|
||||
retval = (int) r;
|
||||
if (retval & RC_SERVICE_STARTED)
|
||||
retval = 0;
|
||||
@ -1301,10 +1287,9 @@ int runscript (int argc, char **argv)
|
||||
if (in_background &&
|
||||
rc_service_state(service) & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
int j;
|
||||
STRLIST_FOREACH (restart_services, svc, j)
|
||||
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
|
||||
rc_service_schedule_start (service, svc);
|
||||
TAILQ_FOREACH(svc, restart_services, entries)
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
rc_service_schedule_start(service, svc->value);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(optarg, "zap") == 0) {
|
||||
@ -1315,7 +1300,7 @@ int runscript (int argc, char **argv)
|
||||
svc_exec(optarg, NULL);
|
||||
|
||||
/* We should ensure this list is empty after an action is done */
|
||||
rc_strlist_free (restart_services);
|
||||
rc_stringlist_free(restart_services);
|
||||
restart_services = NULL;
|
||||
}
|
||||
|
||||
@ -1323,5 +1308,5 @@ int runscript (int argc, char **argv)
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sys/termios.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -71,40 +72,38 @@ static struct pam_conv conv = { NULL, NULL};
|
||||
#include "einfo.h"
|
||||
#include "rc.h"
|
||||
#include "rc-misc.h"
|
||||
#include "strlist.h"
|
||||
|
||||
typedef struct schedulelist
|
||||
typedef struct scheduleitem
|
||||
{
|
||||
enum
|
||||
{
|
||||
schedule_timeout,
|
||||
schedule_signal,
|
||||
schedule_goto,
|
||||
schedule_forever
|
||||
SC_TIMEOUT,
|
||||
SC_SIGNAL,
|
||||
SC_GOTO,
|
||||
SC_FOREVER
|
||||
} type;
|
||||
int value;
|
||||
struct schedulelist *gotolist;
|
||||
struct schedulelist *next;
|
||||
} schedulelist_t;
|
||||
static schedulelist_t *schedule;
|
||||
struct scheduleitem *gotoitem;
|
||||
STAILQ_ENTRY(scheduleitem) entries;
|
||||
} SCHEDULEITEM;
|
||||
STAILQ_HEAD(, scheduleitem) schedule;
|
||||
|
||||
extern const char *applet;
|
||||
static char *changeuser;
|
||||
static char **newenv;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static void free_schedulelist (schedulelist_t **list)
|
||||
static void free_schedulelist(void)
|
||||
{
|
||||
schedulelist_t *here;
|
||||
schedulelist_t *next;
|
||||
SCHEDULEITEM *s1 = STAILQ_FIRST(&schedule);
|
||||
SCHEDULEITEM *s2;
|
||||
|
||||
for (here = *list; here; here = next) {
|
||||
next = here->next;
|
||||
free (here);
|
||||
while (s1) {
|
||||
s2 = STAILQ_NEXT(s1, entries);
|
||||
free(s1);
|
||||
s1 = s2;
|
||||
}
|
||||
|
||||
*list = NULL;
|
||||
STAILQ_INIT(&schedule);
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
@ -112,11 +111,7 @@ static void cleanup (void)
|
||||
if (changeuser)
|
||||
free(changeuser);
|
||||
|
||||
if (schedule)
|
||||
free_schedulelist (&schedule);
|
||||
|
||||
if (newenv)
|
||||
rc_strlist_free (newenv);
|
||||
free_schedulelist();
|
||||
}
|
||||
|
||||
static int parse_signal(const char *sig)
|
||||
@ -125,9 +120,9 @@ static int parse_signal (const char *sig)
|
||||
{
|
||||
const char *name;
|
||||
int signal;
|
||||
} signalpair_t;
|
||||
} SIGNALPAIR;
|
||||
|
||||
static const signalpair_t signallist[] = {
|
||||
static const SIGNALPAIR signallist[] = {
|
||||
{ "ABRT", SIGABRT },
|
||||
{ "ALRM", SIGALRM },
|
||||
{ "FPE", SIGFPE },
|
||||
@ -153,11 +148,11 @@ static int parse_signal (const char *sig)
|
||||
const char *s;
|
||||
|
||||
if (! sig || *sig == '\0')
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if (sscanf(sig, "%u", &i) == 1) {
|
||||
if (i > 0 && i < sizeof(signallist) / sizeof(signallist[0]))
|
||||
return (i);
|
||||
return i;
|
||||
eerrorx("%s: `%s' is not a valid signal", applet, sig);
|
||||
}
|
||||
|
||||
@ -169,21 +164,24 @@ static int parse_signal (const char *sig)
|
||||
for (i = 0; i < sizeof(signallist) / sizeof(signallist[0]); i++)
|
||||
if (strcmp(sig, signallist[i].name) == 0 ||
|
||||
(s && strcmp(s, signallist[i].name) == 0))
|
||||
return (signallist[i].signal);
|
||||
return signallist[i].signal;
|
||||
|
||||
eerrorx("%s: `%s' is not a valid signal", applet, sig);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void parse_schedule_item (schedulelist_t *item, const char *string)
|
||||
static SCHEDULEITEM *parse_schedule_item(const char *string)
|
||||
{
|
||||
const char *after_hyph;
|
||||
int sig;
|
||||
SCHEDULEITEM *item = xmalloc(sizeof(*item));
|
||||
|
||||
item->value = 0;
|
||||
item->gotoitem = NULL;
|
||||
if (strcmp(string,"forever") == 0)
|
||||
item->type = schedule_forever;
|
||||
item->type = SC_FOREVER;
|
||||
else if (isdigit((int) string[0])) {
|
||||
item->type = schedule_timeout;
|
||||
item->type = SC_TIMEOUT;
|
||||
errno = 0;
|
||||
if (sscanf(string, "%d", &item->value) != 1)
|
||||
eerrorx("%s: invalid timeout value in schedule `%s'", applet,
|
||||
@ -191,52 +189,51 @@ static void parse_schedule_item (schedulelist_t *item, const char *string)
|
||||
} else if ((after_hyph = string + (string[0] == '-')) &&
|
||||
((sig = parse_signal(after_hyph)) != -1))
|
||||
{
|
||||
item->type = schedule_signal;
|
||||
item->type = SC_SIGNAL;
|
||||
item->value = (int)sig;
|
||||
}
|
||||
else
|
||||
eerrorx("%s: invalid schedule item `%s'", applet, string);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void parse_schedule (const char *string, int default_signal)
|
||||
static void parse_schedule(const char *string, int timeout)
|
||||
{
|
||||
char buffer[20];
|
||||
const char *slash;
|
||||
int count = 0;
|
||||
schedulelist_t *repeatat = NULL;
|
||||
SCHEDULEITEM *repeatat = NULL;
|
||||
size_t len;
|
||||
schedulelist_t *next;
|
||||
SCHEDULEITEM *item;
|
||||
|
||||
if (string)
|
||||
for (slash = string; *slash; slash++)
|
||||
if (*slash == '/')
|
||||
count++;
|
||||
|
||||
if (schedule)
|
||||
free_schedulelist (&schedule);
|
||||
|
||||
schedule = xmalloc (sizeof (*schedule));
|
||||
schedule->gotolist = NULL;
|
||||
free_schedulelist();
|
||||
|
||||
if (count == 0) {
|
||||
schedule->type = schedule_signal;
|
||||
schedule->value = default_signal;
|
||||
schedule->next = xmalloc (sizeof (*schedule->next));
|
||||
next = schedule->next;
|
||||
next->type = schedule_timeout;
|
||||
next->gotolist = NULL;
|
||||
item = xmalloc(sizeof(*item));
|
||||
item->type = SC_SIGNAL;
|
||||
item->value = timeout;
|
||||
item->gotoitem = NULL;
|
||||
STAILQ_INSERT_TAIL(&schedule, item, entries);
|
||||
|
||||
item = xmalloc(sizeof(*item));
|
||||
item->type = SC_TIMEOUT;
|
||||
item->gotoitem = NULL;
|
||||
STAILQ_INSERT_TAIL(&schedule, item, entries);
|
||||
if (string) {
|
||||
if (sscanf (string, "%d", &next->value) != 1)
|
||||
if (sscanf(string, "%d", &item->value) != 1)
|
||||
eerrorx("%s: invalid timeout value in schedule", applet);
|
||||
}
|
||||
else
|
||||
next->value = 5;
|
||||
next->next = NULL;
|
||||
} else
|
||||
item->value = 5;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
next = schedule;
|
||||
while (string != NULL) {
|
||||
if ((slash = strchr(string, '/')))
|
||||
len = slash - string;
|
||||
@ -250,32 +247,26 @@ static void parse_schedule (const char *string, int default_signal)
|
||||
buffer[len] = 0;
|
||||
string = slash ? slash + 1 : NULL;
|
||||
|
||||
parse_schedule_item (next, buffer);
|
||||
if (next->type == schedule_forever) {
|
||||
item = parse_schedule_item(buffer);
|
||||
STAILQ_INSERT_TAIL(&schedule, item, entries);
|
||||
if (item->type == SC_FOREVER) {
|
||||
if (repeatat)
|
||||
eerrorx ("%s: invalid schedule, `forever' appears more than once",
|
||||
applet);
|
||||
eerrorx("%s: invalid schedule, `forever' "
|
||||
"appears more than once", applet);
|
||||
|
||||
repeatat = next;
|
||||
repeatat = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string) {
|
||||
next->next = xmalloc (sizeof (*next->next));
|
||||
next = next->next;
|
||||
next->gotolist = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (repeatat) {
|
||||
next->next = xmalloc (sizeof (*next->next));
|
||||
next = next->next;
|
||||
next->type = schedule_goto;
|
||||
next->value = 0;
|
||||
next->gotolist = repeatat;
|
||||
item = xmalloc(sizeof(*item));
|
||||
item->type = SC_GOTO;
|
||||
item->value = 0;
|
||||
item->gotoitem = repeatat;
|
||||
STAILQ_INSERT_TAIL(&schedule, item, entries);
|
||||
}
|
||||
|
||||
next->next = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -285,23 +276,24 @@ static pid_t get_pid (const char *pidfile, bool quiet)
|
||||
pid_t pid;
|
||||
|
||||
if (! pidfile)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if ((fp = fopen(pidfile, "r")) == NULL) {
|
||||
if (! quiet)
|
||||
eerror("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fscanf(fp, "%d", &pid) != 1) {
|
||||
if (! quiet)
|
||||
eerror("%s: no pid found in `%s'", applet, pidfile);
|
||||
fclose(fp);
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return (pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* return number of processed killed, -1 on error */
|
||||
@ -317,13 +309,13 @@ static int do_stop (const char *const *argv, const char *cmd,
|
||||
|
||||
if (pidfile) {
|
||||
if ((pid = get_pid(pidfile, quiet)) == -1)
|
||||
return (quiet ? 0 : -1);
|
||||
return quiet ? 0 : -1;
|
||||
pids = rc_find_pids(NULL, NULL, 0, pid);
|
||||
} else
|
||||
pids = rc_find_pids(argv, cmd, uid, pid);
|
||||
|
||||
if (! pids)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
for (i = 0; pids[i]; i++) {
|
||||
if (test) {
|
||||
@ -349,14 +341,14 @@ static int do_stop (const char *const *argv, const char *cmd,
|
||||
}
|
||||
|
||||
free(pids);
|
||||
return (nkilled);
|
||||
return nkilled;
|
||||
}
|
||||
|
||||
static int run_stop_schedule(const char *const *argv, const char *cmd,
|
||||
const char *pidfile, uid_t uid,
|
||||
bool quiet, bool verbose, bool test)
|
||||
{
|
||||
schedulelist_t *item = schedule;
|
||||
SCHEDULEITEM *item = STAILQ_FIRST(&schedule);
|
||||
int nkilled = 0;
|
||||
int tkilled = 0;
|
||||
int nrunning = 0;
|
||||
@ -376,27 +368,28 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
|
||||
|
||||
while (item) {
|
||||
switch (item->type) {
|
||||
case schedule_goto:
|
||||
item = item->gotolist;
|
||||
case SC_GOTO:
|
||||
item = item->gotoitem;
|
||||
continue;
|
||||
|
||||
case schedule_signal:
|
||||
case SC_SIGNAL:
|
||||
nrunning = 0;
|
||||
nkilled = do_stop(argv, cmd, pidfile, uid, item->value,
|
||||
quiet, verbose, test);
|
||||
if (nkilled == 0) {
|
||||
if (tkilled == 0) {
|
||||
if (! quiet)
|
||||
eerror ("%s: no matching processes found", applet);
|
||||
eerror("%s: no matching "
|
||||
"processes found", applet);
|
||||
}
|
||||
return (tkilled);
|
||||
return tkilled;
|
||||
}
|
||||
else if (nkilled == -1)
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
tkilled += nkilled;
|
||||
break;
|
||||
case schedule_timeout:
|
||||
case SC_TIMEOUT:
|
||||
if (item->value < 1) {
|
||||
item = NULL;
|
||||
break;
|
||||
@ -409,14 +402,15 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
|
||||
while (nloops) {
|
||||
if ((nrunning = do_stop(argv, cmd, pidfile,
|
||||
uid, 0, true, false, true)) == 0)
|
||||
return (true);
|
||||
return true;
|
||||
|
||||
if (nanosleep(&ts, NULL) == -1) {
|
||||
if (errno == EINTR)
|
||||
eerror("%s: caught an interrupt", applet);
|
||||
else {
|
||||
eerror ("%s: nanosleep: %s", applet, strerror (errno));
|
||||
return (0);
|
||||
eerror("%s: nanosleep: %s",
|
||||
applet, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nloops --;
|
||||
@ -425,15 +419,15 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
|
||||
|
||||
default:
|
||||
eerror("%s: invalid schedule item `%d'", applet, item->type);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (item)
|
||||
item = item->next;
|
||||
item = STAILQ_NEXT(item, entries);
|
||||
}
|
||||
|
||||
if (test || (tkilled > 0 && nrunning == 0))
|
||||
return (nkilled);
|
||||
return nkilled;
|
||||
|
||||
if (! quiet) {
|
||||
if (nrunning == 1)
|
||||
@ -442,7 +436,7 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
|
||||
eerror("%s: %d process(es) refused to stop", applet, nrunning);
|
||||
}
|
||||
|
||||
return (-nrunning);
|
||||
return -nrunning;
|
||||
}
|
||||
|
||||
static void handle_signal(int sig)
|
||||
@ -575,19 +569,30 @@ int start_stop_daemon (int argc, char **argv)
|
||||
pid_t pid;
|
||||
int i;
|
||||
char *svcname = getenv("SVCNAME");
|
||||
char *env;
|
||||
RC_STRINGLIST *env_list;
|
||||
RC_STRING *env;
|
||||
char *path;
|
||||
bool sethome = false;
|
||||
bool setuser = false;
|
||||
char *p;
|
||||
char *tmp;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
char line[130];
|
||||
FILE *fp;
|
||||
size_t len;
|
||||
|
||||
STAILQ_INIT(&schedule);
|
||||
atexit(cleanup);
|
||||
|
||||
signal_setup(SIGINT, handle_signal);
|
||||
signal_setup(SIGQUIT, handle_signal);
|
||||
signal_setup(SIGTERM, handle_signal);
|
||||
|
||||
if ((env = getenv ("SSD_NICELEVEL")))
|
||||
if (sscanf (env, "%d", &nicelevel) != 1)
|
||||
eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env);
|
||||
if ((path = getenv("SSD_NICELEVEL")))
|
||||
if (sscanf(path, "%d", &nicelevel) != 1)
|
||||
eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
|
||||
applet, path);
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "e:" getoptstring, longopts,
|
||||
(int *) 0)) != -1)
|
||||
@ -616,33 +621,30 @@ int start_stop_daemon (int argc, char **argv)
|
||||
case 'u': /* --user <username>|<uid> */
|
||||
case 'c': /* --chuid <username>|<uid> */
|
||||
{
|
||||
char *p = optarg;
|
||||
char *cu = strsep (&p, ":");
|
||||
struct passwd *pw = NULL;
|
||||
|
||||
changeuser = xstrdup (cu);
|
||||
if (sscanf (cu, "%d", &tid) != 1)
|
||||
pw = getpwnam (cu);
|
||||
p = optarg;
|
||||
tmp = strsep(&p, ":");
|
||||
changeuser = xstrdup(tmp);
|
||||
if (sscanf(tmp, "%d", &tid) != 1)
|
||||
pw = getpwnam(tmp);
|
||||
else
|
||||
pw = getpwuid((uid_t) tid);
|
||||
|
||||
if (! pw)
|
||||
eerrorx ("%s: user `%s' not found", applet, cu);
|
||||
eerrorx("%s: user `%s' not found", applet, tmp);
|
||||
uid = pw->pw_uid;
|
||||
if (! gid)
|
||||
gid = pw->pw_gid;
|
||||
|
||||
if (p) {
|
||||
struct group *gr = NULL;
|
||||
char *cg = strsep (&p, ":");
|
||||
|
||||
if (sscanf (cg, "%d", &tid) != 1)
|
||||
gr = getgrnam (cg);
|
||||
tmp = strsep (&p, ":");
|
||||
if (sscanf(tmp, "%d", &tid) != 1)
|
||||
gr = getgrnam(tmp);
|
||||
else
|
||||
gr = getgrgid((gid_t) tid);
|
||||
|
||||
if (! gr)
|
||||
eerrorx ("%s: group `%s' not found", applet, cg);
|
||||
eerrorx("%s: group `%s' not found",
|
||||
applet, tmp);
|
||||
gid = gr->gr_gid;
|
||||
}
|
||||
}
|
||||
@ -663,8 +665,6 @@ int start_stop_daemon (int argc, char **argv)
|
||||
|
||||
case 'g': /* --group <group>|<gid> */
|
||||
{
|
||||
struct group *gr = getgrnam (optarg);
|
||||
|
||||
if (sscanf(optarg, "%d", &tid) != 1)
|
||||
gr = getgrnam(optarg);
|
||||
else
|
||||
@ -759,7 +759,6 @@ int start_stop_daemon (int argc, char **argv)
|
||||
|
||||
/* Validate that the binary exists if we are starting */
|
||||
if (exec) {
|
||||
char *tmp;
|
||||
if (ch_root)
|
||||
tmp = rc_strcatpaths(ch_root, exec, (char *) NULL);
|
||||
else
|
||||
@ -774,15 +773,13 @@ int start_stop_daemon (int argc, char **argv)
|
||||
/* If we don't have a pidfile or name, check it's not
|
||||
* interpreted, otherwise we should fail */
|
||||
if (! pidfile && ! cmd) {
|
||||
char line[130];
|
||||
FILE *fp = fopen (tmp, "r");
|
||||
|
||||
fp = fopen (tmp, "r");
|
||||
if (fp) {
|
||||
fgets(line, sizeof(line), fp);
|
||||
fclose(fp);
|
||||
|
||||
if (line[0] == '#' && line[1] == '!') {
|
||||
size_t len = strlen (line) - 1;
|
||||
len = strlen (line) - 1;
|
||||
|
||||
/* Remove the trailing newline */
|
||||
if (line[len] == '\n')
|
||||
@ -790,12 +787,12 @@ int start_stop_daemon (int argc, char **argv)
|
||||
|
||||
eerror("%s: %s is a script",
|
||||
applet, exec);
|
||||
eerror ("%s: and should be started, stopped or signalled with ",
|
||||
applet);
|
||||
eerror("%s: and should be started, stopped"
|
||||
" or signalled with ", applet);
|
||||
eerror("%s: --exec %s %s",
|
||||
applet, line + 2, exec);
|
||||
eerror ("%s: or you should specify a pidfile or process name",
|
||||
applet);
|
||||
eerror("%s: or you should specify a pidfile"
|
||||
" or process name", applet);
|
||||
if (ch_root)
|
||||
free(tmp);
|
||||
exit(EXIT_FAILURE);
|
||||
@ -813,7 +810,7 @@ int start_stop_daemon (int argc, char **argv)
|
||||
if (stop) {
|
||||
int result;
|
||||
|
||||
if (! schedule) {
|
||||
if (! STAILQ_FIRST(&schedule)) {
|
||||
if (test || oknodo)
|
||||
parse_schedule("0", sig);
|
||||
else
|
||||
@ -828,7 +825,7 @@ int start_stop_daemon (int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (test || oknodo)
|
||||
return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return result > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
||||
/* Even if we have not actually killed anything, we should
|
||||
* remove information about it as it may have unexpectedly
|
||||
@ -872,10 +869,6 @@ int start_stop_daemon (int argc, char **argv)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Ensure this is unset, so if the daemon does /etc/init.d/foo
|
||||
Then we filter the environment accordingly */
|
||||
unsetenv ("RC_SOFTLEVEL");
|
||||
|
||||
if (verbose) {
|
||||
ebegin("Detaching to start `%s'", exec);
|
||||
eindent();
|
||||
@ -910,10 +903,10 @@ int start_stop_daemon (int argc, char **argv)
|
||||
eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));
|
||||
|
||||
if (makepidfile && pidfile) {
|
||||
FILE *fp = fopen (pidfile, "w");
|
||||
fp = fopen(pidfile, "w");
|
||||
if (! fp)
|
||||
eerrorx ("%s: fopen `%s': %s", applet, pidfile, strerror
|
||||
(errno));
|
||||
eerrorx("%s: fopen `%s': %s", applet, pidfile,
|
||||
strerror(errno));
|
||||
fprintf(fp, "%d\n", mypid);
|
||||
fclose(fp);
|
||||
}
|
||||
@ -941,17 +934,17 @@ int start_stop_daemon (int argc, char **argv)
|
||||
if (uid && setuid(uid))
|
||||
eerrorx ("%s: unable to set userid to %d", applet, uid);
|
||||
else {
|
||||
struct passwd *passwd = getpwuid (uid);
|
||||
if (passwd) {
|
||||
pw = getpwuid(uid);
|
||||
if (pw) {
|
||||
if (! sethome) {
|
||||
unsetenv("HOME");
|
||||
if (passwd->pw_dir)
|
||||
setenv ("HOME", passwd->pw_dir, 1);
|
||||
if (pw->pw_dir)
|
||||
setenv("HOME", pw->pw_dir, 1);
|
||||
}
|
||||
if (! setuser) {
|
||||
unsetenv("USER");
|
||||
if (passwd->pw_name)
|
||||
setenv ("USER", passwd->pw_name, 1);
|
||||
if (pw->pw_name)
|
||||
setenv("USER", pw->pw_name, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -965,48 +958,46 @@ int start_stop_daemon (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
/* Clean the environment of any RC_ variables */
|
||||
STRLIST_FOREACH (environ, env, i) {
|
||||
if ((strncmp (env, "RC_", 3) == 0 &&
|
||||
strncmp (env, "RC_SERVICE=", strlen ("RC_SERVICE=")) != 0) ||
|
||||
strncmp (env, "SSD_NICELEVEL=", strlen ("SSD_NICELEVEL=")) == 0)
|
||||
env_list = rc_stringlist_new();
|
||||
i = 0;
|
||||
while(environ[i])
|
||||
rc_stringlist_add(env_list, environ[i++]);
|
||||
TAILQ_FOREACH(env, env_list, entries) {
|
||||
if ((strncmp(env->value, "RC_", 3) == 0 &&
|
||||
strncmp(env->value, "RC_SERVICE=", strlen("RC_SERVICE=")) != 0) ||
|
||||
strncmp(env->value, "SSD_NICELEVEL=", strlen("SSD_NICELEVEL=")) == 0)
|
||||
{
|
||||
p = strchr(env->value, '=');
|
||||
*p = '\0';
|
||||
unsetenv(env->value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
rc_stringlist_free(env_list);
|
||||
|
||||
/* For the path, remove the rcscript bin dir from it */
|
||||
if (strncmp (env, "PATH=", 5) == 0) {
|
||||
char *path = xstrdup (env);
|
||||
char *newpath = NULL;
|
||||
char *p = path;
|
||||
if ((path = getenv("PATH"))) {
|
||||
size_t mx = strlen(path);
|
||||
char *newpath = xmalloc(mx);
|
||||
char *token;
|
||||
char *np;
|
||||
char *np = newpath;
|
||||
size_t l;
|
||||
int t;
|
||||
|
||||
p += 5;
|
||||
p = path;
|
||||
while ((token = strsep (&p, ":"))) {
|
||||
if (strcmp (token, RC_LIBDIR "/bin") == 0 ||
|
||||
strcmp (token, RC_LIBDIR "/sbin") == 0)
|
||||
continue;
|
||||
|
||||
t = strlen (token);
|
||||
if (newpath) {
|
||||
l = strlen (newpath);
|
||||
newpath = xrealloc (newpath, sizeof (char) * (l + t + 2));
|
||||
np = newpath + l;
|
||||
l = strlen (token);
|
||||
if (np != newpath)
|
||||
*np++ = ':';
|
||||
memcpy (np, token, sizeof (char) * strlen (token));
|
||||
np += t;
|
||||
memcpy (np, token, l);
|
||||
np += l;
|
||||
*np = '\0';
|
||||
} else {
|
||||
l = strlen ("PATH=") + t + 1;
|
||||
newpath = xmalloc (sizeof (char) * l);
|
||||
snprintf (newpath, l, "PATH=%s", token);
|
||||
}
|
||||
}
|
||||
rc_strlist_add (&newenv, newpath);
|
||||
free (path);
|
||||
free (newpath);
|
||||
} else
|
||||
rc_strlist_add (&newenv, env);
|
||||
unsetenv("PATH");
|
||||
setenv("PATH", newpath, 1);
|
||||
}
|
||||
|
||||
umask(022);
|
||||
@ -1036,8 +1027,7 @@ int start_stop_daemon (int argc, char **argv)
|
||||
close(i);
|
||||
|
||||
setsid();
|
||||
|
||||
execve (exec, argv, newenv);
|
||||
execv(exec, argv);
|
||||
#ifdef HAVE_PAM
|
||||
if (pamr == PAM_SUCCESS)
|
||||
pam_close_session(pamh, PAM_SILENT);
|
||||
@ -1056,7 +1046,7 @@ int start_stop_daemon (int argc, char **argv)
|
||||
pid = waitpid(savepid, &status, 0);
|
||||
if (pid < 1) {
|
||||
eerror("waitpid %d: %s", savepid, strerror(errno));
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
} while (! WIFEXITED(status) && ! WIFSIGNALED(status));
|
||||
|
||||
@ -1086,7 +1076,7 @@ int start_stop_daemon (int argc, char **argv)
|
||||
eerror("%s: caught an interrupt", applet);
|
||||
else {
|
||||
eerror("%s: nanosleep: %s", applet, strerror(errno));
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1130,7 +1120,8 @@ int start_stop_daemon (int argc, char **argv)
|
||||
}
|
||||
|
||||
if (svcname)
|
||||
rc_service_daemon_set (svcname, (const char *const *)argv, cmd, pidfile, true);
|
||||
rc_service_daemon_set(svcname, (const char *const *)argv,
|
||||
cmd, pidfile, true);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
/* NOTREACHED */
|
||||
|
Reference in New Issue
Block a user