added -r option to remove extra files.
authorRalph Campbell <ralph@ucbvax.Berkeley.EDU>
Fri, 21 Oct 1983 04:15:12 +0000 (20:15 -0800)
committerRalph Campbell <ralph@ucbvax.Berkeley.EDU>
Fri, 21 Oct 1983 04:15:12 +0000 (20:15 -0800)
SCCS-vsn: usr.bin/rdist/defs.h 4.5
SCCS-vsn: usr.bin/rdist/docmd.c 4.5
SCCS-vsn: usr.bin/rdist/expand.c 4.4
SCCS-vsn: usr.bin/rdist/gram.y 4.5
SCCS-vsn: usr.bin/rdist/main.c 4.6
SCCS-vsn: usr.bin/rdist/server.c 4.5

usr/src/usr.bin/rdist/defs.h
usr/src/usr.bin/rdist/docmd.c
usr/src/usr.bin/rdist/expand.c
usr/src/usr.bin/rdist/gram.y
usr/src/usr.bin/rdist/main.c
usr/src/usr.bin/rdist/server.c

index 1ebeacb..2ee3d1e 100644 (file)
@@ -1,4 +1,4 @@
-/*     defs.h  4.4     83/10/12        */
+/*     defs.h  4.5     83/10/20        */
 
 #include <stdio.h>
 #include <ctype.h>
 
 #include <stdio.h>
 #include <ctype.h>
 #define        MAILCMD         "/usr/lib/sendmail -oi -t"
 
        /* defines for yacc */
 #define        MAILCMD         "/usr/lib/sendmail -oi -t"
 
        /* defines for yacc */
-#define EQUAL 1
-#define LP 2
-#define RP 3
-#define ARROW 4
-#define DCOLON 5
-#define NAME 6
-#define INSTALL 7
-#define NOTIFY 8
-#define EXCEPT 9
-#define OPTION 10
-#define VAR 11
+#define EQUAL  1
+#define LP     2
+#define RP     3
+#define SM     4
+#define ARROW  5
+#define DCOLON 6
+#define NAME   7
+#define INSTALL        8
+#define NOTIFY 9
+#define EXCEPT 10
+#define OPTION 11
+#define VAR    12
 
        /* lexical definitions */
 #define        QUOTE   0200            /* used internally for quoted characters */
 #define        TRIM    0177            /* Mask to strip quote bit */
 
        /* table sizes */
 
        /* lexical definitions */
 #define        QUOTE   0200            /* used internally for quoted characters */
 #define        TRIM    0177            /* Mask to strip quote bit */
 
        /* table sizes */
-#define HASHSIZE 1021
-#define INMAX 3500
-#define NCARGS 10240
-#define GAVSIZ NCARGS / 6
-#define NSTAMPS 15
+#define HASHSIZE       1021
+#define INMAX  3500
+#define NCARGS 10240
+#define GAVSIZ NCARGS / 6
+#define NSTAMPS        15
 
        /* option flags */
 
        /* option flags */
-#define VERIFY 1
-#define WHOLE 2
-#define YOUNGER 4
-#define STRIP 8
+#define VERIFY 0x1
+#define WHOLE  0x2
+#define YOUNGER        0x4
+#define STRIP  0x8
+#define REMOVE 0x10
+
+#define ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 
 #define ALLOC(x) (struct x *) malloc(sizeof(struct x))
 
 
 #define ALLOC(x) (struct x *) malloc(sizeof(struct x))
 
index 5c53133..f9c4b73 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)docmd.c     4.4 (Berkeley) 83/10/12";
+static char *sccsid = "@(#)docmd.c     4.5 (Berkeley) 83/10/20";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -51,11 +51,15 @@ dohcmds(files, hosts, cmds)
                        }
                found:
                        n = 0;
                        }
                found:
                        n = 0;
