1#!/bin/sh 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2021 Axcient 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27 28atf_test_case both_pidfile cleanup 29both_pidfile_head() { 30 atf_set "descr" "daemon should write pid files for itself and its child" 31} 32both_pidfile_body() { 33 daemon -P daemon.pid -p sleep.pid sleep 300 34 atf_check -s exit:0 test -f daemon.pid 35 atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 36 atf_check -s exit:0 test -f sleep.pid 37 atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 38} 39both_pidfile_cleanup() { 40 if [ -f daemon.pid ]; then 41 daemon_pid=`cat daemon.pid` 42 fi 43 if [ -f sleep_pid ]; then 44 sleep_pid=`cat sleep.pid` 45 fi 46 [ -n "$sleep_pid" ] && kill $sleep_pid 47 # NB: killing the sleep should kill the daemon too, so we musn't fail 48 # the test if the second kill fails with ESRCH 49 [ -n "$daemon_pid" ] && kill $daemon_pid || true 50} 51 52atf_test_case chdir cleanup 53chdir_head() { 54 atf_set "descr" "daemon should chdir to /" 55} 56chdir_body() { 57 # Executing sleep by relative path will only work from / 58 daemon -p ${PWD}/sleep.pid -c bin/sleep 300 59 atf_check -s exit:0 test -f sleep.pid 60 atf_check -s exit:0 -o match:"[0-9] bin/sleep 300$" \ 61 ps -p `cat sleep.pid` 62} 63chdir_cleanup() { 64 [ -f sleep.pid ] && kill `cat sleep.pid` 65} 66 67atf_test_case child_pidfile cleanup 68child_pidfile_head() { 69 atf_set "descr" "daemon should write its child's pid to a pidfile" 70} 71child_pidfile_body() { 72 daemon -p sleep.pid sleep 300 73 atf_check -s exit:0 test -f sleep.pid 74 atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 75} 76child_pidfile_cleanup() { 77 [ -f sleep.pid ] && kill `cat sleep.pid` 78} 79 80atf_test_case child_pidfile_lock cleanup 81child_pidfile_lock_head() { 82 atf_set "descr" "daemon should refuse to clobber an existing child" 83} 84child_pidfile_lock_body() { 85 daemon -p sleep.pid sleep 300 86 atf_check -s exit:0 test -f sleep.pid 87 atf_check -s not-exit:0 -e match:"process already running" \ 88 daemon -p sleep.pid sleep 300 89} 90child_pidfile_lock_cleanup() { 91 [ -f sleep.pid ] && kill `cat sleep.pid` 92} 93 94atf_test_case newsyslog cleanup 95newsyslog_head() { 96 atf_set "descr" "daemon should close and reopen the output file on SIGHUP" 97} 98newsyslog_body() { 99 cat > child.sh <<HERE 100#! /bin/sh 101while true ; do 102 echo "my output" 103 sleep 0.1 104done 105HERE 106 chmod +x child.sh 107 daemon -P daemon.pid -H -o output_file ./child.sh 108 atf_check -s exit:0 test -f daemon.pid 109 sleep 0.2 110 mv output_file output_file.0 111 kill -HUP `cat daemon.pid` 112 sleep 0.2 113 atf_check -s exit:0 test -s output_file.0 114 atf_check -s exit:0 test -s output_file 115} 116newsyslog_cleanup() { 117 [ -f daemon.pid ] && kill `cat daemon.pid` 118} 119 120atf_test_case output_file 121output_file_head() { 122 atf_set "descr" "daemon should redirect stdout to a file" 123} 124output_file_body() { 125 daemon -o output_file seq 1 5 126 seq 1 5 > expected_file 127 atf_check -s exit:0 cmp output_file expected_file 128} 129 130atf_test_case restart_child cleanup 131restart_child_head() { 132 atf_set "descr" "daemon should restart a dead child" 133} 134restart_child_body() { 135 daemon -rP daemon.pid -p sleep.pid sleep 300 136 atf_check -s exit:0 test -f daemon.pid 137 atf_check -s exit:0 test -f sleep.pid 138 orig_sleep_pid=`cat sleep.pid` 139 kill $orig_sleep_pid 140 # Wait up to 10s for the daemon to restart the child. 141 for t in `seq 0 0.1 10`; do 142 if [ -s "sleep.pid" ]; then 143 new_sleep_pid=`cat sleep.pid` 144 [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] && break 145 fi 146 147 sleep 0.1 148 done 149 [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] || \ 150 atf_fail "child was not restarted" 151 152} 153restart_child_cleanup() { 154 [ -f daemon.pid ] && kill `cat daemon.pid` 155} 156 157atf_test_case restart_hang cleanup 158restart_hang_head() { 159 atf_set "descr" "daemon should terminate with SIGTERM even pending child restart" 160} 161restart_hang_body() { 162 daemon -rP daemon.pid -R 10 -p sleep.pid sleep 300 163 atf_check -s exit:0 test -f daemon.pid 164 atf_check -s exit:0 test -f sleep.pid 165 read sleep_pid < sleep.pid 166 1>&2 echo "$sleep_pid" 167 kill "$sleep_pid" 168 169 # Wait up to 5s for the child to exit 170 for t in `seq 0 0.1 5`; do 171 [ ! -s "sleep.pid" ] && break 172 sleep 0.1 173 done 174 175 atf_check test ! -s "sleep.pid" 176 177 read daemon_pid < daemon.pid 178 kill -TERM "$daemon_pid" 179 180 # Wait up to 10s for the daemon to terminate 181 for t in `seq 0 0.1 10`; do 182 [ ! -f "daemon.pid" ] && break 183 sleep 0.1 184 done 185 186 atf_check test ! -f "daemon.pid" 187 atf_check test ! -f "sleep.pid" 188} 189restart_hang_cleanup() { 190 [ -s daemon.pid ] && kill -9 `cat daemon.pid` 191 true 192} 193 194atf_test_case supervisor_pidfile cleanup 195supervisor_pidfile_head() { 196 atf_set "descr" "daemon should write its own pid to a pidfile" 197} 198supervisor_pidfile_body() { 199 daemon -P daemon.pid sleep 300 200 atf_check -s exit:0 test -f daemon.pid 201 atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 202} 203supervisor_pidfile_cleanup() { 204 [ -f daemon.pid ] && kill `cat daemon.pid` 205} 206 207atf_test_case supervisor_pidfile_lock cleanup 208supervisor_pidfile_lock_head() { 209 atf_set "descr" "daemon should refuse to clobber an existing instance" 210} 211supervisor_pidfile_lock_body() { 212 daemon -P daemon.pid sleep 300 213 atf_check -s exit:0 test -f daemon.pid 214 atf_check -s not-exit:0 -e match:"process already running" \ 215 daemon -p daemon.pid sleep 300 216} 217supervisor_pidfile_lock_cleanup() { 218 [ -f daemon.pid ] && kill `cat daemon.pid` 219} 220 221atf_test_case title cleanup 222title_head() { 223 atf_set "descr" "daemon should change its process title" 224} 225title_body() { 226 daemon -P daemon.pid -t "I'm a title!" sleep 300 227 atf_check -s exit:0 test -f daemon.pid 228 atf_check -s exit:0 -o match:"daemon: I'm a title!" \ 229 ps -p `cat daemon.pid` 230} 231title_cleanup() { 232 [ -f daemon.pid ] && kill `cat daemon.pid` 233} 234 235atf_test_case user cleanup 236user_head() { 237 atf_set "descr" "daemon should drop privileges" 238 atf_set "require.user" "root" 239} 240user_body() { 241 daemon -p sleep.pid -u nobody sleep 300 242 atf_check -s exit:0 test -f sleep.pid 243 atf_check -s exit:0 -o match:"^nobody" ps -up `cat sleep.pid` 244} 245user_cleanup() { 246 [ -f sleep.pid ] && kill `cat sleep.pid` 247} 248 249 250atf_init_test_cases() { 251 atf_add_test_case both_pidfile 252 atf_add_test_case chdir 253 atf_add_test_case child_pidfile 254 atf_add_test_case child_pidfile_lock 255 atf_add_test_case newsyslog 256 atf_add_test_case output_file 257 atf_add_test_case restart_child 258 atf_add_test_case restart_hang 259 atf_add_test_case supervisor_pidfile 260 atf_add_test_case supervisor_pidfile_lock 261 atf_add_test_case title 262 atf_add_test_case user 263} 264