Writing to file descriptor - c

In the following snippet i am redirecting the output of the ls command to input of wc -l which works perfectly .Now i also want to redirect the output of ls command to a file named "beejoutput.txt" using the following code but its not working. Need help.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int pfds[2];
pipe(pfds);
if (!fork())
{
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
}
else
{
FILE *outputO=fopen ("beejoutput.txt", "w"); //opening file for writing
dup2(pfds[0],0);
dup2(fileno(outputO),pfds[0]);
close(pfds[1]);
execlp("wc", "wc","-l", NULL);
}
return 0;
}

The dup function duplicates a file descriptor, that is, both the old and new file descriptors refer to the same open file afterwards. That is different from having a single file descriptor refer to two different files at the same time.
If you want to send the same data to two different destinations, you need to spawn both commands in separate processes, and do the copying yourself, or spawn a copy of the "tee" command -- either way, you end up with three processes.

This worked for me :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int pfds[2];
pipe(pfds);
pid_t childpid = fork();
if (childpid == 0) {
/* Child */
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
} else {
/* Parent */
pid_t retpid;
int child_stat;
while ((retpid = waitpid(childpid, &child_stat, 0)) != childpid && retpid != (pid_t) -1)
;
close(pfds[1]);
char buf[100];
ssize_t bytesread;
int fd = open("beejoutput.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
fprintf(stderr, "Opening of beejoutput.txt failed!\n");
exit(1);
}
/* This part writes to beejoutput.txt */
while ((bytesread = read(pfds[0], buf, 100)) > 0) {
write(fd, buf, bytesread);
}
lseek(fd, (off_t) 0, SEEK_SET);
dup2(fd, 0);
execlp("wc", "wc", "-l", NULL);
}
return 0;
}

Try checking the result codes of all the system calls that you do (including dup2). This will possibly lead you to an answer. This is a good habbit, anyway.

Related

redirect output of every process to a text file

