From 09cce75c308a6e7ae0f3635724d2ae87e72f9800 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 1 Aug 2022 12:57:12 -0400 Subject: [PATCH] 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. --- src/main.c | 37 +--------------------- src/makeint.h | 3 +- src/misc.c | 88 ++++++++++++++++++++++++++++++++++++++++++--------- src/vmsjobs.c | 4 +-- 4 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/main.c b/src/main.c index e3658f05..723325df 100644 --- a/src/main.c +++ b/src/main.c @@ -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)); diff --git a/src/makeint.h b/src/makeint.h index e711a3c8..737f6a0e 100644 --- a/src/makeint.h +++ b/src/makeint.h @@ -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); diff --git a/src/misc.c b/src/misc.c index 0e889647..fa0669ad 100644 --- a/src/misc.c +++ b/src/misc.c @@ -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; diff --git a/src/vmsjobs.c b/src/vmsjobs.c index ef4ed064..e3226acf 100644 --- a/src/vmsjobs.c +++ b/src/vmsjobs.c @@ -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);