Opening a console from app - c++

I am working on a C and C++ app that uses some graphical engine to handle gtk windows (Opencv/highgui). This app does some minor output to stdout/cout.
On Windows, starting this kind of app from the desktop automatically opens a console, showing the user what is been written on standard output, either with "printf()" or "std::cout".
On Linux, if I start it from a previously opened console, no trouble. But if I start it through the desktop (double-click), then linux doesn't open an associated console, and data written on stdout/cout is lost.
Seems that this is the normal behaviour on Linux (?).
I would like to automatically open a console from my app, when compiled on a linux platform.
This seems like a dupe of this one, the point is, it doesn't work! I have at present the following code:
#ifndef __WIN32
filebuf* console = new filebuf();
console->open( "/dev/tty", ios::out );
if( !console->is_open() )
cerr << "Can't open console" << endl;
else
cout.ios::rdbuf(console);
#endif
(cerr is redirected in a file using freopen() )
I keep getting "Can't open console". I tried replacing the console name:
console->open( "/dev/console", ios::out );
but that didn't change.
Am I in the right direction? What can I try next? Should I try to open specifically the terminal application (xterm)? But then, how could I "connect" that console with my app?

Solution 1
Very simple solution you might not like: have a script that runs your application in a terminal using gnome-terminal -x <your_program> <your_args>. Double-clicking the script will open the terminal.
Solution 2
A bit more involved solution add a '--noconsole' argument to your application. If the argument is present, just run your application. If '--noconsole' is not present:
if( fork() == 0 ) {
execlp("gnome-terminal", "gnome-terminal", "-x", argv[0], "--noconsole", NULL );
} else {
exit( 0 );
}
This creates a child process in which it runs the application in gnome-terminal using the --noconsole arugment. Makes sense? A bit hacky, but hey, it works.
Solution 3
This one is the trickiest solution, but in some ways more elegant. The idea is to redirect our stdout to a file and create a terminal running tail -f <file_name> --pid=<parent_pid>. This prints the output of the parent process and terminates when the parent dies.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
// Create terminal and redirect output to it, returns 0 on success,
// -1 otherwise.
int make_terminal() {
char pidarg[256]; // the '--pid=' argument of tail
pid_t child; // the pid of the child proc
pid_t parent; // the pid of the parent proc
FILE* fp; // file to which output is redirected
int fn; // file no of fp
// Open file for redirection
fp = fopen("/tmp/asdf.log","w");
fn = fileno(fp);
// Get pid of current process and create string with argument for tail
parent = getpid();
sprintf( pidarg, "--pid=%d", parent );
// Create child process
child = fork();
if( child == 0 ) {
// CHILD PROCESS
// Replace child process with a gnome-terminal running:
// tail -f /tmp/asdf.log --pid=<parent_pid>
// This prints the lines outputed in asdf.log and exits when
// the parent process dies.
execlp( "gnome-terminal", "gnome-terminal", "-x", "tail","-f","/tmp/asdf.log", pidarg, NULL );
// if there's an error, print out the message and exit
perror("execlp()");
exit( -1 );
} else {
// PARENT PROCESS
close(1); // close stdout
int ok = dup2( fn, 1 ); // replace stdout with the file
if( ok != 1 ) {
perror("dup2()");
return -1;
}
// Make stdout flush on newline, doesn't happen by default
// since stdout is actually a file at this point.
setvbuf( stdout, NULL, _IONBF, BUFSIZ );
}
return 0;
}
int main( int argc, char *argv[]) {
// Attempt to create terminal.
if( make_terminal() != 0 ) {
fprintf( stderr, "Could not create terminal!\n" );
return -1;
}
// Stuff is now printed to terminal, let's print a message every
// second for 10 seconds.
int i = 0;
while( i < 10 ) {
printf( "iteration %d\n", ++ i );
sleep( 1 );
}
return 0;
}

Your examples all "open" a console - in the sense that one opens a file. This doesn't do anything to a gui. If you want to do that you will have to open a gtk window and direct the output to it.

Related

_popen() in Windows does not work interactively

