Subject: bug#15015: Fix some minor races in hosts lacking mkostemp

From: Paul Eggert <[email-masked]>
Date: Sat, 03 Aug 2013 00:40:05 -0700

Tags: patch

Here's a proposed patch to fix some minor races in hosts lacking mkostemp.
I've tested this on Fedora 17 and Solaris 9.  Eli recently wrote that he
didn't think it was feasible to close the races on Microsoft platforms,
so I'm posting this on bug-gnu-emacs first (with a CC: to Eli to give him
a heads-up).  It looks to me like it may close the races on Microsoft platforms,
at least if they support O_EXCL, and at any rate I hope it doesn't hurt
on those platforms.

Most of this patch consists of code copied automatically from Gnulib.
The meat of the patch is in src/callproc.c and src/filelock.c.

=== modified file 'ChangeLog'
--- ChangeLog	2013-07-29 11:35:16 +0000
+++ ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,12 @@
+2013-08-03  Paul Eggert  <[email-masked]>
+
+	Fix some minor races in hosts lacking mkostemp.
+	Gnulib's emulation of mkostemp doesn't have races that Emacs's does.
+	* lib/mkostemp.c, lib/secure_getenv.c, lib/tempname.c, lib/tempname.h:
+	* m4/mkostemp.m4, m4/secure_getenv.m4, m4/tempname.m4:
+	New files, copied from Gnulib.
+	* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 2013-07-29  Michael Albinus  <[email-masked]>
 
 	* INSTALL (DETAILED BUILDING AND INSTALLATION): Add

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog	2013-07-12 06:45:04 +0000
+++ admin/ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,8 @@
+2013-08-03  Paul Eggert  <[email-masked]>
+
+	Using Gnulib's mkostemp module.
+	* merge-gnulib (GNULIB_MODULES): Add mkostemp.
+
 2013-07-12  Glenn Morris  <[email-masked]>
 
 	* admin.el (manual-style-string): Use non-abbreviated url.

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib	2013-07-09 17:16:21 +0000
+++ admin/merge-gnulib	2013-08-03 07:19:27 +0000
@@ -32,7 +32,7 @@
   fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
   getloadavg getopt-gnu gettime gettimeofday
   intprops largefile lstat
-  manywarnings memrchr mktime
+  manywarnings memrchr mkostemp mktime
   pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
   sig2str socklen stat-time stdalign stdarg stdbool stdio
   strftime strtoimax strtoumax symlink sys_stat

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk	2013-07-09 17:16:21 +0000
+++ lib/gnulib.mk	2013-08-03 07:19:27 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_tim
 e time ti
mer-time timespec-add timespec-sub unsetenv utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_sta
 t sys_tim
e time timer-time timespec-add timespec-sub unsetenv utimens warnings

 MOSTLYCLEANFILES += core *.stackdump
@@ -560,6 +560,15 @@
 
 ## end   gnulib module memrchr
 
+## begin gnulib module mkostemp
+
+
+EXTRA_DIST += mkostemp.c
+
+EXTRA_libgnu_a_SOURCES += mkostemp.c
+
+## end   gnulib module mkostemp
+
 ## begin gnulib module mktime

@@ -657,6 +666,17 @@
 
 ## end   gnulib module root-uid
 
+## begin gnulib module secure_getenv
+
+if gl_GNULIB_ENABLED_secure_getenv
+
+endif
+EXTRA_DIST += secure_getenv.c
+
+EXTRA_libgnu_a_SOURCES += secure_getenv.c
+
+## end   gnulib module secure_getenv
+
 ## begin gnulib module sig2str

@@ -1480,6 +1500,16 @@
 
 ## end   gnulib module sys_time
 
+## begin gnulib module tempname
+
+if gl_GNULIB_ENABLED_tempname
+libgnu_a_SOURCES += tempname.c
+
+endif
+EXTRA_DIST += tempname.h
+
+## end   gnulib module tempname
+
 ## begin gnulib module time
 
 BUILT_SOURCES += time.h

