/* * (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 */ /* 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; */ }