2007-04-05 16:48:42 +05:30
|
|
|
/*
|
|
|
|
* runscript.c
|
2007-11-14 20:52:04 +05:30
|
|
|
* Handle launching of init scripts.
|
|
|
|
*/
|
|
|
|
|
2008-01-14 10:35:22 +05:30
|
|
|
/*
|
2008-02-22 17:37:34 +05:30
|
|
|
* Copyright 2007-2008 Roy Marples
|
2007-11-14 20:52:04 +05:30
|
|
|
* All rights reserved
|
|
|
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2007-04-05 16:48:42 +05:30
|
|
|
*
|
2007-11-14 20:52:04 +05:30
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
2007-04-05 16:48:42 +05:30
|
|
|
*/
|
|
|
|
|
2007-08-09 20:03:20 +05:30
|
|
|
#include <sys/select.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <sys/types.h>
|
2007-09-21 14:19:43 +05:30
|
|
|
#include <sys/ioctl.h>
|
2007-04-25 18:00:24 +05:30
|
|
|
#include <sys/param.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <sys/stat.h>
|
2008-03-16 22:30:56 +05:30
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <errno.h>
|
2007-04-25 18:00:24 +05:30
|
|
|
#include <fcntl.h>
|
2007-04-12 15:38:42 +05:30
|
|
|
#include <getopt.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <limits.h>
|
2007-04-21 00:28:42 +05:30
|
|
|
#include <signal.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2007-09-21 14:19:43 +05:30
|
|
|
#include <termios.h>
|
2007-12-07 20:01:51 +05:30
|
|
|
#include <time.h>
|
2007-04-05 16:48:42 +05:30
|
|
|
#include <unistd.h>
|
|
|
|
|
2007-09-21 14:19:43 +05:30
|
|
|
#ifdef __linux__
|
|
|
|
# include <pty.h>
|
2008-01-10 04:52:04 +05:30
|
|
|
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
|
|
|
# include <util.h>
|
2007-09-21 14:19:43 +05:30
|
|
|
#else
|
|
|
|
# include <libutil.h>
|
|
|
|
#endif
|
|
|
|
|
2007-07-31 21:35:56 +05:30
|
|
|
#include "builtins.h"
|
2008-01-06 19:17:39 +05:30
|
|
|
#include "einfo.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
#include "rc.h"
|
2008-01-06 19:17:39 +05:30
|
|
|
#include "rc-misc.h"
|
2007-04-05 16:48:42 +05:30
|
|
|
#include "rc-plugin.h"
|
|
|
|
|
2007-04-12 18:48:52 +05:30
|
|
|
#define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
#define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
|
2007-04-26 16:54:07 +05:30
|
|
|
|
2007-12-05 23:18:07 +05:30
|
|
|
/* usecs to wait while we poll the fifo */
|
|
|
|
#define WAIT_INTERVAL 20000000
|
|
|
|
|
|
|
|
/* max secs to wait until a service comes up */
|
|
|
|
#define WAIT_MAX 300
|
|
|
|
|
|
|
|
#define ONE_SECOND 1000000000
|
|
|
|
|
2007-12-19 18:16:08 +05:30
|
|
|
static const char *applet = NULL;
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_STRINGLIST *applet_list = NULL;
|
|
|
|
static RC_STRINGLIST *restart_services = NULL;
|
|
|
|
static RC_STRINGLIST *need_services = NULL;
|
|
|
|
static RC_STRINGLIST *use_services = NULL;
|
|
|
|
static RC_STRINGLIST *services = NULL;
|
|
|
|
static RC_STRINGLIST *tmplist = NULL;
|
2007-11-21 21:08:07 +05:30
|
|
|
static char *service = NULL;
|
2008-03-17 18:55:56 +05:30
|
|
|
static char exclusive[PATH_MAX] = { '\0' };
|
|
|
|
static char mtime_test[PATH_MAX] = { '\0' };
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_DEPTREE *deptree = NULL;
|
|
|
|
static char *runlevel = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
static bool sighup = false;
|
|
|
|
static char *ibsave = NULL;
|
|
|
|
static bool in_background = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_HOOK hook_out = 0;
|
2007-04-21 00:28:42 +05:30
|
|
|
static pid_t service_pid = 0;
|
2007-04-25 18:00:24 +05:30
|
|
|
static char *prefix = NULL;
|
2007-04-26 16:54:07 +05:30
|
|
|
static bool prefix_locked = false;
|
2007-09-21 14:19:43 +05:30
|
|
|
static int signal_pipe[2] = { -1, -1 };
|
|
|
|
static int master_tty = -1;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_STRINGLIST *types_b = NULL;
|
|
|
|
static RC_STRINGLIST *types_n = NULL;
|
|
|
|
static RC_STRINGLIST *types_nu = NULL;
|
|
|
|
static RC_STRINGLIST *types_nua = NULL;
|
|
|
|
static RC_STRINGLIST *types_m = NULL;
|
|
|
|
static RC_STRINGLIST *types_mua = NULL;
|
2007-10-15 20:10:53 +05:30
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#ifdef __linux__
|
2008-03-16 22:30:56 +05:30
|
|
|
static void (*selinux_run_init_old)(void);
|
|
|
|
static void (*selinux_run_init_new)(int argc, char **argv);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void setup_selinux(int argc, char **argv);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void setup_selinux(int argc, char **argv)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
void *lib_handle = NULL;
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! exists(SELINUX_LIB))
|
2007-08-08 08:37:42 +05:30
|
|
|
return;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
lib_handle = dlopen(SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
|
2007-08-08 08:37:42 +05:30
|
|
|
if (! lib_handle) {
|
2008-03-16 22:30:56 +05:30
|
|
|
eerror("dlopen: %s", dlerror());
|
2007-08-08 08:37:42 +05:30
|
|
|
return;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2007-08-08 08:37:42 +05:30
|
|
|
|
2007-08-09 20:03:20 +05:30
|
|
|
selinux_run_init_old = (void (*)(void))
|
2008-03-16 22:30:56 +05:30
|
|
|
dlfunc(lib_handle, "selinux_runscript");
|
2007-08-09 20:03:20 +05:30
|
|
|
selinux_run_init_new = (void (*)(int, char **))
|
2008-03-16 22:30:56 +05:30
|
|
|
dlfunc(lib_handle, "selinux_runscript2");
|
2007-08-08 08:37:42 +05:30
|
|
|
|
2007-10-08 16:41:21 +05:30
|
|
|
/* Use new run_init if it exists, else fall back to old */
|
2007-08-08 08:37:42 +05:30
|
|
|
if (selinux_run_init_new)
|
2008-03-16 22:30:56 +05:30
|
|
|
selinux_run_init_new(argc, argv);
|
2007-08-08 08:37:42 +05:30
|
|
|
else if (selinux_run_init_old)
|
2008-03-16 22:30:56 +05:30
|
|
|
selinux_run_init_old();
|
2007-08-08 08:37:42 +05:30
|
|
|
else
|
|
|
|
/* This shouldnt happen... probably corrupt lib */
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("run_init is missing from runscript_selinux.so!");
|
2007-08-08 08:37:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
dlclose(lib_handle);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void handle_signal(int sig)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
int serrno = errno;
|
|
|
|
char signame[10] = { '\0' };
|
2007-09-21 14:19:43 +05:30
|
|
|
struct winsize ws;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
switch (sig) {
|
2008-03-16 22:30:56 +05:30
|
|
|
case SIGHUP:
|
|
|
|
sighup = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGCHLD:
|
|
|
|
if (signal_pipe[1] > -1) {
|
|
|
|
if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
|
|
|
|
eerror("%s: send: %s", service, strerror(errno));
|
|
|
|
} else
|
|
|
|
rc_waitpid (-1);
|
|
|
|
break;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
case SIGWINCH:
|
|
|
|
if (master_tty >= 0) {
|
|
|
|
ioctl(fileno(stdout), TIOCGWINSZ, &ws);
|
|
|
|
ioctl(master_tty, TIOCSWINSZ, &ws);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIGINT:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf(signame, sizeof(signame), "SIGINT");
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SIGTERM:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf(signame, sizeof(signame), "SIGTERM");
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
case SIGQUIT:
|
|
|
|
if (! signame[0])
|
|
|
|
snprintf(signame, sizeof(signame), "SIGQUIT");
|
|
|
|
/* Send the signal to our children too */
|
|
|
|
if (service_pid > 0)
|
|
|
|
kill(service_pid, sig);
|
|
|
|
eerrorx("%s: caught %s, aborting", applet, signame);
|
|
|
|
/* NOTREACHED */
|
|
|
|
|
|
|
|
default:
|
|
|
|
eerror("%s: caught unknown signal %d", applet, sig);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore errno */
|
|
|
|
errno = serrno;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static time_t get_mtime(const char *pathname, bool follow_link)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
struct stat buf;
|
|
|
|
int retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! pathname)
|
2008-03-16 22:30:56 +05:30
|
|
|
return 0;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf);
|
2007-04-11 18:14:47 +05:30
|
|
|
if (! retval)
|
2008-03-16 22:30:56 +05:30
|
|
|
return buf.st_mtime;
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
errno = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
return 0;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static const char *const tests[] = {
|
|
|
|
"starting", "started", "stopping", "inactive", "wasinactive", NULL
|
|
|
|
};
|
|
|
|
static bool in_control()
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-17 18:55:56 +05:30
|
|
|
char file[PATH_MAX];
|
2008-03-16 22:30:56 +05:30
|
|
|
time_t m;
|
2007-04-11 18:14:47 +05:30
|
|
|
time_t mtime;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (sighup)
|
2008-03-16 22:30:56 +05:30
|
|
|
return false;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-17 23:27:07 +05:30
|
|
|
if (! *mtime_test || ! exists(mtime_test))
|
2008-03-16 22:30:56 +05:30
|
|
|
return false;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_service_state(applet) & RC_SERVICE_STOPPED)
|
|
|
|
return false;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! (mtime = get_mtime(mtime_test, false)))
|
|
|
|
return false;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
while (tests[i]) {
|
2008-03-17 18:55:56 +05:30
|
|
|
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet);
|
|
|
|
if (exists(file)) {
|
|
|
|
m = get_mtime(file, false);
|
|
|
|
if (mtime < m && m != 0)
|
2008-03-16 22:30:56 +05:30
|
|
|
return false;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return true;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void uncoldplug()
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-17 18:55:56 +05:30
|
|
|
char file[PATH_MAX];
|
|
|
|
|
|
|
|
snprintf(file, sizeof(file), RC_SVCDIR "/coldplugged/%s", applet);
|
|
|
|
if (exists(file) && unlink(file) != 0)
|
|
|
|
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void start_services(RC_STRINGLIST *list) {
|
|
|
|
RC_STRING *svc;
|
|
|
|
RC_SERVICE state = rc_service_state (service);
|
2007-04-30 18:48:42 +05:30
|
|
|
|
|
|
|
if (! list)
|
|
|
|
return;
|
|
|
|
|
2007-10-26 17:52:26 +05:30
|
|
|
if (state & RC_SERVICE_INACTIVE ||
|
2008-01-11 21:21:40 +05:30
|
|
|
state & RC_SERVICE_WASINACTIVE ||
|
|
|
|
state & RC_SERVICE_STARTING ||
|
|
|
|
state & RC_SERVICE_STARTED)
|
2007-04-30 18:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(svc, list, entries) {
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
2007-09-28 20:23:38 +05:30
|
|
|
if (state & RC_SERVICE_INACTIVE ||
|
2008-01-11 21:21:40 +05:30
|
|
|
state & RC_SERVICE_WASINACTIVE)
|
2007-09-28 20:23:38 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_schedule_start(service, svc->value);
|
|
|
|
ewarn("WARNING: %s is scheduled to started"
|
|
|
|
" when %s has started",
|
|
|
|
svc->value, applet);
|
2007-04-30 18:48:42 +05:30
|
|
|
} else
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_start(svc->value);
|
2007-04-30 18:48:42 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void restore_state(void)
|
2007-10-10 02:50:10 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state;
|
2007-10-10 02:50:10 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_in_plugin || ! in_control())
|
2007-10-10 02:50:10 +05:30
|
|
|
return;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
state = rc_service_state(applet);
|
2007-10-10 02:50:10 +05:30
|
|
|
if (state & RC_SERVICE_STOPPING) {
|
|
|
|
if (state & RC_SERVICE_WASINACTIVE)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(applet, RC_SERVICE_INACTIVE);
|
2007-10-10 02:50:10 +05:30
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(applet, RC_SERVICE_STARTED);
|
|
|
|
if (rc_runlevel_stopping())
|
|
|
|
rc_service_mark(applet, RC_SERVICE_FAILED);
|
2007-10-10 02:50:10 +05:30
|
|
|
} else if (state & RC_SERVICE_STARTING) {
|
|
|
|
if (state & RC_SERVICE_WASINACTIVE)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(applet, RC_SERVICE_INACTIVE);
|
2007-10-10 02:50:10 +05:30
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(applet, RC_SERVICE_STOPPED);
|
|
|
|
if (rc_runlevel_starting())
|
|
|
|
rc_service_mark(applet, RC_SERVICE_FAILED);
|
2007-10-10 02:50:10 +05:30
|
|
|
}
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
if (*exclusive) {
|
2008-03-16 22:30:56 +05:30
|
|
|
unlink(exclusive);
|
2008-03-17 18:55:56 +05:30
|
|
|
*exclusive = '\0';
|
|
|
|
}
|
2007-10-10 02:50:10 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void cleanup(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
restore_state();
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-07-11 19:58:54 +05:30
|
|
|
if (! rc_in_plugin) {
|
|
|
|
if (prefix_locked)
|
2008-03-16 22:30:56 +05:30
|
|
|
unlink(PREFIX_LOCK);
|
2007-10-10 02:50:10 +05:30
|
|
|
if (hook_out) {
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(hook_out, applet);
|
2007-10-10 02:50:10 +05:30
|
|
|
if (hook_out == RC_HOOK_SERVICE_START_DONE)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet);
|
2007-10-10 02:50:10 +05:30
|
|
|
else if (hook_out == RC_HOOK_SERVICE_STOP_DONE)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet);
|
2007-10-10 02:50:10 +05:30
|
|
|
}
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-07-11 19:58:54 +05:30
|
|
|
if (restart_services)
|
2008-03-16 22:30:56 +05:30
|
|
|
start_services(restart_services);
|
2007-04-30 18:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(types_b);
|
|
|
|
rc_stringlist_free(types_n);
|
|
|
|
rc_stringlist_free(types_nu);
|
|
|
|
rc_stringlist_free(types_nua);
|
|
|
|
rc_stringlist_free(types_m);
|
|
|
|
rc_stringlist_free(types_mua);
|
|
|
|
|
|
|
|
rc_plugin_unload();
|
|
|
|
rc_deptree_free(deptree);
|
|
|
|
|
|
|
|
rc_stringlist_free(restart_services);
|
|
|
|
rc_stringlist_free(need_services);
|
|
|
|
rc_stringlist_free(use_services);
|
|
|
|
rc_stringlist_free(services);
|
|
|
|
rc_stringlist_free(applet_list);
|
|
|
|
rc_stringlist_free(tmplist);
|
2007-04-25 18:00:24 +05:30
|
|
|
free (ibsave);
|
2008-03-16 22:30:56 +05:30
|
|
|
free(service);
|
|
|
|
free(prefix);
|
|
|
|
free(runlevel);
|
2008-03-17 18:55:56 +05:30
|
|
|
|
|
|
|
if (*mtime_test && ! rc_in_plugin)
|
|
|
|
unlink(mtime_test);
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
|
2007-04-25 18:00:24 +05:30
|
|
|
unsigned int i;
|
2008-03-16 22:30:56 +05:30
|
|
|
const char *ec = ecolor(ECOLOR_HILITE);
|
|
|
|
const char *ec_normal = ecolor(ECOLOR_NORMAL);
|
2007-04-25 18:00:24 +05:30
|
|
|
ssize_t ret = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
int fd = fileno(stdout);
|
2007-04-25 18:00:24 +05:30
|
|
|
|
|
|
|
for (i = 0; i < bytes; i++) {
|
|
|
|
/* We don't prefix escape codes, like eend */
|
|
|
|
if (buffer[i] == '\033')
|
|
|
|
*prefixed = true;
|
|
|
|
|
|
|
|
if (! *prefixed) {
|
2008-03-16 22:30:56 +05:30
|
|
|
ret += write(fd, ec, strlen(ec));
|
|
|
|
ret += write(fd, prefix, strlen(prefix));
|
|
|
|
ret += write(fd, ec_normal, strlen(ec_normal));
|
|
|
|
ret += write(fd, "|", 1);
|
2007-04-25 18:00:24 +05:30
|
|
|
*prefixed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer[i] == '\n')
|
|
|
|
*prefixed = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
ret += write(fd, buffer + i, 1);
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return ret;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static bool svc_exec(const char *arg1, const char *arg2)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-25 18:00:24 +05:30
|
|
|
bool execok;
|
2008-03-16 22:30:56 +05:30
|
|
|
int fdout = fileno(stdout);
|
2007-09-21 14:19:43 +05:30
|
|
|
struct termios tt;
|
|
|
|
struct winsize ws;
|
|
|
|
int i;
|
2007-10-09 18:22:09 +05:30
|
|
|
int flags = 0;
|
2007-09-21 14:19:43 +05:30
|
|
|
fd_set rset;
|
|
|
|
int s;
|
2007-10-12 05:31:33 +05:30
|
|
|
char *buffer;
|
2007-09-21 14:19:43 +05:30
|
|
|
size_t bytes;
|
|
|
|
bool prefixed = false;
|
|
|
|
int selfd;
|
|
|
|
int slave_tty;
|
|
|
|
|
|
|
|
/* Setup our signal pipe */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (pipe(signal_pipe) == -1)
|
|
|
|
eerrorx("%s: pipe: %s", service, applet);
|
2007-09-21 14:19:43 +05:30
|
|
|
for (i = 0; i < 2; i++)
|
2008-03-16 22:30:56 +05:30
|
|
|
if ((flags = fcntl(signal_pipe[i], F_GETFD, 0) == -1 ||
|
|
|
|
fcntl(signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) == -1))
|
|
|
|
eerrorx("%s: fcntl: %s", service, strerror(errno));
|
2007-09-21 14:19:43 +05:30
|
|
|
|
|
|
|
/* Open a pty for our prefixed output
|
|
|
|
* We do this instead of mapping pipes to stdout, stderr so that
|
|
|
|
* programs can tell if they're attached to a tty or not.
|
|
|
|
* The only loss is that we can no longer tell the difference
|
|
|
|
* between the childs stdout or stderr */
|
|
|
|
master_tty = slave_tty = -1;
|
2008-03-16 22:30:56 +05:30
|
|
|
if (prefix && isatty(fdout)) {
|
|
|
|
tcgetattr(fdout, &tt);
|
|
|
|
ioctl(fdout, TIOCGWINSZ, &ws);
|
2007-09-21 14:19:43 +05:30
|
|
|
|
|
|
|
/* If the below call fails due to not enough ptys then we don't
|
|
|
|
* prefix the output, but we still work */
|
2008-03-16 22:30:56 +05:30
|
|
|
openpty(&master_tty, &slave_tty, NULL, &tt, &ws);
|
2008-02-29 02:56:53 +05:30
|
|
|
|
|
|
|
if (master_tty >= 0 &&
|
2008-03-16 22:30:56 +05:30
|
|
|
(flags = fcntl(master_tty, F_GETFD, 0)) == 0)
|
|
|
|
fcntl(master_tty, F_SETFD, flags | FD_CLOEXEC);
|
2008-02-29 02:56:53 +05:30
|
|
|
|
|
|
|
if (slave_tty >=0 &&
|
2008-03-16 22:30:56 +05:30
|
|
|
(flags = fcntl(slave_tty, F_GETFD, 0)) == 0)
|
|
|
|
fcntl(slave_tty, F_SETFD, flags | FD_CLOEXEC);
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
|
2008-02-20 03:15:01 +05:30
|
|
|
service_pid = fork();
|
2007-04-21 00:28:42 +05:30
|
|
|
if (service_pid == -1)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: fork: %s", service, strerror(errno));
|
2007-04-21 00:28:42 +05:30
|
|
|
if (service_pid == 0) {
|
2007-09-21 14:19:43 +05:30
|
|
|
if (slave_tty >= 0) {
|
2008-03-16 22:30:56 +05:30
|
|
|
dup2(slave_tty, 1);
|
|
|
|
dup2(slave_tty, 2);
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (exists(RC_SVCDIR "/runscript.sh")) {
|
|
|
|
execl(RC_SVCDIR "/runscript.sh", RC_SVCDIR "/runscript.sh",
|
|
|
|
service, arg1, arg2, (char *) NULL);
|
|
|
|
eerror("%s: exec `" RC_SVCDIR "/runscript.sh': %s",
|
|
|
|
service, strerror(errno));
|
|
|
|
_exit(EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
execl(RC_LIBDIR "/sh/runscript.sh", RC_LIBDIR "/sh/runscript.sh",
|
|
|
|
service, arg1, arg2, (char *) NULL);
|
|
|
|
eerror("%s: exec `" RC_LIBDIR "/sh/runscript.sh': %s",
|
|
|
|
service, strerror(errno));
|
|
|
|
_exit(EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
selfd = MAX(master_tty, signal_pipe[0]) + 1;
|
|
|
|
buffer = xmalloc(sizeof(char) * BUFSIZ);
|
2008-01-21 21:40:38 +05:30
|
|
|
for (;;) {
|
2008-03-16 22:30:56 +05:30
|
|
|
FD_ZERO(&rset);
|
|
|
|
FD_SET(signal_pipe[0], &rset);
|
2007-09-21 14:19:43 +05:30
|
|
|
if (master_tty >= 0)
|
2008-03-16 22:30:56 +05:30
|
|
|
FD_SET(master_tty, &rset);
|
2007-09-21 14:19:43 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if ((s = select(selfd, &rset, NULL, NULL, NULL)) == -1) {
|
2007-09-21 14:19:43 +05:30
|
|
|
if (errno != EINTR) {
|
2008-03-16 22:30:56 +05:30
|
|
|
eerror("%s: select: %s", service, strerror(errno));
|
2007-09-21 14:19:43 +05:30
|
|
|
break;
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
}
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-09-21 14:19:43 +05:30
|
|
|
if (s > 0) {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (master_tty >= 0 && FD_ISSET(master_tty, &rset)) {
|
|
|
|
bytes = read(master_tty, buffer, BUFSIZ);
|
|
|
|
write_prefix(buffer, bytes, &prefixed);
|
2007-09-21 14:19:43 +05:30
|
|
|
}
|
2007-10-23 01:03:42 +05:30
|
|
|
|
|
|
|
/* Only SIGCHLD signals come down this pipe */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (FD_ISSET(signal_pipe[0], &rset))
|
2007-10-23 01:03:42 +05:30
|
|
|
break;
|
2007-09-21 14:19:43 +05:30
|
|
|
}
|
|
|
|
}
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
free(buffer);
|
|
|
|
close(signal_pipe[0]);
|
|
|
|
close(signal_pipe[1]);
|
2007-09-21 14:19:43 +05:30
|
|
|
signal_pipe[0] = signal_pipe[1] = -1;
|
|
|
|
|
|
|
|
if (master_tty >= 0) {
|
2008-02-01 18:50:19 +05:30
|
|
|
/* Why did we do this? */
|
|
|
|
/* signal (SIGWINCH, SIG_IGN); */
|
2008-03-16 22:30:56 +05:30
|
|
|
close(master_tty);
|
2007-09-21 14:19:43 +05:30
|
|
|
master_tty = -1;
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
execok = rc_waitpid(service_pid) == 0 ? true : false;
|
2007-04-21 00:28:42 +05:30
|
|
|
service_pid = 0;
|
2007-04-25 18:00:24 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return execok;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static bool svc_wait(const char *svc)
|
2007-12-05 23:18:07 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
char fifo[PATH_MAX];
|
2007-12-05 23:18:07 +05:30
|
|
|
struct timespec ts;
|
|
|
|
int nloops = WAIT_MAX * (ONE_SECOND / WAIT_INTERVAL);
|
|
|
|
bool retval = false;
|
|
|
|
bool forever = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRINGLIST *keywords;
|
|
|
|
RC_STRING *s;
|
2007-12-05 23:18:07 +05:30
|
|
|
|
2008-01-31 23:31:20 +05:30
|
|
|
/* Some services don't have a timeout, like fsck */
|
2008-03-16 22:30:56 +05:30
|
|
|
keywords = rc_deptree_depend(deptree, svc, "keyword");
|
|
|
|
if (keywords) {
|
|
|
|
TAILQ_FOREACH(s, keywords, entries) {
|
|
|
|
if (strcmp (s->value, "notimeout") == 0) {
|
|
|
|
forever = true;
|
|
|
|
break;
|
|
|
|
}
|
2007-12-05 23:18:07 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free (keywords);
|
2007-12-05 23:18:07 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", basename_c(svc));
|
2007-12-05 23:18:07 +05:30
|
|
|
ts.tv_sec = 0;
|
|
|
|
ts.tv_nsec = WAIT_INTERVAL;
|
|
|
|
|
|
|
|
while (nloops) {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! exists(fifo)) {
|
2007-12-05 23:18:07 +05:30
|
|
|
retval = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (nanosleep(&ts, NULL) == -1) {
|
2007-12-05 23:18:07 +05:30
|
|
|
if (errno != EINTR)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! forever)
|
|
|
|
nloops --;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! exists(fifo))
|
2007-12-05 23:18:07 +05:30
|
|
|
retval = true;
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-12-05 23:18:07 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static RC_SERVICE svc_status(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
char status[10];
|
|
|
|
int (*e) (const char *fmt, ...) = &einfo;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state = rc_service_state(service);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-09-28 20:23:38 +05:30
|
|
|
if (state & RC_SERVICE_STOPPING) {
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(status, sizeof(status), "stopping");
|
2007-04-11 18:14:47 +05:30
|
|
|
e = &ewarn;
|
2007-11-01 04:04:26 +05:30
|
|
|
} else if (state & RC_SERVICE_STARTING) {
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(status, sizeof(status), "starting");
|
2007-04-11 18:14:47 +05:30
|
|
|
e = &ewarn;
|
2007-09-28 20:23:38 +05:30
|
|
|
} else if (state & RC_SERVICE_INACTIVE) {
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(status, sizeof(status), "inactive");
|
2007-04-11 18:14:47 +05:30
|
|
|
e = &ewarn;
|
2007-09-28 20:23:38 +05:30
|
|
|
} else if (state & RC_SERVICE_STARTED) {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_service_daemons_crashed(service)) {
|
|
|
|
snprintf(status, sizeof (status), "crashed");
|
2007-09-28 20:34:15 +05:30
|
|
|
e = &eerror;
|
|
|
|
} else
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(status, sizeof(status), "started");
|
2007-04-11 18:14:47 +05:30
|
|
|
} else
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(status, sizeof(status), "stopped");
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
e("status: %s", status);
|
|
|
|
return state;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void make_exclusive(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
/* We create a fifo so that other services can wait until we complete */
|
2008-03-17 18:55:56 +05:30
|
|
|
if (! *exclusive)
|
|
|
|
snprintf(exclusive, sizeof(exclusive), RC_SVCDIR "/exclusive/%s",
|
|
|
|
applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST &&
|
2008-01-11 21:21:40 +05:30
|
|
|
(errno != EACCES || geteuid () == 0))
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("%s: unable to create fifo `%s': %s",
|
2008-03-16 22:30:56 +05:30
|
|
|
applet, exclusive, strerror(errno));
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
snprintf(mtime_test, sizeof(mtime_test), RC_SVCDIR "/exclusive/%s.%d", applet, getpid());
|
2008-03-16 22:30:56 +05:30
|
|
|
|
|
|
|
if (exists(mtime_test) && unlink(mtime_test) != 0) {
|
|
|
|
eerror("%s: unlink `%s': %s",
|
|
|
|
applet, mtime_test, strerror(errno));
|
2008-03-17 18:55:56 +05:30
|
|
|
*mtime_test = '\0';
|
2007-04-11 18:14:47 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (symlink(service, mtime_test) != 0) {
|
|
|
|
eerror("%s: symlink `%s' to `%s': %s",
|
|
|
|
applet, service, mtime_test, strerror(errno));
|
2008-03-17 18:55:56 +05:30
|
|
|
*mtime_test = '\0';
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void unlink_mtime_test(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
if (unlink(mtime_test) != 0)
|
|
|
|
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
|
2008-03-17 18:55:56 +05:30
|
|
|
*mtime_test = '\0';
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void get_started_services(void)
|
|
|
|
{
|
|
|
|
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
|
|
|
|
rc_stringlist_free(restart_services);
|
|
|
|
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (tmp) {
|
|
|
|
if (restart_services) {
|
|
|
|
TAILQ_CONCAT(restart_services, tmp, entries);
|
|
|
|
free(tmp);
|
|
|
|
} else
|
|
|
|
restart_services = tmp;
|
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_types(void)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
types_b = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_b, "broken");
|
|
|
|
|
|
|
|
types_n = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_n, "ineed");
|
|
|
|
|
|
|
|
types_nu = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_nu, "ineed");
|
|
|
|
rc_stringlist_add(types_nu, "iuse");
|
|
|
|
|
|
|
|
types_nua = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_nua, "ineed");
|
|
|
|
rc_stringlist_add(types_nua, "iuse");
|
|
|
|
rc_stringlist_add(types_nua, "iafter");
|
|
|
|
|
|
|
|
types_m = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_m, "needsme");
|
|
|
|
|
|
|
|
types_mua = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(types_mua, "needsme");
|
|
|
|
rc_stringlist_add(types_mua, "usesme");
|
|
|
|
rc_stringlist_add(types_mua, "beforeme");
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void svc_start(bool deps)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
bool started;
|
|
|
|
bool background = false;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRING *svc;
|
|
|
|
RC_STRING *svc2;
|
2007-04-11 18:14:47 +05:30
|
|
|
int depoptions = RC_DEP_TRACE;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state;
|
|
|
|
bool first;
|
|
|
|
int n;
|
|
|
|
size_t len;
|
|
|
|
char *p;
|
|
|
|
char *tmp;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
state = rc_service_state(service);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_yesno(getenv("IN_HOTPLUG")) || in_background) {
|
2007-09-28 20:23:38 +05:30
|
|
|
if (! state & RC_SERVICE_INACTIVE &&
|
2008-01-11 21:21:40 +05:30
|
|
|
! state & RC_SERVICE_STOPPED)
|
2008-03-16 22:30:56 +05:30
|
|
|
exit(EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
background = true;
|
|
|
|
}
|
|
|
|
|
2007-11-16 17:25:08 +05:30
|
|
|
if (state & RC_SERVICE_STARTED) {
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarn("WARNING: %s has already been started", applet);
|
2007-11-16 17:25:08 +05:30
|
|
|
return;
|
|
|
|
} else if (state & RC_SERVICE_STARTING)
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarnx("WARNING: %s is already starting", applet);
|
2007-09-28 20:23:38 +05:30
|
|
|
else if (state & RC_SERVICE_STOPPING)
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarnx("WARNING: %s is stopping", applet);
|
2007-09-28 20:23:38 +05:30
|
|
|
else if (state & RC_SERVICE_INACTIVE && ! background)
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarnx("WARNING: %s has already started, but is inactive", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! rc_service_mark(service, RC_SERVICE_STARTING)) {
|
2008-03-06 17:04:38 +05:30
|
|
|
if (errno == EACCES)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: superuser access required", applet);
|
|
|
|
eerrorx("ERROR: %s has been started by something else", applet);
|
2008-03-06 17:04:38 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
make_exclusive();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-11-19 19:16:09 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_START_OUT;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_START_IN, applet);
|
2007-11-19 19:16:09 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_conf_yesno("rc_depend_strict"))
|
2007-07-21 18:19:51 +05:30
|
|
|
depoptions |= RC_DEP_STRICT;
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
if (deps) {
|
2008-03-17 20:01:44 +05:30
|
|
|
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("failed to load deptree");
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! types_b)
|
|
|
|
setup_types();
|
|
|
|
|
|
|
|
services = rc_deptree_depends(deptree, types_b, applet_list,
|
2008-03-17 20:01:44 +05:30
|
|
|
runlevel, 0);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (services && TAILQ_FIRST(services)) {
|
|
|
|
eerrorn("ERROR: `%s' needs ", applet);
|
2008-03-16 22:30:56 +05:30
|
|
|
first = true;
|
|
|
|
TAILQ_FOREACH(svc, services, entries) {
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
fprintf(stderr, ", ");
|
|
|
|
fprintf(stderr, "%s", svc->value);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
exit(EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(services);
|
2007-04-11 18:14:47 +05:30
|
|
|
services = NULL;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
need_services = rc_deptree_depends(deptree, types_n, applet_list,
|
2008-03-17 20:01:44 +05:30
|
|
|
runlevel, depoptions);
|
2008-03-16 22:30:56 +05:30
|
|
|
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
|
2008-03-17 20:01:44 +05:30
|
|
|
runlevel, depoptions);
|
2008-03-16 22:30:56 +05:30
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
if (! rc_runlevel_starting() && use_services)
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(svc, use_services, entries)
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
|
|
|
pid_t pid = rc_service_start(svc->value);
|
|
|
|
if (! rc_conf_yesno("rc_parallel"))
|
|
|
|
rc_waitpid(pid);
|
2007-04-21 00:28:42 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Now wait for them to start */
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_deptree_depends(deptree, types_nua, applet_list,
|
2008-03-17 20:01:44 +05:30
|
|
|
runlevel, depoptions);
|
|
|
|
|
|
|
|
if (services) {
|
|
|
|
/* We use tmplist to hold our scheduled by list */
|
|
|
|
tmplist = NULL;
|
|
|
|
TAILQ_FOREACH(svc, services, entries) {
|
|
|
|
RC_SERVICE svcs = rc_service_state(svc->value);
|
|
|
|
if (svcs & RC_SERVICE_STARTED)
|
2007-07-03 14:08:27 +05:30
|
|
|
continue;
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2008-03-17 20:01:44 +05:30
|
|
|
/* Don't wait for services which went inactive but are now in
|
|
|
|
* starting state which we are after */
|
|
|
|
if (svcs & RC_SERVICE_STARTING &&
|
|
|
|
svcs & RC_SERVICE_WASINACTIVE) {
|
|
|
|
TAILQ_FOREACH(svc2, use_services, entries) {
|
|
|
|
if (strcmp (svc->value, svc2->value) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (! svc2)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! svc_wait(svc->value))
|
|
|
|
eerror ("%s: timed out waiting for %s",
|
2008-03-16 22:30:56 +05:30
|
|
|
applet, svc->value);
|
2008-03-17 20:01:44 +05:30
|
|
|
if (! need_services)
|
|
|
|
continue;
|
|
|
|
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
|
|
|
|
continue;
|
|
|
|
TAILQ_FOREACH(svc2, need_services, entries) {
|
|
|
|
if (strcmp (svc->value, svc2->value) == 0) {
|
|
|
|
if (svcs & RC_SERVICE_INACTIVE ||
|
|
|
|
svcs & RC_SERVICE_WASINACTIVE)
|
|
|
|
{
|
|
|
|
if (! tmplist)
|
|
|
|
tmplist = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(tmplist, svc->value);
|
|
|
|
} else
|
|
|
|
eerrorx("ERROR: cannot start %s as"
|
|
|
|
" %s would not start",
|
|
|
|
applet, svc->value);
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-17 20:01:44 +05:30
|
|
|
if (tmplist && TAILQ_FIRST(tmplist)) {
|
|
|
|
/* Set the state now, then unlink our exclusive so that
|
|
|
|
our scheduled list is preserved */
|
|
|
|
rc_service_mark(service, RC_SERVICE_STOPPED);
|
|
|
|
unlink_mtime_test();
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(use_services);
|
|
|
|
use_services = NULL;
|
2008-03-17 20:01:44 +05:30
|
|
|
len = 0;
|
|
|
|
n = 0;
|
|
|
|
TAILQ_FOREACH(svc, tmplist, entries) {
|
|
|
|
rc_service_schedule_start(svc->value, service);
|
|
|
|
use_services = rc_deptree_depend(deptree, "iprovide",
|
|
|
|
svc->value);
|
|
|
|
TAILQ_FOREACH (svc2, use_services, entries)
|
|
|
|
rc_service_schedule_start(svc2->value, service);
|
|
|
|
rc_stringlist_free(use_services);
|
|
|
|
use_services = NULL;
|
|
|
|
len += strlen(svc->value) + 2;
|
|
|
|
n++;
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-17 20:01:44 +05:30
|
|
|
len += 5;
|
|
|
|
tmp = p = xmalloc(sizeof(char) * len);
|
|
|
|
TAILQ_FOREACH(svc, tmplist, entries) {
|
|
|
|
if (p != tmp)
|
|
|
|
p += snprintf(p, len, ", ");
|
|
|
|
p += snprintf(p, len, "%s", svc->value);
|
|
|
|
}
|
|
|
|
free(tmp);
|
|
|
|
rc_stringlist_free(tmplist);
|
|
|
|
tmplist = NULL;
|
|
|
|
ewarnx("WARNING: %s is scheduled to start when %s has started",
|
|
|
|
applet, tmp);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-17 20:01:44 +05:30
|
|
|
rc_stringlist_free(services);
|
|
|
|
services = NULL;
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (ibsave)
|
2008-03-16 22:30:56 +05:30
|
|
|
setenv("IN_BACKGROUND", ibsave, 1);
|
2007-10-10 02:50:10 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_START_DONE;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_START_NOW, applet);
|
|
|
|
started = svc_exec("start", NULL);
|
2007-04-11 18:14:47 +05:30
|
|
|
if (ibsave)
|
2008-03-16 22:30:56 +05:30
|
|
|
unsetenv("IN_BACKGROUND");
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (in_control()) {
|
2007-10-10 02:50:10 +05:30
|
|
|
if (! started)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("ERROR: %s failed to start", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_service_state(service) & RC_SERVICE_INACTIVE)
|
|
|
|
ewarnx("WARNING: %s has started, but is inactive", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarnx("WARNING: %s not under our control, aborting", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(service, RC_SERVICE_STARTED);
|
|
|
|
unlink_mtime_test();
|
2007-10-10 02:50:10 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_START_OUT;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_START_DONE, applet);
|
2008-03-17 23:27:07 +05:30
|
|
|
unlink(exclusive);
|
2007-10-10 02:50:10 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Now start any scheduled services */
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_services_scheduled(service);
|
|
|
|
if (services) {
|
|
|
|
TAILQ_FOREACH(svc, services, entries)
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
|
|
|
rc_service_start(svc->value);
|
|
|
|
rc_stringlist_free(services);
|
|
|
|
services = NULL;
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Do the same for any services we provide */
|
2008-03-16 22:30:56 +05:30
|
|
|
tmplist = rc_deptree_depend(deptree, "iprovide", applet);
|
|
|
|
if (tmplist) {
|
|
|
|
TAILQ_FOREACH(svc, tmplist, entries) {
|
|
|
|
services = rc_services_scheduled(svc->value);
|
|
|
|
if (services) {
|
|
|
|
TAILQ_FOREACH(svc2, services, entries)
|
|
|
|
if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED)
|
|
|
|
rc_service_start(svc2->value);
|
|
|
|
rc_stringlist_free(services);
|
|
|
|
services = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rc_stringlist_free(tmplist);
|
|
|
|
tmplist = NULL;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
hook_out = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_START_OUT, applet);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void svc_stop(bool deps)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
bool stopped;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state = rc_service_state(service);
|
|
|
|
int depoptions = RC_DEP_TRACE;
|
|
|
|
RC_STRING *svc;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_runlevel_stopping() &&
|
2008-01-11 21:21:40 +05:30
|
|
|
state & RC_SERVICE_FAILED)
|
2007-04-11 18:14:47 +05:30
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_yesno(getenv("IN_HOTPLUG")) || in_background)
|
2008-01-14 10:35:22 +05:30
|
|
|
if (! (state & RC_SERVICE_STARTED) &&
|
2008-01-11 21:21:40 +05:30
|
|
|
! (state & RC_SERVICE_INACTIVE))
|
2007-04-11 18:14:47 +05:30
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
2007-11-16 17:25:08 +05:30
|
|
|
if (state & RC_SERVICE_STOPPED) {
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarn("WARNING: %s is already stopped", applet);
|
2007-11-16 17:25:08 +05:30
|
|
|
return;
|
|
|
|
} else if (state & RC_SERVICE_STOPPING)
|
2008-03-16 22:30:56 +05:30
|
|
|
ewarnx("WARNING: %s is already stopping", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! rc_service_mark(service, RC_SERVICE_STOPPING)) {
|
2008-03-06 17:04:38 +05:30
|
|
|
if (errno == EACCES)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("%s: superuser access required", applet);
|
|
|
|
eerrorx("ERROR: %s has been stopped by something else", applet);
|
2008-03-06 17:04:38 +05:30
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
make_exclusive();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-11-19 19:16:09 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_STOP_OUT;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_STOP_IN, applet);
|
2007-11-19 19:16:09 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! rc_runlevel_stopping() &&
|
|
|
|
rc_service_in_runlevel(service, RC_LEVEL_BOOT))
|
2007-04-11 18:14:47 +05:30
|
|
|
ewarn ("WARNING: you are stopping a boot service");
|
|
|
|
|
2007-09-28 20:23:38 +05:30
|
|
|
if (deps && ! (state & RC_SERVICE_WASINACTIVE)) {
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_conf_yesno("rc_depend_strict"))
|
2007-04-11 18:14:47 +05:30
|
|
|
depoptions |= RC_DEP_STRICT;
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
|
2007-04-11 18:14:47 +05:30
|
|
|
eerrorx ("failed to load deptree");
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! types_m)
|
|
|
|
setup_types();
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
tmplist = NULL;
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_deptree_depends(deptree, types_m, applet_list,
|
|
|
|
runlevel, depoptions);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (services) {
|
|
|
|
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
|
|
|
RC_SERVICE svcs = rc_service_state(svc->value);
|
2008-01-14 10:35:22 +05:30
|
|
|
if (svcs & RC_SERVICE_STARTED ||
|
2008-03-17 18:55:56 +05:30
|
|
|
svcs & RC_SERVICE_INACTIVE)
|
2007-04-11 18:14:47 +05:30
|
|
|
{
|
2008-03-17 18:55:56 +05:30
|
|
|
svc_wait(svc->value);
|
|
|
|
svcs = rc_service_state(svc->value);
|
|
|
|
if (svcs & RC_SERVICE_STARTED ||
|
|
|
|
svcs & RC_SERVICE_INACTIVE)
|
|
|
|
{
|
|
|
|
pid_t pid = rc_service_stop(svc->value);
|
|
|
|
if (! rc_conf_yesno("rc_parallel"))
|
|
|
|
rc_waitpid(pid);
|
|
|
|
if (! tmplist)
|
|
|
|
tmplist = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(tmplist, svc->value);
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
2008-03-17 18:55:56 +05:30
|
|
|
rc_stringlist_free(services);
|
|
|
|
services = NULL;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
if (tmplist) {
|
|
|
|
TAILQ_FOREACH(svc, tmplist, entries) {
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
|
|
|
continue;
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
/* We used to loop 3 times here - maybe re-do this if needed */
|
|
|
|
svc_wait(svc->value);
|
|
|
|
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
|
|
|
|
if (rc_runlevel_stopping()) {
|
|
|
|
/* If shutting down, we should stop even
|
|
|
|
* if a dependant failed */
|
|
|
|
if (runlevel &&
|
|
|
|
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
|
|
|
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
|
|
|
|
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
|
|
|
|
continue;
|
|
|
|
rc_service_mark(service, RC_SERVICE_FAILED);
|
|
|
|
}
|
2007-08-17 17:01:36 +05:30
|
|
|
|
2008-03-17 18:55:56 +05:30
|
|
|
eerrorx("ERROR: cannot stop %s as %s is still up",
|
|
|
|
applet, svc->value);
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2008-03-17 18:55:56 +05:30
|
|
|
rc_stringlist_free(tmplist);
|
|
|
|
tmplist = NULL;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* We now wait for other services that may use us and are stopping
|
|
|
|
This is important when a runlevel stops */
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_deptree_depends(deptree, types_mua, applet_list,
|
|
|
|
runlevel, depoptions);
|
2008-03-17 18:55:56 +05:30
|
|
|
if (services) {
|
|
|
|
TAILQ_FOREACH(svc, services, entries) {
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
|
|
|
continue;
|
|
|
|
svc_wait(svc->value);
|
|
|
|
}
|
|
|
|
rc_stringlist_free (services);
|
|
|
|
services = NULL;
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-05 04:22:48 +05:30
|
|
|
/* If we're stopping localmount, set LC_ALL=C so that
|
|
|
|
* bash doesn't load anything blocking the unmounting of /usr */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(applet, "localmount") == 0)
|
|
|
|
setenv("LC_ALL", "C", 1);
|
2008-03-05 04:22:48 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
if (ibsave)
|
2008-03-16 22:30:56 +05:30
|
|
|
setenv("IN_BACKGROUND", ibsave, 1);
|
2007-10-10 02:50:10 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_STOP_DONE;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_STOP_NOW, applet);
|
|
|
|
stopped = svc_exec("stop", NULL);
|
2007-04-11 18:14:47 +05:30
|
|
|
if (ibsave)
|
2008-03-16 22:30:56 +05:30
|
|
|
unsetenv("IN_BACKGROUND");
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! in_control())
|
|
|
|
ewarnx("WARNING: %s not under our control, aborting", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-10-10 02:50:10 +05:30
|
|
|
if (! stopped)
|
2008-03-16 22:30:56 +05:30
|
|
|
eerrorx("ERROR: %s failed to stop", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
if (in_background)
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(service, RC_SERVICE_INACTIVE);
|
2007-04-11 18:14:47 +05:30
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_mark(service, RC_SERVICE_STOPPED);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
unlink_mtime_test();
|
2007-10-10 02:50:10 +05:30
|
|
|
hook_out = RC_HOOK_SERVICE_STOP_OUT;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_STOP_DONE, applet);
|
2008-03-17 23:27:07 +05:30
|
|
|
unlink(exclusive);
|
2007-04-11 18:14:47 +05:30
|
|
|
hook_out = 0;
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_run(RC_HOOK_SERVICE_STOP_OUT, applet);
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
static void svc_restart(bool deps)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
/* This is hairly and a better way needs to be found I think!
|
|
|
|
The issue is this - openvpn need net and dns. net can restart
|
|
|
|
dns via resolvconf, so you could have openvpn trying to restart dnsmasq
|
|
|
|
which in turn is waiting on net which in turn is waiting on dnsmasq.
|
|
|
|
The work around is for resolvconf to restart it's services with --nodeps
|
|
|
|
which means just that. The downside is that there is a small window when
|
|
|
|
our status is invalid.
|
|
|
|
One workaround would be to introduce a new status, or status locking. */
|
|
|
|
if (! deps) {
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE state = rc_service_state(service);
|
2007-09-28 20:23:38 +05:30
|
|
|
if (state & RC_SERVICE_STARTED || state & RC_SERVICE_INACTIVE)
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_exec("stop", "start");
|
2007-04-11 18:14:47 +05:30
|
|
|
else
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_exec("start", NULL);
|
2007-04-11 18:14:47 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! (rc_service_state(service) & RC_SERVICE_STOPPED)) {
|
|
|
|
get_started_services();
|
|
|
|
svc_stop(deps);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_start(deps);
|
|
|
|
start_services(restart_services);
|
|
|
|
rc_stringlist_free(restart_services);
|
2007-04-30 18:48:42 +05:30
|
|
|
restart_services = NULL;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|
|
|
|
|
2007-08-28 18:36:44 +05:30
|
|
|
#include "_usage.h"
|
2007-09-26 04:47:25 +05:30
|
|
|
#define getoptstring "dDsv" getoptstring_COMMON
|
2007-12-18 23:31:05 +05:30
|
|
|
#define extraopts "stop | start | restart | describe | zap"
|
2008-02-02 01:24:46 +05:30
|
|
|
static const struct option longopts[] = {
|
2007-04-17 18:14:32 +05:30
|
|
|
{ "debug", 0, NULL, 'd'},
|
2007-08-28 18:36:44 +05:30
|
|
|
{ "ifstarted", 0, NULL, 's'},
|
2007-04-17 18:14:32 +05:30
|
|
|
{ "nodeps", 0, NULL, 'D'},
|
2007-08-28 18:36:44 +05:30
|
|
|
longopts_COMMON
|
2007-04-17 18:14:32 +05:30
|
|
|
};
|
2007-09-25 21:51:38 +05:30
|
|
|
static const char * const longopts_help[] = {
|
2007-12-18 23:31:05 +05:30
|
|
|
"set xtrace when running the script",
|
|
|
|
"only run commands when started",
|
|
|
|
"ignore dependencies",
|
2007-09-25 21:51:38 +05:30
|
|
|
longopts_help_COMMON
|
|
|
|
};
|
2007-08-28 18:36:44 +05:30
|
|
|
#include "_usage.c"
|
2007-04-17 18:14:32 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
int runscript(int argc, char **argv)
|
2007-04-05 16:48:42 +05:30
|
|
|
{
|
2007-04-11 18:14:47 +05:30
|
|
|
bool deps = true;
|
|
|
|
bool doneone = false;
|
|
|
|
char pid[16];
|
|
|
|
int retval;
|
2007-05-14 17:54:18 +05:30
|
|
|
int opt;
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_STRING *svc;
|
|
|
|
char dir[PATH_MAX];
|
|
|
|
size_t l = 0;
|
|
|
|
size_t ll;
|
|
|
|
char *save;
|
|
|
|
int depoptions = RC_DEP_TRACE;
|
2007-04-12 15:38:42 +05:30
|
|
|
|
2007-11-14 21:49:56 +05:30
|
|
|
/* Show help if insufficient args */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (argc < 2 || ! exists(argv[1])) {
|
|
|
|
fprintf(stderr, "runscript is not meant to be to run directly\n");
|
|
|
|
exit(EXIT_FAILURE);
|
2007-11-14 21:49:56 +05:30
|
|
|
}
|
2007-07-04 20:26:59 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
applet = basename_c(argv[1]);
|
2007-12-18 23:31:05 +05:30
|
|
|
if (argc < 3)
|
2008-03-16 22:30:56 +05:30
|
|
|
usage(EXIT_FAILURE);
|
2007-12-18 23:31:05 +05:30
|
|
|
|
2007-11-21 21:08:07 +05:30
|
|
|
if (*argv[1] == '/')
|
2008-03-16 22:30:56 +05:30
|
|
|
service = xstrdup(argv[1]);
|
2007-11-21 21:08:07 +05:30
|
|
|
else {
|
2008-03-16 22:30:56 +05:30
|
|
|
getcwd(dir, sizeof(dir));
|
|
|
|
l = strlen(dir) + strlen(argv[1]) + 2;
|
|
|
|
service = xmalloc(sizeof (char) * l);
|
|
|
|
snprintf(service, l, "%s/%s", dir, argv[1]);
|
2007-11-21 21:08:07 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
atexit(cleanup);
|
2007-06-26 14:17:46 +05:30
|
|
|
|
|
|
|
/* Change dir to / to ensure all init scripts don't use stuff in pwd */
|
2008-03-16 22:30:56 +05:30
|
|
|
chdir("/");
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#ifdef __linux__
|
2007-04-11 18:14:47 +05:30
|
|
|
/* coldplug events can trigger init scripts, but we don't want to run them
|
|
|
|
until after rc sysinit has completed so we punt them to the boot runlevel */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (exists("/dev/.rcsysinit")) {
|
|
|
|
eerror("%s: cannot run until sysvinit completes", applet);
|
|
|
|
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
|
|
|
|
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
|
2008-03-17 18:55:56 +05:30
|
|
|
snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet);
|
|
|
|
symlink(service, exclusive);
|
2007-04-11 18:14:47 +05:30
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if ((runlevel = xstrdup (getenv ("RC_RUNLEVEL"))) == NULL) {
|
|
|
|
env_filter();
|
|
|
|
env_config();
|
|
|
|
runlevel = rc_runlevel_get();
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
setenv("EINFO_LOG", service, 1);
|
|
|
|
setenv("SVCNAME", applet, 1);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Set an env var so that we always know our pid regardless of any
|
|
|
|
subshells the init script may create so that our mark_service_*
|
|
|
|
functions can always instruct us of this change */
|
2008-03-16 22:30:56 +05:30
|
|
|
snprintf(pid, sizeof(pid), "%d", (int) getpid());
|
|
|
|
setenv("RC_RUNSCRIPT_PID", pid, 1);
|
2007-04-05 16:48:42 +05:30
|
|
|
|
2007-04-25 18:00:24 +05:30
|
|
|
/* eprefix is kinda klunky, but it works for our purposes */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_conf_yesno("rc_parallel")) {
|
2007-07-06 21:20:40 +05:30
|
|
|
/* Get the longest service name */
|
2008-03-16 22:30:56 +05:30
|
|
|
services = rc_services_in_runlevel(NULL);
|
|
|
|
TAILQ_FOREACH(svc, services, entries) {
|
|
|
|
ll = strlen(svc->value);
|
2007-07-06 21:20:40 +05:30
|
|
|
if (ll > l)
|
|
|
|
l = ll;
|
|
|
|
}
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-07-06 22:37:29 +05:30
|
|
|
/* Make our prefix string */
|
2008-03-16 22:30:56 +05:30
|
|
|
prefix = xmalloc(sizeof(char) * l + 1);
|
|
|
|
ll = strlen(applet);
|
|
|
|
memcpy(prefix, applet, ll);
|
|
|
|
memset(prefix + ll, ' ', l - ll);
|
|
|
|
memset(prefix + l, 0, 1);
|
|
|
|
eprefix(prefix);
|
2007-04-25 18:00:24 +05:30
|
|
|
}
|
|
|
|
|
2007-04-05 16:48:42 +05:30
|
|
|
#ifdef __linux__
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Ok, we are ready to go, so setup selinux if applicable */
|
2008-03-16 22:30:56 +05:30
|
|
|
setup_selinux(argc, argv);
|
2007-04-05 16:48:42 +05:30
|
|
|
#endif
|
|
|
|
|
2007-04-12 16:10:51 +05:30
|
|
|
/* Punt the first arg as it's our service name */
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Right then, parse any options there may be */
|
2008-03-16 22:30:56 +05:30
|
|
|
while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1)
|
2007-05-14 17:54:18 +05:30
|
|
|
switch (opt) {
|
2008-03-16 22:30:56 +05:30
|
|
|
case 'd':
|
|
|
|
setenv("RC_DEBUG", "yes", 1);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
if (! (rc_service_state(service) & RC_SERVICE_STARTED))
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
deps = false;
|
|
|
|
break;
|
|
|
|
case_RC_COMMON_GETOPT
|
|
|
|
}
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-04-12 16:10:51 +05:30
|
|
|
/* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
|
|
|
|
that is being called and not any dependents */
|
2008-03-16 22:30:56 +05:30
|
|
|
if (getenv("IN_BACKGROUND")) {
|
|
|
|
ibsave = xstrdup(getenv("IN_BACKGROUND"));
|
|
|
|
in_background = rc_yesno(ibsave);
|
|
|
|
unsetenv("IN_BACKGROUND");
|
2007-04-12 16:10:51 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_yesno(getenv("IN_HOTPLUG"))) {
|
|
|
|
if (! rc_conf_yesno("rc_hotplug") || ! service_plugable(applet))
|
|
|
|
eerrorx("%s: not allowed to be hotplugged", applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup a signal handler */
|
2008-03-16 22:30:56 +05:30
|
|
|
signal_setup(SIGHUP, handle_signal);
|
|
|
|
signal_setup(SIGINT, handle_signal);
|
|
|
|
signal_setup(SIGQUIT, handle_signal);
|
|
|
|
signal_setup(SIGTERM, handle_signal);
|
|
|
|
signal_setup(SIGCHLD, handle_signal);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Load our plugins */
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_plugin_load();
|
|
|
|
|
|
|
|
applet_list = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(applet_list, applet);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
/* Now run each option */
|
|
|
|
retval = EXIT_SUCCESS;
|
2007-04-12 15:38:42 +05:30
|
|
|
while (optind < argc) {
|
|
|
|
optarg = argv[optind++];
|
|
|
|
|
2007-04-11 18:14:47 +05:30
|
|
|
/* Abort on a sighup here */
|
|
|
|
if (sighup)
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
|
|
|
/* Export the command we're running.
|
|
|
|
This is important as we stamp on the restart function now but
|
|
|
|
some start/stop routines still need to behave differently if
|
|
|
|
restarting. */
|
2008-03-16 22:30:56 +05:30
|
|
|
unsetenv("RC_CMD");
|
|
|
|
setenv("RC_CMD", optarg, 1);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
|
|
|
doneone = true;
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2007-12-20 23:09:13 +05:30
|
|
|
if (strcmp (optarg, "describe") == 0 ||
|
2008-01-11 21:21:40 +05:30
|
|
|
strcmp (optarg, "help") == 0)
|
2007-12-20 23:09:13 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
save = prefix;
|
|
|
|
eprefix(NULL);
|
2007-12-18 23:31:05 +05:30
|
|
|
prefix = NULL;
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_exec(optarg, NULL);
|
|
|
|
eprefix(save);
|
|
|
|
} else if (strcmp(optarg, "ineed") == 0 ||
|
|
|
|
strcmp(optarg, "iuse") == 0 ||
|
|
|
|
strcmp(optarg, "needsme") == 0 ||
|
|
|
|
strcmp(optarg, "usesme") == 0 ||
|
|
|
|
strcmp(optarg, "iafter") == 0 ||
|
|
|
|
strcmp(optarg, "ibefore") == 0 ||
|
|
|
|
strcmp(optarg, "iprovide") == 0)
|
2008-01-18 16:57:49 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_conf_yesno("rc_depend_strict"))
|
2007-07-21 18:19:51 +05:30
|
|
|
depoptions |= RC_DEP_STRICT;
|
2007-11-01 04:04:26 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
if (! deptree && ((deptree = _rc_deptree_load(NULL)) == NULL))
|
|
|
|
eerrorx("failed to load deptree");
|
|
|
|
|
|
|
|
tmplist = rc_stringlist_new();
|
|
|
|
rc_stringlist_add(tmplist, optarg);
|
|
|
|
services = rc_deptree_depends(deptree, tmplist, applet_list,
|
|
|
|
runlevel, depoptions);
|
|
|
|
rc_stringlist_free(tmplist);
|
|
|
|
tmplist = NULL;
|
|
|
|
TAILQ_FOREACH(svc, services, entries)
|
|
|
|
printf("%s ", svc->value);
|
|
|
|
if (TAILQ_FIRST(services))
|
2007-08-17 18:53:43 +05:30
|
|
|
printf ("\n");
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(services);
|
|
|
|
services = NULL;
|
2007-07-11 00:39:41 +05:30
|
|
|
} else if (strcmp (optarg, "status") == 0) {
|
2008-03-16 22:30:56 +05:30
|
|
|
RC_SERVICE r = svc_status();
|
2007-07-11 00:39:41 +05:30
|
|
|
retval = (int) r;
|
2007-10-09 21:17:25 +05:30
|
|
|
if (retval & RC_SERVICE_STARTED)
|
2007-10-09 21:14:22 +05:30
|
|
|
retval = 0;
|
2007-07-11 00:39:41 +05:30
|
|
|
} else {
|
2008-03-16 22:30:56 +05:30
|
|
|
if (strcmp(optarg, "conditionalrestart") == 0 ||
|
|
|
|
strcmp(optarg, "condrestart") == 0)
|
2007-07-11 00:39:41 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
if (rc_service_state(service) & RC_SERVICE_STARTED)
|
|
|
|
svc_restart(deps);
|
|
|
|
} else if (strcmp(optarg, "restart") == 0) {
|
2007-07-11 00:39:41 +05:30
|
|
|
svc_restart (deps);
|
2008-03-16 22:30:56 +05:30
|
|
|
} else if (strcmp(optarg, "start") == 0) {
|
|
|
|
svc_start(deps);
|
|
|
|
} else if (strcmp(optarg, "stop") == 0) {
|
2007-08-28 18:36:44 +05:30
|
|
|
if (deps && in_background)
|
2008-03-16 22:30:56 +05:30
|
|
|
get_started_services();
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_stop(deps);
|
2007-04-11 18:14:47 +05:30
|
|
|
|
2007-08-28 18:36:44 +05:30
|
|
|
if (deps) {
|
|
|
|
if (! in_background &&
|
2008-03-16 22:30:56 +05:30
|
|
|
! rc_runlevel_stopping() &&
|
|
|
|
rc_service_state(service) & RC_SERVICE_STOPPED)
|
|
|
|
uncoldplug();
|
2007-08-28 18:36:44 +05:30
|
|
|
|
|
|
|
if (in_background &&
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_service_state(service) & RC_SERVICE_INACTIVE)
|
2007-08-28 18:36:44 +05:30
|
|
|
{
|
2008-03-16 22:30:56 +05:30
|
|
|
TAILQ_FOREACH(svc, restart_services, entries)
|
|
|
|
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
|
|
|
rc_service_schedule_start(service, svc->value);
|
2007-08-28 18:36:44 +05:30
|
|
|
}
|
2007-07-11 00:39:41 +05:30
|
|
|
}
|
2008-03-16 22:30:56 +05:30
|
|
|
} else if (strcmp(optarg, "zap") == 0) {
|
|
|
|
einfo("Manually resetting %s to stopped state", applet);
|
|
|
|
rc_service_mark(applet, RC_SERVICE_STOPPED);
|
|
|
|
uncoldplug();
|
2007-07-11 01:41:42 +05:30
|
|
|
} else
|
2008-03-16 22:30:56 +05:30
|
|
|
svc_exec(optarg, NULL);
|
2007-07-11 00:39:41 +05:30
|
|
|
|
|
|
|
/* We should ensure this list is empty after an action is done */
|
2008-03-16 22:30:56 +05:30
|
|
|
rc_stringlist_free(restart_services);
|
2007-07-11 00:39:41 +05:30
|
|
|
restart_services = NULL;
|
|
|
|
}
|
|
|
|
|
2007-12-20 23:09:13 +05:30
|
|
|
if (! doneone)
|
2008-03-16 22:30:56 +05:30
|
|
|
usage(EXIT_FAILURE);
|
2007-04-11 18:14:47 +05:30
|
|
|
}
|
|
|
|
|
2008-03-16 22:30:56 +05:30
|
|
|
return retval;
|
2007-04-05 16:48:42 +05:30
|
|
|
}
|