aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
blob: e2e8ce3e46fa00d9028660eb328833ca100c99fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

@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 */
}
#!/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;
}