#!/bin/bash
#
# QEMU network interface configuration script. This utility needs to
# be run as root, and will use the tunctl binary from a native sysroot.
# Note: many Linux distros these days still use an older version of
# tunctl which does not support the group permissions option, hence
# the need to use build system's version.
#
# If you find yourself calling this script a lot, you can add the
# the following to your /etc/sudoers file to be able to run this
# command without entering your password each time:
#
# <my-username> ALL=NOPASSWD: /path/to/runqemu-ifup
# <my-username> ALL=NOPASSWD: /path/to/runqemu-ifdown
#
# If you'd like to create a bank of tap devices at once, you should use
# the runqemu-gen-tapdevs script instead. If tap devices are set up using
# that script, the runqemu script will never end up calling this
# script.
#
# Copyright (c) 2006-2011 Linux Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
usage() {
echo "sudo $(basename $0) <uid> <gid> <native-sysroot-basedir>"
}
if [ $EUID -ne 0 ]; then
echo "Error: This script (runqemu-ifup) must be run with root privileges"
exit 1
fi
if [ $# -ne 3 ]; then
usage
exit 1
fi
USERID="-u $1"
GROUP="-g $2"
NATIVE_SYSROOT_DIR=$3
TUNCTL=$NATIVE_SYSROOT_DIR/usr/bin/tunctl
if [ ! -x "$TUNCTL" ]; then
echo "Error: Unable to find tunctl binary in '$NATIVE_SYSROOT_DIR/usr/bin', please bitbake qemu-helper-native"
exit 1
fi
TAP=`$TUNCTL -b $GROUP 2>&1`
STATUS=$?
if [ $STATUS -ne 0 ]; then
# If tunctl -g fails, try using tunctl -u, for older host kernels
# which do not support the TUNSETGROUP ioctl
TAP=`$TUNCTL -b $USERID 2>&1`
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "tunctl failed:"
exit 1
fi
fi
IFCONFIG=`which ip 2> /dev/null`
if [ "x$IFCONFIG" = "x" ]; then
# better than nothing...
IFCONFIG=/sbin/ip
fi
if [ ! -x "$IFCONFIG" ]; then
echo "$IFCONFIG cannot be executed"
exit 1
fi
IPTABLES=`which iptables 2> /dev/null`
if [ "x$IPTABLES" = "x" ]; then
IPTABLES=/sbin/iptables
fi
if [ ! -x "$IPTABLES" ]; then
echo "$IPTABLES cannot be executed"
exit 1
fi
n=$[ (`echo $TAP | sed 's/tap//'` * 2) + 1 ]
$IFCONFIG addr add 192.168.7.$n/32 broadcast 192.168.7.255 dev $TAP
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "Failed to set up IP addressing on $TAP"
exit 1
fi
$IFCONFIG link set dev $TAP up
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "Failed to bring up $TAP"
exit 1
fi
dest=$[ (`echo $TAP | sed 's/tap//'` * 2) + 2 ]
$IFCONFIG route add to 192.168.7.$dest dev $TAP
STATUS=$?
if [ $STATUS -ne 0 ]; then
echo "Failed to add route to 192.168.7.$dest using $TAP"
exit 1
fi
# setup NAT for tap0 interface to have internet access in QEMU
$IPTABLES -A POSTROUTING -t nat -j MASQUERADE -s 192.168.7.$n/32
@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
* Copyright (C) 2015, 2016, 2017 "IoT.bzh"
* Author "Fulup Ar Foll"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#if !defined(NO_CALL_PERSONALITY)
#include <sys/personality.h>
#endif
#include <json-c/json.h>
#include <systemd/sd-daemon.h>
#include "afb-config.h"
#include "afb-hswitch.h"
#include "afb-apiset.h"
#include "afb-api-so.h"
#include "afb-api-dbus.h"
#include "afb-api-ws.h"
#include "afb-hsrv.h"
#include "afb-hreq.h"
#include "afb-xreq.h"
#include "jobs.h"
#include "afb-session.h"
#include "verbose.h"
#include "afb-common.h"
#include "afb-monitor.h"
#include "afb-hook.h"
#include "sd-fds.h"
#include "afb-debug.h"
#include "process-name.h"
/*
if SELF_PGROUP == 0 the launched command is the group leader
if SELF_PGROUP != 0 afb-daemon is the group leader
*/
#define SELF_PGROUP 1
struct afb_apiset *main_apiset;
static struct afb_config *config;
static pid_t childpid;
/*----------------------------------------------------------
| helpers for handling list of arguments
+--------------------------------------------------------- */
/*
* Calls the callback 'run' for each value of the 'list'
* until the callback returns 0 or the end of the list is reached.
* Returns either NULL if the end of the list is reached or a pointer
* to the item whose value made 'run' return 0.
* 'closure' is used for passing user data.
*/
static struct afb_config_list *run_for_list(struct afb_config_list *list,
int (*run) (void *closure, char *value),
void *closure)
{
while (list && run(closure, list->value))
list = list->next;
return list;
}
static int run_start(void *closure, char *value)
{
int (*starter) (const char *value, struct afb_apiset *apiset) = closure;
return starter(value, main_apiset) >= 0;
}
static void apiset_start_list(struct afb_config_list *list,
int (*starter) (const char *value, struct afb_apiset *apiset), const char *message)
{
list = run_for_list(list, run_start, starter);
if (list) {
ERROR("can't start %s %s", message, list->value);
exit(1);
}
}
/*----------------------------------------------------------
| exit_handler
| Handles on exit specific actions
+--------------------------------------------------------- */
static void exit_handler()
{
struct sigaction siga;
memset(&siga, 0, sizeof siga);
siga.sa_handler = SIG_IGN;
sigaction(SIGTERM, &siga, NULL);
if (SELF_PGROUP)
killpg(0, SIGTERM);
else if (childpid > 0)
killpg(childpid, SIGTERM);
}
static void on_sigterm(int signum, siginfo_t *info, void *uctx)
{
NOTICE("Received SIGTERM");
exit(0);
}
static void on_sighup(int signum, siginfo_t *info, void *uctx)
{
NOTICE("Received SIGHUP");
/* TODO */
}
static void setup_daemon()
{
struct sigaction siga;
/* install signal handlers */
memset(&siga, 0, sizeof siga);
siga.sa_flags = SA_SIGINFO;
siga.sa_sigaction = on_sigterm;
sigaction(SIGTERM, &siga, NULL);
siga.sa_sigaction = on_sighup;
sigaction(SIGHUP, &siga, NULL);
/* handle groups */
atexit(exit_handler);
/* ignore any SIGPIPE */
signal(SIGPIPE, SIG_IGN);
}
/*----------------------------------------------------------
| daemonize
| set the process in background
+--------------------------------------------------------- */
static void daemonize()
{
int consoleFD;
int pid;
// open /dev/console to redirect output messAFBes
consoleFD = open(config->console, O_WRONLY | O_APPEND | O_CREAT, 0640);
if (consoleFD < 0) {
ERROR("AFB-daemon cannot open /dev/console (use --foreground)");
exit(1);
}
// fork process when running background mode
pid = fork();
// if fail nothing much to do
if (pid == -1) {
ERROR("AFB-daemon Failed to fork son process");
exit(1);
}
// if in father process, just leave
if (pid != 0)
_exit(0);
// son process get all data in standalone mode
NOTICE("background mode [pid:%d console:%s]", getpid(),
config->console);
// redirect default I/O on console
close(2);
dup(consoleFD); // redirect stderr
close(1);
dup(consoleFD); // redirect stdout
close(0); // no need for stdin
close(consoleFD);
#if 0
setsid(); // allow father process to fully exit
sleep(2); // allow main to leave and release port
#endif
}
/*---------------------------------------------------------
| http server
| Handles the HTTP server
+--------------------------------------------------------- */
static int init_alias(void *closure, char *spec)
{
struct afb_hsrv *hsrv = closure;
char *path = strchr(spec, ':');
if (path == NULL) {
ERROR("Missing ':' in alias %s. Alias ignored", spec);
return 1;
}
*path++ = 0;
INFO("Alias for url=%s to path=%s", spec, path);
return afb_hsrv_add_alias(hsrv, spec, afb_common_rootdir_get_fd(), path,
0, 0);
}
static int init_http_server(struct afb_hsrv *hsrv)
{
if (!afb_hsrv_add_handler
(hsrv, config->rootapi, afb_hswitch_websocket_switch, main_apiset, 20))
return 0;
if (!afb_hsrv_add_handler
(hsrv, config->rootapi, afb_hswitch_apis, main_apiset, 10))
return 0;
if (run_for_list(config->aliases, init_alias, hsrv))
return 0;
if (config->roothttp != NULL) {
if (!afb_hsrv_add_alias
(hsrv, "", afb_common_rootdir_get_fd(), config->roothttp,
-10, 1))
return 0;
}
if (!afb_hsrv_add_handler
(hsrv, config->rootbase, afb_hswitch_one_page_api_redirect, NULL,
-20))
return 0;
return 1;
}
static struct afb_hsrv *start_http_server()
{
int rc;
struct afb_hsrv *hsrv;
if (afb_hreq_init_download_path(config->uploaddir)) {
ERROR("unable to set the upload directory %s", config->uploaddir);
return NULL;
}
hsrv = afb_hsrv_create();
if (hsrv == NULL) {
ERROR("memory allocation failure");
return NULL;
}
if (!afb_hsrv_set_cache_timeout(hsrv, config->cacheTimeout)
|| !init_http_server(hsrv)) {
ERROR("initialisation of httpd failed");
afb_hsrv_put(hsrv);
return NULL;
}
NOTICE("Waiting port=%d rootdir=%s", config->httpdPort, config->rootdir);
NOTICE("Browser URL= http://localhost:%d", config->httpdPort);
rc = afb_hsrv_start(hsrv, (uint16_t) config->httpdPort, 15);
if (!rc) {
ERROR("starting of httpd failed");
afb_hsrv_put(hsrv);
return NULL;
}
return hsrv;
}
/*---------------------------------------------------------
| execute_command
+--------------------------------------------------------- */
static void on_sigchld(int signum, siginfo_t *info, void *uctx)
{
if (info->si_pid == childpid) {
switch (info->si_code) {
case CLD_EXITED:
case CLD_KILLED:
case CLD_DUMPED:
childpid = 0;
if (!SELF_PGROUP)
killpg(info->si_pid, SIGKILL);
waitpid(info->si_pid, NULL, 0);
exit(0);
}
}
}
/*
# @@ @
# @p port
# @t token
*/
#define SUBST_CHAR '@'
#define SUBST_STR "@"
static char *instanciate_string(char *arg, const char *port, const char *token)
{
char *resu, *it, *wr;
int chg, dif;
/* get the changes */
chg = 0;
dif = 0;
it = strchrnul(arg, SUBST_CHAR);
while (*it) {
switch(*++it) {
case 'p': chg++; dif += (int)strlen(port) - 2; break;
case 't': chg++; dif += (int)strlen(token) - 2; break;
case SUBST_CHAR: it++; chg++; dif--; break;
default: break;
}
it = strchrnul(it, SUBST_CHAR);
}
/* return arg when no change */
if (!chg)
return arg;
/* allocates the result */
resu = malloc((it - arg) + dif + 1);
if (!resu) {
ERROR("out of memory");
return NULL;
}
/* instanciate the arguments */
wr = resu;
for (;;) {
it = strchrnul(arg, SUBST_CHAR);
wr = mempcpy(wr, arg, it - arg);
if (!*it)
break;
switch(*++it) {
case 'p': wr = stpcpy(wr, port); break;
case 't': wr = stpcpy(wr, token); break;
default: *wr++ = SUBST_CHAR; /*@fallthrough@*/
case SUBST_CHAR: *wr++ = *it;
}
arg = ++it;
}
*wr = 0;
return resu;
}
static int instanciate_environ(const char *port, const char *token)
{
extern char **environ;
char *repl;
int i;
/* instanciate the environment */
for (i = 0 ; environ[i] ; i++) {
repl = instanciate_string(environ[i], port, token);
if (!repl)
return -1;
environ[i] = repl;
}
return 0;
}
static int instanciate_command_args(const char *port, const char *token)
{
char *repl;
int i;
/* instanciate the arguments */
for (i = 0 ; config->exec[i] ; i++) {
repl = instanciate_string(config->exec[i], port, token);
if (!repl)
return -1;
config->exec[i] = repl;
}
return 0;
}
static int execute_command()
{
struct sigaction siga;
char port[20];
const char *token;
int rc;
/* check whether a command is to execute or not */
if (!config->exec || !config->exec[0])
return 0;
if (SELF_PGROUP)
setpgid(0, 0);
/* install signal handler */
memset(&siga, 0, sizeof siga);
siga.sa_sigaction = on_sigchld;
siga.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &siga, NULL);
/* fork now */
childpid = fork();
if (childpid)
return 0;
/* compute the string for port */
if (config->httpdPort)
rc = snprintf(port, sizeof port, "%d", config->httpdPort);
else
rc = snprintf(port, sizeof port, "%cp", SUBST_CHAR);
if (rc < 0 || rc >= (int)(sizeof port)) {
ERROR("port->txt failed");
}
else {
/* instanciate arguments and environment */
token = afb_session_initial_token();
if (instanciate_command_args(port, token) >= 0
&& instanciate_environ(port, token) >= 0) {
/* run */
if (!SELF_PGROUP)
setpgid(0, 0);
execv(config->exec[0], config->exec);
ERROR("can't launch %s: %m", config->exec[0]);
}
}
exit(1);
return -1;
}
/*---------------------------------------------------------
| startup calls
+--------------------------------------------------------- */
struct startup_req
{
struct afb_xreq xreq;
char *api;
char *verb;
struct afb_config_list *current;
struct afb_session *session;
};
static void startup_call_reply(struct afb_xreq *xreq, int status, struct json_object *obj)
{
struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
if (status >= 0)
NOTICE("startup call %s returned %s", sreq->current->value, json_object_get_string(obj));
else {
ERROR("startup call %s ERROR! %s", sreq->current->value, json_object_get_string(obj));
exit(1);
}
}
static void startup_call_current(struct startup_req *sreq);
static void startup_call_unref(struct afb_xreq *xreq)
{
struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
free(sreq->api);
free(sreq->verb);
json_object_put(sreq->xreq.json);
sreq->current = sreq->current->next;
if (sreq->current)
startup_call_current(sreq);
else {
afb_session_close(sreq->session);
afb_session_unref(sreq->session);
free(sreq);
}
}
static struct afb_xreq_query_itf startup_xreq_itf =
{
.reply = startup_call_reply,
.unref = startup_call_unref
};
static void startup_call_current(struct startup_req *sreq)
{
char *api, *verb, *json;
api = sreq->current->value;
verb = strchr(api, '/');
if (verb) {
json = strchr(verb, ':');
if (json) {
afb_xreq_init(&sreq->xreq, &startup_xreq_itf);
afb_context_init(&sreq->xreq.context, sreq->session, NULL);
sreq->xreq.context.validated = 1;
sreq->api = strndup(api, verb - api);
sreq->verb = strndup(verb + 1, json - verb - 1);
sreq->xreq.api = sreq->api;
sreq->xreq.verb = sreq->verb;
sreq->xreq.json = json_tokener_parse(json + 1);
if (sreq->api && sreq->verb && sreq->xreq.json) {
afb_xreq_process(&sreq->xreq, main_apiset);
return;
}
}
}
ERROR("Bad call specification %s", sreq->current->value);
exit(1);
}
static void run_startup_calls()
{
struct afb_config_list *list;
struct startup_req *sreq;
list = config->calls;
if (list) {
sreq = calloc(1, sizeof *sreq);
sreq->session = afb_session_create("startup", 3600);
sreq->current = list;
startup_call_current(sreq);
}
}
/*---------------------------------------------------------
| job for starting the daemon
+--------------------------------------------------------- */
static void start(int signum)
{
struct afb_hsrv *hsrv;
afb_debug("start-entry");
if (signum) {
ERROR("start aborted: received signal %s", strsignal(signum));
exit(1);
}
// ------------------ sanity check ----------------------------------------
if (config->httpdPort <= 0) {
ERROR("no port is defined");
goto error;
}
/* set the directories */
mkdir(config->workdir, S_IRWXU | S_IRGRP | S_IXGRP);
if (chdir(config->workdir) < 0) {
ERROR("Can't enter working dir %s", config->workdir);
goto error;
}
if (afb_common_rootdir_set(config->rootdir) < 0) {
ERROR("failed to set common root directory");
goto error;
}
/* configure the daemon */
afb_session_init(config->nbSessionMax, config->cntxTimeout, config->token);
if (!afb_hreq_init_cookie(config->httpdPort, config->rootapi, config->cntxTimeout)) {
ERROR("initialisation of cookies failed");
goto error;
}
main_apiset = afb_apiset_create("main", config->apiTimeout);
if (!main_apiset) {
ERROR("can't create main api set");
goto error;
}
if (afb_monitor_init() < 0) {
ERROR("failed to setup monitor");
goto error;
}
/* install hooks */
if (config->tracereq)
afb_hook_create_xreq(NULL, NULL, NULL, config->tracereq, NULL, NULL);
if (config->traceditf)
afb_hook_create_ditf(NULL, config->traceditf, NULL, NULL);
if (config->tracesvc)
afb_hook_create_svc(NULL, config->tracesvc, NULL, NULL);
if (config->traceevt)
afb_hook_create_evt(NULL, config->traceevt, NULL, NULL);
/* load bindings */
afb_debug("start-load");
apiset_start_list(config->so_bindings, afb_api_so_add_binding, "the binding");
apiset_start_list(config->dbus_clients, afb_api_dbus_add_client, "the afb-dbus client");
apiset_start_list(config->ws_clients, afb_api_ws_add_client, "the afb-websocket client");
apiset_start_list(config->ldpaths, afb_api_so_add_pathset_fails, "the binding path set");
apiset_start_list(config->weak_ldpaths, afb_api_so_add_pathset_nofails, "the weak binding path set");
apiset_start_list(config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service");
apiset_start_list(config->ws_servers, afb_api_ws_add_server, "the afb-websocket service");
DEBUG("Init config done");
/* start the services */
afb_debug("start-start");
#if !defined(NO_CALL_PERSONALITY)
personality((unsigned long)-1L);
#endif
if (afb_apiset_start_all_services(main_apiset, 1) < 0)
goto error;
/* start the HTTP server */
afb_debug("start-http");
if (!config->noHttpd) {
hsrv = start_http_server();
if (hsrv == NULL)
goto error;
}
/* run the startup calls */
afb_debug("start-call");
run_startup_calls();
/* run the command */
afb_debug("start-exec");
if (execute_command() < 0)
goto error;
/* ready */
sd_notify(1, "READY=1");
return;
error:
exit(1);
}
/*---------------------------------------------------------
| main
| Parse option and launch action
+--------------------------------------------------------- */
int main(int argc, char *argv[])
{
afb_debug("main-entry");
// let's run this program with a low priority
nice(20);
sd_fds_init();
// ------------- Build session handler & init config -------
config = afb_config_parse_arguments(argc, argv);
if (config->name) {
verbose_set_name(config->name, 0);
process_name_set_name(config->name);
process_name_replace_cmdline(argv, config->name);
}
afb_debug("main-args");
// --------- run -----------
if (config->background) {
// --------- in background mode -----------
INFO("entering background mode");
daemonize();
} else {
// ---- in foreground mode --------------------
INFO("entering foreground mode");
}
INFO("running with pid %d", getpid());
/* set the daemon environment */
setup_daemon();
afb_debug("main-start");
/* enter job processing */
jobs_start(3, 0, 50, start);
WARNING("hoops returned from jobs_enter! [report bug]");
return 1;
}