1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/* Auxiliary functions for the creation of subprocesses on Windows.
Copyright (C) 2024 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2024.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
/* Specification. */
#include "windows-path.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *
extended_PATH (const char * const *dll_dirs)
{
/* Create a string PATH=(dll_dirs[0];dll_dirs[1];...;)old_PATH */
const char *old_PATH = getenv ("PATH");
if (old_PATH == NULL)
old_PATH = "";
size_t size;
{
size = 5;
{
size_t i;
for (i = 0; dll_dirs[i] != NULL; i++)
size += strlen (dll_dirs[i]) + 1;
}
size += strlen (old_PATH) + 1;
}
char *new_PATH = (char *) malloc (size);
if (new_PATH == NULL)
return NULL;
{
char *p = new_PATH;
{
memcpy (p, "PATH=", 5);
p += 5;
}
{
size_t i;
for (i = 0; dll_dirs[i] != NULL; i++)
{
size_t l = strlen (dll_dirs[i]);
memcpy (p, dll_dirs[i], l);
p += l;
#if defined _WIN32 && !defined __CYGWIN__
*p++ = ';';
#else
*p++ = ':';
#endif
}
}
{
size_t l = strlen (old_PATH);
memcpy (p, old_PATH, l);
p += l;
*p = '\0';
}
}
return new_PATH;
}
char **
extended_environ (const char * const *dll_dirs)
{
char *child_PATH = extended_PATH (dll_dirs);
if (child_PATH == NULL)
return NULL;
/* Create a shallow copy of environ, adding the child_PATH and removing
the original "PATH=..." string.
This is a bit hairy, because we don't have a lock that would prevent
other threads from making modifications in ENVP. So, just make sure
we don't crash; but if other threads are making modifications, part
of the result may be wrong. */
char **envp;
#if defined _WIN32 && !defined __CYGWIN__
envp = _environ;
#else
envp = environ;
#endif
retry:
{
/* Guess the size of the needed block of memory.
The guess will be exact if other threads don't make modifications. */
size_t size = 0;
{
char **ep;
char *p;
for (ep = envp; (p = *ep) != NULL; ep++)
if (strncmp (p, "PATH=", 5) != 0)
size += 1;
}
char **new_environ = (char **) malloc ((1 + size + 1) * sizeof (char *));
if (new_environ == NULL)
{
free (child_PATH);
errno = ENOMEM;
return NULL;
}
char **nep = new_environ;
*nep++ = child_PATH;
{
size_t i = 0;
char **ep;
char *p;
for (ep = envp; (p = *ep) != NULL; ep++)
if (strncmp (p, "PATH=", 5) != 0)
{
if (i == size)
{
/* Other threads did modifications. Restart. */
free (new_environ);
goto retry;
}
*nep++ = p;
i += 1;
}
if (i < size)
{
/* Other threads did modifications. Restart. */
free (new_environ);
goto retry;
}
}
*nep = NULL;
return new_environ;
}
}
|