Stdout being not read using "popen" and "read" functions - c++

I have a c++ code that is trying to run losetup /dev/loop* and parse what is spitting back at the terminal.
The code is as so
char cmd[32] = {0, };
sprintf(cmd, "losetup /dev/loop%d", i);
FILE *fp;
fp = popen(cmd,"r");
char buf[1024];
read(fileno(fp), buf, 123);
printf("After read: %s\n", buf);
Two different things happen.
When the loop device is set up, the output is like so:
After read: /dev/loop0: [0802] ...Remaining ommitted
which is what I want and expect.
However, when the loop device is not properly set up, the output is like so:
loop: can't get info on device /dev/loop1: No such device or address
After read:
As you can see, "buf" is NULL, and the stdout that should be inside "buf" just printed itself in the terminal. I need to read the output not only when the loop device is set up but also when it isn't. So, can someone explain how to fix this so I can store stdout of both cases?
PS. I've tried "dup2" with "pipe", "fgets", and "getline", and they have all failed similarly.

Pipes only go from the standard input to the standard output. Error messages such as
loop: can't get info on device /dev/loop1: No such device or address
go to the standard error. You can work around this by redirecting the standard error in the command which you pass to popen, e.g.,
sprintf(cmd, "losetup /dev/loop%d 2>&1", i);
because it is a shell command (and shells allow you to do redirection).

Related

Send Character TO CONIN$ (Windows Console)

If you want to spawn a Windows console in an otherwise SUBSYSTEM:WINDOWS application you can use this code:
if (AllocConsole())
{
FILE* file = nullptr;
_wfreopen_s(&file, L"CONIN$", L"r", stdin);
_wfreopen_s(&file, L"CONOUT$", L"w", stdout);
_wfreopen_s(&file, L"CONOUT$", L"w", stderr);
}
The _wfreopen_s function maps stdin to CONIN$ and provides a pointer to pointer in the file variable (which we are effectively discarding).
What I'd like to do is instead map an input from something other than stdin, for example, another file stream and then write that stream to CONIN$.
For a larger picture of what I'm trying to do here, I've got a secondary thread running std::getline(std::cin... which blocks. I'd like the thread context object to just send a \n to the console to break the blocking call.
If there are other ideas, I'm open. The alternative currently is that I print a message to the console that says "Shutting down, press ENTER to quit..." Which, I guess, also works ;)
What I tried was using the FILE* conin = new FILE(); and then did a memcpy to fill it with a \n and then I used WriteFile to that pointer, thinking that it might write the file stream out to CONIN$, and while the code compiles, and the contents of the FILE* appears to be correct (0x0a), it does not appear to send that stream to the console.
I tested this by having std::cout above and below the code testing the stream write. If it works, I'd expect the two lines to be on separate lines, but they always show up on the same, suggesting that I'm not sending the file stream.
Thanks for reading!
You should not discard the FILE* handle, otherwise you won't be able to manipulate it, in particular you won't be able to properly flush/close it if required.
If you're working with threads, simply give the FILE* to the thread that requires it. Threads share the same memory space.
If you're working with processes, then you should create a pipe between the two processes involved (see Win32 API for CreatePipe for details), and connect one's stdout to the other's stdin.

Returning output from bash script to calling C++ function

I am writing a baby program for practice. What I am trying to accomplish is basically a simple little GUI which displays services (for Linux); with buttons to start, stop, enable, and disable services (Much like the msconfig application "Services" tab in Windows). I am using C++ with Qt Creator on Fedora 21.
I want to create the GUI with C++, and populating the GUI with the list of services by calling bash scripts, and calling bash scripts on button clicks to do the appropriate action (enable, disable, etc.)
But when the C++ GUI calls the bash script (using system("path/to/script.sh")) the return value is only for exit success. How do I receive the output of the script itself, so that I can in turn use it to display on the GUI?
For conceptual example: if I were trying to display the output of (systemctl --type service | cut -d " " -f 1) into a GUI I have created in C++, how would I go about doing that? Is this even the correct way to do what I am trying to accomplish? If not,
What is the right way? and
Is there still a way to do it using my current method?
I have looked for a solution to this problem but I can't find information on how to return values from Bash to C++, only how to call Bash scripts from C++.
We're going to take advantage of the popen function, here.
std::string exec(char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
This function takes a command as an argument, and returns the output as a string.
NOTE: this will not capture stderr! A quick and easy workaround is to redirect stderr to stdout, with 2>&1 at the end of your command.
Here is documentation on popen. Happy coding :)
You have to run the commands using popen instead of system and then loop through the returned file pointer.
Here is a simple example for the command ls -l
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *process;
char buff[1024];
process = popen("ls -l", "r");
if (process != NULL) {
while (!feof(process)) {
fgets(buff, sizeof(buff), process);
printf("%s", buff);
}
pclose(process);
}
return 0;
}
The long approach - which gives you complete control of stdin, stdout, and stderr of the child process, at the cost of fairly significant complexity - involves using fork and execve directly.
Before forking, set up your endpoints for communication - pipe works well, or socketpair. I'll assume you've invoked something like below:
int childStdin[2], childStdout[2], childStderr[2];
pipe(childStdin);
pipe(childStdout);
pipe(childStderr);
After fork, in child process before execve:
dup2(childStdin[0], 0); // childStdin read end to fd 0 (stdin)
dup2(childStdout[1], 1); // childStdout write end to fd 1 (stdout)
dup2(childStderr[1], 2); // childStderr write end to fd 2 (stderr)
.. then close all of childStdin, childStdout, and childStderr.
After fork, in parent process:
close(childStdin[0]); // parent cannot read from stdin
close(childStdout[1]); // parent cannot write to stdout/stderr
close(childStderr[1]);
Now, your parent process has complete control of the std i/o of the child process - and must safely multiplex childStdin[1], childStdout[0], and childStderr[0], while also monitoring for SIGCLD and eventually using a wait-series call to check the process termination code. pselect is particularly good for dealing with SIGCLD while dealing with std i/o asynchronously. See also select or poll of course.
If you want to merge the child's stdout and stderr, just dup2(childStdout[1], 2) and get rid of childStderr entirely.
The man pages should fill in the blanks from here. So that's the hard way, should you need it.

