Redirect standard output to file - c

I have to modify this code. The child process should redirect standard output to text file.
I think that I should do sth with dup2 and exec but I don't know what.
I read this ref and also this.
But it didn't helped me, probably I'm doing sth wrong.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main ()
{
int fds[2];
pid_t pid;
/* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */
/* TODO add error handling for system calls like pipe, fork, etc. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
/* This is the child process. Close our copy of the write end of the file descriptor. */
close (fds[1]);
/* Connect the read end of the pipe to standard input. */
dup2 (fds[0], STDIN_FILENO);
/* Replace the child process with the "sort” program. */
execlp ("sort", "sort", NULL);
} else {
/* This is the parent process. */
FILE* stream;
/* Close our copy of the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object, and write to it. */
stream = fdopen (fds[1], "w");
fprintf (stream, "This is a test.\n");
fprintf (stream, "Hello, world.\n");
fprintf (stream, "My dog has fleas.\n");
fprintf (stream, "This program is great.\n");
fprintf (stream, "One fish, two fish.\n");
fflush (stream);
close (fds[1]);
/* Wait for the child process to finish. */
waitpid (pid, NULL, 0);
}
return 0;
}

what you have done with dup2 is connecting the parent's stdout to child's stdin, leaving the child's stdout without a redirection. so the childr would print sorted strings to stdout.
what you should do next is to open a textfile , and do a dup2 with it's stdout. such as something before execlp
int outfd=open("/tmp/output",O_WRONLY|O_TRUNC|O_CREAT,0600);
dup2(outfd,STDOUT_FILENO);
execlp ("sort", "sort", NULL);
you will also need to #include <fcntl.h> to have file flags.

Related

Communication between child and parent process through pipe in unix c

The program first creates a pipe, and then creates a child process of the current process
through fork().
Then each process closes the file descriptors that are not needed for the read
and write pipes.
The child process executes the ls -a command under the current path, and
writes the command execution output to the pipe by copying the pipe write descriptor fd[1]
to standard output; the parent process reads the pipe data and displays it through fd[0].
Every process in Linux is provided with three standard file descriptor including standard
input, output and error files.
By default:
Standard Input is the keyboard, abstracted as a file to make it easier to write shell
scripts.
Standard Output is the shell window or the terminal from which the script runs,
abstracted as a file to again make writing scripts & program easier
Standard error is the same as standard output: the shell window or terminal from
which the script runs.
A file descriptor is simply a number that refers to an open file. By default, file descriptor
0 (zero) refers to the standard input & often abbreviated as stdin.
File descriptor 1 refers
to standard output (stdout) and file descriptor 2 refers to standard error (stderr).
You can use dup(2) function to duplicate a file descriptor with the pipe write descriptor
fd[1] by using function dup2 in order to relocate the standard output
The issue is how can I execute the command and after that I read the stdout in the child
process.
I am executing it using exec function, the line after the exec function will not
execute because the child process memory image is now ls -l.
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE 25
#define READ_END 0
#define WRITE_END 1
int main(void)
{
char writemsg[BUFFER_SIZE] = "Greetings!";
char readmsg[BUFFER_SIZE];
int fd[2];
pid_t pid;
/* create the pipe */
if (pipe(fd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
if (pid > 0) { /* parent process */
/* close the unused end of the pipe */
close(fd[READ_END]);
/* write to the pipe */
write(fd[WRITE_END], writemsg, strlen(writemsg)+1);
/* close the write end of the pipe */
close(fd[WRITE_END]);
}
else { /* child process */
/* close the unused end of the pipe */
close(fd[WRITE_END]);
/* read from the pipe */
read(fd[READ_END], readmsg, BUFFER_SIZE);
printf("read %s\n",readmsg);
/* close the write end of the pipe */
close(fd[READ_END]);
}
return 0;
}
this code is working fine. this is the simple code of pipe communication. kindly help me to solve the command execution portion and writing it in child from console

How to use fork in C?

Here is the full code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
char *command, *infile, *outfile;
int wstatus;
command = argv[1];
infile = argv[2];
outfile = argv[3];
if (fork()) {
wait(&wstatus);
printf("Exit status: %d\n", WEXITSTATUS(wstatus));
}
else {
close(0);
open(infile, O_RDONLY);
close(1);
open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
execlp(command, command, NULL);
}
return 0;
}
This code should fork and exec a command with both stdin and stdout redirection, then wait for it to terminate and printf WEXITSTATUS(wstatus) received. e.g. ./allredir hexdump out_of_ls dump_file.
So, I understand everything before fork(). But I have the following questions:
As far as I understand, fork() clones the process, however I do not understand how it executes the command, because execlp should do that and code never reaches that part.
I do not get how execlp works. Why do we send a command to it twice (execlp(command, command, NULL);)?
How does execlp know where to redirect the output if we do not pass outfile nowhere.
Why do we even need an infile if the command is already passed as the other argument?
Thank you for your answers in advance.
As far as I understand, fork() clones the process, however I do not understand how it executes the command, because execlp should do that
and code never reaches that part.
Fork returns pid of child in parent space and 0 in new process space. The son process makes a call to execlp.
if (fork()) {
/* Parent process waits for child process */
}
else {
/* Son process */
execlp(command, command, NULL);
}
I do not get how execlp works. Why do we send a command to it twice
(execlp(command, command, NULL);)?
Read execlp man page and this thread
The first argument, by convention, should point to the filename
associated with the file being executed.
How does execlp know where to redirect the output if we do not pass outfile nowhere.
Redirection happens before by closing stdin and stdout file descriptors. And redirection happens by opening files which file descriptors will accommodate entries 0 and 1.
else {
/* redirecting stdin */
close(0);
open(infile, O_RDONLY);
/* redirecting stdout */
close(1);
open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0644);
execlp(command, command, NULL);
}
Why do we even need an infile if the command is already passed as the other argument?
We can't tell what your program does without seeing the argument passed as command.

