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}