Skip to content

Commit 2480b61

Browse files
committed
unix,win: add ability to retrieve all env variables
Fixes: libuv#2400 PR-URL: libuv#2404 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]>
1 parent ef218ce commit 2480b61

File tree

6 files changed

+212
-1
lines changed

6 files changed

+212
-1
lines changed

docs/src/misc.rst

+28
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ Data types
180180
char machine[256];
181181
} uv_utsname_t;
182182

183+
.. c:type:: uv_env_item_t
184+
185+
Data type for environment variable storage.
186+
187+
::
188+
189+
typedef struct uv_env_item_s {
190+
char* name;
191+
char* value;
192+
} uv_env_item_t;
193+
183194

184195
API
185196
---
@@ -523,6 +534,23 @@ API
523534
524535
.. versionadded:: 1.8.0
525536
537+
.. c:function:: int uv_os_environ(uv_env_item_t** envitems, int* count)
538+
539+
Retrieves all environment variables. This function will allocate memory
540+
which must be freed by calling :c:func:`uv_os_free_environ`.
541+
542+
.. warning::
543+
This function is not thread safe.
544+
545+
.. versionadded:: 1.31.0
546+
547+
.. c:function:: void uv_os_free_environ(uv_env_item_t* envitems, int count);
548+
549+
Frees the memory allocated for the environment variables by
550+
:c:func:`uv_os_environ`.
551+
552+
.. versionadded:: 1.31.0
553+
526554
.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size)
527555
528556
Retrieves the environment variable specified by `name`, copies its value

include/uv.h

+8
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ typedef struct uv_fs_s uv_fs_t;
231231
typedef struct uv_work_s uv_work_t;
232232

233233
/* None of the above. */
234+
typedef struct uv_env_item_s uv_env_item_t;
234235
typedef struct uv_cpu_info_s uv_cpu_info_t;
235236
typedef struct uv_interface_address_s uv_interface_address_t;
236237
typedef struct uv_dirent_s uv_dirent_t;
@@ -1162,6 +1163,13 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
11621163
UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
11631164
int count);
11641165

1166+
struct uv_env_item_s {
1167+
char* name;
1168+
char* value;
1169+
};
1170+
1171+
UV_EXTERN int uv_os_environ(uv_env_item_t** envitems, int* count);
1172+
UV_EXTERN void uv_os_free_environ(uv_env_item_t* envitems, int count);
11651173
UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
11661174
UV_EXTERN int uv_os_setenv(const char* name, const char* value);
11671175
UV_EXTERN int uv_os_unsetenv(const char* name);

src/unix/core.c

+60
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,15 @@
5050
#endif
5151

5252
#ifdef __APPLE__
53+
# include <crt_externs.h>
5354
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
5455
# include <sys/filio.h>
5556
# if defined(O_CLOEXEC)
5657
# define UV__O_CLOEXEC O_CLOEXEC
5758
# endif
59+
# define environ (*_NSGetEnviron())
60+
#else
61+
extern char** environ;
5862
#endif
5963

6064
#if defined(__DragonFly__) || \
@@ -1284,6 +1288,62 @@ int uv_translate_sys_error(int sys_errno) {
12841288
}
12851289

12861290

1291+
int uv_os_environ(uv_env_item_t** envitems, int* count) {
1292+
int i, j, cnt;
1293+
uv_env_item_t* envitem;
1294+
1295+
*envitems = NULL;
1296+
*count = 0;
1297+
1298+
for (i = 0; environ[i] != NULL; i++);
1299+
1300+
*envitems = uv__calloc(i, sizeof(**envitems));
1301+
1302+
if (envitems == NULL)
1303+
return UV_ENOMEM;
1304+
1305+
for (j = 0, cnt = 0; j < i; j++) {
1306+
char* buf;
1307+
char* ptr;
1308+
1309+
if (environ[j] == NULL)
1310+
break;
1311+
1312+
buf = uv__strdup(environ[j]);
1313+
if (buf == NULL)
1314+
goto fail;
1315+
1316+
ptr = strchr(buf, '=');
1317+
if (ptr == NULL) {
1318+
uv__free(buf);
1319+
continue;
1320+
}
1321+
1322+
*ptr = '\0';
1323+
1324+
envitem = &(*envitems)[cnt];
1325+
envitem->name = buf;
1326+
envitem->value = ptr + 1;
1327+
1328+
cnt++;
1329+
}
1330+
1331+
*count = cnt;
1332+
return 0;
1333+
1334+
fail:
1335+
for (i = 0; i < cnt; i++) {
1336+
envitem = &(*envitems)[cnt];
1337+
uv__free(envitem->name);
1338+
}
1339+
uv__free(*envitems);
1340+
1341+
*envitems = NULL;
1342+
*count = 0;
1343+
return UV_ENOMEM;
1344+
}
1345+
1346+
12871347
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
12881348
char* var;
12891349
size_t len;

