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