I'm having an issue with a process being stuck on wait. I've been troubleshooting this issue and its the only bug i have currently for my shell program.
The problem is the program should exit when the user enters "exit". However it seems if the user enters an invalid string the program gets stuck on wait(). this results in having to type exit twice to exit instead of once. How do I stop this from happening, how do i exit from the wait() call when a user enters a dumb string?
Steps to reproduce:
compile and run with gcc/g++
type in an expletive of your choice
type exit
notice the program doesnt exit (because its stuck on wait() but prompting
type exit again
program exits
#include <iostream>
#include <unistd.h>
#include "stdlib.h"
#include "stdio.h"
#include <iostream>
#include <string>
#include <sys/wait.h>
#include <sstream>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
using std::string;
using std::cout;
using std::endl;
bool exitstatus;
int argsIndex = 0;
pid_t pid;
int main(void)
{
char * args[100];
string check = "";
while(exitstatus==false)
{
cout<<"tinyshell:~>";
std::getline(std::cin, check);
if(check == "exit"){
exitstatus==true;
}
if(exitstatus==false&&check!="cd..")
{
pid = fork();
perror("");
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
//return 1;
}
else if (pid == 0 ) { /* child process */
execvp(args[0],args);
perror("");
}
else if(check!= "&"){/* parent will wait for the child to complete */
wait(NULL);
perror("");
// cout <<"Child Complete" << endl;
}
else
{
}
}
}
return 0;
};
It may have to do something with this line:
exitstatus==true;
Did you, by any chance meant:
existatus = true;
gcc reports something like this for it anyway (-Wall):
warning: statement has no effect [-Wunused-value]
exitstatus==true;
That's a pretty nice example showing why enabling warnings is a good practice ...
There's also a more subtle problem with your code. You're not checking the result of your execvp function. So basically if you enter some garbage command in your shell your exec will fail but your child process will continue running the same code as the parent (the loop).
Just add an exit(EXIT_FAILURE); after your execvp() call.
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'm trying to make a wrapper around an interactive program. For this I use the combination of pipe, dup2 and poll. All seems to go well until the child terminates. At this step the parent process appears to lose its stdin, which is what I can't seem to understand why.
Here's the code:
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <fcntl.h>
#include <signal.h>
#include <vector>
#include <string>
#include <iostream>
struct SystemFunctionFailure
{
std::string what;
SystemFunctionFailure(std::string const& what) : what(what) {}
};
template<typename T,size_t N> constexpr size_t countof(const T(&)[N]) { return N; }
void readAndPrint(std::string const& what, int fd)
{
std::cerr << "Reading "+what+"\n";
std::vector<char> buffer(1024);
const auto bytesRead=read(fd,buffer.data(),buffer.size());
if(bytesRead==-1)
{
if(errno!=EAGAIN)
throw SystemFunctionFailure("read "+what);
}
else if(bytesRead==0)
{
std::cerr << "EOF reached on "+what+"\n";
exit(0);
}
else
std::cerr << "CONTENTS OF "+what+": "+std::string(buffer.data(),buffer.size())+"\n";
}
int main()
{
try
{
int pipeChildOut[2];
if(pipe(pipeChildOut)==-1) throw SystemFunctionFailure("pipe for child stdout");
int pipeChildErr[2];
if(pipe(pipeChildErr)==-1) throw SystemFunctionFailure("pipe for child stderr");
int pipeChildIn[2];
if(pipe(pipeChildIn)==-1) throw SystemFunctionFailure("pipe for child stdin");
const auto child=fork();
if(child==-1) throw SystemFunctionFailure("fork");
if(child)
{
dup2(pipeChildOut[1],STDOUT_FILENO);
close(pipeChildOut[0]);
dup2(pipeChildErr[1],STDERR_FILENO);
close(pipeChildErr[0]);
dup2(pipeChildIn[0],STDIN_FILENO);
close(pipeChildIn[1]);
execlp("sh","sh","-c","sleep 1; echo Test ; sleep 1; echo Child is exiting... >&2",nullptr);
throw SystemFunctionFailure("execlp returned");
}
else
{
const int childStdErr=pipeChildErr[0];
const int childStdOut=pipeChildOut[0];
dup2(pipeChildIn[1],STDOUT_FILENO);
fcntl(childStdErr,F_SETFL,O_NONBLOCK);
fcntl(childStdOut,F_SETFL,O_NONBLOCK);
fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
while(true)
{
std::cerr << "New iteration of IO loop\n";
pollfd pollfds[]={ // making the indices coincide with .._FILENO
{STDIN_FILENO,POLLIN},
{childStdOut,POLLIN},
{childStdErr,POLLIN},
};
if(poll(pollfds,countof(pollfds),{-1})==-1)
throw SystemFunctionFailure("poll");
std::cerr << "poll returned\n";
for(unsigned i=0;i<countof(pollfds);++i)
std::cerr <<" pollfds["<<i<<"].revents: " << pollfds[i].revents << "\n";
if(pollfds[ STDIN_FILENO].revents&POLLIN) readAndPrint("stdin" ,pollfds[ STDIN_FILENO].fd);
if(pollfds[STDOUT_FILENO].revents&POLLIN) readAndPrint("stdout",pollfds[STDOUT_FILENO].fd);
if(pollfds[STDERR_FILENO].revents&POLLIN) readAndPrint("stderr",pollfds[STDERR_FILENO].fd);
}
}
}
catch(SystemFunctionFailure& ex)
{
perror(ex.what.c_str());
exit(EXIT_FAILURE);
}
}
Here the child closes its original stdin implicitly via dup2, so it seems it shouldn't affect any accesses of the parent to the console input. But for some reason here's what I get as output:
$ g++ test.cpp -o test -std=c++14 && ./test
New iteration of IO loop
poll returned
pollfds[0].revents: 0
pollfds[1].revents: 1
pollfds[2].revents: 0
Reading stdout
CONTENTS OF stdout: Test
New iteration of IO loop
poll returned
pollfds[0].revents: 0
pollfds[1].revents: 0
pollfds[2].revents: 1
Reading stderr
CONTENTS OF stderr: Child is exiting...
New iteration of IO loop
$
I.e. I get the shell prompt, so the parent isn't in the foreground anymore. After this, if I wait several seconds and type a letter, I get this output:
poll returned
pollfds[0].revents: 1
pollfds[1].revents: 0
pollfds[2].revents: 0
Reading stdin
read stdin: Input/output error
I'd like to at least have the parent process retain access to its console input after the child dies. After reading an answer to another question, I think my problem is related, but that answer doesn't answer my question: "How to do it right?".
I think if(child) should be if(child == 0).
From https://linux.die.net/man/2/fork
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child. On failure, -1 is returned in the
parent, no child process is created, and errno is set appropriately.
I'm trying to write a program that forks, the child executes a command and then returns control to the parent. I am having trouble getting the SIGTSTP (C-z) signal to work as intended, though... I want the parent to ignore it, but the child to stop and return control to the parent, so that the child can later be resumed or killed (with a builtin command). I isolated the relevant code into a smaller program just to test it, and it seems like A) the child doesn't stop when C-z is typed, or B) it does stop, but does not return control to the parent (I'm leaning towards this because when I use cat for stdin, it behaves differently after the C-z). Here is my code.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <string>
#include <signal.h>
int main(){
std::cout.setf(std::ios::unitbuf);
std::vector<std::string> vec; vec.push_back("cat");
std::vector<char*> chvec;
for(unsigned int i = 0; i < vec.size(); i++){
chvec.push_back(&vec[i][0]);
}
chvec.push_back(NULL);
vec.erase(vec.begin(), vec.begin() + chvec.size());
char** argv = &chvec[0];
signal(SIGTSTP,SIG_IGN);
pid_t pid;
if((pid = fork()) == 0){
signal(SIGTSTP,SIG_DFL);
/*pid = getpid();
setpgid(pid,pid);*/
std::cout << "before exec" << std::endl;
execvp(argv[0],argv);
perror("exec");
}
else{
//setpgid(pid,pid);
int status;
waitpid(pid,&status,0);
if(WIFEXITED(status) || WIFSIGNALED(status)){
std::cout << "exited or signaled" << std::endl;
}
if(WIFSTOPPED(status)){
std::cout << "process stopped" << std::endl;
}
//std::cout << "process exited" << std::endl;
pause();
}
return EXIT_SUCCESS;
}
It was already pointed out in the comments that you need to fix the undefined behavior as a result of the vec vector being erased. That's the first problem.
I see that your code is checking the exit status of a process using WIFSTOPPED.
Let's review the documentation for the wait(2) system call, and see what it says about this:
WIFSTOPPED(wstatus)
returns true if the child process was stopped by delivery of a
signal; this is possible only if the call was done using WUN‐
TRACED or when the child is being traced (see ptrace(2)).
So, with that information at hand, after fixing the previously mentioned undefined behavior, and after changing your waitpid() call to:
waitpid(pid,&status,WUNTRACED);
Then I was able to send a kill -TSTP <pid> message to the spawned cat process, and obtain the expected
process stopped
message from your test program.
P.S. By stracing the child process, I could see that the child process was receiving the TSTP signal, and stopping just fine. The issue was simply that the parent wasn't handling it, without the required option to waitpid().
I am trying to to fork my c++ program and direct the parents output into the childs input, I am using pipe() and fork(). In the directory of the program there is a file called input.txt. Unfortunately the only output I get is "wc: stdin: read: Bad file descriptor". Does anyone know why this is? If so what am I doing wrong? Thanks
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main(int argc, char *argv[]){
int pipes[2],pid,stdIn,stdOut;
stdIn = dup(0);
stdOut = dup(1);
pipe(pipes);
pid = fork();
if(pid == 0){
dup2(pipes[1],0);
close(pipes[1]);
execlp("wc","wc",NULL);
}
else{
dup2(pipes[0],1);
close(pipes[0]);
std::cout<<"input.txt"<<std::endl;
dup2(stdOut,0);
std::cout<<"parent done\n";
wait(NULL);
}
std::cout<<"after"<<std::endl;
return 0;
}
There are several things that should be fixed in your program:
Use STDIN_FILENO and STDOUT_FILENO instead of 0 and 1. This values may change on different platforms and you have also made a mistake which could probably be avoided if you've used names instead of value, e.g. dup2(stdOut,0); duplicated stdin and you need to duplicate stdout here.
You should close write end of the pipe in both child and parent.
By making wc read from stdin, you are then passing "input.txt" string to it - it will return stats for that string, not for the file. You could either fix it be opening a file descriptor for that file or using exec* with cat.
None of your calls the functions like pipe() or execlp() checks for failure. You should do it like that:
if (pipe(pipes) == -1) {
perror("pipe");
exit(1);
}
You don't need stdIn variable.
You will find fixed code below (it does not implement what I've described in the (5) though):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int pipes[2], pid, stdOut;
stdOut = dup(STDOUT_FILENO);
pipe(pipes);
pid = fork();
if (pid == 0) {
dup2(pipes[0], STDIN_FILENO);
/* You need to close write end of the pipe here */
close(pipes[1]);
execlp("wc", "wc", NULL);
} else {
std::cout << "Parent setup" << std::endl;
dup2(pipes[1], STDOUT_FILENO);
/* You need to close write end of the pipe here as well */
close(pipes[1]);
/* This will only send the string "input.txt" through the pipe, to the
* wc command */
std::cout << "input.txt" << std::endl;
dup2(stdOut, STDOUT_FILENO);
std::cout << "Parent done" << std::endl;
wait(NULL);
}
std::cout << "Program finished" << std::endl;
return 0;
}
EDIT: As suggested in the comment to the other answer, you could simple use xargs wc to read stdint as file argument:
execlp("xargs", "xargs","wc",NULL);
You have the pipe backwards, you have connected the write end of the pipe to the standard input of wc. You will need to close the write end of the pipe in both processes before wc will detect an end of file condition and terminate normally.
You also incorrectly restore the original standard output to the standard input of the parent.
Furthermore wc will by default not interpret standard input as a list filenames and will therefore not read input.txt.
Which function is used in C++ stdlib to exit from program execution with status code?
In Java, there's:
System.exit(0)
Assuming you only have one thread:
#include <iostream>
int main()
{
std::cout << "Hello, World!\n";
return(0);
// PROGRAM ENDS HERE.
std::cout << "You should not see this.\n";
return(0);
}
Output:
Hello, World!
The return(0); can be placed anywhere you like - it'll end int main(), and hence your program.
Alternatively, you can call exit(EXIT_SUCCESS); or exit(EXIT_FAILURE); from anywhere you like:
/* exit example */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
FILE * pFile;
pFile = fopen("myfile.txt", "r");
if(pFile == NULL)
{
printf("Error opening file");
exit (1);
}
else
{
/* file operations here */
}
return 0;
}
In addition to the other responses you can also invoke abort, terminate, quick_exit (exits without calling destructors, deallocating etc; hence the name)
terminate calls abort by default but can call any terminate handler you set.
Example usage of abort and set_terminate (to se the handler used by terminate), quick_exit can be called (see example #2)
// set_terminate example
#include <iostream> // std::cerr
#include <exception> // std::set_terminate
#include <cstdlib> // std::abort
void myterminate () {
std::cerr << "terminate handler called\n";
abort(); // forces abnormal termination
}
int main (void) {
std::set_terminate (myterminate);
throw 0; // unhandled exception: calls terminate handler
return 0;
}
quick_exit/at_quick_exit example:
/* at_quick_exit example */
#include <stdio.h> /* puts */
#include <stdlib.h> /* at_quick_exit, quick_exit, EXIT_SUCCESS */
void fnQExit (void)
{
puts ("Quick exit function.");
}
int main ()
{
at_quick_exit (fnQExit);
puts ("Main function: Beginning");
quick_exit (EXIT_SUCCESS);
puts ("Main function: End"); // never executed
return 0;
}
I'm not entirely certain why one would call quick_exit but it exists and thus I should provide documentation for it (courtesy of http://www.cplusplus.com/reference )
Additionally one can call at_exit as the equivalent of at_quick_exit.
Admittedly I am not all that familiar with set_terminate and terminate as I don't call them myself, but I would guess you could use quick_exit as a terminate handler if you wanted; or a custom one (but please don't quote me on that).
In C++, you can use exit(0)
for example:
switch(option){
case 1:
//statement
break;
case 2:
//statement
exit(0);