Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / lib / utils_blkid.c
1 /*
2  * blkid probe utilities
3  *
4  * Copyright (C) 2018-2023 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 <stdbool.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include "utils_blkid.h"
29 #include "utils_io.h"
30
31 #ifdef HAVE_BLKID
32 #include <blkid/blkid.h>
33 /* make bad checksums flag optional */
34 #ifndef BLKID_SUBLKS_BADCSUM
35 #define BLKID_SUBLKS_BADCSUM 0
36 #endif
37 struct blkid_handle {
38         int fd;
39         blkid_probe pr;
40 };
41 #ifndef HAVE_BLKID_WIPE
42 static size_t crypt_getpagesize(void)
43 {
44         long r = sysconf(_SC_PAGESIZE);
45         return r <= 0 ? 4096 : (size_t)r;
46 }
47 #endif
48 #endif
49
50 void blk_set_chains_for_wipes(struct blkid_handle *h)
51 {
52 #ifdef HAVE_BLKID
53         blkid_probe_enable_partitions(h->pr, 1);
54         blkid_probe_set_partitions_flags(h->pr, 0
55 #ifdef HAVE_BLKID_WIPE
56         | BLKID_PARTS_MAGIC
57 #endif
58         );
59
60         blkid_probe_enable_superblocks(h->pr, 1);
61         blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_LABEL   |
62                                                  BLKID_SUBLKS_UUID    |
63                                                  BLKID_SUBLKS_TYPE    |
64                                                  BLKID_SUBLKS_USAGE   |
65                                                  BLKID_SUBLKS_VERSION |
66                                                  BLKID_SUBLKS_MAGIC   |
67                                                  BLKID_SUBLKS_BADCSUM);
68 #endif
69 }
70
71 void blk_set_chains_for_full_print(struct blkid_handle *h)
72 {
73         blk_set_chains_for_wipes(h);
74 }
75
76 void blk_set_chains_for_superblocks(struct blkid_handle *h)
77 {
78 #ifdef HAVE_BLKID
79         blkid_probe_enable_superblocks(h->pr, 1);
80         blkid_probe_set_superblocks_flags(h->pr, BLKID_SUBLKS_TYPE);
81 #endif
82 }
83
84 void blk_set_chains_for_fast_detection(struct blkid_handle *h)
85 {
86 #ifdef HAVE_BLKID
87         blkid_probe_enable_partitions(h->pr, 1);
88         blkid_probe_set_partitions_flags(h->pr, 0);
89         blk_set_chains_for_superblocks(h);
90 #endif
91 }
92
93 int blk_init_by_path(struct blkid_handle **h, const char *path)
94 {
95         int r = -ENOTSUP;
96 #ifdef HAVE_BLKID
97         struct blkid_handle *tmp = malloc(sizeof(*tmp));
98         if (!tmp)
99                 return -ENOMEM;
100
101         tmp->fd = -1;
102
103         tmp->pr = blkid_new_probe_from_filename(path);
104         if (!tmp->pr) {
105                 free(tmp);
106                 return -EINVAL;
107         }
108
109         *h = tmp;
110
111         r = 0;
112 #endif
113         return r;
114 }
115
116 int blk_init_by_fd(struct blkid_handle **h, int fd)
117 {
118         int r = -ENOTSUP;
119 #ifdef HAVE_BLKID
120         struct blkid_handle *tmp = malloc(sizeof(*tmp));
121         if (!tmp)
122                 return -ENOMEM;
123
124         tmp->pr = blkid_new_probe();
125         if (!tmp->pr) {
126                 free(tmp);
127                 return -EINVAL;
128         }
129
130         if (blkid_probe_set_device(tmp->pr, fd, 0, 0)) {
131                 blkid_free_probe(tmp->pr);
132                 free(tmp);
133                 return -EINVAL;
134         }
135
136         tmp->fd = fd;
137
138         *h = tmp;
139
140         r = 0;
141 #endif
142         return r;
143 }
144
145 #ifdef HAVE_BLKID
146 static int blk_superblocks_luks(struct blkid_handle *h, bool enable)
147 {
148         char luks[] = "crypto_LUKS";
149         char *luks_filter[] = {
150                 luks,
151                 NULL
152         };
153         return blkid_probe_filter_superblocks_type(h->pr,
154                         enable ? BLKID_FLTR_ONLYIN : BLKID_FLTR_NOTIN,
155                         luks_filter);
156 }
157 #endif
158
159 int blk_superblocks_filter_luks(struct blkid_handle *h)
160 {
161         int r = -ENOTSUP;
162 #ifdef HAVE_BLKID
163         r = blk_superblocks_luks(h, false);
164 #endif
165         return r;
166 }
167
168 int blk_superblocks_only_luks(struct blkid_handle *h)
169 {
170         int r = -ENOTSUP;
171 #ifdef HAVE_BLKID
172         r = blk_superblocks_luks(h, true);
173 #endif
174         return r;
175 }
176
177 blk_probe_status blk_probe(struct blkid_handle *h)
178 {
179         blk_probe_status pr = PRB_FAIL;
180 #ifdef HAVE_BLKID
181         int r = blkid_do_probe(h->pr);
182
183         if (r == 0)
184                 pr = PRB_OK;
185         else if (r == 1)
186                 pr = PRB_EMPTY;
187 #endif
188         return pr;
189 }
190
191 blk_probe_status blk_safeprobe(struct blkid_handle *h)
192 {
193         int r = -1;
194 #ifdef HAVE_BLKID
195         r = blkid_do_safeprobe(h->pr);
196 #endif
197         switch (r) {
198         case -2:
199                 return PRB_AMBIGUOUS;
200         case 1:
201                 return PRB_EMPTY;
202         case 0:
203                 return PRB_OK;
204         default:
205                 return PRB_FAIL;
206         }
207 }
208
209 int blk_is_partition(struct blkid_handle *h)
210 {
211         int r = 0;
212 #ifdef HAVE_BLKID
213         r = blkid_probe_has_value(h->pr, "PTTYPE");
214 #endif
215         return r;
216 }
217
218 int blk_is_superblock(struct blkid_handle *h)
219 {
220         int r = 0;
221 #ifdef HAVE_BLKID
222         r = blkid_probe_has_value(h->pr, "TYPE");
223 #endif
224         return r;
225 }
226
227 const char *blk_get_partition_type(struct blkid_handle *h)
228 {
229         const char *value = NULL;
230 #ifdef HAVE_BLKID
231         (void) blkid_probe_lookup_value(h->pr, "PTTYPE", &value, NULL);
232 #endif
233         return value;
234 }
235
236 const char *blk_get_superblock_type(struct blkid_handle *h)
237 {
238         const char *value = NULL;
239 #ifdef HAVE_BLKID
240         (void) blkid_probe_lookup_value(h->pr, "TYPE", &value, NULL);
241 #endif
242         return value;
243 }
244
245 void blk_free(struct blkid_handle *h)
246 {
247 #ifdef HAVE_BLKID
248         if (!h)
249                 return;
250
251         if (h->pr)
252                 blkid_free_probe(h->pr);
253
254         free(h);
255 #endif
256 }
257
258 #ifdef HAVE_BLKID
259 #ifndef HAVE_BLKID_WIPE
260 static int blk_step_back(struct blkid_handle *h)
261 {
262 #ifdef HAVE_BLKID_STEP_BACK
263         return blkid_probe_step_back(h->pr);
264 #else
265         blkid_reset_probe(h->pr);
266         blkid_probe_set_device(h->pr, h->fd, 0, 0);
267         return 0;
268 #endif
269 }
270 #endif /* not HAVE_BLKID_WIPE */
271 #endif /* HAVE_BLKID */
272
273 int blk_do_wipe(struct blkid_handle *h)
274 {
275 #ifdef HAVE_BLKID
276 #ifdef HAVE_BLKID_WIPE
277         return blkid_do_wipe(h->pr, 0);
278 #else
279         const char *offset;
280         off_t offset_val;
281         void *buf;
282         ssize_t ret;
283         size_t alignment, len, bsize = blkid_probe_get_sectorsize(h->pr);
284
285         if (h->fd < 0 || !bsize)
286                 return -EINVAL;
287
288         if (blk_is_partition(h)) {
289                 if (blkid_probe_lookup_value(h->pr, "PTMAGIC_OFFSET", &offset, NULL))
290                         return -EINVAL;
291                 if (blkid_probe_lookup_value(h->pr, "PTMAGIC", NULL, &len))
292                         return -EINVAL;
293         } else if (blk_is_superblock(h)) {
294                 if (blkid_probe_lookup_value(h->pr, "SBMAGIC_OFFSET", &offset, NULL))
295                         return -EINVAL;
296                 if (blkid_probe_lookup_value(h->pr, "SBMAGIC", NULL, &len))
297                         return -EINVAL;
298         } else
299                 return 0;
300
301         alignment = crypt_getpagesize();
302
303         if (posix_memalign(&buf, alignment, len))
304                 return -EINVAL;
305         memset(buf, 0, len);
306
307         offset_val = strtoll(offset, NULL, 10);
308
309         /* TODO: missing crypt_wipe_fd() */
310         ret = write_lseek_blockwise(h->fd, bsize, alignment, buf, len, offset_val);
311         free(buf);
312         if (ret < 0)
313                 return -EIO;
314
315         if ((size_t)ret == len) {
316                 blk_step_back(h);
317                 return 0;
318         }
319
320         return -EIO;
321 #endif
322 #else /* HAVE_BLKID */
323         return -ENOTSUP;
324 #endif
325 }
326
327 int blk_supported(void)
328 {
329         int r = 0;
330 #ifdef HAVE_BLKID
331         r = 1;
332 #endif
333         return r;
334 }
335
336 unsigned blk_get_block_size(struct blkid_handle *h)
337 {
338         unsigned block_size = 0;
339 #ifdef HAVE_BLKID
340         const char *data;
341         if (!blk_is_superblock(h) || !blkid_probe_has_value(h->pr, "BLOCK_SIZE") ||
342             blkid_probe_lookup_value(h->pr, "BLOCK_SIZE", &data, NULL) ||
343             sscanf(data, "%u", &block_size) != 1)
344                 block_size = 0;
345 #endif
346         return block_size;
347 }