I'm trying to write an init system, and I want to spawn a process without the IO. meaning, I don't want to see output or for it to take input. I currently use the function from suckless's sinit -
void spawn(char *const argv[]) {
switch (fork()) {
case 0:
sigprocmask(SIG_UNBLOCK, &set, NULL);
setsid();
execvp(argv[0], argv);
perror("execvp");
_exit(1);
break;
case -1:
perror("fork");
break;
default:
break;
}
}
but if I start a process (used top as a test), it doesn't run "in the background". how can I do that?
All processes expect to inherit file descriptors 0, 1, and 2 from their parent process, as standard input, output and error, respectively.
The traditional approach involves redirecting them to /dev/null. All output disappears, and any attempts to read from standard input result in an immediately end-of-file indication.
And redirecting them to /dev/null consists of closing them, and opening /dev/null in their place.
void spawn(char *const argv[]) {
switch (fork()) {
case 0:
sigprocmask(SIG_UNBLOCK, &set, NULL);
setsid();
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY);
open("/dev/null", O_WRONLY);
open("/dev/null", O_wRONLY);
execvp(argv[0], argv);
Robustness suggests meticulously checking if each open() succeeded, or not. But, if opening /dev/null fails you'll have more problems to worry about.
Related
I am trying to write a C program that execute ls | wc using pipe and fork but I can't figure out what is wrong with my code. When I run the code below nothing is returned.
int main() {
pid_t p1, p2;
int fd1[2];
pipe(fd1);
p1 = fork();
if (p1 == 0) {
close(STDOUT_FILENO);
dup2(fd1[1], STDOUT_FILENO);
close(fd1[0]);
execlp("ls", "ls", (char *)NULL);
} else {
p2 = fork();
if (p2 == 0) {
dup2(fd1[0], STDIN_FILENO);
close(fd1[0]);
close(fd1[1]);
execlp("wc", "wc", (char *)NULL);
} else {
waitpid(p2, 0, WUNTRACED);
waitpid(p1, 0, WUNTRACED);
}
}
return 0;
}
You didn't clearly explain what this program was doing that you considered to be wrong. However, when I run this program myself (after adding the appropriate headers -- in the future, please don't leave those out of your question), it hangs until I press control-C. I'm going to assume that this is what you didn't want, and that what you did want is for it to print the output of wc and then exit.
The program hangs because fd1[1] is still open in the parent process at the point when it calls wait. wc will not receive an EOF indication until all of the file descriptors referring to the write side of the pipe are closed. But the parent process is not going to close the write side of the pipe until both of its child processes exit, and wc is not going to exit until it gets an EOF, so you have a deadlock.
You need to add close(fd1[1]) on the parent side of the first if, immediately before p2 = fork(). That is sufficient to clear the deadlock. You should also add close(fd1[0]) on the parent side of the second if, immediately before the waitpid calls. And you should also check all operations for errors.
My program launches two binaries using "system" command the following way:
int status = system("binaryOne &");
int status = system("binaryTwo &");
Since all three binaries write to the same stdout, all the output is mixed and not understandable. So I changed launch command to redirect stdout of two binaries to different files on which I do tail -f:
int status = system("binaryOne > oneOut.txt &");
int status = system("binaryTwo > twoOut.txt &");
The problem is that writing to files stops at some point. Sometimes it freezes, buffered somewhere and than part of it thrown back and again. Most of time it just stops.
I verified that binaries continue to run and write to stdout.
Here is how you could try it with fork + exec
pid_t child_pid = fork();
if (!child_pid) {
// child goes here
char * args[] = {"binaryOne", NULL};
int fd = open("oneOut.txt", O_WRONLY | O_CREAT | O_TRUNC);
if (!fd) {
perror("open");
exit(-1);
}
// map fd onto stdout
dup2(fd, 1);
// keep in mind that the children will retain the parent's stdin and stderr
// this will fix those too:
/*
fd = open("/dev/null", O_RDWR);
if (!fd) {
perror("open");
exit(-1);
}
// disable stdin
dup2(fd, 0);
// disable stderr
dup2(fd, 2);
*/
execvp(*args, args);
// will only return if exec fails for whatever reason
// for instance file not found
perror("exec");
exit(-1);
}
// parent process continues here
if(child_pid == -1) {
perror("fork");
}
Edit Important: forgot to set write flag for open.
You can avoid most of this by using popen(). Each popen call will set up a separate pipe for your main program to read and the output won't be intertwined as it is having everything directed to stdout. Also obviously a lot less clumsy than writing to and tailing files. Whether this is better than fork/exec for your purposes only you can say.
I'm trying to implement unix piping in c (i.e. execute ls | wc). I have found a related solution to my problem (C Unix Pipes Example) however, I am not sure why a specific portion of the solved code snippet works.
Here's the code:
/* Run WC. */
int filedes[2];
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0) {
/* Set stdout to the input side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
} else {
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
}
/* Run WC. */
pid = fork();
if (pid == 0) {
dup2(filedes[0], 0);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
}
In the child process that executes the wc command, though it attaches stndin to a file descriptor, it seems that we are not explicitly reading the output produced by ls in the first child process. Thus, to me it seems that ls is run independently and wc is running independently as we not explicitly using the output of ls when executing wc. How then does this code work (i.e. it executes ls | wc)?
The code shown just about works (it cuts a number of corners, but it works) because the forked children ensure that the the file descriptor that the executed process will write to (in the case of ls) and read from (in the case of wc) is the appropriate end of the pipe. You don't have to do any more; standard input is file descriptor 0, so wc with no (filename) arguments reads from standard input. ls always writes to standard output, file descriptor 1, unless it is writing an error message.
There are three processes in the code snippet; the parent process and two children, one from each fork().
The parent process should be closing both its ends of the pipe too; it only closes one.
In general, after you do a dup() or dup2() call on a pipe file descriptor, you should close both ends of the pipe. You get away with it here because ls generates data and terminates; you wouldn't in all circumstances.
The comment:
/* Set stdout to the input side of the pipe, and run 'ls'. */
is inaccurate; you're setting stdout to the output side of the pipe, not the input side.
You should have an error exit after the execv() calls; if they fail, they return, and the process can wreak havoc (for example, if the ls fails, you end up with two copies of wc running.
An SSCCE
Note the careful closing of both ends of the pipe in each of the processes. The parent process has no use for the pipe once it has launched both children. I left the code which closes filedes[1] early in place (but removed it from an explicit else block since the following code was also only executed if the else was executed). I might well have kept pairs of closes() in each of the three code paths where files need to be closed.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int filedes[2];
int corpse;
int status;
pipe(filedes);
/* Run LS. */
pid_t pid = fork();
if (pid == 0)
{
/* Set stdout to the output side of the pipe, and run 'ls'. */
dup2(filedes[1], 1);
close(filedes[1]);
close(filedes[0]);
char *argv[] = {"ls", NULL};
execv("/bin/ls", argv);
fprintf(stderr, "Failed to execute /bin/ls\n");
exit(1);
}
/* Close the input side of the pipe, to prevent it staying open. */
close(filedes[1]);
/* Run WC. */
pid = fork();
if (pid == 0)
{
/* Set stdin to the input side of the pipe, and run 'wc'. */
dup2(filedes[0], 0);
close(filedes[0]);
char *argv[] = {"wc", NULL};
execv("/usr/bin/wc", argv);
fprintf(stderr, "Failed to execute /usr/bin/wc\n");
exit(1);
}
close(filedes[0]);
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("PID %d died 0x%.4X\n", corpse, status);
return(0);
}
Example output:
$ ./pipes-14312939
32 32 389
PID 75954 died 0x0000
PID 75955 died 0x0000
$
I am trying to implement a simple shell. I fork processes this way:
void forkProcess(char* cmd[]) {
pid_t pid;
char programPath[BUFFERLENGTH] = "/bin/";
strcat(programPath, cmd[0]);
int exitStatus;
pid = fork();
switch (pid) {
case -1:
printf("Fork failed; pid == -1\n");
break;
case 0:
execv(programPath, cmd);
exit(0);
break;
default:
waitpid(pid, &exitStatus, 0);
//printf("Exitstatus = %d\n", WEXITSTATUS(exitStatus));
break;
}
}
Now the cmd parameter might contain a pipe, e.g.:
"ls" "-l" "|" "grep" "whatever" "(char*)NULL";
So how can I implement the pipe functionality? I know there are functions like pipe() and dup(), but I don't know how to use them in this context.
Thank you for any suggestions.
You must fully parse your command line before fork()ing to start the child.
If a pipe operator is being used, you must set up the pipe before calling fork(), so it is inherited.
In general you must also use close() and often dup() to make the pipe replace the forked process' stdin.
Continue reading up on these functions to "get" the big picture, or get a book which covers Unix I/O.
In this case, you may use popen().
I am working on an assignment for my Operating System class (Posix & C), building a mini-shell, and I don't know how to solve the following problem:
My mini-shell has to accept two commands, for example ls | grep a. For that I create a pipe of size two and a child. The child closes all that it has to close and opens all that it has to open (standard/pipe's in & out). It then executes "ls," using execvp. I am sure this works well. After that, the parent shuts and opens inputs and outputs (I am sure I do it well), and then executes grep a.
Now, the problem is that the process grep a never finishes. Same for tail -1, e.g.. Yet it does work for head -1. I think that happens because grep and tail, which are executed by the parent, wait for more input, even though the child has finished its operation. ls | grep a produces the right output, displayed on the console (The pipe's output is set as default output), but, as I've said, grep a does not finish.
So, my question is: how can I inform the parent that the pipe has finished writing, so it can finish the execution of grep a for example?
Thank you.
Here's the code:
[fd is the pipe, it is initialized previously in the code. If you can see any incongruous thing, please let me know; I've cleaned the code a bit, and this is only the problematic part, as you can see.]
int fd[2];
pipe(fd);
if ((pid = fork()) != -1){
if(pid == 0){ /*Child executing */
close(fd[0]);
close(1);
dup(fd[1]);
close(fd[1]);
execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */
} else{ /* Parent executing */
wait(&status);
close(fd[1]);
close(0);
dup(fd[0]);
close(fd[0]);
execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
}
}
If the grep continues to run after the ls has exited, that indicates that you have not closed all the pipes that you need to close.
In particular, the write end of the pipe whose read end is attached to the grep process is still open in another process. You will need to show your code to know more.
The code you have pasted works correctly (when expanded to a full program, as per the below). Both subprocesses exit just fine.
This means that you've eliminated the code that has the problem when you created your cut-down version here - perhaps you have another fork() between the pipe() call and this fork()?
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
char *argvv[2][3] = { { "ls", 0, 0}, { "grep", "a", 0 } };
int status;
int fd[2];
pipe(fd);
if ((pid = fork()) != -1) {
if(pid == 0){ /*Child executing */
close(fd[0]);
close(1);
dup(fd[1]);
close(fd[1]);
execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */
} else{ /* Parent executing */
wait(&status);
close(fd[1]);
close(0);
dup(fd[0]);
close(fd[0]);
execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
}
}
return 0;
}