Check whether a command executed successfully WITHOUT system functions using fork() - c++

fork() creates a new process by duplicating the calling process in the separate memory space. The execution of the forked process can be checked by checking the pid_t returned value by fork() function.
I used fork() to create some concurrent processes from a single parent. These processes are commands in a shell that no need to be executed.
I'm wondering how I can check whether the command is a valid command that can be executed or not without using the system functions and/or execute them.
#include <iostream>
#include <unistd.h>
#include <string>
int main(){
std::string command = "/bin/ls";
//std::string invalidCommand = "/bin/123";
pid_t pid = fork();
if(pid == -1 || `here I want to check if the command is executable without execution`){
std::cout << "Error in forking or Command is not executable" << std::endl;
}
else if (pid == 0){
std::cout << "Process has been forked and valid to execute" << std::endl;
}
return 0;
}

These processes are commands in a shell that no need to be executed.
I don't fully understand what you want to say with this sentence. However, I think you are not aware how fork() works and how system() is related to fork():
As you already found out, fork() duplicates a running process; this means that the program is now running twice and all variables exist twice (just like if you run your program twice).
system() internally uses fork() to create a copy of the process; in the newly created process it uses one of the exec() variants (such as execvp()) to replace the program in the new process by another program.
Then it uses one of the wait() variants (such as waitpid()) to wait for the new process to finish:
fflush(stdout);
fflush(stderr);
int newpid = fork();
if(newpid == 0)
{
execlp("ls", "ls", "./subdirectory", NULL);
std::cerr << "Could not start \"ls\".\n";
fflush(stderr);
_exit(1);
}
if(newpid < 0)
{
std::cerr << "Not enough memory.\n";
}
else
{
int code;
waitpid(newpid, &code, 0);
if(code == 0) std::cout << "\"ls\" was successful.";
else std::cout << "\"ls\" was not successful.";
}
If you want to have "special" behaviour (such as re-directing stdout to a file), you typically don't use the system() function but you will implement the program the way it is shown above.
I'm wondering how I can check whether the command is a valid command ...
Without running the program it is nearly impossible to find out if some command is executable:
It is possible to find out if a program with some name (e.g. "/usr/bin/ls") is existing and marked as executable using the access() function (this is what command -v or test -x do).
However, this test will not detect if a file mistakenly has the x flag set although the file is a document file and not a program. (This is often the case for files on Windows-formatted media.)
If wait() returns the value passed to the _exit() function, it is also difficult to check if the reason is that exec() failed (this means that the program could not be executed) or if the program that has been started returned the same code that we use in our _exit() function.
You can send some information from the new process to the original process if the exec() function has returned. The exec() function will never return on success. However, sending this information is not that easy: Just setting a variable will not work:
int ls_failed = 0;
int pid = fork();
if(pid == 0)
{
execlp("ls", "ls", "./subdirectory", NULL);
ls_failed = 1;
_exit(1);
}
wait(pid, NULL, 0);
if(ls_failed > 0) std::cout << "Starting \"ls\" failed.";
The two processes behave like you started the programs twice; therefore both processes have their own variables, so the variable ls_failed in the newly started process is not identical to the variable ls_failed in the original process.
std::cout << ...
Please note that std::cout probably internally performs an fwrite(...,stdout). This function will not write directly to the terminal but it will write to some buffer. When the buffer is full, all data is written at once.
When calling fork() the buffer is duplicated; when using _exit() or exec(), the data in the buffer is lost.
This may lead to weird effects:
std::cout << "We are doing some fork() now.";
int pid = fork();
if(pid == 0)
{
std::cout << "\nNow the child process is running().";
_exit(0);
}
waitpid(pid, NULL, 0);
std::cout << "\nThe child process has finished.\n";
Depending on the buffer size we could get the following output:
We are doing some fork() now.
Now the chi ng some fork() now.
The child process has finished.
Therefore, we should perform a fflush(stdout) and a fflush(stderr) before using fork(), an exec() variant or _exit() unless you know that the corresponding buffer (stdout for std::cout and stderr for std::cin) is empty.

you can use the system call wait and check the return value of the command that you attempted to execute, other than that fork would really help you. try reading the man page of wait.
https://www.man7.org/linux/man-pages/man2/wait.2.html

Related

How to correctly use pipe to transfer data from child process to parent process?

