]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - contrib/cygtermd/pty.c
e30f9e0eb81347456e6d90ac1b9ecb34a9881d9b
[PuTTY.git] / contrib / cygtermd / pty.c
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 }