Remove old ifdef, all recent systems have this defined.
[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-2011, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 static char *error=NULL;
42
43 __attribute__((format(printf, 1, 0)))
44 void set_error_va(const char *fmt, va_list va)
45 {
46         int r;
47
48         if(error) {
49                 free(error);
50                 error = NULL;
51         }
52
53         if(!fmt) return;
54
55         r = vasprintf(&error, fmt, va);
56         if (r < 0) {
57                 free(error);
58                 error = NULL;
59                 return;
60         }
61
62         if (r && error[r - 1] == '\n')
63                 error[r - 1] = '\0';
64 }
65
66 __attribute__((format(printf, 1, 2)))
67 void set_error(const char *fmt, ...)
68 {
69         va_list va;
70
71         va_start(va, fmt);
72         set_error_va(fmt, va);
73         va_end(va);
74 }
75
76 const char *get_error(void)
77 {
78         return error;
79 }
80
81 static int get_alignment(int fd)
82 {
83         int alignment = DEFAULT_MEM_ALIGNMENT;
84
85 #ifdef _PC_REC_XFER_ALIGN
86         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
87         if (alignment < 0)
88                 alignment = DEFAULT_MEM_ALIGNMENT;
89 #endif
90         return alignment;
91 }
92
93 static void *aligned_malloc(void **base, int size, int alignment)
94 {
95 #ifdef HAVE_POSIX_MEMALIGN
96         return posix_memalign(base, alignment, size) ? NULL : *base;
97 #else
98 /* Credits go to Michal's padlock patches for this alignment code */
99         char *ptr;
100
101         ptr  = malloc(size + alignment);
102         if(ptr == NULL) return NULL;
103
104         *base = ptr;
105         if(alignment > 1 && ((long)ptr & (alignment - 1))) {
106                 ptr += alignment - ((long)(ptr) & (alignment - 1));
107         }
108         return ptr;
109 #endif
110 }
111 static int sector_size(int fd) 
112 {
113         int bsize;
114         if (ioctl(fd,BLKSSZGET, &bsize) < 0)
115                 return -EINVAL;
116         else
117                 return bsize;
118 }
119
120 int sector_size_for_device(const char *device)
121 {
122         int fd = open(device, O_RDONLY);
123         int r;
124         if(fd < 0)
125                 return -EINVAL;
126         r = sector_size(fd);
127         close(fd);
128         return r;
129 }
130
131 ssize_t write_blockwise(int fd, void *orig_buf, size_t count)
132 {
133         void *hangover_buf, *hangover_buf_base = NULL;
134         void *buf, *buf_base = NULL;
135         int r, hangover, solid, bsize, alignment;
136         ssize_t ret = -1;
137
138         if ((bsize = sector_size(fd)) < 0)
139                 return bsize;
140
141         hangover = count % bsize;
142         solid = count - hangover;
143         alignment = get_alignment(fd);
144
145         if ((long)orig_buf & (alignment - 1)) {
146                 buf = aligned_malloc(&buf_base, count, alignment);
147                 if (!buf)
148                         goto out;
149                 memcpy(buf, orig_buf, count);
150         } else
151                 buf = orig_buf;
152
153         r = write(fd, buf, solid);
154         if (r < 0 || r != solid)
155                 goto out;
156
157         if (hangover) {
158                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
159                 if (!hangover_buf)
160                         goto out;
161
162                 r = read(fd, hangover_buf, bsize);
163                 if (r < 0 || r != bsize)
164                         goto out;
165
166                 r = lseek(fd, -bsize, SEEK_CUR);
167                 if (r < 0)
168                         goto out;
169                 memcpy(hangover_buf, (char*)buf + solid, hangover);
170
171                 r = write(fd, hangover_buf, bsize);
172                 if (r < 0 || r != bsize)
173                         goto out;
174         }
175         ret = count;
176 out:
177         free(hangover_buf_base);
178         if (buf != orig_buf)
179                 free(buf_base);
180         return ret;
181 }
182
183 ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
184         void *hangover_buf, *hangover_buf_base = NULL;
185         void *buf, *buf_base = NULL;
186         int r, hangover, solid, bsize, alignment;
187         ssize_t ret = -1;
188
189         if ((bsize = sector_size(fd)) < 0)
190                 return bsize;
191
192         hangover = count % bsize;
193         solid = count - hangover;
194         alignment = get_alignment(fd);
195
196         if ((long)orig_buf & (alignment - 1)) {
197                 buf = aligned_malloc(&buf_base, count, alignment);
198                 if (!buf)
199                         return -1;
200         } else
201                 buf = orig_buf;
202
203         r = read(fd, buf, solid);
204         if(r < 0 || r != solid)
205                 goto out;
206
207         if (hangover) {
208                 hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment);
209                 if (!hangover_buf)
210                         goto out;
211                 r = read(fd, hangover_buf, bsize);
212                 if (r <  0 || r != bsize)
213                         goto out;
214
215                 memcpy((char *)buf + solid, hangover_buf, hangover);
216         }
217         ret = count;
218 out:
219         free(hangover_buf_base);
220         if (buf != orig_buf) {
221                 memcpy(orig_buf, buf, count);
222                 free(buf_base);
223         }
224         return ret;
225 }
226
227 /*
228  * Combines llseek with blockwise write. write_blockwise can already deal with short writes
229  * but we also need a function to deal with short writes at the start. But this information
230  * is implicitly included in the read/write offset, which can not be set to non-aligned
231  * boundaries. Hence, we combine llseek with write.
232  */
233 ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) {
234         char *frontPadBuf;
235         void *frontPadBuf_base = NULL;
236         int r, bsize, frontHang;
237         size_t innerCount = 0;
238         ssize_t ret = -1;
239
240         if ((bsize = sector_size(fd)) < 0)
241                 return bsize;
242
243         frontHang = offset % bsize;
244
245         if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
246                 goto out;
247
248         if (frontHang) {
249                 frontPadBuf = aligned_malloc(&frontPadBuf_base,
250                                              bsize, get_alignment(fd));
251                 if (!frontPadBuf)
252                         goto out;
253
254                 r = read(fd, frontPadBuf, bsize);
255                 if (r < 0 || r != bsize)
256                         goto out;
257
258                 innerCount = bsize - frontHang;
259                 if (innerCount > count)
260                         innerCount = count;
261
262                 memcpy(frontPadBuf + frontHang, buf, innerCount);
263
264                 if (lseek(fd, offset - frontHang, SEEK_SET) < 0)
265                         goto out;
266
267                 r = write(fd, frontPadBuf, bsize);
268                 if (r < 0 || r != bsize)
269                         goto out;
270
271                 buf += innerCount;
272                 count -= innerCount;
273         }
274
275         ret = count ? write_blockwise(fd, buf, count) : 0;
276         if (ret >= 0)
277                 ret += innerCount;
278 out:
279         free(frontPadBuf_base);
280
281         return ret;
282 }
283
284 int device_ready(struct crypt_device *cd, const char *device, int mode)
285 {
286         int devfd, r = 0;
287         ssize_t s;
288         struct stat st;
289         char buf[512];
290
291         if(stat(device, &st) < 0) {
292                 log_err(cd, _("Device %s doesn't exist or access denied.\n"), device);
293                 return -EINVAL;
294         }
295
296         if (!S_ISBLK(st.st_mode))
297                 return -ENOTBLK;
298
299         log_dbg("Trying to open and read device %s.", device);
300         devfd = open(device, mode | O_DIRECT | O_SYNC);
301         if(devfd < 0) {
302                 log_err(cd, _("Cannot open device %s for %s%s access.\n"), device,
303                         (mode & O_EXCL) ? _("exclusive ") : "",
304                         (mode & O_RDWR) ? _("writable") : _("read-only"));
305                 return -EINVAL;
306         }
307
308          /* Try to read first sector */
309         s = read_blockwise(devfd, buf, sizeof(buf));
310         if (s < 0 || s != sizeof(buf)) {
311                 log_verbose(cd, _("Cannot read device %s.\n"), device);
312                 r = -EIO;
313         }
314
315         memset(buf, 0, sizeof(buf));
316         close(devfd);
317
318         return r;
319 }
320
321 int get_device_infos(const char *device,
322                      int open_exclusive,
323                      int *readonly,
324                      uint64_t *size)
325 {
326         struct stat st;
327         unsigned long size_small;
328         int fd, r = -1;
329         int flags = 0;
330
331         *readonly = 0;
332         *size = 0;
333
334         if (stat(device, &st) < 0)
335                 return -EINVAL;
336
337         /* never wipe header on mounted device */
338         if (open_exclusive && S_ISBLK(st.st_mode))
339                 flags |= O_EXCL;
340
341         /* Try to open read-write to check whether it is a read-only device */
342         fd = open(device, O_RDWR | flags);
343         if (fd == -1 && errno == EROFS) {
344                 *readonly = 1;
345                 fd = open(device, O_RDONLY | flags);
346         }
347
348         if (fd == -1 && open_exclusive && errno == EBUSY)
349                 return -EBUSY;
350
351         if (fd == -1)
352                 return -EINVAL;
353
354         /* If the device can be opened read-write, i.e. readonly is still 0, then
355          * check whether BKROGET says that it is read-only. E.g. read-only loop
356          * devices may be openend read-write but are read-only according to BLKROGET
357          */
358         if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
359                 goto out;
360
361         if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
362                 *size >>= SECTOR_SHIFT;
363                 r = 0;
364                 goto out;
365         }
366
367         if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) {
368                 *size = (uint64_t)size_small;
369                 r = 0;
370                 goto out;
371         }
372
373         r = -EINVAL;
374 out:
375         close(fd);
376         return r;
377 }
378
379 int device_check_and_adjust(struct crypt_device *cd,
380                             const char *device,
381                             int open_exclusive,
382                             uint64_t *size,
383                             uint64_t *offset,
384                             int *read_only)
385 {
386         int r, real_readonly;
387         uint64_t real_size;
388
389         if (!device)
390                 return -ENOTBLK;
391
392         r = get_device_infos(device, open_exclusive, &real_readonly, &real_size);
393         if (r < 0) {
394                 if (r == -EBUSY)
395                         log_err(cd, _("Cannot use device %s which is in use "
396                                       "(already mapped or mounted).\n"),
397                                       device);
398                 else
399                         log_err(cd, _("Cannot get info about device %s.\n"),
400                                 device);
401                 return r;
402         }
403
404         if (!*size) {
405                 *size = real_size;
406                 if (!*size) {
407                         log_err(cd, _("Device %s has zero size.\n"), device);
408                         return -ENOTBLK;
409                 }
410                 if (*size < *offset) {
411                         log_err(cd, _("Device %s is too small.\n"), device);
412                         return -EINVAL;
413                 }
414                 *size -= *offset;
415         }
416
417         if (real_readonly)
418                 *read_only = 1;
419
420         log_dbg("Calculated device size is %" PRIu64 " sectors (%s), offset %" PRIu64 ".",
421                 *size, *read_only ? "RO" : "RW", *offset);
422         return 0;
423 }
424
425 int wipe_device_header(const char *device, int sectors)
426 {
427         struct stat st;
428         char *buffer;
429         int size = sectors * SECTOR_SIZE;
430         int r = -1;
431         int devfd;
432         int flags = O_RDWR | O_DIRECT | O_SYNC;
433
434         if (stat(device, &st) < 0)
435                 return -EINVAL;
436
437         /* never wipe header on mounted device */
438         if (S_ISBLK(st.st_mode))
439                 flags |= O_EXCL;
440
441         devfd = open(device, flags);
442         if(devfd == -1)
443                 return errno == EBUSY ? -EBUSY : -EINVAL;
444
445         buffer = malloc(size);
446         if (!buffer) {
447                 close(devfd);
448                 return -ENOMEM;
449         }
450         memset(buffer, 0, size);
451
452         r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0;
453
454         free(buffer);
455         close(devfd);
456
457         return r;
458 }
459
460 /* MEMLOCK */
461 #define DEFAULT_PROCESS_PRIORITY -18
462
463 static int _priority;
464 static int _memlock_count = 0;
465
466 // return 1 if memory is locked
467 int crypt_memlock_inc(struct crypt_device *ctx)
468 {
469         if (!_memlock_count++) {
470                 log_dbg("Locking memory.");
471                 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
472                         log_err(ctx, _("WARNING!!! Possibly insecure memory. Are you root?\n"));
473                         _memlock_count--;
474                         return 0;
475                 }
476                 errno = 0;
477                 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
478                         log_err(ctx, _("Cannot get process priority.\n"));
479                 else
480                         if (setpriority(PRIO_PROCESS, 0, DEFAULT_PROCESS_PRIORITY))
481                                 log_err(ctx, _("setpriority %d failed: %s\n"),
482                                         DEFAULT_PROCESS_PRIORITY, strerror(errno));
483         }
484         return _memlock_count ? 1 : 0;
485 }
486
487 int crypt_memlock_dec(struct crypt_device *ctx)
488 {
489         if (_memlock_count && (!--_memlock_count)) {
490                 log_dbg("Unlocking memory.");
491                 if (munlockall() == -1)
492                         log_err(ctx, _("Cannot unlock memory.\n"));
493                 if (setpriority(PRIO_PROCESS, 0, _priority))
494                         log_err(ctx, _("setpriority %d failed: %s\n"), _priority, strerror(errno));
495         }
496         return _memlock_count ? 1 : 0;
497 }
498
499 /* DEVICE TOPOLOGY */
500
501 /* block device topology ioctls, introduced in 2.6.32 */
502 #ifndef BLKIOMIN
503 #define BLKIOMIN    _IO(0x12,120)
504 #define BLKIOOPT    _IO(0x12,121)
505 #define BLKALIGNOFF _IO(0x12,122)
506 #endif
507
508 void get_topology_alignment(const char *device,
509                             unsigned long *required_alignment, /* bytes */
510                             unsigned long *alignment_offset,   /* bytes */
511                             unsigned long default_alignment)
512 {
513         int dev_alignment_offset = 0;
514         unsigned int min_io_size = 0, opt_io_size = 0;
515         unsigned long temp_alignment = 0;
516         int fd;
517
518         *required_alignment = default_alignment;
519         *alignment_offset = 0;
520
521         fd = open(device, O_RDONLY);
522         if (fd == -1)
523                 return;
524
525         /* minimum io size */
526         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
527                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
528                         device, default_alignment);
529                 goto out;
530         }
531
532         /* optimal io size */
533         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
534                 opt_io_size = min_io_size;
535
536         /* alignment offset, bogus -1 means misaligned/unknown */
537         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
538                 dev_alignment_offset = 0;
539         *alignment_offset = (unsigned long)dev_alignment_offset;
540
541         temp_alignment = (unsigned long)min_io_size;
542
543         if (temp_alignment < (unsigned long)opt_io_size)
544                 temp_alignment = (unsigned long)opt_io_size;
545
546         /* If calculated alignment is multiple of default, keep default */
547         if (temp_alignment && (default_alignment % temp_alignment))
548                 *required_alignment = temp_alignment;
549
550         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
551                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
552 out:
553         (void)close(fd);
554 }