1
/* Miscellaneous system dependent routines for splitsh */
15
#include <sys/ioctl.h>
16
#endif /* HAVE_TERMIO_H */
19
#include <sys/bsdtty.h>
21
#define TIOCNOTTY _IO('t', 113) /* HP-UX void tty definition */
23
#endif /* HAVE_BSDTTY_H */
30
* Initialize a pty, fork a command running under it, and then
31
* return the master file descriptor
34
extern int WU_lines, WL_lines, W_columns; /* From vt100.c */
36
#define UPPER 0 /* Upper window definition */
37
#define LOWER 1 /* Lower window definition */
39
int pty_open(argv, childpid, win)
42
int win; /* 0 for upper, 1 for lower */
45
void dropctty(), pty_setwin();
46
int get_master_pty(), get_slave_pty();
47
char *get_ttyname(), *myputenv();
49
char LINES[12], COLUMNS[12], SPLITVT[24];
50
int returnfd, slave_fd;
52
/* Get the master pty file descriptor */
53
if ( (returnfd=get_master_pty()) < 0 )
57
if ( ((*childpid)=fork()) < 0 )
59
else if ( (*childpid) == 0 )
61
dropctty(); /* Lose controlling tty */
63
if ( (slave_fd=get_slave_pty()) < 0 )
65
perror("Can't open slave tty");
68
close(0); close(1); close(2);
69
dup(slave_fd); dup(slave_fd); dup(slave_fd);
70
close(slave_fd); close(returnfd);
72
/* Reattatch the new tty as the controlling terminal */
73
/* Under old UNIX, just opening the new tty after
74
losing the controlling tty is good enough.
75
Under newer Unices, it requires an ioctl(). */
77
(void) ioctl(0, TIOCSCTTY, 0);
80
/* Set the lines and columns on the new tty */
81
#ifdef TIOCGWINSZ /* We don't want to set the environment if possible */
85
sprintf(LINES, "LINES=%d", WU_lines);
87
sprintf(LINES, "LINES=%d", WL_lines);
89
sprintf(COLUMNS, "COLUMNS=%d", W_columns);
91
#endif /* TIOCGWINSZ */
92
/* Set the SPLITVT environment variable for shell scripts */
94
sprintf(SPLITVT, "SPLITVT=upper");
96
sprintf(SPLITVT, "SPLITVT=lower");
98
myputenv("TERM=vt100"); /* Put the new TERM in the env. */
101
signal(SIGTSTP, SIG_IGN);
104
system("stty sane echo echoe intr '^C' erase '^H'");
108
/* "touch" the tty so 'w' reports proper idle times */
109
(void) utime(get_ttyname(), NULL);
111
/* Set our uid to our real uid if necessary */
112
(void) setuid(getuid());
114
/* Run the requested program, with possible leading dash. */
115
execvp(((*argv[0] == '-') ? argv[0]+1 : argv[0]), argv);
125
* Pseudo-terminal routines for Unix System V Release 3.2 and BSD4.2-3
132
char tty_name[64]={'\0'};
133
char pty_name[64]={'\0'};
142
#ifdef IRIX /* IRIX System V for SGI machines */
144
extern char *_getpty();
151
ttyptr=_getpty(&master_fd, O_RDWR, 0600, 0);
152
if ( ttyptr == NULL || strlen(ttyptr)+1 > sizeof(tty_name) )
155
strcpy(tty_name, ttyptr);
161
* Open the slave half of a pseudo-terminal.
171
if (slavename == NULL) {
176
if ( (slave_fd=open(slavename, O_RDWR)) < 0 ) /* open the slave */
187
#if defined(SOLARIS) || defined(linux) /* System V.4 pty routines from W. Richard Stevens */
193
#define DEV_CLONE "/dev/ptmx"
195
extern char *ptsname();
202
if ( (master_fd=open(DEV_CLONE, O_RDWR)) < 0 )
205
if ( grantpt(master_fd) < 0 ) /* grant access to slave */
214
if ( unlockpt(master_fd) < 0 ) /* clear slave's lock flag */
220
ttyptr=ptsname(master_fd);
221
if ( ttyptr == NULL || strlen(ttyptr)+1 > sizeof(tty_name) )
227
strcpy(tty_name, ttyptr);
233
* Open the slave half of a pseudo-terminal.
243
if ( (slave_fd=open(slavename, O_RDWR)) < 0 ) /* open the slave */
250
if ( ioctl(slave_fd, I_PUSH, "ptem") < 0 )
257
if ( ioctl(slave_fd, I_PUSH, "ldterm") < 0 )
264
if ( ioctl(slave_fd, I_PUSH, "ttcompat") < 0 )
275
#else /* BSD, Sun/OS, AIX, ULTRIX, HP-UX, AT&T SYSV */
280
#define R_OK 4 /* Test for Read permission */
281
#define W_OK 2 /* Test for Write permission */
282
#define X_OK 1 /* Test for eXecute permission */
297
struct stat statbuff;
299
static char ptychar[]=PTYCHAR; /* X */
300
static char hexdigit[]=HEXDIGIT; /* Y */
302
static char ptychar[]="pqrstuvwxyzPQRST"; /* X */
303
static char hexdigit[]="0123456789abcdef"; /* Y */
306
for (ptr=ptychar; *ptr != 0; ptr++)
308
strcpy(pty_name, "/dev/ptyXY");
309
pty_name[8]=(*ptr); /* X */
310
pty_name[9]='0'; /* Y */
312
if ( stat(pty_name, &statbuff) < 0 )
315
fprintf(stderr, "statted.\n");
317
i=(-1); /* Initialize i */
319
/* Set a time limit for the open */
320
if ( setjmp(next) == -1 )
322
signal(SIGALRM, trynext);
324
for ( ++i; hexdigit[i]; ++i)
327
pty_name[9]=hexdigit[i];
329
alarm(2); /* Set an open timeout */
331
if ( (master_fd=open(pty_name, O_RDWR)) >= 0 )
333
alarm(0); /* Reset the alarm */
336
sprintf(tty_name, "%s", pty_name);
338
fprintf(stderr, "tty: %s\n", tty_name);
340
if ( access(tty_name, R_OK|W_OK) == 0 ) {
341
signal(SIGALRM, SIG_DFL);
345
(void) close(master_fd);
348
/* reset the alarm */
356
/* Open the slave half of a pseudo-terminal. */
362
if ( (slave_fd=open(tty_name, O_RDWR)) < 0 )
370
#endif /* if linux or SOLARIS */
374
/* These are the binary data functions that I am using instead of
375
bcopy() and bzero(), written by Richard A. O'Keefe.
379
void d_copy(src, dst, len)
380
register char *src, *dst;
383
while (--len >= 0) *dst++ = *src++;
386
void d_zero(dst, len)
390
while (--len >= 0) *dst++ = 0;
395
/* Here are the Terminal manipulation routines... */
398
/* Code to disassociate from my tty. Yay! :) */
404
#if defined(_POSIX_SOURCE) || defined(SOLARIS) || \
405
defined(__386BSD__) || defined(__FreeBSD__)
406
setsid(); /* The POSIX solution is simple. :) */
408
#ifdef TIOCNOTTY /* We want to get HP-UX, BSD, and Sun/OS here */
411
#ifndef CIBAUD /* Sun/OS doesn't need to do TIOCNOTTY. */
412
if ( (fd=open("/dev/tty", O_RDWR)) > (-1) )
414
if (ioctl(fd, TIOCNOTTY, 0) < 0)
416
perror("ioctl TIOCNOTTY error");
417
fprintf(stderr, "\r");
424
#endif /* TIOCNOTTY */
425
#endif /* _POSIX_SOURCE */
431
/* Get the modes of the controlling tty and save them. Saves
432
ttymodes in tty_mode and returns -1 if ioctl fails. */
434
struct termio tty_mode; /* Save tty mode here */
435
static int tty_init=0;
440
d_zero((char *)&tty_mode, sizeof(struct termio));
441
tty_init=1; /* Flag: we have initialized the tty_mode struct */
447
fprintf(stderr, "Getting tty modes for tty_mode.\r\n");
450
if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0)
453
perror("tty_getmode(): ioctl error");
462
/* Set a tty to a sane mode */
467
struct termio temp_mode;
474
if (ioctl(fd, TCGETA, (char *) &tty_mode) < 0)
479
temp_mode.c_iflag=(tty_mode.c_iflag|(BRKINT|IGNPAR|ISTRIP|ICRNL|IXON));
480
temp_mode.c_oflag=(tty_mode.c_oflag|(OPOST|ONLCR));
482
temp_mode.c_iflag=(tty_mode.c_iflag|(BRKINT|IGNPAR|ICRNL|IXON));
483
temp_mode.c_cflag=(tty_mode.c_cflag|(CS8|CREAD));
485
temp_mode.c_lflag=(tty_mode.c_lflag|(ISIG|ICANON|ECHO|ECHOE|ECHOK));
486
temp_mode.c_cflag=(tty_mode.c_cflag|(CS7|PARENB|CREAD));
487
temp_mode.c_cc[VERASE]=('H'^64);
488
temp_mode.c_cc[VKILL]=('U'^64);
489
temp_mode.c_cc[VQUIT]=('\\'^64);
490
temp_mode.c_cc[VINTR]=('C'^64);
491
temp_mode.c_cc[VEOF]=('D'^64);
493
/* TCSETAW is important for letting tty input drain. */
494
if ( ioctl(fd, TCSETAW, (char *)&temp_mode) < 0 )
497
perror("Can't set tty modes");
506
/* Set a terminal in raw mode */
509
int fd; /* of tty device */
511
struct termio temp_mode;
519
if ( ioctl(fd, TCGETA, (char *)&temp_mode) < 0 )
523
temp_mode.c_iflag=(IGNBRK | ISTRIP); /* turn off all input control */
525
temp_mode.c_iflag=(IGNBRK); /* turn off all input control */
527
temp_mode.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONLRET);
528
/* disable output post-processing */
529
temp_mode.c_lflag = 0;
530
temp_mode.c_cc[VMIN]=1; /* 1 or more chars satisfy read */
531
temp_mode.c_cc[VTIME]=0; /* 10'ths of seconds between chars */
533
/* TCSETAW is important for letting tty input drain. */
534
if (ioctl(fd, TCSETAW, (char *) &temp_mode) < 0)
540
/* Restore terminal's mode to whatever it was on the most
541
recent call to the tty_getmode() function. */
552
/* TCSETAW is important for letting tty input drain. */
553
if (ioctl(fd, TCSETAW, (char *) &tty_mode) < 0)
558
#else /* no /usr/include/termio.h */
559
#ifdef NEED_COMPAT_H /* FreeBSD needs this */
560
#include <sys/ioctl_compat.h>
561
#endif /* NEED_COMPAT_H */
563
/* Set a tty to a sane mode */
568
struct sgttyb temp_mode;
573
if (ioctl(fd, TIOCGETP, (char *) &temp_mode) < 0)
576
temp_mode.sg_flags|=ECHO;
578
if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
586
/* Get the modes of the controlling tty and save them. Saves
587
ttymodes in tty_mode and returns 1 if ioctl fails. */
589
static struct sgttyb tty_mode; /* save tty mode here */
597
if (ioctl(fd, TIOCGETP, (char *) &tty_mode) < 0)
604
* Put a terminal device into RAW mode with ECHO off.
605
* Before doing so we first save the terminal's current mode,
606
* assuming the caller will call the tty_reset() function
607
* (also in this file) when it's done with raw mode.
611
int fd; /* of terminal device */
613
struct sgttyb temp_mode;
618
temp_mode = tty_mode;
620
temp_mode.sg_flags |= RAW; /* turn RAW mode on */
621
temp_mode.sg_flags &= ~ECHO; /* turn ECHO off */
622
if (ioctl(fd, TIOCSETP, (char *) &temp_mode) < 0)
629
* Restore a terminal's mode to whatever it was on the most
630
* recent call to the tty_getmode() function above.
634
int fd; /* of terminal device */
639
if (ioctl(fd, TIOCSETP, (char *) &tty_mode) < 0)
644
#endif /* HAVE_TERMIO_H */
647
/* Set the pty window size to the size of the virtual window */
651
static struct /* winsize */ {
652
unsigned short ws_row; /* rows, in characters */
653
unsigned short ws_col; /* columns, in characters */
654
unsigned short ws_xpixel; /* horizontal size - not used */
655
unsigned short ws_ypixel; /* vertical size - not used */
658
void pty_setwin(fd, win)
659
int fd; /* The pty file descriptor */
660
int win; /* 0 for upper, 1 for lower window */
663
mywinz.ws_row=WU_lines;
665
mywinz.ws_row=WL_lines;
666
mywinz.ws_col=W_columns;
669
(void) ioctl(fd, TIOCSWINSZ, &mywinz);
673
void pty_setwin(fd, win)
679
#endif /* TIOCSWINSZ */
682
* Write "n" bytes to a descriptor.
683
* Use in place of write() when fd is a stream socket.
686
int writen(fd, ptr, nbytes)
695
nwritten = write(fd, ptr, nleft);
697
return(nwritten); /* error */
702
return(nbytes - nleft);
707
A function to put strings in the environment using malloc().
708
Returns a pointer to the environment string or NULL if malloc() fails.
711
char *myputenv(string)
714
extern char **environ; /* The process environment strings */
716
char *newptr, **envptr;
717
char *tmptr, temp[BUFSIZ];
720
for ( distance=0; ((*(string+distance)) &&
721
((*(string+distance)) != '=')); ++distance );
722
if ( ! (*(string+distance)) )
727
if ( (newptr=(char *)malloc(strlen(string)+1)) == NULL )
730
strcpy(newptr, string);
732
for ( envptr=environ; *envptr; ++envptr, ++n ) {
733
if ( strncmp(*envptr, string, distance) == 0 ) {
747
/* * * * * * * Routines to parse a line into an array of tokens * * * * * * */
749
static int istoken(c, tokens)
754
if ( c == *(tokens++) )
760
/* This version of tokenize is destructive to the line it parses. */
762
void tokenize(array, size, line, tokens)
771
for ( head=line; *line && i < size-2; ) {
772
if ( istoken(*line, tokens) ) {
775
while ( istoken(*line, tokens) )
786
/* Return the pathname of the command, or NULL if it's not in our PATH */
787
/* Warning: We use a static buffer that is overwritten at each invocation. */
789
char *pathsearch(command, secure)
794
#define S_IFREG 0100000
796
char *path, *newpath, *paths[256];
797
static char buffer[1024];
801
if ( (path=(char *)getenv("PATH")) == NULL )
803
if ( (newpath=(char *)malloc(strlen(path)+1)) == NULL )
805
strcpy(newpath, path);
807
tokenize(paths, 256, newpath, ":");
808
for ( i=0; paths[i]; ++i ) {
809
if ( secure && paths[i][0] != '/' ) {
810
/* Only allow full pathnames */
814
/* Make sure the file exists */
815
sprintf(buffer, "%s/%s", paths[i], command);
816
if ( stat(buffer, &sb) != 0 )
819
/* Make sure it's a regular file */
820
if ( (sb.st_mode & S_IFREG) != S_IFREG )
823
/* Now make sure we can execute it */
824
if ( sb.st_uid == getuid() ) {
825
/* User execute permission? */
826
if ( sb.st_mode & 0100 )
828
} else if ( sb.st_gid == getgid() ) {
829
/* Group execute permission? */
830
if ( sb.st_mode & 0010 )
833
/* Other execute permission? */
834
if ( sb.st_mode & 0001 )
838
(void) free(newpath);
840
if ( paths[i] == NULL )
846
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
848
/* Safe version of popen() and pclose(), they reset the uid and gid. */
850
FILE *safe_popen(command, type)
858
if ( strcmp(type, "r") == 0 )
859
rw=0; /* READ access for parent */
860
else if ( strcmp(type, "w") == 0 )
861
rw=1; /* WRITE access for parent */
863
return(NULL); /* Unsupported type */
865
if ( pipe(pipe_fds) < 0 ) {
870
case 0: /* Child runs here */
871
/* Reassign file descriptors */
873
close(1); dup(pipe_fds[1]); close(0);
875
close(0); dup(pipe_fds[0]); close(1);
877
close(pipe_fds[0]); close(pipe_fds[1]);
879
/* Set our uid to our real uid if necessary */
880
(void) setuid(getuid());
882
/* Run the requested program */
887
execvp(argv[0], argv);
888
fprintf(stderr, "Can't execute %s: ", argv[0]);
892
case -1: /* fork() error */
898
default: /* Parent runs */
905
return(fdopen(pipe_fds[rw], type));
908
int safe_pclose(pipefp)
916
/* Wait for the child to terminate */