remove a couple of debug lines
[mod_fastcgi.git] / fcgi_config.c
blob92030c90205aebc6d431fdaf4a0157d7b6103a89
1 /*
2 * $Id: fcgi_config.c,v 1.31 2002/02/04 19:39:32 robs Exp $
3 */
5 #include "fcgi.h"
7 #ifdef WIN32
8 #pragma warning( disable : 4100 4706 )
9 #endif
11 /*******************************************************************************
12 * Get the next configuration directive argument, & return an in_addr and port.
13 * The arg must be in the form "host:port" where host can be an IP or hostname.
14 * The pool arg should be persistant storage.
16 static const char *get_host_n_port(pool *p, const char **arg,
17 const char **host, u_short *port)
19 char *cvptr, *portStr;
20 long tmp;
22 *host = ap_getword_conf(p, arg);
23 if (**host == '\0')
24 return "\"\"";
26 portStr = strchr(*host, ':');
27 if (portStr == NULL)
28 return "missing port specification";
30 /* Split the host and port portions */
31 *portStr++ = '\0';
33 /* Convert port number */
34 tmp = (u_short) strtol(portStr, &cvptr, 10);
35 if (*cvptr != '\0' || tmp < 1 || tmp > USHRT_MAX)
36 return ap_pstrcat(p, "bad port number \"", portStr, "\"", NULL);
38 *port = (unsigned short) tmp;
40 return NULL;
43 /*******************************************************************************
44 * Get the next configuration directive argument, & return an u_short.
45 * The pool arg should be temporary storage.
47 static const char *get_u_short(pool *p, const char **arg,
48 u_short *num, u_short min)
50 char *ptr;
51 long tmp;
52 const char *txt = ap_getword_conf(p, arg);
54 if (*txt == '\0') {
55 return "\"\"";
58 tmp = strtol(txt, &ptr, 10);
60 if (*ptr != '\0') {
61 return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
64 if (tmp < min || tmp > USHRT_MAX) {
65 return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX);
68 *num = (u_short) tmp;
70 return NULL;
73 static const char *get_int(pool *p, const char **arg, int *num, int min)
75 char *cp;
76 const char *val = ap_getword_conf(p, arg);
78 if (*val == '\0')
80 return "\"\"";
83 *num = (int) strtol(val, &cp, 10);
85 if (*cp != '\0')
87 return ap_pstrcat(p, "can't parse ", "\"", val, "\"", NULL);
89 else if (*num < min)
91 return ap_psprintf(p, "\"%d\" must be >= %d", *num, min);
94 return NULL;
97 /*******************************************************************************
98 * Get the next configuration directive argument, & return an u_int.
99 * The pool arg should be temporary storage.
101 static const char *get_u_int(pool *p, const char **arg,
102 u_int *num, u_int min)
104 char *ptr;
105 const char *val = ap_getword_conf(p, arg);
107 if (*val == '\0')
108 return "\"\"";
109 *num = (u_int)strtol(val, &ptr, 10);
111 if (*ptr != '\0')
112 return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
113 else if (*num < min)
114 return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
115 return NULL;
118 /*******************************************************************************
119 * Get the next configuration directive argument, & return a float.
120 * The pool arg should be temporary storage.
122 static const char *get_float(pool *p, const char **arg,
123 float *num, float min, float max)
125 char *ptr;
126 const char *val = ap_getword_conf(p, arg);
128 if (*val == '\0')
129 return "\"\"";
130 *num = (float) strtod(val, &ptr);
132 if (*ptr != '\0')
133 return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL);
134 if (*num < min || *num > max)
135 return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max);
136 return NULL;
139 const char *fcgi_config_set_env_var(pool *p, char **envp, unsigned int *envc, char * var)
141 if (*envc >= MAX_INIT_ENV_VARS) {
142 return "too many variables, must be <= MAX_INIT_ENV_VARS";
145 if (strchr(var, '=') == NULL) {
146 *(envp + *envc) = ap_pstrcat(p, var, "=", getenv(var), NULL);
148 else {
149 *(envp + *envc) = var;
152 (*envc)++;
154 return NULL;
157 /*******************************************************************************
158 * Get the next configuration directive argument, & add it to an env array.
159 * The pool arg should be permanent storage.
161 static const char *get_env_var(pool *p, const char **arg, char **envp, unsigned int *envc)
163 char * const val = ap_getword_conf(p, arg);
165 if (*val == '\0') {
166 return "\"\"";
169 return fcgi_config_set_env_var(p, envp, envc, val);
172 static const char *get_pass_header(pool *p, const char **arg, array_header **array)
174 const char **header;
176 if (!*array) {
177 *array = ap_make_array(p, 10, sizeof(char*));
180 header = (const char **)ap_push_array(*array);
181 *header = ap_getword_conf(p, arg);
183 return header ? NULL : "\"\"";
186 /*******************************************************************************
187 * Return a "standard" message for common configuration errors.
189 static const char *invalid_value(pool *p, const char *cmd, const char *id,
190 const char *opt, const char *err)
192 return ap_psprintf(p, "%s%s%s: invalid value for %s: %s",
193 cmd, id ? " " : "", id ? id : "", opt, err);
196 /*******************************************************************************
197 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
198 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
199 * to check that the config files don't set the User/Group after a FastCGI
200 * directive is used that depends on it.
202 /*@@@ To be complete, we should save a handle to the server each AppClass is
203 * configured in and at init() check that the user/group is still what we
204 * thought it was. Also the other directives should only be allowed in the
205 * parent Apache server.
207 const char *fcgi_config_set_fcgi_uid_n_gid(int set)
209 static int isSet = 0;
210 #ifndef WIN32
211 uid_t uid = geteuid();
212 gid_t gid = getegid();
214 if (set == 0) {
215 isSet = 0;
216 fcgi_user_id = (uid_t)-1;
217 fcgi_group_id = (gid_t)-1;
218 return NULL;
221 uid = uid ? uid : ap_user_id;
222 gid = gid ? gid : ap_group_id;
224 if (isSet && (uid != fcgi_user_id || gid != fcgi_group_id)) {
225 return "User/Group commands must preceed FastCGI server definitions";
228 isSet = 1;
229 fcgi_user_id = uid;
230 fcgi_group_id = gid;
231 #endif
232 return NULL;
235 void fcgi_config_reset_globals(void* dummy)
237 fcgi_config_pool = NULL;
238 fcgi_servers = NULL;
239 fcgi_config_set_fcgi_uid_n_gid(0);
240 fcgi_wrapper = NULL;
241 fcgi_socket_dir = DEFAULT_SOCK_DIR;
243 fcgi_dynamic_total_proc_count = 0;
244 fcgi_dynamic_epoch = 0;
245 fcgi_dynamic_last_analyzed = 0;
247 dynamicMaxProcs = FCGI_DEFAULT_MAX_PROCS;
248 dynamicMinProcs = FCGI_DEFAULT_MIN_PROCS;
249 dynamicMaxClassProcs = FCGI_DEFAULT_MAX_CLASS_PROCS;
250 dynamicKillInterval = FCGI_DEFAULT_KILL_INTERVAL;
251 dynamicUpdateInterval = FCGI_DEFAULT_UPDATE_INTERVAL;
252 dynamicGain = FCGI_DEFAULT_GAIN;
253 dynamicThreshold1 = FCGI_DEFAULT_THRESHOLD_1;
254 dynamicThresholdN = FCGI_DEFAULT_THRESHOLD_N;
255 dynamicPleaseStartDelay = FCGI_DEFAULT_START_PROCESS_DELAY;
256 dynamicAppConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
257 dynamicEnvp = &fcgi_empty_env;
258 dynamicProcessSlack = FCGI_DEFAULT_PROCESS_SLACK;
259 dynamicAutoRestart = FCGI_DEFAULT_RESTART_DYNAMIC;
260 dynamicAutoUpdate = FCGI_DEFAULT_AUTOUPDATE;
261 dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
262 dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
263 dynamicRestartDelay = FCGI_DEFAULT_RESTART_DELAY;
264 dynamic_pass_headers = NULL;
265 dynamic_idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
266 dynamicFlush = FCGI_FLUSH;
268 #ifndef WIN32
269 /* Close any old pipe (HUP/USR1) */
270 if (fcgi_pm_pipe[0] != -1) {
271 close(fcgi_pm_pipe[0]);
272 fcgi_pm_pipe[0] = -1;
274 if (fcgi_pm_pipe[1] != -1) {
275 close(fcgi_pm_pipe[1]);
276 fcgi_pm_pipe[1] = -1;
278 #endif
281 /*******************************************************************************
282 * Create a directory to hold Unix/Domain sockets.
284 const char *fcgi_config_make_dir(pool *tp, char *path)
286 struct stat finfo;
287 const char *err = NULL;
289 /* Is the directory spec'd correctly */
290 if (*path != '/') {
291 return "path is not absolute (it must start with a \"/\")";
293 else {
294 int i = strlen(path) - 1;
296 /* Strip trailing "/"s */
297 while(i > 0 && path[i] == '/') path[i--] = '\0';
300 /* Does it exist? */
301 if (stat(path, &finfo) != 0) {
302 /* No, but maybe we can create it */
303 #ifdef WIN32
304 if (mkdir(path) != 0)
305 #else
306 if (mkdir(path, S_IRWXU) != 0)
307 #endif
309 return ap_psprintf(tp,
310 "doesn't exist and can't be created: %s",
311 strerror(errno));
314 #ifndef WIN32
315 /* If we're root, we're gonna setuid/setgid so we need to chown */
316 if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) {
317 return ap_psprintf(tp,
318 "can't chown() to the server (uid %ld, gid %ld): %s",
319 (long)ap_user_id, (long)ap_group_id, strerror(errno));
321 #endif
323 else {
324 /* Yes, is it a directory? */
325 if (!S_ISDIR(finfo.st_mode))
326 return "isn't a directory!";
328 /* Can we RWX in there? */
329 #ifdef WIN32
330 err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
331 #else
332 err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
333 fcgi_user_id, fcgi_group_id);
334 #endif
335 if (err != NULL) {
336 return ap_psprintf(tp,
337 "access for server (uid %ld, gid %ld) failed: %s",
338 (long)fcgi_user_id, (long)fcgi_group_id, err);
341 return NULL;
344 /*******************************************************************************
345 * Create a "dynamic" subdirectory. If the directory
346 * already exists we don't mess with it unless 'wax' is set.
348 const char *fcgi_config_make_dynamic_dir(pool *p, const int wax)
350 #ifndef WIN32
351 DIR *dp = NULL;
352 struct dirent *dirp = NULL;
353 const char *err;
354 pool *tp;
356 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "/dynamic", NULL);
358 if ((err = fcgi_config_make_dir(p, fcgi_dynamic_dir)))
359 return ap_psprintf(p, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir, err);
361 /* Don't step on a running server unless its OK. */
362 if (!wax)
363 return NULL;
365 /* Create a subpool for the directory operations */
366 tp = ap_make_sub_pool(p);
368 dp = ap_popendir(tp, fcgi_dynamic_dir);
369 if (dp == NULL) {
370 ap_destroy_pool(tp);
371 return ap_psprintf(p, "can't open dynamic directory \"%s\": %s",
372 fcgi_dynamic_dir, strerror(errno));
375 /* Delete everything in the directory, its all FCGI specific */
376 while ((dirp = readdir(dp)) != NULL) {
377 if (strcmp(dirp->d_name, ".") == 0
378 || strcmp(dirp->d_name, "..") == 0) {
379 continue;
382 unlink(ap_pstrcat(tp, fcgi_dynamic_dir, "/", dirp->d_name, NULL));
385 ap_destroy_pool(tp);
387 #else
388 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "dynamic", NULL);
389 #endif
390 return NULL;
394 /*******************************************************************************
395 * Change the directory used for the Unix/Domain sockets from the default.
396 * Create the directory and the "dynamic" subdirectory.
398 const char *fcgi_config_set_socket_dir(cmd_parms *cmd, void *dummy, char *arg)
400 pool * const tp = cmd->temp_pool;
401 const char * const name = cmd->cmd->name;
402 const char *err;
404 if (strcmp(fcgi_socket_dir, DEFAULT_SOCK_DIR) != 0) {
405 return ap_psprintf(tp, "%s %s: already defined as \"%s\"",
406 name, arg, fcgi_socket_dir);
409 err = fcgi_config_set_fcgi_uid_n_gid(1);
410 if (err != NULL)
411 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
413 if (fcgi_servers != NULL) {
414 return ap_psprintf(tp,
415 "The %s command must preceed static FastCGI server definitions",
416 name);
419 #ifndef WIN32
420 arg = ap_os_canonical_filename(cmd->pool, arg);
421 arg = ap_server_root_relative(cmd->pool, arg);
422 #else
423 if (strncmp(arg, "\\\\.\\pipe\\", 9) != 0)
424 return ap_psprintf(tp, "%s %s is invalid format",name, arg);
425 #endif
427 fcgi_socket_dir = arg;
429 #ifndef WIN32
430 err = fcgi_config_make_dir(tp, fcgi_socket_dir);
431 if (err != NULL)
432 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
434 err = fcgi_config_make_dynamic_dir(cmd->pool, 0);
435 if (err != NULL)
436 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
437 #endif
439 return NULL;
442 /*******************************************************************************
443 * Enable, disable, or specify the path to a wrapper used to invoke all
444 * FastCGI applications.
446 const char *fcgi_config_set_wrapper(cmd_parms *cmd, void *dummy, const char *arg)
448 const char *err = NULL;
449 const char * const name = cmd->cmd->name;
450 pool * const tp = cmd->temp_pool;
451 char * wrapper;
453 if (!ap_suexec_enabled && strcasecmp(arg, "On") == 0) {
454 fprintf(stderr, "Warning: \"%s On\" requires SUEXEC be enabled in Apache", name);
455 return NULL;
458 err = fcgi_config_set_fcgi_uid_n_gid(1);
459 if (err != NULL)
460 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
462 if (fcgi_servers != NULL) {
463 return ap_psprintf(tp,
464 "The %s command must preceed static FastCGI server definitions", name);
467 if (strcasecmp(arg, "On") == 0) {
468 fcgi_wrapper = SUEXEC_BIN;
470 else if (strcasecmp(arg, "Off") == 0) {
471 fcgi_wrapper = NULL;
473 else {
474 wrapper = (char *) ap_os_canonical_filename(cmd->pool, arg);
475 wrapper = ap_server_root_relative(cmd->pool, wrapper);
477 #ifdef WIN32
478 err = fcgi_util_check_access(tp, wrapper, NULL, _S_IEXEC, fcgi_user_id, fcgi_group_id);
479 #else
480 err = fcgi_util_check_access(tp, wrapper, NULL, X_OK, fcgi_user_id, fcgi_group_id);
481 #endif
483 if (err != NULL) {
484 return ap_psprintf(tp,
485 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
486 name, wrapper, (long)fcgi_user_id, (long)fcgi_group_id, err);
489 fcgi_wrapper = wrapper;
491 return NULL;
494 /*******************************************************************************
495 * Configure a static FastCGI server.
497 const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
499 fcgi_server *s;
500 pool *p = cmd->pool, *tp = cmd->temp_pool;
501 const char *name = cmd->cmd->name;
502 char *fs_path = ap_getword_conf(p, &arg);
503 const char *option, *err;
505 /* Allocate temp storage for the array of initial environment variables */
506 char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
507 unsigned int envc = 0;
509 #ifdef WIN32
510 HANDLE mutex;
511 #endif
513 if (*fs_path == '\0')
514 return "AppClass requires a pathname!?";
516 if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL)
517 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
519 fs_path = ap_os_canonical_filename(p, fs_path);
520 fs_path = ap_server_root_relative(p, fs_path);
522 ap_getparents(fs_path);
523 ap_no2slash(fs_path);
525 /* See if we've already got one of these configured */
526 s = fcgi_util_fs_get_by_id(fs_path, cmd->server->server_uid,
527 cmd->server->server_gid);
528 if (s != NULL) {
529 if (fcgi_wrapper) {
530 return ap_psprintf(tp,
531 "%s: redefinition of a previously defined FastCGI server \"%s\" with uid=%ld and gid=%ld",
532 name, fs_path, (long)cmd->server->server_uid,
533 (long)cmd->server->server_gid);
535 else {
536 return ap_psprintf(tp,
537 "%s: redefinition of a previously defined FastCGI server \"%s\"",
538 name, fs_path);
542 err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL);
543 if (err != NULL) {
544 return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err);
547 s = fcgi_util_fs_new(p);
548 s->fs_path = fs_path;
549 s->directive = APP_CLASS_STANDARD;
550 s->restartOnExit = TRUE;
551 s->numProcesses = 1;
553 #ifdef WIN32
554 // TCP FastCGI applications require SystemRoot be present in the environment
555 // Put it in both for consistency to the application
556 fcgi_config_set_env_var(tp, envp, &envc, "SystemRoot");
558 mutex = CreateMutex(NULL, FALSE, fs_path);
560 if (mutex == NULL)
562 ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
563 "FastCGI: CreateMutex() failed");
564 return "failed to create FastCGI application accept mutex";
567 SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE);
569 s->mutex_env_string = ap_psprintf(p, "_FCGI_MUTEX_=%ld", mutex);;
570 #else
571 if (fcgi_wrapper) {
572 struct passwd *pw;
573 struct group *gr;
575 s->uid = cmd->server->server_uid;
576 pw = getpwuid(s->uid);
577 if (pw == NULL) {
578 return ap_psprintf(tp, "mod_fastcgi: "
579 "getpwuid() couldn't determine the username for uid '%ld', "
580 "you probably need to modify the User directive: %s",
581 (long)s->uid, strerror(errno));
583 s->user = ap_pstrdup(p, pw->pw_name);
584 s->username = s->user;
586 s->gid = cmd->server->server_gid;
587 gr = getgrgid(s->gid);
588 if (gr == NULL) {
589 return ap_psprintf(tp, "mod_fastcgi: "
590 "getgrgid() couldn't determine the group name for gid '%ld', "
591 "you probably need to modify the Group directive: %s\n",
592 (long)s->gid, strerror(errno));
594 s->group = ap_pstrdup(p, gr->gr_name);
596 #endif
598 /* Parse directive arguments */
599 while (*arg) {
600 option = ap_getword_conf(tp, &arg);
602 if (strcasecmp(option, "-processes") == 0) {
603 if ((err = get_u_int(tp, &arg, &s->numProcesses, 1)))
604 return invalid_value(tp, name, fs_path, option, err);
606 else if (strcasecmp(option, "-restart-delay") == 0) {
607 if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
608 return invalid_value(tp, name, fs_path, option, err);
610 else if (strcasecmp(option, "-init-start-delay") == 0) {
611 if ((err = get_int(tp, &arg, &s->initStartDelay, 0)))
612 return invalid_value(tp, name, fs_path, option, err);
614 else if (strcasecmp(option, "-priority") == 0) {
615 if ((err = get_u_int(tp, &arg, &s->processPriority, 0)))
616 return invalid_value(tp, name, fs_path, option, err);
618 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
619 if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1)))
620 return invalid_value(tp, name, fs_path, option, err);
622 else if (strcasecmp(option, "-appConnTimeout") == 0) {
623 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
624 return invalid_value(tp, name, fs_path, option, err);
626 else if (strcasecmp(option, "-idle-timeout") == 0) {
627 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
628 return invalid_value(tp, name, fs_path, option, err);
630 else if (strcasecmp(option, "-port") == 0) {
631 if ((err = get_u_short(tp, &arg, &s->port, 1)))
632 return invalid_value(tp, name, fs_path, option, err);
634 else if (strcasecmp(option, "-socket") == 0) {
635 s->socket_path = ap_getword_conf(tp, &arg);
636 if (*s->socket_path == '\0')
637 return invalid_value(tp, name, fs_path, option, "\"\"");
639 else if (strcasecmp(option, "-initial-env") == 0) {
640 if ((err = get_env_var(p, &arg, envp, &envc)))
641 return invalid_value(tp, name, fs_path, option, err);
643 else if (strcasecmp(option, "-pass-header") == 0) {
644 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
645 return invalid_value(tp, name, fs_path, option, err);
647 else if (strcasecmp(option, "-flush") == 0) {
648 s->flush = 1;
650 else {
651 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
653 } /* while */
655 if (s->socket_path != NULL && s->port != 0) {
656 return ap_psprintf(tp,
657 "%s %s: -port and -socket are mutually exclusive options",
658 name, fs_path);
661 /* Move env array to a surviving pool */
662 ++envc;
663 s->envp = (char **)ap_palloc(p, sizeof(char *) * ++envc);
664 memcpy(s->envp, envp, sizeof(char *) * envc);
666 /* Initialize process structs */
667 s->procs = fcgi_util_fs_create_procs(p, s->numProcesses);
669 /* Build the appropriate sockaddr structure */
670 if (s->port != 0) {
671 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
672 &s->socket_addr_len, NULL, s->port);
673 if (err != NULL)
674 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
675 #ifdef WIN32
676 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
677 &s->socket_addr_len, "localhost", s->port);
678 if (err != NULL)
679 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
680 #endif
681 } else {
682 if (s->socket_path == NULL)
683 s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group);
684 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
685 #ifndef WIN32
686 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
687 &s->socket_addr_len, s->socket_path);
688 if (err != NULL)
689 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
690 #endif
693 /* Add it to the list of FastCGI servers */
694 fcgi_util_fs_add(s);
696 return NULL;
699 /*******************************************************************************
700 * Configure a static FastCGI server that is started/managed elsewhere.
702 const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg)
704 fcgi_server *s;
705 pool * const p = cmd->pool, *tp = cmd->temp_pool;
706 const char * const name = cmd->cmd->name;
707 char *fs_path = ap_getword_conf(p, &arg);
708 const char *option, *err;
710 if (!*fs_path) {
711 return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL);
714 fs_path = ap_os_canonical_filename(p, fs_path);
715 fs_path = ap_server_root_relative(p, fs_path);
717 ap_getparents(fs_path);
718 ap_no2slash(fs_path);
720 /* See if we've already got one of these bettys configured */
721 s = fcgi_util_fs_get_by_id(fs_path, cmd->server->server_uid,
722 cmd->server->server_gid);
723 if (s != NULL) {
724 if (fcgi_wrapper) {
725 return ap_psprintf(tp,
726 "%s: redefinition of a previously defined class \"%s\" with uid=%ld and gid=%ld",
727 name, fs_path, (long)cmd->server->server_uid,
728 (long)cmd->server->server_gid);
730 else {
731 return ap_psprintf(tp,
732 "%s: redefinition of previously defined class \"%s\"", name, fs_path);
736 s = fcgi_util_fs_new(p);
737 s->fs_path = fs_path;
738 s->directive = APP_CLASS_EXTERNAL;
740 err = fcgi_util_fs_set_uid_n_gid(p, s, cmd->server->server_uid, cmd->server->server_gid);
741 if (err != NULL)
742 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
744 /* Parse directive arguments */
745 while (*arg != '\0') {
746 option = ap_getword_conf(tp, &arg);
748 if (strcasecmp(option, "-host") == 0) {
749 if ((err = get_host_n_port(p, &arg, &s->host, &s->port)))
750 return invalid_value(tp, name, fs_path, option, err);
752 else if (strcasecmp(option, "-socket") == 0) {
753 s->socket_path = ap_getword_conf(tp, &arg);
754 if (*s->socket_path == '\0')
755 return invalid_value(tp, name, fs_path, option, "\"\"");
757 else if (strcasecmp(option, "-appConnTimeout") == 0) {
758 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
759 return invalid_value(tp, name, fs_path, option, err);
761 else if (strcasecmp(option, "-idle-timeout") == 0) {
762 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
763 return invalid_value(tp, name, fs_path, option, err);
765 else if (strcasecmp(option, "-pass-header") == 0) {
766 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
767 return invalid_value(tp, name, fs_path, option, err);
769 else if (strcasecmp(option, "-flush") == 0) {
770 s->flush = 1;
772 else {
773 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
775 } /* while */
777 /* Require one of -socket or -host, but not both */
778 if (s->socket_path != NULL && s->port != 0) {
779 return ap_psprintf(tp,
780 "%s %s: -host and -socket are mutually exclusive options",
781 name, fs_path);
783 if (s->socket_path == NULL && s->port == 0) {
784 return ap_psprintf(tp,
785 "%s %s: -socket or -host option missing", name, fs_path);
788 /* Build the appropriate sockaddr structure */
789 if (s->port != 0) {
790 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
791 &s->socket_addr_len, s->host, s->port);
792 if (err != NULL)
793 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
794 } else {
795 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
796 #ifndef WIN32
797 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
798 &s->socket_addr_len, s->socket_path);
799 if (err != NULL)
800 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
801 #endif
804 /* Add it to the list of FastCGI servers */
805 fcgi_util_fs_add(s);
807 return NULL;
811 *----------------------------------------------------------------------
813 * fcgi_config_set_config --
815 * Implements the FastCGI FCGIConfig configuration directive.
816 * This command adds routines to control the execution of the
817 * dynamic FastCGI processes.
820 *----------------------------------------------------------------------
822 const char *fcgi_config_set_config(cmd_parms *cmd, void *dummy, const char *arg)
824 pool * const p = cmd->pool;
825 pool * const tp = cmd->temp_pool;
826 const char *err, *option;
827 const char * const name = cmd->cmd->name;
829 /* Allocate temp storage for an initial environment */
830 unsigned int envc = 0;
831 char **envp = (char **)ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
833 /* Parse the directive arguments */
834 while (*arg) {
835 option = ap_getword_conf(tp, &arg);
837 if (strcasecmp(option, "-maxProcesses") == 0) {
838 if ((err = get_u_int(tp, &arg, &dynamicMaxProcs, 1)))
839 return invalid_value(tp, name, NULL, option, err);
841 else if (strcasecmp(option, "-minProcesses") == 0) {
842 if ((err = get_int(tp, &arg, &dynamicMinProcs, 0)))
843 return invalid_value(tp, name, NULL, option, err);
845 else if (strcasecmp(option, "-maxClassProcesses") == 0) {
846 if ((err = get_int(tp, &arg, &dynamicMaxClassProcs, 1)))
847 return invalid_value(tp, name, NULL, option, err);
849 else if (strcasecmp(option, "-killInterval") == 0) {
850 if ((err = get_u_int(tp, &arg, &dynamicKillInterval, 1)))
851 return invalid_value(tp, name, NULL, option, err);
853 else if (strcasecmp(option, "-updateInterval") == 0) {
854 if ((err = get_u_int(tp, &arg, &dynamicUpdateInterval, 1)))
855 return invalid_value(tp, name, NULL, option, err);
857 else if (strcasecmp(option, "-gainValue") == 0) {
858 if ((err = get_float(tp, &arg, &dynamicGain, 0.0, 1.0)))
859 return invalid_value(tp, name, NULL, option, err);
861 else if ((strcasecmp(option, "-singleThreshold") == 0)
862 || (strcasecmp(option, "-singleThreshhold") == 0))
864 if ((err = get_int(tp, &arg, &dynamicThreshold1, 0)))
865 return invalid_value(tp, name, NULL, option, err);
867 else if ((strcasecmp(option, "-multiThreshold") == 0)
868 || (strcasecmp(option, "-multiThreshhold") == 0))
870 if ((err = get_int(tp, &arg, &dynamicThresholdN, 0)))
871 return invalid_value(tp, name, NULL, option, err);
873 else if (strcasecmp(option, "-startDelay") == 0) {
874 if ((err = get_u_int(tp, &arg, &dynamicPleaseStartDelay, 1)))
875 return invalid_value(tp, name, NULL, option, err);
877 else if (strcasecmp(option, "-initial-env") == 0) {
878 if ((err = get_env_var(p, &arg, envp, &envc)))
879 return invalid_value(tp, name, NULL, option, err);
881 else if (strcasecmp(option, "-pass-header") == 0) {
882 if ((err = get_pass_header(p, &arg, &dynamic_pass_headers)))
883 return invalid_value(tp, name, NULL, option, err);
885 else if (strcasecmp(option, "-appConnTimeout") == 0) {
886 if ((err = get_u_int(tp, &arg, &dynamicAppConnectTimeout, 0)))
887 return invalid_value(tp, name, NULL, option, err);
889 else if (strcasecmp(option, "-idle-timeout") == 0) {
890 if ((err = get_u_int(tp, &arg, &dynamic_idle_timeout, 1)))
891 return invalid_value(tp, name, NULL, option, err);
893 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
894 if ((err = get_u_int(tp, &arg, &dynamicListenQueueDepth, 1)))
895 return invalid_value(tp, name, NULL, option, err);
897 else if (strcasecmp(option, "-restart-delay") == 0) {
898 if ((err = get_u_int(tp, &arg, &dynamicRestartDelay, 0)))
899 return invalid_value(tp, name, NULL, option, err);
901 else if (strcasecmp(option, "-init-start-delay") == 0) {
902 if ((err = get_u_int(tp, &arg, &dynamicInitStartDelay, 0)))
903 return invalid_value(tp, name, NULL, option, err);
905 else if (strcasecmp(option, "-processSlack") == 0) {
906 if ((err = get_u_int(tp, &arg, &dynamicProcessSlack, 1)))
907 return invalid_value(tp, name, NULL, option, err);
909 else if (strcasecmp(option, "-restart") == 0) {
910 dynamicAutoRestart = 1;
912 else if (strcasecmp(option, "-autoUpdate") == 0) {
913 dynamicAutoUpdate = 1;
915 else if (strcasecmp(option, "-flush") == 0) {
916 dynamicFlush = TRUE;
918 else {
919 return ap_psprintf(tp, "%s: invalid option: %s", name, option);
921 } /* while */
923 if (dynamicProcessSlack >= dynamicMaxProcs + 1) {
924 /* the kill policy would work unexpectedly */
925 return ap_psprintf(tp,
926 "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
927 name, dynamicProcessSlack, dynamicMaxProcs);
930 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
931 ++envc;
932 dynamicEnvp = (char **)ap_palloc(p, sizeof(char *) * ++envc);
933 memcpy(dynamicEnvp, envp, sizeof(char *) * envc);
935 return NULL;
938 void *fcgi_config_create_dir_config(pool *p, char *dummy)
940 fcgi_dir_config *dir_config = ap_pcalloc(p, sizeof(fcgi_dir_config));
942 dir_config->authenticator_options = FCGI_AUTHORITATIVE;
943 dir_config->authorizer_options = FCGI_AUTHORITATIVE;
944 dir_config->access_checker_options = FCGI_AUTHORITATIVE;
946 return dir_config;
950 const char *fcgi_config_new_auth_server(cmd_parms * const cmd,
951 fcgi_dir_config *dir_config, const char *fs_path, const char * const compat)
953 pool * const tp = cmd->temp_pool;
954 const uid_t uid = cmd->server->server_uid;
955 const gid_t gid = cmd->server->server_gid;
956 char * auth_server;
958 auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path);
959 auth_server = ap_server_root_relative(cmd->pool, auth_server);
961 /* Make sure its already configured or at least a candidate for dynamic */
962 if (fcgi_util_fs_get_by_id(auth_server, uid, gid) == NULL) {
963 const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL);
964 if (err)
965 return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err);
968 if (compat && strcasecmp(compat, "-compat"))
969 return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat);
971 switch((int)cmd->info) {
972 case FCGI_AUTH_TYPE_AUTHENTICATOR:
973 dir_config->authenticator = auth_server;
974 dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0;
975 break;
976 case FCGI_AUTH_TYPE_AUTHORIZER:
977 dir_config->authorizer = auth_server;
978 dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
979 break;
980 case FCGI_AUTH_TYPE_ACCESS_CHECKER:
981 dir_config->access_checker = auth_server;
982 dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
983 break;
986 return NULL;
989 const char *fcgi_config_set_authoritative_slot(const cmd_parms * const cmd,
990 fcgi_dir_config * const dir_config, int arg)
992 int offset = (int)(long)cmd->info;
994 if (arg)
995 *((u_char *)dir_config + offset) |= FCGI_AUTHORITATIVE;
996 else
997 *((u_char *)dir_config + offset) &= ~FCGI_AUTHORITATIVE;
999 return NULL;