How can I get the user's locale when running as root? - c++

I am running as root, but have the user's uid (e.g. 504). How can I work out the user's locale (in my case en_GB)? The following does not work:
setuid(user_uid);
fprintf(stderr,
CFStringGetCStringPtr(CFLocaleGetIdentifier(CFLocaleCopyCurrent()),
kCFStringEncodingMacRoman);
setuid(0);
This outputs en_US for me.

This information is contained in GlobalPreferences.plist, so running:
$ defaults read /Library/Preferences/.GlobalPreferences AppleLocale
gives the desired result.

You can't, because it doesn't exist. The locale is controled by
environment variables, and can change dynamically, and from window to
window and even from application to application (i.e. if the user
started a program with:
env LC_LANG=fr_FR program_name ...
.) Under Unix, you might be able to get user's default locale by doing
something like:
FILE* in = popen( "su -c 'env | grep ^LC_ ; env | grep ^LANG' - user", "r" );
, then reading and parsing the input, but I don't think that there's
anything simpler.

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

Unexpected behavior of get_environment_variable with gfortran

I am using a subroutine call to GET_ENVIRONMENT_VARIABLE to read the computer hostname in a Fortran program. I cannot read this variable, though it is okay if I read other variables, as $USER. In my system (Debian Jessie, gfortran 4.9):
$ echo $HOSTNAME
deckard
$ echo $USER
curro
I have prepared this short program:
program hello
!
implicit none
integer :: ivar = 0, len, stat
character(LEN=256) :: host, user
call GET_ENVIRONMENT_VARIABLE('HOSTNAME', host, len, stat)
if (stat == 0) then
print*, "Hostname read: ", host
else
print*, "Hostname read failed: stat = ", stat
endif
call GET_ENVIRONMENT_VARIABLE('USER', user, len, stat)
if (stat == 0) print*, "Username read: ", user
print *, "This is user ", trim(user), " in node ", trim(host), "."
!
end program hello
If I run this simple program (compiled with or without the -std=f2003) the output is:
$ ./a.out
Hostname read failed: stat = 1
Username read: curro
This is user curro in node .
Therefore the error is stat = 1.
I know that gfortran has the intrinsic HOSTNM but for compatibility with other compilers I would prefer GET_ENVIRONMENT_VARIABLE. Any idea why is this happening?
I will suppose that your shell is bash but the end result should not change too much if the actual shell is another one.
In bash, you have access to environment variables and to regular bash variables. To make a variable accessible to child process (that is, programs that are launched by bash such as gfortran or your program 'a.out') it has to be part of the environment. By default, only variables from the posix set of environment variables are passed along (altough some may be omitted).
Examples of posix variables that are accessible both from the bash command line and from your fortran program (or any other program for that matter): HOME, USER, PWD or PATH.
You can verify that they are indeed accessible by checking what the env program knows:
env | grep HOME
env | grep USER
while
env | grep HOSTNAME
returns nothing.
So you need to export the variable HOSTNAME to place it in the list of known environment variable. bash happens to know about hostname because it defines a set of variables for the convenience of the user (see https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html#index-HOSTNAME ). Another example of convenience variables is BASH_VERSION that is specific to bash itself.
export HOSTNAME
env | grep HOSTNAME
but the users of your program (or yourself but on a different computer) might not have access to it as an environment variable so this solution might not be of use to you. The "canonical" way of knowing the hostname without relying on the environment variable, on linux, is to execute the program "hostname".
Have you exported the HOSTNAME variable?
Exporting means that it is available to the child processes as well. That might very well be the difference between the HOSTNAME and USER environment variables that you experience.

sublimerepl getenv failing

I'd like to use the SiblimeREPL package with Sublime Text. When I try to start a REPL, I get
SublimeREPL: obtaining sane environment failed in getenv()
Check console and 'getenv_command' setting
WARN: Falling back to SublimeText environment
This happens regardless of which REPL I try to start. (I tried Ruby, Python, and Clojure.) I tried Sublime Text 2 and Sublime Text 3 with the same results. This is on Mac OS X, if that matters.
I looked in the package settings, where I see
"getenv_command": ["/bin/bash", "--login", "-c", "env"],
If I run "/bin/bash --login -c env" at a Terminal prompt, I get my environment listed.
What do I need to change in order to get a successful getenv_command?
I had the same problem as ssgam. The problem line for me is in the getenv method. It calls subprocess.check_output(getenv_command), which doesn't exist in python 2.6, which ST2 seems to use.
The trick is, it only calls subprocess.check_output() if getenv_command is truthy, and defaults to os.environ.copy() otherwise. So to get ssgam's fix without modifying the SublimeREPL package, in Preferences > Package Settings > SublimeREPL > Settings - User, do something like this:
{
"getenv_command": false
}
I investigated this issue a little bit deeper and it seems SublimeText 3 is also affected. In my case the problem is related to bash-completion feature, in particular COMP_WORDBREAKS environment variable.
Use the following command to show the contents of COMP_WORDBREAKS:
$ echo "$COMP_WORDBREAKS"
will output
"'><=;|&(:
You can also use:
$ echo $COMP_WORDBREAKS
but note that with the second command (without quotes), you'll not see that
the variable also contains a line feed character.
The problem here is the line feed character which breaks output parsing in getenv_command feature. If you extract part of the source code for SublimeREPL you can get real error message from python interpreter.
Traceback (most recent call last):
File "main.py", line 71, in getenv
env = dict(line.split('=', 1) for line in lines)
ValueError: dictionary update sequence element #6 has length 1; 2 is required
You can match element #6 with the position of COMP_WORDBREAKS in env listing.
Solution (first that came to my mind)
I can't tell at the moment what is real impact on bash-completion feature after following solution is applied and of course SublimeREPL hopefully should be fixed accordingly. Please comment my answer to fill in missing knowledge.
We may want to remove disturbing characters to get rid of the error.
First let's identify those characters
$ echo -n "${COMP_WORDBREAKS}" | od -t x1c
will output
0000000 20 09 0a 22 27 3e 3c 3b 7c 26 28 3a
\t \n " ' > < ; | & ( :
0000014
so we have three to remove. The simplest way is to add to your .bashrc following line:
COMP_WORDBREAKS="${COMP_WORDBREAKS#???}"
Voila! No more error message.
My final thought is about removed characters. I'm not fully in how bash-completion works and I'm aware of that modifying COMP_WORDBREAKS can affect other scripts using it. For now you can always change it ad-hoc.
I hope this helped.
Cheers
Found it. Fixed it. SublimeREPL assumes that running getenv_command will produce SOLELY the output from running env, and every line will contain an equals sign. But my .bash_profile echos some stuff to stdout.
The solution was to wrap my .bash_profile output in a
if [[ $- == *i* ]]
to not produce extra output besides the executed command.
TLDR;
Replace:
env = dict(line.split('=', 1) for line in lines)
in ~/.config/sublime-text-3/Packages/SublimeREPL/repls/subprocess_repl.py with
env = dict(line.split('=', 1) for line in lines if '=' in line)
(Thanks #MichaelOhlrogge for the shorter syntax)
Why this works
#develucas's solution helped me solve my issue. I didn't have the problem he was describing, but his investigation helped.
In my case, the login shell had a greeting. So, bash --login -c env (the command specified in SublimeREPL.sublime-settings file under the getenv_command option) was printing something like this:
Hello, parth!
USER=parth
SHELL=/bin/bash
.
.
.
It turns out that SublimeREPL uses the output of this command to load the environment variables - as mentioned in the comment above the getenv_command setting:
// On POSIX system SublimeText launched from GUI does not inherit
// a proper environment. Often leading to problems with finding interpreters
// or not using the ones affected by changes in ~/.profile / *rc files
// This command is used as a workaround, it's launched before any subprocess
// repl starts and it's output is parsed as an environment
"getenv_command": ["/bin/bash", "--login", "-c", "env"],
The code that parses this output is like this (in the ~/.config/sublime-text-3/Packages/SublimeREPL/repls/subprocess_repl.py file for ST3):
def getenv(self, settings):
"""Tries to get most appropriate environent, on windows
it's os.environ.copy, but on other system's we'll
try get values from login shell"""
getenv_command = settings.get("getenv_command")
if getenv_command and POSIX:
try:
output = subprocess.check_output(getenv_command)
lines = output.decode("utf-8", errors="replace").splitlines()
env = dict(line.split('=', 1) for line in lines)
return env
except:
import traceback
traceback.print_exc()
error_message(
"SublimeREPL: obtaining sane environment failed in getenv()\n"
"Check console and 'getenv_command' setting \n"
"WARN: Falling back to SublimeText environment")
# Fallback to environ.copy() if not on POSIX or sane getenv failed
return os.environ.copy()
The env = dict(line.split('=', 1) for line in lines) line causes an issue, because the first line in the bash --login -c env output has no =. So I modified this line to ignore the lines that don't have an = sign:
env = dict(line.split('=', 1) for line in lines if '=' in line)
And this solved the issue for me. Don't forget the restart Sublime Text after modifying this file.
changing COMP_WORDBREAKS does not work for me ...
i'm using ST2, and the exception was thrown at check_output().
also, name completions at the command line fails, after changing COMP_WORDBREAKS.
in my case, i changed subprocess_repl.py's env() method:
[wind]$ diff subprocess_repl.py.20151117.173317 subprocess_repl.py
160c160,161
< updated_env = env if env else self.getenv(settings)
---
> # updated_env = env if env else self.getenv(settings)
> updated_env = env if env else os.environ.copy()
[wind]$
would be interesting to find out why the problem started appearing suddenly ...
hth,cheers,
sam
The answer from #develucas mostly works for me with ST3 with OSX El Capitan except I had to put
export COMP_WORDBREAKS="${COMP_WORDBREAKS#???}"
Note the export. However, if I do this, tab completion no longer works.
I had the same problem, it was my .bash_profile that had some utility outputs, such as a welcome message etc.
These outputs are parsed by SublimeREPL to try to extract environment variables from the output of the env command, and the extraneous text lines mixed together provoked the error.
(I'd like to make a PR to SublimeREPL to try to make that phase more robust, it should not depend on particular .bash_profile implementations!)

How to export registry key in C++

I need help for export a registry key in C++.
cmd = " reg.exe export \"HKLM\\software\\Far manager\" \"C:\Users\\user\\Desktop\\test.reg\" ";
// printf("cmd = %s\n", cmd);
system(cmd);
The code does not work, because a name "Far manager" contains a space and show me "ERROR: The system was unable to find the specified registry key or value."
But if I use the name without a space, for example "Mozilla" the program works great.
I am trying to use "Far%20%manager" and Far%backspace%manager, but it does not work too.
But if I write command in cmd (reg.exe export "HKLM\software\Far manager" "%userprofile%\\Desktop\\test.reg") it works great.
If you have any special characters or spaces in your call to system(), you must wrap the entire command in an extra set of double quotes (i.e. \"). For your example:
cmd = "\"reg.exe export \"HKLM\\software\\Far manager\" \"C:\\Users\\user\\Desktop\\test.reg\"\"";
system(cmd);
Check out here for more info.

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.