I am using _popen() to create a pipe to communicate with another program which I can only execute and do not have source code access to. I have tried examples given in MSDN here (_popen example) and here (CreateProcess and CreateThread example(). Note that the code is almost the same except that for _popen I have modified it to write to pipe instead as below:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char psBuffer[128];
FILE *pPipe;
/* Run DIR so that it writes its output to a pipe. Open this
* pipe with read text attribute so that we can read it
* like a text file.
*/
if( (pPipe = _popen( "myprogram", "wt" )) == NULL )
exit( 1 );
/* Read pipe until end of file, or an error occurs. */
while(!feof( pPipe)))
{
char cmd[32]="";
while(fgets(psBuffer, 128, pPipe))
{
printf(psBuffer);
}
scanf("%s", cmd);
fprintf(pPipe,"%s",cmd);
}
/* Close pipe and print return value of pPipe. */
if (feof( pPipe))
{
printf( "\nProcess returned %d\n", _pclose( pPipe ) );
}
else
{
printf( "Error: Failed to read the pipe to the end.\n");
}
}
The output I expect to get is like:
Some Text -> from myprogram
command entered from parent
Some more Text -> from myprogram
more command from parent
..
..
Till myprogram terminates
However what I get is
Some Text -> from myprogram
command entered
and it keeps on accepting the commands eternally
Can you help here?
Thanks,
FC

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.

exec functions not working from linux daemon

I have been writing a linux daemon which listens on TCP/IP for a request and launches an application on receiving that request. My problem is when I run this daemon from command prompt or IDE (eclipse 3.7) everything works fine and my executable launches. But when i use
sudo service <myservicename> start
It will receive request on socket but its not launching that executable.
here is the standard code I am using for daemonizing the process
/// Linux Daemon related stuff
/// Create the lock file as the current user
int lfp = open( "/var/lock/subsys/LauncherService", O_RDWR|O_CREAT, 0640);
if ( lfp < 0 )
{
LOG_ERROR ("Unable to open lockfile");
LOG_ERROR ( strerror(errno) );
}
/// All
/// Our process ID and Session ID
pid_t pid, sid;
/// Fork off the parent process
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/// If we got a good PID, then
/// we can exit the parent process.
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
/// Change the file mode mask
umask(0);
/// Create a new SID for the child process
sid = setsid();
if (sid < 0)
{
LOG_ERROR ("Error Setting sid");
exit(EXIT_FAILURE);
}
LOG_INFO ("sid set");
/// Change the current working directory
if ( (chdir("/usr/local/<mylocaldir>/bin")) < 0 )
{
LOG_ERROR ("Error changing Directory");
exit(EXIT_FAILURE);
}
LOG_INFO ("chdir successful");
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
here is function in which i am launching my binary which needs to be launched. This function is called in forked child process.
std::string configFile = "/usr/local/<mydir>/config/Settings.config";
std::string binary = "<binaryname>";
std::string path ="/usr/local/<mydir>/bin/<binaryname>";
//char *argv[] = { "<binaryname>", "/usr/local/<mydir>/config/Settings.config", (char *)0 };
LOG_INFO("Calling Process" );
if ( execlp( path.c_str(), binary.c_str(), configFile.c_str(), (char *)0 ) == -1 )
//if ( execv("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
//if ( execvp("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
{
LOG_ERROR("System call failed !!")
std::string errString = strerror(errno);
LOG_ERROR (errString );
}
else
{
LOG_INFO("System call successful");
}
So after discussion with Casey I investigated more into my called program and I found that my program indeed is getting called. Also I found out that environment variables are not the issue child process is taking environment from parent itself. I am creating QApplication (qt gui application) in my main program. Its some issue with that and linux system daemon. I will try to figure that out and will ask separate question if needed.
Edit: Final Solution
It was a qt GUI application which was not able to connect to XServer. I had to changes suggested by Casey and given in this post
Cannot connect to X server :0.0 with a Qt application
after that it started launching.

How to read the failure log message displayed when a system call failed in 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.

Execute a process and return its standard output in VC++

What's the easiest way to execute a process, wait for it to finish, and then return its standard output as a string?
Kinda like backtics in Perl.
Not looking for a cross platform thing. I just need the quickest solution for VC++.
Any ideas?
WinAPI solution:
You have to create process (see CreateProcess) with redirected input (hStdInput field in STARTUPINFO structure) and output (hStdOutput) to your pipes (see CreatePipe), and then just read from the pipe (see ReadFile).
hmm.. MSDN has this as an example:
int main( void )
{
char psBuffer[128];
FILE *pPipe;
/* Run DIR so that it writes its output to a pipe. Open this
* pipe with read text attribute so that we can read it
* like a text file.
*/
if( (pPipe = _popen( "dir *.c /on /p", "rt" )) == NULL )
exit( 1 );
/* Read pipe until end of file, or an error occurs. */
while(fgets(psBuffer, 128, pPipe))
{
printf(psBuffer);
}
/* Close pipe and print return value of pPipe. */
if (feof( pPipe))
{
printf( "\nProcess returned %d\n", _pclose( pPipe ) );
}
else
{
printf( "Error: Failed to read the pipe to the end.\n");
}
}
Seems simple enough. Just need to wrap it with C++ goodness.