]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/blkid/src/probe.c
blkid: fix "hangs forever with partition type mdraid"
[thirdparty/util-linux.git] / shlibs / blkid / src / probe.c
CommitLineData
a0948ffe 1/*
51410fc6 2 * probe.c - reads tags (LABEL, UUID, FS type, ..) from a block device
a0948ffe 3 *
51410fc6 4 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
a0948ffe 5 *
a0948ffe
KZ
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
a0948ffe
KZ
8 */
9
10#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <ctype.h>
16#include <sys/types.h>
17#ifdef HAVE_SYS_STAT_H
18#include <sys/stat.h>
19#endif
20#ifdef HAVE_SYS_MKDEV_H
21#include <sys/mkdev.h>
22#endif
a0948ffe
KZ
23#ifdef HAVE_ERRNO_H
24#include <errno.h>
25#endif
51410fc6
KZ
26#include <stdint.h>
27#ifdef HAVE_LIBUUID
28#include <uuid/uuid.h>
29#endif
30#include <stdarg.h>
a0948ffe 31
dc61d909 32#include "blkdev.h"
51410fc6
KZ
33#include "blkidP.h"
34#include "probers/probers.h"
a0948ffe 35
51410fc6 36static const struct blkid_idinfo *idinfos[] =
a0948ffe 37{
3402fff1
KZ
38 /* RAIDs */
39 &linuxraid_idinfo,
f8504a4e 40 &ddfraid_idinfo,
56ad7426 41 &iswraid_idinfo,
dc61d909 42 &lsiraid_idinfo,
3402fff1
KZ
43 &viaraid_idinfo,
44 &silraid_idinfo,
e86961ba 45 &nvraid_idinfo,
b9938904 46 &pdcraid_idinfo,
5784db20
KZ
47 &highpoint45x_idinfo,
48 &highpoint37x_idinfo,
3402fff1
KZ
49 &adraid_idinfo,
50 &jmraid_idinfo,
51 &lvm2_idinfo,
f19f9872 52 &lvm1_idinfo,
06da6d00 53 &luks_idinfo,
3402fff1
KZ
54
55 /* Filesystems */
56 &vfat_idinfo,
57 &swsuspend_idinfo,
58 &swap_idinfo,
59 &xfs_idinfo,
8e7e30e4
KZ
60 &ext4dev_idinfo,
61 &ext4_idinfo,
62 &ext3_idinfo,
63 &ext2_idinfo,
3402fff1
KZ
64 &jbd_idinfo,
65 &reiser_idinfo,
66 &reiser4_idinfo,
80f26373 67 &jfs_idinfo,
3402fff1
KZ
68 &udf_idinfo,
69 &iso9660_idinfo,
1f4da8d2 70 &zfs_idinfo,
3402fff1
KZ
71 &hfsplus_idinfo,
72 &hfs_idinfo,
83b935ae 73 &ufs_idinfo,
e134f470 74 &hpfs_idinfo,
d1e9e1e4
KZ
75 &sysv_idinfo,
76 &xenix_idinfo,
3402fff1
KZ
77 &ntfs_idinfo,
78 &cramfs_idinfo,
79 &romfs_idinfo,
681ff570 80 &minix_idinfo,
81f81873
KZ
81 &gfs_idinfo,
82 &gfs2_idinfo,
7fd65bed
KZ
83 &ocfs_idinfo,
84 &ocfs2_idinfo,
85 &oracleasm_idinfo,
c29368b4 86 &vxfs_idinfo,
fc954eb5 87 &squashfs_idinfo,
990b429a
KZ
88 &netware_idinfo,
89 &btrfs_idinfo
51410fc6 90};
a0948ffe 91
51410fc6
KZ
92#ifndef ARRAY_SIZE
93# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
94#endif
a0948ffe 95
51410fc6
KZ
96/* filter bitmap macros */
97#define blkid_bmp_wordsize (8 * sizeof(unsigned long))
98#define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize))
99#define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize)
a0948ffe 100
51410fc6
KZ
101#define blkid_bmp_set_item(bmp, item) \
102 ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item))
a0948ffe 103
51410fc6
KZ
104#define blkid_bmp_unset_item(bmp, item) \
105 ((bmp)[ bmp_idx_byte(item) ] &= ~bmp_idx_bit(item))
a0948ffe 106
51410fc6
KZ
107#define blkid_bmp_get_item(bmp, item) \
108 ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item))
a0948ffe 109
51410fc6
KZ
110#define blkid_bmp_size(max_items) \
111 (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize)
a0948ffe 112
51410fc6
KZ
113#define BLKID_FLTR_ITEMS ARRAY_SIZE(idinfos)
114#define BLKID_FLTR_SIZE blkid_bmp_size(BLKID_FLTR_ITEMS)
a0948ffe 115
a0948ffe 116
51410fc6 117static int blkid_probe_set_usage(blkid_probe pr, int usage);
a0948ffe 118
51410fc6 119int blkid_known_fstype(const char *fstype)
a0948ffe 120{
51410fc6 121 int i;
a0948ffe 122
51410fc6
KZ
123 if (!fstype)
124 return 0;
a0948ffe 125
51410fc6
KZ
126 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
127 const struct blkid_idinfo *id = idinfos[i];
128 if (strcmp(id->name, fstype) == 0)
129 return 1;
130 }
131 return 0;
a0948ffe
KZ
132}
133
134/*
51410fc6 135 * Returns a pointer to the newly allocated probe struct
a0948ffe 136 */
51410fc6 137blkid_probe blkid_new_probe(void)
a0948ffe 138{
7a458332 139 blkid_init_debug(0);
51410fc6 140 return calloc(1, sizeof(struct blkid_struct_probe));
a0948ffe
KZ
141}
142
143/*
51410fc6
KZ
144 * Deallocates probe struct, buffers and all allocated
145 * data that are associated with this probing control struct.
a0948ffe 146 */
51410fc6 147void blkid_free_probe(blkid_probe pr)
a0948ffe 148{
51410fc6
KZ
149 if (!pr)
150 return;
151 free(pr->fltr);
152 free(pr->buf);
153 free(pr->sbbuf);
154 free(pr);
a0948ffe
KZ
155}
156
51410fc6 157static void blkid_probe_reset_vals(blkid_probe pr)
a0948ffe 158{
51410fc6
KZ
159 memset(pr->vals, 0, sizeof(pr->vals));
160 pr->nvals = 0;
a0948ffe
KZ
161}
162
4ce48a97
KZ
163static void blkid_probe_reset_idx(blkid_probe pr)
164{
165 pr->idx = -1;
166}
167
51410fc6 168void blkid_reset_probe(blkid_probe pr)
a0948ffe 169{
51410fc6
KZ
170 if (!pr)
171 return;
6644688a 172 DBG(DEBUG_LOWPROBE, printf("reseting blkid_probe\n"));
51410fc6
KZ
173 if (pr->buf)
174 memset(pr->buf, 0, pr->buf_max);
175 pr->buf_off = 0;
176 pr->buf_len = 0;
177 if (pr->sbbuf)
178 memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
179 pr->sbbuf_len = 0;
180 blkid_probe_reset_vals(pr);
4ce48a97 181 blkid_probe_reset_idx(pr);
a0948ffe
KZ
182}
183
51410fc6
KZ
184/*
185 * Note that we have two offsets:
186 *
187 * 1/ general device offset (pr->off), that's useful for example when we
188 * probe a partition from whole disk image:
189 * blkid-low --offset <partition_position> disk.img
190 *
191 * 2/ buffer offset (the 'off' argument), that useful for offsets in
192 * superbloks, ...
193 *
194 * That means never use lseek(fd, 0, SEEK_SET), the zero position is always
195 * pr->off, so lseek(fd, pr->off, SEEK_SET).
196 *
197 */
198unsigned char *blkid_probe_get_buffer(blkid_probe pr,
199 blkid_loff_t off, blkid_loff_t len)
a0948ffe 200{
51410fc6 201 ssize_t ret_read = 0;
a0948ffe 202
4884729a
KZ
203 if (off < 0 || len < 0) {
204 DBG(DEBUG_LOWPROBE,
205 printf("unexpected offset or length of buffer requested\n"));
206 return NULL;
207 }
51410fc6
KZ
208 if (off + len <= BLKID_SB_BUFSIZ) {
209 if (!pr->sbbuf) {
210 pr->sbbuf = malloc(BLKID_SB_BUFSIZ);
211 if (!pr->sbbuf)
212 return NULL;
213 }
214 if (!pr->sbbuf_len) {
215 if (lseek(pr->fd, pr->off, SEEK_SET) < 0)
216 return NULL;
217 ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ);
218 if (ret_read < 0)
219 ret_read = 0;
220 pr->sbbuf_len = ret_read;
221 }
222 if (off + len > pr->sbbuf_len)
223 return NULL;
224 return pr->sbbuf + off;
225 } else {
226 unsigned char *newbuf = NULL;
227
228 if (len > pr->buf_max) {
229 newbuf = realloc(pr->buf, len);
230 if (!newbuf)
231 return NULL;
232 pr->buf = newbuf;
233 pr->buf_max = len;
234 pr->buf_off = 0;
235 pr->buf_len = 0;
236 }
237 if (newbuf || off < pr->buf_off ||
238 off + len > pr->buf_off + pr->buf_len) {
239
240 if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0)
241 return NULL;
242
243 ret_read = read(pr->fd, pr->buf, len);
244 if (ret_read != (ssize_t) len)
245 return NULL;
246 pr->buf_off = off;
247 pr->buf_len = len;
248 }
249 return off ? pr->buf + (off - pr->buf_off) : pr->buf;
250 }
a0948ffe
KZ
251}
252
51410fc6
KZ
253/*
254 * Assignes the device to probe control struct, resets internal buffers and
255 * reads 512 bytes from device to the buffers.
256 *
257 * Returns -1 in case of failure, or 0 on success.
258 */
259int blkid_probe_set_device(blkid_probe pr, int fd,
260 blkid_loff_t off, blkid_loff_t size)
a0948ffe 261{
51410fc6
KZ
262 if (!pr)
263 return -1;
a0948ffe 264
51410fc6 265 blkid_reset_probe(pr);
a0948ffe 266
51410fc6
KZ
267 pr->fd = fd;
268 pr->off = off;
bb6c6673 269 pr->size = 0;
dc61d909 270
bb6c6673 271 if (size)
dc61d909 272 pr->size = size;
bb6c6673
KZ
273 else {
274 struct stat sb;
275
276 if (fstat(fd, &sb))
277 return -1;
278
279 if (S_ISBLK(sb.st_mode))
280 blkdev_get_size(fd, (unsigned long long *) &pr->size);
281 else
282 pr->size = sb.st_size;
283 }
284 if (!pr->size)
285 return -1;
a0948ffe 286
51410fc6 287 /* read SB to test if the device is readable */
6644688a
KZ
288 if (!blkid_probe_get_buffer(pr, 0, 0x200)) {
289 DBG(DEBUG_LOWPROBE,
290 printf("failed to prepare a device for low-probing\n"));
51410fc6 291 return -1;
6644688a 292 }
a0948ffe 293
bb6c6673
KZ
294 DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
295 pr->off, pr->size));
a0948ffe
KZ
296 return 0;
297}
298
51410fc6 299int blkid_probe_set_request(blkid_probe pr, int flags)
a0948ffe 300{
51410fc6
KZ
301 if (!pr)
302 return -1;
303 pr->probreq = flags;
a0948ffe
KZ
304 return 0;
305}
306
51410fc6 307int blkid_probe_reset_filter(blkid_probe pr)
a0948ffe 308{
51410fc6
KZ
309 if (!pr)
310 return -1;
311 if (pr->fltr)
312 memset(pr->fltr, 0, BLKID_FLTR_SIZE * sizeof(unsigned long));
4ce48a97 313 blkid_probe_reset_idx(pr);
a0948ffe
KZ
314 return 0;
315}
316
51410fc6
KZ
317/*
318 * flag:
319 *
320 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN names[]
321 *
322 * BLKID_FLTR_ONLYIN - probe filesystem which are IN names[]
323 */
324int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[])
a0948ffe 325{
51410fc6 326 int i;
a0948ffe 327
51410fc6
KZ
328 if (!pr || !names)
329 return -1;
4ce48a97 330 if (!pr->fltr) {
51410fc6 331 pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
4ce48a97
KZ
332 blkid_probe_reset_idx(pr);
333 } else
51410fc6 334 blkid_probe_reset_filter(pr);
a0948ffe 335
deedaa30
KZ
336 if (!pr->fltr)
337 return -1;
338
51410fc6
KZ
339 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
340 int has = 0;
341 const struct blkid_idinfo *id = idinfos[i];
342 char **n;
a0948ffe 343
51410fc6
KZ
344 for (n = names; *n; n++) {
345 if (!strcmp(id->name, *n)) {
346 has = 1;
a0948ffe 347 break;
51410fc6
KZ
348 }
349 }
350 /* The default is enable all filesystems,
351 * set relevant bitmap bit means disable the filesystem.
352 */
353 if (flag & BLKID_FLTR_ONLYIN) {
354 if (!has)
355 blkid_bmp_set_item(pr->fltr, i);
356 } else if (flag & BLKID_FLTR_NOTIN) {
357 if (has)
358 blkid_bmp_set_item(pr->fltr, i);
a0948ffe 359 }
a0948ffe 360 }
6644688a 361 DBG(DEBUG_LOWPROBE, printf("a new probing type-filter initialized\n"));
a0948ffe
KZ
362 return 0;
363}
364
365/*
51410fc6
KZ
366 * flag:
367 *
368 * BLKID_FLTR_NOTIN - probe all filesystems which are NOT IN "usage"
369 *
370 * BLKID_FLTR_ONLYIN - probe filesystem which are IN "usage"
371 *
372 * where the "usage" is a set of filesystem according the usage flag (crypto,
373 * raid, filesystem, ...)
a0948ffe 374 */
51410fc6 375int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage)
a0948ffe 376{
51410fc6 377 int i;
a0948ffe 378
51410fc6
KZ
379 if (!pr || !usage)
380 return -1;
4ce48a97 381 if (!pr->fltr) {
51410fc6 382 pr->fltr = calloc(BLKID_FLTR_SIZE, sizeof(unsigned long));
4ce48a97
KZ
383 blkid_probe_reset_idx(pr);
384 } else
51410fc6 385 blkid_probe_reset_filter(pr);
a0948ffe 386
deedaa30
KZ
387 if (!pr->fltr)
388 return -1;
389
51410fc6
KZ
390 for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
391 const struct blkid_idinfo *id = idinfos[i];
a0948ffe 392
51410fc6
KZ
393 if (id->usage & usage) {
394 if (flag & BLKID_FLTR_NOTIN)
395 blkid_bmp_set_item(pr->fltr, i);
396 } else if (flag & BLKID_FLTR_ONLYIN)
397 blkid_bmp_set_item(pr->fltr, i);
a0948ffe 398 }
6644688a 399 DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n"));
a0948ffe
KZ
400 return 0;
401}
402
403
51410fc6 404int blkid_probe_invert_filter(blkid_probe pr)
a0948ffe 405{
51410fc6 406 int i;
a0948ffe 407
51410fc6
KZ
408 if (!pr || !pr->fltr)
409 return -1;
410 for (i = 0; i < BLKID_FLTR_SIZE; i++)
411 pr->fltr[i] = ~pr->fltr[i];
a0fc685c 412
4ce48a97 413 blkid_probe_reset_idx(pr);
6644688a 414 DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
a0948ffe
KZ
415 return 0;
416}
417
a0fc685c
KZ
418/*
419 * The blkid_do_probe() calls the probe functions. This routine could be used
420 * in a loop when you need to probe for all possible filesystems/raids.
421 *
422 * 1/ basic case -- use the first result:
423 *
424 * if (blkid_do_probe(pr) == 0) {
425 * int nvals = blkid_probe_numof_values(pr);
426 * for (n = 0; n < nvals; n++) {
427 * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0)
428 * printf("%s = %s\n", name, data);
429 * }
430 * }
431 *
432 * 2/ advanced case -- probe for all signatures (don't forget that some
433 * filesystems can co-exist on one volume (e.g. CD-ROM).
434 *
435 * while (blkid_do_probe(pr) == 0) {
436 * int nvals = blkid_probe_numof_values(pr);
437 * ...
438 * }
439 *
440 * The internal probing index (pointer to the last probing function) is
441 * always reseted when you touch probing filter or set a new device. It
442 * means you cannot use:
443 *
444 * blkid_probe_invert_filter()
445 * blkid_probe_filter_usage()
446 * blkid_probe_filter_types()
447 * blkid_probe_reset_filter()
448 * blkid_probe_set_device()
449 *
450 * in the loop (e.g while()) when you iterate on all signatures.
451 */
51410fc6 452int blkid_do_probe(blkid_probe pr)
a0948ffe 453{
a0fc685c 454 int i = 0;
a0948ffe 455
51410fc6
KZ
456 if (!pr)
457 return -1;
a0948ffe 458
51410fc6 459 blkid_probe_reset_vals(pr);
a0948ffe 460
4ce48a97 461 i = pr->idx + 1;
a0fc685c 462
87aab0e1
KZ
463 if (i < 0 && i >= ARRAY_SIZE(idinfos))
464 return -1;
465
92163c45 466 DBG(DEBUG_LOWPROBE, printf("--> starting probing loop\n"));
6644688a 467
a2f01a1c 468 for ( ; i < ARRAY_SIZE(idinfos); i++) {
51410fc6
KZ
469 const struct blkid_idinfo *id;
470 const struct blkid_idmag *mag;
2d4f7576 471 int hasmag = 0;
a0948ffe 472
a0fc685c
KZ
473 pr->idx = i;
474
51410fc6
KZ
475 if (pr->fltr && blkid_bmp_get_item(pr->fltr, i))
476 continue;
a0948ffe 477
51410fc6
KZ
478 id = idinfos[i];
479 mag = id->magics ? &id->magics[0] : NULL;
a0948ffe 480
51410fc6
KZ
481 /* try to detect by magic string */
482 while(mag && mag->magic) {
483 int idx;
484 unsigned char *buf;
a0948ffe 485
51410fc6
KZ
486 idx = mag->kboff + (mag->sboff >> 10);
487 buf = blkid_probe_get_buffer(pr, idx << 10, 1024);
a0948ffe 488
51410fc6 489 if (buf && !memcmp(mag->magic,
6644688a
KZ
490 buf + (mag->sboff & 0x3ff), mag->len)) {
491 DBG(DEBUG_LOWPROBE, printf(
92163c45
KZ
492 "%s: magic sboff=%u, kboff=%ld\n",
493 id->name, mag->sboff, mag->kboff));
2d4f7576 494 hasmag = 1;
51410fc6 495 break;
6644688a 496 }
51410fc6
KZ
497 mag++;
498 }
a0948ffe 499
2d4f7576 500 if (hasmag == 0 && id->magics && id->magics[0].magic)
51410fc6
KZ
501 /* magic string(s) defined, but not found */
502 continue;
a0948ffe 503
51410fc6 504 /* final check by probing function */
6644688a
KZ
505 if (id->probefunc) {
506 DBG(DEBUG_LOWPROBE, printf(
92163c45 507 "%s: call probefunc()\n", id->name));
6644688a
KZ
508 if (id->probefunc(pr, mag) != 0)
509 continue;
510 }
a0948ffe 511
51410fc6
KZ
512 /* all cheks passed */
513 if (pr->probreq & BLKID_PROBREQ_TYPE)
514 blkid_probe_set_value(pr, "TYPE",
515 (unsigned char *) id->name,
516 strlen(id->name) + 1);
51410fc6
KZ
517 if (pr->probreq & BLKID_PROBREQ_USAGE)
518 blkid_probe_set_usage(pr, id->usage);
a0948ffe 519
5b6215b5 520 DBG(DEBUG_LOWPROBE,
92163c45 521 printf("<-- leaving probing loop (type=%s)\n", id->name));
51410fc6
KZ
522 return 0;
523 }
92163c45 524 DBG(DEBUG_LOWPROBE, printf("<-- leaving probing loop (failed)\n"));
51410fc6 525 return 1;
a0948ffe
KZ
526}
527
a2f01a1c
KZ
528/*
529 * This is the same function as blkid_do_probe(), but returns only one result
530 * (cannot be used in while()) and checks for ambivalen results (more
531 * filesystems on the device) -- in such case returns -2.
532 */
533int blkid_do_safeprobe(blkid_probe pr)
534{
535 struct blkid_struct_probe first;
536 int count = 0;
537 int intol = 0;
538 int rc;
539
540 while ((rc = blkid_do_probe(pr)) == 0) {
541 if (!count) {
542 /* store the fist result */
543 memcpy(first.vals, pr->vals, sizeof(first.vals));
544 first.nvals = pr->nvals;
545 first.idx = pr->idx;
546 }
547 if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT))
548 intol++;
549 count++;
550 }
551 if (rc < 0)
552 return rc; /* error */
92163c45
KZ
553 if (count > 1 && intol) {
554 DBG(DEBUG_LOWPROBE,
555 printf("ERROR: ambivalent result detected (%d filesystems)!\n",
556 count));
a2f01a1c 557 return -2; /* error, ambivalent result (more FS) */
92163c45 558 }
a2f01a1c
KZ
559 if (!count)
560 return 1; /* nothing detected */
561
562 /* restore the first result */
563 memcpy(pr->vals, first.vals, sizeof(first.vals));
564 pr->nvals = first.nvals;
565 pr->idx = first.idx;
566
567 return 0;
568}
569
51410fc6 570int blkid_probe_numof_values(blkid_probe pr)
a0948ffe 571{
51410fc6
KZ
572 if (!pr)
573 return -1;
574 return pr->nvals;
a0948ffe
KZ
575}
576
a0948ffe 577
51410fc6
KZ
578static struct blkid_prval *blkid_probe_assign_value(
579 blkid_probe pr, const char *name)
a0948ffe 580{
51410fc6 581 struct blkid_prval *v;
a0948ffe 582
51410fc6
KZ
583 if (!name)
584 return NULL;
585 if (pr->nvals >= BLKID_PROBVAL_NVALS)
586 return NULL;
a0948ffe 587
51410fc6
KZ
588 v = &pr->vals[pr->nvals];
589 v->name = name;
590 pr->nvals++;
6644688a 591
5b6215b5 592 DBG(DEBUG_LOWPROBE, printf("assigning %s\n", name));
51410fc6 593 return v;
a0948ffe
KZ
594}
595
51410fc6
KZ
596int blkid_probe_set_value(blkid_probe pr, const char *name,
597 unsigned char *data, size_t len)
a0948ffe 598{
51410fc6 599 struct blkid_prval *v;
a0948ffe 600
51410fc6
KZ
601 if (len > BLKID_PROBVAL_BUFSIZ)
602 len = BLKID_PROBVAL_BUFSIZ;
a0948ffe 603
51410fc6
KZ
604 v = blkid_probe_assign_value(pr, name);
605 if (!v)
606 return -1;
a0948ffe 607
51410fc6
KZ
608 memcpy(v->data, data, len);
609 v->len = len;
a0948ffe
KZ
610 return 0;
611}
612
51410fc6
KZ
613int blkid_probe_vsprintf_value(blkid_probe pr, const char *name,
614 const char *fmt, va_list ap)
a0948ffe 615{
51410fc6
KZ
616 struct blkid_prval *v;
617 size_t len;
a0948ffe 618
51410fc6
KZ
619 v = blkid_probe_assign_value(pr, name);
620 if (!v)
621 return -1;
a0948ffe 622
51410fc6 623 len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap);
a0948ffe 624
51410fc6
KZ
625 if (len <= 0) {
626 pr->nvals--; /* reset the latest assigned value */
627 return -1;
a0948ffe 628 }
51410fc6 629 v->len = len + 1;
a0948ffe
KZ
630 return 0;
631}
632
51410fc6 633int blkid_probe_set_version(blkid_probe pr, const char *version)
a0948ffe 634{
51410fc6
KZ
635 if (pr->probreq & BLKID_PROBREQ_VERSION)
636 return blkid_probe_set_value(pr, "VERSION",
637 (unsigned char *) version, strlen(version) + 1);
a0948ffe
KZ
638 return 0;
639}
640
51410fc6 641int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...)
a0948ffe 642{
51410fc6 643 int rc = 0;
a0948ffe 644
51410fc6
KZ
645 if (pr->probreq & BLKID_PROBREQ_VERSION) {
646 va_list ap;
a0948ffe 647
51410fc6
KZ
648 va_start(ap, fmt);
649 rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap);
650 va_end(ap);
651 }
652 return rc;
a0948ffe
KZ
653}
654
51410fc6 655static int blkid_probe_set_usage(blkid_probe pr, int usage)
a0948ffe 656{
51410fc6 657 char *u = NULL;
a0948ffe 658
51410fc6
KZ
659 if (usage & BLKID_USAGE_FILESYSTEM)
660 u = "filesystem";
661 else if (usage & BLKID_USAGE_RAID)
662 u = "raid";
663 else if (usage & BLKID_USAGE_CRYPTO)
664 u = "crypto";
665 else if (usage & BLKID_USAGE_OTHER)
666 u = "other";
667 else
668 u = "unknown";
a0948ffe 669
51410fc6 670 return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
a0948ffe
KZ
671}
672
51410fc6 673int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len)
a0948ffe 674{
51410fc6
KZ
675 struct blkid_prval *v;
676 int i;
a0948ffe 677
409b115d
KZ
678 if (len > BLKID_PROBVAL_BUFSIZ)
679 len = BLKID_PROBVAL_BUFSIZ;
680
51410fc6
KZ
681 if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
682 blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
683 return -1;
684 if (!(pr->probreq & BLKID_PROBREQ_LABEL))
685 return 0;
686 v = blkid_probe_assign_value(pr, "LABEL");
687 if (!v)
688 return -1;
a0948ffe 689
51410fc6
KZ
690 memcpy(v->data, label, len);
691 v->data[len] = '\0';
a0948ffe 692
51410fc6
KZ
693 /* remove trailing whitespace */
694 i = strnlen((char *) v->data, len);
695 while (i--) {
696 if (!isspace(v->data[i]))
697 break;
a0948ffe 698 }
51410fc6
KZ
699 v->data[++i] = '\0';
700 v->len = i + 1;
701 return 0;
a0948ffe
KZ
702}
703
51410fc6
KZ
704static size_t encode_to_utf8(int enc, unsigned char *dest, size_t len,
705 unsigned char *src, size_t count)
a0948ffe 706{
51410fc6
KZ
707 size_t i, j;
708 uint16_t c;
a0948ffe 709
2a0f4c4e 710 for (j = i = 0; i + 2 <= count; i += 2) {
51410fc6
KZ
711 if (enc == BLKID_ENC_UTF16LE)
712 c = (src[i+1] << 8) | src[i];
713 else /* BLKID_ENC_UTF16BE */
714 c = (src[i] << 8) | src[i+1];
a0948ffe 715 if (c == 0) {
51410fc6 716 dest[j] = '\0';
a0948ffe
KZ
717 break;
718 } else if (c < 0x80) {
51410fc6 719 if (j+1 >= len)
a0948ffe 720 break;
51410fc6 721 dest[j++] = (uint8_t) c;
a0948ffe 722 } else if (c < 0x800) {
51410fc6 723 if (j+2 >= len)
a0948ffe 724 break;
51410fc6
KZ
725 dest[j++] = (uint8_t) (0xc0 | (c >> 6));
726 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
a0948ffe 727 } else {
51410fc6 728 if (j+3 >= len)
a0948ffe 729 break;
51410fc6
KZ
730 dest[j++] = (uint8_t) (0xe0 | (c >> 12));
731 dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
732 dest[j++] = (uint8_t) (0x80 | (c & 0x3f));
a0948ffe
KZ
733 }
734 }
51410fc6
KZ
735 dest[j] = '\0';
736 return j;
a0948ffe
KZ
737}
738
51410fc6
KZ
739int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label,
740 size_t len, int enc)
a0948ffe 741{
51410fc6
KZ
742 struct blkid_prval *v;
743
744 if ((pr->probreq & BLKID_PROBREQ_LABELRAW) &&
745 blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0)
746 return -1;
747 if (!(pr->probreq & BLKID_PROBREQ_LABEL))
748 return 0;
749 v = blkid_probe_assign_value(pr, "LABEL");
750 if (!v)
751 return -1;
2a0f4c4e 752
51410fc6 753 v->len = encode_to_utf8(enc, v->data, sizeof(v->data), label, len);
a0948ffe
KZ
754 return 0;
755}
756
51410fc6
KZ
757/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */
758static int uuid_is_empty(const unsigned char *buf, size_t len)
a0948ffe 759{
51410fc6 760 int i;
a0948ffe 761
51410fc6
KZ
762 for (i = 0; i < len; i++)
763 if (buf[i])
764 return 0;
765 return 1;
766}
a0948ffe 767
51410fc6
KZ
768int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid,
769 size_t len, const char *fmt, ...)
770{
409b115d 771 int rc = -1;
51410fc6 772 va_list ap;
409b115d
KZ
773
774 if (len > BLKID_PROBVAL_BUFSIZ)
775 len = BLKID_PROBVAL_BUFSIZ;
a0948ffe 776
51410fc6 777 if (uuid_is_empty(uuid, len))
a0948ffe
KZ
778 return 0;
779
51410fc6
KZ
780 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
781 blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0)
782 return -1;
783 if (!(pr->probreq & BLKID_PROBREQ_UUID))
a0948ffe
KZ
784 return 0;
785
51410fc6 786 va_start(ap, fmt);
bb6c6673 787 rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap);
51410fc6 788 va_end(ap);
a0948ffe 789
51410fc6
KZ
790 /* convert to lower case (..be paranoid) */
791 if (!rc) {
792 int i;
793 struct blkid_prval *v = &pr->vals[pr->nvals];
a0948ffe 794
51410fc6
KZ
795 for (i = 0; i < v->len; i++)
796 if (v->data[i] >= 'A' && v->data[i] <= 'F')
797 v->data[i] = (v->data[i] - 'A') + 'a';
a0948ffe 798 }
51410fc6
KZ
799 return rc;
800}
a0948ffe 801
bb6c6673
KZ
802/* function to set UUIDs that are in suberblocks stored as strings */
803int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len)
804{
805 struct blkid_prval *v;
806
807 if (str == NULL || *str == '\0')
808 return -1;
809 if (!len)
810 len = strlen((char *) str);
811 if (len > BLKID_PROBVAL_BUFSIZ)
812 len = BLKID_PROBVAL_BUFSIZ;
813
814 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
815 blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0)
816 return -1;
817 if (!(pr->probreq & BLKID_PROBREQ_UUID))
818 return 0;
819
820 v = blkid_probe_assign_value(pr, "UUID");
821 if (v) {
822 memcpy((char *) v->data, str, len);
22632603 823 *(v->data + len) = '\0';
bb6c6673
KZ
824 v->len = len;
825 return 0;
826 }
827 return -1;
828}
829
51410fc6 830/* default _set_uuid function to set DCE UUIDs */
8e7e30e4 831int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name)
51410fc6
KZ
832{
833 struct blkid_prval *v;
a0948ffe 834
51410fc6 835 if (uuid_is_empty(uuid, 16))
a0948ffe
KZ
836 return 0;
837
8e7e30e4
KZ
838 if (!name) {
839 if ((pr->probreq & BLKID_PROBREQ_UUIDRAW) &&
840 blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0)
841 return -1;
842 if (!(pr->probreq & BLKID_PROBREQ_UUID))
843 return 0;
a0948ffe 844
8e7e30e4
KZ
845 v = blkid_probe_assign_value(pr, "UUID");
846 } else
847 v = blkid_probe_assign_value(pr, name);
a0948ffe 848
51410fc6
KZ
849#ifdef HAVE_LIBUUID
850 {
851 uuid_unparse(uuid, (char *) v->data);
852 v->len = 37;
853 }
854#else
855 v->len = snprintf(v->data, sizeof(v->data),
856 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
857 uuid[0], uuid[1], uuid[2], uuid[3],
858 uuid[4], uuid[5],
859 uuid[6], uuid[7],
860 uuid[8], uuid[9],
861 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]);
862 v->len++;
863#endif
a0948ffe
KZ
864 return 0;
865}
866
8e7e30e4
KZ
867int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid)
868{
869 return blkid_probe_set_uuid_as(pr, uuid, NULL);
870}
871
51410fc6 872int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
6d042d0d 873 const char **data, size_t *len)
a0948ffe 874{
51410fc6 875 struct blkid_prval *v;
a0948ffe 876
51410fc6
KZ
877 if (pr == NULL || num < 0 || num >= pr->nvals)
878 return -1;
a0948ffe 879
51410fc6
KZ
880 v = &pr->vals[num];
881 if (name)
882 *name = v->name;
883 if (data)
6d042d0d 884 *data = (char *) v->data;
51410fc6
KZ
885 if (len)
886 *len = v->len;
6644688a
KZ
887
888 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
a0948ffe
KZ
889 return 0;
890}
a0948ffe 891
51410fc6 892int blkid_probe_lookup_value(blkid_probe pr, const char *name,
6d042d0d 893 const char **data, size_t *len)
a0948ffe 894{
51410fc6 895 int i;
a0948ffe 896
51410fc6
KZ
897 if (pr == NULL || pr->nvals == 0 || name == NULL)
898 return -1;
a0948ffe 899
51410fc6
KZ
900 for (i = 0; i < pr->nvals; i++) {
901 struct blkid_prval *v = &pr->vals[i];
a0948ffe 902
51410fc6
KZ
903 if (v->name && strcmp(name, v->name) == 0) {
904 if (data)
6d042d0d 905 *data = (char *) v->data;
51410fc6
KZ
906 if (len)
907 *len = v->len;
6644688a 908 DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name));
51410fc6 909 return 0;
a0948ffe
KZ
910 }
911 }
51410fc6 912 return -1;
a0948ffe
KZ
913}
914
51410fc6 915int blkid_probe_has_value(blkid_probe pr, const char *name)
a0948ffe 916{
51410fc6
KZ
917 if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0)
918 return 1;
a0948ffe
KZ
919 return 0;
920}
921