3

I want to change the value of PATH variable inside the C program and then see the changed value in the shell using which I run this program.

Doing something like this,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main () {

    char *path = getenv ("PATH");
    printf ("%s\n\n", path);
    setenv ("PATH", strcat (path, ":~/myNewPath/"), 1);
    printf ("%s\n\n", path);

    int pid = fork ();
    if (pid == -1)
        abort ();
    if (pid == 0) {

    } else {
        // use execlp? how? source? any hints?
    }

    return 0;
}

If I use source command in the exec* system call. What will be the syntax to update this PATH variable in the shell backwards?

Fahad Siddiqui
  • 1,829
  • 1
  • 19
  • 41
  • Note: `setenv ("PATH", strcat (path, ":~/myNewPath/"), 1);` will probably segfault. – wildplasser Apr 20 '14 at 13:50
  • @wildplasser no it won't. why? – Fahad Siddiqui Apr 20 '14 at 14:02
  • 1
    Because you cannot safely append characters to the string pointed at by the pointervalue returned by getenv(). If your stcat() doesn't segfault, it's purely by coincident/luck. Also: getenv() can return NULL. – wildplasser Apr 20 '14 at 14:08
  • yeah, but it wasn't the actual question. well thanks for the suggestion. – Fahad Siddiqui Apr 20 '14 at 14:09
  • 2
    wildplasser is quite right: it probably *won't* segfault because the string is in a larger region of writable memory (as described in the ABI document I linked to) but it probably *will* overwrite adjacent data (most likely, other environment strings). – zwol Apr 20 '14 at 14:24
  • 1
    And there is an additional problem: the tilde will not be expanded, since there is no {ksh,bash} shell involved. (the linux man page is rather vague about this) – wildplasser Apr 20 '14 at 16:28

1 Answers1

5

This is impossible. There is no way for a subprocess to change its parent's environment variables.

To understand why it is impossible, look at the signature of execve

int execve(const char *program, char *const *argv, char *const *envp);

which is paired with the true signature of main on Unix systems

int main(int argc, char **argv, char **envp);

and perhaps you begin to understand that as far as the kernel is concerned, the environment variables are a second set of command line arguments. That they appear to be independently accessible via getenv and setenv etc, and appear to inherit from parent to child, is an illusion maintained by the C library.

For more detail on how this works, study the x86-64 ELF ABI specification, section 3.4.1 "Initial Stack and Register State" paying particular attention to figure 3.9 which shows the layout of the data copied by execve onto the newly created stack. (The document linked is specific to one CPU architecture, but the way this works is generally consistent across modern Unixes; fine details will of course vary from CPU to CPU and OS to OS.)

zwol
  • 135,547
  • 38
  • 252
  • 361