22
33/*-
44 * SPDX-License-Identifier: BSD-2-Clause
5- * Copyright (c) 1999, 2016 The NetBSD Foundation, Inc.
5+ * Copyright (c) 1999, 2016, 2026 The NetBSD Foundation, Inc.
66 * All rights reserved.
77 *
88 * This code is derived from software contributed to The NetBSD Foundation
3131 */
3232
3333#include <sys/param.h>
34+ #include <sys/file.h>
35+ #include <sys/stat.h>
3436
3537#include <errno.h>
3638#include <fcntl.h>
3739#include <inttypes.h>
3840#include <limits.h>
3941#include <paths.h>
4042#include <stdbool.h>
41- #include <stdlib.h>
4243#include <stdio.h>
44+ #include <stdlib.h>
4345#include <string.h>
4446#include <unistd.h>
4547
46- #include <sys/file.h> /* for flock(2) */
47- #include "config.h"
48- #include "defs.h"
48+ #ifdef PIDFILE_LOCAL
49+ #include "pidfile.h"
50+ #else
51+ #include <util.h>
52+ #endif
53+
54+ #ifdef __RCSID
55+ __RCSID ("$NetBSD: pidfile.c,v 1.16 2021/08/01 15:29:29 andvar Exp $" );
56+ #endif
57+
58+ static char * pf_path ;
59+ static int pf_fd = -1 ;
60+ static bool pf_removeable = true;
61+
62+ /* Reads a pid from a file descriptor */
63+ static pid_t
64+ pidfile_readfd (int fd )
65+ {
66+ char buf [16 ], * eptr ;
67+ int error ;
68+ ssize_t n ;
69+ pid_t pid = -1 ;
70+
71+ if (lseek (fd , 0 , SEEK_SET ) == -1 )
72+ return -1 ;
73+
74+ n = read (fd , buf , sizeof (buf ) - 1 );
75+ if (n == -1 )
76+ return -1 ;
77+
78+ buf [n ] = '\0' ;
79+ pid = (pid_t )strtoi (buf , & eptr , 10 , 1 , INT_MAX , & error );
80+ if (error != 0 && !(error == ENOTSUP && * eptr == '\n' ))
81+ return -1 ;
82+
83+ return pid ;
84+ }
85+
86+ int
87+ pidfile_fd (void )
88+ {
89+
90+ return pf_fd ;
91+ }
4992
50- static pid_t pidfile_pid ;
51- static char pidfile_path [ PATH_MAX ];
52- static int pidfile_fd = -1 ;
93+ const char *
94+ pidfile_path ( void )
95+ {
5396
54- /* Closes pidfile resources.
97+ return pf_path ;
98+ }
99+
100+ void
101+ pidfile_unremoveable (void )
102+ {
103+
104+ pf_removeable = false;
105+ }
106+
107+ /* Releases pidfile resources.
55108 *
56109 * Returns 0 on success, otherwise -1. */
57- static int
58- pidfile_close (void )
110+ int
111+ pidfile_unlock (void )
59112{
60113 int error ;
61114
62- pidfile_pid = 0 ;
63- error = close (pidfile_fd );
64- pidfile_fd = -1 ;
65- pidfile_path [0 ] = '\0' ;
115+ if (pf_fd == -1 )
116+ error = EBADF ;
117+ else {
118+ error = close (pf_fd );
119+ pf_fd = -1 ;
120+ }
121+ free (pf_path );
122+ pf_path = NULL ;
66123 return error ;
67124}
68125
76133pidfile_clean (void )
77134{
78135 int error ;
136+ pid_t pid ;
79137
80- if (pidfile_fd == -1 ) {
138+ if (pf_fd == -1 ) {
81139 errno = EBADF ;
82140 return -1 ;
83141 }
84142
85- if (pidfile_pid != getpid ())
143+ pid = pidfile_readfd (pf_fd );
144+ if (pid == -1 )
145+ error = errno ;
146+ else if (pid != getpid ())
86147 error = EPERM ;
87- else if (ftruncate (pidfile_fd , 0 ) == -1 )
148+ else if (ftruncate (pf_fd , 0 ) == -1 )
88149 error = errno ;
89- else {
90- #ifndef HAVE_PLEDGE /* Avoid a pledge violating segfault. */
91- (void )unlink (pidfile_path );
92- #endif
150+ else if (pf_removeable && unlink (pf_path ) == -1 )
151+ error = errno ;
152+ else
93153 error = 0 ;
94- }
95154
96- (void ) pidfile_close ();
155+ (void )pidfile_unlock ();
97156
98157 if (error != 0 ) {
99158 errno = error ;
@@ -107,7 +166,7 @@ static void
107166pidfile_cleanup (void )
108167{
109168
110- pidfile_clean ();
169+ ( void ) pidfile_clean ();
111170}
112171
113172/* Constructs a name for a pidfile in the default location (/var/run).
@@ -116,127 +175,114 @@ pidfile_cleanup(void)
116175 *
117176 * Returns 0 on success, otherwise -1. */
118177static int
119- pidfile_varrun_path (char * path , size_t len , const char * bname )
178+ pidfile_varrun_path (char * * path , const char * bname )
120179{
121180
122181 if (bname == NULL )
123- bname = PACKAGE ;
182+ bname = getprogname () ;
124183
125184 /* _PATH_VARRUN includes trailing / */
126- if ((size_t )snprintf (path , len , "%s%s.pid" , _PATH_VARRUN , bname ) >= len )
127- {
128- errno = ENAMETOOLONG ;
129- return -1 ;
130- }
131- return 0 ;
185+ return asprintf (path , "%s%s.pid" , _PATH_VARRUN , bname );
132186}
133187
134188/* Returns the process ID inside path on success, otherwise -1.
135189 * If no path is given, use the last pidfile path, otherwise the default one. */
136190pid_t
137191pidfile_read (const char * path )
138192{
139- char dpath [PATH_MAX ], buf [16 ], * eptr ;
140- int fd , error ;
141- ssize_t n ;
142- pid_t pid ;
193+ char * dpath = NULL ;
194+ int fd ;
195+ pid_t pid = -1 ;
143196
144- if (path == NULL && pidfile_path [ 0 ] != '\0' )
145- path = pidfile_path ;
197+ if (path == NULL && pf_path != NULL )
198+ path = pf_path ;
146199 if (path == NULL || strchr (path , '/' ) == NULL ) {
147- if (pidfile_varrun_path (dpath , sizeof ( dpath ) , path ) == -1 )
148- return -1 ;
200+ if (pidfile_varrun_path (& dpath , path ) == -1 )
201+ goto out ;
149202 path = dpath ;
150203 }
151204
152- if ((fd = open (path , O_RDONLY | O_NONBLOCK )) == -1 )
153- return -1 ;
154- n = read (fd , buf , sizeof (buf ) - 1 );
155- error = errno ;
156- (void ) close (fd );
157- if (n == -1 ) {
158- errno = error ;
159- return -1 ;
160- }
161- buf [n ] = '\0' ;
162- pid = (pid_t )strtoi (buf , & eptr , 10 , 1 , INT_MAX , & error );
163- if (error && !(error == ENOTSUP && * eptr == '\n' )) {
164- errno = error ;
165- return -1 ;
166- }
205+ if (pf_fd != -1 && strcmp (path , pf_path ) == 0 )
206+ fd = pf_fd ;
207+ else if ((fd = open (path , O_RDONLY | O_NONBLOCK )) == -1 )
208+ goto out ;
209+
210+ pid = pidfile_readfd (fd );
211+
212+ out :
213+ free (dpath );
167214 return pid ;
168215}
169216
170217/* Locks the pidfile specified by path and writes the process pid to it.
171- * The new pidfile is "registered" in the global variables pidfile_fd ,
172- * pidfile_path and pidfile_pid so that any further call to pidfile_lock(3)
218+ * The new pidfile is "registered" in the global variables pf_fd ,
219+ * pf_path and so that any further call to pidfile_lock(3)
173220 * can check if we are recreating the same file or a new one.
174221 *
175222 * Returns 0 on success, otherwise the pid of the process who owns the
176223 * lock if it can be read, otherwise -1. */
177224pid_t
178225pidfile_lock (const char * path )
179226{
180- char dpath [ PATH_MAX ] ;
227+ char * dpath = NULL ;
181228 static bool registered_atexit = false;
229+ pid_t pid = -1 ;
182230
183231 /* Register for cleanup with atexit. */
184232 if (!registered_atexit ) {
185233 if (atexit (pidfile_cleanup ) == -1 )
186- return -1 ;
234+ goto out ;
187235 registered_atexit = true;
188236 }
189237
190238 if (path == NULL || strchr (path , '/' ) == NULL ) {
191- if (pidfile_varrun_path (dpath , sizeof ( dpath ) , path ) == -1 )
192- return -1 ;
239+ if (pidfile_varrun_path (& dpath , path ) == -1 )
240+ goto out ;
193241 path = dpath ;
194242 }
195243
196244 /* If path has changed (no good reason), clean up the old pidfile. */
197- if (pidfile_fd != -1 && strcmp (pidfile_path , path ) != 0 )
198- pidfile_clean ();
245+ if (pf_fd != -1 && strcmp (pf_path , path ) != 0 )
246+ ( void ) pidfile_clean ();
199247
200- if (pidfile_fd == -1 ) {
248+ if (pf_fd == -1 ) {
201249 int fd , opts ;
202250
203- opts = O_WRONLY | O_CREAT | O_NONBLOCK ;
251+ opts = O_RDWR | O_CREAT | O_NONBLOCK ;
204252#ifdef O_CLOEXEC
205253 opts |= O_CLOEXEC ;
206254#endif
207255#ifdef O_EXLOCK
208- opts |= O_EXLOCK ;
256+ opts |= O_EXLOCK ;
209257#endif
210258 if ((fd = open (path , opts , 0644 )) == -1 )
211259 goto return_pid ;
260+
212261#ifndef O_CLOEXEC
213262 if ((opts = fcntl (fd , F_GETFD )) == -1 ||
214- fcntl (fd , F_SETFL , opts | FD_CLOEXEC ) == -1 )
215- {
263+ fcntl (fd , F_SETFL , opts | FD_CLOEXEC ) == -1 ) {
216264 int error = errno ;
217265
218- (void ) close (fd );
266+ (void )close (fd );
219267 errno = error ;
220- return -1 ;
268+ goto out ;
221269 }
222270#endif
223271#ifndef O_EXLOCK
224272 if (flock (fd , LOCK_EX | LOCK_NB ) == -1 ) {
225273 int error = errno ;
226274
227- (void ) close (fd );
275+ (void )close (fd );
228276 if (error != EAGAIN ) {
229277 errno = error ;
230- return -1 ;
278+ goto out ;
231279 }
232280 fd = -1 ;
233281 }
234282#endif
235283
236284return_pid :
237285 if (fd == -1 ) {
238- pid_t pid ;
239-
240286 if (errno == EAGAIN ) {
241287 /* The pidfile is locked, return the process ID
242288 * it contains.
@@ -246,27 +292,47 @@ pidfile_lock(const char *path)
246292 } else
247293 pid = -1 ;
248294
249- return pid ;
295+ goto out ;
250296 }
251- pidfile_fd = fd ;
252- strlcpy (pidfile_path , path , sizeof (pidfile_path ));
253- }
254297
255- pidfile_pid = getpid ();
298+ pf_fd = fd ;
299+ if (path == dpath ) {
300+ pf_path = dpath ;
301+ dpath = NULL ;
302+ } else
303+ pf_path = strdup (path );
304+ }
256305
257306 /* Truncate the file, as we could be re-writing it.
258307 * Then write the process ID. */
259- if (ftruncate (pidfile_fd , 0 ) == -1 ||
260- lseek (pidfile_fd , 0 , SEEK_SET ) == -1 ||
261- dprintf (pidfile_fd , "%d\n" , (int )pidfile_pid ) == -1 )
262- {
308+ if (ftruncate (pf_fd , 0 ) == -1 || lseek (pf_fd , 0 , SEEK_SET ) == -1 ||
309+ dprintf (pf_fd , "%ld\n" , (long )getpid ()) == -1 ) {
263310 int error = errno ;
264311
265- pidfile_cleanup ();
312+ ( void ) pidfile_clean ();
266313 errno = error ;
267- return -1 ;
314+ goto out ;
268315 }
269316
270317 /* Hold the fd open to persist the lock. */
271- return 0 ;
318+ pid = 0 ;
319+
320+ out :
321+ free (dpath );
322+ return pid ;
323+ }
324+
325+ /* The old function.
326+ * Historical behaviour is that pidfile is not re-written
327+ * if path has not changed.
328+ *
329+ * Returns 0 on success, otherwise -1.
330+ * As such we have no way of knowing the process ID who owns the lock. */
331+ int
332+ pidfile (const char * path )
333+ {
334+ pid_t pid ;
335+
336+ pid = pidfile_lock (path );
337+ return pid == 0 ? 0 : -1 ;
272338}
0 commit comments