1 /* Copyright (C) 1999, 2001-2002, 2006 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 17 18 /* Extracted from sysdeps/posix/tempname.c. */ 19 20 #include <config.h> 21 22 /* Specification. */ 23 #include "tmpdir.h" 24 25 #include <stdbool.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include <errno.h> 30 #ifndef __set_errno 31 # define __set_errno(Val) errno = (Val) 32 #endif 33 34 #include <stdio.h> 35 #ifndef P_tmpdir 36 # define P_tmpdir "/tmp" 37 #endif 38 39 #include <sys/stat.h> 40 #if !defined S_ISDIR && defined S_IFDIR 41 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 42 #endif 43 #if !S_IRUSR && S_IREAD 44 # define S_IRUSR S_IREAD 45 #endif 46 #if !S_IRUSR 47 # define S_IRUSR 00400 48 #endif 49 #if !S_IWUSR && S_IWRITE 50 # define S_IWUSR S_IWRITE 51 #endif 52 #if !S_IWUSR 53 # define S_IWUSR 00200 54 #endif 55 #if !S_IXUSR && S_IEXEC 56 # define S_IXUSR S_IEXEC 57 #endif 58 #if !S_IXUSR 59 # define S_IXUSR 00100 60 #endif 61 62 #if _LIBC 63 # define struct_stat64 struct stat64 64 #else 65 # define struct_stat64 struct stat 66 # define __xstat64(version, path, buf) stat (path, buf) 67 #endif 68 69 #if ! (HAVE___SECURE_GETENV || _LIBC) 70 # define __secure_getenv getenv 71 #endif 72 73 /* Pathname support. 74 ISSLASH(C) tests whether C is a directory separator character. 75 */ 76 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ 77 /* Win32, Cygwin, OS/2, DOS */ 78 # define ISSLASH(C) ((C) == '/' || (C) == '\\') 79 #else 80 /* Unix */ 81 # define ISSLASH(C) ((C) == '/') 82 #endif 83 84 85 /* Return nonzero if DIR is an existent directory. */ 86 static bool 87 direxists (const char *dir) 88 { 89 struct_stat64 buf; 90 return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); 91 } 92 93 /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is 94 non-null and exists, uses it; otherwise uses the first of $TMPDIR, 95 P_tmpdir, /tmp that exists. Copies into TMPL a template suitable 96 for use with mk[s]temp. Will fail (-1) if DIR is non-null and 97 doesn't exist, none of the searched dirs exists, or there's not 98 enough space in TMPL. */ 99 int 100 path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, 101 bool try_tmpdir) 102 { 103 const char *d; 104 size_t dlen, plen; 105 106 if (!pfx || !pfx[0]) 107 { 108 pfx = "file"; 109 plen = 4; 110 } 111 else 112 { 113 plen = strlen (pfx); 114 if (plen > 5) 115 plen = 5; 116 } 117 118 if (try_tmpdir) 119 { 120 d = __secure_getenv ("TMPDIR"); 121 if (d != NULL && direxists (d)) 122 dir = d; 123 else if (dir != NULL && direxists (dir)) 124 /* nothing */ ; 125 else 126 dir = NULL; 127 } 128 if (dir == NULL) 129 { 130 if (direxists (P_tmpdir)) 131 dir = P_tmpdir; 132 else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) 133 dir = "/tmp"; 134 else 135 { 136 __set_errno (ENOENT); 137 return -1; 138 } 139 } 140 141 dlen = strlen (dir); 142 while (dlen >= 1 && ISSLASH (dir[dlen - 1])) 143 dlen--; /* remove trailing slashes */ 144 145 /* check we have room for "${dir}/${pfx}XXXXXX\0" */ 146 if (tmpl_len < dlen + 1 + plen + 6 + 1) 147 { 148 __set_errno (EINVAL); 149 return -1; 150 } 151 152 sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); 153 return 0; 154 } 155