198b9484cSchristos /* Utility to pick a temporary filename prefix. 2*889f3bb0Schristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 398b9484cSchristos 498b9484cSchristos This file is part of the libiberty library. 598b9484cSchristos Libiberty is free software; you can redistribute it and/or 698b9484cSchristos modify it under the terms of the GNU Library General Public 798b9484cSchristos License as published by the Free Software Foundation; either 898b9484cSchristos version 2 of the License, or (at your option) any later version. 998b9484cSchristos 1098b9484cSchristos Libiberty is distributed in the hope that it will be useful, 1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1398b9484cSchristos Library General Public License for more details. 1498b9484cSchristos 1598b9484cSchristos You should have received a copy of the GNU Library General Public 1698b9484cSchristos License along with libiberty; see the file COPYING.LIB. If not, 1798b9484cSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 1898b9484cSchristos Boston, MA 02110-1301, USA. */ 1998b9484cSchristos 2098b9484cSchristos #ifdef HAVE_CONFIG_H 2198b9484cSchristos #include "config.h" 2298b9484cSchristos #endif 2398b9484cSchristos 2498b9484cSchristos #include <stdio.h> /* May get P_tmpdir. */ 2598b9484cSchristos #include <sys/types.h> 2698b9484cSchristos #include <errno.h> 2798b9484cSchristos #ifdef HAVE_UNISTD_H 2898b9484cSchristos #include <unistd.h> 2998b9484cSchristos #endif 3098b9484cSchristos #ifdef HAVE_STDLIB_H 3198b9484cSchristos #include <stdlib.h> 3298b9484cSchristos #endif 3398b9484cSchristos #ifdef HAVE_STRING_H 3498b9484cSchristos #include <string.h> 3598b9484cSchristos #endif 3698b9484cSchristos #ifdef HAVE_SYS_FILE_H 3798b9484cSchristos #include <sys/file.h> /* May get R_OK, etc. on some systems. */ 3898b9484cSchristos #endif 3998b9484cSchristos #if defined(_WIN32) && !defined(__CYGWIN__) 40*889f3bb0Schristos #define WIN32_LEAN_AND_MEAN 4198b9484cSchristos #include <windows.h> 4298b9484cSchristos #endif 43924795e6Schristos #if HAVE_SYS_STAT_H 44924795e6Schristos #include <sys/stat.h> 45924795e6Schristos #endif 46924795e6Schristos 4798b9484cSchristos 4898b9484cSchristos #ifndef R_OK 4998b9484cSchristos #define R_OK 4 5098b9484cSchristos #define W_OK 2 5198b9484cSchristos #define X_OK 1 5298b9484cSchristos #endif 5398b9484cSchristos 5498b9484cSchristos #include "libiberty.h" 5598b9484cSchristos extern int mkstemps (char *, int); 5698b9484cSchristos 5798b9484cSchristos /* '/' works just fine on MS-DOS based systems. */ 5898b9484cSchristos #ifndef DIR_SEPARATOR 5998b9484cSchristos #define DIR_SEPARATOR '/' 6098b9484cSchristos #endif 6198b9484cSchristos 6298b9484cSchristos /* Name of temporary file. 6398b9484cSchristos mktemp requires 6 trailing X's. */ 64314094e7Schristos #define TEMP_FILE "XXXXXX" 6598b9484cSchristos #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) 6698b9484cSchristos 6798b9484cSchristos #if !defined(_WIN32) || defined(__CYGWIN__) 6898b9484cSchristos 6998b9484cSchristos /* Subroutine of choose_tmpdir. 7098b9484cSchristos If BASE is non-NULL, return it. 7198b9484cSchristos Otherwise it checks if DIR is a usable directory. 7298b9484cSchristos If success, DIR is returned. 7398b9484cSchristos Otherwise NULL is returned. */ 7498b9484cSchristos 7598b9484cSchristos static inline const char *try_dir (const char *, const char *); 7698b9484cSchristos 7798b9484cSchristos static inline const char * 7898b9484cSchristos try_dir (const char *dir, const char *base) 7998b9484cSchristos { 8098b9484cSchristos if (base != 0) 8198b9484cSchristos return base; 8298b9484cSchristos if (dir != 0 8398b9484cSchristos && access (dir, R_OK | W_OK | X_OK) == 0) 84924795e6Schristos { 85924795e6Schristos /* Check to make sure dir is actually a directory. */ 86924795e6Schristos #ifdef S_ISDIR 87924795e6Schristos struct stat s; 88924795e6Schristos if (stat (dir, &s)) 89924795e6Schristos return NULL; 90924795e6Schristos if (!S_ISDIR (s.st_mode)) 91924795e6Schristos return NULL; 92924795e6Schristos #endif 9398b9484cSchristos return dir; 94924795e6Schristos } 9598b9484cSchristos return 0; 9698b9484cSchristos } 9798b9484cSchristos 9898b9484cSchristos static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 }; 9998b9484cSchristos static const char vartmp[] = 10098b9484cSchristos { DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; 10198b9484cSchristos 10298b9484cSchristos #endif 10398b9484cSchristos 10498b9484cSchristos static char *memoized_tmpdir; 10598b9484cSchristos 10698b9484cSchristos /* 10798b9484cSchristos 1089d1da10bSchristos @deftypefn Replacement const char* choose_tmpdir () 10998b9484cSchristos 11098b9484cSchristos Returns a pointer to a directory path suitable for creating temporary 11198b9484cSchristos files in. 11298b9484cSchristos 11398b9484cSchristos @end deftypefn 11498b9484cSchristos 11598b9484cSchristos */ 11698b9484cSchristos 1179d1da10bSchristos const char * 11898b9484cSchristos choose_tmpdir (void) 11998b9484cSchristos { 12098b9484cSchristos if (!memoized_tmpdir) 12198b9484cSchristos { 12298b9484cSchristos #if !defined(_WIN32) || defined(__CYGWIN__) 12398b9484cSchristos const char *base = 0; 12498b9484cSchristos char *tmpdir; 12598b9484cSchristos unsigned int len; 12698b9484cSchristos 12798b9484cSchristos #ifdef VMS 12898b9484cSchristos /* Try VMS standard temp logical. */ 12998b9484cSchristos base = try_dir ("/sys$scratch", base); 13098b9484cSchristos #else 13198b9484cSchristos base = try_dir (getenv ("TMPDIR"), base); 13298b9484cSchristos base = try_dir (getenv ("TMP"), base); 13398b9484cSchristos base = try_dir (getenv ("TEMP"), base); 13498b9484cSchristos #endif 13598b9484cSchristos 13698b9484cSchristos #ifdef P_tmpdir 13798b9484cSchristos /* We really want a directory name here as if concatenated with say \dir 13898b9484cSchristos we do not end up with a double \\ which defines an UNC path. */ 13998b9484cSchristos if (strcmp (P_tmpdir, "\\") == 0) 14098b9484cSchristos base = try_dir ("\\.", base); 14198b9484cSchristos else 14298b9484cSchristos base = try_dir (P_tmpdir, base); 14398b9484cSchristos #endif 14498b9484cSchristos 145924795e6Schristos /* Try /var/tmp, then /tmp. */ 14698b9484cSchristos base = try_dir (vartmp, base); 147543accdbSkamil base = try_dir (tmp, base); 14898b9484cSchristos 14998b9484cSchristos /* If all else fails, use the current directory! */ 15098b9484cSchristos if (base == 0) 15198b9484cSchristos base = "."; 15298b9484cSchristos /* Append DIR_SEPARATOR to the directory we've chosen 15398b9484cSchristos and return it. */ 15498b9484cSchristos len = strlen (base); 15598b9484cSchristos tmpdir = XNEWVEC (char, len + 2); 15698b9484cSchristos strcpy (tmpdir, base); 15798b9484cSchristos tmpdir[len] = DIR_SEPARATOR; 15898b9484cSchristos tmpdir[len+1] = '\0'; 15998b9484cSchristos memoized_tmpdir = tmpdir; 16098b9484cSchristos #else /* defined(_WIN32) && !defined(__CYGWIN__) */ 16198b9484cSchristos DWORD len; 16298b9484cSchristos 16398b9484cSchristos /* Figure out how much space we need. */ 16498b9484cSchristos len = GetTempPath(0, NULL); 16598b9484cSchristos if (len) 16698b9484cSchristos { 16798b9484cSchristos memoized_tmpdir = XNEWVEC (char, len); 16898b9484cSchristos if (!GetTempPath(len, memoized_tmpdir)) 16998b9484cSchristos { 17098b9484cSchristos XDELETEVEC (memoized_tmpdir); 17198b9484cSchristos memoized_tmpdir = NULL; 17298b9484cSchristos } 17398b9484cSchristos } 17498b9484cSchristos if (!memoized_tmpdir) 17598b9484cSchristos /* If all else fails, use the current directory. */ 17698b9484cSchristos memoized_tmpdir = xstrdup (".\\"); 17798b9484cSchristos #endif /* defined(_WIN32) && !defined(__CYGWIN__) */ 17898b9484cSchristos } 17998b9484cSchristos 18098b9484cSchristos return memoized_tmpdir; 18198b9484cSchristos } 18298b9484cSchristos 18398b9484cSchristos /* 18498b9484cSchristos 18598b9484cSchristos @deftypefn Replacement char* make_temp_file (const char *@var{suffix}) 18698b9484cSchristos 18798b9484cSchristos Return a temporary file name (as a string) or @code{NULL} if unable to 18898b9484cSchristos create one. @var{suffix} is a suffix to append to the file name. The 18998b9484cSchristos string is @code{malloc}ed, and the temporary file has been created. 19098b9484cSchristos 19198b9484cSchristos @end deftypefn 19298b9484cSchristos 19398b9484cSchristos */ 19498b9484cSchristos 19598b9484cSchristos char * 196314094e7Schristos make_temp_file_with_prefix (const char *prefix, const char *suffix) 19798b9484cSchristos { 19898b9484cSchristos const char *base = choose_tmpdir (); 19998b9484cSchristos char *temp_filename; 200314094e7Schristos int base_len, suffix_len, prefix_len; 20198b9484cSchristos int fd; 20298b9484cSchristos 203314094e7Schristos if (prefix == 0) 204314094e7Schristos prefix = "cc"; 205314094e7Schristos 20698b9484cSchristos if (suffix == 0) 20798b9484cSchristos suffix = ""; 20898b9484cSchristos 20998b9484cSchristos base_len = strlen (base); 210314094e7Schristos prefix_len = strlen (prefix); 21198b9484cSchristos suffix_len = strlen (suffix); 21298b9484cSchristos 21398b9484cSchristos temp_filename = XNEWVEC (char, base_len 21498b9484cSchristos + TEMP_FILE_LEN 215314094e7Schristos + suffix_len 216314094e7Schristos + prefix_len + 1); 21798b9484cSchristos strcpy (temp_filename, base); 218314094e7Schristos strcpy (temp_filename + base_len, prefix); 219314094e7Schristos strcpy (temp_filename + base_len + prefix_len, TEMP_FILE); 220314094e7Schristos strcpy (temp_filename + base_len + prefix_len + TEMP_FILE_LEN, suffix); 22198b9484cSchristos 22298b9484cSchristos fd = mkstemps (temp_filename, suffix_len); 22398b9484cSchristos /* Mkstemps failed. It may be EPERM, ENOSPC etc. */ 22498b9484cSchristos if (fd == -1) 22598b9484cSchristos { 22698b9484cSchristos fprintf (stderr, "Cannot create temporary file in %s: %s\n", 22798b9484cSchristos base, strerror (errno)); 22898b9484cSchristos abort (); 22998b9484cSchristos } 23098b9484cSchristos /* We abort on failed close out of sheer paranoia. */ 23198b9484cSchristos if (close (fd)) 23298b9484cSchristos abort (); 23398b9484cSchristos return temp_filename; 23498b9484cSchristos } 235314094e7Schristos 236314094e7Schristos char * 237314094e7Schristos make_temp_file (const char *suffix) 238314094e7Schristos { 239314094e7Schristos return make_temp_file_with_prefix (NULL, suffix); 240314094e7Schristos } 241