1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 http://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 /* if we build a static library for unit tests, there is no main() function */ 66 #ifndef UNITTESTS 67 68 /* 69 * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are 70 * open before starting to run. Otherwise, the first three network 71 * sockets opened by curl could be used for input sources, downloaded data 72 * or error logs as they will effectively be stdin, stdout and/or stderr. 73 */ 74 static void main_checkfds(void) 75 { 76 #ifdef HAVE_PIPE 77 int fd[2] = { STDIN_FILENO, STDIN_FILENO }; 78 while(fd[0] == STDIN_FILENO || 79 fd[0] == STDOUT_FILENO || 80 fd[0] == STDERR_FILENO || 81 fd[1] == STDIN_FILENO || 82 fd[1] == STDOUT_FILENO || 83 fd[1] == STDERR_FILENO) 84 if(pipe(fd) < 0) 85 return; /* Out of handles. This isn't really a big problem now, but 86 will be when we try to create a socket later. */ 87 close(fd[0]); 88 close(fd[1]); 89 #endif 90 } 91 92 #ifdef CURLDEBUG 93 static void memory_tracking_init(void) 94 { 95 char *env; 96 /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ 97 env = curlx_getenv("CURL_MEMDEBUG"); 98 if(env) { 99 /* use the value as file name */ 100 char fname[CURL_MT_LOGFNAME_BUFSIZE]; 101 if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) 102 env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; 103 strcpy(fname, env); 104 curl_free(env); 105 curl_memdebug(fname); 106 /* this weird stuff here is to make curl_free() get called 107 before curl_memdebug() as otherwise memory tracking will 108 log a free() without an alloc! */ 109 } 110 /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ 111 env = curlx_getenv("CURL_MEMLIMIT"); 112 if(env) { 113 char *endptr; 114 long num = strtol(env, &endptr, 10); 115 if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) 116 curl_memlimit(num); 117 curl_free(env); 118 } 119 } 120 #else 121 # define memory_tracking_init() Curl_nop_stmt 122 #endif 123 124 /* 125 * This is the main global constructor for the app. Call this before 126 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be 127 * used, or havoc may be the result. 128 */ 129 static CURLcode main_init(struct GlobalConfig *config) 130 { 131 CURLcode result = CURLE_OK; 132 133 #if defined(__DJGPP__) || defined(__GO32__) 134 /* stop stat() wasting time */ 135 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; 136 #endif 137 138 /* Initialise the global config */ 139 config->showerror = -1; /* Will show errors */ 140 config->errors = stderr; /* Default errors to stderr */ 141 142 /* Allocate the initial operate config */ 143 config->first = config->last = malloc(sizeof(struct OperationConfig)); 144 if(config->first) { 145 /* Perform the libcurl initialization */ 146 result = curl_global_init(CURL_GLOBAL_DEFAULT); 147 if(!result) { 148 /* Get information about libcurl */ 149 result = get_libcurl_info(); 150 151 if(!result) { 152 /* Get a curl handle to use for all forthcoming curl transfers */ 153 config->easy = curl_easy_init(); 154 if(config->easy) { 155 /* Initialise the config */ 156 config_init(config->first); 157 config->first->easy = config->easy; 158 config->first->global = config; 159 } 160 else { 161 helpf(stderr, "error initializing curl easy handle\n"); 162 result = CURLE_FAILED_INIT; 163 free(config->first); 164 } 165 } 166 else { 167 helpf(stderr, "error retrieving curl library information\n"); 168 free(config->first); 169 } 170 } 171 else { 172 helpf(stderr, "error initializing curl library\n"); 173 free(config->first); 174 } 175 } 176 else { 177 helpf(stderr, "error initializing curl\n"); 178 result = CURLE_FAILED_INIT; 179 } 180 181 return result; 182 } 183 184 static void free_config_fields(struct GlobalConfig *config) 185 { 186 Curl_safefree(config->trace_dump); 187 188 if(config->errors_fopened && config->errors) 189 fclose(config->errors); 190 config->errors = NULL; 191 192 if(config->trace_fopened && config->trace_stream) 193 fclose(config->trace_stream); 194 config->trace_stream = NULL; 195 196 Curl_safefree(config->libcurl); 197 } 198 199 /* 200 * This is the main global destructor for the app. Call this after 201 * _all_ libcurl usage is done. 202 */ 203 static void main_free(struct GlobalConfig *config) 204 { 205 /* Cleanup the easy handle */ 206 curl_easy_cleanup(config->easy); 207 config->easy = NULL; 208 209 /* Main cleanup */ 210 curl_global_cleanup(); 211 convert_cleanup(); 212 metalink_cleanup(); 213 #ifdef USE_NSS 214 if(PR_Initialized()) { 215 /* prevent valgrind from reporting still reachable mem from NSRP arenas */ 216 PL_ArenaFinish(); 217 /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */ 218 PR_Cleanup(); 219 } 220 #endif 221 free_config_fields(config); 222 223 /* Free the config structures */ 224 config_free(config->last); 225 config->first = NULL; 226 config->last = NULL; 227 } 228 229 /* 230 ** curl tool main function. 231 */ 232 int main(int argc, char *argv[]) 233 { 234 CURLcode result = CURLE_OK; 235 struct GlobalConfig global; 236 memset(&global, 0, sizeof(global)); 237 238 main_checkfds(); 239 240 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) 241 (void)signal(SIGPIPE, SIG_IGN); 242 #endif 243 244 /* Initialize memory tracking */ 245 memory_tracking_init(); 246 247 /* Initialize the curl library - do not call any libcurl functions before 248 this point */ 249 result = main_init(&global); 250 if(!result) { 251 /* Start our curl operation */ 252 result = operate(&global, argc, argv); 253 254 #ifdef __SYMBIAN32__ 255 if(global.showerror) 256 tool_pressanykey(); 257 #endif 258 259 /* Perform the main cleanup */ 260 main_free(&global); 261 } 262 263 #ifdef __NOVELL_LIBC__ 264 if(getenv("_IN_NETWARE_BASH_") == NULL) 265 tool_pressanykey(); 266 #endif 267 268 #ifdef __VMS 269 vms_special_exit(result, vms_show); 270 #else 271 return (int)result; 272 #endif 273 } 274 275 #endif /* ndef UNITTESTS */ 276