1BSD/s6/rmtree.c

Compare this file to the similar file:
Show the results in this format:

#
/* UCB rmtree
 * rmtree dir . . .
 * author: Kurt Shoens
 * recursively removes files and directories
 * in a subtree.  The -v flag prevents it from
 * removing the final directory, ie the one
 * you specify.  The incredible danger of
 * this program must by now be apparent to you.  It
 * asks you if you are sure on each argument.
 */


#define ENOTDIR 20
#define ENOENT 2

#define STACKSIZE 1024

int vflag;
int errs;
int fflag;
int cflag;
int active;

/* set warnflag true to get "last chance before . . . " */

int warnflag 1;

char pathname[STACKSIZE];

char *pathptr;
char *myname;

extern errno;

main(ct,av)
	char **av;
{
	int level,i,thiser;
	char crap[36];
	setuid(getuid());
	myname = av[0];
/*
 *	if (getuid())
 *	{
 *		printf("sorry, not super user\n");
 *		exit(1);
 *	}
 */
	if (ct<2)
	{
		usage(myname);
		exit(9);
	}
	for (i=1;i<ct;++i)
	{
		if (*av[i] == '-')
		{
			process(av[i]);
			continue;
		}
		++active;
		if (stat(av[i],crap))
		{
			perror(av[i]);
			errs++;
			continue;
		}
		if (!dir(av[i]))
		{
			errno = ENOTDIR;
			perror(av[i]);
			errs++;
		}
		else
		{
			if (warning(av[i],warnflag && !fflag))
			{
				if (cflag && !vflag) chmod(av[i], 0700);
				pathptr = pathname;
				pushstr(av[i]);
				thiser = descend();
				errs =+ thiser;
				if (!vflag && !thiser) errs =+ rmdir(av[i]);
			}
		}
	}
	if (!active)
	{
		usage(myname);
		exit(9);
	}
	exit(errs);
}

descend()
{
	int offset,j,err,markerr,xcnt;
	static f,inum,*ip;
	register char *cp;
	char name[16];
	markerr=0;
	offset=16;
	f=open(pathname,0);
	if (f==-1)
	{
		prs(pathname);
		prs(": no read permission\n");
		return(1);
	}
	j=read(f,name,16);
	xcnt=0;
	while (j)
	{
		ip=name;
		inum= *ip;
		if (!scomp(&name[2],".") && !scomp(&name[2],"..") && inum)
		{
			if (!xcnt++) if (access(pathname,3))
			{
				prs(pathname);
				prs(": need both X and W permission\n");
				close(f);
				return(1);
			}
			pushstr(&name[2]);
			if (dir(pathname))
			{
				close(f);
				if (cflag) chmod(pathname, 0700);
				err=descend();
				if (!err) rmdir(pathname);
				else markerr=1;
				popstr();
				f = open(pathname,0);
				seek(f,offset,0);
			}
			else
			{

				/* if unlink fails, keeps going ?? */

				if (rm(pathname)) markerr=1;
				popstr();
			}
		}
		j=read(f,name,16);
		offset=offset+16;
	}
	close(f);
	return(markerr);
}

rmdir(str)
	char *str;
{
	int p;
	p = fork();
	if (!p)
	{
		execl("/bin/rmdir","rmdir",str,0);
		perror("/bin/rmdir");
		exit(1);
	}
	else wait(&p);
	return(p);
}

rm(f)
	char *f;
{
	if (quota(f) && vflag) return(1);
	if (unlink(f))
	{
		perror(f);
		return(1);
	}
	return(0);
}

popstr()
{
	--pathptr;
	while (*pathptr != '/') --pathptr;
	while (*pathptr == '/') --pathptr;
	*++pathptr = 0;
}

dir(n)
	char *n;
{
     struct inode {
       char  minor;	    /* +0: minor device of i-node */
       char  major;	    /* +1: major device */
       int   inumber;	    /* +2 */
       int   flags;	    /* +4: see below */
       char  nlinks;	    /* +6: number of links to file */
       char  uid;	    /* +7: user ID of owner */
       char  gid;	    /* +8: group ID of owner */
       char  size0;	    /* +9: high byte of 24-bit size */
       int   size1;	    /* +10: low word of 24-bit size */
       int   addr[8];	    /* +12: block numbers or device number */
       int   actime[2];     /* +28: time of last access */
       int   modtime[2];    /* +32: time of last modification */
     } buf;
	if (stat(n,&buf)) return(0);
	return((buf.flags & 060000) == 040000);
}

quota(n)
	char *n;
{
     struct inode {
       char  minor;	    /* +0: minor device of i-node */
       char  major;	    /* +1: major device */
       int   inumber;	    /* +2 */
       int   flags;	    /* +4: see below */
       char  nlinks;	    /* +6: number of links to file */
       char  uid;	    /* +7: user ID of owner */
       char  gid;	    /* +8: group ID of owner */
       char  size0;	    /* +9: high byte of 24-bit size */
       int   size1;	    /* +10: low word of 24-bit size */
       int   addr[8];	    /* +12: block numbers or device number */
       int   actime[2];     /* +28: time of last access */
       int   modtime[2];    /* +32: time of last modification */
     } buf;
	if (stat(n,&buf)) return(0);
	return((buf.flags & 060000) == 020000 && buf.addr[0] == -1);
}

scomp(n1,n2)
	char *n1,*n2;
{
	char left,right;
	left= *n1;
	right= *n2;
	while (left && right)
	{
		if (left!=right) return(0);
		++n1;
		++n2;
		left= *n1;
		right= *n2;
	}
	return(left==right);
}

actual(str)
	char *str;
{
	register char *f;
	register slash;
	f = str;
	if (*f == '/') return(f);
	slash = 0;
	while (*f) if (*f++ == '/') slash++;
	if (!slash) return(str);
	while (*f != '/') --f;
	++f;
	return(f);
}

warning(file,f)
	char *file;
{
	char line[20];
	if (!f) return;
	if (gtty(0,line)) return;
	printf("last chance before OBLITERATING %s\n",file);
	printf("ok? ");
	line[read(0,line,20)] = 0;
	return(*line == 'y' || *line == 'Y');
}

process(str)
	char *str;
{
	while (*str) switch(*str++)
	{
	case 'c':
		cflag++;
		break;

	case 'v':
		vflag = 1;
		break;

	case 'f':
		fflag = 1;
		break;

	case 's':
		fflag = 0;
		break;

	case 'a':
		vflag = 0;
		break;

	case '-':
		break;

	default:
		printf("unknown switch: %c\n", *--str);
		exit(1);
	}
}

usage(str)
	char *str;
{
	printf("Usage: %s [ -acfsv ] dir ...\n",str);
	errs++;
}

prs(str)
	char *str;
{
	register char *f;
	f = str;
	while (*f) ++f;
	write(2, str, f-str);
}

pushstr(str)
	char *str;
{
	if (pathptr != pathname) *pathptr++ = '/';
	while (*pathptr++ = *str++) if (pathptr >= pathname + STACKSIZE)
		panic("path name too long");
	pathptr--;
}

panic(str)
	char *str;
{
	prs("PANIC: ");
	prs(str);
	prs("\n");
	exit(1);
}