From 66063e51373ba28d0049e0a49a7908dc1ef8aec3 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 17 Aug 2020 14:59:20 +0200 Subject: [PATCH] qt5_component: support arguments and environment from config Fixes #3049 --- repos/libports/include/libc/args.h | 130 ++++++++++++++++++ repos/libports/src/lib/posix/construct.cc | 125 ++--------------- .../src/lib/qt5_component/qt_component.cc | 27 +++- 3 files changed, 161 insertions(+), 121 deletions(-) create mode 100644 repos/libports/include/libc/args.h diff --git a/repos/libports/include/libc/args.h b/repos/libports/include/libc/args.h new file mode 100644 index 0000000000..76645d82cb --- /dev/null +++ b/repos/libports/include/libc/args.h @@ -0,0 +1,130 @@ +/* + * \brief Populate arguments and environment from config + * \author Christian Prochaska + * \date 2020-08-14 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__LIBC__ARGS_H_ +#define _INCLUDE__LIBC__ARGS_H_ + +/* Genode includes */ +#include +#include + +/* libc includes */ +#include /* 'malloc' */ + +static void populate_args_and_env(Libc::Env &env, int &argc, char **&argv, char **&envp) +{ + using Genode::Xml_node; + using Genode::Xml_attribute; + + env.config([&] (Xml_node const &node) { + + int envc = 0; + + /* count the number of arguments and environment variables */ + node.for_each_sub_node([&] (Xml_node const &node) { + /* check if the 'value' attribute exists */ + if (node.has_type("arg") && node.has_attribute("value")) + ++argc; + else + if (node.has_type("env") && node.has_attribute("key") && node.has_attribute("value")) + ++envc; + }); + + if (argc == 0 && envc == 0) + return; /* from lambda */ + + /* 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 */ + int arg_i = 0; + int env_i = 0; + node.for_each_sub_node([&] (Xml_node const &node) { + + /* insert an argument */ + if (node.has_type("arg")) { + + Xml_attribute attr = node.attribute("value"); + attr.with_raw_value([&] (char const *start, size_t length) { + + size_t const size = length + 1; /* for null termination */ + + argv[arg_i] = (char *)malloc(size); + + Genode::copy_cstring(argv[arg_i], start, size); + }); + + ++arg_i; + } + else + + /* insert an environment variable */ + if (node.has_type("env")) try { + + auto check_attr = [] (Xml_node node, auto key) { + if (!node.has_attribute(key)) + Genode::warning(" node lacks '", key, "' attribute"); }; + + check_attr(node, "key"); + check_attr(node, "value"); + + Xml_attribute const key = node.attribute("key"); + Xml_attribute const value = node.attribute("value"); + + using namespace Genode; + + /* + * An environment variable has the form =, followed + * by a terminating zero. + */ + size_t const var_size = key .value_size() + 1 + + value.value_size() + 1; + + envp[env_i] = (char*)malloc(var_size); + + size_t pos = 0; + + /* append characters to env variable with zero termination */ + auto append = [&] (char const *s, size_t len) { + + if (pos + len >= var_size) { + /* this should never happen */ + warning("truncated environment variable: ", node); + return; + } + + copy_cstring(envp[env_i] + pos, s, len + 1); + pos += len; + }; + + key.with_raw_value([&] (char const *start, size_t length) { + append(start, length); }); + + append("=", 1); + + value.with_raw_value([&] (char const *start, size_t length) { + append(start, length); }); + + ++env_i; + + } + catch (Xml_node::Nonexistent_sub_node) { } + catch (Xml_node::Nonexistent_attribute) { } + }); + + envp[env_i] = NULL; + }); +} + +#endif /* _INCLUDE__LIBC__ARGS_H_ */ diff --git a/repos/libports/src/lib/posix/construct.cc b/repos/libports/src/lib/posix/construct.cc index bbd8c566e8..aaec6f34cb 100644 --- a/repos/libports/src/lib/posix/construct.cc +++ b/repos/libports/src/lib/posix/construct.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2016-2017 Genode Labs GmbH + * Copyright (C) 2016-2020 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. @@ -15,133 +15,26 @@ #include /* libc includes */ -#include /* 'malloc' */ +#include #include /* 'exit' */ -extern char **genode_argv; -extern int genode_argc; -extern char **genode_envp; - /* initial environment for the FreeBSD libc implementation */ extern char **environ; /* provided by the application */ -extern "C" int main(int argc, char ** argv, char **envp); - +extern "C" int main(int argc, char **argv, char **envp); static void construct_component(Libc::Env &env) { - using Genode::Xml_node; - using Genode::Xml_attribute; + int argc = 0; + char **argv = nullptr; + char **envp = nullptr; - env.config([&] (Xml_node const &node) { - int argc = 0; - int envc = 0; - char **argv; - char **envp; + populate_args_and_env(env, argc, argv, envp); - /* count the number of arguments and environment variables */ - node.for_each_sub_node([&] (Xml_node const &node) { - /* check if the 'value' attribute exists */ - if (node.has_type("arg") && node.has_attribute("value")) - ++argc; - else - if (node.has_type("env") && node.has_attribute("key") && node.has_attribute("value")) - ++envc; - }); + environ = envp; - if (argc == 0 && envc == 0) - return; /* from lambda */ - - /* 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 */ - int arg_i = 0; - int env_i = 0; - node.for_each_sub_node([&] (Xml_node const &node) { - - /* insert an argument */ - if (node.has_type("arg")) { - - Xml_attribute attr = node.attribute("value"); - attr.with_raw_value([&] (char const *start, size_t length) { - - size_t const size = length + 1; /* for null termination */ - - argv[arg_i] = (char *)malloc(size); - - Genode::copy_cstring(argv[arg_i], start, size); - }); - - ++arg_i; - } - else - - /* insert an environment variable */ - if (node.has_type("env")) try { - - auto check_attr = [] (Xml_node node, auto key) { - if (!node.has_attribute(key)) - Genode::warning(" node lacks '", key, "' attribute"); }; - - check_attr(node, "key"); - check_attr(node, "value"); - - Xml_attribute const key = node.attribute("key"); - Xml_attribute const value = node.attribute("value"); - - using namespace Genode; - - /* - * An environment variable has the form =, followed - * by a terminating zero. - */ - size_t const var_size = key .value_size() + 1 - + value.value_size() + 1; - - envp[env_i] = (char*)malloc(var_size); - - size_t pos = 0; - - /* append characters to env variable with zero termination */ - auto append = [&] (char const *s, size_t len) { - - if (pos + len >= var_size) { - /* this should never happen */ - warning("truncated environment variable: ", node); - return; - } - - copy_cstring(envp[env_i] + pos, s, len + 1); - pos += len; - }; - - key.with_raw_value([&] (char const *start, size_t length) { - append(start, length); }); - - append("=", 1); - - value.with_raw_value([&] (char const *start, size_t length) { - append(start, length); }); - - ++env_i; - - } - catch (Xml_node::Nonexistent_sub_node) { } - catch (Xml_node::Nonexistent_attribute) { } - }); - - envp[env_i] = NULL; - - /* register command-line arguments at Genode's startup code */ - genode_argc = argc; - genode_argv = argv; - genode_envp = environ = envp; - }); - - exit(main(genode_argc, genode_argv, genode_envp)); + exit(main(argc, argv, envp)); } diff --git a/repos/libports/src/lib/qt5_component/qt_component.cc b/repos/libports/src/lib/qt5_component/qt_component.cc index 99320d44d0..4e22be2f69 100644 --- a/repos/libports/src/lib/qt5_component/qt_component.cc +++ b/repos/libports/src/lib/qt5_component/qt_component.cc @@ -12,6 +12,7 @@ */ /* Genode includes */ +#include #include /* libc includes */ @@ -20,8 +21,11 @@ /* qt5_component includes */ #include +/* initial environment for the FreeBSD libc implementation */ +extern char **environ; + /* provided by the application */ -extern "C" int main(int argc, char const **argv); +extern "C" int main(int argc, char **argv, char **envp); void Libc::Component::construct(Libc::Env &env) { @@ -29,11 +33,24 @@ void Libc::Component::construct(Libc::Env &env) qpa_init(env); - int argc = 1; - char const *argv[] = { "qt5_app", 0 }; + int argc = 0; + char **argv = nullptr; + char **envp = nullptr; - int exit_value = main(argc, argv); + populate_args_and_env(env, argc, argv, envp); - exit(exit_value); + /* at least the executable name is required */ + + char default_argv0[] { "qt5_component" }; + char *default_argv[] { default_argv0, nullptr }; + + if (argc == 0) { + argc = 1; + argv = default_argv; + } + + environ = envp; + + exit(main(argc, argv, envp)); }); }