@@ -267,6 +267,55 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
267267 }
268268 }
269269}
270+
271+ static char * * prep_childenv (const char * const * deltaenv )
272+ {
273+ extern char * * environ ;
274+ char * * childenv ;
275+ struct string_list env = STRING_LIST_INIT_DUP ;
276+ struct strbuf key = STRBUF_INIT ;
277+ const char * const * p ;
278+ int i ;
279+
280+ /* Construct a sorted string list consisting of the current environ */
281+ for (p = (const char * const * ) environ ; p && * p ; p ++ ) {
282+ const char * equals = strchr (* p , '=' );
283+
284+ if (equals ) {
285+ strbuf_reset (& key );
286+ strbuf_add (& key , * p , equals - * p );
287+ string_list_append (& env , key .buf )-> util = (void * ) * p ;
288+ } else {
289+ string_list_append (& env , * p )-> util = (void * ) * p ;
290+ }
291+ }
292+ string_list_sort (& env );
293+
294+ /* Merge in 'deltaenv' with the current environ */
295+ for (p = deltaenv ; p && * p ; p ++ ) {
296+ const char * equals = strchr (* p , '=' );
297+
298+ if (equals ) {
299+ /* ('key=value'), insert or replace entry */
300+ strbuf_reset (& key );
301+ strbuf_add (& key , * p , equals - * p );
302+ string_list_insert (& env , key .buf )-> util = (void * ) * p ;
303+ } else {
304+ /* otherwise ('key') remove existing entry */
305+ string_list_remove (& env , * p , 0 );
306+ }
307+ }
308+
309+ /* Create an array of 'char *' to be used as the childenv */
310+ childenv = xmalloc ((env .nr + 1 ) * sizeof (char * ));
311+ for (i = 0 ; i < env .nr ; i ++ )
312+ childenv [i ] = env .items [i ].util ;
313+ childenv [env .nr ] = NULL ;
314+
315+ string_list_clear (& env , 0 );
316+ strbuf_release (& key );
317+ return childenv ;
318+ }
270319#endif
271320
272321static inline void set_cloexec (int fd )
@@ -395,12 +444,14 @@ int start_command(struct child_process *cmd)
395444#ifndef GIT_WINDOWS_NATIVE
396445{
397446 int notify_pipe [2 ];
447+ char * * childenv ;
398448 struct argv_array argv = ARGV_ARRAY_INIT ;
399449
400450 if (pipe (notify_pipe ))
401451 notify_pipe [0 ] = notify_pipe [1 ] = -1 ;
402452
403453 prepare_cmd (& argv , cmd );
454+ childenv = prep_childenv (cmd -> env );
404455
405456 cmd -> pid = fork ();
406457 failed_errno = errno ;
@@ -456,24 +507,18 @@ int start_command(struct child_process *cmd)
456507 if (cmd -> dir && chdir (cmd -> dir ))
457508 die_errno ("exec '%s': cd to '%s' failed" , cmd -> argv [0 ],
458509 cmd -> dir );
459- if (cmd -> env ) {
460- for (; * cmd -> env ; cmd -> env ++ ) {
461- if (strchr (* cmd -> env , '=' ))
462- putenv ((char * )* cmd -> env );
463- else
464- unsetenv (* cmd -> env );
465- }
466- }
467510
468511 /*
469512 * Attempt to exec using the command and arguments starting at
470513 * argv.argv[1]. argv.argv[0] contains SHELL_PATH which will
471514 * be used in the event exec failed with ENOEXEC at which point
472515 * we will try to interpret the command using 'sh'.
473516 */
474- execv (argv .argv [1 ], (char * const * ) argv .argv + 1 );
517+ execve (argv .argv [1 ], (char * const * ) argv .argv + 1 ,
518+ (char * const * ) childenv );
475519 if (errno == ENOEXEC )
476- execv (argv .argv [0 ], (char * const * ) argv .argv );
520+ execve (argv .argv [0 ], (char * const * ) argv .argv ,
521+ (char * const * ) childenv );
477522
478523 if (errno == ENOENT ) {
479524 if (!cmd -> silent_exec_failure )
@@ -509,6 +554,7 @@ int start_command(struct child_process *cmd)
509554 close (notify_pipe [0 ]);
510555
511556 argv_array_clear (& argv );
557+ free (childenv );
512558}
513559#else
514560{
0 commit comments