aboutsummaryrefslogtreecommitdiff
path: root/lib/libutil/pidfile.c
diff options
context:
space:
mode:
authorMariusz Zaborski <oshogbo@FreeBSD.org>2017-08-10 16:45:05 +0000
committerMariusz Zaborski <oshogbo@FreeBSD.org>2017-08-10 16:45:05 +0000
commit4f9612a321fcdfbb4cd6cefcb251e88d500fdb90 (patch)
treef436376a47731f5fd260cd1645f22cf4d70817f5 /lib/libutil/pidfile.c
parent303cbb93c5cc997c78c180eea59a64281be354b7 (diff)
downloadsrc-4f9612a321fcdfbb4cd6cefcb251e88d500fdb90.tar.gz
src-4f9612a321fcdfbb4cd6cefcb251e88d500fdb90.zip
Store directory descriptor in the pidfh structure and use unlinkat(2)
function instead of unlink(2). Now when pidfile_remove() uses unlinkat(2) to remove the pidfile it is safe to use this function in capability mode. Style fix: sort headers. PR: 220524 Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D11692
Notes
Notes: svn path=/head/; revision=322369
Diffstat (limited to 'lib/libutil/pidfile.c')
-rw-r--r--lib/libutil/pidfile.c77
1 files changed, 53 insertions, 24 deletions
diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c
index 157a53c7448f..50d3a440729d 100644
--- a/lib/libutil/pidfile.c
+++ b/lib/libutil/pidfile.c
@@ -31,19 +31,22 @@ __FBSDID("$FreeBSD$");
#include <sys/file.h>
#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <string.h>
#include <time.h>
-#include <err.h>
-#include <errno.h>
-#include <libutil.h>
+#include <unistd.h>
struct pidfh {
+ int pf_dirfd;
int pf_fd;
- char pf_path[MAXPATHLEN + 1];
+ char pf_dir[MAXPATHLEN + 1];
+ char pf_filename[MAXPATHLEN + 1];
dev_t pf_dev;
ino_t pf_ino;
};
@@ -68,12 +71,12 @@ pidfile_verify(const struct pidfh *pfh)
}
static int
-pidfile_read(const char *path, pid_t *pidptr)
+pidfile_read(int dirfd, const char *filename, pid_t *pidptr)
{
char buf[16], *endptr;
int error, fd, i;
- fd = open(path, O_RDONLY | O_CLOEXEC);
+ fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
if (fd == -1)
return (errno);
@@ -98,32 +101,50 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
struct pidfh *pfh;
struct stat sb;
- int error, fd, len, count;
+ int error, fd, dirfd, dirlen, filenamelen, count;
struct timespec rqtp;
pfh = malloc(sizeof(*pfh));
if (pfh == NULL)
return (NULL);
- if (path == NULL)
- len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
- "/var/run/%s.pid", getprogname());
- else
- len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
+ if (path == NULL) {
+ dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
+ "/var/run/");
+ filenamelen = snprintf(pfh->pf_filename,
+ sizeof(pfh->pf_filename), "%s.pid", getprogname());
+ } else {
+ dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
"%s", path);
- if (len >= (int)sizeof(pfh->pf_path)) {
+ filenamelen = snprintf(pfh->pf_filename,
+ sizeof(pfh->pf_filename), "%s", path);
+
+ dirname(pfh->pf_dir);
+ basename(pfh->pf_filename);
+ }
+
+ if (dirlen >= (int)sizeof(pfh->pf_dir) ||
+ filenamelen >= (int)sizeof(pfh->pf_filename)) {
free(pfh);
errno = ENAMETOOLONG;
return (NULL);
}
+ dirfd = open(pfh->pf_dir, O_CLOEXEC | O_DIRECTORY | O_NONBLOCK);
+ if (dirfd == -1) {
+ error = errno;
+ free(pfh);
+ errno = error;
+ return (NULL);
+ }
+
/*
* Open the PID file and obtain exclusive lock.
* We truncate PID file here only to remove old PID immediately,
* PID file will be truncated again in pidfile_write(), so
* pidfile_write() can be called multiple times.
*/
- fd = flopen(pfh->pf_path,
+ fd = flopenat(dirfd, pfh->pf_filename,
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
if (fd == -1) {
if (errno == EWOULDBLOCK) {
@@ -134,8 +155,8 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
rqtp.tv_sec = 0;
rqtp.tv_nsec = 5000000;
for (;;) {
- errno = pidfile_read(pfh->pf_path,
- pidptr);
+ errno = pidfile_read(dirfd,
+ pfh->pf_filename, pidptr);
if (errno != EAGAIN || --count == 0)
break;
nanosleep(&rqtp, 0);
@@ -146,7 +167,10 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
errno = EEXIST;
}
}
+ error = errno;
+ close(dirfd);
free(pfh);
+ errno = error;
return (NULL);
}
@@ -156,13 +180,15 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
*/
if (fstat(fd, &sb) == -1) {
error = errno;
- unlink(pfh->pf_path);
+ unlinkat(dirfd, pfh->pf_filename, 0);
+ close(dirfd);
close(fd);
free(pfh);
errno = error;
return (NULL);
}
+ pfh->pf_dirfd = dirfd;
pfh->pf_fd = fd;
pfh->pf_dev = sb.st_dev;
pfh->pf_ino = sb.st_ino;
@@ -223,6 +249,9 @@ pidfile_close(struct pidfh *pfh)
if (close(pfh->pf_fd) == -1)
error = errno;
+ if (close(pfh->pf_dirfd) == -1 && error == 0)
+ error = errno;
+
free(pfh);
if (error != 0) {
errno = error;
@@ -242,12 +271,12 @@ _pidfile_remove(struct pidfh *pfh, int freeit)
return (-1);
}
- if (unlink(pfh->pf_path) == -1)
+ if (unlinkat(pfh->pf_dirfd, pfh->pf_filename, 0) == -1)
+ error = errno;
+ if (close(pfh->pf_fd) == -1 && error == 0)
+ error = errno;
+ if (close(pfh->pf_dirfd) == -1 && error == 0)
error = errno;
- if (close(pfh->pf_fd) == -1) {
- if (error == 0)
- error = errno;
- }
if (freeit)
free(pfh);
else