pipe not being read by subprocess? - c

I want to run node.js as a subprocess and feed it input. Using C, here is some sample code of mine that does that.
The issue I have is that although the subprocess's stdout is still directed to the terminal, I see nothing after having fed the subprocess stdin a print 'Hello World' line. Even if I fflush() the pipe, I see nothing on output. However, if I close the pipe's input, then the 'Hello World' appears on the terminal.
The subprocess seems to simply buffer - why is that?
I would like to eventually redirect the subprocess stdout to another pipe and read it
in from main().
int main(int argc, char* argv[]) {
int toNode[2];
pipe(toNode);
pid_t child_pid = fork();
if (child_pid == 0) { // child
// close write end
close(toNode[1]);
// connect read end to stdin
dup2(toNode[0], STDIN_FILENO);
// run node executable
char* arg_list[] = { "/usr/bin/node", NULL};
execvp(arg_list[0], arg_list);
fprintf(stderr, "process failed to start: %s\n", strerror(errno));
abort();
}
else { // parent
FILE* stream;
// close read end
close(toNode[0]);
// convert write fd to FILE object
stream = fdopen(toNode[1], "w");
fprintf(stream, "console.log('Hello World');\n");
fflush(stream);
//close(toNode[1]);
waitpid(child_pid, NULL, 0);
}
return 0; }

There's no problem with the pipe being read. The problem is that /usr/bin/node only invokes the REPL (read-eval-print loop), by default, if it detects that stdin is interactive. If you have a sufficiently recent version of nodejs, then you can provide the -i or --interactive command line flag, but that will do more than just execute each line as it is read; it also really will act as a console, including inserting ANSI colour sequences into the output and printing the value of each expression.
See this forum thread for more information.

Related

redirect unnamed pipe output to log file in c

i want to redirect the output of an unnamed pipe to an opened log file in c but i can't seem to make it happen, my code looks like this:
close(fildes[1]);
FILE * file = fopen(logfile, "w");
int fd = fileno(file);
if (fd == -1) {
bail_out(EXIT_FAILURE, strerror(errno));
}
/* if (dup2(fd, fildes[0]) == -1) {
bail_out(EXIT_FAILURE, strerror(errno));
} */
/* for testing purposes */
char reading_buf[3];
while(read(fildes[0], reading_buf, 3) > 0) {
write(fd, reading_buf, 1);
}
(void)wait(&status);
close(fildes[0]);
break;
the pipe gets filled, i've tested that with the while loop at the bottom. but when i comment out the dup2 call nothing gets redirected to the file. i think i don't fully understand dup2 and pipes.
Also: if i dup2 the reading end of the pipe and then close the original fildes[0], does the pipe get closed? or is it simply the FD that gets closed. not entirely should about that either..
To redirect output from a pipe to a file, somebody needs to read from the read end of the pipe and write to the file's file descriptor. It can't be done merely by duping the file descriptors.
For instance, say you have a pipe
int filedes[2];
pipe (filedes);
and a file
FILE *logfile = fopen (logfile_path, "w");
int logfd = fileno (logfile);
you could launch a child process to do the redirection using the cat command
int child = fork ();
if (child == 0) {
// close the write end of the pipe
close (filedes[1]);
// make STDOUT point to the log file
dup2 (logfd, STDOUT_FILENO);
// make STDIN point to the read end of the pipe
dup2 (filedes[0], STDIN_FILENO);
// launch cat
execlp ("cat", "cat", (char*) NULL);
// in case of error
exit (1);
}
Now, whatever is written to the write end of the pipe in the parent will be read by the child executing cat and written to the file.
// close the read end of the pipe, it's not needed in the parent
close (filedes[0]);
// write something
const char *msg = "Hello World!\n";
write (filedes[1], msg, strlen (msg));
// close the write end of the pipe, this will make the child read EOF
close (filedes[1]);
Don't forget to collect the zombie
wait (&status);
and close the file
fclose (logfile);
About your last question, when a file descriptor is duped there will be two of them pointing to the same underlying open file. So, when one of them is closed the file remains open for it can be accessed through other descriptor.
This is explained in the close man page:
If fd is the last file descriptor referring to the underlying open file
description (see open(2)), the resources associated with the open file
description are freed;

