Exemplo n.º 1
0
/* Create a child process running PROGNAME with a pipe connected to
 * the childs stdin.  The write-end of the pipe will be placed in
 * *FPIN on successful return.  If dummy_stderr is non-zero, the
 * stderr for the child will be the same as the stdout of the parent.
 * Otherwise the child will inherit the stderr from the parent. */
static int log_child(apr_pool_t *p, const char *progname,
                     apr_file_t **fpin, apr_cmdtype_e cmdtype,
                     int dummy_stderr)
{
    /* Child process code for 'ErrorLog "|..."';
     * may want a common framework for this, since I expect it will
     * be common for other foo-loggers to want this sort of thing...
     */
    apr_status_t rc;
    apr_procattr_t *procattr;
    apr_proc_t *procnew;
    apr_file_t *outfile, *errfile;

    if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
        && ((rc = apr_procattr_cmdtype_set(procattr, cmdtype)) == APR_SUCCESS)
        && ((rc = apr_procattr_io_set(procattr,
                                      APR_FULL_BLOCK,
                                      APR_NO_PIPE,
                                      APR_NO_PIPE)) == APR_SUCCESS)
        && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
        && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) 
                == APR_SUCCESS)) {
        char **args;
        const char *pname;

        apr_tokenize_to_argv(progname, &args, p);
        pname = apr_pstrdup(p, args[0]);
        procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));

        if ((rc = apr_file_open_stdout(&outfile, p)) == APR_SUCCESS) {
            rc = apr_procattr_child_out_set(procattr, outfile, NULL);
            if (dummy_stderr)
                rc = apr_procattr_child_err_set(procattr, outfile, NULL);
            else if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS)
                rc = apr_procattr_child_err_set(procattr, errfile, NULL);
        }

        rc = apr_proc_create(procnew, pname, (const char * const *)args,
                             NULL, procattr, p);

        if (rc == APR_SUCCESS) {
            apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
            (*fpin) = procnew->in;
            /* read handle to pipe not kept open, so no need to call
             * close_handle_in_child()
             */
        }
    }

    return rc;
}
Exemplo n.º 2
0
/* Spawn the piped logger process pl->program. */
static apr_status_t piped_log_spawn(piped_log *pl)
{
    apr_procattr_t *procattr;
    apr_proc_t *procnew = NULL;
    apr_status_t status;

    if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
        ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype))
         != APR_SUCCESS) ||
        ((status = apr_procattr_child_in_set(procattr,
                                             ap_piped_log_read_fd(pl),
                                             ap_piped_log_write_fd(pl)))
         != APR_SUCCESS) ||
        ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
         != APR_SUCCESS) ||
        ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
        char buf[120];
        /* Something bad happened, give up and go away. */
        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
                     "piped_log_spawn: unable to setup child process '%s': %s",
                     pl->program, apr_strerror(status, buf, sizeof(buf)));
    }
    else {
        char **args;
        const char *pname;
        apr_file_t *outfile, *errfile;

        if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS)
            status = apr_procattr_child_out_set(procattr, outfile, NULL);
        if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS)
            status = apr_procattr_child_err_set(procattr, errfile, NULL);

        apr_tokenize_to_argv(pl->program, &args, pl->p);
        pname = apr_pstrdup(pl->p, args[0]);
        procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t));
        status = apr_proc_create(procnew, pname, (const char * const *) args,
                                 NULL, procattr, pl->p);

        if (status == APR_SUCCESS) {
            pl->pid = procnew;
            /* procnew->in was dup2'd from ap_piped_log_write_fd(pl);
             * since the original fd is still valid, close the copy to
             * avoid a leak. */
            apr_file_close(procnew->in);
            procnew->in = NULL;
            apr_proc_other_child_register(procnew, piped_log_maintenance, pl,
                                          ap_piped_log_write_fd(pl), pl->p);
            close_handle_in_child(pl->p, ap_piped_log_read_fd(pl));
        }
        else {
            char buf[120];
            /* Something bad happened, give up and go away. */
            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
                         "unable to start piped log program '%s': %s",
                         pl->program, apr_strerror(status, buf, sizeof(buf)));
        }
    }

    return status;
}
Exemplo n.º 3
0
static void test_file_redir(abts_case *tc, void *data)
{
    apr_file_t *testout = NULL;
    apr_file_t *testerr = NULL;
    apr_off_t offset;
    apr_status_t rv;
    const char *args[2];
    apr_procattr_t *attr;
    apr_file_t *testfile = NULL;
    apr_size_t length;
    char *buf;

    testfile = NULL;
    rv = apr_file_open(&testfile, "data/stdin",
                       APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
                       APR_OS_DEFAULT, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_file_open(&testout, "data/stdout",
                       APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
                       APR_OS_DEFAULT, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_file_open(&testerr, "data/stderr",
                       APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
                       APR_OS_DEFAULT, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    length = strlen(TESTSTR);
    apr_file_write(testfile, TESTSTR, &length);
    offset = 0;
    rv = apr_file_seek(testfile, APR_SET, &offset);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_ASSERT(tc, "File position mismatch, expected 0", offset == 0);

    rv = apr_procattr_create(&attr, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_procattr_child_in_set(attr, testfile, NULL);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_procattr_child_out_set(attr, testout, NULL);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_procattr_child_err_set(attr, testerr, NULL);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_procattr_dir_set(attr, "data");
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    args[0] = "proc_child";
    args[1] = NULL;

    rv = apr_proc_create(&newproc, "../" TESTBINPATH "proc_child" EXTENSION, args, NULL, 
                         attr, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_proc_wait(&newproc, NULL, NULL, APR_WAIT);
    ABTS_INT_EQUAL(tc, APR_CHILD_DONE, rv);

    offset = 0;
    rv = apr_file_seek(testout, APR_SET, &offset);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    length = 256;
    buf = apr_pcalloc(p, length);
    rv = apr_file_read(testout, buf, &length);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_STR_EQUAL(tc, TESTSTR, buf);


    apr_file_close(testfile);
    apr_file_close(testout);
    apr_file_close(testerr);

    rv = apr_file_remove("data/stdin", p);;
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_file_remove("data/stdout", p);;
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    rv = apr_file_remove("data/stderr", p);;
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
}
/* init_ext_filter_process: get the external filter process going
 * This is per-filter-instance (i.e., per-request) initialization.
 */
static apr_status_t init_ext_filter_process(ap_filter_t *f)
{
    ef_ctx_t *ctx = f->ctx;
    apr_status_t rc;
    ef_dir_t *dc = ctx->dc;
    const char * const *env;

    ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc));

    rc = apr_procattr_create(&ctx->procattr, ctx->p);
    ap_assert(rc == APR_SUCCESS);

    rc = apr_procattr_io_set(ctx->procattr,
                            APR_CHILD_BLOCK,
                            APR_CHILD_BLOCK,
                            APR_CHILD_BLOCK);
    ap_assert(rc == APR_SUCCESS);

    rc = set_resource_limits(f->r, ctx->procattr);
    ap_assert(rc == APR_SUCCESS);

    if (dc->log_stderr > 0) {
        rc = apr_procattr_child_err_set(ctx->procattr,
                                      f->r->server->error_log, /* stderr in child */
                                      NULL);
        ap_assert(rc == APR_SUCCESS);
    }

    rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn);
    ap_assert(rc == APR_SUCCESS);
    apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p);

    rc = apr_procattr_error_check_set(ctx->procattr, 1);
    if (rc != APR_SUCCESS) {
        return rc;
    }

    /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO,
     * and QUERY_STRING_UNESCAPED
     */
    ap_add_cgi_vars(f->r);
    ap_add_common_vars(f->r);
    apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri);
    apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info);
    if (f->r->args) {
            /* QUERY_STRING is added by ap_add_cgi_vars */
        char *arg_copy = apr_pstrdup(f->r->pool, f->r->args);
        ap_unescape_url(arg_copy);
        apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED",
                       ap_escape_shell_cmd(f->r->pool, arg_copy));
    }

    env = (const char * const *) ap_create_environment(ctx->p,
                                                       f->r->subprocess_env);

    rc = apr_proc_create(ctx->proc,
                            ctx->filter->command,
                            (const char * const *)ctx->filter->args,
                            env, /* environment */
                            ctx->procattr,
                            ctx->p);
    if (rc != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r,
                      "couldn't create child process to run `%s'",
                      ctx->filter->command);
        return rc;
    }

    apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT);

    /* We don't want the handle to the child's stdin inherited by any
     * other processes created by httpd.  Otherwise, when we close our
     * handle, the child won't see EOF because another handle will still
     * be open.
     */

    apr_pool_cleanup_register(ctx->p, ctx->proc->in,
                         apr_pool_cleanup_null, /* other mechanism */
                         ef_close_file);

