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