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
—