00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 #include <fcntl.h>
00035 #include <dirent.h>
00036 #include <getopt.h>
00037 #include <mem.h>
00038 #include <str.h>
00039
00040 #include "config.h"
00041 #include "errors.h"
00042 #include "util.h"
00043 #include "entry.h"
00044 #include "rm.h"
00045 #include "cmds.h"
00046
00047 static const char *cmdname = "rm";
00048 #define RM_VERSION "0.0.1"
00049
00050 static rm_job_t rm;
00051
00052 static struct option const long_options[] = {
00053 { "help", no_argument, 0, 'h' },
00054 { "version", no_argument, 0, 'v' },
00055 { "recursive", no_argument, 0, 'r' },
00056 { "force", no_argument, 0, 'f' },
00057 { "safe", no_argument, 0, 's' },
00058 { 0, 0, 0, 0 }
00059 };
00060
00061 static unsigned int rm_start(rm_job_t *rm)
00062 {
00063 rm->recursive = 0;
00064 rm->force = 0;
00065 rm->safe = 0;
00066
00067
00068
00069 if (NULL == (rm->nwd = (char *) malloc(PATH_MAX)))
00070 return 0;
00071 memset(rm->nwd, 0, sizeof(rm->nwd));
00072
00073 if (NULL == (rm->owd = (char *) malloc(PATH_MAX)))
00074 return 0;
00075 memset(rm->owd, 0, sizeof(rm->owd));
00076
00077 if (NULL == (rm->cwd = (char *) malloc(PATH_MAX)))
00078 return 0;
00079 memset(rm->cwd, 0, sizeof(rm->cwd));
00080
00081 chdir(".");
00082
00083 if (NULL == (getcwd(rm->owd, PATH_MAX)))
00084 return 0;
00085
00086 return 1;
00087 }
00088
00089 static void rm_end(rm_job_t *rm)
00090 {
00091 if (NULL != rm->nwd)
00092 free(rm->nwd);
00093
00094 if (NULL != rm->owd)
00095 free(rm->owd);
00096
00097 if (NULL != rm->cwd)
00098 free(rm->cwd);
00099
00100 return;
00101 }
00102
00103 static unsigned int rm_recursive_not_empty_dirs(const char *path)
00104 {
00105 DIR *dirp;
00106 struct dirent *dp;
00107 char buff[PATH_MAX];
00108 unsigned int scope;
00109 unsigned int ret = 0;
00110
00111 dirp = opendir(path);
00112 if (!dirp) {
00113
00114 cli_error(CL_EFAIL, "Could not open %s", path);
00115 return ret;
00116 }
00117
00118 memset(buff, 0, sizeof(buff));
00119 while ((dp = readdir(dirp))) {
00120 snprintf(buff, PATH_MAX - 1, "%s/%s", path, dp->d_name);
00121 scope = rm_scope(buff);
00122 switch (scope) {
00123 case RM_BOGUS:
00124 break;
00125 case RM_FILE:
00126 ret += rm_single(buff);
00127 break;
00128 case RM_DIR:
00129 ret += rm_recursive(buff);
00130 break;
00131 }
00132 }
00133
00134 return ret;
00135 }
00136
00137 static unsigned int rm_recursive(const char *path)
00138 {
00139 int rc;
00140 unsigned int ret = 0;
00141
00142
00143 rc = rmdir(path);
00144 if (rc == 0)
00145 return 0;
00146
00147
00148 ret = rm_recursive_not_empty_dirs(path);
00149
00150
00151 rc = rmdir(path);
00152 if (rc == 0)
00153 return ret;
00154
00155 cli_error(CL_ENOTSUP, "Can not remove %s", path);
00156
00157 return ret + 1;
00158 }
00159
00160 static unsigned int rm_single(const char *path)
00161 {
00162 if (unlink(path)) {
00163 cli_error(CL_EFAIL, "rm: could not remove file %s", path);
00164 return 1;
00165 }
00166 return 0;
00167 }
00168
00169 static unsigned int rm_scope(const char *path)
00170 {
00171 int fd;
00172 DIR *dirp;
00173
00174 dirp = opendir(path);
00175 if (dirp) {
00176 closedir(dirp);
00177 return RM_DIR;
00178 }
00179
00180 fd = open(path, O_RDONLY);
00181 if (fd > 0) {
00182 close(fd);
00183 return RM_FILE;
00184 }
00185
00186 return RM_BOGUS;
00187 }
00188
00189
00190 void help_cmd_rm(unsigned int level)
00191 {
00192 if (level == HELP_SHORT) {
00193 printf("`%s' removes files and directories.\n", cmdname);
00194 } else {
00195 help_cmd_rm(HELP_SHORT);
00196 printf(
00197 "Usage: %s [options] <path>\n"
00198 "Options:\n"
00199 " -h, --help A short option summary\n"
00200 " -v, --version Print version information and exit\n"
00201 " -r, --recursive Recursively remove sub directories\n"
00202 " -f, --force Do not prompt prior to removing files\n"
00203 " -s, --safe Stop if directories change during removal\n\n"
00204 "Currently, %s is under development, some options don't work.\n",
00205 cmdname, cmdname);
00206 }
00207 return;
00208 }
00209
00210
00211 int cmd_rm(char **argv)
00212 {
00213 unsigned int argc;
00214 unsigned int i, scope, ret = 0;
00215 int c, opt_ind;
00216 size_t len;
00217 char *buff = NULL;
00218
00219 argc = cli_count_args(argv);
00220
00221 if (argc < 2) {
00222 cli_error(CL_EFAIL,
00223 "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
00224 return CMD_FAILURE;
00225 }
00226
00227 if (!rm_start(&rm)) {
00228 cli_error(CL_ENOMEM, "%s: could not initialize", cmdname);
00229 rm_end(&rm);
00230 return CMD_FAILURE;
00231 }
00232
00233 for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
00234 c = getopt_long(argc, argv, "hvrfs", long_options, &opt_ind);
00235 switch (c) {
00236 case 'h':
00237 help_cmd_rm(HELP_LONG);
00238 return CMD_SUCCESS;
00239 case 'v':
00240 printf("%s\n", RM_VERSION);
00241 return CMD_SUCCESS;
00242 case 'r':
00243 rm.recursive = 1;
00244 break;
00245 case 'f':
00246 rm.force = 1;
00247 break;
00248 case 's':
00249 rm.safe = 1;
00250 break;
00251 }
00252 }
00253
00254 if ((unsigned) optind == argc) {
00255 cli_error(CL_EFAIL,
00256 "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
00257 rm_end(&rm);
00258 return CMD_FAILURE;
00259 }
00260
00261 i = optind;
00262 while (NULL != argv[i]) {
00263 len = str_size(argv[i]) + 2;
00264 buff = (char *) realloc(buff, len);
00265 if (buff == NULL) {
00266 printf("rm: out of memory\n");
00267 ret = 1;
00268 break;
00269 }
00270 memset(buff, 0, sizeof(buff));
00271 snprintf(buff, len, "%s", argv[i]);
00272
00273 scope = rm_scope(buff);
00274 switch (scope) {
00275 case RM_BOGUS:
00276 case RM_FILE:
00277 ret += rm_single(buff);
00278 break;
00279 case RM_DIR:
00280 if (! rm.recursive) {
00281 printf("%s is a directory, use -r to remove it.\n", buff);
00282 ret ++;
00283 } else {
00284 ret += rm_recursive(buff);
00285 }
00286 break;
00287 }
00288 i++;
00289 }
00290
00291 if (NULL != buff)
00292 free(buff);
00293
00294 rm_end(&rm);
00295
00296 if (ret)
00297 return CMD_FAILURE;
00298 else
00299 return CMD_SUCCESS;
00300 }
00301