13b57d80cSAlan Somers#!/bin/sh 23b57d80cSAlan Somers# 34d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause 43b57d80cSAlan Somers# 53b57d80cSAlan Somers# Copyright (c) 2021 Axcient 63b57d80cSAlan Somers# 73b57d80cSAlan Somers# Redistribution and use in source and binary forms, with or without 83b57d80cSAlan Somers# modification, are permitted provided that the following conditions 93b57d80cSAlan Somers# are met: 103b57d80cSAlan Somers# 1. Redistributions of source code must retain the above copyright 113b57d80cSAlan Somers# notice, this list of conditions and the following disclaimer. 123b57d80cSAlan Somers# 2. Redistributions in binary form must reproduce the above copyright 133b57d80cSAlan Somers# notice, this list of conditions and the following disclaimer in the 143b57d80cSAlan Somers# documentation and/or other materials provided with the distribution. 153b57d80cSAlan Somers# 163b57d80cSAlan Somers# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 173b57d80cSAlan Somers# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183b57d80cSAlan Somers# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193b57d80cSAlan Somers# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 203b57d80cSAlan Somers# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213b57d80cSAlan Somers# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223b57d80cSAlan Somers# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233b57d80cSAlan Somers# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243b57d80cSAlan Somers# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253b57d80cSAlan Somers# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263b57d80cSAlan Somers# SUCH DAMAGE. 273b57d80cSAlan Somers 283b57d80cSAlan Somersatf_test_case both_pidfile cleanup 293b57d80cSAlan Somersboth_pidfile_head() { 303b57d80cSAlan Somers atf_set "descr" "daemon should write pid files for itself and its child" 313b57d80cSAlan Somers} 323b57d80cSAlan Somersboth_pidfile_body() { 333b57d80cSAlan Somers daemon -P daemon.pid -p sleep.pid sleep 300 343b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 353b57d80cSAlan Somers atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 363b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 373b57d80cSAlan Somers atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 383b57d80cSAlan Somers} 393b57d80cSAlan Somersboth_pidfile_cleanup() { 403b57d80cSAlan Somers if [ -f daemon.pid ]; then 413b57d80cSAlan Somers daemon_pid=`cat daemon.pid` 423b57d80cSAlan Somers fi 433b57d80cSAlan Somers if [ -f sleep_pid ]; then 443b57d80cSAlan Somers sleep_pid=`cat sleep.pid` 453b57d80cSAlan Somers fi 463b57d80cSAlan Somers [ -n "$sleep_pid" ] && kill $sleep_pid 473b57d80cSAlan Somers # NB: killing the sleep should kill the daemon too, so we musn't fail 483b57d80cSAlan Somers # the test if the second kill fails with ESRCH 493b57d80cSAlan Somers [ -n "$daemon_pid" ] && kill $daemon_pid || true 503b57d80cSAlan Somers} 513b57d80cSAlan Somers 523b57d80cSAlan Somersatf_test_case chdir cleanup 533b57d80cSAlan Somerschdir_head() { 543b57d80cSAlan Somers atf_set "descr" "daemon should chdir to /" 553b57d80cSAlan Somers} 563b57d80cSAlan Somerschdir_body() { 573b57d80cSAlan Somers # Executing sleep by relative path will only work from / 583b57d80cSAlan Somers daemon -p ${PWD}/sleep.pid -c bin/sleep 300 593b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 603b57d80cSAlan Somers atf_check -s exit:0 -o match:"[0-9] bin/sleep 300$" \ 613b57d80cSAlan Somers ps -p `cat sleep.pid` 623b57d80cSAlan Somers} 633b57d80cSAlan Somerschdir_cleanup() { 643b57d80cSAlan Somers [ -f sleep.pid ] && kill `cat sleep.pid` 653b57d80cSAlan Somers} 663b57d80cSAlan Somers 673b57d80cSAlan Somersatf_test_case child_pidfile cleanup 683b57d80cSAlan Somerschild_pidfile_head() { 693b57d80cSAlan Somers atf_set "descr" "daemon should write its child's pid to a pidfile" 703b57d80cSAlan Somers} 713b57d80cSAlan Somerschild_pidfile_body() { 723b57d80cSAlan Somers daemon -p sleep.pid sleep 300 733b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 743b57d80cSAlan Somers atf_check -s exit:0 -o match:"[0-9] sleep 300$" ps -p `cat sleep.pid` 753b57d80cSAlan Somers} 763b57d80cSAlan Somerschild_pidfile_cleanup() { 773b57d80cSAlan Somers [ -f sleep.pid ] && kill `cat sleep.pid` 783b57d80cSAlan Somers} 793b57d80cSAlan Somers 803b57d80cSAlan Somersatf_test_case child_pidfile_lock cleanup 813b57d80cSAlan Somerschild_pidfile_lock_head() { 823b57d80cSAlan Somers atf_set "descr" "daemon should refuse to clobber an existing child" 833b57d80cSAlan Somers} 843b57d80cSAlan Somerschild_pidfile_lock_body() { 853b57d80cSAlan Somers daemon -p sleep.pid sleep 300 863b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 873b57d80cSAlan Somers atf_check -s not-exit:0 -e match:"process already running" \ 883b57d80cSAlan Somers daemon -p sleep.pid sleep 300 893b57d80cSAlan Somers} 903b57d80cSAlan Somerschild_pidfile_lock_cleanup() { 913b57d80cSAlan Somers [ -f sleep.pid ] && kill `cat sleep.pid` 923b57d80cSAlan Somers} 933b57d80cSAlan Somers 943b57d80cSAlan Somersatf_test_case newsyslog cleanup 953b57d80cSAlan Somersnewsyslog_head() { 963b57d80cSAlan Somers atf_set "descr" "daemon should close and reopen the output file on SIGHUP" 973b57d80cSAlan Somers} 983b57d80cSAlan Somersnewsyslog_body() { 993b57d80cSAlan Somers cat > child.sh <<HERE 1003b57d80cSAlan Somers#! /bin/sh 1013b57d80cSAlan Somerswhile true ; do 1023b57d80cSAlan Somers echo "my output" 1033b57d80cSAlan Somers sleep 0.1 1043b57d80cSAlan Somersdone 1053b57d80cSAlan SomersHERE 1063b57d80cSAlan Somers chmod +x child.sh 1073b57d80cSAlan Somers daemon -P daemon.pid -H -o output_file ./child.sh 1083b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 1093b57d80cSAlan Somers sleep 0.2 1103b57d80cSAlan Somers mv output_file output_file.0 1113b57d80cSAlan Somers kill -HUP `cat daemon.pid` 1123b57d80cSAlan Somers sleep 0.2 1133b57d80cSAlan Somers atf_check -s exit:0 test -s output_file.0 1143b57d80cSAlan Somers atf_check -s exit:0 test -s output_file 1153b57d80cSAlan Somers} 1163b57d80cSAlan Somersnewsyslog_cleanup() { 1173b57d80cSAlan Somers [ -f daemon.pid ] && kill `cat daemon.pid` 1183b57d80cSAlan Somers} 1193b57d80cSAlan Somers 1203b57d80cSAlan Somersatf_test_case output_file 1213b57d80cSAlan Somersoutput_file_head() { 1223b57d80cSAlan Somers atf_set "descr" "daemon should redirect stdout to a file" 1233b57d80cSAlan Somers} 1243b57d80cSAlan Somersoutput_file_body() { 1253b57d80cSAlan Somers daemon -o output_file seq 1 5 1263b57d80cSAlan Somers seq 1 5 > expected_file 1273b57d80cSAlan Somers atf_check -s exit:0 cmp output_file expected_file 1283b57d80cSAlan Somers} 1293b57d80cSAlan Somers 1303b57d80cSAlan Somersatf_test_case restart_child cleanup 1313b57d80cSAlan Somersrestart_child_head() { 1323b57d80cSAlan Somers atf_set "descr" "daemon should restart a dead child" 1333b57d80cSAlan Somers} 1343b57d80cSAlan Somersrestart_child_body() { 1353b57d80cSAlan Somers daemon -rP daemon.pid -p sleep.pid sleep 300 1363b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 1373b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 1383b57d80cSAlan Somers orig_sleep_pid=`cat sleep.pid` 1393b57d80cSAlan Somers kill $orig_sleep_pid 1403b57d80cSAlan Somers # Wait up to 10s for the daemon to restart the child. 1413b57d80cSAlan Somers for t in `seq 0 0.1 10`; do 142aa8722ccSKyle Evans if [ -s "sleep.pid" ]; then 1433b57d80cSAlan Somers new_sleep_pid=`cat sleep.pid` 1443b57d80cSAlan Somers [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] && break 145aa8722ccSKyle Evans fi 146aa8722ccSKyle Evans 1473b57d80cSAlan Somers sleep 0.1 1483b57d80cSAlan Somers done 1493b57d80cSAlan Somers [ "$orig_sleep_pid" -ne "$new_sleep_pid" ] || \ 1503b57d80cSAlan Somers atf_fail "child was not restarted" 1513b57d80cSAlan Somers 1523b57d80cSAlan Somers} 1533b57d80cSAlan Somersrestart_child_cleanup() { 1543b57d80cSAlan Somers [ -f daemon.pid ] && kill `cat daemon.pid` 1553b57d80cSAlan Somers} 1563b57d80cSAlan Somers 157*9ab59e90SKyle Evansatf_test_case restart_hang cleanup 158*9ab59e90SKyle Evansrestart_hang_head() { 159*9ab59e90SKyle Evans atf_set "descr" "daemon should terminate with SIGTERM even pending child restart" 160*9ab59e90SKyle Evans} 161*9ab59e90SKyle Evansrestart_hang_body() { 162*9ab59e90SKyle Evans daemon -rP daemon.pid -R 10 -p sleep.pid sleep 300 163*9ab59e90SKyle Evans atf_check -s exit:0 test -f daemon.pid 164*9ab59e90SKyle Evans atf_check -s exit:0 test -f sleep.pid 165*9ab59e90SKyle Evans read sleep_pid < sleep.pid 166*9ab59e90SKyle Evans 1>&2 echo "$sleep_pid" 167*9ab59e90SKyle Evans kill "$sleep_pid" 168*9ab59e90SKyle Evans 169*9ab59e90SKyle Evans # Wait up to 5s for the child to exit 170*9ab59e90SKyle Evans for t in `seq 0 0.1 5`; do 171*9ab59e90SKyle Evans [ ! -s "sleep.pid" ] && break 172*9ab59e90SKyle Evans sleep 0.1 173*9ab59e90SKyle Evans done 174*9ab59e90SKyle Evans 175*9ab59e90SKyle Evans atf_check test ! -s "sleep.pid" 176*9ab59e90SKyle Evans 177*9ab59e90SKyle Evans read daemon_pid < daemon.pid 178*9ab59e90SKyle Evans kill -TERM "$daemon_pid" 179*9ab59e90SKyle Evans 180*9ab59e90SKyle Evans # Wait up to 10s for the daemon to terminate 181*9ab59e90SKyle Evans for t in `seq 0 0.1 10`; do 182*9ab59e90SKyle Evans [ ! -f "daemon.pid" ] && break 183*9ab59e90SKyle Evans sleep 0.1 184*9ab59e90SKyle Evans done 185*9ab59e90SKyle Evans 186*9ab59e90SKyle Evans atf_check test ! -f "daemon.pid" 187*9ab59e90SKyle Evans atf_check test ! -f "sleep.pid" 188*9ab59e90SKyle Evans} 189*9ab59e90SKyle Evansrestart_hang_cleanup() { 190*9ab59e90SKyle Evans [ -s daemon.pid ] && kill -9 `cat daemon.pid` 191*9ab59e90SKyle Evans true 192*9ab59e90SKyle Evans} 193*9ab59e90SKyle Evans 1943b57d80cSAlan Somersatf_test_case supervisor_pidfile cleanup 1953b57d80cSAlan Somerssupervisor_pidfile_head() { 1963b57d80cSAlan Somers atf_set "descr" "daemon should write its own pid to a pidfile" 1973b57d80cSAlan Somers} 1983b57d80cSAlan Somerssupervisor_pidfile_body() { 1993b57d80cSAlan Somers daemon -P daemon.pid sleep 300 2003b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 2013b57d80cSAlan Somers atf_check -s exit:0 -o match:"daemon: sleep" ps -p `cat daemon.pid` 2023b57d80cSAlan Somers} 2033b57d80cSAlan Somerssupervisor_pidfile_cleanup() { 2043b57d80cSAlan Somers [ -f daemon.pid ] && kill `cat daemon.pid` 2053b57d80cSAlan Somers} 2063b57d80cSAlan Somers 2073b57d80cSAlan Somersatf_test_case supervisor_pidfile_lock cleanup 2083b57d80cSAlan Somerssupervisor_pidfile_lock_head() { 2093b57d80cSAlan Somers atf_set "descr" "daemon should refuse to clobber an existing instance" 2103b57d80cSAlan Somers} 2113b57d80cSAlan Somerssupervisor_pidfile_lock_body() { 2123b57d80cSAlan Somers daemon -P daemon.pid sleep 300 2133b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 2143b57d80cSAlan Somers atf_check -s not-exit:0 -e match:"process already running" \ 2153b57d80cSAlan Somers daemon -p daemon.pid sleep 300 2163b57d80cSAlan Somers} 2173b57d80cSAlan Somerssupervisor_pidfile_lock_cleanup() { 2183b57d80cSAlan Somers [ -f daemon.pid ] && kill `cat daemon.pid` 2193b57d80cSAlan Somers} 2203b57d80cSAlan Somers 2213b57d80cSAlan Somersatf_test_case title cleanup 2223b57d80cSAlan Somerstitle_head() { 2233b57d80cSAlan Somers atf_set "descr" "daemon should change its process title" 2243b57d80cSAlan Somers} 2253b57d80cSAlan Somerstitle_body() { 2263b57d80cSAlan Somers daemon -P daemon.pid -t "I'm a title!" sleep 300 2273b57d80cSAlan Somers atf_check -s exit:0 test -f daemon.pid 2283b57d80cSAlan Somers atf_check -s exit:0 -o match:"daemon: I'm a title!" \ 2293b57d80cSAlan Somers ps -p `cat daemon.pid` 2303b57d80cSAlan Somers} 2313b57d80cSAlan Somerstitle_cleanup() { 2323b57d80cSAlan Somers [ -f daemon.pid ] && kill `cat daemon.pid` 2333b57d80cSAlan Somers} 2343b57d80cSAlan Somers 2353b57d80cSAlan Somersatf_test_case user cleanup 2363b57d80cSAlan Somersuser_head() { 2373b57d80cSAlan Somers atf_set "descr" "daemon should drop privileges" 2383b57d80cSAlan Somers atf_set "require.user" "root" 2393b57d80cSAlan Somers} 2403b57d80cSAlan Somersuser_body() { 2413b57d80cSAlan Somers daemon -p sleep.pid -u nobody sleep 300 2423b57d80cSAlan Somers atf_check -s exit:0 test -f sleep.pid 2433b57d80cSAlan Somers atf_check -s exit:0 -o match:"^nobody" ps -up `cat sleep.pid` 2443b57d80cSAlan Somers} 2453b57d80cSAlan Somersuser_cleanup() { 2463b57d80cSAlan Somers [ -f sleep.pid ] && kill `cat sleep.pid` 2473b57d80cSAlan Somers} 2483b57d80cSAlan Somers 2493b57d80cSAlan Somers 2503b57d80cSAlan Somersatf_init_test_cases() { 2513b57d80cSAlan Somers atf_add_test_case both_pidfile 2523b57d80cSAlan Somers atf_add_test_case chdir 2533b57d80cSAlan Somers atf_add_test_case child_pidfile 2543b57d80cSAlan Somers atf_add_test_case child_pidfile_lock 2553b57d80cSAlan Somers atf_add_test_case newsyslog 2563b57d80cSAlan Somers atf_add_test_case output_file 2573b57d80cSAlan Somers atf_add_test_case restart_child 258*9ab59e90SKyle Evans atf_add_test_case restart_hang 2593b57d80cSAlan Somers atf_add_test_case supervisor_pidfile 2603b57d80cSAlan Somers atf_add_test_case supervisor_pidfile_lock 2613b57d80cSAlan Somers atf_add_test_case title 2623b57d80cSAlan Somers atf_add_test_case user 2633b57d80cSAlan Somers} 264