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