For Programmers: Free Programming Magazines  


Home > Archive > Unix Programming > September 2004 > Finding environment variables usage









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Finding environment variables usage
LTeixeir

2004-09-25, 9:00 am

Hi everybody,

How can I find which environment variables a certain process is using? Any
ideas?

Thanks....

LTeixeir


Bill Marcum

2004-09-25, 9:00 am

On Sat, 25 Sep 2004 11:35:51 +0100, LTeixeir
<luistex@hotmail.com> wrote:
> Hi everybody,
>
> How can I find which environment variables a certain process is using? Any
> ideas?
>

If you have the /proc filesystem, proc/$PID/environ


--
System Events
=-=-=-=-=-=-=
Sep 16 03:31:11 don kernel: lp0 on fire

Jens.Toerring@physik.fu-berlin.de

2004-09-25, 9:00 am

LTeixeir <luistex@hotmail.com> wrote:
> How can I find which environment variables a certain process is using? Any
> ideas?


From within the process? Depends on the language you're using. E.g.
under C can declare the external variable

extern char **environ;

which is an array of char pointers, each pointing to string a
with one of the environment variables in the form 'name=value'
(and the last one pointing to a NULL pointer). In Perl you
should print a list of all of them by iterating over the %ENV
hash like this

print "$_=$ENV{$_}\n" foreach keys %ENV;

Finding out for a different process is more difficult and system
dependent. E.g. under Linux you could read the pseudo-file
'/proc/PID/environ' (replace PID with the numerical process ID).

Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Pascal Bourguignon

2004-09-25, 3:58 pm

Jens.Toerring@physik.fu-berlin.de writes:

> LTeixeir <luistex@hotmail.com> wrote:
>
> Finding out for a different process is more difficult and system
> dependent. E.g. under Linux you could read the pseudo-file
> '/proc/PID/environ' (replace PID with the numerical process ID).


/proc/$PID/environ gives the current environment of the process, not
the variables that are actually USED by the process!

The answer is that in general it is not possible to find it!

