On 10/31/16 4:40 PM, Tim Rühsen wrote:
> On Montag, 31. Oktober 2016 13:09:15 CET Chet Ramey wrote:
>> On 10/31/16 7:59 AM, Tim Ruehsen wrote:
>>> Added the 'rm' command to examples/loadables.
>>>
>>> It accepts -r and -f.
>>
>> Thanks for the submission.  I modified it pretty heavily, and it will be
>> in the next release of bash and the next devel snapshot.
> 
> Nice, thanks for the modifications.

Here's the modified version.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    c...@case.edu    http://cnswww.cns.cwru.edu/~chet/
/* rm - remove files and directories with -r */

/* See Makefile for compilation details. */

/*
   Copyright (C) 2016 Free Software Foundation, Inc.

   This file is part of GNU Bash.
   Bash is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   Bash is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include "builtins.h"
#include "shell.h"
#include "common.h"
#include "bashgetopt.h"

#if !defined (errno)
extern int errno;
#endif

static int rm_file(const char *fname);

static int force, recursive;

static int
_remove_directory(const char *dirname)
{
  DIR *dir;
  struct dirent *dp;
  size_t dirlen;
  int err, fnsize;
  char *fname;

  dirlen = strlen (dirname);
  err = 0;

  if ((dir = opendir(dirname)))
    {
      while ((dp = readdir(dir)))
        {
          if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
            continue;

	   fnsize = dirlen + 1 + strlen(dp->d_name) + 1;
           fname = xmalloc (fnsize);
           snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);

           if (rm_file (fname) && force == 0)
             err = 1;
           free (fname);
        }

      closedir(dir);
		
      if (err == 0 && rmdir (dirname) && force == 0)
        err = 1;
    }
  else if (force == 0)
    err = 1;

  if (err)
    builtin_error ("%s: %s", dirname, strerror (errno));

  return err;
}

static int
rm_file(const char *fname)
{
  if (unlink (fname) == 0)
    return 0;

  /* If FNAME is a directory glibc returns EISDIR but correct POSIX value
     would be EPERM.  If we get that error and FNAME is a directory and -r
     was supplied, recursively remove the directory and its contents */
  if ((errno == EISDIR || errno == EPERM) && recursive && file_isdir (fname))
    return _remove_directory(fname);
  else if (force)
    return 0;

  builtin_error ("%s: %s", fname, strerror (errno));
  return 1;
}

int
rm_builtin (list)
     WORD_LIST *list;
{
  const char *name;
  WORD_LIST *l;
  int rval, opt;

  recursive = force = 0;
  rval = EXECUTION_SUCCESS;

  reset_internal_getopt ();
  while ((opt = internal_getopt (list, "rf")) != -1)
    {
      switch (opt)
	{
	case 'r':
	  recursive = 1;
	  break;
	case 'f':
	  force = 1;
	  break;
	CASE_HELPOPT;
	default:
	  builtin_usage ();
	  return (EX_USAGE);
	}
    }
  list = loptend;

  if (list == 0)
    return (EXECUTION_SUCCESS);

  for (l = list; l; l = l->next)
    {
      if (rm_file(l->word->word) && force == 0)
	rval = EXECUTION_FAILURE;
    }

  return rval;
}

char *rm_doc[] = {
	"Remove files.",
	"",
	"rm removes the files specified as arguments.",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin rm_struct = {
	"rm",			/* builtin name */
	rm_builtin,		/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	rm_doc,			/* array of long documentation strings. */
	"rm [-rf] file ...",	/* usage synopsis; becomes short_doc */
	0			/* reserved for internal use */
};

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to