source: mainline/uspace/app/bdsh/cmds/modules/rm/rm.c@ 36ab7c7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 36ab7c7 was 36ab7c7, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Standardize formatting of copyright headers in Bdsh and add some that were
missing.

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