blob: 9b6a6430e09ee1da37cc45534c2a517a590f0571 [file] [log] [blame]
alaffincc2e5552000-07-27 17:13:18 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
vapier45a8ba02009-07-20 10:59:32 +00003 *
alaffincc2e5552000-07-27 17:13:18 +00004 * 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.
vapier45a8ba02009-07-20 10:59:32 +00007 *
alaffincc2e5552000-07-27 17:13:18 +00008 * 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.
vapier45a8ba02009-07-20 10:59:32 +000011 *
alaffincc2e5552000-07-27 17:13:18 +000012 * 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.
vapier45a8ba02009-07-20 10:59:32 +000018 *
alaffincc2e5552000-07-27 17:13:18 +000019 * You should have received a copy of the GNU General Public License along
Wanlong Gaofed96412012-10-24 10:10:29 +080020 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
vapier45a8ba02009-07-20 10:59:32 +000022 *
alaffincc2e5552000-07-27 17:13:18 +000023 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
vapier45a8ba02009-07-20 10:59:32 +000025 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
alaffincc2e5552000-07-27 17:13:18 +000030 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 */
32
vapier45a8ba02009-07-20 10:59:32 +000033/* $Id: rmobj.c,v 1.5 2009/07/20 10:59:32 vapier Exp $ */
alaffincc2e5552000-07-27 17:13:18 +000034
35/**********************************************************
36 *
37 * OS Testing - Silicon Graphics, Inc.
38 *
39 * FUNCTION NAME : rmobj()
40 *
41 * FUNCTION TITLE : Remove an object
42 *
43 * SYNOPSIS:
44 * int rmobj(char *obj, char **errmsg)
45 *
46 * AUTHOR : Kent Rogers
47 *
48 * INITIAL RELEASE : UNICOS 7.0
49 *
50 * USER DESCRIPTION
51 * This routine will remove the specified object. If the specified
52 * object is a directory, it will recursively remove the directory
53 * and everything underneath it. It assumes that it has privilege
54 * to remove everything that it tries to remove. If rmobj() encounters
55 * any problems, and errmsg is not NULL, errmsg is set to point to a
56 * string explaining the error.
57 *
58 * DETAILED DESCRIPTION
59 * Allocate space for the directory and its contents
60 * Open the directory to get access to what is in it
61 * Loop through the objects in the directory:
62 * If the object is not "." or "..":
63 * Determine the file type by calling lstat()
64 * If the object is not a directory:
65 * Remove the object with unlink()
66 * Else:
67 * Call rmobj(object) to remove the object's contents
68 * Determine the link count on object by calling lstat()
69 * If the link count >= 3:
70 * Remove the directory with unlink()
71 * Else
72 * Remove the directory with rmdir()
73 * Close the directory and free the pointers
74 *
75 * RETURN VALUE
76 * If there are any problems, rmobj() will set errmsg (if it was not
77 * NULL) and return -1. Otherwise it will return 0.
78 *
79 ************************************************************/
Wanlong Gao354ebb42012-12-07 10:10:04 +080080#include <errno.h> /* for errno */
81#include <stdio.h> /* for NULL */
82#include <stdlib.h> /* for malloc() */
83#include <string.h> /* for string function */
84#include <limits.h> /* for PATH_MAX */
85#include <sys/types.h> /* for opendir(), readdir(), closedir(), stat() */
86#include <sys/stat.h> /* for [l]stat() */
87#include <dirent.h> /* for opendir(), readdir(), closedir() */
88#include <unistd.h> /* for rmdir(), unlink() */
alaffincc2e5552000-07-27 17:13:18 +000089#include "rmobj.h"
90
91#define SYSERR strerror(errno)
92
Wanlong Gao354ebb42012-12-07 10:10:04 +080093int rmobj(char *obj, char **errmsg)
alaffincc2e5552000-07-27 17:13:18 +000094{
Wanlong Gao354ebb42012-12-07 10:10:04 +080095 int ret_val = 0; /* return value from this routine */
96 DIR *dir; /* pointer to a directory */
97 struct dirent *dir_ent; /* pointer to directory entries */
98 char dirobj[PATH_MAX]; /* object inside directory to modify */
99 struct stat statbuf; /* used to hold stat information */
100 static char err_msg[1024]; /* error message */
alaffincc2e5552000-07-27 17:13:18 +0000101
Wanlong Gao354ebb42012-12-07 10:10:04 +0800102 /* Determine the file type */
103 if (lstat(obj, &statbuf) < 0) {
104 if (errmsg != NULL) {
105 sprintf(err_msg, "lstat(%s) failed; errno=%d: %s",
106 obj, errno, SYSERR);
107 *errmsg = err_msg;
108 }
109 return -1;
110 }
alaffincc2e5552000-07-27 17:13:18 +0000111
Wanlong Gao354ebb42012-12-07 10:10:04 +0800112 /* Take appropriate action, depending on the file type */
113 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
114 /* object is a directory */
alaffincc2e5552000-07-27 17:13:18 +0000115
Wanlong Gao354ebb42012-12-07 10:10:04 +0800116 /* Do NOT perform the request if the directory is "/" */
117 if (!strcmp(obj, "/")) {
118 if (errmsg != NULL) {
119 sprintf(err_msg, "Cannot remove /");
120 *errmsg = err_msg;
121 }
122 return -1;
123 }
alaffincc2e5552000-07-27 17:13:18 +0000124
Wanlong Gao354ebb42012-12-07 10:10:04 +0800125 /* Open the directory to get access to what is in it */
126 if ((dir = opendir(obj)) == NULL) {
127 if (rmdir(obj) != 0) {
128 if (errmsg != NULL) {
129 sprintf(err_msg,
130 "rmdir(%s) failed; errno=%d: %s",
131 obj, errno, SYSERR);
132 *errmsg = err_msg;
133 }
134 return -1;
135 } else {
136 return 0;
137 }
138 }
alaffincc2e5552000-07-27 17:13:18 +0000139
Wanlong Gao354ebb42012-12-07 10:10:04 +0800140 /* Loop through the entries in the directory, removing each one */
141 for (dir_ent = (struct dirent *)readdir(dir);
142 dir_ent != NULL; dir_ent = (struct dirent *)readdir(dir)) {
alaffincc2e5552000-07-27 17:13:18 +0000143
Wanlong Gao354ebb42012-12-07 10:10:04 +0800144 /* Don't remove "." or ".." */
145 if (!strcmp(dir_ent->d_name, ".")
146 || !strcmp(dir_ent->d_name, ".."))
147 continue;
alaffincc2e5552000-07-27 17:13:18 +0000148
Wanlong Gao354ebb42012-12-07 10:10:04 +0800149 /* Recursively call this routine to remove the current entry */
150 sprintf(dirobj, "%s/%s", obj, dir_ent->d_name);
151 if (rmobj(dirobj, errmsg) != 0)
152 ret_val = -1;
153 }
alaffincc2e5552000-07-27 17:13:18 +0000154
Wanlong Gao354ebb42012-12-07 10:10:04 +0800155 /* Close the directory */
156 closedir(dir);
alaffincc2e5552000-07-27 17:13:18 +0000157
Wanlong Gao354ebb42012-12-07 10:10:04 +0800158 /* If there were problems removing an entry, don't attempt to
159 remove the directory itself */
160 if (ret_val == -1)
161 return -1;
alaffincc2e5552000-07-27 17:13:18 +0000162
Wanlong Gao354ebb42012-12-07 10:10:04 +0800163 /* Get the link count, now that all the entries have been removed */
164 if (lstat(obj, &statbuf) < 0) {
165 if (errmsg != NULL) {
166 sprintf(err_msg,
167 "lstat(%s) failed; errno=%d: %s", obj,
168 errno, SYSERR);
169 *errmsg = err_msg;
170 }
171 return -1;
172 }
alaffincc2e5552000-07-27 17:13:18 +0000173
Wanlong Gao354ebb42012-12-07 10:10:04 +0800174 /* Remove the directory itself */
175 if (statbuf.st_nlink >= 3) {
176 /* The directory is linked; unlink() must be used */
177 if (unlink(obj) < 0) {
178 if (errmsg != NULL) {
179 sprintf(err_msg,
180 "unlink(%s) failed; errno=%d: %s",
181 obj, errno, SYSERR);
182 *errmsg = err_msg;
183 }
184 return -1;
185 }
186 } else {
187 /* The directory is not linked; remove() can be used */
188 if (remove(obj) < 0) {
189 if (errmsg != NULL) {
190 sprintf(err_msg,
191 "remove(%s) failed; errno=%d: %s",
192 obj, errno, SYSERR);
193 *errmsg = err_msg;
194 }
195 return -1;
196 }
197 }
198 } else {
199 /* object is not a directory; just use unlink() */
200 if (unlink(obj) < 0) {
201 if (errmsg != NULL) {
202 sprintf(err_msg,
203 "unlink(%s) failed; errno=%d: %s", obj,
204 errno, SYSERR);
205 *errmsg = err_msg;
206 }
207 return -1;
208 }
209 } /* if obj is a directory */
alaffincc2e5552000-07-27 17:13:18 +0000210
Wanlong Gao354ebb42012-12-07 10:10:04 +0800211 /*
212 * Everything must have went ok.
213 */
214 return 0;
215} /* rmobj() */