Coverage Report

Created: 2026-09-03 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/util-linux/libblkid/src/partitions/partitions.c
Line
Count
Source
1
/*
2
 * partitions - partition tables parsing
3
 *
4
 * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
5
 *
6
 * This file may be redistributed under the terms of the
7
 * GNU Lesser General Public License.
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
#include <sys/stat.h>
18
#include <errno.h>
19
#include <stdint.h>
20
#include <inttypes.h>
21
#include <stdarg.h>
22
23
#include "partitions.h"
24
#include "sysfs.h"
25
#include "strutils.h"
26
#include "cctype.h"
27
28
/**
29
 * SECTION: partitions
30
 * @title: Partitions probing
31
 * @short_description: partitions tables detection and parsing
32
 *
33
 * This chain supports binary and NAME=value interfaces, but complete PT
34
 * description is provided by binary interface only. The libblkid prober is
35
 * compatible with kernel partition tables parser. The parser does not return
36
 * empty (size=0) partitions or special hidden partitions.
37
 *
38
 * NAME=value interface, supported tags:
39
 *
40
 * @PTTYPE: partition table type (dos, gpt, etc.).
41
 *
42
 * @PTUUID: partition table id (uuid for gpt, hex for dos).
43
44
 * @PART_ENTRY_SCHEME: partition table type
45
 *
46
 * @PART_ENTRY_NAME: partition name (gpt and mac only)
47
 *
48
 * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR)
49
 *
50
 * @PART_ENTRY_TYPE: partition type, 0xNN (e.g. 0x82) or type UUID (gpt only) or type string (mac)
51
 *
52
 * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or  attributes (e.g. gpt attributes)
53
 *
54
 * @PART_ENTRY_NUMBER: partition number
55
 *
56
 * @PART_ENTRY_OFFSET: the begin of the partition
57
 *
58
 * @PART_ENTRY_SIZE: size of the partition
59
 *
60
 * @PART_ENTRY_DISK: whole-disk maj:min
61
 *
62
 * Example:
63
 *
64
 * <informalexample>
65
 *  <programlisting>
66
 * blkid_probe pr;
67
 * const char *ptname;
68
 *
69
 * pr = blkid_new_probe_from_filename(devname);
70
 * if (!pr)
71
 *  err("%s: failed to open device", devname);
72
 *
73
 * blkid_probe_enable_partitions(pr, TRUE);
74
 * blkid_do_fullprobe(pr);
75
 *
76
 * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL);
77
 * printf("%s partition type detected\n", pttype);
78
 *
79
 * blkid_free_probe(pr);
80
 *
81
 * // don't forget to check return codes in your code!
82
 *  </programlisting>
83
 * </informalexample>
84
 *
85
 * Binary interface:
86
 *
87
 * <informalexample>
88
 *  <programlisting>
89
 * blkid_probe pr;
90
 * blkid_partlist ls;
91
 * int nparts = 0, i;
92
 *
93
 * pr = blkid_new_probe_from_filename(devname);
94
 * if (!pr)
95
 *  err("%s: failed to open device", devname);
96
 * ls = blkid_probe_get_partitions(pr);
97
 * if (ls)
98
 *  nparts = blkid_partlist_numof_partitions(ls);
99
 *
100
 * for (i = 0; i < nparts; i++) {
101
 *      blkid_partition par = blkid_partlist_get_partition(ls, i);
102
 *      printf("#%d: %llu %llu  0x%x",
103
 *               blkid_partition_get_partno(par),
104
 *               blkid_partition_get_start(par),
105
 *               blkid_partition_get_size(par),
106
 *               blkid_partition_get_type(par));
107
 * }
108
 *
109
 * blkid_free_probe(pr);
110
 *
111
 * // don't forget to check return codes in your code!
112
 *  </programlisting>
113
 * </informalexample>
114
 */
115
116
/*
117
 * Chain driver function
118
 */
119
static int partitions_probe(blkid_probe pr, struct blkid_chain *chn);
120
static void partitions_free_data(blkid_probe pr, void *data);
121
122
/*
123
 * Partitions chain probing functions
124
 */
125
static const struct blkid_idinfo *idinfos[] =
126
{
127
  &aix_pt_idinfo,
128
  &sgi_pt_idinfo,
129
  &sun_pt_idinfo,
130
  &dos_pt_idinfo,
131
  &gpt_pt_idinfo,
132
  &pmbr_pt_idinfo,  /* always after GPT */
133
  &mac_pt_idinfo,
134
  &ultrix_pt_idinfo,
135
  &bsd_pt_idinfo,
136
  &unixware_pt_idinfo,
137
  &solaris_x86_pt_idinfo,
138
  &minix_pt_idinfo,
139
  &atari_pt_idinfo,
140
  &dasd_pt_idinfo,
141
};
142
143
/*
144
 * Driver definition
145
 */
146
const struct blkid_chaindrv partitions_drv = {
147
  .id           = BLKID_CHAIN_PARTS,
148
  .name         = "partitions",
149
  .dflt_enabled = FALSE,
150
  .idinfos      = idinfos,
151
  .nidinfos     = ARRAY_SIZE(idinfos),
152
  .has_fltr     = TRUE,
153
  .probe        = partitions_probe,
154
  .safeprobe    = partitions_probe,
155
  .free_data    = partitions_free_data
156
};
157
158
159
/*
160
 * For compatibility with the rest of libblkid API (with the old high-level
161
 * API) we use completely opaque typedefs for all structs. Don't forget that
162
 * the final blkid_* types are pointers! See blkid.h.
163
 *
164
 * [Just for the record, I hate typedef for pointers --kzak]
165
 */
