import cinit from unix.schottelius.org

Signed-off-by: Nico Schottelius <nico@ikn.schottelius.org>
This commit is contained in:
Nico Schottelius 2009-09-16 12:53:45 +02:00
commit 423ba10303
13396 changed files with 269468 additions and 0 deletions

View file

@ -0,0 +1,2 @@
client/
These sources are used by the children which are spawned by cinit.

View file

@ -0,0 +1,24 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want to start a service
* part of cinit
*/
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
int begin_msg(char cmd)
{
sock = connect_sock(sock);
if( sock == -1 ) {
return 0;
}
if(write(sock,&cmd,sizeof(cmd)) == -1) {
perror(MSG_ERR_IO);
return 0;
}
return 1;
}

View file

@ -0,0 +1,37 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include "cinit.h"
/* open socket connection to cinit-serv and close original socket */
int connect_sock(int socke)
{
int nsock;
struct sockaddr_un addr;
close(socke);
nsock = socket(PF_UNIX,SOCK_STREAM,0);
if( nsock == -1 ) {
perror(MSG_SOCKET);
return -1;
}
socke = sizeof(addr);
memset(&addr,0,socke);
strcpy(addr.sun_path, CINIT_SOCK);
addr.sun_family = AF_UNIX;
if(connect(nsock,(struct sockaddr *)&addr,socke) == -1) {
return -1;
}
return nsock;
}

View file

