qt5_component: support arguments and environment from config

Fixes #3049
This commit is contained in:
Christian Prochaska 2020-08-17 14:59:20 +02:00 committed by Norman Feske
parent f03917ab7c
commit 66063e5137
3 changed files with 161 additions and 121 deletions

View File

@ -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 <libc/component.h>
#include <util/xml_node.h>
/* libc includes */
#include <stdlib.h> /* '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("<env> 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 <key>=<value>, 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_ */

View File

@ -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/component.h>
/* libc includes */
#include <stdlib.h> /* 'malloc' */
#include <libc/args.h>
#include <stdlib.h> /* '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("<env> 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 <key>=<value>, 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));
}

View File

@ -12,6 +12,7 @@
*/
/* Genode includes */
#include <libc/args.h>
#include <libc/component.h>
/* libc includes */
@ -20,8 +21,11 @@
/* qt5_component includes */
#include <qt5_component/qpa_init.h>
/* 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));
});
}