166
167
/* exported as opaque type "blkid_parttable" */
168
struct blkid_struct_parttable {
169
  const char  *type;    /* partition table type */
170
  uint64_t  offset;   /* begin of the partition table (in bytes) */
171
  int   nparts;   /* number of partitions */
172
  blkid_partition parent;   /* parent of nested partition table */
173
  char    id[UUID_STR_LEN]; /* PT identifier (e.g. UUID for GPT) */
174
175
  struct list_head t_tabs;  /* all tables */
176
};
177
178
/* exported as opaque type "blkid_partition" */
179
struct blkid_struct_partition {
180
  uint64_t  start;    /* begin of the partition (512-bytes sectors) */
181
  uint64_t  size;   /* size of the partitions (512-bytes sectors) */
182
183
  int   type;   /* partition type */
184
  char    typestr[UUID_STR_LEN]; /* partition type string (GPT and Mac) */
185
186
  unsigned long long flags; /* partition flags / attributes */
187
188
  int   partno;   /* partition number */
189
  char    uuid[UUID_STR_LEN]; /* UUID (when supported by PT), e.g. GPT */
190
  unsigned char name[128];  /* Partition in UTF8 name (when supported by PT), e.g. Mac */
191
192
  blkid_parttable tab;    /* partition table */
193
};
194
195
/* exported as opaque type "blkid_partlist" */
196
struct blkid_struct_partlist {
197
  int   next_partno;  /* next partition number */
198
  blkid_partition next_parent;  /* next parent if parsing nested PT */
199
200
  int   nparts;   /* number of partitions */
201
  int   nparts_max; /* max.number of partitions */
202
  blkid_partition *parts;   /* array of pointers to partitions */
203
204
  struct list_head l_tabs;  /* list of partition tables */
205
};
206
207
static int blkid_partitions_probe_partition(blkid_probe pr);
208
209
/**
210
 * blkid_probe_enable_partitions:
211
 * @pr: probe
212
 * @enable: TRUE/FALSE
213
 *
214
 * Enables/disables the partitions probing for non-binary interface.
215
 *
216
 * Returns: 0 on success, or -1 in case of error.
217
 */
218
int blkid_probe_enable_partitions(blkid_probe pr, int enable)
219
15.6k
{
220
15.6k
  pr->chains[BLKID_CHAIN_PARTS].enabled = enable;
221
15.6k
  return 0;
222
15.6k
}
223
224
/**
225
 * blkid_probe_set_partitions_flags:
226
 * @pr: prober
227
 * @flags: BLKID_PARTS_* flags
228
 *
229
 * Sets probing flags to the partitions prober. This function is optional.
230
 *
231
 * Returns: 0 on success, or -1 in case of error.
232
 */
233
int blkid_probe_set_partitions_flags(blkid_probe pr, int flags)
234
15.6k
{
235
15.6k
  pr->chains[BLKID_CHAIN_PARTS].flags = flags;
236
15.6k
  return 0;
237
15.6k
}
238
239
int blkid_probe_get_partitions_flags(blkid_probe pr)
240
3
{
241
3
  return pr->chains[BLKID_CHAIN_PARTS].flags;
242
3
}
243
244
/**
245
 * blkid_probe_reset_partitions_filter:
246
 * @pr: prober
247
 *
248
 * Resets partitions probing filter
249
 *
250
 * Returns: 0 on success, or -1 in case of error.
251
 */
252
int blkid_probe_reset_partitions_filter(blkid_probe pr)
253
0
{
254
0
  return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS);
255
0
}
256
257
/**
258
 * blkid_probe_invert_partitions_filter:
259
 * @pr: prober
260
 *
261
 * Inverts partitions probing filter
262
 *
263
 * Returns: 0 on success, or -1 in case of error.
264
 */
265
int blkid_probe_invert_partitions_filter(blkid_probe pr)
266
0
{
267
0
  return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS);
268
0
}
269
270
/**
271
 * blkid_probe_filter_partitions_type:
272
 * @pr: prober
273
 * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
274
 * @names: NULL terminated array of probing function names (e.g. "vfat").
275
 *
276
 *  %BLKID_FLTR_NOTIN  - probe for all items which are NOT IN @names
277
 *
278
 *  %BLKID_FLTR_ONLYIN - probe for items which are IN @names
279
 *
280
 * Returns: 0 on success, or -1 in case of error.
281
 */
282
int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[])
283
0
{
284
0
  return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names);
285
0
}
286
287
/**
288
 * blkid_probe_get_partitions:
289
 * @pr: probe
290
 *
291
 * This is a binary interface for partitions. See also blkid_partlist_*
292
 * functions.
293
 *
294
 * This function is independent on blkid_do_[safe,full]probe() and
295
 * blkid_probe_enable_partitions() calls.
296
 *
297
 * WARNING: the returned object will be overwritten by the next
298
 *          blkid_probe_get_partitions() call for the same @pr. If you want to
299
 *          use more blkid_partlist objects in the same time you have to create
300
 *          more blkid_probe handlers (see blkid_new_probe()).
301
 *
302
 * Returns: list of partitions, or NULL in case of error.
303
 */
304
blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
305
3
{
306
3
  return (blkid_partlist) blkid_probe_get_binary_data(pr,
307
3
      &pr->chains[BLKID_CHAIN_PARTS]);
308
3
}
309
310
/* for internal usage only */
311
blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
312
1.38k
{
313
1.38k
  return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data;
314
1.38k
}
315
316
static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls)
317
0
{
318
0
  pr->chains[BLKID_CHAIN_PARTS].data = ls;
319
0
}
320
321
static void ref_parttable(blkid_parttable tab)
322
9
{
323
9
  if (tab)
324
9
    tab->nparts++;
325
9
}
326
327
static void unref_parttable(blkid_parttable tab)
328
9
{
329
9
  if (!tab)
330
0
    return;
331
332
9
  tab->nparts--;
333
9
  if (tab->nparts <= 0) {
334
3
    list_del(&tab->t_tabs);
335
3
    free(tab);
336
3
  }
337
9
}
338
339
/* free all allocated parttables */
340
static void free_parttables(blkid_partlist ls)
341
6
{
342
6
  if (!ls || !ls->l_tabs.next)
343
3
    return;
344
345
  /* remove unassigned partition tables */
346
12
  while (!list_empty(&ls->l_tabs)) {
347
9
    blkid_parttable tab = list_entry(ls->l_tabs.next,
348
9
          struct blkid_struct_parttable, t_tabs);
349
9
    unref_parttable(tab);
350
9
  }
351
3
}
352
353
static void reset_partlist(blkid_partlist ls)
354
3
{
355
3
  if (!ls)
356
0
    return;
357
358
3
  free_parttables(ls);
359
360
3
  if (ls->next_partno) {
361
    /* already initialized - free individually allocated partitions */
362
0
    int i, tmp_nparts_max = ls->nparts_max;
363
0
    blkid_partition *tmp_parts = ls->parts;
364
365
0
    for (i = 0; i < ls->nparts; i++)
366
0
      free(ls->parts[i]);
367
368
0
    memset(ls, 0, sizeof(struct blkid_struct_partlist));
369
370
0
    ls->nparts_max = tmp_nparts_max;
371
0
    ls->parts = tmp_parts;
372
0
  }
373
374
3
  ls->nparts = 0;
375
3
  ls->next_partno = 1;
376
3
  INIT_LIST_HEAD(&ls->l_tabs);
377
378
3
  DBG(LOWPROBE, ul_debug("partlist reset"));
379
3
}
380
381
static blkid_partlist partitions_init_data(struct blkid_chain *chn)
382
3
{
383
3
  blkid_partlist ls;
384
385
3
  if (chn->data)
386
0
    ls = (blkid_partlist) chn->data;
387
3
  else {
388
    /* allocate the new list of partitions */
389
3
    ls = calloc(1, sizeof(struct blkid_struct_partlist));
390
3
    if (!ls)
391
0
      return NULL;
392
3
    chn->data = (void *) ls;
393
3
  }
394
395
3
  reset_partlist(ls);
396
397
3
  DBG(LOWPROBE, ul_debug("parts: initialized partitions list (size=%d)", ls->nparts_max));
398
3
  return ls;
399
3
}
400
401
static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
402
         void *data)
