ubase

suckless linux base utils
git clone git://git.suckless.org/ubase
Log | Files | Refs | README | LICENSE

getty.c (2823B)


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