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,6 +98,43 @@
# define _unused
#endif
/* Some libc implemntations don't have these */
#ifndef STAILQ_CONCAT
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#endif
#ifndef TAILQ_CONCAT
#define TAILQ_CONCAT(head1, head2) do { \
if (!TAILQ_EMPTY((head2))) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
#endif
#ifndef STAILQ_FOREACH_SAFE
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
#ifndef TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#endif
_unused static void *xmalloc (size_t size)
{
void *value = malloc(size);
@ -154,8 +191,8 @@ _unused static bool existss (const char *pathname)
char *rc_conf_value(const char *var);
bool rc_conf_yesno(const char *var);
char **env_filter (void);
char **env_config (void);
void env_filter(void);
void env_config(void);
bool service_plugable(const char *service);
int signal_setup(int sig, void (*handler)(int));

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

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

View File

@ -34,6 +34,7 @@ const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@ -52,6 +53,7 @@ const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include "einfo.h"
#include "hidden-visibility.h"
hidden_proto(ecolor)
hidden_proto(ebegin)
hidden_proto(ebeginv)
@ -119,7 +121,7 @@ static const char *_eprefix = NULL;
/* Buffers and structures to hold the final colours */
static char ebuffer[100];
struct ecolor {
einfo_color_t color;
ECOLOR color;
int def;
const char *name;
};
@ -210,7 +212,7 @@ static size_t strlcat (char *dst, const char *src, size_t size)
src_n = size - dst_n;
if (src_n == 0)
return (dst_n + strlen (src));
return dst_n + strlen(src);
while (*s != '\0') {
if (src_n != 1) {
@ -221,7 +223,7 @@ static size_t strlcat (char *dst, const char *src, size_t size)
}
*d = '\0';
return (dst_n + (s - src));
return dst_n + (s - src);
}
static size_t strlcpy(char *dst, const char *src, size_t size)
@ -241,7 +243,7 @@ static size_t strlcpy (char *dst, const char *src, size_t size)
while (*src++);
}
return (src - s - 1);
return src - s - 1;
}
# endif
#endif
@ -250,7 +252,7 @@ static bool yesno (const char *value)
{
if (! value) {
errno = ENOENT;
return (false);
return false;
}
if (strcasecmp(value, "yes") == 0 ||
@ -258,7 +260,7 @@ static bool yesno (const char *value)
strcasecmp(value, "true") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "1") == 0)
return (true);
return true;
if (strcasecmp(value, "no") != 0 &&
strcasecmp(value, "n") != 0 &&
@ -267,7 +269,7 @@ static bool yesno (const char *value)
strcasecmp(value, "0") != 0)
errno = EINVAL;
return (false);
return false;
}
static bool noyes(const char *value)
@ -282,17 +284,17 @@ static bool noyes (const char *value)
errno = serrno;
}
return (retval);
return retval;
}
static bool is_quiet()
static bool is_quiet(void)
{
return (yesno (getenv ("EINFO_QUIET")));
return yesno(getenv("EINFO_QUIET"));
}
static bool is_verbose()
static bool is_verbose(void)
{
return (yesno (getenv ("EINFO_VERBOSE")));
return yesno(getenv ("EINFO_VERBOSE"));
}
/* Fake tgoto call - very crapy, but works for our needs */
@ -302,7 +304,7 @@ static char *tgoto (const char *cap, int a, int b)
static char buf[20];
snprintf(buf, sizeof(buf), cap, b, a);
return (buf);
return buf;
}
#endif
@ -322,22 +324,22 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
unsigned int i = 0;
if (f && ! isatty(fileno(f)))
return (false);
return false;
if (noyes(getenv("EINFO_COLOR")))
return (false);
return false;
if (in_colour == 0)
return (false);
return false;
if (in_colour == 1)
return (true);
return true;
term_is_cons25 = false;
if (! term) {
term = getenv("TERM");
if (! term)
return (false);
return false;
}
if (strcmp(term, "cons25") == 0)
@ -372,7 +374,7 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
if (in_colour != 1) {
in_colour = 0;
return (false);
return false;
}
#endif
if (! _af)
@ -392,7 +394,7 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
if (! _af || ! _ce || ! _me || !_md || ! _up) {
in_colour = 0;
return (false);
return false;
}
/* Many termcap databases don't have ch or RI even though they
@ -447,15 +449,15 @@ static bool colour_terminal (FILE * __EINFO_RESTRICT f)
ecolors_str[i] = &nullstr;
}
_GET_CAP (tmp, _ce)
_ASSIGN_CAP (flush)
_GET_CAP(tmp, _ce);
_ASSIGN_CAP(flush);
_GET_CAP(tmp, _up);
_ASSIGN_CAP(up);
strlcpy(tmp, _ch, sizeof(tmp));
_ASSIGN_CAP(goto_column);
in_colour = 1;
return (true);
return true;
}
static int get_term_columns(FILE * __EINFO_RESTRICT stream)
@ -468,13 +470,13 @@ static int get_term_columns (FILE * __EINFO_RESTRICT stream)
if (env) {
i = strtoimax(env, &p, 10);
if (! *p)
return (i);
return i;
}
if (ioctl(fileno(stream), TIOCGWINSZ, &ws) == 0)
return (ws.ws_col);
return ws.ws_col;
return (DEFAULT_COLS);
return DEFAULT_COLS;
}
void eprefix(const char *__EINFO_RESTRICT prefix)
@ -528,26 +530,26 @@ static int _eindent (FILE * __EINFO_RESTRICT stream)
/* Terminate it */
memset(indent + amount, 0, 1);
return (fprintf (stream, "%s", indent));
return fprintf(stream, "%s", indent);
}
static const char *_ecolor (FILE * __EINFO_RESTRICT f, einfo_color_t color)
static const char *_ecolor(FILE * __EINFO_RESTRICT f, ECOLOR color)
{
unsigned int i;
if (! colour_terminal(f))
return ("");
return "";
for (i = 0; i < sizeof(ecolors) / sizeof(ecolors[0]); i++) {
if (ecolors[i].color == color)
return (ecolors_str[i]);
return ecolors_str[i];
}
return ("");
return "";
}
hidden_def(ecolor)
const char *ecolor (einfo_color_t color)
const char *ecolor(ECOLOR color)
{
FILE *f = stdout;
@ -561,7 +563,7 @@ const char *ecolor (einfo_color_t color)
}
}
return (_ecolor (f, color));
return _ecolor(f, color);
}
#define LASTCMD(_cmd) { \
@ -594,7 +596,7 @@ static int _einfovn (const char *__EINFO_RESTRICT fmt, va_list ap)
int retval = 0;
EINFOVN(stdout, ECOLOR_GOOD);
return (retval);
return retval;
}
static int _ewarnvn(const char *__EINFO_RESTRICT fmt, va_list ap)
@ -602,7 +604,7 @@ static int _ewarnvn (const char *__EINFO_RESTRICT fmt, va_list ap)
int retval = 0;
EINFOVN(stderr, ECOLOR_WARN);
return (retval);
return retval;
}
static int _eerrorvn(const char *__EINFO_RESTRICT fmt, va_list ap)
@ -610,7 +612,7 @@ static int _eerrorvn (const char *__EINFO_RESTRICT fmt, va_list ap)
int retval = 0;
EINFOVN(stderr, ECOLOR_BAD);
return (retval);
return retval;
}
int einfon(const char *__EINFO_RESTRICT fmt, ...)
@ -619,7 +621,7 @@ int einfon (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || is_quiet())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -627,7 +629,7 @@ int einfon (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("einfon");
return (retval);
return retval;
}
hidden_def(einfon)
@ -637,7 +639,7 @@ int ewarnn (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || is_quiet())
return (0);
return 0;
va_start(ap, fmt);
retval = _ewarnvn(fmt, ap);
@ -645,7 +647,7 @@ int ewarnn (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewarnn");
return (retval);
return retval;
}
hidden_def(ewarnn)
@ -660,7 +662,7 @@ int eerrorn (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("errorn");
return (retval);
return retval;
}
hidden_def(eerrorn)
@ -670,7 +672,7 @@ int einfo (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || is_quiet())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -679,7 +681,7 @@ int einfo (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("einfo");
return (retval);
return retval;
}
hidden_def(einfo)
@ -689,7 +691,7 @@ int ewarn (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || is_quiet())
return (0);
return 0;
va_start(ap, fmt);
elogv(LOG_WARNING, fmt, ap);
@ -699,7 +701,7 @@ int ewarn (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewarn");
return (retval);
return retval;
}
hidden_def(ewarn)
@ -725,7 +727,7 @@ int eerror (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt)
return (0);
return 0;
va_start(ap, fmt);
elogv(LOG_ERR, fmt, ap);
@ -735,7 +737,7 @@ int eerror (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("eerror");
return (retval);
return retval;
}
hidden_def(eerror)
@ -761,7 +763,7 @@ int ebegin (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || is_quiet())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -772,11 +774,11 @@ int ebegin (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ebegin");
return (retval);
return retval;
}
hidden_def(ebegin)
static void _eend (FILE * __EINFO_RESTRICT fp, int col, einfo_color_t color,
static void _eend(FILE * __EINFO_RESTRICT fp, int col, ECOLOR color,
const char *msg)
{
int i;
@ -831,7 +833,7 @@ static int _do_eend (const char *cmd, int retval, const char *__EINFO_RESTRICT f
_eend(fp, col,
retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD,
retval == 0 ? OK : NOT_OK);
return (retval);
return retval;
}
int eend(int retval, const char *__EINFO_RESTRICT fmt, ...)
@ -839,7 +841,7 @@ int eend (int retval, const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (is_quiet())
return (retval);
return retval;
va_start(ap, fmt);
_do_eend("eend", retval, fmt, ap);
@ -847,7 +849,7 @@ int eend (int retval, const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("eend");
return (retval);
return retval;
}
hidden_def(eend)
@ -856,7 +858,7 @@ int ewend (int retval, const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (is_quiet())
return (retval);
return retval;
va_start(ap, fmt);
_do_eend("ewend", retval, fmt, ap);
@ -864,11 +866,11 @@ int ewend (int retval, const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewend");
return (retval);
return retval;
}
hidden_def(ewend)
void ebracket (int col, einfo_color_t color, const char *msg)
void ebracket(int col, ECOLOR color, const char *msg)
{
_eend(stdout, col, color, msg);
}
@ -929,7 +931,7 @@ int einfovn (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || ! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -937,7 +939,7 @@ int einfovn (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("einfovn");
return (retval);
return retval;
}
hidden_def(einfovn)
@ -947,7 +949,7 @@ int ewarnvn (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || ! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
retval = _ewarnvn(fmt, ap);
@ -955,7 +957,7 @@ int ewarnvn (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewarnvn");
return (retval);
return retval;
}
hidden_def(ewarnvn)
@ -965,7 +967,7 @@ int einfov (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || ! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -974,7 +976,7 @@ int einfov (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("einfov");
return (retval);
return retval;
}
hidden_def(einfov)
@ -984,7 +986,7 @@ int ewarnv (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || ! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
retval = _ewarnvn(fmt, ap);
@ -993,7 +995,7 @@ int ewarnv (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewarnv");
return (retval);
return retval;
}
hidden_def(ewarnv)
@ -1003,7 +1005,7 @@ int ebeginv (const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! fmt || ! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
retval = _einfovn(fmt, ap);
@ -1014,7 +1016,7 @@ int ebeginv (const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ebeginv");
return (retval);
return retval;
}
hidden_def(ebeginv)
@ -1023,7 +1025,7 @@ int eendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
_do_eend("eendv", retval, fmt, ap);
@ -1031,7 +1033,7 @@ int eendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("eendv");
return (retval);
return retval;
}
hidden_def(eendv)
@ -1040,7 +1042,7 @@ int ewendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
va_list ap;
if (! is_verbose())
return (0);
return 0;
va_start(ap, fmt);
_do_eend("ewendv", retval, fmt, ap);
@ -1048,7 +1050,7 @@ int ewendv (int retval, const char *__EINFO_RESTRICT fmt, ...)
LASTCMD("ewendv");
return (retval);
return retval;
}
hidden_def(ewendv)

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

@ -40,14 +40,14 @@ static bool pid_is_cmd (pid_t pid, const char *cmd)
snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid);
if ((fp = fopen(buffer, "r")) == NULL)
return (false);
return false;
while ((c = getc(fp)) != EOF && c != '(')
;
if (c != '(') {
fclose(fp);
return (false);
return false;
}
while ((c = getc(fp)) != EOF && c == *cmd)
@ -55,7 +55,7 @@ static bool pid_is_cmd (pid_t pid, const char *cmd)
fclose(fp);
return ((c == ')' && *cmd == '\0') ? true : false);
return (c == ')' && *cmd == '\0') ? true : false;
}
static bool pid_is_exec(pid_t pid, const char *const *argv)
@ -66,28 +66,27 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
int fd = -1;
int r;
/* Check it's the right binary */
snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
memset (buffer, 0, sizeof (buffer));
#if 0
if (readlink(cmdline, buffer, sizeof(buffer)) != -1) {
if (strcmp (exec, buffer) == 0)
return (true);
if (strcmp(*argv, buffer) == 0)
return true;
/* We should cater for deleted binaries too */
if (strlen(buffer) > 10) {
p = buffer + (strlen(buffer) - 10);
if (strcmp(p, " (deleted)") == 0) {
*p = 0;
if (strcmp (buffer, exec) == 0)
return (true);
if (strcmp(buffer, *argv) == 0)
return true;
}
}
}
#endif
snprintf(cmdline, sizeof(cmdline), "/proc/%u/cmdline", pid);
if ((fd = open(cmdline, O_RDONLY)) < 0)
return (false);
return false;
r = read(fd, buffer, sizeof(buffer));
close(fd);
@ -99,13 +98,13 @@ static bool pid_is_exec (pid_t pid, const char *const *argv)
p = buffer;
while (*argv) {
if (strcmp(*argv, p) != 0)
return (false);
return false;
argv++;
p += strlen(p) + 1;
if ((unsigned) (p - buffer) > sizeof (buffer))
return (false);
return false;
}
return (true);
return true;
}
pid_t *rc_find_pids(const char *const *argv, const char *cmd,
@ -123,7 +122,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
char *pp;
if ((procdir = opendir("/proc")) == NULL)
return (NULL);
return NULL;
/*
We never match RC_RUNSCRIPT_PID if present so we avoid the below
@ -168,7 +167,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
free(pids);
closedir(procdir);
errno = ENOMEM;
return (NULL);
return NULL;
}
pids = tmp;
@ -178,7 +177,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
}
closedir(procdir);
return (pids);
return pids;
}
librc_hidden_def(rc_find_pids)
@ -218,6 +217,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
char **pargv;
pid_t *pids = NULL;
pid_t *tmp;
pid_t p;
const char *const *arg;
int npids = 0;
int match;
@ -226,7 +226,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
NULL, _KVM_FLAGS, errbuf)) == NULL)
{
fprintf(stderr, "kvm_open: %s\n", errbuf);
return (NULL);
return NULL;
}
#ifdef _KVM_GETPROC2
@ -237,11 +237,11 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
if ((kp == NULL && processes > 0) || (kp != NULL && processes < 0)) {
fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd));
kvm_close(kd);
return (NULL);
return NULL;
}
for (i = 0; i < processes; i++) {
pid_t p = _GET_KINFO_PID (kp[i]);
p = _GET_KINFO_PID(kp[i]);
if (pid != 0 && pid != p)
continue;
@ -277,7 +277,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
free(pids);
kvm_close(kd);
errno = ENOMEM;
return (NULL);
return NULL;
}
pids = tmp;
@ -287,7 +287,7 @@ pid_t *rc_find_pids (const char *const *argv, const char *cmd,
}
kvm_close(kd);
return (pids);
return pids;
}
librc_hidden_def(rc_find_pids)
@ -295,33 +295,39 @@ librc_hidden_def(rc_find_pids)
# error "Platform not supported!"
#endif
static bool _match_daemon (const char *path, const char *file, char **match)
static bool _match_daemon(const char *path, const char *file,
RC_STRINGLIST *match)
{
char *line;
char *ffile = rc_strcatpaths(path, file, (char *) NULL);
FILE *fp;
RC_STRING *m;
fp = fopen(ffile, "r");
free(ffile);
if (! fp)
return (false);
return false;
while ((line = rc_getline(fp))) {
rc_strlist_delete (&match, line);
if (! match || !*match)
TAILQ_FOREACH(m, match, entries)
if (strcmp(line, m->value) == 0) {
TAILQ_REMOVE(match, m, entries);
break;
}
if (! TAILQ_FIRST(match))
break;
}
fclose(fp);
if (match && *match)
return (false);
return (true);
if (TAILQ_FIRST(match))
return false;
return true;
}
static char **_match_list (const char* const* argv,
static RC_STRINGLIST *_match_list(const char* const* argv,
const char *name, const char *pidfile)
{
char **match = NULL;
RC_STRINGLIST *match = rc_stringlist_new();
int i = 0;
size_t l;
char *m;
@ -330,7 +336,7 @@ static char **_match_list (const char* const* argv,
l = strlen(*argv) + strlen("argv_=") + 16;
m = xmalloc(sizeof(char) * l);
snprintf(m, l, "argv_0=%s", argv[i++]);
rc_strlist_add (&match, m);
rc_stringlist_add(match, m);
free(m);
}
@ -338,7 +344,7 @@ static char **_match_list (const char* const* argv,
l = strlen(name) + 6;
m = xmalloc(sizeof (char) * l);
snprintf(m, l, "name=%s", name);
rc_strlist_add (&match, m);
rc_stringlist_add(match, m);
free(m);
}
@ -346,16 +352,15 @@ static char **_match_list (const char* const* argv,
l = strlen(pidfile) + 9;
m = xmalloc(sizeof (char) * l);
snprintf(m, l, "pidfile=%s", pidfile);
rc_strlist_add (&match, m);
rc_stringlist_add(match, m);
free (m);
}
return (match);
return match;
}
bool rc_service_daemon_set(const char *service, const char *const *argv,
const char *name, const char *pidfile,
bool started)
const char *name, const char *pidfile, bool started)
{
char *dirpath;
char *file = NULL;
@ -364,12 +369,14 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
bool retval = false;
DIR *dp;
struct dirent *d;
char **match = NULL;
RC_STRINGLIST *match;
int i = 0;
char buffer[10];
FILE *fp;
if (!(argv && *argv) && ! name && ! pidfile) {
errno = EINVAL;
return (false);
return false;
}
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons",
@ -403,9 +410,6 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
/* Now store our daemon info */
if (started) {
char buffer[10];
FILE *fp;
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1);
file = rc_strcatpaths(dirpath, buffer, (char *) NULL);
@ -429,26 +433,27 @@ bool rc_service_daemon_set (const char *service, const char *const *argv,
} else
retval = true;
rc_strlist_free (match);
rc_stringlist_free(match);
free(dirpath);
return (retval);
return retval;
}
librc_hidden_def(rc_service_daemon_set)
bool rc_service_started_daemon (const char *service, const char *const *argv,
bool
rc_service_started_daemon (const char *service, const char *const *argv,
int indx)
{
char *dirpath;
char *file;
size_t l;
char **match;
RC_STRINGLIST *match;
bool retval = false;
DIR *dp;
struct dirent *d;
if (!service || !(argv && *argv))
return (false);
return false;
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
(char *) NULL);
@ -475,8 +480,8 @@ bool rc_service_started_daemon (const char *service, const char *const *argv,
}
free(dirpath);
rc_strlist_free (match);
return (retval);
rc_stringlist_free(match);
return retval;
}
librc_hidden_def(rc_service_started_daemon)
@ -497,16 +502,16 @@ bool rc_service_daemons_crashed (const char *service)
char *p;
char *token;
bool retval = false;
if (! service)
return (false);
RC_STRINGLIST *list;
RC_STRING *s;
size_t i;
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
(char *) NULL);
if (! (dp = opendir(dirpath))) {
free(dirpath);
return (false);
return false;
}
while ((d = readdir(dp))) {
@ -519,6 +524,8 @@ bool rc_service_daemons_crashed (const char *service)
if (! fp)
break;
list = rc_stringlist_new();
while ((line = rc_getline(fp))) {
p = line;
if ((token = strsep(&p, "=")) == NULL || ! p) {
@ -526,13 +533,13 @@ bool rc_service_daemons_crashed (const char *service)
continue;
}
if (strlen (p) == 0) {
if (! *p) {
free(line);
continue;
}
if (strncmp(token, "argv_", 5) == 0) {
rc_strlist_add (&argv, p);
rc_stringlist_add(list, p);
} else if (strcmp(token, "exec") == 0) {
if (exec)
free(exec);
@ -573,40 +580,45 @@ bool rc_service_daemons_crashed (const char *service)
pidfile = NULL;
/* We have the pid, so no need to match on name */
rc_strlist_free (argv);
argv = NULL;
rc_stringlist_free(list);
list = NULL;
free (exec);
exec = NULL;
free (name);
name = NULL;
} else {
if (exec && ! TAILQ_FIRST(list)) {
rc_stringlist_add(list, exec);
}
if (exec && ! argv) {
rc_strlist_add (&argv, exec);
free(exec);
exec = NULL;
/* We need to flatten our linked list into an array */
i = 0;
TAILQ_FOREACH(s, list, entries)
i++;
argv = xmalloc(sizeof(char *) * (i + 1));
i = 0;
TAILQ_FOREACH(s, list, entries)
argv[i++] = s->value;
argv[i] = '\0';
}
if ((pids = rc_find_pids ((const char *const *)argv, name, 0, pid)) == NULL) {
if ((pids = rc_find_pids((const char *const *)argv, name, 0, pid)) == NULL)
retval = true;
free(pids);
free(argv);
argv = NULL;
rc_stringlist_free(list);
free(name);
name = NULL;
if (retval)
break;
}
free (pids);
rc_strlist_free (argv);
argv = NULL;
free (exec);
exec = NULL;
free (name);
name = NULL;
}
rc_strlist_free (argv);
free (exec);
free (name);
free(dirpath);
closedir(dp);
return (retval);
return retval;
}
librc_hidden_def(rc_service_daemons_crashed)

File diff suppressed because it is too large Load Diff

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,20 +128,22 @@ char *rc_getline (FILE *fp)
if (*line && line[--last] == '\n')
line[last] = '\0';
return (line);
return line;
}
librc_hidden_def(rc_getline)
char **rc_config_list (const char *file)
RC_STRINGLIST *rc_config_list(const char *file)
{
FILE *fp;
char *buffer;
char *p;
char *token;
char **list = NULL;
RC_STRINGLIST *list;
if (!(fp = fopen(file, "r")))
return (NULL);
return NULL;
list = rc_stringlist_new();
while ((p = buffer = rc_getline(fp))) {
/* Strip leading spaces/tabs */
@ -157,45 +159,47 @@ char **rc_config_list (const char *file)
if (token[strlen(token) - 1] == '\n')
token[strlen(token) - 1] = 0;
rc_strlist_add (&list, token);
rc_stringlist_add(list, token);
}
}
free(buffer);
}
fclose(fp);
return (list);
return list;
}
librc_hidden_def(rc_config_list)
char **rc_config_load (const char *file)
RC_STRINGLIST *rc_config_load(const char *file)
{
char **list = NULL;
char **config = NULL;
RC_STRINGLIST *list = NULL;
RC_STRINGLIST *config = NULL;
char *token;
char *line;
char *linep;
char *linetok;
RC_STRING *line;
RC_STRING *cline;
size_t i = 0;
int j;
bool replaced;
char *entry;
char *newline;
char *p;
config = rc_stringlist_new();
list = rc_config_list(file);
STRLIST_FOREACH (list, line, j) {
TAILQ_FOREACH(line, list, entries) {
/* Get entry */
if (! (token = strsep (&line, "=")))
p = line->value;
if (! (token = strsep(&p, "=")))
continue;
entry = xstrdup (token);
/* Preserve shell coloring */
if (*line == '$')
token = line;
if (*p == '$')
token = line->value;
else
do {
/* Bash variables are usually quoted */
token = strsep (&line, "\"\'");
token = strsep(&p, "\"\'");
} while (token && *token == '\0');
/* Drop a newline if that's all we have */
@ -216,46 +220,43 @@ char **rc_config_load (const char *file)
replaced = false;
/* In shells the last item takes precedence, so we need to remove
any prior values we may already have */
STRLIST_FOREACH (config, line, i) {
char *tmp = xstrdup (line);
linep = tmp;
linetok = strsep (&linep, "=");
if (strcmp (linetok, entry) == 0) {
TAILQ_FOREACH(cline, config, entries) {
p = strchr(cline->value, '=');
if (p && strncmp(entry, cline->value,
(size_t) (p - cline->value)) == 0)
{
/* We have a match now - to save time we directly replace it */
free (config[i - 1]);
config[i - 1] = newline;
free(cline->value);
cline->value = newline;
replaced = true;
free (tmp);
break;
}
free (tmp);
}
if (! replaced) {
rc_strlist_addsort (&config, newline);
rc_stringlist_add(config, newline);
free(newline);
}
free(entry);
}
rc_strlist_free (list);
rc_stringlist_free(list);
return (config);
return config;
}
librc_hidden_def(rc_config_load)
char *rc_config_value (const char *const *list, const char *entry)
char *rc_config_value(RC_STRINGLIST *list, const char *entry)
{
const char *line;
int i;
RC_STRING *line;
char *p;
STRLIST_FOREACH (list, line, i) {
p = strchr (line, '=');
if (p && strncmp (entry, line, (size_t) (p - line)) == 0)
return (p += 1);
TAILQ_FOREACH(line, list, entries) {
p = strchr(line->value, '=');
if (p &&
strncmp(entry, line->value, (size_t)(p - line->value)) == 0)
return p += 1;
}
return (NULL);
return NULL;
}
librc_hidden_def(rc_config_value)

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)

View File

@ -47,7 +47,7 @@ const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
FILE *rc_environ_fd = NULL;
typedef struct rc_service_state_name {
rc_service_state_t state;
RC_SERVICE state;
const char *name;
} rc_service_state_name_t;
@ -68,46 +68,50 @@ static const rc_service_state_name_t rc_service_state_names[] = {
#define LS_INITD 0x01
#define LS_DIR 0x02
static char **ls_dir (const char *dir, int options)
static RC_STRINGLIST *ls_dir(const char *dir, int options)
{
DIR *dp;
struct dirent *d;
char **list = NULL;
RC_STRINGLIST *list;
struct stat buf;
size_t l;
char *file;
int r;
if ((dp = opendir(dir)) == NULL)
return (NULL);
return NULL;
list = rc_stringlist_new();
while (((d = readdir(dp)) != NULL)) {
if (d->d_name[0] != '.') {
if (options & LS_INITD) {
int l = strlen (d->d_name);
/* Check that our file really exists.
* This is important as a service maybe in a runlevel, but
* could also have been removed. */
char *file = rc_strcatpaths (dir, d->d_name, NULL);
int ok = stat (file, &buf);
file = rc_strcatpaths(dir, d->d_name, NULL);
r = stat(file, &buf);
free(file);
if (ok != 0)
if (r != 0)
continue;
/* .sh files are not init scripts */
l = strlen(d->d_name);
if (l > 2 && d->d_name[l - 3] == '.' &&
d->d_name[l - 2] == 's' &&
d->d_name[l - 1] == 'h')
continue;
}
if (options & LS_DIR) {
if (stat (d->d_name, &buf) == 0 && ! S_ISDIR (buf.st_mode))
if (stat(d->d_name, &buf) == 0 &&
! S_ISDIR(buf.st_mode))
continue;
}
rc_strlist_addsort (&list, d->d_name);
rc_stringlist_add(list, d->d_name);
}
}
closedir(dp);
return (list);
return list;
}
static bool rm_dir(const char *pathname, bool top)
@ -119,7 +123,7 @@ static bool rm_dir (const char *pathname, bool top)
bool retval = true;
if ((dp = opendir(pathname)) == NULL)
return (false);
return false;
errno = 0;
while (((d = readdir(dp)) != NULL) && errno == 0) {
@ -150,12 +154,12 @@ static bool rm_dir (const char *pathname, bool top)
free(tmp);
if (! retval)
return (false);
return false;
if (top && rmdir(pathname) != 0)
return (false);
return false;
return (true);
return true;
}
/* Other systems may need this at some point, but for now it's Linux only */
@ -169,7 +173,7 @@ static bool file_regex (const char *file, const char *regex)
int result;
if (! (fp = fopen(file, "r")))
return (false);
return false;
if ((result = regcomp(&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
fclose(fp);
@ -177,7 +181,7 @@ static bool file_regex (const char *file, const char *regex)
regerror(result, &re, line, BUFSIZ);
fprintf(stderr, "file_regex: %s", line);
free(line);
return (false);
return false;
}
while ((line = rc_getline(fp))) {
@ -190,7 +194,7 @@ static bool file_regex (const char *file, const char *regex)
fclose(fp);
regfree(&re);
return (retval);
return retval;
}
#endif
@ -198,7 +202,7 @@ static bool file_regex (const char *file, const char *regex)
const char *rc_sys(void)
{
#ifdef PREFIX
return (RC_SYS_PREFIX);
return RC_SYS_PREFIX;
#else
#ifdef __FreeBSD__
@ -207,55 +211,55 @@ const char *rc_sys (void)
if (sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0) == 0)
if (jailed == 1)
return (RC_SYS_JAIL);
return RC_SYS_JAIL;
#endif
#ifdef __linux__
if (exists("/proc/xen")) {
if (file_regex("/proc/xen/capabilities", "control_d"))
return (RC_SYS_XEN0);
return (RC_SYS_XENU);
return RC_SYS_XEN0;
return RC_SYS_XENU;
} else if (file_regex("/proc/cpuinfo", "UML"))
return (RC_SYS_UML);
return RC_SYS_UML;
else if (file_regex("/proc/self/status",
"(s_context|VxID):[[:space:]]*[1-9]"))
return (RC_SYS_VSERVER);
return RC_SYS_VSERVER;
else if (file_regex("/proc/self/status",
"envID:[[:space:]]*[1-9]"))
return (RC_SYS_OPENVZ);
return RC_SYS_OPENVZ;
#endif
return (NULL);
return NULL;
#endif /* PREFIX */
}
static const char *rc_parse_service_state (rc_service_state_t state)
static const char *rc_parse_service_state(RC_SERVICE state)
{
int i;
for (i = 0; rc_service_state_names[i].name; i++) {
if (rc_service_state_names[i].state == state)
return (rc_service_state_names[i].name);
return rc_service_state_names[i].name;
}
return (NULL);
return NULL;
}
bool rc_runlevel_starting(void)
{
return (exists (RC_STARTING));
return exists(RC_STARTING);
}
librc_hidden_def(rc_runlevel_starting)
bool rc_runlevel_stopping(void)
{
return (exists (RC_STOPPING));
return exists(RC_STOPPING);
}
librc_hidden_def(rc_runlevel_stopping)
char **rc_runlevel_list (void)
RC_STRINGLIST *rc_runlevel_list(void)
{
return (ls_dir (RC_RUNLEVELDIR, LS_DIR));
return ls_dir(RC_RUNLEVELDIR, LS_DIR);
}
librc_hidden_def(rc_runlevel_list)
@ -280,7 +284,7 @@ char *rc_runlevel_get (void)
runlevel = xstrdup(RC_LEVEL_SYSINIT);
}
return (runlevel);
return runlevel;
}
librc_hidden_def(rc_runlevel_get)
@ -289,10 +293,10 @@ bool rc_runlevel_set (const char *runlevel)
FILE *fp = fopen(SOFTLEVEL, "w");
if (! fp)
return (false);
return false;
fprintf(fp, "%s", runlevel);
fclose(fp);
return (true);
return true;
}
librc_hidden_def(rc_runlevel_set)
@ -303,13 +307,13 @@ bool rc_runlevel_exists (const char *runlevel)
bool retval = false;
if (! runlevel)
return (false);
return false;
path = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
retval = true;
free(path);
return (retval);
return retval;
}
librc_hidden_def(rc_runlevel_exists)
@ -322,10 +326,10 @@ char *rc_service_resolve (const char *service)
struct stat buf;
if (! service)
return (NULL);
return NULL;
if (service[0] == '/')
return (xstrdup (service));
return xstrdup(service);
/* First check started services */
file = rc_strcatpaths(RC_SVCDIR, "started", service, (char *) NULL);
@ -344,14 +348,14 @@ char *rc_service_resolve (const char *service)
#ifdef RC_LOCAL_INITDIR
snprintf(buffer, sizeof(buffer), RC_LOCAL_INITDIR "/%s", service);
if (stat(buffer, &buf) == 0)
return (xstrdup (buffer));
return xstrdup(buffer);
#endif
if (file) {
r = readlink(file, buffer, sizeof(buffer));
free(file);
if (r > 0)
return (xstrdup (buffer));
return xstrdup(buffer);
}
snprintf(buffer, sizeof(buffer), RC_INITDIR "/%s", service);
@ -360,11 +364,11 @@ char *rc_service_resolve (const char *service)
if (stat(buffer, &buf) != 0) {
snprintf(buffer, sizeof(buffer), RC_PKG_INITDIR "/%s", service);
if (stat(buffer, &buf) != 0)
return (NULL);
return NULL;
}
#endif
return (xstrdup (buffer));
return xstrdup(buffer);
}
librc_hidden_def(rc_service_resolve)
@ -376,7 +380,7 @@ bool rc_service_exists (const char *service)
struct stat buf;
if (! service)
return (false);
return false;
len = strlen(service);
@ -384,46 +388,49 @@ bool rc_service_exists (const char *service)
if (len > 2 && service[len - 3] == '.' &&
service[len - 2] == 's' &&
service[len - 1] == 'h')
return (false);
return false;
if (! (file = rc_service_resolve(service)))
return (false);
return false;
if (stat(file, &buf) == 0 && buf.st_mode & S_IXUGO)
retval = true;
free(file);
return (retval);
return retval;
}
librc_hidden_def(rc_service_exists)
#define OPTSTR ". '%s'; echo \"${opts}\""
char **rc_service_extra_commands (const char *service)
RC_STRINGLIST *rc_service_extra_commands(const char *service)
{
char *svc;
char *cmd = NULL;
char *buffer = NULL;
char **commands = NULL;
RC_STRINGLIST *commands;
char *token;
char *p;
FILE *fp;
size_t l;
if (! (svc = rc_service_resolve(service)))
return (NULL);
return NULL;
commands = rc_stringlist_new();
l = strlen(OPTSTR) + strlen(svc) + 1;
cmd = xmalloc(sizeof(char) * l);
snprintf(cmd, l, OPTSTR, svc);
free(svc);
if ((fp = popen(cmd, "r"))) {
p = buffer = rc_getline(fp);
while ((token = strsep(&p, " ")))
rc_strlist_addsort (&commands, token);
rc_stringlist_add(commands, token);
pclose(fp);
free(buffer);
}
free(cmd);
return (commands);
return commands;
}
librc_hidden_def(rc_service_extra_commands)
@ -437,7 +444,7 @@ char *rc_service_description (const char *service, const char *option)
size_t l;
if (! (svc = rc_service_resolve(service)))
return (NULL);
return NULL;
if (! option)
option = "";
@ -451,7 +458,7 @@ char *rc_service_description (const char *service, const char *option)
pclose(fp);
}
free(cmd);
return (desc);
return desc;
}
librc_hidden_def(rc_service_description)
@ -461,18 +468,18 @@ bool rc_service_in_runlevel (const char *service, const char *runlevel)
bool retval;
if (! runlevel || ! service)
return (false);
return false;
file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service),
(char *) NULL);
retval = exists(file);
free(file);
return (retval);
return retval;
}
librc_hidden_def(rc_service_in_runlevel)
bool rc_service_mark (const char *service, const rc_service_state_t state)
bool rc_service_mark(const char *service, const RC_SERVICE state)
{
char *file;
int i = 0;
@ -480,16 +487,21 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
const char *base;
char *init = rc_service_resolve(service);
bool skip_wasinactive = false;
int s;
char *was;
RC_STRINGLIST *dirs;
RC_STRING *dir;
int serrno;
if (! init)
return (false);
return false;
base = basename_c(service);
if (state != RC_SERVICE_STOPPED) {
if (! exists(init)) {
free(init);
return (false);
return false;
}
file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state (state), base,
@ -500,7 +512,7 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
if (i != 0) {
free(file);
free(init);
return (false);
return false;
}
free(file);
@ -509,12 +521,12 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
if (state == RC_SERVICE_COLDPLUGGED || state == RC_SERVICE_FAILED) {
free(init);
return (true);
return true;
}
/* Remove any old states now */
for (i = 0; rc_service_state_names[i].name; i++) {
int s = rc_service_state_names[i].state;
s = rc_service_state_names[i].state;
if ((s != skip_state &&
s != RC_SERVICE_STOPPED &&
@ -529,13 +541,13 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
state == RC_SERVICE_STOPPING) &&
s == RC_SERVICE_INACTIVE)
{
char *wasfile = rc_strcatpaths (RC_SVCDIR,
was = rc_strcatpaths(RC_SVCDIR,
rc_parse_service_state(RC_SERVICE_WASINACTIVE),
base, (char *) NULL);
symlink (init, wasfile);
symlink(init, was);
skip_wasinactive = true;
free (wasfile);
free(was);
}
unlink(file);
}
@ -555,52 +567,52 @@ bool rc_service_mark (const char *service, const rc_service_state_t state)
/* Remove any options and daemons the service may have stored */
if (state == RC_SERVICE_STOPPED) {
char *dir = rc_strcatpaths (RC_SVCDIR, "options", base, (char *) NULL);
rm_dir (dir, true);
free (dir);
file = rc_strcatpaths(RC_SVCDIR, "options", base, (char *) NULL);
rm_dir(file, true);
free(file);
dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL);
rm_dir (dir, true);
free (dir);
file = rc_strcatpaths(RC_SVCDIR, "daemons", base, (char *) NULL);
rm_dir(file, true);
free(file);
rc_service_schedule_clear(service);
}
/* These are final states, so remove us from scheduled */
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
char *sdir = rc_strcatpaths (RC_SVCDIR, "scheduled", (char *) NULL);
char **dirs = ls_dir (sdir, 0);
char *dir;
int serrno;
file = rc_strcatpaths(RC_SVCDIR, "scheduled", (char *) NULL);
dirs = ls_dir(file, 0);
STRLIST_FOREACH (dirs, dir, i) {
char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL);
file = rc_strcatpaths (bdir, base, (char *) NULL);
unlink (file);
free (file);
TAILQ_FOREACH(dir, dirs, entries) {
was = rc_strcatpaths(file, dir->value, base, (char *) NULL);
unlink(was);
free(was);
/* Try and remove the dir - we don't care about errors */
was = rc_strcatpaths(file, dir->value, (char *) NULL);
serrno = errno;
rmdir (bdir);
rmdir(was);
errno = serrno;
free (bdir);
free(was);
}
rc_strlist_free (dirs);
free (sdir);
rc_stringlist_free(dirs);
}
free(init);
return (true);
return true;
}
librc_hidden_def(rc_service_mark)
rc_service_state_t rc_service_state (const char *service)
RC_SERVICE rc_service_state(const char *service)
{
int i;
int state = RC_SERVICE_STOPPED;
char *file;
RC_STRINGLIST *dirs;
RC_STRING *dir;
for (i = 0; rc_service_state_names[i].name; i++) {
char *file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i].name,
file = rc_strcatpaths(RC_SVCDIR, rc_service_state_names[i].name,
basename_c(service), (char*) NULL);
if (exists(file)) {
if (rc_service_state_names[i].state <= 0x10)
@ -612,14 +624,21 @@ rc_service_state_t rc_service_state (const char *service)
}
if (state & RC_SERVICE_STOPPED) {
char **services = rc_services_scheduled_by (service);
if (services) {
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
TAILQ_FOREACH (dir, dirs, entries) {
file = rc_strcatpaths(RC_SVCDIR, "scheduled",
dir->value,
service, (char *) NULL);
if (exists(file))
state |= RC_SERVICE_SCHEDULED;
free (services);
free(file);
if (state & RC_SERVICE_SCHEDULED)
break;
}
rc_stringlist_free(dirs);
}
return (state);
return state;
}
librc_hidden_def(rc_service_state)
@ -636,7 +655,7 @@ char *rc_service_value_get (const char *service, const char *option)
}
free(file);
return (line);
return line;
}
librc_hidden_def(rc_service_value_get)
@ -651,7 +670,7 @@ bool rc_service_value_set (const char *service, const char *option,
if (mkdir(path, 0755) != 0 && errno != EEXIST) {
free(path);
free(file);
return (false);
return false;
}
if ((fp = fopen(file, "w"))) {
@ -663,7 +682,7 @@ bool rc_service_value_set (const char *service, const char *option,
free(path);
free(file);
return (retval);
return retval;
}
librc_hidden_def(rc_service_value_set)
@ -680,7 +699,7 @@ static pid_t _exec_service (const char *service, const char *arg)
if (! exists(file)) {
rc_service_mark(service, RC_SERVICE_STOPPED);
free(file);
return (0);
return 0;
}
/* We create a fifo so that other services can wait until we complete */
@ -690,7 +709,7 @@ static pid_t _exec_service (const char *service, const char *arg)
if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) {
free(fifo);
free(file);
return (-1);
return -1;
}
/* We need to block signals until we have forked */
@ -729,34 +748,34 @@ static pid_t _exec_service (const char *service, const char *arg)
free(fifo);
free(file);
return (pid);
return pid;
}
pid_t rc_service_stop(const char *service)
{
rc_service_state_t state = rc_service_state (service);
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_FAILED)
return (-1);
return -1;
if (state & RC_SERVICE_STOPPED)
return (0);
return 0;
return (_exec_service (service, "stop"));
return _exec_service(service, "stop");
}
librc_hidden_def(rc_service_stop)
pid_t rc_service_start(const char *service)
{
rc_service_state_t state = rc_service_state (service);
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_FAILED)
return (-1);
return -1;
if (! state & RC_SERVICE_STOPPED)
return (0);
return 0;
return (_exec_service (service, "start"));
return _exec_service(service, "start");
}
librc_hidden_def(rc_service_start)
@ -770,13 +789,13 @@ bool rc_service_schedule_start (const char *service,
/* service may be a provided service, like net */
if (! service || ! rc_service_exists(service_to_start))
return (false);
return false;
dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
(char *) NULL);
if (mkdir(dir, 0755) != 0 && errno != EEXIST) {
free(dir);
return (false);
return false;
}
init = rc_service_resolve(service_to_start);
@ -786,7 +805,7 @@ bool rc_service_schedule_start (const char *service,
free(file);
free(dir);
return (retval);
return retval;
}
librc_hidden_def(rc_service_schedule_start)
@ -799,86 +818,81 @@ bool rc_service_schedule_clear (const char *service)
if (! (retval = rm_dir(dir, true)) && errno == ENOENT)
retval = true;
free(dir);
return (retval);
return retval;
}
librc_hidden_def(rc_service_schedule_clear)
char **rc_services_in_runlevel (const char *runlevel)
RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
{
char *dir;
char **list = NULL;
RC_STRINGLIST *list;
if (! runlevel) {
#if defined(RC_PKG_INITDIR) || defined(RC_LOCAL_INITDIR)
int i;
#endif
#ifdef RC_PKG_INITDIR
char **pkg = ls_dir (RC_PKG_INITDIR, LS_INITD);
RC_STRINGLIST *pkg = ls_dir(RC_PKG_INITDIR, LS_INITD);
#endif
#ifdef RC_LOCAL_INITDIR
char **local = ls_dir (RC_LOCAL_INITDIR, LS_INITD);
RC_STRINGLIST *local = ls_dir(RC_LOCAL_INITDIR, LS_INITD);
#endif
list = ls_dir(RC_INITDIR, LS_INITD);
#ifdef RC_PKG_INITDIR
STRLIST_FOREACH (pkg, dir, i)
rc_strlist_addsortu (&list, dir);
rc_strlist_free (pkg);
if (pkg) {
TAILQ_CONCAT(list, pkg);
free(pkg);
}
#endif
#ifdef RC_LOCAL_DIR
STRLIST_FOREACH (local, dir, i)
rc_strlist_addsortu (&list, dir);
rc_strlist_free (local);
if (local) {
TAILQ_CONCAT(list, local);
free(local);
}
#endif
return (list);
return list;
}
/* These special levels never contain any services */
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
strcmp (runlevel, RC_LEVEL_SINGLE) == 0)
return (NULL);
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
list = rc_stringlist_new();
return list;
}
dir = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
list = ls_dir(dir, LS_INITD);
free(dir);
return (list);
return list;
}
librc_hidden_def(rc_services_in_runlevel)
char **rc_services_in_state (rc_service_state_t state)
RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
{
char *dir = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(state),
(char *) NULL);
char **list = NULL;
RC_STRINGLIST *services;
RC_STRINGLIST *list;
RC_STRINGLIST *dirs;
RC_STRING *d;
char *p;
if (state == RC_SERVICE_SCHEDULED) {
char **dirs = ls_dir (dir, 0);
char *d;
int i;
STRLIST_FOREACH (dirs, d, i) {
char *p = rc_strcatpaths (dir, d, (char *) NULL);
char **entries = ls_dir (p, LS_INITD);
char *e;
int j;
STRLIST_FOREACH (entries, e, j)
rc_strlist_addsortu (&list, e);
if (entries)
free (entries);
dirs = ls_dir(dir, 0);
list = rc_stringlist_new();
TAILQ_FOREACH(d, dirs, entries) {
p = rc_strcatpaths(dir, d->value, (char *) NULL);
services = ls_dir(p, LS_INITD);
free(p);
TAILQ_CONCAT(list, services);
free(services);
}
if (dirs)
free (dirs);
rc_stringlist_free(dirs);
} else {
list = ls_dir(dir, LS_INITD);
}
free(dir);
return (list);
return list;
}
librc_hidden_def(rc_services_in_state)
@ -887,15 +901,17 @@ bool rc_service_add (const char *runlevel, const char *service)
bool retval;
char *init;
char *file;
char path[MAXPATHLEN] = { '\0' };
char *p;
if (! rc_runlevel_exists(runlevel)) {
errno = ENOENT;
return (false);
return false;
}
if (rc_service_in_runlevel(service, runlevel)) {
errno = EEXIST;
return (false);
return false;
}
init = rc_service_resolve(service);
@ -903,18 +919,15 @@ bool rc_service_add (const char *runlevel, const char *service)
/* We need to ensure that only things in /etc/init.d are added
* to the boot runlevel */
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) {
char tmp[MAXPATHLEN] = { '\0' };
char *p;
p = realpath (dirname (init), tmp);
p = realpath(dirname (init), path);
free(init);
if (! *p)
return (false);
return false;
retval = (strcmp (tmp, RC_INITDIR) == 0);
retval = (strcmp(path, RC_INITDIR) == 0);
if (! retval) {
errno = EPERM;
return (false);
return false;
}
init = rc_strcatpaths(RC_INITDIR, service, (char *) NULL);
}
@ -924,7 +937,7 @@ bool rc_service_add (const char *runlevel, const char *service)
retval = (symlink(init, file) == 0);
free(init);
free(file);
return (retval);
return retval;
}
librc_hidden_def(rc_service_add)
@ -934,7 +947,7 @@ bool rc_service_delete (const char *runlevel, const char *service)
bool retval = false;
if (! runlevel || ! service)
return (false);
return false;
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c(service),
(char *) NULL);
@ -942,38 +955,38 @@ bool rc_service_delete (const char *runlevel, const char *service)
retval = true;
free(file);
return (retval);
return retval;
}
librc_hidden_def(rc_service_delete)
char **rc_services_scheduled_by (const char *service)
RC_STRINGLIST *rc_services_scheduled_by(const char *service)
{
char **dirs = ls_dir (RC_SVCDIR "/scheduled", 0);
char **list = NULL;
char *dir;
int i;
RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
RC_STRINGLIST *list;
RC_STRING *dir;
char *file;
STRLIST_FOREACH (dirs, dir, i) {
char *file = rc_strcatpaths (RC_SVCDIR, "scheduled", dir, service,
(char *) NULL);
list = rc_stringlist_new();
TAILQ_FOREACH (dir, dirs, entries) {
file = rc_strcatpaths(RC_SVCDIR, "scheduled", dir->value,
service, (char *) NULL);
if (exists(file))
rc_strlist_add (&list, file);
rc_stringlist_add(list, file);
free(file);
}
rc_strlist_free (dirs);
rc_stringlist_free(dirs);
return (list);
return list;
}
librc_hidden_def(rc_services_scheduled_by)
char **rc_services_scheduled (const char *service)
RC_STRINGLIST *rc_services_scheduled(const char *service)
{
char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
(char *) NULL);
char **list = NULL;
RC_STRINGLIST *list = ls_dir(dir, LS_INITD);
list = ls_dir (dir, LS_INITD);
free(dir);
return (list);
return list;
}
librc_hidden_def(rc_services_scheduled)

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

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

