I'm having a strange problem. I'm currently creating two programs, one will execute on background and the other one will read its output and also allow to make inputs to the other one running on background.
The problem is, when I put the line dup2(in, STDIN_FILENO) the program executing on background stops printing to the files.
The Reader:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int out, err, in;
size_t i = 0, j = 0;
int offErr = 0, offOut = 0;
char bufErr[1024];
char bufOut[1024];
char *cFifo = "/tmp/out";
char *cFifoErr = "/tmp/err";
char *cFifoIn = "/tmp/in";
out = open(cFifo, O_RDONLY|O_CREAT, 0600);
err = open(cFifoErr, O_RDONLY|O_CREAT, 0600);
in = open(cFifoIn, O_WRONLY|O_CREAT, 0600);
while(1)
{
memset(bufOut, 0, 1024);
memset(bufErr, 0, 1024);
i=0;
j=0;
while(!i && !j)
{
j = pread(err, bufErr, 1024, offErr);
i = pread(out, bufOut, 1024, offOut);
offOut +=i;
offErr +=j;
}
if(i)
write(STDOUT_FILENO, bufOut, 1024);
if(j)
write(STDOUT_FILENO, bufErr, 1024);
}
return 0;
}
and the Writer (background):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int out, in, err;
char *cFifo = "/tmp/out";
char *cInFifo = "/tmp/in";
char *cErrFifo = "/tmp/err";
out = open(cFifo, O_RDWR|O_CREAT|O_TRUNC, 0600);
in = open("/tmp/in", O_RDWR|O_CREAT|O_TRUNC, 0600);
err = open(cErrFifo, O_RDWR|O_CREAT|O_TRUNC, 0600);
dup2(out, STDOUT_FILENO);
dup2(err, STDERR_FILENO);
//dup2(in, STDIN_FILENO); //if I uncomment this it stops printing to out or err
system("python");
while(1);
return 0;
}
When you uncomment:
//dup2(in, STDIN_FILENO); //if I uncomment this it stops printing to out or err
you are making Python read from an empty file (it was created and/or truncated when you opened it), so Python gets nothing to do and exits.
Your reader code then sits in the while (1) ; loop doing nothing useful.
At the very least, add a printf() after the system() statement so you know when the Python command has completed.
Related
FINAL UPDATE:
Code updated with final working version, got everything working thanks to the code found on: How to flush stdin without requiring user input?
Im programming C and having some trouble redirecting output from a parent process to a child process using file descriptors.
The idea of all of this, is for program A to be the middleman between all the data that goes from two programs.
I have a process A that creates a child process B which executes a execlp to a program C. There is also a program D that communicates with process A by named pipes and the idea is to redirect this communication to program C using unnamed pipes.
Right now my programs redirect the inicial communication from C to A to D correctly and from D to A correctly but fails when the redirection from A to C is supposed to happen.
I think the problem is that fgets() does not seem to retrieve the input unless two enters are given. I've tried using scanf, fscanf, getchar() and others aswell as flushing in multiple ways, nothing worked.
The only problem really is the fact that two inputs seem to be required for the communication of A to C to occur.
There are a million posts about this, and i've tried a lot of them to no sucess.
Can anyone help? Sorry if it sounds confusing.
Process A:(middleman)
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
int main(void)
{ //0->read 1->write
int fd_out[2];
int fd_in[2];
pipe(fd_out);
pipe(fd_in);
pid_t pid = fork(); //Create process B
char s[BUFSIZ];
char s2[BUFSIZ];
if ( pid == 0 )
{
close(STDOUT_FILENO);
dup(fd_out[1]);
close(fd_out[0]);
close(STDIN_FILENO);
dup(fd_in[0]);
close(fd_in[1]);
if(execlp("./test_pipe_game","./test_pipe_game",(char*)NULL) == -1){
printf("Error EXECL\n"); //Program C
}
}else{
int fifo;
char * myfifo = "/tmp/fifo123";
mkfifo(myfifo, 0666);
close (fd_out[1]);
close(fd_in[0]);
while(1){
read(fd_out[0], s, BUFSIZ);
printf("Game said:\n%s \nsending to client...\n", s);
fifo = open(myfifo, O_WRONLY);
write(fifo, s, BUFSIZ);
close(fifo);
fifo = open(myfifo, O_RDONLY);
read(fifo, s2, BUFSIZ);
close(fifo);
printf("Client said:\n%s \nsending to game...\n", s2);
write(fd_in[1], s2, BUFSIZ);
fflush(stdout);
printf("Sent!\n");
}
}
int status;
waitpid(pid, &status, 0);
if ( WIFEXITED(status) )
{
int exit_status = WEXITSTATUS(status);
printf("Exit status of the child was %d, my pid = %d\n",
exit_status, getpid());
}
return 0;
}
Program C:(game)
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
//https://stackoverflow.com/questions/54299405/how-to-flush-stdin-without-requiring-user-input
int flush_in(FILE *file)
{
int ch;
int flags;
int fd;
fd = fileno(file);
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
return -1;
}
do {
ch = fgetc(file);
} while (ch != EOF);
clearerr(file);
if (fcntl(fd, F_SETFL, flags)) {
return -1;
}
return 0;
}
int main(){
char s[BUFSIZ];
char aux;
int c;
int i = 0;
while(1){
printf("Say something client!\n");
fflush(stdout);
//fgets(s, BUFSIZ, stdin);
scanf("%s",s);
printf("I received %s from the client!\n", s);
flush_in(stdin);
}
}
Program D(client)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd1;
char * myfifo = "/tmp/fifo123";
char str1[BUFSIZ];
char str2[BUFSIZ];
while (1)
{
system("clear");
fd1 = open(myfifo,O_RDONLY);
read(fd1, str1, BUFSIZ);
close(fd1);
printf("The game said:\n%s\n", str1);
printf("Say something:\n");
//fgets(str2, BUFSIZ, stdin);
scanf("%s",str2);
fd1 = open(myfifo,O_WRONLY);
write(fd1, str2, BUFSIZ);
close(fd1);
}
return 0;
}
UPDATE:
Like #CraigEstey and #thebusybee said my problem was using only one pipe, when i added the second pipe it solved the issue. I now have another problem, which seems to be related to reading from stdin without getting trash, i get no trash from the first 2 or 3 communications but after that fgets only reads trash. Flushing stdin does not seem to solve much. I've updated the codes if anyone wants to help!
The code is following.
Q1:
If dup2(fd3, STDOUT_FILENO), string2 will be in log.txt.
If dup2(g_ctl[0], STDOUT_FILENO), string2 won't be received by g_ctl[1].
string1 and ls -al output will be received, Why ?
Q2:
The third library have some stdout/stderr log, if using dup2(socket_fd, STDOUT_FILENO), all logs will be collected by socket. But I also want to print all logs to screen at the same time, how to do it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
static pthread_t g_pid;
static int g_ctl[2] = {-1, -1};
void *_run_loop(void *args) {
char buf[1024];
int n;
while (1) {
n = recv(g_ctl[1], buf, 1024, 0);
if (n > 0) {
fprintf(stderr, "%.*s\n", n, buf);
}
}
}
int main(int argc, char const *argv[])
{
int fd3 = open("./log.txt", O_CREAT | O_RDWR | O_APPEND, 0666);
int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, g_ctl);
assert(ret == 0);
ret = dup2(g_ctl[0], STDOUT_FILENO);
assert(ret > 0);
pthread_create(&g_pid, NULL, _run_loop, NULL);
send(STDOUT_FILENO, "string1", 5, 0);
system("ls -al");
printf("string2\n");
sleep(5);
return 0;
}
Q1: You need to fflush(stdout); after your printf. Otherwise printf may buffer your output. It will be written when your program exits if it hasn't already, but by that time your reading thread has already been canceled, so you don't get to read it.
Q2: As far as I know, the only way to get your output written to two files is to actually write it to both file descriptors. There is no way in Unix to "double-dup" a file descriptor. Even a command like tee is really just calling write() twice for each chunk of data read. You can do it manually, or inside a function, or in a thread, but you have to do it.
In my understanding, according to the https://linux.die.net/man/3/mkfifo,
I got an implication that I must have reader and writer file, in order to
utilize the pipe file. The source below is the writer file,
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
and the source being provided below is for the reader file.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
When run the executable for the writer file, the command prompt goes into
halt, after printing a newline. My assumption for this problem is because the
open() in the writer file is not being able to detect the pipe file,
is that the case?
Thank you.
I suggest that you should create the FIFO before the fork, but only open the FIFO after the fork. This avoids an assortment of problems. For the most part, I've used write() to report errors to standard error; it isn't as convenient as using fprintf(stderr, …) though.
Note that the writer writes a null byte at the end of the message. The reader gets the null byte, but overwrites it with a newline before writing the resulting character array (it is no longer a string; strings have a terminal null byte at the end) to standard output. If the code used <stdio.h> to write the data (e.g. printf("%s\n", buf)), it wouldn't need to replace the null byte with a newline.
writer.c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef READER
#define READER "./reader"
#endif
int main(void)
{
char *myfifo = "./myfifo";
if (mkfifo(myfifo, 0777) != 0)
{
write(STDERR_FILENO, "Failed to create FIFO\n",
sizeof("Failed to create FIFO\n") - 1);
}
int PID = fork();
if (PID == 0)
{
execl(READER, "reader", (char *)NULL);
write(STDERR_FILENO, "Failed to execute reader\n",
sizeof("Failed to execute reader\n") - 1);
exit(EXIT_FAILURE);
}
if (PID < 0)
{
write(STDERR_FILENO, "Failed to fork\n",
sizeof("Failed to fork\n") - 1);
exit(EXIT_FAILURE);
}
int fd = open(myfifo, O_WRONLY);
if (fd < 0)
{
write(STDERR_FILENO, "Failed to open FIFO for writing\n",
sizeof("Failed to open FIFO for writing\n") - 1);
unlink(myfifo);
exit(EXIT_FAILURE);
}
write(fd, "Rock and roll baby", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
return 0;
}
reader.c
#include <fcntl.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(void)
{
char* myfifo = "./myfifo";
int fd = open(myfifo, O_RDONLY);
if (fd < 0)
write(STDERR_FILENO, "Failed to open FIFO for reading\n",
sizeof("Failed to open FIFO for reading\n")-1);
else
{
char buf[MAX_BUF];
int nbytes = read(fd, buf, MAX_BUF);
if (nbytes > 0)
{
buf[nbytes-1] = '\n';
write(STDOUT_FILENO, buf, nbytes);
}
close(fd);
}
return 0;
}
Example output
Rock and roll baby
Child 43734 exited with status 0x0000
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
After having the body of the code, where the execl is, moved above the
mkfifo(),
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
sleep(3);
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
and having the reader have sleep() for 3 seconds, the programs started to
work; however, does anyone know if the two programs can open() the pipe file
exactly at the same time?
Thank you.
I'm writing a program that should run indefinitely maintaining the value of a variable. Two other programs could change the value of the variable. I use named pipes to receive and send the variable value to external programs.
Here is my code for the manager of the variable.
manager.c:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
char a = 'a';
void *editTask(void *dummy)
{
int fd;
char* editor = "editor";
mkfifo(editor, 0666);
while(1)
{
fd = open(editor, O_RDONLY);
read(fd, &a, 1);
close(fd);
}
}
void *readTask(void *dummy)
{
int fd;
char* reader = "reader";
mkfifo(reader, 0666);
while(1)
{
fd = open(reader, O_WRONLY);
write(fd,&a,1);
close(fd);
}
}
int main()
{
pthread_t editor_thread, reader_thread;
pthread_create(&editor_thread, NULL, editTask, NULL);
pthread_create(&reader_thread, NULL, readTask, NULL);
pthread_join (editor_thread, NULL);
pthread_join (reader_thread, NULL);
return 0;
}
This program uses pthreads to separately get external values for the variable and to communicate the current value of the variable to external programs.
The program that is able to write values to the variable is:
writer.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("Need an argument!\n");
return 0;
}
int fd;
char * myfifo = "editor";
fd = open(myfifo, O_WRONLY);
write(fd, argv[0], 1);
close(fd);
return 0;
}
The program that could read the current value is:
reader.c:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd;
char * myfifo = "reader";
fd = open(myfifo, O_RDONLY);
char value = 'z';
read(fd, &value, 1);
printf("The current value of the variable is:%c\n",value);
close(fd);
return 0;
}
I ran these programs in my Ubuntu system as follows:
$ ./manager &
[1] 5226
$ ./writer k
$ ./reader
bash: ./reader: Text file busy
Why doesn't my system allow me to run this program?
Thank you.
You are trying to call both the FIFO and the reader program "reader".
Also, you have no error checking. You have no idea whether those calls to mkfifo and open succeeded or not. Adding this is critical before you attempt to do any troubleshooting.
I am trying to make this work but no luck, basically i need to write to the pipe and then make the pipe return back with the text i sent. I have a server.c and client.c , so i make the server.c run..., open a new terminal and then run the client.. the problem is that the client doesnt do anything when i run it.. I am sure i am missing something.. like closing the pipe. i am not sure.. I would really appreciate some guidance
server.c
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define PIPE1 "PIPE1"
#define PIPE5 "PIPE5"
#define MAX_BUF_SIZE 255
int main(int argc, char *argv[])
{
int rdfd1,rdfd2,rdfd3,rdfd4, wrfd1,wrfd2,wrfd3,wrfd4,ret_val, count, numread1,numread2,numread3,numread4;
char buf1[MAX_BUF_SIZE];
char buf2[MAX_BUF_SIZE];
char buf3[MAX_BUF_SIZE];
char buf4[MAX_BUF_SIZE];
/* Create the first named - pipe */
ret_val = mkfifo(PIPE1, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
return 1;
}
ret_val = mkfifo(PIPE5, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
return 1;
}
/* Open the first named pipe for reading */
rdfd1 = open(PIPE1, O_RDONLY);
/* Open the first named pipe for writing */
wrfd1 = open(PIPE5, O_WRONLY);
/* Read from the pipes */
numread1 = read(rdfd1, buf1, MAX_BUF_SIZE);
buf1[numread1] = '0';
printf("Server : Read From the pipe : %sn", buf1);
/*
* Write the converted content to
* pipe
*/
write(wrfd1, buf1, strlen(buf1));
}
client.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PIPE1 "PIPE1"
#define PIPE5 "PIPE5"
#define MAX_BUF_SIZE 255
int main(int argc, char *argv[ ]) {
pid_t childpid;
int error;
int i;
int nprocs;
/* check command line for a valid number of processes to generate */
int wrfd1, rdfd1, numread;
char rdbuf[MAX_BUF_SIZE];
if ( (argc != 2) || ((nprocs = atoi (argv[1])) <= 0) ) {
fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
return 1;
}
for (i = 1; i < nprocs; i++) {
/* create the remaining processes */
if ((childpid = fork()) == -1) {
fprintf(stderr, "[%ld]:failed to create child %d: %s\n", (long)getpid(), i, strerror(errno));
return 1;
}
/* Open the first named pipe for writing */
wrfd1 = open(PIPE5, O_WRONLY);
/* Open the second named pipe for reading */
rdfd1 = open(PIPE1, O_RDONLY);
if (childpid)
break;
char string1[100];
if(sprintf(string1, "This is process %d with ID %ld and parent id %ld\n", i, (long)getpid(), (long)getppid())) {
write(wrfd1,string1, strlen(string1));
}
/* Read from the pipe */
numread = read(rdfd1, rdbuf, MAX_BUF_SIZE);
rdbuf[numread] = '0';
printf("Full Duplex Client : Read From the Pipe : %sn", rdbuf);
}
return 0;
}
It seems like both server and client read from PIPE1 and write to PIPE5. Shouldn't one of them write to PIPE1 so that the other can read it from the other end?
Also, if you're testing with ./client 1, your for (i = 1; i < nprocs; i++) loop will never execute.
One last thing, see this question. I'm not entirely sure it applies to your code, but it's worth keeping in mind.
Shouldn't this line be '\0' ?
buf1[numread1] = '0';