home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume13 / derez3 / part02 < prev    next >
Text File  |  1988-01-30  |  29KB  |  927 lines

  1. Subject:  v13i041:  Derez, remove stale files from system, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: A. Nonymous
  7. Posting-number: Volume 13, Issue 41
  8. Archive-name: derez3/part02
  9.  
  10. The author will deny being the author of this program.
  11.  
  12. : Run this shell script with "sh" not "csh"
  13. PATH=:/bin:/usr/bin:/usr/ucb
  14. export PATH
  15. all=FALSE
  16. if [ x$1 = x-a ]; then
  17.     all=TRUE
  18. fi
  19. /bin/echo 'Extracting derez.c'
  20. sed 's/^X//' <<'//go.sysin dd *' >derez.c
  21. X/* Derez, the great stale file archiver.  It stages stale files
  22. into a MORGUE directory for later removal with tar or rerez.
  23.     */
  24.  
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <sys/file.h>
  28. #include <strings.h>
  29. #include <errno.h>
  30. extern int errno;
  31.  
  32. #define MAXLEN 10240
  33. #define USAGE "derez [-t days] [dir1 dir2 dir3 ...]\n"
  34.  
  35. #include <stdio.h>
  36.  
  37. main(argc, argv)
  38. int argc;
  39. char **argv;
  40. {
  41.     FILE *fptr;
  42.     struct stat statbuf;
  43.     char filename[MAXLEN];
  44.     char cmd[MAXLEN];
  45.     char dirlist[MAXLEN];
  46.     int since;
  47.     int teflag = 0;
  48.  
  49.     dirlist[0] = NULL;
  50.     since = 180;
  51.  
  52.  
  53.     /* Check for the existence and access permissions on the MORGUE.
  54.         */
  55.     if(stat("MORGUE", &statbuf)) {
  56.         perror("derez: MORGUE");
  57.         exit(1);
  58.     }
  59.     if(!(statbuf.st_mode & S_IFDIR)) {
  60.         fprintf(stderr, "derez: MORGUE is not a directory\n");
  61.         exit(1);
  62.     }
  63.     if(access("MORGUE", R_OK | W_OK | X_OK)) {
  64.         fprintf(stderr, "derez: The MORGUE must have read, write and execute perms\n");
  65.         exit(1);
  66.     }
  67.  
  68.     if(argc > 1) {
  69.         if(strcmp(argv[1], "-t") == 0) {
  70.             if(argc < 3) {
  71.                 fprintf(stderr, USAGE);
  72.                 exit(1);
  73.             }
  74.             if(sscanf(argv[2], "%d", &since) != 1) {
  75.                 fprintf(stderr, "derez: bad arg for -t option %s\n", argv[2]);
  76.                 exit(1);
  77.             }
  78.             if(since < 0 || since > 10000) {
  79.                 fprintf(stderr, "derez: bad value for -t argument\n");
  80.                 exit(1);
  81.             }
  82.             argv += 2;
  83.             argc -= 2;
  84.         }
  85.         else if(strcmp(argv[1], "-te") == 0) {
  86.             if(argc < 3) {
  87.                 fprintf(stderr, USAGE);
  88.                 exit(1);
  89.             }
  90.             if(sscanf(argv[2], "%d", &since) != 1) {
  91.                 fprintf(stderr, "derez: bad arg for -t option %s\n", argv[2]);
  92.                 exit(1);
  93.             }
  94.             if(since < 0 || since > 10000) {
  95.                 fprintf(stderr, "derez: bad value for -te argument\n");
  96.                 exit(1);
  97.             }
  98.             teflag = 1;
  99.             argv += 2;
  100.             argc -= 2;
  101.         }
  102.         while(argc > 1) {
  103.             if((strncmp(argv[1], "/", strlen("/")) == 0) || (strncmp(argv[1], "../", strlen("../")) == 0)) {
  104.                 fprintf(stderr, "derez: Directories must be relative to .\n");
  105.                 exit(1);
  106.             }
  107.             if(lstat(argv[1], &statbuf)) {
  108.                 fprintf(stderr, "The directory %s must exist\n", argv[1]);
  109.                 exit(1);
  110.             }
  111.             if(statbuf.st_mode & S_IFDIR) {
  112.                 if(dirlist[0] != NULL)
  113.                     strcat(dirlist, " ");
  114.                 strcat(dirlist, argv[1]);
  115.                 argv += 1;
  116.                 argc -= 1;
  117.             }
  118.             else {
  119.                 fprintf(stderr, "derez: %s is not a directory\n", argv[1]);
  120.                 exit(1);
  121.             }
  122.         }
  123.     }
  124.     if(teflag) {
  125.         sprintf(cmd, "find %s -type f -atime %d -print > MORGUE/DEREZ",
  126.             (dirlist[0] == NULL ? "." : dirlist), since);
  127.     }
  128.     else {
  129.         sprintf(cmd, "find %s -type f -atime +%d -print > MORGUE/DEREZ",
  130.             (dirlist[0] == NULL ? "." : dirlist), since);
  131.     }
  132.  
  133.     printf("%s\n", cmd);
  134.     if(system(cmd) != 0) {
  135.         fprintf(stderr, "derez: The attempt to create MORGUE/DEREZ failed\n");
  136.         exit(1);
  137.     }
  138.     if((fptr = fopen("MORGUE/DEREZ", "r")) == NULL) {
  139.         fprintf(stderr, "Open of MORGUE/DEREZ for reading failed\n");
  140.         exit(1);
  141.     }
  142.     while(fgets(filename, MAXLEN, fptr) != NULL) {
  143.         char *rightslash;
  144.         /* Kill off the newline. */
  145.         if(filename[strlen(filename) - 1] != '\n') {
  146.             fprintf(stderr, "missing \\n on %s\n", filename);
  147.             continue;
  148.         }
  149.         filename[strlen(filename) - 1] = NULL;
  150.  
  151.         /* If the path name is too long we want to leave the file
  152.         alone so that the enmorgued tree can be archived using tar.
  153.             */
  154.         if(strlen(filename) > 99)
  155.             continue;
  156.  
  157.         /* If the file basename is of the form .* we want to
  158.         leave it alone to prevent removal of someones login
  159.         directory or setup files.  Of course if you take this
  160.         code out you get automatic removal of directories
  161.         associated with inactive accounts.
  162.             */
  163.         if((rightslash = rindex(filename, '/')) != NULL) {
  164.             if(rightslash[1] == '.')
  165.                 continue;
  166.         }
  167.         
  168.         if(
  169.             /* We don't want to mess with files already in the MORGUE.
  170.                 */
  171.             (strncmp(filename, "./MORGUE/", strlen("./MORGUE/")) != 0)
  172.             && (strncmp(filename, "MORGUE/", strlen("MORGUE/")) != 0)
  173.             /* The lost+found directory is a sacred system item.
  174.                 */
  175.             && (strncmp(filename, "./lost+found/", strlen("./lost+found/")) != 0)
  176.             && (strncmp(filename, "lost+found/", strlen("lost+found/")) != 0)
  177.             /* Some systems have a directory local that needs to
  178.             be left alone.
  179.                 */
  180.             && (strncmp(filename, "./local/", strlen("./local/")) != 0)
  181.             && (strncmp(filename, "local/", strlen("local/")) != 0)
  182.             /* If we were to enmorgue a file named DEREZ, we
  183.             would overwrite the list of files to move.
  184.                 */
  185.             && (strcmp(filename, "./DEREZ") != 0)
  186.             && (strcmp(filename, "DEREZ") != 0)
  187.         ){
  188.             /* We get to move the bugger.  We first create any fix up
  189.             the modes and ownership of any needed directories and then
  190.             link the file over.
  191.                 */
  192.             char target[MAXLEN];
  193.             char *source = filename;
  194.             char *dest;
  195.  
  196.             strcpy(target, "MORGUE");
  197.             dest = target;
  198.             while(*dest != NULL) dest += 1;
  199.             while(*source == '.' || *source == '/') source += 1;
  200.             while(1) {
  201.                 /* Peel off the next name in the chain.
  202.                     */
  203.                 *dest++ = '/';
  204.                 *dest = NULL;
  205.                 while(*source != '/' && *source != NULL) *dest++ = *source++;
  206.                 *dest = NULL;
  207.                 source += 1;
  208.                 if(stat(target + strlen("MORGUE/"), &statbuf)) {
  209.                     fprintf(stderr, "derez: stat on %s failed\n", target + strlen("MORGUE/"));
  210.                     perror("stat");
  211.                     exit(1);
  212.                 }
  213.                 if(statbuf.st_mode & S_IFDIR) {
  214.                     int owner = statbuf.st_uid;
  215.                     int group = statbuf.st_gid;
  216.                     int mode = statbuf.st_mode;
  217.                     if(mkdir(target, 0x777)) {
  218.                         if(errno != EEXIST) {
  219.                             fprintf(stderr, "derez: %s does not exist, but attempt to make it failed\n", target);
  220.                             perror("derez: mkdir");
  221.                             exit(1);
  222.                         }
  223.                         if(stat(target, &statbuf)) {
  224.                             perror("derez: stat");
  225.                             exit(1);
  226.                         }
  227.                         if(statbuf.st_uid != owner) {
  228.                             fprintf(stderr, "derez: Inconsistent owner for %s\n", target);
  229.                             exit(1);
  230.                         }
  231.                         if(statbuf.st_gid != group) {
  232.                             fprintf(stderr, "derez: Inconsistent group for %s\n", target);
  233.                             exit(1);
  234.                         }
  235.                         if(statbuf.st_mode != mode) {
  236.                             fprintf(stderr, "derez: Inconsistent mode for %s\n", target);
  237.                             exit(1);
  238.                         }
  239.                     }
  240.                     else {
  241.                         if(geteuid() == 0) {
  242.                             if(chown(target, owner, group)) {
  243.                                 fprintf(stderr, "derez: chown of newly created directory %s failed\n", target);
  244.                                 exit(1);
  245.                             }
  246.                         }
  247.                         else {
  248.                             sprintf(cmd, "/bin/chgrp %d %s", group, target);
  249.                             if(system(cmd)) {
  250.                                 fprintf(stderr, "%s failed\n", cmd);
  251.                                 exit(1);
  252.                             }
  253.                         }
  254.                         if(chmod(target, mode)) {
  255.                             fprintf(stderr, "derez: chmod of newly created directory %s failed\n", target);
  256.                             exit(1);
  257.                         }
  258.                     }
  259.                 }
  260.                 else {
  261.                     if(*(source - 1) != NULL) {
  262.                         fprintf(stderr, "derez: sanity check failed\n");
  263.                         exit(1);
  264.                     }
  265.                     if(!(statbuf.st_mode & S_IFREG)) {
  266.                         fprintf(stderr, "derez: %s is not a regular file\n", target + strlen("MORGUE/"));
  267.                         exit(1);
  268.                     }
  269.                     if(link(target + strlen("MORGUE/"), target)) {
  270.                         fprintf(stderr, "derez: link for %s failed\n", target);
  271.                         exit(1);
  272.                     }
  273.                     break;
  274.                 }
  275.             }
  276.             
  277.             fprintf(stderr, "enmorgue of %s succeeded\n", filename);
  278. #define RIPEM
  279. #ifdef RIPEM
  280.             unlink(filename);
  281. #else
  282.             fprintf(stderr, "Would have unlinked %s\n", filename);
  283. #endif
  284.             /* If it was the last file in the directory
  285.             we also want to remove the directory.
  286.                 */
  287.             while(1) {
  288.             while(strlen(filename) > 0 && filename[strlen(filename) - 1] != '/') {
  289.                 filename[strlen(filename) - 1] = NULL;
  290.             }
  291.             if(strlen(filename) == 0 || strcmp(filename, "./") == 0)
  292.                 break;
  293.             
  294.             filename[strlen(filename) - 1] = NULL;
  295. #ifdef RIPEM
  296.             rmdir(filename);
  297. #else
  298.             fprintf(stderr, "would have rmdir'ed %s if empty\n", filename);
  299. #endif
  300.             }
  301.         }
  302.     }
  303.     fclose(fptr);
  304. }
  305. //go.sysin dd *
  306. if [ `wc -c < derez.c` != 7617 ]; then
  307.     made=FALSE
  308.     /bin/echo 'error transmitting "derez.c" --'
  309.     /bin/echo 'length should be 7617, not' `wc -c < derez.c`
  310. else
  311.     made=TRUE
  312. fi
  313. if [ $made = TRUE ]; then
  314.     /bin/chmod 644 derez.c
  315.     /bin/echo -n '    '; /bin/ls -ld derez.c
  316. fi
  317. /bin/echo 'Extracting readbyte.c'
  318. sed 's/^X//' <<'//go.sysin dd *' >readbyte.c
  319. #include <stdio.h>
  320.  
  321. main(argc,argv)
  322. int argc;
  323. char *argv[];
  324. {
  325.     int fd;
  326.     char cbuffer[512];
  327.  
  328.     if(argc != 2) {
  329.         fprintf(stderr,"usage: readbyte file\n");
  330.         exit(1);
  331.     }
  332.     if((fd=open(argv[1],0)) < 0) {
  333.         fprintf(stderr,"cant open %s\n",argv[1]);
  334.         exit(1);
  335.     }
  336.     if(read(fd,cbuffer,1) != 1) {
  337.         fprintf(stderr,"cant read byte from file %s\n",argv[1]);
  338.         exit(1);
  339.     }
  340. }
  341. //go.sysin dd *
  342. if [ `wc -c < readbyte.c` != 363 ]; then
  343.     made=FALSE
  344.     /bin/echo 'error transmitting "readbyte.c" --'
  345.     /bin/echo 'length should be 363, not' `wc -c < readbyte.c`
  346. else
  347.     made=TRUE
  348. fi
  349. if [ $made = TRUE ]; then
  350.     /bin/chmod 644 readbyte.c
  351.     /bin/echo -n '    '; /bin/ls -ld readbyte.c
  352. fi
  353. /bin/echo 'Extracting agehist.c'
  354. sed 's/^X//' <<'//go.sysin dd *' >agehist.c
  355. X/* Agehist prints out file age histograms for the listed directories.
  356.     */
  357. #include <stdio.h>
  358. #include <sys/types.h>
  359. #include <sys/stat.h>
  360.  
  361. FILE *popen();
  362.  
  363. #define MAXLEN 1024
  364.  
  365. #define MAXDAYS 180
  366.  
  367. int data[MAXDAYS];
  368.  
  369. main(argc, argv)
  370. int argc;
  371. char **argv;
  372. {
  373.     int dir;
  374.     int i;
  375.     int ageindays;
  376.     FILE *list;
  377.     char filename[MAXLEN];
  378.     char cmd[MAXLEN];
  379.     struct stat statbuf;
  380.     time_t time();
  381.     time_t marker;
  382.  
  383.     marker = time((time_t *)0);
  384.  
  385.     for(dir = 1; dir < argc; dir += 1) {
  386.  
  387.     for(i = 0; i < MAXDAYS; i += 1) data[i] = 0;
  388.  
  389.     fprintf(stdout, "directory %s\n", argv[dir]);
  390.     sprintf(cmd, "find %s -type f -print", argv[dir]);
  391.     if((list = popen(cmd, "r")) == NULL) {
  392.         fprintf(stderr, "Failed to open pipe\n");
  393.         exit(1);
  394.     }
  395.     while(fgets(filename, MAXLEN, list) != NULL) {
  396.         if(strlen(filename) >= MAXLEN-1) {
  397.             fprintf(stderr, "path name too long\n");
  398.             exit(1);
  399.         }
  400.         filename[strlen(filename)-1] = NULL;
  401.         if(stat(filename, &statbuf)) {
  402.             perror("agehist: stat");
  403.             exit(1);
  404.         }
  405.         ageindays = (marker - statbuf.st_atime) / (24 * 60 * 60);
  406.     /*    fprintf(stdout, "%d %s\n", ageindays, filename);*/
  407.         if(ageindays > MAXDAYS-1) ageindays = MAXDAYS-1;
  408.         if(ageindays < 0) ageindays = 0;
  409.         data[ageindays] += 1;
  410.     }
  411.     for(i = 0; i < MAXDAYS; i += 1) {
  412.         if(i % 10 == 0) fprintf(stdout, "%4d |", i);
  413.         fprintf(stdout, "%4d", data[i]);
  414.         if(i % 10 == 9) fprintf(stdout, "\n");
  415.     }
  416.     fprintf(stdout, "\n");
  417.     pclose(list);
  418.     }
  419. }
  420. //go.sysin dd *
  421. if [ `wc -c < agehist.c` != 1411 ]; then
  422.     made=FALSE
  423.     /bin/echo 'error transmitting "agehist.c" --'
  424.     /bin/echo 'length should be 1411, not' `wc -c < agehist.c`
  425. else
  426.     made=TRUE
  427. fi
  428. if [ $made = TRUE ]; then
  429.     /bin/chmod 644 agehist.c
  430.     /bin/echo -n '    '; /bin/ls -ld agehist.c
  431. fi
  432. /bin/echo 'Extracting derez.1'
  433. sed 's/^X//' <<'//go.sysin dd *' >derez.1
  434. X.TH DEREZ LOCAL "2 February 1987"
  435. X.UC 4
  436. X.SH NAME
  437. derez \- find stale files, and move them into a MORGUE directory
  438. X.SH SYNOPSIS
  439. X.br
  440. \fBderez [-t[e] days] [dir1 dir2 dir3 ...]\fP
  441. X.SH DESCRIPTION
  442. X.I Derez
  443. is a program which is used to enmorgue stale files.
  444. Most if not \fIall\fP UNIX systems suffer from the finite disk size problem.
  445. If this problem is aggravated by users which have stale files that have not
  446. been read for some time,
  447. derez offers a solution.
  448. It moves the stale files to a \fIMORGUE\fP directory so that they can
  449. later be archived using \fItar\fP.
  450. Derez finds the stale files and moves them to the \fIMORGUE\fP directory,
  451. creating directories as needed.
  452. The files are moved using \fIlink()\fP,
  453. so the process is fast and preserves modification times of the files.
  454. As target directories are created,
  455. their ownership and modes are adjusted to be identical to those of the
  456. source directories.
  457. X.sp
  458. \fIDerez\fP uses the access times,
  459. time last \fIread\fP not time last \fIwritten\fP,
  460. of the files to determine their staleness.
  461. The default number of days since last access is 180 days,
  462. but this can be changed using the \fB-t\fP option.
  463. Normally,
  464. derez considers the files not accessed in the specified number of days or more
  465. to be stale.
  466. If the optional \fBe\fP appears,
  467. derez attacks only those files whose access dates are exactly the specified
  468. number of days in the past.
  469. If no directory list is given to derez it searches current directory,
  470. except the subdirectory \fIMORGUE\fP.
  471. The \fB-t\fP option and a directory list can be used to give special handling to
  472. antisocial users.
  473. See the man page for \fIagehist\fP for useful tool in this regard.
  474. Using agehist and the -te option,
  475. unreasonable peaks in the age spectrum of the files can be specifically attacked.
  476. This is done ruthlessly for any user which destroys the access date information
  477. in his files,
  478. whether intentionally or accidentally.
  479. Your files will be removed first,
  480. and then questions will be asked later.
  481. X.sp
  482. One can attempt to defeat derez by using \fIfind\fP and \fIreadbyte\fP to find and read all
  483. of the files in a directory tree.
  484. Using \fIfind\fP and \fIreadbyte\fP to update the access dates of files
  485. is reasonable for some \fIsmall\fP directory that you haven't
  486. looked at in some time, but will be using in a \fIfew days\fP.
  487. Doing this to a large fraction of your files will cause those files to
  488. be archived onto tape and removed from disk.
  489. Updating the staleness date of a directory tree using find and readbyte is not
  490. guaranteed to save the files from derez in any event.
  491. The derez daemon actively uses \fIagehist\fP to find such cases and tends to
  492. have a rather small staleness limit for these files.
  493. The more abnormal the age distribution of a user's files,
  494. the shorter the cutoff date gets.
  495. The system simply does not have enough disk capacity for
  496. archival store and user's are expected to use tape for such purposes.
  497. X.sp
  498. The best way to avoid getting derez'ed is to actively archive your stale files
  499. onto tape using \fItar\fP or \fIrerez\fP and keep them off line.
  500. \fIRerez\fP has the advantage that it remembers access dates,
  501. \fItar\fP does not and assumes the worst possibility.
  502. The current limits used by the derez daemon are 90 days,
  503. with reasonable peaks in the age spectrum being tolerated for 30 days
  504. and antisocial behavior being dealt with instantly and ruthlessly.
  505. The above limits are subject to change,
  506. on a per user basis,
  507. without notice.
  508. We will try to be reasonable.
  509. If you,
  510. however,
  511. are unreasonable and attempt to mung the access date information in your files
  512. we can be more unreasonable than you might imagine.
  513. X.sp
  514. Users should do a clean up of their stale files on a monthly basis
  515. and should actively move files associated with their various projects off line
  516. when these projects become inactive for more than a month or so.
  517. Derez itself is the recommended tool for this work as it does not
  518. modify the access dates of files you want to keep on the disk.
  519. If you don't keep your stale files off line,
  520. the derez daemon will do it for you automatically.
  521. Two copies of each derez tape archive are made and carefully
  522. checked for quality.
  523. This data is probably safer than the data left on the disk.
  524. The second tape archive is kept in a repository.
  525. If some of your files get archived,
  526. and you really need to use them in the next week or so,
  527. simply spool the \fIneeded\fP files back onto disk using \fIrerez\fP,
  528. or \fItar\fP(for the older derez archives).
  529. You should be very careful in doing this it might overwrite any existing files
  530. on the disk.
  531. \fITar\fP sets the access dates to the creation time of the file,
  532. \fIrerez\fP preserves access dates properly on it's archives.
  533. Don't be surprised if the files you spool back onto the disk,
  534. and do not actually use before the next run of \fIderez\fP,
  535. go right back out on tape.
  536. Did they need to be on disk if you didn't use them?
  537. X.sp
  538. The derez daemon is quite young and,
  539. like any newborn,
  540. wakes up whenever it gets hungry.
  541. The derez daemon is implemented using the latest 6'th generation AI technology
  542. and will learn appropriate algorithms to keep the required amount of disk
  543. space free.
  544. Abusive users will be handled on a case by case basis,
  545. with suitable ruthless application of rules which are changed by the
  546. daemon at will.
  547. Abuse of the disk space will not be tolerated.
  548. Large usage is acceptable,
  549. provided that no efforts are made that defeat the operation of derez.
  550. We have enough disk space for everyone to get their work done,
  551. but not a single byte for users to use as archival store.
  552. X.sp
  553. Although derez was written for the derez daemon's use,
  554. an individual user can use it to find and archive his stale files.
  555. This is done by making a subdirectory with the name \fIMORGUE\fP in any directory
  556. you would like to archive the descendant stale files.
  557. You then run \fIderez\fP.
  558. Derez will create a list of stale files,
  559. with the name \fIMORGUE/DEREZ\fP and then move the stale files into the directory
  560. MORGUE.
  561. If a file that is removed is the last file in it's parent directory,
  562. the parent directory is removed.
  563. The contents of the morgue directory can be archived using tar and then removed from the disk.
  564. The use of \fIderez\fP for stale file control is the only foolproof
  565. way to stay ahead of the derez daemon as it leaves the age distribution of
  566. the remaining files on disk unmodified.
  567. Scratch tapes can be found next to the system console.
  568. X.sp
  569. Files that have been derez'ed by the derez daemon can be recovered from the archive tape using
  570. \fIrerez\fP or \fItar\fP as noted on the tape.
  571. You should recover only those files that you are going to use.
  572. Files which you recover and don't use will be archived again at the next
  573. time the derez daemon wakes up.
  574. X.SH SEE ALSO
  575. find, readbyte, agehist, rerez, tar
  576. X.ta 3.0i
  577. X.SH FILES
  578. X/usr/local/morgue/u#.mm.dd.yy    Lists of files derez'ed by the derez daemon.
  579. X.br
  580. MORGUE/DEREZ    The files derez will enmorgue.
  581. X.br
  582. MORGUE/*    The enmorgued files.
  583. X.SH "ARCHIVE TAPES"
  584. The archive tapes with dates matching the above file names are located
  585. next to the dump tapes in the machine room.
  586. These tapes should never be write enabled or removed from the machine room.
  587. A second copy of every archive tape is kept in a repository so any archived
  588. files are secure.
  589. X.SH "Attempts to defeat Derez"
  590. Will NOT be tolerated.
  591. You might save a small handful of files using \fIreadbyte\fP
  592. but that is about it.
  593. It is not recommended to attempt to save a large number of files from
  594. \fIderez\fP.
  595. The \fIderez\fP daemon will detect such attempts and archive the affected
  596. files.
  597. Attempting to save a large number of files using \fIfind\fP and \fIreadbyte\fP
  598. only produces a nice highly visible target for the the derez daemon.
  599. If you want to beat the derez daemon effectively, use derez yourself to clean
  600. your stale files off of the disk.
  601. This should be done monthly with a cutoff date less that that used by
  602. the derez daemon.
  603. X.SH BUGS
  604. DEREZ shares tar's limits on path name lengths.
  605. X.br
  606. MORGUE and DEREZ are reserved names.
  607. X.br
  608. In an ideal world \fIderez\fP would eventually archive itself onto tape.
  609. We don't live in an ideal world.
  610. X.br
  611. Using the recursive (-r) option of cp can get you in serious
  612. trouble as it will caused peaks in the age distribution of your files.
  613. These peaks will be excised at each run of derez.
  614. Use \fItar\fP or \fIrerez\fP to duplicate directory trees.
  615. //go.sysin dd *
  616. if [ `wc -c < derez.1` != 8340 ]; then
  617.     made=FALSE
  618.     /bin/echo 'error transmitting "derez.1" --'
  619.     /bin/echo 'length should be 8340, not' `wc -c < derez.1`
  620. else
  621.     made=TRUE
  622. fi
  623. if [ $made = TRUE ]; then
  624.     /bin/chmod 644 derez.1
  625.     /bin/echo -n '    '; /bin/ls -ld derez.1
  626. fi
  627. /bin/echo 'Extracting readbyte.1'
  628. sed 's/^X//' <<'//go.sysin dd *' >readbyte.1
  629. X.TH READBYTE LOCAL "2 February 1987"
  630. X.UC 4
  631. X.SH NAME
  632. readbyte \- Read the first byte of a file, removing its staleness
  633. X.SH SYNOPSIS
  634. X.br
  635. \fBreadbyte filename\fP
  636. X.SH DESCRIPTION
  637. X.I Readbyte
  638. reads the first byte of the specified file,
  639. changing its access date.
  640. It is used to remove staleness of a file to prevent derez from
  641. putting the file in the morgue for archival onto tape.
  642. Excessive use of \fIreadbyte\fP, or any other means of updating
  643. the access date of a file to defeat \fIderez\fP,
  644. is interpreted as antisocial by root.
  645. Antisocial behavior is dealt with as described in the man page for \fIderez\fP.
  646. X.SH SEE ALSO
  647. find, derez, agehist
  648. //go.sysin dd *
  649. if [ `wc -c < readbyte.1` != 640 ]; then
  650.     made=FALSE
  651.     /bin/echo 'error transmitting "readbyte.1" --'
  652.     /bin/echo 'length should be 640, not' `wc -c < readbyte.1`
  653. else
  654.     made=TRUE
  655. fi
  656. if [ $made = TRUE ]; then
  657.     /bin/chmod 444 readbyte.1
  658.     /bin/echo -n '    '; /bin/ls -ld readbyte.1
  659. fi
  660. /bin/echo 'Extracting agehist.1'
  661. sed 's/^X//' <<'//go.sysin dd *' >agehist.1
  662. X.TH AGEHIST LOCAL "3 April 1987"
  663. X.UC 4
  664. X.SH NAME
  665. agehist \- Display a histogram of file ages
  666. X.SH SYNOPSIS
  667. X.br
  668. \fBagehist dir [dir2 dir3 ...]\fP
  669. X.SH DESCRIPTION
  670. X.I Agehist
  671. prints a histogram of the age distribution, in days,
  672. of the files in the specified directory trees.
  673. Agehist is the latest in high technology tooling to detect users
  674. that insist on mass use of \fIreadbyte\fP to defeat \fIderez\fP.
  675. The derez daemon,
  676. which is based on the latest 6'th generation AI technology,
  677. enmorgues files which form unreasonable peaks in the age distribution
  678. even though the access date is less than the usual cutoff.
  679. X.SH SEE ALSO
  680. find, derez, readbyte
  681. //go.sysin dd *
  682. if [ `wc -c < agehist.1` != 642 ]; then
  683.     made=FALSE
  684.     /bin/echo 'error transmitting "agehist.1" --'
  685.     /bin/echo 'length should be 642, not' `wc -c < agehist.1`
  686. else
  687.     made=TRUE
  688. fi
  689. if [ $made = TRUE ]; then
  690.     /bin/chmod 444 agehist.1
  691.     /bin/echo -n '    '; /bin/ls -ld agehist.1
  692. fi
  693. /bin/echo 'Extracting rerez.1'
  694. sed 's/^X//' <<'//go.sysin dd *' >rerez.1
  695. X.TH REREZ 1 "10 March 1987"
  696. X.SH NAME
  697. rerez \- tape archiver, that remembers access dates
  698. X.SH SYNOPSIS
  699. X.B rerez
  700. [ key ] [ name ... ]
  701. X.SH DESCRIPTION
  702. X.PP
  703. X.I Rerez
  704. saves and restores multiple files on a single file (usually a magnetic
  705. tape, but it can be any file).  
  706. Rerez is a munged version of \fItar\fP that remembers access dates.
  707. X.IR Rerez 's
  708. actions are controlled by the
  709. X.I key
  710. argument.  The
  711. X.I key
  712. is a string of characters containing at most one function letter and possibly
  713. one or more function modifiers.  Other arguments to 
  714. X.I rerez
  715. are file or directory names specifying which files to dump or restore.
  716. In all cases, appearance of a directory name refers to
  717. the files and (recursively) subdirectories of that directory.
  718. X.PP
  719. The function portion of the key is specified by one of the following letters:
  720. X.TP 8
  721. X.B r
  722. The named files are written on the end of the tape.  The
  723. X.B c
  724. function implies this.
  725. X.TP 8
  726. X.B x
  727. The named files are extracted from the tape.  If the named file
  728. matches a directory whose contents had been written onto the tape, this
  729. directory is (recursively) extracted.  The owner, modification time, and mode
  730. are restored (if possible).  If no file argument is given, the entire content
  731. of the tape is extracted.  Note that if multiple entries specifying the same
  732. file are on the tape, the last one overwrites all earlier.
  733. X.TP 8
  734. X.B t
  735. The names of the specified files are listed each time they occur on
  736. the tape.  If no file argument is given, all of the names on the tape
  737. are listed.
  738. X.TP 8
  739. X.B u
  740. The named files are added to the tape if either they are not
  741. already there or have been modified since last put on the tape.
  742. X.TP 8
  743. X.B c
  744. Create a new tape; writing begins on the beginning of the tape
  745. instead of after the last file.  This command implies
  746. X.BR r .
  747. X.TP 8
  748. X.B o
  749. On output, rerez normally places information specifying owner and modes
  750. of directories in the archive.  Former versions of rerez, when encountering
  751. this information will give error message of the form
  752. X.br
  753.     "<name>/: cannot create".
  754. X.br
  755. This option will suppress the directory information.
  756. X.TP 8
  757. X.B p
  758. This option says to restore files to their original modes,
  759. ignoring the present
  760. X.IR umask (2).
  761. Setuid and sticky information
  762. will also be restored to the super-user.
  763. X.PP
  764. The following characters may be used in addition to the letter
  765. which selects the function desired.
  766. X.TP 10
  767. X.B 0, ..., 9
  768. This modifier selects an alternate drive on which the tape is mounted.
  769. The default is drive 0 at 1600 bpi, which is normally /dev/rmt8.
  770. X.TP 10
  771. X.B v
  772. Normally
  773. X.I rerez
  774. does its work silently.  The
  775. X.B v
  776. (verbose) option makes
  777. X.I rerez
  778. type the name of each file it treats preceded by the function
  779. letter.  With the
  780. X.B t
  781. function, the verbose option
  782. gives more information about the tape entries than just their names.
  783. X.TP 10
  784. X.B w
  785. X.I Rerez
  786. prints the action to be taken followed by file name, then
  787. wait for user confirmation. If a word beginning with `y'
  788. is given, the action is done. Any other input means don't do it.
  789. X.TP 10
  790. X.B f
  791. X.I Rerez
  792. uses the next argument as the name of the archive instead of
  793. X/dev/rmt?.
  794. X.sp
  795. If the file name has the form
  796. X.IR system [. user ]:/dev/???
  797. X.I rerez
  798. will use the tape drive /dev/??? on the remote system
  799. X.IR system ,
  800. via
  801. X.IR rsh (1),
  802. and
  803. X.IR rmt (8).
  804. The optional
  805. X.I user
  806. portion of the pathname specifies the login name to use on the
  807. remote system.
  808. If it is not supplied, the current user's login name will be used.
  809. In all the cases, the user must have the appropriate
  810. permissions on the remote machine, in order to use this facility.
  811. X.sp
  812. If the name of the file is `\-', rerez writes to standard output or
  813. reads from standard input, whichever is appropriate. Thus,
  814. X.I rerez
  815. can be used as the head or tail of a filter chain.
  816. X.I Rerez
  817. can also be used to move hierarchies with the command
  818. X.ce 1
  819. cd fromdir; rerez cf - . | (cd todir; rerez xf -)
  820. X.TP 10
  821. X.B b
  822. X.I Rerez
  823. uses the next argument as the blocking factor for tape records. The
  824. default is 20 (the maximum). This option should only be used with raw magnetic
  825. tape archives (See 
  826. X.B f
  827. above).  The block size is determined automatically
  828. when reading tapes (key letters `x' and `t').
  829. X.TP 10
  830. X.B l
  831. tells 
  832. X.I rerez
  833. to complain if it cannot resolve all of the links to the
  834. files dumped. If this is not specified, no error messages are printed.
  835. X.TP 10
  836. X.B m
  837. tells 
  838. X.I rerez
  839. to print the message ``\fBYou must be joking!\fP'' and exit.
  840. X.TP 10
  841. X.B h
  842. Force 
  843. X.I rerez
  844. to follow symbolic links as if they were normal files or
  845. directories.  Normally, 
  846. X.I rerez
  847. does not follow symbolic links.
  848. X.TP 10
  849. X.B B
  850. Forces input and output blocking to 20 blocks per record.  This option
  851. was added so that 
  852. X.I rerez
  853. can work across a communications channel where the blocking may not
  854. be maintained.
  855. X.PP
  856. If a file name is preceded by 
  857. X.BR \-C ,
  858. then 
  859. X.I rerez
  860. will perform a
  861. X.IR chdir (2)
  862. to that file name.  This allows multiple directories not
  863. related by a close common parent to be archived using short
  864. relative path names.  For example, to archive files from /usr/include
  865. and from /etc, one might use
  866. X.ti +0.5i
  867. rerez c -C /usr include -C / etc
  868. X.PP
  869. Previous restrictions dealing with
  870. X.IR rerez 's
  871. inability to properly handle blocked archives have been lifted.
  872. X.PP
  873. X.SH FILES
  874. X/dev/rmt?
  875. X.br
  876. X/tmp/tar*
  877. X.SH DIAGNOSTICS
  878. Complaints about bad key characters and tape read/write errors.
  879. X.br
  880. Complaints if enough memory is not available to hold the link tables.
  881. X.SH BUGS
  882. There is no way to ask for the
  883. X.IR n -th
  884. occurrence of a file.
  885. X.br
  886. Tape errors are handled ungracefully.
  887. X.br
  888. The 
  889. X.B u
  890. option can be slow.
  891. X.br
  892. The current limit on file name length is 100 characters.
  893. X.br
  894. There is no way to selectively follow symbolic links.
  895. X.br
  896. Using a remote system's tape drive can be slow.
  897. X.SH NOTE
  898. \fIRerez\fP was created in order to have a means of archiving files
  899. on tape in a way that restored their access dates upon extraction.
  900. When \fIrerez\fP is used to extract these files the creation and
  901. access dates are restored to their original values.
  902. If the user does not actually use the files by the next run of \fIderez\fP
  903. the files did not need to be on disk and will be archived again.
  904. \fITar\fP was used for these archives in the past,
  905. but the loss of access dates caused peaks in the age spectrum and
  906. resulted in a rather aggressive derez daemon.
  907. Rerez has been modified to set access dates to be the same as the
  908. creation dates of a files to avoid future problems.
  909. As the creation date of a file may be substantially older than
  910. the date of last access,
  911. users of tar are at somewhat of a disadvantage.
  912. A \fIrerez\fP archive is unfortunately not compatible with tar,
  913. and therefore not portable to other machines.
  914. //go.sysin dd *
  915. if [ `wc -c < rerez.1` != 6645 ]; then
  916.     made=FALSE
  917.     /bin/echo 'error transmitting "rerez.1" --'
  918.     /bin/echo 'length should be 6645, not' `wc -c < rerez.1`
  919. else
  920.     made=TRUE
  921. fi
  922. if [ $made = TRUE ]; then
  923.     /bin/chmod 644 rerez.1
  924.     /bin/echo -n '    '; /bin/ls -ld rerez.1
  925. fi
  926.  
  927.