]>
diplodocus.org Git - nmh/blob - sbr/m_mktemp.c
1 /* m_mktemp.c -- Construct a temporary file.
3 * This code is Copyright (c) 2010, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
12 #include "h/signals.h"
13 #include "m_maildir.h"
16 static void register_for_removal(const char *);
19 /* Create a temporary file. If pfx_in is null, the temporary file
20 * will be created in the temporary directory (more on that later).
21 * If pfx_in is not null, then the temporary file location will be
22 * defined by the value pfx_in.
24 * The file created will be at the pathname specified appended with
25 * 6 random (we hope :) characters.
27 * The return value will be the pathname to the file created.
29 * CAUTION: The return pointer references static data. If
30 * you need to modify, or save, the return string, make a copy of it
33 * When pfx_in is null, the temporary directory is determined as
38 * User's mail directory.
40 * NOTE: One will probably use m_mktemp2() instead of this function.
41 * For example, if you want to create a temp file in the defined
42 * temporary directory, but with a custom basename prefix, do
43 * something like the following:
45 * char *tmp_pathname = m_mktemp2(NULL, "mypre", ...);
49 const char *pfx_in
, /* Pathname prefix for temporary file. */
50 int *fd_ret
, /* (return,optional) File descriptor to temp file. */
51 FILE **fp_ret
/* (return,optional) FILE pointer to temp file. */
54 static char tmpfil
[BUFSIZ
];
56 mode_t oldmode
= umask(077);
59 snprintf(tmpfil
, sizeof(tmpfil
), "%s/nmhXXXXXX", get_temp_dir());
61 snprintf(tmpfil
, sizeof(tmpfil
), "%sXXXXXX", pfx_in
);
71 register_for_removal(tmpfil
);
73 bool keep_open
= false;
79 FILE *fp
= fdopen(fd
, "w+");
82 (void) m_unlink(tmpfil
);
98 /* This version allows one to specify the directory the temp file should
99 * by created based on a given pathname. Although m_mktemp() technically
100 * supports this, this version is when the directory is defined by
101 * a separate variable from the prefix, eliminating the caller from having
102 * to do string manipulation to generate the desired pathname prefix.
104 * The pfx_in parameter specifies a basename prefix for the file. If dir_in
105 * is NULL, then the defined temporary directory (see comments to m_mktemp()
106 * above) is used to create the temp file.
110 const char *dir_in
, /* Directory to place temp file. */
111 const char *pfx_in
, /* Basename prefix for temp file. */
112 int *fd_ret
, /* (return,optional) File descriptor to temp file. */
113 FILE **fp_ret
/* (return,optional) FILE pointer to temp file. */
116 static char buffer
[BUFSIZ
];
120 if (dir_in
== NULL
) {
121 if (pfx_in
== NULL
) {
122 return m_mktemp(NULL
, fd_ret
, fp_ret
);
124 snprintf(buffer
, sizeof(buffer
), "%s/%s", get_temp_dir(), pfx_in
);
125 return m_mktemp(buffer
, fd_ret
, fp_ret
);
128 if ((cp
= r1bindex ((char *)dir_in
, '/')) == dir_in
) {
129 /* No directory component */
130 return m_mktemp(pfx_in
, fd_ret
, fp_ret
);
132 n
= (int)(cp
-dir_in
); /* Length of dir component */
133 snprintf(buffer
, sizeof(buffer
), "%.*s%s", n
, dir_in
, pfx_in
);
134 return m_mktemp(buffer
, fd_ret
, fp_ret
);
139 * This version supports a suffix for the temp filename.
140 * It has two other differences from m_mktemp() and m_mktemp2():
141 * 1) It does not support specification of a directory for the temp
142 * file. Instead it always uses get_temp_dir().
143 * 2) It returns a dynamically allocated string. The caller is
144 * responsible for freeing the allocated memory.
148 const char *pfx_in
, /* Basename prefix for temp file. */
149 const char *suffix
, /* Suffix, including any '.', for temp file. */
150 int *fd_ret
, /* (return,optional) File descriptor to temp file. */
151 FILE **fp_ret
/* (return,optional) FILE pointer to temp file. */
156 mode_t oldmode
= umask(077);
158 if (suffix
== NULL
) {
159 if ((tmpfil
= m_mktemp2(NULL
, pfx_in
, fd_ret
, fp_ret
))) {
160 return mh_xstrdup(tmpfil
);
166 if (pfx_in
== NULL
) {
167 tmpfil
= concat(get_temp_dir(), "/nmhXXXXXX", suffix
, NULL
);
169 tmpfil
= concat(get_temp_dir(), "/", pfx_in
, "XXXXXX", suffix
, NULL
);
172 fd
= mkstemps(tmpfil
, (int) strlen(suffix
));
173 #else /* ! HAVE_MKSTEMPS */
174 /* NetBSD, Solaris 10 */
176 if (pfx_in
== NULL
) {
177 tmpfil
= concat(get_temp_dir(), "/nmhXXXXXX", NULL
);
179 tmpfil
= concat(get_temp_dir(), "/", pfx_in
, "XXXXXX", NULL
);
182 fd
= mkstemp(tmpfil
);
184 char *oldfilename
= tmpfil
;
185 tmpfil
= concat(oldfilename
, suffix
, NULL
);
187 if (rename(oldfilename
, tmpfil
) != 0) {
188 (void) unlink(oldfilename
);
196 #endif /* ! HAVE_MKSTEMPS */
204 register_for_removal(tmpfil
);
206 bool keep_open
= false;
207 if (fd_ret
!= NULL
) {
211 if (fp_ret
!= NULL
) {
212 FILE *fp
= fdopen(fd
, "w+");
215 (void) m_unlink(tmpfil
);
237 /* Ignore envvars if we are setuid */
238 if ((getuid()==geteuid()) && (getgid()==getegid())) {
240 tmpdir
= getenv("MHTMPDIR");
241 if (tmpdir
!= NULL
&& *tmpdir
!= '\0') return tmpdir
;
243 tmpdir
= getenv("TMPDIR");
244 if (tmpdir
!= NULL
&& *tmpdir
!= '\0') return tmpdir
;
246 return m_maildir("");
251 * Array of files (full pathnames) to remove on process exit.
252 * Instead of removing slots from the array, just set to NULL
253 * to indicate that the file should no longer be removed.
255 static svector_t exit_filelist
= NULL
;
258 * Register a file for removal at program termination.
261 register_for_removal(const char *pathname
)
263 if (exit_filelist
== NULL
) exit_filelist
= svector_create(20);
264 (void) svector_push_back(exit_filelist
, mh_xstrdup(pathname
));
268 * Unregister all files that were registered to be removed at program
269 * termination. When called with remove_files of 0, this function is
270 * intended for use by one of the programs after a fork(3) without a
271 * subsequent call to one of the exec(3) functions or _exit(3). When
272 * called with non-0 remove_files argument, it is intended for use by
273 * an atexit() function.
275 * Right after a fork() and before calling exec() or _exit(), if the
276 * child catches one of the appropriate signals, it will remove
277 * all the registered temporary files. Some of those may be needed by
278 * the parent. Some nmh programs ignore or block some of the signals
279 * in the child right after fork(). For the other programs, rather
280 * than complicate things by preventing that, just take the chance
281 * that it might happen. It is harmless to attempt to unlink a
282 * temporary file twice, assuming another one wasn't created too
283 * quickly created with the same name.
286 unregister_for_removal(int remove_files
)
291 for (i
= 0; i
< svector_size(exit_filelist
); ++i
) {
292 char *filename
= svector_at(exit_filelist
, i
);
295 if (remove_files
) (void) unlink(filename
);
300 svector_free(exit_filelist
);
301 exit_filelist
= NULL
;
306 * If the file was registered for removal, deregister it. In
307 * any case, unlink it.
310 m_unlink(const char *pathname
)
313 char **slot
= svector_find(exit_filelist
, pathname
);
321 return unlink(pathname
);
322 /* errno should be set to ENOENT if file was not found */
326 * Remove all registered temporary files.
329 remove_registered_files_atexit(void)
331 unregister_for_removal(1);
335 * Remove all registered temporary files. Suitable for use as a
336 * signal handler. If the signal is one of the usual process
337 * termination signals, calls exit(). Otherwise, disables itself
338 * by restoring the default action and then re-raises the signal,
339 * in case the use was expecting a core dump.
342 remove_registered_files(int sig
)
344 struct sigaction act
;
347 * Ignore this signal for the duration. And we either exit() or
348 * disable this signal handler below, so don't restore this handler.
350 act
.sa_handler
= SIG_IGN
;
351 (void) sigemptyset(&act
.sa_mask
);
353 (void) sigaction(sig
, &act
, 0);
355 if (sig
== SIGHUP
|| sig
== SIGINT
|| sig
== SIGQUIT
|| sig
== SIGTERM
) {
357 * We don't need to call remove_registered_files_atexit() if
358 * it was registered with atexit(), but let's not assume that.
359 * It's harmless to call it twice.
361 remove_registered_files_atexit();
365 remove_registered_files_atexit();
367 act
.sa_handler
= SIG_DFL
;
368 (void) sigemptyset(&act
.sa_mask
);
370 (void) sigaction(sig
, &act
, 0);