Coverage Report

Created: 2025-11-25 07:00

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