From owner-svn-src-head@FreeBSD.ORG Fri Aug 9 17:24:25 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 291B4836; Fri, 9 Aug 2013 17:24:25 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 1460C256A; Fri, 9 Aug 2013 17:24:25 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r79HOObf039639; Fri, 9 Aug 2013 17:24:24 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r79HONBh039632; Fri, 9 Aug 2013 17:24:23 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201308091724.r79HONBh039632@svn.freebsd.org> From: Jilles Tjoelker Date: Fri, 9 Aug 2013 17:24:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r254151 - in head: include lib/libc/stdio tools/regression/lib/libc/stdio X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Aug 2013 17:24:25 -0000 Author: jilles Date: Fri Aug 9 17:24:23 2013 New Revision: 254151 URL: http://svnweb.freebsd.org/changeset/base/254151 Log: Add mkostemp() and mkostemps(). These are like mkstemp() and mkstemps() but allow passing open(2) flags like O_CLOEXEC. Added: head/tools/regression/lib/libc/stdio/test-mkostemp.c (contents, props changed) Modified: head/include/stdlib.h head/lib/libc/stdio/Makefile.inc head/lib/libc/stdio/Symbol.map head/lib/libc/stdio/mktemp.3 head/lib/libc/stdio/mktemp.c head/tools/regression/lib/libc/stdio/Makefile Modified: head/include/stdlib.h ============================================================================== --- head/include/stdlib.h Fri Aug 9 16:43:50 2013 (r254150) +++ head/include/stdlib.h Fri Aug 9 17:24:23 2013 (r254151) @@ -282,6 +282,8 @@ const char * int heapsort(void *, size_t, size_t, int (*)(const void *, const void *)); int l64a_r(long, char *, int); int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); +int mkostemp(char *, int); +int mkostemps(char *, int, int); void qsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *)); int radixsort(const unsigned char **, int, const unsigned char *, Modified: head/lib/libc/stdio/Makefile.inc ============================================================================== --- head/lib/libc/stdio/Makefile.inc Fri Aug 9 16:43:50 2013 (r254150) +++ head/lib/libc/stdio/Makefile.inc Fri Aug 9 17:24:23 2013 (r254151) @@ -60,7 +60,8 @@ MLINKS+=getc.3 fgetc.3 getc.3 getc_unloc getc.3 getchar_unlocked.3 getc.3 getw.3 MLINKS+=getline.3 getdelim.3 MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3 -MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 +MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 \ + mktemp.3 mkostemp.3 mktemp.3 mkostemps.3 MLINKS+=open_memstream.3 open_wmemstream.3 MLINKS+=printf.3 asprintf.3 printf.3 dprintf.3 printf.3 fprintf.3 \ printf.3 snprintf.3 printf.3 sprintf.3 \ Modified: head/lib/libc/stdio/Symbol.map ============================================================================== --- head/lib/libc/stdio/Symbol.map Fri Aug 9 16:43:50 2013 (r254150) +++ head/lib/libc/stdio/Symbol.map Fri Aug 9 17:24:23 2013 (r254151) @@ -158,6 +158,8 @@ FBSD_1.3 { fmemopen; open_memstream; open_wmemstream; + mkostemp; + mkostemps; }; FBSDprivate_1.0 { Modified: head/lib/libc/stdio/mktemp.3 ============================================================================== --- head/lib/libc/stdio/mktemp.3 Fri Aug 9 16:43:50 2013 (r254150) +++ head/lib/libc/stdio/mktemp.3 Fri Aug 9 17:24:23 2013 (r254151) @@ -28,7 +28,7 @@ .\" @(#)mktemp.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd July 5, 2013 +.Dd August 8, 2013 .Dt MKTEMP 3 .Os .Sh NAME @@ -42,6 +42,10 @@ .Fn mktemp "char *template" .Ft int .Fn mkstemp "char *template" +.Ft int +.Fn mkostemp "char *template" "int oflags" +.Ft int +.Fn mkostemps "char *template" "int suffixlen" "int oflags" .Ft char * .Fn mkdtemp "char *template" .In unistd.h @@ -85,16 +89,41 @@ This avoids the race between testing for for use. .Pp The +.Fn mkostemp +function +is like +.Fn mkstemp +but allows specifying additional +.Xr open 2 +flags (defined in +.In fcntl.h ) . +The permitted flags are +.Dv O_APPEND , +.Dv O_DIRECT , +.Dv O_SHLOCK , +.Dv O_EXLOCK , +.Dv O_SYNC +and +.Dv O_CLOEXEC . +.Pp +The .Fn mkstemps -function acts the same as -.Fn mkstemp , -except it permits a suffix to exist in the template. +and +.Fn mkostemps +functions act the same as +.Fn mkstemp +and +.Fn mkostemp +respectively, +except they permit a suffix to exist in the template. The template should be of the form .Pa /tmp/tmpXXXXXXsuffix . The .Fn mkstemps +and +.Fn mkostemps function -is told the length of the suffix string. +are told the length of the suffix string. .Pp The .Fn mkdtemp @@ -110,9 +139,11 @@ functions return a pointer to the templa .Dv NULL on failure. The -.Fn mkstemp -and +.Fn mkstemp , +.Fn mkostemp .Fn mkstemps +and +.Fn mkostemps functions return \-1 if no suitable file could be created. If either call fails an error code is placed in the global variable @@ -120,7 +151,9 @@ If either call fails an error code is pl .Sh ERRORS The .Fn mkstemp , -.Fn mkstemps +.Fn mkostemp , +.Fn mkstemps , +.Fn mkostemps and .Fn mkdtemp functions @@ -133,8 +166,25 @@ The pathname portion of the template is .El .Pp The +.Fn mkostemp +and +.Fn mkostemps +functions +may also set +.Va errno +to the following value: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa oflags +argument is invalid. +.El +.Pp +The .Fn mkstemp , -.Fn mkstemps +.Fn mkostemp , +.Fn mkstemps , +.Fn mkostemps and .Fn mkdtemp functions @@ -145,9 +195,11 @@ to any value specified by the function. .Pp The -.Fn mkstemp -and +.Fn mkstemp , +.Fn mkostemp , .Fn mkstemps +and +.Fn mkostemps functions may also set .Va errno @@ -209,8 +261,11 @@ function is expected to conform to and is not specified by .St -p1003.1-2008 . The +.Fn mkostemp , .Fn mkstemps -function does not conform to any standard. +and +.Fn mkostemps +functions do not conform to any standard. .Sh HISTORY A .Fn mktemp @@ -232,6 +287,12 @@ function first appeared in .Ox 2.4 , and later in .Fx 3.4 . +The +.Fn mkostemp +and +.Fn mkostemps +functions appeared in +.Fx 10.0 . .Sh BUGS This family of functions produces filenames which can be guessed, though the risk is minimized when large numbers of @@ -248,6 +309,8 @@ and opening it for use particularly dangerous from a security perspective. Whenever it is possible, .Fn mkstemp +or +.Fn mkostemp should be used instead, since it does not have the race condition. If .Fn mkstemp Modified: head/lib/libc/stdio/mktemp.c ============================================================================== --- head/lib/libc/stdio/mktemp.c Fri Aug 9 16:43:50 2013 (r254150) +++ head/lib/libc/stdio/mktemp.c Fri Aug 9 17:24:23 2013 (r254151) @@ -47,17 +47,33 @@ __FBSDID("$FreeBSD$"); char *_mktemp(char *); -static int _gettemp(char *, int *, int, int); +static int _gettemp(char *, int *, int, int, int); static const unsigned char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; int +mkostemps(char *path, int slen, int oflags) +{ + int fd; + + return (_gettemp(path, &fd, 0, slen, oflags) ? fd : -1); +} + +int mkstemps(char *path, int slen) { int fd; - return (_gettemp(path, &fd, 0, slen) ? fd : -1); + return (_gettemp(path, &fd, 0, slen, 0) ? fd : -1); +} + +int +mkostemp(char *path, int oflags) +{ + int fd; + + return (_gettemp(path, &fd, 0, 0, oflags) ? fd : -1); } int @@ -65,19 +81,19 @@ mkstemp(char *path) { int fd; - return (_gettemp(path, &fd, 0, 0) ? fd : -1); + return (_gettemp(path, &fd, 0, 0, 0) ? fd : -1); } char * mkdtemp(char *path) { - return (_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL); + return (_gettemp(path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL); } char * _mktemp(char *path) { - return (_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL); + return (_gettemp(path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL); } __warn_references(mktemp, @@ -90,7 +106,7 @@ mktemp(char *path) } static int -_gettemp(char *path, int *doopen, int domkdir, int slen) +_gettemp(char *path, int *doopen, int domkdir, int slen, int oflags) { char *start, *trv, *suffp, *carryp; char *pad; @@ -99,7 +115,9 @@ _gettemp(char *path, int *doopen, int do uint32_t rand; char carrybuf[MAXPATHLEN]; - if ((doopen != NULL && domkdir) || slen < 0) { + if ((doopen != NULL && domkdir) || slen < 0 || + (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC | + O_CLOEXEC)) != 0) { errno = EINVAL; return (0); } @@ -151,7 +169,8 @@ _gettemp(char *path, int *doopen, int do for (;;) { if (doopen) { if ((*doopen = - _open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + _open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600)) >= + 0) return (1); if (errno != EEXIST) return (0); Modified: head/tools/regression/lib/libc/stdio/Makefile ============================================================================== --- head/tools/regression/lib/libc/stdio/Makefile Fri Aug 9 16:43:50 2013 (r254150) +++ head/tools/regression/lib/libc/stdio/Makefile Fri Aug 9 17:24:23 2013 (r254151) @@ -1,8 +1,8 @@ # $FreeBSD$ -TESTS= test-fmemopen test-getdelim test-open_memstream test-open_wmemstream \ - test-perror test-print-positional test-printbasic test-printfloat \ - test-scanfloat +TESTS= test-fmemopen test-getdelim test-mkostemp test-open_memstream \ + test-open_wmemstream test-perror test-print-positional test-printbasic \ + test-printfloat test-scanfloat CFLAGS+= -lm .PHONY: tests Added: head/tools/regression/lib/libc/stdio/test-mkostemp.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/lib/libc/stdio/test-mkostemp.c Fri Aug 9 17:24:23 2013 (r254151) @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 2013 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test program for mkostemp(). + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include + +static const char template[] = _PATH_TMP "mkostemp.XXXXXXXX"; +static int testnum; + +#define MISCFLAGS (O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC) + +static void +test_one(int oflags) +{ + char tmpf[sizeof(template)]; + struct stat st1, st2; + int fd; + + memcpy(tmpf, template, sizeof(tmpf)); + fd = mkostemp(tmpf, oflags); + if (fd < 0) { + printf("not ok %d - oflags=%#x " + "mkostemp() reported failure: %s\n", + testnum++, oflags, strerror(errno)); + return; + } + if (memcmp(tmpf, template, sizeof(tmpf) - 8 - 1) != 0) { + printf("not ok %d - oflags=%#x " + "returned pathname does not match template: %s\n", + testnum++, oflags, tmpf); + return; + } + do { + if (fcntl(fd, F_GETFD) != + (oflags & O_CLOEXEC ? FD_CLOEXEC : 0)) { + printf("not ok %d - oflags=%#x " + "close-on-exec flag incorrect\n", + testnum++, oflags); + break; + } + if ((fcntl(fd, F_GETFL) & MISCFLAGS) != (oflags & MISCFLAGS)) { + printf("not ok %d - oflags=%#x " + "open flags incorrect\n", + testnum++, oflags); + break; + } + if (stat(tmpf, &st1) == -1) { + printf("not ok %d - oflags=%#x " + "cannot stat returned pathname %s: %s\n", + testnum++, oflags, tmpf, strerror(errno)); + break; + } + if (fstat(fd, &st2) == -1) { + printf("not ok %d - oflags=%#x " + "cannot fstat returned fd %d: %s\n", + testnum++, oflags, fd, strerror(errno)); + break; + } + if (!S_ISREG(st1.st_mode) || (st1.st_mode & 0777) != 0600 || + st1.st_nlink != 1 || st1.st_size != 0) { + printf("not ok %d - oflags=%#x " + "named file attributes incorrect\n", + testnum++, oflags); + break; + } + if (!S_ISREG(st2.st_mode) || (st2.st_mode & 0777) != 0600 || + st2.st_nlink != 1 || st2.st_size != 0) { + printf("not ok %d - oflags=%#x " + "opened file attributes incorrect\n", + testnum++, oflags); + break; + } + if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { + printf("not ok %d - oflags=%#x " + "named and opened file do not match\n", + testnum++, oflags); + break; + } + (void)unlink(tmpf); + if (fstat(fd, &st2) == -1) + printf("not ok %d - oflags=%#x " + "cannot fstat returned fd %d again: %s\n", + testnum++, oflags, fd, strerror(errno)); + else if (st2.st_nlink != 0) + printf("not ok %d - oflags=%#x " + "st_nlink is not 0 after unlink\n", + testnum++, oflags); + else + printf("ok %d - oflags=%#x\n", testnum++, oflags); + (void)close(fd); + return; + } while (0); + (void)close(fd); + (void)unlink(tmpf); +} + +static void +test_badflags(void) +{ + char tmpf[sizeof(template)]; + + memcpy(tmpf, template, sizeof(tmpf)); + if (mkostemp(tmpf, O_CREAT) == -1) + printf("ok %d - mkostemp(O_CREAT) correctly failed\n", + testnum++); + else + printf("not ok %d - mkostemp(O_CREAT) wrongly succeeded\n", + testnum++); +} + +int +main(int argc, char *argv[]) +{ + int i; + const char *e; + + printf("1..5\n"); + testnum = 1; + + test_one(0); + test_one(O_CLOEXEC); + test_one(O_APPEND); + test_one(O_APPEND | O_CLOEXEC); + test_badflags(); + + return (0); +}