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.2 (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 217 if (argc == 2) 218 argc++, argv[2] = argv[1]; 219 if (argc < 2) { 220 strcat(line, " "); 221 printf("(local-file) "); 222 gets(&line[strlen(line)]); 223 makeargv(); 224 argc = margc; 225 argv = margv; 226 } 227 if (argc < 2) { 228 usage: 229 printf("%s local-file remote-file\n", argv[0]); 230 return; 231 } 232 if (argc < 3) { 233 strcat(line, " "); 234 printf("(remote-file) "); 235 gets(&line[strlen(line)]); 236 makeargv(); 237 argc = margc; 238 argv = margv; 239 } 240 if (argc < 3) 241 goto usage; 242 if (!globulize(&argv[1])) 243 return; 244 cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 245 sendrequest(cmd, argv[1], argv[2]); 246 } 247 248 /* 249 * Send multiple files. 250 */ 251 mput(argc, argv) 252 char *argv[]; 253 { 254 register int i; 255 256 if (argc < 2) { 257 strcat(line, " "); 258 printf("(local-files) "); 259 gets(&line[strlen(line)]); 260 makeargv(); 261 argc = margc; 262 argv = margv; 263 } 264 if (argc < 2) { 265 printf("%s local-files\n", argv[0]); 266 return; 267 } 268 for (i = 1; i < argc; i++) { 269 register char **cpp, **gargs; 270 271 if (!doglob) { 272 if (confirm(argv[0], argv[i])) 273 sendrequest("STOR", argv[i], argv[i]); 274 continue; 275 } 276 gargs = glob(argv[i]); 277 if (globerr != NULL) { 278 printf("%s\n", globerr); 279 if (gargs) 280 blkfree(gargs); 281 continue; 282 } 283 for (cpp = gargs; cpp && *cpp != NULL; cpp++) 284 if (confirm(argv[0], *cpp)) 285 sendrequest("STOR", *cpp, *cpp); 286 if (gargs != NULL) 287 blkfree(gargs); 288 } 289 } 290 291 /* 292 * Receive one file. 293 */ 294 get(argc, argv) 295 char *argv[]; 296 { 297 298 if (argc == 2) 299 argc++, argv[2] = argv[1]; 300 if (argc < 2) { 301 strcat(line, " "); 302 printf("(remote-file) "); 303 gets(&line[strlen(line)]); 304 makeargv(); 305 argc = margc; 306 argv = margv; 307 } 308 if (argc < 2) { 309 usage: 310 printf("%s remote-file [ local-file ]\n", argv[0]); 311 return; 312 } 313 if (argc < 3) { 314 strcat(line, " "); 315 printf("(local-file) "); 316 gets(&line[strlen(line)]); 317 makeargv(); 318 argc = margc; 319 argv = margv; 320 } 321 if (argc < 3) 322 goto usage; 323 if (!globulize(&argv[2])) 324 return; 325 recvrequest("RETR", argv[2], argv[1], "w"); 326 } 327 328 /* 329 * Get multiple files. 330 */ 331 mget(argc, argv) 332 char *argv[]; 333 { 334 char *cp; 335 336 if (argc < 2) { 337 strcat(line, " "); 338 printf("(remote-files) "); 339 gets(&line[strlen(line)]); 340 makeargv(); 341 argc = margc; 342 argv = margv; 343 } 344 if (argc < 2) { 345 printf("%s remote-files\n", argv[0]); 346 return; 347 } 348 while ((cp = remglob(argc, argv)) != NULL) 349 if (confirm(argv[0], cp)) 350 recvrequest("RETR", cp, cp, "w"); 351 } 352 353 char * 354 remglob(argc, argv) 355 char *argv[]; 356 { 357 char temp[16]; 358 static char buf[MAXPATHLEN]; 359 static FILE *ftemp = NULL; 360 static char **args; 361 int oldverbose, oldhash; 362 char *cp, *mode; 363 364 if (!doglob) { 365 if (args == NULL) 366 args = argv; 367 if ((cp = *++args) == NULL) 368 args = NULL; 369 return (cp); 370 } 371 if (ftemp == NULL) { 372 strcpy(temp, "/tmp/ftpXXXXXX"); 373 mktemp(temp); 374 oldverbose = verbose, verbose = 0; 375 oldhash = hash, hash = 0; 376 for (mode = "w"; *++argv != NULL; mode = "a") 377 recvrequest ("NLST", temp, *argv, mode); 378 verbose = oldverbose; hash = oldhash; 379 ftemp = fopen(temp, "r"); 380 unlink(temp); 381 if (ftemp == NULL) { 382 printf("can't find list of remote files, oops\n"); 383 return (NULL); 384 } 385 } 386 if (fgets(buf, sizeof (buf), ftemp) == NULL) { 387 fclose(ftemp), ftemp = NULL; 388 return (NULL); 389 } 390 if ((cp = index(buf, '\n')) != NULL) 391 *cp = '\0'; 392 return (buf); 393 } 394 395 char * 396 onoff(bool) 397 int bool; 398 { 399 400 return (bool ? "on" : "off"); 401 } 402 403 /* 404 * Show status. 405 */ 406 status(argc, argv) 407 char *argv[]; 408 { 409 410 if (connected) 411 printf("Connected to %s.\n", hostname); 412 else 413 printf("Not connected.\n"); 414 printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 415 modename, typename, formname, structname); 416 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 417 onoff(verbose), onoff(bell), onoff(interactive), 418 onoff(doglob)); 419 printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 420 onoff(hash), onoff(sendport)); 421 } 422 423 /* 424 * Set beep on cmd completed mode. 425 */ 426 /*VARARGS*/ 427 setbell() 428 { 429 430 bell = !bell; 431 printf("Bell mode %s.\n", onoff(bell)); 432 } 433 434 /* 435 * Turn on packet tracing. 436 */ 437 /*VARARGS*/ 438 settrace() 439 { 440 441 trace = !trace; 442 printf("Packet tracing %s.\n", onoff(trace)); 443 } 444 445 /* 446 * Toggle hash mark printing during transfers. 447 */ 448 /*VARARGS*/ 449 sethash() 450 { 451 452 hash = !hash; 453 printf("Hash mark printing %s", onoff(hash)); 454 if (hash) 455 printf(" (%d bytes/hash mark)", BUFSIZ); 456 printf(".\n"); 457 } 458 459 /* 460 * Turn on printing of server echo's. 461 */ 462 /*VARARGS*/ 463 setverbose() 464 { 465 466 verbose = !verbose; 467 printf("Verbose mode %s.\n", onoff(verbose)); 468 } 469 470 /* 471 * Toggle PORT cmd use before each data connection. 472 */ 473 /*VARARGS*/ 474 setport() 475 { 476 477 sendport = !sendport; 478 printf("Use of PORT cmds %s.\n", onoff(sendport)); 479 } 480 481 /* 482 * Turn on interactive prompting 483 * during mget, mput, and mdelete. 484 */ 485 /*VARARGS*/ 486 setprompt() 487 { 488 489 interactive = !interactive; 490 printf("Interactive mode %s.\n", onoff(interactive)); 491 } 492 493 /* 494 * Toggle metacharacter interpretation 495 * on local file names. 496 */ 497 /*VARARGS*/ 498 setglob() 499 { 500 501 doglob = !doglob; 502 printf("Globbing %s.\n", onoff(doglob)); 503 } 504 505 /* 506 * Set debugging mode on/off and/or 507 * set level of debugging. 508 */ 509 /*VARARGS*/ 510 setdebug(argc, argv) 511 char *argv[]; 512 { 513 int val; 514 515 if (argc > 1) { 516 val = atoi(argv[1]); 517 if (val < 0) { 518 printf("%s: bad debugging value.\n", argv[1]); 519 return; 520 } 521 } else 522 val = !debug; 523 debug = val; 524 if (debug) 525 options |= SO_DEBUG; 526 else 527 options &= ~SO_DEBUG; 528 printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 529 } 530 531 /* 532 * Set current working directory 533 * on remote machine. 534 */ 535 cd(argc, argv) 536 char *argv[]; 537 { 538 539 if (argc < 2) { 540 strcat(line, " "); 541 printf("(remote-directory) "); 542 gets(&line[strlen(line)]); 543 makeargv(); 544 argc = margc; 545 argv = margv; 546 } 547 if (argc < 2) { 548 printf("%s remote-directory\n", argv[0]); 549 return; 550 } 551 (void) command("CWD %s", argv[1]); 552 } 553 554 /* 555 * Set current working directory 556 * on local machine. 557 */ 558 lcd(argc, argv) 559 char *argv[]; 560 { 561 char buf[MAXPATHLEN]; 562 563 if (argc < 2) 564 argc++, argv[1] = home; 565 if (argc != 2) { 566 printf("%s local-directory\n", argv[0]); 567 return; 568 } 569 if (!globulize(&argv[1])) 570 return; 571 if (chdir(argv[1]) < 0) { 572 perror(argv[1]); 573 return; 574 } 575 printf("Local directory now %s\n", getwd(buf)); 576 } 577 578 /* 579 * Delete a single file. 580 */ 581 delete(argc, argv) 582 char *argv[]; 583 { 584 585 if (argc < 2) { 586 strcat(line, " "); 587 printf("(remote-file) "); 588 gets(&line[strlen(line)]); 589 makeargv(); 590 argc = margc; 591 argv = margv; 592 } 593 if (argc < 2) { 594 printf("%s remote-file\n", argv[0]); 595 return; 596 } 597 (void) command("DELE %s", argv[1]); 598 } 599 600 /* 601 * Delete multiple files. 602 */ 603 mdelete(argc, argv) 604 char *argv[]; 605 { 606 char *cp; 607 608 if (argc < 2) { 609 strcat(line, " "); 610 printf("(remote-files) "); 611 gets(&line[strlen(line)]); 612 makeargv(); 613 argc = margc; 614 argv = margv; 615 } 616 if (argc < 2) { 617 printf("%s remote-files\n", argv[0]); 618 return; 619 } 620 while ((cp = remglob(argc, argv)) != NULL) 621 if (confirm(argv[0], cp)) 622 (void) command("DELE %s", cp); 623 } 624 625 /* 626 * Rename a remote file. 627 */ 628 renamefile(argc, argv) 629 char *argv[]; 630 { 631 632 if (argc < 2) { 633 strcat(line, " "); 634 printf("(from-name) "); 635 gets(&line[strlen(line)]); 636 makeargv(); 637 argc = margc; 638 argv = margv; 639 } 640 if (argc < 2) { 641 usage: 642 printf("%s from-name to-name\n", argv[0]); 643 return; 644 } 645 if (argc < 3) { 646 strcat(line, " "); 647 printf("(to-name) "); 648 gets(&line[strlen(line)]); 649 makeargv(); 650 argc = margc; 651 argv = margv; 652 } 653 if (argc < 3) 654 goto usage; 655 if (command("RNFR %s", argv[1]) == CONTINUE) 656 (void) command("RNTO %s", argv[2]); 657 } 658 659 /* 660 * Get a directory listing 661 * of remote files. 662 */ 663 ls(argc, argv) 664 char *argv[]; 665 { 666 char *cmd; 667 668 if (argc < 2) 669 argc++, argv[1] = NULL; 670 if (argc < 3) 671 argc++, argv[2] = "-"; 672 if (argc > 3) { 673 printf("usage: %s remote-directory local-file\n", argv[0]); 674 return; 675 } 676 cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 677 if (strcmp(argv[2], "-") && !globulize(&argv[2])) 678 return; 679 recvrequest(cmd, argv[2], argv[1], "w"); 680 } 681 682 /* 683 * Get a directory listing 684 * of multiple remote files. 685 */ 686 mls(argc, argv) 687 char *argv[]; 688 { 689 char *cmd, *mode, *cp, *dest; 690 691 if (argc < 2) { 692 strcat(line, " "); 693 printf("(remote-files) "); 694 gets(&line[strlen(line)]); 695 makeargv(); 696 argc = margc; 697 argv = margv; 698 } 699 if (argc < 3) { 700 strcat(line, " "); 701 printf("(local-file) "); 702 gets(&line[strlen(line)]); 703 makeargv(); 704 argc = margc; 705 argv = margv; 706 } 707 if (argc < 3) { 708 printf("%s remote-files local-file\n", argv[0]); 709 return; 710 } 711 dest = argv[argc - 1]; 712 argv[argc - 1] = NULL; 713 if (strcmp(dest, "-")) 714 if (!globulize(&dest) || !confirm("local-file", dest)) 715 return; 716 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 717 for (mode = "w"; cp = remglob(argc, argv); mode = "a") 718 if (confirm(argv[0], cp)) 719 recvrequest(cmd, dest, cp, mode); 720 } 721 722 /* 723 * Do a shell escape 724 */ 725 shell(argc, argv) 726 char *argv[]; 727 { 728 int pid, status, (*old1)(), (*old2)(); 729 char shellnam[40], *shell, *namep; 730 char **cpp, **gargs; 731 732 old1 = signal (SIGINT, SIG_IGN); 733 old2 = signal (SIGQUIT, SIG_IGN); 734 if ((pid = fork()) == 0) { 735 for (pid = 3; pid < 20; pid++) 736 close(pid); 737 signal(SIGINT, SIG_DFL); 738 signal(SIGQUIT, SIG_DFL); 739 if (argc <= 1) { 740 shell = getenv("SHELL"); 741 if (shell == NULL) 742 shell = "/bin/sh"; 743 namep = rindex(shell,'/'); 744 if (namep == NULL) 745 namep = shell; 746 strcpy(shellnam,"-"); 747 strcat(shellnam, ++namep); 748 if (strcmp(namep, "sh") != 0) 749 shellnam[0] = '+'; 750 if (debug) { 751 printf ("%s\n", shell); 752 fflush (stdout); 753 } 754 execl(shell, shellnam, 0); 755 perror(shell); 756 exit(1); 757 } 758 cpp = &argv[1]; 759 if (argc > 2) { 760 if ((gargs = glob(cpp)) != NULL) 761 cpp = gargs; 762 if (globerr != NULL) { 763 printf("%s\n", globerr); 764 exit(1); 765 } 766 } 767 if (debug) { 768 register char **zip = cpp; 769 770 printf("%s", *zip); 771 while (*++zip != NULL) 772 printf(" %s", *zip); 773 printf("\n"); 774 fflush(stdout); 775 } 776 execvp(argv[1], cpp); 777 perror(argv[1]); 778 exit(1); 779 } 780 if (pid > 0) 781 while (wait(&status) != pid) 782 ; 783 signal(SIGINT, old1); 784 signal(SIGQUIT, old2); 785 if (pid == -1) 786 perror("Try again later"); 787 return (0); 788 } 789 790 /* 791 * Send new user information (re-login) 792 */ 793 user(argc, argv) 794 int argc; 795 char **argv; 796 { 797 char acct[80], *getpass(); 798 int n; 799 800 if (argc < 2) { 801 strcat(line, " "); 802 printf("(username) "); 803 gets(&line[strlen(line)]); 804 makeargv(); 805 argc = margc; 806 argv = margv; 807 } 808 if (argc > 4) { 809 printf("usage: %s username [password] [account]\n", argv[0]); 810 return (0); 811 } 812 n = command("USER %s", argv[1]); 813 if (n == CONTINUE) { 814 if (argc < 3 ) 815 argv[2] = getpass("Password: "), argc++; 816 n = command("PASS %s", argv[2]); 817 } 818 if (n == CONTINUE) { 819 if (argc < 4) { 820 printf("Account: "); (void) fflush(stdout); 821 (void) fgets(acct, sizeof(acct) - 1, stdin); 822 acct[strlen(acct) - 1] = '\0'; 823 argv[3] = acct; argc++; 824 } 825 n = command("ACCT %s", acct); 826 } 827 if (n != COMPLETE) { 828 fprintf(stderr, "Login failed.\n"); 829 return (0); 830 } 831 return (1); 832 } 833 834 /* 835 * Print working directory. 836 */ 837 /*VARARGS*/ 838 pwd() 839 { 840 841 (void) command("XPWD"); 842 } 843 844 /* 845 * Make a directory. 846 */ 847 makedir(argc, argv) 848 char *argv[]; 849 { 850 851 if (argc < 2) { 852 strcat(line, " "); 853 printf("(directory-name) "); 854 gets(&line[strlen(line)]); 855 makeargv(); 856 argc = margc; 857 argv = margv; 858 } 859 if (argc < 2) { 860 printf("%s directory-name\n", argv[0]); 861 return; 862 } 863 (void) command("XMKD %s", argv[1]); 864 } 865 866 /* 867 * Remove a directory. 868 */ 869 removedir(argc, argv) 870 char *argv[]; 871 { 872 873 if (argc < 2) { 874 strcat(line, " "); 875 printf("(directory-name) "); 876 gets(&line[strlen(line)]); 877 makeargv(); 878 argc = margc; 879 argv = margv; 880 } 881 if (argc < 2) { 882 printf("%s directory-name\n", argv[0]); 883 return; 884 } 885 (void) command("XRMD %s", argv[1]); 886 } 887 888 /* 889 * Send a line, verbatim, to the remote machine. 890 */ 891 quote(argc, argv) 892 char *argv[]; 893 { 894 int i; 895 char buf[BUFSIZ]; 896 897 if (argc < 2) { 898 strcat(line, " "); 899 printf("(command line to send) "); 900 gets(&line[strlen(line)]); 901 makeargv(); 902 argc = margc; 903 argv = margv; 904 } 905 if (argc < 2) { 906 printf("usage: %s line-to-send\n", argv[0]); 907 return; 908 } 909 strcpy(buf, argv[1]); 910 for (i = 2; i < argc; i++) { 911 strcat(buf, " "); 912 strcat(buf, argv[i]); 913 } 914 (void) command(buf); 915 } 916 917 /* 918 * Ask the other side for help. 919 */ 920 rmthelp(argc, argv) 921 char *argv[]; 922 { 923 int oldverbose = verbose; 924 925 verbose = 1; 926 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 927 verbose = oldverbose; 928 } 929 930 /* 931 * Terminate session and exit. 932 */ 933 /*VARARGS*/ 934 quit() 935 { 936 937 if (connected) 938 disconnect(); 939 exit(0); 940 } 941 942 /* 943 * Terminate session, but don't exit. 944 */ 945 disconnect() 946 { 947 extern FILE *cout; 948 extern int data; 949 950 if (!connected) 951 return; 952 (void) command("QUIT"); 953 (void) fclose(cout); 954 cout = NULL; 955 connected = 0; 956 data = -1; 957 } 958 959 confirm(cmd, file) 960 char *cmd, *file; 961 { 962 char line[BUFSIZ]; 963 964 if (!interactive) 965 return (1); 966 printf("%s %s? ", cmd, file); 967 fflush(stdout); 968 gets(line); 969 return (*line != 'n' && *line != 'N'); 970 } 971 972 fatal(msg) 973 char *msg; 974 { 975 976 fprintf(stderr, "ftp: %s\n"); 977 exit(1); 978 } 979 980 /* 981 * Glob a local file name specification with 982 * the expectation of a single return value. 983 * Can't control multiple values being expanded 984 * from the expression, we return only the first. 985 */ 986 globulize(cpp) 987 char **cpp; 988 { 989 char **globbed; 990 991 if (!doglob) 992 return (1); 993 globbed = glob(*cpp); 994 if (globerr != NULL) { 995 printf("%s: %s\n", *cpp, globerr); 996 if (globbed) 997 blkfree(globbed); 998 return (0); 999 } 1000 if (globbed) { 1001 *cpp = *globbed++; 1002 /* don't waste too much memory */ 1003 if (*globbed) 1004 blkfree(globbed); 1005 } 1006 return (1); 1007 } 1008