Capture CreateFile()/GetLastError() in errno
[mod_fastcgi.git] / fcgi_config.c
blobf13f5c314eac42f247119cfef5bd8d46d75bbbe0
1 /*
2 * $Id: fcgi_config.c,v 1.22 2000/04/29 21:24:31 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;
17 long tmp;
19 *host = ap_getword_conf(p, arg);
20 if (**host == '\0')
21 return "\"\"";
23 portStr = strchr(*host, ':');
24 if (portStr == NULL)
25 return "missing port specification";
27 /* Split the host and port portions */
28 *portStr++ = '\0';
30 /* Convert port number */
31 tmp = (u_short) strtol(portStr, &cvptr, 10);
32 if (*cvptr != '\0' || tmp < 1 || tmp > USHRT_MAX)
33 return ap_pstrcat(p, "bad port number \"", portStr, "\"", NULL);
35 *port = (unsigned short) tmp;
37 return NULL;
40 /*******************************************************************************
41 * Get the next configuration directive argument, & return an u_short.
42 * The pool arg should be temporary storage.
44 static const char *get_u_short(pool *p, const char **arg,
45 u_short *num, u_short min)
47 char *ptr;
48 long tmp;
49 const char *txt = ap_getword_conf(p, arg);
51 if (*txt == '\0') {
52 return "\"\"";
55 tmp = strtol(txt, &ptr, 10);
57 if (*ptr != '\0') {
58 return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
61 if (tmp < min || tmp > USHRT_MAX) {
62 return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX);
65 *num = (u_short) tmp;
67 return NULL;
70 /*******************************************************************************
71 * Get the next configuration directive argument, & return an u_int.
72 * The pool arg should be temporary storage.
74 static const char *get_u_int(pool *p, const char **arg,
75 u_int *num, u_int min)
77 char *ptr;
78 const char *val = ap_getword_conf(p, arg);
80 if (*val == '\0')
81 return "\"\"";
82 *num = (u_int)strtol(val, &ptr, 10);
84 if (*ptr != '\0')
85 return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
86 else if (*num < min)
87 return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
88 return NULL;
91 /*******************************************************************************
92 * Get the next configuration directive argument, & return a float.
93 * The pool arg should be temporary storage.
95 static const char *get_float(pool *p, const char **arg,
96 float *num, float min, float max)
98 char *ptr;
99 const char *val = ap_getword_conf(p, arg);
101 if (*val == '\0')
102 return "\"\"";
103 *num = (float) strtod(val, &ptr);
105 if (*ptr != '\0')
106 return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL);
107 if (*num < min || *num > max)
108 return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max);
109 return NULL;
112 const char *fcgi_config_set_env_var(pool *p, char **envp, unsigned int *envc, char * var)
114 if (*envc >= MAX_INIT_ENV_VARS) {
115 return "too many variables, must be <= MAX_INIT_ENV_VARS";
118 if (strchr(var, '=') == NULL) {
119 *(envp + *envc) = ap_pstrcat(p, var, "=", getenv(var), NULL);
121 else {
122 *(envp + *envc) = var;
125 (*envc)++;
127 return NULL;
130 /*******************************************************************************
131 * Get the next configuration directive argument, & add it to an env array.
132 * The pool arg should be permanent storage.
134 static const char *get_env_var(pool *p, const char **arg, char **envp, unsigned int *envc)
136 char * const val = ap_getword_conf(p, arg);
138 if (*val == '\0') {
139 return "\"\"";
142 return fcgi_config_set_env_var(p, envp, envc, val);
145 static const char *get_pass_header(pool *p, const char **arg, array_header **array)
147 const char **header;
149 if (!*array) {
150 *array = ap_make_array(p, 10, sizeof(char*));
153 header = (const char **)ap_push_array(*array);
154 *header = ap_getword_conf(p, arg);
156 return header ? NULL : "\"\"";
159 /*******************************************************************************
160 * Return a "standard" message for common configuration errors.
162 static const char *invalid_value(pool *p, const char *cmd, const char *id,
163 const char *opt, const char *err)
165 return ap_psprintf(p, "%s%s%s: invalid value for %s: %s",
166 cmd, id ? " " : "", id ? id : "", opt, err);
169 /*******************************************************************************
170 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
171 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
172 * to check that the config files don't set the User/Group after a FastCGI
173 * directive is used that depends on it.
175 /*@@@ To be complete, we should save a handle to the server each AppClass is
176 * configured in and at init() check that the user/group is still what we
177 * thought it was. Also the other directives should only be allowed in the
178 * parent Apache server.
180 const char *fcgi_config_set_fcgi_uid_n_gid(int set)
182 static int isSet = 0;
183 #ifndef WIN32
184 uid_t uid = geteuid();
185 gid_t gid = getegid();
187 if (set == 0) {
188 isSet = 0;
189 fcgi_user_id = (uid_t)-1;
190 fcgi_group_id = (gid_t)-1;
191 return NULL;
194 uid = uid ? uid : ap_user_id;
195 gid = uid ? gid : ap_group_id;
197 if (isSet && (uid != fcgi_user_id || gid != fcgi_group_id)) {
198 return "User/Group commands must preceed FastCGI server definitions";
201 isSet = 1;
202 fcgi_user_id = uid;
203 fcgi_group_id = gid;
204 #endif
205 return NULL;
208 void fcgi_config_reset_globals(void* dummy)
210 fcgi_config_pool = NULL;
211 fcgi_servers = NULL;
212 fcgi_config_set_fcgi_uid_n_gid(0);
213 fcgi_suexec = NULL;
214 fcgi_socket_dir = DEFAULT_SOCK_DIR;
216 fcgi_dynamic_total_proc_count = 0;
217 fcgi_dynamic_epoch = 0;
218 fcgi_dynamic_last_analyzed = 0;
220 dynamicMaxProcs = FCGI_DEFAULT_MAX_PROCS;
221 dynamicMinProcs = FCGI_DEFAULT_MIN_PROCS;
222 dynamicMaxClassProcs = FCGI_DEFAULT_MAX_CLASS_PROCS;
223 dynamicKillInterval = FCGI_DEFAULT_KILL_INTERVAL;
224 dynamicUpdateInterval = FCGI_DEFAULT_UPDATE_INTERVAL;
225 dynamicGain = FCGI_DEFAULT_GAIN;
226 dynamicThreshhold1 = FCGI_DEFAULT_THRESHHOLD_1;
227 dynamicThreshholdN = FCGI_DEFAULT_THRESHHOLD_N;
228 dynamicPleaseStartDelay = FCGI_DEFAULT_START_PROCESS_DELAY;
229 dynamicAppConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
230 dynamicEnvp = &fcgi_empty_env;
231 dynamicProcessSlack = FCGI_DEFAULT_PROCESS_SLACK;
232 dynamicAutoRestart = FCGI_DEFAULT_RESTART_DYNAMIC;
233 dynamicAutoUpdate = FCGI_DEFAULT_AUTOUPDATE;
234 dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
235 dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
236 dynamicRestartDelay = FCGI_DEFAULT_RESTART_DELAY;
237 dynamic_pass_headers = NULL;
238 dynamic_idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
241 /*******************************************************************************
242 * Create a directory to hold Unix/Domain sockets.
244 const char *fcgi_config_make_dir(pool *tp, char *path)
246 struct stat finfo;
247 const char *err = NULL;
249 /* Is the directory spec'd correctly */
250 if (*path != '/') {
251 return "path is not absolute (it must start with a \"/\")";
253 else {
254 int i = strlen(path) - 1;
256 /* Strip trailing "/"s */
257 while(i > 0 && path[i] == '/') path[i--] = '\0';
260 /* Does it exist? */
261 if (stat(path, &finfo) != 0) {
262 /* No, but maybe we can create it */
263 #ifdef WIN32
264 if (mkdir(path) != 0)
265 #else
266 if (mkdir(path, S_IRWXU) != 0)
267 #endif
269 return ap_psprintf(tp,
270 "doesn't exist and can't be created: %s",
271 strerror(errno));
274 #ifndef WIN32
275 /* If we're root, we're gonna setuid/setgid so we need to chown */
276 if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) {
277 return ap_psprintf(tp,
278 "can't chown() to the server (uid %ld, gid %ld): %s",
279 (long)ap_user_id, (long)ap_group_id, strerror(errno));
281 #endif
283 else {
284 /* Yes, is it a directory? */
285 if (!S_ISDIR(finfo.st_mode))
286 return "isn't a directory!";
288 /* Can we RWX in there? */
289 #ifdef WIN32
290 err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
291 #else
292 err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
293 fcgi_user_id, fcgi_group_id);
294 #endif
295 if (err != NULL) {
296 return ap_psprintf(tp,
297 "access for server (uid %ld, gid %ld) failed: %s",
298 (long)fcgi_user_id, (long)fcgi_group_id, err);
301 return NULL;
304 /*******************************************************************************
305 * Create a "dynamic" subdirectory. If the directory
306 * already exists we don't mess with it unless 'wax' is set.
308 const char *fcgi_config_make_dynamic_dir(pool *p, const int wax)
310 #ifndef WIN32
311 DIR *dp = NULL;
312 struct dirent *dirp = NULL;
313 const char *err;
314 pool *tp;
316 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "/dynamic", NULL);
318 if ((err = fcgi_config_make_dir(p, fcgi_dynamic_dir)))
319 return ap_psprintf(p, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir, err);
321 /* Don't step on a running server unless its OK. */
322 if (!wax)
323 return NULL;
325 /* Create a subpool for the directory operations */
326 tp = ap_make_sub_pool(p);
328 dp = ap_popendir(tp, fcgi_dynamic_dir);
329 if (dp == NULL) {
330 ap_destroy_pool(tp);
331 return ap_psprintf(p, "can't open dynamic directory \"%s\": %s",
332 fcgi_dynamic_dir, strerror(errno));
335 /* Delete everything in the directory, its all FCGI specific */
336 while ((dirp = readdir(dp)) != NULL) {
337 if (strcmp(dirp->d_name, ".") == 0
338 || strcmp(dirp->d_name, "..") == 0) {
339 continue;
342 unlink(ap_pstrcat(tp, fcgi_dynamic_dir, "/", dirp->d_name, NULL));
345 ap_destroy_pool(tp);
347 #else
348 fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "dynamic", NULL);
349 #endif
350 return NULL;
354 /*******************************************************************************
355 * Change the directory used for the Unix/Domain sockets from the default.
356 * Create the directory and the "dynamic" subdirectory.
358 const char *fcgi_config_set_socket_dir(cmd_parms *cmd, void *dummy, char *arg)
360 pool * const tp = cmd->temp_pool;
361 const char * const name = cmd->cmd->name;
362 const char *err;
364 if (strcmp(fcgi_socket_dir, DEFAULT_SOCK_DIR) != 0) {
365 return ap_psprintf(tp, "%s %s: already defined as \"%s\"",
366 name, arg, fcgi_socket_dir);
369 err = fcgi_config_set_fcgi_uid_n_gid(1);
370 if (err != NULL)
371 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
373 if (fcgi_servers != NULL) {
374 return ap_psprintf(tp,
375 "The %s command must preceed static FastCGI server definitions",
376 name);
379 #ifndef WIN32
380 arg = ap_os_canonical_filename(cmd->pool, arg);
381 arg = ap_server_root_relative(cmd->pool, arg);
382 #else
383 if (strncmp(arg, "\\\\.\\pipe\\", 9) != 0)
384 return ap_psprintf(tp, "%s %s is invalid format",name, arg);
385 #endif
387 fcgi_socket_dir = arg;
389 #ifndef WIN32
390 err = fcgi_config_make_dir(tp, fcgi_socket_dir);
391 if (err != NULL)
392 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
394 err = fcgi_config_make_dynamic_dir(cmd->pool, 0);
395 if (err != NULL)
396 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
397 #endif
399 return NULL;
402 /*******************************************************************************
403 * Enable, disable, or specify the path to the suexec program.
405 const char *fcgi_config_set_suexec(cmd_parms *cmd, void *dummy, const char *arg)
407 const char *err = NULL;
408 const char * const name = cmd->cmd->name;
409 pool * const tp = cmd->temp_pool;
410 char * suexec;
412 if (!ap_suexec_enabled) {
413 if (strcasecmp(arg, "Off") != 0) {
414 fprintf(stderr, "Warning: %s requires SUEXEC wrapper be enabled in Apache\n", name);
416 return NULL;
419 err = fcgi_config_set_fcgi_uid_n_gid(1);
420 if (err != NULL)
421 return ap_psprintf(tp, "%s %s: %s", name, arg, err);
423 if (fcgi_servers != NULL) {
424 return ap_psprintf(tp,
425 "The %s command must preceed static FastCGI server definitions", name);
428 if (strcasecmp(arg, "On") == 0) {
429 fcgi_suexec = SUEXEC_BIN;
431 else if (strcasecmp(arg, "Off") == 0) {
432 fcgi_suexec = NULL;
434 else {
435 suexec = (char *) ap_os_canonical_filename(cmd->pool, arg);
436 suexec = ap_server_root_relative(cmd->pool, suexec);
438 #ifdef WIN32
439 err = fcgi_util_check_access(tp, suexec, NULL, _S_IEXEC, fcgi_user_id, fcgi_group_id);
440 #else
441 err = fcgi_util_check_access(tp, suexec, NULL, X_OK, fcgi_user_id, fcgi_group_id);
442 #endif
444 if (err != NULL) {
445 return ap_psprintf(tp,
446 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
447 name, suexec, (long)fcgi_user_id, (long)fcgi_group_id, err);
450 fcgi_suexec = suexec;
452 return NULL;
455 /*******************************************************************************
456 * Configure a static FastCGI server.
458 const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
460 fcgi_server *s;
461 pool *p = cmd->pool, *tp = cmd->temp_pool;
462 const char *name = cmd->cmd->name;
463 char *fs_path = ap_getword_conf(p, &arg);
464 const char *option, *err;
466 /* Allocate temp storage for the array of initial environment variables */
467 char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
468 unsigned int envc = 0;
470 if (*fs_path == '\0')
471 return "AppClass requires a pathname!?";
473 if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL)
474 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
476 fs_path = ap_os_canonical_filename(p, fs_path);
477 fs_path = ap_server_root_relative(p, fs_path);
479 ap_getparents(fs_path);
480 ap_no2slash(fs_path);
482 /* See if we've already got one of these configured */
483 s = fcgi_util_fs_get_by_id(fs_path, cmd->server->server_uid,
484 cmd->server->server_gid);
485 if (s != NULL) {
486 if (fcgi_suexec) {
487 return ap_psprintf(tp,
488 "%s: redefinition of a previously defined FastCGI server \"%s\" with uid=%ld and gid=%ld",
489 name, fs_path, (long)cmd->server->server_uid,
490 (long)cmd->server->server_gid);
492 else {
493 return ap_psprintf(tp,
494 "%s: redefinition of a previously defined FastCGI server \"%s\"",
495 name, fs_path);
499 err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL, cmd->server->server_uid,
500 cmd->server->server_gid);
501 if (err != NULL) {
502 return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err);
505 s = fcgi_util_fs_new(p);
506 s->fs_path = fs_path;
507 s->directive = APP_CLASS_STANDARD;
508 s->restartOnExit = TRUE;
509 s->numProcesses = 1;
511 #ifdef WIN32
512 // TCP FastCGI applications require SystemRoot be present in the environment
513 // Put it in both for consistency to the application
514 fcgi_config_set_env_var(tp, envp, &envc, "SystemRoot");
515 #else
516 if (fcgi_suexec) {
517 struct passwd *pw;
518 struct group *gr;
520 s->uid = cmd->server->server_uid;
521 pw = getpwuid(s->uid);
522 if (pw == NULL) {
523 return ap_psprintf(tp, "mod_fastcgi: "
524 "getpwuid() couldn't determine the username for uid '%ld', "
525 "you probably need to modify the User directive: %s",
526 (long)s->uid, strerror(errno));
528 s->user = ap_pstrdup(p, pw->pw_name);
529 s->username = s->user;
531 s->gid = cmd->server->server_gid;
532 gr = getgrgid(s->gid);
533 if (gr == NULL) {
534 return ap_psprintf(tp, "mod_fastcgi: "
535 "getgrgid() couldn't determine the group name for gid '%ld', "
536 "you probably need to modify the Group directive: %s\n",
537 (long)s->gid, strerror(errno));
539 s->group = ap_pstrdup(p, gr->gr_name);
541 #endif
543 /* Parse directive arguments */
544 while (*arg) {
545 option = ap_getword_conf(tp, &arg);
547 if (strcasecmp(option, "-processes") == 0) {
548 if ((err = get_u_int(tp, &arg, &s->numProcesses, 1)))
549 return invalid_value(tp, name, fs_path, option, err);
551 else if (strcasecmp(option, "-restart-delay") == 0) {
552 if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
553 return invalid_value(tp, name, fs_path, option, err);
555 else if (strcasecmp(option, "-init-start-delay") == 0) {
556 if ((err = get_u_int(tp, &arg, &s->initStartDelay, 0)))
557 return invalid_value(tp, name, fs_path, option, err);
559 else if (strcasecmp(option, "-priority") == 0) {
560 if ((err = get_u_int(tp, &arg, &s->processPriority, 0)))
561 return invalid_value(tp, name, fs_path, option, err);
563 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
564 if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1)))
565 return invalid_value(tp, name, fs_path, option, err);
567 else if (strcasecmp(option, "-appConnTimeout") == 0) {
568 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
569 return invalid_value(tp, name, fs_path, option, err);
571 else if (strcasecmp(option, "-idle-timeout") == 0) {
572 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
573 return invalid_value(tp, name, fs_path, option, err);
575 else if (strcasecmp(option, "-port") == 0) {
576 if ((err = get_u_short(tp, &arg, &s->port, 1)))
577 return invalid_value(tp, name, fs_path, option, err);
579 else if (strcasecmp(option, "-socket") == 0) {
580 s->socket_path = ap_getword_conf(tp, &arg);
581 if (*s->socket_path == '\0')
582 return invalid_value(tp, name, fs_path, option, "\"\"");
584 else if (strcasecmp(option, "-initial-env") == 0) {
585 if ((err = get_env_var(p, &arg, envp, &envc)))
586 return invalid_value(tp, name, fs_path, option, err);
588 else if (strcasecmp(option, "-pass-header") == 0) {
589 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
590 return invalid_value(tp, name, fs_path, option, err);
592 else if (strcasecmp(option, "-flush") == 0) {
593 s->flush = 1;
595 else {
596 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
598 } /* while */
600 if (s->socket_path != NULL && s->port != 0) {
601 return ap_psprintf(tp,
602 "%s %s: -port and -socket are mutually exclusive options",
603 name, fs_path);
606 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
607 ++envc;
608 s->envp = (char **)ap_palloc(p, sizeof(char *) * ++envc);
609 memcpy(s->envp, envp, sizeof(char *) * envc);
611 /* Initialize process structs */
612 s->procs = fcgi_util_fs_create_procs(p, s->numProcesses);
614 /* Build the appropriate sockaddr structure */
615 if (s->port != 0) {
616 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
617 &s->socket_addr_len, NULL, s->port);
618 if (err != NULL)
619 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
620 #ifdef WIN32
621 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
622 &s->socket_addr_len, "localhost", s->port);
623 if (err != NULL)
624 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
625 #endif
626 } else {
627 if (s->socket_path == NULL)
628 s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group);
629 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
630 #ifndef WIN32
631 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
632 &s->socket_addr_len, s->socket_path);
633 if (err != NULL)
634 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
635 #endif
638 /* Add it to the list of FastCGI servers */
639 fcgi_util_fs_add(s);
641 return NULL;
644 /*******************************************************************************
645 * Configure a static FastCGI server that is started/managed elsewhere.
647 const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg)
649 fcgi_server *s;
650 pool * const p = cmd->pool, *tp = cmd->temp_pool;
651 const char * const name = cmd->cmd->name;
652 char *fs_path = ap_getword_conf(p, &arg);
653 const char *option, *err;
655 if (!*fs_path) {
656 return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL);
659 fs_path = ap_os_canonical_filename(p, fs_path);
660 fs_path = ap_server_root_relative(p, fs_path);
662 ap_getparents(fs_path);
663 ap_no2slash(fs_path);
665 /* See if we've already got one of these bettys configured */
666 s = fcgi_util_fs_get_by_id(fs_path, cmd->server->server_uid,
667 cmd->server->server_gid);
668 if (s != NULL) {
669 if (fcgi_suexec != NULL) {
670 return ap_psprintf(tp,
671 "%s: redefinition of a previously defined class \"%s\" with uid=%ld and gid=%ld",
672 name, fs_path, (long)cmd->server->server_uid,
673 (long)cmd->server->server_gid);
675 else {
676 return ap_psprintf(tp,
677 "%s: redefinition of previously defined class \"%s\"", name, fs_path);
681 s = fcgi_util_fs_new(p);
682 s->fs_path = fs_path;
683 s->directive = APP_CLASS_EXTERNAL;
685 err = fcgi_util_fs_set_uid_n_gid(p, s, cmd->server->server_uid, cmd->server->server_gid);
686 if (err != NULL)
687 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
689 /* Parse directive arguments */
690 while (*arg != '\0') {
691 option = ap_getword_conf(tp, &arg);
693 if (strcasecmp(option, "-host") == 0) {
694 if ((err = get_host_n_port(p, &arg, &s->host, &s->port)))
695 return invalid_value(tp, name, fs_path, option, err);
697 else if (strcasecmp(option, "-socket") == 0) {
698 s->socket_path = ap_getword_conf(tp, &arg);
699 if (*s->socket_path == '\0')
700 return invalid_value(tp, name, fs_path, option, "\"\"");
702 else if (strcasecmp(option, "-appConnTimeout") == 0) {
703 if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
704 return invalid_value(tp, name, fs_path, option, err);
706 else if (strcasecmp(option, "-idle-timeout") == 0) {
707 if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
708 return invalid_value(tp, name, fs_path, option, err);
710 else if (strcasecmp(option, "-pass-header") == 0) {
711 if ((err = get_pass_header(p, &arg, &s->pass_headers)))
712 return invalid_value(tp, name, fs_path, option, err);
714 else if (strcasecmp(option, "-flush") == 0) {
715 s->flush = 1;
717 else {
718 return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
720 } /* while */
722 /* Require one of -socket or -host, but not both */
723 if (s->socket_path != NULL && s->port != 0) {
724 return ap_psprintf(tp,
725 "%s %s: -host and -socket are mutually exclusive options",
726 name, fs_path);
728 if (s->socket_path == NULL && s->port == 0) {
729 return ap_psprintf(tp,
730 "%s %s: -socket or -host option missing", name, fs_path);
733 /* Build the appropriate sockaddr structure */
734 if (s->port != 0) {
735 err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
736 &s->socket_addr_len, s->host, s->port);
737 if (err != NULL)
738 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
739 } else {
740 s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
741 #ifndef WIN32
742 err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
743 &s->socket_addr_len, s->socket_path);
744 if (err != NULL)
745 return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
746 #endif
749 /* Add it to the list of FastCGI servers */
750 fcgi_util_fs_add(s);
752 return NULL;
756 *----------------------------------------------------------------------
758 * fcgi_config_set_config --
760 * Implements the FastCGI FCGIConfig configuration directive.
761 * This command adds routines to control the execution of the
762 * dynamic FastCGI processes.
765 *----------------------------------------------------------------------
767 const char *fcgi_config_set_config(cmd_parms *cmd, void *dummy, const char *arg)
769 pool * const p = cmd->pool;
770 pool * const tp = cmd->temp_pool;
771 const char *err, *option;
772 const char * const name = cmd->cmd->name;
774 /* Allocate temp storage for an initial environment */
775 unsigned int envc = 0;
776 char **envp = (char **)ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
778 /* Parse the directive arguments */
779 while (*arg) {
780 option = ap_getword_conf(tp, &arg);
782 if (strcasecmp(option, "-maxProcesses") == 0) {
783 if ((err = get_u_int(tp, &arg, &dynamicMaxProcs, 1)))
784 return invalid_value(tp, name, NULL, option, err);
786 else if (strcasecmp(option, "-minProcesses") == 0) {
787 if ((err = get_u_int(tp, &arg, &dynamicMinProcs, 0)))
788 return invalid_value(tp, name, NULL, option, err);
790 else if (strcasecmp(option, "-maxClassProcesses") == 0) {
791 if ((err = get_u_int(tp, &arg, &dynamicMaxClassProcs, 1)))
792 return invalid_value(tp, name, NULL, option, err);
794 else if (strcasecmp(option, "-killInterval") == 0) {
795 if ((err = get_u_int(tp, &arg, &dynamicKillInterval, 1)))
796 return invalid_value(tp, name, NULL, option, err);
798 else if (strcasecmp(option, "-updateInterval") == 0) {
799 if ((err = get_u_int(tp, &arg, &dynamicUpdateInterval, 1)))
800 return invalid_value(tp, name, NULL, option, err);
802 else if (strcasecmp(option, "-gainValue") == 0) {
803 if ((err = get_float(tp, &arg, &dynamicGain, 0.0, 1.0)))
804 return invalid_value(tp, name, NULL, option, err);
806 else if (strcasecmp(option, "-singleThreshhold") == 0) {
807 if ((err = get_u_int(tp, &arg, &dynamicThreshhold1, 0)))
808 return invalid_value(tp, name, NULL, option, err);
810 else if (strcasecmp(option, "-multiThreshhold") == 0) {
811 if ((err = get_u_int(tp, &arg, &dynamicThreshholdN, 0)))
812 return invalid_value(tp, name, NULL, option, err);
814 else if (strcasecmp(option, "-startDelay") == 0) {
815 if ((err = get_u_int(tp, &arg, &dynamicPleaseStartDelay, 1)))
816 return invalid_value(tp, name, NULL, option, err);
818 else if (strcasecmp(option, "-initial-env") == 0) {
819 if ((err = get_env_var(p, &arg, envp, &envc)))
820 return invalid_value(tp, name, NULL, option, err);
822 else if (strcasecmp(option, "-pass-header") == 0) {
823 if ((err = get_pass_header(p, &arg, &dynamic_pass_headers)))
824 return invalid_value(tp, name, NULL, option, err);
826 else if (strcasecmp(option, "-appConnTimeout") == 0) {
827 if ((err = get_u_int(tp, &arg, &dynamicAppConnectTimeout, 0)))
828 return invalid_value(tp, name, NULL, option, err);
830 else if (strcasecmp(option, "-idle-timeout") == 0) {
831 if ((err = get_u_int(tp, &arg, &dynamic_idle_timeout, 1)))
832 return invalid_value(tp, name, NULL, option, err);
834 else if (strcasecmp(option, "-listen-queue-depth") == 0) {
835 if ((err = get_u_int(tp, &arg, &dynamicListenQueueDepth, 1)))
836 return invalid_value(tp, name, NULL, option, err);
838 else if (strcasecmp(option, "-restart-delay") == 0) {
839 if ((err = get_u_int(tp, &arg, &dynamicRestartDelay, 0)))
840 return invalid_value(tp, name, NULL, option, err);
842 else if (strcasecmp(option, "-init-start-delay") == 0) {
843 if ((err = get_u_int(tp, &arg, &dynamicInitStartDelay, 0)))
844 return invalid_value(tp, name, NULL, option, err);
846 else if (strcasecmp(option, "-processSlack") == 0) {
847 if ((err = get_u_int(tp, &arg, &dynamicProcessSlack, 1)))
848 return invalid_value(tp, name, NULL, option, err);
850 else if (strcasecmp(option, "-restart") == 0) {
851 dynamicAutoRestart = 1;
853 else if (strcasecmp(option, "-autoUpdate") == 0) {
854 dynamicAutoUpdate = 1;
856 else {
857 return ap_psprintf(tp, "%s: invalid option: %s", name, option);
859 } /* while */
861 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
862 ++envc;
863 dynamicEnvp = (char **)ap_palloc(p, sizeof(char *) * ++envc);
864 memcpy(dynamicEnvp, envp, sizeof(char *) * envc);
866 return NULL;
869 void *fcgi_config_create_dir_config(pool *p, char *dummy)
871 fcgi_dir_config *dir_config = ap_pcalloc(p, sizeof(fcgi_dir_config));
873 dir_config->authenticator_options = FCGI_AUTHORITATIVE;
874 dir_config->authorizer_options = FCGI_AUTHORITATIVE;
875 dir_config->access_checker_options = FCGI_AUTHORITATIVE;
877 return dir_config;
881 const char *fcgi_config_new_auth_server(cmd_parms * const cmd,
882 fcgi_dir_config *dir_config, const char *fs_path, const char * const compat)
884 pool * const tp = cmd->temp_pool;
885 const uid_t uid = cmd->server->server_uid;
886 const gid_t gid = cmd->server->server_gid;
887 char * auth_server;
889 auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path);
890 auth_server = ap_server_root_relative(cmd->pool, auth_server);
892 /* Make sure its already configured or at least a candidate for dynamic */
893 if (fcgi_util_fs_get_by_id(auth_server, uid, gid) == NULL) {
894 const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL, uid, gid);
895 if (err)
896 return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err);
899 if (compat && strcasecmp(compat, "-compat"))
900 return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat);
902 switch((int)cmd->info) {
903 case FCGI_AUTH_TYPE_AUTHENTICATOR:
904 dir_config->authenticator = auth_server;
905 dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0;
906 break;
907 case FCGI_AUTH_TYPE_AUTHORIZER:
908 dir_config->authorizer = auth_server;
909 dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
910 break;
911 case FCGI_AUTH_TYPE_ACCESS_CHECKER:
912 dir_config->access_checker = auth_server;
913 dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
914 break;
917 return NULL;
920 const char *fcgi_config_set_authoritative_slot(const cmd_parms * const cmd,
921 fcgi_dir_config * const dir_config, int arg)
923 int offset = (int)(long)cmd->info;
925 if (arg)
926 *(int *)(dir_config + offset) |= FCGI_AUTHORITATIVE;
927 else
928 *(int *)(dir_config + offset) &= ~FCGI_AUTHORITATIVE;
930 return NULL;