I bring more love to everybody's favorite rm option. So I'm wiping a file from a fairly slow USB stick and it's taking forever. I don't really give a shit about some guy with a quantum tachyon microscope taking it apart, I just want the files to be gone enough that a simple undelete tool won't bring them back. The three wipes is the charm approach of rm -P is a little heavy handed.
What I propose is making -P wipe the file once each time it's provided. I get the simple whack the data for good option I want, the paranoid weirdos get the rm `jot -b -P 4096` scrubber they want. Index: rm.1 =================================================================== RCS file: /cvs/src/bin/rm/rm.1,v retrieving revision 1.34 diff -u -p -r1.34 rm.1 --- rm.1 4 Oct 2010 07:17:30 -0000 1.34 +++ rm.1 24 Jul 2012 03:30:50 -0000 @@ -77,13 +77,13 @@ option overrides any previous options. .It Fl P Overwrite regular files before deleting them. -Files are overwritten three times, first with the byte pattern +Files are overwritten once for each time the option is given, first with the +byte pattern .Li 0xff , then .Li 0x00 , -and then -.Li 0xff -again, before they are deleted. +and then alternating between the two patterns as required, +before they are deleted. Files with multiple links will be unlinked but not overwritten. .It Fl R Attempt to remove the file hierarchy rooted in each file argument. Index: rm.c =================================================================== RCS file: /cvs/src/bin/rm/rm.c,v retrieving revision 1.25 diff -u -p -r1.25 rm.c --- rm.c 18 Jun 2012 01:03:05 -0000 1.25 +++ rm.c 24 Jul 2012 03:27:54 -0000 @@ -49,7 +49,7 @@ extern char *__progname; -int dflag, eval, fflag, iflag, Pflag, stdin_ok; +int dflag, eval, fflag, iflag, Pcount, stdin_ok; int check(char *, char *, struct stat *); void checkdot(char **); @@ -73,7 +73,7 @@ main(int argc, char *argv[]) setlocale(LC_ALL, ""); - Pflag = rflag = 0; + Pcount = rflag = 0; while ((ch = getopt(argc, argv, "dfiPRr")) != -1) switch(ch) { case 'd': @@ -88,7 +88,7 @@ main(int argc, char *argv[]) iflag = 1; break; case 'P': - Pflag = 1; + Pcount++; break; case 'R': case 'r': /* Compatibility. */ @@ -200,7 +200,7 @@ rm_tree(char **argv) case FTS_F: case FTS_NSOK: - if (Pflag) + if (Pcount) rm_overwrite(p->fts_accpath, p->fts_info == FTS_NSOK ? NULL : p->fts_statp); /* FALLTHROUGH */ @@ -248,7 +248,7 @@ rm_file(char **argv) else if (S_ISDIR(sb.st_mode)) rval = rmdir(f); else { - if (Pflag) + if (Pcount) rm_overwrite(f, &sb); rval = unlink(f); } @@ -261,7 +261,7 @@ rm_file(char **argv) /* * rm_overwrite -- - * Overwrite the file 3 times with varying bit patterns. + * Overwrite the file Pcount times with varying bit patterns. * * XXX * This is a cheap way to *really* delete files. Note that only regular @@ -277,7 +277,7 @@ rm_overwrite(char *file, struct stat *sb struct stat sb, sb2; struct statfs fsb; size_t bsize; - int fd; + int fd, i; char *buf = NULL; fd = -1; @@ -308,14 +308,11 @@ rm_overwrite(char *file, struct stat *sb if ((buf = malloc(bsize)) == NULL) err(1, "%s: malloc", file); - if (!pass(0xff, fd, sbp->st_size, buf, bsize) || fsync(fd) || - lseek(fd, (off_t)0, SEEK_SET)) - goto err; - if (!pass(0x00, fd, sbp->st_size, buf, bsize) || fsync(fd) || - lseek(fd, (off_t)0, SEEK_SET)) - goto err; - if (!pass(0xff, fd, sbp->st_size, buf, bsize) || fsync(fd)) - goto err; + for (i = 0; i < Pcount; i++) { + if (!pass(i & 0x1 ? 0xff : 0x00, fd, sbp->st_size, buf, bsize) || + fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) + goto err; + } close(fd); free(buf); return (1);