Punt the rc_strcatpaths function and use snprintf instead to save on expensive malloc calls.
This commit is contained in:
parent
50a7697bf2
commit
4c14666423
@ -1,6 +1,6 @@
|
|||||||
MAN3= einfo.3 \
|
MAN3= einfo.3 \
|
||||||
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
|
rc_config.3 rc_deptree.3 rc_find_pids.3 rc_plugin_hook.3 \
|
||||||
rc_runlevel.3 rc_service.3 rc_strcatpaths.3 rc_stringlist.3
|
rc_runlevel.3 rc_service.3 rc_stringlist.3
|
||||||
MAN8= rc-status.8 rc-update.8 rc.8 runscript.8 start-stop-daemon.8
|
MAN8= rc-status.8 rc-update.8 rc.8 runscript.8 start-stop-daemon.8
|
||||||
|
|
||||||
# Handy macro to create symlinks
|
# Handy macro to create symlinks
|
||||||
|
@ -1,45 +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_STRCATPATHS 3 SMM
|
|
||||||
.Os OpenRC
|
|
||||||
.Sh NAME
|
|
||||||
.Nm rc_strcatpaths
|
|
||||||
.Nd concatenates each elements, seperating each with / as necessary
|
|
||||||
.Sh LIBRARY
|
|
||||||
Run Command library (librc, -lrc)
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.In rc.h
|
|
||||||
.Ft "char *" Fn rc_strcatpaths "const char *path" ...
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Fn rc_strcatpaths concatenates each
|
|
||||||
.Fa path ,
|
|
||||||
seperating each with / as necessary and returns a malloced pointer
|
|
||||||
to the result. This should be freed when done.
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr free 3 ,
|
|
||||||
.Xr malloc 3
|
|
||||||
.Sh AUTHORS
|
|
||||||
.An "Roy Marples" Aq roy@marples.name
|
|
@ -31,6 +31,30 @@
|
|||||||
|
|
||||||
#include "librc.h"
|
#include "librc.h"
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
# if ! defined (__UCLIBC__) && ! defined (__dietlibc__)
|
||||||
|
static size_t strlcpy(char *dst, const char *src, size_t size)
|
||||||
|
{
|
||||||
|
const char *s = src;
|
||||||
|
size_t n = size;
|
||||||
|
|
||||||
|
if (n && --n)
|
||||||
|
do {
|
||||||
|
if (! (*dst++ = *src++))
|
||||||
|
break;
|
||||||
|
} while (--n);
|
||||||
|
|
||||||
|
if (! n) {
|
||||||
|
if (size)
|
||||||
|
*dst = '\0';
|
||||||
|
while (*src++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return src - s - 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
static bool pid_is_cmd(pid_t pid, const char *cmd)
|
static bool pid_is_cmd(pid_t pid, const char *cmd)
|
||||||
{
|
{
|
||||||
@ -289,12 +313,12 @@ static bool _match_daemon(const char *path, const char *file,
|
|||||||
RC_STRINGLIST *match)
|
RC_STRINGLIST *match)
|
||||||
{
|
{
|
||||||
char *line;
|
char *line;
|
||||||
char *ffile = rc_strcatpaths(path, file, (char *) NULL);
|
char ffile[PATH_MAX];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
RC_STRING *m;
|
RC_STRING *m;
|
||||||
|
|
||||||
|
snprintf(ffile, sizeof(ffile), "%s/%s", path, file);
|
||||||
fp = fopen(ffile, "r");
|
fp = fopen(ffile, "r");
|
||||||
free(ffile);
|
|
||||||
|
|
||||||
if (! fp)
|
if (! fp)
|
||||||
return false;
|
return false;
|
||||||
@ -352,16 +376,15 @@ static RC_STRINGLIST *_match_list(const char* const* argv,
|
|||||||
bool rc_service_daemon_set(const char *service, const char *const *argv,
|
bool rc_service_daemon_set(const char *service, const char *const *argv,
|
||||||
const char *name, const char *pidfile, bool started)
|
const char *name, const char *pidfile, bool started)
|
||||||
{
|
{
|
||||||
char *dirpath;
|
char dirpath[PATH_MAX];
|
||||||
char *file = NULL;
|
char file[PATH_MAX];
|
||||||
int nfiles = 0;
|
int nfiles = 0;
|
||||||
char *oldfile = NULL;
|
char oldfile[PATH_MAX] = { '\0' };
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
RC_STRINGLIST *match;
|
RC_STRINGLIST *match;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char buffer[10];
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
if (!(argv && *argv) && ! name && ! pidfile) {
|
if (!(argv && *argv) && ! name && ! pidfile) {
|
||||||
@ -369,40 +392,40 @@ bool rc_service_daemon_set(const char *service, const char *const *argv,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons",
|
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
|
||||||
basename_c(service), (char *) NULL);
|
basename_c(service));
|
||||||
|
|
||||||
match = _match_list(argv, name, pidfile);
|
|
||||||
|
|
||||||
/* Regardless, erase any existing daemon info */
|
/* Regardless, erase any existing daemon info */
|
||||||
if ((dp = opendir(dirpath))) {
|
if ((dp = opendir(dirpath))) {
|
||||||
|
match = _match_list(argv, name, pidfile);
|
||||||
while ((d = readdir(dp))) {
|
while ((d = readdir(dp))) {
|
||||||
if (d->d_name[0] == '.')
|
if (d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
file = rc_strcatpaths(dirpath, d->d_name, (char *) NULL);
|
|
||||||
|
snprintf(file, sizeof(file), "%s/%s",
|
||||||
|
dirpath, d->d_name);
|
||||||
nfiles++;
|
nfiles++;
|
||||||
|
|
||||||
if (! oldfile) {
|
if (! *oldfile) {
|
||||||
if (_match_daemon(dirpath, d->d_name, match)) {
|
if (_match_daemon(dirpath, d->d_name, match)) {
|
||||||
unlink (file);
|
unlink(file);
|
||||||
oldfile = file;
|
strlcpy(oldfile, file, sizeof(oldfile));
|
||||||
nfiles--;
|
nfiles--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rename(file, oldfile);
|
rename(file, oldfile);
|
||||||
free(oldfile);
|
strlcpy(oldfile, file, sizeof(oldfile));
|
||||||
oldfile = file;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(file);
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
rc_stringlist_free(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now store our daemon info */
|
/* Now store our daemon info */
|
||||||
if (started) {
|
if (started) {
|
||||||
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
|
if (mkdir(dirpath, 0755) == 0 || errno == EEXIST) {
|
||||||
snprintf(buffer, sizeof(buffer), "%03d", nfiles + 1);
|
snprintf(file, sizeof(file), "%s/%03d",
|
||||||
file = rc_strcatpaths(dirpath, buffer, (char *) NULL);
|
dirpath, nfiles + 1);
|
||||||
if ((fp = fopen(file, "w"))) {
|
if ((fp = fopen(file, "w"))) {
|
||||||
while (argv && argv[i]) {
|
while (argv && argv[i]) {
|
||||||
fprintf(fp, "argv_%d=%s\n", i, argv[i]);
|
fprintf(fp, "argv_%d=%s\n", i, argv[i]);
|
||||||
@ -418,25 +441,19 @@ bool rc_service_daemon_set(const char *service, const char *const *argv,
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
free(file);
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
rc_stringlist_free(match);
|
|
||||||
free(dirpath);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_daemon_set)
|
librc_hidden_def(rc_service_daemon_set)
|
||||||
|
|
||||||
bool
|
bool rc_service_started_daemon(const char *service, const char *const *argv,
|
||||||
rc_service_started_daemon (const char *service, const char *const *argv,
|
|
||||||
int indx)
|
int indx)
|
||||||
{
|
{
|
||||||
char *dirpath;
|
char dirpath[PATH_MAX];
|
||||||
char *file;
|
char file[16];
|
||||||
size_t l;
|
|
||||||
RC_STRINGLIST *match;
|
RC_STRINGLIST *match;
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
@ -445,17 +462,13 @@ rc_service_started_daemon (const char *service, const char *const *argv,
|
|||||||
if (!service || !(argv && *argv))
|
if (!service || !(argv && *argv))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
|
snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
|
||||||
(char *) NULL);
|
basename_c(service));
|
||||||
|
|
||||||
match = _match_list(argv, NULL, NULL);
|
match = _match_list(argv, NULL, NULL);
|
||||||
|
|
||||||
if (indx > 0) {
|
if (indx > 0) {
|
||||||
l = sizeof (char) * 10;
|
snprintf(file, sizeof(file), "%03d", indx);
|
||||||
file = xmalloc(l);
|
|
||||||
snprintf(file, l, "%03d", indx);
|
|
||||||
retval = _match_daemon(dirpath, file, match);
|
retval = _match_daemon(dirpath, file, match);
|
||||||
free(file);
|
|
||||||
} else {
|
} else {
|
||||||
if ((dp = opendir(dirpath))) {
|
if ((dp = opendir(dirpath))) {
|
||||||
while ((d = readdir(dp))) {
|
while ((d = readdir(dp))) {
|
||||||
@ -469,7 +482,6 @@ rc_service_started_daemon (const char *service, const char *const *argv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(dirpath);
|
|
||||||
rc_stringlist_free(match);
|
rc_stringlist_free(match);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -477,10 +489,10 @@ librc_hidden_def(rc_service_started_daemon)
|
|||||||
|
|
||||||
bool rc_service_daemons_crashed(const char *service)
|
bool rc_service_daemons_crashed(const char *service)
|
||||||
{
|
{
|
||||||
char *dirpath;
|
char dirpath[PATH_MAX];
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
char *path;
|
char *path = dirpath;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *line;
|
char *line;
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
@ -498,21 +510,19 @@ bool rc_service_daemons_crashed(const char *service)
|
|||||||
RC_STRING *s;
|
RC_STRING *s;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
dirpath = rc_strcatpaths(RC_SVCDIR, "daemons", basename_c(service),
|
path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s",
|
||||||
(char *) NULL);
|
basename_c(service));
|
||||||
|
|
||||||
if (! (dp = opendir(dirpath))) {
|
if (! (dp = opendir(dirpath)))
|
||||||
free(dirpath);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
while ((d = readdir(dp))) {
|
while ((d = readdir(dp))) {
|
||||||
if (d->d_name[0] == '.')
|
if (d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
path = rc_strcatpaths(dirpath, d->d_name, (char *) NULL);
|
snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s",
|
||||||
fp = fopen(path, "r");
|
d->d_name);
|
||||||
free(path);
|
fp = fopen(dirpath, "r");
|
||||||
if (! fp)
|
if (! fp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -360,9 +360,9 @@ static RC_STRINGLIST *get_provided (const RC_DEPINFO *depinfo,
|
|||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_service (const RC_DEPTREE *deptree,
|
static void visit_service(const RC_DEPTREE *deptree,
|
||||||
const RC_STRINGLIST *types,
|
const RC_STRINGLIST *types,
|
||||||
RC_STRINGLIST *sorted,
|
RC_STRINGLIST **sorted,
|
||||||
RC_STRINGLIST *visited,
|
RC_STRINGLIST *visited,
|
||||||
const RC_DEPINFO *depinfo,
|
const RC_DEPINFO *depinfo,
|
||||||
const char *runlevel, int options)
|
const char *runlevel, int options)
|
||||||
@ -392,7 +392,9 @@ static void visit_service (const RC_DEPTREE *deptree,
|
|||||||
if (! options & RC_DEP_TRACE ||
|
if (! options & RC_DEP_TRACE ||
|
||||||
strcmp(type->value, "iprovide") == 0)
|
strcmp(type->value, "iprovide") == 0)
|
||||||
{
|
{
|
||||||
rc_stringlist_add(sorted, service->value);
|
if (! *sorted)
|
||||||
|
*sorted = rc_stringlist_new();
|
||||||
|
rc_stringlist_add(*sorted, service->value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,8 +447,11 @@ static void visit_service (const RC_DEPTREE *deptree,
|
|||||||
are also the service calling us or we are provided by something */
|
are also the service calling us or we are provided by something */
|
||||||
svcname = getenv("SVCNAME");
|
svcname = getenv("SVCNAME");
|
||||||
if (! svcname || strcmp(svcname, depinfo->service) != 0)
|
if (! svcname || strcmp(svcname, depinfo->service) != 0)
|
||||||
if (! get_deptype(depinfo, "providedby"))
|
if (! get_deptype(depinfo, "providedby")) {
|
||||||
rc_stringlist_add(sorted, depinfo->service);
|
if (! *sorted)
|
||||||
|
*sorted = rc_stringlist_new();
|
||||||
|
rc_stringlist_add(*sorted, depinfo->service);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree,
|
RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree,
|
||||||
@ -478,7 +483,7 @@ RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree,
|
|||||||
const RC_STRINGLIST *services,
|
const RC_STRINGLIST *services,
|
||||||
const char *runlevel, int options)
|
const char *runlevel, int options)
|
||||||
{
|
{
|
||||||
RC_STRINGLIST *sorted = rc_stringlist_new();
|
RC_STRINGLIST *sorted = NULL;
|
||||||
RC_STRINGLIST *visited = rc_stringlist_new();
|
RC_STRINGLIST *visited = rc_stringlist_new();
|
||||||
RC_DEPINFO *di;
|
RC_DEPINFO *di;
|
||||||
const RC_STRING *service;
|
const RC_STRING *service;
|
||||||
@ -493,11 +498,11 @@ RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (types)
|
if (types)
|
||||||
visit_service (deptree, types, sorted, visited,
|
visit_service(deptree, types, &sorted, visited,
|
||||||
di, runlevel, options);
|
di, runlevel, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_stringlist_free (visited);
|
rc_stringlist_free(visited);
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_deptree_depends)
|
librc_hidden_def(rc_deptree_depends)
|
||||||
@ -522,12 +527,23 @@ RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *deptree,
|
|||||||
list = rc_services_in_state(RC_SERVICE_STARTED);
|
list = rc_services_in_state(RC_SERVICE_STARTED);
|
||||||
|
|
||||||
list2 = rc_services_in_state (RC_SERVICE_INACTIVE);
|
list2 = rc_services_in_state (RC_SERVICE_INACTIVE);
|
||||||
|
if (list2) {
|
||||||
|
if (list) {
|
||||||
TAILQ_CONCAT(list, list2, entries);
|
TAILQ_CONCAT(list, list2, entries);
|
||||||
free(list2);
|
free(list2);
|
||||||
|
} else
|
||||||
|
list = list2;
|
||||||
|
}
|
||||||
|
|
||||||
list2 = rc_services_in_state (RC_SERVICE_STARTING);
|
list2 = rc_services_in_state (RC_SERVICE_STARTING);
|
||||||
|
if (list2) {
|
||||||
|
if (list) {
|
||||||
TAILQ_CONCAT(list, list2, entries);
|
TAILQ_CONCAT(list, list2, entries);
|
||||||
free(list2);
|
free(list2);
|
||||||
|
} else
|
||||||
|
list = list2;
|
||||||
|
}
|
||||||
|
TAILQ_CONCAT(list, list2, entries);
|
||||||
} else {
|
} else {
|
||||||
list = rc_services_in_runlevel (runlevel);
|
list = rc_services_in_runlevel (runlevel);
|
||||||
|
|
||||||
@ -567,7 +583,7 @@ bool rc_newer_than(const char *source, const char *target)
|
|||||||
bool newer = true;
|
bool newer = true;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
char *path;
|
char path[PATH_MAX];
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
|
|
||||||
/* We have to exist */
|
/* We have to exist */
|
||||||
@ -594,9 +610,8 @@ bool rc_newer_than(const char *source, const char *target)
|
|||||||
if (d->d_name[0] == '.')
|
if (d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
path = rc_strcatpaths(target, d->d_name, (char *) NULL);
|
snprintf(path, sizeof(path), "%s/%s", target, d->d_name);
|
||||||
newer = rc_newer_than(source, path);
|
newer = rc_newer_than(source, path);
|
||||||
free(path);
|
|
||||||
if (! newer)
|
if (! newer)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -671,7 +686,8 @@ bool rc_deptree_update_needed(void)
|
|||||||
|
|
||||||
/* Some init scripts dependencies change depending on config files
|
/* Some init scripts dependencies change depending on config files
|
||||||
* outside of baselayout, like syslog-ng, so we check those too. */
|
* outside of baselayout, like syslog-ng, so we check those too. */
|
||||||
config = rc_config_list (RC_DEPCONFIG);
|
config = rc_config_list(RC_DEPCONFIG);
|
||||||
|
if (config) {
|
||||||
TAILQ_FOREACH(s, config, entries) {
|
TAILQ_FOREACH(s, config, entries) {
|
||||||
if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) {
|
if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) {
|
||||||
newer = true;
|
newer = true;
|
||||||
@ -679,6 +695,7 @@ bool rc_deptree_update_needed(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc_stringlist_free(config);
|
rc_stringlist_free(config);
|
||||||
|
}
|
||||||
|
|
||||||
return newer;
|
return newer;
|
||||||
}
|
}
|
||||||
|
@ -54,57 +54,6 @@ bool rc_yesno (const char *value)
|
|||||||
}
|
}
|
||||||
librc_hidden_def(rc_yesno)
|
librc_hidden_def(rc_yesno)
|
||||||
|
|
||||||
char *rc_strcatpaths (const char *path1, const char *paths, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
size_t length;
|
|
||||||
size_t i;
|
|
||||||
char *p;
|
|
||||||
char *path;
|
|
||||||
char *pathp;
|
|
||||||
|
|
||||||
if (! path1 || ! paths)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
length = strlen (path1) + strlen (paths) + 1;
|
|
||||||
if (*paths != '/')
|
|
||||||
length ++;
|
|
||||||
|
|
||||||
va_start (ap, paths);
|
|
||||||
while ((p = va_arg (ap, char *)) != NULL) {
|
|
||||||
if (*p != '/')
|
|
||||||
length ++;
|
|
||||||
length += strlen (p);
|
|
||||||
}
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
pathp = path = xmalloc (length * sizeof (char));
|
|
||||||
memset (path, 0, length);
|
|
||||||
i = strlen (path1);
|
|
||||||
memcpy (path, path1, i);
|
|
||||||
pathp += i;
|
|
||||||
if (*paths != '/')
|
|
||||||
*pathp ++ = '/';
|
|
||||||
i = strlen (paths);
|
|
||||||
memcpy (pathp, paths, i);
|
|
||||||
pathp += i;
|
|
||||||
|
|
||||||
va_start (ap, paths);
|
|
||||||
while ((p = va_arg (ap, char *)) != NULL) {
|
|
||||||
if (*p != '/')
|
|
||||||
*pathp ++= '/';
|
|
||||||
i = strlen (p);
|
|
||||||
memcpy (pathp, p, i);
|
|
||||||
pathp += i;
|
|
||||||
}
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
*pathp++ = 0;
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
librc_hidden_def(rc_strcatpaths)
|
|
||||||
|
|
||||||
char *rc_getline (FILE *fp)
|
char *rc_getline (FILE *fp)
|
||||||
{
|
{
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
@ -138,13 +87,11 @@ RC_STRINGLIST *rc_config_list(const char *file)
|
|||||||
char *buffer;
|
char *buffer;
|
||||||
char *p;
|
char *p;
|
||||||
char *token;
|
char *token;
|
||||||
RC_STRINGLIST *list;
|
RC_STRINGLIST *list = NULL;
|
||||||
|
|
||||||
if (!(fp = fopen(file, "r")))
|
if (!(fp = fopen(file, "r")))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
list = rc_stringlist_new();
|
|
||||||
|
|
||||||
while ((p = buffer = rc_getline(fp))) {
|
while ((p = buffer = rc_getline(fp))) {
|
||||||
/* Strip leading spaces/tabs */
|
/* Strip leading spaces/tabs */
|
||||||
while ((*p == ' ') || (*p == '\t'))
|
while ((*p == ' ') || (*p == '\t'))
|
||||||
@ -159,6 +106,8 @@ RC_STRINGLIST *rc_config_list(const char *file)
|
|||||||
if (token[strlen(token) - 1] == '\n')
|
if (token[strlen(token) - 1] == '\n')
|
||||||
token[strlen(token) - 1] = 0;
|
token[strlen(token) - 1] = 0;
|
||||||
|
|
||||||
|
if (! list)
|
||||||
|
list = rc_stringlist_new();
|
||||||
rc_stringlist_add(list, token);
|
rc_stringlist_add(list, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,8 +121,8 @@ librc_hidden_def(rc_config_list)
|
|||||||
|
|
||||||
RC_STRINGLIST *rc_config_load(const char *file)
|
RC_STRINGLIST *rc_config_load(const char *file)
|
||||||
{
|
{
|
||||||
RC_STRINGLIST *list = NULL;
|
RC_STRINGLIST *list;
|
||||||
RC_STRINGLIST *config = NULL;
|
RC_STRINGLIST *config;
|
||||||
char *token;
|
char *token;
|
||||||
RC_STRING *line;
|
RC_STRING *line;
|
||||||
RC_STRING *cline;
|
RC_STRING *cline;
|
||||||
@ -183,9 +132,11 @@ RC_STRINGLIST *rc_config_load(const char *file)
|
|||||||
char *newline;
|
char *newline;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
config = rc_stringlist_new();
|
|
||||||
|
|
||||||
list = rc_config_list(file);
|
list = rc_config_list(file);
|
||||||
|
if (! list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
config = rc_stringlist_new();
|
||||||
TAILQ_FOREACH(line, list, entries) {
|
TAILQ_FOREACH(line, list, entries) {
|
||||||
/* Get entry */
|
/* Get entry */
|
||||||
p = line->value;
|
p = line->value;
|
||||||
|
@ -62,7 +62,7 @@ RC_STRING *rc_stringlist_addu (RC_STRINGLIST *list, const char *value)
|
|||||||
}
|
}
|
||||||
librc_hidden_def(rc_stringlist_addu)
|
librc_hidden_def(rc_stringlist_addu)
|
||||||
|
|
||||||
bool rc_stringlist_delete (RC_STRINGLIST *list, const char *value)
|
bool rc_stringlist_delete(RC_STRINGLIST *list, const char *value)
|
||||||
{
|
{
|
||||||
RC_STRING *s;
|
RC_STRING *s;
|
||||||
|
|
||||||
|
@ -72,25 +72,24 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
|
|||||||
{
|
{
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
RC_STRINGLIST *list;
|
RC_STRINGLIST *list = NULL;
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
size_t l;
|
size_t l;
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if ((dp = opendir(dir)) == NULL)
|
if ((dp = opendir(dir)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
list = rc_stringlist_new();
|
|
||||||
while (((d = readdir(dp)) != NULL)) {
|
while (((d = readdir(dp)) != NULL)) {
|
||||||
if (d->d_name[0] != '.') {
|
if (d->d_name[0] != '.') {
|
||||||
if (options & LS_INITD) {
|
if (options & LS_INITD) {
|
||||||
/* Check that our file really exists.
|
/* Check that our file really exists.
|
||||||
* This is important as a service maybe in a runlevel, but
|
* This is important as a service maybe in a runlevel, but
|
||||||
* could also have been removed. */
|
* could also have been removed. */
|
||||||
file = rc_strcatpaths(dir, d->d_name, NULL);
|
snprintf(file, sizeof(file), "%s/%s",
|
||||||
|
dir, d->d_name);
|
||||||
r = stat(file, &buf);
|
r = stat(file, &buf);
|
||||||
free(file);
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -106,6 +105,8 @@ static RC_STRINGLIST *ls_dir(const char *dir, int options)
|
|||||||
! S_ISDIR(buf.st_mode))
|
! S_ISDIR(buf.st_mode))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (! list)
|
||||||
|
list = rc_stringlist_new();
|
||||||
rc_stringlist_add(list, d->d_name);
|
rc_stringlist_add(list, d->d_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +119,7 @@ static bool rm_dir(const char *pathname, bool top)
|
|||||||
{
|
{
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
char *tmp = NULL;
|
char file[PATH_MAX];
|
||||||
struct stat s;
|
struct stat s;
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
|
|
||||||
@ -128,22 +129,21 @@ static bool rm_dir(const char *pathname, bool top)
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
while (((d = readdir(dp)) != NULL) && errno == 0) {
|
while (((d = readdir(dp)) != NULL) && errno == 0) {
|
||||||
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
|
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
|
||||||
free(tmp);
|
snprintf(file, sizeof(file), "%s/%s", pathname, d->d_name);
|
||||||
tmp = rc_strcatpaths(pathname, d->d_name, (char *) NULL);
|
|
||||||
|
|
||||||
if (stat(tmp, &s) != 0) {
|
if (stat(file, &s) != 0) {
|
||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(s.st_mode)) {
|
if (S_ISDIR(s.st_mode)) {
|
||||||
if (! rm_dir(tmp, true))
|
if (! rm_dir(file, true))
|
||||||
{
|
{
|
||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (unlink(tmp)) {
|
if (unlink(file)) {
|
||||||
retval = false;
|
retval = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -151,7 +151,6 @@ static bool rm_dir(const char *pathname, bool top)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
if (! retval)
|
if (! retval)
|
||||||
return false;
|
return false;
|
||||||
@ -302,18 +301,16 @@ librc_hidden_def(rc_runlevel_set)
|
|||||||
|
|
||||||
bool rc_runlevel_exists(const char *runlevel)
|
bool rc_runlevel_exists(const char *runlevel)
|
||||||
{
|
{
|
||||||
char *path;
|
char path[PATH_MAX];
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
bool retval = false;
|
|
||||||
|
|
||||||
if (! runlevel)
|
if (! runlevel)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
path = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
|
snprintf(path, sizeof(path), "%s/%s", RC_RUNLEVELDIR, runlevel);
|
||||||
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
|
if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
|
||||||
retval = true;
|
return true;
|
||||||
free(path);
|
return false;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_runlevel_exists)
|
librc_hidden_def(rc_runlevel_exists)
|
||||||
|
|
||||||
@ -321,8 +318,8 @@ librc_hidden_def(rc_runlevel_exists)
|
|||||||
char *rc_service_resolve(const char *service)
|
char *rc_service_resolve(const char *service)
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
int r = 0;
|
int r;
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
|
|
||||||
if (! service)
|
if (! service)
|
||||||
@ -332,43 +329,41 @@ char *rc_service_resolve(const char *service)
|
|||||||
return xstrdup(service);
|
return xstrdup(service);
|
||||||
|
|
||||||
/* First check started services */
|
/* First check started services */
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "started", service, (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", "started", service);
|
||||||
if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) {
|
if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) {
|
||||||
free(file);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "inactive", service, (char *) NULL);
|
"inactive", service);
|
||||||
if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode)) {
|
if (lstat(file, &buf) || ! S_ISLNK(buf.st_mode))
|
||||||
free(file);
|
*file = '\0';
|
||||||
file = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*file) {
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
/* Nope, so lets see if the user has written it */
|
|
||||||
#ifdef RC_LOCAL_INITDIR
|
|
||||||
snprintf(buffer, sizeof(buffer), RC_LOCAL_INITDIR "/%s", service);
|
|
||||||
if (stat(buffer, &buf) == 0)
|
|
||||||
return xstrdup(buffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
r = readlink(file, buffer, sizeof(buffer));
|
r = readlink(file, buffer, sizeof(buffer));
|
||||||
free(file);
|
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
return xstrdup(buffer);
|
return xstrdup(buffer);
|
||||||
}
|
}
|
||||||
snprintf(buffer, sizeof(buffer), RC_INITDIR "/%s", service);
|
|
||||||
|
|
||||||
/* So we don't exist in /etc/init.d - check RC_PKG_INITDIR */
|
#ifdef RC_LOCAL_INITDIR
|
||||||
#ifdef RC_PKG_INITDIR
|
/* Nope, so lets see if the user has written it */
|
||||||
if (stat(buffer, &buf) != 0) {
|
snprintf(file, sizeof(file), RC_LOCAL_INITDIR "/%s", service);
|
||||||
snprintf(buffer, sizeof(buffer), RC_PKG_INITDIR "/%s", service);
|
if (stat(file, &buf) == 0)
|
||||||
if (stat(buffer, &buf) != 0)
|
return xstrdup(file);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return xstrdup(buffer);
|
/* System scripts take precedence over 3rd party ones */
|
||||||
|
snprintf(file, sizeof(file), RC_INITDIR "/%s", service);
|
||||||
|
if (stat(file, &buf) == 0)
|
||||||
|
return xstrdup(file);
|
||||||
|
|
||||||
|
#ifdef RC_PKG_INITDIR
|
||||||
|
/* Check RC_PKG_INITDIR */
|
||||||
|
snprintf(file, sizeof(file), RC_PKG_INITDIR "/%s", service);
|
||||||
|
if (stat(file, &buf) == 0)
|
||||||
|
return xstrdup(file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_resolve)
|
librc_hidden_def(rc_service_resolve)
|
||||||
|
|
||||||
@ -406,7 +401,7 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
|
|||||||
char *svc;
|
char *svc;
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
RC_STRINGLIST *commands;
|
RC_STRINGLIST *commands = NULL;
|
||||||
char *token;
|
char *token;
|
||||||
char *p;
|
char *p;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -415,7 +410,6 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
|
|||||||
if (! (svc = rc_service_resolve(service)))
|
if (! (svc = rc_service_resolve(service)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
commands = rc_stringlist_new();
|
|
||||||
|
|
||||||
l = strlen(OPTSTR) + strlen(svc) + 1;
|
l = strlen(OPTSTR) + strlen(svc) + 1;
|
||||||
cmd = xmalloc(sizeof(char) * l);
|
cmd = xmalloc(sizeof(char) * l);
|
||||||
@ -424,8 +418,11 @@ RC_STRINGLIST *rc_service_extra_commands(const char *service)
|
|||||||
|
|
||||||
if ((fp = popen(cmd, "r"))) {
|
if ((fp = popen(cmd, "r"))) {
|
||||||
p = buffer = rc_getline(fp);
|
p = buffer = rc_getline(fp);
|
||||||
while ((token = strsep(&p, " ")))
|
while ((token = strsep(&p, " "))) {
|
||||||
|
if (! commands)
|
||||||
|
commands = rc_stringlist_new();
|
||||||
rc_stringlist_add(commands, token);
|
rc_stringlist_add(commands, token);
|
||||||
|
}
|
||||||
pclose(fp);
|
pclose(fp);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
@ -464,24 +461,17 @@ librc_hidden_def(rc_service_description)
|
|||||||
|
|
||||||
bool rc_service_in_runlevel(const char *service, const char *runlevel)
|
bool rc_service_in_runlevel(const char *service, const char *runlevel)
|
||||||
{
|
{
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
bool retval;
|
|
||||||
|
|
||||||
if (! runlevel || ! service)
|
snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s",
|
||||||
return false;
|
runlevel, basename_c(service));
|
||||||
|
return exists(file);
|
||||||
file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service),
|
|
||||||
(char *) NULL);
|
|
||||||
retval = exists(file);
|
|
||||||
free(file);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_in_runlevel)
|
librc_hidden_def(rc_service_in_runlevel)
|
||||||
|
|
||||||
bool rc_service_mark(const char *service, const RC_SERVICE state)
|
bool rc_service_mark(const char *service, const RC_SERVICE state)
|
||||||
{
|
{
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int skip_state = -1;
|
int skip_state = -1;
|
||||||
const char *base;
|
const char *base;
|
||||||
@ -504,18 +494,16 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state (state), base,
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
(char *) NULL);
|
rc_parse_service_state (state), base);
|
||||||
if (exists(file))
|
if (exists(file))
|
||||||
unlink(file);
|
unlink(file);
|
||||||
i = symlink(init, file);
|
i = symlink(init, file);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
free(file);
|
|
||||||
free(init);
|
free(init);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(file);
|
|
||||||
skip_state = state;
|
skip_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,24 +522,22 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
|
|||||||
s != RC_SERVICE_SCHEDULED) &&
|
s != RC_SERVICE_SCHEDULED) &&
|
||||||
(! skip_wasinactive || s != RC_SERVICE_WASINACTIVE))
|
(! skip_wasinactive || s != RC_SERVICE_WASINACTIVE))
|
||||||
{
|
{
|
||||||
file = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(s), base,
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
(char *) NULL);
|
rc_parse_service_state(s), base);
|
||||||
if (exists(file)) {
|
if (exists(file)) {
|
||||||
if ((state == RC_SERVICE_STARTING ||
|
if ((state == RC_SERVICE_STARTING ||
|
||||||
state == RC_SERVICE_STOPPING) &&
|
state == RC_SERVICE_STOPPING) &&
|
||||||
s == RC_SERVICE_INACTIVE)
|
s == RC_SERVICE_INACTIVE)
|
||||||
{
|
{
|
||||||
was = rc_strcatpaths(RC_SVCDIR,
|
snprintf(was, sizeof(was),
|
||||||
|
RC_SVCDIR "/%s/%s",
|
||||||
rc_parse_service_state(RC_SERVICE_WASINACTIVE),
|
rc_parse_service_state(RC_SERVICE_WASINACTIVE),
|
||||||
base, (char *) NULL);
|
base);
|
||||||
|
|
||||||
symlink(init, was);
|
symlink(init, was);
|
||||||
skip_wasinactive = true;
|
skip_wasinactive = true;
|
||||||
free(was);
|
|
||||||
}
|
}
|
||||||
unlink(file);
|
unlink(file);
|
||||||
}
|
}
|
||||||
free(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,43 +546,44 @@ bool rc_service_mark(const char *service, const RC_SERVICE state)
|
|||||||
state == RC_SERVICE_STOPPED ||
|
state == RC_SERVICE_STOPPED ||
|
||||||
state == RC_SERVICE_INACTIVE)
|
state == RC_SERVICE_INACTIVE)
|
||||||
{
|
{
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "exclusive", base, (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
|
"exclusive", base);
|
||||||
unlink(file);
|
unlink(file);
|
||||||
free(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove any options and daemons the service may have stored */
|
/* Remove any options and daemons the service may have stored */
|
||||||
if (state == RC_SERVICE_STOPPED) {
|
if (state == RC_SERVICE_STOPPED) {
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "options", base, (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
|
"options", base);
|
||||||
rm_dir(file, true);
|
rm_dir(file, true);
|
||||||
free(file);
|
|
||||||
|
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "daemons", base, (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
|
"daemons", base);
|
||||||
rm_dir(file, true);
|
rm_dir(file, true);
|
||||||
free(file);
|
|
||||||
|
|
||||||
rc_service_schedule_clear(service);
|
rc_service_schedule_clear(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These are final states, so remove us from scheduled */
|
/* These are final states, so remove us from scheduled */
|
||||||
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
|
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled", (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s", "scheduled");
|
||||||
dirs = ls_dir(file, 0);
|
dirs = ls_dir(file, 0);
|
||||||
|
if (dirs) {
|
||||||
TAILQ_FOREACH(dir, dirs, entries) {
|
TAILQ_FOREACH(dir, dirs, entries) {
|
||||||
was = rc_strcatpaths(file, dir->value, base, (char *) NULL);
|
snprintf(was, sizeof(was), "%s/%s/%s",
|
||||||
|
file, dir->value, base);
|
||||||
unlink(was);
|
unlink(was);
|
||||||
free(was);
|
|
||||||
|
|
||||||
/* Try and remove the dir - we don't care about errors */
|
/* Try and remove the dir - we don't care about errors */
|
||||||
was = rc_strcatpaths(file, dir->value, (char *) NULL);
|
snprintf(was, sizeof(was), "%s/%s",
|
||||||
|
file, dir->value);
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
rmdir(was);
|
rmdir(was);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
free(was);
|
|
||||||
}
|
}
|
||||||
rc_stringlist_free(dirs);
|
rc_stringlist_free(dirs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(init);
|
free(init);
|
||||||
return true;
|
return true;
|
||||||
@ -607,36 +594,37 @@ RC_SERVICE rc_service_state(const char *service)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int state = RC_SERVICE_STOPPED;
|
int state = RC_SERVICE_STOPPED;
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
RC_STRINGLIST *dirs;
|
RC_STRINGLIST *dirs;
|
||||||
RC_STRING *dir;
|
RC_STRING *dir;
|
||||||
|
const char *base = basename_c(service);
|
||||||
|
|
||||||
for (i = 0; rc_service_state_names[i].name; i++) {
|
for (i = 0; rc_service_state_names[i].name; i++) {
|
||||||
file = rc_strcatpaths(RC_SVCDIR, rc_service_state_names[i].name,
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s",
|
||||||
basename_c(service), (char*) NULL);
|
rc_service_state_names[i].name, base);
|
||||||
if (exists(file)) {
|
if (exists(file)) {
|
||||||
if (rc_service_state_names[i].state <= 0x10)
|
if (rc_service_state_names[i].state <= 0x10)
|
||||||
state = rc_service_state_names[i].state;
|
state = rc_service_state_names[i].state;
|
||||||
else
|
else
|
||||||
state |= rc_service_state_names[i].state;
|
state |= rc_service_state_names[i].state;
|
||||||
}
|
}
|
||||||
free(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state & RC_SERVICE_STOPPED) {
|
if (state & RC_SERVICE_STOPPED) {
|
||||||
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
||||||
|
if (dirs) {
|
||||||
TAILQ_FOREACH (dir, dirs, entries) {
|
TAILQ_FOREACH (dir, dirs, entries) {
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled",
|
snprintf(file, sizeof(file),
|
||||||
dir->value,
|
RC_SVCDIR "/scheduled/%s/%s",
|
||||||
service, (char *) NULL);
|
dir->value, service);
|
||||||
if (exists(file))
|
if (exists(file)) {
|
||||||
state |= RC_SERVICE_SCHEDULED;
|
state |= RC_SERVICE_SCHEDULED;
|
||||||
free(file);
|
|
||||||
if (state & RC_SERVICE_SCHEDULED)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
rc_stringlist_free(dirs);
|
rc_stringlist_free(dirs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -646,14 +634,14 @@ char *rc_service_value_get(const char *service, const char *option)
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
char *file = rc_strcatpaths(RC_SVCDIR, "options", service, option,
|
char file[PATH_MAX];
|
||||||
(char *) NULL);
|
|
||||||
|
|
||||||
|
snprintf(file, sizeof(file), RC_SVCDIR "/options/%s/%s",
|
||||||
|
service, option);
|
||||||
if ((fp = fopen(file, "r"))) {
|
if ((fp = fopen(file, "r"))) {
|
||||||
line = rc_getline(fp);
|
line = rc_getline(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
free(file);
|
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
@ -663,33 +651,27 @@ bool rc_service_value_set(const char *service, const char *option,
|
|||||||
const char *value)
|
const char *value)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *path = rc_strcatpaths(RC_SVCDIR, "options", service, (char *) NULL);
|
char file[PATH_MAX];
|
||||||
char *file = rc_strcatpaths(path, option, (char *) NULL);
|
char *p = file;
|
||||||
bool retval = false;
|
|
||||||
|
|
||||||
if (mkdir(path, 0755) != 0 && errno != EEXIST) {
|
p += snprintf(file, sizeof(file), RC_SVCDIR "/options/%s", service);
|
||||||
free(path);
|
if (mkdir(file, 0755) != 0 && errno != EEXIST)
|
||||||
free(file);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if ((fp = fopen(file, "w"))) {
|
snprintf(p, sizeof(file) - (p - file), "/%s", option);
|
||||||
|
if (!(fp = fopen(file, "w")))
|
||||||
|
return false;
|
||||||
if (value)
|
if (value)
|
||||||
fprintf(fp, "%s", value);
|
fprintf(fp, "%s", value);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
retval = true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
free(file);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_value_set)
|
librc_hidden_def(rc_service_value_set)
|
||||||
|
|
||||||
static pid_t _exec_service(const char *service, const char *arg)
|
static pid_t _exec_service(const char *service, const char *arg)
|
||||||
{
|
{
|
||||||
char *file;
|
char *file;
|
||||||
char *fifo;
|
char fifo[PATH_MAX];
|
||||||
pid_t pid = -1;
|
pid_t pid = -1;
|
||||||
sigset_t full;
|
sigset_t full;
|
||||||
sigset_t old;
|
sigset_t old;
|
||||||
@ -703,11 +685,9 @@ static pid_t _exec_service(const char *service, const char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We create a fifo so that other services can wait until we complete */
|
/* We create a fifo so that other services can wait until we complete */
|
||||||
fifo = rc_strcatpaths(RC_SVCDIR, "exclusive", basename_c(service),
|
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s",
|
||||||
(char *) NULL);
|
basename_c(service));
|
||||||
|
|
||||||
if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) {
|
if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) {
|
||||||
free(fifo);
|
|
||||||
free(file);
|
free(file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -745,7 +725,6 @@ static pid_t _exec_service(const char *service, const char *arg)
|
|||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||||
|
|
||||||
free(fifo);
|
|
||||||
free(file);
|
free(file);
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
@ -782,28 +761,24 @@ librc_hidden_def(rc_service_start)
|
|||||||
bool rc_service_schedule_start(const char *service,
|
bool rc_service_schedule_start(const char *service,
|
||||||
const char *service_to_start)
|
const char *service_to_start)
|
||||||
{
|
{
|
||||||
char *dir;
|
char file[PATH_MAX];
|
||||||
|
char *p = file;
|
||||||
char *init;
|
char *init;
|
||||||
char *file;
|
|
||||||
bool retval;
|
bool retval;
|
||||||
|
|
||||||
/* service may be a provided service, like net */
|
/* service may be a provided service, like net */
|
||||||
if (! service || ! rc_service_exists(service_to_start))
|
if (! service || ! rc_service_exists(service_to_start))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
|
p += snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s",
|
||||||
(char *) NULL);
|
basename_c(service));
|
||||||
if (mkdir(dir, 0755) != 0 && errno != EEXIST) {
|
if (mkdir(file, 0755) != 0 && errno != EEXIST)
|
||||||
free(dir);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
init = rc_service_resolve(service_to_start);
|
init = rc_service_resolve(service_to_start);
|
||||||
file = rc_strcatpaths(dir, basename_c(service_to_start), (char *) NULL);
|
snprintf(p, sizeof(file) - (p - file), "/%s", basename_c(service_to_start));
|
||||||
retval = (exists(file) || symlink(init, file) == 0);
|
retval = (exists(file) || symlink(init, file) == 0);
|
||||||
free(init);
|
free(init);
|
||||||
free(file);
|
|
||||||
free(dir);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -811,20 +786,19 @@ librc_hidden_def(rc_service_schedule_start)
|
|||||||
|
|
||||||
bool rc_service_schedule_clear(const char *service)
|
bool rc_service_schedule_clear(const char *service)
|
||||||
{
|
{
|
||||||
char *dir = rc_strcatpaths(RC_SVCDIR, "scheduled", basename_c(service),
|
char dir[PATH_MAX];
|
||||||
(char *) NULL);
|
|
||||||
bool retval;
|
|
||||||
|
|
||||||
if (! (retval = rm_dir(dir, true)) && errno == ENOENT)
|
snprintf(dir, sizeof(dir), RC_SVCDIR "/scheduled/%s",
|
||||||
retval = true;
|
basename_c(service));
|
||||||
free(dir);
|
if (! rm_dir(dir, true) && errno == ENOENT)
|
||||||
return retval;
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_schedule_clear)
|
librc_hidden_def(rc_service_schedule_clear)
|
||||||
|
|
||||||
RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
|
RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
|
||||||
{
|
{
|
||||||
char *dir;
|
char dir[PATH_MAX];
|
||||||
RC_STRINGLIST *list;
|
RC_STRINGLIST *list;
|
||||||
|
|
||||||
if (! runlevel) {
|
if (! runlevel) {
|
||||||
@ -855,43 +829,47 @@ RC_STRINGLIST *rc_services_in_runlevel(const char *runlevel)
|
|||||||
/* These special levels never contain any services */
|
/* These special levels never contain any services */
|
||||||
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
|
if (strcmp(runlevel, RC_LEVEL_SYSINIT) == 0 ||
|
||||||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
|
strcmp(runlevel, RC_LEVEL_SINGLE) == 0) {
|
||||||
list = rc_stringlist_new();
|
return NULL;
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, (char *) NULL);
|
snprintf(dir, sizeof(dir), RC_RUNLEVELDIR "/%s", runlevel);
|
||||||
list = ls_dir(dir, LS_INITD);
|
list = ls_dir(dir, LS_INITD);
|
||||||
free(dir);
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_services_in_runlevel)
|
librc_hidden_def(rc_services_in_runlevel)
|
||||||
|
|
||||||
RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
|
RC_STRINGLIST *rc_services_in_state(RC_SERVICE state)
|
||||||
{
|
{
|
||||||
char *dir = rc_strcatpaths(RC_SVCDIR, rc_parse_service_state(state),
|
|
||||||
(char *) NULL);
|
|
||||||
RC_STRINGLIST *services;
|
RC_STRINGLIST *services;
|
||||||
RC_STRINGLIST *list;
|
RC_STRINGLIST *list;
|
||||||
RC_STRINGLIST *dirs;
|
RC_STRINGLIST *dirs;
|
||||||
RC_STRING *d;
|
RC_STRING *d;
|
||||||
char *p;
|
char dir[PATH_MAX];
|
||||||
|
char *p = dir;
|
||||||
|
|
||||||
|
p += snprintf(dir, sizeof(dir), RC_SVCDIR "/%s",
|
||||||
|
rc_parse_service_state(state));
|
||||||
|
|
||||||
|
if (state != RC_SERVICE_SCHEDULED)
|
||||||
|
return ls_dir(dir, LS_INITD);
|
||||||
|
|
||||||
|
|
||||||
if (state == RC_SERVICE_SCHEDULED) {
|
|
||||||
dirs = ls_dir(dir, 0);
|
dirs = ls_dir(dir, 0);
|
||||||
list = rc_stringlist_new();
|
if (! dirs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
TAILQ_FOREACH(d, dirs, entries) {
|
TAILQ_FOREACH(d, dirs, entries) {
|
||||||
p = rc_strcatpaths(dir, d->value, (char *) NULL);
|
snprintf(p, sizeof(dir) - (p - dir), "/%s", d->value);
|
||||||
services = ls_dir(p, LS_INITD);
|
services = ls_dir(dir, LS_INITD);
|
||||||
free(p);
|
if (! list)
|
||||||
|
services = list;
|
||||||
|
else if (services) {
|
||||||
TAILQ_CONCAT(list, services, entries);
|
TAILQ_CONCAT(list, services, entries);
|
||||||
free(services);
|
free(services);
|
||||||
}
|
}
|
||||||
rc_stringlist_free(dirs);
|
|
||||||
} else {
|
|
||||||
list = ls_dir(dir, LS_INITD);
|
|
||||||
}
|
}
|
||||||
|
rc_stringlist_free(dirs);
|
||||||
|
|
||||||
free(dir);
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_services_in_state)
|
librc_hidden_def(rc_services_in_state)
|
||||||
@ -900,9 +878,11 @@ bool rc_service_add(const char *runlevel, const char *service)
|
|||||||
{
|
{
|
||||||
bool retval;
|
bool retval;
|
||||||
char *init;
|
char *init;
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
char path[MAXPATHLEN] = { '\0' };
|
char path[MAXPATHLEN] = { '\0' };
|
||||||
char *p;
|
char *p = NULL;
|
||||||
|
char binit[PATH_MAX];
|
||||||
|
char *i;
|
||||||
|
|
||||||
if (! rc_runlevel_exists(runlevel)) {
|
if (! rc_runlevel_exists(runlevel)) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
@ -914,13 +894,15 @@ bool rc_service_add(const char *runlevel, const char *service)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
init = rc_service_resolve(service);
|
i = init = rc_service_resolve(service);
|
||||||
|
snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s",
|
||||||
|
runlevel, basename_c(service));
|
||||||
|
|
||||||
/* We need to ensure that only things in /etc/init.d are added
|
/* We need to ensure that only things in /etc/init.d are added
|
||||||
* to the boot runlevel */
|
* to the boot runlevel */
|
||||||
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) {
|
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) {
|
||||||
p = realpath(dirname (init), path);
|
|
||||||
free(init);
|
free(init);
|
||||||
|
p = realpath(dirname (init), path);
|
||||||
if (! *p)
|
if (! *p)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -929,33 +911,25 @@ bool rc_service_add(const char *runlevel, const char *service)
|
|||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
init = rc_strcatpaths(RC_INITDIR, service, (char *) NULL);
|
snprintf(binit, sizeof(binit), RC_INITDIR "/%s", service);
|
||||||
|
i = binit;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = rc_strcatpaths(RC_RUNLEVELDIR, runlevel, basename_c(service),
|
retval = (symlink(i, file) == 0);
|
||||||
(char *) NULL);
|
|
||||||
retval = (symlink(init, file) == 0);
|
|
||||||
free(init);
|
free(init);
|
||||||
free(file);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_add)
|
librc_hidden_def(rc_service_add)
|
||||||
|
|
||||||
bool rc_service_delete (const char *runlevel, const char *service)
|
bool rc_service_delete (const char *runlevel, const char *service)
|
||||||
{
|
{
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
bool retval = false;
|
|
||||||
|
|
||||||
if (! runlevel || ! service)
|
snprintf(file, sizeof(file), RC_RUNLEVELDIR "/%s/%s",
|
||||||
return false;
|
runlevel, basename_c(service));
|
||||||
|
|
||||||
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c(service),
|
|
||||||
(char *) NULL);
|
|
||||||
if (unlink(file) == 0)
|
if (unlink(file) == 0)
|
||||||
retval = true;
|
return true;
|
||||||
|
return false;
|
||||||
free(file);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_service_delete)
|
librc_hidden_def(rc_service_delete)
|
||||||
|
|
||||||
@ -964,15 +938,19 @@ RC_STRINGLIST *rc_services_scheduled_by(const char *service)
|
|||||||
RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
RC_STRINGLIST *dirs = ls_dir(RC_SVCDIR "/scheduled", 0);
|
||||||
RC_STRINGLIST *list;
|
RC_STRINGLIST *list;
|
||||||
RC_STRING *dir;
|
RC_STRING *dir;
|
||||||
char *file;
|
char file[PATH_MAX];
|
||||||
|
|
||||||
|
if (! dirs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
list = rc_stringlist_new();
|
|
||||||
TAILQ_FOREACH (dir, dirs, entries) {
|
TAILQ_FOREACH (dir, dirs, entries) {
|
||||||
file = rc_strcatpaths(RC_SVCDIR, "scheduled", dir->value,
|
snprintf(file, sizeof(file), RC_SVCDIR "/scheduled/%s/%s",
|
||||||
service, (char *) NULL);
|
dir->value, service);
|
||||||
if (exists(file))
|
if (exists(file)) {
|
||||||
|
if (! list)
|
||||||
|
list = rc_stringlist_new();
|
||||||
rc_stringlist_add(list, file);
|
rc_stringlist_add(list, file);
|
||||||
free(file);
|
}
|
||||||
}
|
}
|
||||||
rc_stringlist_free(dirs);
|
rc_stringlist_free(dirs);
|
||||||
|
|
||||||
@ -982,11 +960,10 @@ librc_hidden_def(rc_services_scheduled_by)
|
|||||||
|
|
||||||
RC_STRINGLIST *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 dir[PATH_MAX];
|
||||||
(char *) NULL);
|
|
||||||
RC_STRINGLIST *list = ls_dir(dir, LS_INITD);
|
|
||||||
|
|
||||||
free(dir);
|
snprintf(dir, sizeof(dir), "RC_SVCDIR/scheduled/%s",
|
||||||
return list;
|
basename_c(service));
|
||||||
|
return ls_dir(dir, LS_INITD);
|
||||||
}
|
}
|
||||||
librc_hidden_def(rc_services_scheduled)
|
librc_hidden_def(rc_services_scheduled)
|
||||||
|
@ -112,7 +112,6 @@ librc_hidden_proto(rc_service_started_daemon)
|
|||||||
librc_hidden_proto(rc_service_state)
|
librc_hidden_proto(rc_service_state)
|
||||||
librc_hidden_proto(rc_service_value_get)
|
librc_hidden_proto(rc_service_value_get)
|
||||||
librc_hidden_proto(rc_service_value_set)
|
librc_hidden_proto(rc_service_value_set)
|
||||||
librc_hidden_proto(rc_strcatpaths)
|
|
||||||
librc_hidden_proto(rc_stringlist_add)
|
librc_hidden_proto(rc_stringlist_add)
|
||||||
librc_hidden_proto(rc_stringlist_addu)
|
librc_hidden_proto(rc_stringlist_addu)
|
||||||
librc_hidden_proto(rc_stringlist_delete)
|
librc_hidden_proto(rc_stringlist_delete)
|
||||||
|
@ -27,17 +27,6 @@
|
|||||||
#ifndef __RC_H__
|
#ifndef __RC_H__
|
||||||
#define __RC_H__
|
#define __RC_H__
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC__MINOR)
|
|
||||||
# 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/types.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -444,13 +433,6 @@ void rc_stringlist_sort(RC_STRINGLIST **);
|
|||||||
* @param list to free */
|
* @param list to free */
|
||||||
void rc_stringlist_free(RC_STRINGLIST *);
|
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 *, const char *, ...) SENTINEL;
|
|
||||||
|
|
||||||
typedef struct rc_pid
|
typedef struct rc_pid
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -26,6 +26,7 @@ global:
|
|||||||
rc_service_delete;
|
rc_service_delete;
|
||||||
rc_service_description;
|
rc_service_description;
|
||||||
rc_service_exists;
|
rc_service_exists;
|
||||||
|
rc_service_extra_commands;
|
||||||
rc_service_in_runlevel;
|
rc_service_in_runlevel;
|
||||||
rc_service_mark;
|
rc_service_mark;
|
||||||
rc_service_options;
|
rc_service_options;
|
||||||
@ -42,7 +43,6 @@ global:
|
|||||||
rc_service_state;
|
rc_service_state;
|
||||||
rc_service_value_get;
|
rc_service_value_get;
|
||||||
rc_service_value_set;
|
rc_service_value_set;
|
||||||
rc_strcatpaths;
|
|
||||||
rc_stringlist_add;
|
rc_stringlist_add;
|
||||||
rc_stringlist_addu;
|
rc_stringlist_addu;
|
||||||
rc_stringlist_delete;
|
rc_stringlist_delete;
|
||||||
|
@ -79,7 +79,7 @@ void rc_plugin_load(void)
|
|||||||
DIR *dp;
|
DIR *dp;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
PLUGIN *plugin;
|
PLUGIN *plugin;
|
||||||
char *p;
|
char file[PATH_MAX];
|
||||||
void *h;
|
void *h;
|
||||||
int (*fptr)(RC_HOOK, const char *);
|
int (*fptr)(RC_HOOK, const char *);
|
||||||
|
|
||||||
@ -96,9 +96,8 @@ void rc_plugin_load(void)
|
|||||||
if (d->d_name[0] == '.')
|
if (d->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL);
|
snprintf(file, sizeof(file), RC_PLUGINDIR "/%s", d->d_name);
|
||||||
h = dlopen(p, RTLD_LAZY);
|
h = dlopen(file, RTLD_LAZY);
|
||||||
free(p);
|
|
||||||
if (! h) {
|
if (! h) {
|
||||||
eerror("dlopen: %s", dlerror());
|
eerror("dlopen: %s", dlerror());
|
||||||
continue;
|
continue;
|
||||||
|
544
src/rc/rc.c
544
src/rc/rc.c
@ -633,148 +633,14 @@ static void do_coldplug(void)
|
|||||||
printf ("%s\n", ecolor(ECOLOR_NORMAL));
|
printf ("%s\n", ecolor(ECOLOR_NORMAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool runlevel_config(const char *service, const char *level)
|
static void do_newlevel(const char *newlevel)
|
||||||
{
|
{
|
||||||
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[] = {
|
|
||||||
{ "override", 1, NULL, 'o' },
|
|
||||||
longopts_COMMON
|
|
||||||
};
|
|
||||||
static const char * const longopts_help[] = {
|
|
||||||
"override the next runlevel to change into\nwhen leaving single user or boot runlevels",
|
|
||||||
longopts_help_COMMON
|
|
||||||
};
|
|
||||||
#include "_usage.c"
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
const char *bootlevel = NULL;
|
|
||||||
const char *sys = rc_sys();
|
|
||||||
char *newlevel = NULL;
|
|
||||||
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;
|
|
||||||
char ksoftbuffer [PATH_MAX];
|
|
||||||
char pidstr[6];
|
|
||||||
int opt;
|
|
||||||
bool parallel;
|
|
||||||
int regen = 0;
|
|
||||||
pid_t pid;
|
|
||||||
RC_STRING *svc1;
|
|
||||||
RC_STRING *svc2 = NULL;
|
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
|
const char *sys;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char *proc;
|
|
||||||
char *p;
|
|
||||||
char *token;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
applet = basename_c(argv[0]);
|
|
||||||
LIST_INIT(&service_pids);
|
|
||||||
atexit(cleanup);
|
|
||||||
if (! applet)
|
|
||||||
eerrorx("arguments required");
|
|
||||||
|
|
||||||
if (argc > 1 && (strcmp(argv[1], "--version") == 0)) {
|
|
||||||
printf("%s (OpenRC", applet);
|
|
||||||
if (sys)
|
|
||||||
printf(" [%s]", sys);
|
|
||||||
printf(") " VERSION
|
|
||||||
#ifdef BRANDING
|
|
||||||
" (" BRANDING ")"
|
|
||||||
#endif
|
|
||||||
"\n");
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Run our built in applets. If we ran one, we don't return. */
|
|
||||||
run_applets(argc, argv);
|
|
||||||
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
/* Change dir to / to ensure all scripts don't use stuff in pwd */
|
|
||||||
chdir("/");
|
|
||||||
|
|
||||||
/* RUNLEVEL is set by sysvinit as is a magic number
|
|
||||||
* RC_SOFTLEVEL is set by us and is the name for this magic number
|
|
||||||
* even though all our userland documentation refers to runlevel */
|
|
||||||
RUNLEVEL = getenv("RUNLEVEL");
|
|
||||||
PREVLEVEL = getenv("PREVLEVEL");
|
|
||||||
|
|
||||||
/* Ensure our environment is pure
|
|
||||||
* Also, add our configuration to it */
|
|
||||||
env_filter();
|
|
||||||
env_config();
|
|
||||||
|
|
||||||
argc++;
|
|
||||||
argv--;
|
|
||||||
while ((opt = getopt_long(argc, argv, getoptstring,
|
|
||||||
longopts, (int *) 0)) != -1)
|
|
||||||
{
|
|
||||||
switch (opt) {
|
|
||||||
case 'o':
|
|
||||||
if (*optarg == '\0')
|
|
||||||
optarg = NULL;
|
|
||||||
exit(set_ksoftlevel(optarg) ? EXIT_SUCCESS : EXIT_FAILURE);
|
|
||||||
/* NOTREACHED */
|
|
||||||
case_RC_COMMON_GETOPT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newlevel = argv[optind++];
|
|
||||||
|
|
||||||
/* Enable logging */
|
|
||||||
setenv("EINFO_LOG", "rc", 1);
|
|
||||||
|
|
||||||
/* Export our PID */
|
|
||||||
snprintf(pidstr, sizeof(pidstr), "%d", getpid());
|
|
||||||
setenv("RC_PID", pidstr, 1);
|
|
||||||
|
|
||||||
/* Load current softlevel */
|
|
||||||
bootlevel = getenv("RC_BOOTLEVEL");
|
|
||||||
runlevel = rc_runlevel_get();
|
|
||||||
|
|
||||||
rc_logger_open(newlevel ? newlevel : runlevel);
|
|
||||||
|
|
||||||
/* Setup a signal handler */
|
|
||||||
signal_setup(SIGINT, handle_signal);
|
|
||||||
signal_setup(SIGQUIT, handle_signal);
|
|
||||||
signal_setup(SIGTERM, handle_signal);
|
|
||||||
signal_setup(SIGUSR1, handle_signal);
|
|
||||||
signal_setup(SIGWINCH, handle_signal);
|
|
||||||
|
|
||||||
if (! rc_yesno(getenv("EINFO_QUIET")))
|
|
||||||
interactive = exists(INTERACTIVE);
|
|
||||||
rc_plugin_load();
|
|
||||||
|
|
||||||
/* Check we're in the runlevel requested, ie from
|
|
||||||
* rc single
|
|
||||||
* rc shutdown
|
|
||||||
* rc reboot
|
|
||||||
*/
|
|
||||||
if (newlevel) {
|
|
||||||
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
|
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
|
||||||
#ifndef PREFIX
|
#ifndef PREFIX
|
||||||
&& RUNLEVEL &&
|
&& RUNLEVEL &&
|
||||||
@ -804,7 +670,7 @@ int main(int argc, char **argv)
|
|||||||
uts.machine);
|
uts.machine);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (sys)
|
if ((sys = rc_sys()))
|
||||||
printf(" [%s]", sys);
|
printf(" [%s]", sys);
|
||||||
|
|
||||||
printf("%s\n\n", ecolor(ECOLOR_NORMAL));
|
printf("%s\n\n", ecolor(ECOLOR_NORMAL));
|
||||||
@ -874,8 +740,278 @@ int main(int argc, char **argv)
|
|||||||
applet, strerror(errno));
|
applet, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_stop_services(const char *newlevel, bool going_down, bool parallel)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
RC_STRING *service, *svc1, *svc2;
|
||||||
|
RC_STRINGLIST *deporder, *tmplist;
|
||||||
|
|
||||||
|
if (! types_n) {
|
||||||
|
types_n = rc_stringlist_new();
|
||||||
|
rc_stringlist_add(types_n, "needsme");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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->value);
|
||||||
|
if (pid > 0 && ! parallel)
|
||||||
|
rc_waitpid(pid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're in the start list then don't bother stopping us */
|
||||||
|
TAILQ_FOREACH(svc1, start_services, entries)
|
||||||
|
if (strcmp (svc1->value, service->value) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
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
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_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;
|
||||||
|
}
|
||||||
|
rc_stringlist_free(deporder);
|
||||||
|
|
||||||
|
if (svc2)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After all that we can finally stop the blighter! */
|
||||||
|
pid = rc_service_stop(service->value);
|
||||||
|
if (pid > 0) {
|
||||||
|
add_pid(pid);
|
||||||
|
if (! parallel) {
|
||||||
|
rc_waitpid(pid);
|
||||||
|
remove_pid(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_start_services(bool parallel)
|
||||||
|
{
|
||||||
|
RC_STRING *service;
|
||||||
|
pid_t pid;
|
||||||
|
bool interactive = false;
|
||||||
|
|
||||||
|
if (! rc_yesno(getenv("EINFO_QUIET")))
|
||||||
|
interactive = exists(INTERACTIVE);
|
||||||
|
|
||||||
|
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->value);
|
||||||
|
eindent();
|
||||||
|
einfo("1) Start the service\t\t2) Skip the service");
|
||||||
|
einfo("3) Continue boot process\t\t4) Exit to shell");
|
||||||
|
eoutdent();
|
||||||
|
interactive_option:
|
||||||
|
switch (read_key(true)) {
|
||||||
|
case '1': break;
|
||||||
|
case '2': continue;
|
||||||
|
case '3': interactive = false; break;
|
||||||
|
case '4': sulogin(true); goto interactive_retry;
|
||||||
|
default: goto interactive_option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = rc_service_start(service->value);
|
||||||
|
|
||||||
|
/* Remember the pid if we're running in parallel */
|
||||||
|
if (pid > 0) {
|
||||||
|
add_pid(pid);
|
||||||
|
|
||||||
|
if (! parallel) {
|
||||||
|
rc_waitpid(pid);
|
||||||
|
remove_pid(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store our interactive status for boot */
|
||||||
|
if (interactive && strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0)
|
||||||
|
mark_interactive();
|
||||||
|
else {
|
||||||
|
if (exists(INTERACTIVE))
|
||||||
|
unlink(INTERACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "_usage.h"
|
||||||
|
#define getoptstring "o:" getoptstring_COMMON
|
||||||
|
static const struct option longopts[] = {
|
||||||
|
{ "override", 1, NULL, 'o' },
|
||||||
|
longopts_COMMON
|
||||||
|
};
|
||||||
|
static const char * const longopts_help[] = {
|
||||||
|
"override the next runlevel to change into\nwhen leaving single user or boot runlevels",
|
||||||
|
longopts_help_COMMON
|
||||||
|
};
|
||||||
|
#include "_usage.c"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *bootlevel = NULL;
|
||||||
|
char *newlevel = NULL;
|
||||||
|
RC_STRINGLIST *deporder = NULL;
|
||||||
|
RC_STRINGLIST *tmplist;
|
||||||
|
RC_STRING *service;
|
||||||
|
bool going_down = false;
|
||||||
|
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
|
||||||
|
char ksoftbuffer [PATH_MAX];
|
||||||
|
char pidstr[6];
|
||||||
|
int opt;
|
||||||
|
bool parallel;
|
||||||
|
int regen = 0;
|
||||||
|
#ifdef __linux__
|
||||||
|
char *proc;
|
||||||
|
char *p;
|
||||||
|
char *token;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
applet = basename_c(argv[0]);
|
||||||
|
LIST_INIT(&service_pids);
|
||||||
|
atexit(cleanup);
|
||||||
|
if (! applet)
|
||||||
|
eerrorx("arguments required");
|
||||||
|
|
||||||
|
if (argc > 1 && (strcmp(argv[1], "--version") == 0)) {
|
||||||
|
printf("%s (OpenRC", applet);
|
||||||
|
if ((bootlevel = rc_sys()))
|
||||||
|
printf(" [%s]", bootlevel);
|
||||||
|
printf(") " VERSION
|
||||||
|
#ifdef BRANDING
|
||||||
|
" (" BRANDING ")"
|
||||||
|
#endif
|
||||||
|
"\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run our built in applets. If we ran one, we don't return. */
|
||||||
|
run_applets(argc, argv);
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
/* Change dir to / to ensure all scripts don't use stuff in pwd */
|
||||||
|
chdir("/");
|
||||||
|
|
||||||
|
/* RUNLEVEL is set by sysvinit as is a magic number
|
||||||
|
* RC_SOFTLEVEL is set by us and is the name for this magic number
|
||||||
|
* even though all our userland documentation refers to runlevel */
|
||||||
|
RUNLEVEL = getenv("RUNLEVEL");
|
||||||
|
PREVLEVEL = getenv("PREVLEVEL");
|
||||||
|
|
||||||
|
/* Ensure our environment is pure
|
||||||
|
* Also, add our configuration to it */
|
||||||
|
env_filter();
|
||||||
|
env_config();
|
||||||
|
|
||||||
|
argc++;
|
||||||
|
argv--;
|
||||||
|
while ((opt = getopt_long(argc, argv, getoptstring,
|
||||||
|
longopts, (int *) 0)) != -1)
|
||||||
|
{
|
||||||
|
switch (opt) {
|
||||||
|
case 'o':
|
||||||
|
if (*optarg == '\0')
|
||||||
|
optarg = NULL;
|
||||||
|
exit(set_ksoftlevel(optarg) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
|
/* NOTREACHED */
|
||||||
|
case_RC_COMMON_GETOPT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newlevel = argv[optind++];
|
||||||
|
|
||||||
|
/* Enable logging */
|
||||||
|
setenv("EINFO_LOG", "rc", 1);
|
||||||
|
|
||||||
|
/* Export our PID */
|
||||||
|
snprintf(pidstr, sizeof(pidstr), "%d", getpid());
|
||||||
|
setenv("RC_PID", pidstr, 1);
|
||||||
|
|
||||||
|
/* Load current softlevel */
|
||||||
|
bootlevel = getenv("RC_BOOTLEVEL");
|
||||||
|
runlevel = rc_runlevel_get();
|
||||||
|
|
||||||
|
rc_logger_open(newlevel ? newlevel : runlevel);
|
||||||
|
|
||||||
|
/* Setup a signal handler */
|
||||||
|
signal_setup(SIGINT, handle_signal);
|
||||||
|
signal_setup(SIGQUIT, handle_signal);
|
||||||
|
signal_setup(SIGTERM, handle_signal);
|
||||||
|
signal_setup(SIGUSR1, handle_signal);
|
||||||
|
signal_setup(SIGWINCH, handle_signal);
|
||||||
|
|
||||||
|
rc_plugin_load();
|
||||||
|
|
||||||
|
/* Check we're in the runlevel requested, ie from
|
||||||
|
* rc single
|
||||||
|
* rc shutdown
|
||||||
|
* rc reboot
|
||||||
|
*/
|
||||||
|
if (newlevel)
|
||||||
|
do_newlevel(newlevel);
|
||||||
|
|
||||||
/* Now we start handling our children */
|
/* Now we start handling our children */
|
||||||
signal_setup(SIGCHLD, handle_signal);
|
signal_setup(SIGCHLD, handle_signal);
|
||||||
|
|
||||||
@ -946,15 +1082,23 @@ int main(int argc, char **argv)
|
|||||||
* correct order for stopping them */
|
* correct order for stopping them */
|
||||||
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
|
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||||
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
|
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||||
|
if (tmplist) {
|
||||||
|
if (stop_services) {
|
||||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||||
free(tmplist);
|
free(tmplist);
|
||||||
|
} else
|
||||||
|
stop_services = tmplist;
|
||||||
|
}
|
||||||
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
|
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
|
||||||
|
if (tmplist) {
|
||||||
|
if (stop_services) {
|
||||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||||
free(tmplist);
|
free(tmplist);
|
||||||
|
} else
|
||||||
|
stop_services = tmplist;
|
||||||
|
}
|
||||||
rc_stringlist_sort(&stop_services);
|
rc_stringlist_sort(&stop_services);
|
||||||
|
|
||||||
types_n = rc_stringlist_new();
|
|
||||||
rc_stringlist_add(types_n, "needsme");
|
|
||||||
|
|
||||||
types_nua = rc_stringlist_new();
|
types_nua = rc_stringlist_new();
|
||||||
rc_stringlist_add(types_nua, "ineed");
|
rc_stringlist_add(types_nua, "ineed");
|
||||||
@ -976,10 +1120,16 @@ int main(int argc, char **argv)
|
|||||||
start_services = rc_services_in_runlevel(bootlevel);
|
start_services = rc_services_in_runlevel(bootlevel);
|
||||||
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
|
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
|
||||||
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
|
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
|
||||||
|
if (tmplist) {
|
||||||
|
if (start_services) {
|
||||||
TAILQ_CONCAT(start_services, tmplist, entries);
|
TAILQ_CONCAT(start_services, tmplist, entries);
|
||||||
free(tmplist);
|
free(tmplist);
|
||||||
|
} else
|
||||||
|
start_services = tmplist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (coldplugged_services)
|
||||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||||
rc_stringlist_addu(start_services, service->value);
|
rc_stringlist_addu(start_services, service->value);
|
||||||
}
|
}
|
||||||
@ -991,69 +1141,8 @@ int main(int argc, char **argv)
|
|||||||
parallel = rc_conf_yesno("rc_parallel");
|
parallel = rc_conf_yesno("rc_parallel");
|
||||||
|
|
||||||
/* Now stop the services that shouldn't be running */
|
/* Now stop the services that shouldn't be running */
|
||||||
TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) {
|
if (stop_services)
|
||||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED)
|
do_stop_services(newlevel, parallel, going_down);
|
||||||
continue;
|
|
||||||
|
|
||||||
/* We always stop the service when in these runlevels */
|
|
||||||
if (going_down) {
|
|
||||||
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 */
|
|
||||||
TAILQ_FOREACH(svc1, start_services, entries)
|
|
||||||
if (strcmp (svc1->value, service->value) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
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
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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_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;
|
|
||||||
}
|
|
||||||
rc_stringlist_free(deporder);
|
|
||||||
|
|
||||||
if (svc2)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* After all that we can finally stop the blighter! */
|
|
||||||
pid = rc_service_stop(service->value);
|
|
||||||
if (pid > 0) {
|
|
||||||
add_pid(pid);
|
|
||||||
if (! parallel) {
|
|
||||||
rc_waitpid(pid);
|
|
||||||
remove_pid(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for our services to finish */
|
/* Wait for our services to finish */
|
||||||
wait_for_services();
|
wait_for_services();
|
||||||
@ -1094,15 +1183,18 @@ int main(int argc, char **argv)
|
|||||||
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
||||||
|
|
||||||
/* Re-add our coldplugged services if they stopped */
|
/* Re-add our coldplugged services if they stopped */
|
||||||
|
if (coldplugged_services)
|
||||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||||
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
|
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
|
||||||
|
|
||||||
/* Order the services to start */
|
/* Order the services to start */
|
||||||
|
if (start_services) {
|
||||||
rc_stringlist_sort(&start_services);
|
rc_stringlist_sort(&start_services);
|
||||||
deporder = rc_deptree_depends(deptree, types_nua, start_services,
|
deporder = rc_deptree_depends(deptree, types_nua, start_services,
|
||||||
runlevel, depoptions | RC_DEP_START);
|
runlevel, depoptions | RC_DEP_START);
|
||||||
rc_stringlist_free(start_services);
|
rc_stringlist_free(start_services);
|
||||||
start_services = deporder;
|
start_services = deporder;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/* mark any services skipped as started */
|
/* mark any services skipped as started */
|
||||||
@ -1116,46 +1208,12 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TAILQ_FOREACH(service, start_services, entries) {
|
if (start_services) {
|
||||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED) {
|
do_start_services(parallel);
|
||||||
if (! interactive)
|
|
||||||
interactive = want_interactive();
|
|
||||||
|
|
||||||
if (interactive) {
|
|
||||||
interactive_retry:
|
|
||||||
printf("\n");
|
|
||||||
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");
|
|
||||||
eoutdent();
|
|
||||||
interactive_option:
|
|
||||||
switch (read_key(true)) {
|
|
||||||
case '1': break;
|
|
||||||
case '2': continue;
|
|
||||||
case '3': interactive = false; break;
|
|
||||||
case '4': sulogin(true); goto interactive_retry;
|
|
||||||
default: goto interactive_option;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = rc_service_start(service->value);
|
|
||||||
|
|
||||||
/* Remember the pid if we're running in parallel */
|
|
||||||
if (pid > 0) {
|
|
||||||
add_pid(pid);
|
|
||||||
|
|
||||||
if (! parallel) {
|
|
||||||
rc_waitpid(pid);
|
|
||||||
remove_pid(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for our services to finish */
|
/* Wait for our services to finish */
|
||||||
wait_for_services();
|
wait_for_services();
|
||||||
|
}
|
||||||
|
|
||||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
|
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
|
||||||
hook_out = 0;
|
hook_out = 0;
|
||||||
@ -1172,14 +1230,6 @@ interactive_option:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Store our interactive status for boot */
|
|
||||||
if (interactive && strcmp(runlevel, bootlevel) == 0)
|
|
||||||
mark_interactive();
|
|
||||||
else {
|
|
||||||
if (exists(INTERACTIVE))
|
|
||||||
unlink(INTERACTIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're in the boot runlevel and we regenerated our dependencies
|
/* If we're in the boot runlevel and we regenerated our dependencies
|
||||||
* we need to delete them so that they are regenerated again in the
|
* 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 */
|
* default runlevel as they may depend on things that are now available */
|
||||||
|
@ -82,8 +82,8 @@ static RC_STRINGLIST *use_services = NULL;
|
|||||||
static RC_STRINGLIST *services = NULL;
|
static RC_STRINGLIST *services = NULL;
|
||||||
static RC_STRINGLIST *tmplist = NULL;
|
static RC_STRINGLIST *tmplist = NULL;
|
||||||
static char *service = NULL;
|
static char *service = NULL;
|
||||||
static char *exclusive = NULL;
|
static char exclusive[PATH_MAX] = { '\0' };
|
||||||
static char *mtime_test = NULL;
|
static char mtime_test[PATH_MAX] = { '\0' };
|
||||||
static RC_DEPTREE *deptree = NULL;
|
static RC_DEPTREE *deptree = NULL;
|
||||||
static char *runlevel = NULL;
|
static char *runlevel = NULL;
|
||||||
static bool sighup = false;
|
static bool sighup = false;
|
||||||
@ -212,7 +212,7 @@ static const char *const tests[] = {
|
|||||||
};
|
};
|
||||||
static bool in_control()
|
static bool in_control()
|
||||||
{
|
{
|
||||||
char *path;
|
char file[PATH_MAX];
|
||||||
time_t m;
|
time_t m;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -230,15 +230,12 @@ static bool in_control()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (tests[i]) {
|
while (tests[i]) {
|
||||||
path = rc_strcatpaths(RC_SVCDIR, tests[i], applet, (char *) NULL);
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet);
|
||||||
if (exists(path)) {
|
if (exists(file)) {
|
||||||
m = get_mtime(path, false);
|
m = get_mtime(file, false);
|
||||||
if (mtime < m && m != 0) {
|
if (mtime < m && m != 0)
|
||||||
free(path);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(path);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,10 +244,11 @@ static bool in_control()
|
|||||||
|
|
||||||
static void uncoldplug()
|
static void uncoldplug()
|
||||||
{
|
{
|
||||||
char *cold = rc_strcatpaths(RC_SVCDIR, "coldplugged", applet, (char *) NULL);
|
char file[PATH_MAX];
|
||||||
if (exists(cold) && unlink(cold) != 0)
|
|
||||||
eerror("%s: unlink `%s': %s", applet, cold, strerror(errno));
|
snprintf(file, sizeof(file), RC_SVCDIR "/coldplugged/%s", applet);
|
||||||
free(cold);
|
if (exists(file) && unlink(file) != 0)
|
||||||
|
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_services(RC_STRINGLIST *list) {
|
static void start_services(RC_STRINGLIST *list) {
|
||||||
@ -305,10 +303,10 @@ static void restore_state(void)
|
|||||||
rc_service_mark(applet, RC_SERVICE_FAILED);
|
rc_service_mark(applet, RC_SERVICE_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exclusive)
|
if (*exclusive) {
|
||||||
unlink(exclusive);
|
unlink(exclusive);
|
||||||
free(exclusive);
|
*exclusive = '\0';
|
||||||
exclusive = NULL;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanup(void)
|
static void cleanup(void)
|
||||||
@ -347,17 +345,12 @@ static void cleanup(void)
|
|||||||
rc_stringlist_free(applet_list);
|
rc_stringlist_free(applet_list);
|
||||||
rc_stringlist_free(tmplist);
|
rc_stringlist_free(tmplist);
|
||||||
free (ibsave);
|
free (ibsave);
|
||||||
|
|
||||||
if (mtime_test)
|
|
||||||
{
|
|
||||||
if (! rc_in_plugin)
|
|
||||||
unlink(mtime_test);
|
|
||||||
free(mtime_test);
|
|
||||||
}
|
|
||||||
free(exclusive);
|
|
||||||
free(service);
|
free(service);
|
||||||
free(prefix);
|
free(prefix);
|
||||||
free(runlevel);
|
free(runlevel);
|
||||||
|
|
||||||
|
if (*mtime_test && ! rc_in_plugin)
|
||||||
|
unlink(mtime_test);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
|
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
|
||||||
@ -580,37 +573,29 @@ static RC_SERVICE svc_status(void)
|
|||||||
|
|
||||||
static void make_exclusive(void)
|
static void make_exclusive(void)
|
||||||
{
|
{
|
||||||
char *path;
|
|
||||||
size_t l;
|
|
||||||
|
|
||||||
/* We create a fifo so that other services can wait until we complete */
|
/* We create a fifo so that other services can wait until we complete */
|
||||||
if (! exclusive)
|
if (! *exclusive)
|
||||||
exclusive = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL);
|
snprintf(exclusive, sizeof(exclusive), RC_SVCDIR "/exclusive/%s",
|
||||||
|
applet);
|
||||||
|
|
||||||
if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST &&
|
if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST &&
|
||||||
(errno != EACCES || geteuid () == 0))
|
(errno != EACCES || geteuid () == 0))
|
||||||
eerrorx ("%s: unable to create fifo `%s': %s",
|
eerrorx ("%s: unable to create fifo `%s': %s",
|
||||||
applet, exclusive, strerror(errno));
|
applet, exclusive, strerror(errno));
|
||||||
|
|
||||||
path = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL);
|
snprintf(mtime_test, sizeof(mtime_test), RC_SVCDIR "/exclusive/%s.%d", applet, getpid());
|
||||||
l = strlen (path) + 16;
|
|
||||||
mtime_test = xmalloc(sizeof (char) * l);
|
|
||||||
snprintf(mtime_test, l, "%s.%d", path, getpid());
|
|
||||||
free(path);
|
|
||||||
|
|
||||||
if (exists(mtime_test) && unlink(mtime_test) != 0) {
|
if (exists(mtime_test) && unlink(mtime_test) != 0) {
|
||||||
eerror("%s: unlink `%s': %s",
|
eerror("%s: unlink `%s': %s",
|
||||||
applet, mtime_test, strerror(errno));
|
applet, mtime_test, strerror(errno));
|
||||||
free(mtime_test);
|
*mtime_test = '\0';
|
||||||
mtime_test = NULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symlink(service, mtime_test) != 0) {
|
if (symlink(service, mtime_test) != 0) {
|
||||||
eerror("%s: symlink `%s' to `%s': %s",
|
eerror("%s: symlink `%s' to `%s': %s",
|
||||||
applet, service, mtime_test, strerror(errno));
|
applet, service, mtime_test, strerror(errno));
|
||||||
free(mtime_test);
|
*mtime_test = '\0';
|
||||||
mtime_test = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,8 +603,7 @@ static void unlink_mtime_test(void)
|
|||||||
{
|
{
|
||||||
if (unlink(mtime_test) != 0)
|
if (unlink(mtime_test) != 0)
|
||||||
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
|
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
|
||||||
free(mtime_test);
|
*mtime_test = '\0';
|
||||||
mtime_test = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_started_services(void)
|
static void get_started_services(void)
|
||||||
@ -627,8 +611,13 @@ static void get_started_services(void)
|
|||||||
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
|
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||||
rc_stringlist_free(restart_services);
|
rc_stringlist_free(restart_services);
|
||||||
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
|
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||||
|
if (tmp) {
|
||||||
|
if (restart_services) {
|
||||||
TAILQ_CONCAT(restart_services, tmp, entries);
|
TAILQ_CONCAT(restart_services, tmp, entries);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
} else
|
||||||
|
restart_services = tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_types(void)
|
static void setup_types(void)
|
||||||
@ -713,8 +702,8 @@ static void svc_start(bool deps)
|
|||||||
|
|
||||||
services = rc_deptree_depends(deptree, types_b, applet_list,
|
services = rc_deptree_depends(deptree, types_b, applet_list,
|
||||||
runlevel, 0);
|
runlevel, 0);
|
||||||
if (TAILQ_FIRST(services)) {
|
if (services && TAILQ_FIRST(services)) {
|
||||||
eerrorn ("ERROR: `%s' needs ", applet);
|
eerrorn("ERROR: `%s' needs ", applet);
|
||||||
first = true;
|
first = true;
|
||||||
TAILQ_FOREACH(svc, services, entries) {
|
TAILQ_FOREACH(svc, services, entries) {
|
||||||
if (first)
|
if (first)
|
||||||
@ -733,7 +722,7 @@ static void svc_start(bool deps)
|
|||||||
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
|
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
|
||||||
runlevel, depoptions);
|
runlevel, depoptions);
|
||||||
|
|
||||||
if (! rc_runlevel_starting())
|
if (! rc_runlevel_starting() && use_services)
|
||||||
TAILQ_FOREACH(svc, use_services, entries)
|
TAILQ_FOREACH(svc, use_services, entries)
|
||||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
||||||
pid_t pid = rc_service_start(svc->value);
|
pid_t pid = rc_service_start(svc->value);
|
||||||
@ -746,8 +735,7 @@ static void svc_start(bool deps)
|
|||||||
runlevel, depoptions);
|
runlevel, depoptions);
|
||||||
|
|
||||||
/* We use tmplist to hold our scheduled by list */
|
/* We use tmplist to hold our scheduled by list */
|
||||||
tmplist = rc_stringlist_new();
|
tmplist = NULL;
|
||||||
|
|
||||||
TAILQ_FOREACH(svc, services, entries) {
|
TAILQ_FOREACH(svc, services, entries) {
|
||||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||||
if (svcs & RC_SERVICE_STARTED)
|
if (svcs & RC_SERVICE_STARTED)
|
||||||
@ -768,14 +756,19 @@ static void svc_start(bool deps)
|
|||||||
if (! svc_wait(svc->value))
|
if (! svc_wait(svc->value))
|
||||||
eerror ("%s: timed out waiting for %s",
|
eerror ("%s: timed out waiting for %s",
|
||||||
applet, svc->value);
|
applet, svc->value);
|
||||||
|
if (! need_services)
|
||||||
|
continue;
|
||||||
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
|
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
|
||||||
continue;
|
continue;
|
||||||
TAILQ_FOREACH(svc2, need_services, entries) {
|
TAILQ_FOREACH(svc2, need_services, entries) {
|
||||||
if (strcmp (svc->value, svc2->value) == 0) {
|
if (strcmp (svc->value, svc2->value) == 0) {
|
||||||
if (svcs & RC_SERVICE_INACTIVE ||
|
if (svcs & RC_SERVICE_INACTIVE ||
|
||||||
svcs & RC_SERVICE_WASINACTIVE)
|
svcs & RC_SERVICE_WASINACTIVE)
|
||||||
|
{
|
||||||
|
if (! tmplist)
|
||||||
|
tmplist = rc_stringlist_new();
|
||||||
rc_stringlist_add(tmplist, svc->value);
|
rc_stringlist_add(tmplist, svc->value);
|
||||||
else
|
} else
|
||||||
eerrorx("ERROR: cannot start %s as"
|
eerrorx("ERROR: cannot start %s as"
|
||||||
" %s would not start",
|
" %s would not start",
|
||||||
applet, svc->value);
|
applet, svc->value);
|
||||||
@ -783,7 +776,7 @@ static void svc_start(bool deps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TAILQ_FIRST(tmplist)) {
|
if (tmplist && TAILQ_FIRST(tmplist)) {
|
||||||
/* Set the state now, then unlink our exclusive so that
|
/* Set the state now, then unlink our exclusive so that
|
||||||
our scheduled list is preserved */
|
our scheduled list is preserved */
|
||||||
rc_service_mark(service, RC_SERVICE_STOPPED);
|
rc_service_mark(service, RC_SERVICE_STOPPED);
|
||||||
@ -813,14 +806,14 @@ static void svc_start(bool deps)
|
|||||||
p += snprintf(p, len, "%s", svc->value);
|
p += snprintf(p, len, "%s", svc->value);
|
||||||
}
|
}
|
||||||
free(tmp);
|
free(tmp);
|
||||||
|
rc_stringlist_free(tmplist);
|
||||||
|
tmplist = NULL;
|
||||||
ewarnx("WARNING: %s is scheduled to start when %s has started",
|
ewarnx("WARNING: %s is scheduled to start when %s has started",
|
||||||
applet, tmp);
|
applet, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_stringlist_free(services);
|
rc_stringlist_free(services);
|
||||||
services = NULL;
|
services = NULL;
|
||||||
rc_stringlist_free(tmplist);
|
|
||||||
tmplist = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ibsave)
|
if (ibsave)
|
||||||
@ -928,9 +921,10 @@ static void svc_stop(bool deps)
|
|||||||
if (! types_m)
|
if (! types_m)
|
||||||
setup_types();
|
setup_types();
|
||||||
|
|
||||||
tmplist = rc_stringlist_new();
|
tmplist = NULL;
|
||||||
services = rc_deptree_depends(deptree, types_m, applet_list,
|
services = rc_deptree_depends(deptree, types_m, applet_list,
|
||||||
runlevel, depoptions);
|
runlevel, depoptions);
|
||||||
|
if (services) {
|
||||||
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
||||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||||
if (svcs & RC_SERVICE_STARTED ||
|
if (svcs & RC_SERVICE_STARTED ||
|
||||||
@ -944,13 +938,17 @@ static void svc_stop(bool deps)
|
|||||||
pid_t pid = rc_service_stop(svc->value);
|
pid_t pid = rc_service_stop(svc->value);
|
||||||
if (! rc_conf_yesno("rc_parallel"))
|
if (! rc_conf_yesno("rc_parallel"))
|
||||||
rc_waitpid(pid);
|
rc_waitpid(pid);
|
||||||
|
if (! tmplist)
|
||||||
|
tmplist = rc_stringlist_new();
|
||||||
rc_stringlist_add(tmplist, svc->value);
|
rc_stringlist_add(tmplist, svc->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc_stringlist_free(services);
|
rc_stringlist_free(services);
|
||||||
services = NULL;
|
services = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmplist) {
|
||||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||||
continue;
|
continue;
|
||||||
@ -975,11 +973,13 @@ static void svc_stop(bool deps)
|
|||||||
}
|
}
|
||||||
rc_stringlist_free(tmplist);
|
rc_stringlist_free(tmplist);
|
||||||
tmplist = NULL;
|
tmplist = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* We now wait for other services that may use us and are stopping
|
/* We now wait for other services that may use us and are stopping
|
||||||
This is important when a runlevel stops */
|
This is important when a runlevel stops */
|
||||||
services = rc_deptree_depends(deptree, types_mua, applet_list,
|
services = rc_deptree_depends(deptree, types_mua, applet_list,
|
||||||
runlevel, depoptions);
|
runlevel, depoptions);
|
||||||
|
if (services) {
|
||||||
TAILQ_FOREACH(svc, services, entries) {
|
TAILQ_FOREACH(svc, services, entries) {
|
||||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||||
continue;
|
continue;
|
||||||
@ -988,6 +988,7 @@ static void svc_stop(bool deps)
|
|||||||
rc_stringlist_free (services);
|
rc_stringlist_free (services);
|
||||||
services = NULL;
|
services = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're stopping localmount, set LC_ALL=C so that
|
/* If we're stopping localmount, set LC_ALL=C so that
|
||||||
* bash doesn't load anything blocking the unmounting of /usr */
|
* bash doesn't load anything blocking the unmounting of /usr */
|
||||||
@ -1114,8 +1115,8 @@ int runscript(int argc, char **argv)
|
|||||||
eerror("%s: cannot run until sysvinit completes", applet);
|
eerror("%s: cannot run until sysvinit completes", applet);
|
||||||
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
|
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
|
||||||
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
|
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
|
||||||
prefix = rc_strcatpaths("/dev/.rcboot", applet, (char *) NULL);
|
snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet);
|
||||||
symlink(service, prefix);
|
symlink(service, exclusive);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -590,6 +591,7 @@ int start_stop_daemon(int argc, char **argv)
|
|||||||
bool setuser = false;
|
bool setuser = false;
|
||||||
char *p;
|
char *p;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
char exec_file[PATH_MAX];
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
char line[130];
|
char line[130];
|
||||||
@ -773,14 +775,13 @@ int start_stop_daemon(int argc, char **argv)
|
|||||||
|
|
||||||
/* Validate that the binary exists if we are starting */
|
/* Validate that the binary exists if we are starting */
|
||||||
if (exec) {
|
if (exec) {
|
||||||
if (ch_root)
|
if (ch_root) {
|
||||||
tmp = rc_strcatpaths(ch_root, exec, (char *) NULL);
|
snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec);
|
||||||
else
|
tmp = exec_file;
|
||||||
|
} else
|
||||||
tmp = exec;
|
tmp = exec;
|
||||||
if (start && ! exists(tmp)) {
|
if (start && ! exists(tmp)) {
|
||||||
eerror("%s: %s does not exist", applet, tmp);
|
eerror("%s: %s does not exist", applet, tmp);
|
||||||
if (ch_root)
|
|
||||||
free(tmp);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,15 +808,10 @@ int start_stop_daemon(int argc, char **argv)
|
|||||||
applet, line + 2, exec);
|
applet, line + 2, exec);
|
||||||
eerror("%s: or you should specify a pidfile"
|
eerror("%s: or you should specify a pidfile"
|
||||||
" or process name", applet);
|
" or process name", applet);
|
||||||
if (ch_root)
|
|
||||||
free(tmp);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch_root)
|
|
||||||
free(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add exec to our arguments */
|
/* Add exec to our arguments */
|
||||||
|
Loading…
Reference in New Issue
Block a user