5e4a475d |
1 | /* |
2 | * pty.c - pseudo-terminal handling |
3 | */ |
4 | |
5 | #define _XOPEN_SOURCE |
6 | #include <features.h> |
7 | |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <string.h> |
11 | #include <assert.h> |
12 | |
13 | #include <unistd.h> |
14 | #include <fcntl.h> |
15 | #include <termios.h> |
16 | #include <sys/ioctl.h> |
17 | #include <sys/types.h> |
18 | #include <pwd.h> |
19 | |
20 | #include "pty.h" |
21 | #include "malloc.h" |
22 | |
23 | static char ptyname[FILENAME_MAX]; |
24 | int master = -1; |
25 | |
26 | void pty_preinit(void) |
27 | { |
28 | /* |
29 | * Allocate the pty. |
30 | */ |
31 | master = open("/dev/ptmx", O_RDWR); |
32 | if (master < 0) { |
33 | perror("/dev/ptmx: open"); |
34 | exit(1); |
35 | } |
36 | |
37 | if (grantpt(master) < 0) { |
38 | perror("grantpt"); |
39 | exit(1); |
40 | } |
41 | |
42 | if (unlockpt(master) < 0) { |
43 | perror("unlockpt"); |
44 | exit(1); |
45 | } |
46 | } |
47 | |
48 | void pty_resize(int w, int h) |
49 | { |
50 | struct winsize sz; |
51 | |
52 | assert(master >= 0); |
53 | |
54 | sz.ws_row = h; |
55 | sz.ws_col = w; |
56 | sz.ws_xpixel = sz.ws_ypixel = 0; |
57 | ioctl(master, TIOCSWINSZ, &sz); |
58 | } |
59 | |
60 | int run_program_in_pty(const struct shell_data *shdata, |
61 | char *directory, char **program_args) |
62 | { |
63 | int slave, pid; |
64 | char *fallback_args[2]; |
65 | |
66 | assert(master >= 0); |
67 | |
68 | ptyname[FILENAME_MAX-1] = '\0'; |
69 | strncpy(ptyname, ptsname(master), FILENAME_MAX-1); |
70 | |
71 | #if 0 |
72 | { |
73 | struct winsize ws; |
74 | struct termios ts; |
75 | |
76 | /* |
77 | * FIXME: think up some good defaults here |
78 | */ |
79 | |
80 | if (!ioctl(0, TIOCGWINSZ, &ws)) |
81 | ioctl(master, TIOCSWINSZ, &ws); |
82 | if (!tcgetattr(0, &ts)) |
83 | tcsetattr(master, TCSANOW, &ts); |
84 | } |
85 | #endif |
86 | |
87 | slave = open(ptyname, O_RDWR | O_NOCTTY); |
88 | if (slave < 0) { |
89 | perror("slave pty: open"); |
90 | return 1; |
91 | } |
92 | |
93 | /* |
94 | * Fork and execute the command. |
95 | */ |
96 | pid = fork(); |
97 | if (pid < 0) { |
98 | perror("fork"); |
99 | return 1; |
100 | } |
101 | |
102 | if (pid == 0) { |
103 | int i, fd; |
104 | |
105 | /* |
106 | * We are the child. |
107 | */ |
108 | close(master); |
109 | |
110 | fcntl(slave, F_SETFD, 0); /* don't close on exec */ |
111 | dup2(slave, 0); |
112 | dup2(slave, 1); |
113 | if (slave != 0 && slave != 1) |
114 | close(slave); |
115 | dup2(1, 2); |
116 | setsid(); |
117 | setpgrp(); |
118 | i = 0; |
119 | #ifdef TIOCNOTTY |
120 | if ((fd = open("/dev/tty", O_RDWR)) >= 0) { |
121 | ioctl(fd, TIOCNOTTY, &i); |
122 | close(fd); |
123 | } |
124 | #endif |
125 | #ifdef TIOCSCTTY |
126 | ioctl(0, TIOCSCTTY, &i); |
127 | #endif |
128 | tcsetpgrp(0, getpgrp()); |
129 | |
130 | for (i = 0; i < shdata->nenvvars; i++) |
131 | putenv(shdata->envvars[i]); |
132 | if (shdata->termtype) |
133 | putenv(shdata->termtype); |
134 | |
135 | if (directory) |
136 | chdir(directory); |
137 | |
138 | /* |
139 | * Use the provided shell program name, if the user gave |
140 | * one. Failing that, use $SHELL; failing that, look up |
141 | * the user's default shell in the password file; failing |
142 | * _that_, revert to the bog-standard /bin/sh. |
143 | */ |
144 | if (!program_args) { |
145 | char *shell; |
146 | |
147 | shell = getenv("SHELL"); |
148 | if (!shell) { |
149 | const char *login; |
150 | uid_t uid; |
151 | struct passwd *pwd; |
152 | |
153 | /* |
154 | * For maximum generality in the face of multiple |
155 | * /etc/passwd entries with different login names and |
156 | * shells but a shared uid, we start by using |
157 | * getpwnam(getlogin()) if it's available - but we |
158 | * insist that its uid must match our real one, or we |
159 | * give up and fall back to getpwuid(getuid()). |
160 | */ |
161 | uid = getuid(); |
162 | login = getlogin(); |
163 | if (login && (pwd = getpwnam(login)) && pwd->pw_uid == uid) |
164 | shell = pwd->pw_shell; |
165 | else if ((pwd = getpwuid(uid))) |
166 | shell = pwd->pw_shell; |
167 | } |
168 | if (!shell) |
169 | shell = "/bin/sh"; |
170 | |
171 | fallback_args[0] = shell; |
172 | fallback_args[1] = NULL; |
173 | program_args = fallback_args; |
174 | } |
175 | |
176 | execv(program_args[0], program_args); |
177 | |
178 | /* |
179 | * If we're here, exec has gone badly foom. |
180 | */ |
181 | perror("exec"); |
182 | exit(127); |
183 | } |
184 | |
185 | close(slave); |
186 | |
187 | return master; |
188 | } |