int lua_apr_file_open(lua_State *L) { apr_status_t status; lua_apr_file *file; apr_int32_t flags; const char *path; apr_fileperms_t perm; # if defined(WIN32) || defined(OS2) || defined(NETWARE) /* On Windows apr_os_file_t isn't an integer: it's a HANDLE. */ if (0) ; # else /* On UNIX like systems apr_os_file_t is an integer. */ if (lua_isnumber(L, 1)) { apr_os_file_t fd = (apr_os_file_t) lua_tonumber(L, 1); flags = parse_mode_str(luaL_optstring(L, 2, "r")); file = file_alloc(L, NULL, NULL); status = apr_os_file_put(&file->handle, &fd, flags, file->pool->ptr); } # endif else { path = luaL_checkstring(L, 1); perm = check_permissions(L, 3, 0); flags = parse_mode_str(luaL_optstring(L, 2, "r")); file = file_alloc(L, path, NULL); status = apr_file_open(&file->handle, path, flags, perm, file->pool->ptr); } if (status != APR_SUCCESS) return push_file_error(L, file, status); init_file_buffers(L, file, !(flags & APR_FOPEN_BINARY)); return 1; }
APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, apr_os_proc_mutex_t *ospmutex, apr_lockmech_e mech, int register_cleanup, apr_pool_t *pool) { apr_status_t rv; if (pool == NULL) { return APR_ENOPOOL; } if ((*pmutex) == NULL) { (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); (*pmutex)->pool = pool; } rv = proc_mutex_choose_method(*pmutex, mech, ospmutex); #if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE if (rv == APR_SUCCESS) { rv = apr_os_file_put(&(*pmutex)->interproc, &(*pmutex)->os.crossproc, 0, pool); } #endif if (rv == APR_SUCCESS && register_cleanup) { apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, apr_pool_cleanup_null); } return rv; }
void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p) { SECURITY_ATTRIBUTES sa; HANDLE hProc = GetCurrentProcess(); HANDLE hPipeRead = NULL; HANDLE hPipeWrite = NULL; HANDLE hDup = NULL; DWORD threadid; apr_file_t *eventlog_file; apr_file_t *stderr_file; display_name = argv0; /* Create a pipe to send stderr messages to the system error log. * * _dup2() duplicates the write handle inheritable for us. */ sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0); ap_assert(hPipeRead && hPipeWrite); stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL); stderr_thread = CreateThread(NULL, 0, service_stderr_thread, (LPVOID) hPipeRead, 0, &threadid); ap_assert(stderr_ready && stderr_thread); WaitForSingleObject(stderr_ready, INFINITE); if ((apr_file_open_stderr(&stderr_file, p) == APR_SUCCESS) && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p) == APR_SUCCESS)) apr_file_dup2(stderr_file, eventlog_file, p); /* The code above _will_ corrupt the StdHandle... * and we must do so anyways. We set this up only * after we initialized the posix stderr API. */ ap_open_stderr_log(p); }
APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, apr_os_proc_mutex_t *ospmutex, apr_pool_t *pool) { if (pool == NULL) { return APR_ENOPOOL; } if ((*pmutex) == NULL) { (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); (*pmutex)->pool = pool; } #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE apr_os_file_put(&(*pmutex)->interproc, &ospmutex->crossproc, 0, pool); #endif #if APR_HAS_PROC_PTHREAD_SERIALIZE (*pmutex)->pthread_interproc = ospmutex->pthread_interproc; #endif return APR_SUCCESS; }
static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb) { apr_bucket *b; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; if (mobj->type == CACHE_TYPE_FILE) { /* CACHE_TYPE_FILE */ apr_file_t *file; apr_os_file_put(&file, &mobj->fd, mobj->flags, p); b = apr_bucket_file_create(file, 0, mobj->m_len, p, bb->bucket_alloc); } else { /* CACHE_TYPE_HEAP */ b = apr_bucket_immortal_create(mobj->m, mobj->m_len, bb->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return APR_SUCCESS; }
static int aikido_handler(request_rec *r) { apr_bucket_brigade *bb; apr_bucket *b; int seen_eos, child_stopped_reading; apr_pool_t *p; apr_status_t rv; conn_rec *c = r->connection; void *aikidoreq; int inpipes[2]; int outpipes[2]; apr_file_t *infile; apr_file_t *outfile; int e; pthread_t tid; pthread_attr_t attrs; ThreadData tdata; void *tresult; if (aikido == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_aikido failed to initalize"); return HTTP_INTERNAL_SERVER_ERROR; } p = r->main ? r->main->pool : r->pool; if (r->method_number == M_OPTIONS) { r->allowed |= (AP_METHOD_BIT << M_GET); r->allowed |= (AP_METHOD_BIT << M_POST); return DECLINED; } // create the request object aikidoreq = aikido_new_request (r); if (!aikido_check_uri(aikido, aikidoreq)) { aikido_delete_request (aikidoreq); return DECLINED; } e = socketpair (AF_UNIX, SOCK_STREAM, 0, inpipes); e |= socketpair (AF_UNIX, SOCK_STREAM, 0, outpipes); if (e != 0) { perror ("socketpair"); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to create pipes"); return HTTP_INTERNAL_SERVER_ERROR; } // redirect the output from the webapp to our outfile apr_os_file_put (&outfile, &outpipes[0], O_RDONLY, r->pool); // open for reading from outpipes pipe // redirect the input to the webapp from out infile apr_os_file_put (&infile, &inpipes[1], O_CREAT | O_WRONLY, r->pool); // open for writing to inpipes pipe ap_add_common_vars(r); ap_add_cgi_vars(r); bb = apr_brigade_create(r->pool, c->bucket_alloc); seen_eos = 0; child_stopped_reading = 0; do { apr_bucket *bucket; rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); return rv; } bucket = APR_BRIGADE_FIRST(bb); while (bucket != APR_BRIGADE_SENTINEL(bb)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } /* We can't do much with this. */ if (APR_BUCKET_IS_FLUSH(bucket)) { continue; } /* If the child stopped, we still must read to EOS. */ if (child_stopped_reading) { continue; } /* read */ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); /* Keep writing data to the child until done or too much time * elapses with no progress or an error occurs. */ rv = apr_file_write_full(infile, data, len, NULL); if (rv != APR_SUCCESS) { /* silly script stopped reading, soak up remaining message */ child_stopped_reading = 1; } bucket = APR_BUCKET_NEXT(bucket); } apr_brigade_cleanup(bb); } while (!seen_eos); /* Is this flush really needed? */ apr_file_flush(infile); apr_file_close(infile); apr_brigade_cleanup(bb); /* start the reader thread */ e = pthread_attr_init (&attrs); if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to allocate script thread attributes"); return HTTP_INTERNAL_SERVER_ERROR; } e = pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_JOINABLE) ; if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to set script thread attributes"); return HTTP_INTERNAL_SERVER_ERROR; } tdata.req = aikidoreq; tdata.in = inpipes[0]; tdata.out = outpipes[1]; e = pthread_create (&tid, NULL, script_thread, &tdata) ; if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to run script thread"); return HTTP_INTERNAL_SERVER_ERROR; } /* script thread is now executing script with i/o redirected to the pipes */ /* read the script output from the pipe*/ apr_file_pipe_timeout_set(outfile, 0); b = aikido_bucket_create(r, outfile, c->bucket_alloc); if (b == NULL) { pthread_join (tid, &tresult); /* wait for script to complete */ close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); return HTTP_INTERNAL_SERVER_ERROR; } APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(r->output_filters, bb); /* wait for the script thread to complete */ pthread_join (tid, &tresult); /* terminate script output */ close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); /* delete the aikido request objects */ aikido_delete_request (aikidoreq); return OK; }
apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, fcgid_procnode *procnode) { HANDLE *finish_event, listen_handle; SECURITY_ATTRIBUTES SecurityAttributes; fcgid_server_conf *sconf; apr_procattr_t *proc_attr; apr_status_t rv; apr_file_t *file; const char * const *proc_environ; char sock_path[FCGID_PATH_MAX]; int argc; char const * wargv[APACHE_ARG_MAX + 1], *word; /* For wrapper */ const char *tmp; /* Build wrapper args */ argc = 0; tmp = cmdline; while (1) { word = ap_getword_white(procnode->proc_pool, &tmp); if (word == NULL || *word == '\0') break; if (argc >= APACHE_ARG_MAX) break; wargv[argc++] = word; } wargv[argc] = NULL; memset(&SecurityAttributes, 0, sizeof(SecurityAttributes)); /* Prepare finish event */ finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE)); *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (*finish_event == NULL || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE)) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create mutex for subprocess"); return APR_ENOLOCK; } apr_pool_cleanup_register(procnode->proc_pool, finish_event, close_finish_event, apr_pool_cleanup_null); /* For proc_kill_gracefully() */ apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME, NULL, procnode->proc_pool); /* Pass the finish event id to subprocess */ apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME, apr_ltoa(procnode->proc_pool, (long) *finish_event)); /* Prepare the listen namedpipe file name (no check for truncation) */ apr_snprintf(sock_path, sizeof sock_path, "\\\\.\\pipe\\fcgidpipe-%lu.%d", GetCurrentProcessId(), g_process_counter++); /* Prepare the listen namedpipe handle */ SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; listen_handle = CreateNamedPipe(sock_path, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192, 0, &SecurityAttributes); if (listen_handle == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create namedpipe for subprocess"); return APR_ENOSOCKET; } apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path)); apr_cpystrn(procnode->executable_path, wargv[0], sizeof(procnode->executable_path)); /* Build environment variables */ proc_environ = (const char * const *) ap_create_environment(procnode->proc_pool, procinfo->proc_environ); if (!proc_environ) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't build environment variables"); return APR_ENOMEM; } /* Create process now */ if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_dir_set(proc_attr, ap_make_dirstr_parent(procnode->proc_pool, wargv[0]))) != APR_SUCCESS || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM)) != APR_SUCCESS || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE, APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS || (rv = apr_os_file_put(&file, &listen_handle, 0, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_child_in_set(proc_attr, file, NULL)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, "mod_fcgid: can't create FastCGI process attribute"); CloseHandle(listen_handle); return APR_ENOPROC; } /* fork and exec now */ rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, proc_environ, proc_attr, procnode->proc_pool); /* OK, I created the process, now put it back to idle list */ CloseHandle(listen_handle); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, "mod_fcgid: can't run %s", wargv[0]); return rv; } /* FcgidWin32PreventOrphans feature */ sconf = ap_get_module_config(procinfo->main_server->module_config, &fcgid_module); if (sconf->hJobObjectForAutoCleanup != NULL) { /* Associate cgi process to current process */ if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup, procnode->proc_id.hproc) == 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: unable to assign child process to " "job object"); } } return APR_SUCCESS; }
int main(int argc, const char * const argv[]) { apr_file_t *infd, *skwrapper; apr_sockaddr_t *skaddr; apr_getopt_t *gopt; apr_socket_t *skt; apr_pool_t *pool; apr_status_t rv; apr_proc_t proc; /* Command line arguments */ int num_to_start = 1, port = 0; const char *interface = NULL; const char *command = NULL; apr_app_initialize(&argc, &argv, NULL); atexit(apr_terminate); apr_pool_create(&pool, NULL); rv = apr_getopt_init(&gopt, pool, argc, argv); if (rv) { return EXIT_FAILURE; } for (;;) { const char *arg; char opt; rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg); if (APR_STATUS_IS_EOF(rv)) { break; } else if (rv) { usage(); } else { switch (opt) { case 'c': command = arg; break; case 'p': port = atoi(arg); if (! port) { usage(); } break; case 'i': interface = arg; break; case 'N': num_to_start = atoi(arg); if (! num_to_start) { usage(); } break; default: break; } } } if (! command || ! port) { usage(); } rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool); if (rv) { exit_error(rv, "apr_sockaddr_info_get"); } rv = apr_socket_create(&skt, skaddr->family, SOCK_STREAM, APR_PROTO_TCP, pool); if (rv) { exit_error(rv, "apr_socket_create"); } rv = apr_socket_bind(skt, skaddr); if (rv) { exit_error(rv, "apr_socket_bind"); } rv = apr_socket_listen(skt, 1024); if (rv) { exit_error(rv, "apr_socket_listen"); } rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE); if (rv) { exit_error(rv, "apr_proc_detach"); } #if defined(WIN32) || defined(OS2) || defined(NETWARE) #error "Please implement me." #else while (--num_to_start >= 0) { rv = apr_proc_fork(&proc, pool); if (rv == APR_INCHILD) { apr_os_file_t oft = 0; apr_os_sock_t oskt; /* Ok, so we need a file that has file descriptor 0 (which * FastCGI wants), but points to our socket. This isn't really * possible in APR, so we cheat a bit. I have no idea how to * do this on a non-unix platform, so for now this is platform * specific. Ick. * * Note that this has to happen post-detach, otherwise fd 0 * gets closed during apr_proc_detach and it's all for nothing. * * Unfortunately, doing this post detach means we have no way * to let anyone know if there's a problem at this point :( */ rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool); if (rv) { exit(EXIT_FAILURE); } rv = apr_os_sock_get(&oskt, skt); if (rv) { exit(EXIT_FAILURE); } rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE, pool); if (rv) { exit(EXIT_FAILURE); } rv = apr_file_dup2(infd, skwrapper, pool); if (rv) { exit(EXIT_FAILURE); } /* XXX Can't use apr_proc_create because there's no way to get * infd into the procattr without going through another dup2, * which means by the time it gets to the fastcgi process it * is no longer fd 0, so it doesn't work. Sigh. */ execl(command, command, NULL); } else if (rv == APR_INPARENT) { if (num_to_start == 0) { apr_socket_close(skt); } } else { exit_error(rv, "apr_proc_fork"); } } #endif return EXIT_SUCCESS; }
APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, const char *filename, apr_pool_t *pool) { if (filename == NULL) { /* It doesn't make sense to attach to a segment if you don't know * the filename. */ return APR_EINVAL; } else { #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM apr_shm_t *new_m; apr_status_t status; int tmpfd; apr_file_t *file; /* file where metadata is stored */ apr_size_t nbytes; new_m = apr_palloc(pool, sizeof(apr_shm_t)); new_m->pool = pool; new_m->filename = apr_pstrdup(pool, filename); #if APR_USE_SHMEM_MMAP_SHM const char *shm_name = make_shm_open_safe_name(filename, pool); /* FIXME: SysV uses 0600... should we? */ tmpfd = shm_open(shm_name, O_RDWR, 0644); if (tmpfd == -1) { return errno; } status = apr_os_file_put(&file, &tmpfd, APR_READ | APR_WRITE, pool); if (status != APR_SUCCESS) { return status; } #elif APR_USE_SHMEM_MMAP_TMP status = apr_file_open(&file, filename, APR_READ | APR_WRITE, APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) { return status; } status = apr_os_file_get(&tmpfd, file); if (status != APR_SUCCESS) { return status; } #else return APR_ENOTIMPL; #endif nbytes = sizeof(new_m->realsize); status = apr_file_read(file, (void *)&(new_m->realsize), &nbytes); if (status != APR_SUCCESS) { return status; } status = apr_os_file_get(&tmpfd, file); if (status != APR_SUCCESS) { apr_file_close(file); /* ignore errors, we're failing */ apr_file_remove(new_m->filename, new_m->pool); return status; } new_m->reqsize = new_m->realsize - sizeof(apr_size_t); new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, MAP_SHARED, tmpfd, 0); /* FIXME: check for errors */ status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } /* metadata isn't part of the usable segment */ new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #elif APR_USE_SHMEM_SHMGET apr_shm_t *new_m; apr_status_t status; apr_file_t *file; /* file where metadata is stored */ apr_size_t nbytes; new_m = apr_palloc(pool, sizeof(apr_shm_t)); status = apr_file_open(&file, filename, APR_FOPEN_READ, APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) { return status; } nbytes = sizeof(new_m->reqsize); status = apr_file_read(file, (void *)&(new_m->reqsize), &nbytes); if (status != APR_SUCCESS) { return status; } status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } new_m->filename = apr_pstrdup(pool, filename); new_m->pool = pool; new_m->shmkey = our_ftok(filename); if (new_m->shmkey == (key_t)-1) { return errno; } if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) { return errno; } if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { return errno; } new_m->usable = new_m->base; new_m->realsize = new_m->reqsize; apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #else return APR_ENOTIMPL; #endif } }
APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, apr_size_t reqsize, const char *filename, apr_pool_t *pool) { apr_shm_t *new_m; apr_status_t status; #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON struct shmid_ds shmbuf; apr_uid_t uid; apr_gid_t gid; #endif #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \ APR_USE_SHMEM_MMAP_ZERO int tmpfd; #endif #if APR_USE_SHMEM_SHMGET apr_size_t nbytes; #endif #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \ APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM apr_file_t *file; /* file where metadata is stored */ #endif /* Check if they want anonymous or name-based shared memory */ if (filename == NULL) { #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON new_m = apr_palloc(pool, sizeof(apr_shm_t)); new_m->pool = pool; new_m->reqsize = reqsize; new_m->realsize = reqsize + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ new_m->filename = NULL; #if APR_USE_SHMEM_MMAP_ZERO status = apr_file_open(&file, "/dev/zero", APR_READ | APR_WRITE, APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) { return status; } status = apr_os_file_get(&tmpfd, file); if (status != APR_SUCCESS) { return status; } new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, MAP_SHARED, tmpfd, 0); if (new_m->base == (void *)MAP_FAILED) { return errno; } status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } /* store the real size in the metadata */ *(apr_size_t*)(new_m->base) = new_m->realsize; /* metadata isn't usable */ new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #elif APR_USE_SHMEM_MMAP_ANON new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); if (new_m->base == (void *)MAP_FAILED) { return errno; } /* store the real size in the metadata */ *(apr_size_t*)(new_m->base) = new_m->realsize; /* metadata isn't usable */ new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #endif /* APR_USE_SHMEM_MMAP_ZERO */ #elif APR_USE_SHMEM_SHMGET_ANON new_m = apr_palloc(pool, sizeof(apr_shm_t)); new_m->pool = pool; new_m->reqsize = reqsize; new_m->realsize = reqsize; new_m->filename = NULL; new_m->shmkey = IPC_PRIVATE; if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, SHM_R | SHM_W | IPC_CREAT)) < 0) { return errno; } if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { return errno; } new_m->usable = new_m->base; if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { return errno; } apr_uid_current(&uid, &gid, pool); shmbuf.shm_perm.uid = uid; shmbuf.shm_perm.gid = gid; if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { return errno; } /* Remove the segment once use count hits zero. * We will not attach to this segment again, since it is * anonymous memory, so it is ok to mark it for deletion. */ if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) { return errno; } apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #else /* It is an error if they want anonymous memory but we don't have it. */ return APR_ENOTIMPL; /* requested anonymous but we don't have it */ #endif } /* Name-based shared memory */ else { new_m = apr_palloc(pool, sizeof(apr_shm_t)); new_m->pool = pool; new_m->reqsize = reqsize; new_m->filename = apr_pstrdup(pool, filename); #if APR_USE_SHMEM_MMAP_SHM const char *shm_name = make_shm_open_safe_name(filename, pool); #endif #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM new_m->realsize = reqsize + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ /* FIXME: Ignore error for now. * * status = apr_file_remove(file, pool);*/ status = APR_SUCCESS; #if APR_USE_SHMEM_MMAP_TMP /* FIXME: Is APR_OS_DEFAULT sufficient? */ status = apr_file_open(&file, filename, APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) { return status; } status = apr_os_file_get(&tmpfd, file); if (status != APR_SUCCESS) { apr_file_close(file); /* ignore errors, we're failing */ apr_file_remove(new_m->filename, new_m->pool); return status; } status = apr_file_trunc(file, new_m->realsize); if (status != APR_SUCCESS && status != APR_ESPIPE) { apr_file_close(file); /* ignore errors, we're failing */ apr_file_remove(new_m->filename, new_m->pool); return status; } new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, MAP_SHARED, tmpfd, 0); /* FIXME: check for errors */ status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } #endif /* APR_USE_SHMEM_MMAP_TMP */ #if APR_USE_SHMEM_MMAP_SHM /* FIXME: SysV uses 0600... should we? */ tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644); if (tmpfd == -1) { return errno; } status = apr_os_file_put(&file, &tmpfd, APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, pool); if (status != APR_SUCCESS) { return status; } status = apr_file_trunc(file, new_m->realsize); if (status != APR_SUCCESS && status != APR_ESPIPE) { shm_unlink(shm_name); /* we're failing, remove the object */ return status; } new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, MAP_SHARED, tmpfd, 0); /* FIXME: check for errors */ status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } #endif /* APR_USE_SHMEM_MMAP_SHM */ /* store the real size in the metadata */ *(apr_size_t*)(new_m->base) = new_m->realsize; /* metadata isn't usable */ new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #elif APR_USE_SHMEM_SHMGET new_m->realsize = reqsize; /* FIXME: APR_OS_DEFAULT is too permissive, switch to 600 I think. */ status = apr_file_open(&file, filename, APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) { return status; } /* ftok() (on solaris at least) requires that the file actually * exist before calling ftok(). */ new_m->shmkey = our_ftok(filename); if (new_m->shmkey == (key_t)-1) { apr_file_close(file); return errno; } if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) { apr_file_close(file); return errno; } if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { apr_file_close(file); return errno; } new_m->usable = new_m->base; if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { apr_file_close(file); return errno; } apr_uid_current(&uid, &gid, pool); shmbuf.shm_perm.uid = uid; shmbuf.shm_perm.gid = gid; if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { apr_file_close(file); return errno; } nbytes = sizeof(reqsize); status = apr_file_write(file, (const void *)&reqsize, &nbytes); if (status != APR_SUCCESS) { apr_file_close(file); return status; } status = apr_file_close(file); if (status != APR_SUCCESS) { return status; } apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, apr_pool_cleanup_null); *m = new_m; return APR_SUCCESS; #else return APR_ENOTIMPL; #endif } }