I am trying to write a simple shell program, but have a small bug, which I can't seem to solve.
The program should be capable of launching a background process, but it fails to do so properly. It seems to work at first (program launches & the shell is still responsible) but fails at the second command.
In other words what happens is
launch some background process (browser) - works (launches and keeps working)
launch some regular process - works (lunches & finishes)
launch another process - doesn't work. The shell isn't responsive and waits until the background process is over.
Removing the following line:
waitpid(pid,NULL,0);
Solves this issue, but now all programs are 'background' (shell won't wait for anything to finish).
This is the complete function:
int launchprog(int background, char** arglist){
/* create a background process*/
if(background == 1){
pid_t pid = fork();
if(pid == 0){
/* child*/
arglist[-1] = NULL;
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
} else if (pid < 0) {
perror("Forking error");
exit(1);
}
return 1;
}
/* create a simple process*/
printf("shalom, %d,%d\n", background,getpid());
pid_t pid = fork();
if (pid == 0) {
/* child*/
struct sigaction saint;
saint.sa_handler = &int_signal_handle_exit;
sigemptyset(&saint.sa_mask);
saint.sa_flags = 0;
if (sigaction(SIGINT, &saint, 0) == -1) {
perror("Sigaction Error");
exit(1);
}
if (execvp(arglist[0], arglist) == -1) {
perror("Error in execvp, cannot init child process");
}
exit(1);
}
else if (pid < 0) {
perror("Forking error");
exit(1);
} else {
if (background == 0){ /* this should always be true*/
waitpid(pid,NULL,0);
}
}
return 1;
}
Related
I have to show the elapsed time to run a command using pipes, so I use the gettimeofday function and pass the pointer through the pipe, but when I'm reading it in the father process I get a different result than expected. I'm supossed to get 1604626608037896 but instead I have this 94762421350317.
This is my code:
if (pipe(p) < 0)
exit(1);
pid=fork();
if (pid == -1){
printf("can't fork, error occured\n");
exit(EXIT_FAILURE);
}else if (pid == 0){
//This is the child I get the time
gettimeofday(¤t,NULL);
//I write it in the pipe, if I print the time here i get the result I want
write(p[1], ¤t, sizeof(current));
close(p[1]);
//then I execute the command
}else{
//this is the parent
if (waitpid(pid, &status, 0) > 0){
close(p[1]);
struct timeval inicio;
//Here is the problem I think, once I tried to read it I get a random number
read(p[0], &inicio, sizeof(inicio));
printf(": %ld,%ld\n", inicio.tv_sec,inicio.tv_usec);
}else{
printf("waitpid() failed\n");
}
exit(0);
}
I believe you are expecting that the if block runs in the child process and else block is running in parent process and the fork is called before the code segment. In that case the p in two process are different for two process and they are not connected.
Your read call if throwing a error. Can you check the return value at of the read system call?
The modified code snipped should looks like
if (pipe(p) < 0)
exit(1);
if (fork() < 0)
exit(1);
if (pid == 0){
//I get the time
gettimeofday(¤t,NULL);
//I write it in the pipe, if I print the time here i get the result I want
if (write(p[1], ¤t, sizeof(current)) < 0) {
perror("write");
exit(1);
}
close(p[1]);
//then I execute the command
}else{
if (waitpid(pid, &status, 0) > 0){
close(p[1]);
struct timeval inicio;
//Here is the problem I think, once I tried to read it I get a random number
if (read(p[0], &inicio, sizeof(inicio)) < 0) {
perror("read");
exit(1);
}
printf(": %ld,%ld\n", inicio.tv_sec,inicio.tv_usec);
}else{
printf("waitpid() failed\n");
}
exit(0);
}
i am trying to create a shell program to execute piped command. When i call ls from forked child & wc from parent it works fine. but if i call wc also from forked child parent keeps on waiting (i don't know why this is happening).
void execPiped(char** Args,char** pipedArgs)
{
int pfds[2];
pipe(pfds);
pid_t pid1 = fork();
if (pid1 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid1 == 0) //CHILD 1 EXECUTING
{
close(1); //close STDOUT
dup(pfds[1]); //set pfds as STDOUT
close(pfds[0]); //we don't need this
if (execvp(Args[0], Args) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else {
pid_t pid2 = fork();
if (pid2 == -1)
{
printf("\nFailed forking child..");
return;
}
else if (pid2 == 0) //CHILD 2 EXECUTING
{
close(0); //close STDIN
dup(pfds[0]); //set pfds as STDIN
close(pfds[1]); //we don't need this
if (execvp(pipedArgs[0], pipedArgs) < 0)
{
printf("\nCould not execute command..");
exit(1);
}
}
else { //Parent Executing
//Wating for Children to exit
wait(NULL);
wait(NULL);
}
return;
}
}
I'm a beginner to systems programming and I am currently trying to play around with basic server/client communication using sockets, pipes, etc
More specifically I want to be able to connect as a client and input something like '/bin/echo hello'. The server will then split the string into the command and its arguments, and run the command with a call to a function that calls execl(). For now I'm just testing exec call before trying to pass user input in. Why does the following fail with errno set to EFAULT: bad address?
int do_command(char *command) {
if(strcmp(command, "some_string") == 0) {
pid_t pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
if (execl("/bin/echo", "/bin/echo/", "hello", (char*)NULL) == -1) {
perror("execl");
exit(1);
}
} else {
printf("parent\n");
}
}
}
But running the same code in main() runs just fine with an output of 'hello'
int main() {
pid_t pid = fork();
if(pid == -1) {
perror("fork");
exit(1);
}
if(pid == 0) {
if (execl("/bin/echo", "/bin/echo/", "hello", (char*)NULL) == -1) {
perror("execl");
exit(1);
}
} else {
printf("parent\n");
}
}
Is it not possible to run exec() system calls within functions? Thanks in advance.
I have a function in C which creates a child process and makes it run execvp.
int Execute(char **arg)
{
pid_t pid;
int status;
if ((pid=fork()) == 0)
{
execvp(arg[0],arg);
perror("Execvp error");
exit(1);
}
else if (pid > 0)
{
waitpid(pid, &status, 0);
}
else
{
perror("Fork error");
exit(2);
}
}
Now I want to alter the function to actually run execvp several times (for example 5), and make the parent process wait for all the children to finish. Tried wrapping it all in for loop, but execvp gets executed just once. I know that basically execvp 'replaces' the current program code, but have no idea whether the iteration does not go on.
Thank you for your help!
First, loop around the process creation collecting the child PIDs
pid_t pid[5];
int i;
for (i = 0; i < 5; i++) {
if ((pid[i]=fork()) == 0) {
execvp(arg[0],arg);
perror("Execvp error");
_exit(1);
}
if (pid[i] < 0) {
perror("Fork error");
}
}
Second, loop around the waitpid call for every valid PID.
for (i = 0; i < 5; i++) {
if (pid[i] > 0) {
int status;
waitpid(pid[i], &status, 0);
if (status > 0) {
// handle a process sent exit status error
}
} else {
// handle a proccess was not started
}
}
I am making my own shell in C. This is my basic code for running a process:
pid_t childpid;
int status;
int ret = 0;
if (strcmp(line[0], "exit") == 0) {
return;
}
childpid = fork();
if (childpid >= 0) {
if (childpid == 0) {
ret = execvp(line[0], &line[0]);
if (ret == -1) {
printf("ERROR\n");
exit(0);
}
exit(ret);
} else {
waitpid(childpid, &status, 0);
ret = WEXITSTATUS(status);
}
} else {
perror("fork");
exit(-1);
}
Where line is a "string array" holding the commands to run.
Now say I want to run a background process - I have to use sigset. A parent doesn't wait for a backgrounded child process, right? How do I handle this without the child becoming a background process?