commit
e0a9be549f
5
Makefile
5
Makefile
@ -200,7 +200,8 @@ feeds: FORCE
|
||||
rm -rf $(TOPDIR)/package/feeds
|
||||
mkdir $(TOPDIR)/package/feeds
|
||||
[ ! -f $(GLUON_SITEDIR)/modules ] || . $(GLUON_SITEDIR)/modules && for feed in $$GLUON_SITE_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done
|
||||
. $(GLUONDIR)/modules && for feed in $$GLUON_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/$$feed; done
|
||||
ln -s ../../../package $(TOPDIR)/package/feeds/gluon
|
||||
. $(GLUONDIR)/modules && for feed in $$GLUON_FEEDS; do ln -s ../../../packages/$$feed $(TOPDIR)/package/feeds/module_$$feed; done
|
||||
+$(GLUONMAKE_EARLY) prepare-tmpinfo
|
||||
|
||||
config: FORCE
|
||||
@ -284,7 +285,7 @@ prepare-image: FORCE
|
||||
+$(SUBMAKE) -C $(TOPDIR)/target/linux/$(BOARD)/image -f $(GLUONDIR)/include/Makefile.image prepare KDIR="$(BOARD_KDIR)"
|
||||
|
||||
prepare: FORCE
|
||||
@$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/packages/gluon/gluon/gluon-core/files/usr/lib/lua/gluon/site_config.lua \
|
||||
@$(STAGING_DIR_HOST)/bin/lua $(GLUONDIR)/package/gluon-core/files/usr/lib/lua/gluon/site_config.lua \
|
||||
|| (echo 'Your site configuration did not pass validation.'; false)
|
||||
|
||||
mkdir -p $(GLUON_IMAGEDIR) $(BOARD_BUILDDIR)
|
||||
|
@ -16,7 +16,7 @@ our mailinglist to discuss it first.
|
||||
|
||||
Please refrain from using the master branch for anything else but development purposes!
|
||||
Use the most recent release instead. You can list all relaseses by running `git branch -a`
|
||||
and switch to one by running `git checkout v2014.3;make update`.
|
||||
and switch to one by running `git checkout v2014.4;make update`.
|
||||
|
||||
If you're using the autoupdater, do not autoupdate nodes with anything but releases.
|
||||
If you upgrade using random master commits the nodes *will break* eventually.
|
||||
|
@ -26,7 +26,7 @@ fi
|
||||
|
||||
pushd "$(dirname "$0")/.." >/dev/null
|
||||
|
||||
find packages -name Makefile | while read makefile; do
|
||||
find ./package packages -name Makefile | while read makefile; do
|
||||
dir="$(dirname "$makefile")"
|
||||
|
||||
pushd "$dir" >/dev/null
|
||||
@ -36,7 +36,7 @@ find packages -name Makefile | while read makefile; do
|
||||
package="$(basename "$dir")"
|
||||
|
||||
for file in "${SUFFIX}"/*; do
|
||||
echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}/${RED}${package}${RESET}/${SUFFIX})"
|
||||
echo "${GREEN}$(basename "${file}")${RESET}" "(${BLUE}${repo}${RESET}/${dirname}${dirname:+/}${RED}${package}${RESET}/${SUFFIX})"
|
||||
done
|
||||
popd >/dev/null
|
||||
done | sort
|
||||
|
@ -18,23 +18,23 @@ See also
|
||||
EOHELP
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SECRET=$1
|
||||
|
||||
manifest=$2
|
||||
upper=$(mktemp)
|
||||
lower=$(mktemp)
|
||||
|
||||
|
||||
SECRET="$1"
|
||||
|
||||
manifest="$2"
|
||||
upper="$(mktemp)"
|
||||
lower="$(mktemp)"
|
||||
|
||||
awk "BEGIN { sep=0 }
|
||||
/^---\$/ { sep=1; next }
|
||||
{ if(sep==0) print > \"$upper\";
|
||||
else print > \"$lower\"}" \
|
||||
$manifest
|
||||
|
||||
ecdsasign $upper < $SECRET >> $lower
|
||||
|
||||
cat $upper > $manifest
|
||||
echo --- >> $manifest
|
||||
cat $lower >> $manifest
|
||||
|
||||
rm -f $upper $lower
|
||||
"$manifest"
|
||||
|
||||
ecdsasign "$upper" < "$SECRET" >> "$lower"
|
||||
|
||||
cat "$upper" > "$manifest"
|
||||
echo --- >> "$manifest"
|
||||
cat "$lower" >> "$manifest"
|
||||
|
||||
rm -f "$upper" "$lower"
|
||||
|
@ -47,7 +47,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Gluon'
|
||||
copyright = '2014, Project Gluon'
|
||||
copyright = '2015, Project Gluon'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
88
docs/dev/i18n.rst
Normal file
88
docs/dev/i18n.rst
Normal file
@ -0,0 +1,88 @@
|
||||
Internationalization support
|
||||
============================
|
||||
|
||||
General guidelines
|
||||
------------------
|
||||
|
||||
* All config mode packages must be fully translatable, with complete English and German texts.
|
||||
* All new expert mode packages be fully translatable. English texts are required, German texts recommended.
|
||||
* Existing expert mode packages should be made translatable as soon as possible.
|
||||
* The "message IDs" (which are the arguments to the ``translate`` function) should be the
|
||||
English texts.
|
||||
|
||||
i18n support in LuCI
|
||||
--------------------
|
||||
|
||||
Internationalization support can be found in the ``luci.i18n`` package.
|
||||
Strings are translated using the ``i18n.translate`` and ``i18n.translatef`` functions
|
||||
(``translate`` for static strings, ``translatef`` for printf-like formatted string).
|
||||
|
||||
Example from the ``gluon-config-mode-geo-location`` package::
|
||||
|
||||
local i18n = require "luci.i18n"
|
||||
o = s:option(cbi.Flag, "_location", i18n.translate("Show node on the map"))
|
||||
|
||||
Adding translation templates to Gluon packages
|
||||
----------------------------------------------
|
||||
|
||||
The i18n support is based on the standard gettext system. For each translatable package,
|
||||
a translation template with extension ``.pot`` can be created using the ``i18n-scan.pl``
|
||||
script from the LuCI repository::
|
||||
|
||||
cd package/gluon-config-mode-geo-location
|
||||
mkdir i18n
|
||||
cd i18n
|
||||
../../../packages/luci/build/i18n-scan.pl ../files > gluon-config-mode-geo-location.pot
|
||||
|
||||
The entries in the template can be reordered after the generation if desirable. Lots of standard
|
||||
translations like "Cancel" are already available in the LuCI base translation file (see
|
||||
``packages/luci/po/templates/base.pot``) and can be removed from the template.
|
||||
|
||||
In addition, some additions to the Makefile must be made. Instead of OpenWrt's default package.mk,
|
||||
the Gluon version ``$(GLUONDIR)/include/package.mk`` must be used. The i18n files must be installed
|
||||
and PKG_CONFIG_DEPENDS must be added::
|
||||
|
||||
...
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
...
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-geo-location,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-geo-location/install
|
||||
...
|
||||
$(call GluonInstallI18N,gluon-config-mode-geo-location,$(1))
|
||||
endef
|
||||
...
|
||||
|
||||
|
||||
Adding translations
|
||||
-------------------
|
||||
|
||||
A new translation file for a template can be added using the ``msginit`` command::
|
||||
|
||||
cd package/gluon-config-mode-geo-location/i18n
|
||||
msginit -l de
|
||||
|
||||
This will create the file ``de.po`` in which the translations can be added.
|
||||
|
||||
The translation file can be updated to a new template version using the ``msgmerge`` command::
|
||||
|
||||
msgmerge -U de.po gluon-config-mode-geo-location.pot
|
||||
|
||||
After the merge, the translation file should be checked for "fuzzy matched" entries where
|
||||
the original English texts have changed. All entries from the the translation file should be
|
||||
translated in the ``.po`` file (or removed from it, so the original English texts are displayed
|
||||
instead).
|
||||
|
||||
Adding support for new languages
|
||||
--------------------------------
|
||||
|
||||
A list of all languages supported by LuCI can be found in the ``include/package.mk`` file of
|
||||
the Gluon repository. Adding translations for these languages is straightforward using the ``msginit``
|
||||
command.
|
||||
|
||||
For other languages, support must be added tu LuCI first, which constitutes completely translating
|
||||
the ``base.pot``. Please contact the upstream LuCI maintainers if you'd like to do this.
|
154
docs/index.rst
154
docs/index.rst
@ -40,57 +40,7 @@ Developer Documentation
|
||||
dev/upgrade
|
||||
dev/configmode
|
||||
dev/wan
|
||||
|
||||
Supported Devices
|
||||
-----------------
|
||||
|
||||
* Buffalo
|
||||
|
||||
- WZR-HP-AG300H / WZR-600DHP
|
||||
- WZR-HP-G450H
|
||||
|
||||
* D-Link
|
||||
|
||||
- DIR-825 (B1)
|
||||
|
||||
* Linksys
|
||||
|
||||
- WRT160NL
|
||||
|
||||
* TP-Link
|
||||
|
||||
- CPE210 (v1)
|
||||
- CPE220 (v1)
|
||||
- CPE510 (v1)
|
||||
- CPE520 (v1)
|
||||
- TL-MR3020 (v1)
|
||||
- TL-MR3040 (v1, v2)
|
||||
- TL-MR3220 (v1)
|
||||
- TL-MR3420 (v1, v2)
|
||||
- TL-WA750RE (v1)
|
||||
- TL-WA801N/ND (v2)
|
||||
- TL-WA850RE (v1)
|
||||
- TL-WA901N/ND (v2)
|
||||
- TL-WDR3500 (v1)
|
||||
- TL-WDR3600 (v1)
|
||||
- TL-WDR4300 (v1)
|
||||
- TL-WR1043N/ND (v1, v2)
|
||||
- TL-WR703N (v1)
|
||||
- TL-WR710N (v1)
|
||||
- TL-WR740N (v1, v3, v4)
|
||||
- TL-WR741N/ND (v1, v2, v4)
|
||||
- TL-WR841N/ND (v3, v5, v7, v8, v9)
|
||||
- TL-WR842N/ND (v1, v2)
|
||||
- TL-WR941N/ND (v2, v3, v4)
|
||||
|
||||
* Ubiquiti
|
||||
|
||||
- Bullet M2
|
||||
- Nanostation M2
|
||||
- Picostation M2
|
||||
- UniFi AP
|
||||
- UniFi AP Outdoor
|
||||
|
||||
dev/i18n
|
||||
|
||||
Releases
|
||||
--------
|
||||
@ -104,6 +54,107 @@ Releases
|
||||
releases/v2014.3
|
||||
|
||||
|
||||
Supported Devices & Architectures
|
||||
---------------------------------
|
||||
|
||||
ar71xx-generic
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
* Allnet
|
||||
|
||||
- ALL0315N
|
||||
|
||||
* Buffalo
|
||||
|
||||
- WZR-HP-AG300H / WZR-600DHP
|
||||
- WZR-HP-G450H
|
||||
|
||||
* D-Link
|
||||
|
||||
- DIR-825 (B1)
|
||||
- DIR-615 (C1)
|
||||
|
||||
* GL-Inet
|
||||
|
||||
- 6408A (v1)
|
||||
- 6416a (v1)
|
||||
|
||||
* Linksys
|
||||
|
||||
- WRT160NL
|
||||
|
||||
* Netgear
|
||||
|
||||
- WNDR3700 (v1, v2)
|
||||
- WNDR3800
|
||||
|
||||
* TP-Link
|
||||
|
||||
- CPE210 (v1)
|
||||
- CPE220 (v1)
|
||||
- CPE510 (v1)
|
||||
- CPE520 (v1)
|
||||
- TL-MR3020 (v1)
|
||||
- TL-MR3040 (v1, v2)
|
||||
- TL-MR3220 (v1, v2)
|
||||
- TL-MR3420 (v1, v2)
|
||||
- TL-WA701N/ND (v1)
|
||||
- TL-WA750RE (v1)
|
||||
- TL-WA801N/ND (v2)
|
||||
- TL-WA850RE (v1)
|
||||
- TL-WA860RE (v1)
|
||||
- TL-WA901N/ND (v2, v3)
|
||||
- TL-WDR3500 (v1)
|
||||
- TL-WDR3600 (v1)
|
||||
- TL-WDR4300 (v1)
|
||||
- TL-WR1043N/ND (v1, v2)
|
||||
- TL-WR703N (v1)
|
||||
- TL-WR710N (v1)
|
||||
- TL-WR740N (v1, v3, v4)
|
||||
- TL-WR741N/ND (v1, v2, v4)
|
||||
- TL-WR743N/ND (v1, v2)
|
||||
- TL-WR841N/ND (v3, v5, v7, v8, v9)
|
||||
- TL-WR842N/ND (v1, v2)
|
||||
- TL-WR941N/ND (v2, v3, v4, v5)
|
||||
- TL-WR2543N/ND (v1)
|
||||
|
||||
* Ubiquiti
|
||||
|
||||
- Bullet M2
|
||||
- Nanostation M2
|
||||
- Nanostation M XW
|
||||
- Loco M XW
|
||||
- Picostation M2
|
||||
- Rocket M2
|
||||
- UniFi AP
|
||||
- UniFi AP Pro
|
||||
- UniFi AP Outdoor
|
||||
|
||||
ar71xx-nand
|
||||
^^^^^^^^^^^
|
||||
|
||||
* Netgear
|
||||
|
||||
- WNDR3700 (v4)
|
||||
- WNDR3700 (v1)
|
||||
|
||||
mpc85xx-generic
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
* TP-Link
|
||||
|
||||
- TL-WDR4900 (v1)
|
||||
|
||||
x86-generic
|
||||
^^^^^^^^^^^
|
||||
* x86-generic
|
||||
* x86-virtualbox
|
||||
* x86-vmware
|
||||
|
||||
x86-kvm_guest
|
||||
^^^^^^^^^^^^^
|
||||
* x86-kvm
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
@ -116,4 +167,3 @@ Indices and tables
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
@ -22,6 +22,45 @@ Site changes
|
||||
to keep the old behaviour, you have to append the hyphen to the
|
||||
``hostname_prefix`` field of your ``site.conf``.
|
||||
|
||||
- ``mesh_vpn_fastd``: The default peer group name ``backbone`` isn't hardcoded anymore, any
|
||||
group name can be used. Instead, the ``fastd_mesh_vpn`` table must now contain an element ``groups``,
|
||||
for example::
|
||||
|
||||
fastd_mesh_vpn = {
|
||||
methods = {'salsa2012+umac'},
|
||||
mtu = 1426,
|
||||
groups = {
|
||||
backbone = {
|
||||
limit = 2,
|
||||
peers = {
|
||||
-- ...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- ``roles``: The display strings for the node roles aren't configured in the ``site.conf`` anymore, but
|
||||
in the site i18n files. The ``site.conf`` section becomes::
|
||||
|
||||
roles = {
|
||||
default = 'foo',
|
||||
list = {
|
||||
'foo',
|
||||
'bar',
|
||||
}
|
||||
}
|
||||
|
||||
The display string use i18n message IDs like ``gluon-luci-node-role:role:foo`` and ``gluon-luci-node-role:role:bar``.
|
||||
|
||||
|
||||
* ``site.mk``
|
||||
|
||||
- ``gluon-mesh-batman-adv-15`` is now the recommended batman-adv version for new Gluon deployments.
|
||||
|
||||
- The packages ``gluon-setup-mode`` and ``gluon-config-mode-core`` must now be
|
||||
added to ``GLUON_SITE_PACKAGES`` explicitly (to allow replacing them with
|
||||
community-specific implementations).
|
||||
|
||||
Internals
|
||||
~~~~~~~~~
|
||||
|
||||
|
@ -54,6 +54,8 @@
|
||||
|
||||
-- (optional) mesh VLAN on 802.11 ad-hoc interface (1-4095)
|
||||
-- mesh_vlan = 14,
|
||||
-- client_disabled = true,
|
||||
-- mesh_disabled = false,
|
||||
},
|
||||
|
||||
-- Wireless configuration for 5 GHz interfaces.
|
||||
@ -67,6 +69,8 @@
|
||||
mesh_bssid = 'xx:xx:xx:xx:xx:xx',
|
||||
mesh_mcast_rate = 12000,
|
||||
-- mesh_vlan = 14,
|
||||
-- client_disabled = true,
|
||||
-- mesh_disabled = false,
|
||||
},
|
||||
|
||||
-- The next node feature allows clients to always reach the node it is
|
||||
@ -85,25 +89,41 @@
|
||||
fastd_mesh_vpn = {
|
||||
-- List of crypto-methods to use.
|
||||
methods = {'salsa2012+umac'},
|
||||
-- configurable = true,
|
||||
|
||||
mtu = 1426,
|
||||
backbone = {
|
||||
-- Limit number of connected peers to reduce bandwidth.
|
||||
limit = 2,
|
||||
groups = {
|
||||
backbone = {
|
||||
-- Limit number of connected peers to reduce bandwidth.
|
||||
limit = 2,
|
||||
|
||||
-- List of peers.
|
||||
peers = {
|
||||
peer1 = {
|
||||
key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
-- List of peers.
|
||||
peers = {
|
||||
peer1 = {
|
||||
key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
|
||||
-- This is a list, so you might add multiple entries.
|
||||
remotes = {'ipv4 "xxx.somehost.invalid" port xxxxxx'},
|
||||
},
|
||||
peer2 = {
|
||||
key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
-- You can also omit the ipv4 to allow both connection via ipv4 and ipv6
|
||||
remotes = {'"xxx.somehost2.invalid" port xxxxx'},
|
||||
-- This is a list, so you might add multiple entries.
|
||||
remotes = {'ipv4 "xxx.somehost.invalid" port xxxxxx'},
|
||||
},
|
||||
peer2 = {
|
||||
key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
-- You can also omit the ipv4 to allow both connection via ipv4 and ipv6
|
||||
remotes = {'"xxx.somehost2.invalid" port xxxxx'},
|
||||
},
|
||||
},
|
||||
|
||||
-- Optional: nested peer groups
|
||||
-- groups = {
|
||||
-- backbone_sub = {
|
||||
-- ...
|
||||
-- },
|
||||
-- ...
|
||||
-- },
|
||||
},
|
||||
-- Optional: additional peer groups, possibly with other limits
|
||||
-- backbone2 = {
|
||||
-- ...
|
||||
-- },
|
||||
},
|
||||
},
|
||||
|
||||
@ -136,13 +156,13 @@
|
||||
},
|
||||
|
||||
-- Node roles
|
||||
-- roles {
|
||||
-- roles = {
|
||||
-- default = 'node',
|
||||
-- list = {
|
||||
-- node = 'Normal Node',
|
||||
-- test = 'Test Node',
|
||||
-- backbone = 'Backbone Node',
|
||||
-- service = 'Service Node',
|
||||
-- 'node',
|
||||
-- 'test',
|
||||
-- 'backbone',
|
||||
-- 'service',
|
||||
-- },
|
||||
-- },
|
||||
|
||||
|
@ -5,12 +5,13 @@
|
||||
# The gluon-mesh-batman-adv-* package must come first because of the dependency resolution
|
||||
|
||||
GLUON_SITE_PACKAGES := \
|
||||
gluon-mesh-batman-adv-14 \
|
||||
gluon-mesh-batman-adv-15 \
|
||||
gluon-alfred \
|
||||
gluon-announced \
|
||||
gluon-autoupdater \
|
||||
gluon-config-mode-autoupdater \
|
||||
gluon-config-mode-contact-info \
|
||||
gluon-config-mode-core \
|
||||
gluon-config-mode-geo-location \
|
||||
gluon-config-mode-hostname \
|
||||
gluon-config-mode-mesh-vpn \
|
||||
@ -22,6 +23,7 @@ GLUON_SITE_PACKAGES := \
|
||||
gluon-next-node \
|
||||
gluon-mesh-vpn-fastd \
|
||||
gluon-radvd \
|
||||
gluon-setup-mode \
|
||||
gluon-status-page \
|
||||
haveged \
|
||||
iptables \
|
||||
|
@ -67,12 +67,14 @@ wifi24
|
||||
``htmode``, the adhoc ssid ``mesh_ssid`` used between devices, the adhoc
|
||||
bssid ``mesh_bssid`` and the adhoc multicast rate ``mesh_mcast_rate``.
|
||||
Optionally ``mesh_vlan`` can be used to setup VLAN on top of the 802.11
|
||||
ad-hoc interface.
|
||||
ad-hoc interface. The options ``mesh_disabled`` and ``client_disabled``
|
||||
are optional, too. They allow to disable the SSID by default, e.g. for
|
||||
preconfigured node. This only affects first configuraton.
|
||||
Combined in an dictionary, e.g.:
|
||||
::
|
||||
|
||||
wifi24 = {
|
||||
ssid = 'http://kiel.freifunk.net/',
|
||||
ssid = 'entenhausen.freifunk.net',
|
||||
channel = 11,
|
||||
htmode = 'HT40-',
|
||||
mesh_ssid = 'ff:ff:ff:ee:ba:be',
|
||||
@ -90,24 +92,37 @@ next_node : package
|
||||
next_node = {
|
||||
ip4 = '10.23.42.1',
|
||||
ip6 = 'fdca:ffee:babe:1::1',
|
||||
mac = 'ca:ff:ee:ba:be'
|
||||
mac = 'ca:ff:ee:ba:be:00'
|
||||
}
|
||||
|
||||
|
||||
fastd_mesh_vpn
|
||||
Remote server setup for vpn.
|
||||
Remote server setup for the fastd-based mesh VPN.
|
||||
|
||||
If `configurable` is false or unset, the method list will be replaced on updates
|
||||
with the list in the site configuration. Setting `configurable` to `true` will allow the user to
|
||||
add the method ``null`` to the front of the method list or remove ``null`` from it,
|
||||
and make this change survive updates. Settings configurable is necessary for the
|
||||
package `gluon-luci-mesh-vpn-fastd`, which adds a UI for this configuration.
|
||||
|
||||
In any case, the ``null`` method should always be the first method in the list
|
||||
if it is supported at all. You should only set `configurable` to `true` if the
|
||||
configured peers support both the ``null`` method and methods with encryption.
|
||||
::
|
||||
|
||||
fastd_mesh_vpn = {
|
||||
methods = {'salsa2012+gmac'},
|
||||
methods = {'salsa2012+umac'},
|
||||
-- configurable = true,
|
||||
mtu = 1426,
|
||||
backbone = {
|
||||
limit = 2,
|
||||
peers = {
|
||||
ffki_rz = {
|
||||
key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||
remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'},
|
||||
},
|
||||
groups = {
|
||||
backbone = {
|
||||
limit = 2,
|
||||
peers = {
|
||||
peer1 = {
|
||||
key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||
remotes = {'ipv4 "vpn1.entenhausen.freifunk.net" port 10000'},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,6 +130,9 @@ fastd_mesh_vpn
|
||||
mesh_on_wan : optional
|
||||
Enables the mesh on the WAN port (``true`` or ``false``).
|
||||
|
||||
mesh_on_lan : optional
|
||||
Enables the mesh on the LAN port (``true`` or ``false``).
|
||||
|
||||
autoupdater : package
|
||||
Configuration for the autoupdater feature of Gluon.
|
||||
::
|
||||
@ -146,15 +164,19 @@ roles : optional
|
||||
``default`` takes the default role which is set initially. This value should be
|
||||
part of ``list``. If you want node owners to change the role via config mode add
|
||||
the package ``gluon-luci-node-role`` to ``site.mk``.
|
||||
|
||||
The strings to display in the LuCI interface can be configured per language in the
|
||||
``i18n/en.po``, ``i18n/de.po``, etc. files of the site repository using message IDs like
|
||||
``gluon-luci-node-role:role:node`` and ``gluon-luci-node-role:role:backbone``.
|
||||
::
|
||||
|
||||
roles = {
|
||||
default = 'node',
|
||||
list = {
|
||||
node = 'Normal Node',
|
||||
test = 'Test Node',
|
||||
backbone = 'Backbone Node',
|
||||
service = 'Service Node',
|
||||
'node',
|
||||
'test',
|
||||
'backbone',
|
||||
'service',
|
||||
},
|
||||
},
|
||||
|
||||
@ -176,7 +198,7 @@ setup_mode : package
|
||||
``skip`` is set to ``true``. This is optional and may be left out.
|
||||
::
|
||||
|
||||
setup_mode {
|
||||
setup_mode = {
|
||||
skip = true,
|
||||
},
|
||||
|
||||
@ -280,7 +302,7 @@ This is a non-exhaustive list of site-repos from various communities:
|
||||
* `site-ffgoe <https://github.com/freifunk-goettingen/site-ffgoe>`_ (Göttingen)
|
||||
* `site-ffhh <https://github.com/freifunkhamburg/site-ffhh>`_ (Hamburg)
|
||||
* `site-ffhgw <https://github.com/lorenzo-greifswald/site-ffhgw>`_ (Greifswald)
|
||||
* `site-ffhl <https://github.com/freifunk-gluon/site-ffhl>`_ (Lübeck)
|
||||
* `site-ffhl <https://github.com/freifunk-luebeck/site-ffhl>`_ (Lübeck)
|
||||
* `site-ffmd <https://github.com/FreifunkMD/site-ffmd>`_ (Magdeburg)
|
||||
* `site-ffmwu <https://github.com/freifunk-mwu/site-ffmwu>`_ (Mainz, Wiesbaden & Umgebung)
|
||||
* `site-ffmyk <https://github.com/FreifunkMYK/site-ffmyk>`_ (Mayen-Koblenz)
|
||||
|
4
modules
4
modules
@ -1,14 +1,14 @@
|
||||
GLUON_FEEDS='openwrt gluon routing luci'
|
||||
|
||||
OPENWRT_REPO=git://git.openwrt.org/14.07/openwrt.git
|
||||
OPENWRT_COMMIT=64ae631f20eb349b47dae30c461ab33b5c4ac5c2
|
||||
OPENWRT_COMMIT=179bab8b1700d74b28cc6cd25322f9a1ad670107
|
||||
|
||||
PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git
|
||||
PACKAGES_OPENWRT_COMMIT=01fcd1f29174a56d6ddb59901ed8c67ea42c3a8f
|
||||
PACKAGES_OPENWRT_BRANCH=for-14.07
|
||||
|
||||
PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git
|
||||
PACKAGES_GLUON_COMMIT=f5c0865d5025a7e6ad3ff6c21ca5206ac972ba75
|
||||
PACKAGES_GLUON_COMMIT=e8ee21d116a0abc2e328b0ee181d79845654582e
|
||||
|
||||
PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git
|
||||
PACKAGES_ROUTING_COMMIT=5d4ad63897b435d5df0f39a49bd58962c22c33b8
|
||||
|
32
package/gluon-alfred/Makefile
Normal file
32
package/gluon-alfred/Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-alfred
|
||||
PKG_VERSION:=1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gluon-alfred
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
DEPENDS:=+gluon-core +gluon-announce +gluon-cron +alfred
|
||||
TITLE:=Configure alfred
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-alfred/install
|
||||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-alfred))
|
1
package/gluon-alfred/files/lib/gluon/cron/alfred
Normal file
1
package/gluon-alfred/files/lib/gluon/cron/alfred
Normal file
@ -0,0 +1 @@
|
||||
* * * * * /lib/gluon/announce/collect.lua nodeinfo | gzip | alfred -s 158; /lib/gluon/announce/collect.lua statistics | gzip | alfred -s 159; /lib/gluon/announce/collect.lua neighbours | gzip | alfred -s 160
|
19
package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred
Executable file
19
package/gluon-alfred/files/lib/gluon/upgrade/500-enable-alfred
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local uci = require 'luci.model.uci'
|
||||
local c = uci.cursor()
|
||||
|
||||
|
||||
c:delete('alfred', 'alfred')
|
||||
c:section('alfred', 'alfred', 'alfred',
|
||||
{
|
||||
interface = 'br-client',
|
||||
mode = 'slave',
|
||||
batmanif = 'bat0',
|
||||
start_vis = '1',
|
||||
run_facters = '0',
|
||||
}
|
||||
)
|
||||
|
||||
c:save('alfred')
|
||||
c:commit('alfred')
|
32
package/gluon-announce/Makefile
Normal file
32
package/gluon-announce/Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-announce
|
||||
PKG_VERSION:=1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gluon-announce
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
DEPENDS:=+gluon-core +luci-lib-json +lua-ethtool-stats
|
||||
TITLE:=Lua scripts announcing various information
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-announce/install
|
||||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-announce))
|
10
package/gluon-announce/files/lib/gluon/announce/collect.lua
Executable file
10
package/gluon-announce/files/lib/gluon/announce/collect.lua
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local announce = require 'gluon.announce'
|
||||
local json = require 'luci.json'
|
||||
local ltn12 = require 'luci.ltn12'
|
||||
|
||||
local announce_dir = '/lib/gluon/announce/' .. arg[1] .. '.d'
|
||||
|
||||
encoder = json.Encoder(announce.collect_dir(announce_dir))
|
||||
ltn12.pump.all(encoder:source(), ltn12.sink.file(io.stdout))
|
@ -0,0 +1 @@
|
||||
return require('gluon.util').node_id()
|
@ -0,0 +1 @@
|
||||
return require('platform_info').get_model()
|
@ -0,0 +1,14 @@
|
||||
local n = 0
|
||||
|
||||
local cpus = util.trim(fs.readfile('/sys/devices/system/cpu/online'))
|
||||
|
||||
for _, entry in ipairs(cpus:split(',')) do
|
||||
local x, y = entry:match('(%d+)-(%d+)')
|
||||
if x then
|
||||
n = n + tonumber(y) - tonumber(x) + 1
|
||||
else
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
|
||||
return n
|
@ -0,0 +1 @@
|
||||
return uci:get_first('system', 'system', 'hostname')
|
@ -0,0 +1 @@
|
||||
return require('gluon.sysconfig').primary_mac
|
@ -0,0 +1 @@
|
||||
return require('gluon.util').node_id()
|
@ -0,0 +1,4 @@
|
||||
return {
|
||||
base = 'gluon-' .. util.trim(fs.readfile('/lib/gluon/gluon-version')),
|
||||
release = util.trim(fs.readfile('/lib/gluon/release')),
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
local site = require 'gluon.site_config'
|
||||
|
||||
return site.site_code
|
@ -0,0 +1 @@
|
||||
return tonumber(fs.readfile('/proc/uptime'):match('^[^ ]+ ([^ ]+)'))
|
@ -0,0 +1 @@
|
||||
return tonumber(fs.readfile('/proc/loadavg'):match('^([^ ]+) '))
|
@ -0,0 +1,13 @@
|
||||
local data = fs.readfile('/proc/meminfo')
|
||||
|
||||
local fields = {}
|
||||
for k, v in data:gmatch('([^\n:]+):%s*(%d+) kB') do
|
||||
fields[k] = tonumber(v)
|
||||
end
|
||||
|
||||
return {
|
||||
total = fields.MemTotal,
|
||||
free = fields.MemFree,
|
||||
buffers = fields.Buffers,
|
||||
cached = fields.Cached,
|
||||
}
|
@ -0,0 +1 @@
|
||||
return require('gluon.util').node_id()
|
@ -0,0 +1,3 @@
|
||||
local running, total = fs.readfile('/proc/loadavg'):match('^[^ ]+ [^ ]+ [^ ]+ (%d+)/(%d+)')
|
||||
|
||||
return { running = tonumber(running), total = tonumber(total) }
|
@ -0,0 +1,4 @@
|
||||
local fs = require "nixio.fs"
|
||||
|
||||
local st = fs.statvfs("/")
|
||||
return 1 - st.bfree / st.blocks
|
@ -0,0 +1 @@
|
||||
return tonumber(fs.readfile('/proc/uptime'):match('^([^ ]+) '))
|
33
package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
Normal file
33
package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
module('gluon.announce', package.seeall)
|
||||
|
||||
fs = require 'luci.fs'
|
||||
uci = require('luci.model.uci').cursor()
|
||||
util = require 'luci.util'
|
||||
|
||||
local function collect_entry(entry)
|
||||
if fs.isdirectory(entry) then
|
||||
return collect_dir(entry)
|
||||
else
|
||||
return setfenv(loadfile(entry), _M)()
|
||||
end
|
||||
end
|
||||
|
||||
function collect_dir(dir)
|
||||
local ret = {}
|
||||
|
||||
for _, entry in ipairs(fs.dir(dir)) do
|
||||
if entry:sub(1, 1) ~= '.' then
|
||||
local ok, val = pcall(collect_entry, dir .. '/' .. entry)
|
||||
if ok then
|
||||
ret[entry] = val
|
||||
else
|
||||
io.stderr:write(val, '\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
32
package/gluon-announced/Makefile
Normal file
32
package/gluon-announced/Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-announced
|
||||
PKG_VERSION:=2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gluon-announced
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Provides node information to the network
|
||||
DEPENDS:=+gluon-announce +respondd +lua-deflate
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-announced/install
|
||||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-announced))
|
@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions/service.sh
|
||||
|
||||
DEVLIST=/var/run/gluon-announced.devs
|
||||
DAEMON=/usr/bin/respondd
|
||||
|
||||
ifname_to_dev () {
|
||||
json_load "$(ubus call network.interface.$1 status)"
|
||||
json_get_var dev device
|
||||
|
||||
echo "$dev"
|
||||
}
|
||||
|
||||
restart_announced () {
|
||||
SERVICE_USE_PID=1
|
||||
SERVICE_WRITE_PID=1
|
||||
SERVICE_DAEMONIZE=1
|
||||
|
||||
DEVS=$(cat $DEVLIST | while read dev iface; do echo -n " -i $dev"; done)
|
||||
|
||||
service_stop $DAEMON
|
||||
service_start $DAEMON -g ff02::2:1001 -p 1001 -c 'return require("gluon.announced").handle_request' $DEVS
|
||||
}
|
||||
|
||||
case "$ACTION" in
|
||||
ifdown)
|
||||
sed -i "/$INTERFACE/d" $DEVLIST
|
||||
;;
|
||||
ifup)
|
||||
DEVICE="$(ifname_to_dev "$INTERFACE")"
|
||||
MESH="$(cat "/sys/class/net/$DEVICE/batman_adv/mesh_iface" 2>/dev/null)"
|
||||
|
||||
[ "$MESH" = "bat0" -o "$INTERFACE" = "client" ] || exit 0
|
||||
|
||||
DEVS=$(cat $DEVLIST; echo $DEVICE $INTERFACE)
|
||||
|
||||
echo "$DEVS" | sort -u > $DEVLIST
|
||||
|
||||
restart_announced
|
||||
|
||||
;;
|
||||
esac
|
||||
|
18
package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall
Executable file
18
package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local uci = require('luci.model.uci').cursor()
|
||||
|
||||
-- Allow announced port on WAN to allow resolving neighbours over mesh-on-wan
|
||||
uci:section('firewall', 'rule', 'wan_announced',
|
||||
{
|
||||
name = 'wan_announced',
|
||||
src = 'wan',
|
||||
src_ip = 'fe80::/64',
|
||||
dest_port = '1001',
|
||||
proto = 'udp',
|
||||
target = 'ACCEPT',
|
||||
}
|
||||
)
|
||||
|
||||
uci:save('firewall')
|
||||
uci:commit('firewall')
|
@ -0,0 +1,33 @@
|
||||
local announce = require 'gluon.announce'
|
||||
local deflate = require 'deflate'
|
||||
local json = require 'luci.json'
|
||||
|
||||
|
||||
local function collect(type)
|
||||
return announce.collect_dir('/lib/gluon/announce/' .. type .. '.d')
|
||||
end
|
||||
|
||||
|
||||
module('gluon.announced', package.seeall)
|
||||
|
||||
function handle_request(query)
|
||||
if query:match('^nodeinfo$') then
|
||||
return json.encode(collect('nodeinfo'))
|
||||
end
|
||||
|
||||
local m = query:match('^GET ([a-z ]+)$')
|
||||
if m then
|
||||
local data = {}
|
||||
|
||||
for q in m:gmatch('([a-z]+)') do
|
||||
local ok, val = pcall(collect, q)
|
||||
if ok then
|
||||
data[q] = val
|
||||
end
|
||||
end
|
||||
|
||||
if next(data) then
|
||||
return deflate.compress(json.encode(data))
|
||||
end
|
||||
end
|
||||
end
|
36
package/gluon-authorized-keys/Makefile
Normal file
36
package/gluon-authorized-keys/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-authorized-keys
|
||||
PKG_VERSION:=2
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
define Package/gluon-authorized-keys
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Fill /etc/dropbear/authorized_keys from site.conf
|
||||
DEPENDS:=+gluon-core
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-authorized-keys/install
|
||||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
define Package/gluon-authorized-keys/postinst
|
||||
#!/bin/sh
|
||||
$(call GluonCheckSite,check_site.lua)
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-authorized-keys))
|
1
package/gluon-authorized-keys/check_site.lua
Normal file
1
package/gluon-authorized-keys/check_site.lua
Normal file
@ -0,0 +1 @@
|
||||
need_string_array 'authorized_keys'
|
22
package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys
Executable file
22
package/gluon-authorized-keys/files/lib/gluon/upgrade/100-authorized-keys
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local site = require 'gluon.site_config'
|
||||
local file = '/etc/dropbear/authorized_keys'
|
||||
|
||||
local keys = {}
|
||||
|
||||
function load_keys()
|
||||
for line in io.lines(file) do
|
||||
keys[line] = true
|
||||
end
|
||||
end
|
||||
|
||||
pcall(load_keys)
|
||||
|
||||
local f = io.open(file, 'a')
|
||||
for _, key in ipairs(site.authorized_keys) do
|
||||
if not keys[key] then
|
||||
f:write(key .. '\n')
|
||||
end
|
||||
end
|
||||
f:close()
|
42
package/gluon-autoupdater/Makefile
Normal file
42
package/gluon-autoupdater/Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-autoupdater
|
||||
PKG_VERSION:=4
|
||||
PKG_RELEASE:=$(GLUON_BRANCH)
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
define Package/gluon-autoupdater
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
DEPENDS:=+gluon-core +gluon-cron +autoupdater
|
||||
TITLE:=Automatically update firmware
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-autoupdater/install
|
||||
$(CP) ./files/* $(1)/
|
||||
|
||||
if [ '$(GLUON_BRANCH)' ]; then \
|
||||
$(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \
|
||||
echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define Package/gluon-autoupdater/postinst
|
||||
#!/bin/sh
|
||||
$(call GluonCheckSite,check_site.lua)
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-autoupdater))
|
12
package/gluon-autoupdater/check_site.lua
Normal file
12
package/gluon-autoupdater/check_site.lua
Normal file
@ -0,0 +1,12 @@
|
||||
need_string 'autoupdater.branch'
|
||||
|
||||
local function check_branch(k, _)
|
||||
local prefix = string.format('autoupdater.branches[%q].', k)
|
||||
|
||||
need_string(prefix .. 'name')
|
||||
need_string_array(prefix .. 'mirrors')
|
||||
need_number(prefix .. 'good_signatures')
|
||||
need_string_array(prefix .. 'pubkeys')
|
||||
end
|
||||
|
||||
need_table('autoupdater.branches', check_branch)
|
@ -0,0 +1,7 @@
|
||||
local autoupdater = uci:get_all('autoupdater', 'settings')
|
||||
if autoupdater then
|
||||
return {
|
||||
branch = autoupdater['branch'],
|
||||
enabled = uci:get_bool('autoupdater', 'settings', 'enabled'),
|
||||
}
|
||||
end
|
57
package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater
Executable file
57
package/gluon-autoupdater/files/lib/gluon/upgrade/500-autoupdater
Executable file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local site = require 'gluon.site_config'
|
||||
local uci = require 'luci.model.uci'
|
||||
|
||||
local c = uci.cursor()
|
||||
|
||||
|
||||
for name, config in pairs(site.autoupdater.branches) do
|
||||
c:delete('autoupdater', name)
|
||||
c:section('autoupdater', 'branch', name,
|
||||
{
|
||||
name = config.name,
|
||||
mirror = config.mirrors,
|
||||
good_signatures = config.good_signatures,
|
||||
pubkey = config.pubkeys,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
if not c:get('autoupdater', 'settings') then
|
||||
local enabled = 0
|
||||
local branch = site.autoupdater.branch
|
||||
|
||||
local f = io.open('/lib/gluon/autoupdater/default_branch')
|
||||
if f then
|
||||
enabled = 1
|
||||
branch = f:read('*line')
|
||||
f:close()
|
||||
end
|
||||
|
||||
c:section('autoupdater', 'autoupdater', 'settings',
|
||||
{
|
||||
enabled = enabled,
|
||||
branch = branch,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
c:set('autoupdater', 'settings', 'version_file', '/lib/gluon/release')
|
||||
|
||||
c:save('autoupdater')
|
||||
c:commit('autoupdater')
|
||||
|
||||
|
||||
local autoupdater_util = require 'autoupdater.util'
|
||||
autoupdater_util.randomseed()
|
||||
|
||||
|
||||
-- Perform updates at a random time between 04:00 and 05:00, and once an hour
|
||||
-- a fallback update (used after the regular updates haven't
|
||||
local minute = math.random(0, 59)
|
||||
|
||||
local f = io.open('/lib/gluon/cron/autoupdater', 'w')
|
||||
f:write(string.format('%i 4 * * * /usr/sbin/autoupdater\n', minute))
|
||||
f:write(string.format('%i 0-3,5-23 * * * /usr/sbin/autoupdater --fallback\n', minute))
|
||||
f:close()
|
40
package/gluon-config-mode-autoupdater/Makefile
Normal file
40
package/gluon-config-mode-autoupdater/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-autoupdater
|
||||
PKG_VERSION:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-autoupdater
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Let the user know whether the autoupdater is enabled or not.
|
||||
DEPENDS:=gluon-config-mode-core-virtual +gluon-autoupdater
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-autoupdater/description
|
||||
Luci based config mode
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-autoupdater,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-autoupdater/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-autoupdater,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-autoupdater))
|
@ -0,0 +1,19 @@
|
||||
local cbi = require "luci.cbi"
|
||||
local i18n = require "luci.i18n"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.section(form)
|
||||
local enabled = uci:get_bool("autoupdater", "settings", "enabled")
|
||||
if enabled then
|
||||
local s = form:section(cbi.SimpleSection, nil,
|
||||
i18n.translate('This node will automatically update its firmware when a new version is available.'))
|
||||
end
|
||||
end
|
||||
|
||||
function M.handle(data)
|
||||
return
|
||||
end
|
||||
|
||||
return M
|
17
package/gluon-config-mode-autoupdater/i18n/de.po
Normal file
17
package/gluon-config-mode-autoupdater/i18n/de.po
Normal file
@ -0,0 +1,17 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"PO-Revision-Date: 2015-03-18 16:03+0100\n"
|
||||
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid ""
|
||||
"This node will automatically update its firmware when a new version is "
|
||||
"available."
|
||||
msgstr "Dieser Knoten aktualisiert seine Firmware automatisch, sobald "
|
||||
"eine neue Version vorliegt."
|
@ -0,0 +1,7 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid ""
|
||||
"This node will automatically update its firmware when a new version is "
|
||||
"available."
|
||||
msgstr ""
|
36
package/gluon-config-mode-contact-info/Makefile
Normal file
36
package/gluon-config-mode-contact-info/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-contact-info
|
||||
PKG_VERSION:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-contact-info
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Set a custom string that will be distributed in the mesh.
|
||||
DEPENDS:=gluon-config-mode-core-virtual +gluon-node-info
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-contact-info,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-contact-info/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-contact-info,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-contact-info))
|
@ -0,0 +1,34 @@
|
||||
local cbi = require "luci.cbi"
|
||||
local i18n = require "luci.i18n"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.section(form)
|
||||
local s = form:section(cbi.SimpleSection, nil, i18n.translate(
|
||||
'You can provide your contact information here to '
|
||||
.. 'allow others to contact you. Please note that '
|
||||
.. 'this information will be visible <em>publicly</em> '
|
||||
.. 'on the internet together with your node\'s coordinates.'
|
||||
)
|
||||
)
|
||||
|
||||
local o = s:option(cbi.Value, "_contact", i18n.translate("Contact info"))
|
||||
o.default = uci:get_first("gluon-node-info", "owner", "contact", "")
|
||||
o.rmempty = true
|
||||
o.datatype = "string"
|
||||
o.description = i18n.translate("e.g. E-mail or phone number")
|
||||
o.maxlen = 140
|
||||
end
|
||||
|
||||
function M.handle(data)
|
||||
if data._contact ~= nil then
|
||||
uci:set("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact", data._contact)
|
||||
else
|
||||
uci:delete("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact")
|
||||
end
|
||||
uci:save("gluon-node-info")
|
||||
uci:commit("gluon-node-info")
|
||||
end
|
||||
|
||||
return M
|
27
package/gluon-config-mode-contact-info/i18n/de.po
Normal file
27
package/gluon-config-mode-contact-info/i18n/de.po
Normal file
@ -0,0 +1,27 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"PO-Revision-Date: 2015-03-19 01:32+0100\n"
|
||||
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Contact info"
|
||||
msgstr "Kontakt"
|
||||
|
||||
msgid ""
|
||||
"You can provide your contact information here to allow others to contact "
|
||||
"you. Please note that this information will be visible <em>publicly</em> on "
|
||||
"the internet together with your node's coordinates."
|
||||
msgstr ""
|
||||
"Hier kannst du einen <em>öffentlichen</em> Hinweis hinterlegen, um anderen "
|
||||
"zu ermöglichen, Kontakt mit dir aufzunehmen. Bitte beachte, dass "
|
||||
"dieser Hinweis auch öffentlich im Internet, zusammen mit den Koordinaten "
|
||||
"deines Knotens, einsehbar sein wird."
|
||||
|
||||
msgid "e.g. E-mail or phone number"
|
||||
msgstr "z.B. E-Mail oder Telefonnummer"
|
@ -0,0 +1,14 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Contact info"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"You can provide your contact information here to allow others to contact "
|
||||
"you. Please note that this information will be visible <em>publicly</em> on "
|
||||
"the internet together with your node's coordinates."
|
||||
msgstr ""
|
||||
|
||||
msgid "e.g. E-mail or phone number"
|
||||
msgstr ""
|
40
package/gluon-config-mode-core/Makefile
Normal file
40
package/gluon-config-mode-core/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright (C) 2012 Nils Schneider <nils at nilsschneider.net>
|
||||
# This is free software, licensed under the Apache 2.0 license.
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-core
|
||||
PKG_VERSION:=2
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-core
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Luci based config mode for user friendly setup of new mesh nodes
|
||||
DEPENDS:=gluon-setup-mode-virtual +gluon-luci-theme +gluon-lock-password $(GLUON_I18N_PACKAGES)
|
||||
PROVIDES:=gluon-config-mode-core-virtual
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-core,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-core/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-core,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-core))
|
@ -0,0 +1,3 @@
|
||||
local i18n = require 'luci.i18n'
|
||||
|
||||
return function () luci.template.render_string(i18n.translate('gluon-config-mode:reboot')) end
|
@ -0,0 +1,89 @@
|
||||
--[[
|
||||
Copyright 2013 Nils Schneider <nils@nilsschneider.net>
|
||||
|
||||
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
|
||||
|
||||
$Id$
|
||||
]]--
|
||||
|
||||
module("luci.controller.gluon-config-mode.index", package.seeall)
|
||||
|
||||
function index()
|
||||
local uci_state = luci.model.uci.cursor_state()
|
||||
|
||||
if uci_state:get_first("gluon-setup-mode", "setup_mode", "running", "0") == "1" then
|
||||
local root = node()
|
||||
if not root.target then
|
||||
root.target = alias("gluon-config-mode")
|
||||
root.index = true
|
||||
end
|
||||
|
||||
page = node()
|
||||
page.lock = true
|
||||
page.target = alias("gluon-config-mode")
|
||||
page.subindex = true
|
||||
page.index = false
|
||||
|
||||
page = node("gluon-config-mode")
|
||||
page.title = _("Wizard")
|
||||
page.target = alias("gluon-config-mode", "wizard")
|
||||
page.order = 5
|
||||
page.setuser = "root"
|
||||
page.setgroup = "root"
|
||||
page.index = true
|
||||
|
||||
entry({"gluon-config-mode", "wizard"}, form("gluon-config-mode/wizard")).index = true
|
||||
entry({"gluon-config-mode", "reboot"}, call("action_reboot"))
|
||||
end
|
||||
end
|
||||
|
||||
function action_reboot()
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", "1")
|
||||
uci:save("gluon-setup-mode")
|
||||
uci:commit("gluon-setup-mode")
|
||||
|
||||
if nixio.fork() ~= 0 then
|
||||
local fs = require "luci.fs"
|
||||
|
||||
local parts_dir = "/lib/gluon/config-mode/reboot/"
|
||||
local files = fs.dir(parts_dir)
|
||||
|
||||
table.sort(files)
|
||||
|
||||
local parts = {}
|
||||
|
||||
for _, entry in ipairs(files) do
|
||||
if entry:sub(1, 1) ~= '.' then
|
||||
local f = dofile(parts_dir .. '/' .. entry)
|
||||
if f ~= nil then
|
||||
table.insert(parts, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hostname = uci:get_first("system", "system", "hostname")
|
||||
|
||||
luci.template.render("gluon/config-mode/reboot", { parts=parts
|
||||
, hostname=hostname
|
||||
})
|
||||
else
|
||||
debug.setfenv(io.stdout, debug.getfenv(io.open '/dev/null'))
|
||||
io.stdout:close()
|
||||
|
||||
-- Sleep a little so the browser can fetch everything required to
|
||||
-- display the reboot page, then reboot the device.
|
||||
nixio.nanosleep(2)
|
||||
|
||||
-- Run reboot with popen so it gets its own std filehandles.
|
||||
io.popen("reboot")
|
||||
|
||||
-- Prevent any further execution in this child.
|
||||
os.exit()
|
||||
end
|
||||
end
|
@ -0,0 +1,38 @@
|
||||
local wizard_dir = "/lib/gluon/config-mode/wizard/"
|
||||
local i18n = luci.i18n
|
||||
local uci = luci.model.uci.cursor()
|
||||
local fs = require "luci.fs"
|
||||
local f, s
|
||||
|
||||
local wizard = {}
|
||||
local files = fs.dir(wizard_dir)
|
||||
|
||||
table.sort(files)
|
||||
|
||||
for _, entry in ipairs(files) do
|
||||
if entry:sub(1, 1) ~= '.' then
|
||||
table.insert(wizard, dofile(wizard_dir .. '/' .. entry))
|
||||
end
|
||||
end
|
||||
|
||||
f = SimpleForm("wizard")
|
||||
f.reset = false
|
||||
f.template = "gluon/cbi/config-mode"
|
||||
|
||||
for _, s in ipairs(wizard) do
|
||||
s.section(f)
|
||||
end
|
||||
|
||||
function f.handle(self, state, data)
|
||||
if state == FORM_VALID then
|
||||
for _, s in ipairs(wizard) do
|
||||
s.handle(data)
|
||||
end
|
||||
|
||||
luci.http.redirect(luci.dispatcher.build_url("gluon-config-mode", "reboot"))
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return f
|
@ -0,0 +1,46 @@
|
||||
<%-
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
local i18n = require 'luci.i18n'
|
||||
local template = require 'luci.template'
|
||||
-%>
|
||||
|
||||
<h2><%:Welcome!%></h2>
|
||||
<p>
|
||||
<%= template.render_string(i18n.translate('gluon-config-mode:welcome'), {hostname=hostname, sysconfig=sysconfig}) %>
|
||||
</p>
|
||||
|
||||
<% if not self.embedded then %>
|
||||
<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>">
|
||||
<div>
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<input type="hidden" name="cbi.submit" value="1" />
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="cbi-map" id="cbi-<%=self.config%>">
|
||||
<% if self.title and #self.title > 0 then %><h2><a id="content" name="content"><%=self.title%></a></h2><% end %>
|
||||
<% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
|
||||
<% self:render_children() %>
|
||||
<br />
|
||||
</div>
|
||||
<%- if self.message then %>
|
||||
<div><%=self.message%></div>
|
||||
<%- end %>
|
||||
<%- if self.errmessage then %>
|
||||
<div class="error"><%=self.errmessage%></div>
|
||||
<%- end %>
|
||||
<% if not self.embedded then %>
|
||||
<div class="cbi-page-actions">
|
||||
<%-
|
||||
if type(self.hidden) == "table" then
|
||||
for k, v in pairs(self.hidden) do
|
||||
-%>
|
||||
<input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" />
|
||||
<%-
|
||||
end
|
||||
end
|
||||
%>
|
||||
<input class="cbi-button cbi-button-save" type="submit" value="<%:Save & restart%>" />
|
||||
<script type="text/javascript">cbi_d_update();</script>
|
||||
</div>
|
||||
</form>
|
||||
<% end %>
|
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%=luci.i18n.context.lang%>" lang="<%=luci.i18n.context.lang%>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title><%=hostname%> is rebooting</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="maincontainer">
|
||||
<div id="maincontent">
|
||||
<h2><%:Your node's setup is now complete.%></h2>
|
||||
<% for k, v in ipairs(parts) do v() end %>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
24
package/gluon-config-mode-core/i18n/de.po
Normal file
24
package/gluon-config-mode-core/i18n/de.po
Normal file
@ -0,0 +1,24 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"PO-Revision-Date: 2015-03-19 02:07+0100\n"
|
||||
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Save & restart"
|
||||
msgstr "Speichern & Neustarten"
|
||||
|
||||
msgid "Welcome!"
|
||||
msgstr "Willkommen!"
|
||||
|
||||
msgid "Wizard"
|
||||
msgstr "Wizard"
|
||||
|
||||
msgid "Your node's setup is now complete."
|
||||
msgstr "Dein Knoten ist nun fertig eingerichtet."
|
@ -0,0 +1,14 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Save & restart"
|
||||
msgstr ""
|
||||
|
||||
msgid "Welcome!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wizard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your node's setup is now complete."
|
||||
msgstr ""
|
36
package/gluon-config-mode-geo-location/Makefile
Normal file
36
package/gluon-config-mode-geo-location/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-geo-location
|
||||
PKG_VERSION:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-geo-location
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Set geographic location of a node
|
||||
DEPENDS:=gluon-config-mode-core-virtual +gluon-node-info
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-geo-location,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-geo-location/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-geo-location,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-geo-location))
|
@ -0,0 +1,60 @@
|
||||
local cbi = require "luci.cbi"
|
||||
local i18n = require "luci.i18n"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.section(form)
|
||||
local s = form:section(cbi.SimpleSection, nil, i18n.translate(
|
||||
'If you want the location of your node to be displayed on the map, '
|
||||
.. 'you can enter its coordinates here. Specifying the altitude '
|
||||
.. 'is optional and should only be done if a proper value is known.'))
|
||||
|
||||
|
||||
local o
|
||||
|
||||
o = s:option(cbi.Flag, "_location", i18n.translate("Show node on the map"))
|
||||
o.default = uci:get_first("gluon-node-info", "location", "share_location", o.disabled)
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(cbi.Value, "_latitude", i18n.translate("Latitude"))
|
||||
o.default = uci:get_first("gluon-node-info", "location", "latitude")
|
||||
o:depends("_location", "1")
|
||||
o.rmempty = false
|
||||
o.datatype = "float"
|
||||
o.description = i18n.translatef("e.g. %s", "53.873621")
|
||||
|
||||
o = s:option(cbi.Value, "_longitude", i18n.translate("Longitude"))
|
||||
o.default = uci:get_first("gluon-node-info", "location", "longitude")
|
||||
o:depends("_location", "1")
|
||||
o.rmempty = false
|
||||
o.datatype = "float"
|
||||
o.description = i18n.translatef("e.g. %s", "10.689901")
|
||||
|
||||
o = s:option(cbi.Value, "_altitude", i18n.translate("Altitude"))
|
||||
o.default = uci:get_first("gluon-node-info", "location", "altitude")
|
||||
o:depends("_location", "1")
|
||||
o.rmempty = true
|
||||
o.datatype = "float"
|
||||
o.description = i18n.translatef("e.g. %s", "11.51")
|
||||
|
||||
end
|
||||
|
||||
function M.handle(data)
|
||||
local sname = uci:get_first("gluon-node-info", "location")
|
||||
|
||||
uci:set("gluon-node-info", sname, "share_location", data._location)
|
||||
if data._location and data._latitude ~= nil and data._longitude ~= nil then
|
||||
uci:set("gluon-node-info", sname, "latitude", data._latitude)
|
||||
uci:set("gluon-node-info", sname, "longitude", data._longitude)
|
||||
if data._altitude ~= nil then
|
||||
uci:set("gluon-node-info", sname, "altitude", data._altitude)
|
||||
else
|
||||
uci:delete("gluon-node-info", sname, "altitude")
|
||||
end
|
||||
end
|
||||
uci:save("gluon-node-info")
|
||||
uci:commit("gluon-node-info")
|
||||
end
|
||||
|
||||
return M
|
36
package/gluon-config-mode-geo-location/i18n/de.po
Normal file
36
package/gluon-config-mode-geo-location/i18n/de.po
Normal file
@ -0,0 +1,36 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gluon-config-mode-geo-location\n"
|
||||
"PO-Revision-Date: 2015-03-23 02:18+0100\n"
|
||||
"Last-Translator: Martin Weinelt <martin@darmstadt.freifunk.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid ""
|
||||
"If you want the location of your node to be displayed on the map, you can "
|
||||
"enter its coordinates here. Specifying the altitude is optional and should "
|
||||
"only be done if a proper value is known."
|
||||
msgstr ""
|
||||
"Um deinen Knoten auf der Karte anzeigen zu können, benötigen wir seine "
|
||||
"Koordinaten. Hier hast du die Möglichkeit, diese zu hinterlegen. Die "
|
||||
"Höhenangabe ist optional und sollte nur gesetzt werden, wenn ein exakter "
|
||||
"Wert bekannt ist."
|
||||
|
||||
msgid "Latitude"
|
||||
msgstr "Breitengrad"
|
||||
|
||||
msgid "Longitude"
|
||||
msgstr "Längengrad"
|
||||
|
||||
msgid "Altitude"
|
||||
msgstr "Höhenmeter über Normalnull"
|
||||
|
||||
msgid "Show node on the map"
|
||||
msgstr "Knoten auf der Karte anzeigen"
|
||||
|
||||
msgid "e.g. %s"
|
||||
msgstr "z.B. %s"
|
@ -0,0 +1,23 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid ""
|
||||
"If you want the location of your node to be displayed on the map, you can "
|
||||
"enter its coordinates here. Specifying the altitude is optional and should "
|
||||
"only be done if a proper value is known."
|
||||
msgstr ""
|
||||
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
msgid "Altitude"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show node on the map"
|
||||
msgstr ""
|
||||
|
||||
msgid "e.g. %s"
|
||||
msgstr ""
|
36
package/gluon-config-mode-hostname/Makefile
Normal file
36
package/gluon-config-mode-hostname/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-hostname
|
||||
PKG_VERSION:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-hostname
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Set the hostname
|
||||
DEPENDS:=gluon-config-mode-core-virtual
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-hostname,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-hostname/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-hostname,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-hostname))
|
@ -0,0 +1,21 @@
|
||||
local cbi = require "luci.cbi"
|
||||
local i18n = require "luci.i18n"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.section(form)
|
||||
local s = form:section(cbi.SimpleSection, nil, nil)
|
||||
local o = s:option(cbi.Value, "_hostname", i18n.translate("Node name"))
|
||||
o.value = uci:get_first("system", "system", "hostname")
|
||||
o.rmempty = false
|
||||
o.datatype = "hostname"
|
||||
end
|
||||
|
||||
function M.handle(data)
|
||||
uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname)
|
||||
uci:save("system")
|
||||
uci:commit("system")
|
||||
end
|
||||
|
||||
return M
|
14
package/gluon-config-mode-hostname/i18n/de.po
Normal file
14
package/gluon-config-mode-hostname/i18n/de.po
Normal file
@ -0,0 +1,14 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"PO-Revision-Date: 2015-03-19 00:54+0100\n"
|
||||
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Node name"
|
||||
msgstr "Name dieses Knotens"
|
@ -0,0 +1,5 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Node name"
|
||||
msgstr ""
|
36
package/gluon-config-mode-mesh-vpn/Makefile
Normal file
36
package/gluon-config-mode-mesh-vpn/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-config-mode-mesh-vpn
|
||||
PKG_VERSION:=2
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
|
||||
|
||||
|
||||
define Package/gluon-config-mode-mesh-vpn
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Toggle mesh-vpn and bandwidth limit
|
||||
DEPENDS:=gluon-config-mode-core-virtual +gluon-mesh-vpn-fastd +gluon-simple-tc
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(call GluonBuildI18N,gluon-config-mode-mesh-vpn,i18n)
|
||||
endef
|
||||
|
||||
define Package/gluon-config-mode-mesh-vpn/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(call GluonInstallI18N,gluon-config-mode-mesh-vpn,$(1))
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-config-mode-mesh-vpn))
|
@ -0,0 +1,29 @@
|
||||
local uci = luci.model.uci.cursor()
|
||||
local meshvpn_enabled = uci:get("fastd", "mesh_vpn", "enabled", "0")
|
||||
|
||||
if meshvpn_enabled ~= "1" then
|
||||
return nil
|
||||
else
|
||||
local i18n = require "luci.i18n"
|
||||
local util = require "luci.util"
|
||||
local site = require 'gluon.site_config'
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
local pubkey = util.trim(util.exec("/etc/init.d/fastd show_key " .. "mesh_vpn"))
|
||||
local hostname = uci:get_first("system", "system", "hostname")
|
||||
|
||||
local msg = [[<p>]] .. i18n.translate('gluon-config-mode:pubkey') .. [[</p>
|
||||
<div class="the-key">
|
||||
# <%= hostname %>
|
||||
<br/>
|
||||
<%= pubkey %>
|
||||
</div>]]
|
||||
|
||||
return function ()
|
||||
luci.template.render_string(msg, { pubkey=pubkey
|
||||
, hostname=hostname
|
||||
, site=site
|
||||
, sysconfig=sysconfig
|
||||
})
|
||||
end
|
||||
end
|
@ -0,0 +1,64 @@
|
||||
local cbi = require "luci.cbi"
|
||||
local i18n = require "luci.i18n"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.section(form)
|
||||
local msg = i18n.translate('Your internet connection can be used to establish an ' ..
|
||||
'encrypted connection with other nodes. ' ..
|
||||
'Enable this option if there are no other nodes reachable ' ..
|
||||
'over WLAN in your vicinity or you want to make a part of ' ..
|
||||
'your connection\'s bandwidth available for the network. You can limit how ' ..
|
||||
'much bandwidth the node will use at most.')
|
||||
local s = form:section(cbi.SimpleSection, nil, msg)
|
||||
|
||||
local o
|
||||
|
||||
o = s:option(cbi.Flag, "_meshvpn", i18n.translate("Use internet connection (mesh VPN)"))
|
||||
o.default = uci:get_bool("fastd", "mesh_vpn", "enabled") and o.enabled or o.disabled
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(cbi.Flag, "_limit_enabled", i18n.translate("Limit bandwidth"))
|
||||
o:depends("_meshvpn", "1")
|
||||
o.default = uci:get_bool("gluon-simple-tc", "mesh_vpn", "enabled") and o.enabled or o.disabled
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(cbi.Value, "_limit_ingress", i18n.translate("Downstream (kbit/s)"))
|
||||
o:depends("_limit_enabled", "1")
|
||||
o.value = uci:get("gluon-simple-tc", "mesh_vpn", "limit_ingress")
|
||||
o.rmempty = false
|
||||
o.datatype = "integer"
|
||||
|
||||
o = s:option(cbi.Value, "_limit_egress", i18n.translate("Upstream (kbit/s)"))
|
||||
o:depends("_limit_enabled", "1")
|
||||
o.value = uci:get("gluon-simple-tc", "mesh_vpn", "limit_egress")
|
||||
o.rmempty = false
|
||||
o.datatype = "integer"
|
||||
end
|
||||
|
||||
function M.handle(data)
|
||||
uci:set("fastd", "mesh_vpn", "enabled", data._meshvpn)
|
||||
uci:save("fastd")
|
||||
uci:commit("fastd")
|
||||
|
||||
-- checks for nil needed due to o:depends(...)
|
||||
if data._limit_enabled ~= nil then
|
||||
uci:set("gluon-simple-tc", "mesh_vpn", "interface")
|
||||
uci:set("gluon-simple-tc", "mesh_vpn", "enabled", data._limit_enabled)
|
||||
uci:set("gluon-simple-tc", "mesh_vpn", "ifname", "mesh-vpn")
|
||||
|
||||
if data._limit_ingress ~= nil then
|
||||
uci:set("gluon-simple-tc", "mesh_vpn", "limit_ingress", data._limit_ingress)
|
||||
end
|
||||
|
||||
if data._limit_egress ~= nil then
|
||||
uci:set("gluon-simple-tc", "mesh_vpn", "limit_egress", data._limit_egress)
|
||||
end
|
||||
|
||||
uci:commit("gluon-simple-tc")
|
||||
uci:commit("gluon-simple-tc")
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
36
package/gluon-config-mode-mesh-vpn/i18n/de.po
Normal file
36
package/gluon-config-mode-mesh-vpn/i18n/de.po
Normal file
@ -0,0 +1,36 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"PO-Revision-Date: 2015-03-19 22:05+0100\n"
|
||||
"Last-Translator: Matthias Schiffer <mschiffer@universe-factory.net>\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
msgid "Downstream (kbit/s)"
|
||||
msgstr "Downstream (kbit/s)"
|
||||
|
||||
msgid "Limit bandwidth"
|
||||
msgstr "Bandbreite begrenzen"
|
||||
|
||||
msgid "Upstream (kbit/s)"
|
||||
msgstr "Upstream (kbit/s)"
|
||||
|
||||
msgid "Use internet connection (mesh VPN)"
|
||||
msgstr "Internetverbindung nutzen (Mesh-VPN)"
|
||||
|
||||
msgid ""
|
||||
"Your internet connection can be used to establish an encrypted connection "
|
||||
"with other nodes. Enable this option if there are no other nodes reachable "
|
||||
"over WLAN in your vicinity or you want to make a part of your connection's "
|
||||
"bandwidth available for the network. You can limit how much bandwidth the "
|
||||
"node will use at most."
|
||||
msgstr ""
|
||||
"Dein Knoten kann deine Internetverbindung nutzen um darüber eine "
|
||||
"verschlüsselte Verbindung zu anderen Knoten aufzubauen. Die dafür "
|
||||
"genutzte Bandbreite kannst du beschränken. Aktiviere die Option, falls keine "
|
||||
"per WLAN erreichbaren Nachbarknoten in deiner Nähe sind oder du deine "
|
||||
"Internetverbindung für das Mesh-Netzwerk zur Verfügung stellen möchtest."
|
@ -0,0 +1,22 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Downstream (kbit/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Limit bandwidth"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upstream (kbit/s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Use internet connection (mesh VPN)"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Your internet connection can be used to establish an encrypted connection "
|
||||
"with other nodes. Enable this option if there are no other nodes reachable "
|
||||
"over WLAN in your vicinity or you want to make a part of your connection's "
|
||||
"bandwidth available for the network. You can limit how much bandwidth the "
|
||||
"node will use at most."
|
||||
msgstr ""
|
59
package/gluon-core/Makefile
Normal file
59
package/gluon-core/Makefile
Normal file
@ -0,0 +1,59 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-core
|
||||
PKG_VERSION:=3
|
||||
PKG_RELEASE:=$(GLUON_VERSION)
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(GLUONDIR)/include/package.mk
|
||||
|
||||
define Package/gluon-core
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Base files of Gluon
|
||||
DEPENDS:=+gluon-site +lua-platform-info +luci-lib-nixio +odhcp6c +firewall
|
||||
endef
|
||||
|
||||
|
||||
define LangConfig
|
||||
config GLUON_LANG_$(1)
|
||||
bool "$(GLUON_LANG_$(1)) language support"
|
||||
depends on PACKAGE_gluon-core
|
||||
default n
|
||||
|
||||
endef
|
||||
|
||||
|
||||
define Package/gluon-core/config
|
||||
$(foreach lang,$(GLUON_SUPPORTED_LANGS),$(call LangConfig,$(lang)))
|
||||
endef
|
||||
|
||||
|
||||
define Package/gluon-core/description
|
||||
Gluon community wifi mesh firmware framework: core
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/gluon-core/install
|
||||
$(CP) ./files/* $(1)/
|
||||
|
||||
$(INSTALL_DIR) $(1)/lib/gluon
|
||||
echo "$(GLUON_VERSION)" > $(1)/lib/gluon/gluon-version
|
||||
endef
|
||||
|
||||
define Package/gluon-core/postinst
|
||||
#!/bin/sh
|
||||
$(call GluonCheckSite,check_site.lua)
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-core))
|
10
package/gluon-core/check_site.lua
Normal file
10
package/gluon-core/check_site.lua
Normal file
@ -0,0 +1,10 @@
|
||||
need_string 'site_code'
|
||||
need_string 'site_name'
|
||||
|
||||
need_string('hostname_prefix', false)
|
||||
need_string 'timezone'
|
||||
|
||||
need_string_array('ntp_servers', false)
|
||||
|
||||
need_string_match('prefix4', '^%d+.%d+.%d+.%d+/%d+$')
|
||||
need_string_match('prefix6', '^[%x:]+/%d+$')
|
5
package/gluon-core/files/etc/uci-defaults/zzz-gluon-upgrade
Executable file
5
package/gluon-core/files/etc/uci-defaults/zzz-gluon-upgrade
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
for script in /lib/gluon/upgrade/*; do
|
||||
"$script"
|
||||
done
|
10
package/gluon-core/files/lib/gluon/upgrade/001-upgrade
Executable file
10
package/gluon-core/files/lib/gluon/upgrade/001-upgrade
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local fs = require 'luci.fs'
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
|
||||
if fs.isfile('/lib/gluon/version/core') and not sysconfig.gluon_version then
|
||||
-- This isn't an initial upgrade, so set gluon_version
|
||||
sysconfig.gluon_version = ''
|
||||
end
|
42
package/gluon-core/files/lib/gluon/upgrade/010-primary-mac
Executable file
42
package/gluon-core/files/lib/gluon/upgrade/010-primary-mac
Executable file
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
|
||||
if sysconfig.primary_mac then
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
|
||||
local platform = require 'gluon.platform'
|
||||
|
||||
local fs = require 'luci.fs'
|
||||
local util = require 'luci.util'
|
||||
|
||||
|
||||
local try_files = {
|
||||
'/sys/class/ieee80211/phy0/macaddress',
|
||||
'/sys/class/net/eth0/address',
|
||||
}
|
||||
|
||||
if platform.match('ar71xx', 'generic', {'tl-wdr3600', 'tl-wdr4300'}) then
|
||||
table.insert(try_files, 1, '/sys/class/ieee80211/phy1/macaddress')
|
||||
end
|
||||
|
||||
if platform.match('ar71xx', 'generic', {'unifi-outdoor-plus'}) then
|
||||
table.insert(try_files, 1, '/sys/class/net/eth0/address')
|
||||
end
|
||||
|
||||
if platform.match('ar71xx', 'generic', {'archer-c5', 'archer-c7'}) then
|
||||
table.insert(try_files, 1, '/sys/class/net/eth1/address')
|
||||
end
|
||||
|
||||
|
||||
for _, file in ipairs(try_files) do
|
||||
local addr = fs.readfile(file)
|
||||
|
||||
if addr then
|
||||
sysconfig.primary_mac = util.trim(addr)
|
||||
break
|
||||
end
|
||||
end
|
36
package/gluon-core/files/lib/gluon/upgrade/020-interfaces
Executable file
36
package/gluon-core/files/lib/gluon/upgrade/020-interfaces
Executable file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
local gluon_util = require 'gluon.util'
|
||||
local platform = require 'gluon.platform'
|
||||
|
||||
local uci = require('luci.model.uci').cursor()
|
||||
|
||||
|
||||
if not (sysconfig.lan_ifname or sysconfig.wan_ifname) then
|
||||
local function iface_exists(name)
|
||||
return (gluon_util.exec('ip', 'link', 'show', 'dev', (name:gsub('%..*$', ''))) == 0)
|
||||
end
|
||||
|
||||
|
||||
local lan_ifname = uci:get('network', 'lan', 'ifname')
|
||||
local wan_ifname = uci:get('network', 'wan', 'ifname')
|
||||
|
||||
if platform.match('ar71xx', 'generic', {'cpe510', 'nanostation-m', 'nanostation-m-xw', 'unifi-outdoor-plus'}) then
|
||||
lan_ifname, wan_ifname = wan_ifname, lan_ifname
|
||||
end
|
||||
|
||||
if wan_ifname and iface_exists(wan_ifname) then
|
||||
sysconfig.wan_ifname = wan_ifname
|
||||
sysconfig.lan_ifname = lan_ifname
|
||||
else
|
||||
sysconfig.wan_ifname = lan_ifname
|
||||
end
|
||||
|
||||
|
||||
uci:delete('network', 'lan')
|
||||
uci:delete('network', 'wan')
|
||||
|
||||
uci:save('network')
|
||||
uci:commit('network')
|
||||
end
|
18
package/gluon-core/files/lib/gluon/upgrade/030-system
Executable file
18
package/gluon-core/files/lib/gluon/upgrade/030-system
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
-- Initial
|
||||
if not sysconfig.gluon_version then
|
||||
local site = require 'gluon.site_config'
|
||||
local util = require 'gluon.util'
|
||||
local uci = require('luci.model.uci').cursor()
|
||||
|
||||
local system = uci:get_first('system', 'system')
|
||||
|
||||
uci:set('system', system, 'hostname', (site.hostname_prefix or '') .. util.node_id())
|
||||
uci:set('system', system, 'timezone', site.timezone)
|
||||
|
||||
uci:save('system')
|
||||
uci:commit('system')
|
||||
end
|
5
package/gluon-core/files/lib/gluon/upgrade/100-dnsmasq
Executable file
5
package/gluon-core/files/lib/gluon/upgrade/100-dnsmasq
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -e /etc/dnsmasq.conf ]; then
|
||||
sed -i -e '/^conf-dir=\/lib\/gluon\/dnsmasq\.d$/d' -e '/^conf-dir=\/var\/gluon\/dnsmasq\.d$/d' /etc/dnsmasq.conf
|
||||
fi
|
59
package/gluon-core/files/lib/gluon/upgrade/110-network
Executable file
59
package/gluon-core/files/lib/gluon/upgrade/110-network
Executable file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local uci = require('luci.model.uci').cursor()
|
||||
local sysctl = require 'gluon.sysctl'
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
|
||||
uci:section('network', 'interface', 'wan',
|
||||
{
|
||||
ifname = sysconfig.wan_ifname,
|
||||
type = 'bridge',
|
||||
igmp_snooping = 0,
|
||||
peerdns = 0,
|
||||
auto = 1,
|
||||
}
|
||||
)
|
||||
|
||||
if not uci:get('network', 'wan', 'proto') then
|
||||
uci:set('network', 'wan', 'proto', 'dhcp')
|
||||
end
|
||||
|
||||
|
||||
uci:section('network', 'interface', 'wan6',
|
||||
{
|
||||
ifname = 'br-wan',
|
||||
peerdns = 0,
|
||||
ip6table = 1,
|
||||
}
|
||||
)
|
||||
|
||||
if not uci:get('network', 'wan6', 'proto') then
|
||||
uci:set('network', 'wan6', 'proto', 'dhcpv6')
|
||||
end
|
||||
|
||||
|
||||
uci:section('network', 'rule6', 'wan6_lookup',
|
||||
{
|
||||
mark = '0x01/0x01',
|
||||
lookup = 1,
|
||||
}
|
||||
)
|
||||
|
||||
uci:section('network', 'route6', 'wan6_unreachable',
|
||||
{
|
||||
type = 'unreachable',
|
||||
interface = 'loopback',
|
||||
target = '::/0',
|
||||
gateway = '::',
|
||||
table = 1,
|
||||
metric = 65535,
|
||||
}
|
||||
)
|
||||
|
||||
uci:save('network')
|
||||
uci:commit('network')
|
||||
|
||||
|
||||
sysctl.set('net.ipv6.conf.all.accept_ra', 0)
|
||||
sysctl.set('net.ipv6.conf.default.accept_ra', 0)
|
14
package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers
Executable file
14
package/gluon-core/files/lib/gluon/upgrade/120-ntp-servers
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local site = require 'gluon.site_config'
|
||||
local uci = require 'luci.model.uci'
|
||||
|
||||
if not site.ntp_servers or #site.ntp_servers == 0 then
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
local c = uci.cursor()
|
||||
c:delete('system', 'ntp', 'server')
|
||||
c:set_list('system', 'ntp', 'server', site.ntp_servers)
|
||||
c:save('system')
|
||||
c:commit('system')
|
5
package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom
Executable file
5
package/gluon-core/files/lib/gluon/upgrade/130-reboot-on-oom
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysctl = require 'gluon.sysctl'
|
||||
|
||||
sysctl.set('vm.panic_on_oom', 1)
|
30
package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules
Executable file
30
package/gluon-core/files/lib/gluon/upgrade/140-firewall-rules
Executable file
@ -0,0 +1,30 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local site = require 'gluon.site_config'
|
||||
local uci = require 'luci.model.uci'
|
||||
|
||||
local c = uci.cursor()
|
||||
|
||||
|
||||
local function reject_input_on_wan(zone)
|
||||
if zone.name == 'wan' then
|
||||
c:set('firewall', zone['.name'], 'input', 'REJECT')
|
||||
c:set('firewall', zone['.name'], 'conntrack', '1')
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
c:foreach('firewall', 'zone', reject_input_on_wan)
|
||||
|
||||
c:section('firewall', 'rule', 'wan_ssh',
|
||||
{
|
||||
name = 'wan_ssh',
|
||||
src = 'wan',
|
||||
dest_port = '22',
|
||||
proto = 'tcp',
|
||||
target = 'ACCEPT',
|
||||
}
|
||||
)
|
||||
|
||||
c:save('firewall')
|
||||
c:commit('firewall')
|
12
package/gluon-core/files/lib/gluon/upgrade/200-wireless
Executable file
12
package/gluon-core/files/lib/gluon/upgrade/200-wireless
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
-- Initial
|
||||
if not sysconfig.gluon_version then
|
||||
local uci = require('luci.model.uci').cursor()
|
||||
|
||||
uci:delete_all('wireless', 'wifi-iface')
|
||||
uci:save('wireless')
|
||||
uci:commit('wireless')
|
||||
end
|
11
package/gluon-core/files/lib/gluon/upgrade/999-version
Executable file
11
package/gluon-core/files/lib/gluon/upgrade/999-version
Executable file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
local fs = require 'luci.fs'
|
||||
local util = require 'luci.util'
|
||||
|
||||
|
||||
-- Save the Gluon version in the sysconfig so we know which version we
|
||||
-- upgraded from after the next upgrade
|
||||
sysconfig.gluon_version = util.trim(fs.readfile('/lib/gluon/gluon-version'))
|
1
package/gluon-core/files/lib/upgrade/keep.d/gluon
Normal file
1
package/gluon-core/files/lib/upgrade/keep.d/gluon
Normal file
@ -0,0 +1 @@
|
||||
/lib/gluon/core/sysconfig/
|
31
package/gluon-core/files/usr/lib/lua/gluon/platform.lua
Normal file
31
package/gluon-core/files/usr/lib/lua/gluon/platform.lua
Normal file
@ -0,0 +1,31 @@
|
||||
local platform_info = require 'platform_info'
|
||||
local util = require 'luci.util'
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
|
||||
module 'gluon.platform'
|
||||
|
||||
setmetatable(_M,
|
||||
{
|
||||
__index = platform_info,
|
||||
}
|
||||
)
|
||||
|
||||
function match(target, subtarget, boards)
|
||||
if get_target() ~= target then
|
||||
return false
|
||||
end
|
||||
|
||||
if get_subtarget() ~= subtarget then
|
||||
return false
|
||||
end
|
||||
|
||||
if not util.contains(boards, get_board_name()) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
21
package/gluon-core/files/usr/lib/lua/gluon/site_config.lua
Normal file
21
package/gluon-core/files/usr/lib/lua/gluon/site_config.lua
Normal file
@ -0,0 +1,21 @@
|
||||
local config = os.getenv('GLUON_SITE_CONFIG') or '/lib/gluon/site.conf'
|
||||
|
||||
local function loader()
|
||||
coroutine.yield('return ')
|
||||
coroutine.yield(io.open(config):read('*a'))
|
||||
end
|
||||
|
||||
-- setfenv doesn't work with Lua 5.2 anymore, but we're using 5.1
|
||||
local site_config = setfenv(assert(load(coroutine.wrap(loader), 'site.conf')), {})()
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
module 'gluon.site_config'
|
||||
|
||||
setmetatable(_M,
|
||||
{
|
||||
__index = site_config,
|
||||
}
|
||||
)
|
||||
|
||||
return _M
|
34
package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua
Normal file
34
package/gluon-core/files/usr/lib/lua/gluon/sysconfig.lua
Normal file
@ -0,0 +1,34 @@
|
||||
local sysconfigdir = '/lib/gluon/core/sysconfig/'
|
||||
|
||||
local function get(_, name)
|
||||
local f = io.open(sysconfigdir .. name)
|
||||
if f then
|
||||
local ret = f:read('*line')
|
||||
f:close()
|
||||
return (ret or '')
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function set(_, name, val)
|
||||
if val then
|
||||
local f = io.open(sysconfigdir .. name, 'w+')
|
||||
f:write(val)
|
||||
f:close()
|
||||
else
|
||||
os.remove(sysconfigdir .. name)
|
||||
end
|
||||
end
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
module 'gluon.sysconfig'
|
||||
|
||||
setmetatable(_M,
|
||||
{
|
||||
__index = get,
|
||||
__newindex = set,
|
||||
}
|
||||
)
|
||||
|
||||
return _M
|
8
package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua
Normal file
8
package/gluon-core/files/usr/lib/lua/gluon/sysctl.lua
Normal file
@ -0,0 +1,8 @@
|
||||
local util = require 'gluon.util'
|
||||
|
||||
|
||||
module 'gluon.sysctl'
|
||||
|
||||
function set(name, value)
|
||||
util.replace_prefix('/etc/sysctl.conf', name .. '=', name .. '=' .. value .. '\n')
|
||||
end
|
33
package/gluon-core/files/usr/lib/lua/gluon/users.lua
Normal file
33
package/gluon-core/files/usr/lib/lua/gluon/users.lua
Normal file
@ -0,0 +1,33 @@
|
||||
local util = require 'gluon.util'
|
||||
|
||||
local os = os
|
||||
local string = string
|
||||
|
||||
|
||||
module 'gluon.users'
|
||||
|
||||
function add_user(username, uid, gid)
|
||||
util.lock('/var/lock/passwd')
|
||||
util.replace_prefix('/etc/passwd', username .. ':', string.format('%s:*:%u:%u::/var:/bin/false\n', username, uid, gid))
|
||||
util.replace_prefix('/etc/shadow', username .. ':', string.format('%s:*:0:0:99999:7:::\n', username))
|
||||
util.unlock('/var/lock/passwd')
|
||||
end
|
||||
|
||||
function remove_user(username)
|
||||
util.lock('/var/lock/passwd')
|
||||
util.replace_prefix('/etc/passwd', username .. ':')
|
||||
util.replace_prefix('/etc/shadow', username .. ':')
|
||||
util.unlock('/var/lock/passwd')
|
||||
end
|
||||
|
||||
function add_group(groupname, gid)
|
||||
util.lock('/var/lock/group')
|
||||
util.replace_prefix('/etc/group', groupname .. ':', string.format('%s:x:%u:\n', groupname, gid))
|
||||
util.unlock('/var/lock/group')
|
||||
end
|
||||
|
||||
function remove_group(groupname)
|
||||
util.lock('/var/lock/group')
|
||||
util.replace_prefix('/etc/group', groupname .. ':')
|
||||
util.unlock('/var/lock/group')
|
||||
end
|
79
package/gluon-core/files/usr/lib/lua/gluon/util.lua
Normal file
79
package/gluon-core/files/usr/lib/lua/gluon/util.lua
Normal file
@ -0,0 +1,79 @@
|
||||
-- Writes all lines from the file input to the file output except those starting with prefix
|
||||
-- Doesn't close the output file, but returns the file object
|
||||
local function do_filter_prefix(input, output, prefix)
|
||||
local f = io.open(output, 'w+')
|
||||
local l = prefix:len()
|
||||
|
||||
for line in io.lines(input) do
|
||||
if line:sub(1, l) ~= prefix then
|
||||
f:write(line, '\n')
|
||||
end
|
||||
end
|
||||
|
||||
return f
|
||||
end
|
||||
|
||||
|
||||
local function escape_args(ret, arg0, ...)
|
||||
if not arg0 then
|
||||
return ret
|
||||
end
|
||||
|
||||
return escape_args(ret .. "'" .. string.gsub(arg0, "'", "'\\''") .. "' ", ...)
|
||||
end
|
||||
|
||||
|
||||
local os = os
|
||||
local string = string
|
||||
local tonumber = tonumber
|
||||
|
||||
local nixio = require 'nixio'
|
||||
local sysconfig = require 'gluon.sysconfig'
|
||||
|
||||
|
||||
module 'gluon.util'
|
||||
|
||||
function exec(...)
|
||||
return os.execute(escape_args('', ...))
|
||||
end
|
||||
|
||||
-- Removes all lines starting with a prefix from a file, optionally adding a new one
|
||||
function replace_prefix(file, prefix, add)
|
||||
local tmp = file .. '.tmp'
|
||||
local f = do_filter_prefix(file, tmp, prefix)
|
||||
if add then
|
||||
f:write(add)
|
||||
end
|
||||
f:close()
|
||||
os.rename(tmp, file)
|
||||
end
|
||||
|
||||
function lock(file)
|
||||
exec('lock', file)
|
||||
end
|
||||
|
||||
function unlock(file)
|
||||
exec('lock', '-u', file)
|
||||
end
|
||||
|
||||
function node_id()
|
||||
return string.gsub(sysconfig.primary_mac, ':', '')
|
||||
end
|
||||
|
||||
-- Generates a (hopefully) unique MAC address
|
||||
-- The first parameter defines the function and the second
|
||||
-- parameter an ID to add to the MAC address
|
||||
-- Functions and IDs defined so far:
|
||||
-- (1, 0): WAN (for mesh-on-WAN)
|
||||
-- (1, 1): LAN (for mesh-on-LAN)
|
||||
-- (2, n): client interface for the n'th radio
|
||||
-- (3, n): adhoc interface for n'th radio
|
||||
-- (4, 0): mesh VPN
|
||||
function generate_mac(f, i)
|
||||
local m1, m2, m3, m4, m5, m6 = string.match(sysconfig.primary_mac, '(%x%x):(%x%x):(%x%x):(%x%x):(%x%x):(%x%x)')
|
||||
m1 = nixio.bit.bor(tonumber(m1, 16), 0x02)
|
||||
m2 = (tonumber(m2, 16)+f) % 0x100
|
||||
m3 = (tonumber(m3, 16)+i) % 0x100
|
||||
|
||||
return string.format('%02x:%02x:%02x:%s:%s:%s', m1, m2, m3, m4, m5, m6)
|
||||
end
|
40
package/gluon-cron/Makefile
Normal file
40
package/gluon-cron/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gluon-cron
|
||||
PKG_VERSION:=1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gluon-cron
|
||||
SECTION:=gluon
|
||||
CATEGORY:=Gluon
|
||||
TITLE:=Cron support
|
||||
DEPENDS:=+gluon-core
|
||||
endef
|
||||
|
||||
define Package/gluon-cron/description
|
||||
Gluon community wifi mesh firmware framework: cron support
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS)
|
||||
endef
|
||||
|
||||
define Package/gluon-cron/install
|
||||
$(CP) ./files/* $(1)/
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-crond $(1)/usr/sbin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gluon-cron))
|
18
package/gluon-cron/files/etc/init.d/gluon-cron
Executable file
18
package/gluon-cron/files/etc/init.d/gluon-cron
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2013 Project Gluon
|
||||
|
||||
START=50
|
||||
|
||||
SERVICE_USE_PID=1
|
||||
SERVICE_WRITE_PID=1
|
||||
SERVICE_DAEMONIZE=1
|
||||
|
||||
CRONDIR=/lib/gluon/cron
|
||||
|
||||
start () {
|
||||
service_start /usr/sbin/gluon-crond "$CRONDIR"
|
||||
}
|
||||
|
||||
stop() {
|
||||
service_stop /usr/sbin/gluon-crond
|
||||
}
|
0
package/gluon-cron/files/lib/gluon/cron/.keep
Normal file
0
package/gluon-cron/files/lib/gluon/cron/.keep
Normal file
3
package/gluon-cron/src/Makefile
Normal file
3
package/gluon-cron/src/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
all: gluon-crond
|
||||
|
||||
gluon-crond: gluon-crond.c
|
316
package/gluon-cron/src/gluon-crond.c
Normal file
316
package/gluon-cron/src/gluon-crond.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
Copyright (c) 2013, Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
typedef struct job {
|
||||
struct job *next;
|
||||
|
||||
uint64_t minutes;
|
||||
uint32_t hours;
|
||||
uint32_t doms;
|
||||
uint16_t months;
|
||||
uint8_t dows;
|
||||
|
||||
char *command;
|
||||
} job_t;
|
||||
|
||||
|
||||
static const char const *const MONTHS[12] = {
|
||||
"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
|
||||
};
|
||||
|
||||
static const char const *const WEEKDAYS[7] = {
|
||||
"sun", "mon", "tue", "wed", "thu", "fri", "sat"
|
||||
};
|
||||
|
||||
|
||||
static const char *crondir;
|
||||
|
||||
static job_t *jobs = NULL;
|
||||
|
||||
|
||||
static void usage(void) {
|
||||
fprintf(stderr, "Usage: gluon-crond <crondir>\n");
|
||||
}
|
||||
|
||||
|
||||
static inline uint64_t bit(unsigned b) {
|
||||
return ((uint64_t)1) << b;
|
||||
}
|
||||
|
||||
static int strict_atoi(const char *s) {
|
||||
char *end;
|
||||
int ret = strtol(s, &end, 10);
|
||||
|
||||
if (*end)
|
||||
return -1;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t parse_strings(const char *input, const char *const *strings, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strcasecmp(input, strings[i]) == 0)
|
||||
return bit(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t parse_times(char *input, int min, int n) {
|
||||
uint64_t ret = 0;
|
||||
int step = 1;
|
||||
|
||||
char *comma = strchr(input, ',');
|
||||
if (comma) {
|
||||
*comma = 0;
|
||||
ret = parse_times(comma+1, min, n);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *slash = strchr(input, '/');
|
||||
if (slash) {
|
||||
*slash = 0;
|
||||
step = strict_atoi(slash+1);
|
||||
|
||||
if (step <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int begin, end;
|
||||
char *minus = strchr(input, '-');
|
||||
if (minus) {
|
||||
*minus = 0;
|
||||
begin = strict_atoi(input);
|
||||
end = strict_atoi(minus+1);
|
||||
}
|
||||
else if (strcmp(input, "*") == 0) {
|
||||
begin = min;
|
||||
end = min+n-1;
|
||||
}
|
||||
else {
|
||||
begin = end = strict_atoi(input);
|
||||
}
|
||||
|
||||
if (begin < min || end < min)
|
||||
return 0;
|
||||
|
||||
int i;
|
||||
for (i = begin-min; i <= end-min; i += step)
|
||||
ret |= bit(i % n);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_line(const char *line) {
|
||||
job_t job = {};
|
||||
int ret = -1;
|
||||
char *columns[5];
|
||||
int i;
|
||||
int len;
|
||||
|
||||
int matches = sscanf(line, "%ms %ms %ms %ms %ms %n", &columns[0], &columns[1], &columns[2], &columns[3], &columns[4], &len);
|
||||
if (matches != 5 && matches != 6) {
|
||||
if (matches <= 0)
|
||||
ret = 0;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
job.minutes = parse_times(columns[0], 0, 60);
|
||||
if (!job.minutes)
|
||||
goto end;
|
||||
|
||||
job.hours = parse_times(columns[1], 0, 24);
|
||||
if (!job.hours)
|
||||
goto end;
|
||||
|
||||
job.doms = parse_times(columns[2], 1, 31);
|
||||
if (!job.doms)
|
||||
goto end;
|
||||
|
||||
|
||||
job.months = parse_strings(columns[3], MONTHS, 12);
|
||||
|
||||
if (!job.months)
|
||||
job.months = parse_times(columns[3], 1, 12);
|
||||
if (!job.months)
|
||||
goto end;
|
||||
|
||||
job.dows = parse_strings(columns[4], WEEKDAYS, 7);
|
||||
if (!job.dows)
|
||||
job.dows = parse_times(columns[4], 0, 7);
|
||||
if (!job.dows)
|
||||
goto end;
|
||||
|
||||
job.command = strdup(line+len);
|
||||
|
||||
job_t *jobp = malloc(sizeof(job_t));
|
||||
*jobp = job;
|
||||
|
||||
jobp->next = jobs;
|
||||
jobs = jobp;
|
||||
|
||||
ret = 0;
|
||||
|
||||
end:
|
||||
for (i = 0; i < matches && i < 5; i++)
|
||||
free(columns[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void read_crontab(const char *name) {
|
||||
FILE *file = fopen(name, "r");
|
||||
if (!file) {
|
||||
syslog(LOG_WARNING, "unable to read crontab `%s'", name);
|
||||
return;
|
||||
}
|
||||
|
||||
char line[16384];
|
||||
unsigned lineno = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
lineno++;
|
||||
|
||||
char *comment = strchr(line, '#');
|
||||
if (comment)
|
||||
*comment = 0;
|
||||
|
||||
if (handle_line(line))
|
||||
syslog(LOG_WARNING, "syntax error in `%s', line %u", name, lineno);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
static void read_crondir(void) {
|
||||
DIR *dir;
|
||||
|
||||
if (chdir(crondir) || ((dir = opendir(".")) == NULL)) {
|
||||
fprintf(stderr, "Unable to read crondir `%s'\n", crondir);
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
read_crontab(ent->d_name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
static void run_job(const job_t *job) {
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
execl("/bin/sh", "/bin/sh", "-c", job->command, (char*)NULL);
|
||||
syslog(LOG_ERR, "unable to run job: exec failed");
|
||||
_exit(1);
|
||||
}
|
||||
else if (pid < 0) {
|
||||
syslog(LOG_ERR, "unable to run job: fork failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void check_job(const job_t *job, const struct tm *tm) {
|
||||
if (!(job->minutes & bit(tm->tm_min)))
|
||||
return;
|
||||
|
||||
if (!(job->hours & bit(tm->tm_hour)))
|
||||
return;
|
||||
|
||||
if (!(job->doms & bit(tm->tm_mday-1)))
|
||||
return;
|
||||
|
||||
if (!(job->months & bit(tm->tm_mon)))
|
||||
return;
|
||||
|
||||
if (!(job->dows & bit(tm->tm_wday)))
|
||||
return;
|
||||
|
||||
run_job(job);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
|
||||
exit(argc < 2 ? 0 : 1);
|
||||
}
|
||||
|
||||
crondir = argv[1];
|
||||
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
read_crondir();
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm *tm = localtime(&t);
|
||||
int minute = tm->tm_min;
|
||||
|
||||
while (1) {
|
||||
sleep(60 - t%60);
|
||||
|
||||
t = time(NULL);
|
||||
tm = localtime(&t);
|
||||
|
||||
minute = (minute+1)%60;
|
||||
if (tm->tm_min != minute) {
|
||||
/* clock has moved, don't execute jobs */
|
||||
minute = tm->tm_min;
|
||||
continue;
|
||||
}
|
||||
|
||||
job_t *job;
|
||||
for (job = jobs; job; job = job->next)
|
||||
check_job(job, tm);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user