Chain of fork() output - c++

I'm totally newbie in Unix environment and i faced some problems with plain example from Unix Systems Programming book by Robbins.
It's plain chain of processes and each process prints some info to log file and stderr
#define BUFSIZE 1024
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_PERMS (S_IRUSR | S_IWUSR| S_IRGRP | S_IROTH)
int main (int argc, char *argv[]) {
char buf[BUFSIZE];
pid_t childpid = 0;
int i, n;
if (argc != 3){ /* check for valid number of command-line arguments */
fprintf (stderr, "Usage: %s processes filename\n", argv[0]);
return 1;
}
/* open the log file before the fork */
n = atoi(argv[1]); /* create a process chain */
for (i = 1; i < n; i++)
if (childpid = fork())
break;
if (childpid == -1) {
fprintf(stderr, "Failed to fork");
return 1;
}
auto fd = open(argv[2], CREATE_FLAGS, CREATE_PERMS);
if (fd < 0) {
fprintf(stderr,"Failed to open file");
return 1;
}
sprintf(buf, "i:%d process:%ld parent:%ld child:%ld\n",
i, (long)getpid(), (long)getppid(), (long)childpid);
fprintf(stderr, buf);
write(fd, buf, strlen(buf));
return 0;
}
It's compiled on Netbeans 7.1 with g++ 4.7 and run command is "${OUTPUT_PATH}" 10 /home/maxim/testlog.log
So the problems are:
When i run or debug project it prints out only 2 or 3 lines of info in both console and file. But if i traverse with "Step Over" through childpid = fork(), it prints info about all 10 processes. Is that some compiler optimization or just my fault?
Even when it prints all lines, the output looks like
i:2 process:6571 parent:6566 child:6572
i:3 process:6572 parent:1 child:6573
i:4 process:6573 parent:6572 child:6574
...
i:9 process:6578 parent:1 child:6579
i:10 process:6579 parent:6578 child:0
Parent pid values for some processes are 1, which seems to be wrong

If the processes each open the same output file there will be a race condition causing the processes to overwrite each other. That is why it only happens when you run at full speed.
When the parent process ends any children that are still alive are either killed or get a new parent depending on a setting in Linux. In your case they seem to get a new parent. That new parent is process 1.

Related

Reading stderr from a linux device, after writing to it from c++

When i write to a linux driver / device, in this case i want to put the embedded linux device to sleep:
echo "mem" > /sys/power/state
I get an error on the terminal if the above command fails
[ 2593.061030] dpm_run_callback(): elan_touch_suspend+0x0/0x114 returns 1
[ 2593.067578] PM: Device 0-0015 failed to suspend: error 1
[ 2593.072994] PM: Some devices failed to suspend, or early wake event detected
[ 2593.107845] ==== calc_soc_by_voltageMethod E60U22 ====
And i do this the same in c++:
int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);
If the above command fails, i get the same error on the terminal. now i want to get this error as a string in c++, in shell i can do something like this:
echo "mem" > /sys/power/state 2>/tmp/sleep_error
But i cant figure this out in c++, I need to to try one more time if it fails
What I tryied:
Capturing cerr of the whole program, with freopen doesn't work. When I write to the device from another terminal, and do cat /dev/stderr from another, i get the output in the second one, I tryied to use it:
char byte[1000];
int stderrdevice = open("/dev/stderr", O_RDONLY | O_NOCTTY);
int fd2 = open("/sys/power/state", O_RDWR);
write(fd2, "mem", 3);
close(fd2);
ssize_t size = read(stderrdevice, &byte, 1000);
printf("Read byte %s\n", byte);
This doesn't work too. Any resources, documentation related to this are welcome
Thanks everyone for help and responding. user17732522 and Nate Eldredge were right. What i was trying to get was the kernel ring buffer, that was printing out to the serial connection. The same thing was in dmesg. I ended up using klogctl to get the errors. I couldn't get only the last line of dmesg with other klogctl options, and the code is a bit chaotic, but here is what I finally used:
bool continueSleeping = true;
int count = 0;
while (continueSleeping == true) {
// https://linux.die.net/man/3/klogctl
klogctl(5, NULL, 0);
log("Trying sleep");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
int fd2 = open("/sys/power/state", O_RDWR);
int status = write(fd2, "mem", 3);
close(fd2);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
log("After sleep");
// get dmesg, and then only lines containing <3>
char *logs_data;
ssize_t len = klogctl(10, NULL, 0);
logs_data = (char *)malloc(len);
klogctl(3, logs_data, len);
vector<string> dmesgErrorsVec;
boost::split(dmesgErrorsVec, logs_data, boost::is_any_of("\n"),
boost::token_compress_on);
// to show whole dmesg
//log("dmesg: " + (string)logs_data);
free(logs_data);
string dmesgErrors;
for (string line : dmesgErrorsVec) {
if (line.find("<3>") != std::string::npos) {
// tesdt
dmesgErrors.append(line);
dmesgErrors.append("\n");
}
}
dmesgErrorsVec.clear();
if (status == -1 or
dmesgErrors.find("PM: Some devices failed to suspend") != std::string::npos) {
log("Failed to suspend, dmesg errors:\n" + dmesgErrors);
log("status: " + to_string(status));
CEG();
count = count + 1;
if (count == 5) {
log("5 failed attemts at suspending, sleep a little longer...");
smartWait(10000);
} else if (count == 15) {
log("15 failed attempts at sleeping...");
// Write to fbink here a sad message
} else {
smartWait(3000);
}
} else {
// Exiting this sleeping hell
log("Tryied going to sleep " + to_string(count) + "times");
continueSleeping = false;
}
}
log("Sleep finished, Exiting going to sleep");

