Skip to content
This repository was archived by the owner on May 20, 2024. It is now read-only.

Commit 87124ac

Browse files
CodingMarkusCodingMarkus
CodingMarkus
authored and
CodingMarkus
committed
Add proc module and tests
1 parent da4cb3e commit 87124ac

File tree

3 files changed

+526
-0
lines changed

3 files changed

+526
-0
lines changed

lib/psst/basic.inc.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ INCLUDE_SEEN_PSST="${INCLUDE_SEEN_PSST-}:basic:"
4343
# shellcheck source=basic/print.inc.sh
4444
. "$INCLUDE_PSST/basic/print.inc.sh"
4545

46+
# shellcheck source=basic/proc.inc.sh
47+
. "$INCLUDE_PSST/basic/proc.inc.sh"
48+
4649
# shellcheck source=basic/stack.inc.sh
4750
. "$INCLUDE_PSST/basic/stack.inc.sh"
4851

lib/psst/basic/proc.inc.sh

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#!/usr/bin/env sh
2+
3+
# Double include protection
4+
case "${INCLUDE_SEEN_PSST-}" in
5+
*_proc.inc.sh_*)
6+
return
7+
;;
8+
esac
9+
INCLUDE_SEEN_PSST="${INCLUDE_SEEN_PSST-} _proc.inc.sh_"
10+
11+
# shellcheck source=assert.inc.sh
12+
. "$INCLUDE_PSST/basic/assert.inc.sh"
13+
14+
# shellcheck source=chkcmd.inc.sh
15+
. "$INCLUDE_PSST/basic/chkcmd.inc.sh"
16+
17+
# shellcheck source=chkcmd.inc.sh
18+
. "$INCLUDE_PSST/basic/esc.inc.sh"
19+
20+
# shellcheck source=onexit.inc.sh
21+
. "$INCLUDE_PSST/basic/onexit.inc.sh"
22+
23+
24+
##
25+
# FUNCTION
26+
# proc_start_psst <resultVarName> <mode> <cmd> [<arg>] [<arg>] [<arg>] ...
27+
#
28+
# SUMMARY
29+
# Start a background process and return a process handle that can be
30+
# used to communicate with or terminate it again. The process handle
31+
# format must be considered private.
32+
#
33+
# The `mode` argument defines what shall happen to stdin, stdout, and
34+
# stderr. `mode` must be a 3-character string. The first character maps to
35+
# stdin, the second one to stdout, and the third one to stderr. If the
36+
# charater is a dot (`.`), the background process inherits the stream of
37+
# the current process. If the character is a lowercase X (`x`), the stream
38+
# of the background process maps to `/dev/null`. If the character is a
39+
# lowercase O (`o`), the stream is captured. E.g. the mode "ox." means:
40+
# capture stdin, redirect stdout to /dev/null, and inherit stderr.
41+
#
42+
# PARAMETERS
43+
# resultVarName: Name of the var the process handle is written to.
44+
# mode: Which streams to inherit, capture, or terminate.
45+
# cmd: The command to execute for the process.
46+
# [arg]*: Any number of arguments to pass along to the command.
47+
#
48+
# RETURNS
49+
# 0: Process was sucessfully launched.
50+
# 1: `cmd` cannot not be called.
51+
#
52+
# SAMPLE
53+
# proc_start_psst shHandle ox. sh
54+
#
55+
# NOTE
56+
# In case the process handle is not stopped prior to the script
57+
# terminating, it is automatically stopped on script termination.
58+
#
59+
proc_start_psst()
60+
{
61+
# We cannot use a subshell for this function as we need to auto-close
62+
# process handles on exit and therefor we require an at-exit handler in
63+
# this shell.
64+
65+
assert_minargc_psst "proc_start_psst" 3 $#
66+
assert_hasarg_psst "proc_start_psst" "resultVarName" "$1"
67+
assert_hasarg_psst "proc_start_psst" "mode" "$2"
68+
assert_hasarg_psst "proc_start_psst" "cmd" "$3"
69+
70+
# resultVarName=$1
71+
# mode=$4
72+
# cmd=$3
73+
74+
# shellcheck disable=SC2016
75+
[ ${#2} -eq 3 ] || assert_fail_psst '`mode` must be 3 characters long'
76+
case $2 in
77+
*[!.ox]*)
78+
# shellcheck disable=SC2016
79+
assert_fail_psst '`mode` may only contain ".", "o", and "x"'
80+
esac
81+
82+
chkcmd_psst "$3" || return 1
83+
84+
_tmpdir_proc_psst=$( mktemp -d )
85+
chmod 0700 "$_tmpdir_proc_psst"
86+
87+
_resultVarName_proc_psst="$1"
88+
_mode_proc_psst="$2"
89+
_evalCMD_proc_psst="'$3'"
90+
printf "%s" "$3" >"$_tmpdir_proc_psst/cmd"
91+
shift 3
92+
93+
for _arg_psst in "$@"
94+
do
95+
_evalCMD_proc_psst="$_evalCMD_proc_psst '$( esc_for_sq_psst "$_arg_psst" )'"
96+
done
97+
unset _arg_psst
98+
99+
printf "%s" "$_evalCMD_proc_psst" >"$_tmpdir_proc_psst/eval"
100+
101+
_stdin_proc_psst=
102+
case $_mode_proc_psst in
103+
x??) _stdin_proc_psst="</dev/null" ;;
104+
o??) mkfifo -m 0600 "$_tmpdir_proc_psst/stdin"
105+
_stdin_proc_psst="<$_tmpdir_proc_psst/stdin"
106+
esac
107+
108+
_stdout_proc_psst=
109+
case $_mode_proc_psst in
110+
?x?) _stdout_proc_psst=">/dev/null" ;;
111+
?o?) mkfifo -m 0600 "$_tmpdir_proc_psst/stdout"
112+
_stdout_proc_psst=">$_tmpdir_proc_psst/stdout"
113+
esac
114+
115+
_stderr_proc_psst=
116+
case $_mode_proc_psst in
117+
??x) _stderr_proc_psst="2>/dev/null" ;;
118+
??o) mkfifo -m 0600 "$_tmpdir_proc_psst/stderr"
119+
_stderr_proc_psst="2>$_tmpdir_proc_psst/stderr"
120+
esac
121+
122+
_evalCMD_proc_psst="$_evalCMD_proc_psst $_stdin_proc_psst"
123+
_evalCMD_proc_psst="$_evalCMD_proc_psst $_stdout_proc_psst"
124+
_evalCMD_proc_psst="$_evalCMD_proc_psst $_stderr_proc_psst"
125+
unset _stdin_proc_psst
126+
unset _stdout_proc_psst
127+
unset _stderr_proc_psst
128+
unset _mode_proc_psst
129+
130+
_result_proc_psst=0
131+
if eval "$_evalCMD_proc_psst &"
132+
then
133+
printf "%s" $! >"$_tmpdir_proc_psst/pid"
134+
135+
_onExit_psst="[ -d \"$_tmpdir_proc_psst\" ]"
136+
_onExit_psst="$_onExit_psst && proc_stop_psst '$_tmpdir_proc_psst'"
137+
# onexit_psst "$_onExit_psst"
138+
eval "$_resultVarName_proc_psst=$_tmpdir_proc_psst"
139+
else
140+
_result_proc_psst=1
141+
rm -rf "$_tmpdir_proc_psst"
142+
fi
143+
144+
unset _tmpdir_proc_psst
145+
unset _resultVarName_proc_psst
146+
unset _evalCMD_proc_psst
147+
148+
if [ $_result_proc_psst -eq 1 ]
149+
then
150+
unset _result_proc_psst
151+
return 1
152+
fi
153+
154+
unset _result_proc_psst
155+
return 0
156+
}
157+
158+
159+
160+
##
161+
# SUBPROCESS
162+
# proc_get_pid_psst <procHandle>
163+
#
164+
# SUMMARY
165+
# Returns the PID of a running or deceased background process.
166+
#
167+
# PARAMETERS
168+
# procHandle: The handle of the background process.
169+
#
170+
# OUTPUT
171+
# stdout: PID of the process.
172+
#
173+
# SAMPLE
174+
# pid=$( proc_get_pid_psst "$handle" )
175+
#
176+
proc_get_pid_psst()
177+
(
178+
func="proc_get_pid_psst"
179+
assert_argc_psst "$func" 1 $#
180+
assert_hasarg_psst "$func" "procHandle" "$1"
181+
182+
procHandle=$1
183+
184+
pidFile="$procHandle/pid"
185+
[ -f "$pidFile" ] || assert_fail_psst "Invalid process handle: $procHandle"
186+
187+
cat "$pidFile"
188+
)
189+
190+
191+
192+
##
193+
# SUBPROCESS
194+
# proc_is_alive_psst <procHandle>
195+
#
196+
# SUMMARY
197+
# Returns the PID of a running or deceased background process.
198+
#
199+
# PARAMETERS
200+
# procHandle: The handle of the background process.
201+
#
202+
# RETURNS
203+
# 0: Process is alive.
204+
# 1: Process is not alive anymore.
205+
#
206+
# SAMPLE
207+
# pid=$( proc_get_pid_psst "$hadnle" )
208+
#
209+
proc_is_alive_psst()
210+
(
211+
func="proc_get_pid_psst"
212+
assert_argc_psst "$func" 1 $#
213+
assert_hasarg_psst "$func" "procHandle" "$1"
214+
215+
procHandle=$1
216+
217+
pidFile="$procHandle/pid"
218+
[ -f "$pidFile" ] || assert_fail_psst "Invalid process handle: $procHandle"
219+
220+
pid=$( cat "$pidFile" )
221+
kill -0 "$pid" 2>/dev/null || return 1
222+
return 0
223+
)
224+
225+
226+
227+
##
228+
# FUNCTION
229+
# proc_stop_psst <procHandle>
230+
#
231+
# SUMMARY
232+
# Terminates a given background process gracefully by sending it the TERM
233+
# signal. After calling `proc_stop_psst` on a `procHandle`, the handle
234+
# becomes invalid.
235+
#
236+
# PARAMETERS
237+
# procHandle: The handle of the background process.
238+
#
239+
# RETURNS
240+
# 0: Process was sucessfully stopped.
241+
# 1: Process has already stopped on its own.
242+
#
243+
# SAMPLE
244+
# proc_stop_psst "$procHandle"
245+
#
246+
proc_stop_psst()
247+
{
248+
# We cannot use a subshell for this function as we need to wait within
249+
# the main process to avoid an error output on main shell termination as
250+
# the main shell will wait for the process if we haven't done so already
251+
# within that very same shell.
252+
253+
# procHandle=$1
254+
255+
func="proc_get_pid_psst"
256+
assert_argc_psst "$func" 1 $#
257+
assert_hasarg_psst "$func" "procHandle" "$1"
258+
259+
_pidFile_proc_psst="$1/pid"
260+
[ -f "$_pidFile_proc_psst" ] \
261+
|| assert_fail_psst "Invalid process handle: $1"
262+
263+
_pid_proc_psst=$( cat "$_pidFile_proc_psst" )
264+
unset _pidFile_proc_psst
265+
rm -rf "$1"
266+
267+
result=0
268+
kill -15 "$_pid_proc_psst" 2>/dev/null || result=1
269+
[ $result = 0 ] && wait "$_pid_proc_psst" 2>/dev/null
270+
271+
unset _pid_proc_psst
272+
273+
return $result
274+
}

0 commit comments

Comments
 (0)