You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Graham Leggett <mi...@sharp.fm> on 2021/04/24 08:26:35 UTC

apr_proc_create() clobbers stdin in the parent

Hi all,

I am using apr_proc_create() to run a process in the middle of parsing a command line (think something similar to bash completion), and have run into a problem.

Key to both the replxx and the libedit libraries is that stdin has to be set unbuffered so that key bindings can be processed immediately. After apr_proc_create() returns, stdin of the parent process finds itself reset back to linebuffered mode, and both command line libraries break.

Modifying the replxx library to “fix” stdin after calling apr_proc_create() works around the problem, but I’ll have to do this somehow for libedit as well.

Is there something that can be done to make apr_proc_create() not touch the parent’s stdin, stdout and stderr at all?

Tried lots of code combinations, the current incarnation looks like this:

        if ((status = apr_procattr_create(&procattr, first->pool)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot create procattr: %pm\n", &status);
            break;
        }

//        if ((status = apr_procattr_detach_set(procattr, 1))
//                != APR_SUCCESS) {
//            apr_file_printf(d->err, "cannot set detached in procattr: %pm\n", &status);
//            break;
//        }


        if ((status = apr_file_pipe_create_ex(&ioread, &iowrite, APR_FULL_BLOCK,
        		first->pool)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot create pipes: %pm\n", &status);
            break;
        }

        if ((status = apr_procattr_child_in_set(procattr, NULL, NULL)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot set stdin: %pm\n", &status);
            break;
        }

        //        if ((status = apr_procattr_child_out_set(procattr, &iowrite, &ioread)) != APR_SUCCESS) {
        if ((status = apr_procattr_child_out_set(procattr, NULL, NULL)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot set out pipe: %pm\n", &status);
            break;
        }

        if ((status = apr_procattr_child_err_set(procattr, NULL, NULL)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot set stderr: %pm\n", &status);
            break;
        }

//        if ((status = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK,
//        		APR_NO_PIPE)) != APR_SUCCESS) {
//            apr_file_printf(d->err, "cannot set io procattr: %pm\n", &status);
//            break;
//        }

        if ((status = apr_procattr_dir_set(procattr, command->r.sysconf))
                != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot set directory in procattr: %pm\n", &status);
            break;
        }

        if ((status = apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot set command type in procattr: %pm\n", &status);
            break;
        }

        proc = apr_pcalloc(first->pool, sizeof(apr_proc_t));
        if ((status = apr_proc_create(proc, command->r.libexec, (const char* const*) argv->elts,
                device_environment_make(d), procattr, first->pool)) != APR_SUCCESS) {
            apr_file_printf(d->err, "cannot run command: %pm\n", &status);
            break;
        }

        apr_file_close(proc->in);
        apr_file_close(proc->err);

	[do stuff that reads proc->out]

        apr_file_close(proc->out);

        if ((status = apr_proc_wait(proc, NULL, NULL, APR_WAIT)) != APR_CHILD_DONE) {
            apr_file_printf(d->err, "cannot wait for command: %pm\n", &status);
            break;
        }


Regards,
Graham
—