How to convert the system call to fork in C++ linux

This is the code for playing sound file in C++ linux code
string str1 = "aplay ";
str1 = str1 + " out.wav" + " & ";
const char *command = str1.c_str();
system(command);
** Entire code is available here : Playing sound C++ linux aplay : device or resource busy
I just want to know how to play this in a fork() as I read that system call is too taxing on cpu, which ofcourse is in my case.
Please help
fork will make a copy of your process, so you can easily write:
// fork the current process: beyond this point, you will have 2 process
int ret = fork();
if (ret == 0) {
// in child: execute the long command
system("aplay out.wav");
// exit the child process
exit(0);
}
// child process will not go here
if (ret < 0) {
perror("fork");
}
After, you should know that system will do for you fork + exec + wait. Since you don't want your parent process to wait the child, you can write:
// fork the current process: beyond this point, you will have 2 process
int ret = fork();
if (ret == 0) {
// in child: execute the long command
char program[] = "/usr/bin/aplay";
char *args[] = {"/usr/bin/aplay", "out.wav" };
ret = execv(program, args);
// this point will be reach only if `exec` fails
// so if we reach this point, we've got an error.
perror("execv");
exit(0);
}
// child process will not go here
if (ret < 0) {
perror("fork");
}

How would one go about 'chain' piping more than 2 pipes in C++? Currently I am getting the Bad file descriptor error from Bash on the second command

