Mercurial > hg > rlgwebd
comparison ptyhelper.c @ 0:bd412f63ce0d
Put this project under version control, finally.
author | John "Elwin" Edwards <elwin@sdf.org> |
---|---|
date | Sun, 06 May 2012 08:45:40 -0700 |
parents | |
children | 9bef0941c6dd |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:bd412f63ce0d |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <unistd.h> | |
4 #include <signal.h> | |
5 #include <pty.h> | |
6 #include <utmp.h> | |
7 #include <sys/types.h> | |
8 #include <sys/wait.h> | |
9 #include <sys/select.h> | |
10 #include <termios.h> | |
11 | |
12 int got_sighup = 0; | |
13 | |
14 void handle_HUP(int signum) { | |
15 if (signum == SIGHUP) | |
16 got_sighup = 1; | |
17 return; | |
18 } | |
19 | |
20 int main(int argc, char *argv[]) { | |
21 | |
22 int ptymaster, ptyslave; /* File descriptors */ | |
23 int child; | |
24 int status, selstatus; | |
25 int w = 80, h = 24, t; | |
26 struct sigaction sighup_act; | |
27 fd_set readset; | |
28 struct timeval select_time; | |
29 char buf[4096]; | |
30 int nread; | |
31 char *penv, *ptmp; | |
32 #if 0 | |
33 struct termios ptysettings; | |
34 #endif | |
35 struct winsize ptysize; | |
36 | |
37 if (argc == 1) { | |
38 fprintf(stderr, "No command given.\n"); | |
39 exit(1); | |
40 } | |
41 | |
42 /* Set up the signal handler. */ | |
43 sighup_act.sa_handler = &handle_HUP; | |
44 sighup_act.sa_flags = SA_RESTART; | |
45 sigaction(SIGHUP, &sighup_act, NULL); | |
46 | |
47 /* Check the environment for configuration options. */ | |
48 penv = getenv("PTYHELPER"); | |
49 if (penv != NULL) { | |
50 t = strtol(penv, &ptmp, 10); | |
51 if (t > 0 && t < 256) | |
52 h = t; | |
53 if (*ptmp != '\0') { | |
54 penv = ptmp + 1; | |
55 t = strtol(penv, &ptmp, 10); | |
56 if (t > 0 && t < 256) | |
57 w = t; | |
58 } | |
59 } | |
60 /* Set up the size. */ | |
61 ptysize.ws_row = h; | |
62 ptysize.ws_col = w; | |
63 | |
64 /* Open a pty */ | |
65 if (openpty(&ptymaster, &ptyslave, NULL, NULL, &ptysize)) { | |
66 return 1; | |
67 } | |
68 #if 0 | |
69 /* Put it into raw mode. */ | |
70 tcgetattr(ptyslave, &ptysettings); | |
71 cfmakeraw(&ptysettings); | |
72 tcsetattr(ptyslave, TCSANOW, &ptysettings); | |
73 #endif | |
74 | |
75 /* Start the child */ | |
76 /* forkpty() might be more convenient. */ | |
77 if (!(child = fork())) { | |
78 /* Child process */ | |
79 login_tty(ptyslave); | |
80 close(ptymaster); | |
81 execvp(argv[1], argv + 1); | |
82 perror("execvp() failed"); | |
83 return 1; | |
84 } | |
85 close(ptyslave); | |
86 | |
87 while (1) { | |
88 /* Now do a select() over stdin and ptymaster, and write anything that | |
89 * appears to ptymaster and stdout respectively. */ | |
90 FD_ZERO(&readset); | |
91 FD_SET(0, &readset); | |
92 FD_SET(ptymaster, &readset); | |
93 select_time.tv_sec = 1; | |
94 select_time.tv_usec = 0; | |
95 selstatus = select(ptymaster + 1, &readset, NULL, NULL, &select_time); | |
96 if (selstatus > 0) { | |
97 /* TODO make sure it all gets written if a signal interrupts write(). */ | |
98 if (FD_ISSET(0, &readset)) { | |
99 nread = read(0, buf, 4096); | |
100 if (nread > 0) { | |
101 write(ptymaster, buf, nread); | |
102 } | |
103 } | |
104 if (FD_ISSET(ptymaster, &readset)) { | |
105 nread = read(ptymaster, buf, 4096); | |
106 if (nread > 0) { | |
107 write(1, buf, nread); | |
108 } | |
109 } | |
110 } | |
111 | |
112 /* Periodically check to see if we're done. */ | |
113 /* TODO: catch SIGCHLD and only wait() if it is delivered. */ | |
114 if (waitpid(child, &status, WNOHANG)) { | |
115 break; | |
116 } | |
117 | |
118 /* If node sighup's us, pass it along. */ | |
119 if (got_sighup) { | |
120 kill(child, SIGHUP); | |
121 } | |
122 } | |
123 | |
124 /* Get any leftover output and clean up. */ | |
125 /* FIXME looping over select() is pointless if there's only one fd that | |
126 * nothing's writing to. Just loop over read() until it's empty. */ | |
127 while (1) { | |
128 FD_ZERO(&readset); | |
129 FD_SET(ptymaster, &readset); | |
130 select_time.tv_sec = 0; | |
131 select_time.tv_usec = 0; | |
132 if (select(ptymaster + 1, &readset, NULL, NULL, &select_time) > 0) { | |
133 nread = read(ptymaster, buf, 4096); | |
134 if (nread > 0) { | |
135 write(1, buf, nread); | |
136 } | |
137 else | |
138 break; | |
139 } | |
140 else | |
141 break; | |
142 } | |
143 close(ptymaster); | |
144 | |
145 /* Return the child's exit status. */ | |
146 if (WIFEXITED(status)) | |
147 return WEXITSTATUS(status); | |
148 return 0; | |
149 } |