1199213Sdes/*- 2199213Sdes * Copyright (c) 2007-2009 Dag-Erling Co��dan Sm��rgrav 3199213Sdes * All rights reserved. 4199213Sdes * 5199213Sdes * Redistribution and use in source and binary forms, with or without 6199213Sdes * modification, are permitted provided that the following conditions 7199213Sdes * are met: 8199213Sdes * 1. Redistributions of source code must retain the above copyright 9199213Sdes * notice, this list of conditions and the following disclaimer 10199213Sdes * in this position and unchanged. 11199213Sdes * 2. Redistributions in binary form must reproduce the above copyright 12199213Sdes * notice, this list of conditions and the following disclaimer in the 13199213Sdes * documentation and/or other materials provided with the distribution. 14199213Sdes * 15199213Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16199213Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17199213Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18199213Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19199213Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20199213Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21199213Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22199213Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23199213Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24199213Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25199213Sdes * SUCH DAMAGE. 26199213Sdes */ 27199213Sdes 28199213Sdes#include <sys/cdefs.h> 29199213Sdes__FBSDID("$FreeBSD: stable/10/lib/libutil/tests/pidfile_test.c 335965 2018-07-04 18:03:19Z emaste $"); 30199213Sdes 31199213Sdes#include <sys/param.h> 32199213Sdes#include <sys/wait.h> 33335965Semaste#include <sys/event.h> 34199213Sdes 35199213Sdes#include <fcntl.h> 36199213Sdes#include <errno.h> 37199213Sdes#include <signal.h> 38199213Sdes#include <stdint.h> 39199213Sdes#include <stdio.h> 40199213Sdes#include <stdlib.h> 41199213Sdes#include <string.h> 42199213Sdes#include <unistd.h> 43199213Sdes 44199213Sdes#include <libutil.h> 45199213Sdes 46199213Sdes/* 47335965Semaste * We need a signal handler so kill(2) will interrupt the child 48335965Semaste * instead of killing it. 49199213Sdes */ 50199213Sdesstatic void 51199213Sdessignal_handler(int sig) 52199213Sdes{ 53199213Sdes (void)sig; 54199213Sdes} 55199213Sdes 56199213Sdes/* 57199213Sdes * Test that pidfile_open() can create a pidfile and that pidfile_write() 58199213Sdes * can write to it. 59199213Sdes */ 60199213Sdesstatic const char * 61199213Sdestest_pidfile_uncontested(void) 62199213Sdes{ 63199213Sdes const char *fn = "test_pidfile_uncontested"; 64199213Sdes struct pidfh *pf; 65199213Sdes pid_t other = 0; 66199213Sdes 67199213Sdes unlink(fn); 68199213Sdes pf = pidfile_open(fn, 0600, &other); 69199213Sdes if (pf == NULL && other != 0) 70199213Sdes return ("pidfile exists and is locked"); 71199213Sdes if (pf == NULL) 72199213Sdes return (strerror(errno)); 73199213Sdes if (pidfile_write(pf) != 0) { 74199213Sdes pidfile_close(pf); 75199213Sdes unlink(fn); 76199213Sdes return ("failed to write PID"); 77199213Sdes } 78199213Sdes pidfile_close(pf); 79199213Sdes unlink(fn); 80199213Sdes return (NULL); 81199213Sdes} 82199213Sdes 83199213Sdes/* 84199213Sdes * Test that pidfile_open() locks against self. 85199213Sdes */ 86199213Sdesstatic const char * 87199213Sdestest_pidfile_self(void) 88199213Sdes{ 89199213Sdes const char *fn = "test_pidfile_self"; 90199213Sdes struct pidfh *pf1, *pf2; 91199213Sdes pid_t other = 0; 92199213Sdes int serrno; 93199213Sdes 94199213Sdes unlink(fn); 95199213Sdes pf1 = pidfile_open(fn, 0600, &other); 96199213Sdes if (pf1 == NULL && other != 0) 97199213Sdes return ("pidfile exists and is locked"); 98199213Sdes if (pf1 == NULL) 99199213Sdes return (strerror(errno)); 100199213Sdes if (pidfile_write(pf1) != 0) { 101199213Sdes serrno = errno; 102199213Sdes pidfile_close(pf1); 103199213Sdes unlink(fn); 104199213Sdes return (strerror(serrno)); 105199213Sdes } 106199213Sdes // second open should fail 107199213Sdes pf2 = pidfile_open(fn, 0600, &other); 108199213Sdes if (pf2 != NULL) { 109199213Sdes pidfile_close(pf1); 110199213Sdes pidfile_close(pf2); 111199213Sdes unlink(fn); 112199213Sdes return ("managed to opened pidfile twice"); 113199213Sdes } 114199213Sdes if (other != getpid()) { 115199213Sdes pidfile_close(pf1); 116199213Sdes unlink(fn); 117199213Sdes return ("pidfile contained wrong PID"); 118199213Sdes } 119199213Sdes pidfile_close(pf1); 120199213Sdes unlink(fn); 121199213Sdes return (NULL); 122199213Sdes} 123199213Sdes 124199213Sdes/* 125199213Sdes * Common code for test_pidfile_{contested,inherited}. 126199213Sdes */ 127199213Sdesstatic const char * 128199213Sdescommon_test_pidfile_child(const char *fn, int parent_open) 129199213Sdes{ 130199213Sdes struct pidfh *pf = NULL; 131199213Sdes pid_t other = 0, pid = 0; 132199213Sdes int fd[2], serrno, status; 133335965Semaste struct kevent event, ke; 134199213Sdes char ch; 135335965Semaste int kq; 136199213Sdes 137199213Sdes unlink(fn); 138199213Sdes if (pipe(fd) != 0) 139199213Sdes return (strerror(errno)); 140199213Sdes 141199213Sdes if (parent_open) { 142199213Sdes pf = pidfile_open(fn, 0600, &other); 143199213Sdes if (pf == NULL && other != 0) 144199213Sdes return ("pidfile exists and is locked"); 145199213Sdes if (pf == NULL) 146199213Sdes return (strerror(errno)); 147199213Sdes } 148199213Sdes 149199213Sdes pid = fork(); 150199213Sdes if (pid == -1) 151199213Sdes return (strerror(errno)); 152199213Sdes if (pid == 0) { 153199213Sdes // child 154199213Sdes close(fd[0]); 155199213Sdes signal(SIGINT, signal_handler); 156199213Sdes if (!parent_open) { 157199213Sdes pf = pidfile_open(fn, 0600, &other); 158199213Sdes if (pf == NULL && other != 0) 159199213Sdes return ("pidfile exists and is locked"); 160199213Sdes if (pf == NULL) 161199213Sdes return (strerror(errno)); 162199213Sdes } 163199213Sdes if (pidfile_write(pf) != 0) { 164199213Sdes serrno = errno; 165199213Sdes pidfile_close(pf); 166199213Sdes unlink(fn); 167199213Sdes return (strerror(serrno)); 168199213Sdes } 169199213Sdes if (pf == NULL) 170199213Sdes _exit(1); 171199213Sdes if (pidfile_write(pf) != 0) 172335965Semaste _exit(2); 173335965Semaste kq = kqueue(); 174335965Semaste if (kq == -1) 175335965Semaste _exit(3); 176335965Semaste EV_SET(&ke, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 177335965Semaste /* Attach event to the kqueue. */ 178335965Semaste if (kevent(kq, &ke, 1, NULL, 0, NULL) != 0) 179335965Semaste _exit(4); 180335965Semaste /* Inform the parent we are ready to receive SIGINT */ 181199213Sdes if (write(fd[1], "*", 1) != 1) 182335965Semaste _exit(5); 183335965Semaste /* Wait for SIGINT received */ 184335965Semaste if (kevent(kq, NULL, 0, &event, 1, NULL) != 1) 185335965Semaste _exit(6); 186199213Sdes _exit(0); 187199213Sdes } 188199213Sdes // parent 189199213Sdes close(fd[1]); 190199213Sdes if (pf) 191199213Sdes pidfile_close(pf); 192199213Sdes 193199213Sdes // wait for the child to signal us 194199213Sdes if (read(fd[0], &ch, 1) != 1) { 195199213Sdes serrno = errno; 196199213Sdes unlink(fn); 197199213Sdes kill(pid, SIGTERM); 198199213Sdes errno = serrno; 199199213Sdes return (strerror(errno)); 200199213Sdes } 201199213Sdes 202199213Sdes // We shouldn't be able to lock the same pidfile as our child 203199213Sdes pf = pidfile_open(fn, 0600, &other); 204199213Sdes if (pf != NULL) { 205199213Sdes pidfile_close(pf); 206199213Sdes unlink(fn); 207199213Sdes return ("managed to lock contested pidfile"); 208199213Sdes } 209199213Sdes 210199213Sdes // Failed to lock, but not because it was contested 211199213Sdes if (other == 0) { 212199213Sdes unlink(fn); 213199213Sdes return (strerror(errno)); 214199213Sdes } 215199213Sdes 216199213Sdes // Locked by the wrong process 217199213Sdes if (other != pid) { 218199213Sdes unlink(fn); 219199213Sdes return ("pidfile contained wrong PID"); 220199213Sdes } 221199213Sdes 222199213Sdes // check our child's fate 223199213Sdes if (pf) 224199213Sdes pidfile_close(pf); 225199213Sdes unlink(fn); 226199213Sdes if (kill(pid, SIGINT) != 0) 227199213Sdes return (strerror(errno)); 228199213Sdes if (waitpid(pid, &status, 0) == -1) 229199213Sdes return (strerror(errno)); 230199213Sdes if (WIFSIGNALED(status)) 231199213Sdes return ("child caught signal"); 232199213Sdes if (WEXITSTATUS(status) != 0) 233199213Sdes return ("child returned non-zero status"); 234199213Sdes 235199213Sdes // success 236199213Sdes return (NULL); 237199213Sdes} 238199213Sdes 239199213Sdes/* 240199213Sdes * Test that pidfile_open() fails when attempting to open a pidfile that 241199213Sdes * is already locked, and that it returns the correct PID. 242199213Sdes */ 243199213Sdesstatic const char * 244199213Sdestest_pidfile_contested(void) 245199213Sdes{ 246199213Sdes const char *fn = "test_pidfile_contested"; 247199213Sdes const char *result; 248199213Sdes 249199213Sdes result = common_test_pidfile_child(fn, 0); 250199213Sdes return (result); 251199213Sdes} 252199213Sdes 253199213Sdes/* 254199213Sdes * Test that the pidfile lock is inherited. 255199213Sdes */ 256199213Sdesstatic const char * 257199213Sdestest_pidfile_inherited(void) 258199213Sdes{ 259199213Sdes const char *fn = "test_pidfile_inherited"; 260199213Sdes const char *result; 261199213Sdes 262199213Sdes result = common_test_pidfile_child(fn, 1); 263199213Sdes return (result); 264199213Sdes} 265199213Sdes 266199213Sdesstatic struct test { 267199213Sdes const char *name; 268199213Sdes const char *(*func)(void); 269199213Sdes} t[] = { 270199213Sdes { "pidfile_uncontested", test_pidfile_uncontested }, 271199213Sdes { "pidfile_self", test_pidfile_self }, 272199213Sdes { "pidfile_contested", test_pidfile_contested }, 273199213Sdes { "pidfile_inherited", test_pidfile_inherited }, 274199213Sdes}; 275199213Sdes 276199213Sdesint 277199213Sdesmain(void) 278199213Sdes{ 279199213Sdes const char *result; 280199213Sdes int i, nt; 281199213Sdes 282199213Sdes nt = sizeof(t) / sizeof(*t); 283199213Sdes printf("1..%d\n", nt); 284199213Sdes for (i = 0; i < nt; ++i) { 285199213Sdes if ((result = t[i].func()) != NULL) 286199213Sdes printf("not ok %d - %s # %s\n", i + 1, 287199213Sdes t[i].name, result); 288199213Sdes else 289199213Sdes printf("ok %d - %s\n", i + 1, 290199213Sdes t[i].name); 291199213Sdes } 292199213Sdes exit(0); 293199213Sdes} 294