Home | History | Annotate | Line # | Download | only in libutil
pidfile.c revision 1.11
      1  1.11  christos /*	$NetBSD: pidfile.c,v 1.11 2015/01/22 19:04:28 christos Exp $	*/
      2   1.1   thorpej 
      3   1.1   thorpej /*-
      4   1.1   thorpej  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5   1.1   thorpej  * All rights reserved.
      6   1.1   thorpej  *
      7   1.1   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8   1.9      jmmv  * by Jason R. Thorpe, Matthias Scheler and Julio Merino.
      9   1.1   thorpej  *
     10   1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     11   1.1   thorpej  * modification, are permitted provided that the following conditions
     12   1.1   thorpej  * are met:
     13   1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     14   1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     15   1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     17   1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     18   1.1   thorpej  *
     19   1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.6      taca  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1   thorpej  */
     31   1.1   thorpej 
     32   1.1   thorpej #include <sys/cdefs.h>
     33   1.1   thorpej #if defined(LIBC_SCCS) && !defined(lint)
     34  1.11  christos __RCSID("$NetBSD: pidfile.c,v 1.11 2015/01/22 19:04:28 christos Exp $");
     35   1.1   thorpej #endif
     36   1.1   thorpej 
     37   1.1   thorpej #include <sys/param.h>
     38   1.9      jmmv 
     39   1.1   thorpej #include <paths.h>
     40   1.9      jmmv #include <stdbool.h>
     41   1.1   thorpej #include <stdlib.h>
     42   1.1   thorpej #include <stdio.h>
     43   1.5      tron #include <string.h>
     44   1.1   thorpej #include <unistd.h>
     45   1.1   thorpej #include <util.h>
     46   1.1   thorpej 
     47   1.5      tron static pid_t pidfile_pid;
     48   1.1   thorpej static char *pidfile_path;
     49   1.1   thorpej 
     50   1.9      jmmv /* Deletes an existent pidfile iff it was created by this process. */
     51   1.9      jmmv static void
     52   1.9      jmmv pidfile_cleanup(void)
     53   1.9      jmmv {
     54   1.1   thorpej 
     55   1.9      jmmv 	if ((pidfile_path != NULL) && (pidfile_pid == getpid()))
     56   1.9      jmmv 		(void) unlink(pidfile_path);
     57   1.9      jmmv }
     58   1.9      jmmv 
     59   1.9      jmmv /* Registers an atexit(3) handler to delete the pidfile we have generated.
     60   1.9      jmmv  * We only register the handler when we create a pidfile, so we can assume
     61   1.9      jmmv  * that the pidfile exists.
     62   1.9      jmmv  *
     63   1.9      jmmv  * Returns 0 on success or -1 if the handler could not be registered. */
     64   1.9      jmmv static int
     65   1.9      jmmv register_atexit_handler(void)
     66   1.1   thorpej {
     67   1.9      jmmv 	static bool done = false;
     68   1.1   thorpej 
     69   1.9      jmmv 	if (!done) {
     70   1.5      tron 		if (atexit(pidfile_cleanup) < 0)
     71   1.7    itojun 			return -1;
     72   1.9      jmmv 		done = true;
     73   1.5      tron 	}
     74   1.1   thorpej 
     75   1.9      jmmv 	return 0;
     76   1.9      jmmv }
     77   1.1   thorpej 
     78   1.9      jmmv /* Given a new pidfile name in 'path', deletes any previously-created pidfile
     79   1.9      jmmv  * if the previous file differs to the new one.
     80   1.9      jmmv  *
     81   1.9      jmmv  * If a previous file is deleted, returns 1, which means that a new pidfile
     82   1.9      jmmv  * must be created.  Otherwise, this returns 0, which means that the existing
     83   1.9      jmmv  * file does not need to be touched. */
     84   1.9      jmmv static int
     85   1.9      jmmv cleanup_old_pidfile(const char* path)
     86   1.9      jmmv {
     87   1.5      tron 	if (pidfile_path != NULL) {
     88   1.9      jmmv 		if (strcmp(pidfile_path, path) != 0) {
     89   1.9      jmmv 			pidfile_cleanup();
     90   1.9      jmmv 
     91   1.9      jmmv 			free(pidfile_path);
     92   1.9      jmmv 			pidfile_path = NULL;
     93   1.9      jmmv 
     94   1.9      jmmv 			return 1;
     95   1.9      jmmv 		} else
     96   1.7    itojun 			return 0;
     97   1.9      jmmv 	} else
     98   1.9      jmmv 		return 1;
     99   1.9      jmmv }
    100   1.9      jmmv 
    101   1.9      jmmv /* Constructs a name for a pidfile in the default location (/var/run).  If
    102  1.11  christos  * 'bname' is NULL, uses the name of the current program for the name of
    103   1.9      jmmv  * the pidfile.
    104   1.9      jmmv  *
    105   1.9      jmmv  * Returns a pointer to a dynamically-allocatd string containing the absolute
    106   1.9      jmmv  * path to the pidfile; NULL on failure. */
    107   1.9      jmmv static char *
    108  1.10  christos generate_varrun_path(const char *bname)
    109   1.9      jmmv {
    110   1.9      jmmv 	char *path;
    111   1.9      jmmv 
    112  1.10  christos 	if (bname == NULL)
    113  1.10  christos 		bname = getprogname();
    114   1.5      tron 
    115   1.9      jmmv 	/* _PATH_VARRUN includes trailing / */
    116  1.11  christos 	if (asprintf(&path, "%s%s.pid", _PATH_VARRUN, bname) == -1)
    117  1.10  christos 		return NULL;
    118   1.9      jmmv 	return path;
    119   1.9      jmmv }
    120   1.5      tron 
    121   1.9      jmmv /* Creates a pidfile with the provided name.  The new pidfile is "registered"
    122   1.9      jmmv  * in the global variables pidfile_path and pidfile_pid so that any further
    123   1.9      jmmv  * call to pidfile(3) can check if we are recreating the same file or a new
    124   1.9      jmmv  * one.
    125   1.9      jmmv  *
    126   1.9      jmmv  * Returns 0 on success or -1 if there is any error. */
    127   1.9      jmmv static int
    128   1.9      jmmv create_pidfile(const char* path)
    129   1.9      jmmv {
    130   1.9      jmmv 	FILE *f;
    131   1.5      tron 
    132   1.9      jmmv 	if (register_atexit_handler() == -1)
    133   1.7    itojun 		return -1;
    134   1.5      tron 
    135   1.9      jmmv 	if (cleanup_old_pidfile(path) == 0)
    136   1.9      jmmv 		return 0;
    137   1.9      jmmv 
    138   1.9      jmmv 	pidfile_path = strdup(path);
    139   1.9      jmmv 	if (pidfile_path == NULL)
    140   1.7    itojun 		return -1;
    141   1.1   thorpej 
    142   1.9      jmmv 	if ((f = fopen(path, "w")) == NULL) {
    143   1.5      tron 		free(pidfile_path);
    144   1.5      tron 		pidfile_path = NULL;
    145   1.7    itojun 		return -1;
    146   1.5      tron 	}
    147   1.1   thorpej 
    148   1.9      jmmv 	pidfile_pid = getpid();
    149   1.9      jmmv 
    150   1.5      tron 	(void) fprintf(f, "%d\n", pidfile_pid);
    151   1.1   thorpej 	(void) fclose(f);
    152   1.9      jmmv 
    153   1.7    itojun 	return 0;
    154   1.1   thorpej }
    155   1.1   thorpej 
    156   1.9      jmmv int
    157   1.9      jmmv pidfile(const char *path)
    158   1.1   thorpej {
    159   1.9      jmmv 
    160   1.9      jmmv 	if (path == NULL || strchr(path, '/') == NULL) {
    161   1.9      jmmv 		char *default_path;
    162   1.9      jmmv 
    163   1.9      jmmv 		if ((default_path = generate_varrun_path(path)) == NULL)
    164   1.9      jmmv 			return -1;
    165   1.9      jmmv 
    166   1.9      jmmv 		if (create_pidfile(default_path) == -1) {
    167   1.9      jmmv 			free(default_path);
    168   1.9      jmmv 			return -1;
    169   1.9      jmmv 		}
    170   1.9      jmmv 
    171   1.9      jmmv 		free(default_path);
    172   1.9      jmmv 		return 0;
    173   1.9      jmmv 	} else
    174   1.9      jmmv 		return create_pidfile(path);
    175   1.1   thorpej }
    176