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