2 * $Id: fcgi_config.c,v 1.24 2000/10/23 20:20:49 robs Exp $
8 /*******************************************************************************
9 * Get the next configuration directive argument, & return an in_addr and port.
10 * The arg must be in the form "host:port" where host can be an IP or hostname.
11 * The pool arg should be persistant storage.
13 static const char *get_host_n_port(pool
*p
, const char **arg
,
14 const char **host
, u_short
*port
)
16 char *cvptr
, *portStr
;
19 *host
= ap_getword_conf(p
, arg
);
23 portStr
= strchr(*host
, ':');
25 return "missing port specification";
27 /* Split the host and port portions */
30 /* Convert port number */
31 tmp
= (u_short
) strtol(portStr
, &cvptr
, 10);
32 if (*cvptr
!= '\0' || tmp
< 1 || tmp
> USHRT_MAX
)
33 return ap_pstrcat(p
, "bad port number \"", portStr
, "\"", NULL
);
35 *port
= (unsigned short) tmp
;
40 /*******************************************************************************
41 * Get the next configuration directive argument, & return an u_short.
42 * The pool arg should be temporary storage.
44 static const char *get_u_short(pool
*p
, const char **arg
,
45 u_short
*num
, u_short min
)
49 const char *txt
= ap_getword_conf(p
, arg
);
55 tmp
= strtol(txt
, &ptr
, 10);
58 return ap_pstrcat(p
, "\"", txt
, "\" must be a positive integer", NULL
);
61 if (tmp
< min
|| tmp
> USHRT_MAX
) {
62 return ap_psprintf(p
, "\"%u\" must be >= %u and < %u", *num
, min
, USHRT_MAX
);
70 /*******************************************************************************
71 * Get the next configuration directive argument, & return an u_int.
72 * The pool arg should be temporary storage.
74 static const char *get_u_int(pool
*p
, const char **arg
,
75 u_int
*num
, u_int min
)
78 const char *val
= ap_getword_conf(p
, arg
);
82 *num
= (u_int
)strtol(val
, &ptr
, 10);
85 return ap_pstrcat(p
, "\"", val
, "\" must be a positive integer", NULL
);
87 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
91 /*******************************************************************************
92 * Get the next configuration directive argument, & return a float.
93 * The pool arg should be temporary storage.
95 static const char *get_float(pool
*p
, const char **arg
,
96 float *num
, float min
, float max
)
99 const char *val
= ap_getword_conf(p
, arg
);
103 *num
= (float) strtod(val
, &ptr
);
106 return ap_pstrcat(p
, "\"", val
, "\" is not a floating point number", NULL
);
107 if (*num
< min
|| *num
> max
)
108 return ap_psprintf(p
, "\"%f\" is not between %f and %f", *num
, min
, max
);
112 const char *fcgi_config_set_env_var(pool
*p
, char **envp
, unsigned int *envc
, char * var
)
114 if (*envc
>= MAX_INIT_ENV_VARS
) {
115 return "too many variables, must be <= MAX_INIT_ENV_VARS";
118 if (strchr(var
, '=') == NULL
) {
119 *(envp
+ *envc
) = ap_pstrcat(p
, var
, "=", getenv(var
), NULL
);
122 *(envp
+ *envc
) = var
;
130 /*******************************************************************************
131 * Get the next configuration directive argument, & add it to an env array.
132 * The pool arg should be permanent storage.
134 static const char *get_env_var(pool
*p
, const char **arg
, char **envp
, unsigned int *envc
)
136 char * const val
= ap_getword_conf(p
, arg
);
142 return fcgi_config_set_env_var(p
, envp
, envc
, val
);
145 static const char *get_pass_header(pool
*p
, const char **arg
, array_header
**array
)
150 *array
= ap_make_array(p
, 10, sizeof(char*));
153 header
= (const char **)ap_push_array(*array
);
154 *header
= ap_getword_conf(p
, arg
);
156 return header
? NULL
: "\"\"";
159 /*******************************************************************************
160 * Return a "standard" message for common configuration errors.
162 static const char *invalid_value(pool
*p
, const char *cmd
, const char *id
,
163 const char *opt
, const char *err
)
165 return ap_psprintf(p
, "%s%s%s: invalid value for %s: %s",
166 cmd
, id
? " " : "", id
? id
: "", opt
, err
);
169 /*******************************************************************************
170 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
171 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
172 * to check that the config files don't set the User/Group after a FastCGI
173 * directive is used that depends on it.
175 /*@@@ To be complete, we should save a handle to the server each AppClass is
176 * configured in and at init() check that the user/group is still what we
177 * thought it was. Also the other directives should only be allowed in the
178 * parent Apache server.
180 const char *fcgi_config_set_fcgi_uid_n_gid(int set
)
182 static int isSet
= 0;
184 uid_t uid
= geteuid();
185 gid_t gid
= getegid();
189 fcgi_user_id
= (uid_t
)-1;
190 fcgi_group_id
= (gid_t
)-1;
194 uid
= uid
? uid
: ap_user_id
;
195 gid
= gid
? gid
: ap_group_id
;
197 if (isSet
&& (uid
!= fcgi_user_id
|| gid
!= fcgi_group_id
)) {
198 return "User/Group commands must preceed FastCGI server definitions";
208 void fcgi_config_reset_globals(void* dummy
)
210 fcgi_config_pool
= NULL
;
212 fcgi_config_set_fcgi_uid_n_gid(0);
214 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
216 fcgi_dynamic_total_proc_count
= 0;
217 fcgi_dynamic_epoch
= 0;
218 fcgi_dynamic_last_analyzed
= 0;
220 dynamicMaxProcs
= FCGI_DEFAULT_MAX_PROCS
;
221 dynamicMinProcs
= FCGI_DEFAULT_MIN_PROCS
;
222 dynamicMaxClassProcs
= FCGI_DEFAULT_MAX_CLASS_PROCS
;
223 dynamicKillInterval
= FCGI_DEFAULT_KILL_INTERVAL
;
224 dynamicUpdateInterval
= FCGI_DEFAULT_UPDATE_INTERVAL
;
225 dynamicGain
= FCGI_DEFAULT_GAIN
;
226 dynamicThreshhold1
= FCGI_DEFAULT_THRESHHOLD_1
;
227 dynamicThreshholdN
= FCGI_DEFAULT_THRESHHOLD_N
;
228 dynamicPleaseStartDelay
= FCGI_DEFAULT_START_PROCESS_DELAY
;
229 dynamicAppConnectTimeout
= FCGI_DEFAULT_APP_CONN_TIMEOUT
;
230 dynamicEnvp
= &fcgi_empty_env
;
231 dynamicProcessSlack
= FCGI_DEFAULT_PROCESS_SLACK
;
232 dynamicAutoRestart
= FCGI_DEFAULT_RESTART_DYNAMIC
;
233 dynamicAutoUpdate
= FCGI_DEFAULT_AUTOUPDATE
;
234 dynamicListenQueueDepth
= FCGI_DEFAULT_LISTEN_Q
;
235 dynamicInitStartDelay
= DEFAULT_INIT_START_DELAY
;
236 dynamicRestartDelay
= FCGI_DEFAULT_RESTART_DELAY
;
237 dynamic_pass_headers
= NULL
;
238 dynamic_idle_timeout
= FCGI_DEFAULT_IDLE_TIMEOUT
;
241 /*******************************************************************************
242 * Create a directory to hold Unix/Domain sockets.
244 const char *fcgi_config_make_dir(pool
*tp
, char *path
)
247 const char *err
= NULL
;
249 /* Is the directory spec'd correctly */
251 return "path is not absolute (it must start with a \"/\")";
254 int i
= strlen(path
) - 1;
256 /* Strip trailing "/"s */
257 while(i
> 0 && path
[i
] == '/') path
[i
--] = '\0';
261 if (stat(path
, &finfo
) != 0) {
262 /* No, but maybe we can create it */
264 if (mkdir(path
) != 0)
266 if (mkdir(path
, S_IRWXU
) != 0)
269 return ap_psprintf(tp
,
270 "doesn't exist and can't be created: %s",
275 /* If we're root, we're gonna setuid/setgid so we need to chown */
276 if (geteuid() == 0 && chown(path
, ap_user_id
, ap_group_id
) != 0) {
277 return ap_psprintf(tp
,
278 "can't chown() to the server (uid %ld, gid %ld): %s",
279 (long)ap_user_id
, (long)ap_group_id
, strerror(errno
));
284 /* Yes, is it a directory? */
285 if (!S_ISDIR(finfo
.st_mode
))
286 return "isn't a directory!";
288 /* Can we RWX in there? */
290 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, _S_IREAD
| _S_IWRITE
| _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
292 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, R_OK
| W_OK
| X_OK
,
293 fcgi_user_id
, fcgi_group_id
);
296 return ap_psprintf(tp
,
297 "access for server (uid %ld, gid %ld) failed: %s",
298 (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
304 /*******************************************************************************
305 * Create a "dynamic" subdirectory. If the directory
306 * already exists we don't mess with it unless 'wax' is set.
308 const char *fcgi_config_make_dynamic_dir(pool
*p
, const int wax
)
312 struct dirent
*dirp
= NULL
;
316 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "/dynamic", NULL
);
318 if ((err
= fcgi_config_make_dir(p
, fcgi_dynamic_dir
)))
319 return ap_psprintf(p
, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir
, err
);
321 /* Don't step on a running server unless its OK. */
325 /* Create a subpool for the directory operations */
326 tp
= ap_make_sub_pool(p
);
328 dp
= ap_popendir(tp
, fcgi_dynamic_dir
);
331 return ap_psprintf(p
, "can't open dynamic directory \"%s\": %s",
332 fcgi_dynamic_dir
, strerror(errno
));
335 /* Delete everything in the directory, its all FCGI specific */
336 while ((dirp
= readdir(dp
)) != NULL
) {
337 if (strcmp(dirp
->d_name
, ".") == 0
338 || strcmp(dirp
->d_name
, "..") == 0) {
342 unlink(ap_pstrcat(tp
, fcgi_dynamic_dir
, "/", dirp
->d_name
, NULL
));
348 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "dynamic", NULL
);
354 /*******************************************************************************
355 * Change the directory used for the Unix/Domain sockets from the default.
356 * Create the directory and the "dynamic" subdirectory.
358 const char *fcgi_config_set_socket_dir(cmd_parms
*cmd
, void *dummy
, char *arg
)
360 pool
* const tp
= cmd
->temp_pool
;
361 const char * const name
= cmd
->cmd
->name
;
364 if (strcmp(fcgi_socket_dir
, DEFAULT_SOCK_DIR
) != 0) {
365 return ap_psprintf(tp
, "%s %s: already defined as \"%s\"",
366 name
, arg
, fcgi_socket_dir
);
369 err
= fcgi_config_set_fcgi_uid_n_gid(1);
371 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
373 if (fcgi_servers
!= NULL
) {
374 return ap_psprintf(tp
,
375 "The %s command must preceed static FastCGI server definitions",
380 arg
= ap_os_canonical_filename(cmd
->pool
, arg
);
381 arg
= ap_server_root_relative(cmd
->pool
, arg
);
383 if (strncmp(arg
, "\\\\.\\pipe\\", 9) != 0)
384 return ap_psprintf(tp
, "%s %s is invalid format",name
, arg
);
387 fcgi_socket_dir
= arg
;
390 err
= fcgi_config_make_dir(tp
, fcgi_socket_dir
);
392 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
394 err
= fcgi_config_make_dynamic_dir(cmd
->pool
, 0);
396 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
402 /*******************************************************************************
403 * Enable, disable, or specify the path to a wrapper used to invoke all
404 * FastCGI applications.
406 const char *fcgi_config_set_wrapper(cmd_parms
*cmd
, void *dummy
, const char *arg
)
408 const char *err
= NULL
;
409 const char * const name
= cmd
->cmd
->name
;
410 pool
* const tp
= cmd
->temp_pool
;
413 if (!ap_suexec_enabled
&& strcasecmp(arg
, "On") == 0) {
414 fprintf(stderr
, "Warning: \"%s On\" requires SUEXEC be enabled in Apache", name
);
418 err
= fcgi_config_set_fcgi_uid_n_gid(1);
420 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
422 if (fcgi_servers
!= NULL
) {
423 return ap_psprintf(tp
,
424 "The %s command must preceed static FastCGI server definitions", name
);
427 if (strcasecmp(arg
, "On") == 0) {
428 fcgi_wrapper
= SUEXEC_BIN
;
430 else if (strcasecmp(arg
, "Off") == 0) {
434 wrapper
= (char *) ap_os_canonical_filename(cmd
->pool
, arg
);
435 wrapper
= ap_server_root_relative(cmd
->pool
, wrapper
);
438 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
440 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, X_OK
, fcgi_user_id
, fcgi_group_id
);
444 return ap_psprintf(tp
,
445 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
446 name
, wrapper
, (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
449 fcgi_wrapper
= wrapper
;
454 /*******************************************************************************
455 * Configure a static FastCGI server.
457 const char *fcgi_config_new_static_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
460 pool
*p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
461 const char *name
= cmd
->cmd
->name
;
462 char *fs_path
= ap_getword_conf(p
, &arg
);
463 const char *option
, *err
;
465 /* Allocate temp storage for the array of initial environment variables */
466 char **envp
= ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
467 unsigned int envc
= 0;
469 if (*fs_path
== '\0')
470 return "AppClass requires a pathname!?";
472 if ((err
= fcgi_config_set_fcgi_uid_n_gid(1)) != NULL
)
473 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
475 fs_path
= ap_os_canonical_filename(p
, fs_path
);
476 fs_path
= ap_server_root_relative(p
, fs_path
);
478 ap_getparents(fs_path
);
479 ap_no2slash(fs_path
);
481 /* See if we've already got one of these configured */
482 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
483 cmd
->server
->server_gid
);
486 return ap_psprintf(tp
,
487 "%s: redefinition of a previously defined FastCGI server \"%s\" with uid=%ld and gid=%ld",
488 name
, fs_path
, (long)cmd
->server
->server_uid
,
489 (long)cmd
->server
->server_gid
);
492 return ap_psprintf(tp
,
493 "%s: redefinition of a previously defined FastCGI server \"%s\"",
498 err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
, cmd
->server
->server_uid
,
499 cmd
->server
->server_gid
);
501 return ap_psprintf(tp
, "%s: \"%s\" %s", name
, fs_path
, err
);
504 s
= fcgi_util_fs_new(p
);
505 s
->fs_path
= fs_path
;
506 s
->directive
= APP_CLASS_STANDARD
;
507 s
->restartOnExit
= TRUE
;
511 // TCP FastCGI applications require SystemRoot be present in the environment
512 // Put it in both for consistency to the application
513 fcgi_config_set_env_var(tp
, envp
, &envc
, "SystemRoot");
519 s
->uid
= cmd
->server
->server_uid
;
520 pw
= getpwuid(s
->uid
);
522 return ap_psprintf(tp
, "mod_fastcgi: "
523 "getpwuid() couldn't determine the username for uid '%ld', "
524 "you probably need to modify the User directive: %s",
525 (long)s
->uid
, strerror(errno
));
527 s
->user
= ap_pstrdup(p
, pw
->pw_name
);
528 s
->username
= s
->user
;
530 s
->gid
= cmd
->server
->server_gid
;
531 gr
= getgrgid(s
->gid
);
533 return ap_psprintf(tp
, "mod_fastcgi: "
534 "getgrgid() couldn't determine the group name for gid '%ld', "
535 "you probably need to modify the Group directive: %s\n",
536 (long)s
->gid
, strerror(errno
));
538 s
->group
= ap_pstrdup(p
, gr
->gr_name
);
542 /* Parse directive arguments */
544 option
= ap_getword_conf(tp
, &arg
);
546 if (strcasecmp(option
, "-processes") == 0) {
547 if ((err
= get_u_int(tp
, &arg
, &s
->numProcesses
, 1)))
548 return invalid_value(tp
, name
, fs_path
, option
, err
);
550 else if (strcasecmp(option
, "-restart-delay") == 0) {
551 if ((err
= get_u_int(tp
, &arg
, &s
->restartDelay
, 0)))
552 return invalid_value(tp
, name
, fs_path
, option
, err
);
554 else if (strcasecmp(option
, "-init-start-delay") == 0) {
555 if ((err
= get_u_int(tp
, &arg
, &s
->initStartDelay
, 0)))
556 return invalid_value(tp
, name
, fs_path
, option
, err
);
558 else if (strcasecmp(option
, "-priority") == 0) {
559 if ((err
= get_u_int(tp
, &arg
, &s
->processPriority
, 0)))
560 return invalid_value(tp
, name
, fs_path
, option
, err
);
562 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
563 if ((err
= get_u_int(tp
, &arg
, &s
->listenQueueDepth
, 1)))
564 return invalid_value(tp
, name
, fs_path
, option
, err
);
566 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
567 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
568 return invalid_value(tp
, name
, fs_path
, option
, err
);
570 else if (strcasecmp(option
, "-idle-timeout") == 0) {
571 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
572 return invalid_value(tp
, name
, fs_path
, option
, err
);
574 else if (strcasecmp(option
, "-port") == 0) {
575 if ((err
= get_u_short(tp
, &arg
, &s
->port
, 1)))
576 return invalid_value(tp
, name
, fs_path
, option
, err
);
578 else if (strcasecmp(option
, "-socket") == 0) {
579 s
->socket_path
= ap_getword_conf(tp
, &arg
);
580 if (*s
->socket_path
== '\0')
581 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
583 else if (strcasecmp(option
, "-initial-env") == 0) {
584 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
585 return invalid_value(tp
, name
, fs_path
, option
, err
);
587 else if (strcasecmp(option
, "-pass-header") == 0) {
588 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
589 return invalid_value(tp
, name
, fs_path
, option
, err
);
591 else if (strcasecmp(option
, "-flush") == 0) {
595 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
599 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
600 return ap_psprintf(tp
,
601 "%s %s: -port and -socket are mutually exclusive options",
605 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
607 s
->envp
= (char **)ap_palloc(p
, sizeof(char *) * ++envc
);
608 memcpy(s
->envp
, envp
, sizeof(char *) * envc
);
610 /* Initialize process structs */
611 s
->procs
= fcgi_util_fs_create_procs(p
, s
->numProcesses
);
613 /* Build the appropriate sockaddr structure */
615 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
616 &s
->socket_addr_len
, NULL
, s
->port
);
618 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
620 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->dest_addr
,
621 &s
->socket_addr_len
, "localhost", s
->port
);
623 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
626 if (s
->socket_path
== NULL
)
627 s
->socket_path
= fcgi_util_socket_hash_filename(tp
, fs_path
, s
->user
, s
->group
);
628 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
630 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
631 &s
->socket_addr_len
, s
->socket_path
);
633 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
637 /* Add it to the list of FastCGI servers */
643 /*******************************************************************************
644 * Configure a static FastCGI server that is started/managed elsewhere.
646 const char *fcgi_config_new_external_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
649 pool
* const p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
650 const char * const name
= cmd
->cmd
->name
;
651 char *fs_path
= ap_getword_conf(p
, &arg
);
652 const char *option
, *err
;
655 return ap_pstrcat(tp
, name
, " requires a path and either a -socket or -host option", NULL
);
658 fs_path
= ap_os_canonical_filename(p
, fs_path
);
659 fs_path
= ap_server_root_relative(p
, fs_path
);
661 ap_getparents(fs_path
);
662 ap_no2slash(fs_path
);
664 /* See if we've already got one of these bettys configured */
665 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
666 cmd
->server
->server_gid
);
669 return ap_psprintf(tp
,
670 "%s: redefinition of a previously defined class \"%s\" with uid=%ld and gid=%ld",
671 name
, fs_path
, (long)cmd
->server
->server_uid
,
672 (long)cmd
->server
->server_gid
);
675 return ap_psprintf(tp
,
676 "%s: redefinition of previously defined class \"%s\"", name
, fs_path
);
680 s
= fcgi_util_fs_new(p
);
681 s
->fs_path
= fs_path
;
682 s
->directive
= APP_CLASS_EXTERNAL
;
684 err
= fcgi_util_fs_set_uid_n_gid(p
, s
, cmd
->server
->server_uid
, cmd
->server
->server_gid
);
686 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
688 /* Parse directive arguments */
689 while (*arg
!= '\0') {
690 option
= ap_getword_conf(tp
, &arg
);
692 if (strcasecmp(option
, "-host") == 0) {
693 if ((err
= get_host_n_port(p
, &arg
, &s
->host
, &s
->port
)))
694 return invalid_value(tp
, name
, fs_path
, option
, err
);
696 else if (strcasecmp(option
, "-socket") == 0) {
697 s
->socket_path
= ap_getword_conf(tp
, &arg
);
698 if (*s
->socket_path
== '\0')
699 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
701 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
702 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
703 return invalid_value(tp
, name
, fs_path
, option
, err
);
705 else if (strcasecmp(option
, "-idle-timeout") == 0) {
706 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
707 return invalid_value(tp
, name
, fs_path
, option
, err
);
709 else if (strcasecmp(option
, "-pass-header") == 0) {
710 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
711 return invalid_value(tp
, name
, fs_path
, option
, err
);
713 else if (strcasecmp(option
, "-flush") == 0) {
717 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
721 /* Require one of -socket or -host, but not both */
722 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
723 return ap_psprintf(tp
,
724 "%s %s: -host and -socket are mutually exclusive options",
727 if (s
->socket_path
== NULL
&& s
->port
== 0) {
728 return ap_psprintf(tp
,
729 "%s %s: -socket or -host option missing", name
, fs_path
);
732 /* Build the appropriate sockaddr structure */
734 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
735 &s
->socket_addr_len
, s
->host
, s
->port
);
737 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
739 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
741 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
742 &s
->socket_addr_len
, s
->socket_path
);
744 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
748 /* Add it to the list of FastCGI servers */
755 *----------------------------------------------------------------------
757 * fcgi_config_set_config --
759 * Implements the FastCGI FCGIConfig configuration directive.
760 * This command adds routines to control the execution of the
761 * dynamic FastCGI processes.
764 *----------------------------------------------------------------------
766 const char *fcgi_config_set_config(cmd_parms
*cmd
, void *dummy
, const char *arg
)
768 pool
* const p
= cmd
->pool
;
769 pool
* const tp
= cmd
->temp_pool
;
770 const char *err
, *option
;
771 const char * const name
= cmd
->cmd
->name
;
773 /* Allocate temp storage for an initial environment */
774 unsigned int envc
= 0;
775 char **envp
= (char **)ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
777 /* Parse the directive arguments */
779 option
= ap_getword_conf(tp
, &arg
);
781 if (strcasecmp(option
, "-maxProcesses") == 0) {
782 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxProcs
, 1)))
783 return invalid_value(tp
, name
, NULL
, option
, err
);
785 else if (strcasecmp(option
, "-minProcesses") == 0) {
786 if ((err
= get_u_int(tp
, &arg
, &dynamicMinProcs
, 0)))
787 return invalid_value(tp
, name
, NULL
, option
, err
);
789 else if (strcasecmp(option
, "-maxClassProcesses") == 0) {
790 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxClassProcs
, 1)))
791 return invalid_value(tp
, name
, NULL
, option
, err
);
793 else if (strcasecmp(option
, "-killInterval") == 0) {
794 if ((err
= get_u_int(tp
, &arg
, &dynamicKillInterval
, 1)))
795 return invalid_value(tp
, name
, NULL
, option
, err
);
797 else if (strcasecmp(option
, "-updateInterval") == 0) {
798 if ((err
= get_u_int(tp
, &arg
, &dynamicUpdateInterval
, 1)))
799 return invalid_value(tp
, name
, NULL
, option
, err
);
801 else if (strcasecmp(option
, "-gainValue") == 0) {
802 if ((err
= get_float(tp
, &arg
, &dynamicGain
, 0.0, 1.0)))
803 return invalid_value(tp
, name
, NULL
, option
, err
);
805 else if (strcasecmp(option
, "-singleThreshhold") == 0) {
806 if ((err
= get_u_int(tp
, &arg
, &dynamicThreshhold1
, 0)))
807 return invalid_value(tp
, name
, NULL
, option
, err
);
809 else if (strcasecmp(option
, "-multiThreshhold") == 0) {
810 if ((err
= get_u_int(tp
, &arg
, &dynamicThreshholdN
, 0)))
811 return invalid_value(tp
, name
, NULL
, option
, err
);
813 else if (strcasecmp(option
, "-startDelay") == 0) {
814 if ((err
= get_u_int(tp
, &arg
, &dynamicPleaseStartDelay
, 1)))
815 return invalid_value(tp
, name
, NULL
, option
, err
);
817 else if (strcasecmp(option
, "-initial-env") == 0) {
818 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
819 return invalid_value(tp
, name
, NULL
, option
, err
);
821 else if (strcasecmp(option
, "-pass-header") == 0) {
822 if ((err
= get_pass_header(p
, &arg
, &dynamic_pass_headers
)))
823 return invalid_value(tp
, name
, NULL
, option
, err
);
825 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
826 if ((err
= get_u_int(tp
, &arg
, &dynamicAppConnectTimeout
, 0)))
827 return invalid_value(tp
, name
, NULL
, option
, err
);
829 else if (strcasecmp(option
, "-idle-timeout") == 0) {
830 if ((err
= get_u_int(tp
, &arg
, &dynamic_idle_timeout
, 1)))
831 return invalid_value(tp
, name
, NULL
, option
, err
);
833 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
834 if ((err
= get_u_int(tp
, &arg
, &dynamicListenQueueDepth
, 1)))
835 return invalid_value(tp
, name
, NULL
, option
, err
);
837 else if (strcasecmp(option
, "-restart-delay") == 0) {
838 if ((err
= get_u_int(tp
, &arg
, &dynamicRestartDelay
, 0)))
839 return invalid_value(tp
, name
, NULL
, option
, err
);
841 else if (strcasecmp(option
, "-init-start-delay") == 0) {
842 if ((err
= get_u_int(tp
, &arg
, &dynamicInitStartDelay
, 0)))
843 return invalid_value(tp
, name
, NULL
, option
, err
);
845 else if (strcasecmp(option
, "-processSlack") == 0) {
846 if ((err
= get_u_int(tp
, &arg
, &dynamicProcessSlack
, 1)))
847 return invalid_value(tp
, name
, NULL
, option
, err
);
849 else if (strcasecmp(option
, "-restart") == 0) {
850 dynamicAutoRestart
= 1;
852 else if (strcasecmp(option
, "-autoUpdate") == 0) {
853 dynamicAutoUpdate
= 1;
856 return ap_psprintf(tp
, "%s: invalid option: %s", name
, option
);
860 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
862 dynamicEnvp
= (char **)ap_palloc(p
, sizeof(char *) * ++envc
);
863 memcpy(dynamicEnvp
, envp
, sizeof(char *) * envc
);
868 void *fcgi_config_create_dir_config(pool
*p
, char *dummy
)
870 fcgi_dir_config
*dir_config
= ap_pcalloc(p
, sizeof(fcgi_dir_config
));
872 dir_config
->authenticator_options
= FCGI_AUTHORITATIVE
;
873 dir_config
->authorizer_options
= FCGI_AUTHORITATIVE
;
874 dir_config
->access_checker_options
= FCGI_AUTHORITATIVE
;
880 const char *fcgi_config_new_auth_server(cmd_parms
* const cmd
,
881 fcgi_dir_config
*dir_config
, const char *fs_path
, const char * const compat
)
883 pool
* const tp
= cmd
->temp_pool
;
884 const uid_t uid
= cmd
->server
->server_uid
;
885 const gid_t gid
= cmd
->server
->server_gid
;
888 auth_server
= (char *) ap_os_canonical_filename(cmd
->pool
, fs_path
);
889 auth_server
= ap_server_root_relative(cmd
->pool
, auth_server
);
891 /* Make sure its already configured or at least a candidate for dynamic */
892 if (fcgi_util_fs_get_by_id(auth_server
, uid
, gid
) == NULL
) {
893 const char *err
= fcgi_util_fs_is_path_ok(tp
, auth_server
, NULL
, uid
, gid
);
895 return ap_psprintf(tp
, "%s: \"%s\" %s", cmd
->cmd
->name
, auth_server
, err
);
898 if (compat
&& strcasecmp(compat
, "-compat"))
899 return ap_psprintf(cmd
->temp_pool
, "%s: unknown option: \"%s\"", cmd
->cmd
->name
, compat
);
901 switch((int)cmd
->info
) {
902 case FCGI_AUTH_TYPE_AUTHENTICATOR
:
903 dir_config
->authenticator
= auth_server
;
904 dir_config
->authenticator_options
|= (compat
) ? FCGI_COMPAT
: 0;
906 case FCGI_AUTH_TYPE_AUTHORIZER
:
907 dir_config
->authorizer
= auth_server
;
908 dir_config
->authorizer_options
|= (compat
) ? FCGI_COMPAT
: 0;
910 case FCGI_AUTH_TYPE_ACCESS_CHECKER
:
911 dir_config
->access_checker
= auth_server
;
912 dir_config
->access_checker_options
|= (compat
) ? FCGI_COMPAT
: 0;
919 const char *fcgi_config_set_authoritative_slot(const cmd_parms
* const cmd
,
920 fcgi_dir_config
* const dir_config
, int arg
)
922 int offset
= (int)(long)cmd
->info
;
925 *(int *)(dir_config
+ offset
) |= FCGI_AUTHORITATIVE
;
927 *(int *)(dir_config
+ offset
) &= ~FCGI_AUTHORITATIVE
;