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