Is there a way to half-close a FILE* file-handle? - macos

My situation is this: In MacOS/X, I've called AuthorizationExecuteWithPrivileges to spawn a privileged child process, and the only way I have to communicate with the child process is by calling fread() and/or fwrite() on the FILE * file-handle returned to me by the final argument to that call.
What I want to do is indicate to the child process that it should go away, which I can do by calling fclose() on the file-handle -- the child process sees that its STDIN_FILENO has closed and responds by exiting.
However, I also want to be able to read any text that the child process printed to its stdout stream before exiting, but calling fclose() on the file-handle precludes doing that.
So my question is, is there any way to "half-close" a FILE *, such that is becomes closed-for-writing but still-open-for-reading? I'm imagining something analogous to the shutdown(SHUT_WR) that can be used on a socket-descriptor.

Related

What is the purpose of closeAfterStart in exec

I'm reading go exec source code. https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/os/exec/exec.go
When Stdinpipe is called, the reader is added to an array closeAfterStart. When Start() is called, the reader is closed. I'm not sure to understand why they close the reader just after starting the process.
To mirror what Penélope Stevens is saying, os.Pipe maps to an underlying os File pipe. By the time the *os.File returned by os.Pipe is closed it has already been passed to the new spawned process. The close will close the file descriptor in this process, but the spawned process can still read/write from that pipe.
The file descriptor is grabbed here: https://cs.opensource.google/go/go/+/refs/tags/go1.17.3:src/os/exec/exec.go;l=404-415;drc=refs%2Ftags%2Fgo1.17.3
And then passed to the spawned process with ProcAttr: https://pkg.go.dev/os#ProcAttr

Is dialogue possible through pipes between mother and child process on Windows?

I use CreateProcess and CreatePipe to spawn a child process and set up pipes between mother and child to communicate through. Then I use WriteFile to write to the write handle of the child's input pipe and ReadFile to read from the read handle of the child's output pipe. After having finished writing to the child I do CloseHandle on the write handle of the input pipe.
This all works well. However, I don't want it to work like this. I want to feed one line to the child, have the child compute something and output the results as a line of output, and then read that line of output from the mother. Then feed another line of input to the child and so on.
Unfortunately, when I skip the CloseHandle function call the two processes hang and nothing happens. So how can I reuse the pipes and avoid closing them? If I close them I have to create the child process again, right? That's a heavy operation, I suppose, and I really want to avoid that. Is there a good solution using pipes? I want the child process to run indefinitely and the communication to be a dialogue, alternating between writes and reads.
I solved it by using Windows kernel ReadFile and WriteFile instead of standard C functions in the child code. Here is the child code:
HANDLE inp = (HANDLE)_get_osfhandle(0);
HANDLE out = (HANDLE)_get_osfhandle(1);
char buffer[0x400];
unsigned long N;
while (ReadFile(inp, buffer, sizeof(buffer), &N, NULL) && N > 0)
{
WriteFile(out, buffer, N, &N, NULL);
}
And here is the mother code:
process app("child.exe");
app.write(string("hello\n"));
app.read().print();
app.write(string("world\n"));
app.read().print();
It prints:
hello
world

Unix: fork and wait

