Hi gijoe!!!
My solution would be: create your own *env()-functions.
Some background: when main() is called, it gets a pointer to all process environment variables defined at this point. Where is that pointer?
<URL url="https://techpubs.jurassic.nl/manuals/0650/developer/CLanguageRef/sgi_html/apa.html#IG3431040850">
Here:
int main(int argc, char *argv[], char *envp[])
Now we have a null-terminated array of pointers to strings (string in c = contiguos sequence of chars), stored in process memory and which you can manipulate, carefully.
The following pseudo code is just my approach to a possible solution, it's neither tested/verified nor optimized. In the end this is all about learning...
Code:
<i>
</i>
getenv(char *envvar):
{
/* pseudo code for gijoe77 - yes, you can */
char *retval;
char **ep = envp
char *s;
while (ep != NULL)
{
*ep now points to the next "envvar=value" string, for example "HOME=/usr/people/root"
s = *ep
Process that string:
1. Look for char '=' in s
1.1 If found, you now have two parts:
Part1: envvar (for example HOME)
Part2: value (for example /usr/people/root)
1.2 If not found, continue
2. Compare first part to requested envvar
2.1 If they match:
2.1.1 Return corresponding value (Part2)
value_length = strlen(Part2)
retval = malloc(value_length + 1) // + 1 for terminating null-byte
strncpy(retval, Part2, value_length)
retval[value_length] = 0; // terminate
return
2.2 If they don't match, continue
Continue to next envvar=value string:
ep++
}
}
setenv(char *envvar, char *newvalue)
{
/* pseudo code for gijoe77 - go, go, go */
int string_length;
int new_length;
char *newp;
Construct new string based on arguments:
new_length = strlen(envvar) + strlen("=") + strlen(newvalue);
newp = malloc(new_length + 1)
strncat(newp, envvar, strlen(envvar))
strncat(newp, "=", strlen("="))
strncat(newp, newvalue, strlen(newvalue))
newp[new_length] = 0;
Now, two cases here:
Case 1: the variable to be set already exists (modify existing envvar)
Case 2: it does NOT already exist (need to extend envp)
Case 1:
Loop through envp (as seen in getenv())
Lookup envvar
Modify existing value
Here you have to consider two cases again - oh boy, this never ends:
Case 1: the new value fits in allocated string (zero out value part and copy-in newvalue)
Case 2: it does not fit (new allocation necessary)
I'd recommend always assuming case 2, since it does work for case 1 as well:
envp[index_to_be_modified] = newp;
Case 2:
Need to extend envp to create room for new pointer to envvar=newvalue
Try one of two options:
Option 1: extend existing envp
Option 2: create new, larger envp, say envp2, copy envp to envp2 and add envvar=newvalue
NOTE: I have never implemented these functions myself and can't assure any of these options work.
Option 1:
Get length of envp:
envp_length = 0
while (envp[envp_length] != NULL) envp_length++;
Add one more pointer for envvar=newvalue:
envp_length++
Add one more for the terminating NULL-pointer:
envp_length++
Extend existing envp:
envp = realloc(envp_length * sizeof(char *))
Add envvar=newvalue
envp[envp_length - 1] = newp;
Terminate:
envp[envp_length] = 0;
Option 2:
Get length of envp:
envp_length = 0
while (envp[envp_length] != NULL) envp_length++;
Add one more pointer for envvar=newvalue:
envp_length++
Add one more for the terminating NULL-pointer:
envp_length++
Create new envp, named envp2:
envp2 = malloc(envp_length * sizeof(char *))
Copy old envp strings to new envp2 (except terminating NULL-pointer):
for (i = 0; i < (envp_length - 1); i++)
Get length of string:
string_length = strlen(envp[i])
Alloc space for string:
envp2[i] = malloc(string_length + 1)
Copy string:
strncpy(envp2[i], envp[i], string_length)
Terminate:
envp2[i][string_length] = 0
Add envvar=newvalue
envp2[envp_length - 1] = newp;
Terminate:
envp2[envp_length] = 0;
Change old envp:
envp = envp2
NOTE: It *may* require a "deeper" modification of the process memory.
Specifically, the address of the old envp needs to be patched throughout all process memory, wherever it is used. A more complicated
scenario can arise if kernel structures for that process (process block?) need to be patched too. hmmmm...
}
unsetenv(char *envvar)
{
/* pseudo code for gijoe77 - there's no idiocy, never. There's just evolution */
For the sake of simplicity, I'll just quickly note what needs to be done, since above descriptions already include all operations needed:
Step 1: Loop through envp, looking for envvar to be deleted
Step 2: If found, you get two parts of the envp array:
Part1: contains all strings ("envvar=value") before the matching string
Part2: contains all strings after the matching string
Create a new envp, envp2, and copy both parts, consecutively (that is, leaving out the envvar=value to be deleted)
Step 3: realloc envp to contain envp2 and copy back strings from envp2 to envp
}
A nice add-on to this solution would be an implementation of unsetenv(char *envvar, char *value), such that:
1. if both arguments are specified, delete only matching strings
2. if envvar and no value is specified, works just like normal unsetenv(char *envvar)
3. if no envvar and value is specified, delete all strings that match the corresponding value part
Anyway, hope this helps.
Tru