openrc/src/librc/librc.c

943 lines
21 KiB
C
Raw Normal View History

/*
2008-01-14 10:35:22 +05:30
librc
core RC functions
*/
2008-01-14 10:35:22 +05:30
/*
* 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.
*/
const char librc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";
#include "librc.h"
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#endif
#include <signal.h>
#define SOFTLEVEL RC_SVCDIR "/softlevel"
2007-10-04 21:56:44 +05:30
#ifndef S_IXUGO
# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
#endif
/* File stream used for plugins to write environ vars to */
FILE *rc_environ_fd = NULL;
typedef struct rc_service_state_name {
rc_service_state_t state;
const char *name;
} rc_service_state_name_t;
/* We MUST list the states below 0x10 first
* The rest can be in any order */
static const rc_service_state_name_t rc_service_state_names[] = {
{ RC_SERVICE_STARTED, "started" },
{ RC_SERVICE_STOPPED, "stopped" },
{ RC_SERVICE_STARTING, "starting" },
{ RC_SERVICE_STOPPING, "stopping" },
{ RC_SERVICE_INACTIVE, "inactive" },
{ RC_SERVICE_WASINACTIVE, "wasinactive" },
{ RC_SERVICE_COLDPLUGGED, "coldplugged" },
{ RC_SERVICE_FAILED, "failed" },
{ RC_SERVICE_SCHEDULED, "scheduled"},
{ 0, NULL}
};
2007-10-05 15:46:14 +05:30
#define LS_INITD 0x01
#define LS_DIR 0x02
static char **ls_dir (const char *dir, int options)
{
DIR *dp;
struct dirent *d;
char **list = NULL;
struct stat buf;
2007-10-05 15:46:14 +05:30
2008-01-14 10:35:22 +05:30
if ((dp = opendir (dir)) == NULL)
2007-10-05 15:46:14 +05:30
return (NULL);
while (((d = readdir (dp)) != NULL)) {
2007-10-05 15:46:14 +05:30
if (d->d_name[0] != '.') {
if (options & LS_INITD) {
int l = strlen (d->d_name);
/* Check that our file really exists.
* This is important as a service maybe in a runlevel, but
* could also have been removed. */
char *file = rc_strcatpaths (dir, d->d_name, NULL);
int ok = stat (file, &buf);
free (file);
if (ok != 0)
2007-10-05 15:46:14 +05:30
continue;
/* .sh files are not init scripts */
if (l > 2 && d->d_name[l - 3] == '.' &&
2008-01-11 21:21:40 +05:30
d->d_name[l - 2] == 's' &&
d->d_name[l - 1] == 'h')
2007-10-05 15:46:14 +05:30
continue;
}
if (options & LS_DIR) {
if (stat (d->d_name, &buf) == 0 && ! S_ISDIR (buf.st_mode))
continue;
}
rc_strlist_addsort (&list, d->d_name);
}
}
closedir (dp);
return (list);
}
2007-10-05 16:06:53 +05:30
static bool rm_dir (const char *pathname, bool top)
{
DIR *dp;
struct dirent *d;
if ((dp = opendir (pathname)) == NULL)
return (false);
errno = 0;
while (((d = readdir (dp)) != NULL) && errno == 0) {
if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) {
char *tmp = rc_strcatpaths (pathname, d->d_name, (char *) NULL);
if (d->d_type == DT_DIR) {
if (! rm_dir (tmp, true))
{
free (tmp);
closedir (dp);
return (false);
}
} else {
if (unlink (tmp)) {
free (tmp);
closedir (dp);
return (false);
}
}
free (tmp);
}
}
closedir (dp);
if (top && rmdir (pathname) != 0)
return (false);
return (true);
}
2008-02-19 21:21:59 +05:30
/* Other systems may need this at some point, but for now it's Linux only */
#ifdef __linux__
static bool file_regex (const char *file, const char *regex)
{
FILE *fp;
char *line;
regex_t re;
bool retval = false;
int result;
if (! (fp = fopen (file, "r")))
return (false);
if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
fclose (fp);
line = xmalloc (sizeof (char) * BUFSIZ);
regerror (result, &re, line, BUFSIZ);
fprintf (stderr, "file_regex: %s", line);
free (line);
return (false);
}
while ((line = rc_getline (fp))) {
if (regexec (&re, line, 0, NULL, 0) == 0)
retval = true;
free (line);
if (retval)
break;
}
fclose (fp);
regfree (&re);
return (retval);
}
#endif
const char *rc_sys (void)
{
#ifdef __FreeBSD__
int jailed = 0;
size_t len = sizeof (jailed);
if (sysctlbyname ("security.jail.jailed", &jailed, &len, NULL, 0) == 0)
if (jailed == 1)
return (RC_SYS_JAIL);
#endif
#ifdef __linux__
if (exists ("/proc/xen")) {
2008-02-19 21:21:59 +05:30
if (file_regex ("/proc/xen/capabilities", "control_d"))
return (RC_SYS_XEN0);
return (RC_SYS_XENU);
} else if (file_regex ("/proc/cpuinfo", "UML"))
return (RC_SYS_UML);
else if (file_regex ("/proc/self/status",
"(s_context|VxID|envID):[[:space:]]*[1-9]"))
return (RC_SYS_VPS);
#endif
return (NULL);
}
static const char *rc_parse_service_state (rc_service_state_t state)
{
int i;
for (i = 0; rc_service_state_names[i].name; i++) {
if (rc_service_state_names[i].state == state)
return (rc_service_state_names[i].name);
}
return (NULL);
}
2007-09-25 23:00:07 +05:30
bool rc_runlevel_starting (void)
{
return (exists (RC_STARTING));
}
librc_hidden_def(rc_runlevel_starting)
2007-09-25 23:00:07 +05:30
bool rc_runlevel_stopping (void)
{
return (exists (RC_STOPPING));
}
librc_hidden_def(rc_runlevel_stopping)
2007-10-03 19:41:55 +05:30
char **rc_runlevel_list (void)
{
2007-10-05 15:46:14 +05:30
return (ls_dir (RC_RUNLEVELDIR, LS_DIR));
}
2007-10-03 19:41:55 +05:30
librc_hidden_def(rc_runlevel_list)
2007-10-02 15:27:23 +05:30
char *rc_runlevel_get (void)
{
2007-04-11 18:14:47 +05:30
FILE *fp;
char *runlevel = NULL;
if ((fp = fopen (SOFTLEVEL, "r"))) {
2007-10-12 05:31:33 +05:30
runlevel = xmalloc (sizeof (char) * PATH_MAX);
if (fgets (runlevel, PATH_MAX, fp)) {
int i = strlen (runlevel) - 1;
if (runlevel[i] == '\n')
runlevel[i] = 0;
} else
*runlevel = '\0';
2007-04-11 18:14:47 +05:30
fclose (fp);
}
2007-10-12 05:31:33 +05:30
if (! runlevel || ! *runlevel) {
free (runlevel);
2007-10-08 16:46:22 +05:30
runlevel = xstrdup (RC_LEVEL_SYSINIT);
2007-10-12 05:31:33 +05:30
}
return (runlevel);
}
2007-10-02 15:27:23 +05:30
librc_hidden_def(rc_runlevel_get)
2007-10-02 15:27:23 +05:30
bool rc_runlevel_set (const char *runlevel)
{
2007-04-11 18:14:47 +05:30
FILE *fp = fopen (SOFTLEVEL, "w");
2007-04-11 18:14:47 +05:30
if (! fp)
return (false);
2007-04-11 18:14:47 +05:30
fprintf (fp, "%s", runlevel);
fclose (fp);
return (true);
}
2007-10-02 15:27:23 +05:30
librc_hidden_def(rc_runlevel_set)
2007-09-25 23:00:07 +05:30
bool rc_runlevel_exists (const char *runlevel)
{
2007-04-11 18:14:47 +05:30
char *path;
2007-10-04 22:24:29 +05:30
struct stat buf;
bool retval = false;
2007-04-11 18:14:47 +05:30
if (! runlevel)
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
path = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL);
2007-10-04 22:24:29 +05:30
if (stat (path, &buf) == 0 && S_ISDIR (buf.st_mode))
retval = true;
2007-04-11 18:14:47 +05:30
free (path);
return (retval);
}
librc_hidden_def(rc_runlevel_exists)
2008-01-11 21:21:40 +05:30
/* Resolve a service name to it's full path */
char *rc_service_resolve (const char *service)
{
2007-04-11 18:14:47 +05:30
char buffer[PATH_MAX];
char *file;
int r = 0;
2007-10-04 21:51:53 +05:30
struct stat buf;
2007-04-11 18:14:47 +05:30
if (! service)
return (NULL);
if (service[0] == '/')
2007-10-08 16:46:22 +05:30
return (xstrdup (service));
2007-04-11 18:14:47 +05:30
file = rc_strcatpaths (RC_SVCDIR, "started", service, (char *) NULL);
2007-10-04 21:51:53 +05:30
if (lstat (file, &buf) || ! S_ISLNK (buf.st_mode)) {
2007-04-11 18:14:47 +05:30
free (file);
file = rc_strcatpaths (RC_SVCDIR, "inactive", service, (char *) NULL);
2007-10-04 21:51:53 +05:30
if (lstat (file, &buf) || ! S_ISLNK (buf.st_mode)) {
2007-04-11 18:14:47 +05:30
free (file);
file = NULL;
}
}
memset (buffer, 0, sizeof (buffer));
if (file) {
r = readlink (file, buffer, sizeof (buffer));
free (file);
if (r > 0)
2007-10-08 16:46:22 +05:30
return (xstrdup (buffer));
2007-04-11 18:14:47 +05:30
}
snprintf (buffer, sizeof (buffer), RC_INITDIR "/%s", service);
/* So we don't exist in /etc/init.d - check /usr/local/etc/init.d */
#ifdef RC_PKG_INITDIR
if (stat (buffer, &buf) != 0) {
snprintf (buffer, sizeof (buffer), RC_PKG_INITDIR "/%s", service);
if (stat (buffer, &buf) != 0)
return (NULL);
}
#endif
2007-10-08 16:46:22 +05:30
return (xstrdup (buffer));
}
librc_hidden_def(rc_service_resolve)
2007-09-25 23:00:07 +05:30
bool rc_service_exists (const char *service)
{
2007-04-11 18:14:47 +05:30
char *file;
2007-09-25 23:00:07 +05:30
bool retval = false;
2007-04-11 18:14:47 +05:30
int len;
2007-10-04 21:56:44 +05:30
struct stat buf;
2007-04-11 18:14:47 +05:30
if (! service)
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
len = strlen (service);
/* .sh files are not init scripts */
if (len > 2 && service[len - 3] == '.' &&
2008-01-11 21:21:40 +05:30
service[len - 2] == 's' &&
service[len - 1] == 'h')
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
if (! (file = rc_service_resolve (service)))
return (false);
2007-10-04 21:56:44 +05:30
if (stat (file, &buf) == 0 && buf.st_mode & S_IXUGO)
retval = true;
2007-04-11 18:14:47 +05:30
free (file);
return (retval);
}
librc_hidden_def(rc_service_exists)
2007-10-24 02:13:45 +05:30
#define OPTSTR ". '%s'; echo \"${opts}\""
char **rc_service_extra_commands (const char *service)
{
char *svc;
2007-10-12 05:31:33 +05:30
char *cmd = NULL;
char *buffer = NULL;
char **commands = NULL;
char *token;
char *p;
FILE *fp;
2008-01-22 15:59:15 +05:30
size_t l;
if (! (svc = rc_service_resolve (service)))
return (NULL);
2007-10-24 02:13:45 +05:30
l = strlen (OPTSTR) + strlen (svc) + 1;
cmd = xmalloc (sizeof (char) * l);
snprintf (cmd, l, OPTSTR, svc);
free (svc);
2007-10-12 05:31:33 +05:30
if ((fp = popen (cmd, "r"))) {
p = buffer = rc_getline (fp);
while ((token = strsep (&p, " ")))
rc_strlist_addsort (&commands, token);
2007-10-12 05:31:33 +05:30
pclose (fp);
free (buffer);
}
2007-10-24 02:13:45 +05:30
free (cmd);
return (commands);
}
librc_hidden_def(rc_service_extra_commands)
2007-10-24 02:13:45 +05:30
#define DESCSTR ". '%s'; echo \"${description%s%s}\""
2007-07-11 00:44:37 +05:30
char *rc_service_description (const char *service, const char *option)
{
char *svc;
char *cmd;
char *desc = NULL;
FILE *fp;
2008-01-22 15:59:15 +05:30
size_t l;
if (! (svc = rc_service_resolve (service)))
return (NULL);
2007-07-11 00:44:37 +05:30
if (! option)
option = "";
2008-01-22 15:59:15 +05:30
l = strlen (DESCSTR) + strlen (svc) + strlen (option) + 2;
cmd = xmalloc (sizeof (char) * l);
snprintf (cmd, l, DESCSTR, svc, option ? "_" : "", option);
free (svc);
2007-10-12 05:31:33 +05:30
if ((fp = popen (cmd, "r"))) {
desc = rc_getline (fp);
2007-10-12 05:31:33 +05:30
pclose (fp);
}
2007-10-24 02:13:45 +05:30
free (cmd);
return (desc);
}
librc_hidden_def(rc_service_description)
2007-09-25 23:00:07 +05:30
bool rc_service_in_runlevel (const char *service, const char *runlevel)
{
2007-04-11 18:14:47 +05:30
char *file;
2007-09-25 23:00:07 +05:30
bool retval;
2007-04-11 18:14:47 +05:30
if (! runlevel || ! service)
2007-09-25 23:00:07 +05:30
return (false);
2007-12-19 19:23:52 +05:30
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
retval = exists (file);
2007-04-11 18:14:47 +05:30
free (file);
2007-04-11 18:14:47 +05:30
return (retval);
}
librc_hidden_def(rc_service_in_runlevel)
bool rc_service_mark (const char *service, const rc_service_state_t state)
{
2007-04-11 18:14:47 +05:30
char *file;
int i = 0;
int skip_state = -1;
const char *base;
char *init = rc_service_resolve (service);
2007-04-11 18:14:47 +05:30
bool skip_wasinactive = false;
if (! init)
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
2007-12-19 19:23:52 +05:30
base = basename_c (service);
2007-04-11 18:14:47 +05:30
if (state != RC_SERVICE_STOPPED) {
if (! exists (init)) {
2007-04-11 18:14:47 +05:30
free (init);
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
}
file = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (state), base,
2008-01-11 21:21:40 +05:30
(char *) NULL);
if (exists (file))
2007-04-11 18:14:47 +05:30
unlink (file);
i = symlink (init, file);
if (i != 0) {
free (file);
free (init);
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
}
free (file);
skip_state = state;
}
if (state == RC_SERVICE_COLDPLUGGED || state == RC_SERVICE_FAILED) {
2007-04-11 18:14:47 +05:30
free (init);
2007-09-25 23:00:07 +05:30
return (true);
2007-04-11 18:14:47 +05:30
}
/* Remove any old states now */
for (i = 0; rc_service_state_names[i].name; i++) {
int s = rc_service_state_names[i].state;
if ((s != skip_state &&
2008-01-11 21:21:40 +05:30
s != RC_SERVICE_STOPPED &&
s != RC_SERVICE_COLDPLUGGED &&
s != RC_SERVICE_SCHEDULED) &&
(! skip_wasinactive || s != RC_SERVICE_WASINACTIVE))
2007-04-11 18:14:47 +05:30
{
file = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (s), base,
2008-01-11 21:21:40 +05:30
(char *) NULL);
if (exists (file)) {
if ((state == RC_SERVICE_STARTING ||
2008-01-11 21:21:40 +05:30
state == RC_SERVICE_STOPPING) &&
s == RC_SERVICE_INACTIVE)
2007-04-11 18:14:47 +05:30
{
char *wasfile = rc_strcatpaths (RC_SVCDIR,
2008-01-11 21:21:40 +05:30
rc_parse_service_state (RC_SERVICE_WASINACTIVE),
base, (char *) NULL);
2007-04-11 18:14:47 +05:30
symlink (init, wasfile);
2007-04-11 18:14:47 +05:30
skip_wasinactive = true;
free (wasfile);
}
unlink (file);
2007-04-11 18:14:47 +05:30
}
free (file);
}
}
/* Remove the exclusive state if we're inactive */
if (state == RC_SERVICE_STARTED ||
2008-01-11 21:21:40 +05:30
state == RC_SERVICE_STOPPED ||
state == RC_SERVICE_INACTIVE)
2007-04-11 18:14:47 +05:30
{
file = rc_strcatpaths (RC_SVCDIR, "exclusive", base, (char *) NULL);
2008-01-14 10:35:22 +05:30
unlink (file);
2007-04-11 18:14:47 +05:30
free (file);
}
/* Remove any options and daemons the service may have stored */
if (state == RC_SERVICE_STOPPED) {
2007-04-11 18:14:47 +05:30
char *dir = rc_strcatpaths (RC_SVCDIR, "options", base, (char *) NULL);
2007-10-05 16:06:53 +05:30
rm_dir (dir, true);
2007-04-11 18:14:47 +05:30
free (dir);
dir = rc_strcatpaths (RC_SVCDIR, "daemons", base, (char *) NULL);
2007-10-05 16:06:53 +05:30
rm_dir (dir, true);
2007-04-11 18:14:47 +05:30
free (dir);
rc_service_schedule_clear (service);
2007-04-11 18:14:47 +05:30
}
/* These are final states, so remove us from scheduled */
if (state == RC_SERVICE_STARTED || state == RC_SERVICE_STOPPED) {
2007-04-11 18:14:47 +05:30
char *sdir = rc_strcatpaths (RC_SVCDIR, "scheduled", (char *) NULL);
2007-10-05 15:46:14 +05:30
char **dirs = ls_dir (sdir, 0);
2007-04-11 18:14:47 +05:30
char *dir;
int serrno;
STRLIST_FOREACH (dirs, dir, i) {
char *bdir = rc_strcatpaths (sdir, dir, (char *) NULL);
file = rc_strcatpaths (bdir, base, (char *) NULL);
unlink (file);
2007-04-11 18:14:47 +05:30
free (file);
/* Try and remove the dir - we don't care about errors */
serrno = errno;
rmdir (bdir);
errno = serrno;
free (bdir);
}
rc_strlist_free (dirs);
free (sdir);
}
free (init);
2007-09-25 23:00:07 +05:30
return (true);
}
librc_hidden_def(rc_service_mark)
rc_service_state_t rc_service_state (const char *service)
{
int i;
int state = RC_SERVICE_STOPPED;
2007-04-11 18:14:47 +05:30
for (i = 0; rc_service_state_names[i].name; i++) {
char *file = rc_strcatpaths (RC_SVCDIR, rc_service_state_names[i].name,
2008-01-11 21:21:40 +05:30
basename_c (service), (char*) NULL);
if (exists (file)) {
if (rc_service_state_names[i].state <= 0x10)
state = rc_service_state_names[i].state;
else
state |= rc_service_state_names[i].state;
}
free (file);
}
if (state & RC_SERVICE_STOPPED) {
2007-04-11 18:14:47 +05:30
char **services = rc_services_scheduled_by (service);
if (services) {
state |= RC_SERVICE_SCHEDULED;
2007-09-25 23:00:07 +05:30
free (services);
}
2007-04-11 18:14:47 +05:30
}
return (state);
}
librc_hidden_def(rc_service_state)
char *rc_service_value_get (const char *service, const char *option)
{
2007-04-11 18:14:47 +05:30
FILE *fp;
char *line = NULL;
2007-04-11 18:14:47 +05:30
char *file = rc_strcatpaths (RC_SVCDIR, "options", service, option,
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-04-11 18:14:47 +05:30
if ((fp = fopen (file, "r"))) {
line = rc_getline (fp);
fclose (fp);
2007-04-11 18:14:47 +05:30
}
free (file);
return (line);
}
librc_hidden_def(rc_service_value_get)
bool rc_service_value_set (const char *service, const char *option,
2008-01-11 21:21:40 +05:30
const char *value)
{
2007-04-11 18:14:47 +05:30
FILE *fp;
char *path = rc_strcatpaths (RC_SVCDIR, "options", service, (char *) NULL);
char *file = rc_strcatpaths (path, option, (char *) NULL);
2007-09-25 23:00:07 +05:30
bool retval = false;
2007-04-11 18:14:47 +05:30
2007-10-04 22:24:29 +05:30
if (mkdir (path, 0755) != 0 && errno != EEXIST) {
free (path);
free (file);
return (false);
2007-04-11 18:14:47 +05:30
}
if ((fp = fopen (file, "w"))) {
2007-04-11 18:14:47 +05:30
if (value)
fprintf (fp, "%s", value);
fclose (fp);
2007-09-25 23:00:07 +05:30
retval = true;
2007-04-11 18:14:47 +05:30
}
free (path);
free (file);
return (retval);
}
librc_hidden_def(rc_service_value_set)
static pid_t _exec_service (const char *service, const char *arg)
{
2007-04-11 18:14:47 +05:30
char *file;
char *fifo;
pid_t pid = -1;
sigset_t full;
sigset_t old;
struct sigaction sa;
2007-04-11 18:14:47 +05:30
file = rc_service_resolve (service);
if (! exists (file)) {
rc_service_mark (service, RC_SERVICE_STOPPED);
2007-04-11 18:14:47 +05:30
free (file);
return (0);
}
/* We create a fifo so that other services can wait until we complete */
2007-12-19 19:23:52 +05:30
fifo = rc_strcatpaths (RC_SVCDIR, "exclusive", basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-04-11 18:14:47 +05:30
if (mkfifo (fifo, 0600) != 0 && errno != EEXIST) {
free (fifo);
free (file);
return (-1);
}
/* We need to block signals until we have forked */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask);
sigfillset (&full);
sigprocmask (SIG_SETMASK, &full, &old);
if ((pid = fork ()) == 0) {
/* Restore default handlers */
sigaction (SIGCHLD, &sa, NULL);
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
sigaction (SIGQUIT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGUSR1, &sa, NULL);
sigaction (SIGWINCH, &sa, NULL);
/* Unmask signals */
2008-02-05 03:18:05 +05:30
sigprocmask (SIG_SETMASK, &old, NULL);
/* Safe to run now */
execl (file, file, arg, (char *) NULL);
fprintf (stderr, "unable to exec `%s': %s\n",
file, strerror (errno));
2007-04-21 14:53:37 +05:30
unlink (fifo);
_exit (EXIT_FAILURE);
2007-04-11 18:14:47 +05:30
}
2008-02-03 03:47:44 +05:30
if (pid == -1)
fprintf (stderr, "fork: %s\n", strerror (errno));
sigprocmask (SIG_SETMASK, &old, NULL);
2007-04-11 18:14:47 +05:30
free (fifo);
free (file);
return (pid);
}
2007-04-11 18:14:47 +05:30
pid_t rc_service_stop (const char *service)
{
rc_service_state_t state = rc_service_state (service);
if (state & RC_SERVICE_FAILED)
return (-1);
if (state & RC_SERVICE_STOPPED)
2007-04-11 18:14:47 +05:30
return (0);
2007-04-11 18:14:47 +05:30
return (_exec_service (service, "stop"));
}
librc_hidden_def(rc_service_stop)
pid_t rc_service_start (const char *service)
{
rc_service_state_t state = rc_service_state (service);
if (state & RC_SERVICE_FAILED)
return (-1);
if (! state & RC_SERVICE_STOPPED)
2007-04-11 18:14:47 +05:30
return (0);
2007-04-11 18:14:47 +05:30
return (_exec_service (service, "start"));
}
librc_hidden_def(rc_service_start)
bool rc_service_schedule_start (const char *service,
2008-01-11 21:21:40 +05:30
const char *service_to_start)
{
2007-04-11 18:14:47 +05:30
char *dir;
char *init;
char *file;
bool retval;
2007-04-11 18:14:47 +05:30
/* service may be a provided service, like net */
if (! service || ! rc_service_exists (service_to_start))
return (false);
2007-04-11 18:14:47 +05:30
2007-12-19 19:23:52 +05:30
dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-10-04 22:24:29 +05:30
if (mkdir (dir, 0755) != 0 && errno != EEXIST) {
free (dir);
return (false);
}
2007-04-11 18:14:47 +05:30
init = rc_service_resolve (service_to_start);
2007-12-19 19:23:52 +05:30
file = rc_strcatpaths (dir, basename_c (service_to_start), (char *) NULL);
retval = (exists (file) || symlink (init, file) == 0);
2007-04-11 18:14:47 +05:30
free (init);
free (file);
free (dir);
return (retval);
}
librc_hidden_def(rc_service_schedule_start)
bool rc_service_schedule_clear (const char *service)
{
2007-12-19 19:23:52 +05:30
char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
bool retval;
2007-10-05 16:06:53 +05:30
if (! (retval = rm_dir (dir, true)) && errno == ENOENT)
retval = true;
2007-04-11 18:14:47 +05:30
free (dir);
return (retval);
}
librc_hidden_def(rc_service_schedule_clear)
char **rc_services_in_runlevel (const char *runlevel)
{
2007-04-11 18:14:47 +05:30
char *dir;
char **list = NULL;
if (! runlevel) {
#ifdef RC_PKG_INITDIR
2008-03-01 14:57:29 +05:30
int i;
char **local = ls_dir (RC_PKG_INITDIR, LS_INITD);
#endif
list = ls_dir (RC_INITDIR, LS_INITD);
#ifdef RC_PKG_INITDIR
STRLIST_FOREACH (local, dir, i)
rc_strlist_addsortu (&list, dir);
rc_strlist_free (local);
#endif
return (list);
}
2007-04-11 18:14:47 +05:30
/* These special levels never contain any services */
if (strcmp (runlevel, RC_LEVEL_SYSINIT) == 0 ||
2008-01-11 21:21:40 +05:30
strcmp (runlevel, RC_LEVEL_SINGLE) == 0)
2007-04-11 18:14:47 +05:30
return (NULL);
2007-04-11 18:14:47 +05:30
dir = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, (char *) NULL);
2007-10-05 15:46:14 +05:30
list = ls_dir (dir, LS_INITD);
2007-04-11 18:14:47 +05:30
free (dir);
return (list);
}
librc_hidden_def(rc_services_in_runlevel)
char **rc_services_in_state (rc_service_state_t state)
{
char *dir = rc_strcatpaths (RC_SVCDIR, rc_parse_service_state (state),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-04-11 18:14:47 +05:30
char **list = NULL;
if (state == RC_SERVICE_SCHEDULED) {
2007-10-05 15:46:14 +05:30
char **dirs = ls_dir (dir, 0);
2007-04-11 18:14:47 +05:30
char *d;
int i;
STRLIST_FOREACH (dirs, d, i) {
char *p = rc_strcatpaths (dir, d, (char *) NULL);
2007-10-05 15:46:14 +05:30
char **entries = ls_dir (p, LS_INITD);
2007-04-11 18:14:47 +05:30
char *e;
int j;
STRLIST_FOREACH (entries, e, j)
rc_strlist_addsortu (&list, e);
2007-04-11 18:14:47 +05:30
if (entries)
free (entries);
}
if (dirs)
free (dirs);
} else {
2007-10-05 15:46:14 +05:30
list = ls_dir (dir, LS_INITD);
2007-04-11 18:14:47 +05:30
}
free (dir);
return (list);
}
librc_hidden_def(rc_services_in_state)
2007-09-25 23:00:07 +05:30
bool rc_service_add (const char *runlevel, const char *service)
{
2007-09-25 23:00:07 +05:30
bool retval;
2007-04-11 18:14:47 +05:30
char *init;
char *file;
if (! rc_runlevel_exists (runlevel)) {
errno = ENOENT;
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
}
2007-09-25 23:00:07 +05:30
if (rc_service_in_runlevel (service, runlevel)) {
2007-04-11 18:14:47 +05:30
errno = EEXIST;
2007-09-25 23:00:07 +05:30
return (false);
2007-04-11 18:14:47 +05:30
}
init = rc_service_resolve (service);
/* We need to ensure that only things in /etc/init.d are added
* to the boot runlevel */
if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) {
char tmp[MAXPATHLEN] = { '\0' };
char *p;
p = realpath (dirname (init), tmp);
free (init);
if (! *p)
return (false);
retval = (strcmp (tmp, RC_INITDIR) == 0);
if (! retval) {
errno = EPERM;
return (false);
}
init = rc_strcatpaths (RC_INITDIR, service, (char *) NULL);
}
2007-12-19 19:23:52 +05:30
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-09-25 23:00:07 +05:30
retval = (symlink (init, file) == 0);
2007-04-11 18:14:47 +05:30
free (init);
free (file);
return (retval);
}
librc_hidden_def(rc_service_add)
2007-09-25 23:00:07 +05:30
bool rc_service_delete (const char *runlevel, const char *service)
{
2007-04-11 18:14:47 +05:30
char *file;
2007-09-25 23:00:07 +05:30
bool retval = false;
2007-04-11 18:14:47 +05:30
if (! runlevel || ! service)
2007-09-25 23:00:07 +05:30
return (false);
2007-04-10 16:54:58 +05:30
2007-12-19 19:23:52 +05:30
file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-09-25 23:00:07 +05:30
if (unlink (file) == 0)
retval = true;
2007-04-11 18:14:47 +05:30
free (file);
return (retval);
}
librc_hidden_def(rc_service_delete)
char **rc_services_scheduled_by (const char *service)
{
2007-10-05 15:46:14 +05:30
char **dirs = ls_dir (RC_SVCDIR "/scheduled", 0);
2007-04-11 18:14:47 +05:30
char **list = NULL;
char *dir;
int i;
STRLIST_FOREACH (dirs, dir, i) {
char *file = rc_strcatpaths (RC_SVCDIR, "scheduled", dir, service,
2008-01-11 21:21:40 +05:30
(char *) NULL);
if (exists (file))
rc_strlist_add (&list, file);
2007-04-11 18:14:47 +05:30
free (file);
}
rc_strlist_free (dirs);
return (list);
}
librc_hidden_def(rc_services_scheduled_by)
char **rc_services_scheduled (const char *service)
{
2007-12-19 19:23:52 +05:30
char *dir = rc_strcatpaths (RC_SVCDIR, "scheduled", basename_c (service),
2008-01-11 21:21:40 +05:30
(char *) NULL);
2007-04-11 18:14:47 +05:30
char **list = NULL;
2007-10-05 15:46:14 +05:30
list = ls_dir (dir, LS_INITD);
2007-04-11 18:14:47 +05:30
free (dir);
return (list);
}
librc_hidden_def(rc_services_scheduled)