How to read the failure log message displayed when a system call failed in C++? - c++

I have a C++ code that calls a test. I am doing a system call to execute this test. When this test fails, it will display something like this " ERROR: One or more devices of following component type(s) could not be discovered:"
I have a C++ code that runs on Linux redhat and it is capable of detecting if the system call pass or failed. But it can not capture the error message (ERROR: One or more devices of following component type(s) could not be discovered:) and append into the log file or print it.
Can someone please tell me how to capture the error message (ERROR: One or more devices of following component type(s) could not be discovered:)?
PS: I am an intern, any help would be really nice.
#include<iostream.h>
int main ()
{
int i;
if (system(NULL))
puts ("Ok");
else
exit (1);
i=system("hpsp --discover -verbose --user Admin --oapasswd password");
printf ("The value returned was: %d.\n",i);
return false;
}

Instead of using system() use popen(). This will open a pipe capturing the standard output of the test program so that your program can read it via the pipe.
Example EDITED:
#define _BSD_SOURCE 1
#define BUFFSIZE 400
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *cmd = "hpsp --discover -verbose --user Admin --oapasswd password";
char buf[BUFFSIZE];
char* searchResult;
int testPassed = 0;
FILE *ptr;
if ((ptr = popen(cmd, "r")) != NULL)
while (fgets(buf, BUFFSIZE, ptr) != NULL)
{
if ((searchResult = strstr(buf, "The test passed")) != NULL )
{
testPassed = 1;
break;
}
}
if (testPassed)
printf("yea!!\n");
else
printf("boo!!\n");
pclose(ptr);
return 0;
}

You can use dup and dup2 to backup/store the stderr file descriptor to redirect to your log file. Well, I'm guessing that errors go to stderr anyways.
Here's an example if you just want to write to a log file.
//open log file, choose whatever flags you need
int logfd = open("whateveryourlogfileis", O_APPEND);
//back up stderr file descriptor
int stderr_copy = dup(STDERR_FILENO);
//redirect stderr to your opened log file
dup2(logfd, STDERR_FILENO);
//close the original file descriptor for the log file
close(logfd);
//system call here
//restore stderr
dup2(stderr_copy, STDERR_FILENO);
//close stderr copy
close(stderr_copy);
Note: dup2 closes the target file descriptor before dup2ing to it. dup just duplicates the file descriptor and returns to you the new file descriptor.

Related

Handing user input on terminal for application launched via exec in C++

xfreerdp asks for password if /p is not supplied as command line argument; when launched via terminal.
But when it is launched via execvp or exec, there is no prompt?
How to show this prompt? Is there a way where I can directly input password on prompt programmatically?
Same is automatically handled in Mac using swift using tasks & pipes. How to do it in C++.
Is there a way where I can directly input password on prompt programmatically?
An example (written in C) using popen() ...
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char *cmd = "xfreerdp";
char output[128] = {'\0'};
const char *arg = "myargs";
// Open process
FILE *fp = popen(cmd, "w");
if (!fp) {
fprintf(stderr, "Could not execute command ...\n");
exit(EXIT_FAILURE);
}
// Pass arguments
if (fprintf(fp, "%s", arg) < 0) {
puts("Could not pass arguments ...");
}
// Print command output (if required)
while (fgets(output, sizeof(output), fp) != NULL) {
puts(output);
}
pclose(fp);
return 0;
}

Communication with Arduino using Linux

