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 void 19 usage(void) 20 { 21 eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0); 22 } 23 24 static char *tty = "/dev/tty1"; 25 static char *defaultterm = "linux"; 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 }