1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# Copyright (c) 2023 Peter Holm <pho@FreeBSD.org> 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28# 29 30# killpg(2) version of reaper.sh. No problems seen. 31 32. ../default.cfg 33 34prog=$(basename "$0" .sh) 35cat > /tmp/$prog.c <<EOF 36#include <sys/param.h> 37#include <sys/mman.h> 38#include <sys/wait.h> 39 40 41#include <err.h> 42#include <errno.h> 43#include <pwd.h> 44#include <signal.h> 45#include <stdatomic.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <time.h> 49#include <unistd.h> 50 51static _Atomic(int) *share; 52 53#define GID 0 54#define PARALLEL 10 55#define RDY 1 56#define MAXP 7000 57 58static void 59hand(int i __unused) { 60 _exit(0); 61} 62 63static void 64innerloop(int parallel) 65{ 66 pid_t pids[MAXP]; 67 struct sigaction sa; 68 int i; 69 70 usleep(1000); 71 for (i = 0; i < parallel; i++) { 72 if ((pids[i] = fork()) == 0) { 73 sa.sa_handler = hand; 74 sigemptyset(&sa.sa_mask); 75 sa.sa_flags = 0; 76 if (sigaction(SIGUSR1, &sa, NULL) == -1) 77 err(1, "sigaction"); 78 atomic_fetch_add(&share[RDY], 1); 79 setproctitle("child"); 80 for (;;) 81 pause(); 82 _exit(0); /* never reached */ 83 } 84 if (pids[i] == -1) 85 err(1, "fork()"); 86 } 87 for (i = 0; i < parallel; i++) { 88 if (waitpid(pids[i], NULL, 0) != pids[i]) 89 err(1, "waitpid(%d) in looper", pids[i]); 90 } 91 _exit(0); 92} 93 94static void 95looper(void) 96{ 97 struct sigaction sa; 98 struct passwd *pw; 99 pid_t pids[MAXP]; 100 int i, parallel; 101 102 setproctitle("looper"); 103 sa.sa_handler = SIG_IGN; 104 sigemptyset(&sa.sa_mask); 105 sa.sa_flags = 0; 106 if (sigaction(SIGUSR1, &sa, NULL) == -1) 107 err(1, "sigaction"); 108 109 if ((pw = getpwnam("TUSER")) == NULL) 110 err(1, "no such user: TUSER"); 111 112 if (setgroups(1, &pw->pw_gid) || 113 setegid(pw->pw_gid) || setgid(pw->pw_gid) || 114 seteuid(pw->pw_uid) || setuid(pw->pw_uid)) 115 err(1, "Can't drop privileges to \"TUSER\""); 116 endpwent(); 117 setpgrp(0, 0); 118 share[GID] = getpgrp(); 119 parallel = arc4random() % MAXP + 1; 120 parallel = parallel / PARALLEL * PARALLEL; 121 for (i = 0; i < PARALLEL; i++) { 122 if ((pids[i] = fork()) == 0) 123 innerloop(parallel / PARALLEL); 124 } 125 while (atomic_load(&share[RDY]) != parallel) 126 usleep(10000); 127 if (killpg(share[GID], SIGUSR1) == -1) 128 err(1, "pgkill(%d)", share[GID]); 129 for (i = 0; i < 4; i++) { 130 if (waitpid(pids[i], NULL, 0) != pids[i]) 131 err(1, "waitpid(%d) in looper", pids[i]); 132 } 133 _exit(0); 134} 135 136int 137main(void) 138{ 139 size_t len; 140 time_t start; 141 int lpid, s1; 142 143 len = PAGE_SIZE; 144 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 145 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 146 err(1, "mmap"); 147 148 start = time(NULL); 149 while (time(NULL) - start < 120) { 150 share[GID] = 0; 151 share[RDY] = 0; 152 if ((lpid = fork()) == 0) 153 looper(); 154 if (waitpid(lpid, &s1, 0) != lpid) 155 err(1, "waitpid looper"); 156 } 157 158 return (0); 159} 160EOF 161sed -i '' "s#TUSER#$testuser#" /tmp/$prog.c 162mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1 163rm /tmp/$prog.c 164 165export MAXSWAPPCT=70 166n=1 167start=`date +%s` 168while true; do 169 ../testcases/swap/swap -t 2m -i 20 > /dev/null & 170 /tmp/$prog & pid=$! 171 st=`date +%s` 172 while kill -0 $pid > /dev/null 2>&1; do 173 e=$((`date +%s` - st)) 174 if [ $e -ge 120 ]; then 175 while pgrep -q swap; do pkill swap; done 176 fi 177 if [ $e -ge 600 ]; then 178 echo "Failed in loop #$n after $e seconds." 179 ps -jU$testuser | head -20 180 kill $pid 181 pkill -U$testuser 182 wait 183 rm -f /tmp/$prog 184 exit 1 185 fi 186 done 187 wait 188 [ $((`date +%s` - start)) -ge 300 ] && break 189 n=$((n + 1)) 190done 191rm /tmp/$prog 192exit 0 193