diff options
Diffstat (limited to 'bin/rm')
| -rw-r--r-- | bin/rm/Makefile | 12 | ||||
| -rw-r--r-- | bin/rm/Makefile.depend | 15 | ||||
| -rw-r--r-- | bin/rm/rm.1 | 232 | ||||
| -rw-r--r-- | bin/rm/rm.c | 537 | ||||
| -rw-r--r-- | bin/rm/tests/Makefile | 3 | ||||
| -rw-r--r-- | bin/rm/tests/Makefile.depend | 10 | ||||
| -rwxr-xr-x | bin/rm/tests/rm_test.sh | 44 |
7 files changed, 853 insertions, 0 deletions
diff --git a/bin/rm/Makefile b/bin/rm/Makefile new file mode 100644 index 000000000000..dac3bee2247c --- /dev/null +++ b/bin/rm/Makefile @@ -0,0 +1,12 @@ +.include <src.opts.mk> + +PACKAGE=runtime +PROG= rm + +LINKS= ${BINDIR}/rm ${BINDIR}/unlink +MLINKS= rm.1 unlink.1 + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + +.include <bsd.prog.mk> diff --git a/bin/rm/Makefile.depend b/bin/rm/Makefile.depend new file mode 100644 index 000000000000..6ef78fac5cbf --- /dev/null +++ b/bin/rm/Makefile.depend @@ -0,0 +1,15 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/bin/rm/rm.1 b/bin/rm/rm.1 new file mode 100644 index 000000000000..8b8677e4a170 --- /dev/null +++ b/bin/rm/rm.1 @@ -0,0 +1,232 @@ +.\"- +.\" Copyright (c) 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 10, 2018 +.Dt RM 1 +.Os +.Sh NAME +.Nm rm , +.Nm unlink +.Nd remove directory entries +.Sh SYNOPSIS +.Nm +.Op Fl f | i +.Op Fl dIRrvWx +.Ar +.Nm unlink +.Op Fl - +.Ar file +.Sh DESCRIPTION +The +.Nm +utility attempts to remove the non-directory type files specified on the +command line. +If the permissions of the file do not permit writing, and the standard +input device is a terminal, the user is prompted (on the standard error +output) for confirmation. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl d +Attempt to remove directories as well as other types of files. +.It Fl f +Attempt to remove the files without prompting for confirmation, +regardless of the file's permissions. +If the file does not exist, do not display a diagnostic message or modify +the exit status to reflect an error. +The +.Fl f +option overrides any previous +.Fl i +options. +.It Fl i +Request confirmation before attempting to remove each file, regardless of +the file's permissions, or whether or not the standard input device is a +terminal. +The +.Fl i +option overrides any previous +.Fl f +options. +.It Fl I +Request confirmation once if more than three files are being removed or if a +directory is being recursively removed. +This is a far less intrusive option than +.Fl i +yet provides almost the same level of protection against mistakes. +.It Fl P +This flag has no effect. +It is kept only for backwards compatibility with +.Bx 4.4 Lite2 . +.It Fl R +Attempt to remove the file hierarchy rooted in each +.Ar file +argument. +The +.Fl R +option implies the +.Fl d +option. +If the +.Fl i +option is specified, the user is prompted for confirmation before +each directory's contents are processed (as well as before the attempt +is made to remove the directory). +If the user does not respond affirmatively, the file hierarchy rooted in +that directory is skipped. +.It Fl r +Equivalent to +.Fl R . +.It Fl v +Be verbose when deleting files, showing them as they are removed. +.It Fl W +Attempt to undelete the named files. +Currently, this option can only be used to recover +files covered by whiteouts in a union file system (see +.Xr undelete 2 ) . +.It Fl x +When removing a hierarchy, do not cross mount points. +.El +.Pp +The +.Nm +utility removes symbolic links, not the files referenced by the links. +.Pp +It is an error to attempt to remove the files +.Pa / , +.Pa .\& +or +.Pa .. . +.Pp +When the utility is called as +.Nm unlink , +only one argument, +which must not be a directory, +may be supplied. +No options may be supplied in this simple mode of operation, +which performs an +.Xr unlink 2 +operation on the passed argument. +However, the usual option-end delimiter, +.Fl - , +may optionally precede the argument. +.Sh EXIT STATUS +The +.Nm +utility exits 0 if all of the named files or file hierarchies were removed, +or if the +.Fl f +option was specified and all of the existing files or file hierarchies were +removed. +If an error occurs, +.Nm +exits with a value >0. +.Sh NOTES +The +.Nm +command uses +.Xr getopt 3 +to parse its arguments, which allows it to accept +the +.Sq Li -- +option which will cause it to stop processing flag options at that +point. +This will allow the removal of file names that begin +with a dash +.Pq Sq - . +For example: +.Pp +.Dl "rm -- -filename" +.Pp +The same behavior can be obtained by using an absolute or relative +path reference. +For example: +.Pp +.Dl "rm /home/user/-filename" +.Dl "rm ./-filename" +.Sh EXAMPLES +Recursively remove all files contained within the +.Pa foobar +directory hierarchy: +.Pp +.Dl $ rm -rf foobar +.Pp +Any of these commands will remove the file +.Pa -f : +.Bd -literal -offset indent +$ rm -- -f +$ rm ./-f +$ unlink -f +.Ed +.Sh COMPATIBILITY +The +.Nm +utility differs from historical implementations in that the +.Fl f +option only masks attempts to remove non-existent files instead of +masking a large variety of errors. +The +.Fl v +option is non-standard and its use in scripts is not recommended. +.Pp +Also, historical +.Bx +implementations prompted on the standard output, +not the standard error output. +.Pp +The +.Fl P +option does not have any effect as of +.Fx 13 +and may be removed in the future. +.Sh SEE ALSO +.Xr chflags 1 , +.Xr rmdir 1 , +.Xr undelete 2 , +.Xr unlink 2 , +.Xr fts 3 , +.Xr getopt 3 , +.Xr symlink 7 +.Sh STANDARDS +The +.Nm +command conforms to +.St -p1003.1-2013 . +.Pp +The simplified +.Nm unlink +command conforms to +.St -susv2 . +.Sh HISTORY +A +.Nm +command appeared in +.At v1 . diff --git a/bin/rm/rm.c b/bin/rm/rm.c new file mode 100644 index 000000000000..2c41d7380cea --- /dev/null +++ b/bin/rm/rm.c @@ -0,0 +1,537 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/mount.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <grp.h> +#include <locale.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +static int dflag, eval, fflag, iflag, vflag, Wflag, stdin_ok; +static int rflag, Iflag, xflag; +static uid_t uid; +static volatile sig_atomic_t info; + +static int check(const char *, const char *, struct stat *); +static int check2(char **); +static void checkdot(char **); +static void checkslash(char **); +static void rm_file(char **); +static void rm_tree(char **); +static void siginfo(int __unused); +static void usage(void); + +/* + * rm -- + * This rm is different from historic rm's, but is expected to match + * POSIX 1003.2 behavior. The most visible difference is that -f + * has two specific effects now, ignore non-existent files and force + * file removal. + */ +int +main(int argc, char *argv[]) +{ + int ch; + char *p; + + (void)setlocale(LC_ALL, ""); + + /* + * Test for the special case where the utility is called as + * "unlink", for which the functionality provided is greatly + * simplified. + */ + if ((p = strrchr(argv[0], '/')) == NULL) + p = argv[0]; + else + ++p; + if (strcmp(p, "unlink") == 0) { + if (argc == 2) + rm_file(&argv[1]); + else if (argc == 3 && strcmp(argv[1], "--") == 0) + rm_file(&argv[2]); + else + usage(); + exit(eval); + } + + rflag = xflag = 0; + while ((ch = getopt(argc, argv, "dfiIPRrvWx")) != -1) + switch(ch) { + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + iflag = 0; + break; + case 'i': + fflag = 0; + iflag = 1; + break; + case 'I': + Iflag = 1; + break; + case 'P': + /* Compatibility no-op. */ + break; + case 'R': + case 'r': /* Compatibility. */ + rflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'W': + Wflag = 1; + break; + case 'x': + xflag = 1; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1) { + if (fflag) + return (0); + usage(); + } + + checkdot(argv); + checkslash(argv); + uid = geteuid(); + + (void)signal(SIGINFO, siginfo); + if (*argv) { + stdin_ok = isatty(STDIN_FILENO); + + if (Iflag) { + if (check2(argv) == 0) + exit (1); + } + if (rflag) + rm_tree(argv); + else + rm_file(argv); + } + + exit (eval); +} + +static void +rm_tree(char **argv) +{ + FTS *fts; + FTSENT *p; + int needstat; + int flags; + int rval; + + /* + * Remove a file hierarchy. If forcing removal (-f), or interactive + * (-i) or can't ask anyway (stdin_ok), don't stat the file. + */ + needstat = !uid || (!fflag && !iflag && stdin_ok); + + /* + * If the -i option is specified, the user can skip on the pre-order + * visit. The fts_number field flags skipped directories. + */ +#define SKIPPED 1 + + flags = FTS_PHYSICAL; + if (!needstat) + flags |= FTS_NOSTAT; + if (Wflag || fflag) + flags |= FTS_WHITEOUT; + if (xflag) + flags |= FTS_XDEV; + if (!(fts = fts_open(argv, flags, NULL))) { + if (fflag && errno == ENOENT) + return; + err(1, "fts_open"); + } + while (errno = 0, (p = fts_read(fts)) != NULL) { + switch (p->fts_info) { + case FTS_DNR: + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_ERR: + errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno)); + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat the + * file, it can't be unlinked. + */ + if (!needstat) + break; + if (!fflag || p->fts_errno != ENOENT) { + warnx("%s: %s", + p->fts_path, strerror(p->fts_errno)); + eval = 1; + } + continue; + case FTS_D: + /* Pre-order: give user chance to skip. */ + if (!fflag && !check(p->fts_path, p->fts_accpath, + p->fts_statp)) { + (void)fts_set(fts, p, FTS_SKIP); + p->fts_number = SKIPPED; + } + else if (!uid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + lchflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0) + goto err; + continue; + case FTS_DP: + /* Post-order: see if user skipped. */ + if (p->fts_number == SKIPPED) + continue; + break; + default: + if (!fflag && + !check(p->fts_path, p->fts_accpath, p->fts_statp)) + continue; + } + + rval = 0; + if (!uid && + (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = lchflags(p->fts_accpath, + p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)); + if (rval == 0) { + /* + * If we can't read or search the directory, may still be + * able to remove it. Don't print out the un{read,search}able + * message unless the remove fails. + */ + switch (p->fts_info) { + case FTS_DP: + case FTS_DNR: + rval = rmdir(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + if (rval == 0 && info) { + info = 0; + (void)printf("%s\n", + p->fts_path); + } + continue; + } + break; + + case FTS_W: + rval = undelete(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (vflag) + (void)printf("%s\n", + p->fts_path); + if (info) { + info = 0; + (void)printf("%s\n", + p->fts_path); + } + continue; + } + break; + + case FTS_NS: + /* + * Assume that since fts_read() couldn't stat + * the file, it can't be unlinked. + */ + if (fflag) + continue; + /* FALLTHROUGH */ + + case FTS_F: + case FTS_NSOK: + default: + rval = unlink(p->fts_accpath); + if (rval == 0 || (fflag && errno == ENOENT)) { + if (rval == 0 && vflag) + (void)printf("%s\n", + p->fts_path); + if (rval == 0 && info) { + info = 0; + (void)printf("%s\n", + p->fts_path); + } + continue; + } + } + } +err: + warn("%s", p->fts_path); + eval = 1; + } + if (!fflag && errno) + err(1, "fts_read"); + fts_close(fts); +} + +static void +rm_file(char **argv) +{ + struct stat sb; + int rval; + char *f; + + /* + * Remove a file. POSIX 1003.2 states that, by default, attempting + * to remove a directory is an error, so must always stat the file. + */ + while ((f = *argv++) != NULL) { + /* Assume if can't stat the file, can't unlink it. */ + if (lstat(f, &sb)) { + if (Wflag) { + sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR; + } else { + if (!fflag || errno != ENOENT) { + warn("%s", f); + eval = 1; + } + continue; + } + } else if (Wflag) { + warnx("%s: %s", f, strerror(EEXIST)); + eval = 1; + continue; + } + + if (S_ISDIR(sb.st_mode) && !dflag) { + warnx("%s: is a directory", f); + eval = 1; + continue; + } + if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb)) + continue; + rval = 0; + if (!uid && !S_ISWHT(sb.st_mode) && + (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) && + !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE))) + rval = lchflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE)); + if (rval == 0) { + if (S_ISWHT(sb.st_mode)) + rval = undelete(f); + else if (S_ISDIR(sb.st_mode)) + rval = rmdir(f); + else + rval = unlink(f); + } + if (rval && (!fflag || errno != ENOENT)) { + warn("%s", f); + eval = 1; + } + if (vflag && rval == 0) + (void)printf("%s\n", f); + if (info && rval == 0) { + info = 0; + (void)printf("%s\n", f); + } + } +} + +static int +check(const char *path, const char *name, struct stat *sp) +{ + int ch, first; + char modep[15], *flagsp; + + /* Check -i first. */ + if (iflag) + (void)fprintf(stderr, "remove %s? ", path); + else { + /* + * If it's not a symbolic link and it's unwritable and we're + * talking to a terminal, ask. Symbolic links are excluded + * because their permissions are meaningless. Check stdin_ok + * first because we may not have stat'ed the file. + */ + if (!stdin_ok || S_ISLNK(sp->st_mode) || + (!access(name, W_OK) && + !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && + (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))) + return (1); + strmode(sp->st_mode, modep); + if ((flagsp = fflagstostr(sp->st_flags)) == NULL) + err(1, "fflagstostr"); + (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", + modep + 1, modep[10] == ' ' ? "" : " ", + user_from_uid(sp->st_uid, 0), + group_from_gid(sp->st_gid, 0), + *flagsp ? flagsp : "", *flagsp ? " " : "", + path); + free(flagsp); + } + (void)fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + return (first == 'y' || first == 'Y'); +} + +#define ISSLASH(a) ((a)[0] == '/' && (a)[1] == '\0') +static void +checkslash(char **argv) +{ + char **t, **u; + int complained; + + complained = 0; + for (t = argv; *t;) { + if (ISSLASH(*t)) { + if (!complained++) + warnx("\"/\" may not be removed"); + eval = 1; + for (u = t; u[0] != NULL; ++u) + u[0] = u[1]; + } else { + ++t; + } + } +} + +static int +check2(char **argv) +{ + struct stat st; + int first; + int ch; + int fcount = 0; + int dcount = 0; + int i; + const char *dname = NULL; + + for (i = 0; argv[i]; ++i) { + if (lstat(argv[i], &st) == 0) { + if (S_ISDIR(st.st_mode)) { + ++dcount; + dname = argv[i]; /* only used if 1 dir */ + } else { + ++fcount; + } + } + } + first = 0; + while (first != 'n' && first != 'N' && first != 'y' && first != 'Y') { + if (dcount && rflag) { + fprintf(stderr, "recursively remove"); + if (dcount == 1) + fprintf(stderr, " %s", dname); + else + fprintf(stderr, " %d dirs", dcount); + if (fcount == 1) + fprintf(stderr, " and 1 file"); + else if (fcount > 1) + fprintf(stderr, " and %d files", fcount); + } else if (dcount + fcount > 3) { + fprintf(stderr, "remove %d files", dcount + fcount); + } else { + return(1); + } + fprintf(stderr, "? "); + fflush(stderr); + + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (ch == EOF) + break; + } + return (first == 'y' || first == 'Y'); +} + +#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2]))) +static void +checkdot(char **argv) +{ + char *p, **save, **t; + int complained; + + complained = 0; + for (t = argv; *t;) { + if ((p = strrchr(*t, '/')) != NULL) + ++p; + else + p = *t; + if (ISDOT(p)) { + if (!complained++) + warnx("\".\" and \"..\" may not be removed"); + eval = 1; + for (save = t; (t[0] = t[1]) != NULL; ++t) + continue; + t = save; + } else + ++t; + } +} + +static void +usage(void) +{ + + (void)fprintf(stderr, "%s\n%s\n", + "usage: rm [-f | -i] [-dIPRrvWx] file ...", + " unlink [--] file"); + exit(EX_USAGE); +} + +static void +siginfo(int sig __unused) +{ + + info = 1; +} diff --git a/bin/rm/tests/Makefile b/bin/rm/tests/Makefile new file mode 100644 index 000000000000..4145756fd3aa --- /dev/null +++ b/bin/rm/tests/Makefile @@ -0,0 +1,3 @@ +ATF_TESTS_SH+= rm_test + +.include <bsd.test.mk> diff --git a/bin/rm/tests/Makefile.depend b/bin/rm/tests/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/bin/rm/tests/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/bin/rm/tests/rm_test.sh b/bin/rm/tests/rm_test.sh new file mode 100755 index 000000000000..0bb8497b6092 --- /dev/null +++ b/bin/rm/tests/rm_test.sh @@ -0,0 +1,44 @@ +# +# Copyright 2018 Yuri Pankov +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +atf_test_case unlink_dash_filename +unlink_dash_filename_head() +{ + atf_set "descr" "unlink correctly handles -filename" +} +unlink_dash_filename_body() +{ + touch -- foo bar -foo -bar + atf_check -s exit:0 unlink foo + atf_check -s exit:0 unlink -- bar + atf_check -s exit:0 unlink -foo + atf_check -s exit:0 unlink -- -bar +} + +atf_init_test_cases() +{ + atf_add_test_case unlink_dash_filename +} |