#if APR_FILES_AS_SOCKETS
    {
        apr_pollfd_t pfd = { 0 };

        rc = apr_pollset_create(&ctx->pollset, 2, ctx->p, 0);
        ap_assert(rc == APR_SUCCESS);

        pfd.p         = ctx->p;
        pfd.desc_type = APR_POLL_FILE;
        pfd.reqevents = APR_POLLOUT;
        pfd.desc.f    = ctx->proc->in;
        rc = apr_pollset_add(ctx->pollset, &pfd);
        ap_assert(rc == APR_SUCCESS);

        pfd.reqevents = APR_POLLIN;
        pfd.desc.f    = ctx->proc->out;
        rc = apr_pollset_add(ctx->pollset, &pfd);
        ap_assert(rc == APR_SUCCESS);
    }
#endif

    return APR_SUCCESS;
}
Exemplo n.º 5
0
/** Try to start a process running the master job. */
static int
trell_start_master( trell_sconf_t* svr_conf,  request_rec* r )
{
    apr_status_t rv;
    
    // Open file into which master job stdout is piped.
    apr_file_t* master_stdout = NULL;
    rv = apr_file_open( &master_stdout,
                        apr_psprintf( r->pool, "/tmp/%s.stdout", svr_conf->m_master_id ),
                        APR_FOPEN_CREATE | APR_WRITE | APR_TRUNCATE | APR_XTHREAD,
                        APR_OS_DEFAULT, r->pool );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to open master job stdout" );
        return rv;
    }
        
    // Open file into which master job stderr is piped.
    apr_file_t* master_stderr = NULL;
    rv = apr_file_open( &master_stderr,
                        apr_psprintf( r->pool, "/tmp/%s.stderr", svr_conf->m_master_id ),
                        APR_FOPEN_CREATE | APR_WRITE | APR_TRUNCATE | APR_XTHREAD,
                        APR_OS_DEFAULT, r->pool );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to open master job stderr" );
        return rv;
    }

    // Create process attribute and set file handles for pipes
    apr_procattr_t* procattr;
    
    rv = apr_procattr_create( &procattr, r->pool );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_create failed" );
        return rv;
    }
    
    rv = apr_procattr_child_out_set( procattr, master_stdout, NULL );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_child_out_set failed" );
        return rv;
    }
    
    rv = apr_procattr_child_err_set( procattr, master_stderr, NULL );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_child_err_set failed" );
        return rv;
    }
    
    rv = apr_procattr_cmdtype_set( procattr, APR_PROGRAM );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: apr_procattr_cmdtype_set failed" );
        return rv;
    }


    const char* env[7] = {
        apr_psprintf( r->pool, "TINIA_JOB_ID=%s",    svr_conf->m_master_id ),
        apr_psprintf( r->pool, "TINIA_MASTER_ID=%s", svr_conf->m_master_id ),
        apr_psprintf( r->pool, "TINIA_APP_ROOT=%s",  svr_conf->m_app_root_dir ),
        NULL,   // PATH
        NULL,   // LD_LIBRARY_PATH
        NULL,   // DISPLAY
        NULL
    };

    // Copy PATH and LD_LIBRARY_PATH from the current environement, if set. It
    // might be an idea to pass these variables through the apache-config,
    // allowing more detailded control on jobs.
    int p = 3;
    char* PATH = NULL;
    if( (apr_env_get( &PATH, "PATH", r->pool ) == APR_SUCCESS ) &&
            (PATH != NULL) )
    {
        env[p++] = apr_psprintf( r->pool, "PATH=%s", PATH );
    } 
    char* LD_LIBRARY_PATH = NULL;
    if( (apr_env_get( &LD_LIBRARY_PATH, "LD_LIBRARY_PATH", r->pool ) == APR_SUCCESS ) &&
            (LD_LIBRARY_PATH != NULL) )
    {
        env[p++] = apr_psprintf( r->pool, "LD_LIBRARY_PATH=%s", LD_LIBRARY_PATH );
    }
    char* DISPLAY = NULL;
    if( (apr_env_get( &DISPLAY, "DISPLAY", r->pool ) == APR_SUCCESS ) &&
            (DISPLAY != NULL) )
    {
        env[p++] = apr_psprintf( r->pool, "DISPLAY=%s", DISPLAY );
    }
    
    // Set up arguments            
    const char* args[2] = {
        svr_conf->m_master_exe,
        NULL
    };

    
    apr_proc_t newproc;
    rv = apr_proc_create( &newproc,
                          svr_conf->m_master_exe,
                          args,
                          env,
                          procattr,
                          r->pool );
    if( rv != APR_SUCCESS ) {
        ap_log_rerror( APLOG_MARK, APLOG_CRIT, rv, r, "mod_trell: Failed to execute '%s'", svr_conf->m_master_exe );
        return rv;
    }
    
    rv = trell_set_master_pid( svr_conf, r, newproc.pid );
    if( rv != APR_SUCCESS ) {
        return rv;
    }
    
    ap_log_rerror( APLOG_MARK, APLOG_NOTICE, OK, r, "mod_trell: Master running at pid %d", newproc.pid );
    return APR_SUCCESS;    
}