ret_t cherokee_shm_map (cherokee_shm_t *shm, cherokee_buffer_t *name) { int re; int fd; struct stat info; fd = shm_open (name->buf, O_RDWR, 0600); if (fd < 0) { return ret_error; } re = fstat (fd, &info); if (re != 0) { return ret_error; } shm->mem = mmap (0, info.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm->mem == MAP_FAILED) { cherokee_fd_close (fd); shm->mem = NULL; return ret_error; } cherokee_fd_close (fd); cherokee_buffer_clean (&shm->name); cherokee_buffer_add_buffer (&shm->name, name); return ret_ok; }
ret_t cherokee_shm_create (cherokee_shm_t *shm, char *name, size_t len) { int re; int fd; fd = shm_open (name, O_RDWR | O_EXCL | O_CREAT, 0600); if (fd < 0) { return ret_error; } re = ftruncate (fd, len); if (re < 0) { cherokee_fd_close (fd); return ret_error; } shm->mem = mmap (0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (shm->mem == MAP_FAILED) { shm->mem = NULL; cherokee_fd_close (fd); return ret_error; } cherokee_fd_close (fd); shm->len = len; cherokee_buffer_add (&shm->name, name, strlen(name)); return ret_ok; }
ret_t cherokee_buffer_read_file (cherokee_buffer_t *buf, char *filename) { int r, f; ret_t ret; struct stat info; /* Stat() the file */ r = cherokee_stat (filename, &info); if (r != 0) return ret_error; /* Is a regular file? */ if (S_ISREG(info.st_mode) == 0) return ret_error; /* Maybe get memory */ ret = cherokee_buffer_ensure_size (buf, buf->len + info.st_size + 1); if (unlikely (ret != ret_ok)) return ret; /* Open the file */ f = cherokee_open (filename, O_RDONLY | O_BINARY, 0); if (f < 0) { LOG_ERRNO(errno, cherokee_err_error, CHEROKEE_ERROR_BUFFER_OPEN_FILE, filename); return ret_error; } cherokee_fd_set_closexec (f); /* Read the content */ r = read (f, buf->buf + buf->len, info.st_size); if (r < 0) { buf->buf[buf->len] = '\0'; cherokee_fd_close(f); return ret_error; } /* Close it and exit */ cherokee_fd_close(f); buf->len += r; buf->buf[buf->len] = '\0'; return ret_ok; }
ret_t cherokee_socket_accept_fd (cherokee_socket_t *server_socket, int *new_fd, cherokee_sockaddr_t *sa) { ret_t ret; socklen_t len; int new_socket; /* Get the new connection */ len = sizeof (cherokee_sockaddr_t); do { new_socket = accept (server_socket->socket, &sa->sa, &len); } while ((new_socket == -1) && (errno == EINTR)); if (new_socket < 0) { return ret_error; } /* It'd nice to be able to reuse the address even if the * socket is still in TIME_WAIT statue (2*RTT ~ 120 seg) */ cherokee_fd_set_reuseaddr (new_socket); /* Close-on-exec: Child processes won't inherit this fd */ cherokee_fd_set_closexec (new_socket); /* Enables nonblocking I/O. */ ret = cherokee_fd_set_nonblocking (new_socket, true); if (ret != ret_ok) { LOG_WARNING (CHEROKEE_ERROR_SOCKET_NON_BLOCKING, new_socket); cherokee_fd_close (new_socket); return ret_error; } /* Disable Nagle's algorithm for this connection * so that there is no delay involved when sending data * which don't fill up a full IP datagram. */ ret = cherokee_fd_set_nodelay (new_socket, true); if (ret != ret_ok) { LOG_WARNING_S (CHEROKEE_ERROR_SOCKET_RM_NAGLES); cherokee_fd_close (new_socket); return ret_error; } *new_fd = new_socket; return ret_ok; }
ret_t cherokee_socket_close (cherokee_socket_t *socket) { ret_t ret; /* Sanity check */ if (socket->socket < 0) { return ret_error; } /* Close the socket */ #ifdef _WIN32 ret = closesocket (socket->socket); #else ret = cherokee_fd_close (socket->socket); #endif /* Clean up */ TRACE (ENTRIES",close", "fd=%d is_tls=%d re=%d\n", socket->socket, socket->is_tls, (int) ret); socket->socket = -1; socket->status = socket_closed; socket->is_tls = non_TLS; return ret; }
static ret_t launch_logger_process (cherokee_logger_writer_t *writer) { #ifdef HAVE_FORK int fd; int to_log_fds[2]; pid_t pid; if (cherokee_pipe (to_log_fds)) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_LOGGER_WRITER_PIPE, errno); return ret_error; } switch (pid = fork()) { case 0: /* Child */ cherokee_fd_close (STDIN_FILENO); dup2 (to_log_fds[0], STDIN_FILENO); cherokee_fd_close (to_log_fds[0]); cherokee_fd_close (to_log_fds[1]); for (fd = 3; fd < 256; fd++) { cherokee_fd_close (fd); } do { execl("/bin/sh", "sh", "-c", writer->command.buf, NULL); } while (errno == EINTR); SHOULDNT_HAPPEN; case -1: LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_LOGGER_WRITER_FORK, errno); break; default: cherokee_fd_close (to_log_fds[0]); writer->fd = to_log_fds[1]; } #else return ret_no_sys; #endif return ret_ok; }
static ret_t fork_and_execute_cgi_unix (cherokee_handler_cgi_t *cgi) { int re; int pid; cherokee_connection_t *conn = HANDLER_CONN(cgi); struct { int cgi[2]; int server[2]; } pipes; /* Creates the pipes ... */ re = pipe (pipes.cgi); re |= pipe (pipes.server); if (re != 0) { conn->error_code = http_internal_error; return ret_error; } /* .. and fork the process */ pid = fork(); if (pid == 0) { /* CGI process */ manage_child_cgi_process (cgi, pipes.cgi, pipes.server); } else if (pid < 0) { /* Error */ cherokee_fd_close (pipes.cgi[0]); cherokee_fd_close (pipes.cgi[1]); cherokee_fd_close (pipes.server[0]); cherokee_fd_close (pipes.server[1]); conn->error_code = http_internal_error; return ret_error; } TRACE (ENTRIES, "pid %d\n", pid); cherokee_fd_close (pipes.server[0]); cherokee_fd_close (pipes.cgi[1]); cgi->pid = pid; cgi->pipeInput = pipes.cgi[0]; cgi->pipeOutput = pipes.server[1]; /* Set to Input to NON-BLOCKING */ _fd_set_properties (cgi->pipeInput, O_NDELAY|O_NONBLOCK, 0); return ret_ok; }
static ret_t logger_writer_close_file (cherokee_logger_writer_t *writer) { ret_t ret = ret_ok; if (writer->fd != -1) { if (writer->type != cherokee_logger_writer_stderr) { if (cherokee_fd_close (writer->fd) != 0) ret = ret_error; } writer->fd = -1; } return ret; }
ret_t cherokee_handler_cgi_read_post (cherokee_handler_cgi_t *cgi) { ret_t ret; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_socket_status_t blocking = socket_closed; cherokee_boolean_t did_IO = false; if (! conn->post.has_info) { return ret_ok; } ret = cherokee_post_send_to_fd (&conn->post, &conn->socket, cgi->pipeOutput, NULL, &blocking, &did_IO); if (did_IO) { cherokee_connection_update_timeout (conn); } switch (ret) { case ret_ok: break; case ret_eagain: if (blocking == socket_writing) { cherokee_thread_deactive_to_polling (HANDLER_THREAD(cgi), conn, cgi->pipeOutput, FDPOLL_MODE_WRITE, false); return ret_deny; } /* ret_eagain - Block on read * ret_deny - Block on back-end write */ if (cherokee_post_has_buffered_info (&conn->post)) { return ret_deny; } return ret_eagain; default: return ret; } TRACE (ENTRIES",post", "%s\n", "finished"); cherokee_fd_close (cgi->pipeOutput); cgi->pipeOutput = -1; return ret_ok; }
ret_t cherokee_socket_accept (cherokee_socket_t *socket, cherokee_socket_t *server_socket) { ret_t ret; int fd; cherokee_sockaddr_t sa; ret = cherokee_socket_accept_fd (server_socket, &fd, &sa); if (unlikely(ret < ret_ok)) return ret; ret = cherokee_socket_set_sockaddr (socket, fd, &sa); if (unlikely(ret < ret_ok)) { cherokee_fd_close (fd); SOCKET_FD(socket) = -1; return ret; } return ret_ok; }
ret_t cherokee_socket_accept_fd (cherokee_socket_t *server_socket, int *new_fd, cherokee_sockaddr_t *sa) { ret_t ret; socklen_t len; int new_socket; /* Get the new connection */ len = sizeof (cherokee_sockaddr_t); do { new_socket = accept (server_socket->socket, &sa->sa, &len); } while ((new_socket == -1) && (errno == EINTR)); if (new_socket < 0) { return ret_error; } #if 0 /* DISABLED */ /* Deal with the FIN_WAIT2 state */ re = 1; re = setsockopt (new_socket, SOL_SOCKET, SO_KEEPALIVE, &re, sizeof(re)); if (re == -1) { LOG_ERRNO (errno, cherokee_err_warning, CHEROKEE_ERROR_SOCKET_SET_KEEPALIVE, new_socket); } linger.l_onoff = 1; linger.l_linger = SECONDS_TO_LINGER; re = setsockopt (new_socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); if (re == -1) { LOG_ERRNO (errno, cherokee_err_warning, CHEROKEE_ERROR_SOCKET_SET_LINGER, new_socket); } #endif /* Close-on-exec: Child processes won't inherit this fd */ cherokee_fd_set_closexec (new_socket); /* Enables nonblocking I/O. */ ret = cherokee_fd_set_nonblocking (new_socket, true); if (ret != ret_ok) { LOG_WARNING (CHEROKEE_ERROR_SOCKET_NON_BLOCKING, new_socket); cherokee_fd_close (new_socket); return ret_error; } /* Disable Nagle's algorithm for this connection * so that there is no delay involved when sending data * which don't fill up a full IP datagram. */ ret = cherokee_fd_set_nodelay (new_socket, true); if (ret != ret_ok) { LOG_WARNING_S (CHEROKEE_ERROR_SOCKET_RM_NAGLES); cherokee_fd_close (new_socket); return ret_error; } *new_fd = new_socket; return ret_ok; }
static NORETURN void manage_child_cgi_process (cherokee_handler_cgi_t *cgi, int pipe_cgi[2], int pipe_server[2]) { /* Child process */ int re; char *script; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); char *absolute_path = cgi_base->executable.buf; char *argv[2] = { NULL, NULL }; #ifdef TRACE_ENABLED TRACE(ENTRIES, "About to execute: '%s'\n", absolute_path); if (! cherokee_buffer_is_empty (&conn->effective_directory)) TRACE(ENTRIES, "Effective directory: '%s'\n", conn->effective_directory.buf); else TRACE(ENTRIES, "No Effective directory %s", "\n"); #endif /* Close useless sides */ cherokee_fd_close (pipe_cgi[0]); cherokee_fd_close (pipe_server[1]); /* Change stdin and out */ re = dup2 (pipe_server[0], STDIN_FILENO); cherokee_fd_close (pipe_server[0]); if (unlikely (re != 0)) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } re |= dup2 (pipe_cgi[1], STDOUT_FILENO); cherokee_fd_close (pipe_cgi[1]); /* Redirect the stderr */ if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { dup2 (CONN_VSRV(conn)->error_writer->fd, STDERR_FILENO); } # if 0 /* Set unbuffered */ setvbuf (stdin, NULL, _IONBF, 0); setvbuf (stdout, NULL, _IONBF, 0); # endif /* Enable blocking mode */ _fd_set_properties (STDIN_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDOUT_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDERR_FILENO, 0, O_NONBLOCK); /* Sets the new environ. */ add_environment (cgi, conn); /* Change the directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { re = chdir (conn->effective_directory.buf); } else { char *file = strrchr (absolute_path, '/'); *file = '\0'; re = chdir (absolute_path); *file = '/'; } if (re < 0) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } /* Build de argv array */ script = absolute_path; argv[0] = absolute_path; /* Change the execution user? */ if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat info; re = stat (script, &info); if (re >= 0) { re = setuid (info.st_uid); if (re != 0) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_SETID, script, info.st_uid); } } } /* Reset the server-wide signal handlers */ #ifdef SIGPIPE signal (SIGPIPE, SIG_DFL); #endif #ifdef SIGHUP signal (SIGHUP, SIG_DFL); #endif #ifdef SIGSEGV signal (SIGSEGV, SIG_DFL); #endif #ifdef SIGBUS signal (SIGBUS, SIG_DFL); #endif #ifdef SIGTERM signal (SIGTERM, SIG_DFL); #endif /* Lets go.. execute it! */ re = execve (absolute_path, argv, cgi->envp); if (re < 0) { int err = errno; char buferr[ERROR_MAX_BUFSIZE]; switch (err) { case ENOENT: printf ("Status: 404" CRLF_CRLF); break; default: printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d cmd=%s: %s" CRLF_CRLF, __FILE__, __LINE__, absolute_path, strerror(err)); } /* Don't use the logging system (concurrency issues) */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_EXECUTE, absolute_path, cherokee_strerror_r(err, buferr, sizeof(buferr))); exit(1); } /* There is no way, it could reach this point. */ SHOULDNT_HAPPEN; exit(2); }
ret_t cherokee_handler_cgi_free (cherokee_handler_cgi_t *cgi) { int i; /* Free the rest of the handler CGI memory */ cherokee_handler_cgi_base_free (HDL_CGI_BASE(cgi)); /* Close the connection with the CGI */ if (cgi->pipeInput > 0) { cherokee_fd_close (cgi->pipeInput); cgi->pipeInput = -1; } if (cgi->pipeOutput > 0) { cherokee_fd_close (cgi->pipeOutput); cgi->pipeOutput = -1; } /* Kill the CGI */ #ifndef _WIN32 if (cgi->pid > 0) { pid_t pid; cint_t tries = 2; while (true) { do { pid = waitpid (cgi->pid, NULL, WNOHANG); } while ((pid == 1) && (errno == EINTR)); if (pid > 0) { /* Ok */ break; } else if (errno == ECHILD) { /* Already death */ break; } /* Failed */ kill (cgi->pid, SIGTERM); tries--; if (tries < 0) break; } } #else if (cgi->process) { WaitForSingleObject (cgi->process, INFINITE); CloseHandle (cgi->process); } if (cgi->thread) { CloseHandle (cgi->thread); } #endif /* Free the environment variables */ #ifdef _WIN32 cherokee_buffer_mrproper (&cgi->envp); #else for (i=0; i<cgi->envp_last; i++) { free (cgi->envp[i]); cgi->envp[i] = NULL; } #endif /* For some reason, we have seen that the SIGCHLD signal does not call to * our handler in a server with a lot of requests, so the wait() call, * necessary to free the resources used by the CGI, is not called. So I * think that a possible solution couble be to put the waitpid call in the * _free method of this handler, so when the handler ends, this will free * the resources used by our cool CGI. */ do_reap(); return ret_ok; }
static ret_t fork_and_execute_cgi_via_spawner(cherokee_handler_cgi_t *cgi) { int re; int pid = -1; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); ret_t ret; uid_t uid; gid_t gid; cherokee_buffer_t empty = CHEROKEE_BUF_INIT; cherokee_buffer_t username = CHEROKEE_BUF_INIT; cherokee_services_fdmap_t fd_map; cherokee_buffer_t *chdir = NULL; cherokee_buffer_t chdir_backing = CHEROKEE_BUF_INIT; struct passwd ent; char ent_tmp[1024]; struct { int cgi[2]; int server[2]; } pipes; TRACE (ENTRIES, "Trying to create CGI via spawner\n"); if (! cherokee_buffer_is_empty (&conn->effective_directory)) { chdir = &conn->effective_directory; } else { int ofs = cgi_base->executable.len - 1; while (ofs >= 0 && cgi_base->executable.buf[ofs] != '/') { ofs--; } TRACE (ENTRIES, "While building chdir, ofs=%d\n", ofs); if (ofs < 0 || cherokee_buffer_add (&chdir_backing, cgi_base->executable.buf, ofs + 1) != ret_ok) { conn->error_code = http_internal_error; TRACE (ENTRIES, "Failed, cannot build chdir entry\n"); cherokee_buffer_mrproper(&chdir_backing); return ret_error; } chdir = &chdir_backing; } /* Creates the pipes ... */ re = cherokee_pipe (pipes.cgi); re |= cherokee_pipe (pipes.server); if (re != 0) { conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); TRACE (ENTRIES, "Failed, cannot build pipes\n"); return ret_error; } if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat nocache_info; struct stat *info; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_handler_cgi_base_props_t *props = HANDLER_CGI_BASE_PROPS(cgi); ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info); if (ret != ret_ok) { info = &nocache_info; nocache_info.st_uid = getuid(); nocache_info.st_gid = getgid(); } uid = info->st_uid; gid = info->st_gid; cherokee_iocache_entry_unref(&io_entry); } else { /* Not changing, so launch as the same uid/gid as the worker */ uid = getuid(); gid = getgid(); } /* Determine the username of the owner of the file */ ret = cherokee_getpwuid(uid, &ent, ent_tmp, sizeof (ent_tmp)); if (ret != ret_ok || cherokee_buffer_add(&username, ent.pw_name, strlen(ent.pw_name) != ret_ok)) { cherokee_fd_close(pipes.cgi[0]); cherokee_fd_close(pipes.cgi[1]); cherokee_fd_close(pipes.server[0]); cherokee_fd_close(pipes.server[1]); conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); TRACE (ENTRIES, "Failed, Unable to retrieve username for uid %d\n", uid); return ret_error; } /* Update the environment ready to run */ add_environment (cgi, conn); /* Set up the FD map */ fd_map.fd_in = pipes.server[0]; fd_map.fd_out = pipes.cgi[1]; if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { fd_map.fd_err = CONN_VSRV(conn)->error_writer->fd; } else { fd_map.fd_err = fd_map.fd_out; } TRACE (ENTRIES, "Doing Spawn\n"); ret = cherokee_services_client_spawn (&cgi_base->executable, &username, uid, gid, &empty, chdir, false, cgi->envp, CONN_VSRV(conn)->error_writer, &pid, &fd_map); cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); /* Close the client FDs */ cherokee_fd_close (pipes.server[0]); cherokee_fd_close (pipes.cgi[1]); /* Did we fail to try to spawn? */ if (ret != ret_ok) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Failed to spawn\n"); return ret; } /* Did we try, but fail, to spawn? */ if (pid == -1) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Spawned, but failed server side\n"); return ret_error; } /* Successfully launched */ cgi->pid = pid; cgi->pipeInput = pipes.cgi[0]; cgi->pipeOutput = pipes.server[1]; /* Set to Input to NON-BLOCKING */ _fd_set_properties (cgi->pipeInput, O_NDELAY|O_NONBLOCK, 0); TRACE (ENTRIES, "CGI running, PID=%d\n", pid); return ret_ok; }
static NORETURN void manage_child_cgi_process (cherokee_handler_cgi_t *cgi, int pipe_cgi[2], int pipe_server[2]) { /* Child process */ int re; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); char *absolute_path = cgi_base->executable.buf; char *argv[2] = { NULL, NULL }; #ifdef TRACE_ENABLED TRACE(ENTRIES, "About to execute: '%s'\n", absolute_path); if (! cherokee_buffer_is_empty (&conn->effective_directory)) TRACE(ENTRIES, "Effective directory: '%s'\n", conn->effective_directory.buf); else TRACE(ENTRIES, "No Effective directory %s", "\n"); #endif /* Close useless sides */ cherokee_fd_close (pipe_cgi[0]); cherokee_fd_close (pipe_server[1]); /* Change stdin and out */ cherokee_fd_close (STDIN_FILENO); re = dup2 (pipe_server[0], STDIN_FILENO); cherokee_fd_close (pipe_server[0]); if (unlikely (re != 0)) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } cherokee_fd_close (STDOUT_FILENO); re |= dup2 (pipe_cgi[1], STDOUT_FILENO); cherokee_fd_close (pipe_cgi[1]); /* Redirect the stderr */ if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { cherokee_fd_close (STDERR_FILENO); dup2 (CONN_VSRV(conn)->error_writer->fd, STDERR_FILENO); } # if 0 /* Set unbuffered */ setvbuf (stdin, NULL, _IONBF, 0); setvbuf (stdout, NULL, _IONBF, 0); # endif /* Enable blocking mode */ _fd_set_properties (STDIN_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDOUT_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDERR_FILENO, 0, O_NONBLOCK); /* Sets the new environ. */ add_environment (cgi, conn); /* Change the directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { re = chdir (conn->effective_directory.buf); } else { char *file = strrchr (absolute_path, '/'); if (file != NULL) { *file = '\0'; re = chdir (absolute_path); *file = '/'; } else { re = -1; } } if (re < 0) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } /* Build de argv array */ argv[0] = absolute_path; /* Change the execution user? */ if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat nocache_info; struct stat *info; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_handler_cgi_base_props_t *props = HANDLER_CGI_BASE_PROPS(cgi); ret_t ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info); if (ret != ret_ok) { info = &nocache_info; } re = setuid (info->st_uid); if (re != 0) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_SETID, absolute_path, info->st_uid); } cherokee_iocache_entry_unref(&io_entry); } /* Reset the server-wide signal handlers */ cherokee_reset_signals(); /* Lets go.. execute it! */ do { re = execve (absolute_path, argv, cgi->envp); } while ((re == -1) && (errno == EINTR)); if (re < 0) { int err = errno; char buferr[ERROR_MAX_BUFSIZE]; switch (err) { case ENODEV: case ENOTDIR: case ENOENT: printf ("Status: 404" CRLF_CRLF); exit(0); case EPERM: case EACCES: case ENOEXEC: printf ("Status: 403" CRLF_CRLF); exit(0); default: printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d cmd=%s errno=%d: %s" CRLF_CRLF, __FILE__, __LINE__, absolute_path, err, strerror(err)); } /* Don't use the logging system (concurrency issues) */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_EXECUTE, absolute_path, cherokee_strerror_r(err, buferr, sizeof(buferr))); exit(1); } /* There is no way, it could reach this point. */ SHOULDNT_HAPPEN; exit(2); }