Skip to content

Commit 9d25437

Browse files
committed
pidfile: Import latest from NetBSD
1 parent 15ff549 commit 9d25437

2 files changed

Lines changed: 161 additions & 89 deletions

File tree

‎compat/pidfile.c‎

Lines changed: 153 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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
@@ -31,38 +31,95 @@
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

@@ -76,24 +133,26 @@ int
76133
pidfile_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
107166
pidfile_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. */
118177
static 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. */
136190
pid_t
137191
pidfile_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. */
177224
pid_t
178225
pidfile_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

236284
return_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

Comments
 (0)