xref: /csrg-svn/bin/rm/rm.c (revision 18277)
1*18277Sralph static char *sccsid = "@(#)rm.c	4.14 (Berkeley) 03/08/85";
21083Sbill 
3*18277Sralph /*
4*18277Sralph  * rm - for ReMoving files, directories & trees.
5*18277Sralph  */
6*18277Sralph 
71083Sbill #include <stdio.h>
86413Smckusic #include <sys/param.h>
91083Sbill #include <sys/stat.h>
1013491Ssam #include <sys/dir.h>
11*18277Sralph #include <sys/file.h>
121083Sbill 
13*18277Sralph int	fflg;			/* -f force - supress error messages */
14*18277Sralph int	iflg;			/* -i interrogate user on each file */
15*18277Sralph int	rflg;			/* -r recurse */
161083Sbill 
17*18277Sralph int	errcode;		/* true if errors occured */
18*18277Sralph 
19*18277Sralph char	*strcpy();
20*18277Sralph 
211083Sbill main(argc, argv)
22*18277Sralph 	char *argv[];
231083Sbill {
241083Sbill 	register char *arg;
251083Sbill 
26*18277Sralph 	fflg = !isatty(0);
271083Sbill 	iflg = 0;
281083Sbill 	rflg = 0;
29*18277Sralph 	while (argc > 1 && argv[1][0] == '-') {
301083Sbill 		arg = *++argv;
311083Sbill 		argc--;
321932Sroot 
331932Sroot 		/*
341932Sroot 		 *  all files following a null option are considered file names
351932Sroot 		 */
36*18277Sralph 		if (arg[1] == '\0')
37*18277Sralph 			break;
381932Sroot 
39*18277Sralph 		while (*++arg != '\0')
401083Sbill 			switch(*arg) {
411083Sbill 			case 'f':
421083Sbill 				fflg++;
431083Sbill 				break;
44*18277Sralph 
451083Sbill 			case 'i':
461083Sbill 				iflg++;
471083Sbill 				break;
48*18277Sralph 
4917964Sserge 			case 'R':
501083Sbill 			case 'r':
511083Sbill 				rflg++;
521083Sbill 				break;
53*18277Sralph 
541083Sbill 			default:
55*18277Sralph 				fprintf(stderr, "usage: rm [-rif] file ...\n");
561083Sbill 				exit(1);
571083Sbill 			}
581083Sbill 	}
5917964Sserge 
6017964Sserge 	if (argc < 2) {
6117964Sserge 		fprintf(stderr, "usage: rm [-rif] file ...\n");
6217964Sserge 		exit(1);
6317964Sserge 	}
6417964Sserge 
65*18277Sralph 	while (--argc > 0)
66*18277Sralph 		(void) rm(*++argv, 0);
671083Sbill 
68*18277Sralph 	exit(errcode != 0);
691083Sbill }
701083Sbill 
71*18277Sralph struct nambuf {
72*18277Sralph 	char	*name;			/* pointer to name */
73*18277Sralph 	struct	nambuf *next;		/* linked list of names */
74*18277Sralph } path, *pathp;
75*18277Sralph 
76*18277Sralph /*
77*18277Sralph  * Return TRUE if sucessful. Recursive with -r (rflg)
78*18277Sralph  */
79*18277Sralph rm(arg, level)
80*18277Sralph 	char arg[];
811083Sbill {
82*18277Sralph 	int ok;				/* true if recursive rm succeeded */
83*18277Sralph 	struct stat buf;		/* for finding out what a file is */
84*18277Sralph 	struct direct *dp;		/* for reading a directory */
85*18277Sralph 	DIR *dirp;			/* for reading a directory */
86*18277Sralph 	char name[MAXNAMLEN + 1];	/* buffer for file name */
87*18277Sralph 	char prevname[MAXNAMLEN + 1];	/* previous name for -r */
88*18277Sralph 	struct nambuf nambuf, *pp;
891083Sbill 
90*18277Sralph 	if (dotname(arg)) {
91*18277Sralph 		fprintf(stderr, "rm: cannot remove `.' or `..'\n");
92*18277Sralph 		return (0);
931083Sbill 	}
94*18277Sralph 	if (level == 0) {
95*18277Sralph 		path.name = arg;
96*18277Sralph 		path.next = NULL;
97*18277Sralph 		pathp = &path;
98*18277Sralph 	}
99*18277Sralph 	if (lstat(arg, &buf)) {
100*18277Sralph 		if (!fflg)
101*18277Sralph 			error("nonexistent");
102*18277Sralph 		errcode++;
103*18277Sralph 		return (0);		/* error */
104*18277Sralph 	}
1051083Sbill 	if ((buf.st_mode&S_IFMT) == S_IFDIR) {
106*18277Sralph 		if (!rflg) {
107*18277Sralph 			error("directory");
108*18277Sralph 			errcode++;
109*18277Sralph 			return (0);
110*18277Sralph 		}
111*18277Sralph 		if (access(arg, R_OK|W_OK|X_OK) != 0) {
112*18277Sralph 			if (rmdir(arg) == 0)
113*18277Sralph 				return (1);	/* salvaged: removed empty dir */
114*18277Sralph 			if (!fflg)
115*18277Sralph 				error("not changed");
116*18277Sralph 			errcode++;
117*18277Sralph 			return (0);		/* error */
118*18277Sralph 		}
119*18277Sralph 		if (iflg && level != 0) {
120*18277Sralph 			if (!yes("remove directory"))
121*18277Sralph 				return (0);	/* didn't remove everything */
122*18277Sralph 		}
123*18277Sralph 		if (chdir(arg) < 0 || (dirp = opendir(".")) == NULL) {
124*18277Sralph 			if (!fflg)
125*18277Sralph 				error("cannot read?");
126*18277Sralph 			errcode++;
127*18277Sralph 			return (0);
128*18277Sralph 		}
129*18277Sralph 		nambuf.name = name;
130*18277Sralph 		nambuf.next = NULL;
131*18277Sralph 		pathp->next = &nambuf;
132*18277Sralph 		pp = pathp;
133*18277Sralph 		pathp = &nambuf;
134*18277Sralph 		prevname[0] = '\0';
135*18277Sralph 		while ((dp = readdir(dirp)) != NULL) {
136*18277Sralph 			if (dotname(dp->d_name)) {
137*18277Sralph 				strcpy(prevname, dp->d_name);
138*18277Sralph 				continue;
139*18277Sralph 			}
140*18277Sralph 			strcpy(name, dp->d_name);
141*18277Sralph 			closedir(dirp);
142*18277Sralph 			ok = rm(name, level + 1);
143*18277Sralph 			if ((dirp = opendir(".")) == NULL) {
144*18277Sralph 				if (!fflg)
145*18277Sralph 					error("cannot read?");
1461083Sbill 				errcode++;
147*18277Sralph 				break;
1481083Sbill 			}
149*18277Sralph 			/* pick up where we left off */
150*18277Sralph 			if (prevname[0] != '\0') {
151*18277Sralph 				while ((dp = readdir(dirp)) != NULL &&
152*18277Sralph 				    strcmp(prevname, dp->d_name) != 0)
153*18277Sralph 					;
1541083Sbill 			}
155*18277Sralph 			/* skip the one we just failed to delete */
156*18277Sralph 			if (!ok) {
157*18277Sralph 				dp = readdir(dirp);
158*18277Sralph 				if (dp != NULL && strcmp(name, dp->d_name) != 0)
159*18277Sralph 					error("internal synchronization error");
160*18277Sralph 				strcpy(prevname, name);
1611083Sbill 			}
1621083Sbill 		}
163*18277Sralph 		closedir(dirp);
164*18277Sralph 		pathp = pp;
165*18277Sralph 		pathp->next = NULL;
166*18277Sralph 		if (chdir("..") < 0) {
167*18277Sralph 			if (!fflg)
168*18277Sralph 				error("cannot cd to '..'?");
169*18277Sralph 			errcode++;
170*18277Sralph 			return (0);
171*18277Sralph 		}
172*18277Sralph 		if (iflg) {
173*18277Sralph 			if (!yes("remove"))
174*18277Sralph 				return (0);
175*18277Sralph 		}
176*18277Sralph 		if (rmdir(arg) < 0) {
177*18277Sralph 			if (!fflg || iflg)
178*18277Sralph 				error("not removed");
179*18277Sralph 			errcode++;
180*18277Sralph 			return (0);
181*18277Sralph 		}
182*18277Sralph 		return (1);
1831083Sbill 	}
1841083Sbill 
185*18277Sralph 	if (iflg) {
186*18277Sralph 		if (!yes("remove"))
187*18277Sralph 			return (0);
188*18277Sralph 	} else if (!fflg) {
189*18277Sralph 		if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) {
190*18277Sralph 			sprintf(name, "override protection %o for",
191*18277Sralph 				buf.st_mode&0777);
192*18277Sralph 			if (!yes(name))
193*18277Sralph 				return (0);
1941083Sbill 		}
1951083Sbill 	}
196*18277Sralph 	if (unlink(arg) < 0) {
197*18277Sralph 		if (!fflg || iflg)
198*18277Sralph 			error("not removed");
199*18277Sralph 		errcode++;
200*18277Sralph 		return (0);
2011083Sbill 	}
202*18277Sralph 	return (1);
2031083Sbill }
2041083Sbill 
205*18277Sralph /*
206*18277Sralph  * boolean: is it "." or ".." ?
207*18277Sralph  */
2081083Sbill dotname(s)
209*18277Sralph 	char *s;
2101083Sbill {
211*18277Sralph 	if (s[0] == '.')
212*18277Sralph 		if (s[1] == '.')
213*18277Sralph 			if (s[2] == '\0')
214*18277Sralph 				return (1);
2151083Sbill 			else
216*18277Sralph 				return (0);
217*18277Sralph 		else if (s[1] == '\0')
218*18277Sralph 			return (1);
219*18277Sralph 	return (0);
2201083Sbill }
2211083Sbill 
222*18277Sralph /*
223*18277Sralph  * Get a yes/no answer from the user.
224*18277Sralph  */
225*18277Sralph yes(msg)
226*18277Sralph 	char *msg;
2271083Sbill {
228*18277Sralph 	register struct nambuf *pp;
2291083Sbill 	int i, b;
2301083Sbill 
231*18277Sralph 	printf("rm: %s %s", msg, path.name);
232*18277Sralph 	for (pp = &path; pp->next != NULL; pp = pp->next)
233*18277Sralph 		printf("/%s", pp->next->name);
234*18277Sralph 	printf("? ");
2351083Sbill 	i = b = getchar();
236*18277Sralph 	while (b != '\n' && b != EOF)
2371083Sbill 		b = getchar();
238*18277Sralph 	return (i == 'y');
2391083Sbill }
240*18277Sralph 
241*18277Sralph /*
242*18277Sralph  * Print the current path and error message.
243*18277Sralph  */
244*18277Sralph error(msg)
245*18277Sralph 	char *msg;
246*18277Sralph {
247*18277Sralph 	register struct nambuf *pp;
248*18277Sralph 
249*18277Sralph 	fprintf(stderr, "rm: %s", path.name);
250*18277Sralph 	for (pp = &path; pp->next != NULL; pp = pp->next)
251*18277Sralph 		fprintf(stderr, "/%s", pp->next->name);
252*18277Sralph 	fprintf(stderr, ": %s\n", msg);
253*18277Sralph }
254