--- /dev/null
+/*
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+
+#include "CommandLine.h"
+#include "sbuf/SBuf.h"
+
+static void
+ResetGetopt(const bool allowStderrWarnings)
+{
+ opterr = allowStderrWarnings;
+ // Resetting optind to zero instead of conventional '1' has an
+ // advantage, since it also resets getopt(3) global state.
+ // getopt(3) always skips argv[0], even if optind is zero
+ optind = 0;
+}
+
+CommandLine::CommandLine(int argC, char *argV[], const char *shortRules, const RawLongOption *longRules):
+ argv_(),
+ shortOptions_(shortRules ? xstrdup(shortRules) : ""),
+ longOptions_()
+{
+ assert(argC > 0); // C++ main() requirement that makes our arg0() safe
+ assert(shortRules);
+
+ /* copy argV items */
+ argv_.reserve(argC+1);
+ for (int i = 0; i < argC; ++i)
+ argv_.push_back(xstrdup(argV[i]));
+ argv_.push_back(nullptr); // POSIX argv "must be terminated by a null pointer"
+
+ /* copy grammar rules for the long options */
+ if (longRules) {
+ for (auto longOption = longRules; longOption->name; ++longOption)
+ longOptions_.emplace_back(*longOption);
+ longOptions_.emplace_back();
+ }
+}
+
+CommandLine::CommandLine(const CommandLine &them):
+ CommandLine(them.argc(), them.argv(), them.shortOptions_, them.longOptions())
+{
+}
+
+CommandLine &
+CommandLine::operator =(const CommandLine &them)
+{
+ // cannot just swap(*this, them): std::swap(T,T) may call this assignment op
+ CommandLine tmp(them);
+ std::swap(argv_, tmp.argv_);
+ std::swap(shortOptions_, tmp.shortOptions_);
+ std::swap(longOptions_, tmp.longOptions_);
+ return *this;
+}
+
+CommandLine::~CommandLine()
+{
+ for (auto arg: argv_)
+ xfree(arg);
+
+ xfree(shortOptions_);
+}
+
+bool
+CommandLine::hasOption(const int optIdToFind, const char **optValue) const
+{
+ ResetGetopt(false); // avoid duped warnings; forEachOption() will complain
+ int optId = 0;
+ while (nextOption(optId)) {
+ if (optId == optIdToFind) {
+ if (optValue) {
+ // do not need to copy the optarg string because it is a pointer into the original
+ // argv array (https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html)
+ *optValue = optarg;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CommandLine::forEachOption(Visitor visitor) const
+{
+ ResetGetopt(true);
+ int optId = 0;
+ while (nextOption(optId))
+ visitor(optId, optarg);
+}
+
+/// extracts the next option (if any)
+/// \returns whether the option was extracted
+/// throws on unknown option or missing required argument
+bool
+CommandLine::nextOption(int &optId) const
+{
+ optId = getopt_long(argc(), argv(), shortOptions_, longOptions(), nullptr);
+ if ((optId == ':' && shortOptions_[0] == ':') || optId == '?') {
+ assert(optind > 0 && static_cast<unsigned int>(optind) < argv_.size());
+ SBuf errMsg;
+ errMsg.Printf("'%s': %s", argv_[optind - 1], optId == '?' ?
+ "unrecognized option or missing required argument" : "missing required argument");
+ throw TexcHere(errMsg);
+ }
+ return optId != -1;
+}
+
+void
+CommandLine::resetArg0(const char *programName)
+{
+ assert(programName);
+ xfree(argv_[0]);
+ argv_[0] = xstrdup(programName);
+}
+
+void
+CommandLine::pushFrontOption(const char *name, const char *value)
+{
+ assert(name);
+ argv_.insert(argv_.begin() + 1, xstrdup(name));
+ if (value)
+ argv_.insert(argv_.begin() + 2, xstrdup(value));
+}
+
+LongOption::LongOption() :
+ option({nullptr, 0, nullptr, 0})
+{
+}
+
+LongOption::LongOption(const RawLongOption &opt) :
+ option({nullptr, 0, nullptr, 0})
+{
+ copy(opt);
+}
+
+LongOption::LongOption(const LongOption &opt):
+ LongOption(static_cast<const RawLongOption &>(opt))
+{
+}
+
+LongOption::~LongOption()
+{
+ xfree(name);
+}
+
+LongOption &
+LongOption::operator =(const LongOption &opt)
+{
+ if (this != &opt)
+ copy(static_cast<const RawLongOption &>(opt));
+ return *this;
+}
+
+void
+LongOption::copy(const RawLongOption &opt)
+{
+ xfree(name);
+ name = opt.name ? xstrdup(opt.name) : nullptr;
+ has_arg = opt.has_arg;
+ flag = opt.flag;
+ val = opt.val;
+}
+
#include "client_db.h"
#include "client_side.h"
#include "comm.h"
+#include "CommandLine.h"
#include "ConfigParser.h"
#include "CpuAffinity.h"
#include "DiskIO/DiskIOModule.h"
#include "mime.h"
#include "neighbors.h"
#include "parser/Tokenizer.h"
+#include "Parsing.h"
#include "pconn.h"
#include "peer_sourcehash.h"
#include "peer_userhash.h"
static void mainReconfigureFinish(void*);
static void mainInitialize(void);
static void usage(void);
-static void mainParseOptions(int argc, char *argv[]);
+static void mainHandleCommandLineOption(const int optId, const char *optValue);
static void sendSignal(void);
static void serverConnectionsOpen(void);
static void serverConnectionsClose(void);
-static void watch_child(char **);
+static void watch_child(const CommandLine &);
static void setEffectiveUser(void);
static void SquidShutdown(void);
static void mainSetCwd(void);
" -N Master process runs in foreground and is a worker. No kids.\n"
" --foreground\n"
" Master process runs in foreground and creates worker kids.\n"
+ " --kid role-ID\n"
+ " Play a given SMP kid process role, with a given ID. Do not use\n"
+ " this option. It is meant for the master process use only.\n"
#if USE_WIN32_SERVICE
" -O options\n"
" Set Windows Service Command line options in Registry.\n"
" -X Force full debugging.\n"
" -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
- exit(1);
+ exit(EXIT_FAILURE);
}
-/**
- * Parse the parameters received via command line interface.
- *
- * \param argc Number of options received on command line
- * \param argv List of parameters received on command line
- */
-static void
-mainParseOptions(int argc, char *argv[])
-{
- int optIndex = 0;
+/// CommandLine option IDs for --long options that lack a short (-x) equivalent
+enum {
+ // The absolute values do not matter except that the following values should
+ // not be used: Values below 2 are for special getopt_long(3) use cases, and
+ // values in the [33,126] range are reserved for short options (-x).
+ optForeground = 2,
+ optKid
+};
- // short options
- const char *shortOpStr =
+// short options
+// TODO: consider prefixing with ':' for better logging
+// (distinguish missing required argument cases)
+static const char *shortOpStr =
#if USE_WIN32_SERVICE
- "O:Vir"
+ "O:Vir"
#endif
- "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
-
- // long options
- static struct option squidOptions[] = {
- {"foreground", no_argument, 0, 1 },
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'v'},
- {0, 0, 0, 0}
- };
-
- int c;
- while ((c = getopt_long(argc, argv, shortOpStr, squidOptions, &optIndex)) != -1) {
-
- switch (c) {
+ "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
- case 'C':
- /** \par C
- * Unset/disabel global option for catchign signals. opt_catch_signals */
- opt_catch_signals = 0;
- break;
+// long options
+static struct option squidOptions[] = {
+ {"foreground", no_argument, 0, optForeground},
+ {"kid", required_argument, 0, optKid},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+};
- case 'D':
- /** \par D
- * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
- debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
- break;
+// handle a command line parameter
+static void
+mainHandleCommandLineOption(const int optId, const char *optValue)
+{
+ switch (optId) {
+
+ case 'C':
+ /** \par C
+ * Unset/disabel global option for catchign signals. opt_catch_signals */
+ opt_catch_signals = 0;
+ break;
+
+ case 'D':
+ /** \par D
+ * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
+ debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
+ break;
+
+ case 'F':
+ /** \par F
+ * Set global option for foreground rebuild. opt_foreground_rebuild */
+ opt_foreground_rebuild = 1;
+ break;
+
+ case 'N':
+ /** \par N
+ * Set global option for 'no_daemon' mode. opt_no_daemon */
+ opt_no_daemon = 1;
+ break;
- case 'F':
- /** \par F
- * Set global option for foreground rebuild. opt_foreground_rebuild */
- opt_foreground_rebuild = 1;
- break;
+#if USE_WIN32_SERVICE
- case 'N':
- /** \par N
- * Set global option for 'no_daemon' mode. opt_no_daemon */
- opt_no_daemon = 1;
- break;
+ case 'O':
+ /** \par O
+ * Set global option. opt_command_lin and WIN32_Command_Line */
+ opt_command_line = 1;
+ WIN32_Command_Line = xstrdup(optValue);
+ break;
+#endif
+
+ case 'R':
+ /** \par R
+ * Unset/disable global option opt_reuseaddr */
+ opt_reuseaddr = 0;
+ break;
+
+ case 'S':
+ /** \par S
+ * Set global option opt_store_doublecheck */
+ opt_store_doublecheck = 1;
+ break;
+
+ case 'X':
+ /** \par X
+ * Force full debugging */
+ Debug::parseOptions("rotate=0 ALL,9");
+ Debug::override_X = 1;
+ sigusr2_handle(SIGUSR2);
+ break;
+
+ case 'Y':
+ /** \par Y
+ * Set global option opt_reload_hit_only */
+ opt_reload_hit_only = 1;
+ break;
#if USE_WIN32_SERVICE
- case 'O':
- /** \par O
- * Set global option. opt_command_lin and WIN32_Command_Line */
- opt_command_line = 1;
- WIN32_Command_Line = xstrdup(optarg);
- break;
-#endif
-
- case 'R':
- /** \par R
- * Unset/disable global option opt_reuseaddr */
- opt_reuseaddr = 0;
- break;
-
- case 'S':
- /** \par S
- * Set global option opt_store_doublecheck */
- opt_store_doublecheck = 1;
- break;
-
- case 'X':
- /** \par X
- * Force full debugging */
- Debug::parseOptions("rotate=0 ALL,9");
- Debug::override_X = 1;
- sigusr2_handle(SIGUSR2);
- break;
-
- case 'Y':
- /** \par Y
- * Set global option opt_reload_hit_only */
- opt_reload_hit_only = 1;
- break;
+ case 'i':
+ /** \par i
+ * Set global option opt_install_service (to TRUE) */
+ opt_install_service = TRUE;
+ break;
+#endif
-#if USE_WIN32_SERVICE
+ case 'a':
+ {
+ /** \par a
+ * Add optional HTTP port as given following the option */
+ char *port = xstrdup(optValue);
+ // use a copy to avoid optValue modification
+ add_http_port(port);
+ xfree(port);
+ break;
+ }
- case 'i':
- /** \par i
- * Set global option opt_install_service (to TRUE) */
- opt_install_service = TRUE;
- break;
-#endif
-
- case 'a':
- /** \par a
- * Add optional HTTP port as given following the option */
- add_http_port(optarg);
- break;
-
- case 'd':
- /** \par d
- * Set global option Debug::log_stderr to the number given following the option */
- Debug::log_stderr = atoi(optarg);
- break;
-
- case 'f':
- /** \par f
- * Load the file given instead of the default squid.conf. */
- xfree(ConfigFile);
- ConfigFile = xstrdup(optarg);
- break;
-
- case 'k':
- /** \par k
- * Run the administrative action given following the option */
-
- /** \li When it is missing or an unknown option display the usage help. */
- if (!optarg || strlen(optarg) < 1)
- usage();
-
- else if (!strncmp(optarg, "reconfigure", strlen(optarg)))
- /** \li On reconfigure send SIGHUP. */
- opt_send_signal = SIGHUP;
- else if (!strncmp(optarg, "rotate", strlen(optarg)))
- /** \li On rotate send SIGQUIT or SIGUSR1. */
+ case 'd':
+ /** \par d
+ * Set global option Debug::log_stderr to the number given following the option */
+ Debug::log_stderr = xatoi(optValue);
+ break;
+
+ case 'f':
+ /** \par f
+ * Load the file given instead of the default squid.conf. */
+ xfree(ConfigFile);
+ ConfigFile = xstrdup(optValue);
+ break;
+
+ case 'k':
+ /** \par k
+ * Run the administrative action given following the option */
+
+ /** \li When it is missing or an unknown option display the usage help. */
+ if (!optValue || strlen(optValue) < 1)
+ usage();
+
+ else if (!strncmp(optValue, "reconfigure", strlen(optValue)))
+ /** \li On reconfigure send SIGHUP. */
+ opt_send_signal = SIGHUP;
+ else if (!strncmp(optValue, "rotate", strlen(optValue)))
+ /** \li On rotate send SIGQUIT or SIGUSR1. */
#if defined(_SQUID_LINUX_THREADS_)
- opt_send_signal = SIGQUIT;
+ opt_send_signal = SIGQUIT;
#else
- opt_send_signal = SIGUSR1;
+ opt_send_signal = SIGUSR1;
#endif
- else if (!strncmp(optarg, "debug", strlen(optarg)))
- /** \li On debug send SIGTRAP or SIGUSR2. */
+ else if (!strncmp(optValue, "debug", strlen(optValue)))
+ /** \li On debug send SIGTRAP or SIGUSR2. */
#if defined(_SQUID_LINUX_THREADS_)
- opt_send_signal = SIGTRAP;
+ opt_send_signal = SIGTRAP;
#else
- opt_send_signal = SIGUSR2;
+ opt_send_signal = SIGUSR2;
#endif
- else if (!strncmp(optarg, "shutdown", strlen(optarg)))
- /** \li On shutdown send SIGTERM. */
- opt_send_signal = SIGTERM;
- else if (!strncmp(optarg, "interrupt", strlen(optarg)))
- /** \li On interrupt send SIGINT. */
- opt_send_signal = SIGINT;
- else if (!strncmp(optarg, "kill", strlen(optarg)))
- /** \li On kill send SIGKILL. */
- opt_send_signal = SIGKILL;
+ else if (!strncmp(optValue, "shutdown", strlen(optValue)))
+ /** \li On shutdown send SIGTERM. */
+ opt_send_signal = SIGTERM;
+ else if (!strncmp(optValue, "interrupt", strlen(optValue)))
+ /** \li On interrupt send SIGINT. */
+ opt_send_signal = SIGINT;
+ else if (!strncmp(optValue, "kill", strlen(optValue)))
+ /** \li On kill send SIGKILL. */
+ opt_send_signal = SIGKILL;
#ifdef SIGTTIN
- else if (!strncmp(optarg, "restart", strlen(optarg)))
- /** \li On restart send SIGTTIN. (exit and restart by parent) */
- opt_send_signal = SIGTTIN;
+ else if (!strncmp(optValue, "restart", strlen(optValue)))
+ /** \li On restart send SIGTTIN. (exit and restart by parent) */
+ opt_send_signal = SIGTTIN;
#endif
- else if (!strncmp(optarg, "check", strlen(optarg)))
- /** \li On check send 0 / SIGNULL. */
- opt_send_signal = 0; /* SIGNULL */
- else if (!strncmp(optarg, "parse", strlen(optarg)))
- /** \li On parse set global flag to re-parse the config file only. */
- opt_parse_cfg_only = 1;
- else
- usage();
+ else if (!strncmp(optValue, "check", strlen(optValue)))
+ /** \li On check send 0 / SIGNULL. */
+ opt_send_signal = 0; /* SIGNULL */
+ else if (!strncmp(optValue, "parse", strlen(optValue)))
+ /** \li On parse set global flag to re-parse the config file only. */
+ opt_parse_cfg_only = 1;
+ else
+ usage();
- break;
+ break;
- case 'm':
- /** \par m
- * Set global malloc_debug_level to the value given following the option.
- * if none is given it toggles the xmalloc_trace option on/off */
- if (optarg) {
+ case 'm':
+ /** \par m
+ * Set global malloc_debug_level to the value given following the option.
+ * if none is given it toggles the xmalloc_trace option on/off */
+ if (optValue) {
#if MALLOC_DBG
- malloc_debug_level = atoi(optarg);
+ malloc_debug_level = xatoi(optValue);
#else
- fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
+ fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
#endif
- }
- break;
-
- case 'n':
- /** \par n
- * Set global option opt_signal_service (to true).
- * Stores the additional parameter given in global service_name */
- if (optarg && *optarg != '\0') {
- const SBuf t(optarg);
- ::Parser::Tokenizer tok(t);
- const CharacterSet chr = CharacterSet::ALPHA+CharacterSet::DIGIT;
- if (!tok.prefix(service_name, chr))
- fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg);
- if (!tok.atEnd())
- fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg);
- if (service_name.length() > 32)
- fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name.length());
- opt_signal_service = true;
- } else {
- fatal("A service name is required for the -n option");
- }
- break;
+ }
+ break;
+
+ case 'n':
+ /** \par n
+ * Set global option opt_signal_service (to true).
+ * Stores the additional parameter given in global service_name */
+ if (optValue && *optValue != '\0') {
+ const SBuf t(optValue);
+ ::Parser::Tokenizer tok(t);
+ const CharacterSet chr = CharacterSet::ALPHA+CharacterSet::DIGIT;
+ if (!tok.prefix(service_name, chr))
+ fatalf("Expected alphanumeric service name for the -n option but got: %s", optValue);
+ if (!tok.atEnd())
+ fatalf("Garbage after alphanumeric service name in the -n option value: %s", optValue);
+ if (service_name.length() > 32)
+ fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name.length());
+ opt_signal_service = true;
+ } else {
+ fatal("A service name is required for the -n option");
+ }
+ break;
#if USE_WIN32_SERVICE
- case 'r':
- /** \par r
- * Set global option opt_remove_service (to TRUE) */
- opt_remove_service = TRUE;
+ case 'r':
+ /** \par r
+ * Set global option opt_remove_service (to TRUE) */
+ opt_remove_service = TRUE;
- break;
+ break;
#endif
- case 'l':
- /** \par l
- * Stores the syslog facility name in global opt_syslog_facility
- * then performs actions for -s option. */
- xfree(opt_syslog_facility); // ignore any previous options sent
- opt_syslog_facility = xstrdup(optarg);
+ case 'l':
+ /** \par l
+ * Stores the syslog facility name in global opt_syslog_facility
+ * then performs actions for -s option. */
+ xfree(opt_syslog_facility); // ignore any previous options sent
+ opt_syslog_facility = xstrdup(optValue);
- case 's':
- /** \par s
- * Initialize the syslog for output */
+ case 's':
+ /** \par s
+ * Initialize the syslog for output */
#if HAVE_SYSLOG
- _db_set_syslog(opt_syslog_facility);
+ _db_set_syslog(opt_syslog_facility);
- break;
+ break;
#else
- fatal("Logging to syslog not available on this platform");
+ fatal("Logging to syslog not available on this platform");
- /* NOTREACHED */
+ /* NOTREACHED */
#endif
- case 'u':
- /** \par u
- * Store the ICP port number given in global option icpPortNumOverride
- * ensuring its a positive number. */
- icpPortNumOverride = atoi(optarg);
+ case 'u':
+ /** \par u
+ * Store the ICP port number given in global option icpPortNumOverride
+ * ensuring its a positive number. */
+ icpPortNumOverride = atoi(optValue);
- if (icpPortNumOverride < 0)
- icpPortNumOverride = 0;
+ if (icpPortNumOverride < 0)
+ icpPortNumOverride = 0;
- break;
+ break;
- case 'v':
- /** \par v
- * Display squid version and build information. Then exit. */
- printf("Squid Cache: Version %s\n" ,version_string);
- printf("Service Name: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(service_name));
- if (strlen(SQUID_BUILD_INFO))
- printf("%s\n",SQUID_BUILD_INFO);
+ case 'v':
+ /** \par v
+ * Display squid version and build information. Then exit. */
+ printf("Squid Cache: Version %s\n",version_string);
+ printf("Service Name: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(service_name));
+ if (strlen(SQUID_BUILD_INFO))
+ printf("%s\n",SQUID_BUILD_INFO);
#if USE_OPENSSL
- printf("\nThis binary uses %s. ", SSLeay_version(SSLEAY_VERSION));
- printf("For legal restrictions on distribution see https://www.openssl.org/source/license.html\n\n");
+ printf("\nThis binary uses %s. ", SSLeay_version(SSLEAY_VERSION));
+ printf("For legal restrictions on distribution see https://www.openssl.org/source/license.html\n\n");
#endif
- printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
+ printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
#if USE_WIN32_SERVICE
- printf("Compiled as Windows System Service.\n");
+ printf("Compiled as Windows System Service.\n");
#endif
- exit(0);
+ exit(EXIT_SUCCESS);
- /* NOTREACHED */
+ /* NOTREACHED */
- case 'z':
- /** \par z
- * Set global option Debug::log_stderr and opt_create_swap_dirs */
- Debug::log_stderr = 1;
- opt_create_swap_dirs = 1;
- break;
+ case 'z':
+ /** \par z
+ * Set global option Debug::log_stderr and opt_create_swap_dirs */
+ Debug::log_stderr = 1;
+ opt_create_swap_dirs = 1;
+ break;
- case 1:
- /** \par --foreground
- * Set global option opt_foreground */
- opt_foreground = 1;
- break;
+ case optForeground:
+ /** \par --foreground
+ * Set global option opt_foreground */
+ opt_foreground = 1;
+ break;
- case 'h':
+ case optKid:
+ // already processed in ConfigureCurrentKid()
+ break;
- case '?':
+ case 'h':
- default:
- /** \par h,?, or unknown
- * \copydoc usage() */
- usage();
+ case '?':
- break;
- }
+ default:
+ /** \par h,?, or unknown
+ * \copydoc usage() */
+ usage();
+ break;
}
}
/// computes name and ID for the current kid process
static void
-ConfigureCurrentKid(const char *processName)
+ConfigureCurrentKid(const CommandLine &cmdLine)
{
- // kids are marked with parenthesis around their process names
- if (processName && processName[0] == '(') {
- if (const char *idStart = strrchr(processName, '-')) {
- KidIdentifier = atoi(idStart + 1);
- const size_t nameLen = idStart - (processName + 1);
- assert(nameLen < sizeof(TheKidName));
- xstrncpy(TheKidName, processName + 1, nameLen + 1);
- if (!strcmp(TheKidName, "squid-coord"))
- TheProcessKind = pkCoordinator;
- else if (!strcmp(TheKidName, "squid"))
- TheProcessKind = pkWorker;
- else if (!strcmp(TheKidName, "squid-disk"))
- TheProcessKind = pkDisker;
- else
- TheProcessKind = pkOther; // including coordinator
- }
+ const char *kidParams = nullptr;
+ if (cmdLine.hasOption(optKid, &kidParams)) {
+ SBuf processName(kidParams);
+ SBuf kidId;
+ Parser::Tokenizer tok(processName);
+ tok.suffix(kidId, CharacterSet::DIGIT);
+ KidIdentifier = xatoi(kidId.c_str());
+ tok.skipSuffix(SBuf("-"));
+ TheKidName = tok.remaining();
+ if (TheKidName.cmp("squid-coord") == 0)
+ TheProcessKind = pkCoordinator;
+ else if (TheKidName.cmp("squid") == 0)
+ TheProcessKind = pkWorker;
+ else if (TheKidName.cmp("squid-disk") == 0)
+ TheProcessKind = pkDisker;
+ else
+ TheProcessKind = pkOther; // including coordinator
} else {
- xstrncpy(TheKidName, APP_SHORTNAME, sizeof(TheKidName));
+ TheKidName.assign(APP_SHORTNAME);
KidIdentifier = 0;
}
}
int
SquidMain(int argc, char **argv)
{
- ConfigureCurrentKid(argv[0]);
+ const CommandLine cmdLine(argc, argv, shortOpStr, squidOptions);
+
+ ConfigureCurrentKid(cmdLine);
Debug::parseOptions(NULL);
#endif
- mainParseOptions(argc, argv);
+ cmdLine.forEachOption(mainHandleCommandLineOption);
if (opt_foreground && opt_no_daemon) {
debugs(1, DBG_CRITICAL, "WARNING: --foreground command-line option has no effect with -N.");
if (IamMasterProcess()) {
if (InDaemonMode()) {
- watch_child(argv);
+ watch_child(cmdLine);
// NOTREACHED
} else {
Instance::WriteOurPid();
#endif /* !_SQUID_WINDOWS_ */
static void
-watch_child(char *argv[])
+watch_child(const CommandLine &masterCommand)
{
#if !_SQUID_WINDOWS_
- char *prog;
pid_t pid;
#ifdef TIOCNOTTY
continue;
if (!mainStartScriptCalled) {
- mainStartScript(argv[0]);
+ mainStartScript(masterCommand.arg0());
mainStartScriptCalled = true;
}
+ // These are only needed by the forked child below, but let's keep
+ // them out of that "no man's land" between fork() and execvp().
+ auto kidCommand = masterCommand;
+ kidCommand.resetArg0(kid.processName().c_str());
+ assert(!kidCommand.hasOption(optKid));
+ kidCommand.pushFrontOption("--kid", kid.gist().c_str());
+
if ((pid = fork()) == 0) {
/* child */
openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
- prog = argv[0];
- argv[0] = const_cast<char*>(kid.name().termedBuf());
- execvp(prog, argv);
+ (void)execvp(masterCommand.arg0(), kidCommand.argv());
int xerrno = errno;
syslog(LOG_ALERT, "execvp failed: %s", xstrerr(xerrno));
}
kid.start(pid);
syslog(LOG_NOTICE, "Squid Parent: %s process %d started",
- kid.name().termedBuf(), pid);
+ kid.processName().c_str(), pid);
}
/* parent */