mirror of
https://github.com/troglobit/libite.git
synced 2026-11-03 13:18:33 +00:00
runbg: new helper function inspired by the Infix project
The runbg() function is a delayed execvp() that has double-forked to the background (to not create zombies). It is useful for running commands in the background for APIs that need to return a reply, e.g. a NETCONF RPC to reboot the system. Compared to the original in Infix, this version double forks to reparent itself to PID 1 (init), closes all open files, including stdio. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
921afdecb4
commit
92bb0ca399
7 files changed
+135
-3
No files matched your search
+13
@@ -249,6 +249,19 @@ Generic Functions
|
|||||||
`delete`, it is now called `opt`. The APIs are 100% compatible if the
|
`delete`, it is now called `opt`. The APIs are 100% compatible if the
|
||||||
value `1` was used.
|
value `1` was used.
|
||||||
|
|
||||||
|
- `runbg(cmd, delay)`
|
||||||
|
|
||||||
|
Run a command in the background, after delay microseconds, essentially
|
||||||
|
a background `execvp()` with a delay. The function employs double-fork
|
||||||
|
to prevent zombies and closes all open files, including stdio.
|
||||||
|
|
||||||
|
```C
|
||||||
|
char *cmd[] = { "sh", "-c", "echo 'hej' >/tmp/foo", NULL};
|
||||||
|
|
||||||
|
runbg(cmd, 200000); /* Create /tmp/foo after 200 millisec */
|
||||||
|
/* Execution continues here immediately */
|
||||||
|
```
|
||||||
|
|
||||||
- `strmatch(str, list)`, `strnmatch(str, list, len)`
|
- `strmatch(str, list)`, `strnmatch(str, list, len)`
|
||||||
|
|
||||||
Find matching string in an array of strings. Returns index in array on
|
Find matching string in an array of strings. Returns index in array on
|
||||||
|
|||||||
+3
-3
@@ -11,12 +11,12 @@ libite_la_SOURCES = chomp.c copyfile.c \
|
|||||||
ifconfig.c lfile.c \
|
ifconfig.c lfile.c \
|
||||||
makepath.c procval.c progress.c \
|
makepath.c procval.c progress.c \
|
||||||
pidfile.c pidfilefn.c popenf.c \
|
pidfile.c pidfilefn.c popenf.c \
|
||||||
reallocarray.c rsync.c strtrim.c \
|
reallocarray.c rsync.c runbg.c \
|
||||||
strlcpy.c strlcat.c strtonum.c \
|
strlcpy.c strlcat.c strtonum.c \
|
||||||
strdupa.h strndupa.h strnlen.h \
|
strdupa.h strndupa.h strnlen.h \
|
||||||
strmatch.c systemf.c touchf.c \
|
strmatch.c systemf.c strtrim.c \
|
||||||
telnet.c tempfile.c truncatef.c \
|
telnet.c tempfile.c truncatef.c \
|
||||||
yorn.c which.c \
|
touchf.c yorn.c which.c \
|
||||||
lite.h strlite.h \
|
lite.h strlite.h \
|
||||||
queue.h tree.h
|
queue.h tree.h
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ void *reallocarray(void *optr, size_t nmemb, size_t size);
|
|||||||
void progress (int percent, int max_width);
|
void progress (int percent, int max_width);
|
||||||
void progress_simple(int percent);
|
void progress_simple(int percent);
|
||||||
|
|
||||||
|
int runbg (char *const cmd[], int delay);
|
||||||
int systemf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
int systemf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||||
|
|
||||||
sdbuf_t*telnet_open (int addr, short port);
|
sdbuf_t*telnet_open (int addr, short port);
|
||||||
|
|||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
/* Run a command in the background: fork() + usleep() + execvp()
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file runbg.c
|
||||||
|
* @author Joachim Wiberg
|
||||||
|
* @date 2023
|
||||||
|
* @copyright ISC License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run command in the background
|
||||||
|
* @param cmd NULL terminated list of command and optional arguments
|
||||||
|
* @param delay Microseconds after fork() to wait before calling cmd
|
||||||
|
*
|
||||||
|
* This function forks to run the given command @p cmd in the background.
|
||||||
|
* To ensure there are no lingering zombies the function actuall forks
|
||||||
|
* twice, and also calls setsid(), before it calls usleep() with the @p
|
||||||
|
* delay argument. The command @p cmd is handed over to execvp().
|
||||||
|
*
|
||||||
|
* Since it runs in the background it is not possible to get the return
|
||||||
|
* code of the command.
|
||||||
|
*
|
||||||
|
* @returns on successful (first) fork(), this function returns POSIX
|
||||||
|
* OK(0), otherwise -1 and @a errno is set to indicate the error.
|
||||||
|
*/
|
||||||
|
int runbg(char *const cmd[], int delay)
|
||||||
|
{
|
||||||
|
int pid = fork();
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!pid) {
|
||||||
|
int fd, maxfd;
|
||||||
|
|
||||||
|
if (setsid() == -1)
|
||||||
|
_exit(errno);
|
||||||
|
|
||||||
|
/* reparent to init */
|
||||||
|
pid = fork();
|
||||||
|
if (pid == -1)
|
||||||
|
_exit(errno);
|
||||||
|
if (pid > 0)
|
||||||
|
_exit(0);
|
||||||
|
|
||||||
|
maxfd = sysconf(_SC_OPEN_MAX);
|
||||||
|
if (maxfd == -1)
|
||||||
|
maxfd = 8192;
|
||||||
|
for (fd = 0; fd < maxfd; fd++)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
usleep(delay);
|
||||||
|
_exit(execvp(cmd[0], cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (waitpid(pid, &rc, 0) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (WIFEXITED(rc)) {
|
||||||
|
errno = WEXITSTATUS(rc);
|
||||||
|
if (errno)
|
||||||
|
rc = -1;
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
} else if (WIFSIGNALED(rc)) {
|
||||||
|
errno = EINTR;
|
||||||
|
rc = -1;
|
||||||
|
} else
|
||||||
|
rc = -1;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
/printhdr
|
/printhdr
|
||||||
/progress
|
/progress
|
||||||
/rsync
|
/rsync
|
||||||
|
/runbg
|
||||||
/str
|
/str
|
||||||
/strmatch
|
/strmatch
|
||||||
/systemf
|
/systemf
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ TESTS += pidfile
|
|||||||
TESTS += printhdr
|
TESTS += printhdr
|
||||||
TESTS += progress
|
TESTS += progress
|
||||||
TESTS += rsync
|
TESTS += rsync
|
||||||
|
TESTS += runbg
|
||||||
TESTS += str
|
TESTS += str
|
||||||
TESTS += strmatch
|
TESTS += strmatch
|
||||||
TESTS += systemf
|
TESTS += systemf
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include "check.h"
|
||||||
|
|
||||||
|
#define file "/tmp/runbg.txt"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
char *cmd[] = {
|
||||||
|
"sh", "-c", "echo 'hello world' > " file, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
erase(file);
|
||||||
|
test(runbg(cmd, 200000), "Calling runbg");
|
||||||
|
|
||||||
|
if (test(fexist(file), "Verifying %s does not yet exist", file))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
test(usleep(300000), "Waiting for runbg");
|
||||||
|
|
||||||
|
if (test(!fexist(file), "Verifying %s has been created", file))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user