In my program, I want to send my switch case value to another process using named pipe "pipeselect". I write the number in the pipe and read the number in another program. But When I run the problem, it cannot show anything when I enter a case value. How can I do this?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipeselect[] = "/tmp/pipeselect";
char bufs[2];
int fds;
int select1;
/* Pipe Creation */
if (access(pipeselect, F_OK) == -1)
{
fds = mkfifo(pipeselect, 0700);
if (fds != 0)
{
printf("Pipe creation error\n");
exit(1);
}
}
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("Please select an option: ");
scanf("%d", &select1);
int i = select1;
switch (i)
{
case 1:
if ((fds = open(pipeselect, O_WRONLY)) < 0)
{
printf("Pipe open error\n");
exit(1);
}
write(fds, bufs, i);
close(fds);
printf("Option 1 is selected\n");
break;
case 2:
if ((fds = open(pipeselect, O_WRONLY)) < 0)
{
printf("Pipe open error\n");
exit(1);
}
write(fds, bufs, i);
close(fds);
printf("Option 2 is selected\n");
break;
default:
printf("Wrong Input!\n");
break;
unlink(pipeselect);
exit(0);
}
}
You probably need to use write like this:
bufs[0] = i; // put value entered by user into buffer
write(fds, bufs, 1); // write 1 byte from the buffer
BTW you could narrow down your code like this:
...
scanf("%d", &select1);
if (select1 == 1 || select1 == 2)
{
if ((fds = open(pipeselect, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
bufs[0] = select1; // put value entered by user into buffer
write(fds, bufs, 1); // write 1 byte from the buffer
close(fds);
printf("Option %d is selected\n", select1);
}
else {
printf("Wrong Input!\n");
}
unlink(pipeselect);
exit(0);
Related
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main() {
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a, child_b;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p1[0]);
close(p1[1]);
}
} else {
child_b = fork();
if (child_b == 0) {
while (1) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p2[0]);
close(p2[1]);
}
} else {
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s", &choice, msgbuf);
switch (choice) {
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
default:
printf("Process does not exist");
break;
case -1:
close(p1[0]);
close(p2[0]);
printf("parent waiting");
wait(NULL);
exit(0);
}
}
}
}
return 0;
}
In the above program I have a parent making two child processes belonging to that same parent. The user writes to the parent process which pipes the message to be read by either child 1 or child 2. It keeps doing this continuously unless the user inputs -1.
The problem is that case in my switch statement doesn't get executed and instead the program hangs. I think I have my pipes closed at the correct places.
You need to send some signal to your child process to inform then to terminate before waiting for them to exit. You should define some pre-defined message which means its time for child to terminate. Check below code. Here pre-defined message is "-1". You should choose your own which doesn't conflict with your application's real data.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main() {
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a, child_b;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p1[0]);
close(p1[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
child_b = fork();
if (child_b == 0) {
while (1) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p2[0]);
close(p2[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s", &choice, msgbuf);
switch (choice) {
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
default:
printf("Process does not exist\n");
break;
case -1:
strcpy(msgbuf, "-1");
write(p1[1], msgbuf, MSGSIZE); // send message to end
close(p1[0]);
close(p2[0]);
printf("parent waiting\n");
wait(NULL);
exit(0);
}
}
}
}
return 0;
}
First, you need to start performing error checking. Check the man page of the calls you make. Add checks in your code to detect errors. When they return an error, use perror and exit(EXIT_FAILURE);.
Second, you need to start paying attention to the values returned by read and write since they could be less than expected. These need to be called in a loop.
For example, for read, you'd use the following:
#include <errno.h>
#include <limits.h>
// Returns the number of bytes read.
// EOF was reached if the number of bytes read is less than requested.
// On error, returns -1 and sets errno.
ssize_t read_fixed_amount(int fd, char *buf, size_t size) {
if (size > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
ssize_t bytes_read = 0;
while (size > 0) {
ssize_t rv = read(fd, buf, size);
if (rv < 0)
return -1;
if (rv == 0)
return bytes_read;
size -= rv;
bytes_read += rv;
buf += rv;
}
return bytes_read;
}
It would be used something like this:
ssize_t bytes_read = read_fixed_amount(fd, buf, size);
if (bytes_read < 0) {
perror("read");
exit(EXIT_FAILURE);
}
if (bytes_read == 0) {
printf("EOF reached\n");
exit(EXIT_SUCCESS);
}
if (bytes_read != size) {
fprintf(stderr, "read: Premature EOF.\n");
exit(EXIT_FAILURE);
}
Third, reading from the pipe will only return EOF once all file descriptors of the write end of the pipes have been closed.
Right after the fork, the parent should do
close(p1[0]);
close(p2[0]);
Right after the fork, child 1 should do
close(p1[1]);
close(p2[0]);
close(p2[1]);
Right after the fork, child 2 should do
close(p1[0]);
close(p1[1]);
close(p2[1]);
Fourth, there's this monstrosity:
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
...
close(p1[0]);
close(p1[1]);
}
Really? Infinite loop. Attempt to repeatedly make STDIN a dup of p1[0]. Duping of a closed descriptor.
This should appear before the loop:
dup2(p1[0], STDIN_FILENO);
close(p1[0]);
Or you could skip those two call and simply read from p1[0] instead of STDIN_FILENO.
As for the infinite loop, it goes back to the second point. Check the value returned by read.
Fifth, you only wait for one child to finish, but there are two children to wait for. You need to call wait twice.
int main(void){
int n, user_length;
char userid[30];
char password[11];
if ((n = read(STDIN_FILENO, userid, 10)) == -1) {
perror("read");
exit(1);
} else if(n == 0) {
fprintf(stderr, "Error: could not read from stdin");
exit(1);
}
if (userid[n-1] == '\n')
userid[n-1] = '\0';
else
userid[n] = '\0';
if ((n = read(STDIN_FILENO, password, 10)) == -1) {
perror("read");
exit(1);
} else if (n == 0) {
fprintf(stderr, "Error: could not read from stdin");
exit(1);
}
if (password[n-1] == '\n')
password[n-1] = '\0';
else
password[n] = '\0';
strcat(userid, ":");
user_length = strlen(userid);
strcat(userid, password);
FILE *fp = fopen(PASSWORD_FILE, "r");
if (!fp) {
perror("fopen");
exit(1);
}
char line[MAXLINE];
while(fgets(line, sizeof(line) - 1, fp)) {
line[strlen(line) - 1] = '\0';
if (strcmp(userid, line) == 0)
exit(0); // found match
else if(strncmp(userid, line, user_length) == 0)
exit (2); // invalid password
}
exit(3); // no such user
}
Above is the implementation of validate.c, but how do I pass value such as userid and password to the function by using pipe(),dup2 or execl()
I used the following`
int main(void) {
char userid[10];
char password[10];
int pid;
int p[2][4];
char other[MAXSIZE];
/* Read a user id and password from stdin */
printf("User id:\n");
scanf("%s", userid);
printf("Password:\n");
scanf("%s", password);
/*Your code here*/
if (pipe(p[1]) == -1) {
perror("pipe");
}
if (pipe(p[0]) == -1) {
perror("pipe");
}
pid = fork();
if (pid != 0) {
close(p[1][0]);
close(p[0][0]);
dup2(p[1][1],STDIN_FILENO);
dup2(p[0][1],STDIN_FILENO);
close(p[1][1]);
close(p[0][1]);
int status;
if (wait(&status)!= -1) {
if (WIFEXITED(status)) {
printf("[%d] Child exited with %d\n", getpid(), WEXITSTATUS(status));
switch(WEXITSTATUS(status)){
case 0:
printf("found match\n");
break;
case 2:
printf("invalid password\n");
break;
case 3:
printf("No such user\n");
break;
default:
printf("error has occur\n");
break;
};
} else {
printf("[%d] Child exited abnormally\n", getpid());
}
}
} else if (pid == 0) {
close(p[1][1]);
close(p[0][1]);
dup2(p[1][0], fileno(stdout));
dup2(p[1][0], fileno(stdout));
execl("validate",other);
printf("what\n");
close(p[1][0]);
close(p[0][0]);
} else {
perror("fork");
exit(1);
}
return 0;
}
But the prompt always asks me for re-entering the input. What is wrong with this approach?( Note: I "execl" "validate" because it is an executable file that has been already created. The execl() I wrote simply calls the validate.c function )
As I said in the comments you probably do not need to spawn another process for this but You have an error in the way you call execl.
This:
execl("validate",other);
Should be:
execl(filename,list of arguments, NULL);
This is the documentation page. They use (char *) 0 which is the same as using NULL.
I want to write a program with 1 sender and 3 receivers. The sender can send individual message to each receivers and group message to all receivers. I am using named pipes to achieve this but can't send group message to all receivers synchronously. Any idea to send broadcast message with named pipe?
Sender program:
/* Sender */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename1[] = "/tmp/pipe1";
char pipename2[] = "/tmp/pipe2";
char pipename3[] = "/tmp/pipe3";
char pipename4[] = "/tmp/pipe4";
char buf1[80];
char buf2[80];
char buf3[80];
char buf4[80];
int fd1, fd2, fd3, fd4;
int select1, select2;
int n,pid;
/* Pipe Creation */
if (access(pipename1, F_OK) == -1) {
fd1 = mkfifo(pipename1, 0700);
if (fd1 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename2, F_OK) == -1) {
fd2 = mkfifo(pipename2, 0700);
if (fd2 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename3, F_OK) == -1) {
fd3 = mkfifo(pipename3, 0700);
if (fd3 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename4, F_OK) == -1) {
fd4 = mkfifo(pipename4, 0700);
if (fd4 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
printf("1. Send individual message\n");
printf("2. Send group message\n");
printf("Please select an option: ");
scanf("%d", &select1);
switch(select1) {
case 1:
printf("1. Receiver 1 (Mary)\n");
printf("2. Receiver 2 (John)\n");
printf("3. Receiver 3 (Peter)\n");
printf("Please select a receiver: ");
scanf("%d", &select2);
switch(select2) {
case 1:
/* Open pipe for writing */
if ((fd1 = open(pipename1, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Mary: \n");
n = read(STDIN_FILENO,buf1,80);
if (n <= 0) break;
buf1[--n] = 0;
printf("Sending message [%s] to Mary\n",buf1);
write(fd1,buf1,n);
}
close(fd1);
break;
case 2:
/* Open pipe for writing */
if ((fd2 = open(pipename2, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to John: \n");
n = read(STDIN_FILENO,buf2,80);
if (n <= 0) break;
buf2[--n] = 0;
printf("Sending message [%s] to John\n",buf2);
write(fd2,buf2,n);
}
break;
case 3:
/* Open pipe for writing */
if ((fd3 = open(pipename3, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Peter: \n");
n = read(STDIN_FILENO,buf3,80);
if (n <= 0) break;
buf3[--n] = 0;
printf("Sending message [%s] to Peter\n",buf3);
write(fd3,buf3,n);
}
break;
default:
printf("Receiver not found\n");
break;
}
case 2:
/* Open pipe for writing */
if ((fd4 = open(pipename4, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Group: \n");
n = read(STDIN_FILENO,buf4,80);
if (n <= 0) break;
buf4[--n] = 0;
printf("Sending message [%s] to Group\n",buf4);
write(fd4,buf4,n);
}
break;
default:
printf("Wrong Input!\n");
break;
}
} else {
wait(NULL);
}
unlink(pipename1);
unlink(pipename2);
unlink(pipename3);
unlink(pipename4);
exit(0);
}
Receiver1 program:
/* Receiver1 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename1[] = "/tmp/pipe1";
char pipename4[] = "/tmp/pipe4";
char buf1[80];
char buf4[80];
int fd1, fd4;
int n, pid;
printf("Mary is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd1 = open(pipename1, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd1, buf1, 80)) > 0) {
buf1[n] = 0;
printf("[Message received:] %s\n", buf1, n);
}
close(fd1);
exit(0);
} else {
/* Open pipe for reading */
if ((fd4 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}
Receiver2 program:
/* Receiver2 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename2[] = "/tmp/pipe2";
char pipename4[] = "/tmp/pipe4";
char buf2[80];
char buf4[80];
int fd2, fd4;
int n, pid;
printf("John is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd2 = open(pipename2, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd2, buf2, 80)) > 0) {
buf2[n] = 0;
printf("[Message received:] %s\n", buf2, n);
}
close(fd2);
exit(0);
} else {
/* Open pipe for reading */
if ((fd4 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}
Receiver3 program:
/* Receiver3 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename3[] = "/tmp/pipe3";
char pipename4[] = "/tmp/pipe4";
char buf3[80];
char buf4[80];
int fd3, fd4;
int n, pid;
printf("Peter is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd3 = open(pipename3, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd3, buf3, 80)) > 0) {
buf3[n] = 0;
printf("[Message received:] %s\n", buf3, n);
}
close(fd3);
exit(0);
} else {
/* Open pipe for reading */
if ((fd6 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}
In my program, I want to send user enter value "select1" to another program using a named pipe "pipeselect". When I run my program and enter 1, the program is on hold and cannot print "Option 1 is selected". What's wrong with my program?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipeselect[] = "/tmp/pipeselect";
char bufs[2];
int fds;
int select1;
/* Pipe Creation */
if (access(pipeselect, F_OK) == -1) {
fds = mkfifo(pipeselect, 0700);
if (fds != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
printf("1. Option 1\n");
printf("2. Option 2\n");
printf("Please select an option: ");
scanf("%d", &select1);
int i = select1;
switch(i) {
case 1:
if ((fds = open(pipeselect, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
bufs[0] = i;
write(fds,bufs,1);
close(fds);
printf("Option 1 is selected\n");
break;
case 2:
if ((fds = open(pipeselect, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
write(fds,bufs,i);
close(fds);
printf("Option 2 is selected\n");
break;
default:
printf("Wrong Input!\n");
break;
unlink(pipeselect);
exit(0);
}
}
I have a piece of code I am trying to alter. The code is simply 2 pipes that communicate between two processes (parent and child process). I am trying to create a "clean termination" of the program so that whenever a 0 is sent from parent to the child the respective process shuts down their end of all pipes.
The code is something like:
int main
{
int pipe1[2], pipe2[2], value, request;
if(pipe(pipe1) < 0 || pipe(pipe2) < 0)
printf("Failed to create pipes.\n");
switch(fork())
{
case -1:
perror("Cannot create fork.\n");
break;
case 0:
close (pipe1[WRITE]);
close (pipe2[READ]);
close (0);
close (1);
for(;;) {
read(pipe1[READ], &value, sizeof value);
//If user enters 0.
if(value == 0)
{
printf("Terminating child process!\n");
close(pipe1[READ]);
//write a 0 back to the parent so that it can close its end.
write(pipe2[WRITE], 0, sizeof (int));
close(pipe2[WRITE]);
exit(0);
}
else
{
/*Enter function to do something on the number here*/
write(pipe2[WRITE], &result, sizeof result);
}
}
break;
default: /* PARENT PROCESS - PRODUCER */
close(pipe1[READ]);
close(pipe2[WRITE]);
for(;;) {
printf("Ange ett tal: ");
scanf("%d", &value);
if(write(pipe1[WRITE], &value, sizeof value) != sizeof value)
{
perror("Cannot write thru pipe.\n");
return 1;
}
//Clean shutdown if value == 0
if(value == 0)
{
close(pipe2[WRITE]);
read(pipe2[READ],&result,sizeof(result));
if(result == 0)
{
close(pipe2[READ]);
printf("Pipe2[Read] closed!\n");
wait(0);
}
}
else
{
read(pipe2[READ],&result,sizeof(result));
printf("Result: %d.\n",result);
}
}
break;
}
}
I have been at this for hours now and I do not understand why my code is acting all crazy. When I enter 1 it says "Pipe closed and if i enter 0 it tries to accept another input before giving an error Cannot create pipes!.
I think I am missing something very fundamental here. Any help on the subject is very much appreciated.
Note the key change!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
enum { READ = 0, WRITE = 1 };
int main(void)
{
int pipe1[2], pipe2[2], value, result;
if (pipe(pipe1) < 0 || pipe(pipe2) < 0)
printf("Failed to create pipes.\n");
switch (fork())
{
case -1:
perror("Cannot create fork.\n");
break;
case 0:
close(pipe1[WRITE]);
close(pipe2[READ]);
while (read(pipe1[READ], &value, sizeof(value)) > 0)
{
// If user enters 0.
if (value == 0)
{
printf("Terminating child process!\n");
close(pipe1[READ]);
// write a 0 back to the parent so that it can close its end.
write(pipe2[WRITE], 0, sizeof(int));
close(pipe2[WRITE]);
exit(0);
}
else
{
result = value + 1;
write(pipe2[WRITE], &result, sizeof result);
}
}
break;
default: /* PARENT PROCESS - PRODUCER */
close(pipe1[READ]);
close(pipe2[WRITE]);
for ( ; ; )
{
printf("Ange ett tal: ");
if (scanf("%d", &value) != 1)
break;
if (write(pipe1[WRITE], &value, sizeof(value)) != sizeof(value))
{
perror("Cannot write thru pipe.\n");
return 1;
}
// Clean shutdown if value == 0
if (value == 0)
{
close(pipe1[WRITE]); // Key change!
if (read(pipe2[READ], &result, sizeof(result)) <= 0 || result == 0)
{
close(pipe2[READ]);
printf("Pipe2[Read] closed!\n");
wait(0);
break;
}
}
else
{
if (read(pipe2[READ], &result, sizeof(result)) <= 0)
break;
printf("Result: %d.\n", result);
if (result == 0)
{
printf("Read zero - exit\n");
close(pipe1[WRITE]);
close(pipe2[READ]);
break;
}
}
}
break;
}
return 0;
}