From cea67383191e1ab8e78a8f7eccf387e4a4b1dcb9 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 25 Jun 2018 23:37:51 -0600 Subject: [PATCH] add preliminary user systemd support --- .gitignore | 4 + bin/telebit.js | 4 + bin/telebitd.js | 5 +- lib/cli-common.js | 25 ++-- .../.config/systemd/user/telebit.service.tpl | 64 ++++++++++ usr/share/install_helper.sh | 112 ++++++++---------- usr/share/install_launcher.sh | 46 +++++++ usr/share/template-launcher.js | 3 + 8 files changed, 183 insertions(+), 80 deletions(-) create mode 100644 usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl create mode 100644 usr/share/install_launcher.sh diff --git a/.gitignore b/.gitignore index ea7292b..54ebd46 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,10 @@ bin/npx bin/telebit bin/telebitd bin/telebit_uninstall +usr/share/dist/Library/LaunchDaemons/cloud.telebit.remote.plist +usr/share/dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist +usr/share/dist/etc/systemd/system/telebit.service +usr/share/dist/etc/skel/.config/systemd/user/telebit.service ./etc/ ./include/ ./share/ diff --git a/bin/telebit.js b/bin/telebit.js index b17aa70..ca99202 100755 --- a/bin/telebit.js +++ b/bin/telebit.js @@ -416,6 +416,10 @@ function parseConfig(err, text) { } state.config = camelCopy(state.config || {}) || {}; + common._init( + state.config.root || path.join(os.homedir(), '.local/share/telebit') + , (state.config.root && path.join(state.config.root, 'etc')) || path.join(os.homedir(), '.config/telebit') + ); state._ipc = common.pipename(state.config, true); if (!Object.keys(state.config).length) { diff --git a/bin/telebitd.js b/bin/telebitd.js index 8d5e31e..ec7406f 100755 --- a/bin/telebitd.js +++ b/bin/telebitd.js @@ -8,7 +8,6 @@ var url = require('url'); var path = require('path'); var os = require('os'); var fs = require('fs'); -var urequest = require('@coolaj86/urequest'); var common = require('../lib/cli-common.js'); var http = require('http'); var YAML = require('js-yaml'); @@ -439,6 +438,10 @@ function parseConfig(err, text) { if (!state.config) { state.config = {}; } + common._init( + state.config.root || path.join(__dirname, '..') + , path.join(state.config.root || path.join(__dirname, '..'), 'etc') + ); state._ipc = common.pipename(state.config, true); console.info(''); console.info(verstr.join(' ')); diff --git a/lib/cli-common.js b/lib/cli-common.js index a299da5..84f22b5 100644 --- a/lib/cli-common.js +++ b/lib/cli-common.js @@ -217,19 +217,12 @@ common.api.token = function (state, handlers) { }; -try { - mkdirp.sync(path.join(__dirname, '..', 'var', 'log')); - mkdirp.sync(path.join(__dirname, '..', 'var', 'run')); - mkdirp.sync(path.join(__dirname, '..', 'etc')); -} catch(e) { - console.error(e); -} - -try { - mkdirp.sync(path.join(homedir, localshare, 'var', 'log')); - mkdirp.sync(path.join(homedir, localshare, 'var', 'run')); - //mkdirp.sync(path.join(homedir, localshare, 'etc')); - mkdirp.sync(path.join(homedir, localconf)); -} catch(e) { - console.error(e); -} +common._init = function (rootpath, confpath) { + try { + mkdirp.sync(path.join(rootpath, 'var', 'log')); + mkdirp.sync(path.join(rootpath, 'var', 'run')); + mkdirp.sync(path.join(confpath)); + } catch(e) { + console.error(e); + } +}; diff --git a/usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl b/usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl new file mode 100644 index 0000000..7249d79 --- /dev/null +++ b/usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl @@ -0,0 +1,64 @@ +# Pre-req +# sudo adduser telebit --home {TELEBIT_PATH} +# sudo mkdir -p {TELEBIT_PATH}/ +# sudo chown -R {TELEBIT_USER}:{TELEBIT_GROUP} {TELEBIT_PATH}/ + +[Unit] +Description=Telebit Remote +Documentation=https://git.coolaj86.com/coolaj86/telebit.js/ +; After=network-online.target +; Wants=network-online.target systemd-networkd-wait-online.service + +[Service] +# Restart on crash (bad signal), and also on 'clean' failure (error exit code) +# Allow up to 3 restarts within 10 seconds +# (it's unlikely that a user or properly-running script will do this) +Restart=always +StartLimitInterval=10 +StartLimitBurst=3 + +# User and group the process will run as +#User={TELEBIT_USER} +#Group={TELEBIT_GROUP} + +WorkingDirectory={TELEBIT_PATH} +# custom directory cannot be set and will be the place where this exists, not the working directory +ExecStart={TELEBIT_PATH}/bin/node {TELEBIT_PATH}/bin/telebitd.js daemon --config {TELEBIT_PATH}/etc/telebitd.yml +ExecReload=/bin/kill -USR1 $MAINPID + +# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings. +# Unmodified, this is not expected to use more than this. +LimitNOFILE=1048576 +LimitNPROC=64 + +# Use private /tmp and /var/tmp, which are discarded after this stops. +PrivateTmp=true +# Use a minimal /dev +PrivateDevices=true +# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys. +ProtectHome=true +# Make /usr, /boot, /etc and possibly some more folders read-only. +ProtectSystem=full +# ... except for a few because we want a place for config, logs, etc +# This merely retains r/w access rights, it does not add any new. +# Must still be writable on the host! +ReadWriteDirectories={TELEBIT_RW_DIRS} + +# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories +; ReadWritePaths={TELEBIT_RW_DIRS} + +# The following additional security directives only work with systemd v229 or later. +# They further retrict privileges that can be gained. +# Note that you may have to add capabilities required by any plugins in use. +;CapabilityBoundingSet=CAP_NET_BIND_SERVICE +;AmbientCapabilities=CAP_NET_BIND_SERVICE +;NoNewPrivileges=true + +# Caveat: Some features may need additional capabilities. +# For example an "upload" may need CAP_LEASE +; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE +; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE +; NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target diff --git a/usr/share/install_helper.sh b/usr/share/install_helper.sh index 56f75d9..3b8d69d 100644 --- a/usr/share/install_helper.sh +++ b/usr/share/install_helper.sh @@ -209,12 +209,18 @@ set -x if [ "$(type -p launchctl)" ]; then sudo launchctl unload -w /Library/LaunchDaemons/${my_app_pkg_name}.plist sudo rm -f /Library/LaunchDaemons/${my_app_pkg_name}.plist + launchctl unload -w ~/Library/LaunchAgents/${my_app_pkg_name}.plist rm -f ~/Library/LaunchAgents/${my_app_pkg_name}.plist fi if [ "$(type -p systemctl)" ]; then - sudo systemctl disable $my_app >/dev/null; sudo systemctl stop $my_app - sudo rm -rf /etc/systemd/system/$my_app.service + systemctl --user disable $my_app >/dev/null + systemctl --user stop $my_app + rm -f ~/.config/systemd/user/$my_app.service + + sudo systemctl disable $my_app >/dev/null + sudo systemctl stop $my_app + sudo rm -f /etc/systemd/system/$my_app.service fi sudo rm -rf $TELEBIT_REAL_PATH /usr/local/bin/$my_app sudo rm -rf $TELEBIT_REAL_PATH /usr/local/bin/$my_daemon @@ -289,6 +295,7 @@ mkdir -p "$(dirname $TELEBIT_TMP_CONFIGD)" if [ ! -e "$TELEBIT_CONFIGD" ]; then echo "sock: $TELEBIT_SOCK" >> "$TELEBIT_TMP_CONFIGD" + echo "root: $TELEBIT_REAL_PATH" >> "$TELEBIT_TMP_CONFIGD" cat $TELEBIT_REAL_PATH/usr/share/$my_daemon.tpl.yml >> "$TELEBIT_TMP_CONFIGD" fi @@ -350,64 +357,18 @@ if [ -d "/Library/LaunchDaemons" ]; then elif [ -d "$my_root/etc/systemd/system" ]; then my_system_launcher="systemd" - # TODO handle Linux userspace systemd - echo " > ${real_sudo_cmde}$rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service" - $real_sudo_cmd $rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service" "/etc/systemd/system/$my_app.service" - - $real_sudo_cmd systemctl daemon-reload - echo " > ${real_sudo_cmde}systemctl enable $my_app" - $real_sudo_cmd systemctl enable $my_app >/dev/null + if [ "yes" == "$TELEBIT_USERSPACE" ]; then + echo " > $rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/etc/skel/.config/systemd/user/$my_app.service ~/.config/systemd/user/$my_app.service" + $rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/etc/skel/.config/systemd/user/$my_app.service" "~/.config/systemd/user/$my_app.service" + systemctl --user daemon-reload + else + echo " > ${real_sudo_cmde}$rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service" + $real_sudo_cmd $rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service" "/etc/systemd/system/$my_app.service" + $real_sudo_cmd systemctl daemon-reload + fi fi sleep 1 -echo "" -echo "" -echo "==============================================" -echo " Launcher Configuration " -echo "==============================================" -echo "" - -my_stopper="" -if [ "systemd" == "$my_system_launcher" ]; then - - my_stopper="${real_sudo_cmde}systemctl stop $my_app" - echo "Edit the config and restart, if desired:" - echo "" - echo " ${real_sudo_cmde}$my_edit $TELEBIT_CONFIGD" - echo " ${real_sudo_cmde}systemctl restart $my_app" - echo "" - echo "Or disabled the service and start manually:" - echo "" - echo " ${real_sudo_cmde}systemctl stop $my_app" - echo " ${real_sudo_cmde}systemctl disable $my_app" - echo " $my_daemon --config $TELEBIT_CONFIGD" - -elif [ "launchd" == "$my_system_launcher" ]; then - - my_stopper="${real_sudo_cmde}launchctl unload $my_app_launchd_service" - echo "Edit the config and restart, if desired:" - echo "" - echo " ${real_sudo_cmde}$my_edit $TELEBIT_CONFIGD" - echo " ${real_sudo_cmde}launchctl unload $my_app_launchd_service" - echo " ${real_sudo_cmde}launchctl load -w $my_app_launchd_service" - echo "" - echo "Or disabled the service and start manually:" - echo "" - echo " ${real_sudo_cmde}launchctl unload -w $my_app_launchd_service" - echo " $my_daemon --config $TELEBIT_CONFIGD" - -else - - my_stopper="not started" - echo "" - echo "Run the service manually (we couldn't detect your system service to do that automatically):" - echo "" - echo " $my_daemon --config $TELEBIT_CONFIGD" - echo " $my_app --config $TELEBIT_CONFIG" - -fi - -sleep 2 ############################### # Actually Launch the Service # @@ -423,16 +384,41 @@ if [ "launchd" == "$my_system_launcher" ]; then $real_sudo_cmd launchctl load -w "$my_app_launchd_service" fi -fi -if [ "systemd" == "$my_system_launcher" ]; then - echo " > ${real_sudo_cmde}systemctl start $my_app" - $real_sudo_cmd systemctl restart $my_app +elif [ "systemd" == "$my_system_launcher" ]; then + + if [ "yes" == "$TELEBIT_USERSPACE" ]; then + # https://wiki.archlinux.org/index.php/Systemd/User + # sudo loginctl enable-linger username + + echo " > systemctl --user enable $my_app" + systemctl --user enable $my_app >/dev/null + echo " > systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer" + systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer + echo " > systemctl --user start $my_app" + systemctl --user restart $my_app + else + + echo " > ${real_sudo_cmde}systemctl enable $my_app" + $real_sudo_cmd systemctl enable $my_app >/dev/null + echo " > ${real_sudo_cmde}systemctl start $my_app" + $real_sudo_cmd systemctl restart $my_app + fi + +else + + echo "Run the service manually (we couldn't detect your system service to do that automatically):" + echo "" + echo " $my_daemon --config $TELEBIT_CONFIGD" + echo " $my_app --config $TELEBIT_CONFIG" + fi echo " > ${real_sudo_cmde}ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app" -$real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app +ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app 2>/dev/null || \ + $real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app echo " > ${real_sudo_cmde}ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon" -$real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon +ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon || \ + $real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon echo " > telebit init --tty" diff --git a/usr/share/install_launcher.sh b/usr/share/install_launcher.sh new file mode 100644 index 0000000..3855758 --- /dev/null +++ b/usr/share/install_launcher.sh @@ -0,0 +1,46 @@ +echo "" +echo "" +echo "==============================================" +echo " Launcher Configuration " +echo "==============================================" +echo "" + +my_stopper="" +if [ "systemd" == "$my_system_launcher" ]; then + + my_stopper="${real_sudo_cmde}systemctl stop $my_app" + echo "Edit the config and restart, if desired:" + echo "" + echo " ${real_sudo_cmde}$my_edit $TELEBIT_CONFIGD" + echo " ${real_sudo_cmde}systemctl restart $my_app" + echo "" + echo "Or disabled the service and start manually:" + echo "" + echo " ${real_sudo_cmde}systemctl stop $my_app" + echo " ${real_sudo_cmde}systemctl disable $my_app" + echo " $my_daemon --config $TELEBIT_CONFIGD" + +elif [ "launchd" == "$my_system_launcher" ]; then + + my_stopper="${real_sudo_cmde}launchctl unload $my_app_launchd_service" + echo "Edit the config and restart, if desired:" + echo "" + echo " ${real_sudo_cmde}$my_edit $TELEBIT_CONFIGD" + echo " ${real_sudo_cmde}launchctl unload $my_app_launchd_service" + echo " ${real_sudo_cmde}launchctl load -w $my_app_launchd_service" + echo "" + echo "Or disabled the service and start manually:" + echo "" + echo " ${real_sudo_cmde}launchctl unload -w $my_app_launchd_service" + echo " $my_daemon --config $TELEBIT_CONFIGD" + +else + + my_stopper="not started" + echo "" + echo "Run the service manually (we couldn't detect your system service to do that automatically):" + echo "" + echo " $my_daemon --config $TELEBIT_CONFIGD" + echo " $my_app --config $TELEBIT_CONFIG" + +fi diff --git a/usr/share/template-launcher.js b/usr/share/template-launcher.js index f584706..5b7a7e9 100644 --- a/usr/share/template-launcher.js +++ b/usr/share/template-launcher.js @@ -8,6 +8,9 @@ var files = [ [ (process.env.TELEBIT_SERVICE_TPL || path.join(__dirname, 'dist/etc/systemd/system/telebit.service.tpl')) , (process.env.TELEBIT_SERVICE || path.join(__dirname, 'dist/etc/systemd/system/telebit.service')) ] +, [ (process.env.TELEBIT_USER_SERVICE_TPL || path.join(__dirname, 'dist/etc/skel/.config/systemd/user/telebit.service.tpl')) + , (process.env.TELEBIT_USER_SERVICE || path.join(__dirname, 'dist/etc/skel/.config/systemd/user/telebit.service')) + ] , [ (process.env.TELEBIT_PLIST_TPL || path.join(__dirname, 'dist/Library/LaunchDaemons/cloud.telebit.remote.plist.tpl')) ,(process.env.TELEBIT_PLIST || path.join(__dirname, 'dist/Library/LaunchDaemons/cloud.telebit.remote.plist')) ]