Executing a command shell from popen and set other command shell - c++

I'm working in a project with a quadrotor and mavlink. I have successfully installed mavproxy in my Ubuntu PC and and ran it without problems from terminal. When I run mavproxy.py from the terminal and connected a quadrotor with support for mavlink (APM autopilot), mavproxy detects the quadrotor and everything is ok.
When you execute mavproxy.py the program in the terminal begin to send and receive several parameters. You can write in the terminal some parameter to access for any configuration. For example, the command help in the terminal:
$ mavlink.py
.
.data beging
.
STABILIZE> "when the program finish the configuration, allowed to you for doing an input any parameter, for example help"
STABILIZE>help
show all helps.
I have a code to execute mavlink.py from C++
include <iostream>
include <stdio.h>
using namespace std;
int main() {
FILE *in;
char buff[512];
if(!(in = popen("mavlink.py", "r"))){
return 1;
}
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff;
}
pclose(in);
return 0;
}
When I run this C++ program the terminal shows the same things that would appear if I were running mavproxy.py from the terminal, but I donĀ“t know how can I send a command such as help in the C++ code.
If you read the program, the while statement allows me to capture the parameters generated from the program mavproxy.py and cout in the terminal, but mavlink.py never ends until you write something in the terminal exit or press CTRL + C so the while loop never ends.
I have been reading about the Popen function, but I haven't found the correct form to do this.
I know that I can use the mavlink.h library in my program and send parameters to the quadrotor, but don't want do this with mavlink.h.

