1/* 2 * tmpfile.c - functions to create and safely open temp files for the shell. 3 */ 4 5/* Copyright (C) 2000 Free Software Foundation, Inc. 6 7 This file is part of GNU Bash, the Bourne Again SHell. 8 9 Bash is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Bash is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Bash. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include <config.h> 24 25#include <bashtypes.h> 26#include <posixstat.h> 27#include <posixtime.h> 28#include <filecntl.h> 29 30#if defined (HAVE_UNISTD_H) 31# include <unistd.h> 32#endif 33 34#include <stdio.h> 35#include <errno.h> 36 37#include <shell.h> 38 39#ifndef errno 40extern int errno; 41#endif 42 43#define BASEOPENFLAGS (O_CREAT | O_TRUNC | O_EXCL) 44 45#define DEFAULT_TMPDIR "." /* bogus default, should be changed */ 46#define DEFAULT_NAMEROOT "shtmp" 47 48extern pid_t dollar_dollar_pid; 49 50static char *get_sys_tmpdir __P((void)); 51static char *get_tmpdir __P((int)); 52 53static char *sys_tmpdir = (char *)NULL; 54static int ntmpfiles; 55static int tmpnamelen = -1; 56static unsigned long filenum = 1L; 57 58static char * 59get_sys_tmpdir () 60{ 61 if (sys_tmpdir) 62 return sys_tmpdir; 63 64#ifdef P_tmpdir 65 sys_tmpdir = P_tmpdir; 66 if (file_iswdir (sys_tmpdir)) 67 return sys_tmpdir; 68#endif 69 70 sys_tmpdir = "/tmp"; 71 if (file_iswdir (sys_tmpdir)) 72 return sys_tmpdir; 73 74 sys_tmpdir = "/var/tmp"; 75 if (file_iswdir (sys_tmpdir)) 76 return sys_tmpdir; 77 78 sys_tmpdir = "/usr/tmp"; 79 if (file_iswdir (sys_tmpdir)) 80 return sys_tmpdir; 81 82 sys_tmpdir = DEFAULT_TMPDIR; 83 84 return sys_tmpdir; 85} 86 87static char * 88get_tmpdir (flags) 89 int flags; 90{ 91 char *tdir; 92 93 tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL; 94 if (tdir && (file_iswdir (tdir) == 0 || strlen (tdir) > PATH_MAX)) 95 tdir = 0; 96 97 if (tdir == 0) 98 tdir = get_sys_tmpdir (); 99 100#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX) 101 if (tmpnamelen == -1) 102 tmpnamelen = pathconf (tdir, _PC_NAME_MAX); 103#else 104 tmpnamelen = 0; 105#endif 106 107 return tdir; 108} 109 110char * 111sh_mktmpname (nameroot, flags) 112 char *nameroot; 113 int flags; 114{ 115 char *filename, *tdir, *lroot; 116 struct stat sb; 117 int r, tdlen; 118 119 filename = (char *)xmalloc (PATH_MAX + 1); 120 tdir = get_tmpdir (flags); 121 tdlen = strlen (tdir); 122 123 lroot = nameroot ? nameroot : DEFAULT_NAMEROOT; 124 125#ifdef USE_MKTEMP 126 sprintf (filename, "%s/%s.XXXXXX", tdir, lroot); 127 if (mktemp (filename) == 0) 128 { 129 free (filename); 130 filename = NULL; 131 } 132#else /* !USE_MKTEMP */ 133 while (1) 134 { 135 filenum = (filenum << 1) ^ 136 (unsigned long) time ((time_t *)0) ^ 137 (unsigned long) dollar_dollar_pid ^ 138 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++); 139 sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum); 140 if (tmpnamelen > 0 && tmpnamelen < 32) 141 filename[tdlen + 1 + tmpnamelen] = '\0'; 142# ifdef HAVE_LSTAT 143 r = lstat (filename, &sb); 144# else 145 r = stat (filename, &sb); 146# endif 147 if (r < 0 && errno == ENOENT) 148 break; 149 } 150#endif /* !USE_MKTEMP */ 151 152 return filename; 153} 154 155int 156sh_mktmpfd (nameroot, flags, namep) 157 char *nameroot; 158 int flags; 159 char **namep; 160{ 161 char *filename, *tdir, *lroot; 162 int fd, tdlen; 163 164 filename = (char *)xmalloc (PATH_MAX + 1); 165 tdir = get_tmpdir (flags); 166 tdlen = strlen (tdir); 167 168 lroot = nameroot ? nameroot : DEFAULT_NAMEROOT; 169 170#ifdef USE_MKSTEMP 171 sprintf (filename, "%s/%s.XXXXXX", tdir, lroot); 172 fd = mkstemp (filename); 173 if (fd < 0 || namep == 0) 174 { 175 free (filename); 176 filename = NULL; 177 } 178 if (namep) 179 *namep = filename; 180 return fd; 181#else /* !USE_MKSTEMP */ 182 do 183 { 184 filenum = (filenum << 1) ^ 185 (unsigned long) time ((time_t *)0) ^ 186 (unsigned long) dollar_dollar_pid ^ 187 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++); 188 sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum); 189 if (tmpnamelen > 0 && tmpnamelen < 32) 190 filename[tdlen + 1 + tmpnamelen] = '\0'; 191 fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600); 192 } 193 while (fd < 0 && errno == EEXIST); 194 195 if (namep) 196 *namep = filename; 197 else 198 free (filename); 199 200 return fd; 201#endif /* !USE_MKSTEMP */ 202} 203 204FILE * 205sh_mktmpfp (nameroot, flags, namep) 206 char *nameroot; 207 int flags; 208 char **namep; 209{ 210 int fd; 211 FILE *fp; 212 213 fd = sh_mktmpfd (nameroot, flags, namep); 214 if (fd < 0) 215 return ((FILE *)NULL); 216 fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w"); 217 if (fp == 0) 218 close (fd); 219 return fp; 220} 221