From a06e2ab3959428ebf7e32b1cde13e386df9115ab Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Mon, 9 Sep 2013 13:20:18 +0000 Subject: [PATCH] big -inspired netbsd switch import/switch of: init, getty, reboot, halt, shutdown, wall, last changes: . change reboot() call to netbsd prototype and args . allows pristine . use clean instead of . implement TIOCSCTTY for use by getty so getty can get controlling terminal from init's child(ren) . allow NULL envp for exec Change-Id: I5ca02cb4230857140c08794bbfeba7df982c58a3 --- commands/Makefile | 8 +- commands/getty/Makefile | 5 - commands/getty/getty.c | 210 ---- commands/last/Makefile | 6 - commands/last/last.c | 482 -------- commands/poweroff/Makefile | 4 - commands/poweroff/poweroff.sh | 13 - commands/reboot/Makefile | 15 - commands/reboot/README | 52 - commands/reboot/halt.c | 126 -- commands/reboot/log.c | 77 -- commands/reboot/sh_wall.c | 109 -- commands/reboot/shutdown.c | 393 ------ commands/reboot/wtmp.h | 3 - commands/telnetd/Makefile | 2 +- commands/telnetd/main.c | 5 - commands/telnetd/wtmp.c | 112 -- distrib/sets/lists/minix/mi | 34 +- drivers/tps65217/tps65217.c | 11 +- drivers/tty/arch/i386/keyboard.c | 4 +- drivers/tty/tty.c | 4 + etc/Makefile | 2 +- etc/gettytab | 154 +++ etc/rc | 30 +- etc/rc.shutdown | 3 + etc/system.conf | 2 +- etc/ttys | 8 +- etc/usr/rc | 7 +- include/minix/Makefile | 2 +- include/minix/reboot.h | 15 - include/minix/termios.h | 6 + include/sys/ioc_tty.h | 1 + include/unistd.h | 2 +- include/utmp.h | 36 - kernel/arch/earm/arch_reset.c | 25 +- kernel/arch/earm/pre_init.c | 4 +- kernel/arch/i386/arch_reset.c | 40 +- kernel/arch/i386/pre_init.c | 4 +- kernel/main.c | 23 +- lib/libc/gen/utmpx.c | 16 +- lib/libc/sys-minix/reboot.c | 2 +- lib/libc/sys-minix/stack_utils.c | 4 +- lib/libc/sys/Makefile.inc | 2 +- lib/libminc/Makefile | 5 +- lib/libutil/Makefile | 2 +- libexec/Makefile | 3 +- libexec/getty/Makefile | 12 + libexec/getty/extern.h | 52 + libexec/getty/getty.8 | 177 +++ libexec/getty/gettytab.5 | 423 +++++++ libexec/getty/gettytab.h | 173 +++ libexec/getty/init.c | 146 +++ libexec/getty/main.c | 707 +++++++++++ libexec/getty/pathnames.h | 37 + libexec/getty/subr.c | 743 ++++++++++++ libexec/getty/ttys.5 | 227 ++++ man/man1/Makefile | 2 +- man/man1/last.1 | 60 - man/man2/Makefile | 2 +- man/man2/reboot.2 | 51 - man/man8/Makefile | 4 +- man/man8/poweroff.8 | 13 - man/man8/reboot.8 | 49 - releasetools/Makefile | 7 +- releasetools/arm_sdimage.sh | 11 +- releasetools/nbsd_ports | 8 +- sbin/Makefile | 7 +- sbin/init/Makefile | 18 + sbin/init/NOTES | 119 ++ sbin/init/init.8 | 374 ++++++ sbin/init/init.c | 1910 ++++++++++++++++++++++++++++++ sbin/init/pathnames.h | 40 + sbin/reboot/Makefile | 14 + sbin/reboot/reboot.8 | 168 +++ sbin/reboot/reboot.c | 264 +++++ sbin/shutdown/Makefile | 15 + sbin/shutdown/pathnames.h | 45 + sbin/shutdown/shutdown.8 | 243 ++++ sbin/shutdown/shutdown.c | 592 +++++++++ servers/Makefile | 4 +- servers/init/Makefile | 11 - servers/init/init.c | 475 -------- servers/mfs/super.c | 6 +- servers/pm/misc.c | 5 +- servers/vfs/device.c | 8 + usr.bin/Makefile | 4 +- usr.bin/last/Makefile | 10 + usr.bin/last/last.1 | 161 +++ usr.bin/last/last.c | 405 +++++++ usr.bin/last/want.c | 318 +++++ usr.bin/wall/Makefile | 18 + usr.bin/wall/wall.1 | 74 ++ usr.bin/wall/wall.c | 276 +++++ 93 files changed, 8096 insertions(+), 2465 deletions(-) delete mode 100644 commands/getty/Makefile delete mode 100644 commands/getty/getty.c delete mode 100644 commands/last/Makefile delete mode 100644 commands/last/last.c delete mode 100644 commands/poweroff/Makefile delete mode 100644 commands/poweroff/poweroff.sh delete mode 100644 commands/reboot/Makefile delete mode 100644 commands/reboot/README delete mode 100644 commands/reboot/halt.c delete mode 100644 commands/reboot/log.c delete mode 100644 commands/reboot/sh_wall.c delete mode 100644 commands/reboot/shutdown.c delete mode 100644 commands/reboot/wtmp.h delete mode 100644 commands/telnetd/wtmp.c create mode 100644 etc/gettytab create mode 100644 etc/rc.shutdown delete mode 100644 include/minix/reboot.h create mode 100644 libexec/getty/Makefile create mode 100644 libexec/getty/extern.h create mode 100644 libexec/getty/getty.8 create mode 100644 libexec/getty/gettytab.5 create mode 100644 libexec/getty/gettytab.h create mode 100644 libexec/getty/init.c create mode 100644 libexec/getty/main.c create mode 100644 libexec/getty/pathnames.h create mode 100644 libexec/getty/subr.c create mode 100644 libexec/getty/ttys.5 delete mode 100644 man/man1/last.1 delete mode 100644 man/man2/reboot.2 delete mode 100644 man/man8/poweroff.8 delete mode 100644 man/man8/reboot.8 create mode 100644 sbin/init/Makefile create mode 100644 sbin/init/NOTES create mode 100644 sbin/init/init.8 create mode 100644 sbin/init/init.c create mode 100644 sbin/init/pathnames.h create mode 100644 sbin/reboot/Makefile create mode 100644 sbin/reboot/reboot.8 create mode 100644 sbin/reboot/reboot.c create mode 100644 sbin/shutdown/Makefile create mode 100644 sbin/shutdown/pathnames.h create mode 100644 sbin/shutdown/shutdown.8 create mode 100644 sbin/shutdown/shutdown.c delete mode 100644 servers/init/Makefile delete mode 100644 servers/init/init.c create mode 100644 usr.bin/last/Makefile create mode 100644 usr.bin/last/last.1 create mode 100644 usr.bin/last/last.c create mode 100644 usr.bin/last/want.c create mode 100644 usr.bin/wall/Makefile create mode 100644 usr.bin/wall/wall.1 create mode 100644 usr.bin/wall/wall.c diff --git a/commands/Makefile b/commands/Makefile index d4e0e36af..58a17cc56 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -10,18 +10,18 @@ SUBDIR= add_route arp ash at backup btrace \ dhrystone diff diskctl \ eject factor fbdctl \ find fix format fortune fsck.mfs \ - gcov-pull getty grep host \ + gcov-pull grep host \ hostaddr ifconfig ifdef \ - intr ipcrm ipcs irdpd isoread last \ + intr ipcrm ipcs irdpd isoread \ less loadkeys loadramdisk logger look lp \ lpd lspci mail MAKEDEV \ mined \ mount mt netconf \ nonamed patch \ - ping postinstall poweroff prep printroot \ + ping postinstall prep printroot \ profile progressbar pr_routes ps pwdauth \ ramdisk rarpd rawspeed rcp readclock \ - reboot remsync rget rlogin \ + remsync rget rlogin \ rotate rsh rshd service setup shar \ sleep slip spell sprofalyze sprofdiff srccrc \ stty svclog svrctl swifi synctree sysenv \ diff --git a/commands/getty/Makefile b/commands/getty/Makefile deleted file mode 100644 index 6425275df..000000000 --- a/commands/getty/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -PROG= getty -BINDIR= /bin -MAN= - -.include diff --git a/commands/getty/getty.c b/commands/getty/getty.c deleted file mode 100644 index 9e35fb2b6..000000000 --- a/commands/getty/getty.c +++ /dev/null @@ -1,210 +0,0 @@ -/* getty - get tty speed Author: Fred van Kempen */ - -/* - * GETTY - Initialize and serve a login-terminal for INIT. - * Also, select the correct speed. The STTY() code - * was taken from stty(1).c; which was written by - * Andrew S. Tanenbaum. - * - * Usage: getty [speed] - * - * Version: 3.4 02/17/90 - * - * Author: F. van Kempen, MicroWalt Corporation - * - * Modifications: - * All the good stuff removed to get a minimal getty, because - * many modems don't like all that fancy speed detection stuff. - * 03/03/91 Kees J. Bot (kjb@cs.vu.nl) - * - * Uname(), termios. More nonsense removed. (The result has - * only 10% of the original functionality, but a 10x chance of - * working.) - * 12/12/92 Kees J. Bot - * - * Customizable login banner. - * 11/13/95 Kees J. Bot - * - * Suspend/resume signals removed. - * 2001-04-04 Kees J. Bot - * - * Removed unused custom banner and returned speed option - * functionality (by simply calling stty). - * 2012-09-24 T. Veerman - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char LOGIN[] = "/usr/bin/login"; -char SHELL[] = "/bin/sh"; - -char *tty_name; /* name of the line */ - -/* Crude indication of a tty being physically secure: */ -#define securetty(dev) ((unsigned) ((dev) - 0x0400) < (unsigned) 8) - -void std_out(const char *s) -{ - write(1, s, strlen(s)); -} - -/* Read one character from stdin. - */ -int readch(void) -{ - int st; - char ch1; - - /* read character from TTY */ - st = read(0, &ch1, 1); - if (st == 0) { - std_out("\n"); - exit(0); - } - if (st < 0) { - std_out("getty: "); - std_out(tty_name); - std_out(": read error\n"); - exit(1); - } - return(ch1 & 0xFF); -} - - -/* Handle the process of a GETTY. - */ -void do_getty(char *name, size_t len, char **args, const char *ttyname) -{ - register char *np, *s, *s0; - int ch; - struct utsname utsname; - char **banner, *t; - static char *def_banner[] = { "%s/%p (%t)\n\n%n login: ", 0 }; - - /* Clean up tty name. */ - if((t = strrchr(ttyname, '/'))) ttyname = t + 1; - - if (args[0] != NULL) { - char cmd[5+6+1]; /* "stty " + "115200" + '\0' */ - int speed; - speed = atoi(args[0]); - snprintf(cmd, sizeof(cmd), "stty %d\n", speed); - system(cmd); - } - - /* Display prompt. */ - ch = ' '; - *name = '\0'; - while (ch != '\n') { - /* Get data about this machine. */ - uname(&utsname); - - /* Print the banner. */ - for (banner = def_banner; *banner != NULL; banner++) { - std_out(banner == args ? "\n" : " "); - s0 = *banner; - for (s = *banner; *s != 0; s++) { - if (*s == '\\') { - write(1, s0, s-s0); - s0 = s+2; - switch (*++s) { - case 'n': std_out("\n"); break; - case 's': std_out(" "); break; - case 't': std_out("\t"); break; - case 0: goto leave; - default: s0 = s; - } - } else - if (*s == '%') { - write(1, s0, s-s0); - s0 = s+2; - switch (*++s) { - case 's': std_out(utsname.sysname); break; - case 'n': std_out(utsname.nodename); break; - case 'r': std_out(utsname.release); break; - case 'v': std_out(utsname.version); break; - case 'm': std_out(utsname.machine); break; - case 'p': std_out(utsname.arch); break; - case 't': std_out(ttyname); break; -#if __minix_vmd - case 'k': std_out(utsname.kernel); break; - case 'h': std_out(utsname.hostname); break; - case 'b': std_out(utsname.bus); break; -#endif - case 0: goto leave; - default: s0 = s-1; - } - } - } - leave: - write(1, s0, s-s0); - } - - np = name; - while ((ch = readch()) != '\n') { - if (np < name + len) *np++ = ch; - } - *np = '\0'; - if (*name == '\0') ch = ' '; /* blank line typed! */ - } -} - - -/* Execute the login(1) command with the current - * username as its argument. It will reply to the - * calling user by typing "Password: "... - */ -void do_login(char *name) -{ - struct stat st; - - execl(LOGIN, LOGIN, name, (char *) NULL); - /* Failed to exec login. Impossible, but true. Try a shell, but only if - * the terminal is more or less secure, because it will be a root shell. - */ - std_out("getty: can't exec "); - std_out(LOGIN); - std_out("\n"); - if (fstat(0, &st) == 0 && S_ISCHR(st.st_mode) && securetty(st.st_rdev)) { - execl(SHELL, SHELL, (char *) NULL); - } -} - - -int main(int argc, char **argv) -{ - char name[30]; - struct sigaction sa; - - /* Don't let QUIT dump core. */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = exit; - sigaction(SIGQUIT, &sa, NULL); - - tty_name = ttyname(0); - if (tty_name == NULL) { - std_out("getty: tty name unknown\n"); - pause(); - return(1); - } - - chown(tty_name, 0, 0); /* set owner of TTY to root */ - chmod(tty_name, 0600); /* mode to max secure */ - - do_getty(name, sizeof(name), argv+1, tty_name); /* handle getty() */ - name[29] = '\0'; /* make sure the name fits! */ - - do_login(name); /* and call login(1) if OK */ - - return(1); /* never executed */ -} diff --git a/commands/last/Makefile b/commands/last/Makefile deleted file mode 100644 index 44f199377..000000000 --- a/commands/last/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -PROG= last -MAN= - -LINKS+= ${BINDIR}/last ${BINDIR}/uptime - -.include diff --git a/commands/last/last.c b/commands/last/last.c deleted file mode 100644 index 1ee80487a..000000000 --- a/commands/last/last.c +++ /dev/null @@ -1,482 +0,0 @@ -/* last - display login history Author: Terrence W. Holm */ - -/* last- Display the user log-in history. - * Last(1) searches backwards through the file of log-in - * records (/usr/adm/wtmp), displaying the length of - * log-in sessions as requested by the options: - * - * Usage: last [-r] [-count] [-f file] [name] [tty] ... - * - * -r Search backwards only until the last reboot - * record. - * - * -count Only print out 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -#define FALSE 0 -#define TRUE 1 -#define RLOGIN 1 - -#define BUFFER_SIZE 4096 /* Room for wtmp records */ -#define MAX_WTMP_COUNT ( BUFFER_SIZE / sizeof(struct utmp) ) - -#define min( a, b ) ( (a < b) ? a : b ) -#define max( a, b ) ( (a > b) ? a : b ) - - -typedef struct logout { /* A logout time record */ - char line[12]; /* The terminal name */ - long time; /* The logout time */ - struct logout *next; /* Next in linked list */ -} logout; - - -static char *Version = "@(#) LAST 1.7 (10/24/92)"; - - -/* command-line option flags */ -char boot_limit = FALSE; /* stop on latest reboot */ -char count_limit = FALSE; /* stop after print_count */ -char tell_uptime = FALSE; /* tell uptime since last reboot */ -int print_count; -char *prog; /* name of this program */ -int arg_count; /* used to select specific */ -char **args; /* users and ttys */ - -/* global variables */ -long boot_time = 0; /* Zero means no reboot yet */ -char *boot_down; /* "crash" or "down " flag */ -logout *first_link = NULL; /* List of logout times */ -int interrupt = FALSE; /* If sigint or sigquit occurs */ - -int main(int argc, char **argv); -void Sigint(int sig); -void Sigquit(int sig); -void usage(void); -void Process(struct utmp *wtmp); -int Print_Record(struct utmp *wtmp); -void Print_Duration(long from, long to); -void Print_Uptime(void); -void Record_Logout_Time(struct utmp *wtmp); - -/* Sigint() and Sigquit() Flag occurrence of an interrupt. */ -void Sigint(sig) -int sig; -{ - interrupt = SIGINT; -} - - -void Sigquit(sig) -int sig; -{ - interrupt = SIGQUIT; -} - - -void usage() -{ - fprintf(stderr, - "Usage: last [-r] [-u] [-count] [-f file] [name] [tty] ...\n"); - exit(-1); -} - - -/* A log-in record format file contains four types of records. - * - * [1] generated on a system reboot: - * - * line="~", name="reboot", host="", time=date() - * - * - * [2] generated after a shutdown: - * - * line="~", name="shutdown", host="", time=date() - * - * - * [3] generated on a successful login(1) - * - * line=ttyname(), name=cuserid(), host=, time=date() - * - * - * [4] generated by init(8) on a logout - * - * line=ttyname(), name="", host="", time=date() - * - * - * Note: This version of last(1) does not recognize the '|' and '}' time - * change records. Last(1) pairs up line login's and logout's to - * generate four types of output lines: - * - * [1] a system reboot or shutdown - * - * reboot ~ Mon May 16 14:16 - * shutdown ~ Mon May 16 14:15 - * - * [2] a login with a matching logout - * - * edwin tty1 Thu May 26 20:05 - 20:32 (00:27) - * - * [3] a login followed by a reboot or shutdown - * - * root tty0 Mon May 16 13:57 - crash (00:19) - * root tty1 Mon May 16 13:45 - down (00:30) - * - * [4] a login not followed by a logout or reboot - * - * terry tty0 Thu May 26 21:19 still logged in - */ -void Process(wtmp) -struct utmp *wtmp; -{ - logout *link; - logout *next_link; - char is_reboot; - - /* suppress the job number on an "ftp" line */ - if (!strncmp(wtmp->ut_line, "ftp", (size_t)3)) strncpy(wtmp->ut_line, "ftp", (size_t)8); - - if (!strcmp(wtmp->ut_line, "~")) { - /* A reboot or shutdown record */ - if (boot_limit) exit(0); - - if (Print_Record(wtmp)) putchar('\n'); - boot_time = wtmp->ut_time; - - is_reboot = !strcmp(wtmp->ut_name, "reboot"); - if (is_reboot) - boot_down = "crash"; - else - boot_down = "down "; - - if (tell_uptime) { - if (!is_reboot) { - fprintf(stderr, - "%s: no reboot record added to wtmp file on system boot!\n", - prog); - exit(1); - } - Print_Uptime(); - exit(0); - } - - /* remove any logout records */ - for (link = first_link; link != NULL; link = next_link) { - next_link = link->next; - free(link); - } - first_link = NULL; - } else if (wtmp->ut_name[0] == '\0') { - /* A logout record */ - Record_Logout_Time(wtmp); - } else { - /* A login record */ - for (link = first_link; link != NULL; link = link->next) - if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) { - /* found corresponding logout record */ - if (Print_Record(wtmp)) { - printf("- %.5s ", ctime(&link->time) + 11); - Print_Duration(wtmp->ut_time, link->time); - } - /* record login time */ - link->time = wtmp->ut_time; - return; - } - /* could not find a logout record for this login tty */ - if (Print_Record(wtmp)) - if (boot_time == 0) /* still on */ - printf(" still logged in\n"); - else { /* system crashed while on */ - printf("- %s ", boot_down); - Print_Duration(wtmp->ut_time, boot_time); - } - Record_Logout_Time(wtmp); /* Needed in case of 2 - * consecutive logins */ - } -} - - -/* Print_Record(wtmp) If the record was requested, then print out - * the user name, terminal, host and time. - */ -int Print_Record(wtmp) -struct utmp *wtmp; -{ - int i; - char print_flag = FALSE; - - /* just interested in the uptime? */ - if (tell_uptime) return(FALSE); - - /* check if we have already printed the requested number of records */ - if (count_limit && print_count == 0) exit(0); - - for (i = 0; i < arg_count; ++i) - if (!strncmp(args[i], wtmp->ut_name, sizeof(wtmp->ut_name)) || - !strncmp(args[i], wtmp->ut_line, sizeof(wtmp->ut_line))) - print_flag = TRUE; - - if (arg_count == 0 || print_flag) { -#ifdef RLOGIN - printf("%-8.8s %-8.8s %-16.16s %.16s ", - wtmp->ut_name, wtmp->ut_line, wtmp->ut_host, - ctime(&wtmp->ut_time)); -#else - printf("%-8.8s %-8.8s %.16s ", - wtmp->ut_name, wtmp->ut_line, ctime(&wtmp->ut_time)); -#endif - --print_count; - return(TRUE); - } - return(FALSE); -} - - -/* Print_Duration(from, to) Calculate and print the days and hh:mm between - * the log-in and the log-out. - */ -void Print_Duration(from, to) -long from; -long to; -{ - long delta, days, hours, minutes; - - delta = max(to - from, 0); - days = delta / (24L * 60L * 60L); - delta = delta % (24L * 60L * 60L); - hours = delta / (60L * 60L); - delta = delta % (60L * 60L); - minutes = delta / 60L; - - if (days > 0) - printf("(%ld+", days); - else - printf(" ("); - - printf("%02ld:%02ld)\n", hours, minutes); -} - - -/* Print_Uptime() Calculate and print the "uptime" between the last recorded - * boot and the current time. - */ -void Print_Uptime() -{ -#define NLOADS 3 - int nloads; - double loads[NLOADS]; - char *utmp_file = _PATH_UTMP; - unsigned nusers; - struct utmp ut; - FILE *uf; - time_t now; - struct tm *tm; - unsigned long up; - - /* Count the number of active users in the utmp file. */ - if ((uf = fopen(utmp_file, "r")) == NULL) { - fprintf(stderr, "%s: %s: %s\n", prog, utmp_file, strerror(errno)); - exit(1); - } - - nusers = 0; - while (fread(&ut, sizeof(ut), 1, uf) == 1) { -#ifdef USER_PROCESS - if (ut.ut_type == USER_PROCESS) nusers++; -#else - if (ut.ut_name[0] != 0 && ut.ut_line[0] != 0) nusers++; -#endif - } - fclose(uf); - - /* Current time. */ - now = time((time_t *) NULL); - tm = localtime(&now); - - /* Uptime. */ - up = now - boot_time; - - printf(" %d:%02d up", tm->tm_hour, tm->tm_min); - if (up >= 24 * 3600L) { - unsigned long days = up / (24 * 3600L); - printf(" %lu day%s,", days, days == 1 ? "" : "s"); - } - printf(" %lu:%02lu,", (up % (24 * 3600L)) / 3600, (up % 3600) / 60); - printf(" %u user%s", nusers, nusers == 1 ? "" : "s"); - if((nloads = getloadavg(loads, NLOADS)) > 0) { - int i; - printf(", load averages:"); - for(i = 0; i < nloads; i++) - printf("%s %.2f", (i > 0) ? "," : "", loads[i]); - } - printf("\n"); -} - - -/* Record_Logout_Time(wtmp) A linked list of "last logout time" is kept. - * Each element of the list is for one terminal. - */ -void Record_Logout_Time(wtmp) -struct utmp *wtmp; -{ - logout *link; - - /* see if the terminal is already in the list */ - for (link = first_link; link != NULL; link = link->next) - if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) { - link->time = wtmp->ut_time; - return; - } - /* allocate a new logout record, for a tty not previously encountered */ - link = (logout *) malloc(sizeof(logout)); - if (link == NULL) { - fprintf(stderr, "%s: malloc failure\n", prog); - exit(1); - } - strncpy(link->line, wtmp->ut_line, (size_t)8); - link->time = wtmp->ut_time; - link->next = first_link; - - first_link = link; -} - - -int main(argc, argv) -int argc; -char *argv[]; -{ - char *wtmp_file = _PATH_WTMP; - FILE *f; - long size; /* Number of wtmp records in the file */ - int wtmp_count; /* How many to read into wtmp_buffer */ - struct utmp wtmp_buffer[MAX_WTMP_COUNT]; - - if ((prog = strrchr(argv[0], '/')) == NULL) prog = argv[0]; else prog++; - - --argc; - ++argv; - - while (argc > 0 && *argv[0] == '-') { - if (!strcmp(argv[0], "-r")) - boot_limit = TRUE; - else - if (!strcmp(argv[0], "-u")) - tell_uptime = TRUE; - else if (argc > 1 && !strcmp(argv[0], "-f")) { - wtmp_file = argv[1]; - --argc; - ++argv; - } else if ((print_count = atoi(argv[0] + 1)) > 0) - count_limit = TRUE; - else - usage(); - - --argc; - ++argv; - } - - arg_count = argc; - args = argv; - - if (!strcmp(prog, "uptime")) tell_uptime = TRUE; - - if ((f = fopen(wtmp_file, "r")) == NULL) { - perror(wtmp_file); - exit(1); - } - if (fseek(f, 0L, 2) != 0 || (size = ftell(f)) % sizeof(struct utmp) != 0) { - fprintf(stderr, "%s: invalid wtmp file\n", prog); - exit(1); - } - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - signal(SIGINT, Sigint); - signal(SIGQUIT, Sigquit); - } - size /= sizeof(struct utmp); /* Number of records in wtmp */ - - if (size == 0) wtmp_buffer[0].ut_time = time((time_t *)0); - - while (size > 0) { - wtmp_count = (int) min(size, MAX_WTMP_COUNT); - size -= (long) wtmp_count; - - fseek(f, size * sizeof(struct utmp), 0); - - - if (fread(&wtmp_buffer[0], sizeof(struct utmp), (size_t)wtmp_count, f) - != wtmp_count) { - fprintf(stderr, "%s: read error on wtmp file\n", prog); - exit(1); - } - while (--wtmp_count >= 0) { - Process(&wtmp_buffer[wtmp_count]); - if (interrupt) { - printf("\ninterrupted %.16s \n", - ctime(&wtmp_buffer[wtmp_count].ut_time)); - - if (interrupt == SIGINT) exit(2); - - interrupt = FALSE; - signal(SIGQUIT, Sigquit); - } - } - - } /* end while(size > 0) */ - - if (tell_uptime) { - fprintf(stderr, - "%s: no reboot record in wtmp file to compute uptime from\n", - prog); - return(1); - } - - printf("\nwtmp begins %.16s \n", ctime(&wtmp_buffer[0].ut_time)); - return(0); -} - diff --git a/commands/poweroff/Makefile b/commands/poweroff/Makefile deleted file mode 100644 index 5af305f79..000000000 --- a/commands/poweroff/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -SCRIPTS= poweroff.sh -MAN= - -.include diff --git a/commands/poweroff/poweroff.sh b/commands/poweroff/poweroff.sh deleted file mode 100644 index 366baac4e..000000000 --- a/commands/poweroff/poweroff.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# poweroff 1.0 - power off the system Author: David van Moolenbroek -# 12 Jun 2009 - -if [ $# -gt 0 ]; then - echo "usage: poweroff" >&2 - exit 1 -fi - -PATH=/usr/bin:$PATH - -exec shutdown -p diff --git a/commands/reboot/Makefile b/commands/reboot/Makefile deleted file mode 100644 index 91c6cee4e..000000000 --- a/commands/reboot/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Makefile for shutdown / halt / reboot. - -PROGS= shutdown halt -SRCS.shutdown= shutdown.c sh_wall.c log.c -SRCS.halt= halt.c log.c -BINDIR=/bin -BINMODE= 4754 -SYMLINKS+= ${BINDIR}/halt ${BINDIR}/reboot -SYMLINKS+= ${BINDIR}/halt /usr/bin/halt -SYMLINKS+= ${BINDIR}/shutdown /usr/bin/shutdown -SYMLINKS+= ${BINDIR}/reboot /usr/bin/reboot -MAN.shutdown= -MAN.halt= - -.include diff --git a/commands/reboot/README b/commands/reboot/README deleted file mode 100644 index 91c378b74..000000000 --- a/commands/reboot/README +++ /dev/null @@ -1,52 +0,0 @@ -This a new implementation of a shutdown procedure. It allows -the system to go down graciously with informing the -users. This package contains 3 programs: - -- halt = Immediately stop the system, no info to users -- shutdown = Inform users, close down the system properly -- wall = Vincent Archer's implementation of wall (Write all) - -Installing - -Shutdown and halt use a new systemcall, which I've added to -MM. Therefor there are several diff's which should be applied: - -callnr.hd - New callnr for reboot(2) - Diff against /usr/include/minix/callnr.h. - Those of you using a symlink package should - change the number and mm/table.c into a free - number. I used 54, LSTAT. -param.hd - Defines reboot_flag as a part of the messages -proto.hd - Add's prototype for do_reboot() -table.cd - Interpretation of the systemcall to MM -mm.cd - I have added the do_reboot code to mm/getset.c but - I couldn't find a getset.c to create a useable diff :-( - So you can add where you want it. It is pure code, no diff. - -Now edit log.c and search for ``host''. Change this into your -systemname or make it empty. - -Shutdown and halt log their actions in /usr/adm/log, edit the -makefile and undefine -DLOG if you don't want this (this at the end of -the makefile). You can change SHUT_LOG in shutdown.c and log.c if you -want it in another file. - -Then type a `make'. This will take a minute or so (13 sec. with bcc :-). -Remember to build a new image and update the ps_database. - -Type `make install' to place the program's where I've got them. -Use them, try them and let me now if you've got problems running -something. - -I have tested to sources both on 16-bits and 32-bits MINIX. I have compiled -it with gcc, bcc and ACK, so that shouldn't really give a problem. Maybe -the standard MINIX-make chokes on the makefile, atleast mine did. - -NOTE: - Make install does not place the man-pages somewhere. You should - do this yourself. - --- -Edvard Tuinder ed@pulstar.NL.mugnet.org v892231@si.hhs.NL -Student Computer Science -Haagse Hogeschool, The Hague, The Netherlands diff --git a/commands/reboot/halt.c b/commands/reboot/halt.c deleted file mode 100644 index a03bbc148..000000000 --- a/commands/reboot/halt.c +++ /dev/null @@ -1,126 +0,0 @@ -/* halt / reboot - halt or reboot system (depends on name) - - halt - calling reboot() with RBT_HALT - reboot - calling reboot() with RBT_REBOOT - - author: Edvard Tuinder v892231@si.hhs.NL - - This program calls the library function reboot(2) which performs - the system-call do_reboot. - - */ - -#define _POSIX_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wtmp.h" - -void write_log( char *fn ); -void usage( void ); -int main( int argc, char *argv[] ); - -char *prog; - -void -usage() -{ - fprintf(stderr, "Usage: %s [-hrRfpd]\n", prog); - exit(1); -} - -int -main(argc,argv) -int argc; -char **argv; -{ - int flag = -1; /* default action unknown */ - int fast = 0; /* fast halt/reboot, don't bother being nice. */ - int i; - struct stat dummy; - pid_t pid; - - if ((prog = strrchr(argv[0],'/')) == NULL) prog = argv[0]; else prog++; - - if (strcmp(prog, "halt") == 0) flag = RBT_HALT; - if (strcmp(prog, "reboot") == 0) flag = RBT_REBOOT; - - i = 1; - while (i < argc && argv[i][0] == '-') { - char *opt = argv[i++] + 1; - - if (*opt == '-' && opt[1] == 0) break; /* -- */ - - while (*opt != 0) switch (*opt++) { - case 'h': flag = RBT_HALT; break; - case 'r': flag = RBT_REBOOT; break; - case 'R': flag = RBT_RESET; break; - case 'd': flag = RBT_DEFAULT; break; - case 'p': flag = RBT_POWEROFF; break; - case 'f': fast = 1; break; - default: - usage(); - } - } - - if (i != argc) usage(); - - if (flag == -1) { - fprintf(stderr, "Don't know what to do when named '%s'\n", prog); - exit(1); - } - - if (stat("/usr/bin", &dummy) < 0) { - /* It seems that /usr isn't present, let's assume "-f." */ - fast = 1; - } - - signal(SIGHUP, SIG_IGN); - signal(SIGTERM, SIG_IGN); - - /* Skip this part for fast shut down. */ - if (! fast) { - /* Run the shutdown scripts. */ - switch ((pid = fork())) { - case -1: - fprintf(stderr, "%s: can't fork(): %s\n", prog, strerror(errno)); - exit(1); - case 0: - execl("/bin/sh", "sh", "/etc/rc", "down", (char *) NULL); - fprintf(stderr, "%s: can't execute: /bin/sh: %s\n", - prog, strerror(errno)); - exit(1); - default: - while (waitpid(pid, NULL, 0) != pid) {} - } - } - - /* Tell init to stop spawning getty's. */ - kill(1, SIGTERM); - - /* Extra sync for the case where SIGTERM causes deadlock */ - sync(); - - /* Give everybody a chance to die peacefully. */ - printf("Sending SIGTERM to all processes ...\n"); - kill(-1, SIGTERM); - sleep(1); - - write_log(STR_WTMP); - write_log(STR_ROOT_WTMP); - - sync(); - - reboot(flag); - fprintf(stderr, "%s: reboot(): %s\n", prog, strerror(errno)); - return 1; -} diff --git a/commands/reboot/log.c b/commands/reboot/log.c deleted file mode 100644 index 53633713d..000000000 --- a/commands/reboot/log.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - log - log the shutdown's and the halt's - - Author: Edvard Tuinder - - 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 -#include -#include -#include -#include -#include -#include -#include -#include - -static char SHUT_LOG[] = "/usr/adm/log"; - -char who[8]; -extern char *prog; -static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -void write_log(char *wtmpfile) -{ - int fd; - static struct utmp wtmp; - static struct passwd *pwd; - char mes[90]; - struct tm *tm; - time_t now; - struct utsname utsname; - char *host = "localhost"; - - time(&now); - tm = localtime(&now); - - if (uname(&utsname) >= 0) host = utsname.nodename; - - pwd = getpwuid(getuid()); - if (pwd == (struct passwd *)0) - strcpy (who,"root"); - else - strcpy (who,pwd->pw_name); - fd = open(wtmpfile,O_APPEND|O_WRONLY|O_CREAT,1); - if (fd) { - if (strcmp(prog,"reboot")) - strcpy (wtmp.ut_name, prog); - else - strcpy (wtmp.ut_name, "shutdown"); /* last ... */ - strcpy (wtmp.ut_id, "~~"); - strcpy (wtmp.ut_line, "~"); - wtmp.ut_pid = 0; - wtmp.ut_type = BOOT_TIME; - wtmp.ut_time = now; - wtmp.ut_host[0]= '\0'; - write (fd, (char *) &wtmp,sizeof(struct utmp)); - close(fd); - } - fd = open(SHUT_LOG,O_APPEND|O_WRONLY,1); - if (!fd) - perror ("open"); - else { - sprintf (mes,"%s %02d %02d:%02d:%02d %s: system %s by %s@%s\n", - month[tm->tm_mon],tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec, - prog,prog,who,host); - write (fd,mes,strlen(mes)); - close(fd); - } - return; -} diff --git a/commands/reboot/sh_wall.c b/commands/reboot/sh_wall.c deleted file mode 100644 index a84019493..000000000 --- a/commands/reboot/sh_wall.c +++ /dev/null @@ -1,109 +0,0 @@ -/* wall - write to all logged in users Author: V. Archer */ -/* - Edvard Tuinder v892231@si.hhs.NL - Modified some things to include this with my shutdown/halt - package - */ - -#define _POSIX_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef UTMP - -static char UTMP[] = "/etc/utmp"; /* Currently logged in users. */ - -void wall( char *when, char *extra ); -void crnlcat( char *message, char *more ); - -void -wall(when, extra) -char *when; /* When is shutdown */ -char *extra; /* If non-nil, why is the shutdown */ -{ - struct utmp utmp; - char utmptty[5 + sizeof(utmp.ut_line) + 2]; - char message[1024]; - struct passwd *pw; - int utmpfd, ttyfd; - char *ourtty, *ourname; - time_t now; - struct utsname utsname; - struct stat con_st, tty_st; - - if ((ourtty = ttyname(1))) { - if ((ourname = strrchr(ourtty, '/'))) ourtty = ourname+1; - } else ourtty = "system task"; - if ((pw = getpwuid(getuid()))) ourname = pw->pw_name; - else ourname = "unknown"; - - time(&now); - if (uname(&utsname) != 0) strcpy(utsname.nodename, "?"); - sprintf(message, "\r\nBroadcast message from %s@%s (%s)\r\n%.24s...\r\n", - ourname, utsname.nodename, ourtty, ctime(&now)); - - crnlcat(message, when); - crnlcat(message, extra); - -/* Search the UTMP database for all logged-in users. */ - - if ((utmpfd = open(UTMP, O_RDONLY)) < 0) { - fprintf(stderr, "Cannot open utmp file\r\n"); - return; - } - - /* first the console */ - strcpy(utmptty, "/dev/console"); - if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) { - perror(utmptty); - } else { - fstat(ttyfd, &con_st); - write(ttyfd, message, strlen(message)); - close(ttyfd); - } - - while (read(utmpfd, (char *) &utmp, sizeof(utmp)) == sizeof(utmp)) { - /* is this the user we are looking for? */ - if (utmp.ut_type != USER_PROCESS) continue; - - strncpy(utmptty+5, utmp.ut_line, sizeof(utmp.ut_line)); - utmptty[5 + sizeof(utmp.ut_line) + 1] = 0; - if ((ttyfd = open(utmptty, O_WRONLY | O_NONBLOCK)) < 0) { - perror(utmptty); - continue; - } - fstat(ttyfd, &tty_st); - if (tty_st.st_rdev != con_st.st_rdev) - write(ttyfd, message, strlen(message)); - close(ttyfd); - } - close(utmpfd); - return; -} - -void -crnlcat(message, more) -char *message, *more; -{ - char *p = message; - char *m = more; - char *end = message + 1024 - 1; - - while (p < end && *p != 0) p++; - - while (p < end && *m != 0) { - if (*m == '\n' && (p == message || p[-1] != '\n')) { - *p++ = '\r'; - if (p == end) p--; - } - *p++ = *m++; - } - *p = 0; -} diff --git a/commands/reboot/shutdown.c b/commands/reboot/shutdown.c deleted file mode 100644 index 972f61804..000000000 --- a/commands/reboot/shutdown.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - shutdown - close down the system graciously - - Author: Edvard Tuinder - - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wtmp.h" - -static char SHUT_PID[] = "/usr/run/shutdown.pid"; -static char NOLOGIN[] = "/etc/nologin"; - -#ifndef __STDC__ -#define inform_user_time inf_time -#define inform_user inf_user -#endif - -void usage( void ); -void write_pid( void ); -int inform_user_time( void ); -void inform_user( void ); -void terminate( void ); -void wall( char *when, char *extra ); -int crash_check( void ); -void parse_time( char *arg ); -void get_message( void ); -int main( int argc, char *argv[] ); -char *itoa( int n ); - -long wait_time=0L; -char message[1024]; -char info[80]; -int reboot_flag='h'; /* default is halt */ -int info_min, info_hour; -char *prog; - -void parse_time (arg) -char *arg; -{ - char *p = arg; - int hours, minutes; - time_t now; - struct tm *tm; - int delta = 0; - int bad = 0; - - if (p[0] == '+') { delta = 1; p++; } - - hours = strtoul(p, &p, 10); - if (*p == 0 && delta) { - minutes = hours; - hours = 0; - } else { - if (*p != ':' && *p != '.') - bad = 1; - else - p++; - minutes = strtoul(p, &p, 10); - if (*p != 0) bad = 1; - } - if (bad) { - fprintf(stderr,"Invalid time specification `%s'\n",arg); - usage(); - } - - time(&now); - tm = localtime(&now); - - if (!delta) { - hours -= tm->tm_hour; - minutes -= tm->tm_min; - } - - if (minutes < 0) { - minutes += 60; - hours--; - } - if (hours < 0) hours += 24; /* Time after midnight. */ - - tm->tm_hour += hours; - tm->tm_min += minutes; - (void) mktime(tm); - info_hour = tm->tm_hour; - info_min = tm->tm_min; - - sprintf(info, - "The system will shutdown in %d hour%s and %d minute%s at %02d:%02d\n\n", - hours,hours==1?"":"s",minutes,minutes==1?"":"s",info_hour,info_min); - - wait_time += hours * 3600 + minutes * 60; - return; -} - -int main(argc,argv) -int argc; -char *argv[]; -{ - int i, now = 0, nologin = 0, want_terminate = 0, want_message = 0, check = 0; - char *opt; - int tty; - static char HALT1[] = "-?"; - static char *HALT[] = { "shutdown", HALT1, NULL }; - - /* Parse options. */ - for (i = 1; i < argc && argv[i][0] == '-'; i++) { - if (argv[i][1] == '-' && argv[i][2] == 0) { - /* -- */ - i++; - break; - } - for (opt = argv[i] + 1; *opt != 0; opt++) { - switch (*opt) { - case 'k': - want_terminate = 1; - break; - case 'h': - case 'r': - case 'p': - case 'd': - case 'R': - reboot_flag = *opt; - break; - case 'm': - want_message = 1; - break; - case 'C': - check = 1; - break; - default: - fprintf (stderr,"shutdown: invalid option '-%c'\n",*opt); - usage(); - break; - } - } - } - if ((argc - i) > 2) usage(); - - if (check) exit(crash_check() ? 0 : 2); - - if (i == argc) { - /* No timespec, assume "now". */ - now = 1; - } else { - if (!strcmp(argv[i], "now")) - now++; - else - parse_time(argv[i]); - } - - if ((argc - i) == 2) { - /* One line message */ - strcat(message, argv[i+1]); - strcat(message, "\n"); - } - - if (want_terminate) terminate(); - if (want_message) get_message(); - - puts(info); - - prog = strrchr(*argv,'/'); - if (prog == (char *)0) - prog = *argv; - else - prog++; - - if (!now) { - /* Daemonize. */ - switch (fork()) { - case 0: - break; - case -1: - fprintf(stderr, "%s: can't fork\n", prog); - exit(1); - default: - exit(0); - } - /* Detach from the terminal (if any). */ - if ((tty = open("/dev/tty", O_RDONLY)) != -1) { - close(tty); - setsid(); - } - write_pid(); - } - - for (;;) { - if (wait_time <= 5 * 60 && !nologin && !now) { - close(creat(NOLOGIN,00644)); - nologin = 1; - } - if (wait_time <= 60) break; - if(inform_user_time()) - inform_user(); - sleep (60); - wait_time -= 60; - } - - if (!now) { - inform_user(); - sleep (30); /* Last minute before shutdown */ - wait_time -= 30; - inform_user(); - sleep (30); /* Last 30 seconds before shutdown */ - } - wait_time = 0; - inform_user(); - - unlink(SHUT_PID); /* No way of stopping anymore */ - unlink(NOLOGIN); - - HALT[1][1] = reboot_flag; -#if __minix_vmd - execv("/usr/sbin/halt", HALT); -#else - execv("/usr/bin/halt", HALT); -#endif - if (errno != ENOENT) - fprintf(stderr, "Can't execute 'halt': %s\n", strerror(errno)); - - sleep(2); - reboot(RBT_HALT); - fprintf(stderr, "Reboot call failed: %s\n", strerror(errno)); - - return(1); -} - -void usage() -{ - fputs("Usage: shutdown [-hrRpmkd] [time [message]]\n", stderr); - fputs(" -h -> halt system after shutdown\n", stderr); - fputs(" -r -> reboot system after shutdown\n", stderr); - fputs(" -R -> reset system after shutdown\n", stderr); - fputs(" -p -> power system off after shutdown\n", stderr); - fputs(" -d -> default CTRL-ALT-DEL shutdown for current bootloader\n", stderr); - fputs(" -m -> read a shutdown message from standard input\n", stderr); - fputs(" -k -> stop an already running shutdown\n", stderr); - fputs(" time -> keyword ``now'', minutes before shutdown ``+5'',\n", stderr); - fputs(" or absolute time specification ``11:20''\n", stderr); - fputs(" message -> short shutdown message\n", stderr); - exit(1); -} - -void terminate() -{ - FILE *in; - pid_t pid; - char c_pid[5]; - - in = fopen(SHUT_PID,"r"); - if (in == (FILE *)0) { - fputs ("Can't get pid of shutdown process, probably not running shutdown\n", stderr); - exit(1); - } - fgets(c_pid,5,in); - fclose(in); - pid = atoi(c_pid); - if (kill(pid,9) == -1) - fputs("Can't kill the shutdown process, probably not running anymore\n",stderr); - else - puts("Shutdown process terminated"); - unlink(SHUT_PID); - unlink(NOLOGIN); - exit(0); -} - -void get_message() -{ - char line[80]; - - puts ("Type your message. End with ^D at an empty line"); - fputs ("shutdown> ",stdout);fflush(stdout); - while (fgets(line,80,stdin) != (char *)0) { - strcat (message,line); - bzero(line,strlen(line)); - fputs ("shutdown> ",stdout);fflush(stdout); - } - putc('\n',stdout);fflush(stdout); -} - -int inform_user_time() -{ - int min; - - min = wait_time /60; - - if (min == 60 || min == 30 || min == 15 || min == 10 || min <= 5) - return 1; - else - return 0; -} - -void inform_user() -{ - int hour, minute; - char mes[80]; - - hour = 0; - minute = wait_time / 60; - while (minute >= 60) { - minute -= 60; - hour++; - } - - if (hour) - sprintf(mes, - "\nThe system will shutdown in %d hour%s and %d minute%s at %.02d:%.02d\n\n", - hour,hour==1?"":"s",minute,minute==1?"":"s",info_hour,info_min); - else - if (minute > 1) - sprintf(mes, - "\nThe system will shutdown in %d minutes at %.02d:%.02d\n\n", - minute,info_hour,info_min); - else - if (wait_time > 1) - sprintf(mes, - "\nThe system will shutdown in %ld seconds\n\n", - wait_time); - else - sprintf(mes, - "\nThe system will shutdown NOW\n\n"); - - wall(mes,message); -} - -void write_pid() -{ - char pid[5]; - int fd; - - fd = creat(SHUT_PID,00600); - if (!fd) - return; - strncpy (pid,itoa(getpid()), sizeof(pid)); - write (fd,pid,sizeof(pid)); - close(fd); - return; -} - -int crash_check() -{ - struct utmp last; - int fd = -1, crashed; - struct stat st; - - if (stat(STR_ROOT_WTMP, &st) < 0 || st.st_size == 0) { - if (stat(STR_WTMP, &st) < 0 || st.st_size == 0) { - return 0; - } - if ((fd = open(STR_WTMP, O_RDONLY)) < 0) return 0; - } else if ((fd = open(STR_ROOT_WTMP, O_RDONLY)) < 0) return 0; - - crashed = (lseek(fd, - (off_t) sizeof(last), SEEK_END) == -1 - || read(fd, (void *) &last, sizeof(last)) != sizeof(last) - || last.ut_line[0] != '~' - || (strncmp(last.ut_name, "shutdown", sizeof(last.ut_name)) - && strncmp(last.ut_name, "halt", sizeof(last.ut_name))) - ); - close(fd); - return crashed; -} diff --git a/commands/reboot/wtmp.h b/commands/reboot/wtmp.h deleted file mode 100644 index 69044ddef..000000000 --- a/commands/reboot/wtmp.h +++ /dev/null @@ -1,3 +0,0 @@ - -static char STR_WTMP[] = "/usr/adm/wtmp"; -static char STR_ROOT_WTMP[] = "/etc/wtmp"; diff --git a/commands/telnetd/Makefile b/commands/telnetd/Makefile index 88168ab6c..55ce0dd2b 100644 --- a/commands/telnetd/Makefile +++ b/commands/telnetd/Makefile @@ -4,7 +4,7 @@ # PROG= in.telnetd -SRCS= main.c telnet.c term.c pty.c wtmp.c +SRCS= main.c telnet.c term.c pty.c MAN= .include diff --git a/commands/telnetd/main.c b/commands/telnetd/main.c index e0bdf4c94..c2f1f623e 100644 --- a/commands/telnetd/main.c +++ b/commands/telnetd/main.c @@ -45,7 +45,6 @@ int opt_d = 0; /* debugging output flag */ void usage(void); int main(int argc, char *argv[]); -void wtmp(int type, int linenr, char *line, pid_t pid, char *host); void usage() { @@ -144,14 +143,10 @@ char *hostname; return(-1); } - wtmp(LOGIN_PROCESS, lineno, tty_name+5, pid, hostname); - term_inout(pty_fd); (void) close(pty_fd); - wtmp(DEAD_PROCESS, lineno, tty_name+5, pid, hostname); - chown(tty_name, 0, 0); chmod(tty_name, 0666); diff --git a/commands/telnetd/wtmp.c b/commands/telnetd/wtmp.c deleted file mode 100644 index 3585e2692..000000000 --- a/commands/telnetd/wtmp.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * TNET A server program for MINIX which implements the TCP/IP - * suite of networking protocols. It is based on the - * TCP/IP code written by Phil Karn et al, as found in - * his NET package for Packet Radio communications. - * - * This file contains an implementation of the "server" - * for the TELNET protocol. This protocol can be used to - * remote-login on other systems, just like a normal TTY - * session. - * - * Usage: telnetd [-dv] - * - * Version: @(#)telnetd.c 1.00 07/26/92 - * - * Author: Fred N. van Kempen, - * Michael Temari, - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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)); -} diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 6f4e38367..f6b1ed75d 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -24,8 +24,8 @@ ./bin/expr minix-sys ./bin/false minix-sys ./bin/getopts minix-sys -./bin/getty minix-sys -./bin/halt minix-sys +./bin/getty minix-sys obsolete +./bin/halt minix-sys obsolete ./bin/intr minix-sys ./bin/kill minix-sys ./bin/ksh minix-sys @@ -42,14 +42,14 @@ ./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 @@ -117,6 +117,8 @@ ./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 @@ -146,6 +148,8 @@ ./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 @@ -155,8 +159,11 @@ ./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 @@ -336,7 +343,7 @@ ./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 @@ -437,7 +444,7 @@ ./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 @@ -456,8 +463,8 @@ ./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 @@ -479,7 +486,7 @@ ./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 @@ -540,8 +547,8 @@ ./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 @@ -552,6 +559,7 @@ ./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 @@ -1201,7 +1209,7 @@ ./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 @@ -1938,6 +1946,7 @@ ./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 @@ -2282,6 +2291,7 @@ ./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 @@ -4696,6 +4706,7 @@ ./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 @@ -4724,6 +4735,7 @@ ./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 @@ -4863,7 +4875,7 @@ ./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 diff --git a/drivers/tps65217/tps65217.c b/drivers/tps65217/tps65217.c index 87d1046d5..787954f60 100644 --- a/drivers/tps65217/tps65217.c +++ b/drivers/tps65217/tps65217.c @@ -3,7 +3,8 @@ #include #include #include -#include + +#include /* Register Addresses */ #define CHIPID_REG 0x00 @@ -155,7 +156,7 @@ enable_pwr_off(void) /* enable power off via the PWR_EN pin. just do the setup here. * the kernel will do the work to toggle the pin when the * system is ready to be powered off. Should be called during startup - * so that shutdown(8) can do power-off with reboot(RBT_POWEROFF). + * so that shutdown(8) can do power-off with reboot(). */ r = i2creg_write8(bus_endpoint, address, STATUS_REG, PWR_OFF_MASK); if (r != OK) { @@ -228,10 +229,8 @@ intr_handler(void) if ((val & PBI_MASK) != 0) { log_info(&log, "Power Button Pressed\n"); - reboot(RBT_POWEROFF); - log_warn(&log, "Failed to power off the system."); - sys_irqenable(&irq_hook_kernel_id); - return -1; + kill(1, SIGUSR1); /* tell init to powerdwn */ + return OK; } /* re-enable interrupt */ diff --git a/drivers/tty/arch/i386/keyboard.c b/drivers/tty/arch/i386/keyboard.c index 4f03efc84..30985ddc2 100644 --- a/drivers/tty/arch/i386/keyboard.c +++ b/drivers/tty/arch/i386/keyboard.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include #include #include "tty.h" @@ -295,7 +295,7 @@ static unsigned make_break(int scode) { if (++CAD_count == 3) { cons_stop(); - sys_abort(RBT_DEFAULT); + sys_abort(RB_AUTOBOOT); } sys_kill(INIT_PROC_NR, SIGABRT); rebooting = 1; diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index db3981068..793e61a2e 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -700,6 +700,10 @@ static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, if (isconsole(tp)) r = con_loadfont(endpt, grant); break; + case TIOCSCTTY: + tp->tty_pgrp = user_endpt; + break; + /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is * not defined. */ diff --git a/etc/Makefile b/etc/Makefile index 11f38be7c..08cb513bf 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -97,7 +97,7 @@ BIN1+= boot.cfg.default \ protocols rc rc.cd rc.subr \ rc.daemons.dist rs.inet rs.single \ services shells syslog.conf \ - termcap utmp + termcap utmp gettytab rc.shutdown .else BIN1+= bootptab changelist csh.cshrc csh.login \ csh.logout daily daily.conf dm.conf envsys.conf floppytab ftpchroot \ diff --git a/etc/gettytab b/etc/gettytab new file mode 100644 index 000000000..111ba33b3 --- /dev/null +++ b/etc/gettytab @@ -0,0 +1,154 @@ +# $NetBSD: gettytab,v 1.18 2006/01/08 22:23:46 dsl Exp $ +# from: @(#)gettytab 8.2 (Berkeley) 4/20/94 +# +# Most of the table entries here are just copies of the old getty table, +# it is by no means certain, or even likely, that any of them are optimal +# for any purpose whatever. Nor is it likely that more than a couple are +# even correct. +# +# The default gettytab entry, used to set defaults for all other +# entries, and in cases where getty is called with no table name +# +default:\ + :ce:ck:np:im=\r\n%s/%m (%h) (%t)\r\n\r\n: + +# +# Fixed speed entries +# +# The "std.NNN" names are known to the special case +# portselector code in getty, however they can +# be assigned to any table desired. +# The "NNN-baud" names are known to the special case +# autobaud code in getty, and likewise can +# be assigned to any table desired (hopefully the same speed). +# +std.110|110-baud:\ + :sp#110: +std.300|300-baud:\ + :sp#300: +std.600|600-baud:\ + :sp#600: +std.1200|1200-baud:\ + :sp#1200: +std.2400|2400-baud:\ + :sp#2400: +std.4800|4800-baud:\ + :sp#4800: +std.9600|9600-baud:\ + :sp#9600: +std.19200|19200-baud:\ + :sp#19200: +std.38400|38400-baud:\ + :sp#38400: +std.57600|57600-baud:\ + :sp#57600: +std.115200|115200-baud:\ + :sp#115200: + +# PPP network link login +# +# these entries can be used by ISPs or others who want to be able +# to offer both a "shell" and a PPP login on the same port. Setting +# the "pp" attribute allows getty(8) to recognize a PPP link start +# negotiation, and invoke the program listed, in addition to normal +# login(1). +# +# N.B.: if PPP is recognized, this bypasses normal login/password +# exchange; the expectation is that you'll configure pppd (or whatever) +# to require a PAP or CHAP handshake for authentication after PPP is +# started up. +# +# It is also recommended that you use hardware (CTS/RTS) flow control +# on the port, and run the port as fast as possible, to allow modems +# extra time to do data compression, if enabled. +# +ppp:np:ce:ck:pp=/usr/sbin/pppd: +# +ppp.19200|PPP-19200:sp#19200:tc=ppp: +ppp.38400|PPP-38400:sp#38400:tc=ppp: +ppp.57600|PPP-57600:sp#57600:tc=ppp: +ppp.115200|PPP-115200:sp#115200:tc=ppp: +ppp.230400|PPP-230400:sp#230400:tc=ppp: + +# +# Dial in rotary tables, speed selection via 'break' +# +d1200|Dial-1200:\ + :nx=d300:sp#1200: +d300|Dial-300:\ + :nx=d1200:sp#300: + +# +# Fast dialup terminals, 2400/1200/300 rotary (can start either way) +# +D2400|d2400|Fast-Dial-2400:\ + :nx=D1200:tc=2400-baud: +D1200|Fast-Dial-1200:\ + :nx=D300:tc=1200-baud: +D300|Fast-Dial-300:\ + :nx=D2400:tc=300-baud: + +# +#telebit (19200) +# +t19200:\ + :nx=t2400:tc=19200-baud: +t2400:\ + :nx=t1200:tc=2400-baud: +t1200:\ + :nx=t19200:tc=1200-baud: + +# +#telebit (9600) +# +t9600:\ + :nx=t2400a:tc=19200-baud: +t2400a:\ + :nx=t1200a:tc=2400-baud: +t1200a:\ + :nx=t9600:tc=1200-baud: + +# +# Odd special case terminals +# +Console|Console Decwriter II:\ + :rw:tc=300-baud: + +Console-1200|Console Decwriter III:\ + :rw:tc=1200-baud: + +X|Xwindow|X window system:\ + :rw:sp#9600: + +Pc|Pc console:\ + :np:ig:ht: + +# 8 bit clean Sun console +suncons|Sun Console:\ + :np:sp#9600: + +# +# Plugboard, and misc other terminals +# +plug-9600|Plugboard-9600:\ + :pf#1:tc=9600-baud: +P9600|Plugboard-9600-rotary:\ + :pf#1:nx=P300:tc=9600-baud: +P300|Plugboard-300:\ + :pf#1:nx=P1200:tc=300-baud: +P1200|Plugboard-1200:\ + :pf#1:nx=P9600:tc=1200-baud: + +# +# XXXX Port selector +# +DSW|Port Selector:\ + :ps:sp#2400: + +# +# Auto-baud speed detect entry for Micom 600. +# Special code in getty will switch this out +# to one of the NNN-baud entries. +# +Auto-baud:\ + :ab:sp#2400:f0#040: diff --git a/etc/rc b/etc/rc index 587c6ef73..58a5f48d6 100755 --- a/etc/rc +++ b/etc/rc @@ -21,7 +21,7 @@ ARCH="`sysenv arch`" usage() { - echo >&2 "Usage: $0 [-saf] start|stop|down" + echo >&2 "Usage: $0 [-saf] autoboot|start|stop|down" exec intr sh } @@ -54,8 +54,12 @@ edit() service=$1 shift - # Assume binaries are always in /usr/sbin - service $opt edit /usr/sbin/$service -label $service "$@" + # Assume binaries are always in /sbin or /usr/sbin + binlocation=/usr/sbin/$service + if [ ! -x $binlocation ] + then binlocation=/sbin/$service + fi + service $opt edit $binlocation -label $service "$@" } while getopts 'saf' opt @@ -70,14 +74,14 @@ done shift `expr $OPTIND - 1` case "$#:$1" in -1:start|1:stop|1:down) +1:start|1:stop|1:down|1:autoboot) action=$1 ;; *) usage esac case $action in -start) +autoboot|start) # National keyboard? test -f /etc/keymap && loadkeys /etc/keymap @@ -104,8 +108,12 @@ start) up readclock.drv readclock -q || date 201301010000 + # We are not shutting down. + rm -f /etc/nologin + # Initialize files. - >/etc/utmp # /etc/utmp keeps track of logins + >/var/run/utmp # /etc/utmp keeps track of logins + >/var/run/utmpx # /etc/utmpx keeps track of logins # Use MFS binary only from kernel image? if [ "`sysenv bin_img`" = 1 ] @@ -147,10 +155,6 @@ start) edit init fi - # This file is necessary for above 'shutdown -C' check. - # (Silence stderr in case of running from cd.) - touch /usr/adm/wtmp /etc/wtmp 2>/dev/null - if [ "$sflag" ] then echo "Single user. Press ^D to resume multiuser startup." @@ -212,6 +216,10 @@ test -f /usr/etc/rc && sh /usr/etc/rc $action test -f /usr/local/etc/rc && sh /usr/local/etc/rc $action # Any messages? -test "$action" = start -a -f /etc/issue && cat /etc/issue +if [ "$action" = start -o "$action" = autoboot ] +then if [ -f /etc/issue ] + then cat /etc/issue + fi +fi exit 0 diff --git a/etc/rc.shutdown b/etc/rc.shutdown new file mode 100644 index 000000000..9b5e85c71 --- /dev/null +++ b/etc/rc.shutdown @@ -0,0 +1,3 @@ +#!/bin/sh + +sh /etc/rc stop diff --git a/etc/system.conf b/etc/system.conf index 8b248ff53..8e0cb3455 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -638,7 +638,7 @@ service tda19988 service tps65217 { - uid 0; # needed for doing reboot(RBT_POWEROFF) + uid 0; # needed for doing reboot() system IRQCTL PRIVCTL; irq 7; # NNMI pin on BeagleBone / BeagleBone Black ipc SYSTEM RS DS PM i2c; diff --git a/etc/ttys b/etc/ttys index 83ee4b48b..7f6c86a15 100755 --- a/etc/ttys +++ b/etc/ttys @@ -3,10 +3,10 @@ # # name getty type status comments # -console getty minix on secure -ttyc1 getty minix on secure -ttyc2 getty minix on secure -ttyc3 getty minix on secure +console "/usr/libexec/getty default" minix on secure +ttyc1 "/usr/libexec/getty default" minix on secure +ttyc2 "/usr/libexec/getty default" minix on secure +ttyc3 "/usr/libexec/getty default" minix on secure tty00 "" unknown off secure tty01 "" unknown off secure diff --git a/etc/usr/rc b/etc/usr/rc index 4b19e611e..2090c0eba 100644 --- a/etc/usr/rc +++ b/etc/usr/rc @@ -25,10 +25,13 @@ fi bootcd="`/bin/sysenv bootcd`" case "$#:$1" in +1:autoboot) + action=start + ;; 1:start|1:stop|1:down) action=$1 ;; -*) echo >&2 "Usage: $0 start|stop|down" +*) echo >&2 "Usage: $0 autoboot|start|stop|down" exit 1 esac @@ -158,7 +161,7 @@ capemgr() { DAEMONS=/etc/rc.daemons case $action in -start) +start|autoboot) # Select console font. test -f /etc/font && loadfont /etc/font #include -#include #include +#include + #include #include "archconst.h" @@ -51,25 +52,23 @@ poweroff(void) __dead void arch_shutdown(int how) { - switch (how) { - case RBT_HALT: - /* Hang */ - for (; ; ) halt_cpu(); - NOT_REACHABLE; - case RBT_POWEROFF: + if((how & RB_POWERDOWN) == RB_POWERDOWN) { /* Power off if possible, hang otherwise */ poweroff(); NOT_REACHABLE; + } - default: - case RBT_DEFAULT: - case RBT_REBOOT: - case RBT_RESET: - /* Reset the system */ - reset(); + if(how & RB_HALT) { + /* Hang */ + for (; ; ) halt_cpu(); NOT_REACHABLE; } + + /* Reset the system */ + reset(); + NOT_REACHABLE; + while (1); } diff --git a/kernel/arch/earm/pre_init.c b/kernel/arch/earm/pre_init.c index c9909017c..1c8646761 100644 --- a/kernel/arch/earm/pre_init.c +++ b/kernel/arch/earm/pre_init.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "string.h" #include "arch_proto.h" #include "direct_utils.h" @@ -412,7 +412,7 @@ kinfo_t *pre_init(int argc, char **argv) * longer used and the "real" implementations are visible */ void send_diag_sig(void) { } -void minix_shutdown(minix_timer_t *t) { arch_shutdown(RBT_PANIC); } +void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); } void busy_delay_ms(int x) { } int raise(int n) { panic("raise(%d)\n", n); } int kern_phys_map_ptr( phys_bytes base_address, vir_bytes io_size, diff --git a/kernel/arch/i386/arch_reset.c b/kernel/arch/i386/arch_reset.c index 0fd32770d..855bd36f2 100644 --- a/kernel/arch/i386/arch_reset.c +++ b/kernel/arch/i386/arch_reset.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -134,30 +134,24 @@ __dead void arch_shutdown(int how) ; reset(); } - - 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_POWERDOWN) == RB_POWERDOWN) { + /* Power off if possible, hang otherwise */ + poweroff(); + 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; } diff --git a/kernel/arch/i386/pre_init.c b/kernel/arch/i386/pre_init.c index 165e6d57b..05801f2be 100644 --- a/kernel/arch/i386/pre_init.c +++ b/kernel/arch/i386/pre_init.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "string.h" #include "arch_proto.h" @@ -246,6 +246,6 @@ kinfo_t *pre_init(u32_t magic, u32_t ebx) } void send_diag_sig(void) { } -void minix_shutdown(minix_timer_t *t) { arch_shutdown(RBT_PANIC); } +void minix_shutdown(minix_timer_t *t) { arch_shutdown(0); } void busy_delay_ms(int x) { } int raise(int sig) { panic("raise(%d)\n", sig); } diff --git a/kernel/main.c b/kernel/main.c index d8e3bdf6b..f309ea6f8 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "clock.h" #include "direct_utils.h" #include "hw_intr.h" @@ -357,8 +357,7 @@ void prepare_shutdown(const int how) void minix_shutdown(minix_timer_t *tp) { /* This function is called from prepare_shutdown or stop_sequence to bring - * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the - * monitor), RBT_RESET (hard reset). + * down MINIX. */ int how; @@ -376,25 +375,17 @@ void minix_shutdown(minix_timer_t *tp) hw_intr_disable_all(); stop_local_timer(); - how = tp ? tmr_arg(tp)->ta_int : RBT_PANIC; + how = tp ? tmr_arg(tp)->ta_int : 0; /* Show shutdown message */ direct_cls(); - switch(how) { - case RBT_HALT: + if((how & RB_POWERDOWN) == RB_POWERDOWN) + direct_print("MINIX has halted and will now power off.\n"); + else if(how & RB_HALT) direct_print("MINIX has halted. " "It is safe to turn off your computer.\n"); - break; - case RBT_POWEROFF: - direct_print("MINIX has halted and will now power off.\n"); - break; - case RBT_DEFAULT: - case RBT_REBOOT: - case RBT_RESET: - default: + else direct_print("MINIX will now reset.\n"); - break; - } arch_shutdown(how); } diff --git a/lib/libc/gen/utmpx.c b/lib/libc/gen/utmpx.c index deab17dec..d3f3594d4 100644 --- a/lib/libc/gen/utmpx.c +++ b/lib/libc/gen/utmpx.c @@ -355,20 +355,14 @@ updwtmpx(const char *file, const struct utmpx *utx) #else if ((fd = open(file, O_CREAT|O_WRONLY, 0644)) < 0) return -1; - if (flock(fd, LOCK_EX) < 0) - return -1; #endif (void)memset(&ut, 0, sizeof(ut)); ut.ut_type = SIGNATURE; (void)memcpy(ut.ut_user, vers, sizeof(vers)); if (write(fd, &ut, sizeof(ut)) == -1) goto failed; - } else { -#ifdef __minix - if (flock(fd, LOCK_SH) < 0 ) - return -1; -#endif } + if (write(fd, utx, sizeof(*utx)) == -1) goto failed; if (close(fd) == -1) @@ -455,10 +449,6 @@ getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) if (db == NULL) return NULL; -#ifdef __minix - if (flock(db->fd(db), LOCK_SH) < 0) - return NULL; -#endif key.data = &uid; key.size = sizeof(uid); @@ -503,10 +493,6 @@ updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) if (db == NULL) return -1; -#ifdef __minix - if (flock(db->fd(db), LOCK_EX) < 0) - return -1; -#endif key.data = &uid; key.size = sizeof(uid); data.data = ll; diff --git a/lib/libc/sys-minix/reboot.c b/lib/libc/sys-minix/reboot.c index 9e292cd6f..08a503e92 100644 --- a/lib/libc/sys-minix/reboot.c +++ b/lib/libc/sys-minix/reboot.c @@ -11,7 +11,7 @@ #include #include -int reboot(int how) +int reboot(int how, char *bootstr) { message m; diff --git a/lib/libc/sys-minix/stack_utils.c b/lib/libc/sys-minix/stack_utils.c index ef3807889..50774e294 100644 --- a/lib/libc/sys-minix/stack_utils.c +++ b/lib/libc/sys-minix/stack_utils.c @@ -99,7 +99,7 @@ void minix_stack_params(const char *path, char * const *argv, char * const *envp (*argc)++; } - for (p = envp; *p != NULL; p++) { + for (p = envp; p && *p != NULL; p++) { size_t const n = sizeof(*p) + strlen(*p) + 1; *stack_size += n; if (*stack_size < n) { @@ -156,7 +156,7 @@ void minix_stack_fill(const char *path, int argc, char * const *argv, } *fpw++ = NULL; - for (p = envp; *p != NULL; p++) { + for (p = envp; p && *p != NULL; p++) { size_t const n = strlen(*p) + 1; *fpw++= (char *)(*vsp + (fp - frame)); memcpy(fp, *p, n); diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 9e5554b4c..a78e87652 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -244,7 +244,7 @@ MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \ mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \ munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2 .else -MAN+= adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2 +MAN+= adjtime.2 clock_settime.2 getvfsstat.2 pipe.2 getrusage.2 reboot.2 .endif # !defined(__MINIX) .if !defined(__MINIX) MAN+= pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \ diff --git a/lib/libminc/Makefile b/lib/libminc/Makefile index 0fa147ab5..a049890a0 100644 --- a/lib/libminc/Makefile +++ b/lib/libminc/Makefile @@ -146,10 +146,11 @@ CPPFLAGS.${i}+= -I${LIBCDIR}/locale .for i in access.c brk.c close.c environ.c execve.c fork.c fsync.c \ getgid.c getpid.c geteuid.c getuid.c gettimeofday.c getvfsstat.c \ init.c link.c loadname.c lseek.c lseek64.c _mcontext.c mknod.c \ - mmap.c nanosleep.c open.c pread.c pwrite.c read.c reboot.c sbrk.c \ + mmap.c nanosleep.c open.c pread.c pwrite.c read.c sbrk.c \ select.c setuid.c sigprocmask.c stack_utils.c stat.c stime.c \ syscall.c _ucontext.c umask.c unlink.c waitpid.c write.c \ - brksize.S _do_kernel_call_intr.S get_minix_kerninfo.S _ipc.S ucontext.S + brksize.S _do_kernel_call_intr.S get_minix_kerninfo.S _ipc.S ucontext.S \ + kill.c .PATH.c: ${LIBCDIR}/sys-minix .PATH.S: ${ARCHDIR}/sys-minix SRCS+= ${i} diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 8994b79aa..16898a348 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -42,7 +42,7 @@ SRCS+= efun.c \ passwd.c pw_scan.c pidfile.c pidlock.c pty.c \ raise_default_signal.c \ secure_path.c stat_flags.c \ - strpct.c ttyaction.c \ + strpct.c ttyaction.c ttymsg.c \ MAN= efun.3 \ getmntopts.3 \ diff --git a/libexec/Makefile b/libexec/Makefile index 6017ec658..13f54a339 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -5,7 +5,8 @@ SUBDIR= \ fingerd ftpd \ - ld.elf_so + ld.elf_so \ + getty .if defined(__MINIX) SUBDIR+= makewhatis diff --git a/libexec/getty/Makefile b/libexec/getty/Makefile new file mode 100644 index 000000000..6f0be0491 --- /dev/null +++ b/libexec/getty/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.19 2010/02/03 15:34:43 roy Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/4/93 + +WARNS?= 2 # XXX: many const & sign-compare issues + +PROG= getty +SRCS= main.c init.c subr.c +DPADD+= ${LIBUTIL} ${LIBTERMINFO} +LDADD+= -lutil -lterminfo +MAN= getty.8 gettytab.5 ttys.5 + +.include diff --git a/libexec/getty/extern.h b/libexec/getty/extern.h new file mode 100644 index 000000000..e0eb4afb1 --- /dev/null +++ b/libexec/getty/extern.h @@ -0,0 +1,52 @@ +/* $NetBSD: extern.h,v 1.6 2003/08/07 09:46:41 agc Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)extern.h 8.1 (Berkeley) 6/4/93 + */ + +struct delayval; + +int adelay(int, struct delayval *); +char *autobaud(void); +int delaybits(void); +void edithost(char *); +void gendefaults(void); +int getent(char *, char *); +int getflag(char *); +long getnum(char *); +char *getstr(char *, char **); +void gettable(char *, char *); +void makeenv(char *[]); +char *portselector(void); +void set_ttydefaults(int); +void setchars(void); +void setdefaults(void); +void setflags(int); +int speed(int); diff --git a/libexec/getty/getty.8 b/libexec/getty/getty.8 new file mode 100644 index 000000000..16d8d968c --- /dev/null +++ b/libexec/getty/getty.8 @@ -0,0 +1,177 @@ +.\" $NetBSD: getty.8,v 1.17 2003/08/07 09:46:42 agc Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93 +.\" +.Dd December 12, 1998 +.Dt GETTY 8 +.Os +.Sh NAME +.Nm getty , +.Nm uugetty +.Nd set terminal modes for system access +.Sh SYNOPSIS +.Nm +.Oo +.Ar type +.Op Ar tty +.Oc +.Nm uugetty +.Oo +.Ar type +.Op Ar tty +.Oc +.Sh DESCRIPTION +The +.Nm +program +is called by +.Xr init 8 +to open and initialize the tty line, read a login name, and invoke +.Xr login 1 . +The devices on which to run +.Nm +are normally determined by +.Xr ttys 5 . +.Pp +The +.Nm +program can also recognize a Point to Point Protocol +.Pq Tn PPP +negotiation, and, if the +.Sy pp +attribute in +.Xr gettytab 5 +is set, invoke the program given by that string, e.g., +.Xr pppd 8 , +instead of +.Xr login 1 . +This makes it possible to use a single serial port for either a +.Qq shell +account with command line interface, or a +.Tn PPP +network link. +.Pp +The argument +.Ar tty +is the special device file in +.Pa /dev +to open for the terminal +.Po +for example, +.Qq ttyh0 +.Pc . +If there is no argument or the argument is +.Ql Fl , +the tty line is assumed to be open as file descriptor 0. +.Pp +The +.Ar type +argument can be used to make +.Nm +treat the terminal line specially. +This argument is used as an index into the +.Xr gettytab 5 +database, to determine the characteristics of the line. +If there is no argument, or there is no such table, the +.Em default +table is used. +If there is no +.Pa /etc/gettytab +a set of system defaults is used. +If indicated by the table located, +.Nm +will clear the terminal screen, +print a banner heading, +and prompt for a login name. +Usually either the banner or the login prompt will include +the system hostname. +.Pp +.Nm +uses the +.Xr ttyaction 3 +facility with an action of +.Qq getty +and user +.Qq root +to execute site-specific commands when it starts. +.Pp +Most of the default actions of +.Nm +can be circumvented, or modified, by a suitable +.Xr gettytab 5 +table. +.Pp +The +.Nm +program can be set to timeout after some interval, +which will cause dial up lines to hang up +if the login name is not entered reasonably quickly. +.Pp +The +.Nm uugetty +program is the same, except that it uses +.Xr pidlock 3 +to respect the locks in +.Pa /var/spool/lock +of processes that dial out on that tty. +.Sh FILES +.Bl -tag -width /var/spool/lock/LCK..ttyXX -compact +.It Pa /etc/gettytab +.It Pa /etc/ttys +.It Pa /var/spool/lock/LCK..ttyXX +.El +.Sh DIAGNOSTICS +.Bl -diag +.It "ttyxx: No such device or address." +.It "ttyxx: No such file or address." +A terminal which is turned on in the +.Xr ttys 5 +file cannot be opened, likely because the requisite +lines are either not configured into the system, the associated device +was not attached during boot-time system configuration, +or the special file in +.Pa /dev +does not exist. +.El +.Sh SEE ALSO +.Xr login 1 , +.Xr ioctl 2 , +.Xr pidlock 3 , +.Xr ttyaction 3 , +.Xr tty 4 , +.Xr gettytab 5 , +.Xr ttys 5 , +.Xr init 8 , +.Xr pppd 8 +.Sh HISTORY +A +.Nm +program appeared in +.At v6 . diff --git a/libexec/getty/gettytab.5 b/libexec/getty/gettytab.5 new file mode 100644 index 000000000..f2e7bde3c --- /dev/null +++ b/libexec/getty/gettytab.5 @@ -0,0 +1,423 @@ +.\" $NetBSD: gettytab.5,v 1.36 2012/04/21 12:27:28 roy Exp $ +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)gettytab.5 8.4 (Berkeley) 4/19/94 +.\" +.Dd April 5, 2012 +.Dt GETTYTAB 5 +.Os +.Sh NAME +.Nm gettytab +.Nd terminal configuration data base +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +The +.Nm +file +is a simplified version of the +.Xr capfile 5 +data base +used to describe terminal lines. +The initial terminal login process +.Xr getty 8 +accesses the +.Nm +file each time it starts, allowing simpler +reconfiguration of terminal characteristics. +Each entry in the data base +is used to describe one class of terminals. +.Pp +Where to run +.Xr getty 8 +processes is normally defined by +.Xr ttys 5 . +.Pp +There is a default terminal class, +.Em default , +that is used to set global defaults for all other classes. +(That is, the +.Em default +entry is read, then the entry for the class required +is used to override particular settings.) +The +.Em default +entry is also normally read by other programs that present login prompts +to the user, such as +.Xr telnetd 8 , +in order to retrieve the values of the +.Em he , +.Em hn , +.Em im , +and +.Em if +capabilities. +.Sh CAPABILITIES +Refer to +.Xr capfile 5 +for a description of the file layout. +The +.Em default +column below lists defaults obtained if there is +no entry in the table obtained, nor one in the special +.Em default +table. +.Bl -column Namexx /usr/bin/login Default +.It Sy Name Type Default Description +.It "ab bool false Auto-baud speed select mechanism for the Micom 600 portselector. Selection is done by looking at how the character `\er' is garbled at 300, 1200, 4800, and 9600 baud." +.It "al str NULL user to auto-login instead of prompting" +.It "ap bool false terminal uses any parity" +.It "bk str 0377 alternative end of line character (input break)" +.It "b2 str 0377 alternative end of line character (input break)" +.It "c0 num unused tty control flags to write messages" +.It "c1 num unused tty control flags to read login name" +.It "c2 num unused tty control flags to leave terminal as" +.It "ce bool false use crt erase algorithm" +.It "ck bool false use crt kill algorithm" +.It "cl str" Ta Dv NULL Ta +.No "screen clear sequence" +.It "co bool false console - add" +.Ql \er\en +after login prompt +.It "cs bool false clear screen based on terminal type in /etc/ttys" +.It "ds str" Ta So Li ^Y Sc Ta +.No "delayed suspend character" +.It "dx bool false set" +.Dv DECCTLQ +.It "ec bool false leave echo" +.Tn OFF +.It "ep bool false terminal uses even parity" +.It "er str" Ta So Li ^? Sc Ta +.No "erase character" +.It "et str" Ta So Li ^D Sc Ta +.No "end of text" +.Pq Dv EOF +character +.It "ev str" Ta Dv NULL Ta +.No "initial environment" +.It "f0 num unused tty mode flags to write messages" +.It "f1 num unused tty mode flags to read login name" +.It "f2 num unused tty mode flags to leave terminal as" +.It "fl str" Ta So Li ^O Sc Ta +.No "output flush character" +.It "hc bool false do" +.Tn NOT +hangup line on last close +.It "he str" Ta Dv NULL Ta +.No "hostname editing string" +.It "hn str hostname hostname" +.It "ht bool false terminal has real tabs" +.It "i0 num unused tty input flags to write messages" +.It "i1 num unused tty input flags to read login name" +.It "i2 num unused tty input flags to leave terminal as" +.It "if str NULL display named file before prompt, like /etc/issue" +.It "ig bool false ignore garbage characters in login name" +.It "im str" Ta Dv NULL Ta +.No "initial (banner) message" +.It "in str" Ta So Li ^C Sc Ta +.No "interrupt character" +.It "is num unused input speed" +.It "kl str" Ta So Li ^U Sc Ta +.No "kill character" +.It "l0 num unused tty local flags to write messages" +.It "l1 num unused tty local flags to read login name" +.It "l2 num unused tty local flags to leave terminal as" +.It "lc bool false terminal has lower case" +.It "lm str login: login prompt" +.It "ln str" Ta So Li ^V Sc Ta +.No "``literal next'' character" +.It "lo str" Ta Pa /usr/bin/login Ta +.No "program to exec when name obtained" +.It "mb bool false do flow control based on carrier" +.It "nl bool false terminal has (or might have) a newline character" +.It "nn bool false do not prompt for a login name" +.It "np bool false terminal uses no parity (i.e. 8-bit characters)" +.It "nx str default next table (for auto speed selection)" +.It "o0 num unused tty output flags to write messages" +.It "o1 num unused tty output flags to read login name" +.It "o2 num unused tty output flags to leave terminal as" +.It "op bool false terminal uses odd parity" +.It "os num unused output speed" +.It "pc str" Ta So Li \e0 Sc Ta +.No "pad character" +.It "pe bool false use printer (hard copy) erase algorithm" +.It "pf num 0 delay" +between first prompt and following flush (seconds) +.It "pp str unused PPP authentication program" +.It "ps bool false line connected to a" +.Tn MICOM +port selector +.It "qu str" Ta So Li \&^\e Sc Ta +.No "quit character" +.It "rp str" Ta So Li ^R Sc Ta +.No "line retype character" +.It "rw bool false do" +.Tn NOT +use raw for input, use cbreak +.It "sp num unused line speed (input and output)" +.It "st str" Ta So Li ^T Sc Ta +.No "status character" +.It "su str" Ta So Li ^Z Sc Ta +.No "suspend character" +.It "tc str none table continuation" +.It "to num 0 timeout (seconds)" +.It "tt str" Ta Dv NULL Ta +.No "terminal type (for environment)" +.It "ub bool false do unbuffered output (of prompts etc)" +.It "we str" Ta So Li ^W Sc Ta +.No "word erase character" +.It "xc bool false do" +.Tn NOT +echo control chars as +.Ql ^X +.It "xf str" Ta So Li ^S Sc Ta Dv XOFF +(stop output) character +.It "xn str" Ta So Li ^Q Sc Ta Dv XON +(start output) character +.El +.Pp +The following capabilities are no longer supported by +.Xr getty 8 : +.Bl -column Namexx /usr/bin/login Default +.It "bd num 0 backspace delay" +.It "cb bool false use crt backspace mode" +.It "cd num 0 carriage-return delay" +.It "fd num 0 form-feed (vertical motion) delay" +.It "nd num 0 newline (line-feed) delay" +.It "uc bool false terminal is known upper case only" +.El +.Pp +If no line speed is specified, speed will not be altered +from that which prevails when getty is entered. +Specifying an input or output speed will override +line speed for stated direction only. +.Pp +Terminal modes to be used for the output of the message, +for input of the login name, +and to leave the terminal set as upon completion, +are derived from the boolean flags specified. +If the derivation should prove inadequate, +any (or all) of these three may be overridden +with one of the +.Em \&c0 , +.Em \&c1 , +.Em \&c2 , +.Em \&i0 , +.Em \&i1 , +.Em \&i2 , +.Em \&l0 , +.Em \&l1 , +.Em \&l2 , +.Em \&o0 , +.Em \&o1 , +or +.Em \&o2 +numeric specifications, which can be used to specify +(usually in octal, with a leading '0') +the exact values of the flags. +These flags correspond to the termios +.Em c_cflag , +.Em c_iflag , +.Em c_lflag , +and +.Em c_oflag +fields, respectively. +Each these sets must be completely specified to be effective. +The +.Em \&f0 , +.Em \&f1 , +and +.Em \&f2 +are excepted for backwards compatibility with a previous incarnation of +the TTY sub-system. +In these flags the bottom 16 bits of the (32 bits) value contain the sgttyb +.Em sg_flags +field, while the top 16 bits represent the local mode word. +.Pp +Should +.Xr getty 8 +receive a null character +(presumed to indicate a line break) +it will restart using the table indicated by the +.Em nx +entry. +If there is none, it will re-use its original table. +.Pp +Delays are specified in milliseconds, the nearest possible +delay available in the tty driver will be used. +Should greater certainty be desired, delays +with values 0, 1, 2, and 3 are interpreted as +choosing that particular delay algorithm from the driver. +.Pp +The +.Em \&cl +screen clear string may be preceded by a (decimal) number +of milliseconds of delay required (a la termcap). +This delay is simulated by repeated use of the pad character +.Em \&pc . +.Pp +The initial message, and login message, +.Em \&im +and +.Em \&lm +may include any of the following character sequences, which expand to +information about the environment in which +.Xr getty 8 +is running. +.Pp +.Bl -tag -width \&%xxx -compact +.It \&%d +The current date. +.It \&%h +The hostname of the machine, which is normally obtained from the +system using +.Xr gethostname 3 , +but may also be overridden by the +.Em \&hn +table entry. +In either case it may be edited with the +.Em \&he +string. +A '@' in the +.Em \&he +string causes one character from the real hostname to +be copied to the final hostname. +A '#' in the +.Em \&he +string causes the next character of the real hostname +to be skipped. +Each character that +is neither '@' nor '#' is copied into the final hostname. +Surplus '@' and '#' characters are ignored. +.It \&%t +The tty name. +.It "\&%m, \&%r, \&%s, \&%v" +The type of machine, release of the operating system, name of the +operating system, and version of the kernel, respectively, as +returned by +.Xr uname 3 . +.It \&%% +A +.Dq % +character. +.El +.Pp +When getty execs the login process, given +in the +.Em \&lo +string (usually +.Dq Pa /usr/bin/login ) , +it will have set +the environment to include the terminal type, as indicated +by the +.Em \&tt +string (if it exists). +The +.Em \&ev +string, can be used to enter additional data into +the environment. +It is a list of comma separated strings, each of which +will presumably be of the form +.Em name=value . +.Pp +If a non-zero timeout is specified, with +.Em \&to , +then getty will exit within the indicated +number of seconds, either having +received a login name and passed control +to +.Xr login 1 , +or having received an alarm signal, and exited. +This may be useful to hangup dial in lines. +.Pp +Output from +.Xr getty 8 +is even parity unless +.Em \&op +or +.Em \&np +is specified. +The +.Em \&op +string +may be specified with +.Em \&ap +to allow any parity on input, but generate odd parity output. +Note: this only applies while getty is being run, +terminal driver limitations prevent a more complete +implementation. +.Xr getty 8 +does not check parity of input characters in +.Dv RAW +mode. +.Pp +If +.Em \&pp +string is specified and a Point to Point Protocol +.Pq Tn PPP +link bringup sequence is recognized, +.Xr getty 8 +will invoke the program referenced by the +.Em \&pp +string, e.g. +.Xr pppd 8 . +This can be used to handle incoming +.Tn PPP +calls. +.Sh SEE ALSO +.Xr login 1 , +.Xr gethostname 3 , +.Xr uname 3 , +.Xr capfile 5 , +.Xr ttys 5 , +.Xr getty 8 , +.Xr pppd 8 , +.Xr telnetd 8 +.Sh HISTORY +The +.Nm +file format appeared in +.Bx 4.2 . +.Sh BUGS +The special characters (erase, kill, etc.) are reset to system defaults +by +.Xr login 1 . +In +.Em all +cases, '#' or '^H' typed in a login name will be treated as +an erase character, and '@' will be treated as a kill character. +.Pp +The delay stuff is a real crock. +Apart from its general lack of flexibility, some +of the delay algorithms are not implemented. +The terminal driver should support sane delay settings. +.Pp +The +.Em \&he +capability is stupid. diff --git a/libexec/getty/gettytab.h b/libexec/getty/gettytab.h new file mode 100644 index 000000000..a69e0630b --- /dev/null +++ b/libexec/getty/gettytab.h @@ -0,0 +1,173 @@ +/* $NetBSD: gettytab.h,v 1.16 2006/11/16 04:31:24 christos Exp $ */ + +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)gettytab.h 8.2 (Berkeley) 3/30/94 + */ + +/* + * Getty description definitions. + */ +struct gettystrs { + char *field; /* name to lookup in gettytab */ + char *defalt; /* value we find by looking in defaults */ + char *value; /* value that we find there */ +}; + +struct gettynums { + char *field; /* name to lookup */ + long defalt; /* number we find in defaults */ + long value; /* number we find there */ + int set; /* we actually got this one */ +}; + +struct gettyflags { + char *field; /* name to lookup */ + char invrt; /* name existing in gettytab --> false */ + char defalt; /* true/false in defaults */ + char value; /* true/false flag */ + char set; /* we found it */ +}; + +/* + * See init.c for the arrays indexed by these values. + */ + +/* + * String values. + */ +#define NX gettystrs[0].value +#define CL gettystrs[1].value +#define IM gettystrs[2].value +#define LM gettystrs[3].value +#define ER gettystrs[4].value +#define KL gettystrs[5].value +#define ET gettystrs[6].value +#define PC gettystrs[7].value +#define TT gettystrs[8].value +#define EV gettystrs[9].value +#define LO gettystrs[10].value +#define HN gettystrs[11].value +#define HE gettystrs[12].value +#define IN gettystrs[13].value +#define QU gettystrs[14].value +#define XN gettystrs[15].value +#define XF gettystrs[16].value +#define BK gettystrs[17].value +#define SU gettystrs[18].value +#define DS gettystrs[19].value +#define RP gettystrs[20].value +#define FL gettystrs[21].value +#define WE gettystrs[22].value +#define LN gettystrs[23].value +#define ST gettystrs[24].value +#define B2 gettystrs[25].value +#define PP gettystrs[26].value +#define IF gettystrs[27].value +#define AL gettystrs[28].value + +/* + * Numeric definitions. + */ +#define IS gettynums[0].value +#define OS gettynums[1].value +#define SP gettynums[2].value +#define ND gettynums[3].value +#define CD gettynums[4].value +#define TD gettynums[5].value +#define FD gettynums[6].value +#define BD gettynums[7].value +#define TO gettynums[8].value +#define F0 gettynums[9].value +#define F0set gettynums[9].set +#define F1 gettynums[10].value +#define F1set gettynums[10].set +#define F2 gettynums[11].value +#define F2set gettynums[11].set +#define PF gettynums[12].value +#define C0 gettynums[13].value +#define C0set gettynums[13].set +#define C1 gettynums[14].value +#define C1set gettynums[14].set +#define C2 gettynums[15].value +#define C2set gettynums[15].set +#define I0 gettynums[16].value +#define I0set gettynums[16].set +#define I1 gettynums[17].value +#define I1set gettynums[17].set +#define I2 gettynums[18].value +#define I2set gettynums[18].set +#define L0 gettynums[19].value +#define L0set gettynums[19].set +#define L1 gettynums[20].value +#define L1set gettynums[20].set +#define L2 gettynums[21].value +#define L2set gettynums[21].set +#define O0 gettynums[22].value +#define O0set gettynums[22].set +#define O1 gettynums[23].value +#define O1set gettynums[23].set +#define O2 gettynums[24].value +#define O2set gettynums[24].set + +/* + * Boolean values. + */ +#define HT gettyflags[0].value +#define NL gettyflags[1].value +#define EP gettyflags[2].value +#define EPset gettyflags[2].set +#define OP gettyflags[3].value +#define OPset gettyflags[3].set +#define AP gettyflags[4].value +#define APset gettyflags[4].set +#define EC gettyflags[5].value +#define CO gettyflags[6].value +#define CB gettyflags[7].value +#define CK gettyflags[8].value +#define CE gettyflags[9].value +#define PE gettyflags[10].value +#define RW gettyflags[11].value +#define XC gettyflags[12].value +#define LC gettyflags[13].value +#define UC gettyflags[14].value +#define IG gettyflags[15].value +#define PS gettyflags[16].value +#define HC gettyflags[17].value +#define UB gettyflags[18].value +#define AB gettyflags[19].value +#define DX gettyflags[20].value +#define NP gettyflags[21].value +#define MB gettyflags[22].value +#define CS gettyflags[23].value +#define NN gettyflags[24].value + +extern struct gettyflags gettyflags[]; +extern struct gettynums gettynums[]; +extern struct gettystrs gettystrs[]; diff --git a/libexec/getty/init.c b/libexec/getty/init.c new file mode 100644 index 000000000..c49c787a9 --- /dev/null +++ b/libexec/getty/init.c @@ -0,0 +1,146 @@ +/* $NetBSD: init.c,v 1.17 2007/12/03 09:54:24 isaki Exp $ */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 + +#include "gettytab.h" +#include "pathnames.h" + +extern struct termios tmode; +extern char hostname[]; + +#define M(a) ((char *)&tmode.c_cc[a]) + +struct gettystrs gettystrs[] = { + { "nx" }, /* next table */ + { "cl" }, /* screen clear characters */ + { "im" }, /* initial message */ + { "lm", "login: " }, /* login message */ + { "er", M(VERASE) }, /* erase character */ + { "kl", M(VKILL) }, /* kill character */ + { "et", M(VEOF) }, /* eof chatacter (eot) */ + { "pc", "" }, /* pad character */ + { "tt" }, /* terminal type */ + { "ev" }, /* environment */ + { "lo", _PATH_LOGIN }, /* login program */ + { "hn", hostname }, /* host name */ + { "he" }, /* host name edit */ + { "in", M(VINTR) }, /* interrupt char */ + { "qu", M(VQUIT) }, /* quit char */ + { "xn", M(VSTART) }, /* XON (start) char */ + { "xf", M(VSTOP) }, /* XOFF (stop) char */ + { "bk", M(VEOL) }, /* brk char (alt \n) */ + { "su", M(VSUSP) }, /* suspend char */ + { "ds", M(VDSUSP) }, /* delayed suspend */ + { "rp", M(VREPRINT) }, /* reprint char */ + { "fl", M(VDISCARD) }, /* flush output */ + { "we", M(VWERASE) }, /* word erase */ + { "ln", M(VLNEXT) }, /* literal next */ + { "st", M(VSTATUS) }, /* status */ + { "b2", M(VEOL2) }, /* alt brk char */ + { "pp" }, /* ppp login program */ + { "if" }, /* sysv-like 'issue' filename */ + { "al" }, /* user to auto-login */ + { 0 } +}; + +struct gettynums gettynums[] = { + { "is" }, /* input speed */ + { "os" }, /* output speed */ + { "sp" }, /* both speeds */ + { "nd" }, /* newline delay */ + { "cd" }, /* carriage-return delay */ + { "td" }, /* tab delay */ + { "fd" }, /* form-feed delay */ + { "bd" }, /* backspace delay */ + { "to" }, /* timeout */ + { "f0" }, /* output flags */ + { "f1" }, /* input flags */ + { "f2" }, /* user mode flags */ + { "pf" }, /* delay before flush at 1st prompt */ + { "c0" }, /* output c_flags */ + { "c1" }, /* input c_flags */ + { "c2" }, /* user mode c_flags */ + { "i0" }, /* output i_flags */ + { "i1" }, /* input i_flags */ + { "i2" }, /* user mode i_flags */ + { "l0" }, /* output l_flags */ + { "l1" }, /* input l_flags */ + { "l2" }, /* user mode l_flags */ + { "o0" }, /* output o_flags */ + { "o1" }, /* input o_flags */ + { "o2" }, /* user mode o_flags */ + { 0 } +}; + +struct gettyflags gettyflags[] = { + { "ht", 0 }, /* has tabs */ + { "nl", 1 }, /* has newline char */ + { "ep", 0 }, /* even parity */ + { "op", 0 }, /* odd parity */ + { "ap", 0 }, /* any parity */ + { "ec", 1 }, /* no echo */ + { "co", 0 }, /* console special */ + { "cb", 0 }, /* crt backspace */ + { "ck", 0 }, /* crt kill */ + { "ce", 0 }, /* crt erase */ + { "pe", 0 }, /* printer erase */ + { "rw", 1 }, /* don't use raw */ + { "xc", 1 }, /* don't ^X ctl chars */ + { "lc", 0 }, /* terminal las lower case */ + { "uc", 0 }, /* terminal has no lower case */ + { "ig", 0 }, /* ignore garbage */ + { "ps", 0 }, /* do port selector speed select */ + { "hc", 1 }, /* don't set hangup on close */ + { "ub", 0 }, /* unbuffered output */ + { "ab", 0 }, /* auto-baud detect with '\r' */ + { "dx", 0 }, /* set decctlq */ + { "np", 0 }, /* no parity at all (8bit chars) */ + { "mb", 0 }, /* do MDMBUF flow control */ + { "cs", 0 }, /* clear screen based on term type */ + { "nn", 0 }, /* don't prompt for login name */ + { 0 } +}; diff --git a/libexec/getty/main.c b/libexec/getty/main.c new file mode 100644 index 000000000..f308ae1ca --- /dev/null +++ b/libexec/getty/main.c @@ -0,0 +1,707 @@ +/* $NetBSD: main.c,v 1.59 2012/06/28 08:55:10 roy Exp $ */ + +/*- + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * and Erik 'PPP' Olson + */ + if (PP && cs == PPP_FRAME) { + ppp_state = 1; + } else if (ppp_state == 1 && cs == PPP_STATION) { + ppp_state = 2; + } else if (ppp_state == 2 && cs == PPP_ESCAPE) { + ppp_state = 3; + } else if ((ppp_state == 2 && cs == PPP_CONTROL) || + (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { + ppp_state = 4; + } else if (ppp_state == 4 && cs == PPP_LCP_HI) { + ppp_state = 5; + } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { + ppp_connection = 1; + break; + } else { + ppp_state = 0; + } + + if (c == EOT) + exit(1); + if (c == '\r' || c == '\n' || + np >= &name[LOGIN_NAME_MAX - 1]) { + *np = '\0'; + putf("\r\n"); + break; + } + if (islower(c)) + lower = 1; + else if (isupper(c)) + upper = 1; + else if (c == ERASE || c == '#' || c == '\b') { + if (np > name) { + np--; + if (cfgetospeed(&tmode) >= 1200) + xputs("\b \b"); + else + putchr(cs); + } + continue; + } else if (c == KILL || c == '@') { + putchr(cs); + putchr('\r'); + if (cfgetospeed(&tmode) < 1200) + putchr('\n'); + /* this is the way they do it down under ... */ + else if (np > name) + xputs( + " \r"); + prompt(); + np = name; + continue; + } else if (isdigit(c) || c == '_') + digit_or_punc = 1; + if (IG && (c <= ' ' || c > 0176)) + continue; + *np++ = c; + putchr(cs); + + /* + * An MS-Windows direct connect PPP "client" won't send its + * first PPP packet until we respond to its "CLIENT" poll + * with a CRLF sequence. We cater to yet another broken + * implementation of a previously-standard protocol... + */ + *np = '\0'; + if (strstr(name, "CLIENT")) + putf("\r\n"); + } + (void)signal(SIGINT, SIG_IGN); + *np = 0; + if (c == '\r') + crmod = 1; + if ((upper && !lower && !LC) || UC) + for (np = name; *np; np++) + *np = tolower((unsigned char)*np); + return (1 + ppp_connection); +} + +static void +xputs(const char *s) +{ + while (*s) + putchr(*s++); +} + +char outbuf[OBUFSIZ]; +size_t obufcnt = 0; + +static int +putchr(int cc) +{ + unsigned char c; + + c = cc; + if (!NP) { + c |= partab[c&0177] & 0200; + if (OP) + c ^= 0200; + } + if (!UB) { + outbuf[obufcnt++] = c; + if (obufcnt >= OBUFSIZ) + oflush(); + return 1; + } + return write(STDOUT_FILENO, &c, 1); +} + +static void +oflush(void) +{ + if (obufcnt) + (void)write(STDOUT_FILENO, outbuf, obufcnt); + obufcnt = 0; +} + +static void +prompt(void) +{ + + putf(LM); + if (CO) + putchr('\n'); +} + +static void +putf(const char *cp) +{ + time_t t; + char *slash, db[100]; + + while (*cp) { + if (*cp != '%') { + putchr(*cp++); + continue; + } + switch (*++cp) { + + case 't': + if ((slash = strstr(ttyn, "/pts/")) == NULL) + slash = strrchr(ttyn, '/'); + if (slash == NULL) + xputs(ttyn); + else + xputs(&slash[1]); + break; + + case 'h': + xputs(editedhost); + break; + + case 'd': + (void)time(&t); + (void)strftime(db, sizeof(db), + "%l:%M%p on %A, %d %B %Y", localtime(&t)); + xputs(db); + break; + + case 's': + xputs(kerninfo.sysname); + break; + + case 'm': + xputs(kerninfo.machine); + break; + + case 'r': + xputs(kerninfo.release); + break; + + case 'v': + xputs(kerninfo.version); + break; + + case '%': + putchr('%'); + break; + } + if (*cp) + cp++; + } +} + +static void +clearscreen(void) +{ + struct ttyent *typ; + int err; + + if (rawttyn == NULL) + return; + + typ = getttynam(rawttyn); + + if ((typ == NULL) || (typ->ty_type == NULL) || + (typ->ty_type[0] == 0)) + return; + + if (setupterm(typ->ty_type, 0, &err) == ERR) + return; + + if (clear_screen) + putpad(clear_screen); + + del_curterm(cur_term); + cur_term = NULL; +} diff --git a/libexec/getty/pathnames.h b/libexec/getty/pathnames.h new file mode 100644 index 000000000..2634fede6 --- /dev/null +++ b/libexec/getty/pathnames.h @@ -0,0 +1,37 @@ +/* $NetBSD: pathnames.h,v 1.9 2008/02/04 15:27:20 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +~ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93 + */ + +#include + +#define _PATH_LOGIN "/usr/bin/login" +#define _PATH_LOCK "/var/spool/lock/LCK.." diff --git a/libexec/getty/subr.c b/libexec/getty/subr.c new file mode 100644 index 000000000..776aab0d5 --- /dev/null +++ b/libexec/getty/subr.c @@ -0,0 +1,743 @@ +/* $NetBSD: subr.c,v 1.33 2006/11/16 04:31:24 christos Exp $ */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 +#include + +#include + +#include +#include +#include +#include +#include + +#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 + */ +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 + +char * +autobaud(void) +{ + struct pollfd set[1]; + struct timespec timeout; + char c, *type = "9600-baud"; + + (void)tcflush(0, TCIOFLUSH); + set[0].fd = STDIN_FILENO; + set[0].events = POLLIN; + if (poll(set, 1, 5000) <= 0) + return (type); + if (read(STDIN_FILENO, &c, 1) != 1) + return (type); + timeout.tv_sec = 0; + timeout.tv_nsec = 20000; + (void)nanosleep(&timeout, NULL); + (void)tcflush(0, TCIOFLUSH); + switch (c & 0377) { + + case 0200: /* 300-baud */ + type = "300-baud"; + break; + + case 0346: /* 1200-baud */ + type = "1200-baud"; + break; + + case 015: /* 2400-baud */ + case 0215: + type = "2400-baud"; + break; + + default: /* 4800-baud */ + type = "4800-baud"; + break; + + case 0377: /* 9600-baud */ + type = "9600-baud"; + break; + } + return (type); +} diff --git a/libexec/getty/ttys.5 b/libexec/getty/ttys.5 new file mode 100644 index 000000000..4ad21a228 --- /dev/null +++ b/libexec/getty/ttys.5 @@ -0,0 +1,227 @@ +.\" $NetBSD: ttys.5,v 1.18 2012/04/21 12:27:28 roy Exp $ +.\" +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)ttys.5 8.1 (Berkeley) 6/4/93 +.\" +.Dd April 5, 2012 +.Dt TTYS 5 +.Os +.Sh NAME +.Nm ttys +.Nd terminal initialization information +.Sh DESCRIPTION +The file +.Nm +contains information that is used by various routines to initialize +and control the use of terminal special files. +This information is read with the +.Xr getttyent 3 +library routines. +.Pp +There is one line in the +.Nm +file per special device file. +Fields are separated by tabs and/or spaces. +Fields comprising more than one word should be enclosed in double +quotes (``"''). +Blank lines and comments may appear anywhere in the file; comments +are delimited by hash marks (``#'') and new lines. +Any unspecified fields will default to null. +.Pp +Each line in +.Nm +has the format: +.Dl tty command type flags +.Pp +The first field is the +name of the terminal special file as it is found in +.Pa /dev . +.Pp +The second field of the file is the command to execute for the line, +usually +.Xr getty 8 , +which initializes and opens the line, setting the speed, waiting for +a user name and executing the +.Xr login 1 +program. +However, it can be any desired command, for example the start up +for a window system terminal emulator or some other daemon process, +and can contain multiple words if quoted. +.Pp +The third field is the type of terminal usually connected to that +tty line, normally the one found in the +.Xr terminfo 5 +data base file. +The environment variable +.Dv TERM +is initialized with the value by either +.Xr getty 8 +or +.Xr login 1 . +.Pp +The remaining fields set flags in the +.Fa ty_status +entry (see +.Xr getttyent 3 ) +or specify a window system process that +.Xr init 8 +will maintain for the terminal line +or a key into a database of tty attributes (currently unused). +.Pp +.Bl -tag -width softcar +.It Sy on No or Sy off +.Xr init 8 +should (or should not) execute the command given in the second field. +.It Sy secure +If +.Sy on +is specified, allows users with a uid of 0 +.Pq e.g. Qq root +to login on this line. +.It Sy local +Sets the +.Dv TIOCFLAG_CLOCAL +.Xr tty 4 +flag for the device. +This will cause the +.Xr termios 4 +.Dv CLOCAL +flag to be set on every open and thus modem control signal lines will be +ignored by default. +.It Sy softcar +Causes the driver to ignore hardware carrier on the line (by setting the +.Dv TIOCFLAG_SOFTCAR +.Xr tty 4 +flag). +.It Sy rtscts +Sets the +.Dv TIOCFLAG_CRTSCTS +.Xr tty 4 +flag for the device to enable +.Tn RTS / +.Tn CTS +.Qq hardware +flow control by default. +.It Sy mdmbuf +Sets the +.Dv TIOCFLAG_MDMBUF +.Xr tty 4 +flag for the device to enable +.Tn DTR / +.Tn DCD +.Qq hardware +flow control by default. +.El +.Pp +The flags +.Qq local , +.Qq rtscts , +.Qq mdmbuf , +and +.Qq softcar +modify the default behaviour of the terminal line, and their actions +are device driver dependent. +These flag fields should not be quoted. +.Pp +The string ``window='' may be followed by a quoted command +string which +.Xr init 8 +will execute +.Em before +starting the command specified by the second field. +.Pp +The string ``class='' may be followed by a quoted string used +as a key into a database of attributes for that category of tty. +See +.Xr getttynam 3 +for more information on this feature. +.Pp +After changing the +.Nm +file a +.Dv SIGHUP +signal can be sent to +.Xr init 8 +with the command +.Dq Li "kill \-s HUP 1" . +On receipt of this signal, +.Xr init 8 +will re-read the +.Nm +file and spawn any necessary +.Xr getty 8 +processes. +.Pp +.Sy Nota Bene : +Sending +.Dv SIGHUP +to +.Xr init 8 +does +.Em not +change the state of the various +.Xr tty 4 +device flags listed above; the +.Xr ttyflags 8 +program must be run for changes in those flags to take effect on the devices. +.Sh FILES +.Bl -tag -width /etc/ttys -compact +.It Pa /etc/ttys +.El +.Sh EXAMPLES +.Bd -literal +# root login on console at 1200 baud +console "/usr/libexec/getty std.1200" vt100 on secure +# dialup at 1200 baud, no root logins +ttyd0 "/usr/libexec/getty d1200" dialup on # 555-1234 +# Mike's terminal: hp2621 +ttyh0 "/usr/libexec/getty std.9600" hp2621-nl on # 457 Evans +# John's terminal: vt100 +ttyh1 "/usr/libexec/getty std.9600" vt100 on # 459 Evans +# terminal emulate/window system +ttyv0 "/usr/new/xterm -L :0" vs100 on window="/usr/new/Xvs100 0" +# Network pseudo ttys -- don't enable getty +ttyp0 none network +ttyp1 none network off +.Ed +.Sh SEE ALSO +.Xr login 1 , +.Xr getttyent 3 , +.Xr ttyslot 3 , +.Xr tty 4 , +.Xr gettytab 5 , +.Xr terminfo 5 , +.Xr getty 8 , +.Xr init 8 , +.Xr ttyflags 8 +.Sh HISTORY +A +.Nm +file appeared in +.At v6 . diff --git a/man/man1/Makefile b/man/man1/Makefile index 5b2282f92..f56314449 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -8,7 +8,7 @@ MAN= ash.1 at.1 \ flexdoc.1 format.1 fortune.1 \ fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \ isodir.1 isoinfo.1 isoread.1 \ - last.1 loadfont.1 loadkeys.1 logger.1 \ + loadfont.1 loadkeys.1 logger.1 \ look.1 lp.1 lspci.1 mail.1 \ mixer.1 \ mkproto.1 mount.1 mt.1 \ diff --git a/man/man1/last.1 b/man/man1/last.1 deleted file mode 100644 index 64527fb9c..000000000 --- a/man/man1/last.1 +++ /dev/null @@ -1,60 +0,0 @@ -.TH LAST 1 -.SH NAME -last, uptime \- display recent on-line session records, show uptime -.SH SYNOPSIS -\fBlast\fR [\fB\-f \fIfile\fR]\fR [\fB\-r\fR] [\fB\-\fIn\fR] [\fIname\fR] [\fItty\fR] ...\fR -.br -\fBuptime\fR -.br -.de FL -.TP -\\fB\\$1\\fR -\\$2 -.. -.de EX -.TP 20 -\\fB\\$1\\fR -# \\$2 -.. -.SH OPTIONS -.TP 5 -.B \-f -# Use \fIfile\fR instead of /usr/adm/wtmp -.TP 5 -.B \-r -# Search backwards only to last reboot -.TP 5 -.B \-u -# Print uptime since last reboot -.TP 5 -.B \-\fIn\fP -# Print a maximum of \fIn\fR lines -.SH EXAMPLES -.TP 20 -.B last reboot -# When was the system last rebooted? -.TP 20 -.B last ast -# When was the last login for ast? -.TP 20 -.B last \-10 tty00 tty01 -# Display last 10 logins on tty00 or tty01 -.TP 20 -.B uptime -# Display uptime (likewise \fBlast \-u\fR) -.SH DESCRIPTION -.PP -.I Last -Searches backward through the login administration file (default is -\fI/usr/adm/wtmp\fR), printing information about previous logins and -reboots. -During a long search, the SIGQUIT signal (CTRL-\\) causes \fIlast\fR to -display how far back it has gone; it then continues. -.PP -.IR Uptime , -an alias for -.IR "last \-u" , -displays the time the system is running since the last reboot. -.SH "SEE ALSO" -.BR who (1), -.BR utmp (5). diff --git a/man/man2/Makefile b/man/man2/Makefile index ce8c400aa..11ad7cf4a 100644 --- a/man/man2/Makefile +++ b/man/man2/Makefile @@ -4,7 +4,7 @@ MAN= accept.2 access.2 bind.2 brk.2 chdir.2 chmod.2 chown.2 \ getpeername.2 getpid.2 getpriority.2 getsockname.2 getsockopt.2 \ gettimeofday.2 getuid.2 intro.2 ioctl.2 kill.2 link.2 listen.2 \ lseek.2 mkdir.2 mknod.2 mount.2 open.2 ptrace.2 \ - read.2 readlink.2 reboot.2 recv.2 recvfrom.2 recvmsg.2 rename.2 \ + read.2 readlink.2 recv.2 recvfrom.2 recvmsg.2 rename.2 \ rmdir.2 select.2 send.2 sendmsg.2 sendto.2 setsid.2 \ setsockopt.2 setuid.2 shutdown.2 sigaction.2 sigpending.2 \ sigprocmask.2 sigsuspend.2 socket.2 socketpair.2 \ diff --git a/man/man2/reboot.2 b/man/man2/reboot.2 deleted file mode 100644 index ed433ef95..000000000 --- a/man/man2/reboot.2 +++ /dev/null @@ -1,51 +0,0 @@ -.TH REBOOT 2 -.SH NAME -reboot \- close down the system or reboot -.SH SYNTAX -.ft B -.nf -#include - -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) diff --git a/man/man8/Makefile b/man/man8/Makefile index 863517143..4f7ec5d12 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -5,8 +5,8 @@ MAN= add_route.8 backup.8 boot.8 btrace.8 \ intr.8 irdpd.8 loadramdisk.8 \ netconf.8 newroot.8 nonamed.8 \ ossdevlinks.8 part.8 partition.8 \ - poweroff.8 printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \ - readclock.8 reboot.8 repartition.8 \ + printroot.8 pr_routes.8 pwdauth.8 rarpd.8 \ + readclock.8 repartition.8 \ rshd.8 screendump.8 serial-ip.8 \ setup.8 shutdown.8 slip.8 srccrc.8 syslogd.8 tcpd.8 \ unix.8 update.8 usage.8 vbfs.8 diff --git a/man/man8/poweroff.8 b/man/man8/poweroff.8 deleted file mode 100644 index 31d6bac55..000000000 --- a/man/man8/poweroff.8 +++ /dev/null @@ -1,13 +0,0 @@ -.TH POWEROFF 1 -.SH NAME -poweroff \- power off the machine -.SH SYNOPSIS -.B poweroff -.SH DESCRIPTION -This command powers off the machine, by calling -.B shutdown -and passing the -.I off -directive to the boot monitor. -.SH "SEE ALSO" -.BR shutdown (8). diff --git a/man/man8/reboot.8 b/man/man8/reboot.8 deleted file mode 100644 index ad47f41c8..000000000 --- a/man/man8/reboot.8 +++ /dev/null @@ -1,49 +0,0 @@ -.TH REBOOT 8 -.SH NAME -reboot \- reboot the system immediately -.SH SYNOPSIS -\fBreboot\fP [\fB\-f\fP] -.SH DESCRIPTION -.B Reboot -can be used to reboot the system after installing a new kernel. It does -not inform the users, but does log it's actions in -.B /usr/adm/wtmp -and -.BR /usr/adm/log . -The system is then rebooted with the -.BR reboot (2) -systemcall. -.PP -If the -.B \-f -flag is not given then all processes are sent terminate -signals to give them a chance to die peacefully before the -.B reboot() -call. -.PP -If the wtmp file exists, -.B reboot -logs itself as if it were a shutdown. This is done to prevent -.BR last (1) -from talking about system-crashes. -.B Reboot -is registered as is in the log file. -.PP -.B Reboot -can only be executed by the super-user. Any other caller will be -refused, either by -.BR reboot (8) -or by -.BR reboot (2). -.SH "SEE ALSO" -.BR reboot (2), -.BR shutdown (8), -.BR halt(8), -.BR boot (8). -.SH BUGS -The error message's given by -.B reboot -are not always useful. There are several routines that can fail, but which -are not fatal for the program. -.SH AUTHOR -Edvard Tuinder (v892231@si.hhs.NL) diff --git a/releasetools/Makefile b/releasetools/Makefile index 8c7e8526f..e96e41806 100644 --- a/releasetools/Makefile +++ b/releasetools/Makefile @@ -28,7 +28,7 @@ PROGRAMS+= ${PROGROOT}/drivers/tty/tty PROGRAMS+= ${PROGROOT}/servers/mfs/mfs PROGRAMS+= ${PROGROOT}/servers/vm/vm PROGRAMS+= ${PROGROOT}/servers/pfs/pfs -PROGRAMS+= ${PROGROOT}/servers/init/init +PROGRAMS+= ${PROGROOT}/sbin/init/init usage: @echo " " >&2 @@ -68,10 +68,13 @@ kernel: libraries servers: libraries ${MAKE} -C ../servers all install +sbin: libraries + ${MAKE} -C ../sbin all install + drivers: libraries servers ${MAKE} -C ../drivers all install -services: kernel servers drivers +services: kernel servers drivers sbin .gitignore: Makefile echo ${GEN_FILES} | tr ' ' '\n' >.gitignore diff --git a/releasetools/arm_sdimage.sh b/releasetools/arm_sdimage.sh index 8a413402f..7a537293f 100755 --- a/releasetools/arm_sdimage.sh +++ b/releasetools/arm_sdimage.sh @@ -178,11 +178,14 @@ ${CROSS_PREFIX}objcopy ${OBJ}/kernel/kernel -O binary ${OBJ}/kernel.bin mcopy -bsp -i ${IMG_DIR}/fat.img ${OBJ}/kernel.bin ::kernel.bin -for f in vm rs pm sched vfs ds mfs pfs init +for f in servers/vm/vm servers/rs/rs servers/pm/pm servers/sched/sched \ + servers/vfs/vfs servers/ds/ds servers/mfs/mfs servers/pfs/pfs \ + sbin/init/init do - cp ${OBJ}/servers/${f}/${f} ${OBJ}/${f}.elf - ${CROSS_PREFIX}strip -s ${OBJ}/${f}.elf - mcopy -bsp -i ${IMG_DIR}/fat.img ${OBJ}/${f}.elf ::${f}.elf + fn=`basename $f`.elf + cp ${OBJ}/${f} ${OBJ}/${fn} + ${CROSS_PREFIX}strip -s ${OBJ}/${fn} + mcopy -bsp -i ${IMG_DIR}/fat.img ${OBJ}/${fn} ::${fn} done for f in tty memory diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 084328d1c..da1fd1e32 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -73,6 +73,7 @@ 2012/10/17 12:00:00,include 2013/05/31 12:00:00,libexec/fingerd 2012/10/17 12:00:00,libexec/ftpd +2012/10/17 12:00:00,libexec/getty 2012/10/17 12:00:00,libexec/ld.elf_so 2012/10/17 12:00:00,libexec/Makefile 2012/10/17 12:00:00,libexec/Makefile.inc @@ -97,6 +98,9 @@ 2012/10/17 12:00:00,Makefile 2011/06/09 21:23:29,sbin/fsck 2011/09/16 16:13:18,sbin/fsck_ext2fs +2012/10/17 12:00:00,sbin/init +2012/10/17 12:00:00,sbin/reboot +2012/10/17 12:00:00,sbin/shutdown 2012/10/17 12:00:00,sbin/Makefile 2012/10/17 12:00:00,sbin/Makefile.inc 2012/10/10 16:16:12,sbin/mknod @@ -188,6 +192,7 @@ 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 @@ -248,11 +253,12 @@ 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 diff --git a/sbin/Makefile b/sbin/Makefile index 8f735e6a5..4453eedac 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -9,7 +9,12 @@ SUBDIR= \ \ fsck \ - mknod nologin + mknod \ + nologin \ + mknod \ + init \ + reboot \ + shutdown # support for various file systems SUBDIR+= newfs_ext2fs fsck_ext2fs diff --git a/sbin/init/Makefile b/sbin/init/Makefile new file mode 100644 index 000000000..b1a55ef4a --- /dev/null +++ b/sbin/init/Makefile @@ -0,0 +1,18 @@ +# $NetBSD: Makefile,v 1.38 2009/04/11 07:58:12 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 7/19/93 + +PROG= init +MAN= init.8 +DPADD= ${LIBUTIL} +LDADD= -lutil +CPPFLAGS+= -DMFS_DEV_IF_NO_CONSOLE -DSUPPORT_UTMP -DSUPPORT_UTMPX + +.ifdef SMALLPROG +CPPFLAGS+= -DLETS_GET_SMALL +.else +CPPFLAGS+= -DALTSHELL -DSECURE -DCHROOT +DPADD+= ${LIBCRYPT} +LDADD+= -lcrypt +.endif + +.include diff --git a/sbin/init/NOTES b/sbin/init/NOTES new file mode 100644 index 000000000..ca4eb7797 --- /dev/null +++ b/sbin/init/NOTES @@ -0,0 +1,119 @@ +$NetBSD: NOTES,v 1.3 2006/04/18 11:40:26 salo Exp $ + +POSIX and init: +-------------- + +POSIX.1 does not define 'init' but it mentions it in a few places. + +B.2.2.2, p205 line 873: + + This is part of the extensive 'job control' glossary entry. + This specific reference says that 'init' must by default provide + protection from job control signals to jobs it starts -- + it sets SIGTSTP, SIGTTIN and SIGTTOU to SIG_IGN. + +B.2.2.2, p206 line 889: + + Here is a reference to 'vhangup'. It says, 'POSIX.1 does + not specify how controlling terminal access is affected by + a user logging out (that is, by a controlling process + terminating).' vhangup() is recognized as one way to handle + the problem. I'm not clear what happens in Reno; I have + the impression that when the controlling process terminates, + references to the controlling terminal are converted to + references to a 'dead' vnode. I don't know whether vhangup() + is required. + +B.2.2.2, p206 line 921: + + Orphaned process groups bear indirectly on this issue. A + session leader's process group is considered to be orphaned; + that is, it's immune to job control signals from the terminal. + +B.2.2.2, p233 line 2055: + + 'Historically, the implementation-dependent process that + inherits children whose parents have terminated without + waiting on them is called "init" and has a process ID of 1.' + + It goes on to note that it used to be the case that 'init' + was responsible for sending SIGHUP to the foreground process + group of a tty whose controlling process has exited, using + vhangup(). It is now the responsibility of the kernel to + do this when the controlling process calls _exit(). The + kernel is also responsible for sending SIGCONT to stopped + process groups that become orphaned. This is like old BSD + but entire process groups are signaled instead of individual + processes. + + In general it appears that the kernel now automatically + takes care of orphans, relieving 'init' of any responsibility. + Specifics are listed on the _exit() page (p50). + +On setsid(): +----------- + +It appears that neither getty nor login call setsid(), so init must +do this -- seems reasonable. B.4.3.2 p 248 implies that this is the +way that 'init' should work; it says that setsid() should be called +after forking. + +Process group leaders cannot call setsid() -- another reason to +fork! Of course setsid() causes the current process to become a +process group leader, so we can only call setsid() once. Note that +the controlling terminal acquires the session leader's process +group when opened. + +Controlling terminals: +--------------------- + +B.7.1.1.3 p276: 'POSIX.1 does not specify a mechanism by which to +allocate a controlling terminal. This is normally done by a system +utility (such as 'getty') and is considered ... outside the scope +of POSIX.1.' It goes on to say that historically the first open() +of a tty in a session sets the controlling terminal. P130 has the +full details; nothing particularly surprising. + +The glossary p12 describes a 'controlling process' as the first +process in a session that acquires a controlling terminal. Access +to the terminal from the session is revoked if the controlling +process exits (see p50, in the discussion of process termination). + +Design notes: +------------ + +your generic finite state machine +we are fascist about which signals we elect to receive, + even signals purportedly generated by hardware +handle fatal errors gracefully if possible (we reboot if we goof!!) + if we get a segmentation fault etc., print a message on the console + and spin for a while before rebooting + (this at least decreases the amount of paper consumed :-) +apply hysteresis to rapidly exiting gettys +check wait status of children we reap + don't wait for stopped children +don't use SIGCHILD, it's too expensive + but it may close windows and avoid races, sigh +look for EINTR in case we need to change state +init is responsible for utmp and wtmp maintenance (ick) + maybe now we can consider replacements? maintain them in parallel + init only removes utmp and closes out wtmp entries... + +necessary states and state transitions (gleaned from the man page): + 1: single user shell (with password checking?); on exit, go to 2 + 2: run rc script, on exit 0 check if init.root sysctl != "/", if it + differs then fork + chroot into the value of init.root and run + /etc/rc inside the chroot: on exit 0, go to 3; on exit N (error), + go to 1 (applies also to /etc/rc when init.root == "/") + 3: read ttys file: on completion, go to 4. If we did chroot in + state 2, we chroot after forking each getty to the same dir + (init.root is not re-read) + 4: multi-user operation: on SIGTERM, go to 7; on SIGHUP, go to 5; + on SIGTSTP, go to 6 + 5: clean up mode (re-read ttys file, killing off controlling processes + on lines that are now 'off', starting them on lines newly 'on') + on completion, go to 4 + 6: boring mode (no new sessions); signals as in 4 + 7: death: send SIGHUP to all controlling processes, reap for 30 seconds, + then go to 1 (warn if not all processes died, i.e. wait blocks) +Given the -s flag, we start at state 1; otherwise state 2 diff --git a/sbin/init/init.8 b/sbin/init/init.8 new file mode 100644 index 000000000..c0378214f --- /dev/null +++ b/sbin/init/init.8 @@ -0,0 +1,374 @@ +.\" $NetBSD: init.8,v 1.57 2009/05/18 14:17:31 wiz Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Donn Seeley at Berkeley Software Design, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)init.8 8.6 (Berkeley) 5/26/95 +.\" +.Dd November 10, 2008 +.Dt INIT 8 +.Os +.Sh NAME +.Nm init +.Nd process control initialization +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +The +.Nm +program is the last stage of the boot process (after the kernel loads +and initializes all the devices). +It normally begins multi-user operation. +.Pp +The following table describes the state machine used by +.Nm : +.Bl -enum +.It +Single user shell. +.Nm +may be passed +.Fl s +from the boot program to prevent the system from going multi-user and +to instead execute a single user shell without starting the normal +daemons. +If the kernel is in a secure mode, +.Nm +will downgrade it to securelevel 0 (insecure mode). +The system is then quiescent for maintenance work and may +later be made to go to state 2 (multi-user) by exiting the single-user +shell (with ^D). +.It +Multi-user boot (default operation). +Executes +.Pa /etc/rc +(see +.Xr rc 8 ) . +If this was the first state entered (as opposed to entering here after +state 1), then +.Pa /etc/rc +will be invoked with its first argument being +.Sq autoboot . +If +.Pa /etc/rc +exits with a non-zero (error) exit code, commence single user +operation by giving the super-user a shell on the console by going +to state 1 (single user). +Otherwise, proceed to state 3. +.Pp +If value of the +.Dq init.root +sysctl node is not equal to +.Pa / +at this point, the +.Pa /etc/rc +process will be run inside a +.Xr chroot 2 +indicated by sysctl with the same error handling as above. +.Pp +If the administrator has not set the security level to \-1 +to indicate that the kernel should not run multiuser in secure +mode, and the +.Pa /etc/rc +script has not set a higher level of security +than level 1, then +.Nm +will put the kernel into securelevel mode 1. +See +.Xr rc.conf 5 +and +.Xr secmodel_securelevel 9 +for more information. +.It +Set up ttys as specified in +.Xr ttys 5 . +See below for more information. +On completion, continue to state 4. +If we did chroot in state 2, each +.Xr getty 8 +process will be run in the same +.Xr chroot 2 +path as in 2 (that is, the value of +.Dq init.root +sysctl is not re-read). +.It +Multi-user operation. +Depending upon the signal received, change state appropriately; +on +.Dv SIGTERM , +go to state 7; +on +.Dv SIGHUP , +go to state 5; +on +.Dv SIGTSTP , +go to state 6. +.It +Clean-up mode; re-read +.Xr ttys 5 , +killing off the controlling processes on lines that are now +.Sq off , +and starting processes that are newly +.Sq on . +On completion, go to state 4. +.It +.Sq Boring +mode; no new sessions. +Signals as per state 4. +.It +Shutdown mode. +Send +.Dv SIGHUP +to all controlling processes, reap the processes for 30 seconds, +and then go to state 1 (single user); warning if not all the processes died. +.El +.Pp +If the +.Sq console +entry in the +.Xr ttys 5 +file is marked +.Dq insecure , +then +.Nm +will require that the superuser password be +entered before the system will start a single-user shell. +The password check is skipped if the +.Sq console +is marked as +.Dq secure . +.Pp +It should be noted that while +.Nm +has the ability to start multi-user operation inside a +.Xr chroot 2 +environment, the +.Nm +process itself will always run in the +.Dq original root directory . +This also implies that single-user mode is always started in the original +root, giving the possibility to create multi-user sessions in different +root directories over time. +The +.Dq init.root +sysctl node is fabricated by +.Nm +at startup and re-created any time it's found to be missing. +Type of the node is string capable of holding full pathname, and +is only accessible by the superuser (unless explicitly destroyed +and re-created with different specification). +.Pp +In multi-user operation, +.Nm +maintains +processes for the terminal ports found in the file +.Xr ttys 5 . +.Nm +reads this file, and executes the command found in the second field. +This command is usually +.Xr getty 8 ; +it opens and initializes the tty line and executes the +.Xr login 1 +program. +The +.Xr login 1 +program, when a valid user logs in, executes a shell for that user. +When this shell dies, either because the user logged out or an +abnormal termination occurred (a signal), the +.Nm +program wakes up, deletes the user from the +.Xr utmp 5 +and +.Xr utmpx 5 +files of current users and records the logout in the +.Xr wtmp 5 +and +.Xr wtmpx 5 +files. +The cycle is +then restarted by +.Nm +executing a new +.Xr getty 8 +for the line. +.Pp +Line status (on, off, secure, getty, or window information) +may be changed in the +.Xr ttys 5 +file without a reboot by sending the signal +.Dv SIGHUP +to +.Nm +with the command +.Dq Li "kill \-s HUP 1" . +This is referenced in the table above as state 5. +On receipt of this signal, +.Nm +re-reads the +.Xr ttys 5 +file. +When a line is turned off in +.Xr ttys 5 , +.Nm +will send a +.Dv SIGHUP +signal to the controlling process +for the session associated with the line. +For any lines that were previously turned off in the +.Xr ttys 5 +file and are now on, +.Nm +executes a new +.Xr getty 8 +to enable a new login. +If the getty or window field for a line is changed, +the change takes effect at the end of the current +login session (e.g., the next time +.Nm +starts a process on the line). +If a line is commented out or deleted from +.Xr ttys 5 , +.Nm +will not do anything at all to that line. +However, it will complain that the relationship between lines +in the +.Xr ttys 5 +file and records in the +.Xr utmp 5 +file is out of sync, +so this practice is not recommended. +.Pp +.Nm +will terminate multi-user operations and resume single-user mode +if sent a terminate +.Pq Dv TERM +signal, for example, +.Dq Li "kill \-s TERM 1" . +If there are processes outstanding that are deadlocked (because of +hardware or software failure), +.Nm +will not wait for them all to die (which might take forever), but +will time out after 30 seconds and print a warning message. +.Pp +.Nm +will cease creating new +.Xr getty 8 Ns 's +and allow the system to slowly die away, if it is sent a terminal stop +.Pq Dv TSTP +signal, i.e. +.Dq Li "kill \-s TSTP 1" . +A later hangup will resume full +multi-user operations, or a terminate will start a single user shell. +This hook is used by +.Xr reboot 8 +and +.Xr halt 8 . +.Pp +The role of +.Nm +is so critical that if it dies, the system will reboot itself +automatically. +If, at bootstrap time, the +.Nm +process cannot be located, or exits during its initialisation, +the system will panic with the message +.Dq panic: init died (signal %d, exit %d) . +.Pp +If +.Pa /dev/console +does not exist, +.Nm +will cd to +.Pa /dev +and run +.Dq Li "MAKEDEV -MM init" . +.Xr MAKEDEV 8 +will use +.Xr mount_tmpfs 8 +or +.Xr mount_mfs 8 +to create a memory file system mounted over +.Pa /dev +that contains the standard devices considered necessary to boot the system. +.Sh FILES +.Bl -tag -width /var/log/wtmp{,x} -compact +.It Pa /dev/console +System console device. +.It Pa /dev/tty* +Terminal ports found in +.Xr ttys 5 . +.It Pa /var/run/utmp{,x} +Record of current users on the system. +.It Pa /var/log/wtmp{,x} +Record of all logins and logouts. +.It Pa /etc/ttys +The terminal initialization information file. +.It Pa /etc/rc +System startup commands. +.El +.Sh DIAGNOSTICS +.Bl -diag +.It "getty repeating too quickly on port %s, sleeping" +A process being started to service a line is exiting quickly +each time it is started. +This is often caused by a ringing or noisy terminal line. +.Em "Init will sleep for 10 seconds" , +.Em "then continue trying to start the process" . +.Pp +.It "some processes would not die; ps axl advised." +A process is hung and could not be killed when the system was +shutting down. +This condition is usually caused by a process that is stuck in a +device driver because of a persistent device error condition. +.El +.Sh SEE ALSO +.Xr config 1 , +.Xr kill 1 , +.Xr login 1 , +.Xr sh 1 , +.Xr options 4 , +.Xr ttys 5 , +.Xr getty 8 , +.Xr halt 8 , +.Xr MAKEDEV 8 , +.Xr MAKEDEV.local 8 , +.Xr mount_mfs 8 , +.Xr mount_tmpfs 8 , +.Xr rc 8 , +.Xr reboot 8 , +.Xr rescue 8 , +.Xr shutdown 8 , +.Xr sysctl 8 , +.Xr secmodel_bsd44 9 , +.Xr secmodel_securelevel 9 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . diff --git a/sbin/init/init.c b/sbin/init/init.c new file mode 100644 index 000000000..85e1c9f9b --- /dev/null +++ b/sbin/init/init.c @@ -0,0 +1,1910 @@ +/* $NetBSD: init.c,v 1.103 2012/03/20 18:50:31 matt Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Donn Seeley at Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef SECURE +#include +#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 + */ + char errbuf[1024]; + int fd, len; + + /* We can't do anything on errors, anyway... */ + fd = open(_PATH_CONSOLE, O_WRONLY); + if (fd == -1) + return ; + + /* %m will get lost... */ + len = vsnprintf(errbuf, sizeof(errbuf), message, ap); + (void)write(fd, (void *)errbuf, len); + (void)close(fd); +} +#endif + +/* + * Log a message and sleep for a while (to give someone an opportunity + * to read it and to save log or hardcopy output if the problem is chronic). + * NB: should send a message to the session logger to avoid blocking. + */ +static void +stall(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + vsyslog(LOG_ALERT, message, ap); + va_end(ap); + closelog(); + (void)sleep(STALL_TIMEOUT); +} + +/* + * Like stall(), but doesn't sleep. + * If cpp had variadic macros, the two functions could be #defines for another. + * NB: should send a message to the session logger to avoid blocking. + */ +static void +warning(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + vsyslog(LOG_ALERT, message, ap); + va_end(ap); + closelog(); +} + +/* + * Log an emergency message. + * NB: should send a message to the session logger to avoid blocking. + */ +static void +emergency(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + vsyslog(LOG_EMERG, message, ap); + va_end(ap); + closelog(); +} + +#ifndef __minix +/* + * Catch a SIGSYS signal. + * + * These may arise if a system does not support sysctl. + * We tolerate up to 25 of these, then throw in the towel. + */ +static void +badsys(int sig) +{ + static int badcount = 0; + + if (badcount++ < 25) + return; + disaster(sig); +} +#endif + +/* + * Catch an unexpected signal. + */ +static void +disaster(int sig) +{ + + emergency("fatal signal: %s", strsignal(sig)); + (void)sleep(STALL_TIMEOUT); + + _exit(sig); /* reboot */ +} + +#ifdef __minix + +/* + * controlled reboot - minix tradition, SIGABRT by tty + */ +static void +minixreboot(int sig) +{ + if(fork() == 0) { + (void)execl("/sbin/shutdown", + "shutdown", "-r", "now", "CTRL-ALT_DEL", NULL); + _exit(1); + } +} + +/* + * controlled powerdown + */ +static void +minixpowerdown(int sig) +{ + if(fork() == 0) { + (void)execl("/sbin/shutdown", + "shutdown", "-p", "now", "CTRL-ALT_DEL", NULL); + _exit(1); + } +} + +#endif + +/* + * Check if securelevel is present. + */ +static int +has_securelevel(void) +{ +#ifdef __minix + return 0; +#else +#ifdef KERN_SECURELVL + int name[2], curlevel; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + len = sizeof curlevel; + if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { + /* If it doesn't exist, it's okay. */ + if (errno == ENOENT) + return 0; + } + return 1; +#else + return 0; +#endif +#endif +} + +/* + * Get the security level of the kernel. + */ +static int +getsecuritylevel(void) +{ +#ifdef KERN_SECURELVL + int name[2], curlevel; + size_t len; + + if (!securelevel_present) + return -1; + + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + len = sizeof curlevel; + if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) { + emergency("cannot get kernel security level: %m"); + return -1; + } + return curlevel; +#else + return -1; +#endif +} + +/* + * Set the security level of the kernel. + */ +static void +setsecuritylevel(int newlevel) +{ +#ifdef KERN_SECURELVL + int name[2], curlevel; + + if (!securelevel_present) + return; + + curlevel = getsecuritylevel(); + if (newlevel == curlevel) + return; + name[0] = CTL_KERN; + name[1] = KERN_SECURELVL; + if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) { + emergency("cannot change kernel security level from" + " %d to %d: %m", curlevel, newlevel); + return; + } +#ifdef SECURE + warning("kernel security level changed from %d to %d", + curlevel, newlevel); +#endif +#endif +} + +/* + * Change states in the finite state machine. + * The initial state is passed as an argument. + */ +static void +transition(state_t s) +{ + + if (s == NULL) + return; + for (;;) { +#ifdef SUPPORT_UTMPX +#ifndef LETS_GET_SMALL + utmpx_set_runlevel(get_runlevel(current_state), + get_runlevel(s)); + current_state = s; +#endif +#endif + s = (state_t)(*s)(); + } +} + +#ifndef LETS_GET_SMALL +/* + * Close out the accounting files for a login session. + * NB: should send a message to the session logger to avoid blocking. + */ +static void +clear_session_logs(session_t *sp, int status) +{ +#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) + char *line = sp->se_device + sizeof(_PATH_DEV) - 1; +#endif + +#ifdef SUPPORT_UTMPX + if (logoutx(line, status, DEAD_PROCESS)) + logwtmpx(line, "", "", status, DEAD_PROCESS); +#endif +#ifdef SUPPORT_UTMP + if (logout(line)) + logwtmp(line, "", ""); +#endif +} +#endif + +/* + * Start a session and allocate a controlling terminal. + * Only called by children of init after forking. + */ +static void +setctty(const char *name) +{ + int fd; + +#ifndef __minix + (void)revoke(name); +#else + if (setsid() < 0) + warn("child setsid() failed"); +#endif + (void)nanosleep(&dtrtime, NULL); /* leave DTR low for a bit */ + if ((fd = open(name, O_RDWR)) == -1) { + stall("can't open %s: %m", name); + _exit(1); + } + if (login_tty(fd) == -1) { + stall("can't get %s for controlling terminal: %m", name); + _exit(2); + } +} + +/* + * Bring the system up single user. + */ +static state_func_t +single_user(void) +{ + pid_t pid, wpid; + int status; + int from_securitylevel; + sigset_t mask; + struct sigaction sa, satstp, sahup; +#ifdef ALTSHELL + const char *shell = INIT_BSHELL; +#endif + const char *argv[2]; +#ifdef SECURE + struct ttyent *typ; + struct passwd *pp; + char *clear, *password; +#endif +#ifdef ALTSHELL + char altshell[128]; +#endif /* ALTSHELL */ + +#if !defined(LETS_GET_SMALL) && defined(CHROOT) + /* Clear previous idea, just in case. */ + did_multiuser_chroot = 0; +#endif /* !LETS_GET_SMALL && CHROOT */ + + /* + * If the kernel is in secure mode, downgrade it to insecure mode. + */ + from_securitylevel = getsecuritylevel(); + if (from_securitylevel > 0) + setsecuritylevel(0); + + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + (void)sigaction(SIGTSTP, &sa, &satstp); + (void)sigaction(SIGHUP, &sa, &sahup); + if ((pid = fork()) == 0) { + /* + * Start the single user session. + */ + if (access(_PATH_CONSTTY, F_OK) == 0) + setctty(_PATH_CONSTTY); + else + setctty(_PATH_CONSOLE); + +#ifdef SECURE + /* + * Check the root password. + * We don't care if the console is 'on' by default; + * it's the only tty that can be 'off' and 'secure'. + */ + typ = getttynam("console"); + pp = getpwnam("root"); + if (typ && (from_securitylevel >=2 || (typ->ty_status + & TTY_SECURE) == 0) && pp && *pp->pw_passwd != '\0') { + (void)fprintf(stderr, + "Enter root password, or ^D to go multi-user\n"); + for (;;) { + clear = getpass("Password:"); + if (clear == 0 || *clear == '\0') + _exit(0); + password = crypt(clear, pp->pw_passwd); + (void)memset(clear, 0, _PASSWORD_LEN); + if (strcmp(password, pp->pw_passwd) == 0) + break; + warning("single-user login failed"); + } + } + (void)endttyent(); + endpwent(); +#endif /* SECURE */ + +#ifdef ALTSHELL + (void)fprintf(stderr, + "Enter pathname of shell or RETURN for %s: ", shell); + if (fgets(altshell, sizeof(altshell), stdin) == NULL) { + altshell[0] = '\0'; + } else { + /* nuke \n */ + char *p; + + if ((p = strchr(altshell, '\n')) != NULL) + *p = '\0'; + } + + if (altshell[0]) + shell = altshell; +#endif /* ALTSHELL */ + + /* + * Unblock signals. + * We catch all the interesting ones, + * and those are reset to SIG_DFL on exec. + */ + (void)sigemptyset(&mask); + (void)sigprocmask(SIG_SETMASK, &mask, NULL); + + /* + * Fire off a shell. + * If the default one doesn't work, try the Bourne shell. + */ + argv[0] = "-sh"; + argv[1] = 0; + (void)setenv("PATH", INIT_PATH, 1); +#ifdef ALTSHELL + if (altshell[0]) + argv[0] = altshell; + (void)execv(shell, __UNCONST(argv)); + emergency("can't exec `%s' for single user: %m", shell); + argv[0] = "-sh"; +#endif /* ALTSHELL */ + (void)execv(INIT_BSHELL, __UNCONST(argv)); + emergency("can't exec `%s' for single user: %m", INIT_BSHELL); + (void)sleep(STALL_TIMEOUT); + _exit(3); + } + + if (pid == -1) { + /* + * We are seriously hosed. Do our best. + */ + emergency("can't fork single-user shell: %m, trying again"); + while (waitpid(-1, NULL, WNOHANG) > 0) + continue; + (void)sigaction(SIGTSTP, &satstp, NULL); + (void)sigaction(SIGHUP, &sahup, NULL); + return (state_func_t)single_user; + } + + requested_transition = 0; + do { + if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) + collect_child(wpid, status); + if (wpid == -1) { + if (errno == EINTR) + continue; + warning("wait for single-user shell failed: %m; " + "restarting"); + return (state_func_t)single_user; + } + if (wpid == pid && WIFSTOPPED(status)) { + warning("shell stopped, restarting"); + (void)kill(pid, SIGCONT); + wpid = -1; + } + } while (wpid != pid && !requested_transition); + + if (requested_transition) { + (void)sigaction(SIGTSTP, &satstp, NULL); + (void)sigaction(SIGHUP, &sahup, NULL); + return (state_func_t)requested_transition; + } + + if (WIFSIGNALED(status)) { + if (WTERMSIG(status) == SIGKILL) { + /* executed /sbin/reboot; wait for the end quietly */ + sigset_t s; + + (void)sigfillset(&s); + for (;;) + (void)sigsuspend(&s); + } else { + warning("single user shell terminated (%x), restarting", + status); + (void)sigaction(SIGTSTP, &satstp, NULL); + (void)sigaction(SIGHUP, &sahup, NULL); + return (state_func_t)single_user; + } + } + + runcom_mode = FASTBOOT; + (void)sigaction(SIGTSTP, &satstp, NULL); + (void)sigaction(SIGHUP, &sahup, NULL); +#ifndef LETS_GET_SMALL + return (state_func_t)runcom; +#else /* LETS_GET_SMALL */ + return (state_func_t)single_user; +#endif /* LETS_GET_SMALL */ +} + +#ifndef LETS_GET_SMALL + +/* ARGSUSED */ +static state_func_t +runetcrc(int trychroot) +{ + pid_t pid, wpid; + int status; + const char *argv[4]; + struct sigaction sa; + + switch ((pid = fork())) { + case 0: + (void)sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + (void)sigaction(SIGTSTP, &sa, NULL); + (void)sigaction(SIGHUP, &sa, NULL); + + setctty(_PATH_CONSOLE); + + argv[0] = "sh"; + argv[1] = _PATH_RUNCOM; + argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0); + argv[3] = 0; + + (void)sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); + +#ifdef CHROOT + if (trychroot) + if (chroot(rootdir) != 0) { + warning("failed to chroot to `%s': %m", + rootdir); + _exit(4); /* force single user mode */ + } +#endif /* CHROOT */ + + (void)execv(INIT_BSHELL, __UNCONST(argv)); + stall("can't exec `%s' for `%s': %m", INIT_BSHELL, _PATH_RUNCOM); + _exit(5); /* force single user mode */ + /*NOTREACHED*/ + case -1: + emergency("can't fork for `%s' on `%s': %m", INIT_BSHELL, + _PATH_RUNCOM); + while (waitpid(-1, NULL, WNOHANG) > 0) + continue; + (void)sleep(STALL_TIMEOUT); + return (state_func_t)single_user; + default: + break; + } + + /* + * Copied from single_user(). This is a bit paranoid. + */ + do { + if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) + collect_child(wpid, status); + if (wpid == -1) { + if (errno == EINTR) + continue; + warning("wait for `%s' on `%s' failed: %m; going to " + "single user mode", INIT_BSHELL, _PATH_RUNCOM); + return (state_func_t)single_user; + } + if (wpid == pid && WIFSTOPPED(status)) { + warning("`%s' on `%s' stopped, restarting", + INIT_BSHELL, _PATH_RUNCOM); + (void)kill(pid, SIGCONT); + wpid = -1; + } + } while (wpid != pid); + + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM && + requested_transition == catatonia) { + /* /etc/rc executed /sbin/reboot; wait for the end quietly */ + sigset_t s; + + (void)sigfillset(&s); + for (;;) + (void)sigsuspend(&s); + } + + if (!WIFEXITED(status)) { + warning("`%s' on `%s' terminated abnormally, going to " + "single user mode", INIT_BSHELL, _PATH_RUNCOM); + return (state_func_t)single_user; + } + + if (WEXITSTATUS(status)) + return (state_func_t)single_user; + + return (state_func_t)read_ttys; +} + +/* + * Run the system startup script. + */ +static state_func_t +runcom(void) +{ + state_func_t next_step; + + /* Run /etc/rc and choose next state depending on the result. */ + next_step = runetcrc(0); + if (next_step != (state_func_t)read_ttys) + return (state_func_t)next_step; + +#ifdef CHROOT + /* + * If init.root sysctl does not point to "/", we'll chroot and run + * The Real(tm) /etc/rc now. Global variable rootdir will tell us + * where to go. + */ + if (shouldchroot()) { + next_step = runetcrc(1); + if (next_step != (state_func_t)read_ttys) + return (state_func_t)next_step; + + did_multiuser_chroot = 1; + } else { + did_multiuser_chroot = 0; + } +#endif /* CHROOT */ + + /* + * Regardless of whether in chroot or not, we booted successfuly. + * It's time to spawn gettys (ie. next_step's value at this point). + */ + runcom_mode = AUTOBOOT; /* the default */ + /* NB: should send a message to the session logger to avoid blocking. */ +#ifdef SUPPORT_UTMPX + logwtmpx("~", "reboot", "", 0, INIT_PROCESS); +#endif +#ifdef SUPPORT_UTMP + logwtmp("~", "reboot", ""); +#endif + return (state_func_t)read_ttys; +} + +/* + * Open the session database. + * + * NB: We could pass in the size here; is it necessary? + */ +static int +start_session_db(void) +{ + + if (session_db && (*session_db->close)(session_db)) + emergency("session database close: %m"); + if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) { + emergency("session database open: %m"); + return 1; + } + return 0; + +} + +/* + * Add a new login session. + */ +static void +add_session(session_t *sp) +{ + DBT key; + DBT data; + + if (session_db == NULL) + return; + + key.data = &sp->se_process; + key.size = sizeof sp->se_process; + data.data = &sp; + data.size = sizeof sp; + + if ((*session_db->put)(session_db, &key, &data, 0)) + emergency("insert %d: %m", sp->se_process); +#ifdef SUPPORT_UTMPX + session_utmpx(sp, 1); +#endif +} + +/* + * Delete an old login session. + */ +static void +del_session(session_t *sp) +{ + DBT key; + + key.data = &sp->se_process; + key.size = sizeof sp->se_process; + + if ((*session_db->del)(session_db, &key, 0)) + emergency("delete %d: %m", sp->se_process); +#ifdef SUPPORT_UTMPX + session_utmpx(sp, 0); +#endif +} + +/* + * Look up a login session by pid. + */ +static session_t * +find_session(pid_t pid) +{ + DBT key; + DBT data; + session_t *ret; + + if (session_db == NULL) + return NULL; + + key.data = &pid; + key.size = sizeof pid; + if ((*session_db->get)(session_db, &key, &data, 0) != 0) + return 0; + (void)memmove(&ret, data.data, sizeof(ret)); + return ret; +} + +/* + * Construct an argument vector from a command line. + */ +static char ** +construct_argv(char *command) +{ + int argc = 0; + char **argv = malloc(((strlen(command) + 1) / 2 + 1) * sizeof (char *)); + static const char separators[] = " \t"; + + if (argv == NULL) + return NULL; + + if ((argv[argc++] = strtok(command, separators)) == 0) { + free(argv); + return NULL; + } + while ((argv[argc++] = strtok(NULL, separators)) != NULL) + continue; + return argv; +} + +/* + * Deallocate a session descriptor. + */ +static void +free_session(session_t *sp) +{ + + free(sp->se_device); + if (sp->se_getty) { + free(sp->se_getty); + free(sp->se_getty_argv); + } + if (sp->se_window) { + free(sp->se_window); + free(sp->se_window_argv); + } + free(sp); +} + +/* + * Allocate a new session descriptor. + */ +static session_t * +new_session(session_t *sprev, int session_index, struct ttyent *typ) +{ + session_t *sp; + + if ((typ->ty_status & TTY_ON) == 0 || typ->ty_name == NULL || + typ->ty_getty == NULL) + return NULL; + + sp = malloc(sizeof (session_t)); + if (sp == NULL) + return NULL; + (void)memset(sp, 0, sizeof *sp); + + sp->se_flags = SE_PRESENT; + sp->se_index = session_index; + + (void)asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name); + if (!sp->se_device) + return NULL; + + if (setupargv(sp, typ) == 0) { + free_session(sp); + return NULL; + } + + sp->se_next = NULL; + if (sprev == NULL) { + sessions = sp; + sp->se_prev = NULL; + } else { + sprev->se_next = sp; + sp->se_prev = sprev; + } + + return sp; +} + +/* + * Calculate getty and if useful window argv vectors. + */ +static int +setupargv(session_t *sp, struct ttyent *typ) +{ + + if (sp->se_getty) { + free(sp->se_getty); + free(sp->se_getty_argv); + } + (void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name); + if (!sp->se_getty) + return 0; + sp->se_getty_argv = construct_argv(sp->se_getty); + if (sp->se_getty_argv == NULL) { + warning("can't parse getty for port `%s'", sp->se_device); + free(sp->se_getty); + sp->se_getty = NULL; + return 0; + } + if (typ->ty_window) { + if (sp->se_window) + free(sp->se_window); + sp->se_window = strdup(typ->ty_window); + sp->se_window_argv = construct_argv(sp->se_window); + if (sp->se_window_argv == NULL) { + warning("can't parse window for port `%s'", + sp->se_device); + free(sp->se_window); + sp->se_window = NULL; + return 0; + } + } + return 1; +} + +/* + * Walk the list of ttys and create sessions for each active line. + */ +static state_func_t +read_ttys(void) +{ + int session_index = 0; + session_t *sp, *snext; + struct ttyent *typ; + +#ifdef SUPPORT_UTMPX + if (sessions == NULL) { + struct stat st; + + make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0); + + /* + * If wtmpx is not empty, pick the down time from there + */ + if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) { + struct timeval down_time; + + TIMESPEC_TO_TIMEVAL(&down_time, + st.st_atime > st.st_mtime ? + &st.st_atimespec : &st.st_mtimespec); + make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0); + } + } +#endif + /* + * Destroy any previous session state. + * There shouldn't be any, but just in case... + */ + for (sp = sessions; sp; sp = snext) { +#ifndef LETS_GET_SMALL + if (sp->se_process) + clear_session_logs(sp, 0); +#endif + snext = sp->se_next; + free_session(sp); + } + sessions = NULL; + + if (start_session_db()) { + warning("start_session_db failed, death"); +#ifdef CHROOT + /* If /etc/rc ran in chroot, we want to kill any survivors. */ + if (did_multiuser_chroot) + return (state_func_t)death; + else +#endif /* CHROOT */ + return (state_func_t)single_user; + } + + (void)do_setttyent(); + + /* + * Allocate a session entry for each active port. + * Note that sp starts at 0. + */ + while ((typ = getttyent()) != NULL) + if ((snext = new_session(sp, ++session_index, typ)) != NULL) + sp = snext; + (void)endttyent(); + + return (state_func_t)multi_user; +} + +/* + * Start a window system running. + */ +static void +start_window_system(session_t *sp) +{ + pid_t pid; + sigset_t mask; + + if ((pid = fork()) == -1) { + emergency("can't fork for window system on port `%s': %m", + sp->se_device); + /* hope that getty fails and we can try again */ + return; + } + + if (pid) + return; + + (void)sigemptyset(&mask); + (void)sigprocmask(SIG_SETMASK, &mask, NULL); + + if (setsid() < 0) + emergency("setsid failed (window): %m"); + + (void)execv(sp->se_window_argv[0], sp->se_window_argv); + stall("can't exec window system `%s' for port `%s': %m", + sp->se_window_argv[0], sp->se_device); + _exit(6); +} + +/* + * Start a login session running. + */ +static pid_t +start_getty(session_t *sp) +{ + pid_t pid; + sigset_t mask; + time_t current_time = time(NULL); + + /* + * fork(), not vfork() -- we can't afford to block. + */ + if ((pid = fork()) == -1) { + emergency("can't fork for getty on port `%s': %m", + sp->se_device); + return -1; + } + + if (pid) + return pid; + +#ifdef CHROOT + /* If /etc/rc did proceed inside chroot, we have to try as well. */ + if (did_multiuser_chroot) + if (chroot(rootdir) != 0) { + stall("can't chroot getty `%s' inside `%s': %m", + sp->se_getty_argv[0], rootdir); + _exit(7); + } +#endif /* CHROOT */ + + if (current_time > sp->se_started.tv_sec && + current_time - sp->se_started.tv_sec < GETTY_SPACING) { + warning("getty repeating too quickly on port `%s', sleeping", + sp->se_device); + (void)sleep(GETTY_SLEEP); + } + + if (sp->se_window) { + start_window_system(sp); + (void)sleep(WINDOW_WAIT); + } + + (void)sigemptyset(&mask); + (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); + + (void)execv(sp->se_getty_argv[0], sp->se_getty_argv); + + stall("can't exec getty `%s' for port `%s': %m", + sp->se_getty_argv[0], sp->se_device); + _exit(8); + /*NOTREACHED*/ +} +#ifdef SUPPORT_UTMPX +static void +session_utmpx(const session_t *sp, int add) +{ + const char *name = sp->se_getty ? sp->se_getty : + (sp->se_window ? sp->se_window : ""); + const char *line = sp->se_device + sizeof(_PATH_DEV) - 1; + + make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS, + sp->se_process, &sp->se_started, sp->se_index); +} + +static void +make_utmpx(const char *name, const char *line, int type, pid_t pid, + const struct timeval *tv, int session) +{ + struct utmpx ut; + const char *eline; + + (void)memset(&ut, 0, sizeof(ut)); + (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name)); + ut.ut_type = type; + (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line)); + ut.ut_pid = pid; + if (tv) + ut.ut_tv = *tv; + else + (void)gettimeofday(&ut.ut_tv, NULL); + ut.ut_session = session; + + eline = line + strlen(line); + if ((size_t)(eline - line) >= sizeof(ut.ut_id)) + line = eline - sizeof(ut.ut_id); + (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id)); + + if (pututxline(&ut) == NULL) + warning("can't add utmpx record for `%s': %m", ut.ut_line); + endutxent(); +} + +static char +get_runlevel(const state_t s) +{ + if (s == (state_t)single_user) + return SINGLE_USER; + if (s == (state_t)runcom) + return RUNCOM; + if (s == (state_t)read_ttys) + return READ_TTYS; + if (s == (state_t)multi_user) + return MULTI_USER; + if (s == (state_t)clean_ttys) + return CLEAN_TTYS; + if (s == (state_t)catatonia) + return CATATONIA; + return DEATH; +} + +static void +utmpx_set_runlevel(char old, char new) +{ + struct utmpx ut; + + /* + * Don't record any transitions until we did the first transition + * to read ttys, which is when we are guaranteed to have a read-write + * /var. Perhaps use a different variable for this? + */ + if (sessions == NULL) + return; + + (void)memset(&ut, 0, sizeof(ut)); + (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new); + ut.ut_type = RUN_LVL; + (void)gettimeofday(&ut.ut_tv, NULL); + ut.ut_exit.e_exit = old; + ut.ut_exit.e_termination = new; + if (pututxline(&ut) == NULL) + warning("can't add utmpx record for `runlevel': %m"); + endutxent(); +} +#endif /* SUPPORT_UTMPX */ + +#endif /* LETS_GET_SMALL */ + +/* + * Collect exit status for a child. + * If an exiting login, start a new login running. + */ +static void +collect_child(pid_t pid, int status) +{ +#ifndef LETS_GET_SMALL + session_t *sp, *sprev, *snext; + + if (! sessions) + return; + + if ((sp = find_session(pid)) == NULL) + return; + + clear_session_logs(sp, status); + del_session(sp); + sp->se_process = 0; + + if (sp->se_flags & SE_SHUTDOWN) { + if ((sprev = sp->se_prev) != NULL) + sprev->se_next = sp->se_next; + else + sessions = sp->se_next; + if ((snext = sp->se_next) != NULL) + snext->se_prev = sp->se_prev; + free_session(sp); + return; + } + + if ((pid = start_getty(sp)) == -1) { + /* serious trouble */ + requested_transition = clean_ttys; + return; + } + + sp->se_process = pid; + (void)gettimeofday(&sp->se_started, NULL); + add_session(sp); +#endif /* LETS_GET_SMALL */ +} + +/* + * Catch a signal and request a state transition. + */ +static void +transition_handler(int sig) +{ + + switch (sig) { +#ifndef LETS_GET_SMALL + case SIGHUP: + requested_transition = clean_ttys; + break; + case SIGTERM: + requested_transition = death; + break; + case SIGTSTP: + requested_transition = catatonia; + break; +#endif /* LETS_GET_SMALL */ + default: + requested_transition = 0; + break; + } +} + +#ifndef LETS_GET_SMALL +/* + * Take the system multiuser. + */ +static state_func_t +multi_user(void) +{ + pid_t pid; + int status; + session_t *sp; + + requested_transition = 0; + + /* + * If the administrator has not set the security level to -1 + * to indicate that the kernel should not run multiuser in secure + * mode, and the run script has not set a higher level of security + * than level 1, then put the kernel into secure mode. + */ + if (getsecuritylevel() == 0) + setsecuritylevel(1); + + for (sp = sessions; sp; sp = sp->se_next) { + if (sp->se_process) + continue; + if ((pid = start_getty(sp)) == -1) { + /* serious trouble */ + requested_transition = clean_ttys; + break; + } + sp->se_process = pid; + (void)gettimeofday(&sp->se_started, NULL); + add_session(sp); + } + + while (!requested_transition) + if ((pid = waitpid(-1, &status, 0)) != -1) + collect_child(pid, status); + + return (state_func_t)requested_transition; +} + +/* + * This is an n-squared algorithm. We hope it isn't run often... + */ +static state_func_t +clean_ttys(void) +{ + session_t *sp, *sprev; + struct ttyent *typ; + int session_index = 0; + int devlen; + + for (sp = sessions; sp; sp = sp->se_next) + sp->se_flags &= ~SE_PRESENT; + + (void)do_setttyent(); + + devlen = sizeof(_PATH_DEV) - 1; + while ((typ = getttyent()) != NULL) { + ++session_index; + + for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next) + if (strcmp(typ->ty_name, sp->se_device + devlen) == 0) + break; + + if (sp) { + sp->se_flags |= SE_PRESENT; + if (sp->se_index != session_index) { + warning("port `%s' changed utmp index from " + "%d to %d", sp->se_device, sp->se_index, + session_index); + sp->se_index = session_index; + } + if ((typ->ty_status & TTY_ON) == 0 || + typ->ty_getty == 0) { + sp->se_flags |= SE_SHUTDOWN; + if (sp->se_process != 0) + (void)kill(sp->se_process, SIGHUP); + continue; + } + sp->se_flags &= ~SE_SHUTDOWN; + if (setupargv(sp, typ) == 0) { + warning("can't parse getty for port `%s'", + sp->se_device); + sp->se_flags |= SE_SHUTDOWN; + if (sp->se_process != 0) + (void)kill(sp->se_process, SIGHUP); + } + continue; + } + + (void)new_session(sprev, session_index, typ); + } + + (void)endttyent(); + + for (sp = sessions; sp; sp = sp->se_next) + if ((sp->se_flags & SE_PRESENT) == 0) { + sp->se_flags |= SE_SHUTDOWN; + if (sp->se_process != 0) + (void)kill(sp->se_process, SIGHUP); + } + + return (state_func_t)multi_user; +} + +/* + * Block further logins. + */ +static state_func_t +catatonia(void) +{ + session_t *sp; + + for (sp = sessions; sp; sp = sp->se_next) + sp->se_flags |= SE_SHUTDOWN; + + return (state_func_t)multi_user; +} +#endif /* LETS_GET_SMALL */ + +/* + * Note SIGALRM. + */ +static void +/*ARGSUSED*/ +alrm_handler(int sig) +{ + + clang = 1; +} + +#ifndef LETS_GET_SMALL +/* + * Bring the system down to single user. + */ +static state_func_t +death(void) +{ + session_t *sp; + int i, status; + pid_t pid; + static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL }; + + for (sp = sessions; sp; sp = sp->se_next) + sp->se_flags |= SE_SHUTDOWN; + + /* NB: should send a message to the session logger to avoid blocking. */ +#ifdef SUPPORT_UTMPX + logwtmpx("~", "shutdown", "", 0, INIT_PROCESS); +#endif +#ifdef SUPPORT_UTMP + logwtmp("~", "shutdown", ""); +#endif + + for (i = 0; i < 3; ++i) { + if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH) + return (state_func_t)single_user; + + clang = 0; + (void)alarm(DEATH_WATCH); + do + if ((pid = waitpid(-1, &status, 0)) != -1) + collect_child(pid, status); + while (clang == 0 && errno != ECHILD); + + if (errno == ECHILD) + return (state_func_t)single_user; + } + + warning("some processes would not die; ps axl advised"); + + return (state_func_t)single_user; +} +#endif /* LETS_GET_SMALL */ + +#ifdef MFS_DEV_IF_NO_CONSOLE + +static int +mfs_dev(void) +{ + /* + * We cannot print errors so we bail out silently... + */ + pid_t pid; + int status; + + /* If we have /dev/console, assume all is OK */ + if (access(_PATH_CONSOLE, F_OK) == 0) + return 0; + +#if 0 /* Useful for testing MAKEDEV */ + /* Mount an mfs over /mnt so we can create a console entry */ + switch ((pid = fork())) { + case 0: + (void)execl(INIT_MOUNT_MFS, "mount_mfs", + "-b", "4096", "-f", "512", + "-s", 64, "-n", 10, + "-p", "0755", + "swap", "/mnt", NULL); + _exit(9); + /*NOTREACHED*/ + + case -1: + return(-1); + + default: + if (waitpid(pid, &status, 0) == -1) + return(-1); + if (status != 0) + return(-1); + break; + } + + { + dev_t dev; +#ifdef CPU_CONSDEV + static int name[2] = { CTL_MACHDEP, CPU_CONSDEV }; + size_t olen; + olen = sizeof(dev); + if (sysctl(name, sizeof(name) / sizeof(name[0]), &dev, &olen, + NULL, 0) == -1) +#endif + dev = makedev(0, 0); + + /* Make a console for us, so we can see things happening */ + if (mknod("/mnt/console", 0666 | S_IFCHR, dev) == -1) + return(-1); + (void)freopen("/mnt/console", "a", stderr); + } + +#endif + + /* Run the makedev script to create devices */ + switch ((pid = fork())) { + case 0: + (void)dup2(2, 1); /* Give the script stdout */ + if (chdir("/dev") == 0) + (void)execl(INIT_BSHELL, "sh", + access("./MAKEDEV", X_OK) == 0 + ? "./MAKEDEV" : "/etc/MAKEDEV", + "-MM", "init", NULL); + _exit(10); + /* NOTREACHED */ + + case -1: + break; + + default: + if (waitpid(pid, &status, 0) == -1) + break; + if (status != 0) + warn("MAKEDEV exit status %d\n", status); + /* + * If /dev/console got created, then return 0 + * regardless of MAKEDEV exit status. + */ + if (access(_PATH_CONSOLE, F_OK) == 0) + return 0; + _exit(11); + } + warn("Unable to run MAKEDEV"); + _exit(12); +} +#endif + +#ifndef LETS_GET_SMALL +static int +do_setttyent(void) +{ + (void)endttyent(); +#ifdef CHROOT + if (did_multiuser_chroot) { + char path[PATH_MAX]; + + (void)snprintf(path, sizeof(path), "%s/%s", rootdir, _PATH_TTYS); + + return setttyentpath(path); + } else +#endif /* CHROOT */ + return setttyent(); +} +#endif + +#if !defined(LETS_GET_SMALL) && defined(CHROOT) + +static int +createsysctlnode(void) +{ +#ifndef __minix + struct sysctlnode node; + int mib[2]; + size_t len; + + /* + * Create top-level dynamic sysctl node. Its child nodes will only + * be readable by the superuser, since regular mortals should not + * care ("Sssh, it's a secret!"). + */ + len = sizeof(struct sysctlnode); + mib[0] = CTL_CREATE; + + (void)memset(&node, 0, len); + node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | + CTLFLAG_PRIVATE | CTLTYPE_NODE; + node.sysctl_num = CTL_CREATE; + (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "init"); + if (sysctl(&mib[0], 1, &node, &len, &node, len) == -1) { + warning("could not create init node: %m"); + return -1; + } + + /* + * Create second level dynamic node capable of holding pathname. + * Provide "/" as the default value. + */ + len = sizeof(struct sysctlnode); + mib[0] = node.sysctl_num; + mib[1] = CTL_CREATE; + + (void)memset(&node, 0, len); + node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE | + CTLTYPE_STRING | CTLFLAG_OWNDATA; + node.sysctl_size = _POSIX_PATH_MAX; + node.sysctl_data = __UNCONST("/"); + node.sysctl_num = CTL_CREATE; + (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "root"); + if (sysctl(&mib[0], 2, NULL, NULL, &node, len) == -1) { + warning("could not create init.root node: %m"); + return -1; + } + +#endif + + return 0; +} + +static int +shouldchroot(void) +{ +#ifndef __minix + struct sysctlnode node; + size_t len, cnt; + int mib; + + len = sizeof(struct sysctlnode); + + if (sysctlbyname("init.root", rootdir, &len, NULL, 0) == -1) { + warning("could not read init.root: %m"); + + /* Child killed our node. Recreate it. */ + if (errno == ENOENT) { + /* Destroy whatever is left, recreate from scratch. */ + if (sysctlnametomib("init", &mib, &cnt) != -1) { + (void)memset(&node, 0, sizeof(node)); + node.sysctl_flags = SYSCTL_VERSION; + node.sysctl_num = mib; + mib = CTL_DESTROY; + + (void)sysctl(&mib, 1, NULL, NULL, &node, + sizeof(node)); + } + + (void)createsysctlnode(); + } + + /* We certainly won't chroot. */ + return 0; + } + + if (rootdir[len] != '\0' || strlen(rootdir) != len - 1) { + warning("init.root is not a string"); + return 0; + } + + if (strcmp(rootdir, "/") == 0) + return 0; + return 1; +#else + return 0; +#endif +} + +#endif /* !LETS_GET_SMALL && CHROOT */ diff --git a/sbin/init/pathnames.h b/sbin/init/pathnames.h new file mode 100644 index 000000000..222e35084 --- /dev/null +++ b/sbin/init/pathnames.h @@ -0,0 +1,40 @@ +/* $NetBSD: pathnames.h,v 1.6 2003/08/07 10:04:25 agc Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Donn Seeley at Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 + */ + +#include + +#define _PATH_SLOGGER "/sbin/session_logger" +#define _PATH_RUNCOM "/etc/rc" diff --git a/sbin/reboot/Makefile b/sbin/reboot/Makefile new file mode 100644 index 000000000..d46104486 --- /dev/null +++ b/sbin/reboot/Makefile @@ -0,0 +1,14 @@ +# $NetBSD: Makefile,v 1.18 2002/08/02 15:05:57 wiz Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/5/93 + +PROG= reboot +DPADD= ${LIBUTIL} +LDADD= -lutil +CPPFLAGS+= -DSUPPORT_UTMP -DSUPPORT_UTMPX +MAN= reboot.8 +MLINKS= reboot.8 halt.8 \ + reboot.8 poweroff.8 +LINKS= ${BINDIR}/reboot ${BINDIR}/halt \ + ${BINDIR}/reboot ${BINDIR}/poweroff + +.include diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8 new file mode 100644 index 000000000..c4db95659 --- /dev/null +++ b/sbin/reboot/reboot.8 @@ -0,0 +1,168 @@ +.\" $NetBSD: reboot.8,v 1.29 2011/02/16 19:32:26 wiz Exp $ +.\" +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)reboot.8 8.1 (Berkeley) 6/9/93 +.\" +.Dd February 16, 2011 +.Dt REBOOT 8 +.Os +.Sh NAME +.Nm reboot , +.Nm poweroff , +.Nm halt +.Nd restarting, powering down and stopping the system +.Sh SYNOPSIS +.Nm halt +.Op Fl dlnpqvxz +.Nm poweroff +.Op Fl dlnqvxz +.Nm +.Op Fl dlnqvxz +.Op Ar arg ... +.Sh DESCRIPTION +The +.Nm poweroff , +.Nm halt +and +.Nm +utilities flush the file system cache to disk, send all running processes +a +.Dv SIGTERM , +wait for up to 30 seconds for them to die, send a +.Dv SIGKILL +to the survivors and, respectively, power down, halt or restart the system. +The action is logged, including entering a shutdown record into the login +accounting file and sending a message via +.Xr syslog 3 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl d +Create a dump before halting or restarting. +This option is useful for debugging system dump procedures or +capturing the state of a corrupted or misbehaving system. +.It Fl l +Suppress sending a message via +.Xr syslog 3 +before halting or restarting. +.It Fl n +Do not flush the file system cache. +This option should be used with extreme caution. +It can be used if a disk or a processor is on fire. +.It Fl p +Attempt to powerdown the system. +If the powerdown fails, or the system does not support +software powerdown, the system will halt. +This option is only valid for +.Nm halt . +.It Fl v +To enable verbose messages on the console, pass the +.Xr boothowto 9 +flag +.Dv AB_VERBOSE +to +.Xr reboot 2 . +.It Fl x +To enable debugging messages on the console, pass the +.Xr boothowto 9 +flag +.Dv AB_DEBUG +to +.Xr reboot 2 . +.It Fl z +To silence some shutdown messages on the console, pass the +.Xr boothowto 9 +flag +.Dv AB_SILENT +to +.Xr reboot 2 . +.It Fl q +Do not give processes a chance to shut down before halting or restarting. +This option should not normally be used. +.El +.Pp +If there are any arguments passed to +.Nm reboot +they are concatenated with spaces and passed as +.Fa bootstr +to the +.Xr reboot 2 +system call. +The string is passed to the firmware on platforms that support it. +.Pp +Normally, the +.Xr shutdown 8 +utility is used when the system needs to be halted or restarted, giving +users advance warning of their impending doom. +.Sh SEE ALSO +.Xr reboot 2 , +.Xr syslog 3 , +.Xr utmp 5 , +.Xr boot 8 , +.Xr init 8 , +.Xr rescue 8 , +.Xr shutdown 8 , +.Xr sync 8 +.Sh HISTORY +A +.Nm +command appeared in +.At v6 . +.Pp +The +.Nm poweroff +command first appeared in +.Nx 1.5 . +.Sh CAVEATS +Once the command has begun its work, stopping it before it completes +will probably result in a system so crippled it must be +physically reset. +To prevent premature termination, the command +blocks many signals early in its execution. +However, nothing can defend against deliberate attempts to evade this. +.Pp +This command will stop the system without running any +.Xr shutdown 8 +scripts. +Amongst other things, this means that swapping will not be +disabled so that +.Xr raid 4 +can shutdown cleanly. +You should normally use +.Xr shutdown 8 +unless you are running in single user mode. +.Sh BUGS +The single user shell will ignore the +.Dv SIGTERM +signal. +To avoid waiting for the timeout when +rebooting or halting from the single user shell, you have to +.Ic exec reboot +or +.Ic exec halt . diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c new file mode 100644 index 000000000..30a4fc16a --- /dev/null +++ b/sbin/reboot/reboot.c @@ -0,0 +1,264 @@ +/* $NetBSD: reboot.c,v 1.39 2011/08/27 18:46:19 joerg Exp $ */ + +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__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] [-- ]\n", + getprogname(), pflag); + exit(1); +} diff --git a/sbin/shutdown/Makefile b/sbin/shutdown/Makefile new file mode 100644 index 000000000..f6b50fce4 --- /dev/null +++ b/sbin/shutdown/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.11 2009/04/11 07:58:13 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/5/93 + +USE_FORT?=yes # setuid +PROG= shutdown +MAN= shutdown.8 +BINOWN= root +BINGRP= operator +BINMODE=4554 + +.if defined(__MINIX) +WARNS=2 +.endif + +.include diff --git a/sbin/shutdown/pathnames.h b/sbin/shutdown/pathnames.h new file mode 100644 index 000000000..42a33bd84 --- /dev/null +++ b/sbin/shutdown/pathnames.h @@ -0,0 +1,45 @@ +/* $NetBSD: pathnames.h,v 1.9 2004/08/19 22:30:10 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 + */ + +#include + +#define _PATH_FASTBOOT "/fastboot" +#ifdef RESCUEDIR +#define _PATH_HALT RESCUEDIR "/halt" +#define _PATH_REBOOT RESCUEDIR "/reboot" +#else +#define _PATH_HALT "/sbin/halt" +#define _PATH_REBOOT "/sbin/reboot" +#endif +#define _PATH_WALL "/usr/bin/wall" +#define _PATH_RCSHUTDOWN "/etc/rc.shutdown" diff --git a/sbin/shutdown/shutdown.8 b/sbin/shutdown/shutdown.8 new file mode 100644 index 000000000..8f3b7d524 --- /dev/null +++ b/sbin/shutdown/shutdown.8 @@ -0,0 +1,243 @@ +.\" $NetBSD: shutdown.8,v 1.31 2011/10/04 07:25:34 dholland Exp $ +.\" +.\" Copyright (c) 1988, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)shutdown.8 8.2 (Berkeley) 4/27/95 +.\" +.Dd October 4, 2011 +.Dt SHUTDOWN 8 +.Os +.Sh NAME +.Nm shutdown +.Nd close down the system at a given time +.Sh SYNOPSIS +.Nm +.Op Fl Ddfhknprvxz +.Op Fl b Ar bootstr +.Ar time +.Op Ar message ... | Ar - +.Sh DESCRIPTION +.Nm +provides an automated shutdown procedure for super-users +to nicely notify users when the system is shutting down, +saving them from system administrators, hackers, and gurus, who +would otherwise not bother with such niceties. +.Pp +Available friendlinesses: +.Bl -tag -width bootstr +.It Fl b Ar bootstr +The given +.Ar bootstr +is passed to +.Xr reboot 8 +for the benefit of those systems that can pass boot arguments to the +firmware. +Currently, this only affects sun3 and sparc machines. +.It Fl d +.Nm +will pass the +.Fl d +flag to +.Xr reboot 8 +or +.Xr halt 8 +to request a kernel core dump. +If neither the +.Fl h +or +.Fl r +flags are specified, then +.Fl d +also implies +.Fl r . +.It Fl f +.Nm +arranges, in the manner of +.Xr fastboot 8 , +for the file systems +.Em not to be +checked on reboot. +.It Fl h +The system is halted at the specified +.Ar time , +using +.Xr halt 8 . +.It Fl k +Kick everybody off. +The +.Fl k +option +does not actually halt the system, but leaves the +system multi-user with logins disabled (for all but super-user). +.It Fl n +Prevent the normal +.Xr sync 2 +before stopping. +.It Fl p +The system is powered down at the specified +.Ar time , +using +.Xr poweroff 8 . +If the powerdown fails, or the system does not support software powerdown, +the system will simply halt instead. +.It Fl r +The system is rebooted at the specified +.Ar time , +using +.Xr reboot 8 . +.It Fl v +To enable verbose messages on the console, pass +.Fl v +to +.Xr reboot 8 +or +.Xr halt 8 . +.It Fl x +To enable debugging messages on the console, pass +.Fl x +to +.Xr reboot 8 +or +.Xr halt 8 . +.It Fl z +To silence some shutdown messages on the console, pass +.Fl z +to +.Xr reboot 8 +or +.Xr halt 8 . +.It Fl D +Prevents +.Nm +from detaching from the tty with +.Xr fork 2 Ns / +.Xr exit 3 . +.It Ar time +.Ar Time +is the time at which +.Nm +will bring the system down and +may be the word +.Ar now +or a future time in one of two formats: +.Ar +number , +or +.Ar [[[[[cc]yy]mm]dd]hh]mm , +where the century, year, month, day, and hour may be defaulted +to the current system values. +The first form brings the system down +.Ar number +minutes from the current time; the second brings the system down at the +absolute time specified. +If the century is not specified, it defaults to 1900 for years between 69 +and 99, or 2000 for years between 0 and 68. +A leading zero in the +.Dq yy +value is +.Em not +optional. +.It Ar message ... +Any other arguments comprise the warning message that is broadcast +to users currently logged into the system. +.It Ar - +If +.Ar - +is supplied as the only argument after the time, the warning message is read +from the standard input. +.El +.Sh BEHAVIOR +.Pp +At intervals, becoming more frequent as apocalypse approaches +and starting at ten hours before shutdown, warning messages are displayed +on the terminals of all users logged in. +Five minutes before shutdown, or immediately if shutdown is in less +than 5 minutes, logins are disabled by creating +.Pa /etc/nologin +and copying the warning message there. +If this file exists when a user attempts to log in, +.Xr login 1 +prints its contents and exits. +The file is removed just before +.Nm +exits. +.Pp +At shutdown time, a message is written in the system log containing the +time of shutdown, who initiated the shutdown, and the reason. +Next a message is printed announcing the start of the system shutdown hooks. +Then the shutdown hooks in +.Pa /etc/rc.shutdown +are run, and a message is printed indicating that they have completed. +After a short delay, +.Nm +runs +.Xr halt 8 +or +.Xr reboot 8 , +or sends a terminate +signal to +.Xr init 8 +to bring the system down to single-user mode, depending on the choice +of options. +.Pp +The time of the shutdown and the warning message are placed in +.Pa /etc/nologin +and should be used to tell the users why the system is +going down, when it will be back up, and to share any other pertinent +information. +.Sh FILES +.Bl -tag -width /etc/rc.shutdown -compact +.It Pa /etc/nologin +tells +.Xr login 1 +not to let anyone log in +.It Pa /fastboot +tells +.Xr rc 8 +not to run +.Xr fsck 8 +when rebooting +.It Pa /etc/rc.shutdown +System shutdown commands +.El +.Sh SEE ALSO +.Xr login 1 , +.Xr wall 1 , +.Xr fastboot 8 , +.Xr halt 8 , +.Xr init 8 , +.Xr poweroff 8 , +.Xr reboot 8 , +.Xr rescue 8 +.Sh BACKWARD COMPATIBILITY +The hours and minutes in the second time format may be separated by +a colon (``:'') for backward compatibility. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.0 . diff --git a/sbin/shutdown/shutdown.c b/sbin/shutdown/shutdown.c new file mode 100644 index 000000000..bd9d0262c --- /dev/null +++ b/sbin/shutdown/shutdown.c @@ -0,0 +1,592 @@ +/* $NetBSD: shutdown.c,v 1.55 2011/08/27 18:54:39 joerg Exp $ */ + +/* + * Copyright (c) 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/servers/Makefile b/servers/Makefile index b4ce396ea..a756094ed 100644 --- a/servers/Makefile +++ b/servers/Makefile @@ -5,11 +5,11 @@ .if ${MKIMAGEONLY} == "yes" -SUBDIR= ds init input mfs pfs pm rs sched vfs vm +SUBDIR= ds input mfs pfs pm rs sched vfs vm .else -SUBDIR= ds ext2 inet init input ipc is iso9660fs \ +SUBDIR= ds ext2 inet input ipc is iso9660fs \ mfs pfs pm procfs rs sched vfs vm devman .if ${MACHINE_ARCH} == "i386" diff --git a/servers/init/Makefile b/servers/init/Makefile deleted file mode 100644 index 95d47b394..000000000 --- a/servers/init/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Makefile for the init program (INIT) -.include - -PROG= init -SRCS= init.c - -MAN= - -BINDIR?= /usr/sbin - -.include diff --git a/servers/init/init.c b/servers/init/init.c deleted file mode 100644 index abfe038d3..000000000 --- a/servers/init/init.c +++ /dev/null @@ -1,475 +0,0 @@ -/* This process is the father (mother) of all Minix user processes. When - * Minix comes up, this is process number 2, and has a pid of 1. It - * executes the /etc/rc shell file, and then reads the /etc/ttytab file to - * determine which terminals need a login process. - * - * If the files /usr/adm/wtmp and /etc/utmp exist and are writable, init - * (with help from login) will maintain login accounting. Sending a - * signal 1 (SIGHUP) to init will cause it to rescan /etc/ttytab and start - * up new shell processes if necessary. It will not, however, kill off - * login processes for lines that have been turned off; do this manually. - * Signal 15 (SIGTERM) makes init stop spawning new processes, this is - * used by shutdown and friends when they are about to close the system - * down. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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; -} diff --git a/servers/mfs/super.c b/servers/mfs/super.c index cb47f8271..c360bdfb3 100644 --- a/servers/mfs/super.c +++ b/servers/mfs/super.c @@ -258,9 +258,13 @@ int read_super(struct super_block *sp) magic = sp->s_magic; /* determines file system type */ + if(magic == SUPER_V2 || magic == SUPER_MAGIC) { + printf("MFS: only supports V3 filesystems.\n"); + return EINVAL; + } + /* Get file system version and type - only support v3. */ if(magic != SUPER_V3) { - printf("MFS: only supports V3 filesystems.\n"); return EINVAL; } version = V3; diff --git a/servers/pm/misc.c b/servers/pm/misc.c index 7676901e4..0e409e018 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -13,11 +13,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -213,10 +213,9 @@ int do_reboot() /* See how the system should be aborted. */ abort_flag = (unsigned) m_in.PM_REBOOT_HOW; - if (abort_flag >= RBT_INVALID) return(EINVAL); /* notify readclock (some arm systems power off via RTC alarms) */ - if (abort_flag == RBT_POWEROFF) { + if (abort_flag & RB_POWERDOWN) { endpoint_t readclock_ep; if (ds_retrieve_label_endpt("readclock.drv", &readclock_ep) == OK) { message m; /* no params to set, nothing we can do if it fails */ diff --git a/servers/vfs/device.c b/servers/vfs/device.c index 20f9b40da..9e45d425c 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -267,6 +268,13 @@ int cdev_io( if ((dp = cdev_get(dev, &minor_dev)) == NULL) return(EIO); + /* Handle TIOCSCTTY ioctl: set controlling tty. + * TODO: cleaner implementation work in progress. + */ + if (op == CDEV_IOCTL && bytes == TIOCSCTTY && major(dev) == TTY_MAJOR) { + fp->fp_tty = dev; + } + /* Create a grant for the buffer provided by the user process. */ gid = make_grant(dp->dmap_driver, proc_e, op, buf, bytes); diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 20903c571..423f170c6 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -14,6 +14,7 @@ SUBDIR= asa \ fsplit ftp genassym getopt \ head hexdump id indent infocmp join jot \ lam ldd leave \ + last \ lock login logname lorder m4 \ machine make man menuc mesg \ mkdep mkfifo mkstr mktemp \ @@ -30,8 +31,9 @@ SUBDIR= asa \ toproto \ uniq units unvis unzip users \ uuidgen vis \ + uniq uname units unzip users \ + wall wc what whatis who whois \ \ - wc what who whois \ write xargs xinstall xstr yes .if !defined(__MINIX) diff --git a/usr.bin/last/Makefile b/usr.bin/last/Makefile new file mode 100644 index 000000000..25348f643 --- /dev/null +++ b/usr.bin/last/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.7 2004/11/19 21:41:25 christos Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= last +CPPFLAGS+=-DSUPPORT_UTMPX -DSUPPORT_UTMP + +LDADD=-lutil +DPADD=${LIBUTIL} + +.include diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1 new file mode 100644 index 000000000..80c440aa7 --- /dev/null +++ b/usr.bin/last/last.1 @@ -0,0 +1,161 @@ +.\" $NetBSD: last.1,v 1.20 2012/05/12 14:52:57 reed Exp $ +.\" +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)last.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd October 18, 2011 +.Dt LAST 1 +.Os +.Sh NAME +.Nm last +.Nd indicate last logins of users and ttys +.Sh SYNOPSIS +.Nm +.Op Fl Ns Ar n +.Op Fl nTx +.Op Fl f Ar file +.Op Fl H Ar hostsize +.Op Fl h Ar host +.Op Fl L Ar linesize +.Op Fl N Ar namesize +.Op Fl t Ar tty +.Op user ... +.Sh DESCRIPTION +.Nm +will list the sessions of specified +.Ar users , +.Ar ttys , +and +.Ar hosts , +in reverse time order. +Each line of output contains +the user name, the tty from which the session was conducted, any +hostname, the start and stop times for the session, and the duration +of the session. +If the session is still continuing or was cut short by +a crash or shutdown, +.Nm +will so indicate. +.Pp +The following options are available: +.Pp +.Bl -tag -width xHxhostsizexx +.It Fl Ar n +Limits the report to +.Ar n +lines. +.It Fl f Ar file +.Nm +reads the file +.Ar file +instead of the default, +.Pa /var/log/wtmpx +or +.Pa /var/log/wtmp . +If the file ends with +.Sq x , +it is treated as a +.Xr utmpx 5 +format file, else it is treated as a +.Xr utmp 5 +format file. +If the file is ``-'', standard input is used. +.It Fl H Ar hostsize +Use the provided hostsize as the width to format the host name field. +.It Fl h Ar host +.Ar Host +names may be names or internet numbers. +.It Fl L Ar linesize +Use the provided linesize as the width to format the tty field. +.It Fl N Ar namesize +Use the provided namesize as the width to format the login name field. +.It Fl n +Print host addresses numerically. +This option works only on +.Xr wtmpx 5 +entries, +and prints nothing on +.Xr wtmp 5 +entries. +.It Fl T +Display better time information, including the year and seconds. +.It Fl t Ar tty +Specify the +.Ar tty . +Tty names may be given fully or abbreviated, for example, +.Dq Li "last -t 03" +is equivalent to +.Dq Li "last -t tty03" . +.It Fl x +Assume that the file given is in +.Xr wtmpx 5 +format, even if the filename does not end with an +.Sq x . +Also useful when reading such format from standard input. +.El +.Pp +If multiple arguments are given, the information which applies to any of the +arguments is printed, e.g., +.Dq Li "last root -t console" +would list all of +.Dq Li root Ns 's +sessions as well as all sessions on the console terminal. +If no users, hostnames, or terminals are specified, +.Nm +prints a record of all logins and logouts. +.Pp +The pseudo-user +.Ar reboot +logs in at reboots of the system, thus +.Dq Li last reboot +will give an indication of mean time between reboot. +.Pp +If +.Nm +is interrupted, it indicates to what date the search has progressed. +If interrupted with a quit signal +.Nm +indicates how far the search has progressed and then continues. +.Sh FILES +.Bl -tag -width /var/log/wtmpx -compact +.It Pa /var/log/wtmp +login data base +.It Pa /var/log/wtmpx +login data base +.El +.Sh SEE ALSO +.Xr lastcomm 1 , +.Xr utmp 5 , +.Xr utmpx 5 , +.Xr ac 8 , +.Xr lastlogin 8 +.Sh HISTORY +.Nm +appeared in +.Bx 1 . diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c new file mode 100644 index 000000000..19cba1081 --- /dev/null +++ b/usr.bin/last/last.c @@ -0,0 +1,405 @@ +/* $NetBSD: last.c,v 1.36 2012/03/15 03:04:05 dholland Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SUPPORT_UTMPX +#include +#endif +#ifdef SUPPORT_UTMP +#include +#endif +#include + +#ifndef UT_NAMESIZE +#define UT_NAMESIZE 8 +#define UT_LINESIZE 8 +#define UT_HOSTSIZE 16 +#endif +#ifndef SIGNATURE +#define SIGNATURE -1 +#endif + + + +#define NO 0 /* false/no */ +#define YES 1 /* true/yes */ + +#define TBUFLEN 30 /* length of time string buffer */ +#define TFMT "%a %b %d %R" /* strftime format string */ +#define LTFMT "%a %b %d %Y %T" /* strftime long format string */ +#define TFMTS "%R" /* strftime format string - time only */ +#define LTFMTS "%T" /* strftime long format string - " */ + +/* fmttime() flags */ +#define FULLTIME 0x1 /* show year, seconds */ +#define TIMEONLY 0x2 /* show time only, not date */ +#define GMT 0x4 /* show time at GMT, for offsets only */ + +#define MAXUTMP 1024 + +typedef struct arg { + const char *name; /* argument */ +#define HOST_TYPE -2 +#define TTY_TYPE -3 +#define USER_TYPE -4 + int type; /* type of arg */ + struct arg *next; /* linked list pointer */ +} ARG; +static ARG *arglist; /* head of linked list */ + +typedef struct ttytab { + time_t logout; /* log out time */ + char tty[128]; /* terminal name */ + struct ttytab *next; /* linked list pointer */ +} TTY; +static TTY *ttylist; /* head of linked list */ + +static time_t currentout; /* current logout value */ +static long maxrec; /* records to display */ +static int fulltime = 0; /* Display seconds? */ +static int xflag; /* Assume file is wtmpx format */ + +static void addarg(int, const char *); +static TTY *addtty(const char *); +static void hostconv(char *); +static const char *ttyconv(char *); +#ifdef SUPPORT_UTMPX +static void wtmpx(const char *, int, int, int, int); +#endif +#ifdef SUPPORT_UTMP +static void wtmp(const char *, int, int, int, int); +#endif +static char *fmttime(time_t, int); +__dead static void usage(void); + +static +void usage(void) +{ + (void)fprintf(stderr, "usage: %s [-#%s] [-nTx] [-f file]" + " [-H hostsize] [-h host] [-L linesize]\n" + "\t [-N namesize] [-t tty] [user ...]\n", getprogname(), +#ifdef NOTYET_SUPPORT_UTMPX + "w" +#else + "" +#endif + ); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + int ch; + char *p; + const char *file = NULL; + int namesize = UT_NAMESIZE; + int linesize = UT_LINESIZE; + int hostsize = UT_HOSTSIZE; + int numeric = 0; + + maxrec = -1; + + while ((ch = getopt(argc, argv, "0123456789f:H:h:L:nN:Tt:x")) != -1) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: last was originally designed to take + * a number after a dash. + */ + if (maxrec == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + maxrec = atol(++p); + else if (optind < argc) + maxrec = atol(argv[optind] + 1); + else + usage(); + if (!maxrec) + return 0; + } + break; + case 'f': + file = optarg; + if ('\0' == file[0]) + usage(); + break; + case 'H': + hostsize = atoi(optarg); + if (hostsize < 1) + usage(); + break; + case 'h': + hostconv(optarg); + addarg(HOST_TYPE, optarg); + break; + case 'L': + linesize = atoi(optarg); + if (linesize < 1) + usage(); + break; + case 'N': + namesize = atoi(optarg); + if (namesize < 1) + usage(); + break; + case 'n': + numeric = 1; + break; + case 'T': + fulltime = 1; + break; + case 't': + addarg(TTY_TYPE, ttyconv(optarg)); + break; + case 'x': + xflag = 1; + break; + case '?': + default: + usage(); + } + + if (argc) { + setlinebuf(stdout); + for (argv += optind; *argv; ++argv) { +#define COMPATIBILITY +#ifdef COMPATIBILITY + /* code to allow "last p5" to work */ + addarg(TTY_TYPE, ttyconv(*argv)); +#endif + addarg(USER_TYPE, *argv); + } + } + if (file == NULL) { +#ifdef SUPPORT_UTMPX + if (access(_PATH_WTMPX, R_OK) == 0) + file = _PATH_WTMPX; + else +#endif +#ifdef SUPPORT_UTMP + if (access(_PATH_WTMP, R_OK) == 0) + file = _PATH_WTMP; +#endif + if (file == NULL) +#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP) + errx(EXIT_FAILURE, "Cannot access `%s' or `%s'", _PATH_WTMPX, + _PATH_WTMP); +#elif defined(SUPPORT_UTMPX) + errx(EXIT_FAILURE, "Cannot access `%s'", _PATH_WTMPX); +#elif defined(SUPPORT_UTMP) + errx(EXIT_FAILURE, "Cannot access `%s'", _PATH_WTMP); +#else + errx(EXIT_FAILURE, "No utmp or utmpx support compiled in."); +#endif + } +#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP) + if (file[strlen(file) - 1] == 'x' || xflag) + wtmpx(file, namesize, linesize, hostsize, numeric); + else + wtmp(file, namesize, linesize, hostsize, numeric); +#elif defined(SUPPORT_UTMPX) + wtmpx(file, namesize, linesize, hostsize, numeric); +#elif defined(SUPPORT_UTMP) + wtmp(file, namesize, linesize, hostsize, numeric); +#else + errx(EXIT_FAILURE, "No utmp or utmpx support compiled in."); +#endif + exit(EXIT_SUCCESS); +} + + +/* + * addarg -- + * add an entry to a linked list of arguments + */ +static void +addarg(int type, const char *arg) +{ + ARG *cur; + + if (!(cur = (ARG *)malloc(sizeof(ARG)))) + err(EXIT_FAILURE, "malloc failure"); + cur->next = arglist; + cur->type = type; + cur->name = arg; + arglist = cur; +} + +/* + * addtty -- + * add an entry to a linked list of ttys + */ +static TTY * +addtty(const char *tty) +{ + TTY *cur; + + if (!(cur = (TTY *)malloc(sizeof(TTY)))) + err(EXIT_FAILURE, "malloc failure"); + cur->next = ttylist; + cur->logout = currentout; + memmove(cur->tty, tty, sizeof(cur->tty)); + return (ttylist = cur); +} + +/* + * hostconv -- + * convert the hostname to search pattern; if the supplied host name + * has a domain attached that is the same as the current domain, rip + * off the domain suffix since that's what login(1) does. + */ +static void +hostconv(char *arg) +{ + static int first = 1; + static char *hostdot, name[MAXHOSTNAMELEN + 1]; + char *argdot; + + if (!(argdot = strchr(arg, '.'))) + return; + if (first) { + first = 0; + if (gethostname(name, sizeof(name))) + err(EXIT_FAILURE, "gethostname"); + name[sizeof(name) - 1] = '\0'; + hostdot = strchr(name, '.'); + } + if (hostdot && !strcasecmp(hostdot, argdot)) + *argdot = '\0'; +} + +/* + * ttyconv -- + * convert tty to correct name. + */ +static const char * +ttyconv(char *arg) +{ + char *mval; + + if (!strcmp(arg, "co")) + return ("console"); + /* + * kludge -- we assume that all tty's end with + * a two character suffix. + */ + if (strlen(arg) == 2) { + if (asprintf(&mval, "tty%s", arg) == -1) + err(EXIT_FAILURE, "malloc failure"); + return (mval); + } + if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) + return (&arg[sizeof(_PATH_DEV) - 1]); + return (arg); +} + +/* + * fmttime -- + * return pointer to (static) formatted time string. + */ +static char * +fmttime(time_t t, int flags) +{ + struct tm *tm; + static char tbuf[TBUFLEN]; + + tm = (flags & GMT) ? gmtime(&t) : localtime(&t); + if (tm == NULL) { + strcpy(tbuf, "????"); + return tbuf; + } + strftime(tbuf, sizeof(tbuf), + (flags & TIMEONLY) + ? (flags & FULLTIME ? LTFMTS : TFMTS) + : (flags & FULLTIME ? LTFMT : TFMT), + tm); + return (tbuf); +} + +#ifdef SUPPORT_UTMP +#define TYPE(a) 0 +#define NAMESIZE UT_NAMESIZE +#define LINESIZE UT_LINESIZE +#define HOSTSIZE UT_HOSTSIZE +#define ut_timefld ut_time +#define HAS_UT_SS 0 +#include "want.c" +#undef TYPE /*(a)*/ +#undef NAMESIZE +#undef LINESIZE +#undef HOSTSIZE +#undef ut_timefld +#undef HAS_UT_SS +#endif + +#ifdef SUPPORT_UTMPX +#define utmp utmpx +#define want wantx +#define wtmp wtmpx +#define gethost gethostx +#define buf bufx +#define onintr onintrx +#define TYPE(a) (a)->ut_type +#define NAMESIZE UTX_USERSIZE +#define LINESIZE UTX_LINESIZE +#define HOSTSIZE UTX_HOSTSIZE +#define ut_timefld ut_xtime +#define HAS_UT_SS 1 +#include "want.c" +#endif diff --git a/usr.bin/last/want.c b/usr.bin/last/want.c new file mode 100644 index 000000000..ffd389175 --- /dev/null +++ b/usr.bin/last/want.c @@ -0,0 +1,318 @@ +/* $NetBSD: want.c,v 1.17 2012/03/15 03:04:05 dholland Exp $ */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +static struct utmp *buf; +static time_t seentime; + +static void onintr(int); +static int want(struct utmp *, int); +static const char *gethost(struct utmp *, const char *, int); + +static const char * +/*ARGSUSED*/ +gethost(struct utmp *ut, const char *host, int numeric) +{ +#if HAS_UT_SS == 0 + return numeric ? "" : host; +#else + if (numeric) { + static char hbuf[512]; + hbuf[0] = '\0'; + (void)sockaddr_snprintf(hbuf, sizeof(hbuf), "%a", + (struct sockaddr *)&ut->ut_ss); + return hbuf; + } else + return host; +#endif +} + +#define NULTERM(what) \ + if (check ## what) \ + (void)strlcpy(what ## p = what ## buf, bp->ut_ ## what, \ + sizeof(what ## buf)); \ + else \ + what ## p = bp->ut_ ## what + +/* + * wtmp -- + * read through the wtmp file + */ +static void +wtmp(const char *file, int namesz, int linesz, int hostsz, int numeric) +{ + struct utmp *bp; /* current structure */ + TTY *T; /* tty list entry */ + struct stat stb; /* stat of file for sz */ + off_t offset; + int wfd; + char *ct; + const char *crmsg; + size_t len = sizeof(*buf) * MAXUTMP; + char namebuf[sizeof(bp->ut_name) + 1], *namep; + char linebuf[sizeof(bp->ut_line) + 1], *linep; + char hostbuf[sizeof(bp->ut_host) + 1], *hostp; + int checkname = namesz > (int)sizeof(bp->ut_name); + int checkline = linesz > (int)sizeof(bp->ut_line); + int checkhost = hostsz > (int)sizeof(bp->ut_host); + + if ((buf = malloc(len)) == NULL) + err(EXIT_FAILURE, "Cannot allocate utmp buffer"); + + crmsg = NULL; + + if (!strcmp(file, "-")) { + wfd = STDIN_FILENO; + file = ""; + } else if ((wfd = open(file, O_RDONLY, 0)) < 0) { + err(EXIT_FAILURE, "%s", file); + } + + if (lseek(wfd, 0, SEEK_CUR) < 0) { + const char *dir; + char *tfile; + int tempfd; + ssize_t tlen; + + if (ESPIPE != errno) { + err(EXIT_FAILURE, "lseek"); + } + dir = getenv("TMPDIR"); + if (asprintf(&tfile, "%s/last.XXXXXX", dir ? dir : _PATH_TMP) == -1) + err(EXIT_FAILURE, "asprintf"); + tempfd = mkstemp(tfile); + if (tempfd < 0) { + err(EXIT_FAILURE, "mkstemp"); + } + unlink(tfile); + for (;;) { + tlen = read(wfd, buf, len); + if (tlen < 0) { + err(1, "%s: read", file); + } + if (tlen == 0) { + break; + } + if (write(tempfd, buf, tlen) != tlen) { + err(1, "%s: write", tfile); + } + } + wfd = tempfd; + } + + if (fstat(wfd, &stb) == -1) + err(EXIT_FAILURE, "%s: fstat", file); + if (!S_ISREG(stb.st_mode)) + errx(EXIT_FAILURE, "%s: Not a regular file", file); + + seentime = stb.st_mtime; + (void)signal(SIGINT, onintr); + (void)signal(SIGQUIT, onintr); + + offset = stb.st_size; + /* Ignore trailing garbage or partial record */ + offset -= offset % (off_t) sizeof(*buf); + + while (offset >= (off_t) sizeof(*buf)) { + ssize_t ret, i; + size_t size; + + size = MIN((off_t)len, offset); + offset -= size; /* Always a multiple of sizeof(*buf) */ + ret = pread(wfd, buf, size, offset); + if (ret < 0) { + err(EXIT_FAILURE, "%s: pread", file); + } else if ((size_t) ret < size) { + err(EXIT_FAILURE, "%s: Unexpected end of file", file); + } + + for (i = ret / sizeof(*buf) - 1; i >= 0; i--) { + bp = &buf[i]; + + NULTERM(name); + NULTERM(line); + NULTERM(host); + + seentime = bp->ut_timefld; + + /* + * if the terminal line is '~', the machine stopped. + * see utmp(5) for more info. + */ + if (linep[0] == '~' && !linep[1]) { + /* everybody just logged out */ + for (T = ttylist; T; T = T->next) + T->logout = -bp->ut_timefld; + currentout = -bp->ut_timefld; + crmsg = strncmp(namep, "shutdown", + namesz) ? "crash" : "shutdown"; + if (want(bp, NO)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s\n", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), ct); + if (maxrec != -1 && !--maxrec) + return; + } + continue; + } + /* + * if the line is '{' or '|', date got set; see + * utmp(5) for more info. + */ + if ((linep[0] == '{' || linep[0] == '|') && !linep[1]) { + if (want(bp, NO)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s\n", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), + ct); + if (maxrec && !--maxrec) + return; + } + continue; + } + /* find associated tty */ + for (T = ttylist;; T = T->next) { + if (!T) { + /* add new one */ + T = addtty(linep); + break; + } + if (!strncmp(T->tty, linep, LINESIZE)) + break; + } + if (TYPE(bp) == SIGNATURE) + continue; + if (namep[0] && want(bp, YES)) { + ct = fmttime(bp->ut_timefld, fulltime); + printf("%-*.*s %-*.*s %-*.*s %s ", + namesz, namesz, namep, + linesz, linesz, linep, + hostsz, hostsz, + gethost(bp, hostp, numeric), + ct); + if (!T->logout) + puts(" still logged in"); + else { + time_t delta; /* time difference */ + + if (T->logout < 0) { + T->logout = -T->logout; + printf("- %s", crmsg); + } + else + printf("- %s", + fmttime(T->logout, + fulltime | TIMEONLY)); + delta = T->logout - bp->ut_timefld; + if (delta < SECSPERDAY) + printf(" (%s)\n", + fmttime(delta, + fulltime | TIMEONLY | GMT)); + else + printf(" (%lld+%s)\n", + (long long) + delta / SECSPERDAY, + fmttime(delta, + fulltime | TIMEONLY | GMT)); + } + if (maxrec != -1 && !--maxrec) + return; + } + T->logout = bp->ut_timefld; + } + } + fulltime = 1; /* show full time */ + crmsg = fmttime(seentime, FULLTIME); + if ((ct = strrchr(file, '/')) != NULL) + ct++; + printf("\n%s begins %s\n", ct ? ct : file, crmsg); +} + +/* + * want -- + * see if want this entry + */ +static int +want(struct utmp *bp, int check) +{ + ARG *step; + + if (check) { + /* + * when uucp and ftp log in over a network, the entry in + * the utmp file is the name plus their process id. See + * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. + */ + if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1)) + bp->ut_line[3] = '\0'; + else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1)) + bp->ut_line[4] = '\0'; + } + if (!arglist) + return (YES); + + for (step = arglist; step; step = step->next) + switch(step->type) { + case HOST_TYPE: + if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE)) + return (YES); + break; + case TTY_TYPE: + if (!strncmp(step->name, bp->ut_line, LINESIZE)) + return (YES); + break; + case USER_TYPE: + if (!strncmp(step->name, bp->ut_name, NAMESIZE)) + return (YES); + break; + } + return (NO); +} + +/* + * onintr -- + * on interrupt, we inform the user how far we've gotten + */ +static void +onintr(int signo) +{ + /* FIXME: None of this is allowed in a signal handler */ + printf("\ninterrupted %s\n", fmttime(seentime, FULLTIME)); + if (signo == SIGINT) { + (void)raise_default_signal(signo); + exit(EXIT_FAILURE); + } + (void)fflush(stdout); /* fix required for rsh */ +} diff --git a/usr.bin/wall/Makefile b/usr.bin/wall/Makefile new file mode 100644 index 000000000..bfc92b59b --- /dev/null +++ b/usr.bin/wall/Makefile @@ -0,0 +1,18 @@ +# $NetBSD: Makefile,v 1.10 2007/05/28 12:06:32 tls Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +.include + +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 diff --git a/usr.bin/wall/wall.1 b/usr.bin/wall/wall.1 new file mode 100644 index 000000000..8a9d73557 --- /dev/null +++ b/usr.bin/wall/wall.1 @@ -0,0 +1,74 @@ +.\" $NetBSD: wall.1,v 1.7 2003/08/07 11:17:14 agc Exp $ +.\" +.\" Copyright (c) 1989, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)wall.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd March 27, 2003 +.Dt WALL 1 +.Os +.Sh NAME +.Nm wall +.Nd write a message to users +.Sh SYNOPSIS +.Nm +.Op Fl g Ar group +.Op Ar file +.Sh DESCRIPTION +.Nm +displays the contents of +.Ar file +or, by default, its standard input, on the terminals of all +currently logged in users. +.Pp +Only the super-user can write on the +terminals of users who have chosen +to deny messages or are using a program which +automatically denies messages. +.Bl -tag -width indent +.It Fl g +Send messages to users in this group. +This option may be specified multiple times, and any user in any of the +specified groups will receive the message. +.El +.Sh SEE ALSO +.Xr mesg 1 , +.Xr talk 1 , +.Xr write 1 , +.Xr shutdown 8 +.Sh HISTORY +A +.Nm +command appeared in +.At v7 . +Support for +.Fl g +was added in +.Nx 2.0 +(from +.Ox 2.0 ) . diff --git a/usr.bin/wall/wall.c b/usr.bin/wall/wall.c new file mode 100644 index 000000000..b969964f3 --- /dev/null +++ b/usr.bin/wall/wall.c @@ -0,0 +1,276 @@ +/* $NetBSD: wall.c,v 1.29 2011/09/06 18:45:21 joerg Exp $ */ + +/* + * Copyright (c) 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +}