예제 #1
0
AP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode,
                                    apr_proc_t *ret, apr_pool_t *p,
                                    server_rec *s)
{
    apr_status_t rv;

    ++wait_or_timeout_counter;
    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
        wait_or_timeout_counter = 0;
        ap_run_monitor(p, s);
    }

    rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
    ap_update_global_status();

    if (APR_STATUS_IS_EINTR(rv)) {
        ret->pid = -1;
        return;
    }

    if (APR_STATUS_IS_CHILD_DONE(rv)) {
        return;
    }

    apr_sleep(apr_time_from_sec(1));
    ret->pid = -1;
}
예제 #2
0
파일: proc.c 프로젝트: LuaDist/lua-apr
static int proc_wait(lua_State *L)
{
  apr_status_t status;
  apr_exit_why_e why;
  apr_wait_how_e how;
  lua_apr_proc *process;
  int code;

  process = proc_check(L, 1);
  how = lua_toboolean(L, 2) ? APR_WAIT : APR_NOWAIT;
  status = apr_proc_wait(&process->handle, &code, &why, how);

  if (APR_STATUS_IS_CHILD_NOTDONE(status))
    return (lua_pushboolean(L, 0), 1);
  else if (!APR_STATUS_IS_CHILD_DONE(status))
    return push_error_status(L, status);
  else
    lua_pushboolean(L, 1);

  switch (why) {
    default:
    case APR_PROC_EXIT:        lua_pushliteral(L, "exit");        break;
    case APR_PROC_SIGNAL:      lua_pushliteral(L, "signal");      break;
    case APR_PROC_SIGNAL_CORE: lua_pushliteral(L, "signal/core"); break;
  }

  lua_pushinteger(L, code);

  return 3;
}
예제 #3
0
파일: mpm_common.c 프로젝트: apresley/Jaxer
void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret,
                        apr_pool_t *p)
{
    apr_status_t rv;

    ++wait_or_timeout_counter;
    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
        wait_or_timeout_counter = 0;
        ap_run_monitor(p);
    }

    rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
    if (APR_STATUS_IS_EINTR(rv)) {
        ret->pid = -1;
        return;
    }

    if (APR_STATUS_IS_CHILD_DONE(rv)) {
        return;
    }

#ifdef NEED_WAITPID
    if ((ret = reap_children(exitcode, status)) > 0) {
        return;
    }
