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 \
+++ /dev/null
-PROG= getty
-BINDIR= /bin
-MAN=
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* 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 */
-}
+++ /dev/null
-PROG= last
-MAN=
-
-LINKS+= ${BINDIR}/last ${BINDIR}/uptime
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* 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);
-}
-
+++ /dev/null
-SCRIPTS= poweroff.sh
-MAN=
-
-.include <bsd.prog.mk>
+++ /dev/null
-#!/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
+++ /dev/null
-# 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>
+++ /dev/null
-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
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/*
- 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;
-}
+++ /dev/null
-
-static char STR_WTMP[] = "/usr/adm/wtmp";
-static char STR_ROOT_WTMP[] = "/etc/wtmp";
#
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>
void usage(void);
int main(int argc, char *argv[]);
-void wtmp(int type, int linenr, char *line, pid_t pid, char *host);
void usage()
{
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);
+++ /dev/null
-/*
- * 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));
-}
./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
#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
/* 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) {
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 */
#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>
#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"
{
if (++CAD_count == 3) {
cons_stop();
- sys_abort(RBT_DEFAULT);
+ sys_abort(RB_AUTOBOOT);
}
sys_kill(INIT_PROC_NR, SIGABRT);
rebooting = 1;
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.
*/
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 \
--- /dev/null
+# $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:
usage()
{
- echo >&2 "Usage: $0 [-saf] start|stop|down"
+ echo >&2 "Usage: $0 [-saf] autoboot|start|stop|down"
exec intr sh
}
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
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
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 ]
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."
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
--- /dev/null
+#!/bin/sh
+
+sh /etc/rc stop
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;
#
# 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
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
DAEMONS=/etc/rc.daemons
case $action in
-start)
+start|autoboot)
# Select console font.
test -f /etc/font && loadfont /etc/font </dev/console
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 \
+++ /dev/null
-#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 */
#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 */
#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. */
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 *);
#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 {
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 *);
#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"
__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);
}
#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"
* 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,
#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>
;
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;
}
#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"
}
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); }
#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"
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;
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);
}
#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)
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);
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;
#include <string.h>
#include <sys/reboot.h>
-int reboot(int how)
+int reboot(int how, char *bootstr)
{
message m;
(*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) {
}
*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);
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 \
.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}
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 \
SUBDIR= \
fingerd ftpd \
- ld.elf_so
+ ld.elf_so \
+ getty
.if defined(__MINIX)
SUBDIR+= makewhatis
--- /dev/null
+# $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>
--- /dev/null
+/* $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);
--- /dev/null
+.\" $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 .
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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[];
--- /dev/null
+/* $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 }
+};
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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.."
--- /dev/null
+/* $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);
+}
--- /dev/null
+.\" $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 .
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 \
+++ /dev/null
-.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).
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 \
+++ /dev/null
-.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)
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
+++ /dev/null
-.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).
+++ /dev/null
-.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)
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
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
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
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
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
SUBDIR= \
\
fsck \
- mknod nologin
+ mknod \
+ nologin \
+ mknod \
+ init \
+ reboot \
+ shutdown
# support for various file systems
SUBDIR+= newfs_ext2fs fsck_ext2fs
--- /dev/null
+# $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>
--- /dev/null
+$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
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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"
--- /dev/null
+# $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>
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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);
+}
--- /dev/null
+# $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>
--- /dev/null
+/* $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"
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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);
+}
.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"
+++ /dev/null
-# Makefile for the init program (INIT)
-.include <bsd.own.mk>
-
-PROG= init
-SRCS= init.c
-
-MAN=
-
-BINDIR?= /usr/sbin
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* 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;
-}
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;
#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>
/* 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 */
#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>
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);
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 \
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)
--- /dev/null
+# $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>
--- /dev/null
+.\" $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 .
--- /dev/null
+/* $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
--- /dev/null
+/* $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 */
+}
--- /dev/null
+# $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>
--- /dev/null
+.\" $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 ) .
--- /dev/null
+/* $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);
+}