mirror of
https://github.com/troglobit/finit.git
synced 2026-11-03 13:28:27 +00:00
inetd: Re-integrate the inetd subsystem into the new service model
This patch introduces a new service type called SVC_TYPE_INETD_CONN, which represents a running inetd connection. These are handled in much the same way as tasks. I.e. they are considered one-time jobs, with the difference that they are removed upon completion.
This commit is contained in:
1 parent
0beb566e45
commit
6ece4b8fa3
6 files changed
+219
-176
No files matched your search
@@ -43,75 +43,8 @@
|
|||||||
#opt, inetd->name); \
|
#opt, inetd->name); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
/* Socket callback, looks up correct svc and starts it as an inetd service */
|
|
||||||
static void socket_cb(uev_t *w, void *arg, int UNUSED(events))
|
|
||||||
{
|
|
||||||
svc_t *svc = (svc_t *)arg;
|
|
||||||
|
|
||||||
if (SVC_START != service_enabled(svc, -1, NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!svc->inetd.forking)
|
|
||||||
uev_io_stop(w);
|
|
||||||
|
|
||||||
service_start(svc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Launch Inet socket for service.
|
|
||||||
* TODO: Add filtering ALLOW/DENY per interface.
|
|
||||||
*/
|
|
||||||
static void spawn_socket(inetd_t *inetd)
|
|
||||||
{
|
|
||||||
int sd;
|
|
||||||
socklen_t len = sizeof(struct sockaddr);
|
|
||||||
struct sockaddr_in s;
|
|
||||||
|
|
||||||
if (!inetd->type) {
|
|
||||||
FLOG_ERROR("Skipping invalid inetd service %s", inetd->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("Spawning server socket for inetd %s ...", inetd->name);
|
|
||||||
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
|
|
||||||
if (-1 == sd) {
|
|
||||||
FLOG_PERROR("Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEADDR);
|
|
||||||
#ifdef SO_REUSEPORT
|
|
||||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEPORT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(&s, 0, sizeof(s));
|
|
||||||
s.sin_family = AF_INET;
|
|
||||||
s.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
s.sin_port = htons(inetd->port);
|
|
||||||
if (bind(sd, (struct sockaddr *)&s, len) < 0) {
|
|
||||||
FLOG_PERROR("Failed binding to port %d, maybe another %s server is already running",
|
|
||||||
inetd->port, inetd->name);
|
|
||||||
close(sd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inetd->port) {
|
|
||||||
if (inetd->type == SOCK_STREAM) {
|
|
||||||
if (-1 == listen(sd, 20)) {
|
|
||||||
FLOG_PERROR("Failed listening to inetd service %s", inetd->name);
|
|
||||||
close(sd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else { /* SOCK_DGRAM */
|
|
||||||
/* Set extra sockopt to get ifindex from inbound packets */
|
|
||||||
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->arg, sd, UEV_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||||
int inetd_dgram_peek(int sd, char *ifname)
|
static int inetd_dgram_peek(int sd, char *ifname)
|
||||||
{
|
{
|
||||||
char cmbuf[0x100];
|
char cmbuf[0x100];
|
||||||
struct msghdr msgh;
|
struct msghdr msgh;
|
||||||
@@ -139,7 +72,7 @@ int inetd_dgram_peek(int sd, char *ifname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
||||||
int inetd_stream_peek(int sd, char *ifname)
|
static int inetd_stream_peek(int sd, char *ifname)
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
@@ -173,46 +106,146 @@ int inetd_stream_peek(int sd, char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inetd monitor, called by service_monitor() */
|
static int get_stdin(svc_t *svc)
|
||||||
int inetd_respawn(pid_t pid)
|
|
||||||
{
|
{
|
||||||
svc_t *svc = svc_find_by_pid(pid);
|
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
||||||
|
int stdin = svc->inetd.watcher.fd;
|
||||||
|
|
||||||
if (svc_is_inetd(svc)) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
inetd_t *inetd = &svc->inetd;
|
/* Open new client socket from server socket */
|
||||||
|
stdin = accept(stdin, NULL, NULL);
|
||||||
|
if (stdin < 0) {
|
||||||
|
FLOG_PERROR("Failed accepting inetd service %d/tcp", svc->inetd.port);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
svc->pid = 0;
|
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||||
|
|
||||||
if (svc_in_runlevel(svc, runlevel) && !inetd->forking)
|
inetd_stream_peek(stdin, ifname);
|
||||||
uev_io_set(&inetd->watcher, inetd->watcher.fd, UEV_READ);
|
} else { /* SOCK_DGRAM */
|
||||||
|
inetd_dgram_peek(stdin, ifname);
|
||||||
return 1; /* It was us! */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* Not an inetd service */
|
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
||||||
|
FLOG_INFO("Service %s on port %d not allowed from interface %s.",
|
||||||
|
svc->inetd.name, svc->inetd.port, ifname);
|
||||||
|
if (svc->inetd.type == SOCK_STREAM)
|
||||||
|
close(stdin);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Socket callback, looks up correct svc and starts it as an inetd service */
|
||||||
|
static void socket_cb(uev_t *w, void *arg, int UNUSED(events))
|
||||||
|
{
|
||||||
|
svc_t *svc = (svc_t *)arg, *task;
|
||||||
|
int stdin;
|
||||||
|
|
||||||
void inetd_start(inetd_t *inetd)
|
stdin = get_stdin(svc);
|
||||||
|
if (stdin < 0) {
|
||||||
|
FLOG_ERROR("%s: Unable to accept incoming connection",
|
||||||
|
svc->cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN);
|
||||||
|
if (!task) {
|
||||||
|
FLOG_ERROR("%s: Unable to allocate service for inetd client",
|
||||||
|
svc->cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy inherited attributes from inetd */
|
||||||
|
task->runlevels = svc->runlevels;
|
||||||
|
task->inetd = svc->inetd;
|
||||||
|
memcpy(task->cond, svc->cond, sizeof(task->cond));
|
||||||
|
memcpy(task->username, svc->username, sizeof(task->username));
|
||||||
|
memcpy(task->group, svc->group, sizeof(task->group));
|
||||||
|
memcpy(task->args, svc->args, sizeof(task->args));
|
||||||
|
snprintf(task->desc, sizeof(task->desc), "%s Connection", svc->desc);
|
||||||
|
|
||||||
|
task->stdin = stdin;
|
||||||
|
service_step(task);
|
||||||
|
|
||||||
|
if (!svc->inetd.forking) {
|
||||||
|
svc->block = SVC_BLOCK_INETD_BUSY;
|
||||||
|
service_step(svc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Launch Inet socket for service.
|
||||||
|
* TODO: Add filtering ALLOW/DENY per interface.
|
||||||
|
*/
|
||||||
|
static int spawn_socket(inetd_t *inetd)
|
||||||
|
{
|
||||||
|
int sd;
|
||||||
|
socklen_t len = sizeof(struct sockaddr);
|
||||||
|
struct sockaddr_in s;
|
||||||
|
|
||||||
|
if (!inetd->type) {
|
||||||
|
FLOG_ERROR("Skipping invalid inetd service %s", inetd->name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("Spawning server socket for inetd %s ...", inetd->name);
|
||||||
|
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
|
||||||
|
if (-1 == sd) {
|
||||||
|
FLOG_PERROR("Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEADDR);
|
||||||
|
#ifdef SO_REUSEPORT
|
||||||
|
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEPORT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
|
s.sin_family = AF_INET;
|
||||||
|
s.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
s.sin_port = htons(inetd->port);
|
||||||
|
if (bind(sd, (struct sockaddr *)&s, len) < 0) {
|
||||||
|
FLOG_PERROR("Failed binding to port %d, maybe another %s server is already running",
|
||||||
|
inetd->port, inetd->name);
|
||||||
|
close(sd);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inetd->port) {
|
||||||
|
if (inetd->type == SOCK_STREAM) {
|
||||||
|
if (-1 == listen(sd, 20)) {
|
||||||
|
FLOG_PERROR("Failed listening to inetd service %s", inetd->name);
|
||||||
|
close(sd);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
} else { /* SOCK_DGRAM */
|
||||||
|
/* Set extra sockopt to get ifindex from inbound packets */
|
||||||
|
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->svc, sd, UEV_READ);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inetd_start(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
if (inetd->watcher.fd == -1)
|
if (inetd->watcher.fd == -1)
|
||||||
spawn_socket(inetd);
|
return spawn_socket(inetd);
|
||||||
|
|
||||||
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inetd_stop(inetd_t *inetd)
|
void inetd_stop(inetd_t *inetd)
|
||||||
{
|
{
|
||||||
svc_t *svc = (svc_t *)inetd->arg;
|
|
||||||
|
|
||||||
if (inetd->watcher.fd != -1) {
|
if (inetd->watcher.fd != -1) {
|
||||||
uev_io_stop(&inetd->watcher);
|
uev_io_stop(&inetd->watcher);
|
||||||
shutdown(inetd->watcher.fd, SHUT_RDWR);
|
shutdown(inetd->watcher.fd, SHUT_RDWR);
|
||||||
close(inetd->watcher.fd);
|
close(inetd->watcher.fd);
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop any running service, not allowed anymore. */
|
|
||||||
if (svc->pid)
|
|
||||||
service_stop(svc, SVC_WAITING_STATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
||||||
@@ -497,7 +530,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
* If equivalent service exists already service_register() will instead call
|
* If equivalent service exists already service_register() will instead call
|
||||||
* inetd_allow().
|
* inetd_allow().
|
||||||
*/
|
*/
|
||||||
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, void *arg)
|
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct servent *sv = NULL;
|
struct servent *sv = NULL;
|
||||||
@@ -515,6 +548,7 @@ int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forkin
|
|||||||
inetd->port = ntohs(sv->s_port);
|
inetd->port = ntohs(sv->s_port);
|
||||||
inetd->proto = pv->p_proto;
|
inetd->proto = pv->p_proto;
|
||||||
inetd->forking = !!forking;
|
inetd->forking = !!forking;
|
||||||
|
inetd->next_id = 2;
|
||||||
if (!name)
|
if (!name)
|
||||||
name = service;
|
name = service;
|
||||||
strlcpy(inetd->name, name, sizeof(inetd->name));
|
strlcpy(inetd->name, name, sizeof(inetd->name));
|
||||||
@@ -526,11 +560,18 @@ int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forkin
|
|||||||
else
|
else
|
||||||
inetd->type = SOCK_DGRAM;
|
inetd->type = SOCK_DGRAM;
|
||||||
|
|
||||||
|
if (inetd->type == SOCK_DGRAM && inetd->forking) {
|
||||||
|
FLOG_WARN("%s: 'nowait' is not applicable on UDP services, ignoring",
|
||||||
|
svc->cmd);
|
||||||
|
|
||||||
|
inetd->forking = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset descriptor, used internally */
|
/* Reset descriptor, used internally */
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
|
|
||||||
/* Setup socket callback argument */
|
/* Setup socket callback argument */
|
||||||
inetd->arg = arg;
|
inetd->svc = svc;
|
||||||
|
|
||||||
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "libuev/uev.h"
|
#include "libuev/uev.h"
|
||||||
|
|
||||||
|
typedef struct svc svc_t;
|
||||||
|
|
||||||
typedef struct inetd_filter {
|
typedef struct inetd_filter {
|
||||||
TAILQ_ENTRY(inetd_filter) link;
|
TAILQ_ENTRY(inetd_filter) link;
|
||||||
@@ -39,28 +40,25 @@ typedef struct inetd_filter {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uev_t watcher;
|
uev_t watcher;
|
||||||
void *arg; /* svc_t pointer for the socket callback */
|
svc_t *svc; /* svc_t pointer for the socket callback */
|
||||||
|
|
||||||
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
||||||
int std; /* Standard proto/port from /etc/services */
|
int std; /* Standard proto/port from /etc/services */
|
||||||
int proto;
|
int proto;
|
||||||
int port;
|
int port;
|
||||||
int forking;
|
int forking;
|
||||||
|
int next_id; /* Next child job's id */
|
||||||
char name[10];
|
char name[10];
|
||||||
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
||||||
|
|
||||||
TAILQ_HEAD(, inetd_filter) filters;
|
TAILQ_HEAD(, inetd_filter) filters;
|
||||||
} inetd_t;
|
} inetd_t;
|
||||||
|
|
||||||
int inetd_dgram_peek (int sd, char *ifname);
|
int inetd_start (inetd_t *inetd);
|
||||||
int inetd_stream_peek (int sd, char *ifname);
|
|
||||||
|
|
||||||
void inetd_start (inetd_t *inetd);
|
|
||||||
void inetd_stop (inetd_t *inetd);
|
void inetd_stop (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_respawn (pid_t pid);
|
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto,
|
||||||
|
int forking, svc_t *svc);
|
||||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, void *arg);
|
|
||||||
int inetd_del (inetd_t *inetd);
|
int inetd_del (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||||
|
|||||||
@@ -234,7 +234,12 @@ static int show_status(char *arg)
|
|||||||
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 %-6d ", jobid, svc_status(svc), svc->pid);
|
printf("%-5s %7s ", jobid, svc_status(svc));
|
||||||
|
if (svc_is_inetd(svc))
|
||||||
|
printf("inetd ");
|
||||||
|
else
|
||||||
|
printf("%-6d ", svc->pid);
|
||||||
|
|
||||||
lvls = runlevel_string(svc->runlevels);
|
lvls = runlevel_string(svc->runlevels);
|
||||||
if (strchr(lvls, '\e'))
|
if (strchr(lvls, '\e'))
|
||||||
printf("%-18.18s ", lvls);
|
printf("%-18.18s ", lvls);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ static int is_norespawn(void)
|
|||||||
*/
|
*/
|
||||||
static int service_start(svc_t *svc)
|
static int service_start(svc_t *svc)
|
||||||
{
|
{
|
||||||
int sd = 0;
|
int result = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
sigset_t nmask, omask;
|
sigset_t nmask, omask;
|
||||||
|
|
||||||
@@ -137,48 +137,20 @@ static int service_start(svc_t *svc)
|
|||||||
if (is_norespawn())
|
if (is_norespawn())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
|
||||||
if (svc_is_inetd(svc)) {
|
|
||||||
char ifname[IF_NAMESIZE] = "UNKNOWN";
|
|
||||||
|
|
||||||
sd = svc->inetd.watcher.fd;
|
|
||||||
|
|
||||||
if (svc->inetd.type == SOCK_STREAM) {
|
|
||||||
/* Open new client socket from server socket */
|
|
||||||
sd = accept(sd, NULL, NULL);
|
|
||||||
if (sd < 0) {
|
|
||||||
FLOG_PERROR("Failed accepting inetd service %d/tcp", svc->inetd.port);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_d("New client socket %d accepted for inetd service %d/tcp", sd, svc->inetd.port);
|
|
||||||
|
|
||||||
/* Find ifname by means of getsockname() and getifaddrs() */
|
|
||||||
inetd_stream_peek(sd, ifname);
|
|
||||||
} else { /* SOCK_DGRAM */
|
|
||||||
/* Find ifname by means of IP_PKTINFO sockopt --> ifindex + if_indextoname() */
|
|
||||||
inetd_dgram_peek(sd, ifname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
|
||||||
FLOG_INFO("Service %s on port %d not allowed from interface %s.",
|
|
||||||
svc->inetd.name, svc->inetd.port, ifname);
|
|
||||||
if (svc->inetd.type == SOCK_STREAM)
|
|
||||||
close(sd);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FLOG_INFO("Starting inetd service %s for requst from iface %s ...", svc->inetd.name, ifname);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
if (svc_is_daemon(svc))
|
if (svc_is_daemon(svc) || svc_is_inetd(svc))
|
||||||
print_desc("Starting ", svc->desc);
|
print_desc("Starting ", svc->desc);
|
||||||
else
|
else
|
||||||
print_desc("", svc->desc);
|
print_desc("", svc->desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (svc_is_inetd(svc)) {
|
||||||
|
result = inetd_start(&svc->inetd);
|
||||||
|
if (verbose)
|
||||||
|
print_result(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Block sigchild while forking. */
|
/* Block sigchild while forking. */
|
||||||
sigemptyset(&nmask);
|
sigemptyset(&nmask);
|
||||||
sigaddset(&nmask, SIGCHLD);
|
sigaddset(&nmask, SIGCHLD);
|
||||||
@@ -219,11 +191,10 @@ static int service_start(svc_t *svc)
|
|||||||
args[i] = svc->args[i];
|
args[i] = svc->args[i];
|
||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
|
|
||||||
/* Redirect inetd socket to stdin for service */
|
/* Redirect inetd socket to stdin for connection */
|
||||||
if (svc_is_inetd(svc)) {
|
if (svc_is_inetd_conn(svc)) {
|
||||||
/* sd set previously */
|
dup2(svc->stdin, STDIN_FILENO);
|
||||||
dup2(sd, STDIN_FILENO);
|
close(svc->stdin);
|
||||||
close(sd);
|
|
||||||
dup2(STDIN_FILENO, STDOUT_FILENO);
|
dup2(STDIN_FILENO, STDOUT_FILENO);
|
||||||
dup2(STDIN_FILENO, STDERR_FILENO);
|
dup2(STDIN_FILENO, STDERR_FILENO);
|
||||||
} else if (debug) {
|
} else if (debug) {
|
||||||
@@ -254,7 +225,7 @@ static int service_start(svc_t *svc)
|
|||||||
else
|
else
|
||||||
status = execv(svc->cmd, args); /* XXX: Maybe use execve() to be able to launch scripts? */
|
status = execv(svc->cmd, args); /* XXX: Maybe use execve() to be able to launch scripts? */
|
||||||
|
|
||||||
if (svc_is_inetd(svc)) {
|
if (svc_is_inetd_conn(svc)) {
|
||||||
if (svc->inetd.type == SOCK_STREAM) {
|
if (svc->inetd.type == SOCK_STREAM) {
|
||||||
close(STDIN_FILENO);
|
close(STDIN_FILENO);
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
@@ -266,21 +237,17 @@ static int service_start(svc_t *svc)
|
|||||||
}
|
}
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|
||||||
if (svc_is_inetd(svc)) {
|
if (svc_is_inetd_conn(svc) && svc->inetd.type == SOCK_STREAM)
|
||||||
if (svc->inetd.type == SOCK_STREAM)
|
close(svc->stdin);
|
||||||
close(sd);
|
|
||||||
} else {
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
if (SVC_TYPE_RUN == svc->type) {
|
if (SVC_TYPE_RUN == svc->type) {
|
||||||
result = WEXITSTATUS(complete(svc->cmd, pid));
|
result = WEXITSTATUS(complete(svc->cmd, pid));
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
print_result(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
print_result(result);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +265,20 @@ static int service_stop(svc_t *svc)
|
|||||||
if (!svc)
|
if (!svc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (svc_is_inetd(svc)) {
|
||||||
|
int do_print = runlevel != 1 && verbose &&
|
||||||
|
svc->block != SVC_BLOCK_INETD_BUSY;
|
||||||
|
|
||||||
|
if (do_print)
|
||||||
|
print_desc("Stopping ", svc->desc);
|
||||||
|
|
||||||
|
inetd_stop(&svc->inetd);
|
||||||
|
|
||||||
|
if (do_print)
|
||||||
|
print_result(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc->pid <= 1) {
|
if (svc->pid <= 1) {
|
||||||
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
|
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -371,12 +352,12 @@ static void service_reload_dynamic_finish(void)
|
|||||||
svc_clean_dynamic(service_unregister);
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
_d("Starting services after reconf ...");
|
_d("Starting services after reconf ...");
|
||||||
service_step_all(SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
_d("Calling reconf hooks ...");
|
_d("Calling reconf hooks ...");
|
||||||
plugin_run_hooks(HOOK_SVC_RECONF);
|
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||||
|
|
||||||
service_step_all(SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
_d("Reconfiguration done");
|
_d("Reconfiguration done");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,7 +378,7 @@ void service_reload_dynamic(void)
|
|||||||
_d("Stopping services services not allowed after reconf ...");
|
_d("Stopping services services not allowed after reconf ...");
|
||||||
in_dyn_teardown = 1;
|
in_dyn_teardown = 1;
|
||||||
cond_reload();
|
cond_reload();
|
||||||
service_step_all(SVC_TYPE_SERVICE);
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
/* Need to wait for any services to stop? If so, exit early
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
* and perform second stage from service_monitor later. */
|
* and perform second stage from service_monitor later. */
|
||||||
@@ -684,7 +665,6 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
if (svc_is_inetd(svc)) {
|
if (svc_is_inetd(svc)) {
|
||||||
char *iface, *name = service;
|
char *iface, *name = service;
|
||||||
|
|
||||||
svc->state = SVC_WAITING_STATE;
|
|
||||||
if (svc->inetd.cmd && plugin)
|
if (svc->inetd.cmd && plugin)
|
||||||
name = plugin->name;
|
name = plugin->name;
|
||||||
|
|
||||||
@@ -714,8 +694,6 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
|
|
||||||
void service_unregister(svc_t *svc)
|
void service_unregister(svc_t *svc)
|
||||||
{
|
{
|
||||||
if (svc->state != SVC_HALTED_STATE)
|
|
||||||
_e("Failed stopping %s, removing anyway from list of monitored services.", svc->cmd);
|
|
||||||
svc_del(svc);
|
svc_del(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,11 +730,6 @@ void service_monitor(pid_t lost)
|
|||||||
if (tty_respawn(lost))
|
if (tty_respawn(lost))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
|
||||||
if (inetd_respawn(lost))
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
svc = svc_find_by_pid(lost);
|
svc = svc_find_by_pid(lost);
|
||||||
if (!svc) {
|
if (!svc) {
|
||||||
_d("collected unknown PID %d", lost);
|
_d("collected unknown PID %d", lost);
|
||||||
@@ -805,6 +778,15 @@ restart:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
|
if (svc_is_inetd_conn(svc)) {
|
||||||
|
if (svc->inetd.svc->block == SVC_BLOCK_INETD_BUSY) {
|
||||||
|
svc->inetd.svc->block = 0;
|
||||||
|
service_step(svc->inetd.svc);
|
||||||
|
}
|
||||||
|
service_unregister(svc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (svc_is_changed(svc))
|
if (svc_is_changed(svc))
|
||||||
*state = SVC_HALTED_STATE;
|
*state = SVC_HALTED_STATE;
|
||||||
break;
|
break;
|
||||||
@@ -816,6 +798,7 @@ restart:
|
|||||||
case SVC_TYPE_INETD:
|
case SVC_TYPE_INETD:
|
||||||
*state = SVC_HALTED_STATE;
|
*state = SVC_HALTED_STATE;
|
||||||
break;
|
break;
|
||||||
|
case SVC_TYPE_INETD_CONN:
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
*state = SVC_DONE_STATE;
|
*state = SVC_DONE_STATE;
|
||||||
@@ -841,16 +824,19 @@ restart:
|
|||||||
err = service_start(svc);
|
err = service_start(svc);
|
||||||
if (err) {
|
if (err) {
|
||||||
(*restart_counter)++;
|
(*restart_counter)++;
|
||||||
break;
|
|
||||||
|
if (!svc_is_inetd_conn(svc))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_mark_clean(svc);
|
svc_mark_clean(svc);
|
||||||
|
|
||||||
switch (svc->type) {
|
switch (svc->type) {
|
||||||
|
case SVC_TYPE_INETD:
|
||||||
case SVC_TYPE_SERVICE:
|
case SVC_TYPE_SERVICE:
|
||||||
*state = SVC_RUNNING_STATE;
|
*state = SVC_RUNNING_STATE;
|
||||||
break;
|
break;
|
||||||
case SVC_TYPE_INETD:
|
case SVC_TYPE_INETD_CONN:
|
||||||
case SVC_TYPE_TASK:
|
case SVC_TYPE_TASK:
|
||||||
case SVC_TYPE_RUN:
|
case SVC_TYPE_RUN:
|
||||||
*state = SVC_STOPPING_STATE;
|
*state = SVC_STOPPING_STATE;
|
||||||
@@ -868,7 +854,7 @@ restart:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!svc->pid) {
|
if (!svc->pid && !svc_is_inetd(svc)) {
|
||||||
(*restart_counter)++;
|
(*restart_counter)++;
|
||||||
/* TODO: There should be an async wait here
|
/* TODO: There should be an async wait here
|
||||||
* before moving back to READY */
|
* before moving back to READY */
|
||||||
|
|||||||
@@ -426,11 +426,20 @@ char *svc_status(svc_t *svc)
|
|||||||
return "crashing";
|
return "crashing";
|
||||||
case SVC_BLOCK_USER:
|
case SVC_BLOCK_USER:
|
||||||
return "blocked";
|
return "blocked";
|
||||||
|
case SVC_BLOCK_INETD_BUSY:
|
||||||
|
return "busy";
|
||||||
}
|
}
|
||||||
case SVC_DONE_STATE:
|
case SVC_DONE_STATE:
|
||||||
return "done";
|
return "done";
|
||||||
case SVC_STOPPING_STATE:
|
case SVC_STOPPING_STATE:
|
||||||
return "stopping";
|
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:
|
case SVC_WAITING_STATE:
|
||||||
return "waiting";
|
return "waiting";
|
||||||
case SVC_READY_STATE:
|
case SVC_READY_STATE:
|
||||||
|
|||||||
@@ -39,11 +39,12 @@ typedef enum {
|
|||||||
} svc_cmd_t;
|
} svc_cmd_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SVC_TYPE_FREE = 0, /* Free to allocate */
|
SVC_TYPE_FREE = 0, /* Free to allocate */
|
||||||
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
|
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
|
||||||
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
|
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
|
||||||
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||||
SVC_TYPE_INETD = 8 /* Classic inetd service */
|
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
||||||
|
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
||||||
} svc_type_t;
|
} svc_type_t;
|
||||||
|
|
||||||
#define SVC_TYPE_ANY (-1)
|
#define SVC_TYPE_ANY (-1)
|
||||||
@@ -62,6 +63,7 @@ typedef enum {
|
|||||||
SVC_BLOCK_MISSING,
|
SVC_BLOCK_MISSING,
|
||||||
SVC_BLOCK_CRASHING,
|
SVC_BLOCK_CRASHING,
|
||||||
SVC_BLOCK_USER,
|
SVC_BLOCK_USER,
|
||||||
|
SVC_BLOCK_INETD_BUSY,
|
||||||
} svc_block_t;
|
} svc_block_t;
|
||||||
|
|
||||||
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
#define FINIT_SHM_ID 0x494E4954 /* "INIT", see ascii(7) */
|
||||||
@@ -96,6 +98,7 @@ typedef struct svc {
|
|||||||
|
|
||||||
/* For inetd services */
|
/* For inetd services */
|
||||||
inetd_t inetd;
|
inetd_t inetd;
|
||||||
|
int stdin;
|
||||||
|
|
||||||
/* Identity */
|
/* Identity */
|
||||||
char username[MAX_USER_LEN];
|
char username[MAX_USER_LEN];
|
||||||
@@ -171,8 +174,9 @@ 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; }
|
||||||
const char *svc_dirtystr (svc_t *svc);
|
const char *svc_dirtystr (svc_t *svc);
|
||||||
|
|
||||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
||||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
||||||
|
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||||
|
|
||||||
#endif /* FINIT_SVC_H_ */
|
#endif /* FINIT_SVC_H_ */
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user