0e3e7fd4b820e51e8a02e7c1a44690bcab479922
[platform/upstream/cryptsetup.git] / lib / utils_blkid.c
1 /*
2  * blkid probe utilities
3  *
4  * Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "utils_blkid.h"
28 #include "utils_io.h"
29
30 #ifdef HAVE_BLKID
31 #include <blkid/blkid.h>
32 /* make bad checksums flag optional */
33 #ifndef BLKID_SUBLKS_BADCSUM
34 #define BLKID_SUBLKS_BADCSUM 0
35 #endif
36 struct blkid_handle {
37         int fd;
38         blkid_probe pr;
39 };
40 #ifndef HAVE_BLKID_WIPE
41 static size_t crypt_getpagesize(void)
42 {
43         long r = sysconf(_SC_PAGESIZE);
44         return r <= 0 ? 4096 : (size_t)r;
45 }
46 #endif
47 #endif
48
49 void blk_set_chains_for_wipes(struct blkid_handle *h)
50 {
51 #ifdef HAVE_BLKID
52         blkid_probe_enable_partitions(h->pr, 1);
53         blkid_probe_set_partitions_flags(h->pr, 0
54 #ifdef HAVE_BLKID_WIPE
55         | BLKID_PARTS_MAGIC
56 #endif
57         );
58
59         blkid_probe_enable_superblocks(h->pr, 1);
60         blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_LABEL   |
61                                                  BLKID_SUBLKS_UUID    |
62                                                  BLKID_SUBLKS_TYPE    |
63                                                  BLKID_SUBLKS_USAGE   |
64                                                  BLKID_SUBLKS_VERSION |
65                                                  BLKID_SUBLKS_MAGIC   |
66                                                  BLKID_SUBLKS_BADCSUM);
67 #endif
68 }
69
70 void blk_set_chains_for_full_print(struct blkid_handle *h)
71 {
72         blk_set_chains_for_wipes(h);
73 }
74
75 void blk_set_chains_for_fast_detection(struct blkid_handle *h)
76 {
77 #ifdef HAVE_BLKID
78         blkid_probe_enable_partitions(h->pr, 1);
79         blkid_probe_set_partitions_flags(h->pr, 0);
80
81         blkid_probe_enable_superblocks(h->pr, 1);
82         blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
83 #endif
84 }
85
86 int blk_init_by_path(struct blkid_handle **h, const char *path)
87 {
88         int r = -ENOTSUP;
89 #ifdef HAVE_BLKID
90         struct blkid_handle *tmp = malloc(sizeof(*tmp));
91         if (!tmp)
92                 return -ENOMEM;
93
94         tmp->fd = -1;
95
96         tmp->pr = blkid_new_probe_from_filename(path);
97         if (!tmp->pr) {
98                 free(tmp);
99                 return -EINVAL;
100         }
101
102         *h = tmp;
103
104         r = 0;
105 #endif
106         return r;
107 }
108
109 int blk_init_by_fd(struct blkid_handle **h, int fd)
110 {
111         int r = -ENOTSUP;
112 #ifdef HAVE_BLKID
113         struct blkid_handle *tmp = malloc(sizeof(*tmp));
114         if (!tmp)
115                 return -ENOMEM;
116
117         tmp->pr = blkid_new_probe();
118         if (!tmp->pr) {
119                 free(tmp);
120                 return -EINVAL;
121         }
122
123         if (blkid_probe_set_device(tmp->pr, fd, 0, 0)) {
124                 blkid_free_probe(tmp->pr);
125                 free(tmp);
126                 return -EINVAL;
127         }
128
129         tmp->fd = fd;
130
131         *h = tmp;
132
133         r = 0;
134 #endif
135         return r;
136 }
137
138 int blk_superblocks_filter_luks(struct blkid_handle *h)
139 {
140         int r = -ENOTSUP;
141 #ifdef HAVE_BLKID
142         char luks[] = "crypto_LUKS";
143         char *luks_filter[] = {
144                 luks,
145                 NULL
146         };
147         r = blkid_probe_filter_superblocks_type(h->pr, BLKID_FLTR_NOTIN, luks_filter);
148 #endif
149         return r;
150 }
151
152 blk_probe_status blk_probe(struct blkid_handle *h)
153 {
154         blk_probe_status pr = PRB_FAIL;
155 #ifdef HAVE_BLKID
156         int r = blkid_do_probe(h->pr);
157
158         if (r == 0)
159                 pr = PRB_OK;
160         else if (r == 1)
161                 pr = PRB_EMPTY;
162 #endif
163         return pr;
164 }
165
166 blk_probe_status blk_safeprobe(struct blkid_handle *h)
167 {
168         int r = -1;
169 #ifdef HAVE_BLKID
170         r = blkid_do_safeprobe(h->pr);
171 #endif
172         switch (r) {
173         case -2:
174                 return PRB_AMBIGUOUS;
175         case 1:
176                 return PRB_EMPTY;
177         case 0:
178                 return PRB_OK;
179         default:
180                 return PRB_FAIL;
181         }
182 }
183
184 int blk_is_partition(struct blkid_handle *h)
185 {
186         int r = 0;
187 #ifdef HAVE_BLKID
188         r = blkid_probe_has_value(h->pr, "PTTYPE");
189 #endif
190         return r;
191 }
192
193 int blk_is_superblock(struct blkid_handle *h)
194 {
195         int r = 0;
196 #ifdef HAVE_BLKID
197         r = blkid_probe_has_value(h->pr, "TYPE");
198 #endif
199         return r;
200 }
201
202 const char *blk_get_partition_type(struct blkid_handle *h)
203 {
204         const char *value = NULL;
205 #ifdef HAVE_BLKID
206         (void) blkid_probe_lookup_value(h->pr, "PTTYPE", &value, NULL);
207 #endif
208         return value;
209 }
210
211 const char *blk_get_superblock_type(struct blkid_handle *h)
212 {
213         const char *value = NULL;
214 #ifdef HAVE_BLKID
215         (void) blkid_probe_lookup_value(h->pr, "TYPE", &value, NULL);
216 #endif
217         return value;
218 }
219
220 void blk_free(struct blkid_handle *h)
221 {
222 #ifdef HAVE_BLKID
223         if (!h)
224                 return;
225
226         if (h->pr)
227                 blkid_free_probe(h->pr);
228
229         free(h);
230 #endif
231 }
232
233 #ifdef HAVE_BLKID
234 #ifndef HAVE_BLKID_WIPE
235 static int blk_step_back(struct blkid_handle *h)
236 {
237 #ifdef HAVE_BLKID_STEP_BACK
238         return blkid_probe_step_back(h->pr);
239 #else
240         blkid_reset_probe(h->pr);
241         blkid_probe_set_device(h->pr, h->fd, 0, 0);
242         return 0;
243 #endif
244 }
245 #endif /* not HAVE_BLKID_WIPE */
246 #endif /* HAVE_BLKID */
247
248 int blk_do_wipe(struct blkid_handle *h)
249 {
250 #ifdef HAVE_BLKID
251 #ifdef HAVE_BLKID_WIPE
252         return blkid_do_wipe(h->pr, 0);
253 #else
254         const char *offset;
255         off_t offset_val;
256         void *buf;
257         ssize_t ret;
258         size_t alignment, len, bsize = blkid_probe_get_sectorsize(h->pr);
259
260         if (h->fd < 0 || !bsize)
261                 return -EINVAL;
262
263         if (blk_is_partition(h)) {
264                 if (blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
265                         return -EINVAL;
266                 if (blkid_probe_lookup_value(h->pr, "PTMAGIC", NULL, &len))
267                         return -EINVAL;
268         } else if (blk_is_superblock(h)) {
269                 if (blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
270                         return -EINVAL;
271                 if (blkid_probe_lookup_value(h->pr, "SBMAGIC", NULL, &len))
272                         return -EINVAL;
273         } else
274                 return 0;
275
276         alignment = crypt_getpagesize();
277
278         if (posix_memalign(&buf, alignment, len))
279                 return -EINVAL;
280         memset(buf, 0, len);
281
282         offset_val = strtoll(offset, NULL, 10);
283
284         /* TODO: missing crypt_wipe_fd() */
285         ret = write_lseek_blockwise(h->fd, bsize, alignment, buf, len, offset_val);
286         free(buf);
287         if (ret < 0)
288                 return -EIO;
289
290         if ((size_t)ret == len) {
291                 blk_step_back(h);
292                 return 0;
293         }
294
295         return -EIO;
296 #endif
297 #else /* HAVE_BLKID */
298         return -ENOTSUP;
299 #endif
300 }
301
302 int blk_supported(void)
303 {
304         int r = 0;
305 #ifdef HAVE_BLKID
306         r = 1;
307 #endif
308         return r;
309 }
310
311 off_t blk_get_offset(struct blkid_handle *h)
312 {
313         off_t offset_value = -1;
314 #ifdef HAVE_BLKID
315         const char *offset;
316         if (blk_is_superblock(h)) {
317                 if (!blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
318                         offset_value = strtoll(offset, NULL, 10);
319         } else if (blk_is_partition(h) && !blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
320                 offset_value = strtoll(offset, NULL, 10);
321 #endif
322         return offset_value;
323 }