Beta WinNT support. David Allen [djallen@raleigh.ibm.com]
[mod_fastcgi.git] / fcgi_config.c
blob3b161874b3f6377d0d0ba76a2fc5268319422cbc
1 /*
2 * $Id: fcgi_config.c,v 1.18 2000/04/27 02:27:35 robs Exp $
3 */
5 #include "fcgi.h"
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);
19 if (**host == '\0')
20 return "\"\"";
22 portStr = strchr(*host, ':');
23 if (portStr == NULL)
24 return "missing port specification";
26 /* Split the host and port portions */
27 *portStr++ = '\0';
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);
34 return 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)
44 char *ptr;
45 long tmp;
46 const char *txt = ap_getword_conf(p, arg);
48 if (*txt == '\0') {
49 return "\"\"";
52 tmp = strtol(txt, &ptr, 10);
54 if (*ptr != '\0') {
55 return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
58 if (tmp < min) {
59 return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
62 *num = (u_short) tmp;
64 return NULL;
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)
74 char *ptr;
75 const char *val = ap_getword_conf(p, arg);
77 if (*val == '\0')
78 return "\"\"";
79 *num = (u_int)strtol(val, &ptr, 10);
81 if (*ptr != '\0')
82 return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
83 else if (*num < min)
84 return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
85 return NULL;
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)
95 char *ptr;
96 const char *val = ap_getword_conf(p, arg);
98 if (*val == '\0')
99 return "\"\"";
100 *num = (float) strtod(val, &ptr);
102 if (*ptr != '\0')
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);
106 return NULL;
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);
117 if (*val == '\0')
118 return "\"\"";
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);
125 else
126 *(envp + *envc) = val;
128 (*envc)++;
130 return NULL;
133 static const char *get_pass_header(pool *p, const char **arg, array_header **array)
135 const char **header;
137 if (!*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;
171 #ifndef WIN32
172 uid_t uid = geteuid();
173 gid_t gid = getegid();
175 if (set == 0) {
176 isSet = 0;
177 fcgi_user_id = (uid_t)-1;
178 fcgi_group_id = (gid_t)-1;
179 return NULL;
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";
189 isSet = 1;
190 fcgi_user_id = uid;
191 fcgi_group_id = gid;
192 #endif
193 return NULL;
196 void fcgi_config_reset_globals(void* dummy)
198 fcgi_config_pool = NULL;
199 fcgi_servers = NULL;
200 fcgi_config_set_fcgi_uid_n_gid(0);
201 fcgi_suexec = NULL;
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)
234 struct stat finfo;
235 const char *err = NULL;
237 /* Is the directory spec'd correctly */
238 if (*path != '/') {
239 return "path is not absolute (it must start with a \"/\")";
241 else {
242 int i = strlen(path) - 1;
244 /* Strip trailing "/"s */
245 while(i > 0 && path[i] == '/') path[i--] = '\0';
248 /* Does it exist? */
249 if (stat(path, &finfo) != 0) {
250 /* No, but maybe we can create it */
251 #ifdef WIN32
252 if (mkdir(path) != 0)
253 #else
254 if (mkdir(path, S_IRWXU) != 0)
255 #endif
257 return ap_psprintf(tp,
258 "doesn't exist and can't be created: %s",
259 strerror(errno));
262 #ifndef WIN32
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));
269 #endif
271 else {
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? */
277 #ifdef WIN32
278 err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
279 #else
280 err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
281 fcgi_user_id, fcgi_group_id);
282 #endif
283 if (err != NULL) {
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);
289 return NULL;
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)
298 #ifndef WIN32
299 DIR *dp = NULL;
300 struct dirent *dirp = NULL;
301 const char *err;
302 pool *tp;
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. */
310 if (!wax)
311 return NULL;
313 /* Create a subpool for the directory operations */
314 tp = ap_make_sub_pool(p);
316 dp = ap_popendir(tp, fcgi_dynamic_dir);
317 if (dp == NULL) {
318 ap_destroy_pool(tp);
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) {
327 continue;
330 unlink(ap_pstrcat(tp, fcgi_dynamic_dir, "/", dirp->d_name, NULL));
333 ap_destroy_pool(tp);
335 #else
336 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "dynamic", NULL);
337 #endif
338 return 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;
350 const char *err;
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);
358 if (err != NULL)
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",
364 name);
367 #ifndef WIN32
368 if (!ap_os_is_path_absolute(arg))
369 arg = ap_make_full_path(cmd->pool, ap_server_root, arg);
370 #else
371 if (strncmp(arg, "\\\\.\\pipe\\", 9) != 0)
372 return ap_psprintf(tp, "%s %s is invalid format",name, arg);
373 #endif
375 fcgi_socket_dir = arg;
377 #ifndef WIN32
378 err = fcgi_config_make_dir(tp, fcgi_socket_dir);
379 if (err != NULL)
380 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
382 err = fcgi_config_make_dynamic_dir(cmd->pool, 0);
383 if (err != NULL)
384 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
385 #endif
387 return NULL;
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);
403 return NULL;
406 err = fcgi_config_set_fcgi_uid_n_gid(1);
407 if (err != NULL)
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) {
419 fcgi_suexec = NULL;
421 else {
422 if (!ap_os_is_path_absolute(arg))
423 arg = ap_make_full_path(cmd->pool, ap_server_root, arg);
425 #ifdef WIN32
426 err = fcgi_util_check_access(tp, arg, NULL, _S_IEXEC, fcgi_user_id, fcgi_group_id);
427 #else
428 err = fcgi_util_check_access(tp, arg, NULL, X_OK, fcgi_user_id, fcgi_group_id);
429 #endif
431 if (err != NULL) {
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);
437 fcgi_suexec = arg;
439 return NULL;
442 /*******************************************************************************
443 * Configure a static FastCGI server.
445 const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
447 fcgi_server *s;
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));
455 int envc = 0;
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);
474 if (s != NULL) {
475 if (fcgi_suexec) {
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);
481 else {
482 return ap_psprintf(tp,
483 "%s: redefinition of a previously defined FastCGI server \"%s\"",
484 name, fs_path);
488 err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL, cmd->server->server_uid,
489 cmd->server->server_gid);
490 if (err != NULL) {
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;
498 s->numProcesses = 1;
500 #ifndef WIN32
501 if (fcgi_suexec) {
502 struct passwd *pw;
503 struct group *gr;
505 s->uid = cmd->server->server_uid;
506 pw = getpwuid(s->uid);
507 if (pw == NULL) {
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);
518 if (gr == NULL) {
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);
526 #endif
528 /* Parse directive arguments */
529 while (*arg) {
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) {
578 s->flush = 1;
580 else {
581 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
583 } /* while */
585 if (s->socket_path != NULL && s->port != 0) {
586 return ap_psprintf(tp,
587 "%s %s: -port and -socket are mutually exclusive options",
588 name, fs_path);
591 /* If -intial-env option was used, move env array to a surviving pool */
592 if (envc++) {
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 */
601 if (s->port != 0) {
602 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
603 &s->socket_addr_len, NULL, s->port);
604 if (err != NULL)
605 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
606 #ifdef WIN32
607 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
608 &s->socket_addr_len, "localhost", s->port);
609 if (err != NULL)
610 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
611 #endif
612 } else {
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);
616 #ifndef WIN32
617 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
618 &s->socket_addr_len, s->socket_path);
619 if (err != NULL)
620 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
621 #endif
624 /* Add it to the list of FastCGI servers */
625 fcgi_util_fs_add(s);
627 return NULL;
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)
635 fcgi_server *s;
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;
641 if (!*fs_path) {
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);
656 if (s != NULL) {
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);
663 else {
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);
674 if (err != NULL)
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) {
703 s->flush = 1;
705 else {
706 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
708 } /* while */
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",
714 name, fs_path);
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 */
722 if (s->port != 0) {
723 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
724 &s->socket_addr_len, s->host, s->port);
725 if (err != NULL)
726 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
727 } else {
728 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
729 #ifndef WIN32
730 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
731 &s->socket_addr_len, s->socket_path);
732 if (err != NULL)
733 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
734 #endif
737 /* Add it to the list of FastCGI servers */
738 fcgi_util_fs_add(s);
740 return NULL;
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 */
763 int envc = 0;
764 char **envp = (char **)ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 1));
766 /* Parse the directive arguments */
767 while (*arg) {
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;
844 else {
845 return ap_psprintf(tp, "%s: invalid option: %s", name, option);
847 } /* while */
849 /* If -intial-env option was used, move env array to a surviving pool */
850 if (envc++) {
851 dynamicEnvp = (char **)ap_palloc(p, sizeof(char *) * envc);
852 memcpy(dynamicEnvp, envp, sizeof(char *) * envc);
855 return NULL;
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;
866 return dir_config;
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);
883 if (err)
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;
894 break;
895 case FCGI_AUTH_TYPE_AUTHORIZER:
896 dir_config->authorizer = fs_path;
897 dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
898 break;
899 case FCGI_AUTH_TYPE_ACCESS_CHECKER:
900 dir_config->access_checker = fs_path;
901 dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
902 break;
905 return NULL;
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;
913 if (arg)
914 *(int *)(dir_config + offset) |= FCGI_AUTHORITATIVE;
915 else
916 *(int *)(dir_config + offset) &= ~FCGI_AUTHORITATIVE;
918 return NULL;