Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   Editing Linux Environment Variables in C (http://www.go4expert.com/articles/editing-linux-environment-variables-c-t27112/)

poornaMoksha 8Nov2011 17:16

Editing Linux Environment Variables in C
 
Environment variables can be thought of as a name value pair that affect the behavior of the processes running on an operating system.

For example, to know the value of environmental variable PATH in my system, I do :

Code:

-laptop ~ $ echo $PATH
 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Now, why do we need environment variables?

Suppose you created a program that creates some temporary files. The program should create temporary files in some standard path of the system which is used for storing temporary files. Now, your program is not restricted to run on one single computer system. It can run on multiple systems. It is very well possible that the standard path for temporary files is different for different systems. So what would your program do to create temporary files at the standard path for the system its running on??

Well, in this situation environment variables come to rescue. The program can access the value of corresponding environment variable and creates the temporary files at that path.

How to access env variables



Inside the code, the environment variables can be accessed by :

1) Accepting a third argument 'environ' to the main function.
Code:

int main(int argc, char *argv[], char **environ)
                      OR
 int main(int argc, char *argv[], char *envp[])

This way of declaring 'main()' has been deprecated by ISO C.

2) Accessing a global variable environ.

This way is preferred over the way described in point 1 above.

Lets understand the above mentioned ways through an example :

1) The code below uses the older declaration of main() function to access environment variables :

Code:

#include<stdio.h>
 
 int main(int argc, char *argv[], char *envp[])
 {
    int i = 0;
 
    while(envp[i] != NULL)
    {
        printf("\n [%s] \n",envp[i]);
        i++;
    }
 
    printf("\n Done...exiting\n");
 
    return 0;
 }

When the above code is run, I get the following output on my machine :

Code:

  ~/practice $ ./environ 
 
  [ORBIT_SOCKETDIR=/tmp/orbit-himanshu] 
 
  [SSH_AGENT_PID=1695] 
 
  [TERM=xterm] 
 
  [SHELL=/bin/bash] 
 
  [XDG_SESSION_COOKIE=b8b52be9a0280f3c8b48fcf04d7ac5a3-1320743817.969365-1067214140] 
 
  [WINDOWID=20971760] 
 
  [GNOME_KEYRING_CONTROL=/tmp/keyring-aob7hd] 
 
  [GTK_MODULES=canberra-gtk-module] 
 
  [USER=himanshu] 
 
  [SSH_AUTH_SOCK=/tmp/keyring-aob7hd/ssh] 
 
  [DEFAULTS_PATH=/usr/share/gconf/gnome.default.path] 
 
  [SESSION_MANAGER=local/himanshu-laptop:@/tmp/.ICE-unix/1661,unix/himanshu-laptop:/tmp/.ICE-unix/1661] 
 
  [USERNAME=himanshu] 
 
  [XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg] 
 
  [DESKTOP_SESSION=gnome] 
 
  [PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games] 
 
  [PWD=/home/himanshu/practice] 
 
  [GDM_KEYBOARD_LAYOUT=us] 
 
  [LANG=en_IN] 
 
  [GNOME_KEYRING_PID=1643] 
 
  [MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path] 
 
  [GDM_LANG=en_IN] 
 
  [GDMSESSION=gnome] 
 
  [SPEECHD_PORT=7560] 
 
  [SHLVL=1] 
 
  [HOME=/home/himanshu] 
 
  [GNOME_DESKTOP_SESSION_ID=this-is-deprecated] 
 
  [LOGNAME=himanshu] 
 
  [XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/] 
 
  [DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-tuOHkHOhpc,guid=5a9c7ce1bf45d031130517354eb8f38a] 
 
  [DISPLAY=:0.0] 
 
  [XAUTHORITY=/var/run/gdm/auth-for-himanshu-UPXg4a/database] 
 
  [COLORTERM=gnome-terminal] 
 
  [_=./environ] 
 
  [OLDPWD=/home/himanshu] 
 
  Done...exiting

So we can see that all the environment variables for my system are displayed.

2) The code below uses the global variable 'environ' :

Code:

#include<stdio.h>
 
 extern char **environ; // Need to declare it at least
 int main(int argc, char *argv[])
 {
    int i = 0;
 
    while(environ[i] != NULL)
    {
        printf("\n [%s] \n",environ[i]);
        i++;
    }
 
    printf("\n Done...exiting\n");
 
    return 0;
 }

