189857Sobrien/* Utility to pick a temporary filename prefix.
289857Sobrien   Copyright (C) 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
389857Sobrien
489857SobrienThis file is part of the libiberty library.
589857SobrienLibiberty is free software; you can redistribute it and/or
689857Sobrienmodify it under the terms of the GNU Library General Public
789857SobrienLicense as published by the Free Software Foundation; either
889857Sobrienversion 2 of the License, or (at your option) any later version.
989857Sobrien
1089857SobrienLibiberty is distributed in the hope that it will be useful,
1189857Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1289857SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1389857SobrienLibrary General Public License for more details.
1489857Sobrien
1589857SobrienYou should have received a copy of the GNU Library General Public
1689857SobrienLicense along with libiberty; see the file COPYING.LIB.  If not,
17218822Sdimwrite to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18218822SdimBoston, MA 02110-1301, USA.  */
1989857Sobrien
2089857Sobrien#ifdef HAVE_CONFIG_H
2189857Sobrien#include "config.h"
2289857Sobrien#endif
2389857Sobrien
2489857Sobrien#include <stdio.h>	/* May get P_tmpdir.  */
2589857Sobrien#include <sys/types.h>
2689857Sobrien#ifdef HAVE_UNISTD_H
2789857Sobrien#include <unistd.h>
2889857Sobrien#endif
2989857Sobrien#ifdef HAVE_STDLIB_H
3089857Sobrien#include <stdlib.h>
3189857Sobrien#endif
3289857Sobrien#ifdef HAVE_STRING_H
3389857Sobrien#include <string.h>
3489857Sobrien#endif
3589857Sobrien#ifdef HAVE_SYS_FILE_H
3689857Sobrien#include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
3789857Sobrien#endif
3889857Sobrien
3989857Sobrien#ifndef R_OK
4089857Sobrien#define R_OK 4
4189857Sobrien#define W_OK 2
4289857Sobrien#define X_OK 1
4389857Sobrien#endif
4489857Sobrien
4589857Sobrien#include "libiberty.h"
46218822Sdimextern int mkstemps (char *, int);
4789857Sobrien
4889857Sobrien/* '/' works just fine on MS-DOS based systems.  */
4989857Sobrien#ifndef DIR_SEPARATOR
5089857Sobrien#define DIR_SEPARATOR '/'
5189857Sobrien#endif
5289857Sobrien
5389857Sobrien/* Name of temporary file.
5489857Sobrien   mktemp requires 6 trailing X's.  */
5589857Sobrien#define TEMP_FILE "ccXXXXXX"
5689857Sobrien#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
5789857Sobrien
5889857Sobrien/* Subroutine of choose_tmpdir.
5989857Sobrien   If BASE is non-NULL, return it.
6089857Sobrien   Otherwise it checks if DIR is a usable directory.
6189857Sobrien   If success, DIR is returned.
6289857Sobrien   Otherwise NULL is returned.  */
6389857Sobrien
64218822Sdimstatic inline const char *try_dir (const char *, const char *);
6589857Sobrien
6689857Sobrienstatic inline const char *
67218822Sdimtry_dir (const char *dir, const char *base)
6889857Sobrien{
6989857Sobrien  if (base != 0)
7089857Sobrien    return base;
7189857Sobrien  if (dir != 0
7289857Sobrien      && access (dir, R_OK | W_OK | X_OK) == 0)
7389857Sobrien    return dir;
7489857Sobrien  return 0;
7589857Sobrien}
7689857Sobrien
7789857Sobrienstatic const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
7889857Sobrienstatic const char usrtmp[] =
7989857Sobrien{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
8089857Sobrienstatic const char vartmp[] =
8189857Sobrien{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
8289857Sobrien
8389857Sobrienstatic char *memoized_tmpdir;
8489857Sobrien
8589857Sobrien/*
8689857Sobrien
8789857Sobrien@deftypefn Replacement char* choose_tmpdir ()
8889857Sobrien
8989857SobrienReturns a pointer to a directory path suitable for creating temporary
9089857Sobrienfiles in.
9189857Sobrien
9289857Sobrien@end deftypefn
9389857Sobrien
9489857Sobrien*/
9589857Sobrien
9689857Sobrienchar *
97218822Sdimchoose_tmpdir (void)
9889857Sobrien{
9989857Sobrien  const char *base = 0;
10089857Sobrien  char *tmpdir;
10189857Sobrien  unsigned int len;
10289857Sobrien
10389857Sobrien  if (memoized_tmpdir)
10489857Sobrien    return memoized_tmpdir;
10589857Sobrien
106218822Sdim  base = try_dir (getenv ("TMPDIR"), base);
107218822Sdim  base = try_dir (getenv ("TMP"), base);
108218822Sdim  base = try_dir (getenv ("TEMP"), base);
10989857Sobrien
11089857Sobrien#ifdef P_tmpdir
111218822Sdim  base = try_dir (P_tmpdir, base);
11289857Sobrien#endif
11389857Sobrien
11489857Sobrien  /* Try /var/tmp, /usr/tmp, then /tmp.  */
115218822Sdim  base = try_dir (vartmp, base);
116218822Sdim  base = try_dir (usrtmp, base);
117218822Sdim  base = try_dir (tmp, base);
11889857Sobrien
11989857Sobrien  /* If all else fails, use the current directory!  */
12089857Sobrien  if (base == 0)
12189857Sobrien    base = ".";
12289857Sobrien
12389857Sobrien  /* Append DIR_SEPARATOR to the directory we've chosen
12489857Sobrien     and return it.  */
12589857Sobrien  len = strlen (base);
126218822Sdim  tmpdir = XNEWVEC (char, len + 2);
12789857Sobrien  strcpy (tmpdir, base);
12889857Sobrien  tmpdir[len] = DIR_SEPARATOR;
12989857Sobrien  tmpdir[len+1] = '\0';
13089857Sobrien
13189857Sobrien  memoized_tmpdir = tmpdir;
13289857Sobrien  return tmpdir;
13389857Sobrien}
13489857Sobrien
13589857Sobrien/*
13689857Sobrien
13789857Sobrien@deftypefn Replacement char* make_temp_file (const char *@var{suffix})
13889857Sobrien
13989857SobrienReturn a temporary file name (as a string) or @code{NULL} if unable to
14089857Sobriencreate one.  @var{suffix} is a suffix to append to the file name.  The
14189857Sobrienstring is @code{malloc}ed, and the temporary file has been created.
14289857Sobrien
14389857Sobrien@end deftypefn
14489857Sobrien
14589857Sobrien*/
14689857Sobrien
14789857Sobrienchar *
148218822Sdimmake_temp_file (const char *suffix)
14989857Sobrien{
15089857Sobrien  const char *base = choose_tmpdir ();
15189857Sobrien  char *temp_filename;
15289857Sobrien  int base_len, suffix_len;
15389857Sobrien  int fd;
15489857Sobrien
15589857Sobrien  if (suffix == 0)
15689857Sobrien    suffix = "";
15789857Sobrien
15889857Sobrien  base_len = strlen (base);
15989857Sobrien  suffix_len = strlen (suffix);
16089857Sobrien
161218822Sdim  temp_filename = XNEWVEC (char, base_len
16289857Sobrien			   + TEMP_FILE_LEN
16389857Sobrien			   + suffix_len + 1);
16489857Sobrien  strcpy (temp_filename, base);
16589857Sobrien  strcpy (temp_filename + base_len, TEMP_FILE);
16689857Sobrien  strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix);
16789857Sobrien
16889857Sobrien  fd = mkstemps (temp_filename, suffix_len);
16989857Sobrien  /* If mkstemps failed, then something bad is happening.  Maybe we should
17089857Sobrien     issue a message about a possible security attack in progress?  */
17189857Sobrien  if (fd == -1)
17289857Sobrien    abort ();
17389857Sobrien  /* Similarly if we can not close the file.  */
17489857Sobrien  if (close (fd))
17589857Sobrien    abort ();
17689857Sobrien  return temp_filename;
17789857Sobrien}
178