This is the first time I'm communicating with Arduino using my computer. I use Ubuntu 14.04. This is the C program for writing to the file. The Arduino shows up ttyACM0.
While compiling using gcc the compiler shows an error saying:
Segmentation fault(core dumped)
How do I rectify this error.
#include<unistd.h>
#include<stdio.h>
int main() {
char data[] = {'f','b','r'}; //Random data we want to send
FILE *file;
file = fopen("/dev/ttyACM0","w"); //Opening device file
int i = 0;
for(i = 0 ; i < 3 ; i++) {
fprintf(file,"%c",data[i]); //Writing to the file
fprintf(file,"%c",','); //To separate digits
sleep(1);
}
fclose(file);
}
Pardon my ignorance. I tried researching on it. Couldn't make it work. Thanks in advance for your help.
You're getting a NULL return from the fopen() that NULL is being passed to fprintf() which is expecting a valid FILE* and messing up causing the SEGV.
If you use fopen you should check what it returns so you can give the user a something more useful than "segmentation fault".
The probable cause of the fopen() failure is you don't have permission to play with the serial port.
Normally you need the group dialout to be able to access the serial port.
As root do:
usermod -a -G dialoutyourusername
Then log out and back in so you get the new group.
Consider using minicom or microcom (on any of the several other serial terminal programs) to access the serial port instead of writing your own.
I also suggest you have the Arduino send a hello message when it boots up so you can be sure you have the right baud rate etc...
You did not put any success check on the return value of fopen("/dev/ttyACM0","w");. In case fopen() fails, using file further is undefined behavior, causing segmentation fault. Do something like
file = fopen("/dev/ttyACM0","w"); //Opening device file
if (file)
{
//do something with file
}
else
return 0;
Also, add a return 0 before ending main().
// the following code:
// compiles cleanly
// performs appropriate error checking
// has proper return statement
#include <unistd.h> // sleep()
#include <stdio.h> // fopen(), fclose(), fprintf(), perror()
#include <stdlib.h> // exit() and EXIT_FAILURE
int main()
{
char data[] = {'f','b','r'}; //Random data we want to send
FILE *file;
if( NULL == (file = fopen("/dev/ttyACM0","w") ) ) //Opening device file
{ // then fopen failed
perror("fopen failed for ttyACM0" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
int i = 0;
for(i = 0 ; i < 3 ; i++)
{
if( 0 >= fprintf(file,"%c",data[i]) ) //Writing to the file
{ // fprintf failed
perror("fprintf data failed" );
exit( EXIT_FAILURE );
}
// implied else, fprintf successful for data
if( 0 >= fprintf(file,"%c",',') ) //To separate digits
{ // then, fprintf failed
perror( "fprintf for comma failed");
exit( EXIT_FAILURE );
}
// implied else, fprintf successful for comma
sleep(1);
} // end for
fclose(file);
return(0);
} // end function: main
On failure fopen returns NULL, so you are potentially dereferencing a NULL pointer, the correct way of doing that, is checking the result of fopen. I would however suggest low level IO for this kind of thing something like
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
char data[] = {'f','b','r'}; //Random data we want to send
int fd;
int i;
fd = open("/dev/ttyACM0", O_WRONLY); //Opening device file
if (fd == -1)
{
perror("cannot open /dev/ttyACM0");
return -1;
}
for(i = 0 ; i < 3 ; i++)
{
write(fd, &(data[i]), 1);
write(fd, ",", 1);
sleep(1);
}
close(fd);
return 0;
}
on error open returns a special value -1 so you should abort writing to it.
I'm pretty sure in your case there will be a permission denied error, since normally the /dev/tty* belong to group dialout and they have group write permission by default, but since probably your user doesn't belong to that group you don't have write access to /dev/ttyACM0.

how to get linux command output string and output status in c++

I want to get a Linux command's output string as well as command output status in a C++ program. I am executing Linux commands in my application.
for example:
Command:
rmdir abcd
Command output string:
rmdir: failed to remove `abcd': No such file or directory
Command Status:
1 (Which means command has been failed)
I tried using Linux function system() which gives the output status, and function popen() which gives me output string of a command, but neither function gives me both
the output string and output status of a Linux command.
The output string is in standard output or standard error descriptor (1 or 2, respectively).
You have to redirect these streams (take a look at dup and dup2 function) to a place, where you can read them (for example - a POSIX pipe).
In C I'd do something like this:
int pd[2];
int retValue;
char buffer[MAXBUF] = {0};
pipe(pd);
dup2(pd[1],1);
retValue = system("your command");
read(pd[0], buffer, MAXBUF);
Now, you have (a part of) your output in buffer and the return code in retValue.
Alternatively, you can use a function from exec (i.e. execve) and get the return value with wait or waitpid.
Update: this will redirect only standard output. To redirect standard error, use dup2(pd[1],1).
The simplest solution is to use system, and to redirect standard out and standard error to a temporarly file, which you can delete later.
Unfortunately there's no easy and simple way in C on Linux to do this. Here's an example how to read/write stdout/stderr/stdin of child process correctly.
And when you want to receive exit code you have to use waitpid (complete example is provided on the bottom of the provided page):
endID = waitpid(childID, &status, WNOHANG|WUNTRACED);
Now you just have to join those two together :)
There's also a great free book named Advanced Linux Programming (ALP) containing detailed information about these kinds of problem available here.
Building on Piotr Zierhoffer answer above, here's a function that does just that, and also restores stdout and stderr their original state.
// Execute command <cmd>, put its output (stdout and stderr) in <output>,
// and return its status
int exec_command(string& cmd, string& output) {
// Save original stdout and stderr to enable restoring
int org_stdout = dup(1);
int org_stderr = dup(2);
int pd[2];
pipe(pd);
// Make the read-end of the pipe non blocking, so if the command being
// executed has no output the read() call won't get stuck
int flags = fcntl(pd[0], F_GETFL);
flags |= O_NONBLOCK;
if(fcntl(pd[0], F_SETFL, flags) == -1) {
throw string("fcntl() failed");
}
// Redirect stdout and stderr to the write-end of the pipe
dup2(pd[1], 1);
dup2(pd[1], 2);
int status = system(cmd.c_str());
int buf_size = 1000;
char buf[buf_size];
// Read from read-end of the pipe
long num_bytes = read(pd[0], buf, buf_size);
if(num_bytes > 0) {
output.clear();
output.append(buf, num_bytes);
}
// Restore stdout and stderr and release the org* descriptors
dup2(org_stdout, 1);
dup2(org_stderr, 2);
close(org_stdout);
close(org_stderr);
return status;
}
you can use popen system call, it will redirect output to a file and from file you can redirect output to a string. like :
char buffer[MAXBUF] = {0};
FILE *fd = popen("openssl version -v", "r");
if (NULL == fd)
{
printf("Error in popen");
return;
}
fread(buffer, MAXBUF, 1, fd);
printf("%s",buffer);
pclose(fd);
For more information read man page for popen.

How to capture the exit_code and stderr of the command that is run in C++?

I'm writing a c++ program that executes and outputs (in real-time) a shell script, makefile or just another program. However I would like to have my program return differently when there are errors or no error.
#include "execxi.h"
using namespace std;
int execXI::run(string command)
{
FILE *in;
char buff[512];
// is this the check for command execution exited with not 0?
if(!(in = popen(command.c_str(), "r"))){
// I want to return the exit code and error message too if any
return 1;
}
// this part echoes the output of the command that's executed
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff;
}
pclose(in);
return 0;
}
is what I have so far.
Let's say this script ran make to build a program and it gave an error like so
on_target_webkit_version out/Release/obj/gen/webkit_version.h
Traceback (most recent call last):
File "../build/webkit_version.py", line 107, in <module>
sys.exit(main())
File "../build/webkit_version.py", line 103, in main
return EmitVersionHeader(*sys.argv[1:])
File "../build/webkit_version.py", line 86, in EmitVersionHeader
webkit_revision = GetWebKitRevision(webkit_dir, version_file)
File "../build/webkit_version.py", line 60, in GetWebKitRevision
version_info = lastchange.FetchVersionInfo(
AttributeError: 'module' object has no attribute 'FetchVersionInfo'
make: *** [out/Release/obj/gen/webkit_version.h] Error 1
Is it possible for me to know that this exited with error?
Does that exit with code else than 0 since it is an error?
Is that last part outputted in stderr?
Considering that make exited with code not 0, let's say 1, and it output in stderr is it not possible for me to capture these exit codes and error message in the end?
How can I capture the exit code and stderr after outputting the results of the program, and return the exit code/ stderr in the function?
If you are interested in the error code, this is a more portable way of getting it rather than dividing by 256:
printf("Exit code: %i\n", WEXITSTATUS(pclose(fp)));
However, popen is one way, so you are either creating further workarounds by the usual redirection style in shell, or you follow this untested code to do it right:
#include <unistd.h>
#include <stdio.h>
/* since pipes are unidirectional, we need two pipes.
one for data to flow from parent's stdout to child's
stdin and the other for child's stdout to flow to
parent's stdin */
#define NUM_PIPES 2
#define PARENT_WRITE_PIPE 0
#define PARENT_READ_PIPE 1
int pipes[NUM_PIPES][2];
/* always in a pipe[], pipe[0] is for read and
pipe[1] is for write */
#define READ_FD 0
#define WRITE_FD 1
#define PARENT_READ_FD ( pipes[PARENT_READ_PIPE][READ_FD] )
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )
#define CHILD_READ_FD ( pipes[PARENT_WRITE_PIPE][READ_FD] )
#define CHILD_WRITE_FD ( pipes[PARENT_READ_PIPE][WRITE_FD] )
void
main()
{
int outfd[2];
int infd[2];
// pipes for parent to write and read
pipe(pipes[PARENT_READ_PIPE]);
pipe(pipes[PARENT_WRITE_PIPE]);
if(!fork()) {
char *argv[]={ "/usr/bin/bc", "-q", 0};
dup2(CHILD_READ_FD, STDIN_FILENO);
dup2(CHILD_WRITE_FD, STDOUT_FILENO);
/* Close fds not required by child. Also, we don't
want the exec'ed program to know these existed */
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
close(PARENT_READ_FD);
close(PARENT_WRITE_FD);
execv(argv[0], argv);
} else {
char buffer[100];
int count;
/* close fds not required by parent */
close(CHILD_READ_FD);
close(CHILD_WRITE_FD);
// Write to child’s stdin
write(PARENT_WRITE_FD, "2^32\n", 5);
// Read from child’s stdout
count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1);
if (count >= 0) {
buffer[count] = 0;
printf("%s", buffer);
} else {
printf("IO Error\n");
}
}
}
The code is from here:
http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/
The returnvalue of the child process is in the top 16 8 bits. You have
to divide the returned value of pclose by 256, then you get the
searched return value of the child process.
Gotten from http://bytes.com/topic/c/answers/131694-pclose-returning-termination-status-command
My answer would be pclose(in)/256 is exit code.
I still don't know how to capture stderr or sdtout differently but until there's an answer for that I will accept this as my answer.
Thanks for the reply about exit code Logan.
I believe a round-trip to get stderr would be to redirect it to a temporary file:
FILE* f = popen("cmd 2>/tmp/tmpfile.txt", "r");

Detect if stdin is a terminal or pipe?

When I execute "python" from the terminal with no arguments it brings up the Python interactive shell.
When I execute "cat | python" from the terminal it doesn't launch the interactive mode. Somehow, without getting any input, it has detected that it is connected to a pipe.
How would I do a similar detection in C or C++ or Qt?
Use isatty:
#include <stdio.h>
#include <io.h>
...
if (isatty(fileno(stdin)))
printf( "stdin is a terminal\n" );
else
printf( "stdin is a file or a pipe\n");
(On windows they're prefixed with underscores: _isatty, _fileno)
Summary
For many use cases the POSIX function isatty() is all what it is needed to detect if stdin is connected to a terminal. A minimal example:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if (isatty(fileno(stdin)))
puts("stdin is connected to a terminal");
else
puts("stdin is NOT connected to a terminal");
return 0;
}
The following section compares different methods that can be used if different degrees of interactivity have to be tested.
Methods in Detail
There are several methods to detect if a program is running interactively.
Following table shows an overview:
cmd\method ctermid open isatty fstat
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
./test /dev/tty OK YES S_ISCHR
./test < test.cc /dev/tty OK NO S_ISREG
cat test.cc | ./test /dev/tty OK NO S_ISFIFO
echo ./test | at now /dev/tty FAIL NO S_ISREG
The results are from a Ubuntu Linux 11.04 system using the following program:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int main() {
char tty[L_ctermid+1];
ctermid(tty);
printf("ID: %s\n", tty);
int fd = open(tty, O_RDONLY);
if (fd < 0) perror("Could not open terminal");
else {
printf("Opened terminal\n");
struct termios term;
int r = tcgetattr(fd, &term);
if (r < 0) perror("Could not get attributes");
else printf("Got attributes\n");
}
if (isatty(fileno(stdin))) printf("Is a terminal\n");
else printf("Is not a terminal\n");
struct stat stats;
int r = fstat(fileno(stdin), &stats);
if (r < 0) perror("fstat failed");
else {
if (S_ISCHR(stats.st_mode)) printf("S_ISCHR\n");
else if (S_ISFIFO(stats.st_mode)) printf("S_ISFIFO\n");
else if (S_ISREG(stats.st_mode)) printf("S_ISREG\n");
else printf("unknown stat mode\n");
}
return 0;
}
Terminal device
If the interactive session needs certain capabilities, you can open the
terminal device and (temporarily) set terminal attributes you need
via tcsetattr().
Python Example
The Python code that decides whether the interpreter runs interactively uses isatty(). The Function PyRun_AnyFileExFlags()
/* Parse input from a file and execute it */
int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
if (filename == NULL)
filename = "???";
if (Py_FdIsInteractive(fp, filename)) {
int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
calls Py_FdIsInteractive()
/*
* The file descriptor fd is considered ``interactive'' if either
* a) isatty(fd) is TRUE, or
* b) the -i flag was given, and the filename associated with
* the descriptor is NULL or "<stdin>" or "???".
*/
int
Py_FdIsInteractive(FILE *fp, const char *filename)
{
if (isatty((int)fileno(fp)))
return 1;
which calls isatty().
Conclusion
There are different degrees of interactivity. For checking if stdin is connected to a pipe/file or a real terminal isatty() is a natural method to do that.
Probably they are checking the type of file that "stdin" is with fstat, something like this:
struct stat stats;
fstat(0, &stats);
if (S_ISCHR(stats.st_mode)) {
// Looks like a tty, so we're in interactive mode.
} else if (S_ISFIFO(stats.st_mode)) {
// Looks like a pipe, so we're in non-interactive mode.
}
Of course Python is open source, so you can just look at what they do and know for sure:
http://www.python.org/ftp/python/2.6.2/Python-2.6.2.tar.bz2
On Windows you can use GetFileType.
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD type = GetFileType(hIn);
switch (type) {
case FILE_TYPE_CHAR:
// it's from a character device, almost certainly the console
case FILE_TYPE_DISK:
// redirected from a file
case FILE_TYPE_PIPE:
// piped from another program, a la "echo hello | myprog"
case FILE_TYPE_UNKNOWN:
// this shouldn't be happening...
}
Call stat() or fstat() and see if S_IFIFO is set in st_mode.
You can call stat(0, &result) and check for !S_ISREG( result.st_mode ). That's Posix, not C/C++, though.