• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, 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  ***************************************************************************/
22 #include "tool_setup.h"
23 
24 #include <sys/stat.h>
25 
26 #ifdef WIN32
27 #include <tchar.h>
28 #endif
29 
30 #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"
45 #include "tool_doswin.h"
46 #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  */
67 int vms_show = 0;
68 #endif
69 
70 #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  */
76 int _CRT_glob = 0;
77 #endif /* __MINGW32__ */
78 
79 /* 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  */
main_checkfds(void)88 static 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
memory_tracking_init(void)107 static 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);
119     curl_dbg_memdebug(fname);
120     /* this weird stuff here is to make curl_free() get called before
121        curl_gdb_memdebug() as otherwise memory tracking will log a free()
122        without an alloc! */
123   }
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))
130       curl_dbg_memlimit(num);
131     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  */
main_init(struct GlobalConfig * config)143 static 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 */
155   config->styled_output = TRUE;       /* enable detection */
156   config->parallel_max = PARALLEL_DEFAULT;
157 
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) {
168         /* Initialise the config */
169         config_init(config->first);
170         config->first->global = config;
171       }
172       else {
173         errorf(config, "error retrieving curl library information\n");
174         free(config->first);
175       }
176     }
177     else {
178       errorf(config, "error initializing curl library\n");
179       free(config->first);
180     }
181   }
182   else {
183     errorf(config, "error initializing curl\n");
184     result = CURLE_FAILED_INIT;
185   }
186 
187   return result;
188 }
189 
free_globalconfig(struct GlobalConfig * config)190 static void free_globalconfig(struct GlobalConfig *config)
191 {
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  */
main_free(struct GlobalConfig * config)209 static void main_free(struct GlobalConfig *config)
210 {
211   /* Cleanup the easy handle */
212   /* Main cleanup */
213   curl_global_cleanup();
214   convert_cleanup();
215 #ifdef USE_NSS
216   if(PR_Initialized()) {
217     /* prevent valgrind from reporting still reachable mem from NSRP arenas */
218     PL_ArenaFinish();
219     /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */
220     PR_Cleanup();
221   }
222 #endif
223   free_globalconfig(config);
224 
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 */
234 #ifdef _UNICODE
wmain(int argc,wchar_t * argv[])235 int wmain(int argc, wchar_t *argv[])
236 #else
237 int main(int argc, char *argv[])
238 #endif
239 {
240   CURLcode result = CURLE_OK;
241   struct GlobalConfig global;
242   memset(&global, 0, sizeof(global));
243 
244 #ifdef WIN32
245   /* Undocumented diagnostic option to list the full paths of all loaded
246      modules. This is purposely pre-init. */
247   if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) {
248     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 
262   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 
278     /* Perform the main cleanup */
279     main_free(&global);
280   }
281 
282 #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 */
295