Ejemplo n.º 1
0
int init_cgi(request * req)
{
#ifndef EXCLUDE_CGI
    int child_pid;
    int pipes[2];
    int use_pipes = 0;
#endif

    SQUASH_KA(req);

#ifndef EXCLUDE_CGI
    if (req->cgi_type) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
    DEBUG(DEBUG_CGI_ENV) {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            log_error_time();
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }

    /* we want to use pipes whenever it's a CGI or directory */
    /* otherwise (NPH, gunzip) we want no pipes */
    if (req->cgi_type == CGI ||
        (!req->cgi_type &&
         (req->pathname[strlen(req->pathname) - 1] == '/'))) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_doc(req);
            perror("pipe");
            return 0;
        }

        /* set the read end of the socket to non-blocking */
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch (child_pid) {
    case -1:
        /* fork unsuccessful */
        /* FIXME: There is a problem here. send_r_error (called by
         * boa_perror) would work for NPH and CGI, but not for GUNZIP.  
         * Fix that. 
         */
        boa_perror(req, "fork failed");
        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        return 0;
        break;
    case 0:
        /* child */
        reset_signals();

        if (req->cgi_type == CGI || req->cgi_type == NPH) {
            char *c;
            unsigned int l;
            char *newpath, *oldpath;

            c = strrchr(req->pathname, '/');
            if (!c) {
                /* there will always be a '.' */
                log_error_doc(req);
                fprintf(stderr,
                        "unable to find '/' in req->pathname: \"%s\"\n",
                        req->pathname);
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            *c = '\0';

            if (chdir(req->pathname) != 0) {
                int saved_errno = errno;
                log_error_doc(req);
                fprintf(stderr, "Could not chdir to \"%s\":",
                        req->pathname);
                errno = saved_errno;
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }

            oldpath = req->pathname;
            req->pathname = ++c;
            l = strlen(req->pathname) + 3;
            /* prefix './' */
            newpath = malloc(sizeof (char) * l);
            if (!newpath) {
                /* there will always be a '.' */
                log_error_doc(req);
                perror("unable to malloc for newpath");
                if (use_pipes)
                    close(pipes[1]);
                _exit(EXIT_FAILURE);
            }
            newpath[0] = '.';
            newpath[1] = '/';
            memcpy(&newpath[2], req->pathname, l - 2); /* includes the trailing '\0' */
            free(oldpath);
            req->pathname = newpath;
        }
        if (use_pipes) {
            /* close the 'read' end of the pipes[] */
            close(pipes[0]);
            /* tie CGI's STDOUT to our write end of pipe */
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - pipes");
                _exit(EXIT_FAILURE);
            }
            close(pipes[1]);
        } else {
            /* tie stdout to socket */
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_doc(req);
                perror("dup2 - fd");
                _exit(EXIT_FAILURE);
            }
            close(req->fd);
        }
        /* Switch socket flags back to blocking */
        if (set_block_fd(STDOUT_FILENO) == -1) {
            log_error_doc(req);
            perror("cgi-fcntl");
            _exit(EXIT_FAILURE);
        }
        /* tie post_data_fd to POST stdin */
        if (req->method == M_POST) { /* tie stdin to file */
// davidhsu ----------------------
#ifndef NEW_POST
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
#endif
//-------------------------------	
			
        }

