1/* Managing temporary directories and their content within libgccjit.so
2   Copyright (C) 2014-2020 Free Software Foundation, Inc.
3   Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24
25#include "jit-tempdir.h"
26
27
28/* Construct a tempdir path template suitable for use by mkdtemp
29   e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
30   libiberty's choose_tempdir rather than hardcoding "/tmp/".
31
32   The memory is allocated using malloc and must be freed.
33   Aborts the process if allocation fails. */
34
35static char *
36make_tempdir_path_template ()
37{
38  const char *tmpdir_buf;
39  size_t tmpdir_len;
40  const char *file_template_buf;
41  size_t file_template_len;
42  char *result;
43
44  /* The result of choose_tmpdir is a cached buffer within libiberty, so
45     we must *not* free it.  */
46  tmpdir_buf = choose_tmpdir ();
47
48  /* choose_tmpdir aborts on malloc failure.  */
49  gcc_assert (tmpdir_buf);
50
51  tmpdir_len = strlen (tmpdir_buf);
52  /* tmpdir_buf should now have a dir separator as the final byte.  */
53  gcc_assert (tmpdir_len > 0);
54  gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
55
56  file_template_buf = "libgccjit-XXXXXX";
57  file_template_len = strlen (file_template_buf);
58
59  result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
60  strcpy (result, tmpdir_buf);
61  strcpy (result + tmpdir_len, file_template_buf);
62
63  return result;
64}
65
66/* The constructor for the jit::tempdir object.
67   The real work is done by the jit::tempdir::create method.  */
68
69gcc::jit::tempdir::tempdir (logger *logger, int keep_intermediates)
70  : log_user (logger),
71    m_keep_intermediates (keep_intermediates),
72    m_path_template (NULL),
73    m_path_tempdir (NULL),
74    m_path_c_file (NULL),
75    m_path_s_file (NULL),
76    m_path_so_file (NULL)
77{
78  JIT_LOG_SCOPE (get_logger ());
79}
80
81/* Do the real work of creating the on-disk tempdir.
82   We do this here, rather than in the jit::tempdir constructor
83   so that we can handle failure without needing exceptions.  */
84
85bool
86gcc::jit::tempdir::create ()
87{
88  JIT_LOG_SCOPE (get_logger ());
89
90  m_path_template = make_tempdir_path_template ();
91  if (!m_path_template)
92    return false;
93
94  log ("m_path_template: %s", m_path_template);
95
96  /* Create tempdir using mkdtemp.  This is created with 0700 perms and
97     is unique.  Hence no other (non-root) users should have access to
98     the paths within it.  */
99  m_path_tempdir = mkdtemp (m_path_template);
100  if (!m_path_tempdir)
101    return false;
102  log ("m_path_tempdir: %s", m_path_tempdir);
103
104  m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
105  m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
106  m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
107
108  /* Success.  */
109  return true;
110}
111
112/* The destructor for the jit::tempdir object, which
113   cleans up the filesystem directory and its contents
114   (unless keep_intermediates was set).  */
115
116gcc::jit::tempdir::~tempdir ()
117{
118  JIT_LOG_SCOPE (get_logger ());
119
120  if (m_keep_intermediates)
121    fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
122  else
123    {
124      /* Clean up .s/.so.  */
125      if (m_path_s_file)
126	{
127	  log ("unlinking .s file: %s", m_path_s_file);
128	  unlink (m_path_s_file);
129	}
130      if (m_path_so_file)
131	{
132	  log ("unlinking .so file: %s", m_path_so_file);
133	  unlink (m_path_so_file);
134	}
135
136      /* Clean up any other tempfiles.  */
137      int i;
138      char *tempfile;
139      FOR_EACH_VEC_ELT (m_tempfiles, i, tempfile)
140	{
141	  log ("unlinking tempfile: %s", tempfile);
142	  unlink (tempfile);
143	}
144
145      /* The tempdir should now be empty; remove it.  */
146      if (m_path_tempdir)
147	{
148	  log ("removing tempdir: %s", m_path_tempdir);
149	  rmdir (m_path_tempdir);
150	}
151    }
152
153  free (m_path_template);
154  /* m_path_tempdir aliases m_path_template, or is NULL, so don't
155     attempt to free it .  */
156  free (m_path_c_file);
157  free (m_path_s_file);
158  free (m_path_so_file);
159
160  int i;
161  char *tempfile;
162  FOR_EACH_VEC_ELT (m_tempfiles, i, tempfile)
163    free (tempfile);
164}
165