From: Karel Zak Date: Wed, 16 Sep 2009 13:39:14 +0000 (+0200) Subject: libblkid: add partitions parsing support X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e4799a35bd44a4a20d672d566383533cbd2c9704;p=util-linux libblkid: add partitions parsing support This patch is large, but not invasive. There is a new code only. Signed-off-by: Karel Zak --- diff --git a/configure.ac b/configure.ac index 68099324..bb2d825d 100644 --- a/configure.ac +++ b/configure.ac @@ -923,6 +923,7 @@ shlibs/blkid/Makefile shlibs/blkid/src/Makefile shlibs/blkid/src/superblocks/Makefile shlibs/blkid/src/topology/Makefile +shlibs/blkid/src/partitions/Makefile shlibs/blkid/samples/Makefile shlibs/uuid/uuid.pc shlibs/uuid/Makefile diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am index 23a9161a..dfa56754 100644 --- a/shlibs/blkid/src/Makefile.am +++ b/shlibs/blkid/src/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/config/include-Makefile.am -SUBDIRS = superblocks topology . +SUBDIRS = superblocks topology partitions . common_ldadd = common_cflags = @@ -34,6 +34,7 @@ libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \ libblkid_la_LIBADD = superblocks/libblkid_superblocks.la \ topology/libblkid_topology.la \ + partitions/libblkid_partitions.la \ $(common_ldadd) libblkid_la_DEPENDENCIES = $(libblkid_la_LIBADD) blkid.sym diff --git a/shlibs/blkid/src/blkid.h b/shlibs/blkid/src/blkid.h index 6549845d..45e03b5b 100644 --- a/shlibs/blkid/src/blkid.h +++ b/shlibs/blkid/src/blkid.h @@ -41,6 +41,27 @@ typedef struct blkid_struct_probe *blkid_probe; */ typedef struct blkid_struct_topology *blkid_topology; +/** + * blkid_partlist + * + * list of all detected partitions and partitions tables + */ +typedef struct blkid_struct_partlist *blkid_partlist; + +/** + * blkid_partition: + * + * information about a partition + */ +typedef struct blkid_struct_partition *blkid_partition; + +/** + * blkid_parttable: + * + * information about a partition table + */ +typedef struct blkid_struct_parttable *blkid_parttable; + typedef int64_t blkid_loff_t; typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; @@ -186,6 +207,37 @@ extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp); extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp); extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp); +/* + * partitions probing + */ +extern int blkid_known_pttype(const char *pttype); +extern int blkid_probe_enable_partitions(blkid_probe pr, int enable); + +/* partitions probing flags */ +#define BLKID_PARTS_FORCE_GPT (1 << 1) +extern int blkid_probe_set_partitions_flags(blkid_probe pr, int flags); + +/* binary interface */ +extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr); + +extern int blkid_partlist_numof_partitions(blkid_partlist ls); +extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n); + +extern blkid_parttable blkid_partition_get_table(blkid_partition par); +extern const char *blkid_partition_get_name(blkid_partition par); +extern const char *blkid_partition_get_uuid(blkid_partition par); +extern int blkid_partition_get_partno(blkid_partition par); +extern blkid_loff_t blkid_partition_get_start(blkid_partition par); +extern blkid_loff_t blkid_partition_get_size(blkid_partition par); +extern int blkid_partition_get_type(blkid_partition par); +extern int blkid_partition_is_logical(blkid_partition par); +extern int blkid_partition_is_extended(blkid_partition par); +extern int blkid_partition_is_primary(blkid_partition par); + +extern const char *blkid_parttable_get_type(blkid_parttable tab); +extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab); +extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab); + /* * NAME=value low-level interface */ diff --git a/shlibs/blkid/src/blkid.sym b/shlibs/blkid/src/blkid.sym index 32ef6cac..ac1b159f 100644 --- a/shlibs/blkid/src/blkid.sym +++ b/shlibs/blkid/src/blkid.sym @@ -73,16 +73,35 @@ BLKID_2.17 { global: blkid_devno_to_wholedisk; blkid_do_fullprobe; + blkid_known_pttype; + blkid_partition_get_name; + blkid_partition_get_partno; + blkid_partition_get_size; + blkid_partition_get_start; + blkid_partition_get_table; + blkid_partition_get_type; + blkid_partition_get_uuid; + blkid_partition_is_extended; + blkid_partition_is_logical; + blkid_partition_is_primary; + blkid_partlist_get_partition; + blkid_partlist_numof_partitions; + blkid_parttable_get_offset; + blkid_parttable_get_parent; + blkid_parttable_get_type; + blkid_probe_enable_partitions; blkid_probe_enable_superblocks; blkid_probe_enable_topology; blkid_probe_filter_superblocks_type; blkid_probe_filter_superblocks_usage; blkid_probe_get_devno; + blkid_probe_get_partitions; blkid_probe_get_sectorsize; blkid_probe_get_size; blkid_probe_get_topology; blkid_probe_invert_superblocks_filter; blkid_probe_reset_superblocks_filter; + blkid_probe_set_partitions_flags; blkid_probe_set_superblocks_flags; blkid_topology_get_alignment_offset; blkid_topology_get_minimum_io_size; diff --git a/shlibs/blkid/src/blkidP.h b/shlibs/blkid/src/blkidP.h index d590cd9d..64ebeee8 100644 --- a/shlibs/blkid/src/blkidP.h +++ b/shlibs/blkid/src/blkidP.h @@ -92,7 +92,7 @@ typedef struct blkid_struct_tag *blkid_tag; enum { BLKID_CHAIN_SUBLKS, /* FS/RAID superblocks (enabled by default) */ BLKID_CHAIN_TOPLGY, /* Block device topology */ -/* BLKID_CHAIN_PARTS, Partition tables */ + BLKID_CHAIN_PARTS, /* Partition tables */ BLKID_NCHAINS /* number of chains */ }; @@ -384,6 +384,7 @@ extern int blkid_probe_set_dimension(blkid_probe pr, ((type *) blkid_probe_get_buffer((_pr),\ (_mag)->kboff << 10, sizeof(type))) +extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr); extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn); extern int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, diff --git a/shlibs/blkid/src/partitions/Makefile.am b/shlibs/blkid/src/partitions/Makefile.am new file mode 100644 index 00000000..c029bfdb --- /dev/null +++ b/shlibs/blkid/src/partitions/Makefile.am @@ -0,0 +1,9 @@ +include $(top_srcdir)/config/include-Makefile.am + +AM_CPPFLAGS += -I$(ul_libblkid_srcdir) +libblkid_partitions_la_LIBADD = + +noinst_LTLIBRARIES = libblkid_partitions.la +libblkid_partitions_la_SOURCES = partitions.c \ + partitions.h \ + blkid_parttypes.h diff --git a/shlibs/blkid/src/partitions/blkid_parttypes.h b/shlibs/blkid/src/partitions/blkid_parttypes.h new file mode 100644 index 00000000..707e53d9 --- /dev/null +++ b/shlibs/blkid/src/partitions/blkid_parttypes.h @@ -0,0 +1,121 @@ +/* + * Partition types + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Note, _L32M means <32M (less), for example FAT16_L32M */ + +enum { + BLKID_EMPTY_PARTITION = 0x00, + BLKID_FAT12_PARTITION = 0x01, + BLKID_XENIX_ROOT_PARTITION = 0x02, + BLKID_XENIX_USR_PARTITION = 0x03, + BLKID_FAT16_LESS32M_PARTITION = 0x04, + BLKID_DOS_EXTENDED_PARTITION = 0x05, + BLKID_FAT16_PARTITION = 0x06, /* DOS 16-bit >=32M */ + BLKID_HPFS_NTFS_PARTITION = 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */ + BLKID_AIX_PARTITION = 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ + BLKID_AIX_BOOTABLE_PARTITION = 0x09, /* AIX data or Coherent */ + BLKID_OS2_BOOTMNGR_PARTITION = 0x0a, /* OS/2 Boot Manager */ + BLKID_W95_FAT32_PARTITION = 0x0b, + BLKID_W95_FAT32_LBA_PARTITION = 0x0c, /* LBA really is `Extended Int 13h' */ + BLKID_W95_FAT16_LBA_PARTITION = 0x0e, + BLKID_W95_EXTENDED_PARTITION = 0x0f, + BLKID_OPUS_PARTITION = 0x10, + BLKID_HIDDEN_FAT12_PARTITION = 0x11, + BLKID_COMPAQ_DIAGNOSTICS_PARTITION = 0x12, + BLKID_HIDDEN_FAT16_L32M_PARTITION = 0x14, + BLKID_HIDDEN_FAT16_PARTITION = 0x16, + BLKID_HIDDEN_HPFS_NTFS_PARTITION = 0x17, + BLKID_AST_SMARTSLEEP_PARTITION = 0x18, + BLKID_HIDDEN_W95_FAT32_PARTITION = 0x1b, + BLKID_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c, + BLKID_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e, + BLKID_NEC_DOS_PARTITION = 0x24, + BLKID_PLAN9_PARTITION = 0x39, + BLKID_PARTITIONMAGIC_PARTITION = 0x3c, + BLKID_VENIX80286_PARTITION = 0x40, + BLKID_PPC_PREP_BOOT_PARTITION = 0x41, + BLKID_SFS_PARTITION = 0x42, + BLKID_QNX_4X_PARTITION = 0x4d, + BLKID_QNX_4X_2ND_PARTITION = 0x4e, + BLKID_QNX_4X_3RD_PARTITION = 0x4f, + BLKID_DM_PARTITION = 0x50, + BLKID_DM6_AUX1_PARTITION = 0x51, /* (or Novell) */ + BLKID_CPM_PARTITION = 0x52, /* CP/M or Microport SysV/AT */ + BLKID_DM6_AUX3_PARTITION = 0x53, + BLKID_DM6_PARTITION = 0x54, + BLKID_EZ_DRIVE_PARTITION = 0x55, + BLKID_GOLDEN_BOW_PARTITION = 0x56, + BLKID_PRIAM_EDISK_PARTITION = 0x5c, + BLKID_SPEEDSTOR_PARTITION = 0x61, + BLKID_GNU_HURD_PARTITION = 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ + BLKID_UNIXWARE_PARTITION = BLKID_GNU_HURD_PARTITION, + BLKID_NETWARE_286_PARTITION = 0x64, + BLKID_NETWARE_386_PARTITION = 0x65, + BLKID_DISKSECURE_MULTIBOOT_PARTITION = 0x70, + BLKID_PC_IX_PARTITION = 0x75, + BLKID_OLD_MINIX_PARTITION = 0x80, /* Minix 1.4a and earlier */ + BLKID_MINIX_PARTITION = 0x81, /* Minix 1.4b and later */ + BLKID_LINUX_SWAP_PARTITION = 0x82, + BLKID_SOLARIS_X86_PARTITION = BLKID_LINUX_SWAP_PARTITION, + BLKID_LINUX_DATA_PARTITION = 0x83, + BLKID_OS2_HIDDEN_DRIVE_PARTITION = 0x84, + BLKID_LINUX_EXTENDED_PARTITION = 0x85, + BLKID_NTFS_VOL_SET1_PARTITION = 0x86, + BLKID_NTFS_VOL_SET2_PARTITION = 0x87, + BLKID_LINUX_PLAINTEXT_PARTITION = 0x88, + BLKID_LINUX_LVM_PARTITION = 0x8e, + BLKID_AMOEBA_PARTITION = 0x93, + BLKID_AMOEBA_BBT_PARTITION = 0x94, /* (bad block table) */ + BLKID_BSD_OS_PARTITION = 0x9f, /* BSDI */ + BLKID_THINKPAD_HIBERNATION_PARTITION = 0xa0, + BLKID_FREEBSD_PARTITION = 0xa5, /* various BSD flavours */ + BLKID_OPENBSD_PARTITION = 0xa6, + BLKID_NEXTSTEP_PARTITION = 0xa7, + BLKID_DARWIN_UFS_PARTITION = 0xa8, + BLKID_NETBSD_PARTITION = 0xa9, + BLKID_DARWIN_BOOT_PARTITION = 0xab, + BLKID_HFS_HFS_PARTITION = 0xaf, + BLKID_BSDI_FS_PARTITION = 0xb7, + BLKID_BSDI_SWAP_PARTITION = 0xb8, + BLKID_BOOTWIZARD_HIDDEN_PARTITION = 0xbb, + BLKID_SOLARIS_BOOT_PARTITION = 0xbe, + BLKID_SOLARIS_PARTITION = 0xbf, + BLKID_DRDOS_FAT12_PARTITION = 0xc1, + BLKID_DRDOS_FAT16_L32M_PARTITION = 0xc4, + BLKID_DRDOS_FAT16_PARTITION = 0xc6, + BLKID_SYRINX_PARTITION = 0xc7, + BLKID_NONFS_DATA_PARTITION = 0xda, + BLKID_CPM_CTOS_PARTITION = 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */ + BLKID_DELL_UTILITY_PARTITION = 0xde, /* Dell PowerEdge Server utilities */ + BLKID_BOOTIT_PARTITION = 0xdf, /* BootIt EMBRM */ + BLKID_DOS_ACCESS_PARTITION = 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */ + BLKID_DOS_RO_PARTITION = 0xe3, /* DOS R/O or SpeedStor */ + BLKID_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */ + BLKID_BEOS_FS_PARTITION = 0xeb, + BLKID_GPT_PARTITION = 0xee, /* Intel EFI GUID Partition Table */ + BLKID_EFI_SYSTEM_PARTITION = 0xef, /* Intel EFI System Partition */ + BLKID_LINUX_PARISC_BOOT_PARTITION = 0xf0, /* Linux/PA-RISC boot loader */ + BLKID_SPEEDSTOR1_PARTITION = 0xf1, + BLKID_SPEEDSTOR2_PARTITION = 0xf4, /* SpeedStor large partition */ + BLKID_DOS_SECONDARY_PARTITION = 0xf2, /* DOS 3.3+ secondary */ + BLKID_VMWARE_VMFS_PARTITION = 0xfb, + BLKID_VMWARE_VMKCORE_PARTITION = 0xfc, /* VMware kernel dump partition */ + BLKID_LINUX_RAID_PARTITION = 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */ + BLKID_LANSTEP_PARTITION = 0xfe, /* SpeedStor >1024 cyl. or LANstep */ + BLKID_XENIX_BBT_PARTITION = 0xff, /* Xenix Bad Block Table */ +}; diff --git a/shlibs/blkid/src/partitions/partitions.c b/shlibs/blkid/src/partitions/partitions.c new file mode 100644 index 00000000..365e0f1f --- /dev/null +++ b/shlibs/blkid/src/partitions/partitions.c @@ -0,0 +1,929 @@ +/* + * partitions - partition tables parsing + * + * Copyright (C) 2008-2009 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "partitions.h" + +/** + * SECTION:partitions + * @title: Partitions probing + * @short_description: partitions tables detection and parsing + * + * This chain supports binary and NAME=value interfaces, but complete PT + * description is provided by binary interface only. + * + * NAME=value interface, supported tags: + * + * @PTTYPE: partition table type (dos, gpt, etc.). + * + * Example: + * + * + * + * blkid_probe pr; + * int fd; + * const char *ptname; + * + * fd = open(devname, O_RDONLY); + * pr = blkid_new_probe(); + * blkid_probe_set_device(pr, fd, 0, 0); + * + * blkid_probe_enable_partitions(pr, TRUE); + * blkid_do_fullprobe(pr); + * + * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL); + * printf("%s partition type detected\n", pttype); + * + * blkid_free_probe(pr); + * close(fd); + * + * // don't forget to check return codes in your code! + * + * + * + * Binary interface: + * + * + * + * blkid_probe pr; + * blkid_partlist ls; + * int nparts, i; + * int fd; + * + * fd = open(devname, O_RDONLY); + * pr = blkid_new_probe(); + * blkid_probe_set_device(pr, fd, 0, 0); + * + * ls = blkid_probe_get_partitions(pr); + * nparts = blkid_partlist_numof_partitions(ls); + * + * for (i = 0; i < nparts; i++) { + * blkid_partition par = blkid_partlist_get_partition(ls, i); + * printf("#%d: %llu %llu 0x%x", + * blkid_partition_get_partno(par), + * blkid_partition_get_start(par), + * blkid_partition_get_size(par), + * blkid_partition_get_type(par)); + * } + * + * blkid_free_probe(pr); + * close(fd); + * + * // don't forget to check return codes in your code! + * + * + */ + +/* + * Chain driver function + */ +static int partitions_probe(blkid_probe pr, struct blkid_chain *chn); +static void partitions_free_data(blkid_probe pr, void *data); + +/* + * Partitions chain probing functions + */ +static const struct blkid_idinfo *idinfos[] = +{ +}; + +/* + * Driver definition + */ +const struct blkid_chaindrv partitions_drv = { + .id = BLKID_CHAIN_PARTS, + .name = "partitions", + .dflt_enabled = FALSE, + .idinfos = idinfos, + .nidinfos = ARRAY_SIZE(idinfos), + .has_fltr = TRUE, + .probe = partitions_probe, + .safeprobe = partitions_probe, + .free_data = partitions_free_data +}; + + +/* + * For compatibility with the rest of libblkid API (with the old high-level + * API) we use completely opaque typedefs for all structs. Don't forget that + * the final blkid_* types are pointers! See blkid.h. + * + * [Just for the record, I hate typedef for pointers --kzak] + */ + +/* exported as opaque type "blkid_parttable" */ +struct blkid_struct_parttable { + const char *type; /* partition table type */ + blkid_loff_t offset; /* begin of the partition table */ + int nparts; /* number of partitions */ + blkid_partition parent; /* parent of nested partition table */ + + struct list_head t_tabs; /* all tables */ +}; + +/* exported as opaque type "blkid_partition" */ +struct blkid_struct_partition { + blkid_loff_t start; /* begin of the partition */ + blkid_loff_t size; /* size of the partitions */ + int type; /* partition type */ + + int partno; /* partition number */ + char uuid[37]; /* UUID (when supported by PT), e.g GPT */ + unsigned char name[128]; /* Partition in UTF8 name (when supporte by PT), e.g. Mac */ + + blkid_parttable tab; /* partition table */ +}; + +/* exported as opaque type "blkid_partlist" */ +struct blkid_struct_partlist { + int next_partno; /* next partition number */ + blkid_partition next_parent; /* next parent if parsing nested PT */ + + int nparts; /* number of partitions */ + int nparts_max; /* max.number of partitions */ + blkid_partition parts; /* array of partitions */ + + struct list_head l_tabs; /* list of partition tables */ +}; + +/** + * blkid_probe_enable_partitions: + * @pr: probe + * @enable: TRUE/FALSE + * + * Enables/disables the partitions probing for non-binary interface. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_enable_partitions(blkid_probe pr, int enable) +{ + if (!pr) + return -1; + pr->chains[BLKID_CHAIN_PARTS].enabled = enable; + return 0; +} + +/** + * blkid_probe_set_partitions_flags: + * @pr: prober + * @flags: BLKID_PARTS_* flags + * + * Sets probing flags to the partitions prober. This function is optional. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_set_partitions_flags(blkid_probe pr, int flags) +{ + if (!pr) + return -1; + + pr->chains[BLKID_CHAIN_PARTS].flags = flags; + return 0; +} + +/** + * blkid_probe_get_partitions: + * @pr: probe + * + * This is a binary interface for partitions. See also blkid_partlist_* + * functions. + * + * This function is independent on blkid_do_[safe,full]probe() and + * blkid_probe_enable_partitions() calls. + * + * Returns: list of partitions, or NULL in case of error. + */ +blkid_partlist blkid_probe_get_partitions(blkid_probe pr) +{ + return (blkid_partlist) blkid_probe_get_binary_data(pr, + &pr->chains[BLKID_CHAIN_PARTS]); +} + +/* for internal usage only */ +blkid_partlist blkid_probe_get_partlist(blkid_probe pr) +{ + return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data; +} + +static void ref_parttable(blkid_parttable tab) +{ + tab->nparts++; +} + +static void unref_parttable(blkid_parttable tab) +{ + tab->nparts--; + + if (tab->nparts <= 0) { + list_del(&tab->t_tabs); + free(tab); + } +} + +/* free all allocated parttables */ +static void free_parttables(blkid_partlist ls) +{ + if (!ls || !ls->l_tabs.next) + return; + + /* remove unassigned partition tables */ + while (!list_empty(&ls->l_tabs)) { + blkid_parttable tab = list_entry(ls->l_tabs.next, + struct blkid_struct_parttable, t_tabs); + unref_parttable(tab); + } +} + +static void reset_partlist(blkid_probe pr, blkid_partlist ls) +{ + if (!ls) + return; + + free_parttables(ls); + + if (ls->next_partno) { + /* already initialized - reset */ + int tmp_nparts = ls->nparts_max; + blkid_partition tmp_parts = ls->parts; + + memset(ls, 0, sizeof(struct blkid_struct_partlist)); + + ls->nparts_max = tmp_nparts; + ls->parts = tmp_parts; + } + + ls->nparts = 0; + ls->next_partno = 1; + INIT_LIST_HEAD(&ls->l_tabs); + + DBG(DEBUG_LOWPROBE, printf("partlist reseted\n")); +} + +static blkid_partlist partitions_init_data(blkid_probe pr, struct blkid_chain *chn) +{ + blkid_partlist ls; + + if (chn->data) + ls = (blkid_partlist) chn->data; + else { + /* allocate the new list of partitions */ + ls = calloc(1, sizeof(struct blkid_struct_partlist)); + if (!ls) + return NULL; + chn->data = (void *) ls; + } + + reset_partlist(pr, ls); + + DBG(DEBUG_LOWPROBE, + printf("parts: initialized partitions list (%p, size=%d)\n", + ls, ls->nparts_max)); + return ls; +} + +static void partitions_free_data(blkid_probe pr, void *data) +{ + blkid_partlist ls = (blkid_partlist) data; + + if (!ls) + return; + + free_parttables(ls); + + /* deallocate partitions and partlist */ + free(ls->parts); + free(ls); +} + +blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls, + const char *type, blkid_loff_t offset) +{ + blkid_parttable tab; + + tab = calloc(1, sizeof(struct blkid_struct_parttable)); + if (!tab) + return NULL; + tab->type = type; + tab->offset = offset; + tab->parent = ls->next_parent; + + INIT_LIST_HEAD(&tab->t_tabs); + list_add_tail(&tab->t_tabs, &ls->l_tabs); + + DBG(DEBUG_LOWPROBE, + printf("parts: create a new partition table " + "(%p, type=%s, offset=%llu)\n", tab, type, + (unsigned long long) offset)); + return tab; +} + +static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab) +{ + blkid_partition par; + + if (ls->nparts + 1 > ls->nparts_max) { + /* Linux kernel has DISK_MAX_PARTS=256, but it's too much for + * generic Linux machine -- let start with 32 partititions. + */ + ls->parts = realloc(ls->parts, (ls->nparts_max + 32) * + sizeof(struct blkid_struct_partition)); + if (!ls->parts) + return NULL; + ls->nparts_max += 32; + } + + par = &ls->parts[ls->nparts++]; + memset(par, 0, sizeof(struct blkid_struct_partition)); + + ref_parttable(tab); + par->tab = tab; + par->partno = ls->next_partno++; + + return par; +} + +blkid_partition blkid_partlist_add_partition(blkid_partlist ls, + blkid_parttable tab, int type, + blkid_loff_t start, blkid_loff_t size) +{ + blkid_partition par = new_partition(ls, tab); + + if (!par) + return NULL; + + par->type = type; + par->start = start; + par->size = size; + + DBG(DEBUG_LOWPROBE, + printf("parts: add partition (%p type=0x%x, " + "start=%llu, size=%llu, table=%p)\n", + par, par->type, + (unsigned long long) par->start, + (unsigned long long) par->size, + tab)); + return par; +} + +/* allows to modify used partitions numbers (for example for logical partitions) */ +int blkid_partlist_set_partno(blkid_partlist ls, int partno) +{ + if (!ls) + return -1; + ls->next_partno = partno; + return 0; +} + +/* allows to set "parent" for the next nested partition */ +int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par) +{ + if (!ls) + return -1; + ls->next_parent = par; + return 0; +} + +blkid_partition blkid_partlist_get_parent(blkid_partlist ls) +{ + if (!ls) + return NULL; + return ls->next_parent; +} + +int blkid_partitions_need_typeonly(blkid_probe pr) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + return chn && chn->data && chn->binary ? FALSE : TRUE; +} + +/* get private chain flags */ +int blkid_partitions_get_flags(blkid_probe pr) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + return chn ? chn->flags : 0; +} + +/* check if @start and @size are within @par partition */ +int blkid_is_nested_dimension(blkid_partition par, + blkid_loff_t start, blkid_loff_t size) +{ + blkid_loff_t pstart; + blkid_loff_t psize; + + if (!par) + return 0; + + pstart = blkid_partition_get_start(par); + psize = blkid_partition_get_size(par); + + if (start < pstart || start + size > pstart + psize) + return 0; + + return 1; +} + +static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id) +{ + const struct blkid_idmag *mag; + int hasmag = 0; + int rc = 1; /* = nothing detected */ + + mag = id->magics ? &id->magics[0] : NULL; + + /* try to detect by magic string */ + while(mag && mag->magic) { + int idx; + unsigned char *buf; + + idx = mag->kboff + (mag->sboff >> 10); + buf = blkid_probe_get_buffer(pr, idx << 10, 1024); + + if (buf && !memcmp(mag->magic, + buf + (mag->sboff & 0x3ff), mag->len)) { + DBG(DEBUG_LOWPROBE, printf( + "%s: magic sboff=%u, kboff=%ld\n", + id->name, mag->sboff, mag->kboff)); + hasmag = 1; + break; + } + mag++; + } + + if (hasmag == 0 && id->magics && id->magics[0].magic) + /* magic string(s) defined, but not found */ + goto nothing; + + /* final check by probing function */ + if (id->probefunc) { + DBG(DEBUG_LOWPROBE, printf( + "%s: ---> call probefunc()\n", id->name)); + rc = id->probefunc(pr, mag); + if (rc == -1) { + /* reset after error */ + reset_partlist(pr, blkid_probe_get_partlist(pr)); + DBG(DEBUG_LOWPROBE, printf( + "%s probefunc failed\n", id->name)); + } + DBG(DEBUG_LOWPROBE, printf( + "%s: <--- (rc = %d)\n", id->name, rc)); + } + +nothing: + return rc; +} + +/* + * The blkid_do_probe() backend. + */ +static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) +{ + int i = 0; + + if (!pr || chn->idx < -1) + return -1; + blkid_probe_chain_reset_vals(pr, chn); + + if (chn->binary) + partitions_init_data(pr, chn); + + DBG(DEBUG_LOWPROBE, + printf("--> starting probing loop [PARTS idx=%d]\n", + chn->idx)); + + i = chn->idx + 1; + + for ( ; i < ARRAY_SIZE(idinfos); i++) { + const char *name; + + chn->idx = i; + + /* apply filter */ + if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) + continue; + + /* apply checks from idinfo */ + if (idinfo_probe(pr, idinfos[i]) != 0) + continue; + + name = idinfos[i]->name; + + /* all checks passed */ + blkid_probe_set_value(pr, "PTTYPE", + (unsigned char *) name, strlen(name) + 1); + + DBG(DEBUG_LOWPROBE, + printf("<-- leaving probing loop (type=%s) [PARTS idx=%d]\n", + name, chn->idx)); + return 0; + } + DBG(DEBUG_LOWPROBE, + printf("<-- leaving probing loop (failed) [PARTS idx=%d]\n", + chn->idx)); + return 1; +} + +/* Probe for nested partition table within the parental partition */ +int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent, + const struct blkid_idinfo *id) +{ + int rc = 1; + blkid_partlist ls; + blkid_loff_t saved_sz, saved_off, sz, off; + + DBG(DEBUG_LOWPROBE, printf( + "parts: ----> %s subprobe requested (parent=%p)\n", + id->name, parent)); + + if (!pr || !parent || !parent->size) + return -1; + + ls = blkid_probe_get_partlist(pr); + + sz = ((blkid_loff_t) parent->size) << 9; + off = ((blkid_loff_t) parent->start) << 9; + + /* get the current setting in bytes */ + blkid_probe_get_dimension(pr, &saved_off, &saved_sz); + + /* check the requested range */ + if (off < saved_off || saved_off + saved_sz < off + sz) { + DBG(DEBUG_LOWPROBE, printf( + "ERROR: parts: <---- '%s' sub-probe: overflow detected.\n", + id->name)); + return -1; + } + + /* define sub-range with in device */ + blkid_probe_set_dimension(pr, off, sz); + + blkid_partlist_set_parent(ls, parent); + + rc = idinfo_probe(pr, id); + + blkid_partlist_set_parent(ls, NULL); + + /* restore the original setting */ + blkid_probe_set_dimension(pr, saved_off, saved_sz); + + DBG(DEBUG_LOWPROBE, printf( + "parts: <---- %s subprobe done (parent=%p, rc=%d)\n", + id->name, parent, rc)); + + return rc; +} + +/** + * blkid_known_pttype: + * @pttype: partiton name + * + * Returns: 1 for known or 0 for unknown partition type. + */ +int blkid_known_pttype(const char *pttype) +{ + int i; + + if (!pttype) + return 0; + + for (i = 0; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + if (strcmp(id->name, pttype) == 0) + return 1; + } + return 0; +} + +/** + * blkid_partlist_numof_partitions: + * @ls: partitions list + * + * Returns: number of partitions in the list or -1 in case of error. + */ +int blkid_partlist_numof_partitions(blkid_partlist ls) +{ + return ls ? ls->nparts : -1; +} + +/** + * blkid_partlist_get_partition: + * @ls: partitions list + * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions(). + * + * It's possible that the list of partitions is *empty*, but there is a valid + * partition table on the disk. This happen when on-disk details about + * partitions are unknown, but we are able to detect partition table magic + * string only. The nice example is AIX. If your question is: "Is there any + * partition table?", use: + * + * blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL); + * + * Returns: partition object or NULL in case or error. + */ +blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n) +{ + if (!ls || n < 0 || n >= ls->nparts) + return NULL; + + return &ls->parts[n]; +} + +/** + * blkid_parttable_get_type: + * @tab: partition table + * + * Returns: partition table type (type name, e.g. "dos", "gpt", ...) + */ +const char *blkid_parttable_get_type(blkid_parttable tab) +{ + return tab ? tab->type : NULL; +} + +/** + * blkid_parttable_get_parent: + * @tab: partition table + * + * Returns: parent for nexted partitition tables or NULL. + */ +blkid_partition blkid_parttable_get_parent(blkid_parttable tab) +{ + return tab ? tab->parent : NULL; +} + +/** + * blkid_parttable_get_offset: + * @tab: partition table + * + * Returns: position (in bytes) of the partition table or -1 in case of error. + * + * Note the position is relative to begin of the device as defined by + * blkid_probe_set_device() for primary partition table, and relative + * to parental partition for nested patition tables. + * + * + * + * off_t offset; + * blkid_partition parent = blkid_parttable_get_parent(tab); + * + * offset = blkid_parttable_get_offset(tab); + * + * if (parent) + * / * 'tab' is nested partition table * / + * offset += blkid_partition_get_start(parent); + * + * + */ +blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab) +{ + return tab ? tab->offset : -1; +} + +/** + * blkid_partition_get_table: + * @par: partition + * + * The "parttable" describes partition table. The table is usually the same for + * all partitions -- except nested partition tables. + * + * For example bsd, solaris, etc. use a nested partition table within + * standard primary dos partition: + * + * + * + * + * -- dos partition table + * 0: sda1 dos primary partition + * 1: sda2 dos primary partition + * -- bsd partition table (with in sda2) + * 2: sda5 bds partition + * 3: sda6 bds partition + * + * + * + * + * The library does not to use a separate partition table object for dos logical + * partitions (partitions within extended partition). It's possible to + * differentiate between logical, extended and primary partitions by + * + * blkid_partition_is_{extended,primary,logical}(). + * + * Returns: partition table object or NULL in case of error. + */ +blkid_parttable blkid_partition_get_table(blkid_partition par) +{ + return par ? par->tab : NULL; +} + +static int partition_get_logical_type(blkid_partition par) +{ + blkid_parttable tab; + + if (!par) + return -1; + + tab = blkid_partition_get_table(par); + if (!tab || !tab->type) + return -1; + + if (tab->parent) + return 'L'; /* report nested partitions as logical */ + + if (!strcmp(tab->type, "dos")) { + if (par->partno > 4) + return 'L'; /* logical */ + + if(par->type == BLKID_DOS_EXTENDED_PARTITION || + par->type == BLKID_W95_EXTENDED_PARTITION || + par->type == BLKID_LINUX_EXTENDED_PARTITION) + return 'E'; + } + return 'P'; +} + +/** + * blkid_partition_is_primary: + * @par: partition + * + * Note, this function returns FALSE for DOS extended partitions and + * all partitions in nested partition tables. + * + * Returns: 1 if the partitions is primary partition or 0 if not. + */ +int blkid_partition_is_primary(blkid_partition par) +{ + return partition_get_logical_type(par) == 'P' ? TRUE : FALSE; +} + +/** + * blkid_partition_is_extended: + * @par: partition + * + * Returns: 1 if the partitions is extended (dos, windows or linux) + * partition or 0 if not. + */ +int blkid_partition_is_extended(blkid_partition par) +{ + return partition_get_logical_type(par) == 'E' ? TRUE : FALSE; +} + +/** + * blkid_partition_is_logical: + * @par: partition + * + * Note that this function returns TRUE for all partitions in all + * nested partition tables (e.g. BSD labels). + * + * Returns: 1 if the partitions is logical partition or 0 if not. + */ +int blkid_partition_is_logical(blkid_partition par) +{ + return partition_get_logical_type(par) == 'L' ? TRUE : FALSE; +} + +int blkid_partition_set_name(blkid_partition par, + const unsigned char *name, size_t len) +{ + int i; + + if (!par) + return -1; + if (len >= sizeof(par->name)) + len = sizeof(par->name) - 1; + + memcpy(par->name, name, len); + par->name[len] = '\0'; + + /* remove trailing whitespace */ + i = strlen((char *) par->name); + while (i--) { + if (!isspace(par->name[i])) + break; + } + par->name[++i] = '\0'; + return 0; +} + +int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name, + size_t len, int enc) +{ + if (!par) + return -1; + blkid_encode_to_utf8(enc, par->name, sizeof(par->name), name, len); + return 0; +} + +int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid) +{ + if (!par) + return -1; + + blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid)); + return 0; +} + +/** + * blkid_partition_get_name: + * @par: partition + * + * Returns: partition name string if supported by PT (e.g. Mac) or NULL. + */ +const char *blkid_partition_get_name(blkid_partition par) +{ + return par && *par->name ? (char *) par->name : NULL; +} + +/** + * blkid_partition_get_uuid: + * @par: partition + * + * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL. + */ +const char *blkid_partition_get_uuid(blkid_partition par) +{ + return par && *par->uuid ? par->uuid : NULL; +} + +/** + * blkid_partition_get_partno: + * @par: partition + * + * Returns: proposed partitin number (e.g. 'N' from sda'N') or -1 in case of + * error. Note that the number is generate by library independenly on your OS. + */ +int blkid_partition_get_partno(blkid_partition par) +{ + return par ? par->partno : -1; +} + +/** + * blkid_partition_get_start: + * @par: partition + * + * Be careful if you _not_ probe whole disk: + * + * 1) the offset is usully relative to begin of the disk -- but if you probe a + * fragment of the disk only -- then the offset could be still relative to + * the begin of the disk rather that relative to the fragment. + * + * 2) the offset for nested partitions could be releative to parent (e.g. Solaris) + * _or_ relative to the begin of the whole disk (e.g. bsd). + * + * You don't have to care about such details if you proble whole disk. In such + * a case libblkid always returns the offset relative to the begin of the disk. + * + * Returns: start of the partition (in 512-sectors). + */ +blkid_loff_t blkid_partition_get_start(blkid_partition par) +{ + return par ? par->start : -1; +} + +/** + * blkid_partition_get_size: + * @par: partition + * + * WARNING: be very careful when you work with MS-DOS extended partitions. The + * library always returns full size of the partition. If you want add + * the partition to the Linux system (BLKPG_ADD_PARTITION ioctl) you + * need to reduce the size of the partition to 1 or 2 blocks. The + * rest of the partition has to be unaccessible for mkfs or mkswap + * programs, we need a small space for boot loaders only. + * + * For some unknown reason this (safe) practice is not to used for + * nested BSD, Solaris, ..., partition tables in Linux kernel. + * + * Returns: size of the partition (in 512-sectors). + */ +blkid_loff_t blkid_partition_get_size(blkid_partition par) +{ + return par ? par->size : -1; +} + +/** + * blkid_partition_get_type: + * @par: partition + * + * Returns: partition type (see BLKID_*_PARTITION in blkid_parttypes.h). + */ +int blkid_partition_get_type(blkid_partition par) +{ + return par ? par->type : 0; +} diff --git a/shlibs/blkid/src/partitions/partitions.h b/shlibs/blkid/src/partitions/partitions.h new file mode 100644 index 00000000..d283b326 --- /dev/null +++ b/shlibs/blkid/src/partitions/partitions.h @@ -0,0 +1,35 @@ +#ifndef BLKID_PARTITIONS_H +#define BLKID_PARTITIONS_H + +#include "blkidP.h" +#include "blkid_parttypes.h" + +extern int blkid_partitions_get_flags(blkid_probe pr); + +extern blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls, + const char *type, blkid_loff_t offset); + +extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls, + blkid_parttable tab, int type, + blkid_loff_t start, blkid_loff_t size); + +extern int blkid_partlist_set_partno(blkid_partlist ls, int partno); +extern blkid_partition blkid_partlist_get_parent(blkid_partlist ls); + +extern int blkid_partitions_do_subprobe(blkid_probe pr, + blkid_partition parent, const struct blkid_idinfo *id); + +extern int blkid_partitions_need_typeonly(blkid_probe pr); +extern int blkid_is_nested_dimension(blkid_partition par, + blkid_loff_t start, blkid_loff_t size); + +extern int blkid_partition_set_name(blkid_partition par, + const unsigned char *name, size_t len); + +extern int blkid_partition_set_utf8name(blkid_partition par, + const unsigned char *name, size_t len, int enc); + +extern int blkid_partition_set_uuid(blkid_partition par, + const unsigned char *uuid); + +#endif /* BLKID_PARTITIONS_H */ diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c index beda26a2..83425929 100644 --- a/shlibs/blkid/src/probe.c +++ b/shlibs/blkid/src/probe.c @@ -98,6 +98,7 @@ /* chains */ extern const struct blkid_chaindrv superblocks_drv; extern const struct blkid_chaindrv topology_drv; +extern const struct blkid_chaindrv partitions_drv; /* * All supported chains @@ -105,6 +106,7 @@ extern const struct blkid_chaindrv topology_drv; static const struct blkid_chaindrv *chains_drvs[] = { [BLKID_CHAIN_SUBLKS] = &superblocks_drv, [BLKID_CHAIN_TOPLGY] = &topology_drv, + [BLKID_CHAIN_PARTS] = &partitions_drv }; static void blkid_probe_reset_vals(blkid_probe pr);