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

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

View File

@ -1,6 +1,6 @@
MAN3= einfo.3 \
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -56,7 +56,7 @@
#define RC_LIBDIR RC_PREFIX "/" LIB "/rc"
#define RC_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,9 +98,46 @@
# 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);
void *value = malloc(size);
if (value)
return (value);
@ -109,9 +146,9 @@ _unused static void *xmalloc (size_t size)
/* NOTREACHED */
}
_unused static void *xrealloc (void *ptr, size_t size)
_unused static void *xrealloc(void *ptr, size_t size)
{
void *value = realloc (ptr, size);
void *value = realloc(ptr, size);
if (value)
return (value);
@ -120,14 +157,14 @@ _unused static void *xrealloc (void *ptr, size_t size)
/* NOTREACHED */
}
_unused static char *xstrdup (const char *str)
_unused static char *xstrdup(const char *str)
{
char *value;
if (! str)
return (NULL);
value = strdup (str);
value = strdup(str);
if (value)
return (value);
@ -138,32 +175,32 @@ _unused static char *xstrdup (const char *str)
#undef ERRX
_unused static bool exists (const char *pathname)
_unused static bool exists(const char *pathname)
{
struct stat buf;
return (stat (pathname, &buf) == 0);
return (stat(pathname, &buf) == 0);
}
_unused static bool existss (const char *pathname)
_unused static bool existss(const char *pathname)
{
struct stat buf;
return (stat (pathname, &buf) == 0 && buf.st_size != 0);
return (stat(pathname, &buf) == 0 && buf.st_size != 0);
}
char *rc_conf_value (const char *var);
bool rc_conf_yesno (const char *var);
char **env_filter (void);
char **env_config (void);
bool service_plugable (const char *service);
int signal_setup (int sig, void (*handler)(int));
char *rc_conf_value(const char *var);
bool rc_conf_yesno(const char *var);
void env_filter(void);
void env_config(void);
bool service_plugable(const char *service);
int signal_setup(int sig, void (*handler)(int));
/* basename_c never modifies the argument. As such, if there is a trailing
* slash then an empty string is returned. */
_unused static const char *basename_c (const char *path)
_unused static const char *basename_c(const char *path)
{
const char *slash = strrchr (path, '/');
const char *slash = strrchr(path, '/');
if (slash)
return (++slash);

View File

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

View File

@ -54,19 +54,19 @@
/*! @brief Color types to use */
typedef enum
{
ECOLOR_NORMAL = 1,
ECOLOR_GOOD = 2,
ECOLOR_WARN = 3,
ECOLOR_BAD = 4,
ECOLOR_HILITE = 5,
ECOLOR_BRACKET = 6
} einfo_color_t;
ECOLOR_NORMAL = 1,
ECOLOR_GOOD = 2,
ECOLOR_WARN = 3,
ECOLOR_BAD = 4,
ECOLOR_HILITE = 5,
ECOLOR_BRACKET = 6
} 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
@ -133,12 +133,12 @@ int ewendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINT
*
* For each indent you should outdent when done */
/*@{*/
void eindent (void);
void eoutdent (void);
void eindentv (void);
void eoutdentv (void);
void eindent(void);
void eoutdent(void);
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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -64,10 +64,8 @@
#include <kvm.h>
#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

View File

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

View File

@ -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
View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@ -48,84 +49,84 @@
extern const char *applet;
static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, int file)
{
struct stat st;
int fd;
memset (&st, 0, sizeof (st));
if (stat (path, &st)) {
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);
einfo("%s: creating file", path);
if ((fd = open(path, O_CREAT)) == -1) {
eerror("%s: open: %s", applet, strerror(errno));
return -1;
}
close (fd);
} else {
einfo ("%s: creating directory", path);
einfo("%s: creating directory", path);
if (! mode)
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
if (mkdir (path, mode)) {
eerror ("%s: mkdir: %s", applet, strerror (errno));
return (-1);
if (mkdir(path, mode)) {
eerror("%s: mkdir: %s", applet, strerror (errno));
return -1;
}
mode = 0;
}
} else {
if ((file && S_ISDIR (st.st_mode)) ||
(! file && ! S_ISDIR (st.st_mode)))
if ((file && S_ISDIR(st.st_mode)) ||
(! file && ! S_ISDIR(st.st_mode)))
{
if (file)
eerror ("%s: is a directory", path);
eerror("%s: is a directory", path);
else
eerror ("%s: is a file", path);
return (-1);
eerror("%s: is a file", path);
return -1;
}
}
if (mode && (st.st_mode & 0777) != mode) {
einfo ("%s: correcting mode", applet);
if (chmod (path, mode)) {
eerror ("%s: chmod: %s", applet, strerror (errno));
return (-1);
einfo("%s: correcting mode", applet);
if (chmod(path, mode)) {
eerror("%s: chmod: %s", applet, strerror(errno));
return -1;
}
}
if (st.st_uid != uid || st.st_gid != gid) {
if (st.st_dev || st.st_ino)
einfo ("%s: correcting owner", path);
if (chown (path, uid, gid)) {
eerror ("%s: chown: %s", applet, strerror (errno));
return (-1);
einfo("%s: correcting owner", path);
if (chown(path, uid, gid)) {
eerror("%s: chown: %s", applet, strerror(errno));
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,
static int parse_owner(struct passwd **user, struct group **group,
const char *owner)
{
char *u = xstrdup (owner);
@ -137,25 +138,25 @@ static int parse_owner (struct passwd **user, struct group **group,
*g++ = '\0';
if (user && *u) {
if (sscanf (u, "%d", &id) == 1)
*user = getpwuid ((uid_t) id);
if (sscanf(u, "%d", &id) == 1)
*user = getpwuid((uid_t) id);
else
*user = getpwnam (u);
*user = getpwnam(u);
if (! *user)
retval = -1;
}
if (group && g && *g) {
if (sscanf (g, "%d", &id) == 1)
*group = getgrgid ((gid_t) id);
if (sscanf(g, "%d", &id) == 1)
*group = getgrgid((gid_t) id);
else
*group = getgrnam (g);
*group = getgrnam(g);
if (! *group)
retval = -1;
}
free (u);
return (retval);
free(u);
return retval;
}
#include "_usage.h"
@ -177,7 +178,7 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int checkpath (int argc, char **argv)
int checkpath(int argc, char **argv)
{
int opt;
uid_t uid = geteuid();
@ -188,33 +189,31 @@ int checkpath (int argc, char **argv)
bool file = 0;
int retval = EXIT_SUCCESS;
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':
file = 0;
break;
case 'f':
file = 1;
break;
case 'm':
if (parse_mode (&mode, optarg) != 0)
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);
break;
case 'd':
file = 0;
break;
case 'f':
file = 1;
break;
case 'm':
if (parse_mode(&mode, optarg) != 0)
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);
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
if (optind >= argc)
usage (EXIT_FAILURE);
usage(EXIT_FAILURE);
if (pw) {
uid = pw->pw_uid;
@ -224,11 +223,11 @@ int checkpath (int argc, char **argv)
gid = gr->gr_gid;
while (optind < argc) {
if (do_check (argv[optind], uid, gid, mode, file))
if (do_check(argv[optind], uid, gid, mode, file))
retval = EXIT_FAILURE;
optind++;
}
exit (retval);
exit(retval);
/* NOTREACHED */
}

View File

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

View File

@ -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,93 +79,93 @@ 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,
char *from, char *to, char *fstype, char *options,
int netdev)
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);
if (strcmp(fstype, "rootfs") == 0)
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);
regexec(args->node_regex, from, 0, NULL, 0) != 0)
return 1;
if (args->skip_node_regex &&
regexec (args->skip_node_regex, from, 0, NULL, 0) == 0)
return (1);
regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
return 1;
if (args->fstype_regex &&
regexec (args->fstype_regex, fstype, 0, NULL, 0) != 0)
return (-1);
regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
return -1;
if (args->skip_fstype_regex &&
regexec (args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return (-1);
regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return -1;
if (args->options_regex &&
regexec (args->options_regex, options, 0, NULL, 0) != 0)
return (-1);
regexec(args->options_regex, options, 0, NULL, 0) != 0)
return -1;
if (args->skip_options_regex &&
regexec (args->skip_options_regex, options, 0, NULL, 0) == 0)
return (-1);
regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
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) {
case mount_from:
p = from;
break;
case mount_to:
p = to;
break;
case mount_fstype:
p = fstype;
break;
case mount_options:
p = options;
break;
default:
p = NULL;
errno = EINVAL;
break;
case mount_from:
p = from;
break;
case mount_to:
p = to;
break;
case mount_fstype:
p = fstype;
break;
case mount_options:
p = options;
break;
default:
p = NULL;
errno = EINVAL;
break;
}
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,70 +211,73 @@ 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));
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) {
if (o->o_opt == MNT_LOCAL)
netdev = 1;
if (! options)
options = xstrdup (o->o_name);
options = xstrdup(o->o_name);
else {
char *tmp = NULL;
size_t l = strlen (options) + strlen (o->o_name) + 2;
tmp = xmalloc (sizeof (char) * l);
snprintf (tmp, l, "%s,%s", options, o->o_name);
free (options);
l = strlen(options) + strlen(o->o_name) + 2;
tmp = xmalloc(sizeof (char) * l);
snprintf(tmp, l, "%s,%s", options, o->o_name);
free(options);
options = tmp;
}
}
flags &= ~o->o_opt;
}
process_mount (&list, args,
mnts[i].f_mntfromname,
mnts[i].f_mntonname,
mnts[i].f_fstypename,
options,
netdev);
process_mount(list, args,
mnts[i].f_mntfromname,
mnts[i].f_mntonname,
mnts[i].f_fstypename,
options,
netdev);
free (options);
free(options);
options = NULL;
}
return (list);
return list;
}
#elif defined (__linux__)
static struct mntent *getmntfile (const char *file)
static struct mntent *getmntfile(const char *file)
{
struct mntent *ent = NULL;
FILE *fp;
fp = setmntent ("/etc/fstab", "r");
while ((ent = getmntent (fp)))
if (strcmp (file, ent->mnt_dir) == 0)
fp = setmntent("/etc/fstab", "r");
while ((ent = getmntent(fp)))
if (strcmp(file, ent->mnt_dir) == 0)
break;
endmntent (fp);
endmntent(fp);
return (ent);
return ent;
}
static char **find_mounts (struct args *args)
static RC_STRINGLIST *find_mounts(struct args *args)
{
FILE *fp;
char *buffer;
@ -284,52 +286,54 @@ 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));
if ((fp = fopen("/proc/mounts", "r")) == NULL)
eerrorx("getmntinfo: %s", strerror(errno));
buffer = xmalloc (sizeof (char) * PATH_MAX * 3);
while (fgets (buffer, PATH_MAX * 3, fp)) {
list = rc_stringlist_new();
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
while (fgets(buffer, PATH_MAX * 3, fp)) {
netdev = -1;
p = buffer;
from = strsep (&p, " ");
to = strsep (&p, " ");
fst = strsep (&p, " ");
opts = strsep (&p, " ");
from = strsep(&p, " ");
to = strsep(&p, " ");
fst = strsep(&p, " ");
opts = strsep(&p, " ");
if ((ent = getmntfile (to))) {
if (strstr (ent->mnt_opts, "_netdev"))
if ((ent = getmntfile(to))) {
if (strstr(ent->mnt_opts, "_netdev"))
netdev = 0;
}
process_mount (&list, args, from, to, fst, opts, netdev);
process_mount(list, args, from, to, fst, opts, netdev);
}
free (buffer);
fclose (fp);
free(buffer);
fclose(fp);
return (list);
return list;
}
#else
# error "Operating system not supported!"
#endif
static regex_t *get_regex (const char *string)
static regex_t *get_regex(const char *string)
{
regex_t *reg = xmalloc (sizeof (*reg));
regex_t *reg = xmalloc(sizeof (*reg));
int result;
char buffer[256];
if ((result = regcomp (reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
if ((result = regcomp(reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
{
regerror (result, reg, buffer, sizeof (buffer));
eerrorx ("%s: invalid regex `%s'", applet, buffer);
regerror(result, reg, buffer, sizeof(buffer));
eerrorx("%s: invalid regex `%s'", applet, buffer);
}
return (reg);
return reg;
}
#include "_usage.h"
@ -347,7 +351,7 @@ static const struct option longopts[] = {
{ "options", 0, NULL, 'i'},
{ "fstype", 0, NULL, 's'},
{ "node", 0, NULL, 't'},
{ "netdev", 0, NULL, 'e'},
{ "netdev", 0, NULL, 'e'},
{ "nonetdev", 0, NULL, 'E'},
longopts_COMMON
};
@ -369,112 +373,113 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int mountinfo (int argc, char **argv)
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;
/* Ensure that we are only quiet when explicitly told to be */
unsetenv ("EINFO_QUIET");
unsetenv("EINFO_QUIET");
#define DO_REG(_var) \
if (_var) free (_var); \
_var = get_regex (optarg);
if (_var) free(_var); \
_var = get_regex(optarg);
#define REG_FREE(_var) \
if (_var) { regfree (_var); free (_var); }
if (_var) { regfree(_var); free(_var); }
memset (&args, 0, sizeof (args));
memset (&args, 0, sizeof(args));
args.mount_type = mount_to;
args.netdev = net_ignore;
args.mounts = rc_stringlist_new();
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 'e':
args.netdev = net_yes;
break;
case 'E':
args.netdev = net_no;
break;
case 'f':
DO_REG (args.fstype_regex);
break;
case 'F':
DO_REG (args.skip_fstype_regex);
break;
case 'n':
DO_REG (args.node_regex);
break;
case 'N':
DO_REG (args.skip_node_regex);
break;
case 'o':
DO_REG (args.options_regex);
break;
case 'O':
DO_REG (args.skip_options_regex);
break;
case 'p':
DO_REG (point_regex);
break;
case 'P':
DO_REG (skip_point_regex);
break;
case 'i':
args.mount_type = mount_options;
break;
case 's':
args.mount_type = mount_fstype;
break;
case 't':
args.mount_type = mount_from;
break;
case 'e':
args.netdev = net_yes;
break;
case 'E':
args.netdev = net_no;
break;
case 'f':
DO_REG(args.fstype_regex);
break;
case 'F':
DO_REG(args.skip_fstype_regex);
break;
case 'n':
DO_REG(args.node_regex);
break;
case 'N':
DO_REG(args.skip_node_regex);
break;
case 'o':
DO_REG(args.options_regex);
break;
case 'O':
DO_REG(args.skip_options_regex);
break;
case 'p':
DO_REG(point_regex);
break;
case 'P':
DO_REG(skip_point_regex);
break;
case 'i':
args.mount_type = mount_options;
break;
case 's':
args.mount_type = mount_fstype;
break;
case 't':
args.mount_type = mount_from;
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
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++]);
eerrorx("%s: `%s' is not a mount point", argv[0], argv[optind]);
rc_stringlist_add(args.mounts, argv[optind++]);
}
nodes = find_mounts(&args);
rc_stringlist_free(args.mounts);
rc_stringlist_sort(&nodes);
nodes = find_mounts (&args);
REG_FREE (args.fstype_regex);
REG_FREE (args.skip_fstype_regex);
REG_FREE (args.node_regex);
REG_FREE (args.skip_node_regex);
REG_FREE (args.options_regex);
REG_FREE (args.skip_options_regex);
rc_strlist_reverse (nodes);
REG_FREE(args.fstype_regex);
REG_FREE(args.skip_fstype_regex);
REG_FREE(args.node_regex);
REG_FREE(args.skip_node_regex);
REG_FREE(args.options_regex);
REG_FREE(args.skip_options_regex);
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)
quiet = rc_yesno(getenv("EINFO_QUIET"));
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);
REG_FREE(point_regex);
REG_FREE(skip_point_regex);
exit (result);
exit(result);
/* NOTREACHED */
}

View File

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

View File

@ -45,34 +45,33 @@
#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 ()) {
int fd;
int retval;
int serrno = errno;
int merrno;
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 ());
close (fd);
return rc_deptree_load();
close(fd);
if (regen)
*regen = 1;
ebegin ("Caching service dependencies");
retval = rc_deptree_update ();
ebegin("Caching service dependencies");
retval = rc_deptree_update();
eend (retval ? 0 : -1, "Failed to update the dependency tree");
}
return (rc_deptree_load ());
return rc_deptree_load();
}
#include "_usage.h"
@ -97,117 +96,114 @@ static const char * const longopts_help[] = {
};
#include "_usage.c"
int rc_depend (int argc, char **argv)
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"));
char *runlevel = xstrdup(getenv("RC_SOFTLEVEL"));
int opt;
char *token;
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
types = rc_stringlist_new();
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'a':
options |= RC_DEP_START;
break;
case 'o':
options |= RC_DEP_STOP;
break;
case 's':
options |= RC_DEP_STRICT;
break;
case 't':
while ((token = strsep (&optarg, ",")))
rc_strlist_addu (&types, token);
break;
case 'u':
update = true;
break;
case 'T':
options &= RC_DEP_TRACE;
break;
case 'a':
options |= RC_DEP_START;
break;
case 'o':
options |= RC_DEP_STOP;
break;
case 's':
options |= RC_DEP_STRICT;
break;
case 't':
while ((token = strsep(&optarg, ",")))
rc_stringlist_add(types, token);
break;
case 'u':
update = true;
break;
case 'T':
options &= RC_DEP_TRACE;
break;
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
if (update) {
bool u = false;
ebegin ("Caching service dependencies");
u = rc_deptree_update ();
eend (u ? 0 : -1, "%s: %s", applet, strerror (errno));
if (! u)
eerrorx ("Failed to update the dependency tree");
ebegin("Caching service dependencies");
update = rc_deptree_update();
eend(update ? 0 : -1, "%s: %s", applet, strerror(errno));
if (! update)
eerrorx("Failed to update the dependency tree");
}
if (! (deptree = _rc_deptree_load (NULL)))
eerrorx ("failed to load deptree");
if (! (deptree = _rc_deptree_load(NULL)))
eerrorx("failed to load deptree");
if (! runlevel)
runlevel = rc_runlevel_get ();
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]);
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);
rc_deptree_free (deptree);
free (runlevel);
if (! TAILQ_FIRST(services)) {
rc_stringlist_free(services);
rc_stringlist_free(types);
rc_deptree_free(deptree);
free(runlevel);
if (update)
return (EXIT_SUCCESS);
eerrorx ("no services specified");
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_deptree_free (deptree);
free (runlevel);
return (EXIT_SUCCESS);
rc_stringlist_free(types);
rc_stringlist_free(services);
rc_stringlist_free(depends);
rc_deptree_free(deptree);
free(runlevel);
return EXIT_SUCCESS;
}

View File

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

View File

@ -30,13 +30,13 @@
*/
#include <sys/types.h>
#include <sys/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,314 +56,253 @@
#define PATH_PREFIX RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
static char **rc_conf = NULL;
static RC_STRINGLIST *rc_conf = NULL;
static void _free_rc_conf (void)
extern char** environ;
static void _free_rc_conf(void)
{
rc_strlist_free (rc_conf);
rc_stringlist_free(rc_conf);
}
char *rc_conf_value (const char *setting)
char *rc_conf_value(const char *setting)
{
if (! rc_conf) {
char *line;
int i;
RC_STRINGLIST *old;
RC_STRING *s;
char *p;
rc_conf = rc_config_load (RC_CONF);
atexit (_free_rc_conf);
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);
if (exists(RC_CONF_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);
if (isupper((int) *p))
*p = tolower((int) *p);
p++;
}
}
}
return (rc_config_value ((const char *const *)rc_conf, setting));
return rc_config_value(rc_conf, setting);
}
bool rc_conf_yesno (const char *setting)
bool rc_conf_yesno(const char *setting)
{
return (rc_yesno (rc_conf_value (setting)));
return rc_yesno(rc_conf_value (setting));
}
char **env_filter (void)
static const char *const env_whitelist[] = {
"PATH", "SHELL", "USER", "HOME", "TERM",
"LANG", "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
"LC_MONETARY", "LC_MESSAGES", "LC_PAPER", "LC_NAME", "LC_ADDRESS",
"LC_TELEPHONE", "LC_MEASUREMENT", "LC_IDENTIFICATION", "LC_ALL",
"INIT_HALT", "INIT_VERSION", "RUNLEVEL", "PREVLEVEL", "CONSOLE",
"IN_HOTPLUG", "IN_BACKGROUND", "RC_INTERFACE_KEEP_CONFIG",
NULL
};
void env_filter(void)
{
char **env = NULL;
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 */
e = env_name = xstrdup (rc_conf_value ("rc_env_allow"));
while ((token = strsep (&e, " "))) {
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);
free(env_name);
rc_stringlist_free(env_allow);
return;
}
rc_strlist_add (&whitelist, token);
rc_stringlist_add(env_allow, token);
}
free (env_name);
free(env_name);
if (exists (PROFILE_ENV))
profile = rc_config_load (PROFILE_ENV);
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);
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);
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_var)
if (env_whitelist[i])
continue;
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
if (strcmp (env_name, "PATH") == 0 &&
strncmp (PATH_PREFIX, env_var, pplen) != 0)
{
got_path = true;
env_len = strlen (env_name) + strlen (env_var) + pplen + 3;
e = p = xmalloc (sizeof (char) * env_len);
p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
/* Check our user defined list */
TAILQ_FOREACH(s, env_allow, entries)
if (strcmp(s->value, env->value) == 0)
break;
if (s)
continue;
/* 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 ((tok = strsep (&npp, ":")))
if (strcmp (tok, token) == 0)
break;
if (! tok)
p += snprintf (p, env_len - (p - e), ":%s", token);
free (np);
}
*p++ = 0;
} else {
env_len = strlen (env_name) + strlen (env_var) + 2;
e = xmalloc (sizeof (char) * env_len);
snprintf (e, env_len, "%s=%s", env_name, env_var);
}
/* Now check our profile */
rc_strlist_add (&env, e);
free (e);
/* OK, not allowed! */
e = strchr(env->value, '=');
*e = '\0';
unsetenv(env->value);
}
/* 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);
free (e);
}
rc_strlist_free (whitelist);
rc_strlist_free (profile);
return (env);
rc_stringlist_free(env_list);
rc_stringlist_free(env_allow);
rc_stringlist_free(profile);
}
char **env_config (void)
void env_config(void)
{
char **env = NULL;
char *line;
size_t pplen = strlen(PATH_PREFIX);
char *path;
char *p;
char *e;
size_t l;
const char *sys = rc_sys ();
struct utsname uts;
FILE *fp;
char *token;
char *np;
char *npp;
char *tok;
const char *sys = rc_sys();
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);
/* Ensure our PATH is prefixed with the system locations first
for a little extra security */
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);
/* 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);
/* Now go through the env var and only add bits not in our PREFIX */
while ((token = strsep(&path, ":"))) {
np = npp = xstrdup(PATH_PREFIX);
while ((tok = strsep(&npp, ":")))
if (strcmp(tok, token) == 0)
break;
if (! tok)
p += snprintf(p, l - (p - e), ":%s", token);
free (np);
}
*p++ = '\0';
unsetenv("PATH");
setenv("PATH", e, 1);
free(e);
}
rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
setenv("RC_LIBDIR", RC_LIBDIR, 1);
setenv("RC_SVCDIR", RC_SVCDIR, 1);
setenv("RC_BOOTLEVEL", RC_LEVEL_BOOT, 1);
e = rc_runlevel_get();
setenv("RC_RUNLEVEL", e, 1);
free(e);
l = strlen ("RC_SOFTLEVEL=") + strlen (runlevel) + 1;
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));
if (fgets (buffer, sizeof (buffer), fp)) {
if ((fp = fopen(RC_KSOFTLEVEL, "r"))) {
memset(buffer, 0, sizeof (buffer));
if (fgets(buffer, sizeof (buffer), fp)) {
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);
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");
if (rc_conf_yesno ("rc_verbose"))
rc_strlist_add (&env, "EINFO_VERBOSE=YES");
if (rc_conf_yesno("rc_quiet"))
setenv("EINFO_QUIET", "YES", 1);
if (rc_conf_yesno("rc_verbose"))
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);
if ((! rc_conf_yesno("rc_color") && errno == 0) ||
rc_conf_yesno("rc_nocolor"))
setenv("EINFO_COLOR", "NO", 1);
}
bool service_plugable (const char *service)
bool service_plugable(const char *service)
{
char *list;
char *p;
char *star;
char *token;
bool allow = true;
char *match = rc_conf_value ("rc_plug_services");
char *match = rc_conf_value("rc_plug_services");
bool truefalse;
if (! match)
return (true);
return true;
list = xstrdup (match);
list = xstrdup(match);
p = list;
while ((token = strsep (&p, " "))) {
bool truefalse = true;
while ((token = strsep(&p, " "))) {
if (token[0] == '!') {
truefalse = false;
token++;
}
} else
truefalse = true;
star = strchr (token, '*');
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;
}
} else {
if (strcmp (service, token) == 0) {
if (strcmp(service, token) == 0) {
allow = truefalse;
break;
}
}
}
free (list);
return (allow);
free(list);
return allow;
}
int signal_setup (int sig, void (*handler)(int))
int signal_setup(int sig, void (*handler)(int))
{
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sigemptyset (&sa.sa_mask);
memset(&sa, 0, sizeof (sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
return (sigaction (sig, &sa, NULL));
return sigaction(sig, &sa, NULL);
}

View File

@ -31,6 +31,7 @@
#include <sys/types.h>
#include <sys/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,129 +56,117 @@ 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)
dlfunc_t dlfunc(void * __restrict handle, const char * __restrict symbol)
{
union {
void *d;
dlfunc_t f;
} rv;
rv.d = dlsym (handle, symbol);
return (rv.f);
rv.d = dlsym(handle, symbol);
return rv.f;
}
#endif
void rc_plugin_load (void)
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)))
if (! (dp = opendir(RC_PLUGINDIR)))
return;
while ((d = readdir (dp))) {
while ((d = readdir(dp))) {
if (d->d_name[0] == '.')
continue;
p = rc_strcatpaths (RC_PLUGINDIR, d->d_name, NULL);
h = dlopen (p, RTLD_LAZY);
free (p);
p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL);
h = dlopen(p, RTLD_LAZY);
free(p);
if (! h) {
eerror ("dlopen: %s", dlerror ());
eerror("dlopen: %s", dlerror());
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);
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->name = xstrdup (d->d_name);
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);
closedir(dp);
}
int rc_waitpid (pid_t pid)
int rc_waitpid(pid_t pid)
{
int status = 0;
pid_t savedpid = pid;
int retval = -1;
errno = 0;
while ((pid = waitpid (savedpid, &status, 0)) > 0) {
while ((pid = waitpid(savedpid, &status, 0)) > 0) {
if (pid == savedpid)
retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
retval = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
}
return (retval);
return retval;
}
void rc_plugin_run (rc_hook_t hook, const char *value)
void rc_plugin_run(RC_HOOK hook, const char *value)
{
plugin_t *plugin = plugins;
PLUGIN *plugin;
struct sigaction sa;
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)
return;
/* We need to block signals until we have forked */
memset (&sa, 0, sizeof (sa));
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask);
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;
}
sigemptyset(&sa.sa_mask);
sigemptyset(&empty);
sigfillset(&full);
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) {
eerror ("pipe: %s", strerror (errno));
if (pipe(pfd) == -1) {
eerror("pipe: %s", strerror(errno));
return;
}
@ -188,81 +176,78 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
for (i = 0; i < 2; i++)
if ((flags = fcntl (pfd[i], F_GETFD, 0)) < 0 ||
fcntl (pfd[i], F_SETFD, flags | FD_CLOEXEC) < 0)
eerror ("fcntl: %s", strerror (errno));
eerror("fcntl: %s", strerror(errno));
sigprocmask (SIG_SETMASK, &full, &old);
sigprocmask(SIG_SETMASK, &full, &old);
/* We run the plugin in a new process so we never crash
* or otherwise affected by it */
if ((pid = fork ()) == -1) {
eerror ("fork: %s", strerror (errno));
if ((pid = fork()) == -1) {
eerror("fork: %s", strerror(errno));
break;
}
if (pid == 0) {
int retval;
/* Restore default handlers */
sigaction (SIGCHLD, &sa, NULL);
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
sigaction (SIGQUIT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGUSR1, &sa, NULL);
sigaction (SIGWINCH, &sa, NULL);
sigprocmask (SIG_SETMASK, &old, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGWINCH, &sa, NULL);
sigprocmask(SIG_SETMASK, &old, NULL);
rc_in_plugin = true;
close (pfd[0]);
rc_environ_fd = fdopen (pfd[1], "w");
retval = plugin->hook (hook, value);
fclose (rc_environ_fd);
close(pfd[0]);
rc_environ_fd = fdopen(pfd[1], "w");
retval = plugin->hook(hook, value);
fclose(rc_environ_fd);
rc_environ_fd = NULL;
/* Just in case the plugin sets this to false */
rc_in_plugin = true;
exit (retval);
exit(retval);
}
sigprocmask (SIG_SETMASK, &old, NULL);
close (pfd[1]);
buffer = xmalloc (sizeof (char) * BUFSIZ);
memset (buffer, 0, BUFSIZ);
sigprocmask(SIG_SETMASK, &old, NULL);
close(pfd[1]);
buffer = xmalloc(sizeof(char) * BUFSIZ);
memset(buffer, 0, BUFSIZ);
while ((nr = read (pfd[0], buffer, BUFSIZ)) > 0) {
while ((nr = read(pfd[0], buffer, BUFSIZ)) > 0) {
p = buffer;
while (*p && p - buffer < nr) {
token = strsep (&p, "=");
token = strsep(&p, "=");
if (token) {
unsetenv (token);
unsetenv(token);
if (*p) {
setenv (token, p, 1);
p += strlen (p) + 1;
setenv(token, p, 1);
p += strlen(p) + 1;
} else
p++;
}
}
}
free (buffer);
close (pfd[0]);
free(buffer);
close(pfd[0]);
rc_waitpid (pid);
plugin = plugin->next;
rc_waitpid(pid);
}
}
void rc_plugin_unload (void)
void rc_plugin_unload(void)
{
plugin_t *plugin = plugins;
plugin_t *next;
PLUGIN *plugin = STAILQ_FIRST(&plugins);
PLUGIN *next;
while (plugin) {
next = plugin->next;
dlclose (plugin->handle);
free (plugin->name);
free (plugin);
next = STAILQ_NEXT(plugin, entries);
dlclose(plugin->handle);
free(plugin->name);
free(plugin);
plugin = next;
}
plugins = NULL;
STAILQ_INIT(&plugins);
}

View File

@ -36,10 +36,10 @@
* Mainly used in atexit code. */
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);
int rc_waitpid(pid_t pid);
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__
@ -47,7 +47,7 @@ struct __dlfunc_arg {
int __dlfunc_dummy;
};
typedef void (*dlfunc_t) (struct __dlfunc_arg);
typedef void (*dlfunc_t)(struct __dlfunc_arg);
dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol);
#endif

