Imported Upstream version 7.59.0
[platform/upstream/curl.git] / src / tool_main.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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 #ifdef __MINGW32__
66 /*
67  * There seems to be no way to escape "*" in command-line arguments with MinGW
68  * when command-line argument globbing is enabled under the MSYS shell, so turn
69  * it off.
70  */
71 int _CRT_glob = 0;
72 #endif /* __MINGW32__ */
73
74 /* if we build a static library for unit tests, there is no main() function */
75 #ifndef UNITTESTS
76
77 /*
78  * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
79  * open before starting to run.  Otherwise, the first three network
80  * sockets opened by curl could be used for input sources, downloaded data
81  * or error logs as they will effectively be stdin, stdout and/or stderr.
82  */
83 static void main_checkfds(void)
84 {
85 #ifdef HAVE_PIPE
86   int fd[2] = { STDIN_FILENO, STDIN_FILENO };
87   while(fd[0] == STDIN_FILENO ||
88         fd[0] == STDOUT_FILENO ||
89         fd[0] == STDERR_FILENO ||
90         fd[1] == STDIN_FILENO ||
91         fd[1] == STDOUT_FILENO ||
92         fd[1] == STDERR_FILENO)
93     if(pipe(fd) < 0)
94       return;   /* Out of handles. This isn't really a big problem now, but
95                    will be when we try to create a socket later. */
96   close(fd[0]);
97   close(fd[1]);
98 #endif
99 }
100
101 #ifdef CURLDEBUG
102 static void memory_tracking_init(void)
103 {
104   char *env;
105   /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
106   env = curlx_getenv("CURL_MEMDEBUG");
107   if(env) {
108     /* use the value as file name */
109     char fname[CURL_MT_LOGFNAME_BUFSIZE];
110     if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
111       env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
112     strcpy(fname, env);
113     curl_free(env);
114     curl_memdebug(fname);
115     /* this weird stuff here is to make curl_free() get called
116        before curl_memdebug() as otherwise memory tracking will
117        log a free() without an alloc! */
118   }
119   /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
120   env = curlx_getenv("CURL_MEMLIMIT");
121   if(env) {
122     char *endptr;
123     long num = strtol(env, &endptr, 10);
124     if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
125       curl_memlimit(num);
126     curl_free(env);
127   }
128 }
129 #else
130 #  define memory_tracking_init() Curl_nop_stmt
131 #endif
132
133 /*
134  * This is the main global constructor for the app. Call this before
135  * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
136  * used, or havoc may be the result.
137  */
138 static CURLcode main_init(struct GlobalConfig *config)
139 {
140   CURLcode result = CURLE_OK;
141
142 #if defined(__DJGPP__) || defined(__GO32__)
143   /* stop stat() wasting time */
144   _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
145 #endif
146
147   /* Initialise the global config */
148   config->showerror = -1;             /* Will show errors */
149   config->errors = stderr;            /* Default errors to stderr */
150
151   /* Allocate the initial operate config */
152   config->first = config->last = malloc(sizeof(struct OperationConfig));
153   if(config->first) {
154     /* Perform the libcurl initialization */
155     result = curl_global_init(CURL_GLOBAL_DEFAULT);
156     if(!result) {
157       /* Get information about libcurl */
158       result = get_libcurl_info();
159
160       if(!result) {
161         /* Get a curl handle to use for all forthcoming curl transfers */
162         config->easy = curl_easy_init();
163         if(config->easy) {
164           /* Initialise the config */
165           config_init(config->first);
166           config->first->easy = config->easy;
167           config->first->global = config;
168         }
169         else {
170           helpf(stderr, "error initializing curl easy handle\n");
171           result = CURLE_FAILED_INIT;
172           free(config->first);
173         }
174       }
175       else {
176         helpf(stderr, "error retrieving curl library information\n");
177         free(config->first);
178       }
179     }
180     else {
181       helpf(stderr, "error initializing curl library\n");
182       free(config->first);
183     }
184   }
185   else {
186     helpf(stderr, "error initializing curl\n");
187     result = CURLE_FAILED_INIT;
188   }
189
190   return result;
191 }
192
193 static void free_config_fields(struct GlobalConfig *config)
194 {
195   Curl_safefree(config->trace_dump);
196
197   if(config->errors_fopened && config->errors)
198     fclose(config->errors);
199   config->errors = NULL;
200
201   if(config->trace_fopened && config->trace_stream)
202     fclose(config->trace_stream);
203   config->trace_stream = NULL;
204
205   Curl_safefree(config->libcurl);
206 }
207
208 /*
209  * This is the main global destructor for the app. Call this after
210  * _all_ libcurl usage is done.
211  */
212 static void main_free(struct GlobalConfig *config)
213 {
214   /* Cleanup the easy handle */
215   curl_easy_cleanup(config->easy);
216   config->easy = NULL;
217
218   /* Main cleanup */
219   curl_global_cleanup();
220   convert_cleanup();
221   metalink_cleanup();
222 #ifdef USE_NSS
223   if(PR_Initialized()) {
224     /* prevent valgrind from reporting still reachable mem from NSRP arenas */
225     PL_ArenaFinish();
226     /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */
227     PR_Cleanup();
228   }
229 #endif
230   free_config_fields(config);
231
232   /* Free the config structures */
233   config_free(config->last);
234   config->first = NULL;
235   config->last = NULL;
236 }
237
238 /*
239 ** curl tool main function.
240 */
241 int main(int argc, char *argv[])
242 {
243   CURLcode result = CURLE_OK;
244   struct GlobalConfig global;
245   memset(&global, 0, sizeof(global));
246
247   main_checkfds();
248
249 #if defined(HAVE_SIGNAL) && defined(SIGPIPE)
250   (void)signal(SIGPIPE, SIG_IGN);
251 #endif
252
253   /* Initialize memory tracking */
254   memory_tracking_init();
255
256   /* Initialize the curl library - do not call any libcurl functions before
257      this point */
258   result = main_init(&global);
259   if(!result) {
260     /* Start our curl operation */
261     result = operate(&global, argc, argv);
262
263 #ifdef __SYMBIAN32__
264     if(global.showerror)
265       tool_pressanykey();
266 #endif
267
268     /* Perform the main cleanup */
269     main_free(&global);
270   }
271
272 #ifdef __NOVELL_LIBC__
273   if(getenv("_IN_NETWARE_BASH_") == NULL)
274     tool_pressanykey();
275 #endif
276
277 #ifdef __VMS
278   vms_special_exit(result, vms_show);
279 #else
280   return (int)result;
281 #endif
282 }
283
284 #endif /* ndef UNITTESTS */