コード例 #1
0
ファイル: io_file.c プロジェクト: LuaDist/lua-apr
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;
}
コード例 #2
0
ファイル: proc_mutex.c プロジェクト: MiKTeX/miktex
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;
}
コード例 #3
0
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);
}
コード例 #4
0
ファイル: proc_mutex.c プロジェクト: Garridon/windowsrtdev
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;
}
コード例 #5
0
ファイル: mod_mem_cache.c プロジェクト: Alivx/apache2nginx
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;
}
コード例 #6
0
ファイル: mod_aikido.c プロジェクト: dallison/aikido3
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;
}
コード例 #7
0
ファイル: fcgid_proc_win.c プロジェクト: Pballer/prayer
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;
}
コード例 #8
0
ファイル: fcgistarter.c プロジェクト: Aimbot2/apache2
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;
}
コード例 #9
0
ファイル: shm.c プロジェクト: MiKTeX/miktex
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
    }
}
コード例 #10
0
ファイル: shm.c プロジェクト: MiKTeX/miktex
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
    }
}