blob: 23ba6cb2009d7553ec1d4eeb72210cc4db71251b [file] [log] [blame]
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes34dd5f42021-08-10 13:01:18 -07008 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Elliott Hughes34dd5f42021-08-10 13:01:18 -070012 * are also available at https://curl.se/docs/copyright.html.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070013 *
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
Elliott Hughes34dd5f42021-08-10 13:01:18 -070026#ifdef WIN32
27#include <tchar.h>
28#endif
29
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070030#ifdef HAVE_SIGNAL_H
31#include <signal.h>
32#endif
33
34#ifdef USE_NSS
35#include <nspr.h>
36#include <plarenas.h>
37#endif
38
39#define ENABLE_CURLX_PRINTF
40/* use our own printf() functions */
41#include "curlx.h"
42
43#include "tool_cfgable.h"
44#include "tool_convert.h"
Haibo Huang21926d52019-01-08 14:27:10 -080045#include "tool_doswin.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070046#include "tool_msgs.h"
47#include "tool_operate.h"
48#include "tool_panykey.h"
49#include "tool_vms.h"
50#include "tool_main.h"
51#include "tool_libinfo.h"
52
53/*
54 * This is low-level hard-hacking memory leak tracking and similar. Using
55 * the library level code from this client-side is ugly, but we do this
56 * anyway for convenience.
57 */
58#include "memdebug.h" /* keep this as LAST include */
59
60#ifdef __VMS
61/*
62 * vms_show is a global variable, used in main() as parameter for
63 * function vms_special_exit() to allow proper curl tool exiting.
64 * Its value may be set in other tool_*.c source files thanks to
65 * forward declaration present in tool_vms.h
66 */
67int vms_show = 0;
68#endif
69
Alex Deymo486467e2017-12-19 19:04:07 +010070#ifdef __MINGW32__
71/*
72 * There seems to be no way to escape "*" in command-line arguments with MinGW
73 * when command-line argument globbing is enabled under the MSYS shell, so turn
74 * it off.
75 */
76int _CRT_glob = 0;
77#endif /* __MINGW32__ */
78
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070079/* if we build a static library for unit tests, there is no main() function */
80#ifndef UNITTESTS
81
82/*
83 * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
84 * open before starting to run. Otherwise, the first three network
85 * sockets opened by curl could be used for input sources, downloaded data
86 * or error logs as they will effectively be stdin, stdout and/or stderr.
87 */
88static void main_checkfds(void)
89{
90#ifdef HAVE_PIPE
91 int fd[2] = { STDIN_FILENO, STDIN_FILENO };
92 while(fd[0] == STDIN_FILENO ||
93 fd[0] == STDOUT_FILENO ||
94 fd[0] == STDERR_FILENO ||
95 fd[1] == STDIN_FILENO ||
96 fd[1] == STDOUT_FILENO ||
97 fd[1] == STDERR_FILENO)
98 if(pipe(fd) < 0)
99 return; /* Out of handles. This isn't really a big problem now, but
100 will be when we try to create a socket later. */
101 close(fd[0]);
102 close(fd[1]);
103#endif
104}
105
106#ifdef CURLDEBUG
107static void memory_tracking_init(void)
108{
109 char *env;
110 /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
111 env = curlx_getenv("CURL_MEMDEBUG");
112 if(env) {
113 /* use the value as file name */
114 char fname[CURL_MT_LOGFNAME_BUFSIZE];
115 if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
116 env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
117 strcpy(fname, env);
118 curl_free(env);
Haibo Huang65021c72019-03-27 15:37:23 -0700119 curl_dbg_memdebug(fname);
Haibo Huang445085a2019-09-11 13:33:50 -0700120 /* this weird stuff here is to make curl_free() get called before
Elliott Hughesf344baa2021-12-07 09:12:34 -0800121 curl_dbg_memdebug() as otherwise memory tracking will log a free()
Haibo Huang445085a2019-09-11 13:33:50 -0700122 without an alloc! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700123 }
124 /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
125 env = curlx_getenv("CURL_MEMLIMIT");
126 if(env) {
127 char *endptr;
128 long num = strtol(env, &endptr, 10);
129 if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
Haibo Huang65021c72019-03-27 15:37:23 -0700130 curl_dbg_memlimit(num);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700131 curl_free(env);
132 }
133}
134#else
135# define memory_tracking_init() Curl_nop_stmt
136#endif
137
138/*
139 * This is the main global constructor for the app. Call this before
140 * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
141 * used, or havoc may be the result.
142 */
143static CURLcode main_init(struct GlobalConfig *config)
144{
145 CURLcode result = CURLE_OK;
146
147#if defined(__DJGPP__) || defined(__GO32__)
148 /* stop stat() wasting time */
149 _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
150#endif
151
152 /* Initialise the global config */
153 config->showerror = -1; /* Will show errors */
154 config->errors = stderr; /* Default errors to stderr */
Elliott Hughes72d948d2018-08-03 14:37:21 -0700155 config->styled_output = TRUE; /* enable detection */
Haibo Huang445085a2019-09-11 13:33:50 -0700156 config->parallel_max = PARALLEL_DEFAULT;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700157
158 /* Allocate the initial operate config */
159 config->first = config->last = malloc(sizeof(struct OperationConfig));
160 if(config->first) {
161 /* Perform the libcurl initialization */
162 result = curl_global_init(CURL_GLOBAL_DEFAULT);
163 if(!result) {
164 /* Get information about libcurl */
165 result = get_libcurl_info();
166
167 if(!result) {
Haibo Huang445085a2019-09-11 13:33:50 -0700168 /* Initialise the config */
169 config_init(config->first);
170 config->first->global = config;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700171 }
172 else {
Haibo Huangb51266f2020-03-04 02:22:48 -0800173 errorf(config, "error retrieving curl library information\n");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700174 free(config->first);
175 }
176 }
177 else {
Haibo Huangb51266f2020-03-04 02:22:48 -0800178 errorf(config, "error initializing curl library\n");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700179 free(config->first);
180 }
181 }
182 else {
Haibo Huangb51266f2020-03-04 02:22:48 -0800183 errorf(config, "error initializing curl\n");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700184 result = CURLE_FAILED_INIT;
185 }
186
187 return result;
188}
189
Haibo Huang21926d52019-01-08 14:27:10 -0800190static void free_globalconfig(struct GlobalConfig *config)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700191{
192 Curl_safefree(config->trace_dump);
193
194 if(config->errors_fopened && config->errors)
195 fclose(config->errors);
196 config->errors = NULL;
197
198 if(config->trace_fopened && config->trace_stream)
199 fclose(config->trace_stream);
200 config->trace_stream = NULL;
201
202 Curl_safefree(config->libcurl);
203}
204
205/*
206 * This is the main global destructor for the app. Call this after
207 * _all_ libcurl usage is done.
208 */
209static void main_free(struct GlobalConfig *config)
210{
211 /* Cleanup the easy handle */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700212 /* Main cleanup */
213 curl_global_cleanup();
214 convert_cleanup();
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700215#ifdef USE_NSS
216 if(PR_Initialized()) {
Elliott Hughesf344baa2021-12-07 09:12:34 -0800217 /* prevent valgrind from reporting still reachable mem from NSPR arenas */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700218 PL_ArenaFinish();
219 /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */
220 PR_Cleanup();
221 }
222#endif
Haibo Huang21926d52019-01-08 14:27:10 -0800223 free_globalconfig(config);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700224
225 /* Free the config structures */
226 config_free(config->last);
227 config->first = NULL;
228 config->last = NULL;
229}
230
231/*
232** curl tool main function.
233*/
Haibo Huangca2a8022020-07-10 20:17:42 -0700234#ifdef _UNICODE
235int wmain(int argc, wchar_t *argv[])
236#else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700237int main(int argc, char *argv[])
Haibo Huangca2a8022020-07-10 20:17:42 -0700238#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700239{
240 CURLcode result = CURLE_OK;
241 struct GlobalConfig global;
242 memset(&global, 0, sizeof(global));
243
Haibo Huangb51266f2020-03-04 02:22:48 -0800244#ifdef WIN32
245 /* Undocumented diagnostic option to list the full paths of all loaded
246 modules. This is purposely pre-init. */
Haibo Huangca2a8022020-07-10 20:17:42 -0700247 if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) {
Haibo Huangb51266f2020-03-04 02:22:48 -0800248 struct curl_slist *item, *head = GetLoadedModulePaths();
249 for(item = head; item; item = item->next)
250 printf("%s\n", item->data);
251 curl_slist_free_all(head);
252 return head ? 0 : 1;
253 }
254 /* win32_init must be called before other init routines. */
255 result = win32_init();
256 if(result) {
257 fprintf(stderr, "curl: (%d) Windows-specific init failed.\n", result);
258 return result;
259 }
260#endif
261
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700262 main_checkfds();
263
264#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
265 (void)signal(SIGPIPE, SIG_IGN);
266#endif
267
268 /* Initialize memory tracking */
269 memory_tracking_init();
270
271 /* Initialize the curl library - do not call any libcurl functions before
272 this point */
273 result = main_init(&global);
274 if(!result) {
275 /* Start our curl operation */
276 result = operate(&global, argc, argv);
277
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700278 /* Perform the main cleanup */
279 main_free(&global);
280 }
281
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700282#ifdef __NOVELL_LIBC__
283 if(getenv("_IN_NETWARE_BASH_") == NULL)
284 tool_pressanykey();
285#endif
286
287#ifdef __VMS
288 vms_special_exit(result, vms_show);
289#else
290 return (int)result;
291#endif
292}
293
294#endif /* ndef UNITTESTS */