1 /* $NetBSD: cmds.c,v 1.35 2012/02/24 16:03:39 joerg Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; 36 #endif 37 __RCSID("$NetBSD: cmds.c,v 1.35 2012/02/24 16:03:39 joerg Exp $"); 38 #endif /* not lint */ 39 40 #include "tip.h" 41 #include "pathnames.h" 42 43 /* 44 * tip 45 * 46 * miscellaneous commands 47 */ 48 49 int quant[] = { 60, 60, 24 }; 50 51 char null = '\0'; 52 const char *sep[] = { "second", "minute", "hour" }; 53 static char *argv[10]; /* argument vector for take and put */ 54 55 int args(char *, char **); 56 int anyof(char *, const char *); 57 void execute(char *); 58 __dead static void intcopy(int); 59 void prtime(const char *, time_t); 60 void stopsnd(int); 61 void transfer(char *, int, const char *); 62 void transmit(FILE *, const char *, char *); 63 64 /* 65 * FTP - remote ==> local 66 * get a file from the remote host 67 */ 68 void 69 getfl(char c) 70 { 71 char buf[256], *cp; 72 73 (void)putchar(c); 74 /* 75 * get the UNIX receiving file's name 76 */ 77 if (prompt("Local file name? ", copyname, sizeof copyname)) 78 return; 79 cp = expand(copyname); 80 if ((sfd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) { 81 (void)printf("\r\n%s: cannot create\r\n", copyname); 82 return; 83 } 84 85 /* 86 * collect parameters 87 */ 88 if (prompt("List command for remote system? ", buf, 89 sizeof buf)) { 90 (void)unlink(copyname); 91 return; 92 } 93 transfer(buf, sfd, value(EOFREAD)); 94 } 95 96 /* 97 * Cu-like take command 98 */ 99 /* ARGSUSED */ 100 void 101 cu_take(char dummy __unused) 102 { 103 int fd, argc; 104 char line[BUFSIZ], *cp; 105 106 if (prompt("[take] ", copyname, sizeof copyname)) 107 return; 108 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 109 (void)printf("usage: <take> from [to]\r\n"); 110 return; 111 } 112 if (argc == 1) 113 argv[1] = argv[0]; 114 cp = expand(argv[1]); 115 if ((fd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) { 116 (void)printf("\r\n%s: cannot create\r\n", argv[1]); 117 return; 118 } 119 (void)snprintf(line, sizeof line, "cat %s;echo \01", argv[0]); 120 transfer(line, fd, "\01"); 121 } 122 123 static jmp_buf intbuf; 124 /* 125 * Bulk transfer routine -- 126 * used by getfl(), cu_take(), and pipefile() 127 */ 128 void 129 transfer(char *buf, int fd, const char *eofchars) 130 { 131 int ct; 132 char c, buffer[BUFSIZ]; 133 char * volatile p; 134 int cnt, eof; 135 time_t start; 136 sig_t f; 137 char r; 138 139 p = buffer; 140 xpwrite(FD, buf, strlen(buf)); 141 quit = 0; 142 (void)write(attndes[1], "W", 1); /* Put TIPOUT into a wait state */ 143 (void)read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ 144 145 /* 146 * finish command 147 */ 148 r = '\r'; 149 xpwrite(FD, &r, 1); 150 do 151 (void)read(FD, &c, 1); 152 while ((c&STRIP_PAR) != '\n'); 153 (void)tcsetattr(0, TCSAFLUSH, &defchars); 154 155 (void) setjmp(intbuf); 156 f = signal(SIGINT, intcopy); 157 start = time(0); 158 for (ct = 0; !quit;) { 159 eof = read(FD, &c, 1) <= 0; 160 c &= STRIP_PAR; 161 if (quit) 162 continue; 163 if (eof || any(c, eofchars)) 164 break; 165 if (c == 0) 166 continue; /* ignore nulls */ 167 if (c == '\r') 168 continue; 169 *p++ = c; 170 171 if (c == '\n' && boolean(value(VERBOSE))) 172 (void)printf("\r%d", ++ct); 173 if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { 174 if (write(fd, buffer, (size_t)cnt) != cnt) { 175 (void)printf("\r\nwrite error\r\n"); 176 quit = 1; 177 } 178 p = buffer; 179 } 180 } 181 if ((cnt = (p-buffer)) != 0) 182 if (write(fd, buffer, (size_t)cnt) != cnt) 183 (void)printf("\r\nwrite error\r\n"); 184 185 if (boolean(value(VERBOSE))) 186 prtime(" lines transferred in ", time(0)-start); 187 (void)tcsetattr(0, TCSAFLUSH, &term); 188 (void)write(fildes[1], (char *)&ccc, 1); 189 (void)signal(SIGINT, f); 190 (void)close(fd); 191 } 192 193 /* 194 * FTP - remote ==> local process 195 * send remote input to local process via pipe 196 */ 197 /* ARGSUSED */ 198 void 199 pipefile(char dummy __unused) 200 { 201 int cpid, pdes[2]; 202 char buf[256]; 203 int status, p; 204 205 if (prompt("Local command? ", buf, sizeof buf)) 206 return; 207 208 if (pipe(pdes)) { 209 (void)printf("can't establish pipe\r\n"); 210 return; 211 } 212 213 if ((cpid = fork()) < 0) { 214 (void)printf("can't fork!\r\n"); 215 return; 216 } else if (cpid) { 217 if (prompt("List command for remote system? ", buf, 218 sizeof buf)) { 219 (void)close(pdes[0]); 220 (void)close(pdes[1]); 221 (void)kill(cpid, SIGKILL); 222 } else { 223 (void)close(pdes[0]); 224 (void)signal(SIGPIPE, intcopy); 225 transfer(buf, pdes[1], value(EOFREAD)); 226 (void)signal(SIGPIPE, SIG_DFL); 227 while ((p = wait(&status)) > 0 && p != cpid) 228 ; 229 } 230 } else { 231 (void)dup2(pdes[0], 0); 232 (void)close(pdes[0]); 233 (void)closefrom(3); 234 execute(buf); 235 (void)printf("can't execl!\r\n"); 236 exit(0); 237 } 238 } 239 240 /* 241 * Interrupt service routine for FTP 242 */ 243 /* ARGSUSED */ 244 void 245 stopsnd(int dummy __unused) 246 { 247 248 stop = 1; 249 (void)signal(SIGINT, SIG_IGN); 250 } 251 252 /* 253 * FTP - local ==> remote 254 * send local file to remote host 255 * terminate transmission with pseudo EOF sequence 256 */ 257 void 258 sendfile(char cc) 259 { 260 FILE *fd; 261 char *fnamex; 262 263 (void)putchar(cc); 264 /* 265 * get file name 266 */ 267 if (prompt("Local file name? ", fname, sizeof fname)) 268 return; 269 270 /* 271 * look up file 272 */ 273 fnamex = expand(fname); 274 if ((fd = fopen(fnamex, "r")) == NULL) { 275 (void)printf("%s: cannot open\r\n", fname); 276 return; 277 } 278 transmit(fd, value(EOFWRITE), NULL); 279 if (!boolean(value(ECHOCHECK))) 280 (void)tcdrain(FD); 281 } 282 283 /* 284 * Bulk transfer routine to remote host -- 285 * used by sendfile() and cu_put() 286 */ 287 void 288 transmit(FILE *fd, const char *eofchars, char *command) 289 { 290 const char *pc; 291 char lastc; 292 int c; 293 int ccount, lcount; 294 time_t start_t, stop_t; 295 sig_t f; 296 297 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 298 stop = 0; 299 f = signal(SIGINT, stopsnd); 300 (void)tcsetattr(0, TCSAFLUSH, &defchars); 301 (void)read(repdes[0], (char *)&ccc, 1); 302 if (command != NULL) { 303 for (pc = command; *pc; pc++) 304 sendchar(*pc); 305 if (boolean(value(ECHOCHECK))) 306 (void)read(FD, &c, (size_t)1); /* trailing \n */ 307 else { 308 (void)tcdrain(FD); 309 (void)sleep(5); /* wait for remote stty to take effect */ 310 } 311 } 312 lcount = 0; 313 lastc = '\0'; 314 start_t = time(0); 315 /* CONSTCOND */ 316 while (1) { 317 ccount = 0; 318 do { 319 c = getc(fd); 320 if (stop) 321 goto out; 322 if (c == EOF) 323 goto out; 324 if (c == 0177 && !boolean(value(RAWFTP))) 325 continue; 326 lastc = c; 327 if (c < 040) { 328 if (c == '\n') { 329 if (!boolean(value(RAWFTP))) 330 c = '\r'; 331 } 332 else if (c == '\t') { 333 if (!boolean(value(RAWFTP))) { 334 if (boolean(value(TABEXPAND))) { 335 sendchar(' '); 336 while ((++ccount % 8) != 0) 337 sendchar(' '); 338 continue; 339 } 340 } 341 } else 342 if (!boolean(value(RAWFTP))) 343 continue; 344 } 345 sendchar(c); 346 } while (c != '\r' && !boolean(value(RAWFTP))); 347 if (boolean(value(VERBOSE))) 348 (void)printf("\r%d", ++lcount); 349 if (boolean(value(ECHOCHECK))) { 350 timedout = 0; 351 (void)alarm((unsigned int)number(value(ETIMEOUT))); 352 do { /* wait for prompt */ 353 (void)read(FD, &c, (size_t)1); 354 if (timedout || stop) { 355 if (timedout) 356 (void)printf( 357 "\r\ntimed out at eol\r\n"); 358 (void)alarm(0); 359 goto out; 360 } 361 } while ((c&STRIP_PAR) != character(value(PROMPT))); 362 (void)alarm(0); 363 } 364 } 365 out: 366 if (lastc != '\n' && !boolean(value(RAWFTP))) 367 sendchar('\r'); 368 if (eofchars) { 369 for (pc = eofchars; *pc; pc++) 370 sendchar(*pc); 371 } 372 stop_t = time(0); 373 (void)fclose(fd); 374 (void)signal(SIGINT, f); 375 if (boolean(value(VERBOSE))) { 376 if (boolean(value(RAWFTP))) 377 prtime(" chars transferred in ", stop_t-start_t); 378 else 379 prtime(" lines transferred in ", stop_t-start_t); 380 } 381 (void)write(fildes[1], (char *)&ccc, 1); 382 (void)tcsetattr(0, TCSAFLUSH, &term); 383 } 384 385 /* 386 * Cu-like put command 387 */ 388 /* ARGSUSED */ 389 void 390 cu_put(char dummy __unused) 391 { 392 FILE *fd; 393 char line[BUFSIZ]; 394 int argc; 395 char *copynamex; 396 397 if (prompt("[put] ", copyname, sizeof copyname)) 398 return; 399 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 400 (void)printf("usage: <put> from [to]\r\n"); 401 return; 402 } 403 if (argc == 1) 404 argv[1] = argv[0]; 405 copynamex = expand(argv[0]); 406 if ((fd = fopen(copynamex, "r")) == NULL) { 407 (void)printf("%s: cannot open\r\n", copynamex); 408 return; 409 } 410 if (boolean(value(ECHOCHECK))) 411 (void)snprintf(line, sizeof line, "cat>%s\r", argv[1]); 412 else 413 (void)snprintf(line, sizeof line, "stty -echo;cat>%s;stty echo\r", argv[1]); 414 transmit(fd, "\04", line); 415 } 416 417 /* 418 * FTP - send single character 419 * wait for echo & handle timeout 420 */ 421 void 422 sendchar(char c) 423 { 424 char cc; 425 int retry = 0; 426 427 cc = c; 428 xpwrite(FD, &cc, 1); 429 #ifdef notdef 430 if (number(value(CDELAY)) > 0 && c != '\r') 431 nap(number(value(CDELAY))); 432 #endif 433 if (!boolean(value(ECHOCHECK))) { 434 #ifdef notdef 435 if (number(value(LDELAY)) > 0 && c == '\r') 436 nap(number(value(LDELAY))); 437 #endif 438 return; 439 } 440 tryagain: 441 timedout = 0; 442 (void)alarm((unsigned int)number(value(ETIMEOUT))); 443 (void)read(FD, &cc, 1); 444 (void)alarm(0); 445 if (timedout) { 446 (void)printf("\r\ntimeout error (%s)\r\n", ctrl(c)); 447 if (retry++ > 3) 448 return; 449 xpwrite(FD, &null, 1); /* poke it */ 450 goto tryagain; 451 } 452 } 453 454 /* ARGSUSED */ 455 void 456 alrmtimeout(int dummy __unused) 457 { 458 459 (void)signal(SIGALRM, alrmtimeout); 460 timedout = 1; 461 } 462 463 /* 464 * Stolen from consh() -- puts a remote file on the output of a local command. 465 * Identical to consh() except for where stdout goes. 466 */ 467 void 468 pipeout(char c) 469 { 470 char buf[256]; 471 int cpid, status, p; 472 time_t start = 0; 473 474 (void)putchar(c); 475 if (prompt("Local command? ", buf, sizeof buf)) 476 return; 477 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 478 (void)signal(SIGINT, SIG_IGN); 479 (void)signal(SIGQUIT, SIG_IGN); 480 (void)tcsetattr(0, TCSAFLUSH, &defchars); 481 (void)read(repdes[0], (char *)&ccc, 1); 482 /* 483 * Set up file descriptors in the child and 484 * let it go... 485 */ 486 if ((cpid = fork()) < 0) 487 (void)printf("can't fork!\r\n"); 488 else if (cpid) { 489 start = time(0); 490 while ((p = wait(&status)) > 0 && p != cpid) 491 ; 492 } else { 493 (void)dup2(FD, 1); 494 (void)closefrom(3); 495 (void)signal(SIGINT, SIG_DFL); 496 (void)signal(SIGQUIT, SIG_DFL); 497 execute(buf); 498 (void)printf("can't find `%s'\r\n", buf); 499 exit(0); 500 } 501 if (boolean(value(VERBOSE))) 502 prtime("away for ", time(0)-start); 503 (void)write(fildes[1], (char *)&ccc, 1); 504 (void)tcsetattr(0, TCSAFLUSH, &term); 505 (void)signal(SIGINT, SIG_DFL); 506 (void)signal(SIGQUIT, SIG_DFL); 507 } 508 509 /* 510 * Fork a program with: 511 * 0 <-> remote tty in 512 * 1 <-> remote tty out 513 * 2 <-> local tty out 514 */ 515 void 516 consh(char c) 517 { 518 char buf[256]; 519 int cpid, status, p; 520 time_t start = 0; 521 522 (void)putchar(c); 523 if (prompt("Local command? ", buf, sizeof buf)) 524 return; 525 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 526 (void)signal(SIGINT, SIG_IGN); 527 (void)signal(SIGQUIT, SIG_IGN); 528 (void)tcsetattr(0, TCSAFLUSH, &defchars); 529 (void)read(repdes[0], (char *)&ccc, 1); 530 /* 531 * Set up file descriptors in the child and 532 * let it go... 533 */ 534 if ((cpid = fork()) < 0) 535 (void)printf("can't fork!\r\n"); 536 else if (cpid) { 537 start = time(0); 538 while ((p = wait(&status)) > 0 && p != cpid) 539 ; 540 } else { 541 (void)dup2(FD, 0); 542 (void)dup2(FD, 1); 543 (void)closefrom(3); 544 (void)signal(SIGINT, SIG_DFL); 545 (void)signal(SIGQUIT, SIG_DFL); 546 execute(buf); 547 (void)printf("can't find `%s'\r\n", buf); 548 exit(0); 549 } 550 if (boolean(value(VERBOSE))) 551 prtime("away for ", time(0)-start); 552 (void)write(fildes[1], (char *)&ccc, 1); 553 (void)tcsetattr(0, TCSAFLUSH, &term); 554 (void)signal(SIGINT, SIG_DFL); 555 (void)signal(SIGQUIT, SIG_DFL); 556 } 557 558 /* 559 * Escape to local shell 560 */ 561 /* ARGSUSED */ 562 void 563 shell(char dummy __unused) 564 { 565 int shpid, status; 566 const char *cp; 567 568 (void)printf("[sh]\r\n"); 569 (void)signal(SIGINT, SIG_IGN); 570 (void)signal(SIGQUIT, SIG_IGN); 571 unraw(); 572 switch (shpid = fork()) { 573 default: 574 while (shpid != wait(&status)); 575 raw(); 576 (void)printf("\r\n!\r\n"); 577 (void)signal(SIGINT, SIG_DFL); 578 (void)signal(SIGQUIT, SIG_DFL); 579 break; 580 case 0: 581 (void)signal(SIGQUIT, SIG_DFL); 582 (void)signal(SIGINT, SIG_DFL); 583 if ((cp = strrchr(value(SHELL), '/')) == NULL) 584 cp = value(SHELL); 585 else 586 cp++; 587 (void)execl(value(SHELL), cp, NULL); 588 (void)fprintf(stderr, "\r\n"); 589 err(1, "can't execl"); 590 /* NOTREACHED */ 591 case -1: 592 (void)fprintf(stderr, "\r\n"); 593 err(1, "can't fork"); 594 /* NOTREACHED */ 595 } 596 } 597 598 /* 599 * TIPIN portion of scripting 600 * initiate the conversation with TIPOUT 601 */ 602 void 603 setscript(void) 604 { 605 char c; 606 /* 607 * enable TIPOUT side for dialogue 608 */ 609 (void)write(attndes[1], "S", 1); 610 if (boolean(value(SCRIPT)) && strlen(value(RECORD))) 611 (void)write(fildes[1], value(RECORD), strlen(value(RECORD))); 612 (void)write(fildes[1], "\n", 1); 613 /* 614 * wait for TIPOUT to finish 615 */ 616 (void)read(repdes[0], &c, 1); 617 if (c == 'n') 618 (void)printf("can't create %s\r\n", (char *)value(RECORD)); 619 } 620 621 /* 622 * Change current working directory of 623 * local portion of tip 624 */ 625 /* ARGSUSED */ 626 void 627 chdirectory(char dummy __unused) 628 { 629 char dirnam[80]; 630 const char *cp = dirnam; 631 632 if (prompt("[cd] ", dirnam, sizeof dirnam)) { 633 if (stoprompt) 634 return; 635 cp = value(HOME); 636 } 637 if (chdir(cp) < 0) 638 (void)printf("%s: bad directory\r\n", cp); 639 (void)printf("!\r\n"); 640 } 641 642 void 643 tipabort(const char *msg) 644 { 645 646 (void)kill(pid, SIGTERM); 647 disconnect(msg); 648 if (msg != NULL) 649 (void)printf("\r\n%s", msg); 650 (void)printf("\r\n[EOT]\r\n"); 651 unraw(); 652 exit(0); 653 } 654 655 /* ARGSUSED */ 656 void 657 finish(char dummy __unused) 658 { 659 const char *dismsg; 660 661 dismsg = value(DISCONNECT); 662 if (dismsg != NULL && dismsg[0] != '\0') { 663 (void)write(FD, dismsg, strlen(dismsg)); 664 (void)sleep(5); 665 } 666 tipabort(NULL); 667 } 668 669 /* ARGSUSED */ 670 void 671 intcopy(int dummy __unused) 672 { 673 674 raw(); 675 quit = 1; 676 longjmp(intbuf, 1); 677 } 678 679 void 680 execute(char *s) 681 { 682 const char *cp; 683 684 if ((cp = strrchr(value(SHELL), '/')) == NULL) 685 cp = value(SHELL); 686 else 687 cp++; 688 (void)execl(value(SHELL), cp, "-c", s, NULL); 689 } 690 691 int 692 args(char *buf, char *a[]) 693 { 694 char *p = buf, *start; 695 char **parg = a; 696 int n = 0; 697 698 do { 699 while (*p && (*p == ' ' || *p == '\t')) 700 p++; 701 start = p; 702 if (*p) 703 *parg = p; 704 while (*p && (*p != ' ' && *p != '\t')) 705 p++; 706 if (p != start) 707 parg++, n++; 708 if (*p) 709 *p++ = '\0'; 710 } while (*p); 711 712 return(n); 713 } 714 715 void 716 prtime(const char *s, time_t a) 717 { 718 int i; 719 int nums[3]; 720 721 for (i = 0; i < 3; i++) { 722 nums[i] = (int)(a % quant[i]); 723 a /= quant[i]; 724 } 725 (void)printf("%s", s); 726 while (--i >= 0) 727 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0)) 728 (void)printf("%d %s%c ", nums[i], sep[i], 729 nums[i] == 1 ? '\0' : 's'); 730 (void)printf("\r\n!\r\n"); 731 } 732 733 /* ARGSUSED */ 734 void 735 variable(char dummy __unused) 736 { 737 char buf[256]; 738 739 if (prompt("[set] ", buf, sizeof buf)) 740 return; 741 vlex(buf); 742 if (vtable[BEAUTIFY].v_access&CHANGED) { 743 vtable[BEAUTIFY].v_access &= ~CHANGED; 744 (void)write(attndes[1], "B", 1); /* Tell TIPOUT to toggle */ 745 } 746 if (vtable[SCRIPT].v_access&CHANGED) { 747 vtable[SCRIPT].v_access &= ~CHANGED; 748 setscript(); 749 /* 750 * So that "set record=blah script" doesn't 751 * cause two transactions to occur. 752 */ 753 if (vtable[RECORD].v_access&CHANGED) 754 vtable[RECORD].v_access &= ~CHANGED; 755 } 756 if (vtable[RECORD].v_access&CHANGED) { 757 vtable[RECORD].v_access &= ~CHANGED; 758 if (boolean(value(SCRIPT))) 759 setscript(); 760 } 761 if (vtable[TAND].v_access&CHANGED) { 762 vtable[TAND].v_access &= ~CHANGED; 763 if (boolean(value(TAND))) 764 tandem("on"); 765 else 766 tandem("off"); 767 } 768 if (vtable[LECHO].v_access&CHANGED) { 769 vtable[LECHO].v_access &= ~CHANGED; 770 HD = boolean(value(LECHO)); 771 } 772 if (vtable[PARITY].v_access&CHANGED) { 773 vtable[PARITY].v_access &= ~CHANGED; 774 setparity(NULL); /* XXX what is the correct arg? */ 775 } 776 if (vtable[HARDWAREFLOW].v_access&CHANGED) { 777 vtable[HARDWAREFLOW].v_access &= ~CHANGED; 778 if (boolean(value(HARDWAREFLOW))) 779 hardwareflow("on"); 780 else 781 hardwareflow("off"); 782 } 783 } 784 785 /* 786 * Turn tandem mode on or off for remote tty. 787 */ 788 void 789 tandem(const char *option) 790 { 791 struct termios rmtty; 792 793 (void)tcgetattr(FD, &rmtty); 794 if (strcmp(option, "on") == 0) { 795 rmtty.c_iflag |= IXOFF; 796 term.c_iflag |= IXOFF; 797 } else { 798 rmtty.c_iflag &= ~IXOFF; 799 term.c_iflag &= ~IXOFF; 800 } 801 (void)tcsetattr(FD, TCSADRAIN, &rmtty); 802 (void)tcsetattr(0, TCSADRAIN, &term); 803 } 804 805 /* 806 * Turn hardware flow control on or off for remote tty. 807 */ 808 void 809 hardwareflow(const char *option) 810 { 811 struct termios rmtty; 812 813 (void)tcgetattr(FD, &rmtty); 814 if (strcmp(option, "on") == 0) 815 rmtty.c_cflag |= CRTSCTS; 816 else 817 rmtty.c_cflag &= ~CRTSCTS; 818 (void)tcsetattr(FD, TCSADRAIN, &rmtty); 819 } 820 821 /* 822 * Send a break. 823 */ 824 /* ARGSUSED */ 825 void 826 genbrk(char dummy __unused) 827 { 828 829 (void)ioctl(FD, TIOCSBRK, NULL); 830 (void)sleep(1); 831 (void)ioctl(FD, TIOCCBRK, NULL); 832 } 833 834 /* 835 * Suspend tip 836 */ 837 void 838 suspend(char c) 839 { 840 841 unraw(); 842 (void)kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 843 raw(); 844 } 845 846 /* 847 * expand a file name if it includes shell meta characters 848 */ 849 850 char * 851 expand(char aname[]) 852 { 853 static char xname[BUFSIZ]; 854 char * volatile name; 855 char cmdbuf[BUFSIZ]; 856 int mypid, l; 857 char *cp; 858 const char *Shell; 859 int s, pivec[2]; 860 861 name = aname; 862 if (!anyof(name, "~{[*?$`'\"\\")) 863 return(name); 864 if (pipe(pivec) < 0) { 865 warn("pipe"); 866 return(name); 867 } 868 (void)snprintf(cmdbuf, sizeof cmdbuf, "echo %s", name); 869 if ((mypid = vfork()) == 0) { 870 Shell = value(SHELL); 871 if (Shell == NULL) 872 Shell = _PATH_BSHELL; 873 (void)close(pivec[0]); 874 (void)close(1); 875 (void)dup(pivec[1]); 876 (void)close(pivec[1]); 877 (void)close(2); 878 (void)execl(Shell, Shell, "-c", cmdbuf, NULL); 879 _exit(1); 880 } 881 if (mypid == -1) { 882 warn("fork"); 883 (void)close(pivec[0]); 884 (void)close(pivec[1]); 885 return(NULL); 886 } 887 (void)close(pivec[1]); 888 l = read(pivec[0], xname, BUFSIZ); 889 (void)close(pivec[0]); 890 while (wait(&s) != mypid) 891 continue; 892 s &= 0377; 893 if (s != 0 && s != SIGPIPE) { 894 (void)fprintf(stderr, "\"Echo\" failed\n"); 895 return(NULL); 896 } 897 if (l < 0) { 898 warn("read"); 899 return(NULL); 900 } 901 if (l == 0) { 902 (void)fprintf(stderr, "\"%s\": No match\n", name); 903 return(NULL); 904 } 905 if (l == BUFSIZ) { 906 (void)fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 907 return(NULL); 908 } 909 xname[l] = 0; 910 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 911 ; 912 *++cp = '\0'; 913 return(xname); 914 } 915 916 /* 917 * Are any of the characters in the two strings the same? 918 */ 919 920 int 921 anyof(char *s1, const char *s2) 922 { 923 int c; 924 925 while ((c = *s1++) != '\0') 926 if (any(c, s2)) 927 return(1); 928 return(0); 929 } 930