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:
Tobias Waldekranz committed 2016-01-15 10:07:15 +01:00
1 parent 0beb566e45
commit 6ece4b8fa3
6 files changed
+219 -176

No files matched your search

+55 -69
View File
@@ -112,7 +112,7 @@ static int is_norespawn(void)
*/
static int service_start(svc_t *svc)
{
int sd = 0;
int result = 0;
pid_t pid;
sigset_t nmask, omask;
@@ -137,48 +137,20 @@ static int service_start(svc_t *svc)
if (is_norespawn())
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 (svc_is_daemon(svc))
if (svc_is_daemon(svc) || svc_is_inetd(svc))
print_desc("Starting ", svc->desc);
else
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. */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
@@ -219,11 +191,10 @@ static int service_start(svc_t *svc)
args[i] = svc->args[i];
args[i] = NULL;
/* Redirect inetd socket to stdin for service */
if (svc_is_inetd(svc)) {
/* sd set previously */
dup2(sd, STDIN_FILENO);
close(sd);
/* Redirect inetd socket to stdin for connection */
if (svc_is_inetd_conn(svc)) {
dup2(svc->stdin, STDIN_FILENO);
close(svc->stdin);
dup2(STDIN_FILENO, STDOUT_FILENO);
dup2(STDIN_FILENO, STDERR_FILENO);
} else if (debug) {
@@ -254,7 +225,7 @@ static int service_start(svc_t *svc)
else
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) {
close(STDIN_FILENO);
close(STDOUT_FILENO);
@@ -266,21 +237,17 @@ static int service_start(svc_t *svc)
}
svc->pid = pid;
if (svc_is_inetd(svc)) {
if (svc->inetd.type == SOCK_STREAM)
close(sd);
} else {
int result = 0;
if (svc_is_inetd_conn(svc) && svc->inetd.type == SOCK_STREAM)
close(svc->stdin);
if (SVC_TYPE_RUN == svc->type) {
result = WEXITSTATUS(complete(svc->cmd, pid));
svc->pid = 0;
}
if (verbose)
print_result(result);
if (SVC_TYPE_RUN == svc->type) {
result = WEXITSTATUS(complete(svc->cmd, pid));
svc->pid = 0;
}
if (verbose)
print_result(result);
return 0;
}
@@ -298,6 +265,20 @@ static int service_stop(svc_t *svc)
if (!svc)
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) {
_d("Bad PID %d for %s, SIGTERM", svc->pid, svc->desc);
return 1;
@@ -371,12 +352,12 @@ static void service_reload_dynamic_finish(void)
svc_clean_dynamic(service_unregister);
_d("Starting services after reconf ...");
service_step_all(SVC_TYPE_SERVICE);
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
_d("Calling reconf hooks ...");
plugin_run_hooks(HOOK_SVC_RECONF);
service_step_all(SVC_TYPE_SERVICE);
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
_d("Reconfiguration done");
}
@@ -397,7 +378,7 @@ void service_reload_dynamic(void)
_d("Stopping services services not allowed after reconf ...");
in_dyn_teardown = 1;
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
* 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)) {
char *iface, *name = service;
svc->state = SVC_WAITING_STATE;
if (svc->inetd.cmd && plugin)
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)
{
if (svc->state != SVC_HALTED_STATE)
_e("Failed stopping %s, removing anyway from list of monitored services.", svc->cmd);
svc_del(svc);
}
@@ -752,11 +730,6 @@ void service_monitor(pid_t lost)
if (tty_respawn(lost))
return;
#ifndef INETD_DISABLED
if (inetd_respawn(lost))
return;
#endif
svc = svc_find_by_pid(lost);
if (!svc) {
_d("collected unknown PID %d", lost);
@@ -805,6 +778,15 @@ restart:
break;
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))
*state = SVC_HALTED_STATE;
break;
@@ -816,6 +798,7 @@ restart:
case SVC_TYPE_INETD:
*state = SVC_HALTED_STATE;
break;
case SVC_TYPE_INETD_CONN:
case SVC_TYPE_TASK:
case SVC_TYPE_RUN:
*state = SVC_DONE_STATE;
@@ -841,16 +824,19 @@ restart:
err = service_start(svc);
if (err) {
(*restart_counter)++;
break;
if (!svc_is_inetd_conn(svc))
break;
}
svc_mark_clean(svc);
switch (svc->type) {
case SVC_TYPE_INETD:
case SVC_TYPE_SERVICE:
*state = SVC_RUNNING_STATE;
break;
case SVC_TYPE_INETD:
case SVC_TYPE_INETD_CONN:
case SVC_TYPE_TASK:
case SVC_TYPE_RUN:
*state = SVC_STOPPING_STATE;
@@ -868,7 +854,7 @@ restart:
break;
}
if (!svc->pid) {
if (!svc->pid && !svc_is_inetd(svc)) {
(*restart_counter)++;
/* TODO: There should be an async wait here
* before moving back to READY */