| 1 | #!/bin/bash |
|---|
| 2 | |
|---|
| 3 | # cereal-admin: manage cereal sessions (runit service directory structure |
|---|
| 4 | # and runit run directory). |
|---|
| 5 | # |
|---|
| 6 | # The cereal scripts were written by |
|---|
| 7 | # Jameson Rollins <jrollins@fifthhorseman.net> |
|---|
| 8 | # and |
|---|
| 9 | # Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>. |
|---|
| 10 | # |
|---|
| 11 | # They are Copyright 2007, and are all released under the GPL, version 3 |
|---|
| 12 | # or later. |
|---|
| 13 | |
|---|
| 14 | ################################################## |
|---|
| 15 | CMD=$(basename $0) |
|---|
| 16 | |
|---|
| 17 | SHAREDIR=${SHAREDIR:-"/usr/share/cereal"} |
|---|
| 18 | export SHAREDIR |
|---|
| 19 | source "$SHAREDIR/common" |
|---|
| 20 | [ -r "$ETC/cereal-admin.conf" ] && source "$ETC/cereal-admin.conf" |
|---|
| 21 | ################################################## |
|---|
| 22 | |
|---|
| 23 | usage() { |
|---|
| 24 | cat <<EOF |
|---|
| 25 | Usage: $CMD <subcommand> [options] [args] |
|---|
| 26 | Cereal session management program. |
|---|
| 27 | |
|---|
| 28 | subcommands: |
|---|
| 29 | create (c) SESSION TTY BAUD USER LOGGROUP create cereal session |
|---|
| 30 | start (s) [options] SESSION [SESSION]... start cereal session(s) |
|---|
| 31 | -a (--all) start all sessions |
|---|
| 32 | stop (k) [options] SESSION [SESSION]... stop cereal session(s) |
|---|
| 33 | -a (--all) stop all sessions |
|---|
| 34 | restart (r) [options] SESSION [SESSION]... restart cereal session(s) |
|---|
| 35 | -a (--all) restart all sessions |
|---|
| 36 | -r (--running) restart any currently running |
|---|
| 37 | sessions |
|---|
| 38 | destroy (d) [options] SESSION [SESSION]... destroy cereal session(s) |
|---|
| 39 | -a (--all) destroy all sessions |
|---|
| 40 | list (l) [SESSION]... list session(s) |
|---|
| 41 | help (h,?) this help |
|---|
| 42 | |
|---|
| 43 | EOF |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | # create session |
|---|
| 47 | create() { |
|---|
| 48 | (( $# < 5 )) && failure "Not enough input arguments. Type '$CMD help' for more info." |
|---|
| 49 | |
|---|
| 50 | SESSION="$1" |
|---|
| 51 | TTY="$2" |
|---|
| 52 | BAUD="$3" |
|---|
| 53 | SUSER="$4" |
|---|
| 54 | SGROUP=$(ls -l "$TTY" | awk '{ print $4 }') |
|---|
| 55 | LOGUSER='cereal' |
|---|
| 56 | LOGGROUP="$5" |
|---|
| 57 | |
|---|
| 58 | if [ -d "$SESSIONDIR/$SESSION" ] ; then |
|---|
| 59 | failure "A session named '$SESSION' already exists." |
|---|
| 60 | fi |
|---|
| 61 | |
|---|
| 62 | check_is_tty "$TTY" |
|---|
| 63 | check_is_session_tty "$TTY" |
|---|
| 64 | check_user "$SUSER" |
|---|
| 65 | check_group "$SGROUP" |
|---|
| 66 | check_user "$LOGUSER" |
|---|
| 67 | check_group "$LOGGROUP" |
|---|
| 68 | check_tty_rw "$SUSER" "$SGROUP" "$TTY" |
|---|
| 69 | |
|---|
| 70 | mkdir -p "$SESSIONDIR/$SESSION" |
|---|
| 71 | |
|---|
| 72 | # create run script |
|---|
| 73 | ln -s "$SHAREDIR/mainrun" "$SESSIONDIR/$SESSION/run" |
|---|
| 74 | |
|---|
| 75 | # store environment variables |
|---|
| 76 | mkdir -p "$SESSIONDIR/$SESSION/env" |
|---|
| 77 | echo "$SESSION" > "$SESSIONDIR/$SESSION/env/SESSION" |
|---|
| 78 | echo "$TTY" > "$SESSIONDIR/$SESSION/env/TTY" |
|---|
| 79 | echo "$BAUD" > "$SESSIONDIR/$SESSION/env/BAUD" |
|---|
| 80 | echo "$SUSER" > "$SESSIONDIR/$SESSION/env/USER" |
|---|
| 81 | echo "$SGROUP" > "$SESSIONDIR/$SESSION/env/GROUP" |
|---|
| 82 | echo "$LOGUSER" > "$SESSIONDIR/$SESSION/env/LOGUSER" |
|---|
| 83 | echo "$LOGGROUP" > "$SESSIONDIR/$SESSION/env/LOGGROUP" |
|---|
| 84 | |
|---|
| 85 | # create logging script |
|---|
| 86 | mkdir -p -m 0750 "$SESSIONDIR/$SESSION/log/main" |
|---|
| 87 | touch "$SESSIONDIR/$SESSION/log/main/current" |
|---|
| 88 | chmod 0640 "$SESSIONDIR/$SESSION/log/main/current" |
|---|
| 89 | chown -R "$LOGUSER" "$SESSIONDIR/$SESSION/log/main" |
|---|
| 90 | chgrp -R "$LOGGROUP" "$SESSIONDIR/$SESSION/log" |
|---|
| 91 | |
|---|
| 92 | # create socket for screen, since it can't log to stdout |
|---|
| 93 | mkfifo "$SESSIONDIR/$SESSION/socket" |
|---|
| 94 | chown "$SUSER:$LOGGROUP" "$SESSIONDIR/$SESSION/socket" |
|---|
| 95 | chmod 0640 "$SESSIONDIR/$SESSION/socket" |
|---|
| 96 | ln -s "$SHAREDIR/logrun" "$SESSIONDIR/$SESSION/log/run" |
|---|
| 97 | |
|---|
| 98 | # make supervise directory world accessible if requested |
|---|
| 99 | if [ "$SUPERVISE_WORLD_ACCESSIBLE" = 'yes' ] ; then |
|---|
| 100 | mkdir -p -m 0755 "$SESSIONDIR/$SESSION/supervise" |
|---|
| 101 | fi |
|---|
| 102 | |
|---|
| 103 | echo "Created session '$SESSION':" |
|---|
| 104 | display_session "$SESSION" |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | start_check() { |
|---|
| 108 | check_tty_rw "$USER" "$GROUP" "$TTY" |
|---|
| 109 | } |
|---|
| 110 | export -f start_check |
|---|
| 111 | |
|---|
| 112 | # start_session SESSION |
|---|
| 113 | start_session() { |
|---|
| 114 | local SESSION="$1" |
|---|
| 115 | ln -s "$SESSIONDIR/$SESSION" "$SERVICE.$SESSION" |
|---|
| 116 | log_write "$SESSION" "session '$SESSION' started." |
|---|
| 117 | } |
|---|
| 118 | export -f start_session |
|---|
| 119 | |
|---|
| 120 | # start session |
|---|
| 121 | start() { |
|---|
| 122 | local ERR=0 |
|---|
| 123 | |
|---|
| 124 | if [ -z "$1" ] ; then |
|---|
| 125 | failure "Not enough input arguments. Type '$CMD help' for more info." |
|---|
| 126 | elif [ "$1" = '--all' -o "$1" = '-a' ] ; then |
|---|
| 127 | SESSIONS=$(list | cut -d ' ' -f 2) |
|---|
| 128 | else |
|---|
| 129 | SESSIONS="$@" |
|---|
| 130 | fi |
|---|
| 131 | |
|---|
| 132 | for SESSION in $SESSIONS ; do |
|---|
| 133 | if ! is_session "$SESSION" ; then |
|---|
| 134 | echo "Session '$SESSION' not found." |
|---|
| 135 | ((ERR++)) |
|---|
| 136 | continue |
|---|
| 137 | elif is_linked "$SESSION" ; then |
|---|
| 138 | echo "Session '$SESSION' is already linked." |
|---|
| 139 | ((ERR++)) |
|---|
| 140 | continue |
|---|
| 141 | elif ! chpst -e "$SESSIONDIR/$SESSION/env/" sh -c start_check ; then |
|---|
| 142 | echo "Session '$SESSION' not properly configured." |
|---|
| 143 | ((ERR++)) |
|---|
| 144 | continue |
|---|
| 145 | else |
|---|
| 146 | start_session "$SESSION" || failure "Session '$SESSION' could not be started." |
|---|
| 147 | echo "Started session '$SESSION'." |
|---|
| 148 | fi |
|---|
| 149 | done |
|---|
| 150 | |
|---|
| 151 | return "$ERR" |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | # stop_session SESSION |
|---|
| 155 | stop_session() { |
|---|
| 156 | local SESSION="$1" |
|---|
| 157 | log_write "$SESSION" "stopping session '$SESSION'..." |
|---|
| 158 | sv exit "$SERVICE.$SESSION" |
|---|
| 159 | rm "$SERVICE.$SESSION" |
|---|
| 160 | } |
|---|
| 161 | export -f stop_session |
|---|
| 162 | |
|---|
| 163 | # stop session |
|---|
| 164 | stop() { |
|---|
| 165 | local ERR=0 |
|---|
| 166 | |
|---|
| 167 | if [ -z "$1" ] ; then |
|---|
| 168 | failure "Not enough input arguments. Type '$CMD help' for more info." |
|---|
| 169 | elif [ "$1" = '--all' -o "$1" = '-a' ] ; then |
|---|
| 170 | SESSIONS=$(list | cut -d ' ' -f 2) |
|---|
| 171 | else |
|---|
| 172 | SESSIONS="$@" |
|---|
| 173 | fi |
|---|
| 174 | |
|---|
| 175 | for SESSION in $SESSIONS ; do |
|---|
| 176 | if ! is_session "$SESSION" ; then |
|---|
| 177 | echo "Session '$SESSION' not found." |
|---|
| 178 | ((ERR++)) |
|---|
| 179 | continue |
|---|
| 180 | elif ! is_linked "$SESSION" ; then |
|---|
| 181 | echo "Session '$SESSION' not linked." |
|---|
| 182 | ((ERR++)) |
|---|
| 183 | continue |
|---|
| 184 | else |
|---|
| 185 | stop_session "$SESSION" || failure "Session '$SESSION' could not be stopped." |
|---|
| 186 | echo "Stopped session '$SESSION'." |
|---|
| 187 | fi |
|---|
| 188 | done |
|---|
| 189 | |
|---|
| 190 | return "$ERR" |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | # restart_session SESSION |
|---|
| 194 | restart_session() { |
|---|
| 195 | local SESSION="$1" |
|---|
| 196 | log_write "$SESSION" "restarting session '$SESSION'..." |
|---|
| 197 | sv restart "$SERVICE.$SESSION" |
|---|
| 198 | } |
|---|
| 199 | export -f restart_session |
|---|
| 200 | |
|---|
| 201 | # restart session |
|---|
| 202 | restart() { |
|---|
| 203 | local ERR=0 |
|---|
| 204 | |
|---|
| 205 | if [ -z "$1" ] ; then |
|---|
| 206 | failure "Not enough input arguments. Type '$CMD help' for more info." |
|---|
| 207 | elif [ "$1" = '--all' -o "$1" = '-a' ] ; then |
|---|
| 208 | SESSIONS=$(list | cut -d ' ' -f 2) |
|---|
| 209 | elif [ "$1" = '--running' -o "$1" = '-r' ] ; then |
|---|
| 210 | SESSIONS=$(list | grep '^+' | cut -d ' ' -f 2) |
|---|
| 211 | [ "$SESSIONS" ] || failure "There are no running sessions." 0 |
|---|
| 212 | else |
|---|
| 213 | SESSIONS="$@" |
|---|
| 214 | fi |
|---|
| 215 | |
|---|
| 216 | for SESSION in $SESSIONS ; do |
|---|
| 217 | if ! is_session "$SESSION" ; then |
|---|
| 218 | echo "Session '$SESSION' not found." |
|---|
| 219 | ((ERR++)) |
|---|
| 220 | continue |
|---|
| 221 | elif ! is_linked "$SESSION" ; then |
|---|
| 222 | start_session "$SESSION" || failure "Session '$SESSION' could not be started." |
|---|
| 223 | echo "Started session '$SESSION'." |
|---|
| 224 | else |
|---|
| 225 | restart_session "$SESSION" || failure "Session '$SESSION' could not be restarted." |
|---|
| 226 | echo "Restarted session '$SESSION'." |
|---|
| 227 | fi |
|---|
| 228 | done |
|---|
| 229 | |
|---|
| 230 | return "$ERR" |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | # destroy_session SESSION |
|---|
| 234 | destroy_session() { |
|---|
| 235 | rm -rf "$SESSIONDIR/$1" |
|---|
| 236 | } |
|---|
| 237 | export -f destroy_session |
|---|
| 238 | |
|---|
| 239 | # destroy session |
|---|
| 240 | destroy() { |
|---|
| 241 | local ERR=0 |
|---|
| 242 | |
|---|
| 243 | if [ -z "$1" ] ; then |
|---|
| 244 | failure "Not enough input arguments. Type '$CMD help' for more info." |
|---|
| 245 | elif [ "$1" = '--all' -o "$1" = '-a' ] ; then |
|---|
| 246 | SESSIONS=$(list | cut -d ' ' -f 2) |
|---|
| 247 | else |
|---|
| 248 | SESSIONS="$@" |
|---|
| 249 | fi |
|---|
| 250 | |
|---|
| 251 | for SESSION in $SESSIONS ; do |
|---|
| 252 | if ! is_session "$SESSION" ; then |
|---|
| 253 | echo "Session '$SESSION' not found." |
|---|
| 254 | ((ERR++)) |
|---|
| 255 | continue |
|---|
| 256 | elif is_linked "$SESSION" ; then |
|---|
| 257 | echo "Session '$SESSION' is currently linked." |
|---|
| 258 | read -p "Really stop and destroy session? [Y|n]: " OK |
|---|
| 259 | if [ -z "$OK" -o "${OK/y/Y}" = 'Y' ] ; then |
|---|
| 260 | stop_session "$SESSION" || failure "Session '$SESSION' could not be stopped." |
|---|
| 261 | destroy_session "$SESSION" || failure "Session '$SESSION' could not be destroyed." |
|---|
| 262 | echo "Stopped and destroyed session '$SESSION'." |
|---|
| 263 | else |
|---|
| 264 | echo "Session '$SESSION' not stopped." |
|---|
| 265 | ((ERR++)) |
|---|
| 266 | continue |
|---|
| 267 | fi |
|---|
| 268 | else |
|---|
| 269 | read -p "Really destroy session '$SESSION'? [Y|n]: " OK |
|---|
| 270 | if [ -z "$OK" -o "${OK/y/Y}" = 'Y' ] ; then |
|---|
| 271 | destroy_session "$SESSION" || failure "Session '$SESSION' could not be destroyed." |
|---|
| 272 | echo "Destroyed session '$SESSION'." |
|---|
| 273 | else |
|---|
| 274 | echo "Session '$SESSION' not destroyed." |
|---|
| 275 | ((ERR++)) |
|---|
| 276 | continue |
|---|
| 277 | fi |
|---|
| 278 | fi |
|---|
| 279 | done |
|---|
| 280 | |
|---|
| 281 | return "$ERR" |
|---|
| 282 | } |
|---|
| 283 | |
|---|
| 284 | ############################################################### |
|---|
| 285 | ### MAIN |
|---|
| 286 | |
|---|
| 287 | COMMAND="$1" |
|---|
| 288 | [ "$COMMAND" ] || failure "Type '$CMD help' for usage." |
|---|
| 289 | shift |
|---|
| 290 | |
|---|
| 291 | case $COMMAND in |
|---|
| 292 | 'create'|'c') |
|---|
| 293 | create "$@" |
|---|
| 294 | ;; |
|---|
| 295 | 'start'|'s') |
|---|
| 296 | start "$@" |
|---|
| 297 | ;; |
|---|
| 298 | 'restart'|'r') |
|---|
| 299 | restart "$@" |
|---|
| 300 | ;; |
|---|
| 301 | 'stop'|'k') |
|---|
| 302 | stop "$@" |
|---|
| 303 | ;; |
|---|
| 304 | 'destroy'|'d') |
|---|
| 305 | destroy "$@" |
|---|
| 306 | ;; |
|---|
| 307 | 'list'|'l') |
|---|
| 308 | list "$@" |
|---|
| 309 | ;; |
|---|
| 310 | 'help'|'h'|'?') |
|---|
| 311 | usage |
|---|
| 312 | ;; |
|---|
| 313 | *) |
|---|
| 314 | failure "Unknown command: '$COMMAND' |
|---|
| 315 | Type '$CMD help' for usage." |
|---|
| 316 | ;; |
|---|
| 317 | esac |
|---|