Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 #include "tool_setup.h"
     23 
     24 #include <sys/stat.h>
     25 
     26 #ifdef HAVE_SIGNAL_H
     27 #include <signal.h>
     28 #endif
     29 
     30 #ifdef USE_NSS
     31 #include <nspr.h>
     32 #include <plarenas.h>
     33 #endif
     34 
     35 #define ENABLE_CURLX_PRINTF
     36 /* use our own printf() functions */
     37 #include "curlx.h"
     38 
     39 #include "tool_cfgable.h"
     40 #include "tool_convert.h"
     41 #include "tool_msgs.h"
     42 #include "tool_operate.h"
     43 #include "tool_panykey.h"
     44 #include "tool_vms.h"
     45 #include "tool_main.h"
     46 #include "tool_libinfo.h"
     47 
     48 /*
     49  * This is low-level hard-hacking memory leak tracking and similar. Using
     50  * the library level code from this client-side is ugly, but we do this
     51  * anyway for convenience.
     52  */
     53 #include "memdebug.h" /* keep this as LAST include */
     54 
     55 #ifdef __VMS
     56 /*
     57  * vms_show is a global variable, used in main() as parameter for
     58  * function vms_special_exit() to allow proper curl tool exiting.
     59  * Its value may be set in other tool_*.c source files thanks to
     60  * forward declaration present in tool_vms.h
     61  */
     62 int vms_show = 0;
     63 #endif
     64 
     65 #ifdef __MINGW32__
     66 /*
     67  * There seems to be no way to escape "*" in command-line arguments with MinGW
     68  * when command-line argument globbing is enabled under the MSYS shell, so turn
     69  * it off.
     70  */
     71 int _CRT_glob = 0;
     72 #endif /* __MINGW32__ */
     73 
     74 /* if we build a static library for unit tests, there is no main() function */
     75 #ifndef UNITTESTS
     76 
     77 /*
     78  * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
     79  * open before starting to run.  Otherwise, the first three network
     80  * sockets opened by curl could be used for input sources, downloaded data
     81  * or error logs as they will effectively be stdin, stdout and/or stderr.
     82  */
     83 static void main_checkfds(void)
     84 {
     85 #ifdef HAVE_PIPE
     86   int fd[2] = { STDIN_FILENO, STDIN_FILENO };
     87   while(fd[0] == STDIN_FILENO ||
     88         fd[0] == STDOUT_FILENO ||
     89         fd[0] == STDERR_FILENO ||
     90         fd[1] == STDIN_FILENO ||
     91         fd[1] == STDOUT_FILENO ||
     92         fd[1] == STDERR_FILENO)
     93     if(pipe(fd) < 0)
     94       return;   /* Out of handles. This isn't really a big problem now, but
     95                    will be when we try to create a socket later. */
     96   close(fd[0]);
     97   close(fd[1]);
     98 #endif
     99 }
    100 
    101 #ifdef CURLDEBUG
    102 static void memory_tracking_init(void)
    103 {
    104   char *env;
    105   /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
    106   env = curlx_getenv("CURL_MEMDEBUG");
    107   if(env) {
    108     /* use the value as file name */
    109     char fname[CURL_MT_LOGFNAME_BUFSIZE];
    110     if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
    111       env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
    112     strcpy(fname, env);
    113     curl_free(env);
    114     curl_memdebug(fname);
    115     /* this weird stuff here is to make curl_free() get called
    116        before curl_memdebug() as otherwise memory tracking will
    117        log a free() without an alloc! */
    118   }
    119   /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
    120   env = curlx_getenv("CURL_MEMLIMIT");
    121   if(env) {
    122     char *endptr;
    123     long num = strtol(env, &endptr, 10);
    124     if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
    125       curl_memlimit(num);
    126     curl_free(env);
    127   }
    128 }
    129 #else
    130 #  define memory_tracking_init() Curl_nop_stmt
    131 #endif
    132 
    133 /*
    134  * This is the main global constructor for the app. Call this before
    135  * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
    136  * used, or havoc may be the result.
    137  */
    138 static CURLcode main_init(struct GlobalConfig *config)
    139 {
    140   CURLcode result = CURLE_OK;
    141 
    142 #if defined(__DJGPP__) || defined(__GO32__)
    143   /* stop stat() wasting time */
    144   _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
    145 #endif
    146 
    147   /* Initialise the global config */
    148   config->showerror = -1;             /* Will show errors */
    149   config->errors = stderr;            /* Default errors to stderr */
    150 
    151   /* Allocate the initial operate config */
    152   config->first = config->last = malloc(sizeof(struct OperationConfig));
    153   if(config->first) {
    154     /* Perform the libcurl initialization */
    155     result = curl_global_init(CURL_GLOBAL_DEFAULT);
    156     if(!result) {
    157       /* Get information about libcurl */
    158       result = get_libcurl_info();
    159 
    160       if(!result) {
    161         /* Get a curl handle to use for all forthcoming curl transfers */
    162         config->easy = curl_easy_init();
    163         if(config->easy) {
    164           /* Initialise the config */
    165           config_init(config->first);
    166           config->first->easy = config->easy;
    167           config->first->global = config;
    168         }
    169         else {
    170           helpf(stderr, "error initializing curl easy handle\n");
    171           result = CURLE_FAILED_INIT;
    172           free(config->first);
    173         }
    174       }
    175       else {
    176         helpf(stderr, "error retrieving curl library information\n");
    177         free(config->first);
    178       }
    179     }
    180     else {
    181       helpf(stderr, "error initializing curl library\n");
    182       free(config->first);
    183     }
    184   }
    185   else {
    186     helpf(stderr, "error initializing curl\n");
    187     result = CURLE_FAILED_INIT;
    188   }
    189 
    190   return result;
    191 }
    192 
    193 static void free_config_fields(struct GlobalConfig *config)
    194 {
    195   Curl_safefree(config->trace_dump);
    196 
    197   if(config->errors_fopened && config->errors)
    198     fclose(config->errors);
    199   config->errors = NULL;
    200 
    201   if(config->trace_fopened && config->trace_stream)
    202     fclose(config->trace_stream);
    203   config->trace_stream = NULL;
    204 
    205   Curl_safefree(config->libcurl);
    206 }
    207 
    208 /*
    209  * This is the main global destructor for the app. Call this after
    210  * _all_ libcurl usage is done.
    211  */
    212 static void main_free(struct GlobalConfig *config)
    213 {
    214   /* Cleanup the easy handle */
    215   curl_easy_cleanup(config->easy);
    216   config->easy = NULL;
    217 
    218   /* Main cleanup */
    219   curl_global_cleanup();
    220   convert_cleanup();
    221   metalink_cleanup();
    222 #ifdef USE_NSS
    223   if(PR_Initialized()) {
    224     /* prevent valgrind from reporting still reachable mem from NSRP arenas */
    225     PL_ArenaFinish();
    226     /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */
    227     PR_Cleanup();
    228   }
    229 #endif
    230   free_config_fields(config);
    231 
    232   /* Free the config structures */
    233   config_free(config->last);
    234   config->first = NULL;
    235   config->last = NULL;
    236 }
    237 
    238 /*
    239 ** curl tool main function.
    240 */
    241 int main(int argc, char *argv[])
    242 {
    243   CURLcode result = CURLE_OK;
    244   struct GlobalConfig global;
    245   memset(&global, 0, sizeof(global));
    246 
    247   main_checkfds();
    248 
    249 #if defined(HAVE_SIGNAL) && defined(SIGPIPE)
    250   (void)signal(SIGPIPE, SIG_IGN);
    251 #endif
    252 
    253   /* Initialize memory tracking */
    254   memory_tracking_init();
    255 
    256   /* Initialize the curl library - do not call any libcurl functions before
    257      this point */
    258   result = main_init(&global);
    259   if(!result) {
    260     /* Start our curl operation */
    261     result = operate(&global, argc, argv);
    262 
    263 #ifdef __SYMBIAN32__
    264     if(global.showerror)
    265       tool_pressanykey();
    266 #endif
    267 
    268     /* Perform the main cleanup */
    269     main_free(&global);
    270   }
    271 
    272 #ifdef __NOVELL_LIBC__
    273   if(getenv("_IN_NETWARE_BASH_") == NULL)
    274     tool_pressanykey();
    275 #endif
    276 
    277 #ifdef __VMS
    278   vms_special_exit(result, vms_show);
    279 #else
    280   return (int)result;
    281 #endif
    282 }
    283 
    284 #endif /* ndef UNITTESTS */
    285