define get_signal_text macro to account for differences in the way AP2 provides acces...
[mod_fastcgi.git] / fcgi_config.c
blob786a4248e69e3757464c992b47d1474b101aa28d
1 /*
2 * $Id: fcgi_config.c,v 1.35 2002/07/29 00:05:06 robs Exp $
3 */
5 #include "fcgi.h"
7 #ifdef APACHE2
8 #include <limits.h>
9 #ifdef WIN32
10 #include <direct.h>
11 #else
12 #include <unistd.h>
13 #endif
14 #endif
16 #ifdef WIN32
17 /* warning C4100: unreferenced formal parameter */
18 /* warning C4706: assignment within conditional expression */
19 #pragma warning( disable : 4100 4706 )
20 #endif
22 /*******************************************************************************
23 * Get the next configuration directive argument, & return an in_addr and port.
24 * The arg must be in the form "host:port" where host can be an IP or hostname.
25 * The pool arg should be persistant storage.
27 static const char *get_host_n_port(pool *p, const char **arg,
28 const char **host, u_short *port)
30 char *cvptr, *portStr;
31 long tmp;
33 *host = ap_getword_conf(p, arg);
34 if (**host == '\0')
35 return "\"\"";
37 portStr = strchr(*host, ':');
38 if (portStr == NULL)
39 return "missing port specification";
41 /* Split the host and port portions */
42 *portStr++ = '\0';
44 /* Convert port number */
45 tmp = (u_short) strtol(portStr, &cvptr, 10);
46 if (*cvptr != '\0' || tmp < 1 || tmp > USHRT_MAX)
47 return ap_pstrcat(p, "bad port number \"", portStr, "\"", NULL);
49 *port = (unsigned short) tmp;
51 return NULL;
54 /*******************************************************************************
55 * Get the next configuration directive argument, & return an u_short.
56 * The pool arg should be temporary storage.
58 static const char *get_u_short(pool *p, const char **arg,
59 u_short *num, u_short min)
61 char *ptr;
62 long tmp;
63 const char *txt = ap_getword_conf(p, arg);
65 if (*txt == '\0') {
66 return "\"\"";
69 tmp = strtol(txt, &ptr, 10);
71 if (*ptr != '\0') {
72 return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
75 if (tmp < min || tmp > USHRT_MAX) {
76 return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX);
79 *num = (u_short) tmp;
81 return NULL;
84 static const char *get_int(pool *p, const char **arg, int *num, int min)
86 char *cp;
87 const char *val = ap_getword_conf(p, arg);
89 if (*val == '\0')
91 return "\"\"";
94 *num = (int) strtol(val, &cp, 10);
96 if (*cp != '\0')
98 return ap_pstrcat(p, "can't parse ", "\"", val, "\"", NULL);
100 else if (*num < min)
102 return ap_psprintf(p, "\"%d\" must be >= %d", *num, min);
105 return NULL;
108 /*******************************************************************************
109 * Get the next configuration directive argument, & return an u_int.
110 * The pool arg should be temporary storage.
112 static const char *get_u_int(pool *p, const char **arg,
113 u_int *num, u_int min)
115 char *ptr;
116 const char *val = ap_getword_conf(p, arg);
118 if (*val == '\0')
119 return "\"\"";
120 *num = (u_int)strtol(val, &ptr, 10);
122 if (*ptr != '\0')
123 return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
124 else if (*num < min)
125 return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
126 return NULL;
129 /*******************************************************************************
130 * Get the next configuration directive argument, & return a float.
131 * The pool arg should be temporary storage.
133 static const char *get_float(pool *p, const char **arg,
134 float *num, float min, float max)
136 char *ptr;
137 const char *val = ap_getword_conf(p, arg);
139 if (*val == '\0')
140 return "\"\"";
141 *num = (float) strtod(val, &ptr);
143 if (*ptr != '\0')
144 return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL);
145 if (*num < min || *num > max)
146 return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max);
147 return NULL;
150 const char *fcgi_config_set_env_var(pool *p, char **envp, unsigned int *envc, char * var)
152 if (*envc >= MAX_INIT_ENV_VARS) {
153 return "too many variables, must be <= MAX_INIT_ENV_VARS";
156 if (strchr(var, '=') == NULL) {
157 *(envp + *envc) = ap_pstrcat(p, var, "=", getenv(var), NULL);
159 else {
160 *(envp + *envc) = var;
163 (*envc)++;
165 return NULL;
168 /*******************************************************************************
169 * Get the next configuration directive argument, & add it to an env array.
170 * The pool arg should be permanent storage.
172 static const char *get_env_var(pool *p, const char **arg, char **envp, unsigned int *envc)
174 char * const val = ap_getword_conf(p, arg);
176 if (*val == '\0') {
177 return "\"\"";
180 return fcgi_config_set_env_var(p, envp, envc, val);
183 static const char *get_pass_header(pool *p, const char **arg, array_header **array)
185 const char **header;
187 if (!*array) {
188 *array = ap_make_array(p, 10, sizeof(char*));
191 header = (const char **)ap_push_array(*array);
192 *header = ap_getword_conf(p, arg);
194 return header ? NULL : "\"\"";
197 /*******************************************************************************
198 * Return a "standard" message for common configuration errors.
200 static const char *invalid_value(pool *p, const char *cmd, const char *id,
201 const char *opt, const char *err)
203 return ap_psprintf(p, "%s%s%s: invalid value for %s: %s",
204 cmd, id ? " " : "", id ? id : "", opt, err);
207 /*******************************************************************************
208 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
209 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
210 * to check that the config files don't set the User/Group after a FastCGI
211 * directive is used that depends on it.
213 /*@@@ To be complete, we should save a handle to the server each AppClass is
214 * configured in and at init() check that the user/group is still what we
215 * thought it was. Also the other directives should only be allowed in the
216 * parent Apache server.
218 const char *fcgi_config_set_fcgi_uid_n_gid(int set)
220 static int isSet = 0;
222 #ifndef WIN32
224 uid_t uid = geteuid();
225 gid_t gid = getegid();
227 if (set == 0) {
228 isSet = 0;
229 fcgi_user_id = (uid_t)-1;
230 fcgi_group_id = (gid_t)-1;
231 return NULL;
234 #ifndef APACHE2
236 if (uid == 0) {
237 uid = ap_user_id;
240 if (gid == 0) {
241 gid = ap_group_id;
244 #endif /* !APACHE2 */
246 if (isSet && (uid != fcgi_user_id || gid != fcgi_group_id)) {
247 return "User/Group commands must preceed FastCGI server definitions";
250 isSet = 1;
251 fcgi_user_id = uid;
252 fcgi_group_id = gid;
254 #endif /* !WIN32 */
256 return NULL;
259 apcb_t fcgi_config_reset_globals(void* dummy)
261 fcgi_config_pool = NULL;
262 fcgi_servers = NULL;
263 fcgi_config_set_fcgi_uid_n_gid(0);
264 fcgi_wrapper = NULL;
265 fcgi_socket_dir = DEFAULT_SOCK_DIR;
267 fcgi_dynamic_total_proc_count = 0;
268 fcgi_dynamic_epoch = 0;
269 fcgi_dynamic_last_analyzed = 0;
271 dynamicMaxProcs = FCGI_DEFAULT_MAX_PROCS;
272 dynamicMinProcs = FCGI_DEFAULT_MIN_PROCS;
273 dynamicMaxClassProcs = FCGI_DEFAULT_MAX_CLASS_PROCS;
274 dynamicKillInterval = FCGI_DEFAULT_KILL_INTERVAL;
275 dynamicUpdateInterval = FCGI_DEFAULT_UPDATE_INTERVAL;
276 dynamicGain = FCGI_DEFAULT_GAIN;
277 dynamicThreshold1 = FCGI_DEFAULT_THRESHOLD_1;
278 dynamicThresholdN = FCGI_DEFAULT_THRESHOLD_N;
279 dynamicPleaseStartDelay = FCGI_DEFAULT_START_PROCESS_DELAY;
280 dynamicAppConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
281 dynamicEnvp = &fcgi_empty_env;
282 dynamicProcessSlack = FCGI_DEFAULT_PROCESS_SLACK;
283 dynamicAutoRestart = FCGI_DEFAULT_RESTART_DYNAMIC;
284 dynamicAutoUpdate = FCGI_DEFAULT_AUTOUPDATE;
285 dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
286 dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
287 dynamicRestartDelay = FCGI_DEFAULT_RESTART_DELAY;
288 dynamic_pass_headers = NULL;
289 dynamic_idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
290 dynamicFlush = FCGI_FLUSH;
292 #ifndef WIN32
293 /* Close any old pipe (HUP/USR1) */
294 if (fcgi_pm_pipe[0] != -1) {
295 close(fcgi_pm_pipe[0]);
296 fcgi_pm_pipe[0] = -1;
298 if (fcgi_pm_pipe[1] != -1) {
299 close(fcgi_pm_pipe[1]);
300 fcgi_pm_pipe[1] = -1;
302 #endif
304 return APCB_OK;
307 /*******************************************************************************
308 * Create a directory to hold Unix/Domain sockets.
310 const char *fcgi_config_make_dir(pool *tp, char *path)
312 struct stat finfo;
313 const char *err = NULL;
315 /* Is the directory spec'd correctly */
316 if (*path != '/') {
317 return "path is not absolute (it must start with a \"/\")";
319 else {
320 int i = strlen(path) - 1;
322 /* Strip trailing "/"s */
323 while(i > 0 && path[i] == '/') path[i--] = '\0';
326 /* Does it exist? */
327 if (stat(path, &finfo) != 0) {
328 /* No, but maybe we can create it */
329 #ifdef WIN32
330 if (mkdir(path) != 0)
331 #else
332 if (mkdir(path, S_IRWXU) != 0)
333 #endif
335 return ap_psprintf(tp,
336 "doesn't exist and can't be created: %s",
337 strerror(errno));
340 #if !defined(WIN32) && !defined(APACHE2)
341 /* If we're root, we're gonna setuid/setgid so we need to chown */
342 if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) {
343 return ap_psprintf(tp,
344 "can't chown() to the server (uid %ld, gid %ld): %s",
345 (long)ap_user_id, (long)ap_group_id, strerror(errno));
347 #endif
349 else {
350 /* Yes, is it a directory? */
351 if (!S_ISDIR(finfo.st_mode))
352 return "isn't a directory!";
354 /* Can we RWX in there? */
355 #ifdef WIN32
356 err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
357 #else
358 err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
359 fcgi_user_id, fcgi_group_id);
360 #endif
361 if (err != NULL) {
362 return ap_psprintf(tp,
363 "access for server (uid %ld, gid %ld) failed: %s",
364 (long)fcgi_user_id, (long)fcgi_group_id, err);
367 return NULL;
370 /*******************************************************************************
371 * Create a "dynamic" subdirectory. If the directory
372 * already exists we don't mess with it unless 'wax' is set.
374 const char *fcgi_config_make_dynamic_dir(pool *p, const int wax)
376 #ifndef WIN32
377 const char *err;
378 pool *tp;
380 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "/dynamic", NULL);
382 if ((err = fcgi_config_make_dir(p, fcgi_dynamic_dir)))
383 return ap_psprintf(p, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir, err);
385 /* Don't step on a running server unless its OK. */
386 if (!wax)
387 return NULL;
389 #ifdef APACHE2
391 apr_dir_t * dir;
392 apr_finfo_t finfo;
394 if (apr_pool_create(&tp, p))
395 return "apr_pool_create() failed";
397 if (apr_dir_open(&dir, fcgi_dynamic_dir, tp))
398 return "apr_dir_open() failed";
400 /* delete the contents */
402 while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS)
404 if (strcmp(finfo.name, ".") == 0 || strcmp(finfo.name, "..") == 0)
405 continue;
407 apr_file_remove(finfo.name, tp);
411 #else /* !APACHE2 */
413 DIR *dp;
414 struct dirent *dirp = NULL;
416 tp = ap_make_sub_pool(p);
418 dp = ap_popendir(tp, fcgi_dynamic_dir);
419 if (dp == NULL) {
420 ap_destroy_pool(tp);
421 return ap_psprintf(p, "can't open dynamic directory \"%s\": %s",
422 fcgi_dynamic_dir, strerror(errno));
425 /* delete the contents */
427 while ((dirp = readdir(dp)) != NULL)
429 if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
430 continue;
432 unlink(ap_pstrcat(tp, fcgi_dynamic_dir, "/", dirp->d_name, NULL));
436 #endif /* !APACHE2 */
438 ap_destroy_pool(tp);
440 #else
441 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "dynamic", NULL);
442 #endif
443 return NULL;
447 /*******************************************************************************
448 * Change the directory used for the Unix/Domain sockets from the default.
449 * Create the directory and the "dynamic" subdirectory.
451 const char *fcgi_config_set_socket_dir(cmd_parms *cmd, void *dummy, const char *arg)
453 pool * const tp = cmd->temp_pool;
454 const char * const name = cmd->cmd->name;
455 const char *err;
456 char * arg_nc;
458 if (strcmp(fcgi_socket_dir, DEFAULT_SOCK_DIR) != 0) {
459 return ap_psprintf(tp, "%s %s: already defined as \"%s\"",
460 name, arg, fcgi_socket_dir);
463 err = fcgi_config_set_fcgi_uid_n_gid(1);
464 if (err != NULL)
465 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
467 if (fcgi_servers != NULL) {
468 return ap_psprintf(tp,
469 "The %s command must preceed static FastCGI server definitions",
470 name);
473 arg_nc = ap_pstrdup(cmd->pool, arg);
475 #ifndef WIN32
477 #ifdef APACHE2
478 if (apr_filepath_merge(&arg_nc, "", arg, 0, cmd->pool))
479 return ap_psprintf(tp, "%s %s: invalid filepath", name, arg);
480 #else
481 arg_nc = ap_os_canonical_filename(cmd->pool, arg_nc);
482 #endif
484 arg_nc = ap_server_root_relative(cmd->pool, arg_nc);
486 #else /* WIN32 */
488 if (strncmp(arg_nc, "\\\\.\\pipe\\", 9) != 0)
489 return ap_psprintf(tp, "%s %s is invalid format",name, arg_nc);
491 #endif
493 fcgi_socket_dir = arg_nc;
495 #ifndef WIN32
496 err = fcgi_config_make_dir(tp, fcgi_socket_dir);
497 if (err != NULL)
498 return ap_psprintf(tp, "%s %s: %s", name, arg_nc, err);
500 err = fcgi_config_make_dynamic_dir(cmd->pool, 0);
501 if (err != NULL)
502 return ap_psprintf(tp, "%s %s: %s", name, arg_nc, err);
503 #endif
505 return NULL;
508 /*******************************************************************************
509 * Enable, disable, or specify the path to a wrapper used to invoke all
510 * FastCGI applications.
512 const char *fcgi_config_set_wrapper(cmd_parms *cmd, void *dummy, const char *arg)
514 #ifdef APACHE2
516 * AP2TODO use ap_run_get_suexec_identity() (this will be hard as it
517 * takes a request_rec) and/or mod_userdir_user note
519 return ap_psprintf(cmd->temp_pool, "%s isn't supported yet under Apache2", cmd->cmd->name);
520 #else
521 const char *err = NULL;
522 const char * const name = cmd->cmd->name;
523 pool * const tp = cmd->temp_pool;
524 char * wrapper;
526 if (!ap_suexec_enabled && strcasecmp(arg, "On") == 0) {
527 fprintf(stderr, "Warning: \"%s On\" requires SUEXEC be enabled in Apache", name);
528 return NULL;
531 err = fcgi_config_set_fcgi_uid_n_gid(1);
532 if (err != NULL)
533 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
535 if (fcgi_servers != NULL) {
536 return ap_psprintf(tp,
537 "The %s command must preceed static FastCGI server definitions", name);
540 if (strcasecmp(arg, "On") == 0) {
541 fcgi_wrapper = SUEXEC_BIN;
543 else if (strcasecmp(arg, "Off") == 0) {
544 fcgi_wrapper = NULL;
546 else {
547 wrapper = (char *) ap_os_canonical_filename(cmd->pool, arg);
548 wrapper = ap_server_root_relative(cmd->pool, wrapper);
550 #ifdef WIN32
551 err = fcgi_util_check_access(tp, wrapper, NULL, _S_IEXEC, fcgi_user_id, fcgi_group_id);
552 #else
553 err = fcgi_util_check_access(tp, wrapper, NULL, X_OK, fcgi_user_id, fcgi_group_id);
554 #endif
556 if (err != NULL) {
557 return ap_psprintf(tp,
558 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
559 name, wrapper, (long)fcgi_user_id, (long)fcgi_group_id, err);
562 fcgi_wrapper = wrapper;
564 return NULL;
565 #endif /* !APACHE2 */
568 /*******************************************************************************
569 * Configure a static FastCGI server.
571 const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
573 fcgi_server *s;
574 pool *p = cmd->pool, *tp = cmd->temp_pool;
575 const char *name = cmd->cmd->name;
576 char *fs_path = ap_getword_conf(p, &arg);
577 const char *option, *err;
579 /* Allocate temp storage for the array of initial environment variables */
580 char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
581 unsigned int envc = 0;
583 #ifdef WIN32
584 HANDLE mutex;
585 #endif
587 if (*fs_path == '\0')
588 return "AppClass requires a pathname!?";
590 if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL)
591 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
593 #ifdef APACHE2
594 if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
595 return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
596 #else
597 fs_path = ap_os_canonical_filename(p, fs_path);
598 #endif
599 fs_path = ap_server_root_relative(p, fs_path);
601 ap_getparents(fs_path);
602 ap_no2slash(fs_path);
604 /* See if we've already got one of these configured */
605 s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
606 fcgi_util_get_server_gid(cmd->server));
607 if (s != NULL) {
608 if (fcgi_wrapper) {
609 return ap_psprintf(tp,
610 "%s: redefinition of a previously defined FastCGI "
611 "server \"%s\" with uid=%ld and gid=%ld",
612 name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
613 (long) fcgi_util_get_server_gid(cmd->server));
615 else {
616 return ap_psprintf(tp,
617 "%s: redefinition of a previously defined FastCGI server \"%s\"",
618 name, fs_path);
622 err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL);
623 if (err != NULL) {
624 return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err);
627 s = fcgi_util_fs_new(p);
628 s->fs_path = fs_path;
629 s->directive = APP_CLASS_STANDARD;
630 s->restartOnExit = TRUE;
631 s->numProcesses = 1;
633 #ifdef WIN32
635 // TCP FastCGI applications require SystemRoot be present in the environment
636 // Put it in both for consistency to the application
637 fcgi_config_set_env_var(tp, envp, &envc, "SystemRoot");
639 mutex = CreateMutex(NULL, FALSE, fs_path);
641 if (mutex == NULL)
643 ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
644 "FastCGI: CreateMutex() failed");
645 return "failed to create FastCGI application accept mutex";
648 SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE);
650 s->mutex_env_string = ap_psprintf(p, "_FCGI_MUTEX_=%ld", mutex);
652 #elif !defined(APACHE2)
654 if (fcgi_wrapper) {
655 struct passwd *pw;
656 struct group *gr;
658 s->uid = cmd->server->server_uid;
659 pw = getpwuid(s->uid);
660 if (pw == NULL) {
661 return ap_psprintf(tp, "mod_fastcgi: "
662 "getpwuid() couldn't determine the username for uid '%ld', "
663 "you probably need to modify the User directive: %s",
664 (long)s->uid, strerror(errno));
666 s->user = ap_pstrdup(p, pw->pw_name);
667 s->username = s->user;
669 s->gid = cmd->server->server_gid;
670 gr = getgrgid(s->gid);
671 if (gr == NULL) {
672 return ap_psprintf(tp, "mod_fastcgi: "
673 "getgrgid() couldn't determine the group name for gid '%ld', "
674 "you probably need to modify the Group directive: %s\n",
675 (long)s->gid, strerror(errno));
677 s->group = ap_pstrdup(p, gr->gr_name);
679 #endif
681 /* Parse directive arguments */
682 while (*arg) {
683 option = ap_getword_conf(tp, &arg);
685 if (strcasecmp(option, "-processes") == 0) {
686 if ((err = get_u_int(tp, &arg, &s->numProcesses, 1)))
687 return invalid_value(tp, name, fs_path, option, err);
689 else if (strcasecmp(option, "-restart-delay") == 0) {
690 if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
691 return invalid_value(tp, name, fs_path, option, err);
693 else if (strcasecmp(option, "-init-start-delay") == 0) {
694 if ((err = get_int(tp, &arg, &s->initStartDelay, 0)))
695 return invalid_value(tp, name, fs_path, option, err);
697 else if (strcasecmp(option, "-priority") == 0) {
698 if ((err = get_u_int(tp, &arg, &s->processPriority, 0)))
699 return invalid_value(tp, name, fs_path, option, err);
701 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
702 if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1)))
703 return invalid_value(tp, name, fs_path, option, err);
705 else if (strcasecmp(option, "-appConnTimeout") == 0) {
706 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
707 return invalid_value(tp, name, fs_path, option, err);
709 else if (strcasecmp(option, "-idle-timeout") == 0) {
710 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
711 return invalid_value(tp, name, fs_path, option, err);
713 else if (strcasecmp(option, "-port") == 0) {
714 if ((err = get_u_short(tp, &arg, &s->port, 1)))
715 return invalid_value(tp, name, fs_path, option, err);
717 else if (strcasecmp(option, "-socket") == 0) {
718 s->socket_path = ap_getword_conf(tp, &arg);
719 if (*s->socket_path == '\0')
720 return invalid_value(tp, name, fs_path, option, "\"\"");
722 else if (strcasecmp(option, "-initial-env") == 0) {
723 if ((err = get_env_var(p, &arg, envp, &envc)))
724 return invalid_value(tp, name, fs_path, option, err);
726 else if (strcasecmp(option, "-pass-header") == 0) {
727 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
728 return invalid_value(tp, name, fs_path, option, err);
730 else if (strcasecmp(option, "-flush") == 0) {
731 s->flush = 1;
733 else {
734 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
736 } /* while */
738 if (s->socket_path != NULL && s->port != 0) {
739 return ap_psprintf(tp,
740 "%s %s: -port and -socket are mutually exclusive options",
741 name, fs_path);
744 /* Move env array to a surviving pool */
745 s->envp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4));
746 memcpy(s->envp, envp, sizeof(char *) * envc);
748 /* Initialize process structs */
749 s->procs = fcgi_util_fs_create_procs(p, s->numProcesses);
751 /* Build the appropriate sockaddr structure */
752 if (s->port != 0) {
753 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
754 &s->socket_addr_len, NULL, s->port);
755 if (err != NULL)
756 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
757 #ifdef WIN32
758 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
759 &s->socket_addr_len, "localhost", s->port);
760 if (err != NULL)
761 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
762 #endif
763 } else {
764 if (s->socket_path == NULL)
765 s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group);
766 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
767 #ifndef WIN32
768 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
769 &s->socket_addr_len, s->socket_path);
770 if (err != NULL)
771 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
772 #endif
775 /* Add it to the list of FastCGI servers */
776 fcgi_util_fs_add(s);
778 return NULL;
781 /*******************************************************************************
782 * Configure a static FastCGI server that is started/managed elsewhere.
784 const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg)
786 fcgi_server *s;
787 pool * const p = cmd->pool, *tp = cmd->temp_pool;
788 const char * const name = cmd->cmd->name;
789 char *fs_path = ap_getword_conf(p, &arg);
790 const char *option, *err;
792 if (!*fs_path) {
793 return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL);
796 #ifdef APACHE2
797 if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
798 return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
799 #else
800 fs_path = ap_os_canonical_filename(p, fs_path);
801 #endif
803 fs_path = ap_server_root_relative(p, fs_path);
805 ap_getparents(fs_path);
806 ap_no2slash(fs_path);
808 /* See if we've already got one of these bettys configured */
809 s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
810 fcgi_util_get_server_gid(cmd->server));
811 if (s != NULL) {
812 if (fcgi_wrapper) {
813 return ap_psprintf(tp,
814 "%s: redefinition of a previously defined class \"%s\" "
815 "with uid=%ld and gid=%ld",
816 name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
817 (long) fcgi_util_get_server_gid(cmd->server));
819 else
821 return ap_psprintf(tp,
822 "%s: redefinition of previously defined class \"%s\"", name, fs_path);
826 s = fcgi_util_fs_new(p);
827 s->fs_path = fs_path;
828 s->directive = APP_CLASS_EXTERNAL;
830 err = fcgi_util_fs_set_uid_n_gid(p, s, fcgi_util_get_server_uid(cmd->server),
831 fcgi_util_get_server_gid(cmd->server));
832 if (err != NULL)
833 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
835 /* Parse directive arguments */
836 while (*arg != '\0') {
837 option = ap_getword_conf(tp, &arg);
839 if (strcasecmp(option, "-host") == 0) {
840 if ((err = get_host_n_port(p, &arg, &s->host, &s->port)))
841 return invalid_value(tp, name, fs_path, option, err);
843 else if (strcasecmp(option, "-socket") == 0) {
844 s->socket_path = ap_getword_conf(tp, &arg);
845 if (*s->socket_path == '\0')
846 return invalid_value(tp, name, fs_path, option, "\"\"");
848 else if (strcasecmp(option, "-appConnTimeout") == 0) {
849 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
850 return invalid_value(tp, name, fs_path, option, err);
852 else if (strcasecmp(option, "-idle-timeout") == 0) {
853 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
854 return invalid_value(tp, name, fs_path, option, err);
856 else if (strcasecmp(option, "-pass-header") == 0) {
857 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
858 return invalid_value(tp, name, fs_path, option, err);
860 else if (strcasecmp(option, "-flush") == 0) {
861 s->flush = 1;
863 else {
864 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
866 } /* while */
868 /* Require one of -socket or -host, but not both */
869 if (s->socket_path != NULL && s->port != 0) {
870 return ap_psprintf(tp,
871 "%s %s: -host and -socket are mutually exclusive options",
872 name, fs_path);
874 if (s->socket_path == NULL && s->port == 0) {
875 return ap_psprintf(tp,
876 "%s %s: -socket or -host option missing", name, fs_path);
879 /* Build the appropriate sockaddr structure */
880 if (s->port != 0) {
881 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
882 &s->socket_addr_len, s->host, s->port);
883 if (err != NULL)
884 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
885 } else {
886 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
887 #ifndef WIN32
888 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
889 &s->socket_addr_len, s->socket_path);
890 if (err != NULL)
891 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
892 #endif
895 /* Add it to the list of FastCGI servers */
896 fcgi_util_fs_add(s);
898 return NULL;
902 *----------------------------------------------------------------------
904 * fcgi_config_set_config --
906 * Implements the FastCGI FCGIConfig configuration directive.
907 * This command adds routines to control the execution of the
908 * dynamic FastCGI processes.
911 *----------------------------------------------------------------------
913 const char *fcgi_config_set_config(cmd_parms *cmd, void *dummy, const char *arg)
915 pool * const p = cmd->pool;
916 pool * const tp = cmd->temp_pool;
917 const char *err, *option;
918 const char * const name = cmd->cmd->name;
920 /* Allocate temp storage for an initial environment */
921 unsigned int envc = 0;
922 char **envp = (char **)ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
924 /* Parse the directive arguments */
925 while (*arg) {
926 option = ap_getword_conf(tp, &arg);
928 if (strcasecmp(option, "-maxProcesses") == 0) {
929 if ((err = get_u_int(tp, &arg, &dynamicMaxProcs, 1)))
930 return invalid_value(tp, name, NULL, option, err);
932 else if (strcasecmp(option, "-minProcesses") == 0) {
933 if ((err = get_int(tp, &arg, &dynamicMinProcs, 0)))
934 return invalid_value(tp, name, NULL, option, err);
936 else if (strcasecmp(option, "-maxClassProcesses") == 0) {
937 if ((err = get_int(tp, &arg, &dynamicMaxClassProcs, 1)))
938 return invalid_value(tp, name, NULL, option, err);
940 else if (strcasecmp(option, "-killInterval") == 0) {
941 if ((err = get_u_int(tp, &arg, &dynamicKillInterval, 1)))
942 return invalid_value(tp, name, NULL, option, err);
944 else if (strcasecmp(option, "-updateInterval") == 0) {
945 if ((err = get_u_int(tp, &arg, &dynamicUpdateInterval, 1)))
946 return invalid_value(tp, name, NULL, option, err);
948 else if (strcasecmp(option, "-gainValue") == 0) {
949 if ((err = get_float(tp, &arg, &dynamicGain, 0.0, 1.0)))
950 return invalid_value(tp, name, NULL, option, err);
952 else if ((strcasecmp(option, "-singleThreshold") == 0)
953 || (strcasecmp(option, "-singleThreshhold") == 0))
955 if ((err = get_int(tp, &arg, &dynamicThreshold1, 0)))
956 return invalid_value(tp, name, NULL, option, err);
958 else if ((strcasecmp(option, "-multiThreshold") == 0)
959 || (strcasecmp(option, "-multiThreshhold") == 0))
961 if ((err = get_int(tp, &arg, &dynamicThresholdN, 0)))
962 return invalid_value(tp, name, NULL, option, err);
964 else if (strcasecmp(option, "-startDelay") == 0) {
965 if ((err = get_u_int(tp, &arg, &dynamicPleaseStartDelay, 1)))
966 return invalid_value(tp, name, NULL, option, err);
968 else if (strcasecmp(option, "-initial-env") == 0) {
969 if ((err = get_env_var(p, &arg, envp, &envc)))
970 return invalid_value(tp, name, NULL, option, err);
972 else if (strcasecmp(option, "-pass-header") == 0) {
973 if ((err = get_pass_header(p, &arg, &dynamic_pass_headers)))
974 return invalid_value(tp, name, NULL, option, err);
976 else if (strcasecmp(option, "-appConnTimeout") == 0) {
977 if ((err = get_u_int(tp, &arg, &dynamicAppConnectTimeout, 0)))
978 return invalid_value(tp, name, NULL, option, err);
980 else if (strcasecmp(option, "-idle-timeout") == 0) {
981 if ((err = get_u_int(tp, &arg, &dynamic_idle_timeout, 1)))
982 return invalid_value(tp, name, NULL, option, err);
984 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
985 if ((err = get_u_int(tp, &arg, &dynamicListenQueueDepth, 1)))
986 return invalid_value(tp, name, NULL, option, err);
988 else if (strcasecmp(option, "-restart-delay") == 0) {
989 if ((err = get_u_int(tp, &arg, &dynamicRestartDelay, 0)))
990 return invalid_value(tp, name, NULL, option, err);
992 else if (strcasecmp(option, "-init-start-delay") == 0) {
993 if ((err = get_u_int(tp, &arg, &dynamicInitStartDelay, 0)))
994 return invalid_value(tp, name, NULL, option, err);
996 else if (strcasecmp(option, "-processSlack") == 0) {
997 if ((err = get_u_int(tp, &arg, &dynamicProcessSlack, 1)))
998 return invalid_value(tp, name, NULL, option, err);
1000 else if (strcasecmp(option, "-restart") == 0) {
1001 dynamicAutoRestart = 1;
1003 else if (strcasecmp(option, "-autoUpdate") == 0) {
1004 dynamicAutoUpdate = 1;
1006 else if (strcasecmp(option, "-flush") == 0) {
1007 dynamicFlush = TRUE;
1009 else {
1010 return ap_psprintf(tp, "%s: invalid option: %s", name, option);
1012 } /* while */
1014 if (dynamicProcessSlack >= dynamicMaxProcs + 1) {
1015 /* the kill policy would work unexpectedly */
1016 return ap_psprintf(tp,
1017 "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
1018 name, dynamicProcessSlack, dynamicMaxProcs);
1021 /* Move env array to a surviving pool, leave 2 extra slots for
1022 * WIN32 _FCGI_MUTEX_ and _FCGI_SHUTDOWN_EVENT_ */
1023 dynamicEnvp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4));
1024 memcpy(dynamicEnvp, envp, sizeof(char *) * envc);
1026 return NULL;
1029 void *fcgi_config_create_dir_config(pool *p, char *dummy)
1031 fcgi_dir_config *dir_config = ap_pcalloc(p, sizeof(fcgi_dir_config));
1033 dir_config->authenticator_options = FCGI_AUTHORITATIVE;
1034 dir_config->authorizer_options = FCGI_AUTHORITATIVE;
1035 dir_config->access_checker_options = FCGI_AUTHORITATIVE;
1037 return dir_config;
1041 const char *fcgi_config_new_auth_server(cmd_parms * cmd,
1042 void * dircfg, const char *fs_path, const char * compat)
1044 fcgi_dir_config * dir_config = (fcgi_dir_config *) dircfg;
1045 pool * const tp = cmd->temp_pool;
1046 char * auth_server;
1048 #ifdef APACHE2
1049 if (apr_filepath_merge(&auth_server, "", fs_path, 0, cmd->pool))
1050 return ap_psprintf(tp, "%s %s: invalid filepath", cmd->cmd->name, fs_path);
1051 #else
1052 auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path);
1053 #endif
1055 auth_server = ap_server_root_relative(cmd->pool, auth_server);
1057 /* Make sure its already configured or at least a candidate for dynamic */
1058 if (fcgi_util_fs_get_by_id(auth_server, fcgi_util_get_server_uid(cmd->server),
1059 fcgi_util_get_server_gid(cmd->server)) == NULL)
1061 const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL);
1062 if (err)
1063 return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err);
1066 if (compat && strcasecmp(compat, "-compat"))
1067 return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat);
1069 switch((int)cmd->info) {
1070 case FCGI_AUTH_TYPE_AUTHENTICATOR:
1071 dir_config->authenticator = auth_server;
1072 dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0;
1073 break;
1074 case FCGI_AUTH_TYPE_AUTHORIZER:
1075 dir_config->authorizer = auth_server;
1076 dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
1077 break;
1078 case FCGI_AUTH_TYPE_ACCESS_CHECKER:
1079 dir_config->access_checker = auth_server;
1080 dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
1081 break;
1084 return NULL;
1087 const char *fcgi_config_set_authoritative_slot(cmd_parms * cmd,
1088 void * dir_config, int arg)
1090 int offset = (int)(long)cmd->info;
1092 if (arg)
1093 *((u_char *)dir_config + offset) |= FCGI_AUTHORITATIVE;
1094 else
1095 *((u_char *)dir_config + offset) &= ~FCGI_AUTHORITATIVE;
1097 return NULL;