Why this code stalls when calling ./prog ls ls wc 1.txt? - c

when compiling this code and calling
./prog ls ls wc 1.txt
(supposed to be
(ls; ls) | wc > 1.txt
this code stalls and done right only after Control-d. What's the matter?
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int fd[2];
pipe(fd);
if (!fork()) {
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
if (!(fork())) {
execlp(argv[1], argv[1], NULL);
_exit(1);
}
wait(NULL);
if (!fork()) {
execlp(argv[2], argv[2], NULL);
_exit(1);
}
wait(NULL);
}
close(fd[1]);
wait(NULL);
if (!fork()) {
dup2(fd[0], 0);
close(fd[0]);
int ffd = open(argv[4], O_WRONLY | O_CREAT | O_TRUNC, 0600);
dup2(ffd, 1);
close(ffd);
execlp(argv[3], argv[3], NULL);
_exit(1);
}
close(fd[0]);
wait(NULL);
return 0;
}

You need to exit the program in the first child process, otherwise both the original process and the child execute the code at the bottom that runs wc reading from the pipe.
Or you can put all that code in an else block, so it doesn't run in the child process.
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
int fd[2];
pipe(fd);
if (!fork()) {
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
if (!(fork())) {
execlp(argv[1], argv[1], NULL);
_exit(1);
}
wait(NULL);
if (!fork()) {
execlp(argv[2], argv[2], NULL);
_exit(1);
}
wait(NULL);
} else {
close(fd[1]);
wait(NULL);
if (!fork()) {
dup2(fd[0], 0);
close(fd[0]);
int ffd = open(argv[4], O_WRONLY | O_CREAT | O_TRUNC, 0600);
dup2(ffd, 1);
close(ffd);
execlp(argv[3], argv[3], NULL);
_exit(1);
}
close(fd[0]);
wait(NULL);
return 0;
}
}

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

Trying to replicate basic bash pipe but i get a stdin: Input/output error

I am currently working on a university project to basically built my own simple shell. Everything is working great so far. The only thing giving me trouble is pipes. To make it easier for myself to figure out why they are not working as intended I wrote this little testing program where I try to replicate the bash behaviour of cat | ls. But i now sadly get this error cat: stdin: Input/output error and i really can't figure it out.
Here is my program:
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
extern char **environ;
char *argv1[] = {"cat",NULL};
char *argv2[] = {"ls",NULL};
int fd[2];
pid_t pid;
int ret;
pipe(fd);
pid = fork();
if (pid == 0)
{
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execve("/bin/cat", argv1, environ);
exit (0);
}
else if (pid > 0)
{
close(fd[1]);
dup2(fd[1], STDIN_FILENO);
execve("/bin/ls", argv2, environ);
waitpid(pid, &ret, 0);
}
return (0);
}
You want a pipe like:
ls | cat
But, you're setting this up like:
cat | ls
And, in your current code, for the ls side, you're doing:
close(fd[1]);
dup2(fd[1], STDIN_FILENO);
This is wrong for two reasons:
You're closing the wrong side of the pipe, so the dup2 gets a closed fd as its first argument
You're attaching the output side of the pipe to the command's input side
So, we need to reverse the pipe order and fix the closing.
Also, after doing dup2(X,...) we want to do close(X).
Also, note that doing waitpid _after execve will have no effect unless the execve fails.
Here is the refactored and working code:
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int
main(void)
{
extern char **environ;
char *argv_cat[] = { "cat", NULL };
char *argv_ls[] = { "ls", NULL };
int fd[2];
pid_t pid;
int ret;
pipe(fd);
pid = fork();
// we want:
// ls | cat
if (pid == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execve("/bin/cat", argv_cat, environ);
exit(0);
}
else if (pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execve("/bin/ls", argv_ls, environ);
waitpid(pid, &ret, 0);
}
return (0);
}
UPDATE:
waitpid after execve is pointless. –
William Pursell
Not quite. It reaps the [stuck] child process so that it doesn't become a child of the init/systemd process.
In the above example, I had forgotten to add a close(STDOUT_FILENO) before the waitpid to "release" the cat process.
Here is the adjusted code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
int opt_f;
int
main(int argc,char **argv)
{
extern char **environ;
char *argv_cat[] = { "cat", NULL };
char *argv_ls[] = { "ls", NULL };
int fd[2];
pid_t pid;
int status;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'f':
opt_f = ! opt_f;
break;
}
}
pipe(fd);
pid = fork();
// we want:
// ls | cat
if (pid == 0) {
if (opt_f)
fprintf(stderr,"cld: getpid=%d\n",getpid());
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execve("/bin/cat", argv_cat, environ);
exit(0);
}
else if (pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
const char *ls = opt_f ? "/bin/gooch" : "/bin/ls";
execve(ls, argv_ls, environ);
fprintf(stderr,"execve failure of '%s' -- %s\n",ls,strerror(errno));
// release other process (cat)
close(STDOUT_FILENO);
// reap the child
pid_t ret = waitpid(pid, &status, 0);
fprintf(stderr,"ret=%d pid=%d status=%8.8X\n",ret,pid,status);
}
return (0);
}

