Split: re-write of the /usr/sbin/service script

Forum Forums antiX-development Development Split: re-write of the /usr/sbin/service script

  • This topic has 7 replies, 2 voices, and was last updated Apr 17-11:19 am by CanToo.
Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • #139316
    Member
    CanToo

      Hello, this is my first post here. I joined especially out of interest for the init-diversity project. I’ve been working on a re-write of the /usr/sbin/service script to add support for both s6 and 66 -and possibly dinit.

      The original script was written first for sysvinit systems, later adding openrc and systemd. antix adds support for runit. The original supports up to 10 ‘standard’ service actions:
      start & stop – the only two actions which are supported by all systems -under different names, like up,down ..
      status – supported natively sometimes, depending on system and service. Must be worked around or ignored, where not
      restart – supported natively sometimes, but easy to work around with down-and-dirty start+stop

      reload force-reload force-stop – all easy to work around, except reload may use SIGHUP instead of start+stop
      try-restart – this may have been added for systemd and can be worked around

      enable & disable (at boot-time) – openrc equivalents to ‘add’ ‘del’ – this is the tough spot, especially for s6, because of need to re-compile database

      The original also supported two ‘internal’ actions, –force-restart( for services not supporting ‘restart’ ), and –status-all, which provides a nice visual output which is easily parsible. As with ‘status’, the problem is to get usable info about the service.

      For my re-write, I’ve implemented all the above, plus 3 more ‘internal’ operations. As above, they don’t ask an service script to perform the action. The 3 new ones are:
      –list-all list all available services
      –list-running list running services
      –status an arbitrary method to provide service status -possibly using ps & Co.

      All the options beginning with ‘–‘ should provide easy-to-parse outputs

      Since the original ‘service’ is mostly init and distro agnostic, I hope to do the same. s6 enable/disable is the most problematic, since there is no standard implementation or directory locations. I’ve implemented for antix and for Artix, and have looked at gentoo and voidlinux. void seems to have not really adopted it. gentoo maybe provides the most generic way to use s6-rc, but I need a bit more info to implement that or other distros.
      I need to know:
      #1 location of service directories sources which correspond to the running system.
      #2 location of bundle which can be modified when enabling/disable. This can be an available service-manager, a.k.a. antix-service-manager, or could be the default dir.
      #3 blacklist of non-removable services – see function ‘is_ignored_file’ in /usr/sbin/service
      The other info needed to re-compile DB can be gained programatically -real location of active database and scandir

      The end-goal is to provide a Universal back-end for any GUI service manager, or for use alone for non-gui systems like the two smallest antix flavours. The intent is not to create an elaborate service-manager -just to provide the most basic 10-15 operations shown above.

      I’m still doing some code cleanup, so I don’t post any code just yet. Where would a new thread for this fit best? Or maybe this post could be moved.

      #139317
      Moderator
      Brian Masinick

        @cantoo I love your idea and I enthusiastically (and patiently) await the completion of your work.

        For best visibility, clarity, and the ability to discuss the specifics of your work without getting it lost or mixed up with other conversations, yes, a separate topic in this same category containing /usr/sbin/service script somewhere in the title of the topic would be very helpful.

        Thank you for asking and also for sharing with us.

        --
        Brian Masinick

        #139320
        Member
        ProwlerGr

          @CanToo welcome to our community.
          As @Masinick mentioned it would be best to start another development thread in regards to your project.

          I can attempt to answer the following 3 questions which are also relevant to this thread:

          I need to know:
          #1 location of service directories sources which correspond to the running system.

          SERVICE_SOURCES=”/etc/s6-rc/sv”
          SERVICE_SCANDIR=”/run/s6-rc/scandir”
          COMPILED_SERVICE_DIRECTORY=”/etc/s6-rc/compiled/servicedirs”

          #2 location of bundle which can be modified when enabling/disable. This can be an available service-manager, a.k.a. antix-service-manager, or could be the default dir.

          You are right it is the “antix-service-manager” bundle that this GUI manages (adding removing starting stopping of services).
          Location of bundle is “/etc/s6-rc/sv/antix-service-manager”
          Obviously other bundles can be defined and modified but this needs to be done manually (not through the GUI)

          #3 blacklist of non-removable services – see function ‘is_ignored_file’ in /usr/sbin/service

          The “boot” bundle is intended to be as such having the “VITAL” services which should not be messed with by a standard user.

          I hope this helps

          #139322
          Member
          abc-nix

            @anticapitalista, could you upload to antiX’s gitlab a repo for init-system-helpers? I remember there was a problem some time ago, and having a repo to send the fixes would be great.

            The init-system-helpers package brings:

            /usr/sbin/invoke-rc.d
            /usr/sbin/service
            /usr/sbin/update-rc.d

            Changes that @CanToo is working on could be sent to this repo if created.

            #139327
            Member
            calciumsodium

              s6 enable/disable is the most problematic

              Hello,

              To enable/disable and to see the status of s6-66 services, @eric had mentioned:

              https://www.antixforum.com/forums/topic/antix-23-1_init-diversity-edition-sysvinit-runit-s6-rc-s6-66/page/15/#post-133985

              Hope this helps.

              #139374
              Member
              CanToo

                I’ve actually already implemented everything for systemd, sysvinit, openrc, and runit. 66 is also working -it has a built-in enable/disable. And I have s6-rc working for antix and artix(I think). The extra info needed pertains to other implementations that you guys may have examined or used. Anyway, I will create a new thread here under Development.

                #139440
                Member
                ProwlerGr

                  The init-system-helpers package brings:

                  /usr/sbin/invoke-rc.d
                  /usr/sbin/service
                  /usr/sbin/update-rc.d

                  Changes that @CanToo is working on could be sent to this repo if created.

                  This or the experimental “init-diversity-tools” package which contains the universal reboot/poweroff scripts.

                  –list-all list all available services
                  –list-running list running services
                  –status an arbitrary method to provide service status -possibly using ps & Co.

                  The gui tool uses

                  ls -l /etc/s6-rc/sv #lists all available services
                  s6-rc -ua list #lists all s6-rc services that are up
                  s6-rc -da list #lists services that are down
                  #139715
                  Member
                  CanToo

                    I had a lot of code cleanup to do before presenting anything.

                    I’m calling this re-implementation of /[usr/]sbin/service as ‘servize’, for the moment. It should already serve as a drop-in replacement for the original -supporting sysVinit, openrc, systemd and also the runit support added by antix. Right now, I can only test runit, s6 and 66 running antix-23.1-init-diversity on an i686 eeePC. So, confirmation that they are working will be needed -especially the s6 DB compile(whether changes really persist, etc). But let me explain where I’m going with this.

                    ‘service’ was written as “A wrapper for syvinit scripts”. Each script would support at least 2 actions: ‘start’ and ‘stop’. Some services still only support those two actions.
                    Naturally, more actions were often needed and came into common use. ‘service’ actually supports any ‘action’, since there is no explicit vocabulary of actions. But, 6 more actions comprised a pretty-standard set of 8 actions: start stop restart reload force-reload force-stop try-restart status
                    It’s easy to see that the 5 re*, force* and try* actions can be aliased to a 2-step start/stop or handled in some generic way. The last action, ‘status’ is a different matter since many service scripts (or init mgrs) do not report any useful status info. More on that in a minute. Anyway, ‘service’ explicitly adopts that 8-action vocabulary for the systemd support. And since nearly every other init/mgr will fallback on sysv scripts when an unknown actions is encountered, it makes sense to use that same vocabulary.

                    The original also included 2 extra actions: –full-restart and –status-all. –full-restart is just-another arbitrary stop/start.
                    –status-all brings us back to ‘status’. You can’t have the one without the other and some services don’t have a mechanism for getting it. On the other hand, some init managers give more than a page of colored out put. –status-all outputs a very simple, parsable and ‘pretty’ output with no special effects, so it can easily used as a backend for any TUI/GUI front-end …

                    In ‘servize’ I am implementing 3 additional –? actions : –list-all –list-running –status
                    As with the original –status-all, they should output uniform, easily parsible lists of services, and/or an exit status code. My inclination is that the normal ‘status’ output should be supplied by the underlying script or manager, and that –status only returns a meaningful exit value -and perhaps a one-word status descriptor. These 3 new actions are all implemented for all 6 inits. But normalizing the content of the lists, through black-listing and filtering, must be done. The same for the proposed exit codes from –status and symbols used by –status-all. Simpler inits/mgrs only have running or NOT running. systemd has all sorts of states: loaded active running dead exited enabled disabled, etc.

                    Now onto the last 2 critical thing I’m working on: enable disable
                    That is, low-level management of services at boot-time. It makes sense to name these without the ‘–‘, as some systems actually provide that feature, and as with ‘status’ they should do that natively and provide native output on stdout. Simpler systems equate ‘up’ with ‘enabled’, or won’t start a service unless it has first been enabled. systemctl does its’ own database thing, and others simple use links or empty files in order to start a service at boot-time, or prevent it from starting. Here S6 makes it all more difficult, because it requires a compiled (and working) database to successfully boot -and during use. It requires a compiled DB, but provides no mechanism for automated adding/removing items or ‘standard’ locations for the Service Directory sources(AFAIK).

                    So, we have a total of 15 actions:
                    start stop status restart restart reload force-reload force-stop try-restart
                    –status-all –full-restart –list-all –list-running –status
                    enable disable

                    My plan is not to create a comprehensive service-manager for any one system. Rather, a solid tool supporting the most common actions, no fuss, non-interactive able to be used as front-end, in itself, or especially as a back-end for something like runit/s6-service-manager. ( I must say I was surprised to see that libqt was being used. I would have expected gtkdialog, since libqt is not used elsewhere. )

                    Last note: what I’d first like to know is whether enable/disable is working on an s6 installation. And, generally, whether enable/disable are working everywhere as expected under runit, s6 and 66. I am able to test systemd, sysVinit and openrc on installations here.
                    Once enable/disable works for all 6, I will need lots of feedback on which services to show in the lists and blacklisting (a La is_ignored_file from ‘service’) -of course we don’t want to bork any systems.

                    Tried attaching the script, with no luck. I hate to post such a long script in-line, but here goes:

                    
                    #!/bin/sh
                    # Tested to run under: ksh dash busybox-ash zsh posh yash bash
                    ####################################################################
                    # /sbin/servize
                    # A wrapper for managing System Services under these 'init' types:
                    #   sysVinit  OpenRC  Runit  S6  S6-66  Systemd
                    ####################################################################
                    ## Complete Copyright and License Details (and some notes on the history)
                    ###########################################################################
                    #  This script is a re-implementation of the  /sbin/service utility
                    #  "A convenient wrapper for the /etc/init.d init scripts" 
                    # * originally found on Red Hat/Fedora systems (licensed GPLv2+).
                    # * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
                    #   note: The original probably only supported syVinit scripts.
                    # * Modifications by Ubuntu and Debian:
                    #   Copyright (C) 2006 Red Hat, Inc. All rights reserved.
                    #   Copyright (C) 2008 Canonical Ltd.
                    #   * August 2008 - Dustin Kirkland <kirkland@canonical.com>
                    #   Copyright (C) 2013 Michael Stapelberg <stapelberg@debian.org>
                    # * note: Latest above version supported: sysVinit OpenRC Systemd
                    #   note: Without tracking down old versions, it's unclear who added what.
                    #
                    # * Antix Linux (service-1.65.2+antix3) added support for: Runit
                    #   Credits unattributed
                    # * Antix 'init-diversity' versions provided ideas and code to 
                    #   add support for systems using s6-rc. More importantly, it
                    #   provided a convenient test-bed for Init Diversity, in general.
                    #   Credits unattributed  - The folks at Antix Linux are modest.
                    #
                    #   This implementation still contain code from the above Authors.
                    #   It adds support for 2 more 'init' systems: S6 and 66(s6-66).
                    #   -  low-level support for enabling/disabling services on boot
                    #   -  eliminates the use of 'sed' and 'grep'
                    #   It is named 'servize' to co-exist with any existing 'service' script.
                    # * Copyright (C) 2024 - Gilbert Ashley <perceptronic@proton.me>
                    #
                    ###########################################################################
                    # This program is free software; you can redistribute it and/or modify
                    # it under the terms of the GNU General Public License as published by
                    # the Free Software Foundation; either version 2 of the License, or
                    # (at your option) any later version.
                    #
                    # This program is distributed in the hope that it will be useful,
                    # but WITHOUT ANY WARRANTY; without even the implied warranty of
                    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                    # GNU General Public License for more details.
                    #
                    # You should have received a copy of the GNU General Public License
                    # along with this program; if not, write to the Free Software
                    # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                    # 
                    ###########################################################################
                    # 'servize' depends on only these externals: id, rm, ln, cp, and touch
                    # And these shell builtins: echo, cd, read, exec, test, and [
                    # May use: 'runlevel', 'which', 'update-rc.d', 'date' (init-dependent)
                    # Requires one of: sysvinit, openrc, runit, s6-rc, s6-66 or systemd 
                    # Disabling of shellcheck suggestions or warnings is done with caution.
                    # shellcheck disable=SC2086,SC2034
                    # 'servize' is a WIP, so is extra verbose at the moment, for testing
                    # The contents of service lists/status need to be normalized and
                    # service 'blacklists' may need additional entries
                    version="0.9"
                    # 17 April 2024  - Gilbert Ashley <perceptronic@proton.me>
                    #   - initial testing version - '0.9' = 10% of '1.0' {:-)
                    # For simplicity, require user to be root or use sudo/su, even
                    # though service information might be available to non-root users.
                    if [ "$(id -u)" != "0" ] ; then
                        echo "must be run as root or with sudo" >&2
                        exit
                    fi
                    # find out which init system is running
                    # 'ps --no-headers -o comm 1' or 'read -r </proc/1/cmdline'
                    # returns 's6-svcan' on both S6 an 66, so use readlink -f
                    init_type=$(readlink -f /sbin/init) ; init_type=${init_type##*/}
                    # 'read -r </proc/1/cmdline' would be useful if s6 'scandir' is unkown
                    # sysVinit service dirs are sometimes used by other 'init' programs,
                    # so make sure this location is always available, if present
                    if [ -d "/etc/init.d" ] ; then
                        SERVICEDIR="/etc/init.d"
                    elif [ -d "/etc/rc.d/init.d" ] ; then
                        # It's unsure whether anyone uses this anymore
                        SERVICEDIR="/etc/rc.d/init.d"
                        # either way, run-level dirs are at /etc/rc[0-6].d
                    fi
                    # find out the runlevel, if any (for enable/disable)
                    run_level=$(runlevel 2>/dev/null) ; run_level=${run_level##* }
                    case $run_level in ''|unknown)  ;;
                        *) run_level_dir="/etc/rc${run_level}.d" ;;
                    esac
                    # very rudimentary documentation as '--help' output
                    # pending finalization of Symbols and Exit codes
                    servize_help() {
                    echo "      ${0%-*} - Multi-Init Service Manager
                        
                        Usage: ${0%-*} Action [Service]
                        
                        'Action' is one of 8 common sysVinit service commands:
                        Most common: start stop restart status 
                        Less common: reload force-reload force-stop try-restart
                        
                        'Action' can also be 'enable' or 'disable'. Where not
                        implemented natively by the service-management tools,
                        'servize' implements them internally (see _s6).
                        Enabling a service means it Will start on next reboot.
                        Disabling it Prevents it from starting on next reboot.
                        
                        Additional generic Actions:
                        --full-restart 'Service' - stop and start 'Service'
                        --status 'Service' - Returns status code on stderr
                        Exit status: 0=running 1=idle 3=disabled 4=unknown
                        
                        Above Actions require a 'Service' name as 2nd argument.
                        
                        These Actions take no 'Service' name.
                        --list-all - List of all available services
                        --list-running  - List of all running services
                        --status-all - List all services with name and symbol
                        Symbols: '+'=running '-'=idle 'x'=disabled '?'=unknown
                        
                        Compatible with: sysVinit openrc runit s6 s6-66 and systemd
                        Runs under shells: ksh dash busybox-ash zsh posh yash bash
                    "
                    }
                    ##### Support for each 'init' system is in a separate shell function
                    ##### Main rogram execution begins around line 695
                    ## Support for OpenRC
                    # Not many systems use openrc, but we show it first because it provides
                    # the best overview of the modular structure for each 'init' type
                    _openrc() {
                    case $ACTION in
                        --status-all) rc-status -s ;;
                        --full-restart) 
                            rm /run/openrc/started/"$SERVICE" || true
                            if [ ! -h /run/openrc/started/"$SERVICE" ] ; then
                                ln -s "$SERVICEDIR/$SERVICE" /run/openrc/started/"$SERVICE" || true
                            fi ;;
                        #--failed) rc-status --crashed ;;
                        --list-all) rc-service -l ;; # rc-update -s
                        --list-running) _sysvinit --list-running ;;
                        --status)  # maintain the symlinks of /run/openrc/started so that
                            # rc-status works with the service command as well
                            _sysvinit status "$SERVICE" ;;
                        start)  if [ ! -h /run/openrc/started/"$SERVICE" ] ; then
                                    ln -s "$SERVICEDIR/$SERVICE" /run/openrc/started/"$SERVICE" || true
                                fi ;;
                        stop|force-stop) #rm /run/openrc/started/"$SERVICE" || true
                            rc-service stop "$SERVICE" ;;
                        restart) rc-service "$SERVICE" restart ;;
                        status) rc-service "$SERVICE" status ;;
                        reload|force-reload|try-restart) 
                            ACTION=stop
                            _sysvinit "$ACTION" "$SERVICE"
                            ACTION=start
                            _sysvinit "$ACTION" "$SERVICE" ;;
                        enable) rc-update add "$SERVICE" ;;
                        disable) rc-update del "$SERVICE" ;;
                        *) echo unknown action "$ACTION" ;;
                        esac
                    }
                    ## openrc
                    ## Support for sysVinit with /etc/init.d
                    # todo: support for 'dinit' should be easy to add
                    # todo: support bsd-like init scripts(slackare ...)
                    # sysVinit scripts are used by most other init systems,
                    # to some degree, so this is vital functions is vital
                    _sysvinit() {
                    case $ACTION in
                        --status-all) cd "${SERVICEDIR}" || return
                            for SERVICE in * ; do
                                is_ignored_sysv "$SERVICE" && continue
                                if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
                                    out=$("$SERVICEDIR/$SERVICE" status 2>&1)
                                    retval=$?
                                    case $retval in
                                        0) echo  " [ + ]  ${SERVICE}" ;;
                                        3) echo " [ ? ]  ${SERVICE}" ;;
                                        *) echo " [ - ]  ${SERVICE}" ;;
                                    esac
                                    #printf " %s %-60s %s\n" "[+]" "$SERVICE:" "running"
                                    # needs improvement to support 'x' symbol
                                fi
                              done ;;
                        --full-restart)
                            if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                "${SERVICEDIR}/${SERVICE}" stop "$SERVICE" 2>&1
                                "${SERVICEDIR}/${SERVICE}" start "$SERVICE" 2>&1
                            else
                                echo Unknown service "'$SERVICE'" >&2 
                                return 1 
                            fi
                            ;;
                        --list-all) cd "${SERVICEDIR}" || return
                            for SERVICE in * ; do
                                is_ignored_sysv "$SERVICE" && continue
                                [ -x "${SERVICEDIR}/${SERVICE}" ] && echo "$SERVICE"
                            done ;;
                        --list-running) cd "${run_level_dir}" || return  # /etc/rc$(runlevel).d
                            for SERVICE in * ; do
                                case ${SERVICE} in 
                                    K*) : ;;
                                    S[0-9][0-9]*) SERVICE=${SERVICE#*???}
                                        is_ignored_sysv "$SERVICE" && continue
                                        [ -x "${SERVICEDIR}/${SERVICE}" ] && echo "$SERVICE"
                                    ;;
                                esac
                            done ;;
                        --status)
                            if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                out=$( "${SERVICEDIR}/${SERVICE}" status 2>&1 )
                                retval=$?
                                case $retval in 
                                    0) echo Running or exited successfully >&2 ; return 0 ;;
                                    1|3) echo Not running >&2 ; return 1 ;;
                                    #3) echo No status unavailable >&2 ; return 3 ;;
                                esac
                            else
                                echo "Service $SERVICE not available" >&2
                                return 3
                            fi ;;
                        start|status) 
                            if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                "${SERVICEDIR}/${SERVICE}" "${ACTION}" 2>&1
                            else
                                echo Unknown service "'$SERVICE'" >&2 
                                return 1 
                            fi ;;
                        stop|force-stop) 
                            if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                "${SERVICEDIR}/${SERVICE}" "${ACTION}" 2>&1
                            else
                                echo Unknown service "'$SERVICE'" >&2 
                                return 1 
                            fi ;;
                        restart|reload|force-reload|try-restart)
                            if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                "${SERVICEDIR}/${SERVICE}" restart >/dev/null
                                case $? in 0) return 0 ;;
                                    *) "${SERVICEDIR}/${SERVICE}" stop "$SERVICE" 2>&1 && \
                                    "${SERVICEDIR}/${SERVICE}" start "$SERVICE" 2>&1 ;; 
                                esac
                            else
                                echo Unknown service "'$SERVICE'" >&2 
                                return 1 
                            fi ;;
                        enable) [ "$run_level" = unknown ] && return 1
                            LEVELS=$run_level # use only current runlevel
                            if which update-rc.d >/dev/null ; then
                                exec update-rc.d "${SERVICE}" enable "${LEVELS}"
                            else
                                if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                    # manual support for runlevels is tentative
                                    for lvl in $LEVELS ; do
                                        cd /etc/rc"${lvl}".de && ln -s ../init.d/"${SERVICE}" "S01$SERVICE"
                                    done
                                else
                                    return 1
                                fi
                            fi ;;
                        disable) [ "$run_level" = unknown ] && return 1
                            LEVELS=$run_level # use only current runlevel
                            if which update-rc.d >/dev/null ; then
                                exec update-rc.d "${SERVICE}" disable "${LEVELS}"
                            else
                                # support for runlevels is tentative
                                if [ -x  "${SERVICEDIR}/${SERVICE}" ] ; then
                                    for lvl in $LEVELS ; do
                                        cd /etc/rc"${lvl}".d && rm "S01$SERVICE"
                                    done
                                else
                                    return 1
                                fi
                            fi ;;
                        *) echo unknown action >&2 ; return 3 ;;
                        esac
                    }
                    ## _sysvinit
                    ## Helper functions for sysVinit support: 'is_ignored_sysv' 'run_via_sysvinit'
                    is_ignored_sysv() {
                        case "$1" in
                            skeleton|README|*.dpkg-dist|*.dpkg-old|rc|rcS|rcM|reboot|bootclean.sh) return 0 ;;
                            functions|halt|killall|single|linuxconf|kudzu|whoopsie ) return 0 ;;
                        esac
                        return 1
                    }
                    run_via_sysvinit() {
                        is_ignored_sysv "$SERVICE" && { echo "Service '$SERVICE' not allowed" >&2 ;}
                        # Otherwise, use the traditional sysvinit
                        if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
                            exec "$SERVICEDIR/$SERVICE" "${ACTION}"
                        else
                            echo "${SERVICE}: unrecognized service" >&2
                            return 3
                        fi
                    }
                    # Support for Systemd
                    # relies heavily on code from original 'service'
                    _systemd() {
                    if [ -n "$SERVICE" ] ; then
                        UNIT="${SERVICE%.sh}.service"
                        echo UNIT="$UNIT" >&2
                    fi
                    case "${ACTION}" in
                        --status-all) systemctl --no-pager list-unit-files --type=service  --state=enabled,disabled | \
                            while read -r unit state preset ; do
                                case $unit in *@*|systemd*) continue ;; esac
                                case $state in enabled) echo '[ + ]' "${unit%.service*}" ;;
                                    disabled) echo '[ - ]' "${unit%.service*}" ;;
                                esac
                                # needs improvement to support 'x' symbol
                            done ;;
                        --full-restart) exec systemctl restart ${UNIT} ;;  
                        --status) systemctl --no-pager status ${UNIT} >/dev/null ; return $? ;;
                        --list-all) systemctl --no-pager list-unit-files --type=service | \
                            while read -r unit ; do
                                case $unit in *@*) continue ;; 
                                    *?.service*) echo ${unit%%.service*}
                                esac
                            done ;;
                        --list-running) systemctl --no-pager list-units --type=service --state=running | \
                            while read -r unit ; do
                                case $unit in *@*) continue ;; 
                                    *?.service*) echo ${unit%%.service*}
                                esac
                            done ;;
                        start|stop)
                            # Follow the principle of least surprise for SysV people:
                            # When running "service foo stop" and foo happens to be a service that
                            # has one or more .socket files, we also stop the .socket units.
                            # Users who need more control will use systemctl directly.
                            systemctl --no-pager list-unit-files --full --type=socket 2>/dev/null | \
                                while read -r unit state preset ; do
                                    case ${unit} in *@*) continue ;; # ignore sockets with '@' in the name
                                        *.socket)
                                        if [ "$(systemctl -p Triggers show ${unit})" = "Triggers=${UNIT}" ]; then
                                            systemctl $sctl_args ${ACTION} ${unit}
                                        fi ;;
                                    esac
                                done
                             exec systemctl $sctl_args ${ACTION} ${UNIT} ;;
                        reload) _canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
                            # Don't block on reload requests during bootup and shutdown
                            # from units/hooks and simply schedule the task.
                            if ! systemctl --quiet is-system-running; then
                                sctl_args="--no-block"
                            fi
                            if [ "$_canreload" = "CanReload=no" ]; then
                                # The reload action falls back to the sysv init script just in case
                                # the systemd service file does not (yet) support reload for a
                                # specific service.
                                #run_via_sysvinit
                                run_via_sysvinit ${ACTION} ${UNIT}
                                return $?
                            else
                                exec systemctl $sctl_args reload ${UNIT}
                            fi ;;
                        force-stop) exec systemctl --signal=KILL kill ${UNIT} ;;
                        force-reload) _canreload="$(systemctl -p CanReload show ${UNIT} 2>/dev/null)"
                            if [ "$_canreload" = "CanReload=no" ]; then
                                exec systemctl $sctl_args restart ${UNIT}
                            else
                                exec systemctl $sctl_args reload ${UNIT}
                            fi ;;
                        restart|status|try-restart) exec systemctl --no-pager $sctl_args ${ACTION} ${UNIT} ;;
                        enable|disable) exec systemctl ${ACTION} ${UNIT} ;;
                        *)  # For non-standard actions try running the sysvinit script, if available.
                             run_via_sysvinit ${ACTION} ${UNIT} 
                             return $? ;;
                       esac
                    }
                    ## Systemd
                    ## Support for Runit
                    # up, down, status, once, pause, cont, hup, alarm, interrupt, 1, 2, term, kill,
                    # Or: exit, or start, stop, restart, shutdown, force-stop, force-reload, force-restart, force-shutdown
                    # unique to runit: once pause cont hup alarm interrupt quit 1 2 term kill exit shutdown force-shutdown
                    # todo - take advantage of more features and improve aliasing to our action 'vocabulary'
                    # config, source and scan locations for s6
                    RUNDIR="/etc/sv"
                    RUNSERVICEDIR="/etc/service"
                    #/etc/runit/runsvdir/current
                    _runit() {
                    case "$ACTION" in
                        --status-all) cd "${RUNDIR}" || return
                            for name in * ; do
                                if ! [ -h "$RUNSERVICEDIR/$name" ] ; then
                                    echo " [ - ] $name"
                                elif [ -f /etc/service/"$name"/supervise/stat ] ; then		
                                    read -r _stat </etc/service/"$name"/supervise/stat
                                    case $_stat in
                                        run) echo " [ + ] $name" ;;
                                        down) echo " [ - ] $name" ;;
                                        fail*) echo " [ - ] $name - failed" ;;
                                        *) echo " [ ? ] $name" ;;
                                    esac
                                else
                                    echo " [ ? ] $name - unknown"
                                fi
                            done 
                            return ;;
                        --full-restart) ACTION=restart ;;
                        --list-all) cd "${RUNDIR}" || return
                            for name in * ; do echo $name ; done
                            return ;;
                        --list-running) cd "${RUNSERVICEDIR}" ||return
                            for name in * ; do
                                read -r _stat </etc/service/"$name"/supervise/stat
                                case $_stat in
                                    run) echo "$name" ;;
                                    *) continue ;;
                                esac
                            done
                            return ;;
                        --status) 
                            if [ -f /etc/service/"$SERVICE"/supervise/stat ] ; then		
                                read -r _stat </etc/service/"$SERVICE"/supervise/stat
                                case $_stat in
                                    run) echo running >&2 ; return 0 ;;
                                    down) echo not running >&2 ; return 1 ;;
                                    fail*) echo disabled >&2 ; return 3 ;;
                                    *)  echo unknown >&2 ; return 4 ;;
                                esac
                            else
                                echo "Service $SERVICE is disabled" >&2
                                return 3
                            fi ;;
                        #start) ACTION=up ;;
                        #status|restart) : ;;
                        #stop) ACTION=down ;;
                        #force-stop) ACTION=exit ;;
                        reload|force-reload|try-restart)  ACTION=restart ;;
                        enable) ln -s /etc/sv/"${SERVICE}" "${RUNSERVICEDIR}/" ; return ;;
                        disable) rm "${RUNSERVICEDIR}/${SERVICE}" ; return ;;
                    esac
                        #Runit-init
                        # Only perform ${ACTION} when there is a runscript for
                        # the service and ${SERVICE} is enabled.
                        # If the service is disabled print a message
                        # and do not perform ${ACTION}
                        # If there is no runscript at all fallback on sysv.
                    if [ -d "${RUNDIR}/${SERVICE}" ]; then
                        case "${ACTION}" in
                            status)
                                if test -h "${RUNSERVICEDIR}/${SERVICE}"; then
                                    exec sv "${ACTION}" "${SERVICE}"
                                else
                                    echo "Service ${SERVICE} is disabled"
                                    return 3
                                fi ;;
                            start) 
                                if ! [ -f /etc/service/"$SERVICE"/supervise/stat ] ; then
                                    echo "Service ${SERVICE} is disabled" >&2 
                                    return 3
                                else
                                    sv start "${SERVICE}"
                                    return $?
                                fi;;
                            *)  if test -h "${RUNSERVICEDIR}/${SERVICE}"; then
                                    exec sv "${ACTION}" "${SERVICE}"
                                else
                                    echo "Can't ${ACTION} ${SERVICE}, the service is disabled"
                                    return 3
                                fi ;;
                        esac
                    fi
                    }
                    ## _runit
                    ## Support for S6_66
                    # todo - review aliasing and listing
                    _s6_66() {
                    case "$ACTION" in
                        --list-all) cd /etc/66/service || return 1
                            for srv in * ; do
                                case "$srv" in
                                    *@*) : ;;
                                    *) echo "$srv"
                                esac
                            done ;;
                        --list-running)	cd /run/66/state/0 || return 1
                            for item in * ; do
                                case "$item" in
                                    *@*|boot*|*-log) : ;;
                                    *) [ -f /run/66/state/0/"$item"/down ] || echo "$item"
                                esac
                            done ;;
                        --status-all) 
                            cd /etc/66/service || return 1
                            for item in * ; do
                                [ -f  /etc/66/service/"${item}" ] || continue
                                if [ -d /run/66/state/0/"$item" ] && ! [ -f /run/66/state/0/"$item"/down ] ; then
                                    echo " [ + ]  ${item%-srv}" 1>&2
                                else
                                    echo " [ - ]  ${item}" 1>&2
                                fi
                                # is there any [ ? ] equivalent for 66?
                            done ;;
                        --force-restart|restart|try-restart|reload|force-reload) 66 restart "$SERVICE" ;;
                        --status) 66 status "$SERVICE" 1>/dev/null 2>/dev/null ;; # fix-me
                        status) 66 status "$SERVICE" ;;
                        stop|force-stop) 66 stop "$SERVICE" ;;
                        start|enable|disable) 66 "$ACTION" "$SERVICE" ;;
                        *) echo unknown command ;;
                    esac
                    }
                    ## s6-66
                    ## Support for S6
                    # todo - all functionality needs testing on installed (antix) systems
                    # todo - review/normalize contents of lists and --status
                    _s6() {
                    LIVESVDIRS=/run/s6-rc/servicedirs
                    case "$ACTION" in
                        --list-all)  s6-rc-db list bundles ;;
                        # or --list-all) cd "$SYSPATH" ||return
                        #    for serv in * ; do
                        #    case "$serv" in
                        #                *-log) : ;;
                        #            *) echo "${serv%-srv}"
                        #        esac
                        #    done ;;
                        --list-running) s6-rc -au list ;;
                        --status-all) cd "$LIVESVDIRS" || return 
                            for item in * ; do
                                # ignore log processes ??
                                case $item in *-log) continue ;; esac
                                if [ -f "$item"/down ] ; then
                                    echo " [ - ]  ${item%-srv*}" #1>&2
                                else
                                    echo " [ + ]  ${item%-srv*}" #1>&2
                                fi
                            done ;;
                        --status|status) cd $LIVESVDIRS || return
                            if [ -d "$SERVICE" ] || [ -d "${SERVICE}-srv" ] ; then
                                if [ -f "$SERVICE"/down ] || [ -f "${SERVICE}-srv"/down ] ; then
                                    echo "$SERVICE is NOT running" ; return 1
                                else
                                    echo "$SERVICE is running" ; return 0
                                fi
                            else
                                echo "$SERVICE is not in s6 database" ; return 1
                            fi ;;
                        --full-restart|restart|try-restart|reload|force-reload) 
                                s6-rc -d change "${SERVICE}" && s6-rc -u change "${SERVICE}" ;;
                        start) s6-rc start "${SERVICE}" ;;
                        stop|force-stop) s6-rc stop "${SERVICE}" ;;
                        enable) update_s6_db enable "$SERVICE" ;;
                        disable) update_s6_db disable "$SERVICE" ;;
                        *) echo "Unknown action $ACTION" ; ;;
                    esac
                    } ## _s6
                    ## Helper scripts for _s6: 'is_ignored_s6' 'recompile_s6_db' 'update_s6_db'
                    is_ignored_s6() {
                        # antix crucial: s6rc-oneshot-runner s6rc-fdholder default boot antix-service-manager + contents of boot
                        # in every case, contents of boot bundle will not be done
                        case $1 in
                            s6rc-oneshot-runner|s6rc-fdholder) return 0 ;; # essential to s6 itself
                            default|boot|antix-service-manager) return 0 ;; # essential bundles
                            *) [ -f "$SVPATH/boot/contents.d/$1" ] && return 0 || return 1 ;;
                        esac
                    }
                    ## recompile_s6_db
                    # does actual compiling of s6 database
                    # requires SYSPATH and SVPATH from update_s6_db
                    # double-commented lines here show the s6 database-compilation method and
                    # and paths used by the antix init-diversity s6-rc_service-manager.sh.
                    # 'servize' generalizes the procedure to work with other systems
                    recompile_s6_db() {
                        timestamp=$(date +%s)
                        if [ -h $SYSPATH/compiled ] ; then
                            target_compiled=$(readlink -f $SYSPATH/compiled)
                            target_compiled=${target_compiled#*"$SYSPATH/"}
                        else
                            target_compiled=${SYSPATH}/compiled
                        fi
                        echo "target_compiled: $target_compiled" >&2
                        
                        ##s6-rc-update /etc/s6-rc/compiled-release
                        ##mv /etc/s6-rc/compiled-active /etc/s6-rc/compiled-superseded-$(date +%s%N)
                        echo "creating a copy of active DB at: $SYSPATH/$target_compiled-$timestamp" >&2
                        cp -a "$SYSPATH/$target_compiled" "$SYSPATH/$target_compiled-$timestamp"
                        echo "switching LIVE to: $target_compiled-$timestamp" >&2
                        if ! s6-rc-update "$SYSPATH/$target_compiled-$timestamp" ; then
                            echo "swithing failed" >&2 ; return 1
                        fi
                        
                        ##rm -r /etc/s6-rc/compiled
                        ##rm -r $SYSPATH/compiled
                        echo "removing original DB $target_compiled" >&2
                        cd "$SYSPATH" && rm -r "${target_compiled:-dud}"
                        ##s6-rc-compile /etc/s6-rc/compiled-active /etc/s6-rc/sv
                        echo "compiling new DB $SYSPATH/$target_compiled at $SVPATH" >&2
                        if ! s6-rc-compile "$SYSPATH/${target_compiled}" "$SVPATH" ; then
                            echo "compiling failed -swithing back" >&2 
                            cp -a "$SYSPATH/$target_compiled-$timestamp" "$SYSPATH/$target_compiled"
                            if [ "$SYSPATH/$target_compiled" != "$SYSPATH/compiled" ] ; then
                                ln -sf "$SYSPATH/$target_compiled" "$SYSPATH"/compiled
                            fi
                        fi
                        ##ln -sf /etc/s6-rc/compiled-active /etc/s6-rc/compiled
                        #ln -sf $SYSPATH/$target_compiled $SYSPATH/compiled
                        ##s6-rc-update /etc/s6-rc/compiled
                        echo "switching LIVE to back to: $target_compiled" >&2
                        if ! s6-rc-update $SYSPATH/compiled ; then
                            echo "swithing failed" >&2 ; return 1
                        fi
                        ##rm -rf /etc/s6-rc/compiled-superseded*
                        echo "removing copy of DB: $target_compiled-$timestamp" >&2
                        rm -rf "$SYSPATH/${target_compiled:-dud}-$timestamp"
                    }
                    ## recompile_s6_db
                    # This function should figure out which implementation of s6 is being used,
                    # especially the location of Service Directory and any native service-manager
                    # Only supports Antix at the moment. Information needed for Artix and gentoo
                    update_s6_db() {
                        echo ACTION="$ACTION" SERVICE="$SERVICE"
                        # these defaults are used by antix
                        RUNPATH='/run/s6-rc'
                        RUNSVDIRS="${RUNPATH}"/servicedirs
                        SYSPATH='/etc/s6-rc' # universal except for aRtix??
                        DBPATH="${SYSPATH}"/compiled # linked to compiled-active in antix
                        
                        if [ -d /etc/s6-rc/sv/antix-service-manager ] ; then
                            rc_type=antix
                            SVPATH="${SYSPATH}/sv"
                            ADMINSVPATH="${SVPATH}/antix-service-manager/contents.d"
                            echo "found antix /etc/s6-rc/sv" >&2  # antix
                        #elif [ -d /etc/s6/adminsv ] && [ -d /etc/s6/sv ] ; then
                        #    rc_type=artix
                        #    SYSPATH='/etc/s6'
                        #    DBPATH="${SYSPATH}/rc/compiled" # ?? does /etc/sv/compile exist as a link to this?
                        #    SVPATH="${SYSPATH}/sv ${SYSPATH}/adminsv"
                        #    ADMINSVPATH="${SYSPATH}/adminsv/default/contents.d"
                        #    #FALLBACKSVPATH="${SYSPATH}/fallbacksv"
                        #    echo "Artix  /etc/s6/adminsv"  # Artix  devuan
                        #elif [ -d /etc/s6-rc/src ] ; then
                        #    rc_type=gentoo  # weak detection, use a generic method
                        #    SVPATH="${SYSPATH}/src"
                        #    ADMINSVPATH="${SVPATH}/serviz/contents.d"
                        #    ! [ -d "$ADMINSVPATH" ] && { mkdir -p "$ADMINSVPATH" ; echo "bundle" > "${SYSPATH}/serviz/type" ;}
                        #    echo "gentoo /etc/s6-rc/src"  # gentoo
                        ## I need more info about artix and gentoo setups -and any other possibles
                        else
                            echo "Unknown implementation of s6" >&2 ; exit 1
                        fi
                        # find out if service/bundle is available
                        #if ! [ -d "${SVPATH}/$SERVICE" ] ; then
                        #    echo "$0: unknown bundle '$SERVICE'" ; return 1
                        #fi
                        # throw out exceptions
                        if is_ignored_s6 "$SERVICE" ; then
                            echo "$0: refusing to remove essential bundle '$SERVICE'" ; return 1
                        fi
                        case $ACTION in # we do allow disabling items from default
                            disable) # but, if enabled again they will appear in ADMINSVPATH
                                if [ -f "${SVPATH}/default/contents.d/$SERVICE" ] ; then
                                    echo "$0: disabling default service '$SERVICE'" >&2
                                    rm -f "${SVPATH:-dud}/default/contents.d/$SERVICE"
                                else
                                    rm -f "${ADMINSVPATH:-dud}/$SERVICE"
                                fi
                            ;;  # only enable things in service-manager dir
                            enable) touch "${ADMINSVPATH:-dud}/$SERVICE" ;;
                        esac
                        case $rc_type in
                            antix) recompile_s6_db ; return $? ;;
                            # recompile_s6_db is generic, so we can support other implementations
                            # if we know location of the standard SV sources and admin dir
                            #artix) refresh_db_artix ; return $? ;;
                            #gentoo) refresh_db_gentoo ; return $? ;;
                            #void) refresh_db_void ; return $? ;;  # void uses old-style DB ??
                            *) return 1 ;;
                        esac
                    }
                    ## main - execution starts here
                    case $# in
                        0) servize_help ; exit ;;
                        1)  case $1 in --help|-h|help) servize_help ; exit ;;
                                --list-all|--list-running|--status-all) : ;;
                                *) echo "Action '$1' requires a Service name" ; exit ;;
                            esac ;;
                    esac
                    SERVICE='' ACTION='' LEVELS=''
                    for item in "$@" ; do
                        case $item in
                            #--help) echo bla bla ; exit ;;
                            --list-all|--list-running|--status-all|--status|--full-restart) [ -z "$ACTION" ] && ACTION="${item}" ;;
                            start|stop|restart|status|try-restart) [ -z "$ACTION" ] && ACTION="${item}" ;;
                            reload|force-reload|force-stop) [ -z "$ACTION" ] && ACTION="${item}" ;;
                            enable|disable) [ -z "$ACTION" ] && ACTION="${item}" ;;
                            [2345]) LEVELS="${LEVELS} ${item}" ;; # only works with update-rc.d for the moment
                            *) SERVICE="${item}" ;;
                        esac
                    done
                    debugit() {
                    echo init_type="$init_type"
                    echo run_level="$run_level"
                    echo ACTION="$ACTION" SERVICE="$SERVICE" # LEVELS="$LEVELS"
                    echo
                    }
                    debugit >&2
                    case $init_type in
                        systemd)    _systemd "$ACTION" "$SERVICE" ;; # [ -d /run/systemd/system ]
                        init)       _sysvinit "$SERVICE" "$ACTION" "$LEVELS" ;; # [ -d /etc/[rc.d/]init.d ] 
                        openrc-init)_openrc "$ACTION" "$SERVICE" "$LEVELS" ;;
                        init-s6-rc) _s6 "$ACTION" "$SERVICE" ;;
                        init-s6-66) _s6_66 "$ACTION" "$SERVICE" ;;
                        init-runit) _runit "$ACTION" "$SERVICE" ;; # [ -f /run/runit.stopit ]
                        #dinit) : ;; # not implemented but OOB supports: start stop restart enable disable list
                        #bsd-init) : ;; # is a mystery
                        #slackware) : ;; # uses sysVinit and purported bsd-style scripts
                        *) echo "Unknown init_type" ; exit 1 ;;
                    esac
                    exit $?
                    
                    • This reply was modified 1 month, 1 week ago by CanToo.
                    • This reply was modified 1 month, 1 week ago by CanToo.
                    • This reply was modified 1 month, 1 week ago by CanToo.
                  Viewing 8 posts - 1 through 8 (of 8 total)
                  • You must be logged in to reply to this topic.