View File

@ -39,57 +39,56 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
extern const char *applet;
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
static void print_level (char *level)
static void print_level(char *level)
{
printf ("Runlevel: ");
if (isatty (fileno (stdout)))
printf ("%s%s%s\n",
ecolor (ECOLOR_HILITE),
level,
ecolor (ECOLOR_NORMAL));
if (isatty(fileno(stdout)))
printf("%s%s%s\n",
ecolor(ECOLOR_HILITE),
level,
ecolor(ECOLOR_NORMAL));
else
printf ("%s\n", level);
printf("%s\n", level);
}
static void print_service (char *service)
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;
int cols = printf(" %s", service);
const char *c = ecolor(ECOLOR_GOOD);
RC_SERVICE state = rc_service_state(service);
ECOLOR color = ECOLOR_BAD;
if (state & RC_SERVICE_STOPPING)
snprintf (status, sizeof (status), "stopping ");
snprintf(status, sizeof(status), "stopping ");
else if (state & RC_SERVICE_STARTING) {
snprintf (status, sizeof (status), "starting ");
snprintf(status, sizeof(status), "starting ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_INACTIVE) {
snprintf (status, sizeof (status), "inactive ");
snprintf(status, sizeof(status), "inactive ");
color = ECOLOR_WARN;
} else if (state & RC_SERVICE_STARTED) {
if (geteuid () == 0 && rc_service_daemons_crashed (service))
snprintf (status, sizeof (status), " crashed ");
if (rc_service_daemons_crashed(service))
snprintf(status, sizeof(status), " crashed ");
else {
snprintf (status, sizeof (status), " started ");
snprintf(status, sizeof(status), " started ");
color = ECOLOR_GOOD;
}
} else if (state & RC_SERVICE_SCHEDULED) {
snprintf (status, sizeof (status), "scheduled");
snprintf(status, sizeof(status), "scheduled");
color = ECOLOR_WARN;
} else
snprintf (status, sizeof (status), " stopped ");
snprintf(status, sizeof(status), " stopped ");
errno = 0;
if (c && *c && isatty (fileno (stdout)))
printf ("\n");
ebracket (cols, color, status);
if (c && *c && isatty(fileno(stdout)))
printf("\n");
ebracket(cols, color, status);
}
#include "_usage.h"
@ -115,99 +114,100 @@ 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,
(int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring, longopts,
(int *) 0)) != -1)
switch (opt) {
case 'a':
levels = rc_runlevel_list ();
break;
case 'l':
levels = rc_runlevel_list ();
STRLIST_FOREACH (levels, level, i)
printf ("%s\n", level);
rc_strlist_free (levels);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'r':
level = rc_runlevel_get ();
printf ("%s\n", level);
free (level);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 's':
services = rc_services_in_runlevel (NULL);
STRLIST_FOREACH (services, service, i)
print_service (service);
rc_strlist_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;
break;
}
if (! found)
print_service (service);
}
rc_strlist_free (levels);
rc_strlist_free (services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case 'a':
levels = rc_runlevel_list();
break;
case 'l':
levels = rc_runlevel_list();
TAILQ_FOREACH (l, levels, entries)
printf("%s\n", l->value);
rc_stringlist_free(levels);
exit(EXIT_SUCCESS);
/* NOTREACHED */
case 'r':
p = rc_runlevel_get ();
printf("%s\n", p);
free(p);
exit(EXIT_SUCCESS);
/* NOTREACHED */
case 's':
services = rc_services_in_runlevel(NULL);
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();
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);
}
rc_stringlist_free(levels);
rc_stringlist_free(services);
exit (EXIT_SUCCESS);
/* NOTREACHED */
case_RC_COMMON_GETOPT
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 ();
deptree = _rc_deptree_load(NULL);
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_deptree_free (deptree);
rc_stringlist_free(types);
rc_stringlist_free(levels);
rc_deptree_free(deptree);
exit (EXIT_SUCCESS);
exit(EXIT_SUCCESS);
/* NOTREACHED */
}