#endif

    apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
    ret->pid = -1;
    return;
}
예제 #4
0
static apr_status_t fortune_process(conn_rec *c,
                                    apr_procattr_t *pattr,
                                    apr_bucket_brigade *bb)
{
    apr_status_t rv;
    int argc = 0;
    const char *argv[APP_MAX_ARGC];
    apr_proc_t proc;
    apr_bucket *b;
    apr_pool_t *p = c->pool;

    fortune_conf_t *fconf = ap_get_module_config(c->base_server->module_config,
						 &fortune_module);

    argv[argc++] = fconf->progname;
    argv[argc++] = NULL;	/* @argvs should be null-terminated */

    if ((rv = apr_proc_create(&proc, fconf->progname,
                              (const char *const *) argv,
                              NULL, (apr_procattr_t *) pattr,
                              p)) != APR_SUCCESS) {
        return rv;
    }

    while (TRUE) {
        char buf[BUFSIZE] = { 0, };

        /* read the command's output through the pipe */
        rv = apr_file_gets(buf, sizeof(buf), proc.out);
        if (APR_STATUS_IS_EOF(rv)) {
            break;
        }
        b = apr_bucket_pool_create(apr_pstrdup(p, buf),
                                   strlen(buf), p, c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(bb, b);
    }
    apr_file_close(proc.out);

    {
        int st;
        apr_exit_why_e why;

        rv = apr_proc_wait(&proc, &st, &why, APR_WAIT);
        if (APR_STATUS_IS_CHILD_DONE(rv)) {
            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
                          "child done: why = %d, exit status = %d", why, st);
        }
        else {
            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "child notdone");
            return APR_EGENERAL;
        }
    }

    return APR_SUCCESS;
}
예제 #5
0
/* This is needed to reap processes spawned by exec_async() */
static void xm_exec_reap(nx_module_t *module)
{
    nx_xm_exec_conf_t *imconf;
    nx_event_t *event;
    apr_exit_why_e exitwhy;
    int exitval;
    apr_status_t rv;
    apr_proc_t proc;

    ASSERT(module->config != NULL);

    imconf = (nx_xm_exec_conf_t *) module->config;

    while ( APR_STATUS_IS_CHILD_DONE(rv = apr_proc_wait_all_procs(&proc, &exitval,
								  &exitwhy, APR_NOWAIT, NULL)) )
    {
	log_debug("process %d reaped by xm_exec_reap", proc.pid);

	if ( proc.pid > 0 )
	{
	    if ( exitwhy == APR_PROC_EXIT )
	    { //normal termination
		if ( exitval != 0 )
		{
		    log_error("subprocess '%d' returned a non-zero exit value of %d",
			      proc.pid, exitval);
		}
	    }
	    else
	    {
		log_error("subprocess '%d' was terminated by a signal", proc.pid); 
	    }
	}
	else
	{ // on windows we get PID = -1 and it would result in an endless loop during exit
	    break;
	}
    }

    event = nx_event_new();
    event->module = module;
    event->type = NX_EVENT_MODULE_SPECIFIC;
    event->delayed = TRUE;
    event->time = apr_time_now() + APR_USEC_PER_SEC;
    event->priority = module->priority;
    nx_event_add(event);
    imconf->event = event;
}
예제 #6
0
static void im_exec_stop(nx_module_t *module)
{
    nx_im_exec_conf_t *imconf;
    int i;
    boolean sigterm_sent = FALSE;
    apr_exit_why_e exitwhy;
    int exitval;
    int sig_num;
    apr_status_t rv;
    apr_status_t stopped = APR_SUCCESS;

    ASSERT(module != NULL);
    imconf = (nx_im_exec_conf_t *) module->config;
    ASSERT(imconf != NULL);

    log_debug("im_exec stopped");

    if ( module->input.desc.f != NULL )
    {
	apr_file_close(module->input.desc.f);
	apr_pool_clear(module->input.pool);
	module->input.desc.f = NULL;
    }

    if ( imconf->running == TRUE )
    {
	for ( i = 0; i < 50; i++ )
	{
	    if ( (rv = apr_proc_wait(&(imconf->proc), &exitval, &exitwhy, APR_NOWAIT)) != APR_SUCCESS )
	    {
		if ( APR_STATUS_IS_CHILD_DONE(rv) )
		{
		    rv = APR_SUCCESS;
		    break;
		}
		else if ( i >= 30 )
		{ // still running, kill it after 3 sec
		    if ( sigterm_sent == FALSE )
		    {
			sigterm_sent = TRUE;
#ifdef WIN32
			sig_num = 1;
#else
			sig_num = SIGTERM;
#endif
		    }
		    else
		    {
			if ( i <= 31 )
			{
			    log_warn("process %s did not exit, killing it.", imconf->cmd);
			}
#ifdef WIN32
			sig_num = 1;
#else
			sig_num = SIGKILL;
#endif
		    }
		    if ( (rv = apr_proc_kill(&(imconf->proc), sig_num)) != APR_SUCCESS )
		    {
			stopped = rv;
		    }
		}
	    }
	    apr_sleep(APR_USEC_PER_SEC / 10);
	}
	if ( !((stopped == APR_SUCCESS) || APR_STATUS_IS_ENOPROC(stopped)) )
	{
	    log_aprerror(stopped, "im_exec couldn't stop process");
	}
    }
    imconf->event = NULL;
}
예제 #7
0
static void im_exec_start(nx_module_t *module)
{
    nx_im_exec_conf_t *imconf;
    apr_status_t rv;
    apr_procattr_t *pattr;
    apr_exit_why_e exitwhy;
    int exitval;

    ASSERT(module->config != NULL);

    imconf = (nx_im_exec_conf_t *) module->config;

    if ( module->input.desc.f == NULL )
    {
	CHECKERR_MSG(apr_procattr_create(&pattr, module->input.pool),
		     "apr_procattr_create() failed");
	CHECKERR_MSG(apr_procattr_error_check_set(pattr, 1),
		     "apr_procattr_error_check_set() failed");
#ifdef WIN32
	CHECKERR_MSG(apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_NONBLOCK,
					 APR_NO_PIPE),
		     "apr_procattr_io_set() failed");
#else
	CHECKERR_MSG(apr_procattr_io_set(pattr, APR_NO_PIPE, APR_FULL_BLOCK,
					 APR_NO_PIPE),
		     "apr_procattr_io_set() failed");
#endif
	CHECKERR_MSG(apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV),
		     "apr_procattr_cmdtype_set() failed");
	CHECKERR_MSG(apr_proc_create(&(imconf->proc), imconf->cmd, (const char* const*)imconf->argv,
				     NULL, (apr_procattr_t*)pattr, module->input.pool),
		     "couldn't execute process %s", imconf->cmd);
	if ( (rv = apr_proc_wait(&(imconf->proc), &exitval, &exitwhy, APR_NOWAIT)) != APR_SUCCESS )
	{
	    if ( APR_STATUS_IS_CHILD_DONE(rv) )
	    {
		throw(rv, "im_exec process %s exited %s with exitval: %d",
		      imconf->cmd, exitwhy == APR_PROC_EXIT ? "normally" : "due to a signal",
		      exitval);
	    }
	    else
	    {
		// still running OK
	    }
	}
	log_debug("im_exec successfully spawned process");
	imconf->running = TRUE;

	module->input.desc_type = APR_POLL_FILE;
	module->input.desc.f = imconf->proc.out;
	module->input.module = module;
	module->input.inputfunc = imconf->inputfunc;