=== added file 'lib/mkostemp.c'
--- lib/mkostemp.c	1970-01-01 00:00:00 +0000
+++ lib/mkostemp.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,46 @@
+/* Copyright (C) 1998-1999, 2001, 2005-2007, 2009-2013 Free Software
+   Foundation, Inc.
+   This file is derived from the one in the GNU C Library.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#if !_LIBC
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#if !_LIBC
+# include "tempname.h"
+# define __gen_tempname gen_tempname
+# ifndef __GTFILE
+#  define __GT_FILE GT_FILE
+# endif
+#endif
+
+#include <stdio.h>
+
+#ifndef __GT_FILE
+# define __GT_FILE 0
+#endif
+
+/* Generate a unique temporary file name from XTEMPLATE.
+   The last six characters of XTEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the file name unique.
+   Then open the file and return a fd. */
+int
+mkostemp (char *xtemplate, int flags)
+{
+  return __gen_tempname (xtemplate, 0, flags, __GT_FILE);
+}

=== added file 'lib/secure_getenv.c'
--- lib/secure_getenv.c	1970-01-01 00:00:00 +0000
+++ lib/secure_getenv.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,41 @@
+/* Look up an environment variable more securely.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#if !HAVE___SECURE_GETENV
+# if HAVE_ISSETUGID
+#  include <unistd.h>
+# else
+#  undef issetugid
+#  define issetugid() 1
+# endif
+#endif
+
+char *
+secure_getenv (char const *name)
+{
+#if HAVE___SECURE_GETENV
+  return __secure_getenv (name);
+#else
+  if (issetugid ())
+    return 0;
+  return getenv (name);
+#endif
+}

=== added file 'lib/tempname.c'
--- lib/tempname.c	1970-01-01 00:00:00 +0000
+++ lib/tempname.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,306 @@
+/* tempname.c - generate the name of a temporary file.
+
+   Copyright (C) 1991-2003, 2005-2007, 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Extracted from glibc sysdeps/posix/tempname.c.  See also tmpdir.c.  */
+
+#if !_LIBC
+# include <config.h>
+# include "tempname.h"
+#endif
+
+#include <sys/types.h>
+#include <assert.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <stdio.h>
+#ifndef P_tmpdir
+# define P_tmpdir "/tmp"
+#endif
+#ifndef TMP_MAX
+# define TMP_MAX 238328
+#endif
+#ifndef __GT_FILE
+# define __GT_FILE      0
+# define __GT_DIR       1
+# define __GT_NOCREATE  2
+#endif
+#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR       \
+               || GT_NOCREATE != __GT_NOCREATE)
+# error report this to [email-masked]
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+
+#if _LIBC
+# define struct_stat64 struct stat64
+#else
+# define struct_stat64 struct stat
+# define __gen_tempname gen_tempname
+# define __getpid getpid
+# define __gettimeofday gettimeofday
+# define __mkdir mkdir
+# define __open open
+# define __lxstat64(version, file, buf) lstat (file, buf)
+# define __secure_getenv secure_getenv
+#endif
+
+#ifdef _LIBC
+# include <hp-timing.h>
+# if HP_TIMING_AVAIL
+#  define RANDOM_BITS(Var) \
+  if (__builtin_expect (value == UINT64_C (0), 0))                            \
+    {                                                                         \
+      /* If this is the first time this function is used initialize           \
+         the variable we accumulate the value in to some somewhat             \
+         random value.  If we'd not do this programs at startup time          \
+         might have a reduced set of possible names, at least on slow         \
+         machines.  */                                                        \
+      struct timeval tv;                                                      \
+      __gettimeofday (&tv, NULL);                                             \
+      value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;                      \
+    }                                                                         \
+  HP_TIMING_NOW (Var)
+# endif
+#endif
+
+/* Use the widest available unsigned type if uint64_t is not
+   available.  The algorithm below extracts a number less than 62**6
+   (approximately 2**35.725) from uint64_t, so ancient hosts where
+   uintmax_t is only 32 bits lose about 3.725 bits of randomness,
+   which is better than not having mkstemp at all.  */
+#if !defined UINT64_MAX && !defined uint64_t
+# define uint64_t uintmax_t
+#endif
+
+#if _LIBC
+/* Return nonzero if DIR is an existent directory.  */
+static int
+direxists (const char *dir)
+{
+  struct_stat64 buf;
+  return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
+   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
+   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
+   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
+   doesn't exist, none of the searched dirs exists, or there's not
+   enough space in TMPL. */
+int
+__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
+               int try_tmpdir)
+{
+  const char *d;
+  size_t dlen, plen;
+
+  if (!pfx || !pfx[0])
+    {
+      pfx = "file";
+      plen = 4;
+    }
+  else
+    {
+      plen = strlen (pfx);
+      if (plen > 5)
+        plen = 5;
+    }
+
+  if (try_tmpdir)
+    {
+      d = __secure_getenv ("TMPDIR");
+      if (d != NULL && direxists (d))
+        dir = d;
+      else if (dir != NULL && direxists (dir))
+        /* nothing */ ;
+      else
+        dir = NULL;
+    }
+  if (dir == NULL)
+    {
+      if (direxists (P_tmpdir))
+        dir = P_tmpdir;
+      else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
+        dir = "/tmp";
+      else
+        {
+          __set_errno (ENOENT);
+          return -1;
+        }
+    }
+
+  dlen = strlen (dir);
+  while (dlen > 1 && dir[dlen - 1] == '/')
+    dlen--;                     /* remove trailing slashes */
+
+  /* check we have room for "${dir}/${pfx}XXXXXX\0" */
+  if (tmpl_len < dlen + 1 + plen + 6 + 1)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
+  return 0;
+}
+#endif /* _LIBC */
+
+/* These are the characters used in temporary file names.  */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix).
+   The name constructed does not exist at the time of the call to
+   __gen_tempname.  TMPL is overwritten with the result.
+
+   KIND may be one of:
+   __GT_NOCREATE:       simply verify that the name does not exist
+                        at the time of the call.
+   __GT_FILE:           create the file using open(O_CREAT|O_EXCL)
+                        and return a read-write fd.  The file is mode 0600.
+   __GT_DIR:            create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+int
+__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
+{
+  int len;
+  char *XXXXXX;
+  static uint64_t value;
+  uint64_t random_time_bits;
+  unsigned int count;
+  int fd = -1;
+  int save_errno = errno;
+  struct_stat64 st;
+
+  /* A lower bound on the number of temporary files to attempt to
+     generate.  The maximum total number of temporary file names that
+     can exist for a given template is 62**6.  It should never be
+     necessary to try all of these combinations.  Instead if a reasonable
+     number of names is tried (we define reasonable as 62**3) fail to
+     give the system administrator the chance to remove the problems.  */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+  /* The number of times to attempt to generate a temporary file.  To
+     conform to POSIX, this must be no smaller than TMP_MAX.  */
+#if ATTEMPTS_MIN < TMP_MAX
+  unsigned int attempts = TMP_MAX;
+#else
+  unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+  len = strlen (tmpl);
+  if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* This is where the Xs start.  */
+  XXXXXX = &tmpl[len - 6 - suffixlen];
+
+  /* Get some more or less random data.  */
+#ifdef RANDOM_BITS
+  RANDOM_BITS (random_time_bits);
+#else
+  {
+    struct timeval tv;
+    __gettimeofday (&tv, NULL);
+    random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+  }
+#endif
+  value += random_time_bits ^ __getpid ();
+
+  for (count = 0; count < attempts; value += 7777, ++count)
+    {
+      uint64_t v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % 62];
+      v /= 62;
+      XXXXXX[1] = letters[v % 62];
+      v /= 62;
+      XXXXXX[2] = letters[v % 62];
+      v /= 62;
+      XXXXXX[3] = letters[v % 62];
+      v /= 62;
+      XXXXXX[4] = letters[v % 62];
+      v /= 62;
+      XXXXXX[5] = letters[v % 62];
+
+      switch (kind)
+        {
+        case __GT_FILE:
+          fd = __open (tmpl,
+                       (flags & ~O_ACCMODE)
+                       | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+          break;
+
+        case __GT_DIR:
+          fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+          break;
+
+        case __GT_NOCREATE:
+          /* This case is backward from the other three.  __gen_tempname
+             succeeds if __xstat fails because the name does not exist.
+             Note the continue to bypass the common logic at the bottom
+             of the loop.  */
+          if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
+            {
+              if (errno == ENOENT)
+                {
+                  __set_errno (save_errno);
+                  return 0;
+                }
+              else
+                /* Give up now. */
+                return -1;
+            }
+          continue;
+
+        default:
+          assert (! "invalid KIND in __gen_tempname");
+          abort ();
+        }
+
+      if (fd >= 0)
+        {
+          __set_errno (save_errno);
+          return fd;
+        }
+      else if (errno != EEXIST)
+        return -1;
+    }
+
+  /* We got out of the loop because we ran out of combinations to try.  */
+  __set_errno (EEXIST);
+  return -1;
+}

