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. */ 86static bool 87direxists (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. */ 99int 100path_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