1301169Slidl/* $NetBSD: pidfile.c,v 1.2 2016/04/05 12:28:57 christos Exp $ */ 2301169Slidl 3301169Slidl/*- 4301169Slidl * Copyright (c) 1999 The NetBSD Foundation, Inc. 5301169Slidl * All rights reserved. 6301169Slidl * 7301169Slidl * This code is derived from software contributed to The NetBSD Foundation 8301169Slidl * by Jason R. Thorpe, Matthias Scheler and Julio Merino. 9301169Slidl * 10301169Slidl * Redistribution and use in source and binary forms, with or without 11301169Slidl * modification, are permitted provided that the following conditions 12301169Slidl * are met: 13301169Slidl * 1. Redistributions of source code must retain the above copyright 14301169Slidl * notice, this list of conditions and the following disclaimer. 15301169Slidl * 2. Redistributions in binary form must reproduce the above copyright 16301169Slidl * notice, this list of conditions and the following disclaimer in the 17301169Slidl * documentation and/or other materials provided with the distribution. 18301169Slidl * 19301169Slidl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20301169Slidl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21301169Slidl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22301169Slidl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23301169Slidl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24301169Slidl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25301169Slidl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26301169Slidl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27301169Slidl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28301169Slidl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29301169Slidl * POSSIBILITY OF SUCH DAMAGE. 30301169Slidl */ 31301169Slidl#ifdef HAVE_CONFIG_H 32301169Slidl#include "config.h" 33301169Slidl#endif 34301169Slidl 35301169Slidl#include <sys/cdefs.h> 36301169Slidl#if defined(LIBC_SCCS) && !defined(lint) 37301169Slidl__RCSID("$NetBSD: pidfile.c,v 1.2 2016/04/05 12:28:57 christos Exp $"); 38301169Slidl#endif 39301169Slidl 40301169Slidl#include <sys/param.h> 41301169Slidl 42301169Slidl#include <paths.h> 43301169Slidl#include <stdbool.h> 44301169Slidl#include <stdlib.h> 45301169Slidl#include <stdio.h> 46301169Slidl#include <string.h> 47301169Slidl#include <unistd.h> 48301169Slidl#ifdef HAVE_LIBUTIL_H 49301169Slidl#include <libutil.h> 50301169Slidl#endif 51301169Slidl#ifdef HAVE_UTIL_H 52301169Slidl#include <util.h> 53301169Slidl#endif 54301169Slidl 55301169Slidlstatic pid_t pidfile_pid; 56301169Slidlstatic char *pidfile_path; 57301169Slidl 58301169Slidl/* Deletes an existent pidfile iff it was created by this process. */ 59301169Slidlstatic void 60301169Slidlpidfile_cleanup(void) 61301169Slidl{ 62301169Slidl 63301169Slidl if ((pidfile_path != NULL) && (pidfile_pid == getpid())) 64301169Slidl (void) unlink(pidfile_path); 65301169Slidl} 66301169Slidl 67301169Slidl/* Registers an atexit(3) handler to delete the pidfile we have generated. 68301169Slidl * We only register the handler when we create a pidfile, so we can assume 69301169Slidl * that the pidfile exists. 70301169Slidl * 71301169Slidl * Returns 0 on success or -1 if the handler could not be registered. */ 72301169Slidlstatic int 73301169Slidlregister_atexit_handler(void) 74301169Slidl{ 75301169Slidl static bool done = false; 76301169Slidl 77301169Slidl if (!done) { 78301169Slidl if (atexit(pidfile_cleanup) < 0) 79301169Slidl return -1; 80301169Slidl done = true; 81301169Slidl } 82301169Slidl 83301169Slidl return 0; 84301169Slidl} 85301169Slidl 86301169Slidl/* Given a new pidfile name in 'path', deletes any previously-created pidfile 87301169Slidl * if the previous file differs to the new one. 88301169Slidl * 89301169Slidl * If a previous file is deleted, returns 1, which means that a new pidfile 90301169Slidl * must be created. Otherwise, this returns 0, which means that the existing 91301169Slidl * file does not need to be touched. */ 92301169Slidlstatic int 93301169Slidlcleanup_old_pidfile(const char* path) 94301169Slidl{ 95301169Slidl if (pidfile_path != NULL) { 96301169Slidl if (strcmp(pidfile_path, path) != 0) { 97301169Slidl pidfile_cleanup(); 98301169Slidl 99301169Slidl free(pidfile_path); 100301169Slidl pidfile_path = NULL; 101301169Slidl 102301169Slidl return 1; 103301169Slidl } else 104301169Slidl return 0; 105301169Slidl } else 106301169Slidl return 1; 107301169Slidl} 108301169Slidl 109301169Slidl/* Constructs a name for a pidfile in the default location (/var/run). If 110301169Slidl * 'basename' is NULL, uses the name of the current program for the name of 111301169Slidl * the pidfile. 112301169Slidl * 113301169Slidl * Returns a pointer to a dynamically-allocatd string containing the absolute 114301169Slidl * path to the pidfile; NULL on failure. */ 115301169Slidlstatic char * 116301169Slidlgenerate_varrun_path(const char *bname) 117301169Slidl{ 118301169Slidl char *path; 119301169Slidl 120301169Slidl if (bname == NULL) 121301169Slidl bname = getprogname(); 122301169Slidl 123301169Slidl /* _PATH_VARRUN includes trailing / */ 124301169Slidl if (asprintf(&path, "%s%s.pid", _PATH_VARRUN, bname) == -1) 125301169Slidl return NULL; 126301169Slidl return path; 127301169Slidl} 128301169Slidl 129301169Slidl/* Creates a pidfile with the provided name. The new pidfile is "registered" 130301169Slidl * in the global variables pidfile_path and pidfile_pid so that any further 131301169Slidl * call to pidfile(3) can check if we are recreating the same file or a new 132301169Slidl * one. 133301169Slidl * 134301169Slidl * Returns 0 on success or -1 if there is any error. */ 135301169Slidlstatic int 136301169Slidlcreate_pidfile(const char* path) 137301169Slidl{ 138301169Slidl FILE *f; 139301169Slidl 140301169Slidl if (register_atexit_handler() == -1) 141301169Slidl return -1; 142301169Slidl 143301169Slidl if (cleanup_old_pidfile(path) == 0) 144301169Slidl return 0; 145301169Slidl 146301169Slidl pidfile_path = strdup(path); 147301169Slidl if (pidfile_path == NULL) 148301169Slidl return -1; 149301169Slidl 150301169Slidl if ((f = fopen(path, "w")) == NULL) { 151301169Slidl free(pidfile_path); 152301169Slidl pidfile_path = NULL; 153301169Slidl return -1; 154301169Slidl } 155301169Slidl 156301169Slidl pidfile_pid = getpid(); 157301169Slidl 158301169Slidl (void) fprintf(f, "%d\n", pidfile_pid); 159301169Slidl (void) fclose(f); 160301169Slidl 161301169Slidl return 0; 162301169Slidl} 163301169Slidl 164301169Slidlint 165301169Slidlpidfile(const char *path) 166301169Slidl{ 167301169Slidl 168301169Slidl if (path == NULL || strchr(path, '/') == NULL) { 169301169Slidl char *default_path; 170301169Slidl 171301169Slidl if ((default_path = generate_varrun_path(path)) == NULL) 172301169Slidl return -1; 173301169Slidl 174301169Slidl if (create_pidfile(default_path) == -1) { 175301169Slidl free(default_path); 176301169Slidl return -1; 177301169Slidl } 178301169Slidl 179301169Slidl free(default_path); 180301169Slidl return 0; 181301169Slidl } else 182301169Slidl return create_pidfile(path); 183301169Slidl} 184