Remove some compilation warnings.
[platform/upstream/cryptsetup.git] / lib / utils.c
1 /*
2  * utils - miscellaneous device utilities for cryptsetup
3  *
4  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
5  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
6  * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <errno.h>
28 #include <linux/fs.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <sys/resource.h>
37
38 #include "libcryptsetup.h"
39 #include "internal.h"
40
41 unsigned crypt_getpagesize(void)
42 {
43         return (unsigned)sysconf(_SC_PAGESIZE);
44 }
45
46 static int get_alignment(int fd)
47 {
48         int alignment = DEFAULT_MEM_ALIGNMENT;
49
50 #ifdef _PC_REC_XFER_ALIGN
51         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
52         if (alignment < 0)
53                 alignment = DEFAULT_MEM_ALIGNMENT;
54 #endif
55         return alignment;
56 }
57
58 static void *aligned_malloc(void **base, int size, int alignment)
59 {
60 #ifdef HAVE_POSIX_MEMALIGN
61         return posix_memalign(base, alignment, size) ? NULL : *base;
62 #else
63 /* Credits go to Michal's padlock patches for this alignment code */
64         char *ptr;
65
66         ptr  = malloc(size + alignment);
67         if(ptr == NULL) return NULL;
68
69         *base = ptr;
70         if(alignment > 1 && ((long)ptr & (alignment - 1))) {
71                 ptr += alignment - ((long)(ptr) & (alignment - 1));
72         }
73         return ptr;
74 #endif
75 }
76
77 int device_read_ahead(const char *dev, uint32_t *read_ahead)
78 {
79         int fd, r = 0;
80         long read_ahead_long;
81
82         if ((fd = open(dev, O_RDONLY)) < 0)
83                 return 0;
84
85         r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
86         close(fd);
87
88         if (r)
89                 *read_ahead = (uint32_t) read_ahead_long;
90
91         return r;
92 }
93
94 static int sector_size(int fd) 
95 {
96         int bsize;
97         if (ioctl(fd,BLKSSZGET, &bsize) < 0)
98                 return -EINVAL;
99         else
100                 return bsize;
101 }
102
103 int sector_size_for_device(const char *device)
104 {
105         int fd = open(device, O_RDONLY);
106         int r;
107         if(fd < 0)
108                 return -EINVAL;
109         r = sector_size(fd);
110         close(fd);
111         return r;
112 }
113
114 ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
115 {
116         void *hangover_buf, *hangover_buf_base = NULL;
117         void *buf, *buf_base = NULL;
118         int r, hangover, solid, bsize, alignment;
119         ssize_t ret = -1;
120
121         if ((bsize = sector_size(fd)) < 0)
122                 return bsize;
123
124         hangover = count % bsize;
125         solid = count - hangover;
126         alignment = get_alignment(fd);
127
128         if ((long)orig_buf & (alignment - 1)) {
129                 buf = aligned_malloc(&buf_base, count, alignment);
130                 if (!buf)
131                         goto out;
132                 memcpy(buf, orig_buf, count);
133         } else
134                 buf = orig_buf;
135
136         r = write(fd, buf, solid);
137         if (r < 0 || r != solid)
138                 goto out;
139
140         if (hangover) {
141                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
142                 if (!hangover_buf)
143                         goto out;
144
145                 r = read(fd, hangover_buf, bsize);
146                 if (r < 0 || r != bsize)
147                         goto out;
148
149                 r = lseek(fd, -bsize, SEEK_CUR);
150                 if (r < 0)
151                         goto out;
152                 memcpy(hangover_buf, (char*)buf + solid, hangover);
153
154                 r = write(fd, hangover_buf, bsize);
155                 if (r < 0 || r != bsize)
156                         goto out;
157         }
158         ret = count;
159 out:
160         free(hangover_buf_base);
161         if (buf != orig_buf)
162                 free(buf_base);
163         return ret;
164 }
165
166 ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
167         void *hangover_buf, *hangover_buf_base = NULL;
168         void *buf, *buf_base = NULL;
169         int r, hangover, solid, bsize, alignment;
170         ssize_t ret = -1;
171
172         if ((bsize = sector_size(fd)) < 0)
173                 return bsize;
174
175         hangover = count % bsize;
176         solid = count - hangover;
177         alignment = get_alignment(fd);
178
179         if ((long)orig_buf & (alignment - 1)) {
180                 buf = aligned_malloc(&buf_base, count, alignment);
181                 if (!buf)
182                         return -1;
183         } else
184                 buf = orig_buf;
185
186         r = read(fd, buf, solid);
187         if(r < 0 || r != solid)
188                 goto out;
189
190         if (hangover) {
191                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
192                 if (!hangover_buf)
193                         goto out;
194                 r = read(fd, hangover_buf, bsize);
195                 if (r <  0 || r != bsize)
196                         goto out;
197
198                 memcpy((char *)buf + solid, hangover_buf, hangover);
199         }
200         ret = count;
201 out:
202         free(hangover_buf_base);
203         if (buf != orig_buf) {
204                 memcpy(orig_buf, buf, count);
205                 free(buf_base);
206         }
207         return ret;
208 }
209
210 /*
211  * Combines llseek with blockwise write. write_blockwise can already deal with short writes
212  * but we also need a function to deal with short writes at the start. But this information
213  * is implicitly included in the read/write offset, which can not be set to non-aligned
214  * boundaries. Hence, we combine llseek with write.
215  */
216 ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
217         char *frontPadBuf;
218         void *frontPadBuf_base = NULL;
219         int r, bsize, frontHang;
220         size_t innerCount = 0;
221         ssize_t ret = -1;
222
223         if ((bsize = sector_size(fd)) < 0)
224                 return bsize;
225
226         frontHang = offset % bsize;
227
228         if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
229                 goto out;
230
231         if (frontHang) {
232                 frontPadBuf = aligned_malloc(&frontPadBuf_base,
233                                              bsize, get_alignment(fd));
234                 if (!frontPadBuf)
235                         goto out;
236
237                 r = read(fd, frontPadBuf, bsize);
238                 if (r < 0 || r != bsize)
239                         goto out;
240
241                 innerCount = bsize - frontHang;
242                 if (innerCount > count)
243                         innerCount = count;
244
245                 memcpy(frontPadBuf + frontHang, buf, innerCount);
246
247                 if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
248                         goto out;
249
250                 r = write(fd, frontPadBuf, bsize);
251                 if (r < 0 || r != bsize)
252                         goto out;
253
254                 buf += innerCount;
255                 count -= innerCount;
256         }
257
258         ret = count ? write_blockwise(fd, buf, count) : 0;
259         if (ret >= 0)
260                 ret += innerCount;
261 out:
262         free(frontPadBuf_base);
263
264         return ret;
265 }
266
267 int device_ready(struct crypt_device *cd, const char *device, int mode)
268 {
269         int devfd, r = 0;
270         ssize_t s;
271         struct stat st;
272         char buf[512];
273
274         if(stat(device, &st) < 0) {
275                 log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
276                 return -EINVAL;
277         }
278
279         if (!S_ISBLK(st.st_mode))
280                 return -ENOTBLK;
281
282         log_dbg("Trying to open and read device %s.", device);
283         devfd = open(device, mode | O_DIRECT | O_SYNC);
284         if(devfd < 0) {
285                 log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
286                         (mode & O_EXCL) ? _("exclusive ") : "",
287                         (mode & O_RDWR) ? _("writable") : _("read-only"));
288                 return -EINVAL;
289         }
290
291          /* Try to read first sector */
292         s = read_blockwise(devfd, buf, sizeof(buf));
293         if (s < 0 || s != sizeof(buf)) {
294                 log_verbose(cd, _("Cannot read device %s.\n"), device);
295                 r = -EIO;
296         }
297
298         memset(buf, 0, sizeof(buf));
299         close(devfd);
300
301         return r;
302 }
303
304 int device_size(const char *device, uint64_t *size)
305 {
306         int devfd, r = 0;
307
308         devfd = open(device, O_RDONLY);
309         if(devfd == -1)
310                 return -EINVAL;
311
312         if (ioctl(devfd, BLKGETSIZE64, size) < 0)
313                 r = -EINVAL;
314
315         close(devfd);
316         return r;
317 }
318
319 static int get_device_infos(const char *device, enum devcheck device_check,
320                             int *readonly, uint64_t *size)
321 {
322         struct stat st;
323         unsigned long size_small;
324         int fd, r = -1;
325         int flags = 0;
326
327         *readonly = 0;
328         *size = 0;
329
330         if (stat(device, &st) < 0)
331                 return -EINVAL;
332
333         /* never wipe header on mounted device */
334         if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
335                 flags |= O_EXCL;
336
337         /* Try to open read-write to check whether it is a read-only device */
338         fd = open(device, O_RDWR | flags);
339         if (fd == -1 && errno == EROFS) {
340                 *readonly = 1;
341                 fd = open(device, O_RDONLY | flags);
342         }
343
344         if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
345                 return -EBUSY;
346
347         if (fd == -1)
348                 return -EINVAL;
349
350         /* If the device can be opened read-write, i.e. readonly is still 0, then
351          * check whether BKROGET says that it is read-only. E.g. read-only loop
352          * devices may be openend read-write but are read-only according to BLKROGET
353          */
354         if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
355                 goto out;
356
357         if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
358                 *size >>= SECTOR_SHIFT;
359                 r = 0;
360                 goto out;
361         }
362
363         if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
364                 *size = (uint64_t)size_small;
365                 r = 0;
366                 goto out;
367         }
368
369         r = -EINVAL;
370 out:
371         close(fd);
372         return r;
373 }
374
375 int device_check_and_adjust(struct crypt_device *cd,
376                             const char *device,
377                             enum devcheck device_check,
378                             uint64_t *size,
379                             uint64_t *offset,
380                             uint32_t *flags)
381 {
382         int r, real_readonly;
383         uint64_t real_size;
384
385         if (!device)
386                 return -ENOTBLK;
387
388         r = get_device_infos(device, device_check, &real_readonly, &real_size);
389         if (r < 0) {
390                 if (r == -EBUSY)
391                         log_err(cd, _("Cannot use device %s which is in use "
392                                       "(already mapped or mounted).\n"),
393                                       device);
394                 else
395                         log_err(cd, _("Cannot get info about device %s.\n"),
396                                 device);
397                 return r;
398         }
399
400         if (*offset >= real_size) {
401                 log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
402                         device);
403                 return -EINVAL;
404         }
405
406         if (!*size) {
407                 *size = real_size;
408                 if (!*size) {
409                         log_err(cd, _("Device %s has zero size.\n"), device);
410                         return -ENOTBLK;
411                 }
412                 *size -= *offset;
413         }
414
415         /* in case of size is set by parameter */
416         if ((real_size - *offset) < *size) {
417                 log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
418                         ", backing device size = %" PRIu64,
419                         device, *offset, *size, real_size);
420                 log_err(cd, _("Device %s is too small.\n"), device);
421                 return -EINVAL;
422         }
423
424         if (real_readonly)
425                 *flags |= CRYPT_ACTIVATE_READONLY;
426
427         log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
428                 *size, real_readonly ? "RO" : "RW", *offset);
429         return 0;
430 }
431
432 /* MEMLOCK */
433 #define DEFAULT_PROCESS_PRIORITY -18
434
435 static int _priority;
436 static int _memlock_count = 0;
437
438 // return 1 if memory is locked
439 int crypt_memlock_inc(struct crypt_device *ctx)
440 {
441         if (!_memlock_count++) {
442                 log_dbg("Locking memory.");
443                 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
444                         log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
445                         _memlock_count--;
446                         return 0;
447                 }
448                 errno = 0;
449                 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
450                         log_err(ctx, _("Cannot get process priority.\n"));
451                 else
452                         if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
453                                 log_err(ctx, _("setpriority %d failed: %s\n"),
454                                         DEFAULT_PROCESS_PRIORITY, strerror(errno));
455         }
456         return _memlock_count ? 1 : 0;
457 }
458
459 int crypt_memlock_dec(struct crypt_device *ctx)
460 {
461         if (_memlock_count && (!--_memlock_count)) {
462                 log_dbg("Unlocking memory.");
463                 if (munlockall() == -1)
464                         log_err(ctx, _("Cannot unlock memory.\n"));
465                 if (setpriority(PRIO_PROCESS, 0, _priority))
466                         log_err(ctx, _("setpriority %d failed: %s\n"), _priority, strerror(errno));
467         }
468         return _memlock_count ? 1 : 0;
469 }
470
471 /* DEVICE TOPOLOGY */
472
473 /* block device topology ioctls, introduced in 2.6.32 */
474 #ifndef BLKIOMIN
475 #define BLKIOMIN    _IO(0x12,120)
476 #define BLKIOOPT    _IO(0x12,121)
477 #define BLKALIGNOFF _IO(0x12,122)
478 #endif
479
480 void get_topology_alignment(const char *device,
481                             unsigned long *required_alignment, /* bytes */
482                             unsigned long *alignment_offset,   /* bytes */
483                             unsigned long default_alignment)
484 {
485         int dev_alignment_offset = 0;
486         unsigned int min_io_size = 0, opt_io_size = 0;
487         unsigned long temp_alignment = 0;
488         int fd;
489
490         *required_alignment = default_alignment;
491         *alignment_offset = 0;
492
493         fd = open(device, O_RDONLY);
494         if (fd == -1)
495                 return;
496
497         /* minimum io size */
498         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
499                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
500                         device, default_alignment);
501                 goto out;
502         }
503
504         /* optimal io size */
505         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
506                 opt_io_size = min_io_size;
507
508         /* alignment offset, bogus -1 means misaligned/unknown */
509         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
510                 dev_alignment_offset = 0;
511         *alignment_offset = (unsigned long)dev_alignment_offset;
512
513         temp_alignment = (unsigned long)min_io_size;
514
515         if (temp_alignment < (unsigned long)opt_io_size)
516                 temp_alignment = (unsigned long)opt_io_size;
517
518         /* If calculated alignment is multiple of default, keep default */
519         if (temp_alignment && (default_alignment % temp_alignment))
520                 *required_alignment = temp_alignment;
521
522         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
523                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
524 out:
525         (void)close(fd);
526 }