Environment Variables

Table of contents:

Each process also has access to a list of environment variables. The environment variables, like the command-line values, are stored as a ragged array of characters . Environment variables, which are most commonly set at the shell level, [11] are passed to a process by its parent when the process begins execution. Environment variables can be accessed in a program by using an external pointer called environ , which is defined as

[11] If at the command-line level you enter the shell command env (or printenv ), the system should display a list of environment variables and their contents.

extern char **environ;

In most older (and in some current) versions of Linux, the environment variables could also be accessed by using a third argument in the function main called envp . When used, the envp argument to main is defined as

main(int argc,char *argv[],char **envp /*

OR

as *envp[]*/)

As environ and envp can both be used to accomplish the same thing, and current standards discourage the use of envp , only the use of the external pointer environ will be discussed in detail.

The contents of the environment variables can be obtained in a manner similar to the command-line arguments (Program 2.7).

A partial listing of the output of this program run on a local system is show in Figure 2.20.

Program 2.7 Displaying environment variables.

File : p2.7.cxx
 /*
 Using the environ pointer to display the command line
 */
 #include 
 + using namespace std;
 extern char **environ;
 int
 main( ){
 for ( ; *environ ; )
 10 cout << *environ++ << endl;
 return 0;
 }

Figure 2.20 Output of Program 2.7.

linux$ p2.7
PWD=/home/faculty/gray/revision/02
VENDOR=intel
REMOTEHOST=zeus.cs.hartford.edu
HOSTNAME=kahuna
LOGNAME=gray
SHLVL=2
GROUP=faculty
USER=gray
PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:.
. . .

The output shows that all environment variables are stored as strings in the format name =value. Many of the environment variables shown here are common to all Linux systems (e.g., USER , PATH , etc.), while others are system-dependent (e.g., VENDOR ). Note that by convention environment variables are normally spelled in uppercase. For the more curious , the manual page on environ ( $ man 5 environ ) furnishes a detailed description of the commonly found environment variables and their uses.

The two library calls shown in Tables 2.23 and 2.24 can be used to manipulate environment variables.

The first library call, getenv , searches the environment list for the first occurrence of a specified variable. The character string argument passed to getenv should be of the format name , where name is the name of the environment variable to find without an appended =. Note that name is case-sensitive (environment variables are often in uppercase). If getenv is successful, it returns a pointer to the string assigned to the environment variable specified; otherwise , it returns a NULL pointer. If getenv fails, it returns a -1 and sets errno to ENOMEM (12"Cannot allocate memory"). In Program 2.8 the output (shown in Figure 2.21) indicates that in this case the environment variable TERM has been found and that its current value is vt220 . Notice that only the string to the right of the equals was returned by getenv .

Table 2.23. Summary of the getenv Library Function.

Include File(s)

Manual Section

3

Summary

char *getenv( const char *name );

Return

Success

Failure

Sets errno

Pointer to the value in the environment

NULL

 

Table 2.24. Summary of the putenv Library Function.

Include File(s)

Manual Section

3

Summary

Int putenv( const char *name );

Return

Success

Failure

Sets errno

-1

Yes

Program 2.8 Using getenv .

File : p2.8.cxx
 /*
 Displaying the contents of the TERM variable
 */
 #include 
 + #include 
 using namespace std;
 int
 main( ){
 char *c_ptr;
 10 c_ptr = getenv("TERM");
 cout << "The variable TERM is "
 << (c_ptr==NULL ? "NOT found" : c_ptr)
 << endl;
 return 0;
 + }

Figure 2.21 Checking the output of Program 2.8.

linux$ echo $TERM
vt220
linux$ p2.8
The variable TERM is vt220

Modifying or adding environment variable information, which is usually accomplished with the library function putenv , is a little trickier. The environment variables, along with the command-line values, are stored by the system in the area just beyond the stack segment for the process (see Chapter 1, Section 1.8). This area is accessible by the process and can be modified by the process, but it cannot be expanded. When environment variables are added or an existing environment variable is modified so it is larger (storage-wise) than its initial setting, the system will move the environment variable information from its stack location to the text segment of the process (the putenv function uses malloc to allocate additional space). To further complicate the issue in this situation, envp (if supported) will still point to the table on the stack when referencing the original environment variables, but will point to the text segment for the new environment variable. This is yet another reason to stay clear of envp !

One last caveat appears in the putenv manual page. The argument for putenv should not be an automatic variable (such as a variable local to a function), as these variables become undefined once the function in question is exited.

Program 2.9 demonstrates the putenv function.

Program 2.9 Using putenv .