403
23.4k
{
404
23.4k
  blkid_partlist ls = (blkid_partlist) data;
405
23.4k
  int i;
406
407
23.4k
  if (!ls)
408
23.4k
    return;
409
410
3
  free_parttables(ls);
411
412
  /* deallocate partitions and partlist */
413
12
  for (i = 0; i < ls->nparts; i++)
414
9
    free(ls->parts[i]);
415
3
  free(ls->parts);
416
3
  free(ls);
417
3
}
418
419
blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
420
        const char *type, uint64_t offset)
421
3
{
422
3
  blkid_parttable tab;
423
424
3
  tab = calloc(1, sizeof(struct blkid_struct_parttable));
425
3
  if (!tab)
426
0
    return NULL;
427
3
  tab->type = type;
428
3
  tab->offset = offset;
429
3
  tab->parent = ls->next_parent;
430
431
3
  INIT_LIST_HEAD(&tab->t_tabs);
432
3
  list_add_tail(&tab->t_tabs, &ls->l_tabs);
433
434
3
  DBG(LOWPROBE, ul_debug("parts: create a new partition table "
435
3
           "(type=%s, offset=%"PRIu64")", type, offset));
436
3
  return tab;
437
3
}
438
439
static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
440
9
{
441
9
  blkid_partition par;
442
443
9
  if (ls->nparts + 1 > ls->nparts_max) {
444
    /* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
445
     * generic Linux machine -- let's start with 32 partitions.
446
     */
447
3
    void *tmp = reallocarray(ls->parts, ls->nparts_max + 32,
448
3
           sizeof(blkid_partition));
449
3
    if (!tmp)
450
0
      return NULL;
451
3
    ls->parts = tmp;
452
3
    ls->nparts_max += 32;
453
3
  }
454
455
9
  par = calloc(1, sizeof(struct blkid_struct_partition));
456
9
  if (!par)
457
0
    return NULL;
458
9
  ls->parts[ls->nparts++] = par;
459
460
9
  ref_parttable(tab);
461
9
  par->tab = tab;
462
9
  par->partno = blkid_partlist_increment_partno(ls);
463
464
9
  return par;
465
9
}
466
467
blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
468
          blkid_parttable tab, uint64_t start, uint64_t size)
469
9
{
470
9
  blkid_partition par = new_partition(ls, tab);
471
472
9
  if (!par)
473
0
    return NULL;
474
475
9
  par->start = start;
476
9
  par->size = size;
477
478
9
  DBG(LOWPROBE, ul_debug("parts: add partition (start=%"
479
9
    PRIu64 ", size=%" PRIu64 ")",
480
9
    par->start, par->size));
481
9
  return par;
482
9
}
483
484
/* can be used to modify used partitions numbers (for example for logical partitions) */
485
int blkid_partlist_set_partno(blkid_partlist ls, int partno)
486
0
{
487
0
  if (!ls)
488
0
    return -1;
489
0
  ls->next_partno = partno;
490
0
  return 0;
491
0
}
492
493
int blkid_partlist_increment_partno(blkid_partlist ls)
494
384
{
495
384
  return ls ? ls->next_partno++ : -1;
496
384
}
497
498
/* can be used to set "parent" for the next nested partition */
499
static int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par)
500
0
{
501
0
  if (!ls)
502
0
    return -1;
503
0
  ls->next_parent = par;
504
0
  return 0;
505
0
}
506
507
blkid_partition blkid_partlist_get_parent(blkid_partlist ls)
508
0
{
509
0
  if (!ls)
510
0
    return NULL;
511
0
  return ls->next_parent;
512
0
}
513
514
int blkid_partitions_need_typeonly(blkid_probe pr)
515
2.65k
{
516
2.65k
  struct blkid_chain *chn = blkid_probe_get_chain(pr);
517
518
2.65k
  return chn && chn->data && chn->binary ? FALSE : TRUE;
519
2.65k
}
520
521
/* get private chain flags */
522
int blkid_partitions_get_flags(blkid_probe pr)
523
28.1k
{
524
28.1k
  struct blkid_chain *chn = blkid_probe_get_chain(pr);
525
526
28.1k
  return chn ? chn->flags : 0;
527
28.1k
}
528
529
/* check if @start and @size are within @par partition */
530
int blkid_is_nested_dimension(blkid_partition par,
531
      uint64_t start, uint64_t size)
532
0
{
533
0
  uint64_t pstart;
534
0
  uint64_t psize;
535
536
0
  if (!par)
537
0
    return 0;
538
539
0
  pstart = blkid_partition_get_start(par);
540
0
  psize = blkid_partition_get_size(par);
541
542
0
  if (start < pstart || start + size > pstart + psize)
543
0
    return 0;
544
545
0
  return 1;
546
0
}
547
548
static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id,
549
      struct blkid_chain *chn)
550
158k
{
551
158k
  const struct blkid_idmag *mag = NULL;
552
158k
  uint64_t off;
553
158k
  int rc = BLKID_PROBE_NONE;   /* default is nothing */
554
555
158k
  if (pr->size <= 0 || (id->minsz && (unsigned)id->minsz > pr->size))
556
10.0k
    goto nothing;  /* the device is too small */
557
148k
  if (pr->flags & BLKID_FL_NOSCAN_DEV)
558
0
    goto nothing;
559
560
148k
  rc = blkid_probe_get_idmag(pr, id, &off, &mag);
561
148k
  if (rc != BLKID_PROBE_OK)
562
94.8k
    goto nothing;
563
564
  /* final check by probing function */
565
53.1k
  if (id->probefunc) {
566
53.1k
    DBG(LOWPROBE, ul_debug(
567
53.1k
      "%s: ---> call probefunc()", id->name));
568
53.1k
    errno = 0;
569
53.1k
    rc = id->probefunc(pr, mag);
570
53.1k
    blkid_probe_prune_buffers(pr);
571
53.1k
    if (rc < 0) {
572
      /* reset after error */
573
0
      reset_partlist(blkid_probe_get_partlist(pr));
574
0
      if (chn && !chn->binary)
575
0
        blkid_probe_chain_reset_values(pr, chn);
576
0
      DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d",
577
0
              id->name, rc));
578
0
    }
