--- a
+++ b/lib/rmobj.c
@@ -0,0 +1,210 @@
+/*
+ * 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: rmobj.c,v 1.1 2000/07/27 17:13:18 alaffin Exp $ */
+
+/**********************************************************
+ *
+ *    OS Testing - Silicon Graphics, Inc.
+ *
+ *    FUNCTION NAME     : rmobj()
+ *
+ *    FUNCTION TITLE    : Remove an object
+ *
+ *    SYNOPSIS:
+ *      int rmobj(char *obj, char **errmsg)
+ *
+ *    AUTHOR            : Kent Rogers
+ *
+ *    INITIAL RELEASE   : UNICOS 7.0
+ *
+ *    USER DESCRIPTION
+ *      This routine will remove the specified object.  If the specified
+ *      object is a directory, it will recursively remove the directory
+ *      and everything underneath it.  It assumes that it has privilege
+ *      to remove everything that it tries to remove.  If rmobj() encounters
+ *      any problems, and errmsg is not NULL, errmsg is set to point to a
+ *      string explaining the error.
+ *
+ *    DETAILED DESCRIPTION
+ *      Allocate space for the directory and its contents
+ *      Open the directory to get access to what is in it
+ *      Loop through the objects in the directory:
+ *        If the object is not "." or "..":
+ *          Determine the file type by calling lstat()
+ *          If the object is not a directory:
+ *            Remove the object with unlink()
+ *         Else:
+ *            Call rmobj(object) to remove the object's contents
+ *            Determine the link count on object by calling lstat()
+ *            If the link count >= 3:
+ *              Remove the directory with unlink()
+ *            Else
+ *               Remove the directory with rmdir()
+ *      Close the directory and free the pointers
+ *
+ *    RETURN VALUE
+ *      If there are any problems, rmobj() will set errmsg (if it was not
+ *      NULL) and return -1.  Otherwise it will return 0.
+ *
+ ************************************************************/
+#include <errno.h>         /* for errno */
+#include <stdio.h>         /* for NULL */
+#include <stdlib.h>        /* for malloc() */
+#include <string.h>        /* for string function */
+#include <limits.h>        /* for PATH_MAX */
+#include <sys/types.h>     /* for opendir(), readdir(), closedir(), stat() */
+#include <sys/stat.h>      /* for [l]stat() */
+#include <dirent.h>        /* for opendir(), readdir(), closedir() */
+#include "rmobj.h"
+
+#define SYSERR strerror(errno)
+
+int
+rmobj(char *obj, char **errmsg)
+{
+   int           ret_val = 0;       /* return value from this routine */
+   DIR           *dir;              /* pointer to a directory */
+   struct dirent *dir_ent;          /* pointer to directory entries */
+   char          dirobj[PATH_MAX];  /* object inside directory to modify */
+   struct stat   statbuf;           /* used to hold stat information */
+   static char   err_msg[1024];     /* error message */
+
+   /* Determine the file type */
+   if ( lstat(obj, &statbuf) < 0 ) {
+      if ( errmsg != NULL ) {
+         sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
+                 obj, errno, SYSERR);
+         *errmsg = err_msg;
+      }
+      return -1;
+   }
+
+   /* Take appropriate action, depending on the file type */
+   if ( (statbuf.st_mode & S_IFMT) == S_IFDIR ) {
+      /* object is a directory */
+
+      /* Do NOT perform the request if the directory is "/" */
+      if ( !strcmp(obj, "/") ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "Cannot remove /");
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+
+      /* Open the directory to get access to what is in it */
+      if ( (dir = opendir(obj)) == NULL ) {
+         if ( rmdir(obj) != 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "rmdir(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         } else {
+            return 0;
+         }
+      }
+
+      /* Loop through the entries in the directory, removing each one */
+      for ( dir_ent = (struct dirent *)readdir(dir);
+            dir_ent != NULL;
+            dir_ent = (struct dirent *)readdir(dir)) {
+
+         /* Don't remove "." or ".." */
+         if ( !strcmp(dir_ent->d_name, ".") || !strcmp(dir_ent->d_name, "..") )
+            continue;
+
+         /* Recursively call this routine to remove the current entry */
+         sprintf(dirobj, "%s/%s", obj, dir_ent->d_name);
+         if ( rmobj(dirobj, errmsg) != 0 )
+            ret_val = -1;
+      }
+
+      /* Close the directory */
+      closedir(dir);
+
+      /* If there were problems removing an entry, don't attempt to
+         remove the directory itself */
+      if ( ret_val == -1 )
+         return -1;
+
+      /* Get the link count, now that all the entries have been removed */
+      if ( lstat(obj, &statbuf) < 0 ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
+                    obj, errno, SYSERR);
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+
+      /* Remove the directory itself */
+      if ( statbuf.st_nlink >= 3 ) {
+         /* The directory is linked; unlink() must be used */
+         if ( unlink(obj) < 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         }
+      } else {
+         /* The directory is not linked; rmdir() can be used */
+         if ( rmdir(obj) < 0 ) {
+            if ( errmsg != NULL ) {
+               sprintf(err_msg, "rmdir(%s) failed; errno=%d: %s",
+                       obj, errno, SYSERR);
+               *errmsg = err_msg;
+            }
+            return -1;
+         }
+      }
+   } else {
+      /* object is not a directory; just use unlink() */
+      if ( unlink(obj) < 0 ) {
+         if ( errmsg != NULL ) {
+            sprintf(err_msg, "unlink(%s) failed; errno=%d: %s",
+                    obj, errno, SYSERR);
+            *errmsg = err_msg;
+         }
+         return -1;
+      }
+   }  /* if obj is a directory */
+
+   /*
+    * Everything must have went ok.
+    */
+   return 0;
+}  /* rmobj() */