Why child process is waiting while using fork and pipes for stdin from parent's output?

I understood how fork and pipes work but i have a doubt regarding the flow of the child and parent process.Since we are using fork the order of execution of parent and child process is undefined but why child process is waiting for stdin from parent process.What happens if child process executes first? it must print empty in console? but it is not happening can i know why?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main () {
int fds[2]; pid_t pid;
/* File descriptors for the two ends of the pipe are placed in fds. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
/* Child proces -. Close the write end of the file descriptor. */
close (fds[1]);
/* Connect the read end of the pipe to standard input. */
dup2 (fds[0], STDIN_FILENO);
/* Replace the child process with the “rev” program. */
execlp("rev", "rev", 0); }
else {
/* This is the parent process. */
FILE* stream;
/* Close the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object */
stream = fdopen (fds[1], "w");
fprintf (stream, ",ereh ot ereht morF\n");
fprintf (stream, ",ereht ot ereh dna\n");
fprintf (stream, ".erehwyreve era sgniht ynnuf\n");
fprintf (stream, "ssueS .rD - \n");
fflush (stream);
close (fds[1]);
/* Wait for the child process to finish. */
waitpid (pid, NULL, 0);
}
return 0;
}
You aren't closing enough file descriptors in the child.
Rule of thumb: If you
dup2()
one end of a pipe to standard input or standard output, close both of the
original file descriptors returned by
pipe()
as soon as possible.
In particular, you should close them before using any of the
exec*()
family of functions.
The rule also applies if you duplicate the descriptors with either
dup()
or
fcntl()
with F_DUPFD
In this case, the child needs to close fds[1] after duplicating it. Because it is still open, rev will never receive EOF because there is a process (the rev child process) that could, in theory, write to the input.
You should use fclose(stream) instead of close(fds[1]) because the output is buffered and fclose() knows to flush the buffers, but close() hasn't got a clue. However, by using fflush(stream) before the misguided close(), you do avoid problems.
That leads to:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int fds[2];
pid_t pid;
pipe(fds);
pid = fork();
if (pid == (pid_t)0)
{
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
close(fds[1]);
execlp("rev", "rev", 0);
}
else
{
FILE *stream;
close(fds[0]);
stream = fdopen(fds[1], "w");
fprintf(stream, ",ereh ot ereht morF\n");
fprintf(stream, ",ereht ot ereh dna\n");
fprintf(stream, ".erehwyreve era sgniht ynnuf\n");
fprintf(stream, "ssueS .rD - \n");
fclose(stream);
waitpid(pid, NULL, 0);
}
return 0;
}
which produces the output:
From there to here,
and here to there,
funny things are everywhere.
- Dr. Seuss

