I tried to write simple fork-and-exec application with the following code
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
int
spawn(char *program, char *arg_list[])
{
pid_t child_pid;
child_pid = fork();
if (child_pid != 0)
return child_pid;
else {
execvp(program, arg_list);
fprintf(stderr, "an error occured\n");
exit(EXIT_FAILURE);
}
}
int
main()
{
int child_stat;
char *arg_list[] = {
"ls",
"-l",
"/",
NULL
};
spawn("ls", arg_list);
printf("return to parent\n");
return 0;
}
Every goes fine, but child after becoming ls does not terminate.
Shell looks like
./main
return to parent
-- ls output here --
But command prompt does not appear, so I assume that one process hangs and the reason is not obvious for me. Can you, please, point to my mistake.
Thanks in advance.
I believe that it works correctly. However, the order of execution of the child and parent are not what you expect, so you see output you don't understand. On my Arch linux box (kernel 4.xx), it works fine, but the parent process returns first, leaving ls to overwrite and otherwise garble the command prompt. Do a wait() on the child process to get execution to happen in a specific order. Add a couple of lines of code after the spawn() call:
spawn("ls", arg_list);
printf("return to parent\n");
wait(&child_stat);
printf("Waited on child\n");
return 0;
After the fork() call, the parent process will call wait(), which won't return until a child process (if there is at least one) exits. Since there's only one child process, the output of ls occurs before the command prompt gets written out, and thus you will see what you believe you should see.
Related
My Code
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
char * arg_list[3];
arg_list[0] = "ls";
arg_list[1] = "-l";
arg_list[2] = 0;
char *arg_list2[3];
arg_list2[0] = " ps";
arg_list2[1] = "-ef";
arg_list2[2] = 0;
for(int i=0;i<5;i++){ // loop will run n times (n=5)
if(fork() == 0) {
if (i == 0){
execvp("ls", arg_list);
}else if(i==1){
execvp("ps" , arg_list2);
}else if(i>1){
printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
}
for(int i=0;i<5;i++) // loop will run n times (n=5)
wait(NULL);
}
ME trying to modify it
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
for(int i=0;i<5;i++){ // loop will run n times (n=5)
if(fork() == 0) {
printf("[son] pid %d from [parent] pid %d\n",getpid(),getppid());
execlp(argv[i],argv[i],argv[i+1],(char*)NULL);
exit(0);
}
}
for(int i=0;i<5;i++) // loop will run n times (n=5)
wait(NULL);
}
-- NEED GUIDANCE AND UNDERSTANDING
I am trying to make my own tiny little shell program. When I run my first code works fine, runs all commands on the command line. But I cannot know and define all commands the user might enter. So i am trying to get a base code which could run any commands single or multiple entered by user. I tried using execlp where it does not compile saying argv is not defined which is true as i don't want to specifically define it.
I am trying to make my own tiny little shell program. When I run my first code works fine, runs all commands on the command line. But I cannot know and define all commands the user might enter.
For sure.... A shell program purpose is basically:
Read user input
Execute user input
Return result of execution.
There's nothing in your code that read user input....
So i am trying to get a base code which could run any commands single or multiple entered by user.
So read user input ;-)
I tried using execlp where it does not compile saying argv is not defined which is true as i don't want to specifically define it.
For sure ... but how would GCC guessed that `argv[]̀ must be automaticallty filled with user input ?
There's nothing automatic when coding in C language. You have to manage this manually.
Also, note that argc, argv et envp are usually reserved for main() function:
main(int argc, char **argv, char **envp)
So you may use something else to build your command array.
In pseudo code, what you must implement is:
quit=0
while (quit = 0) {
command_to_run = read_user_input();
if (command_to_run == "exit") {
quit = 1;
} else {
execute(command_to_run);
}
}
Some advices:
Try to use more functions. For example, implement a fork_and_run(char **cmd) function to fork and then execute command provided by the user. Il will make your code more readable and easy to maintain.
Read carefully manpages: everything you should know (like, for example, the fact that array provided to execvp() must be NULL-terminated) is written in it.
Your debugging messages should be printed to stderr. The result of the command run must be printed to stdin, so use fprintf() instead of printf() to write to the correct stream.
I would use a #define debug(x) fprintf(stderr, x) or something similar for debugging output so that you can easily disable later ;-)
I'm trying to predict the output of the following code, any explanation of how many time a will be printed and why?
#include <stdio.h>
#include <unistd.h>
main() {
fork()&&fork()&&fork();
printf ("a\n");
}
I believe you had already figured out how many time it will print a which is 4 times.
So let now see why.
Let's add some for information to output to get more understanding.
#include <stdio.h>
#include <unistd.h>
void main() {
printf("Main pid:%d\n",getpid());
fork() && fork() && fork();
printf ("a\tpid:%d\tppid:%d\n",getpid(),getppid());
}
Output of this code will be looks like below. Note, value of pip and ppid in your case may be different.
Main pid:4417
a pid:4417 ppid:2398
a pid:4418 ppid:4417
a pid:4420 ppid:4417
a pid:4419 ppid:4417
Now you can see from pid details that printf() executed for one main(parent) process and three child process.
We rewrite line
fork() && fork() && fork();
as below
if(fork()){
if(fork()){
if(fork()){
}
}
}
Above both code doing same thing. With second code we can write flow chart as below.
I believe this will explain your question why.
I'm trying to simulate a pipe behavior on Ubuntu's Terminal, for example the command:
"echo hello | wc".
Please assume I got the tokens from stdin, handled everything correctly and now These are the commands I "received" from the user who typed them in the shell for me to handle.
I'm trying to create two processes. Using a pipe, in the first process, I point the file descriptor of the writing edge of the pipe to stdout. The second process should read into stdin with the reading edge of the pipe what execvp(..) returned.?
Here is the code I wrote:
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
char* fcmd[] = {"echo", "hello", NULL};
char* scmd[] = {"wc", NULL};
pid_t pid;
int pipe_des[2];
int i;
pipe(pipe_des);
for(i = 0; i < 2; i++)
{
pid = fork();
if (pid ==0)
{
switch (i)
{
case 0: // FIRST CHILD
{
dup2(pipe_des[1], STDOUT_FILENO);
close(pipe_des[0]);
execvp(fcmd[0], fcmd);
exit(0);
}
case 1: //SECOND CHILD
{
dup2(pipe_des[0], STDIN_FILENO);
close(pipe_des[1]);
execvp(scmd[0], scmd);
exit(0);
}
}
}
else if (pid < 0)
exit(EXIT_FAILURE);
return EXIT_SUCCESS;
}
I get: " amirla#ubuntu:~/Desktop/os/class/ex4$ 1 1 6 "
Like it should, but why he's printing the bash cwd first? The pipe seems to work because I get what I should, according to the length of the word I'm sending with the echo command(in the main()). After that the cursor just waits on the line below for another command without showing me the bash pwd. (maybe stdin is waiting?)
I've looked in many posts on here as well as on other websites and I still can't seem to find a solution to my problem. Any help would be appreciated. Thanks in advance.
Note: Please Ignore checking for errors, I've delete them to make the code shorter so assume they exist.
Why do I get a prompt before the output?
Your main process doesn't wait for the children to finish. What you see is:
Main starts
Main creates children
Main exits
BASH prints prompt
Children start their work
To prevent this, you need to wait for the children. See How to wait until all child processes called by fork() complete?
In your case, it's enough to add
waitpid(-1, NULL, 0);
after the loop.
I'm new to programming with linux and I was trying to understand how fork() and exec functions work. To make it easier for myself, I created a simply Dummy executable (with gcc -o Dummy.exe ...) and tried to call fork function so I can replace the child with the Dummy.exe executable I have created.
The problem I'm coming accross is that when I run the code, it shows me the contents of the Dummy.exe, however, I don't see anything past that - meaning, I don't see the parent process ending.
When I run my code Ex1.cpp, I get the output:
Program is Running
--- ****** ---
Ended
me#mdev>
The only way I can get the program to end is by pressing return key - you will see a blank line after word Ended.
Here is the code in my Ex1.cpp
#include <iostream>
using namespace std;
int main()
{
pid_t retVal;
int newStatus;
switch(retVal = fork())
{
case -1:
cout<<"Error occured with fork"<<endl;
break;
case 0:
cout<<"Child forked"<<endl;
newStatus = execl("Dummy.exe","Dummy.exe", NULL);
break;
default:
cout<<"Parent has a new child: "<<retVal<<endl;
}
cout<<"Ended ..."<<endl;
return 0;
}
My Dummy.cpp code is below:
#include <iostream>
using namespace std;
int main()
{
cout<<"Program is Running"<<endl;
cout<<"--- ****** ---"<<endl;
cout<<"Ended"<<endl;
return 0;
}
My background is Windows development and all this is new for me - I appreciate your help.
#include <iostream>
using namespace std;
int main ()
{
pid_t retVal;
int newStatus;
int returnStatus;
if (retVal = fork() < 0)
{
cout << "Error on fork" << endl;
exit (1);
}
// Child process
else if (retVal == 0)
{
// No code is executed after an exec statement
newStatus = execl("./Dummy", "Dummy", NULL);
}
else
{
// This waits for the child to finish and clean up
waitpid(retVal, &returnStatus, NULL);
}
return returnStatus;
}
It is not a good idea to use a switch statement in your case since no code is executed after an exec statement. You can read up on that further by reading the man page at the command prompt by typing man 2 exec. Also it is always a good idea to wait for the child to exit successfully which is what the waitpid function does. Try this and let me know if it works and if you have any questions as well.
I try to fork() a child which will run an ls command.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
if (fork()==0){ //child
execlp("ls", "ls", "-l", (char*)0);
exit(1);
}
fflush(stderr); //doesn't fix my problem
fflush(stdout); //doesn't fix my problem
exit(0);
}
This works fine but the cursor gets stuck after the execution of the child. I have to press the enter key to get back the terminal. Why is that?
Your main process exits before the child process is done. Wait for the child process to exit using wait() or waitpid().