I'm trying to create a function that returns true if execvp is successful and false if it is not. Initially, I didn't use a pipe and the problem was that whenever execvp failed, I get 2 returns, one false and one true (from the parent). Now that I'm piping, I'm never getting a false returned when execvp fails.
I know there are a lot related questions and answers on this topic, but I can't seem to narrow down where my particular error is. What I want is for my variables return_type_child, return_type_parent, and this->return_type to all contain the same value. I expected that in the child process, execvp would fail so the next lines would execute. As a result, I thought that the 3 variables mentioned would all be false, but instead when I print out the value in this->return_type, 1 is displayed.
bool Command::execute() {
this->fork_helper();
return return_type;
}
void Command::fork_helper() {
bool return_type_child = true;
int fd[2];
pipe(fd);
pid_t child;
char *const argv[] = {"zf","-la", nullptr};
child = fork();
if (child > 0) {
wait(NULL);
close(0);
close(fd[1]);
dup(fd[0]);
bool return_type_parent = read(fd[0], &return_type_child, sizeof(return_
this->return_type = return_type_parent;
}
else if (child == 0) {
close(fd[0]);
close(1);
dup(fd[1]);
execvp(argv[0], argv);
this->return_type = false;
return_type_child = false;
write(1,&return_type_child,sizeof(return_type_child));
}
return;
}
I've also tried putting a cout statement after execvp(argv[0], argv), which never ran. Any help is greatly appreciated!
From the code, it seems to be an XY problem (edit: moved this section to the front due to a comment that confirms this). If the goal is to get the exit status of the child, then for that there is the value that wait returns, and no pipes are required:
int stat;
wait(&stat);
Read the manual of wait to figure out how to read it. The value of stat can be tested as follows:
WEXITSTATUS(stat) - If WIFEXITED(stat) != 0, then this are the lower 8 bits of child's call to exit(N) or the return value from main. It might work correctly without checking WIFEXITED, but the standard does not specify that.
WTERMSIG(stat) - If WIFSIGNALED(stat) != 0, then this is the signal number that caused the process to exit (e.g. 11 is segmentation fault). It might work correctly without checking WIFSIGNALED, but the standard does not specify that.
There are several errors in the code. See the added comments:
void Command::fork_helper() {
// File descriptors here: 0=stdin, 1=stdout, 2=stderr
//(and 3..N opened in the program, could also be none).
bool return_type_child = true;
int fd[2];
pipe(fd);
// File descriptors here: 0=stdin, 1=stdout, 2=stderr
//(and 3..N opened in the program, could also be none).
// N+1=fd[0] data exhaust of the pipe
// N+2=fd[1] data intake of the pipe
pid_t child;
char *const argv[] = {"zf","-la", nullptr};
child = fork();
if (child > 0) {
// This code is executed in the parent.
wait(NULL); // wait for the child to complete.
This wait is a potential deadlock: if the child writes enough data to the pipe (usually in the kilobytes), the write blocks and waits for the parent to read the pipe. The parent wait(NULL) waits for the child to complete, which which waits for the parent to read the pipe. This is likely not effecting the code in question, but it is problematic.
close(0);
close(fd[1]);
dup(fd[0]);
// File descriptors here: 0=new stdin=data exhaust of the pipe
// 1=stdout, 2=stderr
// (and 3..N opened in the program, could also be none).
// N+1=fd[0] data exhaust of the pipe (stdin is now a duplicate)
This is problematic since:
the code just lost the original stdin.
The pipe is never closed. You should close fd[0] explicitly, don't close(0),
and don't duplicate fd[0].
It is good idea to avoid having duplicate descriptors, except for having stderr duplicate stdout.
.
bool return_type_parent = read(fd[0], &return_type_child, sizeof(return_
this->return_type = return_type_parent;
}
else if (child == 0) {
// this code runs in the child.
close(fd[0]);
close(1);
dup(fd[1]);
// File descriptors here: 0=stdin, 1=new stdout=pipe intake, 2=stderr
//(and 3..N opened in the program, could also be none).
// N+2=fd[1] pipe intake (new stdout is a duplicate)
This is problematic, since there are two duplicate data intakes to the pipe. In this case it is not critical since they are both closed automatically when the process ends, but it is a bad practice. It is a bad practice, since only closing all the pipe intakes signals END-OF-FILE to the exhaust. Closing one intake but not the other, does not signal END-OF-FILE. Again, in your case it is not causing trouble since the child's exit closes all the intakes.
execvp(argv[0], argv);
The code below the above line is never reached, unless execvp itself failed. The execvp fails only when the file does not exist, or the caller has no permission to execute it. If the executable starts to execute and fails later (possibly even if it fails to read a shared library), then still execvp itself succeeds and never returns. This is because execvp replaces the executable, and the following code is no longer in memory when execvp starts to run the other program.
this->return_type = false;
return_type_child = false;
write(1,&return_type_child,sizeof(return_type_child));
}
return;
}

About fork() while building a shell

here is my code.
pid_t fpid=fork();
if(fpid > 0){
wait(&fpid);
}
else{
do_command();
}
The thing is, the function do_command() only execute one line, so I change the do_command() for this:
else{
execlp("/bin/ls","ls","-al",NULL);
cout<<"\ntest<<endl;
}
Also, the ls command was executed but cout command was missing..
What's wrong with my code?
Please excuse my poor English and help me.
Here is my do_command() function declaration:
void do_command(const char *command) {
//all commands with arguments
const char *kernel_address = "/bin/";
char *kernel_command;
strcpy(kernel_command, kernel_address);
strcat(kernel_command, command);
cout << "\nCommand is:" << kernel_command << "\n" << endl;
execlp(kernel_command, command, NULL);
}
Also, there is no any output while function was called in child process
The next line is not printing because the exec family commands only returns on error. If there is no error, it will replace you program and whatever command intended to be executed in exec, is executed. Therefore cout is not working
From the manual of execlp :
The exec() family of functions replaces the current process image with a new process image.
Once your execlp is called, your program is not running anymore. It has been replaced by ls. Thus, it will never reach the cout

weird behaviour when calling external script

My C++ program is just a very simple while loop in which I grab user command from the console (standard input, stdin) using the getline() blocking function. Every now and then I must call an external bash script for other purposes. The script is not directly related to what the user do, it just do some stuff on the filesystem but it has to print text lines in the console standard output (stdout) to inform the user about the outcome of its computations.
What I get is that as soon as the script starts and prints stuff to stdout, the getline() function behave has it were non-blocking (it is supposed to block until the user inputs some text). As a consequence, the while(1) starts spinning at full speed and the CPU usage skyrockets to a near 100%.
I narrowed down the problem to a single C++ source file which reproduces the problem in the same exact way, here it is:
#include<iostream>
#include<string>
#include<sstream>
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
int pid = fork(); // spawn
if(pid > 0)
{
// child thread
system("sleep 5; echo \"you're screwed up!!!\"");
}
else
{
// main thread
std::string input;
while(1)
{
std::cout << std::endl << "command:";
getline(std::cin, input);
}
}
}
In this particular case after 5 seconds the program starts spamming "\ncommand:" on stdout and the only way to stop it is sending a SIGKILL signal. Sometimes you have to press some keys on the keyboard before the program starts spamming text lines.
Let run this code for 10 seconds then press any key on the keyboard. Be sure to be ready to fire the SIGKILL signal to the process from another console. You can use the command killall -9 progname
Did you check if failbit or eof is set?
Try changing the following line of your code
if (pid > 0)
to
if (pid == 0)
fork() returns 0 to child and pid of child to parent. In your example, you are running system() in parent and exiting the parent. The child then becomes orphan process running in a while(1) loop which i guess is messing up with the stdin, stdout.
I have modified your program to run system() in child process.
The basic problem:
if(pid > 0)
{
// child thread
system("sleep 5; echo \"you're screwed up!!!\"");
}
this is the PARENT. ;) The child gets pid : 0.

why can't I pipe output from both execl calls?

Possible duplicates:
How to call execl() in C with the proper arguments?
Grabbing output from exec
Linux Pipes as Input and Output
Using dup2 for piping
Piping for input/output
I've been trying to learn piping in Linux using dup/dup2 and fork the last 3 days. I think I got the hang of it, but when I call two different programs from the child process, it seems that I am only capturing output from the first one called. I don't understand why that is and/or what I'm doing wrong. This is my primary question.
Edit: I think a possible solution is to fork another child and set up pipes with dup2, but I'm more just wondering why the code below doesn't work. What I mean is, I would expect to capture stderr from the first execl call and stdout from the second. This doesn't seem to be happening.
My second question is if I am opening and closing the pipes correctly. If not, I would like to know what I need to add/remove/change.
Here is my code:
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <sys/wait.h>
#define READ_END 0
#define WRITE_END 1
void parentProc(int* stdoutpipe, int* stderrpipe);
void childProc(int* stdoutpipe, int* stderrpipe);
int main(){
pid_t pid;
int status;
int stdoutpipe[2]; // pipe
int stderrpipe[2]; // pipe
// create a pipe
if (pipe(stdoutpipe) || pipe(stderrpipe)){
std::cerr << "Pipe failed." << std::endl;
return EXIT_FAILURE;
}
// fork a child
pid = fork();
if (pid < 0) {
std::cerr << "Fork failed." << std::endl;
return EXIT_FAILURE;
}
// child process
else if (pid == 0){
childProc(stdoutpipe, stderrpipe);
}
// parent process
else {
std::cout<< "waitpid: " << waitpid(pid, &status, 0)
<<'\n'<<std::endl;
parentProc(stdoutpipe, stderrpipe);
}
return 0;
}
void childProc(int* stdoutpipe, int* stderrpipe){
dup2(stdoutpipe[WRITE_END], STDOUT_FILENO);
close(stdoutpipe[READ_END]);
dup2(stderrpipe[WRITE_END], STDERR_FILENO);
close(stderrpipe[READ_END]);
execl("/bin/bash", "/bin/bash", "foo", NULL);
execl("/bin/ls", "ls", "-1", (char *)0);
// execl("/home/me/outerr", "outerr", "-1", (char *)0);
//char * msg = "Hello from stdout";
//std::cout << msg;
//msg = "Hello from stderr!";
//std::cerr << msg << std::endl;
// close write end now?
}
void parentProc(int* stdoutpipe, int* stderrpipe){
close(stdoutpipe[WRITE_END]);
close(stderrpipe[WRITE_END]);
char buffer[256];
char buffer2[256];
read(stdoutpipe[READ_END], buffer, sizeof(buffer));
std::cout << "stdout: " << buffer << std::endl;
read(stderrpipe[READ_END], buffer2, sizeof(buffer));
std::cout << "stderr: " << buffer2 << std::endl;
// close read end now?
}
When I run this, I get the following output:
yfp> g++ selectTest3.cpp; ./a.out
waitpid: 21423
stdout: hB�(6
stderr: foo: line 1: -bash:: command not found
The source code for the "outerr" binary (commented out above) is simply:
#include <iostream>
int main(){
std::cout << "Hello from stdout" << std::endl;
std::cerr << "Hello from stderr!" << std::endl;
return 0;
}
When I call "outerr," instead of ls or "foo" I get the following output, which I would expect:
yfp> g++ selectTest3.cpp; ./a.out
waitpid: 21439
stdout: Hello from stdout
stderr: Hello from stderr!
On execl
Once you successfully call execl or any other function from the exec family, the original process is completely overwritten by the new process. This implies that the new process never "returns" to the old one. If you have two execl calls in a row, the only way the second one can be executed is if the first one fails.
In order to run two different commands in a row, you have to fork one child to run the first command, wait, fork a second child to run the second command, then (optionally) wait for the second child too.
On read
The read system call does not append a terminating null, so in general you need to look at the return value, which tells you the number of bytes actually read. Then set the following character to null to get a C string, or use the range constructor for std::string.
On pipes
Right now you are using waitpid to wait until the child process has already finished, then reading from the pipes. The problem with this is that if the child process produces a lot of output, then it will block because the pipe gets full and the parent process is not reading from it. The result will be a deadlock, as the child waits for the parent to read, and the parent waits for the child to terminate.
What you should do is use select to wait for input to arrive on either the child's stdout or the child's stderr. When input arrives, read it; this will allow the child to continue. When the child process dies, you'll know because you'll get end of file on both. Then you can safely call wait or waitpid.
The exec family of functions replace the current process image with a new process image. When you execute,
execl("/bin/bash", "/bin/bash", "foo", NULL);
the code from the current process is not executed any more. That's why you never see the result of executing
execl("/bin/ls", "ls", "-1", (char *)0);

Opening /proc/net/tcp in C++ from a POSIX thread fails most of the time

When I try to open /proc/net/tcp from a child POSIX thread in C++ it fails with a "No such file or directory" error. If I try to open it from the parent thread it succeeds every time, and the process of opening/closing it in the parent thread then makes it succeed about a third of the time in the child thread too. I can open /proc/uptime in the child thread 100% of the time without issue. Here's some example code which can be compiled with "g++ -Wall test.cc -o test -pthread":
#include <iostream>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <pthread.h>
using namespace std;
void * open_test (void *)
{
ifstream in;
in.open("/proc/net/tcp");
if (in.fail())
cout << "Failed - " << strerror(errno) << endl;
else
cout << "Succeeded" << endl;
in.close();
return 0;
}
int main (int argc, char * argv[])
{
open_test(NULL);
pthread_t thread;
pthread_create(&thread, NULL, open_test, NULL);
pthread_exit(0);
}
I am running this on an Ubuntu 12.04 box with an Intel i5-2520M (2 cores * 2 virtual cores) on Linux kernel 3.2.0. Here is the output of me running the above code 6 times in a row:
mike#ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike#ung:/tmp$ ./test
Succeeded
Succeeded
mike#ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike#ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike#ung:/tmp$ ./test
Succeeded
Succeeded
mike#ung:/tmp$ ./test
Succeeded
Failed - No such file or directory
mike#ung:/tmp$
It's probably worth noting that I don't have this problem if I use fork instead of posix threads. If I use fork, then the child process has no problems reading /proc/net/tcp
Just a couple of data points to throw in.... It looks like this is a regression in Linux as 2.6.35 seems to work 100% of the time. 3.2.0 pukes most of the time even on my slow old Pentium M based laptop.
As scott points out in his answer, adding a pthread_join(thread, NULL) fixes the symptoms. But why?
Let's put the program in gdb and set up a breakpoint at the point where the open has failed:
(gdb) break test.cc:14
Breakpoint 1 at 0x400c98: file test.cc, line 14.
Then we can observe two different types of behaviour:
(gdb) run […]
Succeeded
[New Thread 0x7ffff7fd1700 (LWP 18937)] // <- child thread
[Thread 0x7ffff7fd3740 (LWP 18934) exited] // <- parent thread
[Switching to Thread 0x7ffff7fd1700 (LWP 18937)]
Breakpoint 1, open_test () at test.cc:14
(gdb) run
Succeeded
[New Thread 0x7ffff7fd1700 (LWP 19427)] // <- child thread
Succeeded
[Thread 0x7ffff7fd1700 (LWP 19427) exited]
[Inferior 1 (process 19424) exited normally]
The first one suggests that the parent process exits before the child. As on Linux, processes and threads are pretty much the same, this implies that the PID associated with the main process gets cleaned up. Nothing hinders the child thread from running though. It and his pid are still perfectly valid. Just that /proc/self points to the PID of the main process, which has been deleted at that point.
This behavior seems to be a kind of bug in the /proc virtual filesystem. If you add this code just before opening the file:
system("ls -l /proc/net /proc/self/net/tcp");
You'll see that /proc/net is a symbolic link to /proc/self/net, and /proc/sec/net/tcp is properly listed for both calls to open_test, even when the spawned thread call fails.
Edit: I just realized the above test is bogus, since the self would refer to the shell process of the system call, not this process. Using the following function instead also reveals the bug:
void ls_command () {
ostringstream cmd;
cmd << "ls -l /proc/net "
<< "/proc/" << getpid()
<< "/net/tcp "
<< "/proc/" << syscall(SYS_gettid)
<< "/net/tcp";
system(cmd.str().c_str());
}
You'll see that the spawned thread will sometimes not be able to see the parents' /net/tcp file. In fact it has disappeared, since this is the spawned shell's process that is running the ls command.
The workaround below allows the child thread to reliably access what would be its /proc/net/tcp.
My theory is that it is some kind of race condition bug with correctly setting up the /proc/self entry for the thread as the proper blend of parent state and thread specific state. As a test and work around, I modifed the open_test code to use the "process identifier" associated with the thread, rather than trying to access the parent process's (because /proc/self refers to the parent process id, not the thread's).
Edit: As the evidence indicates, the bug has to do with the parent process cleaning up its /proc/self/... state before the child thread has had a chance to read it. I still maintain this to be a bug, since the child thread is still technically part of the process. It's getpid() is still the same before and after the main thread calls pthread_exit(). The /proc entry for the parent process should remain valid until all child threads are completed. Even though
Edit2: Jonas argues this may not be a bug. As evidence of that, there is this from man proc:
/proc/[pid]/fd
...
In a multithreaded process, the contents of this directory are
not available if the main thread has already terminated (typi-
ally by calling pthread_exit(3)).
But then consider this entry for /proc/self in the same man page entry:
/proc/self
This directory refers to the process accessing the /proc file
system, and is identical to the /proc directory named by the
process ID of the same process.
If one is to believe this is not a bug because threads and processes are treated the same in Linux, then threads should have an expectation that /proc/self will work. The bug may easily be fixed by modifying /proc/self to change to use /proc/[gettid] value when the /proc/[getpid] version is no longer available, just as the workaround is doing below.
void * open_test (void *)
{
ifstream in;
string file = "/proc/net/tcp";
in.open(file.c_str());
if (in.fail()) {
ostringstream ss;
ss << "/proc/" << syscall(SYS_gettid) << "/net/tcp";
cout << "Can't access " << file
<< ", using " << ss.str() << " instead" << endl;
file = ss.str();
in.open(file.c_str());
}
if (in.fail())
cout << "Failed - " << strerror(errno) << endl;
else
cout << "Succeeded" << endl;
in.close();
return 0;
}
If you add a pthread_join(thread, NULL) call before the pthread_exit() call, your program will work correctly.