How to redirect stdout and stdin in a given file using argv in C

I want to redirect stdout and stdin in a specific file which would be given in argv array.
For instance when I enter a command like - ./shell ls > test
it should be redirected to the "test" file, now I am bit confuse because without writing any code it automatically redirects to that file, I want to do it manually, secondly, when I enter a command like- ./shell ls < test, the stdin should be redirected. I tried to find a file name and ">" or "<" sign using argv[argc-1] and argv[argc-2], but it seems that when I use ">" and a filename afterwards, the output prints(the arguments before ">" "<" sing) in that file instead of getting that name and a sign.
Basically, I am creating a shell command using execvp() and fork().
Here is my code, I am able to redirect stdout in a static file.
void call_system(char *argv[],int argc)
{
int pid;
int status=0;
signal(SIGCHLD, SIG_IGN);
int background;
/*two process are created*/
pid=fork();
background = 0;
if(pid<0)
{
fprintf(stderr,"unsuccessful fork /n");
exit(EXIT_SUCCESS);
}
else if(pid==0)
{
//system(argv[1]);
/*argument will be executed*/
freopen("CON","w",stdout);
char *bname;
char *path2 = strdup(*argv);
bname = basename(path2);
execvp(bname, argv);
fclose (stdout);
}
else if(pid>0)
{
/*it will wait untill the child process doesn't finish*/
//waitpid(pid,&status,0);
wait(&status);
//int tempid;
//tempid=waitpid(pid,&status,WNOHANG);
//while(tempid!= pid);// no blocking wait
if(!WIFEXITED(status) || WEXITSTATUS(status))
printf("error");
exit(EXIT_SUCCESS);
}
}
Try using dup() or dup2() or dup3().
The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused descriptor for the new descriptor.
File *fp=fopen(argv[1],"r");
int fd=fileno(fp);
dup2(fd,0); //dup2(fd,STDIN_FILENO) redirect file stream to input stream
scanf("%s",buff); //reading from file.
Similarly output can also be redirected.From manual these informations may be useful
On program startup, the integer file descriptors associated with the
streams stdin, stdout, and stderr are 0, 1, and 2, respectively. The
preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO
are defined with these values in <unistd.h>.
Suppose you want to redirect stdout to this file.
dup2(fd,1);//dup2(fd,STDOUT_FILENO)
printf("%s",buff); //this will write it to the file.
stdio redirection is handled by the shell, not the launched program. The relevant syscalls are pipe, open and dup2, the later of the two is used to redirect the stdio filedescriptors into the pipe or file to be read from or written to.

Redirecting stdout of a process

I am writing a toy version of SSH in C, so I need to redirect stdin, stdout and stderr of the server shell to the client shell (by using pipes and sockets). Right now I have redirected only stdout. If I send commands like ls, netstat, etc there are no problems, the client receives the right output.
But if I write a C program wich, for example, asks for an int n and prints the numbers between 1 and n, and call it through the client I get this behavior: the client doesn't receive the string with the request of n, but if I tape n on the server shell the client receives the request string and the numbers.
I have tried the same thing leaving stdout on the server shell and in this case it works correctly. I have tried to use fflush, fsync and setvbuf without solve it.
Another strange behavior is: if I call through the client the program httrack without redirecting stdout, the server shell shows the normal wizard wich asks for project name, url, etc.
But If I redirect stdout the client doesn't receive the wizard output, instead it receives the httrack help page.
This is the code that performs redirection. As you can see I used both system and execlp call, but the behavior is the same.
pipe(pipefd);
if(fork() > 0)
{
close(pipefd[1]);
*_result = fdopen(pipefd[0], "r");
return 0;
}
else
{
close(pipefd[0]);
close(1);
dup(pipefd[1]);
system(buf);
//execlp(buf, buf, NULL);
exit(0);
}
EDIT:
After this I call this function that reads the stream associated to the read end of the pipe and puts it on the socket. The other parameters are used by AES and log file.
sock_send encrypt the buffer and write it to the socket through sock_write. sock_write(_wsock, NULL, 0) only signals the end of the output. Anyway as I have pointed out before, the output of commands like ls etc. is ok.
void write_result(int _wsock, aes_context *_enc_ctx, unsigned char *_iv, FILE *_result, char *_ip_addr)
{
unsigned char buf[BUF_SIZE];
char lstr[MAX_LOG_LEN];
while(fgets(buf, BUF_SIZE * sizeof(char), _result) != NULL)
{
//li scrivo sulla socket
if(sock_send(_wsock, _enc_ctx, buf, strlen(buf) + 1, _iv) == -1)
{
sprintf(lstr, WRITE_SOCK_ERR, _ip_addr);
log_str(lstr);
close_connection(_wsock, _ip_addr);
}
}
sock_write(_wsock, NULL, 0);
fclose(_result);
}

