I am making my own shell in C and I have been asked to modify the enviroment variable with the function putenv(char*) and i have implemented this code:
char *string = NULL;
if ((string = (char *)malloc(strlen(tokens[2]) strlen(tokens[3]) 2)) == NULL){
perror("Error malloc");
return 0;
}
strcpy(string, tokens[2]);
strcat(string, "=");
strcat(string, tokens[3]);
putenv(string);
tokens[2] and tokens[3] are the name of the variable and the new value I want to give it, respectively. My problem is that this works only if i ask the enviroment to be listed from the extern char **environ, however, when I list it from the third argument of main (char *envp[]) the cange doesnt seem to be working.
Does anyone know how can I tell the putenv() function to change it in both?
The 2 ways of listing enviroment I use are:
void ShowEnviroment (char **enviroment, char * name_enviroment)
{
int i=0;
while (enviroment[i]!=NULL) {
printf ("%p->%s[%d]=(%p) %s\n", &enviroment[i],
name_enviroment, i, enviroment[i], enviroment[i]);
i ;
}
}
The paramether enviroment
can be environ
(defined as extern char **environ
) (it works fine) or &envp
(third argument of main) (is the one that doesnt seem to show the change)
CodePudding user response:
Your program is working fine, and as intended. envp
is a copy of environ
at program start, and may be, unlike environ
, never updated afterwards.
To run commands, shells (such as the one you are writing) use a combination of fork()
execv()
-- and the manual on execv
notes that
For those forms not containing an envp pointer (execl(), execv(), execlp(), and execvp()), the environment for the new process image shall be taken from the external variable environ in the calling process.
... making no reference at all to relying on the envp
that you received, as opposed to one that you may manufacture to pass whichever environment variables you choose to your child processes when using exec*
variants that do take modified environment variables as arguments.
As a side-note, using setenv()
has two advantages over putenv
, and I would therefore recommend it:
- whatever you pass to
putenv
must persist in time; whatever you pass tosetenv
gets copied, so you need not manage its memory. - Therefore,
setenv(char *key, char *value, int replace)
means less responsibility for you (and no need to malloc, strcat, and so on).
Both will modify environ
for you. Note that you should not write environ
directly (but reading it is fine, and needed because there is no lsenv
function to list available environment variables); note this warning:
Any application that directly modifies the pointers to which the environ variable points has undefined behavior