v06i025: "rm" and "unrm" programs (unrm.rm)
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Fri Jun 27 06:29:00 AEST 1986
Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor>
Mod.sources: Volume 6, Issue 25
Archive-name: unrm.rm
[ I wrote a brief manpage and a Makefile; I hope Dave forgives
the (humorous) editorial comment in the latter. Some sites
will want to change the "LOGNAME" strings to "USER" or similar,
in the code below. --r$]
The following `shar' file contains two programs that, when installed, will
allow you to use "rm" as usual but also have the ability to change your
mind and use "unrm".
Another useful program from....
-- Dave Taylor
taylor/HP1900/UX, taylor at HPLABS.{CSNET, ARPA} or ..hplabs!taylor
--------------------CUT HERE--------------------
#!/bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# Contents: rm.c unrm.1 unrm.c Makefile
echo x - rm.c
sed 's/^XX//' > "rm.c" <<'@//E*O*F rm.c//'
XX/** rm.c **/
XX/** This program replaces 'rm' (it's assumed that this program is BEFORE
XX /bin/rm in the path) and will ferret away copies of the files being
XX removed to the directory /tmp/rm/<login>. Files that are copied into
XX /tmp/rm/* can be recalled by 'unrm filename'. Every so often (probably
XX midnight every night) a daemon should clear out the old files in the
XX /tmp/rm directory...
XX (C) Copyright 1986, Dave Taylor, Hewlett-Packard Company
XX**/
XX#include <stdio.h>
XX#include <errno.h>
XX#define real_rm "/bin/rm"
XX#define RM_DIR "/tmp/rm"
XX#define ACCESS_MODE 04 & 02
XX#define DIR_ACCESS 04 & 01
XX#define SLEN 80
XX#define USERS_NAME "LOGNAME" /* "USER" in BSD */
XXextern int errno;
XXchar *basename(), *getlogin(), *getenv();
XXmain(argc, argv)
XXint argc;
XXchar **argv;
XX{
XX extern int optind; /* for getopt */
XX char buffer[SLEN], login_name[SLEN], dirname[SLEN], *cp;
XX int c, oldumask;
XX while ((c = getopt(argc, argv, "rfi")) != EOF) {
XX switch (c) {
XX case 'r' :
XX case 'f' :
XX case 'i' : break; /* just accept 'em... */
XX case '?' : exit(fprintf(stderr,"Usage: rm [-rfi] files\n"));
XX }
XX }
XX if (strlen(argv[optind]) == 0)
XX exit(0);
XX /* is the top level /tmp directory available??? */
XX if (access(RM_DIR, DIR_ACCESS)) {
XX sprintf(buffer,"mkdir %s; chmod 777 %s", RM_DIR, RM_DIR);
XX if (system(buffer) != 0) {
XX printf("'%s' failed!!\n", buffer);
XX exit(1);
XX }
XX }
XX /* now get the users login name... */
XX if ((cp = getenv(USERS_NAME)) == NULL)
XX strcpy(login_name, getlogin());
XX else
XX strcpy(login_name, cp);
XX /* let's see if THAT directory is hangin' around... */
XX sprintf(dirname, "%s/%s", RM_DIR, login_name);
XX if (access(dirname, DIR_ACCESS)) {
XX sprintf(buffer,"mkdir %s; chmod 700 %s", dirname, dirname);
XX if (system(buffer) != 0) {
XX printf("'%s' failed!!\n", buffer);
XX exit(1);
XX }
XX }
XX oldumask = umask(077);
XX while (strlen(argv[optind]) > 0) {
XX if (access(basename(argv[optind]), ACCESS_MODE) == 0)
XX save_copy_of(dirname, argv[optind]);
XX optind++;
XX }
XX (void) umask(oldumask);
XX execv(real_rm, argv);
XX
XX fprintf(stderr,"rm: error %d exec'ing!\n", errno);
XX}
XXchar *basename(string)
XXchar *string;
XX{
XX /** returns the basename of the file specified in string **/
XX static char *buff;
XX buff = string + strlen(string); /* start at last char */
XX
XX while (*buff != '/' && buff > string) buff--;
XX return( (char *) (*buff == '/'? ++buff : buff));
XX}
XXsave_copy_of(dirname, filename)
XXchar *dirname, *filename;
XX{
XX /** Try to link filename to dirname, if that fails, copy it
XX bit by bit... **/
XX char newfname[80];
XX sprintf(newfname,"%s/%s", dirname, basename(filename));
XX (void) unlink(newfname); /* blow it away if already there! */
XX if (link(filename, newfname) != 0) {
XX FILE *infile, *outfile;
XX int c;
XX
XX if ((infile = fopen(filename, "r")) == NULL)
XX exit(fprintf(stderr, "rm: can't read file '%s' to save a copy!\n",
XX filename));
XX if ((outfile = fopen(newfname, "w")) == NULL)
XX exit(fprintf(stderr, "rm: can't write to file '%s'!\n",
XX newfname));
XX while ((c = getc(infile)) != EOF)
XX putc(c, outfile);
XX
XX fclose(infile);
XX fclose(outfile);
XX }
XX}
@//E*O*F rm.c//
chmod u=rw,g=r,o=r rm.c
echo x - unrm.1
sed 's/^XX//' > "unrm.1" <<'@//E*O*F unrm.1//'
XX.TH UNRM 1 LOCAL
XX.SH NAME
XXunrm, rm \- remove files and bring them back
XX.SH SYNOPSIS
XX.B unrm
XX[
XX.B \-f
XX] file ...
XX.br
XX.B rm
XXfile ...
XX.SH DESCRIPTION
XX.I Rm
XXis a local replacement for the standard
XX.IR rm (1)
XXcommand. Prior to removing a file it ferrets away a copy of it in
XXthe directory
XX.RI /tmp/rm/ login_id ,
XXcreating each component along the way as necessary.
XXThe standard ``\-r,'' ``\-f,'' and ``\-i'' options may be specified,
XXbut they are ignored.
XX.PP
XXFiles that have been deleted with this version of
XX.I rm
XXcan than be retrieved with the
XX.I unrm
XXcommand.
XX.I Unrm
XXchecks to see that you are indeed the owner of a file before you
XXcan copy it. It will not overwrite a file of the same name in the
XXcurrent directory, unless the ``\-f'' flag is specified, which
XXcauses the file to be replaced regardless.
XX.PP
XXIf these programs are available, the system administror will probably want
XXto add a line like the following to /usr/lib/crontab:
XX.RS
XX40 4 * * * find /tmp -mtime +2 -exec rm -f {} ;
XX.RE
XXThis removes all files from temp that haven't been touched within
XXtwo days.
XX.SH BUGS
XXStrange things can happen if you try to specify something other than
XXa regular file.
@//E*O*F unrm.1//
chmod u=rw,g=rw,o=rw unrm.1
echo x - unrm.c
sed 's/^XX//' > "unrm.c" <<'@//E*O*F unrm.c//'
XX/** unrm.c **/
XX/** This is the companion program to the rm.c program, and will extract
XX files from the RM_DIR/login directory if they exist. It checks to see
XX that you are indeed the owner of the file before it'll let you copy
XX it AND it ensures that the file doesn't already exist in the current
XX directory (makes sense, eh?).
XX This will not allow unrm'ing files that aren't owned by you, nor
XX will it allow restores that replace a file of the same name in the
XX current directory (unless '-f' is specified, which will cause the
XX file to be replaced regardless).
XX (C) Copyright 1986, Dave Taylor, Hewlett-Packard
XX**/
XX#include <stdio.h>
XX#include <errno.h>
XX#include <sys/types.h>
XX#include <sys/stat.h>
XX#define RM_DIR "/tmp/rm"
XX/** access modes for calls to 'access()' **/
XX#define DIRACCESS 02 & 04
XX#define TOCOPY 04
XX#define TOREPLACE 02 & 04
XX#define SLEN 80
XXint force_overwrite = 0; /* replace current regardless! */
XXchar *getenv(), *getlogin();
XXmain(argc, argv)
XXint argc;
XXchar **argv;
XX{
XX extern int optind; /* for getopt */
XX char buffer[SLEN], login_name[SLEN], dirname[SLEN], *cp;
XX int c;
XX while ((c = getopt(argc, argv, "f")) != EOF) {
XX switch (c) {
XX case 'f' : force_overwrite++; break;
XX case '?' : exit(fprintf(stderr,"Usage: unrm [-f] files\n"));
XX }
XX }
XX if (argv[optind] == 0 || strlen(argv[optind]) == 0)
XX exit(0);
XX if (access(RM_DIR, DIRACCESS)) {
XX fprintf(stderr,"Error: Directory %s doesn't exist!\n", RM_DIR);
XX exit(0);
XX }
XX if ((cp = getenv("LOGNAME")) == NULL)
XX strcpy(login_name, getlogin());
XX else
XX strcpy(login_name, cp);
XX sprintf(dirname, "%s/%s", RM_DIR, login_name);
XX if (access(dirname, DIRACCESS)) {
XX fprintf(stderr,"Error: Directory %s doesn't exist!\n", dirname);
XX exit(0);
XX }
XX while (argv[optind] && strlen(argv[optind]) > 0) {
XX restore(dirname, argv[optind]);
XX optind++;
XX }
XX exit(0);
XX}
XXrestore(directory, filename)
XXchar *directory, *filename;
XX{
XX /** Try to link RM_DIR/filename to current directory. If that
XX fails, try to copy it byte by byte... **/
XX struct stat buffer;
XX char newfname[80], answer[80];
XX sprintf(newfname,"%s/%s", directory, filename);
XX if (access(newfname,TOCOPY) != 0)
XX return(fprintf(stderr,"Error: Can't find old copy of '%s'!\n",
XX filename));
XX
XX if (stat(newfname, &buffer) != 0)
XX return(fprintf(stderr,"Error: Can't stat old copy of '%s'!\n",
XX filename));
XX if (buffer.st_uid != getuid())
XX return(fprintf(stderr,"Error: File '%s' isn't yours to restore!\n",
XX filename));
XX /** now we're ready to start some REAL work... **/
XX if (access(filename,TOREPLACE) == 0) { /* it exists! */
XX if (! force_overwrite)
XX printf(
XX "File %s already exists in this directory! Replace it? (y/n) ",
XX filename);
XX gets(answer, 1);
XX if (tolower(answer[0]) != 'y') {
XX fprintf(stderr,"Restore of file %s cancelled\n", filename);
XX return;
XX }
XX }
XX (void) unlink(filename); /* blow it away, if it's here! */
XX if (link(newfname, filename) != 0) {
XX FILE *infile, *outfile;
XX int c;
XX
XX if ((infile = fopen(newfname, "r")) == NULL)
XX exit(fprintf(stderr,
XX "Error: Can't read file '%s' to restore from!\n",
XX newfname));
XX if ((outfile = fopen(filename, "w")) == NULL)
XX exit(fprintf(stderr, "Error: Can't write to file '%s'!\n",
XX filename));
XX while ((c = getc(infile)) != EOF)
XX putc(c, outfile);
XX
XX fclose(infile);
XX fclose(outfile);
XX }
XX unlink(newfname);
XX fprintf(stderr,"Restored file '%s'\n", filename);
XX}
@//E*O*F unrm.c//
chmod u=rw,g=r,o=r unrm.c
echo x - Makefile
sed 's/^XX//' > "Makefile" <<'@//E*O*F Makefile//'
XXall: unrm rm
XXunrm: unrm.c ; cc $(CFLAGS) -o $@ $?
XXrm: rm.c ; cc $(CFLAGS) -o $@ $?
XXinstall:
XX @echo surely you jest
@//E*O*F Makefile//
chmod u=rw,g=rw,o=rw Makefile
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
136 428 3194 rm.c
43 221 1170 unrm.1
142 454 3554 unrm.c
7 24 117 Makefile
328 1127 8035 total
!!!
wc rm.c unrm.1 unrm.c Makefile | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0
More information about the Mod.sources
mailing list