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