Note that we need to declare the variable 'environ' as extern so that code gets compiled without any errors.
Now, when I run the code, I get :

Code:

  ~/practice $ ./environ 
 
  [ORBIT_SOCKETDIR=/tmp/orbit-himanshu] 
 
  [SSH_AGENT_PID=1695] 
 
  [TERM=xterm] 
 
  [SHELL=/bin/bash] 
 
  [XDG_SESSION_COOKIE=b8b52be9a0280f3c8b48fcf04d7ac5a3-1320743817.969365-1067214140] 
 
  [WINDOWID=20971760] 
 
  [GNOME_KEYRING_CONTROL=/tmp/keyring-aob7hd] 
 
  [GTK_MODULES=canberra-gtk-module] 
 
  [USER=himanshu] 
 
  [SSH_AUTH_SOCK=/tmp/keyring-aob7hd/ssh] 
 
  [DEFAULTS_PATH=/usr/share/gconf/gnome.default.path] 
 
  [SESSION_MANAGER=local/himanshu-laptop:@/tmp/.ICE-unix/1661,unix/himanshu-laptop:/tmp/.ICE-unix/1661] 
 
  [USERNAME=himanshu] 
 
  [XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg] 
 
  [DESKTOP_SESSION=gnome] 
 
  [PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games] 
 
  [PWD=/home/himanshu/practice] 
 
  [GDM_KEYBOARD_LAYOUT=us] 
 
  [LANG=en_IN] 
 
  [GNOME_KEYRING_PID=1643] 
 
  [MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path] 
 
  [GDM_LANG=en_IN] 
 
  [GDMSESSION=gnome] 
 
  [SPEECHD_PORT=7560] 
 
  [SHLVL=1] 
 
  [HOME=/home/himanshu] 
 
  [GNOME_DESKTOP_SESSION_ID=this-is-deprecated] 
 
  [LOGNAME=himanshu] 
 
  [XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/] 
 
  [DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-tuOHkHOhpc,guid=5a9c7ce1bf45d031130517354eb8f38a] 
 
  [DISPLAY=:0.0] 
 
  [XAUTHORITY=/var/run/gdm/auth-for-himanshu-UPXg4a/database] 
 
  [COLORTERM=gnome-terminal] 
 
  [_=./environ] 
 
  [OLDPWD=/home/himanshu] 
 
  Done...exiting

How to fetch a particular env variable?



What if in the code, you want to get value of a particular environment variable ?

Well, 'getenv()' function is there to help you. The signature of the function is :

Code:

char *getenv(const char *name);
From the man page of this function :
DESCRIPTION
The getenv() function searches the environment list to find the environment variable name, and returns a pointer to the corresponding value
string.

RETURN VALUE
The getenv() function returns a pointer to the value in the environment, or NULL if there is no match.
Suppose we want to fetch the value of environment variable PATH using this function.

Lets see how it works :

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(int argc, char *argv[])
 {
 
    char *val = getenv("PATH");
    printf("\nValue of environment variable PATH is [%s]\n",val);
 
    return 0;
 }

When the above code is executed, we see :

Code:

$ ./environ 
 
 Value of environment variable PATH is [/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games]

So we see that through the function 'getenv()' we successfully fetched the value of environment variable PATH. Similarly we can get the value of any environment variable we desire.

How to set value to a particular env variable?



What if from within the code you want to create a new environment variable or change value of an existing environment variable?

Well, this can be done achieved using the 'putenv' or 'setenv' functions.
From the man page of putenv function :
NAME
putenv - change or add an environment variable

SYNOPSIS
#include <stdlib.h>

int putenv(char *string);

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

putenv(): _SVID_SOURCE || _XOPEN_SOURCE

DESCRIPTION
The putenv() function adds or changes the value of environment variables. The argument string is of the form name=value. If name does not
already exist in the environment, then string is added to the environment. If name does exist, then the value of name in the environment is
changed to value. The string pointed to by string becomes part of the environment, so altering the string changes the environment.

RETURN VALUE
The putenv() function returns zero on success, or non-zero if an error occurs.
From the man page of setenv function :
NAME
setenv - change or add an environment variable

SYNOPSIS
#include <stdlib.h>

int setenv(const char *name, const char *value, int overwrite);

int unsetenv(const char *name);

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

setenv(), unsetenv(): _BSD_SOURCE || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600