579
53.1k
    if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
580
3.67k
      rc = blkid_probe_set_magic(pr, off, mag->len,
581
3.67k
          (const unsigned char *) mag->magic);
582
583
53.1k
    DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc));
584
53.1k
  }
585
586
53.1k
  return rc;
587
588
104k
nothing:
589
104k
  return BLKID_PROBE_NONE;
590
148k
}
591
592
/*
593
 * The blkid_do_probe() backend.
594
 */
595
static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
596
13.7k
{
597
13.7k
  int rc = BLKID_PROBE_NONE;
598
13.7k
  size_t i;
599
600
13.7k
  if (!pr || chn->idx < -1)
601
0
    return -EINVAL;
602
603
13.7k
  blkid_probe_chain_reset_values(pr, chn);
604
605
13.7k
  if (pr->flags & BLKID_FL_NOSCAN_DEV)
606
0
    return BLKID_PROBE_NONE;
607
608
13.7k
  if (chn->binary)
609
3
    partitions_init_data(chn);
610
611
13.7k
  if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
612
0
    goto details_only;
613
614
13.7k
  DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]",
615
13.7k
    chn->idx));
616
617
13.7k
  i = chn->idx < 0 ? 0 : chn->idx + 1U;
618
619
168k
  for ( ; i < ARRAY_SIZE(idinfos); i++) {
620
158k
    const char *name;
621
622
158k
    chn->idx = i;
623
624
    /* apply filter */
625
158k
    if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
626
0
      continue;
627
628
    /* apply checks from idinfo */
629
158k
    rc = idinfo_probe(pr, idinfos[i], chn);
630
158k
    if (rc < 0)
631
0
      break;
632
158k
    if (rc != BLKID_PROBE_OK)
633
154k
      continue;
634
635
3.75k
    name = idinfos[i]->name;
636
637
3.75k
    if (!chn->binary)
638
      /*
639
       * Non-binary interface, set generic variables. Note
640
       * that the another variables could be set in prober
641
       * functions.
642
       */
643
3.75k
      blkid_probe_set_value(pr, "PTTYPE",
644
3.75k
            (const unsigned char *) name,
645
3.75k
            strlen(name) + 1);
646
647
3.75k
    DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
648
3.75k
      name, chn->idx));
649
3.75k
    rc = BLKID_PROBE_OK;
650
3.75k
    break;
651
158k
  }
652
653
13.7k
  if (rc != BLKID_PROBE_OK) {
654
9.99k
    DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
655
9.99k
      rc, chn->idx));
656
9.99k
  }
657
658
13.7k
details_only:
659
  /*
660
   * Gather PART_ENTRY_* values if the current device is a partition.
661
   */
662
13.7k
  if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
663
13.7k
      (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
664
665
3
    int xrc = blkid_partitions_probe_partition(pr);
666
667
    /* partition entry probing is optional, and "not-found" from
668
     * this sub-probing must not to overwrite previous success. */
669
3
    if (xrc < 0)
670
0
      rc = xrc;     /* always propagate errors */
671
3
    else if (rc == BLKID_PROBE_NONE)
672
3
      rc = xrc;
673
3
  }
674
675
13.7k
  DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]",  rc));
676
13.7k
  return rc;
677
13.7k
}
678
679
/* Probe for nested partition table within the parental partition */
680
int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
681
    const struct blkid_idinfo *id)
682
0
{
683
0
  blkid_probe prc;
684
0
  int rc;
685
0
  blkid_partlist ls;
686
0
  uint64_t sz, off;
687
688
0
  DBG(LOWPROBE, ul_debug(
689
0
    "parts: ----> %s subprobe requested)",
690
0
    id->name));
691
692
0
  if (!pr || !parent || !parent->size)
693
0
    return -EINVAL;
694
0
  if (pr->flags & BLKID_FL_NOSCAN_DEV)
695
0
    return BLKID_PROBE_NONE;
696
697
  /* range defined by parent */
698
0
  sz = parent->size << 9;
699
0
  off = parent->start << 9;
700
701
0
  if (off < pr->off || pr->off + pr->size < off + sz) {
702
0
    DBG(LOWPROBE, ul_debug(
703
0
      "ERROR: parts: <---- '%s' subprobe: overflow detected.",
704
0
      id->name));
705
0
    return -ENOSPC;
706
0
  }
707
708
  /* create private prober */
709
0
  prc = blkid_clone_probe(pr);
710
0
  if (!prc)
711
0
    return -ENOMEM;
712
713
0
  blkid_probe_set_dimension(prc, off, sz);
714
715
  /* clone is always with reset chain, fix it */
716
0
  prc->cur_chain = blkid_probe_get_chain(pr);
717
718
  /*
719
   * Set 'parent' to the current list of the partitions and use the list
720
   * in cloned prober (so the cloned prober will extend the current list
721
   * of partitions rather than create a new).
722
   */
723
0
  ls = blkid_probe_get_partlist(pr);
724
0
  blkid_partlist_set_parent(ls, parent);
725
726
0
  blkid_probe_set_partlist(prc, ls);
727
728
0
  rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr));
729
730
0
  blkid_probe_set_partlist(prc, NULL);
731
0
  blkid_partlist_set_parent(ls, NULL);
732
733
0
  blkid_free_probe(prc);  /* free cloned prober */
734
735
0
  DBG(LOWPROBE, ul_debug(
736
0
    "parts: <---- %s subprobe done (rc=%d)",
737
0
    id->name, rc));
738
739
0
  return rc;