src/uv-common.c

+11
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,14 @@ void uv_loop_delete(uv_loop_t* loop) {
786786
if (loop != default_loop)
787787
uv__free(loop);
788788
}
789+
790+
791+
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
792+
int i;
793+
794+
for (i = 0; i < count; i++) {
795+
uv__free(envitems[i].name);
796+
}
797+
798+
uv__free(envitems);
799+
}

src/win/util.c

+69
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,75 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
13971397
}
13981398

13991399

1400+
int uv_os_environ(uv_env_item_t** envitems, int* count) {
1401+
wchar_t* env;
1402+
wchar_t* penv;
1403+
int i, cnt;
1404+
uv_env_item_t* envitem;
1405+
1406+
*envitems = NULL;
1407+
*count = 0;
1408+
1409+
env = GetEnvironmentStringsW();
1410+
if (env == NULL)
1411+
return 0;
1412+
1413+
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
1414+
1415+
*envitems = uv__calloc(i, sizeof(**envitems));
1416+
if (envitems == NULL) {
1417+
FreeEnvironmentStringsW(env);
1418+
return UV_ENOMEM;
1419+
}
1420+
1421+
penv = env;
1422+
cnt = 0;
1423+
1424+
while (*penv != L'\0' && cnt < i) {
1425+
char* buf;
1426+
char* ptr;
1427+
1428+
if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
1429+
goto fail;
1430+
1431+
ptr = strchr(buf, '=');
1432+
if (ptr == NULL) {
1433+
uv__free(buf);
1434+
goto do_continue;
1435+
}
1436+
1437+
*ptr = '\0';
1438+
1439+
envitem = &(*envitems)[cnt];
1440+
envitem->name = buf;
1441+
envitem->value = ptr + 1;
1442+
1443+
cnt++;
1444+
1445+
do_continue:
1446+
penv += wcslen(penv) + 1;
1447+
}
1448+
1449+
FreeEnvironmentStringsW(env);
1450+
1451+
*count = cnt;
1452+
return 0;
1453+
1454+
fail:
1455+
FreeEnvironmentStringsW(env);
1456+
1457+
for (i = 0; i < cnt; i++) {
1458+
envitem = &(*envitems)[cnt];
1459+
uv__free(envitem->name);
1460+
}
1461+
uv__free(*envitems);
1462+
1463+
*envitems = NULL;
1464+
*count = 0;
1465+
return UV_ENOMEM;
1466+
}
1467+
1468+
14001469
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
14011470
wchar_t var[MAX_ENV_VAR_LENGTH];
14021471
wchar_t* name_w;

test/test-env-vars.c

+36-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@
2727

2828
TEST_IMPL(env_vars) {
2929
const char* name = "UV_TEST_FOO";
30+
const char* name2 = "UV_TEST_FOO2";
3031
char buf[BUF_SIZE];
3132
size_t size;
32-
int r;
33+
int i, r, envcount, found;
34+
uv_env_item_t* envitems;
3335

3436
/* Reject invalid inputs when setting an environment variable */
3537
r = uv_os_setenv(NULL, "foo");
@@ -86,5 +88,38 @@ TEST_IMPL(env_vars) {
8688
r = uv_os_unsetenv(name);
8789
ASSERT(r == 0);
8890

91+
/* Check getting all env variables. */
92+
r = uv_os_setenv(name, "123456789");
93+
ASSERT(r == 0);
94+
r = uv_os_setenv(name2, "");
95+
ASSERT(r == 0);
96+
97+
r = uv_os_environ(&envitems, &envcount);
98+
ASSERT(r == 0);
99+
ASSERT(envcount > 0);
100+
101+
found = 0;
102+
103+
for (i = 0; i < envcount; i++) {
104+
/* printf("Env: %s = %s\n", envitems[i].name, envitems[i].value); */
105+
if (strcmp(envitems[i].name, name) == 0) {
106+
found++;
107+
ASSERT(strcmp(envitems[i].value, "123456789") == 0);
108+
} else if (strcmp(envitems[i].name, name2) == 0) {
109+
found++;
110+
ASSERT(strlen(envitems[i].value) == 0);
111+
}
112+
}
113+
114+
ASSERT(found == 2);
115+
116+
uv_os_free_environ(envitems, envcount);
117+
118+
r = uv_os_unsetenv(name);
119+
ASSERT(r == 0);
120+
121+
r = uv_os_unsetenv(name2);
122+
ASSERT(r == 0);
123+
89124
return 0;
90125
}

0 commit comments

Comments
 (0)