2 * released into the public domain
3 * written by Mike Frysinger <vapier>
6 #pragma GCC diagnostic warning "-Wall"
7 #pragma GCC diagnostic warning "-Wextra"
9 #define _FILE_OFFSET_BITS 64
10 #define _LARGEFILE_SOURCE
11 #define _LARGEFILE64_SOURCE
28 #include <sys/ioctl.h>
30 #include <sys/types.h>
34 static unsigned long long mbps(struct timespec *stime, struct timespec *etime, off_t len)
37 clock_gettime(CLOCK_MONOTONIC, etime);
38 dtime = ((etime->tv_sec - stime->tv_sec) * 1000 * 1000 * 1000) +
39 (etime->tv_nsec - stime->tv_nsec);
41 return 1000 * len / dtime;
44 static off_t get_blk_size(int fd)
47 if (ioctl(fd, BLKGETSIZE64, &size))
48 err(EX_DATAERR, "ioctl(BLKGETSIZE64) failed");
52 static off_t get_size(int fd)
57 err(EX_DATAERR, "could not stat %i", fd);
59 if (S_ISREG(st.st_mode))
61 else if (S_ISBLK(st.st_mode))
62 return get_blk_size(fd);
65 err(EX_DATAERR, "unknown type of file");
68 static void nuke(int fd, off_t offset, off_t max_size, unsigned char pattern)
70 static char mem[1024 * 1024];
71 memset(mem, pattern, sizeof(mem));
73 printf("Writing 0x%X to the output\n", pattern);
75 if (lseek(fd, offset, SEEK_SET) != offset)
76 err(EX_DATAERR, "lseek(%"PRIu64"u) failed", offset);
78 unsigned long long speed = 0;
79 struct timespec stime, etime, itime;
80 clock_gettime(CLOCK_MONOTONIC, &stime);
83 off_t pos = offset, last_pos = 0;
86 while (pos < max_size) {
87 /* This will round up to sizeof(mem) ... */
88 ret = write(fd, mem, sizeof(mem));
90 if (ret != sizeof(mem)) {
92 printf("\nread() returned %zi (wanted %zu)\n%'llu MB/s over entire run\n",
93 ret, sizeof(mem), mbps(&itime, &etime, pos));
97 unsigned long long eta = speed ? (max_size - pos) / (speed * 1000 * 1000) : 0;
98 printf("\r\e[2K%'llu bytes %u%% (%'llu MB/s) (ETA ~%llum%llus)",
99 (unsigned long long)pos, (unsigned)((pos * 100) / max_size), speed,
102 if ((++fsync_pos % 32) == 0) {
103 speed = mbps(&stime, &etime, pos - last_pos);
113 static void usage(int status)
116 status ? stderr : stdout,
117 "Usage: ddnuke [options] <dev>\n"
121 " -y Assume yes to all prompts\n"
122 " -o <offset> Position to start writing\n"
123 " -r Write three times: 0x00, then 0xaa, then 0x55\n"
128 int main(int argc, char *argv[])
137 setlocale(LC_NUMERIC, "en_US");
139 while ((o = getopt(argc, argv, "ho:qry")) != -1) {
142 offset = atoll(optarg);
161 if (argc != optind + 1)
165 int fd = open(file, O_WRONLY|O_CLOEXEC);
167 err(EX_NOINPUT, "open(%s) failed", file);
171 const char *argv[] = {"fdisk", "-l", file, NULL};
172 if (posix_spawnp(&pid, argv[0], NULL, NULL, (char *const *)argv, NULL))
173 err(EX_OSERR, "spawn(%s %s) failed", argv[0], file);
174 waitpid(pid, NULL, 0);
179 printf("Do you want to wipe '%s'? (y/N) ", file);
182 if (fread(&c, 1, 1, stdin)) {/* don't care */}
183 if (tolower(c) != 'y')
184 errx(EX_UNAVAILABLE, "User decided not to wipe");
187 off_t max_size = get_size(fd);
189 nuke(fd, offset, max_size, 0x00);
191 nuke(fd, offset, max_size, 0xaa);
192 nuke(fd, offset, max_size, 0x55);