Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/ftpgetput.c

    r1765 r2725  
    66 *
    77 * Copyright (C) 2002 Jeff Angielski, The PTR Group <jeff@theptrgroup.com>
    8  * Copyright (C) 2002 Glenn McGrath <bug1@iinet.net.au>
     8 * Copyright (C) 2002 Glenn McGrath
    99 *
    1010 * Based on wget.c by Chip Rosenthal Covad Communications
    1111 * <chip@laserlink.net>
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1414 */
    1515
    16 #include <getopt.h>
    1716#include "libbb.h"
    1817
    19 typedef struct ftp_host_info_s {
     18struct globals {
    2019    const char *user;
    2120    const char *password;
    2221    struct len_and_sockaddr *lsa;
    23 } ftp_host_info_t;
    24 
    25 static smallint verbose_flag;
    26 static smallint do_continue;
    27 
    28 static void ftp_die(const char *msg, const char *remote) ATTRIBUTE_NORETURN;
    29 static void ftp_die(const char *msg, const char *remote)
    30 {
     22    FILE *control_stream;
     23    int verbose_flag;
     24    int do_continue;
     25    char buf[1]; /* actually [BUFSZ] */
     26} FIX_ALIASING;
     27#define G (*(struct globals*)&bb_common_bufsiz1)
     28enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) };
     29struct BUG_G_too_big {
     30    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     31};
     32#define user           (G.user          )
     33#define password       (G.password      )
     34#define lsa            (G.lsa           )
     35#define control_stream (G.control_stream)
     36#define verbose_flag   (G.verbose_flag  )
     37#define do_continue    (G.do_continue   )
     38#define buf            (G.buf           )
     39#define INIT_G() do { } while (0)
     40
     41
     42static void ftp_die(const char *msg) NORETURN;
     43static void ftp_die(const char *msg)
     44{
     45    char *cp = buf; /* buf holds peer's response */
     46
    3147    /* Guard against garbage from remote server */
    32     const char *cp = remote;
    33     while (*cp >= ' ' && *cp < '\x7f') cp++;
    34     bb_error_msg_and_die("unexpected server response%s%s: %.*s",
    35             msg ? " to " : "", msg ? msg : "",
    36             (int)(cp - remote), remote);
    37 }
    38 
    39 
    40 static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
     48    while (*cp >= ' ' && *cp < '\x7f')
     49        cp++;
     50    *cp = '\0';
     51    bb_error_msg_and_die("unexpected server response%s%s: %s",
     52            (msg ? " to " : ""), (msg ? msg : ""), buf);
     53}
     54
     55static int ftpcmd(const char *s1, const char *s2)
    4156{
    4257    unsigned n;
     58
    4359    if (verbose_flag) {
    4460        bb_error_msg("cmd %s %s", s1, s2);
     
    4662
    4763    if (s1) {
    48         if (s2) {
    49             fprintf(stream, "%s %s\r\n", s1, s2);
    50         } else {
    51             fprintf(stream, "%s\r\n", s1);
    52         }
    53     }
     64        fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
     65                        s1, s2);
     66        fflush(control_stream);
     67    }
     68
    5469    do {
    55         char *buf_ptr;
    56 
    57         if (fgets(buf, 510, stream) == NULL) {
    58             bb_perror_msg_and_die("fgets");
    59         }
    60         buf_ptr = strstr(buf, "\r\n");
    61         if (buf_ptr) {
    62             *buf_ptr = '\0';
     70        strcpy(buf, "EOF");
     71        if (fgets(buf, BUFSZ - 2, control_stream) == NULL) {
     72            ftp_die(NULL);
    6373        }
    6474    } while (!isdigit(buf[0]) || buf[3] != ' ');
     
    7080}
    7181
    72 static int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
     82static void ftp_login(void)
     83{
     84    /* Connect to the command socket */
     85    control_stream = fdopen(xconnect_stream(lsa), "r+");
     86    if (control_stream == NULL) {
     87        /* fdopen failed - extremely unlikely */
     88        bb_perror_nomsg_and_die();
     89    }
     90
     91    if (ftpcmd(NULL, NULL) != 220) {
     92        ftp_die(NULL);
     93    }
     94
     95    /*  Login to the server */
     96    switch (ftpcmd("USER", user)) {
     97    case 230:
     98        break;
     99    case 331:
     100        if (ftpcmd("PASS", password) != 230) {
     101            ftp_die("PASS");
     102        }
     103        break;
     104    default:
     105        ftp_die("USER");
     106    }
     107
     108    ftpcmd("TYPE I", NULL);
     109}
     110
     111static int xconnect_ftpdata(void)
    73112{
    74113    char *buf_ptr;
    75     unsigned short port_num;
     114    unsigned port_num;
     115
     116/*
     117TODO: PASV command will not work for IPv6. RFC2428 describes
     118IPv6-capable "extended PASV" - EPSV.
     119
     120"EPSV [protocol]" asks server to bind to and listen on a data port
     121in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
     122If not specified, defaults to "same as used for control connection".
     123If server understood you, it should answer "229 <some text>(|||port|)"
     124where "|" are literal pipe chars and "port" is ASCII decimal port#.
     125
     126There is also an IPv6-capable replacement for PORT (EPRT),
     127but we don't need that.
     128
     129NB: PASV may still work for some servers even over IPv6.
     130For example, vsftp happily answers
     131"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
     132
     133TODO2: need to stop ignoring IP address in PASV response.
     134*/
     135
     136    if (ftpcmd("PASV", NULL) != 227) {
     137        ftp_die("PASV");
     138    }
    76139
    77140    /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]
     
    89152    port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
    90153
    91     set_nport(server->lsa, htons(port_num));
    92     return xconnect_stream(server->lsa);
    93 }
    94 
    95 static FILE *ftp_login(ftp_host_info_t *server)
    96 {
    97     FILE *control_stream;
    98     char buf[512];
    99 
    100     /* Connect to the command socket */
    101     control_stream = fdopen(xconnect_stream(server->lsa), "r+");
    102     if (control_stream == NULL) {
    103         /* fdopen failed - extremely unlikely */
    104         bb_perror_nomsg_and_die();
    105     }
    106 
    107     if (ftpcmd(NULL, NULL, control_stream, buf) != 220) {
    108         ftp_die(NULL, buf);
    109     }
    110 
    111     /*  Login to the server */
    112     switch (ftpcmd("USER", server->user, control_stream, buf)) {
    113     case 230:
    114         break;
    115     case 331:
    116         if (ftpcmd("PASS", server->password, control_stream, buf) != 230) {
    117             ftp_die("PASS", buf);
    118         }
    119         break;
    120     default:
    121         ftp_die("USER", buf);
    122     }
    123 
    124     ftpcmd("TYPE I", NULL, control_stream, buf);
    125 
    126     return control_stream;
     154    set_nport(lsa, htons(port_num));
     155    return xconnect_stream(lsa);
     156}
     157
     158static int pump_data_and_QUIT(int from, int to)
     159{
     160    /* copy the file */
     161    if (bb_copyfd_eof(from, to) == -1) {
     162        /* error msg is already printed by bb_copyfd_eof */
     163        return EXIT_FAILURE;
     164    }
     165
     166    /* close data connection */
     167    close(from); /* don't know which one is that, so we close both */
     168    close(to);
     169
     170    /* does server confirm that transfer is finished? */
     171    if (ftpcmd(NULL, NULL) != 226) {
     172        ftp_die(NULL);
     173    }
     174    ftpcmd("QUIT", NULL);
     175
     176    return EXIT_SUCCESS;
    127177}
    128178
    129179#if !ENABLE_FTPGET
    130 int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
    131         const char *local_path, char *server_path);
     180int ftp_receive(const char *local_path, char *server_path);
    132181#else
    133182static
    134 int ftp_receive(ftp_host_info_t *server, FILE *control_stream,
    135         const char *local_path, char *server_path)
    136 {
    137     char buf[512];
    138 /* I think 'filesize' usage here is bogus. Let's see... */
    139     //off_t filesize = -1;
    140 #define filesize ((off_t)-1)
     183int ftp_receive(const char *local_path, char *server_path)
     184{
    141185    int fd_data;
    142186    int fd_local = -1;
    143187    off_t beg_range = 0;
    144188
    145     /* Connect to the data socket */
    146     if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    147         ftp_die("PASV", buf);
    148     }
    149     fd_data = xconnect_ftpdata(server, buf);
    150 
    151     if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) {
    152         //filesize = BB_STRTOOFF(buf + 4, NULL, 10);
    153         //if (errno || filesize < 0)
    154         //  ftp_die("SIZE", buf);
    155     } else {
     189    /* connect to the data socket */
     190    fd_data = xconnect_ftpdata();
     191
     192    if (ftpcmd("SIZE", server_path) != 213) {
    156193        do_continue = 0;
    157194    }
     
    164201    if (do_continue) {
    165202        struct stat sbuf;
    166         if (lstat(local_path, &sbuf) < 0) {
    167             bb_perror_msg_and_die("lstat");
     203        /* lstat would be wrong here! */
     204        if (stat(local_path, &sbuf) < 0) {
     205            bb_perror_msg_and_die("stat");
    168206        }
    169207        if (sbuf.st_size > 0) {
     
    175213
    176214    if (do_continue) {
    177         sprintf(buf, "REST %"OFF_FMT"d", beg_range);
    178         if (ftpcmd(buf, NULL, control_stream, buf) != 350) {
     215        sprintf(buf, "REST %"OFF_FMT"u", beg_range);
     216        if (ftpcmd(buf, NULL) != 350) {
    179217            do_continue = 0;
    180         } else {
    181             //if (filesize != -1)
    182             //  filesize -= beg_range;
    183         }
    184     }
    185 
    186     if (ftpcmd("RETR", server_path, control_stream, buf) > 150) {
    187         ftp_die("RETR", buf);
    188     }
    189 
    190     /* only make a local file if we know that one exists on the remote server */
     218        }
     219    }
     220
     221    if (ftpcmd("RETR", server_path) > 150) {
     222        ftp_die("RETR");
     223    }
     224
     225    /* create local file _after_ we know that remote file exists */
    191226    if (fd_local == -1) {
    192         if (do_continue) {
    193             fd_local = xopen(local_path, O_APPEND | O_WRONLY);
    194         } else {
    195             fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY);
    196         }
    197     }
    198 
    199     /* Copy the file */
    200     if (filesize != -1) {
    201         if (bb_copyfd_size(fd_data, fd_local, filesize) == -1)
    202             return EXIT_FAILURE;
    203     } else {
    204         if (bb_copyfd_eof(fd_data, fd_local) == -1)
    205             return EXIT_FAILURE;
    206     }
    207 
    208     /* close it all down */
    209     close(fd_data);
    210     if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    211         ftp_die(NULL, buf);
    212     }
    213     ftpcmd("QUIT", NULL, control_stream, buf);
    214 
    215     return EXIT_SUCCESS;
     227        fd_local = xopen(local_path,
     228            do_continue ? (O_APPEND | O_WRONLY)
     229                        : (O_CREAT | O_TRUNC | O_WRONLY)
     230        );
     231    }
     232
     233    return pump_data_and_QUIT(fd_data, fd_local);
    216234}
    217235#endif
    218236
    219237#if !ENABLE_FTPPUT
    220 int ftp_send(ftp_host_info_t *server, FILE *control_stream,
    221         const char *server_path, char *local_path);
     238int ftp_send(const char *server_path, char *local_path);
    222239#else
    223240static
    224 int ftp_send(ftp_host_info_t *server, FILE *control_stream,
    225         const char *server_path, char *local_path)
    226 {
    227     struct stat sbuf;
    228     char buf[512];
     241int ftp_send(const char *server_path, char *local_path)
     242{
    229243    int fd_data;
    230244    int fd_local;
    231245    int response;
    232246
    233     /*  Connect to the data socket */
    234     if (ftpcmd("PASV", NULL, control_stream, buf) != 227) {
    235         ftp_die("PASV", buf);
    236     }
    237     fd_data = xconnect_ftpdata(server, buf);
     247    /* connect to the data socket */
     248    fd_data = xconnect_ftpdata();
    238249
    239250    /* get the local file */
    240251    fd_local = STDIN_FILENO;
    241     if (NOT_LONE_DASH(local_path)) {
     252    if (NOT_LONE_DASH(local_path))
    242253        fd_local = xopen(local_path, O_RDONLY);
    243         fstat(fd_local, &sbuf);
    244 
    245         sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
    246         response = ftpcmd(buf, NULL, control_stream, buf);
    247         switch (response) {
    248         case 200:
    249         case 202:
    250             break;
    251         default:
    252             close(fd_local);
    253             ftp_die("ALLO", buf);
    254             break;
    255         }
    256     }
    257     response = ftpcmd("STOR", server_path, control_stream, buf);
     254
     255    response = ftpcmd("STOR", server_path);
    258256    switch (response) {
    259257    case 125:
     
    261259        break;
    262260    default:
    263         close(fd_local);
    264         ftp_die("STOR", buf);
    265     }
    266 
    267     /* transfer the file  */
    268     if (bb_copyfd_eof(fd_local, fd_data) == -1) {
    269         exit(EXIT_FAILURE);
    270     }
    271 
    272     /* close it all down */
    273     close(fd_data);
    274     if (ftpcmd(NULL, NULL, control_stream, buf) != 226) {
    275         ftp_die("close", buf);
    276     }
    277     ftpcmd("QUIT", NULL, control_stream, buf);
    278 
    279     return EXIT_SUCCESS;
    280 }
    281 #endif
    282 
    283 #define FTPGETPUT_OPT_CONTINUE  1
    284 #define FTPGETPUT_OPT_VERBOSE   2
    285 #define FTPGETPUT_OPT_USER  4
    286 #define FTPGETPUT_OPT_PASSWORD  8
    287 #define FTPGETPUT_OPT_PORT  16
     261        ftp_die("STOR");
     262    }
     263
     264    return pump_data_and_QUIT(fd_local, fd_data);
     265}
     266#endif
    288267
    289268#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
     
    297276#endif
    298277
    299 int ftpgetput_main(int argc, char **argv);
    300 int ftpgetput_main(int argc, char **argv)
    301 {
    302     /* content-length of the file */
     278int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     279int ftpgetput_main(int argc UNUSED_PARAM, char **argv)
     280{
    303281    unsigned opt;
    304282    const char *port = "ftp";
    305283    /* socket to ftp server */
    306     FILE *control_stream;
    307     /* continue previous transfer (-c) */
    308     ftp_host_info_t *server;
    309284
    310285#if ENABLE_FTPPUT && !ENABLE_FTPGET
     
    313288# define ftp_action ftp_receive
    314289#else
    315     int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send;
     290    int (*ftp_action)(const char *, char *) = ftp_send;
     291
    316292    /* Check to see if the command is ftpget or ftput */
    317293    if (applet_name[3] == 'g') {
     
    320296#endif
    321297
     298    INIT_G();
    322299    /* Set default values */
    323     server = xmalloc(sizeof(*server));
    324     server->user = "anonymous";
    325     server->password = "busybox@";
     300    user = "anonymous";
     301    password = "busybox@";
    326302
    327303    /*
     
    331307    applet_long_options = ftpgetput_longopts;
    332308#endif
    333     opt_complementary = "=3"; /* must have 3 params */
    334     opt = getopt32(argv, "cvu:p:P:", &server->user, &server->password, &port);
     309    opt_complementary = "-2:vv:cc"; /* must have 2 to 3 params; -v and -c count */
     310    opt = getopt32(argv, "cvu:p:P:", &user, &password, &port,
     311                    &verbose_flag, &do_continue);
    335312    argv += optind;
    336 
    337     /* Process the non-option command line arguments */
    338     if (opt & FTPGETPUT_OPT_CONTINUE) {
    339         do_continue = 1;
    340     }
    341     if (opt & FTPGETPUT_OPT_VERBOSE) {
    342         verbose_flag = 1;
    343     }
    344313
    345314    /* We want to do exactly _one_ DNS lookup, since some
    346315     * sites (i.e. ftp.us.debian.org) use round-robin DNS
    347316     * and we want to connect to only one IP... */
    348     server->lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
     317    lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
    349318    if (verbose_flag) {
    350319        printf("Connecting to %s (%s)\n", argv[0],
    351             xmalloc_sockaddr2dotted(&server->lsa->sa));
    352     }
    353 
    354     /*  Connect/Setup/Configure the FTP session */
    355     control_stream = ftp_login(server);
    356 
    357     return ftp_action(server, control_stream, argv[1], argv[2]);
    358 }
     320            xmalloc_sockaddr2dotted(&lsa->u.sa));
     321    }
     322
     323    ftp_login();
     324    return ftp_action(argv[1], argv[2] ? argv[2] : argv[1]);
     325}
Note: See TracChangeset for help on using the changeset viewer.