hi im trying to redirect my standard output of every process to a seperate file.
i have tried however it doesn't seem to be working or i can only print the first process to a text file.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd[2];
pid_t pid2, pid1;
int file1 = open("output1.txt", O_CREAT|O_TRUNC |O_RDWR, 0664);
int file2 = open("output2.txt", O_RDWR | O_CREAT | O_TRUNC, 0664);
//fd1 write, fd0 read
if(pipe(fd) == -1)
{
return 1;
}
pid1 = fork();
if (pid1 < 0)
{
return 2;
}
if (pid1 == 0)
{
//child process 1
dup2(fd[1], 1);
close(fd[0]);
execlp("ls", "ls", "-l", NULL);
// close(fd[1]);
}
else
{
pid2 = fork();
if (pid2 < 0)
{
return 3;
}
close(fd[1]);
if (pid2 == 0)
{
char buf[100];
ssize_t bytesread;
// int file2 = open("output2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
close(fd[1]); //close write end
//child process 2
// use execvp
dup2(fd[0], STDIN_FILENO);
while ((bytesread = read(fd[0], buf, 100)) > 0) {
write(file1, buf, bytesread);
}
lseek(file1, (off_t) 0, SEEK_SET);
dup2(file1, 0);
execlp("grep", "grep", "extest", NULL);
// above code prints to text file.
}
}
close(fd[0]);
close(fd[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
return 0;
}
this is my code.
the pipe is supposed to run ls then grep will search for all results in the ls result.
i want ls (process 1) output to be directed to a text file which works called output1.txt then process 2 will be redirected to output2 but i cant figure out for to redirect p2.
any help will be greatly appreciated

Double pipe to save output to file in C

I have created something like "linux pipe" to redirect output from one program to another and it's working like a charm. But now I want to save final output to a file. On the internet I saw that I need to create double pipe, but everything I create is not working.
Here is my actual code of "pipe":
int pipes[2];
int pid;
pipe(pipes);
if(pid=fork()){
int fd = open("t.txt", O_CREAT | O_TRUNC | O_RDWR, 0644);
if (fd < 0) {
perror("open()");
exit(EXIT_FAILURE);
}
close(pipes[1]);
dup2(pipes[0],STDIN_FILENO);
execvp(sec_command[0],sec_command);
}
else{
close(pipes[0]);
dup2(pipes[1],STDOUT_FILENO);
execvp(first_command[0],first_command);
}
Thanks
No. You don't need to. You just need to do a second dup2 in the child process (which will be capturing its input from the pipe) to the file descriptor of the file you want the output to go. You haven't post a Minimal, Reproducible Example, and your code is wrong (it execs in the parent and child process) so i've tried to work a complete solution. Here it is:
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t
subcommand_to_file(
char **subcommand_args,
char *file)
{
int pipes[2];
pipe(pipes);
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return -1;
} else if (pid == 0) { /* child */
int fd = open(file,
O_CREAT | O_TRUNC | O_RDWR,
0666); /* permissions controled by umask */
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
close(pipes[1]); /* close output descriptor of pipe */
dup2(pipes[0], STDIN_FILENO); /* redirect input */
close(pipes[0]); /* not needed after dup2 */
dup2(fd, STDOUT_FILENO); /* rediect output */
close(fd); /* not needed after dup2 */
execvp(subcommand_args[0], subcommand_args);
perror("execvp");
exit(EXIT_FAILURE);
}
/* parent */
close(pipes[0]); /* close input descriptor of pipe */
dup2(pipes[1], STDOUT_FILENO);
close(pipes[1]); /* not needed, after dup */
return pid; /* so if you want to wait for the child */
}
int
main( int argc,
char **argv)
{
int opt;
char file[256];
/* default value for filename */
snprintf(file, sizeof file, "%s.out", argv[0]);
while ((opt = getopt(argc, argv, "f:")) != EOF) {
switch (opt) {
case 'f':
strncpy(file, optarg, sizeof file);
break;
}
}
argc -= optind;
argv += optind;
pid_t child = subcommand_to_file(argv, file);
if (child < 0) {
fprintf(stderr,
"subcommand_to_file: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
/* copy input to output to pass stdin to subprocess */
int c;
while((c = getchar()) != EOF) {
putchar(c);
}
close(STDOUT_FILENO);
wait(NULL);
fprintf(stderr, "%s terminated\n", argv[0]);
exit(EXIT_SUCCESS);
}
The above program is called as
$ a.out -f output_file command [args ...]
and will end when the command program is finished. Just try
$ a.out -f out.txt echo a b c
and you will get
$ cat out.txt
a b c
$ _

How to redirect stderr and stdout to the same file

I have a task to make both stderr and stdout to print to a file called "log.out". I"m not allowed to delete code lines, only to add them.
The stdout part was easy, I have just added close(1); and now it is working. But I have already spend a couple for hours trying to learn how to use the whole dup/dup1/dup2 technic but I"m just not able to make it work even after reading a lot about the subject in the internet.
It would be really nice if someone will show me what lines of code I need to add to make it work, and explain me how it works.
Thanks!
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h> // for fork, sleep etc.
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
void fork_son(char*, int);
void do_son();
int open_file(char*);
int
main()
{
fork_son("1st", 0);
fork_son("2nd", 1);
exit(0);
}
void fork_son(char* which, int need_file)
{
int pid;
int status;
if (need_file)
{
close(1); //close stdout
open_file("log.out");
}
// close and open files before forking
pid = fork();
if (pid <0)
{
fprintf(stderr,"process %d, Fork Failed... Exiting\n", getpid());
exit(1);
}
if (pid == 0)
do_son(which);
else
{
printf("waiting for %s son...", which);
wait(&status);
printf("%s son exited!\n", which);
}
return;
}
void do_son(char* which)
{
fprintf(stdout,"Hello from %s son!\n", which);
fprintf(stderr,"%s son: I'm going to exit\n", which);
exit(0);
}
int open_file(char* name)
{
int fd;
fd = open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
// check if open succeeded
if (fd <0)
{
fprintf(stderr, "ERROR: open \"%s\" failed (%d). Exiting\n", name, fd);
exit(2);
}
// if (fd != 1)
// {
// fprintf(stderr,"ERROR: open \"%s\" - fd is %d (expected 1). Exiting\n", name, fd);
// exit(3);
// }
printf("opened file %s, file descriptor is: %d\n",name, fd);
return(fd);
}
The way open works, it searches for free entry in file descriptor table. Where entries 0, 1 and 2 are reserved for stdin, stdout and stderr respectively.
stdin - 0
stdout - 1
stderr - 2
If you want to redirect stdout and stderr to log.out you could simply do the following:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
int fd = - 1;
fd = open("log.out", O_RDWR | O_CREAT);
dup2(fd, 1); // redirects stdout to log.out
dup2(fd, 2); // redirects stderr to log.out
/* Print to stderr and to stdout */
fprintf(stdout, "%s", "Hello world\n");
fprintf(stderr, "%s", "Stack overflow!\n");
return 0;
}
If you care about order, a call to fflush should follow fprintf as redirecting stdout to a file will not flush buffer on newlines.

Storing output of Linux command in named pipe

My goal is to take a command which is input by the user and execute it with a forked child process, but rather than have the child process print it to the screen, store the output in a named pipe and have the parent process display the output after the child process has completed.
I'm attempting to do so by using dup2() to redirect standard output to the named pipe I've made, but the child process simply prints the output of the command and when attempting to read from the pipe in the parent process, I get the following error:
Error reading from pipe: Bad file descriptor
I've searched for similar questions on this site but have only found solutions for using regular pipes to store the output of exec(), and I wasn't able to adapt those solutions to named pipes. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define CMDSIZE 50
#define BUFSIZE 5000
int main() {
char cmd[CMDSIZE], arg[CMDSIZE], buf[BUFSIZE];
int fd, n;
pid_t pid = fork();
if (pid < 0) {
perror("Error creating process");
return 1;
}
else if (pid == 0) {
printf("SHELL > ");
fgets(buf, BUFSIZE, stdin);
sscanf(buf, "%s %s", cmd, arg);
memset(buf, 0, BUFSIZE);
printf("Working on request...\n");
unlink("cmdpipe");
mkfifo("cmdpipe", 0777);
fd = open("cmdpipe", 0777);
dup2(fd, STDOUT_FILENO);
close(fd);
if (arg[0] == '\0')
execlp(cmd, cmd, NULL);
else
execlp(cmd, cmd, arg, NULL);
}
else {
wait(NULL);
printf("...Output ready! Displaying now.\n");
fd = open("cmdpipe", 0777);
if ((n = read(fd, buf, BUFSIZE)) < 0) {
perror("Error reading from pipe");
return n;
}
close(fd);
printf("%s\n", buf);
}
return 0;
}
Thanks.

execl() does not seem to read from stdin

I'm trying to reproduce this command in c language:
ls | wc > output.txt
So, to do that, I wrote the following program:
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
int main()
{
pid_t lsFork, wcFork;
int tube[2];
pipe(tube);
lsFork = fork();
if(lsFork == 0) // ls command
{
close(tube[0]);
dup2(tube[1], STDOUT_FILENO);
close(tube[1]);
if(execl("/usr/bin/ls", "ls", NULL) == -1)
perror("Cannot execute ls");
}
else
{
wcFork = fork();
if(wcFork == 0) // wc command
{
sleep(1);
int file = open("output.txt", O_WRONLY | O_CREAT);
if(file == -1)
perror("Cannot open output.txt");
close(tube[1]);
dup2(tube[0], STDIN_FILENO);
close(tube[0]);
dup2(file, STDOUT_FILENO);
close(file);
/*char buffer[BUFSIZ];
read(STDIN_FILENO, buffer, BUFSIZ);
write(STDOUT_FILENO, buffer, BUFSIZ);*/
if(execl("/usr/bin/wc", "wc", NULL) == -1)
perror("Cannot execute wc");
close(STDOUT_FILENO);
}
else // parent
{
int status;
waitpid(lsFork, &status, 0);
waitpid(wcFork, &status, 0);
}
}
return EXIT_SUCCESS;
}
But, the program does not exit. According to htop, the wc command is blocking the program. To understand this behaviour, I wrote a piece of code (the lines commented before execl()) and I don't understand what this works and not execl(). Am I forgetting something when calling this function?
The parent process still has the pipe open, so wc is waiting around in case the parent decides to write stuff (which wc would need to count).
Close both ends of the pipe in the parent too:
else // parent
{
int status;
close(tube[0]); // <---
close(tube[1]); // <---
waitpid(lsFork, &status, 0);
waitpid(wcFork, &status, 0);
}
Don't complicate things when you can do it easily..
Try the simpler code below & see if you can understand anything or not.
int main(){
int tube[2];
int fID;
pipe(tube);
if (fork() == 0){
// this is the child process
close(tube[0]); // reading end of the pipe
dup2(tube[1], 1); // stdout ---> pipe writing end
execlp("ls", "ls", NULL);
}else{
if (fork() == 0){
//umask(0022);
fID = open("sample.txt", O_WRONLY | O_CREAT, 0644);
close(tube[1]); // writing end of the pipe
dup2(tube[0], 0); // stdin ----> pipe reading end
dup2(fID, 1);
execlp("wc", "wc", NULL);
}
}
return 0;
}
Note If the purpose of the code is to solely implement the above mentioned piping, then you don't need to implement any waiting mechanisms. The OS will auto-kill all the zombie child, if any. Moreover execlp("wc", "wc", NULL); will auto block the program to end. Hence it will not exit early
You'll need to close the write end of the pipe in the parent too.

Resources