@ -37,6 +37,10 @@ _noreturn static void usage (int exit_status)
{
const char * const has_arg[] = { "", "<arg>", "[arg]" };
int i;
int len;
char *lo;
char *p;
char *token;
#ifdef usagestring
printf(usagestring);
@ -48,13 +52,10 @@ _noreturn static void usage (int exit_status)
#endif
printf("\n\nOptions: [" getoptstring "]\n");
for (i = 0; longopts[i].name; ++i) {
int len = printf (" -%c, --%s %s", longopts[i].val, longopts[i].name,
len = printf(" -%c, --%s %s", longopts[i].val, longopts[i].name,
has_arg[longopts[i].has_arg]);
char *lo = xstrdup (longopts_help[i]);
char *p = lo;
char *token;
lo = p = xstrdup(longopts_help[i]);
while ((token = strsep(&p, "\n"))) {
while (++len < 37)
printf(" ");

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>
@ -51,16 +52,14 @@ extern const char *applet;
static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode, int file)
{
struct stat st;
memset (&st, 0, sizeof (st));
int fd;
if (stat(path, &st)) {
if (file) {
int fd;
einfo("%s: creating file", path);
if ((fd = open(path, O_CREAT)) == -1) {
eerror("%s: open: %s", applet, strerror(errno));
return (-1);
return -1;
}
close (fd);
} else {
@ -69,7 +68,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
if (mkdir(path, mode)) {
eerror("%s: mkdir: %s", applet, strerror (errno));
return (-1);
return -1;
}
mode = 0;
}
@ -81,7 +80,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
eerror("%s: is a directory", path);
else
eerror("%s: is a file", path);
return (-1);
return -1;
}
}
@ -89,7 +88,7 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
einfo("%s: correcting mode", applet);
if (chmod(path, mode)) {
eerror("%s: chmod: %s", applet, strerror(errno));
return (-1);
return -1;
}
}
@ -98,31 +97,33 @@ static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode, int file)
einfo("%s: correcting owner", path);
if (chown(path, uid, gid)) {
eerror("%s: chown: %s", applet, strerror(errno));
return (-1);
return -1;
}
}
return (0);
return 0;
}
/* Based on busybox */
static int parse_mode (mode_t *mode, char *text)
{
char *p;
unsigned long l;
/* Check for a numeric mode */
if ((*text - '0') < 8) {
char *p;
unsigned long l = strtoul (text, &p, 8);
l = strtoul(text, &p, 8);
if (*p || l > 07777U) {
errno = EINVAL;
return (-1);
return -1;
}
*mode = (mode_t) l;
return (0);
return 0;
}
/* We currently don't check g+w type stuff */
errno = EINVAL;
return (-1);
return -1;
}
static int parse_owner(struct passwd **user, struct group **group,
@ -155,7 +156,7 @@ static int parse_owner (struct passwd **user, struct group **group,
}
free(u);
return (retval);
return retval;
}
#include "_usage.h"
@ -200,13 +201,11 @@ int checkpath (int argc, char **argv)
break;
case 'm':
if (parse_mode(&mode, optarg) != 0)
eerrorx ("%s: invalid mode `%s'",
applet, optarg);
eerrorx("%s: invalid mode `%s'", applet, optarg);
break;
case 'o':
if (parse_owner(&pw, &gr, optarg) != 0)
eerrorx ("%s: owner `%s' not found",
applet, optarg);
eerrorx("%s: owner `%s' not found", applet, optarg);
break;
case_RC_COMMON_GETOPT

