2007-04-05 16:48:42 +05:30
|
|
|
/*
|
|
|
|
librc-depend
|
|
|
|
rc service dependency and ordering
|
|
|
|
*/
|
|
|
|
|
2008-01-14 10:35:22 +05:30
|
|
|
/*
|
2008-03-26 23:23:37 +05:30
|
|
|
* Copyright 2007-2008 Roy Marples <roy@marples.name>
|
2007-11-14 20:52:04 +05:30
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2007-04-13 19:38:16 +05:30
|
|
|
#include "librc.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-08-15 20:19:41 +05:30
|
|
|
#define GENDEP RC_LIBDIR "/sh/gendepends.sh"
|
|
|
|
|
|
|
|
#define RC_DEPCONFIG RC_SVCDIR "/depconfig"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
static const char *bootlevel = NULL;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static char *get_shell_value(char *string)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-07-21 18:19:51 +05:30
|
|
|
char *p = string;
|
|
|
|
char *e;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
if (! string)
|
2008-03-16 22:30:56 +05:30
|
|
|
return NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
if (*p == '\'')
|
|
|
|
p++;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
e = p + strlen(p) - 1;
|
2007-07-21 18:19:51 +05:30
|
|
|
if (*e == '\n')
|
|
|
|
*e-- = 0;
|
|
|
|
if (*e == '\'')
|
|
|
|
*e-- = 0;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
if (*p != 0)
|
|
|
|
return p;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
void rc_deptree_free(RC_DEPTREE *deptree)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPINFO *di;
|
|
|
|
RC_DEPINFO *di2;
|
|
|
|
RC_DEPTYPE *dt;
|
|
|
|
RC_DEPTYPE *dt2;
|
|
|
|
|
|
|
|
if (! deptree)
|
|
|
|
return;
|
|
|
|
|
|
|
|
di = STAILQ_FIRST(deptree);
|
2007-07-21 18:19:51 +05:30
|
|
|
while (di)
|
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
di2 = STAILQ_NEXT(di, entries);
|
|
|
|
dt = STAILQ_FIRST(&di->depends);
|
2007-07-21 18:19:51 +05:30
|
|
|
while (dt)
|
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
dt2 = STAILQ_NEXT(dt, entries);
|
|
|
|
rc_stringlist_free(dt->services);
|
|
|
|
free(dt->type);
|
|
|
|
free(dt);
|
|
|
|
dt = dt2;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
free(di->service);
|
|
|
|
free(di);
|
|
|
|
di = di2;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
free(deptree);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2007-09-29 22:12:08 +05:30
|
|
|
librc_hidden_def(rc_deptree_free)
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_DEPINFO *get_depinfo(const RC_DEPTREE *deptree,
|
|
|
|
const char *service)
|
2007-11-22 16:55:08 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPINFO *di;
|
2007-11-22 16:55:08 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_FOREACH(di, deptree, entries)
|
|
|
|
if (strcmp(di->service, service) == 0)
|
|
|
|
return di;
|
2007-11-22 16:55:08 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return NULL;
|
2007-11-22 16:55:08 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_DEPTYPE *get_deptype(const RC_DEPINFO *depinfo,
|
|
|
|
const char *type)
|
2007-11-22 16:55:08 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPTYPE *dt;
|
2007-11-22 16:55:08 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_FOREACH(dt, &depinfo->depends, entries)
|
|
|
|
if (strcmp(dt->type, type) == 0)
|
|
|
|
return dt;
|
2007-11-22 16:55:08 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return NULL;
|
2007-11-22 16:55:08 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPTREE *rc_deptree_load(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-07-21 18:19:51 +05:30
|
|
|
FILE *fp;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPTREE *deptree;
|
|
|
|
RC_DEPINFO *depinfo = NULL;
|
|
|
|
RC_DEPTYPE *deptype = NULL;
|
2008-03-18 02:57:37 +05:30
|
|
|
char *line = NULL;
|
|
|
|
size_t len = 0;
|
2007-07-21 18:19:51 +05:30
|
|
|
char *type;
|
|
|
|
char *p;
|
|
|
|
char *e;
|
|
|
|
int i;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (!(fp = fopen(RC_DEPTREE_CACHE, "r")))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
deptree = xmalloc(sizeof(*deptree));
|
|
|
|
STAILQ_INIT(deptree);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-18 02:57:37 +05:30
|
|
|
while ((rc_getline(&line, &len, fp)))
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-01-07 17:59:30 +05:30
|
|
|
p = line;
|
2008-03-16 22:30:56 +05:30
|
|
|
e = strsep(&p, "_");
|
|
|
|
if (! e || strcmp(e, "depinfo") != 0)
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
e = strsep (&p, "_");
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! e || sscanf(e, "%d", &i) != 1)
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! (type = strsep(&p, "_=")))
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(type, "service") == 0)
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
|
|
|
/* Sanity */
|
2008-03-16 22:30:56 +05:30
|
|
|
e = get_shell_value(p);
|
2008-01-21 21:00:40 +05:30
|
|
|
if (! e || *e == '\0')
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
depinfo = xmalloc(sizeof(*depinfo));
|
|
|
|
STAILQ_INIT(&depinfo->depends);
|
|
|
|
depinfo->service = xstrdup(e);
|
|
|
|
STAILQ_INSERT_TAIL(deptree, depinfo, entries);
|
2007-07-21 18:19:51 +05:30
|
|
|
deptype = NULL;
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
e = strsep(&p, "=");
|
|
|
|
if (! e || sscanf(e, "%d", &i) != 1)
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Sanity */
|
2008-03-16 22:30:56 +05:30
|
|
|
e = get_shell_value(p);
|
2008-01-21 21:00:40 +05:30
|
|
|
if (! e || *e == '\0')
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! deptype || strcmp(deptype->type, type) != 0) {
|
|
|
|
deptype = xmalloc(sizeof(*deptype));
|
|
|
|
deptype->services = rc_stringlist_new();
|
2007-10-08 16:46:22 +05:30
|
|
|
deptype->type = xstrdup (type);
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries);
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(deptype->services, e);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
fclose(fp);
|
2008-03-18 02:57:37 +05:30
|
|
|
free(line);
|
2008-03-16 22:30:56 +05:30
|
|
|
|
|
|
|
return deptree;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2007-09-29 22:12:08 +05:30
|
|
|
librc_hidden_def(rc_deptree_load)
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static bool valid_service(const char *runlevel, const char *service)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state = rc_service_state(service);
|
2007-09-28 20:23:38 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
return ((strcmp (runlevel, bootlevel) != 0 &&
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_in_runlevel(service, bootlevel)) ||
|
|
|
|
rc_service_in_runlevel(service, runlevel) ||
|
2008-01-11 21:21:40 +05:30
|
|
|
state & RC_SERVICE_COLDPLUGGED ||
|
|
|
|
state & RC_SERVICE_STARTED);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static bool get_provided1(const char *runlevel, RC_STRINGLIST *providers,
|
|
|
|
RC_DEPTYPE *deptype,
|
|
|
|
const char *level, bool coldplugged,
|
|
|
|
RC_SERVICE state)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRING *service;
|
|
|
|
RC_SERVICE st;
|
2007-07-21 18:19:51 +05:30
|
|
|
bool retval = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
bool ok;
|
|
|
|
const char *svc;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(service, deptype->services, entries) {
|
|
|
|
ok = true;
|
|
|
|
svc = service->value;
|
|
|
|
st = rc_service_state(svc);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
if (level)
|
2008-03-16 22:30:56 +05:30
|
|
|
ok = rc_service_in_runlevel(svc, level);
|
2007-07-21 18:19:51 +05:30
|
|
|
else if (coldplugged)
|
2008-03-16 22:30:56 +05:30
|
|
|
ok = (st & RC_SERVICE_COLDPLUGGED &&
|
|
|
|
! rc_service_in_runlevel(svc, runlevel) &&
|
|
|
|
! rc_service_in_runlevel(svc, bootlevel));
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
if (! ok)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (state) {
|
2007-09-28 17:59:23 +05:30
|
|
|
case RC_SERVICE_STARTED:
|
2008-03-16 22:30:56 +05:30
|
|
|
ok = (st & RC_SERVICE_STARTED);
|
2007-07-21 18:19:51 +05:30
|
|
|
break;
|
2007-09-28 17:59:23 +05:30
|
|
|
case RC_SERVICE_INACTIVE:
|
|
|
|
case RC_SERVICE_STARTING:
|
|
|
|
case RC_SERVICE_STOPPING:
|
2008-03-16 22:30:56 +05:30
|
|
|
ok = (st & RC_SERVICE_STARTING ||
|
|
|
|
st & RC_SERVICE_STOPPING ||
|
|
|
|
st & RC_SERVICE_INACTIVE);
|
2007-07-21 18:19:51 +05:30
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! ok)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
retval = true;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(providers, svc);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Work out if a service is provided by another service.
|
|
|
|
For example metalog provides logger.
|
|
|
|
We need to be able to handle syslogd providing logger too.
|
|
|
|
We do this by checking whats running, then what's starting/stopping,
|
|
|
|
then what's run in the runlevels and finally alphabetical order.
|
|
|
|
|
|
|
|
If there are any bugs in rc-depend, they will probably be here as
|
|
|
|
provided dependancy can change depending on runlevel state.
|
|
|
|
*/
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_STRINGLIST *get_provided (const RC_DEPINFO *depinfo,
|
|
|
|
const char *runlevel, int options)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPTYPE *dt;
|
|
|
|
RC_STRINGLIST *providers = rc_stringlist_new();
|
|
|
|
RC_STRING *service;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
dt = get_deptype(depinfo, "providedby");
|
2007-07-21 18:19:51 +05:30
|
|
|
if (! dt)
|
2008-03-16 22:30:56 +05:30
|
|
|
return providers;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* If we are stopping then all depends are true, regardless of state.
|
|
|
|
This is especially true for net services as they could force a restart
|
|
|
|
of the local dns resolver which may depend on net. */
|
|
|
|
if (options & RC_DEP_STOP)
|
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(service, dt->services, entries)
|
|
|
|
rc_stringlist_add(providers, service->value);
|
|
|
|
return providers;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-02-04 04:57:16 +05:30
|
|
|
/* If we're strict or startng, then only use what we have in our
|
|
|
|
* runlevel and bootlevel. If we starting then check cold-plugged too. */
|
|
|
|
if (options & RC_DEP_STRICT || options & RC_DEP_START)
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
|
|
|
|
TAILQ_FOREACH(service, dt->services, entries)
|
|
|
|
if (rc_service_in_runlevel(service->value, runlevel) ||
|
|
|
|
rc_service_in_runlevel(service->value, bootlevel) ||
|
2008-02-04 04:57:16 +05:30
|
|
|
(options & RC_DEP_START &&
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_state(service->value) & RC_SERVICE_COLDPLUGGED))
|
|
|
|
rc_stringlist_add(providers, service->value);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (TAILQ_FIRST(providers))
|
|
|
|
return providers;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* OK, we're not strict or there were no services in our runlevel.
|
|
|
|
This is now where the logic gets a little fuzzy :)
|
|
|
|
If there is >1 running service then we return NULL.
|
|
|
|
We do this so we don't hang around waiting for inactive services and
|
|
|
|
our need has already been satisfied as it's not strict.
|
|
|
|
We apply this to our runlevel, coldplugged services, then bootlevel
|
|
|
|
and finally any running.*/
|
|
|
|
#define DO \
|
2008-03-16 22:30:56 +05:30
|
|
|
if (TAILQ_FIRST(providers)) { \
|
|
|
|
if (TAILQ_NEXT(TAILQ_FIRST(providers), entries)) { \
|
|
|
|
rc_stringlist_free(providers); \
|
|
|
|
providers = rc_stringlist_new(); \
|
|
|
|
} \
|
|
|
|
return providers; \
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Anything in the runlevel has to come first */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTED))
|
2007-07-21 18:19:51 +05:30
|
|
|
{ DO }
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTING))
|
|
|
|
return providers;
|
|
|
|
if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED))
|
|
|
|
return providers;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Check coldplugged services */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTED))
|
2007-07-21 18:19:51 +05:30
|
|
|
{ DO }
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTING))
|
|
|
|
return providers;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Check bootlevel if we're not in it */
|
|
|
|
if (bootlevel && strcmp (runlevel, bootlevel) != 0)
|
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTED))
|
2007-07-21 18:19:51 +05:30
|
|
|
{ DO }
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTING))
|
|
|
|
return providers;
|
2007-07-03 03:35:38 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* Check coldplugged services */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STOPPED))
|
2007-08-16 22:23:20 +05:30
|
|
|
{ DO }
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-08-16 22:23:20 +05:30
|
|
|
/* Check manually started */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, NULL, false, RC_SERVICE_STARTED))
|
2007-08-16 22:23:20 +05:30
|
|
|
{ DO }
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, NULL, false, RC_SERVICE_STARTING))
|
|
|
|
return providers;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* Nothing started then. OK, lets get the stopped services */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED))
|
|
|
|
return providers;
|
2007-07-03 03:35:38 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
if (bootlevel && (strcmp (runlevel, bootlevel) != 0)
|
2008-03-16 22:30:56 +05:30
|
|
|
&& (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STOPPED)))
|
|
|
|
return providers;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* Still nothing? OK, list all services */
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(service, dt->services, entries)
|
|
|
|
rc_stringlist_add(providers, service->value);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return providers;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
static void visit_service(const RC_DEPTREE *deptree,
|
|
|
|
const RC_STRINGLIST *types,
|
|
|
|
RC_STRINGLIST **sorted,
|
|
|
|
RC_STRINGLIST *visited,
|
|
|
|
const RC_DEPINFO *depinfo,
|
|
|
|
const char *runlevel, int options)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRING *type;
|
|
|
|
RC_STRING *service;
|
|
|
|
RC_DEPTYPE *dt;
|
|
|
|
RC_DEPINFO *di;
|
|
|
|
RC_STRINGLIST *provided;
|
|
|
|
RC_STRING *p;
|
|
|
|
const char *svcname;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Check if we have already visited this service or not */
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(type, visited, entries)
|
|
|
|
if (strcmp(type->value, depinfo->service) == 0)
|
2007-07-21 18:19:51 +05:30
|
|
|
return;
|
|
|
|
|
|
|
|
/* Add ourselves as a visited service */
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(visited, depinfo->service);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(type, types, entries)
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
if (!(dt = get_deptype(depinfo, type->value)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(service, dt->services, entries) {
|
|
|
|
if (! options & RC_DEP_TRACE ||
|
|
|
|
strcmp(type->value, "iprovide") == 0)
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-03-17 18:55:56 +05:30
|
|
|
if (! *sorted)
|
|
|
|
*sorted = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(*sorted, service->value);
|
2008-03-16 22:30:56 +05:30
|
|
|
continue;
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (!(di = get_depinfo(deptree, service->value)))
|
|
|
|
continue;
|
|
|
|
provided = get_provided(di, runlevel, options);
|
|
|
|
|
|
|
|
if (TAILQ_FIRST(provided)) {
|
|
|
|
TAILQ_FOREACH(p, provided, entries) {
|
|
|
|
di = get_depinfo(deptree, p->value);
|
|
|
|
if (di &&
|
|
|
|
(strcmp(type->value, "ineed") == 0 ||
|
|
|
|
strcmp(type->value, "needsme") == 0 ||
|
|
|
|
valid_service(runlevel, di->service)))
|
|
|
|
visit_service(deptree, types, sorted, visited, di,
|
|
|
|
runlevel, options | RC_DEP_TRACE);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
else if (di &&
|
|
|
|
(strcmp(type->value, "ineed") == 0 ||
|
|
|
|
strcmp(type->value, "needsme") == 0 ||
|
|
|
|
valid_service(runlevel, service->value)))
|
|
|
|
visit_service(deptree, types, sorted, visited, di,
|
|
|
|
runlevel, options | RC_DEP_TRACE);
|
|
|
|
|
|
|
|
rc_stringlist_free(provided);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now visit the stuff we provide for */
|
2007-09-29 22:12:08 +05:30
|
|
|
if (options & RC_DEP_TRACE &&
|
2008-03-16 22:30:56 +05:30
|
|
|
(dt = get_deptype(depinfo, "iprovide")))
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(service, dt->services, entries) {
|
|
|
|
if (!(di = get_depinfo(deptree, service->value)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
provided = get_provided(di, runlevel, options);
|
|
|
|
TAILQ_FOREACH(p, provided, entries)
|
|
|
|
if (strcmp (p->value, depinfo->service) == 0) {
|
|
|
|
//visit_service (deptree, types, sorted, visited, di,
|
|
|
|
// runlevel, options | RC_DEP_TRACE);
|
|
|
|
break;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(provided);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We've visited everything we need, so add ourselves unless we
|
|
|
|
are also the service calling us or we are provided by something */
|
2008-03-20 03:41:22 +05:30
|
|
|
svcname = getenv("RC_SVCNAME");
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! svcname || strcmp(svcname, depinfo->service) != 0)
|
2008-03-17 18:55:56 +05:30
|
|
|
if (! get_deptype(depinfo, "providedby")) {
|
|
|
|
if (! *sorted)
|
|
|
|
*sorted = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(*sorted, depinfo->service);
|
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree,
|
|
|
|
const char *service, const char *type)
|
2007-12-05 23:18:07 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_DEPINFO *di;
|
|
|
|
RC_DEPTYPE *dt;
|
|
|
|
RC_STRINGLIST *svcs;
|
|
|
|
RC_STRING *svc;
|
2007-12-05 23:18:07 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (!(di = get_depinfo(deptree, service)) ||
|
|
|
|
! (dt = get_deptype(di, type)))
|
2007-12-05 23:18:07 +05:30
|
|
|
{
|
|
|
|
errno = ENOENT;
|
2008-03-16 22:30:56 +05:30
|
|
|
return NULL;
|
2007-12-05 23:18:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* For consistency, we copy the array */
|
2008-03-16 22:30:56 +05:30
|
|
|
svcs = rc_stringlist_new();
|
|
|
|
TAILQ_FOREACH(svc, dt->services, entries)
|
|
|
|
rc_stringlist_add(svcs, svc->value);
|
2007-12-05 23:18:07 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return svcs;
|
2007-12-05 23:18:07 +05:30
|
|
|
}
|
|
|
|
librc_hidden_def(rc_deptree_depend)
|
|
|
|
|
2008-04-10 14:19:05 +05:30
|
|
|
RC_STRINGLIST *rc_deptree_depends(const RC_DEPTREE *deptree,
|
|
|
|
const RC_STRINGLIST *types,
|
|
|
|
const RC_STRINGLIST *services,
|
|
|
|
const char *runlevel, int options)
|
2007-12-05 23:18:07 +05:30
|
|
|
{
|
2008-03-17 18:55:56 +05:30
|
|
|
RC_STRINGLIST *sorted = NULL;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *visited = rc_stringlist_new();
|
|
|
|
RC_DEPINFO *di;
|
|
|
|
const RC_STRING *service;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-04-10 14:19:05 +05:30
|
|
|
bootlevel = getenv("RC_BOOTLEVEL");
|
2007-07-21 18:19:51 +05:30
|
|
|
if (! bootlevel)
|
|
|
|
bootlevel = RC_LEVEL_BOOT;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(service, services, entries) {
|
|
|
|
if (! (di = get_depinfo(deptree, service->value))) {
|
2007-10-04 19:08:47 +05:30
|
|
|
errno = ENOENT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (types)
|
2008-03-17 18:55:56 +05:30
|
|
|
visit_service(deptree, types, &sorted, visited,
|
|
|
|
di, runlevel, options);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
rc_stringlist_free(visited);
|
2008-03-16 22:30:56 +05:30
|
|
|
return sorted;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2007-09-29 22:12:08 +05:30
|
|
|
librc_hidden_def(rc_deptree_depends)
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *deptree,
|
|
|
|
const char *runlevel, int options)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *list;
|
|
|
|
RC_STRINGLIST *list2;
|
|
|
|
RC_STRINGLIST *types;
|
|
|
|
RC_STRINGLIST *services;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-04-10 14:19:05 +05:30
|
|
|
bootlevel = getenv("RC_BOOTLEVEL");
|
2007-07-21 18:19:51 +05:30
|
|
|
if (! bootlevel)
|
|
|
|
bootlevel = RC_LEVEL_BOOT;
|
|
|
|
|
|
|
|
/* When shutting down, list all running services */
|
|
|
|
if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
|
|
|
strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
list = rc_services_in_state(RC_SERVICE_STARTED);
|
2008-04-10 14:19:05 +05:30
|
|
|
list2 = rc_services_in_state(RC_SERVICE_INACTIVE);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (list2) {
|
|
|
|
if (list) {
|
|
|
|
TAILQ_CONCAT(list, list2, entries);
|
|
|
|
free(list2);
|
|
|
|
} else
|
|
|
|
list = list2;
|
|
|
|
}
|
2008-04-10 14:19:05 +05:30
|
|
|
list2 = rc_services_in_state(RC_SERVICE_STARTING);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (list2) {
|
|
|
|
if (list) {
|
|
|
|
TAILQ_CONCAT(list, list2, entries);
|
|
|
|
free(list2);
|
|
|
|
} else
|
|
|
|
list = list2;
|
|
|
|
}
|
2007-09-18 17:34:51 +05:30
|
|
|
} else {
|
2008-04-10 14:19:05 +05:30
|
|
|
list = rc_services_in_runlevel(runlevel);
|
2007-07-21 18:19:51 +05:30
|
|
|
/* Add coldplugged services */
|
2008-04-10 14:19:05 +05:30
|
|
|
list2 = rc_services_in_state(RC_SERVICE_COLDPLUGGED);
|
|
|
|
if (list2) {
|
|
|
|
if (list) {
|
|
|
|
TAILQ_CONCAT(list, list2, entries);
|
|
|
|
free(list2);
|
|
|
|
} else
|
|
|
|
list = list2;
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* If we're not the boot runlevel then add that too */
|
2007-09-18 17:34:51 +05:30
|
|
|
if (strcmp (runlevel, bootlevel) != 0) {
|
2008-03-16 22:30:56 +05:30
|
|
|
list2 = rc_services_in_runlevel (bootlevel);
|
2008-04-10 14:19:05 +05:30
|
|
|
if (list2) {
|
|
|
|
if (list) {
|
|
|
|
TAILQ_CONCAT(list, list2, entries);
|
|
|
|
free(list2);
|
|
|
|
} else
|
|
|
|
list = list2;
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2007-09-18 21:13:19 +05:30
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Now we have our lists, we need to pull in any dependencies
|
|
|
|
and order them */
|
2008-03-16 22:30:56 +05:30
|
|
|
types = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types, "ineed");
|
|
|
|
rc_stringlist_add(types, "iuse");
|
|
|
|
rc_stringlist_add(types, "iafter");
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_deptree_depends(deptree, types, list, runlevel,
|
|
|
|
RC_DEP_STRICT | RC_DEP_TRACE | options);
|
2008-04-10 14:19:05 +05:30
|
|
|
rc_stringlist_free(list);
|
|
|
|
rc_stringlist_free(types);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return services;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2007-10-10 18:41:35 +05:30
|
|
|
librc_hidden_def(rc_deptree_order)
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
bool rc_newer_than(const char *source, const char *target)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-07-21 18:19:51 +05:30
|
|
|
struct stat buf;
|
|
|
|
time_t mtime;
|
2007-10-04 22:24:29 +05:30
|
|
|
bool newer = true;
|
2007-10-05 15:46:14 +05:30
|
|
|
DIR *dp;
|
|
|
|
struct dirent *d;
|
2008-03-17 18:55:56 +05:30
|
|
|
char path[PATH_MAX];
|
2008-01-14 13:42:37 +05:30
|
|
|
int serrno = errno;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-01-15 14:54:50 +05:30
|
|
|
/* We have to exist */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (stat(source, &buf) != 0)
|
|
|
|
return false;
|
2007-07-21 18:19:51 +05:30
|
|
|
mtime = buf.st_mtime;
|
|
|
|
|
2008-01-14 13:42:37 +05:30
|
|
|
/* Of course we are newer than targets that don't exist
|
|
|
|
such as broken symlinks */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (stat(target, &buf) != 0)
|
|
|
|
return true;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
if (mtime < buf.st_mtime)
|
2008-03-16 22:30:56 +05:30
|
|
|
return false;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-01-15 14:54:50 +05:30
|
|
|
/* If not a dir then reset errno */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! (dp = opendir(target))) {
|
2008-01-14 13:42:37 +05:30
|
|
|
errno = serrno;
|
2008-03-16 22:30:56 +05:30
|
|
|
return true;
|
2008-01-14 13:42:37 +05:30
|
|
|
}
|
2007-10-05 15:46:14 +05:30
|
|
|
|
2008-01-15 14:54:50 +05:30
|
|
|
/* Check if we're newer than all the entries in the dir */
|
2008-03-16 22:30:56 +05:30
|
|
|
while ((d = readdir(dp))) {
|
2007-10-05 15:46:14 +05:30
|
|
|
if (d->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
snprintf(path, sizeof(path), "%s/%s", target, d->d_name);
|
2008-03-16 22:30:56 +05:30
|
|
|
newer = rc_newer_than(source, path);
|
2007-10-04 22:24:29 +05:30
|
|
|
if (! newer)
|
|
|
|
break;
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
closedir(dp);
|
2007-10-05 15:46:14 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return newer;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2008-01-14 13:42:37 +05:30
|
|
|
librc_hidden_def(rc_newer_than)
|
2007-04-05 16:48:42 +05:30
|
|
|
|
|
|
|
typedef struct deppair
|
|
|
|
{
|
2007-07-21 18:19:51 +05:30
|
|
|
const char *depend;
|
|
|
|
const char *addto;
|
2008-03-16 22:30:56 +05:30
|
|
|
} DEPPAIR;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static const DEPPAIR deppairs[] = {
|
|
|
|
{ "ineed", "needsme" },
|
|
|
|
{ "iuse", "usesme" },
|
|
|
|
{ "iafter", "ibefore" },
|
2007-07-21 18:19:51 +05:30
|
|
|
{ "ibefore", "iafter" },
|
|
|
|
{ "iprovide", "providedby" },
|
|
|
|
{ NULL, NULL }
|
2007-04-05 16:48:42 +05:30
|
|
|
};
|
|
|
|
|
2008-02-02 01:24:46 +05:30
|
|
|
static const char *const depdirs[] =
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-08-09 20:03:20 +05:30
|
|
|
RC_SVCDIR "/starting",
|
|
|
|
RC_SVCDIR "/started",
|
|
|
|
RC_SVCDIR "/stopping",
|
|
|
|
RC_SVCDIR "/inactive",
|
|
|
|
RC_SVCDIR "/wasinactive",
|
|
|
|
RC_SVCDIR "/failed",
|
|
|
|
RC_SVCDIR "/coldplugged",
|
|
|
|
RC_SVCDIR "/daemons",
|
|
|
|
RC_SVCDIR "/options",
|
|
|
|
RC_SVCDIR "/exclusive",
|
|
|
|
RC_SVCDIR "/scheduled",
|
2007-07-21 18:19:51 +05:30
|
|
|
NULL
|
2007-04-05 16:48:42 +05:30
|
|
|
};
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
bool rc_deptree_update_needed(void)
|
2007-09-29 22:12:08 +05:30
|
|
|
{
|
|
|
|
bool newer = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *config;
|
|
|
|
RC_STRING *s;
|
2007-09-29 22:12:08 +05:30
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Create base directories if needed */
|
|
|
|
for (i = 0; depdirs[i]; i++)
|
2008-03-16 22:30:56 +05:30
|
|
|
if (mkdir(depdirs[i], 0755) != 0 && errno != EEXIST)
|
|
|
|
fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror (errno));
|
2007-09-29 22:12:08 +05:30
|
|
|
|
2008-01-15 14:54:50 +05:30
|
|
|
/* Quick test to see if anything we use has changed and we have
|
|
|
|
* data in our deptree */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! existss(RC_DEPTREE_CACHE) ||
|
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR) ||
|
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR) ||
|
2008-02-28 16:38:49 +05:30
|
|
|
#ifdef RC_PKG_INITDIR
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR) ||
|
2008-02-28 16:38:49 +05:30
|
|
|
#endif
|
|
|
|
#ifdef RC_PKG_CONFDIR
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR) ||
|
2008-03-03 16:03:42 +05:30
|
|
|
#endif
|
|
|
|
#ifdef RC_LOCAL_INITDIR
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR) ||
|
2008-03-03 16:03:42 +05:30
|
|
|
#endif
|
|
|
|
#ifdef RC_LOCAL_CONFDIR
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR) ||
|
2008-02-28 16:38:49 +05:30
|
|
|
#endif
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf"))
|
|
|
|
return true;
|
2007-09-29 22:12:08 +05:30
|
|
|
|
|
|
|
/* Some init scripts dependencies change depending on config files
|
|
|
|
* outside of baselayout, like syslog-ng, so we check those too. */
|
2008-03-17 18:55:56 +05:30
|
|
|
config = rc_config_list(RC_DEPCONFIG);
|
|
|
|
if (config) {
|
|
|
|
TAILQ_FOREACH(s, config, entries) {
|
|
|
|
if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) {
|
|
|
|
newer = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-09-29 22:12:08 +05:30
|
|
|
}
|
2008-03-17 18:55:56 +05:30
|
|
|
rc_stringlist_free(config);
|
2007-09-29 22:12:08 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return newer;
|
2007-09-29 22:12:08 +05:30
|
|
|
}
|
|
|
|
librc_hidden_def(rc_deptree_update_needed)
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
/* This is a 5 phase operation
|
|
|
|
Phase 1 is a shell script which loads each init script and config in turn
|
|
|
|
and echos their dependency info to stdout
|
|
|
|
Phase 2 takes that and populates a depinfo object with that data
|
|
|
|
Phase 3 adds any provided services to the depinfo object
|
|
|
|
Phase 4 scans that depinfo object and puts in backlinks
|
|
|
|
Phase 5 saves the depinfo object to disk
|
|
|
|
*/
|
|
|
|
bool rc_deptree_update(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
FILE *fp;
|
|
|
|
RC_DEPTREE *deptree;
|
|
|
|
RC_DEPTREE *providers;
|
|
|
|
RC_DEPINFO *depinfo = NULL;
|
|
|
|
RC_DEPINFO *depinfo_np;
|
|
|
|
RC_DEPINFO *di;
|
|
|
|
RC_DEPTYPE *deptype = NULL;
|
|
|
|
RC_DEPTYPE *dt;
|
|
|
|
RC_DEPTYPE *dt_np;
|
|
|
|
RC_STRINGLIST *config;
|
|
|
|
RC_STRING *s;
|
|
|
|
RC_STRING *s2;
|
|
|
|
RC_DEPTYPE *provide;
|
2008-03-18 02:57:37 +05:30
|
|
|
char *line = NULL;
|
|
|
|
size_t len = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
char *depend;
|
2007-07-21 18:19:51 +05:30
|
|
|
char *depends;
|
|
|
|
char *service;
|
|
|
|
char *type;
|
2008-02-19 19:45:53 +05:30
|
|
|
size_t i;
|
|
|
|
size_t k;
|
2008-03-18 02:57:37 +05:30
|
|
|
size_t l;
|
2008-03-16 22:30:56 +05:30
|
|
|
int retval = true;
|
|
|
|
const char *sys = rc_sys();
|
|
|
|
char *nosys;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Some init scripts need RC_LIBDIR to source stuff
|
|
|
|
Ideally we should be setting our full env instead */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! getenv("RC_LIBDIR"))
|
|
|
|
setenv("RC_LIBDIR", RC_LIBDIR, 0);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-02-19 19:45:53 +05:30
|
|
|
/* Phase 1 - source all init scripts and print dependencies */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! (fp = popen(GENDEP, "r")))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
deptree = xmalloc(sizeof(*deptree));
|
|
|
|
STAILQ_INIT(deptree);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
config = rc_stringlist_new();
|
|
|
|
|
2008-03-18 02:57:37 +05:30
|
|
|
while ((rc_getline(&line, &len, fp)))
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
2008-01-07 17:59:30 +05:30
|
|
|
depends = line;
|
2008-03-16 22:30:56 +05:30
|
|
|
service = strsep(&depends, " ");
|
2008-03-04 16:06:20 +05:30
|
|
|
if (! service || ! *service)
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-18 02:57:37 +05:30
|
|
|
type = strsep(&depends, " ");
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! depinfo || strcmp(depinfo->service, service) != 0) {
|
|
|
|
deptype = NULL;
|
|
|
|
depinfo = get_depinfo(deptree, service);
|
|
|
|
if (! depinfo) {
|
|
|
|
depinfo = xmalloc(sizeof(*depinfo));
|
|
|
|
STAILQ_INIT(&depinfo->depends);
|
|
|
|
depinfo->service = xstrdup(service);
|
|
|
|
STAILQ_INSERT_TAIL(deptree, depinfo, entries);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* We may not have any depends */
|
|
|
|
if (! type || ! depends)
|
2008-03-18 02:57:37 +05:30
|
|
|
continue;
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2007-08-15 20:19:41 +05:30
|
|
|
/* Get the type */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(type, "config") != 0) {
|
|
|
|
if (! deptype || strcmp (deptype->type, type) != 0)
|
|
|
|
deptype = get_deptype(depinfo, type);
|
|
|
|
if (! deptype) {
|
|
|
|
deptype = xmalloc(sizeof(*deptype));
|
|
|
|
deptype->type = xstrdup(type);
|
|
|
|
deptype->services = rc_stringlist_new();
|
|
|
|
STAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now add each depend to our type.
|
|
|
|
We do this individually so we handle multiple spaces gracefully */
|
2008-03-16 22:30:56 +05:30
|
|
|
while ((depend = strsep(&depends, " ")))
|
2007-07-21 18:19:51 +05:30
|
|
|
{
|
|
|
|
if (depend[0] == 0)
|
|
|
|
continue;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(type, "config") == 0) {
|
|
|
|
rc_stringlist_add(config, depend);
|
2007-08-15 20:19:41 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-07-21 18:19:51 +05:30
|
|
|
/* .sh files are not init scripts */
|
2008-03-18 02:57:37 +05:30
|
|
|
l = strlen(depend);
|
|
|
|
if (l > 2 &&
|
|
|
|
depend[l - 3] == '.' &&
|
|
|
|
depend[l - 2] == 's' &&
|
|
|
|
depend[l - 1] == 'h')
|
2007-07-21 18:19:51 +05:30
|
|
|
continue;
|
2008-01-30 19:07:20 +05:30
|
|
|
|
|
|
|
/* Remove our dependency if instructed */
|
|
|
|
if (depend[0] == '!') {
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_delete(deptype->services, depend + 1);
|
2008-01-30 19:07:20 +05:30
|
|
|
continue;
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(deptype->services, depend);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2007-11-22 16:55:08 +05:30
|
|
|
/* We need to allow `after *; before local;` to work.
|
|
|
|
* Conversely, we need to allow 'before *; after modules' also */
|
|
|
|
/* If we're before something, remove us from the after list */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(type, "ibefore") == 0) {
|
|
|
|
if ((dt = get_deptype(depinfo, "iafter")))
|
|
|
|
rc_stringlist_delete(dt->services, depend);
|
2007-11-22 16:55:08 +05:30
|
|
|
}
|
|
|
|
/* If we're after something, remove us from the before list */
|
|
|
|
if (strcmp (type, "iafter") == 0 ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (type, "ineed") == 0 ||
|
|
|
|
strcmp (type, "iuse") == 0) {
|
2008-03-16 22:30:56 +05:30
|
|
|
if ((dt = get_deptype(depinfo, "ibefore")))
|
|
|
|
rc_stringlist_delete(dt->services, depend);
|
2007-11-22 16:55:08 +05:30
|
|
|
}
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-18 02:57:37 +05:30
|
|
|
free(line);
|
2008-03-16 22:30:56 +05:30
|
|
|
pclose(fp);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-02-19 19:45:53 +05:30
|
|
|
/* Phase 2 - if we're a special system, remove services that don't
|
|
|
|
* work for them. This doesn't stop them from being run directly. */
|
|
|
|
if (sys) {
|
2008-03-16 22:30:56 +05:30
|
|
|
len = strlen(sys);
|
|
|
|
nosys = xmalloc(len + 3);
|
2008-02-19 19:45:53 +05:30
|
|
|
nosys[0] = 'n';
|
|
|
|
nosys[1] = 'o';
|
|
|
|
for (i = 0; i < len; i++)
|
2008-04-17 15:49:58 +05:30
|
|
|
nosys[i + 2] = (char)tolower((unsigned char)sys[i]);
|
2008-02-19 19:45:53 +05:30
|
|
|
nosys[i + 2] = '\0';
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_np)
|
|
|
|
if ((deptype = get_deptype(depinfo, "keyword")))
|
|
|
|
TAILQ_FOREACH(s, deptype->services, entries)
|
|
|
|
if (strcmp (s->value, nosys) == 0) {
|
|
|
|
provide = get_deptype(depinfo, "iprovide");
|
|
|
|
STAILQ_REMOVE(deptree, depinfo, rc_depinfo, entries);
|
|
|
|
STAILQ_FOREACH(di, deptree, entries) {
|
|
|
|
STAILQ_FOREACH_SAFE(dt, &di->depends, entries, dt_np) {
|
|
|
|
rc_stringlist_delete(dt->services, depinfo->service);
|
|
|
|
if (provide)
|
|
|
|
TAILQ_FOREACH(s2, provide->services, entries)
|
|
|
|
rc_stringlist_delete(dt->services, s2->value);
|
|
|
|
if (! TAILQ_FIRST(dt->services)) {
|
|
|
|
STAILQ_REMOVE(&di->depends, dt, rc_deptype, entries);
|
|
|
|
free(dt->type);
|
|
|
|
free(dt->services);
|
|
|
|
free(dt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-19 19:45:53 +05:30
|
|
|
}
|
|
|
|
free (nosys);
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
/* Phase 3 - add our providers to the tree */
|
|
|
|
providers = xmalloc(sizeof(*providers));
|
|
|
|
STAILQ_INIT(providers);
|
|
|
|
STAILQ_FOREACH(depinfo, deptree, entries)
|
|
|
|
if ((deptype = get_deptype(depinfo, "iprovide")))
|
|
|
|
TAILQ_FOREACH(s, deptype->services, entries) {
|
|
|
|
STAILQ_FOREACH(di, providers, entries)
|
|
|
|
if (strcmp(di->service, s->value) == 0)
|
2007-07-21 18:19:51 +05:30
|
|
|
break;
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! di) {
|
|
|
|
di = xmalloc(sizeof(*di));
|
|
|
|
STAILQ_INIT(&di->depends);
|
|
|
|
di->service = xstrdup(s->value);
|
|
|
|
STAILQ_INSERT_TAIL(providers, di, entries);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_CONCAT(deptree, providers);
|
|
|
|
free(providers);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
|
|
|
/* Phase 4 - backreference our depends */
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_FOREACH(depinfo, deptree, entries)
|
|
|
|
for (i = 0; deppairs[i].depend; i++) {
|
|
|
|
deptype = get_deptype(depinfo, deppairs[i].depend);
|
2007-07-21 18:19:51 +05:30
|
|
|
if (! deptype)
|
|
|
|
continue;
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(s, deptype->services, entries) {
|
|
|
|
di = get_depinfo(deptree, s->value);
|
|
|
|
if (! di) {
|
2007-07-21 18:19:51 +05:30
|
|
|
if (strcmp (deptype->type, "ineed") == 0)
|
2008-03-16 22:30:56 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
"Service `%s' needs non"
|
|
|
|
" existant service `%s'\n",
|
|
|
|
depinfo->service, s->value);
|
2007-07-21 18:19:51 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
dt = get_deptype(di, deppairs[i].addto);
|
|
|
|
if (! dt) {
|
|
|
|
dt = xmalloc(sizeof(*dt));
|
|
|
|
dt->type = xstrdup(deppairs[i].addto);
|
|
|
|
dt->services = rc_stringlist_new();
|
|
|
|
STAILQ_INSERT_TAIL(&di->depends, dt, entries);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_add(dt->services, depinfo->service);
|
2007-07-21 18:19:51 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Phase 5 - save to disk
|
|
|
|
Now that we're purely in C, do we need to keep a shell parseable file?
|
|
|
|
I think yes as then it stays human readable
|
|
|
|
This works and should be entirely shell parseable provided that depend
|
|
|
|
names don't have any non shell variable characters in
|
|
|
|
*/
|
2008-03-16 22:30:56 +05:30
|
|
|
if ((fp = fopen (RC_DEPTREE_CACHE, "w"))) {
|
2007-07-21 18:19:51 +05:30
|
|
|
i = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
STAILQ_FOREACH(depinfo, deptree, entries) {
|
|
|
|
fprintf(fp, "depinfo_%zu_service='%s'\n",
|
|
|
|
i, depinfo->service);
|
|
|
|
STAILQ_FOREACH(deptype, &depinfo->depends, entries) {
|
2007-07-21 18:19:51 +05:30
|
|
|
k = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(s, deptype->services, entries) {
|
|
|
|
fprintf(fp,
|
|
|
|
"depinfo_%zu_%s_%zu='%s'\n",
|
|
|
|
i, deptype->type, k, s->value);
|
2007-07-21 18:19:51 +05:30
|
|
|
k++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
fclose(fp);
|
2007-10-04 19:08:47 +05:30
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
fprintf(stderr, "fopen `%s': %s\n",
|
|
|
|
RC_DEPTREE_CACHE, strerror(errno));
|
2007-10-04 19:08:47 +05:30
|
|
|
retval = false;
|
|
|
|
}
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2007-08-15 20:19:41 +05:30
|
|
|
/* Save our external config files to disk */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (TAILQ_FIRST(config)) {
|
|
|
|
if ((fp = fopen(RC_DEPCONFIG, "w"))) {
|
|
|
|
TAILQ_FOREACH(s, config, entries)
|
|
|
|
fprintf (fp, "%s\n", s->value);
|
|
|
|
fclose(fp);
|
2007-10-04 19:08:47 +05:30
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
fprintf(stderr, "fopen `%s': %s\n",
|
|
|
|
RC_DEPCONFIG, strerror(errno));
|
2007-10-04 19:08:47 +05:30
|
|
|
retval = false;
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free (config);
|
|
|
|
} else {
|
|
|
|
unlink(RC_DEPCONFIG);
|
2007-08-15 20:19:41 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_deptree_free(deptree);
|
2007-07-21 18:19:51 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
2007-09-29 22:12:08 +05:30
|
|
|
librc_hidden_def(rc_deptree_update)
|