posix_spawn a shell script, trouble passing arguments - c++

I need a to be able to use some of the process control facilities provided by posix_spawn() like suspend/resume/kill etc, something that system() does not give me.
So use the following call to posix_spawn() to launch a shell script from a c++ program:
int result = posix_spawn(&spawnedPid, processExecutable, 0, 0, argumentList, 0);
where processExecutable is "foo.sh" and argumentList is {"bar",0,0,0}; The process foo.sh starts up just fine, except for the argumentList part. If I do something like "echo $1" in foo.sh, I get an empty string. If I launch a binary the same way, the arguments are just fine and I can reach them via argv[]. Is there anything I should be doing differently in order to pass arguments to foo.sh ?

Shame on me, the argumentList parameter of posix_spawn() is 0-based so echo $1 actually outputs argumentList[1], which is, naturally, set to 0. Case closed.

Related

iwlist tries to scan all interfaces when called using execl

I am doing a standard fork/execl in C++ on my Ubuntu PC to scan for Wi-Fi SSIDs. It looks like the interface name is not taking effect when called with excel.
execl( "/sbin/iwlist", "wlp4s0", "scanning", (char*) NULL );
This succeeds but I get this in stderr:
lo Interface doesn't support scanning.
enp0s25 Interface doesn't support scanning.
It looks like iwlist is trying to scan all interfaces.
If instead I do:
system( "/sbin/iwlist wlp4s0 scanning" );
I do not get these messages in stderr.
Is there something I am doing wrong in my execl call?
Figured it out.
In bash you always write something like
command arg1 arg2 ...
When the program 'command' parses the its arguments, the first argument (argv[0]) is 'command'.
However, when you call 'command' using using execl like this:
execl( "/path/to/command", "arg1", "arg2", (char*) NULL );
the first argument it gets is 'arg1'. This clearly does not work if the command is expecting this as argv[1] and is instead getting it as argv[0].
This explains why the command was ignoring my "wlp4s0" ifname. It was simply ignoring the first argument which it expected to be the command name/path.
So the solution to my original problem is this:
execl( "/sbin/iwlist", "iwlist", "wlp4s0", "scanning", (char*) NULL );

How can I find why system can not run my application?

I have a c++ program that run a command and pass some arguments to it. The code is as follow:
int RunApplication(fs::path applicationPathName,std::string arguments)
{
std::string applicationShortPath=GetShortFileName(applicationPathName);
std::string cmd="\""+applicationShortPath +"\" "+ arguments+" >>log.txt 2>&1 \"";
std::cout<<cmd<<std::endl;
int result=std::system(cmd.c_str());
return result;
}
When I run system command, the cmd window appears shortly and then closes, but the result is 1 and the cmd was not run (the command should generate output which is not generated).
To check that the cmd is correct, I stopped the application just before system line and copy/ paste cmd content to a cmd window and it worked.
I am wondering how can I find why application is not run in system()?
the cmd has this value just before running it:
"D:/DEVELO~3/x64/Debug/enfuse.exe" -w --hard-mask --exposure-weight=1 --saturation-weight=0.328 --contrast-weight=0.164 -o "C:/Users/m/AppData/Local/Temp/1.tif" "C:/Users/m/AppData/Local/Temp/1.jpg" "C:/Users/m/AppData/Local/Temp/2.jpg" >>log.txt 2>&1 "
How can I find why it is not working?
Is there any way that I set the system so it doesn't close cmd window so I can inspect it?
is there any better way to run a command on OS?
Does Boost has any solution for this?
Edit
After running it with cmd /k, I get this error message:
The input line is too long.
How can I fix it other than reducing cmd line?
There are two different things here: if you have to start a suprocess, "system" is not the best way of doing it (better to use the proper API, like CreateProcess, or a multiplatform wrapper, but avoid to go through the command interpreter, to avoid to open to potential malware injection).
But in this case system() is probably the right way to go since you in fact need the command interpreter (you cannot manage things like >>log.txt 2>&1 with only a process creation.)
The problem looks like a failure in the called program: may be the path is not correct or some of the files it has to work with are not existent or accessible with appropriate-permission and so on.
One of the firt thing to do: open a command prompt and paste the string you posted, in there. Does it run? Does it say something about any error?
Another thing to check is how escape sequence are used in C++ literals: to get a '\', you need '\\' since the first is the escape for the second (like \n, or \t etc.). Although it seems not the case, here, it is one of the most common mistakes.
Use cmd /k to keep the terminal: http://ss64.com/nt/cmd.html
Or just spawn cmd.exe instead and inspect the environment, permissions, etc. You can manually paste that command to see whether it would work from that shell. If it does, you know that paths, permssions and environment are ok, so you have some other issue on your hands (argument escaping, character encoding issues)
Check here How to execute a command and get output of command within C++ using POSIX?
Boost.Process is not official yet http://www.highscore.de/boost/process/

