From 5f1a18e570e63c9f010c48aca3a3484f56045fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim Rühsen?= Date: Mon, 31 Oct 2016 12:44:20 +0100 Subject: [PATCH 2/2] Add rm [-rf] as examples/loadables/rm.c --- MANIFEST | 1 + examples/loadables/Makefile.in | 5 +- examples/loadables/README | 1 + examples/loadables/rm.c | 153 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 examples/loadables/rm.c diff --git a/MANIFEST b/MANIFEST index a306b6f..c352811 100644 --- a/MANIFEST +++ b/MANIFEST @@ -681,6 +681,7 @@ examples/loadables/dirname.c f examples/loadables/tty.c f examples/loadables/pathchk.c f examples/loadables/tee.c f +examples/loadables/rm.c f examples/loadables/rmdir.c f examples/loadables/head.c f examples/loadables/printenv.c f diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in index ec305cd..da0f595 100644 --- a/examples/loadables/Makefile.in +++ b/examples/loadables/Makefile.in @@ -103,7 +103,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \ ALLPROG = print truefalse sleep finfo logname basename dirname \ tty pathchk tee head mkdir rmdir printenv id whoami \ uname sync push ln unlink realpath strftime mypid setpgid -OTHERPROG = necho hello cat pushd +OTHERPROG = necho hello cat pushd rm all: $(SHOBJ_STATUS) @@ -142,6 +142,9 @@ finfo: finfo.o cat: cat.o $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS) +rm: rm.o + $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rm.o $(SHOBJ_LIBS) + logname: logname.o $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS) diff --git a/examples/loadables/README b/examples/loadables/README index 2eae9cc..3d4e641 100644 --- a/examples/loadables/README +++ b/examples/loadables/README @@ -52,6 +52,7 @@ printenv.c Minimal builtin clone of BSD printenv(1). push.c Anyone remember TOPS-20? README README realpath.c Canonicalize pathnames, resolving symlinks. +rm.c Remove files, and directories with -r. rmdir.c Remove directory. sleep.c sleep for fractions of a second. strftime.c Loadable builtin interface to strftime(3). diff --git a/examples/loadables/rm.c b/examples/loadables/rm.c new file mode 100644 index 0000000..b10e4d9 --- /dev/null +++ b/examples/loadables/rm.c @@ -0,0 +1,153 @@ +/* rm - remove files */ + +/* 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 . +*/ + +#include "config.h" + +#include +#include +#include +#include "builtins.h" +#include "shell.h" +#include "common.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 = strlen(dirname); + int 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; + + char fname[dirlen + 1 + strlen(dp->d_name) + 1]; + snprintf(fname, sizeof(fname), "%s/%s", dirname, dp->d_name); + + if (_rm_file (fname) && !force) + err = 1; + } + + closedir(dir); + + if (!err && rmdir(dirname) && !force) + err = 1; + } + else if (!force) + 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; + + /* in case name is a directory glibc returns EISDIR but correct POSIX value would be EPERM */ + if ((errno == EISDIR || errno == EPERM) && recursive) + 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 force_name, it; + int rval = EXECUTION_SUCCESS; + + recursive = force = force_name = 0; + + for (l = list; l; l = l->next) + { + name = l->word->word; + + if (!force_name && (*name == '-' && name[1])) + { + if (name[1] == '-') + { + force_name = 1; + continue; + } + for (it = 1; name[it]; it++) + { + if (name[it] == 'r') + recursive = 1; + else if (name[it] == 'f') + force = 1; + else + { + builtin_error ("%s: Unknown option", l->word->word); + return EX_USAGE; + } + } + continue; + } + + if (_rm_file(name) && !force) + 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 */ +}; -- 2.10.2