2013-03-06 10:29:49 +01:00
|
|
|
/**
|
|
|
|
* Native CPU entry code
|
|
|
|
*
|
2015-09-27 18:58:30 +02:00
|
|
|
* Copyright (C) 2013 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
|
2017-01-12 18:59:12 +01:00
|
|
|
* 2017 Freie Universität Berlin
|
2013-03-06 10:29:49 +01:00
|
|
|
*
|
2014-07-31 19:45:27 +02:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
2013-03-06 10:29:49 +01:00
|
|
|
*
|
|
|
|
* @ingroup arch
|
|
|
|
* @{
|
|
|
|
* @file
|
2015-09-27 18:58:30 +02:00
|
|
|
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
|
2017-01-12 18:59:12 +01:00
|
|
|
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
2013-03-06 10:29:49 +01:00
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2013-11-07 17:23:08 +01:00
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#else
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
#include <assert.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdbool.h>
|
2013-03-06 01:08:15 +01:00
|
|
|
#include <stdio.h>
|
2013-06-26 23:29:09 +02:00
|
|
|
#include <stdlib.h>
|
2013-08-18 20:34:53 +02:00
|
|
|
#include <unistd.h>
|
2013-06-26 23:29:09 +02:00
|
|
|
#include <err.h>
|
2013-08-18 20:34:53 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2013-06-26 23:29:09 +02:00
|
|
|
|
2016-02-27 01:12:02 +01:00
|
|
|
#include "kernel_init.h"
|
2013-11-07 17:23:08 +01:00
|
|
|
#include "cpu.h"
|
2014-11-28 12:08:51 +01:00
|
|
|
#include "irq.h"
|
2013-06-26 23:29:09 +02:00
|
|
|
|
2013-08-18 20:34:53 +02:00
|
|
|
#include "board_internal.h"
|
2013-11-07 17:23:08 +01:00
|
|
|
#include "native_internal.h"
|
2015-12-09 09:29:47 +01:00
|
|
|
#include "tty_uart.h"
|
2013-03-06 01:08:15 +01:00
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
typedef enum {
|
|
|
|
_STDIOTYPE_STDIO = 0, /**< leave intact */
|
|
|
|
_STDIOTYPE_NULL, /**< redirect to "/dev/null" */
|
|
|
|
_STDIOTYPE_FILE, /**< redirect to file */
|
|
|
|
} _stdiotype_t;
|
|
|
|
|
2013-08-18 20:34:53 +02:00
|
|
|
int _native_null_in_pipe[2];
|
|
|
|
int _native_null_out_file;
|
2013-12-10 12:10:05 +01:00
|
|
|
const char *_progname;
|
2014-02-14 16:18:40 +01:00
|
|
|
char **_native_argv;
|
2014-05-13 16:53:36 +02:00
|
|
|
pid_t _native_pid;
|
2014-05-16 15:40:06 +02:00
|
|
|
pid_t _native_id;
|
2015-01-10 10:22:51 +01:00
|
|
|
unsigned _native_rng_seed = 0;
|
|
|
|
int _native_rng_mode = 0;
|
2014-05-19 19:58:40 +02:00
|
|
|
const char *_native_unix_socket_path = NULL;
|
2013-08-18 20:34:53 +02:00
|
|
|
|
2015-08-21 16:08:43 +02:00
|
|
|
#ifdef MODULE_NETDEV2_TAP
|
2016-07-07 21:38:08 +02:00
|
|
|
#include "netdev2_tap_params.h"
|
|
|
|
|
|
|
|
netdev2_tap_params_t netdev2_tap_params[NETDEV2_TAP_MAX];
|
2015-05-19 09:50:29 +02:00
|
|
|
#endif
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
static const char short_opts[] = ":hi:s:deEoc:";
|
|
|
|
static const struct option long_opts[] = {
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "id", required_argument, NULL, 'i' },
|
|
|
|
{ "seed", required_argument, NULL, 's' },
|
|
|
|
{ "daemonize", no_argument, NULL, 'd' },
|
|
|
|
{ "stderr-pipe", no_argument, NULL, 'e' },
|
|
|
|
{ "stderr-noredirect", no_argument, NULL, 'E' },
|
|
|
|
{ "stdout-pipe", no_argument, NULL, 'o' },
|
|
|
|
{ "uart-tty", required_argument, NULL, 'c' },
|
|
|
|
{ NULL, 0, NULL, '\0' },
|
|
|
|
};
|
|
|
|
|
2013-08-18 20:34:53 +02:00
|
|
|
/**
|
2017-01-12 18:59:12 +01:00
|
|
|
* @brief initialize _native_null_in_pipe to allow for reading from stdin
|
|
|
|
*
|
|
|
|
* @param[in] stdiotype _STDIOTYPE_STDIO to to just initialize pipe, any other
|
|
|
|
* value to also redirect stdin to that pipe
|
2013-08-18 20:34:53 +02:00
|
|
|
*/
|
2017-01-12 18:59:12 +01:00
|
|
|
void _native_input(_stdiotype_t stdintype)
|
2013-08-18 20:34:53 +02:00
|
|
|
{
|
2014-06-13 23:52:05 +02:00
|
|
|
if (real_pipe(_native_null_in_pipe) == -1) {
|
2014-07-18 10:07:02 +02:00
|
|
|
err(EXIT_FAILURE, "_native_null_in(): pipe()");
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
if (stdintype == _STDIOTYPE_STDIO) {
|
2013-08-18 20:34:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-18 20:34:12 +02:00
|
|
|
if (real_dup2(_native_null_in_pipe[0], STDIN_FILENO) == -1) {
|
2013-08-18 20:34:53 +02:00
|
|
|
err(EXIT_FAILURE, "_native_null_in: dup2(STDIN_FILENO)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-12 18:59:12 +01:00
|
|
|
* @brief set up output redirection
|
2013-08-18 20:34:53 +02:00
|
|
|
*
|
2017-01-12 18:59:12 +01:00
|
|
|
* @param[in] stdiotype The type of redirection
|
|
|
|
* @param[in] output Output file. May be either `STDOUT_FILENO` for stdout or
|
|
|
|
* `STDERR_FILENO` for stderr
|
2013-08-18 20:34:53 +02:00
|
|
|
*
|
2017-01-12 18:59:12 +01:00
|
|
|
* @return The new file descriptor of the redirection
|
|
|
|
* @return -1 if the file descriptor did not change from the standard one
|
2013-08-18 20:34:53 +02:00
|
|
|
*/
|
2017-01-12 18:59:12 +01:00
|
|
|
int _native_log_output(_stdiotype_t stdiotype, int output)
|
2013-08-18 20:34:53 +02:00
|
|
|
{
|
2017-01-12 18:59:12 +01:00
|
|
|
int outfile;
|
2013-08-18 20:34:53 +02:00
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
assert((output == STDERR_FILENO) || (output == STDOUT_FILENO));
|
|
|
|
|
|
|
|
switch (stdiotype) {
|
|
|
|
case _STDIOTYPE_STDIO:
|
|
|
|
return -1;
|
|
|
|
case _STDIOTYPE_NULL:
|
|
|
|
if ((outfile = real_open("/dev/null", O_WRONLY)) == -1) {
|
|
|
|
err(EXIT_FAILURE, "_native_log_output: open");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case _STDIOTYPE_FILE: {
|
|
|
|
/* 20 should suffice for 64-bit PIDs ;-) */
|
|
|
|
char logname[sizeof("/tmp/riot.stderr.") + 20];
|
|
|
|
|
|
|
|
snprintf(logname, sizeof(logname), "/tmp/riot.std%s.%d",
|
|
|
|
(output == STDOUT_FILENO) ? "out": "err", _native_pid);
|
|
|
|
if ((outfile = real_creat(logname, 0666)) == -1) {
|
|
|
|
err(EXIT_FAILURE, "_native_log_output: open");
|
|
|
|
}
|
|
|
|
break;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
default:
|
|
|
|
errx(EXIT_FAILURE, "_native_log_output: unknown log type");
|
|
|
|
break;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
if (real_dup2(outfile, output) == -1) {
|
|
|
|
err(EXIT_FAILURE, "_native_log_output: dup2(output)");
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
return outfile;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
|
|
|
|
2014-05-07 12:36:32 +02:00
|
|
|
void daemonize(void)
|
2013-08-18 20:34:53 +02:00
|
|
|
{
|
2014-06-18 20:34:12 +02:00
|
|
|
if ((_native_pid = real_fork()) == -1) {
|
2013-08-18 20:34:53 +02:00
|
|
|
err(EXIT_FAILURE, "daemonize: fork");
|
|
|
|
}
|
|
|
|
|
2014-05-13 16:53:36 +02:00
|
|
|
if (_native_pid > 0) {
|
|
|
|
real_printf("RIOT pid: %d\n", _native_pid);
|
2014-11-18 17:31:26 +01:00
|
|
|
real_exit(EXIT_SUCCESS);
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2014-05-19 19:58:05 +02:00
|
|
|
else {
|
|
|
|
_native_pid = real_getpid();
|
2015-02-15 12:46:54 +01:00
|
|
|
|
|
|
|
/* detach from current working directory */
|
|
|
|
if (real_chdir("/") == -1) {
|
|
|
|
err(EXIT_FAILURE, "daemonize: chdir");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* detach from process group */
|
|
|
|
if (real_setsid() == -1) {
|
|
|
|
err(EXIT_FAILURE, "daemonize: setsid");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set umask */
|
|
|
|
real_umask(0);
|
2014-05-19 19:58:05 +02:00
|
|
|
}
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
|
|
|
|
2014-11-17 12:40:13 +01:00
|
|
|
/**
|
|
|
|
* Remove any -d options from an argument vector.
|
|
|
|
*
|
|
|
|
* @param[in][out] argv an argument vector
|
|
|
|
*/
|
2017-01-12 18:59:12 +01:00
|
|
|
static void filter_daemonize_argv(char **argv)
|
2014-11-17 12:40:13 +01:00
|
|
|
{
|
2017-01-12 18:59:12 +01:00
|
|
|
int idx = 0;
|
|
|
|
for (char **narg = argv; *narg != NULL; narg++, idx++) {
|
2014-11-17 12:40:13 +01:00
|
|
|
if (strcmp("-d", narg[0]) == 0) {
|
|
|
|
char **xarg = narg;
|
|
|
|
do {
|
|
|
|
xarg[0] = xarg[1];
|
|
|
|
} while (*xarg++ != NULL);
|
2017-01-12 18:59:12 +01:00
|
|
|
if (optind > 1) {
|
|
|
|
/* adapt optind if changed */
|
|
|
|
optind--;
|
|
|
|
}
|
2014-11-17 12:40:13 +01:00
|
|
|
narg--; /* rescan current item to filter out double args */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
void usage_exit(int status)
|
2013-08-18 20:34:53 +02:00
|
|
|
{
|
2013-12-10 12:10:05 +01:00
|
|
|
real_printf("usage: %s", _progname);
|
2013-08-18 20:34:53 +02:00
|
|
|
|
2015-08-21 16:08:43 +02:00
|
|
|
#if defined(MODULE_NETDEV2_TAP)
|
2016-07-07 21:38:08 +02:00
|
|
|
for (int i = 0; i < NETDEV2_TAP_MAX; i++) {
|
|
|
|
real_printf(" <tap interface %d>", i + 1);
|
|
|
|
}
|
2013-08-18 20:34:53 +02:00
|
|
|
#endif
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
real_printf(" [-i <id>] [-d] [-e|-E] [-o] [-c <tty>]\n");
|
|
|
|
|
|
|
|
real_printf(" help: %s -h\n\n", _progname);
|
|
|
|
|
|
|
|
real_printf("\nOptions:\n"
|
|
|
|
" -h, --help\n"
|
|
|
|
" print this help message\n"
|
|
|
|
" -i <id>, --id=<id>\n"
|
|
|
|
" specify instance id (set by config module)\n"
|
|
|
|
" -s <seed>, --seed=<seed>\n"
|
|
|
|
" specify srandom(3) seed (/dev/random is used instead of random(3) if\n"
|
|
|
|
" the option is omitted)\n"
|
|
|
|
" -d, --daemonize\n"
|
|
|
|
" daemonize native instance\n"
|
|
|
|
" -e, --stderr-pipe\n"
|
|
|
|
" redirect stderr to file\n"
|
|
|
|
" -E, --stderr-noredirect\n"
|
|
|
|
" do not redirect stderr (i.e. leave sterr unchanged despite\n"
|
|
|
|
" daemon/socket io)\n"
|
|
|
|
" -o, --stdout-pipe\n"
|
|
|
|
" redirect stdout to file (/tmp/riot.stdout.PID) when not attached\n"
|
|
|
|
" to socket\n"
|
|
|
|
" -c <tty>, --uart-tty=<tty>\n"
|
|
|
|
" specify TTY device for UART. This argument can be used multiple\n"
|
|
|
|
" times (up to UART_NUMOF)\n");
|
|
|
|
real_exit(status);
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
|
|
|
|
2013-06-26 23:29:09 +02:00
|
|
|
__attribute__((constructor)) static void startup(int argc, char **argv)
|
2013-03-06 01:08:15 +01:00
|
|
|
{
|
2014-07-18 10:07:02 +02:00
|
|
|
_native_init_syscalls();
|
2014-01-24 17:03:01 +01:00
|
|
|
|
2014-05-13 16:53:36 +02:00
|
|
|
_native_argv = argv;
|
2013-12-10 12:10:05 +01:00
|
|
|
_progname = argv[0];
|
2014-05-13 17:41:36 +02:00
|
|
|
_native_pid = real_getpid();
|
2014-02-14 16:18:40 +01:00
|
|
|
|
2014-05-16 15:40:06 +02:00
|
|
|
/* will possibly be overridden via option below: */
|
|
|
|
_native_id = _native_pid;
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
int c, opt_idx = 0, uart = 0;
|
|
|
|
bool dmn = false, force_stderr = false;
|
|
|
|
_stdiotype_t stderrtype = _STDIOTYPE_STDIO;
|
|
|
|
_stdiotype_t stdouttype = _STDIOTYPE_STDIO;
|
|
|
|
_stdiotype_t stdintype = _STDIOTYPE_STDIO;
|
|
|
|
|
|
|
|
while ((c = getopt_long(argc, argv, short_opts, long_opts, &opt_idx)) >= 0) {
|
|
|
|
switch (c) {
|
|
|
|
case 0:
|
|
|
|
case 'h':
|
|
|
|
usage_exit(EXIT_SUCCESS);
|
|
|
|
case 'i':
|
|
|
|
_native_id = atol(optarg);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
_native_rng_seed = atol(optarg);
|
|
|
|
_native_rng_mode = 1;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
dmn = true;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
if (force_stderr) {
|
|
|
|
/* -e and -E are mutually exclusive */
|
|
|
|
usage_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
stderrtype = _STDIOTYPE_FILE;
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
if (stderrtype == _STDIOTYPE_FILE) {
|
|
|
|
/* -e and -E are mutually exclusive */
|
|
|
|
usage_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
force_stderr = true;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
stdouttype = _STDIOTYPE_FILE;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
tty_uart_setup(uart++, optarg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef MODULE_NETDEV2_TAP
|
2016-07-07 21:38:08 +02:00
|
|
|
for (int i = 0; i < NETDEV2_TAP_MAX; i++) {
|
|
|
|
if (argv[optind + i] == NULL) {
|
|
|
|
/* no tap parameter left */
|
|
|
|
usage_exit(EXIT_FAILURE);
|
|
|
|
}
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
if (dmn) {
|
|
|
|
filter_daemonize_argv(_native_argv);
|
|
|
|
if (stderrtype == _STDIOTYPE_STDIO) {
|
|
|
|
stderrtype = _STDIOTYPE_NULL;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
if (stdouttype == _STDIOTYPE_STDIO) {
|
|
|
|
stdouttype = _STDIOTYPE_NULL;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
if (stdintype == _STDIOTYPE_STDIO) {
|
|
|
|
stdintype = _STDIOTYPE_NULL;
|
2013-08-18 20:34:53 +02:00
|
|
|
}
|
2014-11-17 12:40:13 +01:00
|
|
|
daemonize();
|
|
|
|
}
|
2017-01-12 18:59:12 +01:00
|
|
|
if (force_stderr) {
|
|
|
|
stderrtype = _STDIOTYPE_STDIO;
|
|
|
|
}
|
2014-11-17 12:40:13 +01:00
|
|
|
|
2017-01-12 18:59:12 +01:00
|
|
|
_native_log_output(stderrtype, STDERR_FILENO);
|
|
|
|
_native_null_out_file = _native_log_output(stdouttype, STDOUT_FILENO);
|
|
|
|
_native_input(stdintype);
|
2013-08-18 20:34:53 +02:00
|
|
|
|
2013-03-06 01:08:15 +01:00
|
|
|
native_cpu_init();
|
|
|
|
native_interrupt_init();
|
2015-08-21 16:08:43 +02:00
|
|
|
#ifdef MODULE_NETDEV2_TAP
|
2016-07-07 21:38:08 +02:00
|
|
|
for (int i = 0; i < NETDEV2_TAP_MAX; i++) {
|
|
|
|
netdev2_tap_params[i].tap_name = &argv[optind + i];
|
|
|
|
}
|
2015-05-19 09:50:29 +02:00
|
|
|
#endif
|
2013-03-06 01:08:15 +01:00
|
|
|
|
|
|
|
board_init();
|
|
|
|
|
|
|
|
puts("RIOT native hardware initialization complete.\n");
|
2014-11-28 12:08:51 +01:00
|
|
|
irq_enable();
|
2013-03-06 01:08:15 +01:00
|
|
|
kernel_init();
|
|
|
|
}
|