2 * $Id: fcgi_config.c,v 1.18 2000/04/27 02:27:35 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
;
18 *host
= ap_getword_conf(p
, arg
);
22 portStr
= strchr(*host
, ':');
24 return "missing port specification";
26 /* Split the host and port portions */
29 /* Convert port number */
30 *port
= (u_int
)strtol(portStr
, &cvptr
, 10);
31 if (*cvptr
!= '\0' || *port
< 1 || *port
> 65535)
32 return ap_pstrcat(p
, "bad port number \"", portStr
, "\"", NULL
);
37 /*******************************************************************************
38 * Get the next configuration directive argument, & return an u_short.
39 * The pool arg should be temporary storage.
41 static const char *get_u_short(pool
*p
, const char **arg
,
42 u_short
*num
, u_short min
)
46 const char *txt
= ap_getword_conf(p
, arg
);
52 tmp
= strtol(txt
, &ptr
, 10);
55 return ap_pstrcat(p
, "\"", txt
, "\" must be a positive integer", NULL
);
59 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
67 /*******************************************************************************
68 * Get the next configuration directive argument, & return an u_int.
69 * The pool arg should be temporary storage.
71 static const char *get_u_int(pool
*p
, const char **arg
,
72 u_int
*num
, u_int min
)
75 const char *val
= ap_getword_conf(p
, arg
);
79 *num
= (u_int
)strtol(val
, &ptr
, 10);
82 return ap_pstrcat(p
, "\"", val
, "\" must be a positive integer", NULL
);
84 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
88 /*******************************************************************************
89 * Get the next configuration directive argument, & return a float.
90 * The pool arg should be temporary storage.
92 static const char *get_float(pool
*p
, const char **arg
,
93 float *num
, float min
, float max
)
96 const char *val
= ap_getword_conf(p
, arg
);
100 *num
= (float) strtod(val
, &ptr
);
103 return ap_pstrcat(p
, "\"", val
, "\" is not a floating point number", NULL
);
104 if (*num
< min
|| *num
> max
)
105 return ap_psprintf(p
, "\"%f\" is not between %f and %f", *num
, min
, max
);
109 /*******************************************************************************
110 * Get the next configuration directive argument, & add it to an env array.
111 * The pool arg should be permanent storage.
113 static const char *get_env_var(pool
*p
, const char **arg
, char **envp
, int *envc
)
115 char * const val
= ap_getword_conf(p
, arg
);
120 if (*envc
>= MAX_INIT_ENV_VARS
)
121 return "too many variables, must be <= MAX_INIT_ENV_VARS";
123 if (strchr(val
, '=') == NULL
)
124 *(envp
+ *envc
) = ap_pstrcat(p
, val
, "=", getenv(val
), NULL
);
126 *(envp
+ *envc
) = val
;
133 static const char *get_pass_header(pool
*p
, const char **arg
, array_header
**array
)
138 *array
= ap_make_array(p
, 10, sizeof(char*));
141 header
= (const char **)ap_push_array(*array
);
142 *header
= ap_getword_conf(p
, arg
);
144 return header
? NULL
: "\"\"";
147 /*******************************************************************************
148 * Return a "standard" message for common configuration errors.
150 static const char *invalid_value(pool
*p
, const char *cmd
, const char *id
,
151 const char *opt
, const char *err
)
153 return ap_psprintf(p
, "%s%s%s: invalid value for %s: %s",
154 cmd
, id
? " " : "", id
? id
: "", opt
, err
);
157 /*******************************************************************************
158 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
159 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
160 * to check that the config files don't set the User/Group after a FastCGI
161 * directive is used that depends on it.
163 /*@@@ To be complete, we should save a handle to the server each AppClass is
164 * configured in and at init() check that the user/group is still what we
165 * thought it was. Also the other directives should only be allowed in the
166 * parent Apache server.
168 const char *fcgi_config_set_fcgi_uid_n_gid(int set
)
170 static int isSet
= 0;
172 uid_t uid
= geteuid();
173 gid_t gid
= getegid();
177 fcgi_user_id
= (uid_t
)-1;
178 fcgi_group_id
= (gid_t
)-1;
182 uid
= uid
? uid
: ap_user_id
;
183 gid
= uid
? gid
: ap_group_id
;
185 if (isSet
&& (uid
!= fcgi_user_id
|| gid
!= fcgi_group_id
)) {
186 return "User/Group commands must preceed FastCGI server definitions";
196 void fcgi_config_reset_globals(void* dummy
)
198 fcgi_config_pool
= NULL
;
200 fcgi_config_set_fcgi_uid_n_gid(0);
202 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
204 fcgi_dynamic_total_proc_count
= 0;
205 fcgi_dynamic_epoch
= 0;
206 fcgi_dynamic_last_analyzed
= 0;
208 dynamicMaxProcs
= FCGI_DEFAULT_MAX_PROCS
;
209 dynamicMinProcs
= FCGI_DEFAULT_MIN_PROCS
;
210 dynamicMaxClassProcs
= FCGI_DEFAULT_MAX_CLASS_PROCS
;
211 dynamicKillInterval
= FCGI_DEFAULT_KILL_INTERVAL
;
212 dynamicUpdateInterval
= FCGI_DEFAULT_UPDATE_INTERVAL
;
213 dynamicGain
= FCGI_DEFAULT_GAIN
;
214 dynamicThreshhold1
= FCGI_DEFAULT_THRESHHOLD_1
;
215 dynamicThreshholdN
= FCGI_DEFAULT_THRESHHOLD_N
;
216 dynamicPleaseStartDelay
= FCGI_DEFAULT_START_PROCESS_DELAY
;
217 dynamicAppConnectTimeout
= FCGI_DEFAULT_APP_CONN_TIMEOUT
;
218 dynamicEnvp
= &fcgi_empty_env
;
219 dynamicProcessSlack
= FCGI_DEFAULT_PROCESS_SLACK
;
220 dynamicAutoRestart
= FCGI_DEFAULT_RESTART_DYNAMIC
;
221 dynamicAutoUpdate
= FCGI_DEFAULT_AUTOUPDATE
;
222 dynamicListenQueueDepth
= FCGI_DEFAULT_LISTEN_Q
;
223 dynamicInitStartDelay
= DEFAULT_INIT_START_DELAY
;
224 dynamicRestartDelay
= FCGI_DEFAULT_RESTART_DELAY
;
225 dynamic_pass_headers
= NULL
;
226 dynamic_idle_timeout
= FCGI_DEFAULT_IDLE_TIMEOUT
;
229 /*******************************************************************************
230 * Create a directory to hold Unix/Domain sockets.
232 const char *fcgi_config_make_dir(pool
*tp
, char *path
)
235 const char *err
= NULL
;
237 /* Is the directory spec'd correctly */
239 return "path is not absolute (it must start with a \"/\")";
242 int i
= strlen(path
) - 1;
244 /* Strip trailing "/"s */
245 while(i
> 0 && path
[i
] == '/') path
[i
--] = '\0';
249 if (stat(path
, &finfo
) != 0) {
250 /* No, but maybe we can create it */
252 if (mkdir(path
) != 0)
254 if (mkdir(path
, S_IRWXU
) != 0)
257 return ap_psprintf(tp
,
258 "doesn't exist and can't be created: %s",
263 /* If we're root, we're gonna setuid/setgid so we need to chown */
264 if (geteuid() == 0 && chown(path
, ap_user_id
, ap_group_id
) != 0) {
265 return ap_psprintf(tp
,
266 "can't chown() to the server (uid %ld, gid %ld): %s",
267 (long)ap_user_id
, (long)ap_group_id
, strerror(errno
));
272 /* Yes, is it a directory? */
273 if (!S_ISDIR(finfo
.st_mode
))
274 return "isn't a directory!";
276 /* Can we RWX in there? */
278 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, _S_IREAD
| _S_IWRITE
| _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
280 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, R_OK
| W_OK
| X_OK
,
281 fcgi_user_id
, fcgi_group_id
);
284 return ap_psprintf(tp
,
285 "access for server (uid %ld, gid %ld) failed: %s",
286 (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
292 /*******************************************************************************
293 * Create a "dynamic" subdirectory. If the directory
294 * already exists we don't mess with it unless 'wax' is set.
296 const char *fcgi_config_make_dynamic_dir(pool
*p
, const int wax
)
300 struct dirent
*dirp
= NULL
;
304 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "/dynamic", NULL
);
306 if ((err
= fcgi_config_make_dir(p
, fcgi_dynamic_dir
)))
307 return ap_psprintf(p
, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir
, err
);
309 /* Don't step on a running server unless its OK. */
313 /* Create a subpool for the directory operations */
314 tp
= ap_make_sub_pool(p
);
316 dp
= ap_popendir(tp
, fcgi_dynamic_dir
);
319 return ap_psprintf(p
, "can't open dynamic directory \"%s\": %s",
320 fcgi_dynamic_dir
, strerror(errno
));
323 /* Delete everything in the directory, its all FCGI specific */
324 while ((dirp
= readdir(dp
)) != NULL
) {
325 if (strcmp(dirp
->d_name
, ".") == 0
326 || strcmp(dirp
->d_name
, "..") == 0) {
330 unlink(ap_pstrcat(tp
, fcgi_dynamic_dir
, "/", dirp
->d_name
, NULL
));
336 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "dynamic", NULL
);
342 /*******************************************************************************
343 * Change the directory used for the Unix/Domain sockets from the default.
344 * Create the directory and the "dynamic" subdirectory.
346 const char *fcgi_config_set_socket_dir(cmd_parms
*cmd
, void *dummy
, char *arg
)
348 pool
* const tp
= cmd
->temp_pool
;
349 const char * const name
= cmd
->cmd
->name
;
352 if (strcmp(fcgi_socket_dir
, DEFAULT_SOCK_DIR
) != 0) {
353 return ap_psprintf(tp
, "%s %s: already defined as \"%s\"",
354 name
, arg
, fcgi_socket_dir
);
357 err
= fcgi_config_set_fcgi_uid_n_gid(1);
359 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
361 if (fcgi_servers
!= NULL
) {
362 return ap_psprintf(tp
,
363 "The %s command must preceed static FastCGI server definitions",
368 if (!ap_os_is_path_absolute(arg
))
369 arg
= ap_make_full_path(cmd
->pool
, ap_server_root
, arg
);
371 if (strncmp(arg
, "\\\\.\\pipe\\", 9) != 0)
372 return ap_psprintf(tp
, "%s %s is invalid format",name
, arg
);
375 fcgi_socket_dir
= arg
;
378 err
= fcgi_config_make_dir(tp
, fcgi_socket_dir
);
380 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
382 err
= fcgi_config_make_dynamic_dir(cmd
->pool
, 0);
384 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
390 /*******************************************************************************
391 * Enable, disable, or specify the path to the suexec program.
393 const char *fcgi_config_set_suexec(cmd_parms
*cmd
, void *dummy
, const char *arg
)
395 const char *err
= NULL
;
396 const char * const name
= cmd
->cmd
->name
;
397 pool
* const tp
= cmd
->temp_pool
;
399 if (!ap_suexec_enabled
) {
400 if (strcasecmp(arg
, "Off") != 0) {
401 fprintf(stderr
, "Warning: %s requires SUEXEC wrapper be enabled in Apache\n", name
);
406 err
= fcgi_config_set_fcgi_uid_n_gid(1);
408 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
410 if (fcgi_servers
!= NULL
) {
411 return ap_psprintf(tp
,
412 "The %s command must preceed static FastCGI server definitions", name
);
415 if (strcasecmp(arg
, "On") == 0) {
416 fcgi_suexec
= SUEXEC_BIN
;
418 else if (strcasecmp(arg
, "Off") == 0) {
422 if (!ap_os_is_path_absolute(arg
))
423 arg
= ap_make_full_path(cmd
->pool
, ap_server_root
, arg
);
426 err
= fcgi_util_check_access(tp
, arg
, NULL
, _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
428 err
= fcgi_util_check_access(tp
, arg
, NULL
, X_OK
, fcgi_user_id
, fcgi_group_id
);
432 return ap_psprintf(tp
,
433 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
434 name
, arg
, (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
442 /*******************************************************************************
443 * Configure a static FastCGI server.
445 const char *fcgi_config_new_static_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
448 pool
*p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
449 const char *name
= cmd
->cmd
->name
;
450 char *fs_path
= ap_getword_conf(p
, &arg
);
451 const char *option
, *err
;
453 /* Allocate temp storage for the array of initial environment variables */
454 char **envp
= ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 1));
457 if (*fs_path
== '\0')
458 return "AppClass requires a pathname!?";
460 if ((err
= fcgi_config_set_fcgi_uid_n_gid(1)) != NULL
)
461 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
463 if (!ap_os_is_path_absolute(fs_path
))
464 fs_path
= ap_make_full_path(p
, ap_server_root
, fs_path
);
466 fs_path
= ap_os_canonical_filename(p
, fs_path
);
468 ap_getparents(fs_path
);
469 ap_no2slash(fs_path
);
471 /* See if we've already got one of these configured */
472 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
473 cmd
->server
->server_gid
);
476 return ap_psprintf(tp
,
477 "%s: redefinition of a previously defined FastCGI server \"%s\" with uid=%ld and gid=%ld",
478 name
, fs_path
, (long)cmd
->server
->server_uid
,
479 (long)cmd
->server
->server_gid
);
482 return ap_psprintf(tp
,
483 "%s: redefinition of a previously defined FastCGI server \"%s\"",
488 err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
, cmd
->server
->server_uid
,
489 cmd
->server
->server_gid
);
491 return ap_psprintf(tp
, "%s: \"%s\" %s", name
, fs_path
, err
);
494 s
= fcgi_util_fs_new(p
);
495 s
->fs_path
= fs_path
;
496 s
->directive
= APP_CLASS_STANDARD
;
497 s
->restartOnExit
= TRUE
;
505 s
->uid
= cmd
->server
->server_uid
;
506 pw
= getpwuid(s
->uid
);
508 return ap_psprintf(tp
, "mod_fastcgi: "
509 "getpwuid() couldn't determine the username for uid '%ld', "
510 "you probably need to modify the User directive: %s",
511 (long)s
->uid
, strerror(errno
));
513 s
->user
= ap_pstrdup(p
, pw
->pw_name
);
514 s
->username
= s
->user
;
516 s
->gid
= cmd
->server
->server_gid
;
517 gr
= getgrgid(s
->gid
);
519 return ap_psprintf(tp
, "mod_fastcgi: "
520 "getgrgid() couldn't determine the group name for gid '%ld', "
521 "you probably need to modify the Group directive: %s\n",
522 (long)s
->gid
, strerror(errno
));
524 s
->group
= ap_pstrdup(p
, gr
->gr_name
);
528 /* Parse directive arguments */
530 option
= ap_getword_conf(tp
, &arg
);
532 if (strcasecmp(option
, "-processes") == 0) {
533 if ((err
= get_u_int(tp
, &arg
, &s
->numProcesses
, 1)))
534 return invalid_value(tp
, name
, fs_path
, option
, err
);
536 else if (strcasecmp(option
, "-restart-delay") == 0) {
537 if ((err
= get_u_int(tp
, &arg
, &s
->restartDelay
, 0)))
538 return invalid_value(tp
, name
, fs_path
, option
, err
);
540 else if (strcasecmp(option
, "-init-start-delay") == 0) {
541 if ((err
= get_u_int(tp
, &arg
, &s
->initStartDelay
, 0)))
542 return invalid_value(tp
, name
, fs_path
, option
, err
);
544 else if (strcasecmp(option
, "-priority") == 0) {
545 if ((err
= get_u_int(tp
, &arg
, &s
->processPriority
, 0)))
546 return invalid_value(tp
, name
, fs_path
, option
, err
);
548 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
549 if ((err
= get_u_int(tp
, &arg
, &s
->listenQueueDepth
, 1)))
550 return invalid_value(tp
, name
, fs_path
, option
, err
);
552 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
553 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
554 return invalid_value(tp
, name
, fs_path
, option
, err
);
556 else if (strcasecmp(option
, "-idle-timeout") == 0) {
557 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
558 return invalid_value(tp
, name
, fs_path
, option
, err
);
560 else if (strcasecmp(option
, "-port") == 0) {
561 if ((err
= get_u_short(tp
, &arg
, &s
->port
, 1)))
562 return invalid_value(tp
, name
, fs_path
, option
, err
);
564 else if (strcasecmp(option
, "-socket") == 0) {
565 s
->socket_path
= ap_getword_conf(tp
, &arg
);
566 if (*s
->socket_path
== '\0')
567 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
569 else if (strcasecmp(option
, "-initial-env") == 0) {
570 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
571 return invalid_value(tp
, name
, fs_path
, option
, err
);
573 else if (strcasecmp(option
, "-pass-header") == 0) {
574 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
575 return invalid_value(tp
, name
, fs_path
, option
, err
);
577 else if (strcasecmp(option
, "-flush") == 0) {
581 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
585 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
586 return ap_psprintf(tp
,
587 "%s %s: -port and -socket are mutually exclusive options",
591 /* If -intial-env option was used, move env array to a surviving pool */
593 s
->envp
= (char **)ap_palloc(p
, sizeof(char *) * envc
);
594 memcpy(s
->envp
, envp
, sizeof(char *) * envc
);
597 /* Initialize process structs */
598 s
->procs
= fcgi_util_fs_create_procs(p
, s
->numProcesses
);
600 /* Build the appropriate sockaddr structure */
602 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
603 &s
->socket_addr_len
, NULL
, s
->port
);
605 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
607 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->dest_addr
,
608 &s
->socket_addr_len
, "localhost", s
->port
);
610 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
613 if (s
->socket_path
== NULL
)
614 s
->socket_path
= fcgi_util_socket_hash_filename(tp
, fs_path
, s
->user
, s
->group
);
615 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
617 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
618 &s
->socket_addr_len
, s
->socket_path
);
620 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
624 /* Add it to the list of FastCGI servers */
630 /*******************************************************************************
631 * Configure a static FastCGI server that is started/managed elsewhere.
633 const char *fcgi_config_new_external_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
636 pool
* const p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
637 const char * const name
= cmd
->cmd
->name
;
638 char *fs_path
= ap_getword_conf(p
, &arg
);
639 const char *option
, *err
;
642 return ap_pstrcat(tp
, name
, " requires a path and either a -socket or -host option", NULL
);
645 if (!ap_os_is_path_absolute(fs_path
))
646 fs_path
= ap_make_full_path(p
, ap_server_root
, fs_path
);
648 fs_path
= ap_os_canonical_filename(p
, fs_path
);
650 ap_getparents(fs_path
);
651 ap_no2slash(fs_path
);
653 /* See if we've already got one of these bettys configured */
654 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
655 cmd
->server
->server_gid
);
657 if (fcgi_suexec
!= NULL
) {
658 return ap_psprintf(tp
,
659 "%s: redefinition of a previously defined class \"%s\" with uid=%ld and gid=%ld",
660 name
, fs_path
, (long)cmd
->server
->server_uid
,
661 (long)cmd
->server
->server_gid
);
664 return ap_psprintf(tp
,
665 "%s: redefinition of previously defined class \"%s\"", name
, fs_path
);
669 s
= fcgi_util_fs_new(p
);
670 s
->fs_path
= fs_path
;
671 s
->directive
= APP_CLASS_EXTERNAL
;
673 err
= fcgi_util_fs_set_uid_n_gid(p
, s
, cmd
->server
->server_uid
, cmd
->server
->server_gid
);
675 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
677 /* Parse directive arguments */
678 while (*arg
!= '\0') {
679 option
= ap_getword_conf(tp
, &arg
);
681 if (strcasecmp(option
, "-host") == 0) {
682 if ((err
= get_host_n_port(p
, &arg
, &s
->host
, &s
->port
)))
683 return invalid_value(tp
, name
, fs_path
, option
, err
);
685 else if (strcasecmp(option
, "-socket") == 0) {
686 s
->socket_path
= ap_getword_conf(tp
, &arg
);
687 if (*s
->socket_path
== '\0')
688 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
690 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
691 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
692 return invalid_value(tp
, name
, fs_path
, option
, err
);
694 else if (strcasecmp(option
, "-idle-timeout") == 0) {
695 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
696 return invalid_value(tp
, name
, fs_path
, option
, err
);
698 else if (strcasecmp(option
, "-pass-header") == 0) {
699 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
700 return invalid_value(tp
, name
, fs_path
, option
, err
);
702 else if (strcasecmp(option
, "-flush") == 0) {
706 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
710 /* Require one of -socket or -host, but not both */
711 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
712 return ap_psprintf(tp
,
713 "%s %s: -host and -socket are mutually exclusive options",
716 if (s
->socket_path
== NULL
&& s
->port
== 0) {
717 return ap_psprintf(tp
,
718 "%s %s: -socket or -host option missing", name
, fs_path
);
721 /* Build the appropriate sockaddr structure */
723 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
724 &s
->socket_addr_len
, s
->host
, s
->port
);
726 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
728 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
730 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
731 &s
->socket_addr_len
, s
->socket_path
);
733 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
737 /* Add it to the list of FastCGI servers */
744 *----------------------------------------------------------------------
746 * fcgi_config_set_config --
748 * Implements the FastCGI FCGIConfig configuration directive.
749 * This command adds routines to control the execution of the
750 * dynamic FastCGI processes.
753 *----------------------------------------------------------------------
755 const char *fcgi_config_set_config(cmd_parms
*cmd
, void *dummy
, const char *arg
)
757 pool
* const p
= cmd
->pool
;
758 pool
* const tp
= cmd
->temp_pool
;
759 const char *err
, *option
;
760 const char * const name
= cmd
->cmd
->name
;
762 /* Allocate temp storage for an initial environment */
764 char **envp
= (char **)ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 1));
766 /* Parse the directive arguments */
768 option
= ap_getword_conf(tp
, &arg
);
770 if (strcasecmp(option
, "-maxProcesses") == 0) {
771 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxProcs
, 1)))
772 return invalid_value(tp
, name
, NULL
, option
, err
);
774 else if (strcasecmp(option
, "-minProcesses") == 0) {
775 if ((err
= get_u_int(tp
, &arg
, &dynamicMinProcs
, 0)))
776 return invalid_value(tp
, name
, NULL
, option
, err
);
778 else if (strcasecmp(option
, "-maxClassProcesses") == 0) {
779 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxClassProcs
, 1)))
780 return invalid_value(tp
, name
, NULL
, option
, err
);
782 else if (strcasecmp(option
, "-killInterval") == 0) {
783 if ((err
= get_u_int(tp
, &arg
, &dynamicKillInterval
, 1)))
784 return invalid_value(tp
, name
, NULL
, option
, err
);
786 else if (strcasecmp(option
, "-updateInterval") == 0) {
787 if ((err
= get_u_int(tp
, &arg
, &dynamicUpdateInterval
, 1)))
788 return invalid_value(tp
, name
, NULL
, option
, err
);
790 else if (strcasecmp(option
, "-gainValue") == 0) {
791 if ((err
= get_float(tp
, &arg
, &dynamicGain
, 0.0, 1.0)))
792 return invalid_value(tp
, name
, NULL
, option
, err
);
794 else if (strcasecmp(option
, "-singleThreshhold") == 0) {
795 if ((err
= get_u_int(tp
, &arg
, &dynamicThreshhold1
, 0)))
796 return invalid_value(tp
, name
, NULL
, option
, err
);
798 else if (strcasecmp(option
, "-multiThreshhold") == 0) {
799 if ((err
= get_u_int(tp
, &arg
, &dynamicThreshholdN
, 0)))
800 return invalid_value(tp
, name
, NULL
, option
, err
);
802 else if (strcasecmp(option
, "-startDelay") == 0) {
803 if ((err
= get_u_int(tp
, &arg
, &dynamicPleaseStartDelay
, 1)))
804 return invalid_value(tp
, name
, NULL
, option
, err
);
806 else if (strcasecmp(option
, "-initial-env") == 0) {
807 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
808 return invalid_value(tp
, name
, NULL
, option
, err
);
810 else if (strcasecmp(option
, "-pass-header") == 0) {
811 if ((err
= get_pass_header(p
, &arg
, &dynamic_pass_headers
)))
812 return invalid_value(tp
, name
, NULL
, option
, err
);
814 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
815 if ((err
= get_u_int(tp
, &arg
, &dynamicAppConnectTimeout
, 0)))
816 return invalid_value(tp
, name
, NULL
, option
, err
);
818 else if (strcasecmp(option
, "-idle-timeout") == 0) {
819 if ((err
= get_u_int(tp
, &arg
, &dynamic_idle_timeout
, 1)))
820 return invalid_value(tp
, name
, NULL
, option
, err
);
822 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
823 if ((err
= get_u_int(tp
, &arg
, &dynamicListenQueueDepth
, 1)))
824 return invalid_value(tp
, name
, NULL
, option
, err
);
826 else if (strcasecmp(option
, "-restart-delay") == 0) {
827 if ((err
= get_u_int(tp
, &arg
, &dynamicRestartDelay
, 0)))
828 return invalid_value(tp
, name
, NULL
, option
, err
);
830 else if (strcasecmp(option
, "-init-start-delay") == 0) {
831 if ((err
= get_u_int(tp
, &arg
, &dynamicInitStartDelay
, 0)))
832 return invalid_value(tp
, name
, NULL
, option
, err
);
834 else if (strcasecmp(option
, "-processSlack") == 0) {
835 if ((err
= get_u_int(tp
, &arg
, &dynamicProcessSlack
, 1)))
836 return invalid_value(tp
, name
, NULL
, option
, err
);
838 else if (strcasecmp(option
, "-restart") == 0) {
839 dynamicAutoRestart
= 1;
841 else if (strcasecmp(option
, "-autoUpdate") == 0) {
842 dynamicAutoUpdate
= 1;
845 return ap_psprintf(tp
, "%s: invalid option: %s", name
, option
);
849 /* If -intial-env option was used, move env array to a surviving pool */
851 dynamicEnvp
= (char **)ap_palloc(p
, sizeof(char *) * envc
);
852 memcpy(dynamicEnvp
, envp
, sizeof(char *) * envc
);
858 void *fcgi_config_create_dir_config(pool
*p
, char *dummy
)
860 fcgi_dir_config
*dir_config
= ap_pcalloc(p
, sizeof(fcgi_dir_config
));
862 dir_config
->authenticator_options
= FCGI_AUTHORITATIVE
;
863 dir_config
->authorizer_options
= FCGI_AUTHORITATIVE
;
864 dir_config
->access_checker_options
= FCGI_AUTHORITATIVE
;
870 const char *fcgi_config_new_auth_server(cmd_parms
* const cmd
,
871 fcgi_dir_config
*dir_config
, const char *fs_path
, const char * const compat
)
873 pool
* const tp
= cmd
->temp_pool
;
874 const uid_t uid
= cmd
->server
->server_uid
;
875 const gid_t gid
= cmd
->server
->server_gid
;
877 if (!ap_os_is_path_absolute(fs_path
))
878 fs_path
= ap_make_full_path(cmd
->pool
, ap_server_root
, fs_path
);
880 /* Make sure its already configured or at least a candidate for dynamic */
881 if (fcgi_util_fs_get_by_id(fs_path
, uid
, gid
) == NULL
) {
882 const char *err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
, uid
, gid
);
884 return ap_psprintf(tp
, "%s: \"%s\" %s", cmd
->cmd
->name
, fs_path
, err
);
887 if (compat
&& strcasecmp(compat
, "-compat"))
888 return ap_psprintf(cmd
->temp_pool
, "%s: unknown option: \"%s\"", cmd
->cmd
->name
, compat
);
890 switch((int)cmd
->info
) {
891 case FCGI_AUTH_TYPE_AUTHENTICATOR
:
892 dir_config
->authenticator
= fs_path
;
893 dir_config
->authenticator_options
|= (compat
) ? FCGI_COMPAT
: 0;
895 case FCGI_AUTH_TYPE_AUTHORIZER
:
896 dir_config
->authorizer
= fs_path
;
897 dir_config
->authorizer_options
|= (compat
) ? FCGI_COMPAT
: 0;
899 case FCGI_AUTH_TYPE_ACCESS_CHECKER
:
900 dir_config
->access_checker
= fs_path
;
901 dir_config
->access_checker_options
|= (compat
) ? FCGI_COMPAT
: 0;
908 const char *fcgi_config_set_authoritative_slot(const cmd_parms
* const cmd
,
909 fcgi_dir_config
* const dir_config
, int arg
)
911 int offset
= (int)(long)cmd
->info
;
914 *(int *)(dir_config
+ offset
) |= FCGI_AUTHORITATIVE
;
916 *(int *)(dir_config
+ offset
) &= ~FCGI_AUTHORITATIVE
;