I am running this basic shell program in another shell. I am unable to figure out why my shell doesn't keep running after "ls" executes. I dont have an exit for it but it goes back to original shell. I have to run my shell program every time if want to use it. i figured thats what the fork() is supposed to do. I only want my shell to exit using the exit command which i coded with the if else statement. Any suggestions would be much appreciated. Oh and disregard the gettoks() parser function, i couldn't figure out how to use it for input so i wrote if else statements for the string input cmSTR rather then using the gettoks() parser. Mainly because i couldn't figure how to pass the input into it
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <cstdlib>
#include <sys/wait.h>
using namespace std;
// Initializing counters for trapping
static int cc_counter = 0;
static int cz_counter = 0;
static int cq_counter = 0;
//Functions for trap signal handler
void cc_handler( int signo )
{
++cc_counter;
}
void cz_handler( int signo )
{
++cz_counter;
}
void cq_handler( int signo )
{
++cq_counter;
}
//*********************************************************
//
// Extern Declarations
//
//*********************************************************
using namespace std;
extern "C"
{
extern char **gettoks();
}
//*********************************************************
//
// Main Function
//
//*********************************************************
int main( int argc, char *argv[] )
{
// local variables
int ii;
char **toks;
int retval;
// initialize local variables
ii = 0;
toks = NULL;
retval = 0;
char buf[1000];//Initialize of size for current working directory
string cmSTR;//String to hold input
int status;//Initialization of status for fork()
pid_t pid;//Declaration of pid
// main (infinite) loop
while( true )
{
signal( SIGINT, cc_handler );// Traps Ctrl+C
signal( SIGTSTP, cz_handler);// Traps Ctrl+Z
signal( SIGQUIT, cq_handler);// Traps Ctrl+\
//prompt and show current working directory
cout <<("RS_SHELL:") << getcwd(buf,1000) << "\t";
getline(cin ,cmSTR);//read input from keyboard
// if else loop to switch based on command input
if(cmSTR == "ls")// if ls, then execute arguement
{
execl( "/bin/ls", "ls", NULL );//System call to execute ls
}
else if(cmSTR == "exit")//if exit, then execute block of code
{
cout << "Ctrl C entered: " << ++cc_counter << "times"<< endl;
cout << "Ctrl Z entered: " << ++cz_counter << "times"<< endl;
cout << "Ctrl Back Slash entered: " << ++cq_counter << "times"<< endl;
exit(1);
}
else if(cmSTR == "guish")// if guish, execute guish shell
{
execvp("guish", NULL);
}
//if input is not any of previous commands then fork()
else if(cmSTR != "ls" && cmSTR != "exit" && cmSTR != "guish" && cmSTR != "\n")
{
pid = fork();
if (pid < 0)//Loop to fork parent and child process
{
fprintf(stderr, "Fork Failed");
exit(-1);
}
else if (pid == 0)//Child process
{
execvp("guish", NULL);//system call to execute guish shell
}
else //Parent process
{
waitpid( -1, &status,0);
exit(0);
}
}
// get arguments
toks = gettoks();
if( toks[0] != NULL )
{
// simple loop to echo all arguments
for( ii=0; toks[ii] != NULL; ii++ )
{
cout << "Argument " << ii << ": " << toks[ii] << endl;
}
if( !strcmp( toks[0], "exit" ))
break;
}
}
// return to calling environment
return( retval );
}
As you suspected, execl and its related functions overlay the current process with a new process. Thus, after the execl call that starts ls, your program won't exist any more to keep running.
If you want your shell program to stay around after running ls, you'll need to fork() before the call execl( "/bin/ls", "ls", NULL );.
Also, if you want the output from ls to appear in the same console as your shell, as I think you might be intending, you will need to pipe the output from ls back to your shell and then write that output onto your shell's console. See Writing my own shell… stuck on pipes?, for instance.
Related
I have a multiprocessing application that works well, except the parent process seems to exit twice.
I left out some of the code for simplification. Basically, I use libcurl (I wrote my own abstraction layer for it) to get JSON data from a server (left the code for this out) and then the simdjson library to iterate through it and run worker processes where required.
At the end I wait for all child processes (in the parent process) to terminate before printing "done". I can see however, that my program is printing "done" twice. I presume once after it's done in the for loop to create all the worker processes and then again once the last child returns. At least that is what I can see from the output on the console, as the child processes print to the console as well. However, given that I use if (pid_fork > 0), i.e. I must be in the parent process, any subsequent code should be executed only once. What am I doing wrong?
#include <iostream>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "simdjson.h"
int main (int argc, char *argv[])
{
/* some other code */
pid_t pid_fork;
std::vector<int> v_pid;
// loop through json
for (simdjson::dom::element mq_item : json_mq_items)
{
pid_fork = fork();
if (pid_fork == -1)
{
std::cout << "error: could not fork process" << std::endl;
return EXIT_FAILURE;
} else if (pid_fork > 1) // parent process
{
v_pid.push_back(pid_fork);
}
else // child process (pid_fork == 0)
{
char *argv[] = { (char*)(std::string("foo")), NULL };
if (execv((static_cast<std::string>("./foo")).c_str(), argv) == -1)
{
std::cout << "could not load child" << std::endl;
return EXIT_FAILURE;
}
}
}
// in parent process only
if (pid_fork > 0)
{
// Wait for all child processes to terminate
for (size_t i = 0; i < v_pid.size(); i++)
{
while (waitpid(v_pid[i], NULL, 0) > 0);
}
/* some other code */
std::cout << "done" << std::endl;
return EXIT_SUCCESS;
}
}
I can't seem to find any explanation for sending an int through a named pipe, although I've seen many similar things.
Right now the program takes user input for a Collatz conjecture, but it exits as if the input if 0.
The parent process takes in input and sends it to a child process.
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int pid;
int fd[2];
int input;
//create child
pid = fork();
if (pid > 0){
//parent process
wait(NULL);
close(fd[0]);
std::cout << "Enter an int value: ";
std::cin >> input;
write(fd[1], &input, sizeof(input));
close(fd[1]);
}
else if (pid == 0){
close(fd[1]);
//child process
read(fd[0], &input, sizeof(input));
int workingNum = input;
close(fd[0]);
if (workingNum > 0){
while (workingNum != 1){
//even
if(workingNum % 2 == 0){
workingNum = workingNum / 2;
std::cout << workingNum;
std::cout << " ";
}
else {
workingNum = 3 * workingNum + 1;
std::cout << workingNum;
std::cout << " ";
}
}
}
}
return 0;
}
Two bugs:
As jtbandes points out, you have to actually call the pipe(2) function to create a pipe. So do pipe(fd) before the fork(). (g++ with -Wall -O will give you a warning about fd being uninitialized.)
You have a classic deadlock: the parent calls wait(NULL) so it won't continue on to write to the pipe until the child has exited. But the child is trying to read from the pipe and won't continue on to exit until the parent has written something. So both processes remain stuck. You probably want to move the wait(NULL) to the end of the parent's code.
After those changes it works for me. Error checking on all the system calls would be nice, however.
wait(), exit() and signals are forbidden
only pipes allowed
A user gives an integer positive number-N and N-processes are created, father creates a child, that child becomes a father and creates another child and so on. Each one of the first processes (N-1) should wait to finish its process-child first and then itself. The initial process should print "1-My Process ID: ", the next process that's been created the number "2 My process ID: and my father's ID:" and so on.
my code. i don't have wait or exit instead i use return(-1).
but i didn't managed to print accordingly the numbers 1 my process id..., 2 my process id..., 3 my process id... and so on.
any ideas?
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
/* Read characters from the pipe and echo them to stdout. */
void read_from_pipe (int file)
{
FILE *stream;
int c;
stream = fdopen (file, "r");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
}
/* Write some random text to the pipe. */
void write_to_pipe (int file)
{
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, "\n");
fprintf (stream, " ");
fclose (stream);
}
int main (void)
{
pid_t pid;
int mypipe[2];
int j = 1;
int i;
cout << "\nassume father is by default the first process\n" << "Please enter how child-processes you want: ";
cin >> i;
for( ; j < i; j++)
{
/* Create the pipe. */
if (pipe (mypipe))
{
fprintf (stderr, "Pipe failed.\n");
return (-1);
}
/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0)
{
/* This is the child process. Close other end first. */
pid = getpid();
close (mypipe[1]);
read_from_pipe (mypipe[0]);
printf("Child's ID: %d\n",pid);
sleep(0);
}
else if (pid > (pid_t) 0)
{
/* This is the parent process. Close other end first. */
pid = getpid();
close (mypipe[0]);
write_to_pipe (mypipe[1]);
printf("Dad's ID: %d\n",pid);
sleep(0);
}
else
{
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return (-1);
}
}//end for
//close (mypipe[0]);
//write_to_pipe (mypipe[1]);
// printf("Dad's ID: %d\n",pid);
return (-1);
}// EOP
Recursion could be simpler than iteration because you want each child to in turn create another child. The trick to avoid wait is to have each parent to read on the read end of the pipe, and to have the child to close the write end just before returning without writing anything. Because the read will be blocked until either something has been written or the other end is closed.
You cannot be sure of the order in which the processes will actually end because you do not call wait, but you are sure that a parent cannot end before its childs has terminated its job.
Code could be:
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
using std::cout;
using std::cin;
using std::cerr;
using std::endl;
int start_child(int i, int j) {
int my_pipe[2];
pid_t parent_pid, pid;
/* Create the pipe. */
if (pipe (my_pipe))
{
cerr << "Pipe failed." << endl;
return (-1);
}
/* Create the child process. */
parent_pid = getpid();
pid = fork ();
if (pid == (pid_t) 0) {
/* child */
pid = getpid();
close(my_pipe[0]);
cout << "I'm child " << j << "- my pid is " << pid <<
" - my parent's pid is " << parent_pid << endl;
if (i > 1) start_child(i - 1, j + 1);
if (pid == getpid()) cout << "End of child "<< j << endl;
close(my_pipe[1]);
}
else if (pid == (pid_t) -1) {
perror("forking");
close(my_pipe[0]);
close(my_pipe[1]);
return -1;
}
else {
/* parent */
close(my_pipe[1]);
char buf[2];
read(my_pipe[0], buf, 2); // wait for the child to close its pipe end
close(my_pipe[0]);
}
return 0;
}
int main (void)
{
pid_t pid = getpid();
int i;
cout << "\nassume father is by default the first process\n" << "Please enter how child-processes you want: ";
cin >> i;
cout << "I'm parent - my pid is " << pid << endl;
int cr = start_child(i, 1);
if (pid == getpid()) cout << "End of parent" << endl;
return cr;
}// EOP
I am working on a code where it will do Linux command piping. Basically in my code, it will parse the user input command, then run it using the execvp function.
However, to do this, I would need to know the command, as well as its parameters. I have been trying to get the parsing to work correctly, however, it seems that when I do a test case, the output from both of the arrays that store their respective programs is the same. The commands/parameters are stored in a char array called prgname1 and prgname2.
For instance, if I were to run my program with the parameter "ps aux | grep [username]", then the output of prgname1[0] and prgname2[0] are both [username]. They are supposed to be ps and grep, respectively.
Can anyone take a look at my code and see where I might be having an error which is causing this?
Thanks!
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
#define MAX_PARA_NUM 5
#define MAX_COMMAND_LEN 1024
using namespace std;
int main(int argc, char *argv[]) {
char *prgname1[MAX_PARA_NUM], *prgname2[MAX_PARA_NUM];
char command[MAX_COMMAND_LEN];
int pfd[2];
pipe(pfd);
pid_t cid1, cid2;
char *full = argv[1];
char str[MAX_COMMAND_LEN];
int i = 0;
int j = 0;
int k = 0;
int ind = 0;
while (ind < strlen(full)) {
if (full[ind] == ' ') {
strncpy(command, str, i);
cout << command << endl;
prgname1[j] = command;
j++;
i = 0;
ind++;
}
else {
str[i] = full[ind];
i++;
ind++;
}
if(full[ind] == '|') {
i = 0;
j = 0;
ind+=2;
while (ind < strlen(full)) {
if (full[ind] == ' ') {
strncpy(command, str, i);
cout << command << endl;
prgname2[j] = command;
j++;
i = 0;
ind++;
}
else {
str[i] = full[ind];
i++;
ind++;
}
if (ind == strlen(full)) {
strncpy(command, str, i);
cout << command << endl;
prgname2[j] = command;
break;
}
}
}
}
// test output here not working correctly
cout << prgname1[0] << endl;
cout << prgname2[0] << endl;
// exits if no parameters passed
if (argc != 2) {
cout << "Usage:" << argv[0] << endl;
exit(EXIT_FAILURE);
}
// exits if there is a pipe error
if (pipe(pfd) == -1) {
cerr << "pipe" << endl;
exit(EXIT_FAILURE);
}
cid1 = fork(); // creates child process 1
// exits if there is a fork error
if (cid1 == -1 || cid2 == -1) {
cerr << "fork";
exit(EXIT_FAILURE);
}
// 1st child process executes and writes to the pipe
if (cid1 == 0) {
char **p = prgname1;
close(1); // closes stdout
dup(pfd[1]); // connects pipe output to stdout
close(pfd[0]); // closes pipe input as it is not needed
close(pfd[1]); // closes pipe output as pipe is connected
execvp(prgname1[0], p);
cerr << "execlp 1 failed" << endl;
cid2 = fork();
}
// 2nd child process reads from the pipe and executes
else if (cid2 == 0) {
char **p = prgname2;
close(0); // closes stdin
dup(pfd[0]); // connects pipe input to stdin
close(pfd[0]); // closes pipe input as pipe is connected
close(pfd[1]); // closes pipe output as it is not needed
execvp(prgname2[0], p);
cerr << "execlp 2 failed" << endl;
}
else {
sleep(1);
waitpid(cid1, NULL, 0);
waitpid(cid2, NULL, 0);
cout << "Program successfully completed" << endl;
exit(EXIT_SUCCESS);
}
return 0;
}
argv[1] gives you the first argument on the command line - not the entire command line. If you want the full list of command line arguments passed into the process, you will need to append argv[1], argv[2], ..., argv[argc - 1] together with a space between each.
Additionally, when you process it, you are setting the pointer for your prgname1[index] to command, so every time you set a given character pointer, they are all pointing to the same location (hence, they are all the same value). You need to allocate space for each element in prgname1 and copy command into it (using strncpy). Alternatively, using std::string and std::vector eliminates much of your current code.
I am forking a number of processes and I want to measure how long it takes to complete the whole task, that is when all processes forked are completed. Please advise how to make the parent process wait until all child processes are terminated? I want to make sure that I stop the timer at the right moment.
Here is as a code I use:
#include <iostream>
#include <string>
#include <fstream>
#include <sys/time.h>
#include <sys/wait.h>
using namespace std;
struct timeval first, second, lapsed;
struct timezone tzp;
int main(int argc, char* argv[])// query, file, num. of processes.
{
int pCount = 5; // process count
gettimeofday (&first, &tzp); //start time
pid_t* pID = new pid_t[pCount];
for(int indexOfProcess=0; indexOfProcess<pCount; indexOfProcess++)
{
pID[indexOfProcess]= fork();
if (pID[indexOfProcess] == 0) // child
{
// code only executed by child process
// magic here
// The End
exit(0);
}
else if (pID[indexOfProcess] < 0) // failed to fork
{
cerr << "Failed to fork" << endl;
exit(1);
}
else // parent
{
// if(indexOfProcess==pCount-1) and a loop with waitpid??
gettimeofday (&second, &tzp); //stop time
if (first.tv_usec > second.tv_usec)
{
second.tv_usec += 1000000;
second.tv_sec--;
}
lapsed.tv_usec = second.tv_usec - first.tv_usec;
lapsed.tv_sec = second.tv_sec - first.tv_sec;
cout << "Job performed in " <<lapsed.tv_sec << " sec and " << lapsed.tv_usec << " usec"<< endl << endl;
}
}//for
}//main
I'd move everything after the line "else //parent" down, outside the for loop. After the loop of forks, do another for loop with waitpid, then stop the clock and do the rest:
for (int i = 0; i < pidCount; ++i) {
int status;
while (-1 == waitpid(pids[i], &status, 0));
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
cerr << "Process " << i << " (pid " << pids[i] << ") failed" << endl;
exit(1);
}
}
gettimeofday (&second, &tzp); //stop time
I've assumed that if the child process fails to exit normally with a status of 0, then it didn't complete its work, and therefore the test has failed to produce valid timing data. Obviously if the child processes are supposed to be killed by signals, or exit non-0 return statuses, then you'll have to change the error check accordingly.
An alternative using wait:
while (true) {
int status;
pid_t done = wait(&status);
if (done == -1) {
if (errno == ECHILD) break; // no more child processes
} else {
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
cerr << "pid " << done << " failed" << endl;
exit(1);
}
}
}
This one doesn't tell you which process in sequence failed, but if you care then you can add code to look it up in the pids array and get back the index.
The simplest method is to do
while(wait() > 0) { /* no-op */ ; }
This will not work if wait() fails for some reason other than the fact that there are no children left. So with some error checking, this becomes
int status;
[...]
do {
status = wait();
if(status == -1 && errno != ECHILD) {
perror("Error during wait()");
abort();
}
} while (status > 0);
See also the manual page wait(2).
Call wait (or waitpid) in a loop until all children are accounted for.
In this case, all processes are synchronizing anyway, but in general wait is preferred when more work can be done (eg worker process pool), since it will return when the first available process state changes.
I believe the wait system call will accomplish what you are looking for.
for (int i = 0; i < pidCount; i++) {
while (waitpid(pids[i], NULL, 0) > 0);
}
It won't wait in the right order, but it will stop shortly after the last child dies.