blob: 6e266469affa111fbfa190dfec57667f5bbbb40e [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
subrata_modak38fea912007-04-27 10:12:01 +000033/* $Id: tst_tmpdir.c,v 1.12 2007/04/27 10:12:01 subrata_modak 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 */
subrata_modak0885aa02007-03-23 12:33:39 +0000146 mkdir(TESTDIR,DIR_MODE); /*Try to create the directory if it does not exist already,
147 user might forget to create one before exporting TDIRECTORY,
148 Will fail if it already exists, no issues in that*/
nstrazffe35e22001-03-13 16:33:54 +0000149 no_cleanup++;
alaffincc2e5552000-07-27 17:13:18 +0000150#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000151 printf("TDIRECTORY env var is set\n");
alaffincc2e5552000-07-27 17:13:18 +0000152#endif
nstrazffe35e22001-03-13 16:33:54 +0000153 } else {
154 /*
155 * Create a template for the temporary directory. Use the
156 * environment variable TMPDIR if it is available, otherwise
157 * use our default TEMPDIR.
158 */
159 if ((env_tmpdir = getenv("TMPDIR"))) {
160 snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", env_tmpdir, TCID);
161 } else {
162 snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", TEMPDIR, TCID);
163 }
164
nstraz7891a262001-03-13 21:54:05 +0000165
166#if HAVE_MKDTEMP
nstrazffe35e22001-03-13 16:33:54 +0000167 /*
168 * Make the temporary directory in one shot using mkdtemp()
169 */
nstraz643643a2001-03-15 21:21:46 +0000170 if (mkdtemp(template) == NULL)
nstrazffe35e22001-03-13 16:33:54 +0000171 tst_brkm(TBROK, tmpdir_cleanup,
plars8f4232f2002-09-04 18:40:11 +0000172 "%s: mkdtemp(%s) failed; errno = %d: %s",
173 FN_NAME, template, errno, strerror(errno));
subrata_modak38fea912007-04-27 10:12:01 +0000174 if ( (TESTDIR = strdup(template)) == NULL ) { //Error Handling for strdup()
175 tst_brkm(TBROK, tmpdir_cleanup,
176 "%s: strdup(%s) failed; errno = %d: %s",
177 FN_NAME, template, errno, strerror(errno));
178 }
nstraz7891a262001-03-13 21:54:05 +0000179#else
180 /*
181 * Make the template name, then the directory
182 */
mridgee6508f82005-01-04 21:00:17 +0000183 if ((tfd = mkstemp(template)) == -1)
plars8f4232f2002-09-04 18:40:11 +0000184 tst_brkm(TBROK, tmpdir_cleanup,
185 "%s: mkstemp(%s) failed; errno = %d: %s",
186 FN_NAME, template, errno, strerror(errno));
subrata_modak38fea912007-04-27 10:12:01 +0000187 if ( close(tfd) == -1 ) {
188 tst_brkm(TBROK, tmpdir_cleanup,
189 "%s: close() failed; errno = %d: %s",
190 FN_NAME, errno, strerror(errno));
191 }
192 if ( unlink(template) == -1) {
193 tst_brkm(TBROK, tmpdir_cleanup,
194 "%s: unlink(%s) failed; errno = %d: %s",
195 FN_NAME, template, errno, strerror(errno));
196 }
197 if ( (TESTDIR = strdup(template)) == NULL ) {
198 tst_brkm(TBROK, tmpdir_cleanup,
199 "%s: strdup(%s) failed; errno = %d: %s",
200 FN_NAME, template, errno, strerror(errno));
201 }
nstraz7891a262001-03-13 21:54:05 +0000202 if (mkdir(TESTDIR, DIR_MODE)) {
203 /* If we start failing with EEXIST, wrap this section in
204 * a loop so we can try again.
205 */
plars8f4232f2002-09-04 18:40:11 +0000206 tst_brkm(TBROK, tmpdir_cleanup,
207 "%s: mkdir(%s, %#o) failed; errno = %d: %s",
208 FN_NAME, TESTDIR, DIR_MODE, errno,
209 strerror(errno));
nstraz7891a262001-03-13 21:54:05 +0000210 }
211#endif
nstrazffe35e22001-03-13 16:33:54 +0000212
213 /*
214 * Change the group on this temporary directory to be that of the
robbiewca11e712004-08-25 05:07:02 +0000215 * gid of the person running the tests and permissions to 777.
nstrazffe35e22001-03-13 16:33:54 +0000216 */
217 if ( chown(TESTDIR, -1, getgid()) == -1 )
plars8f4232f2002-09-04 18:40:11 +0000218 tst_brkm(TBROK, tmpdir_cleanup,
219 "chown(%s, -1, %d) failed; errno = %d: %s",
220 TESTDIR, getgid(), errno, strerror(errno));
robbiewca11e712004-08-25 05:07:02 +0000221 if ( chmod(TESTDIR,S_IRWXU | S_IRWXG | S_IRWXO) == -1 )
222 tst_brkm(TBROK, tmpdir_cleanup,
223 "chmod(%s,777) failed; errno %d: %s",
224 TESTDIR, errno, strerror(errno));
nstrazffe35e22001-03-13 16:33:54 +0000225 }
alaffincc2e5552000-07-27 17:13:18 +0000226
227#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000228 printf("TESTDIR = %s\n", TESTDIR);
alaffincc2e5552000-07-27 17:13:18 +0000229#endif
230
nstrazffe35e22001-03-13 16:33:54 +0000231 /*
232 * Change to the temporary directory. If the chdir() fails, issue
233 * TBROK messages for all test cases, attempt to remove the
234 * directory (if it was created), and exit. If the removal also
235 * fails, also issue a TWARN message.
236 */
237 if ( chdir(TESTDIR) == -1 ) {
238 tst_brkm(TBROK, NULL, "%s: chdir(%s) failed; errno = %d: %s",
plars8f4232f2002-09-04 18:40:11 +0000239 FN_NAME, TESTDIR, errno, strerror(errno) );
alaffincc2e5552000-07-27 17:13:18 +0000240
nstrazffe35e22001-03-13 16:33:54 +0000241 /* Try to remove the directory */
242 if ( !no_cleanup && rmdir(TESTDIR) == -1 )
243 tst_resm(TWARN, "%s: rmdir(%s) failed; errno = %d: %s",
plars8f4232f2002-09-04 18:40:11 +0000244 FN_NAME, TESTDIR, errno, strerror(errno) );
alaffincc2e5552000-07-27 17:13:18 +0000245
nstrazffe35e22001-03-13 16:33:54 +0000246 tmpdir_cleanup();
247 }
248
alaffincc2e5552000-07-27 17:13:18 +0000249#if UNIT_TEST
nstrazffe35e22001-03-13 16:33:54 +0000250 printf("CWD is %s\n", getcwd((char *)NULL, PATH_MAX));
alaffincc2e5552000-07-27 17:13:18 +0000251#endif
252
nstrazffe35e22001-03-13 16:33:54 +0000253 /*
254 * If we made through all this stuff, return.
255 */
256 return;
alaffincc2e5552000-07-27 17:13:18 +0000257} /* tst_tmpdir() */
258
259
260/*
261 *
262 * tst_rmdir() - Recursively remove the temporary directory created by
263 * tst_tmpdir(). This function is intended ONLY as a
264 * companion to tst_tmpdir(). If the TDIRECTORY
265 * environment variable is set, no cleanup will be
266 * attempted.
267 */
268#undef FN_NAME
269#define FN_NAME "tst_rmdir()"
270
271void
272tst_rmdir()
273{
274 char *errmsg;
275 char *tdirectory;
276 char current_dir[PATH_MAX]; /* current working directory */
277 char parent_dir[PATH_MAX]; /* directory above TESTDIR */
278 char *basename; /* basename of the TESTDIR */
279
280 /*
281 * If the TDIRECTORY env variable is set, this indicates that no
282 * temp dir was created by tst_tmpdir(). Thus no cleanup will be
283 * necessary.
284 */
285 if ( (tdirectory = getenv(TDIRECTORY)) != NULL ) {
286#if UNIT_TEST
287 printf("\"TDIRECORY\" env variable is set; no cleanup was performed\n");
288#endif
289 return;
290 }
291
292 /*
293 * Check that TESTDIR is not NULL.
294 */
295 if ( TESTDIR == NULL ) {
296 tst_resm(TWARN, "%s: TESTDIR was NULL; no removal attempted",
297 FN_NAME);
298 return;
299 }
300
301 /*
302 * Check that the value of TESTDIR is not "*" or "/". These could
303 * have disastrous effects in a test run by root.
304 */
305 if ( strcmp(TESTDIR, "/") == 0 ) {
306 tst_resm(TWARN,
307 "%s: Recursive remove of root directory not attempted",
308 FN_NAME);
309 return;
310 }
311
312 if ( strchr(TESTDIR, '*') != NULL ) {
313 tst_resm(TWARN, "%s: Recursive remove of '*' not attempted",
314 FN_NAME);
315 return;
316 }
317
318 /*
319 * Get the directory name of TESTDIR. If TESTDIR is a relative path,
320 * get full path.
321 */
322 if ( TESTDIR[0] != '/' ) {
323 if ( getcwd(current_dir,PATH_MAX) == NULL )
324 strcpy(parent_dir, TESTDIR);
325 else
326 sprintf(parent_dir, "%s/%s", current_dir, TESTDIR);
327 } else {
328 strcpy(parent_dir, TESTDIR);
329 }
330 if ( (basename = strrchr(parent_dir, '/')) != NULL ) {
331 *basename='\0'; /* terminate at end of parent_dir */
332 }
333
334 /*
335 * Change directory to parent_dir (The dir above TESTDIR).
336 */
337 if ( chdir(parent_dir) != 0 )
338 tst_resm(TWARN,
339 "%s: chdir(%s) failed; errno = %d: %s\nAttempting to remove temp dir anyway",
340 FN_NAME, parent_dir, errno, strerror(errno));
341
342 /*
343 * Attempt to remove the "TESTDIR" directory, using rmobj().
344 */
345 if ( rmobj(TESTDIR, &errmsg) == -1 )
346 tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
347 FN_NAME, TESTDIR, errmsg);
348
349 return;
350} /* tst_rmdir() */
351
352
353/*
354 * tmpdir_cleanup() - This function is used when tst_tmpdir()
355 * encounters an error, and must cleanup and exit.
356 * It prints a warning message via tst_resm(), and
357 * then calls tst_exit().
358 */
359#undef FN_NAME
360#define FN_NAME "tst_tmpdir()"
361
362static void
363tmpdir_cleanup()
364{
365 /*
366 * Print a warning message and call tst_exit() to exit the test.
367 */
368 tst_resm(TWARN, "%s: No user cleanup function called before exiting",
369 FN_NAME);
370 tst_exit();
371} /* tmpdir_cleanup() */
372
373
374#ifdef UNIT_TEST
375/****************************************************************************
376 * Unit test code: Takes input from stdin and can make the following
377 * calls: tst_tmpdir(), tst_rmdir().
378 ****************************************************************************/
379int TST_TOTAL = 10;
380char *TCID = "TESTTCID";
381
382main()
383{
384 int option;
385 char *chrptr;
386
387 printf("UNIT TEST of tst_tmpdir.c. Options to try:\n\
388 -1 : call tst_exit()\n\
389 0 : call tst_tmpdir()\n\
390 1 : call tst_rmdir()\n\n");
391
392 while ( 1 ) {
393 printf("Enter options (-1, 0, 1): ");
394 (void) scanf("%d%c", &option, &chrptr);
395
396 switch ( option ) {
397 case -1:
398 tst_exit();
399 break;
400
401 case 0:
402 tst_tmpdir();
403 break;
404
405 case 1:
406 tst_rmdir();
407 break;
408 } /* switch() */
409 } /* while() */
410}
411#endif /* UNIT_TEST */