@ -0,0 +1,265 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "cinit.h"
/***********************************************************************
* exec_svc: exec service abspath C_ON or C_OFF
*/
pid_t exec_svc(char *abspath, int on)
{
int tmp;
char *p, pathtmp[PATH_MAX];
char *sbuf = NULL, **nargv = NULL, **nenv = NULL;
int fd, argc;
struct stat buf;
D_PRINTF(abspath);
cpid = fork();
if( cpid == -1 ) {
perror(MSG_ERR_FORK);
return 0;
}
/***** PARENT ******/
if(cpid > 0) {
waitpid(cpid,&tmp,0);
if( WIFEXITED(tmp) ) {
if( ! WEXITSTATUS(tmp) ) {
return cpid;
}
}
LOG(abspath);
LOG(LOG_SVC_FAIL);
return 0;
}
/*********** CHILD EXECUTION ***********/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(on) {
strcat(pathtmp,C_ON);
} else {
strcat(pathtmp,C_OFF);
}
/* readlink retrieves real name, if it is a symlink */
if ( ( tmp = readlink(pathtmp,pathtmp,PATH_MAX) ) == -1) {
/* nothing there? fine, exit */
if(errno == ENOENT) {
_exit(0);
} else if (errno != EINVAL) {
perror(MSG_READLINK);
_exit(1);
}
/* restore original name, file is not a link */
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(on) {
strcat(pathtmp,C_ON);
} else {
strcat(pathtmp,C_OFF);
}
tmp = strlen(pathtmp);
} else {
/* add '\0', readlink forgets it */
pathtmp[tmp] = '\0';
}
++tmp; /* the byte to add to memory for \0;
neither readlink nor strlen count the \0 */
/********** build argv0 ********/
nargv = (char **) malloc( sizeof(char *) );
if(nargv == NULL) _exit(1);
*nargv = (char *) malloc( tmp );
if(*nargv == NULL) _exit(1);
strcpy(*nargv,pathtmp);
/********************** read params *********************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(on) {
strcat(pathtmp,C_ONARG);
} else {
strcat(pathtmp,C_OFFARG);
}
/* open params file */
if( !stat(pathtmp,&buf) ) {
fd = open(pathtmp,O_RDONLY);
if(fd == -1) {
perror(MSG_ERR_OPEN);
_exit(1);
}
argc = 0;
/* fill sbuf with content */
while ( (tmp = read(fd,pathtmp,PATH_MAX) ) != 0 ) {
if(tmp == -1) {
perror(MSG_ERR_READ);
_exit(1);
}
sbuf = realloc(sbuf,argc + tmp + 1);
strncpy(&sbuf[argc],pathtmp,tmp);
argc += tmp;
}
close(fd);
if(argc) {
sbuf[argc] = '\0'; /* terminate string */
}
} else {
sbuf = NULL;
}
/************** build string **************/
/* The idea is to reuse the allocated memory. We'll simply
* replace the \n with \0 and set a char* to it.
* We'll lose the last byte (the initial \0), but we
* don't care, as we die some seconds later with execv()
* oh, we'll only lose it, if the file is terminated by \n */
argc = 1; /* argv0 */
while( sbuf != NULL) {
p = strchr(sbuf,'\n');
nargv = realloc(nargv, sizeof(char *) * (argc + 1));
if(nargv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
/* set to the beginning */
nargv[argc] = sbuf;
/* if we found \n */
if(p != NULL) {
*p = '\0';
} else {
/* set to the end of sbuf, not to the \0, but one before */
p = sbuf + (strlen(sbuf)-1);
}
/* if next byte is 0, the end of string is found */
if( *(p+1) == '\0') {
sbuf = NULL;
} else {
sbuf = p+1;
}
++argc;
}
/************ close argv list **************/
nargv = realloc(nargv, sizeof(char *) * (argc + 1)); /* 1: NULL-pointer */
if(nargv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nargv[argc] = NULL; /* terminate argv list */
/********************** read environment *********************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
if(on) {
strcat(pathtmp,C_ONENV);
} else {
strcat(pathtmp,C_OFFENV);
}
argc = 0;
sbuf = NULL;
if( !stat(pathtmp,&buf) ) {
fd = open(pathtmp,O_RDONLY);
/* if a file exists, failing to open it is an error */
if(fd == -1) {
perror(MSG_ERR_OPEN);
_exit(1);
}
while ( (tmp = read(fd,pathtmp,PATH_MAX) ) != 0 ) {
if(tmp == -1) {
perror(MSG_ERR_READ);
_exit(1);
}
sbuf = realloc(sbuf,argc + tmp + 1);
strncpy(&sbuf[argc],pathtmp,tmp);
argc += tmp;
}
close(fd);
if(argc)
sbuf[argc] = '\0'; /* terminate string */
}
/************** build environment string **************/
argc = 0;
while( sbuf != NULL ) {
p = strchr(sbuf,'\n');
nenv = realloc(nenv, sizeof(char *) * (argc + 1));
if(nenv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nenv[argc] = sbuf;
/* if we found \n */
if(p != NULL) {
*p = '\0';
} else {
/* set to the end of sbuf, not to the \0, but one before */
p = sbuf + (strlen(sbuf)-1);
}
if( *(p+1) == '\0') {
sbuf = NULL;
} else {
sbuf = p+1;
}
++argc;
}
/************ close env list **************/
nenv = realloc(nenv, sizeof(char *) * (argc + 1));
if(nenv == NULL) {
LOG(MSG_ERR_ALLOC);
_exit(1);
}
nenv[argc] = NULL;
/****************** EXECUTE ********************/
execve(nargv[0],nargv,nenv);
/* we should never reach this block */
perror(MSG_ERR_EXECVE);
_exit(1);
}

View file

@ -0,0 +1,29 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want change the status of a service
* part of cinit
*/
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include "cinit.h"
int msg_change_status(char *svc, char status, pid_t pid)
{
D_PRINTF(svc);
if(!begin_msg(CMD_CHG_STATUS)) {
return 0;
}
if(!do_change_status(svc,&status,&pid,sock,ACT_CLIENT)) {
return 0;
}
if(!do_result(sock,NULL)) {
return 0;
}
return 1;
}

View file

@ -0,0 +1,32 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* tell cinit that I want to start a service
* part of cinit
*/
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
/* **********************************************************************
* action: 1=on, 0=off
*/
int msg_svc_on_off(char *svc, int action)
{
char cmd;
D_PRINTF(svc);
if(action) {
cmd = CMD_START_SVC;
} else {
cmd = CMD_STOP_SVC;
}
if(!begin_msg(cmd)) return 0;
if(!do_svc_name(sock,svc,ACT_CLIENT)) return 0;
return (int) do_result(sock,NULL);
}

View file

@ -0,0 +1,98 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "cinit.h"
/* run a service, gets (relative or absolute) path */
pid_t respawn_svc(char *abspath)
{
pid_t pid;
int tmp;
int pipefd[2];
struct sigaction sa;
char delay[PATH_MAX+1];
D_PRINTF(abspath);
if(pipe(pipefd) == -1) {
perror(MSG_ERR_PIPE);
return 0;
}
pid = fork();
if(pid == -1) {
perror(MSG_ERR_FORK);
return 0;
}
/******************** PARENT ********************/
if(pid > 0) {
/* if we read anything, our child succeded */
if( read(pipefd[0],&tmp,sizeof(tmp)) == -1) {
perror(MSG_ERR_IO);
return 0;
}
return pid; /* return watchers pid */
}
/****************** CHILD: Service watcher ********************/
sa.sa_handler = sig_terminate;
sigaction(SIGTERM,&sa,NULL); /* term = kill respawing process */
/* sigterm handler should kill first our watching pid, reset the
pid to 0 and then we'll kill ourselves */
tmp = 1;
if( write(pipefd[1],&tmp,sizeof(tmp)) == -1) {
perror(MSG_ERR_IO);
_exit(1);
}
/* try to read delay into sock */
strcpy(delay,abspath);
strcat(delay,SLASH);
strcat(delay,C_DELAY);
/* reuse sock to specify delay */
sock = -1;
tmp = open(delay,O_RDONLY);
if(tmp != -1) {
pipefd[0] = read(tmp,&delay[0],PATH_MAX);
if(pipefd[0] > 0 && pipefd[0] <= PATH_MAX) {
delay[pipefd[0]] = 0;
sock = atoi(delay);
}
close(tmp);
}
do {
/* exec_svc will set cpid accordingly */
if( ! exec_svc(abspath, 1) ) {
/* only sleep if the service exited itself and is not
killed by sig_term */
if(cpid != 0) {
sleep(SLEEP_SVC);
}
}
} while( cpid ); /* cpid is reset by sig_terminate() */
/* start off task */
exec_svc(abspath,0);
D_PRINTF("jetzt weg");
_exit(0);
}

View file

@ -0,0 +1,85 @@
/*
* cinit
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run services parallel
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "cinit.h"
/***********************************************************************
* parallel run forked() run_svc()
*/
int run_run_svcs(char *abspath)
{
DIR *d_tmp = NULL;
struct dirent *tdirent;
char pathbuf[PATH_MAX+1];
pid_t pids[MAX_DEPS];
int status, i, ret = 1;
D_PRINTF(abspath);
d_tmp = opendir(abspath);
/* if there is no such dir, we are finished */
if(d_tmp == NULL) {
return 1;
}
i = 0;
while( (tdirent = readdir(d_tmp) ) != NULL) {
/* ignore . and .. and everything with a . at the beginning */
if ( *(tdirent->d_name) == '.') continue;
if(i < MAX_DEPS) {
pids[i] = fork();
} else {
LOG(MSG_ERR_DEPS);
break;
}
if(pids[i] == -1) { /* err */
perror(MSG_ERR_FORK);
return 0;
}
if(pids[i] == 0) { /* child */
strcpy(pathbuf,abspath);
strcat(pathbuf,SLASH);
strcat(pathbuf,tdirent->d_name);
if ( run_svc(pathbuf) )
_exit(0);
else
_exit(1);
} else { /* parent */
++i;
}
}
closedir(d_tmp);
/* wait for pids */
--i; /* the index is one too much since last i++ */
while(i >= 0) {
waitpid(pids[i], &status, 0);
/* if anything failed, we failed */
if( ! WIFEXITED(status)) {
ret = 0;
} else {
if( WEXITSTATUS(status) ) {
ret = 0;
}
}
--i;
}
return ret;
}

View file

@ -0,0 +1,133 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* run_svc
* part of cinit
*/
/* headers are clean */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <time.h>
#include "cinit.h"
/***********************************************************************
* run_svc: run a service and beforeo all dependencies
*/
int run_svc(char *rpath)
{
int tmp;
pid_t pid;
char abspath[PATH_MAX], pathtmp[PATH_MAX]; /* pathtmp = use-it-for-all bitch*/
struct stat buf;
struct timespec ts;
D_PRINTF(rpath);
/******************* absolute PATH ***************/
/* get current working dir */
if(! (int) getcwd(pathtmp,PATH_MAX)) {
perror(pathtmp);
return 0;
}
/* change to rpath */
if(chdir(rpath) == -1) {
perror(rpath);
return 0;
}
/* get absolute name of rpath */
if(! (int) getcwd(abspath,PATH_MAX)) {
perror(abspath);
return 0;
}
/* change back */
if(chdir(pathtmp) == -1) {
perror(pathtmp);
return 0;
}
D_PRINTF(abspath);
/******************* REGISTER SERVICE ***************/
do {
tmp = msg_svc_on_off(abspath,1); /* check status */
switch(tmp) {
case 0: /* failed to communicate */
case ST_FAIL: /* somebody failed, we won't retry */
D_PRINTF("fail");
return 0;
break;
case ST_TMP: /* someone is working on it */
D_PRINTF("schon tmp");
ts.tv_sec = SLEEP_RERUN;
nanosleep(&ts,NULL);
break;
case ST_ONCE: /* somebody did our work */
case ST_RESPAWN: /* somebody does our work */
D_PRINTF("schon erledigt");
return 1;
break;
case ST_TMPNOW: /* we are on it! */
D_PRINTF("wir sind dran");
break;
}
} while(tmp != ST_TMPNOW);
/******************* BEGIN DEPENDENCIES ***************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_NEEDS);
D_PRINTF(pathtmp);
if( stat(pathtmp,&buf) == 0 ) {
if( ! run_run_svcs(pathtmp) ) {
LOG(abspath);
LOG(LOG_NEED_FAIL);
msg_change_status(abspath, ST_FAIL, 0);
return 0;
}
}
/********** WANTS ************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_WANTS);
D_PRINTF(pathtmp);
if( stat(pathtmp,&buf) == 0 ) {
run_run_svcs(pathtmp); /* don't care about what happens with the want svc */
}
/******************* execute services ***************/
strcpy(pathtmp,abspath);
strcat(pathtmp,SLASH);
strcat(pathtmp,C_RESPAWN);
if( stat(pathtmp,&buf) == 0) {
pid = respawn_svc(abspath);
tmp = ST_RESPAWN;
} else {
pid = exec_svc(abspath, 1);
tmp = ST_ONCE;
}
if(!pid) {
msg_change_status(abspath, ST_FAIL, pid);
return 0;
}
if(!msg_change_status(abspath, tmp, pid) ) {
return 0;
}
return 1;
}

View file

@ -0,0 +1,61 @@
/*
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
* terminate: terminate our watching pid
* part of cinit
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include "cinit.h"
/* **********************************************************************
* terminate the watching service
*/
void sig_terminate(int signal)
{
struct timespec ts;
int status;
D_PRINTF("ausssachalten");
if( kill(cpid,SIGTERM) == -1) {
if(errno != ESRCH) {
perror(MSG_TERMKILL);
}
}
/* variabel delay */
if(sock > 0) {
ts.tv_sec = sock;
} else {
ts.tv_sec = SLEEP_KILL_SVC; /* defined in conf/sleep_kill_svc */
}
/* if it still exists... */
if(kill(cpid,0) != -1) {
/* kill if there is a delay */
if(sock != 0) {
nanosleep(&ts,NULL);
status = kill(cpid,SIGKILL);
if( status == -1) {
if(errno != ESRCH) {
perror(MSG_TERMKILL);
}
}
}
}
/* remove zombie if killed, if delay is zero wait for it */
waitpid(cpid,&status,0);
/* reset the watching pid to zero (NOT THE WATCHER's!) */
cpid = 0;
D_PRINTF("muesste weg sein");
return;
}