mirror of
https://github.com/troglobit/finit.git
synced 2026-10-13 10:14:47 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
685618691d | ||
|
|
f29d2733c7 | ||
|
|
af59174e49 | ||
|
|
785c21d27b | ||
|
|
40c7a44d4f | ||
|
|
cbb50937cd | ||
|
|
83a4bf7947 | ||
|
|
0d7d5a9820 |
@@ -1,3 +1,16 @@
|
|||||||
|
1.6 (20121006)
|
||||||
|
- Skip . and .. in plugin loader and display error on failed plugins
|
||||||
|
- Support for overriding /etc/finit.d with "runparts DIR" in finit.conf
|
||||||
|
- Revoke support for starting services not starting with a slash.
|
||||||
|
- Prevent endless restart of non-existing services in finit.conf
|
||||||
|
- Support for sysvinit style startstop scripts in /etc/finit.d
|
||||||
|
- Minor fix to alsa-utils plugin to silence on non-existing cards
|
||||||
|
|
||||||
|
1.5 (20121003)
|
||||||
|
- Use bootmisc plugin to setup standard FHS 2.3 structure in /var
|
||||||
|
- Added FLOG_WARN() syslog macro, for plugins
|
||||||
|
- Add plugin dependency resolver. Checks plugin_t for .depends
|
||||||
|
|
||||||
1.4 (20121002)
|
1.4 (20121002)
|
||||||
- Fix I/O plugin watcher and load plugins earlier for a new hook
|
- Fix I/O plugin watcher and load plugins earlier for a new hook
|
||||||
- Start refactoring helpers.c into a libite.so (-lite). This
|
- Start refactoring helpers.c into a libite.so (-lite). This
|
||||||
|
|||||||
@@ -29,13 +29,13 @@
|
|||||||
ROOTDIR = $(shell pwd)
|
ROOTDIR = $(shell pwd)
|
||||||
|
|
||||||
#VERSION ?= $(shell git tag -l | tail -1)
|
#VERSION ?= $(shell git tag -l | tail -1)
|
||||||
VERSION ?= 1.4
|
VERSION ?= 1.6
|
||||||
NAME = finit
|
NAME = finit
|
||||||
PKG = $(NAME)-$(VERSION)
|
PKG = $(NAME)-$(VERSION)
|
||||||
DEV = $(NAME)-dev
|
DEV = $(NAME)-dev
|
||||||
ARCHIVE = $(PKG).tar.xz
|
ARCHIVE = $(PKG).tar.xz
|
||||||
EXEC = finit reboot
|
EXEC = finit reboot
|
||||||
HEADERS = plugin.h svc.h helpers.h
|
HEADERS = plugin.h svc.h helpers.h queue.h
|
||||||
DISTFILES = LICENSE README ChangeLog finit.conf services
|
DISTFILES = LICENSE README ChangeLog finit.conf services
|
||||||
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
|
OBJS = finit.o conf.o helpers.o sig.o svc.o plugin.o
|
||||||
OBJS += strlcpy.o
|
OBJS += strlcpy.o
|
||||||
|
|||||||
@@ -122,6 +122,11 @@ void parse_finit_conf(char *file)
|
|||||||
network = build_cmd(NULL, x, CMD_SIZE);
|
network = build_cmd(NULL, x, CMD_SIZE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (MATCH_CMD(line, "runparts ", x)) {
|
||||||
|
if (rcsd) free(rcsd);
|
||||||
|
hostname = build_cmd(NULL, x, CMD_SIZE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (MATCH_CMD(line, "startx ", x)) {
|
if (MATCH_CMD(line, "startx ", x)) {
|
||||||
svc_register(x, username);
|
svc_register(x, username);
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
#include "sig.h"
|
#include "sig.h"
|
||||||
|
#include "lite.h"
|
||||||
|
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
int verbose = 1;
|
int verbose = 1;
|
||||||
@@ -40,6 +41,7 @@ char *sdown = NULL;
|
|||||||
char *network = NULL;
|
char *network = NULL;
|
||||||
char *username = NULL;
|
char *username = NULL;
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
|
char *rcsd = FINIT_RCSD;
|
||||||
|
|
||||||
|
|
||||||
static void parse_kernel_cmdline(void)
|
static void parse_kernel_cmdline(void)
|
||||||
@@ -181,8 +183,10 @@ int main(int UNUSED(args), char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Run startup scripts in /etc/finit.d/, if any.
|
* Run startup scripts in /etc/finit.d/, if any.
|
||||||
*/
|
*/
|
||||||
_d("Running startup scripts in /etc/finit.d/ ...");
|
if (rcsd && fisdir(rcsd)) {
|
||||||
run_parts(FINIT_RCSD);
|
_d("Running startup scripts in %s ...", rcsd);
|
||||||
|
run_parts(rcsd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hooks that should run at the very end
|
* Hooks that should run at the very end
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ extern char *sdown;
|
|||||||
extern char *network;
|
extern char *network;
|
||||||
extern char *hostname;
|
extern char *hostname;
|
||||||
extern char *username;
|
extern char *username;
|
||||||
|
extern char *rcsd;
|
||||||
|
|
||||||
/* conf.c */
|
/* conf.c */
|
||||||
void parse_finit_conf(char *file);
|
void parse_finit_conf(char *file);
|
||||||
|
|||||||
@@ -566,75 +566,61 @@ pid_t run_getty(char *cmd, char *argv[])
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp(const void *s1, const void *s2)
|
int run_parts(char *dir, char *cmd)
|
||||||
{
|
{
|
||||||
return strcmp(*(char **)s1, *(char **)s2);
|
struct dirent **e;
|
||||||
}
|
int i, num;
|
||||||
|
|
||||||
int run_parts(char *dir, ...)
|
num = scandir(dir, &e, NULL, alphasort);
|
||||||
{
|
if (num < 0) {
|
||||||
DIR *d;
|
_d("No files found in %s, skipping ...", dir);
|
||||||
struct dirent *e;
|
|
||||||
struct stat st;
|
|
||||||
char *oldpwd = NULL;
|
|
||||||
char *ent[NUM_SCRIPTS];
|
|
||||||
int i, num = 0, argnum = 1;
|
|
||||||
char *args[NUM_ARGS];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
oldpwd = getcwd (NULL, 0);
|
|
||||||
if (chdir(dir)) {
|
|
||||||
if (oldpwd) free(oldpwd);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((d = opendir(dir)) == NULL) {
|
|
||||||
if (oldpwd) free(oldpwd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(ap, dir);
|
|
||||||
while (argnum < NUM_ARGS && (args[argnum++] = va_arg(ap, char *)));
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
while ((e = readdir(d))) {
|
|
||||||
if (e->d_type == DT_REG && stat(e->d_name, &st) == 0) {
|
|
||||||
_d("Found %s/%s ...", dir, e->d_name);
|
|
||||||
if (st.st_mode & S_IXUSR) {
|
|
||||||
ent[num++] = strdup(e->d_name);
|
|
||||||
if (num >= NUM_SCRIPTS)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(d);
|
|
||||||
|
|
||||||
if (num == 0) {
|
|
||||||
if (oldpwd) free(oldpwd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort(ent, num, sizeof(char *), cmp);
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
|
int j = 0, status;
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
int status;
|
mode_t mode;
|
||||||
|
char *args[NUM_ARGS];
|
||||||
|
char *name = e[i]->d_name;
|
||||||
|
char path[CMD_SIZE];
|
||||||
|
|
||||||
args[0] = ent[i];
|
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||||
args[1] = NULL;
|
mode = fmode(path);
|
||||||
|
if (!S_ISEXEC(mode) || S_ISDIR(mode)) {
|
||||||
|
_d("Skipping %s ...", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill in args[], starting with full path to executable */
|
||||||
|
args[j++] = path;
|
||||||
|
|
||||||
|
/* If the callee didn't supply a run_parts() argument */
|
||||||
|
if (!cmd) {
|
||||||
|
/* Check if S<NUM>service or K<NUM>service notation is used */
|
||||||
|
_d("Checking if %s is a sysvinit startstop script ...", name);
|
||||||
|
if (name[0] == 'S' && isdigit(name[1])) {
|
||||||
|
args[j++] = "start";
|
||||||
|
} else if (name[0] == 'K' && isdigit(name[1])) {
|
||||||
|
args[j++] = "stop";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[j++] = cmd;
|
||||||
|
}
|
||||||
|
args[j++] = NULL;
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
_d("Calling %s ...", ent[i]);
|
_d("Calling %s ...", path);
|
||||||
execv(ent[i], args);
|
execv(path, args);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
free(ent[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chdir(oldpwd);
|
while (num--)
|
||||||
free(oldpwd);
|
free(e[num]);
|
||||||
|
free(e);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
|
#define FLOG_DEBUG(fmt, args...) DO_LOG(LOG_DEBUG, fmt, ##args)
|
||||||
|
#define FLOG_WARN(fmt, args...) DO_LOG(LOG_WARNING, fmt, ##args)
|
||||||
#define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
|
#define FLOG_ERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt, ##args)
|
||||||
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
|
#define FLOG_PERROR(fmt, args...) DO_LOG(LOG_CRIT, fmt ". Error %d: %s", ##args, errno, strerror(errno))
|
||||||
|
|
||||||
@@ -49,7 +50,9 @@
|
|||||||
#ifndef blkdev
|
#ifndef blkdev
|
||||||
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
|
# define blkdev(x,m,maj,min) mknod((x), S_IFBLK|(m), makedev((maj),(min)))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef S_ISEXEC
|
||||||
|
# define S_ISEXEC(m) (((m) & S_IXUSR) == S_IXUSR)
|
||||||
|
#endif
|
||||||
#ifndef UNUSED
|
#ifndef UNUSED
|
||||||
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
|
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
|
||||||
#endif
|
#endif
|
||||||
@@ -86,7 +89,7 @@ void set_hostname (char *hostname);
|
|||||||
int run (char *cmd);
|
int run (char *cmd);
|
||||||
int run_interactive (char *cmd, char *fmt, ...);
|
int run_interactive (char *cmd, char *fmt, ...);
|
||||||
pid_t run_getty (char *cmd, char *argv[]);
|
pid_t run_getty (char *cmd, char *argv[]);
|
||||||
int run_parts (char *dir, ...);
|
int run_parts (char *dir, char *cmd);
|
||||||
|
|
||||||
/* strlcpy.c */
|
/* strlcpy.c */
|
||||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ mode_t fmode(char *file)
|
|||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0; /* Doesn't exist ... */
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stat(file, &sb))
|
if (!stat(file, &sb))
|
||||||
|
|||||||
@@ -26,18 +26,22 @@
|
|||||||
#include <dirent.h> /* readdir() et al */
|
#include <dirent.h> /* readdir() et al */
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/queue.h> /* BSD sys/queue.h API */
|
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "queue.h" /* BSD sys/queue.h API */
|
||||||
|
#include "lite.h"
|
||||||
|
|
||||||
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
|
#define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0)
|
||||||
|
|
||||||
static size_t num_fds = 0;
|
static char *plugpath = NULL; /* Set by first load. */
|
||||||
|
static size_t num_fds = 0;
|
||||||
static struct pollfd fds[MAX_NUM_FDS];
|
static struct pollfd fds[MAX_NUM_FDS];
|
||||||
static LIST_HEAD(, plugin) plugins = LIST_HEAD_INITIALIZER();
|
static TAILQ_HEAD(, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins);
|
||||||
|
|
||||||
|
static void check_plugin_depends(plugin_t *plugin);
|
||||||
|
|
||||||
int plugin_register(plugin_t *plugin)
|
int plugin_register(plugin_t *plugin)
|
||||||
{
|
{
|
||||||
@@ -57,6 +61,14 @@ int plugin_register(plugin_t *plugin)
|
|||||||
plugin->name = (char *)info.dli_fname;
|
plugin->name = (char *)info.dli_fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Already registered? */
|
||||||
|
if (plugin_find(plugin->name)) {
|
||||||
|
_d("... %s already loaded.", plugin->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_plugin_depends(plugin);
|
||||||
|
|
||||||
if (is_io_plugin(plugin)) {
|
if (is_io_plugin(plugin)) {
|
||||||
if (num_fds + 1 >= MAX_NUM_FDS) {
|
if (num_fds + 1 >= MAX_NUM_FDS) {
|
||||||
num_fds = MAX_NUM_SVC;
|
num_fds = MAX_NUM_SVC;
|
||||||
@@ -88,14 +100,14 @@ int plugin_register(plugin_t *plugin)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_INSERT_HEAD(&plugins, plugin, link);
|
TAILQ_INSERT_TAIL(&plugins, plugin, link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int plugin_unregister(plugin_t *plugin)
|
int plugin_unregister(plugin_t *plugin)
|
||||||
{
|
{
|
||||||
LIST_REMOVE(plugin, link);
|
TAILQ_REMOVE(&plugins, plugin, link);
|
||||||
|
|
||||||
if (plugin->svc.cb) {
|
if (plugin->svc.cb) {
|
||||||
svc_t *svc = svc_find(plugin->name);
|
svc_t *svc = svc_find(plugin->name);
|
||||||
@@ -111,12 +123,64 @@ int plugin_unregister(plugin_t *plugin)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SEARCH_PLUGIN(str) \
|
||||||
|
PLUGIN_ITERATOR(p, tmp) { \
|
||||||
|
_d("Comparing %s against plugin %s", str, p->name); \
|
||||||
|
if (!strcmp(p->name, str)) \
|
||||||
|
return p; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plugin_find - Find a plugin by name
|
||||||
|
* @name: With or without path, or .so extension
|
||||||
|
*
|
||||||
|
* This function uses an opporunistic search for a suitable plugin and
|
||||||
|
* returns the first match. Albeit with at least some measure of
|
||||||
|
* heuristics.
|
||||||
|
*
|
||||||
|
* First it checks for an exact match. If no match is found and @name
|
||||||
|
* starts with a slash the search ends. Otherwise a new search with the
|
||||||
|
* plugin path prepended to @name is made. Also, if @name does not end
|
||||||
|
* with .so it too is added to @name before searching.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* On success the pointer to the matching &plugin_t is returned,
|
||||||
|
* otherwise %NULL is returned.
|
||||||
|
*/
|
||||||
|
plugin_t *plugin_find(char *name)
|
||||||
|
{
|
||||||
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEARCH_PLUGIN(name);
|
||||||
|
|
||||||
|
if (name[0] != '/') {
|
||||||
|
int noext;
|
||||||
|
char path[CMD_SIZE];
|
||||||
|
|
||||||
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
|
snprintf (path, sizeof(path), "%s%s%s%s", plugpath,
|
||||||
|
fisslashdir(plugpath) ? "" : "/",
|
||||||
|
name, noext ? ".so" : "");
|
||||||
|
|
||||||
|
SEARCH_PLUGIN(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = ENOENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Private daemon API *******************************************************/
|
/* Private daemon API *******************************************************/
|
||||||
void plugin_run_hooks(hook_point_t no)
|
void plugin_run_hooks(hook_point_t no)
|
||||||
{
|
{
|
||||||
plugin_t *p;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (p->hook[no].cb) {
|
if (p->hook[no].cb) {
|
||||||
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
|
_d("Calling %s hook n:o %d from runloop...", basename(p->name), no);
|
||||||
p->hook[no].cb(p->hook[no].arg);
|
p->hook[no].cb(p->hook[no].arg);
|
||||||
@@ -127,10 +191,10 @@ void plugin_run_hooks(hook_point_t no)
|
|||||||
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
|
/* Generic libev I/O callback, looks up correct plugin and calls its callback */
|
||||||
static void generic_io_cb(int fd, int events)
|
static void generic_io_cb(int fd, int events)
|
||||||
{
|
{
|
||||||
plugin_t *p;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
/* Find matching plugin, pick first matching fd */
|
/* Find matching plugin, pick first matching fd */
|
||||||
PLUGIN_ITERATOR(p) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (is_io_plugin(p) && p->io.fd == fd) {
|
if (is_io_plugin(p) && p->io.fd == fd) {
|
||||||
_d("Calling I/O %s from runloop...", basename(p->name));
|
_d("Calling I/O %s from runloop...", basename(p->name));
|
||||||
p->io.cb(p->io.arg, fd, events);
|
p->io.cb(p->io.arg, fd, events);
|
||||||
@@ -168,9 +232,9 @@ void plugin_monitor(void)
|
|||||||
static void init_plugins(void)
|
static void init_plugins(void)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
plugin_t *p;
|
plugin_t *p, *tmp;
|
||||||
|
|
||||||
PLUGIN_ITERATOR(p) {
|
PLUGIN_ITERATOR(p, tmp) {
|
||||||
if (is_io_plugin(p)) {
|
if (is_io_plugin(p)) {
|
||||||
_d("Initializing plugin %s for I/O", basename(p->name));
|
_d("Initializing plugin %s for I/O", basename(p->name));
|
||||||
fds[i].revents = 0;
|
fds[i].revents = 0;
|
||||||
@@ -180,6 +244,72 @@ static void init_plugins(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load_one - Load one plugin
|
||||||
|
* @path: Path to finit plugins, usually %PLUGIN_PATH
|
||||||
|
* @name: Name of plugin, optionally ending in ".so"
|
||||||
|
*
|
||||||
|
* Loads a plugin from @path/@name[.so]. Note, if ".so" is missing from
|
||||||
|
* the plugin @name it is added before attempting to load.
|
||||||
|
*
|
||||||
|
* It is up to the plugin itself ot register itself as a "ctor" with the
|
||||||
|
* %PLUGIN_INIT macro so that plugin_register() is called automatically.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* POSIX OK(0) on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
static int load_one(char *path, char *name)
|
||||||
|
{
|
||||||
|
int noext;
|
||||||
|
char plugin[CMD_SIZE];
|
||||||
|
void *handle;
|
||||||
|
|
||||||
|
if (!path || !fisdir(path) || !name) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compose full path, with optional .so extension, to plugin */
|
||||||
|
noext = strcmp(name + strlen(name) - 3, ".so");
|
||||||
|
snprintf(plugin, sizeof(plugin), "%s/%s%s", path, name, noext ? ".so" : "");
|
||||||
|
|
||||||
|
_d("Loading plugin %s ...", basename(plugin));
|
||||||
|
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
if (!handle) {
|
||||||
|
_e("Failed loading plugin %s: %s", plugin, dlerror());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check_plugin_depends - Check and load any plugins this one depends on.
|
||||||
|
* @plugin: Plugin with possible depends to check
|
||||||
|
*
|
||||||
|
* Very simple dependency resolver, should actually load the plugin of
|
||||||
|
* the correct .name, but currently loads a matching filename.
|
||||||
|
*
|
||||||
|
* Works, but only for now. A better way might be to have a try_load()
|
||||||
|
* that actually loads all plugins and checks their &plugin_t for the
|
||||||
|
* correct .name.
|
||||||
|
*/
|
||||||
|
static void check_plugin_depends(plugin_t *plugin)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < PLUGIN_DEP_MAX && plugin->depends[i]; i++) {
|
||||||
|
_d("Plugin %s depends on %s ...", plugin->name, plugin->depends[i]);
|
||||||
|
if (plugin_find(plugin->depends[i])) {
|
||||||
|
_d("OK plugin %s was already loaded.", plugin->depends[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_one(plugpath, plugin->depends[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int plugin_load_all(char *path)
|
int plugin_load_all(char *path)
|
||||||
{
|
{
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
@@ -190,27 +320,16 @@ int plugin_load_all(char *path)
|
|||||||
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
_e("Failed, cannot open plugin directory %s: %s", path, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
plugpath = path;
|
||||||
|
|
||||||
while ((entry = readdir(dp))) {
|
while ((entry = readdir(dp))) {
|
||||||
char *ext = entry->d_name + strlen(entry->d_name) - 3;
|
if (entry->d_name[0] == '.')
|
||||||
|
continue; /* Skip . and .. directories */
|
||||||
|
|
||||||
if (!strcmp(ext, ".so")) {
|
// print_desc(" Loading plugin ", basename(plugin));
|
||||||
int result = 0;
|
if (load_one(path, entry->d_name))
|
||||||
void *handle;
|
fail++;
|
||||||
char plugin[1024];
|
// print_result(result);
|
||||||
|
|
||||||
snprintf(plugin, sizeof(plugin), "%s/%s", path, entry->d_name);
|
|
||||||
// print_desc(" Loading plugin ", basename(plugin));
|
|
||||||
handle = dlopen(plugin, RTLD_LAZY | RTLD_GLOBAL);
|
|
||||||
if (!handle) {
|
|
||||||
_d("Failed loading plugin %s: %s", plugin, dlerror());
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
if (result)
|
|
||||||
fail++;
|
|
||||||
|
|
||||||
// print_result(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|||||||
@@ -25,16 +25,17 @@
|
|||||||
#define FINIT_PLUGIN_H_
|
#define FINIT_PLUGIN_H_
|
||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/queue.h> /* BSD sys/queue.h API */
|
#include "queue.h" /* BSD sys/queue.h API */
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
|
#define PLUGIN_DEP_MAX 10
|
||||||
#define PLUGIN_IO_READ POLLIN
|
#define PLUGIN_IO_READ POLLIN
|
||||||
#define PLUGIN_IO_WRITE POLLOUT
|
#define PLUGIN_IO_WRITE POLLOUT
|
||||||
|
|
||||||
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
|
#define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void)
|
||||||
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
|
#define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void)
|
||||||
|
|
||||||
#define PLUGIN_ITERATOR(x) LIST_FOREACH(x, &plugins, link)
|
#define PLUGIN_ITERATOR(x, tmp) TAILQ_FOREACH_SAFE(x, &plugins, link, tmp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Predefined hook points for easier plugin debugging
|
* Predefined hook points for easier plugin debugging
|
||||||
@@ -76,9 +77,9 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
typedef struct plugin {
|
typedef struct plugin {
|
||||||
/* BSD sys/queue.h linked list node. */
|
/* BSD sys/queue.h linked list node. */
|
||||||
LIST_ENTRY(plugin) link;
|
TAILQ_ENTRY(plugin) link;
|
||||||
|
|
||||||
/* Plugin name, defaults to plugin path if unset.
|
/* Plugin name, defaults to basename of plugin path if unset.
|
||||||
* NOTE: Must be same as @cmd for service plugins! */
|
* NOTE: Must be same as @cmd for service plugins! */
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
@@ -101,12 +102,17 @@ typedef struct plugin {
|
|||||||
void *arg;
|
void *arg;
|
||||||
void (*cb)(void *arg, int fd, int events);
|
void (*cb)(void *arg, int fd, int events);
|
||||||
} io;
|
} io;
|
||||||
|
|
||||||
|
char *depends[PLUGIN_DEP_MAX]; /* List of other .name's this depends on. */
|
||||||
} plugin_t;
|
} plugin_t;
|
||||||
|
|
||||||
/* Public plugin API */
|
/* Public plugin API */
|
||||||
int plugin_register (plugin_t *plugin);
|
int plugin_register (plugin_t *plugin);
|
||||||
int plugin_unregister (plugin_t *plugin);
|
int plugin_unregister (plugin_t *plugin);
|
||||||
|
|
||||||
|
/* Helper API */
|
||||||
|
plugin_t *plugin_find (char *name);
|
||||||
|
|
||||||
#endif /* FINIT_PLUGIN_H_ */
|
#endif /* FINIT_PLUGIN_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,14 +27,14 @@
|
|||||||
|
|
||||||
static void save(void *UNUSED(arg))
|
static void save(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
_d("Saving system clock to RTC ...");
|
_d("Saving sound settings ...");
|
||||||
run_interactive("/usr/sbin/alsactl store > /dev/null 2>&1", "Saving sound settings");
|
run_interactive("/usr/sbin/alsactl -g store", "Saving sound settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore(void *UNUSED(arg))
|
static void restore(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
_d("Restoring system clock from RTC ...");
|
_d("Restoring sound settings ...");
|
||||||
run_interactive("/usr/sbin/alsactl restore > /dev/null 2>&1", "Restoring sound settings");
|
run_interactive("/usr/sbin/alsactl -g restore", "Restoring sound settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
|||||||
@@ -28,12 +28,32 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup standard FHS 2.3 structure in /var, and
|
||||||
|
* write runlevel to UTMP, needed by, e.g., printerdrake.
|
||||||
|
*/
|
||||||
static void setup(void *UNUSED(arg))
|
static void setup(void *UNUSED(arg))
|
||||||
{
|
{
|
||||||
#ifdef RUNLEVEL
|
#ifdef RUNLEVEL
|
||||||
struct utmp entry;
|
struct utmp entry;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_d("Setting up FHS structure in /var ...");
|
||||||
|
mkdir("/var/cache", 0755);
|
||||||
|
mkdir("/var/games", 0755);
|
||||||
|
mkdir("/var/lib", 0755);
|
||||||
|
mkdir("/var/lib/misc", 0755);
|
||||||
|
mkdir("/var/lib/alarm", 0755);
|
||||||
|
mkdir("/var/lock", 0755);
|
||||||
|
mkdir("/var/log", 0755);
|
||||||
|
mkdir("/var/mail", 0755);
|
||||||
|
mkdir("/var/opt", 0755);
|
||||||
|
mkdir("/var/run", 0755);
|
||||||
|
mkdir("/var/spool", 0755);
|
||||||
|
mkdir("/var/spool/cron", 0755);
|
||||||
|
mkdir("/var/tmp", 0755);
|
||||||
|
mkdir("/var/empty", 0755);
|
||||||
|
|
||||||
_d("Setting up necessary UTMP files ...");
|
_d("Setting up necessary UTMP files ...");
|
||||||
touch("/var/run/utmp");
|
touch("/var/run/utmp");
|
||||||
chown("/var/run/utmp", 0, getgroup("utmp"));
|
chown("/var/run/utmp", 0, getgroup("utmp"));
|
||||||
@@ -55,12 +75,17 @@ static void setup(void *UNUSED(arg))
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_d("Setting up misc files ...");
|
_d("Setting up misc files ...");
|
||||||
|
mkdir("/var/run/lldpd", 0755); /* Needed by lldpd */
|
||||||
|
mkdir("/var/run/pluto", 0755); /* Needed by Openswan */
|
||||||
|
mkdir("/var/run/quagga", 0755); /* Needed by Quagga */
|
||||||
|
mkdir("/var/log/quagga", 0755); /* Needed by Quagga */
|
||||||
mkdir("/var/run/sshd", 01755); /* OpenSSH */
|
mkdir("/var/run/sshd", 01755); /* OpenSSH */
|
||||||
mkfifo("/dev/xconsole", 0640); /* sysklogd */
|
mkfifo("/dev/xconsole", 0640); /* sysklogd */
|
||||||
chown("/dev/xconsole", 0, getgroup("tty"));
|
chown("/dev/xconsole", 0, getgroup("tty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static plugin_t plugin = {
|
static plugin_t plugin = {
|
||||||
|
.name = "bootmisc",
|
||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_NETWORK_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ static void setup(void *UNUSED(arg))
|
|||||||
touch("/etc/resolvconf/run/enable-updates");
|
touch("/etc/resolvconf/run/enable-updates");
|
||||||
|
|
||||||
chdir("/etc/resolvconf/run/interface");
|
chdir("/etc/resolvconf/run/interface");
|
||||||
run_parts("/etc/resolvconf/update.d", "-i", NULL);
|
run_parts("/etc/resolvconf/update.d", "-i");
|
||||||
chdir("/");
|
chdir("/");
|
||||||
#endif /* USE_ETC_RESOLVCONF_RUN */
|
#endif /* USE_ETC_RESOLVCONF_RUN */
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,7 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
.depends = { "bootmisc", },
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_BASEFS_UP] = {
|
.hook[HOOK_BASEFS_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
.depends = { "bootmisc", }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ static plugin_t plugin = {
|
|||||||
.hook[HOOK_NETWORK_UP] = {
|
.hook[HOOK_NETWORK_UP] = {
|
||||||
.cb = setup
|
.cb = setup
|
||||||
},
|
},
|
||||||
|
.depends = { "bootmisc", }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INIT(plugin_init)
|
PLUGIN_INIT(plugin_init)
|
||||||
|
|||||||
@@ -0,0 +1,568 @@
|
|||||||
|
/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */
|
||||||
|
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1991, 1993
|
||||||
|
* The Regents of the University of California. 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.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||||
|
*
|
||||||
|
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_QUEUE_H_
|
||||||
|
#define _SYS_QUEUE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file defines five types of data structures: singly-linked lists,
|
||||||
|
* lists, simple queues, tail queues, and circular queues.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* A singly-linked list is headed by a single forward pointer. The elements
|
||||||
|
* are singly linked for minimum space and pointer manipulation overhead at
|
||||||
|
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||||
|
* added to the list after an existing element or at the head of the list.
|
||||||
|
* Elements being removed from the head of the list should use the explicit
|
||||||
|
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||||
|
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||||
|
* for applications with large datasets and few or no removals or for
|
||||||
|
* implementing a LIFO queue.
|
||||||
|
*
|
||||||
|
* A list is headed by a single forward pointer (or an array of forward
|
||||||
|
* pointers for a hash table header). The elements are doubly linked
|
||||||
|
* so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before
|
||||||
|
* or after an existing element or at the head of the list. A list
|
||||||
|
* may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A simple queue is headed by a pair of pointers, one the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are singly
|
||||||
|
* linked to save space, so elements can only be removed from the
|
||||||
|
* head of the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the
|
||||||
|
* list. A simple queue may only be traversed in the forward direction.
|
||||||
|
*
|
||||||
|
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or
|
||||||
|
* after an existing element, at the head of the list, or at the end of
|
||||||
|
* the list. A tail queue may be traversed in either direction.
|
||||||
|
*
|
||||||
|
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||||
|
* list and the other to the tail of the list. The elements are doubly
|
||||||
|
* linked so that an arbitrary element can be removed without a need to
|
||||||
|
* traverse the list. New elements can be added to the list before or after
|
||||||
|
* an existing element, at the head of the list, or at the end of the list.
|
||||||
|
* A circle queue may be traversed in either direction, but has a more
|
||||||
|
* complex end of list detection.
|
||||||
|
*
|
||||||
|
* For details on the use of these macros, see the queue(3) manual page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
|
||||||
|
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
||||||
|
#else
|
||||||
|
#define _Q_INVALIDATE(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List definitions.
|
||||||
|
*/
|
||||||
|
#define SLIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *slh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define SLIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sle_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List access methods.
|
||||||
|
*/
|
||||||
|
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||||
|
#define SLIST_END(head) NULL
|
||||||
|
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||||
|
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||||
|
|
||||||
|
#define SLIST_FOREACH(var, head, field) \
|
||||||
|
for((var) = SLIST_FIRST(head); \
|
||||||
|
(var) != SLIST_END(head); \
|
||||||
|
(var) = SLIST_NEXT(var, field))
|
||||||
|
|
||||||
|
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = SLIST_FIRST(head); \
|
||||||
|
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Singly-linked List functions.
|
||||||
|
*/
|
||||||
|
#define SLIST_INIT(head) { \
|
||||||
|
SLIST_FIRST(head) = SLIST_END(head); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||||
|
(slistelm)->field.sle_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (head)->slh_first; \
|
||||||
|
(head)->slh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_AFTER(elm, field) do { \
|
||||||
|
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||||
|
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||||
|
if ((head)->slh_first == (elm)) { \
|
||||||
|
SLIST_REMOVE_HEAD((head), field); \
|
||||||
|
} else { \
|
||||||
|
struct type *curelm = (head)->slh_first; \
|
||||||
|
\
|
||||||
|
while (curelm->field.sle_next != (elm)) \
|
||||||
|
curelm = curelm->field.sle_next; \
|
||||||
|
curelm->field.sle_next = \
|
||||||
|
curelm->field.sle_next->field.sle_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.sle_next); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List definitions.
|
||||||
|
*/
|
||||||
|
#define LIST_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *lh_first; /* first element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIST_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
|
#define LIST_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *le_next; /* next element */ \
|
||||||
|
struct type **le_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List access methods
|
||||||
|
*/
|
||||||
|
#define LIST_FIRST(head) ((head)->lh_first)
|
||||||
|
#define LIST_END(head) NULL
|
||||||
|
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||||
|
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||||
|
|
||||||
|
#define LIST_FOREACH(var, head, field) \
|
||||||
|
for((var) = LIST_FIRST(head); \
|
||||||
|
(var)!= LIST_END(head); \
|
||||||
|
(var) = LIST_NEXT(var, field))
|
||||||
|
|
||||||
|
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = LIST_FIRST(head); \
|
||||||
|
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List functions.
|
||||||
|
*/
|
||||||
|
#define LIST_INIT(head) do { \
|
||||||
|
LIST_FIRST(head) = LIST_END(head); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||||
|
(listelm)->field.le_next->field.le_prev = \
|
||||||
|
&(elm)->field.le_next; \
|
||||||
|
(listelm)->field.le_next = (elm); \
|
||||||
|
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||||
|
(elm)->field.le_next = (listelm); \
|
||||||
|
*(listelm)->field.le_prev = (elm); \
|
||||||
|
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||||
|
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||||
|
(head)->lh_first = (elm); \
|
||||||
|
(elm)->field.le_prev = &(head)->lh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_REMOVE(elm, field) do { \
|
||||||
|
if ((elm)->field.le_next != NULL) \
|
||||||
|
(elm)->field.le_next->field.le_prev = \
|
||||||
|
(elm)->field.le_prev; \
|
||||||
|
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||||
|
(elm2)->field.le_next->field.le_prev = \
|
||||||
|
&(elm2)->field.le_next; \
|
||||||
|
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||||
|
*(elm2)->field.le_prev = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue definitions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *sqh_first; /* first element */ \
|
||||||
|
struct type **sqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).sqh_first }
|
||||||
|
|
||||||
|
#define SIMPLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *sqe_next; /* next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue access methods.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||||
|
#define SIMPLEQ_END(head) NULL
|
||||||
|
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||||
|
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||||
|
|
||||||
|
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = SIMPLEQ_FIRST(head); \
|
||||||
|
(var) != SIMPLEQ_END(head); \
|
||||||
|
(var) = SIMPLEQ_NEXT(var, field))
|
||||||
|
|
||||||
|
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = SIMPLEQ_FIRST(head); \
|
||||||
|
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple queue functions.
|
||||||
|
*/
|
||||||
|
#define SIMPLEQ_INIT(head) do { \
|
||||||
|
(head)->sqh_first = NULL; \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(head)->sqh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.sqe_next = NULL; \
|
||||||
|
*(head)->sqh_last = (elm); \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
(listelm)->field.sqe_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||||
|
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||||
|
(head)->sqh_last = &(head)->sqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
|
||||||
|
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
|
||||||
|
== NULL) \
|
||||||
|
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue definitions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *tqh_first; /* first element */ \
|
||||||
|
struct type **tqh_last; /* addr of last next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ NULL, &(head).tqh_first }
|
||||||
|
|
||||||
|
#define TAILQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *tqe_next; /* next element */ \
|
||||||
|
struct type **tqe_prev; /* address of previous next element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tail queue access methods
|
||||||
|
*/
|
||||||
|
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||||
|
#define TAILQ_END(head) NULL
|
||||||
|
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||||
|
#define TAILQ_LAST(head, headname) \
|
||||||
|
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||||
|
/* XXX */
|
||||||
|
#define TAILQ_PREV(elm, headname, field) \
|
||||||
|
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||||
|
#define TAILQ_EMPTY(head) \
|
||||||
|
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = TAILQ_FIRST(head); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = TAILQ_NEXT(var, field))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = TAILQ_FIRST(head); \
|
||||||
|
(var) != TAILQ_END(head) && \
|
||||||
|
((tvar) = TAILQ_NEXT(var, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||||
|
for((var) = TAILQ_LAST(head, headname); \
|
||||||
|
(var) != TAILQ_END(head); \
|
||||||
|
(var) = TAILQ_PREV(var, headname, field))
|
||||||
|
|
||||||
|
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||||
|
for ((var) = TAILQ_LAST(head, headname); \
|
||||||
|
(var) != TAILQ_END(head) && \
|
||||||
|
((tvar) = TAILQ_PREV(var, headname, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tail queue functions.
|
||||||
|
*/
|
||||||
|
#define TAILQ_INIT(head) do { \
|
||||||
|
(head)->tqh_first = NULL; \
|
||||||
|
(head)->tqh_last = &(head)->tqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||||
|
(head)->tqh_first->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(head)->tqh_first = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.tqe_next = NULL; \
|
||||||
|
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||||
|
*(head)->tqh_last = (elm); \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||||
|
(listelm)->field.tqe_next = (elm); \
|
||||||
|
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||||
|
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||||
|
(elm)->field.tqe_next = (listelm); \
|
||||||
|
*(listelm)->field.tqe_prev = (elm); \
|
||||||
|
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||||
|
if (((elm)->field.tqe_next) != NULL) \
|
||||||
|
(elm)->field.tqe_next->field.tqe_prev = \
|
||||||
|
(elm)->field.tqe_prev; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||||
|
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||||
|
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||||
|
&(elm2)->field.tqe_next; \
|
||||||
|
else \
|
||||||
|
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||||
|
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||||
|
*(elm2)->field.tqe_prev = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue definitions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_HEAD(name, type) \
|
||||||
|
struct name { \
|
||||||
|
struct type *cqh_first; /* first element */ \
|
||||||
|
struct type *cqh_last; /* last element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||||
|
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||||
|
|
||||||
|
#define CIRCLEQ_ENTRY(type) \
|
||||||
|
struct { \
|
||||||
|
struct type *cqe_next; /* next element */ \
|
||||||
|
struct type *cqe_prev; /* previous element */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue access methods
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||||
|
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||||
|
#define CIRCLEQ_END(head) ((void *)(head))
|
||||||
|
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||||
|
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||||
|
#define CIRCLEQ_EMPTY(head) \
|
||||||
|
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||||
|
for((var) = CIRCLEQ_FIRST(head); \
|
||||||
|
(var) != CIRCLEQ_END(head); \
|
||||||
|
(var) = CIRCLEQ_NEXT(var, field))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
|
for ((var) = CIRCLEQ_FIRST(head); \
|
||||||
|
(var) != CIRCLEQ_END(head) && \
|
||||||
|
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||||
|
for((var) = CIRCLEQ_LAST(head); \
|
||||||
|
(var) != CIRCLEQ_END(head); \
|
||||||
|
(var) = CIRCLEQ_PREV(var, field))
|
||||||
|
|
||||||
|
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||||
|
for ((var) = CIRCLEQ_LAST(head, headname); \
|
||||||
|
(var) != CIRCLEQ_END(head) && \
|
||||||
|
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
|
||||||
|
(var) = (tvar))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Circular queue functions.
|
||||||
|
*/
|
||||||
|
#define CIRCLEQ_INIT(head) do { \
|
||||||
|
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||||
|
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||||
|
(elm)->field.cqe_prev = (listelm); \
|
||||||
|
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||||
|
(listelm)->field.cqe_next = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (listelm); \
|
||||||
|
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||||
|
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||||
|
(listelm)->field.cqe_prev = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||||
|
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||||
|
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||||
|
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||||
|
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||||
|
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm); \
|
||||||
|
else \
|
||||||
|
(head)->cqh_last->field.cqe_next = (elm); \
|
||||||
|
(head)->cqh_last = (elm); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||||
|
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_next->field.cqe_prev = \
|
||||||
|
(elm)->field.cqe_prev; \
|
||||||
|
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||||
|
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||||
|
else \
|
||||||
|
(elm)->field.cqe_prev->field.cqe_next = \
|
||||||
|
(elm)->field.cqe_next; \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||||
|
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||||
|
CIRCLEQ_END(head)) \
|
||||||
|
(head).cqh_last = (elm2); \
|
||||||
|
else \
|
||||||
|
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||||
|
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||||
|
CIRCLEQ_END(head)) \
|
||||||
|
(head).cqh_first = (elm2); \
|
||||||
|
else \
|
||||||
|
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||||
|
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* !_SYS_QUEUE_H_ */
|
||||||
@@ -273,6 +273,20 @@ int svc_start(svc_t *svc)
|
|||||||
sigset_t nmask, omask;
|
sigset_t nmask, omask;
|
||||||
char *args[MAX_NUM_SVC_ARGS];
|
char *args[MAX_NUM_SVC_ARGS];
|
||||||
|
|
||||||
|
if (!svc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Don't try and start service if it doesn't exist. */
|
||||||
|
if (!fexist(svc->cmd)) {
|
||||||
|
char msg[80];
|
||||||
|
|
||||||
|
snprintf(msg, sizeof(msg), "Service %s does not exist!", svc->cmd);
|
||||||
|
print_desc("", msg);
|
||||||
|
print_result(1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ignore if finit is SIGSTOP'ed */
|
/* Ignore if finit is SIGSTOP'ed */
|
||||||
if (is_norespawn())
|
if (is_norespawn())
|
||||||
return 0;
|
return 0;
|
||||||
@@ -311,7 +325,7 @@ int svc_start(svc_t *svc)
|
|||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
int fd;
|
int fd;
|
||||||
char buf[256] = "";
|
char buf[CMD_SIZE] = "";
|
||||||
|
|
||||||
fd = open (CONSOLE, O_WRONLY | O_APPEND);
|
fd = open (CONSOLE, O_WRONLY | O_APPEND);
|
||||||
if (-1 != fd) {
|
if (-1 != fd) {
|
||||||
@@ -329,7 +343,10 @@ int svc_start(svc_t *svc)
|
|||||||
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
|
_e("%starting %s: %s", respawn ? "Res" : "S", svc->cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
execvp(svc->cmd, args);
|
/* XXX: Maybe change to use execve() to be able to launch scripts? */
|
||||||
|
execv(svc->cmd, args);
|
||||||
|
|
||||||
|
/* Only reach this point if exec() fails. */
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|||||||
Reference in New Issue
Block a user