2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
33 /* $Id: tst_tmpdir.c,v 1.14 2009/07/20 10:59:32 vapier Exp $ */
35 /**********************************************************
37 * OS Testing - Silicon Graphics, Inc.
39 * FUNCTION NAME : tst_tmpdir, tst_rmdir
41 * FUNCTION TITLE : Create/remove a testing temp dir
47 * AUTHOR : Dave Fenner
49 * INITIAL RELEASE : UNICOS 8.0
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
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
63 * Neither tst_tmpdir() or tst_rmdir() has a return value.
65 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
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() */
77 * Define some useful macros.
80 #define STRING_SIZE 256
81 #define DIR_MODE 0777 /* mode of tmp dir that will be created */
85 #define PATH_MAX MAXPATHLEN
92 * Define function prototypes.
94 static void tmpdir_cleanup();
97 * Define global variables.
99 extern char *TCID
; /* defined/initialized in main() */
100 extern int TST_TOTAL
; /* defined/initialized in main() */
101 extern char *TESTDIR
; /* the directory created; defined in */
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.
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
117 #define FN_NAME "tst_tmpdir()"
119 void tst_tmpdir(void)
121 char template[PATH_MAX
]; /* template for mkstemp, mkdtemp */
122 int no_cleanup
= 0; /* !0 means TDIRECTORY env var was set */
123 char *env_tmpdir
; /* temporary storage for TMPDIR env var */
124 /* This is an AWEFUL hack to figure out if mkdtemp() is available */
125 #if defined(__GLIBC_PREREQ)
126 # if __GLIBC_PREREQ(2,2)
127 # define HAVE_MKDTEMP 1
129 # define HAVE_MKDTEMP 0
133 # define HAVE_MKDTEMP 0
137 * If the TDIRECTORY env variable is not set, a temp dir will be
140 if ((TESTDIR
= getenv(TDIRECTORY
))) {
142 * The TDIRECTORY env. variable is set, so no temp dir is created.
143 * Also, no clean up will be done via tst_rmdir().
145 mkdir(TESTDIR
,DIR_MODE
); /*Try to create the directory if it does not exist already,
146 user might forget to create one before exporting TDIRECTORY,
147 Will fail if it already exists, no issues in that*/
150 printf("TDIRECTORY env var is set\n");
154 * Create a template for the temporary directory. Use the
155 * environment variable TMPDIR if it is available, otherwise
156 * use our default TEMPDIR.
158 if ((env_tmpdir
= getenv("TMPDIR"))) {
159 snprintf(template, PATH_MAX
, "%s/%.3sXXXXXX", env_tmpdir
, TCID
);
161 snprintf(template, PATH_MAX
, "%s/%.3sXXXXXX", TEMPDIR
, TCID
);
167 * Make the temporary directory in one shot using mkdtemp()
169 if (mkdtemp(template) == NULL
)
170 tst_brkm(TBROK
, tmpdir_cleanup
,
171 "%s: mkdtemp(%s) failed; errno = %d: %s",
172 FN_NAME
, template, errno
, strerror(errno
));
173 if ( (TESTDIR
= strdup(template)) == NULL
) { //Error Handling for strdup()
174 tst_brkm(TBROK
, tmpdir_cleanup
,
175 "%s: strdup(%s) failed; errno = %d: %s",
176 FN_NAME
, template, errno
, strerror(errno
));
180 * Make the template name, then the directory
182 if ((tfd
= mkstemp(template)) == -1)
183 tst_brkm(TBROK
, tmpdir_cleanup
,
184 "%s: mkstemp(%s) failed; errno = %d: %s",
185 FN_NAME
, template, errno
, strerror(errno
));
186 if ( close(tfd
) == -1 ) {
187 tst_brkm(TBROK
, tmpdir_cleanup
,
188 "%s: close() failed; errno = %d: %s",
189 FN_NAME
, errno
, strerror(errno
));
191 if ( unlink(template) == -1) {
192 tst_brkm(TBROK
, tmpdir_cleanup
,
193 "%s: unlink(%s) failed; errno = %d: %s",
194 FN_NAME
, template, errno
, strerror(errno
));
196 if ( (TESTDIR
= strdup(template)) == NULL
) {
197 tst_brkm(TBROK
, tmpdir_cleanup
,
198 "%s: strdup(%s) failed; errno = %d: %s",
199 FN_NAME
, template, errno
, strerror(errno
));
201 if (mkdir(TESTDIR
, DIR_MODE
)) {
202 /* If we start failing with EEXIST, wrap this section in
203 * a loop so we can try again.
205 tst_brkm(TBROK
, tmpdir_cleanup
,
206 "%s: mkdir(%s, %#o) failed; errno = %d: %s",
207 FN_NAME
, TESTDIR
, DIR_MODE
, errno
,
213 * Change the group on this temporary directory to be that of the
214 * gid of the person running the tests and permissions to 777.
216 if ( chown(TESTDIR
, -1, getgid()) == -1 )
217 tst_brkm(TBROK
, tmpdir_cleanup
,
218 "chown(%s, -1, %d) failed; errno = %d: %s",
219 TESTDIR
, getgid(), errno
, strerror(errno
));
220 if ( chmod(TESTDIR
,S_IRWXU
| S_IRWXG
| S_IRWXO
) == -1 )
221 tst_brkm(TBROK
, tmpdir_cleanup
,
222 "chmod(%s,777) failed; errno %d: %s",
223 TESTDIR
, errno
, strerror(errno
));
227 printf("TESTDIR = %s\n", TESTDIR
);
231 * Change to the temporary directory. If the chdir() fails, issue
232 * TBROK messages for all test cases, attempt to remove the
233 * directory (if it was created), and exit. If the removal also
234 * fails, also issue a TWARN message.
236 if ( chdir(TESTDIR
) == -1 ) {
237 tst_brkm(TBROK
, NULL
, "%s: chdir(%s) failed; errno = %d: %s",
238 FN_NAME
, TESTDIR
, errno
, strerror(errno
) );
240 /* Try to remove the directory */
241 if ( !no_cleanup
&& rmdir(TESTDIR
) == -1 )
242 tst_resm(TWARN
, "%s: rmdir(%s) failed; errno = %d: %s",
243 FN_NAME
, TESTDIR
, errno
, strerror(errno
) );
249 printf("CWD is %s\n", getcwd((char *)NULL
, PATH_MAX
));
253 * If we made through all this stuff, return.
261 * tst_rmdir() - Recursively remove the temporary directory created by
262 * tst_tmpdir(). This function is intended ONLY as a
263 * companion to tst_tmpdir(). If the TDIRECTORY
264 * environment variable is set, no cleanup will be
268 #define FN_NAME "tst_rmdir()"
274 char current_dir
[PATH_MAX
]; /* current working directory */
275 char parent_dir
[PATH_MAX
]; /* directory above TESTDIR */
276 char *basename
; /* basename of the TESTDIR */
279 * If the TDIRECTORY env variable is set, this indicates that no
280 * temp dir was created by tst_tmpdir(). Thus no cleanup will be
283 if ( (tdirectory
= getenv(TDIRECTORY
)) != NULL
) {
285 printf("\"TDIRECORY\" env variable is set; no cleanup was performed\n");
291 * Check that TESTDIR is not NULL.
293 if ( TESTDIR
== NULL
) {
294 tst_resm(TWARN
, "%s: TESTDIR was NULL; no removal attempted",
300 * Check that the value of TESTDIR is not "*" or "/". These could
301 * have disastrous effects in a test run by root.
303 if ( strcmp(TESTDIR
, "/") == 0 ) {
305 "%s: Recursive remove of root directory not attempted",
310 if ( strchr(TESTDIR
, '*') != NULL
) {
311 tst_resm(TWARN
, "%s: Recursive remove of '*' not attempted",
317 * Get the directory name of TESTDIR. If TESTDIR is a relative path,
320 if ( TESTDIR
[0] != '/' ) {
321 if ( getcwd(current_dir
,PATH_MAX
) == NULL
)
322 strcpy(parent_dir
, TESTDIR
);
324 sprintf(parent_dir
, "%s/%s", current_dir
, TESTDIR
);
326 strcpy(parent_dir
, TESTDIR
);
328 if ( (basename
= strrchr(parent_dir
, '/')) != NULL
) {
329 *basename
='\0'; /* terminate at end of parent_dir */
333 * Change directory to parent_dir (The dir above TESTDIR).
335 if ( chdir(parent_dir
) != 0 )
337 "%s: chdir(%s) failed; errno = %d: %s\nAttempting to remove temp dir anyway",
338 FN_NAME
, parent_dir
, errno
, strerror(errno
));
341 * Attempt to remove the "TESTDIR" directory, using rmobj().
343 if ( rmobj(TESTDIR
, &errmsg
) == -1 )
344 tst_resm(TWARN
, "%s: rmobj(%s) failed: %s",
345 FN_NAME
, TESTDIR
, errmsg
);
352 * tmpdir_cleanup() - This function is used when tst_tmpdir()
353 * encounters an error, and must cleanup and exit.
354 * It prints a warning message via tst_resm(), and
355 * then calls tst_exit().
358 #define FN_NAME "tst_tmpdir()"
364 * Print a warning message and call tst_exit() to exit the test.
366 tst_resm(TWARN
, "%s: No user cleanup function called before exiting",
369 } /* tmpdir_cleanup() */
373 /****************************************************************************
374 * Unit test code: Takes input from stdin and can make the following
375 * calls: tst_tmpdir(), tst_rmdir().
376 ****************************************************************************/
378 char *TCID
= "TESTTCID";
385 printf("UNIT TEST of tst_tmpdir.c. Options to try:\n\
386 -1 : call tst_exit()\n\
387 0 : call tst_tmpdir()\n\
388 1 : call tst_rmdir()\n\n");
391 printf("Enter options (-1, 0, 1): ");
392 (void) scanf("%d%c", &option
, &chrptr
);
409 #endif /* UNIT_TEST */