Using getenv function in Linux - c++

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.

Related

Show environment variable LD_LIBRARY_PATH

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

C++ execute temp file as bash script

I have a program that needs to run a program we'll call externalProg in parallel on our linux (CentOS) cluster - or rather, it needs to run many instances of externalProg, each on different cores. Each "thread" creates 3 files based on a few parameters - the inputs to externalProg, a command file to tell externalProg how to execute my file, and a bash script to set up the environment (calls a setup script provided by the manufacturer) and actually call externalProg with my inputs.
Since this needs to be parallel with an unknown number of concurrent threads and I don't want to risk overwriting another thread's files, I am creating temp files using
mkstemp("PREFIX_XXXXXX")
for these input files. After the external program runs, I extract the relevant data and store it, and close the temp files (therefore deleting them).
We'll call the files created (Which actually have a name based on the template above)
tmpInputs - Inputs to externalProg
tmpCommand - Input that tells externalProg how to execute tmpInputs
tmpBash - bash script to set up and call externalProg with my inputs
The file tmpBash looks something like
source /path/to/setup/script # Sets up environment variables
externalProg < /path/to/tmpCommand
where tmpCommand is just a simple text file.
The problem I'm having is actually executing the bash script. Within my program, I call
ostringstream launchcmd;
launchcmd << "bash " << path_to_tmpBash
system(launchcmd.str().c_str());
But nothing happens. No error, no warning, no 'file not found' or permission denied or anything. I have verified that the files are being created and have the correct content. The rest of the code after system() is executed successfully (Though it fails since externalProg wasn't run).
Strangely, if I go back to the terminal and type
bash /path/to/tmpBash
then externalProg is executed successfully. I have also cout'd the launchcmd string, copy and pasted that in to the terminal, which also works successfully. For some reason, this only fails when called within my program.
After a bit of experimentation, I've determined that system() calls /bin/sh on our cluster. If I change launchcmd to look like
/path/to/tmpBash
(So that the full command should look like /bin/sh /path/to/tmpBash), I get a permission denied error, which is no surprise. The problem is that I can't chmod +x the tmpBash file while it's still open, and if I close the file, it gets deleted - so I'm not sure how to address that.
Is there something obviously wrong I'm doing, or does system() have some nuance that I'm missing?
edit: I wanted to add that I can successfully call things like
system("echo $PATH")
and get the expected results (in this case, my default $PATH).
Two separate ideas:
Change your SHELL environment variable to be /bin/bash, then call system(),
or:
Use execve directly `execve('/bin/bash', ['/path/to/tmpBash'], environ)

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/

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");

Python not calling an external program part 3

I have been having problems trying to run an external program from a python program that was generated from a trigger in a postgres 9.2 database. The trigger works. It writes to a file. I had tried just running the external program but the permissions would not allow it to run. I was able to create a folder (using os.system(“mkdir”) ). The owner of the folder is NETWORK SERVICE.
I need to run a program called sdktest. When I try to run it no response happens so I think that means that the python program does not have enough permissions (with an owner of NETWORK SERVICE) to run it.
I have been having my program copy files that it needs into that directory so they would have the correct permissions and that has worked to some degree but the program that I need to run is the last one and it is not running because it does not have enough permissions.
My python program runs a C++ program called PG_QB_Connector which calls sdktest.
Is there any way I can change the owner of the process to be a “normal” owner? Is there a better way to do this? Basically I just need to have this C++ program have eniough perms to run correctly.
BTW, when I run the C++ program by hand, the line that runs the sdktest program runs correctly, however, when I run it from the postgres/python it does not do anything...
I have Windows 7, python 3.2. The other 2 questions that I asked about this are located here and here
The python program:
CREATE or replace FUNCTION scalesmyone (thename text)
RETURNS int
AS $$
a=5
f = open('C:\\JUNK\\frompython.txt','w')
f.write(thename)
f.close()
import os
os.system('"mkdir C:\\TEMPWITHOWNER"')
os.system('"mkdir C:\\TEMPWITHOWNER\\addcustomer"')
os.system('"copy C:\\JUNK\\junk.txt C:\\TEMPWITHOWNER\\addcustomer"')
os.system('"copy C:\\BATfiles\\junk6.txt C:\\TEMPWITHOWNER\\addcustomer"')
os.system('"copy C:\\BATfiles\\run_addcust.bat C:\\TEMPWITHOWNER\\addcustomer"')
os.system('"copy C:\\Workfiles\\PG_QB_Connector.exe C:\\TEMPWITHOWNER\\addcustomer"')
os.system('"copy C:\\Workfiles\\sdktest.exe C:\\TEMPWITHOWNER\\addcustomer"')
import subprocess
return_code = subprocess.call(["C:\\TEMPWITHOWNER\\addcustomer\\PG_QB_Connector.exe", '"hello"'])
$$ LANGUAGE plpython3u;
The C++ program that is called from the python program and calls sdktest.exe is below
command = "copy C:\\Workfiles\\AddCustomerFROMWEB.xml C:\\TEMPWITHOWNER\\addcustomer\\AddCustomerFROMWEB.xml";
system(command.c_str());
//everything except for the qb file is in my local folder
command = "C:\\TEMPWITHOWNER\\addcustomer\\sdktest.exe \"C:\\Users\\Public\\Documents\\Intuit\\QuickBooks\\Company Files\\Shain Software.qbw\" C:\\TEMPWITHOWNER\\addcustomer\\AddCustomerFROMWEB.xml C:\\TEMPWITHOWNER\\addcustomer\\outputfromsdktestofaddcust.xml";
system(command.c_str());
It sounds like you want to invoke a command-line program from within a PostgreSQL trigger or function.
A usually-better alternative is to have the trigger send a NOTIFY and have a process with a PostgreSQL connection LISTENing for notifications. When a notification comes in, the process can start your program. This is the approach I would recommend; it's a lot cleaner and it means your program doesn't have to run under PostgreSQL's user ID. See NOTIFY and LISTEN.
If you really need to run commands from inside Pg:
You can use PL/Pythonu with os.system or subprocess.check_call; PL/Perlu with system(); etc. All these can run commands from inside Pg if you need to. You can't invoke programs directly from PostgreSQL, you need to use one of the 'untrusted' (meaning fully privileged, not sandboxed) procedural languages to invoke external executables. PL/TCL can probably do it too.
Update:
Your Python code as shown above has several problems:
Using os.system in Python to copy files is just wrong. Use the shutil library: http://docs.python.org/3/library/shutil.html to copy files, and the simple os.mkdir command to create directories.
The double-layered quoting looks wrong; didn't you mean to quote only each argument not the whole command? You should be using subprocess.call instead of os.system anyway.
Your final subprocess.call invocation appears OK, but fails to check the error code so you'll never know if it went wrong; you should use subprocess.check_call instead.
The C++ code also appears to fail to check for errors from the system() invocations so you'll never know if the command it runs fails.
Like the Python code, copying files in C++ by using the copy shell command is generally wrong. Microsoft Windows provides the CopyFile function for this; equivalents or alternatives exist on other platforms and you can use portable-but-less-efficient stream copying too.