740
0
}
741
742
static int blkid_partitions_probe_partition(blkid_probe pr)
743
3
{
744
3
  blkid_probe disk_pr = NULL;
745
3
  blkid_partlist ls;
746
3
  blkid_partition par;
747
3
  dev_t devno;
748
749
3
  DBG(LOWPROBE, ul_debug("parts: start probing for partition entry"));
750
751
3
  if (pr->flags & BLKID_FL_NOSCAN_DEV)
752
0
    goto nothing;
753
754
3
  devno = blkid_probe_get_devno(pr);
755
3
  if (!devno)
756
0
    goto nothing;
757
758
3
  disk_pr = blkid_probe_get_wholedisk_probe(pr);
759
3
  if (!disk_pr)
760
0
    goto nothing;
761
762
  /* parse PT */
763
3
  ls = blkid_probe_get_partitions(disk_pr);
764
3
  if (!ls)
765
0
    goto nothing;
766
767
3
  par = blkid_partlist_devno_to_partition(ls, devno);
768
3
  if (!par)
769
0
    goto nothing;
770
3
  else {
771
3
    const char *v;
772
3
    blkid_parttable tab = blkid_partition_get_table(par);
773
3
    dev_t disk = blkid_probe_get_devno(disk_pr);
774
775
3
    if (tab) {
776
3
      v = blkid_parttable_get_type(tab);
777
3
      if (v)
778
3
        blkid_probe_set_value(pr, "PART_ENTRY_SCHEME",
779
3
          (const unsigned char *) v, strlen(v) + 1);
780
3
    }
781
782
3
    v = blkid_partition_get_name(par);
783
3
    if (v)
784
0
      blkid_probe_set_value(pr, "PART_ENTRY_NAME",
785
0
        (const unsigned char *) v, strlen(v) + 1);
786
787
3
    v = blkid_partition_get_uuid(par);
788
3
    if (v)
789
3
      blkid_probe_set_value(pr, "PART_ENTRY_UUID",
790
3
        (const unsigned char *) v, strlen(v) + 1);
791
792
    /* type */
793
3
    v = blkid_partition_get_type_string(par);
794
3
    if (v)
795
3
      blkid_probe_set_value(pr, "PART_ENTRY_TYPE",
796
3
        (const unsigned char *) v, strlen(v) + 1);
797
0
    else
798
0
      blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE",
799
0
        "0x%x", blkid_partition_get_type(par));
800
801
3
    if (blkid_partition_get_flags(par))
802
0
      blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS",
803
0
        "0x%llx", blkid_partition_get_flags(par));
804
805
3
    blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER",
806
3
        "%d", blkid_partition_get_partno(par));
807
808
3
    blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd",
809
3
        (intmax_t)blkid_partition_get_start(par));
810
3
    blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd",
811
3
        (intmax_t)blkid_partition_get_size(par));
812
813
3
    blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
814
3
        major(disk), minor(disk));
815
3
  }
816
817
3
  DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]"));
818
3
  return BLKID_PROBE_OK;
819
820
0
nothing:
821
0
  DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]"));
822
0
  return BLKID_PROBE_NONE;
823
824
825
3
}
826
827
/*
828
 * Returns 1 if the device is whole-disk and the area specified by @offset and
829
 * @size is covered by any partition.
830
 */
831
int blkid_probe_is_covered_by_pt(blkid_probe pr,
832
         uint64_t offset, uint64_t size)
833
0
{
834
0
  blkid_probe prc = NULL;
835
0
  blkid_partlist ls = NULL;
836
0
  uint64_t start, end;
837
0
  int nparts, i, rc = 0;
838
839
0
  DBG(LOWPROBE, ul_debug(
840
0
    "=> checking if off=%"PRIu64" size=%"PRIu64" covered by PT",
841
0
    offset, size));
842
843
0
  if (pr->flags & BLKID_FL_NOSCAN_DEV)
844
0
    goto done;
845
846
0
  prc = blkid_clone_probe(pr);
847
0
  if (!prc)
848
0
    goto done;
849
850
0
  ls = blkid_probe_get_partitions(prc);
851
0
  if (!ls)
852
0
    goto done;
853
854
0
  nparts = blkid_partlist_numof_partitions(ls);
855
0
  if (!nparts)
856
0
    goto done;
857
858
0
  end = (offset + size) >> 9;
859
0
  start = offset >> 9;
860
861
  /* check if the partition table fits into the device */
862
0
  for (i = 0; i < nparts; i++) {
863
0
    blkid_partition par = ls->parts[i];
864
865
0
    if (par->start + par->size > (pr->size >> 9)) {
866
0
      DBG(LOWPROBE, ul_debug("partition #%d overflows "
867
0
        "device (off=%" PRIu64 " size=%" PRIu64 ")",
868
0
        par->partno, par->start, par->size));
869
0
      goto done;
870
0
    }
871
0
  }
872
873
  /* check if the requested area is covered by PT */
874
0
  for (i = 0; i < nparts; i++) {
875
0
    blkid_partition par = ls->parts[i];
876
877
0
    if (start >= par->start && end <= par->start + par->size) {
878
0
      rc = 1;
879
0
      break;
880
0
    }
881
0
  }
882
0
done:
883
0
  blkid_free_probe(prc);
884
885
0
  DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT"));
886
0
  return rc;
887
0
}
888
889
/**
890
 * blkid_known_pttype:
891
 * @pttype: partition name
892
 *
893
 * Returns: 1 for known or 0 for unknown partition type.
894
 */
895
int blkid_known_pttype(const char *pttype)
896
0
{
897
0
  size_t i;
898
899
0
  if (!pttype)
900
0
    return 0;
901
902
0
  for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
903
0
    const struct blkid_idinfo *id = idinfos[i];
904
0
    if (strcmp(id->name, pttype) == 0)
905
0
      return 1;
906
0
  }
907
0
  return 0;
908
0
}
909
910
/**
911
 * blkid_partitions_get_name:
912
 * @idx: number >= 0
913
 * @name: returns name of a supported partition
914
 *
915
 * Since: 2.30
916
 *
917
 * Returns: -1 if @idx is out of range, or 0 on success.
918
 */
919
int blkid_partitions_get_name(size_t idx, const char **name)
920
0
{
921
0
  if (idx < ARRAY_SIZE(idinfos)) {
922
0
    *name = idinfos[idx]->name;
923
0
    return 0;
924
0
  }
925
0
  return -1;
926
0
}
927
928
/**
929
 * blkid_partlist_numof_partitions:
930
 * @ls: partitions list
931
 *
932
 * Returns: number of partitions in the list or -1 in case of error.
933
 */
934
int blkid_partlist_numof_partitions(blkid_partlist ls)
935
0
{
936
0
  return ls->nparts;
937
0
}
938
939
/**
940
 * blkid_partlist_get_table:
941
 * @ls: partitions list
942
 *
943
 * Returns: top-level partition table or NULL if there is not a partition table
944
 * on the device.
945
 */
946
blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
947
0
{
948
0
  if (list_empty(&ls->l_tabs))
949
0
    return NULL;
950
951
0
  return list_entry(ls->l_tabs.next,
952
0
      struct blkid_struct_parttable, t_tabs);
953
0
}
954
955
956
/**
957
 * blkid_partlist_get_partition:
958
 * @ls: partitions list
959
 * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions().
960
 *
961
 * It's possible that the list of partitions is *empty*, but there is a valid
962
 * partition table on the disk. This happen when on-disk details about
963
 * partitions are unknown or the partition table is empty.
964
 *
965
 * See also blkid_partlist_get_table().
966
 *
967
 * Returns: partition object or NULL in case or error.
968
 */