I am not sure I understand your question, but I think you want to send commands to mavlink.py as well as read its output.
If that is the case, you must change the open mode of popen() from "r" to "w" so you can write, then you can send commands to it like this:
FILE *fp;
char *command="HELP";
if(!(fp = popen("mavlink.py", "w"))){
return 1;
fwrite(command, sizeof(char), strlen(command), fp);

Related

Transition to command prompt once my console program finishes?

I'm writing some executables that use the Windows console, in C and C++.
I'm trying to get the console to not close after the logic of my program finishes... But not just merely pause or wait, I'd like it to become a cmd.exe command line console itself, ready to accept new prompts.
Essentially I'd like the behavior of running my program via double-clicking or drag-and-dropping to be equivalent to hitting winkey + r and running :
cmd /k "program.exe [list of drag+drop files if any]"
(While not opening a new console if run from a command-line itself.)
Is this possible at all?
Edit
I've been tinkering with this and arrived to a solution that seems to work:
std::getenv("PROMPT") will return 0 when not run from the commandline (I think anyway, not sure if that holds in all cases), and so that can be used to fork the logic depending on how the executable is run.
The following code works for me at least, in my limited experimentation with it. If it's run from the explorer, it uses it's first instance to invoke cmd.exe with parameters that lets THAT instance invoke our program again, with the original parameters.
int main(int argc, char * argv[]) {
// checks if we're in the explorer window, if so delegates to a new instance
if (std::getenv("PROMPT") == NULL) {
printf("Starting from explorer...\n");
std::string str("cmd /Q /k \"");
for (uint32 n = 0; n < argc; ++n) {
str.append("\"");
str.append(argv[n]);
str.append("\"");
if(n < argc-1)
str.append(" ");
}
str.append("\"\n");
system(str.c_str());
return 0;
}
// actual code we want to run
uint32 fileCount = 0;
for (uint32 n = 0; n < argc - 1; ++n) {
fileCount++;
printf("file %02u >> %s\n", n, argv[n+1]);
}
if (fileCount == 0) {
printf("No inputs...\n");
}
return 0;
}
So I guess conceptually, it looks like this.
____stays open_______________________ __closes when finished___
program.exe [paramList] ---> cmd.exe -+-> program.exe [paramList]
|
+-> any subsequent commands
|
etc
In my opinion, you have linked your program as a Windows console program, so it will always open a console terminal when you run it. In that case, your program is presenting the information it outputs in the console (as if the standard output had been redirected to the opened window) this means you cannot use it as a UNIX filter like dir or copy commands. (indeed, you are not in a unix system, so the console is emulated with a special windows library that is linked to your program).
To be able to run your program inside a cmd.exe invocation in a normal window terminal (as you do with the dir command --well, dir is internal to cmd.exe, but others, like xcopy.exe aren't), you need to build your program as a different program type (a unix filter command or a windowless console program, I don't remember the program type name as I'm not a frequent windows developer) so the standard input and the standard output (these are things that Windows hinerits from MS-DOS) are preserved on the program that started it, and you program is capable of running with no window at all.
Windows console program is a different thing that a windows filter program that doesn't require a console to run. The later is like any other ms-dos like command (like dir or copy) and they have an interface more similar to the unix like counterparts.
If you do this, you will be able to run your program from cmd in another window, and it will not create a Windows terminal console to show your program output.
You could simply insert the line
system( "cmd" );
at the end of your program, which will call the command prompt after your program finished executing.
However, this may not fulfil your following requirement:
(While not opening a new console if run from a command-line itself.)
Although using system( "cmd" ); will not open a new console window (it will use the existing one), it will create a new process cmd.exe, which means that you will now have 2 cmd.exe processes if your program was invoked by cmd.exe. Also, if the original cmd.exe process was invoked by your own program, then you will now have 2 processes running your program. If you now call your program again from this new command prompt, you will now have 3 cmd.exe processes and 3 processes running your program. This could get ugly very quickly, especially if you are repeatedly calling your program from a batch file.
In order to prevent this, then your program could try to somehow detect whether its parent process already is cmd.exe, and if it was, it should exit normally instead of invoking cmd.exe again.
Unfortunately, the Windows API does not seem to offer any official way for a child process to obtain the process ID of its parent process. However, according to this page, it is possible to accomplish this using undocumented functions.
Using undocumented functions is generally not advisable, though. Therefore, it would probably be better if you always called your program from a command prompt, so that it could simply exit normally.

Control ubuntu terminal from Qt C++

I want to write a routine that will automatically change my Machine learning parameters and execute the (Machine learning) code multiple times and save its result into a text file.
The Machine learning code is run from the Ubuntu terminal and its result also are written to the Ubuntu terminal.
I need a way to read data and write data to the Ubuntu terminal from the C++ code.
What I have found so far is the QProcess:
QProcess process;
process.start("gnome-terminal"); //THE TERMINAL IS OPENED INDEED
char w[] = "write";
process.write(w,sizeof(w));
process.waitForFinished();
But nothing is written or read from it
What does working is:
QProcess process1;
QProcess process2;
process1.setStandardOutputProcess(&process2);
process1.start("echo 0534230313");
process2.start("sudo -S poweroff");
process2.setProcessChannelMode(QProcess::ForwardedChannels);
And also this works:
int result = system("echo 0534230313 | sudo -S poweroff"); ///COMMANDS TO TERMINAL
int result2 = system("gnome-terminal"); ///OPEN TERMINAL
But the problem is that I wont be able to read the output result (My Machine learning program can open and write to the terminal by itself)
Use the finished signal to read the process output results
connect( poProcess, static_cast<void (QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
[=](int,QProcess::ExitStatus)
{
QByteArray oProcessOutput=
poProcess->readAllStandardOutput();
// Parse the process output.
//
// Mark process for deletion.
emit poProcess->deleteLater();
});

pidof from a background script for another background process

I wrote a c++ program to check if a process is running or not . this process is independently launched at background . my program works fine when I run it on foreground but when I time schedule it, it do not work .
int PID= ReadCommanOutput("pidof /root/test/testProg1"); /// also tested with pidof -m
I made a script in /etc/cron.d/myscript to time schedule it as follows :-
45 15 * * * root /root/ProgramMonitor/./testBkg > /root/ProgramMonitor/OutPut.txt
what could be the reason for this ?
string ReadCommanOutput(string command)
{
string output="";
int its=system((command+" > /root/ProgramMonitor/macinfo.txt").c_str());
if(its==0)
{
ifstream reader1("/root/ProgramMonitor/macinfo.txt",fstream::in);
if(!reader1.fail())
{
while(!reader1.eof())
{
string line;
getline(reader1,line);
if(reader1.fail())// for last read
break;
if(!line.empty())
{
stringstream ss(line.c_str());
ss>>output;
cout<<command<<" output = ["<<output<<"]"<<endl;
break;
}
}
reader1.close();
remove("/root/ProgramMonitor/macinfo.txt");
}
else
cout<<"/root/ProgramMonitor/macinfo.txt not found !"<<endl;
}
else
cout<<"ERROR: code = "<<its<<endl;
return output;
}
its output coming as "ERROR: code = 256"
thanks in advacee .
If you really wanted to pipe(2), fork(2), execve(2) then read the output of a pidof command, you should at least use popen(3) since ReadCommandOutput is not in the Posix API; at the very least
pid_t thepid = 0;
FILE* fpidof = popen("pidof /root/test/testProg1");
if (fpidof) {
int p=0;
if (fscanf(fpidof, "%d", &p)>0 && p>0)
thepid = (pid_t)p;
pclose(fpidof);
}
BTW, you did not specify what should happen if several processes (or none) are running the testProg1....; you also need to check the result of pclose
But you don't need to; actually you'll want to build, perhaps using snprintf, the pidof command (and you should be scared of code injection into that command, so quote arguments appropriately). You could simply find your command by accessing the proc(5) file system: you would opendir(3) on "/proc/", then loop on readdir(3) and for every entry which has a numerical name like 1234 (starts with a digit) readlink(2) its exe entry like e.g. /proc/1234/exe ...). Don't forget the closedir and test every syscall.
Please read Advanced Linux Programming
Notice that libraries like Poco or toolkits like Qt (which has a layer QCore without any GUI, and providing QProcess ....) could be useful to you.
As to why your pidof is failing, we can't guess (perhaps a permission issue, or perhaps there is no more any process like you want). Try to run it as root in another terminal at least. Test its exit code, and display both its stdout & stderr at least for debugging purposes.
Also, a better way (assuming that testProg1 is some kind of a server application, to be run in at most one single process) might be to define different conventions. Your testProg1 might start by writing its own pid into /var/run/testProg1.pid and your current application might then read the pid from that file and check, with kill(2) and a 0 signal number, that the process is still existing.
BTW, you could also improve your crontab(5) entry. You could make it run some shell script which uses logger(1) and (for debugging) runs pidof with its output redirected elsewhere. You might also read the mail perhaps sent to root by cron.
Finally I solved this problem by using su command
I have used
ReadCommanOutput("su -c 'pidof /root/test/testProg1' - root");
insteadof
ReadCommanOutput("pidof /root/test/testProg1");

execute and receive the output of mml command in c++

i have an interface where i use to execute the mml command in my solaris unix like below:
> eaw 0004
<RLTYP;
BSC SYSTEM TYPE DATA
GSYSTYPE
GSM1800
END
<
As soon as i do eaw <name> on the command line.It will start an interface where in i can execute mml commands and i can see the output of those commands executed.
My idea here is to parse the command output in c++.
I can do away with some logic for parsing.But to start with How can get the command to be executed inside c++ ? Is there any predefined way to do this.
This should be similar to executing sql queries inside c++.But we use other libraries to execute sql queries.I also donot want to run a shell script or create temporary files in between.
what i want is to execute the command inside c++ and get the output and even that in c++.
could anybody give me the right directions?
You have several options. From easiest and simplest to hardest and most complex to use:
Use the system() call to spawn a shell to run a command
Use the popen() call to spawn a subprocess and either write to its standard input stream or read from its standard output stream (but not both)
Use a combination of pipe(), fork(), dup()/dup2(), and exec*() to spawn a child process and set up pipes for a child process's standard input and output.
The below code is done with the sh command. This redirects stdout to a file named "out" which can be read later to process the output. Each command to the process can be written through the pipe.
#include <stdio.h>
int main()
{
FILE *fp;
fp = popen("sh > out", "w");
if (fp) {
fprintf(fp, "date\n");
fprintf(fp, "exit\n");
fclose(fp);
}
return 0;
}

C++ Save console output to a text file before quit WINAPI ( No MFC )

I am trying to get my program to log the output of a console application to a text file before it quits. This is a GUI program which launches the console application (tool.exe). The problem is that I am using CTRL + C to quit the console application. This console application cant be altered either. I have tried a few ways of doing this but none have seemed to work ( tool.exe > output.txt ).
Can anyone point me in the right direction of which approach to take ? It would be greatly appreciated.
EDIT:
The file is created but it is empty and does not receive any data. The thing I am after noticing though is if I run the tool from the command line myself, it will work. Eg. c:\>tool.exe > output.txt However this is not working when its executed from my GUI application.
Here is the code I am using to execute the tool:
strcpy (tool, "\" start /D \"");
strcat (tool, toolLocation);
strcat (tool, "\" tool.exe > output.txt\"");
system (tool);
This will run tool.exe and create output.txt fine but will not output anything to the file.
EDIT2:
I think what is actually happening is that because I am using start , the >output.txt is outputing start instead of tool.exe. This would explain why it creates the empty file. Start is just running a fresh command line which is then running tool.exe. The problem is, how do I get around this issue now ?
Try:
#include <signal.h>
void signal_handlerkill(int sig)
{
//Do Soemthing
exit(1);
}
int main()
{
signal(SIGINT, signal_handlerkill); //Connect the interrupt signal (^C) to the function
//Do your code here
return 0;
}
And if that doesn't work, I'd suggest looking here. Specifically:
// crt_signal.c
// compile with: /c
// Use signal to attach a signal handler to the abort routine
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Application aborting...\n");
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGABRT, SignalHandler);
abort();
}
If you run the application without redirecting to a file, do you see the output you need on the console when you press ctrl+c?
If you don't then there is nothing you can do since you cannot change the application.
Update
What you need is to redirect stdout and stderr to the file. I have never done that but jamesdlin seems to have done that. Take a look at his comment.
What you could try is instead of using start try using cmd.exe directly.
This is the code which managed to solve the problem for me:
char path[500]; //Create character array
strcpy (path, "cd "); //Copy 'cd' into the array
strcat (path, toolLocation); //Copy the path of the tool into the array
strcat (path, " & ip.exe > output.txt"); //Append on the name of the exe and output to a file
system (path); //Run the built array
I am creating a character array and then appending to it. The vital bit here was the & being used in the system call. This is working as an and and first cd'ing to the firectory before executing the .exe.