How do I process the output of "dir"? - c

I have written a program that implements a tiny shell to process commands from the user.
If the entered command is recognised as internal command, my program executes this command.
These commands are implemented as internal functions and their output is being processed by another internal function that is able to send the text to the console and / or to file for logging purposes.
If the entered command is not recognised, I try to execute the entered command as part of the windows command shell, e.g. : cmd dir would execute the dir command and the output gets printed on the console. This is done via CreateProcess. Until now I did not specify the members hStdError, hStdOutput and hStdInput of the STARTUPINFO parameter.
I tried to implement and adapt the example of Creating a Child Process with Redirected Input and Output.
I did not use their implementation of the child process, but tried to get the output of the dir command into my application:
#include "pch.h"
#include <windows.h>
#define BUFSIZE 512
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
TCHAR szCmdline[] = TEXT("cmd /c dir q:\\Sicherung\\Bilder /s");
BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!bSuccess)
return; // ErrorExit(("CreateProcess"));
else
{
// Close handles to the child process and its primary thread.
// Some applications might keep these handles to monitor the status
// of the child process, for example.
//CloseHandle(piProcInfo.hProcess);
//CloseHandle(piProcInfo.hThread);
}
}
void ReadFromPipe(void)
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
for (;;)
{
DWORD objectstat = WAIT_TIMEOUT;
//do
//{
// objectstat = WaitForSingleObject(piProcInfo.hProcess, 0);
//} while (objectstat != WAIT_OBJECT_0);
memset(&chBuf[0], 0x00, BUFSIZE);
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess)
break;
bSuccess = WriteFile(hParentStdOut, chBuf,
dwRead, &dwWritten, NULL);
if (!bSuccess)
break;
if (dwRead == 0)
break;
}
}
int main()
{
SECURITY_ATTRIBUTES saAttr;
printf("\n->Start of parent execution.\n");
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
return -1;// ErrorExit("StdoutRd CreatePipe");
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
return -2;// ErrorExit(("Stdout SetHandleInformation"));
// Create a pipe for the child process's STDIN.
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
return -3 ;// ErrorExit(("Stdin CreatePipe"));
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
return -4;// ErrorExit(("Stdin SetHandleInformation"));
// Create the child process.
CreateChildProcess();
ReadFromPipe();
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return 0;
}
I know, that the problem has to be with ReadFile. I can not determine when all output of the dir command has been processed. Checking dwRead for 0 or for BUFSIZE does not work. dwReadnever becomes 0, and it can happen that it is less than BUFSIZE, because the dir command is not fast enough.
So, how am i supposed to end processing of the pipe data?

Ok, after i searched some different terms in google, I came up with this link to stackoverflow ;) :
How to read output from cmd.exe using CreateProcess() and CreatePipe()
Ian Boyd wrote there :
Once you've launched your child process: be sure to close those ends of the pipe you no longer need.
result = CreateProcess(...);
//CreateProcess demands that we close these two populated handles when we're done with them. We're done with them.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
/*
We've given the console app the writable end of the pipe during CreateProcess; we don't need it anymore.
We do keep the handle for the *readable* end of the pipe; as we still need to read from it.
The other reason to close the writable-end handle now is so that there's only one out-standing reference to the writeable end: held by the console app.
When the app closes, it will close the pipe, and ReadFile will return code 109 (The pipe has been ended).
That's how we'll know the console app is done. (no need to wait on process handles with buggy infinite waits)
*/
CloseHandle(g_hChildStd_OUT_Wr);
g_hChildStd_OUT_Wr = 0;
CloseHandle(g_hChildStd_IN_Rd);
g_hChildStd_OUT_Wr = 0;
The common problem with most solutions is that people try to wait on a process handle. There are many problems with this; the main one being that if you wait for the child the terminate, the child will never be able to terminate.
After closing the unneeded handles ReadFile works as expected.

Related

How do you send commands from a parent process to run on an existing child cmd.exe process?

