]> Zhao Yanbai Git Server - minix.git/commitdiff
big <utmp.h>-inspired netbsd switch
authorBen Gras <ben@minix3.org>
Mon, 9 Sep 2013 13:20:18 +0000 (13:20 +0000)
committerLionel Sambuc <lionel@minix3.org>
Sat, 1 Mar 2014 08:05:02 +0000 (09:05 +0100)
import/switch of:
init, getty, reboot, halt, shutdown, wall, last

changes:
. change reboot() call to netbsd prototype and args
. allows pristine <utmp.h>
. use clean <sys/reboot.h> instead of <minix/reboot.h>
. implement TIOCSCTTY for use by getty so getty can get
  controlling terminal from init's child(ren)
. allow NULL envp for exec

Change-Id: I5ca02cb4230857140c08794bbfeba7df982c58a3

93 files changed:
commands/Makefile
commands/getty/Makefile [deleted file]
commands/getty/getty.c [deleted file]
commands/last/Makefile [deleted file]
commands/last/last.c [deleted file]
commands/poweroff/Makefile [deleted file]
commands/poweroff/poweroff.sh [deleted file]
commands/reboot/Makefile [deleted file]
commands/reboot/README [deleted file]
commands/reboot/halt.c [deleted file]
commands/reboot/log.c [deleted file]
commands/reboot/sh_wall.c [deleted file]
commands/reboot/shutdown.c [deleted file]
commands/reboot/wtmp.h [deleted file]
commands/telnetd/Makefile
commands/telnetd/main.c
commands/telnetd/wtmp.c [deleted file]
distrib/sets/lists/minix/mi
drivers/tps65217/tps65217.c
drivers/tty/arch/i386/keyboard.c
drivers/tty/tty.c
etc/Makefile
etc/gettytab [new file with mode: 0644]
etc/rc
etc/rc.shutdown [new file with mode: 0644]
etc/system.conf
etc/ttys
etc/usr/rc
include/minix/Makefile
include/minix/reboot.h [deleted file]
include/minix/termios.h
include/sys/ioc_tty.h
include/unistd.h
include/utmp.h
kernel/arch/earm/arch_reset.c
kernel/arch/earm/pre_init.c
kernel/arch/i386/arch_reset.c
kernel/arch/i386/pre_init.c
kernel/main.c
lib/libc/gen/utmpx.c
lib/libc/sys-minix/reboot.c
lib/libc/sys-minix/stack_utils.c
lib/libc/sys/Makefile.inc
lib/libminc/Makefile
lib/libutil/Makefile
libexec/Makefile
libexec/getty/Makefile [new file with mode: 0644]
libexec/getty/extern.h [new file with mode: 0644]
libexec/getty/getty.8 [new file with mode: 0644]
libexec/getty/gettytab.5 [new file with mode: 0644]
libexec/getty/gettytab.h [new file with mode: 0644]
libexec/getty/init.c [new file with mode: 0644]
libexec/getty/main.c [new file with mode: 0644]
libexec/getty/pathnames.h [new file with mode: 0644]
libexec/getty/subr.c [new file with mode: 0644]
libexec/getty/ttys.5 [new file with mode: 0644]
man/man1/Makefile
man/man1/last.1 [deleted file]
man/man2/Makefile
man/man2/reboot.2 [deleted file]
man/man8/Makefile
man/man8/poweroff.8 [deleted file]
man/man8/reboot.8 [deleted file]
releasetools/Makefile
releasetools/arm_sdimage.sh
releasetools/nbsd_ports
sbin/Makefile
sbin/init/Makefile [new file with mode: 0644]
sbin/init/NOTES [new file with mode: 0644]
sbin/init/init.8 [new file with mode: 0644]
sbin/init/init.c [new file with mode: 0644]
sbin/init/pathnames.h [new file with mode: 0644]
sbin/reboot/Makefile [new file with mode: 0644]
sbin/reboot/reboot.8 [new file with mode: 0644]
sbin/reboot/reboot.c [new file with mode: 0644]
sbin/shutdown/Makefile [new file with mode: 0644]
sbin/shutdown/pathnames.h [new file with mode: 0644]
sbin/shutdown/shutdown.8 [new file with mode: 0644]
sbin/shutdown/shutdown.c [new file with mode: 0644]
servers/Makefile
servers/init/Makefile [deleted file]
servers/init/init.c [deleted file]
servers/mfs/super.c
servers/pm/misc.c
servers/vfs/device.c
usr.bin/Makefile
usr.bin/last/Makefile [new file with mode: 0644]
usr.bin/last/last.1 [new file with mode: 0644]
usr.bin/last/last.c [new file with mode: 0644]
usr.bin/last/want.c [new file with mode: 0644]
usr.bin/wall/Makefile [new file with mode: 0644]
usr.bin/wall/wall.1 [new file with mode: 0644]
usr.bin/wall/wall.c [new file with mode: 0644]

index d4e0e36af8aa4330a2bbbb304c48884c6a36a8f8..58a17cc563cde0ee1e928e2df9c9603cdb56f938 100644 (file)
@@ -10,18 +10,18 @@ SUBDIR=     add_route arp ash at backup btrace \
        dhrystone diff diskctl \
        eject factor fbdctl \
        find fix format fortune fsck.mfs \
-       gcov-pull getty grep host \
+       gcov-pull grep host \
        hostaddr ifconfig ifdef \
-       intr ipcrm ipcs irdpd isoread last \
+       intr ipcrm ipcs irdpd isoread \
        less loadkeys loadramdisk logger look lp \
        lpd lspci mail MAKEDEV \
        mined \
        mount mt netconf \
        nonamed patch \
-       ping postinstall poweroff prep printroot \
+       ping postinstall prep printroot \
        profile progressbar pr_routes ps pwdauth \
        ramdisk rarpd rawspeed rcp readclock \
-       reboot remsync rget rlogin \
+       remsync rget rlogin \
        rotate rsh rshd service setup shar \
        sleep slip spell sprofalyze sprofdiff srccrc \
        stty svclog svrctl swifi synctree sysenv \
diff --git a/commands/getty/Makefile b/commands/getty/Makefile
deleted file mode 100644 (file)
index 6425275..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-PROG=  getty
-BINDIR=        /bin
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/commands/getty/getty.c b/commands/getty/getty.c
deleted file mode 100644 (file)
index 9e35fb2..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* getty - get tty speed                       Author: Fred van Kempen */
-
-/*
- * GETTY  -     Initialize and serve a login-terminal for INIT.
- *             Also, select the correct speed. The STTY() code
- *             was taken from stty(1).c; which was written by
- *             Andrew S. Tanenbaum.
- *
- * Usage:      getty [speed]
- *
- * Version:    3.4     02/17/90
- *
- * Author:     F. van Kempen, MicroWalt Corporation
- *
- * Modifications:
- *             All the good stuff removed to get a minimal getty, because
- *             many modems don't like all that fancy speed detection stuff.
- *             03/03/91        Kees J. Bot (kjb@cs.vu.nl)
- *
- *             Uname(), termios.  More nonsense removed.  (The result has
- *             only 10% of the original functionality, but a 10x chance of
- *             working.)
- *             12/12/92        Kees J. Bot
- *
- *             Customizable login banner.
- *             11/13/95        Kees J. Bot
- *
- *             Suspend/resume signals removed.
- *             2001-04-04      Kees J. Bot
- *
- *             Removed unused custom banner and returned speed option
- *             functionality (by simply calling stty).
- *             2012-09-24      T. Veerman
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/utsname.h>
-#include <stdio.h>
-
-char LOGIN[] =         "/usr/bin/login";
-char SHELL[] =         "/bin/sh";
-
-char *tty_name;                        /* name of the line */
-
-/* Crude indication of a tty being physically secure: */
-#define securetty(dev)         ((unsigned) ((dev) - 0x0400) < (unsigned) 8)
-
-void std_out(const char *s)
-{
-  write(1, s, strlen(s));
-}
-
-/* Read one character from stdin.
- */
-int readch(void)
-{
-  int st;
-  char ch1;
-
-  /* read character from TTY */
-  st = read(0, &ch1, 1);
-  if (st == 0) {
-       std_out("\n");
-       exit(0);
-  }
-  if (st < 0) {
-       std_out("getty: ");
-       std_out(tty_name);
-       std_out(": read error\n");
-       exit(1);
-  }
-  return(ch1 & 0xFF);
-}
-
-
-/* Handle the process of a GETTY.
- */
-void do_getty(char *name, size_t len, char **args, const char *ttyname)
-{
-  register char *np, *s, *s0;
-  int ch;
-  struct utsname utsname;
-  char **banner, *t;
-  static char *def_banner[] = { "%s/%p (%t)\n\n%n login: ", 0 };
-
-  /* Clean up tty name. */
-  if((t = strrchr(ttyname, '/'))) ttyname = t + 1;
-
-  if (args[0] != NULL) {
-       char cmd[5+6+1]; /* "stty " + "115200" + '\0' */
-       int speed;
-       speed = atoi(args[0]);
-       snprintf(cmd, sizeof(cmd), "stty %d\n", speed);
-       system(cmd);
-  }
-
-  /* Display prompt. */
-  ch = ' ';
-  *name = '\0';
-  while (ch != '\n') {
-       /* Get data about this machine. */
-       uname(&utsname);
-
-       /* Print the banner. */
-       for (banner = def_banner; *banner != NULL; banner++) {
-               std_out(banner == args ? "\n" : " ");
-               s0 = *banner;
-               for (s = *banner; *s != 0; s++) {
-                       if (*s == '\\') {
-                               write(1, s0, s-s0);
-                               s0 = s+2;
-                               switch (*++s) {
-                               case 'n':  std_out("\n"); break;
-                               case 's':  std_out(" "); break;
-                               case 't':  std_out("\t"); break;
-                               case 0:    goto leave;
-                               default:   s0 = s;
-                               }
-                       } else
-                       if (*s == '%') {
-                               write(1, s0, s-s0);
-                               s0 = s+2;
-                               switch (*++s) {
-                               case 's':  std_out(utsname.sysname); break;
-                               case 'n':  std_out(utsname.nodename); break;
-                               case 'r':  std_out(utsname.release); break;
-                               case 'v':  std_out(utsname.version); break;
-                               case 'm':  std_out(utsname.machine); break;
-                               case 'p':  std_out(utsname.arch); break;
-                               case 't':  std_out(ttyname); break;
-#if __minix_vmd
-                               case 'k':  std_out(utsname.kernel); break;
-                               case 'h':  std_out(utsname.hostname); break;
-                               case 'b':  std_out(utsname.bus); break;
-#endif
-                               case 0:    goto leave;
-                               default:   s0 = s-1;
-                               }
-                       }
-               }
-           leave:
-               write(1, s0, s-s0);
-       }
-
-       np = name;
-       while ((ch = readch()) != '\n') {
-               if (np < name + len) *np++ = ch;
-       }
-       *np = '\0';
-       if (*name == '\0') ch = ' ';    /* blank line typed! */
-  }
-}
-
-
-/* Execute the login(1) command with the current
- * username as its argument. It will reply to the
- * calling user by typing "Password: "...
- */
-void do_login(char *name)
-{ 
-  struct stat st;
-
-  execl(LOGIN, LOGIN, name, (char *) NULL);
-  /* Failed to exec login.  Impossible, but true.  Try a shell, but only if
-   * the terminal is more or less secure, because it will be a root shell.
-   */
-  std_out("getty: can't exec ");
-  std_out(LOGIN);
-  std_out("\n");
-  if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode) && securetty(st.st_rdev)) {
-       execl(SHELL, SHELL, (char *) NULL);
-  }
-}
-
-
-int main(int argc, char **argv)
-{
-  char name[30];
-  struct sigaction sa;
-
-  /* Don't let QUIT dump core. */
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  sa.sa_handler = exit;
-  sigaction(SIGQUIT, &sa, NULL);
-
-  tty_name = ttyname(0);
-  if (tty_name == NULL) {
-       std_out("getty: tty name unknown\n");
-       pause();
-       return(1);
-  }
-
-  chown(tty_name, 0, 0);       /* set owner of TTY to root */
-  chmod(tty_name, 0600);       /* mode to max secure */
-
-  do_getty(name, sizeof(name), argv+1, tty_name);      /* handle getty() */
-  name[29] = '\0';             /* make sure the name fits! */
-
-  do_login(name);              /* and call login(1) if OK */
-
-  return(1);                   /* never executed */
-}
diff --git a/commands/last/Makefile b/commands/last/Makefile
deleted file mode 100644 (file)
index 44f1993..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-PROG=  last
-MAN=
-
-LINKS+=      ${BINDIR}/last ${BINDIR}/uptime
-
-.include <bsd.prog.mk>
diff --git a/commands/last/last.c b/commands/last/last.c
deleted file mode 100644 (file)
index 1ee8048..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/* last - display login history                        Author: Terrence W. Holm */
-
-/* last-       Display the user log-in history.
- *             Last(1) searches backwards through the file of log-in
- *             records (/usr/adm/wtmp), displaying the length of
- *             log-in sessions as requested by the options:
- *
- * Usage:      last [-r] [-count] [-f file] [name] [tty] ...
- *
- *             -r      Search backwards only until the last reboot
- *                     record.
- *
- *             -count  Only print out <count> records. Last(1) stops
- *                     when either -r or -count is satisfied, or at
- *                     the end of the file if neither is given.
- *
- *             -f file Use "file" instead of "/usr/adm/wtmp".
- *
- *             name    Print records for the user "name".
- *
- *             tty     Print records for the terminal "tty". Actually,
- *                     a list of names may be given and all records
- *                     that match either the user or tty name are
- *                     printed. If no names are given then all records
- *                     are displayed.
- *
- *             A sigquit (^\) causes last(1) to display how far it
- *             has gone back in the log-in record file, it then
- *             continues. This is used to check on the progress of
- *             long running searches. A sigint will stop last(1).
- *
- * Author:     Terrence W. Holm        May 1988
- *
- * Revision:
- *             Fred van Kempen, October 1989
- *              -Adapted to MSS.
- *              -Adapted to new utmp database.
- *
- *             Fred van Kempen, December 1989
- *              -Adapted to POSIX (MINIX 1.5)
- *
- *             Fred van Kempen, January 1990
- *              -Final edit for 1.5
- *
- *             Philip Homburg, March 1992
- *              -Include host in output
- *
- *             Kees J. Bot, July 1997
- *              -Approximate system uptime from last reboot record
- */
-#include <sys/types.h>
-#include <signal.h>
-#include <string.h>
-#include <utmp.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <paths.h>
-
-#define  FALSE 0
-#define  TRUE  1
-#define  RLOGIN        1
-
-#define  BUFFER_SIZE     4096  /* Room for wtmp records */
-#define  MAX_WTMP_COUNT  ( BUFFER_SIZE / sizeof(struct utmp) )
-
-#define  min( a, b )     ( (a < b) ? a : b )
-#define  max( a, b )    ( (a > b) ? a : b )
-
-
-typedef struct logout {                /* A logout time record */
-  char line[12];               /* The terminal name */
-  long time;                   /* The logout time */
-  struct logout *next;         /* Next in linked list */
-} logout;
-
-
-static char *Version = "@(#) LAST 1.7 (10/24/92)";
-
-
-/* command-line option flags */
-char boot_limit = FALSE;       /* stop on latest reboot */
-char count_limit = FALSE;      /* stop after print_count */
-char tell_uptime = FALSE;      /* tell uptime since last reboot */
-int print_count;
-char *prog;                    /* name of this program */
-int arg_count;                 /* used to select specific */
-char **args;                   /* users and ttys */
-
-/* global variables */
-long boot_time = 0;            /* Zero means no reboot yet */
-char *boot_down;               /* "crash" or "down " flag */
-logout *first_link = NULL;     /* List of logout times */
-int interrupt = FALSE;         /* If sigint or sigquit occurs */
-
-int main(int argc, char **argv);
-void Sigint(int sig);
-void Sigquit(int sig);
-void usage(void);
-void Process(struct utmp *wtmp);
-int Print_Record(struct utmp *wtmp);
-void Print_Duration(long from, long to);
-void Print_Uptime(void);
-void Record_Logout_Time(struct utmp *wtmp);
-
-/* Sigint() and Sigquit() Flag occurrence of an interrupt. */
-void Sigint(sig)
-int sig;
-{
-  interrupt = SIGINT;
-}
-
-
-void Sigquit(sig)
-int sig;
-{
-  interrupt = SIGQUIT;
-}
-
-
-void usage()
-{
-  fprintf(stderr,
-       "Usage: last [-r] [-u] [-count] [-f file] [name] [tty] ...\n");
-  exit(-1);
-}
-
-
-/* A log-in record format file contains four types of records.
- *
- *  [1] generated on a system reboot:
- *
- *     line="~", name="reboot", host="", time=date()
- *
- *
- *  [2] generated after a shutdown:
- *
- *     line="~", name="shutdown", host="", time=date()
- *
- *
- *  [3] generated on a successful login(1)
- *
- *     line=ttyname(), name=cuserid(), host=, time=date()
- *
- *
- *  [4] generated by init(8) on a logout
- *
- *     line=ttyname(), name="", host="", time=date()
- *
- *
- * Note: This version of last(1) does not recognize the '|' and '}' time
- *      change records. Last(1) pairs up line login's and logout's to
- *      generate four types of output lines:
- *
- *       [1] a system reboot or shutdown
- *
- *        reboot    ~       Mon May 16 14:16
- *        shutdown  ~       Mon May 16 14:15
- *
- *       [2] a login with a matching logout
- *
- *        edwin     tty1    Thu May 26 20:05 - 20:32  (00:27)
- *
- *       [3] a login followed by a reboot or shutdown
- *
- *        root      tty0    Mon May 16 13:57 - crash  (00:19)
- *        root      tty1    Mon May 16 13:45 - down   (00:30)
- *
- *       [4] a login not followed by a logout or reboot
- *
- *        terry     tty0    Thu May 26 21:19   still logged in
- */
-void Process(wtmp)
-struct utmp *wtmp;
-{
-  logout *link;
-  logout *next_link;
-  char is_reboot;
-
-  /* suppress the job number on an "ftp" line */
-  if (!strncmp(wtmp->ut_line, "ftp", (size_t)3)) strncpy(wtmp->ut_line, "ftp", (size_t)8);
-
-  if (!strcmp(wtmp->ut_line, "~")) {
-       /* A reboot or shutdown record  */
-       if (boot_limit) exit(0);
-
-       if (Print_Record(wtmp)) putchar('\n');
-       boot_time = wtmp->ut_time;
-
-       is_reboot = !strcmp(wtmp->ut_name, "reboot");
-       if (is_reboot)
-               boot_down = "crash";
-       else
-               boot_down = "down ";
-
-       if (tell_uptime) {
-               if (!is_reboot) {
-                       fprintf(stderr,
-               "%s: no reboot record added to wtmp file on system boot!\n",
-                               prog);
-                       exit(1);
-               }
-               Print_Uptime();
-               exit(0);
-       }
-
-       /* remove any logout records */
-       for (link = first_link; link != NULL; link = next_link) {
-               next_link = link->next;
-               free(link);
-       }
-       first_link = NULL;
-  } else if (wtmp->ut_name[0] == '\0') {
-       /* A logout record */
-       Record_Logout_Time(wtmp);
-  } else {
-       /* A login record */
-       for (link = first_link; link != NULL; link = link->next)
-               if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) {
-                       /* found corresponding logout record */
-                       if (Print_Record(wtmp)) {
-                               printf("- %.5s ", ctime(&link->time) + 11);
-                               Print_Duration(wtmp->ut_time, link->time);
-                       }
-                       /* record login time */
-                       link->time = wtmp->ut_time;
-                       return;
-               }
-       /* could not find a logout record for this login tty */
-       if (Print_Record(wtmp))
-               if (boot_time == 0)     /* still on */
-                       printf("  still logged in\n");
-               else {          /* system crashed while on */
-                       printf("- %s ", boot_down);
-                       Print_Duration(wtmp->ut_time, boot_time);
-               }
-       Record_Logout_Time(wtmp);       /* Needed in case of 2
-                                        * consecutive logins  */
-  }
-}
-
-
-/* Print_Record(wtmp) If the record was requested, then print out
- * the user name, terminal, host and time.
- */
-int Print_Record(wtmp)
-struct utmp *wtmp;
-{
-  int i;
-  char print_flag = FALSE;
-
-  /* just interested in the uptime? */
-  if (tell_uptime) return(FALSE);
-
-  /* check if we have already printed the requested number of records */
-  if (count_limit && print_count == 0) exit(0);
-
-  for (i = 0; i < arg_count; ++i)
-       if (!strncmp(args[i], wtmp->ut_name, sizeof(wtmp->ut_name)) ||
-           !strncmp(args[i], wtmp->ut_line, sizeof(wtmp->ut_line)))
-               print_flag = TRUE;
-
-  if (arg_count == 0 || print_flag) {
-#ifdef RLOGIN
-       printf("%-8.8s  %-8.8s %-16.16s %.16s ",
-              wtmp->ut_name, wtmp->ut_line, wtmp->ut_host,
-              ctime(&wtmp->ut_time));
-#else
-       printf("%-8.8s  %-8.8s  %.16s ",
-              wtmp->ut_name, wtmp->ut_line, ctime(&wtmp->ut_time));
-#endif
-       --print_count;
-       return(TRUE);
-  }
-  return(FALSE);
-}
-
-
-/* Print_Duration(from, to) Calculate and print the days and hh:mm between
- * the log-in and the log-out.
- */
-void Print_Duration(from, to)
-long from;
-long to;
-{
-  long delta, days, hours, minutes;
-
-  delta = max(to - from, 0);
-  days = delta / (24L * 60L * 60L);
-  delta = delta % (24L * 60L * 60L);
-  hours = delta / (60L * 60L);
-  delta = delta % (60L * 60L);
-  minutes = delta / 60L;
-
-  if (days > 0)
-       printf("(%ld+", days);
-  else
-       printf(" (");
-
-  printf("%02ld:%02ld)\n", hours, minutes);
-}
-
-
-/* Print_Uptime() Calculate and print the "uptime" between the last recorded
- * boot and the current time.
- */
-void Print_Uptime()
-{
-#define NLOADS 3
-  int nloads;
-  double loads[NLOADS];
-  char *utmp_file = _PATH_UTMP;
-  unsigned nusers;
-  struct utmp ut;
-  FILE *uf;
-  time_t now;
-  struct tm *tm;
-  unsigned long up;
-
-  /* Count the number of active users in the utmp file. */
-  if ((uf = fopen(utmp_file, "r")) == NULL) {
-       fprintf(stderr, "%s: %s: %s\n", prog, utmp_file, strerror(errno));
-       exit(1);
-  }
-
-  nusers = 0;
-  while (fread(&ut, sizeof(ut), 1, uf) == 1) {
-#ifdef USER_PROCESS
-       if (ut.ut_type == USER_PROCESS) nusers++;
-#else
-       if (ut.ut_name[0] != 0 && ut.ut_line[0] != 0) nusers++;
-#endif
-  }
-  fclose(uf);
-
-  /* Current time. */
-  now = time((time_t *) NULL);
-  tm = localtime(&now);
-
-  /* Uptime. */
-  up = now - boot_time;
-
-  printf(" %d:%02d  up", tm->tm_hour, tm->tm_min);
-  if (up >= 24 * 3600L) {
-       unsigned long days = up / (24 * 3600L);
-       printf(" %lu day%s,", days, days == 1 ? "" : "s");
-  }
-  printf(" %lu:%02lu,", (up % (24 * 3600L)) / 3600, (up % 3600) / 60);
-  printf("  %u user%s", nusers, nusers == 1 ? "" : "s");
-  if((nloads = getloadavg(loads, NLOADS)) > 0) {
-       int i;
-       printf(", load averages:");
-       for(i = 0; i < nloads; i++)
-               printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
-  }
-  printf("\n");
-}
-
-
-/* Record_Logout_Time(wtmp) A linked list of "last logout time" is kept.
- * Each element of the list is for one terminal.
- */
-void Record_Logout_Time(wtmp)
-struct utmp *wtmp;
-{
-  logout *link;
-
-  /* see if the terminal is already in the list */
-  for (link = first_link; link != NULL; link = link->next)
-       if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) {
-               link->time = wtmp->ut_time;
-               return;
-       }
-  /* allocate a new logout record, for a tty not previously encountered */
-  link = (logout *) malloc(sizeof(logout));
-  if (link == NULL) {
-       fprintf(stderr, "%s: malloc failure\n", prog);
-       exit(1);
-  }
-  strncpy(link->line, wtmp->ut_line, (size_t)8);
-  link->time = wtmp->ut_time;
-  link->next = first_link;
-
-  first_link = link;
-}
-
-
-int main(argc, argv)
-int argc;
-char *argv[];
-{
-  char *wtmp_file = _PATH_WTMP;
-  FILE *f;
-  long size;                   /* Number of wtmp records in the file    */
-  int wtmp_count;              /* How many to read into wtmp_buffer     */
-  struct utmp wtmp_buffer[MAX_WTMP_COUNT];
-
-  if ((prog = strrchr(argv[0], '/')) == NULL) prog = argv[0]; else prog++;
-
-  --argc;
-  ++argv;
-
-  while (argc > 0 && *argv[0] == '-') {
-       if (!strcmp(argv[0], "-r"))
-               boot_limit = TRUE;
-       else
-       if (!strcmp(argv[0], "-u"))
-               tell_uptime = TRUE;
-       else if (argc > 1 && !strcmp(argv[0], "-f")) {
-               wtmp_file = argv[1];
-               --argc;
-               ++argv;
-       } else if ((print_count = atoi(argv[0] + 1)) > 0)
-               count_limit = TRUE;
-       else
-               usage();
-
-       --argc;
-       ++argv;
-  }
-
-  arg_count = argc;
-  args = argv;
-
-  if (!strcmp(prog, "uptime")) tell_uptime = TRUE;
-
-  if ((f = fopen(wtmp_file, "r")) == NULL) {
-       perror(wtmp_file);
-       exit(1);
-  }
-  if (fseek(f, 0L, 2) != 0 || (size = ftell(f)) % sizeof(struct utmp) != 0) {
-       fprintf(stderr, "%s: invalid wtmp file\n", prog);
-       exit(1);
-  }
-  if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
-       signal(SIGINT, Sigint);
-       signal(SIGQUIT, Sigquit);
-  }
-  size /= sizeof(struct utmp); /* Number of records in wtmp     */
-
-  if (size == 0) wtmp_buffer[0].ut_time = time((time_t *)0);
-
-  while (size > 0) {
-       wtmp_count = (int) min(size, MAX_WTMP_COUNT);
-       size -= (long) wtmp_count;
-
-       fseek(f, size * sizeof(struct utmp), 0);
-
-
-       if (fread(&wtmp_buffer[0], sizeof(struct utmp), (size_t)wtmp_count, f)
-           != wtmp_count) {
-               fprintf(stderr, "%s: read error on wtmp file\n", prog);
-               exit(1);
-       }
-       while (--wtmp_count >= 0) {
-               Process(&wtmp_buffer[wtmp_count]);
-               if (interrupt) {
-                       printf("\ninterrupted %.16s \n",
-                          ctime(&wtmp_buffer[wtmp_count].ut_time));
-
-                       if (interrupt == SIGINT) exit(2);
-
-                       interrupt = FALSE;
-                       signal(SIGQUIT, Sigquit);
-               }
-       }
-
-  }                            /* end while(size > 0) */
-
-  if (tell_uptime) {
-       fprintf(stderr,
-               "%s: no reboot record in wtmp file to compute uptime from\n",
-               prog);
-       return(1);
-  }
-
-  printf("\nwtmp begins %.16s \n", ctime(&wtmp_buffer[0].ut_time));
-  return(0);
-}
-
diff --git a/commands/poweroff/Makefile b/commands/poweroff/Makefile
deleted file mode 100644 (file)
index 5af305f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-SCRIPTS= poweroff.sh
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/commands/poweroff/poweroff.sh b/commands/poweroff/poweroff.sh
deleted file mode 100644 (file)
index 366baac..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-#
-# poweroff 1.0 - power off the system          Author: David van Moolenbroek
-#                                                                12 Jun 2009
-
-if [ $# -gt 0 ]; then
-  echo "usage: poweroff" >&2
-  exit 1
-fi
-
-PATH=/usr/bin:$PATH
-
-exec shutdown -p
diff --git a/commands/reboot/Makefile b/commands/reboot/Makefile
deleted file mode 100644 (file)
index 91c6cee..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# Makefile for shutdown / halt / reboot.
-
-PROGS= shutdown halt
-SRCS.shutdown= shutdown.c sh_wall.c log.c
-SRCS.halt=     halt.c log.c
-BINDIR=/bin
-BINMODE= 4754
-SYMLINKS+=     ${BINDIR}/halt ${BINDIR}/reboot
-SYMLINKS+=     ${BINDIR}/halt /usr/bin/halt
-SYMLINKS+=     ${BINDIR}/shutdown /usr/bin/shutdown
-SYMLINKS+=     ${BINDIR}/reboot /usr/bin/reboot
-MAN.shutdown=
-MAN.halt=
-
-.include <bsd.prog.mk>
diff --git a/commands/reboot/README b/commands/reboot/README
deleted file mode 100644 (file)
index 91c378b..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-This a new implementation of a shutdown procedure. It allows 
-the system to go down graciously with informing the
-users. This package contains 3 programs:
-
-- halt = Immediately stop the system, no info to users
-- shutdown = Inform users, close down the system properly
-- wall = Vincent Archer's implementation of wall (Write all)
-
-Installing
-
-Shutdown and halt use a new systemcall, which I've added to
-MM. Therefor there are several diff's which should be applied:
-
-callnr.hd - New callnr for reboot(2)
-          Diff against /usr/include/minix/callnr.h.
-          Those of you using a symlink package should
-          change the number and mm/table.c into a free
-          number. I used 54, LSTAT.
-param.hd - Defines reboot_flag as a part of the messages
-proto.hd - Add's prototype for do_reboot()
-table.cd - Interpretation of the systemcall to MM
-mm.cd -           I have added the do_reboot code to mm/getset.c but
-          I couldn't find a getset.c to create a useable diff :-(
-          So you can add where you want it. It is pure code, no diff.
-
-Now edit log.c and search for ``host''. Change this into your
-systemname or make it empty.
-
-Shutdown and halt log their actions in /usr/adm/log, edit the
-makefile and undefine -DLOG if you don't want this (this at the end of
-the makefile). You can change SHUT_LOG in shutdown.c and log.c if you
-want it in another file.
-
-Then type a `make'. This will take a minute or so (13 sec. with bcc :-).
-Remember to build a new image and update the ps_database.
-
-Type `make install' to place the program's where I've got them.
-Use them, try them and let me now if you've got problems running
-something.
-
-I have tested to sources both on 16-bits and 32-bits MINIX. I have compiled
-it with gcc, bcc and ACK, so that shouldn't really give a problem. Maybe
-the standard MINIX-make chokes on the makefile, atleast mine did.
-
-NOTE:
-       Make install does not place the man-pages somewhere. You should
-       do this yourself.
-
---
-Edvard Tuinder        ed@pulstar.NL.mugnet.org    v892231@si.hhs.NL
-Student Computer Science
-Haagse Hogeschool, The Hague, The Netherlands
diff --git a/commands/reboot/halt.c b/commands/reboot/halt.c
deleted file mode 100644 (file)
index a03bbc1..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/* halt / reboot - halt or reboot system (depends on name)
-
-   halt   - calling reboot() with RBT_HALT
-   reboot - calling reboot() with RBT_REBOOT
-
-   author: Edvard Tuinder   v892231@si.hhs.NL
-
-   This program calls the library function reboot(2) which performs
-   the system-call do_reboot. 
-
- */
-
-#define _POSIX_SOURCE  1
-#include <sys/types.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <minix/reboot.h>
-
-#include "wtmp.h"
-
-void write_log( char *fn );
-void usage( void );
-int main( int argc, char *argv[] );
-
-char *prog;
-
-void
-usage()
-{
-  fprintf(stderr, "Usage: %s [-hrRfpd]\n", prog);
-  exit(1);
-}
-
-int
-main(argc,argv)
-int argc;
-char **argv;
-{
-  int flag = -1;               /* default action unknown */
-  int fast = 0;                        /* fast halt/reboot, don't bother being nice. */
-  int i;
-  struct stat dummy;
-  pid_t pid;
-
-  if ((prog = strrchr(argv[0],'/')) == NULL) prog = argv[0]; else prog++;
-
-  if (strcmp(prog, "halt") == 0) flag = RBT_HALT;
-  if (strcmp(prog, "reboot") == 0) flag = RBT_REBOOT;
-
-  i = 1;
-  while (i < argc && argv[i][0] == '-') {
-    char *opt = argv[i++] + 1;
-
-    if (*opt == '-' && opt[1] == 0) break;     /* -- */
-
-    while (*opt != 0) switch (*opt++) {
-      case 'h': flag = RBT_HALT;       break;
-      case 'r': flag = RBT_REBOOT;     break;
-      case 'R': flag = RBT_RESET;      break;
-      case 'd': flag = RBT_DEFAULT;    break;
-      case 'p': flag = RBT_POWEROFF;   break;
-      case 'f': fast = 1; break;
-      default:
-       usage();
-    }
-  }
-
-  if (i != argc) usage();
-
-  if (flag == -1) {
-    fprintf(stderr, "Don't know what to do when named '%s'\n", prog);
-    exit(1);
-  }
-
-  if (stat("/usr/bin", &dummy) < 0) {
-    /* It seems that /usr isn't present, let's assume "-f." */
-    fast = 1;
-  }
-
-  signal(SIGHUP, SIG_IGN);
-  signal(SIGTERM, SIG_IGN);
-
-  /* Skip this part for fast shut down. */
-  if (! fast) {
-    /* Run the shutdown scripts. */
-    switch ((pid = fork())) {
-      case -1:
-       fprintf(stderr, "%s: can't fork(): %s\n", prog, strerror(errno));
-       exit(1);
-      case 0:
-       execl("/bin/sh", "sh", "/etc/rc", "down", (char *) NULL);
-       fprintf(stderr, "%s: can't execute: /bin/sh: %s\n",
-         prog, strerror(errno));
-       exit(1);
-      default:
-       while (waitpid(pid, NULL, 0) != pid) {}
-    }
-  }
-
-  /* Tell init to stop spawning getty's. */
-  kill(1, SIGTERM);
-
-  /* Extra sync for the case where SIGTERM causes deadlock */
-  sync();
-
-  /* Give everybody a chance to die peacefully. */
-  printf("Sending SIGTERM to all processes ...\n");
-  kill(-1, SIGTERM);
-  sleep(1);
-
-  write_log(STR_WTMP);
-  write_log(STR_ROOT_WTMP);
-
-  sync();
-
-  reboot(flag);
-  fprintf(stderr, "%s: reboot(): %s\n", prog, strerror(errno));
-  return 1;
-}
diff --git a/commands/reboot/log.c b/commands/reboot/log.c
deleted file mode 100644 (file)
index 5363371..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-  log - log the shutdown's and the halt's
-
-  Author: Edvard Tuinder  <v892231@si.hhs.NL>
-
-  shutdown is logged in /usr/adm/wtmp and in /usr/adm/log (if desired)
-  halt is logged only in /usr/adm/wtmp as `halt' to prevent last from
-       reporting halt's as crashes.
-
- */
-
-#define _POSIX_SOURCE  1
-#include <sys/types.h>
-#include <stdio.h>
-#include <utmp.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-static char SHUT_LOG[] = "/usr/adm/log";
-
-char who[8];
-extern char *prog;
-static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
-void write_log(char *wtmpfile)
-{
-  int fd;
-  static struct utmp wtmp;
-  static struct passwd *pwd;
-  char mes[90];
-  struct tm *tm;
-  time_t now;
-  struct utsname utsname;
-  char *host = "localhost";
-
-  time(&now);
-  tm = localtime(&now);
-
-  if (uname(&utsname) >= 0) host = utsname.nodename;
-
-  pwd = getpwuid(getuid());
-  if (pwd == (struct passwd *)0)
-    strcpy (who,"root");
-  else
-    strcpy (who,pwd->pw_name);
-  fd = open(wtmpfile,O_APPEND|O_WRONLY|O_CREAT,1);
-  if (fd) {
-    if (strcmp(prog,"reboot"))
-      strcpy (wtmp.ut_name, prog);
-    else
-      strcpy (wtmp.ut_name, "shutdown"); /* last ... */
-    strcpy (wtmp.ut_id, "~~");
-    strcpy (wtmp.ut_line, "~");
-    wtmp.ut_pid = 0;
-    wtmp.ut_type = BOOT_TIME;
-    wtmp.ut_time = now;
-    wtmp.ut_host[0]= '\0';
-    write (fd, (char *) &wtmp,sizeof(struct utmp));
-    close(fd);
-  }
-  fd = open(SHUT_LOG,O_APPEND|O_WRONLY,1);
-  if (!fd) 
-    perror ("open");
-  else {
-    sprintf (mes,"%s %02d %02d:%02d:%02d %s: system %s by %s@%s\n",
-       month[tm->tm_mon],tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,
-       prog,prog,who,host);
-    write (fd,mes,strlen(mes));
-    close(fd);
-  }
-  return;
-}
diff --git a/commands/reboot/sh_wall.c b/commands/reboot/sh_wall.c
deleted file mode 100644 (file)
index a840194..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* wall - write to all logged in users                 Author: V. Archer */
-/*
-   Edvard Tuinder    v892231@si.hhs.NL
-    Modified some things to include this with my shutdown/halt
-    package
- */
-
-#define _POSIX_SOURCE  1
-#include <sys/types.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <utmp.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-#include <sys/stat.h>
-#undef UTMP
-
-static char UTMP[] = "/etc/utmp";      /* Currently logged in users. */
-
-void wall( char *when, char *extra );
-void crnlcat( char *message, char *more );
-
-void
-wall(when, extra)
-char *when;                    /* When is shutdown */
-char *extra;                   /* If non-nil, why is the shutdown */
-{
-  struct utmp utmp;
-  char utmptty[5 + sizeof(utmp.ut_line) + 2];
-  char message[1024];
-  struct passwd *pw;
-  int utmpfd, ttyfd;
-  char *ourtty, *ourname;
-  time_t now;
-  struct utsname utsname;
-  struct stat con_st, tty_st;
-
-  if ((ourtty = ttyname(1))) {
-       if ((ourname = strrchr(ourtty, '/'))) ourtty = ourname+1;
-  } else ourtty = "system task";
-  if ((pw = getpwuid(getuid()))) ourname = pw->pw_name;
-  else ourname = "unknown";
-
-  time(&now);
-  if (uname(&utsname) != 0) strcpy(utsname.nodename, "?");
-  sprintf(message, "\r\nBroadcast message from %s@%s (%s)\r\n%.24s...\r\n",
-               ourname, utsname.nodename, ourtty, ctime(&now));
-
-  crnlcat(message, when);
-  crnlcat(message, extra);
-
-/* Search the UTMP database for all logged-in users. */
-
-  if ((utmpfd = open(UTMP, O_RDONLY)) < 0) {
-       fprintf(stderr, "Cannot open utmp file\r\n");
-       return;
-  }
-
-  /* first the console */
-  strcpy(utmptty, "/dev/console");
-  if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) {
-       perror(utmptty);
-  } else {
-       fstat(ttyfd, &con_st);
-       write(ttyfd, message, strlen(message));
-       close(ttyfd);
-  }
-
-  while (read(utmpfd, (char *) &utmp, sizeof(utmp)) == sizeof(utmp)) {
-       /* is this the user we are looking for? */
-       if (utmp.ut_type != USER_PROCESS) continue;
-
-       strncpy(utmptty+5, utmp.ut_line, sizeof(utmp.ut_line));
-       utmptty[5 + sizeof(utmp.ut_line) + 1] = 0;
-       if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) {
-               perror(utmptty);
-               continue;
-       }
-       fstat(ttyfd, &tty_st);
-       if (tty_st.st_rdev != con_st.st_rdev)
-               write(ttyfd, message, strlen(message));
-       close(ttyfd);
-  }
-  close(utmpfd);
-  return;
-}
-
-void
-crnlcat(message, more)
-char *message, *more;
-{
-  char *p = message;
-  char *m = more;
-  char *end = message + 1024 - 1;
-
-  while (p < end && *p != 0) p++;
-
-  while (p < end && *m != 0) {
-    if (*m == '\n' && (p == message || p[-1] != '\n')) {
-      *p++ = '\r';
-      if (p == end) p--;
-    }
-    *p++ = *m++;
-  }
-  *p = 0;
-}
diff --git a/commands/reboot/shutdown.c b/commands/reboot/shutdown.c
deleted file mode 100644 (file)
index 972f618..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
-  shutdown - close down the system graciously
-
-  Author: Edvard Tuinder  <v892231@si.hhs.NL>
-
-  This program informs the users that the system is going
-  down, when and why. After that a shutdown notice is written in
-  both /usr/adm/wtmp and by syslog(3).  Then reboot(2) is called
-  to really close the system.
-
-  This actually is a ``nice'' halt(8).
-
-  Options are supposed to be as with BSD
-   -h: shutdown and halt the system
-   -r: shutdown and reboot
-   -k: stop an already running shutdown
-   -o: obsolete: not implemented
-
-  New Minix options:
-   -C: crash check, i.e. is the last wtmp entry a shutdown entry?
-   -R: reset the system
-   -d: default CTRL-ALT-DEL shutdown for current bootloader
- */
-
-#define _POSIX_SOURCE  1
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <time.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <errno.h>
-#include <minix/reboot.h>
-
-#include "wtmp.h"
-
-static char SHUT_PID[] =       "/usr/run/shutdown.pid";
-static char NOLOGIN[] =                "/etc/nologin";
-
-#ifndef __STDC__
-#define inform_user_time inf_time
-#define inform_user      inf_user
-#endif
-
-void usage( void );
-void write_pid( void );
-int inform_user_time( void );
-void inform_user( void );
-void terminate( void );
-void wall( char *when, char *extra );
-int crash_check( void );
-void parse_time( char *arg );
-void get_message( void );
-int main( int argc, char *argv[] );
-char *itoa( int n );
-
-long wait_time=0L;
-char message[1024];
-char info[80];
-int reboot_flag='h';                   /* default is halt */
-int info_min, info_hour;
-char *prog;
-
-void parse_time (arg)
-char *arg;
-{
-  char *p = arg;
-  int hours, minutes;
-  time_t now;
-  struct tm *tm;
-  int delta = 0;
-  int bad = 0;
-  
-  if (p[0] == '+') { delta = 1; p++; }
-
-  hours = strtoul(p, &p, 10);
-  if (*p == 0 && delta) {
-    minutes = hours;
-    hours = 0;
-  } else {
-    if (*p != ':' && *p != '.')
-      bad = 1;
-    else
-      p++;
-    minutes = strtoul(p, &p, 10);
-    if (*p != 0) bad = 1;
-  }
-  if (bad) {
-    fprintf(stderr,"Invalid time specification `%s'\n",arg);
-    usage();
-  }
-
-  time(&now);
-  tm = localtime(&now);
-
-  if (!delta) {
-    hours -= tm->tm_hour;
-    minutes -= tm->tm_min;
-  }
-
-  if (minutes < 0) {
-    minutes += 60;
-    hours--;
-  }
-  if (hours < 0) hours += 24;  /* Time after midnight. */
-
-  tm->tm_hour += hours;
-  tm->tm_min += minutes;
-  (void) mktime(tm);
-  info_hour = tm->tm_hour;
-  info_min  = tm->tm_min;
-
-  sprintf(info,
-    "The system will shutdown in %d hour%s and %d minute%s at %02d:%02d\n\n",
-    hours,hours==1?"":"s",minutes,minutes==1?"":"s",info_hour,info_min);
-
-  wait_time += hours * 3600 + minutes * 60;
-  return;
-}
-
-int main(argc,argv)
-int argc;
-char *argv[];
-{
-  int i, now = 0, nologin = 0, want_terminate = 0, want_message = 0, check = 0;
-  char *opt;
-  int tty;
-  static char HALT1[] = "-?";
-  static char *HALT[] = { "shutdown", HALT1, NULL };
-
-  /* Parse options. */
-  for (i = 1; i < argc && argv[i][0] == '-'; i++) {
-    if (argv[i][1] == '-' && argv[i][2] == 0) {
-      /* -- */
-      i++;
-      break;
-    }
-    for (opt = argv[i] + 1; *opt != 0; opt++) {
-      switch (*opt) {
-      case 'k':
-       want_terminate = 1;
-       break;
-      case 'h':
-      case 'r':
-      case 'p':
-      case 'd':
-      case 'R':
-       reboot_flag = *opt;
-       break;
-      case 'm':
-       want_message = 1;
-       break;
-      case 'C':
-       check = 1;
-       break;
-      default:
-       fprintf (stderr,"shutdown: invalid option '-%c'\n",*opt);
-       usage();
-       break;
-      }
-    }
-  }
-  if ((argc - i) > 2) usage();
-
-  if (check) exit(crash_check() ? 0 : 2);
-
-  if (i == argc) {
-    /* No timespec, assume "now". */
-    now = 1;
-  } else {
-    if (!strcmp(argv[i], "now"))
-      now++;
-    else
-      parse_time(argv[i]);
-  }
-
-  if ((argc - i) == 2) {
-    /* One line message */
-    strcat(message, argv[i+1]);
-    strcat(message, "\n");
-  }
-
-  if (want_terminate) terminate();
-  if (want_message) get_message();
-
-  puts(info);
-
-  prog = strrchr(*argv,'/');
-  if (prog == (char *)0)
-    prog = *argv;
-  else
-    prog++;
-    
-  if (!now) {
-    /* Daemonize. */
-    switch (fork()) {
-    case 0:
-      break;
-    case -1:
-      fprintf(stderr, "%s: can't fork\n", prog);
-      exit(1);
-    default:
-      exit(0);
-    }
-    /* Detach from the terminal (if any). */
-    if ((tty = open("/dev/tty", O_RDONLY)) != -1) {
-      close(tty);
-      setsid();
-    }
-    write_pid();
-  }
-
-  for (;;) {
-    if (wait_time <= 5 * 60 && !nologin && !now) {
-      close(creat(NOLOGIN,00644));
-      nologin = 1;
-    }
-    if (wait_time <= 60) break;
-    if(inform_user_time())
-      inform_user();
-    sleep (60);
-    wait_time -= 60;
-  }
-  
-  if (!now) {
-    inform_user();
-    sleep (30);                                /* Last minute before shutdown */
-    wait_time -= 30;
-    inform_user();
-    sleep (30);                                /* Last 30 seconds before shutdown */
-  }
-  wait_time = 0;
-  inform_user();
-
-  unlink(SHUT_PID);                    /* No way of stopping anymore */
-  unlink(NOLOGIN);
-
-  HALT[1][1] = reboot_flag;
-#if __minix_vmd
-  execv("/usr/sbin/halt", HALT);
-#else
-  execv("/usr/bin/halt", HALT);
-#endif
-  if (errno != ENOENT)
-    fprintf(stderr, "Can't execute 'halt': %s\n", strerror(errno));
-
-  sleep(2);
-  reboot(RBT_HALT);
-  fprintf(stderr, "Reboot call failed: %s\n", strerror(errno));
-
-  return(1);
-}
-
-void usage()
-{
-  fputs("Usage: shutdown [-hrRpmkd] [time [message]]\n", stderr);
-  fputs("       -h -> halt system after shutdown\n", stderr);
-  fputs("       -r -> reboot system after shutdown\n", stderr);
-  fputs("       -R -> reset system after shutdown\n", stderr);
-  fputs("       -p -> power system off after shutdown\n", stderr);
-  fputs("       -d -> default CTRL-ALT-DEL shutdown for current bootloader\n", stderr);
-  fputs("       -m -> read a shutdown message from standard input\n", stderr);
-  fputs("       -k -> stop an already running shutdown\n", stderr);
-  fputs("       time -> keyword ``now'', minutes before shutdown ``+5'',\n", stderr);
-  fputs("               or absolute time specification ``11:20''\n", stderr);
-  fputs("       message -> short shutdown message\n", stderr);
-  exit(1);
-}
-
-void terminate()
-{
-  FILE *in;
-  pid_t pid;
-  char c_pid[5];
-
-  in = fopen(SHUT_PID,"r");
-  if (in == (FILE *)0) {
-    fputs ("Can't get pid of shutdown process, probably not running shutdown\n", stderr);
-    exit(1);
-  }
-  fgets(c_pid,5,in);
-  fclose(in);
-  pid = atoi(c_pid);
-  if (kill(pid,9) == -1)
-    fputs("Can't kill the shutdown process, probably not running anymore\n",stderr);
-  else
-    puts("Shutdown process terminated");
-  unlink(SHUT_PID);
-  unlink(NOLOGIN);
-  exit(0);
-}
-
-void get_message()
-{
-  char line[80];
-
-  puts ("Type your message. End with ^D at an empty line");
-  fputs ("shutdown> ",stdout);fflush(stdout);
-  while (fgets(line,80,stdin) != (char *)0) {
-    strcat (message,line);
-    bzero(line,strlen(line));
-    fputs ("shutdown> ",stdout);fflush(stdout);
-  }
-  putc('\n',stdout);fflush(stdout);
-}
-
-int inform_user_time()
-{
-  int min;
-
-  min = wait_time /60;
-
-  if (min == 60 || min == 30 || min == 15 || min == 10 || min <= 5)
-    return 1;
-  else
-    return 0;
-}
-
-void inform_user()
-{
-  int hour, minute;
-  char mes[80];
-
-  hour = 0;
-  minute = wait_time / 60;
-  while (minute >= 60) {
-    minute -= 60;
-    hour++;
-  }
-
-  if (hour)
-    sprintf(mes,
-    "\nThe system will shutdown in %d hour%s and %d minute%s at %.02d:%.02d\n\n",
-    hour,hour==1?"":"s",minute,minute==1?"":"s",info_hour,info_min);
-  else
-  if (minute > 1)
-    sprintf(mes,
-    "\nThe system will shutdown in %d minutes at %.02d:%.02d\n\n",
-    minute,info_hour,info_min);
-  else
-  if (wait_time > 1)
-    sprintf(mes,
-    "\nThe system will shutdown in %ld seconds\n\n",
-    wait_time);
-  else
-    sprintf(mes,
-    "\nThe system will shutdown NOW\n\n");
-
-  wall(mes,message);
-}
-
-void write_pid()
-{
-  char pid[5];
-  int fd;
-
-  fd = creat(SHUT_PID,00600);
-  if (!fd)
-    return;
-  strncpy (pid,itoa(getpid()), sizeof(pid));
-  write (fd,pid,sizeof(pid));
-  close(fd);
-  return;
-}
-
-int crash_check()
-{
-  struct utmp last;
-  int fd = -1, crashed;
-  struct stat st;
-
-  if (stat(STR_ROOT_WTMP, &st) < 0 || st.st_size == 0) {
-       if (stat(STR_WTMP, &st) < 0 || st.st_size == 0) {
-               return 0;
-       }
-       if ((fd = open(STR_WTMP, O_RDONLY)) < 0) return 0;
-  } else if ((fd = open(STR_ROOT_WTMP, O_RDONLY)) < 0) return 0;
-
-  crashed = (lseek(fd, - (off_t) sizeof(last), SEEK_END) == -1
-    || read(fd, (void *) &last, sizeof(last)) != sizeof(last)
-    || last.ut_line[0] != '~'
-    || (strncmp(last.ut_name, "shutdown", sizeof(last.ut_name))
-    && strncmp(last.ut_name, "halt", sizeof(last.ut_name)))
-    );
-  close(fd);
-  return crashed;
-}
diff --git a/commands/reboot/wtmp.h b/commands/reboot/wtmp.h
deleted file mode 100644 (file)
index 69044dd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-
-static char STR_WTMP[] = "/usr/adm/wtmp";
-static char STR_ROOT_WTMP[] = "/etc/wtmp";
index 88168ab6c95d9eff95464104e246b0b4439584b3..55ce0dd2b80739c163e443f404cfb8900a18a6a3 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 PROG=  in.telnetd
-SRCS=  main.c telnet.c term.c pty.c wtmp.c
+SRCS=  main.c telnet.c term.c pty.c 
 MAN=
 
 .include <bsd.prog.mk>
index e0bdf4c94b81dca3927a9f99c45b289e9774df8f..c2f1f623e6ab44e6723827ce5b3bf31a5f2d7329 100644 (file)
@@ -45,7 +45,6 @@ int opt_d = 0;                                /* debugging output flag        */
 
 void usage(void);
 int main(int argc, char *argv[]);
-void wtmp(int type, int linenr, char *line, pid_t pid, char *host);
 
 void usage()
 {
@@ -144,14 +143,10 @@ char *hostname;
        return(-1);
    }
 
-   wtmp(LOGIN_PROCESS, lineno, tty_name+5, pid, hostname);
-
    term_inout(pty_fd);
 
    (void) close(pty_fd);
 
-   wtmp(DEAD_PROCESS, lineno, tty_name+5, pid, hostname);
-
    chown(tty_name, 0, 0);
    chmod(tty_name, 0666);
 
diff --git a/commands/telnetd/wtmp.c b/commands/telnetd/wtmp.c
deleted file mode 100644 (file)
index 3585e26..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * TNET                A server program for MINIX which implements the TCP/IP
- *             suite of networking protocols.  It is based on the
- *             TCP/IP code written by Phil Karn et al, as found in
- *             his NET package for Packet Radio communications.
- *
- *             This file contains an implementation of the "server"
- *             for the TELNET protocol.  This protocol can be used to
- *             remote-login on other systems, just like a normal TTY
- *             session.
- *
- * Usage:      telnetd [-dv]
- *
- * Version:    @(#)telnetd.c   1.00    07/26/92
- *
- * Author:     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *             Michael Temari, <temari@temari.ae.ge.com>
- */
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <time.h>
-#include <stdio.h>
-#include "telnetd.h"
-
-static char PATH_UTMP[] = "/etc/utmp";
-static char PATH_WTMP[] = "/usr/adm/wtmp";
-
-void wtmp(int type, int linenr, char *line, pid_t pid, char *host);
-void report(char *label);
-
-void wtmp(type, linenr, line, pid, host)
-int type;                      /* type of entry */
-int linenr;                    /* line number in ttytab */
-char *line;                    /* tty name (only good on login) */
-pid_t pid;                     /* pid of process */
-char *host;                    /* name of the remote host */
-{
-/* Log an event into the UTMP and WTMP files. */
-
-  struct utmp utmp;            /* UTMP/WTMP User Accounting */
-  int fd;
-
-  /* Clear the utmp record. */
-  memset((void *) &utmp, 0, sizeof(utmp));
-
-  /* Fill in utmp. */
-  switch (type) {
-  case LOGIN_PROCESS:
-       /* A new login, fill in line and host name. */
-       strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
-       strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
-       break;
-
-  case DEAD_PROCESS:
-       /* A logout.  Use the current utmp entry, but make sure it is a
-        * user process exiting, and not getty or login giving up.
-        */
-       if ((fd = open(PATH_UTMP, O_RDONLY)) < 0) {
-               if (errno != ENOENT) report(PATH_UTMP);
-               return;
-       }
-       if (lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
-               || read(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               report(PATH_UTMP);
-               close(fd);
-               return;
-       }
-       close(fd);
-       if (utmp.ut_type != USER_PROCESS) return;
-       strncpy(utmp.ut_name, "", sizeof(utmp.ut_name));
-       break;
-  }
-
-  /* Finish new utmp entry. */
-  utmp.ut_pid = pid;
-  utmp.ut_type = type;
-  utmp.ut_time = time((time_t *) 0);
-
-  /* Write new entry to utmp. */
-  if ((fd = open(PATH_UTMP, O_WRONLY)) < 0
-       || lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
-       || write(fd, &utmp, sizeof(utmp)) == -1
-  ) {
-       if (errno != ENOENT) report(PATH_UTMP);
-  }
-  if (fd != -1) close(fd);
-
-  if (type == DEAD_PROCESS) {
-       /* Add new wtmp entry. */
-       if ((fd = open(PATH_WTMP, O_WRONLY | O_APPEND)) < 0
-                 || write(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               if (errno != ENOENT) report(PATH_WTMP);
-       }
-       if (fd != -1) close(fd);
-  }
-}
-
-void report(label)
-char *label;
-{
-  char message[128];
-
-  sprintf(message, "telnetd: %i: %s\r\n", errno, strerror(errno));
-  (void) write(1, message, strlen(message));
-}
index 6f4e38367313ca8e1eb1febb2bc67e58ebde8524..f6b1ed75dd49403a0ff2fcd2966a791e6e4a3692 100644 (file)
@@ -24,8 +24,8 @@
 ./bin/expr                             minix-sys
 ./bin/false                            minix-sys
 ./bin/getopts                          minix-sys
-./bin/getty                            minix-sys
-./bin/halt                             minix-sys
+./bin/getty                            minix-sys       obsolete
+./bin/halt                             minix-sys       obsolete
 ./bin/intr                             minix-sys
 ./bin/kill                             minix-sys
 ./bin/ksh                              minix-sys
 ./bin/pwd                              minix-sys
 ./bin/read                             minix-sys
 ./bin/readclock                                minix-sys
-./bin/reboot                           minix-sys
+./bin/reboot                           minix-sys       obsolete
 ./bin/rm                               minix-sys
 ./bin/rmdir                            minix-sys
 ./bin/sed                              minix-sys
 ./bin/service                          minix-sys
 ./bin/setup                            minix-sys
 ./bin/sh                               minix-sys
-./bin/shutdown                         minix-sys
+./bin/shutdown                         minix-sys       obsolete
 ./bin/sync                             minix-sys
 ./bin/sysenv                           minix-sys
 ./bin/tar                              minix-sys
 ./etc/termcap                          minix-sys
 ./etc/ttys                             minix-sys
 ./etc/utmp                             minix-sys
+./etc/gettytab                         minix-sys
+./etc/rc.shutdown                      minix-sys
 ./home                                 minix-sys
 ./home/ast                             minix-sys
 ./home/ast/.exrc                       minix-sys
 ./sbin/fsck_ext2fs                     minix-sys
 ./sbin/fsck.mfs                                minix-sys
 ./sbin/input                           minix-sys
+./sbin/halt                            minix-sys
+./sbin/init                            minix-sys
 ./sbin/is                              minix-sys
 ./sbin/isofs                           minix-sys
 ./sbin/mfs                             minix-sys
 ./sbin/newfs_ext2                      minix-sys
 ./sbin/newfs_ext2fs                    minix-sys
 ./sbin/nologin                         minix-sys
+./sbin/poweroff                                minix-sys
 ./sbin/procfs                          minix-sys
 ./sbin/readclock.drv                   minix-sys
+./sbin/reboot                          minix-sys
+./sbin/shutdown                                minix-sys
 ./sys                                  minix-sys
 ./tmp                                  minix-sys
 ./usr                                  minix-sys
 ./usr/bin/gzcat                                minix-sys
 ./usr/bin/gzexe                                minix-sys
 ./usr/bin/gzip                         minix-sys
-./usr/bin/halt                         minix-sys
+./usr/bin/halt                         minix-sys       obsolete
 ./usr/bin/head                         minix-sys
 ./usr/bin/hexdump                      minix-sys
 ./usr/bin/host                         minix-sys
 ./usr/bin/pkgin_cd                     minix-sys
 ./usr/bin/playwave                      minix-sys
 ./usr/bin/postinstall                  minix-sys
-./usr/bin/poweroff                     minix-sys
+./usr/bin/poweroff                     minix-sys       obsolete
 ./usr/bin/pr                           minix-sys
 ./usr/bin/prep                         minix-sys
 ./usr/bin/printenv                     minix-sys
 ./usr/bin/readall                      minix-sys       obsolete
 ./usr/bin/readelf                      minix-sys       binutils
 ./usr/bin/readlink                     minix-sys
-./usr/bin/reboot                       minix-sys
 ./usr/bin/recwave                       minix-sys
+./usr/bin/reboot                       minix-sys       obsolete
 ./usr/bin/ref                          minix-sys       obsolete
 ./usr/bin/remsync                      minix-sys
 ./usr/bin/repartition                   minix-sys
 ./usr/bin/shar                         minix-sys
 ./usr/bin/shlock                       minix-sys
 ./usr/bin/shuffle                      minix-sys
-./usr/bin/shutdown                     minix-sys
+./usr/bin/shutdown                     minix-sys       obsolete
 ./usr/bin/size                         minix-sys       binutils
 ./usr/bin/sleep                                minix-sys
 ./usr/bin/slip                         minix-sys
 ./usr/bin/unxz                         minix-sys
 ./usr/bin/unzip                                minix-sys
 ./usr/bin/update                       minix-sys
-./usr/bin/uptime                       minix-sys
 ./usr/bin/users                                minix-sys
+./usr/bin/uptime                       minix-sys       obsolete
 ./usr/bin/uud                          minix-sys
 ./usr/bin/uudecode                     minix-sys
 ./usr/bin/uue                          minix-sys
 ./usr/bin/view                         minix-sys
 ./usr/bin/vis                          minix-sys
 ./usr/bin/vol                          minix-sys
+./usr/bin/wall                         minix-sys
 ./usr/bin/wc                           minix-sys
 ./usr/bin/what                         minix-sys
 ./usr/bin/whatis                       minix-sys
 ./usr/include/minix/procfs.h           minix-sys
 ./usr/include/minix/profile.h          minix-sys
 ./usr/include/minix/queryparam.h       minix-sys
-./usr/include/minix/reboot.h           minix-sys
+./usr/include/minix/reboot.h           minix-sys       obsolete
 ./usr/include/minix/rs.h               minix-sys
 ./usr/include/minix/safecopies.h       minix-sys
 ./usr/include/minix/sched.h            minix-sys
 ./usr/libexec/atf-check                        minix-sys       atf
 ./usr/libexec/fingerd                  minix-sys
 ./usr/libexec/ftpd                     minix-sys
+./usr/libexec/getty                    minix-sys
 ./usr/libexec/kyua-atf-tester          minix-sys       kyua
 ./usr/libexec/kyua-plain-tester                minix-sys       kyua
 ./usr/libexec/ld.elf_so                        minix-sys
 ./usr/man/man1/view.1                  minix-sys
 ./usr/man/man1/vis.1                   minix-sys
 ./usr/man/man1/vol.1                   minix-sys
+./usr/man/man1/wall.1                  minix-sys
 ./usr/man/man1/wait.1                  minix-sys
 ./usr/man/man1/wc.1                    minix-sys
 ./usr/man/man1/what.1                  minix-sys
 ./usr/man/man5/ftpchroot.5                             minix-sys
 ./usr/man/man5/ftpd.conf.5                             minix-sys
 ./usr/man/man5/ftpusers.5                              minix-sys
+./usr/man/man5/gettytab.5                              minix-sys
 ./usr/man/man5/group.5                                 minix-sys
 ./usr/man/man5/hosts.5                                 minix-sys
 ./usr/man/man5/httpd.conf.5                                    minix-sys
 ./usr/man/man5/termcap.5                                       minix-sys
 ./usr/man/man5/terminfo.5                                      minix-sys
 ./usr/man/man5/texinfo.5               minix-sys
+./usr/man/man5/ttys.5                          minix-sys
 ./usr/man/man5/ttytab.5                                        minix-sys
 ./usr/man/man5/TZ.5                                    minix-sys
 ./usr/man/man5/tzfile.5                                        minix-sys
 ./usr/sbin/groupmod                    minix-sys
 ./usr/sbin/i2cscan                     minix-sys
 ./usr/sbin/inet                                minix-sys
-./usr/sbin/init                                minix-sys
+./usr/sbin/init                                minix-sys       obsolete
 ./usr/sbin/installboot_nbsd            minix-sys
 ./usr/sbin/ipc                         minix-sys
 ./usr/sbin/kernel                      minix-sys
index 87d1046d5cd143502b818f3d56c08ec4fc1f3dcd..787954f60731a2e2109b0d176b79ace767cd8109 100644 (file)
@@ -3,7 +3,8 @@
 #include <minix/i2c.h>
 #include <minix/i2cdriver.h>
 #include <minix/log.h>
-#include <minix/reboot.h>
+
+#include <sys/signal.h>
 
 /* Register Addresses */
 #define CHIPID_REG 0x00
@@ -155,7 +156,7 @@ enable_pwr_off(void)
        /* enable power off via the PWR_EN pin. just do the setup here.
         * the kernel will do the work to toggle the pin when the
         * system is ready to be powered off. Should be called during startup
-        * so that shutdown(8) can do power-off with reboot(RBT_POWEROFF).
+        * so that shutdown(8) can do power-off with reboot().
         */
        r = i2creg_write8(bus_endpoint, address, STATUS_REG, PWR_OFF_MASK);
        if (r != OK) {
@@ -228,10 +229,8 @@ intr_handler(void)
 
        if ((val & PBI_MASK) != 0) {
                log_info(&log, "Power Button Pressed\n");
-               reboot(RBT_POWEROFF);
-               log_warn(&log, "Failed to power off the system.");
-               sys_irqenable(&irq_hook_kernel_id);
-               return -1;
+               kill(1, SIGUSR1);       /* tell init to powerdwn */
+               return OK;
        }
 
        /* re-enable interrupt */
index 4f03efc84a3addbc80c4dea27343c4a842c1fdcd..30985ddc21b231833795a829ecb6af117f2cadfc 100644 (file)
@@ -10,6 +10,7 @@
 #include <sys/ioctl.h>
 #include <sys/kbdio.h>
 #include <sys/time.h>
+#include <sys/reboot.h>
 #include <sys/select.h>
 #include <termios.h>
 #include <signal.h>
@@ -18,7 +19,6 @@
 #include <minix/com.h>
 #include <minix/input.h>
 #include <minix/keymap.h>
-#include <minix/reboot.h>
 #include <minix/ds.h>
 #include <assert.h>
 #include "tty.h"
@@ -295,7 +295,7 @@ static unsigned make_break(int scode)
   {
        if (++CAD_count == 3) {
                cons_stop();
-               sys_abort(RBT_DEFAULT);
+               sys_abort(RB_AUTOBOOT);
        }
        sys_kill(INIT_PROC_NR, SIGABRT);
        rebooting = 1;
index db39810687f2e0c9fc61b5d0c020460d6568a3e5..793e61a2e1694e4a0f7f3b765796d111fa4cb664 100644 (file)
@@ -700,6 +700,10 @@ static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
        if (isconsole(tp)) r = con_loadfont(endpt, grant);
        break;
 
+    case TIOCSCTTY:
+       tp->tty_pgrp = user_endpt;
+       break;
+       
 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is 
  * not defined.
  */
index 11f38be7cabe0d68352dee4af9eb103708abe1bd..08cb513bfb09901409004c604a523a3128897d91 100644 (file)
@@ -97,7 +97,7 @@ BIN1+=        boot.cfg.default \
        protocols rc rc.cd rc.subr \
        rc.daemons.dist rs.inet rs.single \
        services shells syslog.conf \
-       termcap utmp
+       termcap utmp gettytab rc.shutdown
 .else
 BIN1+= bootptab changelist csh.cshrc csh.login \
        csh.logout daily daily.conf dm.conf envsys.conf floppytab ftpchroot \
diff --git a/etc/gettytab b/etc/gettytab
new file mode 100644 (file)
index 0000000..111ba33
--- /dev/null
@@ -0,0 +1,154 @@
+#      $NetBSD: gettytab,v 1.18 2006/01/08 22:23:46 dsl Exp $
+#      from: @(#)gettytab      8.2 (Berkeley) 4/20/94
+#
+# Most of the table entries here are just copies of the old getty table,
+# it is by no means certain, or even likely, that any of them are optimal
+# for any purpose whatever.  Nor is it likely that more than a couple are
+# even correct.
+#
+# The default gettytab entry, used to set defaults for all other
+# entries, and in cases where getty is called with no table name
+#
+default:\
+       :ce:ck:np:im=\r\n%s/%m (%h) (%t)\r\n\r\n:
+
+#
+# Fixed speed entries
+#
+#      The "std.NNN" names are known to the special case
+#      portselector code in getty, however they can
+#      be assigned to any table desired.
+#      The "NNN-baud" names are known to the special case
+#      autobaud code in getty, and likewise can
+#      be assigned to any table desired (hopefully the same speed).
+#
+std.110|110-baud:\
+       :sp#110:
+std.300|300-baud:\
+       :sp#300:
+std.600|600-baud:\
+       :sp#600:
+std.1200|1200-baud:\
+       :sp#1200:
+std.2400|2400-baud:\
+       :sp#2400:
+std.4800|4800-baud:\
+       :sp#4800:
+std.9600|9600-baud:\
+       :sp#9600:
+std.19200|19200-baud:\
+       :sp#19200:
+std.38400|38400-baud:\
+       :sp#38400:
+std.57600|57600-baud:\
+       :sp#57600:
+std.115200|115200-baud:\
+       :sp#115200:
+
+# PPP network link login
+#
+# these entries can be used by ISPs or others who want to be able
+# to offer both a "shell" and a PPP login on the same port. Setting
+# the "pp" attribute allows getty(8) to recognize a PPP link start
+# negotiation, and invoke the program listed, in addition to normal
+# login(1).
+#
+# N.B.: if PPP is recognized, this bypasses normal login/password
+# exchange; the expectation is that you'll configure pppd (or whatever)
+# to require a PAP or CHAP handshake for authentication after PPP is
+# started up.
+#
+# It is also recommended that you use hardware (CTS/RTS) flow control
+# on the port, and run the port as fast as possible, to allow modems
+# extra time to do data compression, if enabled.
+#
+ppp:np:ce:ck:pp=/usr/sbin/pppd:
+#
+ppp.19200|PPP-19200:sp#19200:tc=ppp:
+ppp.38400|PPP-38400:sp#38400:tc=ppp:
+ppp.57600|PPP-57600:sp#57600:tc=ppp:
+ppp.115200|PPP-115200:sp#115200:tc=ppp:
+ppp.230400|PPP-230400:sp#230400:tc=ppp:
+
+#
+# Dial in rotary tables, speed selection via 'break'
+#
+d1200|Dial-1200:\
+       :nx=d300:sp#1200:
+d300|Dial-300:\
+       :nx=d1200:sp#300:
+
+#
+# Fast dialup terminals, 2400/1200/300 rotary (can start either way)
+#
+D2400|d2400|Fast-Dial-2400:\
+       :nx=D1200:tc=2400-baud:
+D1200|Fast-Dial-1200:\
+       :nx=D300:tc=1200-baud:
+D300|Fast-Dial-300:\
+       :nx=D2400:tc=300-baud:
+
+#
+#telebit (19200)
+#
+t19200:\
+       :nx=t2400:tc=19200-baud:
+t2400:\
+       :nx=t1200:tc=2400-baud:
+t1200:\
+       :nx=t19200:tc=1200-baud:
+
+#
+#telebit (9600)
+#
+t9600:\
+       :nx=t2400a:tc=19200-baud:
+t2400a:\
+       :nx=t1200a:tc=2400-baud:
+t1200a:\
+       :nx=t9600:tc=1200-baud:
+
+#
+# Odd special case terminals
+#
+Console|Console Decwriter II:\
+       :rw:tc=300-baud:
+
+Console-1200|Console Decwriter III:\
+       :rw:tc=1200-baud:
+
+X|Xwindow|X window system:\
+       :rw:sp#9600:
+
+Pc|Pc console:\
+       :np:ig:ht:
+
+# 8 bit clean Sun console
+suncons|Sun Console:\
+       :np:sp#9600:
+
+#
+# Plugboard, and misc other terminals
+#
+plug-9600|Plugboard-9600:\
+       :pf#1:tc=9600-baud:
+P9600|Plugboard-9600-rotary:\
+       :pf#1:nx=P300:tc=9600-baud:
+P300|Plugboard-300:\
+       :pf#1:nx=P1200:tc=300-baud:
+P1200|Plugboard-1200:\
+       :pf#1:nx=P9600:tc=1200-baud:
+
+#
+# XXXX Port selector
+#
+DSW|Port Selector:\
+       :ps:sp#2400:
+
+#
+# Auto-baud speed detect entry for Micom 600.
+# Special code in getty will switch this out
+# to one of the NNN-baud entries.
+#
+Auto-baud:\
+       :ab:sp#2400:f0#040:
diff --git a/etc/rc b/etc/rc
index 587c6ef73c122ce4a9dab8af265834ed0ea4be1f..58a5f48d6ab4b9c219edcc85849d8b986c8f7438 100755 (executable)
--- a/etc/rc
+++ b/etc/rc
@@ -21,7 +21,7 @@ ARCH="`sysenv arch`"
 
 usage()
 {
-    echo >&2 "Usage: $0 [-saf] start|stop|down"
+    echo >&2 "Usage: $0 [-saf] autoboot|start|stop|down"
     exec intr sh
 }
 
@@ -54,8 +54,12 @@ edit()
     service=$1
     shift
 
-    # Assume binaries are always in /usr/sbin
-    service $opt edit /usr/sbin/$service -label $service "$@" 
+    # Assume binaries are always in /sbin or /usr/sbin
+    binlocation=/usr/sbin/$service
+    if [ ! -x $binlocation ]
+    then       binlocation=/sbin/$service
+    fi
+    service $opt edit $binlocation -label $service "$@" 
 }
 
 while getopts 'saf' opt
@@ -70,14 +74,14 @@ done
 shift `expr $OPTIND - 1`
 
 case "$#:$1" in
-1:start|1:stop|1:down)
+1:start|1:stop|1:down|1:autoboot)
     action=$1
     ;;
 *)  usage
 esac
 
 case $action in
-start)
+autoboot|start)
 
     # National keyboard?
     test -f /etc/keymap && loadkeys /etc/keymap
@@ -104,8 +108,12 @@ start)
     up readclock.drv
     readclock -q || date 201301010000
 
+    # We are not shutting down.
+    rm -f /etc/nologin
+
     # Initialize files.
-    >/etc/utmp                         # /etc/utmp keeps track of logins
+    >/var/run/utmp                             # /etc/utmp keeps track of logins
+    >/var/run/utmpx                            # /etc/utmpx keeps track of logins
 
     # Use MFS binary only from kernel image?
     if [ "`sysenv bin_img`" = 1 ]
@@ -147,10 +155,6 @@ start)
        edit init
     fi
 
-    # This file is necessary for above 'shutdown -C' check.
-    # (Silence stderr in case of running from cd.)
-    touch /usr/adm/wtmp /etc/wtmp 2>/dev/null
-
     if [ "$sflag" ]
     then
        echo "Single user. Press ^D to resume multiuser startup."
@@ -212,6 +216,10 @@ test -f /usr/etc/rc && sh /usr/etc/rc $action
 test -f /usr/local/etc/rc && sh /usr/local/etc/rc $action
 
 # Any messages?
-test "$action" = start -a -f /etc/issue && cat /etc/issue
+if [ "$action" = start -o "$action" = autoboot ]
+then   if [ -f /etc/issue ]
+       then    cat /etc/issue
+       fi
+fi
 
 exit 0
diff --git a/etc/rc.shutdown b/etc/rc.shutdown
new file mode 100644 (file)
index 0000000..9b5e85c
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+sh /etc/rc stop
index 8b248ff53ab2572eaf6d8e5fdeb0aae0ec52c6bc..8e0cb34559324d49296a3a8e449f4e59fd7ef841 100644 (file)
@@ -638,7 +638,7 @@ service tda19988
 
 service tps65217
 {
-       uid 0;          # needed for doing reboot(RBT_POWEROFF)
+       uid 0;          # needed for doing reboot()
        system IRQCTL PRIVCTL;
        irq 7;          # NNMI pin on BeagleBone / BeagleBone Black
        ipc SYSTEM RS DS PM i2c;
index 83ee4b48b8c0e90d466fe38a7fe86205a3ec13e3..7f6c86a15c101fc76ac52de4bbebcd0d9e5413f9 100755 (executable)
--- a/etc/ttys
+++ b/etc/ttys
@@ -3,10 +3,10 @@
 #
 # name         getty           type    status          comments
 #
-console                getty           minix   on secure
-ttyc1          getty           minix   on secure
-ttyc2          getty           minix   on secure
-ttyc3          getty           minix   on secure
+console                "/usr/libexec/getty default"    minix   on secure
+ttyc1          "/usr/libexec/getty default"    minix   on secure
+ttyc2          "/usr/libexec/getty default"    minix   on secure
+ttyc3          "/usr/libexec/getty default"    minix   on secure
 tty00          ""              unknown off secure
 tty01          ""              unknown off secure
 
index 4b19e611efaaa031861851ad799a7c03b858168d..2090c0eba6d423ed5148289b64d1b789b6ae2ad4 100644 (file)
@@ -25,10 +25,13 @@ fi
 bootcd="`/bin/sysenv bootcd`"
 
 case "$#:$1" in
+1:autoboot)
+    action=start
+    ;;
 1:start|1:stop|1:down)
     action=$1
     ;;
-*)  echo >&2 "Usage: $0 start|stop|down"
+*)  echo >&2 "Usage: $0 autoboot|start|stop|down"
     exit 1
 esac
 
@@ -158,7 +161,7 @@ capemgr() {
 DAEMONS=/etc/rc.daemons
 
 case $action in
-start)
+start|autoboot)
     # Select console font.
     test -f /etc/font && loadfont /etc/font </dev/console
 
index db549928f50574f05c461631e1755336d8a4dabc..f0c8f3f2ff0f13e6d06e7214d8a0ff8bb387462f 100644 (file)
@@ -16,7 +16,7 @@ INCS+=        acpi.h audio_fw.h bitmap.h \
        keymap.h log.h mmio.h mount.h mthread.h minlib.h \
        netdriver.h optset.h padconf.h partition.h portio.h \
        priv.h procfs.h profile.h queryparam.h \
-       reboot.h rs.h safecopies.h sched.h sef.h sffs.h \
+       rs.h safecopies.h sched.h sef.h sffs.h \
        sound.h spin.h sys_config.h sysinfo.h \
        syslib.h sysutil.h termios.h timers.h type.h \
        u64.h usb.h usb_ch9.h vbox.h \
diff --git a/include/minix/reboot.h b/include/minix/reboot.h
deleted file mode 100644 (file)
index cdf8a59..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _MINIX_REBOOT_H
-#define _MINIX_REBOOT_H
-
-/* How to exit the system. */
-#define RBT_HALT          0    /* shut down the system */
-#define RBT_REBOOT        1    /* reboot the system */
-#define RBT_PANIC         2    /* the system panics */
-#define RBT_POWEROFF       3    /* power off, reset if not possible */
-#define RBT_RESET         4    /* hard reset the system */
-#define RBT_DEFAULT       5    /* perform the default action du jour */
-#define RBT_INVALID       6    /* first invalid reboot flag */
-
-int reboot(int);
-
-#endif /* _MINIX_REBOOT_H */
index 3a0b6b88bc2d12be7de1ce76f67527bc82c80b5e..e41ef24ff544974613a8bcf8461bcbe9ea0a78f9 100644 (file)
@@ -152,6 +152,12 @@ int tcsetattr(int _filedes, int _opt_actions, const struct termios
 #define VLNEXT            12    /* cc_c[VLNEXT] (^V) */
 #define VDISCARD          13    /* cc_c[VDISCARD] (^O) */
 
+/* Non-functional additions */
+#define VDSUSP         14
+#define VWERASE                15
+#define VSTATUS                16
+#define VEOL2          17
+
 /* Extensions to baud rate settings. */
 #if defined(__minix) && defined(_NETBSD_SOURCE)
 #define B57600         0x0100  /* 57600 baud */
index c51361f75d33bf16fb4c813d4ab8fabdb0e5a310..3eace9572fae3b377b106533508e19300084a0fa 100644 (file)
@@ -22,6 +22,7 @@
 #define        TIOCSWINSZ      _IOW('T', 17, struct winsize)
 #define        TIOCGPGRP       _IOW('T', 18, int)
 #define        TIOCSPGRP       _IOW('T', 19, int)
+#define TIOCSCTTY      _IO ('T', 20)                 /* controlling tty */
 #define TIOCSFON       _IOW_BIG(1, u8_t [8192])
 
 /* Keyboard ioctls. */
index 7d2b1f965491887833f6237878c6c3065b769787..c50e91d0d797b87bbdb5200815acffebd84bc214 100644 (file)
@@ -376,8 +376,8 @@ int  profil(char *, size_t, u_long, u_int);
 void    psignal(int, const char *);
 #endif /* __PSIGNAL_DECLARED */
 int     rcmd(char **, int, const char *, const char *, const char *, int *);
-#ifndef __minix
 int     reboot(int, char *);
+#ifndef __minix
 int     revoke(const char *);
 #endif
 int     rresvport(int *);
index ea05b8519f34c606d4826ea45271930ea9fd6d03..a489cb34f24c25f9f8025e0f508c2f13333798ef 100644 (file)
 #ifndef        _UTMP_H_
 #define        _UTMP_H_
 
-#ifdef __minix
-#define _PATH_UTMP     "/etc/utmp"
-#define _PATH_WTMP     "/usr/adm/wtmp"
-#define _PATH_BTMP     "/usr/adm/btmp"
-#define _PATH_LASTLOG  "/usr/adm/lastlog"
-#define UTMP           _PATH_UTMP
-#define WTMP           _PATH_WTMP
-#define BTMP           _PATH_BTMP
-#else
 #define        _PATH_UTMP      "/var/run/utmp"
 #define        _PATH_WTMP      "/var/log/wtmp"
 #define        _PATH_LASTLOG   "/var/log/lastlog"
-#endif
 
 #define        UT_NAMESIZE     8
-#ifdef __minix
-#define UT_LINESIZE    12
-#else
 #define        UT_LINESIZE     8
-#endif
 #define        UT_HOSTSIZE     16
 
 struct lastlog {
@@ -67,34 +53,12 @@ struct lastlog {
        char    ll_host[UT_HOSTSIZE];
 };
 
-#ifdef __minix
-struct utmp {
-  char ut_name[UT_NAMESIZE];           /* user name */
-  char ut_id[4];               /* /etc/inittab ID */
-  char ut_line[UT_LINESIZE];           /* terminal name */
-  char ut_host[UT_HOSTSIZE];           /* host name, when remote */
-  short ut_pid;                        /* process id */
-  short int ut_type;           /* type of entry */
-  time_t ut_time;                      /* login/logout time */
-};
-
-/* Definitions for ut_type. */
-#define RUN_LVL            1   /* this is a RUN_LEVEL record */
-#define BOOT_TIME          2   /* this is a REBOOT record */
-#define INIT_PROCESS       5   /* this process was spawned by INIT */
-#define LOGIN_PROCESS      6   /* this is a 'getty' process waiting */
-#define USER_PROCESS       7   /* any other user process */
-#define DEAD_PROCESS       8   /* this process has died (wtmp only) */
-
-#else /* !__minix */
-
 struct utmp {
        char    ut_line[UT_LINESIZE];
        char    ut_name[UT_NAMESIZE];
        char    ut_host[UT_HOSTSIZE];
        time_t  ut_time;
 };
-#endif /* __minix */
 
 __BEGIN_DECLS
 int utmpname(const char *);
index 97bc89701ded79caad7ecc1b656820a3a8fd6213..7d5a872de50ca48405f97b4a99c8131df257255a 100644 (file)
@@ -9,8 +9,9 @@
 #include <machine/vm.h>
 #include <io.h>
 
-#include <minix/reboot.h>
 #include <minix/board.h>
+#include <sys/reboot.h>
+
 #include <minix/u64.h>
 
 #include "archconst.h"
@@ -51,25 +52,23 @@ poweroff(void)
 __dead void
 arch_shutdown(int how)
 {
-       switch (how) {
-       case RBT_HALT:
-               /* Hang */
-               for (; ; ) halt_cpu();
-               NOT_REACHABLE;
 
-       case RBT_POWEROFF:
+       if((how & RB_POWERDOWN) == RB_POWERDOWN) {
                /* Power off if possible, hang otherwise */
                poweroff();
                NOT_REACHABLE;
+       }
 
-       default:
-       case RBT_DEFAULT:
-       case RBT_REBOOT:
-       case RBT_RESET:
-               /* Reset the system */
-               reset();
+       if(how & RB_HALT) {
+               /* Hang */
+               for (; ; ) halt_cpu();
                NOT_REACHABLE;
        }
+
+       /* Reset the system */
+       reset();
+       NOT_REACHABLE;
+
        while (1);
 }
 
index c9909017c5d68822e10784fd557453908f8a3330..1c8646761bc50c444b2622a06f6f0cda50466d5f 100644 (file)
@@ -10,7 +10,7 @@
 #include <minix/com.h>
 #include <sys/types.h>
 #include <sys/param.h>
-#include <minix/reboot.h>
+#include <sys/reboot.h>
 #include "string.h"
 #include "arch_proto.h"
 #include "direct_utils.h"
@@ -412,7 +412,7 @@ kinfo_t *pre_init(int argc, char **argv)
  * longer used and the "real" implementations are visible
  */
 void send_diag_sig(void) { }
-void minix_shutdown(minix_timer_t *t) { arch_shutdown(RBT_PANIC); }
+void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
 void busy_delay_ms(int x) { }
 int raise(int n) { panic("raise(%d)\n", n); }
 int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, 
index 0fd32770dbbbbe305314ee56559b4e9cb49790f9..855bd36f23713767646208f3a6fa06aed7ea6443 100644 (file)
@@ -8,7 +8,7 @@
 #include <machine/cpu.h>
 #include <minix/portio.h>
 #include <minix/cpufeature.h>
-#include <minix/reboot.h>
+#include <sys/reboot.h>
 #include <assert.h>
 #include <signal.h>
 #include <machine/vm.h>
@@ -134,30 +134,24 @@ __dead void arch_shutdown(int how)
                        ;
                reset();
        }
+               
+       if((how & RB_POWERDOWN) == RB_POWERDOWN) {
+               /* Power off if possible, hang otherwise */
+               poweroff();
+               NOT_REACHABLE;
+       }
 
-       switch (how) {
-               case RBT_HALT:
-                       /* Hang */
-                       for (; ; ) halt_cpu();
-                       NOT_REACHABLE;
-                       
-               case RBT_POWEROFF:
-                       /* Power off if possible, hang otherwise */
-                       poweroff();
-                       NOT_REACHABLE;
-
-               default:
-               case RBT_DEFAULT:       
-               case RBT_REBOOT:
-               case RBT_RESET:
-                       /* Reset the system by forcing a processor shutdown. 
-                        * First stop the BIOS memory test by setting a soft
-                        * reset flag.
-                        */
-                       reset();
-                       NOT_REACHABLE;
+       if(how & RB_HALT) {
+               /* Hang */
+               for (; ; ) halt_cpu();
+               NOT_REACHABLE;
        }
 
+       /* Reset the system by forcing a processor shutdown. 
+        * First stop the BIOS memory test by setting a soft
+        * reset flag.
+        */
+       reset();
        NOT_REACHABLE;
 }
 
index 165e6d57bb7c3ab1569e2a9661e44df41be44ce3..05801f2beac696f41493bf7aafc0d7db4aa426b1 100644 (file)
@@ -11,7 +11,7 @@
 #include <minix/com.h>
 #include <sys/types.h>
 #include <sys/param.h>
-#include <minix/reboot.h>
+#include <sys/reboot.h>
 #include <machine/partition.h>
 #include "string.h"
 #include "arch_proto.h"
@@ -246,6 +246,6 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx)
 }
 
 void send_diag_sig(void) { }
-void minix_shutdown(minix_timer_t *t) { arch_shutdown(RBT_PANIC); }
+void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); }
 void busy_delay_ms(int x) { }
 int raise(int sig) { panic("raise(%d)\n", sig); }
index d8e3bdf6b9e1cc0d4d6d40c3fc1eaee75c7cf076..f309ea6f8254b5e470824f2d1aa6fadaaab66d05 100644 (file)
@@ -18,7 +18,7 @@
 #include <minix/u64.h>
 #include <minix/board.h>
 #include <minix/type.h>
-#include <minix/reboot.h>
+#include <sys/reboot.h>
 #include "clock.h"
 #include "direct_utils.h"
 #include "hw_intr.h"
@@ -357,8 +357,7 @@ void prepare_shutdown(const int how)
 void minix_shutdown(minix_timer_t *tp)
 {
 /* This function is called from prepare_shutdown or stop_sequence to bring 
- * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the
- * monitor), RBT_RESET (hard reset). 
+ * down MINIX.
  */
   int how;
 
@@ -376,25 +375,17 @@ void minix_shutdown(minix_timer_t *tp)
   hw_intr_disable_all();
   stop_local_timer();
 
-  how = tp ? tmr_arg(tp)->ta_int : RBT_PANIC;
+  how = tp ? tmr_arg(tp)->ta_int : 0;
 
   /* Show shutdown message */
   direct_cls();
-  switch(how) {
-  case RBT_HALT:
+  if((how & RB_POWERDOWN) == RB_POWERDOWN)
+       direct_print("MINIX has halted and will now power off.\n");
+  else if(how & RB_HALT)
        direct_print("MINIX has halted. "
                     "It is safe to turn off your computer.\n");
-       break;
-  case RBT_POWEROFF:
-       direct_print("MINIX has halted and will now power off.\n");
-       break;
-  case RBT_DEFAULT:
-  case RBT_REBOOT:
-  case RBT_RESET:
-  default:
+  else
        direct_print("MINIX will now reset.\n");
-       break;
-  }
   arch_shutdown(how);
 }
 
index deab17decad4e75b3845ac64d2c433b6edab1cc7..d3f3594d4540cc9e1f030cb3bb021003005185ff 100644 (file)
@@ -355,20 +355,14 @@ updwtmpx(const char *file, const struct utmpx *utx)
 #else
                if ((fd = open(file, O_CREAT|O_WRONLY, 0644)) < 0)
                        return -1;
-               if (flock(fd, LOCK_EX) < 0)
-                       return -1;
 #endif
                (void)memset(&ut, 0, sizeof(ut));
                ut.ut_type = SIGNATURE;
                (void)memcpy(ut.ut_user, vers, sizeof(vers));
                if (write(fd, &ut, sizeof(ut)) == -1)
                        goto failed;
-       } else {
-#ifdef __minix
-               if (flock(fd, LOCK_SH) < 0 )
-                       return -1;
-#endif
        }
+
        if (write(fd, utx, sizeof(*utx)) == -1)
                goto failed;
        if (close(fd) == -1)
@@ -455,10 +449,6 @@ getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
 
        if (db == NULL)
                return NULL;
-#ifdef __minix
-       if (flock(db->fd(db), LOCK_SH) < 0)
-               return NULL;
-#endif
 
        key.data = &uid;
        key.size = sizeof(uid);
@@ -503,10 +493,6 @@ updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
        if (db == NULL)
                return -1;
 
-#ifdef __minix
-       if (flock(db->fd(db), LOCK_EX) < 0)
-               return -1;
-#endif
        key.data = &uid;
        key.size = sizeof(uid);
        data.data = ll;
index 9e292cd6f661e3483a82496703324b4d46a3f2bc..08a503e9247440ceb9d7317b1f56ce50b97cd441 100644 (file)
@@ -11,7 +11,7 @@
 #include <string.h>
 #include <sys/reboot.h>
 
-int reboot(int how)
+int reboot(int how, char *bootstr)
 {
   message m;
 
index ef3807889c62be8f7e6fe05708eae40194e09e9e..50774e29456d613fa225b6238e61d84cb7e36bd3 100644 (file)
@@ -99,7 +99,7 @@ void minix_stack_params(const char *path, char * const *argv, char * const *envp
                (*argc)++;
        }
 
-       for (p = envp; *p != NULL; p++) {
+       for (p = envp; p && *p != NULL; p++) {
                size_t const n = sizeof(*p) + strlen(*p) + 1;
                *stack_size += n;
                if (*stack_size < n) {
@@ -156,7 +156,7 @@ void minix_stack_fill(const char *path, int argc, char * const *argv,
        }
        *fpw++ = NULL;
 
-       for (p = envp; *p != NULL; p++) {
+       for (p = envp; p && *p != NULL; p++) {
                size_t const n = strlen(*p) + 1;
                *fpw++= (char *)(*vsp + (fp - frame));
                memcpy(fp, *p, n);
index 9e5554b4c8de0805a2ea8c80427cbac85b7350ac..a78e87652387474494d3f9b2a716d42dd7db311c 100644 (file)
@@ -244,7 +244,7 @@ MAN+=       accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \
        mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \
        munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2 
 .else
-MAN+=  adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2
+MAN+=  adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2 reboot.2
 .endif # !defined(__MINIX)
 .if !defined(__MINIX)
 MAN+=  pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \
index 0fa147ab56c285b016927fd9d09a68f1ca61d1dd..a049890a0a35f4019d00a1328ae4ee4dd27a9e5c 100644 (file)
@@ -146,10 +146,11 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale
 .for i in access.c brk.c close.c environ.c execve.c fork.c fsync.c \
        getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \
        init.c link.c loadname.c lseek.c lseek64.c _mcontext.c mknod.c \
-       mmap.c nanosleep.c open.c pread.c pwrite.c read.c reboot.c sbrk.c \
+       mmap.c nanosleep.c open.c pread.c pwrite.c read.c sbrk.c \
        select.c setuid.c sigprocmask.c stack_utils.c stat.c stime.c \
        syscall.c _ucontext.c umask.c unlink.c waitpid.c write.c \
-       brksize.S _do_kernel_call_intr.S get_minix_kerninfo.S _ipc.S ucontext.S
+       brksize.S _do_kernel_call_intr.S get_minix_kerninfo.S _ipc.S ucontext.S \
+       kill.c
 .PATH.c: ${LIBCDIR}/sys-minix
 .PATH.S: ${ARCHDIR}/sys-minix
 SRCS+= ${i}
index 8994b79aa84d642900b7b3568eab6f9772633d50..16898a348484c2683008f04ad7b845930f1d1dcc 100644 (file)
@@ -42,7 +42,7 @@ SRCS+=        efun.c \
        passwd.c pw_scan.c pidfile.c pidlock.c pty.c \
        raise_default_signal.c \
        secure_path.c stat_flags.c \
-       strpct.c ttyaction.c \
+       strpct.c ttyaction.c ttymsg.c \
 
 MAN=   efun.3 \
        getmntopts.3 \
index 6017ec65870279d5daf24baffb3eadfb88c3fabd..13f54a3390faf49a239924fb1ecef7e2378080dc 100644 (file)
@@ -5,7 +5,8 @@
 
 SUBDIR= \
        fingerd ftpd    \
-       ld.elf_so
+       ld.elf_so       \
+       getty
 
 .if defined(__MINIX)
 SUBDIR+= makewhatis
diff --git a/libexec/getty/Makefile b/libexec/getty/Makefile
new file mode 100644 (file)
index 0000000..6f0be04
--- /dev/null
@@ -0,0 +1,12 @@
+#      $NetBSD: Makefile,v 1.19 2010/02/03 15:34:43 roy Exp $
+#      from: @(#)Makefile      8.1 (Berkeley) 6/4/93
+
+WARNS?=        2       # XXX: many const & sign-compare issues
+
+PROG=  getty
+SRCS=  main.c init.c subr.c
+DPADD+=        ${LIBUTIL} ${LIBTERMINFO}
+LDADD+=        -lutil -lterminfo
+MAN=   getty.8 gettytab.5 ttys.5
+
+.include <bsd.prog.mk>
diff --git a/libexec/getty/extern.h b/libexec/getty/extern.h
new file mode 100644 (file)
index 0000000..e0eb4af
--- /dev/null
@@ -0,0 +1,52 @@
+/*     $NetBSD: extern.h,v 1.6 2003/08/07 09:46:41 agc Exp $   */
+
+/*
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)extern.h      8.1 (Berkeley) 6/4/93
+ */
+
+struct delayval;
+
+int     adelay(int, struct delayval *);
+char   *autobaud(void);
+int     delaybits(void);
+void    edithost(char *);
+void    gendefaults(void);
+int     getent(char *, char *);
+int     getflag(char *);
+long    getnum(char *);
+char   *getstr(char *, char **);
+void    gettable(char *, char *);
+void    makeenv(char *[]);
+char   *portselector(void);
+void    set_ttydefaults(int);
+void    setchars(void);
+void    setdefaults(void);
+void    setflags(int);
+int     speed(int);
diff --git a/libexec/getty/getty.8 b/libexec/getty/getty.8
new file mode 100644 (file)
index 0000000..16d8d96
--- /dev/null
@@ -0,0 +1,177 @@
+.\"    $NetBSD: getty.8,v 1.17 2003/08/07 09:46:42 agc Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)getty.8      8.1 (Berkeley) 6/4/93
+.\"
+.Dd December 12, 1998
+.Dt GETTY 8
+.Os
+.Sh NAME
+.Nm getty ,
+.Nm uugetty
+.Nd set terminal modes for system access
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Ar type
+.Op Ar tty
+.Oc
+.Nm uugetty
+.Oo
+.Ar type
+.Op Ar tty
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+program
+is called by
+.Xr init 8
+to open and initialize the tty line, read a login name, and invoke
+.Xr login 1 .
+The devices on which to run
+.Nm
+are normally determined by
+.Xr ttys 5 .
+.Pp
+The
+.Nm
+program can also recognize a Point to Point Protocol
+.Pq Tn PPP
+negotiation, and, if the
+.Sy pp
+attribute in
+.Xr gettytab 5
+is set, invoke the program given by that string, e.g.,
+.Xr pppd 8 ,
+instead of
+.Xr login 1 .
+This makes it possible to use a single serial port for either a
+.Qq shell
+account with command line interface, or a
+.Tn PPP
+network link.
+.Pp
+The argument
+.Ar tty
+is the special device file in
+.Pa /dev
+to open for the terminal
+.Po
+for example,
+.Qq ttyh0
+.Pc .
+If there is no argument or the argument is
+.Ql Fl ,
+the tty line is assumed to be open as file descriptor 0.
+.Pp
+The
+.Ar type
+argument can be used to make
+.Nm
+treat the terminal line specially.
+This argument is used as an index into the
+.Xr gettytab 5
+database, to determine the characteristics of the line.
+If there is no argument, or there is no such table, the
+.Em default
+table is used.
+If there is no
+.Pa /etc/gettytab
+a set of system defaults is used.
+If indicated by the table located,
+.Nm
+will clear the terminal screen,
+print a banner heading,
+and prompt for a login name.
+Usually either the banner or the login prompt will include
+the system hostname.
+.Pp
+.Nm
+uses the
+.Xr ttyaction 3
+facility with an action of
+.Qq getty
+and user
+.Qq root
+to execute site-specific commands when it starts.
+.Pp
+Most of the default actions of
+.Nm
+can be circumvented, or modified, by a suitable
+.Xr gettytab 5
+table.
+.Pp
+The
+.Nm
+program can be set to timeout after some interval,
+which will cause dial up lines to hang up
+if the login name is not entered reasonably quickly.
+.Pp
+The
+.Nm uugetty
+program is the same, except that it uses
+.Xr pidlock 3
+to respect the locks in
+.Pa /var/spool/lock
+of processes that dial out on that tty.
+.Sh FILES
+.Bl -tag -width /var/spool/lock/LCK..ttyXX -compact
+.It Pa /etc/gettytab
+.It Pa /etc/ttys
+.It Pa /var/spool/lock/LCK..ttyXX
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ttyxx: No such device or address."
+.It "ttyxx: No such file or address."
+A terminal which is turned on in the
+.Xr ttys 5
+file cannot be opened, likely because the requisite
+lines are either not configured into the system, the associated device
+was not attached during boot-time system configuration,
+or the special file in
+.Pa /dev
+does not exist.
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr ioctl 2 ,
+.Xr pidlock 3 ,
+.Xr ttyaction 3 ,
+.Xr tty 4 ,
+.Xr gettytab 5 ,
+.Xr ttys 5 ,
+.Xr init 8 ,
+.Xr pppd 8
+.Sh HISTORY
+A
+.Nm
+program appeared in
+.At v6 .
diff --git a/libexec/getty/gettytab.5 b/libexec/getty/gettytab.5
new file mode 100644 (file)
index 0000000..f2e7bde
--- /dev/null
@@ -0,0 +1,423 @@
+.\"    $NetBSD: gettytab.5,v 1.36 2012/04/21 12:27:28 roy Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)gettytab.5   8.4 (Berkeley) 4/19/94
+.\"
+.Dd April 5, 2012
+.Dt GETTYTAB 5
+.Os
+.Sh NAME
+.Nm gettytab
+.Nd terminal configuration data base
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+file
+is a simplified version of the
+.Xr capfile 5
+data base
+used to describe terminal lines.
+The initial terminal login process
+.Xr getty 8
+accesses the
+.Nm
+file each time it starts, allowing simpler
+reconfiguration of terminal characteristics.
+Each entry in the data base
+is used to describe one class of terminals.
+.Pp
+Where to run
+.Xr getty 8
+processes is normally defined by
+.Xr ttys 5 .
+.Pp
+There is a default terminal class,
+.Em default ,
+that is used to set global defaults for all other classes.
+(That is, the
+.Em default
+entry is read, then the entry for the class required
+is used to override particular settings.)
+The
+.Em default
+entry is also normally read by other programs that present login prompts
+to the user, such as
+.Xr telnetd 8 ,
+in order to retrieve the values of the
+.Em he ,
+.Em hn ,
+.Em im ,
+and
+.Em if
+capabilities.
+.Sh CAPABILITIES
+Refer to
+.Xr capfile 5
+for a description of the file layout.
+The
+.Em default
+column below lists defaults obtained if there is
+no entry in the table obtained, nor one in the special
+.Em default
+table.
+.Bl -column Namexx /usr/bin/login Default
+.It Sy Name    Type    Default Description
+.It "ab        bool    false   Auto-baud speed select mechanism for the Micom 600 portselector. Selection is done by looking at how the character `\er' is garbled at 300, 1200, 4800, and 9600 baud."
+.It "al        str     NULL    user to auto-login instead of prompting"
+.It "ap        bool    false   terminal uses any parity"
+.It "bk        str     0377    alternative end of line character (input break)"
+.It "b2        str     0377    alternative end of line character (input break)"
+.It "c0        num     unused  tty control flags to write messages"
+.It "c1        num     unused  tty control flags to read login name"
+.It "c2        num     unused  tty control flags to leave terminal as"
+.It "ce        bool    false   use crt erase algorithm"
+.It "ck        bool    false   use crt kill algorithm"
+.It "cl        str" Ta Dv NULL Ta
+.No "screen clear sequence"
+.It "co        bool    false   console - add"
+.Ql \er\en
+after login prompt
+.It "cs        bool    false   clear screen based on terminal type in /etc/ttys"
+.It "ds        str" Ta So Li ^Y Sc Ta
+.No "delayed suspend character"
+.It "dx        bool    false   set"
+.Dv DECCTLQ
+.It "ec        bool    false   leave echo"
+.Tn OFF
+.It "ep        bool    false   terminal uses even parity"
+.It "er        str" Ta So Li ^? Sc Ta
+.No "erase character"
+.It "et        str" Ta So Li ^D Sc Ta
+.No "end of text"
+.Pq Dv EOF
+character
+.It "ev        str" Ta Dv NULL Ta
+.No "initial environment"
+.It "f0        num     unused  tty mode flags to write messages"
+.It "f1        num     unused  tty mode flags to read login name"
+.It "f2        num     unused  tty mode flags to leave terminal as"
+.It "fl        str" Ta So Li ^O Sc Ta
+.No "output flush character"
+.It "hc        bool    false   do"
+.Tn NOT
+hangup line on last close
+.It "he        str" Ta Dv NULL Ta
+.No "hostname editing string"
+.It "hn        str     hostname        hostname"
+.It "ht        bool    false   terminal has real tabs"
+.It "i0        num     unused  tty input flags to write messages"
+.It "i1        num     unused  tty input flags to read login name"
+.It "i2        num     unused  tty input flags to leave terminal as"
+.It "if        str     NULL    display named file before prompt, like /etc/issue"
+.It "ig        bool    false   ignore garbage characters in login name"
+.It "im        str" Ta Dv NULL Ta
+.No "initial (banner) message"
+.It "in        str" Ta So Li ^C Sc Ta
+.No "interrupt character"
+.It "is        num     unused  input speed"
+.It "kl        str" Ta So Li ^U Sc Ta
+.No "kill character"
+.It "l0        num     unused  tty local flags to write messages"
+.It "l1        num     unused  tty local flags to read login name"
+.It "l2        num     unused  tty local flags to leave terminal as"
+.It "lc        bool    false   terminal has lower case"
+.It "lm        str     login:  login prompt"
+.It "ln        str" Ta So Li ^V Sc Ta
+.No "``literal next'' character"
+.It "lo        str" Ta Pa /usr/bin/login Ta
+.No "program to exec when name obtained"
+.It "mb        bool    false   do flow control based on carrier"
+.It "nl        bool    false   terminal has (or might have) a newline character"
+.It "nn        bool    false   do not prompt for a login name"
+.It "np        bool    false   terminal uses no parity (i.e. 8-bit characters)"
+.It "nx        str     default next table (for auto speed selection)"
+.It "o0        num     unused  tty output flags to write messages"
+.It "o1        num     unused  tty output flags to read login name"
+.It "o2        num     unused  tty output flags to leave terminal as"
+.It "op        bool    false   terminal uses odd parity"
+.It "os        num     unused  output speed"
+.It "pc        str" Ta So Li \e0 Sc Ta
+.No "pad character"
+.It "pe        bool    false   use printer (hard copy) erase algorithm"
+.It "pf        num     0       delay"
+between first prompt and following flush (seconds)
+.It "pp        str     unused  PPP authentication program"
+.It "ps        bool    false   line connected to a"
+.Tn MICOM
+port selector
+.It "qu        str" Ta So Li \&^\e Sc Ta
+.No "quit character"
+.It "rp        str" Ta So Li ^R Sc Ta
+.No "line retype character"
+.It "rw        bool    false   do"
+.Tn NOT
+use raw for input, use cbreak
+.It "sp        num     unused  line speed (input and output)"
+.It "st        str" Ta So Li ^T Sc Ta
+.No "status character"
+.It "su        str" Ta So Li ^Z Sc Ta
+.No "suspend character"
+.It "tc        str     none    table continuation"
+.It "to        num     0       timeout (seconds)"
+.It "tt        str" Ta Dv NULL Ta
+.No "terminal type (for environment)"
+.It "ub        bool    false   do unbuffered output (of prompts etc)"
+.It "we        str" Ta So Li ^W Sc Ta
+.No "word erase character"
+.It "xc        bool    false   do"
+.Tn NOT
+echo control chars as
+.Ql ^X
+.It "xf        str" Ta So Li ^S Sc Ta Dv XOFF
+(stop output) character
+.It "xn        str" Ta So Li ^Q Sc Ta Dv XON
+(start output) character
+.El
+.Pp
+The following capabilities are no longer supported by
+.Xr getty 8 :
+.Bl -column Namexx /usr/bin/login Default
+.It "bd        num     0       backspace delay"
+.It "cb        bool    false   use crt backspace mode"
+.It "cd        num     0       carriage-return delay"
+.It "fd        num     0       form-feed (vertical motion) delay"
+.It "nd        num     0       newline (line-feed) delay"
+.It "uc        bool    false   terminal is known upper case only"
+.El
+.Pp
+If no line speed is specified, speed will not be altered
+from that which prevails when getty is entered.
+Specifying an input or output speed will override
+line speed for stated direction only.
+.Pp
+Terminal modes to be used for the output of the message,
+for input of the login name,
+and to leave the terminal set as upon completion,
+are derived from the boolean flags specified.
+If the derivation should prove inadequate,
+any (or all) of these three may be overridden
+with one of the
+.Em \&c0 ,
+.Em \&c1 ,
+.Em \&c2 ,
+.Em \&i0 ,
+.Em \&i1 ,
+.Em \&i2 ,
+.Em \&l0 ,
+.Em \&l1 ,
+.Em \&l2 ,
+.Em \&o0 ,
+.Em \&o1 ,
+or
+.Em \&o2
+numeric specifications, which can be used to specify
+(usually in octal, with a leading '0')
+the exact values of the flags.
+These flags correspond to the termios
+.Em c_cflag ,
+.Em c_iflag ,
+.Em c_lflag ,
+and
+.Em c_oflag
+fields, respectively.
+Each these sets must be completely specified to be effective.
+The
+.Em \&f0 ,
+.Em \&f1 ,
+and
+.Em \&f2
+are excepted for backwards compatibility with a previous incarnation of
+the TTY sub-system.
+In these flags the bottom 16 bits of the (32 bits) value contain the sgttyb
+.Em sg_flags
+field, while the top 16 bits represent the local mode word.
+.Pp
+Should
+.Xr getty 8
+receive a null character
+(presumed to indicate a line break)
+it will restart using the table indicated by the
+.Em nx
+entry.
+If there is none, it will re-use its original table.
+.Pp
+Delays are specified in milliseconds, the nearest possible
+delay available in the tty driver will be used.
+Should greater certainty be desired, delays
+with values 0, 1, 2, and 3 are interpreted as
+choosing that particular delay algorithm from the driver.
+.Pp
+The
+.Em \&cl
+screen clear string may be preceded by a (decimal) number
+of milliseconds of delay required (a la termcap).
+This delay is simulated by repeated use of the pad character
+.Em \&pc .
+.Pp
+The initial message, and login message,
+.Em \&im
+and
+.Em \&lm
+may include any of the following character sequences, which expand to
+information about the environment in which
+.Xr getty 8
+is running.
+.Pp
+.Bl -tag -width \&%xxx -compact
+.It \&%d
+The current date.
+.It \&%h
+The hostname of the machine, which is normally obtained from the
+system using
+.Xr gethostname 3 ,
+but may also be overridden by the
+.Em \&hn
+table entry.
+In either case it may be edited with the
+.Em \&he
+string.
+A '@' in the
+.Em \&he
+string causes one character from the real hostname to
+be copied to the final hostname.
+A '#' in the
+.Em \&he
+string causes the next character of the real hostname
+to be skipped.
+Each character that
+is neither '@' nor '#' is copied into the final hostname.
+Surplus '@' and '#' characters are ignored.
+.It \&%t
+The tty name.
+.It "\&%m, \&%r, \&%s, \&%v"
+The type of machine, release of the operating system, name of the
+operating system, and version of the kernel, respectively, as
+returned by
+.Xr uname 3 .
+.It \&%%
+A
+.Dq %
+character.
+.El
+.Pp
+When getty execs the login process, given
+in the
+.Em \&lo
+string (usually
+.Dq Pa /usr/bin/login ) ,
+it will have set
+the environment to include the terminal type, as indicated
+by the
+.Em \&tt
+string (if it exists).
+The
+.Em \&ev
+string, can be used to enter additional data into
+the environment.
+It is a list of comma separated strings, each of which
+will presumably be of the form
+.Em name=value .
+.Pp
+If a non-zero timeout is specified, with
+.Em \&to ,
+then getty will exit within the indicated
+number of seconds, either having
+received a login name and passed control
+to
+.Xr login 1 ,
+or having received an alarm signal, and exited.
+This may be useful to hangup dial in lines.
+.Pp
+Output from
+.Xr getty 8
+is even parity unless
+.Em \&op
+or
+.Em \&np
+is specified.
+The
+.Em \&op
+string
+may be specified with
+.Em \&ap
+to allow any parity on input, but generate odd parity output.
+Note: this only applies while getty is being run,
+terminal driver limitations prevent a more complete
+implementation.
+.Xr getty 8
+does not check parity of input characters in
+.Dv RAW
+mode.
+.Pp
+If
+.Em \&pp
+string is specified and a Point to Point Protocol
+.Pq Tn PPP
+link bringup sequence is recognized,
+.Xr getty 8
+will invoke the program referenced by the
+.Em \&pp
+string, e.g.
+.Xr pppd 8 .
+This can be used to handle incoming
+.Tn PPP
+calls.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr gethostname 3 ,
+.Xr uname 3 ,
+.Xr capfile 5 ,
+.Xr ttys 5 ,
+.Xr getty 8 ,
+.Xr pppd 8 ,
+.Xr telnetd 8
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.2 .
+.Sh BUGS
+The special characters (erase, kill, etc.) are reset to system defaults
+by
+.Xr login 1 .
+In
+.Em all
+cases, '#' or '^H' typed in a login name will be treated as
+an erase character, and '@' will be treated as a kill character.
+.Pp
+The delay stuff is a real crock.
+Apart from its general lack of flexibility, some
+of the delay algorithms are not implemented.
+The terminal driver should support sane delay settings.
+.Pp
+The
+.Em \&he
+capability is stupid.
diff --git a/libexec/getty/gettytab.h b/libexec/getty/gettytab.h
new file mode 100644 (file)
index 0000000..a69e063
--- /dev/null
@@ -0,0 +1,173 @@
+/*     $NetBSD: gettytab.h,v 1.16 2006/11/16 04:31:24 christos Exp $   */
+
+/*
+ * Copyright (c) 1983, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)gettytab.h    8.2 (Berkeley) 3/30/94
+ */
+
+/*
+ * Getty description definitions.
+ */
+struct gettystrs {
+       char    *field;         /* name to lookup in gettytab */
+       char    *defalt;        /* value we find by looking in defaults */
+       char    *value;         /* value that we find there */
+};
+
+struct gettynums {
+       char    *field;         /* name to lookup */
+       long    defalt;         /* number we find in defaults */
+       long    value;          /* number we find there */
+       int     set;            /* we actually got this one */
+};
+
+struct gettyflags {
+       char    *field;         /* name to lookup */
+       char    invrt;          /* name existing in gettytab --> false */
+       char    defalt;         /* true/false in defaults */
+       char    value;          /* true/false flag */
+       char    set;            /* we found it */
+};
+
+/*
+ * See init.c for the arrays indexed by these values.
+ */
+
+/*
+ * String values.
+ */
+#define        NX      gettystrs[0].value
+#define        CL      gettystrs[1].value
+#define IM     gettystrs[2].value
+#define        LM      gettystrs[3].value
+#define        ER      gettystrs[4].value
+#define        KL      gettystrs[5].value
+#define        ET      gettystrs[6].value
+#define        PC      gettystrs[7].value
+#define        TT      gettystrs[8].value
+#define        EV      gettystrs[9].value
+#define        LO      gettystrs[10].value
+#define HN     gettystrs[11].value
+#define HE     gettystrs[12].value
+#define IN     gettystrs[13].value
+#define QU     gettystrs[14].value
+#define XN     gettystrs[15].value
+#define XF     gettystrs[16].value
+#define BK     gettystrs[17].value
+#define SU     gettystrs[18].value
+#define DS     gettystrs[19].value
+#define RP     gettystrs[20].value
+#define FL     gettystrs[21].value
+#define WE     gettystrs[22].value
+#define LN     gettystrs[23].value
+#define ST     gettystrs[24].value
+#define B2     gettystrs[25].value
+#define PP     gettystrs[26].value
+#define IF     gettystrs[27].value
+#define AL     gettystrs[28].value
+
+/*
+ * Numeric definitions.
+ */
+#define        IS      gettynums[0].value
+#define        OS      gettynums[1].value
+#define        SP      gettynums[2].value
+#define        ND      gettynums[3].value
+#define        CD      gettynums[4].value
+#define        TD      gettynums[5].value
+#define        FD      gettynums[6].value
+#define        BD      gettynums[7].value
+#define        TO      gettynums[8].value
+#define        F0      gettynums[9].value
+#define        F0set   gettynums[9].set
+#define        F1      gettynums[10].value
+#define        F1set   gettynums[10].set
+#define        F2      gettynums[11].value
+#define        F2set   gettynums[11].set
+#define        PF      gettynums[12].value
+#define        C0      gettynums[13].value
+#define        C0set   gettynums[13].set
+#define        C1      gettynums[14].value
+#define        C1set   gettynums[14].set
+#define        C2      gettynums[15].value
+#define        C2set   gettynums[15].set
+#define        I0      gettynums[16].value
+#define        I0set   gettynums[16].set
+#define        I1      gettynums[17].value
+#define        I1set   gettynums[17].set
+#define        I2      gettynums[18].value
+#define        I2set   gettynums[18].set
+#define        L0      gettynums[19].value
+#define        L0set   gettynums[19].set
+#define        L1      gettynums[20].value
+#define        L1set   gettynums[20].set
+#define        L2      gettynums[21].value
+#define        L2set   gettynums[21].set
+#define        O0      gettynums[22].value
+#define        O0set   gettynums[22].set
+#define        O1      gettynums[23].value
+#define        O1set   gettynums[23].set
+#define        O2      gettynums[24].value
+#define        O2set   gettynums[24].set
+
+/*
+ * Boolean values.
+ */
+#define        HT      gettyflags[0].value
+#define        NL      gettyflags[1].value
+#define        EP      gettyflags[2].value
+#define        EPset   gettyflags[2].set
+#define        OP      gettyflags[3].value
+#define        OPset   gettyflags[3].set
+#define        AP      gettyflags[4].value
+#define        APset   gettyflags[4].set
+#define        EC      gettyflags[5].value
+#define        CO      gettyflags[6].value
+#define        CB      gettyflags[7].value
+#define        CK      gettyflags[8].value
+#define        CE      gettyflags[9].value
+#define        PE      gettyflags[10].value
+#define        RW      gettyflags[11].value
+#define        XC      gettyflags[12].value
+#define        LC      gettyflags[13].value
+#define        UC      gettyflags[14].value
+#define        IG      gettyflags[15].value
+#define        PS      gettyflags[16].value
+#define        HC      gettyflags[17].value
+#define UB     gettyflags[18].value
+#define AB     gettyflags[19].value
+#define DX     gettyflags[20].value
+#define        NP      gettyflags[21].value
+#define        MB      gettyflags[22].value
+#define        CS      gettyflags[23].value
+#define        NN      gettyflags[24].value
+
+extern struct gettyflags gettyflags[];
+extern struct gettynums gettynums[];
+extern struct gettystrs gettystrs[];
diff --git a/libexec/getty/init.c b/libexec/getty/init.c
new file mode 100644 (file)
index 0000000..c49c787
--- /dev/null
@@ -0,0 +1,146 @@
+/*     $NetBSD: init.c,v 1.17 2007/12/03 09:54:24 isaki Exp $  */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)init.c       8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: init.c,v 1.17 2007/12/03 09:54:24 isaki Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Getty table initializations.
+ *
+ * Melbourne getty.
+ */
+
+#include <termios.h>
+
+#include "gettytab.h"
+#include "pathnames.h"
+
+extern struct termios tmode;
+extern char hostname[];
+
+#define M(a) ((char *)&tmode.c_cc[a])
+
+struct gettystrs gettystrs[] = {
+       { "nx" },               /* next table */
+       { "cl" },               /* screen clear characters */
+       { "im" },               /* initial message */
+       { "lm", "login: " },    /* login message */
+       { "er", M(VERASE) },    /* erase character */
+       { "kl", M(VKILL) },     /* kill character */
+       { "et", M(VEOF) },      /* eof chatacter (eot) */
+       { "pc", "" },           /* pad character */
+       { "tt" },               /* terminal type */
+       { "ev" },               /* environment */
+       { "lo", _PATH_LOGIN },  /* login program */
+       { "hn", hostname },     /* host name */
+       { "he" },               /* host name edit */
+       { "in", M(VINTR) },     /* interrupt char */
+       { "qu", M(VQUIT) },     /* quit char */
+       { "xn", M(VSTART) },    /* XON (start) char */
+       { "xf", M(VSTOP) },     /* XOFF (stop) char */
+       { "bk", M(VEOL) },      /* brk char (alt \n) */
+       { "su", M(VSUSP) },     /* suspend char */
+       { "ds", M(VDSUSP) },    /* delayed suspend */
+       { "rp", M(VREPRINT) },  /* reprint char */
+       { "fl", M(VDISCARD) },  /* flush output */
+       { "we", M(VWERASE) },   /* word erase */
+       { "ln", M(VLNEXT) },    /* literal next */
+       { "st", M(VSTATUS) },   /* status */
+       { "b2", M(VEOL2) },     /* alt brk char */
+       { "pp" },               /* ppp login program */
+       { "if" },               /* sysv-like 'issue' filename */
+       { "al" },               /* user to auto-login */
+       { 0 }
+};
+
+struct gettynums gettynums[] = {
+       { "is" },                       /* input speed */
+       { "os" },                       /* output speed */
+       { "sp" },                       /* both speeds */
+       { "nd" },                       /* newline delay */
+       { "cd" },                       /* carriage-return delay */
+       { "td" },                       /* tab delay */
+       { "fd" },                       /* form-feed delay */
+       { "bd" },                       /* backspace delay */
+       { "to" },                       /* timeout */
+       { "f0" },                       /* output flags */
+       { "f1" },                       /* input flags */
+       { "f2" },                       /* user mode flags */
+       { "pf" },                       /* delay before flush at 1st prompt */
+       { "c0" },                       /* output c_flags */
+       { "c1" },                       /* input c_flags */
+       { "c2" },                       /* user mode c_flags */
+       { "i0" },                       /* output i_flags */
+       { "i1" },                       /* input i_flags */
+       { "i2" },                       /* user mode i_flags */
+       { "l0" },                       /* output l_flags */
+       { "l1" },                       /* input l_flags */
+       { "l2" },                       /* user mode l_flags */
+       { "o0" },                       /* output o_flags */
+       { "o1" },                       /* input o_flags */
+       { "o2" },                       /* user mode o_flags */
+       { 0 }
+};
+
+struct gettyflags gettyflags[] = {
+       { "ht", 0 },                    /* has tabs */
+       { "nl", 1 },                    /* has newline char */
+       { "ep", 0 },                    /* even parity */
+       { "op", 0 },                    /* odd parity */
+       { "ap", 0 },                    /* any parity */
+       { "ec", 1 },                    /* no echo */
+       { "co", 0 },                    /* console special */
+       { "cb", 0 },                    /* crt backspace */
+       { "ck", 0 },                    /* crt kill */
+       { "ce", 0 },                    /* crt erase */
+       { "pe", 0 },                    /* printer erase */
+       { "rw", 1 },                    /* don't use raw */
+       { "xc", 1 },                    /* don't ^X ctl chars */
+       { "lc", 0 },                    /* terminal las lower case */
+       { "uc", 0 },                    /* terminal has no lower case */
+       { "ig", 0 },                    /* ignore garbage */
+       { "ps", 0 },                    /* do port selector speed select */
+       { "hc", 1 },                    /* don't set hangup on close */
+       { "ub", 0 },                    /* unbuffered output */
+       { "ab", 0 },                    /* auto-baud detect with '\r' */
+       { "dx", 0 },                    /* set decctlq */
+       { "np", 0 },                    /* no parity at all (8bit chars) */
+       { "mb", 0 },                    /* do MDMBUF flow control */
+       { "cs", 0 },                    /* clear screen based on term type */
+       { "nn", 0 },                    /* don't prompt for login name */
+       { 0 }
+};
diff --git a/libexec/getty/main.c b/libexec/getty/main.c
new file mode 100644 (file)
index 0000000..f308ae1
--- /dev/null
@@ -0,0 +1,707 @@
+/*     $NetBSD: main.c,v 1.59 2012/06/28 08:55:10 roy Exp $    */
+
+/*-
+ * Copyright (c) 1980, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)main.c       8.1 (Berkeley) 6/20/93";
+#else
+__RCSID("$NetBSD: main.c,v 1.59 2012/06/28 08:55:10 roy Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <term.h>
+#include <time.h>
+#include <ttyent.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "gettytab.h"
+#include "pathnames.h"
+#include "extern.h"
+
+extern char editedhost[];
+
+/*
+ * Set the amount of running time that getty should accumulate
+ * before deciding that something is wrong and exit.
+ */
+#define GETTY_TIMEOUT  60 /* seconds */
+
+/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
+
+#define PPP_FRAME           0x7e  /* PPP Framing character */
+#define PPP_STATION         0xff  /* "All Station" character */
+#define PPP_ESCAPE          0x7d  /* Escape Character */
+#define PPP_CONTROL         0x03  /* PPP Control Field */
+#define PPP_CONTROL_ESCAPED 0x23  /* PPP Control Field, escaped */
+#define PPP_LCP_HI          0xc0  /* LCP protocol - high byte */
+#define PPP_LCP_LOW         0x21  /* LCP protocol - low byte */
+
+struct termios tmode, omode;
+
+int crmod, digit_or_punc, lower, upper;
+
+char   hostname[MAXHOSTNAMELEN + 1];
+struct utsname kerninfo;
+char   name[LOGIN_NAME_MAX];
+char   dev[] = _PATH_DEV;
+char   ttyn[32];
+char   lockfile[512];
+uid_t  ttyowner;
+char   *rawttyn;
+
+#define        OBUFSIZ         128
+#define        TABBUFSIZ       512
+
+char   defent[TABBUFSIZ];
+char   tabent[TABBUFSIZ];
+
+char   *env[128];
+
+const unsigned char partab[] = {
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0202,0004,0003,0205,0005,0206,0201,0001,
+       0201,0001,0001,0201,0001,0201,0201,0001,
+       0001,0201,0201,0001,0201,0001,0001,0201,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0200,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0200,0000,0000,0200,0000,0200,0200,0000,
+       0000,0200,0200,0000,0200,0000,0000,0201
+};
+
+#define        ERASE   tmode.c_cc[VERASE]
+#define        KILL    tmode.c_cc[VKILL]
+#define        EOT     tmode.c_cc[VEOF]
+
+static void    clearscreen(void);
+
+jmp_buf timeout;
+
+static void
+/*ARGSUSED*/
+dingdong(int signo)
+{
+
+       (void)alarm(0);
+       (void)signal(SIGALRM, SIG_DFL);
+       longjmp(timeout, 1);
+}
+
+jmp_buf        intrupt;
+
+static void
+/*ARGSUSED*/
+interrupt(int signo)
+{
+
+       (void)signal(SIGINT, interrupt);
+       longjmp(intrupt, 1);
+}
+
+#ifndef __minix
+/*
+ * Action to take when getty is running too long.
+ */
+static void
+/*ARGSUSED*/
+timeoverrun(int signo)
+{
+
+       syslog(LOG_ERR, "getty exiting due to excessive running time");
+       exit(1);
+}
+#endif
+
+static int     getname(void);
+static void    oflush(void);
+static void    prompt(void);
+static int     putchr(int);
+static void    putf(const char *);
+static void    xputs(const char *);
+
+#define putpad(s) tputs(s, 1, putchr)
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+       const char *progname;
+       char *tname;
+       int repcnt = 0, failopenlogged = 0, uugetty = 0, first_time = 1;
+       struct rlimit limit;
+       struct passwd *pw;
+       int rval;
+
+       (void)signal(SIGINT, SIG_IGN);
+       openlog("getty", LOG_PID, LOG_AUTH);
+       (void)gethostname(hostname, sizeof(hostname));
+       hostname[sizeof(hostname) - 1] = '\0';
+       if (hostname[0] == '\0')
+               (void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
+       (void)uname(&kerninfo);
+
+       progname = getprogname();
+       if (progname[0] == 'u' && progname[1] == 'u')
+               uugetty = 1;
+
+       /*
+        * Find id of uucp login (if present) so we can chown tty properly.
+        */
+       if (uugetty && (pw = getpwnam("uucp")))
+               ttyowner = pw->pw_uid;
+       else
+               ttyowner = 0;
+
+       /*
+        * Limit running time to deal with broken or dead lines.
+        */
+#ifndef __minix
+       (void)signal(SIGXCPU, timeoverrun);
+       limit.rlim_max = RLIM_INFINITY;
+       limit.rlim_cur = GETTY_TIMEOUT;
+       (void)setrlimit(RLIMIT_CPU, &limit);
+#endif
+
+       /*
+        * The following is a work around for vhangup interactions
+        * which cause great problems getting window systems started.
+        * If the tty line is "-", we do the old style getty presuming
+        * that the file descriptors are already set up for us.
+        * J. Gettys - MIT Project Athena.
+        */
+       if (argc <= 2 || strcmp(argv[2], "-") == 0) {
+               (void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
+       }
+       else {
+               int i;
+
+               rawttyn = argv[2];
+               (void)strlcpy(ttyn, dev, sizeof(ttyn));
+               (void)strlcat(ttyn, argv[2], sizeof(ttyn));
+               if (uugetty)  {
+                       (void)chown(ttyn, ttyowner, 0);
+                       (void)strlcpy(lockfile, _PATH_LOCK,
+                               sizeof(lockfile));
+                       (void)strlcat(lockfile, argv[2],
+                               sizeof(lockfile));
+                       /*
+                        * wait for lockfiles to go away before we try
+                        * to open
+                        */
+                       if (pidlock(lockfile, 0, 0, 0) != 0)  {
+                               syslog(LOG_ERR,
+                                       "%s: can't create lockfile", ttyn);
+                               exit(1);
+                       }
+                       (void)unlink(lockfile);
+               }
+               if (strcmp(argv[0], "+") != 0) {
+                       (void)chown(ttyn, ttyowner, 0);
+                       (void)chmod(ttyn, 0600);
+#ifndef __minix
+                       (void)revoke(ttyn);
+#endif
+                       if (ttyaction(ttyn, "getty", "root"))
+                               syslog(LOG_WARNING, "%s: ttyaction failed",
+                                       ttyn);
+                       /*
+                        * Delay the open so DTR stays down long enough
+                        * to be detected.
+                        */
+                       (void)sleep(2);
+                       while ((i = open(ttyn, O_RDWR)) == -1) {
+                               if ((repcnt % 10 == 0) &&
+                                   (errno != ENXIO || !failopenlogged)) {
+                                       syslog(LOG_WARNING, "%s: %m", ttyn);
+                                       closelog();
+                                       failopenlogged = 1;
+                               }
+                               repcnt++;
+                               (void)sleep(60);
+                       }
+                       if (uugetty && pidlock(lockfile, 0, 0, 0) != 0)  {
+                               syslog(LOG_ERR, "%s: can't create lockfile",
+                                       ttyn);
+                               exit(1);
+                       }
+                       if (uugetty)
+                               (void)chown(lockfile, ttyowner, 0);
+                       (void)login_tty(i);
+               }
+       }
+
+       /* Start with default tty settings */
+       if (tcgetattr(0, &tmode) < 0) {
+               syslog(LOG_ERR, "%s: %m", ttyn);
+               exit(1);
+       }
+       omode = tmode;
+
+       gettable("default", defent);
+       gendefaults();
+       tname = "default";
+       if (argc > 1)
+               tname = argv[1];
+       for (;;) {
+               int off;
+
+               rval = 0;
+               gettable(tname, tabent);
+               if (OPset || EPset || APset)
+                       APset++, OPset++, EPset++;
+               setdefaults();
+               off = 0;
+               (void)tcflush(0, TCIOFLUSH);    /* clear out the crap */
+#ifndef  __minix
+               (void)ioctl(0, FIONBIO, &off);  /* turn off non-blocking mode */
+               (void)ioctl(0, FIOASYNC, &off); /* ditto for async mode */
+#endif
+
+               if (IS)
+                       (void)cfsetispeed(&tmode, (speed_t)IS);
+               else if (SP)
+                       (void)cfsetispeed(&tmode, (speed_t)SP);
+               if (OS)
+                       (void)cfsetospeed(&tmode, (speed_t)OS);
+               else if (SP)
+                       (void)cfsetospeed(&tmode, (speed_t)SP);
+               setflags(0);
+               setchars();
+               if (tcsetattr(0, TCSANOW, &tmode) < 0) {
+                       syslog(LOG_ERR, "%s: %m", ttyn);
+                       exit(1);
+               }
+               if (AB) {
+                       tname = autobaud();
+                       continue;
+               }
+               if (PS) {
+                       tname = portselector();
+                       continue;
+               }
+               if (CS)
+                       clearscreen();
+               if (CL && *CL)
+                       putpad(CL);
+               edithost(HE);
+
+               /*
+                * If this is the first time through this, and an
+                * issue file has been given, then send it.
+                */
+               if (first_time != 0 && IF != NULL) {
+                       char buf[_POSIX2_LINE_MAX];
+                       FILE *fp;
+
+                       if ((fp = fopen(IF, "r")) != NULL) {
+                               while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
+                                       putf(buf);
+                               (void)fclose(fp);
+                       }
+               }
+               first_time = 0;
+
+               if (IM && *IM)
+                       putf(IM);
+               oflush();
+               if (setjmp(timeout)) {
+                       tmode.c_ispeed = tmode.c_ospeed = 0;
+                       (void)tcsetattr(0, TCSANOW, &tmode);
+                       exit(1);
+               }
+               if (TO) {
+                       (void)signal(SIGALRM, dingdong);
+                       (void)alarm((unsigned int)TO);
+               }
+               if (NN) {
+                       name[0] = '\0';
+                       lower = 1;
+                       upper = digit_or_punc = 0;
+               } else if (AL) {
+                       const char *p = AL;
+                       char *q = name;
+
+                       while (*p && q < &name[sizeof name - 1]) {
+                               if (isupper((unsigned char)*p))
+                                       upper = 1;
+                               else if (islower((unsigned char)*p))
+                                       lower = 1;
+                               else if (isdigit((unsigned char)*p))
+                                       digit_or_punc = 1;
+                               *q++ = *p++;
+                       }
+               } else if ((rval = getname()) == 2) {
+                       setflags(2);
+                       (void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
+                       syslog(LOG_ERR, "%s: %m", PP);
+                       exit(1);
+               }
+
+               if (rval || AL || NN) {
+                       int i;
+
+                       oflush();
+                       (void)alarm(0);
+                       (void)signal(SIGALRM, SIG_DFL);
+                       if (name[0] == '-') {
+                               xputs("user names may not start with '-'.");
+                               continue;
+                       }
+                       if (!(upper || lower || digit_or_punc))
+                               continue;
+                       setflags(2);
+                       if (crmod) {
+                               tmode.c_iflag |= ICRNL;
+                               tmode.c_oflag |= ONLCR;
+                       }
+#if XXX
+                       if (upper || UC)
+                               tmode.sg_flags |= LCASE;
+                       if (lower || LC)
+                               tmode.sg_flags &= ~LCASE;
+#endif
+                       if (tcsetattr(0, TCSANOW, &tmode) < 0) {
+                               syslog(LOG_ERR, "%s: %m", ttyn);
+                               exit(1);
+                       }
+                       (void)signal(SIGINT, SIG_DFL);
+                       for (i = 0; envp[i] != NULL; i++)
+                               env[i] = envp[i];
+                       makeenv(&env[i]);
+
+                       limit.rlim_max = RLIM_INFINITY;
+                       limit.rlim_cur = RLIM_INFINITY;
+#ifndef __minix
+                       (void)setrlimit(RLIMIT_CPU, &limit);
+#endif
+                       if (NN)
+                               (void)execle(LO, "login", AL ? "-fp" : "-p",
+                                   NULL, env);
+                       else
+                               (void)execle(LO, "login", AL ? "-fp" : "-p",
+                                   "--", name, NULL, env);
+                       syslog(LOG_ERR, "%s: %m", LO);
+                       exit(1);
+               }
+               (void)alarm(0);
+               (void)signal(SIGALRM, SIG_DFL);
+               (void)signal(SIGINT, SIG_IGN);
+               if (NX && *NX)
+                       tname = NX;
+               if (uugetty)
+                       (void)unlink(lockfile);
+       }
+}
+
+static int
+getname(void)
+{
+       int c;
+       char *np;
+       unsigned char cs;
+       int ppp_state, ppp_connection;
+
+       /*
+        * Interrupt may happen if we use CBREAK mode
+        */
+       if (setjmp(intrupt)) {
+               (void)signal(SIGINT, SIG_IGN);
+               return (0);
+       }
+       (void)signal(SIGINT, interrupt);
+       setflags(1);
+       prompt();
+       if (PF > 0) {
+               oflush();
+               (void)sleep((unsigned int)PF);
+               PF = 0;
+       }
+       if (tcsetattr(0, TCSANOW, &tmode) < 0) {
+               syslog(LOG_ERR, "%s: %m", ttyn);
+               exit(1);
+       }
+       crmod = digit_or_punc = lower = upper = 0;
+       ppp_state = ppp_connection = 0;
+       np = name;
+       for (;;) {
+               oflush();
+               if (read(STDIN_FILENO, &cs, 1) <= 0)
+                       exit(0);
+               if ((c = cs&0177) == 0)
+                       return (0);
+
+               /*
+                * PPP detection state machine..
+                * Look for sequences:
+                * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
+                * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
+                * See RFC1662.
+                * Derived from code from Michael Hancock <michaelh@cet.co.jp>
+                * and Erik 'PPP' Olson <eriko@wrq.com>
+                */
+               if (PP && cs == PPP_FRAME) {
+                       ppp_state = 1;
+               } else if (ppp_state == 1 && cs == PPP_STATION) {
+                       ppp_state = 2;
+               } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
+                       ppp_state = 3;
+               } else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
+                   (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
+                       ppp_state = 4;
+               } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
+                       ppp_state = 5;
+               } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
+                       ppp_connection = 1;
+                       break;
+               } else {
+                       ppp_state = 0;
+               }
+
+               if (c == EOT)
+                       exit(1);
+               if (c == '\r' || c == '\n' ||
+                   np >= &name[LOGIN_NAME_MAX - 1]) {
+                       *np = '\0';
+                       putf("\r\n");
+                       break;
+               }
+               if (islower(c))
+                       lower = 1;
+               else if (isupper(c))
+                       upper = 1;
+               else if (c == ERASE || c == '#' || c == '\b') {
+                       if (np > name) {
+                               np--;
+                               if (cfgetospeed(&tmode) >= 1200)
+                                       xputs("\b \b");
+                               else
+                                       putchr(cs);
+                       }
+                       continue;
+               } else if (c == KILL || c == '@') {
+                       putchr(cs);
+                       putchr('\r');
+                       if (cfgetospeed(&tmode) < 1200)
+                               putchr('\n');
+                       /* this is the way they do it down under ... */
+                       else if (np > name)
+                               xputs(
+                                   "                                     \r");
+                       prompt();
+                       np = name;
+                       continue;
+               } else if (isdigit(c) || c == '_')
+                       digit_or_punc = 1;
+               if (IG && (c <= ' ' || c > 0176))
+                       continue;
+               *np++ = c;
+               putchr(cs);
+
+               /*
+                * An MS-Windows direct connect PPP "client" won't send its
+                * first PPP packet until we respond to its "CLIENT" poll
+                * with a CRLF sequence.  We cater to yet another broken
+                * implementation of a previously-standard protocol...
+                */
+               *np = '\0';
+               if (strstr(name, "CLIENT"))
+                       putf("\r\n");
+       }
+       (void)signal(SIGINT, SIG_IGN);
+       *np = 0;
+       if (c == '\r')
+               crmod = 1;
+       if ((upper && !lower && !LC) || UC)
+               for (np = name; *np; np++)
+                       *np = tolower((unsigned char)*np);
+       return (1 + ppp_connection);
+}
+
+static void
+xputs(const char *s)
+{
+       while (*s)
+               putchr(*s++);
+}
+
+char   outbuf[OBUFSIZ];
+size_t obufcnt = 0;
+
+static int
+putchr(int cc)
+{
+       unsigned char c;
+
+       c = cc;
+       if (!NP) {
+               c |= partab[c&0177] & 0200;
+               if (OP)
+                       c ^= 0200;
+       }
+       if (!UB) {
+               outbuf[obufcnt++] = c;
+               if (obufcnt >= OBUFSIZ)
+                       oflush();
+               return 1;
+       }
+       return write(STDOUT_FILENO, &c, 1);
+}
+
+static void
+oflush(void)
+{
+       if (obufcnt)
+               (void)write(STDOUT_FILENO, outbuf, obufcnt);
+       obufcnt = 0;
+}
+
+static void
+prompt(void)
+{
+
+       putf(LM);
+       if (CO)
+               putchr('\n');
+}
+
+static void
+putf(const char *cp)
+{
+       time_t t;
+       char *slash, db[100];
+
+       while (*cp) {
+               if (*cp != '%') {
+                       putchr(*cp++);
+                       continue;
+               }
+               switch (*++cp) {
+
+               case 't':
+                       if ((slash = strstr(ttyn, "/pts/")) == NULL)
+                               slash = strrchr(ttyn, '/');
+                       if (slash == NULL)
+                               xputs(ttyn);
+                       else
+                               xputs(&slash[1]);
+                       break;
+
+               case 'h':
+                       xputs(editedhost);
+                       break;
+
+               case 'd':
+                       (void)time(&t);
+                       (void)strftime(db, sizeof(db),
+                           "%l:%M%p on %A, %d %B %Y", localtime(&t));
+                       xputs(db);
+                       break;
+
+               case 's':
+                       xputs(kerninfo.sysname);
+                       break;
+
+               case 'm':
+                       xputs(kerninfo.machine);
+                       break;
+
+               case 'r':
+                       xputs(kerninfo.release);
+                       break;
+
+               case 'v':
+                       xputs(kerninfo.version);
+                       break;
+
+               case '%':
+                       putchr('%');
+                       break;
+               }
+               if (*cp)
+                       cp++;
+       }
+}
+
+static void
+clearscreen(void)
+{
+       struct ttyent *typ;
+       int err;
+
+       if (rawttyn == NULL)
+               return;
+
+       typ = getttynam(rawttyn);
+
+       if ((typ == NULL) || (typ->ty_type == NULL) ||
+           (typ->ty_type[0] == 0))
+               return;
+
+       if (setupterm(typ->ty_type, 0, &err) == ERR)
+               return;
+
+       if (clear_screen)
+               putpad(clear_screen);
+
+       del_curterm(cur_term);
+       cur_term = NULL;
+}
diff --git a/libexec/getty/pathnames.h b/libexec/getty/pathnames.h
new file mode 100644 (file)
index 0000000..2634fed
--- /dev/null
@@ -0,0 +1,37 @@
+/*     $NetBSD: pathnames.h,v 1.9 2008/02/04 15:27:20 christos Exp $   */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+~ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)pathnames.h   8.1 (Berkeley) 6/4/93
+ */
+
+#include <paths.h>
+
+#define        _PATH_LOGIN     "/usr/bin/login"
+#define        _PATH_LOCK      "/var/spool/lock/LCK.."
diff --git a/libexec/getty/subr.c b/libexec/getty/subr.c
new file mode 100644 (file)
index 0000000..776aab0
--- /dev/null
@@ -0,0 +1,743 @@
+/*     $NetBSD: subr.c,v 1.33 2006/11/16 04:31:24 christos Exp $       */
+
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "from: @(#)subr.c       8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: subr.c,v 1.33 2006/11/16 04:31:24 christos Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Melbourne getty.
+ */
+#ifndef __minix
+#define COMPAT_43
+#endif
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include "extern.h"
+#include "gettytab.h"
+#include "pathnames.h"
+
+extern struct termios tmode, omode;
+
+#ifndef __minix
+static void    compatflags(long);
+#endif
+
+/*
+ * Get a table entry.
+ */
+void
+gettable(char *name, char *buf)
+{
+       struct gettystrs *sp;
+       struct gettynums *np;
+       struct gettyflags *fp;
+       long n;
+       const char *dba[2];
+       dba[0] = _PATH_GETTYTAB;
+       dba[1] = 0;
+
+       if (cgetent(&buf, dba, name) != 0)
+               return;
+
+       for (sp = gettystrs; sp->field; sp++)
+               (void)cgetstr(buf, sp->field, &sp->value);
+       for (np = gettynums; np->field; np++) {
+               if (cgetnum(buf, np->field, &n) == -1)
+                       np->set = 0;
+               else {
+                       np->set = 1;
+                       np->value = n;
+               }
+       }
+       for (fp = gettyflags; fp->field; fp++) {
+               if (cgetcap(buf, fp->field, ':') == NULL)
+                       fp->set = 0;
+               else {
+                       fp->set = 1;
+                       fp->value = 1 ^ fp->invrt;
+               }
+       }
+#ifdef DEBUG
+       printf("name=\"%s\", buf=\"%s\"\n", name, buf);
+       for (sp = gettystrs; sp->field; sp++)
+               printf("cgetstr: %s=%s\n", sp->field, sp->value);
+       for (np = gettynums; np->field; np++)
+               printf("cgetnum: %s=%d\n", np->field, np->value);
+       for (fp = gettyflags; fp->field; fp++)
+               printf("cgetflags: %s='%c' set='%c'\n", fp->field, 
+                      fp->value + '0', fp->set + '0');
+       exit(1);
+#endif /* DEBUG */
+}
+
+void
+gendefaults(void)
+{
+       struct gettystrs *sp;
+       struct gettynums *np;
+       struct gettyflags *fp;
+
+       for (sp = gettystrs; sp->field; sp++)
+               if (sp->value)
+                       sp->defalt = sp->value;
+       for (np = gettynums; np->field; np++)
+               if (np->set)
+                       np->defalt = np->value;
+       for (fp = gettyflags; fp->field; fp++)
+               if (fp->set)
+                       fp->defalt = fp->value;
+               else
+                       fp->defalt = fp->invrt;
+}
+
+void
+setdefaults(void)
+{
+       struct gettystrs *sp;
+       struct gettynums *np;
+       struct gettyflags *fp;
+
+       for (sp = gettystrs; sp->field; sp++)
+               if (!sp->value)
+                       sp->value = sp->defalt;
+       for (np = gettynums; np->field; np++)
+               if (!np->set)
+                       np->value = np->defalt;
+       for (fp = gettyflags; fp->field; fp++)
+               if (!fp->set)
+                       fp->value = fp->defalt;
+}
+
+static char **
+charnames[] = {
+       &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
+       &SU, &DS, &RP, &FL, &WE, &LN, &ST, &B2, 0
+};
+
+static cc_t *
+charvars[] = {
+       &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
+       &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
+       &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
+       &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
+       &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], &tmode.c_cc[VSTATUS],
+       &tmode.c_cc[VEOL2], 0
+};
+
+void
+setchars(void)
+{
+       int i;
+       char *p;
+
+       for (i = 0; charnames[i]; i++) {
+               p = *charnames[i];
+               if (p && *p)
+                       *charvars[i] = *p;
+               else
+                       *charvars[i] = _POSIX_VDISABLE;
+       }
+}
+
+/* Macros to clear/set/test flags. */
+#define        SET(t, f)       (t) |= (f)
+#define        CLR(t, f)       (t) &= ~(f)
+#define        ISSET(t, f)     ((t) & (f))
+
+void
+setflags(int n)
+{
+       tcflag_t iflag, oflag, cflag, lflag;
+
+#ifdef COMPAT_43
+       switch (n) {
+       case 0:
+               if (F0set) {
+                       compatflags(F0);
+                       return;
+               }
+               break;
+       case 1:
+               if (F1set) {
+                       compatflags(F1);
+                       return;
+               }
+               break;
+       default:
+               if (F2set) {
+                       compatflags(F2);
+                       return;
+               }
+               break;
+       }
+#endif
+
+       switch (n) {
+       case 0:
+               if (C0set && I0set && L0set && O0set) {
+                       tmode.c_cflag = C0;
+                       tmode.c_iflag = I0;
+                       tmode.c_lflag = L0;
+                       tmode.c_oflag = O0;
+                       return;
+               }
+               break;
+       case 1:
+               if (C1set && I1set && L1set && O1set) {
+                       tmode.c_cflag = C1;
+                       tmode.c_iflag = I1;
+                       tmode.c_lflag = L1;
+                       tmode.c_oflag = O1;
+                       return;
+               }
+               break;
+       default:
+               if (C2set && I2set && L2set && O2set) {
+                       tmode.c_cflag = C2;
+                       tmode.c_iflag = I2;
+                       tmode.c_lflag = L2;
+                       tmode.c_oflag = O2;
+                       return;
+               }
+               break;
+       }
+
+       iflag = omode.c_iflag;
+       oflag = omode.c_oflag;
+       cflag = omode.c_cflag;
+       lflag = omode.c_lflag;
+
+       if (NP) {
+               CLR(cflag, CSIZE|PARENB);
+               SET(cflag, CS8);
+               CLR(iflag, ISTRIP|INPCK|IGNPAR);
+       } else if (AP || EP || OP) {
+               CLR(cflag, CSIZE);
+               SET(cflag, CS7|PARENB);
+               SET(iflag, ISTRIP);
+               if (OP && !EP) {
+                       SET(iflag, INPCK|IGNPAR);
+                       SET(cflag, PARODD);
+                       if (AP)
+                               CLR(iflag, INPCK);
+               } else if (EP && !OP) {
+                       SET(iflag, INPCK|IGNPAR);
+                       CLR(cflag, PARODD);
+                       if (AP)
+                               CLR(iflag, INPCK);
+               } else if (AP || (EP && OP)) {
+                       CLR(iflag, INPCK|IGNPAR);
+                       CLR(cflag, PARODD);
+               }
+       } /* else, leave as is */
+
+#if 0
+       if (UC)
+               f |= LCASE;
+#endif
+
+       if (HC)
+               SET(cflag, HUPCL);
+       else
+               CLR(cflag, HUPCL);
+
+#ifndef __minix
+       if (MB)
+               SET(cflag, MDMBUF);
+       else
+               CLR(cflag, MDMBUF);
+#endif
+
+       if (NL) {
+               SET(iflag, ICRNL);
+               SET(oflag, ONLCR|OPOST);
+       } else {
+               CLR(iflag, ICRNL);
+               CLR(oflag, ONLCR);
+       }
+
+#ifndef __minix
+       if (!HT)
+               SET(oflag, OXTABS|OPOST);
+       else
+               CLR(oflag, OXTABS);
+#endif
+
+#ifdef XXX_DELAY
+       SET(f, delaybits());
+#endif
+
+       if (n == 1) {           /* read mode flags */
+               if (RW) {
+                       iflag = 0;
+                       CLR(oflag, OPOST);
+                       CLR(cflag, CSIZE|PARENB);
+                       SET(cflag, CS8);
+                       lflag = 0;
+               } else {
+                       CLR(lflag, ICANON);
+               }
+               goto out;
+       }
+
+       if (n == 0)
+               goto out;
+
+#if 0
+       if (CB)
+               SET(f, CRTBS);
+#endif
+
+       if (CE)
+               SET(lflag, ECHOE);
+       else
+               CLR(lflag, ECHOE);
+
+#ifndef __minix
+       if (CK)
+               SET(lflag, ECHOKE);
+       else
+               CLR(lflag, ECHOKE);
+
+       if (PE)
+               SET(lflag, ECHOPRT);
+       else
+               CLR(lflag, ECHOPRT);
+#endif
+
+       if (EC)
+               SET(lflag, ECHO);
+       else
+               CLR(lflag, ECHO);
+
+#ifndef __minix
+       if (XC)
+               SET(lflag, ECHOCTL);
+       else
+               CLR(lflag, ECHOCTL);
+#endif
+
+       if (DX)
+               SET(lflag, IXANY);
+       else
+               CLR(lflag, IXANY);
+
+out:
+       tmode.c_iflag = iflag;
+       tmode.c_oflag = oflag;
+       tmode.c_cflag = cflag;
+       tmode.c_lflag = lflag;
+}
+
+#ifdef COMPAT_43
+/*
+ * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
+ */
+void
+compatflags(long flags)
+{
+       tcflag_t iflag, oflag, cflag, lflag;
+
+       iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY;
+       oflag = OPOST|ONLCR|OXTABS;
+       cflag = CREAD;
+       lflag = ICANON|ISIG|IEXTEN;
+
+       if (ISSET(flags, TANDEM))
+               SET(iflag, IXOFF);
+       else
+               CLR(iflag, IXOFF);
+       if (ISSET(flags, ECHO))
+               SET(lflag, ECHO);
+       else
+               CLR(lflag, ECHO);
+       if (ISSET(flags, CRMOD)) {
+               SET(iflag, ICRNL);
+               SET(oflag, ONLCR);
+       } else {
+               CLR(iflag, ICRNL);
+               CLR(oflag, ONLCR);
+       }
+       if (ISSET(flags, XTABS))
+               SET(oflag, OXTABS);
+       else
+               CLR(oflag, OXTABS);
+
+
+       if (ISSET(flags, RAW)) {
+               iflag &= IXOFF;
+               CLR(lflag, ISIG|ICANON|IEXTEN);
+               CLR(cflag, PARENB);
+       } else {
+               SET(iflag, BRKINT|IXON|IMAXBEL);
+               SET(lflag, ISIG|IEXTEN);
+               if (ISSET(flags, CBREAK))
+                       CLR(lflag, ICANON);
+               else
+                       SET(lflag, ICANON);
+               switch (ISSET(flags, ANYP)) {
+               case 0:
+                       CLR(cflag, PARENB);
+                       break;
+               case ANYP:
+                       SET(cflag, PARENB);
+                       CLR(iflag, INPCK);
+                       break;
+               case EVENP:
+                       SET(cflag, PARENB);
+                       SET(iflag, INPCK);
+                       CLR(cflag, PARODD);
+                       break;
+               case ODDP:
+                       SET(cflag, PARENB);
+                       SET(iflag, INPCK);
+                       SET(cflag, PARODD);
+                       break;
+               }
+       }
+
+       /* Nothing we can do with CRTBS. */
+       if (ISSET(flags, PRTERA))
+               SET(lflag, ECHOPRT);
+       else
+               CLR(lflag, ECHOPRT);
+       if (ISSET(flags, CRTERA))
+               SET(lflag, ECHOE);
+       else
+               CLR(lflag, ECHOE);
+#ifndef __minix
+       /* Nothing we can do with TILDE. */
+       if (ISSET(flags, MDMBUF))
+               SET(cflag, MDMBUF);
+       else
+               CLR(cflag, MDMBUF);
+#endif
+       if (ISSET(flags, NOHANG))
+               CLR(cflag, HUPCL);
+       else
+               SET(cflag, HUPCL);
+
+#ifndef __minix
+       if (ISSET(flags, CRTKIL))
+               SET(lflag, ECHOKE);
+       else
+               CLR(lflag, ECHOKE);
+#endif
+
+       if (ISSET(flags, CTLECH))
+               SET(lflag, ECHOCTL);
+       else
+               CLR(lflag, ECHOCTL);
+       if (!ISSET(flags, DECCTQ))
+               SET(iflag, IXANY);
+       else
+               CLR(iflag, IXANY);
+       CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
+       SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
+
+       if (ISSET(flags, RAW|LITOUT|PASS8)) {
+               CLR(cflag, CSIZE);
+               SET(cflag, CS8);
+               if (!ISSET(flags, RAW|PASS8))
+                       SET(iflag, ISTRIP);
+               else
+                       CLR(iflag, ISTRIP);
+               if (!ISSET(flags, RAW|LITOUT))
+                       SET(oflag, OPOST);
+               else
+                       CLR(oflag, OPOST);
+       } else {
+               CLR(cflag, CSIZE);
+               SET(cflag, CS7);
+               SET(iflag, ISTRIP);
+               SET(oflag, OPOST);
+       }
+
+       tmode.c_iflag = iflag;
+       tmode.c_oflag = oflag;
+       tmode.c_cflag = cflag;
+       tmode.c_lflag = lflag;
+}
+#endif
+
+#ifdef XXX_DELAY
+struct delayval {
+       unsigned        delay;          /* delay in ms */
+       int             bits;
+};
+
+/*
+ * below are random guesses, I can't be bothered checking
+ */
+
+struct delayval        crdelay[] = {
+       { 1,            CR1 },
+       { 2,            CR2 },
+       { 3,            CR3 },
+       { 83,           CR1 },
+       { 166,          CR2 },
+       { 0,            CR3 },
+};
+
+struct delayval nldelay[] = {
+       { 1,            NL1 },          /* special, calculated */
+       { 2,            NL2 },
+       { 3,            NL3 },
+       { 100,          NL2 },
+       { 0,            NL3 },
+};
+
+struct delayval        bsdelay[] = {
+       { 1,            BS1 },
+       { 0,            0 },
+};
+
+struct delayval        ffdelay[] = {
+       { 1,            FF1 },
+       { 1750,         FF1 },
+       { 0,            FF1 },
+};
+
+struct delayval        tbdelay[] = {
+       { 1,             TAB1 },
+       { 2,             TAB2 },
+       { 3,            XTABS },        /* this is expand tabs */
+       { 100,           TAB1 },
+       { 0,             TAB2 },
+};
+
+int
+delaybits(void)
+{
+       int f;
+
+       f  = adelay(CD, crdelay);
+       f |= adelay(ND, nldelay);
+       f |= adelay(FD, ffdelay);
+       f |= adelay(TD, tbdelay);
+       f |= adelay(BD, bsdelay);
+       return (f);
+}
+
+int
+adelay(int ms, struct delayval *dp)
+{
+       if (ms == 0)
+               return (0);
+       while (dp->delay && ms > dp->delay)
+               dp++;
+       return (dp->bits);
+}
+#endif
+
+char   editedhost[MAXHOSTNAMELEN];
+
+void
+edithost(char *pat)
+{
+       char *host = HN;
+       char *res = editedhost;
+
+       if (!pat)
+               pat = "";
+       while (*pat) {
+               switch (*pat) {
+
+               case '#':
+                       if (*host)
+                               host++;
+                       break;
+
+               case '@':
+                       if (*host)
+                               *res++ = *host++;
+                       break;
+
+               default:
+                       *res++ = *pat;
+                       break;
+
+               }
+               if (res == &editedhost[sizeof editedhost - 1]) {
+                       *res = '\0';
+                       return;
+               }
+               pat++;
+       }
+       if (*host)
+               (void)strncpy(res, host,
+                   sizeof editedhost - (res - editedhost) - 1);
+       else
+               *res = '\0';
+       editedhost[sizeof editedhost - 1] = '\0';
+}
+
+void
+makeenv(char *env[])
+{
+       static char termbuf[128] = "TERM=";
+       char *p, *q;
+       char **ep;
+
+       ep = env;
+       if (TT && *TT) {
+               (void)strlcat(termbuf, TT, sizeof(termbuf));
+               *ep++ = termbuf;
+       }
+       if ((p = EV) != NULL) {
+               q = p;
+               while ((q = strchr(q, ',')) != NULL) {
+                       *q++ = '\0';
+                       *ep++ = p;
+                       p = q;
+               }
+               if (*p)
+                       *ep++ = p;
+       }
+       *ep = (char *)0;
+}
+
+/*
+ * This speed select mechanism is written for the Develcon DATASWITCH.
+ * The Develcon sends a string of the form "B{speed}\n" at a predefined
+ * baud rate. This string indicates the user's actual speed.
+ * The routine below returns the terminal type mapped from derived speed.
+ */
+struct portselect {
+       char    *ps_baud;
+       char    *ps_type;
+} portspeeds[] = {
+       { "B110",       "std.110" },
+       { "B134",       "std.134" },
+       { "B150",       "std.150" },
+       { "B300",       "std.300" },
+       { "B600",       "std.600" },
+       { "B1200",      "std.1200" },
+       { "B2400",      "std.2400" },
+       { "B4800",      "std.4800" },
+       { "B9600",      "std.9600" },
+       { "B19200",     "std.19200" },
+       { 0 }
+};
+
+char *
+portselector(void)
+{
+       char c, baud[20], *type = "default";
+       struct portselect *ps;
+       int len;
+
+       (void)alarm(5*60);
+       for (len = 0; len < sizeof (baud) - 1; len++) {
+               if (read(STDIN_FILENO, &c, 1) <= 0)
+                       break;
+               c &= 0177;
+               if (c == '\n' || c == '\r')
+                       break;
+               if (c == 'B')
+                       len = 0;        /* in case of leading garbage */
+               baud[len] = c;
+       }
+       baud[len] = '\0';
+       for (ps = portspeeds; ps->ps_baud; ps++)
+               if (strcmp(ps->ps_baud, baud) == 0) {
+                       type = ps->ps_type;
+                       break;
+               }
+       (void)sleep(2); /* wait for connection to complete */
+       return (type);
+}
+
+/*
+ * This auto-baud speed select mechanism is written for the Micom 600
+ * portselector. Selection is done by looking at how the character '\r'
+ * is garbled at the different speeds.
+ */
+#include <sys/time.h>
+
+char *
+autobaud(void)
+{
+       struct pollfd set[1];
+       struct timespec timeout;
+       char c, *type = "9600-baud";
+
+       (void)tcflush(0, TCIOFLUSH);
+       set[0].fd = STDIN_FILENO;
+       set[0].events = POLLIN;
+       if (poll(set, 1, 5000) <= 0)
+               return (type);
+       if (read(STDIN_FILENO, &c, 1) != 1)
+               return (type);
+       timeout.tv_sec = 0;
+       timeout.tv_nsec = 20000;
+       (void)nanosleep(&timeout, NULL);
+       (void)tcflush(0, TCIOFLUSH);
+       switch (c & 0377) {
+
+       case 0200:              /* 300-baud */
+               type = "300-baud";
+               break;
+
+       case 0346:              /* 1200-baud */
+               type = "1200-baud";
+               break;
+
+       case  015:              /* 2400-baud */
+       case 0215:
+               type = "2400-baud";
+               break;
+
+       default:                /* 4800-baud */
+               type = "4800-baud";
+               break;
+
+       case 0377:              /* 9600-baud */
+               type = "9600-baud";
+               break;
+       }
+       return (type);
+}
diff --git a/libexec/getty/ttys.5 b/libexec/getty/ttys.5
new file mode 100644 (file)
index 0000000..4ad21a2
--- /dev/null
@@ -0,0 +1,227 @@
+.\"    $NetBSD: ttys.5,v 1.18 2012/04/21 12:27:28 roy Exp $
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)ttys.5       8.1 (Berkeley) 6/4/93
+.\"
+.Dd April 5, 2012
+.Dt TTYS 5
+.Os
+.Sh NAME
+.Nm ttys
+.Nd terminal initialization information
+.Sh DESCRIPTION
+The file
+.Nm
+contains information that is used by various routines to initialize
+and control the use of terminal special files.
+This information is read with the
+.Xr getttyent 3
+library routines.
+.Pp
+There is one line in the
+.Nm
+file per special device file.
+Fields are separated by tabs and/or spaces.
+Fields comprising more than one word should be enclosed in double
+quotes (``"'').
+Blank lines and comments may appear anywhere in the file; comments
+are delimited by hash marks (``#'') and new lines.
+Any unspecified fields will default to null.
+.Pp
+Each line in
+.Nm
+has the format:
+.Dl tty command type flags
+.Pp
+The first field is the
+name of the terminal special file as it is found in
+.Pa /dev .
+.Pp
+The second field of the file is the command to execute for the line,
+usually
+.Xr getty 8 ,
+which initializes and opens the line, setting the speed, waiting for
+a user name and executing the
+.Xr login 1
+program.
+However, it can be any desired command, for example the start up
+for a window system terminal emulator or some other daemon process,
+and can contain multiple words if quoted.
+.Pp
+The third field is the type of terminal usually connected to that
+tty line, normally the one found in the
+.Xr terminfo 5
+data base file.
+The environment variable
+.Dv TERM
+is initialized with the value by either
+.Xr getty 8
+or
+.Xr login 1 .
+.Pp
+The remaining fields set flags in the
+.Fa ty_status
+entry (see
+.Xr getttyent 3 )
+or specify a window system process that
+.Xr init 8
+will maintain for the terminal line
+or a key into a database of tty attributes (currently unused).
+.Pp
+.Bl -tag -width softcar
+.It Sy on No or Sy off
+.Xr init 8
+should (or should not) execute the command given in the second field.
+.It Sy secure
+If
+.Sy on
+is specified, allows users with a uid of 0
+.Pq e.g. Qq root
+to login on this line.
+.It Sy local
+Sets the
+.Dv TIOCFLAG_CLOCAL
+.Xr tty 4
+flag for the device.
+This will cause the
+.Xr termios 4
+.Dv CLOCAL
+flag to be set on every open and thus modem control signal lines will be
+ignored by default.
+.It Sy softcar
+Causes the driver to ignore hardware carrier on the line (by setting the
+.Dv TIOCFLAG_SOFTCAR
+.Xr tty 4
+flag).
+.It Sy rtscts
+Sets the
+.Dv TIOCFLAG_CRTSCTS
+.Xr tty 4
+flag for the device to enable
+.Tn RTS /
+.Tn CTS
+.Qq hardware
+flow control by default.
+.It Sy mdmbuf
+Sets the
+.Dv TIOCFLAG_MDMBUF
+.Xr tty 4
+flag for the device to enable
+.Tn DTR /
+.Tn DCD
+.Qq hardware
+flow control by default.
+.El
+.Pp
+The flags
+.Qq local ,
+.Qq rtscts ,
+.Qq mdmbuf ,
+and
+.Qq softcar
+modify the default behaviour of the terminal line, and their actions
+are device driver dependent.
+These flag fields should not be quoted.
+.Pp
+The string ``window='' may be followed by a quoted command
+string which
+.Xr init 8
+will execute
+.Em before
+starting the command specified by the second field.
+.Pp
+The string ``class='' may be followed by a quoted string used
+as a key into a database of attributes for that category of tty.
+See
+.Xr getttynam 3
+for more information on this feature.
+.Pp
+After changing the
+.Nm
+file a
+.Dv SIGHUP
+signal can be sent to
+.Xr init 8
+with the command
+.Dq Li "kill \-s HUP 1" .
+On receipt of this signal,
+.Xr init 8
+will re-read the
+.Nm
+file and spawn any necessary
+.Xr getty 8
+processes.
+.Pp
+.Sy Nota Bene :
+Sending
+.Dv SIGHUP
+to
+.Xr init 8
+does
+.Em not
+change the state of the various
+.Xr tty 4
+device flags listed above; the
+.Xr ttyflags 8
+program must be run for changes in those flags to take effect on the devices.
+.Sh FILES
+.Bl -tag -width /etc/ttys -compact
+.It Pa /etc/ttys
+.El
+.Sh EXAMPLES
+.Bd -literal
+# root login on console at 1200 baud
+console        "/usr/libexec/getty std.1200"   vt100   on secure
+# dialup at 1200 baud, no root logins
+ttyd0  "/usr/libexec/getty d1200"      dialup  on      # 555-1234
+# Mike's terminal: hp2621
+ttyh0  "/usr/libexec/getty std.9600"   hp2621-nl       on      # 457 Evans
+# John's terminal: vt100
+ttyh1  "/usr/libexec/getty std.9600"   vt100   on              # 459 Evans
+# terminal emulate/window system
+ttyv0  "/usr/new/xterm -L :0"          vs100   on window="/usr/new/Xvs100 0"
+# Network pseudo ttys -- don't enable getty
+ttyp0  none    network
+ttyp1  none    network off
+.Ed
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr getttyent 3 ,
+.Xr ttyslot 3 ,
+.Xr tty 4 ,
+.Xr gettytab 5 ,
+.Xr terminfo 5 ,
+.Xr getty 8 ,
+.Xr init 8 ,
+.Xr ttyflags 8
+.Sh HISTORY
+A
+.Nm
+file appeared in
+.At v6 .
index 5b2282f92da59693c592192364574e466245fa4a..f56314449bb7903552e4cee67423de1ba5075d51 100644 (file)
@@ -8,7 +8,7 @@ MAN=    ash.1 at.1 \
        flexdoc.1 format.1 fortune.1 \
        fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \
        isodir.1 isoinfo.1 isoread.1 \
-       last.1 loadfont.1 loadkeys.1 logger.1 \
+       loadfont.1 loadkeys.1 logger.1 \
        look.1 lp.1 lspci.1 mail.1  \
        mixer.1 \
        mkproto.1 mount.1 mt.1 \
diff --git a/man/man1/last.1 b/man/man1/last.1
deleted file mode 100644 (file)
index 64527fb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-.TH LAST 1
-.SH NAME
-last, uptime \- display recent on-line session records, show uptime
-.SH SYNOPSIS
-\fBlast\fR [\fB\-f \fIfile\fR]\fR [\fB\-r\fR] [\fB\-\fIn\fR] [\fIname\fR] [\fItty\fR] ...\fR
-.br
-\fBuptime\fR
-.br
-.de FL
-.TP
-\\fB\\$1\\fR
-\\$2
-..
-.de EX
-.TP 20
-\\fB\\$1\\fR
-# \\$2
-..
-.SH OPTIONS
-.TP 5
-.B \-f
-# Use \fIfile\fR instead of /usr/adm/wtmp
-.TP 5
-.B \-r
-# Search backwards only to last reboot
-.TP 5
-.B \-u
-# Print uptime since last reboot
-.TP 5
-.B \-\fIn\fP
-# Print a maximum of \fIn\fR lines
-.SH EXAMPLES
-.TP 20
-.B last reboot
-# When was the system last rebooted?
-.TP 20
-.B last ast
-# When was the last login for ast?
-.TP 20
-.B last \-10 tty00 tty01
-# Display last 10 logins on tty00 or tty01
-.TP 20
-.B uptime
-# Display uptime (likewise \fBlast \-u\fR)
-.SH DESCRIPTION
-.PP
-.I Last
-Searches backward through the login administration file (default is
-\fI/usr/adm/wtmp\fR), printing information about previous logins and
-reboots.
-During a long search, the SIGQUIT signal (CTRL-\\) causes \fIlast\fR to 
-display how far back it has gone; it then continues. 
-.PP
-.IR Uptime ,
-an alias for
-.IR "last \-u" ,
-displays the time the system is running since the last reboot.
-.SH "SEE ALSO"
-.BR who (1),
-.BR utmp (5).
index ce8c400aacee2fcfee361973f64cccf3ec9d5975..11ad7cf4a630cf2bdcdd110d2eb511fff7e8a484 100644 (file)
@@ -4,7 +4,7 @@ MAN=    accept.2 access.2 bind.2 brk.2 chdir.2 chmod.2 chown.2 \
        getpeername.2 getpid.2 getpriority.2 getsockname.2 getsockopt.2 \
        gettimeofday.2 getuid.2 intro.2 ioctl.2 kill.2 link.2 listen.2 \
        lseek.2 mkdir.2 mknod.2 mount.2 open.2 ptrace.2 \
-       read.2 readlink.2 reboot.2 recv.2 recvfrom.2 recvmsg.2 rename.2 \
+       read.2 readlink.2 recv.2 recvfrom.2 recvmsg.2 rename.2 \
        rmdir.2 select.2 send.2 sendmsg.2 sendto.2 setsid.2 \
        setsockopt.2 setuid.2 shutdown.2 sigaction.2 sigpending.2 \
        sigprocmask.2 sigsuspend.2 socket.2 socketpair.2 \
diff --git a/man/man2/reboot.2 b/man/man2/reboot.2
deleted file mode 100644 (file)
index ed433ef..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-.TH REBOOT 2
-.SH NAME
-reboot \- close down the system or reboot
-.SH SYNTAX
-.ft B
-.nf
-#include <minix/reboot.h>
-
-int reboot(int \fIhow\fP)
-.fi
-.ft P
-.SH DESCRIPTION
-.B Reboot()
-is used to close down the system.  It allows several ways of shutting
-down depending on
-.IR how :
-.PP
-.TP 5
-.BI "reboot(RBT_DEFAULT)"
-Default shut-down action, the same as used when CTRL+ALT+DEL is pressed
-on the keyboard.
-.TP
-.BI "reboot(RBT_HALT)"
-Halt the system.
-.TP
-.BI "reboot(RBT_PANIC)"
-Cause a system panic.  This is not normally done from user mode.
-.TP
-.BI "reboot(RBT_POWEROFF)"
-Power off the system if possible, reset otherwise.
-.TP
-.BI "reboot(RBT_REBOOT)"
-Reboot the system with a software reset (currently not supported, so
-a hardware reset is used).
-.TP
-.BI "reboot(RBT_RESET)"
-Reboot the system with a hardware reset.
-.PP
-.B Reboot()
-may only be executed by the super-user.
-.SH DIAGNOSTICS
-If the call succeeds, it never returns.  If something went wrong,
-the return value is -1 and an error is indicated by
-.BR errno .
-.SH SEE ALSO
-.BR shutdown (8),
-.BR reboot (8),
-.BR halt (8),
-.BR sync (2).
-.SH AUTHOR
-Edvard Tuinder (v892231@si.hhs.NL)
index 8635171433b5c3897821a31109df562f7d4bc49b..4f7ec5d12dae3fa5a7c151f63cbd58697f987f5e 100644 (file)
@@ -5,8 +5,8 @@ MAN=    add_route.8 backup.8 boot.8 btrace.8 \
        intr.8 irdpd.8 loadramdisk.8 \
        netconf.8 newroot.8 nonamed.8 \
        ossdevlinks.8 part.8 partition.8 \
-       poweroff.8 printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
-       readclock.8 reboot.8 repartition.8 \
+       printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \
+       readclock.8 repartition.8 \
        rshd.8  screendump.8 serial-ip.8 \
        setup.8 shutdown.8 slip.8 srccrc.8 syslogd.8 tcpd.8 \
        unix.8 update.8 usage.8 vbfs.8
diff --git a/man/man8/poweroff.8 b/man/man8/poweroff.8
deleted file mode 100644 (file)
index 31d6bac..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-.TH POWEROFF 1
-.SH NAME
-poweroff \- power off the machine
-.SH SYNOPSIS
-.B poweroff
-.SH DESCRIPTION
-This command powers off the machine, by calling
-.B shutdown
-and passing the
-.I off
-directive to the boot monitor.
-.SH "SEE ALSO"
-.BR shutdown (8).
diff --git a/man/man8/reboot.8 b/man/man8/reboot.8
deleted file mode 100644 (file)
index ad47f41..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-.TH REBOOT 8
-.SH NAME
-reboot \- reboot the system immediately
-.SH SYNOPSIS
-\fBreboot\fP [\fB\-f\fP]
-.SH DESCRIPTION
-.B Reboot
-can be used to reboot the system after installing a new kernel.  It does
-not inform the users, but does log it's actions in
-.B /usr/adm/wtmp
-and
-.BR /usr/adm/log .
-The system is then rebooted with the
-.BR reboot (2)
-systemcall.
-.PP
-If the
-.B \-f
-flag is not given then all processes are sent terminate
-signals to give them a chance to die peacefully before the
-.B reboot()
-call.
-.PP
-If the wtmp file exists,
-.B reboot
-logs itself as if it were a shutdown.  This is done to prevent
-.BR last (1)
-from talking about system-crashes.
-.B Reboot
-is registered as is in the log file.
-.PP
-.B Reboot
-can only be executed by the super-user.  Any other caller will be
-refused, either by
-.BR reboot (8)
-or by
-.BR reboot (2).
-.SH "SEE ALSO"
-.BR reboot (2),
-.BR shutdown (8),
-.BR halt(8),
-.BR boot (8).
-.SH BUGS
-The error message's given by
-.B reboot
-are not always useful.  There are several routines that can fail, but which
-are not fatal for the program. 
-.SH AUTHOR
-Edvard Tuinder (v892231@si.hhs.NL)
index 8c7e8526f352d839a72ac8527b12aaa339276f22..e96e418066d9dd4776dd2bbf2ca7df5d6e60bf9c 100644 (file)
@@ -28,7 +28,7 @@ PROGRAMS+= ${PROGROOT}/drivers/tty/tty
 PROGRAMS+= ${PROGROOT}/servers/mfs/mfs
 PROGRAMS+= ${PROGROOT}/servers/vm/vm
 PROGRAMS+= ${PROGROOT}/servers/pfs/pfs
-PROGRAMS+= ${PROGROOT}/servers/init/init
+PROGRAMS+= ${PROGROOT}/sbin/init/init
 
 usage: 
        @echo " " >&2
@@ -68,10 +68,13 @@ kernel: libraries
 servers: libraries
        ${MAKE} -C ../servers all install
 
+sbin: libraries
+       ${MAKE} -C ../sbin all install
+
 drivers: libraries servers
        ${MAKE} -C ../drivers all install
 
-services: kernel servers drivers
+services: kernel servers drivers sbin
 
 .gitignore: Makefile
        echo ${GEN_FILES} | tr ' ' '\n' >.gitignore
index 8a413402f601c37394a5faa9129e8366f35671e1..7a537293f6a2a54cd30308e4180ad77572669812 100755 (executable)
@@ -178,11 +178,14 @@ ${CROSS_PREFIX}objcopy ${OBJ}/kernel/kernel -O binary ${OBJ}/kernel.bin
 
 mcopy -bsp -i ${IMG_DIR}/fat.img ${OBJ}/kernel.bin ::kernel.bin
 
-for f in vm rs pm sched vfs ds mfs pfs init
+for f in servers/vm/vm servers/rs/rs servers/pm/pm servers/sched/sched \
+       servers/vfs/vfs servers/ds/ds servers/mfs/mfs servers/pfs/pfs \
+       sbin/init/init
 do
-    cp ${OBJ}/servers/${f}/${f} ${OBJ}/${f}.elf
-    ${CROSS_PREFIX}strip -s ${OBJ}/${f}.elf
-    mcopy -bsp -i ${IMG_DIR}/fat.img  ${OBJ}/${f}.elf ::${f}.elf
+    fn=`basename $f`.elf
+    cp ${OBJ}/${f} ${OBJ}/${fn}
+    ${CROSS_PREFIX}strip -s ${OBJ}/${fn}
+    mcopy -bsp -i ${IMG_DIR}/fat.img  ${OBJ}/${fn} ::${fn}
 done
 
 for f in tty memory
index 084328d1c948b2c96df4a9f151f491efb75eecbd..da1fd1e328ff2dda81272bd67e64cb8dc50b461d 100644 (file)
@@ -73,6 +73,7 @@
 2012/10/17 12:00:00,include
 2013/05/31 12:00:00,libexec/fingerd
 2012/10/17 12:00:00,libexec/ftpd
+2012/10/17 12:00:00,libexec/getty
 2012/10/17 12:00:00,libexec/ld.elf_so
 2012/10/17 12:00:00,libexec/Makefile
 2012/10/17 12:00:00,libexec/Makefile.inc
@@ -97,6 +98,9 @@
 2012/10/17 12:00:00,Makefile
 2011/06/09 21:23:29,sbin/fsck
 2011/09/16 16:13:18,sbin/fsck_ext2fs
+2012/10/17 12:00:00,sbin/init
+2012/10/17 12:00:00,sbin/reboot
+2012/10/17 12:00:00,sbin/shutdown
 2012/10/17 12:00:00,sbin/Makefile
 2012/10/17 12:00:00,sbin/Makefile.inc
 2012/10/10 16:16:12,sbin/mknod
 2012/10/17 12:00:00,usr.bin/join
 2012/10/17 12:00:00,usr.bin/jot
 2012/10/17 12:00:00,usr.bin/lam
+2012/10/17 12:00:00,usr.bin/last
 2011/01/17 18:11:10,usr.bin/ldd
 2013/10/18 12:00:00,usr.bin/leave
 2012/10/17 12:00:00,usr.bin/lock
 2013/10/14 12:00:00,usr.bin/users
 2013/10/23 12:00:00,usr.bin/uuidgen
 2012/10/17 12:00:00,usr.bin/vis
+2012/10/17 12:00:00,usr.bin/wall
 2012/10/17 12:00:00,usr.bin/wc
 2012/10/17 12:00:00,usr.bin/what
-2013/03/22 12:00:00,usr.bin/whatis
 2013/03/15 12:00:00,usr.bin/who
 2012/10/17 12:00:00,usr.bin/whois
+2013/03/22 12:00:00,usr.bin/whatis
 2012/10/17 12:00:00,usr.bin/write
 2012/10/17 12:00:00,usr.bin/xinstall
 2012/10/17 12:00:00,usr.bin/xstr
index 8f735e6a599aa03e2122098f131f9db99b32b5ef..4453eedac56450a5220bda95aa821988acd752b5 100644 (file)
@@ -9,7 +9,12 @@
 SUBDIR= \
        \
        fsck \
-       mknod nologin
+       mknod \
+       nologin \
+       mknod \
+       init \
+       reboot \
+       shutdown
 
 # support for various file systems
 SUBDIR+= newfs_ext2fs fsck_ext2fs
diff --git a/sbin/init/Makefile b/sbin/init/Makefile
new file mode 100644 (file)
index 0000000..b1a55ef
--- /dev/null
@@ -0,0 +1,18 @@
+#      $NetBSD: Makefile,v 1.38 2009/04/11 07:58:12 lukem Exp $
+#      @(#)Makefile    8.1 (Berkeley) 7/19/93
+
+PROG=  init
+MAN=   init.8
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+CPPFLAGS+=     -DMFS_DEV_IF_NO_CONSOLE -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
+.ifdef SMALLPROG
+CPPFLAGS+=     -DLETS_GET_SMALL
+.else
+CPPFLAGS+=     -DALTSHELL -DSECURE -DCHROOT
+DPADD+=                ${LIBCRYPT}
+LDADD+=                -lcrypt
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sbin/init/NOTES b/sbin/init/NOTES
new file mode 100644 (file)
index 0000000..ca4eb77
--- /dev/null
@@ -0,0 +1,119 @@
+$NetBSD: NOTES,v 1.3 2006/04/18 11:40:26 salo Exp $
+
+POSIX and init:
+--------------
+
+POSIX.1 does not define 'init' but it mentions it in a few places.
+
+B.2.2.2, p205 line 873:
+
+       This is part of the extensive 'job control' glossary entry.
+       This specific reference says that 'init' must by default provide
+       protection from job control signals to jobs it starts --
+       it sets SIGTSTP, SIGTTIN and SIGTTOU to SIG_IGN.
+
+B.2.2.2, p206 line 889:
+
+       Here is a reference to 'vhangup'.  It says, 'POSIX.1 does
+       not specify how controlling terminal access is affected by
+       a user logging out (that is, by a controlling process
+       terminating).'  vhangup() is recognized as one way to handle
+       the problem.  I'm not clear what happens in Reno; I have
+       the impression that when the controlling process terminates,
+       references to the controlling terminal are converted to
+       references to a 'dead' vnode.  I don't know whether vhangup()
+       is required.
+
+B.2.2.2, p206 line 921:
+
+       Orphaned process groups bear indirectly on this issue.  A
+       session leader's process group is considered to be orphaned;
+       that is, it's immune to job control signals from the terminal.
+
+B.2.2.2, p233 line 2055:
+
+       'Historically, the implementation-dependent process that
+       inherits children whose parents have terminated without
+       waiting on them is called "init" and has a process ID of 1.'
+
+       It goes on to note that it used to be the case that 'init'
+       was responsible for sending SIGHUP to the foreground process
+       group of a tty whose controlling process has exited, using
+       vhangup().  It is now the responsibility of the kernel to
+       do this when the controlling process calls _exit().  The
+       kernel is also responsible for sending SIGCONT to stopped
+       process groups that become orphaned.  This is like old BSD
+       but entire process groups are signaled instead of individual
+       processes.
+
+       In general it appears that the kernel now automatically
+       takes care of orphans, relieving 'init' of any responsibility.
+       Specifics are listed on the _exit() page (p50).
+
+On setsid():
+-----------
+
+It appears that neither getty nor login call setsid(), so init must
+do this -- seems reasonable.  B.4.3.2 p 248 implies that this is the
+way that 'init' should work; it says that setsid() should be called
+after forking.
+
+Process group leaders cannot call setsid() -- another reason to
+fork!  Of course setsid() causes the current process to become a
+process group leader, so we can only call setsid() once.  Note that
+the controlling terminal acquires the session leader's process
+group when opened.
+
+Controlling terminals:
+---------------------
+
+B.7.1.1.3 p276: 'POSIX.1 does not specify a mechanism by which to
+allocate a controlling terminal.  This is normally done by a system
+utility (such as 'getty') and is considered ... outside the scope
+of POSIX.1.'  It goes on to say that historically the first open()
+of a tty in a session sets the controlling terminal.  P130 has the
+full details; nothing particularly surprising.
+
+The glossary p12 describes a 'controlling process' as the first
+process in a session that acquires a controlling terminal.  Access
+to the terminal from the session is revoked if the controlling
+process exits (see p50, in the discussion of process termination).
+
+Design notes:
+------------
+
+your generic finite state machine
+we are fascist about which signals we elect to receive,
+       even signals purportedly generated by hardware
+handle fatal errors gracefully if possible (we reboot if we goof!!)
+       if we get a segmentation fault etc., print a message on the console
+       and spin for a while before rebooting
+       (this at least decreases the amount of paper consumed :-)
+apply hysteresis to rapidly exiting gettys
+check wait status of children we reap
+       don't wait for stopped children
+don't use SIGCHILD, it's too expensive
+       but it may close windows and avoid races, sigh
+look for EINTR in case we need to change state
+init is responsible for utmp and wtmp maintenance (ick)
+       maybe now we can consider replacements?  maintain them in parallel
+       init only removes utmp and closes out wtmp entries...
+
+necessary states and state transitions (gleaned from the man page):
+       1: single user shell (with password checking?); on exit, go to 2
+       2: run rc script, on exit 0 check if init.root sysctl != "/", if it
+           differs then fork + chroot into the value of init.root and run
+           /etc/rc inside the chroot: on exit 0, go to 3; on exit N (error),
+           go to 1 (applies also to /etc/rc when init.root == "/")
+       3: read ttys file: on completion, go to 4.  If we did chroot in
+          state 2, we chroot after forking each getty to the same dir
+          (init.root is not re-read)
+       4: multi-user operation: on SIGTERM, go to 7; on SIGHUP, go to 5;
+               on SIGTSTP, go to 6
+       5: clean up mode (re-read ttys file, killing off controlling processes
+               on lines that are now 'off', starting them on lines newly 'on')
+               on completion, go to 4
+       6: boring mode (no new sessions); signals as in 4
+       7: death: send SIGHUP to all controlling processes, reap for 30 seconds,
+               then go to 1 (warn if not all processes died, i.e. wait blocks)
+Given the -s flag, we start at state 1; otherwise state 2
diff --git a/sbin/init/init.8 b/sbin/init/init.8
new file mode 100644 (file)
index 0000000..c037821
--- /dev/null
@@ -0,0 +1,374 @@
+.\"    $NetBSD: init.8,v 1.57 2009/05/18 14:17:31 wiz Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at Berkeley Software Design, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)init.8     8.6 (Berkeley) 5/26/95
+.\"
+.Dd November 10, 2008
+.Dt INIT 8
+.Os
+.Sh NAME
+.Nm init
+.Nd process control initialization
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+program is the last stage of the boot process (after the kernel loads
+and initializes all the devices).
+It normally begins multi-user operation.
+.Pp
+The following table describes the state machine used by
+.Nm :
+.Bl -enum
+.It
+Single user shell.
+.Nm
+may be passed
+.Fl s
+from the boot program to prevent the system from going multi-user and
+to instead execute a single user shell without starting the normal
+daemons.
+If the kernel is in a secure mode,
+.Nm
+will downgrade it to securelevel 0 (insecure mode).
+The system is then quiescent for maintenance work and may
+later be made to go to state 2 (multi-user) by exiting the single-user
+shell (with ^D).
+.It
+Multi-user boot (default operation).
+Executes
+.Pa /etc/rc
+(see
+.Xr rc 8 ) .
+If this was the first state entered (as opposed to entering here after
+state 1), then
+.Pa /etc/rc
+will be invoked with its first argument being
+.Sq autoboot .
+If
+.Pa /etc/rc
+exits with a non-zero (error) exit code, commence single user
+operation by giving the super-user a shell on the console by going
+to state 1 (single user).
+Otherwise, proceed to state 3.
+.Pp
+If value of the
+.Dq init.root
+sysctl node is not equal to
+.Pa /
+at this point, the
+.Pa /etc/rc
+process will be run inside a
+.Xr chroot 2
+indicated by sysctl with the same error handling as above.
+.Pp
+If the administrator has not set the security level to \-1
+to indicate that the kernel should not run multiuser in secure
+mode, and the
+.Pa /etc/rc
+script has not set a higher level of security
+than level 1, then
+.Nm
+will put the kernel into securelevel mode 1.
+See
+.Xr rc.conf 5
+and
+.Xr secmodel_securelevel 9
+for more information.
+.It
+Set up ttys as specified in
+.Xr ttys 5 .
+See below for more information.
+On completion, continue to state 4.
+If we did chroot in state 2, each
+.Xr getty 8
+process will be run in the same
+.Xr chroot 2
+path as in 2 (that is, the value of
+.Dq init.root
+sysctl is not re-read).
+.It
+Multi-user operation.
+Depending upon the signal received, change state appropriately;
+on
+.Dv SIGTERM ,
+go to state 7;
+on
+.Dv SIGHUP ,
+go to state 5;
+on
+.Dv SIGTSTP ,
+go to state 6.
+.It
+Clean-up mode; re-read
+.Xr ttys 5 ,
+killing off the controlling processes on lines that are now
+.Sq off ,
+and starting processes that are newly
+.Sq on .
+On completion, go to state 4.
+.It
+.Sq Boring
+mode; no new sessions.
+Signals as per state 4.
+.It
+Shutdown mode.
+Send
+.Dv SIGHUP
+to all controlling processes, reap the processes for 30 seconds,
+and then go to state 1 (single user); warning if not all the processes died.
+.El
+.Pp
+If the
+.Sq console
+entry in the
+.Xr ttys 5
+file is marked
+.Dq insecure ,
+then
+.Nm
+will require that the superuser password be
+entered before the system will start a single-user shell.
+The password check is skipped if the
+.Sq console
+is marked as
+.Dq secure .
+.Pp
+It should be noted that while
+.Nm
+has the ability to start multi-user operation inside a
+.Xr chroot 2
+environment, the
+.Nm
+process itself will always run in the
+.Dq original root directory .
+This also implies that single-user mode is always started in the original
+root, giving the possibility to create multi-user sessions in different
+root directories over time.
+The
+.Dq init.root
+sysctl node is fabricated by
+.Nm
+at startup and re-created any time it's found to be missing.
+Type of the node is string capable of holding full pathname, and
+is only accessible by the superuser (unless explicitly destroyed
+and re-created with different specification).
+.Pp
+In multi-user operation,
+.Nm
+maintains
+processes for the terminal ports found in the file
+.Xr ttys 5 .
+.Nm
+reads this file, and executes the command found in the second field.
+This command is usually
+.Xr getty 8 ;
+it opens and initializes the tty line and executes the
+.Xr login 1
+program.
+The
+.Xr login 1
+program, when a valid user logs in, executes a shell for that user.
+When this shell dies, either because the user logged out or an
+abnormal termination occurred (a signal), the
+.Nm
+program wakes up, deletes the user from the
+.Xr utmp 5
+and
+.Xr utmpx 5
+files of current users and records the logout in the
+.Xr wtmp 5
+and
+.Xr wtmpx 5
+files.
+The cycle is
+then restarted by
+.Nm
+executing a new
+.Xr getty 8
+for the line.
+.Pp
+Line status (on, off, secure, getty, or window information)
+may be changed in the
+.Xr ttys 5
+file without a reboot by sending the signal
+.Dv SIGHUP
+to
+.Nm
+with the command
+.Dq Li "kill \-s HUP 1" .
+This is referenced in the table above as state 5.
+On receipt of this signal,
+.Nm
+re-reads the
+.Xr ttys 5
+file.
+When a line is turned off in
+.Xr ttys 5 ,
+.Nm
+will send a
+.Dv SIGHUP
+signal to the controlling process
+for the session associated with the line.
+For any lines that were previously turned off in the
+.Xr ttys 5
+file and are now on,
+.Nm
+executes a new
+.Xr getty 8
+to enable a new login.
+If the getty or window field for a line is changed,
+the change takes effect at the end of the current
+login session (e.g., the next time
+.Nm
+starts a process on the line).
+If a line is commented out or deleted from
+.Xr ttys 5 ,
+.Nm
+will not do anything at all to that line.
+However, it will complain that the relationship between lines
+in the
+.Xr ttys 5
+file and records in the
+.Xr utmp 5
+file is out of sync,
+so this practice is not recommended.
+.Pp
+.Nm
+will terminate multi-user operations and resume single-user mode
+if sent a terminate
+.Pq Dv TERM
+signal, for example,
+.Dq Li "kill \-s TERM 1" .
+If there are processes outstanding that are deadlocked (because of
+hardware or software failure),
+.Nm
+will not wait for them all to die (which might take forever), but
+will time out after 30 seconds and print a warning message.
+.Pp
+.Nm
+will cease creating new
+.Xr getty 8 Ns 's
+and allow the system to slowly die away, if it is sent a terminal stop
+.Pq Dv TSTP
+signal, i.e.
+.Dq Li "kill \-s TSTP 1" .
+A later hangup will resume full
+multi-user operations, or a terminate will start a single user shell.
+This hook is used by
+.Xr reboot 8
+and
+.Xr halt 8 .
+.Pp
+The role of
+.Nm
+is so critical that if it dies, the system will reboot itself
+automatically.
+If, at bootstrap time, the
+.Nm
+process cannot be located, or exits during its initialisation,
+the system will panic with the message
+.Dq panic: init died (signal %d, exit %d) .
+.Pp
+If
+.Pa /dev/console
+does not exist,
+.Nm
+will cd to
+.Pa /dev
+and run
+.Dq Li "MAKEDEV -MM init" .
+.Xr MAKEDEV 8
+will use
+.Xr mount_tmpfs 8
+or
+.Xr mount_mfs 8
+to create a memory file system mounted over
+.Pa /dev
+that contains the standard devices considered necessary to boot the system.
+.Sh FILES
+.Bl -tag -width /var/log/wtmp{,x} -compact
+.It Pa /dev/console
+System console device.
+.It Pa /dev/tty*
+Terminal ports found in
+.Xr ttys 5 .
+.It Pa /var/run/utmp{,x}
+Record of current users on the system.
+.It Pa /var/log/wtmp{,x}
+Record of all logins and logouts.
+.It Pa /etc/ttys
+The terminal initialization information file.
+.It Pa /etc/rc
+System startup commands.
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "getty repeating too quickly on port %s, sleeping"
+A process being started to service a line is exiting quickly
+each time it is started.
+This is often caused by a ringing or noisy terminal line.
+.Em "Init will sleep for 10 seconds" ,
+.Em "then continue trying to start the process" .
+.Pp
+.It "some processes would not die; ps axl advised."
+A process is hung and could not be killed when the system was
+shutting down.
+This condition is usually caused by a process that is stuck in a
+device driver because of a persistent device error condition.
+.El
+.Sh SEE ALSO
+.Xr config 1 ,
+.Xr kill 1 ,
+.Xr login 1 ,
+.Xr sh 1 ,
+.Xr options 4 ,
+.Xr ttys 5 ,
+.Xr getty 8 ,
+.Xr halt 8 ,
+.Xr MAKEDEV 8 ,
+.Xr MAKEDEV.local 8 ,
+.Xr mount_mfs 8 ,
+.Xr mount_tmpfs 8 ,
+.Xr rc 8 ,
+.Xr reboot 8 ,
+.Xr rescue 8 ,
+.Xr shutdown 8 ,
+.Xr sysctl 8 ,
+.Xr secmodel_bsd44 9 ,
+.Xr secmodel_securelevel 9
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
diff --git a/sbin/init/init.c b/sbin/init/init.c
new file mode 100644 (file)
index 0000000..85e1c9f
--- /dev/null
@@ -0,0 +1,1910 @@
+/*     $NetBSD: init.c,v 1.103 2012/03/20 18:50:31 matt Exp $  */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at Berkeley Software Design, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)init.c     8.2 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: init.c,v 1.103 2012/03/20 18:50:31 matt Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <machine/cpu.h>
+
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <ttyent.h>
+#include <unistd.h>
+#include <util.h>
+#include <paths.h>
+#include <err.h>
+
+#include <stdarg.h>
+
+#ifdef SECURE
+#include <pwd.h>
+#endif
+
+#include "pathnames.h"
+
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+
+/*
+ * Sleep times; used to prevent thrashing.
+ */
+#define        GETTY_SPACING            5      /* N secs minimum getty spacing */
+#define        GETTY_SLEEP             30      /* sleep N secs after spacing problem */
+#define        WINDOW_WAIT              3      /* wait N secs after starting window */
+#define        STALL_TIMEOUT           30      /* wait N secs after warning */
+#define        DEATH_WATCH             10      /* wait N secs for procs to die */
+
+static const struct timespec dtrtime = {.tv_sec = 0, .tv_nsec = 250000};
+
+#if defined(RESCUEDIR)
+#define        INIT_BSHELL     RESCUEDIR "/sh"
+#define        INIT_MOUNT_MFS  RESCUEDIR "/mount_mfs"
+#define        INIT_PATH       RESCUEDIR ":" _PATH_STDPATH
+#else
+#define        INIT_BSHELL     _PATH_BSHELL
+#define        INIT_MOUNT_MFS  "/sbin/mount_mfs"
+#define        INIT_PATH       _PATH_STDPATH
+#endif
+
+static void handle(sig_t, ...);
+static void delset(sigset_t *, ...);
+
+static void stall(const char *, ...) __printflike(1, 2);
+static void warning(const char *, ...) __printflike(1, 2);
+static void emergency(const char *, ...) __printflike(1, 2);
+__dead static void disaster(int);
+
+#ifdef __minix
+static void minixreboot(int);
+static void minixpowerdown(int);
+#endif
+
+#ifndef __minix
+static void badsys(int);
+#endif
+
+/*
+ * We really need a recursive typedef...
+ * The following at least guarantees that the return type of (*state_t)()
+ * is sufficiently wide to hold a function pointer.
+ */
+typedef long (*state_func_t)(void);
+typedef state_func_t (*state_t)(void);
+
+#define        DEATH           'd'
+#define        SINGLE_USER     's'
+#define        RUNCOM          'r'
+#define        READ_TTYS       't'
+#define        MULTI_USER      'm'
+#define        CLEAN_TTYS      'T'
+#define        CATATONIA       'c'
+
+static state_func_t single_user(void);
+#ifndef LETS_GET_SMALL
+static state_func_t runcom(void);
+static state_func_t read_ttys(void);
+static state_func_t multi_user(void);
+static state_func_t clean_ttys(void);
+static state_func_t catatonia(void);
+static state_func_t death(void);
+#endif
+
+static enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
+
+static void transition(state_t);
+static void setctty(const char *);
+
+typedef struct init_session {
+       int     se_index;               /* index of entry in ttys file */
+       pid_t   se_process;             /* controlling process */
+       struct timeval  se_started;     /* used to avoid thrashing */
+       int     se_flags;               /* status of session */
+#define        SE_SHUTDOWN     0x1             /* session won't be restarted */
+#define        SE_PRESENT      0x2             /* session is in /etc/ttys */
+       char    *se_device;             /* filename of port */
+       char    *se_getty;              /* what to run on that port */
+       char    **se_getty_argv;        /* pre-parsed argument array */
+       char    *se_window;             /* window system (started only once) */
+       char    **se_window_argv;       /* pre-parsed argument array */
+       struct  init_session *se_prev;
+       struct  init_session *se_next;
+} session_t;
+
+static void collect_child(pid_t, int);
+static int clang;
+static void transition_handler(int);
+static void alrm_handler(int);
+static int has_securelevel(void);
+static int securelevel_present;
+
+#ifndef LETS_GET_SMALL
+static int do_setttyent(void);
+static void start_window_system(session_t *);
+static char **construct_argv(char *);
+static int setupargv(session_t *, struct ttyent *);
+static pid_t start_getty(session_t *);
+static void free_session(session_t *);
+static session_t *new_session(session_t *, int, struct ttyent *);
+static session_t *sessions;
+static void setsecuritylevel(int);
+static int getsecuritylevel(void);
+static int start_session_db(void);
+static void add_session(session_t *);
+static void del_session(session_t *);
+static session_t *find_session(pid_t);
+static DB *session_db;
+static state_t requested_transition = runcom;
+
+static void clear_session_logs(session_t *, int);
+static state_func_t runetcrc(int);
+#ifdef SUPPORT_UTMPX
+static struct timeval boot_time;
+static state_t current_state = death;
+static void session_utmpx(const session_t *, int);
+static void make_utmpx(const char *, const char *, int, pid_t,
+    const struct timeval *, int);
+static char get_runlevel(const state_t);
+static void utmpx_set_runlevel(char, char);
+#endif
+
+#ifdef CHROOT
+static int did_multiuser_chroot = 0;
+static char rootdir[PATH_MAX];
+static int shouldchroot(void);
+static int createsysctlnode(void);
+#endif /* CHROOT */
+
+#else /* LETS_GET_SMALL */
+static state_t requested_transition = single_user;
+#endif /* !LETS_GET_SMALL */
+
+#ifdef MFS_DEV_IF_NO_CONSOLE
+
+static int mfs_dev(void);
+
+#endif
+
+/*
+ * The mother of all processes.
+ */
+int
+main(int argc, char **argv)
+{
+       struct sigaction sa;
+       sigset_t mask;
+#ifndef LETS_GET_SMALL
+       int c;
+
+#ifdef SUPPORT_UTMPX
+       (void)gettimeofday(&boot_time, NULL);
+#endif /* SUPPORT_UTMPX */
+
+       /* Dispose of random users. */
+       if (getuid() != 0) {
+               errno = EPERM;
+               err(1, NULL);
+       }
+
+       /* System V users like to reexec init. */
+       if (getpid() != 1)
+               errx(1, "already running");
+#endif
+
+       /*
+        * Create an initial session.
+        */
+       if (setsid() < 0)
+               warn("initial setsid() failed");
+
+       /*
+        * Establish an initial user so that programs running
+        * single user do not freak out and die (like passwd).
+        */
+#ifndef __minix
+       if (setlogin("root") < 0)
+               warn("setlogin() failed");
+#endif
+
+
+#ifdef MFS_DEV_IF_NO_CONSOLE
+       if (mfs_dev() == -1)
+               requested_transition = single_user;
+#endif
+
+#ifndef LETS_GET_SMALL
+       /*
+        * Note that this does NOT open a file...
+        * Does 'init' deserve its own facility number?
+        */
+       openlog("init", LOG_CONS, LOG_AUTH);
+#endif /* LETS_GET_SMALL */
+
+
+#ifndef LETS_GET_SMALL
+       /*
+        * This code assumes that we always get arguments through flags,
+        * never through bits set in some random machine register.
+        */
+       while ((c = getopt(argc, argv, "sf")) != -1)
+               switch (c) {
+               case 's':
+                       requested_transition = single_user;
+                       break;
+               case 'f':
+                       runcom_mode = FASTBOOT;
+                       break;
+               default:
+                       warning("unrecognized flag `%c'", c);
+                       break;
+               }
+
+       if (optind != argc)
+               warning("ignoring excess arguments");
+#else /* LETS_GET_SMALL */
+       requested_transition = single_user;
+#endif /* LETS_GET_SMALL */
+
+       /*
+        * We catch or block signals rather than ignore them,
+        * so that they get reset on exec.
+        */
+#ifndef __minix
+       handle(badsys, SIGSYS, 0);
+       handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
+              SIGBUS, SIGXCPU, SIGXFSZ, 0);
+#else
+       handle(minixreboot, SIGABRT, 0);
+       handle(minixpowerdown, SIGUSR1, 0);
+       handle(disaster, SIGFPE, SIGILL, SIGSEGV, SIGBUS, 0);
+#endif
+       handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
+       handle(alrm_handler, SIGALRM, 0);
+       (void)sigfillset(&mask);
+#ifndef __minix
+       delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
+           SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
+#else
+       delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS,
+           SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
+#endif
+       (void)sigprocmask(SIG_SETMASK, &mask, NULL);
+       (void)sigemptyset(&sa.sa_mask);
+       sa.sa_flags = 0;
+       sa.sa_handler = SIG_IGN;
+       (void)sigaction(SIGTTIN, &sa, NULL);
+       (void)sigaction(SIGTTOU, &sa, NULL);
+
+       /*
+        * Paranoia.
+        */
+       (void)close(0);
+       (void)close(1);
+       (void)close(2);
+
+#if !defined(LETS_GET_SMALL) && defined(CHROOT)
+       /* Create "init.root" sysctl node. */
+       (void)createsysctlnode();
+#endif /* !LETS_GET_SMALL && CHROOT*/
+
+       /*
+        * Securelevel might not be supported by the kernel. Query for it, and
+        * set a variable indicating whether we should attempt anything with it
+        * or not.
+        */
+       securelevel_present = has_securelevel();
+
+       /*
+        * Start the state machine.
+        */
+       transition(requested_transition);
+
+       /*
+        * Should never reach here.
+        */
+       return 1;
+}
+
+/*
+ * Associate a function with a signal handler.
+ */
+static void
+handle(sig_t handler, ...)
+{
+       int sig;
+       struct sigaction sa;
+       sigset_t mask_everything;
+       va_list ap;
+
+       va_start(ap, handler);
+
+       sa.sa_handler = handler;
+       (void)sigfillset(&mask_everything);
+
+       while ((sig = va_arg(ap, int)) != 0) {
+               sa.sa_mask = mask_everything;
+               /* XXX SA_RESTART? */
+               sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
+               (void)sigaction(sig, &sa, NULL);
+       }
+       va_end(ap);
+}
+
+/*
+ * Delete a set of signals from a mask.
+ */
+static void
+delset(sigset_t *maskp, ...)
+{
+       int sig;
+       va_list ap;
+
+       va_start(ap, maskp);
+
+       while ((sig = va_arg(ap, int)) != 0)
+               (void)sigdelset(maskp, sig);
+       va_end(ap);
+}
+
+#if 0  /* Enable to get error messages from init ! */
+#define vsyslog(level, fmt, ap) print_console(level, fmt, ap)
+#define closelog()
+
+static void
+print_console(int level, const char *message, va_list ap)
+{
+       /*
+        * XXX: syslog seems to just plain not work in console-only
+        * XXX: situation... that should be fixed.  Let's leave this
+        * XXX: note + code here in case someone gets in trouble and
+        * XXX: wants to debug. -- Jachym Holecek <freza@liberouter.org>
+        */
+       char errbuf[1024];
+       int fd, len;
+
+       /* We can't do anything on errors, anyway... */
+       fd = open(_PATH_CONSOLE, O_WRONLY);
+       if (fd == -1)
+               return ;
+
+       /* %m will get lost... */
+       len = vsnprintf(errbuf, sizeof(errbuf), message, ap);
+       (void)write(fd, (void *)errbuf, len);
+       (void)close(fd);
+}
+#endif
+
+/*
+ * Log a message and sleep for a while (to give someone an opportunity
+ * to read it and to save log or hardcopy output if the problem is chronic).
+ * NB: should send a message to the session logger to avoid blocking.
+ */
+static void
+stall(const char *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_ALERT, message, ap);
+       va_end(ap);
+       closelog();
+       (void)sleep(STALL_TIMEOUT);
+}
+
+/*
+ * Like stall(), but doesn't sleep.
+ * If cpp had variadic macros, the two functions could be #defines for another.
+ * NB: should send a message to the session logger to avoid blocking.
+ */
+static void
+warning(const char *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_ALERT, message, ap);
+       va_end(ap);
+       closelog();
+}
+
+/*
+ * Log an emergency message.
+ * NB: should send a message to the session logger to avoid blocking.
+ */
+static void
+emergency(const char *message, ...)
+{
+       va_list ap;
+
+       va_start(ap, message);
+       vsyslog(LOG_EMERG, message, ap);
+       va_end(ap);
+       closelog();
+}
+
+#ifndef __minix
+/*
+ * Catch a SIGSYS signal.
+ *
+ * These may arise if a system does not support sysctl.
+ * We tolerate up to 25 of these, then throw in the towel.
+ */
+static void
+badsys(int sig)
+{
+       static int badcount = 0;
+
+       if (badcount++ < 25)
+               return;
+       disaster(sig);
+}
+#endif
+
+/*
+ * Catch an unexpected signal.
+ */
+static void
+disaster(int sig)
+{
+
+       emergency("fatal signal: %s", strsignal(sig));
+       (void)sleep(STALL_TIMEOUT);
+
+       _exit(sig);             /* reboot */
+}
+
+#ifdef __minix
+
+/*
+ * controlled reboot - minix tradition, SIGABRT by tty
+ */
+static void
+minixreboot(int sig)
+{
+       if(fork() == 0) {
+               (void)execl("/sbin/shutdown",
+                       "shutdown", "-r", "now", "CTRL-ALT_DEL", NULL);
+               _exit(1);
+       }
+}
+
+/*
+ * controlled powerdown
+ */
+static void
+minixpowerdown(int sig)
+{
+       if(fork() == 0) {
+               (void)execl("/sbin/shutdown",
+                       "shutdown", "-p", "now", "CTRL-ALT_DEL", NULL);
+               _exit(1);
+       }
+}
+
+#endif
+
+/*
+ * Check if securelevel is present.
+ */
+static int
+has_securelevel(void)
+{
+#ifdef __minix
+       return 0;
+#else
+#ifdef KERN_SECURELVL
+       int name[2], curlevel;
+       size_t len;
+
+       name[0] = CTL_KERN;
+       name[1] = KERN_SECURELVL;
+       len = sizeof curlevel;
+       if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
+               /* If it doesn't exist, it's okay. */
+               if (errno == ENOENT) 
+                       return 0;
+       }
+       return 1;
+#else
+       return 0;
+#endif
+#endif
+}
+
+/*
+ * Get the security level of the kernel.
+ */
+static int
+getsecuritylevel(void)
+{
+#ifdef KERN_SECURELVL
+       int name[2], curlevel;
+       size_t len;
+
+       if (!securelevel_present)
+               return -1;
+
+       name[0] = CTL_KERN;
+       name[1] = KERN_SECURELVL;
+       len = sizeof curlevel;
+       if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
+               emergency("cannot get kernel security level: %m");
+               return -1;
+       }
+       return curlevel;
+#else
+       return -1;
+#endif
+}
+
+/*
+ * Set the security level of the kernel.
+ */
+static void
+setsecuritylevel(int newlevel)
+{
+#ifdef KERN_SECURELVL
+       int name[2], curlevel;
+
+       if (!securelevel_present)
+               return;
+
+       curlevel = getsecuritylevel();
+       if (newlevel == curlevel)
+               return;
+       name[0] = CTL_KERN;
+       name[1] = KERN_SECURELVL;
+       if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
+               emergency("cannot change kernel security level from"
+                   " %d to %d: %m", curlevel, newlevel);
+               return;
+       }
+#ifdef SECURE
+       warning("kernel security level changed from %d to %d",
+           curlevel, newlevel);
+#endif
+#endif
+}
+
+/*
+ * Change states in the finite state machine.
+ * The initial state is passed as an argument.
+ */
+static void
+transition(state_t s)
+{
+
+       if (s == NULL)
+               return;
+       for (;;) {
+#ifdef SUPPORT_UTMPX
+#ifndef LETS_GET_SMALL
+               utmpx_set_runlevel(get_runlevel(current_state),
+                   get_runlevel(s));
+               current_state = s;
+#endif
+#endif
+               s = (state_t)(*s)();
+       }
+}
+
+#ifndef LETS_GET_SMALL
+/*
+ * Close out the accounting files for a login session.
+ * NB: should send a message to the session logger to avoid blocking.
+ */
+static void
+clear_session_logs(session_t *sp, int status)
+{
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+       char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
+#endif
+
+#ifdef SUPPORT_UTMPX
+       if (logoutx(line, status, DEAD_PROCESS))
+               logwtmpx(line, "", "", status, DEAD_PROCESS);
+#endif
+#ifdef SUPPORT_UTMP
+       if (logout(line))
+               logwtmp(line, "", "");
+#endif
+}
+#endif
+
+/*
+ * Start a session and allocate a controlling terminal.
+ * Only called by children of init after forking.
+ */
+static void
+setctty(const char *name)
+{
+       int fd;
+
+#ifndef __minix
+       (void)revoke(name);
+#else
+       if (setsid() < 0)
+               warn("child setsid() failed");
+#endif
+       (void)nanosleep(&dtrtime, NULL);        /* leave DTR low for a bit */
+       if ((fd = open(name, O_RDWR)) == -1) {
+               stall("can't open %s: %m", name);
+               _exit(1);
+       }
+       if (login_tty(fd) == -1) {
+               stall("can't get %s for controlling terminal: %m", name);
+               _exit(2);
+       }
+}
+
+/*
+ * Bring the system up single user.
+ */
+static state_func_t
+single_user(void)
+{
+       pid_t pid, wpid;
+       int status;
+       int from_securitylevel;
+       sigset_t mask;
+       struct sigaction sa, satstp, sahup;
+#ifdef ALTSHELL
+       const char *shell = INIT_BSHELL;
+#endif
+       const char *argv[2];
+#ifdef SECURE
+       struct ttyent *typ;
+       struct passwd *pp;
+       char *clear, *password;
+#endif
+#ifdef ALTSHELL
+       char altshell[128];
+#endif /* ALTSHELL */
+
+#if !defined(LETS_GET_SMALL) && defined(CHROOT)
+       /* Clear previous idea, just in case. */
+       did_multiuser_chroot = 0;
+#endif /* !LETS_GET_SMALL && CHROOT */
+
+       /*
+        * If the kernel is in secure mode, downgrade it to insecure mode.
+        */
+       from_securitylevel = getsecuritylevel();
+       if (from_securitylevel > 0)
+               setsecuritylevel(0);
+
+       (void)sigemptyset(&sa.sa_mask);
+       sa.sa_flags = 0;
+       sa.sa_handler = SIG_IGN;
+       (void)sigaction(SIGTSTP, &sa, &satstp);
+       (void)sigaction(SIGHUP, &sa, &sahup);
+       if ((pid = fork()) == 0) {
+               /*
+                * Start the single user session.
+                */
+               if (access(_PATH_CONSTTY, F_OK) == 0)
+                       setctty(_PATH_CONSTTY);
+               else
+                       setctty(_PATH_CONSOLE);
+
+#ifdef SECURE
+               /*
+                * Check the root password.
+                * We don't care if the console is 'on' by default;
+                * it's the only tty that can be 'off' and 'secure'.
+                */
+               typ = getttynam("console");
+               pp = getpwnam("root");
+               if (typ && (from_securitylevel >=2 || (typ->ty_status
+                   & TTY_SECURE) == 0) && pp && *pp->pw_passwd != '\0') {
+                       (void)fprintf(stderr,
+                           "Enter root password, or ^D to go multi-user\n");
+                       for (;;) {
+                               clear = getpass("Password:");
+                               if (clear == 0 || *clear == '\0')
+                                       _exit(0);
+                               password = crypt(clear, pp->pw_passwd);
+                               (void)memset(clear, 0, _PASSWORD_LEN);
+                               if (strcmp(password, pp->pw_passwd) == 0)
+                                       break;
+                               warning("single-user login failed");
+                       }
+               }
+               (void)endttyent();
+               endpwent();
+#endif /* SECURE */
+
+#ifdef ALTSHELL
+               (void)fprintf(stderr,
+                   "Enter pathname of shell or RETURN for %s: ", shell);
+               if (fgets(altshell, sizeof(altshell), stdin) == NULL) {
+                       altshell[0] = '\0';
+               } else {
+                       /* nuke \n */
+                       char *p;
+
+                       if ((p = strchr(altshell, '\n')) != NULL)
+                               *p = '\0';
+               }
+
+               if (altshell[0])
+                       shell = altshell;
+#endif /* ALTSHELL */
+
+               /*
+                * Unblock signals.
+                * We catch all the interesting ones,
+                * and those are reset to SIG_DFL on exec.
+                */
+               (void)sigemptyset(&mask);
+               (void)sigprocmask(SIG_SETMASK, &mask, NULL);
+
+               /*
+                * Fire off a shell.
+                * If the default one doesn't work, try the Bourne shell.
+                */
+               argv[0] = "-sh";
+               argv[1] = 0;
+               (void)setenv("PATH", INIT_PATH, 1);
+#ifdef ALTSHELL
+               if (altshell[0])
+                       argv[0] = altshell;
+               (void)execv(shell, __UNCONST(argv));
+               emergency("can't exec `%s' for single user: %m", shell);
+               argv[0] = "-sh";
+#endif /* ALTSHELL */
+               (void)execv(INIT_BSHELL, __UNCONST(argv));
+               emergency("can't exec `%s' for single user: %m", INIT_BSHELL);
+               (void)sleep(STALL_TIMEOUT);
+               _exit(3);
+       }
+
+       if (pid == -1) {
+               /*
+                * We are seriously hosed.  Do our best.
+                */
+               emergency("can't fork single-user shell: %m, trying again");
+               while (waitpid(-1, NULL, WNOHANG) > 0)
+                       continue;
+               (void)sigaction(SIGTSTP, &satstp, NULL);
+               (void)sigaction(SIGHUP, &sahup, NULL);
+               return (state_func_t)single_user;
+       }
+
+       requested_transition = 0;
+       do {
+               if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
+                       collect_child(wpid, status);
+               if (wpid == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       warning("wait for single-user shell failed: %m; "
+                           "restarting");
+                       return (state_func_t)single_user;
+               }
+               if (wpid == pid && WIFSTOPPED(status)) {
+                       warning("shell stopped, restarting");
+                       (void)kill(pid, SIGCONT);
+                       wpid = -1;
+               }
+       } while (wpid != pid && !requested_transition);
+
+       if (requested_transition) {
+               (void)sigaction(SIGTSTP, &satstp, NULL);
+               (void)sigaction(SIGHUP, &sahup, NULL);
+               return (state_func_t)requested_transition;
+       }
+
+       if (WIFSIGNALED(status)) {
+               if (WTERMSIG(status) == SIGKILL) {
+                       /* executed /sbin/reboot; wait for the end quietly */
+                       sigset_t s;
+       
+                       (void)sigfillset(&s);
+                       for (;;)
+                               (void)sigsuspend(&s);
+               } else {        
+                       warning("single user shell terminated (%x), restarting",
+                               status);
+                       (void)sigaction(SIGTSTP, &satstp, NULL);
+                       (void)sigaction(SIGHUP, &sahup, NULL);
+                       return (state_func_t)single_user;
+               }
+       }
+
+       runcom_mode = FASTBOOT;
+       (void)sigaction(SIGTSTP, &satstp, NULL);
+       (void)sigaction(SIGHUP, &sahup, NULL);
+#ifndef LETS_GET_SMALL
+       return (state_func_t)runcom;
+#else /* LETS_GET_SMALL */
+       return (state_func_t)single_user;
+#endif /* LETS_GET_SMALL */
+}
+
+#ifndef LETS_GET_SMALL
+
+/* ARGSUSED */
+static state_func_t
+runetcrc(int trychroot)
+{
+       pid_t pid, wpid;
+       int status;
+       const char *argv[4];
+       struct sigaction sa;
+
+       switch ((pid = fork())) {
+       case 0:
+               (void)sigemptyset(&sa.sa_mask);
+               sa.sa_flags = 0;
+               sa.sa_handler = SIG_IGN;
+               (void)sigaction(SIGTSTP, &sa, NULL);
+               (void)sigaction(SIGHUP, &sa, NULL);
+
+               setctty(_PATH_CONSOLE);
+
+               argv[0] = "sh";
+               argv[1] = _PATH_RUNCOM;
+               argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0);
+               argv[3] = 0;
+
+               (void)sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
+
+#ifdef CHROOT
+               if (trychroot)
+                       if (chroot(rootdir) != 0) {
+                               warning("failed to chroot to `%s': %m",
+                                   rootdir);
+                               _exit(4);       /* force single user mode */
+                       }
+#endif /* CHROOT */
+
+               (void)execv(INIT_BSHELL, __UNCONST(argv));
+               stall("can't exec `%s' for `%s': %m", INIT_BSHELL, _PATH_RUNCOM);
+               _exit(5);       /* force single user mode */
+               /*NOTREACHED*/
+       case -1:
+               emergency("can't fork for `%s' on `%s': %m", INIT_BSHELL,
+                   _PATH_RUNCOM);
+               while (waitpid(-1, NULL, WNOHANG) > 0)
+                       continue;
+               (void)sleep(STALL_TIMEOUT);
+               return (state_func_t)single_user;
+       default:
+               break;
+       }
+
+       /*
+        * Copied from single_user().  This is a bit paranoid.
+        */
+       do {
+               if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
+                       collect_child(wpid, status);
+               if (wpid == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       warning("wait for `%s' on `%s' failed: %m; going to "
+                           "single user mode", INIT_BSHELL, _PATH_RUNCOM);
+                       return (state_func_t)single_user;
+               }
+               if (wpid == pid && WIFSTOPPED(status)) {
+                       warning("`%s' on `%s' stopped, restarting",
+                           INIT_BSHELL, _PATH_RUNCOM);
+                       (void)kill(pid, SIGCONT);
+                       wpid = -1;
+               }
+       } while (wpid != pid);
+
+       if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
+           requested_transition == catatonia) {
+               /* /etc/rc executed /sbin/reboot; wait for the end quietly */
+               sigset_t s;
+
+               (void)sigfillset(&s);
+               for (;;)
+                       (void)sigsuspend(&s);
+       }
+
+       if (!WIFEXITED(status)) {
+               warning("`%s' on `%s' terminated abnormally, going to "
+                   "single user mode", INIT_BSHELL, _PATH_RUNCOM);
+               return (state_func_t)single_user;
+       }
+
+       if (WEXITSTATUS(status))
+               return (state_func_t)single_user;
+
+       return (state_func_t)read_ttys;
+}
+
+/*
+ * Run the system startup script.
+ */
+static state_func_t
+runcom(void)
+{
+       state_func_t next_step;
+
+       /* Run /etc/rc and choose next state depending on the result. */
+       next_step = runetcrc(0);
+       if (next_step != (state_func_t)read_ttys)
+               return (state_func_t)next_step;
+
+#ifdef CHROOT
+       /*
+        * If init.root sysctl does not point to "/", we'll chroot and run
+        * The Real(tm) /etc/rc now.  Global variable rootdir will tell us
+        * where to go.
+        */
+       if (shouldchroot()) {
+               next_step = runetcrc(1);
+               if (next_step != (state_func_t)read_ttys)
+                       return (state_func_t)next_step;
+
+               did_multiuser_chroot = 1;
+       } else {
+               did_multiuser_chroot = 0;
+       }
+#endif /* CHROOT */
+
+       /*
+        * Regardless of whether in chroot or not, we booted successfuly.
+        * It's time to spawn gettys (ie. next_step's value at this point).
+        */
+       runcom_mode = AUTOBOOT;         /* the default */
+       /* NB: should send a message to the session logger to avoid blocking. */
+#ifdef SUPPORT_UTMPX
+       logwtmpx("~", "reboot", "", 0, INIT_PROCESS);
+#endif
+#ifdef SUPPORT_UTMP
+       logwtmp("~", "reboot", "");
+#endif
+       return (state_func_t)read_ttys;
+}
+
+/*
+ * Open the session database.
+ *
+ * NB: We could pass in the size here; is it necessary?
+ */
+static int
+start_session_db(void)
+{
+
+       if (session_db && (*session_db->close)(session_db))
+               emergency("session database close: %m");
+       if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
+               emergency("session database open: %m");
+               return 1;
+       }
+       return 0;
+               
+}
+
+/*
+ * Add a new login session.
+ */
+static void
+add_session(session_t *sp)
+{
+       DBT key;
+       DBT data;
+
+       if (session_db == NULL)
+               return;
+
+       key.data = &sp->se_process;
+       key.size = sizeof sp->se_process;
+       data.data = &sp;
+       data.size = sizeof sp;
+
+       if ((*session_db->put)(session_db, &key, &data, 0))
+               emergency("insert %d: %m", sp->se_process);
+#ifdef SUPPORT_UTMPX
+       session_utmpx(sp, 1);
+#endif
+}
+
+/*
+ * Delete an old login session.
+ */
+static void
+del_session(session_t *sp)
+{
+       DBT key;
+
+       key.data = &sp->se_process;
+       key.size = sizeof sp->se_process;
+
+       if ((*session_db->del)(session_db, &key, 0))
+               emergency("delete %d: %m", sp->se_process);
+#ifdef SUPPORT_UTMPX
+       session_utmpx(sp, 0);
+#endif
+}
+
+/*
+ * Look up a login session by pid.
+ */
+static session_t *
+find_session(pid_t pid)
+{
+       DBT key;
+       DBT data;
+       session_t *ret;
+
+       if (session_db == NULL)
+               return NULL;
+
+       key.data = &pid;
+       key.size = sizeof pid;
+       if ((*session_db->get)(session_db, &key, &data, 0) != 0)
+               return 0;
+       (void)memmove(&ret, data.data, sizeof(ret));
+       return ret;
+}
+
+/*
+ * Construct an argument vector from a command line.
+ */
+static char **
+construct_argv(char *command)
+{
+       int argc = 0;
+       char **argv = malloc(((strlen(command) + 1) / 2 + 1) * sizeof (char *));
+       static const char separators[] = " \t";
+
+       if (argv == NULL)
+               return NULL;
+
+       if ((argv[argc++] = strtok(command, separators)) == 0) {
+               free(argv);
+               return NULL;
+       }
+       while ((argv[argc++] = strtok(NULL, separators)) != NULL)
+               continue;
+       return argv;
+}
+
+/*
+ * Deallocate a session descriptor.
+ */
+static void
+free_session(session_t *sp)
+{
+
+       free(sp->se_device);
+       if (sp->se_getty) {
+               free(sp->se_getty);
+               free(sp->se_getty_argv);
+       }
+       if (sp->se_window) {
+               free(sp->se_window);
+               free(sp->se_window_argv);
+       }
+       free(sp);
+}
+
+/*
+ * Allocate a new session descriptor.
+ */
+static session_t *
+new_session(session_t *sprev, int session_index, struct ttyent *typ)
+{
+       session_t *sp;
+
+       if ((typ->ty_status & TTY_ON) == 0 || typ->ty_name == NULL ||
+           typ->ty_getty == NULL)
+               return NULL;
+
+       sp = malloc(sizeof (session_t));
+       if (sp == NULL)
+               return NULL;
+       (void)memset(sp, 0, sizeof *sp);
+
+       sp->se_flags = SE_PRESENT;
+       sp->se_index = session_index;
+
+       (void)asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
+       if (!sp->se_device)
+               return NULL;
+
+       if (setupargv(sp, typ) == 0) {
+               free_session(sp);
+               return NULL;
+       }
+
+       sp->se_next = NULL;
+       if (sprev == NULL) {
+               sessions = sp;
+               sp->se_prev = NULL;
+       } else {
+               sprev->se_next = sp;
+               sp->se_prev = sprev;
+       }
+
+       return sp;
+}
+
+/*
+ * Calculate getty and if useful window argv vectors.
+ */
+static int
+setupargv(session_t *sp, struct ttyent *typ)
+{
+
+       if (sp->se_getty) {
+               free(sp->se_getty);
+               free(sp->se_getty_argv);
+       }
+       (void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
+       if (!sp->se_getty)
+               return 0;
+       sp->se_getty_argv = construct_argv(sp->se_getty);
+       if (sp->se_getty_argv == NULL) {
+               warning("can't parse getty for port `%s'", sp->se_device);
+               free(sp->se_getty);
+               sp->se_getty = NULL;
+               return 0;
+       }
+       if (typ->ty_window) {
+               if (sp->se_window)
+                       free(sp->se_window);
+               sp->se_window = strdup(typ->ty_window);
+               sp->se_window_argv = construct_argv(sp->se_window);
+               if (sp->se_window_argv == NULL) {
+                       warning("can't parse window for port `%s'",
+                           sp->se_device);
+                       free(sp->se_window);
+                       sp->se_window = NULL;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * Walk the list of ttys and create sessions for each active line.
+ */
+static state_func_t
+read_ttys(void)
+{
+       int session_index = 0;
+       session_t *sp, *snext;
+       struct ttyent *typ;
+
+#ifdef SUPPORT_UTMPX
+       if (sessions == NULL) {
+               struct stat st;
+
+               make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0);
+
+               /*
+                * If wtmpx is not empty, pick the down time from there
+                */
+               if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) {
+                       struct timeval down_time;
+
+                       TIMESPEC_TO_TIMEVAL(&down_time, 
+                           st.st_atime > st.st_mtime ?
+                           &st.st_atimespec : &st.st_mtimespec);
+                       make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0);
+               }
+       }
+#endif
+       /*
+        * Destroy any previous session state.
+        * There shouldn't be any, but just in case...
+        */
+       for (sp = sessions; sp; sp = snext) {
+#ifndef LETS_GET_SMALL
+               if (sp->se_process)
+                       clear_session_logs(sp, 0);
+#endif
+               snext = sp->se_next;
+               free_session(sp);
+       }
+       sessions = NULL;
+
+       if (start_session_db()) {
+               warning("start_session_db failed, death");
+#ifdef CHROOT
+               /* If /etc/rc ran in chroot, we want to kill any survivors. */
+               if (did_multiuser_chroot)
+                       return (state_func_t)death;
+               else
+#endif /* CHROOT */
+                       return (state_func_t)single_user;
+       }
+
+       (void)do_setttyent();
+
+       /*
+        * Allocate a session entry for each active port.
+        * Note that sp starts at 0.
+        */
+       while ((typ = getttyent()) != NULL)
+               if ((snext = new_session(sp, ++session_index, typ)) != NULL)
+                       sp = snext;
+       (void)endttyent();
+
+       return (state_func_t)multi_user;
+}
+
+/*
+ * Start a window system running.
+ */
+static void
+start_window_system(session_t *sp)
+{
+       pid_t pid;
+       sigset_t mask;
+
+       if ((pid = fork()) == -1) {
+               emergency("can't fork for window system on port `%s': %m",
+                   sp->se_device);
+               /* hope that getty fails and we can try again */
+               return;
+       }
+
+       if (pid)
+               return;
+
+       (void)sigemptyset(&mask);
+       (void)sigprocmask(SIG_SETMASK, &mask, NULL);
+
+       if (setsid() < 0)
+               emergency("setsid failed (window): %m");
+
+       (void)execv(sp->se_window_argv[0], sp->se_window_argv);
+       stall("can't exec window system `%s' for port `%s': %m",
+           sp->se_window_argv[0], sp->se_device);
+       _exit(6);
+}
+
+/*
+ * Start a login session running.
+ */
+static pid_t
+start_getty(session_t *sp)
+{
+       pid_t pid;
+       sigset_t mask;
+       time_t current_time = time(NULL);
+
+       /*
+        * fork(), not vfork() -- we can't afford to block.
+        */
+       if ((pid = fork()) == -1) {
+               emergency("can't fork for getty on port `%s': %m",
+                   sp->se_device);
+               return -1;
+       }
+
+       if (pid)
+               return pid;
+
+#ifdef CHROOT
+       /* If /etc/rc did proceed inside chroot, we have to try as well. */
+       if (did_multiuser_chroot)
+               if (chroot(rootdir) != 0) {
+                       stall("can't chroot getty `%s' inside `%s': %m",
+                           sp->se_getty_argv[0], rootdir);
+                       _exit(7);
+               }
+#endif /* CHROOT */
+
+       if (current_time > sp->se_started.tv_sec &&
+           current_time - sp->se_started.tv_sec < GETTY_SPACING) {
+               warning("getty repeating too quickly on port `%s', sleeping",
+                   sp->se_device);
+               (void)sleep(GETTY_SLEEP);
+       }
+
+       if (sp->se_window) {
+               start_window_system(sp);
+               (void)sleep(WINDOW_WAIT);
+       }
+
+       (void)sigemptyset(&mask);
+       (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
+
+       (void)execv(sp->se_getty_argv[0], sp->se_getty_argv);
+
+       stall("can't exec getty `%s' for port `%s': %m",
+           sp->se_getty_argv[0], sp->se_device);
+       _exit(8);
+       /*NOTREACHED*/
+}
+#ifdef SUPPORT_UTMPX
+static void
+session_utmpx(const session_t *sp, int add)
+{
+       const char *name = sp->se_getty ? sp->se_getty :
+           (sp->se_window ? sp->se_window : "");
+       const char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
+
+       make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS,
+           sp->se_process, &sp->se_started, sp->se_index);
+}
+
+static void
+make_utmpx(const char *name, const char *line, int type, pid_t pid,
+    const struct timeval *tv, int session)
+{
+       struct utmpx ut;
+       const char *eline;
+
+       (void)memset(&ut, 0, sizeof(ut));
+       (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name));
+       ut.ut_type = type;
+       (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
+       ut.ut_pid = pid;
+       if (tv)
+               ut.ut_tv = *tv;
+       else
+               (void)gettimeofday(&ut.ut_tv, NULL);
+       ut.ut_session = session;
+
+       eline = line + strlen(line);
+       if ((size_t)(eline - line) >= sizeof(ut.ut_id))
+               line = eline - sizeof(ut.ut_id);
+       (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id));
+
+       if (pututxline(&ut) == NULL)
+               warning("can't add utmpx record for `%s': %m", ut.ut_line);
+       endutxent();
+}
+
+static char
+get_runlevel(const state_t s)
+{
+       if (s == (state_t)single_user)
+               return SINGLE_USER;
+       if (s == (state_t)runcom)
+               return RUNCOM;
+       if (s == (state_t)read_ttys)
+               return READ_TTYS;
+       if (s == (state_t)multi_user)
+               return MULTI_USER;
+       if (s == (state_t)clean_ttys)
+               return CLEAN_TTYS;
+       if (s == (state_t)catatonia)
+               return CATATONIA;
+       return DEATH;
+}
+
+static void
+utmpx_set_runlevel(char old, char new)
+{
+       struct utmpx ut;
+
+       /*
+        * Don't record any transitions until we did the first transition
+        * to read ttys, which is when we are guaranteed to have a read-write
+        * /var. Perhaps use a different variable for this?
+        */
+       if (sessions == NULL)
+               return;
+
+       (void)memset(&ut, 0, sizeof(ut));
+       (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new);
+       ut.ut_type = RUN_LVL;
+       (void)gettimeofday(&ut.ut_tv, NULL);
+       ut.ut_exit.e_exit = old;
+       ut.ut_exit.e_termination = new;
+       if (pututxline(&ut) == NULL)
+               warning("can't add utmpx record for `runlevel': %m");
+       endutxent();
+}
+#endif /* SUPPORT_UTMPX */
+
+#endif /* LETS_GET_SMALL */
+
+/*
+ * Collect exit status for a child.
+ * If an exiting login, start a new login running.
+ */
+static void
+collect_child(pid_t pid, int status)
+{
+#ifndef LETS_GET_SMALL
+       session_t *sp, *sprev, *snext;
+
+       if (! sessions)
+               return;
+
+       if ((sp = find_session(pid)) == NULL)
+               return;
+
+       clear_session_logs(sp, status);
+       del_session(sp);
+       sp->se_process = 0;
+
+       if (sp->se_flags & SE_SHUTDOWN) {
+               if ((sprev = sp->se_prev) != NULL)
+                       sprev->se_next = sp->se_next;
+               else
+                       sessions = sp->se_next;
+               if ((snext = sp->se_next) != NULL)
+                       snext->se_prev = sp->se_prev;
+               free_session(sp);
+               return;
+       }
+
+       if ((pid = start_getty(sp)) == -1) {
+               /* serious trouble */
+               requested_transition = clean_ttys;
+               return;
+       }
+
+       sp->se_process = pid;
+       (void)gettimeofday(&sp->se_started, NULL);
+       add_session(sp);
+#endif /* LETS_GET_SMALL */
+}
+
+/*
+ * Catch a signal and request a state transition.
+ */
+static void
+transition_handler(int sig)
+{
+
+       switch (sig) {
+#ifndef LETS_GET_SMALL
+       case SIGHUP:
+               requested_transition = clean_ttys;
+               break;
+       case SIGTERM:
+               requested_transition = death;
+               break;
+       case SIGTSTP:
+               requested_transition = catatonia;
+               break;
+#endif /* LETS_GET_SMALL */
+       default:
+               requested_transition = 0;
+               break;
+       }
+}
+
+#ifndef LETS_GET_SMALL
+/*
+ * Take the system multiuser.
+ */
+static state_func_t
+multi_user(void)
+{
+       pid_t pid;
+       int status;
+       session_t *sp;
+
+       requested_transition = 0;
+
+       /*
+        * If the administrator has not set the security level to -1
+        * to indicate that the kernel should not run multiuser in secure
+        * mode, and the run script has not set a higher level of security 
+        * than level 1, then put the kernel into secure mode.
+        */
+       if (getsecuritylevel() == 0)
+               setsecuritylevel(1);
+
+       for (sp = sessions; sp; sp = sp->se_next) {
+               if (sp->se_process)
+                       continue;
+               if ((pid = start_getty(sp)) == -1) {
+                       /* serious trouble */
+                       requested_transition = clean_ttys;
+                       break;
+               }
+               sp->se_process = pid;
+               (void)gettimeofday(&sp->se_started, NULL);
+               add_session(sp);
+       }
+
+       while (!requested_transition)
+               if ((pid = waitpid(-1, &status, 0)) != -1)
+                       collect_child(pid, status);
+
+       return (state_func_t)requested_transition;
+}
+
+/*
+ * This is an n-squared algorithm.  We hope it isn't run often...
+ */
+static state_func_t
+clean_ttys(void)
+{
+       session_t *sp, *sprev;
+       struct ttyent *typ;
+       int session_index = 0;
+       int devlen;
+
+       for (sp = sessions; sp; sp = sp->se_next)
+               sp->se_flags &= ~SE_PRESENT;
+
+       (void)do_setttyent();
+
+       devlen = sizeof(_PATH_DEV) - 1;
+       while ((typ = getttyent()) != NULL) {
+               ++session_index;
+
+               for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
+                       if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
+                               break;
+
+               if (sp) {
+                       sp->se_flags |= SE_PRESENT;
+                       if (sp->se_index != session_index) {
+                               warning("port `%s' changed utmp index from "
+                                   "%d to %d", sp->se_device, sp->se_index,
+                                   session_index);
+                               sp->se_index = session_index;
+                       }
+                       if ((typ->ty_status & TTY_ON) == 0 ||
+                           typ->ty_getty == 0) {
+                               sp->se_flags |= SE_SHUTDOWN;
+                               if (sp->se_process != 0)
+                                       (void)kill(sp->se_process, SIGHUP);
+                               continue;
+                       }
+                       sp->se_flags &= ~SE_SHUTDOWN;
+                       if (setupargv(sp, typ) == 0) {
+                               warning("can't parse getty for port `%s'",
+                                   sp->se_device);
+                               sp->se_flags |= SE_SHUTDOWN;
+                               if (sp->se_process != 0)
+                                       (void)kill(sp->se_process, SIGHUP);
+                       }
+                       continue;
+               }
+
+               (void)new_session(sprev, session_index, typ);
+       }
+
+       (void)endttyent();
+
+       for (sp = sessions; sp; sp = sp->se_next)
+               if ((sp->se_flags & SE_PRESENT) == 0) {
+                       sp->se_flags |= SE_SHUTDOWN;
+                       if (sp->se_process != 0)
+                               (void)kill(sp->se_process, SIGHUP);
+               }
+
+       return (state_func_t)multi_user;
+}
+
+/*
+ * Block further logins.
+ */
+static state_func_t
+catatonia(void)
+{
+       session_t *sp;
+
+       for (sp = sessions; sp; sp = sp->se_next)
+               sp->se_flags |= SE_SHUTDOWN;
+
+       return (state_func_t)multi_user;
+}
+#endif /* LETS_GET_SMALL */
+
+/*
+ * Note SIGALRM.
+ */
+static void
+/*ARGSUSED*/
+alrm_handler(int sig)
+{
+
+       clang = 1;
+}
+
+#ifndef LETS_GET_SMALL
+/*
+ * Bring the system down to single user.
+ */
+static state_func_t
+death(void)
+{
+       session_t *sp;
+       int i, status;
+       pid_t pid;
+       static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
+
+       for (sp = sessions; sp; sp = sp->se_next)
+               sp->se_flags |= SE_SHUTDOWN;
+
+       /* NB: should send a message to the session logger to avoid blocking. */
+#ifdef SUPPORT_UTMPX
+       logwtmpx("~", "shutdown", "", 0, INIT_PROCESS);
+#endif
+#ifdef SUPPORT_UTMP
+       logwtmp("~", "shutdown", "");
+#endif
+
+       for (i = 0; i < 3; ++i) {
+               if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
+                       return (state_func_t)single_user;
+
+               clang = 0;
+               (void)alarm(DEATH_WATCH);
+               do
+                       if ((pid = waitpid(-1, &status, 0)) != -1)
+                               collect_child(pid, status);
+               while (clang == 0 && errno != ECHILD);
+
+               if (errno == ECHILD)
+                       return (state_func_t)single_user;
+       }
+
+       warning("some processes would not die; ps axl advised");
+
+       return (state_func_t)single_user;
+}
+#endif /* LETS_GET_SMALL */
+
+#ifdef MFS_DEV_IF_NO_CONSOLE
+
+static int
+mfs_dev(void)
+{
+       /*
+        * We cannot print errors so we bail out silently...
+        */
+       pid_t pid;
+       int status;
+
+       /* If we have /dev/console, assume all is OK  */
+       if (access(_PATH_CONSOLE, F_OK) == 0)
+               return 0;
+
+#if 0  /* Useful for testing MAKEDEV */
+       /* Mount an mfs over /mnt so we can create a console entry */
+       switch ((pid = fork())) {
+       case 0:
+               (void)execl(INIT_MOUNT_MFS, "mount_mfs",
+                   "-b", "4096", "-f", "512",
+                   "-s", 64, "-n", 10,
+                   "-p", "0755",
+                   "swap", "/mnt", NULL);
+               _exit(9);
+               /*NOTREACHED*/
+
+       case -1:
+               return(-1);
+
+       default:
+               if (waitpid(pid, &status, 0) == -1)
+                       return(-1);
+               if (status != 0)
+                       return(-1);
+               break;
+       }
+
+       {
+               dev_t dev;
+#ifdef CPU_CONSDEV
+               static int name[2] = { CTL_MACHDEP, CPU_CONSDEV };
+               size_t olen;
+               olen = sizeof(dev);
+               if (sysctl(name, sizeof(name) / sizeof(name[0]), &dev, &olen,
+                   NULL, 0) == -1)
+#endif
+                       dev = makedev(0, 0);
+
+               /* Make a console for us, so we can see things happening */
+               if (mknod("/mnt/console", 0666 | S_IFCHR, dev) == -1)
+                       return(-1);
+               (void)freopen("/mnt/console", "a", stderr);
+       }
+
+#endif
+
+       /* Run the makedev script to create devices */
+       switch ((pid = fork())) {
+       case 0:
+               (void)dup2(2, 1);       /* Give the script stdout */
+               if (chdir("/dev") == 0)
+                       (void)execl(INIT_BSHELL, "sh",
+                           access("./MAKEDEV", X_OK) == 0
+                               ? "./MAKEDEV" : "/etc/MAKEDEV",
+                           "-MM", "init", NULL); 
+               _exit(10);
+               /* NOTREACHED */
+
+       case -1:
+               break;
+
+       default:
+               if (waitpid(pid, &status, 0) == -1)
+                       break;
+               if (status != 0)
+                       warn("MAKEDEV exit status %d\n", status);
+               /*
+                * If /dev/console got created, then return 0
+                * regardless of MAKEDEV exit status.
+                */
+               if (access(_PATH_CONSOLE, F_OK) == 0)
+                       return 0;
+               _exit(11);
+       }
+       warn("Unable to run MAKEDEV");
+       _exit(12);
+}
+#endif
+
+#ifndef LETS_GET_SMALL
+static int
+do_setttyent(void)
+{
+       (void)endttyent();
+#ifdef CHROOT
+       if (did_multiuser_chroot) {
+               char path[PATH_MAX];
+
+               (void)snprintf(path, sizeof(path), "%s/%s", rootdir, _PATH_TTYS);
+
+               return setttyentpath(path);
+       } else
+#endif /* CHROOT */
+               return setttyent();
+}
+#endif
+
+#if !defined(LETS_GET_SMALL) && defined(CHROOT)
+
+static int
+createsysctlnode(void)
+{
+#ifndef __minix
+       struct sysctlnode node;
+       int mib[2];
+       size_t len;
+
+       /*
+        * Create top-level dynamic sysctl node.  Its child nodes will only
+        * be readable by the superuser, since regular mortals should not
+        * care ("Sssh, it's a secret!").
+        */
+       len = sizeof(struct sysctlnode);
+       mib[0] = CTL_CREATE;
+
+       (void)memset(&node, 0, len);
+       node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
+           CTLFLAG_PRIVATE | CTLTYPE_NODE;
+       node.sysctl_num = CTL_CREATE;
+       (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "init");
+       if (sysctl(&mib[0], 1, &node, &len, &node, len) == -1) {
+               warning("could not create init node: %m");
+               return -1;
+       }
+
+       /*
+        * Create second level dynamic node capable of holding pathname.
+        * Provide "/" as the default value.
+        */
+       len = sizeof(struct sysctlnode);
+       mib[0] = node.sysctl_num;
+       mib[1] = CTL_CREATE;
+
+       (void)memset(&node, 0, len);
+       node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
+           CTLTYPE_STRING | CTLFLAG_OWNDATA;
+       node.sysctl_size = _POSIX_PATH_MAX;
+       node.sysctl_data = __UNCONST("/");
+       node.sysctl_num = CTL_CREATE;
+       (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "root");
+       if (sysctl(&mib[0], 2, NULL, NULL, &node, len) == -1) {
+               warning("could not create init.root node: %m");
+               return -1;
+       }
+
+#endif
+
+       return 0;
+}
+
+static int
+shouldchroot(void)
+{
+#ifndef __minix
+       struct sysctlnode node;
+       size_t len, cnt;
+       int mib;
+
+       len = sizeof(struct sysctlnode);
+
+       if (sysctlbyname("init.root", rootdir, &len, NULL, 0) == -1) {
+               warning("could not read init.root: %m");
+
+               /* Child killed our node. Recreate it. */
+               if (errno == ENOENT) {
+                       /* Destroy whatever is left, recreate from scratch. */
+                       if (sysctlnametomib("init", &mib, &cnt) != -1) {
+                               (void)memset(&node, 0, sizeof(node));
+                               node.sysctl_flags = SYSCTL_VERSION;
+                               node.sysctl_num = mib;
+                               mib = CTL_DESTROY;
+
+                               (void)sysctl(&mib, 1, NULL, NULL, &node,
+                                   sizeof(node));
+                       }
+
+                       (void)createsysctlnode();
+               }
+
+               /* We certainly won't chroot. */
+               return 0;
+       }
+
+       if (rootdir[len] != '\0' || strlen(rootdir) != len - 1) {
+               warning("init.root is not a string");
+               return 0;
+       }
+
+       if (strcmp(rootdir, "/") == 0)
+               return 0;
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+#endif /* !LETS_GET_SMALL && CHROOT */
diff --git a/sbin/init/pathnames.h b/sbin/init/pathnames.h
new file mode 100644 (file)
index 0000000..222e350
--- /dev/null
@@ -0,0 +1,40 @@
+/*     $NetBSD: pathnames.h,v 1.6 2003/08/07 10:04:25 agc Exp $        */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Donn Seeley at Berkeley Software Design, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <paths.h>
+
+#define        _PATH_SLOGGER   "/sbin/session_logger"
+#define        _PATH_RUNCOM    "/etc/rc"
diff --git a/sbin/reboot/Makefile b/sbin/reboot/Makefile
new file mode 100644 (file)
index 0000000..d461044
--- /dev/null
@@ -0,0 +1,14 @@
+#      $NetBSD: Makefile,v 1.18 2002/08/02 15:05:57 wiz Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/5/93
+
+PROG=  reboot
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+CPPFLAGS+=     -DSUPPORT_UTMP -DSUPPORT_UTMPX
+MAN=   reboot.8
+MLINKS=        reboot.8 halt.8 \
+       reboot.8 poweroff.8
+LINKS= ${BINDIR}/reboot ${BINDIR}/halt \
+       ${BINDIR}/reboot ${BINDIR}/poweroff
+
+.include <bsd.prog.mk>
diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8
new file mode 100644 (file)
index 0000000..c4db956
--- /dev/null
@@ -0,0 +1,168 @@
+.\"    $NetBSD: reboot.8,v 1.29 2011/02/16 19:32:26 wiz Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)reboot.8    8.1 (Berkeley) 6/9/93
+.\"
+.Dd February 16, 2011
+.Dt REBOOT 8
+.Os
+.Sh NAME
+.Nm reboot ,
+.Nm poweroff ,
+.Nm halt
+.Nd restarting, powering down and stopping the system
+.Sh SYNOPSIS
+.Nm halt
+.Op Fl dlnpqvxz
+.Nm poweroff
+.Op Fl dlnqvxz
+.Nm
+.Op Fl dlnqvxz
+.Op Ar arg ...
+.Sh DESCRIPTION
+The
+.Nm poweroff ,
+.Nm halt
+and
+.Nm
+utilities flush the file system cache to disk, send all running processes
+a
+.Dv SIGTERM ,
+wait for up to 30 seconds for them to die, send a
+.Dv SIGKILL
+to the survivors and, respectively, power down, halt or restart the system.
+The action is logged, including entering a shutdown record into the login
+accounting file and sending a message via
+.Xr syslog 3 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d
+Create a dump before halting or restarting.
+This option is useful for debugging system dump procedures or
+capturing the state of a corrupted or misbehaving system.
+.It Fl l
+Suppress sending a message via
+.Xr syslog 3
+before halting or restarting.
+.It Fl n
+Do not flush the file system cache.
+This option should be used with extreme caution.
+It can be used if a disk or a processor is on fire.
+.It Fl p
+Attempt to powerdown the system.
+If the powerdown fails, or the system does not support
+software powerdown, the system will halt.
+This option is only valid for
+.Nm halt .
+.It Fl v
+To enable verbose messages on the console, pass the
+.Xr boothowto 9
+flag
+.Dv AB_VERBOSE
+to
+.Xr reboot 2 .
+.It Fl x
+To enable debugging messages on the console, pass the
+.Xr boothowto 9
+flag
+.Dv AB_DEBUG
+to
+.Xr reboot 2 .
+.It Fl z
+To silence some shutdown messages on the console, pass the
+.Xr boothowto 9
+flag
+.Dv AB_SILENT
+to
+.Xr reboot 2 .
+.It Fl q
+Do not give processes a chance to shut down before halting or restarting.
+This option should not normally be used.
+.El
+.Pp
+If there are any arguments passed to
+.Nm reboot
+they are concatenated with spaces and passed as
+.Fa bootstr
+to the
+.Xr reboot 2
+system call.
+The string is passed to the firmware on platforms that support it.
+.Pp
+Normally, the
+.Xr shutdown 8
+utility is used when the system needs to be halted or restarted, giving
+users advance warning of their impending doom.
+.Sh SEE ALSO
+.Xr reboot 2 ,
+.Xr syslog 3 ,
+.Xr utmp 5 ,
+.Xr boot 8 ,
+.Xr init 8 ,
+.Xr rescue 8 ,
+.Xr shutdown 8 ,
+.Xr sync 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
+.Pp
+The
+.Nm poweroff
+command first appeared in
+.Nx 1.5 .
+.Sh CAVEATS
+Once the command has begun its work, stopping it before it completes
+will probably result in a system so crippled it must be
+physically reset.
+To prevent premature termination, the command
+blocks many signals early in its execution.
+However, nothing can defend against deliberate attempts to evade this.
+.Pp
+This command will stop the system without running any
+.Xr shutdown 8
+scripts.
+Amongst other things, this means that swapping will not be
+disabled so that
+.Xr raid 4
+can shutdown cleanly.
+You should normally use
+.Xr shutdown 8
+unless you are running in single user mode.
+.Sh BUGS
+The single user shell will ignore the
+.Dv SIGTERM
+signal.
+To avoid waiting for the timeout when
+rebooting or halting from the single user shell, you have to
+.Ic exec reboot
+or
+.Ic exec halt .
diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c
new file mode 100644 (file)
index 0000000..30a4fc1
--- /dev/null
@@ -0,0 +1,264 @@
+/*     $NetBSD: reboot.c,v 1.39 2011/08/27 18:46:19 joerg Exp $        */
+
+/*
+ * Copyright (c) 1980, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)reboot.c   8.1 (Berkeley) 6/5/93";
+#else
+__RCSID("$NetBSD: reboot.c,v 1.39 2011/08/27 18:46:19 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/reboot.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <util.h>
+
+__dead static void usage(void);
+
+static int dohalt;
+static int dopoweroff;
+
+int
+main(int argc, char *argv[])
+{
+       const char *progname;
+       /* int i; */
+       struct passwd *pw;
+       int ch, howto, lflag, nflag, qflag, sverrno, len;
+       const char *user;
+       char *bootstr, **av;
+
+       progname = getprogname();
+       if (progname[0] == '-')
+               progname++;
+       if (strcmp(progname, "halt") == 0) {
+               dohalt = 1;
+               howto = RB_HALT;
+       } else if (strcmp(progname, "poweroff") == 0) {
+               dopoweroff = 1;
+               howto = RB_HALT | RB_POWERDOWN;
+       } else
+               howto = 0;
+       lflag = nflag = qflag = 0;
+       while ((ch = getopt(argc, argv, "dlnpqvxz")) != -1)
+               switch(ch) {
+               case 'd':
+                       howto |= RB_DUMP;
+                       break;
+               case 'l':
+                       lflag = 1;
+                       break;
+               case 'n':
+                       nflag = 1;
+                       howto |= RB_NOSYNC;
+                       break;
+               case 'p':
+                       if (dohalt == 0)
+                               usage();
+                       howto |= RB_POWERDOWN;
+                       break;
+               case 'q':
+                       qflag = 1;
+                       break;
+               case 'v':
+                       howto |= AB_VERBOSE;
+                       break;
+               case 'x':
+                       howto |= AB_DEBUG;
+                       break;
+               case 'z':
+                       howto |= AB_SILENT;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (argc) {
+               for (av = argv, len = 0; *av; av++)
+                       len += strlen(*av) + 1;
+               bootstr = malloc(len + 1);
+               *bootstr = '\0';                /* for first strcat */
+               for (av = argv; *av; av++) {
+                       strcat(bootstr, *av);
+                       strcat(bootstr, " ");
+               }
+               bootstr[len - 1] = '\0';        /* to kill last space */
+               howto |= RB_STRING;
+       } else
+               bootstr = NULL;
+
+       if (geteuid())
+               errx(1, "%s", strerror(EPERM));
+
+       if (qflag) {
+               reboot(howto, bootstr);
+               err(1, "reboot");
+       }
+
+       /* Log the reboot. */
+       if (!lflag)  {
+               if ((user = getlogin()) == NULL)
+                       user = (pw = getpwuid(getuid())) ?
+                           pw->pw_name : "???";
+               if (dohalt) {
+                       openlog("halt", LOG_CONS, LOG_AUTH);
+                       syslog(LOG_CRIT, "halted by %s", user);
+               } else if (dopoweroff) {
+                       openlog("poweroff", LOG_CONS, LOG_AUTH);
+                       syslog(LOG_CRIT, "powered off by %s", user);
+               } else {
+                       openlog("reboot", LOG_CONS, LOG_AUTH);
+                       if (bootstr)
+                               syslog(LOG_CRIT, "rebooted by %s: %s", user,
+                                   bootstr);
+                       else
+                               syslog(LOG_CRIT, "rebooted by %s", user);
+               }
+       }
+#ifdef SUPPORT_UTMP
+       logwtmp("~", "shutdown", "");
+#endif
+#ifdef SUPPORT_UTMPX
+       logwtmpx("~", "shutdown", "", INIT_PROCESS, 0);
+#endif
+
+       /*
+        * Do a sync early on, so disks start transfers while we're off
+        * killing processes.  Don't worry about writes done before the
+        * processes die, the reboot system call syncs the disks.
+        */
+       if (!nflag)
+               sync();
+
+       /* 
+        * Ignore signals that we can get as a result of killing
+        * parents, group leaders, etc.
+        */
+       (void)signal(SIGHUP,  SIG_IGN);
+       (void)signal(SIGINT,  SIG_IGN);
+       (void)signal(SIGQUIT, SIG_IGN);
+       (void)signal(SIGTERM, SIG_IGN);
+       (void)signal(SIGTSTP, SIG_IGN);
+
+       /*
+        * If we're running in a pipeline, we don't want to die
+        * after killing whatever we're writing to.
+        */
+       (void)signal(SIGPIPE, SIG_IGN);
+
+
+       /* Just stop init -- if we fail, we'll restart it. */
+#if 0 && defined(__minix)
+       if (kill(1, SIGTERM) == -1)
+               err(1, "SIGTERM init");
+#else
+       if (kill(1, SIGTSTP) == -1)
+               err(1, "SIGTSTP init");
+#endif
+
+       /* Send a SIGTERM first, a chance to save the buffers. */
+       if (kill(-1, SIGTERM) == -1) {
+               /*
+                * If ESRCH, everything's OK: we're the only non-system
+                * process!  That can happen e.g. via 'exec reboot' in
+                * single-user mode.
+                */
+               if (errno != ESRCH) {
+                       warn("SIGTERM all processes");
+                       goto restart;
+               }
+       }
+
+       /*
+        * After the processes receive the signal, start the rest of the
+        * buffers on their way.  Wait 5 seconds between the SIGTERM and
+        * the SIGKILL to pretend to give everybody a chance.
+        */
+       sleep(2);
+       if (!nflag)
+               sync();
+       sleep(3);
+
+#ifndef __minix
+       for (i = 1;; ++i) {
+               if (kill(-1, SIGKILL) == -1) {
+                       if (errno == ESRCH)
+                               break;
+                       warn("SIGKILL all processes");
+                       goto restart;
+               }
+               if (i > 5) {
+                       warnx("WARNING: some process(es) wouldn't die");
+                       break;
+               }
+               (void)sleep(2 * i);
+       }
+#endif
+
+       reboot(howto, bootstr);
+       warn("reboot()");
+       /* FALLTHROUGH */
+
+restart:
+       sverrno = errno;
+       errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
+           strerror(sverrno));
+       /* NOTREACHED */
+}
+
+static void
+usage(void)
+{
+       const char *pflag = dohalt ? "p" : "";
+
+       (void)fprintf(stderr, "usage: %s [-dln%sqvxz] [-- <boot string>]\n",
+           getprogname(), pflag);
+       exit(1);
+}
diff --git a/sbin/shutdown/Makefile b/sbin/shutdown/Makefile
new file mode 100644 (file)
index 0000000..f6b50fc
--- /dev/null
@@ -0,0 +1,15 @@
+#      $NetBSD: Makefile,v 1.11 2009/04/11 07:58:13 lukem Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/5/93
+
+USE_FORT?=yes  # setuid
+PROG=  shutdown
+MAN=   shutdown.8
+BINOWN=        root
+BINGRP=        operator
+BINMODE=4554
+
+.if defined(__MINIX)
+WARNS=2
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sbin/shutdown/pathnames.h b/sbin/shutdown/pathnames.h
new file mode 100644 (file)
index 0000000..42a33bd
--- /dev/null
@@ -0,0 +1,45 @@
+/*     $NetBSD: pathnames.h,v 1.9 2004/08/19 22:30:10 christos Exp $   */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <paths.h>
+
+#define        _PATH_FASTBOOT  "/fastboot"
+#ifdef RESCUEDIR
+#define        _PATH_HALT      RESCUEDIR "/halt"
+#define        _PATH_REBOOT    RESCUEDIR "/reboot"
+#else
+#define        _PATH_HALT      "/sbin/halt"
+#define        _PATH_REBOOT    "/sbin/reboot"
+#endif
+#define        _PATH_WALL      "/usr/bin/wall"
+#define _PATH_RCSHUTDOWN       "/etc/rc.shutdown"
diff --git a/sbin/shutdown/shutdown.8 b/sbin/shutdown/shutdown.8
new file mode 100644 (file)
index 0000000..8f3b7d5
--- /dev/null
@@ -0,0 +1,243 @@
+.\"    $NetBSD: shutdown.8,v 1.31 2011/10/04 07:25:34 dholland Exp $
+.\"
+.\" Copyright (c) 1988, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)shutdown.8 8.2 (Berkeley) 4/27/95
+.\"
+.Dd October 4, 2011
+.Dt SHUTDOWN 8
+.Os
+.Sh NAME
+.Nm shutdown
+.Nd close down the system at a given time
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ddfhknprvxz
+.Op Fl b Ar bootstr
+.Ar time
+.Op Ar message ... | Ar -
+.Sh DESCRIPTION
+.Nm
+provides an automated shutdown procedure for super-users
+to nicely notify users when the system is shutting down,
+saving them from system administrators, hackers, and gurus, who
+would otherwise not bother with such niceties.
+.Pp
+Available friendlinesses:
+.Bl -tag -width bootstr
+.It Fl b Ar bootstr
+The given
+.Ar bootstr
+is passed to
+.Xr reboot 8
+for the benefit of those systems that can pass boot arguments to the
+firmware.
+Currently, this only affects sun3 and sparc machines.
+.It Fl d
+.Nm
+will pass the
+.Fl d
+flag to
+.Xr reboot 8
+or
+.Xr halt 8
+to request a kernel core dump.
+If neither the
+.Fl h
+or
+.Fl r
+flags are specified, then
+.Fl d
+also implies
+.Fl r .
+.It Fl f
+.Nm
+arranges, in the manner of
+.Xr fastboot 8 ,
+for the file systems
+.Em not to be
+checked on reboot.
+.It Fl h
+The system is halted at the specified
+.Ar time ,
+using
+.Xr halt 8 .
+.It Fl k
+Kick everybody off.
+The
+.Fl k
+option
+does not actually halt the system, but leaves the
+system multi-user with logins disabled (for all but super-user).
+.It Fl n
+Prevent the normal
+.Xr sync 2
+before stopping.
+.It Fl p
+The system is powered down at the specified
+.Ar time ,
+using
+.Xr poweroff 8 .
+If the powerdown fails, or the system does not support software powerdown,
+the system will simply halt instead.
+.It Fl r
+The system is rebooted at the specified
+.Ar time ,
+using
+.Xr reboot 8 .
+.It Fl v
+To enable verbose messages on the console, pass
+.Fl v
+to
+.Xr reboot 8
+or
+.Xr halt 8 .
+.It Fl x
+To enable debugging messages on the console, pass
+.Fl x
+to
+.Xr reboot 8
+or
+.Xr halt 8 .
+.It Fl z
+To silence some shutdown messages on the console, pass
+.Fl z
+to
+.Xr reboot 8
+or
+.Xr halt 8 .
+.It Fl D
+Prevents
+.Nm
+from detaching from the tty with
+.Xr fork 2 Ns /
+.Xr exit 3 .
+.It Ar time
+.Ar Time
+is the time at which
+.Nm
+will bring the system down and
+may be the word
+.Ar now
+or a future time in one of two formats:
+.Ar +number ,
+or
+.Ar [[[[[cc]yy]mm]dd]hh]mm ,
+where the century, year, month, day, and hour may be defaulted
+to the current system values.
+The first form brings the system down
+.Ar number
+minutes from the current time; the second brings the system down at the
+absolute time specified.
+If the century is not specified, it defaults to 1900 for years between 69
+and 99, or 2000 for years between 0 and 68.
+A leading zero in the
+.Dq yy
+value is
+.Em not
+optional.
+.It Ar message ...
+Any other arguments comprise the warning message that is broadcast
+to users currently logged into the system.
+.It Ar -
+If
+.Ar -
+is supplied as the only argument after the time, the warning message is read
+from the standard input.
+.El
+.Sh BEHAVIOR
+.Pp
+At intervals, becoming more frequent as apocalypse approaches
+and starting at ten hours before shutdown, warning messages are displayed
+on the terminals of all users logged in.
+Five minutes before shutdown, or immediately if shutdown is in less
+than 5 minutes, logins are disabled by creating
+.Pa /etc/nologin
+and copying the warning message there.
+If this file exists when a user attempts to log in,
+.Xr login 1
+prints its contents and exits.
+The file is removed just before
+.Nm
+exits.
+.Pp
+At shutdown time, a message is written in the system log containing the
+time of shutdown, who initiated the shutdown, and the reason.
+Next a message is printed announcing the start of the system shutdown hooks.
+Then the shutdown hooks in
+.Pa /etc/rc.shutdown
+are run, and a message is printed indicating that they have completed.
+After a short delay,
+.Nm
+runs
+.Xr halt 8
+or
+.Xr reboot 8 ,
+or sends a terminate
+signal to
+.Xr init 8
+to bring the system down to single-user mode, depending on the choice
+of options.
+.Pp
+The time of the shutdown and the warning message are placed in
+.Pa /etc/nologin
+and should be used to tell the users why the system is
+going down, when it will be back up, and to share any other pertinent
+information.
+.Sh FILES
+.Bl -tag -width /etc/rc.shutdown -compact
+.It Pa /etc/nologin
+tells
+.Xr login 1
+not to let anyone log in
+.It Pa /fastboot
+tells
+.Xr rc 8
+not to run
+.Xr fsck 8
+when rebooting
+.It Pa /etc/rc.shutdown
+System shutdown commands
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr wall 1 ,
+.Xr fastboot 8 ,
+.Xr halt 8 ,
+.Xr init 8 ,
+.Xr poweroff 8 ,
+.Xr reboot 8 ,
+.Xr rescue 8
+.Sh BACKWARD COMPATIBILITY
+The hours and minutes in the second time format may be separated by
+a colon (``:'') for backward compatibility.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/sbin/shutdown/shutdown.c b/sbin/shutdown/shutdown.c
new file mode 100644 (file)
index 0000000..bd9d026
--- /dev/null
@@ -0,0 +1,592 @@
+/*     $NetBSD: shutdown.c,v 1.55 2011/08/27 18:54:39 joerg Exp $      */
+
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: shutdown.c,v 1.55 2011/08/27 18:54:39 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syslog.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "pathnames.h"
+
+#ifdef DEBUG
+#undef _PATH_NOLOGIN
+#define        _PATH_NOLOGIN   "./nologin"
+#undef _PATH_FASTBOOT
+#define        _PATH_FASTBOOT  "./fastboot"
+#endif
+
+#define        H               *60*60
+#define        M               *60
+#define        S               *1
+#define        NOLOG_TIME      5*60
+static const struct interval {
+       time_t timeleft, timetowait;
+} tlist[] = {
+       { 10 H,  5 H }, {  5 H,  3 H }, {  2 H,  1 H }, { 1 H, 30 M },
+       { 30 M, 10 M }, { 20 M, 10 M }, { 10 M,  5 M }, { 5 M,  3 M },
+       {  2 M,  1 M }, {  1 M, 30 S }, { 30 S, 30 S },
+       {  0, 0 }
+};
+#undef H
+#undef M
+#undef S
+
+static time_t offset, shuttime;
+static int dofast, dohalt, doreboot, killflg, nofork, nosync, dodump;
+static size_t mbuflen;
+static int dopowerdown;
+static int dodebug, dosilent, doverbose;
+static const char *whom;
+static char mbuf[BUFSIZ];
+static char *bootstr;
+
+static void badtime(void) __dead;
+static void die_you_gravy_sucking_pig_dog(void) __dead;
+static void doitfast(void);
+static void dorcshutdown(void);
+static void finish(int) __dead;
+static void getoffset(char *);
+static void loop(void) __dead;
+static void nolog(void);
+static void timeout(int) __dead;
+static void timewarn(time_t);
+static void usage(void) __dead;
+
+int
+main(int argc, char *argv[])
+{
+       char *p, *endp;
+       struct passwd *pw;
+       size_t arglen, len;
+       int ch;
+
+       (void)setprogname(argv[0]);
+#ifndef DEBUG
+       if (geteuid())
+               errx(1, "%s: Not super-user", strerror(EPERM));
+#endif
+       while ((ch = getopt(argc, argv, "b:Ddfhknprvxz")) != -1)
+               switch (ch) {
+               case 'b':
+                       bootstr = optarg;
+                       break;
+               case 'd':
+                       dodump = 1;
+                       break;
+               case 'D':
+                       nofork = 1;
+                       break;
+               case 'f':
+                       dofast = 1;
+                       break;
+               case 'p':
+                       dopowerdown = 1;
+                       /* FALLTHROUGH */
+               case 'h':
+                       dohalt = 1;
+                       break;
+               case 'k':
+                       killflg = 1;
+                       break;
+               case 'n':
+                       nosync = 1;
+                       break;
+               case 'r':
+                       doreboot = 1;
+                       break;
+               case 'v':
+                       doverbose = 1;
+                       break;
+               case 'x':
+                       dodebug = 1;
+                       break;
+               case 'z':
+                       dosilent = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1)
+               usage();
+
+       if (dodump && !dohalt && !doreboot)
+               doreboot = 1;
+
+       if (dofast && nosync) {
+               warnx("Incompatible options -f and -n");
+               usage();
+       }
+       if (dohalt && doreboot) {
+               const char *which_flag = dopowerdown ? "p" : "h";
+
+               warnx("Incompatible options -%s and -r", which_flag);
+               usage();
+       }
+
+       getoffset(*argv++);
+
+       if (argv[0]) {
+               if (strcmp(argv[0], "-") || argv[1]) {
+                       for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
+                               arglen = strlen(*argv);
+                               if ((len -= arglen) <= 2)
+                                       break;
+                               if (p != mbuf)
+                                       *p++ = ' ';
+                               (void)memmove(p, *argv, arglen);
+                               p += arglen;
+                       }
+                       *p = '\n';
+                       *++p = '\0';
+               } else {
+                       p = mbuf;
+                       endp = mbuf + sizeof(mbuf) - 2;
+                       for (;;) {
+                               if (!fgets(p, endp - p + 1, stdin))
+                                       break;
+                               for (; *p &&  p < endp; ++p);
+                               if (p == endp) {
+                                       *p = '\n';
+                                       *++p = '\0';
+                                       break;
+                               }
+                       }
+               }
+       }
+       mbuflen = strlen(mbuf);
+
+       if (offset)
+               (void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
+       else
+               (void)printf("Shutdown NOW!\n");
+
+       if (!(whom = getlogin()))
+               whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+
+#ifdef DEBUG
+       (void)putc('\n', stdout);
+#else
+       (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
+       if (nofork == 0) {
+               int forkpid;
+
+               forkpid = fork();
+               if (forkpid == -1) {
+                       perror("shutdown: fork");
+                       exit(1);
+               }
+               if (forkpid) {
+                       (void)printf("shutdown: [pid %d]\n", forkpid);
+                       exit(0);
+               }
+               (void)setsid();
+       }
+#endif
+       openlog("shutdown", LOG_CONS, LOG_AUTH);
+       loop();
+       /* NOTREACHED */
+#ifdef __GNUC__
+       return 1;
+#endif
+}
+
+static void
+loop(void)
+{
+       const struct interval *tp;
+       u_int sltime;
+       int logged;
+
+       if (offset <= NOLOG_TIME) {
+               logged = 1;
+               nolog();
+       }
+       else
+               logged = 0;
+       tp = tlist;
+       if (tp->timeleft < offset)
+               (void)sleep((u_int)(offset - tp->timeleft));
+       else {
+               while (offset < tp->timeleft)
+                       ++tp;
+               /*
+                * Warn now, if going to sleep more than a fifth of
+                * the next wait time.
+                */
+               if ((sltime = offset - tp->timeleft) != 0) {
+                       if (sltime > tp->timetowait / 5)
+                               timewarn(offset);
+                       (void)sleep(sltime);
+               }
+       }
+       for (;; ++tp) {
+               timewarn(tp->timeleft);
+               if (!logged && tp->timeleft <= NOLOG_TIME) {
+                       logged = 1;
+                       nolog();
+               }
+               (void)sleep((u_int)tp->timetowait);
+               if (!tp->timeleft)
+                       break;
+       }
+       die_you_gravy_sucking_pig_dog();
+}
+
+static jmp_buf alarmbuf;
+
+static void
+timewarn(time_t timeleft)
+{
+       static int first;
+       static char hostname[MAXHOSTNAMELEN + 1];
+       FILE *pf;
+       char wcmd[MAXPATHLEN + 4];
+
+       if (!first++) {
+               (void)gethostname(hostname, sizeof(hostname));
+               hostname[sizeof(hostname) - 1] = '\0';
+       }
+
+       /* undoc -n option to wall suppresses normal wall banner */
+       (void)snprintf(wcmd, sizeof wcmd, "%s -n", _PATH_WALL);
+       if ((pf = popen(wcmd, "w")) == NULL) {
+               syslog(LOG_ERR, "%s: Can't find `%s' (%m)", getprogname(),
+                   _PATH_WALL);
+               return;
+       }
+
+       (void)fprintf(pf,
+           "\007*** %sSystem shutdown message from %s@%s ***\007\n",
+           timeleft ? "": "FINAL ", whom, hostname);
+
+       if (timeleft > 10*60)
+               (void)fprintf(pf, "System going down at %5.5s\n\n",
+                   ctime(&shuttime) + 11);
+       else if (timeleft > 59)
+               (void)fprintf(pf, "System going down in %ld minute%s\n\n",
+                   (long)timeleft / 60, (timeleft > 60) ? "s" : "");
+       else if (timeleft)
+               (void)fprintf(pf, "System going down in 30 seconds\n\n");
+       else
+               (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
+
+       if (mbuflen)
+               (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
+
+       /*
+        * play some games, just in case wall doesn't come back
+        * probably unnecessary, given that wall is careful.
+        */
+       if (!setjmp(alarmbuf)) {
+               (void)signal(SIGALRM, timeout);
+               (void)alarm((u_int)30);
+               (void)pclose(pf);
+               (void)alarm((u_int)0);
+               (void)signal(SIGALRM, SIG_DFL);
+       }
+}
+
+static void
+/*ARGSUSED*/
+timeout(int signo)
+{
+       longjmp(alarmbuf, 1);
+}
+
+static void
+die_you_gravy_sucking_pig_dog(void)
+{
+       const char *what;
+
+       if (doreboot) {
+               what = "reboot";
+       } else if (dohalt && dopowerdown) {
+               what = "poweroff";
+       } else if (dohalt) {
+               what = "halt";
+       } else {
+               what = "shutdown";
+       }
+
+       syslog(LOG_NOTICE, "%s by %s: %s", what, whom, mbuf);
+       (void)sleep(2);
+
+       (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
+       if (killflg) {
+               (void)printf("\rbut you'll have to do it yourself\r\n");
+               finish(0);
+       }
+       if (dofast)
+               doitfast();
+       dorcshutdown();
+       if (doreboot || dohalt) {
+               const char *args[20];
+               const char **arg, *path;
+#ifndef DEBUG
+               int serrno;
+#endif
+
+               arg = &args[0];
+               if (doreboot) {
+                       path = _PATH_REBOOT;
+                       *arg++ = "reboot";
+               } else {
+                       path = _PATH_HALT;
+                       *arg++ = "halt";
+               }
+               if (doverbose)
+                       *arg++ = "-v";
+               if (dodebug)
+                       *arg++ = "-x";
+               if (dosilent)
+                       *arg++ = "-z";
+               if (dodump)
+                       *arg++ = "-d";
+               if (nosync)
+                       *arg++ = "-n";
+               if (dopowerdown)
+                       *arg++ = "-p";
+               *arg++ = "-l";
+               if (bootstr)
+                       *arg++ = bootstr;
+               *arg++ = 0;
+#ifndef DEBUG
+               (void)unlink(_PATH_NOLOGIN);
+               (void)execve(path, __UNCONST(args), NULL);
+               serrno = errno;
+               syslog(LOG_ERR, "Can't exec `%s' (%m)", path);
+               errno = serrno;
+               warn("Can't exec `%s'", path);
+#else
+               printf("%s", path);
+               for (arg = &args[0]; *arg; arg++)
+                       printf(" %s", *arg);
+               printf("\n");
+#endif
+       } else {
+#ifndef DEBUG
+               (void)kill(1, SIGTERM);         /* to single user */
+#else
+               printf("kill 1\n");
+#endif
+       }
+       finish(0);
+}
+
+#define        ATOI2(s)        ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+
+static void
+getoffset(char *timearg)
+{
+       struct tm *lt;
+       char *p;
+       time_t now;
+       int yearset;
+
+       (void)time(&now);
+       if (!strcasecmp(timearg, "now")) {              /* now */
+               offset = 0;
+               shuttime = now;
+               return;
+       }
+
+       if (*timearg == '+') {                          /* +minutes */
+               if (!isdigit((unsigned char)*++timearg))
+                       badtime();
+               offset = atoi(timearg) * 60;
+               shuttime = now + offset;
+               return;
+       }
+
+       /* handle hh:mm by getting rid of the colon */
+       for (p = timearg; *p; ++p)
+               if (!isascii(*p) || !isdigit((unsigned char)*p)) {
+                       if (*p == ':' && strlen(p) == 3) {
+                               p[0] = p[1];
+                               p[1] = p[2];
+                               p[2] = '\0';
+                       }
+                       else
+                               badtime();
+               }
+
+       (void)unsetenv("TZ");                           /* OUR timezone */
+       lt = localtime(&now);                           /* current time val */
+
+       lt->tm_sec = 0;
+
+       yearset = 0;
+       switch (strlen(timearg)) {
+       case 12:
+               lt->tm_year = ATOI2(timearg) * 100 - TM_YEAR_BASE;
+               yearset = 1;
+               /* FALLTHROUGH */
+       case 10:
+               if (yearset) {
+                       lt->tm_year += ATOI2(timearg);
+               } else {
+                       yearset = ATOI2(timearg);
+                       if (yearset < 69)
+                               lt->tm_year = yearset + 2000 - TM_YEAR_BASE;
+                       else
+                               lt->tm_year = yearset + 1900 - TM_YEAR_BASE;
+               }
+               /* FALLTHROUGH */
+       case 8:
+               lt->tm_mon = ATOI2(timearg);
+               --lt->tm_mon;
+               /* FALLTHROUGH */
+       case 6:
+               lt->tm_mday = ATOI2(timearg);
+               /* FALLTHROUGH */
+       case 4:
+               lt->tm_hour = ATOI2(timearg);
+               /* FALLTHROUGH */
+       case 2:
+               lt->tm_min = ATOI2(timearg);
+               break;
+       default:
+               badtime();
+       }
+
+       if ((shuttime = mktime(lt)) == -1)
+               badtime();
+       if ((offset = shuttime - now) < 0)
+               errx(1, "time is already past");
+}
+
+static void
+dorcshutdown(void)
+{
+       (void)printf("\r\nAbout to run shutdown hooks...\r\n");
+#ifndef DEBUG
+       (void)setuid(0);
+       (void)system(". " _PATH_RCSHUTDOWN);
+#endif
+       (void)sleep(5);         /* Give operator a chance to abort this. */
+       (void)printf("\r\nDone running shutdown hooks.\r\n");
+}
+
+#define        FSMSG   "fastboot file for fsck\n"
+static void
+doitfast(void)
+{
+       int fastfd;
+
+       if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
+           0664)) >= 0) {
+               (void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
+               (void)close(fastfd);
+       }
+}
+
+#define        NOMSG   "\n\nNO LOGINS: System going down at "
+static void
+nolog(void)
+{
+       int logfd;
+       char *ct;
+
+       (void)unlink(_PATH_NOLOGIN);    /* in case linked to another file */
+       (void)signal(SIGINT, finish);
+       (void)signal(SIGHUP, finish);
+       (void)signal(SIGQUIT, finish);
+       (void)signal(SIGTERM, finish);
+       if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
+           0664)) >= 0) {
+               (void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
+               ct = ctime(&shuttime);
+               (void)write(logfd, ct + 11, 5);
+               (void)write(logfd, "\n\n", 2);
+               (void)write(logfd, mbuf, strlen(mbuf));
+               (void)close(logfd);
+       }
+}
+
+static void
+/*ARGSUSED*/
+finish(int signo)
+{
+
+       if (!killflg)
+               (void)unlink(_PATH_NOLOGIN);
+       exit(0);
+}
+
+static void
+badtime(void)
+{
+
+       warnx("illegal time format");
+       usage();
+}
+
+static void
+usage(void)
+{
+
+       (void)fprintf(stderr,
+           "Usage: %s [-Ddfhknprvxz] [-b bootstr] time [message ... | -]\n",
+           getprogname());
+       exit(1);
+}
index b4ce396eabfcc07da56dec3635bbd55aa1107cb0..a756094ed458c3764ac3b650d56142df6de818bb 100644 (file)
@@ -5,11 +5,11 @@
 
 .if ${MKIMAGEONLY} == "yes"
 
-SUBDIR=        ds init input mfs pfs pm rs sched vfs vm
+SUBDIR=        ds input mfs pfs pm rs sched vfs vm
 
 .else
 
-SUBDIR=        ds ext2 inet init input ipc is iso9660fs \
+SUBDIR=        ds ext2 inet input ipc is iso9660fs \
        mfs pfs pm procfs rs sched vfs vm devman
 
 .if ${MACHINE_ARCH} == "i386"
diff --git a/servers/init/Makefile b/servers/init/Makefile
deleted file mode 100644 (file)
index 95d47b3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Makefile for the init program (INIT)
-.include <bsd.own.mk>
-
-PROG=  init
-SRCS=  init.c
-
-MAN=
-
-BINDIR?= /usr/sbin
-
-.include <bsd.prog.mk>
diff --git a/servers/init/init.c b/servers/init/init.c
deleted file mode 100644 (file)
index abfe038..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-/* This process is the father (mother) of all Minix user processes.  When
- * Minix comes up, this is process number 2, and has a pid of 1.  It
- * executes the /etc/rc shell file, and then reads the /etc/ttytab file to
- * determine which terminals need a login process.
- *
- * If the files /usr/adm/wtmp and /etc/utmp exist and are writable, init
- * (with help from login) will maintain login accounting.  Sending a
- * signal 1 (SIGHUP) to init will cause it to rescan /etc/ttytab and start
- * up new shell processes if necessary.  It will not, however, kill off
- * login processes for lines that have been turned off; do this manually.
- * Signal 15 (SIGTERM) makes init stop spawning new processes, this is
- * used by shutdown and friends when they are about to close the system
- * down.
- */
-
-#include <minix/type.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/svrctl.h>
-#include <ttyent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <minix/reboot.h>
-
-/* Different ttyent structure. */
-struct ttyent TT_REBOOT = { "console", "shutdown -d now CTRL-ALT_DEL", "-"};
-
-char PATH_UTMP[] = "/etc/utmp";                /* current logins */
-char PATH_WTMP[] = "/usr/adm/wtmp";    /* login/logout history */
-char PATH_ROOT_WTMP[] = "/etc/wtmp";   /* wtmp for system up/down events */
-
-#define PIDSLOTS       32              /* first this many ttys can be on */
-
-struct slotent {
-  int errct;                   /* error count */
-  pid_t pid;                   /* pid of login process for this tty line */
-};
-
-#define ERRCT_DISABLE  10      /* disable after this many errors */
-#define NO_PID 0               /* pid value indicating no process */
-
-struct slotent slots[PIDSLOTS];        /* init table of ttys and pids */
-
-int gothup = 0;                        /* flag, showing signal 1 was received */
-int gotabrt = 0;               /* flag, showing signal 6 was received */
-int spawn = 1;                 /* flag, spawn processes only when set */
-
-void tell(int fd, char *s);
-void report(int fd, char *label);
-void wtmp(int type, int linenr, char *line, pid_t pid);
-void startup(int linenr, struct ttyent *ttyp);
-int execute(char **cmd);
-char **construct_argv(char *cmd);
-void onhup(int sig);
-void onterm(int sig);
-void onabrt(int sig);
-
-int main(void)
-{
-  pid_t pid;                   /* pid of child process */
-  int fd;                      /* generally useful */
-  int linenr;                  /* loop variable */
-  int check;                   /* check if a new process must be spawned */
-  int sn;                      /* signal number */
-  struct slotent *slotp;       /* slots[] pointer */
-  struct ttyent *ttyp;         /* ttytab entry */
-  struct sigaction sa;
-  struct stat stb;
-
-#define OPENFDS                                                \
-  if (fstat(0, &stb) < 0) {                            \
-       /* Open standard input, output & error. */      \
-       (void) open("/dev/null", O_RDONLY);             \
-       (void) open("/dev/log", O_WRONLY);              \
-       dup(1);                                         \
-  }
-
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-
-  /* Default: Ignore every signal (except those that follow). */
-  sa.sa_handler = SIG_IGN;
-  for (sn = 1; sn < _NSIG; sn++) {
-      sigaction(sn, &sa, NULL);
-  }
-
-  /* Hangup: Reexamine /etc/ttytab for newly enabled terminal lines. */
-  sa.sa_handler = onhup;
-  sigaction(SIGHUP, &sa, NULL);
-
-  /* Terminate: Stop spawning login processes, shutdown is near. */
-  sa.sa_handler = onterm;
-  sigaction(SIGTERM, &sa, NULL);
-
-  /* Abort: Sent by the kernel on CTRL-ALT-DEL; shut the system down. */
-  sa.sa_handler = onabrt;
-  sigaction(SIGABRT, &sa, NULL);
-
-  /* Execute the /etc/rc file. */
-  if ((pid = fork()) != 0) {
-       /* Parent just waits. */
-       while (wait(NULL) != pid) {
-               if (gotabrt) reboot(RBT_HALT);
-       }
-  } else {
-#if ! SYS_GETKENV
-       struct sysgetenv sysgetenv;
-#endif
-       char bootopts[16];
-       static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL, NULL };
-       char **rcp = rc_command + 2;
-
-       /* Get the boot options from the boot environment. */
-       sysgetenv.key = "bootopts";
-       sysgetenv.keylen = 8+1;
-       sysgetenv.val = bootopts;
-       sysgetenv.vallen = sizeof(bootopts);
-       if (svrctl(PMGETPARAM, &sysgetenv) == 0) *rcp++ = bootopts;
-       *rcp = "start";
-
-       execute(rc_command);
-       report(2, "sh /etc/rc");
-       _exit(1);       /* impossible, we hope */
-  }
-
-  OPENFDS;
-
-  /* Clear /etc/utmp if it exists. */
-  if ((fd = open(PATH_UTMP, O_WRONLY | O_TRUNC)) >= 0) close(fd);
-
-  /* Log system reboot. */
-  wtmp(BOOT_TIME, 0, NULL, 0);
-
-  /* Main loop. If login processes have already been started up, wait for one
-   * to terminate, or for a HUP signal to arrive. Start up new login processes
-   * for all ttys which don't have them. Note that wait() also returns when
-   * somebody's orphan dies, in which case ignore it.  If the TERM signal is
-   * sent then stop spawning processes, shutdown time is near.
-   */
-
-  check = 1;
-  while (1) {
-       while ((pid = waitpid(-1, NULL, check ? WNOHANG : 0)) > 0) {
-               /* Search to see which line terminated. */
-               for (linenr = 0; linenr < PIDSLOTS; linenr++) {
-                       slotp = &slots[linenr];
-                       if (slotp->pid == pid) {
-                               /* Record process exiting. */
-                               wtmp(DEAD_PROCESS, linenr, NULL, pid);
-                               slotp->pid = NO_PID;
-                               check = 1;
-                       }
-               }
-       }
-
-       /* If a signal 1 (SIGHUP) is received, simply reset error counts. */
-       if (gothup) {
-               gothup = 0;
-               for (linenr = 0; linenr < PIDSLOTS; linenr++) {
-                       slots[linenr].errct = 0;
-               }
-               check = 1;
-       }
-
-       /* Shut down on signal 6 (SIGABRT). */
-       if (gotabrt) {
-               gotabrt = 0;
-               startup(0, &TT_REBOOT);
-       }
-
-       if (spawn && check) {
-               /* See which lines need a login process started up. */
-               for (linenr = 0; linenr < PIDSLOTS; linenr++) {
-                       slotp = &slots[linenr];
-                       if ((ttyp = getttyent()) == NULL) break;
-
-                       if (ttyp->ty_getty != NULL
-                               /* ty_getty is a string, and TTY_ON is
-                                * the way to check for enabled ternimanls. */
-                               && (ttyp->ty_status & TTY_ON)
-                               && slotp->pid == NO_PID
-                               && slotp->errct < ERRCT_DISABLE)
-                       {
-                               startup(linenr, ttyp);
-                       }
-               }
-               endttyent();
-       }
-       check = 0;
-  }
-}
-
-void onhup(int sig)
-{
-  gothup = 1;
-  spawn = 1;
-}
-
-void onterm(int sig)
-{
-  spawn = 0;
-}
-
-void onabrt(int sig)
-{
-  static int count = 0;
-
-  if (++count == 2) reboot(RBT_HALT);
-  gotabrt = 1;
-}
-
-void startup(int linenr, struct ttyent *ttyp)
-{
-  /* Fork off a process for the indicated line. */
-
-  struct slotent *slotp;               /* pointer to ttyslot */
-  pid_t pid;                           /* new pid */
-  int err[2];                          /* error reporting pipe */
-  char line[32];                       /* tty device name */
-  char **ty_getty_argv;
-
-  slotp = &slots[linenr];
-
-  /* Error channel for between fork and exec. */
-  if (pipe(err) < 0) err[0] = err[1] = -1;
-
-  if ((pid = fork()) == -1 ) {
-       report(2, "fork()");
-       sleep(10);
-       return;
-  }
-
-  if (pid == 0) {
-       /* Child */
-       close(err[0]);
-       fcntl(err[1], F_SETFD, fcntl(err[1], F_GETFD) | FD_CLOEXEC);
-
-       /* A new session. */
-       setsid();
-
-       /* Construct device name. */
-       strcpy(line, "/dev/");
-       strncat(line, ttyp->ty_name, sizeof(line) - 6);
-
-       /* Open the line for standard input and output. */
-       close(0);
-       close(1);
-       if (open(line, O_RDWR) < 0 || dup(0) < 0) {
-               write(err[1], &errno, sizeof(errno));
-               _exit(1);
-       }
-
-       /* Redirect standard error too. */
-       dup2(0, 2);
-
-       /* Construct argv for execute() */
-       ty_getty_argv = construct_argv(ttyp->ty_getty);
-       if (ty_getty_argv == NULL) {
-               report(2, "construct_argv");
-       } else {
-               /* Execute the getty process. */
-               execute(ty_getty_argv);
-       }
-
-       /* Oops, disaster strikes. */
-       fcntl(2, F_SETFL, fcntl(2, F_GETFL) | O_NONBLOCK);
-       if (linenr != 0 && ty_getty_argv) report(2, ty_getty_argv[0]);
-       write(err[1], &errno, sizeof(errno));
-       _exit(1);
-  }
-
-  /* Parent */
-  if (ttyp != &TT_REBOOT) slotp->pid = pid;
-
-  close(err[1]);
-  if (read(err[0], &errno, sizeof(errno)) != 0) {
-       /* If an errno value goes down the error pipe: Problems. */
-
-       switch (errno) {
-       case ENOENT:
-       case ENODEV:
-       case ENXIO:
-               /* Device nonexistent, no driver, or no minor device. */
-               slotp->errct = ERRCT_DISABLE;
-               close(err[0]);
-               return;
-       case 0:
-               /* Error already reported. */
-               break;
-       default:
-               /* Any other error on the line. */
-               report(2, ttyp->ty_name);
-       }
-       close(err[0]);
-
-       if (++slotp->errct >= ERRCT_DISABLE) {
-               tell(2, "init: ");
-               tell(2, ttyp->ty_name);
-               tell(2, ": excessive errors, shutting down\n");
-       } else {
-               sleep(5);
-       }
-       return;
-  }
-  close(err[0]);
-
-  if (ttyp != &TT_REBOOT) wtmp(LOGIN_PROCESS, linenr, ttyp->ty_name, pid);
-  slotp->errct = 0;
-}
-
-int execute(char **cmd)
-{
-  /* Execute a command with a path search along /sbin:/bin:/usr/sbin:/usr/bin.
-   */
-  static char *nullenv[] = { NULL };
-  char command[128];
-  char *path[] = { "/sbin", "/bin", "/usr/sbin", "/usr/bin" };
-  int i;
-
-  if (cmd[0][0] == '/') {
-       /* A full path. */
-       return execve(cmd[0], cmd, nullenv);
-  }
-
-  /* Path search. */
-  for (i = 0; i < 4; i++) {
-       if (strlen(path[i]) + 1 + strlen(cmd[0]) + 1 > sizeof(command)) {
-               errno= ENAMETOOLONG;
-               return -1;
-       }
-       strcpy(command, path[i]);
-       strcat(command, "/");
-       strcat(command, cmd[0]);
-       execve(command, cmd, nullenv);
-       if (errno != ENOENT) break;
-  }
-  return -1;
-}
-
-void wtmp(type, linenr, line, pid)
-int type;                      /* type of entry */
-int linenr;                    /* line number in ttytab */
-char *line;                    /* tty name (only good on login) */
-pid_t pid;                     /* pid of process */
-{
-/* Log an event into the UTMP and WTMP files. */
-
-  struct utmp utmp;            /* UTMP/WTMP User Accounting */
-  int fd;
-
-  /* Clear the utmp record. */
-  memset((void *) &utmp, 0, sizeof(utmp));
-
-  /* Fill in utmp. */
-  switch (type) {
-  case BOOT_TIME:
-       /* Make a special reboot record. */
-       strcpy(utmp.ut_name, "reboot");
-       strcpy(utmp.ut_line, "~");
-       break;
-
-  case LOGIN_PROCESS:
-       /* A new login, fill in line name. */
-       strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
-       break;
-
-  case DEAD_PROCESS:
-       /* A logout.  Use the current utmp entry, but make sure it is a
-        * user process exiting, and not getty or login giving up.
-        */
-       if ((fd = open(PATH_UTMP, O_RDONLY)) < 0) {
-               if (errno != ENOENT) report(2, PATH_UTMP);
-               return;
-       }
-       if (lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
-               || read(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               report(2, PATH_UTMP);
-               close(fd);
-               return;
-       }
-       close(fd);
-       if (utmp.ut_type != USER_PROCESS) return;
-       strncpy(utmp.ut_name, "", sizeof(utmp.ut_name));
-       break;
-  }
-
-  /* Finish new utmp entry. */
-  utmp.ut_pid = pid;
-  utmp.ut_type = type;
-  utmp.ut_time = time((time_t *) 0);
-
-  switch (type) {
-  case LOGIN_PROCESS:
-  case DEAD_PROCESS:
-       /* Write new entry to utmp. */
-       if ((fd = open(PATH_UTMP, O_WRONLY)) < 0
-               || lseek(fd, (off_t) (linenr+1) * sizeof(utmp), SEEK_SET) == -1
-               || write(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               if (errno != ENOENT) report(2, PATH_UTMP);
-       }
-       if (fd != -1) close(fd);
-       break;
-  }
-
-  switch (type) {
-  case BOOT_TIME:
-       /* Add new root wtmp entry. */
-       if ((fd = open(PATH_ROOT_WTMP, O_WRONLY | O_APPEND)) < 0
-                 || write(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               if (errno != ENOENT) report(2, PATH_ROOT_WTMP);
-       }
-       if (fd != -1) close(fd);
-       /* fall-through */
-  case DEAD_PROCESS:
-       /* Add new wtmp entry. */
-       if ((fd = open(PATH_WTMP, O_WRONLY | O_APPEND)) < 0
-                 || write(fd, &utmp, sizeof(utmp)) == -1
-       ) {
-               if (errno != ENOENT) report(2, PATH_WTMP);
-       }
-       if (fd != -1) close(fd);
-       break;
-  }
-}
-
-char **
-construct_argv(char *cmd)
-{
-       int argc = 0;
-       static const char sep[] = " \t";
-       char **argv = malloc(((strlen(cmd) + 1) / 2 + 1) * sizeof (char *));
-
-       if (argv == NULL)
-               return NULL;
-
-       if ((argv[argc++] = strtok(cmd, sep)) == 0) {
-               free(argv);
-               return NULL;
-       }
-       while ((argv[argc++] = strtok(NULL, sep)) != NULL)
-               continue;
-       return argv;
-}
-
-void tell(fd, s)
-int fd;
-char *s;
-{
-       write(fd, s, strlen(s));
-}
-
-void report(fd, label)
-int fd;
-char *label;
-{
-       int err = errno;
-
-       tell(fd, "init: ");
-       tell(fd, label);
-       tell(fd, ": ");
-       tell(fd, strerror(err));
-       tell(fd, "\n");
-       errno= err;
-}
index cb47f8271f74cd0789d4eac9ff69f618600449d3..c360bdfb3bf9d54db4ab97c7a08f4b38f73b3ef5 100644 (file)
@@ -258,9 +258,13 @@ int read_super(struct super_block *sp)
 
   magic = sp->s_magic;         /* determines file system type */
 
+  if(magic == SUPER_V2 || magic == SUPER_MAGIC) {
+       printf("MFS: only supports V3 filesystems.\n");
+       return EINVAL;
+  }
+
   /* Get file system version and type - only support v3. */
   if(magic != SUPER_V3) {
-       printf("MFS: only supports V3 filesystems.\n");
        return EINVAL;
   }
   version = V3;
index 7676901e4520fd7a013e993b154e1703f40fc840..0e409e018fa427547b5889eed7227f75737a2fae 100644 (file)
 #include <minix/callnr.h>
 #include <signal.h>
 #include <sys/svrctl.h>
+#include <sys/reboot.h>
 #include <sys/resource.h>
 #include <sys/utsname.h>
 #include <minix/com.h>
 #include <minix/config.h>
-#include <minix/reboot.h>
 #include <minix/sysinfo.h>
 #include <minix/type.h>
 #include <minix/ds.h>
@@ -213,10 +213,9 @@ int do_reboot()
 
   /* See how the system should be aborted. */
   abort_flag = (unsigned) m_in.PM_REBOOT_HOW;
-  if (abort_flag >= RBT_INVALID) return(EINVAL); 
 
   /* notify readclock (some arm systems power off via RTC alarms) */
-  if (abort_flag == RBT_POWEROFF) {
+  if (abort_flag & RB_POWERDOWN) {
        endpoint_t readclock_ep;
        if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) {
                message m; /* no params to set, nothing we can do if it fails */
index 20f9b40da307eba419d24d615e141af41bd590cc..9e45d425c4fc368a13695e5cbd7784fe84255f49 100644 (file)
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <assert.h>
 #include <sys/stat.h>
+#include <sys/ioc_tty.h>
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/endpoint.h>
@@ -267,6 +268,13 @@ int cdev_io(
   if ((dp = cdev_get(dev, &minor_dev)) == NULL)
        return(EIO);
 
+  /* Handle TIOCSCTTY ioctl: set controlling tty.
+   * TODO: cleaner implementation work in progress.
+   */
+  if (op == CDEV_IOCTL && bytes == TIOCSCTTY && major(dev) == TTY_MAJOR) {
+       fp->fp_tty = dev;
+  }
+
   /* Create a grant for the buffer provided by the user process. */
   gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes);
 
index 20903c571fb62b391ab0a715999eb0cffcedfaa5..423f170c68ae61408575485e8d481add768a0716 100644 (file)
@@ -14,6 +14,7 @@ SUBDIR= asa \
        fsplit ftp genassym getopt \
        head hexdump id indent infocmp join jot \
        lam ldd leave \
+       last \
        lock login logname lorder m4 \
        machine make man menuc mesg \
        mkdep mkfifo mkstr mktemp \
@@ -30,8 +31,9 @@ SUBDIR= asa \
        toproto \
        uniq units unvis unzip users \
        uuidgen vis \
+       uniq uname units unzip users \
+       wall wc what whatis who whois \
        \
-       wc what who whois \
        write xargs xinstall xstr yes
 
 .if !defined(__MINIX)
diff --git a/usr.bin/last/Makefile b/usr.bin/last/Makefile
new file mode 100644 (file)
index 0000000..25348f6
--- /dev/null
@@ -0,0 +1,10 @@
+#      $NetBSD: Makefile,v 1.7 2004/11/19 21:41:25 christos Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/6/93
+
+PROG=  last
+CPPFLAGS+=-DSUPPORT_UTMPX -DSUPPORT_UTMP
+
+LDADD=-lutil
+DPADD=${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1
new file mode 100644 (file)
index 0000000..80c440a
--- /dev/null
@@ -0,0 +1,161 @@
+.\"    $NetBSD: last.1,v 1.20 2012/05/12 14:52:57 reed Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)last.1     8.1 (Berkeley) 6/6/93
+.\"
+.Dd October 18, 2011
+.Dt LAST 1
+.Os
+.Sh NAME
+.Nm last
+.Nd indicate last logins of users and ttys
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ns Ar n
+.Op Fl nTx
+.Op Fl f Ar file
+.Op Fl H Ar hostsize
+.Op Fl h Ar host
+.Op Fl L Ar linesize
+.Op Fl N Ar namesize
+.Op Fl t Ar tty
+.Op user ...
+.Sh DESCRIPTION
+.Nm
+will list the sessions of specified
+.Ar users ,
+.Ar ttys ,
+and
+.Ar hosts ,
+in reverse time order.
+Each line of output contains
+the user name, the tty from which the session was conducted, any
+hostname, the start and stop times for the session, and the duration
+of the session.
+If the session is still continuing or was cut short by
+a crash or shutdown,
+.Nm
+will so indicate.
+.Pp
+The following options are available:
+.Pp
+.Bl -tag -width xHxhostsizexx
+.It Fl Ar n
+Limits the report to
+.Ar n
+lines.
+.It Fl f Ar file
+.Nm
+reads the file
+.Ar file
+instead of the default,
+.Pa /var/log/wtmpx
+or
+.Pa /var/log/wtmp .
+If the file ends with
+.Sq x ,
+it is treated as a
+.Xr utmpx 5
+format file, else it is treated as a
+.Xr utmp 5
+format file.
+If the file is ``-'', standard input is used.
+.It Fl H Ar hostsize
+Use the provided hostsize as the width to format the host name field.
+.It Fl h Ar host
+.Ar Host
+names may be names or internet numbers.
+.It Fl L Ar linesize
+Use the provided linesize as the width to format the tty field.
+.It Fl N Ar namesize
+Use the provided namesize as the width to format the login name field.
+.It Fl n
+Print host addresses numerically.
+This option works only on
+.Xr wtmpx 5
+entries,
+and prints nothing on
+.Xr wtmp 5
+entries.
+.It Fl T
+Display better time information, including the year and seconds.
+.It Fl t Ar tty
+Specify the
+.Ar tty .
+Tty names may be given fully or abbreviated, for example,
+.Dq Li "last -t 03"
+is equivalent to
+.Dq Li "last -t tty03" .
+.It Fl x
+Assume that the file given is in
+.Xr wtmpx 5
+format, even if the filename does not end with an
+.Sq x .
+Also useful when reading such format from standard input.
+.El
+.Pp
+If multiple arguments are given, the information which applies to any of the
+arguments is printed, e.g.,
+.Dq Li "last root -t console"
+would list all of
+.Dq Li root Ns 's
+sessions as well as all sessions on the console terminal.
+If no users, hostnames, or terminals are specified,
+.Nm
+prints a record of all logins and logouts.
+.Pp
+The pseudo-user
+.Ar reboot
+logs in at reboots of the system, thus
+.Dq Li last reboot
+will give an indication of mean time between reboot.
+.Pp
+If
+.Nm
+is interrupted, it indicates to what date the search has progressed.
+If interrupted with a quit signal
+.Nm
+indicates how far the search has progressed and then continues.
+.Sh FILES
+.Bl -tag -width /var/log/wtmpx -compact
+.It Pa /var/log/wtmp
+login data base
+.It Pa /var/log/wtmpx
+login data base
+.El
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr utmp 5 ,
+.Xr utmpx 5 ,
+.Xr ac 8 ,
+.Xr lastlogin 8
+.Sh HISTORY
+.Nm
+appeared in
+.Bx 1 .
diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c
new file mode 100644 (file)
index 0000000..19cba10
--- /dev/null
@@ -0,0 +1,405 @@
+/*     $NetBSD: last.c,v 1.36 2012/03/15 03:04:05 dholland Exp $       */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)last.c     8.2 (Berkeley) 4/2/94";
+#endif
+__RCSID("$NetBSD: last.c,v 1.36 2012/03/15 03:04:05 dholland Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#include <util.h>
+
+#ifndef UT_NAMESIZE
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#define UT_HOSTSIZE 16
+#endif
+#ifndef SIGNATURE
+#define SIGNATURE -1
+#endif
+
+
+
+#define        NO      0                       /* false/no */
+#define        YES     1                       /* true/yes */
+
+#define        TBUFLEN 30                      /* length of time string buffer */
+#define        TFMT    "%a %b %d %R"           /* strftime format string */
+#define        LTFMT   "%a %b %d %Y %T"        /* strftime long format string */
+#define        TFMTS   "%R"                    /* strftime format string - time only */
+#define        LTFMTS  "%T"                    /* strftime long format string - " */
+
+/* fmttime() flags */
+#define        FULLTIME        0x1             /* show year, seconds */
+#define        TIMEONLY        0x2             /* show time only, not date */
+#define        GMT             0x4             /* show time at GMT, for offsets only */
+
+#define MAXUTMP                1024
+
+typedef struct arg {
+       const char      *name;          /* argument */
+#define        HOST_TYPE       -2
+#define        TTY_TYPE        -3
+#define        USER_TYPE       -4
+       int             type;           /* type of arg */
+       struct arg      *next;          /* linked list pointer */
+} ARG;
+static ARG     *arglist;               /* head of linked list */
+
+typedef struct ttytab {
+       time_t  logout;                 /* log out time */
+       char    tty[128];               /* terminal name */
+       struct ttytab   *next;          /* linked list pointer */
+} TTY;
+static TTY     *ttylist;               /* head of linked list */
+
+static time_t  currentout;             /* current logout value */
+static long    maxrec;                 /* records to display */
+static int     fulltime = 0;           /* Display seconds? */
+static int     xflag;                  /* Assume file is wtmpx format */
+
+static void     addarg(int, const char *);
+static TTY     *addtty(const char *);
+static void     hostconv(char *);
+static const char *ttyconv(char *);
+#ifdef SUPPORT_UTMPX
+static void     wtmpx(const char *, int, int, int, int);
+#endif
+#ifdef SUPPORT_UTMP
+static void     wtmp(const char *, int, int, int, int);
+#endif
+static char    *fmttime(time_t, int);
+__dead static void      usage(void);
+
+static
+void usage(void)
+{
+       (void)fprintf(stderr, "usage: %s [-#%s] [-nTx] [-f file]"
+           " [-H hostsize] [-h host] [-L linesize]\n"
+           "\t    [-N namesize] [-t tty] [user ...]\n", getprogname(),
+#ifdef NOTYET_SUPPORT_UTMPX
+           "w"
+#else
+           ""
+#endif
+       );
+       exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+       int ch;
+       char *p;
+       const char *file = NULL;
+       int namesize = UT_NAMESIZE;
+       int linesize = UT_LINESIZE;
+       int hostsize = UT_HOSTSIZE;
+       int numeric = 0;
+
+       maxrec = -1;
+
+       while ((ch = getopt(argc, argv, "0123456789f:H:h:L:nN:Tt:x")) != -1)
+               switch (ch) {
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       /*
+                        * kludge: last was originally designed to take
+                        * a number after a dash.
+                        */
+                       if (maxrec == -1) {
+                               p = argv[optind - 1];
+                               if (p[0] == '-' && p[1] == ch && !p[2])
+                                       maxrec = atol(++p);
+                               else if (optind < argc)
+                                       maxrec = atol(argv[optind] + 1);
+                               else
+                                       usage();
+                               if (!maxrec)
+                                       return 0;
+                       }
+                       break;
+               case 'f':
+                       file = optarg;
+                       if ('\0' == file[0])
+                               usage();
+                       break;
+               case 'H':
+                       hostsize = atoi(optarg);
+                       if (hostsize < 1)
+                               usage();
+                       break;
+               case 'h':
+                       hostconv(optarg);
+                       addarg(HOST_TYPE, optarg);
+                       break;
+               case 'L':
+                       linesize = atoi(optarg);
+                       if (linesize < 1)
+                               usage();
+                       break;
+               case 'N':
+                       namesize = atoi(optarg);
+                       if (namesize < 1)
+                               usage();
+                       break;
+               case 'n':
+                       numeric = 1;
+                       break;
+               case 'T':
+                       fulltime = 1;
+                       break;
+               case 't':
+                       addarg(TTY_TYPE, ttyconv(optarg));
+                       break;
+               case 'x':
+                       xflag = 1;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+
+       if (argc) {
+               setlinebuf(stdout);
+               for (argv += optind; *argv; ++argv) {
+#define        COMPATIBILITY
+#ifdef COMPATIBILITY
+                       /* code to allow "last p5" to work */
+                       addarg(TTY_TYPE, ttyconv(*argv));
+#endif
+                       addarg(USER_TYPE, *argv);
+               }
+       }
+       if (file == NULL) {
+#ifdef SUPPORT_UTMPX
+               if (access(_PATH_WTMPX, R_OK) == 0)
+                       file = _PATH_WTMPX;
+               else
+#endif
+#ifdef SUPPORT_UTMP
+               if (access(_PATH_WTMP, R_OK) == 0)
+                       file = _PATH_WTMP;
+#endif
+               if (file == NULL)
+#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
+                       errx(EXIT_FAILURE, "Cannot access `%s' or `%s'", _PATH_WTMPX,
+                           _PATH_WTMP);
+#elif defined(SUPPORT_UTMPX)
+                       errx(EXIT_FAILURE, "Cannot access `%s'", _PATH_WTMPX);
+#elif defined(SUPPORT_UTMP)
+                       errx(EXIT_FAILURE, "Cannot access `%s'", _PATH_WTMP);
+#else
+                       errx(EXIT_FAILURE, "No utmp or utmpx support compiled in.");
+#endif
+       }
+#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
+       if (file[strlen(file) - 1] == 'x' || xflag)
+               wtmpx(file, namesize, linesize, hostsize, numeric);
+       else
+               wtmp(file, namesize, linesize, hostsize, numeric);
+#elif defined(SUPPORT_UTMPX)
+       wtmpx(file, namesize, linesize, hostsize, numeric);
+#elif defined(SUPPORT_UTMP)
+       wtmp(file, namesize, linesize, hostsize, numeric);
+#else
+       errx(EXIT_FAILURE, "No utmp or utmpx support compiled in.");
+#endif
+       exit(EXIT_SUCCESS);
+}
+
+
+/*
+ * addarg --
+ *     add an entry to a linked list of arguments
+ */
+static void
+addarg(int type, const char *arg)
+{
+       ARG *cur;
+
+       if (!(cur = (ARG *)malloc(sizeof(ARG))))
+               err(EXIT_FAILURE, "malloc failure");
+       cur->next = arglist;
+       cur->type = type;
+       cur->name = arg;
+       arglist = cur;
+}
+
+/*
+ * addtty --
+ *     add an entry to a linked list of ttys
+ */
+static TTY *
+addtty(const char *tty)
+{
+       TTY *cur;
+
+       if (!(cur = (TTY *)malloc(sizeof(TTY))))
+               err(EXIT_FAILURE, "malloc failure");
+       cur->next = ttylist;
+       cur->logout = currentout;
+       memmove(cur->tty, tty, sizeof(cur->tty));
+       return (ttylist = cur);
+}
+
+/*
+ * hostconv --
+ *     convert the hostname to search pattern; if the supplied host name
+ *     has a domain attached that is the same as the current domain, rip
+ *     off the domain suffix since that's what login(1) does.
+ */
+static void
+hostconv(char *arg)
+{
+       static int first = 1;
+       static char *hostdot, name[MAXHOSTNAMELEN + 1];
+       char *argdot;
+
+       if (!(argdot = strchr(arg, '.')))
+               return;
+       if (first) {
+               first = 0;
+               if (gethostname(name, sizeof(name)))
+                       err(EXIT_FAILURE, "gethostname");
+               name[sizeof(name) - 1] = '\0';
+               hostdot = strchr(name, '.');
+       }
+       if (hostdot && !strcasecmp(hostdot, argdot))
+               *argdot = '\0';
+}
+
+/*
+ * ttyconv --
+ *     convert tty to correct name.
+ */
+static const char *
+ttyconv(char *arg)
+{
+       char *mval;
+
+       if (!strcmp(arg, "co"))
+               return ("console");
+       /*
+        * kludge -- we assume that all tty's end with
+        * a two character suffix.
+        */
+       if (strlen(arg) == 2) {
+               if (asprintf(&mval, "tty%s", arg) == -1)
+                       err(EXIT_FAILURE, "malloc failure");
+               return (mval);
+       }
+       if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
+               return (&arg[sizeof(_PATH_DEV) - 1]);
+       return (arg);
+}
+
+/*
+ * fmttime --
+ *     return pointer to (static) formatted time string.
+ */
+static char *
+fmttime(time_t t, int flags)
+{
+       struct tm *tm;
+       static char tbuf[TBUFLEN];
+
+       tm = (flags & GMT) ? gmtime(&t) : localtime(&t);
+       if (tm == NULL) {
+               strcpy(tbuf, "????");
+               return tbuf;
+       }
+       strftime(tbuf, sizeof(tbuf),
+           (flags & TIMEONLY)
+            ? (flags & FULLTIME ? LTFMTS : TFMTS)
+            : (flags & FULLTIME ? LTFMT : TFMT),
+           tm);
+       return (tbuf);
+}
+
+#ifdef SUPPORT_UTMP
+#define TYPE(a)        0
+#define NAMESIZE UT_NAMESIZE
+#define LINESIZE UT_LINESIZE
+#define HOSTSIZE UT_HOSTSIZE
+#define ut_timefld ut_time
+#define HAS_UT_SS 0
+#include "want.c"
+#undef TYPE /*(a)*/
+#undef NAMESIZE
+#undef LINESIZE
+#undef HOSTSIZE
+#undef ut_timefld
+#undef HAS_UT_SS
+#endif
+
+#ifdef SUPPORT_UTMPX
+#define utmp utmpx
+#define want wantx
+#define wtmp wtmpx
+#define gethost gethostx
+#define buf bufx
+#define onintr onintrx
+#define TYPE(a) (a)->ut_type
+#define NAMESIZE UTX_USERSIZE
+#define LINESIZE UTX_LINESIZE
+#define HOSTSIZE UTX_HOSTSIZE
+#define ut_timefld ut_xtime
+#define HAS_UT_SS 1
+#include "want.c"
+#endif
diff --git a/usr.bin/last/want.c b/usr.bin/last/want.c
new file mode 100644 (file)
index 0000000..ffd3891
--- /dev/null
@@ -0,0 +1,318 @@
+/*     $NetBSD: want.c,v 1.17 2012/03/15 03:04:05 dholland Exp $       */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+static struct utmp *buf;
+static time_t seentime;
+
+static void onintr(int);
+static int want(struct utmp *, int);
+static const char *gethost(struct utmp *, const char *, int);
+
+static const char *
+/*ARGSUSED*/
+gethost(struct utmp *ut, const char *host, int numeric)
+{
+#if HAS_UT_SS == 0
+       return numeric ? "" : host;
+#else
+       if (numeric) {
+               static char hbuf[512];
+               hbuf[0] = '\0';
+               (void)sockaddr_snprintf(hbuf, sizeof(hbuf), "%a",
+                   (struct sockaddr *)&ut->ut_ss);
+               return hbuf;
+       } else
+               return host;
+#endif
+}
+
+#define NULTERM(what) \
+       if (check ## what) \
+               (void)strlcpy(what ## p = what ## buf, bp->ut_ ## what, \
+                   sizeof(what ## buf)); \
+       else \
+               what ## p = bp->ut_ ## what
+       
+/*
+ * wtmp --
+ *     read through the wtmp file
+ */
+static void
+wtmp(const char *file, int namesz, int linesz, int hostsz, int numeric)
+{
+       struct utmp     *bp;            /* current structure */
+       TTY     *T;                     /* tty list entry */
+       struct stat     stb;            /* stat of file for sz */
+       off_t   offset;
+       int     wfd;
+       char    *ct;
+       const char *crmsg;
+       size_t  len = sizeof(*buf) * MAXUTMP;
+       char namebuf[sizeof(bp->ut_name) + 1], *namep;
+       char linebuf[sizeof(bp->ut_line) + 1], *linep;
+       char hostbuf[sizeof(bp->ut_host) + 1], *hostp;
+       int checkname = namesz > (int)sizeof(bp->ut_name);
+       int checkline = linesz > (int)sizeof(bp->ut_line);
+       int checkhost = hostsz > (int)sizeof(bp->ut_host);
+
+       if ((buf = malloc(len)) == NULL)
+               err(EXIT_FAILURE, "Cannot allocate utmp buffer");
+
+       crmsg = NULL;
+
+       if (!strcmp(file, "-")) {
+               wfd = STDIN_FILENO;
+               file = "<stdin>";
+       } else if ((wfd = open(file, O_RDONLY, 0)) < 0) {
+               err(EXIT_FAILURE, "%s", file);
+       }
+
+       if (lseek(wfd, 0, SEEK_CUR) < 0) {
+               const char *dir;
+               char *tfile;
+               int tempfd;
+               ssize_t tlen;
+
+               if (ESPIPE != errno) {
+                       err(EXIT_FAILURE, "lseek");
+               }
+               dir = getenv("TMPDIR");
+               if (asprintf(&tfile, "%s/last.XXXXXX", dir ? dir : _PATH_TMP) == -1)
+                       err(EXIT_FAILURE, "asprintf");
+               tempfd = mkstemp(tfile);
+               if (tempfd < 0) {
+                       err(EXIT_FAILURE, "mkstemp");
+               }
+               unlink(tfile);
+               for (;;) {
+                       tlen = read(wfd, buf, len);
+                       if (tlen < 0) {
+                               err(1, "%s: read", file);
+                       }
+                       if (tlen == 0) {
+                               break;
+                       }
+                       if (write(tempfd, buf, tlen) != tlen) {
+                               err(1, "%s: write", tfile);
+                       }
+               }
+               wfd = tempfd;
+       }
+
+       if (fstat(wfd, &stb) == -1)
+               err(EXIT_FAILURE, "%s: fstat", file);
+       if (!S_ISREG(stb.st_mode))
+               errx(EXIT_FAILURE, "%s: Not a regular file", file);
+
+       seentime = stb.st_mtime;
+       (void)signal(SIGINT, onintr);
+       (void)signal(SIGQUIT, onintr);
+
+       offset = stb.st_size;
+       /* Ignore trailing garbage or partial record */
+       offset -= offset % (off_t) sizeof(*buf);
+       
+       while (offset >= (off_t) sizeof(*buf)) {
+               ssize_t ret, i;
+               size_t size;
+
+               size = MIN((off_t)len, offset);
+               offset -= size; /* Always a multiple of sizeof(*buf) */
+               ret = pread(wfd, buf, size, offset);
+               if (ret < 0) {
+                       err(EXIT_FAILURE, "%s: pread", file);
+               } else if ((size_t) ret < size) {
+                       err(EXIT_FAILURE, "%s: Unexpected end of file", file);
+               }
+
+               for (i = ret / sizeof(*buf) - 1; i >= 0; i--) {
+                       bp = &buf[i];
+
+                       NULTERM(name);
+                       NULTERM(line);
+                       NULTERM(host);
+
+                       seentime = bp->ut_timefld;
+
+                       /*
+                        * if the terminal line is '~', the machine stopped.
+                        * see utmp(5) for more info.
+                        */
+                       if (linep[0] == '~' && !linep[1]) {
+                               /* everybody just logged out */
+                               for (T = ttylist; T; T = T->next)
+                                       T->logout = -bp->ut_timefld;
+                               currentout = -bp->ut_timefld;
+                               crmsg = strncmp(namep, "shutdown",
+                                   namesz) ? "crash" : "shutdown";
+                               if (want(bp, NO)) {
+                                       ct = fmttime(bp->ut_timefld, fulltime);
+                                       printf("%-*.*s  %-*.*s %-*.*s %s\n",
+                                           namesz, namesz, namep,
+                                           linesz, linesz, linep,
+                                           hostsz, hostsz,
+                                           gethost(bp, hostp, numeric), ct);
+                                       if (maxrec != -1 && !--maxrec)
+                                               return;
+                               }
+                               continue;
+                       }
+                       /*
+                        * if the line is '{' or '|', date got set; see
+                        * utmp(5) for more info.
+                        */
+                       if ((linep[0] == '{' || linep[0] == '|') && !linep[1]) {
+                               if (want(bp, NO)) {
+                                       ct = fmttime(bp->ut_timefld, fulltime);
+                                       printf("%-*.*s  %-*.*s %-*.*s %s\n",
+                                           namesz, namesz, namep,
+                                           linesz, linesz, linep,
+                                           hostsz, hostsz,
+                                           gethost(bp, hostp, numeric),
+                                           ct);
+                                       if (maxrec && !--maxrec)
+                                               return;
+                               }
+                               continue;
+                       }
+                       /* find associated tty */
+                       for (T = ttylist;; T = T->next) {
+                               if (!T) {
+                                       /* add new one */
+                                       T = addtty(linep);
+                                       break;
+                               }
+                               if (!strncmp(T->tty, linep, LINESIZE))
+                                       break;
+                       }
+                       if (TYPE(bp) == SIGNATURE)
+                               continue;
+                       if (namep[0] && want(bp, YES)) {
+                               ct = fmttime(bp->ut_timefld, fulltime);
+                               printf("%-*.*s  %-*.*s %-*.*s %s ",
+                                   namesz, namesz, namep,
+                                   linesz, linesz, linep,
+                                   hostsz, hostsz,
+                                   gethost(bp, hostp, numeric),
+                                   ct);
+                               if (!T->logout)
+                                       puts("  still logged in");
+                               else {
+                                       time_t  delta;                  /* time difference */
+
+                                       if (T->logout < 0) {
+                                               T->logout = -T->logout;
+                                               printf("- %s", crmsg);
+                                       }
+                                       else
+                                               printf("- %s",
+                                                   fmttime(T->logout,
+                                                   fulltime | TIMEONLY));
+                                       delta = T->logout - bp->ut_timefld;
+                                       if (delta < SECSPERDAY)
+                                               printf("  (%s)\n",
+                                                   fmttime(delta,
+                                                   fulltime | TIMEONLY | GMT));
+                                       else
+                                               printf(" (%lld+%s)\n",
+                                                   (long long)
+                                                   delta / SECSPERDAY,
+                                                   fmttime(delta,
+                                                   fulltime | TIMEONLY | GMT));
+                               }
+                               if (maxrec != -1 && !--maxrec)
+                                       return;
+                       }
+                       T->logout = bp->ut_timefld;
+               }
+       }
+       fulltime = 1;   /* show full time */
+       crmsg = fmttime(seentime, FULLTIME);
+       if ((ct = strrchr(file, '/')) != NULL)
+               ct++;
+       printf("\n%s begins %s\n", ct ? ct : file, crmsg);
+}
+
+/*
+ * want --
+ *     see if want this entry
+ */
+static int
+want(struct utmp *bp, int check)
+{
+       ARG *step;
+
+       if (check) {
+               /*
+                * when uucp and ftp log in over a network, the entry in
+                * the utmp file is the name plus their process id.  See
+                * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
+                */
+               if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
+                       bp->ut_line[3] = '\0';
+               else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
+                       bp->ut_line[4] = '\0';
+       }
+       if (!arglist)
+               return (YES);
+
+       for (step = arglist; step; step = step->next)
+               switch(step->type) {
+               case HOST_TYPE:
+                       if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE))
+                               return (YES);
+                       break;
+               case TTY_TYPE:
+                       if (!strncmp(step->name, bp->ut_line, LINESIZE))
+                               return (YES);
+                       break;
+               case USER_TYPE:
+                       if (!strncmp(step->name, bp->ut_name, NAMESIZE))
+                               return (YES);
+                       break;
+       }
+       return (NO);
+}
+
+/*
+ * onintr --
+ *     on interrupt, we inform the user how far we've gotten
+ */
+static void
+onintr(int signo)
+{
+       /* FIXME: None of this is allowed in a signal handler */
+       printf("\ninterrupted %s\n", fmttime(seentime, FULLTIME));
+       if (signo == SIGINT) {
+               (void)raise_default_signal(signo);
+               exit(EXIT_FAILURE);
+       }
+       (void)fflush(stdout);           /* fix required for rsh */
+}
diff --git a/usr.bin/wall/Makefile b/usr.bin/wall/Makefile
new file mode 100644 (file)
index 0000000..bfc92b5
--- /dev/null
@@ -0,0 +1,18 @@
+#      $NetBSD: Makefile,v 1.10 2007/05/28 12:06:32 tls Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/6/93
+
+.include <bsd.own.mk>
+
+USE_FORT?= yes # setuid
+PROG=  wall
+SRCS=  wall.c utmpentry.c term_chk.c
+BINGRP=        tty
+BINMODE=2555
+DPADD+=${LIBUTIL}
+LDADD+=-lutil
+
+.PATH.c: ${NETBSDSRCDIR}/usr.bin/who ${NETBSDSRCDIR}/usr.bin/write
+CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/who -DSUPPORT_UTMPX -DSUPPORT_UTMP
+CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/write
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/wall/wall.1 b/usr.bin/wall/wall.1
new file mode 100644 (file)
index 0000000..8a9d735
--- /dev/null
@@ -0,0 +1,74 @@
+.\"    $NetBSD: wall.1,v 1.7 2003/08/07 11:17:14 agc Exp $
+.\"
+.\" Copyright (c) 1989, 1990, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)wall.1     8.1 (Berkeley) 6/6/93
+.\"
+.Dd March 27, 2003
+.Dt WALL 1
+.Os
+.Sh NAME
+.Nm wall
+.Nd write a message to users
+.Sh SYNOPSIS
+.Nm
+.Op Fl g Ar group
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+displays the contents of
+.Ar file
+or, by default, its standard input, on the terminals of all
+currently logged in users.
+.Pp
+Only the super-user can write on the
+terminals of users who have chosen
+to deny messages or are using a program which
+automatically denies messages.
+.Bl -tag -width indent
+.It Fl g
+Send messages to users in this group.
+This option may be specified multiple times, and any user in any of the
+specified groups will receive the message.
+.El
+.Sh SEE ALSO
+.Xr mesg 1 ,
+.Xr talk 1 ,
+.Xr write 1 ,
+.Xr shutdown 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v7 .
+Support for
+.Fl g
+was added in
+.Nx 2.0
+(from
+.Ox 2.0 ) .
diff --git a/usr.bin/wall/wall.c b/usr.bin/wall/wall.c
new file mode 100644 (file)
index 0000000..b969964
--- /dev/null
@@ -0,0 +1,276 @@
+/*     $NetBSD: wall.c,v 1.29 2011/09/06 18:45:21 joerg Exp $  */
+
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)wall.c     8.2 (Berkeley) 11/16/93";
+#endif
+__RCSID("$NetBSD: wall.c,v 1.29 2011/09/06 18:45:21 joerg Exp $");
+#endif /* not lint */
+
+/*
+ * This program is not related to David Wall, whose Stanford Ph.D. thesis
+ * is entitled "Mechanisms for Broadcast and Selective Broadcast".
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <grp.h>
+#include <errno.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "utmpentry.h"
+
+#include "term_chk.h"
+
+static void    addgroup(char *);
+static void    makemsg(const char *);
+__dead static void     usage(void);
+
+static struct wallgroup {
+       gid_t   gid;
+       char    *name;
+       char    **mem;
+       struct wallgroup *next;
+} *grouplist;
+
+static int nobanner;
+static size_t mbufsize;
+static char *mbuf;
+
+/* ARGSUSED */
+int
+main(int argc, char **argv)
+{
+       int ch;
+       struct iovec iov;
+       char *p, **mem;
+       struct utmpentry *ep;
+       gid_t egid;
+       struct wallgroup *wg;
+       struct passwd *pw;
+
+       setprogname(argv[0]);
+       egid = getegid();
+       if (setegid(getgid()) == -1)
+               err(1, "setegid");
+       pw = getpwnam("nobody");
+
+       (void)check_sender(NULL, getuid(), egid);
+
+       while ((ch = getopt(argc, argv, "g:n")) != -1)
+               switch (ch) {
+               case 'n':
+                       /* undoc option for shutdown: suppress banner */
+                       if (geteuid() == 0 || (pw && getuid() == pw->pw_uid))
+                               nobanner = 1;
+                       break;
+               case 'g':
+                       addgroup(optarg);
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       argc -= optind;
+       argv += optind;
+       if (argc > 1)
+               usage();
+
+       makemsg(*argv);
+
+       iov.iov_base = mbuf;
+       iov.iov_len = mbufsize;
+       (void)getutentries(NULL, &ep);
+       (void)setegid(egid);
+       for (; ep; ep = ep->next) {
+               if (grouplist) {
+                       int ingroup;
+
+                       ingroup = 0;
+                       pw = getpwnam(ep->name);
+                       if (!pw)
+                               continue;
+                       for (wg = grouplist; wg && !ingroup; wg = wg->next) {
+                               if (wg->gid == pw->pw_gid)
+                                       ingroup = 1;
+                               for (mem = wg->mem; *mem && !ingroup; mem++)
+                                       if (strcmp(ep->name, *mem) == 0)
+                                               ingroup = 1;
+                       }
+                       if (ingroup == 0)
+                               continue;
+               }
+
+               /* skip [xgk]dm/xserver entries (":0", ":1", etc.) */
+               if (ep->line[0] == ':' && isdigit((unsigned char)ep->line[1]))
+                       continue;
+
+               if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL)
+                       warnx("%s", p);
+       }
+       exit(0);
+}
+
+static void
+addgroup(char *name)
+{
+       int i;
+       struct group *grp;
+       struct wallgroup *g;
+
+       grp = getgrnam(name);
+       if ((grp = getgrnam(name)) == NULL)
+               errx(1, "unknown group `%s'", name);
+       for (i = 0; grp->gr_mem[i]; i++)
+               continue;
+
+       g = (struct wallgroup *)malloc(sizeof *g);
+       if (g == NULL)
+               err(1, "malloc");
+       g->gid = grp->gr_gid;
+       g->name = name;
+       g->mem = (char **)malloc(i + 1);
+       if (g->mem == NULL)
+               err(1, "malloc");
+       for (i = 0; grp->gr_mem[i] != NULL; i++) {
+               g->mem[i] = strdup(grp->gr_mem[i]);
+               if (g->mem[i] == NULL)
+                       err(1, "malloc");
+       }
+       g->mem[i] = NULL;
+       g->next = grouplist;
+       grouplist = g;
+}
+
+static void
+makemsg(const char *fname)
+{
+       int ch, cnt;
+       struct tm *lt;
+       struct passwd *pw;
+       struct stat sbuf;
+       time_t now;
+       FILE *fp;
+       int fd;
+       const char *whom, *tty;
+       char *p, tmpname[MAXPATHLEN], lbuf[100],
+           hostname[MAXHOSTNAMELEN+1];
+
+       (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP);
+       if ((fd = mkstemp(tmpname)) == -1)
+               err(1, "can't open temporary file");
+       (void)unlink(tmpname);
+       if (!(fp = fdopen(fd, "r+")))
+               err(1, "can't open temporary file");
+
+       if (!nobanner) {
+               if (!(whom = getlogin()))
+                       whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+               (void)gethostname(hostname, sizeof(hostname));
+               hostname[sizeof(hostname) - 1] = '\0';
+               (void)time(&now);
+               lt = localtime(&now);
+
+               /*
+                * all this stuff is to blank out a square for the message;
+                * we wrap message lines at column 79, not 80, because some
+                * terminals wrap after 79, some do not, and we can't tell.
+                * Which means that we may leave a non-blank character
+                * in column 80, but that can't be helped.
+                */
+               (void)fprintf(fp, "\r%79s\r\n", " ");
+               (void)snprintf(lbuf, sizeof lbuf,
+                   "Broadcast Message from %s@%s", whom, hostname);
+               (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf);
+               tty = ttyname(STDERR_FILENO);
+               if (tty == NULL)
+                       tty = "??";
+               (void)snprintf(lbuf, sizeof lbuf,
+                   "        (%s) at %d:%02d %s...", tty,
+                   lt->tm_hour, lt->tm_min, lt->tm_zone);
+               (void)fprintf(fp, "%-79.79s\r\n", lbuf);
+       }
+       (void)fprintf(fp, "%79s\r\n", " ");
+
+       if (fname && !(freopen(fname, "r", stdin)))
+               err(1, "can't read %s", fname);
+       while (fgets(lbuf, sizeof(lbuf), stdin))
+               for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+                       if (cnt == 79 || ch == '\n') {
+                               for (; cnt < 79; ++cnt)
+                                       putc(' ', fp);
+                               putc('\r', fp);
+                               putc('\n', fp);
+                               cnt = -1;
+                       }
+                       if (ch != '\n')
+                               putc(ch, fp);
+               }
+       (void)fprintf(fp, "%79s\r\n", " ");
+       rewind(fp);
+
+       if (fstat(fd, &sbuf))
+               err(1, "can't stat temporary file");
+       if ((uint64_t)sbuf.st_size > SIZE_T_MAX)
+               errx(1, "file too big");
+       mbufsize = sbuf.st_size;
+       if (!(mbuf = malloc(mbufsize)))
+               err(1, "malloc");
+       if (fread(mbuf, 1, mbufsize, fp) != mbufsize)
+               err(1, "can't read temporary file");
+       (void)fclose(fp);
+}
+
+static void
+usage(void)
+{
+
+       (void)fprintf(stderr, "usage: %s [-g group] [file]\n", getprogname());
+       exit(1);
+}