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
This commit is contained in:
parent
303cbb93c5
commit
4f9612a321
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=322369
@ -31,19 +31,22 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.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 <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <libutil.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.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) {
|
||||
if (error == 0)
|
||||
if (close(pfh->pf_fd) == -1 && error == 0)
|
||||
error = errno;
|
||||
if (close(pfh->pf_dirfd) == -1 && error == 0)
|
||||
error = errno;
|
||||
}
|
||||
if (freeit)
|
||||
free(pfh);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user