To expand on this, by chain piping I am referring to when I have 3 separate processes:
process 1 writes to process 2,
process 2 reads from process 1 and writes to process 3,
process 3 reads from process 2 and then finishes.
I am specifically trying to handle complex commands in a C++ written bash shell. So I would be using this to execute a set of commands like this that all communicate with each other:
ls | sort | grep "exit"
where process 1 is executing ls and its stdout is written to process 2 through a pipe, etc.
I already am writing code to solve this for a project and was just wondering if my approach is correct, as right now when just doing a 2 command call of ls | grep "exit" I am getting the bash error "grep: (standard input): Bad file descriptor"
//Block for when the userInput is a complex command
else{
if (debug)
printf("Complex command: %s\n", userInput.c_str());
vector<char*> commandsVect = splitCString(const_cast<char*>(userInput.c_str()), const_cast<char*>( delimVertPipe.c_str()));
if (debug)
printVect(commandsVect);
if (pipe(fileDescriptor) == -1){
fprintf(stderr, "Pipe failed for command %s\n", userInput.c_str());
return 1;
}
for (int i = 0; i < commandsVect.size(); ++i) {
vector<char*> tokens = splitCString(const_cast<char*>(commandsVect[i]), const_cast<char*>( delimSpace.c_str()));
printf("Commands vect size is %ld\n", commandsVect.size());
printf("Parsing command \'%s\'\n", commandsVect[i]);
if (debug) {
printVect(tokens);
}
procID = fork();
//Block for the first command
if (i == 0){
if (procID < 0){
fprintf(stderr, "Fork number %d in the complex command \'%s\' failed\n", i+1, userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
//close(fileDescriptor[READ_END]);
close(STDOUT_FILENO);
//Links the write end of the pipe to the STDOUT
dup2(fileDescriptor[WRITE_END], 1);
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
tokens.push_back(nullptr); //execvp() arg array needs a NULL pointer at the end
if ( execvp(tokens[0], tokens.data()) < 0 ) {
fprintf( stderr, "execvp() call failed for the command \'%s\' inside the input string \'%s\'\n", commandsVect[i], userInput.c_str() );
return 1;
}
exit(1);
}
//Parent process
else{
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
wait(NULL);
}
}
//Block for the very last command, which will pipe input from the previous
else if (i == commandsVect.size() - 1){
if (procID < 0){
fprintf(stderr, "Fork number %d in the complex command \'%s\' failed\n", i+1, userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
//close(fileDescriptor[WRITE_END]);
close(STDIN_FILENO);
//Links the read end of the pipe to the STDIN
dup2(fileDescriptor[READ_END], 0);
close(fileDescriptor[WRITE_END]);
close(fileDescriptor[READ_END]);
tokens.push_back(nullptr); //execvp() arg array needs a NULL pointer at the end
if ( execvp(tokens[0], tokens.data()) < 0 ) {
fprintf( stderr, "execvp() call failed for the command \'%s\' inside the input string \'%s\'\n", commandsVect[i], userInput.c_str() );
return 1;
}
exit(1);
}
//Parent process
else{
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
wait(NULL);
}
}
//To note for StackOverflow, this block of code is never executed since I am only ever calling a 2 chained command like ls|grep "exit"
//Block for the middle commands. (Will pipe input from previous, and output to the next)
else{
printf("GOING THROUGH BAD CODE");
continue;
if (procID < 0){
fprintf(stderr, "Fork number %d in the complex command \'%s\' failed\n", i+1, userInput.c_str());
return 1;
}
//Child process
else if (procID == 0){
exit(1);
}
//Parent process
else{
wait(NULL);
}
}
}
close(fileDescriptor[READ_END]);
close(fileDescriptor[WRITE_END]);
}
This might not be possible with your larger application, but you could simplify things by letting the shell manage the pipes. Write P1 (process one), P2, and P3 as three separate executables. In stead of doing IO on pipes, each program could read from stdin and write to stdout. Simple. To execute - let bash or whatever shell you use glue the three together by calling them as...
$P1 | P2 | P3;
Under the hood, your shell is doing pretty much what you're doing in C++ (only successfully 😉). It creates a pipe for P1, which it passes to exec as stdin to launch P1 after forking. It creates an input and output pipe for P2, and binds it stdin and stdout as appropriate in the same way - passed into exec when launching P2 after the fork. P3 gets only a stdin pipe and its stdout stream goes right to the console as normal. It's not quite as sexy as doing it all in C++, but it's very robust - pretty much guaranteed to work.

Multiple fork() Children with pipes

I am trying to make a program in C++ that is creating childs with fork().
It should take childs number from argv and create these childs,every child is creating another one and communicate each other with pipes ....
Example ./a.exe 2
**OUTPUT**
P1 exists
P2 created
Write message: Hello
P1 sending message (“Hello”) to P2
P2 received message (“Hello”) from P1
I get the number from argv, creating the correct number of childs(i think),functions for read and write to pipe,all are OK.
But I have trouble to make it with multiple child!!
My first problem is that if i put more than 2 in argv, child order
is not ascending as it should!(Created shows later)
But my big problem is that if i write
a message with 2 words i can only read first word before space!!I am using scanf.
SOME OF MY CODE
//GETTING,CHECKING ARGV
//OPENING PIPE
pid=fork();
if (pid!=0){
waitpid(pid,&child_status,0);
printf("\n\n****Parent Process:ALL CHILD FINISHED!****");
}
else if (pid==0)
{
printf("\n P%d Exists \n",i);
close (mypipe[READ_END]);
write(mypipe[WRITE_END], msg, 256); /* write pipe*/
close (mypipe[WRITE_END]);
printf("Write a message: \n");
scanf("%s",msg);
printf("\n P%d sending message: '%s' to P%d \n",i,msg,i+1);
do{
childpid[i] = fork();
if (childpid[i] > 0){
/* wait for child to terminate */
waitpid(childpid[i],&child_status,0);
}
else if (childpid[i] == 0)
{
/*child process childpid = 0*/
printf("\n P%d Created \n",i+1);
close (mypipe[WRITE_END]);
read(mypipe[READ_END], msg, 256); /* read pipe */
close (mypipe[READ_END]);
printf("\n P%d received message: '%s' from P%d \n",i+1,msg,i);
exit(0);
return;
}
else{
printf("Child Fork failed");
}
i++;
}
while (i<x);
}
else{
printf("Fork failed");
}
}
I had read other similar questions and tried many things but didn't help!!
Any help will be appreciated!!
Thank you!
You have multiple problems in the code you show, and there is code missing as diagnosed in a comment.
One problem is that you close both ends of the only pipe in the first child, and then close it a second time (but fortunately you ignore the error). More seriously, any subsequent children only have a closed pipe to work with, and that isn't going to help them.
Another problem is that the parent process doesn't close the pipe; it may not matter in this program since you don't try reading to EOF, but in most programs, it would matter.
Another problem is that you don't read the message from standard input until after you've tried to write an uninitialized message to the pipe. It isn't immediately clear whether you should hook up the standard input of the child to the read end of the pipe. You write 256 bytes to the pipe even if the message is not that long.
You run into problems with multiple words because scanf("%s", msg) is designed to read up to the first white space (blank, newline, tab, etc). In this context, I'd probably use fgets() to read the information.
I think you need a new pipe for each child. You should probably be error checking each system call, but that is easier if you have a simple error reporting function, like this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
static char *arg0 = 0;
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s (%d): ", arg0, (int)getpid());
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, "Error %d: %s\n", errnum, strerror(errnum));
exit(1);
}
int main(int argc, char **argv)
{
int i=1;
int x;
int pid, mypipe[2];
pid_t childpid[256];
int child_status;
char msg[256];
arg0 = argv[0];
if (argc != 2 || (x = atoi(argv[1])) <= 0)
err_exit("Usage: %s num-of-children\n", argv[0]);
if (pipe(mypipe) < 0)
err_exit("pipe error\n");
You have some serious thinking about how you want to organize things so that a message is relayed from one process to the next. This is just a start...the error reporting function may be of some use to you.

Capturing stdout from a system() command optimally [duplicate]

This question already has answers here:
How do I execute a command and get the output of the command within C++ using POSIX?
(12 answers)
Closed 7 years ago.
I'm trying to start an external application through system() - for example, system("ls"). I would like to capture its output as it happens so I can send it to another function for further processing. What's the best way to do that in C/C++?
From the popen manual:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
Try the popen() function. It executes a command, like system(), but directs the output into a new file. A pointer to the stream is returned.
FILE *lsofFile_p = popen("lsof", "r");
if (!lsofFile_p)
{
return -1;
}
char buffer[1024];
char *line_p = fgets(buffer, sizeof(buffer), lsofFile_p);
pclose(lsofFile_p);
EDIT: misread question as wanting to pass output to another program, not another function. popen() is almost certainly what you want.
System gives you full access to the shell. If you want to continue using it, you can
redirect it's output to a temporary file, by system("ls > tempfile.txt"), but choosing a secure temporary file is a pain. Or, you can even redirect it through another program: system("ls | otherprogram");
Some may recommend the popen() command. This is what you want if you can process the output yourself:
FILE *output = popen("ls", "r");
which will give you a FILE pointer you can read from with the command's output on it.
You can also use the pipe() call to create a connection in combination with fork() to create new processes, dup2() to change the standard input and output of them, exec() to run the new programs, and wait() in the main program to wait for them. This is just setting up the pipeline much like the shell would. See the pipe() man page for details and an example.
The functions popen() and such don't redirect stderr and such; I wrote popen3() for that purpose.
Here's a bowdlerised version of my popen3():
int popen3(int fd[3],const char **const cmd) {
int i, e;
int p[3][2];
pid_t pid;
// set all the FDs to invalid
for(i=0; i<3; i++)
p[i][0] = p[i][1] = -1;
// create the pipes
for(int i=0; i<3; i++)
if(pipe(p[i]))
goto error;
// and fork
pid = fork();
if(-1 == pid)
goto error;
// in the parent?
if(pid) {
// parent
fd[STDIN_FILENO] = p[STDIN_FILENO][1];
close(p[STDIN_FILENO][0]);
fd[STDOUT_FILENO] = p[STDOUT_FILENO][0];
close(p[STDOUT_FILENO][1]);
fd[STDERR_FILENO] = p[STDERR_FILENO][0];
close(p[STDERR_FILENO][1]);
// success
return 0;
} else {
// child
dup2(p[STDIN_FILENO][0],STDIN_FILENO);
close(p[STDIN_FILENO][1]);
dup2(p[STDOUT_FILENO][1],STDOUT_FILENO);
close(p[STDOUT_FILENO][0]);
dup2(p[STDERR_FILENO][1],STDERR_FILENO);
close(p[STDERR_FILENO][0]);
// here we try and run it
execv(*cmd,const_cast<char*const*>(cmd));
// if we are there, then we failed to launch our program
perror("Could not launch");
fprintf(stderr," \"%s\"\n",*cmd);
_exit(EXIT_FAILURE);
}
// preserve original error
e = errno;
for(i=0; i<3; i++) {
close(p[i][0]);
close(p[i][1]);
}
errno = e;
return -1;
}
The most efficient way is to use stdout file descriptor directly, bypassing FILE stream:
pid_t popen2(const char *command, int * infp, int * outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
} else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(::open("/dev/null", O_WRONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i) {
::close(i);
}
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
} else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
} else {
*outfp = p_stdout[0];
}
return pid;
}
To read output from child use popen2() like this:
int child_stdout = -1;
pid_t child_pid = popen2("ls", 0, &child_stdout);
if (!child_pid) {
handle_error();
}
char buff[128];
ssize_t bytes_read = read(child_stdout, buff, sizeof(buff));
To both write and read:
int child_stdin = -1;
int child_stdout = -1;
pid_t child_pid = popen2("grep 123", &child_stdin, &child_stdout);
if (!child_pid) {
handle_error();
}
const char text = "1\n2\n123\n3";
ssize_t bytes_written = write(child_stdin, text, sizeof(text) - 1);
char buff[128];
ssize_t bytes_read = read(child_stdout, buff, sizeof(buff));
The functions popen() and pclose() could be what you're looking for.
Take a look at the glibc manual for an example.
In Windows, instead of using system(), use CreateProcess, redirect the output to a pipe and connect to the pipe.
I'm guessing this is also possible in some POSIX way?
Actually, I just checked, and:
popen is problematic, because the process is forked. So if you need to wait for the shell command to execute, then you're in danger of missing it. In my case, my program closed even before the pipe got to do it's work.
I ended up using system call with tar command on linux. The return value from system was the result of tar.
So: if you need the return value, then not no only is there no need to use popen, it probably won't do what you want.
In this page: capture_the_output_of_a_child_process_in_c describes the limitations of using popen vs. using fork/exec/dup2/STDOUT_FILENO approach.
I'm having problems capturing tshark output with popen.
And I'm guessing that this limitation might be my problem:
It returns a stdio stream as opposed to a raw file descriptor, which
is unsuitable for handling the output asynchronously.
I'll come back to this answer if I have a solution with the other approach.
I'm not entirely certain that its possible in standard C, as two different processes don't typically share memory space. The simplest way I can think of to do it would be to have the second program redirect its output to a text file (programname > textfile.txt) and then read that text file back in for processing. However, that may not be the best way.