#ifdef USE_SETRLIMIT
        /* setrlimit stuff.
         * This is neat!
         * RLIMIT_STACK    max stack size
         * RLIMIT_CORE     max core file size
         * RLIMIT_RSS      max resident set size
         * RLIMIT_NPROC    max number of processes
         * RLIMIT_NOFILE   max number of open files
         * RLIMIT_MEMLOCK  max locked-in-memory address space
         * RLIMIT_AS       address space (virtual memory) limit
         *
         * RLIMIT_CPU      CPU time in seconds
         * RLIMIT_DATA     max data size
         *
         * Currently, we only limit the CPU time and the DATA segment
         * We also "nice" the process.
         *
         * This section of code adapted from patches sent in by Steve Thompson
         * (no email available)
         */

        {
            struct rlimit rl;
            int retval;

            if (cgi_rlimit_cpu) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_cpu;
                retval = setrlimit(RLIMIT_CPU, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_CPU,%d): %s\n",
                            rlimit_cpu, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_limit_data) {
                rl.rlim_cur = rl.rlim_max = cgi_rlimit_data;
                retval = setrlimit(RLIMIT_DATA, &rl);
                if (retval == -1) {
                    log_error_time();
                    fprintf(stderr,
                            "setrlimit(RLIMIT_DATA,%d): %s\n",
                            rlimit_data, strerror(errno));
                    _exit(EXIT_FAILURE);
                }
            }

            if (cgi_nice) {
                retval = nice(cgi_nice);
                if (retval == -1) {
                    log_error_time();
                    perror("nice");
                    _exit(EXIT_FAILURE);
                }
            }
        }
#endif

        umask(cgi_umask);       /* change umask *again* u=rwx,g=rxw,o= */

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tie STDERR (current log_error) to cgi_log_fd,
         *  then we ought to tie it to /dev/null
         *  FIXME: we currently don't tie it to /dev/null, we leave it
         *  tied to whatever 'error_log' points to.  This means CGIs can
         *  scribble on the error_log, probably a bad thing.
         */
        if (cgi_log_fd) {
            dup2(cgi_log_fd, STDERR_FILENO);
        }

        if (req->cgi_type) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      (void *) NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, (void *) NULL);
#endif
        }
        /* execve failed */
        log_error_doc(req);
        fprintf(stderr, "Unable to execve/execl pathname: \"%s\"",
                req->pathname);
        perror("");
        _exit(EXIT_FAILURE);
        break;

    default:
        /* parent */
        /* if here, fork was successful */
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {

// davidhsu ----------------
#ifndef NEW_POST
             close(req->post_data_fd); /* child closed it too */
             req->post_data_fd = 0;
#else			 
		if (req->post_data) {
			free(req->post_data);
			req->post_data = NULL;
		}
		req->post_data_len = 0;
		req->post_data_idx = 0;
#endif		
//------------------------

        }

        /* NPH, GUNZIP, etc... all go straight to the fd */
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->cgi_type == CGI) {
            req->cgi_status = CGI_PARSE; /* got to parse cgi header */
            /* for cgi_header... I get half the buffer! */
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            /* I get all the buffer! */
            req->header_line = req->header_end = req->buffer;
        }

        /* reset req->filepos for logging (it's used in pipe.c) */
        /* still don't know why req->filesize might be reset though */
        req->filepos = 0;
        break;
    }