969
blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
970
0
{
971
0
  if (n < 0 || n >= ls->nparts)
972
0
    return NULL;
973
974
0
  return ls->parts[n];
975
0
}
976
977
blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start)
978
0
{
979
0
  int i, nparts;
980
0
  blkid_partition par;
981
982
0
  nparts = blkid_partlist_numof_partitions(ls);
983
0
  for (i = 0; i < nparts; i++) {
984
0
    par = blkid_partlist_get_partition(ls, i);
985
0
    if ((uint64_t) blkid_partition_get_start(par) == start)
986
0
      return par;
987
0
  }
988
0
  return NULL;
989
0
}
990
991
/**
992
 * blkid_partlist_get_partition_by_partno
993
 * @ls: partitions list
994
 * @n: the partition number (e.g. 'N' from sda'N')
995
 *
996
 * This does not assume any order of the input blkid_partlist.  And correctly
997
 * handles "out of order" partition tables.  partition N is located after
998
 * partition N+1 on the disk.
999
 *
1000
 * Returns: partition object or NULL in case or error.
1001
 */
1002
blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n)
1003
0
{
1004
0
  int i, nparts;
1005
0
  blkid_partition par;
1006
1007
0
  nparts = blkid_partlist_numof_partitions(ls);
1008
0
  for (i = 0; i < nparts; i++) {
1009
0
    par = blkid_partlist_get_partition(ls, i);
1010
0
    if (n == blkid_partition_get_partno(par))
1011
0
      return par;
1012
0
  }
1013
0
  return NULL;
1014
0
}
1015
1016
1017
/**
1018
 * blkid_partlist_devno_to_partition:
1019
 * @ls: partitions list
1020
 * @devno: requested partition
1021
 *
1022
 * This function tries to get start and size for @devno from sysfs and
1023
 * returns a partition from @ls which matches with the values from sysfs.
1024
 *
1025
 * This function is necessary when you want to make a relation between an entry
1026
 * in the partition table (@ls) and block devices in your system.
1027
 *
1028
 * Returns: partition object or NULL in case or error.
1029
 */
1030
blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
1031
3
{
1032
3
  struct path_cxt *pc;
1033
3
  uint64_t start = 0, size;
1034
3
  int i, rc, partno = 0;
1035
1036
3
  DBG(LOWPROBE, ul_debug("trying to convert devno 0x%llx to partition",
1037
3
      (long long) devno));
1038
1039
1040
3
  pc = ul_new_sysfs_path(devno, NULL, NULL);
1041
3
  if (!pc) {
1042
0
    DBG(LOWPROBE, ul_debug("failed t init sysfs context"));
1043
0
    return NULL;
1044
0
  }
1045
3
  rc = ul_path_read_u64(pc, &size, "size");
1046
3
  if (!rc) {
1047
3
    rc = ul_path_read_u64(pc, &start, "start");
1048
3
    if (rc) {
1049
      /* try to get partition number from DM uuid.
1050
       */
1051
0
      char *uuid = NULL, *tmp, *prefix;
1052
1053
0
      ul_path_read_string(pc, &uuid, "dm/uuid");
1054
0
      tmp = uuid;
1055
0
      prefix = uuid ? strsep(&tmp, "-") : NULL;
1056
1057
0
      if (prefix && c_strncasecmp(prefix, "part", 4) == 0) {
1058
0
        char *end = NULL;
1059
1060
0
        errno = 0;
1061
0
        partno = strtol(prefix + 4, &end, 10);
1062
0
        if (errno || prefix == end || (end && *end))
1063
0
          partno = 0;
1064
0
        else
1065
0
          rc = 0;   /* success */
1066
0
      }
1067
0
      free(uuid);
1068
0
    }
1069
3
  }
1070
1071
3
  ul_unref_path(pc);
1072
1073
3
  if (rc)
1074
0
    return NULL;
1075
1076
3
  if (partno) {
1077
0
    DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno));
1078
1079
    /*
1080
     * Partition mapped by kpartx does not provide "start" offset
1081
     * in /sys, but if we know partno and size of the partition
1082
     * that we can probably make the relation between the device
1083
     * and an entry in partition table.
1084
     */
1085
0
     for (i = 0; i < ls->nparts; i++) {
1086
0
       blkid_partition par = ls->parts[i];
1087
1088
0
       if (partno != blkid_partition_get_partno(par))
1089
0
         continue;
1090
1091
0
       if (size == (uint64_t)blkid_partition_get_size(par) ||
1092
0
           (blkid_partition_is_extended(par) && size <= 1024ULL))
1093
0
         return par;
1094
1095
0
     }
1096
0
     return NULL;
1097
0
  }
1098
1099
3
  DBG(LOWPROBE, ul_debug("searching by offset/size"));
1100
1101
6
  for (i = 0; i < ls->nparts; i++) {
1102
6
    blkid_partition par = ls->parts[i];
1103
1104
6
    if ((uint64_t)blkid_partition_get_start(par) == start &&
1105
3
        (uint64_t)blkid_partition_get_size(par) == size)
1106
3
      return par;
1107
1108
    /* exception for extended dos partitions */
1109
3
    if ((uint64_t)blkid_partition_get_start(par) == start &&
1110
0
        blkid_partition_is_extended(par) && size <= 1024ULL)
1111
0
      return par;
1112
1113
3
  }
1114
1115
0
  DBG(LOWPROBE, ul_debug("not found partition for device"));
1116
0
  return NULL;
1117
3
}
1118
1119
1120
int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id)
1121
3
{
1122
3
  if (!tab)
1123
0
    return -1;
1124
1125
3
  blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
1126
3
  return 0;
1127
3
}
1128
1129
int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id)
1130
0
{
1131
0
  if (!tab)
1132
0
    return -1;
1133
1134
0
  xstrncpy(tab->id, (const char *) id, sizeof(tab->id));
1135
0
  return 0;
1136
0
}
1137
1138
/* set PTUUID variable for non-binary API */
1139
int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
1140
0
{
1141
0
  struct blkid_chain *chn = blkid_probe_get_chain(pr);
1142
0
  struct blkid_prval *v;
1143
1144
0
  if (chn->binary || blkid_uuid_is_empty(uuid, 16))
1145
0
    return 0;
1146
1147
0
  v = blkid_probe_assign_value(pr, "PTUUID");
1148
0
  if (!v)
1149
0
    return -ENOMEM;
1150
1151
0
  v->len = UUID_STR_LEN;
1152
0
  v->data = calloc(1, v->len);
1153
0
  if (v->data) {
1154
0
    blkid_unparse_uuid(uuid, (char *) v->data, v->len);
1155
0
    return 0;
1156
0
  }
1157
1158
0
  blkid_probe_free_value(v);
1159
0
  return -ENOMEM;
1160
0
}
1161
1162
/* set PTUUID variable for non-binary API for tables where
1163
 * the ID is just a string */
