getty.c - ubase - suckless linux base utils
HTML git clone git://git.suckless.org/ubase
DIR Log
DIR Files
DIR Refs
DIR README
DIR 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 }