#define _GNU_SOURCE #include #include #include #include #include #include #include #include #ifdef __linux__ #include #include #include #endif #include "init.h" #include int runlevel = BOOTRL; int changerl(const int newlevel); #define donothing() select(0,NULL,NULL,NULL,NULL) char *conlogind; char *rc; char *rcS; char *rcH; char *cad; int defrl; void sigchld(int n){ int serrno, pid, status; serrno = errno; for(;;){ pid = waitpid(WAIT_ANY,&status,WNOHANG); if(pid <= 0) break; } errno = serrno; } void sigterm(int n){ unlink(SOCK_PATH); signal (n, SIG_DFL); raise (n); } void sigint(int n){ int serrno = errno; system(cad); errno = serrno; } int chvt(int n){ if(ioctl(1,VT_ACTIVATE,n) < 0) return(0); if(ioctl(1,VT_WAITACTIVE,n) < 0) return(0); return(1); } void waitforevents(){ int sock; struct sockaddr_un name; fd_set set; int n; struct initcmd cmd; sock = socket(PF_LOCAL,SOCK_DGRAM,0); if(sock < 0){ perror("socket"); donothing(); } name.sun_family = AF_LOCAL; strncpy(name.sun_path,SOCK_PATH,sizeof(name.sun_path)); unlink(SOCK_PATH); if(bind(sock,(struct sockaddr*)&name,SUN_LEN(&name))<0){ perror("bind"); donothing(); } if(chmod(SOCK_PATH,0600) < 0){ perror("chmod"); unlink(SOCK_PATH); donothing(); } FD_ZERO(&set); for(;;){ FD_SET(sock,&set); n = select(FD_SETSIZE,&set,NULL,NULL,NULL); if(n > 0){ read(sock,&cmd,sizeof(cmd)); if(cmd.command == NEWLEVEL){ chvt(1); changerl(cmd.data); } else if(cmd.command == ASKLEVEL){ fprintf(stdout,"Current Runlevel: %i\n",runlevel); } } else if(n < 0 && errno != EINTR){ perror("select"); exit(EXIT_FAILURE); } } } int changerl(const int newlevel){ char *params[4]; pid_t pid; int status; char buf1[sizeof(int)*3], buf2[sizeof(int)*3]; if(runlevel == BOOTRL && newlevel == 0){ params[0] = rcS; params[1] = NULL; } else if( (newlevel == HALTRL || newlevel == REBOOTRL) ){ if(!changerl(0)) return(0); buf1[0] = newlevel == HALTRL ? 'H' : 'R'; buf1[1] = '\0'; params[0] = rcH; params[1] = buf1; params[2] = NULL; } else if(newlevel == runlevel){ return(1); } else if(newlevel >= 0 && runlevel >= 0){ snprintf(buf1,sizeof(buf1),"%i",runlevel); snprintf(buf2,sizeof(buf2),"%i",newlevel); params[0] = rc; params[1] = buf1; params[2] = buf2; params[3] = NULL; } else { fprintf(stderr,"init: Unsupported runlevel change\n"); return(0); } pid = fork(); if(pid < 0) return(0); if(pid==0){ execv(params[0],params); perror(params[0]); _exit(127); } waitpid(pid,&status,0); if(WEXITSTATUS(status)==EXIT_SUCCESS){ runlevel = newlevel; return(1); } else { fprintf(stderr, "init: Script: %s failed with exit code: %i\n",params[0],WEXITSTATUS(status)); return(0); } } void startconlogind(){ pid_t pid; int status; pid = fork(); if(pid < 0){ perror("fork"); return; } if(pid==0){ execl(conlogind,conlogind,NULL); perror(conlogind); pid = fork(); if(pid == 0){ execl("/bin/sh","/bin/sh",NULL); perror("/bin/sh"); _exit(127); } _exit(0); } waitpid(pid,&status,0); } int main(int argc, char* argv[]){ struct briconf c; int i; char *s; char *p; if(getpid() > 1){ argv[0] = "telinit"; execv("/sbin/telinit",argv); exit(1); } if(!parse_conf("/etc/init.conf",&c)) fprintf(stderr,"Cannot open init.conf\n"); rc = getval(&c,"rc","/etc/init.d/rc"); rcS = getval(&c,"rc","/etc/init.d/rc"); rcH = getval(&c,"rc","/etc/init.d/rc"); conlogind = getval(&c,"conlogind","/sbin/conlogind"); cad = getval(&c,"ctrlaltdel","shutdown -r now"); s = getval(&c,"default","0"); defrl = strtol(s,NULL,10); free(s); free_conf(&c); if(argc > 2){ if(strcasecmp(argv[2],"single")==0) { defrl = 0; } else { i = strtol(argv[2],&p,0); if(*p == '\0') defrl = i; } } for(i=1;i 0) changerl(defrl); startconlogind(); #ifdef __linux__ /* Enable CTRL+ALT+DEL */ signal(SIGINT,sigint); /* This means disable actually rebooting on CAD */ reboot(RB_DISABLE_CAD); #endif waitforevents(); return(EXIT_SUCCESS); /* Not Reached */ }