redirect input using open() and close() - c

I'm trying to understand how the I/O between processes mechanism works.
I have tried to run this code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
...
char *const paramList[] = {"/bin/cat"};
close(0);
open("./my_file", O_RDONLY);
execv("/bin/cat",paramList);
...
but got nothing going on. (it compiles, though)
what did I do wrong and what does my code do?

Per the docs for execv:
The array of pointers must be terminated by a NULL pointer.
Thus, add NULL to the end of paramList.
If you're still having trouble, make sure to check the return values from all syscalls, and see if any of your calls are failing.

Related

How to use pipe and fork

I have the following code(there's a bunch of extra headers that were used in other parts of the code that I removed since they don't have anything to do with my issue). I have also removed the error checking for fork and pipe for brevity:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
void compile(char *fullname)
{
int pid = fork();
int pipe_send_output[2];
pipe(pipe_send_output);
if (pid == 0)
{
close(pipe_send_output[0]);
dup2(pipe_send_output[1], STDERR_FILENO); // redirect output of gcc to the pipe
execlp("gcc", "gcc", "-Wall", fullname, NULL);
printf("execlp error");
}
else
{
close(pipe_send_output[1]);
dup2(STDIN_FILENO, pipe_send_output[0]); // redirect from pipe to stdin
close(pipe_send_output[0]);
exit(0);
}
}
int main(){
compile("folder/small.c");
}
The compile function is supposed to create a new process which compiles some c file using gcc, and then sends the output(errors and warnings) to the parent process, to be printed. To do this I redirected STDERR to the write end of the pipe, and then in the parent process redirected the read end to stdin. I can't for the life of me figure out why it's not displaying anything. If I remove the redirection of stderr to the pipe, then plenty of stuff it outputed, so the issue isn't gcc not outputting anything. I tried to replace the redirection to stdin with reading from the pipe and then printing it, but that has the same result. A couple of time this did print one or 2 characters, which is even more confusing. This is the code that replaces the second call to dup2 for printing:
char buffer[1024];
while(read(pipe_send_output[0], buffer, 1024)) printf("%s", buffer);
I've looked everywhere on google and on the man page and still don't have a clue what's wrong.
Disclaimer:This is part of a project for a lab at university. The code that I wrote follows the blueprint from the materials my professor provided, and makes perfect sense to me. Any hint on what the issue may be is appreciated.

C - Redirecting awk/sed stdout to pipe doesn't work

