getty.c - 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 } |