View File

@ -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);
printf ("\n");
rc_strlist_free (in);
if (inone || verbose) {
printf(" %20s |", service->value);
TAILQ_FOREACH(runlevel, in, entries)
printf (" %s", runlevel->value);
printf ("\n");
}
rc_stringlist_free(in);
}
rc_strlist_free (services);
rc_stringlist_free (services);
}
#include "_usage.h"
@ -146,111 +148,124 @@ static const char * const longopts_help[] = {
#define DODELETE (1 << 2)
#define DOSHOW (1 << 3)
int rc_update (int argc, char **argv)
int rc_update(int argc, char **argv)
{
int i;
RC_STRINGLIST *runlevels;
RC_STRING *runlevel;
char *service = NULL;
char **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,
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case_RC_COMMON_GETOPT
case_RC_COMMON_GETOPT
}
}
verbose = rc_yesno (getenv ("EINFO_VERBOSE"));
verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
if ((action & DOSHOW && action != DOSHOW) ||
(action & DOADD && action != DOADD) ||
(action & DODELETE && action != DODELETE))
eerrorx ("%s: cannot mix commands", applet);
eerrorx("%s: cannot mix commands", applet);
/* We need to be backwards compatible */
if (optind < argc) {
if (strcmp (argv[optind], "add") == 0)
if (strcmp(argv[optind], "add") == 0)
action = DOADD;
else if (strcmp (argv[optind], "delete") == 0 ||
strcmp (argv[optind], "del") == 0)
else if (strcmp(argv[optind], "delete") == 0 ||
strcmp(argv[optind], "del") == 0)
action = DODELETE;
else if (strcmp (argv[optind], "show") == 0)
else if (strcmp(argv[optind], "show") == 0)
action = DOSHOW;
if (action)
optind++;
else
eerrorx ("%s: invalid command `%s'", applet, argv[optind]);
eerrorx("%s: invalid command `%s'", applet, argv[optind]);
}
if (! action)
action = DOSHOW;
runlevels = rc_stringlist_new();
if (optind >= argc) {
if (! action & DOSHOW)
eerrorx ("%s: no service specified", applet);
eerrorx("%s: no service specified", applet);
} else {
service = argv[optind];
optind++;
while (optind < argc)
if (rc_runlevel_exists (argv[optind]))
rc_strlist_add (&runlevels, argv[optind++]);
if (rc_runlevel_exists(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)
runlevels = rc_runlevel_list ();
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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff