0

I was trying to set the environment of child process similar to the parent process and I need to fill the array called envp with string as follows:

char *envp = malloc(sizeof(args) / sizeof(char *));
strcpy(envp[0], strcat("HOME=", getenv("HOME")));
envp[1] = strcat("PATH=", getenv("PATH"));
envp[2] = strcat("TZ=", getenv("TZ"));
envp[3] = strcat("USER=", getenv("USER"));
envp[4] = strcat("LOGNAME=", getenv("LOGNAME"));
envp[5] = 0;

Inside if(fork() ==0)

setenv("parent", cwd, 1);
if((execve(args[0], &args[0], envp)) < 0 ){
            perror(*args);
            exit(EXIT_FAILURE);
}

I'm doing this because I don't know the values of these environment variables so I want to copy the parent variables in order to use them in execve() that will replace the child process! I'm using execve() instead of the execvp() because I want to handle searching the cwd before executing the command and search the directories of the shell path name of the cwd is not found.

So my question is: How to set the values of the array in a correct way? Plus, am I misunderstanding any concept?

I looked at many posts here, but it's obvious that I'm lost! Thanks in advance,

sareem
  • 429
  • 1
  • 8
  • 23
  • `char *envp` is wrong. You need an **array** of character pointers. execve() also wants an array of char* pointers as its 3rd argument. `envp[1] = strcat(` is completerly wrong. envp[1] is a character. One character, not a pointer. `strcat()` works different from how you think it works. (and the first argument must point to a writable array of characters, not a string literal.) – wildplasser Mar 26 '16 at 17:30

2 Answers2

0

You are not allocating memory for the strings that envp [x]is pointing to. Instead you are trying to strcat or strcpy to constant or non-allocated strings which is a no-no (your compiler has most probably warned you)

The general concept is

  1. You need to allocate memory for the array of pointers to environment strings (you did that).
  2. You also need to allocate memory for each of the strings those pointers point at (you didn't do that). Note that memory goes into the ownership of the process environment in most OSs, so you cannot use local variables and you may not free this memory.
  3. You need to save the pointers retrieved from (2) into the array positions you allocated at (1) (You did that)

Your code should look similar to (example for "HOME" only, length of envbuff might need to be adjusted/checked):

char envBuff [100];

strcpy (envBuff, "HOME=");
strcat (envBuff, getenv ("HOME));
envp [0] = strdup (envBuff);

strdupactually allocates the memory it uses, strcator a simple assignment as you do for envp[0] don't - strcat assumes there is enough room for both the original and the appended part and the memory is writable, which is both not true in your case.

tofro
  • 5,640
  • 14
  • 31
  • using this way show me this warning: "assignment makes integer from pointer without a cast [enabled by default]", I tired following this post (while I think this is not correct way), but still getting the same warning! any hints to solve this issue? http://stackoverflow.com/questions/21858412/c-pointers-and-arrays-warning-assignment-makes-pointer-from-integer-without-a – sareem Mar 26 '16 at 16:04
  • this line: envp [0] = strdup (envBuff); – sareem Mar 26 '16 at 16:33
  • @meramees Your `malloc` should allocate an array of `char**` instead of an array of `char*`. `char **envp = malloc...` – tofro Mar 26 '16 at 17:33
0
  • strcat() is a terrible function
  • separate strdup()s for each "Name=value" pair could also be an option.
  • having all the strings in one block of memory is nicer
  • snprintf() will never write beyond the allowed size; instead it gives you the size that you'll need
  • getenv() can return NULL, this MUST be handled

Note: I omitted the checks for realloc() returning NULL, you should add these.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define COUNTOF(a) (sizeof a / sizeof a[0])
char * names[] = {"HOME", "PATH", "TZ", "USER", "LOGNAME", NULL};

int main(void)
{
char *all=NULL;
char *array[COUNTOF(names) ];
size_t size, used, idx, envc, len;

for (idx=envc=size=used= 0; names[idx] ; idx++ ) {
        char *cp;
        cp = getenv(names[idx] );
        if (!cp) {
                fprintf(stderr, "%s not found\n", names[idx] );
                continue;
                }
        fprintf(stderr, "%s found: \"%s\"\n", names[idx], cp );
        while(1) {
                len = snprintf(all+used, size-used, "%s=%s", names[idx], cp);
                        /* enough space for the "NAME=val\0" pair */
                if (len+1 < size-used) break;
                fprintf(stderr, "Len=%zu; realloc %zu += %zu\n" , len, size, 2*len+1 );
                all = realloc(all, size += 2*len+1);
                }
        array[envc++] = all+used; used += len+1;
        }

fprintf(stderr, "Final realloc %zu -->> %zu\n" , size, used+1 );
all = realloc(all, used+1);
array[envc] = NULL;

for (idx=0; idx < envc; idx++) {
        printf("[%zu] -> %s\n", idx, array[idx] );
        }

return 0;
}

BTW: if your OS/environment allows it you can define main() as

int main(int argc, char **argv, char **envp) { ... }

, and use the existing env pointer of the parent process.

wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • thanks for your detailed answer. When I try following this code bit by bit, and then pass the array as third argument to execve() I got this exception which I don't no how to handle ! myshell_3.c:390:7: warning: passing argument 3 of ‘execve’ from incompatible pointer type [enabled by default] if((execve(args[0], &args[0], envp)) < 0 ){ ^ In file included from myshell_3.c:2:0: /usr/include/unistd.h:551:12: note: expected ‘char * const*’ but argument is of type ‘char *’ extern int execve (const char *__path, char *const __argv[], – sareem Mar 26 '16 at 17:07
  • That is the silly const. (execve() is not supposed to return anyway) Cast it away, or better: alter the argument type in main(...) Your code also misses an `*` somewhere, envp is supposed to be a pointer to pointer. – wildplasser Mar 26 '16 at 17:17
  • I'm a beginner and I'm lost! can you point out the lines that I can modify and how to modify them? – sareem Mar 26 '16 at 17:25