#ifdef WIN32
	im_exec_add_read_event(module, 0);
#else
	nx_module_pollset_add_file(module, module->input.desc.f, APR_POLLIN | APR_POLLHUP);
#endif
    }
    else
    {
	log_debug("%s already executed", imconf->cmd);
    }
#ifndef WIN32
    nx_module_add_poll_event(module);
#endif
}
예제 #8
0
int main(void)
{
    printf("hallo!\n");
    
    apr_status_t rv;
    apr_pool_t *p = NULL;
    apr_proc_t newproc;
    
    rv = apr_initialize();
    assert(rv == APR_SUCCESS);

    apr_pool_create(&p, NULL);
    
    
    // --
    char cwd[1024];
    assert(getcwd(cwd, 1024) != NULL);
    
    apr_procattr_t *attr = NULL;
    
    rv = apr_procattr_create(&attr, p);
    assert(rv == APR_SUCCESS);
    
    rv = apr_procattr_io_set(attr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE);
    assert(rv == APR_SUCCESS);
    
    rv = apr_procattr_dir_set(attr, cwd);
    assert(rv == APR_SUCCESS);

    printf("cwd: %s\n", cwd);

    rv = apr_procattr_cmdtype_set(attr, APR_PROGRAM_ENV );
    assert(rv == APR_SUCCESS);


    /* pseudo code of args to apr_proc_create() */
    int argc = 0;
    const char* argv[32];   /* 32 is a magic number. enough size for the number of arguments list */
    argv[argc++] = "test.sh"; /* program path of the command to run */
    /*argv[argc++] = "-i";
    argv[argc++] = "foo";
    argv[argc++] = "--longopt";
    argv[argc++] = "bar";*/
    argv[argc++] = NULL;  
    
    rv = apr_proc_create(&newproc, "test.sh", argv, /* env */ NULL, attr, p);
    assert(rv == APR_SUCCESS);
    
    //
    int exitCode = 0;
    apr_exit_why_e exitWhy = 0;
    
    rv = apr_proc_wait(&newproc, &exitCode, &exitWhy, APR_WAIT);
    if (APR_STATUS_IS_CHILD_DONE(rv)) {
        printf("child done: why = %d, exit status = %d\n", exitWhy, exitCode);
    } else {
        printf("child notdone\n");
    }
    
    
    /*assert(rv == APR_CHILD_DONE);
    
    assert(exitCode == 0);
    assert(exitWhy == APR_PROC_EXIT);*/
    // --
    
    
    apr_pool_destroy(p);
    apr_terminate();
    
    return 0;
}
/* Run an external authentication program using the given method for passing
 * in the data.  The login name is always passed in.   Dataname is "GROUP" or
 * "PASS" and data is the group list or password being checked.  To launch
 * a detached daemon, run this with extmethod=NULL.
 *
 * If the authenticator was run, we return the numeric code from the
 * authenticator, normally 0 if the login was valid, some small positive
 * number if not.  If we were not able to run the authenticator, we log
 * an error message and return a numeric error code:
 *
 *   -1   Could not execute authenticator, usually a path or permission problem
 *   -2   The external authenticator crashed or was killed.
 *   -3   Could not create process attribute structure
 *   -4   apr_proc_wait() did not return a status code.  Should never happen.
 *   -5   apr_proc_wait() returned before child finished.  Should never happen.
 */