DESCRIPTION
The setenv() function adds the variable name to the environment with the value value, if name does not already exist. If name does exist in the
environment, then its value is changed to value if overwrite is non-zero; if overwrite is zero, then the value of name is not changed. This func-
tion makes copies of the strings pointed to by name and value (by contrast with putenv(3)).


RETURN VALUE
The setenv() function returns zero on success, or -1 on error, with errno set to indicate the cause of the error.
Lets take a couple of examples as a proof of concept to the above explanations.

Here is the code which tries to create an environment variable MYENVAR with value /home/himanshu/

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(int argc, char *argv[])
 {
 
    if(putenv("MYENVAR=/home/himanshu"))
    {
        printf("\n putenv() failed\n");
        return 1;
    }
 
    printf("\n Successfully Added a new environment variable\n");
 
    char *val = getenv("MYENVAR");
    printf("\nValue of environment variable MYENVAR is [%s]\n",val);
 
    return 0;
 }

When the above code is run, the output we get is :

Code:

  ~/practice $ ./environ 
 
  Successfully Added a new environment variable
 
 Value of environment variable MYENVAR is [/home/himanshu]

So we see that through the function putenv() we successfully added an environment variable to the environment.


Next up lets try to change the value of existing variable MYENVAR.
Here is the code to achieve this :

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(int argc, char *argv[])
 {
 
    char *val = getenv("MYENVAR");
    if(val == NULL)
    {
        if(putenv("MYENVAR=/home/himanshu"))
        {
            printf("\n putenv() failed\n");
            return 1;
        }
        val = getenv("MYENVAR");
    }
    printf("\nCurrent value of environment variable MYENVAR is [%s]\n",val);
 
    if(putenv("MYENVAR=/home/himanshu/abc"))
    {
        printf("\n putenv() failed\n");
        return 1;
    }
 
    printf("\n Successfully Added a new value to existing environment variable MYENVAR\n");
 
    val = getenv("MYENVAR");
    printf("\nNew value of environment variable MYENVAR is [%s]\n",val);
 
 
    return 0;
 }

In the above code, we first check whether there already exists an environment variable named MYENVAR. If not then we create one with a value and then we change its value. Now, lets see what happens when we run the above code :

Code:

~/practice $ ./environ 
 
 Current value of environment variable MYENVAR is [/home/himanshu]
 
  Successfully Added a new value to existing environment variable MYENVAR
 
 New value of environment variable MYENVAR is [/home/himanshu/abc]

The output shows that through putenv() function the value of the environment variable is changed easily.

Now, we can also add/change an environment variable with function setenv(). Lets see how :

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(int argc, char *argv[])
 {
 
    char *val = getenv("MYENVAR");
    if(val == NULL)
    {
        if(setenv("MYENVAR","/home/himanshu",0))
        {
            printf("\n setenv() failed\n");
            return 1;
        }
        val = getenv("MYENVAR");
    }
    printf("\nCurrent value of environment variable MYENVAR is [%s]\n",val);
 
    if(setenv("MYENVAR","/home/himanshu/abc",1))
    {
        printf("\n setenv() failed\n");
        return 1;
    }
 
    printf("\n Successfuly Added a new value to existing environment variable MYENVAR\n");
 
    val = getenv("MYENVAR");
    printf("\nNew value of environment variable MYENVAR is [%s]\n",val);
 
 
    return 0;
 }

In the above code, we have used the function setenv() and set the value of third argument as '1' when we wanted to update its value.
Lets see the output :

Code:

~/practice $ ./environ 
 
 Current value of environment variable MYENVAR is [/home/himanshu]
 
  Successfully Added a new value to existing environment variable MYENVAR
 
 New value of environment variable MYENVAR is [/home/himanshu/abc]

In the above output we see that through setenv() function too we are able to add/modify an environment variable.


A point worth noting



Please note that if you set/change an environment variable using the above shown techniques. The persistence of that particular change is temporary. If a new environment variable is added through code, its visibility remains up till the code is running. As soon as the process terminates, the environment variable is cleared.

To make permanent changes put the new environment string at the end of the .profile, or .bash_rc or .bash_profile file, depending on your distribution.

Conclusion



To conclude, this article demonstrates the use of environment variables, how to access them through code. Also, how we can fetch the value or change the value of existing environment variable through C functions.

Stay tuned for more...


All times are GMT +5.5. The time now is 18:57.