7

I wrote a C program in Linux to set the values of environment variables using setenv, but after execution, when I run set or export, the environment variable itself seems to be unset. Why?

Here is the code snippet:

int main()
{
  char *mallocPtr, *callocPtr, *reallocPtr, *memalignPtr, *vallocPtr;
  struct sigaction sa;

  sa.sa_handler=SIGSEGV_handler;
  sigaction(SIGSEGV, &sa, NULL);

  if(setenv("ENV1", "3", 1) == 0)
         printf("ENV1 set to 3\n");
  else
         fprintf(stderr, "setenv failed on ENV1");
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
RajSanpui
  • 11,556
  • 32
  • 79
  • 146

3 Answers3

14

The environment variables are set within the context of your program.

When your program exits, you're back in the context from where your program was started.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Didier Trosset
  • 36,376
  • 13
  • 83
  • 122
  • 3
    "[..]each process has a separate copy of the environment. As a result, you can't change the value of an environment variable in another process, such as the shell." from [here](http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC8). – user786653 Aug 08 '11 at 10:56
  • @Didier: But if the option "1" last argument of setenv is set, then i am expecting it to overwrite the already existing ones right? But it is not overwriting. – RajSanpui Aug 08 '11 at 10:56
  • 1
    The man page for `getenv(), setenv()`, etc. says: `These functions set, unset and fetch environment variables from the host environment list.` – Rudy Velthuis Aug 08 '11 at 11:00
  • @Rudy: That's it..so it means it should set in my shell (or at least overwrite), right? – RajSanpui Aug 08 '11 at 11:01
  • @kingsmasher1: you need to read the man page more carefully: `The setenv() function inserts or resets the environment variable name in the current environment list. If the variable name does not exist in the list, it is inserted with the given value. If the variable does exist, the argument overwrite is tested; if overwrite is zero, the variable is not reset, otherwise it is reset to the given value.` -- the overwrite parameter just controls whether you overwrite your existing environment variable setting - it has nothing to do with exporting the environment variable. – Paul R Aug 08 '11 at 11:02
  • It overwrites the existing ones in the current process - try calling getenv in your program to see the change - but the current process is not the shell – mmmmmm Aug 08 '11 at 11:02
  • @Paul R: `it has nothing to do with exporting the environment variable` so it means since it is not exported, it won't be seen, also if i set reset to "1" then the program does not use the existing value, but the value specified in setenv, right? – RajSanpui Aug 08 '11 at 11:07
  • I can see that getenv done within same program gets the value set using setenv, but another shared library cannot. It extracts the one exported in the shell. – RajSanpui Aug 08 '11 at 11:12
  • @kingsmasher1: that is what one could read into it, but that is not what happens. – Rudy Velthuis Aug 08 '11 at 11:21
  • i downvoted this answer. there are no details at all. the answer by zwol is much better. – Eugen May 08 '18 at 19:44
7

The C library treats environment variables as global settings you can read with getenv and adjust with setenv/putenv, and that inherit across calls to the exec family, but that is a convenient fiction. As far as the kernel is concerned, the environment variables are a second set of arguments to main. This becomes clear if you look at the actual system call, execve, underlying the exec family. This is its C prototype:

int execve(const char *filename, char *const argv[], char *const envp[]);
                                                     ^^^^^^^^^^^^^^^^^^

See that third argument? That's the only way for process A to set process B's environment variables.1 Therefore, the only time process A can set process B's environment variables is when process A starts process B, via fork and execve.

Your program is started by the shell, so the shell got to set its copy of the environment variables, but there is no way for it to push a change back to the shell -- just as there is no way for a C function to change the values of its arguments in its caller.

1 Do not bring up ptrace.

zwol
  • 135,547
  • 38
  • 252
  • 361
1

Actually every process has its own envp char array. The main function has the following signature:

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

Usually, the envp of the parent inherit to the child, down the parent-child hierarchy. It is by no means communicated upwards in the parent-child hierarchy.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • `main` with three arguments is definitely non-standard C. Some implementation may support it, but you shouldn't rely on it. – Yu Hao Nov 25 '13 at 13:41