├── CHANGES.md ├── LICENSE ├── Makefile ├── README.md ├── man ├── vsv.8 └── vsv.md ├── screenshots ├── vsv-add-service.jpg ├── vsv-arguments.jpg ├── vsv-down.jpg ├── vsv-log-tree.jpg ├── vsv-log.jpg ├── vsv-restart.jpg ├── vsv-service-status-yellow.jpg ├── vsv-status.jpg ├── vsv-tree-large.jpg ├── vsv-user-d.jpg ├── vsv-user-log.jpg └── vsv-user-u.jpg └── vsv /CHANGES.md: -------------------------------------------------------------------------------- 1 | vsv Changes 2 | =========== 3 | 4 | Not Yet Released 5 | ---------------- 6 | 7 | (nothing yet) 8 | 9 | `v1.3.5` 10 | -------- 11 | 12 | - [#16](https://github.com/bahamas10/vsv/pull/16) loosen-up defensive service name validation logic to allow "@" chars 13 | 14 | `v1.3.4` 15 | -------- 16 | 17 | - [#8](https://github.com/bahamas10/vsv/issues/8) better detect terminals with color support 18 | 19 | `v1.3.3` 20 | -------- 21 | 22 | - [#4](https://github.com/bahamas10/vsv/pull/4) Truncate command output to not overflow 17 characters (PR by @zdykstra) 23 | - [#6](https://github.com/bahamas10/vsv/issues/6) race condition when checking if a service is disabled 24 | 25 | `v1.3.2` 26 | -------- 27 | 28 | - Add license file (MIT) 29 | 30 | `v1.3.1` 31 | -------- 32 | 33 | - Update manpage 34 | 35 | `v1.3.0` 36 | -------- 37 | 38 | - [#1](https://github.com/bahamas10/vsv/pull/1) fix a typo (PR by @pltrz) 39 | - [#2](https://github.com/bahamas10/vsv/pull/2) Add support to enable/disable service (issue by @illiliti) 40 | 41 | `v1.2.1` 42 | -------- 43 | 44 | - Add manpage 45 | 46 | `v1.2.0` 47 | -------- 48 | 49 | - Add `-l` to status to show log processes 50 | - Add `COMMAND` to output (first arg of `cmdline`) 51 | 52 | `v1.1.0` 53 | -------- 54 | 55 | - Add `-V` to print version number 56 | 57 | `v1.0.0` 58 | -------- 59 | 60 | - Initial Commit 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Dave Eddy (https://www.daveeddy.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | 3 | .PHONY: all 4 | all: 5 | @echo 'nothing to do' 6 | 7 | .PHONY: man 8 | man: man/vsv.8 9 | man/vsv.8: man/vsv.md 10 | md2man-roff $^ > $@ 11 | 12 | .PHONY: clean 13 | clean: 14 | rm -f man/vsv.8 15 | 16 | .PHONY: install 17 | install: 18 | install -DTm755 vsv $(PREFIX)/bin/vsv 19 | install -DTm644 man/vsv.8 $(PREFIX)/share/man/man8/vsv.8 20 | 21 | .PHONY: uninstall 22 | uninstall: 23 | rm -f $(PREFIX)/bin/vsv 24 | rm -f $(PREFIX)/share/man/man8/vsv.8 25 | 26 | .PHONY: check 27 | check: 28 | shellcheck vsv 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `vsv` - Void Service Manager 2 | ============================ 3 | 4 | # DEPRECATION NOTICE 5 | 6 | This script has been deprecated as it has been rewritten in Rust 7 | 8 | https://github.com/bahamas10/vsv 9 | 10 | --- 11 | 12 | Manage and view runit services. 13 | 14 | `vsv` was inspired by [`vpm`](https://github.com/netzverweigerer/vpm). `vsv` is 15 | to `sv` as `vpm` is to the `xbps-*` commands. 16 | 17 | See my blog post on `vsv` here: https://www.daveeddy.com/2018/09/20/vsv-void-service-manager/ 18 | 19 | ![vsv-status.jpg](screenshots/vsv-status.jpg) 20 | 21 | Installation 22 | ------------ 23 | 24 | On [Void Linux](https://voidlinux.org/) run: 25 | 26 | xbps-install vsv 27 | 28 | Alternative Installation 29 | ------------------------ 30 | 31 | `vsv` is a standalone bash script that can be dumped anywhere in your `$PATH` 32 | to be used. 33 | 34 | ### `git` 35 | 36 | I personally install it with `git` (with `~/bin` in my `$PATH`): 37 | 38 | mkdir -p ~/bin ~/dev 39 | cd ~/dev 40 | git clone git://github.com/bahamas10/vsv.git 41 | ln -s ~/dev/vsv/vsv ~/bin 42 | 43 | ### `curl` or `wget` 44 | 45 | You can use `curl` or `wget` to pull the script directly from GitHub: 46 | 47 | mkdir -p ~/bin 48 | cd ~/bin 49 | wget https://raw.githubusercontent.com/bahamas10/vsv/master/vsv 50 | # or 51 | curl -O https://raw.githubusercontent.com/bahamas10/vsv/master/vsv 52 | # and then 53 | chmod +x ~/bin/vsv 54 | 55 | ### `Makefile` 56 | 57 | You can use the Makefile in this repo: 58 | 59 | $ sudo make install 60 | cp vsv /usr/local/bin 61 | cp man/vsv.8 /usr/local/share/man/man8/vsv.8 62 | 63 | And uninstall with: 64 | 65 | $ sudo make uninstall 66 | rm -f /usr/local/bin/vsv 67 | rm -f /usr/local/share/man/man8/vsv.8 68 | 69 | Examples 70 | -------- 71 | 72 | **Note:** Some screenshots are outdated or command output may have changed 73 | slightly in newer versions of `vsv`. 74 | 75 | Run `vsv` without any arguments to get process status. This is equivalent to 76 | running `vsv status`: 77 | 78 | ![vsv-status.jpg](screenshots/vsv-status.jpg) 79 | 80 | **Note:** `sudo` or escalated privileges are required to determine service state 81 | because of the strict permissions on each service's `supervise` directory. 82 | 83 | `vsv` scans the `/var/service` directory by default, which can be overridden by 84 | setting the `$SVDIR` environmental variable or passing in a `-d ` argument. 85 | Any service that has been in a state for less than 5 seconds will be marked 86 | in red, making new or failing services easy to spot: 87 | 88 | ![vsv-add-service.jpg](screenshots/vsv-add-service.jpg) 89 | 90 | Services in a state for more than 5 seconds but less than 30 seconds will be 91 | highlighted in yellow: 92 | 93 | ![vsv-service-status-yellow.jpg](screenshots/vsv-service-status-yellow.jpg) 94 | 95 | A string can be passed as the first argument after `status` to filter for 96 | services that contain that string in their name. Also, `-t` can be supplied to 97 | `status` to print the process tree of the pid for that process: 98 | 99 | ![vsv-arguments.jpg](screenshots/vsv-arguments.jpg) 100 | 101 | Any command other than `status` will be passed directly to the `sv` command. 102 | Restarting a service is as easy as `vsv restart `: 103 | 104 | ![vsv-restart.jpg](screenshots/vsv-restart.jpg) 105 | 106 | To stop a service, `vsv down ` or `vsv stop ` can be used: 107 | 108 | ![vsv-down.jpg](screenshots/vsv-down.jpg) 109 | 110 | A full service tree can be generated with `vsv -t`. This command is equivalent 111 | to running `vsv status -t`: 112 | 113 | ![vsv-tree-large.jpg](screenshots/vsv-tree-large.jpg) 114 | 115 | `-l` can be specified to view log services for each service as well. This 116 | command is equivalent to running `vsv status -l virt`: 117 | 118 | ![vsv-log.jpg](screenshots/vsv-log.jpg) 119 | 120 | `-t` can be specified with `-l` to view log services as a tree for each service 121 | as well as normal services. This command is equivalent to running `vsv status 122 | -tl virt`: 123 | 124 | ![vsv-log-tree.jpg](screenshots/vsv-log-tree.jpg) 125 | 126 | `vsv` also first-classes the notion of "user services". I wrote about this in 127 | my blog post for [Using Linux As My Daily 128 | Driver](https://www.daveeddy.com/2018/09/15/using-void-linux-as-my-daily-driver/) 129 | Basically, I have a separate instance of `runsvdir` running as my user out of 130 | `~/runit/service`, and the `vsv` script is set up to look in that location when 131 | invoked with `-u`. 132 | 133 | ![vsv-user-u.jpg](screenshots/vsv-user-u.jpg) 134 | 135 | Note that `-u` is just a shortcut for `-d ~/runit/service` - technically, any 136 | directory can be specified with that option: 137 | 138 | ![vsv-user-d.jpg](screenshots/vsv-user-d.jpg) 139 | 140 | All of the commands and options are supported when `-u` or `-d ` is 141 | specified. 142 | 143 | ![vsv-user-log.jpg](screenshots/vsv-user-log.jpg) 144 | 145 | Usage 146 | ----- 147 | 148 | Quick Examples: 149 | 150 | - `vsv` - show all services 151 | - `vsv status` - same as above 152 | - `vsv stop ` - stop a service 153 | - `vsv start ` - start a service 154 | - `vsv restart ` - restart a service 155 | - `vsv enable ` - enable a service (autostart at boot) 156 | - `vsv disable ` - disable a service (no autostart at boot) 157 | - `vsv hup ` - refresh a service (`SIGHUP`) 158 | 159 | Status: 160 | 161 | The `status` subcommand has the following fields: 162 | 163 | - `SERVICE` - the service (directory) name. 164 | - `STATE` - the service state: output from `.../$service/supervise/stat`. 165 | - `ENABLED` - if the service is enabled (lacks the `.../$service/down` file). 166 | - `PID` - the pid of the process being monitored. 167 | - `COMMAND` - arg0 from the pid being monitored (first field of `/proc/$pid/cmdline`. 168 | - `TIME` - time the service has been in whatever state it is in. 169 | 170 | Command Usage: 171 | 172 | $ vsv -h 173 | __ _______ __ 174 | \ \ / / __\ \ / / Void Service Manager (v1.3.0) 175 | \ V /\__ \\ V / Source: https://github.com/bahamas10/vsv 176 | \_/ |___/ \_/ MIT License 177 | 178 | [vsv] Manage and view runit services 179 | [vsv] Made specifically for Void Linux but should work anywhere 180 | [vsv] Author: Dave Eddy (bahamas10) 181 | 182 | USAGE: 183 | vsv [OPTIONS] [SUBCOMMAND] [] 184 | vsv [-u] [-d ] [-h] [-t] [SUBCOMMAND] [...] 185 | 186 | OPTIONS: 187 | -c Enable/disable color output, defaults to auto 188 | -d Directory to look into, defaults to env SVDIR or /var/service if unset 189 | -h Print this message and exit 190 | -l Show log processes, this is a shortcut for 'status -l' 191 | -t Tree view, this is a shortcut for 'status -t' 192 | -u User mode, this is a shortcut for '-d ~/runit/service' 193 | -v Increase verbosity 194 | -V Print the version number and exit 195 | 196 | ENV: 197 | SVDIR The directory to use, passed to the 'sv' command, can 198 | be overridden with '-d ' 199 | 200 | SUBCOMMANDS: 201 | status [-lt] [filter] Default subcommand, show process status 202 | '-t' enables tree mode (process tree) 203 | '-l' enables log mode (show log processes) 204 | 'filter' is an optional string to match service names against 205 | 206 | enable [...] Enable the service(s) (remove the "down" file, does not start service) 207 | 208 | disable [...] Disable the service(s) (create the "down" file, does not stop service) 209 | 210 | Any other subcommand gets passed directly to the 'sv' command, see sv(1) for the 211 | full list of subcommands and information about what each does specifically. 212 | Common subcommands: 213 | 214 | start Start the service 215 | stop Stop the service 216 | restart Restart the service 217 | reload Reload the service (send SIGHUP) 218 | 219 | EXAMPLES: 220 | vsv Show service status in /var/service 221 | vsv status Same as above 222 | vsv -t Show service status + pstree output 223 | vsv status -t Same as above 224 | vsv status tty Show service status for any service that matches tty* 225 | vsv check uuidd Check the uuidd svc, wrapper for 'sv check uuidd' 226 | vsv restart sshd Restart sshd, wrapper for 'sv restart sshd' 227 | vsv -u Show service status in ~/runit/service 228 | vsv -u restart ssh-agent Restart ssh-agent in ~/runit/service/ssh-agent 229 | 230 | Syntax 231 | ------ 232 | 233 | This project uses: 234 | 235 | - Bash Style Guide: https://www.daveeddy.com/bash/ 236 | - `shellcheck`: https://github.com/koalaman/shellcheck 237 | 238 | ``` 239 | $ make check 240 | shellcheck vsv 241 | ``` 242 | 243 | License 244 | ------- 245 | 246 | MIT License 247 | -------------------------------------------------------------------------------- /man/vsv.8: -------------------------------------------------------------------------------- 1 | .TH VSV 8 "SEP 2018" "System Manager's Utilities" 2 | .SH NAME 3 | .PP 4 | \fB\fCvsv\fR \- manage and view runit services 5 | 6 | .SH SYNOPSIS 7 | .PP 8 | \fB\fCvsv [OPTIONS] [SUBCOMMAND] []\fR 9 | 10 | .PP 11 | \fB\fCvsv [\-u] [\-d ] [\-h] [\-t] [SUBCOMMAND] [...]\fR 12 | 13 | .SH DESCRIPTION 14 | .PP 15 | \fB\fCvsv\fR is a wrapper for the \fB\fCsv\fR command that can be used to query and manage 16 | services under runit. It was made specifically for Void Linux but should 17 | theoretically work on any system using runit to manage services. 18 | 19 | .SH OPTIONS 20 | .PP 21 | \fB\fC\-c \fR 22 | Enable/disable color output, defaults to auto 23 | 24 | .PP 25 | \fB\fC\-d\fR \fIdir\fP 26 | Directory to look into, defaults to env \fB\fCSVDIR\fR or \fB\fC/var/service\fR if unset 27 | 28 | .PP 29 | \fB\fC\-h\fR 30 | Print this message and exit 31 | 32 | .PP 33 | \fB\fC\-l\fR 34 | Show log processes, this is a shortcut for \fB\fCvsv status \-l\fR 35 | 36 | .PP 37 | \fB\fC\-t\fR 38 | Tree view, this is a shortcut for \fB\fCvsv status \-t\fR 39 | 40 | .PP 41 | \fB\fC\-u\fR 42 | User mode, this is a shortcut for \fB\fCvsv \-d ~/runit/service\fR 43 | 44 | .PP 45 | \fB\fC\-v\fR 46 | Increase verbosity 47 | 48 | .PP 49 | \fB\fC\-V\fR 50 | Print the version number and exit 51 | 52 | .SH ENVIRONMENT 53 | .PP 54 | \fB\fCSVDIR\fR 55 | The directory to use, passed to the \fB\fCsv\fR command, can be overridden with \fB\fC\-d 56 | \fR 57 | 58 | .SH SUBCOMMANDS 59 | .PP 60 | \fB\fCstatus\fR 61 | 62 | .PP 63 | \fB\fCvsv status [\-lt] [filter]\fR 64 | 65 | .PP 66 | Default subcommand, show process status 67 | 68 | .PP 69 | \fB\fC\-t\fR 70 | Enables tree mode (process tree) 71 | 72 | .PP 73 | \fB\fC\-l\fR 74 | Enables log mode (show log processes) 75 | 76 | .PP 77 | \fB\fCfilter\fR 78 | An optional string to match service names against 79 | 80 | .PP 81 | Any other subcommand gets passed directly to the \fB\fCsv\fR command, see \fB\fCsv(1)\fR for 82 | the full list of subcommands and information about what each does specifically. 83 | Common subcommands: 84 | 85 | .PP 86 | \fB\fCstart \fR 87 | 88 | .PP 89 | Start the service 90 | 91 | .PP 92 | \fB\fCstop \fR 93 | 94 | .PP 95 | Stop the service 96 | 97 | .PP 98 | \fB\fCrestart \fR 99 | 100 | .PP 101 | Restart the service 102 | 103 | .PP 104 | \fB\fCreload \fR 105 | 106 | .PP 107 | Reload the service (send \fB\fCSIGHUP\fR) 108 | 109 | .PP 110 | \fB\fCenable \fR 111 | 112 | .PP 113 | Enable the service (remove the "down" file, does not start service) 114 | 115 | .PP 116 | \fB\fCdisable \fR 117 | 118 | .PP 119 | Disable the service (create the "down" file, does not stop service) 120 | 121 | .SH EXAMPLES 122 | .PP 123 | \fB\fCvsv\fR 124 | 125 | .PP 126 | Show service status in \fB\fC/var/service\fR 127 | 128 | .PP 129 | \fB\fCvsv status\fR 130 | 131 | .PP 132 | Same as above 133 | 134 | .PP 135 | \fB\fCvsv \-t\fR 136 | 137 | .PP 138 | Show service status + \fB\fCpstree\fR output 139 | 140 | .PP 141 | \fB\fCvsv status \-t\fR 142 | 143 | .PP 144 | Same as above 145 | 146 | .PP 147 | \fB\fCvsv status tty\fR 148 | 149 | .PP 150 | Show service status for any service that matches \fB\fCtty\fR 151 | 152 | .PP 153 | \fB\fCvsv check uuidd\fR 154 | 155 | .PP 156 | Check the uuidd svc, wrapper for \fB\fCsv check uuidd\fR 157 | 158 | .PP 159 | \fB\fCvsv restart sshd\fR 160 | 161 | .PP 162 | Restart sshd, wrapper for \fB\fCsv restart sshd\fR 163 | 164 | .PP 165 | \fB\fCvsv \-u\fR 166 | 167 | .PP 168 | Show service status in \fB\fC\~/runit/service\fR 169 | 170 | .PP 171 | \fB\fCvsv \-u restart ssh\-agent\fR 172 | 173 | .PP 174 | Restart ssh\-agent in \fB\fC\~/runit/service/ssh\-agent\fR 175 | 176 | .SH BUGS 177 | .PP 178 | 179 | \[la]https://github.com/bahamas10/vsv\[ra] 180 | 181 | .SH AUTHOR 182 | .PP 183 | \fB\fCDave Eddy (https://www.daveeddy.com)\fR 184 | 185 | .SH SEE ALSO 186 | .PP 187 | sv(8), runsvdir(8) 188 | 189 | .SH LICENSE 190 | .PP 191 | MIT License 192 | -------------------------------------------------------------------------------- /man/vsv.md: -------------------------------------------------------------------------------- 1 | VSV 8 "SEP 2018" "System Manager's Utilities" 2 | ============================================= 3 | 4 | NAME 5 | ---- 6 | 7 | `vsv` - manage and view runit services 8 | 9 | SYNOPSIS 10 | -------- 11 | 12 | `vsv [OPTIONS] [SUBCOMMAND] []` 13 | 14 | `vsv [-u] [-d ] [-h] [-t] [SUBCOMMAND] [...]` 15 | 16 | DESCRIPTION 17 | ----------- 18 | 19 | `vsv` is a wrapper for the `sv` command that can be used to query and manage 20 | services under runit. It was made specifically for Void Linux but should 21 | theoretically work on any system using runit to manage services. 22 | 23 | OPTIONS 24 | ------- 25 | 26 | `-c ` 27 | Enable/disable color output, defaults to auto 28 | 29 | `-d` *dir* 30 | Directory to look into, defaults to env `SVDIR` or `/var/service` if unset 31 | 32 | `-h` 33 | Print this message and exit 34 | 35 | `-l` 36 | Show log processes, this is a shortcut for `vsv status -l` 37 | 38 | `-t` 39 | Tree view, this is a shortcut for `vsv status -t` 40 | 41 | `-u` 42 | User mode, this is a shortcut for `vsv -d ~/runit/service` 43 | 44 | `-v` 45 | Increase verbosity 46 | 47 | `-V` 48 | Print the version number and exit 49 | 50 | ENVIRONMENT 51 | ----------- 52 | 53 | `SVDIR` 54 | The directory to use, passed to the `sv` command, can be overridden with `-d 55 | ` 56 | 57 | SUBCOMMANDS 58 | ----------- 59 | 60 | `status` 61 | 62 | `vsv status [-lt] [filter]` 63 | 64 | Default subcommand, show process status 65 | 66 | `-t` 67 | Enables tree mode (process tree) 68 | 69 | `-l` 70 | Enables log mode (show log processes) 71 | 72 | `filter` 73 | An optional string to match service names against 74 | 75 | Any other subcommand gets passed directly to the `sv` command, see `sv(1)` for 76 | the full list of subcommands and information about what each does specifically. 77 | Common subcommands: 78 | 79 | `start ` 80 | 81 | Start the service 82 | 83 | `stop ` 84 | 85 | Stop the service 86 | 87 | `restart ` 88 | 89 | Restart the service 90 | 91 | `reload ` 92 | 93 | Reload the service (send `SIGHUP`) 94 | 95 | `enable ` 96 | 97 | Enable the service (remove the "down" file, does not start service) 98 | 99 | `disable ` 100 | 101 | Disable the service (create the "down" file, does not stop service) 102 | 103 | EXAMPLES 104 | -------- 105 | 106 | `vsv` 107 | 108 | Show service status in `/var/service` 109 | 110 | `vsv status` 111 | 112 | Same as above 113 | 114 | `vsv -t` 115 | 116 | Show service status + `pstree` output 117 | 118 | `vsv status -t` 119 | 120 | Same as above 121 | 122 | `vsv status tty` 123 | 124 | Show service status for any service that matches `tty` 125 | 126 | `vsv check uuidd` 127 | 128 | Check the uuidd svc, wrapper for `sv check uuidd` 129 | 130 | `vsv restart sshd` 131 | 132 | Restart sshd, wrapper for `sv restart sshd` 133 | 134 | `vsv -u` 135 | 136 | Show service status in `~/runit/service` 137 | 138 | `vsv -u restart ssh-agent` 139 | 140 | Restart ssh-agent in `~/runit/service/ssh-agent` 141 | 142 | BUGS 143 | ---- 144 | 145 | https://github.com/bahamas10/vsv 146 | 147 | AUTHOR 148 | ------ 149 | 150 | `Dave Eddy (https://www.daveeddy.com)` 151 | 152 | SEE ALSO 153 | -------- 154 | 155 | sv(8), runsvdir(8) 156 | 157 | LICENSE 158 | ------- 159 | 160 | MIT License 161 | -------------------------------------------------------------------------------- /screenshots/vsv-add-service.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-add-service.jpg -------------------------------------------------------------------------------- /screenshots/vsv-arguments.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-arguments.jpg -------------------------------------------------------------------------------- /screenshots/vsv-down.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-down.jpg -------------------------------------------------------------------------------- /screenshots/vsv-log-tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-log-tree.jpg -------------------------------------------------------------------------------- /screenshots/vsv-log.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-log.jpg -------------------------------------------------------------------------------- /screenshots/vsv-restart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-restart.jpg -------------------------------------------------------------------------------- /screenshots/vsv-service-status-yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-service-status-yellow.jpg -------------------------------------------------------------------------------- /screenshots/vsv-status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-status.jpg -------------------------------------------------------------------------------- /screenshots/vsv-tree-large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-tree-large.jpg -------------------------------------------------------------------------------- /screenshots/vsv-user-d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-user-d.jpg -------------------------------------------------------------------------------- /screenshots/vsv-user-log.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-user-log.jpg -------------------------------------------------------------------------------- /screenshots/vsv-user-u.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahamas10/bash-vsv/f30628bf21111b3a73b5e57ef64fff747e78e0ff/screenshots/vsv-user-u.jpg -------------------------------------------------------------------------------- /vsv: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Void Linux service manager (runit) 4 | # 5 | # Author: Dave Eddy 6 | # Date: August 29, 2018 7 | # License: MIT 8 | 9 | VSV_VERSION='v1.3.5' 10 | 11 | export SVDIR=${SVDIR:-/var/service} 12 | 13 | charup='✔' 14 | chardown='X' 15 | charunknown='?' 16 | progname=${0##*/} 17 | num_re='^-?[0-9]+$' 18 | svc_re='^[a-zA-Z0-9_@\.-]+$' 19 | 20 | shopt -s nullglob 21 | 22 | # Get time in a human format, like 1 hour ago, 7 minutes ago, etc. 23 | human() { 24 | local seconds=$1 25 | if ((seconds < 0)); then 26 | ((seconds *= -1)) 27 | fi 28 | 29 | local times=( 30 | $((seconds / 60 / 60 / 24 / 365)) # years 31 | $((seconds / 60 / 60 / 24 / 30)) # months 32 | $((seconds / 60 / 60 / 24 / 7)) # weeks 33 | $((seconds / 60 / 60 / 24)) # days 34 | $((seconds / 60 / 60)) # hours 35 | $((seconds / 60)) # minutes 36 | $((seconds)) # seconds 37 | ) 38 | local names=(year month week day hour minute second) 39 | 40 | local i 41 | for ((i = 0; i < ${#names[@]}; i++)); do 42 | if ((${times[$i]} > 1)); then 43 | echo "${times[$i]} ${names[$i]}s" 44 | return 45 | elif ((${times[$i]} == 1)); then 46 | echo "${times[$i]} ${names[$i]}" 47 | return 48 | fi 49 | done 50 | echo '0 seconds' 51 | } 52 | 53 | # enable or disable colors based on the argument given, i.e.: 54 | # setcolors on # colors on 55 | # setcolors off # colors off 56 | # setcolors auto # colors on or off depending on environment 57 | setcolors() { 58 | local opt=$1 59 | local colors 60 | 61 | if [[ $opt == auto ]]; then 62 | # no colors if stdout is not a TTY 63 | if [[ ! -t 1 ]]; then 64 | opt='off' 65 | else 66 | # stdout is a tty, check tput capability for colors 67 | colors=$(tput colors 2>/dev/null || echo -1) 68 | if ! [[ $colors =~ $num_re ]]; then 69 | fatal "failed to parse output of \`tput colors\` ($colors)" 70 | fi 71 | 72 | if ((colors >= 8)); then 73 | opt='on' 74 | else 75 | opt='off' 76 | fi 77 | fi 78 | fi 79 | 80 | case "$opt" in 81 | on|yes|true) 82 | colorred=$(tput setaf 1) 83 | colorgreen=$(tput setaf 2) 84 | coloryellow=$(tput setaf 3) 85 | colorblue=$(tput setaf 4) 86 | colormagenta=$(tput setaf 5) 87 | colorcyan=$(tput setaf 6) 88 | #colorwhite=$(tput setaf 7) 89 | colorgray=$(tput setaf 8) 90 | colorbold=$(tput bold) 91 | colorreset=$(tput sgr0) 92 | ;; 93 | off|no|false) 94 | colorred= 95 | colorgreen= 96 | coloryellow= 97 | colormagenta= 98 | colorcyan= 99 | #colorwhite= 100 | colorgray= 101 | colorbold= 102 | colorreset= 103 | ;; 104 | *) 105 | echo "unknown color option: '$opt'" >&2 106 | exit 1 107 | ;; 108 | esac 109 | } 110 | 111 | usage() { 112 | local cr=$colorreset 113 | local logo 114 | 115 | logo=$(getlogo) 116 | 117 | cat < (bahamas10) 126 | 127 | ${coloryellow}USAGE:${colorgreen} 128 | $progname [OPTIONS] [SUBCOMMAND] [] 129 | $progname [-u] [-d ] [-h] [-t] [SUBCOMMAND] [...] 130 | 131 | ${coloryellow}OPTIONS:${colorgreen} 132 | ${colorgreen}-c $cr Enable/disable color output, defaults to auto 133 | ${colorgreen}-d $cr Directory to look into, defaults to env SVDIR or /var/service if unset 134 | ${colorgreen}-h $cr Print this message and exit 135 | ${colorgreen}-l $cr Show log processes, this is a shortcut for 'status -l' 136 | ${colorgreen}-t $cr Tree view, this is a shortcut for 'status -t' 137 | ${colorgreen}-u $cr User mode, this is a shortcut for '-d ~/runit/service' 138 | ${colorgreen}-v $cr Increase verbosity 139 | ${colorgreen}-V $cr Print the version number and exit 140 | 141 | ${coloryellow}ENV:${colorgreen} 142 | SVDIR $cr The directory to use, passed to the 'sv' command, can 143 | be overridden with '-d ' 144 | 145 | ${coloryellow}SUBCOMMANDS:${colorgreen} 146 | status [-lt] [filter] $cr Default subcommand, show process status 147 | $cr '-t' enables tree mode (process tree) 148 | $cr '-l' enables log mode (show log processes) 149 | $cr 'filter' is an optional string to match service names against 150 | ${colorgreen} 151 | enable [...] $cr Enable the service(s) (remove the "down" file, does not start service) 152 | ${colorgreen} 153 | disable [...] $cr Disable the service(s) (create the "down" file, does not stop service) 154 | 155 | Any other subcommand gets passed directly to the 'sv' command, see sv(1) for the 156 | full list of subcommands and information about what each does specifically. 157 | Common subcommands: 158 | 159 | ${colorgreen}start $cr Start the service 160 | ${colorgreen}stop $cr Stop the service 161 | ${colorgreen}restart $cr Restart the service 162 | ${colorgreen}reload $cr Reload the service (send SIGHUP) 163 | 164 | ${coloryellow}EXAMPLES:${colorgreen} 165 | ${colorgreen}$progname $cr Show service status in /var/service 166 | ${colorgreen}$progname status $cr Same as above 167 | ${colorgreen}$progname -t $cr Show service status + pstree output 168 | ${colorgreen}$progname status -t $cr Same as above 169 | ${colorgreen}$progname status tty $cr Show service status for any service that matches tty* 170 | ${colorgreen}$progname check uuidd $cr Check the uuidd svc, wrapper for 'sv check uuidd' 171 | ${colorgreen}$progname restart sshd $cr Restart sshd, wrapper for 'sv restart sshd' 172 | ${colorgreen}$progname -u $cr Show service status in ~/runit/service 173 | ${colorgreen}$progname -u restart ssh-agent $cr Restart ssh-agent in ~/runit/service/ssh-agent 174 | EOF 175 | } 176 | 177 | verbose() { 178 | if ((verbosity > 0)); then 179 | echo '>' "$colorgray" "$@" "$colorreset" >&2 180 | fi 181 | } 182 | 183 | # print the logo with brackets colorized 184 | getlogo() { 185 | printf '%s[%s%s%s]%s' \ 186 | "$colorcyan" \ 187 | "$colormagenta" "$progname" \ 188 | "$colorcyan" \ 189 | "$colorreset" 190 | } 191 | 192 | # prints a message 193 | msg() { 194 | local logo 195 | 196 | logo=$(getlogo) 197 | 198 | echo "$logo" "$colorblue$*$colorreset" 199 | } 200 | 201 | # prints a fatal message and exists 202 | fatal() { 203 | echo "${colorred}FATAL:" "$@" "$colorreset" 204 | exit 2 205 | } 206 | 207 | # rmsg - same as msg but colorized based on return status passed via $1 208 | rmsg() { 209 | local code=$1 210 | local logo 211 | local statuscolor 212 | 213 | shift 214 | 215 | logo=$(getlogo) 216 | 217 | if ((code == 0)); then 218 | statuscolor=$colorgreen 219 | else 220 | statuscolor=$colorred 221 | fi 222 | 223 | echo "$logo" "$statuscolor$*$colorreset" 224 | } 225 | 226 | disable_message() { 227 | local svc=$1 228 | 229 | echo "service $svc disabled by user $USER on $(date)" 230 | } 231 | 232 | # process the status of a single service 233 | process_service() { 234 | local svc=$1 235 | local now=$2 236 | local pid when up msg char err enabled msgcolor enabledcolor \ 237 | statecolor code islog prog down 238 | 239 | islog=false 240 | if [[ $svc == */log ]]; then 241 | islog=true 242 | fi 243 | 244 | # check permissions effectively 245 | err=$(sv status "$svc" 2>&1) 246 | code=$? 247 | 248 | # get service state, or set error messages 249 | if ((code == 0)); then 250 | err= 251 | state=$(< "$svc/supervise/stat") 252 | pid=$(< "$svc/supervise/pid") 253 | when=$(stat --printf %Y "$svc/supervise/pid") 254 | up=$((now - when)) 255 | msg=$(human "$up") 256 | 257 | # if the service is enabled (wants up or wants down) 258 | if down=$(cat "$svc/down" 2>&1); then 259 | verbose "service disabled: $down" 260 | enabled='false' 261 | else 262 | enabled='true' 263 | fi 264 | 265 | # color time if the service hasn't been up long 266 | if ((up < 5)); then 267 | msgcolor=$colorred 268 | elif ((up < 30)); then 269 | msgcolor=$coloryellow 270 | else 271 | msgcolor=$colorgray 272 | fi 273 | else 274 | pid= 275 | enabled= 276 | state='n/a' 277 | msg=${err##*: } 278 | msgcolor=$colorred 279 | fi 280 | 281 | # sanity check pid 282 | if [[ -n $pid ]] && ! [[ $pid =~ $num_re ]]; then 283 | fatal "invalid pid: '$pid'" 284 | fi 285 | 286 | # figure out character and color to use for status 287 | if [[ -n $err ]]; then 288 | char=$charunknown 289 | statecolor=$coloryellow 290 | elif [[ $state == 'run' ]]; then 291 | char=$charup 292 | statecolor=$colorgreen 293 | else 294 | char=$chardown 295 | statecolor=$colorred 296 | fi 297 | 298 | # figure out enabled color 299 | if [[ $enabled == 'true' ]]; then 300 | enabledcolor=$colorgreen 301 | elif [[ $enabled == 'false' ]]; then 302 | enabledcolor=$colorred 303 | else 304 | enabledcolor=$coloryellow 305 | fi 306 | 307 | # msg color 308 | if [[ -z $msgcolor ]]; then 309 | msgcolor=$colorgray 310 | fi 311 | 312 | # format service name if it is a log service 313 | if $log && $islog && ! $tree; then 314 | svc='- log' 315 | fi 316 | 317 | # figure out program name 318 | if [[ -n $pid ]]; then 319 | IFS= read -d $'\0' -r prog _ < /proc/$pid/cmdline 320 | prog=${prog##*/} 321 | prog=${prog:0:17} 322 | fi 323 | 324 | # print service line 325 | printf ' %s%s%s %s%-20s%s %s%-7s%s %s%-9s%s %s%-8s%s %s%-17s%s %s%s%s\n' \ 326 | "$statecolor" "$char" "$colorreset" \ 327 | "$colorreset" "$svc" "$colorreset" \ 328 | "$statecolor" "$state" "$colorreset" \ 329 | "$enabledcolor" "${enabled:----}" "$colorreset" \ 330 | "$colormagenta" "${pid:----}" "$colorreset" \ 331 | "$colorgreen" "${prog:----}" "$colorreset" \ 332 | "$msgcolor" "$msg" "$colorreset" 333 | 334 | # optionally print the pstree 335 | if $tree; then 336 | if [[ -n $pid ]] && ((pid > 0)); then 337 | echo "$colorgray" 338 | pstree -ac "$pid" 339 | fi 340 | echo "$colorreset" 341 | fi 342 | } 343 | 344 | # handle the status subcommand 345 | do_status() { 346 | local OPTIND option 347 | local d 348 | local logo 349 | local now 350 | local svcs=() 351 | 352 | logo=$(getlogo) 353 | while getopts 'hlt' option; do 354 | case "$option" in 355 | h) usage; exit 0;; 356 | l) log=true;; 357 | t) tree=true;; 358 | *) usage; exit 1;; 359 | esac 360 | done 361 | shift "$((OPTIND - 1))" 362 | 363 | local filter=$1 364 | 365 | # loop service directories 366 | for d in ./*/; do 367 | d=${d%/} 368 | svc=${d##*/} 369 | 370 | # this is us being a little over-protective here 371 | if ! [[ $svc =~ $svc_re ]]; then 372 | rmsg -1 "unexpected characters in name: '$svc'" >&2 373 | continue 374 | fi 375 | 376 | if [[ ! -d $svc/supervise ]]; then 377 | verbose "skipping $svc - '$svc/supervise' not found" 378 | continue 379 | fi 380 | 381 | if [[ -n $filter && $svc != *"$filter"* ]]; then 382 | verbose "filtering out '$svc' because match '$filter'" 383 | continue 384 | fi 385 | 386 | svcs+=("$svc") 387 | $log && svcs+=("$svc/log") 388 | done 389 | 390 | 391 | # print title if verbose 392 | if ((verbosity > 0)); then 393 | # service count 394 | local services 395 | local count=${#svcs[@]} 396 | 397 | if ((count == 1)); then 398 | services='service' 399 | else 400 | services='services' 401 | fi 402 | 403 | printf '%s> %s %s-%s %s%s %s(%s%s%s)%s %s-%s %s%d %s%s\n' \ 404 | "$colorgray" "$logo" \ 405 | "$colorgray" "$colorreset" \ 406 | "$colorblue" "$HOSTNAME" \ 407 | "$colorcyan" "$colorgreen" "${PWD/#$HOME/\~}" \ 408 | "$colorcyan" "$colorreset" \ 409 | "$colorgray" "$colorreset" \ 410 | "$colorblue" "$count" "$services" "$colorreset" 411 | fi 412 | echo 413 | 414 | # table header 415 | printf '%s %-20s %-7s %-9s %-8s %-17s %s%s\n' \ 416 | "$colorbold" \ 417 | 'SERVICE' 'STATE' 'ENABLED' 'PID' 'COMMAND' 'TIME' \ 418 | "$colorreset" 419 | 420 | # loop services 421 | printf -v now '%(%s)T' -1 422 | for svc in "${svcs[@]}"; do 423 | process_service "$svc" "$now" 424 | done 425 | echo 426 | } 427 | 428 | # handle the enable and disable subcommands 429 | do_enable_disable() { 430 | local cmd=$1 431 | local svc 432 | local ret=0 433 | local file 434 | shift 435 | 436 | if (($# < 1)); then 437 | rmsg -1 "Argument expected for '$cmd'" 438 | return 1 439 | fi 440 | 441 | # Loop all arguments as services 442 | msg "Running $progname $cmd $*" 443 | 444 | for svc in "$@"; do 445 | # Validate service name 446 | if ! [[ $svc =~ $svc_re ]]; then 447 | rmsg -1 "unexpected characters in name: '$svc'" >&2 448 | continue 449 | fi 450 | 451 | # ensure service exists 452 | if ! [[ -d $svc ]]; then 453 | rmsg -1 "service directory '$svc' does not exist" >&2 454 | continue 455 | fi 456 | 457 | file=$svc/down 458 | 459 | case "$cmd" in 460 | enable) 461 | verbose "enable '$svc': rm -f '$file'" 462 | if ! rm -f "$file"; then 463 | rmsg 1 "failed to enable '$svc'" 464 | ret=1 465 | fi 466 | ;; 467 | disable) 468 | verbose "disabling '$svc': creating '$file'" 469 | if ! disable_message "$svc" > "$file"; then 470 | rmsg 1 "failed to disable '$svc'" 471 | ret=1 472 | fi 473 | ;; 474 | *) 475 | rmsg 2 "unknown command: $cmd" >&2 476 | return 2 477 | ;; 478 | esac 479 | done 480 | 481 | rmsg "$ret" "[$progname $cmd $*], exit code: $ret" 482 | return "$ret" 483 | } 484 | 485 | # handle any other subcommand 486 | do_sv_cmd() { 487 | if (($# < 2)); then 488 | rmsg -1 "Argument expected for 'sv $1'" 489 | return 1 490 | fi 491 | 492 | msg "Running sv command (SVDIR=$SVDIR sv $*):" 493 | sv "$@" 494 | local ret=$? 495 | rmsg "$ret" "[sv $*], exit code: $ret" 496 | return "$ret" 497 | } 498 | 499 | colors_set=false 500 | tree=false 501 | log=false 502 | do_usage=-1 503 | verbosity=0 504 | while getopts 'c:d:hltuvV' option; do 505 | case "$option" in 506 | c) setcolors "$OPTARG"; colors_set=true;; 507 | d) SVDIR=$OPTARG;; 508 | h) do_usage=0;; 509 | l) log=true; cmd='status';; 510 | t) tree=true; cmd='status';; 511 | u) SVDIR=~/runit/service;; 512 | v) ((verbosity++));; 513 | V) echo "$VSV_VERSION"; exit 0;; 514 | *) do_usage=1;; 515 | esac 516 | done 517 | shift "$((OPTIND - 1))" 518 | 519 | $colors_set || setcolors auto 520 | 521 | # we wait until the colors are optionally set to output the usage message 522 | if ((do_usage > -1)); then 523 | usage 524 | exit "$do_usage" 525 | fi 526 | 527 | # move to the service directory 528 | cd "$SVDIR" || fatal "failed to enter dir: $SVDIR" 529 | 530 | # figure out 'cmd' command 531 | if [[ -z $cmd ]]; then 532 | cmd=${1:-status} 533 | shift 534 | fi 535 | 536 | case "$cmd" in 537 | status) 538 | do_status "$@" 539 | ;; 540 | enable|disable) 541 | do_enable_disable "$cmd" "$@" 542 | ;; 543 | *) 544 | if $tree; then 545 | rmsg -1 "-t can only be specified with 'status'" 546 | exit 1 547 | fi 548 | if $log; then 549 | rmsg -1 "-l can only be specified with 'status'" 550 | exit 1 551 | fi 552 | do_sv_cmd "$cmd" "$@" 553 | ;; 554 | esac 555 | --------------------------------------------------------------------------------