lib/posix: populate environment variables from config

Parse ``<env key="..." value=".."/>`` nodes from the config ROM and
populate a list at the 'genode_envp' and 'environ' symbols.

Test script at run/libc_getenv.

Fix #2236
This commit is contained in:
Emery Hemingway 2017-01-24 14:07:43 +01:00 committed by Norman Feske
parent 7f7f8063dd
commit 9b3ecb114d
5 changed files with 136 additions and 19 deletions

View File

@ -0,0 +1,53 @@
build "core init drivers/timer test/libc_getenv"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="CPU"/>
<service name="LOG"/>
<service name="PD"/>
<service name="RAM"/>
<service name="RM"/>
<service name="ROM"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="test-libc_getenv">
<resource name="RAM" quantum="4M"/>
<config>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
<libc stdout="/dev/log"/>
<arg value="test-libc_getenv"/>
<arg value="foo"/>
<arg value="bar"/>
<arg value="baz"/>
<env key="foo" value="bar"/>
<env key="bar" value="foo"/>
</config>
</start>
</config>
}
build_boot_image {
core init timer test-libc_getenv
ld.lib.so libc.lib.so libm.lib.so
}
append qemu_args " -nographic -m 64 "
run_genode_until "child .* exited with exit value 0.*\n" 10
grep_output {\[init -\> test-libc_getenv\]}
compare_output_to {
[init -> test-libc_getenv] foo="bar"
[init -> test-libc_getenv] bar="foo"
[init -> test-libc_getenv] baz="(null)"
}

View File

@ -22,6 +22,8 @@ extern char **genode_argv;
extern int genode_argc; extern int genode_argc;
extern char **genode_envp; extern char **genode_envp;
/* initial environment for the FreeBSD libc implementation */
extern char **environ;
/* provided by the application */ /* provided by the application */
extern "C" int main(int argc, char ** argv, char **envp); extern "C" int main(int argc, char ** argv, char **envp);
@ -34,40 +36,72 @@ void Libc::Component::construct(Libc::Env &env)
env.config([&] (Xml_node const &node) { env.config([&] (Xml_node const &node) {
int argc = 0; int argc = 0;
static char **argv; int envc = 0;
char **argv;
char **envp;
/* count the number of arguments */ /* count the number of arguments and environment variables */
node.for_each_sub_node("arg", [&] (Xml_node const &arg_node) { node.for_each_sub_node([&] (Xml_node const &node) {
/* check if the 'value' attribute exists */ /* check if the 'value' attribute exists */
if (arg_node.has_attribute("value")) if (node.has_type("arg") && node.has_attribute("value"))
++argc; ++argc;
else
if (node.has_type("env") && node.has_attribute("key") && node.has_attribute("value"))
++envc;
}); });
if (argc == 0) if (argc == 0 && envc == 0)
return; return; /* from lambda */
argv = (char**)malloc((argc + 1) * sizeof(char*)); /* arguments and environment are a contiguous array (but don't count on it) */
argv = (char**)malloc((argc + envc + 1) * sizeof(char*));
envp = &argv[argc];
/* read the arguments */ /* read the arguments */
int i = 0; int arg_i = 0;
node.for_each_sub_node("arg", [&] (Xml_node const &arg_node) { int env_i = 0;
try { node.for_each_sub_node([&] (Xml_node const &node) {
Xml_attribute attr = arg_node.attribute("value"); /* insert an argument */
if (node.has_type("arg")) try {
Xml_attribute attr = node.attribute("value");
Genode::size_t const arg_len = attr.value_size()+1; Genode::size_t const arg_len = attr.value_size()+1;
argv[i] = (char*)malloc(arg_len); char *arg = argv[arg_i] = (char*)malloc(arg_len);
attr.value(argv[i], arg_len);
++i; attr.value(arg, arg_len);
++arg_i;
} catch (Xml_node::Nonexistent_sub_node) { }
else
/* insert an environment variable */
if (node.has_type("env")) try {
Xml_attribute key_attr = node.attribute("key");
Xml_attribute val_attr = node.attribute("value");
Genode::size_t const pair_len =
key_attr.value_size() +
val_attr.value_size() + 1;
char *env = envp[env_i] = (char*)malloc(pair_len);
Genode::size_t off = 0;
key_attr.value(&env[off], key_attr.value_size()+1);
off = key_attr.value_size();
env[off++] = '=';
val_attr.value(&env[off], val_attr.value_size()+1);
++env_i;
} catch (Xml_node::Nonexistent_sub_node) { } } catch (Xml_node::Nonexistent_sub_node) { }
}); });
argv[i] = nullptr; envp[env_i] = NULL;
/* register command-line arguments at Genode's startup code */ /* register command-line arguments at Genode's startup code */
genode_argc = argc; genode_argc = argc;
genode_argv = argv; genode_argv = argv;
genode_envp = environ = envp;
}); });
/* TODO: environment variables, see #2236 */
exit(main(genode_argc, genode_argv, genode_envp)); exit(main(genode_argc, genode_argv, genode_envp));
} }

View File

@ -0,0 +1,26 @@
/*
* \brief Libc getenv(...) test
* \author Emery Hemingway
* \date 2017-01-24
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for (i = 1; i < argc; ++i) {
char const *key = argv[i];
printf("%s=\"%s\"\n", key, getenv(key));
}
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-libc_getenv
SRC_C = main.c
LIBS = posix

View File

@ -8,10 +8,12 @@ tar_rom
noux noux
noux_net_netcat noux_net_netcat
libc_ffat libc_ffat
libc_getenv
libc_pipe libc_pipe
libc_vfs libc_vfs
libc_vfs_ram libc_vfs_ext2
libc_vfs_fs libc_vfs_fs
libc_vfs_ram
timed_semaphore timed_semaphore
signal signal
sub_rm sub_rm
@ -41,7 +43,6 @@ part_blk
xml_generator xml_generator
blk_cache blk_cache
rump_ext2 rump_ext2
libc_vfs_ext2
thread thread
pthread pthread
vbox_auto_win7 vbox_auto_win7