7d96fa5ceb519fe7880f82938c6971bc41d6df5e
[dragonfly.git] / lib / libtcplay / io.c
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include <sys/types.h>
30 #include <sys/diskslice.h>
31 #include <sys/uio.h>
32 #include <sys/select.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <unistd.h>
40
41 #include "tcplay.h"
42
43 void *
44 read_to_safe_mem(const char *file, off_t offset, size_t *sz)
45 {
46         void *mem = NULL;
47         ssize_t r = 0;
48         int fd;
49
50         if ((fd = open(file, O_RDONLY)) < 0) {
51                 tc_log(1, "Error opening file %s\n", file);
52                 return NULL;
53         }
54
55         if ((mem = alloc_safe_mem(*sz)) == NULL) {
56                 tc_log(1, "Error allocating memory\n");
57                 goto out;
58         }
59
60         if ((lseek(fd, offset, SEEK_SET) < 0)) {
61                 tc_log(1, "Error seeking on file %s\n", file);
62                 goto m_err;
63         }
64
65         if ((r = read(fd, mem, *sz)) <= 0) {
66                 tc_log(1, "Error reading from file %s\n", file);
67                 goto m_err;
68         }
69
70 out:
71         *sz = r;
72         close(fd);
73         return mem;
74         /* NOT REACHED */
75
76 m_err:
77         free_safe_mem(mem);
78         close(fd);
79         return NULL;
80 }
81
82 int
83 get_random(unsigned char *buf, size_t len)
84 {
85         int fd;
86         ssize_t r;
87         size_t rd = 0;
88         struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
89
90
91         if ((fd = open("/dev/random", O_RDONLY)) < 0) {
92                 tc_log(1, "Error opening /dev/random\n");
93                 return -1;
94         }
95
96         while (rd < len) {
97                 if ((r = read(fd, buf+rd, len-rd)) < 0) {
98                         tc_log(1, "Error reading from /dev/random\n");
99                         close(fd);
100                         return -1;
101                 }
102                 rd += r;
103                 nanosleep(&ts, NULL);
104         }
105
106         close(fd);
107         return 0;
108 }
109
110 static size_t secure_erase_total_bytes = 0;
111 static size_t secure_erase_erased_bytes = 0;
112
113 static
114 void
115 secure_erase_summary(void)
116 {
117         float pct_done;
118
119         pct_done = (1.0 * secure_erase_erased_bytes) /
120             (1.0 * secure_erase_total_bytes) * 100.0;
121         tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done);
122 }
123
124 int
125 secure_erase(const char *dev, size_t bytes, size_t blksz)
126 {
127         size_t erased = 0;
128         int fd_rand, fd;
129         char buf[ERASE_BUFFER_SIZE];
130         ssize_t r, w;
131         size_t sz;
132
133         if (blksz > MAX_BLKSZ) {
134                 tc_log(1, "blksz > MAX_BLKSZ\n");
135                 return -1;
136         }
137
138         if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) {
139                 tc_log(1, "Error opening /dev/urandom\n");
140                 return -1;
141         }
142
143         if ((fd = open(dev, O_WRONLY)) < 0) {
144                 close(fd_rand);
145                 tc_log(1, "Error opening %s\n", dev);
146                 return -1;
147         }
148
149         summary_fn = secure_erase_summary;
150         secure_erase_total_bytes = bytes;
151
152         sz = ERASE_BUFFER_SIZE;
153         while (erased < bytes) {
154                 secure_erase_erased_bytes = erased;
155                 /* Switch to block size when not much is remaining */
156                 if ((bytes - erased) <= ERASE_BUFFER_SIZE)
157                         sz = blksz;
158
159                 if ((r = read(fd_rand, buf, sz)) < 0) {
160                         tc_log(1, "Error reading from /dev/urandom\n");
161                         close(fd);
162                         close(fd_rand);
163                         summary_fn = NULL;
164                         return -1;
165                 }
166
167                 if (r < (ssize_t)blksz)
168                         continue;
169
170                 if ((w = write(fd, buf, r)) < 0) {
171                         tc_log(1, "Error writing to %s\n", dev);
172                         close(fd);
173                         close(fd_rand);
174                         summary_fn = NULL;
175                         return -1;
176                 }
177
178                 erased += (size_t)w;
179         }
180
181         close(fd);
182         close(fd_rand);
183
184         summary_fn = NULL;
185
186         return 0;
187 }
188
189 int
190 get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
191 {
192         struct partinfo pinfo;
193         int fd;
194
195         if ((fd = open(dev, O_RDONLY)) < 0) {
196                 tc_log(1, "Error opening %s\n", dev);
197                 return -1;
198         }
199
200         memset(&pinfo, 0, sizeof(struct partinfo));
201
202         if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
203                 close(fd);
204                 return -1;
205         }
206
207         *blocks = pinfo.media_blocks;
208         *bsize = pinfo.media_blksize;
209
210         close(fd);
211         return 0;
212 }
213
214 int
215 write_mem(const char *dev, off_t offset, size_t blksz __unused, void *mem,
216     size_t bytes)
217 {
218         ssize_t w;
219         int fd;
220
221         if ((fd = open(dev, O_WRONLY)) < 0) {
222                 tc_log(1, "Error opening device %s\n", dev);
223                 return -1;
224         }
225
226         if ((lseek(fd, offset, SEEK_SET) < 0)) {
227                 tc_log(1, "Error seeking on device %s\n", dev);
228                 close(fd);
229                 return -1;
230         }
231
232         if ((w = write(fd, mem, bytes)) <= 0) {
233                 tc_log(1, "Error writing to device %s\n", dev);
234                 close(fd);
235                 return -1;
236         }
237
238         close(fd);
239         return 0;
240 }
241
242 int
243 read_passphrase(const char *prompt, char *pass, size_t passlen, time_t timeout)
244 {
245         struct termios termios_old, termios_new;
246         struct timeval to;
247         fd_set fds;
248         ssize_t n;
249         int fd, r = 0, cfd = 0, nready;
250
251         if ((fd = open("/dev/tty", O_RDONLY)) == -1) {
252                 fd = STDIN_FILENO;
253                 cfd = 1;
254         }
255
256         printf(prompt);
257         fflush(stdout);
258
259         memset(pass, 0, passlen);
260
261         tcgetattr(fd, &termios_old);
262         memcpy(&termios_new, &termios_old, sizeof(termios_new));
263         termios_new.c_lflag &= ~ECHO;
264         tcsetattr(fd, TCSAFLUSH, &termios_new);
265
266         if (timeout > 0) {
267                 memset(&to, 0, sizeof(to));
268                 to.tv_sec = timeout;
269
270                 FD_ZERO(&fds);
271                 FD_SET(fd, &fds);
272                 nready = select(fd + 1, &fds, NULL, NULL, &to);
273                 if (nready <= 0) {
274                         r = EINTR;
275                         goto out;
276                 }
277         }
278
279         n = read(fd, pass, passlen-1);
280         if (n > 0) {
281                 pass[n-1] = '\0'; /* Strip trailing \n */
282         } else {
283                 r = EIO;
284         }
285
286 out:
287         if (cfd)
288                 close(fd);
289
290         tcsetattr(fd, TCSAFLUSH, &termios_old);
291         putchar('\n');
292
293         return r;
294 }