C multiple pipes

I am trying to implement multiple pipes in C like
ls - al | less | wc
I have trouble with creating the pipeline. I have a loop that is supposed to create the processes and connect them with pipes:
for(i=0;i<num_cmds;i++){
create_commands(cmds[i]);
}
My create_commands() function looks like this
void create_commands (char cmd[MAX_CMD_LENGTH]) // Command be processed
{
int pipeid[2];
pipe(pipeid);
if (childpid = fork())
{
/* this is the parent process */
dup2(pipeid[1], 1); // dup2() the write end of the pipe to standard output.
close(pipeid[1]); // close() the write end of the pipe
//parse the command
parse_command(cmd, argvector);
// execute the command
execvp(argvector[0], argvector);
close(1); // close standard output
}
else
{
/* child process */
dup2( pipeid[0], 0); // the read end of the pipe to standard input
close( pipeid[0] ); // close() the read end of the pipe
}
}
But this doesn't work, I'm getting my stdin and stdout messed up.
Could anyone please point me to what I am doing wrong?
Thank you in advance!
The popen() function executes the command specified by the string command. It creates a pipe between the calling program and the executed command, and returns a pointer to a stream that can be used to either read from or write to the pipe.
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
int status;
int PATH_MAX = 1024;
char path[PATH_MAX];
fp = popen("ls -al | less | wc", "r");
if (fp == NULL)
/* Handle error */;
while (fgets(path, PATH_MAX, fp) != NULL)
printf("%s", path);
status = pclose(fp);
if (status == -1) {
/* Error reported by pclose() */
} else {
/* Use macros described under wait() to inspect `status' in order
to determine success/failure of command executed by popen() */
}
}
You can use a preset string to be called within popen(), you can also use your argv[] arguments to be piped in you'ld like.
popen() gives you a pipe, a FIFO First In First Out stream, and popen also feeds the STDOUT back to your program.
Here's the man page for popen():
http://linux.die.net/man/3/popen

C: How to redirect named pipe to stdin/out of child process

