428aa1260d714a8739bbf1562e8ffc369c9eb197
[platform/upstream/cryptsetup.git] / lib / utils_device.c
1 /*
2  * device backend utilities
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  * Copyright (C) 2009-2012, Milan Broz
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * version 2 as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/ioctl.h>
30 #include <linux/fs.h>
31 #include <unistd.h>
32 #include "internal.h"
33
34 struct device {
35         char *path;
36
37         char *file_path;
38         int loop_fd;
39
40         int init_done:1;
41 };
42
43 static int device_ready(const char *device)
44 {
45         int devfd, r = 0;
46         struct stat st;
47
48         log_dbg("Trying to open and read device %s.", device);
49         devfd = open(device, O_RDONLY | O_DIRECT | O_SYNC);
50         if (devfd < 0) {
51                 log_err(NULL, _("Device %s doesn't exist or access denied.\n"), device);
52                 return -EINVAL;
53         }
54         if (fstat(devfd, &st) < 0)
55                 r = -EINVAL;
56         else if (!S_ISBLK(st.st_mode))
57                 r = S_ISREG(st.st_mode) ? -ENOTBLK : -EINVAL;
58
59         close(devfd);
60         return r;
61 }
62
63 int device_alloc(struct device **device, const char *path)
64 {
65         struct device *dev;
66         int r;
67
68         if (!path) {
69                 *device = NULL;
70                 return 0;
71         }
72
73         dev = malloc(sizeof(struct device));
74         if (!dev)
75                 return -ENOMEM;
76
77         memset(dev, 0, sizeof(struct device));
78         dev->loop_fd = -1;
79
80         r = device_ready(path);
81         if (!r) {
82                 dev->init_done = 1;
83         } else if (r == -ENOTBLK) {
84                 /* alloc loop later */
85         } else if (r < 0) {
86                 free(dev);
87                 return -ENOTBLK;
88         }
89
90         dev->path = strdup(path);
91         if (!dev->path) {
92                 free(dev);
93                 return -ENOMEM;
94         }
95
96         *device = dev;
97         return 0;
98 }
99
100 void device_free(struct device *device)
101 {
102         if (!device)
103                 return;
104
105         if (device->loop_fd != -1) {
106                 log_dbg("Closed loop %s (%s).", device->path, device->file_path);
107                 close(device->loop_fd);
108         }
109
110         free(device->file_path);
111         free(device->path);
112         free(device);
113 }
114
115 /* Get block device path */
116 const char *device_block_path(const struct device *device)
117 {
118         if (!device || !device->init_done)
119                 return NULL;
120
121         return device->path;
122 }
123
124 /* Get path to device / file */
125 const char *device_path(const struct device *device)
126 {
127         if (!device)
128                 return NULL;
129
130         if (device->file_path)
131                 return device->file_path;
132
133         return device->path;
134 }
135
136 /* block device topology ioctls, introduced in 2.6.32 */
137 #ifndef BLKIOMIN
138 #define BLKIOMIN    _IO(0x12,120)
139 #define BLKIOOPT    _IO(0x12,121)
140 #define BLKALIGNOFF _IO(0x12,122)
141 #endif
142
143 void device_topology_alignment(struct device *device,
144                             unsigned long *required_alignment, /* bytes */
145                             unsigned long *alignment_offset,   /* bytes */
146                             unsigned long default_alignment)
147 {
148         int dev_alignment_offset = 0;
149         unsigned int min_io_size = 0, opt_io_size = 0;
150         unsigned long temp_alignment = 0;
151         int fd;
152
153         *required_alignment = default_alignment;
154         *alignment_offset = 0;
155
156         if (!device || !device->path) //FIXME
157                 return;
158
159         fd = open(device->path, O_RDONLY);
160         if (fd == -1)
161                 return;
162
163         /* minimum io size */
164         if (ioctl(fd, BLKIOMIN, &min_io_size) == -1) {
165                 log_dbg("Topology info for %s not supported, using default offset %lu bytes.",
166                         device->path, default_alignment);
167                 goto out;
168         }
169
170         /* optimal io size */
171         if (ioctl(fd, BLKIOOPT, &opt_io_size) == -1)
172                 opt_io_size = min_io_size;
173
174         /* alignment offset, bogus -1 means misaligned/unknown */
175         if (ioctl(fd, BLKALIGNOFF, &dev_alignment_offset) == -1 || dev_alignment_offset < 0)
176                 dev_alignment_offset = 0;
177         *alignment_offset = (unsigned long)dev_alignment_offset;
178
179         temp_alignment = (unsigned long)min_io_size;
180
181         if (temp_alignment < (unsigned long)opt_io_size)
182                 temp_alignment = (unsigned long)opt_io_size;
183
184         /* If calculated alignment is multiple of default, keep default */
185         if (temp_alignment && (default_alignment % temp_alignment))
186                 *required_alignment = temp_alignment;
187
188         log_dbg("Topology: IO (%u/%u), offset = %lu; Required alignment is %lu bytes.",
189                 min_io_size, opt_io_size, *alignment_offset, *required_alignment);
190 out:
191         (void)close(fd);
192 }
193
194 int device_block_size(struct device *device)
195 {
196         struct stat st;
197         int fd, bsize = 0, r = -EINVAL;
198
199         if (!device)
200                 return 0;
201
202         fd = open(device->path, O_RDONLY);
203         if(fd < 0)
204                 return -EINVAL;
205
206         if (fstat(fd, &st) < 0)
207                 goto out;
208
209         if (S_ISREG(st.st_mode)) {
210                 r = (int)crypt_getpagesize();
211                 goto out;
212         }
213
214         if (ioctl(fd, BLKSSZGET, &bsize) >= 0)
215                 r = bsize;
216 out:
217         close(fd);
218         return r;
219 }
220
221 int device_read_ahead(struct device *device, uint32_t *read_ahead)
222 {
223         int fd, r = 0;
224         long read_ahead_long;
225
226         if (!device)
227                 return 0;
228
229         if ((fd = open(device->path, O_RDONLY)) < 0)
230                 return 0;
231
232         r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1;
233         close(fd);
234
235         if (r)
236                 *read_ahead = (uint32_t) read_ahead_long;
237
238         return r;
239 }
240
241 /* Get data size in bytes */
242 int device_size(struct device *device, uint64_t *size)
243 {
244         struct stat st;
245         int devfd, r = -EINVAL;
246
247         devfd = open(device->path, O_RDONLY);
248         if(devfd == -1)
249                 return -EINVAL;
250
251         if (fstat(devfd, &st) < 0)
252                 goto out;
253
254         if (S_ISREG(st.st_mode)) {
255                 *size = (uint64_t)st.st_size;
256                 r = 0;
257         } else if (ioctl(devfd, BLKGETSIZE64, size) >= 0)
258                 r = 0;
259 out:
260         close(devfd);
261         return r;
262 }
263
264 static int device_info(struct device *device,
265                         enum devcheck device_check,
266                         int *readonly, uint64_t *size)
267 {
268         struct stat st;
269         int fd, r = -EINVAL, flags = 0;
270
271         *readonly = 0;
272         *size = 0;
273
274         if (stat(device->path, &st) < 0)
275                 return -EINVAL;
276
277         /* never wipe header on mounted device */
278         if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
279                 flags |= O_EXCL;
280
281         /* Try to open read-write to check whether it is a read-only device */
282         /* coverity[toctou] */
283         fd = open(device->path, O_RDWR | flags);
284         if (fd == -1 && errno == EROFS) {
285                 *readonly = 1;
286                 fd = open(device->path, O_RDONLY | flags);
287         }
288
289         if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
290                 return -EBUSY;
291
292         if (fd == -1)
293                 return -EINVAL;
294
295         if (S_ISREG(st.st_mode)) {
296                 //FIXME: add readonly check
297                 *size = (uint64_t)st.st_size;
298                 *size >>= SECTOR_SHIFT;
299         } else {
300                 /* If the device can be opened read-write, i.e. readonly is still 0, then
301                  * check whether BKROGET says that it is read-only. E.g. read-only loop
302                  * devices may be openend read-write but are read-only according to BLKROGET
303                  */
304                 if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
305                         goto out;
306
307                 if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
308                         *size >>= SECTOR_SHIFT;
309                         r = 0;
310                         goto out;
311                 }
312         }
313         r = -EINVAL;
314 out:
315         close(fd);
316         return r;
317 }
318
319 static int device_internal_prepare(struct crypt_device *cd, struct device *device)
320 {
321         char *loop_device;
322         int r, loop_fd, readonly = 0;
323
324         if (device->init_done)
325                 return 0;
326
327         log_dbg("Allocating a free loop device.");
328         loop_device = crypt_loop_get_device();
329         if (!loop_device) {
330                 if (getuid() || geteuid())
331                         log_err(cd, _("Cannot use a loopback device, "
332                                       "running as non-root user.\n"));
333                 else
334                         log_err(cd, _("Cannot find a free loopback device.\n"));
335                 return -ENOTSUP;
336         }
337
338         /* Keep the loop open, dettached on last close. */
339         loop_fd = crypt_loop_attach(loop_device, device->path, 0, 1, &readonly);
340         if (loop_fd == -1) {
341                 log_err(cd, _("Attaching loopback device failed "
342                         "(loop device with autoclear flag is required).\n"));
343                 free(loop_device);
344                 return -EINVAL;
345         }
346
347         r = device_ready(loop_device);
348         if (r < 0) {
349                 free(loop_device);
350                 return r;
351         }
352
353         device->loop_fd = loop_fd;
354         device->file_path = device->path;
355         device->path = loop_device;
356         device->init_done = 1;
357
358         return 0;
359 }
360
361 int device_block_adjust(struct crypt_device *cd,
362                         struct device *device,
363                         enum devcheck device_check,
364                         uint64_t device_offset,
365                         uint64_t *size,
366                         uint32_t *flags)
367 {
368         int r, real_readonly;
369         uint64_t real_size;
370
371         if (!device)
372                 return -ENOTBLK;
373
374         r = device_internal_prepare(cd, device);
375         if (r)
376                 return r;
377
378         r = device_info(device, device_check, &real_readonly, &real_size);
379         if (r < 0) {
380                 if (r == -EBUSY)
381                         log_err(cd, _("Cannot use device %s which is in use "
382                                       "(already mapped or mounted).\n"),
383                                       device->path);
384                 else
385                         log_err(cd, _("Cannot get info about device %s.\n"),
386                                 device->path);
387                 return r;
388         }
389
390         if (device_offset >= real_size) {
391                 log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
392                         device->path);
393                 return -EINVAL;
394         }
395
396         if (size && !*size) {
397                 *size = real_size;
398                 if (!*size) {
399                         log_err(cd, _("Device %s has zero size.\n"), device->path);
400                         return -ENOTBLK;
401                 }
402                 *size -= device_offset;
403         }
404
405         /* in case of size is set by parameter */
406         if (size && ((real_size - device_offset) < *size)) {
407                 log_dbg("Device %s: offset = %" PRIu64 " requested size = %" PRIu64
408                         ", backing device size = %" PRIu64,
409                         device->path, device_offset, *size, real_size);
410                 log_err(cd, _("Device %s is too small.\n"), device->path);
411                 return -EINVAL;
412         }
413
414         if (flags && real_readonly)
415                 *flags |= CRYPT_ACTIVATE_READONLY;
416
417         if (size)
418                 log_dbg("Calculated device size is %" PRIu64" sectors (%s), offset %" PRIu64 ".",
419                 *size, real_readonly ? "RO" : "RW", device_offset);
420         return 0;
421 }
422
423 size_t size_round_up(size_t size, unsigned int block)
424 {
425         size_t s = (size + (block - 1)) / block;
426         return s * block;
427 }