how to capture result from system() in C/C++ [duplicate] - c++

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
How can I run an external program from C and parse its output?
Hi,
Could someone please tell us how to capture a result when executing system() function ?
Actually I wrote a c++ program that displays the machine's IP address, called "ipdisp" and I want when a sever program executes this ipdisp program, the server captes the display IP address. So, is this possible? if yes, how?
thanks for your replies

Yes, you can do this but you can't use system(), you'll have to use popen() instead. Something like:
FILE *f = popen("ipdisp", "r");
while (!feof(f)) {
// ... read lines from f using regular stdio functions
}
pclose(f);

Greg is not entirely correct. You can use system, but it's a really bad idea. You can use system by writing the output of the command to a temporary file and then reading the file...but popen() is a much better approach. For example:
#include <stdlib.h>
#include <stdio.h>
void
die( char *msg ) {
perror( msg );
exit( EXIT_FAILURE );
}
int
main( void )
{
size_t len;
FILE *f;
int c;
char *buf;
char *cmd = "echo foo";
char *path = "/tmp/output"; /* Should really use mkstemp() */
len = (size_t) snprintf( buf, 0, "%s > %s", cmd, path ) + 1;
buf = malloc( len );
if( buf == NULL ) die( "malloc");
snprintf( buf, len, "%s > %s", cmd, path );
if( system( buf )) die( buf );
f = fopen( path, "r" );
if( f == NULL ) die( path );
printf( "output of command: %s\n", buf );
while(( c = getc( f )) != EOF )
fputc( c, stdout );
return EXIT_SUCCESS;
}
There are lots of problems with this approach...(portability of the syntax for redirection, leaving the file on the filesystem, security issues with other processes reading the temporary file, etc, etc.)

Related

Running ssh in c++ with popen function or using non-compiled library

I want to run some script on remote device using ssh, but I don't want to use a library. I want to run popen function and run ssh.
FILE *f = popen( "ssh -t -t root#192.168.1.2", "r" );
if(f)
{
fprintf(f, "/opt/somescript.sh\n");
pclose(f);
}
I can see that the connection established and closed on the terminal, when I run this code. But the script doesn't really run on the remote machine.
Don't want to use a library means, compiled library. Because this code will run different platforms and I cannot compile the library for every platform. If I can use pure c++ code, it will be OK. I downloaded libssh source codes but it's so compicated and I didn't understand how to use it without compiling.
Your input and output are wrong. You open the ssh with "r", which means you're interested in the script output, but then you try to fprintf into it, which makes no sense.
Try to replace the popen with:
FILE *f = popen( "ssh -t -t root#192.168.1.2 /opt/somescript.sh", "r" );
what is the output of this code?
#include <stdio.h>
int main() {
FILE * fp = popen( "ssh -t -t root#192.168.1.2", "r" );
if ( !fp ) {
fprintf( stderr, "Could not execute command \n" );
return 1;
}
const int BUFSIZE = 1000;
char buff[ BUFSIZE ];
while( fgets( buf, sizeof( buff ), fp ) ) {
fprintf( stdout, "%s", buff );
}
pclose( fp );
fp=NULL;
return 0;
}

Complex getchar() operation in omxplayer

