| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /*************************************************************************** | 
|  | 2 | *                                  _   _ ____  _ | 
|  | 3 | *  Project                     ___| | | |  _ \| | | 
|  | 4 | *                             / __| | | | |_) | | | 
|  | 5 | *                            | (__| |_| |  _ <| |___ | 
|  | 6 | *                             \___|\___/|_| \_\_____| | 
|  | 7 | * | 
|  | 8 | * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@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 | /* 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 */ |