-                       for (c = cmds; c != NULL; c = c->b_next)
-                               if (c->b_type == INSTALL) {
+                       for (c = cmds; c != NULL; c = c->b_next) {
+                               if (c->b_type != INSTALL)
+                                       continue;
+                               n++;
+                               if (c->b_name == NULL)
+                                       install(f->b_name, f->b_name, 0, c->b_options);
+                               else
                                        install(f->b_name, c->b_name, ddir, c->b_options);
                                        install(f->b_name, c->b_name, ddir, c->b_options);
-                                       n++;
-                               }
+                       }
                        if (n == 0)
                                install(f->b_name, f->b_name, 0, options);
                }
                        if (n == 0)
                                install(f->b_name, f->b_name, 0, options);
                }
@@ -123,9 +127,10 @@ install(src, dest, destdir, opts)
                return;
 
        if (nflag || debug) {
                return;
 
        if (nflag || debug) {
-               printf("%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
+               printf("%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
                        opts & WHOLE ? " -w" : "",
                        opts & WHOLE ? " -w" : "",
-                       opts & YOUNGER ? " -y" : "", src, dest);
+                       opts & YOUNGER ? " -y" : "",
+                       opts & REMOVE ? " -r" : "", src, dest);
                if (nflag)
                        return;
        }
                if (nflag)
                        return;
        }
@@ -139,6 +144,10 @@ install(src, dest, destdir, opts)
 
        if (!destdir && (opts & WHOLE))
                opts |= STRIP;
 
        if (!destdir && (opts & WHOLE))
                opts |= STRIP;
+       if (opts & REMOVE) {
+               opts &= ~REMOVE;
+               rmchk(src, NULL, opts);
+       }
        sendf(src, NULL, opts);
 }
 
        sendf(src, NULL, opts);
 }
 
index 62e4044..fb4c75d 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)expand.c    4.3 (Berkeley) 83/10/10";
+static char *sccsid = "@(#)expand.c    4.4 (Berkeley) 83/10/20";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -257,7 +257,7 @@ matchdir(pattern)
        }
        if (fstat(dirp->dd_fd, &stb) < 0)
                goto patherr1;
        }
        if (fstat(dirp->dd_fd, &stb) < 0)
                goto patherr1;
-       if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+       if (!ISDIR(stb.st_mode)) {
                errno = ENOTDIR;
                goto patherr1;
        }
                errno = ENOTDIR;
                goto patherr1;
        }
@@ -440,8 +440,7 @@ slash:
                        while (*s)
                                addpath(*s++);
                        addpath('/');
                        while (*s)
                                addpath(*s++);
                        addpath('/');
-                       if (stat(path, &stb) == 0 &&
-                           (stb.st_mode & S_IFMT) == S_IFDIR)
+                       if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
                                if (*p == '\0') {
                                        Cat(path, "");
                                        argcnt++;
                                if (*p == '\0') {
                                        Cat(path, "");
                                        argcnt++;
@@ -582,10 +581,9 @@ exptilde(buf, file)
        }
        for (s1 = buf; *s1++ = *s2++; )
                ;
        }
        for (s1 = buf; *s1++ = *s2++; )
                ;
-       s1--;
-       if (s3 == NULL)
-               return(s1);
-       while (*s1++ = *s3++)
-               ;
-       return(s1 - 1);
+       s2 = --s1;
+       if (s3 != NULL)
+               while (*s1++ = *s3++)
+                       ;
+       return(s2);
 }
 }