1164
int blkid_partitions_strcpy_ptuuid(blkid_probe pr, const char *str)
1165
1.27k
{
1166
1.27k
  struct blkid_chain *chn = blkid_probe_get_chain(pr);
1167
1168
1.27k
  if (chn->binary || !str || !*str)
1169
18
    return 0;
1170
1171
1.25k
  if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1))
1172
1.25k
    return -ENOMEM;
1173
1174
0
  return 0;
1175
1.25k
}
1176
1177
/**
1178
 * blkid_parttable_get_id:
1179
 * @tab: partition table
1180
 *
1181
 * The ID is GPT disk UUID or DOS disk ID (in hex format).
1182
 *
1183
 * Returns: partition table ID (for example GPT disk UUID) or NULL
1184
 */
1185
const char *blkid_parttable_get_id(blkid_parttable tab)
1186
0
{
1187
0
  return *tab->id ? tab->id : NULL;
1188
0
}
1189
1190
1191
int blkid_partition_set_type(blkid_partition par, int type)
1192
0
{
1193
0
  par->type = type;
1194
0
  return 0;
1195
0
}
1196
1197
/**
1198
 * blkid_parttable_get_type:
1199
 * @tab: partition table
1200
 *
1201
 * Returns: partition table type (type name, e.g. "dos", "gpt", ...)
1202
 */
1203
const char *blkid_parttable_get_type(blkid_parttable tab)
1204
3
{
1205
3
  return tab->type;
1206
3
}
1207
1208
/**
1209
 * blkid_parttable_get_parent:
1210
 * @tab: partition table
1211
 *
1212
 * Returns: parent for nested partition tables or NULL.
1213
 */
1214
blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
1215
0
{
1216
0
  return tab->parent;
1217
0
}
1218
1219
/**
1220
 * blkid_parttable_get_offset:
1221
 * @tab: partition table
1222
 *
1223
 * Note the position is relative to begin of the device as defined by
1224
 * blkid_probe_set_device() for primary partition table, and relative
1225
 * to parental partition for nested partition tables.
1226
 *
1227
 * <informalexample>
1228
 *   <programlisting>
1229
 * off_t offset;
1230
 * blkid_partition parent = blkid_parttable_get_parent(tab);
1231
 *
1232
 * offset = blkid_parttable_get_offset(tab);
1233
 *
1234
 * if (parent)
1235
 *      / * 'tab' is nested partition table * /
1236
 *  offset += blkid_partition_get_start(parent);
1237
 *   </programlisting>
1238
 * </informalexample>
1239
1240
 * Returns: position (in bytes) of the partition table or -1 in case of error.
1241
 *
1242
 */
1243
blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
1244
0
{
1245
0
  return (blkid_loff_t)tab->offset;
1246
0
}
1247
1248
/**
1249
 * blkid_partition_get_table:
1250
 * @par: partition
1251
 *
1252
 * The "parttable" describes partition table. The table is usually the same for
1253
 * all partitions -- except nested partition tables.
1254
 *
1255
 * For example bsd, solaris, etc. use a nested partition table within
1256
 * standard primary dos partition:
1257
 *
1258
 * <informalexample>
1259
 *   <programlisting>
1260
 *
1261
 *  -- dos partition table
1262
 *  0: sda1     dos primary partition
1263
 *  1: sda2     dos primary partition
1264
 *     -- bsd partition table (with in sda2)
1265
 *  2:    sda5  bds partition
1266
 *  3:    sda6  bds partition
1267
 *
1268
 *   </programlisting>
1269
 * </informalexample>
1270
 *
1271
 * The library does not to use a separate partition table object for dos logical
1272
 * partitions (partitions within extended partition). It's possible to
1273
 * differentiate between logical, extended and primary partitions by
1274
 *
1275
 *  blkid_partition_is_{extended,primary,logical}().
1276
 *
1277
 * Returns: partition table object or NULL in case of error.
1278
 */
1279
blkid_parttable blkid_partition_get_table(blkid_partition par)
1280
3
{
1281
3
  return par->tab;
1282
3
}
1283
1284
static int partition_get_logical_type(blkid_partition par)
1285
0
{
1286
0
  blkid_parttable tab;
1287
1288
0
  if (!par)
1289
0
    return -1;
1290
1291
0
  tab = blkid_partition_get_table(par);
1292
0
  if (!tab || !tab->type)
1293
0
    return -1;
1294
1295
0
  if (tab->parent)
1296
0
    return 'L';  /* report nested partitions as logical */
1297
1298
0
  if (!strcmp(tab->type, "dos")) {
1299
0
    if (par->partno > 4)
1300
0
      return 'L'; /* logical */
1301
1302
0
          if(par->type == MBR_DOS_EXTENDED_PARTITION ||
1303
0
                   par->type == MBR_W95_EXTENDED_PARTITION ||
1304
0
       par->type == MBR_LINUX_EXTENDED_PARTITION)
1305
0
      return 'E';
1306
0
  }
1307
0
  return 'P';
1308
0
}
1309
1310
/**
1311
 * blkid_partition_is_primary:
1312
 * @par: partition
1313
 *
1314
 * Note, this function returns FALSE for DOS extended partitions and
1315
 * all partitions in nested partition tables.
1316
 *
1317
 * Returns: 1 if the partitions is primary partition or 0 if not.
1318
 */
1319
int blkid_partition_is_primary(blkid_partition par)
1320
0
{
1321
0
  return partition_get_logical_type(par) == 'P' ? TRUE : FALSE;
1322
0
}
1323
1324
/**
1325
 * blkid_partition_is_extended:
1326
 * @par: partition
1327
 *
1328
 * Returns: 1 if the partitions is extended (dos, windows or linux)
1329
 * partition or 0 if not.
1330
 */
1331
int blkid_partition_is_extended(blkid_partition par)
1332
0
{
1333
0
  return partition_get_logical_type(par) == 'E' ? TRUE : FALSE;
1334
0
}
1335
1336
/**
1337
 * blkid_partition_is_logical:
1338
 * @par: partition
1339
 *
1340
 * Note that this function returns TRUE for all partitions in all
1341
 * nested partition tables (e.g. BSD labels).
1342
 *
1343
 * Returns: 1 if the partitions is logical partition or 0 if not.
1344
 */
1345
int blkid_partition_is_logical(blkid_partition par)
1346
0
{
1347
0
  return partition_get_logical_type(par) == 'L' ? TRUE : FALSE;
1348
0
}
1349
1350
static void set_string(unsigned char *item, size_t max,
1351
        const unsigned char *data, size_t len)
