[1764] in Release_Engineering

home help back first fref pref prev next nref lref last post

NFS server crontabs and other files

daemon@ATHENA.MIT.EDU (John Carr)
Wed Oct 11 08:23:24 1989

To: rel-eng@ATHENA.MIT.EDU
Cc: dkk@ATHENA.MIT.EDU
Date: Wed, 11 Oct 89 08:22:37 EDT
From: John Carr <jfc@ATHENA.MIT.EDU>

The following is the result of dkk's and my work on temporary file cleanup on
NFS servers.  The scripts included are now running on several NFS servers.

All instances of "/usr/local" in the following except in the string
"/usr/local/filesystems" should be replaced by the name of a directory of
release engineering's choice, and the programs should be installed there.

Source can also be found in /afs/athena/user/j/jfc/src/servers, as well as in
the body of this message.  Files are delimited by 16 dashes.

Contents:

	Addition to /usr/lib/crontab
	Addition to /etc/athena/newsyslog.conf
	2 Bourne shell scripts ("find-daily", "find-weekly")
	2 C programs "rchown.c" (new), "rm.c" (modified version)

Add to /usr/lib/crontab, NFS servers only:

----------------
10 3 * * 2,4,7  root /usr/local/find-daily
10 3 * * 6      root /usr/local/find-weekly
----------------

Add to newsyslog.conf (either NFS servers or global):
----------------
/site/usr/adm/find-times 644 1 10 *
----------------

/usr/local/find-daily:
----------------
#!/bin/sh
/bin/echo -n "Daily find started at: " >> /usr/adm/find-times
/bin/date >> /usr/adm/find-times
if [ -r /usr/local/filesystems ]; then
DIRS=`cat /usr/local/filesystems`
else
DIRS=`awk '{print $1}' /etc/exports`
fi
find $DIRS -xdev \( \( -atime +3 -mtime +3 \( -name '.#*' -o -name '#*' \) \) -o \( -atime +5 -mtime +7 -type f -name 'core' \) \)  -print > /usr/adm/rmlist 2>> /usr/adm/finderr
/bin/rm -F /usr/adm/rmlist > /usr/adm/rmerr 2>&1
/bin/echo -n "Daily find done at: " >> /usr/adm/find-times
/bin/date >> /usr/adm/find-times
----------------

/usr/local/find-weekly:
----------------
#!/bin/sh
/bin/echo -n 'Weekly "nobody" find begins at: ' >> /usr/adm/find-times
/bin/date >> /usr/adm/find-times
if [ -r /usr/local/filesystems ]; then
DIRS=`cat /usr/local/filesystems`
else
DIRS=`awk '{print $1}' /etc/exports`
fi
find $DIRS -xdev -user 32767 -print > /usr/adm/find-nobody-out 2>> /usr/adm/finderr
/bin/echo -n 'Weekly "nobody" find done at: ' >> /usr/adm/find-times
/bin/date >> /usr/adm/find-times
/usr/local/rchown -F /usr/adm/find-nobody-out
----------------

rchown.c:
----------------
/* chown a file to the nearest owner not equal to the current owner:
 *
 *  foo (owner x)
 *   |
 *  bar (owner y)
 *
 *  chowns bar to x.
 *
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <strings.h>
#define NOBODY 32767

static char last_dir[MAXPATHLEN];
int last_uid, last_gid;

int main(argc,argv)
int argc;
char *argv[];
{
  register int i;
  char buf[MAXPATHLEN+1];
  if(argc < 2 || argv[1] == NULL)
    exit(2);
  if(argv[1][0] == '-' && argv[1][1] == 'F' && argc == 3)
    {
      FILE *file;
      if((file = fopen(argv[2],"r")) == NULL)
	exit(3);
      while(fgets(buf,sizeof(buf),file) != NULL)
	{
	  register int tmp;
	  if(buf[tmp=strlen(buf)-1] == '\n')
	    buf[tmp] = '\0';
	  do_chown(buf,0);
	}
    } else {
      for(i=1;i<argc;i++)
	do_chown(argv[i],0);
    }
}


do_chown(str,r)
char *str;
int r;
{
  char tmp[MAXPATHLEN];
  struct stat st;
  register char *c;
#ifdef DEBUG
  printf("do_chown(\"%s\",%d)\n", str, r);
  fflush(stdout);
#endif
  if((c = rindex(str,'/')) == NULL)
    {
      fputs("Warning, file \"",stderr);
      fputs(str,stderr);
      fputs("\" contains no '/'.\n", stderr);
    } else {
      strncpy(tmp,str, c - str + (c - str == 0));
      tmp[c-str+(c-str==0)] = '\0';
      /* Optimization */
      if (strcmp(tmp, last_dir))
	{
#ifdef DEBUG
	  printf("stat(\"%s\")\n", tmp);
#endif
	  if(!r)
	    {
	      strcpy(last_dir, tmp);
	    }
	  if(stat(tmp, &st) == -1)
	    {
	      error("stat",tmp);
	    }
	  if(st.st_uid == NOBODY)
	    {
	      do_chown(tmp,1);
#ifdef DEBUG
	      printf("stat(\"%s\")\n", tmp);
#endif
	      if(stat(tmp, &st) == -1)
		error("stat",tmp);
	    }
	  if(!r)
	    {
	      last_uid = st.st_uid;
	      last_gid = st.st_gid;
	    }
	}
