running pico using execvp after dup2 in C - c

What I want to do is basically make standard out of the child process write in the write end of the pipe using dup2 and run pico using execvp and the parent would read the read end of the file and do something with it and write it out in the standard out and display it in pico. This is run under a Linux machine.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc,char* argv[])
{
char* arguments[] = {"pico", "a.txt", NULL};
int my_pipe[2];
if(pipe(my_pipe)==-1)
fprintf(stderr,"Error\n");
pid_t child_id;
child_id = fork();
if(child_id == -1)
{
fprintf(stderr, "Fork error\n");
}
if(child_id==0)
{
close(my_pipe[0]);
dup2(my_pipe[1],1); /*make standard out write in the write end of the pipe?*/
close(my_pipe[1]);
execvp("pico",arguments);
fprintf(stderr, "Exec failed\n");
exit(0);
}
close(my_pipe[1]);
char reading_buf[1];
char r[] = "S";
while(read(my_pipe[0], reading_buf,1)>0)/*read something in the pipe*/
{
write(1,r,1);/*display "S" in pico*/
}
close(my_pipe[0]);
return 0;
} /* end main */
the problem I'm having is that when I try to do the write() in standard out, pico wouldnt show in the terminal and I got this weird output of continuous "S" (from r) like this:
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
and it would add more "S" 's whenever I try to press any key. I'm pretty new to all of this and any help would be appreciated.

I think I know what's going on here: because stdout is redirected to the pipe, when pico tries to print to stdout it's actually printing to the pipe and nothing shows up on the screen. You have to manually print to stdout in the parent. Try changing "write(1,r,1)" to "write(1, reading_buf, 1)" and pico will display normally.

Related

Unix redirect command programmatically