Here is the last part I do not understand in the source code of the command if.
Source: http://v6shell.org/history/if.c, with Syntax-Highlighting: http://pastebin.com/bj0Hvfrw
if(eq(a, "{")) { /* execute a command for exit code */
if(fork()) /*parent*/ wait(&ccode);
else { /*child*/
doex(1);
goto err;
}
while((a=nxtarg()) && (!eq(a,"}")));
return(ccode? 0 : 1);
}
As described in the man-page (http://man.cat-v.org/unix-6th/1/if), if we put the command in brackets "if expr { command } ", we can obtain his exit code.
So we fork the current process, and then wait for our child process to finish? But where is our child process continuing his work? After the fork, we will go into the while-loop and and just skip some arguments and then return with ccode? Where was ccode changed? What is ccode?
Could you please explain me this the given code snippet?
And elaborate on ccode?
The man page of wait: http://man.cat-v.org/unix-6th/2/wait
fork splits the current process in two: it makes a new process, running the same code, which begins running from the same point as the fork call. fork returns a different value in the parent and the child: in the parent, it returns the PID of the child process, and in the child it returns zero. The PID is a true value, so the wait call only executes in the parent (as the comment says), and the "else" branch only executes in the child (as its comment says). Both processes execute in parallel from the point of the fork onwards.
doex performs an exec of another program, replacing the child process and terminating with the new process's exit code. Only the doex call and execv execute in the child process from the current program.
wait:
causes its caller to delay until one of its child processes terminates.
That is, it causes the parent to pause until the child has exited. It is passed a pointer to an int variable and writes exit information for the child process into that variable. ccode is defined elsewhere in the enclosing function. The child process's exit code will be the exit code of the command that was execed.
When ccode has been given a non-zero value, that indicates an error running the program. In that case, the function returns zero, and otherwise it returns 1 to indicate success to its caller.
I encourage you take a look at either POSIX/the Single Unix Specification, the ISO C standard, or a standard C programming textbook to help understand what's going on in this codebase. The man pages that you link to also describe what the functions do, but often the newer versions fill in the gaps or are generally clearer, and the behaviour hasn't changed too much.
Although all of these questions are related to historical Unix, and the interplay between Unix and C at that point combined with the subsequent changes to both in the intervening time makes them arguably on-topic, they're also rudimentary programming questions (and so arguably off-topic).

fork()/exec() in XWindow application

How to execute xterm from XWindow program, insert it into my window, but continue execution both while xterm is active and after it was closed?
In my XWindows (XLib over XCB) application I want to execute xterm -Into <handle>. So that my window contains xterm window in it. Unfortunately something wrong is happening.
pseudo code:
if (fork() == 0) {
pipe = popen('xterm -Into ' + handle);
while (feof(pipe)) gets(pipe);
exit(0);
}
I tired system() and execvp() as well. Every thing is fine until I exit from bash that runs in xterm, then my program exits. I guess that connection to X server is lost because it is shared between parent and child.
UPDATE: here is what is shown on terminal after program exits (or rather crashes).
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
after 59 requests (59 known processed) with 1 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
y: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted
One possibility is that you are terminating due to the SIGCHLD signal not
being ignored and causing your program to abort.
signal(SIGCHLD, SIG_IGN);
Another is, as you suspect something actively closing the X session. Just
closing the socket itself should not matter but are you using a library that
registers an atexit call it could cause an issue.
Since from your snippet,
it looks like you don't actually care about the stdout of the xterm, a
better way to do it would be to actuall close fd's 0,1,2. Also since it looks
like you don't need to do anything in the child process after xterm
terminates you can use 'exec' rather than 'popen' to fully replace the
child process with that of the xterm including any cleanup handlers that
were left around. Though, I am not sure how pruned your snippet is from what you want to do as obviously the call to 'gets' is not what you want.
to make sure the X connection is closed, you can set its close on exec flag
with the following. (this will work on POSIX systems where the x connection
number is the fd of the server socket)
fcntl(XConnectionNumber(display), F_SETFD, fcntl(XConnectionNumber(display), F_GETFD) | FD_CLOEXEC);
Also note that 'popen' itself forks in the background in addition to your fork, I think you probably want to do an execvp there then use waitpid(... , WNOHANG) to check for the childs termination in your main X11 loop if you care to know when it exited.

FFmpeg progress track visual C++

In my main process, i create a ffmpeg child process using CreateProcess(...).
I need to track the status of converting progress to update a progress bar. To do it, I read text from ffmpeg output and extract progress status from it.
I make a sample programm like this:
HANDLE rPipe, wPipe;
CreatePipe(&rPipe,&wPipe,&secattr,0);
STARTUPINFO sInfo;
ZeroMemory(&sInfo,sizeof(sInfo));
PROCESS_INFORMATION pInfo;
ZeroMemory(&pInfo,sizeof(pInfo));
sInfo.cb=sizeof(sInfo);
sInfo.dwFlags=STARTF_USESTDHANDLES;
sInfo.hStdInput=NULL;
sInfo.hStdOutput=wPipe;
sInfo.hStdError=wPipe;
// pStr contain ffmpeg command
CreateProcess(0,(LPTSTR)pStr,0,0,TRUE,NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&sInfo,&pInfo);
CloseHandle(wPipe);
BOOL ok;
do
{
memset(buf,0,bufsize);
ok=::ReadFile(rPipe,buf,100,&reDword,0);
result += buf;
}while(ok);
But I couldnt get "result" interactively updated. My app is held during conversion, and "result" string update only after ffmpeg's process finish.
How can I have my main process and ffmpeg's run simultaneously, and interactively read from/write to ffmpeg process's output/input?
Thanks for your time!
LRs
If the ffmpeg just uses stdout without explicitly flushing the output then it may not get sent to the calling process until it ends
Child processes that use such C run-time functions as printf() and
fprintf() can behave poorly when redirected. The C run-time functions
maintain separate IO buffers. When redirected, these buffers might not
be flushed immediately after each IO call. As a result, the output to
the redirection pipe of a printf() call or the input from a getch()
call is not flushed immediately and delays, sometimes-infinite delays
occur. This problem is avoided if the child process flushes the IO
buffers after each call to a C run-time IO function. Only the child
process can flush its C run-time IO buffers. A process can flush its C
run-time IO buffers by calling the fflush() function.
http://support.microsoft.com/kb/190351
In order of tracking the progress of your child process while it is running (and after its completion), you need to check the status of this child process.
After the process was launched, check the status periodically using the following code.
pi is the PROCESS_INFORMATION:
PROCESS_INFORMATION pi;
and the code:
DWORD exitCode = 0;
success = [GetExitCodeProcess][2](pi.hProcess, &exitCode);
exitCode will hold the value STILL_ACTIVE if the process is still running.
If the function succeeds, the return value of success is nonzero.

Resources