1352
0
{
1353
0
  if (len >= max)
1354
0
    len = max - 1;
1355
1356
0
  memcpy(item, data, len);
1357
0
  item[len] = '\0';
1358
1359
0
  blkid_rtrim_whitespace(item);
1360
0
}
1361
1362
int blkid_partition_set_name(blkid_partition par,
1363
    const unsigned char *name, size_t len)
1364
0
{
1365
0
  if (!par)
1366
0
    return -1;
1367
1368
0
  set_string(par->name, sizeof(par->name), name, len);
1369
0
  return 0;
1370
0
}
1371
1372
int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name,
1373
    size_t len, int enc)
1374
9
{
1375
9
  if (!par)
1376
0
    return -1;
1377
1378
9
  ul_encode_to_utf8(enc, par->name, sizeof(par->name), name, len);
1379
9
  blkid_rtrim_whitespace(par->name);
1380
9
  return 0;
1381
9
}
1382
1383
int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid)
1384
9
{
1385
9
  if (!par)
1386
0
    return -1;
1387
1388
9
  blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid));
1389
9
  return 0;
1390
9
}
1391
1392
int blkid_partition_gen_uuid(blkid_partition par)
1393
0
{
1394
0
  if (!par || !par->tab || !*par->tab->id)
1395
0
    return -1;
1396
1397
0
  snprintf(par->uuid, sizeof(par->uuid), "%.33s-%02x",
1398
0
      par->tab->id, par->partno);
1399
0
  return 0;
1400
0
}
1401
1402
/**
1403
 * blkid_partition_get_name:
1404
 * @par: partition
1405
 *
1406
 * Returns: partition name string if supported by PT (e.g. Mac) or NULL.
1407
 */
1408
const char *blkid_partition_get_name(blkid_partition par)
1409
3
{
1410
3
  return *par->name ? (char *) par->name : NULL;
1411
3
}
1412
1413
/**
1414
 * blkid_partition_get_uuid:
1415
 * @par: partition
1416
 *
1417
 * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL.
1418
 */
1419
const char *blkid_partition_get_uuid(blkid_partition par)
1420
3
{
1421
3
  return *par->uuid ? par->uuid : NULL;
1422
3
}
1423
1424
/**
1425
 * blkid_partition_get_partno:
1426
 * @par: partition
1427
 *
1428
 * Returns: proposed partition number (e.g. 'N' from sda'N') or -1 in case of
1429
 * error. Note that the number is generated by library independently of your OS.
1430
 */
1431
int blkid_partition_get_partno(blkid_partition par)
1432
3
{
1433
3
  return par->partno;
1434
3
}
1435
1436
/**
1437
 * blkid_partition_get_start:
1438
 * @par: partition
1439
 *
1440
 * Be careful if you _not_ probe whole disk:
1441
 *
1442
 * 1) the offset is usually relative to begin of the disk -- but if you probe a
1443
 *    fragment of the disk only -- then the offset could be still relative to
1444
 *    the begin of the disk rather that relative to the fragment.
1445
 *
1446
 * 2) the offset for nested partitions could be relative to parent (e.g. Solaris)
1447
 *    _or_ relative to the begin of the whole disk (e.g. bsd).
1448
 *
1449
 * You don't have to care about such details if you probe whole disk. In such
1450
 * a case libblkid always returns the offset relative to the begin of the disk.
1451
 *
1452
 * Returns: start of the partition (in 512-sectors).
1453
 */
1454
blkid_loff_t blkid_partition_get_start(blkid_partition par)
1455
12
{
1456
12
  return (blkid_loff_t)par->start;
1457
12
}
1458
1459
/**
1460
 * blkid_partition_get_size:
1461
 * @par: partition
1462
 *
1463
 * WARNING: be very careful when you work with MS-DOS extended partitions. The
1464
 *          library always returns full size of the partition. If you want to
1465
 *          add the partition to the Linux system (BLKPG_ADD_PARTITION ioctl)
1466
 *          you need to reduce the size of the partition to 1 or 2 blocks. The
1467
 *          rest of the partition has to be inaccessible for mkfs or mkswap
1468
 *          programs, we need a small space for boot loaders only.
1469
 *
1470
 *          For some unknown reason this (safe) practice is not used for
1471
 *          nested BSD, Solaris, ..., partition tables in Linux kernel.
1472
 *
1473
 * Returns: size of the partition (in 512-sectors).
1474
 */
1475
blkid_loff_t blkid_partition_get_size(blkid_partition par)
1476
6
{
1477
6
  return (blkid_loff_t)par->size;
1478
6
}
1479
1480
/**
1481
 * blkid_partition_get_type:
1482
 * @par: partition
1483
 *
1484
 * Returns: partition type.
1485
 */
1486
int blkid_partition_get_type(blkid_partition par)
1487
0
{
1488
0
  return par->type;
1489
0
}
1490
1491
/* Sets partition 'type' for PT where the type is defined by string rather
1492
 * than by number
1493
 */
1494
int blkid_partition_set_type_string(blkid_partition par,
1495
    const unsigned char *type, size_t len)
1496
0
{
1497
0
  set_string((unsigned char *) par->typestr,
1498
0
      sizeof(par->typestr), type, len);
1499
0
  return 0;
1500
0
}
1501
1502
/* Sets partition 'type' for PT where the type is defined by UUID rather
1503
 * than by number
1504
 */
1505
int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid)
1506
9
{
1507
9
  blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr));
1508
9
  return 0;
1509
9
}
1510
1511
/**
1512
 * blkid_partition_get_type_string:
1513
 * @par: partition
1514
 *
1515
 * The type string is supported by a small subset of partition tables (e.g. Mac
1516
 * and EFI GPT).  Note that GPT uses type UUID and this function returns this
1517
 * UUID as string.
1518
 *
1519
 * Returns: partition type string or NULL.
1520
 */
1521
const char *blkid_partition_get_type_string(blkid_partition par)
1522
3
{
1523
3
  return *par->typestr ? par->typestr : NULL;
1524
3
}
1525
1526
1527
int blkid_partition_set_flags(blkid_partition par, unsigned long long flags)
1528
9
{
1529
9
  par->flags = flags;
1530
9
  return 0;
1531
9
}
1532
1533
/**
1534
 * blkid_partition_get_flags
1535
 * @par: partition
1536
 *
1537
 * Returns: partition flags (or attributes for gpt).
1538
 */
1539
unsigned long long blkid_partition_get_flags(blkid_partition par)
1540
3
{
1541
3
  return par->flags;
1542
3
}
1543