/* * Copyright (C) 2004 Red Hat, UK * * This file is released under the GPL */ #include #include #include #include #include #include #include #include #include #define HASH_MULT 2654435387U #define CHUNKSIZE 4096 static unsigned seed; static inline unsigned pattern(void) { unsigned r = seed; seed *= HASH_MULT; return r; } void usage(FILE *fp) { fprintf(fp, "Usage:\n"); fprintf(fp, "\n"); fprintf(fp, "hashdd of= seed= [osync=]\n"); fprintf(fp, "hashdd if= seed= [osync=]\n"); } static int io(int fd, int write_p, void *buffer, size_t size) { ssize_t n = 0; size_t total = 0; while (size) { do n = write_p ? write(fd, buffer, size) : read(fd, buffer, size); while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN))); if (n <= 0) break; total += n; buffer += n; } return (total ? total : 0); } static void fill_array(unsigned *array, unsigned count) { unsigned i; for (i = 0; i < count; i++) array[i] = pattern(); } static int valid_array(unsigned *array, unsigned count) { unsigned i; for (i = 0; i < count; i++) if (array[i] != pattern()) { fprintf(stderr, "found invalid data at offset %u\n", i * sizeof(*array)); return 0; } return 1; } static int read_file(char *filename) { int fd; size_t n; unsigned buffer[1024 * 256]; fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Error opening '%s': %s\n", filename, strerror(errno)); return 0; } while (1) { n = io(fd, 0, buffer, sizeof(buffer)); if (!n) break; if (!valid_array(buffer, n / sizeof(*buffer))) return 0; } return 1; } static int write_file(char *filename) { int fd; size_t n, size; unsigned buffer[1024 * 256]; fd = open(filename, O_CREAT | O_WRONLY); if (fd < 0) { fprintf(stderr, "Error opening '%s': %s\n", filename, strerror(errno)); return 0; } size = sizeof(buffer) / sizeof(*buffer); while (1) { fill_array(buffer, size); n = io(fd, 1, buffer, sizeof(buffer)); if (n != sizeof(buffer)) break; } fsync(fd); close(fd); return 1; } int main(int argc, char **argv) { int error = 0; char *filename = NULL; char act[10]; char action = 'r'; int i, count; struct stat st; if(argc != 3) { usage(stderr); return 1; } for(i = 1; i < argc; i++) { count = strcspn(argv[i], "="); count++; if(count < 2 || count > 8) { error = 1; goto end; } memset(act, 0, sizeof(char) * 10); strncpy(act, argv[i], count); if(!strcmp(act, "if=")) { filename = &(argv[i][count]); action = 'r'; } else if(!strcmp(act, "of=")) { filename = &(argv[i][count]); action = 'w'; } else if(!strcmp(act, "seed=")) seed = atoi(&(argv[i][count])); /* else if(!strcmp(act, "osync=")) sync = atoi(&(argv[i][count]));*/ else { usage(stderr); return 1; } } if((error = stat(filename, &st)) != 0) { if(errno != ENOENT) { fprintf(stderr, "Unable to stat %s: %s\n", filename, strerror(errno)); return 1; } } else if(!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode)) { fprintf(stderr, " must be a regular file or a block device\n"); return 1; } if(seed <= 1) { fprintf(stderr, "seed value must be greater than 1\n"); error = 1; goto end; } if(action == 'w') error = !write_file(filename); else if (action == 'r') error = !read_file(filename); else { usage(stderr); return 1; } end: return error; }