master xplshn/aruu / cmd / pseudo / getty.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/ioctl.h>
  5#include <sys/stat.h>
  6#include <sys/types.h>
  7
  8#include <fcntl.h>
  9#include <limits.h>
 10#include <signal.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <string.h>
 14#include <unistd.h>
 15#include <utmp.h>
 16
 17#include "config.h"
 18#include "util.h"
 19
 20static char *tty = "/dev/tty1";
 21static char *defaultterm = "linux";
 22
 23static void
 24usage(void)
 25{
 26	eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0);
 27}
 28
 29// ?man getty: set terminal mode
 30// ?man arguments: tty] [term] [cmd] [args...
 31// ?man set terminal line discipline, speed, and mode
 32int
 33main(int argc, char *argv[])
 34{
 35	char term[128], logname[LOGIN_NAME_MAX], c;
 36	char hostname[HOST_NAME_MAX + 1];
 37	char ut_line_buf[UT_LINESIZE + 1];
 38	struct utmp usr;
 39	struct sigaction sa;
 40	FILE *fp;
 41	int fd;
 42	unsigned int i = 0;
 43	ssize_t n;
 44	long pos;
 45
 46	ARGBEGIN {
 47	default:
 48		usage();
 49	} ARGEND;
 50
 51	strlcpy(term, defaultterm, sizeof(term));
 52	if (argc > 0) {
 53		tty = argv[0];
 54		if (argc > 1)
 55			strlcpy(term, argv[1], sizeof(term));
 56	}
 57
 58	sa.sa_handler = SIG_IGN;
 59	sa.sa_flags = 0;
 60	sigemptyset(&sa.sa_mask);
 61	sigaction(SIGHUP, &sa, NULL);
 62
 63	setenv("TERM", term, 1);
 64
 65	setsid();
 66
 67	fd = open(tty, O_RDWR);
 68	if (fd < 0)
 69		eprintf("open %s:", tty);
 70	if (isatty(fd) == 0)
 71		eprintf("%s is not a tty\n", tty);
 72
 73	/* steal the controlling terminal if necessary */
 74	if (ioctl(fd, TIOCSCTTY, (void *)1) != 0)
 75		weprintf("TIOCSCTTY: could not set controlling tty\n");
 76	vhangup();
 77	close(fd);
 78
 79	fd = open(tty, O_RDWR);
 80	if (fd < 0)
 81		eprintf("open %s:", tty);
 82	dup2(fd, 0);
 83	dup2(fd, 1);
 84	dup2(fd, 2);
 85	if (fchown(fd, 0, 0) < 0)
 86		weprintf("fchown %s:", tty);
 87	if (fchmod(fd, 0600) < 0)
 88		weprintf("fchmod %s:", tty);
 89	if (fd > 2)
 90		close(fd);
 91
 92	sa.sa_handler = SIG_DFL;
 93	sa.sa_flags = 0;
 94	sigemptyset(&sa.sa_mask);
 95	sigaction(SIGHUP, &sa, NULL);
 96
 97	/* Clear all utmp entries for this tty */
 98	fp = fopen(UTMP_PATH, "r+");
 99	if (fp) {
100		do {
101			pos = ftell(fp);
102			if (fread(&usr, sizeof(usr), 1, fp) != 1)
103				break;
104			if (usr.ut_line[0] == '\0')
105				continue;
106			memcpy(ut_line_buf, usr.ut_line, UT_LINESIZE);
107			ut_line_buf[UT_LINESIZE] = '\0';
108			if (strcmp(ut_line_buf, tty) != 0)
109				continue;
110			memset(&usr, 0, sizeof(usr));
111			fseek(fp, pos, SEEK_SET);
112			if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
113				break;
114		} while (1);
115		if (ferror(fp))
116			weprintf("%s: I/O error:", UTMP_PATH);
117		fclose(fp);
118	}
119
120	if (argc > 2)
121		return execvp(argv[2], argv + 2);
122
123	if (gethostname(hostname, sizeof(hostname)) == 0)
124		printf("%s ", hostname);
125	printf("login: ");
126	fflush(stdout);
127
128	/* Flush pending input */
129	ioctl(0, TCFLSH, (void *)0);
130	memset(logname, 0, sizeof(logname));
131	while (1) {
132		n = read(0, &c, 1);
133		if (n < 0)
134			eprintf("read:");
135		if (n == 0)
136			return 1;
137		if (i >= sizeof(logname) - 1)
138			eprintf("login name too long\n");
139		if (c == '\n' || c == '\r')
140			break;
141		logname[i++] = c;
142	}
143	if (logname[0] == '-')
144		eprintf("login name cannot start with '-'\n");
145	if (logname[0] == '\0')
146		return 1;
147	return execlp("/bin/login", "login", "-p", logname, NULL);
148}