(Actually, it has been proved mathematically that it is not possible
to answer any non trival question about any program, "in general", so
the answer is always: in general, it's not possible).


But for processes built from some restricted class of programs,
namely those who just keep the names of the environment variables they
use as literal strings with no trick such as encrypting them,
compressing them, building them dynamically, loading them from a file
or other I/O, or indirectly from the value of another environment
variable, etc, then it's possible to guess a superset of which
environment variables COULD be used by such a given program by dumping
the strings it contains.

For example, start with:

strings /bin/ls|egrep -v '[^A-Za-z0-9_]'

usually, environment variables names are all upcase, but there may be
exceptions.

strings /bin/ls|egrep -v '[^A-Z0-9_]'

_DYNAMIC
_GLOBAL_OFFSET_TABLE_
VUUU
QUOTING_STYLE
LS_BLOCK_SIZE
COLUMNS
POSIXLY_CORRECT
TABSIZE
TIME_STYLE
LS_COLORS
POSIX
KMGTPEZY

So, if /bin/ls is in the restricted class above mentionned, here you
have a superset of the environment variables that are used by ls.

Actually, ls "dynamically" links with a library that will use some
other environment variables, such as LC_ALL, LC_COLLATE and the other
LC_ variables. So you'd have to include theses libraries. Use ldd to
list the dynamic libraries used, and recursively check they are in the
restricted program class above defined and apply strings and ldd on
them to gather all the environment variable names.

ldd /bin/ls

librt.so.1 => /lib/librt.so.1 (0x40016000)
libacl.so.1 => /lib/libacl.so.1 (0x40029000)
libc.so.6 => /lib/libc.so.6 (0x4002f000)
libpthread.so.0 => /lib/libpthread.so.0 (0x40162000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
libattr.so.1 => /lib/libattr.so.1 (0x401b3000)




But may be you don't want to know what variable a process USES,
but what variable a process NEEDS (keeping in mind that most programs
are written to use default values when a "needed" environment variable
is not available. But with a differential analysis, you could
determine which environment variable has an effect on the processes
built from a given program. Use env to remove all environment variables:

Observe the difference in behavior between:

env -i program

and:

program


Finally, the best is to use the source, Luke.

--
__Pascal Bourguignon__ http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
Nick Landsberg

2004-09-25, 3:58 pm

Jens.Toerring@physik.fu-berlin.de wrote:

> LTeixeir <luistex@hotmail.com> wrote:
>
>
>
> From within the process? Depends on the language you're using. E.g.
> under C can declare the external variable
>
> extern char **environ;
>
> which is an array of char pointers, each pointing to string a
> with one of the environment variables in the form 'name=value'
> (and the last one pointing to a NULL pointer). In Perl you
> should print a list of all of them by iterating over the %ENV
> hash like this
>
> print "$_=$ENV{$_}\n" foreach keys %ENV;
>
> Finding out for a different process is more difficult and system
> dependent. E.g. under Linux you could read the pseudo-file
> '/proc/PID/environ' (replace PID with the numerical process ID).
>
> Regards, Jens


I believe that the OP wanted to know which env variables
the process "is using", by which I presume he meant
which env variables the process needs, not just what
is in the environment at invocation. That is, if I have
FOOBAR="something" (appropriately exported in my environment),
and I issue the command "cat junk"
"cat" will inherit the env. variable FOOBAR but will
never actually use it. (Someone correct me if I'm wrong,
please.)

Now, off the top of the head, I can't think of of a
foolproof way, but, if a process uses an env. variable,
it will most likely have to call getenv(), which probably
means it will have to have a literal string with the
name of the env. variable somewhere in the code.
Assuming that most env. variables are by convention
named in upper case, one may run "strings" on the
binary and look for all upper-case strings. Of course,
"strings" will return just about every literal string
in the code (and some stuff which may not be literal
strings but a series of instructions which happen to have the
same bit-pattern as a string), but it's a start.

NPL


--
"It is impossible to make anything foolproof
because fools are so ingenious"
- A. Bloch
Jonathan Adams

2004-09-25, 3:58 pm

In article <j61g22-j7r.ln1@don.localnet>,
Bill Marcum <bmarcum@iglou.com.urgent> wrote:

> On Sat, 25 Sep 2004 11:35:51 +0100, LTeixeir
> <luistex@hotmail.com> wrote:
> If you have the /proc filesystem, proc/$PID/environ


.... and you are running Linux. On Solaris 9 and greater, the pargs(1)
program exists, and accepts the '-e' flag to print the full environment
of the process (and works against core files)

You can also use the 'e' flag to the Berkeley version of ps and a
plethora of 'w' options to retrieve them:

/usr/ucb/ps ewwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
wwwwwwwwwwwww

(supported by /bin/ps on Linux)

This has the distinct advantage of cluing you in to the wonderful output
format in advance.

Cheers,
- jonathan
Barry Margolin

2004-09-25, 3:58 pm

In article <j61g22-j7r.ln1@don.localnet>,
Bill Marcum <bmarcum@iglou.com.urgent> wrote:

> On Sat, 25 Sep 2004 11:35:51 +0100, LTeixeir
> <luistex@hotmail.com> wrote:
> If you have the /proc filesystem, proc/$PID/environ


That will show the values of the environment variables, it won't tell
you which ones the application actually cares about. E.g. PATH will be
set in most processes, but unless the process calls execvp(), execlp(),
or system() it probably doesn't *use* this variable.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Paul Pluzhnikov

2004-09-25, 3:58 pm

"LTeixeir" <luistex@hotmail.com> writes:

> How can I find which environment variables a certain process is using?


Assuming you really want to know what 'getenv()'s the process
performed, and assuming the process is dynamically linked, here is
how you find an answer on Linux:

$ ltrace -e getenv /bin/ls > /dev/null
getenv("QUOTING_STYLE") = NULL
getenv("LS_BLOCK_SIZE") = NULL
getenv("BLOCK_SIZE") = NULL
getenv("POSIXLY_CORRECT") = NULL
getenv("COLUMNS") = NULL
getenv("POSIXLY_CORRECT") = NULL
getenv("TABSIZE") = NULL
+++ exited (status 0) +++

on Solaris I would have expected similar result from

truss -u libc:getenv /bin/ls

but that didn't work -- truss appears to only intercept "top-level"
calls from the traced executable, not intra-libc calls.

Anyway, an LD_PRELOAD solution works on Solaris, and possibly
other platforms. I can provide details if you tell what OS you want
an answer for.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Norm Dresner

2004-09-25, 8:57 pm

"LTeixeir" <luistex@hotmail.com> wrote in message
news:415549fd$0$3057$a729d347@news.telepac.pt...
> Hi everybody,
>
> How can I find which environment variables a certain process is using? Any
> ideas?
>


One way to find out what environment strings a program *may* reference is to
run the command "strings" on the executable file and examine the output for
possible environment variable names. It's far from foolproof but it's a
start
Norm

Måns Rullgård

2004-09-25, 8:57 pm

"Norm Dresner" <ndrez@att.net> writes:

> "LTeixeir" <luistex@hotmail.com> wrote in message
> news:415549fd$0$3057$a729d347@news.telepac.pt...
>
> One way to find out what environment strings a program *may* reference is to
> run the command "strings" on the executable file and examine the output for
> possible environment variable names. It's far from foolproof but it's a
> start


Occasionally it's even useful. I have had to resort to such methods
in order to figure out the names and allowed values of configuration
file parameters for less-than-well-documented proprietary software.

--
Måns Rullgård
mru@mru.ath.cx
LTeixeir

2004-09-25, 8:57 pm

Hello all,

And first of all thanks for the help....

This new project I'm working with is huge: aproximatelly 1000 C/C++ source
code files and 70-80 binaries (both libs and processes)!
The system runs on both the Linux x86 and Solaris platforms and heavilly
depends on environment variables (to hold config paths/files, third party
tools instalation paths, you name it...).
In order to estimate the impact (my assignment) on getting rid of all those
environment variables (someone else's decision) I need to know which process
(or lib) actually needs them.
I think this is not a trivial problem. I was hoping in finding a totally
safe solution to this problem using the binaries.... But on second thought ,
that seems impossible. My best bet is to parse the code and try to find
where 'getenv()' is beeing called and then determine which process/lib will
actually run that code.
Still a lot of work!...
Does anyone think there's better way?


Thanks again,
LTeixeir




"Paul Pluzhnikov" <ppluzhnikov-nsp@charter.net> wrote in message
news:m3brfury0k.fsf@salmon.parasoft.com...
> "LTeixeir" <luistex@hotmail.com> writes:
>
>
> Assuming you really want to know what 'getenv()'s the process
> performed, and assuming the process is dynamically linked, here is
> how you find an answer on Linux:
>
> $ ltrace -e getenv /bin/ls > /dev/null
> getenv("QUOTING_STYLE") = NULL
> getenv("LS_BLOCK_SIZE") = NULL
> getenv("BLOCK_SIZE") = NULL
> getenv("POSIXLY_CORRECT") = NULL
> getenv("COLUMNS") = NULL
> getenv("POSIXLY_CORRECT") = NULL
> getenv("TABSIZE") = NULL
> +++ exited (status 0) +++
>
> on Solaris I would have expected similar result from
>
> truss -u libc:getenv /bin/ls
>
> but that didn't work -- truss appears to only intercept "top-level"
> calls from the traced executable, not intra-libc calls.
>
> Anyway, an LD_PRELOAD solution works on Solaris, and possibly
> other platforms. I can provide details if you tell what OS you want
> an answer for.
>
> Cheers,
> --
> In order to understand recursion you must first understand recursion.
> Remove /-nsp/ for email.



Paul Pluzhnikov

2004-09-26, 3:56 am

"LTeixeir" <luistex@hotmail.com> writes:

> And first of all thanks for the help....


[Please do not top-post.]

> I was hoping in finding a totally
> safe solution to this problem using the binaries.... But on second thought ,
> that seems impossible.


Huh? How did you come to that conclusion?

It would appear that simply running all your binaries under
'ltrace -e getenv' will give you >90% of the answer.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Pascal Bourguignon

2004-09-26, 3:56 am

Paul Pluzhnikov <ppluzhnikov-nsp@charter.net> writes:

> "LTeixeir" <luistex@hotmail.com> writes:
>
>
> [Please do not top-post.]
>
>
> Huh? How did you come to that conclusion?


Start reading the Gödel theorem, and next some computability theory.


> It would appear that simply running all your binaries under
> 'ltrace -e getenv' will give you >90% of the answer.


int main(int argc,char** argv,char** envv){
int s=0;
for(i=0;envv[i]!=0;i++){if(i%2){s+=*(str
chr(envv[i],'=')+1);}}
print("%d\n",s);
return(0);
}

Now, ltrace that and tell me what variables were used!

--
__Pascal Bourguignon__ http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
Paul Pluzhnikov

2004-09-26, 3:56 am

Pascal Bourguignon <spam@mouse-potato.com> writes:

> Start reading the Gödel theorem, and next some computability theory.


Oh, look how smart you are. Congratulations, I am impressed.

> Now, ltrace that and tell me what variables were used!


You didn't read my previous message in this thread, nor apparently
the original message. The OP wants to know which binaries *call*
getenv(), and what variables they are interested in.

*Assuming* the binaries are dynamically linked, on Linux, one can
get a pretty good answer with ltrace.

The fact that you can write a program that doesn't call getenv()
is irrelevant. The fact that I can write 5 more such programs,
accessing environment in different ways and bypassing dynamic linker
(and thus also circumventing ltrace), is also irrelevant.

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Pascal Bourguignon

2004-09-26, 3:56 am

Paul Pluzhnikov <ppluzhnikov-nsp@charter.net> writes:

> Pascal Bourguignon <spam@mouse-potato.com> writes:
>
>
> Oh, look how smart you are. Congratulations, I am impressed.
>
>
> You didn't read my previous message in this thread, nor apparently
> the original message. The OP wants to know which binaries *call*
> getenv(), and what variables they are interested in.


Yes, as it clearly shows in the original post:
------------------------------------------------------------------------
From: "LTeixeir" <luistex@hotmail.com>
Subject: Finding environment variables usage
Newsgroups: comp.unix.programmer
Date: Sat, 25 Sep 2004 11:35:51 +0100
Organization: Telepac II - Comunicacoes Interactivas, SA

Hi everybody,

How can I find which environment variables a certain process is using? Any
ideas?

Thanks....

LTeixeir
------------------------------------------------------------------------


> *Assuming* the binaries are dynamically linked, on Linux, one can
> get a pretty good answer with ltrace.
>
> The fact that you can write a program that doesn't call getenv()
> is irrelevant. The fact that I can write 5 more such programs,
> accessing environment in different ways and bypassing dynamic linker
> (and thus also circumventing ltrace), is also irrelevant.


Try this:

int main(int argc,char** argv,char** envv){
int s=0;
for(i=0;envv[i]!=0;i++){
char* val=strchr(getenv(envv[i]));
if(val[1]%2){s+=val[2];}}
print("%d\n",s);
return(0);
}

Now, ltrace that and tell me what variables were _really_ _used_!

--
__Pascal Bourguignon__ http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
Pascal Bourguignon

2004-09-26, 3:56 am

"LTeixeir" <luistex@hotmail.com> writes:

> Hello all,
>
> And first of all thanks for the help....
>
> This new project I'm working with is huge: aproximatelly 1000 C/C++ source
> code files and 70-80 binaries (both libs and processes)!
> The system runs on both the Linux x86 and Solaris platforms and heavilly
> depends on environment variables (to hold config paths/files, third party
> tools instalation paths, you name it...).
> In order to estimate the impact (my assignment) on getting rid of all those
> environment variables (someone else's decision) I need to know which process
> (or lib) actually needs them.
> I think this is not a trivial problem. I was hoping in finding a totally
> safe solution to this problem using the binaries.... But on second thought ,
> that seems impossible. My best bet is to parse the code and try to find
> where 'getenv()' is beeing called and then determine which process/lib will
> actually run that code.
> Still a lot of work!...
> Does anyone think there's better way?


tracing getenv could give your a first approximation, but if your
programs could as well not used it, or read with it all the variables
and still not used them.

The best way is to analyse the data flow in the sources. Even if it's
huge, you should be able to find the place where getenv, putenv, main,
environ are used and from there where go the variables to check if and
how they're used.

It's not trivial since it cannot be (entirely) done automatically.

--
__Pascal Bourguignon__ http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
LTeixeir

2004-09-26, 9:07 am

Ok fellows...
Thanks a lot for your help. This discussion has been very interesting and
usefull...
I think I'll use a little bit of both:
ltrace for the binaries for a first approach to the problem
and if necessary then i'll throw some thought on the source code problem.

Thanks!

LTeixeir

"LTeixeir" <luistex@hotmail.com> wrote in message
news:415549fd$0$3057$a729d347@news.telepac.pt...
> Hi everybody,
>
> How can I find which environment variables a certain process is using? Any
> ideas?
>
> Thanks....
>
> LTeixeir
>
>



Barry Margolin

2004-09-26, 3:57 pm

In article <871xgpy72z.fsf@thalassa.informatimago.com>,
Pascal Bourguignon <spam@mouse-potato.com> wrote:

> Try this:
>
> int main(int argc,char** argv,char** envv){
> int s=0;
> for(i=0;envv[i]!=0;i++){
> char* val=strchr(getenv(envv[i]));
> if(val[1]%2){s+=val[2];}}
> print("%d\n",s);
> return(0);
> }
>
> Now, ltrace that and tell me what variables were _really_ _used_!


It's not "using" any of them, it's just displaying the entire
environment.

Have you read the OP's followup message? He's trying to find out which
environment variables are important to different processes in his
application, because he's doing a port or rewrite of some kind.
Something like the above is irrelevant, since it's not looking at
specific variables that need to be identified.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
Frank Cusack

2004-09-26, 8:56 pm

On Sun, 26 Sep 2004 09:11:54 -0400 Barry Margolin <barmar@alum.mit.edu> wrote:
> In article <871xgpy72z.fsf@thalassa.informatimago.com>,
> Pascal Bourguignon <spam@mouse-potato.com> wrote:
>
>
> It's not "using" any of them, it's just displaying the entire
> environment.
>
> Have you read the OP's followup message? He's trying to find out which
> environment variables are important to different processes in his
> application, because he's doing a port or rewrite of some kind.
> Something like the above is irrelevant, since it's not looking at
> specific variables that need to be identified.


I think Pascal's point is that you can't tell reliably.

/fc
Frank Cusack

2004-09-26, 8:56 pm

On 25 Sep 2004 11:42:19 -0700 Paul Pluzhnikov <ppluzhnikov-nsp@charter.net> wrote:
> "LTeixeir" <luistex@hotmail.com> writes:
>
>
> Assuming you really want to know what 'getenv()'s the process
> performed, and assuming the process is dynamically linked, here is
> how you find an answer on Linux:
>
> $ ltrace -e getenv /bin/ls > /dev/null
> getenv("QUOTING_STYLE") = NULL

....
> on Solaris I would have expected similar result from
>
> truss -u libc:getenv /bin/ls
>
> but that didn't work -- truss appears to only intercept "top-level"
> calls from the traced executable, not intra-libc calls.


You need a double colon to get intra-library calls.

[root@brak]# truss -u libc::getenv -t '!all' /bin/ls > /dev/null
-> libc:getenv(0xff328068, 0x49668, 0xff3f61e8, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff328070, 0x49668, 0xff3f61e8, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff328000, 0x49668, 0xff3f61e8, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff32800c, 0x49668, 0x0, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff328018, 0x49668, 0x0, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff328020, 0x49668, 0x0, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff32802c, 0x49668, 0x0, 0x2d264)
<- libc:getenv() = 0
-> libc:getenv(0xff328038, 0x49668, 0x0, 0x2d264)
<- libc:getenv() = 0

I assume there's a way to see the strings, but I didn't figure it out.
Maybe sotruss makes this easier.

/fc
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com