index af1372a..ee73c99 100644 (file)
@@ -1,6 +1,6 @@
 %{
 #ifndef lint
 %{
 #ifndef lint
-static char *sccsid = "@(#)gram.y      4.4 (Berkeley) 83/10/12";
+static char *sccsid = "@(#)gram.y      4.5 (Berkeley) 83/10/20";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -13,20 +13,22 @@ struct      block *lastc;
 %term EQUAL 1
 %term LP 2
 %term RP 3
 %term EQUAL 1
 %term LP 2
 %term RP 3
-%term ARROW 4
-%term DCOLON 5
-%term NAME 6
-%term INSTALL 7
-%term NOTIFY 8
-%term EXCEPT 9
-%term OPTION 10
+%term SM 4
+%term ARROW 5
+%term DCOLON 6
+%term NAME 7
+%term INSTALL 8
+%term NOTIFY 9
+%term EXCEPT 10
+%term OPTION 11
 
 %union {
        struct block *blk;
        int intval;
 }
 
 
 %union {
        struct block *blk;
        int intval;
 }
 
-%type <blk> NAME, INSTALL, NOTIFY, EXCEPT, namelist, names, cmdlist, cmd
+%type <blk> NAME, INSTALL, NOTIFY, EXCEPT
+%type <blk> namelist, names, opt_name, cmdlist, cmd
 %type <intval> OPTION, options
 
 %%
 %type <intval> OPTION, options
 
 %%
@@ -84,25 +86,28 @@ cmdlist:      /* VOID */ {
                }
                ;
 
                }
                ;
 
-cmd:             INSTALL options NAME = {
+cmd:             INSTALL options opt_name SM = {
                        register struct block *b;
 
                        $1->b_options = $2 | options;
                        register struct block *b;
 
                        $1->b_options = $2 | options;
-                       b = expand($3, 0);
-                       if (b == NULL || b->b_next != NULL)
-                               fatal("exactly one name allowed\n");
-                       $1->b_name = b->b_name;
+                       if ($3 != NULL) {
+                               b = expand($3, 0);
+                               if (b->b_next != NULL)
+                                       fatal("exactly one name allowed\n");
+                               $1->b_name = b->b_name;
+                       }
                        $$ = $1;
                }
                        $$ = $1;
                }
-               | NOTIFY namelist = {
+               | NOTIFY namelist SM = {
                        $1->b_args = expand($2, 1);
                        $$ = $1;
                }
                        $1->b_args = expand($2, 1);
                        $$ = $1;
                }
-               | EXCEPT namelist = {
+               | EXCEPT namelist SM = {
                        $1->b_args = expand($2, 0);
                        $$ = $1;
                }
                ;
                        $1->b_args = expand($2, 0);
                        $$ = $1;
                }
                ;
+
 options:         /* VOID */ = {
                        $$ = 0;
                }
 options:         /* VOID */ = {
                        $$ = 0;
                }
@@ -111,6 +116,14 @@ options:     /* VOID */ = {
                }
                ;
 
                }
                ;
 
+opt_name:        /* VOID */ = {
+                       $$ = NULL;
+               }
+               | NAME = {
+                       $$ = $1;
+               }
+               ;
+
 %%
 
 int    yylineno = 1;
 %%
 
 int    yylineno = 1;
@@ -148,6 +161,9 @@ again:
        case ')':  /* RP */
                return(RP);
 
        case ')':  /* RP */
                return(RP);
 
+       case ';':  /* SM */
+               return(SM);
+
        case '-':  /* -> */
                if ((c = getc(fin)) == '>')
                        return(ARROW);
        case '-':  /* -> */
                if ((c = getc(fin)) == '>')
                        return(ARROW);
@@ -179,7 +195,7 @@ again:
                }
                *cp1++ = c;
                c = getc(fin);
                }
                *cp1++ = c;
                c = getc(fin);
-               if (c == EOF || any(c, " \t()=\n")) {
+               if (c == EOF || any(c, " \t()=;\n")) {
                        ungetc(c, fin);
                        break;
                }
                        ungetc(c, fin);
                        break;
                }
