]> git.wh0rd.org Git - home.git/blob - ddnuke.c
imgcrush: parse multiple arguments correctly
[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 <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sysexits.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <sys/ioctl.h>
26 #include <sys/stat.h>
27 #include <linux/fs.h>
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 static void nuke(int fd, off_t offset, off_t max_size, unsigned char pattern)
70 {
71         static char mem[1024 * 1024];
72         memset(mem, pattern, sizeof(mem));
73         if (pattern)
74                 printf("Writing 0x%X to the output\n", pattern);
75
76         if (lseek(fd, offset, SEEK_SET) != offset)
77                 errp("lseek(%"PRIu64"u) failed", offset);
78
79         unsigned long long speed = 0;
80         struct timespec stime, etime, itime;
81         clock_gettime(CLOCK_MONOTONIC, &stime);
82         itime = stime;
83
84         off_t pos = offset, last_pos = 0;
85         ssize_t ret;
86         int fsync_pos = 0;
87         while (pos < max_size) {
88                 /* This will round up to sizeof(mem) ... */
89                 ret = write(fd, mem, sizeof(mem));
90                 pos += ret;
91                 if (ret != sizeof(mem)) {
92                         if (pos != max_size)
93                                 printf("\nread() returned %zi (wanted %zu)\n%'llu MB/s over entire run\n",
94                                         ret, sizeof(mem), mbps(&itime, &etime, pos));
95                         return;
96                 }
97
98                 printf("%'llu bytes %u%% (%'llu MB/s)%20s\r", (unsigned long long)pos,
99                         (unsigned)((pos * 100) / max_size), speed, "");
100
101                 if ((++fsync_pos % 32) == 0) {
102                         speed = mbps(&stime, &etime, pos - last_pos);
103                         last_pos = pos;
104                         fflush(stdout);
105                         fsync(fd);
106                 }
107         }
108
109         printf("\n");
110 }
111
112 static void usage(int status)
113 {
114         fprintf(
115                 status ? stderr : stdout,
116                 "Usage: ddnuke [options] <dev>\n"
117                 "\n"
118                 "Options:\n"
119                 " -o <offset>   Position to start writing\n"
120                 " -r            Write three times: 0x00, then 0xaa, then 0x55\n"
121         );
122         exit(status);
123 }
124
125 int main(int argc, char *argv[])
126 {
127         off_t offset = 0;
128         const char *file;
129         bool random = false;
130         int o;
131
132         setlocale(LC_NUMERIC, "en_US");
133
134         while ((o = getopt(argc, argv, "ho:r")) != -1) {
135                 switch (o) {
136                 case 'o':
137                         offset = atoll(optarg);
138                         break;
139                 case 'r':
140                         random = true;
141                         break;
142                 case 'h': usage(EX_OK);
143                 default:  usage(EX_USAGE);
144                 }
145         }
146         if (argc != optind + 1)
147                 usage(EX_USAGE);
148         file = argv[optind];
149
150         int fd = open(file, O_WRONLY|O_CLOEXEC);
151         if (fd == -1)
152                 errp("open(%s) failed", file);
153
154         off_t max_size = get_size(fd);
155
156         nuke(fd, offset, max_size, 0x00);
157         if (random) {
158                 nuke(fd, offset, max_size, 0xaa);
159                 nuke(fd, offset, max_size, 0x55);
160         }
161
162         return EX_OK;
163 }