Is it possible to execute another program using C++?

What I'd like to do is have my C++ code open up Mplus (statistical program that I've downloaded on my computer) and run it. Is it possible?
You may be able to do what you want with std::system() calls like:
std::system("program -e input_commands.txt"); // Assuming it accepts some sort of command line args
std::system("program < input_commands.txt"); // Assuming it responds to stdin
It depends on the program if this approach will work.

How to get the return code from a batch/shell script that launched from C++ code

We have a C++ program, sometimes this program need to execute a user defined batch/shell/ant script. We are not able to control how this script runs. Is there a way to get the return code from C++ program?
Something like:
exec a script.sh > status.tmp ?
We need to support both Windows and Linux.
Any ideas?
Another simple of going this is get the return using the marco WEXITSTATUS. Pretty much the same way that you get return values of child process using waitpid call (in Unix based systems).
Here is the sample program. I have one C/C++ program, and one simple bash script.
Sample bash script
#!/bin/bash
echo "I am in Script"
exit 5;
Sample C/C++ program
int i, ret = system("./b.sh 2>&1 > /dev/null");
i=WEXITSTATUS(ret);
printf("My val= %d\n",i);
Output
./a.out
My val= 5
If you want more advanced approach to have multiple return code from the script or want an interactive session then perhaps you should use popen
Hope this helps.
in linux just use
int ret=system("myshellscrtipt.sh");
since the return value of the script is the return value of the system function.
In Windows I'dont't know wether there is a similar function.
If you used the Qt toolkit you could do something like this
QProcess process;
process.start( "yourShellCommand", QStringList( args );
and this would be really cross-platform..
In bash the status code is stored in a special variable:
C:/myprogram.exe
echo $?

C++: How to escape user input for safe system calls?

On a Linux platform, I have C++ code that goes like this:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
std::string command;
command = "mkdir " + myDir;
if (system(command.c_str()) != 0) {
return 1;
}
// continue....
Is passing user input to a system() call safe at all?
Should the user input be escaped / sanitized?
How?
How could the above code be exploited for malicious purposes?
Thanks.
Just don't use system. Prefer execl.
execl ("/bin/mkdir", "mkdir", myDir, (char *)0);
That way, myDir is always passed as a single argument to mkdir, and the shell isn't involved. Note that you need to fork if you use this method.
But if this is not just an example, you should use the mkdir C function:
mkdir(myDir, someMode);
Using system() call with command line parameters without sanitizing the input can be highly insecure.
The potential security threat could be a user passing the following as directory name
somedir ; rm -rf /
To prevent this , use a mixture of the following
use getopt to ensure your input is
sanitized
sanitize the input
use execl instead of system to execute
the command
The best option would be to use all three
Further to Matthew's answer, don't spawn a shell process unless you absolutely need it. If you use a fork/execl combination, individual parameters will never be parsed so don't need to be escaped. Beware of null characters however which will still prematurely terminate the parameter (this is not a security problem in some cases).
I assume mkdir is just an example, as mkdir can trivially be called from C++ much more easily than these subprocess suggestions.
Reviving this ancient question as I ran into the same problem and the top answers, based on fork() + execl(), weren't working for me. (They create a separate process, whereas I wanted to use async to launch the command in a thread and have the system call stay in-process to share state more easily.) So I'll give an alternative solution.
It's not usually safe to pass user input as-is, especially if the utility is designed to be sudo'd; in order to sanitize it, instead of composing the string to be executed yourself, use environment variables, which the shell has built-in escape mechanisms for.
For your example:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
setenv("MY_DIR", myDir, 1);
if (system("mkdir \"${MY_DIR}\"") != 0) {
return 1;
}
// continue....