=== added file 'lib/tempname.h'
--- lib/tempname.h	1970-01-01 00:00:00 +0000
+++ lib/tempname.h	2013-08-03 07:19:27 +0000
@@ -0,0 +1,50 @@
+/* Create a temporary file or directory.
+
+   Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* header written by Eric Blake */
+
+#ifndef GL_TEMPNAME_H
+# define GL_TEMPNAME_H
+
+# include <stdio.h>
+
+# ifdef __GT_FILE
+#  define GT_FILE     __GT_FILE
+#  define GT_DIR      __GT_DIR
+#  define GT_NOCREATE __GT_NOCREATE
+# else
+#  define GT_FILE     0
+#  define GT_DIR      1
+#  define GT_NOCREATE 2
+# endif
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix).
+   The name constructed does not exist at the time of the call to
+   gen_tempname.  TMPL is overwritten with the result.
+
+   KIND may be one of:
+   GT_NOCREATE:         simply verify that the name does not exist
+                        at the time of the call.
+   GT_FILE:             create a large file using open(O_CREAT|O_EXCL)
+                        and return a read-write fd.  The file is mode 0600.
+   GT_DIR:              create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind);
+
+#endif /* GL_TEMPNAME_H */

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4	2013-07-09 17:16:21 +0000
+++ m4/gnulib-comp.m4	2013-08-03 07:19:27 +0000
@@ -89,6 +89,7 @@
   # Code from module lstat:
   # Code from module manywarnings:
   # Code from module memrchr:
+  # Code from module mkostemp:
   # Code from module mktime:
   # Code from module multiarch:
   # Code from module nocrash:
@@ -102,6 +103,7 @@
   # Code from module readlink:
   # Code from module readlinkat:
   # Code from module root-uid:
+  # Code from module secure_getenv:
   # Code from module sig2str:
   # Code from module signal-h:
   # Code from module snippet/_Noreturn:
@@ -134,6 +136,7 @@
   # Code from module sys_select:
   # Code from module sys_stat:
   # Code from module sys_time:
+  # Code from module tempname:
   # Code from module time:
   # Code from module time_r:
   # Code from module timer-time:
@@ -274,6 +277,13 @@
     gl_PREREQ_MEMRCHR
   fi
   gl_STRING_MODULE_INDICATOR([memrchr])
+  gl_FUNC_MKOSTEMP
+  if test $HAVE_MKOSTEMP = 0; then
+    AC_LIBOBJ([mkostemp])
+    gl_PREREQ_MKOSTEMP
+  fi
+  gl_MODULE_INDICATOR([mkostemp])
+  gl_STDLIB_MODULE_INDICATOR([mkostemp])
   gl_FUNC_MKTIME
   if test $REPLACE_MKTIME = 1; then
     AC_LIBOBJ([mktime])
@@ -381,9 +391,11 @@
   gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false
   gl_gnulib_enabled_pathmax=false
   gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
+  gl_gnulib_enabled_secure_getenv=false
   gl_gnulib_enabled_stat=false
   gl_gnulib_enabled_strtoll=false
   gl_gnulib_enabled_strtoull=false
