Enhance get_tmpfile() and add get_tmppath()

Move all the logic on creating temporary files into misc.c, and add
a new function get_tmppath() that returns the pathname to a temporary
file without creating or opening it.

* src/makeint.h: Add a declaration for get_tmppath().  Remove the
template argument from get_tmpfile(): it will compute its own.
* src/main.c (main): Remove the logic for computing templates.
* src/vmsjobs.c (child_execute_job): Ditto.
* src/misc.c (get_tmptemplate): New function to return an allocated
template string for use with various mktemp-style functions.
(get_tmppath): Return an allocated path to a temporary file, but do
not create it.  Generally this should be avoided due to TOCTOU issues.
(get_tmpfile): Use get_tmptemplate() to generate a template rather
than using one passed in.  If we don't have mkstemp() then use
get_tmppath() to compute the path of a temp file.
This commit is contained in:
Paul Smith 2022-08-01 12:57:12 -04:00
parent 07eea3aa49
commit 09cce75c30
4 changed files with 77 additions and 55 deletions

View file

@ -1813,48 +1813,13 @@ main (int argc, char **argv, char **envp)
and thus re-read the makefiles, we read standard input
into a temporary file and read from that. */
FILE *outfile;
char *template;
char *newnm;
const char *tmpdir;
if (stdin_offset >= 0)
O (fatal, NILF,
_("Makefile from standard input specified twice"));
#ifdef VMS
# define DEFAULT_TMPDIR "/sys$scratch/"
#else
# ifdef P_tmpdir
# define DEFAULT_TMPDIR P_tmpdir
# else
# define DEFAULT_TMPDIR "/tmp"
# endif
#endif
#define DEFAULT_TMPFILE "GmXXXXXX"
if (
#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') &&
((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') &&
#endif
((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
tmpdir = DEFAULT_TMPDIR;
template = alloca (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2);
strcpy (template, tmpdir);
#ifdef HAVE_DOS_PATHS
if (strchr ("/\\", template[strlen (template) - 1]) == NULL)
strcat (template, "/");
#else
# ifndef VMS
if (template[strlen (template) - 1] != '/')
strcat (template, "/");
# endif /* !VMS */
#endif /* !HAVE_DOS_PATHS */
strcat (template, DEFAULT_TMPFILE);
outfile = get_tmpfile (&newnm, template);
outfile = get_tmpfile (&newnm);
if (outfile == 0)
OSS (fatal, NILF,
_("fopen: temporary file %s: %s"), newnm, strerror (errno));

View file

@ -546,7 +546,8 @@ int alpha_compare (const void *, const void *);
void print_spaces (unsigned int);
char *find_percent (char *);
const char *find_percent_cached (const char **);
FILE *get_tmpfile (char **, const char *);
char *get_tmppath ();
FILE *get_tmpfile (char **);
ssize_t writebuf (int, const void *, size_t);
ssize_t readbuf (int, void *, size_t);

View file

@ -505,8 +505,76 @@ umask (mode_t mask)
}
#endif
static char *
get_tmptemplate ()
{
const char *tmpdir;
char *template;
size_t len;
#ifdef VMS
# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
#else
# define DEFAULT_TMPFILE "GmXXXXXX"
#endif
#ifdef VMS
# define DEFAULT_TMPDIR "/sys$scratch/"
#else
# ifdef P_tmpdir
# define DEFAULT_TMPDIR P_tmpdir
# else
# define DEFAULT_TMPDIR "/tmp"
# endif
#endif
if (
#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') &&
((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') &&
#endif
((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
tmpdir = DEFAULT_TMPDIR;
len = strlen (tmpdir);
template = xmalloc (len + CSTRLEN (DEFAULT_TMPFILE) + 2);
strcpy (template, tmpdir);
#ifdef HAVE_DOS_PATHS
if (template[len - 1] != '/' && template[len - 1] != '\\')
strcat (template, "/");
#else
# ifndef VMS
if (template[len - 1] != '/')
strcat (template, "/");
# endif /* !VMS */
#endif /* !HAVE_DOS_PATHS */
strcat (template, DEFAULT_TMPFILE);
return template;
}
char *
get_tmppath ()
{
char *path;
#ifdef HAVE_MKTEMP
path = get_tmptemplate();
if (*mktemp (path) == '\0')
pfatal_with_name ("mktemp");
#else
path = xmalloc (L_tmpnam + 1);
if (tmpnam (path) == NULL)
pfatal_with_name ("tmpnam");
#endif
return path;
}
FILE *
get_tmpfile (char **name, const char *template)
get_tmpfile (char **name)
{
FILE *file;
#ifdef HAVE_FDOPEN
@ -516,15 +584,9 @@ get_tmpfile (char **name, const char *template)
/* Preserve the current umask, and set a restrictive one for temp files. */
mode_t mask = umask (0077);
#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP)
# define TEMPLATE_LEN strlen (template)
#else
# define TEMPLATE_LEN L_tmpnam
#endif
*name = xmalloc (TEMPLATE_LEN + 1);
strcpy (*name, template);
#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN)
*name = get_tmptemplate ();
/* It's safest to use mkstemp(), if we can. */
EINTRLOOP (fd, mkstemp (*name));
if (fd == -1)
@ -532,14 +594,10 @@ get_tmpfile (char **name, const char *template)
else
file = fdopen (fd, "w");
#else
# ifdef HAVE_MKTEMP
(void) mktemp (*name);
# else
(void) tmpnam (*name);
# endif
*name = get_tmppath ();
# ifdef HAVE_FDOPEN
/* Can't use mkstemp(), but guard against a race condition. */
/* Can't use mkstemp(), but try to guard against a race condition. */
EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
if (fd == -1)
return 0;

View file

@ -1241,9 +1241,7 @@ child_execute_job (struct childbase *child, int good_stdin UNUSED, char *argv)
FILE *outfile;
int cmd_len;
outfile = get_tmpfile (&child->comname,
"sys$scratch:gnv$make_cmdXXXXXX.com");
/* 123456789012345678901234567890 */
outfile = get_tmpfile (&child->comname);
if (outfile == 0)
pfatal_with_name (_("fopen (temporary file)"));
comnamelen = strlen (child->comname);