@@ -187,6 +203,10 @@ again:
        *cp1 = '\0';
        if (yytext[0] == '-' && yytext[2] == '\0') {
                switch (yytext[1]) {
        *cp1 = '\0';
        if (yytext[0] == '-' && yytext[2] == '\0') {
                switch (yytext[1]) {
+               case 'r':
+                       yylval.intval = REMOVE;
+                       return(OPTION);
+
                case 'v':
                        yylval.intval = VERIFY;
                        return(OPTION);
                case 'v':
                        yylval.intval = VERIFY;
                        return(OPTION);
@@ -230,5 +250,6 @@ yyerror(s)
 {
        extern int yychar;
 
 {
        extern int yychar;
 
+       errs++;
        fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
 }
        fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
 }
index e5ecc33..faa120b 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)main.c      4.5 (Berkeley) 83/10/12";
+static char *sccsid = "@(#)main.c      4.6 (Berkeley) 83/10/20";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -88,6 +88,10 @@ main(argc, argv)
                                qflag++;
                                break;
 
                                qflag++;
                                break;
 
+                       case 'r':
+                               options |= REMOVE;
+                               break;
+
                        case 'v':
                                options |= VERIFY;
                                break;
                        case 'v':
                                options |= VERIFY;
                                break;
index a78a3fd..33a0acd 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)server.c    4.4 (Berkeley) 83/10/12";
+static char *sccsid = "@(#)server.c    4.5 (Berkeley) 83/10/20";
 #endif
 
 #include "defs.h"
 #endif
 
 #include "defs.h"
@@ -33,6 +33,7 @@ server()
        register char *cp;
        register struct block *bp, *last = NULL;
        static struct block cmdblk = { EXCEPT };
        register char *cp;
        register struct block *bp, *last = NULL;
        static struct block cmdblk = { EXCEPT };
+       int opts;
 
        sumask = umask(0);
        ga();
 
        sumask = umask(0);
        ga();
@@ -113,6 +114,19 @@ server()
                        ga();
                        continue;
 
                        ga();
                        continue;
 
+               case 'C':  /* Clean. Cleanup a directory */
+                       if (*cp < '0' || *cp > '7') {
+                               error("bad options\n");
+                               continue;
+                       }
+                       opts = *cp++ - '0';
+                       if (*cp++ != ' ') {
+                               error("options not delimited\n");
+                               continue;
+                       }
+                       clean(cp, opts, 1);
+                       continue;
+
                case 'Q':  /* Query. Does directory exist? */
                        query(cp, 1);
                        continue;
                case 'Q':  /* Query. Does directory exist? */
                        query(cp, 1);
                        continue;
@@ -327,8 +341,7 @@ update(lname, rname, opts, st)
        /*
         * Check to see if the file exists on the remote machine.
         */
        /*
         * Check to see if the file exists on the remote machine.
         */
-       (void) sprintf(buf, "%c%s\n",
-               (st->st_mode & S_IFMT) == S_IFDIR ? 'Q' : 'q', rname);
+       (void) sprintf(buf, "%c%s\n", ISDIR(st->st_mode) ? 'Q' : 'q', rname);
        if (debug)
                printf("buf = %s", buf);
        (void) write(rem, buf, strlen(buf));
        if (debug)
                printf("buf = %s", buf);
        (void) write(rem, buf, strlen(buf));
@@ -387,7 +400,7 @@ update(lname, rname, opts, st)
                if (st->st_mtime == mtime)
                        return(0);
                if (st->st_mtime < mtime) {
                if (st->st_mtime == mtime)
                        return(0);
                if (st->st_mtime < mtime) {
-                       log(lfp, "Warning: %s older than remote copy\n", lname);
+                       log(lfp, "Warning: %s: remote copy is newer\n", lname);
                        return(0);
                }
        } else if (st->st_mtime == mtime && st->st_size == size)
                        return(0);
                }
        } else if (st->st_mtime == mtime && st->st_size == size)
@@ -528,7 +541,7 @@ recvf(cmd, isdir)
                        return;
                }
                if (stat(target, &stb) == 0) {
                        return;
                }
                if (stat(target, &stb) == 0) {
-                       if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+                       if (!ISDIR(stb.st_mode)) {
                                errno = ENOTDIR;
                                goto bad;
                        }
                                errno = ENOTDIR;
                                goto bad;
                        }
@@ -744,6 +757,299 @@ ok:
        return(0);
 }
 
        return(0);
 }
 