#ifdef DEBUG
      printf("chown(\"%s\",%d,%d)\n", str,st.st_uid,st.st_gid);
      fflush(stdout);
#endif
      if(chown(str, st.st_uid, st.st_gid) == -1)
	error("chown",str);
    }
}

extern int errno;
extern char *sys_errlist[];

error(fn,str)
char *fn,*str;
{
  fputs("rchown: ", stderr);
  fputs(fn, stderr);
  fputs(": \"", stderr);
  fputs(str, stderr);
  fputs("\":", stderr);
  fputs(sys_errlist[errno], stderr);
  putc('\n', stderr);  
}
#if 0
#ifdef DEBUG
int chown(a,b,c)
char *a;
int b,c;
{
  printf("chown(\"%s\",%d,%d)\n",a,b,c);
  return 0;
}
#endif
#endif
----------------

Last, a new version of /bin/rm.  This version is half the size of the
old one on the RT, due to removal of calls to "printf".

rm.c:
----------------
static char *sccsid = "@(#)rm.c	4.18 (Berkeley) 1/6/86";

/*
 * rm - for ReMoving files, directories & trees.
 */

#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <errno.h>
extern int errno;
extern char *sys_errlist[];

int	fflg;		/* -f force - supress error messages */
int	iflg;		/* -i interrogate user on each file */
int	rflg;		/* -r recurse */
int	Fflg;		/* -F file - read input from a file */
int	errcode;	/* true if errors occured */

char	*strcpy(), *malloc(), *realloc();

void usage()

{
  fputs("usage: rm [-rif[F file]] file ...\n",stderr);
  exit(1);
}

main(argc, argv)
	char *argv[];
{
	register char *arg;
	register char *source_file;

	fflg = !isatty(0);
	iflg = 0;
	rflg = 0;
	while (argc > 1 && argv[1][0] == '-') {
		arg = *++argv;
		argc--;

		/*
		 *  all files following a null option are considered file names
		 */
		if (arg[1] == '\0')
			break;

		while (*++arg != '\0')
			switch(*arg) {
			case 'f':
				fflg++;
				break;

			case 'F':
				Fflg++;
				if(0 == (source_file = *++argv))
					usage();
				break;

			case 'i':
				iflg++;
				break;

			case 'R':
			case 'r':
				rflg++;
				break;

			default:
				usage();
			}
	}

	if (argc < 2 && !fflg)
		usage();


	if(Fflg) {
		FILE *fp;
		char f[256];
		fp = fopen(source_file,"r");
		if(fp == NULL) {
			rep_error("unable to open \"%1\", %2.\n",
				  source_file,sys_errlist[errno]);
			exit(1);
		}
		while(fgets(f,256,fp)) {
			if(!*f) continue;
			f[strlen(f)-1]='\0';	/* Strip a trailing newline */
			rm(f,0);
		}
	} else {
		while (--argc > 0)
			(void) rm(*++argv, 0);
	}

	exit(errcode != 0);
}

char	*path;		/* pointer to malloc'ed buffer for path */
char	*pathp;		/* current pointer to end of path */
int	pathsz;		/* size of path */

/*
 * Return TRUE if sucessful. Recursive with -r (rflg)
 */