Unix : What happens to a pipe(half-duplex) if the process dies

I am trying to prove one of my doubts, that two non-related processes can share the fd of half-duplex pipe and have communication.
I have created two programs for that. But then I had this another question, that what happens to the pipe if process dies?Because my reader got some garbage message, when I printed out the message.
Writer
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd[2];
char str[] = "hello\n";
if(pipe(fd) < 0)
perror("Pipe creation failed\n");
//Since i am a writer, i should close the reading end as a best practice
close(fd[0]);
/*
The processes need not to be related processes, in order to use the half duplex pipes. fd is just a number/identifier
which can be shared across different processes
*/
printf("Hey there !!! use this file descriptor for reading : %d\n", fd[0]);
//writing message
write(fd[1],str,strlen(str)+1);
return 0;
}
Reader
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd,bytesRead;
char buffer[1024];
printf("please enter the fd :");
scanf("%d",&fd);
bytesRead = read(fd,buffer,1024);
printf("Bytes Read : %d\nMessage : %s\n", bytesRead, buffer);
return 0;
}
You can't do this.
The table of file descriptors is per-process; every process has its own separate set of open file descriptors (note the distinction between open file descriptors, which are per-process, and open file descriptions, which are system-wide, discussed in open(2)). If you want to share a file descriptor between processes, you need to either inherit it over a fork(2) or pass it through a unix(7) domain socket via sendmesg(2) with SCM_RIGHTS in the cmesg(3) header.
(On Linux, you can also pass around paths to /proc/[PID]/fd/..., and other systems may have their own non-portable equivalents).
What is happening in your case is that the read is failing (you're giving it a file descriptor which is not open), leaving your buffer with uninitialized garbage. Since you don't check the return value, you never know that it failed.
In pipe man page,
pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. The array pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe. Data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe.
The pipe is mainly used for the related process(parent and child). You are not able to use the pipe for non related process.
In related process, one end is closed. In other end process gets the SIGPIPE signal.
Example program using pipe :-
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
The above program creates a pipe, and then fork(2)s to create a child process; the child inherits a duplicate set of file descriptors that refer to the same pipe. After the fork(2), each process closes the descriptors that it doesn't need for the pipe (see pipe(7)). The parent then writes the string contained in the program's command-line argument to the pipe, and the child reads this string a byte at a time from the pipe and echoes it on standard output.

Open a cmd program with full functionality (i/o)

I tried popen() and it is working well for output with "r" passed as a second argument; I know you can use "w" as writing mode and it worked for me (the program was just one scanf()). My question is how to use the append ("a") mode. You can both write and read, how do you know when the program is outputting something and when it's requesting for user input?
popen uses a pipe (that's the "p" in "popen") and pipes are unidirectional. You can either read or write from one end of a pipe, not both. To get both read/write access you should use a socketpair instead. I use this in my programs when I want something like popen, but for read/write:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
FILE *sopen(const char *program)
{
int fds[2];
pid_t pid;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
return NULL;
switch(pid=vfork()) {
case -1: /* Error */
close(fds[0]);
close(fds[1]);
return NULL;
case 0: /* child */
close(fds[0]);
dup2(fds[1], 0);
dup2(fds[1], 1);
close(fds[1]);
execl("/bin/sh", "sh", "-c", program, NULL);
_exit(127);
}
/* parent */
close(fds[1]);
return fdopen(fds[0], "r+");
}
Note that since it doesn't return the child's pid, you'll have a a zombie process after the child program exits. (Unless you set up SIGCHLD...)

Resources