1 #ifndef lint 2 static char sccsid[] = "@(#)cmds.c 4.11 (Berkeley) 03/11/85"; 3 #endif 4 5 /* 6 * FTP User Program -- Command Routines. 7 */ 8 #include <sys/param.h> 9 #include <sys/socket.h> 10 11 #include <arpa/ftp.h> 12 13 #include <signal.h> 14 #include <stdio.h> 15 #include <errno.h> 16 #include <netdb.h> 17 18 #include "ftp_var.h" 19 20 extern char *globerr; 21 extern char **glob(); 22 extern char *home; 23 extern short gflag; 24 extern char *remglob(); 25 extern char *getenv(); 26 extern char *index(); 27 extern char *rindex(); 28 29 /* 30 * Connect to peer server and 31 * auto-login, if possible. 32 */ 33 setpeer(argc, argv) 34 int argc; 35 char *argv[]; 36 { 37 struct hostent *host, *hookup(); 38 int port; 39 40 if (connected) { 41 printf("Already connected to %s, use disconnect first.\n", 42 hostname); 43 return; 44 } 45 if (argc < 2) { 46 strcat(line, " "); 47 printf("(to) "); 48 gets(&line[strlen(line)]); 49 makeargv(); 50 argc = margc; 51 argv = margv; 52 } 53 if (argc > 3) { 54 printf("usage: %s host-name [port]\n", argv[0]); 55 return; 56 } 57 port = sp->s_port; 58 if (argc > 2) { 59 port = atoi(argv[2]); 60 if (port <= 0) { 61 printf("%s: bad port number-- %s\n", argv[1], argv[2]); 62 printf ("usage: %s host-name [port]\n", argv[0]); 63 return; 64 } 65 port = htons(port); 66 } 67 host = hookup(argv[1], port); 68 if (host) { 69 connected = 1; 70 if (autologin) 71 login(host); 72 } 73 } 74 75 struct types { 76 char *t_name; 77 char *t_mode; 78 int t_type; 79 char *t_arg; 80 } types[] = { 81 { "ascii", "A", TYPE_A, 0 }, 82 { "binary", "I", TYPE_I, 0 }, 83 { "image", "I", TYPE_I, 0 }, 84 { "ebcdic", "E", TYPE_E, 0 }, 85 { "tenex", "L", TYPE_L, bytename }, 86 0 87 }; 88 89 /* 90 * Set transfer type. 91 */ 92 settype(argc, argv) 93 char *argv[]; 94 { 95 register struct types *p; 96 int comret; 97 98 if (argc > 2) { 99 char *sep; 100 101 printf("usage: %s [", argv[0]); 102 sep = " "; 103 for (p = types; p->t_name; p++) { 104 printf("%s%s", sep, p->t_name); 105 if (*sep == ' ') 106 sep = " | "; 107 } 108 printf(" ]\n"); 109 return; 110 } 111 if (argc < 2) { 112 printf("Using %s mode to transfer files.\n", typename); 113 return; 114 } 115 for (p = types; p->t_name; p++) 116 if (strcmp(argv[1], p->t_name) == 0) 117 break; 118 if (p->t_name == 0) { 119 printf("%s: unknown mode\n", argv[1]); 120 return; 121 } 122 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 123 comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 124 else 125 comret = command("TYPE %s", p->t_mode); 126 if (comret == COMPLETE) { 127 strcpy(typename, p->t_name); 128 type = p->t_type; 129 } 130 } 131 132 /* 133 * Set binary transfer type. 134 */ 135 /*VARARGS*/ 136 setbinary() 137 { 138 139 call(settype, "type", "binary", 0); 140 } 141 142 /* 143 * Set ascii transfer type. 144 */ 145 /*VARARGS*/ 146 setascii() 147 { 148 149 call(settype, "type", "ascii", 0); 150 } 151 152 /* 153 * Set tenex transfer type. 154 */ 155 /*VARARGS*/ 156 settenex() 157 { 158 159 call(settype, "type", "tenex", 0); 160 } 161 162 /* 163 * Set ebcdic transfer type. 164 */ 165 /*VARARGS*/ 166 setebcdic() 167 { 168 169 call(settype, "type", "ebcdic", 0); 170 } 171 172 /* 173 * Set file transfer mode. 174 */ 175 setmode(argc, argv) 176 char *argv[]; 177 { 178 179 printf("We only support %s mode, sorry.\n", modename); 180 } 181 182 /* 183 * Set file transfer format. 184 */ 185 setform(argc, argv) 186 char *argv[]; 187 { 188 189 printf("We only support %s format, sorry.\n", formname); 190 } 191 192 /* 193 * Set file transfer structure. 194 */ 195 setstruct(argc, argv) 196 char *argv[]; 197 { 198 199 printf("We only support %s structure, sorry.\n", structname); 200 } 201 202 /* 203 * Send a single file. 204 */ 205 put(argc, argv) 206 int argc; 207 char *argv[]; 208 { 209 char *cmd; 210 211 if (argc == 2) 212 argc++, argv[2] = argv[1]; 213 if (argc < 2) { 214 strcat(line, " "); 215 printf("(local-file) "); 216 gets(&line[strlen(line)]); 217 makeargv(); 218 argc = margc; 219 argv = margv; 220 } 221 if (argc < 2) { 222 usage: 223 printf("%s local-file remote-file\n", argv[0]); 224 return; 225 } 226 if (argc < 3) { 227 strcat(line, " "); 228 printf("(remote-file) "); 229 gets(&line[strlen(line)]); 230 makeargv(); 231 argc = margc; 232 argv = margv; 233 } 234 if (argc < 3) 235 goto usage; 236 if (!globulize(&argv[1])) 237 return; 238 cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 239 sendrequest(cmd, argv[1], argv[2]); 240 } 241 242 /* 243 * Send multiple files. 244 */ 245 mput(argc, argv) 246 char *argv[]; 247 { 248 register int i; 249 250 if (argc < 2) { 251 strcat(line, " "); 252 printf("(local-files) "); 253 gets(&line[strlen(line)]); 254 makeargv(); 255 argc = margc; 256 argv = margv; 257 } 258 if (argc < 2) { 259 printf("%s local-files\n", argv[0]); 260 return; 261 } 262 for (i = 1; i < argc; i++) { 263 register char **cpp, **gargs; 264 265 if (!doglob) { 266 if (confirm(argv[0], argv[i])) 267 sendrequest("STOR", argv[i], argv[i]); 268 continue; 269 } 270 gargs = glob(argv[i]); 271 if (globerr != NULL) { 272 printf("%s\n", globerr); 273 if (gargs) 274 blkfree(gargs); 275 continue; 276 } 277 for (cpp = gargs; cpp && *cpp != NULL; cpp++) 278 if (confirm(argv[0], *cpp)) 279 sendrequest("STOR", *cpp, *cpp); 280 if (gargs != NULL) 281 blkfree(gargs); 282 } 283 } 284 285 /* 286 * Receive one file. 287 */ 288 get(argc, argv) 289 char *argv[]; 290 { 291 292 if (argc == 2) 293 argc++, argv[2] = argv[1]; 294 if (argc < 2) { 295 strcat(line, " "); 296 printf("(remote-file) "); 297 gets(&line[strlen(line)]); 298 makeargv(); 299 argc = margc; 300 argv = margv; 301 } 302 if (argc < 2) { 303 usage: 304 printf("%s remote-file [ local-file ]\n", argv[0]); 305 return; 306 } 307 if (argc < 3) { 308 strcat(line, " "); 309 printf("(local-file) "); 310 gets(&line[strlen(line)]); 311 makeargv(); 312 argc = margc; 313 argv = margv; 314 } 315 if (argc < 3) 316 goto usage; 317 if (!globulize(&argv[2])) 318 return; 319 recvrequest("RETR", argv[2], argv[1], "w"); 320 } 321 322 /* 323 * Get multiple files. 324 */ 325 mget(argc, argv) 326 char *argv[]; 327 { 328 char *cp; 329 330 if (argc < 2) { 331 strcat(line, " "); 332 printf("(remote-files) "); 333 gets(&line[strlen(line)]); 334 makeargv(); 335 argc = margc; 336 argv = margv; 337 } 338 if (argc < 2) { 339 printf("%s remote-files\n", argv[0]); 340 return; 341 } 342 while ((cp = remglob(argc, argv)) != NULL) 343 if (confirm(argv[0], cp)) 344 recvrequest("RETR", cp, cp, "w"); 345 } 346 347 char * 348 remglob(argc, argv) 349 char *argv[]; 350 { 351 char temp[16]; 352 static char buf[MAXPATHLEN]; 353 static FILE *ftemp = NULL; 354 static char **args; 355 int oldverbose, oldhash; 356 char *cp, *mode; 357 358 if (!doglob) { 359 if (args == NULL) 360 args = argv; 361 if ((cp = *++args) == NULL) 362 args = NULL; 363 return (cp); 364 } 365 if (ftemp == NULL) { 366 strcpy(temp, "/tmp/ftpXXXXXX"); 367 mktemp(temp); 368 oldverbose = verbose, verbose = 0; 369 oldhash = hash, hash = 0; 370 for (mode = "w"; *++argv != NULL; mode = "a") 371 recvrequest ("NLST", temp, *argv, mode); 372 verbose = oldverbose; hash = oldhash; 373 ftemp = fopen(temp, "r"); 374 unlink(temp); 375 if (ftemp == NULL) { 376 printf("can't find list of remote files, oops\n"); 377 return (NULL); 378 } 379 } 380 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 381 fclose(ftemp), ftemp = NULL; 382 return (NULL); 383 } 384 if ((cp = index(buf, '\n')) != NULL) 385 *cp = '\0'; 386 return (buf); 387 } 388 389 char * 390 onoff(bool) 391 int bool; 392 { 393 394 return (bool ? "on" : "off"); 395 } 396 397 /* 398 * Show status. 399 */ 400 status(argc, argv) 401 char *argv[]; 402 { 403 404 if (connected) 405 printf("Connected to %s.\n", hostname); 406 else 407 printf("Not connected.\n"); 408 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 409 modename, typename, formname, structname); 410 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 411 onoff(verbose), onoff(bell), onoff(interactive), 412 onoff(doglob)); 413 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 414 onoff(hash), onoff(sendport)); 415 } 416 417 /* 418 * Set beep on cmd completed mode. 419 */ 420 /*VARARGS*/ 421 setbell() 422 { 423 424 bell = !bell; 425 printf("Bell mode %s.\n", onoff(bell)); 426 } 427 428 /* 429 * Turn on packet tracing. 430 */ 431 /*VARARGS*/ 432 settrace() 433 { 434 435 trace = !trace; 436 printf("Packet tracing %s.\n", onoff(trace)); 437 } 438 439 /* 440 * Toggle hash mark printing during transfers. 441 */ 442 /*VARARGS*/ 443 sethash() 444 { 445 446 hash = !hash; 447 printf("Hash mark printing %s", onoff(hash)); 448 if (hash) 449 printf(" (%d bytes/hash mark)", BUFSIZ); 450 printf(".\n"); 451 } 452 453 /* 454 * Turn on printing of server echo's. 455 */ 456 /*VARARGS*/ 457 setverbose() 458 { 459 460 verbose = !verbose; 461 printf("Verbose mode %s.\n", onoff(verbose)); 462 } 463 464 /* 465 * Toggle PORT cmd use before each data connection. 466 */ 467 /*VARARGS*/ 468 setport() 469 { 470 471 sendport = !sendport; 472 printf("Use of PORT cmds %s.\n", onoff(sendport)); 473 } 474 475 /* 476 * Turn on interactive prompting 477 * during mget, mput, and mdelete. 478 */ 479 /*VARARGS*/ 480 setprompt() 481 { 482 483 interactive = !interactive; 484 printf("Interactive mode %s.\n", onoff(interactive)); 485 } 486 487 /* 488 * Toggle metacharacter interpretation 489 * on local file names. 490 */ 491 /*VARARGS*/ 492 setglob() 493 { 494 495 doglob = !doglob; 496 printf("Globbing %s.\n", onoff(doglob)); 497 } 498 499 /* 500 * Set debugging mode on/off and/or 501 * set level of debugging. 502 */ 503 /*VARARGS*/ 504 setdebug(argc, argv) 505 char *argv[]; 506 { 507 int val; 508 509 if (argc > 1) { 510 val = atoi(argv[1]); 511 if (val < 0) { 512 printf("%s: bad debugging value.\n", argv[1]); 513 return; 514 } 515 } else 516 val = !debug; 517 debug = val; 518 if (debug) 519 options |= SO_DEBUG; 520 else 521 options &= ~SO_DEBUG; 522 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 523 } 524 525 /* 526 * Set current working directory 527 * on remote machine. 528 */ 529 cd(argc, argv) 530 char *argv[]; 531 { 532 533 if (argc < 2) { 534 strcat(line, " "); 535 printf("(remote-directory) "); 536 gets(&line[strlen(line)]); 537 makeargv(); 538 argc = margc; 539 argv = margv; 540 } 541 if (argc < 2) { 542 printf("%s remote-directory\n", argv[0]); 543 return; 544 } 545 (void) command("CWD %s", argv[1]); 546 } 547 548 /* 549 * Set current working directory 550 * on local machine. 551 */ 552 lcd(argc, argv) 553 char *argv[]; 554 { 555 char buf[MAXPATHLEN]; 556 557 if (argc < 2) 558 argc++, argv[1] = home; 559 if (argc != 2) { 560 printf("%s local-directory\n", argv[0]); 561 return; 562 } 563 if (!globulize(&argv[1])) 564 return; 565 if (chdir(argv[1]) < 0) { 566 perror(argv[1]); 567 return; 568 } 569 printf("Local directory now %s\n", getwd(buf)); 570 } 571 572 /* 573 * Delete a single file. 574 */ 575 delete(argc, argv) 576 char *argv[]; 577 { 578 579 if (argc < 2) { 580 strcat(line, " "); 581 printf("(remote-file) "); 582 gets(&line[strlen(line)]); 583 makeargv(); 584 argc = margc; 585 argv = margv; 586 } 587 if (argc < 2) { 588 printf("%s remote-file\n", argv[0]); 589 return; 590 } 591 (void) command("DELE %s", argv[1]); 592 } 593 594 /* 595 * Delete multiple files. 596 */ 597 mdelete(argc, argv) 598 char *argv[]; 599 { 600 char *cp; 601 602 if (argc < 2) { 603 strcat(line, " "); 604 printf("(remote-files) "); 605 gets(&line[strlen(line)]); 606 makeargv(); 607 argc = margc; 608 argv = margv; 609 } 610 if (argc < 2) { 611 printf("%s remote-files\n", argv[0]); 612 return; 613 } 614 while ((cp = remglob(argc, argv)) != NULL) 615 if (confirm(argv[0], cp)) 616 (void) command("DELE %s", cp); 617 } 618 619 /* 620 * Rename a remote file. 621 */ 622 renamefile(argc, argv) 623 char *argv[]; 624 { 625 626 if (argc < 2) { 627 strcat(line, " "); 628 printf("(from-name) "); 629 gets(&line[strlen(line)]); 630 makeargv(); 631 argc = margc; 632 argv = margv; 633 } 634 if (argc < 2) { 635 usage: 636 printf("%s from-name to-name\n", argv[0]); 637 return; 638 } 639 if (argc < 3) { 640 strcat(line, " "); 641 printf("(to-name) "); 642 gets(&line[strlen(line)]); 643 makeargv(); 644 argc = margc; 645 argv = margv; 646 } 647 if (argc < 3) 648 goto usage; 649 if (command("RNFR %s", argv[1]) == CONTINUE) 650 (void) command("RNTO %s", argv[2]); 651 } 652 653 /* 654 * Get a directory listing 655 * of remote files. 656 */ 657 ls(argc, argv) 658 char *argv[]; 659 { 660 char *cmd; 661 662 if (argc < 2) 663 argc++, argv[1] = NULL; 664 if (argc < 3) 665 argc++, argv[2] = "-"; 666 if (argc > 3) { 667 printf("usage: %s remote-directory local-file\n", argv[0]); 668 return; 669 } 670 cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 671 if (strcmp(argv[2], "-") && !globulize(&argv[2])) 672 return; 673 recvrequest(cmd, argv[2], argv[1], "w"); 674 } 675 676 /* 677 * Get a directory listing 678 * of multiple remote files. 679 */ 680 mls(argc, argv) 681 char *argv[]; 682 { 683 char *cmd, *mode, *cp, *dest; 684 685 if (argc < 2) { 686 strcat(line, " "); 687 printf("(remote-files) "); 688 gets(&line[strlen(line)]); 689 makeargv(); 690 argc = margc; 691 argv = margv; 692 } 693 if (argc < 3) { 694 strcat(line, " "); 695 printf("(local-file) "); 696 gets(&line[strlen(line)]); 697 makeargv(); 698 argc = margc; 699 argv = margv; 700 } 701 if (argc < 3) { 702 printf("%s remote-files local-file\n", argv[0]); 703 return; 704 } 705 dest = argv[argc - 1]; 706 argv[argc - 1] = NULL; 707 if (strcmp(dest, "-")) 708 if (!globulize(&dest) || !confirm("local-file", dest)) 709 return; 710 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 711 for (mode = "w"; cp = remglob(argc, argv); mode = "a") 712 if (confirm(argv[0], cp)) 713 recvrequest(cmd, dest, cp, mode); 714 } 715 716 /* 717 * Do a shell escape 718 */ 719 shell(argc, argv) 720 char *argv[]; 721 { 722 int pid, status, (*old1)(), (*old2)(); 723 char shellnam[40], *shell, *namep; 724 char **cpp, **gargs; 725 726 old1 = signal (SIGINT, SIG_IGN); 727 old2 = signal (SIGQUIT, SIG_IGN); 728 if ((pid = fork()) == 0) { 729 for (pid = 3; pid < 20; pid++) 730 close(pid); 731 signal(SIGINT, SIG_DFL); 732 signal(SIGQUIT, SIG_DFL); 733 if (argc <= 1) { 734 shell = getenv("SHELL"); 735 if (shell == NULL) 736 shell = "/bin/sh"; 737 namep = rindex(shell,'/'); 738 if (namep == NULL) 739 namep = shell; 740 strcpy(shellnam,"-"); 741 strcat(shellnam, ++namep); 742 if (strcmp(namep, "sh") != 0) 743 shellnam[0] = '+'; 744 if (debug) { 745 printf ("%s\n", shell); 746 fflush (stdout); 747 } 748 execl(shell, shellnam, 0); 749 perror(shell); 750 exit(1); 751 } 752 cpp = &argv[1]; 753 if (argc > 2) { 754 if ((gargs = glob(cpp)) != NULL) 755 cpp = gargs; 756 if (globerr != NULL) { 757 printf("%s\n", globerr); 758 exit(1); 759 } 760 } 761 if (debug) { 762 register char **zip = cpp; 763 764 printf("%s", *zip); 765 while (*++zip != NULL) 766 printf(" %s", *zip); 767 printf("\n"); 768 fflush(stdout); 769 } 770 execvp(argv[1], cpp); 771 perror(argv[1]); 772 exit(1); 773 } 774 if (pid > 0) 775 while (wait(&status) != pid) 776 ; 777 signal(SIGINT, old1); 778 signal(SIGQUIT, old2); 779 if (pid == -1) 780 perror("Try again later"); 781 return (0); 782 } 783 784 /* 785 * Send new user information (re-login) 786 */ 787 user(argc, argv) 788 int argc; 789 char **argv; 790 { 791 char acct[80], *getpass(); 792 int n; 793 794 if (argc < 2) { 795 strcat(line, " "); 796 printf("(username) "); 797 gets(&line[strlen(line)]); 798 makeargv(); 799 argc = margc; 800 argv = margv; 801 } 802 if (argc > 4) { 803 printf("usage: %s username [password] [account]\n", argv[0]); 804 return (0); 805 } 806 n = command("USER %s", argv[1]); 807 if (n == CONTINUE) { 808 if (argc < 3 ) 809 argv[2] = getpass("Password: "), argc++; 810 n = command("PASS %s", argv[2]); 811 } 812 if (n == CONTINUE) { 813 if (argc < 4) { 814 printf("Account: "); (void) fflush(stdout); 815 (void) fgets(acct, sizeof(acct) - 1, stdin); 816 acct[strlen(acct) - 1] = '\0'; 817 argv[3] = acct; argc++; 818 } 819 n = command("ACCT %s", acct); 820 } 821 if (n != COMPLETE) { 822 fprintf(stderr, "Login failed.\n"); 823 return (0); 824 } 825 return (1); 826 } 827 828 /* 829 * Print working directory. 830 */ 831 /*VARARGS*/ 832 pwd() 833 { 834 835 (void) command("XPWD"); 836 } 837 838 /* 839 * Make a directory. 840 */ 841 makedir(argc, argv) 842 char *argv[]; 843 { 844 845 if (argc < 2) { 846 strcat(line, " "); 847 printf("(directory-name) "); 848 gets(&line[strlen(line)]); 849 makeargv(); 850 argc = margc; 851 argv = margv; 852 } 853 if (argc < 2) { 854 printf("%s directory-name\n", argv[0]); 855 return; 856 } 857 (void) command("XMKD %s", argv[1]); 858 } 859 860 /* 861 * Remove a directory. 862 */ 863 removedir(argc, argv) 864 char *argv[]; 865 { 866 867 if (argc < 2) { 868 strcat(line, " "); 869 printf("(directory-name) "); 870 gets(&line[strlen(line)]); 871 makeargv(); 872 argc = margc; 873 argv = margv; 874 } 875 if (argc < 2) { 876 printf("%s directory-name\n", argv[0]); 877 return; 878 } 879 (void) command("XRMD %s", argv[1]); 880 } 881 882 /* 883 * Send a line, verbatim, to the remote machine. 884 */ 885 quote(argc, argv) 886 char *argv[]; 887 { 888 int i; 889 char buf[BUFSIZ]; 890 891 if (argc < 2) { 892 strcat(line, " "); 893 printf("(command line to send) "); 894 gets(&line[strlen(line)]); 895 makeargv(); 896 argc = margc; 897 argv = margv; 898 } 899 if (argc < 2) { 900 printf("usage: %s line-to-send\n", argv[0]); 901 return; 902 } 903 strcpy(buf, argv[1]); 904 for (i = 2; i < argc; i++) { 905 strcat(buf, " "); 906 strcat(buf, argv[i]); 907 } 908 (void) command(buf); 909 } 910 911 /* 912 * Ask the other side for help. 913 */ 914 rmthelp(argc, argv) 915 char *argv[]; 916 { 917 int oldverbose = verbose; 918 919 verbose = 1; 920 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 921 verbose = oldverbose; 922 } 923 924 /* 925 * Terminate session and exit. 926 */ 927 /*VARARGS*/ 928 quit() 929 { 930 931 if (connected) 932 disconnect(); 933 exit(0); 934 } 935 936 /* 937 * Terminate session, but don't exit. 938 */ 939 disconnect() 940 { 941 extern FILE *cout; 942 extern int data; 943 944 if (!connected) 945 return; 946 (void) command("QUIT"); 947 (void) fclose(cout); 948 cout = NULL; 949 connected = 0; 950 data = -1; 951 } 952 953 confirm(cmd, file) 954 char *cmd, *file; 955 { 956 char line[BUFSIZ]; 957 958 if (!interactive) 959 return (1); 960 printf("%s %s? ", cmd, file); 961 fflush(stdout); 962 gets(line); 963 return (*line != 'n' && *line != 'N'); 964 } 965 966 fatal(msg) 967 char *msg; 968 { 969 970 fprintf(stderr, "ftp: %s\n"); 971 exit(1); 972 } 973 974 /* 975 * Glob a local file name specification with 976 * the expectation of a single return value. 977 * Can't control multiple values being expanded 978 * from the expression, we return only the first. 979 */ 980 globulize(cpp) 981 char **cpp; 982 { 983 char **globbed; 984 985 if (!doglob) 986 return (1); 987 globbed = glob(*cpp); 988 if (globerr != NULL) { 989 printf("%s: %s\n", *cpp, globerr); 990 if (globbed) 991 blkfree(globbed); 992 return (0); 993 } 994 if (globbed) { 995 *cpp = *globbed++; 996 /* don't waste too much memory */ 997 if (*globbed) 998 blkfree(globbed); 999 } 1000 return (1); 1001 } 1002