So I have an exercise to do, and one part of this exercise requires us to execute a command passed as an argument, be able to pass it some strings on stdin, and get its output on stdout and stderr.
How I did it, I need to redirect the stdout and stderr (of the child, which is gonna call an exec) to a couple of pipes (other end of the pipes is held open by the parent).
I managed to do it, when I ask it to execute bash and send it "ls", it gives me what i want, where i want it. Same with cat and others.
Problem is, when I try executing awk or sed, nothing is ever written on the pipe. Ever.
If i leave stdout untouched, it does print it how it should. But as soon as i redirect the stdout, nothing.
I tried everything, select(), wait(), sleep() (even though it's not allowed). Nothing seems to work.
I made a minimum working example of what i mean (clearly, it lacks of conventions and mindful writing, as free() and close(), but it does it's job) which Is the one I'm attaching. The code works when i call it like this:
./program $(which bash)
It prompts for something, i write "ls" and it gives me the result expected
but when i try
./program $(which awk) '{print $0;}'
I get nothing at all
Here's the code (minimum working example):
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
int main(int argc, char* argv[]){
int fdStdinP[2],fdStdoutP[2];
char *string,*array[3];
array[0]=argv[1];
array[1]=argv[2];
array[2]=0;
pipe(fdStdinP);
pipe(fdStdoutP);
int pid=fork();
if(pid==0){
close(fdStdinP[1]);
close(fdStdoutP[0]);
dup2(fdStdinP[0],0);
close(fdStdinP[0]);
dup2(fdStdoutP[1],1);
close(fdStdoutP[1]);
//as suggested, the file descriptors are now closed
execvp(argv[1],array);
perror("");
return 0;
}
close(fdStdinP[0]);
close(fdStdoutP[1];
string=calloc(1024,sizeof(char));
read(0,string,1024);
write(fdStdinP[1],string,1024);
free(string);
string=calloc(1024,sizeof(char));
read(fdStdoutP[0],string,1024);
printf("I have read:%s",string);
return 0;
}
Thank you for your time.
Awk continues to wait for input and buffers its output, so appears to hang. Closing the sending end will tell awk that it's input has ended so that it will end and flush its output.
write(fdStdinP[1],string,1024);
close(fdStdinP[1]); // just added this line.

Named Semaphores in child processes confusing me

I have this very simple program to test out named semaphores:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/shm.h>
#include <fcntl.h>
sem_t thing;
void processOne() {
sleep(1);
int l;
sem_getvalue(&thing, &l);
printf("processOneThing: %d\n", l);
}
void processTwo(){
sem_wait(&thing);
printf("done");
}
int main(int argc, char **argv) {
int pidOne, pidTwo;
thing = *sem_open("/testest", O_CREAT|O_EXCL,0777,1);
pidTwo=fork();
if(pidTwo==0){
processTwo();
}
else{
pidOne=fork()
if(pidOne==0){
processOne();
}
else{
}
wait(&pidTwo);
wait(&pidOne);
}
sem_unlink("/testest");
sem_close(&thing);
}
The output is:
doneprocessOneThing: 1
Which means that the second process decremented the semaphore however the value of it in the first child process is still 1...
I have no idea what I am doing wrong and I looked at the named semaphore documentation and could not find much that could help me with this issue.
I'm compiling using:
gcc test.c -pthread
Any and all help would be much appreciated.
First, the code is missing a ; at end of this line:
else{
pidOne=fork() <------ here
if(pidOne==0){
processOne();
}
And it fails to #include<sys/wait.h> for wait() prototype. But correcting these issues I get the same output as you. So what is happening? The issue is with how you created the semaphore:
sem_t thing;
...
thing = *sem_open("/testest", O_CREAT|O_EXCL,0777,1);
The return from sem_open is the address of the created semaphore. But you are dereferencing that address and placing a copy of the contents into your variable thing. That means thing isn't actually the semaphore you created, but just a copy of the struct holding state information. The upshot is that interacting with thing in your code isn't actually interacting with what you intended. (In fact, you might get some indication that something isn't right if you check the return values on sem_wait() and sem_getvalue().)
If you instead make thing a pointer to the semaphore and interact with that, you get the following output:
done
processOneThing: 0
which is I think what you expected to see. You can try the corrected code here:
Runnable corrected code

How to reopen stdout if it is closed by the process who called exec

Is it possible to reopen stdout, if it is already closed.
For example the below code.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main(){
fcntl(1,F_SETFD,FD_CLOEXEC) ;
execve("./test2",NULL, NULL);
printf("Can you see me [TWO]\n");
}
The above code closes Standard output file descriptor and then calls execve. The code for test2 is below
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main() {
printf(" standard output\n");
perror("standard error");
}
Output:
standard error: Bad file descriptor
Is there any way of opening stdout in test2.c
First, it is important to notice - you just set fd 1 as CLOEXEC, so of course it will be closed upon the 'execve' call. Make sure you understand that. If you are able to edit 'test1' - you can just remove the 'fcntl' call.
But, on the other hand - if you can't edit 'test'1 at all - there might be a few ways to get around it.
If you are OK with 'stdout' and 'stderr' are pointing to the same place (maybe they are initially?) - you can just duplicate fd=2 into 1, using the following call: dup2(2,1).
(Linux specific) if 'fork' is somehow called before the 'execve', you might be able to access the closed fd using the procfs filesystem. Assuming the parent process of 'test2' have the 'stdout' you want open in fd=1, you can just get its PID using getppid(), and then open /proc/<ppid>/fd/1 (and of course - dup2 the resulting fd into 1).
Otherwise - there might be no way to "reopen" the file descriptor - as it was closed. Obviously, you can always open the file you want the stdout to point on from now on (dup2 it to 1!), and avoid the 'Bad file descriptor' error.
Good luck!

Unix fifo client to server

I want to use a pair of Unix FIFOs in such manner that:
a client sends to a server a file name and
the server returns to the client: the number of words, lines and bytes from the given file.
Could you please help?
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
c2s=open("fifo1",O_WRONLY);
s2c=open("fifo2",O_RDONLY);
printf("give file name \n");
scanf("%s",a);
nr=strlen(a);
write(c2s,&nr,sizeof(int));
write(c2s,&a,sizeof(nr));
read(s2c,&c,sizeof(int));
read(s2c,&d,sizeof(int));
read(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
return 0;
}
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int nr,s2c,c2s,c,d,e;
char a[20];
FILE* f;
c2s=open("fifo1",O_RDONLY);
s2c=open("fifo2",O_WRONLY);
read(c2s,&nr,sizeof(int));
read(c2s,&a,sizeof(nr));
f=fopen(a,"r");
if(fork()==0)
{
printf("result is: \n");
execl("/usr/bin/wc","wc",c,d,e,NULL);
}
wait(0);
write(s2c,&c,sizeof(int));
write(s2c,&d,sizeof(int));
write(s2c,&e,sizeof(int));
close(c2s);
close(s2c);
printf("\n FINISH \n");
return 0;
}
I have done some improvements but still it doesn't work properly.
In the fork'ed part of the server, redirect the standard input and output of wc with
dup2(c2s, STDIN_FILENO);
dup2(s2c, STDOUT_FILENO);
Then exec it with
execl("/usr/bin/wc", "wc", NULL);
Don't pass the file descriptors as arguments to execl. It expects strings (char const*), not int.
See dup2 in the POSIX standard to understand how this works.
Note that wc writes strings of characters to its output. You are trying to read them as if they are binary numbers. This will lead to confusion - especially as you do not check that the read calls worked correctly.
Actually, general comment - you should check many more of your system calls.
You also have to ensure that your processes do not block when opening the FIFOs. You should be OK; you have the processes open 'fifo1' for reading and writing, and then 'fifo2'. I think that forces a correct order on things.
You only write 4-letter file names correctly on the pipe.

Resources