1 /* $OpenBSD: rm.c,v 1.11 2016/10/10 18:13:21 tedu Exp $ */
2 /* $NetBSD: rm.c,v 1.19 1995/09/07 06:48:50 jtc Exp $ */
3
4 /*-
5 * Copyright (c) 1990, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34
35 #include <err.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <fts.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 static int eval;
45
46 static void checkdot(char **);
47 static void rm_tree(char **);
48
49 int
rmmain(int argc,char * argv[])50 rmmain(int argc, char *argv[])
51 {
52
53 checkdot(argv);
54
55 if (*argv)
56 rm_tree(argv);
57
58 return (eval);
59 }
60
61 static void
rm_tree(char ** argv)62 rm_tree(char **argv)
63 {
64 FTS *fts;
65 FTSENT *p;
66 int flags;
67
68 flags = FTS_PHYSICAL;
69 flags |= FTS_NOSTAT;
70 if (!(fts = fts_open(argv, flags, NULL)))
71 err(1, NULL);
72 while ((p = fts_read(fts)) != NULL) {
73 switch (p->fts_info) {
74 case FTS_DNR:
75 if (p->fts_errno != ENOENT) {
76 warnx("%s: %s",
77 p->fts_path, strerror(p->fts_errno));
78 eval = 1;
79 }
80 continue;
81 case FTS_ERR:
82 errc(1, p->fts_errno, "%s", p->fts_path);
83 case FTS_D:
84 continue;
85 default:
86 break;
87 }
88
89 /*
90 * If we can't read or search the directory, may still be
91 * able to remove it. Don't print out the un{read,search}able
92 * message unless the remove fails.
93 */
94 switch (p->fts_info) {
95 case FTS_DP:
96 case FTS_DNR:
97 if (!rmdir(p->fts_accpath) ||
98 (errno == ENOENT))
99 continue;
100 break;
101
102 case FTS_F:
103 case FTS_NSOK:
104 default:
105 if (!unlink(p->fts_accpath) ||
106 (errno == ENOENT))
107 continue;
108 }
109 warn("%s", p->fts_path);
110 eval = 1;
111 }
112 if (errno)
113 err(1, "fts_read");
114 fts_close(fts);
115 }
116
117 /*
118 * POSIX.2 requires that if "." or ".." are specified as the basename
119 * portion of an operand, a diagnostic message be written to standard
120 * error and nothing more be done with such operands.
121 *
122 * Since POSIX.2 defines basename as the final portion of a path after
123 * trailing slashes have been removed, we'll remove them here.
124 */
125 #define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
126 static void
checkdot(char ** argv)127 checkdot(char **argv)
128 {
129 char *p, **save, **t;
130 int complained;
131
132 complained = 0;
133 for (t = argv; *t;) {
134 /* strip trailing slashes */
135 p = strrchr (*t, '\0');
136 while (--p > *t && *p == '/')
137 *p = '\0';
138
139 /* extract basename */
140 if ((p = strrchr(*t, '/')) != NULL)
141 ++p;
142 else
143 p = *t;
144
145 if (ISDOT(p)) {
146 if (!complained++)
147 warnx("\".\" and \"..\" may not be removed");
148 eval = 1;
149 for (save = t; (t[0] = t[1]) != NULL; ++t)
150 continue;
151 t = save;
152 } else
153 ++t;
154 }
155 }
156