/* * (c) 2005 Nico Schottelius (nico-linux at schottelius.org) * run_svc * part of cinit */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinit.h" /* run a service, gets (relative or absolute) path */ int run_svc(char *rpath) { int tmp=0, respawn = 0, status, fd, cnt, sid; int p_com[2]; 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("Fehler"); _exit(1); } 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"); cerr("Does your OS not support SO_PASSCRED (man 7 socket)?",RT_PAR_FAIL); } if(connect(sock,(struct sockaddr *)&addr,tmp) == -1) { perror("connect"); _exit(1); } /******************* end socket *********************/ msg_start_svc(rpath); D_PRINTF("in runsvc"); _exit(0); /* check if service is already (beeing) started */ if ( (tmp = chk_svc_client(rpath) ) != ST_NO) return tmp; /* check whether service exists */ if( stat(rpath,&buf) ) { printf("Service does not exist %s\n",rpath); return ; } else if( ! S_ISDIR(buf.st_mode) ) { printf("Service is not a dir (%s)!\n",rpath); return 0; } /* get our own service ID */ sid = add_mod_svc(rpath,ST_TMP); /* check, whether we should respawn */ strcpy(pathtmp,pathbuf); strcat(pathtmp,"/"); strcat(pathtmp,C_RESPAWN); /* FIXME: check return values */ if( stat(pathtmp,&buf) == 0) respawn = 1; /* if respawn, we have to create a pipe to talk with child */ if(respawn) { if ( pipe(p_com) == -1 ) cerr("pipe failed",RT_PAR_FAIL); } /* fork at the beginning and before chdir */ pid = fork(); /* FIXME: pay attention: we are possibly also a fork()! */ if( pid == -1 ) cerr("fork failed",RT_PAR_FAIL); if(pid > 0) { /* parent gets child's PID */ if(respawn) { /* read the final byte from child */ read(p_com[0],&tmp,1); /* FIXME: check return */ if(tmp == ST_RESPAWN) { D_PRINTF("kind sagte, wir respawnenen jetzt\n"); add_mod_svc(rpath,ST_RESPAWN); /* FIXME: search bei sid! */ return RT_PAR_OK; } else { /* child failed */ printf("kind sagte, respawn kaputt\n"); add_mod_svc(rpath,ST_FAIL); /* FIXME: search bei sid! */ return RT_PAR_FAIL; } } else { /* execute once */ 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 ***********/ /* change to service dir */ if( chdir(rpath) == -1) { 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; */ }