1: /*
   2:  * Copyright (c) 1980,1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)init.c	5.6 (Berkeley) 5/26/86";
   9: #endif not lint
  10: 
  11: #include <signal.h>
  12: #include <sys/types.h>
  13: #include <utmp.h>
  14: #include <setjmp.h>
  15: #include <sys/reboot.h>
  16: #include <errno.h>
  17: #include <sys/file.h>
  18: #include <ttyent.h>
  19: #include <sys/syslog.h>
  20: #include <sys/stat.h>
  21: 
  22: #define LINSIZ  sizeof(wtmp.ut_line)
  23: #define CMDSIZ  200 /* max string length for getty or window command*/
  24: #define ALL p = itab; p ; p = p->next
  25: #define EVER    ;;
  26: #define SCPYN(a, b) strncpy(a, b, sizeof(a))
  27: #define SCMPN(a, b) strncmp(a, b, sizeof(a))
  28: 
  29: char    shell[] = "/bin/sh";
  30: char    minus[] = "-";
  31: char    runc[]  = "/etc/rc";
  32: char    utmpf[] = "/etc/utmp";
  33: char    wtmpf[] = "/usr/adm/wtmp";
  34: char    ctty[]  = "/dev/console";
  35: 
  36: struct utmp wtmp;
  37: struct  tab
  38: {
  39:     char    line[LINSIZ];
  40:     char    comn[CMDSIZ];
  41:     char    xflag;
  42:     int pid;
  43:     int wpid;       /* window system pid for SIGHUP	*/
  44:     char    wcmd[CMDSIZ];   /* command to start window system process */
  45:     time_t  gettytime;
  46:     int gettycnt;
  47:     time_t  windtime;
  48:     int windcnt;
  49:     struct  tab *next;
  50: } *itab;
  51: 
  52: int fi;
  53: int mergflag;
  54: char    tty[20];
  55: jmp_buf sjbuf, shutpass;
  56: time_t  time0;
  57: 
  58: int reset();
  59: int idle();
  60: char    *strcpy(), *strcat();
  61: long    lseek();
  62: 
  63: struct  sigvec rvec = { reset, sigmask(SIGHUP), 0 };
  64: 
  65: 
  66: #ifdef vax
  67: main()
  68: {
  69:     register int r11;       /* passed thru from boot */
  70: #else
  71: main(argc, argv)
  72:     char **argv;
  73: {
  74: #endif
  75:     int howto, oldhowto;
  76: 
  77:     time0 = time(0);
  78: #ifdef vax
  79:     howto = r11;
  80: #else
  81:     if (argc > 1 && argv[1][0] == '-') {
  82:         char *cp;
  83: 
  84:         howto = 0;
  85:         cp = &argv[1][1];
  86:         while (*cp) switch (*cp++) {
  87:         case 'a':
  88:             howto |= RB_ASKNAME;
  89:             break;
  90:         case 's':
  91:             howto |= RB_SINGLE;
  92:             break;
  93:         }
  94:     } else {
  95:         howto = RB_SINGLE;
  96:     }
  97: #endif
  98:     openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
  99:     sigvec(SIGTERM, &rvec, (struct sigvec *)0);
 100:     signal(SIGTSTP, idle);
 101:     signal(SIGSTOP, SIG_IGN);
 102:     signal(SIGTTIN, SIG_IGN);
 103:     signal(SIGTTOU, SIG_IGN);
 104:     (void) setjmp(sjbuf);
 105:     for (EVER) {
 106:         oldhowto = howto;
 107:         howto = RB_SINGLE;
 108:         if (setjmp(shutpass) == 0)
 109:             shutdown();
 110:         if (oldhowto & RB_SINGLE)
 111:             single();
 112:         if (runcom(oldhowto) == 0)
 113:             continue;
 114:         merge();
 115:         multiple();
 116:     }
 117: }
 118: 
 119: int shutreset();
 120: 
 121: shutdown()
 122: {
 123:     register i;
 124:     register struct tab *p, *p1;
 125: 
 126:     close(creat(utmpf, 0644));
 127:     signal(SIGHUP, SIG_IGN);
 128:     for (p = itab; p ; ) {
 129:         term(p);
 130:         p1 = p->next;
 131:         free(p);
 132:         p = p1;
 133:     }
 134:     itab = (struct tab *)0;
 135:     signal(SIGALRM, shutreset);
 136:     (void) kill(-1, SIGTERM);   /* one chance to catch it */
 137:     sleep(5);
 138:     alarm(30);
 139:     for (i = 0; i < 5; i++)
 140:         kill(-1, SIGKILL);
 141:     while (wait((int *)0) != -1)
 142:         ;
 143:     alarm(0);
 144:     shutend();
 145: }
 146: 
 147: char shutfailm[] = "WARNING: Something is hung (wont die); ps axl advised\n";
 148: 
 149: shutreset()
 150: {
 151:     int status;
 152: 
 153:     if (fork() == 0) {
 154:         int ct = open(ctty, 1);
 155:         write(ct, shutfailm, sizeof (shutfailm));
 156:         sleep(5);
 157:         exit(1);
 158:     }
 159:     sleep(5);
 160:     shutend();
 161:     longjmp(shutpass, 1);
 162: }
 163: 
 164: shutend()
 165: {
 166:     register i, f;
 167: 
 168:     acct(0);
 169:     signal(SIGALRM, SIG_DFL);
 170:     for (i = 0; i < 10; i++)
 171:         close(i);
 172:     f = open(wtmpf, O_WRONLY|O_APPEND);
 173:     if (f >= 0) {
 174:         SCPYN(wtmp.ut_line, "~");
 175:         SCPYN(wtmp.ut_name, "shutdown");
 176:         SCPYN(wtmp.ut_host, "");
 177:         time(&wtmp.ut_time);
 178:         write(f, (char *)&wtmp, sizeof(wtmp));
 179:         close(f);
 180:     }
 181:     return (1);
 182: }
 183: 
 184: single()
 185: {
 186:     register pid;
 187:     register xpid;
 188:     extern  errno;
 189: 
 190:     do {
 191:         pid = fork();
 192:         if (pid == 0) {
 193:             signal(SIGTERM, SIG_DFL);
 194:             signal(SIGHUP, SIG_DFL);
 195:             signal(SIGALRM, SIG_DFL);
 196:             signal(SIGTSTP, SIG_IGN);
 197:             (void) open(ctty, O_RDWR);
 198:             dup2(0, 1);
 199:             dup2(0, 2);
 200:             execl(shell, minus, (char *)0);
 201:             exit(0);
 202:         }
 203:         while ((xpid = wait((int *)0)) != pid)
 204:             if (xpid == -1 && errno == ECHILD)
 205:                 break;
 206:     } while (xpid == -1);
 207: }
 208: 
 209: runcom(oldhowto)
 210:     int oldhowto;
 211: {
 212:     register pid, f;
 213:     int status;
 214: 
 215:     pid = fork();
 216:     if (pid == 0) {
 217:         (void) open("/", O_RDONLY);
 218:         dup2(0, 1);
 219:         dup2(0, 2);
 220:         if (oldhowto & RB_SINGLE)
 221:             execl(shell, shell, runc, (char *)0);
 222:         else
 223:             execl(shell, shell, runc, "autoboot", (char *)0);
 224:         exit(1);
 225:     }
 226:     while (wait(&status) != pid)
 227:         ;
 228:     if (status)
 229:         return (0);
 230:     f = open(wtmpf, O_WRONLY|O_APPEND);
 231:     if (f >= 0) {
 232:         SCPYN(wtmp.ut_line, "~");
 233:         SCPYN(wtmp.ut_name, "reboot");
 234:         SCPYN(wtmp.ut_host, "");
 235:         if (time0) {
 236:             wtmp.ut_time = time0;
 237:             time0 = 0;
 238:         } else
 239:             time(&wtmp.ut_time);
 240:         write(f, (char *)&wtmp, sizeof(wtmp));
 241:         close(f);
 242:     }
 243:     return (1);
 244: }
 245: 
 246: struct  sigvec  mvec = { merge, sigmask(SIGTERM), 0 };
 247: /*
 248:  * Multi-user.  Listen for users leaving, SIGHUP's
 249:  * which indicate ttys has changed, and SIGTERM's which
 250:  * are used to shutdown the system.
 251:  */
 252: multiple()
 253: {
 254:     register struct tab *p;
 255:     register pid;
 256:     int omask;
 257: 
 258:     sigvec(SIGHUP, &mvec, (struct sigvec *)0);
 259:     for (EVER) {
 260:         pid = wait((int *)0);
 261:         if (pid == -1)
 262:             return;
 263:         omask = sigblock(SIGHUP);
 264:         for (ALL) {
 265:             /* must restart window system BEFORE emulator */
 266:             if (p->wpid == pid || p->wpid == -1)
 267:                 wstart(p);
 268:             if (p->pid == pid || p->pid == -1) {
 269:                 /* disown the window system */
 270:                 if (p->wpid)
 271:                     kill(p->wpid, SIGHUP);
 272:                 rmut(p);
 273:                 dfork(p);
 274:             }
 275:         }
 276:         sigsetmask(omask);
 277:     }
 278: }
 279: 
 280: /*
 281:  * Merge current contents of ttys file
 282:  * into in-core table of configured tty lines.
 283:  * Entered as signal handler for SIGHUP.
 284:  */
 285: #define FOUND   1
 286: #define CHANGE  2
 287: #define WCHANGE 4
 288: 
 289: merge()
 290: {
 291:     register struct tab *p;
 292:     register struct ttyent *t;
 293:     register struct tab *p1;
 294: 
 295:     for (ALL)
 296:         p->xflag = 0;
 297:     setttyent();
 298:     while (t = getttyent()) {
 299:         if ((t->ty_status & TTY_ON) == 0)
 300:             continue;
 301:         for (ALL) {
 302:             if (SCMPN(p->line, t->ty_name))
 303:                 continue;
 304:             p->xflag |= FOUND;
 305:             if (SCMPN(p->comn, t->ty_getty)) {
 306:                 p->xflag |= CHANGE;
 307:                 SCPYN(p->comn, t->ty_getty);
 308:             }
 309:             if (SCMPN(p->wcmd, t->ty_window)) {
 310:                 p->xflag |= WCHANGE|CHANGE;
 311:                 SCPYN(p->wcmd, t->ty_window);
 312:             }
 313:             goto contin1;
 314:         }
 315: 
 316:         /*
 317: 		 * Make space for a new one
 318: 		 */
 319:         p1 = (struct tab *)calloc(1, sizeof(*p1));
 320:         if (!p1) {
 321:             syslog(LOG_ERR, "no space for '%s' !?!", t->ty_name);
 322:             goto contin1;
 323:         }
 324:         /*
 325: 		 * Put new terminal at the end of the linked list.
 326: 		 */
 327:         if (itab) {
 328:             for (p = itab; p->next ; p = p->next)
 329:                 ;
 330:             p->next = p1;
 331:         } else
 332:             itab = p1;
 333: 
 334:         p = p1;
 335:         SCPYN(p->line, t->ty_name);
 336:         p->xflag |= FOUND|CHANGE;
 337:         SCPYN(p->comn, t->ty_getty);
 338:         if (strcmp(t->ty_window, "") != 0) {
 339:             p->xflag |= WCHANGE;
 340:             SCPYN(p->wcmd, t->ty_window);
 341:         }
 342:     contin1:
 343:         ;
 344:     }
 345:     endttyent();
 346:     p1 = (struct tab *)0;
 347:     for (ALL) {
 348:         if ((p->xflag&FOUND) == 0) {
 349:             term(p);
 350:             wterm(p);
 351:             if (p1)
 352:                 p1->next = p->next;
 353:             else
 354:                 itab = p->next;
 355:             free(p);
 356:             p = p1 ? p1 : itab;
 357:         } else {
 358:             /* window system should be started first */
 359:             if (p->xflag&WCHANGE) {
 360:                 wterm(p);
 361:                 wstart(p);
 362:             }
 363:             if (p->xflag&CHANGE) {
 364:                 term(p);
 365:                 dfork(p);
 366:             }
 367:         }
 368:         p1 = p;
 369:     }
 370: }
 371: 
 372: term(p)
 373:     register struct tab *p;
 374: {
 375: 
 376:     if (p->pid != 0) {
 377:         rmut(p);
 378:         kill(p->pid, SIGKILL);
 379:     }
 380:     p->pid = 0;
 381:     /* send SIGHUP to get rid of connections */
 382:     if (p->wpid > 0)
 383:         kill(p->wpid, SIGHUP);
 384: }
 385: 
 386: #include <sys/ioctl.h>
 387: 
 388: dfork(p)
 389:     struct tab *p;
 390: {
 391:     register pid;
 392:     time_t t;
 393:     int dowait = 0;
 394: 
 395:     time(&t);
 396:     p->gettycnt++;
 397:     if ((t - p->gettytime) >= 60) {
 398:         p->gettytime = t;
 399:         p->gettycnt = 1;
 400:     } else if (p->gettycnt >= 5) {
 401:         dowait = 1;
 402:         p->gettytime = t;
 403:         p->gettycnt = 1;
 404:     }
 405:     pid = fork();
 406:     if (pid == 0) {
 407:         signal(SIGTERM, SIG_DFL);
 408:         signal(SIGHUP, SIG_IGN);
 409:         sigsetmask(0);  /* since can be called from masked code */
 410:         if (dowait) {
 411:             syslog(LOG_ERR, "'%s %s' failing, sleeping", p->comn, p->line);
 412:             closelog();
 413:             sleep(30);
 414:         }
 415:         execit(p->comn, p->line);
 416:         exit(0);
 417:     }
 418:     p->pid = pid;
 419: }
 420: 
 421: /*
 422:  * Remove utmp entry.
 423:  */
 424: rmut(p)
 425:     register struct tab *p;
 426: {
 427:     register f;
 428:     int found = 0;
 429:     static unsigned utmpsize;
 430:     static struct utmp *utmp;
 431:     register struct utmp *u;
 432:     int nutmp;
 433:     struct stat statbf;
 434: 
 435:     f = open(utmpf, O_RDWR);
 436:     if (f >= 0) {
 437:         fstat(f, &statbf);
 438:         if (utmpsize < statbf.st_size) {
 439:             utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
 440:             if (utmp)
 441:                 utmp = (struct utmp *)realloc(utmp, utmpsize);
 442:             else
 443:                 utmp = (struct utmp *)malloc(utmpsize);
 444:             if (!utmp)
 445:                 syslog(LOG_ERR, "utmp malloc failed");
 446:         }
 447:         if (statbf.st_size && utmp) {
 448:             nutmp = read(f, utmp, statbf.st_size);
 449:             nutmp /= sizeof(struct utmp);
 450:             for (u = utmp ; u < &utmp[nutmp] ; u++) {
 451:                 if (SCMPN(u->ut_line, p->line) ||
 452:                     u->ut_name[0]==0)
 453:                     continue;
 454:                 lseek(f, ((long)u)-((long)utmp), L_SET);
 455:                 SCPYN(u->ut_name, "");
 456:                 SCPYN(u->ut_host, "");
 457:                 time(&u->ut_time);
 458:                 write(f, (char *)u, sizeof(*u));
 459:                 found++;
 460:             }
 461:         }
 462:         close(f);
 463:     }
 464:     if (found) {
 465:         f = open(wtmpf, O_WRONLY|O_APPEND);
 466:         if (f >= 0) {
 467:             SCPYN(wtmp.ut_line, p->line);
 468:             SCPYN(wtmp.ut_name, "");
 469:             SCPYN(wtmp.ut_host, "");
 470:             time(&wtmp.ut_time);
 471:             write(f, (char *)&wtmp, sizeof(wtmp));
 472:             close(f);
 473:         }
 474:         /*
 475: 		 * After a proper login force reset
 476: 		 * of error detection code in dfork.
 477: 		 */
 478:         p->gettytime = 0;
 479:         p->windtime = 0;
 480:     }
 481: }
 482: 
 483: reset()
 484: {
 485: 
 486:     longjmp(sjbuf, 1);
 487: }
 488: 
 489: jmp_buf idlebuf;
 490: 
 491: idlehup()
 492: {
 493: 
 494:     longjmp(idlebuf, 1);
 495: }
 496: 
 497: idle()
 498: {
 499:     register struct tab *p;
 500:     register pid;
 501: 
 502:     signal(SIGHUP, idlehup);
 503:     for (EVER) {
 504:         if (setjmp(idlebuf))
 505:             return;
 506:         pid = wait((int *) 0);
 507:         if (pid == -1) {
 508:             sigpause(0);
 509:             continue;
 510:         }
 511:         for (ALL) {
 512:             /* if window system dies, mark it for restart */
 513:             if (p->wpid == pid)
 514:                 p->wpid = -1;
 515:             if (p->pid == pid) {
 516:                 rmut(p);
 517:                 p->pid = -1;
 518:             }
 519:         }
 520:     }
 521: }
 522: 
 523: wterm(p)
 524:     register struct tab *p;
 525: {
 526:     if (p->wpid != 0) {
 527:         kill(p->wpid, SIGKILL);
 528:     }
 529:     p->wpid = 0;
 530: }
 531: 
 532: wstart(p)
 533:     register struct tab *p;
 534: {
 535:     register pid;
 536:     time_t t;
 537:     int dowait = 0;
 538: 
 539:     time(&t);
 540:     p->windcnt++;
 541:     if ((t - p->windtime) >= 60) {
 542:         p->windtime = t;
 543:         p->windcnt = 1;
 544:     } else if (p->windcnt >= 5) {
 545:         dowait = 1;
 546:         p->windtime = t;
 547:         p->windcnt = 1;
 548:     }
 549: 
 550:     pid = fork();
 551: 
 552:     if (pid == 0) {
 553:         signal(SIGTERM, SIG_DFL);
 554:         signal(SIGHUP,  SIG_IGN);
 555:         sigsetmask(0);  /* since can be called from masked code */
 556:         if (dowait) {
 557:             syslog(LOG_ERR, "'%s %s' failing, sleeping", p->wcmd, p->line);
 558:             closelog();
 559:             sleep(30);
 560:         }
 561:         execit(p->wcmd, p->line);
 562:         exit(0);
 563:     }
 564:     p->wpid = pid;
 565: }
 566: 
 567: #define NARGS   20  /* must be at least 4 */
 568: #define ARGLEN  512 /* total size for all the argument strings */
 569: 
 570: execit(s, arg)
 571:     char *s;
 572:     char *arg;  /* last argument on line */
 573: {
 574:     char *argv[NARGS], args[ARGLEN], *envp[1];
 575:     register char *sp = s;
 576:     register char *ap = args;
 577:     register char c;
 578:     register int i;
 579: 
 580:     /*
 581: 	 * First we have to set up the argument vector.
 582: 	 * "prog arg1 arg2" maps to exec("prog", "-", "arg1", "arg2").
 583: 	 */
 584:     for (i = 1; i < NARGS - 2; i++) {
 585:         argv[i] = ap;
 586:         for (EVER) {
 587:             if ((c = *sp++) == '\0' || ap >= &args[ARGLEN-1]) {
 588:                 *ap = '\0';
 589:                 goto done;
 590:             }
 591:             if (c == ' ') {
 592:                 *ap++ = '\0';
 593:                 while (*sp == ' ')
 594:                     sp++;
 595:                 if (*sp == '\0')
 596:                     goto done;
 597:                 break;
 598:             }
 599:             *ap++ = c;
 600:         }
 601:     }
 602: done:
 603:     argv[0] = argv[1];
 604:     argv[1] = "-";
 605:     argv[i+1] = arg;
 606:     argv[i+2] = 0;
 607:     envp[0] = 0;
 608:     execve(argv[0], &argv[1], envp);
 609:     /* report failure of exec */
 610:     syslog(LOG_ERR, "%s: %m", argv[0]);
 611:     closelog();
 612:     sleep(10);  /* prevent failures from eating machine */
 613: }

Defined functions

dfork defined in line 388; used 2 times
execit defined in line 570; used 2 times
idle defined in line 497; used 2 times
idlehup defined in line 491; used 1 times
main defined in line 71; never used
merge defined in line 289; used 2 times
multiple defined in line 252; used 1 times
reset defined in line 483; used 2 times
rmut defined in line 424; used 3 times
runcom defined in line 209; used 1 times
shutdown defined in line 121; used 6 times
shutend defined in line 164; used 2 times
shutreset defined in line 149; used 2 times
single defined in line 184; used 1 times
term defined in line 372; used 3 times
wstart defined in line 532; used 2 times
wterm defined in line 523; used 2 times

Defined variables

ctty defined in line 34; used 2 times
fi defined in line 52; never used
idlebuf defined in line 489; used 2 times
itab defined in line 50; used 8 times
mergflag defined in line 53; never used
minus defined in line 30; used 1 times
mvec defined in line 246; used 1 times
runc defined in line 31; used 2 times
rvec defined in line 63; used 1 times
  • in line 99
sccsid defined in line 8; never used
shell defined in line 29; used 5 times
shutfailm defined in line 147; used 2 times
  • in line 155(2)
shutpass defined in line 55; used 2 times
sjbuf defined in line 55; used 2 times
tty defined in line 54; never used
utmpf defined in line 32; used 2 times
wtmp defined in line 36; used 20 times
wtmpf defined in line 33; used 3 times

Defined struct's

tab defined in line 37; used 28 times

Defined macros

ALL defined in line 24; used 5 times
ARGLEN defined in line 568; used 2 times
CHANGE defined in line 286; used 4 times
CMDSIZ defined in line 23; used 2 times
EVER defined in line 25; used 4 times
FOUND defined in line 285; used 3 times
LINSIZ defined in line 22; used 1 times
  • in line 39
NARGS defined in line 567; used 2 times
SCMPN defined in line 27; used 4 times
SCPYN defined in line 26; used 16 times
WCHANGE defined in line 287; used 3 times
Last modified: 1986-05-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2304
Valid CSS Valid XHTML 1.0 Strict