rm(arg, level)
	char arg[];
{
	int ok;				/* true if recursive rm succeeded */
	struct stat buf;		/* for finding out what a file is */
	struct direct *dp;		/* for reading a directory */
	DIR *dirp;			/* for reading a directory */
	char prevname[MAXNAMLEN + 1];	/* previous name for -r */
	char *cp;

	if (dotname(arg)) {
		if (!fflg) 
			fputs("rm: cannot remove `.' or `..'\n",stderr);
		return (0);
	}
	if (lstat(arg, &buf)) {
		if (!fflg) {
			if(errno == ENOENT)
				rep_error("%1 nonexistent\n", arg,0,0);
			else
				rep_error("%1: %2",arg,sys_errlist[errno]);
			errcode++;
		}
		return (0);		/* error */
	}
	if ((buf.st_mode&S_IFMT) == S_IFDIR) {
		if (!rflg) {
			if (!fflg) {
				rep_error("%1 directory\n", arg);
				errcode++;
			}
			return (0);
		}
		if (iflg && level != 0) {
			msg("remove directory %1? ", arg);
			if (!yes())
				return (0);	/* didn't remove everything */
		}
		if (access(arg, R_OK|W_OK|X_OK) != 0) {
			if (rmdir(arg) == 0)
				return (1);	/* salvaged: removed empty dir */
			if (!fflg) {
			  rep_error("%1 not changed (permission denied)\n", arg);
				errcode++;
			}
			return (0);		/* error */
		}
		if ((dirp = opendir(arg)) == NULL) {
			if (!fflg) {
				rep_error("cannot read %1?\n", arg);
				errcode++;
			}
			return (0);
		}
		if (level == 0)
			append(arg);
		prevname[0] = '\0';
		while ((dp = readdir(dirp)) != NULL) {
			if (dotname(dp->d_name)) {
				strcpy(prevname, dp->d_name);
				continue;
			}
			append(dp->d_name);
			closedir(dirp);
			ok = rm(path, level + 1);
			for (cp = pathp; *--cp != '/' && cp > path; )
				;
			pathp = cp;
			*cp++ = '\0';
			if ((dirp = opendir(arg)) == NULL) {
				if (!fflg) {
					rep_error("cannot read %1?\n", arg);
					errcode++;
				}
				break;
			}
			/* pick up where we left off */
			if (prevname[0] != '\0') {
				while ((dp = readdir(dirp)) != NULL &&
				    strcmp(prevname, dp->d_name) != 0)
					;
			}
			/* skip the one we just failed to delete */
			if (!ok) {
				dp = readdir(dirp);
				if (dp != NULL && strcmp(cp, dp->d_name)) {
					rep_error("internal synchronization error: %1, %2, %3\n",
						  arg, cp, dp->d_name);
				}
				strcpy(prevname, dp->d_name);
			}
		}
		closedir(dirp);
		if (level == 0) {
			pathp = path;
			*pathp = '\0';
		}
		if (iflg) {
			msg("remove %1? ", arg);
			if (!yes())
				return (0);
		}
		if (rmdir(arg) < 0) {
			if (!fflg || iflg) {
				rep_error("%1 not removed: %2\n",
					  arg,sys_errlist[errno]);
				errcode++;
			}
			return (0);
		}
		return (1);
	}

	if (iflg) {
		msg("remove %1? ", arg);
		if (!yes())
			return (0);
	} else if (!fflg) {
		if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) {
		  /* printf("rm: override protection %o for %s? ",
		     buf.st_mode&0777, arg); */
		msg("override protection for %1? ",arg,0,0);
			if (!yes())
				return (0);
		}
	}
	if (unlink(arg) < 0) {
		if (!fflg || iflg) {
			rep_error("%1 not removed: %2\n",arg,sys_errlist[errno]);
			errcode++;
		}
		return (0);
	}
	return (1);
}

/*
 * boolean: is it "." or ".." ?
 */
dotname(s)
	char *s;
{
	if (s[0] == '.')
		if (s[1] == '.')
			if (s[2] == '\0')
				return (1);
			else
				return (0);
		else if (s[1] == '\0')
			return (1);
	return (0);
}

/*
 * Get a yes/no answer from the user.
 */
yes()
{
	int i, b;

	i = b = getchar();
	while (b != '\n' && b != EOF)
		b = getchar();
	return (i == 'y');
}

/*
 * Append 'name' to 'path'.
 */
append(name)
	char *name;
{
	register int n;

	n = strlen(name);
	if (path == NULL) {
		pathsz = MAXNAMLEN + MAXPATHLEN + 2;
		if ((path = malloc(pathsz)) == NULL) {
			fputs("rm: ran out of memory\n",stderr);
			exit(1);
		}
		pathp = path;
	} else if (pathp + n + 2 > path + pathsz) {
		rep_error("path name too long : %1",path);
		exit(1);
	} else if (pathp != path && pathp[-1] != '/')
		*pathp++ = '/';
	strcpy(pathp, name);
	pathp += n;
}

rep_error(s0,s1,s2,s3)
	char *s0,*s1,*s2,*s3;
{
  char c;
  fputs("rm: ",stderr);
  while(c = *s0++) {
    if(c == '%')
      {
	if((c = *s0++) == '1')
	  fputs(s1,stderr);
	else if(c == '2') 
	  fputs(s2,stderr);
	else if(c == '3') 
	  fputs(s3,stderr);
      } else {
	putc(c,stderr);
      }
  }
  fflush(stderr);
}


msg(s0,s1,s2,s3)
	char *s0,*s1,*s2,*s3;
{
  char c;
  fputs("rm: ",stdout);
  while(c = *s0++) {
    if(c == '%')
      {
	if((c = *s0++) == '1')
	  fputs(s1,stdout);
	else if(c == '2') 
	  fputs(s2,stdout);
	else if(c == '3') 
	  fputs(s3,stdout);
      } else {
	putc(c,stdout);
      }
  }
 fflush(stdout);
}
----------------

home help back first fref pref prev next nref lref last post