1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause 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 debug; /* Set to "1" for debug output */ 72static int quit; 73static char file[80]; 74 75#define RUNTIME (2 * 60) 76#define SYNC 0 77 78static void 79handler(int s __unused) 80{ 81 quit = 1; 82} 83 84static void 85test1(void) 86{ 87 time_t start; 88 int fd, n; 89 90 signal(SIGHUP, handler); 91 n = 0; 92 start = time(NULL); 93 while (time(NULL) - start < RUNTIME && quit == 0) { 94 n++; 95 if ((fd = open(file, O_RDWR|O_CREAT|O_EXCL|O_EXLOCK, 96 DEFFILEMODE)) == -1) 97 err(1, "open(%s) creat", file); 98 unlink(file); 99 if (write(fd, "test", 5) != 5) 100 err(1, "write()"); 101 while (share[SYNC] == 1) 102 ; /* wait for test2 to signal "done" */ 103 close(fd); 104 } 105 if (debug != 0) 106 fprintf(stderr, "%s: n = %d\n", __func__, n); 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; 118 119 e = 0; 120 fd = 0; 121 start = time(NULL); 122 while (time(NULL) - start < RUNTIME) { 123 share[SYNC] = 1; 124 if ((fd = open(file, O_RDWR)) == -1) 125 goto out; 126 memset(&fl, 0, sizeof(fl)); 127 fl.l_start = 0; 128 fl.l_len = 0; 129 fl.l_type = F_WRLCK; 130 fl.l_whence = SEEK_SET; 131 if (fcntl(fd, F_SETLK, &fl) < 0) { 132 if (errno != EAGAIN) 133 err(1, "fcntl(F_SETFL)"); 134 goto out; 135 } 136 /* test1 must have dropped the lock */ 137 fprintf(stderr, "%s got the lock.\n", __func__); 138 if (fstat(fd, &st) == -1) 139 err(1, "stat(%s)", file); 140 /* As test1 has opened the file exclusivly, this 141 should not happen */ 142 if (st.st_size == 0) 143 fprintf(stderr, "%s has size 0\n", file); 144 e = 1; 145 break; 146out: 147 if (fd != -1) 148 close(fd); 149 share[SYNC] = 0; 150 usleep(100); 151 } 152 if (debug != 0 && e != 0) 153 system("ps -Uroot | grep -v grep | grep /tmp/exlock2 | "\ 154 "awk '{print $1}' | xargs procstat -f"); 155 share[SYNC] = 0; 156 157 _exit(e); 158} 159 160int 161main(void) 162{ 163 pid_t pid1, pid2; 164 size_t len; 165 int e, status; 166 167 e = 0; 168 len = PAGE_SIZE; 169 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 170 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 171 err(1, "mmap"); 172 173 snprintf(file, sizeof(file), "/tmp/exlock2.%d.file", getpid()); 174 if ((pid1 = fork()) == 0) 175 test1(); 176 if (pid1 == -1) 177 err(1, "fork()"); 178 179 if ((pid2 = fork()) == 0) 180 test2(); 181 if (pid2 == -1) 182 err(1, "fork()"); 183 184 if (waitpid(pid2, &status, 0) != pid2) 185 err(1, "waitpid(%d)", pid2); 186 if (status != 0) { 187 if (WIFSIGNALED(status)) 188 fprintf(stderr, 189 "pid %d exit signal %d\n", 190 pid2, WTERMSIG(status)); 191 } 192 e += status == 0 ? 0 : 1; 193 kill(pid1, SIGHUP); 194 if (waitpid(pid1, &status, 0) != pid1) 195 err(1, "waitpid(%d)", pid1); 196 if (status != 0) { 197 if (WIFSIGNALED(status)) 198 fprintf(stderr, 199 "pid %d exit signal %d\n", 200 pid1, WTERMSIG(status)); 201 } 202 e += status == 0 ? 0 : 1; 203 204 return (e); 205} 206