+/*
+ * Check for files on the machine being updated that are not on the master
+ * machine and remove them.
+ */
+rmchk(lname, rname, opts)
+       char *lname, *rname;
+       int opts;
+{
+       register char *cp;
+       struct stat stb;
+
+       if (debug)
+               printf("rmchk(%s, %s, %x)\n", lname,
+                       rname != NULL ? rname : "NULL", opts);
+
+       if (exclude(lname))
+               return;
+
+       /*
+        * First time rmchk() is called?
+        */
+       if (rname == NULL) {
+               rname = exptilde(target, lname);
+               if (rname == NULL)
+                       return;
+               tp = lname = target;
+               while (*tp)
+                       tp++;
+               /*
+                * If we are renaming a directory and we want to preserve
+                * the directory heirarchy (-w), we must strip off the first
+                * directory name and preserve the rest.
+                */
+               if (opts & STRIP) {
+                       opts &= ~STRIP;
+                       rname = index(rname, '/');
+                       if (rname == NULL)
+                               rname = tp;
+                       else
+                               rname++;
+               } else if (!(opts & WHOLE)) {
+                       rname = rindex(lname, '/');
+                       if (rname == NULL)
+                               rname = lname;
+                       else
+                               rname++;
+               }
+       }
+       if (debug)
+               printf("lname = %s, rname = %s\n", lname, rname);
+       if (access(lname, 4) < 0 || stat(lname, &stb) < 0) {
+               error("%s: %s\n", lname, sys_errlist[errno]);
+               return;
+       }
+       if (!ISDIR(stb.st_mode))
+               return;
+       /*
+        * Tell the remote to clean the files from the last directory sent.
+        */
+       (void) sprintf(buf, "C%o %s\n", opts & VERIFY, rname);
+       if (debug)
+               printf("buf = %s", buf);
+       (void) write(rem, buf, strlen(buf));
+       if (response() < 0)
+               return;
+       catname = 0;
+       for (;;) {
+               cp = buf;
+               do {
+                       if (read(rem, cp, 1) != 1)
+                               lostconn();
+               } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
+
+               if (debug) {
+                       printf("readbuf = ");
+                       fwrite(buf, 1, cp - buf, stdout);
+               }
+               switch (buf[0]) {
+               case 'Q': /* its a directory on the remote end */
+               case 'q': /* its a regular file on the remote end */
+                       *--cp = '\0';
+                       (void) sprintf(tp, "/%s", buf + 1);
+                       if (debug)
+                               printf("check %s\n", target);
+                       if (stat(target, &stb) < 0)
+                               (void) write(rem, "N\n", 2);
+                       else if (buf[0] == 'Q' && ISDIR(stb.st_mode)) {
+                               if (catname >= sizeof(stp)) {
+                                       error("%s: too many directory levels\n", target);
+                                       break;
+                               }
+                               (void) write(rem, "Y\n", 2);
+                               if (response() < 0)
+                                       break;
+                               stp[catname++] = tp;
+                               while (*tp)
+                                       tp++;
+                       } else
+                               (void) write(rem, "y\n", 2);
+                       break;
+
+               case 'E':
+                       if (catname < 0)
+                               fatal("too many 'E's\n");
+                       ga();
+                       if (catname == 0)
+                               return;
+                       tp = stp[--catname];
+                       *tp = '\0';
+                       break;
+
+               case '\0':
+                       *--cp = '\0';
+                       if (buf[1])
+                               log(lfp, "%s\n", buf + 1);
+                       break;
+
+               case '\1':
+               case '\2':
+                       errs++;
+                       if (buf[1] != '\n') {
+                               if (!iamremote) {
+                                       fflush(stdout);
+                                       (void) write(2, buf + 1, cp - buf + 1);
+                               }
+                               if (lfp != NULL)
+                                       (void) fwrite(buf + 1, 1, cp - buf + 1, lfp);
+                       }
+                       if (buf[0] == '\2')
+                               cleanup();
+                       break;
+
+               default:
+                       error("unknown response type %s\n", buf[0]);
+               }
+       }
+}
+
+/*
+ * Check the directory for extraneous files and remove them.
+ */
+clean(lname, opts, first)
+       char *lname;
+       int opts, first;
+{
+       DIR *d;
+       struct direct *dp;
+       register char *cp;
+       struct stat stb;
+       char *ootp, *otp;
+       int len;
+
+       if (first) {
+               ootp = tp;
+               if (catname) {
+                       *tp++ = '/';
+                       cp = lname;
+                       while (*tp++ = *cp++)
+                               ;
+                       tp--;
+               }
+               if (stat(target, &stb) < 0) {
+                       if (errno == ENOENT) {
+                               ga();
+                               goto done;
+                       }
+               bad:
+                       error("%s: %s\n", target, sys_errlist[errno]);
+                       tp = otp;
+                       *tp = '\0';
+                       return;
+               }
+               /*
+                * This should be a directory because its a directory on the
+                * master machine. If not, let install complain about it.
+                */
+               if (!ISDIR(stb.st_mode)) {
+                       ga();
+                       goto done;
+               }
+       }
+       if (access(target, 6) < 0 || (d = opendir(target)) == NULL)
+               goto bad;
+       ga();
+
+       otp = tp;
+       len = tp - target;
+       while (dp = readdir(d)) {
+               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+                       continue;
+               if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+                       error("%s/%s: Name too long\n", target, dp->d_name);
+                       continue;
+               }
+               tp = otp;
+               *tp++ = '/';
+               cp = dp->d_name;;
+               while (*tp++ = *cp++)
+                       ;
+               tp--;
+               if (stat(target, &stb) < 0) {
+                       error("%s: %s\n", target, sys_errlist[errno]);
+                       continue;
+               }
+               (void) sprintf(buf, "%c%s\n", ISDIR(stb.st_mode) ? 'Q' : 'q',
+                       dp->d_name);
+               (void) write(rem, buf, strlen(buf));
+               cp = buf;
+               do {
+                       if (read(rem, cp, 1) != 1)
+                               lostconn();
+               } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
+               *--cp = '\0';
+               cp = buf;
+               if (*cp != 'N') {
+                       if (*cp == 'Y' && ISDIR(stb.st_mode))
+                               clean(dp->d_name, opts, 0);
+                       continue;
+               }
+               if (!(opts & VERIFY))
+                       remove(&stb);
+       }
+       closedir(d);
+done:
+       tp = (first) ? ootp : otp;
+       *tp = '\0';
+       (void) write(rem, "E\n", 2);
+       (void) response();
+}
+
+remove(st)
+       struct stat *st;
+{
+       DIR *d;
+       struct direct *dp;
+       register char *cp;
+       struct stat stb;
+       char *otp;
+       int len;
+
+       switch (st->st_mode & S_IFMT) {
+       case S_IFREG:
+               if (unlink(target) < 0)
+                       goto bad;
+               goto removed;
+
+       case S_IFDIR:
+               break;
+
+       default:
+               error("%s: not a plain file\n", target);
+               return;
+       }
+
+       if (access(target, 6) < 0 || (d = opendir(target)) == NULL)
+               goto bad;
+
+       otp = tp;
+       len = tp - target;
+       while (dp = readdir(d)) {
+               if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+                       continue;
+               if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+                       error("%s/%s: Name too long\n", target, dp->d_name);
+                       continue;
+               }
+               tp = otp;
+               *tp++ = '/';
+               cp = dp->d_name;;
+               while (*tp++ = *cp++)
+                       ;
+               tp--;
+               if (stat(target, &stb) < 0) {
+                       error("%s: %s\n", target, sys_errlist[errno]);
+                       continue;
+               }
+               remove(&stb);
+       }
+       closedir(d);
+       tp = otp;
+       *tp = '\0';
+       if (rmdir(target) < 0) {
+bad:
+               error("%s: %s\n", target, sys_errlist[errno]);
+               return;
+       }
+removed:
+       cp = buf;
+       *cp++ = '\0';
+       (void) sprintf(cp, "removed %s\n", target);
+       (void) write(rem, buf, strlen(cp) + 1);
+}
+
 /*VARARGS2*/
 log(fp, fmt, a1, a2, a3)
        FILE *fp;
 /*VARARGS2*/
 log(fp, fmt, a1, a2, a3)
        FILE *fp;