mirror of
https://github.com/troglobit/finit.git
synced 2026-11-03 13:28:27 +00:00
Merge branch 'master' into cond-generation
This commit is contained in:
commit
e94d2a8c08
26 files changed
+733
-483
No files matched your search
+3
-3
@@ -34,11 +34,11 @@ addons:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- wget https://github.com/troglobit/libuev/releases/download/v2.1.0/libuev-2.1.0.tar.xz
|
- wget https://github.com/troglobit/libuev/releases/download/v2.1.0/libuev-2.1.0.tar.xz
|
||||||
- wget https://github.com/troglobit/libite/releases/download/v1.9.2/libite-1.9.2.tar.xz
|
- wget https://github.com/troglobit/libite/releases/download/v2.0.1/libite-2.0.1.tar.xz
|
||||||
- tar xf libuev-2.1.0.tar.xz
|
- tar xf libuev-2.1.0.tar.xz
|
||||||
- tar xf libite-1.9.2.tar.xz
|
- tar xf libite-2.0.1.tar.xz
|
||||||
- (cd libuev-2.1.0 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libuev-2.1.0 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
- (cd libite-1.9.2 && ./configure --prefix=/tmp && make && make install-strip)
|
- (cd libite-2.0.1 && ./configure --prefix=/tmp && make && make install-strip)
|
||||||
|
|
||||||
# Custom build script for the time being, no "make test" yet
|
# Custom build script for the time being, no "make test" yet
|
||||||
script:
|
script:
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ AC_TYPE_UINT32_T
|
|||||||
|
|
||||||
# Check for required libraries
|
# Check for required libraries
|
||||||
PKG_CHECK_MODULES([uev], [libuev >= 2.1.0])
|
PKG_CHECK_MODULES([uev], [libuev >= 2.1.0])
|
||||||
PKG_CHECK_MODULES([lite], [libite >= 1.9.2])
|
PKG_CHECK_MODULES([lite], [libite >= 2.0.1])
|
||||||
|
|
||||||
# Check for configured Finit features
|
# Check for configured Finit features
|
||||||
AC_ARG_ENABLE(emergency_shell,
|
AC_ARG_ENABLE(emergency_shell,
|
||||||
|
|||||||
+3
-3
@@ -21,9 +21,9 @@ can also be used.
|
|||||||
General
|
General
|
||||||
-------
|
-------
|
||||||
|
|
||||||
* Remove shm, let `initctl` call `api.c` for each `svc_t` instead of
|
* Add support for `rescue` on the kernel command line, start rescue mode
|
||||||
opening up the inner parts of PID 1 to other processes. Also, this
|
if enabled with `configure` script. Could mean skip `/etc/finit.conf`
|
||||||
would prevent issues like #81 from happening.
|
et al and jump straight to a single getty login on console.
|
||||||
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
* Add support for timed shutdown in Finit, including cancelled shutdown.
|
||||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||||
API restart to SIGHUP callback for the same functionality in Finit.
|
API restart to SIGHUP callback for the same functionality in Finit.
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ optional plugins to enable. It depends on two external libraries:
|
|||||||
|
|
||||||
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
||||||
|
|
||||||
|
The configure script checks for all dependencies, including the correct
|
||||||
|
version of the above mentioned libraries. Currently requried versions:
|
||||||
|
|
||||||
|
- libite v2.0.1
|
||||||
|
- libuEv v2.1.0
|
||||||
|
|
||||||
|
|
||||||
Configure
|
Configure
|
||||||
---------
|
---------
|
||||||
|
|||||||
+3
-4
@@ -92,17 +92,16 @@ static void pidfile_callback(void *arg, int fd, int events)
|
|||||||
*
|
*
|
||||||
* We must wait for the service to create/touch its pidfile.
|
* We must wait for the service to create/touch its pidfile.
|
||||||
*/
|
*/
|
||||||
static void pidfile_reconf(void *_null)
|
static void pidfile_reconf(void *arg)
|
||||||
{
|
{
|
||||||
static char cond[MAX_COND_LEN];
|
static char cond[MAX_COND_LEN];
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
(void)(_null);
|
|
||||||
int restart = 0;
|
int restart = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
restart = 0;
|
restart = 0;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
mkcond(cond, sizeof(cond), svc->cmd);
|
mkcond(cond, sizeof(cond), svc->cmd);
|
||||||
if (svc->state == SVC_RUNNING_STATE &&
|
if (svc->state == SVC_RUNNING_STATE &&
|
||||||
!svc_is_changed(svc) &&
|
!svc_is_changed(svc) &&
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ finit_LDADD += -ldl
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
initctl_SOURCES = initctl.c client.c client.h \
|
initctl_SOURCES = initctl.c client.c client.h \
|
||||||
serv.c serv.h svc.c svc.h \
|
serv.c serv.h svc.h \
|
||||||
cond.c cond.h util.c util.h
|
cond.c cond.h util.c util.h
|
||||||
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||||
initctl_CFLAGS += $(lite_CFLAGS)
|
initctl_CFLAGS += $(lite_CFLAGS)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
uev_t api_watcher;
|
static uev_t api_watcher;
|
||||||
|
|
||||||
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
static int call(int (*action)(svc_t *), char *buf, size_t len)
|
||||||
{
|
{
|
||||||
@@ -87,15 +88,42 @@ static int do_start (char *buf, size_t len) { return call(service_start, buf,
|
|||||||
static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); }
|
static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); }
|
||||||
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); }
|
||||||
|
|
||||||
#ifdef INETD_ENABLED
|
static char query_buf[368];
|
||||||
static int do_query_inetd(char *buf, size_t len)
|
static int missing(char *job, int id)
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
char idstr[10] = "";
|
||||||
|
|
||||||
|
if (!job)
|
||||||
|
job = "";
|
||||||
|
if (id > 1)
|
||||||
|
snprintf(idstr, sizeof(idstr), ":%d", id);
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%s%s ", job, idstr);
|
||||||
|
strlcat(query_buf, buf, sizeof(query_buf));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_query(struct init_request *rq, size_t len)
|
||||||
|
{
|
||||||
|
memset(query_buf, 0, sizeof(query_buf));
|
||||||
|
if (svc_parse_jobstr(rq->data, strlen(rq->data) + 1, NULL, missing)) {
|
||||||
|
memcpy(rq->data, query_buf, sizeof(rq->data));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static svc_t *do_find(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int id = 1;
|
int id = 1;
|
||||||
char *ptr, *input = sanitize(buf, len);
|
char *ptr, *input;
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
|
input = sanitize(buf, len);
|
||||||
if (!input)
|
if (!input)
|
||||||
return -1;
|
return NULL;
|
||||||
|
|
||||||
ptr = strchr(input, ':');
|
ptr = strchr(input, ':');
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
@@ -103,11 +131,20 @@ static int do_query_inetd(char *buf, size_t len)
|
|||||||
id = atonum(ptr);
|
id = atonum(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
svc = svc_find_by_jobid(atonum(input), id);
|
if (isdigit(input[0]))
|
||||||
if (!svc || !svc_is_inetd(svc)) {
|
return svc_find_by_jobid(atonum(input), id);
|
||||||
_e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", input);
|
|
||||||
|
return svc_find_by_nameid(input, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef INETD_ENABLED
|
||||||
|
static int do_query_inetd(char *buf, size_t len)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
svc = do_find(buf, len);
|
||||||
|
if (!svc || !svc_is_inetd(svc))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
return inetd_filter_str(&svc->inetd, buf, len);
|
return inetd_filter_str(&svc->inetd, buf, len);
|
||||||
}
|
}
|
||||||
@@ -164,6 +201,22 @@ static int do_handle_emit(char *buf, size_t len)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void send_svc(int sd, svc_t *svc)
|
||||||
|
{
|
||||||
|
svc_t empty;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!svc) {
|
||||||
|
empty.pid = -1;
|
||||||
|
svc = ∅
|
||||||
|
}
|
||||||
|
|
||||||
|
len = write(sd, svc, sizeof(*svc));
|
||||||
|
if (len != sizeof(*svc))
|
||||||
|
_d("Failed sending svc_t to client");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In contrast to the SysV compat handling in plugins/initctl.c, when
|
* In contrast to the SysV compat handling in plugins/initctl.c, when
|
||||||
* `initctl runlevel 0` is issued we default to POWERDOWN the system
|
* `initctl runlevel 0` is issued we default to POWERDOWN the system
|
||||||
@@ -172,6 +225,8 @@ static int do_handle_emit(char *buf, size_t len)
|
|||||||
static void api_cb(uev_t *w, void *arg, int events)
|
static void api_cb(uev_t *w, void *arg, int events)
|
||||||
{
|
{
|
||||||
int sd, lvl;
|
int sd, lvl;
|
||||||
|
svc_t *svc;
|
||||||
|
static svc_t *iter = NULL;
|
||||||
struct init_request rq;
|
struct init_request rq;
|
||||||
|
|
||||||
sd = accept(w->fd, NULL, NULL);
|
sd = accept(w->fd, NULL, NULL);
|
||||||
@@ -290,6 +345,27 @@ static void api_cb(uev_t *w, void *arg, int events)
|
|||||||
wdogpid = rq.runlevel;
|
wdogpid = rq.runlevel;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_SVC_ITER:
|
||||||
|
_d("svc iter, first: %d", rq.runlevel);
|
||||||
|
/*
|
||||||
|
* XXX: This severly limits the number of
|
||||||
|
* simultaneous client connections, but will
|
||||||
|
* have to do for now.
|
||||||
|
*/
|
||||||
|
svc = svc_iterator(&iter, rq.runlevel);
|
||||||
|
send_svc(sd, svc);
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
case INIT_CMD_SVC_QUERY:
|
||||||
|
_d("svc query: %s", rq.data);
|
||||||
|
result = do_query(&rq, len);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INIT_CMD_SVC_FIND:
|
||||||
|
_d("svc find: %s", rq.data);
|
||||||
|
send_svc(sd, do_find(rq.data, sizeof(rq.data)));
|
||||||
|
goto leave;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_d("Unsupported cmd: %d", rq.cmd);
|
_d("Unsupported cmd: %d", rq.cmd);
|
||||||
break;
|
break;
|
||||||
@@ -326,6 +402,7 @@ int api_init(uev_ctx_t *ctx)
|
|||||||
.sun_path = INIT_SOCKET,
|
.sun_path = INIT_SOCKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_d("Setting up external API socket ...");
|
||||||
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
if (-1 == sd) {
|
if (-1 == sd) {
|
||||||
_pe("Failed starting external API socket");
|
_pe("Failed starting external API socket");
|
||||||
|
|||||||
@@ -89,6 +89,74 @@ exit:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svc_t *client_svc_iterator(int first)
|
||||||
|
{
|
||||||
|
int sd = -1;
|
||||||
|
struct init_request rq = {
|
||||||
|
.magic = INIT_MAGIC,
|
||||||
|
.cmd = INIT_CMD_SVC_ITER,
|
||||||
|
};
|
||||||
|
static svc_t svc;
|
||||||
|
|
||||||
|
sd = client_connect();
|
||||||
|
if (sd == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
rq.runlevel = 1;
|
||||||
|
else
|
||||||
|
rq.runlevel = 0;
|
||||||
|
|
||||||
|
if (write(sd, &rq, sizeof(rq)) != sizeof(rq))
|
||||||
|
goto error;
|
||||||
|
if (read(sd, &svc, sizeof(svc)) != sizeof(svc))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
client_disconnect();
|
||||||
|
if (svc.pid < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &svc;
|
||||||
|
error:
|
||||||
|
perror("Failed communicating with finit");
|
||||||
|
client_disconnect();
|
||||||
|
sd = -1;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_t *client_svc_find(char *arg)
|
||||||
|
{
|
||||||
|
int sd = -1;
|
||||||
|
struct init_request rq = {
|
||||||
|
.magic = INIT_MAGIC,
|
||||||
|
.cmd = INIT_CMD_SVC_FIND,
|
||||||
|
};
|
||||||
|
static svc_t svc;
|
||||||
|
|
||||||
|
sd = client_connect();
|
||||||
|
if (sd == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||||
|
if (write(sd, &rq, sizeof(rq)) != sizeof(rq))
|
||||||
|
goto error;
|
||||||
|
if (read(sd, &svc, sizeof(svc)) != sizeof(svc))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
client_disconnect();
|
||||||
|
if (svc.pid < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &svc;
|
||||||
|
error:
|
||||||
|
client_disconnect();
|
||||||
|
perror("Failed communicating with finit");
|
||||||
|
sd = -1;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
+6
-3
@@ -25,15 +25,18 @@
|
|||||||
#define FINIT_CLIENT_H_
|
#define FINIT_CLIENT_H_
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
|
#include "svc.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
int (*cb)(char *arg);
|
int (*cb)(char *arg);
|
||||||
} command_t;
|
} command_t;
|
||||||
|
|
||||||
int client_connect (void);
|
int client_connect (void);
|
||||||
int client_disconnect (void);
|
int client_disconnect (void);
|
||||||
|
|
||||||
int client_send (struct init_request *rq, ssize_t len);
|
int client_send (struct init_request *rq, ssize_t len);
|
||||||
|
svc_t *client_svc_iterator (int first);
|
||||||
|
svc_t *client_svc_find (char *arg);
|
||||||
|
|
||||||
#endif /* FINIT_CLIENT_H_ */
|
#endif /* FINIT_CLIENT_H_ */
|
||||||
+2
-2
@@ -122,10 +122,10 @@ static int svc_has_cond(svc_t *svc)
|
|||||||
|
|
||||||
static void cond_update(const char *name)
|
static void cond_update(const char *name)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
_d("%s", name);
|
_d("%s", name);
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
if (!svc_has_cond(svc) || !cond_affects(name, svc->cond))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
+233
-38
@@ -25,8 +25,10 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
@@ -35,12 +37,22 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#define BOOTSTRAP (runlevel == 0)
|
||||||
#define MATCH_CMD(l, c, x) \
|
#define MATCH_CMD(l, c, x) \
|
||||||
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
|
||||||
|
|
||||||
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
struct rlimit global_rlimit[RLIMIT_NLIMITS];
|
||||||
static int parse_conf(char *file);
|
|
||||||
|
|
||||||
|
struct conf_change {
|
||||||
|
TAILQ_ENTRY(conf_change) link;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uev_t w1, w2, w3;
|
||||||
|
static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_change_list);
|
||||||
|
|
||||||
|
static int parse_conf(char *file);
|
||||||
|
static void drop_changes(void);
|
||||||
|
|
||||||
void conf_parse_cmdline(void)
|
void conf_parse_cmdline(void)
|
||||||
{
|
{
|
||||||
@@ -242,13 +254,13 @@ static void parse_static(char *line)
|
|||||||
char *x;
|
char *x;
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
|
|
||||||
if (MATCH_CMD(line, "host ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "host ", x)) {
|
||||||
if (hostname) free(hostname);
|
if (hostname) free(hostname);
|
||||||
hostname = strdup(strip_line(x));
|
hostname = strdup(strip_line(x));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "mknod ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "mknod ", x)) {
|
||||||
char *dev = strip_line(x);
|
char *dev = strip_line(x);
|
||||||
|
|
||||||
strcpy(cmd, "mknod ");
|
strcpy(cmd, "mknod ");
|
||||||
@@ -258,13 +270,13 @@ static void parse_static(char *line)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "network ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "network ", x)) {
|
||||||
if (network) free(network);
|
if (network) free(network);
|
||||||
network = strdup(strip_line(x));
|
network = strdup(strip_line(x));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MATCH_CMD(line, "runparts ", x)) {
|
if (BOOTSTRAP && MATCH_CMD(line, "runparts ", x)) {
|
||||||
if (runparts) free(runparts);
|
if (runparts) free(runparts);
|
||||||
runparts = strdup(strip_line(x));
|
runparts = strdup(strip_line(x));
|
||||||
return;
|
return;
|
||||||
@@ -289,10 +301,12 @@ static void parse_static(char *line)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The desired runlevel to start when leaving bootstrap (S).
|
/*
|
||||||
|
* The desired runlevel to start when leaving bootstrap (S).
|
||||||
* Finit supports 1-9, but most systems only use 1-6, where
|
* Finit supports 1-9, but most systems only use 1-6, where
|
||||||
* 6 is reserved for reboot */
|
* 6 is reserved for reboot and 0 for halt/poweroff.
|
||||||
if (MATCH_CMD(line, "runlevel ", x)) {
|
*/
|
||||||
|
if (BOOTSTRAP && MATCH_CMD(line, "runlevel ", x)) {
|
||||||
char *token = strip_line(x);
|
char *token = strip_line(x);
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
|
|
||||||
@@ -305,7 +319,7 @@ static void parse_static(char *line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_dynamic(char *line, struct rlimit rlimit[], struct timeval *mtime)
|
static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
char *x;
|
char *x;
|
||||||
char cmd[CMD_SIZE];
|
char cmd[CMD_SIZE];
|
||||||
@@ -331,26 +345,26 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], struct timeval *mt
|
|||||||
|
|
||||||
/* Monitored daemon, will be respawned on exit */
|
/* Monitored daemon, will be respawned on exit */
|
||||||
if (MATCH_CMD(line, "service ", x)) {
|
if (MATCH_CMD(line, "service ", x)) {
|
||||||
service_register(SVC_TYPE_SERVICE, x, rlimit, mtime);
|
service_register(SVC_TYPE_SERVICE, x, rlimit, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One-shot task, will not be respawned */
|
/* One-shot task, will not be respawned */
|
||||||
if (MATCH_CMD(line, "task ", x)) {
|
if (MATCH_CMD(line, "task ", x)) {
|
||||||
service_register(SVC_TYPE_TASK, x, rlimit, mtime);
|
service_register(SVC_TYPE_TASK, x, rlimit, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like task but waits for completion, useful w/ [S] */
|
/* Like task but waits for completion, useful w/ [S] */
|
||||||
if (MATCH_CMD(line, "run ", x)) {
|
if (MATCH_CMD(line, "run ", x)) {
|
||||||
service_register(SVC_TYPE_RUN, x, rlimit, mtime);
|
service_register(SVC_TYPE_RUN, x, rlimit, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Classic inetd service */
|
/* Classic inetd service */
|
||||||
if (MATCH_CMD(line, "inetd ", x)) {
|
if (MATCH_CMD(line, "inetd ", x)) {
|
||||||
#ifdef INETD_ENABLED
|
#ifdef INETD_ENABLED
|
||||||
service_register(SVC_TYPE_INETD, x, rlimit, mtime);
|
service_register(SVC_TYPE_INETD, x, rlimit, file);
|
||||||
#else
|
#else
|
||||||
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
||||||
#endif
|
#endif
|
||||||
@@ -365,7 +379,7 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], struct timeval *mt
|
|||||||
|
|
||||||
/* Regular or serial TTYs to run getty */
|
/* Regular or serial TTYs to run getty */
|
||||||
if (MATCH_CMD(line, "tty ", x)) {
|
if (MATCH_CMD(line, "tty ", x)) {
|
||||||
tty_register(strip_line(x), rlimit, mtime);
|
tty_register(strip_line(x), rlimit, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,7 +395,7 @@ static void tabstospaces(char *line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_conf_dynamic(char *file, struct timeval *mtime)
|
static int parse_conf_dynamic(char *file)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct rlimit rlimit[RLIMIT_NLIMITS];
|
struct rlimit rlimit[RLIMIT_NLIMITS];
|
||||||
@@ -395,7 +409,7 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
|
|||||||
/* Prepare default limits for each service */
|
/* Prepare default limits for each service */
|
||||||
memcpy(rlimit, global_rlimit, sizeof(rlimit));
|
memcpy(rlimit, global_rlimit, sizeof(rlimit));
|
||||||
|
|
||||||
_d("Parsing %s", file);
|
_d("Parsing %s <<<<<<", file);
|
||||||
while (!feof(fp)) {
|
while (!feof(fp)) {
|
||||||
char line[LINE_SIZE] = "";
|
char line[LINE_SIZE] = "";
|
||||||
|
|
||||||
@@ -406,7 +420,7 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
|
|||||||
tabstospaces(line);
|
tabstospaces(line);
|
||||||
_d("%s", line);
|
_d("%s", line);
|
||||||
|
|
||||||
parse_dynamic(line, rlimit, mtime);
|
parse_dynamic(line, rlimit, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -414,7 +428,6 @@ static int parse_conf_dynamic(char *file, struct timeval *mtime)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads /etc/finit.conf, once at boot */
|
|
||||||
static int parse_conf(char *file)
|
static int parse_conf(char *file)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@@ -456,21 +469,26 @@ static int parse_conf(char *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reload all *.conf in /etc/finit.d/ */
|
/*
|
||||||
int conf_reload_dynamic(void)
|
* Reload /etc/finit.conf and all *.conf in /etc/finit.d/
|
||||||
|
*/
|
||||||
|
int conf_reload(void)
|
||||||
{
|
{
|
||||||
int i, num;
|
int i, num;
|
||||||
char *dir = rcsd;
|
|
||||||
struct dirent **e;
|
struct dirent **e;
|
||||||
|
|
||||||
/* Mark and sweep */
|
/* Mark and sweep */
|
||||||
svc_mark_dynamic();
|
svc_mark_dynamic();
|
||||||
tty_mark();
|
tty_mark();
|
||||||
|
|
||||||
num = scandir(dir, &e, NULL, alphasort);
|
/* First, read /etc/finit.conf */
|
||||||
|
parse_conf(FINIT_CONF);
|
||||||
|
|
||||||
|
/* Next, read all *.conf in /etc/finit.d/ */
|
||||||
|
num = scandir(rcsd, &e, NULL, alphasort);
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
_d("Skipping %s, no files found ...", dir);
|
_d("Skipping %s, no files found ...", rcsd);
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update global limits in case operator used prlimit(1) on us */
|
/* Update global limits in case operator used prlimit(1) on us */
|
||||||
@@ -482,13 +500,11 @@ int conf_reload_dynamic(void)
|
|||||||
char path[LINE_SIZE];
|
char path[LINE_SIZE];
|
||||||
size_t len;
|
size_t len;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct timeval mtime;
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
snprintf(path, sizeof(path), "%s/%s", rcsd, name);
|
||||||
|
|
||||||
/* Check that it's an actual file ... beyond any symlinks */
|
/* Check that it's an actual file ... beyond any symlinks */
|
||||||
if (lstat(path, &st)) {
|
if (lstat(path, &st)) {
|
||||||
lost:
|
|
||||||
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
_d("Skipping %s, cannot access: %s", path, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -505,10 +521,6 @@ int conf_reload_dynamic(void)
|
|||||||
|
|
||||||
rp = realpath(path, NULL);
|
rp = realpath(path, NULL);
|
||||||
if (!rp) {
|
if (!rp) {
|
||||||
/*
|
|
||||||
* XXX: Prune from rcsd?
|
|
||||||
* XXX: Possibly temporary service from last boot
|
|
||||||
*/
|
|
||||||
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
|
logit(LOG_WARNING, "Skipping %s, dangling symlink: %s", path, strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -523,27 +535,210 @@ int conf_reload_dynamic(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stat(path, &st))
|
parse_conf_dynamic(path);
|
||||||
goto lost; /* Weird, lost file between here and lstat() */
|
|
||||||
|
|
||||||
TIMESPEC_TO_TIMEVAL(&mtime, &st.st_mtim);
|
|
||||||
parse_conf_dynamic(path, &mtime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (num--)
|
while (num--)
|
||||||
free(e[num]);
|
free(e[num]);
|
||||||
free(e);
|
free(e);
|
||||||
|
|
||||||
|
/* Drop record of all .conf changes */
|
||||||
|
drop_changes();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set host name, from %DEFHOST, *.conf or /etc/hostname. The
|
||||||
|
* latter wins, if neither exists we default to "noname"
|
||||||
|
*/
|
||||||
set_hostname(&hostname);
|
set_hostname(&hostname);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int conf_parse_config(void)
|
static struct conf_change *conf_find(char *file)
|
||||||
|
{
|
||||||
|
struct conf_change *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &conf_change_list, link, tmp) {
|
||||||
|
if (string_compare(node->name, file))
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drop_change(struct conf_change *node)
|
||||||
|
{
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&conf_change_list, node, link);
|
||||||
|
free(node->name);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void drop_changes(void)
|
||||||
|
{
|
||||||
|
struct conf_change *node, *tmp;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(node, &conf_change_list, link, tmp)
|
||||||
|
drop_change(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_change(char *name, uint32_t mask)
|
||||||
|
{
|
||||||
|
struct conf_change *node;
|
||||||
|
|
||||||
|
node = conf_find(name);
|
||||||
|
if (mask & (IN_DELETE | IN_MOVED_FROM)) {
|
||||||
|
drop_change(node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
_d("Event already registered for %s ...", name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = malloc(sizeof(*node));
|
||||||
|
if (!node)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
node->name = strdup(name);
|
||||||
|
if (!node->name) {
|
||||||
|
free(node);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INSERT_HEAD(&conf_change_list, node,link);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int conf_changed(char *file)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (file && (ptr = strrchr(file, '/')))
|
||||||
|
file = ++ptr;
|
||||||
|
|
||||||
|
if (conf_find(file))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conf_cb(uev_t *w, void *arg, int events)
|
||||||
|
{
|
||||||
|
static char ev_buf[8 *(sizeof(struct inotify_event) + NAME_MAX + 1) + 1];
|
||||||
|
struct inotify_event *ev;
|
||||||
|
ssize_t sz, len;
|
||||||
|
|
||||||
|
sz = read(w->fd, ev_buf, sizeof(ev_buf) - 1);
|
||||||
|
if (sz <= 0) {
|
||||||
|
_pe("invalid inotify event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ev_buf[sz] = 0;
|
||||||
|
ev = (struct inotify_event *)ev_buf;
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
do_change(arg, ev->mask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ev = (void *)ev_buf; sz > (ssize_t)sizeof(*ev);
|
||||||
|
len = sizeof(*ev) + ev->len, ev = (void *)ev + len, sz -= len) {
|
||||||
|
if (do_change(ev->name, ev->mask)) {
|
||||||
|
_pe("conf_monitor: Out of memory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_watcher(uev_ctx_t *ctx, uev_t *w, char *path, uint32_t opt)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
uint32_t mask = IN_CREATE | IN_DELETE | IN_MODIFY | IN_ATTRIB | IN_MOVE;
|
||||||
|
char *arg = NULL;
|
||||||
|
int fd, wd;
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (stat(path, &st)) {
|
||||||
|
_d("No such file or directory, skipping %s", path);
|
||||||
|
w->fd = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
arg = strrchr(path, '/');
|
||||||
|
if (!arg)
|
||||||
|
arg = path;
|
||||||
|
else
|
||||||
|
arg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w->fd >= 0)
|
||||||
|
close(w->fd);
|
||||||
|
|
||||||
|
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
_pe("Failed creating inotify descriptor");
|
||||||
|
w->fd = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only forward error, don't report error,
|
||||||
|
* user may not have @path and that's OK
|
||||||
|
*/
|
||||||
|
wd = inotify_add_watch(fd, path, mask | opt);
|
||||||
|
if (wd < 0) {
|
||||||
|
w->fd = -1;
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uev_io_init(ctx, w, conf_cb, arg, fd, UEV_READ)) {
|
||||||
|
_pe("Failed setting up I/O callback for %s watcher", path);
|
||||||
|
w->fd = -1;
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up inotify watcher and load all *.conf in /etc/finit.d/
|
||||||
|
*/
|
||||||
|
int conf_monitor(uev_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If only one watcher fails, that's OK. A user may have only
|
||||||
|
* one of /etc/finit.conf or /etc/finit.d in use, and may also
|
||||||
|
* have or not have symlinks in place. We need to monitor for
|
||||||
|
* changes to either symlink or target.
|
||||||
|
*/
|
||||||
|
rc += add_watcher(ctx, &w1, FINIT_RCSD, 0);
|
||||||
|
rc += add_watcher(ctx, &w2, FINIT_RCSD "/available", IN_DONT_FOLLOW);
|
||||||
|
rc += add_watcher(ctx, &w3, FINIT_CONF, 0);
|
||||||
|
|
||||||
|
return rc + conf_reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare .conf parser and load all .conf files
|
||||||
|
*/
|
||||||
|
int conf_init(void)
|
||||||
{
|
{
|
||||||
hostname = strdup(DEFHOST);
|
hostname = strdup(DEFHOST);
|
||||||
|
w1.fd = w2.fd = w3.fd = -1;
|
||||||
|
|
||||||
return parse_conf(FINIT_CONF) || conf_reload_dynamic();
|
return conf_monitor(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+5
-2
@@ -31,11 +31,14 @@ extern struct rlimit global_rlimit[];
|
|||||||
int str2rlim(char *str);
|
int str2rlim(char *str);
|
||||||
char *rlim2str(int rlim);
|
char *rlim2str(int rlim);
|
||||||
|
|
||||||
|
int conf_init (void);
|
||||||
|
void conf_reload (void);
|
||||||
|
int conf_changed (char *file);
|
||||||
|
int conf_monitor (uev_ctx_t *ctx);
|
||||||
|
|
||||||
void conf_parse_cmdline (void);
|
void conf_parse_cmdline (void);
|
||||||
int conf_parse_runlevels (char *runlevels);
|
int conf_parse_runlevels (char *runlevels);
|
||||||
void conf_parse_cond (svc_t *svc, char *cond);
|
void conf_parse_cond (svc_t *svc, char *cond);
|
||||||
int conf_parse_config (void);
|
|
||||||
void conf_reload_dynamic (void);
|
|
||||||
|
|
||||||
#endif /* FINIT_CONF_H_ */
|
#endif /* FINIT_CONF_H_ */
|
||||||
|
|
||||||
|
|||||||
+24
-22
@@ -254,12 +254,25 @@ static void emergency_shell(void)
|
|||||||
*/
|
*/
|
||||||
static void finalize(void)
|
static void finalize(void)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Network stuff
|
||||||
|
*/
|
||||||
|
_d("Setting up networking ...");
|
||||||
|
networking();
|
||||||
|
umask(022);
|
||||||
|
|
||||||
|
/* Hooks that rely on loopback, or basic networking being up. */
|
||||||
|
_d("Calling all network up hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_NETWORK_UP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all tasks/services in the configured runlevel
|
* Start all tasks/services in the configured runlevel
|
||||||
*/
|
*/
|
||||||
|
_d("Change to default runlevel, start all services ...");
|
||||||
service_runlevel(cfglevel);
|
service_runlevel(cfglevel);
|
||||||
|
|
||||||
/* Clean up bootstrap-only tasks/services that never started */
|
/* Clean up bootstrap-only tasks/services that never started */
|
||||||
|
_d("Clean up all bootstrap-only tasks/services ...");
|
||||||
svc_prune_bootstrap();
|
svc_prune_bootstrap();
|
||||||
|
|
||||||
/* All services/tasks/inetd/etc. in configure runlevel have started */
|
/* All services/tasks/inetd/etc. in configure runlevel have started */
|
||||||
@@ -283,13 +296,16 @@ static void finalize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Hooks that should run at the very end */
|
/* Hooks that should run at the very end */
|
||||||
|
_d("Calling all system up hooks ...");
|
||||||
plugin_run_hooks(HOOK_SYSTEM_UP);
|
plugin_run_hooks(HOOK_SYSTEM_UP);
|
||||||
service_step_all(SVC_TYPE_ANY);
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
/* Enable silent mode before starting TTYs */
|
/* Enable silent mode before starting TTYs */
|
||||||
|
_d("Going silent ...");
|
||||||
log_silent();
|
log_silent();
|
||||||
|
|
||||||
/* Delayed start of TTYs at bootstrap */
|
/* Delayed start of TTYs at bootstrap */
|
||||||
|
_d("Launching all getty services ...");
|
||||||
tty_runlevel();
|
tty_runlevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,9 +395,8 @@ int main(int argc, char* argv[])
|
|||||||
makedir("/dev/pts", 0755);
|
makedir("/dev/pts", 0755);
|
||||||
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620");
|
||||||
|
|
||||||
|
/* Some systems rely on /dev/shm being there, for `mount -a` below */
|
||||||
makedir("/dev/shm", 0755);
|
makedir("/dev/shm", 0755);
|
||||||
if (!fismnt("/dev/shm"))
|
|
||||||
mount("shm", "/dev/shm", "tmpfs", 0, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New tmpfs based /run for volatile runtime data
|
* New tmpfs based /run for volatile runtime data
|
||||||
@@ -436,19 +451,15 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse /etc/finit.conf and all *.conf in /etc/finit.d/ to
|
* Initialize .conf system and load static /etc/finit.conf
|
||||||
* figure out how to bootstrap the system.
|
|
||||||
*/
|
*/
|
||||||
conf_parse_config();
|
conf_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start built-in watchdog as soon as possible, if enabled
|
* Start built-in watchdog as soon as possible, if enabled
|
||||||
*/
|
*/
|
||||||
wdogpid = watchdog(argv[0]);
|
wdogpid = watchdog(argv[0]);
|
||||||
|
|
||||||
/* Set hostname as soon as possible, for syslog et al. */
|
|
||||||
set_hostname(&hostname);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mount filesystems
|
* Mount filesystems
|
||||||
*/
|
*/
|
||||||
@@ -480,12 +491,10 @@ int main(int argc, char* argv[])
|
|||||||
cond_init();
|
cond_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reload all *.conf in /etc/finit.d, the mount command (above)
|
* Set up inotify watcher for /etc/finit.d and read all .conf
|
||||||
* may have brought in new files (overlayfs).
|
* files to figure out how to bootstrap the system.
|
||||||
*
|
|
||||||
* XXX: Can we detect remounted /etc to trigger this instead?
|
|
||||||
*/
|
*/
|
||||||
conf_reload_dynamic();
|
conf_monitor(&loop);
|
||||||
|
|
||||||
_d("Base FS up, calling hooks ...");
|
_d("Base FS up, calling hooks ...");
|
||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
@@ -497,15 +506,6 @@ int main(int argc, char* argv[])
|
|||||||
sm_init(&sm);
|
sm_init(&sm);
|
||||||
sm_step(&sm);
|
sm_step(&sm);
|
||||||
|
|
||||||
/*
|
|
||||||
* Network stuff
|
|
||||||
*/
|
|
||||||
networking();
|
|
||||||
umask(022);
|
|
||||||
|
|
||||||
/* Hooks that rely on loopback, or basic networking being up. */
|
|
||||||
plugin_run_hooks(HOOK_NETWORK_UP);
|
|
||||||
|
|
||||||
/* Start new initctl API responder */
|
/* Start new initctl API responder */
|
||||||
api_init(&loop);
|
api_init(&loop);
|
||||||
|
|
||||||
@@ -513,11 +513,13 @@ int main(int argc, char* argv[])
|
|||||||
* Wait for all SVC_TYPE_RUNTASK to have completed their work in
|
* Wait for all SVC_TYPE_RUNTASK to have completed their work in
|
||||||
* [S], or timeout, before calling finalize()
|
* [S], or timeout, before calling finalize()
|
||||||
*/
|
*/
|
||||||
|
_d("Starting bootstrap finalize timer ...");
|
||||||
uev_timer_init(&loop, &timer, service_bootstrap_cb, finalize, 1000, 1000);
|
uev_timer_init(&loop, &timer, service_bootstrap_cb, finalize, 1000, 1000);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter main loop to monior /dev/initctl and services
|
* Enter main loop to monior /dev/initctl and services
|
||||||
*/
|
*/
|
||||||
|
_d("Entering main loop ...");
|
||||||
return uev_run(&loop, 0);
|
return uev_run(&loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,9 @@
|
|||||||
#define INIT_CMD_EMIT 15
|
#define INIT_CMD_EMIT 15
|
||||||
#define INIT_CMD_GET_RUNLEVEL 16
|
#define INIT_CMD_GET_RUNLEVEL 16
|
||||||
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
#define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */
|
||||||
|
#define INIT_CMD_SVC_ITER 129
|
||||||
|
#define INIT_CMD_SVC_QUERY 130
|
||||||
|
#define INIT_CMD_SVC_FIND 131
|
||||||
#define INIT_CMD_NACK 254
|
#define INIT_CMD_NACK 254
|
||||||
#define INIT_CMD_ACK 255
|
#define INIT_CMD_ACK 255
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -225,10 +225,10 @@ static void socket_cb(uev_t *w, void *arg, int events)
|
|||||||
*/
|
*/
|
||||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
|
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
char pname[NI_MAXHOST];
|
char pname[NI_MAXHOST];
|
||||||
|
|
||||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
for (svc = svc_inetd_iterator(&iter, 1); svc; svc = svc_inetd_iterator(&iter, 0)) {
|
||||||
inetd_t *i = &svc->inetd;
|
inetd_t *i = &svc->inetd;
|
||||||
|
|
||||||
if (!i->builtin || i->type != SOCK_DGRAM)
|
if (!i->builtin || i->type != SOCK_DGRAM)
|
||||||
@@ -665,9 +665,9 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
|
|
||||||
svc_t *inetd_find_svc(char *path, char *service, char *proto)
|
svc_t *inetd_find_svc(char *path, char *service, char *proto)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
for (svc = svc_inetd_iterator(&iter, 1); svc; svc = svc_inetd_iterator(&iter, 0)) {
|
||||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
+24
-41
@@ -138,21 +138,6 @@ static int do_svc(int cmd, char *arg)
|
|||||||
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); }
|
||||||
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); }
|
||||||
|
|
||||||
static int missing(char *job, int id)
|
|
||||||
{
|
|
||||||
char idstr[10] = "";
|
|
||||||
|
|
||||||
if (!job)
|
|
||||||
job = "";
|
|
||||||
if (id > 1)
|
|
||||||
snprintf(idstr, sizeof(idstr), ":%d", id);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
fprintf(stderr, "No such service %s%s\n", job, idstr);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a wrapper for do_svc() that adds a simple sanity check of
|
* This is a wrapper for do_svc() that adds a simple sanity check of
|
||||||
* the service(s) provided as argument. If a service does not exist
|
* the service(s) provided as argument. If a service does not exist
|
||||||
@@ -160,8 +145,14 @@ static int missing(char *job, int id)
|
|||||||
*/
|
*/
|
||||||
static int do_startstop(int cmd, char *arg)
|
static int do_startstop(int cmd, char *arg)
|
||||||
{
|
{
|
||||||
/* Include \0 in len, needed by parser */
|
struct init_request rq = {
|
||||||
if (svc_parse_jobstr(arg, strlen(arg) + 1, NULL, missing)) {
|
.magic = INIT_MAGIC,
|
||||||
|
.cmd = INIT_CMD_SVC_QUERY
|
||||||
|
};
|
||||||
|
|
||||||
|
strlcpy(rq.data, arg, sizeof(rq.data));
|
||||||
|
if (client_send(&rq, sizeof(rq))) {
|
||||||
|
fprintf(stderr, "No such job(s) or service(s): %s\n\n", rq.data);
|
||||||
fprintf(stderr, "Usage: initctl %s <JOB|NAME>[:ID]\n",
|
fprintf(stderr, "Usage: initctl %s <JOB|NAME>[:ID]\n",
|
||||||
cmd == INIT_CMD_START_SVC ? "start" :
|
cmd == INIT_CMD_START_SVC ? "start" :
|
||||||
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
|
(cmd == INIT_CMD_STOP_SVC ? "stop" : "restart"));
|
||||||
@@ -257,7 +248,7 @@ static int do_cond_show(char *arg)
|
|||||||
|
|
||||||
printheader(NULL, "PID SERVICE STATUS CONDITION (+ ON, ~ FLUX, - OFF)", 0);
|
printheader(NULL, "PID SERVICE STATUS CONDITION (+ ON, ~ FLUX, - OFF)", 0);
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
if (!svc->cond[0])
|
if (!svc->cond[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -420,39 +411,29 @@ static int show_status(char *arg)
|
|||||||
runlevel = runlevel_get(NULL);
|
runlevel = runlevel_get(NULL);
|
||||||
|
|
||||||
if (arg && arg[0]) {
|
if (arg && arg[0]) {
|
||||||
int id = 1;
|
svc = client_svc_find(arg);
|
||||||
char *ptr, *next;
|
|
||||||
|
|
||||||
ptr = strchr(arg, ':');
|
|
||||||
if (ptr) {
|
|
||||||
*ptr++ = 0;
|
|
||||||
next = strchr(ptr, ' ');
|
|
||||||
if (next)
|
|
||||||
*next = 0;
|
|
||||||
id = atonum(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isdigit(arg[0]))
|
|
||||||
svc = svc_find_by_jobid(atonum(arg), id);
|
|
||||||
else
|
|
||||||
svc = svc_find_by_nameid(arg, id);
|
|
||||||
|
|
||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
printf("%s\n", svc_status(svc));
|
printf("Service : %s\n", svc->cmd);
|
||||||
return 0;
|
printf("Description : %s\n", svc->desc);
|
||||||
|
printf("PID : %d\n", svc->pid);
|
||||||
|
printf("Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
|
printf("Status : %s\n", svc_status(svc));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return do_log(svc->cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0);
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
char jobid[10], args[512] = "", *lvls;
|
char jobid[10], args[512] = "", *lvls;
|
||||||
|
|
||||||
if (svc_is_unique(svc))
|
// if (svc_is_unique(svc))
|
||||||
snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
// snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||||
else
|
// else
|
||||||
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id);
|
||||||
|
|
||||||
printf("%-5s %7s ", jobid, svc_status(svc));
|
printf("%-5s %7s ", jobid, svc_status(svc));
|
||||||
@@ -543,6 +524,7 @@ static int usage(int rc)
|
|||||||
" list List all .conf in /etc/finit.d/\n"
|
" list List all .conf in /etc/finit.d/\n"
|
||||||
" enable <CONF> Enable .conf in /etc/finit.d/available/\n"
|
" enable <CONF> Enable .conf in /etc/finit.d/available/\n"
|
||||||
" disable <CONF> Disable .conf in /etc/finit.d/[enabled/]\n"
|
" disable <CONF> Disable .conf in /etc/finit.d/[enabled/]\n"
|
||||||
|
" touch <CONF> Mark .conf in /etc/finit.d/ for reload\n"
|
||||||
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
" reload Reload *.conf in /etc/finit.d/ (activates changes)\n"
|
||||||
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
// " reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -585,6 +567,7 @@ int main(int argc, char *argv[])
|
|||||||
{ "list", serv_list },
|
{ "list", serv_list },
|
||||||
{ "enable", serv_enable },
|
{ "enable", serv_enable },
|
||||||
{ "disable", serv_disable },
|
{ "disable", serv_disable },
|
||||||
|
{ "touch", serv_touch },
|
||||||
{ "reload", do_reload },
|
{ "reload", do_reload },
|
||||||
|
|
||||||
{ "cond", do_cond },
|
{ "cond", do_cond },
|
||||||
|
|||||||
@@ -105,45 +105,43 @@ int log_is_debug(void)
|
|||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void early_logit(int prio, const char *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (!debug && prio > loglevel)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fp = fopen("/dev/kmsg", "w");
|
|
||||||
if (fp) {
|
|
||||||
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
|
||||||
vfprintf(fp, fmt, ap);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
} else {
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log to /dev/kmsg until syslogd has started, then openlog()
|
* Log to /dev/kmsg until syslogd has started, then openlog()
|
||||||
* and continue logging as a regular daemon.
|
* and continue logging as a regular daemon.
|
||||||
*/
|
*/
|
||||||
void logit(int prio, const char *fmt, ...)
|
void logit(int prio, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
FILE *fp;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (!up) {
|
|
||||||
if (!fexist("/dev/log")) {
|
|
||||||
early_logit(prio, fmt, ap);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_open();
|
if (up || fexist("/dev/log")) {
|
||||||
|
if (!up)
|
||||||
|
log_open();
|
||||||
|
vsyslog(prio, fmt, ap);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!debug && prio > loglevel)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
fp = fopen("/dev/kmsg", "w");
|
||||||
|
if (!fp) {
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "<%d>finit[1]:", LOG_DAEMON | prio);
|
||||||
|
vfprintf(fp, fmt, ap);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
va_end(ap);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
vsyslog(prio, fmt, ap);
|
|
||||||
done:
|
done:
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|||||||
+25
@@ -24,6 +24,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <fcntl.h> /* Definition of AT_* constants */
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
@@ -168,6 +169,30 @@ int serv_disable(char *arg)
|
|||||||
return remove(link) != 0;
|
return remove(link) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int serv_touch(char *arg)
|
||||||
|
{
|
||||||
|
char corr[40];
|
||||||
|
|
||||||
|
if (!strstr(arg, ".conf")) {
|
||||||
|
snprintf(corr, sizeof(corr), "%s.conf", arg);
|
||||||
|
arg = corr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushd(FINIT_RCSD);
|
||||||
|
if (!fexist(arg)) {
|
||||||
|
popd();
|
||||||
|
if (!strstr(arg, "finit.conf"))
|
||||||
|
errx(1, "Service %s is not enabled", arg);
|
||||||
|
arg = FINIT_CONF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* libite:touch() follows symlinks */
|
||||||
|
if (utimensat(AT_FDCWD, arg, NULL, AT_SYMLINK_NOFOLLOW))
|
||||||
|
err(1, "Failed marking %s for reload", arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
int serv_list (char *arg);
|
int serv_list (char *arg);
|
||||||
int serv_enable (char *arg);
|
int serv_enable (char *arg);
|
||||||
int serv_disable (char *arg);
|
int serv_disable (char *arg);
|
||||||
|
int serv_touch (char *arg);
|
||||||
|
|
||||||
#endif /* FINIT_SERV_H_ */
|
#endif /* FINIT_SERV_H_ */
|
||||||
|
|
||||||
|
|||||||
+13
-9
@@ -474,7 +474,7 @@ void service_runlevel(int newlevel)
|
|||||||
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
|
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
|
||||||
* @cfg: Configuration, complete command, with -- for description text
|
* @cfg: Configuration, complete command, with -- for description text
|
||||||
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
||||||
* @mtime: The modification time if service is loaded from /etc/finit.d
|
* @file: The file name service was loaded from
|
||||||
*
|
*
|
||||||
* This function is used to register commands to be run on different
|
* This function is used to register commands to be run on different
|
||||||
* system runlevels with optional username. The @type argument details
|
* system runlevels with optional username. The @type argument details
|
||||||
@@ -521,7 +521,7 @@ void service_runlevel(int newlevel)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||||
*/
|
*/
|
||||||
int service_register(int type, char *cfg, struct rlimit rlimit[], struct timeval *mtime)
|
int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int id = -1;
|
int id = -1;
|
||||||
@@ -727,9 +727,13 @@ recreate:
|
|||||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||||
|
|
||||||
/* New, recently modified or unchanged ... used on reload. */
|
/* New, recently modified or unchanged ... used on reload. */
|
||||||
svc_check_dirty(svc, mtime);
|
if (file && conf_changed(file))
|
||||||
free(line);
|
svc_mark_dirty(svc);
|
||||||
|
else
|
||||||
|
svc_mark_clean(svc);
|
||||||
|
|
||||||
|
/* Free duped line, from above */
|
||||||
|
free(line);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,11 +1027,12 @@ void service_step_all(int types)
|
|||||||
*/
|
*/
|
||||||
void service_runtask_clean(void)
|
void service_runtask_clean(void)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_is_runtask(svc))
|
if (!svc_is_runtask(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
svc->once = 0;
|
svc->once = 0;
|
||||||
if (svc->state == SVC_DONE_STATE)
|
if (svc->state == SVC_DONE_STATE)
|
||||||
svc_set_state(svc, SVC_HALTED_STATE);
|
svc_set_state(svc, SVC_HALTED_STATE);
|
||||||
@@ -1051,9 +1056,9 @@ void service_runtask_clean(void)
|
|||||||
*/
|
*/
|
||||||
int service_runtask_completed(int skip)
|
int service_runtask_completed(int skip)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc_is_runtask(svc))
|
if (!svc_is_runtask(svc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1094,7 +1099,6 @@ void service_bootstrap_cb(uev_t *w, void *arg, int events)
|
|||||||
finalize();
|
finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* indent-tabs-mode: t
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
|
|
||||||
void service_runlevel (int newlevel);
|
void service_runlevel (int newlevel);
|
||||||
int service_register (int type, char *line, struct rlimit rlimit[], struct timeval *mtime);
|
int service_register (int type, char *line, struct rlimit rlimit[], char *file);
|
||||||
void service_unregister (svc_t *svc);
|
void service_unregister (svc_t *svc);
|
||||||
|
|
||||||
void service_runtask_clean (void);
|
void service_runtask_clean (void);
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ void sm_step(sm_t *sm)
|
|||||||
restart:
|
restart:
|
||||||
old_state = sm->state;
|
old_state = sm->state;
|
||||||
|
|
||||||
_d("state: %s", sm_status(sm->state));
|
_d("state: %s, runlevel: %d, newlevel: %d, teardown: %d, reload: %d",
|
||||||
|
sm_status(sm->state), runlevel, sm->newlevel, sm->in_teardown, sm->reload);
|
||||||
|
|
||||||
switch (sm->state) {
|
switch (sm->state) {
|
||||||
case SM_BOOTSTRAP_STATE:
|
case SM_BOOTSTRAP_STATE:
|
||||||
@@ -143,7 +144,7 @@ restart:
|
|||||||
|
|
||||||
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
if (runlevel != 0 && runlevel != 6)
|
if (runlevel != 0 && runlevel != 6)
|
||||||
conf_reload_dynamic();
|
conf_reload();
|
||||||
|
|
||||||
/* Reset once flag of runtasks */
|
/* Reset once flag of runtasks */
|
||||||
service_runtask_clean();
|
service_runtask_clean();
|
||||||
@@ -198,7 +199,7 @@ restart:
|
|||||||
|
|
||||||
case SM_RELOAD_CHANGE_STATE:
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
/* First reload all *.conf in /etc/finit.d/ */
|
/* First reload all *.conf in /etc/finit.d/ */
|
||||||
conf_reload_dynamic();
|
conf_reload();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Then, mark all affected service conditions as in-flux and
|
* Then, mark all affected service conditions as in-flux and
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "svc.h"
|
#include "svc.h"
|
||||||
@@ -35,38 +36,7 @@
|
|||||||
|
|
||||||
/* Each svc_t needs a unique job# */
|
/* Each svc_t needs a unique job# */
|
||||||
static int jobcounter = 1;
|
static int jobcounter = 1;
|
||||||
static svc_t *workaround = NULL;
|
static TAILQ_HEAD(head, svc) svc_list = TAILQ_HEAD_INITIALIZER(svc_list);
|
||||||
|
|
||||||
static svc_t *__connect_shm(void)
|
|
||||||
{
|
|
||||||
svc_t *list;
|
|
||||||
|
|
||||||
list = finit_svc_connect();
|
|
||||||
if (!list) {
|
|
||||||
if (workaround)
|
|
||||||
return workaround;
|
|
||||||
|
|
||||||
/* Linux not built with CONFIG_SYSVIPC, or libc does not support shmat()/shmget() */
|
|
||||||
if (ENOSYS == errno)
|
|
||||||
warn("Kernel does support SYSV shmat() IPC, error %d", errno);
|
|
||||||
|
|
||||||
/* Try to prevent PID 1 from aborting, issue #81 */
|
|
||||||
if (getpid() == 1) {
|
|
||||||
warnx("Implementing PID 1 workaround, initctl tool will not work ...");
|
|
||||||
if (!workaround)
|
|
||||||
workaround = calloc(MAX_NUM_SVC, sizeof(svc_t));
|
|
||||||
|
|
||||||
list = workaround;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!list) {
|
|
||||||
warn("Failed connecting to shared memory, error %d", errno);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_new - Create a new service
|
* svc_new - Create a new service
|
||||||
@@ -79,11 +49,12 @@ static svc_t *__connect_shm(void)
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_new(char *cmd, int id, int type)
|
svc_t *svc_new(char *cmd, int id, int type)
|
||||||
{
|
{
|
||||||
int i, job = -1;
|
int job = -1;
|
||||||
svc_t *svc, *list = __connect_shm();
|
char *desc;
|
||||||
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
/* Find first job n:o if registering multiple instances */
|
/* Find first job n:o if registering multiple instances */
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!strcmp(svc->cmd, cmd)) {
|
if (!strcmp(svc->cmd, cmd)) {
|
||||||
job = svc->job;
|
job = svc->job;
|
||||||
break;
|
break;
|
||||||
@@ -92,32 +63,26 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
if (job == -1)
|
if (job == -1)
|
||||||
job = jobcounter++;
|
job = jobcounter++;
|
||||||
|
|
||||||
for (i = 0; i < MAX_NUM_SVC; i++) {
|
svc = calloc(1, sizeof(*svc));
|
||||||
svc_t *svc = &list[i];
|
if (!svc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (svc->type == SVC_TYPE_FREE) {
|
svc->type = type;
|
||||||
char *desc;
|
svc->job = job;
|
||||||
|
svc->id = id;
|
||||||
|
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
||||||
|
|
||||||
memset(svc, 0, sizeof(*svc));
|
/* Default description, if missing */
|
||||||
svc->type = type;
|
desc = rindex(cmd, '/');
|
||||||
svc->job = job;
|
if (desc)
|
||||||
svc->id = id;
|
desc++;
|
||||||
strlcpy(svc->cmd, cmd, sizeof(svc->cmd));
|
else
|
||||||
|
desc = cmd;
|
||||||
|
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||||
|
|
||||||
/* Default description, if missing */
|
TAILQ_INSERT_TAIL(&svc_list, svc, link);
|
||||||
desc = rindex(cmd, '/');
|
|
||||||
if (desc)
|
|
||||||
desc++;
|
|
||||||
else
|
|
||||||
desc = cmd;
|
|
||||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
|
||||||
|
|
||||||
return svc;
|
return svc;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = ENOMEM;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,50 +94,55 @@ svc_t *svc_new(char *cmd, int id, int type)
|
|||||||
*/
|
*/
|
||||||
int svc_del(svc_t *svc)
|
int svc_del(svc_t *svc)
|
||||||
{
|
{
|
||||||
svc->type = SVC_TYPE_FREE;
|
TAILQ_REMOVE(&svc_list, svc, link);
|
||||||
|
memset(svc, 0, sizeof(*svc));
|
||||||
|
free(svc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_iterator - Naive iterator over all registered services.
|
* svc_iterator - Naive iterator over all registered services.
|
||||||
* @first: Get first &svc_t object, or next until end.
|
* @iter: Iterator, must be a valid pointer
|
||||||
|
* @first: If set, get first &svc_t, otherwise get next
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* The first &svc_t when @first is set, otherwise the next &svc_t until
|
* An &svc_t pointer, or %NULL when no more entries can be found.
|
||||||
* the end when %NULL is returned.
|
|
||||||
*/
|
*/
|
||||||
svc_t *svc_iterator(int first)
|
svc_t *svc_iterator(svc_t **iter, int first)
|
||||||
{
|
|
||||||
static int i = 0;
|
|
||||||
svc_t *list = __connect_shm();
|
|
||||||
|
|
||||||
if (first)
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
while (i < MAX_NUM_SVC) {
|
|
||||||
svc_t *svc = &list[i++];
|
|
||||||
|
|
||||||
if (svc->type != SVC_TYPE_FREE)
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* svc_inetd_iterator - Naive iterator over all registered inetd services.
|
|
||||||
* @first: Get first &svc_t object, or next until end.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* The first inetd &svc_t when @first is set, otherwise the next
|
|
||||||
* inetd &svc_t until the end when %NULL is returned.
|
|
||||||
*/
|
|
||||||
svc_t *svc_inetd_iterator(int first)
|
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(first); svc; svc = svc_iterator(0)) {
|
if (!iter) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first)
|
||||||
|
svc = TAILQ_FIRST(&svc_list);
|
||||||
|
else
|
||||||
|
svc = *iter;
|
||||||
|
|
||||||
|
if (svc)
|
||||||
|
*iter = TAILQ_NEXT(svc, link);
|
||||||
|
|
||||||
|
return svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svc_inetd_iterator - Naive iterator over all registered inetd services.
|
||||||
|
* @iter: Iterator, must be a valid pointer
|
||||||
|
* @first: If set, get first &svc_t, otherwise get next
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The first inetd &svc_t when %NULL is given as argument, otherwise the
|
||||||
|
* next inetd &svc_t until the end when %NULL is returned.
|
||||||
|
*/
|
||||||
|
svc_t *svc_inetd_iterator(svc_t **iter, int first)
|
||||||
|
{
|
||||||
|
svc_t *svc;
|
||||||
|
|
||||||
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
if (svc_is_inetd(svc))
|
if (svc_is_inetd(svc))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -181,42 +151,22 @@ svc_t *svc_inetd_iterator(int first)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* svc_dynamic_iterator - Naive iterator over all registered dynamic services.
|
|
||||||
* @first: Get first &svc_t object, or next until end.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* The first dynamically loaded &svc_t when @first is set, otherwise the
|
|
||||||
* next dynamically loaded &svc_t until the end when %NULL is returned.
|
|
||||||
*/
|
|
||||||
svc_t *svc_dynamic_iterator(int first)
|
|
||||||
{
|
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
for (svc = svc_iterator(first); svc; svc = svc_iterator(0)) {
|
|
||||||
if (svc->mtime.tv_sec)
|
|
||||||
return svc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_named_iterator - Iterates over all instances of a service.
|
* svc_named_iterator - Iterates over all instances of a service.
|
||||||
* @first: Get first &svc_t object, or next until end.
|
* @iter: Iterator, must be a valid pointer
|
||||||
|
* @first: If set, get first &svc_t, otherwise get next
|
||||||
* @cmd: Service name to look for.
|
* @cmd: Service name to look for.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* The first matching &svc_t when @first is set, otherwise the next
|
* The first matching &svc_t when %NULL is given as argument, otherwise
|
||||||
* &svc_t instance with the same @cmd until the end when %NULL is
|
* the next &svc_t with the same @cmd name until the end when %NULL is
|
||||||
* returned.
|
* returned.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_named_iterator(int first, char *cmd)
|
svc_t *svc_named_iterator(svc_t **iter, int first, char *cmd)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(first); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
char *name = basename(svc->cmd);
|
char *name = basename(svc->cmd);
|
||||||
|
|
||||||
if (!strncmp(name, cmd, strlen(name)))
|
if (!strncmp(name, cmd, strlen(name)))
|
||||||
@@ -229,19 +179,20 @@ svc_t *svc_named_iterator(int first, char *cmd)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_job_iterator - Iterates over all instances of a service.
|
* svc_job_iterator - Iterates over all instances of a service.
|
||||||
* @first: Get first &svc_t object, or next until end.
|
* @iter: Iterator, must be a valid pointer
|
||||||
|
* @first: If set, get first &svc_t, otherwise get next
|
||||||
* @job: Job to look for.
|
* @job: Job to look for.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* The first matching &svc_t when @first is set, otherwise the next
|
* The first matching &svc_t when %NULL is given as argument, otherwise
|
||||||
* &svc_t instance with the same @job until the end when %NULL is
|
* the next &svc_t with the same @job ID until the end when %NULL is
|
||||||
* returned.
|
* returned.
|
||||||
*/
|
*/
|
||||||
svc_t *svc_job_iterator(int first, int job)
|
svc_t *svc_job_iterator(svc_t **iter, int first, int job)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
for (svc = svc_iterator(first); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||||
if (svc->job == job)
|
if (svc->job == job)
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -256,28 +207,12 @@ svc_t *svc_job_iterator(int first, int job)
|
|||||||
*/
|
*/
|
||||||
void svc_foreach(void (*cb)(svc_t *))
|
void svc_foreach(void (*cb)(svc_t *))
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
if (!cb)
|
if (!cb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0))
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0))
|
||||||
cb(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* svc_foreach_dynamic - Run a callback for each registered dynamic service
|
|
||||||
* @cb: Callback to run for each dynamic service
|
|
||||||
*/
|
|
||||||
void svc_foreach_dynamic(void (*cb)(svc_t *))
|
|
||||||
{
|
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
if (!cb)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (svc = svc_dynamic_iterator(1); svc; svc = svc_dynamic_iterator(0))
|
|
||||||
cb(svc);
|
cb(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,12 +224,12 @@ void svc_foreach_dynamic(void (*cb)(svc_t *))
|
|||||||
*/
|
*/
|
||||||
void svc_foreach_type(int types, void (*cb)(svc_t *))
|
void svc_foreach_type(int types, void (*cb)(svc_t *))
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
if (!cb)
|
if (!cb)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!(svc->type & types))
|
if (!(svc->type & types))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -312,9 +247,9 @@ void svc_foreach_type(int types, void (*cb)(svc_t *))
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_stop_completed(void)
|
svc_t *svc_stop_completed(void)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->state == SVC_STOPPING_STATE)
|
if (svc->state == SVC_STOPPING_STATE)
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -331,9 +266,9 @@ svc_t *svc_stop_completed(void)
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_find(char *cmd, int id)
|
svc_t *svc_find(char *cmd, int id)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
if (svc->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd)))
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -350,9 +285,9 @@ svc_t *svc_find(char *cmd, int id)
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_pid(pid_t pid)
|
svc_t *svc_find_by_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->pid == pid)
|
if (svc->pid == pid)
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -370,9 +305,9 @@ svc_t *svc_find_by_pid(pid_t pid)
|
|||||||
*/
|
*/
|
||||||
svc_t *svc_find_by_jobid(int job, int id)
|
svc_t *svc_find_by_jobid(int job, int id)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->job == job && svc->id == id)
|
if (svc->job == job && svc->id == id)
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
@@ -391,9 +326,9 @@ svc_t *svc_find_by_jobid(int job, int id)
|
|||||||
svc_t *svc_find_by_nameid(char *name, int id)
|
svc_t *svc_find_by_nameid(char *name, int id)
|
||||||
{
|
{
|
||||||
char *ptr;
|
char *ptr;
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
ptr = strrchr(svc->cmd, '/');
|
ptr = strrchr(svc->cmd, '/');
|
||||||
if (ptr)
|
if (ptr)
|
||||||
ptr++;
|
ptr++;
|
||||||
@@ -419,12 +354,10 @@ svc_t *svc_find_by_nameid(char *name, int id)
|
|||||||
*/
|
*/
|
||||||
void svc_mark_dynamic(void)
|
void svc_mark_dynamic(void)
|
||||||
{
|
{
|
||||||
svc_t *svc = svc_dynamic_iterator(1);
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
while (svc) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0))
|
||||||
*((int *)&svc->dirty) = -1;
|
*((int *)&svc->dirty) = -1;
|
||||||
svc = svc_dynamic_iterator(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svc_mark_dirty(svc_t *svc)
|
void svc_mark_dirty(svc_t *svc)
|
||||||
@@ -437,17 +370,6 @@ void svc_mark_clean(svc_t *svc)
|
|||||||
*((int *)&svc->dirty) = 0;
|
*((int *)&svc->dirty) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void svc_check_dirty(svc_t *svc, struct timeval *mtime)
|
|
||||||
{
|
|
||||||
if (mtime && timercmp(&svc->mtime, mtime, !=))
|
|
||||||
svc_mark_dirty(svc);
|
|
||||||
else
|
|
||||||
svc_mark_clean(svc);
|
|
||||||
|
|
||||||
svc->mtime.tv_sec = mtime ? mtime->tv_sec : 0;
|
|
||||||
svc->mtime.tv_usec = mtime ? mtime->tv_usec : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* svc_clean_dynamic - Stop and cleanup stale services removed from /etc/finit.d
|
* svc_clean_dynamic - Stop and cleanup stale services removed from /etc/finit.d
|
||||||
* @cb: Callback to run for each stale service
|
* @cb: Callback to run for each stale service
|
||||||
@@ -457,14 +379,13 @@ void svc_check_dirty(svc_t *svc, struct timeval *mtime)
|
|||||||
*/
|
*/
|
||||||
void svc_clean_dynamic(void (*cb)(svc_t *))
|
void svc_clean_dynamic(void (*cb)(svc_t *))
|
||||||
{
|
{
|
||||||
svc_t *svc = svc_dynamic_iterator(1);
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
while (svc) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (svc->dirty == -1 && cb) {
|
if (svc->dirty == -1 && cb) {
|
||||||
cb(svc);
|
cb(svc);
|
||||||
svc_mark_clean(svc);
|
svc_mark_clean(svc);
|
||||||
}
|
}
|
||||||
svc = svc_dynamic_iterator(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,9 +416,9 @@ int svc_clean_bootstrap(svc_t *svc)
|
|||||||
*/
|
*/
|
||||||
void svc_prune_bootstrap(void)
|
void svc_prune_bootstrap(void)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!svc->pid)
|
if (!svc->pid)
|
||||||
svc_clean_bootstrap(svc);
|
svc_clean_bootstrap(svc);
|
||||||
}
|
}
|
||||||
@@ -526,77 +447,13 @@ int svc_enabled(svc_t *svc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *svc_status(svc_t *svc)
|
|
||||||
{
|
|
||||||
switch (svc->state) {
|
|
||||||
case SVC_HALTED_STATE:
|
|
||||||
switch (svc->block) {
|
|
||||||
case SVC_BLOCK_NONE:
|
|
||||||
return "halted";
|
|
||||||
|
|
||||||
case SVC_BLOCK_MISSING:
|
|
||||||
return "missing";
|
|
||||||
|
|
||||||
case SVC_BLOCK_CRASHING:
|
|
||||||
return "crashed";
|
|
||||||
|
|
||||||
case SVC_BLOCK_USER:
|
|
||||||
return "stopped";
|
|
||||||
|
|
||||||
case SVC_BLOCK_BUSY:
|
|
||||||
return "busy";
|
|
||||||
|
|
||||||
case SVC_BLOCK_RESTARTING:
|
|
||||||
return "restart";
|
|
||||||
}
|
|
||||||
|
|
||||||
case SVC_DONE_STATE:
|
|
||||||
return "done";
|
|
||||||
|
|
||||||
case SVC_STOPPING_STATE:
|
|
||||||
switch (svc->type) {
|
|
||||||
case SVC_TYPE_INETD_CONN:
|
|
||||||
case SVC_TYPE_RUN:
|
|
||||||
case SVC_TYPE_TASK:
|
|
||||||
return "active";
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "stopping";
|
|
||||||
}
|
|
||||||
|
|
||||||
case SVC_WAITING_STATE:
|
|
||||||
return "waiting";
|
|
||||||
|
|
||||||
case SVC_READY_STATE:
|
|
||||||
return "ready";
|
|
||||||
|
|
||||||
case SVC_RUNNING_STATE:
|
|
||||||
return "running";
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *svc_dirtystr(svc_t *svc)
|
|
||||||
{
|
|
||||||
if (svc_is_removed(svc))
|
|
||||||
return "removed";
|
|
||||||
if (svc_is_updated(svc))
|
|
||||||
return "updated";
|
|
||||||
if (svc_is_changed(svc))
|
|
||||||
return "UNKNOWN";
|
|
||||||
|
|
||||||
return "clean";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Same base service, return unique ID */
|
/* Same base service, return unique ID */
|
||||||
int svc_next_id(char *cmd)
|
int svc_next_id(char *cmd)
|
||||||
{
|
{
|
||||||
int id = 0;
|
int id = 0;
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
|
|
||||||
for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
|
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||||
if (!strcmp(svc->cmd, cmd) && id < svc->id)
|
if (!strcmp(svc->cmd, cmd) && id < svc->id)
|
||||||
id = svc->id;
|
id = svc->id;
|
||||||
}
|
}
|
||||||
@@ -606,12 +463,10 @@ int svc_next_id(char *cmd)
|
|||||||
|
|
||||||
int svc_is_unique(svc_t *svc)
|
int svc_is_unique(svc_t *svc)
|
||||||
{
|
{
|
||||||
svc_t *list = __connect_shm();
|
svc_t *s, *iter = NULL;
|
||||||
int i, unique = 1;
|
int unique = 1;
|
||||||
|
|
||||||
for (i = 0; i < MAX_NUM_SVC; i++) {
|
|
||||||
svc_t *s = &list[i];
|
|
||||||
|
|
||||||
|
for (s = svc_iterator(&iter, 1); s; s = svc_iterator(&iter, 0)) {
|
||||||
if (svc->type == SVC_TYPE_FREE)
|
if (svc->type == SVC_TYPE_FREE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -642,21 +497,21 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
token = strtok_r(input, " ", &pos);
|
token = strtok_r(input, " ", &pos);
|
||||||
while (token) {
|
while (token) {
|
||||||
int id = 1;
|
int id = 1;
|
||||||
svc_t *svc;
|
svc_t *svc, *iter = NULL;
|
||||||
char *ptr = strchr(token, ':');
|
char *ptr = strchr(token, ':');
|
||||||
|
|
||||||
if (isdigit(token[0])) {
|
if (isdigit(token[0])) {
|
||||||
int job = atonum(token);
|
int job = atonum(token);
|
||||||
|
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
svc = svc_job_iterator(1, job);
|
svc = svc_job_iterator(&iter, 1, job);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(NULL, job);
|
result += not_found(NULL, job);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
result += found(svc);
|
result += found(svc);
|
||||||
svc = svc_job_iterator(0, job);
|
svc = svc_job_iterator(&iter, 0, job);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
@@ -671,14 +526,14 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
svc = svc_named_iterator(1, token);
|
svc = svc_named_iterator(&iter, 1, token);
|
||||||
if (!svc && not_found)
|
if (!svc && not_found)
|
||||||
result += not_found(token, id);
|
result += not_found(token, id);
|
||||||
|
|
||||||
while (svc) {
|
while (svc) {
|
||||||
if (found)
|
if (found)
|
||||||
result += found(svc);
|
result += found(svc);
|
||||||
svc = svc_named_iterator(0, token);
|
svc = svc_named_iterator(&iter, 0, token);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*ptr++ = 0;
|
*ptr++ = 0;
|
||||||
|
|||||||
@@ -27,9 +27,9 @@
|
|||||||
|
|
||||||
#include <sys/ipc.h> /* IPC_CREAT */
|
#include <sys/ipc.h> /* IPC_CREAT */
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/shm.h> /* shmat() */
|
|
||||||
#include <sys/types.h> /* pid_t */
|
#include <sys/types.h> /* pid_t */
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
|
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||||
|
|
||||||
#include "inetd.h"
|
#include "inetd.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -66,13 +66,11 @@ typedef enum {
|
|||||||
SVC_BLOCK_RESTARTING,
|
SVC_BLOCK_RESTARTING,
|
||||||
} svc_block_t;
|
} svc_block_t;
|
||||||
|
|
||||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
|
||||||
#define MAX_ARG_LEN 64
|
#define MAX_ARG_LEN 64
|
||||||
#define MAX_STR_LEN 64
|
#define MAX_STR_LEN 64
|
||||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||||
#define MAX_USER_LEN 16
|
#define MAX_USER_LEN 16
|
||||||
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
||||||
#define MAX_NUM_SVC 64 /* Enough? */
|
|
||||||
#define MAX_NUM_SVC_ARGS 32
|
#define MAX_NUM_SVC_ARGS 32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -82,6 +80,8 @@ typedef enum {
|
|||||||
* initctl <stop|start|restart> service
|
* initctl <stop|start|restart> service
|
||||||
*/
|
*/
|
||||||
typedef struct svc {
|
typedef struct svc {
|
||||||
|
TAILQ_ENTRY(svc) link;
|
||||||
|
|
||||||
/* Instance specifics */
|
/* Instance specifics */
|
||||||
int job, id; /* JOB:ID */
|
int job, id; /* JOB:ID */
|
||||||
|
|
||||||
@@ -92,9 +92,7 @@ typedef struct svc {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||||
svc_type_t type; /* Service, run, task, inetd, ... */
|
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||||
struct timeval mtime; /* Modification time for .conf from /etc/finit.d/ */
|
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
||||||
const int dirty; /* Set if old mtime != new mtime => reloaded,
|
|
||||||
* or -1 when marked for removal */
|
|
||||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||||
int runlevels;
|
int runlevels;
|
||||||
int sighup; /* This service supports SIGHUP :) */
|
int sighup; /* This service supports SIGHUP :) */
|
||||||
@@ -129,23 +127,6 @@ typedef struct svc {
|
|||||||
void (*timer_cb)(struct svc *svc);
|
void (*timer_cb)(struct svc *svc);
|
||||||
} svc_t;
|
} svc_t;
|
||||||
|
|
||||||
typedef struct svc_map svc_map_t;
|
|
||||||
|
|
||||||
/* Put services array in shm */
|
|
||||||
static inline svc_t *finit_svc_connect(void)
|
|
||||||
{
|
|
||||||
static void *ptr = (void *)-1;
|
|
||||||
|
|
||||||
if ((void *)-1 == ptr) {
|
|
||||||
ptr = shmat(shmget(FINIT_SHM_ID, sizeof(svc_t) * MAX_NUM_SVC,
|
|
||||||
0600 | IPC_CREAT), NULL, 0);
|
|
||||||
if ((void *)-1 == ptr)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (svc_t *)ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
svc_t *svc_new (char *cmd, int id, int type);
|
svc_t *svc_new (char *cmd, int id, int type);
|
||||||
int svc_del (svc_t *svc);
|
int svc_del (svc_t *svc);
|
||||||
|
|
||||||
@@ -154,20 +135,17 @@ svc_t *svc_find_by_pid (pid_t pid);
|
|||||||
svc_t *svc_find_by_jobid (int job, int id);
|
svc_t *svc_find_by_jobid (int job, int id);
|
||||||
svc_t *svc_find_by_nameid (char *name, int id);
|
svc_t *svc_find_by_nameid (char *name, int id);
|
||||||
|
|
||||||
svc_t *svc_iterator (int first);
|
svc_t *svc_iterator (svc_t **iter, int first);
|
||||||
svc_t *svc_inetd_iterator (int first);
|
svc_t *svc_inetd_iterator (svc_t **iter, int first);
|
||||||
svc_t *svc_dynamic_iterator (int first);
|
svc_t *svc_named_iterator (svc_t **iter, int first, char *cmd);
|
||||||
svc_t *svc_named_iterator (int first, char *cmd);
|
svc_t *svc_job_iterator (svc_t **iter, int first, int job);
|
||||||
svc_t *svc_job_iterator (int first, int job);
|
|
||||||
|
|
||||||
void svc_foreach (void (*cb)(svc_t *));
|
void svc_foreach (void (*cb)(svc_t *));
|
||||||
void svc_foreach_dynamic (void (*cb)(svc_t *));
|
|
||||||
void svc_foreach_type (int types, void (*cb)(svc_t *));
|
void svc_foreach_type (int types, void (*cb)(svc_t *));
|
||||||
|
|
||||||
svc_t *svc_stop_completed (void);
|
svc_t *svc_stop_completed (void);
|
||||||
|
|
||||||
void svc_mark_dynamic (void);
|
void svc_mark_dynamic (void);
|
||||||
void svc_check_dirty (svc_t *svc, struct timeval *mtime);
|
|
||||||
void svc_mark_dirty (svc_t *svc);
|
void svc_mark_dirty (svc_t *svc);
|
||||||
void svc_mark_clean (svc_t *svc);
|
void svc_mark_clean (svc_t *svc);
|
||||||
void svc_clean_dynamic (void (*cb)(svc_t *));
|
void svc_clean_dynamic (void (*cb)(svc_t *));
|
||||||
@@ -175,8 +153,6 @@ int svc_clean_bootstrap (svc_t *svc);
|
|||||||
void svc_prune_bootstrap (void);
|
void svc_prune_bootstrap (void);
|
||||||
|
|
||||||
int svc_enabled (svc_t *svc);
|
int svc_enabled (svc_t *svc);
|
||||||
char *svc_status (svc_t *svc);
|
|
||||||
const char *svc_dirtystr (svc_t *svc);
|
|
||||||
int svc_next_id (char *cmd);
|
int svc_next_id (char *cmd);
|
||||||
int svc_is_unique (svc_t *svc);
|
int svc_is_unique (svc_t *svc);
|
||||||
|
|
||||||
@@ -189,7 +165,6 @@ static inline void svc_starting (svc_t *svc) { svc->starting = 1; }
|
|||||||
static inline void svc_started (svc_t *svc) { svc->starting = 0; }
|
static inline void svc_started (svc_t *svc) { svc->starting = 0; }
|
||||||
static inline int svc_is_starting (svc_t *svc) { return 0 != svc->starting; }
|
static inline int svc_is_starting (svc_t *svc) { return 0 != svc->starting; }
|
||||||
|
|
||||||
static inline int svc_is_dynamic (svc_t *svc) { return svc && 0 != svc->mtime.tv_sec; }
|
|
||||||
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
static inline int svc_is_removed (svc_t *svc) { return svc && -1 == svc->dirty; }
|
||||||
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
static inline int svc_is_changed (svc_t *svc) { return svc && 0 != svc->dirty; }
|
||||||
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
static inline int svc_is_updated (svc_t *svc) { return svc && 1 == svc->dirty; }
|
||||||
@@ -209,6 +184,70 @@ static inline void svc_missing (svc_t *svc) { svc->block = SVC_BLOCK_MISSING
|
|||||||
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
|
static inline void svc_restarting (svc_t *svc) { svc->block = SVC_BLOCK_RESTARTING; }
|
||||||
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
static inline void svc_crashing (svc_t *svc) { svc->block = SVC_BLOCK_CRASHING; }
|
||||||
|
|
||||||
|
static inline char *svc_status(svc_t *svc)
|
||||||
|
{
|
||||||
|
switch (svc->state) {
|
||||||
|
case SVC_HALTED_STATE:
|
||||||
|
switch (svc->block) {
|
||||||
|
case SVC_BLOCK_NONE:
|
||||||
|
return "halted";
|
||||||
|
|
||||||
|
case SVC_BLOCK_MISSING:
|
||||||
|
return "missing";
|
||||||
|
|
||||||
|
case SVC_BLOCK_CRASHING:
|
||||||
|
return "crashed";
|
||||||
|
|
||||||
|
case SVC_BLOCK_USER:
|
||||||
|
return "stopped";
|
||||||
|
|
||||||
|
case SVC_BLOCK_BUSY:
|
||||||
|
return "busy";
|
||||||
|
|
||||||
|
case SVC_BLOCK_RESTARTING:
|
||||||
|
return "restart";
|
||||||
|
}
|
||||||
|
|
||||||
|
case SVC_DONE_STATE:
|
||||||
|
return "done";
|
||||||
|
|
||||||
|
case SVC_STOPPING_STATE:
|
||||||
|
switch (svc->type) {
|
||||||
|
case SVC_TYPE_INETD_CONN:
|
||||||
|
case SVC_TYPE_RUN:
|
||||||
|
case SVC_TYPE_TASK:
|
||||||
|
return "active";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "stopping";
|
||||||
|
}
|
||||||
|
|
||||||
|
case SVC_WAITING_STATE:
|
||||||
|
return "waiting";
|
||||||
|
|
||||||
|
case SVC_READY_STATE:
|
||||||
|
return "ready";
|
||||||
|
|
||||||
|
case SVC_RUNNING_STATE:
|
||||||
|
return "running";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *svc_dirtystr(svc_t *svc)
|
||||||
|
{
|
||||||
|
if (svc_is_removed(svc))
|
||||||
|
return "removed";
|
||||||
|
if (svc_is_updated(svc))
|
||||||
|
return "updated";
|
||||||
|
if (svc_is_changed(svc))
|
||||||
|
return "UNKNOWN";
|
||||||
|
|
||||||
|
return "clean";
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -90,22 +90,8 @@ void tty_mark(void)
|
|||||||
{
|
{
|
||||||
tty_node_t *tty;
|
tty_node_t *tty;
|
||||||
|
|
||||||
LIST_FOREACH(tty, &tty_list, link) {
|
LIST_FOREACH(tty, &tty_list, link)
|
||||||
if (tty->mtime.tv_sec)
|
tty->dirty = -1;
|
||||||
tty->dirty = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tty_check(tty_node_t *tty, struct timeval *mtime)
|
|
||||||
{
|
|
||||||
if (mtime && timercmp(&tty->mtime, mtime, !=))
|
|
||||||
tty->dirty = 1; /* Modified, restart */
|
|
||||||
else
|
|
||||||
tty->dirty = 0; /* Not modified */
|
|
||||||
|
|
||||||
/* Update mtime, if given */
|
|
||||||
tty->mtime.tv_sec = mtime ? mtime->tv_sec : 0;
|
|
||||||
tty->mtime.tv_usec = mtime ? mtime->tv_usec : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_sweep(void)
|
void tty_sweep(void)
|
||||||
@@ -113,14 +99,15 @@ void tty_sweep(void)
|
|||||||
tty_node_t *tty, *tmp;
|
tty_node_t *tty, *tmp;
|
||||||
|
|
||||||
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
LIST_FOREACH_SAFE(tty, &tty_list, link, tmp) {
|
||||||
if (tty->mtime.tv_sec && tty->dirty) {
|
if (!tty->dirty)
|
||||||
_d("TTY %s dirty, stopping ...", tty->data.name);
|
continue;
|
||||||
tty_stop(&tty->data);
|
|
||||||
|
|
||||||
if (tty->dirty == -1) {
|
_d("TTY %s dirty, stopping ...", tty->data.name);
|
||||||
_d("TTY %s removed, cleaning up.", tty->data.name);
|
tty_stop(&tty->data);
|
||||||
tty_unregister(tty);
|
|
||||||
}
|
if (tty->dirty == -1) {
|
||||||
|
_d("TTY %s removed, cleaning up.", tty->data.name);
|
||||||
|
tty_unregister(tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +116,7 @@ void tty_sweep(void)
|
|||||||
* tty_register - Register a getty on a device
|
* tty_register - Register a getty on a device
|
||||||
* @line: Configuration, text after initial "tty"
|
* @line: Configuration, text after initial "tty"
|
||||||
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
||||||
* @mtime: Modification time, to propagate to lower layers
|
* @file: The file name TTY was loaded from
|
||||||
*
|
*
|
||||||
* A Finit tty line can use the internal getty implementation or an
|
* A Finit tty line can use the internal getty implementation or an
|
||||||
* external one, like the BusyBox getty for instance. This function
|
* external one, like the BusyBox getty for instance. This function
|
||||||
@@ -147,7 +134,7 @@ void tty_sweep(void)
|
|||||||
* Different getty implementations prefer the TTY device argument in
|
* Different getty implementations prefer the TTY device argument in
|
||||||
* different order, so take care to investigate this first.
|
* different order, so take care to investigate this first.
|
||||||
*/
|
*/
|
||||||
int tty_register(char *line, struct rlimit rlimit[], struct timeval *mtime)
|
int tty_register(char *line, struct rlimit rlimit[], char *file)
|
||||||
{
|
{
|
||||||
tty_node_t *entry;
|
tty_node_t *entry;
|
||||||
int insert = 0, noclear = 0, nowait = 0;
|
int insert = 0, noclear = 0, nowait = 0;
|
||||||
@@ -282,7 +269,10 @@ int tty_register(char *line, struct rlimit rlimit[], struct timeval *mtime)
|
|||||||
/* Register configured limits */
|
/* Register configured limits */
|
||||||
memcpy(entry->data.rlimit, rlimit, sizeof(entry->data.rlimit));
|
memcpy(entry->data.rlimit, rlimit, sizeof(entry->data.rlimit));
|
||||||
|
|
||||||
tty_check(entry, mtime);
|
if (file && conf_changed(file))
|
||||||
|
entry->dirty = 1; /* Modified, restart */
|
||||||
|
else
|
||||||
|
entry->dirty = 0; /* Not modified */
|
||||||
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
_d("TTY %s is %sdirty", dev, entry->dirty ? "" : "NOT ");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ typedef struct tty_node {
|
|||||||
finit_tty_t data;
|
finit_tty_t data;
|
||||||
|
|
||||||
/* XXX: Yes, TTYs should be refactored into a separate SVC type. */
|
/* XXX: Yes, TTYs should be refactored into a separate SVC type. */
|
||||||
struct timeval mtime; /* Modification time for .conf from /etc/finit.d/ */
|
|
||||||
int dirty; /* Set if old mtime != new mtime => reloaded,
|
int dirty; /* Set if old mtime != new mtime => reloaded,
|
||||||
* or -1 when marked for removal */
|
* or -1 when marked for removal */
|
||||||
} tty_node_t;
|
} tty_node_t;
|
||||||
@@ -62,10 +61,9 @@ typedef struct tty_node {
|
|||||||
//extern LIST_HEAD(, tty_node) tty_list;
|
//extern LIST_HEAD(, tty_node) tty_list;
|
||||||
|
|
||||||
void tty_mark (void);
|
void tty_mark (void);
|
||||||
void tty_check (tty_node_t *tty, struct timeval *mtime);
|
|
||||||
void tty_sweep (void);
|
void tty_sweep (void);
|
||||||
|
|
||||||
int tty_register (char *line, struct rlimit rlimit[], struct timeval *mtime);
|
int tty_register (char *line, struct rlimit rlimit[], char *file);
|
||||||
int tty_unregister (tty_node_t *tty);
|
int tty_unregister (tty_node_t *tty);
|
||||||
|
|
||||||
tty_node_t *tty_find (char *dev);
|
tty_node_t *tty_find (char *dev);
|
||||||
|
|||||||
Reference in new issue
Block a user