From: Justin Cinkelj <justin.cink...@xlab.si>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master
command line: use loader_parse_cmdline
Parse loader options with loader_parse_cmdline instead of strtok_r.
The cmdline passed in prepare_commands to osv::parse_command_line
is not reassebled from already parsed argv anymore, as app_cmdline
contains unmodifed commandline string (only loader options are removed).
Minor bug: commandline with only whitespaces results in VM to nicely
shutdown instead of reporting:
"This image has an empty command line. Nothing to run."
E.g.
./scripts/run.py -e ' --env=AA=aa ' # OK
./scripts/run.py -e ' --env=AA=aa ' # bug
This is fixed in last (6th) commit, title
command line: check for empty cmdline case after parsing cmdline
Cosmetic change: many argc/argv were renamed to loader_argc/loader_argv.
Fixes #892
Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
Message-Id: <20170913120516.17024-5-justin.cink...@xlab.si>
---
diff --git a/arch/x64/boot.S b/arch/x64/boot.S
--- a/arch/x64/boot.S
+++ b/arch/x64/boot.S
@@ -102,8 +102,8 @@ start64:
mov %rbx, osv_multiboot_info
lea init_stack_top, %rsp
call premain
- mov __argc, %edi
- mov __argv, %rsi
+ mov __loader_argc, %edi
+ mov __loader_argv, %rsi
call main
.cfi_endproc
diff --git a/core/commands.cc b/core/commands.cc
--- a/core/commands.cc
+++ b/core/commands.cc
@@ -311,7 +311,7 @@ parse_command_line(const std::string line, bool &ok)
// time. So let's go for a more traditional memory management to avoid
testing
// early / not early, etc
char *osv_cmdline = nullptr;
-static std::vector<char*> args;
+static char* parsed_cmdline = nullptr;
std::string getcmdline()
{
@@ -440,32 +440,22 @@ void loader_parse_cmdline(char* str, int *pargc,
char*** pargv, char** app_cmdli
int parse_cmdline(const char *p)
{
- char* save;
-
- if (args.size()) {
- // From the strtok manpage, we see that: "The first call to
strtok()
- // sets this pointer to point to the first byte of the string." It
- // follows from this that the first argument contains the address
we
- // should use to free the memory allocated for the string
- free(args[0]);
+ if (__loader_argv) {
+ // __loader_argv was allocated by loader_parse_cmdline
+ free(__loader_argv);
}
- args.resize(0);
if (osv_cmdline) {
free(osv_cmdline);
}
osv_cmdline = strdup(p);
- char* cmdline = strdup(p);
-
- while ((p = strtok_r(cmdline, " \t\n", &save)) != nullptr) {
- args.push_back(const_cast<char *>(p));
- cmdline = nullptr;
+ if (parsed_cmdline) {
+ free(parsed_cmdline);
}
- args.push_back(nullptr);
- __argv = args.data();
- __argc = args.size() - 1;
+ parsed_cmdline = strdup(p);
+ loader_parse_cmdline(parsed_cmdline, &__loader_argc, &__loader_argv,
&__app_cmdline);
return 0;
}
diff --git a/include/osv/commands.hh b/include/osv/commands.hh
--- a/include/osv/commands.hh
+++ b/include/osv/commands.hh
@@ -13,8 +13,9 @@
#include <vector>
#include <system_error>
-extern int __argc;
-extern char** __argv;
+extern int __loader_argc;
+extern char** __loader_argv;
+extern char* __app_cmdline;
static constexpr size_t max_cmdline = 1024;
namespace osv {
diff --git a/loader.cc b/loader.cc
--- a/loader.cc
+++ b/loader.cc
@@ -113,11 +113,11 @@ void premain()
boot_time.event(".init functions");
}
-int main(int ac, char **av)
+int main(int loader_argc, char **loader_argv)
{
smp_initial_find_current_cpu()->init_on_cpu();
- void main_cont(int ac, char** av);
- sched::init([=] { main_cont(ac, av); });
+ void main_cont(int loader_argc, char** loader_argv);
+ sched::init([=] { main_cont(loader_argc, loader_argv); });
}
static bool opt_leak = false;
@@ -144,20 +144,13 @@ int maxnic;
static int sampler_frequency;
static bool opt_enable_sampler = false;
-std::tuple<int, char**> parse_options(int ac, char** av)
+void parse_options(int loader_argc, char** loader_argv)
{
namespace bpo = boost::program_options;
namespace bpos = boost::program_options::command_line_style;
std::vector<const char*> args = { "osv" };
-
- // due to https://svn.boost.org/trac/boost/ticket/6991, we can't
terminate
- // command line parsing on the executable name, so we need to look for
it
- // ourselves
-
- auto nr_options = std::find_if(av, av + ac,
- [](const char* arg) { return
arg[0] != '-'; }) - av;
- std::copy(av, av + nr_options, std::back_inserter(args));
+ std::copy(loader_argv, loader_argv + loader_argc,
std::back_inserter(args));
bpo::options_description desc("OSv options");
desc.add_options()
@@ -297,29 +290,19 @@ std::tuple<int, char**> parse_options(int ac, char**
av)
}
boot_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(1_s
* vars["delay"].as<float>());
-
- av += nr_options;
- ac -= nr_options;
- return std::make_tuple(ac, av);
}
// return the std::string and the commands_args poiting to them as a move
-std::vector<std::vector<std::string> > prepare_commands(int ac, char** av)
+std::vector<std::vector<std::string> > prepare_commands(char* app_cmdline)
{
- if (ac == 0) {
+ if (strlen(app_cmdline) == 0) {
puts("This image has an empty command line. Nothing to run.");
osv::poweroff();
}
std::vector<std::vector<std::string> > commands;
- std::string line = std::string("");
bool ok;
- // concatenate everything
- for (auto i = 0; i < ac; i++) {
- line += std::string(av[i]) + " ";
- }
-
- commands = osv::parse_command_line(line, ok);
+ commands = osv::parse_command_line(app_cmdline, ok);
if (!ok) {
puts("Failed to parse command line.");
@@ -338,7 +321,7 @@ static std::string read_file(std::string fn)
void* do_main_thread(void *_main_args)
{
- auto main_args = static_cast<std::tuple<int,char**> *>(_main_args);
+ auto app_cmdline = static_cast<char*>(_main_args);
if (!arch_setup_console(opt_console)) {
abort("Unknown console:%s\n", opt_console.c_str());
@@ -448,7 +431,7 @@ void* do_main_thread(void *_main_args)
}
}
- auto commands = prepare_commands(std::get<0>(*main_args),
std::get<1>(*main_args));
+ auto commands = prepare_commands(app_cmdline);
// Run command lines in /init/* before the manual command line
if (opt_init) {
@@ -516,7 +499,7 @@ void* do_main_thread(void *_main_args)
return nullptr;
}
-void main_cont(int ac, char** av)
+void main_cont(int loader_argc, char** loader_argv)
{
osv::firmware_probe();
@@ -526,7 +509,7 @@ void main_cont(int ac, char** av)
std::vector<std::vector<std::string> > cmds;
- std::tie(ac, av) = parse_options(ac, av);
+ parse_options(loader_argc, loader_argv);
setenv("OSV_VERSION", osv::version().c_str(), 1);
@@ -581,7 +564,6 @@ void main_cont(int ac, char** av)
pthread_t pthread;
// run the payload in a pthread, so pthread_self() etc. work
- std::tuple<int,char**> main_args = std::make_tuple(ac,av);
// start do_main_thread unpinned (== pinned to all cpus)
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
@@ -591,7 +573,7 @@ void main_cont(int ac, char** av)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset);
- pthread_create(&pthread, &attr, do_main_thread, (void *) &main_args);
+ pthread_create(&pthread, &attr, do_main_thread, (void *)
__app_cmdline);
void* retval;
pthread_join(pthread, &retval);
@@ -610,5 +592,6 @@ void main_cont(int ac, char** av)
}
}
-int __argc;
-char** __argv;
+int __loader_argc = 0;
+char** __loader_argv = nullptr;
+char* __app_cmdline = nullptr;
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.