View File

@ -30,6 +30,7 @@
*/
#include <sys/wait.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
@ -72,12 +73,11 @@
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
#ifdef HAVE_GETMNTENT
static struct mntent *getmntfile(const char *file)
{
struct mntent *ent = NULL;
struct mntent *ent;
FILE *fp;
START_ENT;
@ -86,7 +86,7 @@ static struct mntent *getmntfile (const char *file)
break;
END_ENT;
return (ent);
return ent;
}
#endif
@ -108,21 +108,19 @@ static int do_mount (struct ENT *ent)
argv[7] = NULL;
switch (pid = vfork()) {
case -1:
eerrorx ("%s: vfork: %s", applet,
strerror (errno));
eerrorx("%s: vfork: %s", applet, strerror(errno));
/* NOTREACHED */
case 0:
execvp(argv[0], argv);
eerror ("%s: execv: %s", applet,
strerror (errno));
eerror("%s: execv: %s", applet, strerror(errno));
_exit(EXIT_FAILURE);
/* NOTREACHED */
default:
waitpid(pid, &status, 0);
if (WIFEXITED(status))
return (WEXITSTATUS(status));
return WEXITSTATUS(status);
else
return (-1);
return -1;
/* NOTREACHED */
}
}
@ -163,8 +161,8 @@ int fstabinfo (int argc, char **argv)
int i;
int opt;
int output = OUTPUT_FILE;
char **files = NULL;
char *file;
RC_STRINGLIST *files = rc_stringlist_new();
RC_STRING *file;
bool filtered = false;
#ifdef HAVE_GETMNTENT
@ -197,7 +195,8 @@ int fstabinfo (int argc, char **argv)
case '<':
case '>':
if (sscanf(optarg + 1, "%d", &i) != 1)
eerrorx ("%s: invalid passno %s", argv[0], optarg + 1);
eerrorx("%s: invalid passno %s",
argv[0], optarg + 1);
filtered = true;
START_ENT;
@ -206,13 +205,13 @@ int fstabinfo (int argc, char **argv)
(optarg[0] == '<' && i > ENT_PASS(ent)) ||
(optarg[0] == '>' && i < ENT_PASS(ent))) &&
strcmp(ENT_FILE(ent), "none") != 0)
rc_strlist_add (&files, ENT_FILE (ent));
rc_stringlist_add(files, ENT_FILE(ent));
}
END_ENT;
break;
default:
rc_strlist_add (&files, optarg);
rc_stringlist_add(files, optarg);
output = OUTPUT_PASSNO;
break;
}
@ -224,7 +223,7 @@ int fstabinfo (int argc, char **argv)
START_ENT;
while ((ent = GET_ENT))
if (strcmp(token, ENT_TYPE(ent)) == 0)
rc_strlist_add (&files, ENT_FILE (ent));
rc_stringlist_add(files, ENT_FILE(ent));
END_ENT;
}
break;
@ -233,23 +232,23 @@ int fstabinfo (int argc, char **argv)
}
}
if (optind < argc) {
while (optind < argc)
rc_strlist_add (&files, argv[optind++]);
if (! files && ! filtered) {
rc_stringlist_add(files, argv[optind++]);
} else if (! filtered) {
START_ENT;
while ((ent = GET_ENT))
rc_strlist_add (&files, ENT_FILE (ent));
rc_stringlist_add(files, ENT_FILE(ent));
END_ENT;
if (! files)
if (! TAILQ_FIRST(files))
eerrorx("%s: emtpy fstab", argv[0]);
}
/* Ensure we always display something */
START_ENT;
STRLIST_FOREACH (files, file, i) {
if (! (ent = GET_ENT_FILE (file))) {
TAILQ_FOREACH(file, files, entries) {
if (! (ent = GET_ENT_FILE(file->value))) {
result = EXIT_FAILURE;
continue;
}
@ -272,7 +271,7 @@ int fstabinfo (int argc, char **argv)
ENT_OPTS(ent),
ENT_TYPE(ent),
ENT_BLOCKDEVICE(ent),
file);
file->value);
break;
case OUTPUT_OPTIONS:
@ -280,7 +279,7 @@ int fstabinfo (int argc, char **argv)
break;
case OUTPUT_FILE:
printf ("%s\n", file);
printf("%s\n", file->value);
break;
case OUTPUT_PASSNO:
@ -290,7 +289,7 @@ int fstabinfo (int argc, char **argv)
}
END_ENT;
rc_strlist_free (files);
rc_stringlist_free(files);
exit(result);
/* NOTREACHED */
}

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,65 +79,65 @@ struct args {
regex_t *skip_fstype_regex;
regex_t *options_regex;
regex_t *skip_options_regex;
char **mounts;
RC_STRINGLIST *mounts;
mount_type mount_type;
net_opts netdev;
};
static int process_mount (char ***list, struct args *args,
static int process_mount(RC_STRINGLIST *list, struct args *args,
char *from, char *to, char *fstype, char *options,
int netdev)
{
char *p;
RC_STRING *s;
errno = ENOENT;
#ifdef __linux__
/* Skip the really silly rootfs */
if (strcmp(fstype, "rootfs") == 0)
return (-1);
return -1;
#endif
if (args->netdev == net_yes && (netdev != -1 || args->mounts)) {
if (args->netdev == net_yes &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 0)
return (1);
} else if (args->netdev == net_no && (netdev != -1 || args->mounts)) {
return 1;
} else if (args->netdev == net_no &&
(netdev != -1 || TAILQ_FIRST(args->mounts)))
{
if (netdev != 1)
return (1);
return 1;
} else {
if (args->node_regex &&
regexec(args->node_regex, from, 0, NULL, 0) != 0)
return (1);
return 1;
if (args->skip_node_regex &&
regexec(args->skip_node_regex, from, 0, NULL, 0) == 0)
return (1);
return 1;
if (args->fstype_regex &&
regexec(args->fstype_regex, fstype, 0, NULL, 0) != 0)
return (-1);
return -1;
if (args->skip_fstype_regex &&
regexec(args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
return (-1);
return -1;
if (args->options_regex &&
regexec(args->options_regex, options, 0, NULL, 0) != 0)
return (-1);
return -1;
if (args->skip_options_regex &&
regexec(args->skip_options_regex, options, 0, NULL, 0) == 0)
return (-1);
return -1;
}
if (args->mounts) {
bool found = false;
int j;
char *mnt;
STRLIST_FOREACH (args->mounts, mnt, j)
if (strcmp (mnt, to) == 0) {
found = true;
if (TAILQ_FIRST(args->mounts)) {
TAILQ_FOREACH(s, args->mounts, entries)
if (strcmp(s->value, to) == 0)
break;
}
if (! found)
return (-1);
if (! s)
return -1;
}
switch (args->mount_type) {
@ -162,11 +161,11 @@ static int process_mount (char ***list, struct args *args,
if (p) {
errno = 0;
rc_strlist_addsortc (list, p);
return (0);
rc_stringlist_add(list, p);
return 0;
}
return (-1);
return -1;
}
#ifdef BSD
@ -212,21 +211,25 @@ static struct opt {
{ 0, NULL }
};
static char **find_mounts (struct args *args)
static RC_STRINGLIST *find_mounts(struct args *args)
{
struct statfs *mnts;
int nmnts;
int i;
char **list = NULL;
RC_STRINGLIST *list;
char *options = NULL;
uint64_t flags;
struct opt *o;
int netdev;
char *tmp;
size_t l;
if ((nmnts = getmntinfo(&mnts, MNT_NOWAIT)) == 0)
eerrorx("getmntinfo: %s", strerror (errno));
list = rc_stringlist_new();
for (i = 0; i < nmnts; i++) {
int netdev = 0;
netdev = 0;
flags = mnts[i].F_FLAGS & MNT_VISFLAGMASK;
for (o = optnames; flags && o->o_opt; o++) {
if (flags & o->o_opt) {
@ -235,8 +238,7 @@ static char **find_mounts (struct args *args)
if (! options)
options = xstrdup(o->o_name);
else {
char *tmp = NULL;
size_t l = strlen (options) + strlen (o->o_name) + 2;
l = strlen(options) + strlen(o->o_name) + 2;
tmp = xmalloc(sizeof (char) * l);
snprintf(tmp, l, "%s,%s", options, o->o_name);
free(options);
@ -246,7 +248,7 @@ static char **find_mounts (struct args *args)
flags &= ~o->o_opt;
}
process_mount (&list, args,
process_mount(list, args,
mnts[i].f_mntfromname,
mnts[i].f_mntonname,
mnts[i].f_fstypename,
@ -257,7 +259,7 @@ static char **find_mounts (struct args *args)
options = NULL;
}
return (list);
return list;
}
#elif defined (__linux__)
@ -272,10 +274,10 @@ static struct mntent *getmntfile (const char *file)
break;
endmntent(fp);
return (ent);
return ent;
}
static char **find_mounts (struct args *args)
static RC_STRINGLIST *find_mounts(struct args *args)
{
FILE *fp;
char *buffer;
@ -284,13 +286,15 @@ static char **find_mounts (struct args *args)
char *to;
char *fst;
char *opts;
char **list = NULL;
struct mntent *ent;
int netdev;
RC_STRINGLIST *list;
if ((fp = fopen("/proc/mounts", "r")) == NULL)
eerrorx("getmntinfo: %s", strerror(errno));
list = rc_stringlist_new();
buffer = xmalloc(sizeof(char) * PATH_MAX * 3);
while (fgets(buffer, PATH_MAX * 3, fp)) {
netdev = -1;
@ -305,12 +309,12 @@ static char **find_mounts (struct args *args)
netdev = 0;
}
process_mount (&list, args, from, to, fst, opts, netdev);
process_mount(list, args, from, to, fst, opts, netdev);
}
free(buffer);
fclose(fp);
return (list);
return list;
}
#else
@ -329,7 +333,7 @@ static regex_t *get_regex (const char *string)
eerrorx("%s: invalid regex `%s'", applet, buffer);
}
return (reg);
return reg;
}
#include "_usage.h"
@ -371,12 +375,11 @@ static const char * const longopts_help[] = {
int mountinfo(int argc, char **argv)
{
int i;
struct args args;
regex_t *point_regex = NULL;
regex_t *skip_point_regex = NULL;
char **nodes = NULL;
char *n;
RC_STRINGLIST *nodes;
RC_STRING *s;
int opt;
int result;
bool quiet;
@ -393,6 +396,7 @@ int mountinfo (int argc, char **argv)
memset (&args, 0, sizeof(args));
args.mount_type = mount_to;
args.netdev = net_ignore;
args.mounts = rc_stringlist_new();
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
@ -445,10 +449,11 @@ int mountinfo (int argc, char **argv)
while (optind < argc) {
if (argv[optind][0] != '/')
eerrorx("%s: `%s' is not a mount point", argv[0], argv[optind]);
rc_strlist_add (&args.mounts, argv[optind++]);
rc_stringlist_add(args.mounts, argv[optind++]);
}
nodes = find_mounts(&args);
rc_stringlist_free(args.mounts);
rc_stringlist_sort(&nodes);
REG_FREE(args.fstype_regex);
REG_FREE(args.skip_fstype_regex);
@ -457,20 +462,20 @@ int mountinfo (int argc, char **argv)
REG_FREE(args.options_regex);
REG_FREE(args.skip_options_regex);
rc_strlist_reverse (nodes);
result = EXIT_FAILURE;
quiet = rc_yesno(getenv("EINFO_QUIET"));
STRLIST_FOREACH (nodes, n, i) {
if (point_regex && regexec (point_regex, n, 0, NULL, 0) != 0)
TAILQ_FOREACH_REVERSE(s, nodes, rc_stringlist, entries) {
if (point_regex &&
regexec(point_regex, s->value, 0, NULL, 0) != 0)
continue;
if (skip_point_regex && regexec (skip_point_regex, n, 0, NULL, 0) == 0)
if (skip_point_regex &&
regexec(skip_point_regex, s->value, 0, NULL, 0) == 0)
continue;
if (! quiet)
printf ("%s\n", n);
printf("%s\n", s->value);
result = EXIT_SUCCESS;
}
rc_strlist_free (nodes);
rc_stringlist_free(nodes);
REG_FREE(point_regex);
REG_FREE(skip_point_regex);

View File

@ -35,6 +35,7 @@
#define SYSLOG_NAMES
#include <sys/types.h>
#include <errno.h>
#include <ctype.h>
#include <inttypes.h>
@ -49,7 +50,6 @@
#include "builtins.h"
#include "einfo.h"
#include "rc-misc.h"
#include "strlist.h"
/* Applet is first parsed in rc.c - no point in doing it again */
extern const char *applet;
@ -59,13 +59,13 @@ static int syslog_decode (char *name, CODE *codetab)
CODE *c;
if (isdigit((int) *name))
return (atoi (name));
return atoi(name);
for (c = codetab; c->c_name; c++)
if (! strcasecmp(name, c->c_name))
return (c->c_val);
return c->c_val;
return (-1);
return -1;
}
static int do_e(int argc, char **argv)
@ -109,8 +109,8 @@ static int do_e (int argc, char **argv)
}
} else if (strcmp(applet, "esyslog") == 0 ||
strcmp(applet, "elog") == 0) {
char *dot = strchr (argv[0], '.');
if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
p = strchr(argv[0], '.');
if ((level = syslog_decode(p + 1, prioritynames)) == -1)
eerrorx("%s: invalid log level `%s'", applet, argv[0]);
if (argc < 3)
@ -134,8 +134,9 @@ static int do_e (int argc, char **argv)
for (i = 0; i < argc; i++) {
if (i > 0)
*p++ = ' ';
memcpy (p, argv[i], strlen (argv[i]));
p += strlen (argv[i]);
l = strlen(argv[i]);
memcpy(p, argv[i], l);
p += l;
}
*p = 0;
}
@ -193,13 +194,15 @@ static int do_e (int argc, char **argv)
}
free(message);
return (retval);
return retval;
}
static int do_service(int argc, char **argv)
{
bool ok = false;
char *service = NULL;
int idx = 0;
char *d[] = { NULL, NULL };
if (argc > 1)
service = argv[1];
@ -224,8 +227,7 @@ static int do_service (int argc, char **argv)
else if (strcmp(applet, "service_wasinactive") == 0)
ok = (rc_service_state(service) & RC_SERVICE_WASINACTIVE);
else if (strcmp(applet, "service_started_daemon") == 0) {
int idx = 0;
char *d[] = { argv[1], NULL };
d[0] = argv[1];
service = getenv("SVCNAME");
if (argc > 3) {
@ -235,7 +237,7 @@ static int do_service (int argc, char **argv)
} else if (argc == 3) {
if (sscanf(argv[2], "%d", &idx) != 1) {
service = argv[1];
*d = argv[2];
d[0] = argv[2];
}
}
ok = rc_service_started_daemon(service,
@ -244,7 +246,7 @@ static int do_service (int argc, char **argv)
} else
eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_mark_service(int argc, char **argv)
@ -252,6 +254,10 @@ static int do_mark_service (int argc, char **argv)
bool ok = false;
char *svcname = getenv("SVCNAME");
char *service = NULL;
char *runscript_pid;
char *mtime;
pid_t pid;
size_t l;
if (argc > 1)
service = argv[1];
@ -281,11 +287,7 @@ static int do_mark_service (int argc, char **argv)
/* If we're marking ourselves then we need to inform our parent runscript
process so they do not mark us based on our exit code */
if (ok && svcname && strcmp(svcname, service) == 0) {
char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
char *mtime;
pid_t pid = 0;
size_t l;
runscript_pid = getenv("RC_RUNSCRIPT_PID");
if (runscript_pid && sscanf(runscript_pid, "%d", &pid) == 1)
if (kill(pid, SIGHUP) != 0)
eerror("%s: failed to signal parent %d: %s",
@ -293,10 +295,8 @@ static int do_mark_service (int argc, char **argv)
/* Remove the exclusive time test. This ensures that it's not
in control as well */
l = strlen (RC_SVCDIR "exclusive") +
strlen (svcname) +
strlen (runscript_pid) +
4;
l = strlen(RC_SVCDIR "exclusive") + strlen(svcname) +
strlen(runscript_pid) + 4;
mtime = xmalloc(l);
snprintf(mtime, l, RC_SVCDIR "exclusive/%s.%s",
svcname, runscript_pid);
@ -305,13 +305,14 @@ static int do_mark_service (int argc, char **argv)
free(mtime);
}
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_value(int argc, char **argv)
{
bool ok = false;
char *service = getenv("SVCNAME");
char *option;
if (! service)
eerrorx("%s: no service specified", applet);
@ -322,7 +323,7 @@ static int do_value (int argc, char **argv)
if (strcmp(applet, "service_get_value") == 0 ||
strcmp(applet, "get_options") == 0)
{
char *option = rc_service_value_get (service, argv[1]);
option = rc_service_value_get(service, argv[1]);
if (option) {
printf("%s", option);
free(option);
@ -334,34 +335,41 @@ static int do_value (int argc, char **argv)
else
eerrorx("%s: unknown applet", applet);
return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int do_shell_var(int argc, char **argv)
{
int i;
char *p;
int c;
for (i = 1; i < argc; i++) {
char *p = argv[i];
p = argv[i];
if (i != 1)
putchar(' ');
while (*p) {
char c = *p++;
if (! isalnum ((int) c))
c = *p++;
if (! isalnum(c))
c = '_';
putchar(c);
}
}
putchar('\n');
return (EXIT_SUCCESS);
return EXIT_SUCCESS;
}
void run_applets(int argc, char **argv)
{
int i = 2;
bool match = false;
char *p;
pid_t pid = 0;
/* These are designed to be applications in their own right */
if (strcmp(applet, "fstabinfo") == 0)
exit(fstabinfo(argc, argv));
@ -388,9 +396,6 @@ void run_applets (int argc, char **argv)
if (strcmp(applet, "is_newer_than") == 0 ||
strcmp(applet, "is_older_than") == 0)
{
bool match = false;
int i = 2;
if (argc < 3)
exit (EXIT_FAILURE);
if (strcmp(applet, "is_newer_than") == 0)
@ -425,9 +430,7 @@ void run_applets (int argc, char **argv)
exit(rc_runlevel_stopping() ? 0 : 1);
if (strcmp(applet, "rc-abort") == 0) {
char *p = getenv ("RC_PID");
pid_t pid = 0;
p = getenv("RC_PID");
if (p && sscanf(p, "%d", &pid) == 1) {
if (kill(pid, SIGUSR1) != 0)
eerrorx("rc-abort: failed to signal parent %d: %s",

View File

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

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>
@ -108,7 +109,6 @@ cont:
p++;
}
}
static void write_time(FILE *f, const char *s)
{
time_t now = time(NULL);
@ -118,10 +118,11 @@ static void write_time (FILE *f, const char *s)
fflush(f);
}
void rc_logger_close ()
void rc_logger_close(void)
{
if (signal_pipe[1] > -1) {
int sig = SIGTERM;
if (signal_pipe[1] > -1) {
write(signal_pipe[1], &sig, sizeof(sig));
close(signal_pipe[1]);
signal_pipe[1] = -1;
@ -178,7 +179,7 @@ void rc_logger_open (const char *level)
rc_logger_pid = fork();
switch (rc_logger_pid) {
case -1:
eerror ("forkpty: %s", strerror (errno));
eerror("fork: %s", strerror(errno));
break;
case 0:
rc_in_logger = true;
@ -218,7 +219,8 @@ void rc_logger_open (const char *level)
else {
if (logbuf_size - logbuf_len < bytes) {
logbuf_size += BUFSIZ * 10;
logbuf = xrealloc (logbuf, sizeof (char ) *
logbuf = xrealloc(logbuf,
sizeof(char ) *
logbuf_size);
}
@ -251,6 +253,7 @@ void rc_logger_open (const char *level)
exit(0);
/* NOTREACHED */
default:
setpgid(rc_logger_pid, 0);
fd_stdout = dup(STDOUT_FILENO);

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

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,11 +56,10 @@ typedef struct plugin
{
char *name;
void *handle;
int (*hook) (rc_hook_t, const char *);
struct plugin *next;
} plugin_t;
static plugin_t *plugins = NULL;
int (*hook)(RC_HOOK, const char *);
STAILQ_ENTRY(plugin) entries;
} PLUGIN;
STAILQ_HEAD(, plugin) plugins;
#ifndef __FreeBSD__
dlfunc_t dlfunc(void * __restrict handle, const char * __restrict symbol)
@ -71,7 +70,7 @@ dlfunc_t dlfunc (void * __restrict handle, const char * __restrict symbol)
} rv;
rv.d = dlsym(handle, symbol);
return (rv.f);
return rv.f;
}
#endif
@ -79,17 +78,16 @@ void rc_plugin_load (void)
{
DIR *dp;
struct dirent *d;
plugin_t *plugin = plugins;
PLUGIN *plugin;
char *p;
void *h;
int (*fptr) (rc_hook_t, const char *);
int (*fptr)(RC_HOOK, const char *);
/* Don't load plugins if we're in one */
if (rc_in_plugin)
return;
/* Ensure some sanity here */
rc_plugin_unload ();
STAILQ_INIT(&plugins);
if (! (dp = opendir(RC_PLUGINDIR)))
return;
@ -106,21 +104,16 @@ void rc_plugin_load (void)
continue;
}
fptr = (int (*)(rc_hook_t, const char*)) dlfunc (h, RC_PLUGIN_HOOK);
fptr = (int (*)(RC_HOOK, const char*))dlfunc(h, RC_PLUGIN_HOOK);
if (! fptr) {
eerror("%s: cannot find symbol `%s'", d->d_name, RC_PLUGIN_HOOK);
dlclose(h);
} else {
if (plugin) {
plugin->next = xmalloc (sizeof (*plugin->next));
plugin = plugin->next;
} else
plugin = plugins = xmalloc (sizeof (*plugin));
plugin = xmalloc(sizeof(*plugin));
plugin->name = xstrdup(d->d_name);
plugin->handle = h;
plugin->hook = fptr;
plugin->next = NULL;
STAILQ_INSERT_TAIL(&plugins, plugin, entries);
}
}
closedir(dp);
@ -138,16 +131,25 @@ int rc_waitpid (pid_t pid)
retval = WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE;
}
return (retval);
return retval;
}
void rc_plugin_run (rc_hook_t hook, const char *value)
void rc_plugin_run(RC_HOOK hook, const char *value)
{
plugin_t *plugin = plugins;
PLUGIN *plugin;
struct sigaction sa;
sigset_t empty;
sigset_t full;
sigset_t old;
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
int retval;
/* Don't run plugins if we're in one */
if (rc_in_plugin)
@ -160,21 +162,7 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
sigemptyset(&empty);
sigfillset(&full);
while (plugin) {
int i;
int flags;
int pfd[2];
pid_t pid;
char *buffer;
char *token;
char *p;
ssize_t nr;
if (! plugin->hook) {
plugin = plugin->next;
continue;
}
STAILQ_FOREACH(plugin, &plugins, entries) {
/* We create a pipe so that plugins can affect our environment
* vars, which in turn influence our scripts. */
if (pipe(pfd) == -1) {
@ -200,8 +188,6 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
}
if (pid == 0) {
int retval;
/* Restore default handlers */
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
@ -248,21 +234,20 @@ void rc_plugin_run (rc_hook_t hook, const char *value)
close(pfd[0]);
rc_waitpid(pid);
plugin = plugin->next;
}
}
void rc_plugin_unload(void)
{
plugin_t *plugin = plugins;
plugin_t *next;
PLUGIN *plugin = STAILQ_FIRST(&plugins);
PLUGIN *next;
while (plugin) {
next = plugin->next;
next = STAILQ_NEXT(plugin, entries);
dlclose(plugin->handle);
free(plugin->name);
free(plugin);
plugin = next;
}
plugins = NULL;
STAILQ_INIT(&plugins);
}

View File

@ -37,9 +37,9 @@
extern bool rc_in_plugin;
int rc_waitpid(pid_t pid);
void rc_plugin_load ();
void rc_plugin_unload ();
void rc_plugin_run (rc_hook_t, const char *value);
void rc_plugin_load(void);
void rc_plugin_unload(void);
void rc_plugin_run(RC_HOOK, const char *value);
/* dlfunc defines needed to avoid ISO errors. FreeBSD has this right :) */
#ifndef __FreeBSD__

View File

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

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);
if (inone || verbose) {
printf(" %20s |", service->value);
TAILQ_FOREACH(runlevel, in, entries)
printf (" %s", runlevel->value);
printf ("\n");
rc_strlist_free (in);
}
rc_stringlist_free(in);
}
rc_strlist_free (services);
rc_stringlist_free (services);
}
#include "_usage.h"
@ -148,22 +150,23 @@ static const char * const longopts_help[] = {
int rc_update(int argc, char **argv)
{
int i;
RC_STRINGLIST *runlevels;
RC_STRING *runlevel;
char *service = NULL;
char **runlevels = NULL;
char *runlevel;
char *p;
int action = 0;
bool verbose = false;
int opt;
int retval = EXIT_FAILURE;
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
while ((opt = getopt_long(argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case_RC_COMMON_GETOPT
}
}
verbose = rc_yesno(getenv ("EINFO_VERBOSE"));
@ -189,6 +192,8 @@ int rc_update (int argc, char **argv)
if (! action)
action = DOSHOW;
runlevels = rc_stringlist_new();
if (optind >= argc) {
if (! action & DOSHOW)
eerrorx("%s: no service specified", applet);
@ -198,59 +203,69 @@ int rc_update (int argc, char **argv)
while (optind < argc)
if (rc_runlevel_exists(argv[optind]))
rc_strlist_add (&runlevels, argv[optind++]);
rc_stringlist_add(runlevels, argv[optind++]);
else {
rc_strlist_free (runlevels);
eerrorx ("%s: `%s' is not a valid runlevel", applet, argv[optind]);
rc_stringlist_free(runlevels);
eerrorx ("%s: `%s' is not a valid runlevel",
applet, argv[optind]);
}
}
retval = EXIT_SUCCESS;
if (action & DOSHOW) {
if (service)
rc_strlist_add (&runlevels, service);
if (! runlevels)
rc_stringlist_add(runlevels, service);
if (! TAILQ_FIRST(runlevels)) {
free(runlevels);
runlevels = rc_runlevel_list();
}
show (runlevels, verbose);
} else {
if (! service)
eerror ("%s: no service specified", applet);
else {
int num_updated = 0;
int (*actfunc)(const char *, const char *);
int ret;
if (action & DOADD) {
actfunc = add;
} else if (action & DODELETE) {
actfunc = delete;
} else
} else {
rc_stringlist_free(runlevels);
eerrorx ("%s: invalid action", applet);
}
if (! runlevels)
rc_strlist_add (&runlevels, rc_runlevel_get ());
if (! TAILQ_FIRST(runlevels)) {
p = rc_runlevel_get();
rc_stringlist_add(runlevels, p);
free(p);
}
if (! runlevels)
if (! TAILQ_FIRST(runlevels)) {
free(runlevels);
eerrorx ("%s: no runlevels found", applet);
}
STRLIST_FOREACH (runlevels, runlevel, i) {
if (! rc_runlevel_exists (runlevel)) {
eerror ("%s: runlevel `%s' does not exist", applet, runlevel);
TAILQ_FOREACH (runlevel, runlevels, entries) {
if (! rc_runlevel_exists(runlevel->value)) {
eerror ("%s: runlevel `%s' does not exist",
applet, runlevel->value);
continue;
}
ret = actfunc (runlevel, service);
ret = actfunc(runlevel->value, service);
if (ret < 0)
retval = EXIT_FAILURE;
num_updated += ret;
}
if (retval == EXIT_SUCCESS && num_updated == 0 && action & DODELETE)
ewarnx ("%s: service `%s' not found in any of the specified runlevels", applet, service);
if (retval == EXIT_SUCCESS &&
num_updated == 0 && action & DODELETE)
ewarnx("%s: service `%s' not found in any"
" of the specified runlevels",
applet, service);
}
}
rc_strlist_free (runlevels);
return (retval);
rc_stringlist_free(runlevels);
return retval;
}

View File

@ -42,10 +42,18 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sys/wait.h>
/* So we can coldplug net devices */
#ifdef BSD
# include <sys/socket.h>
# include <ifaddrs.h>
#endif
#include <errno.h>
#include <dirent.h>
#include <ctype.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
@ -56,19 +64,12 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include <termios.h>
#include <unistd.h>
/* So we can coldplug net devices */
#ifdef BSD
# include <sys/socket.h>
# include <ifaddrs.h>
#endif
#include "builtins.h"
#include "einfo.h"
#include "rc.h"
#include "rc-logger.h"
#include "rc-misc.h"
#include "rc-plugin.h"
#include "strlist.h"
#include "version.h"
@ -83,39 +84,27 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#define DEVBOOT "/dev/.rcboot"
/* Cleanup anything in main */
#define CHAR_FREE(_item) if (_item) { \
free (_item); \
_item = NULL; \
}
extern char **environ;
static char *RUNLEVEL = NULL;
static char *PREVLEVEL = NULL;
const char *applet = NULL;
static char *runlevel = NULL;
static char **env = NULL;
static char **newenv = NULL;
static char **coldplugged_services = NULL;
static char **stop_services = NULL;
static char **start_services = NULL;
static rc_depinfo_t *deptree = NULL;
static rc_hook_t hook_out = 0;
static char *tmp = NULL;
static RC_STRINGLIST *coldplugged_services = NULL;
static RC_STRINGLIST *stop_services = NULL;
static RC_STRINGLIST *start_services = NULL;
static RC_STRINGLIST *types_n = NULL;
static RC_STRINGLIST *types_nua = NULL;
static RC_DEPTREE *deptree = NULL;
static RC_HOOK hook_out = 0;
struct termios *termios_orig = NULL;
typedef struct pidlist
typedef struct piditem
{
pid_t pid;
struct pidlist *next;
} pidlist_t;
static pidlist_t *service_pids = NULL;
static const char *const types_n[] = { "needsme", NULL };
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
LIST_ENTRY(piditem) entries;
} PIDITEM;
LIST_HEAD(, piditem) service_pids;
static void clean_failed(void)
{
@ -149,7 +138,8 @@ static void clean_failed (void)
static void cleanup(void)
{
if (applet && strcmp(applet, "rc") == 0) {
pidlist_t *pl = service_pids;
PIDITEM *p1 = LIST_FIRST(&service_pids);
PIDITEM *p2;
if (hook_out)
rc_plugin_run(hook_out, runlevel);
@ -161,17 +151,17 @@ static void cleanup (void)
free(termios_orig);
}
while (pl) {
pidlist_t *p = pl->next;
free (pl);
pl = p;
while (p1) {
p2 = LIST_NEXT(p1, entries);
free(p1);
p1 = p2;
}
rc_strlist_free (env);
rc_strlist_free (newenv);
rc_strlist_free (coldplugged_services);
rc_strlist_free (stop_services);
rc_strlist_free (start_services);
rc_stringlist_free(coldplugged_services);
rc_stringlist_free(stop_services);
rc_stringlist_free(start_services);
rc_stringlist_free(types_n);
rc_stringlist_free(types_nua);
rc_deptree_free(deptree);
/* Clean runlevel start, stop markers */
@ -197,11 +187,11 @@ static char *proc_getent (const char *ent)
int i;
if (! exists("/proc/cmdline"))
return (NULL);
return NULL;
if (! (fp = fopen("/proc/cmdline", "r"))) {
eerror("failed to open `/proc/cmdline': %s", strerror(errno));
return (NULL);
return NULL;
}
if ((proc = rc_getline(fp)) &&
@ -219,7 +209,7 @@ static char *proc_getent (const char *ent)
free(proc);
fclose(fp);
return (value);
return value;
}
#endif
@ -230,7 +220,7 @@ static char read_key (bool block)
int fd = fileno(stdin);
if (! isatty(fd))
return (false);
return false;
/* Now save our terminal settings. We need to restore them at exit as we
* will be changing it for non-blocking reads for Interactive */
@ -253,7 +243,7 @@ static char read_key (bool block)
tcsetattr(fd, TCSANOW, termios_orig);
return (c);
return c;
}
static bool want_interactive(void)
@ -263,23 +253,23 @@ static bool want_interactive (void)
static bool interactive;
if (rc_yesno(getenv("EINFO_QUIET")))
return (false);
return false;
if (PREVLEVEL &&
strcmp(PREVLEVEL, "N") != 0 &&
strcmp(PREVLEVEL, "S") != 0 &&
strcmp(PREVLEVEL, "1") != 0)
return (false);
return false;
if (! gotinteractive) {
gotinteractive = true;
interactive = rc_conf_yesno("rc_interactive");
}
if (! interactive)
return (false);
return false;
c = read_key(false);
return ((c == 'I' || c == 'i') ? true : false);
return (c == 'I' || c == 'i') ? true : false;
}
static void mark_interactive(void)
@ -302,17 +292,17 @@ static void sulogin (bool cont)
/* VSERVER and OPENVZ systems cannot do a sulogin */
if (sys && (strcmp(sys, "VSERVER") == 0 || strcmp(sys, "OPENVZ") == 0)) {
execl("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
eerrorx("%s: unable to exec `/sbin/halt': %s",
applet, strerror(errno));
}
#endif
newenv = env_filter ();
if (! cont) {
rc_logger_close();
#ifdef __linux__
execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
execl("/sbin/sulogin", "/sbin/sulogin", (char *) NULL);
eerrorx("%s: unable to exec `/sbin/sulogin': %s",
applet, strerror(errno));
#else
exit(EXIT_SUCCESS);
#endif
@ -345,11 +335,11 @@ static void sulogin (bool cont)
tcsetattr(fileno(stdin), TCSANOW, termios_orig);
#ifdef __linux__
execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
execl(SULOGIN, SULOGIN, (char *) NULL);
eerror("%s: unable to exec `%s': %s", applet, SULOGIN,
strerror(errno));
#else
execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
execl("/bin/sh", "/bin/sh", (char *) NULL);
eerror("%s: unable to exec `/bin/sh': %s", applet,
strerror(errno));
#endif
@ -382,17 +372,17 @@ static bool set_ksoftlevel (const char *level)
if (exists(RC_KSOFTLEVEL) &&
unlink(RC_KSOFTLEVEL) != 0)
eerror("unlink `%s': %s", RC_KSOFTLEVEL, strerror(errno));
return (false);
return false;
}
if (! (fp = fopen(RC_KSOFTLEVEL, "w"))) {
eerror("fopen `%s': %s", RC_KSOFTLEVEL, strerror(errno));
return (false);
return false;
}
fprintf(fp, "%s", level);
fclose(fp);
return (true);
return true;
}
static int get_ksoftlevel(char *buffer, int buffer_len)
@ -401,11 +391,11 @@ static int get_ksoftlevel (char *buffer, int buffer_len)
int i = 0;
if (! exists(RC_KSOFTLEVEL))
return (0);
return 0;
if (! (fp = fopen(RC_KSOFTLEVEL, "r"))) {
eerror("fopen `%s': %s", RC_KSOFTLEVEL, strerror(errno));
return (-1);
return -1;
}
if (fgets(buffer, buffer_len, fp)) {
@ -415,42 +405,29 @@ static int get_ksoftlevel (char *buffer, int buffer_len)
}
fclose(fp);
return (i);
return i;
}
static void add_pid(pid_t pid)
{
pidlist_t *sp = service_pids;
if (sp) {
while (sp->next)
sp = sp->next;
sp->next = xmalloc (sizeof (*sp->next));
sp = sp->next;
} else
sp = service_pids = xmalloc (sizeof (*sp));
memset (sp, 0, sizeof (*sp));
sp->pid = pid;
PIDITEM *p = xmalloc(sizeof(*p));
p->pid = pid;
LIST_INSERT_HEAD(&service_pids, p, entries);
}
static void remove_pid(pid_t pid)
{
pidlist_t *last = NULL;
pidlist_t *pl;
PIDITEM *p;
for (pl = service_pids; pl; pl = pl->next) {
if (pl->pid == pid) {
if (last)
last->next = pl->next;
else
service_pids = pl->next;
free (pl);
break;
}
last = pl;
LIST_FOREACH(p, &service_pids, entries)
if (p->pid == pid) {
LIST_REMOVE(p, entries);
free(p);
return;
}
}
static void wait_for_services ()
static void wait_for_services(void)
{
while (waitpid(0, 0, 0) != -1);
}
@ -459,8 +436,8 @@ static void handle_signal (int sig)
{
int serrno = errno;
char signame[10] = { '\0' };
pidlist_t *pl;
pid_t pid;
PIDITEM *pi;
int status = 0;
struct winsize ws;
sigset_t sset;
@ -510,8 +487,8 @@ static void handle_signal (int sig)
sigprocmask(SIG_BLOCK, &sset, NULL);
/* Kill any running services we have started */
for (pl = service_pids; pl; pl = pl->next)
kill (pl->pid, SIGTERM);
LIST_FOREACH(pi, &service_pids, entries)
kill(pi->pid, SIGTERM);
/* Notify plugins we are aborting */
rc_plugin_run(RC_HOOK_ABORT, NULL);
@ -540,6 +517,7 @@ static void run_script (const char *script)
{
int status = 0;
pid_t pid = vfork();
pid_t wpid;
if (pid < 0)
eerrorx("%s: vfork: %s", applet, strerror(errno));
@ -551,7 +529,7 @@ static void run_script (const char *script)
}
do {
pid_t wpid = waitpid (pid, &status, 0);
wpid = waitpid(pid, &status, 0);
if (wpid < 1)
eerror("waitpid: %s", strerror(errno));
} while (! WIFEXITED(status) && ! WIFSIGNALED(status));
@ -562,14 +540,15 @@ static void run_script (const char *script)
static void do_coldplug(void)
{
size_t s;
int i;
size_t l;
DIR *dp;
struct dirent *d;
char *service;
RC_STRING *s;
#ifdef BSD
struct ifaddrs *ifap;
struct ifaddrs *ifa;
char *p;
#endif
if (! rc_conf_yesno("rc_coldplug") && errno != ENOENT)
@ -585,13 +564,13 @@ static void do_coldplug (void)
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
s = strlen ("net.") + strlen (ifa->ifa_name) + 1;
tmp = xmalloc (sizeof (char) * s);
snprintf (tmp, s, "net.%s", ifa->ifa_name);
if (rc_service_exists (tmp) &&
service_plugable (tmp))
rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
CHAR_FREE (tmp);
l = strlen("net.") + strlen(ifa->ifa_name) + 1;
service = xmalloc(sizeof (char) * l);
snprintf(service, l, "net.%s", ifa->ifa_name);
if (rc_service_exists(service) &&
service_plugable(service))
rc_service_mark(service, RC_SERVICE_COLDPLUGGED);
free(service);
}
freeifaddrs (ifap);
}
@ -603,15 +582,15 @@ static void do_coldplug (void)
if (strncmp(d->d_name, "psm", 3) == 0 ||
strncmp(d->d_name, "ums", 3) == 0)
{
char *p = d->d_name + 3;
p = d->d_name + 3;
if (p && isdigit((int) *p)) {
s = strlen ("moused.") + strlen (d->d_name) + 1;
tmp = xmalloc (sizeof (char) * s);
snprintf (tmp, s, "moused.%s", d->d_name);
if (rc_service_exists (tmp) &&
service_plugable (tmp))
rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
CHAR_FREE (tmp);
l = strlen("moused.") + strlen(d->d_name) + 1;
service = xmalloc(sizeof(char) * l);
snprintf (service, l, "moused.%s", d->d_name);
if (rc_service_exists (service) &&
service_plugable (service))
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
free(service);
}
}
}
@ -635,15 +614,13 @@ static void do_coldplug (void)
service_plugable(d->d_name))
rc_service_mark(d->d_name, RC_SERVICE_COLDPLUGGED);
s = strlen (DEVBOOT "/") + strlen (d->d_name) + 1;
tmp = xmalloc (sizeof (char) * s);
snprintf (tmp, s, DEVBOOT "/%s", d->d_name);
if (tmp) {
if (unlink (tmp))
eerror ("%s: unlink `%s': %s", applet, tmp,
l = strlen(DEVBOOT "/") + strlen(d->d_name) + 1;
service = xmalloc(sizeof (char) * l);
snprintf(service, l, DEVBOOT "/%s", d->d_name);
if (unlink(service))
eerror("%s: unlink `%s': %s", applet, service,
strerror(errno));
free (tmp);
}
free(service);
}
closedir(dp);
rmdir(DEVBOOT);
@ -656,11 +633,29 @@ static void do_coldplug (void)
/* Load our list of coldplugged services and display them */
einfon("Device initiated services:%s", ecolor(ECOLOR_HILITE));
coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
STRLIST_FOREACH (coldplugged_services, service, i)
printf (" %s", service);
TAILQ_FOREACH(s, coldplugged_services, entries)
printf(" %s", s->value);
printf ("%s\n", ecolor(ECOLOR_NORMAL));
}
static bool runlevel_config(const char *service, const char *level)
{
char *init = rc_service_resolve(service);
char *conf;
size_t l;
bool retval;
init = dirname(init);
init = dirname(init);
l = strlen(init) + strlen(level) + strlen(service) + 10;
conf = xmalloc(sizeof(char) * l);
snprintf(conf, l, "%s/conf.d/%s.%s", init, service, level);
retval = exists(conf);
free(conf);
return retval;
}
#include "_usage.h"
#define getoptstring "o:" getoptstring_COMMON
static const struct option longopts[] = {
@ -678,11 +673,9 @@ int main (int argc, char **argv)
const char *bootlevel = NULL;
const char *sys = rc_sys();
char *newlevel = NULL;
char *service = NULL;
char **deporder = NULL;
char **tmplist;
int i = 0;
int j = 0;
RC_STRINGLIST *deporder = NULL;
RC_STRINGLIST *tmplist;
RC_STRING *service;
bool going_down = false;
bool interactive = false;
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
@ -692,8 +685,18 @@ int main (int argc, char **argv)
bool parallel;
int regen = 0;
pid_t pid;
RC_STRING *svc1;
RC_STRING *svc2 = NULL;
struct utsname uts;
#ifdef __linux__
char *cmd;
char *proc;
char *p;
char *token;
#endif
applet = basename_c(argv[0]);
LIST_INIT(&service_pids);
atexit(cleanup);
if (! applet)
eerrorx("arguments required");
@ -727,40 +730,8 @@ int main (int argc, char **argv)
/* Ensure our environment is pure
* Also, add our configuration to it */
env = env_filter ();
tmplist = env_config ();
rc_strlist_join (&env, tmplist);
rc_strlist_free (tmplist);
if (env) {
char *p;
#ifdef __linux__
/* clearenv isn't portable, but there's no harm in using it
* if we have it */
clearenv ();
#else
char *var;
/* No clearenv present here then.
* We could manipulate environ directly ourselves, but it seems that
* some kernels bitch about this according to the environ man pages
* so we walk though environ and call unsetenv for each value. */
while (environ[0]) {
tmp = xstrdup (environ[0]);
p = tmp;
var = strsep (&p, "=");
unsetenv (var);
free (tmp);
}
tmp = NULL;
#endif
STRLIST_FOREACH (env, p, i)
if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
putenv (p);
/* We don't free our list as that would be null in environ */
}
env_filter();
env_config();
argc++;
argv--;
@ -817,12 +788,7 @@ int main (int argc, char **argv)
#endif
)
{
struct utsname uts;
/* OK, we're either in runlevel 1 or single user mode */
#ifdef __linux__
char *cmd;
#endif
/* exec init-early.sh if it exists
* This should just setup the console to use the correct
@ -945,7 +911,7 @@ int main (int argc, char **argv)
{
going_down = true;
rc_runlevel_set(newlevel);
setenv ("RC_SOFTLEVEL", newlevel, 1);
setenv("RC_RUNLEVEL", newlevel, 1);
#ifdef __FreeBSD__
/* FIXME: we shouldn't have todo this */
@ -977,30 +943,33 @@ int main (int argc, char **argv)
if (mkdir(RC_STOPPING, 0755) != 0) {
if (errno == EACCES)
eerrorx("%s: superuser access required", applet);
eerrorx ("%s: failed to create stopping dir: %s",
applet, strerror (errno));
eerrorx("%s: failed to create stopping dir `%s': %s",
applet, RC_STOPPING, strerror(errno));
}
/* Build a list of all services to stop and then work out the
* correct order for stopping them */
stop_services = rc_services_in_state (RC_SERVICE_STARTING);
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
rc_strlist_join (&stop_services, tmplist);
rc_strlist_free (tmplist);
TAILQ_CONCAT(stop_services, tmplist);
free(tmplist);
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
TAILQ_CONCAT(stop_services, tmplist);
free(tmplist);
rc_stringlist_sort(&stop_services);
tmplist = rc_services_in_state (RC_SERVICE_STARTED);
rc_strlist_join (&stop_services, tmplist);
rc_strlist_free (tmplist);
types_n = rc_stringlist_new();
rc_stringlist_add(types_n, "needsme");
deporder = rc_deptree_depends (deptree, types_nua,
(const char **) stop_services,
types_nua = rc_stringlist_new();
rc_stringlist_add(types_nua, "ineed");
rc_stringlist_add(types_nua, "iuse");
rc_stringlist_add(types_nua, "iafter");
tmplist = rc_deptree_depends(deptree, types_nua, stop_services,
runlevel, depoptions | RC_DEP_STOP);
rc_strlist_free (stop_services);
stop_services = deporder;
deporder = NULL;
rc_strlist_reverse (stop_services);
rc_stringlist_free(stop_services);
stop_services = tmplist;
/* Load our list of coldplugged services */
coldplugged_services = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
@ -1012,12 +981,12 @@ int main (int argc, char **argv)
start_services = rc_services_in_runlevel(bootlevel);
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
rc_strlist_join (&start_services, tmplist);
rc_strlist_free (tmplist);
TAILQ_CONCAT(start_services, tmplist);
free(tmplist);
}
STRLIST_FOREACH (coldplugged_services, service, i)
rc_strlist_add (&start_services, service);
TAILQ_FOREACH(service, coldplugged_services, entries)
rc_stringlist_addu(start_services, service->value);
}
/* Save our softlevel now */
@ -1027,87 +996,61 @@ int main (int argc, char **argv)
parallel = rc_conf_yesno("rc_parallel");
/* Now stop the services that shouldn't be running */
STRLIST_FOREACH (stop_services, service, i) {
bool found = false;
char *conf = NULL;
char **stopdeps = NULL;
char *svc1 = NULL;
char *svc2 = NULL;
int k;
if (rc_service_state (service) & RC_SERVICE_STOPPED)
TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) {
if (rc_service_state(service->value) & RC_SERVICE_STOPPED)
continue;
/* We always stop the service when in these runlevels */
if (going_down) {
pid = rc_service_stop (service);
pid = rc_service_stop(service->value);
if (pid > 0 && ! parallel)
rc_waitpid(pid);
continue;
}
/* If we're in the start list then don't bother stopping us */
STRLIST_FOREACH (start_services, svc1, j)
if (strcmp (svc1, service) == 0) {
found = true;
TAILQ_FOREACH(svc1, start_services, entries)
if (strcmp (svc1->value, service->value) == 0)
break;
}
/* Unless we would use a different config file */
if (found) {
size_t len;
if (! newlevel)
continue;
len = strlen (service) + strlen (runlevel) + 2;
tmp = xmalloc (sizeof (char) * len);
snprintf (tmp, len, "%s.%s", service, runlevel);
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
found = exists (conf);
CHAR_FREE (conf);
CHAR_FREE (tmp);
if (! found) {
len = strlen (service) + strlen (newlevel) + 2;
tmp = xmalloc (sizeof (char) * len);
snprintf (tmp, len, "%s.%s", service, newlevel);
conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
found = exists (conf);
CHAR_FREE (conf);
CHAR_FREE (tmp);
if (!found)
if (svc1) {
if (newlevel && strcmp(runlevel, newlevel) != 0) {
/* So we're in the start list. But we should
* be stopped if we have a runlevel
* configuration file for either the current
* or next so we use the correct one. */
if (! runlevel_config(service->value, runlevel) &&
! runlevel_config(service->value, newlevel))
continue;
}
} else {
/* Allow coldplugged services not to be in the runlevels list */
if (rc_service_state (service) & RC_SERVICE_COLDPLUGGED)
else
continue;
}
/* We got this far! Or last check is to see if any any service that
* going to be started depends on us */
rc_strlist_add (&stopdeps, service);
deporder = rc_deptree_depends (deptree, types_n,
(const char **) stopdeps,
/* We got this far! Or last check is to see if any any service
* that going to be started depends on us */
if (! svc1) {
tmplist = rc_stringlist_new();
rc_stringlist_add(tmplist, service->value);
deporder = rc_deptree_depends(deptree, types_n, tmplist,
runlevel, RC_DEP_STRICT);
rc_strlist_free (stopdeps);
stopdeps = NULL;
found = false;
STRLIST_FOREACH (deporder, svc1, j) {
STRLIST_FOREACH (start_services, svc2, k)
if (strcmp (svc1, svc2) == 0) {
found = true;
rc_stringlist_free(tmplist);
svc2 = NULL;
TAILQ_FOREACH (svc1, deporder, entries) {
TAILQ_FOREACH(svc2, start_services, entries)
if (strcmp (svc1->value, svc2->value) == 0)
break;
if (svc2)
break;
}
if (found)
break;
rc_stringlist_free(deporder);
if (svc2)
continue;
}
rc_strlist_free (deporder);
deporder = NULL;
/* After all that we can finally stop the blighter! */
if (! found) {
pid = rc_service_stop (service);
pid = rc_service_stop(service->value);
if (pid > 0) {
add_pid(pid);
if (! parallel) {
@ -1116,7 +1059,6 @@ int main (int argc, char **argv)
}
}
}
}
/* Wait for our services to finish */
wait_for_services();
@ -1132,7 +1074,7 @@ int main (int argc, char **argv)
rc_runlevel_set(newlevel);
free(runlevel);
runlevel = xstrdup(newlevel);
setenv ("RC_SOFTLEVEL", runlevel, 1);
setenv("RC_RUNLEVEL", runlevel, 1);
}
/* Run the halt script if needed */
@ -1157,40 +1099,38 @@ int main (int argc, char **argv)
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
/* Re-add our coldplugged services if they stopped */
STRLIST_FOREACH (coldplugged_services, service, i)
rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
TAILQ_FOREACH(service, coldplugged_services, entries)
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
/* Order the services to start */
deporder = rc_deptree_depends (deptree, types_nua,
(const char **) start_services,
rc_stringlist_sort(&start_services);
deporder = rc_deptree_depends(deptree, types_nua, start_services,
runlevel, depoptions | RC_DEP_START);
rc_strlist_free (start_services);
rc_stringlist_free(start_services);
start_services = deporder;
deporder = NULL;
#ifdef __linux__
/* mark any services skipped as started */
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
if ((service = proc_getent ("noinitd"))) {
char *p = service;
char *token;
proc = p = proc_getent("noinitd");
if (proc) {
while ((token = strsep(&p, ",")))
rc_service_mark(token, RC_SERVICE_STARTED);
free (service);
free(proc);
}
}
#endif
STRLIST_FOREACH (start_services, service, i) {
if (rc_service_state (service) & RC_SERVICE_STOPPED) {
TAILQ_FOREACH(service, start_services, entries) {
if (rc_service_state(service->value) & RC_SERVICE_STOPPED) {
if (! interactive)
interactive = want_interactive();
if (interactive) {
interactive_retry:
printf("\n");
einfo ("About to start the service %s", service);
einfo("About to start the service %s",
service->value);
eindent();
einfo("1) Start the service\t\t2) Skip the service");
einfo("3) Continue boot process\t\t4) Exit to shell");
@ -1205,7 +1145,7 @@ interactive_option:
}
}
pid = rc_service_start (service);
pid = rc_service_start(service->value);
/* Remember the pid if we're running in parallel */
if (pid > 0) {
@ -1228,13 +1168,11 @@ interactive_option:
#ifdef __linux__
/* mark any services skipped as stopped */
if (PREVLEVEL && strcmp(PREVLEVEL, "N") == 0) {
if ((service = proc_getent ("noinitd"))) {
char *p = service;
char *token;
proc = p = proc_getent("noinitd");
if (proc) {
while ((token = strsep(&p, ",")))
rc_service_mark(token, RC_SERVICE_STOPPED);
free (service);
free(proc);
}
}
#endif
@ -1251,8 +1189,8 @@ interactive_option:
* we need to delete them so that they are regenerated again in the
* default runlevel as they may depend on things that are now available */
if (regen && strcmp(runlevel, bootlevel) == 0)
unlink (RC_DEPTREE);
unlink(RC_DEPTREE_CACHE);
return (EXIT_SUCCESS);
return EXIT_SUCCESS;
}

View File

@ -34,6 +34,7 @@
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
@ -60,7 +61,6 @@
#include "rc.h"
#include "rc-misc.h"
#include "rc-plugin.h"
#include "strlist.h"
#define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
@ -75,39 +75,33 @@
#define ONE_SECOND 1000000000
static const char *applet = NULL;
static char **applet_list = NULL;
static RC_STRINGLIST *applet_list = NULL;
static RC_STRINGLIST *restart_services = NULL;
static RC_STRINGLIST *need_services = NULL;
static RC_STRINGLIST *use_services = NULL;
static RC_STRINGLIST *services = NULL;
static RC_STRINGLIST *tmplist = NULL;
static char *service = NULL;
static char *exclusive = NULL;
static char *mtime_test = NULL;
static rc_depinfo_t *deptree = NULL;
static char **services = NULL;
static char **tmplist = NULL;
static char **providelist = NULL;
static char **restart_services = NULL;
static char **need_services = NULL;
static char **use_services = NULL;
static char **env = NULL;
static char *tmp = NULL;
static char *softlevel = NULL;
static RC_DEPTREE *deptree = NULL;
static char *runlevel = NULL;
static bool sighup = false;
static char *ibsave = NULL;
static bool in_background = false;
static rc_hook_t hook_out = 0;
static RC_HOOK hook_out = 0;
static pid_t service_pid = 0;
static char *prefix = NULL;
static bool prefix_locked = false;
static int signal_pipe[2] = { -1, -1 };
static int master_tty = -1;
extern char **environ;
static const char *const types_b[] = { "broken", NULL };
static const char *const types_n[] = { "ineed", NULL };
static const char *const types_nu[] = { "ineed", "iuse", NULL };
static const char *const types_nua[] = { "ineed", "iuse", "iafter", NULL };
static const char *const types_m[] = { "needsme", NULL };
static const char *const types_mua[] = { "needsme", "usesme", "beforeme", NULL };
static RC_STRINGLIST *types_b = NULL;
static RC_STRINGLIST *types_n = NULL;
static RC_STRINGLIST *types_nu = NULL;
static RC_STRINGLIST *types_nua = NULL;
static RC_STRINGLIST *types_m = NULL;
static RC_STRINGLIST *types_mua = NULL;
#ifdef __linux__
static void (*selinux_run_init_old)(void);
@ -203,50 +197,52 @@ static time_t get_mtime (const char *pathname, bool follow_link)
int retval;
if (! pathname)
return (0);
return 0;
retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
if (! retval)
return (buf.st_mtime);
return buf.st_mtime;
errno = 0;
return (0);
return 0;
}
static const char *const tests[] = {
"starting", "started", "stopping", "inactive", "wasinactive", NULL
};
static bool in_control()
{
char *path;
time_t m;
time_t mtime;
const char *tests[] = { "starting", "started", "stopping",
"inactive", "wasinactive", NULL };
int i = 0;
if (sighup)
return (false);
return false;
if (! mtime_test || ! exists(mtime_test))
return (false);
return false;
if (rc_service_state(applet) & RC_SERVICE_STOPPED)
return (false);
return false;
if (! (mtime = get_mtime(mtime_test, false)))
return (false);
return false;
while (tests[i]) {
path = rc_strcatpaths(RC_SVCDIR, tests[i], applet, (char *) NULL);
if (exists(path)) {
time_t m = get_mtime (path, false);
m = get_mtime(path, false);
if (mtime < m && m != 0) {
free(path);
return (false);
return false;
}
}
free(path);
i++;
}
return (true);
return true;
}
static void uncoldplug()
@ -257,10 +253,9 @@ static void uncoldplug ()
free(cold);
}
static void start_services (char **list) {
char *svc;
int i;
rc_service_state_t state = rc_service_state (service);
static void start_services(RC_STRINGLIST *list) {
RC_STRING *svc;
RC_SERVICE state = rc_service_state (service);
if (! list)
return;
@ -270,16 +265,17 @@ static void start_services (char **list) {
state & RC_SERVICE_STARTING ||
state & RC_SERVICE_STARTED)
{
STRLIST_FOREACH (list, svc, i) {
if (rc_service_state (svc) & RC_SERVICE_STOPPED) {
TAILQ_FOREACH(svc, list, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
if (state & RC_SERVICE_INACTIVE ||
state & RC_SERVICE_WASINACTIVE)
{
rc_service_schedule_start (service, svc);
ewarn ("WARNING: %s is scheduled to started when %s has started",
svc, applet);
rc_service_schedule_start(service, svc->value);
ewarn("WARNING: %s is scheduled to started"
" when %s has started",
svc->value, applet);
} else
rc_service_start (svc);
rc_service_start(svc->value);
}
}
}
@ -287,14 +283,13 @@ static void start_services (char **list) {
static void restore_state(void)
{
rc_service_state_t state;
RC_SERVICE state;
if (rc_in_plugin || ! in_control())
return;
state = rc_service_state(applet);
if (state & RC_SERVICE_STOPPING) {
if (state & RC_SERVICE_WASINACTIVE)
rc_service_mark(applet, RC_SERVICE_INACTIVE);
else
@ -335,18 +330,23 @@ static void cleanup (void)
start_services(restart_services);
}
rc_stringlist_free(types_b);
rc_stringlist_free(types_n);
rc_stringlist_free(types_nu);
rc_stringlist_free(types_nua);
rc_stringlist_free(types_m);
rc_stringlist_free(types_mua);
rc_plugin_unload();
rc_deptree_free(deptree);
rc_strlist_free (services);
rc_strlist_free (providelist);
rc_strlist_free (need_services);
rc_strlist_free (use_services);
rc_strlist_free (restart_services);
rc_strlist_free (applet_list);
rc_strlist_free (tmplist);
free (ibsave);
rc_strlist_free (env);
rc_stringlist_free(restart_services);
rc_stringlist_free(need_services);
rc_stringlist_free(use_services);
rc_stringlist_free(services);
rc_stringlist_free(applet_list);
rc_stringlist_free(tmplist);
free (ibsave);
if (mtime_test)
{
@ -357,7 +357,7 @@ static void cleanup (void)
free(exclusive);
free(service);
free(prefix);
free (softlevel);
free(runlevel);
}
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
@ -385,7 +385,7 @@ static int write_prefix (const char *buffer, size_t bytes, bool *prefixed) {
ret += write(fd, buffer + i, 1);
}
return (ret);
return ret;
}
static bool svc_exec(const char *arg1, const char *arg2)
@ -501,34 +501,32 @@ static bool svc_exec (const char *arg1, const char *arg2)
execok = rc_waitpid(service_pid) == 0 ? true : false;
service_pid = 0;
return (execok);
return execok;
}
static bool svc_wait (rc_depinfo_t *depinfo, const char *svc)
static bool svc_wait(const char *svc)
{
char *s;
char *fifo;
char fifo[PATH_MAX];
struct timespec ts;
int nloops = WAIT_MAX * (ONE_SECOND / WAIT_INTERVAL);
bool retval = false;
bool forever = false;
char **keywords = NULL;
int i;
if (! service)
return (false);
RC_STRINGLIST *keywords;
RC_STRING *s;
/* Some services don't have a timeout, like fsck */
keywords = rc_deptree_depend (depinfo, svc, "keyword");
STRLIST_FOREACH (keywords, s, i) {
if (strcmp (s, "notimeout") == 0) {
keywords = rc_deptree_depend(deptree, svc, "keyword");
if (keywords) {
TAILQ_FOREACH(s, keywords, entries) {
if (strcmp (s->value, "notimeout") == 0) {
forever = true;
break;
}
}
rc_strlist_free (keywords);
rc_stringlist_free (keywords);
}
fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename_c (svc), (char *) NULL);
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", basename_c(svc));
ts.tv_sec = 0;
ts.tv_nsec = WAIT_INTERVAL;
@ -549,16 +547,14 @@ static bool svc_wait (rc_depinfo_t *depinfo, const char *svc)
if (! exists(fifo))
retval = true;
free (fifo);
return (retval);
return retval;
}
static rc_service_state_t svc_status ()
static RC_SERVICE svc_status(void)
{
char status[10];
int (*e) (const char *fmt, ...) = &einfo;
rc_service_state_t state = rc_service_state (service);
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_STOPPING) {
snprintf(status, sizeof(status), "stopping");
@ -570,7 +566,7 @@ static rc_service_state_t svc_status ()
snprintf(status, sizeof(status), "inactive");
e = &ewarn;
} else if (state & RC_SERVICE_STARTED) {
if (geteuid () == 0 && rc_service_daemons_crashed (service)) {
if (rc_service_daemons_crashed(service)) {
snprintf(status, sizeof (status), "crashed");
e = &eerror;
} else
@ -579,10 +575,10 @@ static rc_service_state_t svc_status ()
snprintf(status, sizeof(status), "stopped");
e("status: %s", status);
return (state);
return state;
}
static void make_exclusive ()
static void make_exclusive(void)
{
char *path;
size_t l;
@ -618,7 +614,7 @@ static void make_exclusive ()
}
}
static void unlink_mtime_test ()
static void unlink_mtime_test(void)
{
if (unlink(mtime_test) != 0)
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
@ -626,27 +622,54 @@ static void unlink_mtime_test ()
mtime_test = NULL;
}
static void get_started_services ()
static void get_started_services(void)
{
rc_strlist_free (tmplist);
tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
rc_strlist_free (restart_services);
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
rc_stringlist_free(restart_services);
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
rc_strlist_join (&restart_services, tmplist);
rc_strlist_free (tmplist);
tmplist = NULL;
TAILQ_CONCAT(restart_services, tmp);
free(tmp);
}
static void setup_types(void)
{
types_b = rc_stringlist_new();
rc_stringlist_add(types_b, "broken");
types_n = rc_stringlist_new();
rc_stringlist_add(types_n, "ineed");
types_nu = rc_stringlist_new();
rc_stringlist_add(types_nu, "ineed");
rc_stringlist_add(types_nu, "iuse");
types_nua = rc_stringlist_new();
rc_stringlist_add(types_nua, "ineed");
rc_stringlist_add(types_nua, "iuse");
rc_stringlist_add(types_nua, "iafter");
types_m = rc_stringlist_new();
rc_stringlist_add(types_m, "needsme");
types_mua = rc_stringlist_new();
rc_stringlist_add(types_mua, "needsme");
rc_stringlist_add(types_mua, "usesme");
rc_stringlist_add(types_mua, "beforeme");
}
static void svc_start(bool deps)
{
bool started;
bool background = false;
char *svc;
char *svc2;
int i;
int j;
RC_STRING *svc;
RC_STRING *svc2;
int depoptions = RC_DEP_TRACE;
rc_service_state_t state;
RC_SERVICE state;
bool first;
int n;
size_t len;
char *p;
char *tmp;
state = rc_service_state(service);
@ -673,7 +696,7 @@ static void svc_start (bool deps)
eerrorx("ERROR: %s has been started by something else", applet);
}
make_exclusive (service);
make_exclusive();
hook_out = RC_HOOK_SERVICE_START_OUT;
rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet);
@ -685,52 +708,48 @@ static void svc_start (bool deps)
if (! deptree && ((deptree = _rc_deptree_load (NULL)) == NULL))
eerrorx("failed to load deptree");
rc_strlist_free (services);
services = rc_deptree_depends (deptree, types_b,
(const char * const *) applet_list,
softlevel, 0);
if (services) {
if (! types_b)
setup_types();
services = rc_deptree_depends(deptree, types_b, applet_list,
runlevel, 0);
if (TAILQ_FIRST(services)) {
eerrorn ("ERROR: `%s' needs ", applet);
STRLIST_FOREACH (services, svc, i) {
if (i > 0)
first = true;
TAILQ_FOREACH(svc, services, entries) {
if (first)
first = false;
else
fprintf(stderr, ", ");
fprintf (stderr, "%s", svc);
fprintf(stderr, "%s", svc->value);
}
exit(EXIT_FAILURE);
}
rc_strlist_free (services);
rc_stringlist_free(services);
services = NULL;
rc_strlist_free (need_services);
need_services = rc_deptree_depends (deptree, types_n,
(const char * const *) applet_list,
softlevel, depoptions);
need_services = rc_deptree_depends(deptree, types_n, applet_list,
runlevel, depoptions);
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
runlevel, depoptions);
rc_strlist_free (use_services);
use_services = rc_deptree_depends (deptree, types_nu,
(const char * const *) applet_list,
softlevel, depoptions);
if (! rc_runlevel_starting ()) {
STRLIST_FOREACH (use_services, svc, i)
if (rc_service_state (svc) & RC_SERVICE_STOPPED) {
pid_t pid = rc_service_start (svc);
if (! rc_runlevel_starting())
TAILQ_FOREACH(svc, use_services, entries)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
pid_t pid = rc_service_start(svc->value);
if (! rc_conf_yesno("rc_parallel"))
rc_waitpid(pid);
}
}
/* Now wait for them to start */
services = rc_deptree_depends (deptree, types_nua,
(const char * const *) applet_list,
softlevel, depoptions);
services = rc_deptree_depends(deptree, types_nua, applet_list,
runlevel, depoptions);
/* We use tmplist to hold our scheduled by list */
rc_strlist_free (tmplist);
tmplist = NULL;
tmplist = rc_stringlist_new();
STRLIST_FOREACH (services, svc, i) {
rc_service_state_t svcs = rc_service_state (svc);
TAILQ_FOREACH(svc, services, entries) {
RC_SERVICE svcs = rc_service_state(svc->value);
if (svcs & RC_SERVICE_STARTED)
continue;
@ -738,71 +757,70 @@ static void svc_start (bool deps)
* starting state which we are after */
if (svcs & RC_SERVICE_STARTING &&
svcs & RC_SERVICE_WASINACTIVE) {
bool use = false;
STRLIST_FOREACH (use_services, svc2, j)
if (strcmp (svc, svc2) == 0) {
use = true;
TAILQ_FOREACH(svc2, use_services, entries) {
if (strcmp (svc->value, svc2->value) == 0)
break;
}
if (! use)
if (! svc2)
continue;
}
if (! svc_wait (deptree, svc))
eerror ("%s: timed out waiting for %s", applet, svc);
if ((svcs = rc_service_state (svc)) & RC_SERVICE_STARTED)
if (! svc_wait(svc->value))
eerror ("%s: timed out waiting for %s",
applet, svc->value);
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
continue;
STRLIST_FOREACH (need_services, svc2, j)
if (strcmp (svc, svc2) == 0) {
TAILQ_FOREACH(svc2, need_services, entries) {
if (strcmp (svc->value, svc2->value) == 0) {
if (svcs & RC_SERVICE_INACTIVE ||
svcs & RC_SERVICE_WASINACTIVE)
rc_strlist_add (&tmplist, svc);
rc_stringlist_add(tmplist, svc->value);
else
eerrorx ("ERROR: cannot start %s as %s would not start",
applet, svc);
eerrorx("ERROR: cannot start %s as"
" %s would not start",
applet, svc->value);
}
}
}
if (tmplist) {
int n = 0;
size_t len = 0;
char *p;
if (TAILQ_FIRST(tmplist)) {
/* Set the state now, then unlink our exclusive so that
our scheduled list is preserved */
rc_service_mark(service, RC_SERVICE_STOPPED);
unlink_mtime_test();
STRLIST_FOREACH (tmplist, svc, i) {
rc_service_schedule_start (svc, service);
rc_strlist_free (providelist);
providelist = rc_deptree_depend (deptree, "iprovide", svc);
STRLIST_FOREACH (providelist, svc2, j)
rc_service_schedule_start (svc2, service);
len += strlen (svc) + 2;
rc_stringlist_free(use_services);
use_services = NULL;
len = 0;
n = 0;
TAILQ_FOREACH(svc, tmplist, entries) {
rc_service_schedule_start(svc->value, service);
use_services = rc_deptree_depend(deptree, "iprovide",
svc->value);
TAILQ_FOREACH (svc2, use_services, entries)
rc_service_schedule_start(svc2->value, service);
rc_stringlist_free(use_services);
use_services = NULL;
len += strlen(svc->value) + 2;
n++;
}
len += 5;
tmp = xmalloc (sizeof (char) * len);
p = tmp;
STRLIST_FOREACH (tmplist, svc, i) {
if (i > 1) {
if (i == n)
p += snprintf (p, len, " or ");
else
tmp = p = xmalloc(sizeof(char) * len);
TAILQ_FOREACH(svc, tmplist, entries) {
if (p != tmp)
p += snprintf(p, len, ", ");
p += snprintf(p, len, "%s", svc->value);
}
p += snprintf (p, len, "%s", svc);
}
free(tmp);
ewarnx("WARNING: %s is scheduled to start when %s has started",
applet, tmp);
}
rc_strlist_free (services);
rc_stringlist_free(services);
services = NULL;
rc_stringlist_free(tmplist);
tmplist = NULL;
}
if (ibsave)
@ -832,24 +850,30 @@ static void svc_start (bool deps)
unlink(exclusive);
/* Now start any scheduled services */
rc_strlist_free (services);
services = rc_services_scheduled(service);
STRLIST_FOREACH (services, svc, i)
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
rc_service_start (svc);
rc_strlist_free (services);
if (services) {
TAILQ_FOREACH(svc, services, entries)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
rc_service_start(svc->value);
rc_stringlist_free(services);
services = NULL;
}
/* Do the same for any services we provide */
rc_strlist_free (tmplist);
tmplist = rc_deptree_depend(deptree, "iprovide", applet);
STRLIST_FOREACH (tmplist, svc2, j) {
rc_strlist_free (services);
services = rc_services_scheduled (svc2);
STRLIST_FOREACH (services, svc, i)
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
rc_service_start (svc);
if (tmplist) {
TAILQ_FOREACH(svc, tmplist, entries) {
services = rc_services_scheduled(svc->value);
if (services) {
TAILQ_FOREACH(svc2, services, entries)
if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED)
rc_service_start(svc2->value);
rc_stringlist_free(services);
services = NULL;
}
}
rc_stringlist_free(tmplist);
tmplist = NULL;
}
hook_out = 0;
@ -859,7 +883,9 @@ static void svc_start (bool deps)
static void svc_stop(bool deps)
{
bool stopped;
rc_service_state_t state = rc_service_state (service);
RC_SERVICE state = rc_service_state(service);
int depoptions = RC_DEP_TRACE;
RC_STRING *svc;
if (rc_runlevel_stopping() &&
state & RC_SERVICE_FAILED)
@ -882,7 +908,7 @@ static void svc_stop (bool deps)
eerrorx("ERROR: %s has been stopped by something else", applet);
}
make_exclusive (service);
make_exclusive();
hook_out = RC_HOOK_SERVICE_STOP_OUT;
rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet);
@ -892,9 +918,6 @@ static void svc_stop (bool deps)
ewarn ("WARNING: you are stopping a boot service");
if (deps && ! (state & RC_SERVICE_WASINACTIVE)) {
int depoptions = RC_DEP_TRACE;
char *svc;
int i;
if (rc_conf_yesno("rc_depend_strict"))
depoptions |= RC_DEP_STRICT;
@ -902,69 +925,67 @@ static void svc_stop (bool deps)
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
eerrorx ("failed to load deptree");
rc_strlist_free (tmplist);
tmplist = NULL;
rc_strlist_free (services);
services = rc_deptree_depends (deptree, types_m,
(const char * const *) applet_list,
softlevel, depoptions);
rc_strlist_reverse (services);
STRLIST_FOREACH (services, svc, i) {
rc_service_state_t svcs = rc_service_state (svc);
if (! types_m)
setup_types();
tmplist = rc_stringlist_new();
services = rc_deptree_depends(deptree, types_m, applet_list,
runlevel, depoptions);
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
RC_SERVICE svcs = rc_service_state(svc->value);
if (svcs & RC_SERVICE_STARTED ||
svcs & RC_SERVICE_INACTIVE)
{
svc_wait (deptree, svc);
svcs = rc_service_state (svc);
svc_wait(svc->value);
svcs = rc_service_state(svc->value);
if (svcs & RC_SERVICE_STARTED ||
svcs & RC_SERVICE_INACTIVE)
{
pid_t pid = rc_service_stop (svc);
pid_t pid = rc_service_stop(svc->value);
if (! rc_conf_yesno("rc_parallel"))
rc_waitpid(pid);
rc_strlist_add (&tmplist, svc);
rc_stringlist_add(tmplist, svc->value);
}
}
}
rc_strlist_free (services);
rc_stringlist_free(services);
services = NULL;
STRLIST_FOREACH (tmplist, svc, i) {
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
TAILQ_FOREACH(svc, tmplist, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
/* We used to loop 3 times here - maybe re-do this if needed */
svc_wait (deptree, svc);
if (! (rc_service_state (svc) & RC_SERVICE_STOPPED)) {
svc_wait(svc->value);
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
if (rc_runlevel_stopping()) {
/* If shutting down, we should stop even if a dependant failed */
if (softlevel &&
(strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp (softlevel, RC_LEVEL_REBOOT) == 0 ||
strcmp (softlevel, RC_LEVEL_SINGLE) == 0))
/* If shutting down, we should stop even
* if a dependant failed */
if (runlevel &&
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
continue;
rc_service_mark(service, RC_SERVICE_FAILED);
}
eerrorx("ERROR: cannot stop %s as %s is still up",
applet, svc);
applet, svc->value);
}
}
rc_strlist_free (tmplist);
rc_stringlist_free(tmplist);
tmplist = NULL;
/* We now wait for other services that may use us and are stopping
This is important when a runlevel stops */
services = rc_deptree_depends (deptree, types_mua,
(const char * const *) applet_list,
softlevel, depoptions);
STRLIST_FOREACH (services, svc, i) {
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
services = rc_deptree_depends(deptree, types_mua, applet_list,
runlevel, depoptions);
TAILQ_FOREACH(svc, services, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
svc_wait (deptree, svc);
svc_wait(svc->value);
}
rc_strlist_free (services);
rc_stringlist_free (services);
services = NULL;
}
@ -1012,7 +1033,7 @@ static void svc_restart (bool deps)
our status is invalid.
One workaround would be to introduce a new status, or status locking. */
if (! deps) {
rc_service_state_t state = rc_service_state (service);
RC_SERVICE state = rc_service_state(service);
if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
svc_exec("stop", "start");
else
@ -1027,7 +1048,7 @@ static void svc_restart (bool deps)
svc_start(deps);
start_services(restart_services);
rc_strlist_free (restart_services);
rc_stringlist_free(restart_services);
restart_services = NULL;
}
@ -1050,13 +1071,17 @@ static const char * const longopts_help[] = {
int runscript(int argc, char **argv)
{
size_t i;
bool deps = true;
bool doneone = false;
char pid[16];
int retval;
int opt;
char *svc;
RC_STRING *svc;
char dir[PATH_MAX];
size_t l = 0;
size_t ll;
char *save;
int depoptions = RC_DEP_TRACE;
/* Show help if insufficient args */
if (argc < 2 || ! exists(argv[1])) {
@ -1071,11 +1096,10 @@ int runscript (int argc, char **argv)
if (*argv[1] == '/')
service = xstrdup(argv[1]);
else {
char d[PATH_MAX];
getcwd (d, sizeof (d));
i = strlen (d) + strlen (argv[1]) + 2;
service = xmalloc (sizeof (char) * i);
snprintf (service, i, "%s/%s", d, argv[1]);
getcwd(dir, sizeof(dir));
l = strlen(dir) + strlen(argv[1]) + 2;
service = xmalloc(sizeof (char) * l);
snprintf(service, l, "%s/%s", dir, argv[1]);
}
atexit(cleanup);
@ -1090,50 +1114,16 @@ int runscript (int argc, char **argv)
eerror("%s: cannot run until sysvinit completes", applet);
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
symlink (service, tmp);
prefix = rc_strcatpaths("/dev/.rcboot", applet, (char *) NULL);
symlink(service, prefix);
exit (EXIT_FAILURE);
}
#endif
if ((softlevel = xstrdup (getenv ("RC_SOFTLEVEL"))) == NULL) {
/* Ensure our environment is pure
Also, add our configuration to it */
char *p;
env = env_filter ();
if (env) {
#ifdef __linux__
/* clearenv isn't portable, but there's no harm in using it
if we have it */
clearenv ();
#else
char *var;
/* No clearenv present here then.
We could manipulate environ directly ourselves, but it seems that
some kernels bitch about this according to the environ man pages
so we walk though environ and call unsetenv for each value. */
while (environ[0]) {
tmp = xstrdup (environ[0]);
p = tmp;
var = strsep (&p, "=");
unsetenv (var);
free (tmp);
}
tmp = NULL;
#endif
}
tmplist = env_config ();
rc_strlist_join (&env, tmplist);
rc_strlist_free (tmplist);
tmplist = NULL;
STRLIST_FOREACH (env, p, i)
putenv (p);
/* We don't free our list as that would be null in environ */
softlevel = rc_runlevel_get ();
if ((runlevel = xstrdup (getenv ("RC_RUNLEVEL"))) == NULL) {
env_filter();
env_config();
runlevel = rc_runlevel_get();
}
setenv("EINFO_LOG", service, 1);
@ -1147,13 +1137,10 @@ int runscript (int argc, char **argv)
/* eprefix is kinda klunky, but it works for our purposes */
if (rc_conf_yesno("rc_parallel")) {
size_t l = 0;
size_t ll;
/* Get the longest service name */
services = rc_services_in_runlevel(NULL);
STRLIST_FOREACH (services, svc, i) {
ll = strlen (svc);
TAILQ_FOREACH(svc, services, entries) {
ll = strlen(svc->value);
if (ll > l)
l = ll;
}
@ -1177,8 +1164,7 @@ int runscript (int argc, char **argv)
argv++;
/* Right then, parse any options there may be */
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1)
switch (opt) {
case 'd':
setenv("RC_DEBUG", "yes", 1);
@ -1216,6 +1202,9 @@ int runscript (int argc, char **argv)
/* Load our plugins */
rc_plugin_load();
applet_list = rc_stringlist_new();
rc_stringlist_add(applet_list, applet);
/* Now run each option */
retval = EXIT_SUCCESS;
while (optind < argc) {
@ -1233,13 +1222,11 @@ int runscript (int argc, char **argv)
setenv("RC_CMD", optarg, 1);
doneone = true;
rc_strlist_add (&applet_list, applet);
if (strcmp (optarg, "describe") == 0 ||
strcmp (optarg, "help") == 0)
{
char *save = prefix;
save = prefix;
eprefix(NULL);
prefix = NULL;
svc_exec(optarg, NULL);
@ -1252,27 +1239,26 @@ int runscript (int argc, char **argv)
strcmp(optarg, "ibefore") == 0 ||
strcmp(optarg, "iprovide") == 0)
{
int depoptions = RC_DEP_TRACE;
if (rc_conf_yesno("rc_depend_strict"))
depoptions |= RC_DEP_STRICT;
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
eerrorx("failed to load deptree");
rc_strlist_free (services);
rc_strlist_free (tmplist);
rc_strlist_add (&tmplist, optarg);
services = rc_deptree_depends (deptree,
(const char * const *) tmplist,
(const char * const *) applet_list,
softlevel, depoptions);
STRLIST_FOREACH (services, svc, i)
printf ("%s%s", i == 1 ? "" : " ", svc);
if (services)
tmplist = rc_stringlist_new();
rc_stringlist_add(tmplist, optarg);
services = rc_deptree_depends(deptree, tmplist, applet_list,
runlevel, depoptions);
rc_stringlist_free(tmplist);
tmplist = NULL;
TAILQ_FOREACH(svc, services, entries)
printf("%s ", svc->value);
if (TAILQ_FIRST(services))
printf ("\n");
rc_stringlist_free(services);
services = NULL;
} else if (strcmp (optarg, "status") == 0) {
rc_service_state_t r = svc_status (service);
RC_SERVICE r = svc_status();
retval = (int) r;
if (retval & RC_SERVICE_STARTED)
retval = 0;
@ -1301,10 +1287,9 @@ int runscript (int argc, char **argv)
if (in_background &&
rc_service_state(service) & RC_SERVICE_INACTIVE)
{
int j;
STRLIST_FOREACH (restart_services, svc, j)
if (rc_service_state (svc) & RC_SERVICE_STOPPED)
rc_service_schedule_start (service, svc);
TAILQ_FOREACH(svc, restart_services, entries)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
rc_service_schedule_start(service, svc->value);
}
}
} else if (strcmp(optarg, "zap") == 0) {
@ -1315,7 +1300,7 @@ int runscript (int argc, char **argv)
svc_exec(optarg, NULL);
/* We should ensure this list is empty after an action is done */
rc_strlist_free (restart_services);
rc_stringlist_free(restart_services);
restart_services = NULL;
}
@ -1323,5 +1308,5 @@ int runscript (int argc, char **argv)
usage(EXIT_FAILURE);
}
return (retval);
return retval;
}

View File

@ -46,6 +46,7 @@
#include <sys/termios.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@ -71,40 +72,38 @@ static struct pam_conv conv = { NULL, NULL};
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
typedef struct schedulelist
typedef struct scheduleitem
{
enum
{
schedule_timeout,
schedule_signal,
schedule_goto,
schedule_forever
SC_TIMEOUT,
SC_SIGNAL,
SC_GOTO,
SC_FOREVER
} type;
int value;
struct schedulelist *gotolist;
struct schedulelist *next;
} schedulelist_t;
static schedulelist_t *schedule;
struct scheduleitem *gotoitem;
STAILQ_ENTRY(scheduleitem) entries;
} SCHEDULEITEM;
STAILQ_HEAD(, scheduleitem) schedule;
extern const char *applet;
static char *changeuser;
static char **newenv;
extern char **environ;
static void free_schedulelist (schedulelist_t **list)
static void free_schedulelist(void)
{
schedulelist_t *here;
schedulelist_t *next;
SCHEDULEITEM *s1 = STAILQ_FIRST(&schedule);
SCHEDULEITEM *s2;
for (here = *list; here; here = next) {
next = here->next;
free (here);
while (s1) {
s2 = STAILQ_NEXT(s1, entries);
free(s1);
s1 = s2;
}
*list = NULL;
STAILQ_INIT(&schedule);
}
static void cleanup(void)
@ -112,11 +111,7 @@ static void cleanup (void)
if (changeuser)
free(changeuser);
if (schedule)
free_schedulelist (&schedule);
if (newenv)
rc_strlist_free (newenv);
free_schedulelist();
}
static int parse_signal(const char *sig)
@ -125,9 +120,9 @@ static int parse_signal (const char *sig)
{
const char *name;
int signal;
} signalpair_t;
} SIGNALPAIR;
static const signalpair_t signallist[] = {
static const SIGNALPAIR signallist[] = {
{ "ABRT", SIGABRT },
{ "ALRM", SIGALRM },
{ "FPE", SIGFPE },
@ -153,11 +148,11 @@ static int parse_signal (const char *sig)
const char *s;
if (! sig || *sig == '\0')
return (-1);
return -1;
if (sscanf(sig, "%u", &i) == 1) {
if (i > 0 && i < sizeof(signallist) / sizeof(signallist[0]))
return (i);
return i;
eerrorx("%s: `%s' is not a valid signal", applet, sig);
}
@ -169,21 +164,24 @@ static int parse_signal (const char *sig)
for (i = 0; i < sizeof(signallist) / sizeof(signallist[0]); i++)
if (strcmp(sig, signallist[i].name) == 0 ||
(s && strcmp(s, signallist[i].name) == 0))
return (signallist[i].signal);
return signallist[i].signal;
eerrorx("%s: `%s' is not a valid signal", applet, sig);
/* NOTREACHED */
}
static void parse_schedule_item (schedulelist_t *item, const char *string)
static SCHEDULEITEM *parse_schedule_item(const char *string)
{
const char *after_hyph;
int sig;
SCHEDULEITEM *item = xmalloc(sizeof(*item));
item->value = 0;
item->gotoitem = NULL;
if (strcmp(string,"forever") == 0)
item->type = schedule_forever;
item->type = SC_FOREVER;
else if (isdigit((int) string[0])) {
item->type = schedule_timeout;
item->type = SC_TIMEOUT;
errno = 0;
if (sscanf(string, "%d", &item->value) != 1)
eerrorx("%s: invalid timeout value in schedule `%s'", applet,
@ -191,52 +189,51 @@ static void parse_schedule_item (schedulelist_t *item, const char *string)
} else if ((after_hyph = string + (string[0] == '-')) &&
((sig = parse_signal(after_hyph)) != -1))
{
item->type = schedule_signal;
item->type = SC_SIGNAL;
item->value = (int)sig;
}
else
eerrorx("%s: invalid schedule item `%s'", applet, string);
return item;
}
static void parse_schedule (const char *string, int default_signal)
static void parse_schedule(const char *string, int timeout)
{
char buffer[20];
const char *slash;
int count = 0;
schedulelist_t *repeatat = NULL;
SCHEDULEITEM *repeatat = NULL;
size_t len;
schedulelist_t *next;
SCHEDULEITEM *item;
if (string)
for (slash = string; *slash; slash++)
if (*slash == '/')
count++;
if (schedule)
free_schedulelist (&schedule);
schedule = xmalloc (sizeof (*schedule));
schedule->gotolist = NULL;
free_schedulelist();
if (count == 0) {
schedule->type = schedule_signal;
schedule->value = default_signal;
schedule->next = xmalloc (sizeof (*schedule->next));
next = schedule->next;
next->type = schedule_timeout;
next->gotolist = NULL;
item = xmalloc(sizeof(*item));
item->type = SC_SIGNAL;
item->value = timeout;
item->gotoitem = NULL;
STAILQ_INSERT_TAIL(&schedule, item, entries);
item = xmalloc(sizeof(*item));
item->type = SC_TIMEOUT;
item->gotoitem = NULL;
STAILQ_INSERT_TAIL(&schedule, item, entries);
if (string) {
if (sscanf (string, "%d", &next->value) != 1)
if (sscanf(string, "%d", &item->value) != 1)
eerrorx("%s: invalid timeout value in schedule", applet);
}
else
next->value = 5;
next->next = NULL;
} else
item->value = 5;
return;
}
next = schedule;
while (string != NULL) {
if ((slash = strchr(string, '/')))
len = slash - string;
@ -250,32 +247,26 @@ static void parse_schedule (const char *string, int default_signal)
buffer[len] = 0;
string = slash ? slash + 1 : NULL;
parse_schedule_item (next, buffer);
if (next->type == schedule_forever) {
item = parse_schedule_item(buffer);
STAILQ_INSERT_TAIL(&schedule, item, entries);
if (item->type == SC_FOREVER) {
if (repeatat)
eerrorx ("%s: invalid schedule, `forever' appears more than once",
applet);
eerrorx("%s: invalid schedule, `forever' "
"appears more than once", applet);
repeatat = next;
repeatat = item;
continue;
}
if (string) {
next->next = xmalloc (sizeof (*next->next));
next = next->next;
next->gotolist = NULL;
}
}
if (repeatat) {
next->next = xmalloc (sizeof (*next->next));
next = next->next;
next->type = schedule_goto;
next->value = 0;
next->gotolist = repeatat;
item = xmalloc(sizeof(*item));
item->type = SC_GOTO;
item->value = 0;
item->gotoitem = repeatat;
STAILQ_INSERT_TAIL(&schedule, item, entries);
}
next->next = NULL;
return;
}
@ -285,23 +276,24 @@ static pid_t get_pid (const char *pidfile, bool quiet)
pid_t pid;
if (! pidfile)
return (-1);
return -1;
if ((fp = fopen(pidfile, "r")) == NULL) {
if (! quiet)
eerror("%s: fopen `%s': %s", applet, pidfile, strerror(errno));
return (-1);
return -1;
}
if (fscanf(fp, "%d", &pid) != 1) {
if (! quiet)
eerror("%s: no pid found in `%s'", applet, pidfile);
fclose(fp);
return (-1);
return -1;
}
fclose(fp);
return (pid);
return pid;
}
/* return number of processed killed, -1 on error */
@ -317,13 +309,13 @@ static int do_stop (const char *const *argv, const char *cmd,
if (pidfile) {
if ((pid = get_pid(pidfile, quiet)) == -1)
return (quiet ? 0 : -1);
return quiet ? 0 : -1;
pids = rc_find_pids(NULL, NULL, 0, pid);
} else
pids = rc_find_pids(argv, cmd, uid, pid);
if (! pids)
return (0);
return 0;
for (i = 0; pids[i]; i++) {
if (test) {
@ -349,14 +341,14 @@ static int do_stop (const char *const *argv, const char *cmd,
}
free(pids);
return (nkilled);
return nkilled;
}
static int run_stop_schedule(const char *const *argv, const char *cmd,
const char *pidfile, uid_t uid,
bool quiet, bool verbose, bool test)
{
schedulelist_t *item = schedule;
SCHEDULEITEM *item = STAILQ_FIRST(&schedule);
int nkilled = 0;
int tkilled = 0;
int nrunning = 0;
@ -376,27 +368,28 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
while (item) {
switch (item->type) {
case schedule_goto:
item = item->gotolist;
case SC_GOTO:
item = item->gotoitem;
continue;
case schedule_signal:
case SC_SIGNAL:
nrunning = 0;
nkilled = do_stop(argv, cmd, pidfile, uid, item->value,
quiet, verbose, test);
if (nkilled == 0) {
if (tkilled == 0) {
if (! quiet)
eerror ("%s: no matching processes found", applet);
eerror("%s: no matching "
"processes found", applet);
}
return (tkilled);
return tkilled;
}
else if (nkilled == -1)
return (0);
return 0;
tkilled += nkilled;
break;
case schedule_timeout:
case SC_TIMEOUT:
if (item->value < 1) {
item = NULL;
break;
@ -409,14 +402,15 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
while (nloops) {
if ((nrunning = do_stop(argv, cmd, pidfile,
uid, 0, true, false, true)) == 0)
return (true);
return true;
if (nanosleep(&ts, NULL) == -1) {
if (errno == EINTR)
eerror("%s: caught an interrupt", applet);
else {
eerror ("%s: nanosleep: %s", applet, strerror (errno));
return (0);
eerror("%s: nanosleep: %s",
applet, strerror(errno));
return 0;
}
}
nloops --;
@ -425,15 +419,15 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
default:
eerror("%s: invalid schedule item `%d'", applet, item->type);
return (0);
return 0;
}
if (item)
item = item->next;
item = STAILQ_NEXT(item, entries);
}
if (test || (tkilled > 0 && nrunning == 0))
return (nkilled);
return nkilled;
if (! quiet) {
if (nrunning == 1)
@ -442,7 +436,7 @@ static int run_stop_schedule (const char *const *argv, const char *cmd,
eerror("%s: %d process(es) refused to stop", applet, nrunning);
}
return (-nrunning);
return -nrunning;
}
static void handle_signal(int sig)
@ -575,19 +569,30 @@ int start_stop_daemon (int argc, char **argv)
pid_t pid;
int i;
char *svcname = getenv("SVCNAME");
char *env;
RC_STRINGLIST *env_list;
RC_STRING *env;
char *path;
bool sethome = false;
bool setuser = false;
char *p;
char *tmp;
struct passwd *pw;
struct group *gr;
char line[130];
FILE *fp;
size_t len;
STAILQ_INIT(&schedule);
atexit(cleanup);
signal_setup(SIGINT, handle_signal);
signal_setup(SIGQUIT, handle_signal);
signal_setup(SIGTERM, handle_signal);
if ((env = getenv ("SSD_NICELEVEL")))
if (sscanf (env, "%d", &nicelevel) != 1)
eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env);
if ((path = getenv("SSD_NICELEVEL")))
if (sscanf(path, "%d", &nicelevel) != 1)
eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)",
applet, path);
while ((opt = getopt_long(argc, argv, "e:" getoptstring, longopts,
(int *) 0)) != -1)
@ -616,33 +621,30 @@ int start_stop_daemon (int argc, char **argv)
case 'u': /* --user <username>|<uid> */
case 'c': /* --chuid <username>|<uid> */
{
char *p = optarg;
char *cu = strsep (&p, ":");
struct passwd *pw = NULL;
changeuser = xstrdup (cu);
if (sscanf (cu, "%d", &tid) != 1)
pw = getpwnam (cu);
p = optarg;
tmp = strsep(&p, ":");
changeuser = xstrdup(tmp);
if (sscanf(tmp, "%d", &tid) != 1)
pw = getpwnam(tmp);
else
pw = getpwuid((uid_t) tid);
if (! pw)
eerrorx ("%s: user `%s' not found", applet, cu);
eerrorx("%s: user `%s' not found", applet, tmp);
uid = pw->pw_uid;
if (! gid)
gid = pw->pw_gid;
if (p) {
struct group *gr = NULL;
char *cg = strsep (&p, ":");
if (sscanf (cg, "%d", &tid) != 1)
gr = getgrnam (cg);
tmp = strsep (&p, ":");
if (sscanf(tmp, "%d", &tid) != 1)
gr = getgrnam(tmp);
else
gr = getgrgid((gid_t) tid);
if (! gr)
eerrorx ("%s: group `%s' not found", applet, cg);
eerrorx("%s: group `%s' not found",
applet, tmp);
gid = gr->gr_gid;
}
}
@ -663,8 +665,6 @@ int start_stop_daemon (int argc, char **argv)
case 'g': /* --group <group>|<gid> */
{
struct group *gr = getgrnam (optarg);
if (sscanf(optarg, "%d", &tid) != 1)
gr = getgrnam(optarg);
else
@ -759,7 +759,6 @@ int start_stop_daemon (int argc, char **argv)
/* Validate that the binary exists if we are starting */
if (exec) {
char *tmp;
if (ch_root)
tmp = rc_strcatpaths(ch_root, exec, (char *) NULL);
else
@ -774,15 +773,13 @@ int start_stop_daemon (int argc, char **argv)
/* If we don't have a pidfile or name, check it's not
* interpreted, otherwise we should fail */
if (! pidfile && ! cmd) {
char line[130];
FILE *fp = fopen (tmp, "r");
fp = fopen (tmp, "r");
if (fp) {
fgets(line, sizeof(line), fp);
fclose(fp);
if (line[0] == '#' && line[1] == '!') {
size_t len = strlen (line) - 1;
len = strlen (line) - 1;
/* Remove the trailing newline */
if (line[len] == '\n')
@ -790,12 +787,12 @@ int start_stop_daemon (int argc, char **argv)
eerror("%s: %s is a script",
applet, exec);
eerror ("%s: and should be started, stopped or signalled with ",
applet);
eerror("%s: and should be started, stopped"
" or signalled with ", applet);
eerror("%s: --exec %s %s",
applet, line + 2, exec);
eerror ("%s: or you should specify a pidfile or process name",
applet);
eerror("%s: or you should specify a pidfile"
" or process name", applet);
if (ch_root)
free(tmp);
exit(EXIT_FAILURE);
@ -813,7 +810,7 @@ int start_stop_daemon (int argc, char **argv)
if (stop) {
int result;
if (! schedule) {
if (! STAILQ_FIRST(&schedule)) {
if (test || oknodo)
parse_schedule("0", sig);
else
@ -828,7 +825,7 @@ int start_stop_daemon (int argc, char **argv)
exit(EXIT_FAILURE);
if (test || oknodo)
return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
return result > 0 ? EXIT_SUCCESS : EXIT_FAILURE;
/* Even if we have not actually killed anything, we should
* remove information about it as it may have unexpectedly
@ -872,10 +869,6 @@ int start_stop_daemon (int argc, char **argv)
exit(EXIT_SUCCESS);
}
/* Ensure this is unset, so if the daemon does /etc/init.d/foo
Then we filter the environment accordingly */
unsetenv ("RC_SOFTLEVEL");
if (verbose) {
ebegin("Detaching to start `%s'", exec);
eindent();
@ -910,10 +903,10 @@ int start_stop_daemon (int argc, char **argv)
eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));
if (makepidfile && pidfile) {
FILE *fp = fopen (pidfile, "w");
fp = fopen(pidfile, "w");
if (! fp)
eerrorx ("%s: fopen `%s': %s", applet, pidfile, strerror
(errno));
eerrorx("%s: fopen `%s': %s", applet, pidfile,
strerror(errno));
fprintf(fp, "%d\n", mypid);
fclose(fp);
}
@ -941,17 +934,17 @@ int start_stop_daemon (int argc, char **argv)
if (uid && setuid(uid))
eerrorx ("%s: unable to set userid to %d", applet, uid);
else {
struct passwd *passwd = getpwuid (uid);
if (passwd) {
pw = getpwuid(uid);
if (pw) {
if (! sethome) {
unsetenv("HOME");
if (passwd->pw_dir)
setenv ("HOME", passwd->pw_dir, 1);
if (pw->pw_dir)
setenv("HOME", pw->pw_dir, 1);
}
if (! setuser) {
unsetenv("USER");
if (passwd->pw_name)
setenv ("USER", passwd->pw_name, 1);
if (pw->pw_name)
setenv("USER", pw->pw_name, 1);
}
}
}
@ -965,48 +958,46 @@ int start_stop_daemon (int argc, char **argv)
#endif
/* Clean the environment of any RC_ variables */
STRLIST_FOREACH (environ, env, i) {
if ((strncmp (env, "RC_", 3) == 0 &&
strncmp (env, "RC_SERVICE=", strlen ("RC_SERVICE=")) != 0) ||
strncmp (env, "SSD_NICELEVEL=", strlen ("SSD_NICELEVEL=")) == 0)
env_list = rc_stringlist_new();
i = 0;
while(environ[i])
rc_stringlist_add(env_list, environ[i++]);
TAILQ_FOREACH(env, env_list, entries) {
if ((strncmp(env->value, "RC_", 3) == 0 &&
strncmp(env->value, "RC_SERVICE=", strlen("RC_SERVICE=")) != 0) ||
strncmp(env->value, "SSD_NICELEVEL=", strlen("SSD_NICELEVEL=")) == 0)
{
p = strchr(env->value, '=');
*p = '\0';
unsetenv(env->value);
continue;
}
}
rc_stringlist_free(env_list);
/* For the path, remove the rcscript bin dir from it */
if (strncmp (env, "PATH=", 5) == 0) {
char *path = xstrdup (env);
char *newpath = NULL;
char *p = path;
if ((path = getenv("PATH"))) {
size_t mx = strlen(path);
char *newpath = xmalloc(mx);
char *token;
char *np;
char *np = newpath;
size_t l;
int t;
p += 5;
p = path;
while ((token = strsep (&p, ":"))) {
if (strcmp (token, RC_LIBDIR "/bin") == 0 ||
strcmp (token, RC_LIBDIR "/sbin") == 0)
continue;
t = strlen (token);
if (newpath) {
l = strlen (newpath);
newpath = xrealloc (newpath, sizeof (char) * (l + t + 2));
np = newpath + l;
l = strlen (token);
if (np != newpath)
*np++ = ':';
memcpy (np, token, sizeof (char) * strlen (token));
np += t;
memcpy (np, token, l);
np += l;
*np = '\0';
} else {
l = strlen ("PATH=") + t + 1;
newpath = xmalloc (sizeof (char) * l);
snprintf (newpath, l, "PATH=%s", token);
}
}
rc_strlist_add (&newenv, newpath);
free (path);
free (newpath);
} else
rc_strlist_add (&newenv, env);
unsetenv("PATH");
setenv("PATH", newpath, 1);
}
umask(022);
@ -1036,8 +1027,7 @@ int start_stop_daemon (int argc, char **argv)
close(i);
setsid();
execve (exec, argv, newenv);
execv(exec, argv);
#ifdef HAVE_PAM
if (pamr == PAM_SUCCESS)
pam_close_session(pamh, PAM_SILENT);
@ -1056,7 +1046,7 @@ int start_stop_daemon (int argc, char **argv)
pid = waitpid(savepid, &status, 0);
if (pid < 1) {
eerror("waitpid %d: %s", savepid, strerror(errno));
return (-1);
return -1;
}
} while (! WIFEXITED(status) && ! WIFSIGNALED(status));
@ -1086,7 +1076,7 @@ int start_stop_daemon (int argc, char **argv)
eerror("%s: caught an interrupt", applet);
else {
eerror("%s: nanosleep: %s", applet, strerror(errno));
return (0);
return 0;
}
}
@ -1130,7 +1120,8 @@ int start_stop_daemon (int argc, char **argv)
}
if (svcname)
rc_service_daemon_set (svcname, (const char *const *)argv, cmd, pidfile, true);
rc_service_daemon_set(svcname, (const char *const *)argv,
cmd, pidfile, true);
exit(EXIT_SUCCESS);
/* NOTREACHED */