File: common

package info (click to toggle)
cereal 0.24-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 176 kB
  • sloc: sh: 425; makefile: 39
file content (253 lines) | stat: -rw-r--r-- 5,820 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# -*-shell-script-*-

# Shared bash functions for cereal
#
# The cereal scripts were written by
# Jameson Graef Rollins <jrollins@finestructure.net>
# and
# Daniel Kahn Gillmor <dkg@fifthhorseman.net>.
#
# They are Copyright 2007, and are all released under the GPL, version 3
# or later.

##################################################
# managed directories
ETC="/etc/cereal"
export ETC
SESSIONDIR="/var/lib/cereal/sessions"
export SESSIONDIR
ERR=0
export ERR
##################################################

error() {
    echo "$1" >&2
    ERR=${2:-'1'}
}

failure() {
    echo "$1" >&2
    exit ${2:-'2'}
}

# check if TTY is valid tty
# check_is_tty TTY
check_tty() {
    [ -c "$1" ] || failure "'$1' is not a valid tty."
}

# check is tty is already being used in another session
# check_is_session_tty TTY
check_session_tty() {
    local SESSION
    local TTY
    TTY="$1"

    for SESSION in $(ls "$SESSIONDIR") ; do
	if grep -q "^$TTY$" "$SESSIONDIR/$SESSION/env/TTY" ; then
	    failure "TTY '$TTY' is already being monitored by session '$SESSION'."
	fi
    done
}	

# check if USER is valid
# check_user USER
check_user() {
    getent passwd "$1" > /dev/null || failure "'$1' is not a valid user."
}

# check if GROUP is valid
# check_group GROUP
check_group() {
    getent group "$1" > /dev/null || failure "'$1' is not a valid group."
}

# check if the user can read/write to a TTY
is_tty_rw() {
    chpst -u "$1:$2" bash -c "test -r $3 && test -w $3"
}

# check_tty_rw USER GROUP TTY
check_tty_rw() {
    is_tty_rw "$@" || failure "User '$1' does not have read/write access to tty '$3', tty is not g+rw, or you do not have permission to change user."
}

# start_check
# this is called with "chpst -e" with a session environment
start_check() {
    is_tty_rw "$USER" "$GROUP" "$TTY"
}

# check if session exists
# is_session SESSION
is_session() {
    test -d "$SESSIONDIR/$1"
}

# is_running SESSION
is_running() {
    local SESSION
    SESSION="$1"

    STAT_FILE="$SESSIONDIR/$SESSION/supervise/stat"

    if [ -r "$SESSIONDIR/$SESSION/supervise" ] ; then
	if [ -e "$STAT_FILE" ] ; then
	    if [ $(cat "$STAT_FILE") = 'run' ] ; then
		# return 0 if the service is running
		return 0
	    else
		# return 1 if the service is *not* running
		return 1
	    fi
	else
	    # if the stat file doesn't exist, assume it's not running
	    return 1
	fi
    else
        # return 2 if we can't read the stat file and don't know the status
	return 2
    fi
}

# check if sessions tty is locked
# is_locked SESSION
is_locked() {
    local TTY
    TTY=$(cat "$SESSIONDIR/$1/env/TTY")
    test -e /var/lock/LCK..${TTY##/dev/}
}

# can_attach SESSION [USER]
can_attach() {
    local USER
    USER=${2:-"$USER"}
    [ "$USER" = $(cat "$SESSIONDIR/$1/env/USER") ]
}

# in_group USER GROUP
in_group() {
    groups "$1" | cut -d ':' -f 2 | tr ' ' '\n' | grep -q "^$2$"
}

# can_follow SESSION [USER]
can_follow() {
    local LOGUSER
    local LOGGROUP
    local USER
    LOGUSER=$(cat "$SESSIONDIR/$1/env/LOGUSER")
    LOGGROUP=$(cat "$SESSIONDIR/$1/env/LOGGROUP")
    USER=${2:-"$USER"}
    [ "$USER" = "$LOGUSER" ] || in_group "$USER" "$LOGGROUP" || [ $(id -u "$USER") = '0' ]
}

# write to the log of a session
#log_write SESSION STATEMENT
log_write() {
    printf "\ncereal: %s\n" "$2" >> "$SESSIONDIR/$1/socket"
}

# display_session SESSION [USER]
display_session() {
    local SESSION
    local SFLAG
    local AFLAG
    local FFLAG

    SESSION="$1"
    USER=${2:-"$USER"}

    # set state flag
    # last flag works only for users that can read supervise/stat
    is_running "$SESSION"
    case $? in
	0)
	    SFLAG='+' # running
	    ;;
	1)
	    SFLAG='-' # stopped
	    ;;
	2)
	    SFLAG='?' # unknown
	    ;;
    esac
    # set attach flag
    if can_attach "$SESSION" "$USER" ; then
	AFLAG='a'
    else
	AFLAG='-'
    fi    
    # set follow flag

    if can_follow "$SESSION" "$USER" ; then
	FFLAG='f'
    else
	FFLAG='-'
    fi

    cd "$SESSIONDIR/$SESSION/env"
    echo "${SFLAG}${AFLAG}${FFLAG} $SESSION $(cat TTY) $(cat BAUD) $(cat USER) $(cat LOGGROUP)"
}

# list [-n] SESSION [SESSION...]
list() {
    local SESSION
    local SESSIONS
    local DISP
    DISP=0

    # flag to just output session names (otherwise display full info)
    if [ "$1" = '--names' -o "$1" = '-n' ] ; then
	unset DISP
	shift 1
    fi

    # list of session to display
    if [ "$1" ] ; then
	SESSIONS="$@"
    else
	SESSIONS=$(ls -1 "$SESSIONDIR" 2> /dev/null)
	[ "$SESSIONS" ] || return 1
    fi

    for SESSION in $SESSIONS ; do
	if ! is_session "$SESSION" ; then
	    error "Session '$SESSION' not found." 1
	elif [ "$DISP" ] ; then
	    display_session "$SESSION"
	else
	    echo "$SESSION"
	fi
    done
}

# function called by the session service run script to actually start screen
# takes no arguments, since it is called with a "chpst -e"
mainrun() {
    check_tty "$TTY"
    check_user "$USER"
    check_group "$GROUP"
    check_group "$LOGGROUP"
    check_tty_rw "$USER" "$GROUP" "$TTY"
    chown "$USER:$LOGGROUP" ./socket || failure "Can not properly set ownership of socket."
    chmod 0640 ./socket || failure "Can not properly set permissions on socket."

    echo "starting screen session..."
    LOCKFILE=/var/lock/LCK..${TTY##/dev/}
    lockfile -r0 "$LOCKFILE"
    LOCK_EXIT_CODE=$?
    if [ "$LOCK_EXIT_CODE" != 0 ] ; then
        exit "$LOCK_EXIT_CODE"
    fi
    chmod u+w "$LOCKFILE"
    printf '%9s\n' $$ >> "$LOCKFILE"
    exec chpst -u "$USER:$GROUP" /usr/bin/screen -D -m -L -c "$SCREENRC" -s /bin/false -S "cereal:$SESSION" -t "$SESSION" "$TTY" "$BAUD"
}

# function called by the session service finish script to remove the
# serial device lockfile
# takes no arguments, since it is called with a "chpst -e"
remove_lock() {
    LOCKFILE=/var/lock/LCK..${TTY##/dev/}
    rm -r "$LOCKFILE"
}