1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5# 6# Copyright (c) 2021 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# O_CREAT|O_EXCL|O_EXLOCK atomic implementation test. 31# Lots of input from kib@ 32 33[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 34. ../default.cfg 35 36dir=/tmp 37odir=`pwd` 38cd $dir 39sed '1,/^EOF/d' < $odir/$0 > $dir/exlock2.c 40mycc -o exlock2 -Wall -Wextra -O0 -g exlock2.c || exit 1 41rm -f exlock2.c 42cd $odir 43 44$dir/exlock2 45s=$? 46[ -f exlock2.core -a $s -eq 0 ] && 47 { ls -l exlock2.core; mv exlock2.core $dir; s=1; } 48cd $odir 49 50rm -f $dir/exlock2 /tmp/exlock2.*.file 51exit $s 52 53EOF 54#include <sys/param.h> 55#include <sys/mman.h> 56#include <sys/stat.h> 57#include <sys/wait.h> 58 59#include <err.h> 60#include <errno.h> 61#include <fcntl.h> 62#include <signal.h> 63#include <stdatomic.h> 64#include <stdio.h> 65#include <string.h> 66#include <stdlib.h> 67#include <time.h> 68#include <unistd.h> 69 70static _Atomic(int) *share; 71static int quit; 72static char file[80]; 73 74#define RUNTIME (2 * 60) 75#define SYNC 0 76 77static void 78handler(int s __unused) 79{ 80 quit = 1; 81} 82 83static void 84test1(void) 85{ 86 time_t start; 87 int fd, n; 88 89 signal(SIGHUP, handler); 90 n = 0; 91 start = time(NULL); 92 while (time(NULL) - start < RUNTIME && quit == 0) { 93 n++; 94 if ((fd = open(file, O_RDWR|O_CREAT|O_EXCL|O_EXLOCK, 95 DEFFILEMODE)) == -1) 96 err(1, "open(%s) creat", file); 97 unlink(file); 98 if (write(fd, "test", 5) != 5) 99 err(1, "write()"); 100 while (share[SYNC] == 1) 101 ; /* wait for test2 to signal "done" */ 102 close(fd); 103 } 104#if defined(DEBUG) 105 fprintf(stderr, "%s: n = %d\n", __func__, n); 106#endif 107 108 _exit(0); 109} 110 111static void 112test2(void) 113{ 114 struct flock fl; 115 struct stat st; 116 time_t start; 117 int e, fd, n; 118 119 e = 0; 120 fd = 0; 121 n = 0; 122 start = time(NULL); 123 while (time(NULL) - start < RUNTIME) { 124 share[SYNC] = 1; 125 if ((fd = open(file, O_RDWR)) == -1) 126 goto out; 127 n++; 128 memset(&fl, 0, sizeof(fl)); 129 fl.l_start = 0; 130 fl.l_len = 0; 131 fl.l_type = F_WRLCK; 132 fl.l_whence = SEEK_SET; 133 if (fcntl(fd, F_SETLK, &fl) < 0) { 134 if (errno != EAGAIN) 135 err(1, "fcntl(F_SETFL)"); 136 goto out; 137 } 138 /* test1 must have dropped the lock */ 139 fprintf(stderr, "%s got the lock.\n", __func__); 140 if (fstat(fd, &st) == -1) 141 err(1, "stat(%s)", file); 142 /* As test1 has opened the file exclusivly, this 143 should not happen */ 144 if (st.st_size == 0) 145 fprintf(stderr, "%s has size 0\n", file); 146 e = 1; 147 break; 148out: 149 if (fd != -1) 150 close(fd); 151 share[SYNC] = 0; 152 usleep(100); 153 } 154#if defined(DEBUG) 155 if (e != 0) { 156 system("ps -Uroot | grep -v grep | grep /tmp/exlock2 | "\ 157 "awk '{print $1}' | xargs procstat -f"); 158 } 159#endif 160 share[SYNC] = 0; 161 162 _exit(e); 163} 164 165int 166main(void) 167{ 168 pid_t pid1, pid2; 169 size_t len; 170 int e, status; 171 172 e = 0; 173 len = PAGE_SIZE; 174 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 175 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 176 err(1, "mmap"); 177 178 snprintf(file, sizeof(file), "/tmp/exlock2.%d.file", getpid()); 179 if ((pid1 = fork()) == 0) 180 test1(); 181 if (pid1 == -1) 182 err(1, "fork()"); 183 184 if ((pid2 = fork()) == 0) 185 test2(); 186 if (pid2 == -1) 187 err(1, "fork()"); 188 189 if (waitpid(pid2, &status, 0) != pid2) 190 err(1, "waitpid(%d)", pid2); 191 if (status != 0) { 192 if (WIFSIGNALED(status)) 193 fprintf(stderr, 194 "pid %d exit signal %d\n", 195 pid2, WTERMSIG(status)); 196 } 197 e += status == 0 ? 0 : 1; 198 kill(pid1, SIGHUP); 199 if (waitpid(pid1, &status, 0) != pid1) 200 err(1, "waitpid(%d)", pid1); 201 if (status != 0) { 202 if (WIFSIGNALED(status)) 203 fprintf(stderr, 204 "pid %d exit signal %d\n", 205 pid1, WTERMSIG(status)); 206 } 207 e += status == 0 ? 0 : 1; 208 209 return (e); 210} 211