[1764] in Release_Engineering
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);
}
----------------