I made a function where you get the output of a command. It works but it doesn't preserve the status of the previous command, for example if you change directory (cd dir) it isn't changed in the new command. Can I change the function such that if I change the directory it is preserved in the next command? This is my function:
int execute(char *command, char *output)
{
int rc;
char buffer[4096], *cmd;
DWORD byte, bytes;
HANDLE in_read, in_write, out_read, out_write;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
cmd = malloc(sizeof(char) * (strlen(command) + 8));
strcpy(cmd, "cmd /c ");
strcat(cmd, command);
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
ZeroMemory(&si, sizeof(STARTUPINFO));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
rc = CreatePipe(&out_read, &out_write, &sa, 0);
check(rc != 0)
rc = SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0);
check(rc != 0)
rc = CreatePipe(&in_read, &in_write, &sa, 0);
check(rc != 0)
rc = SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0);
check(rc != 0)
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdError = out_write;
si.hStdOutput = out_write;
si.hStdInput = in_read;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
rc = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi);
check(rc != 0)
CloseHandle(out_write);
bytes = 0;
while (ReadFile(out_read, &buffer, 4096, &byte, NULL)) {
if (bytes == 0) {
bytes = bytes + byte;
check(bytes > sizeof(output))
strcpy(output, buffer);
ZeroMemory(&buffer, sizeof(buffer));
} else {
bytes = bytes + byte;
check(bytes > sizeof(output))
strcat(output, buffer);
ZeroMemory(&buffer, sizeof(buffer));
}
};
CloseHandle(in_read);
CloseHandle(in_write);
CloseHandle(out_read);
free(cmd);
return 1;
error:
free(cmd);
return -1;
}
The CreateProcess starts a brand new process that is running independently from yours.
If you make that independent process change its own current working directory, then it will be changed only in the new process, and not in your process running your program.
Related
I am trying to capture output from cmd.exe when running commands. I am trying to capture Unicode output to support other languages. My code works right now for getting unicode back from built in commands to cmd.exe. Such as Dir. But if I try to run external commands such as "net user" or "ipconfig" it does not output unicode.
I did reading and found out it is due to my pipes being file pipes. Ipconfig.exe determines if it is printing to the console or not. If it is printing to console, it uses WriteFileW and outputs unicode. Else it just prints ANSI and I get ???????? for anything Unicode.
#include <winsock.h>
#include <Windows.h>
#include <stdio.h>
void ExecCmd() {
HANDLE hPipeRead;
HANDLE hPipeWrite;
SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = { 0 };
BOOL fSuccess;
BOOL bProcessEnded = FALSE;
size_t total = 0;
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0)) {
return;
}
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdOutput = hPipeWrite;
si.hStdError = hPipeWrite;
si.wShowWindow = SW_HIDE;
WCHAR k[] = L"cmd.exe /u /c net user";
fSuccess = CreateProcessW(NULL, k, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (!fSuccess) {
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
return;
}
for (; !bProcessEnded;) {
bProcessEnded = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0;
while (TRUE) {
DWORD dwRead = 0;
DWORD dwAvail = 0;
WCHAR *buffer = NULL;
if (!PeekNamedPipe(hPipeRead, NULL, NULL, NULL, &dwAvail, NULL)) {
break;
}
if (!dwAvail) {
break;
}
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (dwAvail + 2));
if (buffer == NULL) {
break;
}
if (!ReadFile(hPipeRead, buffer, dwAvail, &dwRead, NULL) || !dwRead) {
break;
}
total += dwRead;
}
}
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return;
}
int main() {
ExecCmd();
return 0;
}
My question is how can I change the way my pipes are getting information back from external commands like ipconfig so that it will support unicode.
I'm working in a C project, windows environment using WinAPI.
My function execs a command (e.g. : "dir C:\Users") it received as a param, and returns its output.
It is ran from a DLL so it must not spawn a cmd.exe windows, which means I can't use _popen. So I use CreateProcessA, and a pipe to catch stdout.
Here is the code :
char *runExec(char *command, int *contentLen) {
char *ret=NULL,*tmp=NULL;
DWORD readBytes;
int size=0;
char buffer[128],cmdBuf[4096];
HANDLE StdOutHandles[2];
CreatePipe(&StdOutHandles[0], &StdOutHandles[1], NULL, 4096);
STARTUPINFOA si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = StdOutHandles[1];
si.hStdError = StdOutHandles[1];
PROCESS_INFORMATION pi;
snprintf(cmdBuf,4096,"cmd /C %s", command);
if (!CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi)) {
printf("Error createProcess : %d\n",GetLastError());
return NULL;
}
CloseHandle(StdOutHandles[1]);
printf("Before read\n");
while (ReadFile(StdOutHandles[0], buffer, 127, &readBytes, NULL)){
printf("IN WHILE\n");
buffer[readBytes] = 0;
printf("read %d bytes\n", readBytes);
size += readBytes;
tmp = (char *)realloc(ret, size + 1);
if (tmp == NULL) {
free(ret);
return NULL;
}
ret = tmp;
strncpy(ret + (size - readBytes), buffer, readBytes);
ret[size] = 0;
}
printf("Readfile returned with %d, read %d\n", GetLastError(),readBytes);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(StdOutHandles[0]);
printf("#%s#\n", ret);
return ret;
}
And the output is :
Before read
Readfile returned with 109, read 0
#(null)#
So from that I understand that :
- My loop isn't even executed once
- ReadFile reads nothing and returns Broken Pipe immediately
I have read various stackoverflow and MSDN pages, but I can't seem to make it work.
As pointed out in the comment, handles must be inheritable, which means replacing the CreatePipe like this :
SECURITY_ATTRIBUTES pipeAttrib;
memset(&pipeAttrib, 0, sizeof(pipeAttrib));
pipeAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeAttrib.bInheritHandle = NULL;
pipeAttrib.bInheritHandle = TRUE;
if (!CreatePipe(&StdOutHandles[0], &StdOutHandles[1],&pipeAttrib, 4096)) {
printf("Create pipe error %d\n", GetLastError());
return NULL;
}
And setting CreateProcess 5th parameter (bInheritHandles) to TRUE instead of FALSE.
Im trying to print the output and input of cmd commands recieved to stdout just like a normal cmd.exe would do.
I could use the function _popen but when i start a program like Python or Powershell whith it, it doesnt work. So i Need the Output of the child process and be able to send commands to the child process.
there is a simmilar question here
So i modified the code from this link to look like this:
void WriteToPipe(char* command){
DWORD dwRead, dwWritten;
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);
// Close the pipe handle so the child process stops reading.
if (!CloseHandle(g_hChildStd_IN_Wr))
ErrorExit(TEXT("StdInWr CloseHandle"));
}
void ReadFromPipe(void){
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
//bSuccess = PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, BUFSIZE, &dwRead, &dwTotalAvailBytes, &dwBytesLeft);
}
the main loop looks like this:
CreateChildProcess("C:\\Python27\\python.exe");
char input_buffer[100] = { 0 };
while (1){
fgets(input_buffer, 99, stdin);
WriteToPipe(input_buffer);
ReadFromPipe();
}
everything else (from the code) stayed the same.
Now my Problem is, i want to enter multiple commands to the same process, but there is a CloseHandle fucntion in WriteToPipe, after the handle is closed i cant enter more commands.
How to get a valid HANDLE to write more than 1 command to the process ?
int WriteToPipe(char* command){
DWORD dwRead, dwWritten;
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);
return bSuccess ;
}
close the handle in main() function since g_hChildStd_IN_Wr is global. also, return bSuccess; notify you if write to pipe has succeeded
put ReadFromPipe() in a separate Thread;
my code here is a garbage but it is working code, it is for test purpose only.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hInputFile = NULL;
int CreateChildProcess(TCHAR *szCmdline);
void PrintError(char *text,int err);
int InitPipes();
int WriteToPipe(char* command){
DWORD dwRead, dwWritten;
BOOL bSuccess = FALSE;
SetLastError(0);
WriteFile(g_hChildStd_IN_Wr, command, strlen(command), &dwWritten, NULL);
bSuccess=GetLastError();
PrintError("WriteToPipe",bSuccess);
return (bSuccess==0)||(bSuccess==ERROR_IO_PENDING);
}
int ReadFromPipe(void){
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetLastError(0);
while(
ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL)
&&
WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL)
);
bSuccess=GetLastError();
PrintError("ReadFromPipe",bSuccess);
return (bSuccess==0)||(bSuccess==ERROR_IO_PENDING);
}
HANDLE hThread;
int __stdcall ThreadProc(int arg){
while(ReadFromPipe())
;
return 0;
}
int main(){
char input_buffer[100] = { 0 };
if(!InitPipes()){
printf("Failed to CreatePipes\n");
return -1;
}
if(!CreateChildProcess("cmd.exe")){
printf("Failed to create child process\n");
return -2;
}
hThread=CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
while (1){
fgets(input_buffer, 99, stdin);
if(!WriteToPipe(input_buffer)) break;
}
printf("Program terminated\n");
return 0;
}
int CreateChildProcess(TCHAR *szCmdline){
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
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 ){
// 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);
}
return bSuccess;
}
int InitPipes(){
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
return 0;
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
return 0;
if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
return 0;
if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
return 0;
return 1;
}
void PrintError(char *text,int err){
DWORD retSize;
LPTSTR pTemp=NULL;
if(!err) return;
retSize=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
err,
LANG_NEUTRAL,
(LPTSTR)&pTemp,
0,
NULL );
if(pTemp) printf("%s: %s\n",text,pTemp);
LocalFree((HLOCAL)pTemp);
return ;
}
Below is my code:
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <db.h>
#define DATABASE "access.db"
typedef struct {
char data1[20];
char src[20];
} pearson_record;
I am geting the error:
illegal flag specified to DB->get
DB->get: Invalid argument
Any idea where I am going wrong.
int
main()
{
pearson_record s;
char *papa="1.1.1.1";
char *source="papa";
DB *dbp;
DBT key, data;
int ret, t_ret;
db_recno_t recno;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp->open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp->err(dbp, ret, "%s", DATABASE);
goto err;
}
recno = 10;
#define BUFFER_LENGTH (5 * 1024 * 1024)
data.ulen = BUFFER_LENGTH;
data.flags = DB_DBT_USERMEM;
strncpy(s.data1, papa, strlen(papa)+1);
strncpy(s.src, source, strlen(source)+1);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
//memset(&s, 0, sizeof(struct pearson_record));
key.data = &recno;
key.size = sizeof(recno);
data.data = &s;
data.size = sizeof(s);
papa="1.1.1.2";
source="papaa";
strncpy(s.data1, papa, strlen(papa)+1);
strncpy(s.src, source, strlen(source)+1);
if ((ret = dbp->put(dbp, NULL, &key,&data,0)) == 0)
printf("db: %d: key stored.\n", *(int *)key.data);
else
{
dbp->err(dbp, ret, "DB->put");
goto err;
}
recno = 11;
strncpy(s.data1, papa, strlen(papa)+1);
strncpy(s.src, source, strlen(source)+1);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
//memset(&s, 0, sizeof(struct pearson_record));
key.data = &recno;
key.size = sizeof(recno);
data.data = &s;
data.size = sizeof(s);
papa="1.1.1.2";
source="papaa";
strncpy(s.data1, papa, strlen(papa)+1);
strncpy(s.src, source, strlen(source)+1);
if ((ret = dbp->put(dbp, NULL, &key,&data,0)) == 0)
printf("db: %d: key stored.\n", *(int *)key.data);
else
{
dbp->err(dbp, ret, "DB->put");
goto err;
}
pearson_record *ppr;
if ((ret = dbp->get(dbp, NULL, &key, &data, DB_SET_RECNO)) == 0) {
ppr = (pearson_record *) data.data;
printf("db: %d: key retrieved: data was %s,%s. %d\n",
*(int *)key.data, ppr->data1,ppr->src, data.size);
}
else {
dbp->err(dbp, ret, "DB->get");
goto err;
}
if ((ret = dbp->get(dbp, NULL, &key, &data, DB_SET_RECNO)) == 0) {
ppr = (pearson_record *) data.data;
printf("db: %d: key retrieved: data was %s,%s. %d\n",
*(int *)key.data, ppr->data1,ppr->src, data.size);
}
else {
dbp->err(dbp, ret, "DB->get");
goto err;
}
err: if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
ret = t_ret;
exit(ret);
}
A quick glance at the documentation for DB->get says: "For DB_SET_RECNO to be specified, the underlying database must be of type Btree, and it must have been created with the DB_RECNUM flag."
It doesn't look like you created the database with that flag. I haven't looked through the rest of your code, but that's one obvious place that needs to be fixed.
You can also ask these questions on the online Berkeley DB forum.
Regards,
Dave
I am trying to implement something that will give me a solution for:
| --> cmd3 --> cmd4 -->
cmd2-->|
| --> cmd5 --> cmd6 -->
and so on...
This is multiple executions of processes and pipe the results via chains of other's processes with threads, each commands chain should run in different thread.
I choose socketpair for the implementation of IPC, because pipe has a a bottleneck with the buffer size limit 64K.
When I test the program with single chain - it's work as expected, but when I am running master command and the output of it I send via socketpair to read end of multiple processes in each thread - the program stuck (look like a deadlock)
Whats I am doing wrong:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>
typedef struct command {
char** argv;
int num_children;
struct command* master_cmd;
struct command** chains;
struct command* next;
int fd;
} command;
void be_child(command* cmd);
int execute_master_command_and_pipe_to_childs(command* cmd, int input);
int run_pipeline_sockets(command *cmd, int input);
void waitfor(int fd);
int main(int argc, char* argv[]) {
handle_segfault();
command* cmd1 = (command*) malloc(sizeof(command));
command* cmd2 = (command*) malloc(sizeof(command));
command* cmd3 = (command*) malloc(sizeof(command));
command* cmd4 = (command*) malloc(sizeof(command));
command* cmd5 = (command*) malloc(sizeof(command));
command* cmd6 = (command*) malloc(sizeof(command));
command* chains1[2];
chains1[0] = cmd3;
chains1[1] = cmd5;
char* args1[] = { "cat", "/tmp/test.log", NULL };
char* args3[] = { "sort", NULL, NULL };
char* args4[] = { "wc", "-l", NULL };
char* args5[] = { "wc", "-l", NULL };
char* args6[] = { "wc", "-l", NULL };
cmd1->argv = args1;
cmd2->argv = NULL;
cmd3->argv = args3;
cmd4->argv = args4;
cmd5->argv = args5;
cmd6->argv = args6;
cmd1->master_cmd = NULL;
cmd1->next = NULL;
cmd1->chains = NULL;
cmd1->num_children = -1;
cmd2->master_cmd = cmd1;
cmd2->chains = chains1;
cmd2->next = NULL;
cmd2->num_children = 2;
cmd3->master_cmd = NULL;
cmd3->next = cmd4;
cmd3->chains = NULL;
cmd3->num_children = -1;
cmd4->master_cmd = NULL;
cmd4->next = NULL;
cmd4->chains = NULL;
cmd4->num_children = -1;
cmd5->master_cmd = NULL;
cmd5->next = cmd6;
cmd5->chains = NULL;
cmd5->num_children = -1;
cmd6->master_cmd = NULL;
cmd6->next = NULL;
cmd6->chains = NULL;
cmd6->num_children = -1;
int rc = execute_master_command_and_pipe_to_childs(cmd2, -1);
return 0;
}
int execute_master_command_and_pipe_to_childs(command* cmd, int input) {
int num_children = cmd->num_children;
int write_pipes[num_children];
pthread_t threads[num_children];
command* master_cmd = cmd->master_cmd;
pid_t pid;
int i;
for (i = 0; i < num_children; i++) {
int new_pipe[2];
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, new_pipe) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "ERROR (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if (cmd->chains[i] != NULL) {
cmd->chains[i]->fd = new_pipe[0];
if (pthread_create(&threads[i], NULL, (void *) be_child,
cmd->chains[i]) != 0) {
perror("pthread_create"), exit(1);
}
write_pipes[i] = new_pipe[1];
} else {
perror("ERROR\n");
}
}
if (input != -1) {
waitfor(input);
}
int pipefd = run_pipeline_sockets(master_cmd, input);
int buffer[1024];
int len = 0;
while ((len = read(pipefd, buffer, sizeof(buffer))) != 0) {
int j;
for (j = 0; j < num_children; j++) {
if (write(write_pipes[j], &buffer, len) != len) {
fprintf(STDERR_FILENO, "Write failed (child %d)\n", j);
exit(1);
}
}
}
close(pipefd);
for (i = 0; i < num_children; i++) {
close(write_pipes[i]);
}
for (i = 0; i < num_children; i++) {
if (pthread_join(threads[i], NULL) != 0) {
perror("pthread_join"), exit(1);
}
}
}
void waitfor(int fd) {
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 500000;
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
perror("select()");
else if (retval) {
printf("Data is available now on: %d\n", fd);
} else {
printf("No data on: %d\n", fd);
///waitfor(fd);
}
}
void be_child(command* cmd) {
printf(
"fd = %d , argv = %s , args = %s , next = %d , master_cmd = %d , next_chain = %d\n",
cmd->fd, cmd->argv[0], cmd->argv[1], cmd->next, cmd->master_cmd,
cmd->chains);
waitfor(cmd->fd);
int fd = run_pipeline_sockets(cmd, cmd->fd);
waitfor(fd);
int buffer[1024];
int len = 0;
while ((len = read(fd, buffer, sizeof(buffer))) != 0) {
write(STDERR_FILENO, &buffer, len);
}
close(cmd->fd);
close(fd);
}
int run_pipeline_sockets(command *cmd, int input) {
int pfds[2] = { -1, -1 };
int pid = -1;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pfds) < 0) {
int errnum = errno;
fprintf(STDERR_FILENO, "socketpair failed (%d: %s)\n", errnum,
strerror(errnum));
return EXIT_FAILURE;
}
if ((pid = fork()) == 0) { /* child */
if (input != -1) {
dup2(input, STDIN_FILENO);
close(input);
}
if (pfds[1] != -1) {
dup2(pfds[1], STDOUT_FILENO);
close(pfds[1]);
}
if (pfds[0] != -1) {
close(pfds[0]);
}
execvp(cmd->argv[0], cmd->argv);
exit(1);
} else { /* parent */
if (input != -1) {
close(input);
}
if (pfds[1] != -1) {
close(pfds[1]);
}
if (cmd->next != NULL) {
run_pipeline_sockets(cmd->next, pfds[0]);
} else {
return pfds[0];
}
}
}
void segfault_sigaction(int signal, siginfo_t *si, void *arg) {
printf("Caught segfault at address %p\n", si->si_addr);
printf("Caught segfault errno %p\n", si->si_errno);
exit(0);
}
void handle_segfault(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = segfault_sigaction;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
}
I would come at this problem from a very different angle: rather than coming up with a large data structure to manage the pipe tree, and using threads (where an io blockage in a process may block in its threads) I would use only processes.
I also fail to see how a 64K buffer is your bottleneck when you're only using a 1K buffer.
2 simple functions should guide this: (error handling omitted for brevity, and using a pseudocodey parsecmd() function which turns a space separated string into an argument vector)
int mkproc(char *cmd, int outfd)
{
Command c = parsecmd(cmd);
int pipeleft[2];
pipe(pipeleft);
if(!fork()){
close(pipeleft[1]);
dup2(pipeleft[0], 0);
dup2(outfd, 1);
execvp(c.name, c.argv);
}
close(pipeleft[0]);
return pipeleft[1];
}
Mkproc takes the fd it will write to, and returns what it will read from. This way chains are really easy to initalize:
int chain_in = mkproc("cat foo.txt", mkproc("sort", mkproc("wc -l", 1)));
the next is:
int mktree(char *cmd, int ofd0, ...)
{
int piperight[2];
pipe(piperight);
int cmdin = mkproc(cmd, piperight[1]);
close(piperight[1]);
if(!fork()){
uchar buf[4096];
int n;
while((n=read(piperight[0], buf, sizeof buf))>0){
va_list ap;
int fd;
va_start(ap, ofd0);
for(fd=ofd0; fd!=-1; fd=va_arg(ap, int)){
write(fd, buf, n);
}
va_end(ap);
}
}
return cmdin;
}
Between the two of these, it is very easy to construct trees of arbitrary complexity, as so:
int tree_in = mktree("cat foo.txt",
mktree("rot13",
mkproc("uniq", mkproc("wc -l", 1)),
mkproc("wc -l", open("out.txt", O_WRONLY)), -1),
mkproc("sort", 2), -1);
This would output a sorted foo.txt to stderr, the number of lines in rot13'd foo.txt to out.txt, and the number of non-duplicate lines of rot13'd foo.txt to stdout.