2 * $Id: fcgi_config.c,v 1.33 2002/07/26 03:10:53 robs Exp $
17 /* warning C4100: unreferenced formal parameter */
18 /* warning C4706: assignment within conditional expression */
19 #pragma warning( disable : 4100 4706 )
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
;
33 *host
= ap_getword_conf(p
, arg
);
37 portStr
= strchr(*host
, ':');
39 return "missing port specification";
41 /* Split the host and port portions */
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
;
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
)
63 const char *txt
= ap_getword_conf(p
, arg
);
69 tmp
= strtol(txt
, &ptr
, 10);
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
);
84 static const char *get_int(pool
*p
, const char **arg
, int *num
, int min
)
87 const char *val
= ap_getword_conf(p
, arg
);
94 *num
= (int) strtol(val
, &cp
, 10);
98 return ap_pstrcat(p
, "can't parse ", "\"", val
, "\"", NULL
);
102 return ap_psprintf(p
, "\"%d\" must be >= %d", *num
, min
);
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
)
116 const char *val
= ap_getword_conf(p
, arg
);
120 *num
= (u_int
)strtol(val
, &ptr
, 10);
123 return ap_pstrcat(p
, "\"", val
, "\" must be a positive integer", NULL
);
125 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
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
)
137 const char *val
= ap_getword_conf(p
, arg
);
141 *num
= (float) strtod(val
, &ptr
);
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
);
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
);
160 *(envp
+ *envc
) = var
;
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
);
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
)
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 #if !defined(WIN32) && !defined(APACHE2)
224 uid_t uid
= geteuid();
225 gid_t gid
= getegid();
229 fcgi_user_id
= (uid_t
)-1;
230 fcgi_group_id
= (gid_t
)-1;
234 uid
= uid
? uid
: ap_user_id
;
235 gid
= gid
? gid
: ap_group_id
;
237 if (isSet
&& (uid
!= fcgi_user_id
|| gid
!= fcgi_group_id
)) {
238 return "User/Group commands must preceed FastCGI server definitions";
250 apcb_t
fcgi_config_reset_globals(void* dummy
)
252 fcgi_config_pool
= NULL
;
254 fcgi_config_set_fcgi_uid_n_gid(0);
256 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
258 fcgi_dynamic_total_proc_count
= 0;
259 fcgi_dynamic_epoch
= 0;
260 fcgi_dynamic_last_analyzed
= 0;
262 dynamicMaxProcs
= FCGI_DEFAULT_MAX_PROCS
;
263 dynamicMinProcs
= FCGI_DEFAULT_MIN_PROCS
;
264 dynamicMaxClassProcs
= FCGI_DEFAULT_MAX_CLASS_PROCS
;
265 dynamicKillInterval
= FCGI_DEFAULT_KILL_INTERVAL
;
266 dynamicUpdateInterval
= FCGI_DEFAULT_UPDATE_INTERVAL
;
267 dynamicGain
= FCGI_DEFAULT_GAIN
;
268 dynamicThreshold1
= FCGI_DEFAULT_THRESHOLD_1
;
269 dynamicThresholdN
= FCGI_DEFAULT_THRESHOLD_N
;
270 dynamicPleaseStartDelay
= FCGI_DEFAULT_START_PROCESS_DELAY
;
271 dynamicAppConnectTimeout
= FCGI_DEFAULT_APP_CONN_TIMEOUT
;
272 dynamicEnvp
= &fcgi_empty_env
;
273 dynamicProcessSlack
= FCGI_DEFAULT_PROCESS_SLACK
;
274 dynamicAutoRestart
= FCGI_DEFAULT_RESTART_DYNAMIC
;
275 dynamicAutoUpdate
= FCGI_DEFAULT_AUTOUPDATE
;
276 dynamicListenQueueDepth
= FCGI_DEFAULT_LISTEN_Q
;
277 dynamicInitStartDelay
= DEFAULT_INIT_START_DELAY
;
278 dynamicRestartDelay
= FCGI_DEFAULT_RESTART_DELAY
;
279 dynamic_pass_headers
= NULL
;
280 dynamic_idle_timeout
= FCGI_DEFAULT_IDLE_TIMEOUT
;
281 dynamicFlush
= FCGI_FLUSH
;
284 /* Close any old pipe (HUP/USR1) */
285 if (fcgi_pm_pipe
[0] != -1) {
286 close(fcgi_pm_pipe
[0]);
287 fcgi_pm_pipe
[0] = -1;
289 if (fcgi_pm_pipe
[1] != -1) {
290 close(fcgi_pm_pipe
[1]);
291 fcgi_pm_pipe
[1] = -1;
298 /*******************************************************************************
299 * Create a directory to hold Unix/Domain sockets.
301 const char *fcgi_config_make_dir(pool
*tp
, char *path
)
304 const char *err
= NULL
;
306 /* Is the directory spec'd correctly */
308 return "path is not absolute (it must start with a \"/\")";
311 int i
= strlen(path
) - 1;
313 /* Strip trailing "/"s */
314 while(i
> 0 && path
[i
] == '/') path
[i
--] = '\0';
318 if (stat(path
, &finfo
) != 0) {
319 /* No, but maybe we can create it */
321 if (mkdir(path
) != 0)
323 if (mkdir(path
, S_IRWXU
) != 0)
326 return ap_psprintf(tp
,
327 "doesn't exist and can't be created: %s",
331 #if !defined(WIN32) && !defined(APACHE2)
332 /* If we're root, we're gonna setuid/setgid so we need to chown */
333 if (geteuid() == 0 && chown(path
, ap_user_id
, ap_group_id
) != 0) {
334 return ap_psprintf(tp
,
335 "can't chown() to the server (uid %ld, gid %ld): %s",
336 (long)ap_user_id
, (long)ap_group_id
, strerror(errno
));
341 /* Yes, is it a directory? */
342 if (!S_ISDIR(finfo
.st_mode
))
343 return "isn't a directory!";
345 /* Can we RWX in there? */
347 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, _S_IREAD
| _S_IWRITE
| _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
349 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, R_OK
| W_OK
| X_OK
,
350 fcgi_user_id
, fcgi_group_id
);
353 return ap_psprintf(tp
,
354 "access for server (uid %ld, gid %ld) failed: %s",
355 (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
361 /*******************************************************************************
362 * Create a "dynamic" subdirectory. If the directory
363 * already exists we don't mess with it unless 'wax' is set.
365 const char *fcgi_config_make_dynamic_dir(pool
*p
, const int wax
)
371 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "/dynamic", NULL
);
373 if ((err
= fcgi_config_make_dir(p
, fcgi_dynamic_dir
)))
374 return ap_psprintf(p
, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir
, err
);
376 /* Don't step on a running server unless its OK. */
385 if (apr_pool_create(&tp
, p
))
386 return "apr_pool_create() failed";
388 if (apr_dir_open(&dir
, fcgi_dynamic_dir
, tp
))
389 return "apr_dir_open() failed";
391 /* delete the contents */
393 while (apr_dir_read(&finfo
, APR_FINFO_NAME
, dir
) == APR_SUCCESS
)
395 if (strcmp(finfo
.name
, ".") == 0 || strcmp(finfo
.name
, "..") == 0)
398 apr_file_remove(finfo
.name
, tp
);
405 struct dirent
*dirp
= NULL
;
407 tp
= ap_make_sub_pool(p
);
409 dp
= ap_popendir(tp
, fcgi_dynamic_dir
);
412 return ap_psprintf(p
, "can't open dynamic directory \"%s\": %s",
413 fcgi_dynamic_dir
, strerror(errno
));
416 /* delete the contents */
418 while ((dirp
= readdir(dp
)) != NULL
)
420 if (strcmp(dirp
->d_name
, ".") == 0 || strcmp(dirp
->d_name
, "..") == 0)
423 unlink(ap_pstrcat(tp
, fcgi_dynamic_dir
, "/", dirp
->d_name
, NULL
));
427 #endif /* !APACHE2 */
432 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "dynamic", NULL
);
438 /*******************************************************************************
439 * Change the directory used for the Unix/Domain sockets from the default.
440 * Create the directory and the "dynamic" subdirectory.
442 const char *fcgi_config_set_socket_dir(cmd_parms
*cmd
, void *dummy
, const char *arg
)
444 pool
* const tp
= cmd
->temp_pool
;
445 const char * const name
= cmd
->cmd
->name
;
449 if (strcmp(fcgi_socket_dir
, DEFAULT_SOCK_DIR
) != 0) {
450 return ap_psprintf(tp
, "%s %s: already defined as \"%s\"",
451 name
, arg
, fcgi_socket_dir
);
454 err
= fcgi_config_set_fcgi_uid_n_gid(1);
456 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
458 if (fcgi_servers
!= NULL
) {
459 return ap_psprintf(tp
,
460 "The %s command must preceed static FastCGI server definitions",
466 arg_nc
= ap_pstrdup(cmd
->pool
, arg
);
469 if (apr_filepath_merge(&arg_nc
, "", arg
, 0, cmd
->pool
))
470 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, arg
);
472 arg_nc
= ap_os_canonical_filename(cmd
->pool
, arg_nc
);
475 arg_nc
= ap_server_root_relative(cmd
->pool
, arg_nc
);
479 if (strncmp(arg_nc
, "\\\\.\\pipe\\", 9) != 0)
480 return ap_psprintf(tp
, "%s %s is invalid format",name
, arg_nc
);
484 fcgi_socket_dir
= arg_nc
;
487 err
= fcgi_config_make_dir(tp
, fcgi_socket_dir
);
489 return ap_psprintf(tp
, "%s %s: %s", name
, arg_nc
, err
);
491 err
= fcgi_config_make_dynamic_dir(cmd
->pool
, 0);
493 return ap_psprintf(tp
, "%s %s: %s", name
, arg_nc
, err
);
499 /*******************************************************************************
500 * Enable, disable, or specify the path to a wrapper used to invoke all
501 * FastCGI applications.
503 const char *fcgi_config_set_wrapper(cmd_parms
*cmd
, void *dummy
, const char *arg
)
507 * AP2TODO use ap_run_get_suexec_identity() (this will be hard as it
508 * takes a request_rec) and/or mod_userdir_user note
510 return ap_psprintf(cmd
->temp_pool
, "%s isn't supported yet under Apache2", cmd
->cmd
->name
);
512 const char *err
= NULL
;
513 const char * const name
= cmd
->cmd
->name
;
514 pool
* const tp
= cmd
->temp_pool
;
517 if (!ap_suexec_enabled
&& strcasecmp(arg
, "On") == 0) {
518 fprintf(stderr
, "Warning: \"%s On\" requires SUEXEC be enabled in Apache", name
);
522 err
= fcgi_config_set_fcgi_uid_n_gid(1);
524 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
526 if (fcgi_servers
!= NULL
) {
527 return ap_psprintf(tp
,
528 "The %s command must preceed static FastCGI server definitions", name
);
531 if (strcasecmp(arg
, "On") == 0) {
532 fcgi_wrapper
= SUEXEC_BIN
;
534 else if (strcasecmp(arg
, "Off") == 0) {
538 wrapper
= (char *) ap_os_canonical_filename(cmd
->pool
, arg
);
539 wrapper
= ap_server_root_relative(cmd
->pool
, wrapper
);
542 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
544 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, X_OK
, fcgi_user_id
, fcgi_group_id
);
548 return ap_psprintf(tp
,
549 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
550 name
, wrapper
, (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
553 fcgi_wrapper
= wrapper
;
556 #endif /* !APACHE2 */
559 /*******************************************************************************
560 * Configure a static FastCGI server.
562 const char *fcgi_config_new_static_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
565 pool
*p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
566 const char *name
= cmd
->cmd
->name
;
567 char *fs_path
= ap_getword_conf(p
, &arg
);
568 const char *option
, *err
;
570 /* Allocate temp storage for the array of initial environment variables */
571 char **envp
= ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
572 unsigned int envc
= 0;
578 if (*fs_path
== '\0')
579 return "AppClass requires a pathname!?";
581 if ((err
= fcgi_config_set_fcgi_uid_n_gid(1)) != NULL
)
582 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
585 if (apr_filepath_merge(&fs_path
, "", fs_path
, 0, p
))
586 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, fs_path
);
588 fs_path
= ap_os_canonical_filename(p
, fs_path
);
590 fs_path
= ap_server_root_relative(p
, fs_path
);
592 ap_getparents(fs_path
);
593 ap_no2slash(fs_path
);
595 /* See if we've already got one of these configured */
596 s
= fcgi_util_fs_get_by_id(fs_path
, fcgi_util_get_server_uid(cmd
->server
),
597 fcgi_util_get_server_gid(cmd
->server
));
600 return ap_psprintf(tp
,
601 "%s: redefinition of a previously defined FastCGI "
602 "server \"%s\" with uid=%ld and gid=%ld",
603 name
, fs_path
, (long) fcgi_util_get_server_uid(cmd
->server
),
604 (long) fcgi_util_get_server_gid(cmd
->server
));
607 return ap_psprintf(tp
,
608 "%s: redefinition of a previously defined FastCGI server \"%s\"",
613 err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
);
615 return ap_psprintf(tp
, "%s: \"%s\" %s", name
, fs_path
, err
);
618 s
= fcgi_util_fs_new(p
);
619 s
->fs_path
= fs_path
;
620 s
->directive
= APP_CLASS_STANDARD
;
621 s
->restartOnExit
= TRUE
;
626 // TCP FastCGI applications require SystemRoot be present in the environment
627 // Put it in both for consistency to the application
628 fcgi_config_set_env_var(tp
, envp
, &envc
, "SystemRoot");
630 mutex
= CreateMutex(NULL
, FALSE
, fs_path
);
634 ap_log_error(FCGI_LOG_ALERT
, fcgi_apache_main_server
,
635 "FastCGI: CreateMutex() failed");
636 return "failed to create FastCGI application accept mutex";
639 SetHandleInformation(mutex
, HANDLE_FLAG_INHERIT
, TRUE
);
641 s
->mutex_env_string
= ap_psprintf(p
, "_FCGI_MUTEX_=%ld", mutex
);
643 #elif !defined(APACHE2)
649 s
->uid
= cmd
->server
->server_uid
;
650 pw
= getpwuid(s
->uid
);
652 return ap_psprintf(tp
, "mod_fastcgi: "
653 "getpwuid() couldn't determine the username for uid '%ld', "
654 "you probably need to modify the User directive: %s",
655 (long)s
->uid
, strerror(errno
));
657 s
->user
= ap_pstrdup(p
, pw
->pw_name
);
658 s
->username
= s
->user
;
660 s
->gid
= cmd
->server
->server_gid
;
661 gr
= getgrgid(s
->gid
);
663 return ap_psprintf(tp
, "mod_fastcgi: "
664 "getgrgid() couldn't determine the group name for gid '%ld', "
665 "you probably need to modify the Group directive: %s\n",
666 (long)s
->gid
, strerror(errno
));
668 s
->group
= ap_pstrdup(p
, gr
->gr_name
);
672 /* Parse directive arguments */
674 option
= ap_getword_conf(tp
, &arg
);
676 if (strcasecmp(option
, "-processes") == 0) {
677 if ((err
= get_u_int(tp
, &arg
, &s
->numProcesses
, 1)))
678 return invalid_value(tp
, name
, fs_path
, option
, err
);
680 else if (strcasecmp(option
, "-restart-delay") == 0) {
681 if ((err
= get_u_int(tp
, &arg
, &s
->restartDelay
, 0)))
682 return invalid_value(tp
, name
, fs_path
, option
, err
);
684 else if (strcasecmp(option
, "-init-start-delay") == 0) {
685 if ((err
= get_int(tp
, &arg
, &s
->initStartDelay
, 0)))
686 return invalid_value(tp
, name
, fs_path
, option
, err
);
688 else if (strcasecmp(option
, "-priority") == 0) {
689 if ((err
= get_u_int(tp
, &arg
, &s
->processPriority
, 0)))
690 return invalid_value(tp
, name
, fs_path
, option
, err
);
692 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
693 if ((err
= get_u_int(tp
, &arg
, &s
->listenQueueDepth
, 1)))
694 return invalid_value(tp
, name
, fs_path
, option
, err
);
696 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
697 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
698 return invalid_value(tp
, name
, fs_path
, option
, err
);
700 else if (strcasecmp(option
, "-idle-timeout") == 0) {
701 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
702 return invalid_value(tp
, name
, fs_path
, option
, err
);
704 else if (strcasecmp(option
, "-port") == 0) {
705 if ((err
= get_u_short(tp
, &arg
, &s
->port
, 1)))
706 return invalid_value(tp
, name
, fs_path
, option
, err
);
708 else if (strcasecmp(option
, "-socket") == 0) {
709 s
->socket_path
= ap_getword_conf(tp
, &arg
);
710 if (*s
->socket_path
== '\0')
711 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
713 else if (strcasecmp(option
, "-initial-env") == 0) {
714 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
715 return invalid_value(tp
, name
, fs_path
, option
, err
);
717 else if (strcasecmp(option
, "-pass-header") == 0) {
718 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
719 return invalid_value(tp
, name
, fs_path
, option
, err
);
721 else if (strcasecmp(option
, "-flush") == 0) {
725 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
729 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
730 return ap_psprintf(tp
,
731 "%s %s: -port and -socket are mutually exclusive options",
735 /* Move env array to a surviving pool */
736 s
->envp
= (char **)ap_pcalloc(p
, sizeof(char *) * (envc
+ 4));
737 memcpy(s
->envp
, envp
, sizeof(char *) * envc
);
739 /* Initialize process structs */
740 s
->procs
= fcgi_util_fs_create_procs(p
, s
->numProcesses
);
742 /* Build the appropriate sockaddr structure */
744 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
745 &s
->socket_addr_len
, NULL
, s
->port
);
747 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
749 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->dest_addr
,
750 &s
->socket_addr_len
, "localhost", s
->port
);
752 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
755 if (s
->socket_path
== NULL
)
756 s
->socket_path
= fcgi_util_socket_hash_filename(tp
, fs_path
, s
->user
, s
->group
);
757 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
759 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
760 &s
->socket_addr_len
, s
->socket_path
);
762 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
766 /* Add it to the list of FastCGI servers */
772 /*******************************************************************************
773 * Configure a static FastCGI server that is started/managed elsewhere.
775 const char *fcgi_config_new_external_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
778 pool
* const p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
779 const char * const name
= cmd
->cmd
->name
;
780 char *fs_path
= ap_getword_conf(p
, &arg
);
781 const char *option
, *err
;
784 return ap_pstrcat(tp
, name
, " requires a path and either a -socket or -host option", NULL
);
788 if (apr_filepath_merge(&fs_path
, "", fs_path
, 0, p
))
789 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, fs_path
);
791 fs_path
= ap_os_canonical_filename(p
, fs_path
);
794 fs_path
= ap_server_root_relative(p
, fs_path
);
796 ap_getparents(fs_path
);
797 ap_no2slash(fs_path
);
799 /* See if we've already got one of these bettys configured */
800 s
= fcgi_util_fs_get_by_id(fs_path
, fcgi_util_get_server_uid(cmd
->server
),
801 fcgi_util_get_server_gid(cmd
->server
));
804 return ap_psprintf(tp
,
805 "%s: redefinition of a previously defined class \"%s\" "
806 "with uid=%ld and gid=%ld",
807 name
, fs_path
, (long) fcgi_util_get_server_uid(cmd
->server
),
808 (long) fcgi_util_get_server_gid(cmd
->server
));
812 return ap_psprintf(tp
,
813 "%s: redefinition of previously defined class \"%s\"", name
, fs_path
);
817 s
= fcgi_util_fs_new(p
);
818 s
->fs_path
= fs_path
;
819 s
->directive
= APP_CLASS_EXTERNAL
;
821 err
= fcgi_util_fs_set_uid_n_gid(p
, s
, fcgi_util_get_server_uid(cmd
->server
),
822 fcgi_util_get_server_gid(cmd
->server
));
824 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
826 /* Parse directive arguments */
827 while (*arg
!= '\0') {
828 option
= ap_getword_conf(tp
, &arg
);
830 if (strcasecmp(option
, "-host") == 0) {
831 if ((err
= get_host_n_port(p
, &arg
, &s
->host
, &s
->port
)))
832 return invalid_value(tp
, name
, fs_path
, option
, err
);
834 else if (strcasecmp(option
, "-socket") == 0) {
835 s
->socket_path
= ap_getword_conf(tp
, &arg
);
836 if (*s
->socket_path
== '\0')
837 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
839 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
840 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
841 return invalid_value(tp
, name
, fs_path
, option
, err
);
843 else if (strcasecmp(option
, "-idle-timeout") == 0) {
844 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
845 return invalid_value(tp
, name
, fs_path
, option
, err
);
847 else if (strcasecmp(option
, "-pass-header") == 0) {
848 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
849 return invalid_value(tp
, name
, fs_path
, option
, err
);
851 else if (strcasecmp(option
, "-flush") == 0) {
855 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
859 /* Require one of -socket or -host, but not both */
860 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
861 return ap_psprintf(tp
,
862 "%s %s: -host and -socket are mutually exclusive options",
865 if (s
->socket_path
== NULL
&& s
->port
== 0) {
866 return ap_psprintf(tp
,
867 "%s %s: -socket or -host option missing", name
, fs_path
);
870 /* Build the appropriate sockaddr structure */
872 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
873 &s
->socket_addr_len
, s
->host
, s
->port
);
875 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
877 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
879 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
880 &s
->socket_addr_len
, s
->socket_path
);
882 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
886 /* Add it to the list of FastCGI servers */
893 *----------------------------------------------------------------------
895 * fcgi_config_set_config --
897 * Implements the FastCGI FCGIConfig configuration directive.
898 * This command adds routines to control the execution of the
899 * dynamic FastCGI processes.
902 *----------------------------------------------------------------------
904 const char *fcgi_config_set_config(cmd_parms
*cmd
, void *dummy
, const char *arg
)
906 pool
* const p
= cmd
->pool
;
907 pool
* const tp
= cmd
->temp_pool
;
908 const char *err
, *option
;
909 const char * const name
= cmd
->cmd
->name
;
911 /* Allocate temp storage for an initial environment */
912 unsigned int envc
= 0;
913 char **envp
= (char **)ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
915 /* Parse the directive arguments */
917 option
= ap_getword_conf(tp
, &arg
);
919 if (strcasecmp(option
, "-maxProcesses") == 0) {
920 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxProcs
, 1)))
921 return invalid_value(tp
, name
, NULL
, option
, err
);
923 else if (strcasecmp(option
, "-minProcesses") == 0) {
924 if ((err
= get_int(tp
, &arg
, &dynamicMinProcs
, 0)))
925 return invalid_value(tp
, name
, NULL
, option
, err
);
927 else if (strcasecmp(option
, "-maxClassProcesses") == 0) {
928 if ((err
= get_int(tp
, &arg
, &dynamicMaxClassProcs
, 1)))
929 return invalid_value(tp
, name
, NULL
, option
, err
);
931 else if (strcasecmp(option
, "-killInterval") == 0) {
932 if ((err
= get_u_int(tp
, &arg
, &dynamicKillInterval
, 1)))
933 return invalid_value(tp
, name
, NULL
, option
, err
);
935 else if (strcasecmp(option
, "-updateInterval") == 0) {
936 if ((err
= get_u_int(tp
, &arg
, &dynamicUpdateInterval
, 1)))
937 return invalid_value(tp
, name
, NULL
, option
, err
);
939 else if (strcasecmp(option
, "-gainValue") == 0) {
940 if ((err
= get_float(tp
, &arg
, &dynamicGain
, 0.0, 1.0)))
941 return invalid_value(tp
, name
, NULL
, option
, err
);
943 else if ((strcasecmp(option
, "-singleThreshold") == 0)
944 || (strcasecmp(option
, "-singleThreshhold") == 0))
946 if ((err
= get_int(tp
, &arg
, &dynamicThreshold1
, 0)))
947 return invalid_value(tp
, name
, NULL
, option
, err
);
949 else if ((strcasecmp(option
, "-multiThreshold") == 0)
950 || (strcasecmp(option
, "-multiThreshhold") == 0))
952 if ((err
= get_int(tp
, &arg
, &dynamicThresholdN
, 0)))
953 return invalid_value(tp
, name
, NULL
, option
, err
);
955 else if (strcasecmp(option
, "-startDelay") == 0) {
956 if ((err
= get_u_int(tp
, &arg
, &dynamicPleaseStartDelay
, 1)))
957 return invalid_value(tp
, name
, NULL
, option
, err
);
959 else if (strcasecmp(option
, "-initial-env") == 0) {
960 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
961 return invalid_value(tp
, name
, NULL
, option
, err
);
963 else if (strcasecmp(option
, "-pass-header") == 0) {
964 if ((err
= get_pass_header(p
, &arg
, &dynamic_pass_headers
)))
965 return invalid_value(tp
, name
, NULL
, option
, err
);
967 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
968 if ((err
= get_u_int(tp
, &arg
, &dynamicAppConnectTimeout
, 0)))
969 return invalid_value(tp
, name
, NULL
, option
, err
);
971 else if (strcasecmp(option
, "-idle-timeout") == 0) {
972 if ((err
= get_u_int(tp
, &arg
, &dynamic_idle_timeout
, 1)))
973 return invalid_value(tp
, name
, NULL
, option
, err
);
975 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
976 if ((err
= get_u_int(tp
, &arg
, &dynamicListenQueueDepth
, 1)))
977 return invalid_value(tp
, name
, NULL
, option
, err
);
979 else if (strcasecmp(option
, "-restart-delay") == 0) {
980 if ((err
= get_u_int(tp
, &arg
, &dynamicRestartDelay
, 0)))
981 return invalid_value(tp
, name
, NULL
, option
, err
);
983 else if (strcasecmp(option
, "-init-start-delay") == 0) {
984 if ((err
= get_u_int(tp
, &arg
, &dynamicInitStartDelay
, 0)))
985 return invalid_value(tp
, name
, NULL
, option
, err
);
987 else if (strcasecmp(option
, "-processSlack") == 0) {
988 if ((err
= get_u_int(tp
, &arg
, &dynamicProcessSlack
, 1)))
989 return invalid_value(tp
, name
, NULL
, option
, err
);
991 else if (strcasecmp(option
, "-restart") == 0) {
992 dynamicAutoRestart
= 1;
994 else if (strcasecmp(option
, "-autoUpdate") == 0) {
995 dynamicAutoUpdate
= 1;
997 else if (strcasecmp(option
, "-flush") == 0) {
1001 return ap_psprintf(tp
, "%s: invalid option: %s", name
, option
);
1005 if (dynamicProcessSlack
>= dynamicMaxProcs
+ 1) {
1006 /* the kill policy would work unexpectedly */
1007 return ap_psprintf(tp
,
1008 "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
1009 name
, dynamicProcessSlack
, dynamicMaxProcs
);
1012 /* Move env array to a surviving pool, leave 2 extra slots for
1013 * WIN32 _FCGI_MUTEX_ and _FCGI_SHUTDOWN_EVENT_ */
1014 dynamicEnvp
= (char **)ap_pcalloc(p
, sizeof(char *) * (envc
+ 4));
1015 memcpy(dynamicEnvp
, envp
, sizeof(char *) * envc
);
1020 void *fcgi_config_create_dir_config(pool
*p
, char *dummy
)
1022 fcgi_dir_config
*dir_config
= ap_pcalloc(p
, sizeof(fcgi_dir_config
));
1024 dir_config
->authenticator_options
= FCGI_AUTHORITATIVE
;
1025 dir_config
->authorizer_options
= FCGI_AUTHORITATIVE
;
1026 dir_config
->access_checker_options
= FCGI_AUTHORITATIVE
;
1032 const char *fcgi_config_new_auth_server(cmd_parms
* cmd
,
1033 void * dircfg
, const char *fs_path
, const char * compat
)
1035 fcgi_dir_config
* dir_config
= (fcgi_dir_config
*) dircfg
;
1036 pool
* const tp
= cmd
->temp_pool
;
1040 if (apr_filepath_merge(&auth_server
, "", fs_path
, 0, cmd
->pool
))
1041 return ap_psprintf(tp
, "%s %s: invalid filepath", cmd
->cmd
->name
, fs_path
);
1043 auth_server
= (char *) ap_os_canonical_filename(cmd
->pool
, fs_path
);
1046 auth_server
= ap_server_root_relative(cmd
->pool
, auth_server
);
1048 /* Make sure its already configured or at least a candidate for dynamic */
1049 if (fcgi_util_fs_get_by_id(auth_server
, fcgi_util_get_server_uid(cmd
->server
),
1050 fcgi_util_get_server_gid(cmd
->server
)) == NULL
)
1052 const char *err
= fcgi_util_fs_is_path_ok(tp
, auth_server
, NULL
);
1054 return ap_psprintf(tp
, "%s: \"%s\" %s", cmd
->cmd
->name
, auth_server
, err
);
1057 if (compat
&& strcasecmp(compat
, "-compat"))
1058 return ap_psprintf(cmd
->temp_pool
, "%s: unknown option: \"%s\"", cmd
->cmd
->name
, compat
);
1060 switch((int)cmd
->info
) {
1061 case FCGI_AUTH_TYPE_AUTHENTICATOR
:
1062 dir_config
->authenticator
= auth_server
;
1063 dir_config
->authenticator_options
|= (compat
) ? FCGI_COMPAT
: 0;
1065 case FCGI_AUTH_TYPE_AUTHORIZER
:
1066 dir_config
->authorizer
= auth_server
;
1067 dir_config
->authorizer_options
|= (compat
) ? FCGI_COMPAT
: 0;
1069 case FCGI_AUTH_TYPE_ACCESS_CHECKER
:
1070 dir_config
->access_checker
= auth_server
;
1071 dir_config
->access_checker_options
|= (compat
) ? FCGI_COMPAT
: 0;
1078 const char *fcgi_config_set_authoritative_slot(cmd_parms
* cmd
,
1079 void * dir_config
, int arg
)
1081 int offset
= (int)(long)cmd
->info
;
1084 *((u_char
*)dir_config
+ offset
) |= FCGI_AUTHORITATIVE
;
1086 *((u_char
*)dir_config
+ offset
) &= ~FCGI_AUTHORITATIVE
;