#endif //!EXCLUDE_CGI

    return 1;
}
Ejemplo n.º 2
0
int init_cgi(request * req)
{
	int child_pid;
	int pipes[2];
	int use_pipes = 0;

	SQUASH_KA(req);

	if (req->is_cgi) {
		if (complete_env(req) == 0) {
			return 0;
		}
	}

	if (req->is_cgi == CGI || 1) {
		use_pipes = 1;
		if (pipe(pipes) == -1) {
			log_error_time();
			perror("pipe");
			return 0;
		}

		/* set the read end of the socket to non-blocking */
		if (set_nonblock_fd(pipes[0]) == -1) {
			log_error_time();
			perror("cgi-fcntl");
			close(pipes[0]);
			close(pipes[1]);
			return 0;
		}
	}

	child_pid = fork();
	switch(child_pid) {
		case -1:
			/* fork unsuccessful */
			log_error_time();
			perror("fork");

			if (use_pipes) {
				close(pipes[0]);
				close(pipes[1]);
			}
			send_r_error(req);
			/* FIXME: There is aproblem here. send_r_error would work
			   for NPH and CGI, but not for GUNZIP.  Fix that. */
			/* i'd like to send_r_error, but.... */
			return 0;
			break;
		case 0:
			/* child */
			if (req->is_cgi == CGI || req->is_cgi == NPH) {
				char *foo = strdup(req->pathname);
				char *c;

				if (!foo) {
					WARN("unable to strdup pathname for req->pathname");
					_exit(1);
				}
				c = strrchr(foo, '/');
				if (c) {
					++c;
					*c = '\0';
				} else {
					/* we have a serious problem */
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
				if (chdir(foo) != 0) {
					log_error_time();
					perror("chdir");
					if (use_pipes)
						close(pipes[1]);
					_exit(1);
				}
			}
			if (use_pipes) {
				close(pipes[0]);
				/* tie cgi's STDOUT to it's write end of pipe */
				if (dup2(pipes[1], STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - pipes");
					close(pipes[1]);
					_exit(1);
				}
				close(pipes[1]);
				if (set_block_fd(STDOUT_FILENO) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			} else {
				/* tie stdout to socket */
				if (dup2(req->fd, STDOUT_FILENO) == -1) {
					log_error_time();
					perror("dup2 - fd");
					_exit(1);
				}
				/* Switch socket flags back to blocking */
				if (set_block_fd(req->fd) == -1) {
					log_error_time();
					perror("cgi-fcntl");
					_exit(1);
				}
			}
			/* tie post_data_fd to POST stdin */
			if (req->method == M_POST) { /* tie stdin to file */
				lseek(req->post_data_fd, SEEK_SET, 0);
				dup2(req->post_data_fd, STDIN_FILENO);
				close(req->post_data_fd);
			}
			/* Close access log, so CGI program can't scribble
			 * where it shouldn't
			 */
			close_access_log();

			/*
			 * tie STDERR to cgi_log_fd
			 * cgi_log_fd will automatically close, close-on-exec rocks!
			 * if we don't tied STDERR (current log_error) to cgi_log_fd,
			 *  then we ought to close it.
			 */
			//if (!cgi_log_fd)
			//	dup2(devnullfd, STDERR_FILENO);
			//else
			//	dup2(cgi_log_fd, STDERR_FILENO);

			if (req->is_cgi) {
				char *aargv[CGI_ARGC_MAX + 1];
				create_argv(req, aargv);
				execve(req->pathname, aargv, req->cgi_env);
			} else {
				if (req->pathname[strlen(req->pathname) - 1] == '/')
					execl(dirmaker, dirmaker, req->pathname, req->request_uri,
							NULL);
#ifdef GUNZIP
				else
					execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
							req->pathname, NULL);
#endif
			}
			/* execve failed */
			WARN(req->pathname);
			_exit(1);
			break;

		default:
			/* parent */
			/* if here, fork was successful */
			if (verbose_cgi_logs) {
				log_error_time();
				fprintf(stderr, "Forked child \"%s\" pid %d\n",
						req->pathname, child_pid);
			}

			if (req->method == M_POST) {
				close(req->post_data_fd); /* child closed it too */
				req->post_data_fd = 0;
			}

			/* NPH, GUNZIP, etc... all go straight to the fd */
			if (!use_pipes)
				return 0;

			close(pipes[1]);
			req->data_fd = pipes[0];

			req->status = PIPE_READ;
			if (req->is_cgi == CGI) {
				req->cgi_status = CGI_PARSE; /* got to parse cgi header */
				/* for cgi_header... I get half the buffer! */
				req->header_line = req->header_end =
					(req->buffer + BUFFER_SIZE / 2);
			} else {
				req->cgi_status = CGI_BUFFER;
				/* I get all the buffer! */
				req->header_line = req->header_end = req->buffer;
			}

			/* reset req->filepos for logging (it's used in pipe.c) */
			/* still don't know why req->filesize might be reset though */
			req->filepos = 0;
			break;
	}

	return 1;
}
int handle_input_line(int socket_fd, const char *input_line, int had_cr, int had_lf)
{
  static const char *seperator_seperator = ";";
  static const char *terminator_terminator = "\n";
  const char *this_stSettings_iTimeOut_str_s = ".THIS.stSettings.iTimeOut=";

  static unsigned int counter;

  const char **my_argv = NULL;
  int argc = create_argv(input_line, had_cr, had_lf, (const char*** )&my_argv);
  const char *argv1 = (argc > 1) ? my_argv[1] : "";
  int is_EAT_cmd = strchr(input_line, ';') != NULL;

  if (!strncmp(argv1, this_stSettings_iTimeOut_str_s, strlen(this_stSettings_iTimeOut_str_s))) {
    const char *myarg_1 = &argv1[strlen(this_stSettings_iTimeOut_str_s)];
    int timeout;
    int nvals;
    nvals = sscanf(myarg_1, "%d", &timeout);
    if (nvals == 1) {
      int res = socket_set_timeout(socket_fd, timeout);
      cmd_buf_printf("%s%s%s",
                     res ? "Error" : "OK",
                     seperator_seperator,
                     terminator_terminator);
    } else {
      cmd_buf_printf("Error nvals=%d %s%s",
                     nvals,
                     seperator_seperator,
                     terminator_terminator);
    }
  }
  else if (is_EAT_cmd) {
    cmd_EAT(argc, my_argv);
  }
  else if ((argc > 1) && (0 == strcmp(argv1, "bye"))) {
    fprintf(stdlog, "%s/%s:%d bye\n", __FILE__, __FUNCTION__, __LINE__);
    return 1;
  }
  else if ((argc > 1) && (0 == strcmp(argv1, "kill"))) {
    exit(0);
  }
  else if (cmd_TCPsim(argc, my_argv)) {
    ; /* TCPsim command */
  }
  else if (cmd_IcePAP(argc, my_argv)) {
    ; /* IcePAP command */
  }
  else if (argv1[0] == 'h' ||
           argv1[0] == '?') {
    fd_printf_crlf(socket_fd, had_cr,
                   "Valid commands :\n");
    fd_printf_crlf(socket_fd, had_cr,
                   "bye            : Bye\n"
                   "kill           : exit(0)\n");
  }
  else if (argc > 2){
    fd_printf_crlf(socket_fd, had_cr,"error(%s:%d): invalid command (%s)\n",
                   __FILE__, __LINE__,  argv1);
  }
  else if (argc == 1) {
    /* Just a return, print a prompt */
  }
  {
    int i;
    for (i=0; i < argc; i++)
    {
      free((void *)my_argv[i]);
    }
    free(my_argv);
  }
  if (PRINT_STDOUT_BIT2()) {
    fprintf(stdlog, "%s/%s:%d (%u)\n",
            __FILE__, __FUNCTION__, __LINE__,
            counter++);
  }
  {
    int flags = had_cr ? PRINT_ADD_CR : 0;
    const char *buf = get_buf();

    fd_printf_crlf(socket_fd, flags, "%s", buf);
    clear_buf();
  }

  return 0;
}
Ejemplo n.º 4
0
int init_cgi(request * req)
{
	int child_pid;
	int p[2];

	SQUASH_KA(req);

	complete_env(req);

	if (req->is_cgi == CGI) {
		if (pipe(p) == -1) {
#ifdef BOA_TIME_LOG
			log_error_time();
			perror("pipe");
#endif
			syslog(LOG_ERR, "pipe: %d.\n", errno);
			return 0;
		}
		if (fcntl(p[0], F_SETFL, O_NONBLOCK) == -1) {
#ifdef BOA_TIME_LOG
			fprintf(stderr, "Unable to do something: %d.\n", errno);
#endif
			syslog(LOG_ERR, "Unable to do something: %d.\n", errno);
			close(p[0]);
			close(p[1]);
			return 0;
		}
	}
#ifdef EMBED
	if ((child_pid = vfork()) == -1) {	/* vfork unsuccessful */
#else
	if ((child_pid = fork()) == -1) {	/* fork unsuccessful */
#endif
		if (req->is_cgi == CGI) {
			close(p[0]);
			close(p[1]);
		}
#ifdef BOA_TIME_LOG
		log_error_time();
		perror("fork");
#endif
		return 0;
	}
	/* if here, fork was successful */

	if (!child_pid) {			/* 0 == child */
		int newstdin = -1, newstdout = -1, newstderr = -1;

		if (req->is_cgi != CGI) {	/* nph or gunzip, etc... */
			newstdout = req->fd;
		} else {
			/* tie stdout to write end of pipe */
			close(p[0]);
			newstdout = p[1];
		}

		/* tie post_data_fd to POST stdin */
		if (req->method == M_POST) {	/* tie stdin to file */
			lseek(req->post_data_fd, SEEK_SET, 0);
			newstdin = req->post_data_fd;
		}

		/* Close access log, so CGI program can't scribble 
		 * where it shouldn't 
		 */
		close_access_log();

		/* tie STDERR to cgi_log_fd */
		if (cgi_log_fd)
			newstderr = cgi_log_fd;
		else
			newstderr = open("/dev/null", O_WRONLY);

		/* Set up stdin/out/err without trampling over each other. */
		if (newstdin >= 0 && newstdin != STDIN_FILENO) {
			if (newstdout == STDIN_FILENO)
				newstdout = dup(newstdout);
			if (newstderr == STDIN_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdin, STDIN_FILENO);
			close(newstdin);
		}
		if (newstdout >= 0 && newstdout != STDOUT_FILENO) {
			if (newstderr == STDOUT_FILENO)
				newstderr = dup(newstderr);
			dup2(newstdout, STDOUT_FILENO);
			close(newstdout);
			/* Switch socket flags back to blocking */
			if (fcntl(STDOUT_FILENO, F_SETFL, 0) == -1) {
#ifdef BOA_TIME_LOG
				perror("cgi-fcntl");
#endif
			}
		}
		if (newstderr >= 0 && newstderr != STDERR_FILENO) {
			dup2(newstderr, STDERR_FILENO);
			close(newstderr);
		}

		if (req->is_cgi) {
			char *aargv[ARGC_MAX + 1];
			create_argv(req, aargv);
			execve(req->pathname, aargv, req->cgi_env);
		} else {
			if (req->pathname[strlen(req->pathname) - 1] == '/')
				execl(dirmaker, dirmaker, req->pathname, req->request_uri, NULL);
			else {
#if 0
				execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
					  req->pathname, NULL);
#endif
				syslog(LOG_ERR, "gunzip not found");
				
			}
		}
		/* execve failed */
		log_error_time();
		perror(req->pathname);
		_exit(1);
	}
	/* if here, fork was successful */

	if (verbose_cgi_logs) {
#ifdef BOA_TIME_LOG
		log_error_time();
		fprintf(stderr, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
#endif
		syslog(LOG_INFO, "Forked child \"%s\" pid %d\n",
				req->pathname, child_pid);
	}
	if (req->is_cgi != CGI)
		return 0;

	req->data_fd = p[0];

	/* close duplicate write end of pipe */
	close(p[1]);
	
	req->status = PIPE_READ;
	req->filesize = req->filepos = 0; /* why is this here??? */

	if (req->is_cgi == CGI) {		/* cgi */
		/* for cgi_header... I get half the buffer! */
		req->header_line = req->header_end = 
 			(req->buffer + BUFFER_SIZE / 2);
		req->cgi_status = CGI_READ;	/* got to parse cgi header */
	} else	{					/* gunzip or similar */
		req->header_line = req->header_end = req->buffer;
		req->cgi_status = CGI_WRITE;	/* don't do it. */
	}
	
	return 1;					/* success */
}
Ejemplo n.º 5
0
int init_cgi(request * req)
{
    int child_pid;
    int pipes[2];
    int use_pipes = 0;

    SQUASH_KA(req);

    if (req->is_cgi) {
        if (complete_env(req) == 0) {
            return 0;
        }
    }
#ifdef FASCIST_LOGGING
    {
        int i;
        for (i = 0; i < req->cgi_env_index; ++i)
            fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n",
                    __FILE__, req->cgi_env[i]);
    }
#endif

    if (req->is_cgi == CGI || 1) {
        use_pipes = 1;
        if (pipe(pipes) == -1) {
            log_error_time();
            perror("pipe");
            return 0;
        }

        
        if (set_nonblock_fd(pipes[0]) == -1) {
            log_error_time();
            perror("cgi-fcntl");
            close(pipes[0]);
            close(pipes[1]);
            return 0;
        }
    }

    child_pid = fork();
    switch(child_pid) {
    case -1:
        
        log_error_time();
        perror("fork");

        if (use_pipes) {
            close(pipes[0]);
            close(pipes[1]);
        }
        send_r_error(req);
        /* FIXME: There is aproblem here. send_r_error would work
           for NPH and CGI, but not for GUNZIP.  Fix that. */
        
        return 0;
        break;
    case 0:
        
        if (req->is_cgi == CGI || req->is_cgi == NPH) {
            char *foo = strdup(req->pathname);
            char *c;

            if (!foo) {
                WARN("unable to strdup pathname for req->pathname");
                _exit(1);
            }
            c = strrchr(foo, '/');
            if (c) {
                ++c;
                *c = '\0';
            } else {
                
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
            if (chdir(foo) != 0) {
                log_error_time();
                perror("chdir");
                if (use_pipes)
                    close(pipes[1]);
                _exit(1);
            }
        }
        if (use_pipes) {
            close(pipes[0]);
            
            if (dup2(pipes[1], STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - pipes");
                close(pipes[1]);
                _exit(1);
            }
            close(pipes[1]);
            if (set_block_fd(STDOUT_FILENO) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        } else {
            
            if (dup2(req->fd, STDOUT_FILENO) == -1) {
                log_error_time();
                perror("dup2 - fd");
                _exit(1);
            }
            
            if (set_block_fd(req->fd) == -1) {
                log_error_time();
                perror("cgi-fcntl");
                _exit(1);
            }
        }
        
        if (req->method == M_POST) { 
            lseek(req->post_data_fd, SEEK_SET, 0);
            dup2(req->post_data_fd, STDIN_FILENO);
            close(req->post_data_fd);
        }
        /* Close access log, so CGI program can't scribble
         * where it shouldn't
         */
        close_access_log();

        /*
         * tie STDERR to cgi_log_fd
         * cgi_log_fd will automatically close, close-on-exec rocks!
         * if we don't tied STDERR (current log_error) to cgi_log_fd,
         *  then we ought to close it.
         */
        if (!cgi_log_fd)
            dup2(devnullfd, STDERR_FILENO);
        else
            dup2(cgi_log_fd, STDERR_FILENO);

        if (req->is_cgi) {
            char *aargv[CGI_ARGC_MAX + 1];
            create_argv(req, aargv);
            execve(req->pathname, aargv, req->cgi_env);
        } else {
            if (req->pathname[strlen(req->pathname) - 1] == '/')
                execl(dirmaker, dirmaker, req->pathname, req->request_uri,
                      NULL);
#ifdef GUNZIP
            else
                execl(GUNZIP, GUNZIP, "--stdout", "--decompress",
                      req->pathname, NULL);
#endif
        }
        
        WARN(req->pathname);
        _exit(1);
        break;

    default:
        
        
        if (verbose_cgi_logs) {
            log_error_time();
            fprintf(stderr, "Forked child \"%s\" pid %d\n",
                    req->pathname, child_pid);
        }

        if (req->method == M_POST) {
            close(req->post_data_fd); 
            req->post_data_fd = 0;
        }

        
        if (!use_pipes)
            return 0;

        close(pipes[1]);
        req->data_fd = pipes[0];

        req->status = PIPE_READ;
        if (req->is_cgi == CGI) {
            req->cgi_status = CGI_PARSE; 
            
            req->header_line = req->header_end =
                (req->buffer + BUFFER_SIZE / 2);
        } else {
            req->cgi_status = CGI_BUFFER;
            
            req->header_line = req->header_end = req->buffer;
        }

        
        
        req->filepos = 0;
        break;
    }

    return 1;
}