I'm writing a program where I want to redirect command to another process programmatically.
So if I receive the command as argument, I want to receive the output on the parent process.
My code is:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char* argv[]) {
{
char msg[8]=“message”;
int pp[2];
if(pipe(pp)<0) {
printf("Error pipe");
exit(1);
}
if (!fork())
{
close(fd[0]);
//TODO...
} else {
close(fd[1]);
read(fd[0], msg, 8);
close(fd[0]);
}
}
I'm lost about the child part, where I execute the command and do the redirection. I'm using pipe to communicate between child process and parent process.
On the child side, I've closed the pipe side not used, then I don't know how to continue.
Can you help?
The steps are the following:
close pipe-read and stdout
dup() pipe-write to redirect pipe-write to stdout with fd=1
close initial pipe-write
execute the command, reading from argv the first argument
Your code becomes like that:
if (!fork())
{
close(pp[0]);
close(1);
dup(pp[1]);
close(pp[1]);
execlp(argv[1], argv[1],(char *)0);
exit(0)
}

With vs without the C pipe() function- what's causing this behavior?

I wrote a simple script (taken from a tutorial) which writes data to one end of a pipe in a child process, and reads it from the other end of the pipe in the parent process:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int mypipefd[2];
int ret;
char buf[20];
ret = pipe(mypipefd);
if (ret == -1) {
printf("Pipe failed.\n");
exit(1);
}
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!";
write(mypipefd[1], msg, strlen(msg) + 1);
} else {
printf("Parent process.\n");
read(mypipefd[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This works fine and outputs the results I expect:
Parent process.
Child process.
Buf: Hello there!
[ project ] $
Then as I got more familiar with the code, I wondered why we need to use mypipefd[2] and pipe() to achieve this goal, or whether mypipefd[1] by itself would work. So I tried it out with the following code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int my_array[1];
char buf[20];
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!\n";
write(my_array[0], msg, strlen(msg) + 1);
} else {
// wait(NULL);
printf("Parent process.\n");
read(my_array[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This code outputs the same text, but it hangs after it finishes printing.
Parent process.
Child process.
Buf: Hello there!
No prompt, this time. I even tried un-commenting that call to wait(NULL), on the off-chance that the root cause was a conflict between parent and child processes. No such luck.
What's going on here? Why am I unable to read and write to a length-of-one array in this way without the program hanging? What exactly is the compiler stuck on?
A pipe, on computers as well as in real life, have two ends. And like pipes in real life, data flows from one end of the pipe (the write end) to the other (the read end).
The pipe function gives you those two ends by writing them to an array of two file-descriptors. The first element of the pair is read-only, and the second is write-only.
The pipe() function accepts an array of 2 integer as an input argument.
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
It then generates a new pipe object, and initializes the pipefd array with file descriptors for read and write operation.
What you try to do is call read() and write() using some arbitrary, uninitialized ints (or file descriptor). Meaning the OS did not allocate a pipe object and did not provide you with file descriptors (the pipe's API) to be use with read() and write().
This (calling read() or write() with uninitialized file descriptor) will result in "undefined behavior".
"I find that a good working definition of "undefined behaviur" is "works for me, works for you, works during development and QA, but blows up in your most important customer's face"" --- Scott Meyers

Redirection of stdin and stdout via pipes in C works for external programmes but not for recursive call

I am trying to communicate with forked child processes via pipe redirection of stdin and stdout in C. I already managed to get this to work for shell commands (like ls, for example) executed in child processes. However, I wasn't able to recursively execute the same program and redirect the output (printed by printf(), fprintf() to stdout, ...) via the pipes from the child process to the parent (in this test to stdout of the parent), although this works fine for ls or similar commands.
Here's how I tried to approach this:
I create a pipe, the reading end is for the parent, the child process should write to the writing end.
The Process forks, both processes close the unused end, respectively.
The writing end of the pipe is redirected to STDOUT_FILENO and closed
The child process executes the program recursively (it is called ./to2)
As mentioned, this does work if I execute ls in the child process, but not if I try to call the same program recursively. Here's my test program where I tried to get this to work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
static void usage(void){
fprintf(stderr,"RIP");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
if(argc > 1){
dprintf(STDOUT_FILENO,"Please work\n");
printf("\n THIS IS A MESSAGE FROM THE CHILD \n");
fputs("Pretty Please!\n",stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if(-1 == pipe(p1)) {
fprintf(stderr,"pipe\n");
fprintf(stderr,"%s\n",strerror(errno));
usage();
}
int f = fork();
if(f == 0){
close(p1[0]);
if(dup2(p1[1],STDOUT_FILENO) < 0){
fprintf(stderr,"dup2\n");
usage();
}
close(p1[1]);
//I want this to work:
//execlp("./to2", "./to2", "-e");
//This works fine:
execlp("ls", "ls");
exit(EXIT_SUCCESS);
} else if (f == -1) {
usage();
} else {
close(p1[1]);
int w = -1;
if(-1 == wait(&w)) usage();
char b[12];
memset(b,0,12);
read(p1[0],&b,12);
char reading_buf[1];
while(read(p1[0], reading_buf, 1) > 0){
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
}
}
For testing purposes, the function is called recursively with additional arguments, while the parent program is called without additional arguments (hence the if(argc>1)).
In the final program, endless recursion is being avoided by other means.
Did I understand something wrongly? I am pretty confused by the fact that the only thing that doesn't seem to work is redirecting the output of my own
program...
Thank you very much in advance, any help or ideas are greatly appreciated.
The primary problem is precisely as outlined in the comments — you are not calling execlp() correctly (nor ls in the alternative). You must make the last argument on those function calls into an explicit null pointer, as shown in this code, which is a mostly mildly edited version of what's in the question:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static void usage(void)
{
fprintf(stderr, "RIP\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
dprintf(STDOUT_FILENO, "Please work\n");
printf("THIS IS A MESSAGE FROM THE CHILD\n");
fputs("Pretty Please!\n", stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if (-1 == pipe(p1))
{
fprintf(stderr, "pipe: %s\n", strerror(errno));
usage();
}
int f = fork();
if (f == 0)
{
close(p1[0]);
if (dup2(p1[1], STDOUT_FILENO) < 0)
{
fprintf(stderr, "dup2: %s\n", strerror(errno));
usage();
}
close(p1[1]);
execlp(argv[0], argv[0], "-e", (char *)0);
fprintf(stderr, "failed to exec %s again\n", argv[0]);
exit(EXIT_FAILURE);
}
else if (f == -1)
{
usage();
}
else
{
close(p1[1]);
char b[13];
memset(b, 0, 13);
if (read(p1[0], &b, 12) < 0)
{
fprintf(stderr, "Failed to read from pipe (%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
int len = strcspn(b, "\n");
printf("M1 [%.*s]\n", len, b);
char reading_buf[1];
while (read(p1[0], reading_buf, 1) > 0)
{
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
int w = -1;
if (-1 == wait(&w))
usage();
}
return 0;
}
Two important changes should be highlighted:
This code echoes the first line of data — the one written by dprintf() — whereas the original code just read it and discarded it.
The wait() call is after the input, not before. If the child had more data to write than a set of fixed messages, it could block waiting for the parent to read some of the data, while the parent is blocked waiting for the child to exit. This would be a deadlock.
The usage() function is not appropriately named — it doesn't report how to run the program. I also exit with a failure status, not success, if the child process fails the execlp().
Under peculiar circumstances, the wait() call might report on the exit status from some child other than the one that was forked. It is generally best to use a loop to reap such children. However, the circumstances required are extremely peculiar — the process which launched the parent with an exec*() function must have previously created some children for which it didn't wait, so that they are inherited by the parent process (because the PID doesn't change across an exec*() call).

send up down arrow keys to process through pipe in linux using c language

I have created two processes using fork. Created a pipe. Parent will write keys at write end of pipe and child stdin(0) will be duplicated by read end of pipe. Up to know its working very well and good for alphabets.
But i want to send up and down arrow keys also, please help me.
int main()
{
int fd[2];
char enter = 10;
char *exit = "exit";
char up = 193;//what i have to use here
char down = 194;//what i have to use here
pipe(p);
if(fork())
{
write(p[1],&up,1); //not working
write(p[1],&down,1); //not working
write(p[1],exit,strlen(exit)); //working
write(p[1],&enter,1); //working
wait(NULL);
}
else
{
close(0);
dup(p[0]);
execl("/bin/sh","sh",NULL);
}
}
Please help me,
There are several points:
1.) You have to invoke a shell which supports terminal editing with arrows. On a usual Linux this may be /bin/bash instead of /bin/sh.
2.) bash is checking whether it's input is coming from a terminal device or not. Depending on this, it behaves like an interactive shell or not. It seems that you want to use it in interactive mode. However pipe is not a terminal device. To get it into interactive mode you can use bash option "-i" on its invocation.
3.) As pointed by commentaries, on a usual Linux X-terminal codes for arrow up and down are multi character strings like "\033[A" and "\033[B". It depends on the device and environment you are using, maybe your values are correct for your system.
The following code works on a usual Linux environment:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
int p[2];
char enter = 10;
char *exit = "exit";
char *up = "\033[A";
char *down = "\033[B";
pipe(p);
if(fork())
{
write(p[1],up,3);
write(p[1],down,3);
write(p[1],exit,strlen(exit));
write(p[1],&enter,1);
wait(NULL);
}
else
{
close(0);
dup(p[0]);
execl("/bin/bash","bash","-i",NULL);
}
}
Also, you shall test return values of pipe and fork. Personally I'd write it like:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
int p[2];
int r;
char command[] = "\033[A\033[Bexit\n";
r = pipe(p);
if (r < 0) {
perror("Can't create pipe");
return(-1);
}
r = fork();
if (r < 0) {
perror("Can't fork");
return(-1);
} else if (r > 0) {
close(p[0]);
write(p[1], command, sizeof(command)-1);
close(p[1]);
wait(NULL);
} else {
close(p[1]);
dup2(p[0], 0);
close(p[0]);
execl("/bin/bash","bash","-i",NULL);
}
}

Passing stdout to C program

I am trying to figure out piping in C by playing around with it. I want to write a program that takes the output from the shell command 'cat', saves it as a string, then prints that string. The command should look like this:
cat foo.txt | ./my_prog
I am having issues sending the output from the cat command to my_prog. Here is what I have tried so far.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int pipe_1[2];
pid_t pid = -1;
char catString[200];
catString [199] = '\0';
// dup stdout to pipe_1
if( dup2(STDOUT_FILENO, pipe_1[1]) == -1 ){
perror("Could not create pipe 1");
exit(-1);
}
// fork a new process
pid = fork();
switch(pid){
case -1:
perror("Fork 1 failed");
exit(-1);
case 0: // child
// close stdin and write stdout to the string
close(pipe_1[0]);
write(pipe_1[1], catString, 200);
break;
default: // parent
// wait for child process to finish, close stdout, then print the string
wait(NULL);
close(pipe_1[1]);
printf("Parent recieved %s\n", catString);
break;
}
return 0;
}
This doesn't print anything and gives me the output:
Parent recieved
On a side note, am I using the wait() function correctly? I wanted to make sure the child is done writing to catString before the parent process executed.
The shell will send the output of cat foo.txt to stdin of your program. You don't have to do anything with "pipes" inside your program, just accept the input in the way the shell delivers it.

Resources