113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "tool_setup.h" 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#include <sys/stat.h> 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#ifdef _WIN32 2913498266Sopenharmony_ci#include <tchar.h> 3013498266Sopenharmony_ci#endif 3113498266Sopenharmony_ci 3213498266Sopenharmony_ci#include <signal.h> 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci#ifdef HAVE_FCNTL_H 3513498266Sopenharmony_ci#include <fcntl.h> 3613498266Sopenharmony_ci#endif 3713498266Sopenharmony_ci 3813498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 3913498266Sopenharmony_ci/* use our own printf() functions */ 4013498266Sopenharmony_ci#include "curlx.h" 4113498266Sopenharmony_ci 4213498266Sopenharmony_ci#include "tool_cfgable.h" 4313498266Sopenharmony_ci#include "tool_doswin.h" 4413498266Sopenharmony_ci#include "tool_msgs.h" 4513498266Sopenharmony_ci#include "tool_operate.h" 4613498266Sopenharmony_ci#include "tool_vms.h" 4713498266Sopenharmony_ci#include "tool_main.h" 4813498266Sopenharmony_ci#include "tool_libinfo.h" 4913498266Sopenharmony_ci#include "tool_stderr.h" 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci/* 5213498266Sopenharmony_ci * This is low-level hard-hacking memory leak tracking and similar. Using 5313498266Sopenharmony_ci * the library level code from this client-side is ugly, but we do this 5413498266Sopenharmony_ci * anyway for convenience. 5513498266Sopenharmony_ci */ 5613498266Sopenharmony_ci#include "memdebug.h" /* keep this as LAST include */ 5713498266Sopenharmony_ci 5813498266Sopenharmony_ci#ifdef __VMS 5913498266Sopenharmony_ci/* 6013498266Sopenharmony_ci * vms_show is a global variable, used in main() as parameter for 6113498266Sopenharmony_ci * function vms_special_exit() to allow proper curl tool exiting. 6213498266Sopenharmony_ci * Its value may be set in other tool_*.c source files thanks to 6313498266Sopenharmony_ci * forward declaration present in tool_vms.h 6413498266Sopenharmony_ci */ 6513498266Sopenharmony_ciint vms_show = 0; 6613498266Sopenharmony_ci#endif 6713498266Sopenharmony_ci 6813498266Sopenharmony_ci#ifdef __MINGW32__ 6913498266Sopenharmony_ci/* 7013498266Sopenharmony_ci * There seems to be no way to escape "*" in command-line arguments with MinGW 7113498266Sopenharmony_ci * when command-line argument globbing is enabled under the MSYS shell, so turn 7213498266Sopenharmony_ci * it off. 7313498266Sopenharmony_ci */ 7413498266Sopenharmony_ciextern int _CRT_glob; 7513498266Sopenharmony_ciint _CRT_glob = 0; 7613498266Sopenharmony_ci#endif /* __MINGW32__ */ 7713498266Sopenharmony_ci 7813498266Sopenharmony_ci/* if we build a static library for unit tests, there is no main() function */ 7913498266Sopenharmony_ci#ifndef UNITTESTS 8013498266Sopenharmony_ci 8113498266Sopenharmony_ci#if defined(HAVE_PIPE) && defined(HAVE_FCNTL) 8213498266Sopenharmony_ci/* 8313498266Sopenharmony_ci * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are 8413498266Sopenharmony_ci * open before starting to run. Otherwise, the first three network 8513498266Sopenharmony_ci * sockets opened by curl could be used for input sources, downloaded data 8613498266Sopenharmony_ci * or error logs as they will effectively be stdin, stdout and/or stderr. 8713498266Sopenharmony_ci * 8813498266Sopenharmony_ci * fcntl's F_GETFD instruction returns -1 if the file descriptor is closed, 8913498266Sopenharmony_ci * otherwise it returns "the file descriptor flags (which typically can only 9013498266Sopenharmony_ci * be FD_CLOEXEC, which is not set here). 9113498266Sopenharmony_ci */ 9213498266Sopenharmony_cistatic int main_checkfds(void) 9313498266Sopenharmony_ci{ 9413498266Sopenharmony_ci int fd[2]; 9513498266Sopenharmony_ci while((fcntl(STDIN_FILENO, F_GETFD) == -1) || 9613498266Sopenharmony_ci (fcntl(STDOUT_FILENO, F_GETFD) == -1) || 9713498266Sopenharmony_ci (fcntl(STDERR_FILENO, F_GETFD) == -1)) 9813498266Sopenharmony_ci if(pipe(fd)) 9913498266Sopenharmony_ci return 1; 10013498266Sopenharmony_ci return 0; 10113498266Sopenharmony_ci} 10213498266Sopenharmony_ci#else 10313498266Sopenharmony_ci#define main_checkfds() 0 10413498266Sopenharmony_ci#endif 10513498266Sopenharmony_ci 10613498266Sopenharmony_ci#ifdef CURLDEBUG 10713498266Sopenharmony_cistatic void memory_tracking_init(void) 10813498266Sopenharmony_ci{ 10913498266Sopenharmony_ci char *env; 11013498266Sopenharmony_ci /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ 11113498266Sopenharmony_ci env = curlx_getenv("CURL_MEMDEBUG"); 11213498266Sopenharmony_ci if(env) { 11313498266Sopenharmony_ci /* use the value as file name */ 11413498266Sopenharmony_ci char fname[CURL_MT_LOGFNAME_BUFSIZE]; 11513498266Sopenharmony_ci if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) 11613498266Sopenharmony_ci env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; 11713498266Sopenharmony_ci strcpy(fname, env); 11813498266Sopenharmony_ci curl_free(env); 11913498266Sopenharmony_ci curl_dbg_memdebug(fname); 12013498266Sopenharmony_ci /* this weird stuff here is to make curl_free() get called before 12113498266Sopenharmony_ci curl_dbg_memdebug() as otherwise memory tracking will log a free() 12213498266Sopenharmony_ci without an alloc! */ 12313498266Sopenharmony_ci } 12413498266Sopenharmony_ci /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ 12513498266Sopenharmony_ci env = curlx_getenv("CURL_MEMLIMIT"); 12613498266Sopenharmony_ci if(env) { 12713498266Sopenharmony_ci char *endptr; 12813498266Sopenharmony_ci long num = strtol(env, &endptr, 10); 12913498266Sopenharmony_ci if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) 13013498266Sopenharmony_ci curl_dbg_memlimit(num); 13113498266Sopenharmony_ci curl_free(env); 13213498266Sopenharmony_ci } 13313498266Sopenharmony_ci} 13413498266Sopenharmony_ci#else 13513498266Sopenharmony_ci# define memory_tracking_init() Curl_nop_stmt 13613498266Sopenharmony_ci#endif 13713498266Sopenharmony_ci 13813498266Sopenharmony_ci/* 13913498266Sopenharmony_ci * This is the main global constructor for the app. Call this before 14013498266Sopenharmony_ci * _any_ libcurl usage. If this fails, *NO* libcurl functions may be 14113498266Sopenharmony_ci * used, or havoc may be the result. 14213498266Sopenharmony_ci */ 14313498266Sopenharmony_cistatic CURLcode main_init(struct GlobalConfig *config) 14413498266Sopenharmony_ci{ 14513498266Sopenharmony_ci CURLcode result = CURLE_OK; 14613498266Sopenharmony_ci 14713498266Sopenharmony_ci#if defined(__DJGPP__) || defined(__GO32__) 14813498266Sopenharmony_ci /* stop stat() wasting time */ 14913498266Sopenharmony_ci _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; 15013498266Sopenharmony_ci#endif 15113498266Sopenharmony_ci 15213498266Sopenharmony_ci /* Initialise the global config */ 15313498266Sopenharmony_ci config->showerror = FALSE; /* show errors when silent */ 15413498266Sopenharmony_ci config->styled_output = TRUE; /* enable detection */ 15513498266Sopenharmony_ci config->parallel_max = PARALLEL_DEFAULT; 15613498266Sopenharmony_ci 15713498266Sopenharmony_ci /* Allocate the initial operate config */ 15813498266Sopenharmony_ci config->first = config->last = malloc(sizeof(struct OperationConfig)); 15913498266Sopenharmony_ci if(config->first) { 16013498266Sopenharmony_ci /* Perform the libcurl initialization */ 16113498266Sopenharmony_ci result = curl_global_init(CURL_GLOBAL_DEFAULT); 16213498266Sopenharmony_ci if(!result) { 16313498266Sopenharmony_ci /* Get information about libcurl */ 16413498266Sopenharmony_ci result = get_libcurl_info(); 16513498266Sopenharmony_ci 16613498266Sopenharmony_ci if(!result) { 16713498266Sopenharmony_ci /* Initialise the config */ 16813498266Sopenharmony_ci config_init(config->first); 16913498266Sopenharmony_ci config->first->global = config; 17013498266Sopenharmony_ci } 17113498266Sopenharmony_ci else { 17213498266Sopenharmony_ci errorf(config, "error retrieving curl library information"); 17313498266Sopenharmony_ci free(config->first); 17413498266Sopenharmony_ci } 17513498266Sopenharmony_ci } 17613498266Sopenharmony_ci else { 17713498266Sopenharmony_ci errorf(config, "error initializing curl library"); 17813498266Sopenharmony_ci free(config->first); 17913498266Sopenharmony_ci } 18013498266Sopenharmony_ci } 18113498266Sopenharmony_ci else { 18213498266Sopenharmony_ci errorf(config, "error initializing curl"); 18313498266Sopenharmony_ci result = CURLE_FAILED_INIT; 18413498266Sopenharmony_ci } 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci return result; 18713498266Sopenharmony_ci} 18813498266Sopenharmony_ci 18913498266Sopenharmony_cistatic void free_globalconfig(struct GlobalConfig *config) 19013498266Sopenharmony_ci{ 19113498266Sopenharmony_ci Curl_safefree(config->trace_dump); 19213498266Sopenharmony_ci 19313498266Sopenharmony_ci if(config->trace_fopened && config->trace_stream) 19413498266Sopenharmony_ci fclose(config->trace_stream); 19513498266Sopenharmony_ci config->trace_stream = NULL; 19613498266Sopenharmony_ci 19713498266Sopenharmony_ci Curl_safefree(config->libcurl); 19813498266Sopenharmony_ci} 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci/* 20113498266Sopenharmony_ci * This is the main global destructor for the app. Call this after 20213498266Sopenharmony_ci * _all_ libcurl usage is done. 20313498266Sopenharmony_ci */ 20413498266Sopenharmony_cistatic void main_free(struct GlobalConfig *config) 20513498266Sopenharmony_ci{ 20613498266Sopenharmony_ci /* Cleanup the easy handle */ 20713498266Sopenharmony_ci /* Main cleanup */ 20813498266Sopenharmony_ci curl_global_cleanup(); 20913498266Sopenharmony_ci free_globalconfig(config); 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci /* Free the config structures */ 21213498266Sopenharmony_ci config_free(config->last); 21313498266Sopenharmony_ci config->first = NULL; 21413498266Sopenharmony_ci config->last = NULL; 21513498266Sopenharmony_ci} 21613498266Sopenharmony_ci 21713498266Sopenharmony_ci/* 21813498266Sopenharmony_ci** curl tool main function. 21913498266Sopenharmony_ci*/ 22013498266Sopenharmony_ci#ifdef _UNICODE 22113498266Sopenharmony_ci#if defined(__GNUC__) 22213498266Sopenharmony_ci/* GCC doesn't know about wmain() */ 22313498266Sopenharmony_ci#pragma GCC diagnostic push 22413498266Sopenharmony_ci#pragma GCC diagnostic ignored "-Wmissing-prototypes" 22513498266Sopenharmony_ci#pragma GCC diagnostic ignored "-Wmissing-declarations" 22613498266Sopenharmony_ci#endif 22713498266Sopenharmony_ciint wmain(int argc, wchar_t *argv[]) 22813498266Sopenharmony_ci#else 22913498266Sopenharmony_ciint main(int argc, char *argv[]) 23013498266Sopenharmony_ci#endif 23113498266Sopenharmony_ci{ 23213498266Sopenharmony_ci CURLcode result = CURLE_OK; 23313498266Sopenharmony_ci struct GlobalConfig global; 23413498266Sopenharmony_ci memset(&global, 0, sizeof(global)); 23513498266Sopenharmony_ci 23613498266Sopenharmony_ci tool_init_stderr(); 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci#ifdef _WIN32 23913498266Sopenharmony_ci /* Undocumented diagnostic option to list the full paths of all loaded 24013498266Sopenharmony_ci modules. This is purposely pre-init. */ 24113498266Sopenharmony_ci if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) { 24213498266Sopenharmony_ci struct curl_slist *item, *head = GetLoadedModulePaths(); 24313498266Sopenharmony_ci for(item = head; item; item = item->next) 24413498266Sopenharmony_ci printf("%s\n", item->data); 24513498266Sopenharmony_ci curl_slist_free_all(head); 24613498266Sopenharmony_ci return head ? 0 : 1; 24713498266Sopenharmony_ci } 24813498266Sopenharmony_ci /* win32_init must be called before other init routines. */ 24913498266Sopenharmony_ci result = win32_init(); 25013498266Sopenharmony_ci if(result) { 25113498266Sopenharmony_ci errorf(&global, "(%d) Windows-specific init failed", result); 25213498266Sopenharmony_ci return result; 25313498266Sopenharmony_ci } 25413498266Sopenharmony_ci#endif 25513498266Sopenharmony_ci 25613498266Sopenharmony_ci if(main_checkfds()) { 25713498266Sopenharmony_ci errorf(&global, "out of file descriptors"); 25813498266Sopenharmony_ci return CURLE_FAILED_INIT; 25913498266Sopenharmony_ci } 26013498266Sopenharmony_ci 26113498266Sopenharmony_ci#if defined(HAVE_SIGNAL) && defined(SIGPIPE) 26213498266Sopenharmony_ci (void)signal(SIGPIPE, SIG_IGN); 26313498266Sopenharmony_ci#endif 26413498266Sopenharmony_ci 26513498266Sopenharmony_ci /* Initialize memory tracking */ 26613498266Sopenharmony_ci memory_tracking_init(); 26713498266Sopenharmony_ci 26813498266Sopenharmony_ci /* Initialize the curl library - do not call any libcurl functions before 26913498266Sopenharmony_ci this point */ 27013498266Sopenharmony_ci result = main_init(&global); 27113498266Sopenharmony_ci if(!result) { 27213498266Sopenharmony_ci /* Start our curl operation */ 27313498266Sopenharmony_ci result = operate(&global, argc, argv); 27413498266Sopenharmony_ci 27513498266Sopenharmony_ci /* Perform the main cleanup */ 27613498266Sopenharmony_ci main_free(&global); 27713498266Sopenharmony_ci } 27813498266Sopenharmony_ci 27913498266Sopenharmony_ci#ifdef _WIN32 28013498266Sopenharmony_ci /* Flush buffers of all streams opened in write or update mode */ 28113498266Sopenharmony_ci fflush(NULL); 28213498266Sopenharmony_ci#endif 28313498266Sopenharmony_ci 28413498266Sopenharmony_ci#ifdef __VMS 28513498266Sopenharmony_ci vms_special_exit(result, vms_show); 28613498266Sopenharmony_ci#else 28713498266Sopenharmony_ci return (int)result; 28813498266Sopenharmony_ci#endif 28913498266Sopenharmony_ci} 29013498266Sopenharmony_ci 29113498266Sopenharmony_ci#ifdef _UNICODE 29213498266Sopenharmony_ci#ifdef __GNUC__ 29313498266Sopenharmony_ci#pragma GCC diagnostic pop 29413498266Sopenharmony_ci#endif 29513498266Sopenharmony_ci#endif 29613498266Sopenharmony_ci 29713498266Sopenharmony_ci#endif /* ndef UNITTESTS */ 298