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