]>
Commit | Line | Data |
---|---|---|
a0948ffe | 1 | /* |
4d72b337 | 2 | * Low-level libblkid probing API |
a0948ffe | 3 | * |
4d72b337 | 4 | * Copyright (C) 2008-2009 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 | ||
4d72b337 KZ |
10 | /** |
11 | * SECTION: lowprobe | |
12 | * @title: Low-level probing | |
13 | * @short_description: low-level prober initialization | |
14 | * | |
15 | * The low-level probing routines always and directly read information from | |
16 | * the selected (see blkid_probe_set_device()) device. | |
17 | * | |
18 | * The probing routines are grouped together into separate chains. Currently, | |
19 | * the librray provides superblocks, partitions and topology chains. | |
20 | * | |
21 | * The probing routines is possible to filter (enable/disable) by type (e.g. | |
22 | * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID). | |
488e52be KZ |
23 | * These filters are per-chain. Note that always when you touch the chain |
24 | * filter the current probing position is reseted and probing starts from | |
25 | * scratch. It means that the chain filter should not be modified during | |
26 | * probing, for example in loop where you call blkid_do_probe(). | |
27 | * | |
28 | * For more details see the chain specific documentation. | |
4d72b337 KZ |
29 | * |
30 | * The low-level API provides two ways how access to probing results. | |
31 | * | |
32 | * 1. The NAME=value (tag) interface. This interface is older and returns all data | |
33 | * as strings. This interface is generic for all chains. | |
34 | * | |
35 | * 2. The binary interfaces. These interfaces return data in the native formats. | |
36 | * The interface is always specific to the probing chain. | |
488e52be | 37 | * |
4d72b337 KZ |
38 | */ |
39 | ||
40 | /** | |
41 | * SECTION: lowprobe-tags | |
42 | * @title: Low-level tags | |
43 | * @short_description: generic NAME=value interface. | |
44 | * | |
45 | * The probing routines inside the chain are mutually exclusive by default -- | |
46 | * only few probing routines are marked as "tolerant". The "tolerant" probing | |
47 | * routines are used for filesystem which can share the same device with any | |
48 | * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag. | |
49 | * | |
50 | * The SUPERBLOCKS chain is enabled by default. The all others chains is | |
51 | * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific | |
488e52be | 52 | * documentation. |
4d72b337 KZ |
53 | * |
54 | * The blkid_do_probe() function returns a result from only one probing | |
55 | * routine, and the next call from the next probing routine. It means you need | |
56 | * to call the function in loop, for example: | |
57 | * | |
58 | * <informalexample> | |
59 | * <programlisting> | |
60 | * while((blkid_do_probe(pr) == 0) | |
61 | * ... use result ... | |
62 | * </programlisting> | |
63 | * </informalexample> | |
64 | * | |
65 | * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only | |
66 | * first probing result for every enabled chain. This function checks for | |
67 | * ambivalent results (e.g. more "intolerant" filesystems superblocks on the | |
68 | * device). | |
69 | * | |
70 | * The probing result is set of NAME=value pairs (the NAME is always unique). | |
71 | */ | |
72 | ||
a0948ffe KZ |
73 | #include <stdio.h> |
74 | #include <string.h> | |
75 | #include <stdlib.h> | |
76 | #include <unistd.h> | |
77 | #include <fcntl.h> | |
78 | #include <ctype.h> | |
79 | #include <sys/types.h> | |
80 | #ifdef HAVE_SYS_STAT_H | |
81 | #include <sys/stat.h> | |
82 | #endif | |
83 | #ifdef HAVE_SYS_MKDEV_H | |
84 | #include <sys/mkdev.h> | |
85 | #endif | |
a0948ffe KZ |
86 | #ifdef HAVE_ERRNO_H |
87 | #include <errno.h> | |
88 | #endif | |
51410fc6 | 89 | #include <stdint.h> |
8c0dc071 KZ |
90 | #include <stdarg.h> |
91 | ||
51410fc6 | 92 | #ifdef HAVE_LIBUUID |
8c0dc071 KZ |
93 | # ifdef HAVE_UUID_UUID_H |
94 | # include <uuid/uuid.h> | |
e5127179 KZ |
95 | # else |
96 | # include <uuid.h> | |
8c0dc071 | 97 | # endif |
51410fc6 | 98 | #endif |
a0948ffe | 99 | |
dc61d909 | 100 | #include "blkdev.h" |
51410fc6 | 101 | #include "blkidP.h" |
219227c2 | 102 | |
52448df8 KZ |
103 | /* chains */ |
104 | extern const struct blkid_chaindrv superblocks_drv; | |
cc33d693 | 105 | extern const struct blkid_chaindrv topology_drv; |
e4799a35 | 106 | extern const struct blkid_chaindrv partitions_drv; |
52448df8 KZ |
107 | |
108 | /* | |
109 | * All supported chains | |
110 | */ | |
111 | static const struct blkid_chaindrv *chains_drvs[] = { | |
112 | [BLKID_CHAIN_SUBLKS] = &superblocks_drv, | |
cc33d693 | 113 | [BLKID_CHAIN_TOPLGY] = &topology_drv, |
e4799a35 | 114 | [BLKID_CHAIN_PARTS] = &partitions_drv |
52448df8 KZ |
115 | }; |
116 | ||
117 | static void blkid_probe_reset_vals(blkid_probe pr); | |
118 | ||
52448df8 KZ |
119 | /** |
120 | * blkid_new_probe: | |
121 | * | |
122 | * Returns: a pointer to the newly allocated probe struct. | |
a0948ffe | 123 | */ |
51410fc6 | 124 | blkid_probe blkid_new_probe(void) |
a0948ffe | 125 | { |
52448df8 KZ |
126 | int i; |
127 | blkid_probe pr; | |
128 | ||
7a458332 | 129 | blkid_init_debug(0); |
52448df8 KZ |
130 | pr = calloc(1, sizeof(struct blkid_struct_probe)); |
131 | if (!pr) | |
132 | return NULL; | |
133 | ||
134 | /* initialize chains */ | |
135 | for (i = 0; i < BLKID_NCHAINS; i++) { | |
136 | pr->chains[i].driver = chains_drvs[i]; | |
137 | pr->chains[i].flags = chains_drvs[i]->dflt_flags; | |
138 | pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; | |
139 | } | |
140 | return pr; | |
a0948ffe KZ |
141 | } |
142 | ||
f38db0cf KZ |
143 | /** |
144 | * blkid_new_probe_from_filename: | |
145 | * @filename: device or regular file | |
146 | * | |
147 | * This function is same as call open(filename), blkid_new_probe() and | |
148 | * blkid_probe_set_device(pr, fd, 0, 0). | |
149 | * | |
150 | * The @filename is closed by blkid_free_probe() or by the | |
151 | * blkid_probe_set_device() call. | |
152 | * | |
153 | * Returns: a pointer to the newly allocated probe struct or NULL in case of | |
154 | * error. | |
155 | */ | |
156 | blkid_probe blkid_new_probe_from_filename(const char *filename) | |
157 | { | |
158 | int fd = -1; | |
159 | blkid_probe pr = NULL; | |
160 | ||
161 | if (!filename) | |
162 | return NULL; | |
163 | ||
164 | fd = open(filename, O_RDONLY); | |
165 | if (fd < 0) | |
166 | return NULL; | |
167 | ||
168 | pr = blkid_new_probe(); | |
169 | if (!pr) | |
170 | goto err; | |
171 | ||
172 | if (blkid_probe_set_device(pr, fd, 0, 0)) | |
173 | goto err; | |
174 | ||
175 | pr->flags |= BLKID_PRIVATE_FD; | |
176 | return pr; | |
177 | err: | |
178 | if (fd >= 0) | |
179 | close(fd); | |
180 | blkid_free_probe(pr); | |
181 | return NULL; | |
182 | } | |
183 | ||
52448df8 KZ |
184 | /** |
185 | * blkid_free_probe: | |
186 | * @pr: probe | |
187 | * | |
188 | * Deallocates the probe struct, buffers and all allocated | |
51410fc6 | 189 | * data that are associated with this probing control struct. |
a0948ffe | 190 | */ |
51410fc6 | 191 | void blkid_free_probe(blkid_probe pr) |
a0948ffe | 192 | { |
52448df8 KZ |
193 | int i; |
194 | ||
51410fc6 KZ |
195 | if (!pr) |
196 | return; | |
52448df8 KZ |
197 | |
198 | for (i = 0; i < BLKID_NCHAINS; i++) { | |
199 | struct blkid_chain *ch = &pr->chains[i]; | |
200 | ||
201 | if (ch->driver->free_data) | |
202 | ch->driver->free_data(pr, ch->data); | |
203 | free(ch->fltr); | |
204 | } | |
51410fc6 KZ |
205 | free(pr->buf); |
206 | free(pr->sbbuf); | |
f38db0cf KZ |
207 | |
208 | if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0) | |
209 | close(pr->fd); | |
51410fc6 | 210 | free(pr); |
a0948ffe KZ |
211 | } |
212 | ||
52448df8 KZ |
213 | static void blkid_probe_reset_buffer(blkid_probe pr) |
214 | { | |
215 | DBG(DEBUG_LOWPROBE, printf("reseting blkid probe buffer\n")); | |
216 | if (pr->buf) | |
217 | memset(pr->buf, 0, pr->buf_max); | |
218 | pr->buf_off = 0; | |
219 | pr->buf_len = 0; | |
220 | if (pr->sbbuf) | |
221 | memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ); | |
222 | pr->sbbuf_len = 0; | |
223 | } | |
224 | ||
225 | ||
9bdf6885 KZ |
226 | /* |
227 | * Removes chain values from probing result. | |
228 | */ | |
229 | void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) | |
230 | { | |
231 | int nvals = pr->nvals; | |
232 | int i, x; | |
233 | ||
234 | for (x = 0, i = 0; i < pr->nvals; i++) { | |
235 | struct blkid_prval *v = &pr->vals[i]; | |
236 | ||
237 | if (v->chain != chn && x == i) { | |
238 | x++; | |
239 | continue; | |
240 | } | |
241 | if (v->chain == chn) { | |
242 | --nvals; | |
243 | continue; | |
244 | } | |
245 | memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval)); | |
246 | } | |
247 | pr->nvals = nvals; | |
248 | } | |
249 | ||
250 | /* | |
251 | * Copies chain values from probing result to @vals, the max size of @vals is | |
252 | * @nvals and returns real number of values. | |
253 | */ | |
254 | int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, | |
255 | struct blkid_prval *vals, int nvals) | |
256 | { | |
257 | int i, x; | |
258 | ||
259 | for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) { | |
260 | struct blkid_prval *v = &pr->vals[i]; | |
261 | ||
262 | if (v->chain != chn) | |
263 | continue; | |
264 | memcpy(&vals[x++], v, sizeof(struct blkid_prval)); | |
265 | } | |
266 | return x; | |
267 | } | |
268 | ||
269 | /* | |
270 | * Appends values from @vals to the probing result | |
271 | */ | |
272 | void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals) | |
273 | { | |
274 | int i = 0; | |
275 | ||
276 | while (i < nvals && pr->nvals < BLKID_NVALS) { | |
277 | memcpy(&pr->vals[pr->nvals++], &vals[i++], | |
278 | sizeof(struct blkid_prval)); | |
279 | } | |
280 | } | |
281 | ||
51410fc6 | 282 | static void blkid_probe_reset_vals(blkid_probe pr) |
a0948ffe | 283 | { |
51410fc6 KZ |
284 | memset(pr->vals, 0, sizeof(pr->vals)); |
285 | pr->nvals = 0; | |
a0948ffe KZ |
286 | } |
287 | ||
1c1726a7 KZ |
288 | struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) |
289 | { | |
290 | return pr->cur_chain; | |
291 | } | |
292 | ||
22571ebb KZ |
293 | void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) |
294 | { | |
295 | int rc; | |
296 | ||
297 | if (!pr && !chn) | |
298 | return NULL; | |
299 | ||
300 | pr->cur_chain = chn; | |
958757bb | 301 | chn->idx = -1; /* start probing from scratch */ |
22571ebb KZ |
302 | chn->binary = TRUE; |
303 | ||
304 | rc = chn->driver->probe(pr, chn); | |
305 | ||
306 | chn->binary = FALSE; | |
307 | pr->cur_chain = NULL; | |
308 | ||
309 | if (rc < 0) | |
310 | return NULL; | |
311 | ||
312 | DBG(DEBUG_LOWPROBE, | |
313 | printf("returning %s binary data\n", chn->driver->name)); | |
314 | return chn->data; | |
315 | } | |
316 | ||
317 | ||
52448df8 KZ |
318 | /** |
319 | * blkid_reset_probe: | |
320 | * @pr: probe | |
321 | * | |
44ef90bc KZ |
322 | * Zeroize probing results and resets the current probing (this has impact to |
323 | * blkid_do_probe() only). This function does not touch probing filters and | |
324 | * keeps assigned device. | |
52448df8 | 325 | */ |
51410fc6 | 326 | void blkid_reset_probe(blkid_probe pr) |
a0948ffe | 327 | { |
52448df8 KZ |
328 | int i; |
329 | ||
51410fc6 KZ |
330 | if (!pr) |
331 | return; | |
52448df8 KZ |
332 | |
333 | blkid_probe_reset_buffer(pr); | |
51410fc6 | 334 | blkid_probe_reset_vals(pr); |
52448df8 | 335 | |
44ef90bc KZ |
336 | pr->cur_chain = NULL; |
337 | ||
52448df8 KZ |
338 | for (i = 0; i < BLKID_NCHAINS; i++) |
339 | pr->chains[i].idx = -1; | |
a0948ffe KZ |
340 | } |
341 | ||
46a734fd KZ |
342 | /*** |
343 | static int blkid_probe_dump_filter(blkid_probe pr, int chain) | |
344 | { | |
345 | struct blkid_chain *chn; | |
346 | int i; | |
347 | ||
348 | if (!pr || chain < 0 || chain >= BLKID_NCHAINS) | |
349 | return -1; | |
350 | ||
351 | chn = &pr->chains[chain]; | |
352 | ||
353 | if (!chn->fltr) | |
354 | return -1; | |
355 | ||
356 | for (i = 0; i < chn->driver->nidinfos; i++) { | |
357 | const struct blkid_idinfo *id = chn->driver->idinfos[i]; | |
358 | ||
359 | DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n", | |
360 | i, | |
361 | id->name, | |
362 | blkid_bmp_get_item(chn->fltr, i) | |
363 | ? "disabled" : "enabled <--")); | |
46a734fd KZ |
364 | } |
365 | return 0; | |
366 | } | |
367 | ***/ | |
368 | ||
369 | /* | |
370 | * Returns properly initialized chain filter | |
371 | */ | |
372 | unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) | |
373 | { | |
374 | struct blkid_chain *chn; | |
375 | ||
376 | if (!pr || chain < 0 || chain >= BLKID_NCHAINS) | |
377 | return NULL; | |
378 | ||
379 | chn = &pr->chains[chain]; | |
380 | ||
381 | /* always when you touch the chain filter all indexes are reseted and | |
382 | * probing starts from scratch | |
383 | */ | |
384 | chn->idx = -1; | |
385 | pr->cur_chain = NULL; | |
386 | ||
387 | if (!chn->driver->has_fltr || (!chn->fltr && !create)) | |
388 | return NULL; | |
389 | ||
390 | if (!chn->fltr) | |
391 | chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos)); | |
392 | else | |
393 | memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos)); | |
394 | ||
395 | /* blkid_probe_dump_filter(pr, chain); */ | |
396 | return chn->fltr; | |
397 | } | |
398 | ||
399 | /* | |
400 | * Generic private functions for filter setting | |
401 | */ | |
402 | int __blkid_probe_invert_filter(blkid_probe pr, int chain) | |
403 | { | |
404 | int i; | |
405 | struct blkid_chain *chn; | |
406 | unsigned long *fltr; | |
407 | ||
408 | fltr = blkid_probe_get_filter(pr, chain, FALSE); | |
409 | if (!fltr) | |
410 | return -1; | |
411 | ||
412 | chn = &pr->chains[chain]; | |
413 | ||
414 | for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++) | |
415 | fltr[i] = ~fltr[i]; | |
416 | ||
417 | DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); | |
418 | /* blkid_probe_dump_filter(pr, chain); */ | |
419 | return 0; | |
420 | } | |
421 | ||
422 | int __blkid_probe_reset_filter(blkid_probe pr, int chain) | |
423 | { | |
424 | return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1; | |
425 | } | |
426 | ||
427 | int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) | |
428 | { | |
429 | unsigned long *fltr; | |
430 | struct blkid_chain *chn; | |
431 | int i; | |
432 | ||
433 | fltr = blkid_probe_get_filter(pr, chain, TRUE); | |
434 | if (!fltr) | |
435 | return -1; | |
436 | ||
437 | chn = &pr->chains[chain]; | |
438 | ||
439 | for (i = 0; i < chn->driver->nidinfos; i++) { | |
440 | int has = 0; | |
441 | const struct blkid_idinfo *id = chn->driver->idinfos[i]; | |
442 | char **n; | |
443 | ||
444 | for (n = names; *n; n++) { | |
445 | if (!strcmp(id->name, *n)) { | |
446 | has = 1; | |
447 | break; | |
448 | } | |
449 | } | |
450 | if (flag & BLKID_FLTR_ONLYIN) { | |
451 | if (!has) | |
452 | blkid_bmp_set_item(fltr, i); | |
453 | } else if (flag & BLKID_FLTR_NOTIN) { | |
454 | if (has) | |
455 | blkid_bmp_set_item(fltr, i); | |
456 | } | |
457 | } | |
458 | ||
459 | DBG(DEBUG_LOWPROBE, | |
460 | printf("%s: a new probing type-filter initialized\n", | |
461 | chn->driver->name)); | |
462 | /* blkid_probe_dump_filter(pr, chain); */ | |
463 | return 0; | |
464 | } | |
465 | ||
51410fc6 KZ |
466 | /* |
467 | * Note that we have two offsets: | |
468 | * | |
469 | * 1/ general device offset (pr->off), that's useful for example when we | |
470 | * probe a partition from whole disk image: | |
471 | * blkid-low --offset <partition_position> disk.img | |
472 | * | |
473 | * 2/ buffer offset (the 'off' argument), that useful for offsets in | |
474 | * superbloks, ... | |
475 | * | |
476 | * That means never use lseek(fd, 0, SEEK_SET), the zero position is always | |
477 | * pr->off, so lseek(fd, pr->off, SEEK_SET). | |
478 | * | |
479 | */ | |
480 | unsigned char *blkid_probe_get_buffer(blkid_probe pr, | |
481 | blkid_loff_t off, blkid_loff_t len) | |
a0948ffe | 482 | { |
51410fc6 | 483 | ssize_t ret_read = 0; |
a0948ffe | 484 | |
4884729a KZ |
485 | if (off < 0 || len < 0) { |
486 | DBG(DEBUG_LOWPROBE, | |
487 | printf("unexpected offset or length of buffer requested\n")); | |
488 | return NULL; | |
489 | } | |
51410fc6 KZ |
490 | if (off + len <= BLKID_SB_BUFSIZ) { |
491 | if (!pr->sbbuf) { | |
492 | pr->sbbuf = malloc(BLKID_SB_BUFSIZ); | |
493 | if (!pr->sbbuf) | |
494 | return NULL; | |
495 | } | |
496 | if (!pr->sbbuf_len) { | |
497 | if (lseek(pr->fd, pr->off, SEEK_SET) < 0) | |
498 | return NULL; | |
499 | ret_read = read(pr->fd, pr->sbbuf, BLKID_SB_BUFSIZ); | |
500 | if (ret_read < 0) | |
501 | ret_read = 0; | |
502 | pr->sbbuf_len = ret_read; | |
503 | } | |
504 | if (off + len > pr->sbbuf_len) | |
505 | return NULL; | |
506 | return pr->sbbuf + off; | |
507 | } else { | |
508 | unsigned char *newbuf = NULL; | |
509 | ||
510 | if (len > pr->buf_max) { | |
511 | newbuf = realloc(pr->buf, len); | |
512 | if (!newbuf) | |
513 | return NULL; | |
514 | pr->buf = newbuf; | |
515 | pr->buf_max = len; | |
516 | pr->buf_off = 0; | |
517 | pr->buf_len = 0; | |
518 | } | |
519 | if (newbuf || off < pr->buf_off || | |
520 | off + len > pr->buf_off + pr->buf_len) { | |
521 | ||
522 | if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) | |
523 | return NULL; | |
524 | ||
525 | ret_read = read(pr->fd, pr->buf, len); | |
526 | if (ret_read != (ssize_t) len) | |
527 | return NULL; | |
528 | pr->buf_off = off; | |
529 | pr->buf_len = len; | |
530 | } | |
531 | return off ? pr->buf + (off - pr->buf_off) : pr->buf; | |
532 | } | |
a0948ffe KZ |
533 | } |
534 | ||
52448df8 KZ |
535 | /** |
536 | * blkid_probe_set_device: | |
537 | * @pr: probe | |
538 | * @fd: device file descriptor | |
539 | * @off: begin of probing area | |
f38db0cf | 540 | * @size: size of probing area (zero means whole device/file) |
52448df8 KZ |
541 | * |
542 | * Assigns the device to probe control struct, resets internal buffers and | |
44ef90bc | 543 | * resets the current probing. |
51410fc6 | 544 | * |
52448df8 | 545 | * Returns: -1 in case of failure, or 0 on success. |
51410fc6 KZ |
546 | */ |
547 | int blkid_probe_set_device(blkid_probe pr, int fd, | |
548 | blkid_loff_t off, blkid_loff_t size) | |
a0948ffe | 549 | { |
51410fc6 KZ |
550 | if (!pr) |
551 | return -1; | |
a0948ffe | 552 | |
51410fc6 | 553 | blkid_reset_probe(pr); |
a0948ffe | 554 | |
f38db0cf KZ |
555 | if ((pr->flags & BLKID_PRIVATE_FD) && pr->fd >= 0) |
556 | close(pr->fd); | |
557 | ||
558 | pr->flags &= ~BLKID_PRIVATE_FD; | |
51410fc6 KZ |
559 | pr->fd = fd; |
560 | pr->off = off; | |
bb6c6673 | 561 | pr->size = 0; |
52448df8 KZ |
562 | pr->devno = 0; |
563 | pr->mode = 0; | |
564 | pr->blkssz = 0; | |
dc61d909 | 565 | |
bb6c6673 | 566 | if (size) |
dc61d909 | 567 | pr->size = size; |
bb6c6673 KZ |
568 | else { |
569 | struct stat sb; | |
570 | ||
571 | if (fstat(fd, &sb)) | |
0d17b1cf | 572 | goto err; |
bb6c6673 | 573 | |
52448df8 KZ |
574 | pr->mode = sb.st_mode; |
575 | ||
c1ba7962 | 576 | if (S_ISBLK(sb.st_mode)) |
bb6c6673 | 577 | blkdev_get_size(fd, (unsigned long long *) &pr->size); |
c1ba7962 CC |
578 | else if (S_ISCHR(sb.st_mode)) |
579 | pr->size = 1; /* UBI devices are char... */ | |
0d17b1cf | 580 | else if (S_ISREG(sb.st_mode)) |
c1ba7962 CC |
581 | pr->size = sb.st_size; /* regular file */ |
582 | ||
583 | if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) | |
52448df8 | 584 | pr->devno = sb.st_rdev; |
bb6c6673 | 585 | } |
c1ba7962 | 586 | |
bb6c6673 | 587 | if (!pr->size) |
0d17b1cf | 588 | goto err; |
a0948ffe | 589 | |
bb6c6673 KZ |
590 | DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n", |
591 | pr->off, pr->size)); | |
a0948ffe | 592 | return 0; |
0d17b1cf KZ |
593 | err: |
594 | DBG(DEBUG_LOWPROBE, | |
595 | printf("failed to prepare a device for low-probing\n")); | |
596 | return -1; | |
597 | ||
a0948ffe KZ |
598 | } |
599 | ||
f319b5ca KZ |
600 | int blkid_probe_get_dimension(blkid_probe pr, |
601 | blkid_loff_t *off, blkid_loff_t *size) | |
602 | { | |
603 | if (!pr) | |
604 | return -1; | |
605 | ||
606 | *off = pr->off; | |
607 | *size = pr->size; | |
608 | return 0; | |
609 | } | |
610 | ||
611 | int blkid_probe_set_dimension(blkid_probe pr, | |
612 | blkid_loff_t off, blkid_loff_t size) | |
613 | { | |
614 | if (!pr) | |
615 | return -1; | |
616 | ||
617 | DBG(DEBUG_LOWPROBE, printf( | |
618 | "changing probing area: size=%llu, off=%llu " | |
619 | "-to-> size=%llu, off=%llu\n", | |
620 | (unsigned long long) pr->size, | |
621 | (unsigned long long) pr->off, | |
622 | (unsigned long long) size, | |
623 | (unsigned long long) off)); | |
624 | ||
625 | pr->off = off; | |
626 | pr->size = size; | |
627 | ||
628 | blkid_probe_reset_buffer(pr); | |
629 | ||
630 | return 0; | |
631 | } | |
632 | ||
0bffad47 KZ |
633 | /** |
634 | * blkid_do_probe: | |
635 | * @pr: prober | |
636 | * | |
637 | * Calls probing functions in all enabled chains. The superblocks chain is | |
638 | * enabled by default. The blkid_do_probe() stores result from only one | |
639 | * probing function. It's necessary to call this routine in a loop to get | |
44ef90bc KZ |
640 | * results from all probing functions in all chains. The probing is reseted |
641 | * by blkid_reset_probe() or by filter functions. | |
a0fc685c | 642 | * |
0bffad47 KZ |
643 | * This is string-based NAME=value interface only. |
644 | * | |
645 | * <example> | |
646 | * <title>basic case - use the first result only</title> | |
647 | * <programlisting> | |
a0fc685c KZ |
648 | * |
649 | * if (blkid_do_probe(pr) == 0) { | |
650 | * int nvals = blkid_probe_numof_values(pr); | |
651 | * for (n = 0; n < nvals; n++) { | |
652 | * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) | |
653 | * printf("%s = %s\n", name, data); | |
654 | * } | |
655 | * } | |
0bffad47 KZ |
656 | * </programlisting> |
657 | * </example> | |
a0fc685c | 658 | * |
0bffad47 KZ |
659 | * <example> |
660 | * <title>advanced case - probe for all signatures</title> | |
661 | * <programlisting> | |
a0fc685c KZ |
662 | * |
663 | * while (blkid_do_probe(pr) == 0) { | |
664 | * int nvals = blkid_probe_numof_values(pr); | |
665 | * ... | |
666 | * } | |
0bffad47 KZ |
667 | * </programlisting> |
668 | * </example> | |
a0fc685c | 669 | * |
0bffad47 | 670 | * See also blkid_reset_probe(). |
a0fc685c | 671 | * |
0bffad47 | 672 | * Returns: 0 on success, 1 when probing is done and -1 in case of error. |
a0fc685c | 673 | */ |
51410fc6 | 674 | int blkid_do_probe(blkid_probe pr) |
a0948ffe | 675 | { |
0bffad47 | 676 | int rc = 1; |
a0948ffe | 677 | |
0bffad47 | 678 | if (!pr) |
51410fc6 | 679 | return -1; |
a0948ffe | 680 | |
0bffad47 | 681 | do { |
44ef90bc KZ |
682 | struct blkid_chain *chn = pr->cur_chain; |
683 | ||
684 | if (!chn) | |
685 | chn = pr->cur_chain = &pr->chains[0]; | |
686 | ||
687 | /* we go to the next chain only when the previous probing | |
688 | * result was nothing (rc == 1) and when the current chain is | |
689 | * disabled or we are at end of the current chain (chain->idx + | |
690 | * 1 == sizeof chain) | |
691 | */ | |
692 | else if (rc == 1 && (chn->enabled == FALSE || | |
693 | chn->idx + 1 == chn->driver->nidinfos)) { | |
a0948ffe | 694 | |
44ef90bc | 695 | int idx = chn->driver->id + 1; |
bd635f86 KZ |
696 | |
697 | if (idx < BLKID_NCHAINS) | |
44ef90bc | 698 | chn = pr->cur_chain = &pr->chains[idx]; |
bd635f86 KZ |
699 | else |
700 | return 1; /* all chains already probed */ | |
701 | } | |
a0fc685c | 702 | |
0bffad47 | 703 | chn->binary = FALSE; /* for sure... */ |
6644688a | 704 | |
44ef90bc | 705 | DBG(DEBUG_LOWPROBE, printf("chain probe %s %s (idx=%d)\n", |
0bffad47 | 706 | chn->driver->name, |
44ef90bc KZ |
707 | chn->enabled? "ENABLED" : "DISABLED", |
708 | chn->idx)); | |
a0948ffe | 709 | |
0bffad47 | 710 | if (!chn->enabled) |
51410fc6 | 711 | continue; |
a0948ffe | 712 | |
0bffad47 KZ |
713 | /* rc: -1 = error, 0 = success, 1 = no result */ |
714 | rc = chn->driver->probe(pr, chn); | |
a0948ffe | 715 | |
0bffad47 | 716 | } while (rc == 1); |
a0948ffe | 717 | |
0bffad47 KZ |
718 | return rc; |
719 | } | |
a0948ffe | 720 | |
0bffad47 KZ |
721 | /** |
722 | * blkid_do_safeprobe: | |
723 | * @pr: prober | |
724 | * | |
725 | * This function gathers probing results from all enabled chains and checks | |
726 | * for ambivalent results (e.g. more filesystems on the device). | |
727 | * | |
728 | * This is string-based NAME=value interface only. | |
729 | * | |
730 | * Note about suberblocks chain -- the function does not check for filesystems | |
731 | * when a RAID signature is detected. The function also does not check for | |
732 | * collision between RAIDs. The first detected RAID is returned. | |
733 | * | |
734 | * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is | |
735 | * detected and -1 on case of error. | |
736 | */ | |
737 | int blkid_do_safeprobe(blkid_probe pr) | |
738 | { | |
739 | int i, count = 0, rc = 0; | |
a0948ffe | 740 | |
0bffad47 KZ |
741 | if (!pr) |
742 | return -1; | |
a0948ffe | 743 | |
0bffad47 KZ |
744 | for (i = 0; i < BLKID_NCHAINS; i++) { |
745 | struct blkid_chain *chn; | |
a0948ffe | 746 | |
0bffad47 KZ |
747 | chn = pr->cur_chain = &pr->chains[i]; |
748 | chn->binary = FALSE; /* for sure... */ | |
a0948ffe | 749 | |
0bffad47 KZ |
750 | DBG(DEBUG_LOWPROBE, printf("chain safeprobe %s %s\n", |
751 | chn->driver->name, | |
752 | chn->enabled? "ENABLED" : "DISABLED")); | |
753 | ||
754 | if (!chn->enabled) | |
755 | continue; | |
756 | ||
757 | chn->idx = - 1; | |
758 | ||
759 | /* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */ | |
760 | rc = chn->driver->safeprobe(pr, chn); | |
761 | if (rc < 0) | |
762 | goto done; /* error */ | |
763 | if (rc == 0) | |
764 | count++; /* success */ | |
51410fc6 | 765 | } |
0bffad47 KZ |
766 | |
767 | done: | |
768 | pr->cur_chain = NULL; | |
769 | if (rc < 0) | |
770 | return rc; | |
771 | return count ? 0 : 1; | |
a0948ffe KZ |
772 | } |
773 | ||
0bffad47 KZ |
774 | /** |
775 | * blkid_do_fullprobe: | |
776 | * @pr: prober | |
777 | * | |
778 | * This function gathers probing results from all enabled chains. Same as | |
779 | * blkid_so_safeprobe() but does not check for collision between probing | |
780 | * result. | |
781 | * | |
782 | * This is string-based NAME=value interface only. | |
7103157c | 783 | * |
0bffad47 | 784 | * Returns: 0 on success, 1 if nothing is detected or -1 on case of error. |
a2f01a1c | 785 | */ |
0bffad47 | 786 | int blkid_do_fullprobe(blkid_probe pr) |
a2f01a1c | 787 | { |
0bffad47 | 788 | int i, count = 0, rc = 0; |
7103157c | 789 | |
0bffad47 KZ |
790 | if (!pr) |
791 | return -1; | |
a2f01a1c | 792 | |
0bffad47 KZ |
793 | for (i = 0; i < BLKID_NCHAINS; i++) { |
794 | int rc; | |
795 | struct blkid_chain *chn; | |
a2f01a1c | 796 | |
0bffad47 KZ |
797 | chn = pr->cur_chain = &pr->chains[i]; |
798 | chn->binary = FALSE; /* for sure... */ | |
799 | ||
800 | DBG(DEBUG_LOWPROBE, printf("chain fullprobe %s: %s\n", | |
801 | chn->driver->name, | |
802 | chn->enabled? "ENABLED" : "DISABLED")); | |
803 | ||
804 | if (!chn->enabled) | |
805 | continue; | |
806 | ||
807 | chn->idx = - 1; | |
808 | ||
809 | /* rc: -1 = error, 0 = success, 1 = no result */ | |
810 | rc = chn->driver->probe(pr, chn); | |
811 | if (rc < 0) | |
812 | goto done; /* error */ | |
813 | if (rc == 0) | |
814 | count++; /* success */ | |
815 | } | |
816 | ||
817 | done: | |
818 | pr->cur_chain = NULL; | |
819 | if (rc < 0) | |
820 | return rc; | |
821 | return count ? 0 : 1; | |
a2f01a1c KZ |
822 | } |
823 | ||
ce011388 KZ |
824 | /* same sa blkid_probe_get_buffer() but works with 512-sectors */ |
825 | unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) | |
826 | { | |
827 | return pr ? blkid_probe_get_buffer(pr, | |
828 | ((blkid_loff_t) sector) << 9, 0x200) : NULL; | |
829 | } | |
830 | ||
9bdf6885 | 831 | struct blkid_prval *blkid_probe_assign_value( |
51410fc6 | 832 | blkid_probe pr, const char *name) |
a0948ffe | 833 | { |
51410fc6 | 834 | struct blkid_prval *v; |
a0948ffe | 835 | |
51410fc6 KZ |
836 | if (!name) |
837 | return NULL; | |
924fe747 | 838 | if (pr->nvals >= BLKID_NVALS) |
51410fc6 | 839 | return NULL; |
a0948ffe | 840 | |
51410fc6 KZ |
841 | v = &pr->vals[pr->nvals]; |
842 | v->name = name; | |
9bdf6885 | 843 | v->chain = pr->cur_chain; |
51410fc6 | 844 | pr->nvals++; |
6644688a | 845 | |
9bdf6885 KZ |
846 | DBG(DEBUG_LOWPROBE, |
847 | printf("assigning %s [%s]\n", name, v->chain->driver->name)); | |
51410fc6 | 848 | return v; |
a0948ffe KZ |
849 | } |
850 | ||
51410fc6 KZ |
851 | int blkid_probe_set_value(blkid_probe pr, const char *name, |
852 | unsigned char *data, size_t len) | |
a0948ffe | 853 | { |
51410fc6 | 854 | struct blkid_prval *v; |
a0948ffe | 855 | |
51410fc6 KZ |
856 | if (len > BLKID_PROBVAL_BUFSIZ) |
857 | len = BLKID_PROBVAL_BUFSIZ; | |
a0948ffe | 858 | |
51410fc6 KZ |
859 | v = blkid_probe_assign_value(pr, name); |
860 | if (!v) | |
861 | return -1; | |
a0948ffe | 862 | |
51410fc6 KZ |
863 | memcpy(v->data, data, len); |
864 | v->len = len; | |
a0948ffe KZ |
865 | return 0; |
866 | } | |
867 | ||
51410fc6 KZ |
868 | int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, |
869 | const char *fmt, va_list ap) | |
a0948ffe | 870 | { |
51410fc6 KZ |
871 | struct blkid_prval *v; |
872 | size_t len; | |
a0948ffe | 873 | |
51410fc6 KZ |
874 | v = blkid_probe_assign_value(pr, name); |
875 | if (!v) | |
876 | return -1; | |
a0948ffe | 877 | |
51410fc6 | 878 | len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); |
a0948ffe | 879 | |
51410fc6 KZ |
880 | if (len <= 0) { |
881 | pr->nvals--; /* reset the latest assigned value */ | |
882 | return -1; | |
a0948ffe | 883 | } |
51410fc6 | 884 | v->len = len + 1; |
a0948ffe KZ |
885 | return 0; |
886 | } | |
887 | ||
cc33d693 KZ |
888 | int blkid_probe_sprintf_value(blkid_probe pr, const char *name, |
889 | const char *fmt, ...) | |
890 | { | |
891 | int rc; | |
892 | va_list ap; | |
893 | ||
894 | va_start(ap, fmt); | |
895 | rc = blkid_probe_vsprintf_value(pr, name, fmt, ap); | |
896 | va_end(ap); | |
897 | ||
898 | return rc; | |
899 | } | |
900 | ||
b3ee97a3 KZ |
901 | /** |
902 | * blkid_probe_get_devno: | |
903 | * @pr: probe | |
904 | * | |
905 | * Returns: block device number, or 0 for regilar files. | |
906 | */ | |
907 | dev_t blkid_probe_get_devno(blkid_probe pr) | |
908 | { | |
909 | if (!pr->devno) { | |
910 | struct stat sb; | |
911 | ||
c1ba7962 CC |
912 | if (fstat(pr->fd, &sb) == 0 && |
913 | (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))) | |
b3ee97a3 KZ |
914 | pr->devno = sb.st_rdev; |
915 | } | |
916 | return pr->devno; | |
917 | } | |
918 | ||
919 | /** | |
920 | * blkid_probe_get_size: | |
921 | * @pr: probe | |
922 | * | |
923 | * Returns: block device (or file) size in bytes or -1 in case of error. | |
924 | */ | |
925 | blkid_loff_t blkid_probe_get_size(blkid_probe pr) | |
926 | { | |
927 | return pr ? pr->size : -1; | |
928 | } | |
929 | ||
930 | /** | |
931 | * blkid_probe_get_sectorsize: | |
932 | * @pr: probe | |
933 | * | |
2a1dfbad | 934 | * Returns: block device logical sector size (BLKSSZGET ioctl, default 512). |
b3ee97a3 KZ |
935 | */ |
936 | unsigned int blkid_probe_get_sectorsize(blkid_probe pr) | |
937 | { | |
938 | if (!pr) | |
939 | return DEFAULT_SECTOR_SIZE; /*... and good luck! */ | |
940 | if (pr->blkssz) | |
941 | return pr->blkssz; | |
942 | if (!pr->mode) { | |
943 | struct stat st; | |
944 | ||
945 | if (fstat(pr->fd, &st)) | |
946 | goto fallback; | |
947 | pr->mode = st.st_mode; | |
948 | } | |
949 | if (S_ISBLK(pr->mode)) { | |
950 | if (blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz)) | |
951 | goto fallback; | |
952 | ||
953 | return pr->blkssz; | |
954 | } | |
955 | ||
956 | fallback: | |
957 | pr->blkssz = DEFAULT_SECTOR_SIZE; | |
958 | return pr->blkssz; | |
959 | } | |
960 | ||
4d72b337 KZ |
961 | /** |
962 | * blkid_probe_numof_values: | |
963 | * @pr: probe | |
964 | * | |
965 | * Returns: number of values in probing result or -1 in case of error. | |
966 | */ | |
967 | int blkid_probe_numof_values(blkid_probe pr) | |
968 | { | |
969 | if (!pr) | |
970 | return -1; | |
971 | return pr->nvals; | |
972 | } | |
973 | ||
81f73792 KZ |
974 | /** |
975 | * blkid_probe_get_value: | |
976 | * @pr: probe | |
977 | * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1 | |
978 | * @name: pointer to return value name or NULL | |
979 | * @data: pointer to return value data or NULL | |
980 | * @len: pointer to return value length or NULL | |
981 | * | |
c2dbd49b KZ |
982 | * Note, the @len returns length of the @data, including the terminating |
983 | * '\0' character. | |
984 | * | |
81f73792 KZ |
985 | * Returns: 0 on success, or -1 in case of error. |
986 | */ | |
51410fc6 | 987 | int blkid_probe_get_value(blkid_probe pr, int num, const char **name, |
6d042d0d | 988 | const char **data, size_t *len) |
a0948ffe | 989 | { |
81f73792 | 990 | struct blkid_prval *v = __blkid_probe_get_value(pr, num); |
a0948ffe | 991 | |
81f73792 | 992 | if (!v) |
51410fc6 | 993 | return -1; |
51410fc6 KZ |
994 | if (name) |
995 | *name = v->name; | |
996 | if (data) | |
6d042d0d | 997 | *data = (char *) v->data; |
51410fc6 KZ |
998 | if (len) |
999 | *len = v->len; | |
6644688a KZ |
1000 | |
1001 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
a0948ffe KZ |
1002 | return 0; |
1003 | } | |
a0948ffe | 1004 | |
81f73792 KZ |
1005 | /** |
1006 | * blkid_probe_lookup_value: | |
1007 | * @pr: probe | |
1008 | * @name: name of value | |
1009 | * @data: pointer to return value data or NULL | |
1010 | * @len: pointer to return value length or NULL | |
1011 | * | |
c2dbd49b KZ |
1012 | * Note, the @len returns length of the @data, including the terminating |
1013 | * '\0' character. | |
1014 | * | |
81f73792 KZ |
1015 | * Returns: 0 on success, or -1 in case of error. |
1016 | */ | |
51410fc6 | 1017 | int blkid_probe_lookup_value(blkid_probe pr, const char *name, |
6d042d0d | 1018 | const char **data, size_t *len) |
a0948ffe | 1019 | { |
81f73792 | 1020 | struct blkid_prval *v = __blkid_probe_lookup_value(pr, name); |
a0948ffe | 1021 | |
81f73792 | 1022 | if (!v) |
51410fc6 | 1023 | return -1; |
81f73792 KZ |
1024 | if (data) |
1025 | *data = (char *) v->data; | |
1026 | if (len) | |
1027 | *len = v->len; | |
1028 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
1029 | return 0; | |
a0948ffe KZ |
1030 | } |
1031 | ||
81f73792 KZ |
1032 | /** |
1033 | * blkid_probe_has_value: | |
1034 | * @pr: probe | |
1035 | * @name: name of value | |
1036 | * | |
1037 | * Returns: 1 if value exist in probing result, otherwise 0. | |
1038 | */ | |
51410fc6 | 1039 | int blkid_probe_has_value(blkid_probe pr, const char *name) |
a0948ffe | 1040 | { |
51410fc6 KZ |
1041 | if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) |
1042 | return 1; | |
a0948ffe KZ |
1043 | return 0; |
1044 | } | |
1045 | ||
1c1726a7 KZ |
1046 | struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) |
1047 | { | |
1048 | if (pr == NULL || num < 0 || num >= pr->nvals) | |
1049 | return NULL; | |
1050 | ||
1051 | return &pr->vals[num]; | |
1052 | } | |
1053 | ||
1054 | struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) | |
1055 | { | |
1056 | int i; | |
1057 | ||
1058 | if (pr == NULL || pr->nvals == 0 || name == NULL) | |
1059 | return NULL; | |
1060 | ||
1061 | for (i = 0; i < pr->nvals; i++) { | |
1062 | struct blkid_prval *v = &pr->vals[i]; | |
1063 | ||
1064 | if (v->name && strcmp(name, v->name) == 0) { | |
1065 | DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); | |
1066 | return v; | |
1067 | } | |
1068 | } | |
1069 | return NULL; | |
1070 | } | |
1071 | ||
201529bd KZ |
1072 | |
1073 | /* converts DCE UUID (uuid[16]) to human readable string | |
1074 | * - the @len should be always 37 */ | |
1075 | void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) | |
1076 | { | |
1077 | #ifdef HAVE_LIBUUID | |
1078 | uuid_unparse(uuid, str); | |
1079 | #else | |
1080 | snprintf(str, len, | |
1081 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
1082 | uuid[0], uuid[1], uuid[2], uuid[3], | |
1083 | uuid[4], uuid[5], | |
1084 | uuid[6], uuid[7], | |
1085 | uuid[8], uuid[9], | |
1086 | uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); | |
1087 | #endif | |
1088 | } | |
1089 | ||
c2dbd49b KZ |
1090 | |
1091 | /* Removes whitespace from the right-hand side of a string (trailing | |
1092 | * whitespace). | |
1093 | * | |
1094 | * Returns size of the new string (without \0). | |
1095 | */ | |
1096 | size_t blkid_rtrim_whitespace(unsigned char *str) | |
1097 | { | |
1098 | size_t i = strlen((char *) str); | |
1099 | ||
1100 | while (i--) { | |
1101 | if (!isspace(str[i])) | |
1102 | break; | |
1103 | } | |
1104 | str[++i] = '\0'; | |
1105 | return i; | |
1106 | } | |
1107 |