tool_main.c (8168B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "tool_setup.h" 25 26 #ifdef _WIN32 27 #include <tchar.h> 28 #endif 29 30 #ifndef UNDER_CE 31 #include <signal.h> 32 #endif 33 34 #ifdef HAVE_FCNTL_H 35 #include <fcntl.h> 36 #endif 37 38 #include "tool_cfgable.h" 39 #include "tool_doswin.h" 40 #include "tool_msgs.h" 41 #include "tool_operate.h" 42 #include "tool_vms.h" 43 #include "tool_main.h" 44 #include "tool_libinfo.h" 45 #include "tool_stderr.h" 46 47 /* 48 * This is low-level hard-hacking memory leak tracking and similar. Using 49 * the library level code from this client-side is ugly, but we do this 50 * anyway for convenience. 51 */ 52 #include "memdebug.h" /* keep this as LAST include */ 53 54 #ifdef __VMS 55 /* 56 * vms_show is a global variable, used in main() as parameter for 57 * function vms_special_exit() to allow proper curl tool exiting. 58 * Its value may be set in other tool_*.c source files thanks to 59 * forward declaration present in tool_vms.h 60 */ 61 int vms_show = 0; 62 #endif 63 64 #if defined(__AMIGA__) 65 #if defined(__GNUC__) 66 #define CURL_USED __attribute__((used)) 67 #else 68 #define CURL_USED 69 #endif 70 static const char CURL_USED min_stack[] = "$STACK:16384"; 71 #endif 72 73 #ifdef __MINGW32__ 74 /* 75 * There seems to be no way to escape "*" in command-line arguments with MinGW 76 * when command-line argument globbing is enabled under the MSYS shell, so turn 77 * it off. 78 */ 79 extern int _CRT_glob; 80 int _CRT_glob = 0; 81 #endif /* __MINGW32__ */ 82 83 /* if we build a static library for unit tests, there is no main() function */ 84 #ifndef UNITTESTS 85 86 #if defined(HAVE_PIPE) && defined(HAVE_FCNTL) 87 /* 88 * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are 89 * open before starting to run. Otherwise, the first three network 90 * sockets opened by curl could be used for input sources, downloaded data 91 * or error logs as they will effectively be stdin, stdout and/or stderr. 92 * 93 * fcntl's F_GETFD instruction returns -1 if the file descriptor is closed, 94 * otherwise it returns "the file descriptor flags (which typically can only 95 * be FD_CLOEXEC, which is not set here). 96 */ 97 static int main_checkfds(void) 98 { 99 int fd[2]; 100 while((fcntl(STDIN_FILENO, F_GETFD) == -1) || 101 (fcntl(STDOUT_FILENO, F_GETFD) == -1) || 102 (fcntl(STDERR_FILENO, F_GETFD) == -1)) 103 if(pipe(fd)) 104 return 1; 105 return 0; 106 } 107 #else 108 #define main_checkfds() 0 109 #endif 110 111 #ifdef CURLDEBUG 112 static void memory_tracking_init(void) 113 { 114 char *env; 115 /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ 116 env = curl_getenv("CURL_MEMDEBUG"); 117 if(env) { 118 /* use the value as filename */ 119 char fname[512]; 120 if(strlen(env) >= sizeof(fname)) 121 env[sizeof(fname)-1] = '\0'; 122 strcpy(fname, env); 123 curl_free(env); 124 curl_dbg_memdebug(fname); 125 /* this weird stuff here is to make curl_free() get called before 126 curl_dbg_memdebug() as otherwise memory tracking will log a free() 127 without an alloc! */ 128 } 129 /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ 130 env = curl_getenv("CURL_MEMLIMIT"); 131 if(env) { 132 curl_off_t num; 133 const char *p = env; 134 if(!curlx_str_number(&p, &num, LONG_MAX)) 135 curl_dbg_memlimit((long)num); 136 curl_free(env); 137 } 138 } 139 #else 140 # define memory_tracking_init() tool_nop_stmt 141 #endif 142 143 /* 144 * This is the main global constructor for the app. Call this before 145 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be 146 * used, or havoc may be the result. 147 */ 148 static CURLcode main_init(struct GlobalConfig *global) 149 { 150 CURLcode result = CURLE_OK; 151 152 #ifdef __DJGPP__ 153 /* stop stat() wasting time */ 154 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; 155 #endif 156 157 /* Initialise the global config */ 158 global->showerror = FALSE; /* show errors when silent */ 159 global->styled_output = TRUE; /* enable detection */ 160 global->parallel_max = PARALLEL_DEFAULT; 161 162 /* Allocate the initial operate config */ 163 global->first = global->last = config_alloc(global); 164 if(global->first) { 165 /* Perform the libcurl initialization */ 166 result = curl_global_init(CURL_GLOBAL_DEFAULT); 167 if(!result) { 168 /* Get information about libcurl */ 169 result = get_libcurl_info(); 170 171 if(result) { 172 errorf(global, "error retrieving curl library information"); 173 free(global->first); 174 } 175 } 176 else { 177 errorf(global, "error initializing curl library"); 178 free(global->first); 179 } 180 } 181 else { 182 errorf(global, "error initializing curl"); 183 result = CURLE_FAILED_INIT; 184 } 185 186 return result; 187 } 188 189 static void free_globalconfig(struct GlobalConfig *global) 190 { 191 tool_safefree(global->trace_dump); 192 193 if(global->trace_fopened && global->trace_stream) 194 fclose(global->trace_stream); 195 global->trace_stream = NULL; 196 197 tool_safefree(global->libcurl); 198 } 199 200 /* 201 * This is the main global destructor for the app. Call this after _all_ 202 * libcurl usage is done. 203 */ 204 static void main_free(struct GlobalConfig *global) 205 { 206 /* Cleanup the easy handle */ 207 /* Main cleanup */ 208 curl_global_cleanup(); 209 free_globalconfig(global); 210 211 /* Free the OperationConfig structures */ 212 config_free(global->last); 213 global->first = NULL; 214 global->last = NULL; 215 } 216 217 /* 218 ** curl tool main function. 219 */ 220 #if defined(_UNICODE) && !defined(UNDER_CE) 221 #if defined(__GNUC__) || defined(__clang__) 222 /* GCC does not know about wmain() */ 223 #pragma GCC diagnostic push 224 #pragma GCC diagnostic ignored "-Wmissing-prototypes" 225 #pragma GCC diagnostic ignored "-Wmissing-declarations" 226 #endif 227 int wmain(int argc, wchar_t *argv[]) 228 #else 229 int main(int argc, char *argv[]) 230 #endif 231 { 232 CURLcode result = CURLE_OK; 233 struct GlobalConfig global; 234 memset(&global, 0, sizeof(global)); 235 236 tool_init_stderr(); 237 238 #if defined(_WIN32) && !defined(UNDER_CE) 239 /* Undocumented diagnostic option to list the full paths of all loaded 240 modules. This is purposely pre-init. */ 241 if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) { 242 struct curl_slist *item, *head = GetLoadedModulePaths(); 243 for(item = head; item; item = item->next) 244 printf("%s\n", item->data); 245 curl_slist_free_all(head); 246 return head ? 0 : 1; 247 } 248 #endif 249 #ifdef _WIN32 250 /* win32_init must be called before other init routines. */ 251 result = win32_init(); 252 if(result) { 253 errorf(&global, "(%d) Windows-specific init failed", result); 254 return (int)result; 255 } 256 #endif 257 258 if(main_checkfds()) { 259 errorf(&global, "out of file descriptors"); 260 return CURLE_FAILED_INIT; 261 } 262 263 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) 264 (void)signal(SIGPIPE, SIG_IGN); 265 #endif 266 267 /* Initialize memory tracking */ 268 memory_tracking_init(); 269 270 /* Initialize the curl library - do not call any libcurl functions before 271 this point */ 272 result = main_init(&global); 273 if(!result) { 274 /* Start our curl operation */ 275 result = operate(&global, argc, argv); 276 277 /* Perform the main cleanup */ 278 main_free(&global); 279 } 280 281 #ifdef _WIN32 282 /* Flush buffers of all streams opened in write or update mode */ 283 fflush(NULL); 284 #endif 285 286 #ifdef __VMS 287 vms_special_exit(result, vms_show); 288 #else 289 return (int)result; 290 #endif 291 } 292 293 #if defined(_UNICODE) && !defined(UNDER_CE) 294 #if defined(__GNUC__) || defined(__clang__) 295 #pragma GCC diagnostic pop 296 #endif 297 #endif 298 299 #endif /* ndef UNITTESTS */