text: /*
   * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
   * 
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2 of the GNU General Public License as
   * published by the Free Software Foundation.
   * 
   * This program is distributed in the hope that it would be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   * 
   * Further, this software is distributed without any warranty that it is
   * free of the rightful claim of any third person regarding infringement
   * or the like.  Any license provided herein, whether implied or
   * otherwise, applies only to this software file.  Patent licenses, if
   * any, provided herein do not apply to combinations of this program with
   * other software, or any other product whatsoever.
   * 
   * You should have received a copy of the GNU General Public License along
   * with this program; if not, write the Free Software Foundation, Inc., 59
   * Temple Place - Suite 330, Boston MA 02111-1307, USA.
   * 
   * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
   * Mountain View, CA  94043, or:
   * 
   * http://www.sgi.com 
   * 
   * For further information regarding this notice, see: 
   * 
   * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
   */
  
  /* $Id$ */
  
  /**********************************************************
   *
   *    OS Testing - Silicon Graphics, Inc.
   *
   *    FUNCTION NAME     : tst_tmpdir, tst_rmdir
   *
   *    FUNCTION TITLE    : Create/remove a testing temp dir
   *
   *    SYNOPSIS:
   *      void tst_tmpdir();
   *      void tst_rmdir();
   *
   *    AUTHOR            : Dave Fenner
   *
   *    INITIAL RELEASE   : UNICOS 8.0
   *
   *    DESCRIPTION
   *      tst_tmpdir() is used to create a unique, temporary testing
   *      directory, and make it the current working directory.
   *      tst_rmdir() is used to remove the directory created by
   *      tst_tmpdir().
   *
   *      Setting the env variable "TDIRECTORY" will override the creation
   *      of a new temp dir.  The directory specified by TDIRECTORY will
   *      be used as the temporary directory, and no removal will be done
   *      in tst_rmdir().
   *
   *    RETURN VALUE
   *      Neither tst_tmpdir() or tst_rmdir() has a return value.
   *
   *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
  #include <errno.h>
  #include <sys/types.h>     /* for mkdir() */
  #include <sys/stat.h>      /* for mkdir() */
  #include "test.h"
  #include "rmobj.h"
  
  /*
   * Define some useful macros.
   */
  #define PREFIX_SIZE     4
  #define STRING_SIZE     256
  #define DIR_MODE        0777  /* mode of tmp dir that will be created */
  
  #ifndef PATH_MAX
  #ifdef MAXPATHLEN
  #define PATH_MAX MAXPATHLEN
  #else
  #define PATH_MAX 1024
  #endif
  #endif
  
  /*
   * Define function prototypes.
   */
  static void tmpdir_cleanup();
  
  /*
   * Define global variables.
   */
  extern char *TCID;            /* defined/initialized in main() */
  extern int  TST_TOTAL;        /* defined/initialized in main() */
  extern char *TESTDIR;         /* the directory created; defined in */
                                /* tst_res.c */
  
  /*
   * tst_tmpdir() - Create a unique temporary directory and chdir() to it.
   *                It expects the caller to have defined/initialized the
   *                TCID/TST_TOTAL global variables.  The TESTDIR global
   *                variable will be set to the directory that gets used
   *                as the testing directory.
   *
   *                NOTE: This function must be called BEFORE any activity
   *                that would require CLEANUP.  If tst_tmpdir() fails, it
   *                cleans up afer itself and calls tst_exit() (i.e. does
   *                not return).
   */
  #undef   FN_NAME
  #define  FN_NAME  "tst_tmpdir()"
  
  void
  tst_tmpdir()
  {
     char prefix[PREFIX_SIZE];     /* first three characters from TCID */
     int  no_cleanup = 0;          /* !0 means TDIRECTORY env var was set */
  
     /*
      * If the TDIRECTORY env variable is not set, a temp dir will be
      * created.
      */
     if ( (TESTDIR = getenv(TDIRECTORY)) == NULL ) {
        /*
         * Create a unique name based on the first three characters of the
         * TCID.  The last byte in "prefix" is for the null.
         */
        strncpy(prefix, TCID, PREFIX_SIZE - 1);
        prefix[PREFIX_SIZE-1] = '\0';
        if ( (TESTDIR = tempnam(TEMPDIR, prefix)) == NULL )
           tst_brkm(TBROK, tmpdir_cleanup, "%s: tempnam(%s, %s) failed",
                    FN_NAME, TEMPDIR, prefix);
  
        /*
         * Create the temporary directory.
         */
        if ( mkdir(TESTDIR, DIR_MODE) == -1 )
           tst_brkm(TBROK, tmpdir_cleanup,
                    "%s: mkdir(%s, %#o) failed; errno = %d: %s", 
                    FN_NAME, TESTDIR, DIR_MODE, errno, strerror(errno));
  
        /*
         * Change the group on this temporary directory to be that of the
         * gid of the person running the tests.
         */
        if ( chown(TESTDIR, -1, getgid()) == -1 )
           tst_brkm(TBROK, tmpdir_cleanup,
                    "chown(%s, -1, %d) failed; errno = %d: %s", 
                    TESTDIR, getgid(), errno, strerror(errno));
     } else {
        /*
         * The TDIRECTORY env. variable is set, so no temp dir is created.
         * Also, no clean up will be done via tst_rmdir().
         */
        no_cleanup++;
  #if UNIT_TEST
        printf("TDIRECTORY env var is set\n");
  #endif
     }
  
  #if UNIT_TEST
        printf("TESTDIR = %s\n", TESTDIR);
  #endif
  
     /*
      * Change to the temporary directory.  If the chdir() fails, issue
      * TBROK messages for all test cases, attempt to remove the
      * directory (if it was created), and exit.  If the removal also
      * fails, also issue a TWARN message.   
      */
     if ( chdir(TESTDIR) == -1 ) {
        tst_brkm(TBROK, NULL, "%s: chdir(%s) failed; errno = %d: %s",
                 FN_NAME, TESTDIR, errno, strerror(errno) );
  
        /* Try to remove the directory */
        if ( !no_cleanup && rmdir(TESTDIR) == -1 )
           tst_resm(TWARN, "%s: rmdir(%s) failed; errno = %d: %s",
                    FN_NAME, TESTDIR, errno, strerror(errno) );
  
        tmpdir_cleanup();
     }
  
  #if UNIT_TEST
     printf("CWD is %s\n", getcwd((char *)NULL, PATH_MAX));
  #endif
  
     /*
      *  If we made through all this stuff, return.
      */
     return;
  }  /* tst_tmpdir() */
  
  
  /*
   *
   * tst_rmdir() - Recursively remove the temporary directory created by
   *               tst_tmpdir().  This function is intended ONLY as a
   *               companion to tst_tmpdir().  If the TDIRECTORY
   *               environment variable is set, no cleanup will be
   *               attempted.
   */ 
  #undef   FN_NAME
  #define  FN_NAME  "tst_rmdir()"
  
  void
  tst_rmdir()
  {
     char *errmsg;
     char *tdirectory;
     char current_dir[PATH_MAX];   /* current working directory */
     char parent_dir[PATH_MAX];    /* directory above TESTDIR */
     char *basename;               /* basename of the TESTDIR */
  
     /*
      * If the TDIRECTORY env variable is set, this indicates that no
      * temp dir was created by tst_tmpdir().  Thus no cleanup will be
      * necessary.
      */
     if ( (tdirectory = getenv(TDIRECTORY)) != NULL ) {
  #if UNIT_TEST
        printf("\"TDIRECORY\" env variable is set; no cleanup was performed\n");
  #endif
        return;
     }
     
     /*
      * Check that TESTDIR is not NULL.
      */
     if ( TESTDIR == NULL ) {
        tst_resm(TWARN, "%s: TESTDIR was NULL; no removal attempted",
                 FN_NAME);
        return;
     }
  
     /*
      * Check that the value of TESTDIR is not "*" or "/".  These could
      * have disastrous effects in a test run by root.
      */
     if ( strcmp(TESTDIR, "/") == 0 ) {
        tst_resm(TWARN,
                 "%s: Recursive remove of root directory not attempted",
                 FN_NAME);
        return;
     }
  
     if ( strchr(TESTDIR, '*') != NULL ) {
        tst_resm(TWARN, "%s: Recursive remove of '*' not attempted",
                 FN_NAME);
        return;
     }
  
     /*
      * Get the directory name of TESTDIR.  If TESTDIR is a relative path,
      * get full path.
      */
     if ( TESTDIR[0] != '/' ) {
        if ( getcwd(current_dir,PATH_MAX) == NULL )
           strcpy(parent_dir, TESTDIR);
        else
           sprintf(parent_dir, "%s/%s", current_dir, TESTDIR);
     } else {
        strcpy(parent_dir, TESTDIR);
     }
     if ( (basename = strrchr(parent_dir, '/')) != NULL ) {
        *basename='\0';   /* terminate at end of parent_dir */
     }
  
     /*
      * Change directory to parent_dir (The dir above TESTDIR).
      */
     if ( chdir(parent_dir) != 0 )
        tst_resm(TWARN,
                 "%s: chdir(%s) failed; errno = %d: %s\nAttempting to remove temp dir anyway",
                 FN_NAME, parent_dir, errno, strerror(errno));
     
     /*
      * Attempt to remove the "TESTDIR" directory, using rmobj().
      */
     if ( rmobj(TESTDIR, &errmsg) == -1 )
        tst_resm(TWARN, "%s: rmobj(%s) failed: %s",
                 FN_NAME, TESTDIR, errmsg);
  
     return;
  }  /* tst_rmdir() */
  
  
  /*
   * tmpdir_cleanup() - This function is used when tst_tmpdir()
   *                    encounters an error, and must cleanup and exit.
   *                    It prints a warning message via tst_resm(), and
   *                    then calls tst_exit().
   */
  #undef  FN_NAME
  #define FN_NAME "tst_tmpdir()"
  
  static void
  tmpdir_cleanup()
  {
     /*
      * Print a warning message and call tst_exit() to exit the test.
      */
     tst_resm(TWARN, "%s: No user cleanup function called before exiting",
              FN_NAME);
     tst_exit();
  }  /* tmpdir_cleanup() */
  
  
  #ifdef UNIT_TEST
  /****************************************************************************
   * Unit test code: Takes input from stdin and can make the following
   *                 calls: tst_tmpdir(), tst_rmdir().
   ****************************************************************************/
  int  TST_TOTAL = 10;
  char *TCID = "TESTTCID";
  
  main()
  {
     int  option;
     char *chrptr;
  
     printf("UNIT TEST of tst_tmpdir.c.  Options to try:\n\
     -1 : call tst_exit()\n\
      0 : call tst_tmpdir()\n\
      1 : call tst_rmdir()\n\n");
  
     while ( 1 ) {
        printf("Enter options (-1, 0, 1): ");
        (void) scanf("%d%c", &option, &chrptr);
  
        switch ( option ) {
        case -1:
           tst_exit();
           break;
  
        case 0:
           tst_tmpdir();
           break;
  
        case 1:
           tst_rmdir();
           break;
        }  /* switch() */
     }  /* while() */
  }
  #endif  /* UNIT_TEST */
  