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