source: mainline/uspace/app/bdsh/cmds/modules/rm/rm.c@ 1e2629f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1e2629f was ed2c8ff, checked in by Jakub Jermar <jakub@…>, 14 years ago

Support for recursive 'rm'.
(Thanks to Laura-Mihaela Vasilescu.)

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of the original program's authors nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <fcntl.h>
35#include <dirent.h>
36#include <getopt.h>
37#include <mem.h>
38#include <str.h>
39
40#include "config.h"
41#include "errors.h"
42#include "util.h"
43#include "entry.h"
44#include "rm.h"
45#include "cmds.h"
46
47static const char *cmdname = "rm";
48#define RM_VERSION "0.0.1"
49
50static rm_job_t rm;
51
52static struct option const long_options[] = {
53 { "help", no_argument, 0, 'h' },
54 { "version", no_argument, 0, 'v' },
55 { "recursive", no_argument, 0, 'r' },
56 { "force", no_argument, 0, 'f' },
57 { "safe", no_argument, 0, 's' },
58 { 0, 0, 0, 0 }
59};
60
61static unsigned int rm_start(rm_job_t *rm)
62{
63 rm->recursive = 0;
64 rm->force = 0;
65 rm->safe = 0;
66
67 /* Make sure we can allocate enough memory to store
68 * what is needed in the job structure */
69 if (NULL == (rm->nwd = (char *) malloc(PATH_MAX)))
70 return 0;
71 memset(rm->nwd, 0, sizeof(rm->nwd));
72
73 if (NULL == (rm->owd = (char *) malloc(PATH_MAX)))
74 return 0;
75 memset(rm->owd, 0, sizeof(rm->owd));
76
77 if (NULL == (rm->cwd = (char *) malloc(PATH_MAX)))
78 return 0;
79 memset(rm->cwd, 0, sizeof(rm->cwd));
80
81 chdir(".");
82
83 if (NULL == (getcwd(rm->owd, PATH_MAX)))
84 return 0;
85
86 return 1;
87}
88
89static void rm_end(rm_job_t *rm)
90{
91 if (NULL != rm->nwd)
92 free(rm->nwd);
93
94 if (NULL != rm->owd)
95 free(rm->owd);
96
97 if (NULL != rm->cwd)
98 free(rm->cwd);
99
100 return;
101}
102
103static unsigned int rm_recursive_not_empty_dirs(const char *path)
104{
105 DIR *dirp;
106 struct dirent *dp;
107 char buff[PATH_MAX];
108 unsigned int scope;
109 unsigned int ret = 0;
110
111 dirp = opendir(path);
112 if (!dirp) {
113 /* May have been deleted between scoping it and opening it */
114 cli_error(CL_EFAIL, "Could not open %s", path);
115 return ret;
116 }
117
118 memset(buff, 0, sizeof(buff));
119 while ((dp = readdir(dirp))) {
120 snprintf(buff, PATH_MAX - 1, "%s/%s", path, dp->d_name);
121 scope = rm_scope(buff);
122 switch (scope) {
123 case RM_BOGUS:
124 break;
125 case RM_FILE:
126 ret += rm_single(buff);
127 break;
128 case RM_DIR:
129 ret += rm_recursive(buff);
130 break;
131 }
132 }
133
134 return ret;
135}
136
137static unsigned int rm_recursive(const char *path)
138{
139 int rc;
140 unsigned int ret = 0;
141
142 /* First see if it will just go away */
143 rc = rmdir(path);
144 if (rc == 0)
145 return 0;
146
147 /* Its not empty, recursively scan it */
148 ret = rm_recursive_not_empty_dirs(path);
149
150 /* Delete directory */
151 rc = rmdir(path);
152 if (rc == 0)
153 return ret;
154
155 cli_error(CL_ENOTSUP, "Can not remove %s", path);
156
157 return ret + 1;
158}
159
160static unsigned int rm_single(const char *path)
161{
162 if (unlink(path)) {
163 cli_error(CL_EFAIL, "rm: could not remove file %s", path);
164 return 1;
165 }
166 return 0;
167}
168
169static unsigned int rm_scope(const char *path)
170{
171 int fd;
172 DIR *dirp;
173
174 dirp = opendir(path);
175 if (dirp) {
176 closedir(dirp);
177 return RM_DIR;
178 }
179
180 fd = open(path, O_RDONLY);
181 if (fd > 0) {
182 close(fd);
183 return RM_FILE;
184 }
185
186 return RM_BOGUS;
187}
188
189/* Dispays help for rm in various levels */
190void help_cmd_rm(unsigned int level)
191{
192 if (level == HELP_SHORT) {
193 printf("`%s' removes files and directories.\n", cmdname);
194 } else {
195 help_cmd_rm(HELP_SHORT);
196 printf(
197 "Usage: %s [options] <path>\n"
198 "Options:\n"
199 " -h, --help A short option summary\n"
200 " -v, --version Print version information and exit\n"
201 " -r, --recursive Recursively remove sub directories\n"
202 " -f, --force Do not prompt prior to removing files\n"
203 " -s, --safe Stop if directories change during removal\n\n"
204 "Currently, %s is under development, some options don't work.\n",
205 cmdname, cmdname);
206 }
207 return;
208}
209
210/* Main entry point for rm, accepts an array of arguments */
211int cmd_rm(char **argv)
212{
213 unsigned int argc;
214 unsigned int i, scope, ret = 0;
215 int c, opt_ind;
216 size_t len;
217 char *buff = NULL;
218
219 argc = cli_count_args(argv);
220
221 if (argc < 2) {
222 cli_error(CL_EFAIL,
223 "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
224 return CMD_FAILURE;
225 }
226
227 if (!rm_start(&rm)) {
228 cli_error(CL_ENOMEM, "%s: could not initialize", cmdname);
229 rm_end(&rm);
230 return CMD_FAILURE;
231 }
232
233 for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
234 c = getopt_long(argc, argv, "hvrfs", long_options, &opt_ind);
235 switch (c) {
236 case 'h':
237 help_cmd_rm(HELP_LONG);
238 return CMD_SUCCESS;
239 case 'v':
240 printf("%s\n", RM_VERSION);
241 return CMD_SUCCESS;
242 case 'r':
243 rm.recursive = 1;
244 break;
245 case 'f':
246 rm.force = 1;
247 break;
248 case 's':
249 rm.safe = 1;
250 break;
251 }
252 }
253
254 if ((unsigned) optind == argc) {
255 cli_error(CL_EFAIL,
256 "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
257 rm_end(&rm);
258 return CMD_FAILURE;
259 }
260
261 i = optind;
262 while (NULL != argv[i]) {
263 len = str_size(argv[i]) + 2;
264 buff = (char *) realloc(buff, len);
265 if (buff == NULL) {
266 printf("rm: out of memory\n");
267 ret = 1;
268 break;
269 }
270 memset(buff, 0, sizeof(buff));
271 snprintf(buff, len, "%s", argv[i]);
272
273 scope = rm_scope(buff);
274 switch (scope) {
275 case RM_BOGUS: /* FIXME */
276 case RM_FILE:
277 ret += rm_single(buff);
278 break;
279 case RM_DIR:
280 if (! rm.recursive) {
281 printf("%s is a directory, use -r to remove it.\n", buff);
282 ret ++;
283 } else {
284 ret += rm_recursive(buff);
285 }
286 break;
287 }
288 i++;
289 }
290
291 if (NULL != buff)
292 free(buff);
293
294 rm_end(&rm);
295
296 if (ret)
297 return CMD_FAILURE;
298 else
299 return CMD_SUCCESS;
300}
301
Note: See TracBrowser for help on using the repository browser.