File : p2.9.cxx
 /*
 Using putenv to modify the environment as seen by parent child
 */
 #define _GNU_SOURCE
 + #include 
 #include 
 #include 
 #include 
 using namespace std;
 10 extern char **environ;
 int show_env( char ** );
 int
 main( ){
 int numb;
 + cout << "Parent before any additions **********" << endl;
 show_env( environ );
 putenv("PARENT_ED=parent");
 cout << "Parent after one addition **********" << endl;
 show_env( environ );
 20 if ( fork( ) == 0 ){ // In the CHILD now
 cout << "Child before any additions *********" << endl;
 show_env( environ );
 putenv("CHILD_ED=child");
 cout << "Child after one addition *********" << endl;
 + show_env( environ );
 return 0;
 } // In the PARENT now
 sleep( 10 ); // Make sure child is done
 cout << "Parent after child is done **********" << endl;
 30 numb = show_env( environ );
 cout << "... and at address [" << hex << environ+numb
 << "] is ... "
 << (*(environ+numb) == NULL ? "Nothing!" : *(environ+numb))
 << endl;
 + return 0;
 }
 /*
 Display the contents of the passed list ... return number found
 */
 40 int show_env( char **cp ){
 int i;
 for (i=0; *cp; ++cp, ++i)
 cout << "[" << hex << cp << "] " << *cp << endl;
 return i;
 + }

The abridged output (some of the intervening lines of output were removed for clarity) of this program, when run on a local system, is explained in Figure 2.22.

Figure 2.22 Output of Program 2.9.

linux$ p2.9
Parent before any additions **********
[0xbffffc9c] TERM=vt220

<-- 1

. . .
[0xbffffd08] CA_DB=
Parent after one addition **********
[0x8049ec8] TERM=vt220
. . .
[0x8049f34] CA_DB=
[0x8049f38] PARENT_ED=parent

<-- 2

Child before any additions **********
[0x8049ec8] TERM=vt220

<-- 3

. . .
[0x8049f34] CA_DB=
[0x8049f38] PARENT_ED=parent

<-- 3

Child after one addition **********
[0x8049ec8] TERM=vt220
. . .
[0x8049f34] CA_DB=
[0x8049f38] PARENT_ED=parent
[0x8049f3c] CHILD_ED=child

<-- 4

Parent after child is done **********
[0x8049ec8] TERM=vt220
 . . .
[0x8049f34] CA_DB=
[0x8049f38] PARENT_ED=parent

<-- 5

... and at address [0x8049f3c] is ... Nothing!

(1) The environment variables start their life in storage just beyond the stack segment (notice the addresses).

(2) This environment variable is added by the parent process. All variables have been moved to the text segment.

(3) Notice the addresses in the child are the same.

(4) This environment variable is added by the child process.

(5) When the child process is gone, so is the environment variable it added.

There are several important concepts that can be gained by examining this program and its output. First, it is clear that the addresses associated with the environment variables are changed (from the stack segment to the text segment) when a new environment variable is added. Second, the child process inherits a copy of the environment variables from its parent. Third, as each process has its own address space, it is not possible to pass information back to a parent process from a child process. [12] Fourth, when adding an environment variable, the name= value format should be adhered to. While it is not checked in the example program, putenv will return a 0 if it is successful and a -1 if it fails to accomplish its mission.

[12] I am sure that many human children would say this is also true for their parent/child relationshipeverything ( especially tasks ) seems to flow one way.

EXERCISE

Sam figures he has a way for a child process to communicate with its parent via the environment. His solution is to have the child process modify (without changing the storage size and without using putenv ) an environment variable that was initially found in the parent. He wrote the following program to test his idea. Will his program work as he thoughtwhy, or why not?

[View full width]


 

[View full width]

File : sam.cxx /* Sam's environment program */ #define _GNU_SOURCE + #include #include #include #include using namespace std; 10 int main( ){ int numb; char *p; putenv("DEMO=abcdefghijklmnop"); + p = getenv("DEMO"); cout << "1. Parent environment has " << p << endl; if ( fork( ) == 0 ){ // In the CHILD now *(p + 9) = 'X'; // Change ref graphics/ccc.gif location 20 p = getenv("DEMO"); cout << "2. Child environment has " << p << endl; cout << "3. Exiting child." << endl; return 0; } // In the PARENT graphics/ccc.gif now + sleep( 10 ); // Make sure child graphics/ccc.gif is done cout << "4. Back in parent." << endl; p = getenv("DEMO"); cout << "5. Parent environment has " << p << endl; return 0; 30 }

Programs and Processes

Processing Environment

Using Processes

Primitive Communications

Pipes

Message Queues

Semaphores

Shared Memory

Remote Procedure Calls

Sockets

Threads

Appendix A. Using Linux Manual Pages

Appendix B. UNIX Error Messages

Appendix C. RPC Syntax Diagrams

Appendix D. Profiling Programs



Interprocess Communication in Linux
Interprocess Communications in Linux: The Nooks and Crannies
ISBN: 0130460427
EAN: 2147483647
Year: 2001
Pages: 136

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net