+  gl_gnulib_enabled_tempname=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
   func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
   {
@@ -485,6 +497,18 @@
       gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true
     fi
   }
+  func_gl_gnulib_m4code_secure_getenv ()
+  {
+    if ! $gl_gnulib_enabled_secure_getenv; then
+      gl_FUNC_SECURE_GETENV
+      if test $HAVE_SECURE_GETENV = 0; then
+        AC_LIBOBJ([secure_getenv])
+        gl_PREREQ_SECURE_GETENV
+      fi
+      gl_STDLIB_MODULE_INDICATOR([secure_getenv])
+      gl_gnulib_enabled_secure_getenv=true
+    fi
+  }
   func_gl_gnulib_m4code_stat ()
   {
     if ! $gl_gnulib_enabled_stat; then
@@ -527,6 +551,14 @@
       gl_gnulib_enabled_strtoull=true
     fi
   }
+  func_gl_gnulib_m4code_tempname ()
+  {
+    if ! $gl_gnulib_enabled_tempname; then
+      gl_FUNC_GEN_TEMPNAME
+      gl_gnulib_enabled_tempname=true
+      func_gl_gnulib_m4code_secure_getenv
+    fi
+  }
   func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
   {
     if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -569,6 +601,9 @@
   if test $REPLACE_LSTAT = 1; then
     func_gl_gnulib_m4code_stat
   fi
+  if test $HAVE_MKOSTEMP = 0; then
+    func_gl_gnulib_m4code_tempname
+  fi
   if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
     func_gl_gnulib_m4code_stat
   fi
@@ -598,9 +633,11 @@
   AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_secure_getenv], [$gl_gnulib_enabled_secure_getenv])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_tempname], [$gl_gnulib_enabled_tempname])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
@@ -806,6 +843,7 @@
   lib/md5.c
   lib/md5.h
   lib/memrchr.c
+  lib/mkostemp.c
   lib/mktime-internal.h
   lib/mktime.c
   lib/openat-priv.h
@@ -821,6 +859,7 @@
   lib/readlink.c
   lib/readlinkat.c
   lib/root-uid.h
+  lib/secure_getenv.c
   lib/sha1.c
   lib/sha1.h
   lib/sha256.c
@@ -853,6 +892,8 @@
   lib/sys_select.in.h
   lib/sys_stat.in.h
   lib/sys_time.in.h
+  lib/tempname.c
+  lib/tempname.h
   lib/time.in.h
   lib/time_r.c
   lib/timespec-add.c
@@ -908,6 +949,7 @@
   m4/manywarnings.m4
   m4/md5.m4
   m4/memrchr.m4
+  m4/mkostemp.m4
   m4/mktime.m4
   m4/multiarch.m4
   m4/nocrash.m4
@@ -919,6 +961,7 @@
   m4/putenv.m4
   m4/readlink.m4
   m4/readlinkat.m4
+  m4/secure_getenv.m4
   m4/setenv.m4
   m4/sha1.m4
   m4/sha256.m4
@@ -948,6 +991,7 @@
   m4/sys_socket_h.m4
   m4/sys_stat_h.m4
   m4/sys_time_h.m4
+  m4/tempname.m4
   m4/time_h.m4
   m4/time_r.m4
   m4/timer_time.m4

=== added file 'm4/mkostemp.m4'
--- m4/mkostemp.m4	1970-01-01 00:00:00 +0000
+++ m4/mkostemp.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,23 @@
+# mkostemp.m4 serial 2
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MKOSTEMP],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+
+  dnl Persuade glibc <stdlib.h> to declare mkostemp().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([mkostemp])
+  if test $ac_cv_func_mkostemp != yes; then
+    HAVE_MKOSTEMP=0
+  fi
+])
+
+# Prerequisites of lib/mkostemp.c.
+AC_DEFUN([gl_PREREQ_MKOSTEMP],
+[
+])

