Subversion Repositories HelenOS

Rev

Rev 3397 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 <assert.h>
  37. #include <getopt.h>
  38.  
  39. #include "config.h"
  40. #include "errors.h"
  41. #include "util.h"
  42. #include "entry.h"
  43. #include "rm.h"
  44. #include "cmds.h"
  45.  
  46. static char *cmdname = "rm";
  47. #define RM_VERSION "0.0.1"
  48.  
  49. static rm_job_t rm;
  50.  
  51. static struct option const long_options[] = {
  52.     { "help", no_argument, 0, 'h' },
  53.     { "version", no_argument, 0, 'v' },
  54.     { "recursive", no_argument, 0, 'r' },
  55.     { "force", no_argument, 0, 'f' },
  56.     { "safe", no_argument, 0, 's' },
  57.     { 0, 0, 0, 0 }
  58. };
  59.  
  60. static unsigned int rm_start(rm_job_t *rm)
  61. {
  62.     rm->recursive = 0;
  63.     rm->force = 0;
  64.     rm->safe = 0;
  65.  
  66.     /* Make sure we can allocate enough memory to store
  67.      * what is needed in the job structure */
  68.     if (NULL == (rm->nwd = (char *) malloc(PATH_MAX)))
  69.         return 0;
  70.     memset(rm->nwd, 0, sizeof(rm->nwd));
  71.  
  72.     if (NULL == (rm->owd = (char *) malloc(PATH_MAX)))
  73.         return 0;
  74.     memset(rm->owd, 0, sizeof(rm->owd));
  75.  
  76.     if (NULL == (rm->cwd = (char *) malloc(PATH_MAX)))
  77.         return 0;
  78.     memset(rm->cwd, 0, sizeof(rm->cwd));
  79.  
  80.     chdir(".");
  81.  
  82.     if (NULL == (getcwd(rm->owd, PATH_MAX)))
  83.         return 0;
  84.  
  85.     return 1;
  86. }
  87.  
  88. static void rm_end(rm_job_t *rm)
  89. {
  90.     if (NULL != rm->nwd)
  91.         free(rm->nwd);
  92.  
  93.     if (NULL != rm->owd)
  94.         free(rm->owd);
  95.  
  96.     if (NULL != rm->cwd)
  97.         free(rm->cwd);
  98.  
  99.     return;
  100. }
  101.  
  102. static unsigned int rm_recursive(const char *path)
  103. {
  104.     int rc;
  105.  
  106.     /* First see if it will just go away */
  107.     rc = rmdir(path);
  108.     if (rc == 0)
  109.         return 0;
  110.  
  111.     /* Its not empty, recursively scan it */
  112.     cli_error(CL_ENOTSUP,
  113.         "Can not remove %s, directory not empty", path);
  114.     return 1;
  115. }
  116.  
  117. static unsigned int rm_single(const char *path)
  118. {
  119.     if (unlink(path)) {
  120.         cli_error(CL_EFAIL, "rm: could not remove file %s", path);
  121.         return 1;
  122.     }
  123.     return 0;
  124. }
  125.  
  126. static unsigned int rm_scope(const char *path)
  127. {
  128.     int fd;
  129.     DIR *dirp;
  130.  
  131.     dirp = opendir(path);
  132.     if (dirp) {
  133.         closedir(dirp);
  134.         return RM_DIR;
  135.     }
  136.  
  137.     fd = open(path, O_RDONLY);
  138.     if (fd > 0) {
  139.         close(fd);
  140.         return RM_FILE;
  141.     }
  142.  
  143.     return RM_BOGUS;
  144. }
  145.  
  146. /* Dispays help for rm in various levels */
  147. void help_cmd_rm(unsigned int level)
  148. {
  149.     if (level == HELP_SHORT) {
  150.         printf("`%s' removes files and directories.\n", cmdname);
  151.     } else {
  152.         help_cmd_rm(HELP_SHORT);
  153.         printf(
  154.         "Usage:  %s [options] <path>\n"
  155.         "Options:\n"
  156.         "  -h, --help       A short option summary\n"
  157.         "  -v, --version    Print version information and exit\n"
  158.         "  -r, --recursive  Recursively remove sub directories\n"
  159.         "  -f, --force      Do not prompt prior to removing files\n"
  160.         "  -s, --safe       Stop if directories change during removal\n\n"
  161.         "Currently, %s is under development, some options don't work.\n",
  162.         cmdname, cmdname);
  163.     }
  164.     return;
  165. }
  166.  
  167. /* Main entry point for rm, accepts an array of arguments */
  168. int cmd_rm(char **argv)
  169. {
  170.     unsigned int argc;
  171.     unsigned int i, scope, ret = 0;
  172.     int c, opt_ind;
  173.     size_t len;
  174.     char *buff = NULL;
  175.  
  176.     argc = cli_count_args(argv);
  177.  
  178.     if (argc < 2) {
  179.         cli_error(CL_EFAIL,
  180.             "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
  181.         return CMD_FAILURE;
  182.     }
  183.  
  184.     if (!rm_start(&rm)) {
  185.         cli_error(CL_ENOMEM, "%s: could not initialize", cmdname);
  186.         rm_end(&rm);
  187.         return CMD_FAILURE;
  188.     }
  189.  
  190.     for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
  191.         c = getopt_long(argc, argv, "hvrfs", long_options, &opt_ind);
  192.         switch (c) {
  193.         case 'h':
  194.             help_cmd_rm(HELP_LONG);
  195.             return CMD_SUCCESS;
  196.         case 'v':
  197.             printf("%s\n", RM_VERSION);
  198.             return CMD_SUCCESS;
  199.         case 'r':
  200.             rm.recursive = 1;
  201.             break;
  202.         case 'f':
  203.             rm.force = 1;
  204.             break;
  205.         case 's':
  206.             rm.safe = 1;
  207.             break;
  208.         }
  209.     }
  210.  
  211.     if (optind == argc) {
  212.         cli_error(CL_EFAIL,
  213.             "%s: insufficient arguments. Try %s --help", cmdname, cmdname);
  214.         rm_end(&rm);
  215.         return CMD_FAILURE;
  216.     }
  217.  
  218.     i = optind;
  219.     while (NULL != argv[i]) {
  220.         len = strlen(argv[i]) + 2;
  221.         buff = (char *) realloc(buff, len);
  222.         assert(buff != NULL);
  223.         memset(buff, 0, sizeof(buff));
  224.         snprintf(buff, len, argv[i]);
  225.  
  226.         scope = rm_scope(buff);
  227.         switch (scope) {
  228.         case RM_BOGUS: /* FIXME */
  229.         case RM_FILE:
  230.             ret += rm_single(buff);
  231.             break;
  232.         case RM_DIR:
  233.             if (! rm.recursive) {
  234.                 printf("%s is a directory, use -r to remove it.\n", buff);
  235.                 ret ++;
  236.             } else {
  237.                 ret += rm_recursive(buff);
  238.             }
  239.             break;
  240.         }
  241.         i++;
  242.     }
  243.  
  244.     if (NULL != buff)
  245.         free(buff);
  246.  
  247.     rm_end(&rm);
  248.  
  249.     if (ret)
  250.         return CMD_FAILURE;
  251.     else
  252.         return CMD_SUCCESS;
  253. }
  254.  
  255.