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