From 040bd1324eaa1b68350b134676530fca90e5f941 Mon Sep 17 00:00:00 2001 From: eleksir Date: Mon, 24 Feb 2020 16:28:05 +0300 Subject: [PATCH] Initial commit --- AUTHORS | 1 + COPYING | 1 + LICENSE | 19 ++++ README | 15 +++ TODO | 6 ++ doc/examples/svc.json | 6 ++ doc/man/runit-svc.1 | 37 +++++++ doc/slackbuild/runit-svc.SlackBuild | 69 ++++++++++++ doc/slackbuild/slack-desc | 19 ++++ doc/slackbuild/slack-required | 2 + src/runit-svc | 161 ++++++++++++++++++++++++++++ 11 files changed, 336 insertions(+) create mode 100644 AUTHORS create mode 120000 COPYING create mode 100644 LICENSE create mode 100644 README create mode 100644 TODO create mode 100644 doc/examples/svc.json create mode 100644 doc/man/runit-svc.1 create mode 100644 doc/slackbuild/runit-svc.SlackBuild create mode 100644 doc/slackbuild/slack-desc create mode 100644 doc/slackbuild/slack-required create mode 100644 src/runit-svc diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..1f7ef4d --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Sergei Fedosoff diff --git a/COPYING b/COPYING new file mode 120000 index 0000000..7a694c9 --- /dev/null +++ b/COPYING @@ -0,0 +1 @@ +LICENSE \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d10c802 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright 2020 Sergei Fedosoff + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..686e67f --- /dev/null +++ b/README @@ -0,0 +1,15 @@ +svc - runit sv replacement utility. + +Svc was created because of there is no mean to manage services, running under +runsvdir from user. Despite of docs runit native utility disregard environment +variable SVDIR when looking for service, so all services MUST be in /service +dir which is not user writable. + +Also sv is unable to list, enable, disable and restart services. + +There is sample config file for user services, it is located in doc/examples. +It should be placed in ~/.local/etc directory of non-root user. + +For system-wide services there is no config file required. + +Requirements: perl, perl-JSON-PP (both already supplied with slackware linux) diff --git a/TODO b/TODO new file mode 100644 index 0000000..55b8702 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +There is some thing that are not critical, but should be done, eventually. + + +1. Regard SVDIR environment variable, to be more good than original sv utility. + +2. Think about XDG compliance for user config. diff --git a/doc/examples/svc.json b/doc/examples/svc.json new file mode 100644 index 0000000..fc37f3b --- /dev/null +++ b/doc/examples/svc.json @@ -0,0 +1,6 @@ +{ + "mode": "user", + "dir": "/.local/etc/services", + "servicedir": "/.local/etc/service.d", + "timeout": 3 +} diff --git a/doc/man/runit-svc.1 b/doc/man/runit-svc.1 new file mode 100644 index 0000000..c2ac33c --- /dev/null +++ b/doc/man/runit-svc.1 @@ -0,0 +1,37 @@ +.TH "SVC" "1" "24 February 2020" +.SH "NAME" +runit-svc \- sv replacement tool for runit +.SH "SYNOPSIS" +.B svc +SERVICE_NAME start|stop|restart|status|enable|disable +.br +.B svc +list [--all] +.SH "DESCRIPTION" +.PP +Manipulates system or user runit-services. +.SH "OPTIONS" +.TP +\fBsvc list\fR +Show enabled services list for system or user +.TP +\fBsvc list \-\-all\fR +Show all services for system or user +.TP +\fBsvc SERVICE_NAME start|stop|restart|status\fR +Starts, stops, restarts, show status of service +.TP +\fBsvc SERVICE_NAME disable\fR +Disables service. Note that service will be stopped immediately after disabling. +.TP +\fBsvc SERVICE_NAME enable\fR +Enables service. Note that service will be started immediately after enabling. +.TP +.SH "AUTHOR" +.TP +Sergei Fedosoff aka eleksir +.SH "COPYRIGHT" +Copyright \*R 2020 Sergei Fedosoff. License 2 clause BSD: +https://directory.fsf.org/wiki?title=License:FreeBSD +.SH "SEE ALSO" +.B sv (1). diff --git a/doc/slackbuild/runit-svc.SlackBuild b/doc/slackbuild/runit-svc.SlackBuild new file mode 100644 index 0000000..7852689 --- /dev/null +++ b/doc/slackbuild/runit-svc.SlackBuild @@ -0,0 +1,69 @@ +#!/bin/bash + +# Slackware build script for runit-svc + +# Copyright 2020 Sergei Fedosoff +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "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 AUTHOR 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. + +PRGNAM=runit-svc +VERSION=${VERSION:-0.1} +BUILD=${BUILD:-1} +TAG=${TAG:-_EXs} + +if [ -z "$ARCH" ]; then + case "$( uname -m )" in + i?86) ARCH=i586 ;; + arm*) ARCH=arm ;; + *) ARCH=$( uname -m ) ;; + esac +fi + +CWD=$(pwd) +TMP=${TMP:-/tmp/EXs} +PKG=${PKG:-$TMP/package-$PRGNAM} +OUTPUT=${OUTPUT:-/tmp} + +set -e + +rm -rf $PKG +mkdir -p $TMP $PKG $OUTPUT +cd $TMP +rm -rf $PRGNAM-$VERSION +tar xvf $CWD/$PRGNAM-$VERSION.tar.gz +cd $PRGNAM-$VERSION +chown -R root:root . + +install -Dpm 0755 src/runit-svc $PKG/usr/bin/runit-svc +ln -s /usr/bin/runit-svc $PKG/usr/bin/svc +mkdir -p $PKG/usr/man/man1 +gzip -9c doc/man/runit-svc.1 > $PKG/usr/man/man1/svc.1.gz +gzip -9c doc/man/runit-svc.1 > $PKG/usr/man/man1/runit-svc.1.gz +install -Dpm 0644 doc/examples/svc.json $PKG/usr/doc/$PRGNAM-$VERSION/examples/svc.json +install -Dpm 0644 README $PKG/usr/doc/$PRGNAM-$VERSION/README +install -Dpm 0644 LICENSE $PKG/usr/doc/$PRGNAM-$VERSION/LICENSE +install -Dpm 0644 AUTHORS $PKG/usr/doc/$PRGNAM-$VERSION/AUTHORS + +install -Dpm 0644 $CWD/$PRGNAM.SlackBuild $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild + +install -Dpm 0644 $CWD/slack-desc $PKG/install/slack-desc +install -Dpm 0644 $CWD/slack-required $PKG/install/slack-required + +cd $PKG +/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.${PKGTYPE:-tgz} diff --git a/doc/slackbuild/slack-desc b/doc/slackbuild/slack-desc new file mode 100644 index 0000000..c10d732 --- /dev/null +++ b/doc/slackbuild/slack-desc @@ -0,0 +1,19 @@ +# HOW TO EDIT THIS FILE: +# The "handy ruler" below makes it easier to edit a package description. +# Line up the first '|' above the ':' following the base package name, and +# the '|' on the right side marks the last column you can put a character in. +# You must make exactly 11 lines for the formatting to be correct. It's also +# customary to leave one space after the ':' except on otherwise blank lines. + + |-----handy-ruler------------------------------------------------------| +runit-svc: runit-svc (runit sv utility replacement) +runit-svc: +runit-svc: +runit-svc: +runit-svc: +runit-svc: +runit-svc: +runit-svc: +runit-svc: Homepage: https://github.com/eleksir/runit-svc +runit-svc: +runit-svc: diff --git a/doc/slackbuild/slack-required b/doc/slackbuild/slack-required new file mode 100644 index 0000000..7584ba8 --- /dev/null +++ b/doc/slackbuild/slack-required @@ -0,0 +1,2 @@ +runit +perl diff --git a/src/runit-svc b/src/runit-svc new file mode 100644 index 0000000..967856b --- /dev/null +++ b/src/runit-svc @@ -0,0 +1,161 @@ +#!/usr/bin/perl + +# runit sv utility ignores evironment variable SVDIR +# and unable to list services, fully relying to user this knowlege + +use strict; +use warnings "all"; +use JSON::PP; + +sub help; +sub ctrl ($); +sub status; + +my $c; + +if ($>) { +# looks like we run in user-mode, so manage user services + die "\$HOME is not set\n" unless (defined($ENV{HOME})); + die "$ENV{HOME} does not exist\n" unless (-d $ENV{HOME}); + + my $sep = $/; + $/ = ''; + +# TODO: actually, to be the most XDG-compatible, we should put config to $ENV{HOME}/.config/svc/svc.json + open (CONF, "$ENV{HOME}/.local/etc/svc.json") or die "No config at $ENV{HOME}/.local/etc/svc.json\n"; + $c = ; + close CONF; + $/ = $sep; + + $c = decode_json($c); + $c->{dir} = sprintf("%s%s", $ENV{HOME}, $c->{dir}); + $c->{servicedir} = sprintf("%s%s", $ENV{HOME}, $c->{servicedir}); +} else { +# looks like we run with root privileges, manage system services + $c->{mode} = "system"; + $c->{dir} = "/etc/service"; + + if (-d "/etc/service.d") { + $c->{servicedir} = "/etc/service.d"; + } else { + +# guideline of runit suggest to use /service directory, also sv utility expects services placed there by default + $c->{servicedir} = "/service"; + } + + $c->{timeout} = 3; +} + +die "No such directory $c->{dir}\n" unless (-d $c->{dir}); +chdir $c->{dir}; + +unless (defined($ARGV[0])) { + help; +} else { + if ($ARGV[0] ne 'list') { + help unless (defined($ARGV[1])); + } +} + +if ($ARGV[0] eq 'list') { + my $d; + + if (defined($ARGV[1]) && $ARGV[1] eq '--all') { + $d = $c->{servicedir}; + } else { + $d = $c->{dir}; + } + + opendir(D, $d) or die "Unable to list services, no such directory $d\n"; + print join("\n", sort (grep {!/^\.{1,2}$/} readdir(D))) . "\n"; + closedir D; +} elsif ($ARGV[1] eq 'disable') { + my $d = "$c->{dir}/$ARGV[0]"; + + if (-l $d) { + unlink ("$d") or die "Unable to disable $ARGV[0]\n"; + } else { + die "No such service $ARGV[0]\n"; + } +} elsif ($ARGV[1] eq 'enable') { + my $d = "$c->{dir}/$ARGV[0]"; + + if (-l $d) { + die "Service $ARGV[0] already enabled\n"; + } else { + my $svcdir = "$c->{servicedir}/$ARGV[0]"; + + if (-d $svcdir) { + symlink ($svcdir, $d) or die "Unable to enable service $ARGV[0]\n"; + } else { + die "No such service $ARGV[0]\n"; + } + } +} elsif ((-l "./$ARGV[0]") || (-d "./$ARGV[0]")) { + chdir "./$ARGV[0]"; + die "Is service running?\n" unless (-d './supervise'); + chdir './supervise'; + + if ($ARGV[1] eq 'start') { + die "Service $ARGV[0] already running.\n" if (status() eq 'run'); + ctrl('u'); + } elsif ($ARGV[1] eq 'restart') { + die "Service $ARGV[0] already stopped.\n" if (status() eq 'down'); + ctrl('d'); + + for (my $cnt = 0; $cnt < $c->{timeout}; $cnt++) { + if (status() eq 'down') { + last; + } + + sleep 1; + } + + ctrl('k') if (status() ne 'down'); + sleep 1; + ctrl('u'); + } elsif ($ARGV[1] eq 'stop') { + die "Service $ARGV[0] already stopped.\n" if (status() eq 'down'); + ctrl('d'); + + for (my $cnt = 0; $cnt < $c->{timeout}; $cnt++) { + if (status() eq 'down') { + last; + } + + sleep 1; + } + + ctrl('k') if (status() ne 'down'); + sleep 1; + } elsif ($ARGV[1] eq 'status') { + print status() . "\n"; + } +} else { + die "No such service.\n"; +} + +exit 0; + +sub help { + print "Usage $0 SERVICE [start|stop|restart|status|enable|disable]\n"; + print " $0 list [--all]\n"; + exit 0; +} + +sub ctrl ($) { + my $command = shift; + open (C, ">", "control") or die "Unable to write to control socket\n"; + print C $command; + close C; +} + +sub status { + open (S, "stat") or die "Unable to read status.\n"; + my $status = ; + chomp $status; + close S; + return $status; +} + +# vim: set ft=perl noet ai ts=4 sw=4 sts=4: