PageRenderTime 52ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/fpm/fpm_conf.c

http://github.com/dreamcat4/php-fpm
C | 537 lines | 411 code | 124 blank | 2 comment | 66 complexity | a0825e4a23c4cf5e155e1fc6005fe626 MD5 | raw file
  1. /* $Id: fpm_conf.c,v 1.33.2.3 2008/12/13 03:50:29 anight Exp $ */
  2. /* (c) 2007,2008 Andrei Nigmatulin */
  3. #include "fpm_config.h"
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <stddef.h>
  10. #if HAVE_INTTYPES_H
  11. #include <inttypes.h>
  12. #else
  13. #include <stdint.h>
  14. #endif
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #include "fpm.h"
  18. #include "fpm_conf.h"
  19. #include "fpm_stdio.h"
  20. #include "fpm_worker_pool.h"
  21. #include "fpm_cleanup.h"
  22. #include "fpm_php.h"
  23. #include "fpm_sockets.h"
  24. #include "xml_config.h"
  25. #include "zlog.h"
  26. struct fpm_global_config_s fpm_global_config;
  27. static void *fpm_global_config_ptr()
  28. {
  29. return &fpm_global_config;
  30. }
  31. static char *fpm_conf_set_log_level(void **conf, char *name, void *vv, intptr_t offset)
  32. {
  33. char *value = vv;
  34. if (!strcmp(value, "debug")) {
  35. fpm_globals.log_level = ZLOG_DEBUG;
  36. }
  37. else if (!strcmp(value, "notice")) {
  38. fpm_globals.log_level = ZLOG_NOTICE;
  39. }
  40. else if (!strcmp(value, "warn")) {
  41. fpm_globals.log_level = ZLOG_WARNING;
  42. }
  43. else if (!strcmp(value, "error")) {
  44. fpm_globals.log_level = ZLOG_ERROR;
  45. }
  46. else if (!strcmp(value, "alert")) {
  47. fpm_globals.log_level = ZLOG_ALERT;
  48. }
  49. else {
  50. return "invalid value for 'log_level'";
  51. }
  52. return NULL;
  53. }
  54. static struct xml_conf_section xml_section_fpm_global_options = {
  55. .conf = &fpm_global_config_ptr,
  56. .path = "/configuration/global_options",
  57. .parsers = (struct xml_value_parser []) {
  58. { XML_CONF_SCALAR, "emergency_restart_threshold", &xml_conf_set_slot_integer, offsetof(struct fpm_global_config_s, emergency_restart_threshold) },
  59. { XML_CONF_SCALAR, "emergency_restart_interval", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, emergency_restart_interval) },
  60. { XML_CONF_SCALAR, "process_control_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_global_config_s, process_control_timeout) },
  61. { XML_CONF_SCALAR, "daemonize", &xml_conf_set_slot_boolean, offsetof(struct fpm_global_config_s, daemonize) },
  62. { XML_CONF_SCALAR, "pid_file", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, pid_file) },
  63. { XML_CONF_SCALAR, "error_log", &xml_conf_set_slot_string, offsetof(struct fpm_global_config_s, error_log) },
  64. { XML_CONF_SCALAR, "log_level", &fpm_conf_set_log_level, 0 },
  65. { 0, 0, 0, 0 }
  66. }
  67. };
  68. static char *fpm_conf_set_pm_style(void **conf, char *name, void *vv, intptr_t offset)
  69. {
  70. char *value = vv;
  71. struct fpm_pm_s *c = *conf;
  72. if (!strcmp(value, "static")) {
  73. c->style = PM_STYLE_STATIC;
  74. }
  75. else if (!strcmp(value, "apache-like")) {
  76. c->style = PM_STYLE_APACHE_LIKE;
  77. }
  78. else {
  79. return "invalid value for 'style'";
  80. }
  81. return NULL;
  82. }
  83. static char *fpm_conf_set_rlimit_core(void **conf, char *name, void *vv, intptr_t offset)
  84. {
  85. char *value = vv;
  86. struct fpm_worker_pool_config_s *c = *conf;
  87. if (!strcmp(value, "unlimited")) {
  88. c->rlimit_core = -1;
  89. }
  90. else {
  91. int int_value;
  92. void *subconf = &int_value;
  93. char *error;
  94. error = xml_conf_set_slot_integer(&subconf, name, vv, 0);
  95. if (error) { return error; }
  96. if (int_value < 0) { return "invalid value for 'rlimit_core'"; }
  97. c->rlimit_core = int_value;
  98. }
  99. return NULL;
  100. }
  101. static char *fpm_conf_set_catch_workers_output(void **conf, char *name, void *vv, intptr_t offset)
  102. {
  103. struct fpm_worker_pool_config_s *c = *conf;
  104. int int_value;
  105. void *subconf = &int_value;
  106. char *error;
  107. error = xml_conf_set_slot_boolean(&subconf, name, vv, 0);
  108. if (error) { return error; }
  109. c->catch_workers_output = int_value;
  110. return NULL;
  111. }
  112. static struct xml_conf_section fpm_conf_set_apache_like_subsection_conf = {
  113. .path = "apache_like somewhere", /* fixme */
  114. .parsers = (struct xml_value_parser []) {
  115. { XML_CONF_SCALAR, "StartServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.StartServers) },
  116. { XML_CONF_SCALAR, "MinSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MinSpareServers) },
  117. { XML_CONF_SCALAR, "MaxSpareServers", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, options_apache_like.MaxSpareServers) },
  118. { 0, 0, 0, 0 }
  119. }
  120. };
  121. static char *fpm_conf_set_apache_like_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
  122. {
  123. return xml_conf_parse_section(conf, &fpm_conf_set_apache_like_subsection_conf, xml_node);
  124. }
  125. static struct xml_conf_section fpm_conf_set_listen_options_subsection_conf = {
  126. .path = "listen options somewhere", /* fixme */
  127. .parsers = (struct xml_value_parser []) {
  128. { XML_CONF_SCALAR, "backlog", &xml_conf_set_slot_integer, offsetof(struct fpm_listen_options_s, backlog) },
  129. { XML_CONF_SCALAR, "owner", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, owner) },
  130. { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, group) },
  131. { XML_CONF_SCALAR, "mode", &xml_conf_set_slot_string, offsetof(struct fpm_listen_options_s, mode) },
  132. { 0, 0, 0, 0 }
  133. }
  134. };
  135. static char *fpm_conf_set_listen_options_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
  136. {
  137. void *subconf = (char *) *conf + offset;
  138. struct fpm_listen_options_s *lo;
  139. lo = malloc(sizeof(*lo));
  140. if (!lo) {
  141. return "malloc() failed";
  142. }
  143. memset(lo, 0, sizeof(*lo));
  144. lo->backlog = -1;
  145. * (struct fpm_listen_options_s **) subconf = lo;
  146. subconf = lo;
  147. return xml_conf_parse_section(&subconf, &fpm_conf_set_listen_options_subsection_conf, xml_node);
  148. }
  149. static struct xml_conf_section fpm_conf_set_pm_subsection_conf = {
  150. .path = "pm settings somewhere", /* fixme */
  151. .parsers = (struct xml_value_parser []) {
  152. { XML_CONF_SCALAR, "style", &fpm_conf_set_pm_style, 0 },
  153. { XML_CONF_SCALAR, "max_children", &xml_conf_set_slot_integer, offsetof(struct fpm_pm_s, max_children) },
  154. { XML_CONF_SUBSECTION, "apache_like", &fpm_conf_set_apache_like_subsection, offsetof(struct fpm_pm_s, options_apache_like) },
  155. { 0, 0, 0, 0 }
  156. }
  157. };
  158. static char *fpm_conf_set_pm_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
  159. {
  160. void *subconf = (char *) *conf + offset;
  161. struct fpm_pm_s *pm;
  162. pm = malloc(sizeof(*pm));
  163. if (!pm) {
  164. return "fpm_conf_set_pm_subsection(): malloc failed";
  165. }
  166. memset(pm, 0, sizeof(*pm));
  167. * (struct fpm_pm_s **) subconf = pm;
  168. subconf = pm;
  169. return xml_conf_parse_section(&subconf, &fpm_conf_set_pm_subsection_conf, xml_node);
  170. }
  171. static char *xml_conf_set_slot_key_value_pair(void **conf, char *name, void *vv, intptr_t offset)
  172. {
  173. char *value = vv;
  174. struct key_value_s *kv;
  175. struct key_value_s ***parent = (struct key_value_s ***) conf;
  176. kv = malloc(sizeof(*kv));
  177. if (!kv) {
  178. return "malloc() failed";
  179. }
  180. memset(kv, 0, sizeof(*kv));
  181. kv->key = strdup(name);
  182. kv->value = strdup(value);
  183. if (!kv->key || !kv->value) {
  184. return "xml_conf_set_slot_key_value_pair(): strdup() failed";
  185. }
  186. **parent = kv;
  187. *parent = &kv->next;
  188. return NULL;
  189. }
  190. static struct xml_conf_section fpm_conf_set_key_value_pairs_subsection_conf = {
  191. .path = "key_value_pairs somewhere", /* fixme */
  192. .parsers = (struct xml_value_parser []) {
  193. { XML_CONF_SCALAR, 0, &xml_conf_set_slot_key_value_pair, 0 },
  194. { 0, 0, 0, 0 }
  195. }
  196. };
  197. static char *fpm_conf_set_key_value_pairs_subsection(void **conf, char *name, void *xml_node, intptr_t offset)
  198. {
  199. void *next_kv = (char *) *conf + offset;
  200. return xml_conf_parse_section(&next_kv, &fpm_conf_set_key_value_pairs_subsection_conf, xml_node);
  201. }
  202. static void *fpm_worker_pool_config_alloc()
  203. {
  204. static struct fpm_worker_pool_s *current_wp = 0;
  205. struct fpm_worker_pool_s *wp;
  206. wp = fpm_worker_pool_alloc();
  207. if (!wp) { return 0; }
  208. wp->config = malloc(sizeof(struct fpm_worker_pool_config_s));
  209. if (!wp->config) { return 0; }
  210. memset(wp->config, 0, sizeof(struct fpm_worker_pool_config_s));
  211. if (current_wp) { current_wp->next = wp; }
  212. current_wp = wp;
  213. return wp->config;
  214. }
  215. int fpm_worker_pool_config_free(struct fpm_worker_pool_config_s *wpc)
  216. {
  217. struct key_value_s *kv, *kv_next;
  218. free(wpc->name);
  219. free(wpc->listen_address);
  220. if (wpc->listen_options) {
  221. free(wpc->listen_options->owner);
  222. free(wpc->listen_options->group);
  223. free(wpc->listen_options->mode);
  224. free(wpc->listen_options);
  225. }
  226. for (kv = wpc->php_defines; kv; kv = kv_next) {
  227. kv_next = kv->next;
  228. free(kv->key);
  229. free(kv->value);
  230. free(kv);
  231. }
  232. for (kv = wpc->environment; kv; kv = kv_next) {
  233. kv_next = kv->next;
  234. free(kv->key);
  235. free(kv->value);
  236. free(kv);
  237. }
  238. free(wpc->pm);
  239. free(wpc->user);
  240. free(wpc->group);
  241. free(wpc->chroot);
  242. free(wpc->chdir);
  243. free(wpc->allowed_clients);
  244. free(wpc->slowlog);
  245. return 0;
  246. }
  247. static struct xml_conf_section xml_section_fpm_worker_pool_config = {
  248. .conf = &fpm_worker_pool_config_alloc,
  249. .path = "/configuration/workers/pool",
  250. .parsers = (struct xml_value_parser []) {
  251. { XML_CONF_SCALAR, "name", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, name) },
  252. { XML_CONF_SCALAR, "listen_address", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, listen_address) },
  253. { XML_CONF_SUBSECTION, "listen_options", &fpm_conf_set_listen_options_subsection, offsetof(struct fpm_worker_pool_config_s, listen_options) },
  254. { XML_CONF_SUBSECTION, "php_defines", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, php_defines) },
  255. { XML_CONF_SCALAR, "user", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, user) },
  256. { XML_CONF_SCALAR, "group", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, group) },
  257. { XML_CONF_SCALAR, "chroot", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chroot) },
  258. { XML_CONF_SCALAR, "chdir", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, chdir) },
  259. { XML_CONF_SCALAR, "allowed_clients", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, allowed_clients) },
  260. { XML_CONF_SUBSECTION, "environment", &fpm_conf_set_key_value_pairs_subsection, offsetof(struct fpm_worker_pool_config_s, environment) },
  261. { XML_CONF_SCALAR, "request_terminate_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_terminate_timeout) },
  262. { XML_CONF_SCALAR, "request_slowlog_timeout", &xml_conf_set_slot_time, offsetof(struct fpm_worker_pool_config_s, request_slowlog_timeout) },
  263. { XML_CONF_SCALAR, "slowlog", &xml_conf_set_slot_string, offsetof(struct fpm_worker_pool_config_s, slowlog) },
  264. { XML_CONF_SCALAR, "rlimit_files", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, rlimit_files) },
  265. { XML_CONF_SCALAR, "rlimit_core", &fpm_conf_set_rlimit_core, 0 },
  266. { XML_CONF_SCALAR, "max_requests", &xml_conf_set_slot_integer, offsetof(struct fpm_worker_pool_config_s, max_requests) },
  267. { XML_CONF_SCALAR, "catch_workers_output", &fpm_conf_set_catch_workers_output, 0 },
  268. { XML_CONF_SUBSECTION, "pm", &fpm_conf_set_pm_subsection, offsetof(struct fpm_worker_pool_config_s, pm) },
  269. { 0, 0, 0, 0 }
  270. }
  271. };
  272. static struct xml_conf_section *fpm_conf_all_sections[] = {
  273. &xml_section_fpm_global_options,
  274. &xml_section_fpm_worker_pool_config,
  275. 0
  276. };
  277. static int fpm_evaluate_full_path(char **path)
  278. {
  279. if (**path != '/') {
  280. char *full_path;
  281. full_path = malloc(sizeof(PHP_PREFIX) + strlen(*path) + 1);
  282. if (!full_path) { return -1; }
  283. sprintf(full_path, "%s/%s", PHP_PREFIX, *path);
  284. free(*path);
  285. *path = full_path;
  286. }
  287. return 0;
  288. }
  289. static int fpm_conf_process_all_pools()
  290. {
  291. struct fpm_worker_pool_s *wp;
  292. if (!fpm_worker_all_pools) {
  293. zlog(ZLOG_STUFF, ZLOG_ERROR, "at least one pool section must be specified in config file");
  294. return -1;
  295. }
  296. for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
  297. if (wp->config->listen_address && *wp->config->listen_address) {
  298. wp->listen_address_domain = fpm_sockets_domain_from_address(wp->config->listen_address);
  299. if (wp->listen_address_domain == FPM_AF_UNIX && *wp->config->listen_address != '/') {
  300. fpm_evaluate_full_path(&wp->config->listen_address);
  301. }
  302. }
  303. else {
  304. wp->is_template = 1;
  305. }
  306. if (wp->config->request_slowlog_timeout) {
  307. #if HAVE_FPM_TRACE
  308. if (! (wp->config->slowlog && *wp->config->slowlog)) {
  309. zlog(ZLOG_STUFF, ZLOG_ERROR, "pool %s: 'slowlog' must be specified for use with 'request_slowlog_timeout'",
  310. wp->config->name);
  311. return -1;
  312. }
  313. #else
  314. static int warned = 0;
  315. if (!warned) {
  316. zlog(ZLOG_STUFF, ZLOG_WARNING, "pool %s: 'request_slowlog_timeout' is not supported on your system",
  317. wp->config->name);
  318. warned = 1;
  319. }
  320. wp->config->request_slowlog_timeout = 0;
  321. #endif
  322. }
  323. if (wp->config->request_slowlog_timeout && wp->config->slowlog && *wp->config->slowlog) {
  324. int fd;
  325. fpm_evaluate_full_path(&wp->config->slowlog);
  326. if (wp->config->request_slowlog_timeout) {
  327. fd = open(wp->config->slowlog, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
  328. if (0 > fd) {
  329. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "open(%s) failed", wp->config->slowlog);
  330. return -1;
  331. }
  332. close(fd);
  333. }
  334. }
  335. }
  336. return 0;
  337. }
  338. int fpm_conf_unlink_pid()
  339. {
  340. if (fpm_global_config.pid_file) {
  341. if (0 > unlink(fpm_global_config.pid_file)) {
  342. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "unlink(\"%s\") failed", fpm_global_config.pid_file);
  343. return -1;
  344. }
  345. }
  346. return 0;
  347. }
  348. int fpm_conf_write_pid()
  349. {
  350. int fd;
  351. if (fpm_global_config.pid_file) {
  352. char buf[64];
  353. int len;
  354. unlink(fpm_global_config.pid_file);
  355. fd = creat(fpm_global_config.pid_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  356. if (fd < 0) {
  357. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "creat(\"%s\") failed", fpm_global_config.pid_file);
  358. return -1;
  359. }
  360. len = sprintf(buf, "%d", (int) fpm_globals.parent_pid);
  361. if (len != write(fd, buf, len)) {
  362. zlog(ZLOG_STUFF, ZLOG_SYSERROR, "write() failed");
  363. return -1;
  364. }
  365. close(fd);
  366. }
  367. return 0;
  368. }
  369. static int fpm_conf_post_process()
  370. {
  371. if (fpm_global_config.pid_file) {
  372. fpm_evaluate_full_path(&fpm_global_config.pid_file);
  373. }
  374. if (!fpm_global_config.error_log) {
  375. fpm_global_config.error_log = strdup(PHP_FPM_LOG_PATH);
  376. }
  377. fpm_evaluate_full_path(&fpm_global_config.error_log);
  378. if (0 > fpm_stdio_open_error_log(0)) {
  379. return -1;
  380. }
  381. return fpm_conf_process_all_pools();
  382. }
  383. static void fpm_conf_cleanup(int which, void *arg)
  384. {
  385. free(fpm_global_config.pid_file);
  386. free(fpm_global_config.error_log);
  387. fpm_global_config.pid_file = 0;
  388. fpm_global_config.error_log = 0;
  389. }
  390. int fpm_conf_init_main()
  391. {
  392. char *filename = fpm_globals.config;
  393. char *err;
  394. if (0 > xml_conf_sections_register(fpm_conf_all_sections)) {
  395. return -1;
  396. }
  397. if (filename == NULL) {
  398. filename = PHP_FPM_CONF_PATH;
  399. }
  400. err = xml_conf_load_file(filename);
  401. if (err) {
  402. zlog(ZLOG_STUFF, ZLOG_ERROR, "failed to load configuration file: %s", err);
  403. return -1;
  404. }
  405. if (0 > fpm_conf_post_process()) {
  406. return -1;
  407. }
  408. xml_conf_clean();
  409. if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_conf_cleanup, 0)) {
  410. return -1;
  411. }
  412. return 0;
  413. }