1169695Skan/* Utility to pick a temporary filename prefix.
2169695Skan   Copyright (C) 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
3169695Skan
4169695SkanThis file is part of the libiberty library.
5169695SkanLibiberty is free software; you can redistribute it and/or
6169695Skanmodify it under the terms of the GNU Library General Public
7169695SkanLicense as published by the Free Software Foundation; either
8169695Skanversion 2 of the License, or (at your option) any later version.
9169695Skan
10169695SkanLibiberty is distributed in the hope that it will be useful,
11169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
12169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13169695SkanLibrary General Public License for more details.
14169695Skan
15169695SkanYou should have received a copy of the GNU Library General Public
16169695SkanLicense along with libiberty; see the file COPYING.LIB.  If not,
17169695Skanwrite to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18169695SkanBoston, MA 02110-1301, USA.  */
19169695Skan
20169695Skan#ifdef HAVE_CONFIG_H
21169695Skan#include "config.h"
22169695Skan#endif
23169695Skan
24169695Skan#include <stdio.h>	/* May get P_tmpdir.  */
25169695Skan#include <sys/types.h>
26169695Skan#ifdef HAVE_UNISTD_H
27169695Skan#include <unistd.h>
28169695Skan#endif
29169695Skan#ifdef HAVE_STDLIB_H
30169695Skan#include <stdlib.h>
31169695Skan#endif
32169695Skan#ifdef HAVE_STRING_H
33169695Skan#include <string.h>
34169695Skan#endif
35169695Skan#ifdef HAVE_SYS_FILE_H
36169695Skan#include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
37169695Skan#endif
38169695Skan
39169695Skan#ifndef R_OK
40169695Skan#define R_OK 4
41169695Skan#define W_OK 2
42169695Skan#define X_OK 1
43169695Skan#endif
44169695Skan
45169695Skan#include "libiberty.h"
46169695Skanextern int mkstemps (char *, int);
47169695Skan
48169695Skan/* '/' works just fine on MS-DOS based systems.  */
49169695Skan#ifndef DIR_SEPARATOR
50169695Skan#define DIR_SEPARATOR '/'
51169695Skan#endif
52169695Skan
53169695Skan/* Name of temporary file.
54169695Skan   mktemp requires 6 trailing X's.  */
55169695Skan#define TEMP_FILE "ccXXXXXX"
56169695Skan#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
57169695Skan
58169695Skan/* Subroutine of choose_tmpdir.
59169695Skan   If BASE is non-NULL, return it.
60169695Skan   Otherwise it checks if DIR is a usable directory.
61169695Skan   If success, DIR is returned.
62169695Skan   Otherwise NULL is returned.  */
63169695Skan
64169695Skanstatic inline const char *try_dir (const char *, const char *);
65169695Skan
66169695Skanstatic inline const char *
67169695Skantry_dir (const char *dir, const char *base)
68169695Skan{
69169695Skan  if (base != 0)
70169695Skan    return base;
71169695Skan  if (dir != 0
72169695Skan      && access (dir, R_OK | W_OK | X_OK) == 0)
73169695Skan    return dir;
74169695Skan  return 0;
75169695Skan}
76169695Skan
77169695Skanstatic const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
78169695Skanstatic const char usrtmp[] =
79169695Skan{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
80169695Skanstatic const char vartmp[] =
81169695Skan{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
82169695Skan
83169695Skanstatic char *memoized_tmpdir;
84169695Skan
85169695Skan/*
86169695Skan
87169695Skan@deftypefn Replacement char* choose_tmpdir ()
88169695Skan
89169695SkanReturns a pointer to a directory path suitable for creating temporary
90169695Skanfiles in.
91169695Skan
92169695Skan@end deftypefn
93169695Skan
94169695Skan*/
95169695Skan
96169695Skanchar *
97169695Skanchoose_tmpdir (void)
98169695Skan{
99169695Skan  const char *base = 0;
100169695Skan  char *tmpdir;
101169695Skan  unsigned int len;
102169695Skan
103169695Skan  if (memoized_tmpdir)
104169695Skan    return memoized_tmpdir;
105169695Skan
106169695Skan  base = try_dir (getenv ("TMPDIR"), base);
107169695Skan  base = try_dir (getenv ("TMP"), base);
108169695Skan  base = try_dir (getenv ("TEMP"), base);
109169695Skan
110169695Skan#ifdef P_tmpdir
111169695Skan  base = try_dir (P_tmpdir, base);
112169695Skan#endif
113169695Skan
114169712Skan  /* Try /tmp, /var/tmp, then /usr/tmp.  */
115169712Skan  base = try_dir (tmp, base);
116169695Skan  base = try_dir (vartmp, base);
117169695Skan  base = try_dir (usrtmp, base);
118169695Skan
119169695Skan  /* If all else fails, use the current directory!  */
120169695Skan  if (base == 0)
121169695Skan    base = ".";
122169695Skan
123169695Skan  /* Append DIR_SEPARATOR to the directory we've chosen
124169695Skan     and return it.  */
125169695Skan  len = strlen (base);
126169695Skan  tmpdir = XNEWVEC (char, len + 2);
127169695Skan  strcpy (tmpdir, base);
128169695Skan  tmpdir[len] = DIR_SEPARATOR;
129169695Skan  tmpdir[len+1] = '\0';
130169695Skan
131169695Skan  memoized_tmpdir = tmpdir;
132169695Skan  return tmpdir;
133169695Skan}
134169695Skan
135169695Skan/*
136169695Skan
137169695Skan@deftypefn Replacement char* make_temp_file (const char *@var{suffix})
138169695Skan
139169695SkanReturn a temporary file name (as a string) or @code{NULL} if unable to
140169695Skancreate one.  @var{suffix} is a suffix to append to the file name.  The
141169695Skanstring is @code{malloc}ed, and the temporary file has been created.
142169695Skan
143169695Skan@end deftypefn
144169695Skan
145169695Skan*/
146169695Skan
147169695Skanchar *
148169695Skanmake_temp_file (const char *suffix)
149169695Skan{
150169695Skan  const char *base = choose_tmpdir ();
151169695Skan  char *temp_filename;
152169695Skan  int base_len, suffix_len;
153169695Skan  int fd;
154169695Skan
155169695Skan  if (suffix == 0)
156169695Skan    suffix = "";
157169695Skan
158169695Skan  base_len = strlen (base);
159169695Skan  suffix_len = strlen (suffix);
160169695Skan
161169695Skan  temp_filename = XNEWVEC (char, base_len
162169695Skan			   + TEMP_FILE_LEN
163169695Skan			   + suffix_len + 1);
164169695Skan  strcpy (temp_filename, base);
165169695Skan  strcpy (temp_filename + base_len, TEMP_FILE);
166169695Skan  strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix);
167169695Skan
168169695Skan  fd = mkstemps (temp_filename, suffix_len);
169169695Skan  /* If mkstemps failed, then something bad is happening.  Maybe we should
170169695Skan     issue a message about a possible security attack in progress?  */
171169695Skan  if (fd == -1)
172169695Skan    abort ();
173169695Skan  /* Similarly if we can not close the file.  */
174169695Skan  if (close (fd))
175169695Skan    abort ();
176169695Skan  return temp_filename;
177169695Skan}
178