Your IP : 18.191.178.145
/*
* Phusion Passenger - https://www.phusionpassenger.com/
* Copyright (c) 2010-2018 Phusion Holding B.V.
*
* "Passenger", "Phusion Passenger" and "Union Station" are registered
* trademarks of Phusion Holding B.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _PASSENGER_CORE_OPTION_PARSER_H_
#define _PASSENGER_CORE_OPTION_PARSER_H_
#include <boost/thread.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <Constants.h>
#include <JsonTools/Autocast.h>
#include <Utils.h>
#include <Utils/OptionParsing.h>
#include <StrIntTools/StrIntUtils.h>
#include <jsoncpp/json.h>
namespace Passenger {
using namespace std;
inline void
coreUsage() {
// ....|---------------Keep output within standard terminal width (80 chars)------------|
printf("Usage: " AGENT_EXE " core <OPTIONS...> [APP DIRECTORY]\n");
printf("Runs the " PROGRAM_NAME " core.\n");
printf("\n");
printf("The core starts in single-app mode, unless --multi-app is specified. When\n");
printf("in single-app mode, it serves the app at the current working directory, or the\n");
printf("app specified by APP DIRECTORY.\n");
printf("\n");
printf("Required options:\n");
printf(" --passenger-root PATH The location to the " PROGRAM_NAME " source\n");
printf(" directory\n");
printf("\n");
printf("Socket options (optional):\n");
printf(" -l, --listen ADDRESS Listen on the given address. The address must be\n");
printf(" formatted as tcp://IP:PORT for TCP sockets, or\n");
printf(" unix:PATH for Unix domain sockets. You can specify\n");
printf(" this option multiple times (up to %u times) to\n",
SERVER_KIT_MAX_SERVER_ENDPOINTS);
printf(" listen on multiple addresses. Default:\n");
printf(" " DEFAULT_HTTP_SERVER_LISTEN_ADDRESS "\n");
printf(" --api-listen ADDRESS Listen on the given address for API commands.\n");
printf(" The same syntax and limitations as with --listen\n");
printf(" are applicable\n");
printf(" --socket-backlog Override size of the socket backlog.\n");
printf(" Default: %d\n", DEFAULT_SOCKET_BACKLOG);
printf("\n");
printf("Daemon options (optional):\n");
printf(" --pid-file PATH Store the core's PID in the given file. The file\n");
printf(" is deleted on exit\n");
printf("\n");
printf("Security options (optional):\n");
printf(" --multi-app-password-file PATH\n");
printf(" Password-protect access to the core's HTTP server\n");
printf(" (multi-app mode only)\n");
printf(" --authorize [LEVEL]:USERNAME:PASSWORDFILE\n");
printf(" Enables authentication on the API server, through\n");
printf(" the given API account. LEVEL indicates the\n");
printf(" privilege level (see below). PASSWORDFILE must\n");
printf(" point to a file containing the password\n");
printf(" --no-user-switching Disables user switching support\n");
printf(" --default-user NAME Default user to start apps as, when user\n");
printf(" switching is enabled. Default: " DEFAULT_WEB_APP_USER "\n");
printf(" --default-group NAME Default group to start apps as, when user\n");
printf(" switching is disabled. Default: the default\n");
printf(" user's primary group\n");
printf(" --disable-security-update-check\n");
printf(" Disable the periodic check and notice about\n");
printf(" important security updates\n");
printf(" --security-update-check-proxy PROXY\n");
printf(" Use HTTP/SOCKS proxy for the security update check:\n");
printf(" scheme://user:password@proxy_host:proxy_port\n");
printf(" --disable-anonymous-telemetry\n");
printf(" Disable anonymous telemetry collection\n");
printf(" --anonymous-telemetry-proxy PROXY\n");
printf(" Use HTTP/SOCKS proxy for anonymous telemetry sending:\n");
printf(" scheme://user:password@proxy_host:proxy_port\n");
printf("\n");
printf("Application serving options (optional):\n");
printf(" -e, --environment NAME Default framework environment name to use.\n");
printf(" Default: " DEFAULT_APP_ENV "\n");
printf(" --app-type TYPE The type of application you want to serve\n");
printf(" (single-app mode only)\n");
printf(" --startup-file PATH The path of the app's startup file, relative to\n");
printf(" the app root directory (single-app mode only)\n");
printf(" --app-start-command COMMAND\n");
printf(" The command string with which to start the app\n");
printf(" (single-app mode only)\n");
printf(" --spawn-method NAME Spawn method to use. Can either be 'smart' or\n");
printf(" 'direct'. Default: %s\n", DEFAULT_SPAWN_METHOD);
printf(" --load-shell-envvars Load shell startup files before loading application\n");
printf(" --preload-bundler Tell Ruby to load bundler gem before loading application\n");
printf(" --concurrency-model The concurrency model to use for the app, either\n");
printf(" 'process' or 'thread' (Enterprise only).\n");
printf(" Default: " DEFAULT_CONCURRENCY_MODEL "\n");
printf(" --app-thread-count The number of application threads to use when using\n");
printf(" the 'thread' concurrency model (Enterprise only).\n");
printf(" Default: %d\n", DEFAULT_APP_THREAD_COUNT);
printf("\n");
printf(" --multi-app Enable multi-app mode\n");
printf("\n");
printf(" --force-friendly-error-pages\n");
printf(" Force friendly error pages to be always on\n");
printf(" --disable-friendly-error-pages\n");
printf(" Force friendly error pages to be always off\n");
printf("\n");
printf(" --ruby PATH Default Ruby interpreter to use.\n");
printf(" --nodejs PATH Default NodeJs interpreter to use.\n");
printf(" --python PATH Default Python interpreter to use.\n");
printf(" --meteor-app-settings PATH\n");
printf(" File with settings for a Meteor (non-bundled) app.\n");
printf(" (passed to Meteor using --settings)\n");
printf(" --app-file-descriptor-ulimit NUMBER\n");
printf(" Set custom file descriptor ulimit for the app\n");
printf(" --debugger Enable Ruby debugger support (Enterprise only)\n");
printf("\n");
printf(" --rolling-restarts Enable rolling restarts (Enterprise only)\n");
printf(" --resist-deployment-errors\n");
printf(" Enable deployment error resistance (Enterprise only)\n");
printf("\n");
printf("Process management options (optional):\n");
printf(" --max-pool-size N Maximum number of application processes.\n");
printf(" Default: %d\n", DEFAULT_MAX_POOL_SIZE);
printf(" --pool-idle-time SECS\n");
printf(" Maximum number of seconds an application process\n");
printf(" may be idle. Default: %d\n", DEFAULT_POOL_IDLE_TIME);
printf(" --max-preloader-idle-time SECS\n");
printf(" Maximum time that preloader processes may be\n");
printf(" be idle. A value of 0 means that preloader\n");
printf(" processes never timeout. Default: %d\n", DEFAULT_MAX_PRELOADER_IDLE_TIME);
printf(" --force-max-concurrent-requests-per-process NUMBER\n");
printf(" Force " SHORT_PROGRAM_NAME " to believe that an application\n");
printf(" process can handle the given number of concurrent\n");
printf(" requests per process\n");
printf(" --min-instances N Minimum number of application processes. Default: 1\n");
printf(" --memory-limit MB Restart application processes that go over the\n");
printf(" given memory limit (Enterprise only)\n");
printf("\n");
printf("Request handling options (optional):\n");
printf(" --max-requests Restart application processes that have handled\n");
printf(" the specified maximum number of requests\n");
printf(" --max-request-time Abort requests that take too much time (Enterprise\n");
printf(" only)\n");
printf(" --max-request-queue-size NUMBER\n");
printf(" Specify request queue size. Default: %d\n",
DEFAULT_MAX_REQUEST_QUEUE_SIZE);
printf(" --sticky-sessions Enable sticky sessions\n");
printf(" --sticky-sessions-cookie-name NAME\n");
printf(" Cookie name to use for sticky sessions.\n");
printf(" Default: " DEFAULT_STICKY_SESSIONS_COOKIE_NAME "\n");
printf(" --sticky-sessions-cookie-attributes 'NAME1=VALUE1; NAME2'\n");
printf(" The attributes to use for the sticky session cookie.\n");
printf(" Default: " DEFAULT_STICKY_SESSIONS_COOKIE_ATTRIBUTES "\n");
printf(" --vary-turbocache-by-cookie NAME\n");
printf(" Vary the turbocache by the cookie of the given name\n");
printf(" --disable-turbocaching\n");
printf(" Disable turbocaching\n");
printf(" --no-abort-websockets-on-process-shutdown\n");
printf(" Do not abort WebSocket connections on process\n");
printf(" shutdown or restart\n");
printf("\n");
printf("Other options (optional):\n");
printf(" --log-file PATH Log to the given file.\n");
printf(" --log-level LEVEL Logging level. Default: %d\n", DEFAULT_LOG_LEVEL);
printf(" --fd-log-file PATH Log file descriptor activity to the given file.\n");
printf(" --stat-throttle-rate SECONDS\n");
printf(" Throttle filesystem restart.txt checks to at most\n");
printf(" once per given seconds. Default: %d\n", DEFAULT_STAT_THROTTLE_RATE);
printf(" --no-show-version-in-header\n");
printf(" Do not show " PROGRAM_NAME " version number in\n");
printf(" HTTP headers.\n");
printf(" --data-buffer-dir PATH\n");
printf(" Directory to store data buffers in. Default:\n");
printf(" %s\n", getSystemTempDir());
printf(" --no-graceful-exit When exiting, exit immediately instead of waiting\n");
printf(" for all connections to terminate\n");
printf(" --benchmark MODE Enable benchmark mode. Available modes:\n");
printf(" after_accept,before_checkout,after_checkout,\n");
printf(" response_begin\n");
printf(" --disable-selfchecks Disable various self-checks. This improves\n");
printf(" performance, but might delay finding bugs in\n");
printf(" " PROGRAM_NAME "\n");
printf(" --threads NUMBER Number of threads to use for request handling.\n");
printf(" Default: number of CPU cores (%d)\n",
boost::thread::hardware_concurrency());
printf(" --cpu-affine Enable per-thread CPU affinity (Linux only)\n");
printf(" --core-file-descriptor-ulimit NUMBER\n");
printf(" Set custom file descriptor ulimit for the core\n");
printf(" --admin-panel-url URL\n");
printf(" Connect to an admin panel through this service\n");
printf(" connector URL\n");
printf(" --ctl NAME=VALUE Set low-level config option directly\n");
printf(" -h, --help Show this help\n");
printf("\n");
printf("API account privilege levels (ordered from most to least privileges):\n");
printf(" readonly Read-only access\n");
printf(" full Full access (default)\n");
}
inline bool
parseCoreOption(int argc, const char *argv[], int &i, Json::Value &updates) {
OptionParser p(coreUsage);
if (p.isValueFlag(argc, i, argv[i], '\0', "--passenger-root")) {
updates["passenger_root"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], 'l', "--listen")) {
if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
Json::Value &addresses = updates["controller_addresses"];
if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
fprintf(stderr, "ERROR: you may specify up to %u --listen addresses.\n",
SERVER_KIT_MAX_SERVER_ENDPOINTS);
exit(1);
}
addresses.append(argv[i + 1]);
i += 2;
} else {
fprintf(stderr, "ERROR: invalid address format for --listen. The address "
"must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
"for Unix domain sockets.\n");
exit(1);
}
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--api-listen")) {
if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
Json::Value &addresses = updates["api_server_addresses"];
if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
fprintf(stderr, "ERROR: you may specify up to %u --api-listen addresses.\n",
SERVER_KIT_MAX_SERVER_ENDPOINTS);
exit(1);
}
addresses.append(argv[i + 1]);
i += 2;
} else {
fprintf(stderr, "ERROR: invalid address format for --api-listen. The address "
"must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
"for Unix domain sockets.\n");
exit(1);
}
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--pid-file")) {
updates["pid_file"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--authorize")) {
vector<string> args;
split(argv[i + 1], ':', args);
if (args.size() < 2 || args.size() > 3) {
fprintf(stderr, "ERROR: invalid format for --authorize. The syntax "
"is \"[LEVEL:]USERNAME:PASSWORDFILE\".\n");
exit(1);
}
updates["api_server_authorizations"].append(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--socket-backlog")) {
updates["controller_socket_backlog"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--no-user-switching")) {
updates["user_switching"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-user")) {
updates["default_user"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-group")) {
updates["default_group"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--disable-security-update-check")) {
updates["security_update_checker_disabled"] = true;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--security-update-check-proxy")) {
updates["security_update_checker_proxy_url"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--disable-anonymous-telemetry")) {
updates["telemetry_collector_disabled"] = true;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--anonymous-telemetry-proxy")) {
updates["telemetry_collector_proxy_url"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-pool-size")) {
updates["max_pool_size"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--pool-idle-time")) {
updates["pool_idle_time"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-preloader-idle-time")) {
updates["default_max_preloader_idle_time"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--force-max-concurrent-requests-per-process")) {
updates["default_force_max_concurrent_requests_per_process"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--min-instances")) {
updates["default_min_instances"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], 'e', "--environment")) {
updates["default_environment"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-type")) {
updates["single_app_mode_app_type"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--startup-file")) {
updates["single_app_mode_startup_file"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-start-command")) {
updates["single_app_mode_app_start_command"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--spawn-method")) {
updates["default_spawn_method"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--load-shell-envvars")) {
updates["default_load_shell_envvars"] = true;
i++;
} else if (p.isFlag(argv[i], '\0', "--preload-bundler")) {
updates["default_preload_bundler"] = true;
i++;
} else if (p.isFlag(argv[i], '\0', "--multi-app")) {
updates["multi_app"] = true;
i++;
} else if (p.isFlag(argv[i], '\0', "--custom-error-page")) {
updates["custom_error_page"] = argv[i + 1];
i+=2;
} else if (p.isFlag(argv[i], '\0', "--force-friendly-error-pages")) {
updates["default_friendly_error_pages"] = true;
i++;
} else if (p.isFlag(argv[i], '\0', "--disable-friendly-error-pages")) {
updates["default_friendly_error_pages"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-requests")) {
updates["default_max_requests"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-request-queue-size")) {
updates["default_max_request_queue_size"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isFlag(argv[i], '\0', "--sticky-sessions")) {
updates["default_sticky_sessions"] = true;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--sticky-sessions-cookie-name")) {
updates["default_sticky_sessions_cookie_name"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--vary-turbocache-by-cookie")) {
updates["vary_turbocache_by_cookie"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--disable-turbocaching")) {
updates["turbocaching"] = false;
i++;
} else if (p.isFlag(argv[i], '\0', "--no-abort-websockets-on-process-shutdown")) {
updates["default_abort_websockets_on_process_shutdown"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--ruby")) {
updates["default_ruby"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--nodejs")) {
updates["default_nodejs"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--python")) {
updates["default_python"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--meteor-app-settings")) {
updates["default_meteor_app_settings"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-file-descriptor-ulimit")) {
updates["default_app_file_descriptor_ulimit"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
updates["log_level"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-file")) {
updates["log_target"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--fd-log-file")) {
updates["file_descriptor_log_target"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--stat-throttle-rate")) {
updates["stat_throttle_rate"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isFlag(argv[i], '\0', "--no-show-version-in-header")) {
updates["show_version_in_header"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--data-buffer-dir")) {
updates["controller_file_buffered_channel_buffer_dir"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isFlag(argv[i], '\0', "--no-graceful-exit")) {
updates["graceful_exit"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--benchmark")) {
updates["benchmark_mode"] = argv[i + 1];
i += 2;
} else if (p.isFlag(argv[i], '\0', "--disable-selfchecks")) {
updates["pool_selfchecks"] = false;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--threads")) {
updates["controller_threads"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isFlag(argv[i], '\0', "--cpu-affine")) {
updates["controller_cpu_affine"] = true;
i++;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--core-file-descriptor-ulimit")) {
updates["file_descriptor_ulimit"] = atoi(argv[i + 1]);
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--admin-panel-url")) {
updates["admin_panel_url"] = argv[i + 1];
i += 2;
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--ctl")) {
const char *sep = strchr(argv[i + 1], '=');
if (sep == NULL) {
fprintf(stderr, "ERROR: invalid --ctl format: %s\n", argv[i + 1]);
exit(1);
}
string name(argv[i + 1], sep - argv[i + 1]);
string value(sep + 1);
updates[name] = autocastValueToJson(value);
i += 2;
} else if (!startsWith(argv[i], "-")) {
if (!updates.isMember("single_app_mode_app_root")) {
updates["single_app_mode_app_root"] = argv[i];
i++;
} else {
fprintf(stderr, "ERROR: you may not pass multiple application directories. "
"Please type '%s core --help' for usage.\n", argv[0]);
exit(1);
}
} else {
return false;
}
return true;
}
} // namespace Passenger
#endif /* _PASSENGER_CORE_OPTION_PARSER_H_ */