]> git.wh0rd.org - home.git/blob - ddnuke.c
ddnuke: document error case better
[home.git] / ddnuke.c
1 /*
2 * released into the public domain
3 * written by Mike Frysinger <vapier>
4 */
5
6 #pragma GCC diagnostic warning "-Wall"
7 #pragma GCC diagnostic warning "-Wextra"
8
9 #define _FILE_OFFSET_BITS 64
10 #define _LARGEFILE_SOURCE
11 #define _LARGEFILE64_SOURCE
12 #define _GNU_SOURCE
13
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <inttypes.h>
17 #include <locale.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <linux/fs.h>
26
27 static const char zero[1024 * 1024];
28
29 #define errp(msg, args...) \
30 do { \
31 printf("%s: " msg ": %m\n", program_invocation_short_name, ## args); \
32 exit(1); \
33 } while (0)
34
35 static unsigned long long mbps(struct timespec *stime, struct timespec *etime, off_t len)
36 {
37 uint64_t dtime;
38 clock_gettime(CLOCK_MONOTONIC, etime);
39 dtime = ((etime->tv_sec - stime->tv_sec) * 1000 * 1000 * 1000) +
40 (etime->tv_nsec - stime->tv_nsec);
41 *stime = *etime;
42 return 1000 * len / dtime;
43 }
44
45 static off_t get_blk_size(int fd)
46 {
47 uint64_t size;
48 if (ioctl(fd, BLKGETSIZE64, &size))
49 errp("ioctl(BLKGETSIZE64) failed");
50 return size;
51 }
52
53 static off_t get_size(int fd)
54 {
55 struct stat st;
56
57 if (fstat(fd, &st))
58 errp("could not stat %i", fd);
59
60 if (S_ISREG(st.st_mode))
61 return st.st_size;
62 else if (S_ISBLK(st.st_mode))
63 return get_blk_size(fd);
64
65 errno = EINVAL;
66 errp("unknown type of file");
67 }
68
69 int main(int argc, char *argv[])
70 {
71 off_t offset = 0;
72 const char *file;
73
74 setlocale(LC_NUMERIC, "en_US");
75
76 switch (argc) {
77 case 3:
78 offset = atoll(argv[2]);
79 case 2:
80 file = argv[1];
81 break;
82 default:
83 puts("Usage: ddnuke <dev> [offset in bytes]");
84 return 1;
85 }
86
87 int fd = open(file, O_WRONLY);
88 if (fd == -1)
89 errp("open(%s) failed", file);
90
91 off_t max_size = get_size(fd);
92
93 if (lseek(fd, offset, SEEK_SET) != offset)
94 errp("lseek(%"PRIu64"u) failed", offset);
95
96 unsigned long long speed = 0;
97 struct timespec stime, etime, itime;
98 clock_gettime(CLOCK_MONOTONIC, &stime);
99 itime = stime;
100
101 off_t pos = offset, last_pos = 0;
102 ssize_t ret;
103 int fsync_pos = 0;
104 while (pos < max_size) {
105 ret = write(fd, zero, sizeof(zero));
106 pos += ret;
107 if (ret != sizeof(zero)) {
108 printf("\nread() returned %zi (wanted %zu)\n%'llu MB/s over entire run\n",
109 ret, sizeof(zero), mbps(&itime, &etime, pos));
110 return 0;
111 }
112
113 printf("%'llu bytes %u%% (%'llu MB/s)%20s\r", (unsigned long long)pos,
114 (unsigned)((pos * 100) / max_size), speed, "");
115
116 if ((++fsync_pos % 16) == 0) {
117 speed = mbps(&stime, &etime, pos - last_pos);
118 last_pos = pos;
119 fflush(stdout);
120 fsync(fd);
121 }
122 }
123
124 printf("\n");
125 return 0;
126 }