doprnt.o is needed only on vax (need better way than this)
[unix-history] / usr / src / bin / rm / rm.c
CommitLineData
cd7f3a28 1static char *sccsid = "@(#)rm.c 4.18 (Berkeley) %G%";
d1e4967d
RC
2
3/*
4 * rm - for ReMoving files, directories & trees.
5 */
ae80f4a2
BJ
6
7#include <stdio.h>
d7ab2ea5 8#include <sys/param.h>
ae80f4a2 9#include <sys/stat.h>
6b7bfa6e 10#include <sys/dir.h>
d1e4967d
RC
11#include <sys/file.h>
12
731d7e2f
RC
13int fflg; /* -f force - supress error messages */
14int iflg; /* -i interrogate user on each file */
15int rflg; /* -r recurse */
d1e4967d 16
731d7e2f 17int errcode; /* true if errors occured */
ae80f4a2 18
731d7e2f 19char *strcpy(), *malloc(), *realloc();
ae80f4a2
BJ
20
21main(argc, argv)
d1e4967d 22 char *argv[];
ae80f4a2
BJ
23{
24 register char *arg;
ae80f4a2 25
d1e4967d 26 fflg = !isatty(0);
ae80f4a2
BJ
27 iflg = 0;
28 rflg = 0;
d1e4967d 29 while (argc > 1 && argv[1][0] == '-') {
ae80f4a2
BJ
30 arg = *++argv;
31 argc--;
ca02483b
BJ
32
33 /*
34 * all files following a null option are considered file names
35 */
d1e4967d
RC
36 if (arg[1] == '\0')
37 break;
ca02483b 38
d1e4967d 39 while (*++arg != '\0')
ae80f4a2
BJ
40 switch(*arg) {
41 case 'f':
42 fflg++;
43 break;
d1e4967d 44
ae80f4a2
BJ
45 case 'i':
46 iflg++;
47 break;
d1e4967d 48
3606edc1 49 case 'R':
ae80f4a2
BJ
50 case 'r':
51 rflg++;
52 break;
d1e4967d 53
ae80f4a2 54 default:
d1e4967d 55 fprintf(stderr, "usage: rm [-rif] file ...\n");
ae80f4a2
BJ
56 exit(1);
57 }
58 }
3606edc1 59
cd7f3a28 60 if (argc < 2 && !fflg) {
3606edc1
S
61 fprintf(stderr, "usage: rm [-rif] file ...\n");
62 exit(1);
63 }
64
d1e4967d
RC
65 while (--argc > 0)
66 (void) rm(*++argv, 0);
ae80f4a2 67
d1e4967d 68 exit(errcode != 0);
ae80f4a2
BJ
69}
70
731d7e2f
RC
71char *path; /* pointer to malloc'ed buffer for path */
72char *pathp; /* current pointer to end of path */
73int pathsz; /* size of path */
d1e4967d
RC
74
75/*
76 * Return TRUE if sucessful. Recursive with -r (rflg)
77 */
78rm(arg, level)
79 char arg[];
ae80f4a2 80{
d1e4967d
RC
81 int ok; /* true if recursive rm succeeded */
82 struct stat buf; /* for finding out what a file is */
83 struct direct *dp; /* for reading a directory */
84 DIR *dirp; /* for reading a directory */
d1e4967d 85 char prevname[MAXNAMLEN + 1]; /* previous name for -r */
731d7e2f 86 char *cp;
d1e4967d
RC
87
88 if (dotname(arg)) {
89 fprintf(stderr, "rm: cannot remove `.' or `..'\n");
90 return (0);
91 }
d1e4967d 92 if (lstat(arg, &buf)) {
b2704a87 93 if (!fflg) {
731d7e2f 94 fprintf(stderr, "rm: %s nonexistent\n", arg);
b2704a87
RC
95 errcode++;
96 }
d1e4967d 97 return (0); /* error */
ae80f4a2
BJ
98 }
99 if ((buf.st_mode&S_IFMT) == S_IFDIR) {
d1e4967d 100 if (!rflg) {
b2704a87 101 if (!fflg) {
731d7e2f 102 fprintf(stderr, "rm: %s directory\n", arg);
b2704a87
RC
103 errcode++;
104 }
d1e4967d
RC
105 return (0);
106 }
731d7e2f
RC
107 if (iflg && level != 0) {
108 printf("rm: remove directory %s? ", arg);
109 if (!yes())
110 return (0); /* didn't remove everything */
111 }
d1e4967d
RC
112 if (access(arg, R_OK|W_OK|X_OK) != 0) {
113 if (rmdir(arg) == 0)
114 return (1); /* salvaged: removed empty dir */
b2704a87 115 if (!fflg) {
731d7e2f 116 fprintf(stderr, "rm: %s not changed\n", arg);
b2704a87
RC
117 errcode++;
118 }
d1e4967d
RC
119 return (0); /* error */
120 }
731d7e2f 121 if ((dirp = opendir(arg)) == NULL) {
b2704a87 122 if (!fflg) {
731d7e2f 123 fprintf(stderr, "rm: cannot read %s?\n", arg);
b2704a87
RC
124 errcode++;
125 }
d1e4967d
RC
126 return (0);
127 }
731d7e2f
RC
128 if (level == 0)
129 append(arg);
d1e4967d
RC
130 prevname[0] = '\0';
131 while ((dp = readdir(dirp)) != NULL) {
132 if (dotname(dp->d_name)) {
133 strcpy(prevname, dp->d_name);
134 continue;
ae80f4a2 135 }
731d7e2f 136 append(dp->d_name);
c1a06f06 137 closedir(dirp);
731d7e2f
RC
138 ok = rm(path, level + 1);
139 for (cp = pathp; *--cp != '/' && cp > path; )
140 ;
141 pathp = cp;
142 *cp++ = '\0';
143 if ((dirp = opendir(arg)) == NULL) {
b2704a87 144 if (!fflg) {
731d7e2f 145 fprintf(stderr, "rm: cannot read %s?\n", arg);
b2704a87
RC
146 errcode++;
147 }
d1e4967d
RC
148 break;
149 }
150 /* pick up where we left off */
151 if (prevname[0] != '\0') {
152 while ((dp = readdir(dirp)) != NULL &&
153 strcmp(prevname, dp->d_name) != 0)
154 ;
155 }
156 /* skip the one we just failed to delete */
157 if (!ok) {
158 dp = readdir(dirp);
731d7e2f
RC
159 if (dp != NULL && strcmp(cp, dp->d_name)) {
160 fprintf(stderr,
161 "rm: internal synchronization error: %s, %s, %s\n",
162 arg, cp, dp->d_name);
163 }
164 strcpy(prevname, dp->d_name);
fc96c1d6 165 }
ae80f4a2 166 }
d1e4967d 167 closedir(dirp);
731d7e2f
RC
168 if (level == 0) {
169 pathp = path;
170 *pathp = '\0';
d1e4967d
RC
171 }
172 if (iflg) {
731d7e2f
RC
173 printf("rm: remove %s? ", arg);
174 if (!yes())
d1e4967d
RC
175 return (0);
176 }
177 if (rmdir(arg) < 0) {
b2704a87 178 if (!fflg || iflg) {
731d7e2f 179 fprintf(stderr, "rm: %s not removed\n", arg);
b2704a87
RC
180 errcode++;
181 }
d1e4967d
RC
182 return (0);
183 }
184 return (1);
ae80f4a2
BJ
185 }
186
d1e4967d 187 if (iflg) {
731d7e2f
RC
188 printf("rm: remove %s? ", arg);
189 if (!yes())
d1e4967d
RC
190 return (0);
191 } else if (!fflg) {
192 if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) {
731d7e2f
RC
193 printf("rm: override protection %o for %s? ",
194 buf.st_mode&0777, arg);
195 if (!yes())
d1e4967d 196 return (0);
ae80f4a2
BJ
197 }
198 }
d1e4967d 199 if (unlink(arg) < 0) {
b2704a87 200 if (!fflg || iflg) {
731d7e2f 201 fprintf(stderr, "rm: %s not removed\n", arg);
b2704a87
RC
202 errcode++;
203 }
d1e4967d 204 return (0);
ae80f4a2 205 }
d1e4967d 206 return (1);
ae80f4a2
BJ
207}
208
d1e4967d
RC
209/*
210 * boolean: is it "." or ".." ?
211 */
ae80f4a2 212dotname(s)
d1e4967d 213 char *s;
ae80f4a2 214{
d1e4967d
RC
215 if (s[0] == '.')
216 if (s[1] == '.')
217 if (s[2] == '\0')
218 return (1);
ae80f4a2 219 else
d1e4967d
RC
220 return (0);
221 else if (s[1] == '\0')
222 return (1);
223 return (0);
ae80f4a2
BJ
224}
225
d1e4967d
RC
226/*
227 * Get a yes/no answer from the user.
228 */
731d7e2f 229yes()
ae80f4a2
BJ
230{
231 int i, b;
232
233 i = b = getchar();
d1e4967d 234 while (b != '\n' && b != EOF)
ae80f4a2 235 b = getchar();
d1e4967d
RC
236 return (i == 'y');
237}
238
239/*
731d7e2f 240 * Append 'name' to 'path'.
d1e4967d 241 */
731d7e2f
RC
242append(name)
243 char *name;
d1e4967d 244{
731d7e2f 245 register int n;
d1e4967d 246
731d7e2f
RC
247 n = strlen(name);
248 if (path == NULL) {
5780b382 249 pathsz = MAXNAMLEN + MAXPATHLEN + 2;
731d7e2f
RC
250 if ((path = malloc(pathsz)) == NULL) {
251 fprintf(stderr, "rm: ran out of memory\n");
252 exit(1);
253 }
254 pathp = path;
255 } else if (pathp + n + 2 > path + pathsz) {
5780b382
JB
256 fprintf(stderr, "rm: path name too long: %s\n", path);
257 exit(1);
731d7e2f
RC
258 } else if (pathp != path && pathp[-1] != '/')
259 *pathp++ = '/';
260 strcpy(pathp, name);
261 pathp += n;
ae80f4a2 262}