=== added file 'm4/secure_getenv.m4'
--- m4/secure_getenv.m4	1970-01-01 00:00:00 +0000
+++ m4/secure_getenv.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,25 @@
+# Look up an environment variable more securely.
+dnl Copyright 2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_SECURE_GETENV],
+[
+  dnl Persuade glibc <stdlib.h> to declare secure_getenv().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([secure_getenv])
+  if test $ac_cv_func_secure_getenv = no; then
+    HAVE_SECURE_GETENV=0
+  fi
+])
+
+# Prerequisites of lib/secure_getenv.c.
+AC_DEFUN([gl_PREREQ_SECURE_GETENV], [
+  AC_CHECK_FUNCS([__secure_getenv])
+  if test $ac_cv_func___secure_getenv = no; then
+    AC_CHECK_FUNCS([issetugid])
+  fi
+])

=== added file 'm4/tempname.m4'
--- m4/tempname.m4	1970-01-01 00:00:00 +0000
+++ m4/tempname.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,19 @@
+#serial 5
+
+# Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# glibc provides __gen_tempname as a wrapper for mk[ds]temp.  Expose
+# it as a public API, and provide it on systems that are lacking.
+AC_DEFUN([gl_FUNC_GEN_TEMPNAME],
+[
+  gl_PREREQ_TEMPNAME
+])
+
+# Prerequisites of lib/tempname.c.
+AC_DEFUN([gl_PREREQ_TEMPNAME],
+[
+  :
+])

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2013-08-03 03:29:03 +0000
+++ src/ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,10 @@
+2013-08-03  Paul Eggert  <[email-masked]>
+
+	Fix some minor races in hosts lacking mkostemp.
+	* callproc.c (create_temp_file):
+	* filelock.c (create_lock_file):
+	Assume mkostemp, since it's now provided by Gnulib.
+
 2013-08-03  Dmitry Antipov  <[email-masked]>
 
 	Drop FRAME_PTR typedef.

=== modified file 'src/callproc.c'
--- src/callproc.c	2013-07-30 21:44:43 +0000
+++ src/callproc.c	2013-08-03 07:19:27 +0000
@@ -1009,23 +1009,11 @@
     tempfile = SSDATA (filename_string);
 
     {
-      int fd;
-
-#ifdef HAVE_MKOSTEMP
-      fd = mkostemp (tempfile, O_CLOEXEC);
-#elif defined HAVE_MKSTEMP
-      fd = mkstemp (tempfile);
-#else
-      errno = EEXIST;
-      mktemp (tempfile);
-      fd = *tempfile ? 0 : -1;
-#endif
+      int fd = mkostemp (tempfile, O_CLOEXEC);
       if (fd < 0)
 	report_file_error ("Failed to open temporary file using pattern",
 			   pattern);
-#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP
       emacs_close (fd);
-#endif
     }
 
     record_unwind_protect (delete_temp_file, filename_string);

=== modified file 'src/filelock.c'
--- src/filelock.c	2013-07-19 18:09:23 +0000
+++ src/filelock.c	2013-08-03 07:35:27 +0000
@@ -411,28 +411,14 @@
       memcpy (nonce, lfname, lfdirlen);
       strcpy (nonce + lfdirlen, nonce_base);
 
-#if HAVE_MKOSTEMP
-      /* Prefer mkostemp to mkstemp, as it avoids a window where FD is
-	 temporarily open without close-on-exec.  */
       fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
-#elif HAVE_MKSTEMP
-      /* Prefer mkstemp to mktemp, as it avoids a race between
-	 mktemp and emacs_open.  */
-      fd = mkstemp (nonce);
-#else
-      mktemp (nonce);
-      fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
-		       S_IRUSR | S_IWUSR);
-#endif
-
       if (fd < 0)
 	err = errno;
       else
 	{
 	  ptrdiff_t lock_info_len;
-#if ! (HAVE_MKOSTEMP && O_CLOEXEC)
-	  fcntl (fd, F_SETFD, FD_CLOEXEC);
-#endif
+	  if (! O_CLOEXEC)
+	    fcntl (fd, F_SETFD, FD_CLOEXEC);
 	  lock_info_len = strlen (lock_info_str);
 	  err = 0;
 	  /* Use 'write', not 'emacs_write', as garbage collection