321 lines
8.4 KiB
Groff
321 lines
8.4 KiB
Groff
|
/*
|
||
|
* (c) 2005 Nico Schottelius (nico-linux at schottelius.org)
|
||
|
* run_svc
|
||
|
* part of cinit
|
||
|
*/
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <string.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <limits.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <errno.h>
|
||
|
#include <dirent.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <sys/un.h>
|
||
|
#include <stdio.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
|
||
|
#include "cinit.h"
|
||
|
|
||
|
/* Run a service */
|
||
|
/* We _MUST_ return!!! */
|
||
|
int run_svc(char *rpath)
|
||
|
{
|
||
|
int tmp=0, respawn = 0, status, fd, cnt, sid;
|
||
|
int p_com[2]; /* talk to respawnig watcher */
|
||
|
char pathbuf[PATH_MAX], pathtmp[PATH_MAX]; /* pathtmp = use-it-for-all bitch*/
|
||
|
char **nargv, *sbuf, *p; /* the argv for the executed process */
|
||
|
struct stat buf;
|
||
|
pid_t pid;
|
||
|
struct sockaddr_un addr;
|
||
|
|
||
|
D_PRINTF("starte run_svc");
|
||
|
D_PRINTF(rpath);
|
||
|
|
||
|
/******************* begin socket *********************/
|
||
|
/* close old socket connection */
|
||
|
D_PRINTF("beginne socket zeugs");
|
||
|
close(sock);
|
||
|
|
||
|
sock = socket(PF_UNIX,SOCK_STREAM,0);
|
||
|
if( sock == -1 ) {
|
||
|
perror("socket");
|
||
|
return 0;
|
||
|
}
|
||
|
memset(&addr,0,sizeof(addr));
|
||
|
strcpy(addr.sun_path, CINIT_SOCK);
|
||
|
|
||
|
addr.sun_family = AF_UNIX;
|
||
|
tmp = sizeof(addr);
|
||
|
|
||
|
if(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &tmp, sizeof(tmp)) == -1) {
|
||
|
perror("passcred");
|
||
|
return 0;
|
||
|
}
|
||
|
if(connect(sock,(struct sockaddr *)&addr,tmp) == -1) {
|
||
|
perror("connect");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/******************* end socket *********************/
|
||
|
|
||
|
sid = msg_start_svc(rpath); /* now we are temporary */
|
||
|
if(sid == -1) {
|
||
|
cerr("cinit returned start error",RT_CHLD_FAIL);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* check whether service exists */
|
||
|
if( stat(rpath,&buf) ) {
|
||
|
printf("Service does not exist %s\n",rpath);
|
||
|
msg_change_status(sid,ST_FAIL);
|
||
|
return 0;
|
||
|
} else if( ! S_ISDIR(buf.st_mode) ) {
|
||
|
printf("Service is not a dir (%s)!\n",rpath);
|
||
|
msg_change_status(sid,ST_FAIL);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* check, whether we should respawn */
|
||
|
strcpy(pathtmp,pathbuf);
|
||
|
strcat(pathtmp,"/");
|
||
|
strcat(pathtmp,C_RESPAWN); /* FIXME: check return values */
|
||
|
if( stat(pathtmp,&buf) == 0) {
|
||
|
D_PRINTF("Respawn, ja das werden wir tun");
|
||
|
respawn = 1;
|
||
|
}
|
||
|
|
||
|
/* if respawn, we have to create a pipe to talk with child */
|
||
|
if(respawn) {
|
||
|
if ( pipe(p_com) == -1 ) {
|
||
|
perror("pipe");
|
||
|
cerr("pipe failed",RT_PAR_FAIL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* clone */
|
||
|
pid = fork();
|
||
|
if( pid == -1 ) {
|
||
|
perror("fork");
|
||
|
cerr("fork failed",RT_CHLD_FAIL);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
_exit(0);
|
||
|
|
||
|
/* the following block handles parent situation */
|
||
|
|
||
|
if(pid > 0) { /* parent gets child's PID */
|
||
|
|
||
|
/*************** THIS BLOCK IS CRAP ******************/
|
||
|
|
||
|
/* FIXME: when respawing, we'll watch our child */
|
||
|
if(respawn) {
|
||
|
tmp = MSG_FAIL;
|
||
|
read(p_com[0],&tmp,1); /* FIXME: check return */
|
||
|
if(tmp == MSG_OK) {
|
||
|
D_PRINTF("kind sagte, wir respawnenen jetzt\n");
|
||
|
msg_change_status(sid,ST_RESPAWN); /* FIXME: search bei sid! */
|
||
|
return RT_PAR_OK;
|
||
|
} else { /* child failed */
|
||
|
printf("kind sagte, respawn kaputt\n");
|
||
|
msg_change_status(sid,ST_FAIL); /* FIXME: search bei sid! */
|
||
|
return RT_PAR_FAIL;
|
||
|
}
|
||
|
/* FIXME: MISSING:
|
||
|
- signal handling (stop respawing)
|
||
|
- waitpid() in while(1)
|
||
|
*/
|
||
|
_exit(0); /* FIXME !!! */
|
||
|
|
||
|
/*************** END THIS BLOCK IS CRAP ******************/
|
||
|
|
||
|
} else /* don't RESPAWN */ { /* execute only once */
|
||
|
D_PRINTF("Warte EINMAL auf mein Kind...");
|
||
|
waitpid(pid, &status, 0);
|
||
|
|
||
|
if(WIFEXITED(status)) {
|
||
|
add_mod_svc(rpath,ST_ONCE); /* FIXME: search bei sid! */
|
||
|
return RT_PAR_OK;
|
||
|
} else {
|
||
|
add_mod_svc(rpath,ST_FAIL); /* FIXME: search bei sid! */
|
||
|
return RT_PAR_FAIL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* done till here. PARENTS EXECUTION ENDED! */
|
||
|
|
||
|
|
||
|
/*********** CHILD EXECUTION HERE ***********/
|
||
|
do {
|
||
|
|
||
|
|
||
|
} while(respawn);
|
||
|
|
||
|
|
||
|
|
||
|
/* change to service dir */
|
||
|
if( chdir(rpath) == -1) {
|
||
|
/* FIXME: errno! */
|
||
|
printf("chdir(%s) failed!\n",rpath);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* getcwd returns the full service name */
|
||
|
if(getcwd(pathbuf,PATH_MAX) == NULL) return 0;
|
||
|
|
||
|
printf("absolut and current %s\n",pathbuf);
|
||
|
|
||
|
/* check for needs */
|
||
|
|
||
|
/* CHECKME: do we need absolute paths anymore? */
|
||
|
// strcpy(pathbuf,rpath);
|
||
|
// strcat(pathbuf,"/");
|
||
|
strcpy(pathtmp,C_NEEDS);
|
||
|
if( ! stat(pathtmp,&buf) ) {
|
||
|
printf("going for %s\n",pathtmp);
|
||
|
if( run_run_svcs(pathtmp) != RT_ALL_STARTED ) {
|
||
|
cerr("couldn't start all services I depend on\n",RT_CHLD_FAIL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* check for wants -> forked() ? */
|
||
|
// strcpy(pathbuf,rpath);
|
||
|
// strcat(pathbuf,"/");
|
||
|
strcpy(pathtmp,C_WANTS);
|
||
|
|
||
|
if( ! stat(pathtmp,&buf) ) {
|
||
|
printf("dir gibt es auch: %s\n", pathtmp);
|
||
|
run_run_svcs(pathtmp); /* don't care if everything went well */
|
||
|
}
|
||
|
|
||
|
/* everything is started, now start ourselves! */
|
||
|
|
||
|
/**** RETRIEVE REAL BINARY NAME ****/
|
||
|
/* .../run */
|
||
|
// strcpy(pathtmp,pathbuf);
|
||
|
// strcat(pathtmp,"/");
|
||
|
// strcpy(pathtmp,C_RUN); /* FIXME: check return values */
|
||
|
|
||
|
/* readlink retrieves real name, if "./run" is a symlink */
|
||
|
if ( (tmp = readlink(C_RUN,pathtmp,PATH_MAX) ) == -1) {
|
||
|
if (errno != EINVAL) cerr("readlinx failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
/* binary is not a link, copy that to argv0 */
|
||
|
sbuf = (char *) malloc( strlen(pathbuf) + strlen(C_RUN) + 1 );
|
||
|
if(sbuf == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
strcpy(sbuf,pathbuf);
|
||
|
strcat(pathtmp,"/");
|
||
|
strcat(pathtmp,C_RUN); /* FIXME: check return values */
|
||
|
|
||
|
} else { /* it's a link, copy to sbuf */
|
||
|
sbuf = (char *) malloc( tmp + 1 );
|
||
|
if(sbuf == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
strncpy(sbuf,pathtmp,tmp);
|
||
|
sbuf[tmp] = '\0';
|
||
|
}
|
||
|
printf("argv0: %s\n",sbuf);
|
||
|
|
||
|
/**** BUILD ARGV ****/
|
||
|
|
||
|
/* STOPPPPPPPED **********
|
||
|
broken code: malloc of char* missing! */
|
||
|
nargv = malloc( sizeof(char *) );
|
||
|
if(nargv == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
nargv[0] = sbuf;
|
||
|
|
||
|
/**** read params ****/
|
||
|
strcpy(pathtmp,pathbuf);
|
||
|
strcat(pathtmp,"/");
|
||
|
strcat(pathtmp,C_PARAMS);
|
||
|
if( !stat(pathtmp,&buf) ) {
|
||
|
fd = open(pathtmp,O_RDONLY);
|
||
|
if(fd == -1) cerr("open params failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
sbuf = NULL;
|
||
|
cnt = 0;
|
||
|
/* most likely one round */
|
||
|
while ( (tmp = read(fd,pathtmp,PATH_MAX-1) ) != 0 ) {
|
||
|
if(tmp == -1) cerr("read params failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
/* STRCHR >> tmp ???? */
|
||
|
/* terminate for strchr - do we really need that? */
|
||
|
pathtmp[PATH_MAX-1] = '\0';
|
||
|
|
||
|
sbuf = realloc(sbuf,cnt + tmp + 1);
|
||
|
if(sbuf == NULL) cerr("realloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
/* copy to temporary buffer */
|
||
|
strncpy(&sbuf[cnt],pathtmp,tmp);
|
||
|
|
||
|
cnt += tmp;
|
||
|
printf("Groesse: %d (%d)\n",tmp,cnt+1);
|
||
|
}
|
||
|
close(fd);
|
||
|
} /* if params */
|
||
|
sbuf[cnt] = '\0';
|
||
|
|
||
|
/* build argv, now really */
|
||
|
/* use the allocated buffer and replace \n with \0 ;-) */
|
||
|
|
||
|
cnt = 1;
|
||
|
// p = sbuf;
|
||
|
while ( *sbuf != '\0' ) {
|
||
|
p = strchr(sbuf,'\n'); /* set p to next \n */
|
||
|
|
||
|
nargv = realloc(nargv,(cnt+1) * sizeof(char *) );
|
||
|
if(nargv == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
// nargv[cnt] = malloc( sizeof(char *) );
|
||
|
// if(nargv[cnt] == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
nargv[cnt] = sbuf; /* beginning of argv[cnt] */
|
||
|
*p = '\0'; /* end argv[cnt] */
|
||
|
|
||
|
tmp = p - sbuf;
|
||
|
printf("argv[%d]: %s (%d)\n",cnt,nargv[cnt],tmp);
|
||
|
sbuf = p+1;
|
||
|
cnt++;
|
||
|
}
|
||
|
/* GNAAAAAAAAAA: correct???? */
|
||
|
/* close argv list */
|
||
|
nargv[cnt] = malloc( sizeof(char *) );
|
||
|
if(nargv[cnt] == NULL) cerr("malloc failed\n",RT_CHLD_FAIL);
|
||
|
|
||
|
nargv[cnt] = NULL;
|
||
|
|
||
|
// char *strchr(const char *s, int c);
|
||
|
/* end buffer */
|
||
|
|
||
|
/* get size of argv[n] */
|
||
|
|
||
|
/* run the fscking service */
|
||
|
strcpy(pathtmp,pathbuf);
|
||
|
strcat(pathtmp,"/");
|
||
|
strcat(pathtmp,C_RUN);
|
||
|
printf("Service starten: %s \n", pathtmp);
|
||
|
|
||
|
/* nothing to run, so it's finished */
|
||
|
if( stat(pathtmp,&buf) ) _exit(0);
|
||
|
|
||
|
//execl(pathtmp,pathtmp,"/bin/ls","-l", "/bin/echo");
|
||
|
execv(pathtmp,nargv);
|
||
|
|
||
|
// _exit(1);
|
||
|
|
||
|
/*
|
||
|
if(respawn)
|
||
|
tmp = 0;
|
||
|
execl();
|
||
|
return 1;
|
||
|
*/
|
||
|
}
|