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