3
* Author : Manoj Srivastava ( srivasta@glaurung.internal.golden-gryphon.com )
4
* Created On : Fri Jan 14 10:48:28 2005
5
* Created On Node : glaurung.internal.golden-gryphon.com
6
* Last Modified By : Manoj Srivastava
7
* Last Modified On : Thu Sep 15 00:57:00 2005
8
* Last Machine Used: glaurung.internal.golden-gryphon.com
10
* Status : Unknown, Use with caution!
14
* Distributed under the terms of the GNU General Public License v2
20
* This program allows a systems administrator to execute daemons
21
* which need to work in the initrc domain, and which need to have
22
* pty's as system_u:system_r:initrc_t
26
* * arch-tag: a5583d39-72b9-4cdf-ba1b-5678ea4cbe20
37
#include <pty.h> /* for openpty and forkpty */
38
#include <utmp.h> /* for login_tty */
42
#include <sys/select.h>
44
static struct termios saved_termios;
45
static int saved_fd = -1;
46
static enum { RESET, RAW, CBREAK } tty_state = RESET;
48
static int tty_semi_raw(int fd)
52
if (tty_state == RESET) {
53
if (tcgetattr(fd, &saved_termios) < 0) {
60
* echo off, canonical mode off, extended input processing off,
63
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
65
* no SIGINT on break, CR-to-NL off, input parity check off, do not
66
* strip 8th bit on input,output flow control off
68
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
69
/* Clear size bits, parity checking off */
70
buf.c_cflag &= ~(CSIZE | PARENB);
73
/* Output processing off
74
buf.c_oflag &= ~(OPOST); */
76
buf.c_cc[VMIN] = 1; /* one byte at a time, no timer */
78
if (tcsetattr(fd, TCSANOW, &buf) < 0) {
80
} /* end of if(tcsetattr(fileno(stdin), TCSANOW, &buf) < 0) */
88
if (tty_state != CBREAK && tty_state != RAW) {
92
if (tcsetattr(saved_fd, TCSANOW, &saved_termios) < 0) {
94
} /* end of if(tcsetattr(fileno(stdin), TCSANOW, &buf) < 0) */
99
int main(int argc, char *argv[])
102
struct termios tty_attr;
103
struct winsize window_size;
114
/* for sigtimedwait() */
115
struct timespec timeout;
119
printf("usage: %s PROGRAM [ARGS]...\n", argv[0]);
124
siginfo_t signalinfo;
127
sigemptyset(&signal_set); /* no signals */
128
sigaddset(&signal_set, SIGCHLD); /* Add sig child */
129
sigprocmask(SIG_BLOCK, &signal_set, NULL); /* Block the signal */
131
/* Set both to 0, so sigtimed wait just does a poll */
135
if (isatty(fileno(stdin))) {
136
/* get terminal parameters associated with stdout */
137
if (tcgetattr(fileno(stdout), &tty_attr) < 0) {
138
perror("tcgetattr:");
142
/* end of if(tcsetattr(&tty_attr)) */
143
/* get window size */
144
if (ioctl(fileno(stdout), TIOCGWINSZ, &window_size) < 0) {
145
perror("ioctl stdout:");
149
child_pid = forkpty(&pty_master, NULL, &tty_attr, &window_size);
150
} /* end of if(isatty(fileno(stdin))) */
151
else { /* not interactive */
152
child_pid = forkpty(&pty_master, NULL, NULL, NULL);
156
perror("forkpty():");
160
} /* end of if(child_pid < 0) */
161
if (child_pid == 0) {
163
struct termios s_tty_attr;
164
if (tcgetattr(fileno(stdin), &s_tty_attr)) {
171
s_tty_attr.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
172
/* Also turn of NL to CR?LF on output */
173
s_tty_attr.c_oflag &= ~(ONLCR);
174
if (tcsetattr(fileno(stdin), TCSANOW, &s_tty_attr)) {
178
{ /* There is no reason to block sigchild for the process we
180
sigset_t chld_signal_set;
181
/* release SIGCHLD */
182
sigemptyset(&chld_signal_set); /* no signals */
183
sigaddset(&chld_signal_set, SIGCHLD); /* Add sig child */
184
sigprocmask(SIG_UNBLOCK, &chld_signal_set, NULL); /* Unblock the signal */
187
if (execvp(argv[1], argv + 1)) {
195
/* end of if(child_pid == 0) */
197
* OK. Prepare to handle IO from the child. We need to transfer
198
* everything from the child's stdout to ours.
205
* Read current file descriptor flags, preparing to do non blocking reads
207
retval = fcntl(pty_master, F_GETFL);
215
/* Set the connection to be non-blocking */
216
if (fcntl(pty_master, F_SETFL, retval | O_NONBLOCK) < 0) {
217
perror("fcnt_setFlag_nonblock:");
223
FD_SET(pty_master, &readfds);
224
FD_SET(pty_master, &writefds);
225
FD_SET(fileno(stdin), &readfds);
226
if (isatty(fileno(stdin))) {
227
if (tty_semi_raw(fileno(stdin)) < 0) {
228
perror("Error: settingraw mode:");
231
} /* end of if(tty_raw(fileno(stdin)) < 0) */
232
if (atexit(tty_atexit) < 0) {
233
perror("Atexit setup:");
236
} /* end of if(atexit(tty_atexit) < 0) */
239
/* ignore return from nice, but lower our priority */
240
int ignore __attribute__ ((unused)) = nice(19);
242
/* while no signal, we loop around */
245
struct timeval interval;
250
* We still use a blocked signal, and check for SIGCHLD every
251
* loop, since waiting infinitely did not really help the load
252
* when running, say, top.
255
interval.tv_usec = 200000; /* so, check for signals every 200 milli
259
t_writefds = writefds;
260
t_exceptfds = exceptfds;
262
/* check for the signal */
263
retval = sigtimedwait(&signal_set, &signalinfo, &timeout);
265
if (retval == SIGCHLD) {
266
/* child terminated */
267
done = 1; /* in case they do not close off their
271
if (errno != EAGAIN) {
272
perror("sigtimedwait");
277
/* No signal in set was delivered within the timeout period specified */
283
(pty_master + 1, &t_readfds, &t_writefds, &t_exceptfds,
291
if (FD_ISSET(pty_master, &t_readfds)) {
292
retval = read(pty_master, buf, (unsigned int)16384);
294
if (errno != EINTR && errno != EAGAIN) { /* Nothing left to read? */
297
/* fprintf(stderr, "DEBUG: %d: Nothing left to read?\n", __LINE__); */
300
} /* end of if(retval < 0) */
303
if (++err_count > 5) { /* child closed connection */
306
/*fprintf(stderr, "DEBUG: %d: child closed connection?\n", __LINE__); */
309
} /* end of if(retval == 0) */
311
ssize_t nleft = retval;
312
ssize_t nwritten = 0;
316
write(fileno(stdout), ptr,
317
(unsigned int)nleft))
319
if (errno == EINTR) {
321
} /* end of if(errno == EINTR) */
328
} /* end of if((nwritten = write(sockfd, ptr, nleft)) <= 0) */
331
} /* end of while(nleft > 0) */
333
/* fprintf(stderr, "DEBUG: %d: wrote %d\n", __LINE__, retval); */
338
if (FD_ISSET(fileno(stdin), &t_readfds)) {
339
if (FD_ISSET(pty_master, &t_writefds)) {
341
read(fileno(stdin), buf,
342
(unsigned int)16384);
344
if (errno != EINTR && errno != EAGAIN) { /* Nothing left to read? */
349
} /* end of if(retval < 0) */
352
if (++err_count > 5) { /* lost controlling tty */
357
} /* end of if(retval == 0) */
359
ssize_t nleft = retval;
360
ssize_t nwritten = 0;
373
} /* end of if(errno == EINTR) */
383
} /* end of if((nwritten = write(sockfd, ptr, nleft)) <= 0) */
386
} /* end of while(nleft > 0) */
391
} /* end of if(FD_ISSET(pty_master, &writefds)) */
392
} /* something to read on stdin */
399
} /* end of main() */