Show environment variable LD_LIBRARY_PATH - c++

I have simple console application that prints environment variables:
int main(int argc, char **argv, char **envp)
{
printf("Scanning for LD_LIB_PATH\n");
for (char **env = envp; *env != 0; env++)
{
char *thisEnv = *env;
std::string s= *env;
if (s.find("LD_LIBRARY_PATH")!=std::string::npos)
{
printf("!!!!!!! %s\n", thisEnv);
}
printf("%s\n", thisEnv);
}
}
Before run executable I run script that sets LD_LIBRARY_PATH
export LD_LIBRARY_PATH=~/aaa/bbb/Debug:~/ccc/ddd/Debug
echo "searching:"
export | grep LD_LIBRARY
echo "done"
Script run fine with output:
exporting
searching:
declare -x LD_LIBRARY_PATH="/home/vicp/aaa/bbb/Debug:/home/vico/ccc/ddd/Debug"
done
I run executable and it finds many variables but no environment variable LD_LIB_PATH. Why?
UPD
As recommended I script . ./script.sh
Then double check with command:
export |grep LD_LIBRARY_PATH
Got output:
declare -x LD_LIBRARY_PATH="/home/vicp/aaa/bbb/Debug:/home/vico/ccc/ddd/Debug"
But still don't see LD_LIBRARY_PATH in my programm.

Depending on how you run the script, the env variable will only be added to the environment of the subshell running the script.
If you run the script like this:
$ ./script.sh
This will spawn a new shell wherein the script is run. The parent shell, i.e. the one you started the script from, will not be affected by what the script does. Changes to the environment will therefore not be visible (changing the working directory or similar will also not work).
If the script is intended to modify the environment of the current shell, the script needs to be sourced using the . or source commands:
$ . ./script.sh
$ source ./script.sh
From help source in bash:
Execute commands from a file in the current shell.
Then there seems to be a problem with the code:
As a commenter stated previousy, there are a lot of exclamation points in the success case printf. I presume these were meant to highlight the found variable name. Since they are outside of the opening quote of the format string, they are interpreted as logical not operators.
The result is that the format string literal (a pointer) is negated, resulting in false due to the number of operators. This usually maps to 0, which would mean the format string becomes a null pointer. What happens when handing a null pointer to printf as the format string depends, as far as I can tell, on the implementation. If it doesn't crash, it most certainly will not print anything however.
So the code may actually work, but there is no visible output due to that bug. To fix it, move the exclamation points into the format string, i.e. after the opening quote.

Look at the line printf(!!!!!!!"%s\n", thisEnv);
Change to printf("!!!! %s\n", thisEnv);

It has nothing to do with your C/C++ application.
try the following:
$ ./script.sh
$ echo $LD_LIBRARY_PATH
And you'll see that LD_LIBRARY_PATH is not set
When you launch your script, bash creates a new process with its environment inherited from the original bash process. In that newly created process, you set the process environment variable LD_LIBRARY_PATH=xxxx
When finalized your script.sh exits, and its environment dies with it.
Meaning the LD_LIBRARY_PATH is not set in your original shell.
As mentioned here above you need to run your script in the current shell
Either with . or with source.
I tested with your C/C++ and it works

Related

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/

Permissions issue calling bash script from c++ code that apache is running

The goal of this code is to create a stack trace whenever a sigterm/sigint/sigsegv/etc is caught. In order to not rely on memory management inside of the C++ code in the case of a sigsegv, I have decided to write a bash script that will receive the PID and memory addresses in the trace array.
The Sig events are being caught.
Below is where I generate the call to the bash script
trace_size = backtrace(trace, 16);
trace[1] = (void *)ctx->rsi;
messages = backtrace_symbols(trace, trace_size);
char syscom[356] = {0};
sprintf(syscom,"bash_crash_supp.sh %d", getpid());
for (i=1; i<(trace_size-1) && i < 10; ++i)
{
sprintf(syscom,"%s %p",syscom,trace[i]);
}
Below is where my issue arises. The command in syscom is generating correctly. I can stop the code before the following popen, run the command in a terminal, and it functions correctly.
However running the script directly from the c++ code does not seem to work.
setuid(0);
FILE *bashCommand = popen(syscom,"r");
char buf[256] = {0};
while(fgets(buf,sizeof(buf),bashCommand) != 0) {
LogMessage(LOG_WARNING, "%s\n", buf);
}
pclose(bashCommand);
exit(sig);
The purpose of the bash script is to get the offset from /proc/pid/maps, and then use that to run addr2line to get the file name/line number.
strResult=$(sudo cat /proc/"$1"/maps | grep "target_file" | grep -m 1 '[0-9a-fA-F]')
offset=$( cut -d '-' -f 1 <<< "$strResult");
However offset is getting 0 when I run from the c++ code, but when I run the exact same command (that is stored in syscom in the c++ code) in a terminal, I get the expected output.
I have been trying to fix this for a while. Permissions are most likely the issue, but I've tried to work around these with every way I know of/have seen via google. The user trying to run the script (currently running the c++ code) is apache.
The fix does not need to worry about the security of the box. If something as simple as "chmod 777 /proc -r" worked, that would have been the solution (sadly the OS doesn't let me mess do such commands with /proc).
Things I've already tried:
Adding `` around the command that's stored in syscom from the c++ code
chown the script to apache
chmod 4755 on the bash_crash_supp.sh script, allowing it to always fire as root.
I have added apache to sudoers (visudo), allowing them to run sudo without using a password
I have added a sub file to sudoers.d (just in case) that does the same as above
I have looked into objdump, however it does not give me either the offset or the file/line num for an addr (from what I can see)
I have setuid(0) in the c++ code to set the current user to root
Command generated in C++
bash_crash_supp.sh 25817 0x7f4bfe600ec8 0x7f4bf28f7400 0x7f4bf28f83c6 0x7f4bf2904f02 0x7f4bfdf0fbb0 0x7f4bfdf1346e 0x7f4bfdf1eb30 0x7f4bfdf1b9a8 0x7f4bfdf176b8
Params in bash:
25817 0x7f4bfe600ec8 0x7f4bf28f7400 0x7f4bf28f83c6 0x7f4bf2904f02 0x7f4bfdf0fbb0 0x7f4bfdf1346e 0x7f4bfdf1eb30 0x7f4bfdf1b9a8 0x7f4bfdf176b8
Can anyone think of any other ways to solve this?
Long story short, almost all Unix-based systems ignore setuid on any interpreted script (anything with a shebang #!) as a security precaution.
You may use setuid on actual executables, but not the shell scripts themselves. If you're willing to take a massive security risk, you can make a wrapper executable to run the shell script and give the executable setuid.
For more information, see this question on the Unix StackExchange: https://unix.stackexchange.com/a/2910

Passing the environment variables to the launched process bash script

Under linux, I have a bash script, that launches a c++ program binary.
What I need to do is set an environment variable in that script, and access that variable
inside the launched C++ program using getenv .
Here is the code for the script
#!/bin/bash
export SAMPLE_VAR=1
./c++_binary
The c++ program:
char * env_var = getenv("SAMPLE_VAR");
if (env_var != NULL) printf("var set\n");
However this does not seem to work. From what I understand is that when we execute the script, it will run in a new subshell and set the environment variable SAMPLE_BAR there, but the C++ binary is launched in the same subshell as well (may be I am wrong here) so it should have access to the SAMPLE_VAR. I even tried writing a separate script that just sets the env variable, and in the main script I called that script as source env_var_set.sh to no avail.
Is it possible to pass on a newly set environment variable to a program this way ?
Thanks
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
Ah Sorry for the Typos, And my mistake, Inside the script I was launching the binary with 'sudo' which ran it in root's env and didnt have the variable set there. Removed sudo and it worked fine. Sorry for the confusion. Cheers. – Abdullah
First of all you need to source your shell script in order for the env variable to be set. and secondly include quotes in the getenv call.
char * env_var = getenv("SAMPLE_VAR");
if (env_var != NULL) printf("var set\n");

Problems passing source command to bash from c++ application

I am developing an application for work that allows the users to quickly set environment variables on a terminal basis. By setting the path in each terminal we ensure files with the same name in different directories aren't causing application testing to be problematic. I am Using Qt to build the program which is c++ based and all the datatypes are foundationally the same.
I am using the following code to invoke commands in the terminal from which the application launches from using system(). I can run commands into the bash just fine with code; however, I run into a problem when I attempt to use a command with arguments. This is probably why source doesn't seem to work right as the source command is followed by the filename. It would appear that I drop the argument appended after the bash command.
My Code:
void assignTerminalToPath(QString path)
{
QString data = "";
QString currentUsersHomeDirectory = QDir::homePath();
QString tmpScriptLocation = currentUsersHomeDirectory;
QByteArray ba;
tmpScriptLocation += "/.tmpSourceFile";
QFile tmpSourceFile(tmpScriptLocation);
if(tmpSourceFile.open(QFile::WriteOnly | QFile::Truncate))
{
QTextStream output(&tmpSourceFile);
data.append("export PATH=.:");
data.append(path);
data.append(":$PATH");
output << QString("#!/bin/bash\n");
output << data;
tmpSourceFile.close();
}
data.clear();
data.append("/bin/bash -c source ");
data.append(tmpScriptLocation);
ba = data.toLatin1();
const char *cStr = ba.data();
system(cStr);
}
Perhaps I'm not referencing bash correctly and I need something outside of -c?
Reference Execute shell/bash command using C/C++
Thanks for any help in advance!
source is not a program that you can call, it is embedded bash command. It is designed to be processed by bash without invoking another copy of bash, such that environment variables can be changed in current bash copy.
However, you cannot call source as part of system(). And even if you did succeed at that, its effects to change environment variables would be completely lost for caller app once system() has returned.
Try a command to envelop with parameters in double quotes ("command - arg1 - to arg2") to transfer in the function system().
used:
char *com = "\"command -arg1 -arg2\"";
system(com);

Using getenv function in Linux

I have this following simple program:
int main()
{
char* v = getenv("TEST_VAR");
cout << "v = " << (v==NULL ? "NULL" : v) << endl;
return 0;
}
These lines are added to .bashrc file:
TEST_VAR="2"
export TEST_VAR
Now, when I run this program from the terminal window (Ubuntu 10.04), it prints v = 2. If I run the program by another way: using launcher or from Eclipse, it prints NULL. I think this is because TEST_VAR is defined only inside bash shell. How can I create persistent Linux environment variable, which is accessible in any case?
On my system (Fedora 13) you can make system wide environment variables by adding them under /etc/profile.d/.
So for example if you add this to a file in /etc/profile.d/my_system_wide.sh
SYSTEM_WIDE="system wide"
export SYSTEM_WIDE
and then open a another terminal it should source it regardless of who the user is opening the terminal
echo $SYSTEM_WIDE
system_wide
Add that to .bash_profile (found in your home directory). You will need to log out and log back in for it to take effect.
Also, since you are using bash, you can combine the export and set in a single statement:
export TEST_VAR="2"
Sorry if I'm being naive but isn't .bash_profile useful only if you are running bash as your default shell ?
I 'sometimes' use Linux and mostly use ksh. I have .profile so may be you should check for .*profile and export the variable there.
Good luck :)
There is no such thing as a system-wide environment variable on Linux. Every process has its own environment. Now by default, every process inherits its environment from its parent, so you can get something like a system-wide environment by ensuring that a var is set in an ancestor of every process of interest. Then, as long as no other process changes that var, every process of interest will have it set.
The other answers here give various methods of setting variables early. For example, .bash_profile sets it in every login process a user runs, which is the ultimate parent of every process they run after login.
/etc/profile is read by every bash login by every user.