Recently I have been trying to redirect the output of a named pipe into a running instance of omxplayer (see here for a minimum working example that doesn't control omxplayer even though it should). I suspected that it had something to do with reading and writing to pipes --perhaps a new line got appended-- so I got some help and wrote a C program which writes to a pipe and reads from it (see here) but turns out that it is not a read/write error either. So I went and traced omxplayer's code thinking that no matter how complicated it was, eventually there has to be a place which has standard C++ code which reads user input, and thank god I found it. Here is the method which, to the best of my understanding, is responsible for getting user input and preparing it for the Dbus to do all its heavenly goodness:
void Keyboard::Process()
{
while(!m_bStop && conn && dbus_connection_read_write_dispatch(conn, 0))
{
int ch[8];
int chnum = 0;
while ((ch[chnum] = getchar()) != EOF) chnum++;
if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8);
if (m_keymap[ch[0]] != 0)
send_action(m_keymap[ch[0]]);
else
Sleep(20);
}
}
As far as I can glean, the while(!m_bStop... is a conditional just to make sure things are still working, m_keymap is a cypher which matches integers such as 'p' or 'q' to enum values such as ACTION_PAUSE and ACTION_QUIT, and I presume send_action() just gets the ball rolling.
Questions:
Here is what I do not understand:
How is EOF detected when I am not even pressing Enter --> while ((ch[chnum] = getchar()) != EOF) (in case you are confused by this, when a movie is playing I press p to pause the film, not p and then Enter or Ctrl+D). I have attached a small script below labeled getchar.c which illustrates how it is looping forever.
Why are we looping for potentially more than 8 iterations in the while loop while ((ch[chnum] = getchar()) != EOF) chnum++ when the array ch is only of length 8?
This might be implementation specific, but why an array of size 8 when all inputs are guaranteed to be 1 character long (I can both see it here in the map, and by the fact that keys are processed instantly). Is this in any way related to the arrow keys and the escape key?
Assuming it is possible to have more than 1 character, somehow, what is this line supposed to do if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8)?
Knowing, finally, how omxplayer reads user generated input, can anyone tell me why my simple script, labelled omxplayer_test.c, does not succeed in controlling the player?
getchar.c:
#include <stdio.h>
int main( int argc, char *argv[] ) {
int ch [ 8 ];
int chnum = 0;
while ( ( ch [ chnum ] = getchar() ) != EOF ) chnum++;
printf ( "You will never make it here!\n" );
return 0;
}
omxplayer_test.c:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define PIPE_PATH "testpipe"
#define VIDEO_PATH "Matrix.mkv"
#define P_MESSAGE "p"
#define Q_MESSAGE "q"
#define I_MESSAGE "."
#define VIDEO_PLAYER "omxplayer"
#define SLEEP_PERIOD 2L
int main()
{
int fd;
pid_t pid;
pid_t wpid;
int status;
char shellCmd [ 1000 ];
struct timespec time1, time2; //used for sleeping
bool parent;
char c;
parent = false;
//Make pipe BEFORE forking
mkfifo ( PIPE_PATH, 0666 );
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //first child launches the movie
sprintf ( shellCmd, "%s %s < %s >/dev/null 2>&1", VIDEO_PLAYER, VIDEO_PATH, PIPE_PATH );
if ( system ( shellCmd ) == -1 )
{
printf ( "Error: %s\n", shellCmd );
fflush(stdout);
}
printf ("First child finished\n");
fflush (stdout);
}
else
{
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //second child waits x seconds then pauses/unpauses/quits movie
time1.tv_sec = SLEEP_PERIOD; //sleep for x seconds
time1.tv_nsec = 0L; //Dont worry about milli seconds
nanosleep ( &time1, &time2 );
//Suprisingly, this signal which gets ball rolling works
fd = open ( PIPE_PATH, O_WRONLY );
write ( fd, I_MESSAGE, sizeof ( I_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, pausing movie\n");
fflush(stdout);
write ( fd, I_MESSAGE, sizeof ( P_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, unpausing movie\n");
fflush(stdout);
write ( fd, P_MESSAGE, sizeof ( P_MESSAGE ) );
nanosleep ( &time1, &time2 );
printf ( "Sleep over, quiting movie\n");
fflush(stdout);
write ( fd, Q_MESSAGE, sizeof ( Q_MESSAGE ) );
close ( fd );
printf ("Second child finished\n");
fflush (stdout);
}
else
{
parent = true;
}
}
while ( ( wpid = wait ( &status ) ) > 0 )
{
printf ( "Exit status of %d was %d (%s)\n", ( int ) wpid, status, ( status == 0 ) ? "accept" : "reject" );
fflush(stdout);
}
if ( parent == true )
{
printf ("deleting pipe\n");
fflush(stdout);
unlink ( PIPE_PATH );
}
return 0;
}
#puk I stumbled upon your 'oldĀ“ question but in case you didn't have it answered by yourself.
Look at something similar on https://github.com/popcornmix/omxplayer/issues/131. As omxplayer releases 0.3.x comes from this 'popcornmix' repository, I will answer these questions there because it is a better place for your omxplayer questions ;)
But I will answer the question why your omxplayer_test.c isn't working here, as it is your code that let omxplayer fail :) Strictly not true, as it is a current issue in omxplayer :(
The sending of I_MESSAGE surprises me the most, as I don't know of any keyboard input handling on a '.' character. On the other hand, 'i' commands omxplayer to go to the previous chapter. So if you didn't key-mapped anything on the '.' input key or meant the real 'i' actions, just leave that out; it isn't (and shouldn't be) needed to start omxplayer.
To pause omxplayer, your typo'd it with the I_MESSAGE in stead of P_MESSAGE.
But sending commands to omxplayer with the write() and the sizeof() of the message causes the same effect as mentioned in forementioned issue. The sizeof() of an x_MESSAGE gives 2 as result back, and not 1 (one)! The sizeof() counts in the '\0'-character of a (c-coded) string; e.g. "p" is stored as 'p''\0', so at least 2 characters. So use strlen() (which needs #include <string.h>) in stead, as it will sent only the x_MESSAGE character.

Starting a program fails with error code 1

I made an application and a dll, which are working this way:
I have to register the dll. After registering the dll if i right click on an .exe file, the pop-up menu appears, and i have inserted into this menu one line ("Start MyApp"), and if i click there, it should start MyApp. MyApp has one parameter which is the full path of the selected .exe file. After starting MyApp with this path it should create a process with CreateProcessWithLogonW(). This application reads the username, password and the domain from an .ini file. My problem is, that after MyApp starts, it fails always, because it can't find the ini file. Errorcode is: 1 (Incorrect function).
If i start MyApp manually, than it works fine.
Does anyone has any idea why is this, and how could i fix this problem?
Thanks in advance!
kampi
Update1:
Here is the code which reads from the ini file.
int main ( int argc, char *argv[] )
{
int i, slash = 0, j;
char application[size];
wchar_t wuser[65], wdomain[33], wpass[129];
memset( user, 0, sizeof ( user ) );
memset( password, 0, sizeof ( password ) );
memset( domain, 0, sizeof ( domain ) );
file_exists( "RunAs.ini" );
readfile( "RunAs.ini" );
....
....
....
}
void file_exists( const char * filename )
{
if (FILE * file = fopen(filename, "r"))
{
fclose(file);
}
else
{
printf("\nCan't find %s!\n",filename);
getch();
exit(1);
}
}//file_exists
void readfile( char * filename )
{
FILE *inifile;
char tmp[256], buf[256], what[128];
int i, j;
inifile = fopen( "RunAs.ini", "r" );
while ( fgets(tmp, sizeof tmp, inifile) != NULL )
{
if ( tmp[ strlen(tmp) - 1 ] == '\n' )
{
tmp[ strlen(tmp) - 1 ] = '\0';
}//if
memset ( buf, 0, sizeof( buf ) );
for ( i = 0; tmp[i]!= '='; i++ )
{
buf[i] = tmp[i];
}
buf[i] = '\0';
i++;
// memset ( what, 0, sizeof( what ) );
SecureZeroMemory( what, sizeof(what) * 128 );
for ( j = 0; i != strlen(tmp); i++ )
{
what[j] = tmp[i];
j++;
}
what[j] = '\0';
upcase( buf );
removespace( what );
if ( strcmp( buf, "USERNAME" ) == 0 )
{
strcpy( user, what );
}
if ( strcmp( buf, "PASSWORD" ) == 0 )
{
strcpy( password, what );
}
if ( strcmp( buf, "DOMAIN" ) == 0 )
{
strcpy( domain, what );
}
}//while
fclose (inifile);
}//readfile
As others have said, your problem is here:
file_exists( "RunAs.ini" );
readfile( "RunAs.ini" );
Neither of the function calls provides a path. You're expecting the current working directory to be the folder where your application is located, but it doesn't have to be (in fact, you should never assume that it is). The context menu isn't setting the working directory first.
Your safest bet is to retrieve the path to your folder using the path provided in argv[] (the 0th element is the fully qualified path and name of the application itself, and you can extract the path from that). You'll then have exact knowledge of where the file is located, and can append the name of the ini file to that path.
I suspect you're looking for the ini file in the wrong folder. I would try changing the ini file name in the application to the fully qualified name of the ini file. (i.e from "foo.ini" to "c:\\temp\\foo.ini")
(Please note that I've doubled the backslashes because without this, the single backslash may change the meaning of the next character or the backslash may be ignored.)
Are you providing an absolute path or a relative path? Your CWD may be different on startup.
When starting your application directly, the current path is the path that your application is installed to.
However, when starting it from that context menu, the current path is something else.
There are two ways to resolve this. First, don't use an ini file. Instead, store your information to the registry. That way you don't care where the program is started from.
Alternatively, your app will have to locate the directory where it was actually installed, then load the ini file from there.
Obviously the first choice is the easiest path.
Have you checked whether file path for the ini is valid ?

Read() from file descriptor hangs

Hey, hopefully this should be my last PTY-related question and I can move onto more exciting issues. (c;
Here's a set of small functions I have written for creating and reading/writing to a pty: http://pastebin.com/m4fcee34d The only problem is that they don't work! After I run the initializer and writeToPty( "ls -l" ) , 'output' from readFromPty is still empty.
Ubuntu, QT C++
EDITED: Ok, I can confirm all this stuff works except for the read loop. In the debuggers' locals/watchers tab it shows that the QString 'output' actually does get the right data put in it, but after it ( the read() ) runs out of characters from the output it runs and then hangs. What is going on and how can I fix it?
Thanks! (c:
#include <iostream>
#include <unistd.h>
#include <utmp.h>
#include <pty.h>
#include <QString>
#include <QThread>
// You also need libutil in your .pro file for this to compile.
class CMkPty
{
public:
CMkPty( int *writeChannel, int *readChannel );
~CMkPty();
int runInPty( char *command );
int writeToPty( char *input );
int readFromPty( QString output );
int m_nPid;
private:
int m_nMaster, m_nSlave, m_nPosition, m_nBytes;
char *m_chName;
void safe_print( char *s );
char m_output;
};
CMkPty::CMkPty( int *masterFD, int *slaveFD )
{
openpty( &m_nMaster, &m_nSlave, (char*)0, __null, __null );
m_nPid = fork();
*masterFD = m_nMaster;
*slaveFD = m_nSlave;
if( m_nPid == 0 )
{
login_tty( m_nSlave );
execl( "/bin/bash", "-l", (char*)0 );
return;
}
else if( m_nPid > 0 )
{
return;
}
else if( m_nPid < 0 )
{
std::cout << "Failed to fork." ;
return;
}
}
CMkPty::~CMkPty()
{
close( m_nMaster );
close( m_nSlave );
}
int CMkPty::writeToPty( char *szInput )
{
int nWriteTest;
write( m_nMaster, szInput, sizeof( szInput ) );
nWriteTest = write( m_nMaster, "\n", 1 );
if( nWriteTest < 0 )
{
std::cout << "Write to PTY failed" ;
return -1;
}
return 0;
}
int CMkPty::readFromPty( QString output )
{
char buffer[ 160 ];
m_nBytes = sizeof( buffer );
while ( ( m_nPosition = read( m_nMaster, buffer, m_nBytes ) ) > 0 )
{
buffer[ m_nPosition ] = 0;
output += buffer;
}
return 0;
}
EDIT: Here's a link to the question with the code that finally worked for me.
I'm note entirely familiar with posix, but after reading this page http://pwet.fr/man/linux/fonctions_bibliotheques/posix/read I had some insight. What's more, I don't see you adjusting your M_nBytes value if you haven't read as much as you were expecting on the first pass of the loop.
edit: from that link, perhaps this will be of some help:
If some process has the pipe open for writing and O_NONBLOCK is clear, read() shall block the calling thread until some data is written or the pipe is closed by all processes that had the pipe open for writing.
When attempting to read a file (other than a pipe or FIFO) that supports non-blocking reads and has no data currently available:
*
If O_NONBLOCK is clear, read() shall block the calling thread until some data becomes available.
so essentially, if you're not in an error state, and you tell it to keep reading, it will block until it finds something to read.

How can I execute external commands in C++/Linux?

I just want to know which is the best way to execute an external command in C++ and how can I grab the output if there is any?
Edit: I Guess I had to tell that I'm a newbie here in this world, so I think I'm gonna need a working example. For example I want to execute a command like:
ls -la
how do I do that?
Use the popen function.
Example (not complete, production quality code, no error handling):
FILE* file = popen("ls", "r");
// use fscanf to read:
char buffer[100];
fscanf(file, "%100s", buffer);
pclose(file);
An example:
#include <stdio.h>
int main() {
FILE * f = popen( "ls -al", "r" );
if ( f == 0 ) {
fprintf( stderr, "Could not execute\n" );
return 1;
}
const int BUFSIZE = 1000;
char buf[ BUFSIZE ];
while( fgets( buf, BUFSIZE, f ) ) {
fprintf( stdout, "%s", buf );
}
pclose( f );
}
popen definitely does the job that you're looking for, but it has a few drawbacks:
It invokes a shell on the command you're executing (which means that you need to untaint any user provided command strings)
It only works in one direction, either you can provide input to the subprocess or you can read its output.
If you want invoke a subprocess and provide input and capture output then you'll have to do something like this:
int Input[2], Output[2];
pipe( Input );
pipe( Output );
if( fork() )
{
// We're in the parent here.
// Close the reading end of the input pipe.
close( Input[ 0 ] );
// Close the writing end of the output pipe
close( Output[ 1 ] );
// Here we can interact with the subprocess. Write to the subprocesses stdin via Input[ 1 ], and read from the subprocesses stdout via Output[ 0 ].
...
}
else
{ // We're in the child here.
close( Input[ 1 ] );
dup2( Input[ 0 ], STDIN_FILENO );
close( Output[ 0 ] );
dup2( Output[ 1 ], STDOUT_FILENO );
execlp( "ls", "-la", NULL );
}
Of course, you can replace the execlp with any of the other exec functions as appropriate.