blob: 4e8ad14c796dc580171efc8c08ca470077a43c70 [file] [log] [blame]
alaffincc2e5552000-07-27 17:13:18 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 */
32
robbiew5d94fdf2003-04-01 20:20:54 +000033/* $Id: tst_tmpdir.c,v 1.8 2003/04/01 20:20:54 robbiew Exp $ */
alaffincc2e5552000-07-27 17:13:18 +000034
35/**********************************************************
36 *
37 * OS Testing - Silicon Graphics, Inc.
38 *
39 * FUNCTION NAME : tst_tmpdir, tst_rmdir
40 *
41 * FUNCTION TITLE : Create/remove a testing temp dir
42 *
43 * SYNOPSIS:
44 * void tst_tmpdir();
45 * void tst_rmdir();
46 *
47 * AUTHOR : Dave Fenner
48 *
49 * INITIAL RELEASE : UNICOS 8.0
50 *
51 * DESCRIPTION
52 * tst_tmpdir() is used to create a unique, temporary testing
53 * directory, and make it the current working directory.
54 * tst_rmdir() is used to remove the directory created by
55 * tst_tmpdir().
56 *
57 * Setting the env variable "TDIRECTORY" will override the creation
58 * of a new temp dir. The directory specified by TDIRECTORY will
59 * be used as the temporary directory, and no removal will be done
60 * in tst_rmdir().
61 *
62 * RETURN VALUE
63 * Neither tst_tmpdir() or tst_rmdir() has a return value.
64 *
65 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
66#include <stdio.h>
67#include <errno.h>
68#include <stdlib.h> /* for getenv() */
69#include <string.h> /* for string functions */
70#include <unistd.h> /* for sysconf(), getcwd(), rmdir() */
71#include <sys/types.h> /* for mkdir() */
72#include <sys/stat.h> /* for mkdir() */
73#include "test.h"
74#include "rmobj.h"
75
76/*
77 * Define some useful macros.
78 */
79#define PREFIX_SIZE 4
80#define STRING_SIZE 256
81#define DIR_MODE 0777 /* mode of tmp dir that will be created */
82
83#ifndef PATH_MAX
84#ifdef MAXPATHLEN
85#define PATH_MAX MAXPATHLEN
86#else
87#define PATH_MAX 1024
88#endif
89#endif
90
91/*
92 * Define function prototypes.
93 */
94static void tmpdir_cleanup();
95
96/*
97 * Define global variables.
98 */
99extern char *TCID; /* defined/initialized in main() */
100extern int TST_TOTAL; /* defined/initialized in main() */
101extern char *TESTDIR; /* the directory created; defined in */
102 /* tst_res.c */
103
104/*
105 * tst_tmpdir() - Create a unique temporary directory and chdir() to it.
106 * It expects the caller to have defined/initialized the
107 * TCID/TST_TOTAL global variables. The TESTDIR global
108 * variable will be set to the directory that gets used
109 * as the testing directory.
110 *
111 * NOTE: This function must be called BEFORE any activity
112 * that would require CLEANUP. If tst_tmpdir() fails, it
113 * cleans up afer itself and calls tst_exit() (i.e. does
114 * not return).
115 */
116#undef FN_NAME
117#define FN_NAME "tst_tmpdir()"
118
119void
120tst_tmpdir()
121{
plarsb00626b2002-09-04 14:01:28 +0000122 char template[PATH_MAX]; /* template for mkstemp, mkdtemp */
nstrazffe35e22001-03-13 16:33:54 +0000123 int no_cleanup = 0; /* !0 means TDIRECTORY env var was set */
124 char *env_tmpdir; /* temporary storage for TMPDIR env var */
robbiew5d94fdf2003-04-01 20:20:54 +0000125/* This is an AWEFUL hack to figure out if mkdtemp() is available */
126#if defined(__GLIBC_PREREQ)
127# if __GLIBC_PREREQ(2,2)
128# define HAVE_MKDTEMP 1
129# else
130# define HAVE_MKDTEMP 0
plarsca41c6b2002-09-04 18:45:17 +0000131 int tfd;
robbiew5d94fdf2003-04-01 20:20:54 +0000132# endif
133#else
134# define HAVE_MKDTEMP 0
135 int tfd;
136#endif
nstrazffe35e22001-03-13 16:33:54 +0000137 /*
138 * If the TDIRECTORY env variable is not set, a temp dir will be
139 * created.
140 */
141 if ((TESTDIR = getenv(TDIRECTORY))) {
142 /*
143 * The TDIRECTORY env. variable is set, so no temp dir is created.
144 * Also, no clean up will be done via tst_rmdir().
145 */
146 no_cleanup++;
alaffincc2e5552000-07-27 17:13:18 +0000147#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000148 printf("TDIRECTORY env var is set\n");
alaffincc2e5552000-07-27 17:13:18 +0000149#endif
nstrazffe35e22001-03-13 16:33:54 +0000150 } else {
151 /*
152 * Create a template for the temporary directory. Use the
153 * environment variable TMPDIR if it is available, otherwise
154 * use our default TEMPDIR.
155 */
156 if ((env_tmpdir = getenv("TMPDIR"))) {
157 snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", env_tmpdir, TCID);
158 } else {
159 snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", TEMPDIR, TCID);
160 }
161
nstraz7891a262001-03-13 21:54:05 +0000162
163#if HAVE_MKDTEMP
nstrazffe35e22001-03-13 16:33:54 +0000164 /*
165 * Make the temporary directory in one shot using mkdtemp()
166 */
nstraz643643a2001-03-15 21:21:46 +0000167 if (mkdtemp(template) == NULL)
nstrazffe35e22001-03-13 16:33:54 +0000168 tst_brkm(TBROK, tmpdir_cleanup,
plars8f4232f2002-09-04 18:40:11 +0000169 "%s: mkdtemp(%s) failed; errno = %d: %s",
170 FN_NAME, template, errno, strerror(errno));
nstraz643643a2001-03-15 21:21:46 +0000171 TESTDIR = strdup(template);
nstraz7891a262001-03-13 21:54:05 +0000172#else
173 /*
174 * Make the template name, then the directory
175 */
plars8f4232f2002-09-04 18:40:11 +0000176 if (tfd = mkstemp(template) == -1)
177 tst_brkm(TBROK, tmpdir_cleanup,
178 "%s: mkstemp(%s) failed; errno = %d: %s",
179 FN_NAME, template, errno, strerror(errno));
180 close(tfd);
181 unlink(template);
nstraz643643a2001-03-15 21:21:46 +0000182 TESTDIR = strdup(template);
nstraz7891a262001-03-13 21:54:05 +0000183 if (mkdir(TESTDIR, DIR_MODE)) {
184 /* If we start failing with EEXIST, wrap this section in
185 * a loop so we can try again.
186 */
plars8f4232f2002-09-04 18:40:11 +0000187 tst_brkm(TBROK, tmpdir_cleanup,
188 "%s: mkdir(%s, %#o) failed; errno = %d: %s",
189 FN_NAME, TESTDIR, DIR_MODE, errno,
190 strerror(errno));
nstraz7891a262001-03-13 21:54:05 +0000191 }
192#endif
nstrazffe35e22001-03-13 16:33:54 +0000193
194 /*
195 * Change the group on this temporary directory to be that of the
196 * gid of the person running the tests.
197 */
198 if ( chown(TESTDIR, -1, getgid()) == -1 )
plars8f4232f2002-09-04 18:40:11 +0000199 tst_brkm(TBROK, tmpdir_cleanup,
200 "chown(%s, -1, %d) failed; errno = %d: %s",
201 TESTDIR, getgid(), errno, strerror(errno));
nstrazffe35e22001-03-13 16:33:54 +0000202 }
alaffincc2e5552000-07-27 17:13:18 +0000203
204#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000205 printf("TESTDIR = %s\n", TESTDIR);
alaffincc2e5552000-07-27 17:13:18 +0000206#endif
207
nstrazffe35e22001-03-13 16:33:54 +0000208 /*
209 * Change to the temporary directory. If the chdir() fails, issue
210 * TBROK messages for all test cases, attempt to remove the
211 * directory (if it was created), and exit. If the removal also
212 * fails, also issue a TWARN message.
213 */
214 if ( chdir(TESTDIR) == -1 ) {
215 tst_brkm(TBROK, NULL, "%s: chdir(%s) failed; errno = %d: %s",
plars8f4232f2002-09-04 18:40:11 +0000216 FN_NAME, TESTDIR, errno, strerror(errno) );
alaffincc2e5552000-07-27 17:13:18 +0000217
nstrazffe35e22001-03-13 16:33:54 +0000218 /* Try to remove the directory */
219 if ( !no_cleanup && rmdir(TESTDIR) == -1 )
220 tst_resm(TWARN, "%s: rmdir(%s) failed; errno = %d: %s",
plars8f4232f2002-09-04 18:40:11 +0000221 FN_NAME, TESTDIR, errno, strerror(errno) );
alaffincc2e5552000-07-27 17:13:18 +0000222
nstrazffe35e22001-03-13 16:33:54 +0000223 tmpdir_cleanup();
224 }
225
alaffincc2e5552000-07-27 17:13:18 +0000226#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000227 printf("CWD is %s\n", getcwd((char *)NULL, PATH_MAX));
alaffincc2e5552000-07-27 17:13:18 +0000228#endif
229
nstrazffe35e22001-03-13 16:33:54 +0000230 /*
231 * If we made through all this stuff, return.
232 */
233 return;
alaffincc2e5552000-07-27 17:13:18 +0000234} /* tst_tmpdir() */
235
236
237/*
238 *
239 * tst_rmdir() - Recursively remove the temporary directory created by
240 * tst_tmpdir(). This function is intended ONLY as a
241 * companion to tst_tmpdir(). If the TDIRECTORY
242 * environment variable is set, no cleanup will be
243 * attempted.
244 */
245#undef FN_NAME
246#define FN_NAME "tst_rmdir()"
247
248void
249tst_rmdir()
250{
251 char *errmsg;
252 char *tdirectory;
253 char current_dir[PATH_MAX]; /* current working directory */
254 char parent_dir[PATH_MAX]; /* directory above TESTDIR */
255 char *basename; /* basename of the TESTDIR */
256
257 /*
258 * If the TDIRECTORY env variable is set, this indicates that no
259 * temp dir was created by tst_tmpdir(). Thus no cleanup will be
260 * necessary.
261 */
262 if ( (tdirectory = getenv(TDIRECTORY)) != NULL ) {
263#if UNIT_TEST
264 printf("\"TDIRECORY\" env variable is set; no cleanup was performed\n");
265#endif
266 return;
267 }
268
269 /*
270 * Check that TESTDIR is not NULL.
271 */
272 if ( TESTDIR == NULL ) {
273 tst_resm(TWARN, "%s: TESTDIR was NULL; no removal attempted",
274 FN_NAME);
275 return;
276 }
277
278 /*
279 * Check that the value of TESTDIR is not "*" or "/". These could
280 * have disastrous effects in a test run by root.
281 */
282 if ( strcmp(TESTDIR, "/") == 0 ) {
283 tst_resm(TWARN,
284 "%s: Recursive remove of root directory not attempted",
285 FN_NAME);
286 return;
287 }
288
289 if ( strchr(TESTDIR, '*') != NULL ) {
290 tst_resm(TWARN, "%s: Recursive remove of '*' not attempted",
291 FN_NAME);
292 return;
293 }
294
295 /*
296 * Get the directory name of TESTDIR. If TESTDIR is a relative path,
297 * get full path.
298 */
299 if ( TESTDIR[0] != '/' ) {
300 if ( getcwd(current_dir,PATH_MAX) == NULL )
301 strcpy(parent_dir, TESTDIR);
302 else
303 sprintf(parent_dir, "%s/%s", current_dir, TESTDIR);
304 } else {
305 strcpy(parent_dir, TESTDIR);
306 }
307 if ( (basename = strrchr(parent_dir, '/')) != NULL ) {
308 *basename='\0'; /* terminate at end of parent_dir */
309 }
310
311 /*
312 * Change directory to parent_dir (The dir above TESTDIR).
313 */
314 if ( chdir(parent_dir) != 0 )
315 tst_resm(TWARN,
316 "%s: chdir(%s) failed; errno = %d: %s\nAttempting to remove temp dir anyway",
317 FN_NAME, parent_dir, errno, strerror(errno));
318
319 /*
320 * Attempt to remove the "TESTDIR" directory, using rmobj().
321 */
322 if ( rmobj(TESTDIR, &errmsg) == -1 )
323 tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
324 FN_NAME, TESTDIR, errmsg);
325
326 return;
327} /* tst_rmdir() */
328
329
330/*
331 * tmpdir_cleanup() - This function is used when tst_tmpdir()
332 * encounters an error, and must cleanup and exit.
333 * It prints a warning message via tst_resm(), and
334 * then calls tst_exit().
335 */
336#undef FN_NAME
337#define FN_NAME "tst_tmpdir()"
338
339static void
340tmpdir_cleanup()
341{
342 /*
343 * Print a warning message and call tst_exit() to exit the test.
344 */
345 tst_resm(TWARN, "%s: No user cleanup function called before exiting",
346 FN_NAME);
347 tst_exit();
348} /* tmpdir_cleanup() */
349
350
351#ifdef UNIT_TEST
352/****************************************************************************
353 * Unit test code: Takes input from stdin and can make the following
354 * calls: tst_tmpdir(), tst_rmdir().
355 ****************************************************************************/
356int TST_TOTAL = 10;
357char *TCID = "TESTTCID";
358
359main()
360{
361 int option;
362 char *chrptr;
363
364 printf("UNIT TEST of tst_tmpdir.c. Options to try:\n\
365 -1 : call tst_exit()\n\
366 0 : call tst_tmpdir()\n\
367 1 : call tst_rmdir()\n\n");
368
369 while ( 1 ) {
370 printf("Enter options (-1, 0, 1): ");
371 (void) scanf("%d%c", &option, &chrptr);
372
373 switch ( option ) {
374 case -1:
375 tst_exit();
376 break;
377
378 case 0:
379 tst_tmpdir();
380 break;
381
382 case 1:
383 tst_rmdir();
384 break;
385 } /* switch() */
386 } /* while() */
387}
388#endif /* UNIT_TEST */