Pipe & Fork Problem, output is in sorted order

I have a program that is supposed to create a child process and run the ls command. The output of this command should be piped to the parent process where it is printed to the screen.
The problem is that the parent process receives the output of the child in sorted order. After 2 days of working on it, I still have no clue why it is doing this.
This is my code:
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
int main(){
int Pipe1[2];
int pid, numread;
char buf;
pipe(Pipe1);
pid = fork();
if(pid == 0){
close(Pipe1[0]);
dup2(Pipe1[1], STDOUT_FILENO);
close(Pipe1[1]);
execl("/bin/ls", "ls", NULL);
}
else{
close(Pipe1[1]);
dup2(Pipe1[0], STDIN_FILENO);
close(Pipe1[0]);
while(1){
numread = read(STDIN_FILENO, &buf, 1);
if(numread > 0)
fprintf(stderr, "%c", buf);
else break;
}
close(STDOUT_FILENO);
wait(NULL);
}
}
This is the expected output:
a.out tk-quiz-01-ptr-trace.pdf tk-quiz-02c-prog-image-static.pdf tk-quiz-04-cpu-schedule.pdf
quiz7.c tk-quiz-02b-cl-allocate.pdf tk-quiz-03-unix-process.pdf tk-quiz-05-cpu-sch-link-list.pdf
This is the actual output:
a.out
quiz7.c
tk-quiz-01-ptr-trace.pdf
tk-quiz-02b-cl-allocate.pdf
tk-quiz-02c-prog-image-static.pdf
tk-quiz-03-unix-process.pdf
tk-quiz-04-cpu-schedule.pdf
tk-quiz-05-cpu-sch-link-list.pdf

I want an existing program work for two external processes as a child

I have a program that pipes two child processes. But I want these two processes (child) as external independent C program.
I want to connect the output of first process to input of a pipe and connect the input of second process as output of first pipe
Basically I want a program that works like this command in unix:
./myprogram prog1 | prog2
This is the code:
As I am a beginner, I took return value of prog1 and dup2 the output to the Standard Input of pipe and gave value to of the standard output to prog2 and tried to connect in prog2 program through dup2.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
printf("%s \n", argv[1]);
printf("%s \n", argv[2]);
int pipefd[2], status, done = 0;
int cpid;
pipe(pipefd);
cpid = fork();
if (cpid == 0) {
// Child 1 - Process 1
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
execlp(argv[1], argv[1], (char *)NULL);
}
cpid = fork();
if (cpid == 0) {
// Child 2 - Process 2
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
execlp(argv[2], argv[2], (char *)NULL);
}
close(pipefd[0]);
close(pipefd[1]);
waitpid(-1, &status, 0);
waitpid(-1, &status, 0);
return (0);
}

Pipe two shell commands in C

I'm trying to execute grep -o colour colourfile.txt | wc -w > newfile.txt through a program in C, instead of using the command line.
This is what I have so far:
#include <stdlib.h>
#include <unistd.h>
int main (void) {
int fd[2];
pipe(fd);
if (fork()) {
// Child process
dup2(fd[0], 0); // wc reads from the pipe
close(fd[0]);
close(fd[1]);
execlp("wc", "wc", "-w", ">", "newfile.txt", NULL);
} else {
// Parent process
dup2(fd[1], 1); // grep writes to the pipe
close(fd[0]);
close(fd[1]);
execlp("grep", "grep", "-o", "colour", "colourfile.txt", NULL);
}
exit(EXIT_FAILURE);
}
if (fork()) { means parent process not child process, see http://man7.org/linux/man-pages/man2/fork.2.html
You should handle > like | use open()
The following code could work:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main (void) {
int pipefd[2];
pipe(pipefd);
if (fork()) {
// Child process
dup2(pipefd[0], 0); // wc reads from the pipe
close(pipefd[0]);
close(pipefd[1]);
int fd = open("newfile.txt", O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
dup2(fd, 1);
close(fd);
execlp("wc", "wc", "-w", NULL);
} else {
// Parent process
dup2(pipefd[1], 1); // grep writes to the pipe
close(pipefd[0]);
close(pipefd[1]);
execlp("grep", "grep", "-o", "colour", "colourfile.txt", NULL);
}
exit(EXIT_FAILURE);
}

Resources