PageRenderTime 122ms CodeModel.GetById 32ms RepoModel.GetById 8ms app.codeStats 0ms

/src/agent/Core/OptionParser.h

http://github.com/FooBarWidget/passenger
C Header | 444 lines | 406 code | 12 blank | 26 comment | 124 complexity | 52b632ac70d0e49ee15cf1c464899c60 MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause, ISC
  1. /*
  2. * Phusion Passenger - https://www.phusionpassenger.com/
  3. * Copyright (c) 2010-2018 Phusion Holding B.V.
  4. *
  5. * "Passenger", "Phusion Passenger" and "Union Station" are registered
  6. * trademarks of Phusion Holding B.V.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #ifndef _PASSENGER_CORE_OPTION_PARSER_H_
  27. #define _PASSENGER_CORE_OPTION_PARSER_H_
  28. #include <boost/thread.hpp>
  29. #include <cstdio>
  30. #include <cstdlib>
  31. #include <cstring>
  32. #include <Constants.h>
  33. #include <JsonTools/Autocast.h>
  34. #include <Utils.h>
  35. #include <Utils/OptionParsing.h>
  36. #include <StrIntTools/StrIntUtils.h>
  37. #include <jsoncpp/json.h>
  38. namespace Passenger {
  39. using namespace std;
  40. inline void
  41. coreUsage() {
  42. // ....|---------------Keep output within standard terminal width (80 chars)------------|
  43. printf("Usage: " AGENT_EXE " core <OPTIONS...> [APP DIRECTORY]\n");
  44. printf("Runs the " PROGRAM_NAME " core.\n");
  45. printf("\n");
  46. printf("The core starts in single-app mode, unless --multi-app is specified. When\n");
  47. printf("in single-app mode, it serves the app at the current working directory, or the\n");
  48. printf("app specified by APP DIRECTORY.\n");
  49. printf("\n");
  50. printf("Required options:\n");
  51. printf(" --passenger-root PATH The location to the " PROGRAM_NAME " source\n");
  52. printf(" directory\n");
  53. printf("\n");
  54. printf("Socket options (optional):\n");
  55. printf(" -l, --listen ADDRESS Listen on the given address. The address must be\n");
  56. printf(" formatted as tcp://IP:PORT for TCP sockets, or\n");
  57. printf(" unix:PATH for Unix domain sockets. You can specify\n");
  58. printf(" this option multiple times (up to %u times) to\n",
  59. SERVER_KIT_MAX_SERVER_ENDPOINTS);
  60. printf(" listen on multiple addresses. Default:\n");
  61. printf(" " DEFAULT_HTTP_SERVER_LISTEN_ADDRESS "\n");
  62. printf(" --api-listen ADDRESS Listen on the given address for API commands.\n");
  63. printf(" The same syntax and limitations as with --listen\n");
  64. printf(" are applicable\n");
  65. printf(" --socket-backlog Override size of the socket backlog.\n");
  66. printf(" Default: %d\n", DEFAULT_SOCKET_BACKLOG);
  67. printf("\n");
  68. printf("Daemon options (optional):\n");
  69. printf(" --pid-file PATH Store the core's PID in the given file. The file\n");
  70. printf(" is deleted on exit\n");
  71. printf("\n");
  72. printf("Security options (optional):\n");
  73. printf(" --multi-app-password-file PATH\n");
  74. printf(" Password-protect access to the core's HTTP server\n");
  75. printf(" (multi-app mode only)\n");
  76. printf(" --authorize [LEVEL]:USERNAME:PASSWORDFILE\n");
  77. printf(" Enables authentication on the API server, through\n");
  78. printf(" the given API account. LEVEL indicates the\n");
  79. printf(" privilege level (see below). PASSWORDFILE must\n");
  80. printf(" point to a file containing the password\n");
  81. printf(" --no-user-switching Disables user switching support\n");
  82. printf(" --default-user NAME Default user to start apps as, when user\n");
  83. printf(" switching is enabled. Default: " DEFAULT_WEB_APP_USER "\n");
  84. printf(" --default-group NAME Default group to start apps as, when user\n");
  85. printf(" switching is disabled. Default: the default\n");
  86. printf(" user's primary group\n");
  87. printf(" --disable-security-update-check\n");
  88. printf(" Disable the periodic check and notice about\n");
  89. printf(" important security updates\n");
  90. printf(" --security-update-check-proxy PROXY\n");
  91. printf(" Use HTTP/SOCKS proxy for the security update check:\n");
  92. printf(" scheme://user:password@proxy_host:proxy_port\n");
  93. printf(" --disable-anonymous-telemetry\n");
  94. printf(" Disable anonymous telemetry collection\n");
  95. printf(" --anonymous-telemetry-proxy PROXY\n");
  96. printf(" Use HTTP/SOCKS proxy for anonymous telemetry sending:\n");
  97. printf(" scheme://user:password@proxy_host:proxy_port\n");
  98. printf("\n");
  99. printf("Application serving options (optional):\n");
  100. printf(" -e, --environment NAME Default framework environment name to use.\n");
  101. printf(" Default: " DEFAULT_APP_ENV "\n");
  102. printf(" --app-type TYPE The type of application you want to serve\n");
  103. printf(" (single-app mode only)\n");
  104. printf(" --startup-file PATH The path of the app's startup file, relative to\n");
  105. printf(" the app root directory (single-app mode only)\n");
  106. printf(" --app-start-command COMMAND\n");
  107. printf(" The command string with which to start the app\n");
  108. printf(" (single-app mode only)\n");
  109. printf(" --spawn-method NAME Spawn method to use. Can either be 'smart' or\n");
  110. printf(" 'direct'. Default: %s\n", DEFAULT_SPAWN_METHOD);
  111. printf(" --load-shell-envvars Load shell startup files before loading application\n");
  112. printf(" --concurrency-model The concurrency model to use for the app, either\n");
  113. printf(" 'process' or 'thread' (Enterprise only).\n");
  114. printf(" Default: " DEFAULT_CONCURRENCY_MODEL "\n");
  115. printf(" --app-thread-count The number of application threads to use when using\n");
  116. printf(" the 'thread' concurrency model (Enterprise only).\n");
  117. printf(" Default: %d\n", DEFAULT_APP_THREAD_COUNT);
  118. printf("\n");
  119. printf(" --multi-app Enable multi-app mode\n");
  120. printf("\n");
  121. printf(" --force-friendly-error-pages\n");
  122. printf(" Force friendly error pages to be always on\n");
  123. printf(" --disable-friendly-error-pages\n");
  124. printf(" Force friendly error pages to be always off\n");
  125. printf("\n");
  126. printf(" --ruby PATH Default Ruby interpreter to use.\n");
  127. printf(" --nodejs PATH Default NodeJs interpreter to use.\n");
  128. printf(" --python PATH Default Python interpreter to use.\n");
  129. printf(" --meteor-app-settings PATH\n");
  130. printf(" File with settings for a Meteor (non-bundled) app.\n");
  131. printf(" (passed to Meteor using --settings)\n");
  132. printf(" --app-file-descriptor-ulimit NUMBER\n");
  133. printf(" Set custom file descriptor ulimit for the app\n");
  134. printf(" --debugger Enable Ruby debugger support (Enterprise only)\n");
  135. printf("\n");
  136. printf(" --rolling-restarts Enable rolling restarts (Enterprise only)\n");
  137. printf(" --resist-deployment-errors\n");
  138. printf(" Enable deployment error resistance (Enterprise only)\n");
  139. printf("\n");
  140. printf("Process management options (optional):\n");
  141. printf(" --max-pool-size N Maximum number of application processes.\n");
  142. printf(" Default: %d\n", DEFAULT_MAX_POOL_SIZE);
  143. printf(" --pool-idle-time SECS\n");
  144. printf(" Maximum number of seconds an application process\n");
  145. printf(" may be idle. Default: %d\n", DEFAULT_POOL_IDLE_TIME);
  146. printf(" --max-preloader-idle-time SECS\n");
  147. printf(" Maximum time that preloader processes may be\n");
  148. printf(" be idle. A value of 0 means that preloader\n");
  149. printf(" processes never timeout. Default: %d\n", DEFAULT_MAX_PRELOADER_IDLE_TIME);
  150. printf(" --force-max-concurrent-requests-per-process NUMBER\n");
  151. printf(" Force " SHORT_PROGRAM_NAME " to believe that an application\n");
  152. printf(" process can handle the given number of concurrent\n");
  153. printf(" requests per process\n");
  154. printf(" --min-instances N Minimum number of application processes. Default: 1\n");
  155. printf(" --memory-limit MB Restart application processes that go over the\n");
  156. printf(" given memory limit (Enterprise only)\n");
  157. printf("\n");
  158. printf("Request handling options (optional):\n");
  159. printf(" --max-requests Restart application processes that have handled\n");
  160. printf(" the specified maximum number of requests\n");
  161. printf(" --max-request-time Abort requests that take too much time (Enterprise\n");
  162. printf(" only)\n");
  163. printf(" --max-request-queue-size NUMBER\n");
  164. printf(" Specify request queue size. Default: %d\n",
  165. DEFAULT_MAX_REQUEST_QUEUE_SIZE);
  166. printf(" --sticky-sessions Enable sticky sessions\n");
  167. printf(" --sticky-sessions-cookie-name NAME\n");
  168. printf(" Cookie name to use for sticky sessions.\n");
  169. printf(" Default: " DEFAULT_STICKY_SESSIONS_COOKIE_NAME "\n");
  170. printf(" --vary-turbocache-by-cookie NAME\n");
  171. printf(" Vary the turbocache by the cookie of the given name\n");
  172. printf(" --disable-turbocaching\n");
  173. printf(" Disable turbocaching\n");
  174. printf(" --no-abort-websockets-on-process-shutdown\n");
  175. printf(" Do not abort WebSocket connections on process\n");
  176. printf(" shutdown or restart\n");
  177. printf("\n");
  178. printf("Other options (optional):\n");
  179. printf(" --log-file PATH Log to the given file.\n");
  180. printf(" --log-level LEVEL Logging level. Default: %d\n", DEFAULT_LOG_LEVEL);
  181. printf(" --fd-log-file PATH Log file descriptor activity to the given file.\n");
  182. printf(" --stat-throttle-rate SECONDS\n");
  183. printf(" Throttle filesystem restart.txt checks to at most\n");
  184. printf(" once per given seconds. Default: %d\n", DEFAULT_STAT_THROTTLE_RATE);
  185. printf(" --no-show-version-in-header\n");
  186. printf(" Do not show " PROGRAM_NAME " version number in\n");
  187. printf(" HTTP headers.\n");
  188. printf(" --data-buffer-dir PATH\n");
  189. printf(" Directory to store data buffers in. Default:\n");
  190. printf(" %s\n", getSystemTempDir());
  191. printf(" --no-graceful-exit When exiting, exit immediately instead of waiting\n");
  192. printf(" for all connections to terminate\n");
  193. printf(" --benchmark MODE Enable benchmark mode. Available modes:\n");
  194. printf(" after_accept,before_checkout,after_checkout,\n");
  195. printf(" response_begin\n");
  196. printf(" --disable-selfchecks Disable various self-checks. This improves\n");
  197. printf(" performance, but might delay finding bugs in\n");
  198. printf(" " PROGRAM_NAME "\n");
  199. printf(" --threads NUMBER Number of threads to use for request handling.\n");
  200. printf(" Default: number of CPU cores (%d)\n",
  201. boost::thread::hardware_concurrency());
  202. printf(" --cpu-affine Enable per-thread CPU affinity (Linux only)\n");
  203. printf(" --core-file-descriptor-ulimit NUMBER\n");
  204. printf(" Set custom file descriptor ulimit for the core\n");
  205. printf(" --admin-panel-url URL\n");
  206. printf(" Connect to an admin panel through this service\n");
  207. printf(" connector URL\n");
  208. printf(" --ctl NAME=VALUE Set low-level config option directly\n");
  209. printf(" -h, --help Show this help\n");
  210. printf("\n");
  211. printf("API account privilege levels (ordered from most to least privileges):\n");
  212. printf(" readonly Read-only access\n");
  213. printf(" full Full access (default)\n");
  214. }
  215. inline bool
  216. parseCoreOption(int argc, const char *argv[], int &i, Json::Value &updates) {
  217. OptionParser p(coreUsage);
  218. if (p.isValueFlag(argc, i, argv[i], '\0', "--passenger-root")) {
  219. updates["passenger_root"] = argv[i + 1];
  220. i += 2;
  221. } else if (p.isValueFlag(argc, i, argv[i], 'l', "--listen")) {
  222. if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
  223. Json::Value &addresses = updates["controller_addresses"];
  224. if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
  225. fprintf(stderr, "ERROR: you may specify up to %u --listen addresses.\n",
  226. SERVER_KIT_MAX_SERVER_ENDPOINTS);
  227. exit(1);
  228. }
  229. addresses.append(argv[i + 1]);
  230. i += 2;
  231. } else {
  232. fprintf(stderr, "ERROR: invalid address format for --listen. The address "
  233. "must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
  234. "for Unix domain sockets.\n");
  235. exit(1);
  236. }
  237. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--api-listen")) {
  238. if (getSocketAddressType(argv[i + 1]) != SAT_UNKNOWN) {
  239. Json::Value &addresses = updates["api_server_addresses"];
  240. if (addresses.size() == SERVER_KIT_MAX_SERVER_ENDPOINTS) {
  241. fprintf(stderr, "ERROR: you may specify up to %u --api-listen addresses.\n",
  242. SERVER_KIT_MAX_SERVER_ENDPOINTS);
  243. exit(1);
  244. }
  245. addresses.append(argv[i + 1]);
  246. i += 2;
  247. } else {
  248. fprintf(stderr, "ERROR: invalid address format for --api-listen. The address "
  249. "must be formatted as tcp://IP:PORT for TCP sockets, or unix:PATH "
  250. "for Unix domain sockets.\n");
  251. exit(1);
  252. }
  253. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--pid-file")) {
  254. updates["pid_file"] = argv[i + 1];
  255. i += 2;
  256. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--authorize")) {
  257. vector<string> args;
  258. split(argv[i + 1], ':', args);
  259. if (args.size() < 2 || args.size() > 3) {
  260. fprintf(stderr, "ERROR: invalid format for --authorize. The syntax "
  261. "is \"[LEVEL:]USERNAME:PASSWORDFILE\".\n");
  262. exit(1);
  263. }
  264. updates["api_server_authorizations"].append(argv[i + 1]);
  265. i += 2;
  266. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--socket-backlog")) {
  267. updates["controller_socket_backlog"] = argv[i + 1];
  268. i += 2;
  269. } else if (p.isFlag(argv[i], '\0', "--no-user-switching")) {
  270. updates["user_switching"] = false;
  271. i++;
  272. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-user")) {
  273. updates["default_user"] = argv[i + 1];
  274. i += 2;
  275. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--default-group")) {
  276. updates["default_group"] = argv[i + 1];
  277. i += 2;
  278. } else if (p.isFlag(argv[i], '\0', "--disable-security-update-check")) {
  279. updates["security_update_checker_disabled"] = true;
  280. i++;
  281. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--security-update-check-proxy")) {
  282. updates["security_update_checker_proxy_url"] = argv[i + 1];
  283. i += 2;
  284. } else if (p.isFlag(argv[i], '\0', "--disable-anonymous-telemetry")) {
  285. updates["telemetry_collector_disabled"] = true;
  286. i++;
  287. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--anonymous-telemetry-proxy")) {
  288. updates["telemetry_collector_proxy_url"] = argv[i + 1];
  289. i += 2;
  290. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-pool-size")) {
  291. updates["max_pool_size"] = atoi(argv[i + 1]);
  292. i += 2;
  293. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--pool-idle-time")) {
  294. updates["pool_idle_time"] = atoi(argv[i + 1]);
  295. i += 2;
  296. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-preloader-idle-time")) {
  297. updates["default_max_preloader_idle_time"] = atoi(argv[i + 1]);
  298. i += 2;
  299. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--force-max-concurrent-requests-per-process")) {
  300. updates["default_force_max_concurrent_requests_per_process"] = atoi(argv[i + 1]);
  301. i += 2;
  302. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--min-instances")) {
  303. updates["default_min_instances"] = atoi(argv[i + 1]);
  304. i += 2;
  305. } else if (p.isValueFlag(argc, i, argv[i], 'e', "--environment")) {
  306. updates["default_environment"] = argv[i + 1];
  307. i += 2;
  308. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-type")) {
  309. updates["single_app_mode_app_type"] = argv[i + 1];
  310. i += 2;
  311. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--startup-file")) {
  312. updates["single_app_mode_startup_file"] = argv[i + 1];
  313. i += 2;
  314. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-start-command")) {
  315. updates["single_app_mode_app_start_command"] = argv[i + 1];
  316. i += 2;
  317. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--spawn-method")) {
  318. updates["default_spawn_method"] = argv[i + 1];
  319. i += 2;
  320. } else if (p.isFlag(argv[i], '\0', "--load-shell-envvars")) {
  321. updates["default_load_shell_envvars"] = true;
  322. i++;
  323. } else if (p.isFlag(argv[i], '\0', "--multi-app")) {
  324. updates["multi_app"] = true;
  325. i++;
  326. } else if (p.isFlag(argv[i], '\0', "--force-friendly-error-pages")) {
  327. updates["default_friendly_error_pages"] = true;
  328. i++;
  329. } else if (p.isFlag(argv[i], '\0', "--disable-friendly-error-pages")) {
  330. updates["default_friendly_error_pages"] = false;
  331. i++;
  332. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-requests")) {
  333. updates["default_max_requests"] = atoi(argv[i + 1]);
  334. i += 2;
  335. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--max-request-queue-size")) {
  336. updates["default_max_request_queue_size"] = atoi(argv[i + 1]);
  337. i += 2;
  338. } else if (p.isFlag(argv[i], '\0', "--sticky-sessions")) {
  339. updates["default_sticky_sessions"] = true;
  340. i++;
  341. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--sticky-sessions-cookie-name")) {
  342. updates["default_sticky_sessions_cookie_name"] = argv[i + 1];
  343. i += 2;
  344. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--vary-turbocache-by-cookie")) {
  345. updates["vary_turbocache_by_cookie"] = argv[i + 1];
  346. i += 2;
  347. } else if (p.isFlag(argv[i], '\0', "--disable-turbocaching")) {
  348. updates["turbocaching"] = false;
  349. i++;
  350. } else if (p.isFlag(argv[i], '\0', "--no-abort-websockets-on-process-shutdown")) {
  351. updates["default_abort_websockets_on_process_shutdown"] = false;
  352. i++;
  353. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--ruby")) {
  354. updates["default_ruby"] = argv[i + 1];
  355. i += 2;
  356. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--nodejs")) {
  357. updates["default_nodejs"] = argv[i + 1];
  358. i += 2;
  359. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--python")) {
  360. updates["default_python"] = argv[i + 1];
  361. i += 2;
  362. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--meteor-app-settings")) {
  363. updates["default_meteor_app_settings"] = argv[i + 1];
  364. i += 2;
  365. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--app-file-descriptor-ulimit")) {
  366. updates["default_app_file_descriptor_ulimit"] = atoi(argv[i + 1]);
  367. i += 2;
  368. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-level")) {
  369. updates["log_level"] = atoi(argv[i + 1]);
  370. i += 2;
  371. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--log-file")) {
  372. updates["log_target"] = argv[i + 1];
  373. i += 2;
  374. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--fd-log-file")) {
  375. updates["file_descriptor_log_target"] = argv[i + 1];
  376. i += 2;
  377. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--stat-throttle-rate")) {
  378. updates["stat_throttle_rate"] = atoi(argv[i + 1]);
  379. i += 2;
  380. } else if (p.isFlag(argv[i], '\0', "--no-show-version-in-header")) {
  381. updates["show_version_in_header"] = false;
  382. i++;
  383. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--data-buffer-dir")) {
  384. updates["controller_file_buffered_channel_buffer_dir"] = atoi(argv[i + 1]);
  385. i += 2;
  386. } else if (p.isFlag(argv[i], '\0', "--no-graceful-exit")) {
  387. updates["graceful_exit"] = false;
  388. i++;
  389. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--benchmark")) {
  390. updates["benchmark_mode"] = argv[i + 1];
  391. i += 2;
  392. } else if (p.isFlag(argv[i], '\0', "--disable-selfchecks")) {
  393. updates["pool_selfchecks"] = false;
  394. i++;
  395. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--threads")) {
  396. updates["controller_threads"] = atoi(argv[i + 1]);
  397. i += 2;
  398. } else if (p.isFlag(argv[i], '\0', "--cpu-affine")) {
  399. updates["controller_cpu_affine"] = true;
  400. i++;
  401. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--core-file-descriptor-ulimit")) {
  402. updates["file_descriptor_ulimit"] = atoi(argv[i + 1]);
  403. i += 2;
  404. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--admin-panel-url")) {
  405. updates["admin_panel_url"] = argv[i + 1];
  406. i += 2;
  407. } else if (p.isValueFlag(argc, i, argv[i], '\0', "--ctl")) {
  408. const char *sep = strchr(argv[i + 1], '=');
  409. if (sep == NULL) {
  410. fprintf(stderr, "ERROR: invalid --ctl format: %s\n", argv[i + 1]);
  411. exit(1);
  412. }
  413. string name(argv[i + 1], sep - argv[i + 1]);
  414. string value(sep + 1);
  415. updates[name] = autocastValueToJson(value);
  416. i += 2;
  417. } else if (!startsWith(argv[i], "-")) {
  418. if (!updates.isMember("single_app_mode_app_root")) {
  419. updates["single_app_mode_app_root"] = argv[i];
  420. i++;
  421. } else {
  422. fprintf(stderr, "ERROR: you may not pass multiple application directories. "
  423. "Please type '%s core --help' for usage.\n", argv[0]);
  424. exit(1);
  425. }
  426. } else {
  427. return false;
  428. }
  429. return true;
  430. }
  431. } // namespace Passenger
  432. #endif /* _PASSENGER_CORE_OPTION_PARSER_H_ */