00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <minix/type.h>
00017 #include <sys/types.h>
00018 #include <sys/wait.h>
00019 #include <sys/stat.h>
00020 #include <sys/svrctl.h>
00021 #include <ttyent.h>
00022 #include <errno.h>
00023 #include <fcntl.h>
00024 #include <limits.h>
00025 #include <signal.h>
00026 #include <string.h>
00027 #include <time.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <utmp.h>
00031
00032
00033 char *REBOOT_CMD[] = { "shutdown", "now", "CTRL-ALT-DEL", NULL };
00034
00035
00036 struct ttyent TT_REBOOT = { "console", "-", REBOOT_CMD, NULL };
00037
00038 char PATH_UTMP[] = "/etc/utmp";
00039 char PATH_WTMP[] = "/usr/adm/wtmp";
00040
00041 #define PIDSLOTS 32
00042
00043 struct slotent {
00044 int errct;
00045 pid_t pid;
00046 };
00047
00048 #define ERRCT_DISABLE 10
00049 #define NO_PID 0
00050
00051 struct slotent slots[PIDSLOTS];
00052
00053 int gothup = 0;
00054 int gotabrt = 0;
00055 int spawn = 1;
00056
00057 void tell(int fd, char *s);
00058 void report(int fd, char *label);
00059 void wtmp(int type, int linenr, char *line, pid_t pid);
00060 void startup(int linenr, struct ttyent *ttyp);
00061 int execute(char **cmd);
00062 void onhup(int sig);
00063 void onterm(int sig);
00064 void onabrt(int sig);
00065
00066 int main(void)
00067 {
00068 pid_t pid;
00069 int fd;
00070 int linenr;
00071 int check;
00072 int sn;
00073 struct slotent *slotp;
00074 struct ttyent *ttyp;
00075 struct sigaction sa;
00076 struct stat stb;
00077
00078 #define OPENFDS \
00079 if (fstat(0, &stb) < 0) { \
00080 \
00081 (void) open("/dev/null", O_RDONLY); \
00082 (void) open("/dev/log", O_WRONLY); \
00083 dup(1); \
00084 }
00085
00086 sigemptyset(&sa.sa_mask);
00087 sa.sa_flags = 0;
00088
00089
00090 sa.sa_handler = SIG_IGN;
00091 for (sn = 1; sn < _NSIG; sn++) {
00092 sigaction(sn, &sa, NULL);
00093 }
00094
00095
00096 sa.sa_handler = onhup;
00097 sigaction(SIGHUP, &sa, NULL);
00098
00099
00100 sa.sa_handler = onterm;
00101 sigaction(SIGTERM, &sa, NULL);
00102
00103
00104 sa.sa_handler = onabrt;
00105 sigaction(SIGABRT, &sa, NULL);
00106
00107
00108 if ((pid = fork()) != 0) {
00109
00110 while (wait(NULL) != pid) {
00111 if (gotabrt) reboot(RBT_HALT);
00112 }
00113 } else {
00114 #if ! SYS_GETKENV
00115 struct sysgetenv sysgetenv;
00116 #endif
00117 char bootopts[16];
00118 static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL, NULL };
00119 char **rcp = rc_command + 2;
00120
00121
00122 sysgetenv.key = "bootopts";
00123 sysgetenv.keylen = 8+1;
00124 sysgetenv.val = bootopts;
00125 sysgetenv.vallen = sizeof(bootopts);
00126 if (svrctl(MMGETPARAM, &sysgetenv) == 0) *rcp++ = bootopts;
00127 *rcp = "start";
00128
00129 execute(rc_command);
00130 report(2, "sh /etc/rc");
00131 _exit(1);
00132 }
00133
00134 OPENFDS;
00135
00136
00137 if ((fd = open(PATH_UTMP, O_WRONLY | O_TRUNC)) >= 0) close(fd);
00138
00139
00140 wtmp(BOOT_TIME, 0, NULL, 0);
00141
00142
00143
00144
00145
00146
00147
00148
00149 check = 1;
00150 while (1) {
00151 while ((pid = waitpid(-1, NULL, check ? WNOHANG : 0)) > 0) {
00152
00153 for (linenr = 0; linenr < PIDSLOTS; linenr++) {
00154 slotp = &slots[linenr];
00155 if (slotp->pid == pid) {
00156
00157 wtmp(DEAD_PROCESS, linenr, NULL, pid);
00158 slotp->pid = NO_PID;
00159 check = 1;
00160 }
00161 }
00162 }
00163
00164
00165 if (gothup) {
00166 gothup = 0;
00167 for (linenr = 0; linenr < PIDSLOTS; linenr++) {
00168 slots[linenr].errct = 0;
00169 }
00170 check = 1;
00171 }
00172
00173
00174 if (gotabrt) {
00175 gotabrt = 0;
00176 startup(0, &TT_REBOOT);
00177 }
00178
00179 if (spawn && check) {
00180
00181 for (linenr = 0; linenr < PIDSLOTS; linenr++) {
00182 slotp = &slots[linenr];
00183 if ((ttyp = getttyent()) == NULL) break;
00184
00185 if (ttyp->ty_getty != NULL
00186 && ttyp->ty_getty[0] != NULL
00187 && slotp->pid == NO_PID
00188 && slotp->errct < ERRCT_DISABLE)
00189 {
00190 startup(linenr, ttyp);
00191 }
00192 }
00193 endttyent();
00194 }
00195 check = 0;
00196 }
00197 }
00198
00199 void onhup(int sig)
00200 {
00201 gothup = 1;
00202 spawn = 1;
00203 }
00204
00205 void onterm(int sig)
00206 {
00207 spawn = 0;
00208 }
00209
00210 void onabrt(int sig)
00211 {
00212 static int count = 0;
00213
00214 if (++count == 2) reboot(RBT_HALT);
00215 gotabrt = 1;
00216 }
00217
00218 void startup(int linenr, struct ttyent *ttyp)
00219 {
00220
00221
00222 struct slotent *slotp;
00223 pid_t pid;
00224 int err[2];
00225 char line[32];
00226 int status;
00227
00228 slotp = &slots[linenr];
00229
00230
00231 if (pipe(err) < 0) err[0] = err[1] = -1;
00232
00233 if ((pid = fork()) == -1 ) {
00234 report(2, "fork()");
00235 sleep(10);
00236 return;
00237 }
00238
00239 if (pid == 0) {
00240
00241 close(err[0]);
00242 fcntl(err[1], F_SETFD, fcntl(err[1], F_GETFD) | FD_CLOEXEC);
00243
00244
00245 setsid();
00246
00247
00248 strcpy(line, "/dev/");
00249 strncat(line, ttyp->ty_name, sizeof(line) - 6);
00250
00251
00252 close(0);
00253 close(1);
00254 if (open(line, O_RDWR) < 0 || dup(0) < 0) {
00255 write(err[1], &errno, sizeof(errno));
00256 _exit(1);
00257 }
00258
00259 if (ttyp->ty_init != NULL && ttyp->ty_init[0] != NULL) {
00260
00261
00262 if ((pid = fork()) == -1) {
00263 report(2, "fork()");
00264 errno= 0;
00265 write(err[1], &errno, sizeof(errno));
00266 _exit(1);
00267 }
00268
00269 if (pid == 0) {
00270 alarm(10);
00271 execute(ttyp->ty_init);
00272 report(2, ttyp->ty_init[0]);
00273 _exit(1);
00274 }
00275
00276 while (waitpid(pid, &status, 0) != pid) {}
00277 if (status != 0) {
00278 tell(2, "init: ");
00279 tell(2, ttyp->ty_name);
00280 tell(2, ": ");
00281 tell(2, ttyp->ty_init[0]);
00282 tell(2, ": bad exit status\n");
00283 errno = 0;
00284 write(err[1], &errno, sizeof(errno));
00285 _exit(1);
00286 }
00287 }
00288
00289
00290 dup2(0, 2);
00291
00292
00293 execute(ttyp->ty_getty);
00294
00295
00296 fcntl(2, F_SETFL, fcntl(2, F_GETFL) | O_NONBLOCK);
00297 if (linenr != 0) report(2, ttyp->ty_getty[0]);
00298 write(err[1], &errno, sizeof(errno));
00299 _exit(1);
00300 }
00301
00302
00303 if (ttyp != &TT_REBOOT) slotp->pid = pid;
00304
00305 close(err[1]);
00306 if (read(err[0], &errno, sizeof(errno)) != 0) {
00307
00308
00309 switch (errno) {
00310 case ENOENT:
00311 case ENODEV:
00312 case ENXIO:
00313
00314 slotp->errct = ERRCT_DISABLE;
00315 close(err[0]);
00316 return;
00317 case 0:
00318
00319 break;
00320 default:
00321
00322 report(2, ttyp->ty_name);
00323 }
00324 close(err[0]);
00325
00326 if (++slotp->errct >= ERRCT_DISABLE) {
00327 tell(2, "init: ");
00328 tell(2, ttyp->ty_name);
00329 tell(2, ": excessive errors, shutting down\n");
00330 } else {
00331 sleep(5);
00332 }
00333 return;
00334 }
00335 close(err[0]);
00336
00337 if (ttyp != &TT_REBOOT) wtmp(LOGIN_PROCESS, linenr, ttyp->ty_name, pid);
00338 slotp->errct = 0;
00339 }
00340
00341 int execute(char **cmd)
00342 {
00343
00344
00345 static char *nullenv[] = { NULL };
00346 char command[128];
00347 char *path[] = { "/sbin", "/bin", "/usr/sbin", "/usr/bin" };
00348 int i;
00349
00350 if (cmd[0][0] == '/') {
00351
00352 return execve(cmd[0], cmd, nullenv);
00353 }
00354
00355
00356 for (i = 0; i < 4; i++) {
00357 if (strlen(path[i]) + 1 + strlen(cmd[0]) + 1 > sizeof(command)) {
00358 errno= ENAMETOOLONG;
00359 return -1;
00360 }
00361 strcpy(command, path[i]);
00362 strcat(command, "/");
00363 strcat(command, cmd[0]);
00364 execve(command, cmd, nullenv);
00365 if (errno != ENOENT) break;
00366 }
00367 return -1;
00368 }
00369
00370 void wtmp(type, linenr, line, pid)
00371 int type;
00372 int linenr;
00373 char *line;
00374 pid_t pid;
00375 {
00376
00377
00378 struct utmp utmp;
00379 int fd;
00380
00381
00382 memset((void *) &utmp, 0, sizeof(utmp));
00383
00384
00385 switch (type) {
00386 case BOOT_TIME:
00387
00388 strcpy(utmp.ut_name, "reboot");
00389 strcpy(utmp.ut_line, "~");
00390 break;
00391
00392 case LOGIN_PROCESS:
00393
00394 strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
00395 break;
00396
00397 case DEAD_PROCESS:
00398
00399
00400
00401 if ((fd = open(PATH_UTMP, O_RDONLY)) < 0) {
00402 if (errno != ENOENT) report(2, PATH_UTMP);
00403 return;
00404 }
00405 if (lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
00406 || read(fd, &utmp, sizeof(utmp)) == -1
00407 ) {
00408 report(2, PATH_UTMP);
00409 close(fd);
00410 return;
00411 }
00412 close(fd);
00413 if (utmp.ut_type != USER_PROCESS) return;
00414 strncpy(utmp.ut_name, "", sizeof(utmp.ut_name));
00415 break;
00416 }
00417
00418
00419 utmp.ut_pid = pid;
00420 utmp.ut_type = type;
00421 utmp.ut_time = time((time_t *) 0);
00422
00423 switch (type) {
00424 case LOGIN_PROCESS:
00425 case DEAD_PROCESS:
00426
00427 if ((fd = open(PATH_UTMP, O_WRONLY)) < 0
00428 || lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
00429 || write(fd, &utmp, sizeof(utmp)) == -1
00430 ) {
00431 if (errno != ENOENT) report(2, PATH_UTMP);
00432 }
00433 if (fd != -1) close(fd);
00434 break;
00435 }
00436
00437 switch (type) {
00438 case BOOT_TIME:
00439 case DEAD_PROCESS:
00440
00441 if ((fd = open(PATH_WTMP, O_WRONLY | O_APPEND)) < 0
00442 || write(fd, &utmp, sizeof(utmp)) == -1
00443 ) {
00444 if (errno != ENOENT) report(2, PATH_WTMP);
00445 }
00446 if (fd != -1) close(fd);
00447 break;
00448 }
00449 }
00450
00451 void tell(fd, s)
00452 int fd;
00453 char *s;
00454 {
00455 write(fd, s, strlen(s));
00456 }
00457
00458 void report(fd, label)
00459 int fd;
00460 char *label;
00461 {
00462 int err = errno;
00463
00464 tell(fd, "init: ");
00465 tell(fd, label);
00466 tell(fd, ": ");
00467 tell(fd, strerror(err));
00468 tell(fd, "\n");
00469 errno= err;
00470 }