From 993828d84eed0468c6c15b2818e534e6b134b8e4 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Mon, 21 May 2018 01:11:46 +0200 Subject: [PATCH] Add flopenat() function from FreeBSD --- COPYING | 2 +- include/bsd/libutil.h | 1 + man/flopen.3bsd | 42 +++++++++++++++++++++++------ src/flopen.c | 62 ++++++++++++++++++++++++++++++++++++------- src/libbsd.map | 4 +++ 5 files changed, 92 insertions(+), 19 deletions(-) diff --git a/COPYING b/COPYING index 9ffc6b4..021e67e 100644 --- a/COPYING +++ b/COPYING @@ -367,7 +367,7 @@ License: BSD-2-clause Files: src/flopen.c Copyright: - Copyright © 2007 Dag-Erling Coïdan Smørgrav + Copyright © 2007-2009 Dag-Erling Coïdan Smørgrav All rights reserved. License: BSD-2-clause-verbatim Redistribution and use in source and binary forms, with or without diff --git a/include/bsd/libutil.h b/include/bsd/libutil.h index e5f148a..2c4c731 100644 --- a/include/bsd/libutil.h +++ b/include/bsd/libutil.h @@ -62,6 +62,7 @@ int humanize_number(char *buf, size_t len, int64_t bytes, int expand_number(const char *_buf, uint64_t *_num); int flopen(const char *_path, int _flags, ...); +int flopenat(int dirfd, const char *path, int flags, ...); struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); int pidfile_write(struct pidfh *pfh); diff --git a/man/flopen.3bsd b/man/flopen.3bsd index ab58b28..b3cd8c9 100644 --- a/man/flopen.3bsd +++ b/man/flopen.3bsd @@ -25,12 +25,13 @@ .\" .\" $FreeBSD$ .\" -.Dd June 6, 2009 +.Dd July 28, 2017 .Dt FLOPEN 3bsd .Os .Sh NAME -.Nm flopen -.Nd reliably open and lock a file +.Nm flopen , +.Nm flopenat +.Nd "Reliably open and lock a file" .Sh LIBRARY .ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd) .Lb libbsd @@ -44,6 +45,10 @@ for include usage.) .Fn flopen "const char *path" "int flags" .Ft int .Fn flopen "const char *path" "int flags" "mode_t mode" +.Ft int +.Fn flopenat "int fd" "const char *path" "int flags" +.Ft int +.Fn flopenat "int fd" "const char *path" "int flags" "mode_t mode" .Sh DESCRIPTION The .Fn flopen @@ -53,7 +58,7 @@ It is essentially equivalent with calling with the same parameters followed by .Fn flock with an -.Va operation +.Fa operation argument of .Dv LOCK_EX , except that @@ -65,7 +70,7 @@ files, mailboxes and other kinds of files which are used for synchronization between processes. .Pp If -.Va flags +.Fa flags includes .Dv O_NONBLOCK and the file is already locked, @@ -78,11 +83,32 @@ to As with .Fn open , the additional -.Va mode +.Fa mode argument is required if -.Va flags +.Fa flags includes .Dv O_CREAT . +.Pp +The +.Fn flopenat +function is equivalent to the +.Fn flopen +function except in the case where the +.Fa path +specifies a relative path. +In this case the file to be opened is determined relative to the directory +associated with the file descriptor +.Fa fd +instead of the current working directory. +If +.Fn flopenat +is passed the special value +.Dv AT_FDCWD +in the +.Fa fd +parameter, the current working directory is used +and the behavior is identical to a call to +.Fn flopen . .Sh RETURN VALUES If successful, .Fn flopen @@ -102,4 +128,4 @@ and The .Nm function and this manual page were written by -.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . +.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org . diff --git a/src/flopen.c b/src/flopen.c index aa506f5..b9972c9 100644 --- a/src/flopen.c +++ b/src/flopen.c @@ -1,5 +1,7 @@ /*- - * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,13 +32,21 @@ #include #include -#include #include #include + #include -int -flopen(const char *path, int flags, ...) +/* + * Reliably open and lock a file. + * + * Please do not modify this code without first reading the revision history + * and discussing your changes with . Don't be fooled by the + * code's apparent simplicity; there would be no need for this function if it + * was easy to get right. + */ +static int +vflopenat(int dirfd, const char *path, int flags, va_list ap) { int fd, operation, serrno, trunc; struct stat sb, fsb; @@ -48,11 +58,7 @@ flopen(const char *path, int flags, ...) mode = 0; if (flags & O_CREAT) { - va_list ap; - - va_start(ap, flags); mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */ - va_end(ap); } operation = LOCK_EX; @@ -63,7 +69,7 @@ flopen(const char *path, int flags, ...) flags &= ~O_TRUNC; for (;;) { - if ((fd = open(path, flags, mode)) == -1) + if ((fd = openat(dirfd, path, flags, mode)) == -1) /* non-existent or no access */ return (-1); if (flock(fd, operation) == -1) { @@ -73,7 +79,7 @@ flopen(const char *path, int flags, ...) errno = serrno; return (-1); } - if (stat(path, &sb) == -1) { + if (fstatat(dirfd, path, &sb, 0) == -1) { /* disappeared from under our feet */ (void)close(fd); continue; @@ -98,6 +104,42 @@ flopen(const char *path, int flags, ...) errno = serrno; return (-1); } + /* + * The following change is provided as a specific example to + * avoid. + */ +#if 0 + if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + serrno = errno; + (void)close(fd); + errno = serrno; + return (-1); + } +#endif return (fd); } } + +int +flopen(const char *path, int flags, ...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = vflopenat(AT_FDCWD, path, flags, ap); + va_end(ap); + return (ret); +} + +int +flopenat(int dirfd, const char *path, int flags, ...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = vflopenat(dirfd, path, flags, ap); + va_end(ap); + return (ret); +} diff --git a/src/libbsd.map b/src/libbsd.map index 304c593..47d7df5 100644 --- a/src/libbsd.map +++ b/src/libbsd.map @@ -139,3 +139,7 @@ LIBBSD_0.7 { LIBBSD_0.8 { explicit_bzero; } LIBBSD_0.7; + +LIBBSD_0.9 { + flopenat; +} LIBBSD_0.8;