mirror of
https://github.com/troglobit/finit.git
synced 2026-10-23 11:44:37 +00:00
Westermo service starter and supervisor, inspired by daemontools
finit.c:
o New service and shell_service stanzas for finit.conf
o Run service_startup() before /etc/finit.d/ hooks
o Run service_monitor() at end of startup
helpers.c:
o Several new functions:
- print_desc() displays a service starting up
- print_result() shows if service started OK or not
- start_process() is used by the services framework
svc.c:
Generic API for managing svc_t structures
ipc.o:
TIPC based framework for communicating with the service monitor.
E.g., to relay (re)configuration signals from a Web/CLI
front-end via finit to one or many setup daemons, and back.
services.c:
Service monitor framework
strlcpy.c:
Secure strncpy() replacement from OpenBSD under the free ISC License.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
c0356b5c7a
commit
d21dc2b477
14 files changed
+1352
-28
No files matched your search
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h> /* isdigit() */
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
@@ -78,7 +79,7 @@ void ifconfig(char *name, char *inet, char *mask, int up)
|
||||
return;
|
||||
|
||||
memset(&ifr, 0, sizeof (ifr));
|
||||
strncpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
strlcpy(ifr.ifr_name, name, IFNAMSIZ);
|
||||
a->sin_family = AF_INET;
|
||||
|
||||
if (up) {
|
||||
@@ -126,6 +127,95 @@ void copyfile(char *src, char *dst, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static int print_uptime(void)
|
||||
{
|
||||
#if defined(CONFIG_PRINTK_TIME)
|
||||
FILE * uptimefile;
|
||||
float num1, num2;
|
||||
char uptime_str[30];
|
||||
|
||||
if((uptimefile = fopen("/proc/uptime", "r")) == NULL)
|
||||
return 1;
|
||||
|
||||
fgets(uptime_str, 20, uptimefile);
|
||||
fclose(uptimefile);
|
||||
|
||||
sscanf(uptime_str, "%f %f", &num1, &num2);
|
||||
sprintf(uptime_str, "[ %.6f ]", num1);
|
||||
|
||||
write(STDERR_FILENO, uptime_str, strlen(uptime_str));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_descr(char *action, char *descr)
|
||||
{
|
||||
const char home[] = "\r\e[K";
|
||||
const char dots[] = " .....................................................................";
|
||||
|
||||
write(STDERR_FILENO, home, strlen(home));
|
||||
|
||||
print_uptime();
|
||||
|
||||
write(STDERR_FILENO, action, strlen(action));
|
||||
write(STDERR_FILENO, descr, strlen(descr));
|
||||
write(STDERR_FILENO, dots, 60 - strlen(descr) - strlen(action)); /* pad with dots. */
|
||||
}
|
||||
|
||||
int print_result(int fail)
|
||||
{
|
||||
if (fail)
|
||||
fprintf(stderr, " \e[7m[FAIL]\e[0m\n");
|
||||
else
|
||||
fprintf(stderr, " \e[1m[ OK ]\e[0m\n");
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int start_process(char *cmd, char *args[], int console)
|
||||
{
|
||||
pid_t pid;
|
||||
sigset_t nmask, omask;
|
||||
|
||||
if (sig_stopped())
|
||||
return 0;
|
||||
|
||||
/* Block SIGCHLD while forking. */
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||
pid = fork();
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
if (!pid) {
|
||||
int i;
|
||||
struct sigaction act;
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_handler = SIG_DFL;
|
||||
|
||||
sigemptyset(&nmask);
|
||||
sigaddset(&nmask, SIGCHLD);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
sigaction(i, &act, NULL);
|
||||
|
||||
if (console) {
|
||||
int fd = open (CONSOLE, O_WRONLY | O_APPEND);
|
||||
if (-1 != fd) {
|
||||
dup2(STDOUT_FILENO, fd);
|
||||
dup2(STDERR_FILENO, fd);
|
||||
}
|
||||
}
|
||||
|
||||
execv(cmd, args);
|
||||
exit(!console ? print_result(0) : 0);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_RUNPARTS
|
||||
|
||||
#define NUM_SCRIPTS 128 /* ought to be enough for anyone */
|
||||
@@ -251,7 +341,106 @@ void set_procname(char *args[], char *name)
|
||||
|
||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
memset(args[0], 0, len);
|
||||
strncpy(args[0], name, len);
|
||||
strlcpy(args[0], name, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_pidname - Find name of a process
|
||||
* @pid: PID of process to find.
|
||||
* @name: Pointer to buffer where to return process name, may be %NULL
|
||||
* @len: Length in bytes of @name buffer.
|
||||
*
|
||||
* If @name is %NULL, or @len is zero the function will return
|
||||
* a static string. This may be useful to one-off calls.
|
||||
*
|
||||
* Returns:
|
||||
* %NULL on error, otherwise a va
|
||||
*/
|
||||
char *get_pidname(pid_t pid, char *name, size_t len)
|
||||
{
|
||||
int ret = 1;
|
||||
FILE *fp;
|
||||
char path[32];
|
||||
static char line[64];
|
||||
|
||||
if (!name || len == 0)
|
||||
name = line;
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
if ((fp = fopen(path, "r")) != NULL) {
|
||||
if (fgets(line, sizeof (line), fp)) {
|
||||
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
|
||||
chomp(pname);
|
||||
strlcpy(name, pname, len);
|
||||
ret = 0; /* Found it! */
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* kill_procname - Send a signal to a process group by name.
|
||||
* @name: Name of process to send signal to.
|
||||
* @signo: Signal to send.
|
||||
*
|
||||
* Send a signal to a running process (group). This function searches
|
||||
* for a given process @name and sends a signal, @signo, to each
|
||||
* process ID matching that @name.
|
||||
*
|
||||
* Returns:
|
||||
* Number of signals sent, i.e. number of processes who have received the signal.
|
||||
*/
|
||||
int kill_procname (const char *name, int signo)
|
||||
{
|
||||
int result = 0;
|
||||
char path[32], line[64];
|
||||
FILE *fp;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (!dir || !name) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((entry = readdir (dir)) != NULL) {
|
||||
/* Skip non-process entries in /proc */
|
||||
if (!isdigit (*entry->d_name))
|
||||
continue;
|
||||
|
||||
snprintf (path, sizeof(path), "/proc/%s/status", entry->d_name);
|
||||
/* Skip non-readable files (protected?) */
|
||||
if ((fp = fopen (path, "r")) == NULL)
|
||||
continue;
|
||||
|
||||
if (fgets (line, sizeof (line), fp)) {
|
||||
char *pname = line + 6; /* Skip first part of line --> "Name:\t" */
|
||||
|
||||
if (strncmp(pname, name, strlen(pname) - 1) == 0) {
|
||||
int error = errno;
|
||||
|
||||
if (kill(atoi(entry->d_name), signo)) {
|
||||
ERROR("Failed signalling(%d) %s: %s!", signo, name, strerror(error));
|
||||
} else {
|
||||
result++; /* Track number of processes we deliver the signal to. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_hostname(char *hostname)
|
||||
|
||||
Reference in new issue
Block a user