Basically I want to do in C (and without buffering) the same as this bash-script:
#!/bin/sh
cat ./fifo_in | myprogram > ./fifo_out
In other words I want to exec "myprogram" and redirect its stdin and stdout to two pipes which have been created previously.
Another program is feeding data into fifo_in and reading out of fifo_out.
Of course it would be easy to just read from ./fifo_in, buffer it in the parent and write to myprogram's stdin (and reverse for stdout and ./fifo_out) but I think there is probably a way to let "myprogram" read/write directly from/to the fifos without buffering in the parent process.
Edit:
Eugen's answer seems to be the correct one, but I cannot get it to work.
I use this function on the C-side, which seems correct to me:
pid_t execpipes(const char *wd, const char *command, const char *pipename)
{
char pipename_in[FALK_NAMESIZE];
char pipename_out[FALK_NAMESIZE];
strcpy(pipename_in, FALKPATH);
strcat(pipename_in, "/");
strcat(pipename_in, FALK_FIFO_PATH);
strcat(pipename_in, "/");
strncat(pipename_in, pipename, FALK_NAMESIZE-2);
strcpy(pipename_out, pipename_in);
strcat(pipename_out, "R");
pid_t pid;
pid = fork();
if (pid < 0)
{ //Error occured
perror("fork");
exit(1);
}
if (pid == 0)
{
chdir(wd);
d("execpipes: pipename_in=\"%s\"\n", pipename_in);
d(" pipename_out=\"%s\"\n", pipename_out);
freopen(pipename_in,"r",stdin);
freopen(pipename_out,"w",stdout);
d("execpipes: command=\"%s\"\n", command);
execl("/bin/sh", "sh", "-c", command, (char *)NULL); // using execv is probably faster
// Should never get here
perror("execl");
exit(1);
}
return pid;
}
I read and write the pipes from a PHP-script (only relevant part posted):
$pipe_in = fopen($fp.$pipename, "w");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000); // Program hangs here
The program is started correctly, receives the input via $pipe_in correctly, processes the data correctly and (because it ran fine for many months) I assume it puts out the data correctly to stdout, but when I try to read from $pipe_out, it hangs. I know that the pipes themselves are set up correctly because if I don't open $pipe_out, the program does not get any input - which makes sense because there is no reader for $pipe_out and therefore the pipeline is not complete. So I can open $pipe_out, but I cannot read anything from it, which is quite strange.
Edit2:
Program works now, thanks guys - For some reason the first pipe has to be closed before you can read from the second pipe:
$pipe_in = fopen($fp.$pipename, "w");
$pipe_out = fopen($fp.$pipename.'R', "r");
$DEBUG .= "Write to pipe_in\n";
$ret = fwrite($pipe_in, $in);
fclose($pipe_in);
$DEBUG .= "Read from pipe_out\n";
$atext = fread($pipe_out, 200000);
fclose($pipe_out);
unlink($fp.$pipename);
unlink($fp.$pipename.'R');
I'd write a small wrapper for myprogram, that does
freopen("./fifo_in","r",stdin)
freopen("./fifo_out","w",stdout)
(Ofcourse not with constant paths!), then execve myprogram
Korn shell supports coprocesses, which I think effectively does what you ask: read from a pipe and write to a pipe (which can be stdout and stdin of a C process)
http://www.dartmouth.edu/~rc/classes/ksh/coprocesses.html
How about
myprogram < ./fifo_in > ./fifo_out
?
As for getting rid of the buffering: Since your program directly reads/writes the pipes, the buffering shouldn't hurt you.
An important point is that the process which writes fifo_in should flush properly so you don't have to wait. The same goes for your output: As soon as a "work unit" is complete, flush your stdout which will make the data available to whoever reads the output pipe.
But you can't do anything in myprogram to make the writer of fifo_in flush its buffers.
[EDIT] To do this from C (without the help of a shell), use code like this:
- Put the names of the two pipes into local variables on the stack
- Call `fork()`. If that returns '0', then open the two fifos with `freopen()` [like Eugen suggested][1]
- Call `execve` to launch the real exec.
That's (in a nutshell) what the shell is doing when it runs commands. Make sure the parent process (the one where fork() returns a PID != 0) handles the signal SIGCHLD
Perhaps you are looking of a named pipe? For example:
mkfifo fifo_in
As a test stub for my_program.c, to read fifo_in via the buffered stdin:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char buf[80];
if (!freopen("./fifo_in", "r", stdin)) {
perror("freopen");
exit(EXIT_FAILURE);
}
while (!ferror(stdin)) {
while (fgets(buf, sizeof buf, stdin))
fputs(buf, stdout);
sleep(1);
}
return 0;
}
Then as a test for the writer, using the bash shell:
for x in {1..10}; do
echo $x
echo $x >> fifo_in
sleep 1
done
Notes:
I'd prefer to use unbuffered I/O.
The writer, at least on my machine, blocks until there is a reader.
The reader, in this sample, cannot tell when the writer is finished.

Resources