mirror of
https://github.com/moparisthebest/curl
synced 2024-11-16 06:25:03 -05:00
397664a065
- Add an undocumented diagnostic option for Windows to show the full paths of all loaded modules regardless of whether or not libcurl initialization succeeds. This is needed so that in the CI we can get a list of all DLL dependencies after initialization (when they're most likely to have finished loading) and then package them as artifacts so that a functioning build can be downloaded. Also I imagine it may have some use as a diagnostic for help requests. Ref: https://github.com/curl/curl/pull/3103 Closes https://github.com/curl/curl/pull/3208
353 lines
9.7 KiB
C
353 lines
9.7 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.haxx.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
***************************************************************************/
|
|
#include "tool_setup.h"
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef HAVE_SIGNAL_H
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#ifdef USE_NSS
|
|
#include <nspr.h>
|
|
#include <plarenas.h>
|
|
#endif
|
|
|
|
#define ENABLE_CURLX_PRINTF
|
|
/* use our own printf() functions */
|
|
#include "curlx.h"
|
|
|
|
#include "tool_cfgable.h"
|
|
#include "tool_convert.h"
|
|
#include "tool_doswin.h"
|
|
#include "tool_msgs.h"
|
|
#include "tool_operate.h"
|
|
#include "tool_panykey.h"
|
|
#include "tool_vms.h"
|
|
#include "tool_main.h"
|
|
#include "tool_libinfo.h"
|
|
|
|
/*
|
|
* This is low-level hard-hacking memory leak tracking and similar. Using
|
|
* the library level code from this client-side is ugly, but we do this
|
|
* anyway for convenience.
|
|
*/
|
|
#include "memdebug.h" /* keep this as LAST include */
|
|
|
|
#ifdef __VMS
|
|
/*
|
|
* vms_show is a global variable, used in main() as parameter for
|
|
* function vms_special_exit() to allow proper curl tool exiting.
|
|
* Its value may be set in other tool_*.c source files thanks to
|
|
* forward declaration present in tool_vms.h
|
|
*/
|
|
int vms_show = 0;
|
|
#endif
|
|
|
|
#ifdef __MINGW32__
|
|
/*
|
|
* There seems to be no way to escape "*" in command-line arguments with MinGW
|
|
* when command-line argument globbing is enabled under the MSYS shell, so turn
|
|
* it off.
|
|
*/
|
|
int _CRT_glob = 0;
|
|
#endif /* __MINGW32__ */
|
|
|
|
/* if we build a static library for unit tests, there is no main() function */
|
|
#ifndef UNITTESTS
|
|
|
|
/*
|
|
* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
|
|
* open before starting to run. Otherwise, the first three network
|
|
* sockets opened by curl could be used for input sources, downloaded data
|
|
* or error logs as they will effectively be stdin, stdout and/or stderr.
|
|
*/
|
|
static void main_checkfds(void)
|
|
{
|
|
#ifdef HAVE_PIPE
|
|
int fd[2] = { STDIN_FILENO, STDIN_FILENO };
|
|
while(fd[0] == STDIN_FILENO ||
|
|
fd[0] == STDOUT_FILENO ||
|
|
fd[0] == STDERR_FILENO ||
|
|
fd[1] == STDIN_FILENO ||
|
|
fd[1] == STDOUT_FILENO ||
|
|
fd[1] == STDERR_FILENO)
|
|
if(pipe(fd) < 0)
|
|
return; /* Out of handles. This isn't really a big problem now, but
|
|
will be when we try to create a socket later. */
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
#endif
|
|
}
|
|
|
|
#ifdef CURLDEBUG
|
|
static void memory_tracking_init(void)
|
|
{
|
|
char *env;
|
|
/* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
|
|
env = curlx_getenv("CURL_MEMDEBUG");
|
|
if(env) {
|
|
/* use the value as file name */
|
|
char fname[CURL_MT_LOGFNAME_BUFSIZE];
|
|
if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
|
|
env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
|
|
strcpy(fname, env);
|
|
curl_free(env);
|
|
curl_memdebug(fname);
|
|
/* this weird stuff here is to make curl_free() get called
|
|
before curl_memdebug() as otherwise memory tracking will
|
|
log a free() without an alloc! */
|
|
}
|
|
/* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
|
|
env = curlx_getenv("CURL_MEMLIMIT");
|
|
if(env) {
|
|
char *endptr;
|
|
long num = strtol(env, &endptr, 10);
|
|
if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
|
|
curl_memlimit(num);
|
|
curl_free(env);
|
|
}
|
|
}
|
|
#else
|
|
# define memory_tracking_init() Curl_nop_stmt
|
|
#endif
|
|
|
|
/*
|
|
* This is the main global constructor for the app. Call this before
|
|
* _any_ libcurl usage. If this fails, *NO* libcurl functions may be
|
|
* used, or havoc may be the result.
|
|
*/
|
|
static CURLcode main_init(struct GlobalConfig *config)
|
|
{
|
|
CURLcode result = CURLE_OK;
|
|
|
|
#if defined(__DJGPP__) || defined(__GO32__)
|
|
/* stop stat() wasting time */
|
|
_djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
|
|
#endif
|
|
|
|
/* Initialise the global config */
|
|
config->showerror = -1; /* Will show errors */
|
|
config->errors = stderr; /* Default errors to stderr */
|
|
config->styled_output = TRUE; /* enable detection */
|
|
|
|
/* Allocate the initial operate config */
|
|
config->first = config->last = malloc(sizeof(struct OperationConfig));
|
|
if(config->first) {
|
|
/* Perform the libcurl initialization */
|
|
result = curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
if(!result) {
|
|
/* Get information about libcurl */
|
|
result = get_libcurl_info();
|
|
|
|
if(!result) {
|
|
/* Get a curl handle to use for all forthcoming curl transfers */
|
|
config->easy = curl_easy_init();
|
|
if(config->easy) {
|
|
/* Initialise the config */
|
|
config_init(config->first);
|
|
config->first->easy = config->easy;
|
|
config->first->global = config;
|
|
}
|
|
else {
|
|
helpf(stderr, "error initializing curl easy handle\n");
|
|
result = CURLE_FAILED_INIT;
|
|
free(config->first);
|
|
}
|
|
}
|
|
else {
|
|
helpf(stderr, "error retrieving curl library information\n");
|
|
free(config->first);
|
|
}
|
|
}
|
|
else {
|
|
helpf(stderr, "error initializing curl library\n");
|
|
free(config->first);
|
|
}
|
|
}
|
|
else {
|
|
helpf(stderr, "error initializing curl\n");
|
|
result = CURLE_FAILED_INIT;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void free_config_fields(struct GlobalConfig *config)
|
|
{
|
|
Curl_safefree(config->trace_dump);
|
|
|
|
if(config->errors_fopened && config->errors)
|
|
fclose(config->errors);
|
|
config->errors = NULL;
|
|
|
|
if(config->trace_fopened && config->trace_stream)
|
|
fclose(config->trace_stream);
|
|
config->trace_stream = NULL;
|
|
|
|
Curl_safefree(config->libcurl);
|
|
}
|
|
|
|
/*
|
|
* This is the main global destructor for the app. Call this after
|
|
* _all_ libcurl usage is done.
|
|
*/
|
|
static void main_free(struct GlobalConfig *config)
|
|
{
|
|
/* Cleanup the easy handle */
|
|
curl_easy_cleanup(config->easy);
|
|
config->easy = NULL;
|
|
|
|
/* Main cleanup */
|
|
curl_global_cleanup();
|
|
convert_cleanup();
|
|
metalink_cleanup();
|
|
#ifdef USE_NSS
|
|
if(PR_Initialized()) {
|
|
/* prevent valgrind from reporting still reachable mem from NSRP arenas */
|
|
PL_ArenaFinish();
|
|
/* prevent valgrind from reporting possibly lost memory (fd cache, ...) */
|
|
PR_Cleanup();
|
|
}
|
|
#endif
|
|
free_config_fields(config);
|
|
|
|
/* Free the config structures */
|
|
config_free(config->last);
|
|
config->first = NULL;
|
|
config->last = NULL;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
/* TerminalSettings for Windows */
|
|
static struct TerminalSettings {
|
|
HANDLE hStdOut;
|
|
DWORD dwOutputMode;
|
|
} TerminalSettings;
|
|
|
|
static void configure_terminal(void)
|
|
{
|
|
/*
|
|
* If we're running Windows, enable VT output.
|
|
* Note: VT mode flag can be set on any version of Windows, but VT
|
|
* processing only performed on Win10 >= Creators Update)
|
|
*/
|
|
|
|
/* Define the VT flags in case we're building with an older SDK */
|
|
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
#endif
|
|
|
|
memset(&TerminalSettings, 0, sizeof(TerminalSettings));
|
|
|
|
/* Enable VT output */
|
|
TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if((TerminalSettings.hStdOut != INVALID_HANDLE_VALUE)
|
|
&& (GetConsoleMode(TerminalSettings.hStdOut,
|
|
&TerminalSettings.dwOutputMode))) {
|
|
SetConsoleMode(TerminalSettings.hStdOut,
|
|
TerminalSettings.dwOutputMode
|
|
| ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
|
}
|
|
}
|
|
#else
|
|
#define configure_terminal()
|
|
#endif
|
|
|
|
static void restore_terminal(void)
|
|
{
|
|
#ifdef _WIN32
|
|
/* Restore Console output mode and codepage to whatever they were
|
|
* when Curl started */
|
|
SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
** curl tool main function.
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
CURLcode result = CURLE_OK;
|
|
struct GlobalConfig global;
|
|
memset(&global, 0, sizeof(global));
|
|
|
|
/* Perform any platform-specific terminal configuration */
|
|
configure_terminal();
|
|
|
|
main_checkfds();
|
|
|
|
#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
|
|
(void)signal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
|
|
/* Initialize memory tracking */
|
|
memory_tracking_init();
|
|
|
|
/* Initialize the curl library - do not call any libcurl functions before
|
|
this point */
|
|
result = main_init(&global);
|
|
|
|
#ifdef WIN32
|
|
/* Undocumented diagnostic option to list the full paths of all loaded
|
|
modules, regardless of whether or not initialization succeeded. */
|
|
if(argc == 2 && !strcmp(argv[1], "--dump-module-paths")) {
|
|
struct curl_slist *item, *head = GetLoadedModulePaths();
|
|
for(item = head; item; item = item->next) {
|
|
printf("%s\n", item->data);
|
|
}
|
|
curl_slist_free_all(head);
|
|
if(!result)
|
|
main_free(&global);
|
|
}
|
|
else
|
|
#endif /* WIN32 */
|
|
if(!result) {
|
|
/* Start our curl operation */
|
|
result = operate(&global, argc, argv);
|
|
|
|
#ifdef __SYMBIAN32__
|
|
if(global.showerror)
|
|
tool_pressanykey();
|
|
#endif
|
|
|
|
/* Perform the main cleanup */
|
|
main_free(&global);
|
|
}
|
|
|
|
/* Return the terminal to its original state */
|
|
restore_terminal();
|
|
|
|
#ifdef __NOVELL_LIBC__
|
|
if(getenv("_IN_NETWARE_BASH_") == NULL)
|
|
tool_pressanykey();
|
|
#endif
|
|
|
|
#ifdef __VMS
|
|
vms_special_exit(result, vms_show);
|
|
#else
|
|
return (int)result;
|
|
#endif
|
|
}
|
|
|
|
#endif /* ndef UNITTESTS */
|