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