| /* |
| * Copyright 2006 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| /* |
| * Copyright (c) 1983 Regents of the University of California. |
| * All rights reserved. The Berkeley software License Agreement |
| * specifies the terms and conditions for redistribution. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| #include "tip.h" |
| #include <limits.h> |
| #ifdef USG |
| #include <unistd.h> |
| #else |
| #include <vfork.h> |
| #endif |
| |
| /* |
| * tip |
| * |
| * miscellaneous commands |
| */ |
| |
| int quant[] = { 60, 60, 24 }; |
| |
| char null = '\0'; |
| char *sep[] = { "second", "minute", "hour" }; |
| static char *argv[10]; /* argument vector for take and put */ |
| |
| sigjmp_buf intbuf; /* for interrupts and timeouts */ |
| |
| void timeout(void); /* timeout function called on alarm */ |
| void intcopy(void); /* interrupt routine for file transfers */ |
| void transfer(char *, int, char *); |
| void transmit(FILE *, char *, char *); |
| void send(char); |
| void execute(char *); |
| void prtime(char *, time_t); |
| void hardwareflow(char *); |
| void intr(char *); |
| int args(char *, char *[], size_t); |
| int anyof(char *, char *); |
| |
| /* |
| * FTP - remote ==> local |
| * get a file from the remote host |
| */ |
| void |
| getfl(int c) |
| { |
| char buf[256], *cp; |
| |
| (void) putchar(c); |
| /* |
| * get the UNIX receiving file's name |
| */ |
| if (prompt("Local file name? ", copyname, sizeof (copyname))) |
| return; |
| cp = expand(copyname); |
| if (cp == NOSTR) |
| return; |
| if ((sfd = creat(cp, 0666)) < 0) { |
| (void) printf("\r\n%s: cannot creat\r\n", copyname); |
| return; |
| } |
| |
| /* |
| * collect parameters |
| */ |
| if (prompt("List command for remote system? ", buf, sizeof (buf))) { |
| (void) unlink(copyname); |
| return; |
| } |
| transfer(buf, sfd, value(EOFREAD)); |
| } |
| |
| /* |
| * Cu-like take command |
| */ |
| /* ARGSUSED */ |
| void |
| cu_take(int cc) |
| { |
| int fd, argc; |
| char line[BUFSIZ], *cp; |
| |
| if (prompt("[take] ", copyname, sizeof (copyname))) |
| return; |
| argc = args(copyname, argv, sizeof (argv)/sizeof (char *)); |
| if (argc < 1 || argc > 2) { |
| (void) printf("usage: <take> from [to]\r\n"); |
| return; |
| } |
| if (argc == 1) |
| argv[1] = argv[0]; |
| cp = expand(argv[1]); |
| if (cp == NOSTR) |
| return; |
| if ((fd = creat(cp, 0666)) < 0) { |
| (void) printf("\r\n%s: cannot create\r\n", argv[1]); |
| return; |
| } |
| (void) snprintf(line, sizeof (line), "cat %s; echo \01", argv[0]); |
| transfer(line, fd, "\01"); |
| } |
| |
| /* |
| * Bulk transfer routine -- |
| * used by getfl(), cu_take(), and pipefile() |
| */ |
| void |
| transfer(char *buf, int fd, char *eofchars) |
| { |
| int ct; |
| char c, buffer[BUFSIZ]; |
| char *p = buffer; /* can't be register because of longjmp */ |
| int cnt, eof, bol; |
| time_t start; |
| sig_handler_t f; |
| |
| parwrite(FD, (unsigned char *)buf, strlen(buf)); |
| (void) kill(pid, SIGIOT); |
| /* Wait until read process stops */ |
| (void) read(repdes[0], (char *)&ccc, 1); |
| |
| /* |
| * finish command |
| */ |
| parwrite(FD, (unsigned char *)"\r", 1); |
| do |
| (void) read(FD, &c, 1); |
| while ((c&0177) != '\n') |
| ; |
| |
| if (sigsetjmp(intbuf, 1)) |
| goto out; |
| f = signal(SIGINT, (sig_handler_t)intcopy); |
| intr("on"); |
| |
| start = time(0); |
| bol = 1; |
| ct = 0; |
| for (;;) { |
| eof = read(FD, &c, 1) <= 0; |
| if (noparity) |
| c &= 0377; |
| else |
| c &= 0177; |
| if (eof || (bol && any(c, eofchars))) |
| break; |
| if (c == 0) |
| continue; /* ignore nulls */ |
| if (c == '\r') |
| continue; |
| *p++ = c; |
| |
| if (c == '\n') { |
| bol = 1; |
| if (boolean(value(VERBOSE))) |
| (void) printf("\r%d", ++ct); |
| } else |
| bol = 0; |
| if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { |
| if (write(fd, buffer, cnt) != cnt) { |
| (void) printf("\r\nwrite error\r\n"); |
| goto out; |
| } |
| p = buffer; |
| } |
| } |
| out: |
| if ((cnt = (p-buffer)) != 0) |
| if (write(fd, buffer, cnt) != cnt) |
| (void) printf("\r\nwrite error\r\n"); |
| |
| if (boolean(value(VERBOSE))) |
| prtime(" lines transferred in ", time(0)-start); |
| intr("off"); |
| (void) write(fildes[1], (char *)&ccc, 1); |
| (void) signal(SIGINT, f); |
| (void) close(fd); |
| } |
| |
| /* |
| * FTP - remote ==> local process |
| * send remote input to local process via pipe |
| */ |
| /* ARGSUSED */ |
| void |
| pipefile(int cc) |
| { |
| int cpid, pdes[2]; |
| char buf[256]; |
| int status, p; |
| |
| if (prompt("Local command? ", buf, sizeof (buf))) |
| return; |
| |
| if (pipe(pdes)) { |
| (void) printf("can't establish pipe\r\n"); |
| return; |
| } |
| |
| if ((cpid = fork()) < 0) { |
| (void) printf("can't fork!\r\n"); |
| return; |
| } else if (cpid) { |
| if (prompt("List command for remote system? ", buf, |
| sizeof (buf))) { |
| (void) close(pdes[0]), (void) close(pdes[1]); |
| (void) kill(cpid, SIGKILL); |
| } else { |
| (void) close(pdes[0]); |
| (void) signal(SIGPIPE, (sig_handler_t)intcopy); |
| transfer(buf, pdes[1], value(EOFREAD)); |
| (void) signal(SIGPIPE, SIG_DFL); |
| while ((p = wait(&status)) > 0 && p != cpid) |
| ; |
| } |
| } else { |
| int f; |
| |
| userperm(); |
| (void) dup2(pdes[0], 0); |
| (void) close(pdes[0]); |
| for (f = 3; f < 20; f++) |
| (void) close(f); |
| execute(buf); |
| (void) printf("can't execl!\r\n"); |
| exit(0); |
| } |
| } |
| |
| /* |
| * FTP - local ==> remote |
| * send local file to remote host |
| * terminate transmission with pseudo EOF sequence |
| */ |
| void |
| tip_sendfile(int cc) |
| { |
| FILE *fd; |
| char *fnamex; |
| |
| (void) putchar(cc); |
| /* |
| * get file name |
| */ |
| if (prompt("Local file name? ", fname, sizeof (fname))) |
| return; |
| |
| /* |
| * look up file |
| */ |
| fnamex = expand(fname); |
| if (fnamex == NOSTR) |
| return; |
| if ((fd = fopen(fnamex, "r")) == NULL) { |
| (void) printf("%s: cannot open\r\n", fname); |
| return; |
| } |
| transmit(fd, value(EOFWRITE), NULL); |
| if (!boolean(value(ECHOCHECK))) { |
| struct termios buf; |
| |
| (void) ioctl(FD, TCGETS, (char *)&buf); /* this does a */ |
| (void) ioctl(FD, TCSETSF, (char *)&buf); /* wflushtty */ |
| } |
| } |
| |
| /* |
| * Bulk transfer routine to remote host -- |
| * used by tip_sendfile() and cu_put() |
| */ |
| void |
| transmit(FILE *fd, char *eofchars, char *command) |
| { |
| sig_handler_t ointr; |
| char *pc, lastc, rc; |
| int c, ccount, lcount; |
| time_t start_t, stop_t; |
| |
| (void) kill(pid, SIGIOT); /* put TIPOUT into a wait state */ |
| timedout = 0; |
| if (sigsetjmp(intbuf, 1)) { |
| if (timedout) |
| (void) printf("\r\ntimed out at eol\r\n"); |
| (void) alarm(0); |
| goto out; |
| } |
| ointr = signal(SIGINT, (sig_handler_t)intcopy); |
| intr("on"); |
| (void) read(repdes[0], (char *)&ccc, 1); |
| if (command != NULL) { |
| for (pc = command; *pc; pc++) |
| send(*pc); |
| if (boolean(value(ECHOCHECK))) |
| (void) read(FD, (char *)&c, 1); /* trailing \n */ |
| else { |
| struct termios buf; |
| /* wait for remote stty to take effect */ |
| (void) sleep(5); |
| /* this does a */ |
| (void) ioctl(FD, TCGETS, (char *)&buf); |
| /* wflushtty */ |
| (void) ioctl(FD, TCSETSF, (char *)&buf); |
| } |
| } |
| lcount = 0; |
| lastc = '\0'; |
| start_t = time(0); |
| if (boolean(value(RAWFTP))) { |
| while ((c = getc(fd)) != EOF) { |
| lcount++; |
| send(c); |
| if (boolean(value(VERBOSE)) && lcount%100 == 0) |
| (void) printf("\r%d", lcount); |
| } |
| if (boolean(value(VERBOSE))) |
| (void) printf("\r%d", lcount); |
| goto out; |
| } |
| for (;;) { |
| ccount = 0; |
| do { |
| c = getc(fd); |
| if (c == EOF) |
| goto out; |
| if (c == 0177) |
| continue; |
| lastc = c; |
| if (c < 040) { |
| if (c == '\n') { |
| c = '\r'; |
| } else if (c == '\t') { |
| if (boolean(value(TABEXPAND))) { |
| send(' '); |
| while ((++ccount % 8) != 0) |
| send(' '); |
| continue; |
| } |
| } else |
| continue; |
| } |
| send(c); |
| } while (c != '\r'); |
| if (boolean(value(VERBOSE))) |
| (void) printf("\r%d", ++lcount); |
| if (boolean(value(ECHOCHECK))) { |
| (void) alarm(number(value(ETIMEOUT))); |
| do { /* wait for prompt */ |
| (void) read(FD, &rc, 1); |
| } while ((rc&0177) != character(value(PROMPT))); |
| (void) alarm(0); |
| } |
| } |
| out: |
| if (lastc != '\n' && !boolean(value(RAWFTP))) |
| send('\r'); |
| if (eofchars) |
| for (pc = eofchars; *pc; pc++) |
| send(*pc); |
| stop_t = time(0); |
| (void) fclose(fd); |
| if (boolean(value(VERBOSE))) |
| if (boolean(value(RAWFTP))) |
| prtime(" chars transferred in ", stop_t-start_t); |
| else |
| prtime(" lines transferred in ", stop_t-start_t); |
| (void) write(fildes[1], (char *)&ccc, 1); |
| intr("off"); |
| (void) signal(SIGINT, ointr); |
| } |
| |
| /* |
| * Cu-like put command |
| */ |
| /* ARGSUSED */ |
| void |
| cu_put(int cc) |
| { |
| FILE *fd; |
| char line[BUFSIZ]; |
| int argc; |
| char *copynamex; |
| |
| if (prompt("[put] ", copyname, sizeof (copyname))) |
| return; |
| argc = args(copyname, argv, sizeof (argv)/sizeof (char *)); |
| if (argc < 1 || argc > 2) { |
| (void) printf("usage: <put> from [to]\r\n"); |
| return; |
| } |
| if (argc == 1) |
| argv[1] = argv[0]; |
| copynamex = expand(argv[0]); |
| if (copynamex == NOSTR) |
| return; |
| if ((fd = fopen(copynamex, "r")) == NULL) { |
| (void) printf("%s: cannot open\r\n", copynamex); |
| return; |
| } |
| if (boolean(value(ECHOCHECK))) |
| (void) snprintf(line, sizeof (line), "cat>%s\r", argv[1]); |
| else |
| (void) snprintf(line, sizeof (line), |
| "stty -echo; cat>%s; stty echo\r", argv[1]); |
| transmit(fd, "\04", line); |
| } |
| |
| /* |
| * FTP - send single character |
| * wait for echo & handle timeout |
| */ |
| void |
| send(char c) |
| { |
| char cc; |
| int retry = 0; |
| |
| cc = c; |
| parwrite(FD, (unsigned char *)&cc, 1); |
| #ifdef notdef |
| if (number(value(CDELAY)) > 0 && c != '\r') |
| nap(number(value(CDELAY))); |
| #endif |
| if (!boolean(value(ECHOCHECK))) { |
| #ifdef notdef |
| if (number(value(LDELAY)) > 0 && c == '\r') |
| nap(number(value(LDELAY))); |
| #endif |
| return; |
| } |
| tryagain: |
| timedout = 0; |
| if (sigsetjmp(intbuf, 1) && timedout) { |
| (void) printf("\r\ntimeout error (%s)\r\n", ctrl(c)); |
| if (retry++ > 3) |
| return; |
| parwrite(FD, (unsigned char *)&null, 1); /* poke it */ |
| goto tryagain; |
| } |
| (void) alarm(number(value(ETIMEOUT))); |
| (void) read(FD, &cc, 1); |
| (void) alarm(0); |
| } |
| |
| void |
| timeout(void) |
| { |
| (void) signal(SIGALRM, (sig_handler_t)timeout); |
| timedout = 1; |
| siglongjmp(intbuf, 1); |
| } |
| |
| /* |
| * Stolen from consh() -- puts a remote file on the output of a local command. |
| * Identical to consh() except for where stdout goes. |
| */ |
| void |
| pipeout(int c) |
| { |
| char buf[256]; |
| int cpid, status, p; |
| time_t start; |
| |
| (void) putchar(c); |
| if (prompt("Local command? ", buf, sizeof (buf))) |
| return; |
| (void) kill(pid, SIGIOT); /* put TIPOUT into a wait state */ |
| (void) signal(SIGINT, SIG_IGN); |
| (void) signal(SIGQUIT, SIG_IGN); |
| intr("on"); |
| (void) read(repdes[0], (char *)&ccc, 1); |
| /* |
| * Set up file descriptors in the child and |
| * let it go... |
| */ |
| if ((cpid = fork()) < 0) |
| (void) printf("can't fork!\r\n"); |
| else if (cpid) { |
| start = time(0); |
| while ((p = wait(&status)) > 0 && p != cpid) |
| ; |
| } else { |
| int i; |
| |
| userperm(); |
| (void) dup2(FD, 1); |
| for (i = 3; i < 20; i++) |
| (void) close(i); |
| (void) signal(SIGINT, SIG_DFL); |
| (void) signal(SIGQUIT, SIG_DFL); |
| execute(buf); |
| (void) printf("can't find `%s'\r\n", buf); |
| exit(0); |
| } |
| if (boolean(value(VERBOSE))) |
| prtime("away for ", time(0)-start); |
| (void) write(fildes[1], (char *)&ccc, 1); |
| intr("off"); |
| (void) signal(SIGINT, SIG_DFL); |
| (void) signal(SIGQUIT, SIG_DFL); |
| } |
| |
| /* |
| * Fork a program with: |
| * 0 <-> remote tty in |
| * 1 <-> remote tty out |
| * 2 <-> local tty stderr out |
| */ |
| void |
| consh(int c) |
| { |
| char buf[256]; |
| int cpid, status, p; |
| sig_handler_t ointr, oquit; |
| time_t start; |
| |
| (void) putchar(c); |
| if (prompt("Local command? ", buf, sizeof (buf))) |
| return; |
| (void) kill(pid, SIGIOT); /* put TIPOUT into a wait state */ |
| (void) read(repdes[0], (char *)&ccc, 1); |
| ointr = signal(SIGINT, SIG_IGN); |
| oquit = signal(SIGQUIT, SIG_IGN); |
| unraw(); |
| /* |
| * Set up file descriptors in the child and |
| * let it go... |
| */ |
| if ((cpid = fork()) < 0) |
| (void) printf("can't fork!\r\n"); |
| else if (cpid) { |
| start = time(0); |
| while ((p = wait(&status)) > 0 && p != cpid) |
| ; |
| raw(); |
| (void) signal(SIGINT, ointr); |
| (void) signal(SIGQUIT, oquit); |
| } else { |
| int i; |
| |
| userperm(); |
| (void) dup2(FD, 0); |
| (void) dup2(0, 1); |
| for (i = 3; i < 20; i++) |
| (void) close(i); |
| (void) signal(SIGINT, SIG_DFL); |
| (void) signal(SIGQUIT, SIG_DFL); |
| execute(buf); |
| (void) printf("can't find `%s'\r\n", buf); |
| exit(0); |
| } |
| if (boolean(value(VERBOSE))) |
| prtime("\r\naway for ", time(0)-start); |
| (void) write(fildes[1], (char *)&ccc, 1); |
| } |
| |
| /* |
| * Escape to local shell |
| */ |
| /* ARGSUSED */ |
| void |
| shell(int cc) |
| { |
| int shpid, status; |
| sig_handler_t ointr, oquit; |
| char *cp; |
| |
| (void) printf("[sh]\r\n"); |
| ointr = signal(SIGINT, SIG_IGN); |
| oquit = signal(SIGQUIT, SIG_IGN); |
| unraw(); |
| if (shpid = fork()) { |
| while (shpid != wait(&status)) |
| ; |
| raw(); |
| (void) printf("\r\n!\r\n"); |
| (void) signal(SIGINT, ointr); |
| (void) signal(SIGQUIT, oquit); |
| } else { |
| userperm(); |
| (void) signal(SIGQUIT, SIG_DFL); |
| (void) signal(SIGINT, SIG_DFL); |
| if ((cp = strrchr(value(SHELL), '/')) == NULL) |
| cp = value(SHELL); |
| else |
| cp++; |
| (void) execl(value(SHELL), cp, 0); |
| (void) printf("\r\ncan't execl!\r\n"); |
| exit(1); |
| } |
| } |
| |
| /* |
| * TIPIN portion of scripting |
| * initiate the conversation with TIPOUT |
| */ |
| void |
| setscript(void) |
| { |
| char c; |
| |
| if (strlen(value(RECORD)) >= PATH_MAX-1) { |
| (void) fprintf(stderr, "tip: record file name too long\r\n"); |
| return; |
| } |
| /* |
| * enable TIPOUT side for dialogue |
| */ |
| (void) kill(pid, SIGEMT); |
| if (boolean(value(SCRIPT))) |
| (void) write(fildes[1], value(RECORD), strlen(value(RECORD))); |
| (void) write(fildes[1], "\n", 1); |
| /* |
| * wait for TIPOUT to finish |
| */ |
| (void) read(repdes[0], &c, 1); |
| if (c == 'n') |
| (void) fprintf(stderr, "tip: can't create record file %s\r\n", |
| value(RECORD)); |
| } |
| |
| /* |
| * Change current working directory of |
| * local portion of tip |
| */ |
| /* ARGSUSED */ |
| void |
| chdirectory(int cc) |
| { |
| char dirname[80]; |
| char *cp = dirname; |
| |
| if (prompt("[cd] ", dirname, sizeof (dirname))) { |
| if (stoprompt) |
| return; |
| cp = value(HOME); |
| } |
| if (chdir(cp) < 0) |
| (void) printf("%s: bad directory\r\n", cp); |
| (void) printf("!\r\n"); |
| } |
| |
| void |
| tip_abort(char *msg) |
| { |
| /* don't want to hear about our child */ |
| (void) signal(SIGCHLD, SIG_DFL); |
| (void) kill(pid, SIGTERM); |
| myperm(); |
| disconnect(msg); |
| if (msg != NOSTR) |
| (void) printf("\r\n%s", msg); |
| (void) printf("\r\n[EOT]\r\n"); |
| delock(uucplock); |
| unraw(); |
| exit(0); |
| } |
| |
| /* ARGSUSED */ |
| void |
| finish(int cc) |
| { |
| char *dismsg; |
| |
| if ((dismsg = value(DISCONNECT)) != NOSTR) { |
| (void) write(FD, dismsg, strlen(dismsg)); |
| (void) sleep(5); |
| } |
| tip_abort(NOSTR); |
| } |
| |
| void |
| intcopy(void) |
| { |
| |
| (void) signal(SIGINT, SIG_IGN); |
| siglongjmp(intbuf, 1); |
| } |
| |
| void |
| execute(char *s) |
| { |
| char *cp; |
| |
| if ((cp = strrchr(value(SHELL), '/')) == NULL) |
| cp = value(SHELL); |
| else |
| cp++; |
| (void) execl(value(SHELL), cp, "-c", s, 0); |
| } |
| |
| int |
| args(char *buf, char *a[], size_t na) |
| { |
| char *p = buf, *start; |
| char **parg = a; |
| int n = 0; |
| |
| do { |
| while (*p && (*p == ' ' || *p == '\t')) |
| p++; |
| start = p; |
| if (*p) |
| *parg = p; |
| while (*p && (*p != ' ' && *p != '\t')) |
| p++; |
| if (p != start) |
| parg++, n++; |
| if (*p) |
| *p++ = '\0'; |
| } while (*p && n < na); |
| |
| return (n); |
| } |
| |
| void |
| prtime(char *s, time_t a) |
| { |
| int i; |
| int nums[3]; |
| |
| for (i = 0; i < 3; i++) { |
| nums[i] = (int)(a % quant[i]); |
| a /= quant[i]; |
| } |
| (void) printf("%s", s); |
| while (--i >= 0) |
| if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0) |
| (void) printf("%d %s%c ", nums[i], sep[i], |
| nums[i] == 1 ? '\0' : 's'); |
| (void) printf("\r\n!\r\n"); |
| } |
| |
| /* ARGSUSED */ |
| void |
| variable(int cc) |
| { |
| char buf[256]; |
| |
| if (prompt("[set] ", buf, sizeof (buf))) |
| return; |
| vlex(buf); |
| if (vtable[BEAUTIFY].v_access&CHANGED) { |
| vtable[BEAUTIFY].v_access &= ~CHANGED; |
| (void) kill(pid, SIGSYS); |
| } |
| if (vtable[SCRIPT].v_access&CHANGED) { |
| vtable[SCRIPT].v_access &= ~CHANGED; |
| setscript(); |
| /* |
| * So that "set record=blah script" doesn't |
| * cause two transactions to occur. |
| */ |
| if (vtable[RECORD].v_access&CHANGED) |
| vtable[RECORD].v_access &= ~CHANGED; |
| } |
| if (vtable[RECORD].v_access&CHANGED) { |
| vtable[RECORD].v_access &= ~CHANGED; |
| if (boolean(value(SCRIPT))) |
| setscript(); |
| } |
| if (vtable[TAND].v_access&CHANGED) { |
| vtable[TAND].v_access &= ~CHANGED; |
| if (boolean(value(TAND))) |
| tandem("on"); |
| else |
| tandem("off"); |
| } |
| if (vtable[LECHO].v_access&CHANGED) { |
| vtable[LECHO].v_access &= ~CHANGED; |
| boolean(value(HALFDUPLEX)) = boolean(value(LECHO)); |
| } |
| if (vtable[PARITY].v_access&CHANGED) { |
| vtable[PARITY].v_access &= ~CHANGED; |
| setparity(NULL); |
| } |
| if (vtable[BAUDRATE].v_access&CHANGED) { |
| vtable[BAUDRATE].v_access &= ~CHANGED; |
| ttysetup(speed(number(value(BAUDRATE)))); |
| } |
| if (vtable[HARDWAREFLOW].v_access & CHANGED) { |
| vtable[HARDWAREFLOW].v_access &= ~CHANGED; |
| if (boolean(value(HARDWAREFLOW))) |
| hardwareflow("on"); |
| else |
| hardwareflow("off"); |
| } |
| } |
| |
| /* |
| * Turn tandem mode on or off for remote tty. |
| */ |
| void |
| tandem(char *option) |
| { |
| struct termios rmtty; |
| |
| (void) ioctl(FD, TCGETS, (char *)&rmtty); |
| if (equal(option, "on")) { |
| rmtty.c_iflag |= IXOFF|IXON; |
| arg.c_iflag |= IXOFF|IXON; |
| rmtty.c_cc[VSTART] = defarg.c_cc[VSTART]; |
| rmtty.c_cc[VSTOP] = defarg.c_cc[VSTOP]; |
| } else { |
| rmtty.c_iflag &= ~(IXOFF|IXON); |
| arg.c_iflag &= ~(IXOFF|IXON); |
| } |
| (void) ioctl(FD, TCSETSF, (char *)&rmtty); |
| (void) ioctl(0, TCSETSF, (char *)&arg); |
| } |
| |
| /* |
| * Turn hardwareflow mode on or off for remote tty. |
| */ |
| void |
| hardwareflow(char *option) |
| { |
| struct termios rmtty; |
| |
| (void) ioctl(FD, TCGETS, (char *)&rmtty); |
| if (equal(option, "on")) { |
| rmtty.c_cflag |= (CRTSCTS|CRTSXOFF); |
| } else { |
| rmtty.c_cflag &= ~(CRTSCTS|CRTSXOFF); |
| } |
| (void) ioctl(FD, TCSETSF, (char *)&rmtty); |
| } |
| |
| /* |
| * Turn interrupts from local tty on or off. |
| */ |
| void |
| intr(char *option) |
| { |
| |
| if (equal(option, "on")) |
| arg.c_lflag |= ISIG; |
| else |
| arg.c_lflag &= ~ISIG; |
| (void) ioctl(0, TCSETSF, (char *)&arg); |
| } |
| |
| /* |
| * Send a break. |
| */ |
| /* ARGSUSED */ |
| void |
| genbrk(int cc) |
| { |
| |
| (void) ioctl(FD, TCSBRK, 0); |
| } |
| |
| /* |
| * Suspend tip |
| */ |
| void |
| suspend(int c) |
| { |
| |
| unraw(); |
| (void) kill(c == _CTRL('y') ? getpid() : 0, SIGTSTP); |
| raw(); |
| } |
| |
| /* |
| * expand a file name if it includes shell meta characters |
| */ |
| |
| char * |
| expand(char name[]) |
| { |
| static char xname[BUFSIZ]; |
| char cmdbuf[BUFSIZ]; |
| int pid, l; |
| char *cp, *Shell; |
| int s, pivec[2]; |
| |
| if (!anyof(name, "~{[*?$`'\"\\")) |
| return (name); |
| if (pipe(pivec) < 0) { |
| perror("pipe"); |
| return (name); |
| } |
| (void) snprintf(cmdbuf, sizeof (cmdbuf), "echo %s", name); |
| if ((pid = vfork()) == 0) { |
| userperm(); |
| Shell = value(SHELL); |
| if (Shell == NOSTR) |
| Shell = "/bin/sh"; |
| (void) close(pivec[0]); |
| (void) close(1); |
| (void) dup(pivec[1]); |
| (void) close(pivec[1]); |
| (void) close(2); |
| (void) execl(Shell, Shell, "-c", cmdbuf, 0); |
| _exit(1); |
| } |
| if (pid == -1) { |
| perror("fork"); |
| (void) close(pivec[0]); |
| (void) close(pivec[1]); |
| return (NOSTR); |
| } |
| (void) close(pivec[1]); |
| l = read(pivec[0], xname, BUFSIZ); |
| (void) close(pivec[0]); |
| while (wait(&s) != pid) |
| ; |
| s &= 0377; |
| if (s != 0 && s != SIGPIPE) { |
| (void) fprintf(stderr, "\"Echo\" failed\n"); |
| return (NOSTR); |
| } |
| if (l < 0) { |
| perror("read"); |
| return (NOSTR); |
| } |
| if (l == 0) { |
| (void) fprintf(stderr, "\"%s\": No match\n", name); |
| return (NOSTR); |
| } |
| if (l == BUFSIZ) { |
| (void) fprintf(stderr, "Buffer overflow expanding \"%s\"\n", |
| name); |
| return (NOSTR); |
| } |
| xname[l] = 0; |
| for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) |
| ; |
| *++cp = '\0'; |
| return (xname); |
| } |
| |
| /* |
| * Are any of the characters in the two strings the same? |
| */ |
| |
| int |
| anyof(char *s1, char *s2) |
| { |
| int c; |
| |
| while ((c = *s1++) != 0) |
| if (any(c, s2)) |
| return (1); |
| return (0); |
| } |