├── bin ├── halt ├── poweroff ├── shutdown ├── begin ├── reboot └── rc ├── .gitignore ├── doc ├── skel_virtual └── skel ├── man └── rc.conf.5.ronn ├── etc └── rc.conf ├── lib ├── rc.conf ├── rc.distro.conf ├── rc.d │ ├── randomseed │ ├── sysctl │ ├── hwclock │ └── hostname ├── rc.shutdown ├── rc.init └── rc.functions ├── LICENSE ├── share └── bash-completion │ └── rc ├── libexec ├── halt.c ├── reboot.c └── poweroff.c ├── CONTRIBUTING.md ├── Makefile └── README.md /bin/halt: -------------------------------------------------------------------------------- 1 | reboot -------------------------------------------------------------------------------- /bin/poweroff: -------------------------------------------------------------------------------- 1 | reboot -------------------------------------------------------------------------------- /bin/shutdown: -------------------------------------------------------------------------------- 1 | reboot -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | image/ 3 | *.swp 4 | *~ 5 | .*.kak.* 6 | 7 | -------------------------------------------------------------------------------- /doc/skel_virtual: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | skel_virtual() { true; } 4 | -------------------------------------------------------------------------------- /man/rc.conf.5.ronn: -------------------------------------------------------------------------------- 1 | # rc.conf(5) -- Main configuration file for Beginning 2 | ============================================= 3 | 4 | ## SYNOPSIS 5 | 6 | ## DESCRIPTION 7 | 8 | ## OPTIONS 9 | 10 | ## EXAMPLES 11 | 12 | ## SEE ALSO 13 | 14 | rc(8), rc.conf.d(5), rc.d(5) 15 | -------------------------------------------------------------------------------- /etc/rc.conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # @@sysconfdir@@/rc.conf 4 | # 5 | 6 | # You probably want to keep most of these. 7 | # NOTE: If 'tty' is removed, you will be unable to log in from virtual consoles. 8 | DAEMONS=( hwclock syslog consolefont dev network tty ) 9 | 10 | # Virtual providers 11 | # _PROVIDER= 12 | DEV_PROVIDER= 13 | NETWORK_PROVIDER= 14 | SYSLOG_PROVIDER= 15 | TTY_PROVIDER= 16 | -------------------------------------------------------------------------------- /doc/skel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | skel_exists() { 4 | prog_exists skel 5 | } 6 | 7 | skel_wants() { 8 | [[ "${BEGINNING_PLATFORM}" == Linux ]] && echo linux-only-daemon 9 | } 10 | 11 | skel_start() { 12 | skel_status || rm -f "@@runstatedir@@"/skel.pid 13 | skel & 14 | echo $! > "@@runstatedir@@"/skel.pid 15 | } 16 | 17 | skel_reload() { 18 | skel --reload 19 | } 20 | 21 | skel_stop() { 22 | pidfilekill "@@runstatedir@@"/skel.pid 23 | skel_status || rm -f "@@runstatedir@@"/skel.pid 24 | } 25 | 26 | skel_status() { 27 | pidexists "@@runstatedir@@"/skel.pid 28 | } 29 | -------------------------------------------------------------------------------- /lib/rc.conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # @@libdir@@/beginning/rc.conf 4 | # 5 | # Defaults that are used by Beginning's rc.init 6 | # 7 | 8 | readonly BEGINNING_COPYRIGHT="(c) 2015-2016 Kylie McClain, distributed under the terms of the ISC license" 9 | 10 | LIBDIR="@@libdir@@" 11 | BEGINNING_LIB="${LIBDIR}"/beginning 12 | 13 | # CORE_DAEMONS_{BEFORE,AFTER} - daemons that will always run without being set in DAEMONS 14 | CORE_DAEMONS_BEFORE=( 15 | hostname randomseed sysctl 16 | ) 17 | 18 | CORE_DAEMONS_AFTER=() 19 | 20 | ## Init settings 21 | # rc.init 22 | # RC_CLEAR_BOOT - clear screen at boot; if not true, don't clear 23 | RC_CLEAR_BOOT=true 24 | 25 | [[ -r "${BEGINNING_LIB}"/rc.distro.conf ]] && . "${BEGINNING_LIB}"/rc.distro.conf 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Kylie McClain 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /share/bash-completion/rc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _rc() { 4 | local cur prev words cword 5 | _init_completion || return 6 | 7 | case "${prev}" in 8 | beginning_daemon_list|list|ls) 9 | COMPREPLY=( $(compgen -W "started stopped nonexistent existent daemons virtuals all" -- "${cur}") ) 10 | ;; 11 | providers) 12 | COMPREPLY=( $(compgen -W "$(rc beginning_daemon_list virtuals)" -- "${cur}") ) 13 | ;; 14 | *) 15 | if [[ "${cword:-0}" -ge 2 ]];then 16 | COMPREPLY=( $(compgen -W "$(rc beginning_daemon_list existent)" -- "${cur}") ) 17 | else 18 | COMPREPLY=( $(compgen -W "$(rc print-commands)" -- "${cur}") ) 19 | fi 20 | ;; 21 | esac 22 | } 23 | 24 | complete -F _rc rc 25 | -------------------------------------------------------------------------------- /lib/rc.distro.conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # @@libdir@@/beginning/rc.distro.conf 4 | # 5 | # Distro specific variables for Beginning 6 | # 7 | 8 | # Copyright that will be shown during boot sequence 9 | readonly COPYRIGHT="@@COPYRIGHT@@" 10 | 11 | # *_URL is normally provided by os-release, which is read after this file 12 | HOME_URL="https://github.com/somasis/beginning" 13 | SUPPORT_URL="https://github.com/somasis/beginning/issues" 14 | 15 | readonly LIBDIR="@@libdir@@" 16 | readonly LIBEXECDIR="@@libexecdir@@" 17 | readonly SYSCONFDIR="@@sysconfdir@@" 18 | 19 | readonly BEGINNING_LIB="${LIBDIR}"/beginning 20 | readonly BEGINNING_RC="${BEGINNING_LIB}"/rc.d 21 | readonly USER_RC="${SYSCONFDIR}"/rc.d 22 | 23 | readonly INIT_REBOOT_CMD="${BEGINNING_LIB}/rc.shutdown reboot" 24 | readonly INIT_SHUTDOWN_CMD="${BEGINNING_LIB}/rc.shutdown poweroff" 25 | readonly INIT_RC_CMD="${BEGINNING_LIB}/rc.init" 26 | 27 | -------------------------------------------------------------------------------- /libexec/halt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Beginning - an init system that isn't smarter than you 3 | * 4 | * Copyright (c) 2015-2016 Kylie McClain 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, const char* argv[]) { 24 | sync(); 25 | reboot(RB_HALT_SYSTEM); 26 | _exit(errno); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /libexec/reboot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Beginning - an init system that isn't smarter than you 3 | * 4 | * Copyright (c) 2015-2016 Kylie McClain 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, const char* argv[]) { 24 | sync(); 25 | reboot(RB_AUTOBOOT); 26 | _exit(errno); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /libexec/poweroff.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Beginning - an init system that isn't smarter than you 3 | * 4 | * Copyright (c) 2015-2016 Kylie McClain 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, const char* argv[]) { 24 | sync(); 25 | reboot(RB_POWER_OFF); 26 | _exit(errno); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /lib/rc.d/randomseed: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RANDOMSEED_FILE=${RANDOMSEED_FILE:-"@@localstatedir@@"/tmp/random-seed} 4 | RANDOMSEED_POOLSIZE=$(echo $( /dev/urandom || err=$? 16 | rm -f "${RANDOMSEED_FILE}" 17 | fi 18 | echo "RANDOMSEED_FILE=${RANDOMSEED_FILE}" > "@@runstatedir@@"/beginning/randomseed 19 | echo "RANDOMSEED_POOLSIZE=${RANDOMSEED_POOLSIZE}" >> "@@runstatedir@@"/beginning/randomseed 20 | return $err 21 | } 22 | 23 | randomseed_stop() { 24 | randomseed_status 25 | local err 26 | # save random state 27 | dd if=/dev/urandom of="${RANDOMSEED_FILE}" count=1 bs=${RANDOMSEED_POOLSIZE} >/dev/null 2>&1 || err=$? 28 | [[ "$err" -eq 0 ]] && rm -f "@@runstatedir@@"/beginning/randomseed 29 | return $err 30 | } 31 | 32 | randomseed_status() { 33 | [[ -r "@@runstatedir@@"/beginning/randomseed ]] 34 | } 35 | -------------------------------------------------------------------------------- /lib/rc.d/sysctl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl_exists() { 4 | [[ "${BEGINNING_PLATFORM}" == Linux ]] && prog_exists sysctl 5 | } 6 | 7 | sysctl_start() { 8 | # this matches the list of sysctl configuration files in sysctl's manpage 9 | local file err files 10 | files=( 11 | "@@runstatedir@@"/sysctl.d/*.conf 12 | "@@sysconfdir@@"/sysctl.d/*.conf 13 | "@@libdir@@"/sysctl.d/*.conf 14 | "@@sysconfdir@@"/sysctl.conf 15 | ) 16 | for file in ${files[@]};do 17 | if [[ -r "${file}" ]];then 18 | status CUSTOM "sysctl: applying settings from \"${file}\"" 19 | sysctl -p "${file}" >/dev/null 2>&1 || err=$? 20 | if [[ "${err}" -ne 0 ]];then 21 | BEGINNING_FAILURE="failed to apply \"${file}\"" 22 | return 1 23 | else 24 | printf '%s\n' "${file}" >> "@@runstatedir@@"/beginning/sysctl 25 | fi 26 | fi 27 | done 28 | } 29 | 30 | sysctl_stop() { 31 | [[ "${BEGINNING_RUNNER}" == rc.shutdown ]] || return 1 32 | return 0 33 | } 34 | 35 | sysctl_status() { 36 | [[ -r "@@runstatedir@@"/beginning/sysctl ]] 37 | } 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Beginning 2 | 3 | ## Code 4 | 5 | Contributions of code are accepted through [GitHub's pull requests][pull-requests]. 6 | 7 | If you have multiple features/fixes/things done in one commit, please split them 8 | up into multiple commits, so that they can be reviewed seperately. 9 | 10 | ### Daemon scripts 11 | 12 | Scripts for controlling daemons (which are located in lib/rc.d) should be sent to 13 | [beginning-scripts], unless they concern the scripts already located in the lib/rc.d 14 | directory in this repository. However, for scripts that may be deemed important 15 | enough for systems of any type (embedded, servers, desktops, low-resource), scripts 16 | can be submitted and we can decide then. 17 | 18 | But for the most part they should go in [beginning-scripts]. 19 | 20 | ## Bugs 21 | 22 | Bugs should be reported to [GitHub's issue tracker][issues]. It is recommended 23 | that you read Simon Tatham's excellent article, 24 | ["How to Report Bugs Effectively"][reporting-bugs]. 25 | 26 | [reporting-bugs]: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html 27 | [pull-requests]: https://github.com/somasis/beginning/pulls 28 | [issues]: https://github.com/somasis/beginning/issues 29 | [beginning-scripts]: https://github.com/somasis/beginning-scripts 30 | -------------------------------------------------------------------------------- /lib/rc.d/hwclock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HWCLOCK_ARGS=${HWCLOCK_ARGS:-} 4 | HWCLOCK_TYPE=${HWCLOCK_TYPE:-UTC} 5 | [[ -L "@@sysconfdir@@"/localtime && -r "@@sysconfdir@@"/localtime ]] && \ 6 | HWCLOCK_TZ=$(realpath "@@sysconfdir@@"/localtime | cut -d'/' -f5-) 7 | HWCLOCK_TZ=${HWCLOCK_TZ:-UTC} 8 | 9 | hwclock_exists() { 10 | if prog_exists hwclock && [[ -e /dev/rtc0 ]];then 11 | return 0 12 | else 13 | return 1 14 | fi 15 | } 16 | 17 | hwclock_start() { 18 | local err 19 | export TZ=${HWCLOCK_TZ} 20 | case ${HWCLOCK_TYPE,,} in 21 | localtime) 22 | hwclock --hctosys --localtime ${HWCLOCK_ARGS};err=$? 23 | ;; 24 | utc) 25 | hwclock --hctosys --utc ${HWCLOCK_ARGS};err=$? 26 | ;; 27 | *) 28 | err=1 29 | ;; 30 | esac 31 | unset TZ 32 | echo "TZ=${HWCLOCK_TZ}" > "@@runstatedir@@"/beginning/hwclock 33 | return $err 34 | } 35 | 36 | hwclock_stop() { 37 | local err 38 | export TZ=${HWCLOCK_TZ} 39 | case ${HWCLOCK_TYPE,,} in 40 | localtime) 41 | hwclock --systohc --localtime;err=$? 42 | ;; 43 | utc) 44 | hwclock --systohc --utc;err=$? 45 | ;; 46 | *) 47 | err=1 48 | ;; 49 | esac 50 | unset TZ 51 | rm -f "@@runstatedir@@"/beginning/hwclock 52 | return $err 53 | } 54 | 55 | hwclock_status() { 56 | [[ -r "@@runstatedir@@"/beginning/hwclock ]] 57 | } 58 | -------------------------------------------------------------------------------- /bin/begin: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | if [[ "$$" -ne 1 ]];then 21 | printf "This program should only be run as init.\n" >&2 22 | exit 1 23 | fi 24 | 25 | cd / 26 | 27 | BEGINNING_LIB="@@libdir@@"/beginning 28 | 29 | if [[ -r "${BEGINNING_LIB}"/rc.functions ]];then 30 | . "${BEGINNING_LIB}"/rc.functions 31 | else 32 | printf 'Could not find %s/rc.functions, dying...\n' "${BEGINNING_LIB}" 33 | exit 2 34 | fi 35 | 36 | trap "BEGINNING_RUNNER=begin ${INIT_SHUTDOWN_CMD}" SIGUSR1 37 | trap "BEGINNING_RUNNER=begin ${INIT_REBOOT_CMD}" SIGINT 38 | 39 | BEGINNING_RUNNER=begin ${INIT_RC_CMD} & 40 | 41 | cat & 42 | 43 | wait 44 | -------------------------------------------------------------------------------- /lib/rc.d/hostname: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HOSTNAME=${HOSTNAME:-"localhost"} 4 | [[ -s "@@sysconfdir@@"/hostname ]] && HOSTNAME=$(<"@@sysconfdir@@"/hostname) 5 | 6 | hostname_exists() { 7 | prog_exists hostname || [[ -r "/proc/sys/kernel/hostname" ]] 8 | } 9 | 10 | hostname_lo_up() { 11 | if prog_exists ip;then 12 | ip link set dev lo up 13 | elif prog_exists ifconfig;then 14 | ifconfig lo up 15 | elif prog_exists toybox && toybox | tr ' ' '\n' | fgrep -q ifconfig;then 16 | toybox ifconfig lo up 17 | elif prog_exists busybox && busybox --list | fgrep -q ifconfig;then 18 | busybox ifconfig lo up 19 | else 20 | return 1 21 | fi 22 | return $? 23 | } 24 | 25 | hostname_lo_down() { 26 | if prog_exists ip;then 27 | ip link set dev lo down 28 | elif prog_exists ifconfig;then 29 | ifconfig lo down 30 | elif prog_exists toybox && toybox | tr ' ' '\n' | fgrep -q ifconfig;then 31 | toybox ifconfig lo down 32 | elif prog_exists busybox && busybox --list | fgrep -q ifconfig;then 33 | busybox ifconfig lo down 34 | else 35 | return 1 36 | fi 37 | return $? 38 | } 39 | 40 | hostname_lo_status() { 41 | if prog_exists ip;then 42 | ip link show lo | fgrep -q 'UP' 43 | elif prog_exists ifconfig;then 44 | ifconfig lo | fgrep -q 'UP' 45 | elif prog_exists toybox && toybox | tr ' ' '\n' | fgrep -q ifconfig;then 46 | toybox ifconfig lo | fgrep -q 'UP' 47 | elif prog_exists busybox && busybox --list | fgrep -q ifconfig;then 48 | busybox ifconfig lo | fgrep -q 'UP' 49 | else 50 | return 1 51 | fi 52 | return $? 53 | } 54 | 55 | hostname_start() { 56 | local err 57 | if prog_exists hostname;then 58 | hostname "${HOSTNAME}" || err=$? 59 | elif [[ -w "/proc/sys/kernel/hostname" ]];then 60 | echo "${HOSTNAME}" > /proc/sys/kernel/hostname || err=$? 61 | fi 62 | hostname_lo_up || err=$? 63 | [[ $err -eq 0 ]] && echo "${HOSTNAME}" > "@@runstatedir@@"/beginning/hostname 64 | return $err 65 | } 66 | 67 | hostname_stop() { 68 | hostname_lo_down 69 | return $? 70 | } 71 | 72 | hostname_status() { 73 | hostname_lo_status && [[ -r "@@runstatedir@@"/beginning/hostname ]] 74 | } 75 | -------------------------------------------------------------------------------- /bin/reboot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | if [[ "$UID" -ne 0 ]];then 21 | printf "This program should only be run as root.\n" >&2 22 | exit 1 23 | fi 24 | 25 | BEGINNING_LIBEXEC="@@libexecdir@@"/beginning 26 | BEGINNING_LIB="@@libdir@@"/beginning 27 | 28 | if [[ -r "${BEGINNING_LIB}"/rc.functions ]];then 29 | . "${BEGINNING_LIB}"/rc.functions 30 | else 31 | printf 'Could not find %s/rc.functions, dying...\n' "${BEGINNING_LIB}" 32 | exit 2 33 | fi 34 | 35 | bin="${0##*/}" 36 | bin="${bin##beginning.}" 37 | 38 | case "${bin}" in 39 | reboot) 40 | if [[ "${BEGINNING_RUNNER}" == "rc.shutdown" ]];then 41 | # if being ran by one of the init scripts, run the binary 42 | # that actually calls reboot() 43 | exec "${BEGINNING_LIBEXEC}"/reboot 44 | else 45 | kill -2 1 46 | fi 47 | ;; 48 | shutdown) 49 | if [[ "${BEGINNING_RUNNER}" == "rc.shutdown" ]];then 50 | exec "${BEGINNING_LIBEXEC}"/poweroff 51 | else 52 | if [[ "$1" == '-r' ]];then 53 | exec reboot 54 | else 55 | kill -10 1 56 | fi 57 | fi 58 | ;; 59 | poweroff|halt) 60 | if [[ "${BEGINNING_RUNNER}" == "rc.shutdown" ]];then 61 | exec "${BEGINNING_LIBEXEC}"/"${bin}" 62 | else 63 | kill -10 1 64 | fi 65 | ;; 66 | esac 67 | -------------------------------------------------------------------------------- /lib/rc.shutdown: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | ## start 21 | if [[ "$PPID" -ne 1 ]];then 22 | printf 'This script should only be ran from `begin`.\n' >&2 23 | exit 1 24 | fi 25 | 26 | # Since we check for the readability/existence of rc.functions in rc.init, 27 | # we don't really need to check again. If you remove it then uh... 28 | # don't do that, stupid 29 | LIBDIR="@@libdir@@" 30 | . "${LIBDIR}"/beginning/rc.functions 31 | 32 | BEGINNING_RUNNER=rc.shutdown 33 | 34 | case "$1" in 35 | reboot) 36 | word="Rebooting" 37 | ;; 38 | poweroff) 39 | word="Shutting down" 40 | ;; 41 | *) 42 | printf "Invalid action '$1' for rc.shutdown\n" 1>&2 43 | exit 1 44 | ;; 45 | esac 46 | 47 | clear;printf '\n';tput reset;chvt 1 48 | 49 | printf "\e[0m%s ${ANSI_COLOR}%s\e[0m...\n\n" "${word}" "${PRETTY_NAME}" 50 | 51 | # Allow for ctrl-alt-del hard reboots, for if this script breaks 52 | { echo 1 > /proc/sys/kernel/ctrl-alt-del; } >/dev/null 2>&1 || ctrlaltdel hard >/dev/null 2>&1 53 | 54 | stty -F /dev/tty0 -echo 2>/dev/null 55 | 56 | 57 | beginning_daemon_stop $(echo ${CORE_DAEMONS_BEFORE[@]} $(beginning_daemon_list) ${DAEMONS[@]} ${CORE_DAEMONS_AFTER[@]} | tr ' ' '\n' | tac) 58 | 59 | printf 'Sending TERM to all processes...\n' 60 | killall5 -15 61 | sleep 1 62 | 63 | printf 'Sending KILL to all processes...\n' 64 | killall5 -9 65 | 66 | printf 'Remounting root as read-only...\n' 67 | mount -o remount,ro / 68 | 69 | printf 'Unmounting filesystems...\n' 70 | umount -av 71 | 72 | printf '%s...\n' "${word}" 73 | 74 | case "$1" in 75 | reboot) 76 | reboot -f 77 | ;; 78 | poweroff) 79 | poweroff -f 80 | ;; 81 | esac 82 | 83 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?=cc 2 | CFLAGS ?=-O2 -g 3 | PKG_CONFIG ?=pkg-config 4 | 5 | DESTDIR ?=$(PWD)/image 6 | BUILD ?=$(PWD)/build 7 | 8 | prefix ?=/usr/local 9 | exec_prefix ?=$(prefix) 10 | bindir ?=$(exec_prefix)/bin 11 | sbindir ?=$(exec_prefix)/sbin 12 | libdir ?=$(exec_prefix)/lib 13 | libexecdir ?=$(exec_prefix)/libexec 14 | datarootdir ?=$(prefix)/share 15 | datadir ?=$(datarootdir) 16 | sysconfdir ?=$(prefix)/etc 17 | docdir ?=$(datarootdir)/doc/beginning-$(VERSION) 18 | mandir ?=$(datarootdir)/man 19 | localstatedir ?=$(prefix)/var 20 | runstatedir ?=$(localstatedir)/run 21 | 22 | bash_completion ?=true 23 | COPYRIGHT ?= 24 | VERSION =scm 25 | 26 | ifeq ($(bash_completion), true) 27 | bash_completion =true 28 | bashcompletiondir :=$(shell $(PKG_CONFIG) --variable=completionsdir bash-completion) 29 | else 30 | ifeq ($(bash_completion), false) 31 | bash_completion =false 32 | else 33 | $(error bash_completion can only be true or false) 34 | endif 35 | endif 36 | 37 | all: 38 | @printf "Beginning $(VERSION), an init system that isn't smarter than you\n\n" 39 | @printf "%-20s%-20s\n" \ 40 | "DESTDIR" "$(DESTDIR)" \ 41 | "BUILD" "$(BUILD)" \ 42 | "prefix" "$(prefix)" \ 43 | "exec_prefix" "$(exec_prefix)" \ 44 | "bindir" "$(bindir)" \ 45 | "sbindir" "$(sbindir)" \ 46 | "libdir" "$(libdir)" \ 47 | "libexecdir" "$(libexecdir)" \ 48 | "datarootdir" "$(datarootdir)" \ 49 | "datadir" "$(datadir)" \ 50 | "sysconfdir" "$(sysconfdir)" \ 51 | "docdir" "$(docdir)" \ 52 | "mandir" "$(mandir)" \ 53 | "localstatedir" "$(localstatedir)" \ 54 | "runstatedir" "$(runstatedir)" \ 55 | "bashcompletiondir" "$(bashcompletiondir)" \ 56 | "" "" \ 57 | "Options:" "" \ 58 | "COPYRIGHT" "$(COPYRIGHT)" \ 59 | "bash_completion" "$(bash_completion)" \ 60 | "" 61 | @$(MAKE) --no-print-directory build 62 | 63 | $(BUILD)/%: libexec/%.c 64 | -mkdir -p $(BUILD) 65 | $(CC) $(CFLAGS) $< -o $@ 66 | 67 | build: $(BUILD)/halt $(BUILD)/poweroff $(BUILD)/reboot 68 | mkdir -p $(BUILD) 69 | mkdir -p $(BUILD)$(bindir) 70 | mkdir -p $(BUILD)$(libdir)/beginning 71 | mkdir -p $(BUILD)$(libexecdir)/beginning 72 | mkdir -p $(BUILD)$(datadir) 73 | mkdir -p $(BUILD)$(sysconfdir) 74 | mkdir -p $(BUILD)$(docdir) 75 | cp -r bin/* $(BUILD)$(bindir) 76 | cp -r lib/* $(BUILD)$(libdir)/beginning 77 | mv $(BUILD)/reboot $(BUILD)/halt $(BUILD)/poweroff $(BUILD)$(libexecdir)/beginning 78 | cp -r etc/* $(BUILD)$(sysconfdir) 79 | cp -r doc/* $(BUILD)$(docdir) 80 | -if [ "$(bash_completion)" = 'true' ];then \ 81 | mkdir -p $(BUILD)$(bashcompletiondir) && \ 82 | cp -r share/bash-completion/* $(BUILD)$(bashcompletiondir); \ 83 | fi 84 | find $(BUILD) -type f -exec sed \ 85 | -e "s|@@prefix@@|$(prefix)|g" \ 86 | -e "s|@@exec_prefix@@|$(exec_prefix)|g" \ 87 | -e "s|@@bindir@@|$(bindir)|g" \ 88 | -e "s|@@sbindir@@|$(sbindir)|g" \ 89 | -e "s|@@libdir@@|$(libdir)|g" \ 90 | -e "s|@@libexecdir@@|$(libexecdir)|g" \ 91 | -e "s|@@datarootdir@@|$(datarootdir)|g" \ 92 | -e "s|@@datadir@@|$(datadir)|g" \ 93 | -e "s|@@sysconfdir@@|$(sysconfdir)|g" \ 94 | -e "s|@@docdir@@|$(docdir)|g" \ 95 | -e "s|@@mandir@@|$(mandir)|g" \ 96 | -e "s|@@localstatedir@@|$(localstatedir)|g" \ 97 | -e "s|@@runstatedir@@|$(runstatedir)|g" \ 98 | -e "s|@@COPYRIGHT@@|$(COPYRIGHT)|g" \ 99 | -e "s|@@VERSION@@|$(VERSION)|g" \ 100 | -i {} \; 101 | @echo 102 | @for file in $$(grep -lr '^\#!/bin/bash' $(BUILD));do \ 103 | bash -n "$$file"; \ 104 | if [ $$? -eq 0 ];then \ 105 | echo "SYNTAX PASS: $$file"; \ 106 | else \ 107 | echo "SYNTAX FAIL: $$file"; \ 108 | exit 2; \ 109 | fi; \ 110 | done 111 | 112 | install: $(BUILD) 113 | mkdir -p $(DESTDIR) 114 | cp -r $(BUILD)/* $(DESTDIR) 115 | 116 | clean: 117 | rm -rf $(BUILD) 118 | 119 | .PHONY: all build clean 120 | 121 | -------------------------------------------------------------------------------- /lib/rc.init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | ## Start 21 | if [[ "$PPID" -ne 1 ]];then 22 | printf 'This script should only be ran from `begin`.\n' >&2 23 | exit 1 24 | fi 25 | 26 | LIBDIR="@@libdir@@" 27 | BEGINNING_DIR="${LIBDIR}"/beginning 28 | 29 | BEGINNING_CLEAN_DIRECTORIES=( /tmp /run ) 30 | BEGINNING_EXPECTED_DIRECTORIES=( /dev /proc /tmp "@@runstatedir@@"{,/beginning,/user,/lock} /sys ) 31 | if [[ -r "${BEGINNING_DIR}"/rc.functions ]];then 32 | . "${BEGINNING_DIR}"/rc.functions 33 | else 34 | printf 'Could not find %s/rc.functions, going into emergency shell...\n' "${BEGINNING_DIR}" 35 | while true;do 36 | sulogin && exec "$0" 37 | done 38 | fi 39 | 40 | BEGINNING_RUNNER=rc.init 41 | 42 | rchook pre_beginning 43 | 44 | # We've read the configuration... time to start working. 45 | dmesg -n 3 46 | 47 | [[ "${RC_CLEAR_BOOT}" == true ]] && clear 48 | 49 | printf "Beginning ${ANSI_COLOR}%s\e[0m...\n" "${PRETTY_NAME}" 50 | [[ "${COPYRIGHT}" ]] && printf "\t%s\n" "${COPYRIGHT}${HOME_URL:+ - ${HOME_URL}}${SUPPORT_URL:+ - ${SUPPORT_URL}}" 51 | printf "\t%s\n" "${BEGINNING_COPYRIGHT}" "Running $(uname -srvm)" 52 | printf "\n" 53 | 54 | # Disable echoing of keyboard input so everything looks pretty even if you're messing with keys 55 | stty -F /dev/tty0 -echo 2>/dev/null 56 | 57 | for d in ${BEGINNING_EXPECTED_DIRECTORIES[@]};do 58 | mkdir -p "${d}" >/dev/null 2>&1 59 | d= 60 | done 61 | 62 | # Mount partitions required to do anything useful 63 | printf "Mounting system partitions...\n" 64 | mountpoint -q /proc || mount -n -t proc -o nodev,noexec,nosuid proc /proc 65 | mountpoint -q /sys || mount -n -t sysfs -o nodev,noexec,nosuid sys /sys 66 | mountpoint -q /dev || mount -n -t devtmpfs -o nosuid,mode=0755 dev /dev 67 | mkdir -p /dev/{pts,shm} >/dev/null 2>&1 68 | mountpoint -q /dev/pts || mount -n -t devpts -o mode=0620 devpts /dev/pts 69 | mountpoint -q /dev/shm || mount -n -t tmpfs -o nodev,nosuid,noexec shm /dev/shm 70 | mountpoint -q /tmp || mount -n -t tmpfs -o nodev,nosuid,noexec tmpfs /tmp 71 | mountpoint -q "@@runstatedir@@" || mount -n -t tmpfs -o rw,nosuid,nodev,mode=755 tmpfs "@@runstatedir@@" 72 | 73 | # Enable ctrl-alt-del rebooting 74 | { echo 0 > /proc/sys/kernel/ctrl-alt-del; } >/dev/null 2>&1 || ctrlaltdel soft >/dev/null 2>&1 75 | 76 | # If we specify that the kernel should be verbose, we should tell dmesg 77 | if [[ " $(/dev/null 2>&1 109 | d= 110 | done 111 | for d in ${BEGINNING_EXPECTED_DIRECTORIES[@]};do 112 | [[ -d "${d}" ]] || mkdir -p "${d}" 113 | d= 114 | done 115 | 116 | rchook pre_fstab_mount 117 | printf "Mounting filesystems in fstab...\n" 118 | mount -a 119 | printf "Activating swap devices...\n" 120 | swapon -a 121 | 122 | printf "Storing dmesg output to %s...\n" "@@localstatedir@@/log/dmesg.log" 123 | dmesg > "@@localstatedir@@"/log/dmesg.log 124 | 125 | # If the kernel wants us to restrict dmesg to just the root, do so with the log 126 | if [[ -r /proc/sys/kernel/dmesg_restrict && $( "@@runstatedir@@"/utmp 133 | 134 | rchook post_boot 135 | 136 | if [[ " $(/dev/null 149 | 150 | wait 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **This project is abandoned.** I've been thoroughly convinced that this is 2 | a problem being solved well by existing systems, notably the `s6` process 3 | supervision suite of programs. 4 | 5 | This repository will continue to stay up for archival purposes. 6 | 7 | # Beginning, an init system that isn't smarter than you 8 | 9 | "_Omnium rerum principia parva sunt._" --Marcus Tullius Cicero 10 | 11 | An [ISC-licensed](LICENSE) init system and service manager, designed to be 12 | deterministic and minimal, but not difficult to use. 13 | 14 | **Beginning is still a work-in-progress.** Design choices may still change, 15 | and configurations may need to be updated often. You should keep an eye on 16 | the commit log and actually read the changes if you plan on installing this, 17 | until it is stable. 18 | 19 | ## Requirements 20 | - bash 21 | - C compiler (for the executables in libexec/) 22 | - coreutils (busybox is known to be enough) 23 | - bash-completion (if usage of `rc`'s completion script is desired) 24 | - pkg-config is needed to detect directory to install completion files to 25 | - (optional but highly recommended) [beginning-scripts] 26 | 27 | ## Installation 28 | 1. `git clone https://github.com/somasis/beginning`, or [download a release] 29 | 30 | 2. `make` 31 | 32 | The makefile follows GNU Makefile standards, and can be influenced by variables 33 | such as `DESTDIR`, `bindir`, `libdir`, `libexecdir`,`docdir`, `sysconfdir`, 34 | and `prefix`. Variables for directories are changed in the source files. 35 | 36 | The top of the Makefile contains a full list of variables. 37 | 38 | If bash_completion should not be installed, set bash_completion to 39 | anything but 'true'. 40 | 41 | 3. `make install` 42 | 43 | Beginning only comes with two core daemons, `hostname` and `randomseed` which are 44 | considered to be important enough to be part of the default installation. 45 | All other daemon scripts written so far are located in [beginning-scripts] and 46 | are almost certainly needed if you wish to have a nice default system. 47 | 48 | See [beginning-scripts]'s README for usage. 49 | 50 | [download a release]: https://github.com/somasis/beginning/releases 51 | [beginning-scripts]: https://github.com/somasis/beginning-scripts 52 | 53 | ### Defaults 54 | - The `PID 1` will be installed to `$(PREFIX)$(bindir)/begin`. To use it as 55 | the default init system, either add `init=/bin/begin` to your kernel's boot 56 | parameters, or make a symlink at `/bin/init` that points to `begin`. 57 | - A reboot/shutdown/poweroff/halt program is installed to 58 | `$(PREFIX)$(bindir)/reboot`. Run it as root to reboot, make a symlink to it 59 | named `poweroff`, `halt`, and `shutdown` in order to turn off the system. 60 | 61 | ## Usage 62 | After installation, `/bin/begin` will need to be linked to `/bin/init`. Or, 63 | you can just add `init=/bin/begin` to the kernel command line if you wish. 64 | 65 | ## Rationale and Design choices 66 | *Prior art: OpenBSD init, systemd, Arch Linux initscripts, sinit* 67 | 68 | Beginning is my response to systemd and friends. I've used systemd, 69 | Upstart, OpenRC, Arch Linux's initscripts, and basically all of them leave 70 | a bit to be desired, are annoying to use, feel inconsistent, or do too much. 71 | 72 | The philosophy behind it is very much akin to how BSD-style inits work. 73 | 74 | Configuration is intended to be flexible, but not overbearing; in addition, 75 | I want it to be as deterministic as it can. The program should not have any 76 | functionality which decides for the user; things like providers for virtuals, 77 | order to run daemons in, and so on, should all be determined and executed the 78 | same way each time. While this does mean it requires some initial set up 79 | before you can safely reboot with Beginning as your init, it means that you 80 | can expect it to always run the same way, regardless of what changes on your 81 | system. (aside from obvious things such as removing daemons and stuff) 82 | 83 | You could also consider this to be a demonstration of just how simple init 84 | systems really need to be; the most complex part of this is probably the 85 | daemon dependency resolution. 86 | 87 | The actual `init` program is just 34 SLOC, because all `init` has to do is 88 | sleep forever, and handle shutdown and reboot signals. `bash` takes care of 89 | reparenting children processes for us. 90 | 91 | Beginning can be ran with theoretically any sensible filesystem layout, but for 92 | intents of compatibility and forward-looking practices, it expects the 93 | filesystem to loosely adhere to systemd's own `file-hierarchy(7)` guidelines. 94 | 95 | `file-hierarchy(7)` is used because it provides some compatibility with 96 | programs that expect the layout, distributions which have adopted it, as well as 97 | the author liking it. 98 | 99 | ### What it does have 100 | - `PID 1` 101 | - Only handles shutdown, reboot, and starting the service manager 102 | - Service management 103 | - Daemon starting, with dependency resolution 104 | - Virtuals, with customizable providers for them (network/syslog/udev, 105 | etc.) 106 | - `rc`, the main way for interacting with Beginning 107 | - `rc.conf`, which allows for lots of configuration 108 | 109 | ### What it does not have 110 | - No runlevels (`telinit 1`, `systemctl start multi-user.target`, etc.) 111 | - No network management (use a separate daemon for that) 112 | - No socket managing 113 | - Not enough possible benefits of using sockets for daemons. If you 114 | have to keep starting and stopping `sshd` instances when users come 115 | and go to conserve resources, you might have bigger problems on your 116 | hands. 117 | - No enable/disable functionality in `rc` 118 | - Keeping in line with having deterministic functionality, it seems to me that 119 | having the boot sequence be affected by a command line program, rather than 120 | explicit configuration editing would go against Beginning's philosophy. 121 | - OpenBSD apparently switched to using key=value format for their `rc.conf`; 122 | but we don't want to do that because having functions in rc.conf is nice. 123 | 124 | -------------------------------------------------------------------------------- /bin/rc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | BEGINNING_RUNNER= 21 | BEGINNING_LIB="@@libdir@@"/beginning 22 | 23 | if [[ -r "${BEGINNING_LIB}"/rc.functions ]];then 24 | . "${BEGINNING_LIB}"/rc.functions 25 | else 26 | printf 'Could not find %s/rc.functions...\n' "${BEGINNING_LIB}" 27 | exit 2 28 | fi 29 | 30 | if [[ "${UID}" -ne 0 ]];then 31 | printf 'Must be root to use %s.\n' "${0##*/}" 32 | exit 4 33 | fi 34 | 35 | commands=( 36 | --help 37 | --version 38 | list 39 | ls 40 | print-commands 41 | providers 42 | restart 43 | start 44 | status 45 | stop 46 | $(declare -F | sed 's/.*declare -f //' | grep -- '^beginning_daemon_.*') 47 | ) 48 | 49 | help() { 50 | echo "usage: ${0##*/} [daemon]" 51 | echo 52 | echo "commands:" 53 | printf ' %s\n' ${commands[@]} | cut -d'|' -f2- 54 | } 55 | 56 | version() { 57 | echo "Beginning ${VERSION}" 58 | } 59 | 60 | rc_list() { 61 | [[ -n "$2" ]] || shift 62 | case "$2" in 63 | '') 64 | for dae in $(beginning_daemon_list started "${@}" 2>/dev/null);do 65 | beginning_daemon_load "${dae}" >/dev/null 2>&1 66 | provides=$(${dae}_provides 2>/dev/null) 67 | status STARTED "${dae}${provides:+ ($provides)}" 68 | done 69 | for dae in $(beginning_daemon_list stopped "${@}" 2>/dev/null);do 70 | beginning_daemon_load "${dae}" >/dev/null 2>&1 71 | provides=$(${dae}_provides 2>/dev/null) 72 | status STOPPED "${dae}${provides:+ ($provides)}" 73 | done 74 | ;; 75 | virtuals|all|started|stopped|existent|nonexistent|daemons) 76 | beginning_daemon_list "${2}" 2>/dev/null 77 | ;; 78 | esac 79 | } 80 | 81 | rc_status() { 82 | [[ $# -lt 2 ]] && help && return 3 83 | shift 84 | beginning_daemon_list all 2>/dev/null | for dae in "${@}";do 85 | grep -q "^${dae}$" 86 | done 87 | 88 | for dae in $(beginning_daemon_list started "${@}" 2>/dev/null);do 89 | status STARTED "${dae}" 90 | done 91 | for dae in $(beginning_daemon_list stopped "${@}" 2>/dev/null);do 92 | status STOPPED "${dae}" 93 | done 94 | } 95 | 96 | rc_providers() { 97 | [[ $# -ne 2 ]] && help && return 2 98 | shift 99 | BEGINNING_PROVIDER_LIST_ONLY=true 100 | beginning_daemon_load "${1}" >/dev/null 2>&1 101 | providers=$(beginning_daemon_provider "" "$1" "installed") 102 | possible=$(beginning_daemon_provider "" "$1" "all") 103 | if [[ "${providers}" ]];then 104 | for p in ${providers};do 105 | echo "$p" 106 | done 107 | elif ! "${1}"_virtual >/dev/null 2>&1;then 108 | printf '%s: %s is not a virtual and therefore has no providers.\n' "${0##*/}" "$1" >&2 109 | return 20 110 | elif [[ -z "${possible}" ]];then 111 | printf '%s: %s does not have any providers, installed or nonexisttent.\n' "${0##*/}" "$1" >&2 112 | elif [[ -z "${providers}" ]];then 113 | printf '%s: %s does not have any providers installed. Possible providers: %s\n' "${0##*/}" "$1" "${possible}" >&2 114 | return 30 115 | fi 116 | } 117 | 118 | rc_action() { 119 | [[ "$#" -lt 2 ]] && return 1 120 | act="$1" 121 | shift 122 | for dae in ${@};do 123 | err= 124 | beginning_daemon_load "${dae}" >/dev/null 2>&1 125 | if func_exists ${dae}_exists && ! ${dae}_exists >/dev/null 2>&1;then 126 | err=5 127 | elif func_exists beginning_daemon_${act};then 128 | beginning_daemon_${act} "${dae}" 129 | elif func_exists ${dae}_${act};then 130 | beginning_daemon_do ${dae} ${act} 131 | else 132 | err=1 133 | fi 134 | err=${err:-$?} 135 | done 136 | if [[ "$err" -eq 5 ]];then 137 | printf "%s: %s isn't installed.\n" "${0##*/}" "${dae}" >&2 138 | elif [[ "$err" -eq 4 ]];then 139 | printf "%s: %s does not have a %s action.\n" "${0##*/}" "${dae}" "${act}" >&2 140 | elif [[ "$err" -eq 3 ]];then 141 | printf "%s: %s: script not found.\n" "${0##*/}" "${dae}" >&2 142 | fi 143 | return $err 144 | } 145 | 146 | rc_restart() { 147 | local d 148 | for d in $@;do 149 | beginning_daemon_status started "${d}" && rc_action stop "${d}" 150 | rc_action start "${d}" 151 | done 152 | } 153 | 154 | case "$1" in 155 | # non-daemon actions 156 | --help) 157 | help 158 | ;; 159 | --version) 160 | version 161 | ;; 162 | print-commands) 163 | printf '%s\n' ${commands[@]} 164 | ;; 165 | 166 | # internal functions 167 | beginning_daemon_*) 168 | [[ $# -lt 2 ]] && help && exit 2 169 | act="$1" 170 | shift 171 | "${act}" "$@"; exit $? 172 | ;; 173 | 174 | # informative 175 | list|ls|'') 176 | rc_list "$@" 177 | ;; 178 | status) 179 | rc_status "$@" 180 | ;; 181 | 182 | providers) 183 | rc_providers "$@" 184 | ;; 185 | 186 | # acting on daemons 187 | restart) 188 | shift 189 | rc_restart "$@" 190 | ;; 191 | *) 192 | rc_action "$@" 193 | ;; 194 | esac 195 | 196 | exit $? 197 | 198 | -------------------------------------------------------------------------------- /lib/rc.functions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Beginning - an init system that isn't smarter than you 4 | # 5 | # Copyright (c) 2015-2016 Kylie McClain 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | umask 022 21 | 22 | export PATH="@@sbindir@@:@@bindir@@:/bin:/sbin" 23 | 24 | BEGINNING_PLATFORM=$(uname -s) 25 | 26 | VERSION="@@VERSION@@" 27 | 28 | LIBEXECDIR="@@libexecdir@@" 29 | LIBDIR="@@libdir@@" 30 | SYSCONFDIR="@@sysconfdir@@" 31 | 32 | BEGINNING_LIB="${LIBDIR}"/beginning 33 | BEGINNING_LIBEXEC="${LIBEXECDIR}"/beginning 34 | BEGINNING_RC="${BEGINNING_LIB}"/rc.d 35 | USER_RC="${SYSCONFDIR}"/rc.d 36 | 37 | [[ -r "${BEGINNING_LIB}"/rc.conf ]] && . "${BEGINNING_LIB}"/rc.conf 38 | [[ -r "${SYSCONFDIR}"/rc.conf ]] && . "${SYSCONFDIR}"/rc.conf 39 | # os-release contains things such as distro name, distro's 'color'... 40 | [[ -r "${LIBDIR}"/os-release ]] && . "${LIBDIR}"/os-release 41 | [[ -r "${SYSCONFDIR}"/os-release ]] && . "${SYSCONFDIR}"/os-release 42 | 43 | if [[ -d "${BEGINNING_LIB}"/rc.conf.d ]];then 44 | for file in "${BEGINNING_LIB}"/rc.conf.d/*;do 45 | . "${file}" 46 | done 47 | file= 48 | fi 49 | if [[ -d "${SYSCONFDIR}"/rc.conf.d ]];then 50 | for file in "${SYSCONFDIR}"/rc.conf.d/*;do 51 | . "${file}" 52 | done 53 | file= 54 | fi 55 | 56 | if [[ ! -r "${BEGINNING_LIB}"/rc.conf && ! -f "${SYSCONFDIR}"/rc.conf ]];then 57 | printf 'Could not read/find %s/rc.conf or %s/rc.conf, going into emergency shell...\n' "${BEGINNING_LIB}" "${SYSCONFDIR}" 58 | emergency_shell 59 | fi 60 | 61 | # If os-release gives us a color, use it; if not, use the reset color code 62 | ANSI_COLOR="\e[${ANSI_COLOR:-0}m" 63 | [[ -z "$PRETTY_NAME" ]] && PRETTY_NAME="${NAME:-$BEGINNING_PLATFORM}" 64 | 65 | status() { 66 | local bold='\e[1m' 67 | local fg_black='\e[30m' 68 | local fg_red='\e[31m' 69 | local fg_green='\e[32m' 70 | local fg_white='\e[37m' 71 | local bg_black='\e[40m' 72 | local bg_red='\e[41m' 73 | local bg_green='\e[42m' 74 | local bg_white='\e[47m' 75 | local reset='\e[0m' 76 | local stat="${1^^}" 77 | STATUS_SUCCESS="${bold}${fg_white}${bg_green}" 78 | STATUS_STARTED=${STATUS_SUCCESS} 79 | STATUS_FAILURE="${bold}${fg_white}${bg_red}" 80 | STATUS_STOPPED=${STATUS_FAILURE} 81 | STATUS_UNKNOWN="${bold}${fg_white}${bg_black}" 82 | STATUS_NOTHING=${STATUS_UNKNOWN} 83 | STATUS_CUSTOM=${STATUS_UNKNOWN} 84 | shift 85 | 86 | case "${stat}" in 87 | STARTED) printf "\e[2K\r${STATUS_STARTED}[ ${stat} ]${reset} %s\n" "$@${BEGINNING_STARTED:+: ${BEGINNING_STARTED}}" ;; # green bg [white] 88 | SUCCESS) printf "\e[2K\r${STATUS_SUCCESS}[ ${stat} ]${reset} %s\n" "$@${BEGINNING_SUCCESS:+: ${BEGINNING_SUCCESS}}" ;; # green bg [white] 89 | FAILURE) printf "\e[2K\r${STATUS_FAILURE}[ ${stat} ]${reset} %s\n" "$@${BEGINNING_FAILURE:+: ${BEGINNING_FAILURE}}" ;; # red bg [white] 90 | STOPPED) printf "\e[2K\r${STATUS_STOPPED}[ ${stat} ]${reset} %s\n" "$@${BEGINNING_STOPPED:+: ${BEGINNING_STOPPED}}" ;; # red bg [white] 91 | UNKNOWN) printf "\e[2K\r${STATUS_UNKNOWN}[ ${stat} ]${reset} %s\n" "$@${BEGINNING_UNKNOWN:+: ${BEGINNING_UNKNOWN}}" ;; # black bg [white] 92 | NOTHING) printf "\e[2K\r${STATUS_NOTHING}[ ]${reset} %s" "$@${BEGINNING_NOTHING:+: ${BEGINNING_NOTHING}}" ;; # black bg [white] 93 | CUSTOM) printf "\e[2K\r${STATUS_CUSTOM}[ ]${reset} %s" "$@${BEGINNING_CUSTOM:+: ${BEGINNING_CUSTOM}}" ;; # black bg [white] 94 | esac 95 | } 96 | 97 | emergency_shell() { 98 | while true;do 99 | setsid sulogin && exec "$@" 100 | done 101 | } 102 | 103 | reverse() { 104 | if [[ $# -ne 0 ]];then 105 | local rev="$1" 106 | shift 107 | reverse "$@" 108 | printf '%s\n' "$rev" 109 | fi 110 | } 111 | 112 | func_exists() { 113 | local func err 114 | for func in $@;do 115 | type -t "${func}" >/dev/null 2>&1 116 | err=$? 117 | [[ "${err}" -eq 0 ]] || break 118 | done 119 | [[ "${err}" -eq 0 ]] || return $? 120 | } 121 | 122 | prog_exists() { 123 | local prog err 124 | for prog in $@;do 125 | type -fPt "${prog}" >/dev/null 2>&1 126 | err=$? 127 | [[ "${err}" -eq 0 ]] || break 128 | done 129 | [[ "${err}" -eq 0 ]] || return $? 130 | } 131 | 132 | beginning_daemon_load() { 133 | local daemon file 134 | for daemon in $@;do 135 | file=$(beginning_daemon_file "${daemon}" 2>/dev/null) 136 | if [[ "${file}" ]];then 137 | . "${file}" >/dev/null 2>&1 || printf "%s: invalid script. possible syntax errors?\n" "${daemon}" >&2 && return 4 138 | else 139 | printf "%s: script not found.\n" "${daemon}" >&2 140 | return 3 141 | fi 142 | done 143 | } 144 | 145 | beginning_daemon_file() { 146 | local daemon 147 | for daemon in $@;do 148 | if [[ -f "${USER_RC}/${daemon}" ]];then 149 | echo "${USER_RC}/${daemon}" 150 | elif [[ -f "${BEGINNING_RC}/${daemon}" ]];then 151 | echo "${BEGINNING_RC}/${daemon}" 152 | else 153 | return 1 154 | fi 155 | done 156 | } 157 | 158 | beginning_daemon_list() { 159 | local daemon daes=() list="${1}" 160 | if [[ "$#" -gt 1 ]];then 161 | shift 162 | daes=( "$@" ) 163 | else 164 | daes=( ${BEGINNING_RC}/* ${USER_RC}/* ) 165 | fi 166 | for daemon in "${daes[@]}";do 167 | daemon=${daemon##*/} 168 | [[ "${daemon}" == '*' ]] && continue 169 | beginning_daemon_load "${daemon}" 2>/dev/null 170 | case "${list^^}" in 171 | STARTED) 172 | if func_exists ${daemon}_status && ${daemon}_exists && ${daemon}_status;then 173 | echo "${daemon}" 174 | fi 175 | ;; 176 | STOPPED) 177 | if func_exists ${daemon}_status && ${daemon}_exists && ! ${daemon}_status;then 178 | echo ${daemon} 179 | fi 180 | ;; 181 | NONEXISTENT) 182 | if func_exists ${daemon}_exists && ! ${daemon}_exists;then 183 | echo ${daemon} 184 | fi 185 | ;; 186 | EXISTENT) 187 | if func_exists ${daemon}_exists && ${daemon}_exists;then 188 | echo ${daemon} 189 | fi 190 | ;; 191 | DAEMONS) 192 | if ! func_exists ${daemon}_virtual;then 193 | echo ${daemon} 194 | fi 195 | ;; 196 | VIRTUALS) 197 | if func_exists ${daemon}_virtual;then 198 | echo ${daemon} 199 | fi 200 | ;; 201 | ALL) 202 | echo ${daemon} 203 | ;; 204 | esac 205 | done 206 | } 207 | 208 | beginning_daemon_provider() { 209 | local action="${1}" 210 | local daemon="${2}" 211 | local type="${3:-installed}" 212 | 213 | d_list= 214 | d_list=( 215 | $(for d in $(beginning_daemon_list all);do 216 | beginning_daemon_load "$d" 217 | if func_exists ${d##*/}_exists && ! ${d##*/}_exists;then 218 | [[ "${type}" == "installed" ]] && continue 219 | if [[ " $(func_exists ${d##*/}_provides && ${d##*/}_provides) " == *" ${daemon} "* ]];then 220 | echo "${d##*/}" 221 | fi 222 | elif func_exists ${d##*/}_exists && ${d##*/}_exists;then 223 | if [[ " $(func_exists ${d##*/}_provides && ${d##*/}_provides) " == *" ${daemon} "* ]];then 224 | echo "${d##*/}" 225 | fi 226 | fi 227 | done 2>/dev/null) 228 | ) 229 | [[ "${BEGINNING_PROVIDER_LIST_ONLY}" ]] && echo "${d_list[*]}" && return 0 230 | local provider= 231 | local provider=${daemon^^}_PROVIDER 232 | local provider=${!provider} 233 | if [[ -z ${d_list[*]} ]];then 234 | status FAILURE "${daemon}: has no providers. You need to install one." 235 | return 3 236 | fi 237 | 238 | if [[ -n "${provider}" && " ${d_list[@]} " == *" ${provider} "* ]];then 239 | d_list=( "${provider}" ) 240 | elif [[ -n "${provider}" && " ${d_list[@]} " != *" ${provider} "* ]];then 241 | status FAILURE "${daemon}: invalid provider. Possible providers: ${d_list[*]}" 242 | return 1 243 | elif [[ -z "${provider}" && -n "${d_list[@]}" ]];then 244 | status FAILURE "${daemon}: provider is not set. Possible providers: ${d_list[*]}" 245 | return 2 246 | fi 247 | if [[ -n ${d_list} ]];then # space removal intentional 248 | beginning_daemon_${action} "${d_list}"; return $? 249 | fi 250 | } 251 | 252 | beginning_daemon_start() { 253 | export BEGINNING_PHASE=start 254 | local daemon 255 | for daemon in ${@};do 256 | beginning_daemon_load "${daemon}" 257 | if func_exists ${daemon}_virtual && ${daemon}_virtual;then 258 | if [[ -z "$BEGINNING_NO_RESOLVE_DEPENDS" ]];then 259 | BEGINNING_RESOLVING_DEPS=true 260 | func_exists ${daemon}_depends && beginning_daemon_start $(${daemon}_depends) 261 | BEGINNING_RESOLVING_DEPS= 262 | fi 263 | if func_exists ${daemon}_wants;then 264 | BEGINNING_RESOLVING_DEPS=true 265 | beginning_daemon_start $(${daemon}_wants) || true 266 | BEGINNING_RESOLVING_DEPS= 267 | fi 268 | beginning_daemon_provider start "${daemon}" 269 | continue 270 | fi 271 | if func_exists ${daemon}_exists && ${daemon}_exists;then 272 | true 273 | else 274 | continue 275 | fi 276 | if func_exists ${daemon}_status;then 277 | if ! ${daemon}_status;then 278 | if [[ -z "$BEGINNING_NO_RESOLVE_DEPENDS" ]];then 279 | BEGINNING_RESOLVING_DEPS=true 280 | func_exists ${daemon}_depends && beginning_daemon_start $(${daemon}_depends) 281 | BEGINNING_RESOLVING_DEPS= 282 | fi 283 | if func_exists ${daemon}_wants;then 284 | BEGINNING_RESOLVING_DEPS=true 285 | beginning_daemon_start $(${daemon}_wants) || true 286 | BEGINNING_RESOLVING_DEPS= 287 | fi 288 | if func_exists ${daemon}_start;then 289 | status CUSTOM "${daemon}" 290 | ${daemon}_start 291 | if [[ $? -eq 0 ]];then 292 | status STARTED "${daemon}" 293 | else 294 | status FAILURE "${daemon}" 295 | fi 296 | fi 297 | else 298 | [[ -z "${BEGINNING_RESOLVING_DEPS}" ]] && [[ "${BEGINNING_RUNNER}" != rc.init ]] && status STARTED "${daemon}: already started" 299 | fi 300 | fi 301 | done 302 | } 303 | 304 | beginning_daemon_stop() { 305 | export BEGINNING_PHASE=stop 306 | local daemon 307 | for daemon in ${@};do 308 | if [[ " ${BEGINNING_SKIP_DEPS} " == *" ${daemon} "* ]];then 309 | continue 310 | fi 311 | beginning_daemon_load "${daemon}" 312 | if func_exists ${daemon}_virtual && ${daemon}_virtual;then 313 | beginning_daemon_provider stop ${daemon}; continue 314 | elif ! func_exists ${daemon}_exists || func_exists ${daemon}_exists && ! ${daemon}_exists;then 315 | continue 316 | fi 317 | BEGINNING_RESOLVING_DEPS=true 318 | d_list=( 319 | $(for d in $(beginning_daemon_list all);do 320 | beginning_daemon_load "$d" || true 321 | func_exists ${d}_depends && ${d}_depends | 322 | while read line;do 323 | [[ " $line " == *" ${daemon} "* ]] && echo "${d}" 324 | done 325 | done) 326 | ) 327 | depends=( ) 328 | for dep in ${d_list[@]};do 329 | dname=${dep/:*} 330 | [[ " ${BEGINNING_SKIP_DEPS} " == *" ${dname} "* ]] && continue 331 | depends+=( "${dname}" ) 332 | done 333 | if [[ " ${depends[@]} " != *" ${daemon} "* ]];then 334 | BEGINNING_SKIP_DEPS="${BEGINNING_SKIP_DEPS} ${daemon} " beginning_daemon_stop ${depends[@]} 335 | fi 336 | if func_exists ${daemon}_status;then 337 | if ${daemon}_status;then 338 | if func_exists ${daemon}_stop;then 339 | status CUSTOM "${daemon}" 340 | ${daemon}_stop 341 | if [[ $? -eq 0 ]];then 342 | status STOPPED "${daemon}" 343 | else 344 | status FAILURE "${daemon}" 345 | fi 346 | fi 347 | else 348 | [[ -z "${BEGINNING_SKIP_DEPS}" ]] && status FAILURE "${daemon}: already stopped" 349 | fi 350 | fi 351 | done 352 | } 353 | 354 | beginning_daemon_do() { 355 | local daemon="$1" action="$2" require_started="${3:-true}" 356 | if func_exists ${daemon}_${action};then 357 | if [[ "${require_started,,}" == "true" ]];then 358 | if ! ${daemon}_status;then 359 | status FAILURE "${daemon}: must be running for \`${action}\`" 360 | return 1 361 | fi 362 | fi 363 | status CUSTOM "${daemon}${action:+: $action}" 364 | ${daemon}_${action} 365 | if [[ $? -eq 0 ]];then 366 | status SUCCESS "${daemon}" 367 | else 368 | status FAILURE "${daemon}" 369 | return 2 370 | fi 371 | fi 372 | } 373 | 374 | beginning_daemon_status() { 375 | local status="$1" d 376 | shift 377 | for d in $@;do 378 | if [[ -z $(beginning_daemon_list "${status}" "${d}") ]];then 379 | return 1 380 | else 381 | return 0 382 | fi 383 | done 384 | } 385 | 386 | # check if $1's contents is a pid which is exists 387 | pidfileexists() { 388 | if [[ -f "${1}" ]];then 389 | local pid=$(<"${1}") 390 | elif [[ -f "@@runstatedir@@"/beginning/"${1}".pid ]];then 391 | local pid=$(<"@@runstatedir@@"/beginning/"${1}".pid) 392 | elif [[ -f "@@runstatedir@@"/"${1}" ]];then 393 | local pid=$(<"@@runstatedir@@"/"${1}") 394 | elif [[ -f "@@runstatedir@@"/"${1}".pid ]];then 395 | local pid=$(<"@@runstatedir@@"/"${1}".pid) 396 | else 397 | return 1 398 | fi 399 | pidexists "$pid" 400 | } 401 | 402 | # if we are root, we use the bash builtin kill, and if not we use ps 403 | # since kill will return 'operation not permitted' with a 1 errcode, which 404 | # would be interpreted as the pid not existing 405 | pidexists() { 406 | local pid="$1" 407 | if [[ "$UID" -eq 0 ]];then 408 | kill -0 "$pid" >/dev/null 2>&1; return $? 409 | else 410 | ps "$pid" >/dev/null 2>&1; return $? 411 | fi 412 | } 413 | 414 | pidfilewrite() { 415 | local pid="$1" file="$2" 416 | echo "$pid" > "@@runstatedir@@"/beginning/"${file}".pid 417 | } 418 | 419 | pidfile() { 420 | local pid="$1" file="$2" 421 | pidfilewrite "${pid}" "${file}" 422 | if pidexists "$pid";then 423 | return 0 424 | else 425 | return 1 426 | fi 427 | } 428 | 429 | pidfilekill() { 430 | [[ $# -gt 1 ]] && local sig="${1}" && shift 431 | if [[ -f "${1}" ]];then 432 | local pid=$(<"${1}") 433 | elif [[ -f "@@runstatedir@@"/beginning/"${1}".pid ]];then 434 | local pid=$(<"@@runstatedir@@"/beginning/"${1}".pid) 435 | elif [[ -f "@@runstatedir@@"/"${1}" ]];then 436 | local pid=$(<"@@runstatedir@@"/"${1}") 437 | elif [[ -f "@@runstatedir@@"/"${1}".pid ]];then 438 | local pid=$(<"@@runstatedir@@"/"${1}".pid) 439 | else 440 | return 1 441 | fi 442 | kill ${sig} "$pid" >/dev/null 2>&1 443 | return $? 444 | } 445 | 446 | killall5() { 447 | for pid in $(pgrep . | egrep -v "^(1|$$|$PPID)$");do 448 | disown "$pid" >/dev/null 2>&1 # hide Killed message from bash 449 | kill "${1:--15}" "$pid" >/dev/null 2>&1 450 | done 451 | } 452 | 453 | keeprunning() { 454 | local err 455 | local daemon="$1" 456 | shift 457 | while [[ "${err:-1}" -ne 0 ]];do 458 | local i=$(( ${i:-1} + 1 )) 459 | "$@"; local err=$? 460 | sleep 1 461 | if [[ "$i" -eq 10 ]];then 462 | break 463 | fi 464 | done 465 | } 466 | 467 | rchook() { 468 | if func_exists "$@";then 469 | status NOTHING "rchook: ${@}" 470 | if "$@";then 471 | status STARTED "rchook: ${@}" 472 | else 473 | status FAILURE "rchook: ${@}" 474 | fi 475 | fi 476 | } 477 | --------------------------------------------------------------------------------