I have a piece of code that, amongst other things, creates a child cmd.exe process with redirected I/O handles, given a specific input.
HANDLE child_IN_Rd = NULL;
HANDLE child_IN_Wr = NULL;
HANDLE child_OUT_Rd = NULL;
HANDLE child_OUT_Wr = NULL;
SECURITY_ATTRIBUTES sa;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&child_IN_Rd, &child_IN_Wr, sa, 0);
CreatePipe(&child_OUT_Rd, &child_OUT_Wr, sa, 0);
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.hStdError = child_OUT_Wr;
si.hStdOutput = child_OUT_Wr;
si.hStdInput = child_IN_Rd;
CreateProcessA("C:\\Windows\\system32\\cmd.exe",
NULL,
NULL.
NULL,
false,
NULL,
NULL,
NULL,
si,
pi)
CloseHandle(child_IN_Rd);
CloseHandle(child_OUT_Wr);
The intent is for the code to run cmd commands at the behest of a remote client. The parent receives a string from the client, and writes it to child_IN_Wr. The cmd.exe process should then run the string as a command, and the output is read on the parent console.
Something like this:
WriteFile(child_IN_Wr, command, command_size, NULL, NULL);
...
ReadFile(child_OUT_Rd, buffer, buffer_size, NULL, NULL);
//Do something with the output, eg. print, or sending it back to client.
printf("%s", buffer);
However, I am unable to get it to work. The existing cmd.exe process does not seem to register/process an input written to child_IN_Wr, and no output is read as a result.
I understand that this issue can be easily fixed by simply running CreateProcess with the given command under the CommandLine parameter, every time the parent receives an input from the remote client. However, this spawns and terminates a new cmd.exe process every time a command is run, and I wish to run all the commands on a single cmd.exe process created beforehand given a specific input from a client, that only terminates after the client sends another specific input.
How should I go about this? I have been trying out the use of pipes for IPC, as seen above, but have had no luck thus far. Thanks in advance.

Capture stdout of child process with overlapped I/O

I want to spawn a child process and capture its stdout (and stderr) using overlapped I/O without using threads. Here's my current knowledge of all the stars that must align in order to achieve that, i.e. here's the recipe:
Set an inheritable handle as the stdout (and stderr) of the process when creating the process (set hStdOutput and hStdError fields of STARTUPINFO).
Tell the process to inherit any inheritable handles from its parent so that it will inherit said stdout handle (arg bInheritHandles of CreateProcess()).
The handle itself must be the writing end of an anonymous pipe. I will then capture the process' stdout by reading from the reading end of that pipe.
The pipe must be overlapped-I/O-enabled.
Since anonymous pipes don't support overlapped I/O, I must emulate them using a named pipe (which I create with FILE_FLAG_OVERLAPPED). This pipe will serve as the writing end of the anonymous pipe. I then open this pipe using CreateFile to get a handle to the reading end (this is more/less how anonymous pipes are implemented in Windows also).
The reading end of the pipe must not be inherited by the child process, so I am careful to not make it inheritable. (does anyone have a good explanation for why that is?)
After the process is created and the writing handle is thus inherited, I close said handle in the parent process. This is so that (thanks #o11c in the comments) the writing end of the pipe is left with only one handle open to it (the handle that the child holds), so that when the child exists, the pipe is closed and reading from it fails with a broken pipe error (otherwise we would never know when to stop reading).
Now that everything is set up I can start reading from the pipe: I create a completion port, perform an overlapped ReadFile() and then check the completion status.
And here's the problem: GetQueuedCompletionStatus() hangs until timeout and then returns WAIT_TIMEOUT instead of returning immediately with either some data or with ERROR_IO_PENDING so I can check again.
Below is the minimum amount of C code that reproduces the problem. Any help appreciated. Thanks!
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
PROCESS_INFORMATION pi;
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
OVERLAPPED o;
#define sz 1024
unsigned char buf[sz];
char* pipe_name = "\\\\.\\pipe\\t1";
int main(int argc, char **argv) {
sa.nLength = sizeof(sa);
sa.bInheritHandle = 1;
HANDLE stdout_r = CreateNamedPipe(pipe_name,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
0,
1,
8192, 8192,
120 * 1000,
0
);
assert(stdout_r != INVALID_HANDLE_VALUE);
HANDLE stdout_w = CreateFile(pipe_name,
GENERIC_WRITE,
0,
&sa,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0
);
assert(stdout_w != INVALID_HANDLE_VALUE);
si.hStdOutput = stdout_w;
si.hStdError = stdout_w;
si.dwFlags = STARTF_USESTDHANDLES;
assert(CreateProcess(0, "dir", 0, 0, 1, 0, 0, 0, &si, &pi) != 0);
assert(CloseHandle(stdout_w) != 0);
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
assert(iocp != INVALID_HANDLE_VALUE);
if (ReadFile(stdout_r, buf, sz, 0, &o) == 0) {
if (GetLastError() == ERROR_IO_PENDING) {
DWORD n;
ULONG_PTR compkey;
LPOVERLAPPED po;
int ret = GetQueuedCompletionStatus(iocp, &n, &compkey, &po, 1000);
if (!ret) {
assert(GetLastError() != WAIT_TIMEOUT);
}
}
}
return 0;
}
NOTE: I built/tested this with mingw but VC should work too (in ANSI mode).

Passing an anonymous PIPE HANDLE to Child Process

I am wanting to pass an anonymous Pipe HANDLE to a Child Process. This answer seems to explain it well for C++, however I am wanting to do this in C.
Do I convert the handle into an integer? Or do I pass the memory address of the HANDLE to the child process, and then make another HANDLE pointing to that?
For example:
Parent:
BOOL bCreatePipe, bReadFile;
HANDLE hRead = NULL;
HANDLE hWrite = NULL;
SECURITY_ATTRIBUTES lpPipeAttributes;
lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
lpPipeAttributes.lpSecurityDescriptor = NULL;
lpPipeAttributes.bInheritHandle = TRUE;
// Create pipe file descriptors for parent and child
bCreatePipe = CreatePipe(&hRead, &hWrite, &lpPipeAttributes, (DWORD)BUFFER_SIZE);
if (bCreatePipe == FALSE) {
printf("[-]Error creating IPC pipe : %d", GetLastError());
exit(-1);
}
// Create command line arguments for child process
snprintf(child_cmd, CMD_LINE_SIZE, "%d", &hWrite);
// Create child process to handle request
if ( !CreateProcess(
"C:\\Users\\Child.exe", // No module name (use command line)
child_cmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to TRUE (for pipe)
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("[-]CreateProcess failed : %d\n", GetLastError());
exit(-1);
}
Child:
// Set variables to arguments passed by parent
HANDLE hWrite = atoi(argv[0]);
yes, this is ok pass HANDLE by value. in practice currently your code will be work ok. however need remember that HANDLE is 64-bit size on 64-bit system - so not fit in int which is 32-bit size (now user mode handle values in practice fit to 32bit). so need use say %I64x format to encode handle value and _atoi64 or _wcstoi64 to decode.
for example in parent:
WCHAR child_cmd[32];
swprintf(child_cmd, L"<%I64x>", (ULONG64)(ULONG_PTR)hWrite);
and in child:
HANDLE hWrite = 0;
if (PWSTR sz = wcschr(GetCommandLineW(), '<'))
{
hWrite = (HANDLE)(ULONG_PTR)_wcstoi64(sz + 1, &sz, 16);
if (*sz != '>')
{
hWrite = 0;
}
}
as separate note - use CreatePipe not the best choice - this api very bad design, say one handle only for write, another only for read, can not select asynchronous I/O, can not make one handle inherit and another not (as need in this case) - better use CreateNamedPipeW + CreateFileW for create pipe pair. or this way if you want no name on pipe (work from win7)

Win32: Anonymous inherited pipes don't close on subprocess exit

I have been attempting to use anonymous pipes to communicate with a spawned subprocess via their stdin and stdout, similar to this example. So far, so good - I communicate with it via WriteFile(), and I read data from it via PeekNamedPipe() and then ReadFile(). Life is good.
However, I'm encountering something distressing - when the subprocess closes unexpectedly, a parent process call to WriteFile() never seems to return any sort of failure state indicating that the pipe has closed, and my parent process happily continues chugging along writing data until I overflow the pipe's internal buffer and block forever.
My setup code looks like this:
// Set up pipes
SECURITY_ATTRIBUTES sec_attrs;
memset(&sec_attrs, 0, sizeof(SECURITY_ATTRIBUTES));
sec_attrs.nLength = sizeof(SECURITY_ATTRIBUTES);
sec_attrs.bInheritHandle = TRUE;
sec_attrs.lpSecurityDescriptor = NULL;
if (!CreatePipe(&midi_process_in_reader, &midi_process_in_writer, &sec_attrs, 0))
{
DEBUGOUT("Could not initialize midiproc stdin");
return false;
}
if (!SetHandleInformation(midi_process_in_writer, HANDLE_FLAG_INHERIT, 0))
{
DEBUGOUT("Could not disinherit midiproc stdin");
return false;
}
if (!CreatePipe(&midi_process_out_reader, &midi_process_out_writer, &sec_attrs, 0))
{
DEBUGOUT("Could not initialize midiproc stdout/stderr");
return false;
}
if (!SetHandleInformation(midi_process_out_reader, HANDLE_FLAG_INHERIT, 0))
{
DEBUGOUT("Could not disinherit midiproc stdin");
return false;
}
// Launch the subprocess
PROCESS_INFORMATION proc_info;
memset(&proc_info, 0, sizeof(proc_info));
STARTUPINFO startup_info;
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
startup_info.hStdInput = midi_process_in_reader;
startup_info.hStdOutput = midi_process_out_writer;
startup_info.dwFlags = STARTF_USESTDHANDLES;
BOOL ok = CreateProcess(TEXT(module), TEXT(cmdline), NULL, NULL, TRUE,
CREATE_NEW_CONSOLE, NULL, NULL, &startup_info, &proc_info);
The only difference that I can see between the example and my code is that I don't hook up stderr - I want to keep it around for fprintf debugging.
I am probably going to need to go with some sort of "heartbeat" message in the long run, because the subprocess could become a zombie and be completely alive and keep their handles open but never read off of stdin, which would wedge things in a different way. However, I want to make sure that I'm not missing something in my understanding of anonymous pipes on Windows.
You must close midi_process_in_reader and midi_process_out_writer after calling CreateProcess(). Your issue is not because the "inherited pipes don't close on subprocess exit", it is because you forgot to close the pipes in your own process.

C, Create Processes and wait

Hi I'm creating more than one process with the CreateProcess
and I need to wait all of them to finish, to analyze the results.
And I cant WaitForSingleObject because I need all of the processes running at the same time.
Since each process has a handle at Process_Information (hProcess)
I tought it was ok to use WaitForMultipleObjects,but the parent process ends without waiting for the child.
Is it ok to use WaitForMultipleObjects or there is a better way?
This is how I'm creating the processes:
#define MAX_PROCESS 3
STARTUPINFO si[MAX_PROCESS];
PROCESS_INFORMATION pi[MAX_PROCESS];
WIN32_FIND_DATA fileData;
HANDLE find;
int j=0, t=0;
ZeroMemory(&si, sizeof(si));
for (t = 0; t < MAX_PROCESS; t++)
si[t].cb = sizeof(si[0]);
ZeroMemory(&pi, sizeof(pi));
while (FindNextFile(find, &fileData) != 0)
{
// Start the child process.
if (!CreateProcess(_T("C:\\Users\\Kumppler\\Documents\\Visual Studio 2010\\Projects\ \teste3\\Debug\\teste3.exe"), // No module name (use command line)
aux2, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si[j], // Pointer to STARTUPINFO structure
&pi[j]) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
j++;
//find next file related
}
FindClose(find);
WaitForMultipleObjects(MAX_PROCESS, &pi[j].hProcess, FALSE, INFINITE);
//wait and analyze results
Btw I'm trying not to use threads.
WaitForMultipleObjects expects array of handles:
HANDLE hanldes[MAX_PROCESS];
for (int i = 0; i < MAX_PROCESS; ++i)
{
handles[i] = pi[i].hProcess;
}
WaitForMultipleObjects(MAX_PROCESS, handles, TRUE, INFINITE);
Also you should know that maximum array size of handles for WaitForMultipleObjects is limited to MAXIMUM_WAIT_OBJECTS (which is 64).
If you want to wait for all the HANDLEs set 'bWaitAll' (the third parameter) to 'TRUE'.

Resources