I was implementing a custom shell in C which required me to implement simple commands like echo,ls etc and input/output redirection.My project is done but when I was searching for some tips I found that there is a book which asked for a custom shell to support a single pipe so I tried to code that.First of all I tried to make a pipe in a normal c program to make sure that I can implement pipes.I was able to do it but somehow I have difficulties in doing it in my custom shell.
int mypipe[2];
if (pipe(mypipe) == -1) {
perror("Pipe failed");
exit(1);
}
firstchild=fork();
if (firstchild == 0) { // first child
close(mypipe[1]); //Closing the output of pipe
read1 = read(mypipe[0], buffer, sizeof(buffer));
printf(" %s\n", buffer);
myDate(child1, child2, result);
write(mypipe2[1], result, strlen(result)+1);
} else {
secondchild=fork(); //Creating second child
if(secondchild == 0) { //2nd child
read1 = read(mypipe2[0], buffer, sizeof(buffer));
printf(" %s\n", buffer);
I believe this code is correct since I could send time from child1 to child 2 and print it with child 2 but I cannot apply the same concept to my own shell where there is a parent who is waiting for child to terminate.And there are so many execv in my code which confuses me about what will happen in the future.And I only created one child process in my custom shell so I believe I need to create another which again is another problem for me since it will be hard for me to synchronize it with exec vs.Here is a small part of my own shell.
}if(!strcmp(args[0] ,"clear")){
execv("/usr/bin/clear",args);
}if(!strcmp(args[0] ,"env")){
execv("/usr/bin/env",args);
}
perror("Error");
exit(1); //Failure
}else{
do{
waitpid(child,&status,WUNTRACED);
}while(!WIFEXITED(status) && !WIFSIGNALED(status));
As you can guess else statement is coming from if(child=0).I would be really glad if someone can show me how to support a single pipe in a structure like this.My ultimate purpose is trying to support multiple pipes but I think I can figure it out myself when I see a single pipe
Related
I want to communicate with a child process like the following:
int main(int argc, char *argv[])
{
int bak, temp;
int fd[2];
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[0]);
dup2(STDOUT_FILENO, fd[1]);
fflush(stdout);
bak = dup(1);
temp = open("/dev/null", O_WRONLY);
dup2(temp, 1);
close(temp );
Mat frame;
std::vector<uchar> buf;
namedWindow( "Camera", WINDOW_AUTOSIZE );
VideoCapture cam(0 + CAP_V4L);
sleep(1);
if (!cam.isOpened())
{
cout << "\nCould not open reference " << 0 << endl;
return -1;
}
for (int i=0; i<30; i++)
{
cam>>frame;
}
//cout<<"\nCamera initialized\n";
/*Set the normal STDOUT back*/
fflush(stdout);
dup2(bak, 1);
close(bak);
imencode(".png",frame, buf);
cout<<buf.size()<<endl;
ssize_t written= 0;
size_t s = 128;
while (written<buf.size())
{
written += write(fd[1], buf.size()+written, s);
}
cout<<'\0';
return 0;
}
The process corresponding to the compilation of the source code above is called from the parent with popen.
Note that I am writing to the std out that has been duplicated with a pipe.
The parent will read the data and resend them to UDP socket.
If I do something like this:
#define BUFLEN 128
FILE *fp;
char buf[BUFLEN];
if ((fp = popen("path/to/exec", "r")) != NULL)
{
while((fgets(buf, BUFLEN, fp)!=NULL))
{
sendto(sockfd, buf, strlen(buf),0, addr, alen);
}
}
the program is working i.e. the receiver of sendto will receive the data.
I tried to use a pipe as done in the child process:
int fd[2];
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[1]);
dup2(STDIN_FILENO, fd[0]);
if ((fp = popen("path/to/exec", "r")) != NULL)
{
while((read(fd[0], buf, BUFLEN) > 0)
{
sendto(sockfd, buf, strlen(buf),0, addr, alen);
}
}
but with this are not sent.
So how to use pipe in this case to achieve the same behaviour of the first case? Should I do dup2(STDIN_FILENO, fd[0]); or dup2(STDOUT_FILENO, fd[0]);?
I am using the sandard(s) since the file descriptors are inherited by the child process so should not require any other effort. That is why I thought I can use pipe but is that so?
In the parent:
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[0]);
you get a pipe, and then immediately close one end of it. This pipe is now useless, because no-one will ever be able to recover the closed end, and so no data can flow through it. You have converted a pipe into a hollow cylinder sealed at one end.
Then in the child:
if (pipe(fd) < 0)
{
// pipe error
exit(1);
}
close(fd[1]);
you create another unrelated pipe, and seal this at the other end. The two pipes are not connected, and now you have two separate hollow cyclinders, each sealed at one end. Nothing can flow through either of them.
If putting something in the first cylinder made it appear in the other, that'd be a pretty good magic trick. Without sleight of hand or cleverly arranged mirrors, the solution is to create one pipe, keep both ends open and push data through it.
The usual way to manually set up a pipe from which a parent process can read a child process's standard output has these general steps:
parent creates a pipe by calling pipe()
parent fork()s
parent closes (clarification: its copy of) the write end of the pipe
child dupes the write end of the pipe onto its standard output via dup2()
child closes the original file descriptor for the write end of the pipe
(optional) child closes (clarification: its copy of) the read end of the pipe
child execs the desired command, or else performs the wanted work directly
The parent can then read the child's output from the read end of the pipe.
The popen() function does all of that for you, plus wraps the parent's pipe end in a FILE. Of course, it can and will set up a pipe going in the opposite direction instead if that's what the caller requests.
You need to understand and appreciate that in the procedural scheme presented above, it is important which actions are performed by which process, and in what order relative to other actions in the same process. In particular, the parent must not close the write end of the pipe before the child is launched, because that renders the pipe useless. The child inherits the one-end-closed pipe, through which no data can be conveyed.
With respect to your latter example, note also that redirecting the standard input to the read end of the pipe is not part of the process for either parent or child. The fact that your pipe is half-closed, so that nothing can ever be read from it anyway, is just icing on the cake. Moreover, the parent clobbers its own standard input this way. That's not necessarily wrong, but the parent does not even rely on it.
Overall, however, there is a bigger picture that you seem not to appreciate. Even if you performed the redirection you seem to want in the parent, so that it could be inherited by the child, popen() performs its own redirection to a pipe of its own creation. The FILE * it returns is the means by which you can read the child's output. No previous output redirection you may have performed is relevant (clarification: of the child's standard output).
In principle, an approach similar to yours could be used to create a second redirection going the other way, but at that point the convenience factor of popen() is totally lost. It would be better go take the direct pipe / fork / dup2 / exec route all the way through if you want to redirect the child's input and output.
Applying all that to your first example, you have to appreciate that although a process can redirect its own standard streams, it cannot establish a pipe to its parent process that way. The parent needs to provide the pipe, else it has no knowledge of it. And when a process dupes one file descriptor onto another, that replaces the original with the new, closing the original if it is open. It does not redefine the original. And of course, in this case, too, a pipe is useless once either end is no longer open anywhere.
I am trying to write a simple shell in c. Right now I'm trying to get pipes to work. I have a struct c which I'm feeding into this function, it contains a place to store the pipe file descriptor pipfd and also contains information about the ending tag of each command c->type (this can be | || && & etc). CommandPrev is just tracking the last command so I can see if the command immediately before had a pipe tag.
After I finish this function, I give the child pid (the return value) to waitpid to wait on the command I called with execvp
When I run commands such as echo foo | echo bar I get bar as an output exactly as I would expect and everything works great. My problem is when I try to run any command that actually uses the input from the first half of the pipe, everything gets stuck. If I run something like echo foo | wc -c I get no output and it just hangs forever.
I can see that this function finishes for these sort of commands because I print when it returns. What's happening is that the command that I'm calling with execvp is never happening so my waitpid waits forever.
I think that somehow my connection between the two ends of my pipe is broken. Either things are never getting written, or they're never being read, or the receiving end of the pipe never realizes that the writing side is finished and is just waiting forever. I call close immediately on all my pipes so I tend to doubt its the last one... but I'm really not sure how to go about testing any of these three scenarios.
This is my code:
pid_t start_command(command* c, pid_t pgid) {
(void) pgid;
// If its a pipe token, create a shared pipe descriptor
if (c->type == TOKEN_PIPE){
pipe(c->pipefd);
}
// Fork a child process, run the command using `execvp`
pid_t child = fork();
if (child == 0) {
// writing side of the pipe
if (c->type == TOKEN_PIPE){
dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);
close(c->pipefd);
}
// receiving side of the pipe
else if (commandPrev->type == TOKEN_PIPE){
dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);
close(commandPrev->pipefd);
}
// run the command
if (execvp(c->argv[0], c->argv) == -1) {
// fork failed
exit(-1);
}
}
else{
// clean up, clean up, everybody, everywhere
if (commandPrev->type == TOKEN_PIPE){
close(commandPrev->pipefd);
}
}
printf("return %i\n", getpid() );
return child;
}
Thank you!
As the other commenter says, you look like you're trying to close an array.
Something like this should work better:
// writing side of the pipe
if (c->type == TOKEN_PIPE){
close(c->pipefd[READ_SIDE]);
dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);
close(c->pipefd[WRITE_SIDE]);
}
// receiving side of the pipe
if (commandPrev->type == TOKEN_PIPE){
close(commandPrev->pipefd[WRITE_SIDE]);
dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);
close(commandPrev->pipefd[READ_SIDE]);
}
Alternatively, you can close the active sides of the pipe after a waitpid call in the parent. Something like this:
waitpid(child, &status, 0);
if (commandPrev->type == TOKEN_PIPE){
close(commandPrev->pipefd[READ_SIDE]);
}
if (c->type == TOKEN_PIPE){
close(c->pipefd[WRITE_SIDE]);
}
I'm trying to write a simple shell that can handle pipe commands. I want to be able to handle multiple pipes all chained together but I'm having a hard time figuring out how to implement something like this.
This is my current attempt:
int status;
int lastToken = 0;
int pipe_pid;
//create the pipes
int pipefd[pipes][2];
// Loop to run all commands in the vertical list.
while(1){
if (c->type == TOKEN_PIPE){
// Here is where we deal with pipes
for (int i = 0; i < pipes; i++){
pipe(pipefd[i]);
pipe_pid = fork();
//this is a receiving pipe
if (pipe_pid == 0){
// create the write end of the pipe
dup2(pipefd[i][WRITE_SIDE], STDOUT_FILENO);
close(pipefd[i][READ_SIDE]);
close(pipefd[i][WRITE_SIDE]);
execvp(c->argv[0], c->argv);
// printf("parent pipe\n");
}
//this is a writing pipe
else{
close(pipefd[i][WRITE_SIDE]);
dup2(pipefd[i][READ_SIDE], STDIN_FILENO);
close(pipefd[i][READ_SIDE]);
// printf("child pipe\n");
}
}
// This stuff happens for all commands
lastToken = c->type;
// If it's the last command, we're done
if (c->next == NULL){
break;
}
else{
c = c->next;
}
}
the commands are chained together in a linked list, c is my command pointer
pipes is a variable that I create as I parse the in-string, so I know how many '|' I saw in the command. This should tell me the number of child processes I need to fork.
I use pipes to create a 2d array for the pipe descriptors.
Then I want to loop over the pipes and fork once for each, and use dup2 to map the inputs and outputs.
I'm getting inconsistent errors that I can't figure out. First of all, every time I run a pipe command, my shell immediately crashes with no segfault or other printed errors.
Second, if I run commands like echo foo | wc -c I sometimes get 4 and sometimes get 0 as the output.
I'm sure I'm just doing something dumb but I'm not sure what :/
I figured out what I was doing wrong, I was closing the pipes before all the threads were finished using them. I fixed it by pulling out the close calls.
// writing side of the pipe
if (c->type == TOKEN_PIPE){
close(c->pipefd[READ_SIDE]);
dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);
}
// receiving side of the pipe
if (commandPrev->type == TOKEN_PIPE){
close(commandPrev->pipefd[WRITE_SIDE]);
dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);
}
And then in the parent thread, right before I reep my zombies, I check for pipes that are finished being used and close them.
// writing side of the pipe
if (c->type == TOKEN_PIPE){
close(c->pipefd[READ_SIDE]);
dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO);
}
// receiving side of the pipe
if (commandPrev->type == TOKEN_PIPE){
close(commandPrev->pipefd[WRITE_SIDE]);
dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO);
close(commandPrev->pipefd[READ_SIDE]);
I'm not sure if this is the optimal way to do it but it works without errors for me.
I'm new to piping and have been trying to create a pair of pipes which allow a child process to write to the parent process, and the parent process to communicate back. There is 1 parent with up to 4 children. The child becomes a different program with exec.
What I have working:
Writing from the parent to the child process. When I read in the child program's stdin, it will receive what I wrote from the parent.
The aim:
To create a card game where the parent talks to each individual client (the child processes) and gives all the moves and information to them, from its stdout to the children's stdin. The individual child processes give back their moves on their stdout, read by the main parent. The moves that the game makes is fully decided by a sequence, not players. So it's a bot game.
What I am stuck with:
I'm not sure how to get it so the parent can read the child's stdout through a file stream. When I try to setup the reading from child lines, the code seems to stop working. Not even the child can read from parent (it seems to stop at the now commented out liens for setting up child to parent).
I also am unsure how to "wait" until something appears. Like, at the start the players have to send a "ready" message back to the parent to let them know they are working. Once I send the "ready" from the child, how do I "wait" indefinitely until the next message appears?
I'm not sure if I'm setting up the pipes correctly. Can someone provide guidance on how to use communication pipes and confirm my logic below?
What I gather for getting parent to write to child is:
Create the pipe first
Fork off the parent process into another process (child)
Connect the pipe's in to the parent's stdout, and close off the reading side for the parent using dup2 and close
Connect the pipe's out to the child's stdin, and close off the writing part for the child using dup2 and close
Get a file stream using fdopen() from the file descriptor and then print to that.
The child process stdin is now whatever you print to stdout from the parent.
Is this correct? I tried applying this kind of logic for child to parent but reversing it.
Connect the in pipe to the read file stream, which is where the child program writes to from its stdout.
Connect the out pipe to the read stream, where the parent reads from.
void start_child_process(Game *game, int position) {
int child2Parent[2];
int parent2Child[2];
if (pipe(parent2Child)) {
printf("PIPE FAIL!\n");
}
if (pipe(child2Parent)) {
printf("PIPE FAIL!\n");
}
pid_t pid = fork();
game->readStream[position] = fdopen(child2Parent[0], "r");
game->writeStream[position] = fdopen(parent2Child[1], "w");
if (pid) { // Parent
// Write from parent to child
close(parent2Child[0]);
dup2(fileno(game->writeStream[position]), STDOUT_FILENO);
fprintf(game->writeStream[position], "%s", "test message");
fflush(game->writeStream[position]);
close(parent2Child[1]);
// Read from child -- not working
/*dup2(child2Parent[0], STDIN_FILENO);
close(child2Parent[0]);
close(child2Parent[1]);
*/
} else {
// Setup child to read from stdin from parent
dup2(parent2Child[0], STDIN_FILENO);
close(parent2Child[1]);
// Setup writing from child to parent
/*
if (dup2(child2Parent[1], STDOUT_FILENO) == -1) {
fprintf(stderr, "dup2 in child failed\n");
} else {
fprintf(stderr, "dup2 in child successful\n");
close(child2Parent[0]);
close(child2Parent[1]);
}
*/
if ((int)execl("child", "2", "A", NULL) == -1) {
printf("Failed child process\n");
}
}
}
My child main has the following which reads it:
char string[100];
printf("reading from pipe: %s\n", fgets(string, 100, stdin));
But I'm not sure how
Also, I'm not permitted to use popen() or write(). I'm also encouraged to use file streams apparently.
I speak principally to your main question of establishing two-way communication between parent and child processes. If you would like additional answers then please pose separate questions.
You seem to have a reasonable general approach, but you do have one serious misconception / design flaw: whereas it is reasonable for multiple clients to each connect their standard streams to pipes for communicating with the parent process, you cannot connect the parent's end of all those pipes to the parent's standard streams if you want to be able to handle more than one client at a time. The parent only has one set of standard streams, after all. To support multiple clients, then, the parent process must maintain a separate pair of file descriptors and/or streams for each one, and must communicate via those instead of via its standard streams.
I am uncertain why your parent / child communication is failing when you hook up the child-to-parent direction. The process is indeed analogous to setting up the other other endpoint. Here is a working example:
parent.c:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int main() {
int child2Parent[2];
int parent2Child[2];
char buffer[256];
FILE *p2cStream;
FILE *c2pStream;
pid_t pid;
if (pipe(parent2Child) || pipe(child2Parent)) {
perror("Failed to create pipes");
exit(EXIT_FAILURE);
}
switch (pid = fork()) {
case -1: /* error */
perror("Failed to fork");
break;
case 0: /* child */
// Setup child to read from stdin from parent
close(parent2Child[1]); /* ignoring any error */
close(child2Parent[0]); /* ignoring any error */
if ((dup2(parent2Child[0], STDIN_FILENO) < 0)
|| (dup2(child2Parent[1], STDOUT_FILENO) < 0)) {
perror("Failed to duplicate file descriptors");
} else {
/* conventionally, the first program argument is the program name */
/* also, execl() returns only if it fails */
execl("child", "child", "2", "A", NULL);
perror("Failed to exec child process");
}
exit(EXIT_FAILURE);
break;
default: /* parent */
close(parent2Child[0]); /* ignoring any error */
close(child2Parent[1]); /* ignoring any error */
if (!(p2cStream = fdopen(parent2Child[1], "w"))
|| !(c2pStream = fdopen(child2Parent[0], "r"))) {
perror("Failed to open streams");
exit(EXIT_FAILURE);
}
if ((fprintf(p2cStream, "test message from parent\n") < 0)
|| fclose(p2cStream)) {
perror("Failed to write to the child");
exit(EXIT_FAILURE);
}
if (fscanf(c2pStream, "%255[^\n]", buffer) < 1) {
perror("Failed to read the child's message");
exit(EXIT_FAILURE);
}
printf("The child responds: '%s'\n", buffer); /* ignoring any error */
break;
}
return EXIT_SUCCESS;
}
child.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
char buffer[256] = { 0 };
if (scanf("%255[^\n]", buffer) < 0) {
perror("Failed to reading input");
exit(EXIT_FAILURE);
}
/*
* If stdout is connected to the parent then we must avoid
* writing anything unexpected to it
*/
if (fprintf(stderr, "received: '%s'\n", buffer) < 0) {
perror("Failed to echo input");
exit(EXIT_FAILURE);
}
printf("Hi, Mom!\n"); /* ignoring any error */
fflush(stdout); /* ignoring any error */
return EXIT_SUCCESS;
}
In contrast to your code, do note
the attention to checking all return values that may signal an error that I care about;
the parent's use of streams other than the standard streams for communicating with the child (though with only one child, that's a convenience rather than a necessity);
the convention for execl() arguments.
Note also that as for waiting for something to "appear", I/O operations on the IPC streams you set up this way will automatically produce that effect. How you can or should make use of that, however, is certainly a different issue.
i ve searched quite a lot already and am aware that maybe i already came across some helpful answers but were unable to understand them...not really much of a programmer i am: )
the case is i would like to implement a daemon - background process totally independent of what is happening in the meantime - to parse data which are being received from the server (am writing IRC client) but to do it in non-blocking way using select().
Here s fragment of my code.
But i cant get to printf under the comment //rest of the program
i hope it s understandable enough.
pID=fork();
if(pID < 0){
//failed to execute fork()
perror("Error while forking");
getchar();getchar();
exit(1);
}
if(pID > 0){
exit(0);
}
//child down here
umask(0);
//setting new session
sID = setpgid(0,0);
if(sID < 0){
perror("Error while setting new session");
getchar();getchar();
exit(1);
}
while(1){
sleep(1);
if((readReady = readReadiness(sockfd))==0)
continue;
else{
//here am going to recv() data from server
printf("I am child and parsing\n"); //testing if its in background -i would like it not to print to stdout (run in background)
}
}
//rest of the program down here
printf("Why isnt it printing to stdout ??\n");
should i use grandchild ? (double forking ?)
or... ?
Thanks in advance
My comment above was neither answer nor suggestion; it was a question.
I don't see why you need to fork again - you have a process without a controlling terminal (thanks to setpgid) as you desire. You can process received data in the while(1) loop. Looks like you are set to go - the 'rest of the program' goes in the while loop.
EDIT
Calling fork creates a child copy of the running process. Calling setsid in the child will disconnect the child from the terminal but will not affect the parent (which exits anyway). I suggest you start off with something like:
static void
process_stuff(int sockfd)
{
while (1) {
/* receive data on socket and process */
}
}
void
run_daemon(int sockfd, int foreground)
{
if (!foreground) {
if (fork()) {
exit(EXIT_SUCCESS); /* parent */
}
/* child */
setsid();
}
process_stuff(sockfd);
}
The reason for having the if (foreground) clause is that it allows you to debug the server in the foreground under gdb when it doesn't work.