rm.c

00001 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  * Redistributions of source code must retain the above copyright notice, this
00008  * list of conditions and the following disclaimer.
00009  *
00010  * Redistributions in binary form must reproduce the above copyright notice,
00011  * this list of conditions and the following disclaimer in the documentation
00012  * and/or other materials provided with the distribution.
00013  *
00014  * Neither the name of the original program's authors nor the names of its
00015  * contributors may be used to endorse or promote products derived from this
00016  * software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
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         /* Make sure we can allocate enough memory to store
00068          * what is needed in the job structure */
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                 /* May have been deleted between scoping it and opening it */
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         /* First see if it will just go away */
00143         rc = rmdir(path);
00144         if (rc == 0)
00145                 return 0;
00146 
00147         /* Its not empty, recursively scan it */
00148         ret = rm_recursive_not_empty_dirs(path);
00149 
00150         /* Delete directory */
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 /* Dispays help for rm in various levels */
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 /* Main entry point for rm, accepts an array of arguments */
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: /* FIXME */
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 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7