#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char *optarg;
extern int optind;
static long
random_long(long mi, long ma)
{
return (arc4random() % (ma - mi + 1) + mi);
}
static void
flip(void *ap, size_t len)
{
unsigned char *cp;
int byte;
unsigned char bit, buf, mask, old __unused;
cp = (unsigned char *)ap;
byte = random_long(0, len - 1);
bit = random_long(0,7);
mask = ~(1 << bit);
buf = cp[byte];
old = cp[byte];
buf = (buf & mask) | (~buf & ~mask);
cp[byte] = buf;
#if defined(DEBUG)
printf("Change %2x to %2x at %d by flipping bit %d\n",
old, buf, byte, bit);
#endif
}
static void
trash(char *c)
{
if (arc4random() % 2 == 1)
*c = 0;
else
arc4random_buf(c, sizeof(c));
}
int
main(int argc, char *argv[])
{
struct stat st;
off_t pos;
size_t size;
int c, fd, i, times;
times = 1;
size = 0;
while ((c = getopt(argc, argv, "n:s:")) != -1) {
switch (c) {
case 'n':
times = atoi(optarg);
break;
case 's':
size = atol(optarg);
break;
case '?':
default:
fprintf(stderr,
"Usage: %s [ -n <num> <file>]\n",
argv[0]);
exit(1);
}
}
argc -= optind;
argv += optind;
if (argc != 1) {
fprintf(stderr, "Missing file name\n");
exit(1);
}
if ((fd = open(argv[0], O_RDWR)) == -1)
err(1, "open(%s)", argv[0]);
if (size == 0) {
if (fstat(fd, &st) == -1)
err(1, "stat %s", argv[0]);
if ((st.st_mode & S_IFREG) == 0)
errx(1, "%s must be a regular file\n", argv[0]);
size = st.st_size;
}
for (i = 0; i < times; i++) {
char ch;
pos = arc4random() % size;
if (lseek(fd, pos, SEEK_SET) == -1)
err(1, "lseek()");
if (read(fd, &ch, 1) != 1)
err(1, "read()");
if (arc4random() % 100 < 98)
flip(&ch, 1);
else
trash(&ch);
if (lseek(fd, pos, SEEK_SET) == -1)
err(1, "lseek()");
if (write(fd, &ch, 1) != 1)
err(1, "write()");
}
return (0);
}