static int exec_external(const char *extpath, const char *extmethod,
		const request_rec *r, const char *dataname, const char *data)
{
    conn_rec *c= r->connection;
    apr_pool_t *p= r->pool;
    int isdaemon, usecheck= 0, usepipeout= 0, usepipein= 0;
    apr_procattr_t *procattr;
    apr_proc_t proc;
    apr_status_t rc= APR_SUCCESS;
    char *child_env[12];
    char *child_arg[MAX_ARG+2];
    const char *t;
    int i, status= -4;
    apr_exit_why_e why= APR_PROC_EXIT;
    apr_sigfunc_t *sigchld;

    /* Set various flags based on the execution method */

    isdaemon= (extmethod == NULL);
    if (!isdaemon)
    {
	usecheck= extmethod && !strcasecmp(extmethod, "checkpassword");
	usepipeout= usecheck || (extmethod && !strcasecmp(extmethod, "pipes"));
	usepipein= usepipeout || (extmethod && !strcasecmp(extmethod, "pipe"));
    }

    /* Create the environment for the child.  Daemons don't get these, they
     * just inherit apache's environment variables.
     */

    if (!isdaemon)
    {
	const char *cookie, *host, *remote_host;
	authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
	    ap_get_module_config(r->per_dir_config, &authnz_external_module);
	i= 0;

	if (!usepipein)
	{
	    /* Put user name and password/group into environment */
	    child_env[i++]= apr_pstrcat(p, ENV_USER"=", r->user, NULL);
	    child_env[i++]= apr_pstrcat(p, dataname, "=", data, NULL);
	}

	child_env[i++]= apr_pstrcat(p, "PATH=", getenv("PATH"), NULL);

	child_env[i++]= apr_pstrcat(p, "AUTHTYPE=", dataname, NULL);

	remote_host= ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST,NULL);
	if (remote_host != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_HOST"=", remote_host,NULL);

	if (r->useragent_ip)
	    child_env[i++]= apr_pstrcat(p, ENV_IP"=", r->useragent_ip, NULL);

	if (r->uri)
	    child_env[i++]= apr_pstrcat(p, ENV_URI"=", r->uri, NULL);

	if ((host= apr_table_get(r->headers_in, "Host")) != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_HTTP_HOST"=", host, NULL);

	if (dir->context)
	    child_env[i++]= apr_pstrcat(r->pool, ENV_CONTEXT"=",
	    	dir->context, NULL);

#ifdef ENV_COOKIE
	if ((cookie= apr_table_get(r->headers_in, "Cookie")) != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_COOKIE"=", cookie, NULL);
#endif
	/* NOTE:  If you add environment variables,
	 *   remember to increase the size of the child_env[] array */

	/* End of environment */
	child_env[i]= NULL;
    }

    /* Construct argument array */
    for (t= extpath, i=0; *t != '\0' && (i <= MAX_ARG + 1);
	 child_arg[i++]= ap_getword_white(p, &t)) {}
    child_arg[i]= NULL;

    /* Create the process attribute structure describing the script we
     * want to run using the Thread/Process functions from the Apache
     * portable runtime library. */

    if (((rc= apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||

	/* should we create pipes to stdin, stdout and stderr? */
        ((rc= apr_procattr_io_set(procattr,
	    (usepipein && !usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE,
	    usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE,
	    (usepipein && usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE))
	       != APR_SUCCESS ) ||

	/* will give full path of program and make a new environment */
	((rc= apr_procattr_cmdtype_set(procattr,
	    isdaemon ? APR_PROGRAM_ENV : APR_PROGRAM)) != APR_SUCCESS) ||

	/* detach the child only if it is a daemon */
	((rc= apr_procattr_detach_set(procattr, isdaemon)) != APR_SUCCESS) ||

	/* function to call if child has error after fork, before exec */
	((rc= apr_procattr_child_errfn_set(procattr, extchilderr)
	      != APR_SUCCESS)))
    {
	/* Failed.  Probably never happens. */
    	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
	    "could not set child process attributes");
	return -3;
    }

    /* Sometimes other modules wil mess up sigchild.  Need to fix it for
     * the wait call to work correctly.  */
    sigchld= apr_signal(SIGCHLD,SIG_DFL);

    /* Start the child process */
    rc= apr_proc_create(&proc, child_arg[0],
    	(const char * const *)child_arg,
	(const char * const *)child_env, procattr, p);
    if (rc != APR_SUCCESS)
    {
	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
		"Could not run external authenticator: %d: %s", rc,
		child_arg[0]);
	return -1;
    }

    if (isdaemon) return 0;

    apr_pool_note_subprocess(p, &proc, APR_KILL_AFTER_TIMEOUT);

    if (usepipein)
    {
	/* Select appropriate pipe to write to */
	apr_file_t *pipe= (usecheck ? proc.err : proc.in);

	/* Send the user */
	apr_file_write_full(pipe, r->user, strlen(r->user), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send the password */
	apr_file_write_full(pipe, data, strlen(data), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send the uri/path */
	apr_file_write_full(pipe, r->uri, strlen(r->uri), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send dummy timestamp for checkpassword */
	if (usecheck) apr_file_write_full(pipe, "0", 2, NULL);

	/* Close the file */
	apr_file_close(pipe);
    }

    /* Wait for the child process to terminate, and get status */
    rc= apr_proc_wait(&proc,&status,&why,APR_WAIT);

    /* Restore sigchild to whatever it was before we reset it */
    apr_signal(SIGCHLD,sigchld);

    if (!APR_STATUS_IS_CHILD_DONE(rc))
    {
    	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
		"Could not get status from child process");
	return -5;
    }
    if (!APR_PROC_CHECK_EXIT(why))
    {
	ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
		"External authenticator died on signal %d",status);
	return -2;
    }

    return status;
}