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