get failed output back

I'm trying to run a script and output the result in the console. It works, but there is a
small problem i'm facing right now. If the "script" file is writed/coded wrong i get as output something like:
syntax error, unexpected $undefined, expecting $end puts
which is very good that it tells me somehting is wrong with the code inside the script file, but in my code line:
printf("%s", path);
it dosent print that to me and i want it to print it so i can display it on the screen. Please help me out
fp = popen("our script...is here", "r");
if (fp == NULL)
/* Handle error */;
while (fgets(path, PATH_MAX, fp) != NULL)
printf("%s", path);
status = pclose(fp);
Ps: just to make it more clear i'm using xcode and dont mind the code in C or C++
By default fgets() reads only from stdout of the stream. To capture stderr, you can simply redirect it to stdout:
fp = popen("./script 2>&1", "r");
Now both the stdout and stderr will go stdout which your C code can read from.
Note that once you have redirected as above there's no way to differentiate stdout and stderr.
You have to care about the stderr - popen() handled only stdout:
Conversely, reading from a "popened" stream reads the command's standard output,
The shell error will be printed to stderr - which popen() does not handle.

How to listen to stderr in C/C++ for sending to callback?

How do I passively listen to stderr and obtain it as string for sending to callback? I have seen posts on reading stderr but I want to listen to it rather than actively reading it.
Background:
I have a cross-platform piece that uses 3rd party library (libcurl) which will output verbose info into stderr. This cross-platform piece is to be used by more than 1 non-cross-platform applications.
I would like to log these info, which I can do by providing FILE* to libcurl. But instead of doing that, I want to see if I can capture (passively listen to) the output in stderr as string, and send back to the calling main application via callback. This has the benefit of 1. main app can keep a single log using whatever logging tool it wants. 2. it will keep this piece cross-platform.
Doing this in a single process is a little tricky, but you can probably do it.
1: Using freopen() you can redirect your stderr to a named file. You can simultaneously open that file for reading on another handle. You might also need to call setvbuf() on stderr to turn off buffering on output to stderr so that you will be able to read it right away from the 2nd handle. Since it is being written to a file you can read it at anytime - when it is convenient. The unix function "select" is what you need if you want to be notified when the file changes. (see also fileno()).
2: More tricky would be to setup stderr as the write end of a pipe. Should be doable using dup3(), though this isn't exactly cross-platform (to non-unixy OS's). It would also require that a 2nd thread be reading from the pipe to prevent the writer from being blocked if they write very much.
Like:
FILE *stream = freopen("stderr.out", "w", stderr); // Added missing pointer
setvbuf(stream, 0, _IONBF, 0); // No Buffering
FILE *input = fopen("stderr.out", "r");
fprintf(stderr, "Output to stderr dude\n");
//fflush(stderr); // You can explicitly flush instead of setting no buffering.
char buffer[1024];
while (fgets(buffer, 512, input))
{
printf(">>>%s\n", buffer);
}

About the read() in unistd.h (C++)

all, I am designing a Key-Value server, and when I wrote the client, and I found a really strange thing,see the simplified code:
while(1)
{
printf("->:");
read(STDIN_FILENO, buf, sizeof(buf));
write(client_sock, buf, sizeof(buf));
int m = read(client_sock, buf, sizeof(buf));
buf[m] = '\0';
printf("%s", buf);
}
when I run the program, it first ask for input, so I input something, but nothing happen!
(the server runs well, and it well echo something, when I use other client)
then I change the code only one line:
printf("\n->:");
then it runs well! why? why "\n" can change the output? I guess it maybe the read() , but I can't explain it
printf(3) is part of the C standard IO library, which performs internal buffering to provide performance improvements.
There are three types of buffering: none, line, and block.
Which buffering is applied is determined in part by whether the descriptor being written to is 2 or not, and if it is connected to a terminal. (See isatty(3).)
If the printing is done to stderr (2) then no buffering is done.
If the printing is done to any other descriptor, then the behavior changes if it is a terminal or not: if output is a terminal, then the output is line buffered. If the output is not a terminal (file, pipe, socket, etc.) then the output is block buffered.
When line buffered, it waits for the \n before printing anything. (Or if you write enough to overflow the internal buffers before sending a \n.)
What I'd recommend instead is the following:
printf("->:");
fflush(stdout);
read(STDIN_FILENO, buf, sizeof(buf));
/* ... */
printf("%s\n", buf);
It's a small change; you won't get a pointless empty line at program start, and the prompt should show up .. promptly.
You can use the setvbuf(3) function to change the buffering for your stream once, at start up, and never need to flush it again, if you would rather.
int err = setvbuf(stdout, NULL, _IONBF, 0);
/* check err */
Standard output is line-buffered by default. If you don't write a complete line, the output will be held in the buffer until you do. You can use fflush to flush the stream or setbuf to change the buffering mode.