diff options
Diffstat (limited to '')
416 files changed, 55168 insertions, 27971 deletions
diff --git a/Android.mk b/Android.mk index 203c901de..a1e68346c 100644 --- a/Android.mk +++ b/Android.mk @@ -34,8 +34,9 @@ LOCAL_SRC_FILES := \ twrp.cpp \ fixPermissions.cpp \ twrpTar.cpp \ - twrpDU.cpp \ + twrpDU.cpp \ twrpDigest.cpp \ + digest/md5.c \ find_file.cpp \ infomanager.cpp diff --git a/libblkid/Android.mk b/libblkid/Android.mk index d6c203f90..630e0690f 100644 --- a/libblkid/Android.mk +++ b/libblkid/Android.mk @@ -2,12 +2,194 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_MODULE := libblkid +LOCAL_MODULE := libutil-linux LOCAL_MODULE_TAGS := optional #LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin -LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -LOCAL_SRC_FILES = aix.c at.c befs.c bfs.c blkdev.c bsd.c btrfs.c cache.c canonicalize.c colors.c config.c cramfs.c crc32.c ddf_raid.c dev.c devname.c devno.c dm.c dos.c drbd.c drbdproxy_datalog.c encode.c env.c evaluate.c evms.c exec_shell.c exfat.c ext.c f2fs.c fileutils.c getsize.c gfs.c gpt.c hfs.c highpoint_raid.c hpfs.c ioctl.c ismounted.c iso9660.c isw_raid.c jfs.c jmicron_raid.c langinfo.c linux_raid.c linux_version.c llseek.c loopdev.c lsi_raid.c luks.c lvm1.c lvm2.c mac.c mangle.c match.c mbsalign.c md5.c md.c minix1.c minix2.c netware.c nilfs.c ntfs.c nvidia_raid.c ocfs.c pager.c partitions.c path.c probe.c procutils.c promise_raid.c randutils.c read.c reiserfs.c resolve.c romfs.c save.c setproctitle.c sgi.c silicon_raid.c solaris_x86.c squashfs.c sun.c superblocks.c swap.c sysfs1.c sysfs2.c sysv.c tag.c topology.c ubifs.c udf.c ufs.c ultrix.c unixware.c verify.c version.c vfat.c via_raid.c vmfs.c vxfs.c wholedisk.c xfs.c zfs.c adaptec_raid.c -LOCAL_C_INCLUDES += $(LOCAL_PATH) \ +LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC +LOCAL_SRC_FILES = lib/at.c \ + lib/blkdev.c \ + lib/canonicalize.c \ + lib/colors.c \ + lib/crc32.c \ + lib/crc64.c \ + lib/env.c \ + lib/exec_shell.c \ + lib/fileutils.c \ + lib/ismounted.c \ + lib/langinfo.c \ + lib/linux_version.c \ + lib/loopdev.c \ + lib/mangle.c \ + lib/match.c \ + lib/mbsalign.c \ + lib/md5.c \ + lib/pager.c \ + lib/path.c \ + lib/procutils.c \ + lib/randutils.c \ + lib/setproctitle.c \ + lib/strutils.c \ + lib/sysfs.c \ + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/libfdisk/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/libuuid/src \ + $(LOCAL_PATH)/src + LOCAL_SHARED_LIBRARIES += libc +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libuuid +LOCAL_MODULE_TAGS := optional +#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC +LOCAL_SRC_FILES = libuuid/src/clear.c \ + libuuid/src/copy.c \ + libuuid/src/isnull.c \ + libuuid/src/parse.c \ + libuuid/src/unpack.c \ + libuuid/src/uuid_time.c \ + libuuid/src/compare.c \ + libuuid/src/gen_uuid.c \ + libuuid/src/pack.c \ + libuuid/src/test_uuid.c \ + libuuid/src/unparse.c + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/libuuid/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/src + +LOCAL_SHARED_LIBRARIES += libc libutil-linux + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libfdisk +LOCAL_MODULE_TAGS := optional +#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC +LOCAL_SRC_FILES = libfdisk/src/alignment.c \ + libfdisk/src/context.c \ + libfdisk/src/init.c \ + libfdisk/src/partition.c \ + libfdisk/src/sgi.c \ + libfdisk/src/test.c \ + libfdisk/src/ask.c \ + libfdisk/src/dos.c \ + libfdisk/src/iter.c \ + libfdisk/src/parttype.c \ + libfdisk/src/sun.c \ + libfdisk/src/utils.c \ + libfdisk/src/bsd.c \ + libfdisk/src/gpt.c \ + libfdisk/src/label.c \ + libfdisk/src/script.c \ + libfdisk/src/table.c + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/libfdisk/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/libuuid/src \ + $(LOCAL_PATH)/src + +LOCAL_SHARED_LIBRARIES += libc libutil-linux libuuid +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libblkid +LOCAL_MODULE_TAGS := optional +#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_CFLAGS = -D_FILE_OFFSET_BITS=64 -DHAVE_LOFF_T -DHAVE_ERR_H -DHAVE_MEMPCPY -DHAVE_FSYNC +LOCAL_SRC_FILES = src/cache.c \ + src/config.c \ + src/dev.c \ + src/devname.c \ + src/devno.c \ + src/encode.c \ + src/evaluate.c \ + src/getsize.c \ + src/init.c \ + src/llseek.c \ + src/probe.c \ + src/read.c \ + src/resolve.c \ + src/save.c \ + src/tag.c \ + src/verify.c \ + src/version.c \ + src/partitions/aix.c \ + src/partitions/bsd.c \ + src/partitions/dos.c \ + src/partitions/gpt.c \ + src/partitions/mac.c \ + src/partitions/minix.c \ + src/partitions/partitions.c \ + src/partitions/sgi.c \ + src/partitions/solaris_x86.c \ + src/partitions/sun.c \ + src/partitions/ultrix.c \ + src/partitions/unixware.c \ + src/superblocks/adaptec_raid.c \ + src/superblocks/bcache.c \ + src/superblocks/befs.c \ + src/superblocks/bfs.c \ + src/superblocks/btrfs.c \ + src/superblocks/cramfs.c \ + src/superblocks/ddf_raid.c \ + src/superblocks/drbd.c \ + src/superblocks/drbdproxy_datalog.c \ + src/superblocks/exfat.c \ + src/superblocks/ext.c \ + src/superblocks/f2fs.c \ + src/superblocks/gfs.c \ + src/superblocks/hfs.c \ + src/superblocks/highpoint_raid.c \ + src/superblocks/hpfs.c \ + src/superblocks/iso9660.c \ + src/superblocks/isw_raid.c \ + src/superblocks/jfs.c \ + src/superblocks/jmicron_raid.c \ + src/superblocks/linux_raid.c \ + src/superblocks/lsi_raid.c \ + src/superblocks/luks.c \ + src/superblocks/lvm.c \ + src/superblocks/minix.c \ + src/superblocks/netware.c \ + src/superblocks/nilfs.c \ + src/superblocks/ntfs.c \ + src/superblocks/nvidia_raid.c \ + src/superblocks/ocfs.c \ + src/superblocks/promise_raid.c \ + src/superblocks/refs.c \ + src/superblocks/reiserfs.c \ + src/superblocks/romfs.c \ + src/superblocks/silicon_raid.c \ + src/superblocks/squashfs.c \ + src/superblocks/superblocks.c \ + src/superblocks/swap.c \ + src/superblocks/sysv.c \ + src/superblocks/ubifs.c \ + src/superblocks/udf.c \ + src/superblocks/ufs.c \ + src/superblocks/vfat.c \ + src/superblocks/via_raid.c \ + src/superblocks/vmfs.c \ + src/superblocks/vxfs.c \ + src/superblocks/xfs.c \ + src/superblocks/zfs.c \ + src/topology/dm.c \ + src/topology/evms.c \ + src/topology/ioctl.c \ + src/topology/lvm.c \ + src/topology/md.c \ + src/topology/sysfs.c \ + src/topology/topology.c \ + +LOCAL_C_INCLUDES += $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/src +LOCAL_SHARED_LIBRARIES += libc libfdisk libutil-linux include $(BUILD_SHARED_LIBRARY) diff --git a/libblkid/COPYING b/libblkid/COPYING new file mode 100644 index 000000000..be1a5b3a1 --- /dev/null +++ b/libblkid/COPYING @@ -0,0 +1,8 @@ +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. + +The complete text of the license is available in the +../Documentation/licenses/COPYING.LGPLv2.1 file. diff --git a/libblkid/Makemodule.am b/libblkid/Makemodule.am new file mode 100644 index 000000000..b4f6f9c4e --- /dev/null +++ b/libblkid/Makemodule.am @@ -0,0 +1,16 @@ +if BUILD_LIBBLKID + +include libblkid/src/Makemodule.am +include libblkid/samples/Makemodule.am + +if ENABLE_GTK_DOC +# Docs uses separate Makefiles +SUBDIRS += libblkid/docs +endif + +pkgconfig_DATA += libblkid/blkid.pc +PATHFILES += libblkid/blkid.pc +dist_man_MANS += libblkid/libblkid.3 +EXTRA_DIST += libblkid/libblkid.3 libblkid/COPYING + +endif # BUILD_LIBBLKID diff --git a/libblkid/adaptec_raid.c b/libblkid/adaptec_raid.c deleted file mode 100644 index 02e900df0..000000000 --- a/libblkid/adaptec_raid.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct adaptec_metadata { - - uint32_t b0idcode; - uint8_t lunsave[8]; - uint16_t sdtype; - uint16_t ssavecyl; - uint8_t ssavehed; - uint8_t ssavesec; - uint8_t sb0flags; - uint8_t jbodEnable; - uint8_t lundsave; - uint8_t svpdirty; - uint16_t biosInfo; - uint16_t svwbskip; - uint16_t svwbcln; - uint16_t svwbmax; - uint16_t res3; - uint16_t svwbmin; - uint16_t res4; - uint16_t svrcacth; - uint16_t svwcacth; - uint16_t svwbdly; - uint8_t svsdtime; - uint8_t res5; - uint16_t firmval; - uint16_t firmbln; - uint32_t firmblk; - uint32_t fstrsvrb; - uint16_t svBlockStorageTid; - uint16_t svtid; - uint8_t svseccfl; - uint8_t res6; - uint8_t svhbanum; - uint8_t resver; - uint32_t drivemagic; - uint8_t reserved[20]; - uint8_t testnum; - uint8_t testflags; - uint16_t maxErrorCount; - uint32_t count; - uint32_t startTime; - uint32_t interval; - uint8_t tstxt0; - uint8_t tstxt1; - uint8_t serNum[32]; - uint8_t res8[102]; - uint32_t fwTestMagic; - uint32_t fwTestSeqNum; - uint8_t fwTestRes[8]; - uint32_t smagic; - uint32_t raidtbl; - uint16_t raidline; - uint8_t res9[0xF6]; -} __attribute__((packed)); - -#define AD_SIGNATURE 0x4450544D /* "DPTM" */ -#define AD_MAGIC 0x37FC4D1E - -static int probe_adraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct adaptec_metadata *ad; - - if (pr->size < 0x10000) - return -1; - - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200)-1) * 0x200; - ad = (struct adaptec_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct adaptec_metadata)); - if (!ad) - return -1; - if (ad->smagic != be32_to_cpu(AD_SIGNATURE)) - return -1; - if (ad->b0idcode != be32_to_cpu(AD_MAGIC)) - return -1; - if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode), - (unsigned char *) &ad->b0idcode)) - return -1; - return 0; -} - -const struct blkid_idinfo adraid_idinfo = { - .name = "adaptec_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_adraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/aix.c b/libblkid/aix.c deleted file mode 100644 index de397bf4a..000000000 --- a/libblkid/aix.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * aix partitions - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" -#include "aix.h" - -static int probe_aix_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - blkid_partlist ls; - blkid_parttable tab; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "aix", 0); - if (!tab) - goto err; - - return 0; -err: - return -1; -} - -/* - * We know nothing about AIX on-disk structures. Everything what we know is the - * magic number at begin of the disk. - * - * Note, Linux kernel is tring to be smart and AIX signature is ignored when - * there is a valid DOS partitions table. We don't support such behaviour. All - * fdisk-like programs has to properly wipe the fist sector. Everything other - * is a bug. - */ -const struct blkid_idinfo aix_pt_idinfo = -{ - .name = "aix", - .probefunc = probe_aix_pt, - .magics = - { - { .magic = BLKID_AIX_MAGIC_STRING, .len = BLKID_AIX_MAGIC_STRLEN }, - { NULL } - } -}; - diff --git a/libblkid/all-io.h b/libblkid/all-io.h deleted file mode 100644 index 424ab7d3f..000000000 --- a/libblkid/all-io.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - * Petr Uzel <petr.uzel@suse.cz> - */ - -#ifndef UTIL_LINUX_ALL_IO_H -#define UTIL_LINUX_ALL_IO_H - -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include "c.h" - -static inline int write_all(int fd, const void *buf, size_t count) -{ - while (count) { - ssize_t tmp; - - errno = 0; - tmp = write(fd, buf, count); - if (tmp > 0) { - count -= tmp; - if (count) - buf = (void *) ((char *) buf + tmp); - } else if (errno != EINTR && errno != EAGAIN) - return -1; - if (errno == EAGAIN) /* Try later, *sigh* */ - usleep(10000); - } - return 0; -} - -static inline int fwrite_all(const void *ptr, size_t size, - size_t nmemb, FILE *stream) -{ - while (nmemb) { - size_t tmp; - - errno = 0; - tmp = fwrite(ptr, size, nmemb, stream); - if (tmp > 0) { - nmemb -= tmp; - if (nmemb) - ptr = (void *) ((char *) ptr + (tmp * size)); - } else if (errno != EINTR && errno != EAGAIN) - return -1; - if (errno == EAGAIN) /* Try later, *sigh* */ - usleep(10000); - } - return 0; -} - -static inline ssize_t read_all(int fd, char *buf, size_t count) -{ - ssize_t ret; - ssize_t c = 0; - int tries = 0; - - memset(buf, 0, count); - while (count > 0) { - ret = read(fd, buf, count); - if (ret <= 0) { - if ((errno == EAGAIN || errno == EINTR || ret == 0) && - (tries++ < 5)) - continue; - return c ? c : -1; - } - if (ret > 0) - tries = 0; - count -= ret; - buf += ret; - c += ret; - } - return c; -} - - -#endif /* UTIL_LINUX_ALL_IO_H */ diff --git a/libblkid/befs.c b/libblkid/befs.c deleted file mode 100644 index 847860ad5..000000000 --- a/libblkid/befs.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com> - * - * Partly based on the Haiku BFS driver by - * Axel Dörfler <axeld@pinc-software.de> - * - * Also inspired by the Linux BeFS driver by - * Will Dyson <will_dyson@pobox.com>, et al. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <inttypes.h> -#include <byteswap.h> -#include "bitops.h" -#include "superblocks.h" - -#define B_OS_NAME_LENGTH 0x20 -#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ -#define SUPER_BLOCK_MAGIC2 0xdd121031 -#define SUPER_BLOCK_MAGIC3 0x15b6830e -#define SUPER_BLOCK_FS_ENDIAN 0x42494745 /* BIGE */ -#define INODE_MAGIC1 0x3bbe0ad9 -#define BPLUSTREE_MAGIC 0x69f6c2e8 -#define BPLUSTREE_NULL -1LL -#define NUM_DIRECT_BLOCKS 12 -#define B_UINT64_TYPE 0x554c4c47 /* ULLG */ -#define KEY_NAME "be:volume_id" -#define KEY_SIZE 8 -#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \ - : be16_to_cpu(value)) -#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \ - : be32_to_cpu(value)) -#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \ - : be64_to_cpu(value)) - -typedef struct block_run { - int32_t allocation_group; - uint16_t start; - uint16_t len; -} __attribute__((packed)) block_run, inode_addr; - -struct befs_super_block { - char name[B_OS_NAME_LENGTH]; - int32_t magic1; - int32_t fs_byte_order; - uint32_t block_size; - uint32_t block_shift; - int64_t num_blocks; - int64_t used_blocks; - int32_t inode_size; - int32_t magic2; - int32_t blocks_per_ag; - int32_t ag_shift; - int32_t num_ags; - int32_t flags; - block_run log_blocks; - int64_t log_start; - int64_t log_end; - int32_t magic3; - inode_addr root_dir; - inode_addr indices; - int32_t pad[8]; -} __attribute__((packed)); - -typedef struct data_stream { - block_run direct[NUM_DIRECT_BLOCKS]; - int64_t max_direct_range; - block_run indirect; - int64_t max_indirect_range; - block_run double_indirect; - int64_t max_double_indirect_range; - int64_t size; -} __attribute__((packed)) data_stream; - -struct befs_inode { - int32_t magic1; - inode_addr inode_num; - int32_t uid; - int32_t gid; - int32_t mode; - int32_t flags; - int64_t create_time; - int64_t last_modified_time; - inode_addr parent; - inode_addr attributes; - uint32_t type; - int32_t inode_size; - uint32_t etc; - data_stream data; - int32_t pad[4]; - int32_t small_data[0]; -} __attribute__((packed)); - -struct small_data { - uint32_t type; - uint16_t name_size; - uint16_t data_size; - char name[0]; -} __attribute__((packed)); - -struct bplustree_header { - uint32_t magic; - uint32_t node_size; - uint32_t max_number_of_levels; - uint32_t data_type; - int64_t root_node_pointer; - int64_t free_node_pointer; - int64_t maximum_size; -} __attribute__((packed)); - -struct bplustree_node { - int64_t left_link; - int64_t right_link; - int64_t overflow_link; - uint16_t all_key_count; - uint16_t all_key_length; - char name[0]; -} __attribute__((packed)); - -static unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs, - const struct block_run *br, int fs_le) -{ - return blkid_probe_get_buffer(pr, - ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) - << FS32_TO_CPU(bs->ag_shift, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)), - (blkid_loff_t) FS16_TO_CPU(br->len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)); -} - -static unsigned char *get_custom_block_run(blkid_probe pr, - const struct befs_super_block *bs, - const struct block_run *br, - int64_t offset, uint32_t length, int fs_le) -{ - if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - return NULL; - - return blkid_probe_get_buffer(pr, - ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) - << FS32_TO_CPU(bs->ag_shift, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - + offset, - length); -} - -static unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs, - const struct data_stream *ds, - int64_t start, uint32_t length, int fs_le) -{ - if (start < (int64_t) FS64_TO_CPU(ds->max_direct_range, fs_le)) { - int64_t br_len; - size_t i; - - for (i = 0; i < NUM_DIRECT_BLOCKS; i++) { - br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le); - if (start < br_len) - return get_custom_block_run(pr, bs, - &ds->direct[i], - start, length, fs_le); - else - start -= br_len; - } - } else if (start < (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le)) { - struct block_run *br; - int64_t max_br, br_len, i; - - start -= FS64_TO_CPU(ds->max_direct_range, fs_le); - max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le)) - / sizeof(struct block_run); - - br = (struct block_run *) get_block_run(pr, bs, &ds->indirect, - fs_le); - if (!br) - return NULL; - - for (i = 0; i < max_br; i++) { - br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le) - << FS32_TO_CPU(bs->block_shift, fs_le); - if (start < br_len) - return get_custom_block_run(pr, bs, &br[i], - start, length, fs_le); - else - start -= br_len; - } - } else if (start < (int64_t) FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) { - struct block_run *br; - int64_t di_br_size, br_per_di_br, di_index, i_index; - - start -= (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le); - - di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len, - fs_le) << FS32_TO_CPU(bs->block_shift, fs_le); - if (di_br_size == 0) - return NULL; - - br_per_di_br = di_br_size / sizeof(struct block_run); - if (br_per_di_br == 0) - return NULL; - - di_index = start / (br_per_di_br * di_br_size); - i_index = (start % (br_per_di_br * di_br_size)) / di_br_size; - start = (start % (br_per_di_br * di_br_size)) % di_br_size; - - br = (struct block_run *) get_block_run(pr, bs, - &ds->double_indirect, fs_le); - if (!br) - return NULL; - - br = (struct block_run *) get_block_run(pr, bs, &br[di_index], - fs_le); - if (!br) - return NULL; - - return get_custom_block_run(pr, bs, &br[i_index], start, length, - fs_le); - } - return NULL; -} - -static int32_t compare_keys(const char keys1[], uint16_t keylengths1[], int32_t index, - const char *key2, uint16_t keylength2, int fs_le) -{ - const char *key1; - uint16_t keylength1; - int32_t result; - - key1 = &keys1[index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], - fs_le)]; - keylength1 = FS16_TO_CPU(keylengths1[index], fs_le) - - (index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], - fs_le)); - - result = strncmp(key1, key2, min(keylength1, keylength2)); - - if (result == 0) - return keylength1 - keylength2; - - return result; -} - -static int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs, - const struct befs_inode *bi, const char *key, int fs_le) -{ - struct bplustree_header *bh; - struct bplustree_node *bn; - uint16_t *keylengths; - int64_t *values; - int64_t node_pointer; - int32_t first, last, mid, cmp; - - bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0, - sizeof(struct bplustree_header), fs_le); - if (!bh) - return -1; - - if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC) - return -1; - - node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le); - - do { - bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data, - node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le); - if (!bn) - return -1; - - keylengths = (uint16_t *) ((uint8_t *) bn - + ((sizeof(struct bplustree_node) - + FS16_TO_CPU(bn->all_key_length, fs_le) - + sizeof(int64_t) - 1) - & ~(sizeof(int64_t) - 1))); - values = (int64_t *) ((uint8_t *) keylengths - + FS16_TO_CPU(bn->all_key_count, fs_le) - * sizeof(uint16_t)); - first = 0; - mid = 0; - last = FS16_TO_CPU(bn->all_key_count, fs_le) - 1; - - cmp = compare_keys(bn->name, keylengths, last, key, strlen(key), - fs_le); - if (cmp == 0) { - if ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) - == BPLUSTREE_NULL) - return FS64_TO_CPU(values[last], fs_le); - else - node_pointer = FS64_TO_CPU(values[last], fs_le); - } else if (cmp < 0) - node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le); - else { - while (first <= last) { - mid = (first + last) / 2; - - cmp = compare_keys(bn->name, keylengths, mid, - key, strlen(key), fs_le); - if (cmp == 0) { - if ((int64_t) FS64_TO_CPU(bn->overflow_link, - fs_le) == BPLUSTREE_NULL) - return FS64_TO_CPU(values[mid], - fs_le); - else - break; - } else if (cmp < 0) - first = mid + 1; - else - last = mid - 1; - } - if (cmp < 0) - node_pointer = FS64_TO_CPU(values[mid + 1], - fs_le); - else - node_pointer = FS64_TO_CPU(values[mid], fs_le); - } - } while ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) - != BPLUSTREE_NULL); - return 0; -} - -static int get_uuid(blkid_probe pr, const struct befs_super_block *bs, - uint64_t * const uuid, int fs_le) -{ - struct befs_inode *bi; - struct small_data *sd; - - bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - sd = (struct small_data *) bi->small_data; - - do { - if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE - && FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME) - && FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE - && strcmp(sd->name, KEY_NAME) == 0) { - - memcpy(uuid, - sd->name + FS16_TO_CPU(sd->name_size, fs_le) + 3, - sizeof(uint64_t)); - - break; - } else if (FS32_TO_CPU(sd->type, fs_le) == 0 - && FS16_TO_CPU(sd->name_size, fs_le) == 0 - && FS16_TO_CPU(sd->data_size, fs_le) == 0) - break; - - sd = (struct small_data *) ((uint8_t *) sd - + sizeof(struct small_data) - + FS16_TO_CPU(sd->name_size, fs_le) + 3 - + FS16_TO_CPU(sd->data_size, fs_le) + 1); - - } while ((intptr_t) sd < (intptr_t) bi - + (int32_t) FS32_TO_CPU(bi->inode_size, fs_le) - - (int32_t) sizeof(struct small_data)); - if (*uuid == 0 - && (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0 - || FS16_TO_CPU(bi->attributes.start, fs_le) != 0 - || FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) { - int64_t value; - - bi = (struct befs_inode *) get_block_run(pr, bs, - &bi->attributes, fs_le); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - value = get_key_value(pr, bs, bi, KEY_NAME, fs_le); - - if (value < 0) - return value; - else if (value > 0) { - bi = (struct befs_inode *) blkid_probe_get_buffer(pr, - value << FS32_TO_CPU(bs->block_shift, fs_le), - FS32_TO_CPU(bs->block_size, fs_le)); - if (!bi) - return -1; - - if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) - return -1; - - if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE - && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE - && FS16_TO_CPU(bi->data.direct[0].len, fs_le) - == 1) { - uint64_t *attr_data; - - attr_data = (uint64_t *) get_block_run(pr, bs, - &bi->data.direct[0], fs_le); - if (!attr_data) - return -1; - - *uuid = *attr_data; - } - } - } - return 0; -} - -static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct befs_super_block *bs; - const char *version = NULL; - uint64_t volume_id = 0; - int fs_le, ret; - - bs = (struct befs_super_block *) blkid_probe_get_buffer(pr, - mag->sboff - B_OS_NAME_LENGTH, - sizeof(struct befs_super_block)); - if (!bs) - return -1; - - if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 - && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 - && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 - && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { - fs_le = 1; - version = "little-endian"; - } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 - && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 - && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 - && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { - fs_le = 0; - version = "big-endian"; - } else - return -1; - - ret = get_uuid(pr, bs, &volume_id, fs_le); - - if (ret < 0) - return ret; - - /* - * all checks pass, set LABEL, VERSION and UUID - */ - if (strlen(bs->name)) - blkid_probe_set_label(pr, (unsigned char *) bs->name, - sizeof(bs->name)); - if (version) - blkid_probe_set_version(pr, version); - - if (volume_id) - blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id, - sizeof(volume_id), "%016" PRIx64, - FS64_TO_CPU(volume_id, fs_le)); - return 0; -} - -const struct blkid_idinfo befs_idinfo = -{ - .name = "befs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_befs, - .minsz = 1024 * 1440, - .magics = { - { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH }, - { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH }, - { .magic = "BFS1", .len = 4, .sboff = 0x200 + - B_OS_NAME_LENGTH }, - { .magic = "1SFB", .len = 4, .sboff = 0x200 + - B_OS_NAME_LENGTH }, - { NULL } - } -}; diff --git a/libblkid/blkdev.c b/libblkid/blkdev.c deleted file mode 100644 index 514082e34..000000000 --- a/libblkid/blkdev.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <stdint.h> - -#ifdef HAVE_LINUX_FD_H -#include <linux/fd.h> -#endif - -#ifdef HAVE_SYS_DISKLABEL_H -#include <sys/disklabel.h> -#endif - -#ifdef HAVE_SYS_DISK_H -#ifdef HAVE_SYS_QUEUE_H -#include <sys/queue.h> /* for LIST_HEAD */ -#endif -#include <sys/disk.h> -#endif - -#include "blkdev.h" -#include "c.h" -#include "linux_version.h" -#include "xalloc.h" - -static long -blkdev_valid_offset (int fd, off_t offset) { - char ch; - - if (lseek (fd, offset, 0) < 0) - return 0; - if (read (fd, &ch, 1) < 1) - return 0; - return 1; -} - -int is_blkdev(int fd) -{ - struct stat st; - return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)); -} - -off_t -blkdev_find_size (int fd) { - uintmax_t high, low = 0; - - for (high = 1024; blkdev_valid_offset (fd, high); ) { - if (high == UINTMAX_MAX) - return -1; - - low = high; - - if (high >= UINTMAX_MAX/2) - high = UINTMAX_MAX; - else - high *= 2; - } - - while (low < high - 1) - { - uintmax_t mid = (low + high) / 2; - - if (blkdev_valid_offset (fd, mid)) - low = mid; - else - high = mid; - } - blkdev_valid_offset (fd, 0); - return (low + 1); -} - -/* get size in bytes */ -int -blkdev_get_size(int fd, unsigned long long *bytes) -{ -#ifdef DKIOCGETBLOCKCOUNT - /* Apple Darwin */ - if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) { - *bytes <<= 9; - return 0; - } -#endif - -#ifdef BLKGETSIZE64 - { -#ifdef __linux__ - int ver = get_linux_version(); - - /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */ - if (ver >= KERNEL_VERSION (2,6,0) || - (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0))) -#endif - if (ioctl(fd, BLKGETSIZE64, bytes) >= 0) - return 0; - } -#endif /* BLKGETSIZE64 */ - -#ifdef BLKGETSIZE - { - unsigned long size; - - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - *bytes = ((unsigned long long)size << 9); - return 0; - } - } - -#endif /* BLKGETSIZE */ - -#ifdef DIOCGMEDIASIZE - /* FreeBSD */ - if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0) - return 0; -#endif - -#ifdef FDGETPRM - { - struct floppy_struct this_floppy; - - if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { - *bytes = this_floppy.size << 9; - return 0; - } - } -#endif /* FDGETPRM */ - -#ifdef HAVE_SYS_DISKLABEL_H - { - /* - * This code works for FreeBSD 4.11 i386, except for the full device - * (such as /dev/ad0). It doesn't work properly for newer FreeBSD - * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE - * above however. - * - * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, - * character) devices, so we need to check for S_ISCHR, too. - */ - int part = -1; - struct disklabel lab; - struct partition *pp; - char ch; - struct stat st; - - if ((fstat(fd, &st) >= 0) && - (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) - part = st.st_rdev & 7; - - if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { - pp = &lab.d_partitions[part]; - if (pp->p_size) { - *bytes = pp->p_size << 9; - return 0; - } - } - } -#endif /* HAVE_SYS_DISKLABEL_H */ - - { - struct stat st; - - if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { - *bytes = st.st_size; - return 0; - } - if (!S_ISBLK(st.st_mode)) - return -1; - } - - *bytes = blkdev_find_size(fd); - return 0; -} - -/* get 512-byte sector count */ -int -blkdev_get_sectors(int fd, unsigned long long *sectors) -{ - unsigned long long bytes; - - if (blkdev_get_size(fd, &bytes) == 0) { - *sectors = (bytes >> 9); - return 0; - } - - return -1; -} - -/* - * Get logical sector size. - * - * This is the smallest unit the storage device can - * address. It is typically 512 bytes. - */ -int blkdev_get_sector_size(int fd, int *sector_size) -{ -#ifdef BLKSSZGET - if (ioctl(fd, BLKSSZGET, sector_size) >= 0) - return 0; - return -1; -#else - *sector_size = DEFAULT_SECTOR_SIZE; - return 0; -#endif -} - -/* - * Get physical block device size. The BLKPBSZGET is supported since Linux - * 2.6.32. For old kernels is probably the best to assume that physical sector - * size is the same as logical sector size. - * - * Example: - * - * rc = blkdev_get_physector_size(fd, &physec); - * if (rc || physec == 0) { - * rc = blkdev_get_sector_size(fd, &physec); - * if (rc) - * physec = DEFAULT_SECTOR_SIZE; - * } - */ -int blkdev_get_physector_size(int fd, int *sector_size) -{ -#ifdef BLKPBSZGET - if (ioctl(fd, BLKPBSZGET, §or_size) >= 0) - return 0; - return -1; -#else - *sector_size = DEFAULT_SECTOR_SIZE; - return 0; -#endif -} - -/* - * Return the alignment status of a device - */ -int blkdev_is_misaligned(int fd) -{ -#ifdef BLKALIGNOFF - int aligned; - - if (ioctl(fd, BLKALIGNOFF, &aligned) < 0) - return 0; /* probably kernel < 2.6.32 */ - /* - * Note that kernel returns -1 as alignement offset if no compatible - * sizes and alignments exist for stacked devices - */ - return aligned != 0 ? 1 : 0; -#else - return 0; -#endif -} - -int blkdev_is_cdrom(int fd) -{ -#ifdef CDROM_GET_CAPABILITY - int ret; - - if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0) - return 0; - else - return ret; -#else - return 0; -#endif -} - -/* - * Get kernel's interpretation of the device's geometry. - * - * Returns the heads and sectors - but not cylinders - * as it's truncated for disks with more than 65535 tracks. - * - * Note that this is deprecated in favor of LBA addressing. - */ -int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s) -{ -#ifdef HDIO_GETGEO - struct hd_geometry geometry; - - if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) { - *h = geometry.heads; - *s = geometry.sectors; - return 0; - } -#else - *h = 0; - *s = 0; -#endif - return -1; -} - -/* - * Convert scsi type to human readable string. - */ -const char *blkdev_scsi_type_to_name(int type) -{ - switch (type) { - case SCSI_TYPE_DISK: - return "disk"; - case SCSI_TYPE_TAPE: - return "tape"; - case SCSI_TYPE_PRINTER: - return "printer"; - case SCSI_TYPE_PROCESSOR: - return "processor"; - case SCSI_TYPE_WORM: - return "worm"; - case SCSI_TYPE_ROM: - return "rom"; - case SCSI_TYPE_SCANNER: - return "scanner"; - case SCSI_TYPE_MOD: - return "mo-disk"; - case SCSI_TYPE_MEDIUM_CHANGER: - return "changer"; - case SCSI_TYPE_COMM: - return "comm"; - case SCSI_TYPE_RAID: - return "raid"; - case SCSI_TYPE_ENCLOSURE: - return "enclosure"; - case SCSI_TYPE_RBC: - return "rbc"; - case SCSI_TYPE_OSD: - return "osd"; - case SCSI_TYPE_NO_LUN: - return "no-lun"; - default: - break; - } - return NULL; -} - -#ifdef TEST_PROGRAM -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -int -main(int argc, char **argv) -{ - unsigned long long bytes; - unsigned long long sectors; - int sector_size, phy_sector_size; - int fd; - - if (argc != 2) { - fprintf(stderr, "usage: %s device\n", argv[0]); - exit(EXIT_FAILURE); - } - - if ((fd = open(argv[1], O_RDONLY)) < 0) - err(EXIT_FAILURE, "open %s failed", argv[1]); - - if (blkdev_get_size(fd, &bytes) < 0) - err(EXIT_FAILURE, "blkdev_get_size() failed"); - if (blkdev_get_sectors(fd, §ors) < 0) - err(EXIT_FAILURE, "blkdev_get_sectors() failed"); - if (blkdev_get_sector_size(fd, §or_size) < 0) - err(EXIT_FAILURE, "blkdev_get_sector_size() failed"); - if (blkdev_get_physector_size(fd, &phy_sector_size) < 0) - err(EXIT_FAILURE, "blkdev_get_physector_size() failed"); - - printf(" bytes: %llu\n", bytes); - printf(" sectors: %llu\n", sectors); - printf(" sector size: %d\n", sector_size); - printf("phy-sector size: %d\n", phy_sector_size); - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/libblkid/blkid.h b/libblkid/blkid.h deleted file mode 100644 index b283009f6..000000000 --- a/libblkid/blkid.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * blkid.h - Interface for libblkid, a library to identify block devices - * - * Copyright (C) 2001 Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef _BLKID_BLKID_H -#define _BLKID_BLKID_H - -#include <stdint.h> -#include <sys/types.h> - -#define _SC_HOST_NAME_MAX 255 -#ifdef __cplusplus -extern "C" { -#endif - -#define BLKID_VERSION "2.22.0" -#define BLKID_DATE "04-Sep-2012" - -/** - * blkid_dev: - * - * The device object keeps information about one device - */ -typedef struct blkid_struct_dev *blkid_dev; - -/** - * blkid_cache: - * - * information about all system devices - */ -typedef struct blkid_struct_cache *blkid_cache; - -/** - * blkid_probe: - * - * low-level probing setting - */ -typedef struct blkid_struct_probe *blkid_probe; - -/** - * blkid_topology: - * - * device topology information - */ -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; - -/** - * blkid_loff_t: - * - * 64-bit signed number for offsets and sizes - */ -typedef int64_t blkid_loff_t; - -/** - * blkid_tag_iterate: - * - * tags iterator for high-level (blkid_cache) API - */ -typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; - -/** - * blkid_dev_iterate: - * - * devices iterator for high-level (blkid_cache) API - */ -typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; - -/* - * Flags for blkid_get_dev - * - * BLKID_DEV_CREATE Create an empty device structure if not found - * in the cache. - * BLKID_DEV_VERIFY Make sure the device structure corresponds - * with reality. - * BLKID_DEV_FIND Just look up a device entry, and return NULL - * if it is not found. - * BLKID_DEV_NORMAL Get a valid device structure, either from the - * cache or by probing the device. - */ -#define BLKID_DEV_FIND 0x0000 -#define BLKID_DEV_CREATE 0x0001 -#define BLKID_DEV_VERIFY 0x0002 -#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY) - - -#ifndef __GNUC_PREREQ -# if defined __GNUC__ && defined __GNUC_MINOR__ -# define __GNUC_PREREQ(maj, min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -# else -# define __GNUC_PREREQ(maj, min) 0 -# endif -#endif - -#ifndef __ul_attribute__ -# if __GNUC_PREREQ (3, 4) -# define __ul_attribute__(_a_) __attribute__(_a_) -# else -# define __ul_attribute__(_a_) -# endif -#endif - -/* cache.c */ -extern void blkid_put_cache(blkid_cache cache); -extern int blkid_get_cache(blkid_cache *cache, const char *filename); -extern void blkid_gc_cache(blkid_cache cache); - -/* dev.c */ -extern const char *blkid_dev_devname(blkid_dev dev) - __ul_attribute__((warn_unused_result)); - -extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache) - __ul_attribute__((nonnull)); -extern int blkid_dev_set_search(blkid_dev_iterate iter, - char *search_type, char *search_value); -extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev); -extern void blkid_dev_iterate_end(blkid_dev_iterate iterate); - -/* devno.c */ -extern char *blkid_devno_to_devname(dev_t devno) - __ul_attribute__((warn_unused_result)); -extern int blkid_devno_to_wholedisk(dev_t dev, char *diskname, - size_t len, dev_t *diskdevno) - __ul_attribute__((warn_unused_result)); - -/* devname.c */ -extern int blkid_probe_all(blkid_cache cache); -extern int blkid_probe_all_new(blkid_cache cache); -extern int blkid_probe_all_removable(blkid_cache cache); - -extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags); - -/* getsize.c */ -extern blkid_loff_t blkid_get_dev_size(int fd) - __ul_attribute__((warn_unused_result)); - -/* verify.c */ -extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); - -/* read.c */ - -/* resolve.c */ -extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, - const char *devname) - __ul_attribute__((warn_unused_result)); -extern char *blkid_get_devname(blkid_cache cache, const char *token, - const char *value) - __ul_attribute__((warn_unused_result)); - -/* tag.c */ -extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) - __ul_attribute__((warn_unused_result)); -extern int blkid_tag_next(blkid_tag_iterate iterate, - const char **type, const char **value); -extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); -extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value) - __ul_attribute__((nonnull(1,2))); - -extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, - const char *type, - const char *value) - __ul_attribute__((warn_unused_result)); - -extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val); - -/* version.c */ -extern int blkid_parse_version_string(const char *ver_string) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern int blkid_get_library_version(const char **ver_string, - const char **date_string); - -/* encode.c */ -extern int blkid_encode_string(const char *str, char *str_enc, size_t len); -extern int blkid_safe_string(const char *str, char *str_safe, size_t len); - -/* evaluate.c */ -extern int blkid_send_uevent(const char *devname, const char *action); -extern char *blkid_evaluate_tag(const char *token, const char *value, - blkid_cache *cache) - __ul_attribute__((warn_unused_result)); -extern char *blkid_evaluate_spec(const char *spec, blkid_cache *cache) - __ul_attribute__((warn_unused_result)); - -/* probe.c */ -extern blkid_probe blkid_new_probe(void) - __ul_attribute__((warn_unused_result)); -extern blkid_probe blkid_new_probe_from_filename(const char *filename) - __ul_attribute__((warn_unused_result)); -extern void blkid_free_probe(blkid_probe pr); - -extern void blkid_reset_probe(blkid_probe pr); - -extern int blkid_probe_set_device(blkid_probe pr, int fd, - blkid_loff_t off, blkid_loff_t size); - -extern dev_t blkid_probe_get_devno(blkid_probe pr) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern int blkid_probe_is_wholedisk(blkid_probe pr) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern blkid_loff_t blkid_probe_get_size(blkid_probe pr) - __ul_attribute__((warn_unused_result)); -extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr) - __ul_attribute__((warn_unused_result)); -extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr) - __ul_attribute__((warn_unused_result)); -extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr) - __ul_attribute__((warn_unused_result)); - -extern int blkid_probe_get_fd(blkid_probe pr) - __ul_attribute__((warn_unused_result)); - -/* - * superblocks probing - */ -extern int blkid_known_fstype(const char *fstype) - __ul_attribute__((warn_unused_result)); - -extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage); - -extern int blkid_probe_enable_superblocks(blkid_probe pr, int enable); - -#define BLKID_SUBLKS_LABEL (1 << 1) /* read LABEL from superblock */ -#define BLKID_SUBLKS_LABELRAW (1 << 2) /* read and define LABEL_RAW result value*/ -#define BLKID_SUBLKS_UUID (1 << 3) /* read UUID from superblock */ -#define BLKID_SUBLKS_UUIDRAW (1 << 4) /* read and define UUID_RAW result value */ -#define BLKID_SUBLKS_TYPE (1 << 5) /* define TYPE result value */ -#define BLKID_SUBLKS_SECTYPE (1 << 6) /* define compatible fs type (second type) */ -#define BLKID_SUBLKS_USAGE (1 << 7) /* define USAGE result value */ -#define BLKID_SUBLKS_VERSION (1 << 8) /* read FS type from superblock */ -#define BLKID_SUBLKS_MAGIC (1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */ - -#define BLKID_SUBLKS_DEFAULT (BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \ - BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE) - -extern int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags); -extern int blkid_probe_reset_superblocks_filter(blkid_probe pr); -extern int blkid_probe_invert_superblocks_filter(blkid_probe pr); - -/** - * BLKID_FLTR_NOTIN - */ -#define BLKID_FLTR_NOTIN 1 -/** - * BLKID_FLTR_ONLYIN - */ -#define BLKID_FLTR_ONLYIN 2 -extern int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]); - -#define BLKID_USAGE_FILESYSTEM (1 << 1) -#define BLKID_USAGE_RAID (1 << 2) -#define BLKID_USAGE_CRYPTO (1 << 3) -#define BLKID_USAGE_OTHER (1 << 4) -extern int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage); - -/* - * topology probing - */ -extern int blkid_probe_enable_topology(blkid_probe pr, int enable); - -/* binary interface */ -extern blkid_topology blkid_probe_get_topology(blkid_probe pr) - __ul_attribute__((warn_unused_result)); - -extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -/* - * partitions probing - */ -extern int blkid_known_pttype(const char *pttype) - __ul_attribute__((warn_unused_result)); - -extern int blkid_probe_enable_partitions(blkid_probe pr, int enable); - -extern int blkid_probe_reset_partitions_filter(blkid_probe pr); -extern int blkid_probe_invert_partitions_filter(blkid_probe pr); -extern int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]); - -/* partitions probing flags */ -#define BLKID_PARTS_FORCE_GPT (1 << 1) -#define BLKID_PARTS_ENTRY_DETAILS (1 << 2) -#define BLKID_PARTS_MAGIC (1 << 3) -extern int blkid_probe_set_partitions_flags(blkid_probe pr, int flags); - -/* binary interface */ -extern blkid_partlist blkid_probe_get_partitions(blkid_probe pr) - __ul_attribute__((warn_unused_result)); - -extern int blkid_partlist_numof_partitions(blkid_partlist ls) - __ul_attribute__((warn_unused_result)); -extern blkid_parttable blkid_partlist_get_table(blkid_partlist ls) - __ul_attribute__((warn_unused_result)); -extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n) - __ul_attribute__((warn_unused_result)); -extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno) - __ul_attribute__((warn_unused_result)); -extern blkid_parttable blkid_partition_get_table(blkid_partition par) - __ul_attribute__((warn_unused_result)); - -extern const char *blkid_partition_get_name(blkid_partition par) - __ul_attribute__((warn_unused_result)); -extern const char *blkid_partition_get_uuid(blkid_partition par) - __ul_attribute__((warn_unused_result)); -extern int blkid_partition_get_partno(blkid_partition par) - __ul_attribute__((warn_unused_result)); -extern blkid_loff_t blkid_partition_get_start(blkid_partition par) - __ul_attribute__((warn_unused_result)); -extern blkid_loff_t blkid_partition_get_size(blkid_partition par) - __ul_attribute__((warn_unused_result)); - -extern int blkid_partition_get_type(blkid_partition par) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern const char *blkid_partition_get_type_string(blkid_partition par) - __ul_attribute__((warn_unused_result)); - -extern unsigned long long blkid_partition_get_flags(blkid_partition par) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern int blkid_partition_is_logical(blkid_partition par) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern int blkid_partition_is_extended(blkid_partition par) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); -extern int blkid_partition_is_primary(blkid_partition par) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern const char *blkid_parttable_get_type(blkid_parttable tab) - __ul_attribute__((warn_unused_result)); - -extern const char *blkid_parttable_get_id(blkid_parttable tab) - __ul_attribute__((warn_unused_result)); - -extern blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab) - __ul_attribute__((warn_unused_result)); -extern blkid_partition blkid_parttable_get_parent(blkid_parttable tab) - __ul_attribute__((warn_unused_result)); - -/* - * NAME=value low-level interface - */ -extern int blkid_do_probe(blkid_probe pr); -extern int blkid_do_safeprobe(blkid_probe pr); -extern int blkid_do_fullprobe(blkid_probe pr); - -extern int blkid_probe_numof_values(blkid_probe pr) - __ul_attribute__((warn_unused_result)); -extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name, - const char **data, size_t *len); -extern int blkid_probe_lookup_value(blkid_probe pr, const char *name, - const char **data, size_t *len); -extern int blkid_probe_has_value(blkid_probe pr, const char *name) - __ul_attribute__((nonnull)) - __ul_attribute__((warn_unused_result)); - -extern int blkid_do_wipe(blkid_probe pr, int dryrun); -extern int blkid_probe_step_back(blkid_probe pr); - -/* - * Deprecated functions/macros - */ -#ifndef BLKID_DISABLE_DEPRECATED - -#define BLKID_PROBREQ_LABEL BLKID_SUBLKS_LABEL -#define BLKID_PROBREQ_LABELRAW BLKID_SUBLKS_LABELRAW -#define BLKID_PROBREQ_UUID BLKID_SUBLKS_UUID -#define BLKID_PROBREQ_UUIDRAW BLKID_SUBLKS_UUIDRAW -#define BLKID_PROBREQ_TYPE BLKID_SUBLKS_TYPE -#define BLKID_PROBREQ_SECTYPE BLKID_SUBLKS_SECTYPE -#define BLKID_PROBREQ_USAGE BLKID_SUBLKS_USAGE -#define BLKID_PROBREQ_VERSION BLKID_SUBLKS_VERSION - -extern int blkid_probe_set_request(blkid_probe pr, int flags) - __ul_attribute__((deprecated)); - -extern int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) - __ul_attribute__((deprecated)); - -extern int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) - __ul_attribute__((deprecated)); - -extern int blkid_probe_invert_filter(blkid_probe pr) - __ul_attribute__((deprecated)); - -extern int blkid_probe_reset_filter(blkid_probe pr) - __ul_attribute__((deprecated)); - -#endif /* BLKID_DISABLE_DEPRECATED */ - -#ifdef __cplusplus -} -#endif - -#endif /* _BLKID_BLKID_H */ diff --git a/libblkid/blkid.pc.in b/libblkid/blkid.pc.in new file mode 100644 index 000000000..40ec8a9d7 --- /dev/null +++ b/libblkid/blkid.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@usrlib_execdir@ +includedir=@includedir@ + +Name: blkid +Description: Block device id library +Version: @LIBBLKID_VERSION@ +Requires.private: uuid +Cflags: -I${includedir}/blkid +Libs: -L${libdir} -lblkid diff --git a/libblkid/blkidP.h b/libblkid/blkidP.h deleted file mode 100644 index 2d5e8cb78..000000000 --- a/libblkid/blkidP.h +++ /dev/null @@ -1,551 +0,0 @@ -/* - * blkidP.h - Internal interfaces for libblkid - * - * Copyright (C) 2001 Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#ifndef _BLKID_BLKIDP_H -#define _BLKID_BLKIDP_H - -/* support debug output if LIBBLKID_DEBUG env. variable is set */ -#define CONFIG_BLKID_DEBUG 1 - -/* Always confirm that /dev/disk-by symlinks match with LABEL/UUID on device */ -/* #define CONFIG_BLKID_VERIFY_UDEV 1 */ - -#include <sys/types.h> -#include <dirent.h> -#include <sys/stat.h> -#include <stdio.h> -#include <stdarg.h> -#include <stdint.h> - -#include "c.h" -#include "bitops.h" /* $(top_srcdir)/include/ */ -#include "blkdev.h" - -#include "blkid.h" -#include "list.h" - -/* - * This describes the attributes of a specific device. - * We can traverse all of the tags by bid_tags (linking to the tag bit_names). - * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag - * values, if they exist. - */ -struct blkid_struct_dev -{ - struct list_head bid_devs; /* All devices in the cache */ - struct list_head bid_tags; /* All tags for this device */ - blkid_cache bid_cache; /* Dev belongs to this cache */ - char *bid_name; /* Device inode pathname */ - char *bid_type; /* Preferred device TYPE */ - int bid_pri; /* Device priority */ - dev_t bid_devno; /* Device major/minor number */ - time_t bid_time; /* Last update time of device */ - suseconds_t bid_utime; /* Last update time (microseconds) */ - unsigned int bid_flags; /* Device status bitflags */ - char *bid_label; /* Shortcut to device LABEL */ - char *bid_uuid; /* Shortcut to binary UUID */ -}; - -#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ -#define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */ -#define BLKID_BID_FL_REMOVABLE 0x0008 /* Device added by blkid_probe_all_removable() */ - -/* - * Each tag defines a NAME=value pair for a particular device. The tags - * are linked via bit_names for a single device, so that traversing the - * names list will get you a list of all tags associated with a device. - * They are also linked via bit_values for all devices, so one can easily - * search all tags with a given NAME for a specific value. - */ -struct blkid_struct_tag -{ - struct list_head bit_tags; /* All tags for this device */ - struct list_head bit_names; /* All tags with given NAME */ - char *bit_name; /* NAME of tag (shared) */ - char *bit_val; /* value of tag */ - blkid_dev bit_dev; /* pointer to device */ -}; -typedef struct blkid_struct_tag *blkid_tag; - -/* - * Chain IDs - */ -enum { - BLKID_CHAIN_SUBLKS, /* FS/RAID superblocks (enabled by default) */ - BLKID_CHAIN_TOPLGY, /* Block device topology */ - BLKID_CHAIN_PARTS, /* Partition tables */ - - BLKID_NCHAINS /* number of chains */ -}; - -struct blkid_chain { - const struct blkid_chaindrv *driver; /* chain driver */ - - int enabled; /* boolean */ - int flags; /* BLKID_<chain>_* */ - int binary; /* boolean */ - int idx; /* index of the current prober (or -1) */ - unsigned long *fltr; /* filter or NULL */ - void *data; /* private chain data or NULL */ -}; - -/* - * Chain driver - */ -struct blkid_chaindrv { - const size_t id; /* BLKID_CHAIN_* */ - const char *name; /* name of chain (for debug purpose) */ - const int dflt_flags; /* default chain flags */ - const int dflt_enabled; /* default enabled boolean */ - int has_fltr; /* boolean */ - - const struct blkid_idinfo **idinfos; /* description of probing functions */ - const size_t nidinfos; /* number of idinfos */ - - /* driver operations */ - int (*probe)(blkid_probe, struct blkid_chain *); - int (*safeprobe)(blkid_probe, struct blkid_chain *); - void (*free_data)(blkid_probe, void *); -}; - -/* - * Low-level probe result - */ -#define BLKID_PROBVAL_BUFSIZ 128 - -#define BLKID_NVALS_SUBLKS 18 -#define BLKID_NVALS_TOPLGY 5 -#define BLKID_NVALS_PARTS 13 - -/* Max number of all values in probing result */ -#define BLKID_NVALS (BLKID_NVALS_SUBLKS + \ - BLKID_NVALS_TOPLGY + \ - BLKID_NVALS_PARTS) - -struct blkid_prval -{ - const char *name; /* value name */ - unsigned char data[BLKID_PROBVAL_BUFSIZ]; /* value data */ - size_t len; /* length of value data */ - - struct blkid_chain *chain; /* owner */ -}; - -/* - * Filesystem / Raid magic strings - */ -struct blkid_idmag -{ - const char *magic; /* magic string */ - unsigned int len; /* length of magic */ - - long kboff; /* kilobyte offset of superblock */ - unsigned int sboff; /* byte offset within superblock */ -}; - -/* - * Filesystem / Raid description - */ -struct blkid_idinfo -{ - const char *name; /* fs, raid or partition table name */ - int usage; /* BLKID_USAGE_* flag */ - int flags; /* BLKID_IDINFO_* flags */ - int minsz; /* minimal device size */ - - /* probe function */ - int (*probefunc)(blkid_probe pr, const struct blkid_idmag *mag); - - struct blkid_idmag magics[]; /* NULL or array with magic strings */ -}; - -#define BLKID_NONE_MAGIC {{ NULL }} - -/* - * tolerant FS - can share the same device with more filesystems (e.g. typical - * on CD-ROMs). We need this flag to detect ambivalent results (e.g. valid fat - * and valid linux swap on the same device). - */ -#define BLKID_IDINFO_TOLERANT (1 << 1) - -struct blkid_bufinfo { - unsigned char *data; - blkid_loff_t off; - blkid_loff_t len; - struct list_head bufs; /* list of buffers */ -}; - -/* - * Low-level probing control struct - */ -struct blkid_struct_probe -{ - int fd; /* device file descriptor */ - blkid_loff_t off; /* begin of data on the device */ - blkid_loff_t size; /* end of data on the device */ - - dev_t devno; /* device number (st.st_rdev) */ - dev_t disk_devno; /* devno of the whole-disk or 0 */ - unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */ - mode_t mode; /* struct stat.sb_mode */ - - int flags; /* private libray flags */ - int prob_flags; /* always zeroized by blkid_do_*() */ - - blkid_loff_t wipe_off; /* begin of the wiped area */ - blkid_loff_t wipe_size; /* size of the wiped area */ - struct blkid_chain *wipe_chain; /* superblock, partition, ... */ - - struct list_head buffers; /* list of buffers */ - - struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ - struct blkid_chain *cur_chain; /* current chain */ - - struct blkid_prval vals[BLKID_NVALS]; /* results */ - int nvals; /* number of assigned vals */ - - struct blkid_struct_probe *parent; /* for clones */ - struct blkid_struct_probe *disk_probe; /* whole-disk probing */ -}; - -/* private flags library flags */ -#define BLKID_FL_PRIVATE_FD (1 << 1) /* see blkid_new_probe_from_filename() */ -#define BLKID_FL_TINY_DEV (1 << 2) /* <= 1.47MiB (floppy or so) */ -#define BLKID_FL_CDROM_DEV (1 << 3) /* is a CD/DVD drive */ - -/* private per-probing flags */ -#define BLKID_PROBE_FL_IGNORE_PT (1 << 1) /* ignore partition table */ -#define BLKID_PROBE_FL_IGNORE_BACKUP (1 << 2) /* ignore backup superblocks or PT */ - -extern int blkid_probe_ignore_backup(blkid_probe pr); - -extern blkid_probe blkid_clone_probe(blkid_probe parent); -extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr); - -/* - * Evaluation methods (for blkid_eval_* API) - */ -enum { - BLKID_EVAL_UDEV = 0, - BLKID_EVAL_SCAN, - - __BLKID_EVAL_LAST -}; - -/* - * Library config options - */ -struct blkid_config { - int eval[__BLKID_EVAL_LAST]; /* array with EVALUATION=<udev,cache> options */ - int nevals; /* number of elems in eval array */ - int uevent; /* SEND_UEVENT=<yes|not> option */ - char *cachefile; /* CACHE_FILE=<path> option */ -}; - -extern struct blkid_config *blkid_read_config(const char *filename) - __ul_attribute__((warn_unused_result)); -extern void blkid_free_config(struct blkid_config *conf); - -/* - * Minimum number of seconds between device probes, even when reading - * from the cache. This is to avoid re-probing all devices which were - * just probed by another program that does not share the cache. - */ -#define BLKID_PROBE_MIN 2 - -/* - * Time in seconds an entry remains verified in the in-memory cache - * before being reverified (in case of long-running processes that - * keep a cache in memory and continue to use it for a long time). - */ -#define BLKID_PROBE_INTERVAL 200 - -/* This describes an entire blkid cache file and probed devices. - * We can traverse all of the found devices via bic_list. - * We can traverse all of the tag types by bic_tags, which hold empty tags - * for each tag type. Those tags can be used as list_heads for iterating - * through all devices with a specific tag type (e.g. LABEL). - */ -struct blkid_struct_cache -{ - struct list_head bic_devs; /* List head of all devices */ - struct list_head bic_tags; /* List head of all tag types */ - time_t bic_time; /* Last probe time */ - time_t bic_ftime; /* Mod time of the cachefile */ - unsigned int bic_flags; /* Status flags of the cache */ - char *bic_filename; /* filename of cache */ - blkid_probe probe; /* low-level probing stuff */ -}; - -#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */ -#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */ - -/* config file */ -#define BLKID_CONFIG_FILE "/etc/blkid.conf" - -/* cache file on systemds with /run */ -#define BLKID_RUNTIME_TOPDIR "/run" -#define BLKID_RUNTIME_DIR BLKID_RUNTIME_TOPDIR "/blkid" -#define BLKID_CACHE_FILE BLKID_RUNTIME_DIR "/blkid.tab" - -/* old systems */ -#define BLKID_CACHE_FILE_OLD "/etc/blkid.tab" - -#define BLKID_ERR_IO 5 -#define BLKID_ERR_PROC 9 -#define BLKID_ERR_MEM 12 -#define BLKID_ERR_CACHE 14 -#define BLKID_ERR_DEV 19 -#define BLKID_ERR_PARAM 22 -#define BLKID_ERR_BIG 27 - -/* - * Priority settings for different types of devices - */ -#define BLKID_PRI_UBI 50 -#define BLKID_PRI_DM 40 -#define BLKID_PRI_EVMS 30 -#define BLKID_PRI_LVM 20 -#define BLKID_PRI_MD 10 - -#if defined(TEST_PROGRAM) && !defined(CONFIG_BLKID_DEBUG) -#define CONFIG_BLKID_DEBUG -#endif - -#define DEBUG_CACHE 0x0001 -#define DEBUG_DUMP 0x0002 -#define DEBUG_DEV 0x0004 -#define DEBUG_DEVNAME 0x0008 -#define DEBUG_DEVNO 0x0010 -#define DEBUG_PROBE 0x0020 -#define DEBUG_READ 0x0040 -#define DEBUG_RESOLVE 0x0080 -#define DEBUG_SAVE 0x0100 -#define DEBUG_TAG 0x0200 -#define DEBUG_LOWPROBE 0x0400 -#define DEBUG_CONFIG 0x0800 -#define DEBUG_EVALUATE 0x1000 -#define DEBUG_INIT 0x8000 -#define DEBUG_ALL 0xFFFF - -#ifdef CONFIG_BLKID_DEBUG -extern int blkid_debug_mask; -extern void blkid_init_debug(int mask); -extern void blkid_debug_dump_dev(blkid_dev dev); -extern void blkid_debug_dump_tag(blkid_tag tag); - -#define DBG(m,x) do { if ((m) & blkid_debug_mask) x; } while (0) - -#else /* !CONFIG_BLKID_DEBUG */ -#define DBG(m,x) -#define blkid_init_debug(x) -#endif /* CONFIG_BLKID_DEBUG */ - -/* devno.c */ -struct dir_list { - char *name; - struct dir_list *next; -}; -extern void blkid__scan_dir(char *, dev_t, struct dir_list **, char **) - __attribute__((nonnull(1,4))); -extern int blkid_driver_has_major(const char *drvname, int major) - __attribute__((warn_unused_result)); - -/* lseek.c */ -extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); - -/* read.c */ -extern void blkid_read_cache(blkid_cache cache) - __attribute__((nonnull)); - -/* save.c */ -extern int blkid_flush_cache(blkid_cache cache) - __attribute__((nonnull)); - -/* cache */ -extern char *blkid_safe_getenv(const char *arg) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern char *blkid_get_cache_filename(struct blkid_config *conf) - __attribute__((warn_unused_result)); -/* - * Functions to create and find a specific tag type: tag.c - */ -extern void blkid_free_tag(blkid_tag tag); -extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int blkid_set_tag(blkid_dev dev, const char *name, - const char *value, const int vlength) - __attribute__((nonnull(1,2))); - -/* - * Functions to create and find a specific tag type: dev.c - */ -extern blkid_dev blkid_new_dev(void) - __attribute__((warn_unused_result)); -extern void blkid_free_dev(blkid_dev dev); - -/* probe.c */ -extern int blkid_probe_is_tiny(blkid_probe pr) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); -extern int blkid_probe_is_cdrom(blkid_probe pr) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern unsigned char *blkid_probe_get_buffer(blkid_probe pr, - blkid_loff_t off, blkid_loff_t len) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int blkid_probe_get_dimension(blkid_probe pr, - blkid_loff_t *off, blkid_loff_t *size) - __attribute__((nonnull)); - -extern int blkid_probe_set_dimension(blkid_probe pr, - blkid_loff_t off, blkid_loff_t size) - __attribute__((nonnull)); - -extern int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, - blkid_loff_t *offset, const struct blkid_idmag **res) - __attribute__((nonnull(1))); - -/* returns superblok according to 'struct blkid_idmag' */ -#define blkid_probe_get_sb(_pr, _mag, type) \ - ((type *) blkid_probe_get_buffer((_pr),\ - (_mag)->kboff << 10, sizeof(type))) - -extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int blkid_probe_is_covered_by_pt(blkid_probe pr, - blkid_loff_t offset, blkid_loff_t size) - __attribute__((warn_unused_result)); - -extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) - __attribute__((nonnull)); -extern int blkid_probe_chain_copy_vals(blkid_probe pr, - struct blkid_chain *chn, - struct blkid_prval *vals, - int nvals) - __attribute__((nonnull)); - -extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr, - const char *name) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int blkid_probe_reset_last_value(blkid_probe pr) - __attribute__((nonnull)); -extern void blkid_probe_append_vals(blkid_probe pr, - struct blkid_prval *vals, - int nvals) - __attribute__((nonnull)); - -extern struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int __blkid_probe_invert_filter(blkid_probe pr, int chain) - __attribute__((nonnull)); -extern int __blkid_probe_reset_filter(blkid_probe pr, int chain) - __attribute__((nonnull)); -extern int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) - __attribute__((nonnull)); - -extern void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); - -extern int blkid_probe_set_value(blkid_probe pr, const char *name, - unsigned char *data, size_t len) - __attribute__((nonnull)); - -extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, - const char *fmt, va_list ap) - __attribute__((nonnull)); - -extern int blkid_probe_sprintf_value(blkid_probe pr, const char *name, - const char *fmt, ...) - __attribute__((nonnull)) - __attribute__ ((__format__ (__printf__, 3, 4))); - -extern int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset, - size_t len, unsigned char *magic) - __attribute__((nonnull)); - -extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) - __attribute__((nonnull)); -extern size_t blkid_rtrim_whitespace(unsigned char *str) - __attribute__((nonnull)); -extern size_t blkid_ltrim_whitespace(unsigned char *str) - __attribute__((nonnull)); - -extern void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, - blkid_loff_t size) - __attribute__((nonnull)); -extern int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, - blkid_loff_t off, blkid_loff_t size) - __attribute__((nonnull)) - __attribute__((warn_unused_result)); -extern void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) - __attribute__((nonnull)); - -/* filter bitmap macros */ -#define blkid_bmp_wordsize (8 * sizeof(unsigned long)) -#define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) -#define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize) - -#define blkid_bmp_set_item(bmp, item) \ - ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item)) - -#define blkid_bmp_unset_item(bmp, item) \ - ((bmp)[ blkid_bmp_idx_byte(item) ] &= ~blkid_bmp_idx_bit(item)) - -#define blkid_bmp_get_item(bmp, item) \ - ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item)) - -#define blkid_bmp_nwords(max_items) \ - (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize) - -#define blkid_bmp_nbytes(max_items) \ - (blkid_bmp_nwords(max_items) * sizeof(unsigned long)) - -/* encode.c */ -extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len, - const unsigned char *src, size_t count) - __attribute__((nonnull)); - -#define BLKID_ENC_UTF16BE 0 -#define BLKID_ENC_UTF16LE 1 - -#endif /* _BLKID_BLKIDP_H */ diff --git a/libblkid/blkid_parttypes.h b/libblkid/blkid_parttypes.h deleted file mode 100644 index b0aad86e6..000000000 --- a/libblkid/blkid_parttypes.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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/libblkid/bsd.c b/libblkid/bsd.c deleted file mode 100644 index ee15ad2fe..000000000 --- a/libblkid/bsd.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * BSD/OSF partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -#define BSD_MAXPARTITIONS 16 -#define BSD_FS_UNUSED 0 - -struct bsd_disklabel { - uint32_t d_magic; /* the magic number */ - int16_t d_type; /* drive type */ - int16_t d_subtype; /* controller/d_type specific */ - char d_typename[16]; /* type name, e.g. "eagle" */ - char d_packname[16]; /* pack identifier */ - - /* disk geometry: */ - uint32_t d_secsize; /* # of bytes per sector */ - uint32_t d_nsectors; /* # of data sectors per track */ - uint32_t d_ntracks; /* # of tracks per cylinder */ - uint32_t d_ncylinders; /* # of data cylinders per unit */ - uint32_t d_secpercyl; /* # of data sectors per cylinder */ - uint32_t d_secperunit; /* # of data sectors per unit */ - - /* - * Spares (bad sector replacements) below - * are not counted in d_nsectors or d_secpercyl. - * Spare sectors are assumed to be physical sectors - * which occupy space at the end of each track and/or cylinder. - */ - uint16_t d_sparespertrack; /* # of spare sectors per track */ - uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ - - /* - * Alternate cylinders include maintenance, replacement, - * configuration description areas, etc. - */ - uint32_t d_acylinders; /* # of alt. cylinders per unit */ - - /* hardware characteristics: */ - /* - * d_interleave, d_trackskew and d_cylskew describe perturbations - * in the media format used to compensate for a slow controller. - * Interleave is physical sector interleave, set up by the formatter - * or controller when formatting. When interleaving is in use, - * logically adjacent sectors are not physically contiguous, - * but instead are separated by some number of sectors. - * It is specified as the ratio of physical sectors traversed - * per logical sector. Thus an interleave of 1:1 implies contiguous - * layout, while 2:1 implies that logical sector 0 is separated - * by one sector from logical sector 1. - * d_trackskew is the offset of sector 0 on track N - * relative to sector 0 on track N-1 on the same cylinder. - * Finally, d_cylskew is the offset of sector 0 on cylinder N - * relative to sector 0 on cylinder N-1. - */ - uint16_t d_rpm; /* rotational speed */ - uint16_t d_interleave; /* hardware sector interleave */ - uint16_t d_trackskew; /* sector 0 skew, per track */ - uint16_t d_cylskew; /* sector 0 skew, per cylinder */ - uint32_t d_headswitch; /* head switch time, usec */ - uint32_t d_trkseek; /* track-to-track seek, usec */ - uint32_t d_flags; /* generic flags */ - uint32_t d_drivedata[5]; /* drive-type specific information */ - uint32_t d_spare[5]; /* reserved for future use */ - uint32_t d_magic2; /* the magic number (again) */ - uint16_t d_checksum; /* xor of data incl. partitions */ - - /* filesystem and partition information: */ - uint16_t d_npartitions; /* number of partitions in following */ - uint32_t d_bbsize; /* size of boot area at sn0, bytes */ - uint32_t d_sbsize; /* max size of fs superblock, bytes */ - - struct bsd_partition { /* the partition table */ - uint32_t p_size; /* number of sectors in partition */ - uint32_t p_offset; /* starting sector */ - uint32_t p_fsize; /* filesystem basic fragment size */ - uint8_t p_fstype; /* filesystem type, see below */ - uint8_t p_frag; /* filesystem fragments per block */ - uint16_t p_cpg; /* filesystem cylinders per group */ - } __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ -} __attribute__((packed)); - - -/* Returns 'blkid_idmag' in 512-sectors */ -#define BLKID_MAG_SECTOR(_mag) (((_mag)->kboff * 2) + ((_mag)->sboff >> 9)) - -/* Returns 'blkid_idmag' in bytes */ -#define BLKID_MAG_OFFSET(_mag) ((_mag)->kboff >> 10) + ((_mag)->sboff) - -/* Returns 'blkid_idmag' offset in bytes within the last sector */ -#define BLKID_MAG_LASTOFFSET(_mag) \ - (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9)) - -static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct bsd_disklabel *l; - struct bsd_partition *p; - const char *name = "bsd" ; - blkid_parttable tab = NULL; - blkid_partition parent; - blkid_partlist ls; - int i, nparts = BSD_MAXPARTITIONS; - unsigned char *data; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag)); - if (!data) - goto nothing; - - l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag); - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - /* try to determine the real type of BSD system according to - * (parental) primary partition */ - parent = blkid_partlist_get_parent(ls); - if (parent) { - switch(blkid_partition_get_type(parent)) { - case BLKID_FREEBSD_PARTITION: - name = "freebsd"; - break; - case BLKID_NETBSD_PARTITION: - name = "netbsd"; - break; - case BLKID_OPENBSD_PARTITION: - name = "openbsd"; - break; - default: - DBG(DEBUG_LOWPROBE, printf( - "WARNING: BSD label detected on unknown (0x%x) " - "primary partition\n", - blkid_partition_get_type(parent))); - break; - } - } - - tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag)); - if (!tab) - goto err; - - if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS) - nparts = le16_to_cpu(l->d_npartitions); - - else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS) - DBG(DEBUG_LOWPROBE, printf( - "WARNING: ignore %d more BSD partitions\n", - le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS)); - - for (i = 0, p = l->d_partitions; i < nparts; i++, p++) { - blkid_partition par; - uint32_t start, size; - - /* TODO: in fdisk-mode returns all non-zero (p_size) partitions */ - if (p->p_fstype == BSD_FS_UNUSED) - continue; - - start = le32_to_cpu(p->p_offset); - size = le32_to_cpu(p->p_size); - - if (parent && !blkid_is_nested_dimension(parent, start, size)) { - DBG(DEBUG_LOWPROBE, printf( - "WARNING: BSD partition (%d) overflow " - "detected, ignore\n", i)); - continue; - } - - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, p->p_fstype); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - - -/* - * All BSD variants use the same magic string (little-endian), - * and the same disklabel. - * - * The difference between {Free,Open,...}BSD is in the (parental) - * primary partition type. - * - * See also: http://en.wikipedia.org/wiki/BSD_disklabel - * - * The location of BSD disk label is architecture specific and in defined by - * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location - * also depends on BSD variant, FreeBSD uses only one location, NetBSD and - * OpenBSD are more creative... - * - * The basic overview: - * - * arch | LABELSECTOR | LABELOFFSET - * ------------------------+-------------+------------ - * amd64 arm hppa hppa64 | | - * i386, macppc, mvmeppc | 1 | 0 - * sgi, aviion, sh, socppc | | - * ------------------------+-------------+------------ - * alpha luna88k mac68k | 0 | 64 - * sparc(OpenBSD) vax | | - * ------------------------+-------------+------------ - * spark64 sparc(NetBSD) | 0 | 128 - * ------------------------+-------------+------------ - * - * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR) - * - */ -const struct blkid_idinfo bsd_pt_idinfo = -{ - .name = "bsd", - .probefunc = probe_bsd_pt, - .magics = - { - { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 }, - { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 }, - { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 }, - { NULL } - } -}; - diff --git a/libblkid/btrfs.c b/libblkid/btrfs.c deleted file mode 100644 index 5813035f3..000000000 --- a/libblkid/btrfs.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct btrfs_super_block { - uint8_t csum[32]; - uint8_t fsid[16]; - uint64_t bytenr; - uint64_t flags; - uint8_t magic[8]; - uint64_t generation; - uint64_t root; - uint64_t chunk_root; - uint64_t log_root; - uint64_t log_root_transid; - uint64_t total_bytes; - uint64_t bytes_used; - uint64_t root_dir_objectid; - uint64_t num_devices; - uint32_t sectorsize; - uint32_t nodesize; - uint32_t leafsize; - uint32_t stripesize; - uint32_t sys_chunk_array_size; - uint64_t chunk_root_generation; - uint64_t compat_flags; - uint64_t compat_ro_flags; - uint64_t incompat_flags; - uint16_t csum_type; - uint8_t root_level; - uint8_t chunk_root_level; - uint8_t log_root_level; - struct btrfs_dev_item { - uint64_t devid; - uint64_t total_bytes; - uint64_t bytes_used; - uint32_t io_align; - uint32_t io_width; - uint32_t sector_size; - uint64_t type; - uint64_t generation; - uint64_t start_offset; - uint32_t dev_group; - uint8_t seek_speed; - uint8_t bandwidth; - uint8_t uuid[16]; - uint8_t fsid[16]; - } __attribute__ ((__packed__)) dev_item; - uint8_t label[256]; -} __attribute__ ((__packed__)); - -static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct btrfs_super_block *bfs; - - if (mag->kboff > 64 && blkid_probe_ignore_backup(pr)) { - DBG(DEBUG_LOWPROBE, printf("btrfs: found backup superblock, ignore\n")); - return 1; - } - - bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); - if (!bfs) - return -1; - - if (*bfs->label) - blkid_probe_set_label(pr, - (unsigned char *) bfs->label, - sizeof(bfs->label)); - - blkid_probe_set_uuid(pr, bfs->fsid); - blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB"); - - return 0; -} - -const struct blkid_idinfo btrfs_idinfo = -{ - .name = "btrfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_btrfs, - .minsz = 1024 * 1024, - .magics = - { - { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 }, - { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 * 1024 }, - { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 256 * 1024 * 1024 }, - { NULL } - } -}; - diff --git a/libblkid/c.h b/libblkid/c.h deleted file mode 100644 index 037a09928..000000000 --- a/libblkid/c.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Fundamental C definitions. - */ - -#ifndef UTIL_LINUX_C_H -#define UTIL_LINUX_C_H - -#include <limits.h> -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> -#include <unistd.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include "blkid.h" -#ifdef HAVE_ERR_H -# include <err.h> -#endif - -#ifndef HAVE_USLEEP -# include <time.h> -#endif - -/* - * Compiler specific stuff - */ -#ifndef __GNUC_PREREQ -# if defined __GNUC__ && defined __GNUC_MINOR__ -# define __GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) -# else -# define __GNUC_PREREQ(maj, min) 0 -# endif -#endif - -#ifdef __GNUC__ - -/* &a[0] degrades to a pointer: a different type from an array */ -# define __must_be_array(a) \ - UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0]))) - -# define ignore_result(x) ({ \ - __typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \ -}) - -#else /* !__GNUC__ */ -# define __must_be_array(a) 0 -# define __attribute__(_arg_) -# define ignore_result(x) ((void) (x)) -#endif /* !__GNUC__ */ - -/* - * Function attributes - */ -#ifndef __ul_alloc_size -# if __GNUC_PREREQ (4, 3) -# define __ul_alloc_size(s) __attribute__((alloc_size(s))) -# else -# define __ul_alloc_size(s) -# endif -#endif - -#ifndef __ul_calloc_size -# if __GNUC_PREREQ (4, 3) -# define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s))) -# else -# define __ul_calloc_size(n, s) -# endif -#endif - -/* Force a compilation error if condition is true, but also produce a - * result (of value 0 and type size_t), so the expression can be used - * e.g. in a structure initializer (or where-ever else comma expressions - * aren't permitted). - */ -#define UL_BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) -#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) -#endif - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif - -#ifndef TRUE -# define TRUE 1 -#endif - -#ifndef FALSE -# define FALSE 0 -#endif - -#ifndef min -# define min(x, y) ({ \ - __typeof__(x) _min1 = (x); \ - __typeof__(y) _min2 = (y); \ - (void) (&_min1 == &_min2); \ - _min1 < _min2 ? _min1 : _min2; }) -#endif - -#ifndef max -# define max(x, y) ({ \ - __typeof__(x) _max1 = (x); \ - __typeof__(y) _max2 = (y); \ - (void) (&_max1 == &_max2); \ - _max1 > _max2 ? _max1 : _max2; }) -#endif - -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -#ifndef container_of -#define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) -#endif - -#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME -# ifdef HAVE___PROGNAME -extern char *__progname; -# define program_invocation_short_name __progname -# else -# ifdef HAVE_GETEXECNAME -# define program_invocation_short_name \ - prog_inv_sh_nm_from_file(getexecname(), 0) -# else -# define program_invocation_short_name \ - prog_inv_sh_nm_from_file(__FILE__, 1) -# endif -static char prog_inv_sh_nm_buf[256]; -static inline char * -prog_inv_sh_nm_from_file(char *f, char stripext) -{ - char *t; - - if ((t = strrchr(f, '/')) != NULL) - t++; - else - t = f; - - strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1); - prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0'; - - if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL) - *t = '\0'; - - return prog_inv_sh_nm_buf; -} -# endif -#endif - - -#ifndef HAVE_ERR_H -static inline void -errmsg(char doexit, int excode, char adderr, const char *fmt, ...) -{ - fprintf(stderr, "%s: ", program_invocation_short_name); - if (fmt != NULL) { - va_list argp; - va_start(argp, fmt); - vfprintf(stderr, fmt, argp); - va_end(argp); - if (adderr) - fprintf(stderr, ": "); - } - if (adderr) - fprintf(stderr, "%m"); - fprintf(stderr, "\n"); - if (doexit) - exit(excode); -} - -#ifndef HAVE_ERR -# define err(E, FMT...) errmsg(1, E, 1, FMT) -#endif - -#ifndef HAVE_ERRX -# define errx(E, FMT...) errmsg(1, E, 0, FMT) -#endif - -#ifndef HAVE_WARN -# define warn(FMT...) errmsg(0, 0, 1, FMT) -#endif - -#ifndef HAVE_WARNX -# define warnx(FMT...) errmsg(0, 0, 0, FMT) -#endif -#endif /* !HAVE_ERR_H */ - - -static inline __attribute__((const)) int is_power_of_2(unsigned long num) -{ - return (num != 0 && ((num & (num - 1)) == 0)); -} - -#ifndef HAVE_LOFF_T -typedef int64_t loff_t; -#endif - -#if !defined(HAVE_DIRFD) && (!defined(HAVE_DECL_DIRFD) || HAVE_DECL_DIRFD == 0) && defined(HAVE_DIR_DD_FD) -#include <sys/types.h> -#include <dirent.h> -static inline int dirfd(DIR *d) -{ - return d->dd_fd; -} -#endif - -/* - * Fallback defines for old versions of glibc - */ -#include <fcntl.h> -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef AI_ADDRCONFIG -#define AI_ADDRCONFIG 0x0020 -#endif - -#ifndef IUTF8 -#define IUTF8 0040000 -#endif - -/* - * MAXHOSTNAMELEN replacement - */ -static inline size_t get_hostname_max(void) -{ - long len = sysconf(_SC_HOST_NAME_MAX); - - if (0 < len) - return len; - -#ifdef MAXHOSTNAMELEN - return MAXHOSTNAMELEN; -#elif HOST_NAME_MAX - return HOST_NAME_MAX; -#endif - return 64; -} - -/* - * Constant strings for usage() functions. For more info see - * Documentation/howto-usage-function.txt and sys-utils/arch.c - */ -#define USAGE_HEADER _("\nUsage:\n") -#define USAGE_OPTIONS _("\nOptions:\n") -#define USAGE_SEPARATOR _("\n") -#define USAGE_HELP _(" -h, --help display this help and exit\n") -#define USAGE_VERSION _(" -V, --version output version information and exit\n") -#define USAGE_MAN_TAIL(_man) _("\nFor more details see %s.\n"), _man - -#define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING - -/* - * scanf modifiers for "strings allocation" - */ -#ifdef HAVE_SCANF_MS_MODIFIER -#define UL_SCNsA "%ms" -#elif defined(HAVE_SCANF_AS_MODIFIER) -#define UL_SCNsA "%as" -#endif - -/* - * seek stuff - */ -#ifndef SEEK_DATA -# define SEEK_DATA 3 -#endif -#ifndef SEEK_HOLE -# define SEEK_HOLE 4 -#endif - -#endif /* UTIL_LINUX_C_H */ diff --git a/libblkid/cache.c b/libblkid/cache.c deleted file mode 100644 index cc2cf8e94..000000000 --- a/libblkid/cache.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * cache.c - allocation/initialization/free routines for cache - * - * Copyright (C) 2001 Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include "blkidP.h" -#include "env.h" - -int blkid_debug_mask = 0; - -/** - * SECTION:cache - * @title: Cache - * @short_description: basic routines to work with libblkid cache - * - * Block device information is normally kept in a cache file blkid.tab and is - * verified to still be valid before being returned to the user (if the user has - * read permission on the raw block device, otherwise not). The cache file also - * allows unprivileged users (normally anyone other than root, or those not in the - * "disk" group) to locate devices by label/id. The standard location of the - * cache file can be overridden by the environment variable BLKID_FILE. - * - * In situations where one is getting information about a single known device, it - * does not impact performance whether the cache is used or not (unless you are - * not able to read the block device directly). If you are dealing with multiple - * devices, use of the cache is highly recommended (even if empty) as devices will - * be scanned at most one time and the on-disk cache will be updated if possible. - * There is rarely a reason not to use the cache. - * - * In some cases (modular kernels), block devices are not even visible until after - * they are accessed the first time, so it is critical that there is some way to - * locate these devices without enumerating only visible devices, so the use of - * the cache file is required in this situation. - */ - -#if 0 /* ifdef CONFIG_BLKID_DEBUG */ -static blkid_debug_dump_cache(int mask, blkid_cache cache) -{ - struct list_head *p; - - if (!cache) { - printf("cache: NULL\n"); - return; - } - - printf("cache: time = %lu\n", cache->bic_time); - printf("cache: flags = 0x%08X\n", cache->bic_flags); - - list_for_each(p, &cache->bic_devs) { - blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); - blkid_debug_dump_dev(dev); - } -} -#endif - -#ifdef CONFIG_BLKID_DEBUG -void blkid_init_debug(int mask) -{ - if (blkid_debug_mask & DEBUG_INIT) - return; - - if (!mask) - { - char *dstr = getenv("LIBBLKID_DEBUG"); - - if (!dstr) - dstr = getenv("BLKID_DEBUG"); /* for backward compatibility */ - if (dstr) - blkid_debug_mask = strtoul(dstr, 0, 0); - } else - blkid_debug_mask = mask; - - if (blkid_debug_mask) - printf("libblkid: debug mask set to 0x%04x.\n", blkid_debug_mask); - - blkid_debug_mask |= DEBUG_INIT; -} -#endif - -static const char *get_default_cache_filename(void) -{ - struct stat st; - - if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode)) - return BLKID_CACHE_FILE; /* cache in /run */ - - return BLKID_CACHE_FILE_OLD; /* cache in /etc */ -} - -/* returns allocated path to cache */ -char *blkid_get_cache_filename(struct blkid_config *conf) -{ - char *filename; - - filename = safe_getenv("BLKID_FILE"); - if (filename) - filename = strdup(filename); - else if (conf) - filename = conf->cachefile ? strdup(conf->cachefile) : NULL; - else { - struct blkid_config *c = blkid_read_config(NULL); - if (!c) - filename = strdup(get_default_cache_filename()); - else { - filename = c->cachefile; /* already allocated */ - c->cachefile = NULL; - blkid_free_config(c); - } - } - return filename; -} - -/** - * blkid_get_cache: - * @cache: pointer to return cache handler - * @filename: path to the cache file or NULL for the default path - * - * Allocates and initialize librray cache handler. - * - * Returns: 0 on success or number less than zero in case of error. - */ -int blkid_get_cache(blkid_cache *ret_cache, const char *filename) -{ - blkid_cache cache; - - if (!ret_cache) - return -BLKID_ERR_PARAM; - - blkid_init_debug(0); - - DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n", - filename ? filename : "default cache")); - - if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache)))) - return -BLKID_ERR_MEM; - - INIT_LIST_HEAD(&cache->bic_devs); - INIT_LIST_HEAD(&cache->bic_tags); - - if (filename && !*filename) - filename = NULL; - if (filename) - cache->bic_filename = strdup(filename); - else - cache->bic_filename = blkid_get_cache_filename(NULL); - - blkid_read_cache(cache); - *ret_cache = cache; - return 0; -} - -/** - * blkid_put_cache: - * @cache: cache handler - * - * Saves changes to cache file. - */ -void blkid_put_cache(blkid_cache cache) -{ - if (!cache) - return; - - (void) blkid_flush_cache(cache); - - DBG(DEBUG_CACHE, printf("freeing cache struct\n")); - - /* DBG(DEBUG_CACHE, blkid_debug_dump_cache(cache)); */ - - while (!list_empty(&cache->bic_devs)) { - blkid_dev dev = list_entry(cache->bic_devs.next, - struct blkid_struct_dev, - bid_devs); - blkid_free_dev(dev); - } - - while (!list_empty(&cache->bic_tags)) { - blkid_tag tag = list_entry(cache->bic_tags.next, - struct blkid_struct_tag, - bit_tags); - - while (!list_empty(&tag->bit_names)) { - blkid_tag bad = list_entry(tag->bit_names.next, - struct blkid_struct_tag, - bit_names); - - DBG(DEBUG_CACHE, printf("warning: unfreed tag %s=%s\n", - bad->bit_name, bad->bit_val)); - blkid_free_tag(bad); - } - blkid_free_tag(tag); - } - - blkid_free_probe(cache->probe); - - free(cache->bic_filename); - free(cache); -} - -/** - * blkid_gc_cache: - * @cache: cache handler - * - * Removes garbage (non-existing devices) from the cache. - */ -void blkid_gc_cache(blkid_cache cache) -{ - struct list_head *p, *pnext; - struct stat st; - - if (!cache) - return; - - list_for_each_safe(p, pnext, &cache->bic_devs) { - blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); - if (stat(dev->bid_name, &st) < 0) { - DBG(DEBUG_CACHE, - printf("freeing %s\n", dev->bid_name)); - blkid_free_dev(dev); - cache->bic_flags |= BLKID_BIC_FL_CHANGED; - } else { - DBG(DEBUG_CACHE, - printf("Device %s exists\n", dev->bid_name)); - } - } -} - -#ifdef TEST_PROGRAM -int main(int argc, char** argv) -{ - blkid_cache cache = NULL; - int ret; - - blkid_init_debug(DEBUG_ALL); - - if ((argc > 2)) { - fprintf(stderr, "Usage: %s [filename] \n", argv[0]); - exit(1); - } - - if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { - fprintf(stderr, "error %d parsing cache file %s\n", ret, - argv[1] ? argv[1] : blkid_get_cache_filename(NULL)); - exit(1); - } - if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - if ((ret = blkid_probe_all(cache)) < 0) - fprintf(stderr, "error probing devices\n"); - - blkid_put_cache(cache); - - return ret; -} -#endif diff --git a/libblkid/canonicalize.c b/libblkid/canonicalize.c deleted file mode 100644 index 1e8aff4f2..000000000 --- a/libblkid/canonicalize.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * canonicalize.c -- canonicalize pathname by removing symlinks - * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 Library Public License for more details. - * - */ - -/* - * This routine is part of libc. We include it nevertheless, - * since the libc version has some security flaws. - * - * TODO: use canonicalize_file_name() when exist in glibc - */ -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> - -#include "canonicalize.h" - -#ifndef MAXSYMLINKS -# define MAXSYMLINKS 256 -#endif - -static char * -myrealpath(const char *path, char *resolved_path, int maxreslth) { - int readlinks = 0; - char *npath; - char link_path[PATH_MAX+1]; - int n; - char *buf = NULL; - - npath = resolved_path; - - /* If it's a relative pathname use getcwd for starters. */ - if (*path != '/') { - if (!getcwd(npath, maxreslth-2)) - return NULL; - npath += strlen(npath); - if (npath[-1] != '/') - *npath++ = '/'; - } else { - *npath++ = '/'; - path++; - } - - /* Expand each slash-separated pathname component. */ - while (*path != '\0') { - /* Ignore stray "/" */ - if (*path == '/') { - path++; - continue; - } - if (*path == '.' && (path[1] == '\0' || path[1] == '/')) { - /* Ignore "." */ - path++; - continue; - } - if (*path == '.' && path[1] == '.' && - (path[2] == '\0' || path[2] == '/')) { - /* Backup for ".." */ - path += 2; - while (npath > resolved_path+1 && - (--npath)[-1] != '/') - ; - continue; - } - /* Safely copy the next pathname component. */ - while (*path != '\0' && *path != '/') { - if (npath-resolved_path > maxreslth-2) { - errno = ENAMETOOLONG; - goto err; - } - *npath++ = *path++; - } - - /* Protect against infinite loops. */ - if (readlinks++ > MAXSYMLINKS) { - errno = ELOOP; - goto err; - } - - /* See if last pathname component is a symlink. */ - *npath = '\0'; - n = readlink(resolved_path, link_path, PATH_MAX); - if (n < 0) { - /* EINVAL means the file exists but isn't a symlink. */ - if (errno != EINVAL) - goto err; - } else { - int m; - char *newbuf; - - /* Note: readlink doesn't add the null byte. */ - link_path[n] = '\0'; - if (*link_path == '/') - /* Start over for an absolute symlink. */ - npath = resolved_path; - else - /* Otherwise back up over this component. */ - while (*(--npath) != '/') - ; - - /* Insert symlink contents into path. */ - m = strlen(path); - newbuf = malloc(m + n + 1); - if (!newbuf) - goto err; - memcpy(newbuf, link_path, n); - memcpy(newbuf + n, path, m + 1); - free(buf); - path = buf = newbuf; - } - *npath++ = '/'; - } - /* Delete trailing slash but don't whomp a lone slash. */ - if (npath != resolved_path+1 && npath[-1] == '/') - npath--; - /* Make sure it's null terminated. */ - *npath = '\0'; - - free(buf); - return resolved_path; - - err: - free(buf); - return NULL; -} - -/* - * Converts private "dm-N" names to "/dev/mapper/<name>" - * - * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs - * provides the real DM device names in /sys/block/<ptname>/dm/name - */ -char * -canonicalize_dm_name(const char *ptname) -{ - FILE *f; - size_t sz; - char path[256], name[256], *res = NULL; - - snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); - if (!(f = fopen(path, "r"))) - return NULL; - - /* read "<name>\n" from sysfs */ - if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { - name[sz - 1] = '\0'; - snprintf(path, sizeof(path), "/dev/mapper/%s", name); - res = strdup(path); - } - fclose(f); - return res; -} - -char * -canonicalize_path(const char *path) -{ - char canonical[PATH_MAX+2]; - char *p; - - if (path == NULL) - return NULL; - - if (!myrealpath(path, canonical, PATH_MAX+1)) - return strdup(path); - - - p = strrchr(canonical, '/'); - if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { - p = canonicalize_dm_name(p+1); - if (p) - return p; - } - - return strdup(canonical); -} - -char * -canonicalize_path_restricted(const char *path) -{ - char canonical[PATH_MAX+2]; - char *p = NULL; - int errsv; - uid_t euid; - gid_t egid; - - if (path == NULL) - return NULL; - - euid = geteuid(); - egid = getegid(); - - /* drop permissions */ - if (setegid(getgid()) < 0 || seteuid(getuid()) < 0) - return NULL; - - errsv = errno = 0; - - if (myrealpath(path, canonical, PATH_MAX+1)) { - p = strrchr(canonical, '/'); - if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) - p = canonicalize_dm_name(p+1); - else - p = NULL; - if (!p) - p = strdup(canonical); - } else - errsv = errno; - - /* restore */ - if (setegid(egid) < 0 || seteuid(euid) < 0) { - free(p); - return NULL; - } - - errno = errsv; - return p; -} - - -#ifdef TEST_PROGRAM_CANONICALIZE -int main(int argc, char **argv) -{ - if (argc < 2) { - fprintf(stderr, "usage: %s <device>\n", argv[0]); - exit(EXIT_FAILURE); - } - - fprintf(stdout, "orig: %s\n", argv[1]); - fprintf(stdout, "real: %s\n", canonicalize_path(argv[1])); - - exit(EXIT_SUCCESS); -} -#endif diff --git a/libblkid/carefulputc.h b/libblkid/carefulputc.h deleted file mode 100644 index 2d857ebb0..000000000 --- a/libblkid/carefulputc.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _CAREFUULPUTC_H -#define _CAREFUULPUTC_H - -/* putc() for use in write and wall (that sometimes are sgid tty) */ -/* Avoid control characters in our locale, and also ASCII control characters. - Note that the locale of the recipient is unknown. */ -#include <stdio.h> -#include <ctype.h> - -#define iso8859x_iscntrl(c) \ - (((c) & 0x7f) < 0x20 || (c) == 0x7f) - -static inline int carefulputc(int c, FILE *fp) { - int ret; - - if (c == '\007' || c == '\t' || c == '\r' || c == '\n' || - (!iso8859x_iscntrl(c) && (isprint(c) || isspace(c)))) - ret = putc(c, fp); - else if ((c & 0x80) || !isprint(c^0x40)) - ret = fprintf(fp, "\\%3o", (unsigned char) c); - else { - ret = putc('^', fp); - if (ret != EOF) - ret = putc(c^0x40, fp); - } - return (ret < 0) ? EOF : 0; -} - -#endif /* _CAREFUULPUTC_H */ diff --git a/libblkid/closestream.h b/libblkid/closestream.h deleted file mode 100644 index d61b83b5e..000000000 --- a/libblkid/closestream.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef UTIL_LINUX_CLOSESTREAM_H -#define UTIL_LINUX_CLOSESTREAM_H - -#include <stdio.h> -#ifdef HAVE_STDIO_EXT_H -#include <stdio_ext.h> -#endif -#include <unistd.h> - -#include "c.h" -#include "nls.h" - -#ifndef HAVE___FPENDING -static inline int -__fpending(FILE *stream __attribute__((__unused__))) -{ - return 0; -} -#endif - -static inline int -close_stream(FILE * stream) -{ - const int some_pending = (__fpending(stream) != 0); - const int prev_fail = (ferror(stream) != 0); - const int fclose_fail = (fclose(stream) != 0); - if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) { - if (!fclose_fail) - errno = 0; - return EOF; - } - return 0; -} - -/* Meant to be used atexit(close_stdout); */ -static inline void -close_stdout(void) -{ - if (close_stream(stdout) != 0 && !(errno == EPIPE)) { - if (errno) - warn(_("write error")); - else - warnx(_("write error")); - _exit(EXIT_FAILURE); - } - - if (close_stream(stderr) != 0) - _exit(EXIT_FAILURE); -} - -#endif /* UTIL_LINUX_CLOSESTREAM_H */ diff --git a/libblkid/colors.c b/libblkid/colors.c deleted file mode 100644 index bb9c057e1..000000000 --- a/libblkid/colors.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com> - * - * This file may be distributed under the terms of the - * GNU Lesser General Public License. - */ - -#include "colors.h" - -static int ul_color_term_ok; - -int colors_init(void) -{ - ul_color_term_ok = isatty(STDOUT_FILENO); - return ul_color_term_ok; -} - -void color_enable(const char *color_scheme) -{ - if (ul_color_term_ok) - fputs(color_scheme, stdout); -} - -void color_disable(void) -{ - if (ul_color_term_ok) - fputs(UL_COLOR_RESET, stdout); -} diff --git a/libblkid/colors.h b/libblkid/colors.h deleted file mode 100644 index 0eb19464f..000000000 --- a/libblkid/colors.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com> - * - * This file may be distributed under the terms of the - * GNU Lesser General Public License. - */ -#ifndef UTIL_LINUX_COLORS_H -#define UTIL_LINUX_COLORS_H - -#include <stdio.h> -#include <unistd.h> - -#define UL_COLOR_RESET "\033[0m" -#define UL_COLOR_BOLD "\033[1m" -#define UL_COLOR_HALFBRIGHT "\033[2m" -#define UL_COLOR_UNDERSCORE "\033[4m" -#define UL_COLOR_BLINK "\033[5m" -#define UL_COLOR_REVERSE "\033[7m" - -/* Standard colors */ -#define UL_COLOR_BLACK "\033[30m" -#define UL_COLOR_RED "\033[31m" -#define UL_COLOR_GREEN "\033[32m" -#define UL_COLOR_YELLOW "\033[33m" -#define UL_COLOR_BLUE "\033[34m" -#define UL_COLOR_MAGENTA "\033[35m" -#define UL_COLOR_CYAN "\033[36m" -#define UL_COLOR_GRAY "\033[37m" - -/* Bold variants */ -#define UL_COLOR_DARK_GRAY "\033[1;30m" -#define UL_COLOR_BOLD_RED "\033[1;31m" -#define UL_COLOR_BOLD_GREEN "\033[1;32m" -#define UL_COLOR_BOLD_YELLOW "\033[1;33m" -#define UL_COLOR_BOLD_BLUE "\033[1;34m" -#define UL_COLOR_BOLD_MAGENTA "\033[1;35m" -#define UL_COLOR_BOLD_CYAN "\033[1;36m" - -#define UL_COLOR_WHITE "\033[1;37m" - -/* Initialize the global variable OUT_IS_TERM */ -extern int colors_init(void); - -/* Set the color to CLR_SCHEME */ -extern void color_enable(const char *clr_scheme); - -/* Reset colors to default */ -extern void color_disable(void); - -#endif /* UTIL_LINUX_COLORS_H */ diff --git a/libblkid/config.c b/libblkid/config.c deleted file mode 100644 index edad6cd7c..000000000 --- a/libblkid/config.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * config.c - blkid.conf routines - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <stdint.h> -#include <stdarg.h> - -#include "blkidP.h" -#include "env.h" - -static int parse_evaluate(struct blkid_config *conf, char *s) -{ - while(s && *s) { - char *sep; - - if (conf->nevals >= __BLKID_EVAL_LAST) - goto err; - sep = strchr(s, ','); - if (sep) - *sep = '\0'; - if (strcmp(s, "udev") == 0) - conf->eval[conf->nevals] = BLKID_EVAL_UDEV; - else if (strcmp(s, "scan") == 0) - conf->eval[conf->nevals] = BLKID_EVAL_SCAN; - else - goto err; - conf->nevals++; - if (sep) - s = sep + 1; - else - break; - } - return 0; -err: - DBG(DEBUG_CONFIG, printf( - "config file: unknown evaluation method '%s'.\n", s)); - return -1; -} - -static int parse_next(FILE *fd, struct blkid_config *conf) -{ - char buf[BUFSIZ]; - char *s; - - /* read the next non-blank non-comment line */ - do { - if (fgets (buf, sizeof(buf), fd) == NULL) - return feof(fd) ? 0 : -1; - s = strchr (buf, '\n'); - if (!s) { - /* Missing final newline? Otherwise extremely */ - /* long line - assume file was corrupted */ - if (feof(fd)) - s = strchr (buf, '\0'); - else { - DBG(DEBUG_CONFIG, fprintf(stderr, - "libblkid: config file: missing newline at line '%s'.\n", - buf)); - return -1; - } - } - *s = '\0'; - if (--s >= buf && *s == '\r') - *s = '\0'; - - s = buf; - while (*s == ' ' || *s == '\t') /* skip space */ - s++; - - } while (*s == '\0' || *s == '#'); - - if (!strncmp(s, "SEND_UEVENT=", 12)) { - s += 13; - if (*s && !strcasecmp(s, "yes")) - conf->uevent = TRUE; - else if (*s) - conf->uevent = FALSE; - } else if (!strncmp(s, "CACHE_FILE=", 11)) { - s += 11; - if (*s) - conf->cachefile = strdup(s); - } else if (!strncmp(s, "EVALUATE=", 9)) { - s += 9; - if (*s && parse_evaluate(conf, s) == -1) - return -1; - } else { - DBG(DEBUG_CONFIG, printf( - "config file: unknown option '%s'.\n", s)); - return -1; - } - return 0; -} - -/* return real config data or built-in default */ -struct blkid_config *blkid_read_config(const char *filename) -{ - struct blkid_config *conf; - FILE *f; - - if (!filename) - filename = safe_getenv("BLKID_CONF"); - if (!filename) - filename = BLKID_CONFIG_FILE; - - conf = (struct blkid_config *) calloc(1, sizeof(*conf)); - if (!conf) - return NULL; - conf->uevent = -1; - - DBG(DEBUG_CONFIG, fprintf(stderr, - "reading config file: %s.\n", filename)); - - f = fopen(filename, "r"); - if (!f) { - DBG(DEBUG_CONFIG, fprintf(stderr, - "%s: does not exist, using built-in default\n", filename)); - goto dflt; - } - while (!feof(f)) { - if (parse_next(f, conf)) { - DBG(DEBUG_CONFIG, fprintf(stderr, - "%s: parse error\n", filename)); - goto err; - } - } -dflt: - if (!conf->nevals) { - conf->eval[0] = BLKID_EVAL_UDEV; - conf->eval[1] = BLKID_EVAL_SCAN; - conf->nevals = 2; - } - if (!conf->cachefile) - conf->cachefile = strdup(BLKID_CACHE_FILE); - if (conf->uevent == -1) - conf->uevent = TRUE; - if (f) - fclose(f); - return conf; -err: - free(conf); - fclose(f); - return NULL; -} - -void blkid_free_config(struct blkid_config *conf) -{ - if (!conf) - return; - free(conf->cachefile); - free(conf); -} - -#ifdef TEST_PROGRAM -/* - * usage: tst_config [<filename>] - */ -int main(int argc, char *argv[]) -{ - int i; - struct blkid_config *conf; - char *filename = NULL; - - blkid_init_debug(DEBUG_ALL); - - if (argc == 2) - filename = argv[1]; - - conf = blkid_read_config(filename); - if (!conf) - return EXIT_FAILURE; - - printf("EVALUATE: "); - for (i = 0; i < conf->nevals; i++) - printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan"); - printf("\n"); - - printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE"); - printf("CACHE_FILE: %s\n", conf->cachefile); - - blkid_free_config(conf); - return EXIT_SUCCESS; -} -#endif diff --git a/libblkid/config.h b/libblkid/config.h deleted file mode 100644 index 3b4b18ba8..000000000 --- a/libblkid/config.h +++ /dev/null @@ -1,654 +0,0 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if building universal (internal helper macro) */ -/* #undef AC_APPLE_UNIVERSAL_BUILD */ - -/* Should chfn and chsh require the user to enter the password? */ -#define CHFN_CHSH_PASSWORD 1 - -/* Define to 1 if translation of program messages to the user's native - language is requested. */ -#define ENABLE_NLS 1 - -/* search path for fs helpers */ -#define FS_SEARCH_PATH "/sbin:/sbin/fs.d:/sbin/fs" - -/* Define to 1 if you have the <asm/io.h> header file. */ -/* #undef HAVE_ASM_IO_H */ - -/* Define to 1 if you have the <byteswap.h> header file. */ -#define HAVE_BYTESWAP_H 1 - -/* Define to 1 if the system has the type `cpu_set_t'. */ -#define HAVE_CPU_SET_T 1 - -/* Define to 1 if you have the <crypt.h> header file. */ -#define HAVE_CRYPT_H 1 - -/* Define if the GNU dcgettext() function is already present or preinstalled. - */ -#define HAVE_DCGETTEXT 1 - -/* Define to 1 if you have the declaration of `ADDR_COMPAT_LAYOUT', and to 0 - if you don't. */ -#define HAVE_DECL_ADDR_COMPAT_LAYOUT 1 - -/* Define to 1 if you have the declaration of `ADDR_LIMIT_32BIT', and to 0 if - you don't. */ -#define HAVE_DECL_ADDR_LIMIT_32BIT 1 - -/* Define to 1 if you have the declaration of `ADDR_LIMIT_3GB', and to 0 if - you don't. */ -#define HAVE_DECL_ADDR_LIMIT_3GB 1 - -/* Define to 1 if you have the declaration of `ADDR_NO_RANDOMIZE', and to 0 if - you don't. */ -#define HAVE_DECL_ADDR_NO_RANDOMIZE 1 - -/* Define to 1 if you have the declaration of `CPU_ALLOC', and to 0 if you - don't. */ -#define HAVE_DECL_CPU_ALLOC 1 - -/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't. - */ -/* #undef HAVE_DECL_DIRFD */ - -/* Define to 1 if you have the declaration of `FDPIC_FUNCPTRS', and to 0 if - you don't. */ -#define HAVE_DECL_FDPIC_FUNCPTRS 1 - -/* Define to 1 if you have the declaration of `MMAP_PAGE_ZERO', and to 0 if - you don't. */ -#define HAVE_DECL_MMAP_PAGE_ZERO 1 - -/* Define to 1 if you have the declaration of `READ_IMPLIES_EXEC', and to 0 if - you don't. */ -#define HAVE_DECL_READ_IMPLIES_EXEC 1 - -/* Define to 1 if you have the declaration of `STICKY_TIMEOUTS', and to 0 if - you don't. */ -#define HAVE_DECL_STICKY_TIMEOUTS 1 - -/* Define to 1 if you have the declaration of `UNAME26', and to 0 if you - don't. */ -#define HAVE_DECL_UNAME26 1 - -/* Define to 1 if you have the declaration of `WHOLE_SECONDS', and to 0 if you - don't. */ -#define HAVE_DECL_WHOLE_SECONDS 1 - -/* Define to 1 if you have the declaration of `_NL_TIME_WEEK_1STDAY', and to 0 - if you don't. */ -#define HAVE_DECL__NL_TIME_WEEK_1STDAY 1 - -/* Define to 1 if you have the `dirfd' function. */ -#define HAVE_DIRFD 1 - -/* Define to 1 if `dd_fd' is a member of `DIR'. */ -/* #undef HAVE_DIR_DD_FD */ - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the <endian.h> header file. */ -#define HAVE_ENDIAN_H 1 - -/* Define to 1 if have **environ prototype */ -#define HAVE_ENVIRON_DECL 1 - -/* Define to 1 if you have the `err' function. */ -#define HAVE_ERR 1 - -/* Define to 1 if you have the <errno.h> header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the `errx' function. */ -#define HAVE_ERRX 1 - -/* Define to 1 if you have the <err.h> header file. */ -#define HAVE_ERR_H 1 - -/* Have valid fallocate() function */ -#define HAVE_FALLOCATE 1 - -/* Define to 1 if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -#define HAVE_FSEEKO 1 - -/* Define to 1 if you have the `fstatat' function. */ -#define HAVE_FSTATAT 1 - -/* Define to 1 if you have the `fsync' function. */ -#define HAVE_FSYNC 1 - -/* Define to 1 if you have the `futimens' function. */ -#define HAVE_FUTIMENS 1 - -/* Define to 1 if you have the `getdomainname' function. */ -#define HAVE_GETDOMAINNAME 1 - -/* Define to 1 if you have the `getdtablesize' function. */ -#define HAVE_GETDTABLESIZE 1 - -/* Define to 1 if you have the `getexecname' function. */ -/* #undef HAVE_GETEXECNAME */ - -/* Define to 1 if you have the `getmntinfo' function. */ -/* #undef HAVE_GETMNTINFO */ - -/* Define to 1 if you have the <getopt.h> header file. */ -#define HAVE_GETOPT_H 1 - -/* Define to 1 if you have the `getrlimit' function. */ -#define HAVE_GETRLIMIT 1 - -/* Define if the GNU gettext() function is already present or preinstalled. */ -#define HAVE_GETTEXT 1 - -/* Define if you have the iconv() function. */ -/* #undef HAVE_ICONV */ - -/* Define to 1 if you have the `inotify_init' function. */ -#define HAVE_INOTIFY_INIT 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `ioperm' function. */ -#define HAVE_IOPERM 1 - -/* Define to 1 if you have the `iopl' function. */ -#define HAVE_IOPL 1 - -/* Define to 1 if you have the `jrand48' function. */ -#define HAVE_JRAND48 1 - -/* Define to 1 if you have the <langinfo.h> header file. */ -#define HAVE_LANGINFO_H 1 - -/* Define to 1 if you have the `lchown' function. */ -#define HAVE_LCHOWN 1 - -/* Define to 1 if you have the `audit' library (-laudit). */ -/* #undef HAVE_LIBAUDIT */ - -/* Define to 1 if you have the -lblkid. */ -#define HAVE_LIBBLKID 1 - -/* Define to 1 if you have the `cap-ng' library (-lcap-ng). */ -/* #undef HAVE_LIBCAP_NG */ - -/* Do we need -lcrypt? */ -#define HAVE_LIBCRYPT 1 - -/* Define to 1 if you have the `ncurses' library (-lncurses). */ -#define HAVE_LIBNCURSES 1 - -/* Define to 1 if you have the `ncursesw' library (-lncursesw). */ -/* #undef HAVE_LIBNCURSESW */ - -/* Define if SELinux is available */ -/* #undef HAVE_LIBSELINUX */ - -/* Define to 1 if you have the `termcap' library (-ltermcap). */ -#define HAVE_LIBTERMCAP 1 - -/* Define to 1 if you have the `udev' library (-ludev). */ -/* #undef HAVE_LIBUDEV */ - -/* Define to 1 if you have the `user' library (-luser). */ -/* #undef HAVE_LIBUSER */ - -/* Define to 1 if you have the `utempter' library (-lutempter). */ -/* #undef HAVE_LIBUTEMPTER */ - -/* Define to 1 if you have the `util' library (-lutil). */ -#define HAVE_LIBUTIL 1 - -/* Define to 1 if you have the -luuid. */ -#define HAVE_LIBUUID 1 - -/* Define to 1 if you have the <linux/blkpg.h> header file. */ -#define HAVE_LINUX_BLKPG_H 1 - -/* Define to 1 if you have the <linux/cdrom.h> header file. */ -#define HAVE_LINUX_CDROM_H 1 - -/* Define to 1 if you have the <linux/compiler.h> header file. */ -/* #undef HAVE_LINUX_COMPILER_H */ - -/* Define to 1 if you have the <linux/falloc.h> header file. */ -#define HAVE_LINUX_FALLOC_H 1 - -/* Define to 1 if you have the <linux/fd.h> header file. */ -#define HAVE_LINUX_FD_H 1 - -/* Define to 1 if you have the <linux/major.h> header file. */ -#define HAVE_LINUX_MAJOR_H 1 - -/* Define to 1 if you have the <linux/raw.h> header file. */ -#define HAVE_LINUX_RAW_H 1 - -/* Define to 1 if you have the <linux/tiocl.h> header file. */ -#define HAVE_LINUX_TIOCL_H 1 - -/* Define to 1 if you have the <linux/version.h> header file. */ -#define HAVE_LINUX_VERSION_H 1 - -/* Define to 1 if you have the <linux/watchdog.h> header file. */ -#define HAVE_LINUX_WATCHDOG_H 1 - -/* Define to 1 if you have the `llseek' function. */ -#define HAVE_LLSEEK 1 - -/* Define to 1 if have llseek prototype */ -/* #undef HAVE_LLSEEK_PROTOTYPE */ - -/* Define to 1 if you have the <locale.h> header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if the system has the type `loff_t'. */ -#define HAVE_LOFF_T 1 - -/* Define to 1 if you have the `lseek64' function. */ -#define HAVE_LSEEK64 1 - -/* Define to 1 if have lseek64 prototype */ -#define HAVE_LSEEK64_PROTOTYPE 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `mempcpy' function. */ -#define HAVE_MEMPCPY 0 - -/* Define to 1 if you have the <mntent.h> header file. */ -#define HAVE_MNTENT_H 1 - -/* Define to 1 if you have the `nanosleep' function. */ -#define HAVE_NANOSLEEP 1 - -/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */ -/* #undef HAVE_NCURSESW_NCURSES_H */ - -/* Define to 1 if you have the <ncurses.h> header file. */ -#define HAVE_NCURSES_H 1 - -/* Define to 1 if you have the <ncurses/ncurses.h> header file. */ -/* #undef HAVE_NCURSES_NCURSES_H */ - -/* Define to 1 if you have the <netinet/in.h> header file. */ -#define HAVE_NETINET_IN_H 1 - -/* Define to 1 if you have the <net/if_dl.h> header file. */ -/* #undef HAVE_NET_IF_DL_H */ - -/* Define to 1 if you have the <net/if.h> header file. */ -#define HAVE_NET_IF_H 1 - -/* Define to 1 if you have the `openat' function. */ -#define HAVE_OPENAT 1 - -/* Define to 1 if you have the <paths.h> header file. */ -#define HAVE_PATHS_H 1 - -/* Define to 1 if you have the `personality' function. */ -#define HAVE_PERSONALITY 1 - -/* Define to 1 if you have the `posix_fadvise' function. */ -#define HAVE_POSIX_FADVISE 1 - -/* Define to 1 if you have the `prctl' function. */ -#define HAVE_PRCTL 1 - -/* Define to 1 if you have the `prlimit' function. */ -#define HAVE_PRLIMIT 1 - -/* Define if program_invocation_short_name is defined */ -#define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 - -/* Define to 1 if you have the <pty.h> header file. */ -#define HAVE_PTY_H 1 - -/* Define to 1 if you have the `rpmatch' function. */ -#define HAVE_RPMATCH 1 - -/* Define if struct sockaddr contains sa_len */ -/* #undef HAVE_SA_LEN */ - -/* Define to 1 if you have the `scandirat' function. */ -#define HAVE_SCANDIRAT 1 - -/* scanf %as modifier */ -/* #undef HAVE_SCANF_AS_MODIFIER */ - -/* scanf %ms modifier */ -#define HAVE_SCANF_MS_MODIFIER 1 - -/* Define to 1 if you have the `secure_getenv' function. */ -/* #undef HAVE_SECURE_GETENV */ - -/* Define to 1 if you have the <security/pam_misc.h> header file. */ -#define HAVE_SECURITY_PAM_MISC_H 1 - -/* Define to 1 if you have the `setns' function. */ -#define HAVE_SETNS 1 - -/* Define to 1 if you have the `setresgid' function. */ -#define HAVE_SETRESGID 1 - -/* Define to 1 if you have the `setresuid' function. */ -#define HAVE_SETRESUID 1 - -/* Define to 1 if you have the `sigqueue' function. */ -#define HAVE_SIGQUEUE 1 - -/* Define to 1 if you have the <slang.h> header file. */ -/* #undef HAVE_SLANG_H */ - -/* Define to 1 if you have the <slang/slang.h> header file. */ -/* #undef HAVE_SLANG_SLANG_H */ - -/* Define to 1 if you have the <slang/slcurses.h> header file. */ -/* #undef HAVE_SLANG_SLCURSES_H */ - -/* Define to 1 if you have the <slcurses.h> header file. */ -/* #undef HAVE_SLCURSES_H */ - -/* Define to 1 if you have the `srandom' function. */ -#define HAVE_SRANDOM 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdio_ext.h> header file. */ -#define HAVE_STDIO_EXT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strnchr' function. */ -/* #undef HAVE_STRNCHR */ - -/* Define to 1 if you have the `strndup' function. */ -#define HAVE_STRNDUP 1 - -/* Define to 1 if you have the `strnlen' function. */ -#define HAVE_STRNLEN 1 - -/* Define to 1 if have strsignal function prototype */ -#define HAVE_STRSIGNAL_DECL 1 - -/* Define to 1 if you have the `strtoull' function. */ -#define HAVE_STRTOULL 1 - -/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 - -/* Define to 1 if `c_line' is a member of `struct termios'. */ -#define HAVE_STRUCT_TERMIOS_C_LINE 1 - -/* Define to 1 if you have the `sysconf' function. */ -#define HAVE_SYSCONF 1 - -/* Define to 1 if you have the <sys/disklabel.h> header file. */ -/* #undef HAVE_SYS_DISKLABEL_H */ - -/* Define to 1 if you have the <sys/disk.h> header file. */ -/* #undef HAVE_SYS_DISK_H */ - -/* Define to 1 if you have the <sys/endian.h> header file. */ -/* #undef HAVE_SYS_ENDIAN_H */ - -/* Define to 1 if you have the <sys/file.h> header file. */ -#define HAVE_SYS_FILE_H 1 - -/* Define to 1 if you have the <sys/ioccom.h> header file. */ -/* #undef HAVE_SYS_IOCCOM_H */ - -/* Define to 1 if you have the <sys/ioctl.h> header file. */ -#define HAVE_SYS_IOCTL_H 1 - -/* Define to 1 if you have the <sys/io.h> header file. */ -#define HAVE_SYS_IO_H 1 - -/* Define to 1 if you have the <sys/mkdev.h> header file. */ -/* #undef HAVE_SYS_MKDEV_H */ - -/* Define to 1 if you have the <sys/prctl.h> header file. */ -#define HAVE_SYS_PRCTL_H 1 - -/* Define to 1 if you have the <sys/queue.h> header file. */ -#define HAVE_SYS_QUEUE_H 1 - -/* Define to 1 if you have the <sys/resource.h> header file. */ -#define HAVE_SYS_RESOURCE_H 1 - -/* Define to 1 if you have the <sys/socket.h> header file. */ -#define HAVE_SYS_SOCKET_H 1 - -/* Define to 1 if you have the <sys/sockio.h> header file. */ -/* #undef HAVE_SYS_SOCKIO_H */ - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/swap.h> header file. */ -#define HAVE_SYS_SWAP_H 1 - -/* Define to 1 if you have the <sys/syscall.h> header file. */ -#define HAVE_SYS_SYSCALL_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -#define HAVE_SYS_TIME_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <sys/un.h> header file. */ -#define HAVE_SYS_UN_H 1 - -/* Define to 1 if the target supports thread-local storage. */ -#define HAVE_TLS 1 - -/* Does struct tm have a field tm_gmtoff? */ -#define HAVE_TM_GMTOFF 1 - -/* Define to 1 if the system has the type `union semun'. */ -/* #undef HAVE_UNION_SEMUN */ - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to 1 if you have the `unlinkat' function. */ -#define HAVE_UNLINKAT 1 - -/* Define to 1 if you have the `unshare' function. */ -#define HAVE_UNSHARE 1 - -/* Define to 1 if you have the `updwtmp' function. */ -#define HAVE_UPDWTMP 1 - -/* Define to 1 if you have the `usleep' function. */ -#define HAVE_USLEEP 1 - -/* Define to 1 if you want to use uuid daemon. */ -#define HAVE_UUIDD 1 - -/* Define to 1 if you have the `warn' function. */ -#define HAVE_WARN 1 - -/* Define to 1 if you have the `warnx' function. */ -#define HAVE_WARNX 1 - -/* Do we have wide character support? */ -#define HAVE_WIDECHAR 1 - -/* Define to 1 if you have the `__fpending' function. */ -#define HAVE___FPENDING 1 - -/* Define if __progname is defined */ -#define HAVE___PROGNAME 1 - -/* Define to 1 if you have the `__secure_getenv' function. */ -#define HAVE___SECURE_GETENV 1 - -/* libblkid date string */ -#define LIBBLKID_DATE "04-Sep-2012" - -/* libblkid version string */ -#define LIBBLKID_VERSION "2.22.0" - -/* libmount version string */ -#define LIBMOUNT_VERSION "2.22.0" - -/* Should login chown /dev/vcsN? */ -/* #undef LOGIN_CHOWN_VCS */ - -/* Should login stat() the mailbox? */ -/* #undef LOGIN_STAT_MAIL */ - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Should chsh allow only shells in /etc/shells? */ -#define ONLY_LISTED_SHELLS 1 - -/* Name of package */ -#define PACKAGE "util-linux" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "kzak@redhat.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "util-linux" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "util-linux 2.22.552-d48f6" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "util-linux" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "http://www.kernel.org/pub/linux/utils/util-linux/" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "2.22.552-d48f6" - -/* Should pg ring the bell on invalid keys? */ -#define PG_BELL 1 - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Is swapon() declared with two parameters? */ -#define SWAPON_HAS_TWO_ARGS 1 - -/* Fallback syscall number for fallocate */ -/* #undef SYS_fallocate */ - -/* Fallback syscall number for ioprio_get */ -/* #undef SYS_ioprio_get */ - -/* Fallback syscall number for ioprio_set */ -/* #undef SYS_ioprio_set */ - -/* Fallback syscall number for pivot_root */ -/* #undef SYS_pivot_root */ - -/* Fallback syscall number for prlimit64 */ -/* #undef SYS_prlimit64 */ - -/* Fallback syscall number for sched_getaffinity */ -/* #undef SYS_sched_getaffinity */ - -/* Fallback syscall number for setns */ -/* #undef SYS_setns */ - -/* Fallback syscall number for unshare */ -/* #undef SYS_unshare */ - -/* Should uuidd support socket activation? */ -/* #undef USE_SOCKET_ACTIVATION */ - -/* Should sulogin use a emergency mount of /dev and /proc? */ -/* #undef USE_SULOGIN_EMERGENCY_MOUNT */ - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# define _ALL_SOURCE 1 -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS 1 -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# define _TANDEM_SOURCE 1 -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# define __EXTENSIONS__ 1 -#endif - - -/* Should wall and write be installed setgid tty? */ -#define USE_TTY_GROUP 1 - -/* Version number of package */ -#define VERSION "2.22.552-d48f6" - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ -# endif -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to empty if the keyword `volatile' does not work. Warning: valid - code using `volatile' can become incorrect without. Disable with care. */ -/* #undef volatile */ diff --git a/libblkid/cpuset.c b/libblkid/cpuset.c deleted file mode 100644 index e5b6b9dfe..000000000 --- a/libblkid/cpuset.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Terminology: - * - * cpuset - (libc) cpu_set_t data structure represents set of CPUs - * cpumask - string with hex mask (e.g. "0x00000001") - * cpulist - string with CPU ranges (e.g. "0-3,5,7,8") - * - * Based on code from taskset.c and Linux kernel. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * Copyright (C) 2010 Karel Zak <kzak@redhat.com> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sched.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <sys/syscall.h> - -#include "cpuset.h" -#include "c.h" - -static inline int val_to_char(int v) -{ - if (v >= 0 && v < 10) - return '0' + v; - else if (v >= 10 && v < 16) - return ('a' - 10) + v; - else - return -1; -} - -static inline int char_to_val(int c) -{ - int cl; - - cl = tolower(c); - if (c >= '0' && c <= '9') - return c - '0'; - else if (cl >= 'a' && cl <= 'f') - return cl + (10 - 'a'); - else - return -1; -} - -static const char *nexttoken(const char *q, int sep) -{ - if (q) - q = strchr(q, sep); - if (q) - q++; - return q; -} - -/* - * Number of bits in a CPU bitmask on current system - */ -int get_max_number_of_cpus(void) -{ -#ifdef SYS_sched_getaffinity - int n, cpus = 2048; - size_t setsize; - cpu_set_t *set = cpuset_alloc(cpus, &setsize, NULL); - - if (!set) - return -1; /* error */ - - for (;;) { - CPU_ZERO_S(setsize, set); - - /* the library version does not return size of cpumask_t */ - n = syscall(SYS_sched_getaffinity, 0, setsize, set); - - if (n < 0 && errno == EINVAL && cpus < 1024 * 1024) { - cpuset_free(set); - cpus *= 2; - set = cpuset_alloc(cpus, &setsize, NULL); - if (!set) - return -1; /* error */ - continue; - } - cpuset_free(set); - return n * 8; - } -#endif - return -1; -} - -/* - * Allocates a new set for ncpus and returns size in bytes and size in bits - */ -cpu_set_t *cpuset_alloc(int ncpus, size_t *setsize, size_t *nbits) -{ - cpu_set_t *set = CPU_ALLOC(ncpus); - - if (!set) - return NULL; - if (setsize) - *setsize = CPU_ALLOC_SIZE(ncpus); - if (nbits) - *nbits = cpuset_nbits(CPU_ALLOC_SIZE(ncpus)); - return set; -} - -void cpuset_free(cpu_set_t *set) -{ - CPU_FREE(set); -} - -#if !HAVE_DECL_CPU_ALLOC -/* Please, use CPU_COUNT_S() macro. This is fallback */ -int __cpuset_count_s(size_t setsize, const cpu_set_t *set) -{ - int s = 0; - const __cpu_mask *p = set->__bits; - const __cpu_mask *end = &set->__bits[setsize / sizeof (__cpu_mask)]; - - while (p < end) { - __cpu_mask l = *p++; - - if (l == 0) - continue; -# if LONG_BIT > 32 - l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); - l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); - l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); - l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); - l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); - l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); -# else - l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); - l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); - l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); - l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); - l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); -# endif - s += l; - } - return s; -} -#endif - -/* - * Returns human readable representation of the cpuset. The output format is - * a list of CPUs with ranges (for example, "0,1,3-9"). - */ -char *cpulist_create(char *str, size_t len, - cpu_set_t *set, size_t setsize) -{ - size_t i; - char *ptr = str; - int entry_made = 0; - size_t max = cpuset_nbits(setsize); - - for (i = 0; i < max; i++) { - if (CPU_ISSET_S(i, setsize, set)) { - int rlen; - size_t j, run = 0; - entry_made = 1; - for (j = i + 1; j < max; j++) { - if (CPU_ISSET_S(j, setsize, set)) - run++; - else - break; - } - if (!run) - rlen = snprintf(ptr, len, "%zd,", i); - else if (run == 1) { - rlen = snprintf(ptr, len, "%zd,%zd,", i, i + 1); - i++; - } else { - rlen = snprintf(ptr, len, "%zd-%zd,", i, i + run); - i += run; - } - if (rlen < 0 || (size_t) rlen + 1 > len) - return NULL; - ptr += rlen; - if (rlen > 0 && len > (size_t) rlen) - len -= rlen; - else - len = 0; - } - } - ptr -= entry_made; - *ptr = '\0'; - - return str; -} - -/* - * Returns string with CPU mask. - */ -char *cpumask_create(char *str, size_t len, - cpu_set_t *set, size_t setsize) -{ - char *ptr = str; - char *ret = NULL; - int cpu; - - for (cpu = cpuset_nbits(setsize) - 4; cpu >= 0; cpu -= 4) { - char val = 0; - - if (len == (size_t) (ptr - str)) - break; - - if (CPU_ISSET_S(cpu, setsize, set)) - val |= 1; - if (CPU_ISSET_S(cpu + 1, setsize, set)) - val |= 2; - if (CPU_ISSET_S(cpu + 2, setsize, set)) - val |= 4; - if (CPU_ISSET_S(cpu + 3, setsize, set)) - val |= 8; - - if (!ret && val) - ret = ptr; - *ptr++ = val_to_char(val); - } - *ptr = '\0'; - return ret ? ret : ptr - 1; -} - -/* - * Parses string with CPUs mask. - */ -int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize) -{ - int len = strlen(str); - const char *ptr = str + len - 1; - int cpu = 0; - - /* skip 0x, it's all hex anyway */ - if (len > 1 && !memcmp(str, "0x", 2L)) - str += 2; - - CPU_ZERO_S(setsize, set); - - while (ptr >= str) { - char val; - - /* cpu masks in /sys uses comma as a separator */ - if (*ptr == ',') - ptr--; - - val = char_to_val(*ptr); - if (val == (char) -1) - return -1; - if (val & 1) - CPU_SET_S(cpu, setsize, set); - if (val & 2) - CPU_SET_S(cpu + 1, setsize, set); - if (val & 4) - CPU_SET_S(cpu + 2, setsize, set); - if (val & 8) - CPU_SET_S(cpu + 3, setsize, set); - len--; - ptr--; - cpu += 4; - } - - return 0; -} - -/* - * Parses string with list of CPU ranges. - * Returns 0 on success. - * Returns 1 on error. - * Returns 2 if fail is set and a cpu number passed in the list doesn't fit - * into the cpu_set. If fail is not set cpu numbers that do not fit are - * ignored and 0 is returned instead. - */ -int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail) -{ - size_t max = cpuset_nbits(setsize); - const char *p, *q; - int r = 0; - - q = str; - CPU_ZERO_S(setsize, set); - - while (p = q, q = nexttoken(q, ','), p) { - unsigned int a; /* beginning of range */ - unsigned int b; /* end of range */ - unsigned int s; /* stride */ - const char *c1, *c2; - char c; - - if ((r = sscanf(p, "%u%c", &a, &c)) < 1) - return 1; - b = a; - s = 1; - - c1 = nexttoken(p, '-'); - c2 = nexttoken(p, ','); - if (c1 != NULL && (c2 == NULL || c1 < c2)) { - if ((r = sscanf(c1, "%u%c", &b, &c)) < 1) - return 1; - c1 = nexttoken(c1, ':'); - if (c1 != NULL && (c2 == NULL || c1 < c2)) { - if ((r = sscanf(c1, "%u%c", &s, &c)) < 1) - return 1; - if (s == 0) - return 1; - } - } - - if (!(a <= b)) - return 1; - while (a <= b) { - if (fail && (a >= max)) - return 2; - CPU_SET_S(a, setsize, set); - a += s; - } - } - - if (r == 2) - return 1; - return 0; -} - -#ifdef TEST_PROGRAM - -#include <getopt.h> - -int main(int argc, char *argv[]) -{ - cpu_set_t *set; - size_t setsize, buflen, nbits; - char *buf, *mask = NULL, *range = NULL; - int ncpus = 2048, rc, c; - - static const struct option longopts[] = { - { "ncpus", 1, 0, 'n' }, - { "mask", 1, 0, 'm' }, - { "range", 1, 0, 'r' }, - { NULL, 0, 0, 0 } - }; - - while ((c = getopt_long(argc, argv, "n:m:r:", longopts, NULL)) != -1) { - switch(c) { - case 'n': - ncpus = atoi(optarg); - break; - case 'm': - mask = strdup(optarg); - break; - case 'r': - range = strdup(optarg); - break; - default: - goto usage_err; - } - } - - if (!mask && !range) - goto usage_err; - - set = cpuset_alloc(ncpus, &setsize, &nbits); - if (!set) - err(EXIT_FAILURE, "failed to allocate cpu set"); - - /* - fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n", - ncpus, nbits, setsize); - */ - - buflen = 7 * nbits; - buf = malloc(buflen); - if (!buf) - err(EXIT_FAILURE, "failed to allocate cpu set buffer"); - - if (mask) - rc = cpumask_parse(mask, set, setsize); - else - rc = cpulist_parse(range, set, setsize, 0); - - if (rc) - errx(EXIT_FAILURE, "failed to parse string: %s", mask ? : range); - - printf("%-15s = %15s ", mask ? : range, - cpumask_create(buf, buflen, set, setsize)); - printf("[%s]\n", cpulist_create(buf, buflen, set, setsize)); - - free(buf); - free(range); - cpuset_free(set); - - return EXIT_SUCCESS; - -usage_err: - fprintf(stderr, - "usage: %s [--ncpus <num>] --mask <mask> | --range <list>", - program_invocation_short_name); - exit(EXIT_FAILURE); -} -#endif diff --git a/libblkid/cramfs.c b/libblkid/cramfs.c deleted file mode 100644 index b58ed08cb..000000000 --- a/libblkid/cramfs.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct cramfs_super -{ - uint8_t magic[4]; - uint32_t size; - uint32_t flags; - uint32_t future; - uint8_t signature[16]; - struct cramfs_info - { - uint32_t crc; - uint32_t edition; - uint32_t blocks; - uint32_t files; - } __attribute__((packed)) info; - uint8_t name[16]; -} __attribute__((packed)); - -static int probe_cramfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct cramfs_super *cs; - - cs = blkid_probe_get_sb(pr, mag, struct cramfs_super); - if (!cs) - return -1; - - blkid_probe_set_label(pr, cs->name, sizeof(cs->name)); - return 0; -} - -const struct blkid_idinfo cramfs_idinfo = -{ - .name = "cramfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_cramfs, - .magics = - { - { "\x45\x3d\xcd\x28", 4, 0, 0 }, - { "\x28\xcd\x3d\x45", 4, 0, 0 }, - { NULL } - } -}; - - diff --git a/libblkid/crc32.c b/libblkid/crc32.c deleted file mode 100644 index eaaa06a0c..000000000 --- a/libblkid/crc32.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or - * code or tables extracted from it, as desired without restriction. - * - * First, the polynomial itself and its table of feedback terms. The - * polynomial is - * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 - * - * Note that we take it "backwards" and put the highest-order term in - * the lowest-order bit. The X^32 term is "implied"; the LSB is the - * X^31 term, etc. The X^0 term (usually shown as "+1") results in - * the MSB being 1. - * - * Note that the usual hardware shift register implementation, which - * is what we're using (we're merely optimizing it by doing eight-bit - * chunks at a time) shifts bits into the lowest-order term. In our - * implementation, that means shifting towards the right. Why do we - * do it this way? Because the calculated CRC must be transmitted in - * order from highest-order term to lowest-order term. UARTs transmit - * characters in order from LSB to MSB. By storing the CRC this way, - * we hand it to the UART in the order low-byte to high-byte; the UART - * sends each low-bit to hight-bit; and the result is transmission bit - * by bit from highest- to lowest-order term without requiring any bit - * shuffling on our part. Reception works similarly. - * - * The feedback terms table consists of 256, 32-bit entries. Notes - * - * The table can be generated at runtime if desired; code to do so - * is shown later. It might not be obvious, but the feedback - * terms simply represent the results of eight shift/xor opera- - * tions for all combinations of data and CRC register values. - * - * The values must be right-shifted by eight bits by the "updcrc" - * logic; the shift must be unsigned (bring in zeroes). On some - * hardware you could probably optimize the shift in assembler by - * using byte-swap instructions. - * polynomial $edb88320 - * - */ - -#include <stdio.h> - -#include "crc32.h" - - -static const uint32_t crc32_tab[] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - -/* - * This a generic crc32() function, it takes seed as an argument, - * and does __not__ xor at the end. Then individual users can do - * whatever they need. - */ -uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len) -{ - uint32_t crc = seed; - const unsigned char *p = buf; - - while(len-- > 0) - crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); - - return crc; -} - diff --git a/libblkid/crc32.h b/libblkid/crc32.h deleted file mode 100644 index b454be9fc..000000000 --- a/libblkid/crc32.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UL_NG_CRC32_H -#define UL_NG_CRC32_H - -#include <stdint.h> - -extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len); - -#endif - diff --git a/libblkid/ddf_raid.c b/libblkid/ddf_raid.c deleted file mode 100644 index 24df421d1..000000000 --- a/libblkid/ddf_raid.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -/* http://www.snia.org/standards/home */ -#define DDF_GUID_LENGTH 24 -#define DDF_REV_LENGTH 8 -#define DDF_MAGIC 0xDE11DE11 - - -struct ddf_header { - uint32_t signature; - uint32_t crc; - uint8_t guid[DDF_GUID_LENGTH]; - char ddf_rev[8]; /* 01.02.00 */ - uint32_t seq; /* starts at '1' */ - uint32_t timestamp; - uint8_t openflag; - uint8_t foreignflag; - uint8_t enforcegroups; - uint8_t pad0; /* 0xff */ - uint8_t pad1[12]; /* 12 * 0xff */ - /* 64 bytes so far */ - uint8_t header_ext[32]; /* reserved: fill with 0xff */ - uint64_t primary_lba; - uint64_t secondary_lba; - uint8_t type; - uint8_t pad2[3]; /* 0xff */ - uint32_t workspace_len; /* sectors for vendor space - - * at least 32768(sectors) */ - uint64_t workspace_lba; - uint16_t max_pd_entries; /* one of 15, 63, 255, 1023, 4095 */ - uint16_t max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */ - uint16_t max_partitions; /* i.e. max num of configuration - record entries per disk */ - uint16_t config_record_len; /* 1 +ROUNDUP(max_primary_element_entries - *12/512) */ - uint16_t max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */ - uint8_t pad3[54]; /* 0xff */ - /* 192 bytes so far */ - uint32_t controller_section_offset; - uint32_t controller_section_length; - uint32_t phys_section_offset; - uint32_t phys_section_length; - uint32_t virt_section_offset; - uint32_t virt_section_length; - uint32_t config_section_offset; - uint32_t config_section_length; - uint32_t data_section_offset; - uint32_t data_section_length; - uint32_t bbm_section_offset; - uint32_t bbm_section_length; - uint32_t diag_space_offset; - uint32_t diag_space_length; - uint32_t vendor_offset; - uint32_t vendor_length; - /* 256 bytes so far */ - uint8_t pad4[256]; /* 0xff */ -} __attribute__((packed)); - -static int probe_ddf(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - int hdrs[] = { 1, 257 }; - size_t i; - struct ddf_header *ddf = NULL; - char version[DDF_REV_LENGTH + 1]; - uint64_t off, lba; - - if (pr->size < 0x30000) - return -1; - - for (i = 0; i < ARRAY_SIZE(hdrs); i++) { - off = ((pr->size / 0x200) - hdrs[i]) * 0x200; - - ddf = (struct ddf_header *) blkid_probe_get_buffer(pr, - off, - sizeof(struct ddf_header)); - if (!ddf) - return -1; - - if (ddf->signature == cpu_to_be32(DDF_MAGIC) || - ddf->signature == cpu_to_le32(DDF_MAGIC)) - break; - ddf = NULL; - } - - if (!ddf) - return -1; - - lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ? - be64_to_cpu(ddf->primary_lba) : - le64_to_cpu(ddf->primary_lba); - - if (lba > 0) { - /* check primary header */ - unsigned char *buf; - - buf = blkid_probe_get_buffer(pr, - lba << 9, sizeof(ddf->signature)); - if (!buf || memcmp(buf, &ddf->signature, 4)) - return -1; - } - - blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); - - memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev)); - *(version + sizeof(ddf->ddf_rev)) = '\0'; - - if (blkid_probe_set_version(pr, version) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, - sizeof(ddf->signature), - (unsigned char *) &ddf->signature)) - return -1; - return 0; -} - -const struct blkid_idinfo ddfraid_idinfo = { - .name = "ddf_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_ddf, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/dev.c b/libblkid/dev.c deleted file mode 100644 index 62dfc24d3..000000000 --- a/libblkid/dev.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * dev.c - allocation/initialization/free routines for dev - * - * Copyright (C) 2001 Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#include <stdlib.h> -#include <string.h> - -#include "blkidP.h" - -/* - * NOTE: reference manual is not structured as code. The following section is a generic - * section for all high-level cache search+iterate routines. - */ - -/** - * SECTION:search - * @title: Search and iterate - * @short_description: search devices and iterate over devices in the cache. - * - * Note that high-level probing API provides information about superblocks - * (filesystems/raids) only. For partitions and topology is necessary to use - * the low-level API. - */ - -blkid_dev blkid_new_dev(void) -{ - blkid_dev dev; - - if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev)))) - return NULL; - - INIT_LIST_HEAD(&dev->bid_devs); - INIT_LIST_HEAD(&dev->bid_tags); - - return dev; -} - -void blkid_free_dev(blkid_dev dev) -{ - if (!dev) - return; - - DBG(DEBUG_DEV, - printf(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type ? - dev->bid_type : "(null)")); - DBG(DEBUG_DEV, blkid_debug_dump_dev(dev)); - - list_del(&dev->bid_devs); - while (!list_empty(&dev->bid_tags)) { - blkid_tag tag = list_entry(dev->bid_tags.next, - struct blkid_struct_tag, - bit_tags); - blkid_free_tag(tag); - } - free(dev->bid_name); - free(dev); -} - -/* - * Given a blkid device, return its name - */ -extern const char *blkid_dev_devname(blkid_dev dev) -{ - return dev ? dev->bid_name : NULL; -} - -#ifdef CONFIG_BLKID_DEBUG -void blkid_debug_dump_dev(blkid_dev dev) -{ - struct list_head *p; - - if (!dev) { - printf(" dev: NULL\n"); - return; - } - - printf(" dev: name = %s\n", dev->bid_name); - printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); - printf(" dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); - printf(" dev: PRI=\"%d\"\n", dev->bid_pri); - printf(" dev: flags = 0x%08X\n", dev->bid_flags); - - list_for_each(p, &dev->bid_tags) { - blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); - if (tag) - printf(" tag: %s=\"%s\"\n", tag->bit_name, - tag->bit_val); - else - printf(" tag: NULL\n"); - } - printf("\n"); -} -#endif - -/* - * dev iteration routines for the public libblkid interface. - * - * These routines do not expose the list.h implementation, which are a - * contamination of the namespace, and which force us to reveal far, far - * too much of our internal implemenation. I'm not convinced I want - * to keep list.h in the long term, anyway. It's fine for kernel - * programming, but performance is not the #1 priority for this - * library, and I really don't like the tradeoff of type-safety for - * performance for this application. [tytso:20030125.2007EST] - */ - -/* - * This series of functions iterate over all devices in a blkid cache - */ -#define DEV_ITERATE_MAGIC 0x01a5284c - -struct blkid_struct_dev_iterate { - int magic; - blkid_cache cache; - char *search_type; - char *search_value; - struct list_head *p; -}; - -extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache) -{ - blkid_dev_iterate iter; - - iter = malloc(sizeof(struct blkid_struct_dev_iterate)); - if (iter) { - iter->magic = DEV_ITERATE_MAGIC; - iter->cache = cache; - iter->p = cache->bic_devs.next; - iter->search_type = 0; - iter->search_value = 0; - } - return iter; -} - -extern int blkid_dev_set_search(blkid_dev_iterate iter, - char *search_type, char *search_value) -{ - char *new_type, *new_value; - - if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type || - !search_value) - return -1; - new_type = malloc(strlen(search_type)+1); - new_value = malloc(strlen(search_value)+1); - if (!new_type || !new_value) { - free(new_type); - free(new_value); - return -1; - } - strcpy(new_type, search_type); - strcpy(new_value, search_value); - free(iter->search_type); - free(iter->search_value); - iter->search_type = new_type; - iter->search_value = new_value; - return 0; -} - -/* - * Return 0 on success, -1 on error - */ -extern int blkid_dev_next(blkid_dev_iterate iter, - blkid_dev *ret_dev) -{ - blkid_dev dev; - - if (!ret_dev || !iter || iter->magic != DEV_ITERATE_MAGIC) - return -1; - *ret_dev = 0; - while (iter->p != &iter->cache->bic_devs) { - dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); - iter->p = iter->p->next; - if (iter->search_type && - !blkid_dev_has_tag(dev, iter->search_type, - iter->search_value)) - continue; - *ret_dev = dev; - return 0; - } - return -1; -} - -extern void blkid_dev_iterate_end(blkid_dev_iterate iter) -{ - if (!iter || iter->magic != DEV_ITERATE_MAGIC) - return; - iter->magic = 0; - free(iter->search_type); - free(iter->search_value); - free(iter); -} - -#ifdef TEST_PROGRAM -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#else -extern char *optarg; -extern int optind; -#endif - -void __attribute__((__noreturn__)) usage(char *prog) -{ - fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); - fprintf(stderr, "\tList all devices and exit\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - blkid_dev_iterate iter; - blkid_cache cache = NULL; - blkid_dev dev; - int c, ret; - char *tmp; - char *file = NULL; - char *search_type = NULL; - char *search_value = NULL; - - while ((c = getopt (argc, argv, "m:f:")) != EOF) - switch (c) { - case 'f': - file = optarg; - break; - case 'm': - { - int mask = strtoul (optarg, &tmp, 0); - if (*tmp) { - fprintf(stderr, "Invalid debug mask: %s\n", - optarg); - exit(1); - } - blkid_init_debug(mask); - break; - } - case '?': - usage(argv[0]); - } - if (argc >= optind+2) { - search_type = argv[optind]; - search_value = argv[optind+1]; - optind += 2; - } - if (argc != optind) - usage(argv[0]); - - if ((ret = blkid_get_cache(&cache, file)) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - - iter = blkid_dev_iterate_begin(cache); - if (search_type) - blkid_dev_set_search(iter, search_type, search_value); - while (blkid_dev_next(iter, &dev) == 0) { - printf("Device: %s\n", blkid_dev_devname(dev)); - } - blkid_dev_iterate_end(iter); - - - blkid_put_cache(cache); - return (0); -} -#endif diff --git a/libblkid/devname.c b/libblkid/devname.c deleted file mode 100644 index b27b6612c..000000000 --- a/libblkid/devname.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * devname.c - get a dev by its device inode name - * - * Copyright (C) Andries Brouwer - * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o - * Copyright (C) 2001 Andreas Dilger - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#define _GNU_SOURCE 1 - -#include <stdio.h> -#include <string.h> -#include <limits.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <stdlib.h> -#include <ctype.h> -#include <fcntl.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#include <dirent.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <time.h> - -#include "blkidP.h" - -#include "canonicalize.h" /* $(top_srcdir)/include */ -#include "pathnames.h" -#include "sysfs.h" -#include "at.h" - -/* - * Find a dev struct in the cache by device name, if available. - * - * If there is no entry with the specified device name, and the create - * flag is set, then create an empty device entry. - */ -blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) -{ - blkid_dev dev = NULL, tmp; - struct list_head *p, *pnext; - - if (!cache || !devname) - return NULL; - - list_for_each(p, &cache->bic_devs) { - tmp = list_entry(p, struct blkid_struct_dev, bid_devs); - if (strcmp(tmp->bid_name, devname)) - continue; - - DBG(DEBUG_DEVNAME, - printf("found devname %s in cache\n", tmp->bid_name)); - dev = tmp; - break; - } - - if (!dev && (flags & BLKID_DEV_CREATE)) { - if (access(devname, F_OK) < 0) - return NULL; - dev = blkid_new_dev(); - if (!dev) - return NULL; - dev->bid_time = INT_MIN; - dev->bid_name = strdup(devname); - dev->bid_cache = cache; - list_add_tail(&dev->bid_devs, &cache->bic_devs); - cache->bic_flags |= BLKID_BIC_FL_CHANGED; - } - - if (flags & BLKID_DEV_VERIFY) { - dev = blkid_verify(cache, dev); - if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) - return dev; - /* - * If the device is verified, then search the blkid - * cache for any entries that match on the type, uuid, - * and label, and verify them; if a cache entry can - * not be verified, then it's stale and so we remove - * it. - */ - list_for_each_safe(p, pnext, &cache->bic_devs) { - blkid_dev dev2 = list_entry(p, struct blkid_struct_dev, bid_devs); - if (dev2->bid_flags & BLKID_BID_FL_VERIFIED) - continue; - if (!dev->bid_type || !dev2->bid_type || - strcmp(dev->bid_type, dev2->bid_type)) - continue; - if (dev->bid_label && dev2->bid_label && - strcmp(dev->bid_label, dev2->bid_label)) - continue; - if (dev->bid_uuid && dev2->bid_uuid && - strcmp(dev->bid_uuid, dev2->bid_uuid)) - continue; - if ((dev->bid_label && !dev2->bid_label) || - (!dev->bid_label && dev2->bid_label) || - (dev->bid_uuid && !dev2->bid_uuid) || - (!dev->bid_uuid && dev2->bid_uuid)) - continue; - dev2 = blkid_verify(cache, dev2); - if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED)) - blkid_free_dev(dev2); - } - } - return dev; -} - -/* Directories where we will try to search for device names */ -static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; - -static int is_dm_leaf(const char *devname) -{ - struct dirent *de, *d_de; - DIR *dir, *d_dir; - char path[256]; - int ret = 1; - - if ((dir = opendir("/sys/block")) == NULL) - return 0; - while ((de = readdir(dir)) != NULL) { - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || - !strcmp(de->d_name, devname) || - strncmp(de->d_name, "dm-", 3) || - strlen(de->d_name) > sizeof(path)-32) - continue; - sprintf(path, "/sys/block/%s/slaves", de->d_name); - if ((d_dir = opendir(path)) == NULL) - continue; - while ((d_de = readdir(d_dir)) != NULL) { - if (!strcmp(d_de->d_name, devname)) { - ret = 0; - break; - } - } - closedir(d_dir); - if (!ret) - break; - } - closedir(dir); - return ret; -} - -/* - * Probe a single block device to add to the device cache. - */ -static void probe_one(blkid_cache cache, const char *ptname, - dev_t devno, int pri, int only_if_new, int removable) -{ - blkid_dev dev = NULL; - struct list_head *p, *pnext; - const char **dir; - char *devname = NULL; - - /* See if we already have this device number in the cache. */ - list_for_each_safe(p, pnext, &cache->bic_devs) { - blkid_dev tmp = list_entry(p, struct blkid_struct_dev, - bid_devs); - if (tmp->bid_devno == devno) { - if (only_if_new && !access(tmp->bid_name, F_OK)) - return; - dev = blkid_verify(cache, tmp); - if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) - break; - dev = 0; - } - } - if (dev && dev->bid_devno == devno) - goto set_pri; - - /* Try to translate private device-mapper dm-<N> names - * to standard /dev/mapper/<name>. - */ - if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { - devname = canonicalize_dm_name(ptname); - if (!devname) - blkid__scan_dir("/dev/mapper", devno, 0, &devname); - if (devname) - goto get_dev; - } - - /* - * Take a quick look at /dev/ptname for the device number. We check - * all of the likely device directories. If we don't find it, or if - * the stat information doesn't check out, use blkid_devno_to_devname() - * to find it via an exhaustive search for the device major/minor. - */ - for (dir = dirlist; *dir; dir++) { - struct stat st; - char device[256]; - - snprintf(device, sizeof(device), "%s/%s", *dir, ptname); - if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && - dev->bid_devno == devno) - goto set_pri; - - if (stat(device, &st) == 0 && - (S_ISBLK(st.st_mode) || - (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) && - st.st_rdev == devno) { - devname = strdup(device); - goto get_dev; - } - } - /* Do a short-cut scan of /dev/mapper first */ - if (!devname) - blkid__scan_dir("/dev/mapper", devno, 0, &devname); - if (!devname) { - devname = blkid_devno_to_devname(devno); - if (!devname) - return; - } - -get_dev: - dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); - free(devname); - -set_pri: - if (dev) { - if (pri) - dev->bid_pri = pri; - else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) { - dev->bid_pri = BLKID_PRI_DM; - if (is_dm_leaf(ptname)) - dev->bid_pri += 5; - } else if (!strncmp(ptname, "md", 2)) - dev->bid_pri = BLKID_PRI_MD; - if (removable) - dev->bid_flags |= BLKID_BID_FL_REMOVABLE; - } - return; -} - -#define PROC_PARTITIONS "/proc/partitions" -#define VG_DIR "/proc/lvm/VGs" - -/* - * This function initializes the UUID cache with devices from the LVM - * proc hierarchy. We currently depend on the names of the LVM - * hierarchy giving us the device structure in /dev. (XXX is this a - * safe thing to do?) - */ -#ifdef VG_DIR -static dev_t lvm_get_devno(const char *lvm_device) -{ - FILE *lvf; - char buf[1024]; - int ma, mi; - dev_t ret = 0; - - DBG(DEBUG_DEVNAME, printf("opening %s\n", lvm_device)); - if ((lvf = fopen(lvm_device, "r")) == NULL) { - DBG(DEBUG_DEVNAME, printf("%s: (%d) %m\n", lvm_device, errno)); - return 0; - } - - while (fgets(buf, sizeof(buf), lvf)) { - if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { - ret = makedev(ma, mi); - break; - } - } - fclose(lvf); - - return ret; -} - -static void lvm_probe_all(blkid_cache cache, int only_if_new) -{ - DIR *vg_list; - struct dirent *vg_iter; - int vg_len = strlen(VG_DIR); - dev_t dev; - - if ((vg_list = opendir(VG_DIR)) == NULL) - return; - - DBG(DEBUG_DEVNAME, printf("probing LVM devices under %s\n", VG_DIR)); - - while ((vg_iter = readdir(vg_list)) != NULL) { - DIR *lv_list; - char *vdirname; - char *vg_name; - struct dirent *lv_iter; - - vg_name = vg_iter->d_name; - if (!strcmp(vg_name, ".") || !strcmp(vg_name, "..")) - continue; - vdirname = malloc(vg_len + strlen(vg_name) + 8); - if (!vdirname) - goto exit; - sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); - - lv_list = opendir(vdirname); - free(vdirname); - if (lv_list == NULL) - continue; - - while ((lv_iter = readdir(lv_list)) != NULL) { - char *lv_name, *lvm_device; - - lv_name = lv_iter->d_name; - if (!strcmp(lv_name, ".") || !strcmp(lv_name, "..")) - continue; - - lvm_device = malloc(vg_len + strlen(vg_name) + - strlen(lv_name) + 8); - if (!lvm_device) { - closedir(lv_list); - goto exit; - } - sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, - lv_name); - dev = lvm_get_devno(lvm_device); - sprintf(lvm_device, "%s/%s", vg_name, lv_name); - DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n", - lvm_device, - (unsigned int) dev)); - probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, - only_if_new, 0); - free(lvm_device); - } - closedir(lv_list); - } -exit: - closedir(vg_list); -} -#endif - -#define PROC_EVMS_VOLUMES "/proc/evms/volumes" - -static int -evms_probe_all(blkid_cache cache, int only_if_new) -{ - char line[100]; - int ma, mi, sz, num = 0; - FILE *procpt; - char device[110]; - - procpt = fopen(PROC_EVMS_VOLUMES, "r"); - if (!procpt) - return 0; - while (fgets(line, sizeof(line), procpt)) { - if (sscanf (line, " %d %d %d %*s %*s %[^\n ]", - &ma, &mi, &sz, device) != 4) - continue; - - DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n", - device, ma, mi)); - - probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, - only_if_new, 0); - num++; - } - fclose(procpt); - return num; -} - -static void -ubi_probe_all(blkid_cache cache, int only_if_new) -{ - const char **dirname; - - for (dirname = dirlist; *dirname; dirname++) { - DBG(DEBUG_DEVNAME, printf("probing UBI volumes under %s\n", - *dirname)); - - DIR *dir; - struct dirent *iter; - - dir = opendir(*dirname); - if (dir == NULL) - continue ; - - while ((iter = readdir(dir)) != NULL) { - char *name; - struct stat st; - dev_t dev; - - name = iter->d_name; -#ifdef _DIRENT_HAVE_D_TYPE - if (iter->d_type != DT_UNKNOWN && - iter->d_type != DT_CHR && iter->d_type != DT_LNK) - continue; -#endif - if (!strcmp(name, ".") || !strcmp(name, "..") || - !strstr(name, "ubi")) - continue; - if (!strcmp(name, "ubi_ctrl")) - continue; - if (fstat_at(dirfd(dir), *dirname, name, &st, 0)) - continue; - - dev = st.st_rdev; - - if (!S_ISCHR(st.st_mode) || !minor(dev)) - continue; - DBG(DEBUG_DEVNAME, printf("UBI vol %s/%s: devno 0x%04X\n", - *dirname, name, (int) dev)); - probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0); - } - closedir(dir); - } -} - -/* - * Read the device data for all available block devices in the system. - */ -static int probe_all(blkid_cache cache, int only_if_new) -{ - FILE *proc; - char line[1024]; - char ptname0[128 + 1], ptname1[128 + 1], *ptname = 0; - char *ptnames[2]; - dev_t devs[2]; - int ma, mi; - unsigned long long sz; - int lens[2] = { 0, 0 }; - int which = 0, last = 0; - struct list_head *p, *pnext; - - ptnames[0] = ptname0; - ptnames[1] = ptname1; - - if (!cache) - return -BLKID_ERR_PARAM; - - if (cache->bic_flags & BLKID_BIC_FL_PROBED && - time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) - return 0; - - blkid_read_cache(cache); - evms_probe_all(cache, only_if_new); -#ifdef VG_DIR - lvm_probe_all(cache, only_if_new); -#endif - ubi_probe_all(cache, only_if_new); - - proc = fopen(PROC_PARTITIONS, "r"); - if (!proc) - return -BLKID_ERR_PROC; - - while (fgets(line, sizeof(line), proc)) { - last = which; - which ^= 1; - ptname = ptnames[which]; - - if (sscanf(line, " %d %d %llu %128[^\n ]", - &ma, &mi, &sz, ptname) != 4) - continue; - devs[which] = makedev(ma, mi); - - DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); - - /* Skip whole disk devs unless they have no partitions. - * If base name of device has changed, also - * check previous dev to see if it didn't have a partn. - * heuristic: partition name ends in a digit, & partition - * names contain whole device name as substring. - * - * Skip extended partitions. - * heuristic: size is 1 - * - * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs - */ - - lens[which] = strlen(ptname); - - /* ends in a digit, clearly a partition, so check */ - if (isdigit(ptname[lens[which] - 1])) { - DBG(DEBUG_DEVNAME, - printf("partition dev %s, devno 0x%04X\n", - ptname, (unsigned int) devs[which])); - - if (sz > 1) - probe_one(cache, ptname, devs[which], 0, - only_if_new, 0); - lens[which] = 0; /* mark as checked */ - } - - /* - * If last was a whole disk and we just found a partition - * on it, remove the whole-disk dev from the cache if - * it exists. - */ - if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) { - list_for_each_safe(p, pnext, &cache->bic_devs) { - blkid_dev tmp; - - /* find blkid dev for the whole-disk devno */ - tmp = list_entry(p, struct blkid_struct_dev, - bid_devs); - if (tmp->bid_devno == devs[last]) { - DBG(DEBUG_DEVNAME, - printf("freeing %s\n", - tmp->bid_name)); - blkid_free_dev(tmp); - cache->bic_flags |= BLKID_BIC_FL_CHANGED; - break; - } - } - lens[last] = 0; - } - /* - * If last was not checked because it looked like a whole-disk - * dev, and the device's base name has changed, - * check last as well. - */ - if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { - DBG(DEBUG_DEVNAME, - printf("whole dev %s, devno 0x%04X\n", - ptnames[last], (unsigned int) devs[last])); - probe_one(cache, ptnames[last], devs[last], 0, - only_if_new, 0); - lens[last] = 0; - } - } - - /* Handle the last device if it wasn't partitioned */ - if (lens[which]) - probe_one(cache, ptname, devs[which], 0, only_if_new, 0); - - fclose(proc); - blkid_flush_cache(cache); - return 0; -} - -/* Don't use it by default -- it's pretty slow (because cdroms, floppy, ...) - */ -static int probe_all_removable(blkid_cache cache) -{ - DIR *dir; - struct dirent *d; - - if (!cache) - return -BLKID_ERR_PARAM; - - dir = opendir(_PATH_SYS_BLOCK); - if (!dir) - return -BLKID_ERR_PROC; - - while((d = readdir(dir))) { - struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY; - int removable = 0; - dev_t devno; - -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK) - continue; -#endif - if (d->d_name[0] == '.' && - ((d->d_name[1] == 0) || - ((d->d_name[1] == '.') && (d->d_name[2] == 0)))) - continue; - - devno = sysfs_devname_to_devno(d->d_name, NULL); - if (!devno) - continue; - - if (sysfs_init(&sysfs, devno, NULL) == 0) { - sysfs_read_int(&sysfs, "removable", &removable); - sysfs_deinit(&sysfs); - } - - if (removable) - probe_one(cache, d->d_name, devno, 0, 0, 1); - } - - closedir(dir); - return 0; -} - - -/** - * blkid_probe_all: - * @cache: cache handler - * - * Probes all block devices. - * - * Returns: 0 on success, or number less than zero in case of error. - */ -int blkid_probe_all(blkid_cache cache) -{ - int ret; - - DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n")); - ret = probe_all(cache, 0); - if (ret == 0) { - cache->bic_time = time(0); - cache->bic_flags |= BLKID_BIC_FL_PROBED; - } - DBG(DEBUG_PROBE, printf("End blkid_probe_all() [rc=%d]\n", ret)); - return ret; -} - -/** - * blkid_probe_all_new: - * @cache: cache handler - * - * Probes all new block devices. - * - * Returns: 0 on success, or number less than zero in case of error. - */ -int blkid_probe_all_new(blkid_cache cache) -{ - int ret; - - DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n")); - ret = probe_all(cache, 1); - DBG(DEBUG_PROBE, printf("End blkid_probe_all_new() [rc=%d]\n", ret)); - return ret; -} - -/** - * blkid_probe_all_removable: - * @cache: cache handler - * - * The libblkid probing is based on devices from /proc/partitions by default. - * This file usually does not contain removable devices (e.g. CDROMs) and this kind - * of devices are invisible for libblkid. - * - * This function adds removable block devices to @cache (probing is based on - * information from the /sys directory). Don't forget that removable devices - * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call - * this function by default. - * - * Note that devices which were detected by this function won't be written to - * blkid.tab cache file. - * - * Returns: 0 on success, or number less than zero in case of error. - */ -int blkid_probe_all_removable(blkid_cache cache) -{ - int ret; - - DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_removable()\n")); - ret = probe_all_removable(cache); - DBG(DEBUG_PROBE, printf("End blkid_probe_all_removable() [rc=%d]\n", ret)); - return ret; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - blkid_cache cache = NULL; - int ret; - - blkid_init_debug(DEBUG_ALL); - if (argc != 1) { - fprintf(stderr, "Usage: %s\n" - "Probe all devices and exit\n", argv[0]); - exit(1); - } - if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - if (blkid_probe_all(cache) < 0) - printf("%s: error probing devices\n", argv[0]); - - if (blkid_probe_all_removable(cache) < 0) - printf("%s: error probing removable devices\n", argv[0]); - - blkid_put_cache(cache); - return (0); -} -#endif diff --git a/libblkid/devno.c b/libblkid/devno.c deleted file mode 100644 index 906c91fcd..000000000 --- a/libblkid/devno.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * devno.c - find a particular device by its device number (major/minor) - * - * Copyright (C) 2000, 2001, 2003 Theodore Ts'o - * Copyright (C) 2001 Andreas Dilger - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#include <stdio.h> -#include <string.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <stdlib.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include <dirent.h> -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_MKDEV_H -#include <sys/mkdev.h> -#endif -#include <fcntl.h> -#include <inttypes.h> - -#include "blkidP.h" -#include "pathnames.h" -#include "at.h" -#include "sysfs.h" - -static char *blkid_strconcat(const char *a, const char *b, const char *c) -{ - char *res, *p; - size_t len, al, bl, cl; - - al = a ? strlen(a) : 0; - bl = b ? strlen(b) : 0; - cl = c ? strlen(c) : 0; - - len = al + bl + cl; - if (!len) - return NULL; - p = res = malloc(len + 1); - if (!res) - return NULL; - if (al) { - memcpy(p, a, al); - p += al; - } - if (bl) { - memcpy(p, b, bl); - p += bl; - } - if (cl) { - memcpy(p, c, cl); - p += cl; - } - *p = '\0'; - return res; -} - -/* - * This function adds an entry to the directory list - */ -static void add_to_dirlist(const char *dir, const char *subdir, - struct dir_list **list) -{ - struct dir_list *dp; - - dp = malloc(sizeof(struct dir_list)); - if (!dp) - return; - dp->name = subdir ? blkid_strconcat(dir, "/", subdir) : - dir ? strdup(dir) : NULL; - - if (!dp->name) { - free(dp); - return; - } - dp->next = *list; - *list = dp; -} - -/* - * This function frees a directory list - */ -static void free_dirlist(struct dir_list **list) -{ - struct dir_list *dp, *next; - - for (dp = *list; dp; dp = next) { - next = dp->next; - free(dp->name); - free(dp); - } - *list = NULL; -} - -void blkid__scan_dir(char *dirname, dev_t devno, struct dir_list **list, - char **devname) -{ - DIR *dir; - struct dirent *dp; - struct stat st; - - if ((dir = opendir(dirname)) == NULL) - return; - - while ((dp = readdir(dir)) != NULL) { -#ifdef _DIRENT_HAVE_D_TYPE - if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_BLK && - dp->d_type != DT_LNK && dp->d_type != DT_DIR) - continue; -#endif - if (dp->d_name[0] == '.' && - ((dp->d_name[1] == 0) || - ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) - continue; - - if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 0)) - continue; - - if (S_ISBLK(st.st_mode) && st.st_rdev == devno) { - *devname = blkid_strconcat(dirname, "/", dp->d_name); - DBG(DEBUG_DEVNO, - printf("found 0x%llx at %s\n", (long long)devno, - *devname)); - break; - } - - if (!list || !S_ISDIR(st.st_mode)) - continue; - - /* add subdirectory (but not symlink) to the list */ -#ifdef _DIRENT_HAVE_D_TYPE - if (dp->d_type == DT_LNK) - continue; - if (dp->d_type == DT_UNKNOWN) -#endif - { - if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 1) || - !S_ISDIR(st.st_mode)) - continue; /* symlink or lstat() failed */ - } - - if (*dp->d_name == '.' || ( -#ifdef _DIRENT_HAVE_D_TYPE - dp->d_type == DT_DIR && -#endif - strcmp(dp->d_name, "shm") == 0)) - /* ignore /dev/.{udev,mount,mdadm} and /dev/shm */ - continue; - - add_to_dirlist(dirname, dp->d_name, list); - } - closedir(dir); - return; -} - -/* Directories where we will try to search for device numbers */ -static const char *devdirs[] = { "/devices", "/devfs", "/dev", NULL }; - -/** - * SECTION: misc - * @title: Miscellaneous utils - * @short_description: mix of various utils for low-level and high-level API - */ - - - -static char *scandev_devno_to_devpath(dev_t devno) -{ - struct dir_list *list = NULL, *new_list = NULL; - char *devname = NULL; - const char **dir; - - /* - * Add the starting directories to search in reverse order of - * importance, since we are using a stack... - */ - for (dir = devdirs; *dir; dir++) - add_to_dirlist(*dir, NULL, &list); - - while (list) { - struct dir_list *current = list; - - list = list->next; - DBG(DEBUG_DEVNO, printf("directory %s\n", current->name)); - blkid__scan_dir(current->name, devno, &new_list, &devname); - free(current->name); - free(current); - if (devname) - break; - /* - * If we're done checking at this level, descend to - * the next level of subdirectories. (breadth-first) - */ - if (list == NULL) { - list = new_list; - new_list = NULL; - } - } - free_dirlist(&list); - free_dirlist(&new_list); - - return devname; -} - -/** - * blkid_devno_to_devname: - * @devno: device number - * - * This function finds the pathname to a block device with a given - * device number. - * - * Returns: a pointer to allocated memory to the pathname on success, - * and NULL on failure. - */ -char *blkid_devno_to_devname(dev_t devno) -{ - char *path = NULL; - char buf[PATH_MAX]; - - path = sysfs_devno_to_devpath(devno, buf, sizeof(buf)); - if (path) - path = strdup(path); - if (!path) - path = scandev_devno_to_devpath(devno); - - if (!path) { - DBG(DEBUG_DEVNO, - printf("blkid: couldn't find devno 0x%04lx\n", - (unsigned long) devno)); - } else { - DBG(DEBUG_DEVNO, - printf("found devno 0x%04llx as %s\n", (long long)devno, path)); - } - - return path; -} - - -/** - * blkid_devno_to_wholedisk: - * @dev: device number - * @diskname: buffer to return diskname (or NULL) - * @len: diskname buffer size (or 0) - * @diskdevno: pointer to returns devno of entire disk (or NULL) - * - * This function uses sysfs to convert the @devno device number to the *name* - * of the whole disk. The function DOES NOT return full device name. The @dev - * argument could be partition or whole disk -- both is converted. - * - * For example: sda1, 0x0801 --> sda, 0x0800 - * - * For conversion to the full disk *path* use blkid_devno_to_devname(), for - * example: - * - * <informalexample> - * <programlisting> - * - * dev_t dev = 0x0801, disk; // sda1 = 8:1 - * char *diskpath, diskname[32]; - * - * blkid_devno_to_wholedisk(dev, diskname, sizeof(diskname), &disk); - * diskpath = blkid_devno_to_devname(disk); - * - * // print "0x0801: sda, /dev/sda, 8:0 - * printf("0x%x: %s, %s, %d:%d\n", - * dev, diskname, diskpath, major(disk), minor(disk)); - * - * free(diskpath); - * - * </programlisting> - * </informalexample> - * - * Returns: 0 on success or -1 in case of error. - */ -int blkid_devno_to_wholedisk(dev_t dev, char *diskname, - size_t len, dev_t *diskdevno) -{ - return sysfs_devno_to_wholedisk( dev, diskname, len, diskdevno); -} - -/* - * Returns 1 if the @major number is associated with @drvname. - */ -int blkid_driver_has_major(const char *drvname, int major) -{ - FILE *f; - char buf[128]; - int match = 0; - - f = fopen(_PATH_PROC_DEVICES, "r"); - if (!f) - return 0; - - while (fgets(buf, sizeof(buf), f)) { /* skip to block dev section */ - if (strncmp("Block devices:\n", buf, sizeof(buf)) == 0) - break; - } - - while (fgets(buf, sizeof(buf), f)) { - int maj; - char name[64 + 1]; - - if (sscanf(buf, "%d %64[^\n ]", &maj, name) != 2) - continue; - - if (maj == major && strcmp(name, drvname) == 0) { - match = 1; - break; - } - } - - fclose(f); - - DBG(DEBUG_DEVNO, printf("major %d %s associated with '%s' driver\n", - major, match ? "is" : "is NOT", drvname)); - return match; -} - - -#ifdef TEST_PROGRAM -int main(int argc, char** argv) -{ - char *devname, *tmp; - char diskname[PATH_MAX]; - int major, minor; - dev_t devno, disk_devno; - const char *errmsg = "Couldn't parse %s: %s\n"; - - blkid_init_debug(DEBUG_ALL); - if ((argc != 2) && (argc != 3)) { - fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" - "Resolve a device number to a device name\n", - argv[0], argv[0]); - exit(1); - } - if (argc == 2) { - devno = strtoul(argv[1], &tmp, 0); - if (*tmp) { - fprintf(stderr, errmsg, "device number", argv[1]); - exit(1); - } - } else { - major = strtoul(argv[1], &tmp, 0); - if (*tmp) { - fprintf(stderr, errmsg, "major number", argv[1]); - exit(1); - } - minor = strtoul(argv[2], &tmp, 0); - if (*tmp) { - fprintf(stderr, errmsg, "minor number", argv[2]); - exit(1); - } - devno = makedev(major, minor); - } - printf("Looking for device 0x%04llx\n", (long long)devno); - devname = blkid_devno_to_devname(devno); - free(devname); - - printf("Looking for whole-device for 0x%04llx\n", (long long)devno); - if (blkid_devno_to_wholedisk(devno, diskname, - sizeof(diskname), &disk_devno) == 0) - printf("found devno 0x%04llx as /dev/%s\n", (long long) disk_devno, diskname); - - return 0; -} -#endif diff --git a/libblkid/dm.c b/libblkid/dm.c deleted file mode 100644 index 72ec9bd8e..000000000 --- a/libblkid/dm.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * device-mapper (dm) topology - * -- this is fallback for old systems where the topology information is not - * exported by sysfs - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <errno.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "topology.h" - -static int is_dm_device(dev_t devno) -{ - return blkid_driver_has_major("device-mapper", major(devno)); -} - -static int probe_dm_tp(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - const char *paths[] = { - "/usr/local/sbin/dmsetup", - "/usr/sbin/dmsetup", - "/sbin/dmsetup" - }; - int dmpipe[] = { -1, -1 }, stripes, stripesize; - char *cmd = NULL; - FILE *stream = NULL; - long long offset, size; - size_t i; - dev_t devno = blkid_probe_get_devno(pr); - - if (!devno) - goto nothing; /* probably not a block device */ - if (!is_dm_device(devno)) - goto nothing; - - for (i = 0; i < ARRAY_SIZE(paths); i++) { - struct stat sb; - if (stat(paths[i], &sb) == 0) { - cmd = (char *) paths[i]; - break; - } - } - - if (!cmd) - goto nothing; - if (pipe(dmpipe) < 0) { - DBG(DEBUG_LOWPROBE, - printf("Failed to open pipe: errno=%d", errno)); - goto nothing; - } - - switch (fork()) { - case 0: - { - char *dmargv[7], maj[16], min[16]; - - /* Plumbing */ - close(dmpipe[0]); - - if (dmpipe[1] != STDOUT_FILENO) - dup2(dmpipe[1], STDOUT_FILENO); - - /* The libblkid library could linked with setuid programs */ - if (setgid(getgid()) < 0) - exit(1); - if (setuid(getuid()) < 0) - exit(1); - - snprintf(maj, sizeof(maj), "%d", major(devno)); - snprintf(min, sizeof(min), "%d", minor(devno)); - - dmargv[0] = cmd; - dmargv[1] = "table"; - dmargv[2] = "-j"; - dmargv[3] = maj; - dmargv[4] = "-m"; - dmargv[5] = min; - dmargv[6] = NULL; - - execv(dmargv[0], dmargv); - - DBG(DEBUG_LOWPROBE, - printf("Failed to execute %s: errno=%d", cmd, errno)); - exit(1); - } - case -1: - DBG(DEBUG_LOWPROBE, - printf("Failed to forking: errno=%d", errno)); - goto nothing; - default: - break; - } - - stream = fdopen(dmpipe[0], "r"); - if (!stream) - goto nothing; - - if (fscanf(stream, "%lld %lld striped %d %d ", - &offset, &size, &stripes, &stripesize) != 0) - goto nothing; - - blkid_topology_set_minimum_io_size(pr, stripesize << 9); - blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 9); - - fclose(stream); - close(dmpipe[1]); - return 0; - -nothing: - if (stream) - fclose(stream); - else if (dmpipe[0] != -1) - close(dmpipe[0]); - if (dmpipe[1] != -1) - close(dmpipe[1]); - return 1; -} - -const struct blkid_idinfo dm_tp_idinfo = -{ - .name = "dm", - .probefunc = probe_dm_tp, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/docs/.gitignore b/libblkid/docs/.gitignore new file mode 100644 index 000000000..f91f93db7 --- /dev/null +++ b/libblkid/docs/.gitignore @@ -0,0 +1,18 @@ +*-decl-list.txt +*-decl.txt +*-overrides.txt +*-undeclared.txt +*-undocumented.txt +*-unused.txt +*.args +*.bak +*.hierarchy +*.interfaces +*.prerequisites +*.signals +*.stamp +*.types +html/* +tmpl/* +version.xml +xml/* diff --git a/libblkid/docs/Makefile.am b/libblkid/docs/Makefile.am new file mode 100644 index 000000000..dc6dd3e5e --- /dev/null +++ b/libblkid/docs/Makefile.am @@ -0,0 +1,95 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.10 at least. +AUTOMAKE_OPTIONS = 1.10 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=libblkid + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +#DOC_MODULE_VERSION=2 + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=../src + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS=--deprecated-guards="BLKID_DISABLE_DEPRECATED" + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space blkid + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS= + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS= + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(top_builddir)/libblkid/src/blkid.h +CFILE_GLOB=$(top_srcdir)/libblkid/src/*.c + +# Extra header to include when scanning, which are not under DOC_SOURCE_DIR +# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h +EXTRA_HFILES= + +# Header files to ignore when scanning. Use base file name, no paths +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES=blkidP.h partitions.h superblocks.h \ + topology.h aix.h dos.h iso9660.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = $(builddir)/version.xml $(srcdir)/libblkid-config.xml + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_CFLAGS= +GTKDOC_LIBS= + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/config/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += version.xml.in $(srcdir)/libblkid-config.xml + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt +DISTCLEANFILES += version.xml + diff --git a/libblkid/docs/libblkid-config.xml b/libblkid/docs/libblkid-config.xml new file mode 100644 index 000000000..89fbb7f17 --- /dev/null +++ b/libblkid/docs/libblkid-config.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" + "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" +[ + <!ENTITY version SYSTEM "version.xml"> +]> +<refentry id="libblkid-config"> +<refmeta> +<refentrytitle role="top_of_page" id="libblkid-config.top_of_page">Config file</refentrytitle> +<manvolnum>3</manvolnum> +<refmiscinfo>LIBBLKID Library</refmiscinfo> +</refmeta> + +<refnamediv> +<refname>Config file</refname> +<refpurpose>config file to control paths and basic library behavior</refpurpose> +</refnamediv> + +<refsect1 id="libblkid-config.description" role="desc"> +<title role="desc.title">Description</title> +<para> +The standard location of the +/etc/blkid.conf config file can be overridden by the environment variable +BLKID_CONF. The following options control the libblkid library: +</para> + +<variablelist role="params"> + <varlistentry> + <term>SEND_UEVENT=<parameter>yes|not</parameter></term> + <listitem><simpara> + Sends uevent when /dev/disk/by-{label,uuid}/ + symlink does not match with LABEL or UUID on the device. Default is "yes". + </simpara></listitem> + </varlistentry> + <varlistentry> + <term>CACHE_FILE=<parameter>path</parameter></term> + <listitem><simpara> + Overrides the standard location of the cache file. This + setting can be overridden by the environment variable BLKID_FILE. Default is + /etc/blkid.tab. + </simpara></listitem> + </varlistentry> + <varlistentry> + <term>EVALUATE=<parameter>method</parameter></term> + <listitem><simpara> + Defines LABEL and UUID evaluation method(s). Currently, + the libblkid library supports "udev" and "scan" methods. More than one methods + may be specified in a comma separated list. Default is "udev,scan". The "udev" + method uses udev /dev/disk/by-* symlinks and the "scan" method scans all + block devices from the /proc/partitions file. + </simpara></listitem> + </varlistentry> +</variablelist> + +</refsect1> + +</refentry> diff --git a/libblkid/docs/libblkid-docs.xml b/libblkid/docs/libblkid-docs.xml new file mode 100644 index 000000000..1f412c105 --- /dev/null +++ b/libblkid/docs/libblkid-docs.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" + "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" +[ + <!ENTITY version SYSTEM "version.xml"> +]> +<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> + <bookinfo> + <title>libblkid Reference Manual</title> + <releaseinfo>for libblkid version &version;</releaseinfo> + <copyright> + <year>2009-2013</year> + <holder>Karel Zak <kzak@redhat.com></holder> + </copyright> + </bookinfo> + + <part id="gtk"> + <title>libblkid Overview</title> + <partintro> + <para> +The libblkid library is used to identify block devices (disks) as to their +content (e.g. filesystem type, partitions) as well as extracting additional +information such as filesystem labels/volume names, partitions, unique +identifiers/serial numbers, etc. A common use is to allow use of LABEL= and +UUID= tags instead of hard-coding specific block device names into +configuration files. + </para> + <para> +The libblkid librray +was written by Andreas Dilger for the ext2 filesystem utilties, with input +from Ted Ts'o. The library was subsequently heavily modified by Ted Ts'o. + </para> + <para> +The low-level probing code, topology and partitions support was written +by Karel Zak. Currently, the library is mainatned by Karel Zak. + </para> + <para> +The library is part of the util-linux package since version 2.15 and is +available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/. + </para> + </partintro> + <xi:include href="xml/libblkid-config.xml"/> + </part> + + <part> + <title>High-level</title> + <xi:include href="xml/evaluate.xml"/> + <xi:include href="xml/cache.xml"/> + <xi:include href="xml/search.xml"/> + </part> + <part> + <title>Low-level</title> + <xi:include href="xml/init.xml"/> + <xi:include href="xml/lowprobe.xml"/> + <xi:include href="xml/lowprobe-tags.xml"/> + <xi:include href="xml/superblocks.xml"/> + <xi:include href="xml/partitions.xml"/> + <xi:include href="xml/topology.xml"/> + </part> + <part> + <title>Common utils</title> + <xi:include href="xml/encode.xml"/> + <xi:include href="xml/misc.xml"/> + </part> + + <index id="api-index-full"> + <title>API Index</title> + <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> + </index> +</book> diff --git a/libblkid/docs/libblkid-sections.txt b/libblkid/docs/libblkid-sections.txt new file mode 100644 index 000000000..53cf84b78 --- /dev/null +++ b/libblkid/docs/libblkid-sections.txt @@ -0,0 +1,201 @@ +<SECTION> +<FILE>evaluate</FILE> +blkid_evaluate_tag +blkid_evaluate_spec +</SECTION> + +<SECTION> +<FILE>init</FILE> +blkid_init_debug +</SECTION> + +<SECTION> +<FILE>cache</FILE> +blkid_cache +blkid_gc_cache +blkid_get_cache +blkid_put_cache +blkid_probe_all +blkid_probe_all_removable +blkid_probe_all_new +blkid_verify +</SECTION> + +<SECTION> +<FILE>search</FILE> +blkid_dev +blkid_dev_devname +blkid_dev_has_tag +blkid_dev_iterate +blkid_dev_iterate_begin +blkid_dev_iterate_end +blkid_dev_next +blkid_dev_set_search +blkid_find_dev_with_tag +blkid_get_dev +blkid_get_devname +blkid_get_tag_value +blkid_tag_iterate +blkid_tag_iterate_begin +blkid_tag_iterate_end +blkid_tag_next +</SECTION> + +<SECTION> +<FILE>lowprobe</FILE> +blkid_probe +blkid_free_probe +blkid_new_probe +blkid_new_probe_from_filename +blkid_probe_get_devno +blkid_probe_get_fd +blkid_probe_get_offset +blkid_probe_get_sectors +blkid_probe_get_sectorsize +blkid_probe_get_size +blkid_probe_get_wholedisk_devno +blkid_probe_is_wholedisk +blkid_probe_set_device +blkid_probe_step_back +blkid_reset_probe +</SECTION> + +<SECTION> +<FILE>lowprobe-tags</FILE> +blkid_do_fullprobe +blkid_do_wipe +blkid_do_probe +blkid_do_safeprobe +<SUBSECTION> +blkid_probe_get_value +blkid_probe_has_value +blkid_probe_lookup_value +blkid_probe_numof_values +</SECTION> + +<SECTION> +<FILE>partitions</FILE> +blkid_partlist +blkid_partition +blkid_parttable +blkid_probe_enable_partitions +blkid_probe_set_partitions_flags +blkid_probe_filter_partitions_type +blkid_probe_invert_partitions_filter +blkid_probe_reset_partitions_filter +<SUBSECTION> +blkid_known_pttype +<SUBSECTION> +blkid_partition_get_name +blkid_partition_get_flags +blkid_partition_get_partno +blkid_partition_get_size +blkid_partition_get_start +blkid_partition_get_table +blkid_partition_get_type +blkid_partition_get_type_string +blkid_partition_get_uuid +blkid_partition_is_extended +blkid_partition_is_logical +blkid_partition_is_primary +<SUBSECTION> +blkid_partlist_get_partition +blkid_partlist_get_partition_by_partno +blkid_partlist_numof_partitions +blkid_partlist_devno_to_partition +blkid_partlist_get_table +<SUBSECTION> +blkid_parttable_get_id +blkid_parttable_get_offset +blkid_parttable_get_parent +blkid_parttable_get_type +<SUBSECTION> +blkid_probe_get_partitions +</SECTION> + +<SECTION> +<FILE>superblocks</FILE> +blkid_probe_enable_superblocks +<SUBSECTION> +blkid_known_fstype +blkid_superblocks_get_name +<SUBSECTION> +blkid_probe_filter_superblocks_type +blkid_probe_filter_superblocks_usage +blkid_probe_invert_superblocks_filter +blkid_probe_reset_superblocks_filter +blkid_probe_set_superblocks_flags +<SUBSECTION> +blkid_probe_reset_filter +blkid_probe_filter_types +blkid_probe_filter_usage +blkid_probe_invert_filter +blkid_probe_set_request +</SECTION> + +<SECTION> +<FILE>topology</FILE> +blkid_topology +blkid_probe_enable_topology +<SUBSECTION> +blkid_probe_get_topology +blkid_topology_get_alignment_offset +blkid_topology_get_logical_sector_size +blkid_topology_get_minimum_io_size +blkid_topology_get_optimal_io_size +blkid_topology_get_physical_sector_size +</SECTION> + +<SECTION> +<FILE>encode</FILE> +blkid_encode_string +blkid_safe_string +</SECTION> + +<SECTION> +<FILE>misc</FILE> +blkid_loff_t +blkid_devno_to_devname +blkid_devno_to_wholedisk +blkid_get_dev_size +blkid_get_library_version +blkid_parse_tag_string +blkid_parse_version_string +blkid_send_uevent +BLKID_VERSION +BLKID_DATE +BLKID_FLTR_NOTIN +BLKID_FLTR_ONLYIN +BLKID_DEV_CREATE +BLKID_DEV_FIND +BLKID_DEV_NORMAL +BLKID_DEV_VERIFY +BLKID_PARTS_ENTRY_DETAILS +BLKID_PARTS_FORCE_GPT +BLKID_PARTS_MAGIC +BLKID_PROBREQ_LABEL +BLKID_PROBREQ_LABELRAW +BLKID_PROBREQ_SECTYPE +BLKID_PROBREQ_TYPE +BLKID_PROBREQ_USAGE +BLKID_PROBREQ_UUID +BLKID_PROBREQ_UUIDRAW +BLKID_PROBREQ_VERSION +BLKID_SUBLKS_BADCSUM +BLKID_SUBLKS_DEFAULT +BLKID_SUBLKS_LABEL +BLKID_SUBLKS_LABELRAW +BLKID_SUBLKS_MAGIC +BLKID_SUBLKS_SECTYPE +BLKID_SUBLKS_TYPE +BLKID_SUBLKS_USAGE +BLKID_SUBLKS_UUID +BLKID_SUBLKS_UUIDRAW +BLKID_SUBLKS_VERSION +BLKID_USAGE_CRYPTO +BLKID_USAGE_FILESYSTEM +BLKID_USAGE_OTHER +BLKID_USAGE_RAID +</SECTION> + + diff --git a/libblkid/docs/version.xml.in b/libblkid/docs/version.xml.in new file mode 100644 index 000000000..d78bda934 --- /dev/null +++ b/libblkid/docs/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/libblkid/dos.c b/libblkid/dos.c deleted file mode 100644 index 58877691d..000000000 --- a/libblkid/dos.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * MS-DOS partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * Inspired by fdisk, partx, Linux kernel and libparted. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" -#include "dos.h" -#include "aix.h" - -/* see superblocks/vfat.c */ -extern int blkid_probe_is_vfat(blkid_probe pr); - -static const struct dos_subtypes { - unsigned char type; - const struct blkid_idinfo *id; -} dos_nested[] = { - { BLKID_FREEBSD_PARTITION, &bsd_pt_idinfo }, - { BLKID_NETBSD_PARTITION, &bsd_pt_idinfo }, - { BLKID_OPENBSD_PARTITION, &bsd_pt_idinfo }, - { BLKID_UNIXWARE_PARTITION, &unixware_pt_idinfo }, - { BLKID_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo }, - { BLKID_MINIX_PARTITION, &minix_pt_idinfo } -}; - -static inline int is_extended(struct dos_partition *p) -{ - return (p->sys_type == BLKID_DOS_EXTENDED_PARTITION || - p->sys_type == BLKID_W95_EXTENDED_PARTITION || - p->sys_type == BLKID_LINUX_EXTENDED_PARTITION); -} - -static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, - uint32_t ex_start, uint32_t ex_size, int ssf) -{ - blkid_partlist ls = blkid_probe_get_partlist(pr); - uint32_t cur_start = ex_start, cur_size = ex_size; - unsigned char *data; - int ct_nodata = 0; /* count ext.partitions without data partitions */ - int i; - - while (1) { - struct dos_partition *p, *p0; - uint32_t start, size; - - if (++ct_nodata > 100) - return 0; - data = blkid_probe_get_sector(pr, cur_start); - if (!data) - goto leave; /* malformed partition? */ - - if (!is_valid_mbr_signature(data)) - goto leave; - - p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - - /* Usually, the first entry is the real data partition, - * the 2nd entry is the next extended partition, or empty, - * and the 3rd and 4th entries are unused. - * However, DRDOS sometimes has the extended partition as - * the first entry (when the data partition is empty), - * and OS/2 seems to use all four entries. - * -- Linux kernel fs/partitions/dos.c - * - * See also http://en.wikipedia.org/wiki/Extended_boot_record - */ - - /* Parse data partition */ - for (p = p0, i = 0; i < 4; i++, p++) { - uint32_t abs_start; - blkid_partition par; - - /* the start is relative to the parental ext.partition */ - start = dos_partition_start(p) * ssf; - size = dos_partition_size(p) * ssf; - abs_start = cur_start + start; /* absolute start */ - - if (!size || is_extended(p)) - continue; - if (i >= 2) { - /* extra checks to detect real data on - * 3rd and 4th entries */ - if (start + size > cur_size) - continue; - if (abs_start < ex_start) - continue; - if (abs_start + size > ex_start + ex_size) - continue; - } - - par = blkid_partlist_add_partition(ls, tab, abs_start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, p->sys_type); - blkid_partition_set_flags(par, p->boot_ind); - ct_nodata = 0; - } - /* The first nested ext.partition should be a link to the next - * logical partition. Everything other (recursive ext.partitions) - * is junk. - */ - for (p = p0, i = 0; i < 4; i++, p++) { - start = dos_partition_start(p) * ssf; - size = dos_partition_size(p) * ssf; - - if (size && is_extended(p)) - break; - } - if (i == 4) - goto leave; - - cur_start = ex_start + start; - cur_size = size; - } -leave: - return 0; -err: - return -1; -} - -static int probe_dos_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - int i; - int ssf; - blkid_parttable tab = NULL; - blkid_partlist ls; - struct dos_partition *p0, *p; - unsigned char *data; - uint32_t start, size, id; - - data = blkid_probe_get_sector(pr, 0); - if (!data) - goto nothing; - - /* ignore disks with AIX magic number -- for more details see aix.c */ - if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) - goto nothing; - - /* - * Now that the 55aa signature is present, this is probably - * either the boot sector of a FAT filesystem or a DOS-type - * partition table. - */ - if (blkid_probe_is_vfat(pr)) { - DBG(DEBUG_LOWPROBE, printf("probably FAT -- ignore\n")); - goto nothing; - } - - p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - - /* - * Reject PT where boot indicator is not 0 or 0x80. - */ - for (p = p0, i = 0; i < 4; i++, p++) - if (p->boot_ind != 0 && p->boot_ind != 0x80) { - DBG(DEBUG_LOWPROBE, printf("missing boot indicator -- ignore\n")); - goto nothing; - } - - /* - * GPT uses valid MBR - */ - for (p = p0, i = 0; i < 4; i++, p++) { - if (p->sys_type == BLKID_GPT_PARTITION) { - DBG(DEBUG_LOWPROBE, printf("probably GPT -- ignore\n")); - goto nothing; - } - } - - blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET, - 512 - BLKID_MSDOS_PT_OFFSET); - - /* - * Well, all checks pass, it's MS-DOS partiton table - */ - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - - /* sector size factor (the start and size are in the real sectors, but - * we need to convert all sizes to 512 logical sectors - */ - ssf = blkid_probe_get_sectorsize(pr) / 512; - - /* allocate a new partition table */ - tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET); - if (!tab) - goto err; - - id = dos_parttable_id(data); - if (id) { - char buf[37]; - - snprintf(buf, sizeof(buf), "0x%08x", id); - blkid_parttable_set_id(tab, (unsigned char *) buf); - } - - - /* Parse primary partitions */ - for (p = p0, i = 0; i < 4; i++, p++) { - blkid_partition par; - - start = dos_partition_start(p) * ssf; - size = dos_partition_size(p) * ssf; - - if (!size) { - /* Linux kernel ignores empty partitions, but partno for - * the empty primary partitions is not reused */ - blkid_partlist_increment_partno(ls); - continue; - } - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, p->sys_type); - blkid_partition_set_flags(par, p->boot_ind); - } - - /* Linux uses partition numbers greater than 4 - * for all logical partition and all nested partition tables (bsd, ..) - */ - blkid_partlist_set_partno(ls, 5); - - /* Parse logical partitions */ - for (p = p0, i = 0; i < 4; i++, p++) { - start = dos_partition_start(p) * ssf; - size = dos_partition_size(p) * ssf; - - if (!size) - continue; - if (is_extended(p) && - parse_dos_extended(pr, tab, start, size, ssf) == -1) - goto err; - } - - /* Parse subtypes (nested partitions) on large disks */ - if (!blkid_probe_is_tiny(pr)) { - for (p = p0, i = 0; i < 4; i++, p++) { - size_t n; - - if (!dos_partition_size(p) || is_extended(p)) - continue; - - for (n = 0; n < ARRAY_SIZE(dos_nested); n++) { - if (dos_nested[n].type != p->sys_type) - continue; - - if (blkid_partitions_do_subprobe(pr, - blkid_partlist_get_partition(ls, i), - dos_nested[n].id) == -1) - goto err; - break; - } - } - } - return 0; - -nothing: - return 1; -err: - return -1; -} - - -const struct blkid_idinfo dos_pt_idinfo = -{ - .name = "dos", - .probefunc = probe_dos_pt, - .magics = - { - /* DOS master boot sector: - * - * 0 | Code Area - * 440 | Optional Disk signature - * 446 | Partition table - * 510 | 0x55 - * 511 | 0xAA - */ - { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, - { NULL } - } -}; - diff --git a/libblkid/dos.h b/libblkid/dos.h deleted file mode 100644 index d7588a856..000000000 --- a/libblkid/dos.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef BLKID_PARTITIONS_DOS_H -#define BLKID_PARTITIONS_DOS_H - -struct dos_partition { - unsigned char boot_ind; /* 0x80 - active */ - unsigned char bh, bs, bc; /* begin CHS */ - unsigned char sys_type; - unsigned char eh, es, ec; /* end CHS */ - unsigned char start_sect[4]; - unsigned char nr_sects[4]; -} __attribute__((packed)); - -#define BLKID_MSDOS_PT_OFFSET 0x1be - -/* assemble badly aligned little endian integer */ -static inline unsigned int assemble4le(const unsigned char *p) -{ - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - -static inline unsigned int dos_partition_start(struct dos_partition *p) -{ - return assemble4le(&(p->start_sect[0])); -} - -static inline unsigned int dos_partition_size(struct dos_partition *p) -{ - return assemble4le(&(p->nr_sects[0])); -} - -static inline int is_valid_mbr_signature(const unsigned char *mbr) -{ - return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0; -} - -static inline unsigned int dos_parttable_id(const unsigned char *mbr) -{ - return assemble4le(&mbr[440]); -} - -#endif /* BLKID_PARTITIONS_DOS_H */ diff --git a/libblkid/drbd.c b/libblkid/drbd.c deleted file mode 100644 index 43e544e89..000000000 --- a/libblkid/drbd.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2009 by Bastian Friedrich <bastian.friedrich@collax.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * defines, structs taken from drbd source; file names represent drbd source - * files. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <inttypes.h> -#include <stddef.h> - -#include "superblocks.h" - -/* - * drbd/linux/drbd.h - */ -#define DRBD_MAGIC 0x83740267 - -/* - * user/drbdmeta.c - * We only support v08 for now - */ -#define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) -#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) - -/* - * drbd/linux/drbd.h - */ -enum drbd_uuid_index { - UI_CURRENT, - UI_BITMAP, - UI_HISTORY_START, - UI_HISTORY_END, - UI_SIZE, /* nl-packet: number of dirty bits */ - UI_FLAGS, /* nl-packet: flags */ - UI_EXTENDED_SIZE /* Everything. */ -}; - -/* - * user/drbdmeta.c - * Minor modifications wrt. types - */ -struct md_on_disk_08 { - uint64_t la_sect; /* last agreed size. */ - uint64_t uuid[UI_SIZE]; /* UUIDs */ - uint64_t device_uuid; - uint64_t reserved_u64_1; - uint32_t flags; - uint32_t magic; - uint32_t md_size_sect; - int32_t al_offset; /* signed sector offset to this block */ - uint32_t al_nr_extents; /* important for restoring the AL */ - int32_t bm_offset; /* signed sector offset to the bitmap, from here */ - uint32_t bm_bytes_per_bit; - uint32_t reserved_u32[4]; - - char reserved[8 * 512 - (8*(UI_SIZE+3)+4*11)]; -}; - - -static int probe_drbd(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct md_on_disk_08 *md; - off_t off; - - off = pr->size - sizeof(*md); - - /* Small devices cannot be drbd (?) */ - if (pr->size < 0x10000) - return -1; - - md = (struct md_on_disk_08 *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct md_on_disk_08)); - if (!md) - return -1; - - if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 && - be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN) - return -1; - - /* - * DRBD does not have "real" uuids; the following resembles DRBD's - * notion of uuids (64 bit, see struct above) - */ - blkid_probe_sprintf_uuid(pr, - (unsigned char *) &md->device_uuid, sizeof(md->device_uuid), - "%" PRIx64, be64_to_cpu(md->device_uuid)); - - blkid_probe_set_version(pr, "v08"); - - if (blkid_probe_set_magic(pr, - off + offsetof(struct md_on_disk_08, magic), - sizeof(md->magic), - (unsigned char *) &md->magic)) - return -1; - - return 0; -} - -const struct blkid_idinfo drbd_idinfo = -{ - .name = "drbd", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_drbd, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/drbdproxy_datalog.c b/libblkid/drbdproxy_datalog.c deleted file mode 100644 index afe4725a0..000000000 --- a/libblkid/drbdproxy_datalog.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2011 by Philipp Marek <philipp.marek@linbit.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <inttypes.h> -#include <stddef.h> - -#include "superblocks.h" - - -struct log_header_t { - uint64_t magic; - uint64_t version; - - unsigned char uuid[16]; - - uint64_t flags; -} __attribute__((packed)); - - -static int probe_drbdproxy_datalog(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct log_header_t *lh; - - lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh)); - if (!lh) - return -1; - - blkid_probe_set_uuid(pr, lh->uuid); - blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version)); - - return 0; -} - -const struct blkid_idinfo drbdproxy_datalog_idinfo = -{ - .name = "drbdproxy_datalog", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_drbdproxy_datalog, - .minsz = 16*1024, - .magics = - { - { .magic = "DRBDdlh*", .len = 8, .sboff = 0, .kboff = 0 }, - { NULL } - } -}; diff --git a/libblkid/evaluate.c b/libblkid/evaluate.c deleted file mode 100644 index 2e1ca574d..000000000 --- a/libblkid/evaluate.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * evaluate.c - very high-level API to evaluate LABELs or UUIDs - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <stdint.h> -#include <stdarg.h> - -#include "pathnames.h" -#include "canonicalize.h" - -#include "blkidP.h" - -/** - * SECTION:evaluate - * @title: Tags and Spec evaluation - * @short_description: top-level API for LABEL and UUID evaluation. - * - * This API provides very simple and portable way how evaluate LABEL and UUID - * tags. The blkid_evaluate_tag() and blkid_evaluate_spec() work on 2.4 and - * 2.6 systems and on systems with or without udev. Currently, the libblkid - * library supports "udev" and "scan" methods. The "udev" method uses udev - * /dev/disk/by-* symlinks and the "scan" method scans all block devices from - * the /proc/partitions file. The evaluation could be controlled by the - * /etc/blkid.conf config file. The default is to try "udev" and then "scan" - * method. - * - * The blkid_evaluate_tag() also automatically informs udevd when an obsolete - * /dev/disk/by-* symlink is detected. - * - * If you are not sure how translate LABEL or UUID to the device name use this - * API. - */ - -#ifdef CONFIG_BLKID_VERIFY_UDEV -/* returns zero when the device has NAME=value (LABEL/UUID) */ -static int verify_tag(const char *devname, const char *name, const char *value) -{ - blkid_probe pr; - int fd = -1, rc = -1; - size_t len; - const char *data; - int errsv = 0; - - pr = blkid_new_probe(); - if (!pr) - return -1; - - blkid_probe_enable_superblocks(pr, TRUE); - blkid_probe_set_superblocks_flags(pr, - BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); - - blkid_probe_enable_partitions(pr, TRUE); - blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); - - fd = open(devname, O_RDONLY|O_CLOEXEC); - if (fd < 0) { - errsv = errno; - goto done; - } - if (blkid_probe_set_device(pr, fd, 0, 0)) - goto done; - rc = blkid_do_safeprobe(pr); - if (rc) - goto done; - rc = blkid_probe_lookup_value(pr, name, &data, &len); - if (!rc) - rc = memcmp(value, data, len); -done: - DBG(DEBUG_EVALUATE, printf("%s: %s verification %s\n", - devname, name, rc == 0 ? "PASS" : "FAILED")); - if (fd >= 0) - close(fd); - blkid_free_probe(pr); - - /* for non-root users we use unverified udev links */ - return errsv == EACCES ? 0 : rc; -} -#endif /* CONFIG_BLKID_VERIFY_UDEV*/ - -/** - * blkid_send_uevent: - * @devname: absolute path to the device - * @action: event string - * - * Returns: -1 in case of failure, or 0 on success. - */ -int blkid_send_uevent(const char *devname, const char *action) -{ - char uevent[PATH_MAX]; - struct stat st; - FILE *f; - int rc = -1; - - DBG(DEBUG_EVALUATE, printf("%s: uevent '%s' requested\n", devname, action)); - - if (!devname || !action) - return -1; - if (stat(devname, &st) || !S_ISBLK(st.st_mode)) - return -1; - - snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent", - major(st.st_rdev), minor(st.st_rdev)); - - f = fopen(uevent, "w"); - if (f) { - rc = 0; - if (fputs(action, f) >= 0) - rc = 0; - fclose(f); - } - DBG(DEBUG_EVALUATE, printf("%s: send uevent %s\n", - uevent, rc == 0 ? "SUCCES" : "FAILED")); - return rc; -} - -static char *evaluate_by_udev(const char *token, const char *value, int uevent) -{ - char dev[PATH_MAX]; - char *path = NULL; - size_t len; - struct stat st; - - DBG(DEBUG_EVALUATE, - printf("evaluating by udev %s=%s\n", token, value)); - - if (!strcmp(token, "UUID")) - strcpy(dev, _PATH_DEV_BYUUID "/"); - else if (!strcmp(token, "LABEL")) - strcpy(dev, _PATH_DEV_BYLABEL "/"); - else if (!strcmp(token, "PARTLABEL")) - strcpy(dev, _PATH_DEV_BYPARTLABEL "/"); - else if (!strcmp(token, "PARTUUID")) - strcpy(dev, _PATH_DEV_BYPARTUUID "/"); - else { - DBG(DEBUG_EVALUATE, - printf("unsupported token %s\n", token)); - return NULL; /* unsupported tag */ - } - - len = strlen(dev); - if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0) - return NULL; - - DBG(DEBUG_EVALUATE, - printf("expected udev link: %s\n", dev)); - - if (stat(dev, &st)) - goto failed; /* link or device does not exist */ - - if (!S_ISBLK(st.st_mode)) - return NULL; - - path = canonicalize_path(dev); - if (!path) - return NULL; - -#ifdef CONFIG_BLKID_VERIFY_UDEV - if (verify_tag(path, token, value)) - goto failed; -#endif - return path; - -failed: - DBG(DEBUG_EVALUATE, printf("failed to evaluate by udev\n")); - - if (uevent && path) - blkid_send_uevent(path, "change"); - free(path); - return NULL; -} - -static char *evaluate_by_scan(const char *token, const char *value, - blkid_cache *cache, struct blkid_config *conf) -{ - blkid_cache c = cache ? *cache : NULL; - char *res; - - DBG(DEBUG_EVALUATE, - printf("evaluating by blkid scan %s=%s\n", token, value)); - - if (!c) { - char *cachefile = blkid_get_cache_filename(conf); - blkid_get_cache(&c, cachefile); - free(cachefile); - } - if (!c) - return NULL; - - res = blkid_get_devname(c, token, value); - - if (cache) - *cache = c; - else - blkid_put_cache(c); - - return res; -} - -/** - * blkid_evaluate_tag: - * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo") - * @value: token data (e.g. "foo") - * @cache: pointer to cache (or NULL when you don't want to re-use the cache) - * - * Returns: allocated string with a device name. - */ -char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache) -{ - struct blkid_config *conf = NULL; - char *t = NULL, *v = NULL; - char *ret = NULL; - int i; - - if (!token) - return NULL; - - if (!cache || !*cache) - blkid_init_debug(0); - - DBG(DEBUG_EVALUATE, - printf("evaluating %s%s%s\n", token, value ? "=" : "", - value ? value : "")); - - if (!value) { - if (!strchr(token, '=')) { - ret = strdup(token); - goto out; - } - blkid_parse_tag_string(token, &t, &v); - if (!t || !v) - goto out; - token = t; - value = v; - } - - conf = blkid_read_config(NULL); - if (!conf) - goto out; - - for (i = 0; i < conf->nevals; i++) { - if (conf->eval[i] == BLKID_EVAL_UDEV) - ret = evaluate_by_udev(token, value, conf->uevent); - else if (conf->eval[i] == BLKID_EVAL_SCAN) - ret = evaluate_by_scan(token, value, cache, conf); - if (ret) - break; - } - - DBG(DEBUG_EVALUATE, - printf("%s=%s evaluated as %s\n", token, value, ret)); -out: - blkid_free_config(conf); - free(t); - free(v); - return ret; -} - -/** - * blkid_evaluate_spec: - * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0) - * @cache: pointer to cache (or NULL when you don't want to re-use the cache) - * - * All returned paths are canonicalized, device-mapper paths are converted - * to the /dev/mapper/name format. - * - * Returns: allocated string with a device name. - */ -char *blkid_evaluate_spec(const char *spec, blkid_cache *cache) -{ - char *t = NULL, *v = NULL, *res; - - if (!spec) - return NULL; - - if (strchr(spec, '=') && - blkid_parse_tag_string(spec, &t, &v) != 0) /* parse error */ - return NULL; - - if (v) - res = blkid_evaluate_tag(t, v, cache); - else - res = canonicalize_path(spec); - - free(t); - free(v); - return res; -} - - -#ifdef TEST_PROGRAM -int main(int argc, char *argv[]) -{ - blkid_cache cache = NULL; - char *res; - - if (argc < 2) { - fprintf(stderr, "usage: %s <tag> | <spec>\n", argv[0]); - return EXIT_FAILURE; - } - - blkid_init_debug(0); - - res = blkid_evaluate_spec(argv[1], &cache); - if (res) - printf("%s\n", res); - if (cache) - blkid_put_cache(cache); - - return res ? EXIT_SUCCESS : EXIT_FAILURE; -} -#endif diff --git a/libblkid/exec_shell.c b/libblkid/exec_shell.c deleted file mode 100644 index 95620cd4d..000000000 --- a/libblkid/exec_shell.c +++ /dev/null @@ -1,27 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> - -#include "nls.h" -#include "c.h" -#include "xalloc.h" - -#include "exec_shell.h" - -#define DEFAULT_SHELL "/bin/sh" - -void __attribute__((__noreturn__)) exec_shell(void) { - const char *shell = getenv("SHELL"), *shell_basename; - char *arg0; - if (!shell) - shell = DEFAULT_SHELL; - - shell_basename = basename(shell); - arg0 = xmalloc(strlen(shell_basename) + 2); - arg0[0] = '-'; - strcpy(arg0 + 1, shell_basename); - - execl(shell, arg0, NULL); - err(EXIT_FAILURE, _("failed to execute %s"), shell); -} diff --git a/libblkid/exfat.c b/libblkid/exfat.c deleted file mode 100644 index 215c67114..000000000 --- a/libblkid/exfat.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include "superblocks.h" - -struct exfat_super_block { - uint8_t jump[3]; - uint8_t oem_name[8]; - uint8_t __unused1[53]; - uint64_t block_start; - uint64_t block_count; - uint32_t fat_block_start; - uint32_t fat_block_count; - uint32_t cluster_block_start; - uint32_t cluster_count; - uint32_t rootdir_cluster; - uint8_t volume_serial[4]; - struct { - uint8_t minor; - uint8_t major; - } version; - uint16_t volume_state; - uint8_t block_bits; - uint8_t bpc_bits; - uint8_t fat_count; - uint8_t drive_no; - uint8_t allocated_percent; -} __attribute__((__packed__)); - -struct exfat_entry_label { - uint8_t type; - uint8_t length; - uint8_t name[30]; -} __attribute__((__packed__)); - -#define BLOCK_SIZE(sb) (1 << (sb)->block_bits) -#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits) -#define EXFAT_FIRST_DATA_CLUSTER 2 -#define EXFAT_LAST_DATA_CLUSTER 0xffffff6 -#define EXFAT_ENTRY_SIZE 32 - -#define EXFAT_ENTRY_EOD 0x00 -#define EXFAT_ENTRY_LABEL 0x83 - -static blkid_loff_t block_to_offset(const struct exfat_super_block *sb, - blkid_loff_t block) -{ - return (blkid_loff_t) block << sb->block_bits; -} - -static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb, - uint32_t cluster) -{ - return le32_to_cpu(sb->cluster_block_start) + - ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) - << sb->bpc_bits); -} - -static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb, - uint32_t cluster) -{ - return block_to_offset(sb, cluster_to_block(sb, cluster)); -} - -static uint32_t next_cluster(blkid_probe pr, - const struct exfat_super_block *sb, uint32_t cluster) -{ - uint32_t *next; - blkid_loff_t fat_offset; - - fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start)) - + (blkid_loff_t) cluster * sizeof(cluster); - next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset, - sizeof(uint32_t)); - if (!next) - return 0; - return le32_to_cpu(*next); -} - -static struct exfat_entry_label *find_label(blkid_probe pr, - const struct exfat_super_block *sb) -{ - uint32_t cluster = le32_to_cpu(sb->rootdir_cluster); - blkid_loff_t offset = cluster_to_offset(sb, cluster); - uint8_t *entry; - - for (;;) { - entry = (uint8_t *) blkid_probe_get_buffer(pr, offset, - EXFAT_ENTRY_SIZE); - if (!entry) - return NULL; - if (entry[0] == EXFAT_ENTRY_EOD) - return NULL; - if (entry[0] == EXFAT_ENTRY_LABEL) - return (struct exfat_entry_label *) entry; - offset += EXFAT_ENTRY_SIZE; - if (offset % CLUSTER_SIZE(sb) == 0) { - cluster = next_cluster(pr, sb, cluster); - if (cluster < EXFAT_FIRST_DATA_CLUSTER) - return NULL; - if (cluster > EXFAT_LAST_DATA_CLUSTER) - return NULL; - offset = cluster_to_offset(sb, cluster); - } - } -} - -static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct exfat_super_block *sb; - struct exfat_entry_label *label; - - sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); - if (!sb) - return -1; - - label = find_label(pr, sb); - if (label) - blkid_probe_set_utf8label(pr, label->name, - min(label->length * 2, 30), BLKID_ENC_UTF16LE); - - blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4, - "%02hhX%02hhX-%02hhX%02hhX", - sb->volume_serial[3], sb->volume_serial[2], - sb->volume_serial[1], sb->volume_serial[0]); - - blkid_probe_sprintf_version(pr, "%u.%u", - sb->version.major, sb->version.minor); - - return 0; -} - -const struct blkid_idinfo exfat_idinfo = -{ - .name = "exfat", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_exfat, - .magics = - { - { .magic = "EXFAT ", .len = 8, .sboff = 3 }, - { NULL } - } -}; diff --git a/libblkid/ext.c b/libblkid/ext.c deleted file mode 100644 index eff96a066..000000000 --- a/libblkid/ext.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (C) 1999, 2001 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> -#ifdef __linux__ -#include <sys/utsname.h> -#endif -#include <time.h> - -#include "linux_version.h" -#include "superblocks.h" - -struct ext2_super_block { - uint32_t s_inodes_count; - uint32_t s_blocks_count; - uint32_t s_r_blocks_count; - uint32_t s_free_blocks_count; - uint32_t s_free_inodes_count; - uint32_t s_first_data_block; - uint32_t s_log_block_size; - uint32_t s_dummy3[7]; - unsigned char s_magic[2]; - uint16_t s_state; - uint16_t s_errors; - uint16_t s_minor_rev_level; - uint32_t s_lastcheck; - uint32_t s_checkinterval; - uint32_t s_creator_os; - uint32_t s_rev_level; - uint16_t s_def_resuid; - uint16_t s_def_resgid; - uint32_t s_first_ino; - uint16_t s_inode_size; - uint16_t s_block_group_nr; - uint32_t s_feature_compat; - uint32_t s_feature_incompat; - uint32_t s_feature_ro_compat; - unsigned char s_uuid[16]; - char s_volume_name[16]; - char s_last_mounted[64]; - uint32_t s_algorithm_usage_bitmap; - uint8_t s_prealloc_blocks; - uint8_t s_prealloc_dir_blocks; - uint16_t s_reserved_gdt_blocks; - uint8_t s_journal_uuid[16]; - uint32_t s_journal_inum; - uint32_t s_journal_dev; - uint32_t s_last_orphan; - uint32_t s_hash_seed[4]; - uint8_t s_def_hash_version; - uint8_t s_jnl_backup_type; - uint16_t s_reserved_word_pad; - uint32_t s_default_mount_opts; - uint32_t s_first_meta_bg; - uint32_t s_mkfs_time; - uint32_t s_jnl_blocks[17]; - uint32_t s_blocks_count_hi; - uint32_t s_r_blocks_count_hi; - uint32_t s_free_blocks_hi; - uint16_t s_min_extra_isize; - uint16_t s_want_extra_isize; - uint32_t s_flags; - uint16_t s_raid_stride; - uint16_t s_mmp_interval; - uint64_t s_mmp_block; - uint32_t s_raid_stripe_width; - uint32_t s_reserved[163]; -} __attribute__((packed)); - -/* magic string */ -#define EXT_SB_MAGIC "\123\357" -/* supper block offset */ -#define EXT_SB_OFF 0x400 -/* supper block offset in kB */ -#define EXT_SB_KBOFF (EXT_SB_OFF >> 10) -/* magic string offset within super block */ -#define EXT_MAG_OFF 0x38 - - - -/* for s_flags */ -#define EXT2_FLAGS_TEST_FILESYS 0x0004 - -/* for s_feature_compat */ -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 - -/* for s_feature_ro_compat */ -#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 -#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 -#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 -#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 -#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 - -/* for s_feature_incompat */ -#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 -#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ -#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 -#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 -#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 - -#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT2_FEATURE_RO_COMPAT_BTREE_DIR) -#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ - EXT2_FEATURE_INCOMPAT_META_BG) -#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP -#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP - -#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT2_FEATURE_RO_COMPAT_BTREE_DIR) -#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ - EXT3_FEATURE_INCOMPAT_RECOVER| \ - EXT2_FEATURE_INCOMPAT_META_BG) -#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP -#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP - -/* - * Check to see if a filesystem is in /proc/filesystems. - * Returns 1 if found, 0 if not - */ -static int fs_proc_check(const char *fs_name) -{ - FILE *f; - char buf[80], *cp, *t; - - f = fopen("/proc/filesystems", "r"); - if (!f) - return 0; - while (!feof(f)) { - if (!fgets(buf, sizeof(buf), f)) - break; - cp = buf; - if (!isspace(*cp)) { - while (*cp && !isspace(*cp)) - cp++; - } - while (*cp && isspace(*cp)) - cp++; - if ((t = strchr(cp, '\n')) != NULL) - *t = 0; - if ((t = strchr(cp, '\t')) != NULL) - *t = 0; - if ((t = strchr(cp, ' ')) != NULL) - *t = 0; - if (!strcmp(fs_name, cp)) { - fclose(f); - return 1; - } - } - fclose(f); - return (0); -} - -/* - * Check to see if a filesystem is available as a module - * Returns 1 if found, 0 if not - */ -static int check_for_modules(const char *fs_name) -{ -#ifdef __linux__ - struct utsname uts; - FILE *f; - char buf[1024], *cp; - int namesz; - - if (uname(&uts)) - return 0; - snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); - - f = fopen(buf, "r"); - if (!f) - return 0; - - namesz = strlen(fs_name); - - while (!feof(f)) { - if (!fgets(buf, sizeof(buf), f)) - break; - if ((cp = strchr(buf, ':')) != NULL) - *cp = 0; - else - continue; - if ((cp = strrchr(buf, '/')) == NULL) - continue; - cp++; - - if (!strncmp(cp, fs_name, namesz) && - (!strcmp(cp + namesz, ".ko") || - !strcmp(cp + namesz, ".ko.gz"))) { - fclose(f); - return 1; - } - } - fclose(f); -#endif /* __linux__ */ - return 0; -} - -/* - * Starting in 2.6.29, ext4 can be used to support filesystems - * without a journal. - */ -#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29) - -static int system_supports_ext2(void) -{ - static time_t last_check = 0; - static int ret = -1; - time_t now = time(0); - - if (ret != -1 || (now - last_check) < 5) - return ret; - last_check = now; - ret = (fs_proc_check("ext2") || check_for_modules("ext2")); - return ret; -} - -static int system_supports_ext4(void) -{ - static time_t last_check = 0; - static int ret = -1; - time_t now = time(0); - - if (ret != -1 || (now - last_check) < 5) - return ret; - last_check = now; - ret = (fs_proc_check("ext4") || check_for_modules("ext4")); - return ret; -} - -static int system_supports_ext4dev(void) -{ - static time_t last_check = 0; - static int ret = -1; - time_t now = time(0); - - if (ret != -1 || (now - last_check) < 5) - return ret; - last_check = now; - ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); - return ret; -} - -static int system_supports_ext4_ext2(void) -{ -#ifdef __linux__ - return get_linux_version() >= EXT4_SUPPORTS_EXT2; -#else - return 0; -#endif -} -/* - * reads superblock and returns: - * fc = feature_compat - * fi = feature_incompat - * frc = feature_ro_compat - */ -static struct ext2_super_block *ext_get_super( - blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc) -{ - struct ext2_super_block *es; - - es = (struct ext2_super_block *) - blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200); - if (!es) - return NULL; - if (fc) - *fc = le32_to_cpu(es->s_feature_compat); - if (fi) - *fi = le32_to_cpu(es->s_feature_incompat); - if (frc) - *frc = le32_to_cpu(es->s_feature_ro_compat); - - return es; -} - -static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", - le32_to_cpu(es->s_feature_compat), - le32_to_cpu(es->s_feature_incompat), - le32_to_cpu(es->s_feature_ro_compat))); - - if (strlen(es->s_volume_name)) - blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name, - sizeof(es->s_volume_name)); - blkid_probe_set_uuid(pr, es->s_uuid); - - if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) - blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL"); - - if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) && - ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) - blkid_probe_set_value(pr, "SEC_TYPE", - (unsigned char *) "ext2", - sizeof("ext2")); - - blkid_probe_sprintf_version(pr, "%u.%u", - le32_to_cpu(es->s_rev_level), - le16_to_cpu(es->s_minor_rev_level)); -} - - -static int probe_jbd(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct ext2_super_block *es; - uint32_t fi; - - es = ext_get_super(pr, NULL, &fi, NULL); - if (!es) - return -BLKID_ERR_PARAM; - if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) - return -BLKID_ERR_PARAM; - - ext_get_info(pr, 2, es); - return 0; -} - -static int probe_ext2(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct ext2_super_block *es; - uint32_t fc, frc, fi; - - es = ext_get_super(pr, &fc, &fi, &frc); - if (!es) - return -BLKID_ERR_PARAM; - - /* Distinguish between ext3 and ext2 */ - if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) - return -BLKID_ERR_PARAM; - - /* Any features which ext2 doesn't understand */ - if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || - (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) - return -BLKID_ERR_PARAM; - - /* - * If ext2 is not present, but ext4 or ext4dev are, then - * disclaim we are ext2 - */ - if (!system_supports_ext2() && - (system_supports_ext4() || system_supports_ext4dev()) && - system_supports_ext4_ext2()) - return -BLKID_ERR_PARAM; - - ext_get_info(pr, 2, es); - return 0; -} - -static int probe_ext3(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct ext2_super_block *es; - uint32_t fc, frc, fi; - - es = ext_get_super(pr, &fc, &fi, &frc); - if (!es) - return -BLKID_ERR_PARAM; - - /* ext3 requires journal */ - if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) - return -BLKID_ERR_PARAM; - - /* Any features which ext3 doesn't understand */ - if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || - (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) - return -BLKID_ERR_PARAM; - - ext_get_info(pr, 3, es); - return 0; -} - - -static int probe_ext4dev(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct ext2_super_block *es; - uint32_t fc, frc, fi; - - es = ext_get_super(pr, &fc, &fi, &frc); - if (!es) - return -BLKID_ERR_PARAM; - - /* Distinguish from jbd */ - if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) - return -BLKID_ERR_PARAM; - - /* - * If the filesystem does not have a journal and ext2 and ext4 - * is not present, then force this to be detected as an - * ext4dev filesystem. - */ - if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && - !system_supports_ext2() && !system_supports_ext4() && - system_supports_ext4dev() && - system_supports_ext4_ext2()) - goto force_ext4dev; - - /* - * If the filesystem is marked as OK for use by in-development - * filesystem code, but ext4dev is not supported, and ext4 is, - * then don't call ourselves ext4dev, since we should be - * detected as ext4 in that case. - * - * If the filesystem is marked as in use by production - * filesystem, then it can only be used by ext4 and NOT by - * ext4dev, so always disclaim we are ext4dev in that case. - */ - if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { - if (!system_supports_ext4dev() && system_supports_ext4()) - return -BLKID_ERR_PARAM; - } else - return -BLKID_ERR_PARAM; - -force_ext4dev: - ext_get_info(pr, 4, es); - return 0; -} - -static int probe_ext4(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct ext2_super_block *es; - uint32_t fc, frc, fi; - - es = ext_get_super(pr, &fc, &fi, &frc); - if (!es) - return -1; - - /* Distinguish from jbd */ - if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) - return -BLKID_ERR_PARAM; - - /* - * If the filesystem does not have a journal and ext2 is not - * present, then force this to be detected as an ext2 - * filesystem. - */ - if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && - !system_supports_ext2() && system_supports_ext4() && - system_supports_ext4_ext2()) - goto force_ext4; - - /* Ext4 has at least one feature which ext3 doesn't understand */ - if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && - !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) - return -BLKID_ERR_PARAM; - -force_ext4: - /* - * If the filesystem is a OK for use by in-development - * filesystem code, and ext4dev is supported or ext4 is not - * supported, then don't call ourselves ext4, so we can redo - * the detection and mark the filesystem as ext4dev. - * - * If the filesystem is marked as in use by production - * filesystem, then it can only be used by ext4 and NOT by - * ext4dev. - */ - if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { - if (system_supports_ext4dev() || !system_supports_ext4()) - return -BLKID_ERR_PARAM; - } - - ext_get_info(pr, 4, es); - return 0; -} - -#define BLKID_EXT_MAGICS \ - { \ - { \ - .magic = EXT_SB_MAGIC, \ - .len = sizeof(EXT_SB_MAGIC) - 1, \ - .kboff = EXT_SB_KBOFF, \ - .sboff = EXT_MAG_OFF \ - }, \ - { NULL } \ - } - -const struct blkid_idinfo jbd_idinfo = -{ - .name = "jbd", - .usage = BLKID_USAGE_OTHER, - .probefunc = probe_jbd, - .magics = BLKID_EXT_MAGICS -}; - -const struct blkid_idinfo ext2_idinfo = -{ - .name = "ext2", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ext2, - .magics = BLKID_EXT_MAGICS -}; - -const struct blkid_idinfo ext3_idinfo = -{ - .name = "ext3", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ext3, - .magics = BLKID_EXT_MAGICS -}; - -const struct blkid_idinfo ext4_idinfo = -{ - .name = "ext4", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ext4, - .magics = BLKID_EXT_MAGICS -}; - -const struct blkid_idinfo ext4dev_idinfo = -{ - .name = "ext4dev", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ext4dev, - .magics = BLKID_EXT_MAGICS -}; - diff --git a/libblkid/f2fs.c b/libblkid/f2fs.c deleted file mode 100644 index 1543a7a8b..000000000 --- a/libblkid/f2fs.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2013 Alejandro Martinez Ruiz <alex@nowcomputing.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License - */ - -#include <stddef.h> -#include <string.h> - -#include "superblocks.h" - -#define F2FS_MAGIC "\x10\x20\xF5\xF2" -#define F2FS_MAGIC_OFF 0 -#define F2FS_UUID_SIZE 16 -#define F2FS_LABEL_SIZE 512 -#define F2FS_SB1_OFF 0x400 -#define F2FS_SB1_KBOFF (F2FS_SB1_OFF >> 10) -#define F2FS_SB2_OFF 0x1400 -#define F2FS_SB2_KBOFF (F2FS_SB2_OFF >> 10) - -struct f2fs_super_block { /* According to version 1.1 */ -/* 0x00 */ uint32_t magic; /* Magic Number */ -/* 0x04 */ uint16_t major_ver; /* Major Version */ -/* 0x06 */ uint16_t minor_ver; /* Minor Version */ -/* 0x08 */ uint32_t log_sectorsize; /* log2 sector size in bytes */ -/* 0x0C */ uint32_t log_sectors_per_block; /* log2 # of sectors per block */ -/* 0x10 */ uint32_t log_blocksize; /* log2 block size in bytes */ -/* 0x14 */ uint32_t log_blocks_per_seg; /* log2 # of blocks per segment */ -/* 0x18 */ uint32_t segs_per_sec; /* # of segments per section */ -/* 0x1C */ uint32_t secs_per_zone; /* # of sections per zone */ -/* 0x20 */ uint32_t checksum_offset; /* checksum offset inside super block */ -/* 0x24 */ uint64_t block_count; /* total # of user blocks */ -/* 0x2C */ uint32_t section_count; /* total # of sections */ -/* 0x30 */ uint32_t segment_count; /* total # of segments */ -/* 0x34 */ uint32_t segment_count_ckpt; /* # of segments for checkpoint */ -/* 0x38 */ uint32_t segment_count_sit; /* # of segments for SIT */ -/* 0x3C */ uint32_t segment_count_nat; /* # of segments for NAT */ -/* 0x40 */ uint32_t segment_count_ssa; /* # of segments for SSA */ -/* 0x44 */ uint32_t segment_count_main; /* # of segments for main area */ -/* 0x48 */ uint32_t segment0_blkaddr; /* start block address of segment 0 */ -/* 0x4C */ uint32_t cp_blkaddr; /* start block address of checkpoint */ -/* 0x50 */ uint32_t sit_blkaddr; /* start block address of SIT */ -/* 0x54 */ uint32_t nat_blkaddr; /* start block address of NAT */ -/* 0x58 */ uint32_t ssa_blkaddr; /* start block address of SSA */ -/* 0x5C */ uint32_t main_blkaddr; /* start block address of main area */ -/* 0x60 */ uint32_t root_ino; /* root inode number */ -/* 0x64 */ uint32_t node_ino; /* node inode number */ -/* 0x68 */ uint32_t meta_ino; /* meta inode number */ -/* 0x6C */ uint8_t uuid[F2FS_UUID_SIZE]; /* 128-bit uuid for volume */ -/* 0x7C */ uint16_t volume_name[F2FS_LABEL_SIZE]; /* volume name */ -#if 0 -/* 0x47C */ uint32_t extension_count; /* # of extensions below */ -/* 0x480 */ uint8_t extension_list[64][8]; /* extension array */ -#endif -} __attribute__((packed)); - -static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct f2fs_super_block *sb; - uint16_t major, minor; - - sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block); - if (!sb) - return -1; - - major = le16_to_cpu(sb->major_ver); - minor = le16_to_cpu(sb->minor_ver); - - /* For version 1.0 we cannot know the correct sb structure */ - if (major == 1 && minor == 0) - return 0; - - if (*((unsigned char *) sb->volume_name)) - blkid_probe_set_utf8label(pr, (unsigned char *) sb->volume_name, - sizeof(sb->volume_name), - BLKID_ENC_UTF16LE); - - blkid_probe_set_uuid(pr, sb->uuid); - blkid_probe_sprintf_version(pr, "%u.%u", major, minor); - return 0; -} - -const struct blkid_idinfo f2fs_idinfo = -{ - .name = "f2fs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_f2fs, - .magics = - { - { - .magic = F2FS_MAGIC, - .len = 4, - .kboff = F2FS_SB1_KBOFF, - .sboff = F2FS_MAGIC_OFF - }, - { NULL } - } -}; diff --git a/libblkid/fileutils.c b/libblkid/fileutils.c deleted file mode 100644 index ebfb12857..000000000 --- a/libblkid/fileutils.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/time.h> -#include <sys/resource.h> - -#include "c.h" -#include "fileutils.h" -#include "pathnames.h" -#include "xalloc.h" - -#define _PATH_TMP "/tmp" -/* Create open temporary file in safe way. Please notice that the - * file permissions are -rw------- by default. */ -int xmkstemp(char **tmpname, char *dir) -{ - char *localtmp; - char *tmpenv; - mode_t old_mode; - int fd; - - /* Some use cases must be capable of being moved atomically - * with rename(2), which is the reason why dir is here. */ - if (dir != NULL) - tmpenv = dir; - else - tmpenv = getenv("TMPDIR"); - - if (tmpenv) - xasprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, - program_invocation_short_name); - else - xasprintf(&localtmp, "%s/%s.XXXXXX", _PATH_TMP, - program_invocation_short_name); - old_mode = umask(077); - fd = mkstemp(localtmp); - umask(old_mode); - if (fd == -1) { - free(localtmp); - localtmp = NULL; - } - *tmpname = localtmp; - return fd; -} - -/* - * portable getdtablesize() - */ -int get_fd_tabsize(void) -{ - int m; - -#if defined(HAVE_GETDTABLESIZE) - m = getdtablesize(); -#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) - struct rlimit rl; - - getrlimit(RLIMIT_NOFILE, &rl); - m = rl.rlim_cur; -#elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) - m = sysconf(_SC_OPEN_MAX); -#else - m = OPEN_MAX; -#endif - return m; -} - -#ifdef TEST_PROGRAM -int main(void) -{ - FILE *f; - char *tmpname; - f = xfmkstemp(&tmpname, NULL); - unlink(tmpname); - free(tmpname); - fclose(f); - return EXIT_FAILURE; -} -#endif diff --git a/libblkid/fileutils.h b/libblkid/fileutils.h deleted file mode 100644 index cf29e1b83..000000000 --- a/libblkid/fileutils.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef UTIL_LINUX_FILEUTILS -#define UTIL_LINUX_FILEUTILS - -extern int xmkstemp(char **tmpname, char *dir); - -static inline FILE *xfmkstemp(char **tmpname, char *dir) -{ - int fd; - FILE *ret; - fd = xmkstemp(tmpname, dir); - if (fd == -1) { - return NULL; - } - if (!(ret = fdopen(fd, "w+"))) { - close(fd); - return NULL; - } - return ret; -} - -extern int get_fd_tabsize(void); - -#endif /* UTIL_LINUX_FILEUTILS */ diff --git a/libblkid/gfs.c b/libblkid/gfs.c deleted file mode 100644 index b2c016304..000000000 --- a/libblkid/gfs.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -/* Common gfs/gfs2 constants: */ -#define GFS_LOCKNAME_LEN 64 - -/* gfs1 constants: */ -#define GFS_FORMAT_FS 1309 -#define GFS_FORMAT_MULTI 1401 -/* gfs2 constants: */ -#define GFS2_FORMAT_FS 1801 -#define GFS2_FORMAT_MULTI 1900 - -struct gfs2_meta_header { - uint32_t mh_magic; - uint32_t mh_type; - uint64_t __pad0; /* Was generation number in gfs1 */ - uint32_t mh_format; - uint32_t __pad1; /* Was incarnation number in gfs1 */ -}; - -struct gfs2_inum { - uint64_t no_formal_ino; - uint64_t no_addr; -}; - -struct gfs2_sb { - struct gfs2_meta_header sb_header; - - uint32_t sb_fs_format; - uint32_t sb_multihost_format; - uint32_t __pad0; /* Was superblock flags in gfs1 */ - - uint32_t sb_bsize; - uint32_t sb_bsize_shift; - uint32_t __pad1; /* Was journal segment size in gfs1 */ - - struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ - struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ - struct gfs2_inum sb_root_dir; - - char sb_lockproto[GFS_LOCKNAME_LEN]; - char sb_locktable[GFS_LOCKNAME_LEN]; - - struct gfs2_inum __pad3; /* Was quota inode in gfs1 */ - struct gfs2_inum __pad4; /* Was licence inode in gfs1 */ - uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */ -} __attribute__((packed)); - -static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct gfs2_sb *sbd; - - sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); - if (!sbd) - return -1; - - if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS && - be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) - { - if (*sbd->sb_locktable) - blkid_probe_set_label(pr, - (unsigned char *) sbd->sb_locktable, - sizeof(sbd->sb_locktable)); - - blkid_probe_set_uuid(pr, sbd->sb_uuid); - return 0; - } - - return -1; -} - -static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct gfs2_sb *sbd; - - sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); - if (!sbd) - return -1; - - if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS && - be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) - { - if (*sbd->sb_locktable) - blkid_probe_set_label(pr, - (unsigned char *) sbd->sb_locktable, - sizeof(sbd->sb_locktable)); - blkid_probe_set_uuid(pr, sbd->sb_uuid); - blkid_probe_set_version(pr, "1"); - return 0; - } - return -1; -} - -const struct blkid_idinfo gfs_idinfo = -{ - .name = "gfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_gfs, - .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ - .magics = - { - { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, - { NULL } - } -}; - -const struct blkid_idinfo gfs2_idinfo = -{ - .name = "gfs2", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_gfs2, - .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ - .magics = - { - { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, - { NULL } - } -}; - diff --git a/libblkid/gpt.c b/libblkid/gpt.c deleted file mode 100644 index 7288d683e..000000000 --- a/libblkid/gpt.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * EFI GPT partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * This code is not copy & past from any other implementation. - * - * For more information about GPT start your study at: - * http://en.wikipedia.org/wiki/GUID_Partition_Table - * http://technet.microsoft.com/en-us/library/cc739412(WS.10).aspx - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> -#include <stddef.h> - -#include "partitions.h" -#include "crc32.h" -#include "dos.h" - -#define GPT_PRIMARY_LBA 1 - -/* Signature - “EFI PART” */ -#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL -#define GPT_HEADER_SIGNATURE_STR "EFI PART" - -/* basic types */ -typedef uint16_t efi_char16_t; - -/* UUID */ -typedef struct { - uint32_t time_low; - uint16_t time_mid; - uint16_t time_hi_and_version; - uint8_t clock_seq_hi; - uint8_t clock_seq_low; - uint8_t node[6]; -} efi_guid_t; - - -#define GPT_UNUSED_ENTRY_GUID \ - ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}) -struct gpt_header { - uint64_t signature; /* "EFI PART" */ - uint32_t revision; - uint32_t header_size; /* usually 92 bytes */ - uint32_t header_crc32; /* checksum of header with this - * field zeroed during calculation */ - uint32_t reserved1; - - uint64_t my_lba; /* location of this header copy */ - uint64_t alternate_lba; /* location of the other header copy */ - uint64_t first_usable_lba; /* lirst usable LBA for partitions */ - uint64_t last_usable_lba; /* last usable LBA for partitions */ - - efi_guid_t disk_guid; /* disk UUID */ - - uint64_t partition_entries_lba; /* always 2 in primary header copy */ - uint32_t num_partition_entries; - uint32_t sizeof_partition_entry; - uint32_t partition_entry_array_crc32; - - /* - * The rest of the block is reserved by UEFI and must be zero. EFI - * standard handles this by: - * - * uint8_t reserved2[ BLKSSZGET - 92 ]; - * - * This definition is useless in practice. It is necessary to read - * whole block from the device rather than sizeof(struct gpt_header) - * only. - */ -} __attribute__ ((packed)); - -/*** not used -struct gpt_entry_attributes { - uint64_t required_to_function:1; - uint64_t reserved:47; - uint64_t type_guid_specific:16; -} __attribute__ ((packed)); -***/ - -struct gpt_entry { - efi_guid_t partition_type_guid; /* type UUID */ - efi_guid_t unique_partition_guid; /* partition UUID */ - uint64_t starting_lba; - uint64_t ending_lba; - - /*struct gpt_entry_attributes attributes;*/ - - uint64_t attributes; - - efi_char16_t partition_name[72 / sizeof(efi_char16_t)]; /* UTF-16LE string*/ -} __attribute__ ((packed)); - - -/* - * EFI uses crc32 with ~0 seed and xor's with ~0 at the end. - */ -static inline uint32_t count_crc32(const unsigned char *buf, size_t len) -{ - return (crc32(~0L, buf, len) ^ ~0L); -} - -static inline unsigned char *get_lba_buffer(blkid_probe pr, - uint64_t lba, size_t bytes) -{ - return blkid_probe_get_buffer(pr, - blkid_probe_get_sectorsize(pr) * lba, bytes); -} - -static inline int guidcmp(efi_guid_t left, efi_guid_t right) -{ - return memcmp(&left, &right, sizeof (efi_guid_t)); -} - -/* - * UUID is traditionally 16 byte big-endian array, except Intel EFI - * specification where the UUID is a structure of little-endian fields. - */ -static void swap_efi_guid(efi_guid_t *uid) -{ - uid->time_low = swab32(uid->time_low); - uid->time_mid = swab16(uid->time_mid); - uid->time_hi_and_version = swab16(uid->time_hi_and_version); -} - -static int last_lba(blkid_probe pr, uint64_t *lba) -{ - blkid_loff_t sz = blkid_probe_get_size(pr); - unsigned int ssz = blkid_probe_get_sectorsize(pr); - - if (sz < ssz) - return -1; - - *lba = (sz / ssz) - 1ULL; - return 0; -} - -/* - * Protective (legacy) MBR. - * - * This MBR contains standard DOS partition table with a single partition, type - * of 0xEE. The partition usually encompassing the entire GPT drive - or 2TiB - * for large disks. - * - * Note that Apple uses GPT/MBR hybrid disks, where the DOS partition table is - * synchronized with GPT. This synchronization has many restriction of course - * (due DOS PT limitations). - * - * Note that the PMBR detection is optional (enabled by default) and could be - * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()). - */ -static int is_pmbr_valid(blkid_probe pr) -{ - int flags = blkid_partitions_get_flags(pr); - unsigned char *data; - struct dos_partition *p; - int i; - - if (flags & BLKID_PARTS_FORCE_GPT) - goto ok; /* skip PMBR check */ - - data = blkid_probe_get_sector(pr, 0); - if (!data) - goto failed; - - if (!is_valid_mbr_signature(data)) - goto failed; - - p = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - - for (i = 0; i < 4; i++, p++) { - if (p->sys_type == BLKID_GPT_PARTITION) - goto ok; - } -failed: - return 0; -ok: - return 1; -} - -/* - * Reads GPT header to @hdr and returns a pointer to @hdr or NULL in case of - * error. The function also returns GPT entries in @ents. - * - * Note, this function does not allocate any memory. The GPT header has fixed - * size so we use stack, and @ents returns memory from libblkid buffer (so the - * next blkid_probe_get_buffer() will overwrite this buffer). - * - * This function checks validity of header and entries array. A corrupted - * header is not returned. - */ -static struct gpt_header *get_gpt_header( - blkid_probe pr, struct gpt_header *hdr, - struct gpt_entry **ents, uint64_t lba, - uint64_t lastlba) -{ - struct gpt_header *h; - uint32_t crc, orgcrc; - uint64_t lu, fu; - size_t esz; - uint32_t hsz, ssz; - - ssz = blkid_probe_get_sectorsize(pr); - - /* whole sector is allocated for GPT header */ - h = (struct gpt_header *) get_lba_buffer(pr, lba, ssz); - if (!h) - return NULL; - - if (le64_to_cpu(h->signature) != GPT_HEADER_SIGNATURE) - return NULL; - - hsz = le32_to_cpu(h->header_size); - - /* EFI: The HeaderSize must be greater than 92 and must be less - * than or equal to the logical block size. - */ - if (hsz > ssz || hsz < sizeof(*h)) - return NULL; - - /* Header has to be verified when header_crc32 is zero */ - orgcrc = h->header_crc32; - h->header_crc32 = 0; - crc = count_crc32((unsigned char *) h, hsz); - h->header_crc32 = orgcrc; - - if (crc != le32_to_cpu(orgcrc)) { - DBG(DEBUG_LOWPROBE, printf("GPT header corrupted\n")); - return NULL; - } - - /* Valid header has to be at MyLBA */ - if (le64_to_cpu(h->my_lba) != lba) { - DBG(DEBUG_LOWPROBE, printf( - "GPT->MyLBA mismatch with real position\n")); - return NULL; - } - - fu = le64_to_cpu(h->first_usable_lba); - lu = le64_to_cpu(h->last_usable_lba); - - /* Check if First and Last usable LBA makes sense */ - if (lu < fu || fu > lastlba || lu > lastlba) { - DBG(DEBUG_LOWPROBE, printf( - "GPT->{First,Last}UsableLBA out of range\n")); - return NULL; - } - - /* The header has to be outside usable range */ - if (fu < lba && lba < lu) { - DBG(DEBUG_LOWPROBE, printf("GPT header is inside usable area\n")); - return NULL; - } - - /* Size of blocks with GPT entries */ - esz = le32_to_cpu(h->num_partition_entries) * - le32_to_cpu(h->sizeof_partition_entry); - if (!esz) { - DBG(DEBUG_LOWPROBE, printf("GPT entries undefined\n")); - return NULL; - } - - /* The header seems valid, save it - * (we don't care about zeros in hdr->reserved2 area) */ - memcpy(hdr, h, sizeof(*h)); - h = hdr; - - /* Read GPT entries */ - *ents = (struct gpt_entry *) get_lba_buffer(pr, - le64_to_cpu(h->partition_entries_lba), esz); - if (!*ents) { - DBG(DEBUG_LOWPROBE, printf("GPT entries unreadable\n")); - return NULL; - } - - /* Validate entries */ - crc = count_crc32((unsigned char *) *ents, esz); - if (crc != le32_to_cpu(h->partition_entry_array_crc32)) { - DBG(DEBUG_LOWPROBE, printf("GPT entries corrupted\n")); - return NULL; - } - - return h; -} - -static int probe_gpt_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t lastlba = 0, lba; - struct gpt_header hdr, *h; - struct gpt_entry *e; - blkid_parttable tab = NULL; - blkid_partlist ls; - uint64_t fu, lu; - uint32_t ssf, i; - efi_guid_t guid; - - if (last_lba(pr, &lastlba)) - goto nothing; - - if (!is_pmbr_valid(pr)) - goto nothing; - - h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba); - if (!h) - h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba); - - if (!h) - goto nothing; - - blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8); - - if (blkid_probe_set_magic(pr, lba << 9, - sizeof(GPT_HEADER_SIGNATURE_STR) - 1, - (unsigned char *) GPT_HEADER_SIGNATURE_STR)) - goto err; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "gpt", lba << 9); - if (!tab) - goto err; - - guid = h->disk_guid; - swap_efi_guid(&guid); - blkid_parttable_set_id(tab, (const unsigned char *) &guid); - - ssf = blkid_probe_get_sectorsize(pr) / 512; - - fu = le64_to_cpu(h->first_usable_lba); - lu = le64_to_cpu(h->last_usable_lba); - - for (i = 0; i < le32_to_cpu(h->num_partition_entries); i++, e++) { - - blkid_partition par; - uint64_t start = le64_to_cpu(e->starting_lba); - uint64_t size = le64_to_cpu(e->ending_lba) - - le64_to_cpu(e->starting_lba) + 1ULL; - - /* 00000000-0000-0000-0000-000000000000 entry */ - if (!guidcmp(e->partition_type_guid, GPT_UNUSED_ENTRY_GUID)) { - blkid_partlist_increment_partno(ls); - continue; - } - /* the partition has to inside usable range */ - if (start < fu || start + size - 1 > lu) { - DBG(DEBUG_LOWPROBE, printf( - "GPT entry[%d] overflows usable area - ignore\n", - i)); - blkid_partlist_increment_partno(ls); - continue; - } - - par = blkid_partlist_add_partition(ls, tab, - start * ssf, size * ssf); - if (!par) - goto err; - - blkid_partition_set_utf8name(par, - (unsigned char *) e->partition_name, - sizeof(e->partition_name), BLKID_ENC_UTF16LE); - - guid = e->unique_partition_guid; - swap_efi_guid(&guid); - blkid_partition_set_uuid(par, (const unsigned char *) &guid); - - guid = e->partition_type_guid; - swap_efi_guid(&guid); - blkid_partition_set_type_uuid(par, (const unsigned char *) &guid); - - blkid_partition_set_flags(par, e->attributes); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - - -const struct blkid_idinfo gpt_pt_idinfo = -{ - .name = "gpt", - .probefunc = probe_gpt_pt, - .minsz = 1024 * 1440 + 1, /* ignore floppies */ - - /* - * It would be possible to check for DOS signature (0xAA55), but - * unfortunately almost all EFI GPT implemenations allow to optionaly - * skip the legacy MBR. We follows this behavior and MBR is optional. - * See is_valid_pmbr(). - * - * It means we have to always call probe_gpt_pt(). - */ - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/hfs.c b/libblkid/hfs.c deleted file mode 100644 index 6d960e9e7..000000000 --- a/libblkid/hfs.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <inttypes.h> - -#include "superblocks.h" -#include "md5.h" - -/* HFS / HFS+ */ -struct hfs_finder_info { - uint32_t boot_folder; - uint32_t start_app; - uint32_t open_folder; - uint32_t os9_folder; - uint32_t reserved; - uint32_t osx_folder; - uint8_t id[8]; -} __attribute__((packed)); - -struct hfs_mdb { - uint8_t signature[2]; - uint32_t cr_date; - uint32_t ls_Mod; - uint16_t atrb; - uint16_t nm_fls; - uint16_t vbm_st; - uint16_t alloc_ptr; - uint16_t nm_al_blks; - uint32_t al_blk_size; - uint32_t clp_size; - uint16_t al_bl_st; - uint32_t nxt_cnid; - uint16_t free_bks; - uint8_t label_len; - uint8_t label[27]; - uint32_t vol_bkup; - uint16_t vol_seq_num; - uint32_t wr_cnt; - uint32_t xt_clump_size; - uint32_t ct_clump_size; - uint16_t num_root_dirs; - uint32_t file_count; - uint32_t dir_count; - struct hfs_finder_info finder_info; - uint8_t embed_sig[2]; - uint16_t embed_startblock; - uint16_t embed_blockcount; -} __attribute__((packed)); - - -#define HFS_NODE_LEAF 0xff -#define HFSPLUS_POR_CNID 1 - -struct hfsplus_bnode_descriptor { - uint32_t next; - uint32_t prev; - uint8_t type; - uint8_t height; - uint16_t num_recs; - uint16_t reserved; -} __attribute__((packed)); - -struct hfsplus_bheader_record { - uint16_t depth; - uint32_t root; - uint32_t leaf_count; - uint32_t leaf_head; - uint32_t leaf_tail; - uint16_t node_size; -} __attribute__((packed)); - -struct hfsplus_catalog_key { - uint16_t key_len; - uint32_t parent_id; - uint16_t unicode_len; - uint8_t unicode[255 * 2]; -} __attribute__((packed)); - -struct hfsplus_extent { - uint32_t start_block; - uint32_t block_count; -} __attribute__((packed)); - -#define HFSPLUS_EXTENT_COUNT 8 -struct hfsplus_fork { - uint64_t total_size; - uint32_t clump_size; - uint32_t total_blocks; - struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; -} __attribute__((packed)); - -struct hfsplus_vol_header { - uint8_t signature[2]; - uint16_t version; - uint32_t attributes; - uint32_t last_mount_vers; - uint32_t reserved; - uint32_t create_date; - uint32_t modify_date; - uint32_t backup_date; - uint32_t checked_date; - uint32_t file_count; - uint32_t folder_count; - uint32_t blocksize; - uint32_t total_blocks; - uint32_t free_blocks; - uint32_t next_alloc; - uint32_t rsrc_clump_sz; - uint32_t data_clump_sz; - uint32_t next_cnid; - uint32_t write_count; - uint64_t encodings_bmp; - struct hfs_finder_info finder_info; - struct hfsplus_fork alloc_file; - struct hfsplus_fork ext_file; - struct hfsplus_fork cat_file; - struct hfsplus_fork attr_file; - struct hfsplus_fork start_file; -} __attribute__((packed)); - -#define HFSPLUS_SECTOR_SIZE 512 - -static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len) -{ - static unsigned char const hash_init[MD5LENGTH] = { - 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6, - 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac - }; - unsigned char uuid[MD5LENGTH]; - struct MD5Context md5c; - - if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0) - return -1; - MD5Init(&md5c); - MD5Update(&md5c, hash_init, MD5LENGTH); - MD5Update(&md5c, hfs_info, len); - MD5Final(uuid, &md5c); - uuid[6] = 0x30 | (uuid[6] & 0x0f); - uuid[8] = 0x80 | (uuid[8] & 0x3f); - return blkid_probe_set_uuid(pr, uuid); -} - -static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct hfs_mdb *hfs; - - hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb); - if (!hfs) - return -1; - - if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || - (memcmp(hfs->embed_sig, "HX", 2) == 0)) - return 1; /* Not hfs, but an embedded HFS+ */ - - hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id)); - - blkid_probe_set_label(pr, hfs->label, hfs->label_len); - return 0; -} - -static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; - struct hfsplus_bnode_descriptor *descr; - struct hfsplus_bheader_record *bnode; - struct hfsplus_catalog_key *key; - struct hfsplus_vol_header *hfsplus; - struct hfs_mdb *sbd; - unsigned int alloc_block_size; - unsigned int alloc_first_block; - unsigned int embed_first_block; - unsigned int off = 0; - unsigned int blocksize; - unsigned int cat_block; - unsigned int ext_block_start; - unsigned int ext_block_count; - unsigned int record_count; - unsigned int leaf_node_head; - unsigned int leaf_node_count; - unsigned int leaf_node_size; - unsigned int leaf_block; - int ext; - uint64_t leaf_off; - unsigned char *buf; - - sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb); - if (!sbd) - return -1; - - /* Check for a HFS+ volume embedded in a HFS volume */ - if (memcmp(sbd->signature, "BD", 2) == 0) { - if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && - (memcmp(sbd->embed_sig, "HX", 2) != 0)) - /* This must be an HFS volume, so fail */ - return 1; - - alloc_block_size = be32_to_cpu(sbd->al_blk_size); - alloc_first_block = be16_to_cpu(sbd->al_bl_st); - embed_first_block = be16_to_cpu(sbd->embed_startblock); - off = (alloc_first_block * 512) + - (embed_first_block * alloc_block_size); - - buf = blkid_probe_get_buffer(pr, - off + (mag->kboff * 1024), - sizeof(struct hfsplus_vol_header)); - hfsplus = (struct hfsplus_vol_header *) buf; - - } else - hfsplus = blkid_probe_get_sb(pr, mag, - struct hfsplus_vol_header); - - if (!hfsplus) - return -1; - - if ((memcmp(hfsplus->signature, "H+", 2) != 0) && - (memcmp(hfsplus->signature, "HX", 2) != 0)) - return 1; - - hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id)); - - blocksize = be32_to_cpu(hfsplus->blocksize); - if (blocksize < HFSPLUS_SECTOR_SIZE) - return -1; - - memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); - cat_block = be32_to_cpu(extents[0].start_block); - - buf = blkid_probe_get_buffer(pr, - off + ((blkid_loff_t) cat_block * blocksize), 0x2000); - if (!buf) - return 0; - - bnode = (struct hfsplus_bheader_record *) - &buf[sizeof(struct hfsplus_bnode_descriptor)]; - - leaf_node_head = be32_to_cpu(bnode->leaf_head); - leaf_node_size = be16_to_cpu(bnode->node_size); - leaf_node_count = be32_to_cpu(bnode->leaf_count); - if (leaf_node_count == 0) - return 0; - - leaf_block = (leaf_node_head * leaf_node_size) / blocksize; - - /* get physical location */ - for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { - ext_block_start = be32_to_cpu(extents[ext].start_block); - ext_block_count = be32_to_cpu(extents[ext].block_count); - if (ext_block_count == 0) - return 0; - - /* this is our extent */ - if (leaf_block < ext_block_count) - break; - - leaf_block -= ext_block_count; - } - if (ext == HFSPLUS_EXTENT_COUNT) - return 0; - - leaf_off = (ext_block_start + leaf_block) * blocksize; - - buf = blkid_probe_get_buffer(pr, - (blkid_loff_t) off + leaf_off, - leaf_node_size); - if (!buf) - return 0; - - descr = (struct hfsplus_bnode_descriptor *) buf; - record_count = be16_to_cpu(descr->num_recs); - if (record_count == 0) - return 0; - - if (descr->type != HFS_NODE_LEAF) - return 0; - - key = (struct hfsplus_catalog_key *) - &buf[sizeof(struct hfsplus_bnode_descriptor)]; - - if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID) - return 0; - - blkid_probe_set_utf8label(pr, key->unicode, - be16_to_cpu(key->unicode_len) * 2, - BLKID_ENC_UTF16BE); - return 0; -} - -const struct blkid_idinfo hfs_idinfo = -{ - .name = "hfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_hfs, - .flags = BLKID_IDINFO_TOLERANT, - .magics = - { - { .magic = "BD", .len = 2, .kboff = 1 }, - { NULL } - } -}; - -const struct blkid_idinfo hfsplus_idinfo = -{ - .name = "hfsplus", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_hfsplus, - .magics = - { - { .magic = "BD", .len = 2, .kboff = 1 }, - { .magic = "H+", .len = 2, .kboff = 1 }, - { .magic = "HX", .len = 2, .kboff = 1 }, - { NULL } - } -}; diff --git a/libblkid/highpoint_raid.c b/libblkid/highpoint_raid.c deleted file mode 100644 index 0b41344ae..000000000 --- a/libblkid/highpoint_raid.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct hpt45x_metadata { - uint32_t magic; -}; - -#define HPT45X_MAGIC_OK 0x5a7816f3 -#define HPT45X_MAGIC_BAD 0x5a7816fd - -static int probe_highpoint45x(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct hpt45x_metadata *hpt; - uint64_t off; - uint32_t magic; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 11) * 0x200; - hpt = (struct hpt45x_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct hpt45x_metadata)); - if (!hpt) - return -1; - magic = le32_to_cpu(hpt->magic); - if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic), - (unsigned char *) &hpt->magic)) - return -1; - return 0; -} - -static int probe_highpoint37x(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - return 0; -} - - -const struct blkid_idinfo highpoint45x_idinfo = { - .name = "hpt45x_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_highpoint45x, - .magics = BLKID_NONE_MAGIC -}; - -const struct blkid_idinfo highpoint37x_idinfo = { - .name = "hpt37x_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_highpoint37x, - .magics = { - /* - * Superblok offset: 4608 bytes (9 sectors) - * Magic string offset within superblock: 32 bytes - * - * kboff = (4608 + 32) / 1024 - * sboff = (4608 + 32) % kboff - */ - { .magic = "\xf0\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 }, - { .magic = "\xfd\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 }, - { NULL } - } -}; - - diff --git a/libblkid/hpfs.c b/libblkid/hpfs.c deleted file mode 100644 index f9b851a47..000000000 --- a/libblkid/hpfs.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct hpfs_boot_block -{ - uint8_t jmp[3]; - uint8_t oem_id[8]; - uint8_t bytes_per_sector[2]; - uint8_t sectors_per_cluster; - uint8_t n_reserved_sectors[2]; - uint8_t n_fats; - uint8_t n_rootdir_entries[2]; - uint8_t n_sectors_s[2]; - uint8_t media_byte; - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t heads_per_cyl; - uint32_t n_hidden_sectors; - uint32_t n_sectors_l; - uint8_t drive_number; - uint8_t mbz; - uint8_t sig_28h; - uint8_t vol_serno[4]; - uint8_t vol_label[11]; - uint8_t sig_hpfs[8]; - uint8_t pad[448]; - uint8_t magic[2]; -} __attribute__((packed)); - -struct hpfs_super_block -{ - uint8_t magic[4]; - uint8_t magic1[4]; - uint8_t version; -} __attribute__((packed)); - -struct hpfs_spare_super -{ - uint8_t magic[4]; - uint8_t magic1[4]; -} __attribute__((packed)); - - -#define HPFS_SB_OFFSET 0x2000 -#define HPFS_SBSPARE_OFFSET 0x2200 - -static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct hpfs_super_block *hs; - struct hpfs_spare_super *hss; - struct hpfs_boot_block *hbb; - uint8_t version; - - /* super block */ - hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block); - if (!hs) - return -1; - version = hs->version; - - /* spare super block */ - hss = (struct hpfs_spare_super *) - blkid_probe_get_buffer(pr, - HPFS_SBSPARE_OFFSET, - sizeof(struct hpfs_spare_super)); - if (!hss) - return -1; - if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0) - return -1; - - /* boot block (with UUID and LABEL) */ - hbb = (struct hpfs_boot_block *) - blkid_probe_get_buffer(pr, - 0, - sizeof(struct hpfs_boot_block)); - if (!hbb) - return -1; - if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 && - memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 && - hbb->sig_28h == 0x28) { - blkid_probe_set_label(pr, hbb->vol_label, sizeof(hbb->vol_label)); - blkid_probe_sprintf_uuid(pr, - hbb->vol_serno, sizeof(hbb->vol_serno), - "%02X%02X-%02X%02X", - hbb->vol_serno[3], hbb->vol_serno[2], - hbb->vol_serno[1], hbb->vol_serno[0]); - } - blkid_probe_sprintf_version(pr, "%u", version); - - return 0; -} - -const struct blkid_idinfo hpfs_idinfo = -{ - .name = "hpfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_hpfs, - .magics = - { - { - .magic = "\x49\xe8\x95\xf9", - .len = 4, - .kboff = (HPFS_SB_OFFSET >> 10) - }, - { NULL } - } -}; - - diff --git a/libblkid/include/Makemodule.am b/libblkid/include/Makemodule.am new file mode 100644 index 000000000..c4a52e4cf --- /dev/null +++ b/libblkid/include/Makemodule.am @@ -0,0 +1,57 @@ + +dist_noinst_HEADERS += \ + include/all-io.h \ + include/at.h \ + include/bitops.h \ + include/blkdev.h \ + include/monotonic.h \ + include/c.h \ + include/canonicalize.h \ + include/carefulputc.h \ + include/closestream.h \ + include/colors.h \ + include/cpuset.h \ + include/crc32.h \ + include/crc64.h \ + include/debug.h \ + include/env.h \ + include/exec_shell.h \ + include/exitcodes.h \ + include/fileutils.h \ + include/ismounted.h \ + include/linux_reboot.h \ + include/linux_version.h \ + include/list.h \ + include/loopdev.h \ + include/mangle.h \ + include/match.h \ + include/mbsalign.h \ + include/md5.h \ + include/minix.h \ + include/namespace.h \ + include/nls.h \ + include/optutils.h \ + include/pager.h \ + include/pamfail.h \ + include/path.h \ + include/pathnames.h \ + include/procutils.h \ + include/randutils.h \ + include/readutmp.h \ + include/rpmatch.h \ + include/setproctitle.h \ + include/strutils.h \ + include/swapprober.h \ + include/swapheader.h \ + include/sysfs.h \ + include/timer.h \ + include/timeutils.h \ + include/ttyutils.h \ + include/widechar.h \ + include/xalloc.h \ + include/pt-sgi.h \ + include/pt-bsd.h \ + include/pt-mbr.h \ + include/pt-mbr-partnames.h \ + include/pt-sun.h \ + include/statfs_magic.h diff --git a/libblkid/include/all-io.h b/libblkid/include/all-io.h new file mode 100644 index 000000000..1fad66e53 --- /dev/null +++ b/libblkid/include/all-io.h @@ -0,0 +1,84 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + * Petr Uzel <petr.uzel@suse.cz> + */ + +#ifndef UTIL_LINUX_ALL_IO_H +#define UTIL_LINUX_ALL_IO_H + +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "c.h" + +static inline int write_all(int fd, const void *buf, size_t count) +{ + while (count) { + ssize_t tmp; + + errno = 0; + tmp = write(fd, buf, count); + if (tmp > 0) { + count -= tmp; + if (count) + buf = (void *) ((char *) buf + tmp); + } else if (errno != EINTR && errno != EAGAIN) + return -1; + if (errno == EAGAIN) /* Try later, *sigh* */ + usleep(250000); + } + return 0; +} + +static inline int fwrite_all(const void *ptr, size_t size, + size_t nmemb, FILE *stream) +{ + while (nmemb) { + size_t tmp; + + errno = 0; + tmp = fwrite(ptr, size, nmemb, stream); + if (tmp > 0) { + nmemb -= tmp; + if (nmemb) + ptr = (void *) ((char *) ptr + (tmp * size)); + } else if (errno != EINTR && errno != EAGAIN) + return -1; + if (errno == EAGAIN) /* Try later, *sigh* */ + xusleep(250000); + } + return 0; +} + +static inline ssize_t read_all(int fd, char *buf, size_t count) +{ + ssize_t ret; + ssize_t c = 0; + int tries = 0; + + memset(buf, 0, count); + while (count > 0) { + ret = read(fd, buf, count); + if (ret <= 0) { + if ((errno == EAGAIN || errno == EINTR || ret == 0) && + (tries++ < 5)) { + usleep(250000); + continue; + } + return c ? c : -1; + } + if (ret > 0) + tries = 0; + count -= ret; + buf += ret; + c += ret; + } + return c; +} + + +#endif /* UTIL_LINUX_ALL_IO_H */ diff --git a/libblkid/at.h b/libblkid/include/at.h index 63a80f0c0..63a80f0c0 100644 --- a/libblkid/at.h +++ b/libblkid/include/at.h diff --git a/libblkid/include/bitops.h b/libblkid/include/bitops.h new file mode 100644 index 000000000..498ec63e7 --- /dev/null +++ b/libblkid/include/bitops.h @@ -0,0 +1,124 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#ifndef BITOPS_H +#define BITOPS_H + +#include <stdint.h> +#include <sys/param.h> + +#if defined(HAVE_BYTESWAP_H) +# include <byteswap.h> +#endif + +#if defined(HAVE_ENDIAN_H) +# include <endian.h> +#elif defined(HAVE_SYS_ENDIAN_H) /* BSDs have them here */ +# include <sys/endian.h> +#endif + +#if defined(__OpenBSD__) +# include <sys/types.h> +# define be16toh(x) betoh16(x) +# define be32toh(x) betoh32(x) +# define be64toh(x) betoh64(x) +#endif + +/* + * Fallbacks + */ +#ifndef bswap_16 +# define bswap_16(x) ((((x) & 0x00FF) << 8) | \ + (((x) & 0xFF00) >> 8)) +#endif + +#ifndef bswap_32 +# define bswap_32(x) ((((x) & 0x000000FF) << 24) | \ + (((x) & 0x0000FF00) << 8) | \ + (((x) & 0x00FF0000) >> 8) | \ + (((x) & 0xFF000000) >> 24)) +#endif + +#ifndef bswap_64 +# define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \ + (((x) & 0x000000000000FF00ULL) << 40) | \ + (((x) & 0x0000000000FF0000ULL) << 24) | \ + (((x) & 0x00000000FF000000ULL) << 8) | \ + (((x) & 0x000000FF00000000ULL) >> 8) | \ + (((x) & 0x0000FF0000000000ULL) >> 24) | \ + (((x) & 0x00FF000000000000ULL) >> 40) | \ + (((x) & 0xFF00000000000000ULL) >> 56)) +#endif + +#ifndef htobe16 +# if !defined(WORDS_BIGENDIAN) +# define htobe16(x) bswap_16 (x) +# define htole16(x) (x) +# define be16toh(x) bswap_16 (x) +# define le16toh(x) (x) +# define htobe32(x) bswap_32 (x) +# define htole32(x) (x) +# define be32toh(x) bswap_32 (x) +# define le32toh(x) (x) +# define htobe64(x) bswap_64 (x) +# define htole64(x) (x) +# define be64toh(x) bswap_64 (x) +# define le64toh(x) (x) +# else +# define htobe16(x) (x) +# define htole16(x) bswap_16 (x) +# define be16toh(x) (x) +# define le16toh(x) bswap_16 (x) +# define htobe32(x) (x) +# define htole32(x) bswap_32 (x) +# define be32toh(x) (x) +# define le32toh(x) bswap_32 (x) +# define htobe64(x) (x) +# define htole64(x) bswap_64 (x) +# define be64toh(x) (x) +# define le64toh(x) bswap_64 (x) +# endif +#endif + +/* + * Byte swab macros (based on linux/byteorder/swab.h) + */ +#define swab16(x) bswap_16(x) +#define swab32(x) bswap_32(x) +#define swab64(x) bswap_64(x) + +#define cpu_to_le16(x) ((uint16_t) htole16(x)) +#define cpu_to_le32(x) ((uint32_t) htole32(x)) +#define cpu_to_le64(x) ((uint64_t) htole64(x)) + +#define cpu_to_be16(x) ((uint16_t) htobe16(x)) +#define cpu_to_be32(x) ((uint32_t) htobe32(x)) +#define cpu_to_be64(x) ((uint64_t) htobe64(x)) + +#define le16_to_cpu(x) ((uint16_t) le16toh(x)) +#define le32_to_cpu(x) ((uint32_t) le32toh(x)) +#define le64_to_cpu(x) ((uint64_t) le64toh(x)) + +#define be16_to_cpu(x) ((uint16_t) be16toh(x)) +#define be32_to_cpu(x) ((uint32_t) be32toh(x)) +#define be64_to_cpu(x) ((uint64_t) be64toh(x)) + +/* + * Bit map related macros. Usually provided by libc. + */ +#ifndef NBBY +# define NBBY CHAR_BIT +#endif + +#ifndef setbit +# define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +# define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +# define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +# define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) +#endif + +#endif /* BITOPS_H */ + diff --git a/libblkid/include/blkdev.h b/libblkid/include/blkdev.h new file mode 100644 index 000000000..c994795a2 --- /dev/null +++ b/libblkid/include/blkdev.h @@ -0,0 +1,146 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#ifndef BLKDEV_H +#define BLKDEV_H + +#include <sys/types.h> +#include <sys/ioctl.h> +#ifdef HAVE_SYS_IOCCOM_H +# include <sys/ioccom.h> /* for _IO macro on e.g. Solaris */ +#endif +#include <fcntl.h> +#include <unistd.h> + +#ifdef HAVE_SYS_MKDEV_H +# include <sys/mkdev.h> /* major and minor on Solaris */ +#endif + +#define DEFAULT_SECTOR_SIZE 512 + +#ifdef __linux__ +/* very basic ioctls, should be available everywhere */ +# ifndef BLKROSET +# define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */ +# define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */ +# define BLKRRPART _IO(0x12,95) /* re-read partition table */ +# define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */ +# define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ +# define BLKRASET _IO(0x12,98) /* set read ahead for block device */ +# define BLKRAGET _IO(0x12,99) /* get current read ahead setting */ +# define BLKFRASET _IO(0x12,100) /* set filesystem (mm/filemap.c) read-ahead */ +# define BLKFRAGET _IO(0x12,101) /* get filesystem (mm/filemap.c) read-ahead */ +# define BLKSECTSET _IO(0x12,102) /* set max sectors per request (ll_rw_blk.c) */ +# define BLKSECTGET _IO(0x12,103) /* get max sectors per request (ll_rw_blk.c) */ +# define BLKSSZGET _IO(0x12,104) /* get block device sector size */ + +/* ioctls introduced in 2.2.16, removed in 2.5.58 */ +# define BLKELVGET _IOR(0x12,106,size_t) /* elevator get */ +# define BLKELVSET _IOW(0x12,107,size_t) /* elevator set */ + +# define BLKBSZGET _IOR(0x12,112,size_t) +# define BLKBSZSET _IOW(0x12,113,size_t) +# endif /* !BLKROSET */ + +# ifndef BLKGETSIZE64 +# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +# endif + +/* block device topology ioctls, introduced in 2.6.32 (commit ac481c20) */ +# ifndef BLKIOMIN +# define BLKIOMIN _IO(0x12,120) +# define BLKIOOPT _IO(0x12,121) +# define BLKALIGNOFF _IO(0x12,122) +# define BLKPBSZGET _IO(0x12,123) +# endif + +/* discard zeroes support, introduced in 2.6.33 (commit 98262f27) */ +# ifndef BLKDISCARDZEROES +# define BLKDISCARDZEROES _IO(0x12,124) +# endif + +/* filesystem freeze, introduced in 2.6.29 (commit fcccf502) */ +# ifndef FIFREEZE +# define FIFREEZE _IOWR('X', 119, int) /* Freeze */ +# define FITHAW _IOWR('X', 120, int) /* Thaw */ +# endif + +/* uniform CD-ROM information */ +# ifndef CDROM_GET_CAPABILITY +# define CDROM_GET_CAPABILITY 0x5331 +# endif + +#endif /* __linux */ + + +#ifdef APPLE_DARWIN +# define BLKGETSIZE DKIOCGETBLOCKCOUNT32 +#endif + +#ifndef HDIO_GETGEO +# ifdef __linux__ +# define HDIO_GETGEO 0x0301 +# endif + +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; /* truncated */ + unsigned long start; +}; +#endif /* HDIO_GETGEO */ + + +/* are we working with block device? */ +int is_blkdev(int fd); + +/* Determine size in bytes */ +off_t blkdev_find_size (int fd); + +/* get size in bytes */ +int blkdev_get_size(int fd, unsigned long long *bytes); + +/* get 512-byte sector count */ +int blkdev_get_sectors(int fd, unsigned long long *sectors); + +/* get hardware sector size */ +int blkdev_get_sector_size(int fd, int *sector_size); + +/* specifies whether or not the device is misaligned */ +int blkdev_is_misaligned(int fd); + +/* get physical block device size */ +int blkdev_get_physector_size(int fd, int *sector_size); + +/* is the device cdrom capable? */ +int blkdev_is_cdrom(int fd); + +/* get device's geometry - legacy */ +int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s); + +/* SCSI device types. Copied almost as-is from kernel header. + * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/scsi/scsi.h */ +#define SCSI_TYPE_DISK 0x00 +#define SCSI_TYPE_TAPE 0x01 +#define SCSI_TYPE_PRINTER 0x02 +#define SCSI_TYPE_PROCESSOR 0x03 /* HP scanners use this */ +#define SCSI_TYPE_WORM 0x04 /* Treated as ROM by our system */ +#define SCSI_TYPE_ROM 0x05 +#define SCSI_TYPE_SCANNER 0x06 +#define SCSI_TYPE_MOD 0x07 /* Magneto-optical disk - treated as SCSI_TYPE_DISK */ +#define SCSI_TYPE_MEDIUM_CHANGER 0x08 +#define SCSI_TYPE_COMM 0x09 /* Communications device */ +#define SCSI_TYPE_RAID 0x0c +#define SCSI_TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ +#define SCSI_TYPE_RBC 0x0e +#define SCSI_TYPE_OSD 0x11 +#define SCSI_TYPE_NO_LUN 0x7f + +/* convert scsi type code to name */ +const char *blkdev_scsi_type_to_name(int type); + + +#endif /* BLKDEV_H */ diff --git a/libblkid/include/blkid.h b/libblkid/include/blkid.h new file mode 100644 index 000000000..4d4313021 --- /dev/null +++ b/libblkid/include/blkid.h @@ -0,0 +1,414 @@ +/* + * blkid.h - Interface for libblkid, a library to identify block devices + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BLKID_BLKID_H +#define _BLKID_BLKID_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBBLKID_VERSION "2.25.0" +#define LIBBLKID_DATE "22-Jul-2014" + +/** + * blkid_dev: + * + * The device object keeps information about one device + */ +typedef struct blkid_struct_dev *blkid_dev; + +/** + * blkid_cache: + * + * information about all system devices + */ +typedef struct blkid_struct_cache *blkid_cache; + +/** + * blkid_probe: + * + * low-level probing setting + */ +typedef struct blkid_struct_probe *blkid_probe; + +/** + * blkid_topology: + * + * device topology information + */ +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; + +/** + * blkid_loff_t: + * + * 64-bit signed number for offsets and sizes + */ +typedef int64_t blkid_loff_t; + +/** + * blkid_tag_iterate: + * + * tags iterator for high-level (blkid_cache) API + */ +typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; + +/** + * blkid_dev_iterate: + * + * devices iterator for high-level (blkid_cache) API + */ +typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; + +/* + * Flags for blkid_get_dev + * + * BLKID_DEV_CREATE Create an empty device structure if not found + * in the cache. + * BLKID_DEV_VERIFY Make sure the device structure corresponds + * with reality. + * BLKID_DEV_FIND Just look up a device entry, and return NULL + * if it is not found. + * BLKID_DEV_NORMAL Get a valid device structure, either from the + * cache or by probing the device. + */ +#define BLKID_DEV_FIND 0x0000 +#define BLKID_DEV_CREATE 0x0001 +#define BLKID_DEV_VERIFY 0x0002 +#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY) + + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __ul_attribute__ +# if __GNUC_PREREQ (3, 4) +# define __ul_attribute__(_a_) __attribute__(_a_) +# else +# define __ul_attribute__(_a_) +# endif +#endif + +/* cache.c */ +extern void blkid_init_debug(int mask); +extern void blkid_put_cache(blkid_cache cache); +extern int blkid_get_cache(blkid_cache *cache, const char *filename); +extern void blkid_gc_cache(blkid_cache cache); + +/* dev.c */ +extern const char *blkid_dev_devname(blkid_dev dev) + __ul_attribute__((warn_unused_result)); + +extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache); +extern int blkid_dev_set_search(blkid_dev_iterate iter, + char *search_type, char *search_value); +extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev); +extern void blkid_dev_iterate_end(blkid_dev_iterate iterate); + +/* devno.c */ +extern char *blkid_devno_to_devname(dev_t devno) + __ul_attribute__((warn_unused_result)); +extern int blkid_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno) + __ul_attribute__((warn_unused_result)); + +/* devname.c */ +extern int blkid_probe_all(blkid_cache cache); +extern int blkid_probe_all_new(blkid_cache cache); +extern int blkid_probe_all_removable(blkid_cache cache); + +extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags); + +/* getsize.c */ +extern blkid_loff_t blkid_get_dev_size(int fd); + +/* verify.c */ +extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); + +/* read.c */ + +/* resolve.c */ +extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname) + __ul_attribute__((warn_unused_result)); +extern char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value) + __ul_attribute__((warn_unused_result)); + +/* tag.c */ +extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev); +extern int blkid_tag_next(blkid_tag_iterate iterate, + const char **type, const char **value); +extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); +extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value); + +extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value); + +extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val); + +/* version.c */ +extern int blkid_parse_version_string(const char *ver_string) + __ul_attribute__((nonnull)); +extern int blkid_get_library_version(const char **ver_string, + const char **date_string); + +/* encode.c */ +extern int blkid_encode_string(const char *str, char *str_enc, size_t len); +extern int blkid_safe_string(const char *str, char *str_safe, size_t len); + +/* evaluate.c */ +extern int blkid_send_uevent(const char *devname, const char *action); +extern char *blkid_evaluate_tag(const char *token, const char *value, + blkid_cache *cache) + __ul_attribute__((warn_unused_result)); +extern char *blkid_evaluate_spec(const char *spec, blkid_cache *cache) + __ul_attribute__((warn_unused_result)); + +/* probe.c */ +extern blkid_probe blkid_new_probe(void) + __ul_attribute__((warn_unused_result)); +extern blkid_probe blkid_new_probe_from_filename(const char *filename) + __ul_attribute__((warn_unused_result)); +extern void blkid_free_probe(blkid_probe pr); + +extern void blkid_reset_probe(blkid_probe pr); + +extern int blkid_probe_set_device(blkid_probe pr, int fd, + blkid_loff_t off, blkid_loff_t size); + +extern dev_t blkid_probe_get_devno(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern int blkid_probe_is_wholedisk(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern blkid_loff_t blkid_probe_get_size(blkid_probe pr); +extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr); +extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr); +extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr); + +extern int blkid_probe_get_fd(blkid_probe pr); + +/* + * superblocks probing + */ +extern int blkid_known_fstype(const char *fstype); + +extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage); + +extern int blkid_probe_enable_superblocks(blkid_probe pr, int enable); + +#define BLKID_SUBLKS_LABEL (1 << 1) /* read LABEL from superblock */ +#define BLKID_SUBLKS_LABELRAW (1 << 2) /* read and define LABEL_RAW result value*/ +#define BLKID_SUBLKS_UUID (1 << 3) /* read UUID from superblock */ +#define BLKID_SUBLKS_UUIDRAW (1 << 4) /* read and define UUID_RAW result value */ +#define BLKID_SUBLKS_TYPE (1 << 5) /* define TYPE result value */ +#define BLKID_SUBLKS_SECTYPE (1 << 6) /* define compatible fs type (second type) */ +#define BLKID_SUBLKS_USAGE (1 << 7) /* define USAGE result value */ +#define BLKID_SUBLKS_VERSION (1 << 8) /* read FS type from superblock */ +#define BLKID_SUBLKS_MAGIC (1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */ +#define BLKID_SUBLKS_BADCSUM (1 << 10) /* allow a bad checksum */ + +#define BLKID_SUBLKS_DEFAULT (BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \ + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE) + +extern int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags); +extern int blkid_probe_reset_superblocks_filter(blkid_probe pr); +extern int blkid_probe_invert_superblocks_filter(blkid_probe pr); + +/** + * BLKID_FLTR_NOTIN + */ +#define BLKID_FLTR_NOTIN 1 +/** + * BLKID_FLTR_ONLYIN + */ +#define BLKID_FLTR_ONLYIN 2 +extern int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]); + +#define BLKID_USAGE_FILESYSTEM (1 << 1) +#define BLKID_USAGE_RAID (1 << 2) +#define BLKID_USAGE_CRYPTO (1 << 3) +#define BLKID_USAGE_OTHER (1 << 4) +extern int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage); + +/* + * topology probing + */ +extern int blkid_probe_enable_topology(blkid_probe pr, int enable); + +/* binary interface */ +extern blkid_topology blkid_probe_get_topology(blkid_probe pr); + +extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) + __ul_attribute__((nonnull)); + +/* + * partitions probing + */ +extern int blkid_known_pttype(const char *pttype); + +extern int blkid_probe_enable_partitions(blkid_probe pr, int enable); + +extern int blkid_probe_reset_partitions_filter(blkid_probe pr); +extern int blkid_probe_invert_partitions_filter(blkid_probe pr); +extern int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]); + +/* partitions probing flags */ +#define BLKID_PARTS_FORCE_GPT (1 << 1) +#define BLKID_PARTS_ENTRY_DETAILS (1 << 2) +#define BLKID_PARTS_MAGIC (1 << 3) +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_parttable blkid_partlist_get_table(blkid_partlist ls); +extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n); +extern blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n); +extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno); +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) + __ul_attribute__((nonnull)); + +extern const char *blkid_partition_get_type_string(blkid_partition par); + +extern unsigned long long blkid_partition_get_flags(blkid_partition par) + __ul_attribute__((nonnull)); + +extern int blkid_partition_is_logical(blkid_partition par) + __ul_attribute__((nonnull)); +extern int blkid_partition_is_extended(blkid_partition par) + __ul_attribute__((nonnull)); +extern int blkid_partition_is_primary(blkid_partition par) + __ul_attribute__((nonnull)); + +extern const char *blkid_parttable_get_type(blkid_parttable tab); +extern const char *blkid_parttable_get_id(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 + */ +extern int blkid_do_probe(blkid_probe pr); +extern int blkid_do_safeprobe(blkid_probe pr); +extern int blkid_do_fullprobe(blkid_probe pr); + +extern int blkid_probe_numof_values(blkid_probe pr); +extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name, + const char **data, size_t *len); +extern int blkid_probe_lookup_value(blkid_probe pr, const char *name, + const char **data, size_t *len); +extern int blkid_probe_has_value(blkid_probe pr, const char *name) + __ul_attribute__((nonnull)); + +extern int blkid_do_wipe(blkid_probe pr, int dryrun); +extern int blkid_probe_step_back(blkid_probe pr); + +/* + * Deprecated functions/macros + */ +#ifndef BLKID_DISABLE_DEPRECATED + +#define BLKID_PROBREQ_LABEL BLKID_SUBLKS_LABEL +#define BLKID_PROBREQ_LABELRAW BLKID_SUBLKS_LABELRAW +#define BLKID_PROBREQ_UUID BLKID_SUBLKS_UUID +#define BLKID_PROBREQ_UUIDRAW BLKID_SUBLKS_UUIDRAW +#define BLKID_PROBREQ_TYPE BLKID_SUBLKS_TYPE +#define BLKID_PROBREQ_SECTYPE BLKID_SUBLKS_SECTYPE +#define BLKID_PROBREQ_USAGE BLKID_SUBLKS_USAGE +#define BLKID_PROBREQ_VERSION BLKID_SUBLKS_VERSION + +extern int blkid_probe_set_request(blkid_probe pr, int flags) + __ul_attribute__((deprecated)); + +extern int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) + __ul_attribute__((deprecated)); + +extern int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) + __ul_attribute__((deprecated)); + +extern int blkid_probe_invert_filter(blkid_probe pr) + __ul_attribute__((deprecated)); + +extern int blkid_probe_reset_filter(blkid_probe pr) + __ul_attribute__((deprecated)); + +#endif /* BLKID_DISABLE_DEPRECATED */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_BLKID_H */ diff --git a/libblkid/canonicalize.h b/libblkid/include/canonicalize.h index 7a18aca09..7a18aca09 100644 --- a/libblkid/canonicalize.h +++ b/libblkid/include/canonicalize.h diff --git a/libblkid/include/carefulputc.h b/libblkid/include/carefulputc.h new file mode 100644 index 000000000..3a0ec5b66 --- /dev/null +++ b/libblkid/include/carefulputc.h @@ -0,0 +1,67 @@ +#ifndef UTIL_LINUX_CAREFUULPUTC_H +#define UTIL_LINUX_CAREFUULPUTC_H + +/* + * A putc() for use in write and wall (that sometimes are sgid tty). + * It avoids control characters in our locale, and also ASCII control + * characters. Note that the locale of the recipient is unknown. +*/ +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +static inline int fputc_careful(int c, FILE *fp, const char fail) +{ + int ret; + + if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') + ret = putc(c, fp); + else if (!isascii(c)) + ret = fprintf(fp, "\\%3o", (unsigned char)c); + else { + ret = putc(fail, fp); + if (ret != EOF) + ret = putc(c ^ 0x40, fp); + } + return (ret < 0) ? EOF : 0; +} + +static inline void fputs_quoted(const char *data, FILE *out) +{ + const char *p; + + fputc('"', out); + for (p = data; p && *p; p++) { + if ((unsigned char) *p == 0x22 || /* " */ + (unsigned char) *p == 0x5c || /* \ */ + (unsigned char) *p == 0x60 || /* ` */ + (unsigned char) *p == 0x24 || /* $ */ + !isprint((unsigned char) *p) || + iscntrl((unsigned char) *p)) { + + fprintf(out, "\\x%02x", (unsigned char) *p); + } else + fputc(*p, out); + } + fputc('"', out); +} + +static inline void fputs_nonblank(const char *data, FILE *out) +{ + const char *p; + + for (p = data; p && *p; p++) { + if (isblank((unsigned char) *p) || + (unsigned char) *p == 0x5c || /* \ */ + !isprint((unsigned char) *p) || + iscntrl((unsigned char) *p)) { + + fprintf(out, "\\x%02x", (unsigned char) *p); + + } else + fputc(*p, out); + } +} + + +#endif /* _CAREFUULPUTC_H */ diff --git a/libblkid/include/closestream.h b/libblkid/include/closestream.h new file mode 100644 index 000000000..7842456fb --- /dev/null +++ b/libblkid/include/closestream.h @@ -0,0 +1,71 @@ +#ifndef UTIL_LINUX_CLOSESTREAM_H +#define UTIL_LINUX_CLOSESTREAM_H + +#include <stdio.h> +#ifdef HAVE_STDIO_EXT_H +#include <stdio_ext.h> +#endif +#include <unistd.h> + +#include "c.h" +#include "nls.h" + +#ifndef HAVE___FPENDING +static inline int +__fpending(FILE *stream __attribute__((__unused__))) +{ + return 0; +} +#endif + +static inline int +close_stream(FILE * stream) +{ + const int some_pending = (__fpending(stream) != 0); + const int prev_fail = (ferror(stream) != 0); + const int fclose_fail = (fclose(stream) != 0); + + if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) { + if (!fclose_fail && !(errno == EPIPE)) + errno = 0; + return EOF; + } + return 0; +} + +/* Meant to be used atexit(close_stdout); */ +static inline void +close_stdout(void) +{ + if (close_stream(stdout) != 0 && !(errno == EPIPE)) { + if (errno) + warn(_("write error")); + else + warnx(_("write error")); + _exit(EXIT_FAILURE); + } + + if (close_stream(stderr) != 0) + _exit(EXIT_FAILURE); +} + +#ifndef HAVE_FSYNC +static inline int +fsync(int fd __attribute__((__unused__))) +{ + return 0; +} +#endif + +static inline int +close_fd(int fd) +{ + const int fsync_fail = (fsync(fd) != 0); + const int close_fail = (close(fd) != 0); + + if (fsync_fail || close_fail) + return EOF; + return 0; +} + +#endif /* UTIL_LINUX_CLOSESTREAM_H */ diff --git a/libblkid/include/colors.h b/libblkid/include/colors.h new file mode 100644 index 000000000..97efc486a --- /dev/null +++ b/libblkid/include/colors.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com> + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef UTIL_LINUX_COLORS_H +#define UTIL_LINUX_COLORS_H + +#include <stdio.h> +#include <unistd.h> + +#define UL_COLOR_RESET "\033[0m" +#define UL_COLOR_BOLD "\033[1m" +#define UL_COLOR_HALFBRIGHT "\033[2m" +#define UL_COLOR_UNDERSCORE "\033[4m" +#define UL_COLOR_BLINK "\033[5m" +#define UL_COLOR_REVERSE "\033[7m" + +/* Standard colors */ +#define UL_COLOR_BLACK "\033[30m" +#define UL_COLOR_RED "\033[31m" +#define UL_COLOR_GREEN "\033[32m" +#define UL_COLOR_BROWN "\033[33m" /* well, brown */ +#define UL_COLOR_BLUE "\033[34m" +#define UL_COLOR_MAGENTA "\033[35m" +#define UL_COLOR_CYAN "\033[36m" +#define UL_COLOR_GRAY "\033[37m" + +/* Bold variants */ +#define UL_COLOR_DARK_GRAY "\033[1;30m" +#define UL_COLOR_BOLD_RED "\033[1;31m" +#define UL_COLOR_BOLD_GREEN "\033[1;32m" +#define UL_COLOR_BOLD_YELLOW "\033[1;33m" +#define UL_COLOR_BOLD_BLUE "\033[1;34m" +#define UL_COLOR_BOLD_MAGENTA "\033[1;35m" +#define UL_COLOR_BOLD_CYAN "\033[1;36m" + +#define UL_COLOR_WHITE "\033[1;37m" + +/* --color[=WHEN] */ +enum colortmode { + UL_COLORMODE_AUTO = 0, + UL_COLORMODE_NEVER, + UL_COLORMODE_ALWAYS, + UL_COLORMODE_UNDEF, + + __UL_NCOLORMODES /* last */ +}; + +extern int colormode_from_string(const char *str); +extern int colormode_or_err(const char *str, const char *errmsg); + +/* Initialize the global variable UL_COLOR_TERM_OK */ +extern int colors_init(int mode, const char *util_name); + +/* Returns 1 or 0 */ +extern int colors_wanted(void); + +/* temporary enable/disable colors */ +extern void colors_off(void); +extern void colors_on(void); + + +/* Set the color */ +extern void color_fenable(const char *seq, FILE *f); + +extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f); +extern const char *color_scheme_get_sequence(const char *name, const char *dflt); + +static inline void color_enable(const char *seq) +{ + color_fenable(seq, stdout); +} + +static inline void color_scheme_enable(const char *name, const char *dflt) +{ + color_scheme_fenable(name, dflt, stdout); +} + +/* Reset colors to default */ +extern void color_fdisable(FILE *f); + +static inline void color_disable(void) +{ + color_fdisable(stdout); +} + +/* converts "red" to UL_COLOR_RED, etc. */ +extern const char *color_sequence_from_colorname(const char *str); + + +#endif /* UTIL_LINUX_COLORS_H */ diff --git a/libblkid/include/config.h b/libblkid/include/config.h new file mode 100644 index 000000000..0a71fcf9c --- /dev/null +++ b/libblkid/include/config.h @@ -0,0 +1,687 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Enable agetty --reload feature */ +#define AGETTY_RELOAD 1 + +/* Should chfn and chsh require the user to enter the password? */ +#define CHFN_CHSH_PASSWORD 1 + +/* Path to hwclock adjtime file */ +#define CONFIG_ADJTIME_PATH "/etc/adjtime" + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 1 + +/* search path for fs helpers */ +#define FS_SEARCH_PATH "/sbin:/sbin/fs.d:/sbin/fs" + +/* Define to 1 if you have the <asm/io.h> header file. */ +/* #undef HAVE_ASM_IO_H */ + +/* Define to 1 if you have the <byteswap.h> header file. */ +#define HAVE_BYTESWAP_H 1 + +/* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +/* #undef HAVE_CFLOCALECOPYCURRENT */ + +/* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ + +/* Define to 1 if you have the `clock_gettime' function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if the system has the type `cpu_set_t'. */ +#define HAVE_CPU_SET_T 1 + +/* Define to 1 if you have the <crypt.h> header file. */ +#define HAVE_CRYPT_H 1 + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#define HAVE_DCGETTEXT 1 + +/* Define to 1 if you have the declaration of `CPU_ALLOC', and to 0 if you + don't. */ +#define HAVE_DECL_CPU_ALLOC 1 + +/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't. + */ +/* #undef HAVE_DECL_DIRFD */ + +/* Define to 1 if you have the declaration of `_NL_TIME_WEEK_1STDAY', and to 0 + if you don't. */ +#define HAVE_DECL__NL_TIME_WEEK_1STDAY 1 + +/* Define to 1 if you have the `dirfd' function. */ +#define HAVE_DIRFD 1 + +/* Define to 1 if `dd_fd' is a member of `DIR'. */ +/* #undef HAVE_DIR_DD_FD */ + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the <endian.h> header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if have **environ prototype */ +#define HAVE_ENVIRON_DECL 1 + +/* Define to 1 if you have the `err' function. */ +#define HAVE_ERR 1 + +/* Define to 1 if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `errx' function. */ +#define HAVE_ERRX 1 + +/* Define to 1 if you have the <err.h> header file. */ +#define HAVE_ERR_H 1 + +/* Have valid fallocate() function */ +#define HAVE_FALLOCATE 1 + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fstatat' function. */ +#define HAVE_FSTATAT 1 + +/* Define to 1 if you have the `fsync' function. */ +#define HAVE_FSYNC 1 + +/* Define to 1 if you have the `futimens' function. */ +#define HAVE_FUTIMENS 1 + +/* Define to 1 if you have the `getdomainname' function. */ +#define HAVE_GETDOMAINNAME 1 + +/* Define to 1 if you have the `getdtablesize' function. */ +#define HAVE_GETDTABLESIZE 1 + +/* Define to 1 if you have the `getexecname' function. */ +/* #undef HAVE_GETEXECNAME */ + +/* Define to 1 if you have the `getmntinfo' function. */ +/* #undef HAVE_GETMNTINFO */ + +/* Define to 1 if you have the <getopt.h> header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have the `getsgnam' function. */ +#define HAVE_GETSGNAM 1 + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#define HAVE_GETTEXT 1 + +/* Define if you have the iconv() function and it works. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the `inotify_init' function. */ +#define HAVE_INOTIFY_INIT 1 + +/* Define to 1 if you have the `inotify_init1' function. */ +#define HAVE_INOTIFY_INIT1 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `ioperm' function. */ +#define HAVE_IOPERM 1 + +/* Define to 1 if you have the `iopl' function. */ +#define HAVE_IOPL 1 + +/* Define to 1 if you have the `jrand48' function. */ +#define HAVE_JRAND48 1 + +/* Define to 1 if you have the <langinfo.h> header file. */ +#define HAVE_LANGINFO_H 1 + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `audit' library (-laudit). */ +/* #undef HAVE_LIBAUDIT */ + +/* Define to 1 if you have the -lblkid. */ +#define HAVE_LIBBLKID 1 + +/* Define to 1 if you have the `cap-ng' library (-lcap-ng). */ +/* #undef HAVE_LIBCAP_NG */ + +/* Do we need -lcrypt? */ +#define HAVE_LIBCRYPT 1 + +/* Define to 1 if you have the `ncurses' library (-lncurses). */ +#define HAVE_LIBNCURSES 1 + +/* Define to 1 if you have the `ncursesw' library (-lncursesw). */ +/* #undef HAVE_LIBNCURSESW */ + +/* Define if SELinux is available */ +/* #undef HAVE_LIBSELINUX */ + +/* Define if libsystemd is available */ +/* #undef HAVE_LIBSYSTEMD */ + +/* Define to 1 if you have the `termcap' library (-ltermcap). */ +#define HAVE_LIBTERMCAP 1 + +/* Define to 1 if you have the `udev' library (-ludev). */ +/* #undef HAVE_LIBUDEV */ + +/* Define if libuser is available */ +/* #undef HAVE_LIBUSER */ + +/* Define to 1 if you have the `utempter' library (-lutempter). */ +/* #undef HAVE_LIBUTEMPTER */ + +/* Define to 1 if you have the `util' library (-lutil). */ +#define HAVE_LIBUTIL 1 + +/* Define to 1 if you have the -luuid. */ +#define HAVE_LIBUUID 1 + +/* Define to 1 if you have the <linux/blkpg.h> header file. */ +#define HAVE_LINUX_BLKPG_H 1 + +/* Define to 1 if you have the <linux/cdrom.h> header file. */ +#define HAVE_LINUX_CDROM_H 1 + +/* Define to 1 if you have the <linux/compiler.h> header file. */ +/* #undef HAVE_LINUX_COMPILER_H */ + +/* Define to 1 if you have the <linux/falloc.h> header file. */ +#define HAVE_LINUX_FALLOC_H 1 + +/* Define to 1 if you have the <linux/fd.h> header file. */ +#define HAVE_LINUX_FD_H 1 + +/* Define to 1 if you have the <linux/gsmmux.h> header file. */ +/* #undef HAVE_LINUX_GSMMUX_H */ + +/* Define to 1 if you have the <linux/major.h> header file. */ +#define HAVE_LINUX_MAJOR_H 1 + +/* Define to 1 if you have the <linux/raw.h> header file. */ +#define HAVE_LINUX_RAW_H 1 + +/* Define to 1 if you have the <linux/securebits.h> header file. */ +#define HAVE_LINUX_SECUREBITS_H 1 + +/* Define to 1 if you have the <linux/tiocl.h> header file. */ +#define HAVE_LINUX_TIOCL_H 1 + +/* Define to 1 if you have the <linux/version.h> header file. */ +#define HAVE_LINUX_VERSION_H 1 + +/* Define to 1 if you have the <linux/watchdog.h> header file. */ +#define HAVE_LINUX_WATCHDOG_H 1 + +/* Define to 1 if you have the `llseek' function. */ +#define HAVE_LLSEEK 1 + +/* Define to 1 if have llseek prototype */ +/* #undef HAVE_LLSEEK_PROTOTYPE */ + +/* Define to 1 if you have the <locale.h> header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if the system has the type `loff_t'. */ +#define HAVE_LOFF_T 1 + +/* Define to 1 if you have the `lseek64' function. */ +#define HAVE_LSEEK64 1 + +/* Define to 1 if have lseek64 prototype */ +#define HAVE_LSEEK64_PROTOTYPE 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mempcpy' function. */ +#define HAVE_MEMPCPY 1 + +/* Define to 1 if you have the <mntent.h> header file. */ +#define HAVE_MNTENT_H 1 + +/* Define to 1 if you have the `nanosleep' function. */ +#define HAVE_NANOSLEEP 1 + +/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */ +/* #undef HAVE_NCURSESW_NCURSES_H */ + +/* Define to 1 if you have the <ncurses.h> header file. */ +#define HAVE_NCURSES_H 1 + +/* Define to 1 if you have the <ncurses/ncurses.h> header file. */ +/* #undef HAVE_NCURSES_NCURSES_H */ + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the <net/if_dl.h> header file. */ +/* #undef HAVE_NET_IF_DL_H */ + +/* Define to 1 if you have the <net/if.h> header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have the `openat' function. */ +#define HAVE_OPENAT 1 + +/* Define to 1 if you have the `open_memstream' function. */ +#define HAVE_OPEN_MEMSTREAM 1 + +/* Define to 1 if you have the <paths.h> header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the `personality' function. */ +#define HAVE_PERSONALITY 1 + +/* Define to 1 if you have the `posix_fadvise' function. */ +#define HAVE_POSIX_FADVISE 1 + +/* Define to 1 if you have the `prctl' function. */ +#define HAVE_PRCTL 1 + +/* Define to 1 if you have the `prlimit' function. */ +#define HAVE_PRLIMIT 1 + +/* Define if program_invocation_short_name is defined */ +#define HAVE_PROGRAM_INVOCATION_SHORT_NAME 1 + +/* Define to 1 if you have the <pty.h> header file. */ +#define HAVE_PTY_H 1 + +/* Define to 1 if you have the `qsort_r' function. */ +#define HAVE_QSORT_R 1 + +/* Define if curses library has the resizeterm(). */ +/* #undef HAVE_RESIZETERM */ + +/* Define to 1 if you have the `rpmatch' function. */ +#define HAVE_RPMATCH 1 + +/* Define if struct sockaddr contains sa_len */ +/* #undef HAVE_SA_LEN */ + +/* Define to 1 if you have the `scandirat' function. */ +#define HAVE_SCANDIRAT 1 + +/* scanf %as modifier */ +/* #undef HAVE_SCANF_AS_MODIFIER */ + +/* scanf %ms modifier */ +#define HAVE_SCANF_MS_MODIFIER 1 + +/* Define to 1 if you have the `secure_getenv' function. */ +#define HAVE_SECURE_GETENV 1 + +/* Define to 1 if you have the `security_get_initial_context' function. */ +/* #undef HAVE_SECURITY_GET_INITIAL_CONTEXT */ + +/* Define to 1 if you have the <security/openpam.h> header file. */ +/* #undef HAVE_SECURITY_OPENPAM_H */ + +/* Define to 1 if you have the <security/pam_appl.h> header file. */ +/* #undef HAVE_SECURITY_PAM_APPL_H */ + +/* Define to 1 if you have the <security/pam_misc.h> header file. */ +/* #undef HAVE_SECURITY_PAM_MISC_H */ + +/* Define to 1 if you have the `setns' function. */ +#define HAVE_SETNS 1 + +/* Define to 1 if you have the `setresgid' function. */ +#define HAVE_SETRESGID 1 + +/* Define to 1 if you have the `setresuid' function. */ +#define HAVE_SETRESUID 1 + +/* Define to 1 if the system has the type `sighandler_t'. */ +#define HAVE_SIGHANDLER_T 1 + +/* Define to 1 if you have the `sigqueue' function. */ +#define HAVE_SIGQUEUE 1 + +/* Define to 1 if you have the <slang.h> header file. */ +/* #undef HAVE_SLANG_H */ + +/* Define to 1 if you have the <slang/slang.h> header file. */ +/* #undef HAVE_SLANG_SLANG_H */ + +/* Define to 1 if you have the <slang/slcurses.h> header file. */ +/* #undef HAVE_SLANG_SLCURSES_H */ + +/* Define to 1 if you have the <slcurses.h> header file. */ +/* #undef HAVE_SLCURSES_H */ + +/* Add SMACK support */ +/* #undef HAVE_SMACK */ + +/* Define to 1 if you have the `srandom' function. */ +#define HAVE_SRANDOM 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdio_ext.h> header file. */ +#define HAVE_STDIO_EXT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strnchr' function. */ +/* #undef HAVE_STRNCHR */ + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if have strsignal function prototype */ +#define HAVE_STRSIGNAL_DECL 1 + +/* Define to 1 if you have the `strtoull' function. */ +#define HAVE_STRTOULL 1 + +/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 + +/* Define to 1 if `c_line' is a member of `struct termios'. */ +#define HAVE_STRUCT_TERMIOS_C_LINE 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the `sysinfo' function. */ +#define HAVE_SYSINFO 1 + +/* Define to 1 if you have the <sys/disklabel.h> header file. */ +/* #undef HAVE_SYS_DISKLABEL_H */ + +/* Define to 1 if you have the <sys/disk.h> header file. */ +/* #undef HAVE_SYS_DISK_H */ + +/* Define to 1 if you have the <sys/endian.h> header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the <sys/file.h> header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the <sys/ioccom.h> header file. */ +/* #undef HAVE_SYS_IOCCOM_H */ + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the <sys/io.h> header file. */ +#define HAVE_SYS_IO_H 1 + +/* Define to 1 if you have the <sys/mkdev.h> header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#define HAVE_SYS_PRCTL_H 1 + +/* Define to 1 if you have the <sys/queue.h> header file. */ +#define HAVE_SYS_QUEUE_H 1 + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the <sys/sockio.h> header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/swap.h> header file. */ +#define HAVE_SYS_SWAP_H 1 + +/* Define to 1 if you have the <sys/syscall.h> header file. */ +#define HAVE_SYS_SYSCALL_H 1 + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the <sys/ttydefaults.h> header file. */ +#define HAVE_SYS_TTYDEFAULTS_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <sys/un.h> header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define to 1 if the target supports thread-local storage. */ +#define HAVE_TLS 1 + +/* Does struct tm have a field tm_gmtoff? */ +#define HAVE_TM_GMTOFF 1 + +/* Define to 1 if the system has the type `union semun'. */ +/* #undef HAVE_UNION_SEMUN */ + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unlinkat' function. */ +#define HAVE_UNLINKAT 1 + +/* Define to 1 if you have the `unshare' function. */ +#define HAVE_UNSHARE 1 + +/* Define to 1 if you have the `updwtmp' function. */ +#define HAVE_UPDWTMP 1 + +/* Define if curses library has the use_default_colors(). */ +/* #undef HAVE_USE_DEFAULT_COLORS */ + +/* Define to 1 if you have the `usleep' function. */ +#define HAVE_USLEEP 1 + +/* Define to 1 if you have the `utimensat' function. */ +#define HAVE_UTIMENSAT 1 + +/* Define to 1 if you want to use uuid daemon. */ +#define HAVE_UUIDD 1 + +/* Define to 1 if you have the `warn' function. */ +#define HAVE_WARN 1 + +/* Define to 1 if you have the `warnx' function. */ +#define HAVE_WARNX 1 + +/* Do we have wide character support? */ +#define HAVE_WIDECHAR 1 + +/* Define to 1 if you have the `__fpending' function. */ +#define HAVE___FPENDING 1 + +/* Define if __progname is defined */ +#define HAVE___PROGNAME 1 + +/* Define to 1 if you have the `__secure_getenv' function. */ +/* #undef HAVE___SECURE_GETENV */ + +/* libblkid date string */ +#define LIBBLKID_DATE "22-Jul-2014" + +/* libblkid version string */ +#define LIBBLKID_VERSION "2.25.0" + +/* libfdisk version string */ +#define LIBFDISK_VERSION "2.25.0" + +/* libmount version string */ +#define LIBMOUNT_VERSION "2.25.0" + +/* libsmartcols version string */ +#define LIBSMARTCOLS_VERSION "2.25.0" + +/* Should login chown /dev/vcsN? */ +/* #undef LOGIN_CHOWN_VCS */ + +/* Should login stat() the mailbox? */ +/* #undef LOGIN_STAT_MAIL */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Should chsh allow only shells in /etc/shells? */ +#define ONLY_LISTED_SHELLS 1 + +/* Name of package */ +#define PACKAGE "util-linux" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "kzak@redhat.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "util-linux" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "util-linux 2.25.590-bf6c" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "util-linux" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.kernel.org/pub/linux/utils/util-linux/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.25.590-bf6c" + +/* Should pg ring the bell on invalid keys? */ +#define PG_BELL 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Is swapon() declared with two parameters? */ +#define SWAPON_HAS_TWO_ARGS 1 + +/* Fallback syscall number for fallocate */ +/* #undef SYS_fallocate */ + +/* Fallback syscall number for ioprio_get */ +/* #undef SYS_ioprio_get */ + +/* Fallback syscall number for ioprio_set */ +/* #undef SYS_ioprio_set */ + +/* Fallback syscall number for pivot_root */ +/* #undef SYS_pivot_root */ + +/* Fallback syscall number for prlimit64 */ +/* #undef SYS_prlimit64 */ + +/* Fallback syscall number for sched_getaffinity */ +/* #undef SYS_sched_getaffinity */ + +/* Fallback syscall number for setns */ +/* #undef SYS_setns */ + +/* Fallback syscall number for unshare */ +/* #undef SYS_unshare */ + +/* Should sulogin use a emergency mount of /dev and /proc? */ +/* #undef USE_SULOGIN_EMERGENCY_MOUNT */ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Should wall and write be installed setgid tty? */ +#define USE_TTY_GROUP 1 + +/* Version number of package */ +#define VERSION "2.25.590-bf6c" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to empty if the keyword `volatile' does not work. Warning: valid + code using `volatile' can become incorrect without. Disable with care. */ +/* #undef volatile */ diff --git a/libblkid/cpuset.h b/libblkid/include/cpuset.h index f8948a984..f8948a984 100644 --- a/libblkid/cpuset.h +++ b/libblkid/include/cpuset.h diff --git a/libblkid/include/crc32.h b/libblkid/include/crc32.h new file mode 100644 index 000000000..26169109e --- /dev/null +++ b/libblkid/include/crc32.h @@ -0,0 +1,10 @@ +#ifndef UL_NG_CRC32_H +#define UL_NG_CRC32_H + +#include <sys/types.h> +#include <stdint.h> + +extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len); + +#endif + diff --git a/libblkid/include/crc64.h b/libblkid/include/crc64.h new file mode 100644 index 000000000..40475d56f --- /dev/null +++ b/libblkid/include/crc64.h @@ -0,0 +1,9 @@ +#ifndef UTIL_LINUX_CRC64_H +#define UTIL_LINUX_CRC64_H + +#include <sys/types.h> +#include <stdint.h> + +extern uint64_t crc64(uint64_t seed, const unsigned char *data, size_t len); + +#endif diff --git a/libblkid/include/debug.h b/libblkid/include/debug.h new file mode 100644 index 000000000..0229ab329 --- /dev/null +++ b/libblkid/include/debug.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2014 Karel Zak <kzak@redhat.com> + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef UTIL_LINUX_DEBUG_H +#define UTIL_LINUX_DEBUG_H + + +/* + * util-linux debug macros + * + * The debug stuff is based on <name>_debug_mask that controls what outputs is + * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable + * + * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set + * to the mask (this flag is required). The <PREFIX> is usually library API + * prefix (e.g. MNT_) or program name (e.g. CFDISK_) + * + * In the code is possible to use + * + * DBG(FOO, ul_debug("this is output for foo")); + * + * where for the FOO has to be defined <PREFIX>_DEBUG_FOO. + * + * It's possible to initialize the mask by comma delimited strings with + * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is + * necessary to define mask names array. This functionality is optional. + * + * It's stringly recommended to use UL_* macros to define/declare/use + * the debug stuff. + * + * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug + * or libmount/src/init.c: mnt_init_debug() for library debug + * + */ + +#include <stdarg.h> +#include <string.h> + +struct ul_debug_maskname { + const char *name; + int mask; + const char *help; +}; +#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }} +#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[] +#define UL_DEBUG_MASKNAMES(m) m ## _masknames + +#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask +#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) + +/* p - flag prefix, m - flag postfix */ +#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m + +/* l - library name, p - flag prefix, m - flag postfix, x - function */ +#define __UL_DBG(l, p, m, x) \ + do { \ + if ((p ## m) & l ## _debug_mask) { \ + fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \ + x; \ + } \ + } while (0) + +#define __UL_DBG_CALL(l, p, m, x) \ + do { \ + if ((p ## m) & l ## _debug_mask) { \ + x; \ + } \ + } while (0) + +#define __UL_DBG_FLUSH(l, p) \ + do { \ + if (l ## _debug_mask && \ + l ## _debug_mask != p ## INIT) { \ + fflush(stderr); \ + } \ + } while (0) + + +#define __UL_INIT_DEBUG(lib, pref, mask, env) \ + do { \ + if (lib ## _debug_mask & pref ## INIT) \ + ; \ + else if (!mask) { \ + char *str = getenv(# env); \ + if (str) \ + lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \ + } else \ + lib ## _debug_mask = mask; \ + lib ## _debug_mask |= pref ## INIT; \ + } while (0) + + +static inline void __attribute__ ((__format__ (__printf__, 1, 2))) +ul_debug(const char *mesg, ...) +{ + va_list ap; + va_start(ap, mesg); + vfprintf(stderr, mesg, ap); + va_end(ap); + fputc('\n', stderr); +} + +static inline void __attribute__ ((__format__ (__printf__, 2, 3))) +ul_debugobj(void *handler, const char *mesg, ...) +{ + va_list ap; + + if (handler) + fprintf(stderr, "[%p]: ", handler); + va_start(ap, mesg); + vfprintf(stderr, mesg, ap); + va_end(ap); + fputc('\n', stderr); +} + +static inline int ul_debug_parse_envmask( + const struct ul_debug_maskname flagnames[], + const char *mask) +{ + int res; + char *ptr; + + /* let's check for a numeric mask first */ + res = strtoul(mask, &ptr, 0); + + /* perhaps it's a comma-separated string? */ + if (ptr && *ptr && flagnames && flagnames[0].name) { + char *msbuf, *ms, *name; + res = 0; + + ms = msbuf = strdup(mask); + if (!ms) + return res; + + while ((name = strtok_r(ms, ",", &ptr))) { + const struct ul_debug_maskname *d; + ms = ptr; + + for (d = flagnames; d && d->name; d++) { + if (strcmp(name, d->name) == 0) { + res |= d->mask; + break; + } + } + /* nothing else we can do by OR-ing the mask */ + if (res == 0xffff) + break; + } + free(msbuf); + } else if (ptr && strcmp(ptr, "all") == 0) + res = 0xffff; + + return res; +} + +static inline void ul_debug_print_masks( + const char *env, + const struct ul_debug_maskname flagnames[]) +{ + const struct ul_debug_maskname *d; + + if (!flagnames) + return; + + fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n", + env); + for (d = flagnames; d && d->name; d++) { + if (!d->help) + continue; + fprintf(stderr, " %-8s [0x%04x] : %s\n", + d->name, d->mask, d->help); + } +} + +#endif /* UTIL_LINUX_DEBUG_H */ diff --git a/libblkid/env.h b/libblkid/include/env.h index a53d31027..a53d31027 100644 --- a/libblkid/env.h +++ b/libblkid/include/env.h diff --git a/libblkid/exec_shell.h b/libblkid/include/exec_shell.h index a2aa757de..a2aa757de 100644 --- a/libblkid/exec_shell.h +++ b/libblkid/include/exec_shell.h diff --git a/libblkid/exitcodes.h b/libblkid/include/exitcodes.h index 24ee12364..24ee12364 100644 --- a/libblkid/exitcodes.h +++ b/libblkid/include/exitcodes.h diff --git a/libblkid/include/fileutils.h b/libblkid/include/fileutils.h new file mode 100644 index 000000000..b4e0a4adb --- /dev/null +++ b/libblkid/include/fileutils.h @@ -0,0 +1,33 @@ +#ifndef UTIL_LINUX_FILEUTILS +#define UTIL_LINUX_FILEUTILS + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "c.h" + +extern int xmkstemp(char **tmpname, char *dir); + +static inline FILE *xfmkstemp(char **tmpname, char *dir) +{ + int fd; + FILE *ret; + + fd = xmkstemp(tmpname, dir); + if (fd == -1) + return NULL; + + if (!(ret = fdopen(fd, "w+"))) { + close(fd); + return NULL; + } + return ret; +} + +extern int get_fd_tabsize(void); + +extern int mkdir_p(const char *path, mode_t mode); +extern char *stripoff_last_component(char *path); + +#endif /* UTIL_LINUX_FILEUTILS */ diff --git a/libblkid/ismounted.h b/libblkid/include/ismounted.h index 57918cb3a..57918cb3a 100644 --- a/libblkid/ismounted.h +++ b/libblkid/include/ismounted.h diff --git a/libblkid/linux_reboot.h b/libblkid/include/linux_reboot.h index 9cebc67e8..9cebc67e8 100644 --- a/libblkid/linux_reboot.h +++ b/libblkid/include/linux_reboot.h diff --git a/libblkid/linux_version.h b/libblkid/include/linux_version.h index a6a1e99c7..a6a1e99c7 100644 --- a/libblkid/linux_version.h +++ b/libblkid/include/linux_version.h diff --git a/libblkid/include/list.h b/libblkid/include/list.h new file mode 100644 index 000000000..3c08aa5f2 --- /dev/null +++ b/libblkid/include/list.h @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 1999-2008 by Theodore Ts'o + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * (based on list.h from e2fsprogs) + * Merge sort based on kernel's implementation. + */ + +#ifndef UTIL_LINUX_LIST_H +#define UTIL_LINUX_LIST_H + +/* TODO: use AC_C_INLINE */ +#ifdef __GNUC__ +#define _INLINE_ static __inline__ +#else /* For Watcom C */ +#define _INLINE_ static inline +#endif + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +_INLINE_ void __list_add(struct list_head * add, + struct list_head * prev, + struct list_head * next) +{ + next->prev = add; + add->next = next; + add->prev = prev; + prev->next = add; +} + +/** + * list_add - add a new entry + * @add: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +_INLINE_ void list_add(struct list_head *add, struct list_head *head) +{ + __list_add(add, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @add: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +_INLINE_ void list_add_tail(struct list_head *add, struct list_head *head) +{ + __list_add(add, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +_INLINE_ void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * + * list_empty() on @entry does not return true after this, @entry is + * in an undefined state. + */ +_INLINE_ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +_INLINE_ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +_INLINE_ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_entry_is_last - tests whether is entry last in the list + * @entry: the entry to test. + * @head: the list to test. + */ +_INLINE_ int list_entry_is_last(struct list_head *entry, struct list_head *head) +{ + return head->prev == entry; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +_INLINE_ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) __extension__ ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +#define list_first_entry(head, type, member) \ + ((head) && (head)->next != (head) ? list_entry((head)->next, type, member) : NULL) + +#define list_last_entry(head, type, member) \ + ((head) && (head)->prev != (head) ? list_entry((head)->prev, type, member) : NULL) + +/** + * list_for_each - iterate over elements in a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_backwardly - iterate over elements in a list in reverse + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_backwardly(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over elements in a list, but don't dereference + * pos after the body is done (in case it is freed) + * @pos: the &struct list_head to use as a loop counter. + * @pnext: the &struct list_head to use as a pointer to the next item. + * @head: the head for your list (not included in iteration). + */ +#define list_for_each_safe(pos, pnext, head) \ + for (pos = (head)->next, pnext = pos->next; pos != (head); \ + pos = pnext, pnext = pos->next) + +#define MAX_LIST_LENGTH_BITS 20 + +/* + * Returns a list organized in an intermediate format suited + * to chaining of merge() calls: null-terminated, no reserved or + * sentinel head node, "prev" links not maintained. + */ +_INLINE_ struct list_head *merge(int (*cmp)(struct list_head *a, + struct list_head *b, + void *data), + void *data, + struct list_head *a, struct list_head *b) +{ + struct list_head head, *tail = &head; + + while (a && b) { + /* if equal, take 'a' -- important for sort stability */ + if ((*cmp)(a, b, data) <= 0) { + tail->next = a; + a = a->next; + } else { + tail->next = b; + b = b->next; + } + tail = tail->next; + } + tail->next = a ? a : b; + return head.next; +} + +/* + * Combine final list merge with restoration of standard doubly-linked + * list structure. This approach duplicates code from merge(), but + * runs faster than the tidier alternatives of either a separate final + * prev-link restoration pass, or maintaining the prev links + * throughout. + */ +_INLINE_ void merge_and_restore_back_links(int (*cmp)(struct list_head *a, + struct list_head *b, + void *data), + void *data, + struct list_head *head, + struct list_head *a, struct list_head *b) +{ + struct list_head *tail = head; + + while (a && b) { + /* if equal, take 'a' -- important for sort stability */ + if ((*cmp)(a, b, data) <= 0) { + tail->next = a; + a->prev = tail; + a = a->next; + } else { + tail->next = b; + b->prev = tail; + b = b->next; + } + tail = tail->next; + } + tail->next = a ? a : b; + + do { + /* + * In worst cases this loop may run many iterations. + * Continue callbacks to the client even though no + * element comparison is needed, so the client's cmp() + * routine can invoke cond_resched() periodically. + */ + (*cmp)(tail->next, tail->next, data); + + tail->next->prev = tail; + tail = tail->next; + } while (tail->next); + + tail->next = head; + head->prev = tail; +} + + +/** + * list_sort - sort a list + * @head: the list to sort + * @cmp: the elements comparison function + * + * This function implements "merge sort", which has O(nlog(n)) + * complexity. + * + * The comparison function @cmp must return a negative value if @a + * should sort before @b, and a positive value if @a should sort after + * @b. If @a and @b are equivalent, and their original relative + * ordering is to be preserved, @cmp must return 0. + */ +_INLINE_ void list_sort(struct list_head *head, + int (*cmp)(struct list_head *a, + struct list_head *b, + void *data), + void *data) +{ + struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists + -- last slot is a sentinel */ + size_t lev; /* index into part[] */ + size_t max_lev = 0; + struct list_head *list; + + if (list_empty(head)) + return; + + memset(part, 0, sizeof(part)); + + head->prev->next = NULL; + list = head->next; + + while (list) { + struct list_head *cur = list; + list = list->next; + cur->next = NULL; + + for (lev = 0; part[lev]; lev++) { + cur = merge(cmp, data, part[lev], cur); + part[lev] = NULL; + } + if (lev > max_lev) { + /* list passed to list_sort() too long for efficiency */ + if (lev >= ARRAY_SIZE(part) - 1) + lev--; + max_lev = lev; + } + part[lev] = cur; + } + + for (lev = 0; lev < max_lev; lev++) + if (part[lev]) + list = merge(cmp, data, part[lev], list); + + merge_and_restore_back_links(cmp, data, head, part[max_lev], list); +} + +#undef _INLINE_ + +#endif /* UTIL_LINUX_LIST_H */ diff --git a/libblkid/include/loopdev.h b/libblkid/include/loopdev.h new file mode 100644 index 000000000..573a5699d --- /dev/null +++ b/libblkid/include/loopdev.h @@ -0,0 +1,193 @@ +#ifndef UTIL_LINUX_LOOPDEV_H +#define UTIL_LINUX_LOOPDEV_H + +#include "sysfs.h" + +/* + * loop_info.lo_encrypt_type + */ +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 +#define LO_CRYPT_CRYPTOAPI 18 + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +/* + * Obsolete (kernel < 2.6) + * + * #define LOOP_SET_STATUS 0x4C02 + * #define LOOP_GET_STATUS 0x4C03 + */ +#define LOOP_SET_STATUS64 0x4C04 +#define LOOP_GET_STATUS64 0x4C05 +/* #define LOOP_CHANGE_FD 0x4C06 */ +#define LOOP_SET_CAPACITY 0x4C07 + +/* /dev/loop-control interface */ +#ifndef LOOP_CTL_ADD +# define LOOP_CTL_ADD 0x4C80 +# define LOOP_CTL_REMOVE 0x4C81 +# define LOOP_CTL_GET_FREE 0x4C82 +#endif + +/* + * loop_info.lo_flags + */ +enum { + LO_FLAGS_READ_ONLY = 1, + LO_FLAGS_USE_AOPS = 2, + LO_FLAGS_AUTOCLEAR = 4, /* kernel >= 2.6.25 */ + LO_FLAGS_PARTSCAN = 8, /* kernel >= 3.2 */ +}; + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +/* + * Linux LOOP_{SET,GET}_STATUS64 ioctl struct + */ +struct loop_info64 { + uint64_t lo_device; + uint64_t lo_inode; + uint64_t lo_rdevice; + uint64_t lo_offset; + uint64_t lo_sizelimit; /* bytes, 0 == max available */ + uint32_t lo_number; + uint32_t lo_encrypt_type; + uint32_t lo_encrypt_key_size; + uint32_t lo_flags; + uint8_t lo_file_name[LO_NAME_SIZE]; + uint8_t lo_crypt_name[LO_NAME_SIZE]; + uint8_t lo_encrypt_key[LO_KEY_SIZE]; + uint64_t lo_init[2]; +}; + +#define LOOPDEV_MAJOR 7 /* loop major number */ +#define LOOPDEV_DEFAULT_NNODES 8 /* default number of loop devices */ + +struct loopdev_iter { + FILE *proc; /* /proc/partitions */ + DIR *sysblock; /* /sys/block */ + int ncur; /* current position */ + int *minors; /* ary of minor numbers (when scan whole /dev) */ + int nminors; /* number of items in *minors */ + int ct_perm; /* count permission problems */ + int ct_succ; /* count number of detected devices */ + + unsigned int done:1; /* scanning done */ + unsigned int default_check:1;/* check first LOOPDEV_NLOOPS */ + int flags; /* LOOPITER_FL_* flags */ +}; + +enum { + LOOPITER_FL_FREE = (1 << 0), + LOOPITER_FL_USED = (1 << 1) +}; + +/* + * handler for work with loop devices + */ +struct loopdev_cxt { + char device[128]; /* device path (e.g. /dev/loop<N>) */ + char *filename; /* backing file for loopcxt_set_... */ + int fd; /* open(/dev/looo<N>) */ + int mode; /* fd mode O_{RDONLY,RDWR} */ + + int flags; /* LOOPDEV_FL_* flags */ + unsigned int has_info:1; /* .info contains data */ + unsigned int extra_check:1; /* unusual stuff for iterator */ + unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */ + unsigned int control_ok:1; /* /dev/loop-control success */ + + struct sysfs_cxt sysfs; /* pointer to /sys/dev/block/<maj:min>/ */ + struct loop_info64 info; /* for GET/SET ioctl */ + struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */ +}; + +#define UL_LOOPDEVCXT_EMPTY { .fd = -1, .sysfs = UL_SYSFSCXT_EMPTY } + +/* + * loopdev_cxt.flags + */ +enum { + LOOPDEV_FL_RDONLY = (1 << 0), /* open(/dev/loop) mode; default */ + LOOPDEV_FL_RDWR = (1 << 1), /* necessary for loop setup only */ + LOOPDEV_FL_OFFSET = (1 << 4), + LOOPDEV_FL_NOSYSFS = (1 << 5), + LOOPDEV_FL_NOIOCTL = (1 << 6), + LOOPDEV_FL_DEVSUBDIR = (1 << 7), + LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */ + LOOPDEV_FL_SIZELIMIT = (1 << 9) +}; + +/* + * High-level + */ +extern int loopmod_supports_partscan(void); + +extern int is_loopdev(const char *device); +extern int loopdev_is_autoclear(const char *device); + +extern char *loopdev_get_backing_file(const char *device); +extern int loopdev_is_used(const char *device, const char *filename, + uint64_t offset, int flags); +extern char *loopdev_find_by_backing_file(const char *filename, + uint64_t offset, int flags); +extern int loopcxt_find_unused(struct loopdev_cxt *lc); +extern int loopdev_delete(const char *device); +extern int loopdev_count_by_backing_file(const char *filename, char **loopdev); + +/* + * Low-level + */ +extern int loopcxt_init(struct loopdev_cxt *lc, int flags) + __attribute__ ((warn_unused_result)); +extern void loopcxt_deinit(struct loopdev_cxt *lc); + +extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) + __attribute__ ((warn_unused_result)); +extern int loopcxt_has_device(struct loopdev_cxt *lc); +extern int loopcxt_add_device(struct loopdev_cxt *lc); +extern char *loopcxt_strdup_device(struct loopdev_cxt *lc); +extern const char *loopcxt_get_device(struct loopdev_cxt *lc); +extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc); +extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc); + +extern int loopcxt_get_fd(struct loopdev_cxt *lc); +extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode); + +extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags); +extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc); +extern int loopcxt_next(struct loopdev_cxt *lc); + +extern int loopcxt_setup_device(struct loopdev_cxt *lc); +extern int loopcxt_delete_device(struct loopdev_cxt *lc); +extern int loopcxt_set_capacity(struct loopdev_cxt *lc); + +int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset); +int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit); +int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags); +int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename); + +extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc); +extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno); +extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino); +extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); +extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size); +extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type); +extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc); +extern int loopcxt_is_autoclear(struct loopdev_cxt *lc); +extern int loopcxt_is_readonly(struct loopdev_cxt *lc); +extern int loopcxt_is_partscan(struct loopdev_cxt *lc); +extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, + const char *filename, + uint64_t offset, int flags); + +extern int loopcxt_is_used(struct loopdev_cxt *lc, + struct stat *st, + const char *backing_file, + uint64_t offset, + int flags); + +#endif /* UTIL_LINUX_LOOPDEV_H */ diff --git a/libblkid/mangle.h b/libblkid/include/mangle.h index ec492b556..ec492b556 100644 --- a/libblkid/mangle.h +++ b/libblkid/include/mangle.h diff --git a/libblkid/match.h b/libblkid/include/match.h index 94440c22e..94440c22e 100644 --- a/libblkid/match.h +++ b/libblkid/include/match.h diff --git a/libblkid/include/mbsalign.h b/libblkid/include/mbsalign.h new file mode 100644 index 000000000..5eaf606e5 --- /dev/null +++ b/libblkid/include/mbsalign.h @@ -0,0 +1,56 @@ +/* Align/Truncate a string in a given screen width + Copyright (C) 2009-2010 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com> + + This program 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 program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef UTIL_LINUX_MBSALIGN_H +# define UTIL_LINUX_MBSALIGN_H +# include <stddef.h> + +typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t; + +enum { + /* Use unibyte mode for invalid multibyte strings or + or when heap memory is exhausted. */ + MBA_UNIBYTE_FALLBACK = 0x0001, + +#if 0 /* Other possible options. */ + /* Skip invalid multibyte chars rather than failing */ + MBA_IGNORE_INVALID = 0x0002, + + /* Align multibyte strings using "figure space" (\u2007) */ + MBA_USE_FIGURE_SPACE = 0x0004, + + /* Don't add any padding */ + MBA_TRUNCATE_ONLY = 0x0008, + + /* Don't truncate */ + MBA_PAD_ONLY = 0x0010, +#endif +}; + +extern size_t mbs_truncate(char *str, size_t *width); + +extern size_t mbsalign (const char *src, char *dest, + size_t dest_size, size_t *width, + mbs_align_t align, int flags); + +extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz); +extern size_t mbs_safe_width(const char *s); + +extern char *mbs_safe_encode(const char *s, size_t *width); +extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf); +extern size_t mbs_safe_encode_size(size_t bytes); + +#endif /* UTIL_LINUX_MBSALIGN_H */ diff --git a/libblkid/md5.h b/libblkid/include/md5.h index d997e379d..d997e379d 100644 --- a/libblkid/md5.h +++ b/libblkid/include/md5.h diff --git a/libblkid/include/minix.h b/libblkid/include/minix.h new file mode 100644 index 000000000..f28991ce9 --- /dev/null +++ b/libblkid/include/minix.h @@ -0,0 +1,85 @@ +#ifndef UTIL_LINUX_MINIX_H +#define UTIL_LINUX_MINIX_H + +#include <stdint.h> + +struct minix_inode { + uint16_t i_mode; + uint16_t i_uid; + uint32_t i_size; + uint32_t i_time; + uint8_t i_gid; + uint8_t i_nlinks; + uint16_t i_zone[9]; +}; + +struct minix2_inode { + uint16_t i_mode; + uint16_t i_nlinks; + uint16_t i_uid; + uint16_t i_gid; + uint32_t i_size; + uint32_t i_atime; + uint32_t i_mtime; + uint32_t i_ctime; + uint32_t i_zone[10]; +}; + +struct minix_super_block { + uint16_t s_ninodes; + uint16_t s_nzones; + uint16_t s_imap_blocks; + uint16_t s_zmap_blocks; + uint16_t s_firstdatazone; + uint16_t s_log_zone_size; + uint32_t s_max_size; + uint16_t s_magic; + uint16_t s_state; + uint32_t s_zones; +}; + +/* V3 minix super-block data on disk */ +struct minix3_super_block { + uint32_t s_ninodes; + uint16_t s_pad0; + uint16_t s_imap_blocks; + uint16_t s_zmap_blocks; + uint16_t s_firstdatazone; + uint16_t s_log_zone_size; + uint16_t s_pad1; + uint32_t s_max_size; + uint32_t s_zones; + uint16_t s_magic; + uint16_t s_pad2; + uint16_t s_blocksize; + uint8_t s_disk_version; +}; + +/* + * Minix subpartitions are always within primary dos partition. + */ +#define MINIX_MAXPARTITIONS 4 + +#define MINIX_BLOCK_SIZE_BITS 10 +#define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SIZE_BITS) + +#define MINIX_NAME_MAX 255 /* # chars in a file name */ +#define MINIX_MAX_INODES 65535 + +#define MINIX_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +/* minix_super_block.s_state */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + + +#define MINIX_SUPER_MAGIC 0x137F /* minix V1 fs, 14 char names */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix V1 fs, 30 char names */ + +#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs, 14 char names */ +#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ + +#define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs (60 char names) */ + +#endif /* UTIL_LINUX_MINIX_H */ diff --git a/libblkid/include/monotonic.h b/libblkid/include/monotonic.h new file mode 100644 index 000000000..f3b03d3d0 --- /dev/null +++ b/libblkid/include/monotonic.h @@ -0,0 +1,11 @@ +#ifndef UTIL_LINUX_BOOTTIME_H +#define UTIL_LINUX_BOOTTIME_H + +/* + * Uses clock_gettime() that requires $CLOCKGETTIME_LIBS + */ +extern int get_boot_time(struct timeval *boot_time); + +extern int gettime_monotonic(struct timeval *tv); + +#endif /* UTIL_LINUX_BOOTTIME_H */ diff --git a/libblkid/include/namespace.h b/libblkid/include/namespace.h new file mode 100644 index 000000000..ea231cacb --- /dev/null +++ b/libblkid/include/namespace.h @@ -0,0 +1,44 @@ +/* Compat code so unshare and setns can be used with older libcs */ +#ifndef UTIL_LINUX_NAMESPACE_H +# define UTIL_LINUX_NAMESPACE_H + +# include <sched.h> + +# ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +# endif +# ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +# endif +# ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +# endif +# ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +# endif +# ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +# endif +# ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +# endif + +# if !defined(HAVE_UNSHARE) || !defined(HAVE_SETNS) +# include <sys/syscall.h> +# endif + +# if !defined(HAVE_UNSHARE) && defined(SYS_unshare) +static inline int unshare(int flags) +{ + return syscall(SYS_unshare, flags); +} +# endif + +# if !defined(HAVE_SETNS) && defined(SYS_setns) +static inline int setns(int fd, int nstype) +{ + return syscall(SYS_setns, fd, nstype); +} +# endif + +#endif /* UTIL_LINUX_NAMESPACE_H */ diff --git a/libblkid/nls.h b/libblkid/include/nls.h index 3eabfe63b..3eabfe63b 100644 --- a/libblkid/nls.h +++ b/libblkid/include/nls.h diff --git a/libblkid/include/optutils.h b/libblkid/include/optutils.h new file mode 100644 index 000000000..99ad7e4b4 --- /dev/null +++ b/libblkid/include/optutils.h @@ -0,0 +1,103 @@ +#ifndef UTIL_LINUX_OPTUTILS_H +#define UTIL_LINUX_OPTUTILS_H + +#include "c.h" +#include "nls.h" + +static inline const char *option_to_longopt(int c, const struct option *opts) +{ + const struct option *o; + + for (o = opts; o->name; o++) + if (o->val == c) + return o->name; + return NULL; +} + +#ifndef OPTUTILS_EXIT_CODE +# define OPTUTILS_EXIT_CODE EXIT_FAILURE +#endif + +/* + * Check collisions between options. + * + * The conflicts between options are described in ul_excl_t array. The + * array contains groups of mutually exclusive options. For example + * + * static const ul_excl_t excl[] = { + * { 'Z','b','c' }, // first group + * { 'b','x' }, // second group + * { 0 } + * }; + * + * int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; + * + * while ((c = getopt_long(argc, argv, "Zbcx", longopts, NULL)) != -1) { + * + * err_exclusive_options(c, longopts, excl, excl_st); + * + * switch (c) { + * case 'Z': + * .... + * } + * } + * + * The array excl[] defines two groups of the mutually exclusive options. The + * option '-b' is in the both groups. + * + * Note that the options in the group have to be in ASCII order (ABC..abc..) and + * groups have to be also in ASCII order. + * + * The maximal number of the options in the group is 15 (size of the array is + * 16, last is zero). + * + * The current status of options is stored in excl_st array. The size of the array + * must be the same as number of the groups in the ul_excl_t array. + * + * If you're unsure then see sys-utils/mount.c or misc-utils/findmnt.c. + */ +#define UL_EXCL_STATUS_INIT { 0 } +typedef int ul_excl_t[16]; + +static inline void err_exclusive_options( + int c, + const struct option *opts, + const ul_excl_t *excl, + int *status) +{ + int e; + + for (e = 0; excl[e][0] && excl[e][0] <= c; e++) { + const int *op = excl[e]; + + for (; *op && *op <= c; op++) { + if (*op != c) + continue; + if (status[e] == 0) + status[e] = c; + else if (status[e] != c) { + size_t ct = 0; + + fprintf(stderr, _("%s: these options are " + "mutually exclusive:"), + program_invocation_short_name); + + for (op = excl[e]; + ct + 1 < ARRAY_SIZE(excl[0]) && *op; + op++, ct++) { + const char *n = option_to_longopt(*op, opts); + if (n) + fprintf(stderr, " --%s", n); + else + fprintf(stderr, " -%c", *op); + } + fputc('\n', stderr); + exit(OPTUTILS_EXIT_CODE); + } + break; + } + } +} + +#endif + diff --git a/libblkid/pager.h b/libblkid/include/pager.h index 9ca42eb35..9ca42eb35 100644 --- a/libblkid/pager.h +++ b/libblkid/include/pager.h diff --git a/libblkid/include/pamfail.h b/libblkid/include/pamfail.h new file mode 100644 index 000000000..bb83b9404 --- /dev/null +++ b/libblkid/include/pamfail.h @@ -0,0 +1,26 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#ifndef UTIL_LINUX_PAMFAIL_H +#include <security/pam_appl.h> +#ifdef HAVE_SECURITY_PAM_MISC_H +# include <security/pam_misc.h> +#elif defined(HAVE_SECURITY_OPENPAM_H) +# include <security/openpam.h> +#endif +#include "c.h" + +static inline int +pam_fail_check(pam_handle_t *pamh, int retcode) +{ + if (retcode == PAM_SUCCESS) + return 0; + warnx("%s", pam_strerror(pamh, retcode)); + pam_end(pamh, retcode); + return 1; +} + +#endif /* UTIL_LINUX_PAMFAIL_H */ diff --git a/libblkid/include/path.h b/libblkid/include/path.h new file mode 100644 index 000000000..45da692f8 --- /dev/null +++ b/libblkid/include/path.h @@ -0,0 +1,33 @@ +#ifndef UTIL_LINUX_PATH_H +#define UTIL_LINUX_PATH_H + +#include <stdio.h> +#include <stdint.h> + +extern char *path_strdup(const char *path, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); +extern FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern void path_read_str(char *result, size_t len, const char *path, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern int path_write_str(const char *str, const char *path, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern int path_read_s32(const char *path, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); +extern uint64_t path_read_u64(const char *path, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +extern int path_exist(const char *path, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); + +#ifdef HAVE_CPU_SET_T +# include "cpuset.h" + +extern cpu_set_t *path_read_cpuset(int, const char *path, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern cpu_set_t *path_read_cpulist(int, const char *path, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void path_set_prefix(const char *); +#endif /* HAVE_CPU_SET_T */ + +#endif /* UTIL_LINUX_PATH_H */ diff --git a/libblkid/include/pathnames.h b/libblkid/include/pathnames.h new file mode 100644 index 000000000..0d21b980b --- /dev/null +++ b/libblkid/include/pathnames.h @@ -0,0 +1,196 @@ +/* + * Vaguely based on + * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 + * This code is in the public domain. + */ +#ifndef PATHNAMES_H +#define PATHNAMES_H + +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#ifndef __STDC__ +# error "we need an ANSI compiler" +#endif + +/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */ +#define PATH_DELETED_SUFFIX "\\040(deleted)" +#define PATH_DELETED_SUFFIX_SZ (sizeof(PATH_DELETED_SUFFIX) - 1) + +/* DEFPATHs from <paths.h> don't include /usr/local */ +#undef _PATH_DEFPATH +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" + +#undef _PATH_DEFPATH_ROOT +#define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" + +#define _PATH_SECURETTY "/etc/securetty" +#define _PATH_WTMPLOCK "/etc/wtmplock" + +#define _PATH_HUSHLOGIN ".hushlogin" +#define _PATH_HUSHLOGINS "/etc/hushlogins" + +#define _PATH_NOLOGIN_TXT "/etc/nologin.txt" + +#ifndef _PATH_MAILDIR +#define _PATH_MAILDIR "/var/spool/mail" +#endif +#define _PATH_MOTDFILE "/etc/motd" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_VAR_NOLOGIN "/var/run/nologin" + +#define _PATH_LOGIN "/bin/login" +#define _PATH_INITTAB "/etc/inittab" +#define _PATH_RC "/etc/rc" +#define _PATH_REBOOT "/sbin/reboot" +#define _PATH_SHUTDOWN "/sbin/shutdown" +#define _PATH_SINGLE "/etc/singleboot" +#define _PATH_SHUTDOWN_CONF "/etc/shutdown.conf" + +#define _PATH_SECURE "/etc/securesingle" +#define _PATH_USERTTY "/etc/usertty" + +#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d" +#define _PATH_TERMCOLORS_DIR "/etc/" _PATH_TERMCOLORS_DIRNAME + +/* used in login-utils/shutdown.c */ + +/* used in login-utils/setpwnam.h and login-utils/islocal.c */ +#define _PATH_PASSWD "/etc/passwd" + +/* used in login-utils/newgrp and login-utils/setpwnam.h*/ +#define _PATH_GSHADOW "/etc/gshadow" + +/* used in login-utils/setpwnam.h */ +#define _PATH_GROUP "/etc/group" +#define _PATH_SHADOW_PASSWD "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" + +/* used in term-utils/agetty.c */ +#define _PATH_ISSUE "/etc/issue" +#define _PATH_OS_RELEASE "/etc/os-release" +#define _PATH_NUMLOCK_ON _PATH_LOCALSTATEDIR "/numlock-on" + +#define _PATH_LOGINDEFS "/etc/login.defs" + +/* used in misc-utils/look.c */ +#define _PATH_WORDS "/usr/share/dict/words" +#define _PATH_WORDS_ALT "/usr/share/dict/web2" + +/* mount paths */ +#define _PATH_UMOUNT "/bin/umount" + +#define _PATH_FILESYSTEMS "/etc/filesystems" +#define _PATH_PROC_SWAPS "/proc/swaps" +#define _PATH_PROC_FILESYSTEMS "/proc/filesystems" +#define _PATH_PROC_MOUNTS "/proc/mounts" +#define _PATH_PROC_PARTITIONS "/proc/partitions" +#define _PATH_PROC_DEVICES "/proc/devices" +#define _PATH_PROC_MOUNTINFO "/proc/self/mountinfo" +#define _PATH_PROC_LOCKS "/proc/locks" +#define _PATH_PROC_CDROMINFO "/proc/sys/dev/cdrom/info" + +#define _PATH_PROC_UIDMAP "/proc/self/uid_map" +#define _PATH_PROC_GIDMAP "/proc/self/gid_map" + +#define _PATH_PROC_ATTR_CURRENT "/proc/self/attr/current" +#define _PATH_PROC_ATTR_EXEC "/proc/self/attr/exec" +#define _PATH_PROC_CAPLASTCAP "/proc/sys/kernel/cap_last_cap" + + +#define _PATH_SYS_BLOCK "/sys/block" +#define _PATH_SYS_DEVBLOCK "/sys/dev/block" +#define _PATH_SYS_CLASS "/sys/class" +#define _PATH_SYS_SCSI "/sys/bus/scsi" + +#define _PATH_SYS_SELINUX "/sys/fs/selinux" +#define _PATH_SYS_APPARMOR "/sys/kernel/security/apparmor" + +#ifndef _PATH_MOUNTED +# ifdef MOUNTED /* deprecated */ +# define _PATH_MOUNTED MOUNTED +# else +# define _PATH_MOUNTED "/etc/mtab" +# endif +#endif + +#ifndef _PATH_MNTTAB +# ifdef MNTTAB /* deprecated */ +# define _PATH_MNTTAB MNTTAB +# else +# define _PATH_MNTTAB "/etc/fstab" +# endif +#endif + +#define _PATH_MNTTAB_DIR _PATH_MNTTAB ".d" + +#define _PATH_MOUNTED_LOCK _PATH_MOUNTED "~" +#define _PATH_MOUNTED_TMP _PATH_MOUNTED ".tmp" + +#ifndef _PATH_DEV + /* + * The tailing '/' in _PATH_DEV is there for compatibility with libc. + */ +# define _PATH_DEV "/dev/" +#endif + +#define _PATH_DEV_MEM "/dev/mem" + +#define _PATH_DEV_LOOP "/dev/loop" +#define _PATH_DEV_LOOPCTL "/dev/loop-control" +#define _PATH_DEV_TTY "/dev/tty" + + +/* udev paths */ +#define _PATH_DEV_BYLABEL "/dev/disk/by-label" +#define _PATH_DEV_BYUUID "/dev/disk/by-uuid" +#define _PATH_DEV_BYID "/dev/disk/by-id" +#define _PATH_DEV_BYPATH "/dev/disk/by-path" +#define _PATH_DEV_BYPARTLABEL "/dev/disk/by-partlabel" +#define _PATH_DEV_BYPARTUUID "/dev/disk/by-partuuid" + +/* hwclock paths */ +#ifdef CONFIG_ADJTIME_PATH +# define _PATH_ADJTIME CONFIG_ADJTIME_PATH +#else +# define _PATH_ADJTIME "/etc/adjtime" +#endif + +#define _PATH_LASTDATE "/var/lib/lastdate" +#ifdef __ia64__ +# define _PATH_RTC_DEV "/dev/efirtc" +#else +# define _PATH_RTC_DEV "/dev/rtc" +#endif + +#ifndef _PATH_BTMP +#define _PATH_BTMP "/var/log/btmp" +#endif + +/* raw paths*/ +#define _PATH_RAWDEVDIR "/dev/raw/" +#define _PATH_RAWDEVCTL _PATH_RAWDEVDIR "rawctl" +/* deprecated */ +#define _PATH_RAWDEVCTL_OLD "/dev/rawctl" + +/* wdctl path */ +#define _PATH_WATCHDOG_DEV "/dev/watchdog" + +/* ipc paths */ +#define _PATH_PROC_SYSV_MSG "/proc/sysvipc/msg" +#define _PATH_PROC_SYSV_SEM "/proc/sysvipc/sem" +#define _PATH_PROC_SYSV_SHM "/proc/sysvipc/shm" +#define _PATH_PROC_IPC_MSGMAX "/proc/sys/kernel/msgmax" +#define _PATH_PROC_IPC_MSGMNB "/proc/sys/kernel/msgmnb" +#define _PATH_PROC_IPC_MSGMNI "/proc/sys/kernel/msgmni" +#define _PATH_PROC_IPC_SEM "/proc/sys/kernel/sem" +#define _PATH_PROC_IPC_SHMALL "/proc/sys/kernel/shmall" +#define _PATH_PROC_IPC_SHMMAX "/proc/sys/kernel/shmmax" +#define _PATH_PROC_IPC_SHMMNI "/proc/sys/kernel/shmmni" + +/* kernel command line */ +#define _PATH_PROC_CMDLINE "/proc/cmdline" + +#endif /* PATHNAMES_H */ + diff --git a/libblkid/include/procutils.h b/libblkid/include/procutils.h new file mode 100644 index 000000000..14b766cb7 --- /dev/null +++ b/libblkid/include/procutils.h @@ -0,0 +1,32 @@ +#ifndef UTIL_LINUX_PROCUTILS +#define UTIL_LINUX_PROCUTILS + +#include <dirent.h> + +struct proc_tasks { + DIR *dir; +}; + +extern struct proc_tasks *proc_open_tasks(pid_t pid); +extern void proc_close_tasks(struct proc_tasks *tasks); +extern int proc_next_tid(struct proc_tasks *tasks, pid_t *tid); + +struct proc_processes { + DIR *dir; + + const char *fltr_name; + uid_t fltr_uid; + + unsigned int has_fltr_name : 1, + has_fltr_uid : 1; +}; + +extern struct proc_processes *proc_open_processes(void); +extern void proc_close_processes(struct proc_processes *ps); + +extern void proc_processes_filter_by_name(struct proc_processes *ps, const char *name); +extern void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid); +extern int proc_next_pid(struct proc_processes *ps, pid_t *pid); + + +#endif /* UTIL_LINUX_PROCUTILS */ diff --git a/libblkid/include/pt-bsd.h b/libblkid/include/pt-bsd.h new file mode 100644 index 000000000..9bf47a576 --- /dev/null +++ b/libblkid/include/pt-bsd.h @@ -0,0 +1,156 @@ +#ifndef UTIL_LINUX_PT_BSD_H +#define UTIL_LINUX_PT_BSD_H + +#define BSD_MAXPARTITIONS 16 +#define BSD_FS_UNUSED 0 + +#ifndef BSD_DISKMAGIC +# define BSD_DISKMAGIC ((uint32_t) 0x82564557) +#endif + +#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" + +#if defined (__alpha__) || defined (__powerpc__) || \ + defined (__ia64__) || defined (__hppa__) +# define BSD_LABELSECTOR 0 +# define BSD_LABELOFFSET 64 +#else +# define BSD_LABELSECTOR 1 +# define BSD_LABELOFFSET 0 +#endif + +#define BSD_BBSIZE 8192 /* size of boot area, with label */ +#define BSD_SBSIZE 8192 /* max size of fs superblock */ + +struct bsd_disklabel { + uint32_t d_magic; /* the magic number */ + int16_t d_type; /* drive type */ + int16_t d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + char d_packname[16]; /* pack identifier */ + + /* disk geometry: */ + uint32_t d_secsize; /* # of bytes per sector */ + uint32_t d_nsectors; /* # of data sectors per track */ + uint32_t d_ntracks; /* # of tracks per cylinder */ + uint32_t d_ncylinders; /* # of data cylinders per unit */ + uint32_t d_secpercyl; /* # of data sectors per cylinder */ + uint32_t d_secperunit; /* # of data sectors per unit */ + + /* + * Spares (bad sector replacements) below + * are not counted in d_nsectors or d_secpercyl. + * Spare sectors are assumed to be physical sectors + * which occupy space at the end of each track and/or cylinder. + */ + uint16_t d_sparespertrack; /* # of spare sectors per track */ + uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ + + /* + * Alternate cylinders include maintenance, replacement, + * configuration description areas, etc. + */ + uint32_t d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the formatter + * or controller when formatting. When interleaving is in use, + * logically adjacent sectors are not physically contiguous, + * but instead are separated by some number of sectors. + * It is specified as the ratio of physical sectors traversed + * per logical sector. Thus an interleave of 1:1 implies contiguous + * layout, while 2:1 implies that logical sector 0 is separated + * by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N + * relative to sector 0 on track N-1 on the same cylinder. + * Finally, d_cylskew is the offset of sector 0 on cylinder N + * relative to sector 0 on cylinder N-1. + */ + uint16_t d_rpm; /* rotational speed */ + uint16_t d_interleave; /* hardware sector interleave */ + uint16_t d_trackskew; /* sector 0 skew, per track */ + uint16_t d_cylskew; /* sector 0 skew, per cylinder */ + uint32_t d_headswitch; /* head switch time, usec */ + uint32_t d_trkseek; /* track-to-track seek, usec */ + uint32_t d_flags; /* generic flags */ + uint32_t d_drivedata[5]; /* drive-type specific information */ + uint32_t d_spare[5]; /* reserved for future use */ + uint32_t d_magic2; /* the magic number (again) */ + uint16_t d_checksum; /* xor of data incl. partitions */ + + /* filesystem and partition information: */ + uint16_t d_npartitions; /* number of partitions in following */ + uint32_t d_bbsize; /* size of boot area at sn0, bytes */ + uint32_t d_sbsize; /* max size of fs superblock, bytes */ + + struct bsd_partition { /* the partition table */ + uint32_t p_size; /* number of sectors in partition */ + uint32_t p_offset; /* starting sector */ + uint32_t p_fsize; /* filesystem basic fragment size */ + uint8_t p_fstype; /* filesystem type, see below */ + uint8_t p_frag; /* filesystem fragments per block */ + uint16_t p_cpg; /* filesystem cylinders per group */ + } __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +} __attribute__((packed)); + + +/* d_type values: */ +#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define BSD_DTYPE_MSCP 2 /* MSCP */ +#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define BSD_DTYPE_SCSI 4 /* SCSI */ +#define BSD_DTYPE_ESDI 5 /* ESDI interface */ +#define BSD_DTYPE_ST506 6 /* ST506 etc. */ +#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ +#define BSD_DTYPE_FLOPPY 10 /* floppy */ + +/* d_subtype values: */ +#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ +#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ +#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ + +/* + * Filesystem type and version. + * Used to interpret other filesystem-specific + * per-partition information. + */ +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ +#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ +#define BSD_FS_ISOFS BSD_FS_ISO9660 +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ +#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */ + +/* this is annoying, but it's also the way it is :-( */ +#ifdef __alpha__ +#define BSD_FS_EXT2 8 /* ext2 file system */ +#else +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#endif + +/* + * flags shared by various drives: + */ +#define BSD_D_REMOVABLE 0x01 /* removable media */ +#define BSD_D_ECC 0x02 /* supports ECC */ +#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ +#define BSD_D_RAMDISK 0x08 /* disk emulator */ +#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ +#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ + +#endif /* UTIL_LINUX_PT_BSD_H */ diff --git a/libblkid/include/pt-mbr-partnames.h b/libblkid/include/pt-mbr-partnames.h new file mode 100644 index 000000000..282adba91 --- /dev/null +++ b/libblkid/include/pt-mbr-partnames.h @@ -0,0 +1,105 @@ + {0x00, N_("Empty")}, + {0x01, N_("FAT12")}, + {0x02, N_("XENIX root")}, + {0x03, N_("XENIX usr")}, + {0x04, N_("FAT16 <32M")}, + {0x05, N_("Extended")}, /* DOS 3.3+ extended partition */ + {0x06, N_("FAT16")}, /* DOS 16-bit >=32M */ + {0x07, N_("HPFS/NTFS/exFAT")}, /* OS/2 IFS, eg, HPFS or NTFS or QNX or exFAT */ + {0x08, N_("AIX")}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ + {0x09, N_("AIX bootable")}, /* AIX data or Coherent */ + {0x0a, N_("OS/2 Boot Manager")},/* OS/2 Boot Manager */ + {0x0b, N_("W95 FAT32")}, + {0x0c, N_("W95 FAT32 (LBA)")},/* LBA really is `Extended Int 13h' */ + {0x0e, N_("W95 FAT16 (LBA)")}, + {0x0f, N_("W95 Ext'd (LBA)")}, + {0x10, N_("OPUS")}, + {0x11, N_("Hidden FAT12")}, + {0x12, N_("Compaq diagnostics")}, + {0x14, N_("Hidden FAT16 <32M")}, + {0x16, N_("Hidden FAT16")}, + {0x17, N_("Hidden HPFS/NTFS")}, + {0x18, N_("AST SmartSleep")}, + {0x1b, N_("Hidden W95 FAT32")}, + {0x1c, N_("Hidden W95 FAT32 (LBA)")}, + {0x1e, N_("Hidden W95 FAT16 (LBA)")}, + {0x24, N_("NEC DOS")}, + {0x27, N_("Hidden NTFS WinRE")}, + {0x39, N_("Plan 9")}, + {0x3c, N_("PartitionMagic recovery")}, + {0x40, N_("Venix 80286")}, + {0x41, N_("PPC PReP Boot")}, + {0x42, N_("SFS")}, + {0x4d, N_("QNX4.x")}, + {0x4e, N_("QNX4.x 2nd part")}, + {0x4f, N_("QNX4.x 3rd part")}, + {0x50, N_("OnTrack DM")}, + {0x51, N_("OnTrack DM6 Aux1")}, /* (or Novell) */ + {0x52, N_("CP/M")}, /* CP/M or Microport SysV/AT */ + {0x53, N_("OnTrack DM6 Aux3")}, + {0x54, N_("OnTrackDM6")}, + {0x55, N_("EZ-Drive")}, + {0x56, N_("Golden Bow")}, + {0x5c, N_("Priam Edisk")}, + {0x61, N_("SpeedStor")}, + {0x63, N_("GNU HURD or SysV")}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ + {0x64, N_("Novell Netware 286")}, + {0x65, N_("Novell Netware 386")}, + {0x70, N_("DiskSecure Multi-Boot")}, + {0x75, N_("PC/IX")}, + {0x80, N_("Old Minix")}, /* Minix 1.4a and earlier */ + {0x81, N_("Minix / old Linux")},/* Minix 1.4b and later */ + {0x82, N_("Linux swap / Solaris")}, + {0x83, N_("Linux")}, + {0x84, N_("OS/2 hidden C: drive")}, + {0x85, N_("Linux extended")}, + {0x86, N_("NTFS volume set")}, + {0x87, N_("NTFS volume set")}, + {0x88, N_("Linux plaintext")}, + {0x8e, N_("Linux LVM")}, + {0x93, N_("Amoeba")}, + {0x94, N_("Amoeba BBT")}, /* (bad block table) */ + {0x9f, N_("BSD/OS")}, /* BSDI */ + {0xa0, N_("IBM Thinkpad hibernation")}, + {0xa5, N_("FreeBSD")}, /* various BSD flavours */ + {0xa6, N_("OpenBSD")}, + {0xa7, N_("NeXTSTEP")}, + {0xa8, N_("Darwin UFS")}, + {0xa9, N_("NetBSD")}, + {0xab, N_("Darwin boot")}, + {0xaf, N_("HFS / HFS+")}, + {0xb7, N_("BSDI fs")}, + {0xb8, N_("BSDI swap")}, + {0xbb, N_("Boot Wizard hidden")}, + {0xbe, N_("Solaris boot")}, + {0xbf, N_("Solaris")}, + {0xc1, N_("DRDOS/sec (FAT-12)")}, + {0xc4, N_("DRDOS/sec (FAT-16 < 32M)")}, + {0xc6, N_("DRDOS/sec (FAT-16)")}, + {0xc7, N_("Syrinx")}, + {0xda, N_("Non-FS data")}, + {0xdb, N_("CP/M / CTOS / ...")},/* CP/M or Concurrent CP/M or + Concurrent DOS or CTOS */ + {0xde, N_("Dell Utility")}, /* Dell PowerEdge Server utilities */ + {0xdf, N_("BootIt")}, /* BootIt EMBRM */ + {0xe1, N_("DOS access")}, /* DOS access or SpeedStor 12-bit FAT + extended partition */ + {0xe3, N_("DOS R/O")}, /* DOS R/O or SpeedStor */ + {0xe4, N_("SpeedStor")}, /* SpeedStor 16-bit FAT extended + partition < 1024 cyl. */ + {0xeb, N_("BeOS fs")}, + {0xee, N_("GPT")}, /* Intel EFI GUID Partition Table */ + {0xef, N_("EFI (FAT-12/16/32)")},/* Intel EFI System Partition */ + {0xf0, N_("Linux/PA-RISC boot")},/* Linux/PA-RISC boot loader */ + {0xf1, N_("SpeedStor")}, + {0xf4, N_("SpeedStor")}, /* SpeedStor large partition */ + {0xf2, N_("DOS secondary")}, /* DOS 3.3+ secondary */ + {0xfb, N_("VMware VMFS")}, + {0xfc, N_("VMware VMKCORE")}, /* VMware kernel dump partition */ + {0xfd, N_("Linux raid autodetect")},/* New (2.2.x) raid partition with + autodetect using persistent + superblock */ + {0xfe, N_("LANstep")}, /* SpeedStor >1024 cyl. or LANstep */ + {0xff, N_("BBT")}, /* Xenix Bad Block Table */ + + { 0, 0 } diff --git a/libblkid/include/pt-mbr.h b/libblkid/include/pt-mbr.h new file mode 100644 index 000000000..1279e3cf2 --- /dev/null +++ b/libblkid/include/pt-mbr.h @@ -0,0 +1,178 @@ +#ifndef UTIL_LINUX_PT_MBR_H +#define UTIL_LINUX_PT_MBR_H + +struct dos_partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char bh, bs, bc; /* begin CHS */ + unsigned char sys_ind; + unsigned char eh, es, ec; /* end CHS */ + unsigned char start_sect[4]; + unsigned char nr_sects[4]; +} __attribute__((packed)); + +#define MBR_PT_OFFSET 0x1be + +static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i) +{ + return (struct dos_partition *) + (mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition))); +} + +/* assemble badly aligned little endian integer */ +static inline unsigned int __dos_assemble_4le(const unsigned char *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +static inline void __dos_store_4le(unsigned char *p, unsigned int val) +{ + p[0] = (val & 0xff); + p[1] = ((val >> 8) & 0xff); + p[2] = ((val >> 16) & 0xff); + p[3] = ((val >> 24) & 0xff); +} + +static inline unsigned int dos_partition_get_start(struct dos_partition *p) +{ + return __dos_assemble_4le(&(p->start_sect[0])); +} + +static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n) +{ + __dos_store_4le(p->start_sect, n); +} + +static inline unsigned int dos_partition_get_size(struct dos_partition *p) +{ + return __dos_assemble_4le(&(p->nr_sects[0])); +} + +static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n) +{ + __dos_store_4le(p->nr_sects, n); +} + +static inline int mbr_is_valid_magic(const unsigned char *mbr) +{ + return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0; +} + +static inline void mbr_set_magic(unsigned char *b) +{ + b[510] = 0x55; + b[511] = 0xaa; +} + +static inline unsigned int mbr_get_id(const unsigned char *mbr) +{ + return __dos_assemble_4le(&mbr[440]); +} + +static inline void mbr_set_id(unsigned char *b, unsigned int id) +{ + __dos_store_4le(&b[440], id); +} + +enum { + MBR_EMPTY_PARTITION = 0x00, + MBR_FAT12_PARTITION = 0x01, + MBR_XENIX_ROOT_PARTITION = 0x02, + MBR_XENIX_USR_PARTITION = 0x03, + MBR_FAT16_LESS32M_PARTITION = 0x04, + MBR_DOS_EXTENDED_PARTITION = 0x05, + MBR_FAT16_PARTITION = 0x06, /* DOS 16-bit >=32M */ + MBR_HPFS_NTFS_PARTITION = 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */ + MBR_AIX_PARTITION = 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ + MBR_AIX_BOOTABLE_PARTITION = 0x09, /* AIX data or Coherent */ + MBR_OS2_BOOTMNGR_PARTITION = 0x0a, /* OS/2 Boot Manager */ + MBR_W95_FAT32_PARTITION = 0x0b, + MBR_W95_FAT32_LBA_PARTITION = 0x0c, /* LBA really is `Extended Int 13h' */ + MBR_W95_FAT16_LBA_PARTITION = 0x0e, + MBR_W95_EXTENDED_PARTITION = 0x0f, + MBR_OPUS_PARTITION = 0x10, + MBR_HIDDEN_FAT12_PARTITION = 0x11, + MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12, + MBR_HIDDEN_FAT16_L32M_PARTITION = 0x14, + MBR_HIDDEN_FAT16_PARTITION = 0x16, + MBR_HIDDEN_HPFS_NTFS_PARTITION = 0x17, + MBR_AST_SMARTSLEEP_PARTITION = 0x18, + MBR_HIDDEN_W95_FAT32_PARTITION = 0x1b, + MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c, + MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e, + MBR_NEC_DOS_PARTITION = 0x24, + MBR_PLAN9_PARTITION = 0x39, + MBR_PARTITIONMAGIC_PARTITION = 0x3c, + MBR_VENIX80286_PARTITION = 0x40, + MBR_PPC_PREP_BOOT_PARTITION = 0x41, + MBR_SFS_PARTITION = 0x42, + MBR_QNX_4X_PARTITION = 0x4d, + MBR_QNX_4X_2ND_PARTITION = 0x4e, + MBR_QNX_4X_3RD_PARTITION = 0x4f, + MBR_DM_PARTITION = 0x50, + MBR_DM6_AUX1_PARTITION = 0x51, /* (or Novell) */ + MBR_CPM_PARTITION = 0x52, /* CP/M or Microport SysV/AT */ + MBR_DM6_AUX3_PARTITION = 0x53, + MBR_DM6_PARTITION = 0x54, + MBR_EZ_DRIVE_PARTITION = 0x55, + MBR_GOLDEN_BOW_PARTITION = 0x56, + MBR_PRIAM_EDISK_PARTITION = 0x5c, + MBR_SPEEDSTOR_PARTITION = 0x61, + MBR_GNU_HURD_PARTITION = 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ + MBR_UNIXWARE_PARTITION = MBR_GNU_HURD_PARTITION, + MBR_NETWARE_286_PARTITION = 0x64, + MBR_NETWARE_386_PARTITION = 0x65, + MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70, + MBR_PC_IX_PARTITION = 0x75, + MBR_OLD_MINIX_PARTITION = 0x80, /* Minix 1.4a and earlier */ + MBR_MINIX_PARTITION = 0x81, /* Minix 1.4b and later */ + MBR_LINUX_SWAP_PARTITION = 0x82, + MBR_SOLARIS_X86_PARTITION = MBR_LINUX_SWAP_PARTITION, + MBR_LINUX_DATA_PARTITION = 0x83, + MBR_OS2_HIDDEN_DRIVE_PARTITION = 0x84, + MBR_LINUX_EXTENDED_PARTITION = 0x85, + MBR_NTFS_VOL_SET1_PARTITION = 0x86, + MBR_NTFS_VOL_SET2_PARTITION = 0x87, + MBR_LINUX_PLAINTEXT_PARTITION = 0x88, + MBR_LINUX_LVM_PARTITION = 0x8e, + MBR_AMOEBA_PARTITION = 0x93, + MBR_AMOEBA_BBT_PARTITION = 0x94, /* (bad block table) */ + MBR_BSD_OS_PARTITION = 0x9f, /* BSDI */ + MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0, + MBR_FREEBSD_PARTITION = 0xa5, /* various BSD flavours */ + MBR_OPENBSD_PARTITION = 0xa6, + MBR_NEXTSTEP_PARTITION = 0xa7, + MBR_DARWIN_UFS_PARTITION = 0xa8, + MBR_NETBSD_PARTITION = 0xa9, + MBR_DARWIN_BOOT_PARTITION = 0xab, + MBR_HFS_HFS_PARTITION = 0xaf, + MBR_BSDI_FS_PARTITION = 0xb7, + MBR_BSDI_SWAP_PARTITION = 0xb8, + MBR_BOOTWIZARD_HIDDEN_PARTITION = 0xbb, + MBR_SOLARIS_BOOT_PARTITION = 0xbe, + MBR_SOLARIS_PARTITION = 0xbf, + MBR_DRDOS_FAT12_PARTITION = 0xc1, + MBR_DRDOS_FAT16_L32M_PARTITION = 0xc4, + MBR_DRDOS_FAT16_PARTITION = 0xc6, + MBR_SYRINX_PARTITION = 0xc7, + MBR_NONFS_DATA_PARTITION = 0xda, + MBR_CPM_CTOS_PARTITION = 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */ + MBR_DELL_UTILITY_PARTITION = 0xde, /* Dell PowerEdge Server utilities */ + MBR_BOOTIT_PARTITION = 0xdf, /* BootIt EMBRM */ + MBR_DOS_ACCESS_PARTITION = 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */ + MBR_DOS_RO_PARTITION = 0xe3, /* DOS R/O or SpeedStor */ + MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */ + MBR_BEOS_FS_PARTITION = 0xeb, + MBR_GPT_PARTITION = 0xee, /* Intel EFI GUID Partition Table */ + MBR_EFI_SYSTEM_PARTITION = 0xef, /* Intel EFI System Partition */ + MBR_LINUX_PARISC_BOOT_PARTITION = 0xf0, /* Linux/PA-RISC boot loader */ + MBR_SPEEDSTOR1_PARTITION = 0xf1, + MBR_SPEEDSTOR2_PARTITION = 0xf4, /* SpeedStor large partition */ + MBR_DOS_SECONDARY_PARTITION = 0xf2, /* DOS 3.3+ secondary */ + MBR_VMWARE_VMFS_PARTITION = 0xfb, + MBR_VMWARE_VMKCORE_PARTITION = 0xfc, /* VMware kernel dump partition */ + MBR_LINUX_RAID_PARTITION = 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */ + MBR_LANSTEP_PARTITION = 0xfe, /* SpeedStor >1024 cyl. or LANstep */ + MBR_XENIX_BBT_PARTITION = 0xff, /* Xenix Bad Block Table */ +}; + +#endif /* UTIL_LINUX_PT_MBR_H */ diff --git a/libblkid/include/pt-sgi.h b/libblkid/include/pt-sgi.h new file mode 100644 index 000000000..547b37a87 --- /dev/null +++ b/libblkid/include/pt-sgi.h @@ -0,0 +1,110 @@ +#ifndef UTIL_LINUX_PT_SUN_H +#define UTIL_LINUX_PT_SUN_H + +#include <stdint.h> + +#define SGI_LABEL_MAGIC 0x0be5a941 + +#define SGI_MAXPARTITIONS 16 +#define SGI_MAXVOLUMES 15 + +/* partition types */ +enum { + SGI_TYPE_VOLHDR = 0x00, + SGI_TYPE_TRKREPL = 0x01, + SGI_TYPE_SECREPL = 0x02, + SGI_TYPE_SWAP = 0x03, + SGI_TYPE_BSD = 0x04, + SGI_TYPE_SYSV = 0x05, + SGI_TYPE_ENTIRE_DISK = 0x06, + SGI_TYPE_EFS = 0x07, + SGI_TYPE_LVOL = 0x08, + SGI_TYPE_RLVOL = 0x09, + SGI_TYPE_XFS = 0x0a, + SGI_TYPE_XFSLOG = 0x0b, + SGI_TYPE_XLV = 0x0c, + SGI_TYPE_XVM = 0x0d +}; + +struct sgi_device_parameter { + unsigned char skew; + unsigned char gap1; + unsigned char gap2; + unsigned char sparecyl; + + uint16_t pcylcount; + uint16_t head_vol0; + uint16_t ntrks; /* tracks in cyl 0 or vol 0 */ + + unsigned char cmd_tag_queue_depth; + unsigned char unused0; + + uint16_t unused1; + uint16_t nsect; /* sectors/tracks in cyl 0 or vol 0 */ + uint16_t bytes; + uint16_t ilfact; + uint32_t flags; /* SGI_DEVPARAM_* controller flags */ + uint32_t datarate; + uint32_t retries_on_error; + uint32_t ms_per_word; + uint16_t xylogics_gap1; + uint16_t xylogics_syncdelay; + uint16_t xylogics_readdelay; + uint16_t xylogics_gap2; + uint16_t xylogics_readgate; + uint16_t xylogics_writecont; +} __attribute__((packed)); + +enum { + SGI_DEVPARAM_SECTOR_SLIP = 0x01, + SGI_DEVPARAM_SECTOR_FWD = 0x02, + SGI_DEVPARAM_TRACK_FWD = 0x04, + SGI_DEVPARAM_TRACK_MULTIVOL = 0x08, + SGI_DEVPARAM_IGNORE_ERRORS = 0x10, + SGI_DEVPARAM_RESEEK = 0x20, + SGI_DEVPARAM_CMDTAGQ_ENABLE = 0x40 +}; + + +struct sgi_disklabel { + uint32_t magic; /* magic number */ + uint16_t root_part_num; /* # root partition */ + uint16_t swap_part_num; /* # swap partition */ + unsigned char boot_file[16]; /* name of boot file */ + + struct sgi_device_parameter devparam; /* not used now */ + + struct sgi_volume { + unsigned char name[8]; /* name of volume */ + uint32_t block_num; /* logical block number */ + uint32_t num_bytes; /* how big, in bytes */ + } __attribute__((packed)) volume[SGI_MAXVOLUMES]; + + struct sgi_partition { + uint32_t num_blocks; /* size in logical blocks */ + uint32_t first_block; /* first logical block */ + uint32_t type; /* type of this partition */ + } __attribute__((packed)) partitions[SGI_MAXPARTITIONS]; + + /* checksum is the 32bit 2's complement sum of the disklabel */ + uint32_t csum; /* disk label checksum */ + uint32_t padding; /* padding */ +} __attribute__((packed)); + +static inline uint32_t sgi_pt_checksum(struct sgi_disklabel *label) +{ + int i; + uint32_t *ptr = (uint32_t *) label; + uint32_t sum = 0; + + i = sizeof(*label) / sizeof(*ptr); + + while (i) { + i--; + sum -= be32_to_cpu(ptr[i]); + } + + return sum; +} + +#endif /* UTIL_LINUX_PT_SUN_H */ diff --git a/libblkid/include/pt-sun.h b/libblkid/include/pt-sun.h new file mode 100644 index 000000000..b085268ca --- /dev/null +++ b/libblkid/include/pt-sun.h @@ -0,0 +1,90 @@ +#ifndef UTIL_LINUX_PT_SUN_H +#define UTIL_LINUX_PT_SUN_H + +#include <stdint.h> + +#define SUN_LABEL_MAGIC 0xDABE + +/* Supported VTOC setting */ +#define SUN_VTOC_SANITY 0x600DDEEE /* magic number */ +#define SUN_VTOC_VERSION 1 +#define SUN_MAXPARTITIONS 8 + +struct sun_disklabel { + unsigned char label_id[128]; /* Informative text string */ + + struct sun_vtoc { + uint32_t version; /* version */ + char volume_id[8];/* volume name */ + uint16_t nparts; /* num of partitions */ + + struct sun_info { /* partition information */ + uint16_t id; /* SUN_TAG_* */ + uint16_t flags; /* SUN_FLAG_* */ + } __attribute__ ((packed)) infos[8]; + + uint16_t padding; /* padding */ + uint32_t bootinfo[3]; /* info needed by mboot */ + uint32_t sanity; /* magic number */ + uint32_t reserved[10]; /* padding */ + uint32_t timestamp[8]; /* partition timestamp */ + } __attribute__ ((packed)) vtoc; + + uint32_t write_reinstruct; /* sectors to skip, writes */ + uint32_t read_reinstruct; /* sectors to skip, reads */ + unsigned char spare[148]; /* padding */ + uint16_t rpm; /* disk rotational speed */ + uint16_t pcyl; /* physical cylinder count */ + uint16_t apc; /* extra sects per cylinder */ + uint16_t obs1; + uint16_t obs2; + uint16_t intrlv; /* interleave factor */ + uint16_t ncyl; /* data cylinder count */ + uint16_t acyl; /* alt. cylinder count */ + uint16_t nhead; /* tracks per cylinder <---- */ + uint16_t nsect; /* sectors per track <---- */ + uint16_t obs3; + uint16_t obs4; + + struct sun_partition { /* partitions */ + uint32_t start_cylinder; + uint32_t num_sectors; + } __attribute__ ((packed)) partitions[8]; + + uint16_t magic; /* magic number */ + uint16_t csum; /* label xor'd checksum */ +} __attribute__ ((packed)); + + +#define SUN_TAG_UNASSIGNED 0x00 /* Unassigned partition */ +#define SUN_TAG_BOOT 0x01 /* Boot partition */ +#define SUN_TAG_ROOT 0x02 /* Root filesystem */ +#define SUN_TAG_SWAP 0x03 /* Swap partition */ +#define SUN_TAG_USR 0x04 /* /usr filesystem */ +#define SUN_TAG_WHOLEDISK 0x05 /* Full-disk slice */ +#define SUN_TAG_STAND 0x06 /* Stand partition */ +#define SUN_TAG_VAR 0x07 /* /var filesystem */ +#define SUN_TAG_HOME 0x08 /* /home filesystem */ +#define SUN_TAG_ALTSCTR 0x09 /* Alt sector partition */ +#define SUN_TAG_CACHE 0x0a /* Cachefs partition */ +#define SUN_TAG_RESERVED 0x0b /* SMI reserved data */ +#define SUN_TAG_LINUX_SWAP 0x82 /* Linux SWAP */ +#define SUN_TAG_LINUX_NATIVE 0x83 /* Linux filesystem */ +#define SUN_TAG_LINUX_LVM 0x8e /* Linux LVM */ +#define SUN_TAG_LINUX_RAID 0xfd /* LInux RAID */ + +#define SUN_FLAG_UNMNT 0x01 /* Unmountable partition*/ +#define SUN_FLAG_RONLY 0x10 /* Read only */ + +static inline uint16_t sun_pt_checksum(struct sun_disklabel *label) +{ + uint16_t *ptr = ((uint16_t *) (label + 1)) - 1; + uint16_t sum; + + for (sum = 0; ptr >= ((uint16_t *) label);) + sum ^= *ptr--; + + return sum; +} + +#endif /* UTIL_LINUX_PT_SUN_H */ diff --git a/libblkid/include/randutils.h b/libblkid/include/randutils.h new file mode 100644 index 000000000..17e2a02fa --- /dev/null +++ b/libblkid/include/randutils.h @@ -0,0 +1,13 @@ +#ifndef UTIL_LINUX_RANDUTILS +#define UTIL_LINUX_RANDUTILS + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +extern int random_get_fd(void); +extern void random_get_bytes(void *buf, size_t nbytes); +extern const char *random_tell_source(void); + +#endif diff --git a/libblkid/include/readutmp.h b/libblkid/include/readutmp.h new file mode 100644 index 000000000..93251eac1 --- /dev/null +++ b/libblkid/include/readutmp.h @@ -0,0 +1,28 @@ +/* Declarations for GNU's read utmp module. + + Copyright (C) 1992-2007, 2009-2014 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by jla; revised by djm */ + +#ifndef READUTMP_H +#define READUTMP_H + +#include <sys/types.h> +#include <utmp.h> + +int read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf); + +#endif /* READUTMP_H */ diff --git a/libblkid/rpmatch.h b/libblkid/include/rpmatch.h index d62634bd8..d62634bd8 100644 --- a/libblkid/rpmatch.h +++ b/libblkid/include/rpmatch.h diff --git a/libblkid/setproctitle.h b/libblkid/include/setproctitle.h index 70a9efa10..70a9efa10 100644 --- a/libblkid/setproctitle.h +++ b/libblkid/include/setproctitle.h diff --git a/libblkid/include/statfs_magic.h b/libblkid/include/statfs_magic.h new file mode 100644 index 000000000..7397a4e5d --- /dev/null +++ b/libblkid/include/statfs_magic.h @@ -0,0 +1,99 @@ +#ifndef UTIL_LINUX_STATFS_MAGIC_H +#define UTIL_LINUX_STATFS_MAGIC_H + +#include <sys/statfs.h> + +/* + * If possible then don't depend on internal libc __SWORD_TYPE type. + */ +#ifdef __GNUC__ +#define F_TYPE_EQUAL(a, b) (a == (__typeof__(a)) b) +#else +#define F_TYPE_EQUAL(a, b) (a == (__SWORD_TYPE) b) +#endif + +/* + * Unfortunately, Linux kernel hedeader file <linux/magic.h> is incomplete + * mess and kernel returns by statfs f_type many numbers that are nowhere + * specified (in API). + * + * This is collection of the magic numbers. + */ +#define STATFS_ADFS_MAGIC 0xadf5 +#define STATFS_AFFS_MAGIC 0xadff +#define STATFS_AFS_MAGIC 0x5346414F +#define STATFS_AUTOFS_MAGIC 0x0187 +#define STATFS_BDEVFS_MAGIC 0x62646576 +#define STATFS_BEFS_MAGIC 0x42465331 +#define STATFS_BFS_MAGIC 0x1BADFACE +#define STATFS_BINFMTFS_MAGIC 0x42494e4d +#define STATFS_BTRFS_MAGIC 0x9123683E +#define STATFS_CEPH_MAGIC 0x00c36400 +#define STATFS_CGROUP_MAGIC 0x27e0eb +#define STATFS_CIFS_MAGIC 0xff534d42 +#define STATFS_CODA_MAGIC 0x73757245 +#define STATFS_CONFIGFS_MAGIC 0x62656570 +#define STATFS_CRAMFS_MAGIC 0x28cd3d45 +#define STATFS_DEBUGFS_MAGIC 0x64626720 +#define STATFS_DEVPTS_MAGIC 0x1cd1 +#define STATFS_ECRYPTFS_MAGIC 0xf15f +#define STATFS_EFIVARFS_MAGIC 0xde5e81e4 +#define STATFS_EFS_MAGIC 0x414A53 +#define STATFS_EXOFS_MAGIC 0x5DF5 +#define STATFS_EXT2_MAGIC 0xEF53 +#define STATFS_EXT3_MAGIC 0xEF53 +#define STATFS_EXT4_MAGIC 0xEF53 +#define STATFS_F2FS_MAGIC 0xF2F52010 +#define STATFS_FUSE_MAGIC 0x65735546 +#define STATFS_FUTEXFS_MAGIC 0xBAD1DEA +#define STATFS_GFS2_MAGIC 0x01161970 +#define STATFS_HFSPLUS_MAGIC 0x482b +#define STATFS_HOSTFS_MAGIC 0x00c0ffee +#define STATFS_HPFS_MAGIC 0xf995e849 +#define STATFS_HPPFS_MAGIC 0xb00000ee +#define STATFS_HUGETLBFS_MAGIC 0x958458f6 +#define STATFS_ISOFS_MAGIC 0x9660 +#define STATFS_JFFS2_MAGIC 0x72b6 +#define STATFS_JFS_MAGIC 0x3153464a +#define STATFS_LOGFS_MAGIC 0xc97e8168 +#define STATFS_MINIX2_MAGIC 0x2468 +#define STATFS_MINIX2_MAGIC2 0x2478 +#define STATFS_MINIX3_MAGIC 0x4d5a +#define STATFS_MINIX_MAGIC 0x137F +#define STATFS_MINIX_MAGIC2 0x138F +#define STATFS_MQUEUE_MAGIC 0x19800202 +#define STATFS_MSDOS_MAGIC 0x4d44 +#define STATFS_NCP_MAGIC 0x564c +#define STATFS_NFS_MAGIC 0x6969 +#define STATFS_NILFS_MAGIC 0x3434 +#define STATFS_NTFS_MAGIC 0x5346544e +#define STATFS_OCFS2_MAGIC 0x7461636f +#define STATFS_OMFS_MAGIC 0xC2993D87 +#define STATFS_OPENPROMFS_MAGIC 0x9fa1 +#define STATFS_PIPEFS_MAGIC 0x50495045 +#define STATFS_PROC_MAGIC 0x9fa0 +#define STATFS_PSTOREFS_MAGIC 0x6165676C +#define STATFS_QNX4_MAGIC 0x002f +#define STATFS_QNX6_MAGIC 0x68191122 +#define STATFS_RAMFS_MAGIC 0x858458f6 +#define STATFS_REISERFS_MAGIC 0x52654973 +#define STATFS_ROMFS_MAGIC 0x7275 +#define STATFS_SECURITYFS_MAGIC 0x73636673 +#define STATFS_SELINUXFS_MAGIC 0xf97cff8c +#define STATFS_SMACKFS_MAGIC 0x43415d53 +#define STATFS_SMB_MAGIC 0x517B +#define STATFS_SOCKFS_MAGIC 0x534F434B +#define STATFS_SQUASHFS_MAGIC 0x73717368 +#define STATFS_SYSFS_MAGIC 0x62656572 +#define STATFS_TMPFS_MAGIC 0x01021994 +#define STATFS_UBIFS_MAGIC 0x24051905 +#define STATFS_UDF_MAGIC 0x15013346 +#define STATFS_UFS2_MAGIC 0x19540119 +#define STATFS_UFS_MAGIC 0x00011954 +#define STATFS_V9FS_MAGIC 0x01021997 +#define STATFS_VXFS_MAGIC 0xa501FCF5 +#define STATFS_XENFS_MAGIC 0xabba1974 +#define STATFS_XFS_MAGIC 0x58465342 + +#endif /* UTIL_LINUX_STATFS_MAGIC_H */ + diff --git a/libblkid/include/strutils.h b/libblkid/include/strutils.h new file mode 100644 index 000000000..4d8463a6d --- /dev/null +++ b/libblkid/include/strutils.h @@ -0,0 +1,204 @@ +#ifndef UTIL_LINUX_STRUTILS +#define UTIL_LINUX_STRUTILS + +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <ctype.h> + +/* default strtoxx_or_err() exit code */ +#ifndef STRTOXX_EXIT_CODE +# define STRTOXX_EXIT_CODE EXIT_FAILURE +#endif + + +extern int parse_size(const char *str, uintmax_t *res, int *power); +extern int strtosize(const char *str, uintmax_t *res); +extern uintmax_t strtosize_or_err(const char *str, const char *errmesg); + +extern int16_t strtos16_or_err(const char *str, const char *errmesg); +extern uint16_t strtou16_or_err(const char *str, const char *errmesg); + +extern int32_t strtos32_or_err(const char *str, const char *errmesg); +extern uint32_t strtou32_or_err(const char *str, const char *errmesg); + +extern int64_t strtos64_or_err(const char *str, const char *errmesg); +extern uint64_t strtou64_or_err(const char *str, const char *errmesg); + +extern double strtod_or_err(const char *str, const char *errmesg); + +extern long strtol_or_err(const char *str, const char *errmesg); +extern unsigned long strtoul_or_err(const char *str, const char *errmesg); + +extern void strtotimeval_or_err(const char *str, struct timeval *tv, + const char *errmesg); + +extern int isdigit_string(const char *str); + +#ifndef HAVE_MEMPCPY +extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n); +#endif +#ifndef HAVE_STRNLEN +extern size_t strnlen(const char *s, size_t maxlen); +#endif +#ifndef HAVE_STRNDUP +extern char *strndup(const char *s, size_t n); +#endif +#ifndef HAVE_STRNCHR +extern char *strnchr(const char *s, size_t maxlen, int c); +#endif + +/* caller guarantees n > 0 */ +static inline void xstrncpy(char *dest, const char *src, size_t n) +{ + strncpy(dest, src, n-1); + dest[n-1] = 0; +} + +static inline char *strdup_to_offset(void *stru, size_t offset, const char *str) +{ + char *n = NULL; + char **o = (char **) ((char *) stru + offset); + + if (str) { + n = strdup(str); + if (!n) + return NULL; + } + + free(*o); + *o = n; + return n; +} + +#define strdup_to_struct_member(_s, _m, _str) \ + strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str) + +extern void strmode(mode_t mode, char *str); + +/* Options for size_to_human_string() */ +enum +{ + SIZE_SUFFIX_1LETTER = 0, + SIZE_SUFFIX_3LETTER = 1, + SIZE_SUFFIX_SPACE = 2 +}; + +extern char *size_to_human_string(int options, uint64_t bytes); + +extern int string_to_idarray(const char *list, int ary[], size_t arysz, + int (name2id)(const char *, size_t)); +extern int string_add_to_idarray(const char *list, int ary[], + size_t arysz, int *ary_pos, + int (name2id)(const char *, size_t)); + +extern int string_to_bitarray(const char *list, char *ary, + int (*name2bit)(const char *, size_t)); + +extern int string_to_bitmask(const char *list, + unsigned long *mask, + long (*name2flag)(const char *, size_t)); +extern int parse_range(const char *str, int *lower, int *upper, int def); + +extern int streq_except_trailing_slash(const char *s1, const char *s2); + +/* + * Match string beginning. + */ +static inline const char *startswith(const char *s, const char *prefix) +{ + size_t sz = prefix ? strlen(prefix) : 0; + + if (s && sz && strncmp(s, prefix, sz) == 0) + return s + sz; + return NULL; +} + +/* + * Case insensitive match string beginning. + */ +static inline const char *startswith_no_case(const char *s, const char *prefix) +{ + size_t sz = prefix ? strlen(prefix) : 0; + + if (s && sz && strncasecmp(s, prefix, sz) == 0) + return s + sz; + return NULL; +} + +/* + * Match string ending. + */ +static inline const char *endswith(const char *s, const char *postfix) +{ + size_t sl = s ? strlen(s) : 0; + size_t pl = postfix ? strlen(postfix) : 0; + + if (pl == 0) + return (char *)s + sl; + if (sl < pl) + return NULL; + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + return (char *)s + sl - pl; +} + +/* + * Skip leading white space. + */ +static inline const char *skip_space(const char *p) +{ + while (isspace(*p)) + ++p; + return p; +} + +static inline const char *skip_blank(const char *p) +{ + while (isblank(*p)) + ++p; + return p; +} + + +/* Removes whitespace from the right-hand side of a string (trailing + * whitespace). + * + * Returns size of the new string (without \0). + */ +static inline size_t rtrim_whitespace(unsigned char *str) +{ + size_t i = strlen((char *) str); + + while (i) { + i--; + if (!isspace(str[i])) { + i++; + break; + } + } + str[i] = '\0'; + return i; +} + +/* Removes whitespace from the left-hand side of a string. + * + * Returns size of the new string (without \0). + */ +static inline size_t ltrim_whitespace(unsigned char *str) +{ + size_t len; + unsigned char *p; + + for (p = str; p && isspace(*p); p++); + + len = strlen((char *) p); + + if (len && p > str) + memmove(str, p, len + 1); + + return len; +} + +#endif diff --git a/libblkid/include/swapheader.h b/libblkid/include/swapheader.h new file mode 100644 index 000000000..3fce0d0fb --- /dev/null +++ b/libblkid/include/swapheader.h @@ -0,0 +1,23 @@ +#ifndef _SWAPHEADER_H +#define _SWAPHEADER_H + +#define SWAP_VERSION 1 +#define SWAP_UUID_LENGTH 16 +#define SWAP_LABEL_LENGTH 16 +#define SWAP_SIGNATURE "SWAPSPACE2" +#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1) + +#include <stdint.h> + +struct swap_header_v1_2 { + char bootbits[1024]; /* Space for disklabel etc. */ + uint32_t version; + uint32_t last_page; + uint32_t nr_badpages; + unsigned char uuid[SWAP_UUID_LENGTH]; + char volume_name[SWAP_LABEL_LENGTH]; + uint32_t padding[117]; + uint32_t badpages[1]; +}; + +#endif /* _SWAPHEADER_H */ diff --git a/libblkid/include/swapprober.h b/libblkid/include/swapprober.h new file mode 100644 index 000000000..510770045 --- /dev/null +++ b/libblkid/include/swapprober.h @@ -0,0 +1,9 @@ +#ifndef UTIL_LINUX_SWAP_PROBER_H +#define UTIL_LINUX_SWAP_PROBER_H + +#include <blkid.h> + +blkid_probe get_swap_prober(const char *devname); + +#endif /* UTIL_LINUX_SWAP_PROBER_H */ + diff --git a/libblkid/include/sysfs.h b/libblkid/include/sysfs.h new file mode 100644 index 000000000..1de624aad --- /dev/null +++ b/libblkid/include/sysfs.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Karel Zak <kzak@redhat.com> + */ +#ifndef UTIL_LINUX_SYSFS_H +#define UTIL_LINUX_SYSFS_H + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <inttypes.h> +#include <dirent.h> + +struct sysfs_cxt { + dev_t devno; + int dir_fd; /* /sys/block/<name> */ + char *dir_path; + struct sysfs_cxt *parent; + + unsigned int scsi_host, + scsi_channel, + scsi_target, + scsi_lun; + + unsigned int has_hctl : 1; +}; + +#define UL_SYSFSCXT_EMPTY { 0, -1, NULL, NULL, 0, 0, 0, 0, 0 } + +extern char *sysfs_devno_attribute_path(dev_t devno, char *buf, + size_t bufsiz, const char *attr); +extern int sysfs_devno_has_attribute(dev_t devno, const char *attr); +extern char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz); +extern char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz); +extern dev_t sysfs_devname_to_devno(const char *name, const char *parent); + +extern int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent) + __attribute__ ((warn_unused_result)); +extern void sysfs_deinit(struct sysfs_cxt *cxt); + +extern DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st); +extern ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr, + char *buf, size_t bufsiz); +extern int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, + const char *fmt, ...) + __attribute__ ((format (scanf, 3, 4))); + +extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res); +extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res); +extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res); + +extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str); +extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num); + +extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz); + +extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr); +extern int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname); +extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno); +extern char *sysfs_get_slave(struct sysfs_cxt *cxt); + +extern char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz); +extern int sysfs_next_subsystem(struct sysfs_cxt *cxt, char *devchain, char **subsys); +extern int sysfs_is_hotpluggable(struct sysfs_cxt *cxt); + +extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, + const char *parent_name); + +extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno); + +extern int sysfs_devno_is_lvm_private(dev_t devno); +extern int sysfs_devno_is_wholedisk(dev_t devno); + +extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, + int *c, int *t, int *l); +extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, + const char *type, const char *attr); +extern int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type); +extern int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr); +extern int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern); + +#endif /* UTIL_LINUX_SYSFS_H */ diff --git a/libblkid/include/timer.h b/libblkid/include/timer.h new file mode 100644 index 000000000..79ef64919 --- /dev/null +++ b/libblkid/include/timer.h @@ -0,0 +1,31 @@ +#ifndef UTIL_LINUX_TIMER_H +#define UTIL_LINUX_TIMER_H + +#include <signal.h> +#include <sys/time.h> + +static inline int setup_timer( + struct itimerval *timer, + struct itimerval *old_timer, + struct sigaction *old_sa, + void (*timeout_handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_handler = timeout_handler; + sa.sa_flags = SA_RESETHAND; + sigaction(SIGALRM, &sa, old_sa); + + return setitimer(ITIMER_REAL, timer, old_timer); +} + +static inline void cancel_timer( + struct itimerval *old_timer, + struct sigaction *old_sa) +{ + setitimer(ITIMER_REAL, old_timer, NULL); + sigaction(SIGALRM, old_sa, NULL); +} + +#endif diff --git a/libblkid/include/timeutils.h b/libblkid/include/timeutils.h new file mode 100644 index 000000000..8ed501b9d --- /dev/null +++ b/libblkid/include/timeutils.h @@ -0,0 +1,56 @@ +/*** + First set of functions in this file are part of systemd, and were + copied to util-linux at August 2013. + + Copyright 2010 Lennart Poettering + Copyright (C) 2014 Karel Zak <kzak@redhat.com> + + systemd 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. + + systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>. +***/ +#ifndef UTIL_LINUX_TIME_UTIL_H +#define UTIL_LINUX_TIME_UTIL_H + +#include <stdio.h> +#include <inttypes.h> + +typedef uint64_t usec_t; +typedef uint64_t nsec_t; + +#define MSEC_PER_SEC 1000ULL +#define USEC_PER_SEC 1000000ULL +#define USEC_PER_MSEC 1000ULL +#define NSEC_PER_SEC 1000000000ULL +#define NSEC_PER_MSEC 1000000ULL +#define NSEC_PER_USEC 1000ULL + +#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC) +#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC) +#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE) +#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE) +#define USEC_PER_DAY (24ULL*USEC_PER_HOUR) +#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR) +#define USEC_PER_WEEK (7ULL*USEC_PER_DAY) +#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY) +#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC) +#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC) +#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC) +#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC) + +#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ +#define FORMAT_TIMESTAMP_RELATIVE_MAX 256 +#define FORMAT_TIMESPAN_MAX 64 + +int parse_timestamp(const char *t, usec_t *usec); + +#endif /* UTIL_LINUX_TIME_UTIL_H */ diff --git a/libblkid/include/ttyutils.h b/libblkid/include/ttyutils.h new file mode 100644 index 000000000..e842f9f0d --- /dev/null +++ b/libblkid/include/ttyutils.h @@ -0,0 +1,168 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#ifndef UTIL_LINUX_TTYUTILS_H +#define UTIL_LINUX_TTYUTILS_H + +#include <stdlib.h> +#include <termios.h> +#include <limits.h> +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_TTYDEFAULTS_H +#include <sys/ttydefaults.h> +#endif + +/* Some shorthands for control characters. */ +#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ +#define CR CTL('M') /* carriage return */ +#define NL CTL('J') /* line feed */ +#define BS CTL('H') /* back space */ +#define DEL CTL('?') /* delete */ + +/* Defaults for line-editing etc. characters; you may want to change these. */ +#define DEF_ERASE DEL /* default erase character */ +#define DEF_INTR CTL('C') /* default interrupt character */ +#define DEF_QUIT CTL('\\') /* default quit char */ +#define DEF_KILL CTL('U') /* default kill char */ +#define DEF_EOF CTL('D') /* default EOF char */ +#define DEF_EOL 0 +#define DEF_SWITCH 0 /* default switch char */ + +/* Storage for things detected while the login name was read. */ +struct chardata { + int erase; /* erase character */ + int kill; /* kill character */ + int eol; /* end-of-line character */ + int parity; /* what parity did we see */ + int capslock; /* upper case without lower case */ +}; + +#define INIT_CHARDATA(ptr) do { \ + (ptr)->erase = DEF_ERASE; \ + (ptr)->kill = DEF_KILL; \ + (ptr)->eol = CTRL('r'); \ + (ptr)->parity = 0; \ + (ptr)->capslock = 0; \ + } while (0) + +extern int get_terminal_width(void); +extern int get_terminal_name(int fd, const char **path, const char **name, + const char **number); + +#define UL_TTY_KEEPCFLAGS (1 << 1) +#define UL_TTY_UTF8 (1 << 2) + +static inline void reset_virtual_console(struct termios *tp, int flags) +{ + /* Use defaults of <sys/ttydefaults.h> for base settings */ + tp->c_iflag |= TTYDEF_IFLAG; + tp->c_oflag |= TTYDEF_OFLAG; + tp->c_lflag |= TTYDEF_LFLAG; + + if ((flags & UL_TTY_KEEPCFLAGS) == 0) { +#ifdef CBAUD + tp->c_lflag &= ~CBAUD; +#endif + tp->c_cflag |= (B38400 | TTYDEF_CFLAG); + } + + /* Sane setting, allow eight bit characters, no carriage return delay + * the same result as `stty sane cr0 pass8' + */ +#ifndef IUCLC +# define IUCLC 0 +#endif +#ifndef NL0 +# define NL0 0 +#endif +#ifndef CR0 +# define CR0 0 +#endif +#ifndef BS0 +# define BS0 0 +#endif +#ifndef VT0 +# define VT0 0 +#endif +#ifndef FF0 +# define FF0 0 +#endif +#ifndef OLCUC +# define OLCUC 0 +#endif +#ifndef OFILL +# define OFILL 0 +#endif +#ifndef NLDLY +# define NLDLY 0 +#endif +#ifndef CRDLY +# define CRDLY 0 +#endif +#ifndef BSDLY +# define BSDLY 0 +#endif +#ifndef VTDLY +# define VTDLY 0 +#endif +#ifndef FFDLY +# define FFDLY 0 +#endif + + tp->c_iflag |= (BRKINT | ICRNL | IMAXBEL); + tp->c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP); + tp->c_oflag |= (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0); + tp->c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | \ + NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); + tp->c_lflag |= (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE|ECHOCTL); + tp->c_lflag &= ~(ECHONL|ECHOPRT | NOFLSH | TOSTOP); + + if ((flags & UL_TTY_KEEPCFLAGS) == 0) { + tp->c_cflag |= (CREAD | CS8 | HUPCL); + tp->c_cflag &= ~(PARODD | PARENB); + } +#ifdef OFDEL + tp->c_oflag &= ~OFDEL; +#endif +#ifdef XCASE + tp->c_lflag &= ~XCASE; +#endif +#ifdef IUTF8 + if (flags & UL_TTY_UTF8) + tp->c_iflag |= IUTF8; /* Set UTF-8 input flag */ + else + tp->c_iflag &= ~IUTF8; +#endif + /* VTIME and VMIN can overlap with VEOF and VEOL since they are + * only used for non-canonical mode. We just set the at the + * beginning, so nothing bad should happen. + */ + tp->c_cc[VTIME] = 0; + tp->c_cc[VMIN] = 1; + tp->c_cc[VINTR] = CINTR; + tp->c_cc[VQUIT] = CQUIT; + tp->c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */ + tp->c_cc[VKILL] = CKILL; + tp->c_cc[VEOF] = CEOF; +#ifdef VSWTC + tp->c_cc[VSWTC] = _POSIX_VDISABLE; +#elif defined(VSWTCH) + tp->c_cc[VSWTCH] = _POSIX_VDISABLE; +#endif + tp->c_cc[VSTART] = CSTART; + tp->c_cc[VSTOP] = CSTOP; + tp->c_cc[VSUSP] = CSUSP; + tp->c_cc[VEOL] = _POSIX_VDISABLE; + tp->c_cc[VREPRINT] = CREPRINT; + tp->c_cc[VDISCARD] = CDISCARD; + tp->c_cc[VWERASE] = CWERASE; + tp->c_cc[VLNEXT] = CLNEXT; + tp->c_cc[VEOL2] = _POSIX_VDISABLE; +} + +#endif /* UTIL_LINUX_TTYUTILS_H */ diff --git a/libblkid/widechar.h b/libblkid/include/widechar.h index b023b5fb2..b023b5fb2 100644 --- a/libblkid/widechar.h +++ b/libblkid/include/widechar.h diff --git a/libblkid/include/xalloc.h b/libblkid/include/xalloc.h new file mode 100644 index 000000000..f012fb294 --- /dev/null +++ b/libblkid/include/xalloc.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * General memory allocation wrappers for malloc, realloc, calloc and strdup + */ + +#ifndef UTIL_LINUX_XALLOC_H +#define UTIL_LINUX_XALLOC_H + +#include <stdlib.h> +#include <string.h> + +#include "c.h" + +#ifndef XALLOC_EXIT_CODE +# define XALLOC_EXIT_CODE EXIT_FAILURE +#endif + +static inline __ul_alloc_size(1) +void *xmalloc(const size_t size) +{ + void *ret = malloc(size); + + if (!ret && size) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline __ul_alloc_size(2) +void *xrealloc(void *ptr, const size_t size) +{ + void *ret = realloc(ptr, size); + + if (!ret && size) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline __ul_calloc_size(1, 2) +void *xcalloc(const size_t nelems, const size_t size) +{ + void *ret = calloc(nelems, size); + + if (!ret && size && nelems) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline char __attribute__((warn_unused_result)) *xstrdup(const char *str) +{ + char *ret; + + if (!str) + return NULL; + + ret = strdup(str); + + if (!ret) + err(XALLOC_EXIT_CODE, "cannot duplicate string"); + return ret; +} + +static inline char * __attribute__((warn_unused_result)) xstrndup(const char *str, size_t size) +{ + char *ret; + + if (!str) + return NULL; + + ret = strndup(str, size); + + if (!ret) + err(XALLOC_EXIT_CODE, "cannot duplicate string"); + return ret; +} + + +static inline int __attribute__ ((__format__(printf, 2, 3))) + xasprintf(char **strp, const char *fmt, ...) +{ + int ret; + va_list args; + va_start(args, fmt); + ret = vasprintf(&(*strp), fmt, args); + va_end(args); + if (ret < 0) + err(XALLOC_EXIT_CODE, "cannot allocate string"); + return ret; +} + +static inline int xvasprintf(char **strp, const char *fmt, va_list ap) +{ + int ret = vasprintf(&(*strp), fmt, ap); + if (ret < 0) + err(XALLOC_EXIT_CODE, "cannot allocate string"); + return ret; +} + + +static inline char * __attribute__((warn_unused_result)) xgethostname(void) +{ + char *name; + size_t sz = get_hostname_max() + 1; + + name = xmalloc(sizeof(char) * sz); + + if (gethostname(name, sz) != 0) { + free(name); + return NULL; + } + name[sz - 1] = '\0'; + return name; +} + +#endif diff --git a/libblkid/ismounted.c b/libblkid/ismounted.c deleted file mode 100644 index d9f1f57d0..000000000 --- a/libblkid/ismounted.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * ismounted.c --- Check to see if the filesystem was mounted - * - * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o. - * - * This file may be redistributed under the terms of the GNU Public - * License. - */ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <errno.h> -#include <fcntl.h> -#ifdef HAVE_MNTENT_H -#include <mntent.h> -#endif -#include <string.h> -#include <sys/stat.h> -#include <ctype.h> -#include <sys/param.h> -#ifdef __APPLE__ -#include <sys/ucred.h> -#include <sys/mount.h> -#endif - -#include "pathnames.h" -#include "ismounted.h" -#include "c.h" -#ifdef __linux__ -# include "loopdev.h" -#endif - - - -#ifdef HAVE_MNTENT_H -/* - * Helper function which checks a file in /etc/mtab format to see if a - * filesystem is mounted. Returns an error if the file doesn't exist - * or can't be opened. - */ -static int check_mntent_file(const char *mtab_file, const char *file, - int *mount_flags, char *mtpt, int mtlen) -{ - struct mntent *mnt; - struct stat st_buf; - int retval = 0; - dev_t file_dev=0, file_rdev=0; - ino_t file_ino=0; - FILE *f; - int fd; - - *mount_flags = 0; - if ((f = setmntent (mtab_file, "r")) == NULL) - return errno; - - if (stat(file, &st_buf) == 0) { - if (S_ISBLK(st_buf.st_mode)) { -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - file_rdev = st_buf.st_rdev; -#endif /* __GNU__ */ - } else { - file_dev = st_buf.st_dev; - file_ino = st_buf.st_ino; - } - } - - while ((mnt = getmntent (f)) != NULL) { - if (mnt->mnt_fsname[0] != '/') - continue; - if (strcmp(file, mnt->mnt_fsname) == 0) - break; - if (stat(mnt->mnt_fsname, &st_buf) != 0) - continue; - - if (S_ISBLK(st_buf.st_mode)) { -#ifndef __GNU__ - if (file_rdev && file_rdev == st_buf.st_rdev) - break; -#ifdef __linux__ - /* maybe the file is loopdev backing file */ - if (file_dev - && major(st_buf.st_rdev) == LOOPDEV_MAJOR - && loopdev_is_used(mnt->mnt_fsname, file, 0, 0)) - break; -#endif /* __linux__ */ -#endif /* __GNU__ */ - } else { - if (file_dev && ((file_dev == st_buf.st_dev) && - (file_ino == st_buf.st_ino))) - break; - } - } - - if (mnt == NULL) { -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - /* - * Do an extra check to see if this is the root device. We - * can't trust /etc/mtab, and /proc/mounts will only list - * /dev/root for the root filesystem. Argh. Instead we - * check if the given device has the same major/minor number - * as the device that the root directory is on. - */ - if (file_rdev && stat("/", &st_buf) == 0 && - st_buf.st_dev == file_rdev) { - *mount_flags = MF_MOUNTED; - if (mtpt) - strncpy(mtpt, "/", mtlen); - goto is_root; - } -#endif /* __GNU__ */ - goto errout; - } -#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ - /* Validate the entry in case /etc/mtab is out of date */ - /* - * We need to be paranoid, because some broken distributions - * (read: Slackware) don't initialize /etc/mtab before checking - * all of the non-root filesystems on the disk. - */ - if (stat(mnt->mnt_dir, &st_buf) < 0) { - retval = errno; - if (retval == ENOENT) { -#ifdef DEBUG - printf("Bogus entry in %s! (%s does not exist)\n", - mtab_file, mnt->mnt_dir); -#endif /* DEBUG */ - retval = 0; - } - goto errout; - } - if (file_rdev && (st_buf.st_dev != file_rdev)) { -#ifdef DEBUG - printf("Bogus entry in %s! (%s not mounted on %s)\n", - mtab_file, file, mnt->mnt_dir); -#endif /* DEBUG */ - goto errout; - } -#endif /* __GNU__ */ - *mount_flags = MF_MOUNTED; - -#ifdef MNTOPT_RO - /* Check to see if the ro option is set */ - if (hasmntopt(mnt, MNTOPT_RO)) - *mount_flags |= MF_READONLY; -#endif - - if (mtpt) - strncpy(mtpt, mnt->mnt_dir, mtlen); - /* - * Check to see if we're referring to the root filesystem. - * If so, do a manual check to see if we can open /etc/mtab - * read/write, since if the root is mounted read/only, the - * contents of /etc/mtab may not be accurate. - */ - if (!strcmp(mnt->mnt_dir, "/")) { -is_root: -#define TEST_FILE "/.ismount-test-file" - *mount_flags |= MF_ISROOT; - fd = open(TEST_FILE, O_RDWR|O_CREAT, 0600); - if (fd < 0) { - if (errno == EROFS) - *mount_flags |= MF_READONLY; - } else - close(fd); - (void) unlink(TEST_FILE); - } - retval = 0; -errout: - endmntent (f); - return retval; -} - -static int check_mntent(const char *file, int *mount_flags, - char *mtpt, int mtlen) -{ - int retval; - -#ifdef DEBUG - retval = check_mntent_file("/tmp/mtab", file, mount_flags, - mtpt, mtlen); - if (retval == 0) - return 0; -#endif /* DEBUG */ -#ifdef __linux__ - retval = check_mntent_file("/proc/mounts", file, mount_flags, - mtpt, mtlen); - if (retval == 0 && (*mount_flags != 0)) - return 0; - if (access("/proc/mounts", R_OK) == 0) { - *mount_flags = 0; - return retval; - } -#endif /* __linux__ */ -#if defined(MOUNTED) || defined(_PATH_MOUNTED) -#ifndef MOUNTED -#define MOUNTED _PATH_MOUNTED -#endif /* MOUNTED */ - retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); - return retval; -#else - *mount_flags = 0; - return 0; -#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ -} - -#else -#if defined(HAVE_GETMNTINFO) - -static int check_getmntinfo(const char *file, int *mount_flags, - char *mtpt, int mtlen) -{ - struct statfs *mp; - int len, n; - const char *s1; - char *s2; - - n = getmntinfo(&mp, MNT_NOWAIT); - if (n == 0) - return errno; - - len = sizeof(_PATH_DEV) - 1; - s1 = file; - if (strncmp(_PATH_DEV, s1, len) == 0) - s1 += len; - - *mount_flags = 0; - while (--n >= 0) { - s2 = mp->f_mntfromname; - if (strncmp(_PATH_DEV, s2, len) == 0) { - s2 += len - 1; - *s2 = 'r'; - } - if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { - *mount_flags = MF_MOUNTED; - break; - } - ++mp; - } - if (mtpt) - strncpy(mtpt, mp->f_mntonname, mtlen); - return 0; -} -#endif /* HAVE_GETMNTINFO */ -#endif /* HAVE_MNTENT_H */ - -/* - * Check to see if we're dealing with the swap device. - */ -static int is_swap_device(const char *file) -{ - FILE *f; - char buf[1024], *cp; - dev_t file_dev; - struct stat st_buf; - int ret = 0; - - file_dev = 0; -#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ - if ((stat(file, &st_buf) == 0) && - S_ISBLK(st_buf.st_mode)) - file_dev = st_buf.st_rdev; -#endif /* __GNU__ */ - - if (!(f = fopen("/proc/swaps", "r"))) - return 0; - /* Skip the first line */ - if (!fgets(buf, sizeof(buf), f)) - goto leave; - if (*buf && strncmp(buf, "Filename\t", 9)) - /* Linux <=2.6.19 contained a bug in the /proc/swaps - * code where the header would not be displayed - */ - goto valid_first_line; - - while (fgets(buf, sizeof(buf), f)) { -valid_first_line: - if ((cp = strchr(buf, ' ')) != NULL) - *cp = 0; - if ((cp = strchr(buf, '\t')) != NULL) - *cp = 0; - if (strcmp(buf, file) == 0) { - ret++; - break; - } -#ifndef __GNU__ - if (file_dev && (stat(buf, &st_buf) == 0) && - S_ISBLK(st_buf.st_mode) && - file_dev == st_buf.st_rdev) { - ret++; - break; - } -#endif /* __GNU__ */ - } - -leave: - fclose(f); - return ret; -} - - -/* - * check_mount_point() fills determines if the device is mounted or otherwise - * busy, and fills in mount_flags with one or more of the following flags: - * MF_MOUNTED, MF_ISROOT, MF_READONLY, MF_SWAP, and MF_BUSY. If mtpt is - * non-NULL, the directory where the device is mounted is copied to where mtpt - * is pointing, up to mtlen characters. - */ -#ifdef __TURBOC__ - #pragma argsused -#endif -int check_mount_point(const char *device, int *mount_flags, - char *mtpt, int mtlen) -{ - struct stat st_buf; - int retval = 0; - int fd; - - if (is_swap_device(device)) { - *mount_flags = MF_MOUNTED | MF_SWAP; - strncpy(mtpt, "<swap>", mtlen); - } else { -#ifdef HAVE_MNTENT_H - retval = check_mntent(device, mount_flags, mtpt, mtlen); -#else -#ifdef HAVE_GETMNTINFO - retval = check_getmntinfo(device, mount_flags, mtpt, mtlen); -#else -#ifdef __GNUC__ - #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" -#endif - *mount_flags = 0; -#endif /* HAVE_GETMNTINFO */ -#endif /* HAVE_MNTENT_H */ - } - if (retval) - return retval; - -#ifdef __linux__ /* This only works on Linux 2.6+ systems */ - if ((stat(device, &st_buf) != 0) || - !S_ISBLK(st_buf.st_mode)) - return 0; - fd = open(device, O_RDONLY | O_EXCL); - if (fd < 0) { - if (errno == EBUSY) - *mount_flags |= MF_BUSY; - } else - close(fd); -#endif - - return 0; -} - -int is_mounted(const char *file) -{ - int retval; - int mount_flags = 0; - - retval = check_mount_point(file, &mount_flags, NULL, 0); - if (retval) - return 0; - return mount_flags & MF_MOUNTED; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - int flags = 0; - char devname[PATH_MAX]; - - if (argc < 2) { - fprintf(stderr, "Usage: %s device\n", argv[0]); - return EXIT_FAILURE; - } - - if (check_mount_point(argv[1], &flags, devname, sizeof(devname)) == 0 && - (flags & MF_MOUNTED)) { - if (flags & MF_SWAP) - printf("used swap device\n"); - else - printf("mounted on %s\n", devname); - return EXIT_SUCCESS; - } - - printf("not mounted\n"); - return EXIT_FAILURE; -} -#endif /* DEBUG */ diff --git a/libblkid/iso9660.c b/libblkid/iso9660.c deleted file mode 100644 index 148587b3b..000000000 --- a/libblkid/iso9660.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired also by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> -#include <ctype.h> - -#include "superblocks.h" - -struct iso9660_date { - unsigned char year[4]; - unsigned char month[2]; - unsigned char day[2]; - unsigned char hour[2]; - unsigned char minute[2]; - unsigned char second[2]; - unsigned char hundredth[2]; - unsigned char offset; -} __attribute__ ((packed)); - -/* PVD - Primary volume descriptor */ -struct iso_volume_descriptor { - unsigned char vd_type; - unsigned char vd_id[5]; - unsigned char vd_version; - unsigned char flags; - unsigned char system_id[32]; - unsigned char volume_id[32]; - unsigned char unused[8]; - unsigned char space_size[8]; - unsigned char escape_sequences[8]; - unsigned char unused1[222]; - unsigned char publisher_id[128]; - unsigned char unused2[128]; - unsigned char application_id[128]; - unsigned char unused3[111]; - struct iso9660_date created; - struct iso9660_date modified; -} __attribute__((packed)); - -/* Boot Record */ -struct boot_record { - unsigned char vd_type; - unsigned char vd_id[5]; - unsigned char vd_version; - unsigned char boot_system_id[32]; - unsigned char boot_id[32]; - unsigned char unused[1]; -} __attribute__((packed)); - -#define ISO_SUPERBLOCK_OFFSET 0x8000 -#define ISO_SECTOR_SIZE 0x800 -#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE) -#define ISO_VD_BOOT_RECORD 0x0 -#define ISO_VD_SUPPLEMENTARY 0x2 -#define ISO_VD_END 0xff -#define ISO_VD_MAX 16 - -struct high_sierra_volume_descriptor { - unsigned char foo[8]; - unsigned char type; - unsigned char id[5]; - unsigned char version; - unsigned char unused1; - unsigned char system_id[32]; - unsigned char volume_id[32]; -} __attribute__((packed)); - -/* returns 1 if the begin of @ascii is equal to @utf16 string. - */ -static int ascii_eq_utf16be(unsigned char *ascii, - unsigned char *utf16, size_t len) -{ - size_t a, u; - - for (a = 0, u = 0; u < len; a++, u += 2) { - if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1]) - return 0; - } - return 1; -} - -/* old High Sierra format */ -static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct high_sierra_volume_descriptor *iso; - - iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor); - if (!iso) - return -1; - - blkid_probe_set_version(pr, "High Sierra"); - blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id)); - return 0; -} - -static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date) -{ - unsigned char buffer[16]; - unsigned int i, zeros = 0; - - buffer[0] = date->year[0]; - buffer[1] = date->year[1]; - buffer[2] = date->year[2]; - buffer[3] = date->year[3]; - buffer[4] = date->month[0]; - buffer[5] = date->month[1]; - buffer[6] = date->day[0]; - buffer[7] = date->day[1]; - buffer[8] = date->hour[0]; - buffer[9] = date->hour[1]; - buffer[10] = date->minute[0]; - buffer[11] = date->minute[1]; - buffer[12] = date->second[0]; - buffer[13] = date->second[1]; - buffer[14] = date->hundredth[0]; - buffer[15] = date->hundredth[1]; - - /* count the number of zeros ('0') in the date buffer */ - for (i = 0, zeros = 0; i < sizeof(buffer); i++) - if (buffer[i] == '0') - zeros++; - - /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */ - if (zeros == sizeof(buffer) && date->offset == 0) - return 0; - - /* generate an UUID using this date and return success */ - blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer), - "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", - buffer[0], buffer[1], buffer[2], buffer[3], - buffer[4], buffer[5], - buffer[6], buffer[7], - buffer[8], buffer[9], - buffer[10], buffer[11], - buffer[12], buffer[13], - buffer[14], buffer[15]); - - return 1; -} - -static int is_str_empty(const unsigned char *str, size_t len) -{ - size_t i; - - if (!str || !*str) - return 1; - - for (i = 0; i < len; i++) - if (!isspace(str[i])) - return 0; - return 1; -} - -/* iso9660 [+ Microsoft Joliet Extension] */ -int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct iso_volume_descriptor *iso; - unsigned char label[32]; - int i; - int off; - - if (strcmp(mag->magic, "CDROM") == 0) - return probe_iso9660_hsfs(pr, mag); - - iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor); - if (!iso) - return -1; - - memcpy(label, iso->volume_id, sizeof(label)); - - if (!is_str_empty(iso->system_id, sizeof(iso->system_id))) - blkid_probe_set_id_label(pr, "SYSTEM_ID", - iso->system_id, sizeof(iso->system_id)); - - if (!is_str_empty(iso->publisher_id, sizeof(iso->publisher_id))) - blkid_probe_set_id_label(pr, "PUBLISHER_ID", - iso->publisher_id, sizeof(iso->publisher_id)); - - if (!is_str_empty(iso->application_id, sizeof(iso->application_id))) - blkid_probe_set_id_label(pr, "APPLICATION_ID", - iso->application_id, sizeof(iso->application_id)); - - /* create an UUID using the modified/created date */ - if (! probe_iso9660_set_uuid(pr, &iso->modified)) - probe_iso9660_set_uuid(pr, &iso->created); - - /* Joliet Extension and Boot Record */ - off = ISO_VD_OFFSET; - for (i = 0; i < ISO_VD_MAX; i++) { - struct boot_record *boot= (struct boot_record *) - blkid_probe_get_buffer(pr, - off, - max(sizeof(struct boot_record), - sizeof(struct iso_volume_descriptor))); - - if (boot == NULL || boot->vd_type == ISO_VD_END) - break; - - if (boot->vd_type == ISO_VD_BOOT_RECORD) { - if (!is_str_empty(boot->boot_system_id, - sizeof(boot->boot_system_id))) - blkid_probe_set_id_label(pr, "BOOT_SYSTEM_ID", - boot->boot_system_id, - sizeof(boot->boot_system_id)); - off += ISO_SECTOR_SIZE; - continue; - } - - /* Not a Boot record, lets see if its supplemntary volume descriptor */ - iso = (struct iso_volume_descriptor *) boot; - - if (iso->vd_type != ISO_VD_SUPPLEMENTARY) { - off += ISO_SECTOR_SIZE; - continue; - } - - if (memcmp(iso->escape_sequences, "%/@", 3) == 0 || - memcmp(iso->escape_sequences, "%/C", 3) == 0 || - memcmp(iso->escape_sequences, "%/E", 3) == 0) { - - blkid_probe_set_version(pr, "Joliet Extension"); - - /* Is the Joliet (UTF16BE) label equal to the label in - * the PVD? If yes, use PVD label. The Jolied version - * of the label could be trimed (because UTF16..). - */ - if (ascii_eq_utf16be(label, iso->volume_id, 32)) - break; - - blkid_probe_set_utf8label(pr, - iso->volume_id, - sizeof(iso->volume_id), - BLKID_ENC_UTF16BE); - goto has_label; - } - off += ISO_SECTOR_SIZE; - } - - /* Joliet not found, let use standard iso label */ - blkid_probe_set_label(pr, label, sizeof(label)); - -has_label: - return 0; -} - -const struct blkid_idinfo iso9660_idinfo = -{ - .name = "iso9660", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_iso9660, - .flags = BLKID_IDINFO_TOLERANT, - .magics = - { - { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 }, - { NULL } - } -}; - diff --git a/libblkid/isw_raid.c b/libblkid/isw_raid.c deleted file mode 100644 index 755c1b652..000000000 --- a/libblkid/isw_raid.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct isw_metadata { - uint8_t sig[32]; - uint32_t check_sum; - uint32_t mpb_size; - uint32_t family_num; - uint32_t generation_num; -}; - -#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " - - -static int probe_iswraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct isw_metadata *isw; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 2) * 0x200; - isw = (struct isw_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct isw_metadata)); - if (!isw) - return -1; - if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) - return -1; - if (blkid_probe_sprintf_version(pr, "%6s", - &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(isw->sig), - (unsigned char *) isw->sig)) - return -1; - return 0; -} - -const struct blkid_idinfo iswraid_idinfo = { - .name = "isw_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_iswraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/jfs.c b/libblkid/jfs.c deleted file mode 100644 index 78c018c15..000000000 --- a/libblkid/jfs.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -struct jfs_super_block { - unsigned char js_magic[4]; - uint32_t js_version; - uint64_t js_size; - uint32_t js_bsize; /* 4: aggregate block size in bytes */ - uint16_t js_l2bsize; /* 2: log2 of s_bsize */ - uint16_t js_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ - uint32_t js_pbsize; /* 4: hardware/LVM block size in bytes */ - uint16_t js_l2pbsize; /* 2: log2 of s_pbsize */ - uint16_t js_pad; /* 2: padding necessary for alignment */ - uint32_t js_dummy2[26]; - unsigned char js_uuid[16]; - unsigned char js_label[16]; - unsigned char js_loguuid[16]; -}; - -static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct jfs_super_block *js; - - js = blkid_probe_get_sb(pr, mag, struct jfs_super_block); - if (!js) - return -1; - if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize))) - return 1; - if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize))) - return 1; - if ((le16_to_cpu(js->js_l2bsize) - le16_to_cpu(js->js_l2pbsize)) != - le16_to_cpu(js->js_l2bfactor)) - return 1; - - if (strlen((char *) js->js_label)) - blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label)); - blkid_probe_set_uuid(pr, js->js_uuid); - return 0; -} - - -const struct blkid_idinfo jfs_idinfo = -{ - .name = "jfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_jfs, - .minsz = 16 * 1024 * 1024, - .magics = - { - { .magic = "JFS1", .len = 4, .kboff = 32 }, - { NULL } - } -}; - diff --git a/libblkid/jmicron_raid.c b/libblkid/jmicron_raid.c deleted file mode 100644 index c7080780f..000000000 --- a/libblkid/jmicron_raid.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct jm_metadata { - int8_t signature[2]; - uint8_t minor_version; - uint8_t major_version; - uint16_t checksum; -}; - -#define JM_SIGNATURE "JM" - -static int probe_jmraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct jm_metadata *jm; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 1) * 0x200; - jm = (struct jm_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct jm_metadata)); - if (!jm) - return -1; - if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0) - return -1; - if (blkid_probe_sprintf_version(pr, "%u.%u", - jm->major_version, jm->minor_version) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(jm->signature), - (unsigned char *) jm->signature)) - return -1; - return 0; -} - -const struct blkid_idinfo jmraid_idinfo = { - .name = "jmicron_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_jmraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/lib/Makemodule.am b/libblkid/lib/Makemodule.am new file mode 100644 index 000000000..565294e5c --- /dev/null +++ b/libblkid/lib/Makemodule.am @@ -0,0 +1,115 @@ + +noinst_LTLIBRARIES += libcommon.la +libcommon_la_CFLAGS = $(AM_CFLAGS) +libcommon_la_SOURCES = \ + lib/at.c \ + lib/blkdev.c \ + lib/canonicalize.c \ + lib/colors.c \ + lib/crc32.c \ + lib/crc64.c \ + lib/env.c \ + lib/fileutils.c \ + lib/ismounted.c \ + lib/mangle.c \ + lib/match.c \ + lib/mbsalign.c \ + lib/md5.c \ + lib/pager.c \ + lib/path.c \ + lib/procutils.c \ + lib/randutils.c \ + lib/setproctitle.c \ + lib/strutils.c \ + lib/sysfs.c \ + lib/timeutils.c \ + lib/ttyutils.c \ + lib/exec_shell.c \ + lib/readutmp.c + +if LINUX +libcommon_la_SOURCES += \ + lib/linux_version.c \ + lib/loopdev.c +endif + +if !HAVE_LANGINFO +libcommon_la_SOURCES += lib/langinfo.c +endif + +if HAVE_CPU_SET_T +libcommon_la_SOURCES += lib/cpuset.c +endif + +dist_man_MANS += lib/terminal-colors.d.5 + +check_PROGRAMS += \ + test_at \ + test_blkdev \ + test_canonicalize \ + test_colors \ + test_fileutils \ + test_ismounted \ + test_mangle \ + test_procutils \ + test_randutils \ + test_strutils \ + test_ttyutils + +if LINUX +if HAVE_CPU_SET_T +check_PROGRAMS += test_cpuset +endif +check_PROGRAMS += \ + test_sysfs \ + test_pager +endif + +test_ttyutils_SOURCES = lib/ttyutils.c +test_ttyutils_CFLAGS = -DTEST_PROGRAM +test_ttyutils_LDADD = libcommon.la + +test_blkdev_SOURCES = lib/blkdev.c +test_blkdev_CFLAGS = -DTEST_PROGRAM_BLKDEV +test_blkdev_LDADD = libcommon.la + +test_ismounted_SOURCES = lib/ismounted.c +test_ismounted_CFLAGS = -DTEST_PROGRAM +test_ismounted_LDADD = libcommon.la + +test_mangle_SOURCES = lib/mangle.c +test_mangle_CFLAGS = -DTEST_PROGRAM + +test_at_SOURCES = lib/at.c +test_at_CFLAGS = -DTEST_PROGRAM_AT + +test_strutils_SOURCES = lib/strutils.c +test_strutils_CFLAGS = -DTEST_PROGRAM + +test_colors_SOURCES = lib/colors.c +test_colors_CFLAGS = -DTEST_PROGRAM + +test_randutils_SOURCES = lib/randutils.c +test_randutils_CFLAGS = -DTEST_PROGRAM + +test_procutils_SOURCES = lib/procutils.c lib/at.c +test_procutils_CFLAGS = -DTEST_PROGRAM + +if LINUX +test_cpuset_SOURCES = lib/cpuset.c +test_cpuset_CFLAGS = -DTEST_PROGRAM + +test_sysfs_SOURCES = lib/sysfs.c +test_sysfs_CFLAGS = -DTEST_PROGRAM_SYSFS +test_sysfs_LDADD = libcommon.la + +test_pager_SOURCES = lib/pager.c +test_pager_CFLAGS = -DTEST_PROGRAM +endif + +test_fileutils_SOURCES = lib/fileutils.c +test_fileutils_CFLAGS = -DTEST_PROGRAM + +test_canonicalize_SOURCES = lib/canonicalize.c +test_canonicalize_CFLAGS = -DTEST_PROGRAM_CANONICALIZE + diff --git a/libblkid/at.c b/libblkid/lib/at.c index f8bfe1399..f8bfe1399 100644 --- a/libblkid/at.c +++ b/libblkid/lib/at.c diff --git a/libblkid/lib/blkdev.c b/libblkid/lib/blkdev.c new file mode 100644 index 000000000..a29352963 --- /dev/null +++ b/libblkid/lib/blkdev.c @@ -0,0 +1,378 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <stdint.h> + +#ifdef HAVE_LINUX_FD_H +#include <linux/fd.h> +#endif + +#ifdef HAVE_SYS_DISKLABEL_H +#include <sys/disklabel.h> +#endif + +#ifdef HAVE_SYS_DISK_H +#ifdef HAVE_SYS_QUEUE_H +#include <sys/queue.h> /* for LIST_HEAD */ +#endif +#include <sys/disk.h> +#endif + +#ifdef __FreeBSD_kernel__ +#include <sys/disk.h> +#endif + +#include "blkdev.h" +#include "c.h" +#include "linux_version.h" + +static long +blkdev_valid_offset (int fd, off_t offset) { + char ch; + + if (lseek (fd, offset, 0) < 0) + return 0; + if (read (fd, &ch, 1) < 1) + return 0; + return 1; +} + +int is_blkdev(int fd) +{ + struct stat st; + return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)); +} + +off_t +blkdev_find_size (int fd) { + uintmax_t high, low = 0; + + for (high = 1024; blkdev_valid_offset (fd, high); ) { + if (high == UINTMAX_MAX) + return -1; + + low = high; + + if (high >= UINTMAX_MAX/2) + high = UINTMAX_MAX; + else + high *= 2; + } + + while (low < high - 1) + { + uintmax_t mid = (low + high) / 2; + + if (blkdev_valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + blkdev_valid_offset (fd, 0); + return (low + 1); +} + +/* get size in bytes */ +int +blkdev_get_size(int fd, unsigned long long *bytes) +{ +#ifdef DKIOCGETBLOCKCOUNT + /* Apple Darwin */ + if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) { + *bytes <<= 9; + return 0; + } +#endif + +#ifdef BLKGETSIZE64 + { +#ifdef __linux__ + int ver = get_linux_version(); + + /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */ + if (ver >= KERNEL_VERSION (2,6,0) || + (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0))) +#endif + if (ioctl(fd, BLKGETSIZE64, bytes) >= 0) + return 0; + } +#endif /* BLKGETSIZE64 */ + +#ifdef BLKGETSIZE + { + unsigned long size; + + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + *bytes = ((unsigned long long)size << 9); + return 0; + } + } + +#endif /* BLKGETSIZE */ + +#ifdef DIOCGMEDIASIZE + /* FreeBSD */ + if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0) + return 0; +#endif + +#ifdef FDGETPRM + { + struct floppy_struct this_floppy; + + if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { + *bytes = this_floppy.size << 9; + return 0; + } + } +#endif /* FDGETPRM */ + +#ifdef HAVE_SYS_DISKLABEL_H + { + /* + * This code works for FreeBSD 4.11 i386, except for the full device + * (such as /dev/ad0). It doesn't work properly for newer FreeBSD + * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE + * above however. + * + * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw, + * character) devices, so we need to check for S_ISCHR, too. + */ + int part = -1; + struct disklabel lab; + struct partition *pp; + char ch; + struct stat st; + + if ((fstat(fd, &st) >= 0) && + (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))) + part = st.st_rdev & 7; + + if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { + pp = &lab.d_partitions[part]; + if (pp->p_size) { + *bytes = pp->p_size << 9; + return 0; + } + } + } +#endif /* HAVE_SYS_DISKLABEL_H */ + + { + struct stat st; + + if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { + *bytes = st.st_size; + return 0; + } + if (!S_ISBLK(st.st_mode)) + return -1; + } + + *bytes = blkdev_find_size(fd); + return 0; +} + +/* get 512-byte sector count */ +int +blkdev_get_sectors(int fd, unsigned long long *sectors) +{ + unsigned long long bytes; + + if (blkdev_get_size(fd, &bytes) == 0) { + *sectors = (bytes >> 9); + return 0; + } + + return -1; +} + +/* + * Get logical sector size. + * + * This is the smallest unit the storage device can + * address. It is typically 512 bytes. + */ +int blkdev_get_sector_size(int fd, int *sector_size) +{ +#ifdef BLKSSZGET + if (ioctl(fd, BLKSSZGET, sector_size) >= 0) + return 0; + return -1; +#else + *sector_size = DEFAULT_SECTOR_SIZE; + return 0; +#endif +} + +/* + * Get physical block device size. The BLKPBSZGET is supported since Linux + * 2.6.32. For old kernels is probably the best to assume that physical sector + * size is the same as logical sector size. + * + * Example: + * + * rc = blkdev_get_physector_size(fd, &physec); + * if (rc || physec == 0) { + * rc = blkdev_get_sector_size(fd, &physec); + * if (rc) + * physec = DEFAULT_SECTOR_SIZE; + * } + */ +int blkdev_get_physector_size(int fd, int *sector_size) +{ +#ifdef BLKPBSZGET + if (ioctl(fd, BLKPBSZGET, §or_size) >= 0) + return 0; + return -1; +#else + *sector_size = DEFAULT_SECTOR_SIZE; + return 0; +#endif +} + +/* + * Return the alignment status of a device + */ +int blkdev_is_misaligned(int fd) +{ +#ifdef BLKALIGNOFF + int aligned; + + if (ioctl(fd, BLKALIGNOFF, &aligned) < 0) + return 0; /* probably kernel < 2.6.32 */ + /* + * Note that kernel returns -1 as alignement offset if no compatible + * sizes and alignments exist for stacked devices + */ + return aligned != 0 ? 1 : 0; +#else + return 0; +#endif +} + +int blkdev_is_cdrom(int fd) +{ +#ifdef CDROM_GET_CAPABILITY + int ret; + + if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0) + return 0; + else + return ret; +#else + return 0; +#endif +} + +/* + * Get kernel's interpretation of the device's geometry. + * + * Returns the heads and sectors - but not cylinders + * as it's truncated for disks with more than 65535 tracks. + * + * Note that this is deprecated in favor of LBA addressing. + */ +int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s) +{ +#ifdef HDIO_GETGEO + struct hd_geometry geometry; + + if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) { + *h = geometry.heads; + *s = geometry.sectors; + return 0; + } +#else + *h = 0; + *s = 0; +#endif + return -1; +} + +/* + * Convert scsi type to human readable string. + */ +const char *blkdev_scsi_type_to_name(int type) +{ + switch (type) { + case SCSI_TYPE_DISK: + return "disk"; + case SCSI_TYPE_TAPE: + return "tape"; + case SCSI_TYPE_PRINTER: + return "printer"; + case SCSI_TYPE_PROCESSOR: + return "processor"; + case SCSI_TYPE_WORM: + return "worm"; + case SCSI_TYPE_ROM: + return "rom"; + case SCSI_TYPE_SCANNER: + return "scanner"; + case SCSI_TYPE_MOD: + return "mo-disk"; + case SCSI_TYPE_MEDIUM_CHANGER: + return "changer"; + case SCSI_TYPE_COMM: + return "comm"; + case SCSI_TYPE_RAID: + return "raid"; + case SCSI_TYPE_ENCLOSURE: + return "enclosure"; + case SCSI_TYPE_RBC: + return "rbc"; + case SCSI_TYPE_OSD: + return "osd"; + case SCSI_TYPE_NO_LUN: + return "no-lun"; + default: + break; + } + return NULL; +} + +#ifdef TEST_PROGRAM_BLKDEV +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +int +main(int argc, char **argv) +{ + unsigned long long bytes; + unsigned long long sectors; + int sector_size, phy_sector_size; + int fd; + + if (argc != 2) { + fprintf(stderr, "usage: %s device\n", argv[0]); + exit(EXIT_FAILURE); + } + + if ((fd = open(argv[1], O_RDONLY|O_CLOEXEC)) < 0) + err(EXIT_FAILURE, "open %s failed", argv[1]); + + if (blkdev_get_size(fd, &bytes) < 0) + err(EXIT_FAILURE, "blkdev_get_size() failed"); + if (blkdev_get_sectors(fd, §ors) < 0) + err(EXIT_FAILURE, "blkdev_get_sectors() failed"); + if (blkdev_get_sector_size(fd, §or_size) < 0) + err(EXIT_FAILURE, "blkdev_get_sector_size() failed"); + if (blkdev_get_physector_size(fd, &phy_sector_size) < 0) + err(EXIT_FAILURE, "blkdev_get_physector_size() failed"); + + printf(" bytes: %llu\n", bytes); + printf(" sectors: %llu\n", sectors); + printf(" sector size: %d\n", sector_size); + printf("phy-sector size: %d\n", phy_sector_size); + + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ diff --git a/libblkid/lib/canonicalize.c b/libblkid/lib/canonicalize.c new file mode 100644 index 000000000..303703b7c --- /dev/null +++ b/libblkid/lib/canonicalize.c @@ -0,0 +1,145 @@ +/* + * canonicalize.c -- canonicalize pathname by removing symlinks + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + * + * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com> + */ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "canonicalize.h" + +/* + * Converts private "dm-N" names to "/dev/mapper/<name>" + * + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block/<ptname>/dm/name + */ +char *canonicalize_dm_name(const char *ptname) +{ + FILE *f; + size_t sz; + char path[256], name[256], *res = NULL; + + if (!ptname || !*ptname) + return NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if (!(f = fopen(path, "r"))) + return NULL; + + /* read "<name>\n" from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { + name[sz - 1] = '\0'; + snprintf(path, sizeof(path), "/dev/mapper/%s", name); + + if (access(path, F_OK) == 0) + res = strdup(path); + } + fclose(f); + return res; +} + +static int is_dm_devname(char *canonical, char **name) +{ + struct stat sb; + char *p = strrchr(canonical, '/'); + + *name = NULL; + + if (!p + || strncmp(p, "/dm-", 4) != 0 + || !isdigit(*(p + 4)) + || stat(canonical, &sb) != 0 + || !S_ISBLK(sb.st_mode)) + return 0; + + *name = p + 1; + return 1; +} + +char *canonicalize_path(const char *path) +{ + char *canonical, *dmname; + + if (!path || !*path) + return NULL; + + canonical = realpath(path, NULL); + if (!canonical) + return strdup(path); + + if (is_dm_devname(canonical, &dmname)) { + char *dm = canonicalize_dm_name(dmname); + if (dm) { + free(canonical); + return dm; + } + } + + return canonical; +} + +char *canonicalize_path_restricted(const char *path) +{ + char *canonical, *dmname; + int errsv; + uid_t euid; + gid_t egid; + + if (!path || !*path) + return NULL; + + euid = geteuid(); + egid = getegid(); + + /* drop permissions */ + if (setegid(getgid()) < 0 || seteuid(getuid()) < 0) + return NULL; + + errsv = errno = 0; + + canonical = realpath(path, NULL); + if (!canonical) + errsv = errno; + else if (is_dm_devname(canonical, &dmname)) { + char *dm = canonicalize_dm_name(dmname); + if (dm) { + free(canonical); + canonical = dm; + } + } + + /* restore */ + if (setegid(egid) < 0 || seteuid(euid) < 0) { + free(canonical); + return NULL; + } + + errno = errsv; + return canonical; +} + + +#ifdef TEST_PROGRAM_CANONICALIZE +int main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "usage: %s <device>\n", argv[0]); + exit(EXIT_FAILURE); + } + + fprintf(stdout, "orig: %s\n", argv[1]); + fprintf(stdout, "real: %s\n", canonicalize_path(argv[1])); + + exit(EXIT_SUCCESS); +} +#endif diff --git a/libblkid/lib/colors.c b/libblkid/lib/colors.c new file mode 100644 index 000000000..6f79ac4a8 --- /dev/null +++ b/libblkid/lib/colors.c @@ -0,0 +1,877 @@ +/* + * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com> + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + */ +#include <assert.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> + +#include "c.h" +#include "colors.h" +#include "pathnames.h" +#include "strutils.h" + +#include "debug.h" + +/* + * terminal-colors.d debug stuff + */ +UL_DEBUG_DEFINE_MASK(termcolors); +UL_DEBUG_DEFINE_MASKNAMES(termcolors) = UL_DEBUG_EMPTY_MASKNAMES; + +#define TERMCOLORS_DEBUG_INIT (1 << 1) +#define TERMCOLORS_DEBUG_CONF (1 << 2) +#define TERMCOLORS_DEBUG_SCHEME (1 << 3) +#define TERMCOLORS_DEBUG_ALL 0xFFFF + +#define DBG(m, x) __UL_DBG(termcolors, TERMCOLORS_DEBUG_, m, x) +#define ON_DBG(m, x) __UL_DBG_CALL(termcolors, TERMCOLORS_DEBUG_, m, x) + +/* + * terminal-colors.d file types + */ +enum { + UL_COLORFILE_DISABLE, /* .disable */ + UL_COLORFILE_ENABLE, /* .enable */ + UL_COLORFILE_SCHEME, /* .scheme */ + + __UL_COLORFILE_COUNT +}; + +struct ul_color_scheme { + char *name; + char *seq; +}; + +/* + * Global colors control struct + * + * The terminal-colors.d/ evaluation is based on "scores": + * + * filename score + * --------------------------------------- + * type 1 + * @termname.type 10 + 1 + * utilname.type 20 + 1 + * utilname@termname.type 20 + 10 + 1 + * + * the match with higher score wins. The score is per type. + */ +struct ul_color_ctl { + const char *utilname; /* util name */ + const char *termname; /* terminal name ($TERM) */ + + char *sfile; /* path to scheme */ + + struct ul_color_scheme *schemes; /* array with color schemes */ + size_t nschemes; /* number of the items */ + size_t schemes_sz; /* number of the allocated items */ + + int mode; /* UL_COLORMODE_* */ + unsigned int has_colors : 1, /* based on mode and scores[] */ + disabled : 1, /* disable colors */ + cs_configured : 1, /* color schemes read */ + configured : 1; /* terminal-colors.d parsed */ + + int scores[__UL_COLORFILE_COUNT]; /* the best match */ +}; + +/* + * Control struct, globally shared. + */ +static struct ul_color_ctl ul_colors; + +static void colors_free_schemes(struct ul_color_ctl *cc); +static int colors_read_schemes(struct ul_color_ctl *cc); + +/* + * qsort/bsearch buddy + */ +static int cmp_scheme_name(const void *a0, const void *b0) +{ + struct ul_color_scheme *a = (struct ul_color_scheme *) a0, + *b = (struct ul_color_scheme *) b0; + return strcmp(a->name, b->name); +} + +/* + * Maintains human readable color names + */ +const char *color_sequence_from_colorname(const char *str) +{ + static const struct ul_color_scheme basic_schemes[] = { + { "black", UL_COLOR_BLACK }, + { "blue", UL_COLOR_BLUE }, + { "brown", UL_COLOR_BROWN }, + { "cyan", UL_COLOR_CYAN }, + { "darkgray", UL_COLOR_DARK_GRAY }, + { "gray", UL_COLOR_GRAY }, + { "green", UL_COLOR_GREEN }, + { "lightblue", UL_COLOR_BOLD_BLUE }, + { "lightcyan", UL_COLOR_BOLD_CYAN }, + { "lightgray,", UL_COLOR_GRAY }, + { "lightgreen", UL_COLOR_BOLD_GREEN }, + { "lightmagenta", UL_COLOR_BOLD_MAGENTA }, + { "lightred", UL_COLOR_BOLD_RED }, + { "magenta", UL_COLOR_MAGENTA }, + { "red", UL_COLOR_RED }, + { "yellow", UL_COLOR_BOLD_YELLOW }, + }; + struct ul_color_scheme key = { .name = (char *) str }, *res; + + if (!str) + return NULL; + + res = bsearch(&key, basic_schemes, ARRAY_SIZE(basic_schemes), + sizeof(struct ul_color_scheme), + cmp_scheme_name); + return res ? res->seq : NULL; +} + + +/* + * Resets control struct (note that we don't allocate the struct) + */ +static void colors_reset(struct ul_color_ctl *cc) +{ + if (!cc) + return; + + colors_free_schemes(cc); + + free(cc->sfile); + + cc->sfile = NULL; + cc->utilname = NULL; + cc->termname = NULL; + cc->mode = UL_COLORMODE_UNDEF; + + memset(cc->scores, 0, sizeof(cc->scores)); +} + +static void colors_debug(struct ul_color_ctl *cc) +{ + size_t i; + + if (!cc) + return; + + printf("Colors:\n"); + printf("\tutilname = '%s'\n", cc->utilname); + printf("\ttermname = '%s'\n", cc->termname); + printf("\tscheme file = '%s'\n", cc->sfile); + printf("\tmode = %s\n", + cc->mode == UL_COLORMODE_UNDEF ? "undefined" : + cc->mode == UL_COLORMODE_AUTO ? "auto" : + cc->mode == UL_COLORMODE_NEVER ? "never" : + cc->mode == UL_COLORMODE_ALWAYS ? "always" : "???"); + printf("\thas_colors = %d\n", cc->has_colors); + printf("\tdisabled = %d\n", cc->disabled); + printf("\tconfigured = %d\n", cc->configured); + printf("\tcs configured = %d\n", cc->cs_configured); + + fputc('\n', stdout); + + for (i = 0; i < ARRAY_SIZE(cc->scores); i++) + printf("\tscore %s = %d\n", + i == UL_COLORFILE_DISABLE ? "disable" : + i == UL_COLORFILE_ENABLE ? "enable" : + i == UL_COLORFILE_SCHEME ? "scheme" : "???", + cc->scores[i]); + + fputc('\n', stdout); + + for (i = 0; i < cc->nschemes; i++) { + printf("\tscheme #%02zu ", i); + color_scheme_enable(cc->schemes[i].name, NULL); + fputs(cc->schemes[i].name, stdout); + color_disable(); + fputc('\n', stdout); + } + fputc('\n', stdout); +} + +/* + * Parses [[<utilname>][@<termname>].]<type> + */ +static int filename_to_tokens(const char *str, + const char **name, size_t *namesz, + const char **term, size_t *termsz, + int *filetype) +{ + const char *type_start, *term_start, *p; + + if (!str || !*str || *str == '.' || strlen(str) > PATH_MAX) + return -EINVAL; + + /* parse .type */ + p = strrchr(str, '.'); + type_start = p ? p + 1 : str; + + if (strcmp(type_start, "disable") == 0) + *filetype = UL_COLORFILE_DISABLE; + else if (strcmp(type_start, "enable") == 0) + *filetype = UL_COLORFILE_ENABLE; + else if (strcmp(type_start, "scheme") == 0) + *filetype = UL_COLORFILE_SCHEME; + else { + DBG(CONF, ul_debug("unknown type '%s'", type_start)); + return 1; /* unknown type */ + } + + if (type_start == str) + return 0; /* "type" only */ + + /* parse @termname */ + p = strchr(str, '@'); + term_start = p ? p + 1 : NULL; + if (term_start) { + *term = term_start; + *termsz = type_start - term_start - 1; + if (term_start - 1 == str) + return 0; /* "@termname.type" */ + } + + /* parse utilname */ + p = term_start ? term_start : type_start; + *name = str; + *namesz = p - str - 1; + + return 0; +} + +/* + * Scans @dirname and select the best matches for UL_COLORFILE_* types. + * The result is stored to cc->scores. The path to the best "scheme" + * file is stored to cc->scheme. + */ +static int colors_readdir(struct ul_color_ctl *cc, const char *dirname) +{ + DIR *dir; + int rc = 0; + struct dirent *d; + char sfile[PATH_MAX] = { '\0' }; + size_t namesz, termsz; + + if (!dirname || !cc || !cc->utilname || !*cc->utilname) + return -EINVAL; + + DBG(CONF, ul_debug("reading dir: '%s'", dirname)); + + dir = opendir(dirname); + if (!dir) + return -errno; + + namesz = strlen(cc->utilname); + termsz = cc->termname ? strlen(cc->termname) : 0; + + while ((d = readdir(dir))) { + int type, score = 1; + const char *tk_name = NULL, *tk_term = NULL; + size_t tk_namesz = 0, tk_termsz = 0; + + if (*d->d_name == '.') + continue; +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK && + d->d_type != DT_REG) + continue; +#endif + if (filename_to_tokens(d->d_name, + &tk_name, &tk_namesz, + &tk_term, &tk_termsz, &type) != 0) + continue; + + /* count teoretical score before we check names to avoid + * unnecessary strcmp() */ + if (tk_name) + score += 20; + if (tk_term) + score += 10; + + DBG(CONF, ul_debug("item '%s': score=%d " + "[cur: %d, name(%zu): %s, term(%zu): %s]", + d->d_name, score, cc->scores[type], + tk_namesz, tk_name, + tk_termsz, tk_term)); + + + if (score < cc->scores[type]) + continue; + + /* filter out by names */ + if (tk_namesz && (tk_namesz != namesz || + strncmp(tk_name, cc->utilname, namesz) != 0)) + continue; + + if (tk_termsz && (termsz == 0 || tk_termsz != termsz || + strncmp(tk_term, cc->termname, termsz) != 0)) + continue; + + DBG(CONF, ul_debug("setting '%s' from %d -to-> %d", + type == UL_COLORFILE_SCHEME ? "scheme" : + type == UL_COLORFILE_DISABLE ? "disable" : + type == UL_COLORFILE_ENABLE ? "enable" : "???", + cc->scores[type], score)); + cc->scores[type] = score; + if (type == UL_COLORFILE_SCHEME) + strncpy(sfile, d->d_name, sizeof(sfile)); + } + + if (*sfile) { + sfile[sizeof(sfile) - 1] = '\0'; + if (asprintf(&cc->sfile, "%s/%s", dirname, sfile) <= 0) + rc = -ENOMEM; + } + + closedir(dir); + return rc; +} + +/* atexit() wrapper */ +static void colors_deinit(void) +{ + colors_reset(&ul_colors); +} + +/* + * Returns path to $XDG_CONFIG_HOME/terminal-colors.d + */ +static char *colors_get_homedir(char *buf, size_t bufsz) +{ + char *p = getenv("XDG_CONFIG_HOME"); + + if (p) { + snprintf(buf, bufsz, "%s/" _PATH_TERMCOLORS_DIRNAME, p); + return buf; + } + + p = getenv("HOME"); + if (p) { + snprintf(buf, bufsz, "%s/.config/" _PATH_TERMCOLORS_DIRNAME, p); + return buf; + } + + return NULL; +} + +/* canonicalize sequence */ +static int cn_sequence(const char *str, char **seq) +{ + char *in, *out; + + if (!str) + return -EINVAL; + + *seq = NULL; + + /* convert logical names like "red" to the real sequence */ + if (*str != '\\' && isalpha(*str)) { + const char *s = color_sequence_from_colorname(str); + *seq = strdup(s ? s : str); + + return *seq ? 0 : -ENOMEM; + } + + /* convert xx;yy sequences to "\033[xx;yy" */ + if (asprintf(seq, "\033[%sm", str) < 1) + return -ENOMEM; + + for (in = *seq, out = *seq; in && *in; in++) { + if (*in != '\\') { + *out++ = *in; + continue; + } + switch(*(in + 1)) { + case 'a': + *out++ = '\a'; /* Bell */ + break; + case 'b': + *out++ = '\b'; /* Backspace */ + break; + case 'e': + *out++ = '\033'; /* Escape */ + break; + case 'f': + *out++ = '\f'; /* Form Feed */ + break; + case 'n': + *out++ = '\n'; /* Newline */ + break; + case 'r': + *out++ = '\r'; /* Carriage Return */ + break; + case 't': + *out++ = '\t'; /* Tab */ + break; + case 'v': + *out++ = '\v'; /* Vertical Tab */ + break; + case '\\': + *out++ = '\\'; /* Backslash */ + break; + case '_': + *out++ = ' '; /* Space */ + break; + case '#': + *out++ = '#'; /* Hash mark */ + break; + case '?': + *out++ = '?'; /* Qestion mark */ + break; + default: + *out++ = *in; + *out++ = *(in + 1); + break; + } + in++; + } + *out = '\0'; + + return 0; +} + + +/* + * Adds one color sequence to array with color scheme. + * When returning success (0) this function takes ownership of + * @seq and @name, which have to be allocated strings. + */ +static int colors_add_scheme(struct ul_color_ctl *cc, + char *name, + char *seq0) +{ + struct ul_color_scheme *cs = NULL; + char *seq = NULL; + int rc; + + if (!cc || !name || !*name || !seq0 || !*seq0) + return -EINVAL; + + DBG(SCHEME, ul_debug("add '%s'", name)); + + rc = cn_sequence(seq0, &seq); + if (rc) + return rc; + + rc = -ENOMEM; + + /* convert logical name (e.g. "red") to real ESC code */ + if (isalpha(*seq)) { + const char *s = color_sequence_from_colorname(seq); + char *p; + + if (!s) { + DBG(SCHEME, ul_debug("unknown logical name: %s", seq)); + rc = -EINVAL; + goto err; + } + + p = strdup(s); + if (!p) + goto err; + free(seq); + seq = p; + } + + /* enlarge the array */ + if (cc->nschemes == cc->schemes_sz) { + void *tmp = realloc(cc->schemes, (cc->nschemes + 10) + * sizeof(struct ul_color_scheme)); + if (!tmp) + goto err; + cc->schemes = tmp; + cc->schemes_sz = cc->nschemes + 10; + } + + /* add a new item */ + cs = &cc->schemes[cc->nschemes]; + cs->seq = seq; + cs->name = strdup(name); + if (!cs->name) + goto err; + + cc->nschemes++; + return 0; +err: + if (cs) { + free(cs->seq); + free(cs->name); + cs->seq = cs->name = NULL; + } else + free(seq); + return rc; +} + +/* + * Deallocates all regards to color schemes + */ +static void colors_free_schemes(struct ul_color_ctl *cc) +{ + size_t i; + + DBG(SCHEME, ul_debug("free scheme")); + + for (i = 0; i < cc->nschemes; i++) { + free(cc->schemes[i].name); + free(cc->schemes[i].seq); + } + + free(cc->schemes); + cc->schemes = NULL; + cc->nschemes = 0; + cc->schemes_sz = 0; +} + +/* + * The scheme configuration has to be sorted for bsearch + */ +static void colors_sort_schemes(struct ul_color_ctl *cc) +{ + if (!cc->nschemes) + return; + + DBG(SCHEME, ul_debug("sort scheme")); + + qsort(cc->schemes, cc->nschemes, + sizeof(struct ul_color_scheme), cmp_scheme_name); +} + +/* + * Returns just one color scheme + */ +static struct ul_color_scheme *colors_get_scheme(struct ul_color_ctl *cc, + const char *name) +{ + struct ul_color_scheme key = { .name = (char *) name}, *res; + + if (!cc || !name || !*name) + return NULL; + + if (!cc->cs_configured) { + int rc = colors_read_schemes(cc); + if (rc) + return NULL; + } + if (!cc->nschemes) + return NULL; + + DBG(SCHEME, ul_debug("search '%s'", name)); + + res = bsearch(&key, cc->schemes, cc->nschemes, + sizeof(struct ul_color_scheme), + cmp_scheme_name); + + return res && res->seq ? res : NULL; +} + +/* + * Parses filenames in terminal-colors.d + */ +static int colors_read_configuration(struct ul_color_ctl *cc) +{ + int rc = -ENOENT; + char *dirname, buf[PATH_MAX]; + + cc->termname = getenv("TERM"); + + dirname = colors_get_homedir(buf, sizeof(buf)); + if (dirname) + rc = colors_readdir(cc, dirname); /* ~/.config */ + if (rc == -EPERM || rc == -EACCES || rc == -ENOENT) + rc = colors_readdir(cc, _PATH_TERMCOLORS_DIR); /* /etc */ + + cc->configured = 1; + return rc; +} + +/* + * Reads terminal-colors.d/ scheme file into array schemes + */ +static int colors_read_schemes(struct ul_color_ctl *cc) +{ + int rc = 0; + FILE *f = NULL; + char buf[BUFSIZ], + cn[129], seq[129]; + + if (!cc->configured) + rc = colors_read_configuration(cc); + + cc->cs_configured = 1; + + if (rc || !cc->sfile) + goto done; + + DBG(SCHEME, ul_debug("reading file '%s'", cc->sfile)); + + f = fopen(cc->sfile, "r"); + if (!f) { + rc = -errno; + goto done; + } + + while (fgets(buf, sizeof(buf), f)) { + char *p = strchr(buf, '\n'); + + if (!p) { + if (feof(f)) + p = strchr(buf, '\0'); + else { + rc = -errno; + goto done; + } + } + *p = '\0'; + p = (char *) skip_blank(buf); + if (*p == '\0' || *p == '#') + continue; + + rc = sscanf(p, "%128[^ ] %128[^\n ]", cn, seq); + if (rc == 2 && *cn && *seq) { + rc = colors_add_scheme(cc, cn, seq); /* set rc=0 on success */ + if (rc) + goto done; + } + } + rc = 0; + +done: + if (f) + fclose(f); + colors_sort_schemes(cc); + + return rc; +} + + +static void termcolors_init_debug(void) +{ + __UL_INIT_DEBUG(termcolors, TERMCOLORS_DEBUG_, 0, TERMINAL_COLORS_DEBUG); +} + +/** + * colors_init: + * @mode: UL_COLORMODE_* + * @name: util argv[0] + * + * Initialize private color control struct and initialize the colors + * status. The color schemes are parsed on demand by colors_get_scheme(). + * + * Returns: >0 on success. + */ +int colors_init(int mode, const char *name) +{ + int atty = -1; + struct ul_color_ctl *cc = &ul_colors; + + cc->utilname = name; + cc->mode = mode; + + termcolors_init_debug(); + + if (mode == UL_COLORMODE_UNDEF && (atty = isatty(STDOUT_FILENO))) { + int rc = colors_read_configuration(cc); + if (rc) + cc->mode = UL_COLORMODE_AUTO; + else { + + /* evaluate scores */ + if (cc->scores[UL_COLORFILE_DISABLE] > + cc->scores[UL_COLORFILE_ENABLE]) + cc->mode = UL_COLORMODE_NEVER; + else + cc->mode = UL_COLORMODE_AUTO; + + atexit(colors_deinit); + } + } + + switch (cc->mode) { + case UL_COLORMODE_AUTO: + cc->has_colors = atty == -1 ? isatty(STDOUT_FILENO) : atty; + break; + case UL_COLORMODE_ALWAYS: + cc->has_colors = 1; + break; + case UL_COLORMODE_NEVER: + default: + cc->has_colors = 0; + } + + ON_DBG(CONF, colors_debug(cc)); + + return cc->has_colors; +} + +/* + * Temporary disable colors (this setting is independent on terminal-colors.d/) + */ +void colors_off(void) +{ + ul_colors.disabled = 1; +} + +/* + * Enable colors + */ +void colors_on(void) +{ + ul_colors.disabled = 0; +} + +/* + * Is terminal-colors.d/ configured to use colors? + */ +int colors_wanted(void) +{ + return ul_colors.has_colors; +} + +/* + * Enable @seq color + */ +void color_fenable(const char *seq, FILE *f) +{ + if (!ul_colors.disabled && ul_colors.has_colors && seq) + fputs(seq, f); +} + +/* + * Returns escape sequence by logical @name, if undefined then returns @dflt. + */ +const char *color_scheme_get_sequence(const char *name, const char *dflt) +{ + struct ul_color_scheme *cs; + + if (ul_colors.disabled || !ul_colors.has_colors) + return NULL; + + cs = colors_get_scheme(&ul_colors, name); + return cs && cs->seq ? cs->seq : dflt; +} + +/* + * Enable color by logical @name, if undefined enable @dflt. + */ +void color_scheme_fenable(const char *name, const char *dflt, FILE *f) +{ + const char *seq = color_scheme_get_sequence(name, dflt); + + if (!seq) + return; + color_fenable(seq, f); +} + + +/* + * Disable previously enabled color + */ +void color_fdisable(FILE *f) +{ + if (!ul_colors.disabled && ul_colors.has_colors) + fputs(UL_COLOR_RESET, f); +} + +/* + * Parses @str to return UL_COLORMODE_* + */ +int colormode_from_string(const char *str) +{ + size_t i; + static const char *modes[] = { + [UL_COLORMODE_AUTO] = "auto", + [UL_COLORMODE_NEVER] = "never", + [UL_COLORMODE_ALWAYS] = "always", + [UL_COLORMODE_UNDEF] = "" + }; + + if (!str || !*str) + return -EINVAL; + + assert(ARRAY_SIZE(modes) == __UL_NCOLORMODES); + + for (i = 0; i < ARRAY_SIZE(modes); i++) { + if (strcasecmp(str, modes[i]) == 0) + return i; + } + + return -EINVAL; +} + +/* + * Parses @str and exit(EXIT_FAILURE) on error + */ +int colormode_or_err(const char *str, const char *errmsg) +{ + const char *p = str && *str == '=' ? str + 1 : str; + int colormode; + + colormode = colormode_from_string(p); + if (colormode < 0) + errx(EXIT_FAILURE, "%s: '%s'", errmsg, p); + + return colormode; +} + +#ifdef TEST_PROGRAM +# include <getopt.h> +int main(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "mode", required_argument, 0, 'm' }, + { "color", required_argument, 0, 'c' }, + { "color-scheme", required_argument, 0, 'C' }, + { "name", required_argument, 0, 'n' }, + { NULL, 0, 0, 0 } + }; + int c, mode = UL_COLORMODE_UNDEF; /* default */ + const char *color = "red", *name = NULL, *color_scheme = NULL; + const char *seq = NULL; + + while ((c = getopt_long(argc, argv, "C:c:m:n:", longopts, NULL)) != -1) { + switch (c) { + case 'c': + color = optarg; + break; + case 'C': + color_scheme = optarg; + break; + case 'm': + mode = colormode_or_err(optarg, "unsupported color mode"); + break; + case 'n': + name = optarg; + break; + default: + fprintf(stderr, "usage: %s [options]\n" + " -m, --mode <auto|never|always> default is undefined\n" + " -c, --color <red|blue|...> color for the test message\n" + " -C, --color-scheme <name> color for the test message\n" + " -n, --name <utilname> util name\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + } + + colors_init(mode, name ? name : program_invocation_short_name); + + seq = color_sequence_from_colorname(color); + + if (color_scheme) + color_scheme_enable(color_scheme, seq); + else + color_enable(seq); + printf("Hello World!"); + color_disable(); + fputc('\n', stdout); + + return EXIT_SUCCESS; +} +#endif + diff --git a/libblkid/lib/cpuset.c b/libblkid/lib/cpuset.c new file mode 100644 index 000000000..d715720e3 --- /dev/null +++ b/libblkid/lib/cpuset.c @@ -0,0 +1,403 @@ +/* + * Terminology: + * + * cpuset - (libc) cpu_set_t data structure represents set of CPUs + * cpumask - string with hex mask (e.g. "0x00000001") + * cpulist - string with CPU ranges (e.g. "0-3,5,7,8") + * + * Based on code from taskset.c and Linux kernel. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Copyright (C) 2010 Karel Zak <kzak@redhat.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <sys/syscall.h> + +#include "cpuset.h" +#include "c.h" + +static inline int val_to_char(int v) +{ + if (v >= 0 && v < 10) + return '0' + v; + else if (v >= 10 && v < 16) + return ('a' - 10) + v; + else + return -1; +} + +static inline int char_to_val(int c) +{ + int cl; + + cl = tolower(c); + if (c >= '0' && c <= '9') + return c - '0'; + else if (cl >= 'a' && cl <= 'f') + return cl + (10 - 'a'); + else + return -1; +} + +static const char *nexttoken(const char *q, int sep) +{ + if (q) + q = strchr(q, sep); + if (q) + q++; + return q; +} + +/* + * Number of bits in a CPU bitmask on current system + */ +int get_max_number_of_cpus(void) +{ +#ifdef SYS_sched_getaffinity + int n, cpus = 2048; + size_t setsize; + cpu_set_t *set = cpuset_alloc(cpus, &setsize, NULL); + + if (!set) + return -1; /* error */ + + for (;;) { + CPU_ZERO_S(setsize, set); + + /* the library version does not return size of cpumask_t */ + n = syscall(SYS_sched_getaffinity, 0, setsize, set); + + if (n < 0 && errno == EINVAL && cpus < 1024 * 1024) { + cpuset_free(set); + cpus *= 2; + set = cpuset_alloc(cpus, &setsize, NULL); + if (!set) + return -1; /* error */ + continue; + } + cpuset_free(set); + return n * 8; + } +#endif + return -1; +} + +/* + * Allocates a new set for ncpus and returns size in bytes and size in bits + */ +cpu_set_t *cpuset_alloc(int ncpus, size_t *setsize, size_t *nbits) +{ + cpu_set_t *set = CPU_ALLOC(ncpus); + + if (!set) + return NULL; + if (setsize) + *setsize = CPU_ALLOC_SIZE(ncpus); + if (nbits) + *nbits = cpuset_nbits(CPU_ALLOC_SIZE(ncpus)); + return set; +} + +void cpuset_free(cpu_set_t *set) +{ + CPU_FREE(set); +} + +#if !HAVE_DECL_CPU_ALLOC +/* Please, use CPU_COUNT_S() macro. This is fallback */ +int __cpuset_count_s(size_t setsize, const cpu_set_t *set) +{ + int s = 0; + const __cpu_mask *p = set->__bits; + const __cpu_mask *end = &set->__bits[setsize / sizeof (__cpu_mask)]; + + while (p < end) { + __cpu_mask l = *p++; + + if (l == 0) + continue; +# if LONG_BIT > 32 + l = (l & 0x5555555555555555ul) + ((l >> 1) & 0x5555555555555555ul); + l = (l & 0x3333333333333333ul) + ((l >> 2) & 0x3333333333333333ul); + l = (l & 0x0f0f0f0f0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0f0f0f0f0ful); + l = (l & 0x00ff00ff00ff00fful) + ((l >> 8) & 0x00ff00ff00ff00fful); + l = (l & 0x0000ffff0000fffful) + ((l >> 16) & 0x0000ffff0000fffful); + l = (l & 0x00000000fffffffful) + ((l >> 32) & 0x00000000fffffffful); +# else + l = (l & 0x55555555ul) + ((l >> 1) & 0x55555555ul); + l = (l & 0x33333333ul) + ((l >> 2) & 0x33333333ul); + l = (l & 0x0f0f0f0ful) + ((l >> 4) & 0x0f0f0f0ful); + l = (l & 0x00ff00fful) + ((l >> 8) & 0x00ff00fful); + l = (l & 0x0000fffful) + ((l >> 16) & 0x0000fffful); +# endif + s += l; + } + return s; +} +#endif + +/* + * Returns human readable representation of the cpuset. The output format is + * a list of CPUs with ranges (for example, "0,1,3-9"). + */ +char *cpulist_create(char *str, size_t len, + cpu_set_t *set, size_t setsize) +{ + size_t i; + char *ptr = str; + int entry_made = 0; + size_t max = cpuset_nbits(setsize); + + for (i = 0; i < max; i++) { + if (CPU_ISSET_S(i, setsize, set)) { + int rlen; + size_t j, run = 0; + entry_made = 1; + for (j = i + 1; j < max; j++) { + if (CPU_ISSET_S(j, setsize, set)) + run++; + else + break; + } + if (!run) + rlen = snprintf(ptr, len, "%zd,", i); + else if (run == 1) { + rlen = snprintf(ptr, len, "%zd,%zd,", i, i + 1); + i++; + } else { + rlen = snprintf(ptr, len, "%zd-%zd,", i, i + run); + i += run; + } + if (rlen < 0 || (size_t) rlen + 1 > len) + return NULL; + ptr += rlen; + if (rlen > 0 && len > (size_t) rlen) + len -= rlen; + else + len = 0; + } + } + ptr -= entry_made; + *ptr = '\0'; + + return str; +} + +/* + * Returns string with CPU mask. + */ +char *cpumask_create(char *str, size_t len, + cpu_set_t *set, size_t setsize) +{ + char *ptr = str; + char *ret = NULL; + int cpu; + + for (cpu = cpuset_nbits(setsize) - 4; cpu >= 0; cpu -= 4) { + char val = 0; + + if (len == (size_t) (ptr - str)) + break; + + if (CPU_ISSET_S(cpu, setsize, set)) + val |= 1; + if (CPU_ISSET_S(cpu + 1, setsize, set)) + val |= 2; + if (CPU_ISSET_S(cpu + 2, setsize, set)) + val |= 4; + if (CPU_ISSET_S(cpu + 3, setsize, set)) + val |= 8; + + if (!ret && val) + ret = ptr; + *ptr++ = val_to_char(val); + } + *ptr = '\0'; + return ret ? ret : ptr - 1; +} + +/* + * Parses string with CPUs mask. + */ +int cpumask_parse(const char *str, cpu_set_t *set, size_t setsize) +{ + int len = strlen(str); + const char *ptr = str + len - 1; + int cpu = 0; + + /* skip 0x, it's all hex anyway */ + if (len > 1 && !memcmp(str, "0x", 2L)) + str += 2; + + CPU_ZERO_S(setsize, set); + + while (ptr >= str) { + char val; + + /* cpu masks in /sys uses comma as a separator */ + if (*ptr == ',') + ptr--; + + val = char_to_val(*ptr); + if (val == (char) -1) + return -1; + if (val & 1) + CPU_SET_S(cpu, setsize, set); + if (val & 2) + CPU_SET_S(cpu + 1, setsize, set); + if (val & 4) + CPU_SET_S(cpu + 2, setsize, set); + if (val & 8) + CPU_SET_S(cpu + 3, setsize, set); + len--; + ptr--; + cpu += 4; + } + + return 0; +} + +/* + * Parses string with list of CPU ranges. + * Returns 0 on success. + * Returns 1 on error. + * Returns 2 if fail is set and a cpu number passed in the list doesn't fit + * into the cpu_set. If fail is not set cpu numbers that do not fit are + * ignored and 0 is returned instead. + */ +int cpulist_parse(const char *str, cpu_set_t *set, size_t setsize, int fail) +{ + size_t max = cpuset_nbits(setsize); + const char *p, *q; + int r = 0; + + q = str; + CPU_ZERO_S(setsize, set); + + while (p = q, q = nexttoken(q, ','), p) { + unsigned int a; /* beginning of range */ + unsigned int b; /* end of range */ + unsigned int s; /* stride */ + const char *c1, *c2; + char c; + + if ((r = sscanf(p, "%u%c", &a, &c)) < 1) + return 1; + b = a; + s = 1; + + c1 = nexttoken(p, '-'); + c2 = nexttoken(p, ','); + if (c1 != NULL && (c2 == NULL || c1 < c2)) { + if ((r = sscanf(c1, "%u%c", &b, &c)) < 1) + return 1; + c1 = nexttoken(c1, ':'); + if (c1 != NULL && (c2 == NULL || c1 < c2)) { + if ((r = sscanf(c1, "%u%c", &s, &c)) < 1) + return 1; + if (s == 0) + return 1; + } + } + + if (!(a <= b)) + return 1; + while (a <= b) { + if (fail && (a >= max)) + return 2; + CPU_SET_S(a, setsize, set); + a += s; + } + } + + if (r == 2) + return 1; + return 0; +} + +#ifdef TEST_PROGRAM + +#include <getopt.h> + +int main(int argc, char *argv[]) +{ + cpu_set_t *set; + size_t setsize, buflen, nbits; + char *buf, *mask = NULL, *range = NULL; + int ncpus = 2048, rc, c; + + static const struct option longopts[] = { + { "ncpus", 1, 0, 'n' }, + { "mask", 1, 0, 'm' }, + { "range", 1, 0, 'r' }, + { NULL, 0, 0, 0 } + }; + + while ((c = getopt_long(argc, argv, "n:m:r:", longopts, NULL)) != -1) { + switch(c) { + case 'n': + ncpus = atoi(optarg); + break; + case 'm': + mask = strdup(optarg); + break; + case 'r': + range = strdup(optarg); + break; + default: + goto usage_err; + } + } + + if (!mask && !range) + goto usage_err; + + set = cpuset_alloc(ncpus, &setsize, &nbits); + if (!set) + err(EXIT_FAILURE, "failed to allocate cpu set"); + + /* + fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n", + ncpus, nbits, setsize); + */ + + buflen = 7 * nbits; + buf = malloc(buflen); + if (!buf) + err(EXIT_FAILURE, "failed to allocate cpu set buffer"); + + if (mask) + rc = cpumask_parse(mask, set, setsize); + else + rc = cpulist_parse(range, set, setsize, 0); + + if (rc) + errx(EXIT_FAILURE, "failed to parse string: %s", mask ? : range); + + printf("%-15s = %15s ", mask ? : range, + cpumask_create(buf, buflen, set, setsize)); + printf("[%s]\n", cpulist_create(buf, buflen, set, setsize)); + + free(buf); + free(mask); + free(range); + cpuset_free(set); + + return EXIT_SUCCESS; + +usage_err: + fprintf(stderr, + "usage: %s [--ncpus <num>] --mask <mask> | --range <list>", + program_invocation_short_name); + exit(EXIT_FAILURE); +} +#endif diff --git a/libblkid/lib/crc32.c b/libblkid/lib/crc32.c new file mode 100644 index 000000000..be98f1a8d --- /dev/null +++ b/libblkid/lib/crc32.c @@ -0,0 +1,118 @@ +/* + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1. + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way, + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly. + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera- + * tions for all combinations of data and CRC register values. + * + * The values must be right-shifted by eight bits by the "updcrc" + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions. + * polynomial $edb88320 + * + */ + +#include <stdio.h> + +#include "crc32.h" + + +static const uint32_t crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* + * This a generic crc32() function, it takes seed as an argument, + * and does __not__ xor at the end. Then individual users can do + * whatever they need. + */ +uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len) +{ + uint32_t crc = seed; + const unsigned char *p = buf; + + while (len) { + crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); + len--; + } + + return crc; +} + diff --git a/libblkid/lib/crc64.c b/libblkid/lib/crc64.c new file mode 100644 index 000000000..0be78e63b --- /dev/null +++ b/libblkid/lib/crc64.c @@ -0,0 +1,109 @@ +#include "crc64.h" + +static const uint64_t crc64_tab[256] = { + 0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL, + 0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL, + 0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL, + 0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL, + 0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL, + 0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL, + 0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL, + 0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL, + 0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL, + 0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL, + 0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL, + 0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL, + 0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL, + 0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL, + 0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL, + 0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL, + 0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL, + 0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL, + 0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL, + 0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL, + 0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL, + 0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL, + 0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL, + 0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL, + 0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL, + 0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL, + 0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL, + 0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL, + 0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL, + 0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL, + 0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL, + 0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL, + 0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL, + 0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL, + 0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL, + 0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL, + 0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL, + 0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL, + 0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL, + 0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL, + 0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL, + 0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL, + 0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL, + 0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL, + 0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL, + 0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL, + 0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL, + 0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL, + 0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL, + 0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL, + 0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL, + 0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL, + 0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL, + 0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL, + 0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL, + 0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL, + 0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL, + 0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL, + 0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL, + 0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL, + 0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL, + 0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL, + 0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL, + 0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL, + 0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL, + 0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL, + 0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL, + 0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL, + 0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL, + 0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL, + 0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL, + 0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL, + 0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL, + 0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL, + 0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL, + 0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL, + 0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL, + 0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL, + 0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL, + 0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL, + 0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL, + 0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL, + 0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL, + 0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL, + 0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL, + 0x9AFCE626CE85B507ULL +}; + +/* + * This a generic crc64() function, it takes seed as an argument, + * and does __not__ xor at the end. Then individual users can do + * whatever they need. + */ +uint64_t crc64(uint64_t seed, const unsigned char *data, size_t len) +{ + uint64_t crc = seed; + + while (len) { + int i = ((int) (crc >> 56) ^ *data++) & 0xFF; + crc = crc64_tab[i] ^ (crc << 8); + len--; + } + + return crc; +} + diff --git a/libblkid/env.c b/libblkid/lib/env.c index c79e0e0de..c79e0e0de 100644 --- a/libblkid/env.c +++ b/libblkid/lib/env.c diff --git a/libblkid/lib/exec_shell.c b/libblkid/lib/exec_shell.c new file mode 100644 index 000000000..2b263644d --- /dev/null +++ b/libblkid/lib/exec_shell.c @@ -0,0 +1,46 @@ +/* + * exec_shell() - launch a shell, else exit! + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + +#include "nls.h" +#include "c.h" +#include "xalloc.h" + +#include "exec_shell.h" + +#define DEFAULT_SHELL "/bin/sh" + +void exec_shell(void) +{ + const char *shell = getenv("SHELL"), *shell_basename; + char *arg0; + if (!shell) + shell = DEFAULT_SHELL; + + shell_basename = basename(shell); + arg0 = xmalloc(strlen(shell_basename) + 2); + arg0[0] = '-'; + strcpy(arg0 + 1, shell_basename); + + execl(shell, arg0, NULL); + err(EXIT_FAILURE, _("failed to execute %s"), shell); +} diff --git a/libblkid/lib/fileutils.c b/libblkid/lib/fileutils.c new file mode 100644 index 000000000..4e884d39a --- /dev/null +++ b/libblkid/lib/fileutils.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 Sami Kerola <kerolasa@iki.fi> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <paths.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include "c.h" +#include "fileutils.h" +#include "pathnames.h" + +/* Create open temporary file in safe way. Please notice that the + * file permissions are -rw------- by default. */ +int xmkstemp(char **tmpname, char *dir) +{ + char *localtmp; + char *tmpenv; + mode_t old_mode; + int fd, rc; + + /* Some use cases must be capable of being moved atomically + * with rename(2), which is the reason why dir is here. */ + if (dir != NULL) + tmpenv = dir; + else + tmpenv = getenv("TMPDIR"); + + if (tmpenv) + rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, + program_invocation_short_name); + else + rc = asprintf(&localtmp, "%s/%s.XXXXXX", _PATH_TMP, + program_invocation_short_name); + + if (rc < 0) + return -1; + + old_mode = umask(077); + fd = mkstemp(localtmp); + umask(old_mode); + if (fd == -1) { + free(localtmp); + localtmp = NULL; + } + *tmpname = localtmp; + return fd; +} + +/* + * portable getdtablesize() + */ +int get_fd_tabsize(void) +{ + int m; + +#if defined(HAVE_GETDTABLESIZE) + m = getdtablesize(); +#elif defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit rl; + + getrlimit(RLIMIT_NOFILE, &rl); + m = rl.rlim_cur; +#elif defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) + m = sysconf(_SC_OPEN_MAX); +#else + m = OPEN_MAX; +#endif + return m; +} + +#ifdef TEST_PROGRAM +int main(void) +{ + FILE *f; + char *tmpname; + f = xfmkstemp(&tmpname, NULL); + unlink(tmpname); + free(tmpname); + fclose(f); + return EXIT_FAILURE; +} +#endif + + +int mkdir_p(const char *path, mode_t mode) +{ + char *p, *dir; + int rc = 0; + + if (!path || !*path) + return -EINVAL; + + dir = p = strdup(path); + if (!dir) + return -ENOMEM; + + if (*p == '/') + p++; + + while (p && *p) { + char *e = strchr(p, '/'); + if (e) + *e = '\0'; + if (*p) { + rc = mkdir(dir, mode); + if (rc && errno != EEXIST) + break; + rc = 0; + } + if (!e) + break; + *e = '/'; + p = e + 1; + } + + free(dir); + return rc; +} + +/* returns basename and keeps dirname in the @path, if @path is "/" (root) + * then returns empty string */ +char *stripoff_last_component(char *path) +{ + char *p = path ? strrchr(path, '/') : NULL; + + if (!p) + return NULL; + *p = '\0'; + return p + 1; +} diff --git a/libblkid/lib/ismounted.c b/libblkid/lib/ismounted.c new file mode 100644 index 000000000..8099bd7d5 --- /dev/null +++ b/libblkid/lib/ismounted.c @@ -0,0 +1,388 @@ +/* + * ismounted.c --- Check to see if the filesystem was mounted + * + * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o. + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#ifdef HAVE_MNTENT_H +#include <mntent.h> +#endif +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> +#include <sys/param.h> +#ifdef __APPLE__ +#include <sys/ucred.h> +#include <sys/mount.h> +#endif + +#include "pathnames.h" +#include "ismounted.h" +#include "c.h" +#ifdef __linux__ +# include "loopdev.h" +#endif + + + +#ifdef HAVE_MNTENT_H +/* + * Helper function which checks a file in /etc/mtab format to see if a + * filesystem is mounted. Returns an error if the file doesn't exist + * or can't be opened. + */ +static int check_mntent_file(const char *mtab_file, const char *file, + int *mount_flags, char *mtpt, int mtlen) +{ + struct mntent *mnt; + struct stat st_buf; + int retval = 0; + dev_t file_dev=0, file_rdev=0; + ino_t file_ino=0; + FILE *f; + int fd; + + *mount_flags = 0; + if ((f = setmntent (mtab_file, "r")) == NULL) + return errno; + + if (stat(file, &st_buf) == 0) { + if (S_ISBLK(st_buf.st_mode)) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + file_rdev = st_buf.st_rdev; +#endif /* __GNU__ */ + } else { + file_dev = st_buf.st_dev; + file_ino = st_buf.st_ino; + } + } + + while ((mnt = getmntent (f)) != NULL) { + if (mnt->mnt_fsname[0] != '/') + continue; + if (strcmp(file, mnt->mnt_fsname) == 0) + break; + if (stat(mnt->mnt_fsname, &st_buf) != 0) + continue; + + if (S_ISBLK(st_buf.st_mode)) { +#ifndef __GNU__ + if (file_rdev && file_rdev == st_buf.st_rdev) + break; +#ifdef __linux__ + /* maybe the file is loopdev backing file */ + if (file_dev + && major(st_buf.st_rdev) == LOOPDEV_MAJOR + && loopdev_is_used(mnt->mnt_fsname, file, 0, 0)) + break; +#endif /* __linux__ */ +#endif /* __GNU__ */ + } else { + if (file_dev && ((file_dev == st_buf.st_dev) && + (file_ino == st_buf.st_ino))) + break; + } + } + + if (mnt == NULL) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + /* + * Do an extra check to see if this is the root device. We + * can't trust /etc/mtab, and /proc/mounts will only list + * /dev/root for the root filesystem. Argh. Instead we + * check if the given device has the same major/minor number + * as the device that the root directory is on. + */ + if (file_rdev && stat("/", &st_buf) == 0 && + st_buf.st_dev == file_rdev) { + *mount_flags = MF_MOUNTED; + if (mtpt) + strncpy(mtpt, "/", mtlen); + goto is_root; + } +#endif /* __GNU__ */ + goto errout; + } +#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ + /* Validate the entry in case /etc/mtab is out of date */ + /* + * We need to be paranoid, because some broken distributions + * (read: Slackware) don't initialize /etc/mtab before checking + * all of the non-root filesystems on the disk. + */ + if (stat(mnt->mnt_dir, &st_buf) < 0) { + retval = errno; + if (retval == ENOENT) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s does not exist)\n", + mtab_file, mnt->mnt_dir); +#endif /* DEBUG */ + retval = 0; + } + goto errout; + } + if (file_rdev && (st_buf.st_dev != file_rdev)) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s not mounted on %s)\n", + mtab_file, file, mnt->mnt_dir); +#endif /* DEBUG */ + goto errout; + } +#endif /* __GNU__ */ + *mount_flags = MF_MOUNTED; + +#ifdef MNTOPT_RO + /* Check to see if the ro option is set */ + if (hasmntopt(mnt, MNTOPT_RO)) + *mount_flags |= MF_READONLY; +#endif + + if (mtpt) + strncpy(mtpt, mnt->mnt_dir, mtlen); + /* + * Check to see if we're referring to the root filesystem. + * If so, do a manual check to see if we can open /etc/mtab + * read/write, since if the root is mounted read/only, the + * contents of /etc/mtab may not be accurate. + */ + if (!strcmp(mnt->mnt_dir, "/")) { +is_root: +#define TEST_FILE "/.ismount-test-file" + *mount_flags |= MF_ISROOT; + fd = open(TEST_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0600); + if (fd < 0) { + if (errno == EROFS) + *mount_flags |= MF_READONLY; + } else + close(fd); + (void) unlink(TEST_FILE); + } + retval = 0; +errout: + endmntent (f); + return retval; +} + +static int check_mntent(const char *file, int *mount_flags, + char *mtpt, int mtlen) +{ + int retval; + +#ifdef DEBUG + retval = check_mntent_file("/tmp/mtab", file, mount_flags, + mtpt, mtlen); + if (retval == 0) + return 0; +#endif /* DEBUG */ +#ifdef __linux__ + retval = check_mntent_file("/proc/mounts", file, mount_flags, + mtpt, mtlen); + if (retval == 0 && (*mount_flags != 0)) + return 0; + if (access("/proc/mounts", R_OK) == 0) { + *mount_flags = 0; + return retval; + } +#endif /* __linux__ */ +#if defined(MOUNTED) || defined(_PATH_MOUNTED) +#ifndef MOUNTED +#define MOUNTED _PATH_MOUNTED +#endif /* MOUNTED */ + retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); + return retval; +#else + *mount_flags = 0; + return 0; +#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */ +} + +#else +#if defined(HAVE_GETMNTINFO) + +static int check_getmntinfo(const char *file, int *mount_flags, + char *mtpt, int mtlen) +{ + struct statfs *mp; + int len, n; + const char *s1; + char *s2; + + n = getmntinfo(&mp, MNT_NOWAIT); + if (n == 0) + return errno; + + len = sizeof(_PATH_DEV) - 1; + s1 = file; + if (strncmp(_PATH_DEV, s1, len) == 0) + s1 += len; + + *mount_flags = 0; + while (--n >= 0) { + s2 = mp->f_mntfromname; + if (strncmp(_PATH_DEV, s2, len) == 0) { + s2 += len - 1; + *s2 = 'r'; + } + if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { + *mount_flags = MF_MOUNTED; + break; + } + ++mp; + } + if (mtpt) + strncpy(mtpt, mp->f_mntonname, mtlen); + return 0; +} +#endif /* HAVE_GETMNTINFO */ +#endif /* HAVE_MNTENT_H */ + +/* + * Check to see if we're dealing with the swap device. + */ +static int is_swap_device(const char *file) +{ + FILE *f; + char buf[1024], *cp; + dev_t file_dev; + struct stat st_buf; + int ret = 0; + + file_dev = 0; +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + if ((stat(file, &st_buf) == 0) && + S_ISBLK(st_buf.st_mode)) + file_dev = st_buf.st_rdev; +#endif /* __GNU__ */ + + if (!(f = fopen("/proc/swaps", "r"))) + return 0; + /* Skip the first line */ + if (!fgets(buf, sizeof(buf), f)) + goto leave; + if (*buf && strncmp(buf, "Filename\t", 9)) + /* Linux <=2.6.19 contained a bug in the /proc/swaps + * code where the header would not be displayed + */ + goto valid_first_line; + + while (fgets(buf, sizeof(buf), f)) { +valid_first_line: + if ((cp = strchr(buf, ' ')) != NULL) + *cp = 0; + if ((cp = strchr(buf, '\t')) != NULL) + *cp = 0; + if (strcmp(buf, file) == 0) { + ret++; + break; + } +#ifndef __GNU__ + if (file_dev && (stat(buf, &st_buf) == 0) && + S_ISBLK(st_buf.st_mode) && + file_dev == st_buf.st_rdev) { + ret++; + break; + } +#endif /* __GNU__ */ + } + +leave: + fclose(f); + return ret; +} + + +/* + * check_mount_point() fills determines if the device is mounted or otherwise + * busy, and fills in mount_flags with one or more of the following flags: + * MF_MOUNTED, MF_ISROOT, MF_READONLY, MF_SWAP, and MF_BUSY. If mtpt is + * non-NULL, the directory where the device is mounted is copied to where mtpt + * is pointing, up to mtlen characters. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +int check_mount_point(const char *device, int *mount_flags, + char *mtpt, int mtlen) +{ + struct stat st_buf; + int retval = 0; + int fd; + + if (is_swap_device(device)) { + *mount_flags = MF_MOUNTED | MF_SWAP; + if (mtpt && mtlen) + strncpy(mtpt, "[SWAP]", mtlen); + } else { +#ifdef HAVE_MNTENT_H + retval = check_mntent(device, mount_flags, mtpt, mtlen); +#else +#ifdef HAVE_GETMNTINFO + retval = check_getmntinfo(device, mount_flags, mtpt, mtlen); +#else +#ifdef __GNUC__ + #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" +#endif + *mount_flags = 0; +#endif /* HAVE_GETMNTINFO */ +#endif /* HAVE_MNTENT_H */ + } + if (retval) + return retval; + +#ifdef __linux__ /* This only works on Linux 2.6+ systems */ + if ((stat(device, &st_buf) != 0) || + !S_ISBLK(st_buf.st_mode)) + return 0; + fd = open(device, O_RDONLY|O_EXCL|O_CLOEXEC); + if (fd < 0) { + if (errno == EBUSY) + *mount_flags |= MF_BUSY; + } else + close(fd); +#endif + + return 0; +} + +int is_mounted(const char *file) +{ + int retval; + int mount_flags = 0; + + retval = check_mount_point(file, &mount_flags, NULL, 0); + if (retval) + return 0; + return mount_flags & MF_MOUNTED; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + int flags = 0; + char devname[PATH_MAX]; + + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n", argv[0]); + return EXIT_FAILURE; + } + + if (check_mount_point(argv[1], &flags, devname, sizeof(devname)) == 0 && + (flags & MF_MOUNTED)) { + if (flags & MF_SWAP) + printf("used swap device\n"); + else + printf("mounted on %s\n", devname); + return EXIT_SUCCESS; + } + + printf("not mounted\n"); + return EXIT_FAILURE; +} +#endif /* DEBUG */ diff --git a/libblkid/langinfo.c b/libblkid/lib/langinfo.c index deeab9b11..deeab9b11 100644 --- a/libblkid/langinfo.c +++ b/libblkid/lib/langinfo.c diff --git a/libblkid/linux_version.c b/libblkid/lib/linux_version.c index 2bcc2cc65..2bcc2cc65 100644 --- a/libblkid/linux_version.c +++ b/libblkid/lib/linux_version.c diff --git a/libblkid/lib/loopdev.c b/libblkid/lib/loopdev.c new file mode 100644 index 000000000..09b9bbf75 --- /dev/null +++ b/libblkid/lib/loopdev.c @@ -0,0 +1,1572 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + * + * -- based on mount/losetup.c + * + * Simple library for work with loop devices. + * + * - requires kernel 2.6.x + * - reads info from /sys/block/loop<N>/loop/<attr> (new kernels) + * - reads info by ioctl + * - supports *unlimited* number of loop devices + * - supports /dev/loop<N> as well as /dev/loop/<N> + * - minimize overhead (fd, loopinfo, ... are shared for all operations) + * - setup (associate device and backing file) + * - delete (dis-associate file) + * - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported + * - extendible + */ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/sysmacros.h> +#include <inttypes.h> +#include <dirent.h> +#include <linux/posix_types.h> + +#include "linux_version.h" +#include "c.h" +#include "sysfs.h" +#include "pathnames.h" +#include "loopdev.h" +#include "canonicalize.h" +#include "at.h" +#include "blkdev.h" +#include "debug.h" + +/* + * Debug stuff (based on include/debug.h) + */ +UL_DEBUG_DEFINE_MASK(loopdev); +UL_DEBUG_DEFINE_MASKNAMES(loopdev) = UL_DEBUG_EMPTY_MASKNAMES; + +#define LOOPDEV_DEBUG_INIT (1 << 1) +#define LOOPDEV_DEBUG_CXT (1 << 2) +#define LOOPDEV_DEBUG_ITER (1 << 3) +#define LOOPDEV_DEBUG_SETUP (1 << 4) +#define SFDISKPROG_DEBUG_ALL 0xFFFF + +#define DBG(m, x) __UL_DBG(loopdev, LOOPDEV_DEBUG_, m, x) +#define ON_DBG(m, x) __UL_DBG_CALL(loopdev, LOOPDEV_DEBUG_, m, x) + +static void loopdev_init_debug(void) +{ + if (loopdev_debug_mask) + return; + __UL_INIT_DEBUG(loopdev, LOOPDEV_DEBUG_, 0, LOOPDEV_DEBUG); +} + +/* + * see loopcxt_init() + */ +#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL)) +#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \ + && !loopcxt_ioctl_enabled(_lc) + +/* + * @lc: context + * @device: device name, absolute device path or NULL to reset the current setting + * + * Sets device, absolute paths (e.g. "/dev/loop<N>") are unchanged, device + * names ("loop<N>") are converted to the path (/dev/loop<N> or to + * /dev/loop/<N>) + * + * This sets the device name, but does not check if the device exists! + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) +{ + if (!lc) + return -EINVAL; + + if (lc->fd >= 0) { + close(lc->fd); + DBG(CXT, ul_debugobj(lc, "closing old open fd")); + } + lc->fd = -1; + lc->mode = 0; + lc->has_info = 0; + lc->info_failed = 0; + *lc->device = '\0'; + memset(&lc->info, 0, sizeof(lc->info)); + + /* set new */ + if (device) { + if (*device != '/') { + const char *dir = _PATH_DEV; + + /* compose device name for /dev/loop<n> or /dev/loop/<n> */ + if (lc->flags & LOOPDEV_FL_DEVSUBDIR) { + if (strlen(device) < 5) + return -1; + device += 4; + dir = _PATH_DEV_LOOP "/"; /* _PATH_DEV uses tailing slash */ + } + snprintf(lc->device, sizeof(lc->device), "%s%s", + dir, device); + } else { + strncpy(lc->device, device, sizeof(lc->device)); + lc->device[sizeof(lc->device) - 1] = '\0'; + } + DBG(CXT, ul_debugobj(lc, "%s name assigned", device)); + } + + sysfs_deinit(&lc->sysfs); + return 0; +} + +int loopcxt_has_device(struct loopdev_cxt *lc) +{ + return lc && *lc->device; +} + +/* + * @lc: context + * @flags: LOOPDEV_FL_* flags + * + * Initilize loop handler. + * + * We have two sets of the flags: + * + * * LOOPDEV_FL_* flags control loopcxt_* API behavior + * + * * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls + * + * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2) + * syscall to open loop device. By default is the device open read-only. + * + * The expection is loopcxt_setup_device(), where the device is open read-write + * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()). + * + * Returns: <0 on error, 0 on success. + */ +int loopcxt_init(struct loopdev_cxt *lc, int flags) +{ + int rc; + struct stat st; + struct loopdev_cxt dummy = UL_LOOPDEVCXT_EMPTY; + + if (!lc) + return -EINVAL; + + loopdev_init_debug(); + DBG(CXT, ul_debugobj(lc, "initialize context")); + + memcpy(lc, &dummy, sizeof(dummy)); + lc->flags = flags; + + rc = loopcxt_set_device(lc, NULL); + if (rc) + return rc; + + if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) { + lc->flags |= LOOPDEV_FL_NOSYSFS; + lc->flags &= ~LOOPDEV_FL_NOIOCTL; + DBG(CXT, ul_debugobj(lc, "init: disable /sys usage")); + } + + if (!(lc->flags & LOOPDEV_FL_NOSYSFS) && + get_linux_version() >= KERNEL_VERSION(2,6,37)) { + /* + * Use only sysfs for basic information about loop devices + */ + lc->flags |= LOOPDEV_FL_NOIOCTL; + DBG(CXT, ul_debugobj(lc, "init: ignore ioctls")); + } + + if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) { + lc->flags |= LOOPDEV_FL_CONTROL; + DBG(CXT, ul_debugobj(lc, "init: loop-control detected ")); + } + + return 0; +} + +/* + * @lc: context + * + * Deinitialize loop context + */ +void loopcxt_deinit(struct loopdev_cxt *lc) +{ + int errsv = errno; + + if (!lc) + return; + + DBG(CXT, ul_debugobj(lc, "de-initialize")); + + free(lc->filename); + lc->filename = NULL; + + ignore_result( loopcxt_set_device(lc, NULL) ); + loopcxt_deinit_iterator(lc); + + errno = errsv; +} + +/* + * @lc: context + * + * Returns newly allocated device path. + */ +char *loopcxt_strdup_device(struct loopdev_cxt *lc) +{ + if (!lc || !*lc->device) + return NULL; + return strdup(lc->device); +} + +/* + * @lc: context + * + * Returns pointer device name in the @lc struct. + */ +const char *loopcxt_get_device(struct loopdev_cxt *lc) +{ + return lc && *lc->device ? lc->device : NULL; +} + +/* + * @lc: context + * + * Returns pointer to the sysfs context (see lib/sysfs.c) + */ +struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc) +{ + if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS)) + return NULL; + + if (!lc->sysfs.devno) { + dev_t devno = sysfs_devname_to_devno(lc->device, NULL); + if (!devno) { + DBG(CXT, ul_debugobj(lc, "sysfs: failed devname to devno")); + return NULL; + } + if (sysfs_init(&lc->sysfs, devno, NULL)) { + DBG(CXT, ul_debugobj(lc, "sysfs: init failed")); + return NULL; + } + } + + return &lc->sysfs; +} + +/* + * @lc: context + * + * Returns: file descriptor to the open loop device or <0 on error. The mode + * depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is + * read-only. + */ +int loopcxt_get_fd(struct loopdev_cxt *lc) +{ + if (!lc || !*lc->device) + return -EINVAL; + + if (lc->fd < 0) { + lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY; + lc->fd = open(lc->device, lc->mode | O_CLOEXEC); + DBG(CXT, ul_debugobj(lc, "open %s [%s]: %m", lc->device, + lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro")); + } + return lc->fd; +} + +int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode) +{ + if (!lc) + return -EINVAL; + + lc->fd = fd; + lc->mode = mode; + return 0; +} + +/* + * @lc: context + * @flags: LOOPITER_FL_* flags + * + * Iterator allows to scan list of the free or used loop devices. + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags) +{ + struct loopdev_iter *iter; + struct stat st; + + if (!lc) + return -EINVAL; + + + iter = &lc->iter; + DBG(ITER, ul_debugobj(iter, "initialize")); + + /* always zeroize + */ + memset(iter, 0, sizeof(*iter)); + iter->ncur = -1; + iter->flags = flags; + iter->default_check = 1; + + if (!lc->extra_check) { + /* + * Check for /dev/loop/<N> subdirectory + */ + if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) && + stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode)) + lc->flags |= LOOPDEV_FL_DEVSUBDIR; + + lc->extra_check = 1; + } + return 0; +} + +/* + * @lc: context + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_deinit_iterator(struct loopdev_cxt *lc) +{ + struct loopdev_iter *iter; + + if (!lc) + return -EINVAL; + + iter = &lc->iter; + DBG(ITER, ul_debugobj(iter, "de-initialize")); + + free(iter->minors); + if (iter->proc) + fclose(iter->proc); + if (iter->sysblock) + closedir(iter->sysblock); + iter->minors = NULL; + iter->proc = NULL; + iter->sysblock = NULL; + iter->done = 1; + return 0; +} + +/* + * Same as loopcxt_set_device, but also checks if the device is + * associeted with any file. + * + * Returns: <0 on error, 0 on success, 1 device does not match with + * LOOPITER_FL_{USED,FREE} flags. + */ +static int loopiter_set_device(struct loopdev_cxt *lc, const char *device) +{ + int rc = loopcxt_set_device(lc, device); + int used; + + if (rc) + return rc; + + if (!(lc->iter.flags & LOOPITER_FL_USED) && + !(lc->iter.flags & LOOPITER_FL_FREE)) + return 0; /* caller does not care about device status */ + + if (!is_loopdev(lc->device)) { + DBG(ITER, ul_debugobj(&lc->iter, "%s does not exist", lc->device)); + return -errno; + } + + DBG(ITER, ul_debugobj(&lc->iter, "%s exist", lc->device)); + + used = loopcxt_get_offset(lc, NULL) == 0; + + if ((lc->iter.flags & LOOPITER_FL_USED) && used) + return 0; + + if ((lc->iter.flags & LOOPITER_FL_FREE) && !used) + return 0; + + DBG(ITER, ul_debugobj(&lc->iter, "failed to use %s device", lc->device)); + + ignore_result( loopcxt_set_device(lc, NULL) ); + return 1; +} + +static int cmpnum(const void *p1, const void *p2) +{ + return (((* (int *) p1) > (* (int *) p2)) - + ((* (int *) p1) < (* (int *) p2))); +} + +/* + * The classic scandir() is more expensive and less portable. + * We needn't full loop device names -- loop numbers (loop<N>) + * are enough. + */ +static int loop_scandir(const char *dirname, int **ary, int hasprefix) +{ + DIR *dir; + struct dirent *d; + unsigned int n, count = 0, arylen = 0; + + if (!dirname || !ary) + return 0; + + DBG(ITER, ul_debug("scan dir: %s", dirname)); + + dir = opendir(dirname); + if (!dir) + return 0; + free(*ary); + *ary = NULL; + + while((d = readdir(dir))) { +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN && + d->d_type != DT_LNK) + continue; +#endif + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + if (hasprefix) { + /* /dev/loop<N> */ + if (sscanf(d->d_name, "loop%u", &n) != 1) + continue; + } else { + /* /dev/loop/<N> */ + char *end = NULL; + + errno = 0; + n = strtol(d->d_name, &end, 10); + if (d->d_name == end || (end && *end) || errno) + continue; + } + if (n < LOOPDEV_DEFAULT_NNODES) + continue; /* ignore loop<0..7> */ + + if (count + 1 > arylen) { + int *tmp; + + arylen += 1; + + tmp = realloc(*ary, arylen * sizeof(int)); + if (!tmp) { + free(*ary); + closedir(dir); + return -1; + } + *ary = tmp; + } + if (*ary) + (*ary)[count++] = n; + } + if (count && *ary) + qsort(*ary, count, sizeof(int), cmpnum); + + closedir(dir); + return count; +} + +/* + * Set the next *used* loop device according to /proc/partitions. + * + * Loop devices smaller than 512 bytes are invisible for this function. + */ +static int loopcxt_next_from_proc(struct loopdev_cxt *lc) +{ + struct loopdev_iter *iter = &lc->iter; + char buf[BUFSIZ]; + + DBG(ITER, ul_debugobj(iter, "scan /proc/partitions")); + + if (!iter->proc) + iter->proc = fopen(_PATH_PROC_PARTITIONS, "r"); + if (!iter->proc) + return 1; + + while (fgets(buf, sizeof(buf), iter->proc)) { + unsigned int m; + char name[128 + 1]; + + + if (sscanf(buf, " %u %*s %*s %128[^\n ]", + &m, name) != 2 || m != LOOPDEV_MAJOR) + continue; + + DBG(ITER, ul_debugobj(iter, "checking %s", name)); + + if (loopiter_set_device(lc, name) == 0) + return 0; + } + + return 1; +} + +/* + * Set the next *used* loop device according to + * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required). + * + * This is preferred method. + */ +static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc) +{ + struct loopdev_iter *iter = &lc->iter; + struct dirent *d; + int fd; + + DBG(ITER, ul_debugobj(iter, "scanning /sys/block")); + + if (!iter->sysblock) + iter->sysblock = opendir(_PATH_SYS_BLOCK); + + if (!iter->sysblock) + return 1; + + fd = dirfd(iter->sysblock); + + while ((d = readdir(iter->sysblock))) { + char name[256]; + struct stat st; + + DBG(ITER, ul_debugobj(iter, "check %s", d->d_name)); + + if (strcmp(d->d_name, ".") == 0 + || strcmp(d->d_name, "..") == 0 + || strncmp(d->d_name, "loop", 4) != 0) + continue; + + snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name); + if (fstat_at(fd, _PATH_SYS_BLOCK, name, &st, 0) != 0) + continue; + + if (loopiter_set_device(lc, d->d_name) == 0) + return 0; + } + + return 1; +} + +/* + * @lc: context, has to initialized by loopcxt_init_iterator() + * + * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details + * about the current loop device are available by + * loopcxt_get_{fd,backing_file,device,offset, ...} functions. + */ +int loopcxt_next(struct loopdev_cxt *lc) +{ + struct loopdev_iter *iter; + + if (!lc) + return -EINVAL; + + + iter = &lc->iter; + if (iter->done) + return 1; + + DBG(ITER, ul_debugobj(iter, "next")); + + /* A) Look for used loop devices in /proc/partitions ("losetup -a" only) + */ + if (iter->flags & LOOPITER_FL_USED) { + int rc; + + if (loopcxt_sysfs_available(lc)) + rc = loopcxt_next_from_sysfs(lc); + else + rc = loopcxt_next_from_proc(lc); + if (rc == 0) + return 0; + goto done; + } + + /* B) Classic way, try first eight loop devices (default number + * of loop devices). This is enough for 99% of all cases. + */ + if (iter->default_check) { + DBG(ITER, ul_debugobj(iter, "next: default check")); + for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES; + iter->ncur++) { + char name[16]; + snprintf(name, sizeof(name), "loop%d", iter->ncur); + + if (loopiter_set_device(lc, name) == 0) + return 0; + } + iter->default_check = 0; + } + + /* C) the worst possibility, scan whole /dev or /dev/loop/<N> + */ + if (!iter->minors) { + DBG(ITER, ul_debugobj(iter, "next: scanning /dev")); + iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ? + loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) : + loop_scandir(_PATH_DEV, &iter->minors, 1); + iter->ncur = -1; + } + for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) { + char name[16]; + snprintf(name, sizeof(name), "loop%d", iter->minors[iter->ncur]); + + if (loopiter_set_device(lc, name) == 0) + return 0; + } +done: + loopcxt_deinit_iterator(lc); + return 1; +} + +/* + * @device: path to device + */ +int is_loopdev(const char *device) +{ + struct stat st; + + if (!device) + return 0; + + return (stat(device, &st) == 0 && + S_ISBLK(st.st_mode) && + major(st.st_rdev) == LOOPDEV_MAJOR); +} + +/* + * @lc: context + * + * Returns result from LOOP_GET_STAT64 ioctl or NULL on error. + */ +struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc) +{ + int fd; + + if (!lc || lc->info_failed) { + errno = EINVAL; + return NULL; + } + errno = 0; + if (lc->has_info) + return &lc->info; + + fd = loopcxt_get_fd(lc); + if (fd < 0) + return NULL; + + if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) { + lc->has_info = 1; + lc->info_failed = 0; + DBG(CXT, ul_debugobj(lc, "reading loop_info64 OK")); + return &lc->info; + } + + lc->info_failed = 1; + DBG(CXT, ul_debugobj(lc, "reading loop_info64 FAILED")); + + return NULL; +} + +/* + * @lc: context + * + * Returns (allocated) string with path to the file assicieted + * with the current loop device. + */ +char *loopcxt_get_backing_file(struct loopdev_cxt *lc) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + char *res = NULL; + + if (sysfs) + /* + * This is always preffered, the loop_info64 + * has too small buffer for the filename. + */ + res = sysfs_strdup(sysfs, "loop/backing_file"); + + if (!res && loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + + if (lo) { + lo->lo_file_name[LO_NAME_SIZE - 2] = '*'; + lo->lo_file_name[LO_NAME_SIZE - 1] = '\0'; + res = strdup((char *) lo->lo_file_name); + } + } + + DBG(CXT, ul_debugobj(lc, "get_backing_file [%s]", res)); + return res; +} + +/* + * @lc: context + * @offset: returns offset number for the given device + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + int rc = -EINVAL; + + if (sysfs) + rc = sysfs_read_u64(sysfs, "loop/offset", offset); + + if (rc && loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + if (lo) { + if (offset) + *offset = lo->lo_offset; + rc = 0; + } else + rc = -errno; + } + + DBG(CXT, ul_debugobj(lc, "get_offset [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @sizelimit: returns size limit for the given device + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + int rc = -EINVAL; + + if (sysfs) + rc = sysfs_read_u64(sysfs, "loop/sizelimit", size); + + if (rc && loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + if (lo) { + if (size) + *size = lo->lo_sizelimit; + rc = 0; + } else + rc = -errno; + } + + DBG(CXT, ul_debugobj(lc, "get_sizelimit [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @devno: returns encryption type + * + * Cryptoloop is DEPRECATED! + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc; + + /* not provided by sysfs */ + if (lo) { + if (type) + *type = lo->lo_encrypt_type; + rc = 0; + } else + rc = -errno; + + DBG(CXT, ul_debugobj(lc, "get_encrypt_type [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @devno: returns crypt name + * + * Cryptoloop is DEPRECATED! + * + * Returns: <0 on error, 0 on success + */ +const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + + if (lo) + return (char *) lo->lo_crypt_name; + + DBG(CXT, ul_debugobj(lc, "get_crypt_name failed")); + return NULL; +} + +/* + * @lc: context + * @devno: returns backing file devno + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc; + + if (lo) { + if (devno) + *devno = lo->lo_device; + rc = 0; + } else + rc = -errno; + + DBG(CXT, ul_debugobj(lc, "get_backing_devno [rc=%d]", rc)); + return rc; +} + +/* + * @lc: context + * @ino: returns backing file inode + * + * Returns: <0 on error, 0 on success + */ +int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino) +{ + struct loop_info64 *lo = loopcxt_get_info(lc); + int rc; + + if (lo) { + if (ino) + *ino = lo->lo_inode; + rc = 0; + } else + rc = -errno; + + DBG(CXT, ul_debugobj(lc, "get_backing_inode [rc=%d]", rc)); + return rc; +} + +/* + * Check if the kernel supports partitioned loop devices. + * + * Notes: + * - kernels < 3.2 support partitioned loop devices and PT scanning + * only if max_part= module paremeter is non-zero + * + * - kernels >= 3.2 always support partitioned loop devices + * + * - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls + * + * - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the + * LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled + * by default. + * + * See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98. + */ +int loopmod_supports_partscan(void) +{ + int rc, ret = 0; + FILE *f; + + if (get_linux_version() >= KERNEL_VERSION(3,2,0)) + return 1; + + f = fopen("/sys/module/loop/parameters/max_part", "r"); + if (!f) + return 0; + rc = fscanf(f, "%d", &ret); + fclose(f); + return rc == 1 ? ret : 0; +} + +/* + * @lc: context + * + * Returns: 1 if the partscan flags is set *or* (for old kernels) partitions + * scannig is enabled for all loop devices. + */ +int loopcxt_is_partscan(struct loopdev_cxt *lc) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + + if (sysfs) { + /* kernel >= 3.2 */ + int fl; + if (sysfs_read_int(sysfs, "loop/partscan", &fl) == 0) + return fl; + } + + /* old kernels (including kernels without loopN/loop/<flags> directory */ + return loopmod_supports_partscan(); +} + +/* + * @lc: context + * + * Returns: 1 if the autoclear flags is set. + */ +int loopcxt_is_autoclear(struct loopdev_cxt *lc) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + + if (sysfs) { + int fl; + if (sysfs_read_int(sysfs, "loop/autoclear", &fl) == 0) + return fl; + } + + if (loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + if (lo) + return lo->lo_flags & LO_FLAGS_AUTOCLEAR; + } + return 0; +} + +/* + * @lc: context + * + * Returns: 1 if the readonly flags is set. + */ +int loopcxt_is_readonly(struct loopdev_cxt *lc) +{ + struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); + + if (sysfs) { + int fl; + if (sysfs_read_int(sysfs, "ro", &fl) == 0) + return fl; + } + + if (loopcxt_ioctl_enabled(lc)) { + struct loop_info64 *lo = loopcxt_get_info(lc); + if (lo) + return lo->lo_flags & LO_FLAGS_READ_ONLY; + } + return 0; +} + +/* + * @lc: context + * @st: backing file stat or NULL + * @backing_file: filename + * @offset: offset + * @flags: LOOPDEV_FL_OFFSET if @offset should not be ignored + * + * Returns 1 if the current @lc loopdev is associated with the given backing + * file. Note that the preferred way is to use devno and inode number rather + * than filename. The @backing_file filename is poor solution usable in case + * that you don't have rights to call stat(). + * + * Don't forget that old kernels provide very restricted (in size) backing + * filename by LOOP_GET_STAT64 ioctl only. + */ +int loopcxt_is_used(struct loopdev_cxt *lc, + struct stat *st, + const char *backing_file, + uint64_t offset, + int flags) +{ + ino_t ino; + dev_t dev; + + if (!lc) + return 0; + + DBG(CXT, ul_debugobj(lc, "checking %s vs. %s", + loopcxt_get_device(lc), + backing_file)); + + if (st && loopcxt_get_backing_inode(lc, &ino) == 0 && + loopcxt_get_backing_devno(lc, &dev) == 0) { + + if (ino == st->st_ino && dev == st->st_dev) + goto found; + + /* don't use filename if we have devno and inode */ + return 0; + } + + /* poor man's solution */ + if (backing_file) { + char *name = loopcxt_get_backing_file(lc); + int rc = name && strcmp(name, backing_file) == 0; + + free(name); + if (rc) + goto found; + } + + return 0; +found: + if (flags & LOOPDEV_FL_OFFSET) { + uint64_t off; + + return loopcxt_get_offset(lc, &off) == 0 && off == offset; + } + return 1; +} + +/* + * The setting is removed by loopcxt_set_device() loopcxt_next()! + */ +int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset) +{ + if (!lc) + return -EINVAL; + lc->info.lo_offset = offset; + + DBG(CXT, ul_debugobj(lc, "set offset=%jd", offset)); + return 0; +} + +/* + * The setting is removed by loopcxt_set_device() loopcxt_next()! + */ +int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit) +{ + if (!lc) + return -EINVAL; + lc->info.lo_sizelimit = sizelimit; + + DBG(CXT, ul_debugobj(lc, "set sizelimit=%jd", sizelimit)); + return 0; +} + +/* + * @lc: context + * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags + * + * The setting is removed by loopcxt_set_device() loopcxt_next()! + * + * Returns: 0 on success, <0 on error. + */ +int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags) +{ + if (!lc) + return -EINVAL; + lc->info.lo_flags = flags; + + DBG(CXT, ul_debugobj(lc, "set flags=%u", (unsigned) flags)); + return 0; +} + +/* + * @lc: context + * @filename: backing file path (the path will be canonicalized) + * + * The setting is removed by loopcxt_set_device() loopcxt_next()! + * + * Returns: 0 on success, <0 on error. + */ +int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename) +{ + if (!lc) + return -EINVAL; + + lc->filename = canonicalize_path(filename); + if (!lc->filename) + return -errno; + + strncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE); + lc->info.lo_file_name[LO_NAME_SIZE- 1] = '\0'; + + DBG(CXT, ul_debugobj(lc, "set backing file=%s", lc->info.lo_file_name)); + return 0; +} + +/* + * In kernels prior to v3.9, if the offset or sizelimit options + * are used, the block device's size won't be synced automatically. + * blockdev --getsize64 and filesystems will use the backing + * file size until the block device has been re-opened or the + * LOOP_SET_CAPACITY ioctl is called to sync the sizes. + * + * Since mount -oloop uses the LO_FLAGS_AUTOCLEAR option and passes + * the open file descriptor to the mount system call, we need to use + * the ioctl. Calling losetup directly doesn't have this problem since + * it closes the device when it exits and whatever consumes the device + * next will re-open it, causing the resync. + */ +static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd) +{ + uint64_t size, expected_size; + int dev_fd; + struct stat st; + + if (!lc->info.lo_offset && !lc->info.lo_sizelimit) + return 0; + + if (fstat(file_fd, &st)) { + DBG(CXT, ul_debugobj(lc, "failed to fstat backing file")); + return -errno; + } + if (S_ISBLK(st.st_mode)) { + if (blkdev_get_size(file_fd, + (unsigned long long *) &expected_size)) { + DBG(CXT, ul_debugobj(lc, "failed to determine device size")); + return -errno; + } + } else + expected_size = st.st_size; + + if (expected_size == 0 || expected_size <= lc->info.lo_offset) { + DBG(CXT, ul_debugobj(lc, "failed to determine expected size")); + return 0; /* ignore this error */ + } + + if (lc->info.lo_offset > 0) + expected_size -= lc->info.lo_offset; + + if (lc->info.lo_sizelimit > 0 && lc->info.lo_sizelimit < expected_size) + expected_size = lc->info.lo_sizelimit; + + dev_fd = loopcxt_get_fd(lc); + if (dev_fd < 0) { + DBG(CXT, ul_debugobj(lc, "failed to get loop FD")); + return -errno; + } + + if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) { + DBG(CXT, ul_debugobj(lc, "failed to determine loopdev size")); + return -errno; + } + + /* It's block device, so, align to 512-byte sectors */ + if (expected_size % 512) { + DBG(CXT, ul_debugobj(lc, "expected size misaligned to 512-byte sectors")); + expected_size = (expected_size >> 9) << 9; + } + + if (expected_size != size) { + DBG(CXT, ul_debugobj(lc, "warning: loopdev and expected " + "size dismatch (%ju/%ju)", + size, expected_size)); + + if (loopcxt_set_capacity(lc)) { + /* ioctl not available */ + if (errno == ENOTTY || errno == EINVAL) + errno = ERANGE; + return -errno; + } + + if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) + return -errno; + + if (expected_size != size) { + errno = ERANGE; + DBG(CXT, ul_debugobj(lc, "failed to set loopdev size, " + "size: %ju, expected: %ju", + size, expected_size)); + return -errno; + } + } + + return 0; +} + +/* + * @cl: context + * + * Associate the current device (see loopcxt_{set,get}_device()) with + * a file (see loopcxt_set_backing_file()). + * + * The device is initialized read-write by default. If you want read-only + * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_* + * flags are ignored and modified according to LO_FLAGS_*. + * + * If the device is already open by loopcxt_get_fd() then this setup device + * function will re-open the device to fix read/write mode. + * + * The device is also initialized read-only if the backing file is not + * possible to open read-write (e.g. read-only FS). + * + * Returns: <0 on error, 0 on success. + */ +int loopcxt_setup_device(struct loopdev_cxt *lc) +{ + int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0; + + if (!lc || !*lc->device || !lc->filename) + return -EINVAL; + + DBG(SETUP, ul_debugobj(lc, "device setup requested")); + + /* + * Open backing file and device + */ + if (lc->info.lo_flags & LO_FLAGS_READ_ONLY) + mode = O_RDONLY; + + if ((file_fd = open(lc->filename, mode | O_CLOEXEC)) < 0) { + if (mode != O_RDONLY && (errno == EROFS || errno == EACCES)) + file_fd = open(lc->filename, mode = O_RDONLY); + + if (file_fd < 0) { + DBG(SETUP, ul_debugobj(lc, "open backing file failed: %m")); + return -errno; + } + } + DBG(SETUP, ul_debugobj(lc, "backing file open: OK")); + + if (lc->fd != -1 && lc->mode != mode) { + DBG(SETUP, ul_debugobj(lc, "closing already open device (mode mismatch)")); + close(lc->fd); + lc->fd = -1; + lc->mode = 0; + } + + if (mode == O_RDONLY) { + lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */ + lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */ + } else { + lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */ + lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY; + lc->flags &= ~LOOPDEV_FL_RDONLY; + } + + do { + errno = 0; + dev_fd = loopcxt_get_fd(lc); + if (dev_fd >= 0 || lc->control_ok == 0) + break; + if (errno != EACCES && errno != ENOENT) + break; + /* We have permissions to open /dev/loop-control, but open + * /dev/loopN failed with EACCES, it's probably because udevd + * does not applied chown yet. Let's wait a moment. */ + usleep(25000); + } while (cnt++ < 16); + + if (dev_fd < 0) { + rc = -errno; + goto err; + } + + DBG(SETUP, ul_debugobj(lc, "device open: OK")); + + /* + * Set FD + */ + if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { + rc = -errno; + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD failed: %m")); + goto err; + } + + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_FD: OK")); + + if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) { + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); + goto err; + } + + DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64: OK")); + + if ((rc = loopcxt_check_size(lc, file_fd))) + goto err; + + close(file_fd); + + memset(&lc->info, 0, sizeof(lc->info)); + lc->has_info = 0; + lc->info_failed = 0; + + DBG(SETUP, ul_debugobj(lc, "success [rc=0]")); + return 0; +err: + if (file_fd >= 0) + close(file_fd); + if (dev_fd >= 0 && rc != -EBUSY) + ioctl(dev_fd, LOOP_CLR_FD, 0); + + DBG(SETUP, ul_debugobj(lc, "failed [rc=%d]", rc)); + return rc; +} + +int loopcxt_set_capacity(struct loopdev_cxt *lc) +{ + int fd = loopcxt_get_fd(lc); + + if (fd < 0) + return -EINVAL; + + /* Kernels prior to v2.6.30 don't support this ioctl */ + if (ioctl(fd, LOOP_SET_CAPACITY, 0) < 0) { + int rc = -errno; + DBG(CXT, ul_debugobj(lc, "LOOP_SET_CAPACITY failed: %m")); + return rc; + } + + DBG(CXT, ul_debugobj(lc, "capacity set")); + return 0; +} + +int loopcxt_delete_device(struct loopdev_cxt *lc) +{ + int fd = loopcxt_get_fd(lc); + + if (fd < 0) + return -EINVAL; + + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m")); + return -errno; + } + + DBG(CXT, ul_debugobj(lc, "device removed")); + return 0; +} + +int loopcxt_add_device(struct loopdev_cxt *lc) +{ + int rc = -EINVAL; + int ctl, nr = -1; + const char *p, *dev = loopcxt_get_device(lc); + + if (!dev) + goto done; + + if (!(lc->flags & LOOPDEV_FL_CONTROL)) { + rc = -ENOSYS; + goto done; + } + + p = strrchr(dev, '/'); + if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1) + || nr < 0) + goto done; + + ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); + if (ctl >= 0) { + DBG(CXT, ul_debugobj(lc, "add_device %d", nr)); + rc = ioctl(ctl, LOOP_CTL_ADD, nr); + close(ctl); + } + lc->control_ok = rc >= 0 ? 1 : 0; +done: + DBG(CXT, ul_debugobj(lc, "add_device done [rc=%d]", rc)); + return rc; +} + +/* + * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older + * kernels we have to check all loop devices to found unused one. + * + * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484. + */ +int loopcxt_find_unused(struct loopdev_cxt *lc) +{ + int rc = -1; + + DBG(CXT, ul_debugobj(lc, "find_unused requested")); + + if (lc->flags & LOOPDEV_FL_CONTROL) { + int ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC); + + if (ctl >= 0) + rc = ioctl(ctl, LOOP_CTL_GET_FREE); + if (rc >= 0) { + char name[16]; + snprintf(name, sizeof(name), "loop%d", rc); + + rc = loopiter_set_device(lc, name); + } + lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0; + if (ctl >= 0) + close(ctl); + DBG(CXT, ul_debugobj(lc, "find_unused by loop-control [rc=%d]", rc)); + } + + if (rc < 0) { + rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE); + if (rc) + return rc; + + rc = loopcxt_next(lc); + loopcxt_deinit_iterator(lc); + DBG(CXT, ul_debugobj(lc, "find_unused by scan [rc=%d]", rc)); + } + return rc; +} + + + +/* + * Return: TRUE/FALSE + */ +int loopdev_is_autoclear(const char *device) +{ + struct loopdev_cxt lc; + int rc; + + if (!device) + return 0; + + rc = loopcxt_init(&lc, 0); + if (!rc) + rc = loopcxt_set_device(&lc, device); + if (!rc) + rc = loopcxt_is_autoclear(&lc); + + loopcxt_deinit(&lc); + return rc; +} + +char *loopdev_get_backing_file(const char *device) +{ + struct loopdev_cxt lc; + char *res = NULL; + + if (!device) + return NULL; + if (loopcxt_init(&lc, 0)) + return NULL; + if (loopcxt_set_device(&lc, device) == 0) + res = loopcxt_get_backing_file(&lc); + + loopcxt_deinit(&lc); + return res; +} + +/* + * Returns: TRUE/FALSE + */ +int loopdev_is_used(const char *device, const char *filename, + uint64_t offset, int flags) +{ + struct loopdev_cxt lc; + struct stat st; + int rc = 0; + + if (!device || !filename) + return 0; + + rc = loopcxt_init(&lc, 0); + if (!rc) + rc = loopcxt_set_device(&lc, device); + if (rc) + return rc; + + rc = !stat(filename, &st); + rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, flags); + + loopcxt_deinit(&lc); + return rc; +} + +int loopdev_delete(const char *device) +{ + struct loopdev_cxt lc; + int rc; + + if (!device) + return -EINVAL; + + rc = loopcxt_init(&lc, 0); + if (!rc) + rc = loopcxt_set_device(&lc, device); + if (!rc) + rc = loopcxt_delete_device(&lc); + loopcxt_deinit(&lc); + return rc; +} + +/* + * Returns: 0 = success, < 0 error, 1 not found + */ +int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, + uint64_t offset, int flags) +{ + int rc, hasst; + struct stat st; + + if (!filename) + return -EINVAL; + + hasst = !stat(filename, &st); + + rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); + if (rc) + return rc; + + while ((rc = loopcxt_next(lc)) == 0) { + + if (loopcxt_is_used(lc, hasst ? &st : NULL, + filename, offset, flags)) + break; + } + + loopcxt_deinit_iterator(lc); + return rc; +} + +/* + * Returns allocated string with device name + */ +char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, int flags) +{ + struct loopdev_cxt lc; + char *res = NULL; + + if (!filename) + return NULL; + + if (loopcxt_init(&lc, 0)) + return NULL; + if (loopcxt_find_by_backing_file(&lc, filename, offset, flags) == 0) + res = loopcxt_strdup_device(&lc); + loopcxt_deinit(&lc); + + return res; +} + +/* + * Returns number of loop devices associated with @file, if only one loop + * device is associeted with the given @filename and @loopdev is not NULL then + * @loopdev returns name of the device. + */ +int loopdev_count_by_backing_file(const char *filename, char **loopdev) +{ + struct loopdev_cxt lc; + int count = 0, rc; + + if (!filename) + return -1; + + rc = loopcxt_init(&lc, 0); + if (rc) + return rc; + if (loopcxt_init_iterator(&lc, LOOPITER_FL_USED)) + return -1; + + while(loopcxt_next(&lc) == 0) { + char *backing = loopcxt_get_backing_file(&lc); + + if (!backing || strcmp(backing, filename)) { + free(backing); + continue; + } + + free(backing); + if (loopdev && count == 0) + *loopdev = loopcxt_strdup_device(&lc); + count++; + } + + loopcxt_deinit(&lc); + + if (loopdev && count > 1) { + free(*loopdev); + *loopdev = NULL; + } + return count; +} + diff --git a/libblkid/mangle.c b/libblkid/lib/mangle.c index 5236e97bf..5236e97bf 100644 --- a/libblkid/mangle.c +++ b/libblkid/lib/mangle.c diff --git a/libblkid/match.c b/libblkid/lib/match.c index 9be82b0cc..9be82b0cc 100644 --- a/libblkid/match.c +++ b/libblkid/lib/match.c diff --git a/libblkid/lib/mbsalign.c b/libblkid/lib/mbsalign.c new file mode 100644 index 000000000..5e52e8f44 --- /dev/null +++ b/libblkid/lib/mbsalign.c @@ -0,0 +1,466 @@ +/* Align/Truncate a string in a given screen width + Copyright (C) 2009-2010 Free Software Foundation, Inc. + + This program 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 program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Pádraig Brady. */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdbool.h> +#include <limits.h> +#include <ctype.h> + +#include "c.h" +#include "mbsalign.h" +#include "widechar.h" + +#ifdef HAVE_WIDECHAR +/* Replace non printable chars. + Note \t and \n etc. are non printable. + Return 1 if replacement made, 0 otherwise. */ + +/* + * Counts number of cells in multibyte string. For all control and + * non-printable chars is the result width enlarged to store \x?? hex + * sequence. See mbs_safe_encode(). + * + * Returns: number of cells, @sz returns number of bytes. + */ +size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz) +{ + mbstate_t st; + const char *p = buf, *last = buf; + size_t width = 0, bytes = 0; + + memset(&st, 0, sizeof(st)); + + if (p && *p && bufsz) + last = p + (bufsz - 1); + + while (p && *p && p <= last) { + if (iscntrl((unsigned char) *p)) { + width += 4, bytes += 4; /* *p encoded to \x?? */ + p++; + } +#ifdef HAVE_WIDECHAR + else { + wchar_t wc; + size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); + + if (len == 0) + break; + + if (len == (size_t) -1 || len == (size_t) -2) { + len = 1; + if (isprint((unsigned char) *p)) + width += 1, bytes += 1; + else + width += 4, bytes += 4; + + } else if (!iswprint(wc)) { + width += len * 4; /* hex encode whole sequence */ + bytes += len * 4; + } else { + width += wcwidth(wc); /* number of cells */ + bytes += len; /* number of bytes */ + } + p += len; + } +#else + else if (!isprint((unsigned char) *p)) { + width += 4, bytes += 4; /* *p encoded to \x?? */ + p++; + } else { + width++, bytes++; + p++; + } +#endif + } + + if (sz) + *sz = bytes; + return width; +} + +size_t mbs_safe_width(const char *s) +{ + if (!s || !*s) + return 0; + return mbs_safe_nwidth(s, strlen(s), NULL); +} + +/* + * Copy @s to @buf and replace control and non-printable chars with + * \x?? hex sequence. The @width returns number of cells. + * + * The @buf has to be big enough to store mbs_safe_encode_size(strlen(s))) + * bytes. + */ +char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf) +{ + mbstate_t st; + const char *p = s; + char *r; + size_t sz = s ? strlen(s) : 0; + + if (!sz || !buf) + return NULL; + + memset(&st, 0, sizeof(st)); + + r = buf; + *width = 0; + + while (p && *p) { + if (iscntrl((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + p++; + } +#ifdef HAVE_WIDECHAR + else { + wchar_t wc; + size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); + + if (len == 0) + break; /* end of string */ + + if (len == (size_t) -1 || len == (size_t) -2) { + len = 1; + /* + * Not valid multibyte sequence -- maybe it's + * printable char according to the current locales. + */ + if (!isprint((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + } else { + width++; + *r++ = *p; + } + } else if (!iswprint(wc)) { + size_t i; + for (i = 0; i < len; i++) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + } + } else { + memcpy(r, p, len); + r += len; + *width += wcwidth(wc); + } + p += len; + } +#else + else if (!isprint((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + p++; + r += 4; + *width += 4; + } else { + *r++ = *p++; + *width++; + } +#endif + } + + *r = '\0'; + + return buf; +} + +size_t mbs_safe_encode_size(size_t bytes) +{ + return (bytes * 4) + 1; +} + +/* + * Returns allocated string where all control and non-printable chars are + * replaced with \x?? hex sequence. + */ +char *mbs_safe_encode(const char *s, size_t *width) +{ + size_t sz = s ? strlen(s) : 0; + char *buf; + + if (!sz) + return NULL; + buf = malloc(mbs_safe_encode_size(sz)); + if (!buf) + return NULL; + + return mbs_safe_encode_to_buffer(s, width, buf); +} + +static bool +wc_ensure_printable (wchar_t *wchars) +{ + bool replaced = false; + wchar_t *wc = wchars; + while (*wc) + { + if (!iswprint ((wint_t) *wc)) + { + *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ + replaced = true; + } + wc++; + } + return replaced; +} + +/* Truncate wchar string to width cells. + * Returns number of cells used. */ + +static size_t +wc_truncate (wchar_t *wc, size_t width) +{ + size_t cells = 0; + int next_cells = 0; + + while (*wc) + { + next_cells = wcwidth (*wc); + if (next_cells == -1) /* non printable */ + { + *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ + next_cells = 1; + } + if (cells + next_cells > width) + break; + cells += next_cells; + wc++; + } + *wc = L'\0'; + return cells; +} + +/* FIXME: move this function to gnulib as it's missing on: + OpenBSD 3.8, IRIX 5.3, Solaris 2.5.1, mingw, BeOS */ + +static int +rpl_wcswidth (const wchar_t *s, size_t n) +{ + int ret = 0; + + while (n-- > 0 && *s != L'\0') + { + int nwidth = wcwidth (*s++); + if (nwidth == -1) /* non printable */ + return -1; + if (ret > (INT_MAX - nwidth)) /* overflow */ + return -1; + ret += nwidth; + } + + return ret; +} +#endif + +/* Truncate multi-byte string to @width and returns number of + * bytes of the new string @str, and in @width returns number + * of cells. + */ +size_t +mbs_truncate(char *str, size_t *width) +{ + ssize_t bytes = strlen(str); +#ifdef HAVE_WIDECHAR + ssize_t sz = mbstowcs(NULL, str, 0); + wchar_t *wcs = NULL; + + if (sz == (ssize_t) -1) + goto done; + + wcs = malloc((sz + 1) * sizeof(wchar_t)); + if (!wcs) + goto done; + + if (!mbstowcs(wcs, str, sz)) + goto done; + *width = wc_truncate(wcs, *width); + bytes = wcstombs(str, wcs, bytes); +done: + free(wcs); +#else + if (*width < bytes) + bytes = *width; +#endif + if (bytes >= 0) + str[bytes] = '\0'; + return bytes; +} + +/* Write N_SPACES space characters to DEST while ensuring + nothing is written beyond DEST_END. A terminating NUL + is always added to DEST. + A pointer to the terminating NUL is returned. */ + +static char* +mbs_align_pad (char *dest, const char* dest_end, size_t n_spaces) +{ + /* FIXME: Should we pad with "figure space" (\u2007) + if non ascii data present? */ + for (/* nothing */; n_spaces && (dest < dest_end); n_spaces--) + *dest++ = ' '; + *dest = '\0'; + return dest; +} + +/* Align a string, SRC, in a field of *WIDTH columns, handling multi-byte + characters; write the result into the DEST_SIZE-byte buffer, DEST. + ALIGNMENT specifies whether to left- or right-justify or to center. + If SRC requires more than *WIDTH columns, truncate it to fit. + When centering, the number of trailing spaces may be one less than the + number of leading spaces. The FLAGS parameter is unused at present. + Return the length in bytes required for the final result, not counting + the trailing NUL. A return value of DEST_SIZE or larger means there + wasn't enough space. DEST will be NUL terminated in any case. + Return (size_t) -1 upon error (invalid multi-byte sequence in SRC, + or malloc failure), unless MBA_UNIBYTE_FALLBACK is specified. + Update *WIDTH to indicate how many columns were used before padding. */ + +size_t +mbsalign (const char *src, char *dest, size_t dest_size, + size_t *width, mbs_align_t align, int flags) +{ + size_t ret = -1; + size_t src_size = strlen (src) + 1; + char *newstr = NULL; + wchar_t *str_wc = NULL; + const char *str_to_print = src; + size_t n_cols = src_size - 1; + size_t n_used_bytes = n_cols; /* Not including NUL */ + size_t n_spaces = 0, space_left; + bool conversion = false; + bool wc_enabled = false; + +#ifdef HAVE_WIDECHAR + /* In multi-byte locales convert to wide characters + to allow easy truncation. Also determine number + of screen columns used. */ + if (MB_CUR_MAX > 1) + { + size_t src_chars = mbstowcs (NULL, src, 0); + if (src_chars == (size_t) -1) + { + if (flags & MBA_UNIBYTE_FALLBACK) + goto mbsalign_unibyte; + else + goto mbsalign_cleanup; + } + src_chars += 1; /* make space for NUL */ + str_wc = malloc (src_chars * sizeof (wchar_t)); + if (str_wc == NULL) + { + if (flags & MBA_UNIBYTE_FALLBACK) + goto mbsalign_unibyte; + else + goto mbsalign_cleanup; + } + if (mbstowcs (str_wc, src, src_chars) != 0) + { + str_wc[src_chars - 1] = L'\0'; + wc_enabled = true; + conversion = wc_ensure_printable (str_wc); + n_cols = rpl_wcswidth (str_wc, src_chars); + } + } + + /* If we transformed or need to truncate the source string + then create a modified copy of it. */ + if (wc_enabled && (conversion || (n_cols > *width))) + { + if (conversion) + { + /* May have increased the size by converting + \t to \uFFFD for example. */ + src_size = wcstombs(NULL, str_wc, 0) + 1; + } + newstr = malloc (src_size); + if (newstr == NULL) + { + if (flags & MBA_UNIBYTE_FALLBACK) + goto mbsalign_unibyte; + else + goto mbsalign_cleanup; + } + str_to_print = newstr; + n_cols = wc_truncate (str_wc, *width); + n_used_bytes = wcstombs (newstr, str_wc, src_size); + } +#endif + +mbsalign_unibyte: + + if (n_cols > *width) /* Unibyte truncation required. */ + { + n_cols = *width; + n_used_bytes = n_cols; + } + + if (*width > n_cols) /* Padding required. */ + n_spaces = *width - n_cols; + + /* indicate to caller how many cells needed (not including padding). */ + *width = n_cols; + + /* indicate to caller how many bytes needed (not including NUL). */ + ret = n_used_bytes + (n_spaces * 1); + + /* Write as much NUL terminated output to DEST as possible. */ + if (dest_size != 0) + { + char *dest_end = dest + dest_size - 1; + size_t start_spaces; + size_t end_spaces; + + switch (align) + { + case MBS_ALIGN_CENTER: + start_spaces = n_spaces / 2 + n_spaces % 2; + end_spaces = n_spaces / 2; + break; + case MBS_ALIGN_LEFT: + start_spaces = 0; + end_spaces = n_spaces; + break; + case MBS_ALIGN_RIGHT: + start_spaces = n_spaces; + end_spaces = 0; + break; + default: + abort(); + } + + dest = mbs_align_pad (dest, dest_end, start_spaces); + space_left = dest_end - dest; + dest = memcpy (dest, str_to_print, min (n_used_bytes, space_left)); + mbs_align_pad (dest, dest_end, end_spaces); + } + +mbsalign_cleanup: + + free (str_wc); + free (newstr); + + return ret; +} diff --git a/libblkid/md5.c b/libblkid/lib/md5.c index 488d16ef6..488d16ef6 100644 --- a/libblkid/md5.c +++ b/libblkid/lib/md5.c diff --git a/libblkid/lib/monotonic.c b/libblkid/lib/monotonic.c new file mode 100644 index 000000000..3d4a4438e --- /dev/null +++ b/libblkid/lib/monotonic.c @@ -0,0 +1,68 @@ +/* + * Please, don't add this file to libcommon because clock_gettime() requires + * -lrt on systems with old libc. + */ +#include <time.h> +#include <sys/sysinfo.h> +#include <sys/time.h> + +#include "c.h" +#include "nls.h" +#include "monotonic.h" + +int get_boot_time(struct timeval *boot_time) +{ +#ifdef CLOCK_BOOTTIME + struct timespec hires_uptime; + struct timeval lores_uptime; +#endif + struct timeval now; +#ifdef HAVE_SYSINFO + struct sysinfo info; +#endif + + if (gettimeofday(&now, NULL) != 0) { + warn(_("gettimeofday failed")); + return -errno; + } +#ifdef CLOCK_BOOTTIME + if (clock_gettime(CLOCK_BOOTTIME, &hires_uptime) == 0) { + TIMESPEC_TO_TIMEVAL(&lores_uptime, &hires_uptime); + timersub(&now, &lores_uptime, boot_time); + return 0; + } +#endif +#ifdef HAVE_SYSINFO + /* fallback */ + if (sysinfo(&info) != 0) + warn(_("sysinfo failed")); + + boot_time->tv_sec = now.tv_sec - info.uptime; + boot_time->tv_usec = 0; + return 0; +#else + return -ENOSYS; +#endif +} + +int gettime_monotonic(struct timeval *tv) +{ +#ifdef CLOCK_MONOTONIC + /* Can slew only by ntp and adjtime */ + int ret; + struct timespec ts; + +# ifdef CLOCK_MONOTONIC_RAW + /* Linux specific, cant slew */ + if (!(ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts))) { +# else + if (!(ret = clock_gettime(CLOCK_MONOTONIC, &ts))) { +# endif + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + } + return ret; +#else + return gettimeofday(tv, NULL); +#endif +} diff --git a/libblkid/lib/pager.c b/libblkid/lib/pager.c new file mode 100644 index 000000000..9e09cd52b --- /dev/null +++ b/libblkid/lib/pager.c @@ -0,0 +1,210 @@ +/* + * Based on linux-perf/git scm + * + * Some modifications and simplifications for util-linux + * by Davidlohr Bueso <dave@xxxxxxx> - March 2012. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "c.h" +#include "xalloc.h" +#include "nls.h" + +#define NULL_DEVICE "/dev/null" + +void setup_pager(void); + +static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; + +struct child_process { + const char **argv; + pid_t pid; + int in; + int out; + int err; + unsigned no_stdin:1; + void (*preexec_cb)(void); +}; +static struct child_process pager_process; + +static inline void close_pair(int fd[2]) +{ + close(fd[0]); + close(fd[1]); +} + +static int start_command(struct child_process *cmd) +{ + int need_in; + int fdin[2]; + + /* + * In case of errors we must keep the promise to close FDs + * that have been passed in via ->in and ->out. + */ + need_in = !cmd->no_stdin && cmd->in < 0; + if (need_in) { + if (pipe(fdin) < 0) { + if (cmd->out > 0) + close(cmd->out); + return -1; + } + cmd->in = fdin[1]; + } + + fflush(NULL); + cmd->pid = fork(); + if (!cmd->pid) { + if (need_in) { + dup2(fdin[0], STDIN_FILENO); + close_pair(fdin); + } else if (cmd->in > 0) { + dup2(cmd->in, STDIN_FILENO); + close(cmd->in); + } + + cmd->preexec_cb(); + execvp(cmd->argv[0], (char *const*) cmd->argv); + exit(127); /* cmd not found */ + } + + if (cmd->pid < 0) { + if (need_in) + close_pair(fdin); + else if (cmd->in) + close(cmd->in); + return -1; + } + + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + return 0; +} + +static int wait_or_whine(pid_t pid) +{ + for (;;) { + int status, code; + pid_t waiting = waitpid(pid, &status, 0); + + if (waiting < 0) { + if (errno == EINTR) + continue; + err(EXIT_FAILURE, _("waitpid failed (%s)"), strerror(errno)); + } + if (waiting != pid) + return -1; + if (WIFSIGNALED(status)) + return -1; + + if (!WIFEXITED(status)) + return -1; + code = WEXITSTATUS(status); + switch (code) { + case 127: + return -1; + case 0: + return 0; + default: + return -1; + } + } +} + +static int finish_command(struct child_process *cmd) +{ + return wait_or_whine(cmd->pid); +} + +static void pager_preexec(void) +{ + /* + * Work around bug in "less" by not starting it until we + * have real input + */ + fd_set in; + + FD_ZERO(&in); + FD_SET(STDIN_FILENO, &in); + select(1, &in, NULL, &in, NULL); + + setenv("LESS", "FRSX", 0); +} + +static void wait_for_pager(void) +{ + fflush(stdout); + fflush(stderr); + /* signal EOF to pager */ + close(STDOUT_FILENO); + close(STDERR_FILENO); + finish_command(&pager_process); +} + +static void wait_for_pager_signal(int signo) +{ + wait_for_pager(); + raise(signo); +} + +void setup_pager(void) +{ + const char *pager = getenv("PAGER"); + + if (!isatty(STDOUT_FILENO)) + return; + + if (!pager) + pager = "less"; + else if (!*pager || !strcmp(pager, "cat")) + return; + + /* spawn the pager */ + pager_argv[2] = pager; + pager_process.argv = pager_argv; + pager_process.in = -1; + pager_process.preexec_cb = pager_preexec; + + if (start_command(&pager_process)) + return; + + /* original process continues, but writes to the pipe */ + dup2(pager_process.in, STDOUT_FILENO); + if (isatty(STDERR_FILENO)) + dup2(pager_process.in, STDERR_FILENO); + close(pager_process.in); + + /* this makes sure that the parent terminates after the pager */ + signal(SIGINT, wait_for_pager_signal); + signal(SIGHUP, wait_for_pager_signal); + signal(SIGTERM, wait_for_pager_signal); + signal(SIGQUIT, wait_for_pager_signal); + signal(SIGPIPE, wait_for_pager_signal); + + atexit(wait_for_pager); +} + +#ifdef TEST_PROGRAM + +#define MAX 255 + +int main(int argc __attribute__ ((__unused__)), + char *argv[] __attribute__ ((__unused__))) +{ + int i; + + setup_pager(); + for (i = 0; i < MAX; i++) + printf("%d\n", i); + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ diff --git a/libblkid/lib/path.c b/libblkid/lib/path.c new file mode 100644 index 000000000..fc90c0a16 --- /dev/null +++ b/libblkid/lib/path.c @@ -0,0 +1,258 @@ +/* + * Simple functions to access files, paths maybe be globally prefixed by a + * global prefix to read data from alternative destination (e.g. /proc dump for + * regression tests). + * + * Taken from lscpu.c + * + * Copyright (C) 2008 Cai Qian <qcai@redhat.com> + * Copyright (C) 2008-2012 Karel Zak <kzak@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <inttypes.h> +#include <errno.h> + +#include "all-io.h" +#include "path.h" +#include "nls.h" +#include "c.h" + +static size_t prefixlen; +static char pathbuf[PATH_MAX]; + +static const char * +path_vcreate(const char *path, va_list ap) +{ + if (prefixlen) + vsnprintf(pathbuf + prefixlen, + sizeof(pathbuf) - prefixlen, path, ap); + else + vsnprintf(pathbuf, sizeof(pathbuf), path, ap); + return pathbuf; +} + +char * +path_strdup(const char *path, ...) +{ + const char *p; + va_list ap; + + va_start(ap, path); + p = path_vcreate(path, ap); + va_end(ap); + + return p ? strdup(p) : NULL; +} + +static FILE * +path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap) +{ + FILE *f; + const char *p = path_vcreate(path, ap); + + f = fopen(p, mode); + if (!f && exit_on_error) + err(EXIT_FAILURE, _("cannot open %s"), p); + return f; +} + +static int +path_vopen(int flags, const char *path, va_list ap) +{ + int fd; + const char *p = path_vcreate(path, ap); + + fd = open(p, flags); + if (fd == -1) + err(EXIT_FAILURE, _("cannot open %s"), p); + return fd; +} + +FILE * +path_fopen(const char *mode, int exit_on_error, const char *path, ...) +{ + FILE *fd; + va_list ap; + + va_start(ap, path); + fd = path_vfopen(mode, exit_on_error, path, ap); + va_end(ap); + + return fd; +} + +void +path_read_str(char *result, size_t len, const char *path, ...) +{ + FILE *fd; + va_list ap; + + va_start(ap, path); + fd = path_vfopen("r", 1, path, ap); + va_end(ap); + + if (!fgets(result, len, fd)) + err(EXIT_FAILURE, _("cannot read %s"), pathbuf); + fclose(fd); + + len = strlen(result); + if (result[len - 1] == '\n') + result[len - 1] = '\0'; +} + +int +path_read_s32(const char *path, ...) +{ + FILE *fd; + va_list ap; + int result; + + va_start(ap, path); + fd = path_vfopen("r", 1, path, ap); + va_end(ap); + + if (fscanf(fd, "%d", &result) != 1) { + if (ferror(fd)) + err(EXIT_FAILURE, _("cannot read %s"), pathbuf); + else + errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); + } + fclose(fd); + return result; +} + +uint64_t +path_read_u64(const char *path, ...) +{ + FILE *fd; + va_list ap; + uint64_t result; + + va_start(ap, path); + fd = path_vfopen("r", 1, path, ap); + va_end(ap); + + if (fscanf(fd, "%"SCNu64, &result) != 1) { + if (ferror(fd)) + err(EXIT_FAILURE, _("cannot read %s"), pathbuf); + else + errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); + } + fclose(fd); + return result; +} + +int +path_write_str(const char *str, const char *path, ...) +{ + int fd, result; + va_list ap; + + va_start(ap, path); + fd = path_vopen(O_WRONLY|O_CLOEXEC, path, ap); + va_end(ap); + result = write_all(fd, str, strlen(str)); + close(fd); + return result; +} + +int +path_exist(const char *path, ...) +{ + va_list ap; + const char *p; + + va_start(ap, path); + p = path_vcreate(path, ap); + va_end(ap); + + return access(p, F_OK) == 0; +} + +#ifdef HAVE_CPU_SET_T + +static cpu_set_t * +path_cpuparse(int maxcpus, int islist, const char *path, va_list ap) +{ + FILE *fd; + cpu_set_t *set; + size_t setsize, len = maxcpus * 7; + char buf[len]; + + fd = path_vfopen("r", 1, path, ap); + + if (!fgets(buf, len, fd)) + err(EXIT_FAILURE, _("cannot read %s"), pathbuf); + fclose(fd); + + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + set = cpuset_alloc(maxcpus, &setsize, NULL); + if (!set) + err(EXIT_FAILURE, _("failed to callocate cpu set")); + + if (islist) { + if (cpulist_parse(buf, set, setsize, 0)) + errx(EXIT_FAILURE, _("failed to parse CPU list %s"), buf); + } else { + if (cpumask_parse(buf, set, setsize)) + errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf); + } + return set; +} + +cpu_set_t * +path_read_cpuset(int maxcpus, const char *path, ...) +{ + va_list ap; + cpu_set_t *set; + + va_start(ap, path); + set = path_cpuparse(maxcpus, 0, path, ap); + va_end(ap); + + return set; +} + +cpu_set_t * +path_read_cpulist(int maxcpus, const char *path, ...) +{ + va_list ap; + cpu_set_t *set; + + va_start(ap, path); + set = path_cpuparse(maxcpus, 1, path, ap); + va_end(ap); + + return set; +} + +#endif /* HAVE_CPU_SET_T */ + +void +path_set_prefix(const char *prefix) +{ + prefixlen = strlen(prefix); + strncpy(pathbuf, prefix, sizeof(pathbuf)); + pathbuf[sizeof(pathbuf) - 1] = '\0'; +} diff --git a/libblkid/lib/procutils.c b/libblkid/lib/procutils.c new file mode 100644 index 000000000..ef969417d --- /dev/null +++ b/libblkid/lib/procutils.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org> + * + * procutils.c: General purpose procfs parsing utilities + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 Library Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> + +#include "procutils.h" +#include "at.h" +#include "c.h" + +/* + * @pid: process ID for which we want to obtain the threads group + * + * Returns: newly allocated tasks structure + */ +struct proc_tasks *proc_open_tasks(pid_t pid) +{ + struct proc_tasks *tasks; + char path[PATH_MAX]; + + sprintf(path, "/proc/%d/task/", pid); + + tasks = malloc(sizeof(struct proc_tasks)); + if (tasks) { + tasks->dir = opendir(path); + if (tasks->dir) + return tasks; + } + + free(tasks); + return NULL; +} + +/* + * @tasks: allocated tasks structure + * + * Returns: nothing + */ +void proc_close_tasks(struct proc_tasks *tasks) +{ + if (tasks && tasks->dir) + closedir(tasks->dir); + free(tasks); +} + +/* + * @tasks: allocated task structure + * @tid: [output] one of the thread IDs belonging to the thread group + * If when an error occurs, it is set to 0. + * + * Returns: 0 on success, 1 on end, -1 on failure or no more threads + */ +int proc_next_tid(struct proc_tasks *tasks, pid_t *tid) +{ + struct dirent *d; + char *end; + + if (!tasks || !tid) + return -EINVAL; + + *tid = 0; + errno = 0; + + do { + d = readdir(tasks->dir); + if (!d) + return errno ? -1 : 1; /* error or end-of-dir */ + + if (!isdigit((unsigned char) *d->d_name)) + continue; + errno = 0; + *tid = (pid_t) strtol(d->d_name, &end, 10); + if (errno || d->d_name == end || (end && *end)) + return -1; + + } while (!*tid); + + return 0; +} + +struct proc_processes *proc_open_processes(void) +{ + struct proc_processes *ps; + + ps = calloc(1, sizeof(struct proc_processes)); + if (ps) { + ps->dir = opendir("/proc"); + if (ps->dir) + return ps; + } + + free(ps); + return NULL; +} + +void proc_close_processes(struct proc_processes *ps) +{ + if (ps && ps->dir) + closedir(ps->dir); + free(ps); +} + +void proc_processes_filter_by_name(struct proc_processes *ps, const char *name) +{ + ps->fltr_name = name; + ps->has_fltr_name = name ? 1 : 0; +} + +void proc_processes_filter_by_uid(struct proc_processes *ps, uid_t uid) +{ + ps->fltr_uid = uid; + ps->has_fltr_uid = 1; +} + +int proc_next_pid(struct proc_processes *ps, pid_t *pid) +{ + struct dirent *d; + + if (!ps || !pid) + return -EINVAL; + + *pid = 0; + errno = 0; + + do { + char buf[BUFSIZ], *p; + + d = readdir(ps->dir); + if (!d) + return errno ? -1 : 1; /* error or end-of-dir */ + + + if (!isdigit((unsigned char) *d->d_name)) + continue; + + /* filter out by UID */ + if (ps->has_fltr_uid) { + struct stat st; + + if (fstat_at(dirfd(ps->dir), "/proc", d->d_name, &st, 0)) + continue; + if (ps->fltr_uid != st.st_uid) + continue; + } + + /* filter out by NAME */ + if (ps->has_fltr_name) { + char procname[256]; + FILE *f; + + snprintf(buf, sizeof(buf), "%s/stat", d->d_name); + f = fopen_at(dirfd(ps->dir), "/proc", buf, + O_CLOEXEC|O_RDONLY, "r"); + if (!f) + continue; + + p = fgets(buf, sizeof(buf), f); + fclose(f); + if (!p) + continue; + + if (sscanf(buf, "%*d (%255[^)])", procname) != 1) + continue; + + /* ok, we got the process name. */ + if (strcmp(procname, ps->fltr_name) != 0) + continue; + } + + p = NULL; + errno = 0; + *pid = (pid_t) strtol(d->d_name, &p, 10); + if (errno || d->d_name == p || (p && *p)) + return errno ? -errno : -1; + + return 0; + } while (1); + + return 0; +} + +#ifdef TEST_PROGRAM + +static int test_tasks(int argc, char *argv[]) +{ + pid_t tid, pid; + struct proc_tasks *ts; + + if (argc != 2) + return EXIT_FAILURE; + + pid = strtol(argv[1], (char **) NULL, 10); + printf("PID=%d, TIDs:", pid); + + ts = proc_open_tasks(pid); + if (!ts) + err(EXIT_FAILURE, "open list of tasks failed"); + + while (proc_next_tid(ts, &tid) == 0) + printf(" %d", tid); + + printf("\n"); + proc_close_tasks(ts); + return EXIT_SUCCESS; +} + +static int test_processes(int argc, char *argv[]) +{ + pid_t pid; + struct proc_processes *ps; + + ps = proc_open_processes(); + if (!ps) + err(EXIT_FAILURE, "open list of processes failed"); + + if (argc >= 3 && strcmp(argv[1], "--name") == 0) + proc_processes_filter_by_name(ps, argv[2]); + + if (argc >= 3 && strcmp(argv[1], "--uid") == 0) + proc_processes_filter_by_uid(ps, (uid_t) atol(argv[2])); + + while (proc_next_pid(ps, &pid) == 0) + printf(" %d", pid); + + printf("\n"); + proc_close_processes(ps); + return EXIT_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "usage: %1$s --tasks <pid>\n" + " %1$s --processes [---name <name>] [--uid <uid>]\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + if (strcmp(argv[1], "--tasks") == 0) + return test_tasks(argc - 1, argv + 1); + if (strcmp(argv[1], "--processes") == 0) + return test_processes(argc - 1, argv + 1); + + return EXIT_FAILURE; +} +#endif /* TEST_PROGRAM */ diff --git a/libblkid/lib/randutils.c b/libblkid/lib/randutils.c new file mode 100644 index 000000000..684ac0ac1 --- /dev/null +++ b/libblkid/lib/randutils.c @@ -0,0 +1,147 @@ +/* + * General purpose random utilities + * + * Based on libuuid code. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include <sys/syscall.h> + +#include "c.h" +#include "randutils.h" +#include "nls.h" + +#ifdef HAVE_TLS +#define THREAD_LOCAL static __thread +#else +#define THREAD_LOCAL static +#endif + +#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) +#define DO_JRAND_MIX +THREAD_LOCAL unsigned short ul_jrand_seed[3]; +#endif + +int random_get_fd(void) +{ + int i, fd; + struct timeval tv; + + gettimeofday(&tv, 0); + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1) + fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd >= 0) { + i = fcntl(fd, F_GETFD); + if (i >= 0) + fcntl(fd, F_SETFD, i | FD_CLOEXEC); + } + srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); + +#ifdef DO_JRAND_MIX + ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); + ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); + ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; +#endif + /* Crank the random number generator a few times */ + gettimeofday(&tv, 0); + for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) + rand(); + return fd; +} + + +/* + * Generate a stream of random nbytes into buf. + * Use /dev/urandom if possible, and if not, + * use glibc pseudo-random functions. + */ +void random_get_bytes(void *buf, size_t nbytes) +{ + size_t i, n = nbytes; + int fd = random_get_fd(); + int lose_counter = 0; + unsigned char *cp = (unsigned char *) buf; + + if (fd >= 0) { + while (n > 0) { + ssize_t x = read(fd, cp, n); + if (x <= 0) { + if (lose_counter++ > 16) + break; + continue; + } + n -= x; + cp += x; + lose_counter = 0; + } + + close(fd); + } + + /* + * We do this all the time, but this is the only source of + * randomness if /dev/random/urandom is out to lunch. + */ + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (rand() >> 7) & 0xFF; + +#ifdef DO_JRAND_MIX + { + unsigned short tmp_seed[3]; + + memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed)); + ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid); + for (cp = buf, i = 0; i < nbytes; i++) + *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; + memcpy(ul_jrand_seed, tmp_seed, + sizeof(ul_jrand_seed)-sizeof(unsigned short)); + } +#endif + + return; +} + + +/* + * Tell source of randomness. + */ +const char *random_tell_source(void) +{ + size_t i; + static const char *random_sources[] = { + "/dev/urandom", + "/dev/random" + }; + + for (i = 0; i < ARRAY_SIZE(random_sources); i++) { + if (!access(random_sources[i], R_OK)) + return random_sources[i]; + } + + return _("libc pseudo-random functions"); +} + +#ifdef TEST_PROGRAM +int main(int argc __attribute__ ((__unused__)), + char *argv[] __attribute__ ((__unused__))) +{ + unsigned int v, i; + + /* generate and print 10 random numbers */ + for (i = 0; i < 10; i++) { + random_get_bytes(&v, sizeof(v)); + printf("%d\n", v); + } + + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ diff --git a/libblkid/lib/readutmp.c b/libblkid/lib/readutmp.c new file mode 100644 index 000000000..b11e9a4d2 --- /dev/null +++ b/libblkid/lib/readutmp.c @@ -0,0 +1,78 @@ +/* GNU's read utmp module. + + Copyright (C) 1992-2001, 2003-2006, 2009-2014 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by jla; revised by djm */ +/* extracted for util-linux by ooprala */ + +#include <errno.h> +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "xalloc.h" +#include "readutmp.h" + +/* Read the utmp entries corresponding to file FILE into freshly- + malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to + the number of entries, and return zero. If there is any error, + return -1, setting errno, and don't modify the parameters. + If OPTIONS & READ_UTMP_CHECK_PIDS is nonzero, omit entries whose + process-IDs do not currently exist. */ +int +read_utmp (char const *file, size_t *n_entries, struct utmp **utmp_buf) +{ + size_t n_read = 0; + size_t n_alloc = 0; + struct utmp *utmp = NULL; + struct utmp *u; + + /* Ignore the return value for now. + Solaris' utmpname returns 1 upon success -- which is contrary + to what the GNU libc version does. In addition, older GNU libc + versions are actually void. */ + utmpname(file); + + setutent(); + + errno = 0; + while ((u = getutent()) != NULL) { + if (n_read == n_alloc) { + n_alloc += 32; + utmp = xrealloc(utmp, n_alloc * sizeof (struct utmp)); + if (!utmp) + return -1; + } + utmp[n_read++] = *u; + } + if (!u && errno) { + free(utmp); + return -1; + } + + endutent(); + + *n_entries = n_read; + *utmp_buf = utmp; + + return 0; +} diff --git a/libblkid/setproctitle.c b/libblkid/lib/setproctitle.c index 4bcf8c8a9..4bcf8c8a9 100644 --- a/libblkid/setproctitle.c +++ b/libblkid/lib/setproctitle.c diff --git a/libblkid/lib/strutils.c b/libblkid/lib/strutils.c new file mode 100644 index 000000000..9fe9481bc --- /dev/null +++ b/libblkid/lib/strutils.c @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2010 Karel Zak <kzak@redhat.com> + * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <ctype.h> +#include <errno.h> +#include <sys/stat.h> +#include <string.h> +#include <assert.h> + +#include "c.h" +#include "nls.h" +#include "strutils.h" +#include "bitops.h" + +static int do_scale_by_power (uintmax_t *x, int base, int power) +{ + while (power--) { + if (UINTMAX_MAX / base < *x) + return -ERANGE; + *x *= base; + } + return 0; +} + +/* + * strtosize() - convert string to size (uintmax_t). + * + * Supported suffixes: + * + * XiB or X for 2^N + * where X = {K,M,G,T,P,E,Z,Y} + * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only) + * for example: + * 10KiB = 10240 + * 10K = 10240 + * + * XB for 10^N + * where X = {K,M,G,T,P,E,Z,Y} + * for example: + * 10KB = 10000 + * + * The optinal 'power' variable returns number associated with used suffix + * {K,M,G,T,P,E,Z,Y} = {1,2,3,4,5,6,7,8}. + * + * The function also supports decimal point, for example: + * 0.5MB = 500000 + * 0.5MiB = 512000 + * + * Note that the function does not accept numbers with '-' (negative sign) + * prefix. + */ +int parse_size(const char *str, uintmax_t *res, int *power) +{ + char *p; + uintmax_t x, frac = 0; + int base = 1024, rc = 0, pwr = 0, frac_zeros = 0; + + static const char *suf = "KMGTPEYZ"; + static const char *suf2 = "kmgtpeyz"; + const char *sp; + + *res = 0; + + if (!str || !*str) { + rc = -EINVAL; + goto err; + } + + /* Only positive numbers are acceptable + * + * Note that this check is not perfect, it would be better to + * use lconv->negative_sign. But coreutils use the same solution, + * so it's probably good enough... + */ + p = (char *) str; + while (isspace((unsigned char) *p)) + p++; + if (*p == '-') { + rc = -EINVAL; + goto err; + } + p = NULL; + + errno = 0; + x = strtoumax(str, &p, 0); + + if (p == str || + (errno != 0 && (x == UINTMAX_MAX || x == 0))) { + rc = errno ? -errno : -1; + goto err; + } + if (!p || !*p) + goto done; /* without suffix */ + + /* + * Check size suffixes + */ +check_suffix: + if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3)) + base = 1024; /* XiB, 2^N */ + else if (*(p + 1) == 'B' && !*(p + 2)) + base = 1000; /* XB, 10^N */ + else if (*(p + 1)) { + struct lconv const *l = localeconv(); + char *dp = l ? l->decimal_point : NULL; + size_t dpsz = dp ? strlen(dp) : 0; + + if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) { + char *fstr = p + dpsz; + + for (p = fstr; *p && *p == '0'; p++) + frac_zeros++; + errno = 0, p = NULL; + frac = strtoumax(fstr, &p, 0); + if (p == fstr || + (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) { + rc = errno ? -errno : -1; + goto err; + } + if (frac && (!p || !*p)) { + rc = -EINVAL; + goto err; /* without suffix, but with frac */ + } + goto check_suffix; + } + rc = -EINVAL; + goto err; /* unexpected suffix */ + } + + sp = strchr(suf, *p); + if (sp) + pwr = (sp - suf) + 1; + else { + sp = strchr(suf2, *p); + if (sp) + pwr = (sp - suf2) + 1; + else { + rc = -EINVAL; + goto err; + } + } + + rc = do_scale_by_power(&x, base, pwr); + if (power) + *power = pwr; + if (frac && pwr) { + int zeros_in_pwr = frac_zeros % 3; + int frac_pwr = pwr - (frac_zeros / 3) - 1; + uintmax_t y = frac * (zeros_in_pwr == 0 ? 100 : + zeros_in_pwr == 1 ? 10 : 1); + + if (frac_pwr < 0) { + rc = -EINVAL; + goto err; + } + do_scale_by_power(&y, base, frac_pwr); + x += y; + } +done: + *res = x; +err: + return rc; +} + +int strtosize(const char *str, uintmax_t *res) +{ + return parse_size(str, res, NULL); +} + +int isdigit_string(const char *str) +{ + const char *p; + + for (p = str; p && *p && isdigit((unsigned char) *p); p++); + + return p && p > str && !*p; +} + + +#ifndef HAVE_MEMPCPY +void *mempcpy(void *restrict dest, const void *restrict src, size_t n) +{ + return ((char *)memcpy(dest, src, n)) + n; +} +#endif + +#ifndef HAVE_STRNLEN +size_t strnlen(const char *s, size_t maxlen) +{ + int i; + + for (i = 0; i < maxlen; i++) { + if (s[i] == '\0') + return i + 1; + } + return maxlen; +} +#endif + +#ifndef HAVE_STRNCHR +char *strnchr(const char *s, size_t maxlen, int c) +{ + for (; maxlen-- && *s != '\0'; ++s) + if (*s == (char)c) + return (char *)s; + return NULL; +} +#endif + +#ifndef HAVE_STRNDUP +char *strndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n); + char *new = (char *) malloc((len + 1) * sizeof(char)); + if (!new) + return NULL; + new[len] = '\0'; + return (char *) memcpy(new, s, len); +} +#endif + +int16_t strtos16_or_err(const char *str, const char *errmesg) +{ + int32_t num = strtos32_or_err(str, errmesg); + + if (num < INT16_MIN || num > INT16_MAX) + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + return num; +} + +uint16_t strtou16_or_err(const char *str, const char *errmesg) +{ + uint32_t num = strtou32_or_err(str, errmesg); + + if (num > UINT16_MAX) + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + return num; +} + +int32_t strtos32_or_err(const char *str, const char *errmesg) +{ + int64_t num = strtos64_or_err(str, errmesg); + + if (num < INT32_MIN || num > INT32_MAX) + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + return num; +} + +uint32_t strtou32_or_err(const char *str, const char *errmesg) +{ + uint64_t num = strtou64_or_err(str, errmesg); + + if (num > UINT32_MAX) + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + return num; +} + +int64_t strtos64_or_err(const char *str, const char *errmesg) +{ + int64_t num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + num = strtoimax(str, &end, 10); + + if (errno || str == end || (end && *end)) + goto err; + + return num; +err: + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + +uint64_t strtou64_or_err(const char *str, const char *errmesg) +{ + uintmax_t num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + num = strtoumax(str, &end, 10); + + if (errno || str == end || (end && *end)) + goto err; + + return num; +err: + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + + +double strtod_or_err(const char *str, const char *errmesg) +{ + double num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + num = strtod(str, &end); + + if (errno || str == end || (end && *end)) + goto err; + + return num; +err: + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + +long strtol_or_err(const char *str, const char *errmesg) +{ + long num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + num = strtol(str, &end, 10); + + if (errno || str == end || (end && *end)) + goto err; + + return num; +err: + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + +unsigned long strtoul_or_err(const char *str, const char *errmesg) +{ + unsigned long num; + char *end = NULL; + + if (str == NULL || *str == '\0') + goto err; + errno = 0; + num = strtoul(str, &end, 10); + + if (errno || str == end || (end && *end)) + goto err; + + return num; +err: + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + +uintmax_t strtosize_or_err(const char *str, const char *errmesg) +{ + uintmax_t num; + + if (strtosize(str, &num) == 0) + return num; + + if (errno) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); +} + + +void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg) +{ + double user_input; + + user_input = strtod_or_err(str, errmesg); + tv->tv_sec = (time_t) user_input; + tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000); +} + +/* + * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must + * be 11 bytes. + */ +void strmode(mode_t mode, char *str) +{ + if (S_ISDIR(mode)) + str[0] = 'd'; + else if (S_ISLNK(mode)) + str[0] = 'l'; + else if (S_ISCHR(mode)) + str[0] = 'c'; + else if (S_ISBLK(mode)) + str[0] = 'b'; + else if (S_ISSOCK(mode)) + str[0] = 's'; + else if (S_ISFIFO(mode)) + str[0] = 'p'; + else if (S_ISREG(mode)) + str[0] = '-'; + + str[1] = mode & S_IRUSR ? 'r' : '-'; + str[2] = mode & S_IWUSR ? 'w' : '-'; + str[3] = (mode & S_ISUID + ? (mode & S_IXUSR ? 's' : 'S') + : (mode & S_IXUSR ? 'x' : '-')); + str[4] = mode & S_IRGRP ? 'r' : '-'; + str[5] = mode & S_IWGRP ? 'w' : '-'; + str[6] = (mode & S_ISGID + ? (mode & S_IXGRP ? 's' : 'S') + : (mode & S_IXGRP ? 'x' : '-')); + str[7] = mode & S_IROTH ? 'r' : '-'; + str[8] = mode & S_IWOTH ? 'w' : '-'; + str[9] = (mode & S_ISVTX + ? (mode & S_IXOTH ? 't' : 'T') + : (mode & S_IXOTH ? 'x' : '-')); + str[10] = '\0'; +} + +/* + * returns exponent (2^x=n) in range KiB..PiB + */ +static int get_exp(uint64_t n) +{ + int shft; + + for (shft = 10; shft <= 60; shft += 10) { + if (n < (1ULL << shft)) + break; + } + return shft - 10; +} + +char *size_to_human_string(int options, uint64_t bytes) +{ + char buf[32]; + int dec, exp; + uint64_t frac; + const char *letters = "BKMGTPE"; + char suffix[sizeof(" KiB")], *psuf = suffix; + char c; + + if (options & SIZE_SUFFIX_SPACE) + *psuf++ = ' '; + + exp = get_exp(bytes); + c = *(letters + (exp ? exp / 10 : 0)); + dec = exp ? bytes / (1ULL << exp) : bytes; + frac = exp ? bytes % (1ULL << exp) : 0; + + *psuf++ = c; + + if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) { + *psuf++ = 'i'; + *psuf++ = 'B'; + } + + *psuf = '\0'; + + /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n", + * exp, suffix[0], dec, frac); + */ + + if (frac) { + /* round */ + frac = (frac / (1ULL << (exp - 10)) + 50) / 100; + if (frac == 10) + dec++, frac = 0; + } + + if (frac) { + struct lconv const *l = localeconv(); + char *dp = l ? l->decimal_point : NULL; + + if (!dp || !*dp) + dp = "."; + snprintf(buf, sizeof(buf), "%d%s%jd%s", dec, dp, frac, suffix); + } else + snprintf(buf, sizeof(buf), "%d%s", dec, suffix); + + return strdup(buf); +} + +/* + * Parses comma delimited list to array with IDs, for example: + * + * "aaa,bbb,ccc" --> ary[0] = FOO_AAA; + * ary[1] = FOO_BBB; + * ary[3] = FOO_CCC; + * + * The function name2id() provides conversion from string to ID. + * + * Returns: >= 0 : number of items added to ary[] + * -1 : parse error or unknown item + * -2 : arysz reached + */ +int string_to_idarray(const char *list, int ary[], size_t arysz, + int (name2id)(const char *, size_t)) +{ + const char *begin = NULL, *p; + size_t n = 0; + + if (!list || !*list || !ary || !arysz || !name2id) + return -1; + + for (p = list; p && *p; p++) { + const char *end = NULL; + int id; + + if (n >= arysz) + return -2; + if (!begin) + begin = p; /* begin of the column name */ + if (*p == ',') + end = p; /* terminate the name */ + if (*(p + 1) == '\0') + end = p + 1; /* end of string */ + if (!begin || !end) + continue; + if (end <= begin) + return -1; + + id = name2id(begin, end - begin); + if (id == -1) + return -1; + ary[ n++ ] = id; + begin = NULL; + if (end && !*end) + break; + } + return n; +} + +/* + * Parses the array like string_to_idarray but if format is "+aaa,bbb" + * it adds fields to array instead of replacing them. + */ +int string_add_to_idarray(const char *list, int ary[], size_t arysz, + int *ary_pos, int (name2id)(const char *, size_t)) +{ + const char *list_add; + int r; + + if (!list || !*list || !ary_pos || + *ary_pos < 0 || (size_t) *ary_pos > arysz) + return -1; + + if (list[0] == '+') + list_add = &list[1]; + else { + list_add = list; + *ary_pos = 0; + } + + r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id); + if (r > 0) + *ary_pos += r; + return r; +} + +/* + * LIST ::= <item> [, <item>] + * + * The <item> is translated to 'id' by name2id() function and the 'id' is used + * as a position in the 'ary' bit array. It means that the 'id' has to be in + * range <0..N> where N < sizeof(ary) * NBBY. + * + * Returns: 0 on success, <0 on error. + */ +int string_to_bitarray(const char *list, + char *ary, + int (*name2bit)(const char *, size_t)) +{ + const char *begin = NULL, *p; + + if (!list || !name2bit || !ary) + return -EINVAL; + + for (p = list; p && *p; p++) { + const char *end = NULL; + int bit; + + if (!begin) + begin = p; /* begin of the level name */ + if (*p == ',') + end = p; /* terminate the name */ + if (*(p + 1) == '\0') + end = p + 1; /* end of string */ + if (!begin || !end) + continue; + if (end <= begin) + return -1; + + bit = name2bit(begin, end - begin); + if (bit < 0) + return bit; + setbit(ary, bit); + begin = NULL; + if (end && !*end) + break; + } + return 0; +} + +/* + * LIST ::= <item> [, <item>] + * + * The <item> is translated to 'id' by name2flag() function and the flags is + * set to the 'mask' +* + * Returns: 0 on success, <0 on error. + */ +int string_to_bitmask(const char *list, + unsigned long *mask, + long (*name2flag)(const char *, size_t)) +{ + const char *begin = NULL, *p; + + if (!list || !name2flag || !mask) + return -EINVAL; + + for (p = list; p && *p; p++) { + const char *end = NULL; + long flag; + + if (!begin) + begin = p; /* begin of the level name */ + if (*p == ',') + end = p; /* terminate the name */ + if (*(p + 1) == '\0') + end = p + 1; /* end of string */ + if (!begin || !end) + continue; + if (end <= begin) + return -1; + + flag = name2flag(begin, end - begin); + if (flag < 0) + return flag; /* error */ + *mask |= flag; + begin = NULL; + if (end && !*end) + break; + } + return 0; +} + +/* + * Parse the lower and higher values in a string containing + * "lower:higher" or "lower-higher" format. Note that either + * the lower or the higher values may be missing, and the def + * value will be assigned to it by default. + * + * Returns: 0 on success, <0 on error. + */ +int parse_range(const char *str, int *lower, int *upper, int def) +{ + char *end = NULL; + + if (!str) + return 0; + + *upper = *lower = def; + errno = 0; + + if (*str == ':') { /* <:N> */ + str++; + *upper = strtol(str, &end, 10); + if (errno || !end || *end || end == str) + return -1; + } else { + *upper = *lower = strtol(str, &end, 10); + if (errno || !end || end == str) + return -1; + + if (*end == ':' && !*(end + 1)) /* <M:> */ + *upper = 0; + else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */ + str = end + 1; + end = NULL; + errno = 0; + *upper = strtol(str, &end, 10); + + if (errno || !end || *end || end == str) + return -1; + } + } + return 0; +} + +/* + * Compare two strings for equality, ignoring at most one trailing + * slash. + */ +int streq_except_trailing_slash(const char *s1, const char *s2) +{ + int equal; + + if (!s1 && !s2) + return 1; + if (!s1 || !s2) + return 0; + + equal = !strcmp(s1, s2); + + if (!equal) { + size_t len1 = strlen(s1); + size_t len2 = strlen(s2); + + if (len1 && *(s1 + len1 - 1) == '/') + len1--; + if (len2 && *(s2 + len2 - 1) == '/') + len2--; + if (len1 != len2) + return 0; + + equal = !strncmp(s1, s2, len1); + } + + return equal; +} + + +#ifdef TEST_PROGRAM + +int main(int argc, char *argv[]) +{ + uintmax_t size = 0; + char *hum, *hum2; + + if (argc < 2) { + fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (strtosize(argv[1], &size)) + errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]); + + hum = size_to_human_string(SIZE_SUFFIX_1LETTER, size); + hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER | + SIZE_SUFFIX_SPACE, size); + + printf("%25s : %20ju : %8s : %12s\n", argv[1], size, hum, hum2); + free(hum); + free(hum2); + + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ diff --git a/libblkid/lib/swapprober.c b/libblkid/lib/swapprober.c new file mode 100644 index 000000000..5a4b112e1 --- /dev/null +++ b/libblkid/lib/swapprober.c @@ -0,0 +1,49 @@ + +#include "c.h" +#include "nls.h" + +#include "swapheader.h" +#include "swapprober.h" + +blkid_probe get_swap_prober(const char *devname) +{ + blkid_probe pr; + int rc; + const char *version = NULL; + char *swap_filter[] = { "swap", NULL }; + + pr = blkid_new_probe_from_filename(devname); + if (!pr) { + warn(_("%s: unable to probe device"), devname); + return NULL; + } + + blkid_probe_enable_superblocks(pr, TRUE); + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | + BLKID_SUBLKS_VERSION); + + blkid_probe_filter_superblocks_type(pr, BLKID_FLTR_ONLYIN, swap_filter); + + rc = blkid_do_safeprobe(pr); + if (rc == -1) + warn(_("%s: unable to probe device"), devname); + else if (rc == -2) + warnx(_("%s: ambiguous probing result; use wipefs(8)"), devname); + else if (rc == 1) + warnx(_("%s: not a valid swap partition"), devname); + + if (rc == 0) { + /* Only the SWAPSPACE2 is supported. */ + if (blkid_probe_lookup_value(pr, "VERSION", &version, NULL) == 0 + && version + && strcmp(version, stringify_value(SWAP_VERSION))) + warnx(_("%s: unsupported swap version '%s'"), + devname, version); + else + return pr; + } + + blkid_free_probe(pr); + return NULL; +} diff --git a/libblkid/lib/sysfs.c b/libblkid/lib/sysfs.c new file mode 100644 index 000000000..63a90dcbc --- /dev/null +++ b/libblkid/lib/sysfs.c @@ -0,0 +1,1069 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#include <ctype.h> + +#include "c.h" +#include "at.h" +#include "pathnames.h" +#include "sysfs.h" +#include "fileutils.h" +#include "all-io.h" + +char *sysfs_devno_attribute_path(dev_t devno, char *buf, + size_t bufsiz, const char *attr) +{ + int len; + + if (attr) + len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d/%s", + major(devno), minor(devno), attr); + else + len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d", + major(devno), minor(devno)); + + return (len < 0 || (size_t) len + 1 > bufsiz) ? NULL : buf; +} + +int sysfs_devno_has_attribute(dev_t devno, const char *attr) +{ + char path[PATH_MAX]; + struct stat info; + + if (!sysfs_devno_attribute_path(devno, path, sizeof(path), attr)) + return 0; + if (stat(path, &info) == 0) + return 1; + return 0; +} + +char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz) +{ + return sysfs_devno_attribute_path(devno, buf, bufsiz, NULL); +} + +dev_t sysfs_devname_to_devno(const char *name, const char *parent) +{ + char buf[PATH_MAX], *path = NULL; + dev_t dev = 0; + + if (strncmp("/dev/", name, 5) == 0) { + /* + * Read from /dev + */ + struct stat st; + + if (stat(name, &st) == 0) + dev = st.st_rdev; + else + name += 5; /* unaccesible, or not node in /dev */ + } + + if (!dev && parent && strncmp("dm-", name, 3)) { + /* + * Create path to /sys/block/<parent>/<name>/dev + */ + int len = snprintf(buf, sizeof(buf), + _PATH_SYS_BLOCK "/%s/%s/dev", parent, name); + if (len < 0 || (size_t) len + 1 > sizeof(buf)) + return 0; + path = buf; + + } else if (!dev) { + /* + * Create path to /sys/block/<name>/dev + */ + int len = snprintf(buf, sizeof(buf), + _PATH_SYS_BLOCK "/%s/dev", name); + if (len < 0 || (size_t) len + 1 > sizeof(buf)) + return 0; + path = buf; + } + + if (path) { + /* + * read devno from sysfs + */ + FILE *f; + int maj = 0, min = 0; + + f = fopen(path, "r" UL_CLOEXECSTR); + if (!f) + return 0; + + if (fscanf(f, "%d:%d", &maj, &min) == 2) + dev = makedev(maj, min); + fclose(f); + } + return dev; +} + +/* + * Returns devname (e.g. "/dev/sda1") for the given devno. + * + * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min> + * symlinks. + * + * Please, use more robust blkid_devno_to_devname() in your applications. + */ +char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz) +{ + struct sysfs_cxt cxt; + char *name; + size_t sz; + struct stat st; + + if (sysfs_init(&cxt, devno, NULL)) + return NULL; + + name = sysfs_get_devname(&cxt, buf, bufsiz); + sysfs_deinit(&cxt); + + if (!name) + return NULL; + + sz = strlen(name); + + if (sz + sizeof("/dev/") > bufsiz) + return NULL; + + /* create the final "/dev/<name>" string */ + memmove(buf + 5, name, sz + 1); + memcpy(buf, "/dev/", 5); + + if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == devno) + return buf; + + return NULL; +} + +int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent) +{ + char path[PATH_MAX]; + int fd, rc; + + memset(cxt, 0, sizeof(*cxt)); + cxt->dir_fd = -1; + + if (!sysfs_devno_path(devno, path, sizeof(path))) + goto err; + + fd = open(path, O_RDONLY|O_CLOEXEC); + if (fd < 0) + goto err; + cxt->dir_fd = fd; + + cxt->dir_path = strdup(path); + if (!cxt->dir_path) + goto err; + cxt->devno = devno; + cxt->parent = parent; + return 0; +err: + rc = errno > 0 ? -errno : -1; + sysfs_deinit(cxt); + return rc; +} + +void sysfs_deinit(struct sysfs_cxt *cxt) +{ + if (!cxt) + return; + + if (cxt->dir_fd >= 0) + close(cxt->dir_fd); + free(cxt->dir_path); + + memset(cxt, 0, sizeof(*cxt)); + + cxt->dir_fd = -1; +} + +int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st) +{ + int rc = fstat_at(cxt->dir_fd, cxt->dir_path, attr, st, 0); + + if (rc != 0 && errno == ENOENT && + strncmp(attr, "queue/", 6) == 0 && cxt->parent) { + + /* Exception for "queue/<attr>". These attributes are available + * for parental devices only + */ + return fstat_at(cxt->parent->dir_fd, + cxt->parent->dir_path, attr, st, 0); + } + return rc; +} + +int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr) +{ + struct stat st; + + return sysfs_stat(cxt, attr, &st) == 0; +} + +static int sysfs_open(struct sysfs_cxt *cxt, const char *attr, int flags) +{ + int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, flags); + + if (fd == -1 && errno == ENOENT && + strncmp(attr, "queue/", 6) == 0 && cxt->parent) { + + /* Exception for "queue/<attr>". These attributes are available + * for parental devices only + */ + fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, flags); + } + return fd; +} + +ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr, + char *buf, size_t bufsiz) +{ + if (!cxt->dir_path) + return -1; + + if (attr) + return readlink_at(cxt->dir_fd, cxt->dir_path, attr, buf, bufsiz); + + /* read /sys/dev/block/<maj:min> link */ + return readlink(cxt->dir_path, buf, bufsiz); +} + +DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr) +{ + DIR *dir; + int fd = -1; + + if (attr) + fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC); + + else if (cxt->dir_fd >= 0) + /* request to open root of device in sysfs (/sys/block/<dev>) + * -- we cannot use cxt->sysfs_fd directly, because closedir() + * will close this our persistent file descriptor. + */ + fd = dup(cxt->dir_fd); + + if (fd < 0) + return NULL; + + dir = fdopendir(fd); + if (!dir) { + close(fd); + return NULL; + } + if (!attr) + rewinddir(dir); + return dir; +} + + +static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr) +{ + int fd = sysfs_open(cxt, attr, O_RDONLY|O_CLOEXEC); + + return fd < 0 ? NULL : fdopen(fd, "r" UL_CLOEXECSTR); +} + + +static struct dirent *xreaddir(DIR *dp) +{ + struct dirent *d; + + while ((d = readdir(dp))) { + if (!strcmp(d->d_name, ".") || + !strcmp(d->d_name, "..")) + continue; + + /* blacklist here? */ + break; + } + return d; +} + +int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name) +{ + char path[256]; + +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_DIR && + d->d_type != DT_LNK && + d->d_type != DT_UNKNOWN) + return 0; +#endif + if (parent_name) { + const char *p = parent_name; + size_t len; + + /* /dev/sda --> "sda" */ + if (*parent_name == '/') { + p = strrchr(parent_name, '/'); + if (!p) + return 0; + p++; + } + + len = strlen(p); + if (strlen(d->d_name) <= len) + return 0; + + /* partitions subdir name is + * "<parent>[:digit:]" or "<parent>p[:digit:]" + */ + return strncmp(p, d->d_name, len) == 0 && + ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1))) + || isdigit(*(d->d_name + len))); + } + + /* Cannot use /partition file, not supported on old sysfs */ + snprintf(path, sizeof(path), "%s/start", d->d_name); + + return faccessat(dirfd(dir), path, R_OK, 0) == 0; +} + +/* + * Converts @partno (partition number) to devno of the partition. + * The @cxt handles wholedisk device. + * + * Note that this code does not expect any special format of the + * partitions devnames. + */ +dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno) +{ + DIR *dir; + struct dirent *d; + char path[256]; + dev_t devno = 0; + + dir = sysfs_opendir(cxt, NULL); + if (!dir) + return 0; + + while ((d = xreaddir(dir))) { + int n, maj, min; + + if (!sysfs_is_partition_dirent(dir, d, NULL)) + continue; + + snprintf(path, sizeof(path), "%s/partition", d->d_name); + if (sysfs_read_int(cxt, path, &n)) + continue; + + if (n == partno) { + snprintf(path, sizeof(path), "%s/dev", d->d_name); + if (sysfs_scanf(cxt, path, "%d:%d", &maj, &min) == 2) + devno = makedev(maj, min); + break; + } + } + + closedir(dir); + return devno; +} + + +int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, const char *fmt, ...) +{ + FILE *f = sysfs_fopen(cxt, attr); + va_list ap; + int rc; + + if (!f) + return -EINVAL; + va_start(ap, fmt); + rc = vfscanf(f, fmt, ap); + va_end(ap); + + fclose(f); + return rc; +} + + +int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res) +{ + int64_t x = 0; + + if (sysfs_scanf(cxt, attr, "%"SCNd64, &x) == 1) { + if (res) + *res = x; + return 0; + } + return -1; +} + +int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res) +{ + uint64_t x = 0; + + if (sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1) { + if (res) + *res = x; + return 0; + } + return -1; +} + +int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res) +{ + int x = 0; + + if (sysfs_scanf(cxt, attr, "%d", &x) == 1) { + if (res) + *res = x; + return 0; + } + return -1; +} + +int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str) +{ + int fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC); + int rc, errsv; + + if (fd < 0) + return -errno; + rc = write_all(fd, str, strlen(str)); + + errsv = errno; + close(fd); + errno = errsv; + return rc; +} + +int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num) +{ + char buf[sizeof(stringify_value(ULLONG_MAX))]; + int fd, rc = 0, len, errsv; + + fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC); + if (fd < 0) + return -errno; + + len = snprintf(buf, sizeof(buf), "%ju", num); + if (len < 0 || (size_t) len + 1 > sizeof(buf)) + rc = -errno; + else + rc = write_all(fd, buf, len); + + errsv = errno; + close(fd); + errno = errsv; + return rc; +} + +char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr) +{ + char buf[1024]; + return sysfs_scanf(cxt, attr, "%1023[^\n]", buf) == 1 ? + strdup(buf) : NULL; +} + +int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr) +{ + DIR *dir; + int r = 0; + + if (!(dir = sysfs_opendir(cxt, attr))) + return 0; + + while (xreaddir(dir)) r++; + + closedir(dir); + return r; +} + +int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname) +{ + DIR *dir; + struct dirent *d; + int r = 0; + + if (!(dir = sysfs_opendir(cxt, NULL))) + return 0; + + while ((d = xreaddir(dir))) { + if (sysfs_is_partition_dirent(dir, d, devname)) + r++; + } + + closedir(dir); + return r; +} + +/* + * Returns slave name if there is only one slave, otherwise returns NULL. + * The result should be deallocated by free(). + */ +char *sysfs_get_slave(struct sysfs_cxt *cxt) +{ + DIR *dir; + struct dirent *d; + char *name = NULL; + + if (!(dir = sysfs_opendir(cxt, "slaves"))) + return NULL; + + while ((d = xreaddir(dir))) { + if (name) + goto err; /* more slaves */ + + name = strdup(d->d_name); + } + + closedir(dir); + return name; +err: + free(name); + closedir(dir); + return NULL; +} + +/* + * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min> + * symlinks. + */ +char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz) +{ + char *name = NULL; + ssize_t sz; + + sz = sysfs_readlink(cxt, NULL, buf, bufsiz - 1); + if (sz < 0) + return NULL; + + buf[sz] = '\0'; + name = strrchr(buf, '/'); + if (!name) + return NULL; + + name++; + sz = strlen(name); + + memmove(buf, name, sz + 1); + return buf; +} + +#define SUBSYSTEM_LINKNAME "/subsystem" + +/* + * For example: + * + * chain: /sys/dev/block/../../devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/ \ + * 1-1.2:1.0/host65/target65:0:0/65:0:0:0/block/sdb + * + * The function check if <chain>/subsystem symlink exists, if yes then returns + * basename of the readlink result, and remove the last subdirectory from the + * <chain> path. + */ +static char *get_subsystem(char *chain, char *buf, size_t bufsz) +{ + size_t len; + char *p; + + if (!chain || !*chain) + return NULL; + + len = strlen(chain); + if (len + sizeof(SUBSYSTEM_LINKNAME) > PATH_MAX) + return NULL; + + do { + ssize_t sz; + + /* append "/subsystem" to the path */ + memcpy(chain + len, SUBSYSTEM_LINKNAME, sizeof(SUBSYSTEM_LINKNAME)); + + /* try if subsystem symlink exists */ + sz = readlink(chain, buf, bufsz - 1); + + /* remove last subsystem from chain */ + chain[len] = '\0'; + p = strrchr(chain, '/'); + if (p) { + *p = '\0'; + len = p - chain; + } + + if (sz > 0) { + /* we found symlink to subsystem, return basename */ + buf[sz] = '\0'; + return basename(buf); + } + + } while (p); + + return NULL; +} + +/* + * Returns complete path to the device, the patch contains all all sybsystems + * used for the device. + */ +char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz) +{ + /* read /sys/dev/block/<maj>:<min> symlink */ + size_t sz = sysfs_readlink(cxt, NULL, buf, bufsz); + if (sz <= 0 || sz + sizeof(_PATH_SYS_DEVBLOCK "/") > bufsz) + return NULL; + + buf[sz++] = '\0'; + + /* create absolute patch from the link */ + memmove(buf + sizeof(_PATH_SYS_DEVBLOCK "/") - 1, buf, sz); + memcpy(buf, _PATH_SYS_DEVBLOCK "/", sizeof(_PATH_SYS_DEVBLOCK "/") - 1); + + return buf; +} + +/* + * The @subsys returns the next subsystem in the chain. Function modifies + * @devchain string. + * + * Returns: 0 in success, <0 on error, 1 on end of chain + */ +int sysfs_next_subsystem(struct sysfs_cxt *cxt __attribute__((unused)), + char *devchain, char **subsys) +{ + char subbuf[PATH_MAX]; + char *sub; + + if (!subsys || !devchain) + return -EINVAL; + + while ((sub = get_subsystem(devchain, subbuf, sizeof(subbuf)))) { + *subsys = strdup(sub); + if (!*subsys) + return -ENOMEM; + return 0; + } + + return 1; +} + + +static int is_hotpluggable_subsystem(const char *name) +{ + static const char * const hotplug_subsystems[] = { + "usb", + "ieee1394", + "pcmcia", + "mmc", + "ccw" + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(hotplug_subsystems); i++) + if (strcmp(name, hotplug_subsystems[i]) == 0) + return 1; + + return 0; +} + +int sysfs_is_hotpluggable(struct sysfs_cxt *cxt) +{ + char buf[PATH_MAX], *chain, *sub; + int rc = 0; + + + /* check /sys/dev/block/<maj>:<min>/removable attribute */ + if (sysfs_read_int(cxt, "removable", &rc) == 0 && rc == 1) + return 1; + + chain = sysfs_get_devchain(cxt, buf, sizeof(buf)); + + while (chain && sysfs_next_subsystem(cxt, chain, &sub) == 0) { + rc = is_hotpluggable_subsystem(sub); + if (rc) { + free(sub); + break; + } + free(sub); + } + + return rc; +} + +static int get_dm_wholedisk(struct sysfs_cxt *cxt, char *diskname, + size_t len, dev_t *diskdevno) +{ + int rc = 0; + char *name; + + /* Note, sysfs_get_slave() returns the first slave only, + * if there is more slaves, then return NULL + */ + name = sysfs_get_slave(cxt); + if (!name) + return -1; + + if (diskname && len) { + strncpy(diskname, name, len); + diskname[len - 1] = '\0'; + } + + if (diskdevno) { + *diskdevno = sysfs_devname_to_devno(name, NULL); + if (!*diskdevno) + rc = -1; + } + + free(name); + return rc; +} + +/* + * Returns by @diskdevno whole disk device devno and (optionaly) by + * @diskname the whole disk device name. + */ +int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno) +{ + struct sysfs_cxt cxt; + int is_part = 0; + + if (!dev || sysfs_init(&cxt, dev, NULL) != 0) + return -1; + + is_part = sysfs_has_attribute(&cxt, "partition"); + if (!is_part) { + /* + * Extra case for partitions mapped by device-mapper. + * + * All regualar partitions (added by BLKPG ioctl or kernel PT + * parser) have the /sys/.../partition file. The partitions + * mapped by DM don't have such file, but they have "part" + * prefix in DM UUID. + */ + char *uuid = sysfs_strdup(&cxt, "dm/uuid"); + char *tmp = uuid; + char *prefix = uuid ? strsep(&tmp, "-") : NULL; + + if (prefix && strncasecmp(prefix, "part", 4) == 0) + is_part = 1; + free(uuid); + + if (is_part && + get_dm_wholedisk(&cxt, diskname, len, diskdevno) == 0) + /* + * partitioned device, mapped by DM + */ + goto done; + + is_part = 0; + } + + if (!is_part) { + /* + * unpartitioned device + */ + if (diskname && len) { + if (!sysfs_get_devname(&cxt, diskname, len)) + goto err; + } + if (diskdevno) + *diskdevno = dev; + + } else { + /* + * partitioned device + * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1 + * - dirname ../../block/sda/sda1 = ../../block/sda + * - basename ../../block/sda = sda + */ + char linkpath[PATH_MAX]; + char *name; + int linklen; + + linklen = sysfs_readlink(&cxt, NULL, + linkpath, sizeof(linkpath) - 1); + if (linklen < 0) + goto err; + linkpath[linklen] = '\0'; + + stripoff_last_component(linkpath); /* dirname */ + name = stripoff_last_component(linkpath); /* basename */ + if (!name) + goto err; + + if (diskname && len) { + strncpy(diskname, name, len); + diskname[len - 1] = '\0'; + } + + if (diskdevno) { + *diskdevno = sysfs_devname_to_devno(name, NULL); + if (!*diskdevno) + goto err; + } + } + +done: + sysfs_deinit(&cxt); + return 0; +err: + sysfs_deinit(&cxt); + return -1; +} + +/* + * Returns 1 if the device is private LVM device. + */ +int sysfs_devno_is_lvm_private(dev_t devno) +{ + struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; + char *uuid = NULL; + int rc = 0; + + if (sysfs_init(&cxt, devno, NULL) != 0) + return 0; + + uuid = sysfs_strdup(&cxt, "dm/uuid"); + + /* Private LVM devices use "LVM-<uuid>-<name>" uuid format (important + * is the "LVM" prefix and "-<name>" postfix). + */ + if (uuid && strncmp(uuid, "LVM-", 4) == 0) { + char *p = strrchr(uuid + 4, '-'); + + if (p && *(p + 1)) + rc = 1; + } + + sysfs_deinit(&cxt); + free(uuid); + return rc; +} + +/* + * Return 0 or 1, or < 0 in case of error + */ +int sysfs_devno_is_wholedisk(dev_t devno) +{ + dev_t disk; + + if (sysfs_devno_to_wholedisk(devno, NULL, 0, &disk) != 0) + return -1; + + return devno == disk; +} + + +int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l) +{ + char buf[PATH_MAX], *hctl; + ssize_t len; + + if (!cxt) + return -EINVAL; + if (cxt->has_hctl) + goto done; + + len = sysfs_readlink(cxt, "device", buf, sizeof(buf) - 1); + if (len < 0) + return len; + + buf[len] = '\0'; + hctl = strrchr(buf, '/'); + if (!hctl) + return -1; + hctl++; + + if (sscanf(hctl, "%u:%u:%u:%u", &cxt->scsi_host, &cxt->scsi_channel, + &cxt->scsi_target, &cxt->scsi_lun) != 4) + return -1; + + cxt->has_hctl = 1; +done: + if (h) + *h = cxt->scsi_host; + if (c) + *c = cxt->scsi_channel; + if (t) + *t = cxt->scsi_target; + if (l) + *l = cxt->scsi_lun; + return 0; +} + + +static char *sysfs_scsi_host_attribute_path(struct sysfs_cxt *cxt, + const char *type, char *buf, size_t bufsz, const char *attr) +{ + int len; + int host; + + if (sysfs_scsi_get_hctl(cxt, &host, NULL, NULL, NULL)) + return NULL; + + if (attr) + len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d/%s", + type, host, attr); + else + len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d", + type, host); + + return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf; +} + +char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, + const char *type, const char *attr) +{ + char buf[1024]; + int rc; + FILE *f; + + if (!attr || !type || + !sysfs_scsi_host_attribute_path(cxt, type, buf, sizeof(buf), attr)) + return NULL; + + if (!(f = fopen(buf, "r" UL_CLOEXECSTR))) + return NULL; + + rc = fscanf(f, "%1023[^\n]", buf); + fclose(f); + + return rc == 1 ? strdup(buf) : NULL; +} + +int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type) +{ + char buf[PATH_MAX]; + struct stat st; + + if (!type || !sysfs_scsi_host_attribute_path(cxt, type, + buf, sizeof(buf), NULL)) + return 0; + + return stat(buf, &st) == 0 && S_ISDIR(st.st_mode); +} + +static char *sysfs_scsi_attribute_path(struct sysfs_cxt *cxt, + char *buf, size_t bufsz, const char *attr) +{ + int len, h, c, t, l; + + if (sysfs_scsi_get_hctl(cxt, &h, &c, &t, &l) != 0) + return NULL; + + if (attr) + len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d/%s", + h,c,t,l, attr); + else + len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d", + h,c,t,l); + return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf; +} + +int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr) +{ + char path[PATH_MAX]; + struct stat st; + + if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), attr)) + return 0; + + return stat(path, &st) == 0; +} + +int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern) +{ + char path[PATH_MAX], linkc[PATH_MAX]; + struct stat st; + ssize_t len; + + if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), NULL)) + return 0; + + if (stat(path, &st) != 0) + return 0; + + len = readlink(path, linkc, sizeof(linkc) - 1); + if (len < 0) + return 0; + + linkc[len] = '\0'; + return strstr(linkc, pattern) != NULL; +} + +#ifdef TEST_PROGRAM_SYSFS +#include <errno.h> +#include <err.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) +{ + struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; + char *devname; + dev_t devno; + char path[PATH_MAX], *sub, *chain; + int i, is_part; + uint64_t u64; + ssize_t len; + + if (argc != 2) + errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]); + + devname = argv[1]; + devno = sysfs_devname_to_devno(devname, NULL); + + if (!devno) + err(EXIT_FAILURE, "failed to read devno"); + + is_part = sysfs_devno_has_attribute(devno, "partition"); + + printf("NAME: %s\n", devname); + printf("DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno)); + printf("DEVNOPATH: %s\n", sysfs_devno_path(devno, path, sizeof(path))); + printf("DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path))); + printf("PARTITION: %s\n", is_part ? "YES" : "NOT"); + + if (sysfs_init(&cxt, devno, NULL)) + return EXIT_FAILURE; + + len = sysfs_readlink(&cxt, NULL, path, sizeof(path) - 1); + if (len > 0) { + path[len] = '\0'; + printf("DEVNOLINK: %s\n", path); + } + + if (!is_part) { + printf("First 5 partitions:\n"); + for (i = 1; i <= 5; i++) { + dev_t dev = sysfs_partno_to_devno(&cxt, i); + if (dev) + printf("\t#%d %d:%d\n", i, major(dev), minor(dev)); + } + } + + printf("SLAVES: %d\n", sysfs_count_dirents(&cxt, "slaves")); + + if (sysfs_read_u64(&cxt, "size", &u64)) + printf("read SIZE failed\n"); + else + printf("SIZE: %jd\n", u64); + + if (sysfs_read_int(&cxt, "queue/hw_sector_size", &i)) + printf("read SECTOR failed\n"); + else + printf("SECTOR: %d\n", i); + + printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path))); + printf("HOTPLUG: %s\n", sysfs_is_hotpluggable(&cxt) ? "yes" : "no"); + + chain = sysfs_get_devchain(&cxt, path, sizeof(path)); + printf("SUBSUSTEMS:\n"); + + while (chain && sysfs_next_subsystem(&cxt, chain, &sub) == 0) { + printf("\t%s\n", sub); + free(sub); + } + + + sysfs_deinit(&cxt); + return EXIT_SUCCESS; +} +#endif diff --git a/libblkid/lib/terminal-colors.d.5 b/libblkid/lib/terminal-colors.d.5 new file mode 100644 index 000000000..66ecf2c48 --- /dev/null +++ b/libblkid/lib/terminal-colors.d.5 @@ -0,0 +1,190 @@ +.\" terminal-colors.d.5 -- +.\" Copyright 2014 Ondrej Oprala <ooprala@redhat.com> +.\" Copyright (C) 2014 Karel Zak <kzak@redhat.com> +.\" Copyright 2014 Red Hat, Inc. +.\" May be distributed under the GNU General Public License +.TH "TERMINAL_COLORS.D" "5" "January 2014" "util-linux" "terminal-colors.d" +.SH "NAME" +terminal-colors.d \- Configure output colorization for various utilities +.SH "SYNOPSIS" +/etc/terminal-colors\&.d/[[\fIname\fR][@\fIterm\fR]\&.][\fItype\fR] +.SH "DESCRIPTION" +Files in this directory determine the default behavior for utilities +when coloring output. + +The +.I name +is a utility name. The name is optional and when none is specified then the +file is used for all unspecified utilities. + +The +.I term +is a terminal identifier (the TERM environment variable). +The terminal identifier is optional and when none is specified then the file +is used for all unspecified terminals. + +The +.I type +is a file type. Supported file types are: +.TP +.B disable +Turns off output colorization for all compatible utilities. +.TP +.B enable +Turns on output colorization; any matching +.B disable +files are ignored. +.TP +.B scheme +Specifies colors used for output. The file format may be specific to the utility, +the default format is described below. +.PP +If there are more files that match for a utility, then the file with the more +specific filename wins. For example, the filename "@xterm.scheme" has less +priority than "dmesg@xterm.scheme". The lowest priority are those files without a +utility name and terminal identifier (e.g. "disable"). + +The user-specific +.I $XDG_CONFIG_HOME/terminal-colors.d +or +.I $HOME/.config/terminal-colors.d +overrides the global setting. + +.SH EXAMPLES +Disable colors for all compatible utilities: +.RS +.br +.B "touch /etc/terminal-colors.d/disable" +.br +.RE + +Disable colors for all compatible utils on a vt100 terminal: +.RS +.br +.B "touch /etc/terminal-colors.d/@vt100.disable" +.br +.RE + +Disable colors for all compatible utils except dmesg(1): +.RS +.br +.B "touch /etc/terminal-colors.d/disable" +.sp +.B "touch /etc/terminal-colors.d/dmesg.enable" +.br +.RE + +.SH DEFAULT SCHEME FILES FORMAT +The following statement is recognized: + +.RS +.br +.B "name color-sequence" +.br +.RE + +The +.B name +is a logical name of color sequence (for example "error"). The names are +specific to the utilities. For more details always see the COLORS section +in the man page for the utility. + +The +.B color-sequence +is a color name, ASCII color sequences or escape sequences. + +.SS Color names +black, blue, brown, cyan, darkgray, gray, green, lightblue, lightcyan +lightgray, lightgreen, lightmagenta, lightred, magenta, red and yellow +.SS ANSI color sequences +The color sequences are composed of sequences of numbers +separated by semicolons. The most common codes are: +.sp +.RS +.TS +l l. + 0 to restore default color + 1 for brighter colors + 4 for underlined text + 5 for flashing text +30 for black foreground +31 for red foreground +32 for green foreground +33 for yellow (or brown) foreground +34 for blue foreground +35 for purple foreground +36 for cyan foreground +37 for white (or gray) foreground +40 for black background +41 for red background +42 for green background +43 for yellow (or brown) background +44 for blue background +45 for purple background +46 for cyan background +47 for white (or gray) background +.TE +.RE +.SS Escape sequences +To specify control or blank characters in the color sequences, +C-style \e-escaped notation can be used: +.sp +.RS +.TS +lb l. +\ea Bell (ASCII 7) +\eb Backspace (ASCII 8) +\ee Escape (ASCII 27) +\ef Form feed (ASCII 12) +\en Newline (ASCII 10) +\er Carriage Return (ASCII 13) +\et Tab (ASCII 9) +\ev Vertical Tab (ASCII 11) +\e? Delete (ASCII 127) +\e_ Space +\e\e Backslash (\e) +\e^ Caret (^) +\e# Hash mark (#) +.TE +.RE +.sp +Please note that escapes are necessary to enter a space, backslash, +caret, or any control character anywhere in the string, as well as a +hash mark as the first character. + +For example, to use a red background for alert messages in the output of +.BR dmesg (1), +use: + +.RS +.br +.B "echo 'alert 37;41' >> /etc/terminal-colors.d/dmesg.scheme" +.br +.RE + +.SS Comments +Lines where the first non-blank character is a # (hash) are ignored. +Any other use of the hash character is not interpreted as introducing +a comment. + +.SH FILES +.B $XDG_CONFIG_HOME/terminal-colors.d +.br +.B $HOME/.config/terminal-colors.d +.br +.B /etc/terminal-colors.d + +.SH ENVIRONMENT +.IP TERMINAL_COLORS_DEBUG=all +enables debug output. + +.SH COMPATIBILITY +The terminal-colors.d functionality is currently supported by all util-linux +utilities which provides colorized output. For more details always see the +COLORS section in the man page for the utility. + +.SH AVAILABILITY +terminal-colors.d is part of the util-linux package and is available from +.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/ +Linux Kernel Archive +.UE . diff --git a/libblkid/lib/timeutils.c b/libblkid/lib/timeutils.c new file mode 100644 index 000000000..b811041e4 --- /dev/null +++ b/libblkid/lib/timeutils.c @@ -0,0 +1,342 @@ +/*** + First set of functions in this file are part of systemd, and were + copied to util-linux at August 2013. + + Copyright 2010 Lennart Poettering + + systemd 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. + + systemd 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 util-linux; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <sys/sysinfo.h> +#include <sys/time.h> +#include <time.h> + +#include "c.h" +#include "nls.h" +#include "strutils.h" +#include "timeutils.h" + +#define WHITESPACE " \t\n\r" + +#define streq(a,b) (strcmp((a),(b)) == 0) + +static int parse_sec(const char *t, usec_t *usec) +{ + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "seconds", USEC_PER_SEC }, + { "second", USEC_PER_SEC }, + { "sec", USEC_PER_SEC }, + { "s", USEC_PER_SEC }, + { "minutes", USEC_PER_MINUTE }, + { "minute", USEC_PER_MINUTE }, + { "min", USEC_PER_MINUTE }, + { "months", USEC_PER_MONTH }, + { "month", USEC_PER_MONTH }, + { "msec", USEC_PER_MSEC }, + { "ms", USEC_PER_MSEC }, + { "m", USEC_PER_MINUTE }, + { "hours", USEC_PER_HOUR }, + { "hour", USEC_PER_HOUR }, + { "hr", USEC_PER_HOUR }, + { "h", USEC_PER_HOUR }, + { "days", USEC_PER_DAY }, + { "day", USEC_PER_DAY }, + { "d", USEC_PER_DAY }, + { "weeks", USEC_PER_WEEK }, + { "week", USEC_PER_WEEK }, + { "w", USEC_PER_WEEK }, + { "years", USEC_PER_YEAR }, + { "year", USEC_PER_YEAR }, + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, + { "", USEC_PER_SEC }, /* default is sec */ + }; + + const char *p; + usec_t r = 0; + int something = FALSE; + + assert(t); + assert(usec); + + p = t; + for (;;) { + long long l, z = 0; + char *e; + unsigned i, n = 0; + + p += strspn(p, WHITESPACE); + + if (*p == 0) { + if (!something) + return -EINVAL; + + break; + } + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (*e == '.') { + char *b = e + 1; + + errno = 0; + z = strtoll(b, &e, 10); + if (errno > 0) + return -errno; + + if (z < 0) + return -ERANGE; + + if (e == b) + return -EINVAL; + + n = e - b; + + } else if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ARRAY_SIZE(table); i++) + if (startswith(e, table[i].suffix)) { + usec_t k = (usec_t) z * table[i].usec; + + for (; n > 0; n--) + k /= 10; + + r += (usec_t) l *table[i].usec + k; + p = e + strlen(table[i].suffix); + + something = TRUE; + break; + } + + if (i >= ARRAY_SIZE(table)) + return -EINVAL; + + } + + *usec = r; + + return 0; +} + +int parse_timestamp(const char *t, usec_t *usec) +{ + static const struct { + const char *name; + const int nr; + } day_nr[] = { + { "Sunday", 0 }, + { "Sun", 0 }, + { "Monday", 1 }, + { "Mon", 1 }, + { "Tuesday", 2 }, + { "Tue", 2 }, + { "Wednesday", 3 }, + { "Wed", 3 }, + { "Thursday", 4 }, + { "Thu", 4 }, + { "Friday", 5 }, + { "Fri", 5 }, + { "Saturday", 6 }, + { "Sat", 6 }, + }; + + const char *k; + struct tm tm, copy; + time_t x; + usec_t plus = 0, minus = 0, ret; + int r, weekday = -1; + unsigned i; + + /* + * Allowed syntaxes: + * + * 2012-09-22 16:34:22 + * 2012-09-22 16:34 (seconds will be set to 0) + * 2012-09-22 (time will be set to 00:00:00) + * 16:34:22 (date will be set to today) + * 16:34 (date will be set to today, seconds to 0) + * now + * yesterday (time is set to 00:00:00) + * today (time is set to 00:00:00) + * tomorrow (time is set to 00:00:00) + * +5min + * -5days + * + */ + + assert(t); + assert(usec); + + x = time(NULL); + localtime_r(&x, &tm); + tm.tm_isdst = -1; + + if (streq(t, "now")) + goto finish; + + else if (streq(t, "today")) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (streq(t, "yesterday")) { + tm.tm_mday--; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (streq(t, "tomorrow")) { + tm.tm_mday++; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + + } else if (t[0] == '+') { + + r = parse_sec(t + 1, &plus); + if (r < 0) + return r; + + goto finish; + } else if (t[0] == '-') { + + r = parse_sec(t + 1, &minus); + if (r < 0) + return r; + + goto finish; + + } else if (endswith(t, " ago")) { + char *z; + + z = strndup(t, strlen(t) - 4); + if (!z) + return -ENOMEM; + + r = parse_sec(z, &minus); + free(z); + if (r < 0) + return r; + + goto finish; + } + + for (i = 0; i < ARRAY_SIZE(day_nr); i++) { + size_t skip; + + if (!startswith_no_case(t, day_nr[i].name)) + continue; + + skip = strlen(day_nr[i].name); + if (t[skip] != ' ') + continue; + + weekday = day_nr[i].nr; + t += skip + 1; + break; + } + + copy = tm; + k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%H:%M:%S", &tm); + if (k && *k == 0) + goto finish; + + tm = copy; + k = strptime(t, "%H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + tm = copy; + k = strptime(t, "%Y%m%d%H%M%S", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto finish; + } + + return -EINVAL; + + finish: + x = mktime(&tm); + if (x == (time_t)-1) + return -EINVAL; + + if (weekday >= 0 && tm.tm_wday != weekday) + return -EINVAL; + + ret = (usec_t) x *USEC_PER_SEC; + + ret += plus; + if (ret > minus) + ret -= minus; + else + ret = 0; + + *usec = ret; + + return 0; +} diff --git a/libblkid/lib/ttyutils.c b/libblkid/lib/ttyutils.c new file mode 100644 index 000000000..ea551e26c --- /dev/null +++ b/libblkid/lib/ttyutils.c @@ -0,0 +1,95 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + * + * Written by Karel Zak <kzak@redhat.com> + */ +#include <ctype.h> + +#include "c.h" +#include "ttyutils.h" + +int get_terminal_width(void) +{ +#ifdef TIOCGSIZE + struct ttysize t_win; +#endif +#ifdef TIOCGWINSZ + struct winsize w_win; +#endif + const char *cp; + +#ifdef TIOCGSIZE + if (ioctl (STDIN_FILENO, TIOCGSIZE, &t_win) == 0) + return t_win.ts_cols; +#endif +#ifdef TIOCGWINSZ + if (ioctl (STDIN_FILENO, TIOCGWINSZ, &w_win) == 0) + return w_win.ws_col; +#endif + cp = getenv("COLUMNS"); + if (cp) { + char *end = NULL; + long c; + + errno = 0; + c = strtol(cp, &end, 10); + + if (errno == 0 && end && *end == '\0' && end > cp && + c > 0 && c <= INT_MAX) + return c; + } + return 0; +} + +int get_terminal_name(int fd, + const char **path, + const char **name, + const char **number) +{ + const char *tty; + const char *p; + + if (name) + *name = NULL; + if (path) + *path = NULL; + if (number) + *number = NULL; + + tty = ttyname(fd); + if (!tty) + return -1; + if (path) + *path = tty; + tty = strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty; + if (name) + *name = tty; + if (number) { + for (p = tty; p && *p; p++) { + if (isdigit(*p)) { + *number = p; + break; + } + } + } + return 0; +} + + +#ifdef TEST_PROGRAM +# include <stdlib.h> +int main(void) +{ + const char *path, *name, *num; + + if (get_terminal_name(STDERR_FILENO, &path, &name, &num) == 0) { + fprintf(stderr, "tty path: %s\n", path); + fprintf(stderr, "tty name: %s\n", name); + fprintf(stderr, "tty number: %s\n", num); + } + fprintf(stderr, "tty width: %d\n", get_terminal_width()); + + return EXIT_SUCCESS; +} +#endif diff --git a/libblkid/libblkid.3 b/libblkid/libblkid.3 new file mode 100644 index 000000000..58ca91cbb --- /dev/null +++ b/libblkid/libblkid.3 @@ -0,0 +1,79 @@ +.\" Copyright 2001 Andreas Dilger (adilger@turbolinux.com) +.\" +.\" This man page was created for libblkid.so.1.0 from e2fsprogs-1.24. +.\" +.\" This file may be copied under the terms of the GNU Lesser General Public +.\" License. +.\" +.\" Created Wed Sep 14 12:02:12 2001, Andreas Dilger +.TH LIBBLKID 3 "May 2009" "util-linux" "Programmer's Manual" +.SH NAME +libblkid \- block device identification library +.SH SYNOPSIS +.B #include <blkid.h> +.sp +.B cc +.I file.c +.B \-lblkid +.SH DESCRIPTION +The +.B libblkid +library is used to identify block devices (disks) as to their content (e.g. +filesystem type) as well as extracting additional information such as +filesystem labels/volume names, unique identifiers/serial numbers. +A common use is to allow use of LABEL= and UUID= tags instead of hard-coding +specific block device names into configuration files. +.P +The low-level part of the library also allows to extract information about +partitions and block device topology. +.P +The high-level part of the library keeps information about block devices in a +cache file and is verified to still be valid before being returned to the user +(if the user has read permission on the raw block device, otherwise not). +The cache file also allows unprivileged users (normally anyone other +than root, or those not in the "disk" group) to locate devices by label/id. +The standard location of the cache file can be overridden by the +environment variable BLKID_FILE. +.P +In situations where one is getting information about a single known device, it +does not impact performance whether the cache is used or not (unless you are +not able to read the block device directly). +.P +The high-level part of the library supports two methods to evaluate LABEL/UUID. +It reads information directly from a block device or read information from +/dev/disk/by-* udev symlinks. The udev is preferred method by default. +.P +If you are dealing with +multiple devices, use of the cache is highly recommended (even if empty) as +devices will be scanned at most one time and the on-disk cache will be +updated if possible. +.P +In some cases (modular kernels), block devices are not even visible until +after they are accessed the first time, so it is critical that there is +some way to locate these devices without enumerating only visible devices, +so the use of the cache file is +.B required +in this situation. +.SH CONFIGURATION FILE +The standard location of the +.I /etc/blkid.conf +config file can be overridden by the environment variable BLKID_CONF. For more +details about the config file see +.BR blkid (8) +man page. +.SH AUTHOR +.B libblkid +was written by Andreas Dilger for the ext2 filesystem utilties, with input +from Ted Ts'o. The library was subsequently heavily modified by Ted Ts'o. + +The low-level probing code was rewritten by Karel Zak. +.SH COPYING +.B libblkid +is available under the terms of the GNU Library General Public License (LGPL), +version 2 (or at your discretion any later version). +.SH "SEE ALSO" +.BR blkid (8), +.BR findfs (8) +.SH AVAILABILITY +libblkid is part of the util-linux package since version 2.15 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. diff --git a/libblkid/libfdisk/COPYING b/libblkid/libfdisk/COPYING new file mode 100644 index 000000000..be1a5b3a1 --- /dev/null +++ b/libblkid/libfdisk/COPYING @@ -0,0 +1,8 @@ +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. + +The complete text of the license is available in the +../Documentation/licenses/COPYING.LGPLv2.1 file. diff --git a/libblkid/libfdisk/Makemodule.am b/libblkid/libfdisk/Makemodule.am new file mode 100644 index 000000000..5d8334164 --- /dev/null +++ b/libblkid/libfdisk/Makemodule.am @@ -0,0 +1,14 @@ +if BUILD_LIBFDISK + +include libfdisk/src/Makemodule.am + +if ENABLE_GTK_DOC +# Docs uses separate Makefiles +SUBDIRS += libfdisk/docs +endif + +pkgconfig_DATA += libfdisk/fdisk.pc +PATHFILES += libfdisk/fdisk.pc +EXTRA_DIST += libfdisk/COPYING + +endif # BUILD_LIBFDISK diff --git a/libblkid/libfdisk/docs/.gitignore b/libblkid/libfdisk/docs/.gitignore new file mode 100644 index 000000000..f91f93db7 --- /dev/null +++ b/libblkid/libfdisk/docs/.gitignore @@ -0,0 +1,18 @@ +*-decl-list.txt +*-decl.txt +*-overrides.txt +*-undeclared.txt +*-undocumented.txt +*-unused.txt +*.args +*.bak +*.hierarchy +*.interfaces +*.prerequisites +*.signals +*.stamp +*.types +html/* +tmpl/* +version.xml +xml/* diff --git a/libblkid/libfdisk/docs/Makefile.am b/libblkid/libfdisk/docs/Makefile.am new file mode 100644 index 000000000..dc7097995 --- /dev/null +++ b/libblkid/libfdisk/docs/Makefile.am @@ -0,0 +1,93 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.10 at least. +AUTOMAKE_OPTIONS = 1.10 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=libfdisk + +# Uncomment for versioned docs and specify the version of the module, e.g. '2'. +#DOC_MODULE_VERSION=2 + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=../src + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS= + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space fdisk + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-mkhtml +MKHTML_OPTIONS= + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS= + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(top_builddir)/libfdisk/src/libfdisk.h +CFILE_GLOB=$(top_srcdir)/libfdisk/src/*.c + +# Extra header to include when scanning, which are not under DOC_SOURCE_DIR +# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h +EXTRA_HFILES= + +# Header files to ignore when scanning. Use base file name, no paths +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES=fdiskP.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = $(builddir)/version.xml + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_CFLAGS= +GTKDOC_LIBS= + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/config/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += version.xml.in + +# Files not to distribute +# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types +# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt +DISTCLEANFILES += version.xml diff --git a/libblkid/libfdisk/docs/libfdisk-docs.xml b/libblkid/libfdisk/docs/libfdisk-docs.xml new file mode 100644 index 000000000..546d007a7 --- /dev/null +++ b/libblkid/libfdisk/docs/libfdisk-docs.xml @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" + "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" +[ + <!ENTITY version SYSTEM "version.xml"> +]> +<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> + <bookinfo> + <title>libfdisk Reference Manual</title> + <releaseinfo>for libfdisk version &version;</releaseinfo> + <copyright> + <year>2014</year> + <holder>Karel Zak <kzak@redhat.com></holder> + </copyright> + </bookinfo> + + <part id="over"> + <title>libfdisk Overview</title> + <partintro> + <para> +The libfdisk library is used for manipulating with partition tables. + </para> + <para> +The library is part of the util-linux package since version 2.26 and is +available from ftp://ftp.kernel.org/pub/linux/utils/util-linux/. + </para> + </partintro> + </part> + + <part> + <title>Basic handlers and setting</title> + <xi:include href="xml/context.xml"/> + <xi:include href="xml/ask.xml"/> + <xi:include href="xml/alignment.xml"/> + <xi:include href="xml/script.xml"/> + </part> + <part> + <title>Partitining</title> + <xi:include href="xml/label.xml"/> + <xi:include href="xml/partition.xml"/> + <xi:include href="xml/table.xml"/> + <xi:include href="xml/parttype.xml"/> + </part> + <part> + <title>Label specific functions</title> + <xi:include href="xml/dos.xml"/> + <xi:include href="xml/gpt.xml"/> + <xi:include href="xml/sun.xml"/> + <xi:include href="xml/sgi.xml"/> + <xi:include href="xml/bsd.xml"/> + </part> + <part> + <title>Misc</title> + <xi:include href="xml/iter.xml"/> + <xi:include href="xml/utils.xml"/> + <xi:include href="xml/init.xml"/> + </part> + <index id="api-index-full"> + <title>API Index</title> + <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> + </index> +</book> diff --git a/libblkid/libfdisk/docs/libfdisk-sections.txt b/libblkid/libfdisk/docs/libfdisk-sections.txt new file mode 100644 index 000000000..c0aaeaef8 --- /dev/null +++ b/libblkid/libfdisk/docs/libfdisk-sections.txt @@ -0,0 +1,303 @@ +<SECTION> +<FILE>init</FILE> +fdisk_init_debug +</SECTION> + +<SECTION> +<FILE>ask</FILE> +fdisk_info +fdisk_warn +fdisk_warnx +fdisk_set_ask +<SUBSECTION> +fdisk_ask +fdisk_ask_get_query +fdisk_ask_get_type +fdisk_ask_menu_get_default +fdisk_ask_menu_get_item +fdisk_ask_menu_get_nitems +fdisk_ask_menu_get_result +fdisk_ask_menu_set_result +fdisk_ask_number +fdisk_ask_number_get_base +fdisk_ask_number_get_default +fdisk_ask_number_get_high +fdisk_ask_number_get_low +fdisk_ask_number_get_range +fdisk_ask_number_get_result +fdisk_ask_number_get_unit +fdisk_ask_number_inchars +fdisk_ask_number_set_relative +fdisk_ask_number_set_result +fdisk_ask_partnum +fdisk_ask_print_get_errno +fdisk_ask_print_get_mesg +fdisk_ask_string +fdisk_ask_string_get_result +fdisk_ask_string_set_result +fdisk_ask_yesno +fdisk_ask_yesno_get_result +fdisk_ask_yesno_set_result +fdisk_ref_ask +fdisk_unref_ask +</SECTION> + +<SECTION> +<FILE>alignment</FILE> +fdisk_align_lba +fdisk_align_lba_in_range +fdisk_has_user_device_properties +fdisk_lba_is_phy_aligned +fdisk_override_geometry +fdisk_reread_partition_table +fdisk_reset_alignment +fdisk_reset_device_properties +fdisk_save_user_geometry +fdisk_save_user_sector_size +</SECTION> + +<SECTION> +<FILE>label</FILE> +fdisk_create_disklabel +fdisk_list_disklabel +fdisk_locate_disklabel +fdisk_reorder_partitions +fdisk_set_disklabel_id +fdisk_set_partition_type +fdisk_toggle_partition_flag +fdisk_verify_disklabel +fdisk_write_disklabel +<SUBSECTION> +fdisk_get_disklabel_id +fdisk_get_label +fdisk_get_nlabels +fdisk_next_label +fdisk_get_npartitions +<SUBSECTION> +fdisk_field +fdisk_field_get_id +fdisk_field_get_name +fdisk_field_get_width +fdisk_field_is_number +<SUBSECTION> +fdisk_label +fdisk_label_get_field +fdisk_label_get_field_by_name +fdisk_label_get_fields_ids +fdisk_label_get_name +fdisk_label_get_nparttypes +fdisk_label_get_parttype +fdisk_label_get_parttype_from_code +fdisk_label_get_parttype_from_string +fdisk_label_get_type +fdisk_label_has_code_parttypes +fdisk_label_is_changed +fdisk_label_is_disabled +fdisk_label_parse_parttype +fdisk_label_require_geometry +fdisk_label_set_changed +fdisk_label_set_disabled +</SECTION> + +<SECTION> +<FILE>script</FILE> +fdisk_set_script +fdisk_get_script +<SUBSECTION> +fdisk_apply_script +fdisk_apply_script_headers +<SUBSECTION> +fdisk_script +fdisk_new_script +fdisk_new_script_from_file +fdisk_ref_script +fdisk_script_get_header +fdisk_script_get_nlines +fdisk_script_get_table +fdisk_script_read_context +fdisk_script_read_file +fdisk_script_read_line +fdisk_script_set_header +fdisk_script_write_file +fdisk_unref_script +</SECTION> + +<SECTION> +<FILE>bsd</FILE> +fdisk_bsd_edit_disklabel +fdisk_bsd_link_partition +fdisk_bsd_write_bootstrap +</SECTION> + +<SECTION> +<FILE>partition</FILE> +fdisk_add_partition +fdisk_delete_all_partitions +fdisk_delete_partition +fdisk_get_partition +fdisk_is_partition_used +fdisk_set_partition +<SUBSECTION> +fdisk_partition +fdisk_new_partition +fdisk_partition_cmp_partno +fdisk_partition_cmp_start +fdisk_partition_end_follow_default +fdisk_partition_end_is_default +fdisk_partition_get_attrs +fdisk_partition_get_end +fdisk_partition_get_name +fdisk_partition_get_parent +fdisk_partition_get_partno +fdisk_partition_get_size +fdisk_partition_get_start +fdisk_partition_get_type +fdisk_partition_get_uuid +fdisk_partition_has_end +fdisk_partition_has_partno +fdisk_partition_has_size +fdisk_partition_has_start +fdisk_partition_is_bootable +fdisk_partition_is_container +fdisk_partition_is_freespace +fdisk_partition_is_nested +fdisk_partition_is_used +fdisk_partition_next_partno +fdisk_partition_partno_follow_default +fdisk_partition_set_attrs +fdisk_partition_set_name +fdisk_partition_set_partno +fdisk_partition_set_size +fdisk_partition_set_start +fdisk_partition_set_type +fdisk_partition_set_uuid +fdisk_partition_size_explicit +fdisk_partition_start_follow_default +fdisk_partition_start_is_default +fdisk_partition_to_string +fdisk_partition_unset_partno +fdisk_partition_unset_size +fdisk_partition_unset_start +fdisk_ref_partition +fdisk_reset_partition +fdisk_unref_partition +</SECTION> + +<SECTION> +<FILE>dos</FILE> +fdisk_dos_enable_compatible +fdisk_dos_is_compatible +fdisk_dos_move_begin +</SECTION> + +<SECTION> +<FILE>sgi</FILE> +fdisk_sgi_create_info +fdisk_sgi_set_bootfile +</SECTION> + +<SECTION> +<FILE>gpt</FILE> +fdisk_gpt_is_hybrid +</SECTION> + +<SECTION> +<FILE>sun</FILE> +fdisk_sun_set_alt_cyl +fdisk_sun_set_ilfact +fdisk_sun_set_pcylcount +fdisk_sun_set_rspeed +fdisk_sun_set_xcyl +</SECTION> + +<SECTION> +<FILE>parttype</FILE> +fdisk_parttype +fdisk_copy_parttype +fdisk_new_parttype +fdisk_new_unknown_parttype +fdisk_parttype_get_code +fdisk_parttype_get_name +fdisk_parttype_get_string +fdisk_parttype_is_unknown +fdisk_parttype_set_code +fdisk_parttype_set_name +fdisk_parttype_set_typestr +fdisk_ref_parttype +fdisk_unref_parttype +</SECTION> + +<SECTION> +<FILE>table</FILE> +fdisk_get_freespaces +fdisk_get_partitions +<SUBSECTION> +fdisk_table +fdisk_apply_table +fdisk_new_table +fdisk_ref_table +fdisk_reset_table +fdisk_table_add_partition +fdisk_table_get_nents +fdisk_table_get_partition +fdisk_table_is_empty +fdisk_table_next_partition +fdisk_table_remove_partition +fdisk_table_sort_partitions +fdisk_table_wrong_order +fdisk_unref_table +</SECTION> + + +<SECTION> +<FILE>context</FILE> +fdisk_context +fdisk_assign_device +fdisk_deassign_device +fdisk_enable_details +fdisk_enable_listonly +fdisk_get_alignment_offset +fdisk_get_devfd +fdisk_get_devname +fdisk_get_first_lba +fdisk_get_geom_cylinders +fdisk_get_geom_heads +fdisk_get_geom_sectors +fdisk_get_grain_size +fdisk_get_last_lba +fdisk_get_minimal_iosize +fdisk_get_nsectors +fdisk_get_optimal_iosize +fdisk_get_parent +fdisk_get_physector_size +fdisk_get_sector_size +fdisk_get_unit +fdisk_get_units_per_sector +fdisk_has_label +fdisk_has_user_device_properties +fdisk_is_details +fdisk_is_labeltype +fdisk_is_listonly +fdisk_is_readonly +fdisk_new_context +fdisk_new_nested_context +fdisk_ref_context +fdisk_set_first_lba +fdisk_set_last_lba +fdisk_set_unit +fdisk_unref_context +fdisk_use_cylinders +</SECTION> + +<SECTION> +<FILE>utils</FILE> +fdisk_partname +</SECTION> + +<SECTION> +<FILE>iter</FILE> +fdisk_free_iter +fdisk_iter_get_direction +fdisk_new_iter +fdisk_reset_iter +</SECTION> diff --git a/libblkid/libfdisk/docs/version.xml.in b/libblkid/libfdisk/docs/version.xml.in new file mode 100644 index 000000000..d78bda934 --- /dev/null +++ b/libblkid/libfdisk/docs/version.xml.in @@ -0,0 +1 @@ +@VERSION@ diff --git a/libblkid/libfdisk/fdisk.pc.in b/libblkid/libfdisk/fdisk.pc.in new file mode 100644 index 000000000..bf81df009 --- /dev/null +++ b/libblkid/libfdisk/fdisk.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@usrlib_execdir@ +includedir=@includedir@ + +Name: fdisk +Description: fdisk library +Version: @LIBFDISK_VERSION@ +Requires.private: @LIBFDISK_PC_REQUIRES@ +Cflags: -I${includedir}/libfdisk +Libs: -L${libdir} -lfdisk diff --git a/libblkid/libfdisk/src/.gitignore b/libblkid/libfdisk/src/.gitignore new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/libblkid/libfdisk/src/.gitignore diff --git a/libblkid/libfdisk/src/Makemodule.am b/libblkid/libfdisk/src/Makemodule.am new file mode 100644 index 000000000..18ddec739 --- /dev/null +++ b/libblkid/libfdisk/src/Makemodule.am @@ -0,0 +1,112 @@ + +# libfdisk.h is generated, so it's stored in builddir! +fdiskincdir = $(includedir)/libfdisk +nodist_fdiskinc_HEADERS = $(top_builddir)/libfdisk/src/libfdisk.h + +usrlib_exec_LTLIBRARIES += libfdisk.la +libfdisk_la_SOURCES = \ + include/list.h \ + \ + libfdisk/src/fdiskP.h \ + libfdisk/src/init.c \ + libfdisk/src/test.c \ + libfdisk/src/ask.c \ + libfdisk/src/alignment.c \ + libfdisk/src/label.c \ + libfdisk/src/utils.c \ + libfdisk/src/context.c \ + libfdisk/src/parttype.c \ + libfdisk/src/partition.c \ + libfdisk/src/table.c \ + libfdisk/src/iter.c \ + libfdisk/src/script.c \ + \ + libfdisk/src/sun.c \ + libfdisk/src/sgi.c \ + libfdisk/src/dos.c \ + libfdisk/src/bsd.c \ + libfdisk/src/gpt.c \ + $(nodist_fdiskinc_HEADERS) + + +nodist_libfdisk_la_SOURCES = libfdisk/src/fdiskP.h + +libfdisk_la_LIBADD = libcommon.la libuuid.la + +libfdisk_la_CFLAGS = \ + $(SOLIB_CFLAGS) \ + -I$(ul_libuuid_incdir) \ + -I$(ul_libfdisk_incdir) \ + -I$(top_srcdir)/libfdisk/src + +libfdisk_la_DEPENDENCIES = \ + libcommon.la \ + libuuid.la \ + libfdisk/src/libfdisk.sym \ + libfdisk/src/libfdisk.h.in + +libfdisk_la_LDFLAGS = \ + $(SOLIB_LDFLAGS) \ + -Wl,--version-script=$(top_srcdir)/libfdisk/src/libfdisk.sym \ + -version-info $(LIBFDISK_VERSION_INFO) + +if BUILD_LIBBLKID +libfdisk_la_LIBADD += libblkid.la +libfdisk_la_DEPENDENCIES += libblkid.la +libfdisk_la_CFLAGS += -I$(ul_libblkid_incdir) +endif + +EXTRA_DIST += \ + libfdisk/src/libfdisk.sym \ + libfdisk/src/libfdisk.h.in + +if BUILD_LIBFDISK_TESTS +check_PROGRAMS += \ + test_fdisk_ask \ + test_fdisk_script \ + test_fdisk_utils + +libfdisk_tests_cflags = -DTEST_PROGRAM $(libfdisk_la_CFLAGS) +libfdisk_tests_ldflags = libuuid.la -static +libfdisk_tests_ldadd = libfdisk.la $(UUID_LIBS) + +if BUILD_LIBBLKID +libfdisk_tests_ldflags += libblkid.la +endif + +test_fdisk_ask_SOURCES = libfdisk/src/ask.c +test_fdisk_ask_CFLAGS = $(libfdisk_tests_cflags) +test_fdisk_ask_LDFLAGS = $(libfdisk_tests_ldflags) +test_fdisk_ask_LDADD = $(libfdisk_tests_ldadd) + +test_fdisk_utils_SOURCES = libfdisk/src/utils.c +test_fdisk_utils_CFLAGS = $(libfdisk_tests_cflags) +test_fdisk_utils_LDFLAGS = $(libfdisk_tests_ldflags) +test_fdisk_utils_LDADD = $(libfdisk_tests_ldadd) + +test_fdisk_script_SOURCES = libfdisk/src/script.c +test_fdisk_script_CFLAGS = $(libfdisk_tests_cflags) +test_fdisk_script_LDFLAGS = $(libfdisk_tests_ldflags) +test_fdisk_script_LDADD = $(libfdisk_tests_ldadd) + +endif # BUILD_LIBFDISK_TESTS + + +# move lib from $(usrlib_execdir) to $(libdir) if needed +install-exec-hook-libfdisk: + if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libfdisk.so"; then \ + mkdir -p $(DESTDIR)$(libdir); \ + mv $(DESTDIR)$(usrlib_execdir)/libfdisk.so.* $(DESTDIR)$(libdir); \ + so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libfdisk.so); \ + so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ + (cd $(DESTDIR)$(usrlib_execdir) && \ + rm -f libfdisk.so && \ + $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libfdisk.so); \ + fi + +uninstall-hook-libfdisk: + rm -f $(DESTDIR)$(libdir)/libfdisk.so* + +INSTALL_EXEC_HOOKS += install-exec-hook-libfdisk +UNINSTALL_HOOKS += uninstall-hook-libfdisk + diff --git a/libblkid/libfdisk/src/alignment.c b/libblkid/libfdisk/src/alignment.c new file mode 100644 index 000000000..67f1ddd08 --- /dev/null +++ b/libblkid/libfdisk/src/alignment.c @@ -0,0 +1,654 @@ + +#ifdef HAVE_LIBBLKID +#include <blkid.h> +#endif +#include "blkdev.h" + +#include "fdiskP.h" + +/** + * SECTION: alignment + * @title: Alignment + * @short_description: functions to align partitions and work with disk topology and geometry + * + * The libfdisk aligns the end of the partitions to make it possible to align + * the next partition to the "grain" (see fdisk_get_grain()). The grain is + * usually 1MiB (or more for devices where optimal I/O is greater than 1MiB). + * + * It means that the library does not align strictly to physical sector size + * (or minimal or optimal I/O), but it uses greater granularity. It makes + * partition tables more portable. If you copy disk layout from 512-sector to + * 4K-sector device, all partitions are still aligned to physical sectors. + * + * This unified concept also makes partition tables more user friendly, all + * tables look same, LBA of the first partition is 2048 sectors everywhere, etc. + * + * It's recommended to not change any alignment or device properties. All is + * initialized by default by fdisk_assign_device(). + * + * Note that terminology used by libfdisk is: + * - device properties: I/O limits (topology), geometry, sector size, ... + * - alignment: first, last LBA, grain, ... + * + * The alignment setting may be modified by disk label driver. + */ + +/* + * Alignment according to logical granularity (usually 1MiB) + */ +static int lba_is_aligned(struct fdisk_context *cxt, fdisk_sector_t lba) +{ + unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size); + uintmax_t offset; + + if (cxt->grain > granularity) + granularity = cxt->grain; + offset = (lba * cxt->sector_size) & (granularity - 1); + + return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); +} + +/* + * Alignment according to physical device topology (usually minimal i/o size) + */ +static int lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba) +{ + unsigned long granularity = max(cxt->phy_sector_size, cxt->min_io_size); + uintmax_t offset = (lba * cxt->sector_size) & (granularity - 1); + + return !((granularity + cxt->alignment_offset - offset) & (granularity - 1)); +} + +/** + * fdisk_align_lba: + * @cxt: context + * @lba: address to align + * @direction: FDISK_ALIGN_{UP,DOWN,NEAREST} + * + * This function aligns @lba to the "grain" (see fdisk_get_grain()). If the + * device uses alignment offset then the result is moved according the offset + * to be on the physical boundary. + * + * Returns: alignment LBA. + */ +fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction) +{ + fdisk_sector_t res; + + if (lba_is_aligned(cxt, lba)) + res = lba; + else { + fdisk_sector_t sects_in_phy = cxt->grain / cxt->sector_size; + + if (lba < cxt->first_lba) + res = cxt->first_lba; + + else if (direction == FDISK_ALIGN_UP) + res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy; + + else if (direction == FDISK_ALIGN_DOWN) + res = (lba / sects_in_phy) * sects_in_phy; + + else /* FDISK_ALIGN_NEAREST */ + res = ((lba + sects_in_phy / 2) / sects_in_phy) * sects_in_phy; + + if (cxt->alignment_offset && !lba_is_aligned(cxt, res) && + res > cxt->alignment_offset / cxt->sector_size) { + /* + * apply alignment_offset + * + * On disk with alignment compensation physical blocks starts + * at LBA < 0 (usually LBA -1). It means we have to move LBA + * according the offset to be on the physical boundary. + */ + /* fprintf(stderr, "LBA: %llu apply alignment_offset\n", res); */ + res -= (max(cxt->phy_sector_size, cxt->min_io_size) - + cxt->alignment_offset) / cxt->sector_size; + + if (direction == FDISK_ALIGN_UP && res < lba) + res += sects_in_phy; + } + } + + if (lba != res) + DBG(CXT, ul_debugobj(cxt, "LBA %ju -aligned-to-> %ju", + (uintmax_t) lba, + (uintmax_t) res)); + return res; +} + +/** + * fdisk_align_lba_in_range: + * @cxt: context + * @lba: LBA + * @start: range start + * @stop: range stop + * + * Align @lba, the result has to be between @start and @stop + * + * Returns: aligned LBA + */ +fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, + fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop) +{ + fdisk_sector_t res; + + start = fdisk_align_lba(cxt, start, FDISK_ALIGN_UP); + stop = fdisk_align_lba(cxt, stop, FDISK_ALIGN_DOWN); + lba = fdisk_align_lba(cxt, lba, FDISK_ALIGN_NEAREST); + + if (lba < start) + res = start; + else if (lba > stop) + res = stop; + else + res = lba; + + DBG(CXT, ul_debugobj(cxt, "LBA %ju range:<%ju..%ju>, result: %ju", + (uintmax_t) lba, + (uintmax_t) start, + (uintmax_t) stop, + (uintmax_t) res)); + return res; +} + +/** + * fdisk_lba_is_phy_aligned: + * @cxt: context + * @lba: LBA to check + * + * Check if the @lba is aligned to physical sector boundary. + * + * Returns: 1 if aligned. + */ +int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba) +{ + return lba_is_phy_aligned(cxt, lba); +} + +static unsigned long get_sector_size(int fd) +{ + int sect_sz; + + if (!blkdev_get_sector_size(fd, §_sz)) + return (unsigned long) sect_sz; + return DEFAULT_SECTOR_SIZE; +} + +static void recount_geometry(struct fdisk_context *cxt) +{ + if (!cxt->geom.heads) + cxt->geom.heads = 255; + if (!cxt->geom.sectors) + cxt->geom.sectors = 63; + + cxt->geom.cylinders = cxt->total_sectors / + (cxt->geom.heads * cxt->geom.sectors); +} + +/** + * fdisk_override_geometry: + * @cxt: fdisk context + * @cylinders: user specified cylinders + * @heads: user specified heads + * @sectors: user specified sectors + * + * Overrides auto-discovery. The function fdisk_reset_device_properties() + * restores the original setting. + * + * The difference between fdisk_override_geometry() and fdisk_save_user_geometry() + * is that saved user geometry is persistent setting and it's applied always + * when device is assigned to the context or device properties are reseted. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_override_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors) +{ + if (!cxt) + return -EINVAL; + if (heads) + cxt->geom.heads = heads; + if (sectors) + cxt->geom.sectors = sectors; + + if (cylinders) + cxt->geom.cylinders = cylinders; + else + recount_geometry(cxt); + + fdisk_reset_alignment(cxt); + + DBG(CXT, ul_debugobj(cxt, "override C/H/S: %u/%u/%u", + (unsigned) cxt->geom.cylinders, + (unsigned) cxt->geom.heads, + (unsigned) cxt->geom.sectors)); + + return 0; +} + +/** + * fdisk_save_user_geometry: + * @cxt: context + * @cylinders: C + * @heads: H + * @sectors: S + * + * Save user defined geometry to use it for partitioning. + * + * The user properties are applied by fdisk_assign_device() or + * fdisk_reset_device_properties(). + + * Returns: <0 on error, 0 on success. + */ +int fdisk_save_user_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors) +{ + if (!cxt) + return -EINVAL; + + if (heads) + cxt->user_geom.heads = heads > 256 ? 0 : heads; + if (sectors) + cxt->user_geom.sectors = sectors >= 64 ? 0 : sectors; + if (cylinders) + cxt->user_geom.cylinders = cylinders; + + DBG(CXT, ul_debugobj(cxt, "user C/H/S: %u/%u/%u", + (unsigned) cxt->user_geom.cylinders, + (unsigned) cxt->user_geom.heads, + (unsigned) cxt->user_geom.sectors)); + + return 0; +} + +/** + * fdisk_save_user_sector_size: + * @cxt: context + * @phy: physical sector size + * @log: logicla sector size + * + * Save user defined sector sizes to use it for partitioning. + * + * The user properties are applied by fdisk_assign_device() or + * fdisk_reset_device_properties(). + * + * Returns: <0 on error, 0 on success. + */ +int fdisk_save_user_sector_size(struct fdisk_context *cxt, + unsigned int phy, + unsigned int log) +{ + if (!cxt) + return -EINVAL; + + DBG(CXT, ul_debugobj(cxt, "user phy/log sector size: %u/%u", phy, log)); + + cxt->user_pyh_sector = phy; + cxt->user_log_sector = log; + + return 0; +} + +/** + * fdisk_has_user_device_properties: + * @cxt: context + * + * Returns: 1 if user specified any properties + */ +int fdisk_has_user_device_properties(struct fdisk_context *cxt) +{ + return (cxt->user_pyh_sector + || cxt->user_log_sector + || cxt->user_geom.heads + || cxt->user_geom.sectors + || cxt->user_geom.cylinders); +} + +int fdisk_apply_user_device_properties(struct fdisk_context *cxt) +{ + if (!cxt) + return -EINVAL; + + DBG(CXT, ul_debugobj(cxt, "appling user device properties")); + + if (cxt->user_pyh_sector) + cxt->phy_sector_size = cxt->user_pyh_sector; + if (cxt->user_log_sector) + cxt->sector_size = cxt->min_io_size = + cxt->io_size = cxt->user_log_sector; + + if (cxt->user_geom.heads) + cxt->geom.heads = cxt->user_geom.heads; + if (cxt->user_geom.sectors) + cxt->geom.sectors = cxt->user_geom.sectors; + + if (cxt->user_geom.cylinders) + cxt->geom.cylinders = cxt->user_geom.cylinders; + else if (cxt->user_geom.heads || cxt->user_geom.sectors) + recount_geometry(cxt); + + fdisk_reset_alignment(cxt); + if (cxt->firstsector_bufsz != cxt->sector_size) + fdisk_read_firstsector(cxt); + + DBG(CXT, ul_debugobj(cxt, "new C/H/S: %u/%u/%u", + (unsigned) cxt->geom.cylinders, + (unsigned) cxt->geom.heads, + (unsigned) cxt->geom.sectors)); + DBG(CXT, ul_debugobj(cxt, "new log/phy sector size: %u/%u", + (unsigned) cxt->sector_size, + (unsigned) cxt->phy_sector_size)); + + return 0; +} + +void fdisk_zeroize_device_properties(struct fdisk_context *cxt) +{ + assert(cxt); + + cxt->io_size = 0; + cxt->optimal_io_size = 0; + cxt->min_io_size = 0; + cxt->phy_sector_size = 0; + cxt->sector_size = 0; + cxt->alignment_offset = 0; + cxt->grain = 0; + cxt->first_lba = 0; + cxt->last_lba = 0; + cxt->total_sectors = 0; + + memset(&cxt->geom, 0, sizeof(struct fdisk_geometry)); +} + +/** + * fdisk_reset_device_properties: + * @cxt: context + * + * Resets and discovery topology (I/O limits), geometry, re-read the first + * rector on the device if necessary and apply user device setting (geometry + * and sector size), then initialize alignment according to label driver (see + * fdisk_reset_alignment()). + * + * You don't have to use this function by default, fdisk_assign_device() is + * smart enough to initialize all necessary setting. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_reset_device_properties(struct fdisk_context *cxt) +{ + int rc; + + if (!cxt) + return -EINVAL; + + DBG(CXT, ul_debugobj(cxt, "*** reseting device properties")); + + fdisk_zeroize_device_properties(cxt); + fdisk_discover_topology(cxt); + fdisk_discover_geometry(cxt); + + rc = fdisk_read_firstsector(cxt); + if (rc) + return rc; + + fdisk_apply_user_device_properties(cxt); + return 0; +} + +/* + * Generic (label independent) geometry + */ +int fdisk_discover_geometry(struct fdisk_context *cxt) +{ + fdisk_sector_t nsects; + + assert(cxt); + assert(cxt->geom.heads == 0); + + DBG(CXT, ul_debugobj(cxt, "%s: discovering geometry...", cxt->dev_path)); + + /* get number of 512-byte sectors, and convert it the real sectors */ + if (!blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &nsects)) + cxt->total_sectors = (nsects / (cxt->sector_size >> 9)); + + DBG(CXT, ul_debugobj(cxt, "total sectors: %ju (ioctl=%ju)", + (uintmax_t) cxt->total_sectors, + (uintmax_t) nsects)); + + /* what the kernel/bios thinks the geometry is */ + blkdev_get_geometry(cxt->dev_fd, &cxt->geom.heads, (unsigned int *) &cxt->geom.sectors); + + /* obtained heads and sectors */ + recount_geometry(cxt); + + DBG(CXT, ul_debugobj(cxt, "result: C/H/S: %u/%u/%u", + (unsigned) cxt->geom.cylinders, + (unsigned) cxt->geom.heads, + (unsigned) cxt->geom.sectors)); + return 0; +} + +int fdisk_discover_topology(struct fdisk_context *cxt) +{ +#ifdef HAVE_LIBBLKID + blkid_probe pr; +#endif + assert(cxt); + assert(cxt->sector_size == 0); + + DBG(CXT, ul_debugobj(cxt, "%s: discovering topology...", cxt->dev_path)); +#ifdef HAVE_LIBBLKID + DBG(CXT, ul_debugobj(cxt, "initialize libblkid prober")); + + pr = blkid_new_probe(); + if (pr && blkid_probe_set_device(pr, cxt->dev_fd, 0, 0) == 0) { + blkid_topology tp = blkid_probe_get_topology(pr); + + if (tp) { + cxt->min_io_size = blkid_topology_get_minimum_io_size(tp); + cxt->optimal_io_size = blkid_topology_get_optimal_io_size(tp); + cxt->phy_sector_size = blkid_topology_get_physical_sector_size(tp); + cxt->alignment_offset = blkid_topology_get_alignment_offset(tp); + + /* I/O size used by fdisk */ + cxt->io_size = cxt->optimal_io_size; + if (!cxt->io_size) + /* optimal IO is optional, default to minimum IO */ + cxt->io_size = cxt->min_io_size; + } + } + blkid_free_probe(pr); +#endif + + cxt->sector_size = get_sector_size(cxt->dev_fd); + if (!cxt->phy_sector_size) /* could not discover physical size */ + cxt->phy_sector_size = cxt->sector_size; + + /* no blkid or error, use default values */ + if (!cxt->min_io_size) + cxt->min_io_size = cxt->sector_size; + if (!cxt->io_size) + cxt->io_size = cxt->sector_size; + + DBG(CXT, ul_debugobj(cxt, "result: log/phy sector size: %ld/%ld", + cxt->sector_size, cxt->phy_sector_size)); + DBG(CXT, ul_debugobj(cxt, "result: fdisk/min/optimal io: %ld/%ld/%ld", + cxt->io_size, cxt->optimal_io_size, cxt->min_io_size)); + return 0; +} + +static int has_topology(struct fdisk_context *cxt) +{ + /* + * Assume that the device provides topology info if + * optimal_io_size is set or alignment_offset is set or + * minimum_io_size is not power of 2. + */ + if (cxt && + (cxt->optimal_io_size || + cxt->alignment_offset || + !is_power_of_2(cxt->min_io_size))) + return 1; + return 0; +} + +/* + * The LBA of the first partition is based on the device geometry and topology. + * This offset is generic (and recommended) for all labels. + * + * Returns: 0 on error or number of logical sectors. + */ +static fdisk_sector_t topology_get_first_lba(struct fdisk_context *cxt) +{ + fdisk_sector_t x = 0, res; + + if (!cxt) + return 0; + + if (!cxt->io_size) + fdisk_discover_topology(cxt); + + /* + * Align the begin of partitions to: + * + * a) topology + * a2) alignment offset + * a1) or physical sector (minimal_io_size, aka "grain") + * + * b) or default to 1MiB (2048 sectrors, Windows Vista default) + * + * c) or for very small devices use 1 phy.sector + */ + if (has_topology(cxt)) { + if (cxt->alignment_offset) + x = cxt->alignment_offset; + else if (cxt->io_size > 2048 * 512) + x = cxt->io_size; + } + /* default to 1MiB */ + if (!x) + x = 2048 * 512; + + res = x / cxt->sector_size; + + /* don't use huge offset on small devices */ + if (cxt->total_sectors <= res * 4) + res = cxt->phy_sector_size / cxt->sector_size; + + return res; +} + +static unsigned long topology_get_grain(struct fdisk_context *cxt) +{ + unsigned long res; + + if (!cxt) + return 0; + + if (!cxt->io_size) + fdisk_discover_topology(cxt); + + res = cxt->io_size; + + /* use 1MiB grain always when possible */ + if (res < 2048 * 512) + res = 2048 * 512; + + /* don't use huge grain on small devices */ + if (cxt->total_sectors <= (res * 4 / cxt->sector_size)) + res = cxt->phy_sector_size; + + return res; +} + +/** + * fdisk_reset_alignment: + * @cxt: fdisk context + * + * Resets alignment setting to the default and label specific values. This + * function does not change device properties (I/O limits, geometry etc.). + * + * Returns: 0 on success, < 0 in case of error. + */ +int fdisk_reset_alignment(struct fdisk_context *cxt) +{ + int rc = 0; + + if (!cxt) + return -EINVAL; + + DBG(CXT, ul_debugobj(cxt, "reseting alignment...")); + + /* default */ + cxt->grain = topology_get_grain(cxt); + cxt->first_lba = topology_get_first_lba(cxt); + cxt->last_lba = cxt->total_sectors - 1; + + /* overwrite default by label stuff */ + if (cxt->label && cxt->label->op->reset_alignment) + rc = cxt->label->op->reset_alignment(cxt); + + DBG(CXT, ul_debugobj(cxt, "alignment reseted to: " + "first LBA=%ju, last LBA=%ju, grain=%lu [rc=%d]", + (uintmax_t) cxt->first_lba, (uintmax_t) cxt->last_lba, + cxt->grain, rc)); + return rc; +} + + +fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num) +{ + fdisk_sector_t un = fdisk_get_units_per_sector(cxt); + return (num + un - 1) / un; +} + +fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num) +{ + return fdisk_use_cylinders(cxt) ? + (num / fdisk_get_units_per_sector(cxt)) + 1 : num; +} + +/** + * fdisk_reread_partition_table: + * @cxt: context + * + * Force *kernel* to re-read partition table on block devices. + * + * Returns: 0 on success, < 0 in case of error. + */ +int fdisk_reread_partition_table(struct fdisk_context *cxt) +{ + int i; + struct stat statbuf; + + assert(cxt); + assert(cxt->dev_fd >= 0); + + i = fstat(cxt->dev_fd, &statbuf); + if (i == 0 && S_ISBLK(statbuf.st_mode)) { + sync(); +#ifdef BLKRRPART + fdisk_info(cxt, _("Calling ioctl() to re-read partition table.")); + i = ioctl(cxt->dev_fd, BLKRRPART); +#else + errno = ENOSYS; + i = 1; +#endif + } + + if (i) { + fdisk_warn(cxt, _("Re-reading the partition table failed.")); + fdisk_info(cxt, _( + "The kernel still uses the old table. The " + "new table will be used at the next reboot " + "or after you run partprobe(8) or kpartx(8).")); + return -errno; + } + + return 0; +} diff --git a/libblkid/libfdisk/src/ask.c b/libblkid/libfdisk/src/ask.c new file mode 100644 index 000000000..7e0c3c218 --- /dev/null +++ b/libblkid/libfdisk/src/ask.c @@ -0,0 +1,1044 @@ + +#include "strutils.h" +#include "fdiskP.h" + +/** + * SECTION: ask + * @title: Ask + * @short_description: interface for dialog driven partitioning, warning and info messages + * + */ + +static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask); + + +/** + * fdisk_set_ask: + * @cxt: context + * @ask_cb: callback + * @data: callback data + * + * Set callback for dialog driven partitioning and library warnings/errors. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_set_ask(struct fdisk_context *cxt, + int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *), + void *data) +{ + assert(cxt); + + cxt->ask_cb = ask_cb; + cxt->ask_data = data; + return 0; +} + +struct fdisk_ask *fdisk_new_ask(void) +{ + struct fdisk_ask *ask = calloc(1, sizeof(struct fdisk_ask)); + DBG(ASK, ul_debugobj(ask, "alloc")); + ask->refcount = 1; + return ask; +} + +void fdisk_reset_ask(struct fdisk_ask *ask) +{ + int refcount; + + assert(ask); + free(ask->query); + + DBG(ASK, ul_debugobj(ask, "reset")); + refcount = ask->refcount; + + if (fdisk_is_ask(ask, MENU)) + fdisk_ask_menu_reset_items(ask); + + memset(ask, 0, sizeof(*ask)); + ask->refcount = refcount; +} + +/** + * fdisk_ref_ask: + * @ask: ask instance + * + * Incremparts reference counter. + */ +void fdisk_ref_ask(struct fdisk_ask *ask) +{ + if (ask) + ask->refcount++; +} + + +/** + * fdisk_unref_ask: + * @ask: ask instance + * + * De-incremparts reference counter, on zero the @ask is automatically + * deallocated. + */ +void fdisk_unref_ask(struct fdisk_ask *ask) +{ + if (!ask) + return; + ask->refcount--; + + if (ask->refcount <= 0) { + fdisk_reset_ask(ask); + DBG(ASK, ul_debugobj(ask, "free")); + free(ask); + } +} + +/** + * fdisk_ask_get_query: + * @ask: ask instance + * + * Returns: pointer to dialog string. + */ +const char *fdisk_ask_get_query(struct fdisk_ask *ask) +{ + assert(ask); + return ask->query; +} + +int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str) +{ + assert(ask); + return !strdup_to_struct_member(ask, query, str) ? -ENOMEM : 0; +} + +/** + * fdisk_ask_get_type: + * @ask: ask instance + * + * Returns: FDISK_ASKTYPE_* + */ +int fdisk_ask_get_type(struct fdisk_ask *ask) +{ + assert(ask); + return ask->type; +} + +int fdisk_ask_set_type(struct fdisk_ask *ask, int type) +{ + assert(ask); + ask->type = type; + return 0; +} + +int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask) +{ + int rc; + + assert(ask); + assert(cxt); + + DBG(ASK, ul_debugobj(ask, "do_ask for '%s'", + ask->query ? ask->query : + ask->type == FDISK_ASKTYPE_INFO ? "info" : + ask->type == FDISK_ASKTYPE_WARNX ? "warnx" : + ask->type == FDISK_ASKTYPE_WARN ? "warn" : + "?nothing?")); + + if (!cxt->ask_cb) { + DBG(ASK, ul_debugobj(ask, "no ask callback specified!")); + return -EINVAL; + } + + rc = cxt->ask_cb(cxt, ask, cxt->ask_data); + + DBG(ASK, ul_debugobj(ask, "do_ask done [rc=%d]", rc)); + return rc; +} + +#define is_number_ask(a) (fdisk_is_ask(a, NUMBER) || fdisk_is_ask(a, OFFSET)) + +/** + * fdisk_ask_number_get_range: + * @ask: ask instance + * + * Returns: string with range (e.g. "1,3,5-10") + */ +const char *fdisk_ask_number_get_range(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.range; +} + +int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range) +{ + assert(ask); + assert(is_number_ask(ask)); + ask->data.num.range = range; + return 0; +} + +/** + * fdisk_ask_number_get_default: + * @ask: ask instance + * + * Returns: default number + * + */ +uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.dfl; +} + +int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt) +{ + assert(ask); + ask->data.num.dfl = dflt; + return 0; +} + +/** + * fdisk_ask_number_get_low: + * @ask: ask instance + * + * Returns: minimal possible number when ask for numbers in range + */ +uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.low; +} + +int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low) +{ + assert(ask); + ask->data.num.low = low; + return 0; +} + +/** + * fdisk_ask_number_get_high: + * @ask: ask instance + * + * Returns: maximal possible number when ask for numbers in range + */ +uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.hig; +} + +int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high) +{ + assert(ask); + ask->data.num.hig = high; + return 0; +} + +/** + * fdisk_ask_number_get_result: + * @ask: ask instance + * + * Returns: result + */ +uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.result; +} + +/** + * fdisk_ask_number_set_result: + * @ask: ask instance + * @result: dialog result + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result) +{ + assert(ask); + ask->data.num.result = result; + return 0; +} + +/** + * fdisk_ask_number_get_base: + * @ask: ask instance + * + * Returns: base when user specify number in relative notation (+size) + */ +uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.base; +} + +int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base) +{ + assert(ask); + ask->data.num.base = base; + return 0; +} + +/** + * fdisk_ask_number_get_unit: + * @ask: ask instance + * + * Returns: number of bytes per the unit + */ +uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.unit; +} + +int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit) +{ + assert(ask); + ask->data.num.unit = unit; + return 0; +} + +int fdisk_ask_number_is_relative(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.relative; +} + +/** + * fdisk_ask_number_set_relative + * @ask: ask instance + * @relative: 0 or 1 + * + * Inform libfdisk that user specified number in relative notation rather than + * by explicit number. This info allows to fdisk do some optimization (e.g. + * align end of partiton, etc.) + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative) +{ + assert(ask); + ask->data.num.relative = relative ? 1 : 0; + return 0; +} + +/** + * fdisk_ask_number_inchars: + * @ask: ask instance + * + * For example for BSD is normal to address partition by chars rather than by + * number (first partition is 'a'). + * + * Returns: 1 if number should be presented as chars + * + */ +int fdisk_ask_number_inchars(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_number_ask(ask)); + return ask->data.num.inchars; +} + +/* + * Generates string with list ranges (e.g. 1,2,5-8) for the 'cur' + */ +#define tochar(num) ((int) ('a' + num - 1)) +static char *mk_string_list(char *ptr, size_t *len, size_t *begin, + size_t *run, ssize_t cur, int inchar) +{ + int rlen; + + if (cur != -1) { + if (!*begin) { /* begin of the list */ + *begin = cur + 1; + return ptr; + } + + if (*begin + *run == cur) { /* no gap, continue */ + (*run)++; + return ptr; + } + } else if (!*begin) { + *ptr = '\0'; + return ptr; /* end of empty list */ + } + + /* add to the list */ + if (!*run) + rlen = inchar ? snprintf(ptr, *len, "%c,", tochar(*begin)) : + snprintf(ptr, *len, "%zu,", *begin); + else if (*run == 1) + rlen = inchar ? + snprintf(ptr, *len, "%c,%c,", tochar(*begin), tochar(*begin + 1)) : + snprintf(ptr, *len, "%zu,%zu,", *begin, *begin + 1); + else + rlen = inchar ? + snprintf(ptr, *len, "%c-%c,", tochar(*begin), tochar(*begin + *run)) : + snprintf(ptr, *len, "%zu-%zu,", *begin, *begin + *run); + + if (rlen < 0 || (size_t) rlen + 1 > *len) + return NULL; + + ptr += rlen; + + if (rlen > 0 && *len > (size_t) rlen) + *len -= rlen; + else + *len = 0; + + if (cur == -1 && *begin) { + /* end of the list */ + *(ptr - 1) = '\0'; /* remove tailing ',' from the list */ + return ptr; + } + + *begin = cur + 1; + *run = 0; + + return ptr; +} + +/** + * fdisk_ask_partnum: + * @cxt: context + * @partnum: returns partition number + * @wantnew: 0|1 + * + * High-level API to ask for used or unused partition number. + * + * Returns: 0 on success, < 0 on error, 1 if no free/used partition + */ +int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew) +{ + int rc = 0, inchar = 0; + char range[BUFSIZ], *ptr = range; + size_t i, len = sizeof(range), begin = 0, run = 0; + struct fdisk_ask *ask = NULL; + __typeof__(ask->data.num) *num; + + assert(cxt); + assert(cxt->label); + assert(partnum); + + if (cxt->label && cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO) + inchar = 1; + + DBG(ASK, ul_debug("%s: asking for %s partition number " + "(max: %zu, inchar: %s)", + cxt->label->name, + wantnew ? "new" : "used", + cxt->label->nparts_max, + inchar ? "yes" : "not")); + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + num = &ask->data.num; + + ask->data.num.inchars = inchar ? 1 : 0; + + for (i = 0; i < cxt->label->nparts_max; i++) { + int used = fdisk_is_partition_used(cxt, i); + + if (wantnew && !used) { + ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar); + if (!ptr) { + rc = -EINVAL; + break; + } + if (!num->low) + num->dfl = num->low = i + 1; + num->hig = i + 1; + } else if (!wantnew && used) { + ptr = mk_string_list(ptr, &len, &begin, &run, i, inchar); + if (!num->low) + num->low = i + 1; + num->dfl = num->hig = i + 1; + } + } + + DBG(ASK, ul_debugobj(ask, "ask limits: low: %ju, high: %ju, default: %ju", + num->low, num->hig, num->dfl)); + + if (!rc && !wantnew && num->low == num->hig) { + if (num->low > 0) { + /* only one existing partiton, don't ask, return the number */ + fdisk_ask_number_set_result(ask, num->low); + fdisk_info(cxt, _("Selected partition %ju"), num->low); + + } else if (num->low == 0) { + fdisk_warnx(cxt, _("No partition is defined yet!")); + rc = 1; + } + goto dont_ask; + } + if (!rc && wantnew && num->low == num->hig) { + if (num->low > 0) { + /* only one free partition, don't ask, return the number */ + fdisk_ask_number_set_result(ask, num->low); + fdisk_info(cxt, _("Selected partition %ju"), num->low); + } + if (num->low == 0) { + fdisk_warnx(cxt, _("No free partition available!")); + rc = 1; + } + goto dont_ask; + } + if (!rc) { + mk_string_list(ptr, &len, &begin, &run, -1, inchar); /* terminate the list */ + rc = fdisk_ask_number_set_range(ask, range); + } + if (!rc) + rc = fdisk_ask_set_query(ask, _("Partition number")); + if (!rc) + rc = fdisk_do_ask(cxt, ask); + +dont_ask: + if (!rc) { + *partnum = fdisk_ask_number_get_result(ask); + if (*partnum) + *partnum -= 1; + } + DBG(ASK, ul_debugobj(ask, "result: %ju [rc=%d]\n", fdisk_ask_number_get_result(ask), rc)); + fdisk_unref_ask(ask); + return rc; +} + +/** + * fdisk_ask_number: + * @cxt: context + * @low: minimal possible number + * @dflt: default suggestion + * @high: maximal possible number + * @query: question string + * @result: returns result + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_ask_number(struct fdisk_context *cxt, + uintmax_t low, + uintmax_t dflt, + uintmax_t high, + const char *query, + uintmax_t *result) +{ + struct fdisk_ask *ask; + int rc; + + assert(cxt); + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + if (!rc) + fdisk_ask_number_set_low(ask, low); + if (!rc) + fdisk_ask_number_set_default(ask, dflt); + if (!rc) + fdisk_ask_number_set_high(ask, high); + if (!rc) + fdisk_ask_set_query(ask, query); + if (!rc) + rc = fdisk_do_ask(cxt, ask); + if (!rc) + *result = fdisk_ask_number_get_result(ask); + + DBG(ASK, ul_debugobj(ask, "result: %ju [rc=%d]\n", *result, rc)); + fdisk_unref_ask(ask); + return rc; +} + +/** + * fdisk_ask_string_get_result: + * @ask: ask instance + * + * Returns: pointer to dialog result + */ +char *fdisk_ask_string_get_result(struct fdisk_ask *ask) +{ + assert(ask); + assert(fdisk_is_ask(ask, STRING)); + return ask->data.str.result; +} + +/** + * fdisk_ask_string_set_result: + * @ask: ask instance + * @result: pointer to allocated buffer with string + * + * You don't have to care about the @result deallocation, libfdisk is going to + * deallocate the result when destroy @ask instance. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result) +{ + assert(ask); + ask->data.str.result = result; + return 0; +} + +/** + * fdisk_ask_string: + * @cxt: context: + * @query: question string + * @result: returns allocated buffer + * + * High-level API to ask for strings. Don't forget to deallocate the @result. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_ask_string(struct fdisk_context *cxt, + const char *query, + char **result) +{ + struct fdisk_ask *ask; + int rc; + + assert(cxt); + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_STRING); + if (!rc) + fdisk_ask_set_query(ask, query); + if (!rc) + rc = fdisk_do_ask(cxt, ask); + if (!rc) + *result = fdisk_ask_string_get_result(ask); + + DBG(ASK, ul_debugobj(ask, "result: %s [rc=%d]\n", *result, rc)); + fdisk_unref_ask(ask); + return rc; +} + +/** + * fdisk_ask_yesno: + * @cxt: context + * @query: question string + * @result: returns 0 (no) or 1 (yes) + * + * Hight-level API to ask Yes/No questions + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_yesno(struct fdisk_context *cxt, + const char *query, + int *result) +{ + struct fdisk_ask *ask; + int rc; + + assert(cxt); + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + rc = fdisk_ask_set_type(ask, FDISK_ASKTYPE_YESNO); + if (!rc) + fdisk_ask_set_query(ask, query); + if (!rc) + rc = fdisk_do_ask(cxt, ask); + if (!rc) + *result = fdisk_ask_yesno_get_result(ask) == 1 ? 1 : 0; + + DBG(ASK, ul_debugobj(ask, "result: %d [rc=%d]\n", *result, rc)); + fdisk_unref_ask(ask); + return rc; +} + +/** + * fdisk_ask_yesno_get_result: + * @ask: ask instance + * + * Returns: 0 or 1 + */ +int fdisk_ask_yesno_get_result(struct fdisk_ask *ask) +{ + assert(ask); + assert(fdisk_is_ask(ask, YESNO)); + return ask->data.yesno.result; +} + +/** + * fdisk_ask_yesno_set_result: + * @ask: ask instance + * @result: 1 or 0 + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result) +{ + assert(ask); + ask->data.yesno.result = result; + return 0; +} + +/* + * menu + */ +int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl) +{ + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + ask->data.menu.dfl = dfl; + return 0; +} + +/** + * fdisk_ask_menu_get_default: + * @ask: ask instance + * + * Returns: default menu item key + */ +int fdisk_ask_menu_get_default(struct fdisk_ask *ask) +{ + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + return ask->data.menu.dfl; +} + +/** + * fdisk_ask_menu_set_result: + * @ask: ask instance + * @key: result + * + * Returns: 0 on success, <0 on error + */ +int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key) +{ + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + ask->data.menu.result = key; + DBG(ASK, ul_debugobj(ask, "menu result: %c\n", key)); + return 0; + +} + +/** + * fdisk_ask_menu_get_result: + * @ask: ask instance + * @key: returns selected menu item key + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key) +{ + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + if (key) + *key = ask->data.menu.result; + return 0; +} + +/** + * fdisk_ask_menu_get_item: + * @ask: ask menu instance + * @idx: wanted menu item index + * @key: returns key of the menu item + * @name: returns name of the menu item + * @desc: returns description of the menu item + * + * Returns: 0 on success, <0 on error, >0 if idx out-of-range + */ +int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key, + const char **name, const char **desc) +{ + size_t i; + struct ask_menuitem *mi; + + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + + for (i = 0, mi = ask->data.menu.first; mi; mi = mi->next, i++) { + if (i == idx) + break; + } + + if (!mi) + return 1; /* no more items */ + if (key) + *key = mi->key; + if (name) + *name = mi->name; + if (desc) + *desc = mi->desc; + return 0; +} + +static void fdisk_ask_menu_reset_items(struct fdisk_ask *ask) +{ + struct ask_menuitem *mi; + + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + + for (mi = ask->data.menu.first; mi; ) { + struct ask_menuitem *next = mi->next; + free(mi); + mi = next; + } +} + +/** + * fdisk_ask_menu_get_nitems: + * @ask: ask instance + * + * Returns: number of menu items + */ +size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask) +{ + struct ask_menuitem *mi; + size_t n; + + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + + for (n = 0, mi = ask->data.menu.first; mi; mi = mi->next, n++); + + return n; +} + +int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key, + const char *name, const char *desc) +{ + struct ask_menuitem *mi; + + assert(ask); + assert(fdisk_is_ask(ask, MENU)); + + mi = calloc(1, sizeof(*mi)); + if (!mi) + return -ENOMEM; + mi->key = key; + mi->name = name; + mi->desc = desc; + + if (!ask->data.menu.first) + ask->data.menu.first = mi; + else { + struct ask_menuitem *last = ask->data.menu.first; + + while (last->next) + last = last->next; + last->next = mi; + } + + DBG(ASK, ul_debugobj(ask, "new menu item: %c, \"%s\" (%s)\n", mi->key, mi->name, mi->desc)); + return 0; +} + + +/* + * print-like + */ + +#define is_print_ask(a) (fdisk_is_ask(a, WARN) || fdisk_is_ask(a, WARNX) || fdisk_is_ask(a, INFO)) + +/** + * fdisk_ask_print_get_errno: + * @ask: ask instance + * + * Returns: error number for warning/error messages + */ +int fdisk_ask_print_get_errno(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_print_ask(ask)); + return ask->data.print.errnum; +} + +int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum) +{ + assert(ask); + ask->data.print.errnum = errnum; + return 0; +} + +/** + * fdisk_ask_print_get_mesg: + * @ask: ask instance + * + * Returns: pointer to message + */ +const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask) +{ + assert(ask); + assert(is_print_ask(ask)); + return ask->data.print.mesg; +} + +/* does not reallocate the message! */ +int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg) +{ + assert(ask); + ask->data.print.mesg = mesg; + return 0; +} + +static int do_vprint(struct fdisk_context *cxt, int errnum, int type, + const char *fmt, va_list va) +{ + struct fdisk_ask *ask; + int rc; + char *mesg; + + assert(cxt); + + if (vasprintf(&mesg, fmt, va) < 0) + return -ENOMEM; + + ask = fdisk_new_ask(); + if (!ask) { + free(mesg); + return -ENOMEM; + } + + fdisk_ask_set_type(ask, type); + fdisk_ask_print_set_mesg(ask, mesg); + if (errnum >= 0) + fdisk_ask_print_set_errno(ask, errnum); + rc = fdisk_do_ask(cxt, ask); + + fdisk_unref_ask(ask); + free(mesg); + return rc; +} + +/** + * fdisk_info: + * @cxt: context + * @fmt: printf-like formatted string + * @...: variable parametrs + * + * High-level API to print info messages, + * + * Returns: 0 on success, <0 on error + */ +int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...) +{ + int rc; + va_list ap; + + assert(cxt); + va_start(ap, fmt); + rc = do_vprint(cxt, -1, FDISK_ASKTYPE_INFO, fmt, ap); + va_end(ap); + return rc; +} + +/** + * fdisk_info: + * @cxt: context + * @fmt: printf-like formatted string + * @...: variable parametrs + * + * High-level API to print warning message (errno expected) + * + * Returns: 0 on success, <0 on error + */ +int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...) +{ + int rc; + va_list ap; + + assert(cxt); + va_start(ap, fmt); + rc = do_vprint(cxt, errno, FDISK_ASKTYPE_WARN, fmt, ap); + va_end(ap); + return rc; +} + +/** + * fdisk_warnx: + * @cxt: context + * @fmt: printf-like formatted string + * @...: variable options + * + * High-level API to print warning message + * + * Returns: 0 on success, <0 on error + */ +int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...) +{ + int rc; + va_list ap; + + assert(cxt); + va_start(ap, fmt); + rc = do_vprint(cxt, -1, FDISK_ASKTYPE_WARNX, fmt, ap); + va_end(ap); + return rc; +} + +int fdisk_info_new_partition( + struct fdisk_context *cxt, + int num, fdisk_sector_t start, fdisk_sector_t stop, + struct fdisk_parttype *t) +{ + int rc; + char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, + (uint64_t)(stop - start + 1) * cxt->sector_size); + + rc = fdisk_info(cxt, + _("Created a new partition %d of type '%s' and of size %s."), + num, t ? t->name : _("Unknown"), str); + free(str); + return rc; +} + +#ifdef TEST_PROGRAM +int test_ranges(struct fdisk_test *ts, int argc, char *argv[]) +{ + /* 1 - 3, 6, 8, 9, 11 13 */ + size_t nums[] = { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1 }; + size_t numx[] = { 0, 0, 0 }; + char range[BUFSIZ], *ptr = range; + size_t i, len = sizeof(range), begin = 0, run = 0; + + for (i = 0; i < ARRAY_SIZE(nums); i++) { + if (!nums[i]) + continue; + ptr = mk_string_list(ptr, &len, &begin, &run, i, 0); + } + mk_string_list(ptr, &len, &begin, &run, -1, 0); + printf("list: '%s'\n", range); + + ptr = range; + len = sizeof(range), begin = 0, run = 0; + for (i = 0; i < ARRAY_SIZE(numx); i++) { + if (!numx[i]) + continue; + ptr = mk_string_list(ptr, &len, &begin, &run, i, 0); + } + mk_string_list(ptr, &len, &begin, &run, -1, 0); + printf("empty list: '%s'\n", range); + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct fdisk_test tss[] = { + { "--ranges", test_ranges, "generates ranges" }, + { NULL } + }; + + return fdisk_run_test(tss, argc, argv); +} + +#endif diff --git a/libblkid/libfdisk/src/bsd.c b/libblkid/libfdisk/src/bsd.c new file mode 100644 index 000000000..618a3eef9 --- /dev/null +++ b/libblkid/libfdisk/src/bsd.c @@ -0,0 +1,992 @@ +/* + * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com> + * + * Based on the original code from fdisk + * written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de) + * with code from the NetBSD disklabel command. + * + * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, March 1999 + * David Huggins-Daines <dhuggins@linuxcare.com>, January 2000 + */ +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/param.h> + +#include "nls.h" +#include "blkdev.h" +#include "fdiskP.h" +#include "pt-mbr.h" +#include "pt-bsd.h" +#include "all-io.h" + + +/** + * SECTION: bsd + * @title: BSD + * @short_description: disk label specific functions + * + */ + +static const char *bsd_dktypenames[] = { + "unknown", + "SMD", + "MSCP", + "old DEC", + "SCSI", + "ESDI", + "ST506", + "HP-IB", + "HP-FL", + "type 9", + "floppy", + 0 +}; +#define BSD_DKMAXTYPES (ARRAY_SIZE(bsd_dktypenames) - 1) + +static struct fdisk_parttype bsd_fstypes[] = { + {BSD_FS_UNUSED, "unused"}, + {BSD_FS_SWAP, "swap"}, + {BSD_FS_V6, "Version 6"}, + {BSD_FS_V7, "Version 7"}, + {BSD_FS_SYSV, "System V"}, + {BSD_FS_V71K, "4.1BSD"}, + {BSD_FS_V8, "Eighth Edition"}, + {BSD_FS_BSDFFS, "4.2BSD"}, +#ifdef __alpha__ + {BSD_FS_EXT2, "ext2"}, +#else + {BSD_FS_MSDOS, "MS-DOS"}, +#endif + {BSD_FS_BSDLFS, "4.4LFS"}, + {BSD_FS_OTHER, "unknown"}, + {BSD_FS_HPFS, "HPFS"}, + {BSD_FS_ISO9660,"ISO-9660"}, + {BSD_FS_BOOT, "boot"}, + {BSD_FS_ADOS, "ADOS"}, + {BSD_FS_HFS, "HFS"}, + {BSD_FS_ADVFS, "AdvFS"}, + { 0, NULL } +}; +#define BSD_FSMAXTYPES (ARRAY_SIZE(bsd_fstypes)-1) + +/* + * in-memory fdisk BSD stuff + */ +struct fdisk_bsd_label { + struct fdisk_label head; /* generic part */ + + struct dos_partition *dos_part; /* parent */ + struct bsd_disklabel bsd; /* on disk label */ +#if defined (__alpha__) + /* We access this through a u_int64_t * when checksumming */ + char bsdbuffer[BSD_BBSIZE] __attribute__((aligned(8))); +#else + char bsdbuffer[BSD_BBSIZE]; +#endif +}; + +static int bsd_list_disklabel(struct fdisk_context *cxt); +static int bsd_initlabel(struct fdisk_context *cxt); +static int bsd_readlabel(struct fdisk_context *cxt); +static void sync_disks(struct fdisk_context *cxt); + +static inline struct fdisk_bsd_label *self_label(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, BSD)); + + return (struct fdisk_bsd_label *) cxt->label; +} + +static inline struct bsd_disklabel *self_disklabel(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, BSD)); + + return &((struct fdisk_bsd_label *) cxt->label)->bsd; +} + +static struct fdisk_parttype *bsd_partition_parttype( + struct fdisk_context *cxt, + struct bsd_partition *p) +{ + struct fdisk_parttype *t + = fdisk_label_get_parttype_from_code(cxt->label, p->p_fstype); + return t ? : fdisk_new_unknown_parttype(p->p_fstype, NULL); +} + + +#if defined (__alpha__) +static void alpha_bootblock_checksum (char *boot) +{ + uint64_t *dp = (uint64_t *) boot, sum = 0; + int i; + + for (i = 0; i < 63; i++) + sum += dp[i]; + dp[63] = sum; +} +#endif /* __alpha__ */ + +#define HIDDEN_MASK 0x10 + +static int is_bsd_partition_type(int type) +{ + return (type == MBR_FREEBSD_PARTITION || + type == (MBR_FREEBSD_PARTITION ^ HIDDEN_MASK) || + type == MBR_NETBSD_PARTITION || + type == (MBR_NETBSD_PARTITION ^ HIDDEN_MASK) || + type == MBR_OPENBSD_PARTITION || + type == (MBR_OPENBSD_PARTITION ^ HIDDEN_MASK)); +} + +/* + * look for DOS partition usable for nested BSD partition table + */ +static int bsd_assign_dos_partition(struct fdisk_context *cxt) +{ + struct fdisk_bsd_label *l = self_label(cxt); + size_t i; + + for (i = 0; i < 4; i++) { + fdisk_sector_t ss; + + l->dos_part = fdisk_dos_get_partition(cxt->parent, i); + + if (!l->dos_part || !is_bsd_partition_type(l->dos_part->sys_ind)) + continue; + + ss = dos_partition_get_start(l->dos_part); + if (!ss) { + fdisk_warnx(cxt, _("Partition %zd: has invalid starting " + "sector 0."), i + 1); + return -1; + } + + if (cxt->parent->dev_path) { + free(cxt->dev_path); + cxt->dev_path = fdisk_partname( + cxt->parent->dev_path, i + 1); + } + + DBG(LABEL, ul_debug("partition %zu assigned to BSD", i + 1)); + return 0; + } + + fdisk_warnx(cxt, _("There is no *BSD partition on %s."), + cxt->parent->dev_path); + free(cxt->dev_path); + cxt->dev_path = NULL; + l->dos_part = NULL; + return 1; +} + +static int bsd_probe_label(struct fdisk_context *cxt) +{ + int rc = 0; + + if (cxt->parent) + rc = bsd_assign_dos_partition(cxt); /* nested BSD partiotn table */ + if (!rc) + rc = bsd_readlabel(cxt); + if (!rc) + return 1; /* found BSD */ + return 0; /* not found */ +} + +static int set_parttype( + struct fdisk_context *cxt, + size_t partnum, + struct fdisk_parttype *t) +{ + struct bsd_partition *p; + struct bsd_disklabel *d = self_disklabel(cxt); + + if (partnum >= d->d_npartitions || !t || t->code > UINT8_MAX) + return -EINVAL; + + p = &d->d_partitions[partnum]; + if (t->code == p->p_fstype) + return 0; + + p->p_fstype = t->code; + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static int bsd_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + struct fdisk_bsd_label *l = self_label(cxt); + struct bsd_disklabel *d = self_disklabel(cxt); + size_t i; + unsigned int begin = 0, end; + int rc = 0; + + rc = fdisk_partition_next_partno(pa, cxt, &i); + if (rc) + return rc; + if (i >= BSD_MAXPARTITIONS) + return -ERANGE; + if (l->dos_part) { + begin = dos_partition_get_start(l->dos_part); + end = begin + dos_partition_get_size(l->dos_part) - 1; + } else + end = d->d_secperunit - 1; + + /* + * First sector + */ + if (pa && pa->start_follow_default) + ; + else if (pa && fdisk_partition_has_start(pa)) { + if (pa->start < begin || pa->start > end) + return -ERANGE; + begin = pa->start; + } else { + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + fdisk_ask_set_query(ask, + fdisk_use_cylinders(cxt) ? + _("First cylinder") : _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); + + rc = fdisk_do_ask(cxt, ask); + begin = fdisk_ask_number_get_result(ask); + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) + begin = (begin - 1) * d->d_secpercyl; + } + + /* + * Last sector + */ + if (pa && pa->end_follow_default) + ; + else if (pa && fdisk_partition_has_size(pa)) { + if (begin + pa->size > end) + return -ERANGE; + end = begin + pa->size - 1ULL; + } else { + /* ask user by dialog */ + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + + if (fdisk_use_cylinders(cxt)) { + fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_get_units_per_sector(cxt)); + } else { + fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask,cxt->sector_size); + } + + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); + fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin)); + + rc = fdisk_do_ask(cxt, ask); + end = fdisk_ask_number_get_result(ask); + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) + end = end * d->d_secpercyl - 1; + } + + d->d_partitions[i].p_size = end - begin + 1; + d->d_partitions[i].p_offset = begin; + d->d_partitions[i].p_fstype = BSD_FS_UNUSED; + + if (i >= d->d_npartitions) + d->d_npartitions = i + 1; + cxt->label->nparts_cur = d->d_npartitions; + + if (pa && pa->type) + set_parttype(cxt, i, pa->type); + + fdisk_label_set_changed(cxt->label, 1); + if (partno) + *partno = i; + return 0; +} + +static int bsd_set_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct bsd_partition *p; + struct fdisk_bsd_label *l = self_label(cxt); + struct bsd_disklabel *d = self_disklabel(cxt); + + if (n >= d->d_npartitions) + return -EINVAL; + + p = &d->d_partitions[n]; + + /* we have to stay within parental DOS partition */ + if (l->dos_part && (fdisk_partition_has_start(pa) || + fdisk_partition_has_size(pa))) { + + fdisk_sector_t dosbegin = dos_partition_get_start(l->dos_part); + fdisk_sector_t dosend = dosbegin + dos_partition_get_size(l->dos_part) - 1; + fdisk_sector_t begin = fdisk_partition_has_start(pa) ? pa->start : p->p_offset; + fdisk_sector_t end = begin + (fdisk_partition_has_size(pa) ? pa->size : p->p_size) - 1; + + if (begin < dosbegin || begin > dosend) + return -ERANGE; + if (end < dosbegin || end > dosend) + return -ERANGE; + } + + if (pa->type) { + int rc = set_parttype(cxt, n, pa->type); + if (rc) + return rc; + } + + if (fdisk_partition_has_start(pa)) + d->d_partitions[n].p_offset = pa->start; + if (fdisk_partition_has_size(pa)) + d->d_partitions[n].p_size = pa->size; + + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + + +/* Returns 0 on success, < 0 on error. */ +static int bsd_create_disklabel(struct fdisk_context *cxt) +{ + int rc, yes = 0; + struct bsd_disklabel *d = self_disklabel(cxt); + + fdisk_info(cxt, _("The device %s does not contain BSD disklabel."), cxt->dev_path); + rc = fdisk_ask_yesno(cxt, + _("Do you want to create a BSD disklabel?"), + &yes); + if (rc) + return rc; + if (!yes) + return 1; + if (cxt->parent) { + rc = bsd_assign_dos_partition(cxt); + if (rc == 1) + /* not found DOS partition usable for BSD label */ + rc = -EINVAL; + } + if (rc) + return rc; + + rc = bsd_initlabel(cxt); + if (!rc) { + int org = fdisk_is_details(cxt); + + cxt->label->nparts_cur = d->d_npartitions; + cxt->label->nparts_max = BSD_MAXPARTITIONS; + + fdisk_enable_details(cxt, 1); + bsd_list_disklabel(cxt); + fdisk_enable_details(cxt, org); + } + + return rc; +} + +static int bsd_delete_part( + struct fdisk_context *cxt, + size_t partnum) +{ + struct bsd_disklabel *d = self_disklabel(cxt); + + d->d_partitions[partnum].p_size = 0; + d->d_partitions[partnum].p_offset = 0; + d->d_partitions[partnum].p_fstype = BSD_FS_UNUSED; + + if (d->d_npartitions == partnum + 1) + while (!d->d_partitions[d->d_npartitions - 1].p_size) + d->d_npartitions--; + + cxt->label->nparts_cur = d->d_npartitions; + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static int bsd_list_disklabel(struct fdisk_context *cxt) +{ + struct bsd_disklabel *d = self_disklabel(cxt); + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, BSD)); + + if (fdisk_is_details(cxt)) { + fdisk_info(cxt, "# %s:", cxt->dev_path); + + if ((unsigned) d->d_type < BSD_DKMAXTYPES) + fdisk_info(cxt, _("type: %s"), bsd_dktypenames[d->d_type]); + else + fdisk_info(cxt, _("type: %d"), d->d_type); + + fdisk_info(cxt, _("disk: %.*s"), (int) sizeof(d->d_typename), d->d_typename); + fdisk_info(cxt, _("label: %.*s"), (int) sizeof(d->d_packname), d->d_packname); + + fdisk_info(cxt, _("flags: %s"), + d->d_flags & BSD_D_REMOVABLE ? _(" removable") : + d->d_flags & BSD_D_ECC ? _(" ecc") : + d->d_flags & BSD_D_BADSECT ? _(" badsect") : ""); + + /* On various machines the fields of *lp are short/int/long */ + /* In order to avoid problems, we cast them all to long. */ + fdisk_info(cxt, _("bytes/sector: %ld"), (long) d->d_secsize); + fdisk_info(cxt, _("sectors/track: %ld"), (long) d->d_nsectors); + fdisk_info(cxt, _("tracks/cylinder: %ld"), (long) d->d_ntracks); + fdisk_info(cxt, _("sectors/cylinder: %ld"), (long) d->d_secpercyl); + fdisk_info(cxt, _("cylinders: %ld"), (long) d->d_ncylinders); + fdisk_info(cxt, _("rpm: %d"), d->d_rpm); + fdisk_info(cxt, _("interleave: %d"), d->d_interleave); + fdisk_info(cxt, _("trackskew: %d"), d->d_trackskew); + fdisk_info(cxt, _("cylinderskew: %d"), d->d_cylskew); + fdisk_info(cxt, _("headswitch: %ld (milliseconds)"), (long) d->d_headswitch); + fdisk_info(cxt, _("track-to-track seek: %ld (milliseconds)"), (long) d->d_trkseek); + } + + fdisk_info(cxt, _("partitions: %d"), d->d_npartitions); + + return 0; +} + +static int bsd_get_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct bsd_partition *p; + struct bsd_disklabel *d = self_disklabel(cxt); + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, BSD)); + + if (n >= d->d_npartitions) + return -EINVAL; + + p = &d->d_partitions[n]; + + pa->used = p->p_size ? 1 : 0; + if (!pa->used) + return 0; + + if (fdisk_use_cylinders(cxt) && d->d_secpercyl) { + pa->start_post = p->p_offset % d->d_secpercyl ? '*' : ' '; + pa->end_post = (p->p_offset + p->p_size) % d->d_secpercyl ? '*' : ' '; + } + + pa->start = p->p_offset; + pa->size = p->p_size; + pa->type = bsd_partition_parttype(cxt, p); + + if (p->p_fstype == BSD_FS_UNUSED || p->p_fstype == BSD_FS_BSDFFS) { + pa->fsize = p->p_fsize; + pa->bsize = p->p_fsize * p->p_frag; + } + if (p->p_fstype == BSD_FS_BSDFFS) + pa->cpg = p->p_cpg; + + return 0; +} + +static uint32_t ask_uint32(struct fdisk_context *cxt, + uint32_t dflt, char *mesg) +{ + uintmax_t res; + + if (fdisk_ask_number(cxt, min(dflt, (uint32_t) 1), dflt, + UINT32_MAX, mesg, &res) == 0) + return res; + return dflt; +} + +static uint16_t ask_uint16(struct fdisk_context *cxt, + uint16_t dflt, char *mesg) +{ + uintmax_t res; + + if (fdisk_ask_number(cxt, min(dflt, (uint16_t) 1), + dflt, UINT16_MAX, mesg, &res) == 0) + return res; + return dflt; +} + +/** + * fdisk_bsd_edit_disklabel: + * @cxt: context + * + * Edits fields in BSD disk label. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt) +{ + struct bsd_disklabel *d = self_disklabel(cxt); + uintmax_t res; + +#if defined (__alpha__) || defined (__ia64__) + if (fdisk_ask_number(cxt, DEFAULT_SECTOR_SIZE, d->d_secsize, + UINT32_MAX, _("bytes/sector"), &res) == 0) + d->d_secsize = res; + + d->d_nsectors = ask_uint32(cxt, d->d_nsectors, _("sectors/track")); + d->d_ntracks = ask_uint32(cxt, d->d_ntracks, _("tracks/cylinder")); + d->d_ncylinders = ask_uint32(cxt, d->d_ncylinders ,_("cylinders")); +#endif + if (fdisk_ask_number(cxt, 1, d->d_nsectors * d->d_ntracks, + d->d_nsectors * d->d_ntracks, + _("sectors/cylinder"), &res) == 0) + d->d_secpercyl = res; + + d->d_rpm = ask_uint16(cxt, d->d_rpm, _("rpm")); + d->d_interleave = ask_uint16(cxt, d->d_interleave, _("interleave")); + d->d_trackskew = ask_uint16(cxt, d->d_trackskew, _("trackskew")); + d->d_cylskew = ask_uint16(cxt, d->d_cylskew, _("cylinderskew")); + + d->d_headswitch = ask_uint32(cxt, d->d_headswitch, _("headswitch")); + d->d_trkseek = ask_uint32(cxt, d->d_trkseek, _("track-to-track seek")); + + d->d_secperunit = d->d_secpercyl * d->d_ncylinders; + return 0; +} + +static int bsd_get_bootstrap(struct fdisk_context *cxt, + char *path, void *ptr, int size) +{ + int fd; + + if ((fd = open(path, O_RDONLY)) < 0) { + fdisk_warn(cxt, _("cannot open %s"), path); + return -errno; + } + + if (read_all(fd, ptr, size) != size) { + fdisk_warn(cxt, _("cannot read %s"), path); + close(fd); + return -errno; + } + + fdisk_info(cxt, _("The bootstrap file %s successfully loaded."), path); + close (fd); + return 0; +} + +/** + * fdisk_bsd_write_bootstrap: + * @cxt: context + * + * Install bootstrap file to the BSD device + */ +int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt) +{ + struct bsd_disklabel dl, *d = self_disklabel(cxt); + struct fdisk_bsd_label *l = self_label(cxt); + char *name = d->d_type == BSD_DTYPE_SCSI ? "sd" : "wd"; + char buf[BUFSIZ]; + char *res, *dp, *p; + int rc; + fdisk_sector_t sector; + + snprintf(buf, sizeof(buf), + _("Bootstrap: %1$sboot -> boot%1$s (default %1$s)"), + name); + rc = fdisk_ask_string(cxt, buf, &res); + if (rc) + goto done; + if (res && *res) + name = res; + + snprintf(buf, sizeof(buf), "%s/%sboot", BSD_LINUX_BOOTDIR, name); + rc = bsd_get_bootstrap(cxt, buf, l->bsdbuffer, (int) d->d_secsize); + if (rc) + goto done; + + /* We need a backup of the disklabel (might have changed). */ + dp = &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE]; + memmove(&dl, dp, sizeof(struct bsd_disklabel)); + + /* The disklabel will be overwritten by 0's from bootxx anyway */ + memset(dp, 0, sizeof(struct bsd_disklabel)); + + snprintf(buf, sizeof(buf), "%s/boot%s", BSD_LINUX_BOOTDIR, name); + rc = bsd_get_bootstrap(cxt, buf, + &l->bsdbuffer[d->d_secsize], + (int) d->d_bbsize - d->d_secsize); + if (rc) + goto done; + + /* check end of the bootstrap */ + for (p = dp; p < dp + sizeof(struct bsd_disklabel); p++) { + if (!*p) + continue; + fdisk_warnx(cxt, _("Bootstrap overlaps with disklabel!")); + return -EINVAL; + } + + /* move disklabel back */ + memmove(dp, &dl, sizeof(struct bsd_disklabel)); + + sector = 0; + if (l->dos_part) + sector = dos_partition_get_start(l->dos_part); +#if defined (__alpha__) + alpha_bootblock_checksum(l->bsdbuffer); +#endif + if (lseek(cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1) { + fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path); + rc = -errno; + goto done; + } + if (write_all(cxt->dev_fd, l->bsdbuffer, BSD_BBSIZE)) { + fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path); + rc = -errno; + goto done; + } + + fdisk_info(cxt, _("Bootstrap installed on %s."), cxt->dev_path); + sync_disks(cxt); + + rc = 0; +done: + free(res); + return rc; +} + +static unsigned short bsd_dkcksum (struct bsd_disklabel *lp) +{ + unsigned short *start, *end; + unsigned short sum = 0; + + start = (unsigned short *) lp; + end = (unsigned short *) &lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return sum; +} + +static int bsd_initlabel (struct fdisk_context *cxt) +{ + struct fdisk_bsd_label *l = self_label(cxt); + struct bsd_disklabel *d = self_disklabel(cxt); + struct bsd_partition *pp; + + memset (d, 0, sizeof (struct bsd_disklabel)); + + d -> d_magic = BSD_DISKMAGIC; + + if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0) + d -> d_type = BSD_DTYPE_SCSI; + else + d -> d_type = BSD_DTYPE_ST506; + +#if !defined (__alpha__) + d -> d_flags = BSD_D_DOSPART; +#else + d -> d_flags = 0; +#endif + d -> d_secsize = DEFAULT_SECTOR_SIZE; /* bytes/sector */ + d -> d_nsectors = cxt->geom.sectors; /* sectors/track */ + d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */ + d -> d_ncylinders = cxt->geom.cylinders; + d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */ + if (d -> d_secpercyl == 0) + d -> d_secpercyl = 1; /* avoid segfaults */ + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; + + d -> d_rpm = 3600; + d -> d_interleave = 1; + d -> d_trackskew = 0; + d -> d_cylskew = 0; + d -> d_headswitch = 0; + d -> d_trkseek = 0; + + d -> d_magic2 = BSD_DISKMAGIC; + d -> d_bbsize = BSD_BBSIZE; + d -> d_sbsize = BSD_SBSIZE; + + if (l->dos_part) { + d->d_npartitions = 4; + + pp = &d->d_partitions[2]; /* Partition C should be the NetBSD partition */ + pp->p_offset = dos_partition_get_start(l->dos_part); + pp->p_size = dos_partition_get_size(l->dos_part); + pp->p_fstype = BSD_FS_UNUSED; + + pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */ + pp->p_offset = 0; + pp->p_size = d->d_secperunit; + pp->p_fstype = BSD_FS_UNUSED; + } else { + d->d_npartitions = 3; + + pp = &d->d_partitions[2]; /* Partition C should be the whole disk */ + pp->p_offset = 0; + pp->p_size = d->d_secperunit; + pp->p_fstype = BSD_FS_UNUSED; + } + + return 0; +} + +/* + * Read a bsd_disklabel from sector 0 or from the starting sector of p. + * If it has the right magic, return 0. + */ +static int bsd_readlabel(struct fdisk_context *cxt) +{ + struct fdisk_bsd_label *l; + struct bsd_disklabel *d; + int t; + off_t offset = 0; + + l = self_label(cxt); + d = self_disklabel(cxt); + + if (l->dos_part) + /* BSD is nested within DOS partition, get the begin of the + * partition. Note that DOS uses native sector size. */ + offset = dos_partition_get_start(l->dos_part) * cxt->sector_size; + + if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1) + return -1; + if (read_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer)) < 0) + return errno ? -errno : -1; + + /* The offset to begin of the disk label. Note that BSD uses + * 512-byte (default) sectors. */ + memmove(d, &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE + + BSD_LABELOFFSET], sizeof(*d)); + + if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC) { + DBG(LABEL, ul_debug("not found magic")); + return -1; + } + + for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) { + d->d_partitions[t].p_size = 0; + d->d_partitions[t].p_offset = 0; + d->d_partitions[t].p_fstype = BSD_FS_UNUSED; + } + + if (d->d_npartitions > BSD_MAXPARTITIONS) + fdisk_warnx(cxt, ("Too many partitions (%d, maximum is %d)."), + d->d_npartitions, BSD_MAXPARTITIONS); + + /* let's follow in-PT geometry */ + cxt->geom.sectors = d->d_nsectors; + cxt->geom.heads = d->d_ntracks; + cxt->geom.cylinders = d->d_ncylinders; + + cxt->label->nparts_cur = d->d_npartitions; + cxt->label->nparts_max = BSD_MAXPARTITIONS; + DBG(LABEL, ul_debug("read BSD label")); + return 0; +} + +static int bsd_write_disklabel(struct fdisk_context *cxt) +{ + off_t offset = 0; + struct fdisk_bsd_label *l = self_label(cxt); + struct bsd_disklabel *d = self_disklabel(cxt); + + + if (l->dos_part) + offset = dos_partition_get_start(l->dos_part) * cxt->sector_size; + + d->d_checksum = 0; + d->d_checksum = bsd_dkcksum(d); + + /* Update label within boot block. */ + memmove(&l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE + + BSD_LABELOFFSET], d, sizeof(*d)); + +#if defined (__alpha__) && BSD_LABELSECTOR == 0 + /* Write the checksum to the end of the first sector. */ + alpha_bootblock_checksum(l->bsdbuffer); +#endif + if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1) { + fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path); + return -errno; + } + if (write_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer))) { + fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path); + return -errno; + } + sync_disks(cxt); + + fdisk_info(cxt, _("Disklabel written to %s."), cxt->dev_path); + return 0; +} + +static void sync_disks(struct fdisk_context *cxt) +{ + fdisk_info(cxt, _("Syncing disks.")); + sync(); +} + +static int bsd_translate_fstype (int linux_type) +{ + switch (linux_type) { + case 0x01: /* DOS 12-bit FAT */ + case 0x04: /* DOS 16-bit <32M */ + case 0x06: /* DOS 16-bit >=32M */ + case 0xe1: /* DOS access */ + case 0xe3: /* DOS R/O */ +#if !defined (__alpha__) + case 0xf2: /* DOS secondary */ + return BSD_FS_MSDOS; +#endif + case 0x07: /* OS/2 HPFS */ + return BSD_FS_HPFS; + default: + break; + } + + return BSD_FS_OTHER; +} + +/** + * fdisk_bsd_link_partition: + * @cxt: context + * + * Links partition from parent (DOS) to nested BSD partition table. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_bsd_link_partition(struct fdisk_context *cxt) +{ + size_t k, i; + int rc; + struct dos_partition *p; + struct bsd_disklabel *d = self_disklabel(cxt); + + if (!cxt->parent || !fdisk_is_label(cxt->parent, DOS)) { + fdisk_warnx(cxt, _("BSD label is not nested within a DOS partition.")); + return -EINVAL; + } + + /* ask for DOS partition */ + rc = fdisk_ask_partnum(cxt->parent, &k, FALSE); + if (rc) + return rc; + /* ask for BSD partition */ + rc = fdisk_ask_partnum(cxt, &i, TRUE); + if (rc) + return rc; + + if (i >= BSD_MAXPARTITIONS) + return -EINVAL; + + p = fdisk_dos_get_partition(cxt->parent, k); + + d->d_partitions[i].p_size = dos_partition_get_size(p); + d->d_partitions[i].p_offset = dos_partition_get_start(p); + d->d_partitions[i].p_fstype = bsd_translate_fstype(p->sys_ind); + + if (i >= d->d_npartitions) + d->d_npartitions = i + 1; + + cxt->label->nparts_cur = d->d_npartitions; + fdisk_label_set_changed(cxt->label, 1); + + fdisk_info(cxt, _("BSD partition '%c' linked to DOS partition %zu."), + 'a' + (int) i, k + 1); + return 0; +} + + +static int bsd_partition_is_used( + struct fdisk_context *cxt, + size_t partnum) +{ + struct bsd_disklabel *d = self_disklabel(cxt); + + if (partnum >= BSD_MAXPARTITIONS) + return 0; + + return d->d_partitions[partnum].p_size ? 1 : 0; +} + + +static const struct fdisk_label_operations bsd_operations = +{ + .probe = bsd_probe_label, + .list = bsd_list_disklabel, + .write = bsd_write_disklabel, + .create = bsd_create_disklabel, + + .del_part = bsd_delete_part, + .get_part = bsd_get_partition, + .set_part = bsd_set_partition, + .add_part = bsd_add_partition, + + .part_is_used = bsd_partition_is_used, +}; + +static const struct fdisk_field bsd_fields[] = +{ + { FDISK_FIELD_DEVICE, N_("Slice"), 1, 0 }, + { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_TYPE, N_("Type"), 8, 0 }, + { FDISK_FIELD_FSIZE, N_("Fsize"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_BSIZE, N_("Bsize"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_CPG, N_("Cpg"), 5, FDISK_FIELDFL_NUMBER } +}; + +/* + * allocates BSD label driver + */ +struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + struct fdisk_bsd_label *bsd; + + assert(cxt); + + bsd = calloc(1, sizeof(*bsd)); + if (!bsd) + return NULL; + + /* initialize generic part of the driver */ + lb = (struct fdisk_label *) bsd; + lb->name = "bsd"; + lb->id = FDISK_DISKLABEL_BSD; + lb->op = &bsd_operations; + lb->parttypes = bsd_fstypes; + lb->nparttypes = ARRAY_SIZE(bsd_fstypes) - 1; + + lb->fields = bsd_fields; + lb->nfields = ARRAY_SIZE(bsd_fields); + + lb->flags |= FDISK_LABEL_FL_INCHARS_PARTNO; + lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY; + + return lb; +} diff --git a/libblkid/libfdisk/src/context.c b/libblkid/libfdisk/src/context.c new file mode 100644 index 000000000..2a4d377e0 --- /dev/null +++ b/libblkid/libfdisk/src/context.c @@ -0,0 +1,1017 @@ +#ifdef HAVE_LIBBLKID +# include <blkid.h> +#endif + +#include "fdiskP.h" + + +/** + * SECTION: context + * @title: Context + * @short_description: stores info about device, labels etc. + * + * The library distinguish between three types of partitioning objects. + * + * on-disk data + * - disk label specific + * - probed and read by disklabel drivers when assign device to the context + * or when switch to another disk label type + * - only fdisk_write_disklabel() modify on-disk data + * + * in-memory data + * - generic data and disklabel specific data stored in struct fdisk_label + * - all partitioning operations are based on in-memory data only + * + * struct fdisk_partition + * - provides abstraction to present partitions to users + * - fdisk_partition is possible to gather to fdisk_table container + * - used as unified template for new partitions + * - the struct fdisk_partition is always completely independent object and + * any change to the object has no effect to in-memory (or on-disk) label data + */ + +/** + * fdisk_new_context: + * + * Returns: newly allocated libfdisk handler + */ +struct fdisk_context *fdisk_new_context(void) +{ + struct fdisk_context *cxt; + + cxt = calloc(1, sizeof(*cxt)); + if (!cxt) + return NULL; + + DBG(CXT, ul_debugobj(cxt, "alloc")); + cxt->dev_fd = -1; + cxt->refcount = 1; + + /* + * Allocate label specific structs. + * + * This is necessary (for example) to store label specific + * context setting. + */ + cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt); + cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); + cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt); + cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt); + cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt); + + return cxt; +} + +static int init_nested_from_parent(struct fdisk_context *cxt, int isnew) +{ + struct fdisk_context *parent; + + assert(cxt); + assert(cxt->parent); + + parent = cxt->parent; + + cxt->alignment_offset = parent->alignment_offset; + cxt->ask_cb = parent->ask_cb; + cxt->ask_data = parent->ask_data; + cxt->dev_fd = parent->dev_fd; + cxt->first_lba = parent->first_lba; + cxt->firstsector_bufsz = parent->firstsector_bufsz; + cxt->firstsector = parent->firstsector; + cxt->geom = parent->geom; + cxt->grain = parent->grain; + cxt->io_size = parent->io_size; + cxt->last_lba = parent->last_lba; + cxt->min_io_size = parent->min_io_size; + cxt->optimal_io_size = parent->optimal_io_size; + cxt->phy_sector_size = parent->phy_sector_size; + cxt->readonly = parent->readonly; + cxt->script = parent->script; + fdisk_ref_script(cxt->script); + cxt->sector_size = parent->sector_size; + cxt->total_sectors = parent->total_sectors; + cxt->user_geom = parent->user_geom; + cxt->user_log_sector = parent->user_log_sector; + cxt->user_pyh_sector = parent->user_pyh_sector; + + /* parent <--> nested independent setting, initialize for new nested + * contexts only */ + if (isnew) { + cxt->listonly = parent->listonly; + cxt->display_details = parent->display_details; + cxt->display_in_cyl_units = parent->display_in_cyl_units; + } + + free(cxt->dev_path); + cxt->dev_path = NULL; + + if (parent->dev_path) { + cxt->dev_path = strdup(parent->dev_path); + if (!cxt->dev_path) + return -ENOMEM; + } + + return 0; +} + +/** + * fdisk_new_nested_context: + * @parent: parental context + * @name: optional label name (e.g. "bsd") + * + * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR). + * The function also probes for the nested label on the device if device is + * already assigned to parent. + * + * The new context is initialized according to @parent and both context shares + * some settings and file descriptor to the device. The child propagate some + * changes (like fdisk_assign_device()) to parent, but it does not work + * vice-versa. The behavior is undefined if you assign another device to + * parent. + * + * Returns: new context for nested partition table. + */ +struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, + const char *name) +{ + struct fdisk_context *cxt; + struct fdisk_label *lb = NULL; + + assert(parent); + + cxt = calloc(1, sizeof(*cxt)); + if (!cxt) + return NULL; + + DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt)); + cxt->refcount = 1; + + fdisk_ref_context(parent); + cxt->parent = parent; + + if (init_nested_from_parent(cxt, 1) != 0) + return NULL; + + if (name) { + if (strcmp(name, "bsd") == 0) + lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt); + else if (strcmp(name, "dos") == 0) + lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); + } + + if (lb && parent->dev_fd >= 0) { + DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name)); + + cxt->label = lb; + + if (lb->op->probe(cxt) == 1) + __fdisk_switch_label(cxt, lb); + else { + DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name)); + if (lb->op->deinit) + lb->op->deinit(lb); + cxt->label = NULL; + } + } + + return cxt; +} + + +/** + * fdisk_ref_context: + * @cxt: context pointer + * + * Increments reference counter. + */ +void fdisk_ref_context(struct fdisk_context *cxt) +{ + if (cxt) + cxt->refcount++; +} + +/** + * fdisk_get_label: + * @cxt: context instance + * @name: label name (e.g. "gpt") + * + * If no @name specified then returns the current context label. + * + * The label is allocated and maintained within the context #cxt. There is + * nothing like reference counting for labels, you cannot delallocate the + * label. + * + * Returns: label struct or NULL in case of error. + */ +struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name) +{ + size_t i; + + assert(cxt); + + if (!name) + return cxt->label; + + for (i = 0; i < cxt->nlabels; i++) + if (cxt->labels[i] + && strcmp(cxt->labels[i]->name, name) == 0) + return cxt->labels[i]; + + DBG(CXT, ul_debugobj(cxt, "failed to found %s label driver", name)); + return NULL; +} + +/** + * fdisk_next_label: + * @cxt: context instance + * @lb: returns pointer to the next label + * + * <informalexample> + * <programlisting> + * // print all supported labels + * struct fdisk_context *cxt = fdisk_new_context(); + * struct fdisk_label *lb = NULL; + * + * while (fdisk_next_label(cxt, &lb) == 0) + * print("label name: %s\n", fdisk_label_get_name(lb)); + * fdisk_unref_context(cxt); + * </programlisting> + * </informalexample> + * + * Returns: <0 in case of error, 0 on success, 1 at the end. + */ +int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb) +{ + size_t i; + struct fdisk_label *res = NULL; + + if (!lb || !cxt) + return -EINVAL; + + if (!*lb) + res = cxt->labels[0]; + else { + for (i = 1; i < cxt->nlabels; i++) { + if (*lb == cxt->labels[i - 1]) { + res = cxt->labels[i]; + break; + } + } + } + + *lb = res; + return res ? 0 : 1; +} + +/** + * fdisk_get_nlabels: + * @cxt: context + * + * Returns: number of supported label types + */ +size_t fdisk_get_nlabels(struct fdisk_context *cxt) +{ + return cxt ? cxt->nlabels : 0; +} + +int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb) +{ + if (!lb || !cxt) + return -EINVAL; + if (lb->disabled) { + DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name)); + return -EINVAL; + } + cxt->label = lb; + DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name)); + return 0; +} + +/** + * fdisk_has_label: + * @cxt: fdisk context + * + * Returns: return 1 if there is label on the device. + */ +int fdisk_has_label(struct fdisk_context *cxt) +{ + return cxt && cxt->label; +} + +/** + * fdisk_get_npartitions: + * @cxt: context + * + * The maximal number of the partitions depends on disklabel and does not + * have to describe the real limit of PT. + * + * For example the limit for MBR without extend partition is 4, with extended + * partition it's unlimited (so the function returns the current number of all + * partitions in this case). + * + * And for example for GPT it depends on space allocated on disk for array of + * entry records (usually 128). + * + * It's fine to use fdisk_get_npartitions() in loops, but don't forget that + * partition may be unused (see fdisk_is_partition_used()). + * + * <informalexample> + * <programlisting> + * struct fdisk_partition *pa = NULL; + * size_t i, nmax = fdisk_get_npartitions(cxt); + * + * for (i = 0; i < nmax; i++) { + * if (!fdisk_is_partition_used(cxt, i)) + * continue; + * ... do something ... + * } + * </programlisting> + * </informalexample> + * + * Note that the recommended way to list partitions is to use + * fdisk_get_partitions() and struct fdisk_table than ask disk driver for each + * individual partitions. + * + * Returns: maximal number of partitions for the current label. + */ +size_t fdisk_get_npartitions(struct fdisk_context *cxt) +{ + return cxt && cxt->label ? cxt->label->nparts_max : 0; +} + +/** + * fdisk_is_labeltype: + * @cxt: fdisk context + * @id: FDISK_DISKLABEL_* + * + * See also fdisk_is_label() macro in libfdisk.h. + * + * Returns: return 1 if the current label is @id + */ +int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id) +{ + assert(cxt); + + return cxt->label && fdisk_label_get_type(cxt->label) == id; +} + +/** + * fdisk_get_parent: + * @cxt: nested fdisk context + * + * Returns: pointer to parental context, or NULL + */ +struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->parent; +} + +static void reset_context(struct fdisk_context *cxt) +{ + size_t i; + + DBG(CXT, ul_debugobj(cxt, "*** resetting context")); + + /* reset drives' private data */ + for (i = 0; i < cxt->nlabels; i++) + fdisk_deinit_label(cxt->labels[i]); + + if (cxt->parent) { + /* the first sector may be independent on parent */ + if (cxt->parent->firstsector != cxt->firstsector) + free(cxt->firstsector); + } else { + /* we close device only in primary context */ + if (cxt->dev_fd > -1) + close(cxt->dev_fd); + free(cxt->firstsector); + } + + free(cxt->dev_path); + cxt->dev_path = NULL; + + cxt->dev_fd = -1; + cxt->firstsector = NULL; + cxt->firstsector_bufsz = 0; + + fdisk_zeroize_device_properties(cxt); + + fdisk_unref_script(cxt->script); + cxt->script = NULL; + + cxt->label = NULL; +} + +/* + * This function prints a warning if the device is not wiped (e.g. wipefs(8). + * Please don't call this function if there is already a PT. + * + * Returns: 0 if nothing found, < 0 on error, 1 if found a signature + */ +static int warn_wipe(struct fdisk_context *cxt) +{ +#ifdef HAVE_LIBBLKID + blkid_probe pr; +#endif + int rc = 0; + + assert(cxt); + + if (fdisk_has_label(cxt) || cxt->dev_fd < 0) + return -EINVAL; +#ifdef HAVE_LIBBLKID + DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober")); + + pr = blkid_new_probe(); + if (!pr) + return -ENOMEM; + rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0); + if (rc) + return rc; + + blkid_probe_enable_superblocks(pr, 1); + blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); + blkid_probe_enable_partitions(pr, 1); + + /* we care about the first found FS/raid, so don't call blkid_do_probe() + * in loop or don't use blkid_do_fullprobe() ... */ + rc = blkid_do_probe(pr); + if (rc == 0) { + const char *name = NULL; + + if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 || + blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) { + fdisk_warnx(cxt, _( + "%s: device contains a valid '%s' signature; it is " + "strongly recommended to wipe the device with " + "wipefs(8) if this is unexpected, in order to " + "avoid possible collisions"), cxt->dev_path, name); + rc = 1; + } + } + + blkid_free_probe(pr); +#endif + return rc; +} + +/** + * fdisk_assign_device: + * @cxt: context + * @fname: path to the device to be handled + * @readonly: how to open the device + * + * Open the device, discovery topology, geometry, detect disklabel and switch + * the current label driver to reflect the probing result. + * + * Note that this function resets all generic setting in context. If the @cxt + * is nested context then the device is assigned to the parental context and + * necessary properties are copied to the @cxt. The change is propagated in + * child->parent direction only. It's impossible to use a different device for + * primary and nested contexts. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_assign_device(struct fdisk_context *cxt, + const char *fname, int readonly) +{ + int fd; + + DBG(CXT, ul_debugobj(cxt, "assigning device %s", fname)); + assert(cxt); + + /* redirect request to parent */ + if (cxt->parent) { + int rc, org = fdisk_is_listonly(cxt->parent); + + /* assign_device() is sensitive to "listonly" mode, so let's + * follow the current context setting for the parent to avoid + * unwanted extra warnings. */ + fdisk_enable_listonly(cxt->parent, fdisk_is_listonly(cxt)); + + rc = fdisk_assign_device(cxt->parent, fname, readonly); + fdisk_enable_listonly(cxt->parent, org); + + if (!rc) + rc = init_nested_from_parent(cxt, 0); + if (!rc) + fdisk_probe_labels(cxt); + return rc; + } + + reset_context(cxt); + + fd = open(fname, (readonly ? O_RDONLY : O_RDWR ) | O_CLOEXEC); + if (fd < 0) + return -errno; + + cxt->readonly = readonly; + cxt->dev_fd = fd; + cxt->dev_path = strdup(fname); + if (!cxt->dev_path) + goto fail; + + fdisk_discover_topology(cxt); + fdisk_discover_geometry(cxt); + + if (fdisk_read_firstsector(cxt) < 0) + goto fail; + + /* detect labels and apply labes specific stuff (e.g geomery) + * to the context */ + fdisk_probe_labels(cxt); + + /* let's apply user geometry *after* label prober + * to make it possible to override in-label setting */ + fdisk_apply_user_device_properties(cxt); + + /* warn about obsolete stuff on the device if we aren't in + * list-only mode and there is not PT yet */ + if (!fdisk_is_listonly(cxt) && !fdisk_has_label(cxt)) + warn_wipe(cxt); + + DBG(CXT, ul_debugobj(cxt, "initialized for %s [%s]", + fname, readonly ? "READ-ONLY" : "READ-WRITE")); + return 0; +fail: + DBG(CXT, ul_debugobj(cxt, "failed to assign device")); + return -errno; +} + +/** + * fdisk_deassign_device: + * @cxt: context + * @nosync: disable fsync() + * + * Close device and call fsync(). If the @cxt is nested context than the + * request is redirected to the parent. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_deassign_device(struct fdisk_context *cxt, int nosync) +{ + assert(cxt); + assert(cxt->dev_fd >= 0); + + if (cxt->parent) { + int rc = fdisk_deassign_device(cxt->parent, nosync); + + if (!rc) + rc = init_nested_from_parent(cxt, 0); + return rc; + } + + if (cxt->readonly) + close(cxt->dev_fd); + else { + if (fsync(cxt->dev_fd) || close(cxt->dev_fd)) { + fdisk_warn(cxt, _("%s: close device failed"), + cxt->dev_path); + return -errno; + } + + if (!nosync) { + fdisk_info(cxt, _("Syncing disks.")); + sync(); + } + } + + free(cxt->dev_path); + cxt->dev_path = NULL; + + cxt->dev_fd = -1; + + return 0; +} + +/** + * fdisk_is_readonly: + * @cxt: context + * + * Returns: 1 if device open readonly + */ +int fdisk_is_readonly(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->readonly; +} + +/** + * fdisk_unref_context: + * @cxt: fdisk context + * + * Deallocates context struct. + */ +void fdisk_unref_context(struct fdisk_context *cxt) +{ + int i; + + if (!cxt) + return; + + cxt->refcount--; + if (cxt->refcount <= 0) { + DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path)); + + reset_context(cxt); /* this is sensitive to parent<->child relationship! */ + + /* deallocate label's private stuff */ + for (i = 0; i < cxt->nlabels; i++) { + if (!cxt->labels[i]) + continue; + if (cxt->labels[i]->op->free) + cxt->labels[i]->op->free(cxt->labels[i]); + else + free(cxt->labels[i]); + } + + fdisk_unref_context(cxt->parent); + cxt->parent = NULL; + + free(cxt); + } +} + + +/** + * fdisk_enable_details: + * @cxt: context + * @enable: true/flase + * + * Enables or disables "details" display mode. This function has effect to + * fdisk_partition_to_string() function. + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_enable_details(struct fdisk_context *cxt, int enable) +{ + assert(cxt); + cxt->display_details = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_is_details: + * @cxt: context + * + * Returns: 1 if details are enabled + */ +int fdisk_is_details(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->display_details == 1; +} + +/** + * fdisk_enable_listonly: + * @cxt: context + * @enable: true/flase + * + * Just list partition only, don't care about another details, mistakes, ... + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_enable_listonly(struct fdisk_context *cxt, int enable) +{ + assert(cxt); + cxt->listonly = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_is_listonly: + * @cxt: context + * + * Returns: 1 if list-only mode enabled + */ +int fdisk_is_listonly(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->listonly == 1; +} + + +/** + * fdisk_set_unit: + * @cxt: context + * @str: "cylinder" or "sector". + * + * This is pure shit, unfortunately for example Sun addresses begin of the + * partition by cylinders... + * + * Returns: 0 on succes, <0 on error. + */ +int fdisk_set_unit(struct fdisk_context *cxt, const char *str) +{ + assert(cxt); + + cxt->display_in_cyl_units = 0; + + if (!str) + return 0; + + if (strcmp(str, "cylinder") == 0 || strcmp(str, "cylinders") == 0) + cxt->display_in_cyl_units = 1; + + else if (strcmp(str, "sector") == 0 || strcmp(str, "sectors") == 0) + cxt->display_in_cyl_units = 0; + + DBG(CXT, ul_debugobj(cxt, "display unit: %s", fdisk_get_unit(cxt, 0))); + return 0; +} + +/** + * fdisk_get_unit: + * @cxt: context + * @n: FDISK_PLURAL or FDISK_SINGULAR + * + * Returns: unit name. + */ +const char *fdisk_get_unit(struct fdisk_context *cxt, int n) +{ + assert(cxt); + + if (fdisk_use_cylinders(cxt)) + return P_("cylinder", "cylinders", n); + return P_("sector", "sectors", n); +} + +/** + * fdisk_use_cylinders: + * @cxt: context + * + * Returns: 1 if user wants to display in cylinders. + */ +int fdisk_use_cylinders(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->display_in_cyl_units == 1; +} + +/** + * fdisk_get_units_per_sector: + * @cxt: context + * + * This is necessary only for brain dead situations when we use "cylinders"; + * + * Returns: number of "units" per sector, default is 1 if display unit is sector. + */ +unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt) +{ + assert(cxt); + + if (fdisk_use_cylinders(cxt)) { + assert(cxt->geom.heads); + return cxt->geom.heads * cxt->geom.sectors; + } + return 1; +} + +/** + * fdisk_get_optimal_iosize: + * @cxt: context + * + * The optimal I/O is optional and does not have to be provided by device, + * anyway libfdisk never returns zero. If the optimal I/O size is not provided + * then libfdisk returns minimal I/O size or sector size. + * + * Returns: optimal I/O size in bytes. + */ +unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->optimal_io_size ? cxt->optimal_io_size : cxt->io_size; +} + +/** + * fdisk_get_minimal_iosize: + * @cxt: context + * + * Returns: minimal I/O size in bytes + */ +unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->min_io_size; +} + +/** + * fdisk_get_physector_size: + * @cxt: context + * + * Returns: physical sector size in bytes + */ +unsigned long fdisk_get_physector_size(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->phy_sector_size; +} + +/** + * fdisk_get_sector_size: + * @cxt: context + * + * Returns: logical sector size in bytes + */ +unsigned long fdisk_get_sector_size(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->sector_size; +} + +/** + * fdisk_get_alignment_offset + * @cxt: context + * + * The alignment offset is offset between logical and physical sectors. For + * backward compatibility the first logical sector on 4K disks does no have to + * start on the same place like physical sectors. + * + * Returns: alignment offset in bytes + */ +unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->alignment_offset; +} + +/** + * fdisk_get_grain_size: + * @cxt: context + * + * Returns: grain in bytes used to align partitions (usually 1MiB) + */ +unsigned long fdisk_get_grain_size(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->grain; +} + +/** + * fdisk_get_first_lba: + * @cxt: context + * + * Returns: first possible LBA on disk for data partitions. + */ +fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->first_lba; +} + +/** + * fdisk_set_first_lba: + * @cxt: fdisk context + * @lba: first possible logical sector for data + * + * It's strongly recommended to use the default library setting. The first LBA + * is always reseted by fdisk_assign_device(), fdisk_override_geometry() + * and fdisk_reset_alignment(). This is very low level function and library + * does not check if your setting makes any sense. + * + * This function is necessary only when you want to work with very unusual + * partition tables like GPT protective MBR or hybrid partition tables on + * bootable media where the first partition may start on very crazy offsets. + * + * Returns: 0 on success, <0 on error. + */ +fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba) +{ + assert(cxt); + DBG(CXT, ul_debugobj(cxt, "setting first LBA from %ju to %ju", + (uintmax_t) cxt->first_lba, (uintmax_t) lba)); + cxt->first_lba = lba; + return 0; +} + +/** + * fdisk_get_last_lba: + * @cxt: fdisk context + * + * Note that the device has to be already assigned. + * + * Returns: last possible LBA on device + */ +fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt) +{ + return cxt->last_lba; +} + +/** + * fdisk_set_last_lba: + * @cxt: fdisk context + * @lba: last possible logical sector + * + * It's strongly recommended to use the default library setting. The last LBA + * is always reseted by fdisk_assign_device(), fdisk_override_geometry() and + * fdisk_reset_alignment(). + * + * The default is number of sectors on the device, but maybe modified by the + * current disklabel driver (for example GPT uses and of disk for backup + * header, so last_lba is smaller than total number of sectors). + * + * Returns: 0 on success, <0 on error. + */ +fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba) +{ + assert(cxt); + + if (lba > cxt->total_sectors - 1 && lba < 1) + return -ERANGE; + cxt->last_lba = lba; + return 0; +} + + +/** + * fdisk_get_nsectors: + * @cxt: context + * + * Returns: size of the device in logical sectors. + */ +fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->total_sectors; +} + +/** + * fdisk_get_devname: + * @cxt: context + * + * Returns: device name. + */ +const char *fdisk_get_devname(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->dev_path; +} + +/** + * fdisk_get_devfd: + * @cxt: context + * + * Retruns: device file descriptor. + */ +int fdisk_get_devfd(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->dev_fd; +} + +/** + * fdisk_get_geom_heads: + * @cxt: context + * + * Returns: number of geometry heads. + */ +unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->geom.heads; +} +/** + * fdisk_get_geom_sectors: + * @cxt: context + * + * Returns: number of geometry sectors. + */ +fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->geom.sectors; + +} + +/** + * fdisk_get_geom_cylinders: + * @cxt: context + * + * Returns: number of geometry cylinders + */ +fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->geom.cylinders; +} + +int fdisk_missing_geometry(struct fdisk_context *cxt) +{ + int rc; + + assert(cxt); + + if (!cxt || !cxt->label) + return 0; + + rc = (fdisk_label_require_geometry(cxt->label) && + (!cxt->geom.heads || !cxt->geom.sectors + || !cxt->geom.cylinders)); + + if (rc && !fdisk_is_listonly(cxt)) + fdisk_warnx(cxt, _("Incomplete geometry setting.")); + + return rc; +} + diff --git a/libblkid/libfdisk/src/dos.c b/libblkid/libfdisk/src/dos.c new file mode 100644 index 000000000..2a067076e --- /dev/null +++ b/libblkid/libfdisk/src/dos.c @@ -0,0 +1,2331 @@ +/* + * + * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com> + * 2012 Davidlohr Bueso <dave@gnu.org> + * + * This is re-written version for libfdisk, the original was fdiskdoslabel.c + * from util-linux fdisk. + */ +#include "c.h" +#include "nls.h" +#include "randutils.h" +#include "pt-mbr.h" +#include "strutils.h" + +#include "fdiskP.h" + +#include <ctype.h> + +#define MAXIMUM_PARTS 60 +#define ACTIVE_FLAG 0x80 + +/** + * SECTION: dos + * @title: DOS (MBR) + * @short_description: disk label specific functions + * + */ + + +#define IS_EXTENDED(i) \ + ((i) == MBR_DOS_EXTENDED_PARTITION \ + || (i) == MBR_W95_EXTENDED_PARTITION \ + || (i) == MBR_LINUX_EXTENDED_PARTITION) + +/* + * per partition table entry data + * + * The four primary partitions have the same sectorbuffer + * and have NULL ex_entry. + * + * Each logical partition table entry has two pointers, one for the + * partition and one link to the next one. + */ +struct pte { + struct dos_partition *pt_entry; /* on-disk MBR entry */ + struct dos_partition *ex_entry; /* on-disk EBR entry */ + fdisk_sector_t offset; /* disk sector number */ + unsigned char *sectorbuffer; /* disk sector contents */ + + unsigned int changed : 1, + private_sectorbuffer : 1; +}; + +/* + * in-memory fdisk GPT stuff + */ +struct fdisk_dos_label { + struct fdisk_label head; /* generic part */ + + struct pte ptes[MAXIMUM_PARTS]; /* partition */ + fdisk_sector_t ext_offset; /* start of the ext.partition */ + size_t ext_index; /* ext.partition index (if ext_offset is set) */ + unsigned int compatible : 1, /* is DOS compatible? */ + non_pt_changed : 1; /* MBR, but no PT changed */ +}; + +/* + * Partition types + */ +static struct fdisk_parttype dos_parttypes[] = { + #include "pt-mbr-partnames.h" +}; + +#define set_hsc(h,s,c,sector) { \ + s = sector % cxt->geom.sectors + 1; \ + sector /= cxt->geom.sectors; \ + h = sector % cxt->geom.heads; \ + sector /= cxt->geom.heads; \ + c = sector & 0xff; \ + s |= (sector >> 2) & 0xc0; \ + } + + +#define sector(s) ((s) & 0x3f) +#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) + +#define alignment_required(_x) ((_x)->grain != (_x)->sector_size) + +#define is_dos_compatible(_x) \ + (fdisk_is_label(_x, DOS) && \ + fdisk_dos_is_compatible(fdisk_get_label(_x, NULL))) + +#define cround(c, n) fdisk_cround(c, n) + + +static inline struct fdisk_dos_label *self_label(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + return (struct fdisk_dos_label *) cxt->label; +} + +static inline struct pte *self_pte(struct fdisk_context *cxt, size_t i) +{ + struct fdisk_dos_label *l = self_label(cxt); + + if (i >= ARRAY_SIZE(l->ptes)) + return NULL; + + return &l->ptes[i]; +} + +static inline struct dos_partition *self_partition( + struct fdisk_context *cxt, + size_t i) +{ + struct pte *pe = self_pte(cxt, i); + return pe ? pe->pt_entry : NULL; +} + +struct dos_partition *fdisk_dos_get_partition( + struct fdisk_context *cxt, + size_t i) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + return self_partition(cxt, i); +} + +static struct fdisk_parttype *dos_partition_parttype( + struct fdisk_context *cxt, + struct dos_partition *p) +{ + struct fdisk_parttype *t + = fdisk_label_get_parttype_from_code(cxt->label, p->sys_ind); + return t ? : fdisk_new_unknown_parttype(p->sys_ind, NULL); +} + +/* + * Linux kernel cares about partition size only. Things like + * partition type or so are completely irrelevant -- kzak Nov-2013 + */ +static int is_used_partition(struct dos_partition *p) +{ + return p && dos_partition_get_size(p) != 0; +} + +static void partition_set_changed( + struct fdisk_context *cxt, + size_t i, + int changed) +{ + struct pte *pe = self_pte(cxt, i); + + if (!pe) + return; + + DBG(LABEL, ul_debug("DOS: setting %zu partition to %s", i, + changed ? "changed" : "unchanged")); + + pe->changed = changed ? 1 : 0; + if (changed) + fdisk_label_set_changed(cxt->label, 1); +} + +static fdisk_sector_t get_abs_partition_start(struct pte *pe) +{ + assert(pe); + assert(pe->pt_entry); + + return pe->offset + dos_partition_get_start(pe->pt_entry); +} + +static fdisk_sector_t get_abs_partition_end(struct pte *pe) +{ + fdisk_sector_t size; + + assert(pe); + assert(pe->pt_entry); + + size = dos_partition_get_size(pe->pt_entry); + return get_abs_partition_start(pe) + size - (size ? 1 : 0); +} + +static int is_cleared_partition(struct dos_partition *p) +{ + return !(!p || p->boot_ind || p->bh || p->bs || p->bc || + p->sys_ind || p->eh || p->es || p->ec || + dos_partition_get_start(p) || dos_partition_get_size(p)); +} + +static int get_partition_unused_primary(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + size_t org, n; + int rc; + + assert(cxt); + assert(cxt->label); + assert(partno); + + org = cxt->label->nparts_max; + + cxt->label->nparts_max = 4; + rc = fdisk_partition_next_partno(pa, cxt, &n); + cxt->label->nparts_max = org; + + if (rc == 1) { + fdisk_info(cxt, _("All primary partitions have been defined already.")); + rc = -1; + } else if (rc == 0) + *partno = n; + return rc; +} + +static int seek_sector(struct fdisk_context *cxt, fdisk_sector_t secno) +{ + off_t offset = (off_t) secno * cxt->sector_size; + + return lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1 ? -errno : 0; +} + +static int read_sector(struct fdisk_context *cxt, fdisk_sector_t secno, + unsigned char *buf) +{ + int rc = seek_sector(cxt, secno); + ssize_t r; + + if (rc < 0) + return rc; + + r = read(cxt->dev_fd, buf, cxt->sector_size); + if (r == (ssize_t) cxt->sector_size) + return 0; + if (r < 0) + return -errno; + return -1; +} + +/* Allocate a buffer and read a partition table sector */ +static int read_pte(struct fdisk_context *cxt, size_t pno, fdisk_sector_t offset) +{ + int rc; + unsigned char *buf; + struct pte *pe = self_pte(cxt, pno); + + buf = calloc(1, cxt->sector_size); + if (!buf) + return -ENOMEM; + + DBG(LABEL, ul_debug("DOS: reading EBR %zu: offset=%ju, buffer=%p", + pno, (uintmax_t) offset, buf)); + + pe->offset = offset; + pe->sectorbuffer = buf; + pe->private_sectorbuffer = 1; + + rc = read_sector(cxt, offset, pe->sectorbuffer); + if (rc) { + fdisk_warn(cxt, _("Failed to read extended partition table " + "(offset=%ju)"), (uintmax_t) offset); + return rc; + } + + pe->changed = 0; + pe->pt_entry = pe->ex_entry = NULL; + return 0; +} + + +static void clear_partition(struct dos_partition *p) +{ + if (!p) + return; + p->boot_ind = 0; + p->bh = 0; + p->bs = 0; + p->bc = 0; + p->sys_ind = 0; + p->eh = 0; + p->es = 0; + p->ec = 0; + dos_partition_set_start(p,0); + dos_partition_set_size(p,0); +} + +static void dos_init(struct fdisk_context *cxt) +{ + struct fdisk_dos_label *l = self_label(cxt); + size_t i; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + DBG(LABEL, ul_debug("DOS: initialize, first sector buffer %p", cxt->firstsector)); + + cxt->label->nparts_max = 4; /* default, unlimited number of logical */ + + l->ext_index = 0; + l->ext_offset = 0; + l->non_pt_changed = 0; + + memset(l->ptes, 0, sizeof(l->ptes)); + + for (i = 0; i < 4; i++) { + struct pte *pe = self_pte(cxt, i); + + pe->pt_entry = mbr_get_partition(cxt->firstsector, i); + pe->ex_entry = NULL; + pe->offset = 0; + pe->sectorbuffer = cxt->firstsector; + pe->private_sectorbuffer = 0; + pe->changed = 0; + } + + if (fdisk_is_listonly(cxt)) + return; + /* + * Various warnings... + */ + if (fdisk_missing_geometry(cxt)) + fdisk_warnx(cxt, _("You can set geometry from the extra functions menu.")); + + if (is_dos_compatible(cxt)) { + fdisk_warnx(cxt, _("DOS-compatible mode is deprecated.")); + + if (cxt->sector_size != cxt->phy_sector_size) + fdisk_info(cxt, _( + "The device presents a logical sector size that is smaller than " + "the physical sector size. Aligning to a physical sector (or optimal " + "I/O) size boundary is recommended, or performance may be impacted.")); + } + + if (fdisk_use_cylinders(cxt)) + fdisk_warnx(cxt, _("Cylinders as display units are deprecated.")); + + if (cxt->total_sectors > UINT_MAX) { + uint64_t bytes = cxt->total_sectors * cxt->sector_size; + char *szstr = size_to_human_string(SIZE_SUFFIX_SPACE + | SIZE_SUFFIX_3LETTER, bytes); + fdisk_warnx(cxt, + _("The size of this disk is %s (%ju bytes). DOS " + "partition table format can not be used on drives for " + "volumes larger than %lu bytes for %lu-byte " + "sectors. Use GUID partition table format (GPT)."), + szstr, bytes, + UINT_MAX * cxt->sector_size, + cxt->sector_size); + free(szstr); + } +} + +/* callback called by libfdisk */ +static void dos_deinit(struct fdisk_label *lb) +{ + size_t i; + struct fdisk_dos_label *l = (struct fdisk_dos_label *) lb; + + for (i = 0; i < ARRAY_SIZE(l->ptes); i++) { + struct pte *pe = &l->ptes[i]; + + if (pe->private_sectorbuffer && pe->sectorbuffer) { + DBG(LABEL, ul_debug("DOS: freeing pte %zu sector buffer %p", + i, pe->sectorbuffer)); + free(pe->sectorbuffer); + } + pe->sectorbuffer = NULL; + pe->private_sectorbuffer = 0; + } + + memset(l->ptes, 0, sizeof(l->ptes)); +} + +static void reset_pte(struct pte *pe) +{ + assert(pe); + + if (pe->private_sectorbuffer) { + DBG(LABEL, ul_debug(" --> freeing pte sector buffer %p", + pe->sectorbuffer)); + free(pe->sectorbuffer); + } + memset(pe, 0, sizeof(struct pte)); +} + +static int dos_delete_partition(struct fdisk_context *cxt, size_t partnum) +{ + struct fdisk_dos_label *l; + struct pte *pe; + struct dos_partition *p; + struct dos_partition *q; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + pe = self_pte(cxt, partnum); + if (!pe) + return -EINVAL; + + DBG(LABEL, ul_debug("DOS: delete partiton %zu (max=%zu)", partnum, + cxt->label->nparts_max)); + + l = self_label(cxt); + p = pe->pt_entry; + q = pe->ex_entry; + + /* Note that for the fifth partition (partnum == 4) we don't actually + decrement partitions. */ + if (partnum < 4) { + DBG(LABEL, ul_debug("--> delete primary")); + if (IS_EXTENDED(p->sys_ind) && partnum == l->ext_index) { + cxt->label->nparts_max = 4; + l->ptes[l->ext_index].ex_entry = NULL; + l->ext_offset = 0; + l->ext_index = 0; + } + partition_set_changed(cxt, partnum, 1); + clear_partition(p); + } else if (!q->sys_ind && partnum > 4) { + DBG(LABEL, ul_debug("--> delete logical [last in the chain]")); + reset_pte(&l->ptes[partnum]); + --cxt->label->nparts_max; + --partnum; + /* clear link to deleted partition */ + clear_partition(l->ptes[partnum].ex_entry); + partition_set_changed(cxt, partnum, 1); + } else { + DBG(LABEL, ul_debug("--> delete logical [move down]")); + if (partnum > 4) { + DBG(LABEL, ul_debug(" --> delete %zu logical link", partnum)); + p = l->ptes[partnum - 1].ex_entry; + *p = *q; + dos_partition_set_start(p, dos_partition_get_start(q)); + dos_partition_set_size(p, dos_partition_get_size(q)); + partition_set_changed(cxt, partnum - 1, 1); + + } else if (cxt->label->nparts_max > 5) { + DBG(LABEL, ul_debug(" --> delete first logical link")); + pe = &l->ptes[5]; /* second logical */ + + if (pe->pt_entry) /* prevent SEGFAULT */ + dos_partition_set_start(pe->pt_entry, + get_abs_partition_start(pe) - + l->ext_offset); + pe->offset = l->ext_offset; + partition_set_changed(cxt, 5, 1); + } + + if (cxt->label->nparts_max > 5) { + DBG(LABEL, ul_debug(" --> move ptes")); + cxt->label->nparts_max--; + reset_pte(&l->ptes[partnum]); + while (partnum < cxt->label->nparts_max) { + DBG(LABEL, ul_debug(" --> moving pte %zu <-- %zu", partnum, partnum + 1)); + l->ptes[partnum] = l->ptes[partnum + 1]; + partnum++; + } + memset(&l->ptes[partnum], 0, sizeof(struct pte)); + } else { + DBG(LABEL, ul_debug(" --> the only logical: clear only")); + clear_partition(l->ptes[partnum].pt_entry); + cxt->label->nparts_max--; + + if (partnum == 4) { + DBG(LABEL, ul_debug(" --> clear last logical")); + reset_pte(&l->ptes[partnum]); + partition_set_changed(cxt, l->ext_index, 1); + } + } + } + + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static void read_extended(struct fdisk_context *cxt, size_t ext) +{ + size_t i; + struct pte *pex, *pe; + struct dos_partition *p, *q; + struct fdisk_dos_label *l = self_label(cxt); + + l->ext_index = ext; + pex = self_pte(cxt, ext); + pex->ex_entry = pex->pt_entry; + + p = pex->pt_entry; + if (!dos_partition_get_start(p)) { + fdisk_warnx(cxt, _("Bad offset in primary extended partition.")); + return; + } + + DBG(LABEL, ul_debug("DOS: Reading extended %zu", ext)); + + while (IS_EXTENDED (p->sys_ind)) { + pe = self_pte(cxt, cxt->label->nparts_max); + + if (cxt->label->nparts_max >= MAXIMUM_PARTS) { + /* This is not a Linux restriction, but + this program uses arrays of size MAXIMUM_PARTS. + Do not try to `improve' this test. */ + struct pte *pre = self_pte(cxt, + cxt->label->nparts_max - 1); + fdisk_warnx(cxt, + _("Omitting partitions after #%zu. They will be deleted " + "if you save this partition table."), + cxt->label->nparts_max); + + clear_partition(pre->ex_entry); + partition_set_changed(cxt, + cxt->label->nparts_max - 1, 1); + return; + } + + if (read_pte(cxt, cxt->label->nparts_max, l->ext_offset + + dos_partition_get_start(p))) + return; + + if (!l->ext_offset) + l->ext_offset = dos_partition_get_start(p); + + assert(pe->sectorbuffer); + q = p = mbr_get_partition(pe->sectorbuffer, 0); + + for (i = 0; i < 4; i++, p++) { + if (!dos_partition_get_size(p)) + continue; + + if (IS_EXTENDED (p->sys_ind)) { + if (pe->ex_entry) + fdisk_warnx(cxt, _( + "Extra link pointer in partition " + "table %zu."), + cxt->label->nparts_max + 1); + else + pe->ex_entry = p; + } else if (p->sys_ind) { + if (pe->pt_entry) + fdisk_warnx(cxt, _( + "Ignoring extra data in partition " + "table %zu."), + cxt->label->nparts_max + 1); + else + pe->pt_entry = p; + } + } + + /* very strange code here... */ + if (!pe->pt_entry) { + if (q != pe->ex_entry) + pe->pt_entry = q; + else + pe->pt_entry = q + 1; + } + if (!pe->ex_entry) { + if (q != pe->pt_entry) + pe->ex_entry = q; + else + pe->ex_entry = q + 1; + } + + p = pe->ex_entry; + cxt->label->nparts_cur = ++cxt->label->nparts_max; + + DBG(LABEL, ul_debug("DOS: EBR[offset=%ju]: link: type=%x, start=%u, size=%u; " + " data: type=%x, start=%u, size=%u", + (uintmax_t) pe->offset, + pe->ex_entry->sys_ind, + dos_partition_get_start(pe->ex_entry), + dos_partition_get_size(pe->ex_entry), + pe->pt_entry->sys_ind, + dos_partition_get_start(pe->pt_entry), + dos_partition_get_size(pe->pt_entry))); + + } + + /* remove last empty EBR */ + pe = self_pte(cxt, cxt->label->nparts_max - 1); + if (is_cleared_partition(pe->ex_entry) && + is_cleared_partition(pe->pt_entry)) { + DBG(LABEL, ul_debug("DOS: EBR[offset=%ju]: empty, remove", (uintmax_t) pe->offset)); + reset_pte(pe); + cxt->label->nparts_max--; + cxt->label->nparts_cur--; + } + + /* remove empty links */ + remove: + q = self_partition(cxt, 4); + for (i = 4; i < cxt->label->nparts_max; i++) { + p = self_partition(cxt, i); + + if (!dos_partition_get_size(p) && + (cxt->label->nparts_max > 5 || q->sys_ind)) { + fdisk_info(cxt, _("omitting empty partition (%zu)"), i+1); + dos_delete_partition(cxt, i); + goto remove; /* numbering changed */ + } + } + + DBG(LABEL, ul_debug("DOS: nparts_max: %zu", cxt->label->nparts_max)); +} + +static int dos_get_disklabel_id(struct fdisk_context *cxt, char **id) +{ + unsigned int num; + + assert(cxt); + assert(id); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + num = mbr_get_id(cxt->firstsector); + if (asprintf(id, "0x%08x", num) > 0) + return 0; + + return -ENOMEM; +} + +static int dos_create_disklabel(struct fdisk_context *cxt) +{ + unsigned int id = 0; + int rc, has_id = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + DBG(LABEL, ul_debug("DOS: creating new disklabel")); + + if (cxt->script) { + char *end = NULL; + const char *s = fdisk_script_get_header(cxt->script, "label-id"); + + if (s) { + errno = 0; + id = strtol(s, &end, 16); + if (!errno && end && s < end) + has_id = 1; + } + } + + /* random disk signature */ + if (!has_id) + random_get_bytes(&id, sizeof(id)); + + dos_init(cxt); + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + fdisk_label_set_changed(cxt->label, 1); + + /* Generate an MBR ID for this disk */ + mbr_set_id(cxt->firstsector, id); + + /* Put MBR signature */ + mbr_set_magic(cxt->firstsector); + + fdisk_info(cxt, _("Created a new DOS disklabel with disk " + "identifier 0x%08x."), id); + return 0; +} + +static int dos_set_disklabel_id(struct fdisk_context *cxt) +{ + char *end = NULL, *str = NULL; + unsigned int id, old; + struct fdisk_dos_label *l; + int rc; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + DBG(LABEL, ul_debug("DOS: setting Id")); + + l = self_label(cxt); + old = mbr_get_id(cxt->firstsector); + rc = fdisk_ask_string(cxt, + _("Enter the new disk identifier"), &str); + if (rc) + return rc; + + errno = 0; + id = strtoul(str, &end, 0); + if (errno || str == end || (end && *end)) { + fdisk_warnx(cxt, _("Incorrect value.")); + return -EINVAL; + } + + + mbr_set_id(cxt->firstsector, id); + l->non_pt_changed = 1; + fdisk_label_set_changed(cxt->label, 1); + + fdisk_info(cxt, _("Disk identifier changed from 0x%08x to 0x%08x."), + old, id); + return 0; +} + +static void get_partition_table_geometry(struct fdisk_context *cxt, + unsigned int *ph, unsigned int *ps) +{ + unsigned char *bufp = cxt->firstsector; + struct dos_partition *p; + int i, h, s, hh, ss; + int first = 1; + int bad = 0; + + hh = ss = 0; + for (i = 0; i < 4; i++) { + p = mbr_get_partition(bufp, i); + if (p->sys_ind != 0) { + h = p->eh + 1; + s = (p->es & 077); + if (first) { + hh = h; + ss = s; + first = 0; + } else if (hh != h || ss != s) + bad = 1; + } + } + + if (!first && !bad) { + *ph = hh; + *ps = ss; + } + + DBG(LABEL, ul_debug("DOS PT geometry: heads=%u, sectors=%u", *ph, *ps)); +} + +static int dos_reset_alignment(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + /* overwrite necessary stuff by DOS deprecated stuff */ + if (is_dos_compatible(cxt)) { + DBG(LABEL, ul_debug("DOS: reseting alignemnt for DOS-comaptiblem PT")); + if (cxt->geom.sectors) + cxt->first_lba = cxt->geom.sectors; /* usually 63 */ + + cxt->grain = cxt->sector_size; /* usually 512 */ + } + + return 0; +} + +/* TODO: move to include/pt-dos.h and share with libblkid */ +#define AIX_MAGIC_STRING "\xC9\xC2\xD4\xC1" +#define AIX_MAGIC_STRLEN (sizeof(AIX_MAGIC_STRING) - 1) + +static int dos_probe_label(struct fdisk_context *cxt) +{ + size_t i; + unsigned int h = 0, s = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + /* ignore disks with AIX magic number */ + if (memcmp(cxt->firstsector, AIX_MAGIC_STRING, AIX_MAGIC_STRLEN) == 0) + return 0; + + if (!mbr_is_valid_magic(cxt->firstsector)) + return 0; + + dos_init(cxt); + + get_partition_table_geometry(cxt, &h, &s); + if (h && s) { + cxt->geom.heads = h; + cxt->geom.sectors = s; + } + + for (i = 0; i < 4; i++) { + struct pte *pe = self_pte(cxt, i); + + if (is_used_partition(pe->pt_entry)) + cxt->label->nparts_cur++; + + if (IS_EXTENDED (pe->pt_entry->sys_ind)) { + if (cxt->label->nparts_max != 4) + fdisk_warnx(cxt, _( + "Ignoring extra extended partition %zu"), + i + 1); + else + read_extended(cxt, i); + } + } + + for (i = 3; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + struct fdisk_dos_label *l = self_label(cxt); + + if (!mbr_is_valid_magic(pe->sectorbuffer)) { + fdisk_info(cxt, _( + "Invalid flag 0x%02x%02x of EBR (for partition %zu) will " + "be corrected by w(rite)."), + pe->sectorbuffer[510], + pe->sectorbuffer[511], + i + 1); + partition_set_changed(cxt, i, 1); + + /* mark also extended as changed to update the first EBR + * in situation that there is no logical partitions at all */ + partition_set_changed(cxt, l->ext_index, 1); + } + } + + return 1; +} + +static void set_partition(struct fdisk_context *cxt, + int i, int doext, fdisk_sector_t start, + fdisk_sector_t stop, int sysid, int boot) +{ + struct pte *pe = self_pte(cxt, i); + struct dos_partition *p; + fdisk_sector_t offset; + + assert(!FDISK_IS_UNDEF(start)); + assert(!FDISK_IS_UNDEF(stop)); + + if (doext) { + struct fdisk_dos_label *l = self_label(cxt); + p = pe->ex_entry; + offset = l->ext_offset; + } else { + p = pe->pt_entry; + offset = pe->offset; + } + + DBG(LABEL, ul_debug("DOS: setting partition %d%s, offset=%zu, start=%zu, stop=%zu, sysid=%02x", + i, doext ? " [extended]" : "", + (size_t) offset, + (size_t) (start - offset), + (size_t) (stop - start + 1), + sysid)); + + p->boot_ind = boot ? ACTIVE_FLAG : 0; + p->sys_ind = sysid; + dos_partition_set_start(p, start - offset); + dos_partition_set_size(p, stop - start + 1); + + if (is_dos_compatible(cxt) && (start/(cxt->geom.sectors*cxt->geom.heads) > 1023)) + start = cxt->geom.heads*cxt->geom.sectors*1024 - 1; + set_hsc(p->bh, p->bs, p->bc, start); + if (is_dos_compatible(cxt) && (stop/(cxt->geom.sectors*cxt->geom.heads) > 1023)) + stop = cxt->geom.heads*cxt->geom.sectors*1024 - 1; + set_hsc(p->eh, p->es, p->ec, stop); + partition_set_changed(cxt, i, 1); +} + +static fdisk_sector_t get_unused_start(struct fdisk_context *cxt, + int part_n, fdisk_sector_t start, + fdisk_sector_t first[], fdisk_sector_t last[]) +{ + size_t i; + + for (i = 0; i < cxt->label->nparts_max; i++) { + fdisk_sector_t lastplusoff; + struct pte *pe = self_pte(cxt, i); + + if (start == pe->offset) + start += cxt->first_lba; + lastplusoff = last[i] + ((part_n < 4) ? 0 : cxt->first_lba); + if (start >= first[i] && start <= lastplusoff) + start = lastplusoff + 1; + } + + return start; +} + +static void fill_bounds(struct fdisk_context *cxt, + fdisk_sector_t *first, fdisk_sector_t *last) +{ + size_t i; + struct pte *pe = self_pte(cxt, 0); + struct dos_partition *p; + + for (i = 0; i < cxt->label->nparts_max; pe++,i++) { + p = pe->pt_entry; + if (is_cleared_partition(p) || IS_EXTENDED (p->sys_ind)) { + first[i] = 0xffffffff; + last[i] = 0; + } else { + first[i] = get_abs_partition_start(pe); + last[i] = get_abs_partition_end(pe); + } + } +} + +static int get_start_from_user( struct fdisk_context *cxt, + fdisk_sector_t *start, + fdisk_sector_t low, + fdisk_sector_t dflt, + fdisk_sector_t limit, + struct fdisk_partition *pa) +{ + assert(start); + + /* try to use tepmlate from 'pa' */ + if (pa && pa->start_follow_default) + *start = dflt; + + else if (pa && fdisk_partition_has_start(pa)) { + DBG(LABEL, ul_debug("DOS: start: wanted=%ju, low=%ju, limit=%ju", + (uintmax_t) pa->start, (uintmax_t) low, (uintmax_t) limit)); + *start = pa->start; + if (*start < low || *start > limit) { + fdisk_warnx(cxt, _("Start sector %ju out of range."), + (uintmax_t) *start); + return -ERANGE; + } + } else { + /* ask user by dialog */ + struct fdisk_ask *ask = fdisk_new_ask(); + int rc; + + if (!ask) + return -ENOMEM; + fdisk_ask_set_query(ask, + fdisk_use_cylinders(cxt) ? + _("First cylinder") : _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, low)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, dflt)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit)); + + rc = fdisk_do_ask(cxt, ask); + *start = fdisk_ask_number_get_result(ask); + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) { + *start = (*start - 1) + * fdisk_get_units_per_sector(cxt); + if (*start < low) + *start = low; + } + } + + DBG(LABEL, ul_debug("DOS: start is %ju", (uintmax_t) *start)); + return 0; +} + +static fdisk_sector_t get_possible_last(struct fdisk_context *cxt, size_t n) +{ + fdisk_sector_t limit; + + if (n >= 4) { + /* logical partitions */ + struct fdisk_dos_label *l = self_label(cxt); + struct pte *ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + if (!ext_pe) + return 0; + limit = get_abs_partition_end(ext_pe); + } else { + /* primary partitions */ + if (fdisk_use_cylinders(cxt) || !cxt->total_sectors) + limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1; + else + limit = cxt->total_sectors - 1; + + if (limit > UINT_MAX) + limit = UINT_MAX; + } + + DBG(LABEL, ul_debug("DOS: last possible sector for #%zu is %ju", + n, (uintmax_t) limit)); + return limit; +} + +/* returns last free sector for area addressed by @start, the first[] and + * last[] are fill_bounds() results */ +static fdisk_sector_t get_unused_last(struct fdisk_context *cxt, size_t n, + fdisk_sector_t start, + fdisk_sector_t first[], fdisk_sector_t last[]) +{ + size_t i; + fdisk_sector_t limit = get_possible_last(cxt, n); + + for (i = 0; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + + if (start < pe->offset && limit >= pe->offset) + limit = pe->offset - 1; + if (start < first[i] && limit >= first[i]) + limit = first[i] - 1; + } + + DBG(LABEL, ul_debug("DOS: unused sector for #%zu is %ju", + n, (uintmax_t) limit)); + return limit; +} + +static int add_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + int sys, read = 0, rc, isrel = 0; + size_t i; + struct fdisk_dos_label *l = self_label(cxt); + struct dos_partition *p = self_partition(cxt, n); + struct pte *ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + fdisk_sector_t start, stop = 0, limit, temp, + first[cxt->label->nparts_max], + last[cxt->label->nparts_max]; + + DBG(LABEL, ul_debug("DOS: adding partition %zu", n)); + + sys = pa && pa->type ? pa->type->code : MBR_LINUX_DATA_PARTITION; + + if (is_used_partition(p)) { + fdisk_warnx(cxt, _("Partition %zu is already defined. " + "Delete it before re-adding it."), + n + 1); + return -EINVAL; + } + fill_bounds(cxt, first, last); + limit = get_possible_last(cxt, n); + + if (n < 4) { + if (cxt->parent && fdisk_is_label(cxt->parent, GPT)) + start = 1; /* Bad boy modifies hybrid MBR */ + else { + if (cxt->script && pa && fdisk_partition_has_start(pa) + && pa->start < cxt->first_lba + && pa->start >= 1) + fdisk_set_first_lba(cxt, 1); + + start = cxt->first_lba; + } + + if (l->ext_offset) { + assert(ext_pe); + first[l->ext_index] = l->ext_offset; + last[l->ext_index] = get_abs_partition_end(ext_pe); + } + } else { + assert(ext_pe); + + if (cxt->script && pa && fdisk_partition_has_start(pa) + && pa->start >= l->ext_offset + && pa->start < l->ext_offset + cxt->first_lba) + fdisk_set_first_lba(cxt, 1); + + start = l->ext_offset + cxt->first_lba; + } + + if (fdisk_use_cylinders(cxt)) + for (i = 0; i < cxt->label->nparts_max; i++) { + first[i] = (fdisk_cround(cxt, first[i]) - 1) + * fdisk_get_units_per_sector(cxt); + } + + /* + * Ask for first sector + */ + do { + fdisk_sector_t dflt, aligned; + + temp = start; + dflt = start = get_unused_start(cxt, n, start, first, last); + + if (n >= 4 && pa && fdisk_partition_has_start(pa) && cxt->script + && cxt->first_lba > 1 + && temp == start - cxt->first_lba) { + fdisk_set_first_lba(cxt, 1); + start = pa->start; + } + + /* the default sector should be aligned and unused */ + do { + aligned = fdisk_align_lba_in_range(cxt, dflt, dflt, limit); + dflt = get_unused_start(cxt, n, aligned, first, last); + } while (dflt != aligned && dflt > aligned && dflt < limit); + + if (dflt >= limit) + dflt = start; + if (start > limit) + break; + if (start >= temp + fdisk_get_units_per_sector(cxt) + && read) { + fdisk_info(cxt, _("Sector %llu is already allocated."), + temp); + temp = start; + read = 0; + if (pa && (fdisk_partition_has_start(pa) || + pa->start_follow_default)) + break; + } + + if (!read && start == temp) { + rc = get_start_from_user(cxt, &start, temp, dflt, limit, pa); + if (rc) + return rc; + read = 1; + } + } while (start != temp || !read); + + if (n == 4) { + /* The first EBR is stored at begin of the extended partition */ + struct pte *pe = self_pte(cxt, n); + pe->offset = l->ext_offset; + + } else if (n > 4) { + /* The second (and another) EBR */ + struct pte *pe = self_pte(cxt, n); + + pe->offset = start - cxt->first_lba; + if (pe->offset == l->ext_offset) { /* must be corrected */ + pe->offset++; + if (cxt->first_lba == 1) + start++; + } + } + + limit = get_unused_last(cxt, n, start, first, last); + + if (start > limit) { + fdisk_info(cxt, _("No free sectors available.")); + if (n > 4) + cxt->label->nparts_max--; + return -ENOSPC; + } + + /* + * Ask for last sector + */ + if (fdisk_cround(cxt, start) == fdisk_cround(cxt, limit)) + stop = limit; + else if (pa && pa->end_follow_default) + stop = limit; + else if (pa && fdisk_partition_has_size(pa)) { + stop = start + pa->size - 1; + isrel = pa->size_explicit ? 0 : 1; + } else { + /* ask user by dialog */ + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + + if (fdisk_use_cylinders(cxt)) { + fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_get_units_per_sector(cxt)); + } else { + fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask,cxt->sector_size); + } + + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, start)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, limit)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit)); + fdisk_ask_number_set_base(ask, fdisk_cround(cxt, start)); /* base for relative input */ + + rc = fdisk_do_ask(cxt, ask); + stop = fdisk_ask_number_get_result(ask); + isrel = fdisk_ask_number_is_relative(ask); + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) { + stop = stop * fdisk_get_units_per_sector(cxt) - 1; + if (stop >limit) + stop = limit; + } + } + + DBG(LABEL, ul_debug("DOS: raw stop: %ju", (uintmax_t) stop)); + + if (stop > limit) + stop = limit; + + if (stop < limit) { + if (isrel && alignment_required(cxt)) { + /* the last sector has not been exactly requested (but + * defined by +size{K,M,G} convention), so be smart and + * align the end of the partition. The next partition + * will start at phy.block boundary. + */ + stop = fdisk_align_lba_in_range(cxt, stop, start, limit) - 1; + if (stop > limit) + stop = limit; + } + } + + set_partition(cxt, n, 0, start, stop, sys, pa && pa->boot == 1 ? 1 : 0); + if (n > 4) { + struct pte *pe = self_pte(cxt, n); + set_partition(cxt, n - 1, 1, pe->offset, stop, + MBR_DOS_EXTENDED_PARTITION, 0); + } + + /* report */ + { + struct fdisk_parttype *t = + fdisk_label_get_parttype_from_code(cxt->label, sys); + fdisk_info_new_partition(cxt, n + 1, start, stop, t); + fdisk_unref_parttype(t); + } + + + if (IS_EXTENDED(sys)) { + struct pte *pen = self_pte(cxt, n); + + l->ext_index = n; + l->ext_offset = start; + pen->ex_entry = p; + } + + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static int add_logical(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + struct pte *pe; + int rc; + + assert(cxt); + assert(partno); + assert(cxt->label); + assert(self_label(cxt)->ext_offset); + + DBG(LABEL, ul_debug("DOS: nparts max: %zu", cxt->label->nparts_max)); + pe = self_pte(cxt, cxt->label->nparts_max); + + if (!pe->sectorbuffer) { + pe->sectorbuffer = calloc(1, cxt->sector_size); + if (!pe->sectorbuffer) + return -ENOMEM; + DBG(LABEL, ul_debug("DOS: logical: %zu: new EBR sector buffer %p", + cxt->label->nparts_max, pe->sectorbuffer)); + pe->private_sectorbuffer = 1; + } + pe->pt_entry = mbr_get_partition(pe->sectorbuffer, 0); + pe->ex_entry = pe->pt_entry + 1; + pe->offset = 0; + partition_set_changed(cxt, cxt->label->nparts_max, 1); + + cxt->label->nparts_max++; + + /* this message makes sense only when we use extended/primary/logical + * dialog. The dialog is disable for scripts, see dos_add_partition() */ + if (!cxt->script) + fdisk_info(cxt, _("Adding logical partition %zu"), + cxt->label->nparts_max); + *partno = cxt->label->nparts_max - 1; + rc = add_partition(cxt, *partno, pa); + + if (rc) { + /* reset on error */ + cxt->label->nparts_max--; + pe->pt_entry = NULL; + pe->ex_entry = NULL; + pe->offset = 0; + pe->changed = 0; + } + + return rc; +} + +static void check(struct fdisk_context *cxt, size_t n, + unsigned int h, unsigned int s, unsigned int c, + unsigned int start) +{ + unsigned int total, real_s, real_c; + + if (!is_dos_compatible(cxt)) + return; + + real_s = sector(s) - 1; + real_c = cylinder(s, c); + total = (real_c * cxt->geom.heads + h) * cxt->geom.sectors + real_s; + + if (!total) + fdisk_warnx(cxt, _("Partition %zu: contains sector 0"), n); + if (h >= cxt->geom.heads) + fdisk_warnx(cxt, _("Partition %zu: head %d greater than " + "maximum %d"), n, h + 1, cxt->geom.heads); + if (real_s >= cxt->geom.sectors) + fdisk_warnx(cxt, _("Partition %zu: sector %d greater than " + "maximum %llu"), n, s, cxt->geom.sectors); + if (real_c >= cxt->geom.cylinders) + fdisk_warnx(cxt, _("Partition %zu: cylinder %d greater than " + "maximum %llu"), + n, real_c + 1, + cxt->geom.cylinders); + + if (cxt->geom.cylinders <= 1024 && start != total) + fdisk_warnx(cxt, _("Partition %zu: previous sectors %u " + "disagrees with total %u"), n, start, total); +} + +/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993, + * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, + * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. + * Lubkin Oct. 1991). */ + +static void +long2chs(struct fdisk_context *cxt, unsigned long ls, + unsigned int *c, unsigned int *h, unsigned int *s) { + int spc = cxt->geom.heads * cxt->geom.sectors; + + *c = ls / spc; + ls = ls % spc; + *h = ls / cxt->geom.sectors; + *s = ls % cxt->geom.sectors + 1; /* sectors count from 1 */ +} + +static void check_consistency(struct fdisk_context *cxt, struct dos_partition *p, + size_t partition) +{ + unsigned int pbc, pbh, pbs; /* physical beginning c, h, s */ + unsigned int pec, peh, pes; /* physical ending c, h, s */ + unsigned int lbc, lbh, lbs; /* logical beginning c, h, s */ + unsigned int lec, leh, les; /* logical ending c, h, s */ + + if (!is_dos_compatible(cxt)) + return; + + if (!cxt->geom.heads || !cxt->geom.sectors || (partition >= 4)) + return; /* do not check extended partitions */ + + /* physical beginning c, h, s */ + pbc = (p->bc & 0xff) | ((p->bs << 2) & 0x300); + pbh = p->bh; + pbs = p->bs & 0x3f; + + /* physical ending c, h, s */ + pec = (p->ec & 0xff) | ((p->es << 2) & 0x300); + peh = p->eh; + pes = p->es & 0x3f; + + /* compute logical beginning (c, h, s) */ + long2chs(cxt, dos_partition_get_start(p), &lbc, &lbh, &lbs); + + /* compute logical ending (c, h, s) */ + long2chs(cxt, dos_partition_get_start(p) + dos_partition_get_size(p) - 1, &lec, &leh, &les); + + /* Same physical / logical beginning? */ + if (cxt->geom.cylinders <= 1024 + && (pbc != lbc || pbh != lbh || pbs != lbs)) { + fdisk_warnx(cxt, _("Partition %zu: different physical/logical " + "beginnings (non-Linux?): " + "phys=(%d, %d, %d), logical=(%d, %d, %d)"), + partition + 1, + pbc, pbh, pbs, + lbc, lbh, lbs); + } + + /* Same physical / logical ending? */ + if (cxt->geom.cylinders <= 1024 + && (pec != lec || peh != leh || pes != les)) { + fdisk_warnx(cxt, _("Partition %zu: different physical/logical " + "endings: phys=(%d, %d, %d), logical=(%d, %d, %d)"), + partition + 1, + pec, peh, pes, + lec, leh, les); + } + + /* Ending on cylinder boundary? */ + if (peh != (cxt->geom.heads - 1) || pes != cxt->geom.sectors) { + fdisk_warnx(cxt, _("Partition %zu: does not end on " + "cylinder boundary."), + partition + 1); + } +} + +static int dos_verify_disklabel(struct fdisk_context *cxt) +{ + size_t i, j; + fdisk_sector_t total = 1, n_sectors = cxt->total_sectors; + fdisk_sector_t first[cxt->label->nparts_max], + last[cxt->label->nparts_max]; + struct dos_partition *p; + struct fdisk_dos_label *l = self_label(cxt); + + assert(fdisk_is_label(cxt, DOS)); + + fill_bounds(cxt, first, last); + for (i = 0; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + + p = self_partition(cxt, i); + if (is_used_partition(p) && !IS_EXTENDED(p->sys_ind)) { + check_consistency(cxt, p, i); + if (get_abs_partition_start(pe) < first[i]) + fdisk_warnx(cxt, _( + "Partition %zu: bad start-of-data."), + i + 1); + + check(cxt, i + 1, p->eh, p->es, p->ec, last[i]); + total += last[i] + 1 - first[i]; + + if (i == 0) + total += get_abs_partition_start(pe) - 1; + + for (j = 0; j < i; j++) { + if ((first[i] >= first[j] && first[i] <= last[j]) + || ((last[i] <= last[j] && last[i] >= first[j]))) { + + fdisk_warnx(cxt, _("Partition %zu: " + "overlaps partition %zu."), + j + 1, i + 1); + + total += first[i] >= first[j] ? + first[i] : first[j]; + total -= last[i] <= last[j] ? + last[i] : last[j]; + } + } + } + } + + if (l->ext_offset) { + fdisk_sector_t e_last; + struct pte *ext_pe = self_pte(cxt, l->ext_index); + + e_last = get_abs_partition_end(ext_pe); + + for (i = 4; i < cxt->label->nparts_max; i++) { + total++; + p = self_partition(cxt, i); + + if (!p->sys_ind) { + if (i != 4 || i + 1 < cxt->label->nparts_max) + fdisk_warnx(cxt, + _("Partition %zu: empty."), + i + 1); + } else if (first[i] < l->ext_offset + || last[i] > e_last) { + + fdisk_warnx(cxt, _("Logical partition %zu: " + "not entirely in partition %zu."), + i + 1, l->ext_index + 1); + } + } + } + + if (total > n_sectors) + fdisk_warnx(cxt, _("Total allocated sectors %llu greater " + "than the maximum %llu."), total, n_sectors); + else if (total < n_sectors) + fdisk_warnx(cxt, _("Remaining %lld unallocated %ld-byte " + "sectors."), n_sectors - total, cxt->sector_size); + + return 0; +} + +/* + * Ask the user for new partition type information (logical, extended). + * This function calls the actual partition adding logic - add_partition. + * + * API callback. + */ +static int dos_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + size_t i, free_primary = 0, free_sectors = 0; + fdisk_sector_t last = 0, grain; + int rc = 0; + struct fdisk_dos_label *l; + struct pte *ext_pe; + size_t res; /* partno */ + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + DBG(LABEL, ul_debug("DOS: new partition wanted")); + + l = self_label(cxt); + ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + /* + * partition template (@pa) based partitioning + */ + + /* pa specifies start within extended partition, add logical */ + if (pa && fdisk_partition_has_start(pa) && ext_pe + && pa->start >= l->ext_offset + && pa->start <= get_abs_partition_end(ext_pe)) { + DBG(LABEL, ul_debug("DOS: pa template %p: add logical", pa)); + rc = add_logical(cxt, pa, &res); + goto done; + + /* pa specifies that extended partition is wanted */ + } else if (pa && pa->type && pa->type->code == MBR_DOS_EXTENDED_PARTITION) { + DBG(LABEL, ul_debug("DOS: pa template %p: add extened", pa)); + if (l->ext_offset) { + fdisk_warnx(cxt, _("Extended partition already exists.")); + return -EINVAL; + } + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) { + rc = add_partition(cxt, res, pa); + goto done; + } + + /* pa specifies start, but outside extended partition */ + } else if (pa && fdisk_partition_has_start(pa) && l->ext_offset) { + DBG(LABEL, ul_debug("DOS: pa template %p: add primary", pa)); + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) { + rc = add_partition(cxt, res, pa); + goto done; + } + } + + /* + * dialog driven partitioning (it does not mean that @pa template is + * completely ignored!) + */ + + /* check if there is space for primary partition */ + grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1; + last = cxt->first_lba; + + for (i = 0; i < 4; i++) { + struct dos_partition *p = self_partition(cxt, i); + + if (is_used_partition(p)) { + fdisk_sector_t start = dos_partition_get_start(p); + if (last + grain <= start) + free_sectors = 1; + last = start + dos_partition_get_size(p); + } else + free_primary++; + } + if (last + grain < cxt->total_sectors - 1) + free_sectors = 1; + + if (!free_primary && cxt->label->nparts_max >= MAXIMUM_PARTS) { + fdisk_info(cxt, _("The maximum number of partitions has " + "been created.")); + return -EINVAL; + } + rc = 1; + + if (!free_primary || !free_sectors) { + DBG(LABEL, ul_debug("DOS: primary impossible, add logical")); + if (l->ext_offset) { + if (!pa || fdisk_partition_has_start(pa)) { + if (!free_primary) + fdisk_info(cxt, _("All primary partitions are in use.")); + else if (!free_sectors) + fdisk_info(cxt, _("All space for primary partitions is in use.")); + } + rc = add_logical(cxt, pa, &res); + } else { + fdisk_info(cxt, + _( "Impossible to create another primary partition. " + "If you want to create more partitions, you must " + "replace a primary partition with an extended " + "partition first.")); + return -EINVAL; + } + } else if (cxt->label->nparts_max >= MAXIMUM_PARTS) { + fdisk_info(cxt, _("All logical partitions are in use. " + "Adding a primary partition.")); + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) + rc = add_partition(cxt, res, pa); + } else { + char hint[BUFSIZ]; + struct fdisk_ask *ask; + int c; + + /* the default layout for scripts is to create primary partitions */ + if (cxt->script) { + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) + rc = add_partition(cxt, res, pa); + goto done; + } + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + fdisk_ask_set_type(ask, FDISK_ASKTYPE_MENU); + fdisk_ask_set_query(ask, _("Partition type")); + fdisk_ask_menu_set_default(ask, free_primary == 1 + && !l->ext_offset ? 'e' : 'p'); + snprintf(hint, sizeof(hint), + _("%zu primary, %d extended, %zu free"), + 4 - (l->ext_offset ? 1 : 0) - free_primary, + l->ext_offset ? 1 : 0, + free_primary); + + fdisk_ask_menu_add_item(ask, 'p', _("primary"), hint); + if (!l->ext_offset) + fdisk_ask_menu_add_item(ask, 'e', _("extended"), _("container for logical partitions")); + else + fdisk_ask_menu_add_item(ask, 'l', _("logical"), _("numbered from 5")); + + rc = fdisk_do_ask(cxt, ask); + if (rc) + return rc; + fdisk_ask_menu_get_result(ask, &c); + fdisk_unref_ask(ask); + + if (c == 'p') { + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) + rc = add_partition(cxt, res, pa); + goto done; + } else if (c == 'l' && l->ext_offset) { + rc = add_logical(cxt, pa, &res); + goto done; + } else if (c == 'e' && !l->ext_offset) { + rc = get_partition_unused_primary(cxt, pa, &res); + if (rc == 0) { + struct fdisk_partition *xpa = NULL; + struct fdisk_parttype *t; + + t = fdisk_label_get_parttype_from_code(cxt->label, + MBR_DOS_EXTENDED_PARTITION); + if (!pa) { + pa = xpa = fdisk_new_partition(); + if (!xpa) + return -ENOMEM; + } + fdisk_partition_set_type(pa, t); + rc = add_partition(cxt, res, pa); + if (xpa) { + fdisk_unref_partition(xpa); + pa = NULL; + } + } + goto done; + } else + fdisk_warnx(cxt, _("Invalid partition type `%c'."), c); + } +done: + if (rc == 0) { + cxt->label->nparts_cur++; + if (partno) + *partno = res; + } + return rc; +} + +static int write_sector(struct fdisk_context *cxt, fdisk_sector_t secno, + unsigned char *buf) +{ + int rc; + + rc = seek_sector(cxt, secno); + if (rc != 0) { + fdisk_warn(cxt, _("Cannot write sector %jd: seek failed"), + (uintmax_t) secno); + return rc; + } + + DBG(LABEL, ul_debug("DOS: writting to sector %ju", (uintmax_t) secno)); + + if (write(cxt->dev_fd, buf, cxt->sector_size) != (ssize_t) cxt->sector_size) + return -errno; + return 0; +} + +static int dos_write_disklabel(struct fdisk_context *cxt) +{ + struct fdisk_dos_label *l = self_label(cxt); + size_t i; + int rc = 0, mbr_changed = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + mbr_changed = l->non_pt_changed; + + /* MBR (primary partitions) */ + if (!mbr_changed) { + for (i = 0; i < 4; i++) { + struct pte *pe = self_pte(cxt, i); + if (pe->changed) + mbr_changed = 1; + } + } + if (mbr_changed) { + mbr_set_magic(cxt->firstsector); + rc = write_sector(cxt, 0, cxt->firstsector); + if (rc) + goto done; + } + + if (cxt->label->nparts_max <= 4 && l->ext_offset) { + /* we have empty extended partition, check if the partition has + * been modified and then cleanup possible remaining EBR */ + struct pte *pe = self_pte(cxt, l->ext_index); + unsigned char empty[512] = { 0 }; + fdisk_sector_t off = pe ? get_abs_partition_start(pe) : 0; + + if (off && pe->changed) { + mbr_set_magic(empty); + write_sector(cxt, off, empty); + } + } + + /* EBR (logical partitions) */ + for (i = 4; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + + if (!pe->changed || !pe->offset || !pe->sectorbuffer) + continue; + + mbr_set_magic(pe->sectorbuffer); + rc = write_sector(cxt, pe->offset, pe->sectorbuffer); + if (rc) + goto done; + } + +done: + return rc; +} + +static int dos_locate_disklabel(struct fdisk_context *cxt, int n, + const char **name, off_t *offset, size_t *size) +{ + assert(cxt); + + *name = NULL; + *offset = 0; + *size = 0; + + switch (n) { + case 0: + *name = "MBR"; + *offset = 0; + *size = 512; + break; + default: + /* extended partitions */ + if (n - 1 + 4 < cxt->label->nparts_max) { + struct pte *pe = self_pte(cxt, n - 1 + 4); + + assert(pe->private_sectorbuffer); + + *name = "EBR"; + *offset = pe->offset * cxt->sector_size; + *size = 512; + } else + return 1; + break; + } + + return 0; +} + +/* + * Check whether partition entries are ordered by their starting positions. + * Return 0 if OK. Return i if partition i should have been earlier. + * Two separate checks: primary and logical partitions. + */ +static int wrong_p_order(struct fdisk_context *cxt, size_t *prev) +{ + size_t last_p_start_pos = 0, p_start_pos; + size_t i, last_i = 0; + + for (i = 0 ; i < cxt->label->nparts_max; i++) { + + struct pte *pe = self_pte(cxt, i); + struct dos_partition *p = pe->pt_entry; + + if (i == 4) { + last_i = 4; + last_p_start_pos = 0; + } + if (is_used_partition(p)) { + p_start_pos = get_abs_partition_start(pe); + + if (last_p_start_pos > p_start_pos) { + if (prev) + *prev = last_i; + return i; + } + + last_p_start_pos = p_start_pos; + last_i = i; + } + } + return 0; +} + +static int dos_list_disklabel(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + return 0; +} + +static int dos_get_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct dos_partition *p; + struct pte *pe; + struct fdisk_dos_label *lb; + + assert(cxt); + assert(pa); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + lb = self_label(cxt); + pe = self_pte(cxt, n); + p = pe->pt_entry; + pa->used = !is_cleared_partition(p); + if (!pa->used) + return 0; + + pa->type = dos_partition_parttype(cxt, p); + pa->boot = p->boot_ind == ACTIVE_FLAG ? 1 : 0; + pa->start = get_abs_partition_start(pe); + pa->size = dos_partition_get_size(p); + pa->container = lb->ext_offset && n == lb->ext_index; + + if (n >= 4) + pa->parent_partno = lb->ext_index; + + if (p->boot_ind && asprintf(&pa->attrs, "%02x", p->boot_ind) < 0) + return -ENOMEM; + + /* start C/H/S */ + if (asprintf(&pa->start_chs, "%d/%d/%d", + cylinder(p->bs, p->bc), + sector(p->bs), + p->bh) < 0) + return -ENOMEM; + + /* end C/H/S */ + if (asprintf(&pa->end_chs, "%d/%d/%d", + cylinder(p->es, p->ec), + sector(p->es), + p->eh) < 0) + return -ENOMEM; + + return 0; +} + +static int dos_set_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct fdisk_dos_label *l; + struct dos_partition *p; + struct pte *pe; + fdisk_sector_t start, size; + + assert(cxt); + assert(pa); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + if (n >= cxt->label->nparts_max) + return -EINVAL; + + if (pa->type && IS_EXTENDED(pa->type->code)) { + fdisk_warnx(cxt, _("You cannot change a partition into an " + "extended one or vice versa. Delete it first.")); + return -EINVAL; + } + + if (pa->type && !pa->type->code) + fdisk_warnx(cxt, _("Type 0 means free space to many systems. " + "Having partitions of type 0 is probably unwise.")); + l = self_label(cxt); + p = self_partition(cxt, n); + pe = self_pte(cxt, n); + + FDISK_INIT_UNDEF(start); + FDISK_INIT_UNDEF(size); + + if (fdisk_partition_has_start(pa)) + start = pa->start; + if (fdisk_partition_has_size(pa)) + size = pa->size; + + if (pa->end_follow_default) { + fdisk_sector_t first[cxt->label->nparts_max], + last[cxt->label->nparts_max], + xlast; + struct pte *ext = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + fill_bounds(cxt, first, last); + + if (ext && l->ext_offset) { + first[l->ext_index] = l->ext_offset; + last[l->ext_index] = get_abs_partition_end(ext); + } + if (FDISK_IS_UNDEF(start)) + start = get_abs_partition_start(pe); + + DBG(LABEL, ul_debug("DOS: #%zu now %ju +%ju sectors", + n, (uintmax_t) start, (uintmax_t) dos_partition_get_size(p))); + + xlast = get_unused_last(cxt, n, start, first, last); + size = xlast ? xlast - start + 1: dos_partition_get_size(p); + + DBG(LABEL, ul_debug("DOS: #%zu wanted %ju +%ju sectors", + n, (uintmax_t) start, (uintmax_t) size)); + } + + if (!FDISK_IS_UNDEF(start) || !FDISK_IS_UNDEF(size)) { + DBG(LABEL, ul_debug("DOS: resize partition")); + + if (FDISK_IS_UNDEF(start)) + start = get_abs_partition_start(pe); + if (FDISK_IS_UNDEF(size)) + size = dos_partition_get_size(p); + + set_partition(cxt, n, 0, start, start + size - 1, + pa->type ? pa->type->code : p->sys_ind, + pa->boot == 1); + } else { + DBG(LABEL, ul_debug("DOS: keep size, modify properties")); + if (pa->type) + p->sys_ind = pa->type->code; + if (!FDISK_IS_UNDEF(pa->boot)) + p->boot_ind = pa->boot == 1 ? ACTIVE_FLAG : 0; + } + + partition_set_changed(cxt, n, 1); + return 0; +} + +static void print_chain_of_logicals(struct fdisk_context *cxt) +{ + size_t i; + struct fdisk_dos_label *l = self_label(cxt); + + fputc('\n', stdout); + + for (i = 4; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + + fprintf(stderr, "#%02zu EBR [%10ju], " + "data[start=%10ju (%10ju), size=%10ju], " + "link[start=%10ju (%10ju), size=%10ju]\n", + i, (uintmax_t) pe->offset, + /* data */ + (uintmax_t) dos_partition_get_start(pe->pt_entry), + (uintmax_t) get_abs_partition_start(pe), + (uintmax_t) dos_partition_get_size(pe->pt_entry), + /* link */ + (uintmax_t) dos_partition_get_start(pe->ex_entry), + (uintmax_t) l->ext_offset + dos_partition_get_start(pe->ex_entry), + (uintmax_t) dos_partition_get_size(pe->ex_entry)); + } +} + +static int cmp_ebr_offsets(const void *a, const void *b) +{ + struct pte *ae = (struct pte *) a, + *be = (struct pte *) b; + + if (ae->offset == 0 && be->offset == 0) + return 0; + if (ae->offset == 0) + return 1; + if (be->offset == 0) + return -1; + + return cmp_numbers(ae->offset, be->offset); +} + +/* + * Fix the chain of logicals. + * + * The function does not modify data partitions within EBR tables + * (pte->pt_entry). It sorts the chain by EBR offsets and then update links + * (pte->ex_entry) between EBR tables. + * + */ +static void fix_chain_of_logicals(struct fdisk_context *cxt) +{ + struct fdisk_dos_label *l = self_label(cxt); + struct pte *last; + size_t i; + + DBG(LABEL, print_chain_of_logicals(cxt)); + + /* Sort chain by EBR offsets */ + qsort(&l->ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte), + cmp_ebr_offsets); + +again: + /* Sort data partitions by start */ + for (i = 4; i < cxt->label->nparts_max - 1; i++) { + struct pte *cur = self_pte(cxt, i), + *nxt = self_pte(cxt, i + 1); + + if (get_abs_partition_start(cur) > + get_abs_partition_start(nxt)) { + + struct dos_partition tmp = *cur->pt_entry; + fdisk_sector_t cur_start = get_abs_partition_start(cur), + nxt_start = get_abs_partition_start(nxt); + + /* swap data partitions */ + *cur->pt_entry = *nxt->pt_entry; + *nxt->pt_entry = tmp; + + /* Recount starts according to EBR offsets, the absolute + * address tas to be still the same! */ + dos_partition_set_start(cur->pt_entry, nxt_start - cur->offset); + dos_partition_set_start(nxt->pt_entry, cur_start - nxt->offset); + + partition_set_changed(cxt, i, 1); + partition_set_changed(cxt, i + 1, 1); + goto again; + } + } + + /* Update EBR links */ + for (i = 4; i < cxt->label->nparts_max - 1; i++) { + struct pte *cur = self_pte(cxt, i), + *nxt = self_pte(cxt, i + 1); + + fdisk_sector_t noff = nxt->offset - l->ext_offset, + ooff = dos_partition_get_start(cur->ex_entry); + + if (noff == ooff) + continue; + + DBG(LABEL, ul_debug("DOS: fix EBR [%10ju] link %ju -> %ju", + (uintmax_t) cur->offset, + (uintmax_t) ooff, (uintmax_t) noff)); + + set_partition(cxt, i, 1, nxt->offset, + get_abs_partition_end(nxt), + MBR_DOS_EXTENDED_PARTITION, 0); + } + + /* always terminate the chain ! */ + last = self_pte(cxt, cxt->label->nparts_max - 1); + if (last) { + clear_partition(last->ex_entry); + partition_set_changed(cxt, cxt->label->nparts_max - 1, 1); + } + + DBG(LABEL, print_chain_of_logicals(cxt)); +} + +static int dos_reorder(struct fdisk_context *cxt) +{ + struct pte *pei, *pek; + size_t i,k; + + if (!wrong_p_order(cxt, NULL)) { + fdisk_info(cxt, _("Nothing to do. Ordering is correct already.")); + return 0; + } + + while ((i = wrong_p_order(cxt, &k)) != 0 && i < 4) { + /* partition i should have come earlier, move it */ + /* We have to move data in the MBR */ + struct dos_partition *pi, *pk, *pe, pbuf; + pei = self_pte(cxt, i); + pek = self_pte(cxt, k); + + pe = pei->ex_entry; + pei->ex_entry = pek->ex_entry; + pek->ex_entry = pe; + + pi = pei->pt_entry; + pk = pek->pt_entry; + + memmove(&pbuf, pi, sizeof(struct dos_partition)); + memmove(pi, pk, sizeof(struct dos_partition)); + memmove(pk, &pbuf, sizeof(struct dos_partition)); + + partition_set_changed(cxt, i, 1); + partition_set_changed(cxt, k, 1); + } + + if (i) + fix_chain_of_logicals(cxt); + + fdisk_info(cxt, _("Done.")); + return 0; +} + +/* TODO: use fdisk_set_partition() API */ +int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i) +{ + struct pte *pe; + struct dos_partition *p; + unsigned int new, free_start, curr_start, last; + uintmax_t res = 0; + size_t x; + int rc; + + assert(cxt); + assert(fdisk_is_label(cxt, DOS)); + + pe = self_pte(cxt, i); + p = pe->pt_entry; + + if (!is_used_partition(p) || IS_EXTENDED (p->sys_ind)) { + fdisk_warnx(cxt, _("Partition %zu: no data area."), i + 1); + return 0; + } + + /* the default start is at the second sector of the disk or at the + * second sector of the extended partition + */ + free_start = pe->offset ? pe->offset + 1 : 1; + + curr_start = get_abs_partition_start(pe); + + /* look for a free space before the current start of the partition */ + for (x = 0; x < cxt->label->nparts_max; x++) { + unsigned int end; + struct pte *prev_pe = self_pte(cxt, x); + struct dos_partition *prev_p = prev_pe->pt_entry; + + if (!prev_p) + continue; + end = get_abs_partition_start(prev_pe) + + dos_partition_get_size(prev_p); + + if (is_used_partition(prev_p) && + end > free_start && end <= curr_start) + free_start = end; + } + + last = get_abs_partition_end(pe); + + rc = fdisk_ask_number(cxt, free_start, curr_start, last, + _("New beginning of data"), &res); + if (rc) + return rc; + + new = res - pe->offset; + + if (new != dos_partition_get_size(p)) { + unsigned int sects = dos_partition_get_size(p) + + dos_partition_get_start(p) - new; + + dos_partition_set_size(p, sects); + dos_partition_set_start(p, new); + + partition_set_changed(cxt, i, 1); + } + + return rc; +} + +static int dos_partition_is_used( + struct fdisk_context *cxt, + size_t i) +{ + struct dos_partition *p; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + if (i >= cxt->label->nparts_max) + return 0; + + p = self_partition(cxt, i); + + return p && !is_cleared_partition(p); +} + +static int dos_toggle_partition_flag( + struct fdisk_context *cxt, + size_t i, + unsigned long flag) +{ + struct dos_partition *p; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, DOS)); + + if (i >= cxt->label->nparts_max) + return -EINVAL; + + p = self_partition(cxt, i); + + switch (flag) { + case DOS_FLAG_ACTIVE: + if (IS_EXTENDED(p->sys_ind) && !p->boot_ind) + fdisk_warnx(cxt, _("Partition %zu: is an extended " + "partition."), i + 1); + + p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG); + partition_set_changed(cxt, i, 1); + fdisk_info(cxt, p->boot_ind ? + _("The bootable flag on partition %zu is enabled now.") : + _("The bootable flag on partition %zu is disabled now."), + i + 1); + break; + default: + return 1; + } + + return 0; +} + +static const struct fdisk_field dos_fields[] = +{ + /* basic */ + { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 }, + { FDISK_FIELD_BOOT, N_("Boot"), 1, 0 }, + { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY }, + { FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_TYPE, N_("Type"), 0.1, 0 }, + + /* expert mode */ + { FDISK_FIELD_SADDR, N_("Start-C/H/S"), 1, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL }, + { FDISK_FIELD_EADDR, N_("End-C/H/S"), 1, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL }, + { FDISK_FIELD_ATTR, N_("Attrs"), 2, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_DETAIL } + +}; + +static const struct fdisk_label_operations dos_operations = +{ + .probe = dos_probe_label, + .write = dos_write_disklabel, + .verify = dos_verify_disklabel, + .create = dos_create_disklabel, + .locate = dos_locate_disklabel, + .list = dos_list_disklabel, + .reorder = dos_reorder, + .get_id = dos_get_disklabel_id, + .set_id = dos_set_disklabel_id, + + .get_part = dos_get_partition, + .set_part = dos_set_partition, + .add_part = dos_add_partition, + .del_part = dos_delete_partition, + + .part_toggle_flag = dos_toggle_partition_flag, + .part_is_used = dos_partition_is_used, + + .reset_alignment = dos_reset_alignment, + + .deinit = dos_deinit, +}; + +/* + * allocates DOS in-memory stuff + */ +struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + struct fdisk_dos_label *dos; + + assert(cxt); + + dos = calloc(1, sizeof(*dos)); + if (!dos) + return NULL; + + /* initialize generic part of the driver */ + lb = (struct fdisk_label *) dos; + lb->name = "dos"; + lb->id = FDISK_DISKLABEL_DOS; + lb->op = &dos_operations; + lb->parttypes = dos_parttypes; + lb->nparttypes = ARRAY_SIZE(dos_parttypes) - 1; + lb->fields = dos_fields; + lb->nfields = ARRAY_SIZE(dos_fields); + + return lb; +} + +/** + * fdisk_dos_enable_compatible: + * @lb: DOS label (see fdisk_get_label()) + * @enable: 0 or 1 + * + * Enables deprecated DOS compatible mode, in this mode library checks for + * cylinders boundary, cases about CHS addressing and another obscure things. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable) +{ + struct fdisk_dos_label *dos = (struct fdisk_dos_label *) lb; + + if (!lb) + return -EINVAL; + + dos->compatible = enable; + if (enable) + lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY; + return 0; +} + +/** + * fdisk_dos_is_compatible: + * @lb: DOS label + * + * Returns: 0 if DOS compatibility disabled, 1 if enabled + */ +int fdisk_dos_is_compatible(struct fdisk_label *lb) +{ + return ((struct fdisk_dos_label *) lb)->compatible; +} diff --git a/libblkid/libfdisk/src/fdiskP.h b/libblkid/libfdisk/src/fdiskP.h new file mode 100644 index 000000000..b169a9ffb --- /dev/null +++ b/libblkid/libfdisk/src/fdiskP.h @@ -0,0 +1,438 @@ +/* + * fdiskP.h - private library header file + * + * Copyright (C) 2012 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#ifndef _LIBFDISK_PRIVATE_H +#define _LIBFDISK_PRIVATE_H + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + + +#include "c.h" +#include "libfdisk.h" + +#include "nls.h" /* temporary before dialog API will be implamented */ +#include "list.h" +#include "debug.h" +#include <stdio.h> +#include <stdarg.h> + +/* features */ +#define CONFIG_LIBFDISK_ASSERT + +#ifdef CONFIG_LIBFDISK_ASSERT +#include <assert.h> +#endif + +/* + * Debug + */ +#define LIBFDISK_DEBUG_HELP (1 << 0) +#define LIBFDISK_DEBUG_INIT (1 << 1) +#define LIBFDISK_DEBUG_CXT (1 << 2) +#define LIBFDISK_DEBUG_LABEL (1 << 3) +#define LIBFDISK_DEBUG_ASK (1 << 4) +#define LIBFDISK_DEBUG_PART (1 << 6) +#define LIBFDISK_DEBUG_PARTTYPE (1 << 7) +#define LIBFDISK_DEBUG_TAB (1 << 8) +#define LIBFDISK_DEBUG_SCRIPT (1 << 9) +#define LIBFDISK_DEBUG_ALL 0xFFFF + +UL_DEBUG_DECLARE_MASK(libfdisk); +#define DBG(m, x) __UL_DBG(libfdisk, LIBFDISK_DEBUG_, m, x) +#define ON_DBG(m, x) __UL_DBG_CALL(libfdisk, LIBFDISK_DEBUG_, m, x) +#define DBG_FLUSH __UL_DBG_FLUSH(libfdisk, LIBFDISK_DEBUG_) + +#ifdef TEST_PROGRAM +struct fdisk_test { + const char *name; + int (*body)(struct fdisk_test *ts, int argc, char *argv[]); + const char *usage; +}; + +/* test.c */ +extern int fdisk_run_test(struct fdisk_test *tests, int argc, char *argv[]); +#endif + + +/* + * Generic iterator + */ +struct fdisk_iter { + struct list_head *p; /* current position */ + struct list_head *head; /* start position */ + int direction; /* FDISK_ITER_{FOR,BACK}WARD */ +}; + +#define IS_ITER_FORWARD(_i) ((_i)->direction == FDISK_ITER_FORWARD) +#define IS_ITER_BACKWARD(_i) ((_i)->direction == FDISK_ITER_BACKWARD) + +#define FDISK_ITER_INIT(itr, list) \ + do { \ + (itr)->p = IS_ITER_FORWARD(itr) ? \ + (list)->next : (list)->prev; \ + (itr)->head = (list); \ + } while(0) + +#define FDISK_ITER_ITERATE(itr, res, restype, member) \ + do { \ + res = list_entry((itr)->p, restype, member); \ + (itr)->p = IS_ITER_FORWARD(itr) ? \ + (itr)->p->next : (itr)->p->prev; \ + } while(0) + +/* + * Partition types + */ +struct fdisk_parttype { + unsigned int code; /* type as number or zero */ + char *name; /* description */ + char *typestr; /* type as string or NULL */ + + unsigned int flags; /* FDISK_PARTTYPE_* flags */ + int refcount; /* reference counter for allocated types */ +}; + +enum { + FDISK_PARTTYPE_UNKNOWN = (1 << 1), + FDISK_PARTTYPE_INVISIBLE = (1 << 2), + FDISK_PARTTYPE_ALLOCATED = (1 << 3) +}; + +#define fdisk_parttype_is_invisible(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_INVISIBLE)) +#define fdisk_parttype_is_allocated(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_ALLOCATED)) + +struct fdisk_partition { + int refcount; /* reference counter */ + + size_t partno; /* partition number */ + size_t parent_partno; /* for logical partitions */ + + fdisk_sector_t start; /* first sectors */ + fdisk_sector_t size; /* size in sectors */ + + char *name; /* partition name */ + char *uuid; /* partition UUID */ + char *attrs; /* partition flags/attributes converted to string */ + struct fdisk_parttype *type; /* partition type */ + + struct list_head parts; /* list of partitions */ + + /* extra fields for partition_to_string() */ + char start_post; /* start postfix (e.g. '+') */ + char end_post; /* end postfix */ + char size_post; /* size postfix */ + + uint64_t fsize; /* bsd junk */ + uint64_t bsize; + uint64_t cpg; + + char *start_chs; /* start C/H/S in string */ + char *end_chs; /* end C/H/S in string */ + + unsigned int boot; /* MBR: bootable */ + + unsigned int container : 1, /* container partition (e.g. extended partition) */ + end_follow_default : 1, /* use default end */ + freespace : 1, /* this is free space */ + partno_follow_default : 1, /* use default partno */ + size_explicit : 1, /* don't align the size */ + start_follow_default : 1, /* use default start */ + used : 1, /* partition already used */ + wholedisk : 1; /* special system partition */ +}; + +#define FDISK_INIT_UNDEF(_x) ((_x) = (__typeof__(_x)) -1) +#define FDISK_IS_UNDEF(_x) ((_x) == (__typeof__(_x)) -1) + +struct fdisk_table { + struct list_head parts; /* partitions */ + int refcount; + size_t nents; /* number of partitions */ +}; + +/* + * Legacy CHS based geometry + */ +struct fdisk_geometry { + unsigned int heads; + fdisk_sector_t sectors; + fdisk_sector_t cylinders; +}; + +/* + * Label specific operations + */ +struct fdisk_label_operations { + /* probe disk label */ + int (*probe)(struct fdisk_context *cxt); + /* write in-memory changes to disk */ + int (*write)(struct fdisk_context *cxt); + /* verify the partition table */ + int (*verify)(struct fdisk_context *cxt); + /* create new disk label */ + int (*create)(struct fdisk_context *cxt); + /* list disklabel details */ + int (*list)(struct fdisk_context *cxt); + /* returns offset and size of the 'n' part of the PT */ + int (*locate)(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size); + /* reorder partitions */ + int (*reorder)(struct fdisk_context *cxt); + + /* get disk label ID */ + int (*get_id)(struct fdisk_context *cxt, char **id); + /* set disk label ID */ + int (*set_id)(struct fdisk_context *cxt); + + + /* new partition */ + int (*add_part)(struct fdisk_context *cxt, struct fdisk_partition *pa, + size_t *partno); + /* delete partition */ + int (*del_part)(struct fdisk_context *cxt, size_t partnum); + + /* fill in partition struct */ + int (*get_part)(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa); + /* modify partition */ + int (*set_part)(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa); + + /* return state of the partition */ + int (*part_is_used)(struct fdisk_context *cxt, size_t partnum); + + int (*part_toggle_flag)(struct fdisk_context *cxt, size_t i, unsigned long flag); + + /* refresh alignment setting */ + int (*reset_alignment)(struct fdisk_context *cxt); + + /* free in-memory label stuff */ + void (*free)(struct fdisk_label *lb); + + /* deinit in-memory label stuff */ + void (*deinit)(struct fdisk_label *lb); +}; + +/* + * The fields describes how to display libfdisk_partition + */ +struct fdisk_field { + int id; /* FDISK_FIELD_* */ + const char *name; /* field name */ + double width; /* field width (compatible with libsmartcols whint) */ + int flags; /* FDISK_FIELDFL_* */ +}; + +/* note that the defauls is to display a column always */ +enum { + FDISK_FIELDFL_DETAIL = (1 << 1), /* only display if fdisk_is_details() */ + FDISK_FIELDFL_EYECANDY = (1 << 2), /* don't display if fdisk_is_details() */ + FDISK_FIELDFL_NUMBER = (1 << 3), /* column display numbers */ +}; + +/* + * Generic label + */ +struct fdisk_label { + const char *name; /* label name */ + enum fdisk_labeltype id; /* FDISK_DISKLABEL_* */ + struct fdisk_parttype *parttypes; /* supported partitions types */ + size_t nparttypes; /* number of items in parttypes[] */ + + size_t nparts_max; /* maximal number of partitions */ + size_t nparts_cur; /* number of currently used partitions */ + + int flags; /* FDISK_LABEL_FL_* flags */ + + unsigned int changed:1, /* label has been modified */ + disabled:1; /* this driver is disabled at all */ + + const struct fdisk_field *fields; /* all possible fields */ + size_t nfields; + + const struct fdisk_label_operations *op; +}; + + +/* label driver flags */ +enum { + FDISK_LABEL_FL_REQUIRE_GEOMETRY = (1 << 2), + FDISK_LABEL_FL_INCHARS_PARTNO = (1 << 3) +}; + +/* label allocators */ +extern struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt); +extern struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt); +extern struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt); +extern struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt); +extern struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt); + + +struct ask_menuitem { + char key; + const char *name; + const char *desc; + + struct ask_menuitem *next; +}; + +/* fdisk dialog -- note that nothing from this stuff will be directly exported, + * we will have get/set() function for everything. + */ +struct fdisk_ask { + int type; /* FDISK_ASKTYPE_* */ + char *query; + + int refcount; + + union { + /* FDISK_ASKTYPE_{NUMBER,OFFSET} */ + struct ask_number { + uint64_t hig; /* high limit */ + uint64_t low; /* low limit */ + uint64_t dfl; /* default */ + uint64_t result; + uint64_t base; /* for relative results */ + uint64_t unit; /* unit for offsets */ + const char *range; /* by library generated list */ + unsigned int relative :1, + inchars :1; + } num; + /* FDISK_ASKTYPE_{WARN,WARNX,..} */ + struct ask_print { + const char *mesg; + int errnum; /* errno */ + } print; + /* FDISK_ASKTYPE_YESNO */ + struct ask_yesno { + int result; /* TRUE or FALSE */ + } yesno; + /* FDISK_ASKTYPE_STRING */ + struct ask_string { + char *result; /* allocated */ + } str; + /* FDISK_ASKTYPE_MENU */ + struct ask_menu { + int dfl; /* default meni item */ + int result; + struct ask_menuitem *first; + } menu; + } data; +}; + +struct fdisk_context { + int dev_fd; /* device descriptor */ + char *dev_path; /* device path */ + int refcount; + + unsigned char *firstsector; /* buffer with master boot record */ + unsigned long firstsector_bufsz; + + /* topology */ + unsigned long io_size; /* I/O size used by fdisk */ + unsigned long optimal_io_size; /* optional I/O returned by device */ + unsigned long min_io_size; /* minimal I/O size */ + unsigned long phy_sector_size; /* physical size */ + unsigned long sector_size; /* logical size */ + unsigned long alignment_offset; + + unsigned int readonly : 1, /* don't write to the device */ + display_in_cyl_units : 1, /* for obscure labels */ + display_details : 1, /* expert display mode */ + listonly : 1; /* list partition, nothing else */ + + /* alignment */ + unsigned long grain; /* alignment unit */ + fdisk_sector_t first_lba; /* recommended begin of the first partition */ + fdisk_sector_t last_lba; /* recomennded end of last partition */ + + /* geometry */ + fdisk_sector_t total_sectors; /* in logical sectors */ + struct fdisk_geometry geom; + + /* user setting to overwrite device default */ + struct fdisk_geometry user_geom; + unsigned long user_pyh_sector; + unsigned long user_log_sector; + + struct fdisk_label *label; /* current label, pointer to labels[] */ + + size_t nlabels; /* number of initialized label drivers */ + struct fdisk_label *labels[8]; /* all supported labels, + * FIXME: use any enum rather than hardcoded number */ + + int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *); /* fdisk dialogs callback */ + void *ask_data; /* ask_cb() data */ + + struct fdisk_context *parent; /* for nested PT */ + struct fdisk_script *script; /* what we want to follow */ +}; + +/* partition.c */ +int fdisk_partition_next_partno(struct fdisk_partition *pa, + struct fdisk_context *cxt, + size_t *n); + +/* context.c */ +extern int __fdisk_switch_label(struct fdisk_context *cxt, + struct fdisk_label *lb); +extern int fdisk_missing_geometry(struct fdisk_context *cxt); + +/* alignment.c */ +fdisk_sector_t fdisk_scround(struct fdisk_context *cxt, fdisk_sector_t num); +fdisk_sector_t fdisk_cround(struct fdisk_context *cxt, fdisk_sector_t num); + +extern int fdisk_discover_geometry(struct fdisk_context *cxt); +extern int fdisk_discover_topology(struct fdisk_context *cxt); + +extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt); +extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt); + +/* utils.c */ +extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt); +extern int fdisk_read_firstsector(struct fdisk_context *cxt); +extern char *fdisk_partname(const char *dev, size_t partno); + +/* label.c */ +extern int fdisk_probe_labels(struct fdisk_context *cxt); +extern void fdisk_deinit_label(struct fdisk_label *lb); + +/* ask.c */ +struct fdisk_ask *fdisk_new_ask(void); +void fdisk_reset_ask(struct fdisk_ask *ask); +int fdisk_ask_set_query(struct fdisk_ask *ask, const char *str); +int fdisk_ask_set_type(struct fdisk_ask *ask, int type); +int fdisk_do_ask(struct fdisk_context *cxt, struct fdisk_ask *ask); +int fdisk_ask_number_set_range(struct fdisk_ask *ask, const char *range); +int fdisk_ask_number_set_default(struct fdisk_ask *ask, uint64_t dflt); +int fdisk_ask_number_set_low(struct fdisk_ask *ask, uint64_t low); +int fdisk_ask_number_set_high(struct fdisk_ask *ask, uint64_t high); +int fdisk_ask_number_set_base(struct fdisk_ask *ask, uint64_t base); +int fdisk_ask_number_set_unit(struct fdisk_ask *ask, uint64_t unit); +int fdisk_ask_number_is_relative(struct fdisk_ask *ask); +int fdisk_ask_menu_set_default(struct fdisk_ask *ask, int dfl); +int fdisk_ask_menu_add_item(struct fdisk_ask *ask, int key, + const char *name, const char *desc); +int fdisk_ask_print_set_errno(struct fdisk_ask *ask, int errnum); +int fdisk_ask_print_set_mesg(struct fdisk_ask *ask, const char *mesg); +int fdisk_info_new_partition( + struct fdisk_context *cxt, + int num, fdisk_sector_t start, fdisk_sector_t stop, + struct fdisk_parttype *t); + +/* dos.c */ +extern struct dos_partition *fdisk_dos_get_partition( + struct fdisk_context *cxt, + size_t i); + +#endif /* _LIBFDISK_PRIVATE_H */ diff --git a/libblkid/libfdisk/src/gpt.c b/libblkid/libfdisk/src/gpt.c new file mode 100644 index 000000000..8c1c96c37 --- /dev/null +++ b/libblkid/libfdisk/src/gpt.c @@ -0,0 +1,2565 @@ +/* + * Copyright (C) 2007 Karel Zak <kzak@redhat.com> + * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org> + * + * GUID Partition Table (GPT) support. Based on UEFI Specs 2.3.1 + * Chapter 5: GUID Partition Table (GPT) Disk Layout (Jun 27th, 2012). + * Some ideas and inspiration from GNU parted and gptfdisk. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <sys/stat.h> +#include <sys/utsname.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <uuid.h> + +#include "fdiskP.h" + +#include "nls.h" +#include "crc32.h" +#include "blkdev.h" +#include "bitops.h" +#include "strutils.h" +#include "all-io.h" + +/** + * SECTION: gpt + * @title: UEFI GPT + * @short_description: specific functionality + */ + +#define GPT_HEADER_SIGNATURE 0x5452415020494645LL /* EFI PART */ +#define GPT_HEADER_REVISION_V1_02 0x00010200 +#define GPT_HEADER_REVISION_V1_00 0x00010000 +#define GPT_HEADER_REVISION_V0_99 0x00009900 +#define GPT_HEADER_MINSZ 92 /* bytes */ + +#define GPT_PMBR_LBA 0 +#define GPT_MBR_PROTECTIVE 1 +#define GPT_MBR_HYBRID 2 + +#define GPT_PRIMARY_PARTITION_TABLE_LBA 0x00000001 + +#define EFI_PMBR_OSTYPE 0xEE +#define MSDOS_MBR_SIGNATURE 0xAA55 +#define GPT_PART_NAME_LEN (72 / sizeof(uint16_t)) +#define GPT_NPARTITIONS 128 + +/* Globally unique identifier */ +struct gpt_guid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi; + uint8_t clock_seq_low; + uint8_t node[6]; +}; + + +/* only checking that the GUID is 0 is enough to verify an empty partition. */ +#define GPT_UNUSED_ENTRY_GUID \ + ((struct gpt_guid) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}) + +/* Linux native partition type */ +#define GPT_DEFAULT_ENTRY_TYPE "0FC63DAF-8483-4772-8E79-3D69D8477DE4" + +/* + * Attribute bits + */ +enum { + /* UEFI specific */ + GPT_ATTRBIT_REQ = 0, + GPT_ATTRBIT_NOBLOCK = 1, + GPT_ATTRBIT_LEGACY = 2, + + /* GUID specific (range 48..64)*/ + GPT_ATTRBIT_GUID_FIRST = 48, + GPT_ATTRBIT_GUID_COUNT = 16 +}; + +#define GPT_ATTRSTR_REQ "RequiredPartiton" +#define GPT_ATTRSTR_NOBLOCK "NoBlockIOProtocol" +#define GPT_ATTRSTR_LEGACY "LegacyBIOSBootable" + +/* The GPT Partition entry array contains an array of GPT entries. */ +struct gpt_entry { + struct gpt_guid type; /* purpose and type of the partition */ + struct gpt_guid partition_guid; + uint64_t lba_start; + uint64_t lba_end; + uint64_t attrs; + uint16_t name[GPT_PART_NAME_LEN]; +} __attribute__ ((packed)); + +/* GPT header */ +struct gpt_header { + uint64_t signature; /* header identification */ + uint32_t revision; /* header version */ + uint32_t size; /* in bytes */ + uint32_t crc32; /* header CRC checksum */ + uint32_t reserved1; /* must be 0 */ + uint64_t my_lba; /* LBA of block that contains this struct (LBA 1) */ + uint64_t alternative_lba; /* backup GPT header */ + uint64_t first_usable_lba; /* first usable logical block for partitions */ + uint64_t last_usable_lba; /* last usable logical block for partitions */ + struct gpt_guid disk_guid; /* unique disk identifier */ + uint64_t partition_entry_lba; /* LBA of start of partition entries array */ + uint32_t npartition_entries; /* total partition entries - normally 128 */ + uint32_t sizeof_partition_entry; /* bytes for each GUID pt */ + uint32_t partition_entry_array_crc32; /* partition CRC checksum */ + uint8_t reserved2[512 - 92]; /* must all be 0 */ +} __attribute__ ((packed)); + +struct gpt_record { + uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */ + uint8_t start_head; /* unused by EFI, pt start in CHS */ + uint8_t start_sector; /* unused by EFI, pt start in CHS */ + uint8_t start_track; + uint8_t os_type; /* EFI and legacy non-EFI OS types */ + uint8_t end_head; /* unused by EFI, pt end in CHS */ + uint8_t end_sector; /* unused by EFI, pt end in CHS */ + uint8_t end_track; /* unused by EFI, pt end in CHS */ + uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */ + uint32_t size_in_lba; /* used by EFI - size of pt in LBA */ +} __attribute__ ((packed)); + +/* Protected MBR and legacy MBR share same structure */ +struct gpt_legacy_mbr { + uint8_t boot_code[440]; + uint32_t unique_mbr_signature; + uint16_t unknown; + struct gpt_record partition_record[4]; + uint16_t signature; +} __attribute__ ((packed)); + +/* + * Here be dragons! + * See: http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs + */ +#define DEF_GUID(_u, _n) \ + { \ + .typestr = (_u), \ + .name = (_n), \ + } + +static struct fdisk_parttype gpt_parttypes[] = +{ + /* Generic OS */ + DEF_GUID("C12A7328-F81F-11D2-BA4B-00A0C93EC93B", N_("EFI System")), + + DEF_GUID("024DEE41-33E7-11D3-9D69-0008C781F39F", N_("MBR partition scheme")), + DEF_GUID("D3BFE2DE-3DAF-11DF-BA40-E3A556D89593", N_("Intel Fast Flash")), + + /* Hah!IdontneedEFI */ + DEF_GUID("21686148-6449-6E6F-744E-656564454649", N_("BIOS boot")), + + /* Windows */ + DEF_GUID("E3C9E316-0B5C-4DB8-817D-F92DF00215AE", N_("Microsoft reserved")), + DEF_GUID("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", N_("Microsoft basic data")), + DEF_GUID("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", N_("Microsoft LDM metadata")), + DEF_GUID("AF9B60A0-1431-4F62-BC68-3311714A69AD", N_("Microsoft LDM data")), + DEF_GUID("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", N_("Windows recovery environment")), + DEF_GUID("37AFFC90-EF7D-4E96-91C3-2D7AE055B174", N_("IBM General Parallel Fs")), + DEF_GUID("E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D", N_("Microsoft Storage Spaces")), + + /* HP-UX */ + DEF_GUID("75894C1E-3AEB-11D3-B7C1-7B03A0000000", N_("HP-UX data")), + DEF_GUID("E2A1E728-32E3-11D6-A682-7B03A0000000", N_("HP-UX service")), + + /* Linux (http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec) */ + DEF_GUID("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", N_("Linux swap")), + DEF_GUID("0FC63DAF-8483-4772-8E79-3D69D8477DE4", N_("Linux filesystem")), + DEF_GUID("3B8F8425-20E0-4F3B-907F-1A25A76F98E8", N_("Linux server data")), + DEF_GUID("44479540-F297-41B2-9AF7-D131D5F0458A", N_("Linux root (x86)")), + DEF_GUID("4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709", N_("Linux root (x86-64)")), + DEF_GUID("8DA63339-0007-60C0-C436-083AC8230908", N_("Linux reserved")), + DEF_GUID("933AC7E1-2EB4-4F13-B844-0E14E2AEF915", N_("Linux home")), + DEF_GUID("A19D880F-05FC-4D3B-A006-743F0F84911E", N_("Linux RAID")), + DEF_GUID("BC13C2FF-59E6-4262-A352-B275FD6F7172", N_("Linux extended boot")), + DEF_GUID("E6D6D379-F507-44C2-A23C-238F2A3DF928", N_("Linux LVM")), + + /* FreeBSD */ + DEF_GUID("516E7CB4-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD data")), + DEF_GUID("83BD6B9D-7F41-11DC-BE0B-001560B84F0F", N_("FreeBSD boot")), + DEF_GUID("516E7CB5-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD swap")), + DEF_GUID("516E7CB6-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD UFS")), + DEF_GUID("516E7CBA-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD ZFS")), + DEF_GUID("516E7CB8-6ECF-11D6-8FF8-00022D09712B", N_("FreeBSD Vinum")), + + /* Apple OSX */ + DEF_GUID("48465300-0000-11AA-AA11-00306543ECAC", N_("Apple HFS/HFS+")), + DEF_GUID("55465300-0000-11AA-AA11-00306543ECAC", N_("Apple UFS")), + DEF_GUID("52414944-0000-11AA-AA11-00306543ECAC", N_("Apple RAID")), + DEF_GUID("52414944-5F4F-11AA-AA11-00306543ECAC", N_("Apple RAID offline")), + DEF_GUID("426F6F74-0000-11AA-AA11-00306543ECAC", N_("Apple boot")), + DEF_GUID("4C616265-6C00-11AA-AA11-00306543ECAC", N_("Apple label")), + DEF_GUID("5265636F-7665-11AA-AA11-00306543ECAC", N_("Apple TV recovery")), + DEF_GUID("53746F72-6167-11AA-AA11-00306543ECAC", N_("Apple Core storage")), + + /* Solaris */ + DEF_GUID("6A82CB45-1DD2-11B2-99A6-080020736631", N_("Solaris boot")), + DEF_GUID("6A85CF4D-1DD2-11B2-99A6-080020736631", N_("Solaris root")), + /* same as Apple ZFS */ + DEF_GUID("6A898CC3-1DD2-11B2-99A6-080020736631", N_("Solaris /usr & Apple ZFS")), + DEF_GUID("6A87C46F-1DD2-11B2-99A6-080020736631", N_("Solaris swap")), + DEF_GUID("6A8B642B-1DD2-11B2-99A6-080020736631", N_("Solaris backup")), + DEF_GUID("6A8EF2E9-1DD2-11B2-99A6-080020736631", N_("Solaris /var")), + DEF_GUID("6A90BA39-1DD2-11B2-99A6-080020736631", N_("Solaris /home")), + DEF_GUID("6A9283A5-1DD2-11B2-99A6-080020736631", N_("Solaris alternate sector")), + DEF_GUID("6A945A3B-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 1")), + DEF_GUID("6A9630D1-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 2")), + DEF_GUID("6A980767-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 3")), + DEF_GUID("6A96237F-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 4")), + DEF_GUID("6A8D2AC7-1DD2-11B2-99A6-080020736631", N_("Solaris reserved 5")), + + /* NetBSD */ + DEF_GUID("49F48D32-B10E-11DC-B99B-0019D1879648", N_("NetBSD swap")), + DEF_GUID("49F48D5A-B10E-11DC-B99B-0019D1879648", N_("NetBSD FFS")), + DEF_GUID("49F48D82-B10E-11DC-B99B-0019D1879648", N_("NetBSD LFS")), + DEF_GUID("2DB519C4-B10E-11DC-B99B-0019D1879648", N_("NetBSD concatenated")), + DEF_GUID("2DB519EC-B10E-11DC-B99B-0019D1879648", N_("NetBSD encrypted")), + DEF_GUID("49F48DAA-B10E-11DC-B99B-0019D1879648", N_("NetBSD RAID")), + + /* ChromeOS */ + DEF_GUID("FE3A2A5D-4F32-41A7-B725-ACCC3285A309", N_("ChromeOS kernel")), + DEF_GUID("3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", N_("ChromeOS root fs")), + DEF_GUID("2E0A753D-9E48-43B0-8337-B15192CB1B5E", N_("ChromeOS reserved")), + + /* MidnightBSD */ + DEF_GUID("85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD data")), + DEF_GUID("85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD boot")), + DEF_GUID("85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD swap")), + DEF_GUID("0394Ef8B-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD UFS")), + DEF_GUID("85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD ZFS")), + DEF_GUID("85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7", N_("MidnightBSD Vinum")), +}; + +/* gpt_entry macros */ +#define gpt_partition_start(_e) le64_to_cpu((_e)->lba_start) +#define gpt_partition_end(_e) le64_to_cpu((_e)->lba_end) + +/* + * in-memory fdisk GPT stuff + */ +struct fdisk_gpt_label { + struct fdisk_label head; /* generic part */ + + /* gpt specific part */ + struct gpt_header *pheader; /* primary header */ + struct gpt_header *bheader; /* backup header */ + struct gpt_entry *ents; /* entries (partitions) */ +}; + +static void gpt_deinit(struct fdisk_label *lb); + +static inline struct fdisk_gpt_label *self_label(struct fdisk_context *cxt) +{ + return (struct fdisk_gpt_label *) cxt->label; +} + +/* + * Returns the partition length, or 0 if end is before beginning. + */ +static uint64_t gpt_partition_size(const struct gpt_entry *e) +{ + uint64_t start = gpt_partition_start(e); + uint64_t end = gpt_partition_end(e); + + return start > end ? 0 : end - start + 1ULL; +} + +/* prints UUID in the real byte order! */ +static void gpt_debug_uuid(const char *mesg, struct gpt_guid *guid) +{ + const unsigned char *uuid = (unsigned char *) guid; + + fprintf(stderr, "%s: " + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + mesg, + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], + uuid[6], uuid[7], + uuid[8], uuid[9], + uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); +} + +/* + * UUID is traditionally 16 byte big-endian array, except Intel EFI + * specification where the UUID is a structure of little-endian fields. + */ +static void swap_efi_guid(struct gpt_guid *uid) +{ + uid->time_low = swab32(uid->time_low); + uid->time_mid = swab16(uid->time_mid); + uid->time_hi_and_version = swab16(uid->time_hi_and_version); +} + +static int string_to_guid(const char *in, struct gpt_guid *guid) +{ + if (uuid_parse(in, (unsigned char *) guid)) /* BE */ + return -1; + swap_efi_guid(guid); /* LE */ + return 0; +} + +static char *guid_to_string(const struct gpt_guid *guid, char *out) +{ + struct gpt_guid u = *guid; /* LE */ + + swap_efi_guid(&u); /* BE */ + uuid_unparse_upper((unsigned char *) &u, out); + + return out; +} + +static struct fdisk_parttype *gpt_partition_parttype( + struct fdisk_context *cxt, + const struct gpt_entry *e) +{ + struct fdisk_parttype *t; + char str[37]; + + guid_to_string(&e->type, str); + t = fdisk_label_get_parttype_from_string(cxt->label, str); + return t ? : fdisk_new_unknown_parttype(0, str); +} + +static void gpt_entry_set_type(struct gpt_entry *e, struct gpt_guid *uuid) +{ + e->type = *uuid; + DBG(LABEL, gpt_debug_uuid("new type", &(e->type))); +} + +static void gpt_entry_set_name(struct gpt_entry *e, char *str) +{ + char name[GPT_PART_NAME_LEN] = { 0 }; + size_t i, sz = strlen(str); + + if (sz) { + if (sz > GPT_PART_NAME_LEN) + sz = GPT_PART_NAME_LEN; + memcpy(name, str, sz); + } + + for (i = 0; i < GPT_PART_NAME_LEN; i++) + e->name[i] = cpu_to_le16((uint16_t) name[i]); +} + +static int gpt_entry_set_uuid(struct gpt_entry *e, char *str) +{ + struct gpt_guid uuid; + int rc; + + rc = string_to_guid(str, &uuid); + if (rc) + return rc; + + e->partition_guid = uuid; + return 0; +} + + +static const char *gpt_get_header_revstr(struct gpt_header *header) +{ + if (!header) + goto unknown; + + switch (header->revision) { + case GPT_HEADER_REVISION_V1_02: + return "1.2"; + case GPT_HEADER_REVISION_V1_00: + return "1.0"; + case GPT_HEADER_REVISION_V0_99: + return "0.99"; + default: + goto unknown; + } + +unknown: + return "unknown"; +} + +static inline int partition_unused(const struct gpt_entry *e) +{ + return !memcmp(&e->type, &GPT_UNUSED_ENTRY_GUID, + sizeof(struct gpt_guid)); +} + +/* + * Builds a clean new valid protective MBR - will wipe out any existing data. + * Returns 0 on success, otherwise < 0 on error. + */ +static int gpt_mknew_pmbr(struct fdisk_context *cxt) +{ + struct gpt_legacy_mbr *pmbr = NULL; + int rc; + + if (!cxt || !cxt->firstsector) + return -ENOSYS; + + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + + pmbr = (struct gpt_legacy_mbr *) cxt->firstsector; + + pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE); + pmbr->partition_record[0].os_type = EFI_PMBR_OSTYPE; + pmbr->partition_record[0].start_sector = 1; + pmbr->partition_record[0].end_head = 0xFE; + pmbr->partition_record[0].end_sector = 0xFF; + pmbr->partition_record[0].end_track = 0xFF; + pmbr->partition_record[0].starting_lba = cpu_to_le32(1); + pmbr->partition_record[0].size_in_lba = + cpu_to_le32(min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF)); + + return 0; +} + +/* some universal differences between the headers */ +static void gpt_mknew_header_common(struct fdisk_context *cxt, + struct gpt_header *header, uint64_t lba) +{ + if (!cxt || !header) + return; + + header->my_lba = cpu_to_le64(lba); + + if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */ + header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1); + header->partition_entry_lba = cpu_to_le64(2); + } else { /* backup */ + uint64_t esz = le32_to_cpu(header->npartition_entries) * sizeof(struct gpt_entry); + uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size; + + header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA); + header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects); + } +} + +/* + * Builds a new GPT header (at sector lba) from a backup header2. + * If building a primary header, then backup is the secondary, and vice versa. + * + * Always pass a new (zeroized) header to build upon as we don't + * explicitly zero-set some values such as CRCs and reserved. + * + * Returns 0 on success, otherwise < 0 on error. + */ +static int gpt_mknew_header_from_bkp(struct fdisk_context *cxt, + struct gpt_header *header, + uint64_t lba, + struct gpt_header *header2) +{ + if (!cxt || !header || !header2) + return -ENOSYS; + + header->signature = header2->signature; + header->revision = header2->revision; + header->size = header2->size; + header->npartition_entries = header2->npartition_entries; + header->sizeof_partition_entry = header2->sizeof_partition_entry; + header->first_usable_lba = header2->first_usable_lba; + header->last_usable_lba = header2->last_usable_lba; + + memcpy(&header->disk_guid, + &header2->disk_guid, sizeof(header2->disk_guid)); + gpt_mknew_header_common(cxt, header, lba); + + return 0; +} + +static struct gpt_header *gpt_copy_header(struct fdisk_context *cxt, + struct gpt_header *src) +{ + struct gpt_header *res; + + if (!cxt || !src) + return NULL; + + res = calloc(1, sizeof(*res)); + if (!res) { + fdisk_warn(cxt, _("failed to allocate GPT header")); + return NULL; + } + + res->my_lba = src->alternative_lba; + res->alternative_lba = src->my_lba; + + res->signature = src->signature; + res->revision = src->revision; + res->size = src->size; + res->npartition_entries = src->npartition_entries; + res->sizeof_partition_entry = src->sizeof_partition_entry; + res->first_usable_lba = src->first_usable_lba; + res->last_usable_lba = src->last_usable_lba; + + memcpy(&res->disk_guid, &src->disk_guid, sizeof(src->disk_guid)); + + + if (res->my_lba == GPT_PRIMARY_PARTITION_TABLE_LBA) + res->partition_entry_lba = cpu_to_le64(2); + else { + uint64_t esz = le32_to_cpu(src->npartition_entries) * sizeof(struct gpt_entry); + uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size; + + res->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects); + } + + return res; +} + +static void count_first_last_lba(struct fdisk_context *cxt, + uint64_t *first, uint64_t *last) +{ + uint64_t esz = 0; + + assert(cxt); + + esz = sizeof(struct gpt_entry) * GPT_NPARTITIONS / cxt->sector_size; + *last = cxt->total_sectors - 2 - esz; + *first = esz + 2; + + if (*first < cxt->first_lba && cxt->first_lba < *last) + /* Align according to topology */ + *first = cxt->first_lba; +} + +/* + * Builds a clean new GPT header (currently under revision 1.0). + * + * Always pass a new (zeroized) header to build upon as we don't + * explicitly zero-set some values such as CRCs and reserved. + * + * Returns 0 on success, otherwise < 0 on error. + */ +static int gpt_mknew_header(struct fdisk_context *cxt, + struct gpt_header *header, uint64_t lba) +{ + uint64_t first, last; + int has_id = 0; + + if (!cxt || !header) + return -ENOSYS; + + header->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); + header->revision = cpu_to_le32(GPT_HEADER_REVISION_V1_00); + header->size = cpu_to_le32(sizeof(struct gpt_header)); + + /* + * 128 partitions are the default. It can go beyond that, but + * we're creating a de facto header here, so no funny business. + */ + header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS); + header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry)); + + count_first_last_lba(cxt, &first, &last); + header->first_usable_lba = cpu_to_le64(first); + header->last_usable_lba = cpu_to_le64(last); + + gpt_mknew_header_common(cxt, header, lba); + + if (cxt->script) { + const char *id = fdisk_script_get_header(cxt->script, "label-id"); + if (id && string_to_guid(id, &header->disk_guid) == 0) + has_id = 1; + } + + if (!has_id) { + uuid_generate_random((unsigned char *) &header->disk_guid); + swap_efi_guid(&header->disk_guid); + } + return 0; +} + +/* + * Checks if there is a valid protective MBR partition table. + * Returns 0 if it is invalid or failure. Otherwise, return + * GPT_MBR_PROTECTIVE or GPT_MBR_HYBRID, depeding on the detection. + */ +static int valid_pmbr(struct fdisk_context *cxt) +{ + int i, part = 0, ret = 0; /* invalid by default */ + struct gpt_legacy_mbr *pmbr = NULL; + uint32_t sz_lba = 0; + + if (!cxt->firstsector) + goto done; + + pmbr = (struct gpt_legacy_mbr *) cxt->firstsector; + + if (le16_to_cpu(pmbr->signature) != MSDOS_MBR_SIGNATURE) + goto done; + + /* LBA of the GPT partition header */ + if (pmbr->partition_record[0].starting_lba != + cpu_to_le32(GPT_PRIMARY_PARTITION_TABLE_LBA)) + goto done; + + /* seems like a valid MBR was found, check DOS primary partitions */ + for (i = 0; i < 4; i++) { + if (pmbr->partition_record[i].os_type == EFI_PMBR_OSTYPE) { + /* + * Ok, we at least know that there's a protective MBR, + * now check if there are other partition types for + * hybrid MBR. + */ + part = i; + ret = GPT_MBR_PROTECTIVE; + goto check_hybrid; + } + } + + if (ret != GPT_MBR_PROTECTIVE) + goto done; +check_hybrid: + for (i = 0 ; i < 4; i++) { + if ((pmbr->partition_record[i].os_type != EFI_PMBR_OSTYPE) && + (pmbr->partition_record[i].os_type != 0x00)) + ret = GPT_MBR_HYBRID; + } + + /* + * Protective MBRs take up the lesser of the whole disk + * or 2 TiB (32bit LBA), ignoring the rest of the disk. + * Some partitioning programs, nonetheless, choose to set + * the size to the maximum 32-bit limitation, disregarding + * the disk size. + * + * Hybrid MBRs do not necessarily comply with this. + * + * Consider a bad value here to be a warning to support dd-ing + * an image from a smaller disk to a bigger disk. + */ + if (ret == GPT_MBR_PROTECTIVE) { + sz_lba = le32_to_cpu(pmbr->partition_record[part].size_in_lba); + if (sz_lba != (uint32_t) cxt->total_sectors - 1 && sz_lba != 0xFFFFFFFF) { + fdisk_warnx(cxt, _("GPT PMBR size mismatch (%u != %u) " + "will be corrected by w(rite)."), + sz_lba, + (uint32_t) cxt->total_sectors - 1); + fdisk_label_set_changed(cxt->label, 1); + } + } +done: + return ret; +} + +static uint64_t last_lba(struct fdisk_context *cxt) +{ + struct stat s; + uint64_t sectors = 0; + + memset(&s, 0, sizeof(s)); + if (fstat(cxt->dev_fd, &s) == -1) { + fdisk_warn(cxt, _("gpt: stat() failed")); + return 0; + } + + if (S_ISBLK(s.st_mode)) + sectors = cxt->total_sectors - 1; + else if (S_ISREG(s.st_mode)) + sectors = ((uint64_t) s.st_size / + (uint64_t) cxt->sector_size) - 1ULL; + else + fdisk_warnx(cxt, _("gpt: cannot handle files with mode %o"), s.st_mode); + + DBG(LABEL, ul_debug("GPT last LBA: %ju", sectors)); + return sectors; +} + +static ssize_t read_lba(struct fdisk_context *cxt, uint64_t lba, + void *buffer, const size_t bytes) +{ + off_t offset = lba * cxt->sector_size; + + if (lseek(cxt->dev_fd, offset, SEEK_SET) == (off_t) -1) + return -1; + return read(cxt->dev_fd, buffer, bytes) != bytes; +} + + +/* Returns the GPT entry array */ +static struct gpt_entry *gpt_read_entries(struct fdisk_context *cxt, + struct gpt_header *header) +{ + ssize_t sz; + struct gpt_entry *ret = NULL; + off_t offset; + + assert(cxt); + assert(header); + + sz = le32_to_cpu(header->npartition_entries) * + le32_to_cpu(header->sizeof_partition_entry); + + ret = calloc(1, sz); + if (!ret) + return NULL; + offset = le64_to_cpu(header->partition_entry_lba) * + cxt->sector_size; + + if (offset != lseek(cxt->dev_fd, offset, SEEK_SET)) + goto fail; + if (sz != read(cxt->dev_fd, ret, sz)) + goto fail; + + return ret; + +fail: + free(ret); + return NULL; +} + +static inline uint32_t count_crc32(const unsigned char *buf, size_t len) +{ + return (crc32(~0L, buf, len) ^ ~0L); +} + +/* + * Recompute header and partition array 32bit CRC checksums. + * This function does not fail - if there's corruption, then it + * will be reported when checksuming it again (ie: probing or verify). + */ +static void gpt_recompute_crc(struct gpt_header *header, struct gpt_entry *ents) +{ + uint32_t crc = 0; + size_t entry_sz = 0; + + if (!header) + return; + + /* header CRC */ + header->crc32 = 0; + crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); + header->crc32 = cpu_to_le32(crc); + + /* partition entry array CRC */ + header->partition_entry_array_crc32 = 0; + entry_sz = le32_to_cpu(header->npartition_entries) * + le32_to_cpu(header->sizeof_partition_entry); + + crc = count_crc32((unsigned char *) ents, entry_sz); + header->partition_entry_array_crc32 = cpu_to_le32(crc); +} + +/* + * Compute the 32bit CRC checksum of the partition table header. + * Returns 1 if it is valid, otherwise 0. + */ +static int gpt_check_header_crc(struct gpt_header *header, struct gpt_entry *ents) +{ + uint32_t crc, orgcrc = le32_to_cpu(header->crc32); + + header->crc32 = 0; + crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); + header->crc32 = cpu_to_le32(orgcrc); + + if (crc == le32_to_cpu(header->crc32)) + return 1; + + /* + * If we have checksum mismatch it may be due to stale data, + * like a partition being added or deleted. Recompute the CRC again + * and make sure this is not the case. + */ + if (ents) { + gpt_recompute_crc(header, ents); + orgcrc = le32_to_cpu(header->crc32); + header->crc32 = 0; + crc = count_crc32((unsigned char *) header, le32_to_cpu(header->size)); + header->crc32 = cpu_to_le32(orgcrc); + + return crc == le32_to_cpu(header->crc32); + } + + return 0; +} + +/* + * It initializes the partition entry array. + * Returns 1 if the checksum is valid, otherwise 0. + */ +static int gpt_check_entryarr_crc(struct gpt_header *header, + struct gpt_entry *ents) +{ + int ret = 0; + ssize_t entry_sz; + uint32_t crc; + + if (!header || !ents) + goto done; + + entry_sz = le32_to_cpu(header->npartition_entries) * + le32_to_cpu(header->sizeof_partition_entry); + + if (!entry_sz) + goto done; + + crc = count_crc32((unsigned char *) ents, entry_sz); + ret = (crc == le32_to_cpu(header->partition_entry_array_crc32)); +done: + return ret; +} + +static int gpt_check_lba_sanity(struct fdisk_context *cxt, struct gpt_header *header) +{ + int ret = 0; + uint64_t lu, fu, lastlba = last_lba(cxt); + + fu = le64_to_cpu(header->first_usable_lba); + lu = le64_to_cpu(header->last_usable_lba); + + /* check if first and last usable LBA make sense */ + if (lu < fu) { + DBG(LABEL, ul_debug("error: header last LBA is before first LBA")); + goto done; + } + + /* check if first and last usable LBAs with the disk's last LBA */ + if (fu > lastlba || lu > lastlba) { + DBG(LABEL, ul_debug("error: header LBAs are after the disk's last LBA")); + goto done; + } + + /* the header has to be outside usable range */ + if (fu < GPT_PRIMARY_PARTITION_TABLE_LBA && + GPT_PRIMARY_PARTITION_TABLE_LBA < lu) { + DBG(LABEL, ul_debug("error: header outside of usable range")); + goto done; + } + + ret = 1; /* sane */ +done: + return ret; +} + +/* Check if there is a valid header signature */ +static int gpt_check_signature(struct gpt_header *header) +{ + return header->signature == cpu_to_le64(GPT_HEADER_SIGNATURE); +} + +/* + * Return the specified GPT Header, or NULL upon failure/invalid. + * Note that all tests must pass to ensure a valid header, + * we do not rely on only testing the signature for a valid probe. + */ +static struct gpt_header *gpt_read_header(struct fdisk_context *cxt, + uint64_t lba, + struct gpt_entry **_ents) +{ + struct gpt_header *header = NULL; + struct gpt_entry *ents = NULL; + uint32_t hsz; + + if (!cxt) + return NULL; + + header = calloc(1, sizeof(*header)); + if (!header) + return NULL; + + /* read and verify header */ + if (read_lba(cxt, lba, header, sizeof(struct gpt_header)) != 0) + goto invalid; + + if (!gpt_check_signature(header)) + goto invalid; + + if (!gpt_check_header_crc(header, NULL)) + goto invalid; + + /* read and verify entries */ + ents = gpt_read_entries(cxt, header); + if (!ents) + goto invalid; + + if (!gpt_check_entryarr_crc(header, ents)) + goto invalid; + + if (!gpt_check_lba_sanity(cxt, header)) + goto invalid; + + /* valid header must be at MyLBA */ + if (le64_to_cpu(header->my_lba) != lba) + goto invalid; + + /* make sure header size is between 92 and sector size bytes */ + hsz = le32_to_cpu(header->size); + if (hsz < GPT_HEADER_MINSZ || hsz > cxt->sector_size) + goto invalid; + + if (_ents) + *_ents = ents; + else + free(ents); + + DBG(LABEL, ul_debug("found valid GPT Header on LBA %ju", lba)); + return header; +invalid: + free(header); + free(ents); + + DBG(LABEL, ul_debug("read GPT Header on LBA %ju failed", lba)); + return NULL; +} + + +static int gpt_locate_disklabel(struct fdisk_context *cxt, int n, + const char **name, off_t *offset, size_t *size) +{ + struct fdisk_gpt_label *gpt; + + assert(cxt); + + *name = NULL; + *offset = 0; + *size = 0; + + switch (n) { + case 0: + *name = "PMBR"; + *offset = 0; + *size = 512; + break; + case 1: + *name = _("GPT Header"); + *offset = GPT_PRIMARY_PARTITION_TABLE_LBA * cxt->sector_size; + *size = sizeof(struct gpt_header); + break; + case 2: + *name = _("GPT Entries"); + gpt = self_label(cxt); + *offset = le64_to_cpu(gpt->pheader->partition_entry_lba) * cxt->sector_size; + *size = le32_to_cpu(gpt->pheader->npartition_entries) * + le32_to_cpu(gpt->pheader->sizeof_partition_entry); + break; + default: + return 1; /* no more chunks */ + } + + return 0; +} + + + +/* + * Returns the number of partitions that are in use. + */ +static unsigned partitions_in_use(struct gpt_header *header, + struct gpt_entry *ents) +{ + uint32_t i, used = 0; + + if (!header || ! ents) + return 0; + + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) + if (!partition_unused(&ents[i])) + used++; + return used; +} + + +/* + * Check if a partition is too big for the disk (sectors). + * Returns the faulting partition number, otherwise 0. + */ +static uint32_t check_too_big_partitions(struct gpt_header *header, + struct gpt_entry *ents, uint64_t sectors) +{ + uint32_t i; + + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + if (partition_unused(&ents[i])) + continue; + if (gpt_partition_end(&ents[i]) >= sectors) + return i + 1; + } + + return 0; +} + +/* + * Check if a partition ends before it begins + * Returns the faulting partition number, otherwise 0. + */ +static uint32_t check_start_after_end_paritions(struct gpt_header *header, + struct gpt_entry *ents) +{ + uint32_t i; + + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + if (partition_unused(&ents[i])) + continue; + if (gpt_partition_start(&ents[i]) > gpt_partition_end(&ents[i])) + return i + 1; + } + + return 0; +} + +/* + * Check if partition e1 overlaps with partition e2. + */ +static inline int partition_overlap(struct gpt_entry *e1, struct gpt_entry *e2) +{ + uint64_t start1 = gpt_partition_start(e1); + uint64_t end1 = gpt_partition_end(e1); + uint64_t start2 = gpt_partition_start(e2); + uint64_t end2 = gpt_partition_end(e2); + + return (start1 && start2 && (start1 <= end2) != (end1 < start2)); +} + +/* + * Find any partitions that overlap. + */ +static uint32_t check_overlap_partitions(struct gpt_header *header, + struct gpt_entry *ents) +{ + uint32_t i, j; + + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) + for (j = 0; j < i; j++) { + if (partition_unused(&ents[i]) || + partition_unused(&ents[j])) + continue; + if (partition_overlap(&ents[i], &ents[j])) { + DBG(LABEL, ul_debug("GPT partitions overlap detected [%u vs. %u]", i, j)); + return i + 1; + } + } + + return 0; +} + +/* + * Find the first available block after the starting point; returns 0 if + * there are no available blocks left, or error. From gdisk. + */ +static uint64_t find_first_available(struct gpt_header *header, + struct gpt_entry *ents, uint64_t start) +{ + uint64_t first; + uint32_t i, first_moved = 0; + + uint64_t fu, lu; + + if (!header || !ents) + return 0; + + fu = le64_to_cpu(header->first_usable_lba); + lu = le64_to_cpu(header->last_usable_lba); + + /* + * Begin from the specified starting point or from the first usable + * LBA, whichever is greater... + */ + first = start < fu ? fu : start; + + /* + * Now search through all partitions; if first is within an + * existing partition, move it to the next sector after that + * partition and repeat. If first was moved, set firstMoved + * flag; repeat until firstMoved is not set, so as to catch + * cases where partitions are out of sequential order.... + */ + do { + first_moved = 0; + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + if (partition_unused(&ents[i])) + continue; + if (first < gpt_partition_start(&ents[i])) + continue; + if (first <= gpt_partition_end(&ents[i])) { + first = gpt_partition_end(&ents[i]) + 1; + first_moved = 1; + } + } + } while (first_moved == 1); + + if (first > lu) + first = 0; + + return first; +} + + +/* Returns last available sector in the free space pointed to by start. From gdisk. */ +static uint64_t find_last_free(struct gpt_header *header, + struct gpt_entry *ents, uint64_t start) +{ + uint32_t i; + uint64_t nearest_start; + + if (!header || !ents) + return 0; + + nearest_start = le64_to_cpu(header->last_usable_lba); + + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + uint64_t ps = gpt_partition_start(&ents[i]); + + if (nearest_start > ps && ps > start) + nearest_start = ps - 1; + } + + return nearest_start; +} + +/* Returns the last free sector on the disk. From gdisk. */ +static uint64_t find_last_free_sector(struct gpt_header *header, + struct gpt_entry *ents) +{ + uint32_t i, last_moved; + uint64_t last = 0; + + if (!header || !ents) + goto done; + + /* start by assuming the last usable LBA is available */ + last = le64_to_cpu(header->last_usable_lba); + do { + last_moved = 0; + for (i = 0; i < le32_to_cpu(header->npartition_entries); i++) { + if ((last >= gpt_partition_start(&ents[i])) && + (last <= gpt_partition_end(&ents[i]))) { + last = gpt_partition_start(&ents[i]) - 1; + last_moved = 1; + } + } + } while (last_moved == 1); +done: + return last; +} + +/* + * Finds the first available sector in the largest block of unallocated + * space on the disk. Returns 0 if there are no available blocks left. + * From gdisk. + */ +static uint64_t find_first_in_largest(struct gpt_header *header, + struct gpt_entry *ents) +{ + uint64_t start = 0, first_sect, last_sect; + uint64_t segment_size, selected_size = 0, selected_segment = 0; + + if (!header || !ents) + goto done; + + do { + first_sect = find_first_available(header, ents, start); + if (first_sect != 0) { + last_sect = find_last_free(header, ents, first_sect); + segment_size = last_sect - first_sect + 1; + + if (segment_size > selected_size) { + selected_size = segment_size; + selected_segment = first_sect; + } + start = last_sect + 1; + } + } while (first_sect != 0); + +done: + return selected_segment; +} + +/* + * Find the total number of free sectors, the number of segments in which + * they reside, and the size of the largest of those segments. From gdisk. + */ +static uint64_t get_free_sectors(struct fdisk_context *cxt, struct gpt_header *header, + struct gpt_entry *ents, uint32_t *nsegments, + uint64_t *largest_segment) +{ + uint32_t num = 0; + uint64_t first_sect, last_sect; + uint64_t largest_seg = 0, segment_sz; + uint64_t totfound = 0, start = 0; /* starting point for each search */ + + if (!cxt->total_sectors) + goto done; + + do { + first_sect = find_first_available(header, ents, start); + if (first_sect) { + last_sect = find_last_free(header, ents, first_sect); + segment_sz = last_sect - first_sect + 1; + + if (segment_sz > largest_seg) + largest_seg = segment_sz; + totfound += segment_sz; + num++; + start = last_sect + 1; + } + } while (first_sect); + +done: + if (nsegments) + *nsegments = num; + if (largest_segment) + *largest_segment = largest_seg; + + return totfound; +} + +static int gpt_probe_label(struct fdisk_context *cxt) +{ + int mbr_type; + struct fdisk_gpt_label *gpt; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + /* TODO: it would be nice to support scenario when GPT headers are OK, + * but PMBR is corrupt */ + mbr_type = valid_pmbr(cxt); + if (!mbr_type) + goto failed; + + DBG(LABEL, ul_debug("found a %s MBR", mbr_type == GPT_MBR_PROTECTIVE ? + "protective" : "hybrid")); + + /* primary header */ + gpt->pheader = gpt_read_header(cxt, GPT_PRIMARY_PARTITION_TABLE_LBA, + &gpt->ents); + + if (gpt->pheader) + /* primary OK, try backup from alternative LBA */ + gpt->bheader = gpt_read_header(cxt, + le64_to_cpu(gpt->pheader->alternative_lba), + NULL); + else + /* primary corrupted -- try last LBA */ + gpt->bheader = gpt_read_header(cxt, last_lba(cxt), &gpt->ents); + + if (!gpt->pheader && !gpt->bheader) + goto failed; + + /* primary OK, backup corrupted -- recovery */ + if (gpt->pheader && !gpt->bheader) { + fdisk_warnx(cxt, _("The backup GPT table is corrupt, but the " + "primary appears OK, so that will be used.")); + gpt->bheader = gpt_copy_header(cxt, gpt->pheader); + if (!gpt->bheader) + goto failed; + gpt_recompute_crc(gpt->bheader, gpt->ents); + + /* primary corrupted, backup OK -- recovery */ + } else if (!gpt->pheader && gpt->bheader) { + fdisk_warnx(cxt, _("The primary GPT table is corrupt, but the " + "backup appears OK, so that will be used.")); + gpt->pheader = gpt_copy_header(cxt, gpt->bheader); + if (!gpt->pheader) + goto failed; + gpt_recompute_crc(gpt->pheader, gpt->ents); + } + + cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries); + cxt->label->nparts_cur = partitions_in_use(gpt->pheader, gpt->ents); + return 1; +failed: + DBG(LABEL, ul_debug("GPT probe failed")); + gpt_deinit(cxt->label); + return 0; +} + +/* + * Stolen from libblkid - can be removed once partition semantics + * are added to the fdisk API. + */ +static char *encode_to_utf8(unsigned char *src, size_t count) +{ + uint16_t c; + char *dest; + size_t i, j, len = count; + + dest = calloc(1, count); + if (!dest) + return NULL; + + for (j = i = 0; i + 2 <= count; i += 2) { + /* always little endian */ + c = (src[i+1] << 8) | src[i]; + if (c == 0) { + dest[j] = '\0'; + break; + } else if (c < 0x80) { + if (j+1 >= len) + break; + dest[j++] = (uint8_t) c; + } else if (c < 0x800) { + if (j+2 >= len) + break; + dest[j++] = (uint8_t) (0xc0 | (c >> 6)); + dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } else { + if (j+3 >= len) + break; + dest[j++] = (uint8_t) (0xe0 | (c >> 12)); + dest[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); + dest[j++] = (uint8_t) (0x80 | (c & 0x3f)); + } + } + dest[j] = '\0'; + + return dest; +} + +static int gpt_entry_attrs_to_string(struct gpt_entry *e, char **res) +{ + unsigned int n, count = 0; + size_t l; + char *bits, *p; + uint64_t attrs; + + assert(e); + assert(res); + + *res = NULL; + attrs = le64_to_cpu(e->attrs); + if (!attrs) + return 0; /* no attributes at all */ + + bits = (char *) &attrs; + + /* Note that sizeof() is correct here, we need separators between + * the strings so also count \0 is correct */ + *res = calloc(1, sizeof(GPT_ATTRSTR_NOBLOCK) + + sizeof(GPT_ATTRSTR_REQ) + + sizeof(GPT_ATTRSTR_LEGACY) + + sizeof("GUID:") + (GPT_ATTRBIT_GUID_COUNT * 3)); + if (!*res) + return -errno; + + p = *res; + if (isset(bits, GPT_ATTRBIT_REQ)) { + memcpy(p, GPT_ATTRSTR_REQ, (l = sizeof(GPT_ATTRSTR_REQ))); + p += l - 1; + } + if (isset(bits, GPT_ATTRBIT_NOBLOCK)) { + if (p > *res) + *p++ = ' '; + memcpy(p, GPT_ATTRSTR_NOBLOCK, (l = sizeof(GPT_ATTRSTR_NOBLOCK))); + p += l - 1; + } + if (isset(bits, GPT_ATTRBIT_LEGACY)) { + if (p > *res) + *p++ = ' '; + memcpy(p, GPT_ATTRSTR_LEGACY, (l = sizeof(GPT_ATTRSTR_LEGACY))); + p += l - 1; + } + + for (n = GPT_ATTRBIT_GUID_FIRST; + n < GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT; n++) { + + if (!isset(bits, n)) + continue; + if (!count) { + if (p > *res) + *p++ = ' '; + p += sprintf(p, "GUID:%u", n); + } else + p += sprintf(p, ",%u", n); + count++; + } + + return 0; +} + +static int gpt_entry_attrs_from_string( + struct fdisk_context *cxt, + struct gpt_entry *e, + const char *str) +{ + const char *p = str; + uint64_t attrs = 0; + char *bits; + + assert(e); + assert(p); + + DBG(LABEL, ul_debug("GPT: parsing string attributes '%s'", p)); + + bits = (char *) &attrs; + + while (p && *p) { + int bit = -1; + + while (isblank(*p)) p++; + if (!*p) + break; + + DBG(LABEL, ul_debug(" parsing item '%s'", p)); + + if (strncmp(p, "GUID:", 5) == 0) { + p += 5; + continue; + } else if (strncmp(p, GPT_ATTRSTR_REQ, + sizeof(GPT_ATTRSTR_REQ) - 1) == 0) { + bit = GPT_ATTRBIT_REQ; + p += sizeof(GPT_ATTRSTR_REQ) - 1; + } else if (strncmp(p, GPT_ATTRSTR_LEGACY, + sizeof(GPT_ATTRSTR_LEGACY) - 1) == 0) { + bit = GPT_ATTRBIT_LEGACY; + p += sizeof(GPT_ATTRSTR_LEGACY) - 1; + } else if (strncmp(p, GPT_ATTRSTR_NOBLOCK, + sizeof(GPT_ATTRSTR_NOBLOCK) - 1) == 0) { + bit = GPT_ATTRBIT_NOBLOCK; + p += sizeof(GPT_ATTRSTR_NOBLOCK) - 1; + } else if (isdigit((unsigned int) *p)) { + char *end = NULL; + + errno = 0; + bit = strtol(p, &end, 0); + if (errno || !end || end == str + || bit < GPT_ATTRBIT_GUID_FIRST + || bit >= GPT_ATTRBIT_GUID_FIRST + GPT_ATTRBIT_GUID_COUNT) + bit = -1; + else + p = end; + } + + if (bit < 0) { + fdisk_warnx(cxt, _("unssuported GPT attribute bit '%s'"), p); + return -EINVAL; + } + + setbit(bits, bit); + + while (isblank(*p)) p++; + if (*p == ',') + p++; + } + + e->attrs = cpu_to_le64(attrs); + return 0; +} + +static int gpt_get_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct fdisk_gpt_label *gpt; + struct gpt_entry *e; + char u_str[37]; + int rc = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + if ((uint32_t) n >= le32_to_cpu(gpt->pheader->npartition_entries)) + return -EINVAL; + + gpt = self_label(cxt); + e = &gpt->ents[n]; + + pa->used = !partition_unused(e) || gpt_partition_start(e); + if (!pa->used) + return 0; + + pa->start = gpt_partition_start(e); + pa->size = gpt_partition_size(e); + pa->type = gpt_partition_parttype(cxt, e); + + if (guid_to_string(&e->partition_guid, u_str)) { + pa->uuid = strdup(u_str); + if (!pa->uuid) { + rc = -errno; + goto done; + } + } else + pa->uuid = NULL; + + rc = gpt_entry_attrs_to_string(e, &pa->attrs); + if (rc) + goto done; + + pa->name = encode_to_utf8((unsigned char *)e->name, sizeof(e->name)); + return 0; +done: + fdisk_reset_partition(pa); + return rc; +} + + +static int gpt_set_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct fdisk_gpt_label *gpt; + struct gpt_entry *e; + int rc = 0; + uint64_t start, end; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + if ((uint32_t) n >= le32_to_cpu(gpt->pheader->npartition_entries)) + return -EINVAL; + + FDISK_INIT_UNDEF(start); + FDISK_INIT_UNDEF(end); + + gpt = self_label(cxt); + e = &gpt->ents[n]; + + if (pa->uuid) { + char new_u[37], old_u[37]; + + guid_to_string(&e->partition_guid, old_u); + rc = gpt_entry_set_uuid(e, pa->uuid); + if (rc) + return rc; + guid_to_string(&e->partition_guid, new_u); + fdisk_info(cxt, _("Partition UUID changed from %s to %s."), + old_u, new_u); + } + + if (pa->name) { + char *old = encode_to_utf8((unsigned char *)e->name, sizeof(e->name)); + gpt_entry_set_name(e, pa->name); + + fdisk_info(cxt, _("Partition name changed from '%s' to '%.*s'."), + old, (int) GPT_PART_NAME_LEN, pa->name); + free(old); + } + + if (pa->type && pa->type->typestr) { + struct gpt_guid typeid; + + rc = string_to_guid(pa->type->typestr, &typeid); + if (rc) + return rc; + gpt_entry_set_type(e, &typeid); + } + if (pa->attrs) { + rc = gpt_entry_attrs_from_string(cxt, e, pa->attrs); + if (rc) + return rc; + } + + if (fdisk_partition_has_start(pa)) + start = pa->start; + if (fdisk_partition_has_size(pa)) + end = gpt_partition_start(e) + pa->size - 1ULL; + + if (pa->end_follow_default) { + /* enlarge */ + if (!FDISK_IS_UNDEF(start)) + start = gpt_partition_start(e); + end = find_last_free(gpt->bheader, gpt->ents, start); + if (!end) + FDISK_INIT_UNDEF(end); + } + + if (!FDISK_IS_UNDEF(start)) + e->lba_start = cpu_to_le64(start); + if (!FDISK_IS_UNDEF(end)) + e->lba_end = cpu_to_le64(end); + + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + + fdisk_label_set_changed(cxt->label, 1); + return rc; +} + + +/* + * List label partitions. + */ +static int gpt_list_disklabel(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + if (fdisk_is_details(cxt)) { + struct gpt_header *h = self_label(cxt)->pheader; + + fdisk_info(cxt, _("First LBA: %ju"), h->first_usable_lba); + fdisk_info(cxt, _("Last LBA: %ju"), h->last_usable_lba); + /* TRANSLATORS: The LBA (Logical Block Address) of the backup GPT header. */ + fdisk_info(cxt, _("Alternative LBA: %ju"), h->alternative_lba); + /* TRANSLATORS: The start of the array of partition entries. */ + fdisk_info(cxt, _("Partition entries LBA: %ju"), h->partition_entry_lba); + fdisk_info(cxt, _("Allocated partition entries: %u"), h->npartition_entries); + } + + return 0; +} + +/* + * Write partitions. + * Returns 0 on success, or corresponding error otherwise. + */ +static int gpt_write_partitions(struct fdisk_context *cxt, + struct gpt_header *header, struct gpt_entry *ents) +{ + off_t offset = le64_to_cpu(header->partition_entry_lba) * cxt->sector_size; + uint32_t nparts = le32_to_cpu(header->npartition_entries); + uint32_t totwrite = nparts * le32_to_cpu(header->sizeof_partition_entry); + ssize_t rc; + + if (offset != lseek(cxt->dev_fd, offset, SEEK_SET)) + goto fail; + + rc = write(cxt->dev_fd, ents, totwrite); + if (rc > 0 && totwrite == (uint32_t) rc) + return 0; +fail: + return -errno; +} + +/* + * Write a GPT header to a specified LBA + * Returns 0 on success, or corresponding error otherwise. + */ +static int gpt_write_header(struct fdisk_context *cxt, + struct gpt_header *header, uint64_t lba) +{ + off_t offset = lba * cxt->sector_size; + + if (offset != lseek(cxt->dev_fd, offset, SEEK_SET)) + goto fail; + if (cxt->sector_size == + (size_t) write(cxt->dev_fd, header, cxt->sector_size)) + return 0; +fail: + return -errno; +} + +/* + * Write the protective MBR. + * Returns 0 on success, or corresponding error otherwise. + */ +static int gpt_write_pmbr(struct fdisk_context *cxt) +{ + off_t offset; + struct gpt_legacy_mbr *pmbr = NULL; + + assert(cxt); + assert(cxt->firstsector); + + pmbr = (struct gpt_legacy_mbr *) cxt->firstsector; + + /* zero out the legacy partitions */ + memset(pmbr->partition_record, 0, sizeof(pmbr->partition_record)); + + pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE); + pmbr->partition_record[0].os_type = EFI_PMBR_OSTYPE; + pmbr->partition_record[0].start_sector = 1; + pmbr->partition_record[0].end_head = 0xFE; + pmbr->partition_record[0].end_sector = 0xFF; + pmbr->partition_record[0].end_track = 0xFF; + pmbr->partition_record[0].starting_lba = cpu_to_le32(1); + + /* + * Set size_in_lba to the size of the disk minus one. If the size of the disk + * is too large to be represented by a 32bit LBA (2Tb), set it to 0xFFFFFFFF. + */ + if (cxt->total_sectors - 1 > 0xFFFFFFFFULL) + pmbr->partition_record[0].size_in_lba = cpu_to_le32(0xFFFFFFFF); + else + pmbr->partition_record[0].size_in_lba = + cpu_to_le32(cxt->total_sectors - 1UL); + + offset = GPT_PMBR_LBA * cxt->sector_size; + if (offset != lseek(cxt->dev_fd, offset, SEEK_SET)) + goto fail; + + /* pMBR covers the first sector (LBA) of the disk */ + if (write_all(cxt->dev_fd, pmbr, cxt->sector_size)) + goto fail; + return 0; +fail: + return -errno; +} + +/* + * Writes in-memory GPT and pMBR data to disk. + * Returns 0 if successful write, otherwise, a corresponding error. + * Any indication of error will abort the operation. + */ +static int gpt_write_disklabel(struct fdisk_context *cxt) +{ + struct fdisk_gpt_label *gpt; + int mbr_type; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + mbr_type = valid_pmbr(cxt); + + /* check that disk is big enough to handle the backup header */ + if (le64_to_cpu(gpt->pheader->alternative_lba) > cxt->total_sectors) + goto err0; + + /* check that the backup header is properly placed */ + if (le64_to_cpu(gpt->pheader->alternative_lba) < cxt->total_sectors - 1) + /* TODO: correct this (with user authorization) and write */ + goto err0; + + if (check_overlap_partitions(gpt->pheader, gpt->ents)) + goto err0; + + /* recompute CRCs for both headers */ + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + + /* + * UEFI requires writing in this specific order: + * 1) backup partition tables + * 2) backup GPT header + * 3) primary partition tables + * 4) primary GPT header + * 5) protective MBR + * + * If any write fails, we abort the rest. + */ + if (gpt_write_partitions(cxt, gpt->bheader, gpt->ents) != 0) + goto err1; + if (gpt_write_header(cxt, gpt->bheader, + le64_to_cpu(gpt->pheader->alternative_lba)) != 0) + goto err1; + if (gpt_write_partitions(cxt, gpt->pheader, gpt->ents) != 0) + goto err1; + if (gpt_write_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA) != 0) + goto err1; + + if (mbr_type == GPT_MBR_HYBRID) + fdisk_warnx(cxt, _("The device contains hybrid MBR -- writing GPT only. " + "You have to sync the MBR manually.")); + else if (gpt_write_pmbr(cxt) != 0) + goto err1; + + DBG(LABEL, ul_debug("GPT write success")); + return 0; +err0: + DBG(LABEL, ul_debug("GPT write failed: incorrect input")); + errno = EINVAL; + return -EINVAL; +err1: + DBG(LABEL, ul_debug("GPT write failed: %m")); + return -errno; +} + +/* + * Verify data integrity and report any found problems for: + * - primary and backup header validations + * - paritition validations + */ +static int gpt_verify_disklabel(struct fdisk_context *cxt) +{ + int nerror = 0; + unsigned int ptnum; + struct fdisk_gpt_label *gpt; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + if (!gpt || !gpt->bheader) { + nerror++; + fdisk_warnx(cxt, _("Disk does not contain a valid backup header.")); + } + + if (!gpt_check_header_crc(gpt->pheader, gpt->ents)) { + nerror++; + fdisk_warnx(cxt, _("Invalid primary header CRC checksum.")); + } + if (gpt->bheader && !gpt_check_header_crc(gpt->bheader, gpt->ents)) { + nerror++; + fdisk_warnx(cxt, _("Invalid backup header CRC checksum.")); + } + + if (!gpt_check_entryarr_crc(gpt->pheader, gpt->ents)) { + nerror++; + fdisk_warnx(cxt, _("Invalid partition entry checksum.")); + } + + if (!gpt_check_lba_sanity(cxt, gpt->pheader)) { + nerror++; + fdisk_warnx(cxt, _("Invalid primary header LBA sanity checks.")); + } + if (gpt->bheader && !gpt_check_lba_sanity(cxt, gpt->bheader)) { + nerror++; + fdisk_warnx(cxt, _("Invalid backup header LBA sanity checks.")); + } + + if (le64_to_cpu(gpt->pheader->my_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) { + nerror++; + fdisk_warnx(cxt, _("MyLBA mismatch with real position at primary header.")); + } + if (gpt->bheader && le64_to_cpu(gpt->bheader->my_lba) != last_lba(cxt)) { + nerror++; + fdisk_warnx(cxt, _("MyLBA mismatch with real position at backup header.")); + + } + if (le64_to_cpu(gpt->pheader->alternative_lba) >= cxt->total_sectors) { + nerror++; + fdisk_warnx(cxt, _("Disk is too small to hold all data.")); + } + + /* + * if the GPT is the primary table, check the alternateLBA + * to see if it is a valid GPT + */ + if (gpt->bheader && (le64_to_cpu(gpt->pheader->my_lba) != + le64_to_cpu(gpt->bheader->alternative_lba))) { + nerror++; + fdisk_warnx(cxt, _("Primary and backup header mismatch.")); + } + + ptnum = check_overlap_partitions(gpt->pheader, gpt->ents); + if (ptnum) { + nerror++; + fdisk_warnx(cxt, _("Partition %u overlaps with partition %u."), + ptnum, ptnum+1); + } + + ptnum = check_too_big_partitions(gpt->pheader, gpt->ents, cxt->total_sectors); + if (ptnum) { + nerror++; + fdisk_warnx(cxt, _("Partition %u is too big for the disk."), + ptnum); + } + + ptnum = check_start_after_end_paritions(gpt->pheader, gpt->ents); + if (ptnum) { + nerror++; + fdisk_warnx(cxt, _("Partition %u ends before it starts."), + ptnum); + } + + if (!nerror) { /* yay :-) */ + uint32_t nsegments = 0; + uint64_t free_sectors = 0, largest_segment = 0; + char *strsz = NULL; + + fdisk_info(cxt, _("No errors detected.")); + fdisk_info(cxt, _("Header version: %s"), gpt_get_header_revstr(gpt->pheader)); + fdisk_info(cxt, _("Using %u out of %d partitions."), + partitions_in_use(gpt->pheader, gpt->ents), + le32_to_cpu(gpt->pheader->npartition_entries)); + + free_sectors = get_free_sectors(cxt, gpt->pheader, gpt->ents, + &nsegments, &largest_segment); + if (largest_segment) + strsz = size_to_human_string(SIZE_SUFFIX_SPACE | SIZE_SUFFIX_3LETTER, + largest_segment * cxt->sector_size); + + fdisk_info(cxt, + P_("A total of %ju free sectors is available in %u segment.", + "A total of %ju free sectors is available in %u segments " + "(the largest is %s).", nsegments), + free_sectors, nsegments, strsz); + free(strsz); + + } else + fdisk_warnx(cxt, + P_("%d error detected.", "%d errors detected.", nerror), + nerror); + + return 0; +} + +/* Delete a single GPT partition, specified by partnum. */ +static int gpt_delete_partition(struct fdisk_context *cxt, + size_t partnum) +{ + struct fdisk_gpt_label *gpt; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + if (partnum >= cxt->label->nparts_max + || partition_unused(&gpt->ents[partnum])) + return -EINVAL; + + /* hasta la vista, baby! */ + memset(&gpt->ents[partnum], 0, sizeof(struct gpt_entry)); + if (!partition_unused(&gpt->ents[partnum])) + return -EINVAL; + else { + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + cxt->label->nparts_cur--; + fdisk_label_set_changed(cxt->label, 1); + } + + return 0; +} + + +/* Performs logical checks to add a new partition entry */ +static int gpt_add_partition( + struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + uint64_t user_f, user_l; /* user input ranges for first and last sectors */ + uint64_t disk_f, disk_l; /* first and last available sector ranges on device*/ + uint64_t dflt_f, dflt_l; /* largest segment (default) */ + struct gpt_guid typeid; + struct fdisk_gpt_label *gpt; + struct gpt_header *pheader; + struct gpt_entry *e, *ents; + struct fdisk_ask *ask = NULL; + size_t partnum; + int rc; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + pheader = gpt->pheader; + ents = gpt->ents; + + rc = fdisk_partition_next_partno(pa, cxt, &partnum); + if (rc) { + DBG(LABEL, ul_debug("GPT failed to get next partno")); + return rc; + } + if (!partition_unused(&ents[partnum])) { + fdisk_warnx(cxt, _("Partition %zu is already defined. " + "Delete it before re-adding it."), partnum +1); + return -ERANGE; + } + if (le32_to_cpu(pheader->npartition_entries) == + partitions_in_use(pheader, ents)) { + fdisk_warnx(cxt, _("All partitions are already in use.")); + return -ENOSPC; + } + if (!get_free_sectors(cxt, pheader, ents, NULL, NULL)) { + fdisk_warnx(cxt, _("No free sectors available.")); + return -ENOSPC; + } + + string_to_guid(pa && pa->type && pa->type->typestr ? + pa->type->typestr: + GPT_DEFAULT_ENTRY_TYPE, &typeid); + + disk_f = find_first_available(pheader, ents, pheader->first_usable_lba); + + /* if first sector no explicitly defined then ignore small gaps before + * the first partition */ + if ((!pa || !fdisk_partition_has_start(pa)) + && !partition_unused(&ents[0]) + && disk_f < gpt_partition_start(&ents[0])) { + + do { + uint64_t x; + DBG(LABEL, ul_debug("testing first sector %ju", disk_f)); + disk_f = find_first_available(pheader, ents, disk_f); + if (!disk_f) + break; + x = find_last_free(pheader, ents, disk_f); + if (x - disk_f >= cxt->grain / cxt->sector_size) + break; + DBG(LABEL, ul_debug("first sector %ju addresses to small space, continue...", disk_f)); + disk_f = x + 1; + } while(1); + + if (disk_f == 0) + disk_f = find_first_available(pheader, ents, pheader->first_usable_lba); + } + + disk_l = find_last_free_sector(pheader, ents); + + /* the default is the largest free space */ + dflt_f = find_first_in_largest(pheader, ents); + dflt_l = find_last_free(pheader, ents, dflt_f); + + /* align the default in range <dflt_f,dflt_l>*/ + dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l); + + /* first sector */ + if (pa && pa->start_follow_default) { + user_f = dflt_f; + + } else if (pa && fdisk_partition_has_start(pa)) { + DBG(LABEL, ul_debug("first sector defined: %ju", pa->start)); + if (pa->start != find_first_available(pheader, ents, pa->start)) { + fdisk_warnx(cxt, _("Sector %ju already used."), pa->start); + return -ERANGE; + } + user_f = pa->start; + } else { + /* ask by dialog */ + for (;;) { + if (!ask) + ask = fdisk_new_ask(); + else + fdisk_reset_ask(ask); + + /* First sector */ + fdisk_ask_set_query(ask, _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, disk_f); /* minimal */ + fdisk_ask_number_set_default(ask, dflt_f); /* default */ + fdisk_ask_number_set_high(ask, disk_l); /* maximal */ + + rc = fdisk_do_ask(cxt, ask); + if (rc) + goto done; + + user_f = fdisk_ask_number_get_result(ask); + if (user_f != find_first_available(pheader, ents, user_f)) { + fdisk_warnx(cxt, _("Sector %ju already used."), user_f); + continue; + } + break; + } + } + + + /* Last sector */ + dflt_l = find_last_free(pheader, ents, user_f); + + if (pa && pa->end_follow_default) { + user_l = dflt_l; + + } else if (pa && fdisk_partition_has_size(pa)) { + user_l = user_f + pa->size - 1; + DBG(LABEL, ul_debug("size defined: %ju, end: %ju (last possible: %ju)", + pa->size, user_l, dflt_l)); + if (user_l != dflt_l && !pa->size_explicit) + user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; + + } else { + for (;;) { + if (!ask) + ask = fdisk_new_ask(); + else + fdisk_reset_ask(ask); + + fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + fdisk_ask_number_set_low(ask, user_f); /* minimal */ + fdisk_ask_number_set_default(ask, dflt_l); /* default */ + fdisk_ask_number_set_high(ask, dflt_l); /* maximal */ + fdisk_ask_number_set_base(ask, user_f); /* base for relative input */ + fdisk_ask_number_set_unit(ask, cxt->sector_size); + + rc = fdisk_do_ask(cxt, ask); + if (rc) + goto done; + + user_l = fdisk_ask_number_get_result(ask); + if (fdisk_ask_number_is_relative(ask)) { + user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; + + /* no space for anything useful, use all space + if (user_l + (cxt->grain / cxt->sector_size) > dflt_l) + user_l = dflt_l; + */ + } + + if (user_l > user_f && user_l <= disk_l) + break; + } + } + + + if (user_f > user_l || partnum >= cxt->label->nparts_max) { + fdisk_warnx(cxt, _("Could not create partition %zu"), partnum + 1); + rc = -EINVAL; + goto done; + } + + assert(!FDISK_IS_UNDEF(user_l)); + assert(!FDISK_IS_UNDEF(user_f)); + + e = &ents[partnum]; + e->lba_end = cpu_to_le64(user_l); + e->lba_start = cpu_to_le64(user_f); + + gpt_entry_set_type(e, &typeid); + + if (pa && pa->uuid) { + /* Sometimes it's necessary to create a copy of the PT and + * reuse already defined UUID + */ + rc = gpt_entry_set_uuid(e, pa->uuid); + if (rc) + goto done; + } else { + /* Any time a new partition entry is created a new GUID must be + * generated for that partition, and every partition is guaranteed + * to have a unique GUID. + */ + uuid_generate_random((unsigned char *) &e->partition_guid); + swap_efi_guid(&e->partition_guid); + } + + if (pa && pa->name && *pa->name) + gpt_entry_set_name(e, pa->name); + if (pa && pa->attrs) + gpt_entry_attrs_from_string(cxt, e, pa->attrs); + + DBG(LABEL, ul_debug("GPT new partition: partno=%zu, start=%ju, end=%ju, size=%ju", + partnum, + gpt_partition_start(e), + gpt_partition_end(e), + gpt_partition_size(e))); + + gpt_recompute_crc(gpt->pheader, ents); + gpt_recompute_crc(gpt->bheader, ents); + + /* report result */ + { + struct fdisk_parttype *t; + + cxt->label->nparts_cur++; + fdisk_label_set_changed(cxt->label, 1); + + t = gpt_partition_parttype(cxt, &ents[partnum]); + fdisk_info_new_partition(cxt, partnum + 1, user_f, user_l, t); + fdisk_unref_parttype(t); + } + + rc = 0; + if (partno) + *partno = partnum; +done: + fdisk_unref_ask(ask); + return rc; +} + +/* + * Create a new GPT disklabel - destroys any previous data. + */ +static int gpt_create_disklabel(struct fdisk_context *cxt) +{ + int rc = 0; + ssize_t esz = 0; + char str[37]; + struct fdisk_gpt_label *gpt; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + /* label private stuff has to be empty, see gpt_deinit() */ + assert(gpt->pheader == NULL); + assert(gpt->bheader == NULL); + + /* + * When no header, entries or pmbr is set, we're probably + * dealing with a new, empty disk - so always allocate memory + * to deal with the data structures whatever the case is. + */ + rc = gpt_mknew_pmbr(cxt); + if (rc < 0) + goto done; + + /* primary */ + gpt->pheader = calloc(1, sizeof(*gpt->pheader)); + if (!gpt->pheader) { + rc = -ENOMEM; + goto done; + } + rc = gpt_mknew_header(cxt, gpt->pheader, GPT_PRIMARY_PARTITION_TABLE_LBA); + if (rc < 0) + goto done; + + /* backup ("copy" primary) */ + gpt->bheader = calloc(1, sizeof(*gpt->bheader)); + if (!gpt->bheader) { + rc = -ENOMEM; + goto done; + } + rc = gpt_mknew_header_from_bkp(cxt, gpt->bheader, + last_lba(cxt), gpt->pheader); + if (rc < 0) + goto done; + + esz = le32_to_cpu(gpt->pheader->npartition_entries) * + le32_to_cpu(gpt->pheader->sizeof_partition_entry); + gpt->ents = calloc(1, esz); + if (!gpt->ents) { + rc = -ENOMEM; + goto done; + } + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + + cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries); + cxt->label->nparts_cur = 0; + + guid_to_string(&gpt->pheader->disk_guid, str); + fdisk_label_set_changed(cxt->label, 1); + fdisk_info(cxt, _("Created a new GPT disklabel (GUID: %s)."), str); +done: + return rc; +} + +static int gpt_get_disklabel_id(struct fdisk_context *cxt, char **id) +{ + struct fdisk_gpt_label *gpt; + char str[37]; + + assert(cxt); + assert(id); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + guid_to_string(&gpt->pheader->disk_guid, str); + + *id = strdup(str); + if (!*id) + return -ENOMEM; + return 0; +} + +static int gpt_set_disklabel_id(struct fdisk_context *cxt) +{ + struct fdisk_gpt_label *gpt; + struct gpt_guid uuid; + char *str, *old, *new; + int rc; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + if (fdisk_ask_string(cxt, + _("Enter new disk UUID (in 8-4-4-4-12 format)"), &str)) + return -EINVAL; + + rc = string_to_guid(str, &uuid); + free(str); + + if (rc) { + fdisk_warnx(cxt, _("Failed to parse your UUID.")); + return rc; + } + + gpt_get_disklabel_id(cxt, &old); + + gpt->pheader->disk_guid = uuid; + gpt->bheader->disk_guid = uuid; + + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + + gpt_get_disklabel_id(cxt, &new); + + fdisk_info(cxt, _("Disk identifier changed from %s to %s."), old, new); + + free(old); + free(new); + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static int gpt_part_is_used(struct fdisk_context *cxt, size_t i) +{ + struct fdisk_gpt_label *gpt; + struct gpt_entry *e; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + + if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries)) + return 0; + e = &gpt->ents[i]; + + return !partition_unused(e) || gpt_partition_start(e); +} + +/** + * fdisk_gpt_is_hybrid: + * @cxt: context + * + * The regular GPT contains PMBR (dummy protective MBR) where the protective + * MBR does not address any partitions. + * + * Hybrid GPT contains regular MBR where this partition table addresses the + * same partitions as GPT. It's recommended to not use hybrid GPT due to MBR + * limits. + * + * The libfdisk does not provide functionality to sync GPT and MBR, you have to + * directly access and modify (P)MBR (see fdisk_new_nested_context()). + * + * Returns: 1 if partition table detected as hybrid otherwise return 0 + */ +int fdisk_gpt_is_hybrid(struct fdisk_context *cxt) +{ + assert(cxt); + return valid_pmbr(cxt) == GPT_MBR_HYBRID; +} + +static int gpt_toggle_partition_flag( + struct fdisk_context *cxt, + size_t i, + unsigned long flag) +{ + struct fdisk_gpt_label *gpt; + uint64_t attrs, tmp; + char *bits; + const char *name = NULL; + int bit = -1, rc; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + DBG(LABEL, ul_debug("GPT entry attribute change requested partno=%zu", i)); + gpt = self_label(cxt); + + if ((uint32_t) i >= le32_to_cpu(gpt->pheader->npartition_entries)) + return -EINVAL; + + attrs = le64_to_cpu(gpt->ents[i].attrs); + bits = (char *) &attrs; + + switch (flag) { + case GPT_FLAG_REQUIRED: + bit = GPT_ATTRBIT_REQ; + name = GPT_ATTRSTR_REQ; + break; + case GPT_FLAG_NOBLOCK: + bit = GPT_ATTRBIT_NOBLOCK; + name = GPT_ATTRSTR_NOBLOCK; + break; + case GPT_FLAG_LEGACYBOOT: + bit = GPT_ATTRBIT_LEGACY; + name = GPT_ATTRSTR_LEGACY; + break; + case GPT_FLAG_GUIDSPECIFIC: + rc = fdisk_ask_number(cxt, 48, 48, 63, _("Enter GUID specific bit"), &tmp); + if (rc) + return rc; + bit = tmp; + break; + default: + /* already specified PT_FLAG_GUIDSPECIFIC bit */ + if (flag >= 48 && flag <= 63) { + bit = flag; + flag = GPT_FLAG_GUIDSPECIFIC; + } + break; + } + + if (bit < 0) { + fdisk_warnx(cxt, _("failed to toggle unsupported bit %lu"), flag); + return -EINVAL; + } + + if (!isset(bits, bit)) + setbit(bits, bit); + else + clrbit(bits, bit); + + gpt->ents[i].attrs = cpu_to_le64(attrs); + + if (flag == GPT_FLAG_GUIDSPECIFIC) + fdisk_info(cxt, isset(bits, bit) ? + _("The GUID specific bit %d on partition %zu is enabled now.") : + _("The GUID specific bit %d on partition %zu is disabled now."), + bit, i + 1); + else + fdisk_info(cxt, isset(bits, bit) ? + _("The %s flag on partition %zu is enabled now.") : + _("The %s flag on partition %zu is disabled now."), + name, i + 1); + + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + +static int gpt_entry_cmp_start(const void *a, const void *b) +{ + struct gpt_entry *ae = (struct gpt_entry *) a, + *be = (struct gpt_entry *) b; + int au = partition_unused(ae), + bu = partition_unused(be); + + if (au && bu) + return 0; + if (au) + return 1; + if (bu) + return -1; + + return cmp_numbers(gpt_partition_start(ae), gpt_partition_start(be)); +} + +/* sort partition by start sector */ +static int gpt_reorder(struct fdisk_context *cxt) +{ + struct fdisk_gpt_label *gpt; + size_t nparts; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + nparts = le32_to_cpu(gpt->pheader->npartition_entries); + + qsort(gpt->ents, nparts, sizeof(struct gpt_entry), + gpt_entry_cmp_start); + + gpt_recompute_crc(gpt->pheader, gpt->ents); + gpt_recompute_crc(gpt->bheader, gpt->ents); + fdisk_label_set_changed(cxt->label, 1); + + fdisk_info(cxt, _("Done.")); + return 0; +} + +static int gpt_reset_alignment(struct fdisk_context *cxt) +{ + struct fdisk_gpt_label *gpt; + struct gpt_header *h; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, GPT)); + + gpt = self_label(cxt); + h = gpt ? gpt->pheader : NULL; + + if (h) { + /* always follow existing table */ + cxt->first_lba = h->first_usable_lba; + cxt->last_lba = h->last_usable_lba; + } else { + /* estimate ranges for GPT */ + uint64_t first, last; + + count_first_last_lba(cxt, &first, &last); + + if (cxt->first_lba < first) + cxt->first_lba = first; + if (cxt->last_lba > last) + cxt->last_lba = last; + } + + return 0; +} +/* + * Deinitialize fdisk-specific variables + */ +static void gpt_deinit(struct fdisk_label *lb) +{ + struct fdisk_gpt_label *gpt = (struct fdisk_gpt_label *) lb; + + if (!gpt) + return; + + free(gpt->ents); + free(gpt->pheader); + free(gpt->bheader); + + gpt->ents = NULL; + gpt->pheader = NULL; + gpt->bheader = NULL; +} + +static const struct fdisk_label_operations gpt_operations = +{ + .probe = gpt_probe_label, + .write = gpt_write_disklabel, + .verify = gpt_verify_disklabel, + .create = gpt_create_disklabel, + .list = gpt_list_disklabel, + .locate = gpt_locate_disklabel, + .reorder = gpt_reorder, + .get_id = gpt_get_disklabel_id, + .set_id = gpt_set_disklabel_id, + + .get_part = gpt_get_partition, + .set_part = gpt_set_partition, + .add_part = gpt_add_partition, + .del_part = gpt_delete_partition, + + .part_is_used = gpt_part_is_used, + .part_toggle_flag = gpt_toggle_partition_flag, + + .deinit = gpt_deinit, + + .reset_alignment = gpt_reset_alignment +}; + +static const struct fdisk_field gpt_fields[] = +{ + /* basic */ + { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 }, + { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY }, + { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY }, + /* expert */ + { FDISK_FIELD_TYPEID, N_("Type-UUID"), 36, FDISK_FIELDFL_DETAIL }, + { FDISK_FIELD_UUID, N_("UUID"), 36, FDISK_FIELDFL_DETAIL }, + { FDISK_FIELD_NAME, N_("Name"), 0.2, FDISK_FIELDFL_DETAIL }, + { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_DETAIL } +}; + +/* + * allocates GPT in-memory stuff + */ +struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + struct fdisk_gpt_label *gpt; + + assert(cxt); + + gpt = calloc(1, sizeof(*gpt)); + if (!gpt) + return NULL; + + /* initialize generic part of the driver */ + lb = (struct fdisk_label *) gpt; + lb->name = "gpt"; + lb->id = FDISK_DISKLABEL_GPT; + lb->op = &gpt_operations; + lb->parttypes = gpt_parttypes; + lb->nparttypes = ARRAY_SIZE(gpt_parttypes); + + lb->fields = gpt_fields; + lb->nfields = ARRAY_SIZE(gpt_fields); + + return lb; +} diff --git a/libblkid/libfdisk/src/init.c b/libblkid/libfdisk/src/init.c new file mode 100644 index 000000000..61acb0a4f --- /dev/null +++ b/libblkid/libfdisk/src/init.c @@ -0,0 +1,55 @@ + +#include "fdiskP.h" + + +/** + * SECTION: init + * @title: Library initialization + * @short_description: initialize debug stuff + * + */ + +UL_DEBUG_DEFINE_MASK(libfdisk); +UL_DEBUG_DEFINE_MASKNAMES(libfdisk) = +{ + { "all", LIBFDISK_DEBUG_ALL, "info about all subsystems" }, + { "ask", LIBFDISK_DEBUG_ASK, "fdisk dialogs" }, + { "help", LIBFDISK_DEBUG_HELP, "this help" }, + { "cxt", LIBFDISK_DEBUG_CXT, "library context (handler)" }, + { "label", LIBFDISK_DEBUG_LABEL, "disk label utils" }, + { "part", LIBFDISK_DEBUG_PART, "partition utils" }, + { "parttype", LIBFDISK_DEBUG_PARTTYPE,"partition type utils" }, + { "script", LIBFDISK_DEBUG_SCRIPT, "sfdisk-like scripts" }, + { "tab", LIBFDISK_DEBUG_TAB, "table utils"}, + { NULL, 0 } +}; + +/** + * fdisk_init_debug: + * @mask: debug mask (0xffff to enable full debuging) + * + * If the @mask is not specified then this function reads + * LIBFDISK_DEBUG environment variable to get the mask. + * + * Already initialized debugging stuff cannot be changed. It does not + * have effect to call this function twice. + * + * It's strongly recommended to use fdisk_init_debug(0) in your code. + */ +void fdisk_init_debug(int mask) +{ + if (libfdisk_debug_mask) + return; + + __UL_INIT_DEBUG(libfdisk, LIBFDISK_DEBUG_, mask, LIBFDISK_DEBUG); + + + if (libfdisk_debug_mask != LIBFDISK_DEBUG_INIT + && libfdisk_debug_mask != (LIBFDISK_DEBUG_HELP|LIBFDISK_DEBUG_INIT)) { + + DBG(INIT, ul_debug("library debug mask: 0x%04x", libfdisk_debug_mask)); + } + + ON_DBG(HELP, ul_debug_print_masks("LIBFDISK_DEBUG", + UL_DEBUG_MASKNAMES(libfdisk))); +} diff --git a/libblkid/libfdisk/src/iter.c b/libblkid/libfdisk/src/iter.c new file mode 100644 index 000000000..9a0b0801c --- /dev/null +++ b/libblkid/libfdisk/src/iter.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +/** + * SECTION: iter + * @title: Iterator + * @short_description: unified iterator + * + * The iterator keeps the direction and the last position for access to the + * internal library tables/lists. + * + * It's very unusual to use the same iterator on multiple places in your + * application or share the same iterator, for this purpose libfdisk does not + * provide reference counting for this object. It's recommended to initialize + * the iterator by fdisk_new_iter() at begin of your function and then + * fdisk_free_iter() before you return from the function. + * + * Don't forget to call fdisk_reset_iter() if you want to use the iterator more + * than once. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "fdiskP.h" + +/** + * fdisk_new_iter: + * @direction: FDISK_INTER_{FOR,BACK}WARD direction + * + * Returns: newly allocated generic libmount iterator. + */ +struct fdisk_iter *fdisk_new_iter(int direction) +{ + struct fdisk_iter *itr = calloc(1, sizeof(*itr)); + if (!itr) + return NULL; + itr->direction = direction; + return itr; +} + +/** + * fdisk_free_iter: + * @itr: iterator pointer + * + * Deallocates the iterator. + */ +void fdisk_free_iter(struct fdisk_iter *itr) +{ + free(itr); +} + +/** + * fdisk_reset_iter: + * @itr: iterator pointer + * @direction: FDISK_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged + * + * Resets the iterator. + */ +void fdisk_reset_iter(struct fdisk_iter *itr, int direction) +{ + if (direction == -1) + direction = itr->direction; + + memset(itr, 0, sizeof(*itr)); + itr->direction = direction; +} + +/** + * fdisk_iter_get_direction: + * @itr: iterator pointer + * + * Returns: FDISK_INTER_{FOR,BACK}WARD + */ +int fdisk_iter_get_direction(struct fdisk_iter *itr) +{ + return itr->direction; +} diff --git a/libblkid/libfdisk/src/label.c b/libblkid/libfdisk/src/label.c new file mode 100644 index 000000000..750cfca55 --- /dev/null +++ b/libblkid/libfdisk/src/label.c @@ -0,0 +1,569 @@ + +#include "fdiskP.h" + + +/** + * SECTION: label + * @title: Label + * @short_description: disk label (PT) specific data and functions + * + * The fdisk_new_context() initializes all label drivers, and allocate + * per-label specific data struct. This concept allows to store label specific + * settings to the label driver independently on the currently active label + * driver. Note that label struct cannot be deallocated, so there is no + * reference counting for fdisk_label objects. All is destroyed by + * fdisk_unref_context() only. + * + * Anyway, all label drives share in-memory first sector. The function + * fdisk_create_disklabel() overwrites the sector. But it's possible that + * label driver also uses another buffers, for example GPT uses more than only + * the first sector. + * + * All label operations are in-memory only, except fdisk_write_disklabel(). + * + * All functions that use "struct fdisk_context" rather than "struct + * fdisk_label" use the currently active label driver. + */ + + +int fdisk_probe_labels(struct fdisk_context *cxt) +{ + size_t i; + + cxt->label = NULL; + + for (i = 0; i < cxt->nlabels; i++) { + struct fdisk_label *lb = cxt->labels[i]; + struct fdisk_label *org = fdisk_get_label(cxt, NULL); + int rc; + + if (!lb->op->probe) + continue; + if (lb->disabled) { + DBG(CXT, ul_debugobj(cxt, "%s: disabled -- ignore", lb->name)); + continue; + } + DBG(CXT, ul_debugobj(cxt, "probing for %s", lb->name)); + + cxt->label = lb; + rc = lb->op->probe(cxt); + cxt->label = org; + + if (rc != 1) { + if (lb->op->deinit) + lb->op->deinit(lb); /* for sure */ + continue; + } + + __fdisk_switch_label(cxt, lb); + return 0; + } + + DBG(CXT, ul_debugobj(cxt, "no label found")); + return 1; /* not found */ +} + +/** + * fdisk_label_get_name: + * @lb: label + * + * Returns: label name + */ +const char *fdisk_label_get_name(const struct fdisk_label *lb) +{ + return lb ? lb->name : NULL; +} + +/** + * fdisk_label_is_labeltype: + * @lb: label + * + * Returns: FDISK_DISKLABEL_*. + */ +int fdisk_label_get_type(const struct fdisk_label *lb) +{ + return lb->id; +} + +/** + * fdisk_label_require_geometry: + * @lb: label + * + * Returns: 1 if label requires CHS geometry + */ +int fdisk_label_require_geometry(const struct fdisk_label *lb) +{ + assert(lb); + + return lb->flags & FDISK_LABEL_FL_REQUIRE_GEOMETRY ? 1 : 0; +} + +/** + * fdisk_label_get_fields_ids + * @lb: label (or NULL for the current label) + * @cxt: context + * @ids: returns allocated array with FDISK_FIELD_* IDs + * @nids: returns number of items in fields + * + * This function returns the default fields for the label. + * + * Note that the set of the default fields depends on fdisk_enable_details() + * function. If the details are enabled then this function usually returns more + * fields. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_label_get_fields_ids( + const struct fdisk_label *lb, + struct fdisk_context *cxt, + int **ids, size_t *nids) +{ + size_t i, n; + int *c; + + assert(cxt); + + if (!lb) + lb = cxt->label; + if (!lb) + return -EINVAL; + if (!lb->fields || !lb->nfields) + return -ENOSYS; + c = calloc(lb->nfields, sizeof(int)); + if (!c) + return -ENOMEM; + for (n = 0, i = 0; i < lb->nfields; i++) { + int id = lb->fields[i].id; + + if ((fdisk_is_details(cxt) && + (lb->fields[i].flags & FDISK_FIELDFL_EYECANDY)) + || (!fdisk_is_details(cxt) && + (lb->fields[i].flags & FDISK_FIELDFL_DETAIL)) + || (id == FDISK_FIELD_SECTORS && + fdisk_use_cylinders(cxt)) + || (id == FDISK_FIELD_CYLINDERS && + !fdisk_use_cylinders(cxt))) + continue; + + c[n++] = id; + } + if (ids) + *ids = c; + else + free(c); + if (nids) + *nids = n; + return 0; +} + +/** + * fdisk_label_get_field: + * @lb: label + * @id: FDISK_FIELD_* + * + * The field struct describes data stored in struct fdisk_partition. The info + * about data is usable for example to generate human readable output (e.g. + * fdisk 'p'rint command). See fdisk_partition_to_stirng() and fdisk code. + * + * Returns: pointer to static instance of the field. + */ +const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id) +{ + size_t i; + + assert(lb); + assert(id > 0); + + for (i = 0; i < lb->nfields; i++) { + if (lb->fields[i].id == id) + return &lb->fields[i]; + } + + return NULL; +} + +/** + * fdisk_label_get_field_by_name + * @lb: label + * @name: field name + * + * Returns: pointer to static instance of the field. + */ +const struct fdisk_field *fdisk_label_get_field_by_name( + const struct fdisk_label *lb, + const char *name) +{ + size_t i; + + assert(lb); + assert(name); + + for (i = 0; i < lb->nfields; i++) { + if (lb->fields[i].name && strcasecmp(lb->fields[i].name, name) == 0) + return &lb->fields[i]; + } + + return NULL; +} + + +/** + * fdisk_field_get_id: + * @field: field instance + * + * Returns: field Id (FDISK_FIELD_*) + */ +int fdisk_field_get_id(const struct fdisk_field *field) +{ + return field ? field->id : -EINVAL; +} + +/** + * fdisk_field_get_name: + * @field: field instance + * + * Returns: field name + */ +const char *fdisk_field_get_name(const struct fdisk_field *field) +{ + return field ? field->name : NULL; +} + +/** + * fdisk_field_get_width: + * @field: field instance + * + * Returns: libsmartcols compatible width. + */ +double fdisk_field_get_width(const struct fdisk_field *field) +{ + return field ? field->width : -EINVAL; +} + +/** + * fdisk_field_is_number: + * @field: field instance + * + * Returns: 1 if field represent number + */ +int fdisk_field_is_number(const struct fdisk_field *field) +{ + return field->flags ? field->flags & FDISK_FIELDFL_NUMBER : 0; +} + + +/** + * fdisk_write_disklabel: + * @cxt: fdisk context + * + * Write in-memory changes to disk. Be careful! + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_write_disklabel(struct fdisk_context *cxt) +{ + if (!cxt || !cxt->label || cxt->readonly) + return -EINVAL; + if (!cxt->label->op->write) + return -ENOSYS; + return cxt->label->op->write(cxt); +} + +/** + * fdisk_verify_disklabel: + * @cxt: fdisk context + * + * Verifies the partition table. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_verify_disklabel(struct fdisk_context *cxt) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->verify) + return -ENOSYS; + if (fdisk_missing_geometry(cxt)) + return -EINVAL; + + return cxt->label->op->verify(cxt); +} + +/** + * fdisk_list_disklabel: + * @cxt: fdisk context + * + * Lists details about disklabel, but no partitions. + * + * This function uses libfdisk ASK interface to print data. The details about + * partitions table are printed by FDISK_ASKTYPE_INFO. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_list_disklabel(struct fdisk_context *cxt) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->list) + return -ENOSYS; + + return cxt->label->op->list(cxt); +} + +/** + * fdisk_create_disklabel: + * @cxt: fdisk context + * @name: label name + * + * Creates a new disk label of type @name. If @name is NULL, then it will + * create a default system label type, either SUN or DOS. The function + * automaticaly switches the current label driver to @name. The function + * fdisk_get_label() returns the current label driver. + * + * The function modifies in-memory data only. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name) +{ + int haslabel = 0; + struct fdisk_label *lb; + + if (!cxt) + return -EINVAL; + + if (!name) { /* use default label creation */ +#ifdef __sparc__ + name = "sun"; +#else + name = "dos"; +#endif + } + + if (cxt->label) { + fdisk_deinit_label(cxt->label); + haslabel = 1; + } + + lb = fdisk_get_label(cxt, name); + if (!lb || lb->disabled) + return -EINVAL; + if (!lb->op->create) + return -ENOSYS; + + __fdisk_switch_label(cxt, lb); + + if (haslabel && !cxt->parent) + fdisk_reset_device_properties(cxt); + + DBG(CXT, ul_debugobj(cxt, "create a new %s label", lb->name)); + return cxt->label->op->create(cxt); +} + +/** + * fdisk_locate_disklabel: + * @cxt: context + * @n: N item + * @name: return item name + * @offset: return offset where is item + * @size: of the item + * + * Locate disklabel and returns info about @n item of the label. For example + * GPT is composed from two items, PMBR and GPT, n=0 return offset to PMBR and n=1 + * return offset to GPT. For more details see 'D' expect fdisk command. + * + * Returns: 0 on succes, <0 on error, 1 no more items. + */ +int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name, + off_t *offset, size_t *size) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->locate) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "locating %d chunk of %s.", n, cxt->label->name)); + return cxt->label->op->locate(cxt, n, name, offset, size); +} + + +/** + * fdisk_get_disklabel_id: + * @cxt: fdisk context + * @id: returns pointer to allocated string (MBR Id or GPT dirk UUID) + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->get_id) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "asking for disk %s ID", cxt->label->name)); + return cxt->label->op->get_id(cxt, id); +} + +/** + * fdisk_set_disklabel_id: + * @cxt: fdisk context + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_set_disklabel_id(struct fdisk_context *cxt) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->set_id) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "setting %s disk ID", cxt->label->name)); + return cxt->label->op->set_id(cxt); +} + +/** + * fdisk_set_partition_type: + * @cxt: fdisk context + * @partnum: partition number + * @t: new type + * + * Returns: 0 on success, < 0 on error. + */ +int fdisk_set_partition_type(struct fdisk_context *cxt, + size_t partnum, + struct fdisk_parttype *t) +{ + if (!cxt || !cxt->label || !t) + return -EINVAL; + + + if (cxt->label->op->set_part) { + struct fdisk_partition *pa = fdisk_new_partition(); + int rc; + + if (!pa) + return -ENOMEM; + fdisk_partition_set_type(pa, t); + + DBG(CXT, ul_debugobj(cxt, "partition: %zd: set type", partnum)); + rc = cxt->label->op->set_part(cxt, partnum, pa); + fdisk_unref_partition(pa); + return rc; + } + + return -ENOSYS; +} + + +/** + * fdisk_toggle_partition_flag: + * @cxt: fdisk context + * @partnum: partition number + * @flag: flag ID + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_toggle_partition_flag(struct fdisk_context *cxt, + size_t partnum, + unsigned long flag) +{ + int rc; + + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->part_toggle_flag) + return -ENOSYS; + + rc = cxt->label->op->part_toggle_flag(cxt, partnum, flag); + + DBG(CXT, ul_debugobj(cxt, "partition: %zd: toggle: 0x%04lx [rc=%d]", partnum, flag, rc)); + return rc; +} + +/** + * fdisk_reorder_partitions + * @cxt: fdisk context + * + * Sort partitions according to the partition start sector. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_reorder_partitions(struct fdisk_context *cxt) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->reorder) + return -ENOSYS; + + return cxt->label->op->reorder(cxt); +} + +/* + * Resets the current used label driver to initial state + */ +void fdisk_deinit_label(struct fdisk_label *lb) +{ + assert(lb); + + /* private label information */ + if (lb->op->deinit) + lb->op->deinit(lb); +} + +/** + * fdisk_label_set_changed: + * @lb: label + * @changed: 0/1 + * + * Marks in-memory data as changed, to force fdisk_write_disklabel() to write + * to device. This should be unnecessar by default, the library keeps track + * about changes. + */ +void fdisk_label_set_changed(struct fdisk_label *lb, int changed) +{ + assert(lb); + lb->changed = changed ? 1 : 0; +} + +/** + * fdisk_label_is_changed: + * @lb: label + * + * Returns: 1 if in-memory data has been changed. + */ +int fdisk_label_is_changed(const struct fdisk_label *lb) +{ + assert(lb); + return lb ? lb->changed : 0; +} + +/** + * fdisk_label_set_disabled: + * @lb: label + * @disabled: 0 or 1 + * + * Mark label as disabled, then libfdisk is going to ignore the label when + * probe device for labels. + */ +void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled) +{ + assert(lb); + + DBG(LABEL, ul_debug("%s label %s", + lb->name, + disabled ? "DISABLED" : "ENABLED")); + lb->disabled = disabled ? 1 : 0; +} + +/** + * fdisk_label_is_disabled: + * @lb: label + * + * Returns: 1 if label driver disabled. + */ +int fdisk_label_is_disabled(const struct fdisk_label *lb) +{ + assert(lb); + return lb ? lb->disabled : 0; +} diff --git a/libblkid/libfdisk/src/libfdisk.h b/libblkid/libfdisk/src/libfdisk.h new file mode 100644 index 000000000..844e17e19 --- /dev/null +++ b/libblkid/libfdisk/src/libfdisk.h @@ -0,0 +1,579 @@ +/* + * libfdisk.h - libfdisk API + * + * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com> + * + * 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LIBFDISK_H +#define _LIBFDISK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> + +/** + * LIBFDISK_VERSION: + * + * Library version string + */ +#define LIBFDISK_VERSION "2.25.0" + +/** + * fdisk_context: + * + * Basic library handler. + */ +struct fdisk_context; + +/** + * fdisk_label: + * + * Disk label specific driver and setting. + */ +struct fdisk_label; + +/** + * fdisk_parttype: + * + * Partition type. + */ +struct fdisk_parttype; + +/** + * fdisk_partition: + * + * Partition abstraction (and template). + */ +struct fdisk_partition; + +/** + * fdisk_ask: + * + * Ask API handler for dialogs with users. + */ +struct fdisk_ask; + +/** + * fdisk_iter: + * + * Unified iterator. + */ +struct fdisk_iter; + +/** + * fdisk_table: + * + * Container for fdisk_partition objects + */ +struct fdisk_table; + +/** + * fdisk_field + * + * Output field description. + */ +struct fdisk_field; + +/** + * fdisk_script + * + * library handler for sfdisk compatible scripts + */ +struct fdisk_script; + +/** + * fdisk_sector_t + * + * LBA adresses type + */ +typedef uint64_t fdisk_sector_t; + +/** + * fdisk_labeltype: + * + * Supported partition table types (labels) + */ +enum fdisk_labeltype { + FDISK_DISKLABEL_DOS = (1 << 1), + FDISK_DISKLABEL_SUN = (1 << 2), + FDISK_DISKLABEL_SGI = (1 << 3), + FDISK_DISKLABEL_BSD = (1 << 4), + FDISK_DISKLABEL_GPT = (1 << 5) +}; + +/** + * fdisk_asktype: + * + * Ask API dialog types + */ +enum fdisk_asktype { + FDISK_ASKTYPE_NONE = 0, + FDISK_ASKTYPE_NUMBER, + FDISK_ASKTYPE_OFFSET, + FDISK_ASKTYPE_WARN, + FDISK_ASKTYPE_WARNX, + FDISK_ASKTYPE_INFO, + FDISK_ASKTYPE_YESNO, + FDISK_ASKTYPE_STRING, + FDISK_ASKTYPE_MENU +}; + +/* init.c */ +extern void fdisk_init_debug(int mask); + +/* context.h */ + +#define FDISK_PLURAL 0 +#define FDISK_SINGULAR 1 + +struct fdisk_context *fdisk_new_context(void); +struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name); +void fdisk_unref_context(struct fdisk_context *cxt); +void fdisk_ref_context(struct fdisk_context *cxt); + +struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt); +size_t fdisk_get_npartitions(struct fdisk_context *cxt); + +struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name); +int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb); +size_t fdisk_get_nlabels(struct fdisk_context *cxt); + +int fdisk_has_label(struct fdisk_context *cxt); +int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id); +#define fdisk_is_label(c, x) fdisk_is_labeltype(c, FDISK_DISKLABEL_ ## x) + + +int fdisk_assign_device(struct fdisk_context *cxt, + const char *fname, int readonly); +int fdisk_deassign_device(struct fdisk_context *cxt, int nosync); +int fdisk_is_readonly(struct fdisk_context *cxt); + +int fdisk_enable_details(struct fdisk_context *cxt, int enable); +int fdisk_is_details(struct fdisk_context *cxt); + +int fdisk_enable_listonly(struct fdisk_context *cxt, int enable); +int fdisk_is_listonly(struct fdisk_context *cxt); + +int fdisk_set_unit(struct fdisk_context *cxt, const char *str); +const char *fdisk_get_unit(struct fdisk_context *cxt, int n); +int fdisk_use_cylinders(struct fdisk_context *cxt); +unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt); + +unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt); +unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt); +unsigned long fdisk_get_physector_size(struct fdisk_context *cxt); +unsigned long fdisk_get_sector_size(struct fdisk_context *cxt); +unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt); +unsigned long fdisk_get_grain_size(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt); +fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba); +fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt); +fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba); +fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt); +const char *fdisk_get_devname(struct fdisk_context *cxt); +int fdisk_get_devfd(struct fdisk_context *cxt); + +unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt); + + + +/* parttype.c */ +struct fdisk_parttype *fdisk_new_parttype(void); +void fdisk_ref_parttype(struct fdisk_parttype *t); +void fdisk_unref_parttype(struct fdisk_parttype *t); +int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str); +int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str); +int fdisk_parttype_set_code(struct fdisk_parttype *t, int code); +size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb); +struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n); +int fdisk_label_has_code_parttypes(const struct fdisk_label *lb); +struct fdisk_parttype *fdisk_label_get_parttype_from_code( + const struct fdisk_label *lb, + unsigned int code); +struct fdisk_parttype *fdisk_label_get_parttype_from_string( + const struct fdisk_label *lb, + const char *str); +struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code, + const char *typestr); +struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type); +struct fdisk_parttype *fdisk_label_parse_parttype( + const struct fdisk_label *lb, + const char *str); +const char *fdisk_parttype_get_string(const struct fdisk_parttype *t); +unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t); +const char *fdisk_parttype_get_name(const struct fdisk_parttype *t); +int fdisk_parttype_is_unknown(const struct fdisk_parttype *t); + +/* label.c */ + +/** + * fdisk_fieldtype + * + * Types of fdisk_field + */ +enum fdisk_fieldtype { + FDISK_FIELD_NONE = 0, + + /* generic */ + FDISK_FIELD_DEVICE, + FDISK_FIELD_START, + FDISK_FIELD_END, + FDISK_FIELD_SECTORS, + FDISK_FIELD_CYLINDERS, + FDISK_FIELD_SIZE, + FDISK_FIELD_TYPE, + FDISK_FIELD_TYPEID, + + /* label specific */ + FDISK_FIELD_ATTR, + FDISK_FIELD_BOOT, + FDISK_FIELD_BSIZE, + FDISK_FIELD_CPG, + FDISK_FIELD_EADDR, + FDISK_FIELD_FSIZE, + FDISK_FIELD_NAME, + FDISK_FIELD_SADDR, + FDISK_FIELD_UUID, + + FDISK_NFIELDS /* must be last */ +}; + +int fdisk_label_get_type(const struct fdisk_label *lb); +const char *fdisk_label_get_name(const struct fdisk_label *lb); +int fdisk_label_require_geometry(const struct fdisk_label *lb); + + +extern int fdisk_write_disklabel(struct fdisk_context *cxt); +extern int fdisk_verify_disklabel(struct fdisk_context *cxt); +extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name); +extern int fdisk_list_disklabel(struct fdisk_context *cxt); +extern int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size); + +extern int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id); +extern int fdisk_set_disklabel_id(struct fdisk_context *cxt); + +extern int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition **pa); +extern int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition *pa); +extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa, size_t *partno); +extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno); + +extern int fdisk_delete_all_partitions(struct fdisk_context *cxt); + +extern int fdisk_set_partition_type(struct fdisk_context *cxt, size_t partnum, + struct fdisk_parttype *t); + + +extern int fdisk_label_get_fields_ids( + const struct fdisk_label *lb, + struct fdisk_context *cxt, + int **ids, size_t *nids); + +extern const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id); +extern const struct fdisk_field *fdisk_label_get_field_by_name( + const struct fdisk_label *lb, + const char *name); + +extern int fdisk_field_get_id(const struct fdisk_field *field); +extern const char *fdisk_field_get_name(const struct fdisk_field *field); +extern double fdisk_field_get_width(const struct fdisk_field *field); +extern int fdisk_field_is_number(const struct fdisk_field *field); + + +extern void fdisk_label_set_changed(struct fdisk_label *lb, int changed); +extern int fdisk_label_is_changed(const struct fdisk_label *lb); + +extern void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled); +extern int fdisk_label_is_disabled(const struct fdisk_label *lb); + +extern int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n); + +extern int fdisk_toggle_partition_flag(struct fdisk_context *cxt, size_t partnum, unsigned long flag); + +extern struct fdisk_partition *fdisk_new_partition(void); +extern void fdisk_reset_partition(struct fdisk_partition *pa); +extern void fdisk_ref_partition(struct fdisk_partition *pa); +extern void fdisk_unref_partition(struct fdisk_partition *pa); +extern int fdisk_partition_is_freespace(struct fdisk_partition *pa); + +int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off); +int fdisk_partition_unset_start(struct fdisk_partition *pa); +uint64_t fdisk_partition_get_start(struct fdisk_partition *pa); +int fdisk_partition_has_start(struct fdisk_partition *pa); +int fdisk_partition_cmp_start(struct fdisk_partition *a, + struct fdisk_partition *b); +int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable); +int fdisk_partition_start_is_default(struct fdisk_partition *pa); + +int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t sz); +int fdisk_partition_unset_size(struct fdisk_partition *pa); +uint64_t fdisk_partition_get_size(struct fdisk_partition *pa); +int fdisk_partition_has_size(struct fdisk_partition *pa); +int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable); + +int fdisk_partition_has_end(struct fdisk_partition *pa); +fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa); + +int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num); +int fdisk_partition_unset_partno(struct fdisk_partition *pa); +size_t fdisk_partition_get_partno(struct fdisk_partition *pa); +int fdisk_partition_has_partno(struct fdisk_partition *pa); +int fdisk_partition_cmp_partno(struct fdisk_partition *a, + struct fdisk_partition *b); +int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable); + + +extern int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type); +extern struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa); +extern int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name); +extern const char *fdisk_partition_get_name(struct fdisk_partition *pa); +extern int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid); +extern int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs); +extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa); +extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa); +extern int fdisk_partition_is_nested(struct fdisk_partition *pa); +extern int fdisk_partition_is_container(struct fdisk_partition *pa); +extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent); +extern int fdisk_partition_is_used(struct fdisk_partition *pa); +extern int fdisk_partition_is_bootable(struct fdisk_partition *pa); +extern int fdisk_partition_to_string(struct fdisk_partition *pa, + struct fdisk_context *cxt, + int id, char **data); + +int fdisk_partition_next_partno(struct fdisk_partition *pa, + struct fdisk_context *cxt, + size_t *n); + +extern int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable); +extern int fdisk_partition_end_is_default(struct fdisk_partition *pa); + +extern int fdisk_reorder_partitions(struct fdisk_context *cxt); + +/* table.c */ +extern struct fdisk_table *fdisk_new_table(void); +extern int fdisk_reset_table(struct fdisk_table *tb); +extern void fdisk_ref_table(struct fdisk_table *tb); +extern void fdisk_unref_table(struct fdisk_table *tb); +extern size_t fdisk_table_get_nents(struct fdisk_table *tb); +extern int fdisk_table_is_empty(struct fdisk_table *tb); +extern int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa); +extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa); + +extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb); +extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb); + +extern int fdisk_table_wrong_order(struct fdisk_table *tb); +extern int fdisk_table_sort_partitions(struct fdisk_table *tb, + int (*cmp)(struct fdisk_partition *, + struct fdisk_partition *)); + +extern int fdisk_table_next_partition( + struct fdisk_table *tb, + struct fdisk_iter *itr, + struct fdisk_partition **pa); + +extern struct fdisk_partition *fdisk_table_get_partition( + struct fdisk_table *tb, + size_t n); +extern int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb); + +/* alignment.c */ +#define FDISK_ALIGN_UP 1 +#define FDISK_ALIGN_DOWN 2 +#define FDISK_ALIGN_NEAREST 3 + +fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction); +fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, + fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop); +int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba); + +int fdisk_override_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors); +int fdisk_save_user_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors); +int fdisk_save_user_sector_size(struct fdisk_context *cxt, + unsigned int phy, + unsigned int log); +int fdisk_has_user_device_properties(struct fdisk_context *cxt); +int fdisk_reset_alignment(struct fdisk_context *cxt); +int fdisk_reset_device_properties(struct fdisk_context *cxt); +int fdisk_reread_partition_table(struct fdisk_context *cxt); + +/* iter.c */ +enum { + + FDISK_ITER_FORWARD = 0, + FDISK_ITER_BACKWARD +}; +extern struct fdisk_iter *fdisk_new_iter(int direction); +extern void fdisk_free_iter(struct fdisk_iter *itr); +extern void fdisk_reset_iter(struct fdisk_iter *itr, int direction); +extern int fdisk_iter_get_direction(struct fdisk_iter *itr); + + +/* dos.c */ +#define DOS_FLAG_ACTIVE 1 + +extern int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i); +extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable); +extern int fdisk_dos_is_compatible(struct fdisk_label *lb); + +/* sun.h */ +extern int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt); +extern int fdisk_sun_set_xcyl(struct fdisk_context *cxt); +extern int fdisk_sun_set_ilfact(struct fdisk_context *cxt); +extern int fdisk_sun_set_rspeed(struct fdisk_context *cxt); +extern int fdisk_sun_set_pcylcount(struct fdisk_context *cxt); + +/* bsd.c */ +extern int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt); +extern int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt); +extern int fdisk_bsd_link_partition(struct fdisk_context *cxt); + +/* sgi.h */ +#define SGI_FLAG_BOOT 1 +#define SGI_FLAG_SWAP 2 +extern int fdisk_sgi_set_bootfile(struct fdisk_context *cxt); +extern int fdisk_sgi_create_info(struct fdisk_context *cxt); + +/* gpt */ + +/* GPT partition attributes */ +enum { + /* System partition (disk partitioning utilities must preserve the + * partition as is) */ + GPT_FLAG_REQUIRED = 1, + + /* EFI firmware should ignore the content of the partition and not try + * to read from it */ + GPT_FLAG_NOBLOCK, + + /* Legacy BIOS bootable */ + GPT_FLAG_LEGACYBOOT, + + /* bites 48-63, Defined and used by the individual partition type. + * + * The flag GPT_FLAG_GUIDSPECIFIC forces libfdisk to ask (by ask API) + * for a bit number. If you want to toggle specific bit and avoid any + * dialog, then use the bit number (in range 48..63). For example: + * + * // start dialog to ask for bit number + * fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_GUIDSPECIFIC); + * + * // toggle bit 60 + * fdisk_toggle_partition_flag(cxt, n, 60); + */ + GPT_FLAG_GUIDSPECIFIC +}; + +extern int fdisk_gpt_is_hybrid(struct fdisk_context *cxt); + + +/* script.c */ +struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt); +struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt, + const char *filename); +void fdisk_ref_script(struct fdisk_script *dp); +void fdisk_unref_script(struct fdisk_script *dp); + +const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name); +int fdisk_script_set_header(struct fdisk_script *dp, const char *name, const char *data); +struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp); +int fdisk_script_get_nlines(struct fdisk_script *dp); + +int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt); +int fdisk_script_write_file(struct fdisk_script *dp, FILE *f); +int fdisk_script_read_file(struct fdisk_script *dp, FILE *f); +int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz); + +int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp); +struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt); + +int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp); +int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp); + + +/* ask.c */ +#define fdisk_is_ask(a, x) (fdisk_ask_get_type(a) == FDISK_ASKTYPE_ ## x) + +int fdisk_set_ask(struct fdisk_context *cxt, + int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *), + void *data); + + +void fdisk_ref_ask(struct fdisk_ask *ask); +void fdisk_unref_ask(struct fdisk_ask *ask); +const char *fdisk_ask_get_query(struct fdisk_ask *ask); +int fdisk_ask_get_type(struct fdisk_ask *ask); +const char *fdisk_ask_number_get_range(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask); +int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result); +uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask); +int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative); +int fdisk_ask_number_inchars(struct fdisk_ask *ask); +int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew); + +int fdisk_ask_number(struct fdisk_context *cxt, + uintmax_t low, + uintmax_t dflt, + uintmax_t high, + const char *query, + uintmax_t *result); +char *fdisk_ask_string_get_result(struct fdisk_ask *ask); +int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result); +int fdisk_ask_string(struct fdisk_context *cxt, + const char *query, + char **result); +int fdisk_ask_yesno(struct fdisk_context *cxt, + const char *query, + int *result); +int fdisk_ask_yesno_get_result(struct fdisk_ask *ask); +int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result); +int fdisk_ask_menu_get_default(struct fdisk_ask *ask); +int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key); +int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key); +int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key, + const char **name, const char **desc); +size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask); +int fdisk_ask_print_get_errno(struct fdisk_ask *ask); +const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask); + +int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...); +int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...); +int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...); + +/* utils.h */ +extern char *fdisk_partname(const char *dev, size_t partno); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBFDISK_H */ diff --git a/libblkid/libfdisk/src/libfdisk.h.in b/libblkid/libfdisk/src/libfdisk.h.in new file mode 100644 index 000000000..f82d5bd97 --- /dev/null +++ b/libblkid/libfdisk/src/libfdisk.h.in @@ -0,0 +1,579 @@ +/* + * libfdisk.h - libfdisk API + * + * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com> + * + * 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LIBFDISK_H +#define _LIBFDISK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> + +/** + * LIBFDISK_VERSION: + * + * Library version string + */ +#define LIBFDISK_VERSION "@LIBFDISK_VERSION@" + +/** + * fdisk_context: + * + * Basic library handler. + */ +struct fdisk_context; + +/** + * fdisk_label: + * + * Disk label specific driver and setting. + */ +struct fdisk_label; + +/** + * fdisk_parttype: + * + * Partition type. + */ +struct fdisk_parttype; + +/** + * fdisk_partition: + * + * Partition abstraction (and template). + */ +struct fdisk_partition; + +/** + * fdisk_ask: + * + * Ask API handler for dialogs with users. + */ +struct fdisk_ask; + +/** + * fdisk_iter: + * + * Unified iterator. + */ +struct fdisk_iter; + +/** + * fdisk_table: + * + * Container for fdisk_partition objects + */ +struct fdisk_table; + +/** + * fdisk_field + * + * Output field description. + */ +struct fdisk_field; + +/** + * fdisk_script + * + * library handler for sfdisk compatible scripts + */ +struct fdisk_script; + +/** + * fdisk_sector_t + * + * LBA adresses type + */ +typedef uint64_t fdisk_sector_t; + +/** + * fdisk_labeltype: + * + * Supported partition table types (labels) + */ +enum fdisk_labeltype { + FDISK_DISKLABEL_DOS = (1 << 1), + FDISK_DISKLABEL_SUN = (1 << 2), + FDISK_DISKLABEL_SGI = (1 << 3), + FDISK_DISKLABEL_BSD = (1 << 4), + FDISK_DISKLABEL_GPT = (1 << 5) +}; + +/** + * fdisk_asktype: + * + * Ask API dialog types + */ +enum fdisk_asktype { + FDISK_ASKTYPE_NONE = 0, + FDISK_ASKTYPE_NUMBER, + FDISK_ASKTYPE_OFFSET, + FDISK_ASKTYPE_WARN, + FDISK_ASKTYPE_WARNX, + FDISK_ASKTYPE_INFO, + FDISK_ASKTYPE_YESNO, + FDISK_ASKTYPE_STRING, + FDISK_ASKTYPE_MENU +}; + +/* init.c */ +extern void fdisk_init_debug(int mask); + +/* context.h */ + +#define FDISK_PLURAL 0 +#define FDISK_SINGULAR 1 + +struct fdisk_context *fdisk_new_context(void); +struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name); +void fdisk_unref_context(struct fdisk_context *cxt); +void fdisk_ref_context(struct fdisk_context *cxt); + +struct fdisk_context *fdisk_get_parent(struct fdisk_context *cxt); +size_t fdisk_get_npartitions(struct fdisk_context *cxt); + +struct fdisk_label *fdisk_get_label(struct fdisk_context *cxt, const char *name); +int fdisk_next_label(struct fdisk_context *cxt, struct fdisk_label **lb); +size_t fdisk_get_nlabels(struct fdisk_context *cxt); + +int fdisk_has_label(struct fdisk_context *cxt); +int fdisk_is_labeltype(struct fdisk_context *cxt, enum fdisk_labeltype id); +#define fdisk_is_label(c, x) fdisk_is_labeltype(c, FDISK_DISKLABEL_ ## x) + + +int fdisk_assign_device(struct fdisk_context *cxt, + const char *fname, int readonly); +int fdisk_deassign_device(struct fdisk_context *cxt, int nosync); +int fdisk_is_readonly(struct fdisk_context *cxt); + +int fdisk_enable_details(struct fdisk_context *cxt, int enable); +int fdisk_is_details(struct fdisk_context *cxt); + +int fdisk_enable_listonly(struct fdisk_context *cxt, int enable); +int fdisk_is_listonly(struct fdisk_context *cxt); + +int fdisk_set_unit(struct fdisk_context *cxt, const char *str); +const char *fdisk_get_unit(struct fdisk_context *cxt, int n); +int fdisk_use_cylinders(struct fdisk_context *cxt); +unsigned int fdisk_get_units_per_sector(struct fdisk_context *cxt); + +unsigned long fdisk_get_optimal_iosize(struct fdisk_context *cxt); +unsigned long fdisk_get_minimal_iosize(struct fdisk_context *cxt); +unsigned long fdisk_get_physector_size(struct fdisk_context *cxt); +unsigned long fdisk_get_sector_size(struct fdisk_context *cxt); +unsigned long fdisk_get_alignment_offset(struct fdisk_context *cxt); +unsigned long fdisk_get_grain_size(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_first_lba(struct fdisk_context *cxt); +fdisk_sector_t fdisk_set_first_lba(struct fdisk_context *cxt, fdisk_sector_t lba); +fdisk_sector_t fdisk_get_last_lba(struct fdisk_context *cxt); +fdisk_sector_t fdisk_set_last_lba(struct fdisk_context *cxt, fdisk_sector_t lba); +fdisk_sector_t fdisk_get_nsectors(struct fdisk_context *cxt); +const char *fdisk_get_devname(struct fdisk_context *cxt); +int fdisk_get_devfd(struct fdisk_context *cxt); + +unsigned int fdisk_get_geom_heads(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_geom_sectors(struct fdisk_context *cxt); +fdisk_sector_t fdisk_get_geom_cylinders(struct fdisk_context *cxt); + + + +/* parttype.c */ +struct fdisk_parttype *fdisk_new_parttype(void); +void fdisk_ref_parttype(struct fdisk_parttype *t); +void fdisk_unref_parttype(struct fdisk_parttype *t); +int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str); +int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str); +int fdisk_parttype_set_code(struct fdisk_parttype *t, int code); +size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb); +struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n); +int fdisk_label_has_code_parttypes(const struct fdisk_label *lb); +struct fdisk_parttype *fdisk_label_get_parttype_from_code( + const struct fdisk_label *lb, + unsigned int code); +struct fdisk_parttype *fdisk_label_get_parttype_from_string( + const struct fdisk_label *lb, + const char *str); +struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code, + const char *typestr); +struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type); +struct fdisk_parttype *fdisk_label_parse_parttype( + const struct fdisk_label *lb, + const char *str); +const char *fdisk_parttype_get_string(const struct fdisk_parttype *t); +unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t); +const char *fdisk_parttype_get_name(const struct fdisk_parttype *t); +int fdisk_parttype_is_unknown(const struct fdisk_parttype *t); + +/* label.c */ + +/** + * fdisk_fieldtype + * + * Types of fdisk_field + */ +enum fdisk_fieldtype { + FDISK_FIELD_NONE = 0, + + /* generic */ + FDISK_FIELD_DEVICE, + FDISK_FIELD_START, + FDISK_FIELD_END, + FDISK_FIELD_SECTORS, + FDISK_FIELD_CYLINDERS, + FDISK_FIELD_SIZE, + FDISK_FIELD_TYPE, + FDISK_FIELD_TYPEID, + + /* label specific */ + FDISK_FIELD_ATTR, + FDISK_FIELD_BOOT, + FDISK_FIELD_BSIZE, + FDISK_FIELD_CPG, + FDISK_FIELD_EADDR, + FDISK_FIELD_FSIZE, + FDISK_FIELD_NAME, + FDISK_FIELD_SADDR, + FDISK_FIELD_UUID, + + FDISK_NFIELDS /* must be last */ +}; + +int fdisk_label_get_type(const struct fdisk_label *lb); +const char *fdisk_label_get_name(const struct fdisk_label *lb); +int fdisk_label_require_geometry(const struct fdisk_label *lb); + + +extern int fdisk_write_disklabel(struct fdisk_context *cxt); +extern int fdisk_verify_disklabel(struct fdisk_context *cxt); +extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name); +extern int fdisk_list_disklabel(struct fdisk_context *cxt); +extern int fdisk_locate_disklabel(struct fdisk_context *cxt, int n, const char **name, off_t *offset, size_t *size); + +extern int fdisk_get_disklabel_id(struct fdisk_context *cxt, char **id); +extern int fdisk_set_disklabel_id(struct fdisk_context *cxt); + +extern int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition **pa); +extern int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition *pa); +extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa, size_t *partno); +extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno); + +extern int fdisk_delete_all_partitions(struct fdisk_context *cxt); + +extern int fdisk_set_partition_type(struct fdisk_context *cxt, size_t partnum, + struct fdisk_parttype *t); + + +extern int fdisk_label_get_fields_ids( + const struct fdisk_label *lb, + struct fdisk_context *cxt, + int **ids, size_t *nids); + +extern const struct fdisk_field *fdisk_label_get_field(const struct fdisk_label *lb, int id); +extern const struct fdisk_field *fdisk_label_get_field_by_name( + const struct fdisk_label *lb, + const char *name); + +extern int fdisk_field_get_id(const struct fdisk_field *field); +extern const char *fdisk_field_get_name(const struct fdisk_field *field); +extern double fdisk_field_get_width(const struct fdisk_field *field); +extern int fdisk_field_is_number(const struct fdisk_field *field); + + +extern void fdisk_label_set_changed(struct fdisk_label *lb, int changed); +extern int fdisk_label_is_changed(const struct fdisk_label *lb); + +extern void fdisk_label_set_disabled(struct fdisk_label *lb, int disabled); +extern int fdisk_label_is_disabled(const struct fdisk_label *lb); + +extern int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n); + +extern int fdisk_toggle_partition_flag(struct fdisk_context *cxt, size_t partnum, unsigned long flag); + +extern struct fdisk_partition *fdisk_new_partition(void); +extern void fdisk_reset_partition(struct fdisk_partition *pa); +extern void fdisk_ref_partition(struct fdisk_partition *pa); +extern void fdisk_unref_partition(struct fdisk_partition *pa); +extern int fdisk_partition_is_freespace(struct fdisk_partition *pa); + +int fdisk_partition_set_start(struct fdisk_partition *pa, uint64_t off); +int fdisk_partition_unset_start(struct fdisk_partition *pa); +uint64_t fdisk_partition_get_start(struct fdisk_partition *pa); +int fdisk_partition_has_start(struct fdisk_partition *pa); +int fdisk_partition_cmp_start(struct fdisk_partition *a, + struct fdisk_partition *b); +int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable); +int fdisk_partition_start_is_default(struct fdisk_partition *pa); + +int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t sz); +int fdisk_partition_unset_size(struct fdisk_partition *pa); +uint64_t fdisk_partition_get_size(struct fdisk_partition *pa); +int fdisk_partition_has_size(struct fdisk_partition *pa); +int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable); + +int fdisk_partition_has_end(struct fdisk_partition *pa); +fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa); + +int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num); +int fdisk_partition_unset_partno(struct fdisk_partition *pa); +size_t fdisk_partition_get_partno(struct fdisk_partition *pa); +int fdisk_partition_has_partno(struct fdisk_partition *pa); +int fdisk_partition_cmp_partno(struct fdisk_partition *a, + struct fdisk_partition *b); +int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable); + + +extern int fdisk_partition_set_type(struct fdisk_partition *pa, struct fdisk_parttype *type); +extern struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa); +extern int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name); +extern const char *fdisk_partition_get_name(struct fdisk_partition *pa); +extern int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid); +extern int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs); +extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa); +extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa); +extern int fdisk_partition_is_nested(struct fdisk_partition *pa); +extern int fdisk_partition_is_container(struct fdisk_partition *pa); +extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent); +extern int fdisk_partition_is_used(struct fdisk_partition *pa); +extern int fdisk_partition_is_bootable(struct fdisk_partition *pa); +extern int fdisk_partition_to_string(struct fdisk_partition *pa, + struct fdisk_context *cxt, + int id, char **data); + +int fdisk_partition_next_partno(struct fdisk_partition *pa, + struct fdisk_context *cxt, + size_t *n); + +extern int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable); +extern int fdisk_partition_end_is_default(struct fdisk_partition *pa); + +extern int fdisk_reorder_partitions(struct fdisk_context *cxt); + +/* table.c */ +extern struct fdisk_table *fdisk_new_table(void); +extern int fdisk_reset_table(struct fdisk_table *tb); +extern void fdisk_ref_table(struct fdisk_table *tb); +extern void fdisk_unref_table(struct fdisk_table *tb); +extern size_t fdisk_table_get_nents(struct fdisk_table *tb); +extern int fdisk_table_is_empty(struct fdisk_table *tb); +extern int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa); +extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa); + +extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb); +extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb); + +extern int fdisk_table_wrong_order(struct fdisk_table *tb); +extern int fdisk_table_sort_partitions(struct fdisk_table *tb, + int (*cmp)(struct fdisk_partition *, + struct fdisk_partition *)); + +extern int fdisk_table_next_partition( + struct fdisk_table *tb, + struct fdisk_iter *itr, + struct fdisk_partition **pa); + +extern struct fdisk_partition *fdisk_table_get_partition( + struct fdisk_table *tb, + size_t n); +extern int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb); + +/* alignment.c */ +#define FDISK_ALIGN_UP 1 +#define FDISK_ALIGN_DOWN 2 +#define FDISK_ALIGN_NEAREST 3 + +fdisk_sector_t fdisk_align_lba(struct fdisk_context *cxt, fdisk_sector_t lba, int direction); +fdisk_sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, + fdisk_sector_t lba, fdisk_sector_t start, fdisk_sector_t stop); +int fdisk_lba_is_phy_aligned(struct fdisk_context *cxt, fdisk_sector_t lba); + +int fdisk_override_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors); +int fdisk_save_user_geometry(struct fdisk_context *cxt, + unsigned int cylinders, + unsigned int heads, + unsigned int sectors); +int fdisk_save_user_sector_size(struct fdisk_context *cxt, + unsigned int phy, + unsigned int log); +int fdisk_has_user_device_properties(struct fdisk_context *cxt); +int fdisk_reset_alignment(struct fdisk_context *cxt); +int fdisk_reset_device_properties(struct fdisk_context *cxt); +int fdisk_reread_partition_table(struct fdisk_context *cxt); + +/* iter.c */ +enum { + + FDISK_ITER_FORWARD = 0, + FDISK_ITER_BACKWARD +}; +extern struct fdisk_iter *fdisk_new_iter(int direction); +extern void fdisk_free_iter(struct fdisk_iter *itr); +extern void fdisk_reset_iter(struct fdisk_iter *itr, int direction); +extern int fdisk_iter_get_direction(struct fdisk_iter *itr); + + +/* dos.c */ +#define DOS_FLAG_ACTIVE 1 + +extern int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i); +extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable); +extern int fdisk_dos_is_compatible(struct fdisk_label *lb); + +/* sun.h */ +extern int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt); +extern int fdisk_sun_set_xcyl(struct fdisk_context *cxt); +extern int fdisk_sun_set_ilfact(struct fdisk_context *cxt); +extern int fdisk_sun_set_rspeed(struct fdisk_context *cxt); +extern int fdisk_sun_set_pcylcount(struct fdisk_context *cxt); + +/* bsd.c */ +extern int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt); +extern int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt); +extern int fdisk_bsd_link_partition(struct fdisk_context *cxt); + +/* sgi.h */ +#define SGI_FLAG_BOOT 1 +#define SGI_FLAG_SWAP 2 +extern int fdisk_sgi_set_bootfile(struct fdisk_context *cxt); +extern int fdisk_sgi_create_info(struct fdisk_context *cxt); + +/* gpt */ + +/* GPT partition attributes */ +enum { + /* System partition (disk partitioning utilities must preserve the + * partition as is) */ + GPT_FLAG_REQUIRED = 1, + + /* EFI firmware should ignore the content of the partition and not try + * to read from it */ + GPT_FLAG_NOBLOCK, + + /* Legacy BIOS bootable */ + GPT_FLAG_LEGACYBOOT, + + /* bites 48-63, Defined and used by the individual partition type. + * + * The flag GPT_FLAG_GUIDSPECIFIC forces libfdisk to ask (by ask API) + * for a bit number. If you want to toggle specific bit and avoid any + * dialog, then use the bit number (in range 48..63). For example: + * + * // start dialog to ask for bit number + * fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_GUIDSPECIFIC); + * + * // toggle bit 60 + * fdisk_toggle_partition_flag(cxt, n, 60); + */ + GPT_FLAG_GUIDSPECIFIC +}; + +extern int fdisk_gpt_is_hybrid(struct fdisk_context *cxt); + + +/* script.c */ +struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt); +struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt, + const char *filename); +void fdisk_ref_script(struct fdisk_script *dp); +void fdisk_unref_script(struct fdisk_script *dp); + +const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name); +int fdisk_script_set_header(struct fdisk_script *dp, const char *name, const char *data); +struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp); +int fdisk_script_get_nlines(struct fdisk_script *dp); + +int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt); +int fdisk_script_write_file(struct fdisk_script *dp, FILE *f); +int fdisk_script_read_file(struct fdisk_script *dp, FILE *f); +int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz); + +int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp); +struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt); + +int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp); +int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp); + + +/* ask.c */ +#define fdisk_is_ask(a, x) (fdisk_ask_get_type(a) == FDISK_ASKTYPE_ ## x) + +int fdisk_set_ask(struct fdisk_context *cxt, + int (*ask_cb)(struct fdisk_context *, struct fdisk_ask *, void *), + void *data); + + +void fdisk_ref_ask(struct fdisk_ask *ask); +void fdisk_unref_ask(struct fdisk_ask *ask); +const char *fdisk_ask_get_query(struct fdisk_ask *ask); +int fdisk_ask_get_type(struct fdisk_ask *ask); +const char *fdisk_ask_number_get_range(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_default(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_low(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_high(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_result(struct fdisk_ask *ask); +int fdisk_ask_number_set_result(struct fdisk_ask *ask, uint64_t result); +uint64_t fdisk_ask_number_get_base(struct fdisk_ask *ask); +uint64_t fdisk_ask_number_get_unit(struct fdisk_ask *ask); +int fdisk_ask_number_set_relative(struct fdisk_ask *ask, int relative); +int fdisk_ask_number_inchars(struct fdisk_ask *ask); +int fdisk_ask_partnum(struct fdisk_context *cxt, size_t *partnum, int wantnew); + +int fdisk_ask_number(struct fdisk_context *cxt, + uintmax_t low, + uintmax_t dflt, + uintmax_t high, + const char *query, + uintmax_t *result); +char *fdisk_ask_string_get_result(struct fdisk_ask *ask); +int fdisk_ask_string_set_result(struct fdisk_ask *ask, char *result); +int fdisk_ask_string(struct fdisk_context *cxt, + const char *query, + char **result); +int fdisk_ask_yesno(struct fdisk_context *cxt, + const char *query, + int *result); +int fdisk_ask_yesno_get_result(struct fdisk_ask *ask); +int fdisk_ask_yesno_set_result(struct fdisk_ask *ask, int result); +int fdisk_ask_menu_get_default(struct fdisk_ask *ask); +int fdisk_ask_menu_set_result(struct fdisk_ask *ask, int key); +int fdisk_ask_menu_get_result(struct fdisk_ask *ask, int *key); +int fdisk_ask_menu_get_item(struct fdisk_ask *ask, size_t idx, int *key, + const char **name, const char **desc); +size_t fdisk_ask_menu_get_nitems(struct fdisk_ask *ask); +int fdisk_ask_print_get_errno(struct fdisk_ask *ask); +const char *fdisk_ask_print_get_mesg(struct fdisk_ask *ask); + +int fdisk_info(struct fdisk_context *cxt, const char *fmt, ...); +int fdisk_warn(struct fdisk_context *cxt, const char *fmt, ...); +int fdisk_warnx(struct fdisk_context *cxt, const char *fmt, ...); + +/* utils.h */ +extern char *fdisk_partname(const char *dev, size_t partno); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBFDISK_H */ diff --git a/libblkid/libfdisk/src/libfdisk.sym b/libblkid/libfdisk/src/libfdisk.sym new file mode 100644 index 000000000..bf85d4e2a --- /dev/null +++ b/libblkid/libfdisk/src/libfdisk.sym @@ -0,0 +1,234 @@ +/* + * The symbol versioning ensures that a new application requiring symbol foo; + * can't run with old libblkid.so not providing foo; + * version info can't enforce this since we never change the SONAME. + * + * Copyright (C) 2014 Karel Zak <kzak@redhat.com> + */ +MOUNT_2.26 { +global: + fdisk_add_partition; + fdisk_align_lba; + fdisk_align_lba_in_range; + fdisk_apply_script; + fdisk_apply_script_headers; + fdisk_apply_table; + fdisk_ask_get_query; + fdisk_ask_get_type; + fdisk_ask_menu_get_default; + fdisk_ask_menu_get_item; + fdisk_ask_menu_get_nitems; + fdisk_ask_menu_get_result; + fdisk_ask_menu_set_result; + fdisk_ask_number; + fdisk_ask_number_get_base; + fdisk_ask_number_get_default; + fdisk_ask_number_get_high; + fdisk_ask_number_get_low; + fdisk_ask_number_get_range; + fdisk_ask_number_get_result; + fdisk_ask_number_get_unit; + fdisk_ask_number_inchars; + fdisk_ask_number_set_relative; + fdisk_ask_number_set_result; + fdisk_ask_partnum; + fdisk_ask_print_get_errno; + fdisk_ask_print_get_mesg; + fdisk_ask_string; + fdisk_ask_string_get_result; + fdisk_ask_string_set_result; + fdisk_ask_yesno; + fdisk_ask_yesno_get_result; + fdisk_ask_yesno_set_result; + fdisk_assign_device; + fdisk_bsd_edit_disklabel; + fdisk_bsd_link_partition; + fdisk_bsd_write_bootstrap; + fdisk_copy_parttype; + fdisk_create_disklabel; + fdisk_deassign_device; + fdisk_delete_all_partitions; + fdisk_delete_partition; + fdisk_dos_enable_compatible; + fdisk_dos_is_compatible; + fdisk_dos_move_begin; + fdisk_enable_details; + fdisk_enable_listonly; + fdisk_field_get_id; + fdisk_field_get_name; + fdisk_field_get_width; + fdisk_field_is_number; + fdisk_free_iter; + fdisk_get_alignment_offset; + fdisk_get_devfd; + fdisk_get_devname; + fdisk_get_disklabel_id; + fdisk_get_first_lba; + fdisk_get_freespaces; + fdisk_get_geom_cylinders; + fdisk_get_geom_heads; + fdisk_get_geom_sectors; + fdisk_get_grain_size; + fdisk_get_label; + fdisk_get_last_lba; + fdisk_get_minimal_iosize; + fdisk_get_nlabels; + fdisk_get_npartitions; + fdisk_get_nsectors; + fdisk_get_optimal_iosize; + fdisk_get_parent; + fdisk_get_partition; + fdisk_get_partitions; + fdisk_get_physector_size; + fdisk_get_script; + fdisk_get_sector_size; + fdisk_get_unit; + fdisk_get_units_per_sector; + fdisk_gpt_is_hybrid; + fdisk_has_label; + fdisk_has_user_device_properties; + fdisk_info; + fdisk_init_debug; + fdisk_is_details; + fdisk_is_labeltype; + fdisk_is_listonly; + fdisk_is_partition_used; + fdisk_is_readonly; + fdisk_iter_get_direction; + fdisk_label_get_field; + fdisk_label_get_field_by_name; + fdisk_label_get_fields_ids; + fdisk_label_get_name; + fdisk_label_get_nparttypes; + fdisk_label_get_parttype; + fdisk_label_get_parttype_from_code; + fdisk_label_get_parttype_from_string; + fdisk_label_get_type; + fdisk_label_has_code_parttypes; + fdisk_label_is_changed; + fdisk_label_is_disabled; + fdisk_label_parse_parttype; + fdisk_label_require_geometry; + fdisk_label_set_changed; + fdisk_label_set_disabled; + fdisk_lba_is_phy_aligned; + fdisk_list_disklabel; + fdisk_locate_disklabel; + fdisk_new_context; + fdisk_new_iter; + fdisk_new_nested_context; + fdisk_new_partition; + fdisk_new_parttype; + fdisk_new_script; + fdisk_new_script_from_file; + fdisk_new_table; + fdisk_new_unknown_parttype; + fdisk_next_label; + fdisk_override_geometry; + fdisk_partition_cmp_partno; + fdisk_partition_cmp_start; + fdisk_partition_end_follow_default; + fdisk_partition_end_is_default; + fdisk_partition_get_attrs; + fdisk_partition_get_end; + fdisk_partition_get_name; + fdisk_partition_get_parent; + fdisk_partition_get_partno; + fdisk_partition_get_size; + fdisk_partition_get_start; + fdisk_partition_get_type; + fdisk_partition_get_uuid; + fdisk_partition_has_end; + fdisk_partition_has_partno; + fdisk_partition_has_size; + fdisk_partition_has_start; + fdisk_partition_is_bootable; + fdisk_partition_is_container; + fdisk_partition_is_freespace; + fdisk_partition_is_nested; + fdisk_partition_is_used; + fdisk_partition_next_partno; + fdisk_partition_partno_follow_default; + fdisk_partition_set_attrs; + fdisk_partition_set_name; + fdisk_partition_set_partno; + fdisk_partition_set_size; + fdisk_partition_set_start; + fdisk_partition_set_type; + fdisk_partition_set_uuid; + fdisk_partition_size_explicit; + fdisk_partition_start_follow_default; + fdisk_partition_start_is_default; + fdisk_toggle_partition_flag; + fdisk_partition_to_string; + fdisk_partition_unset_partno; + fdisk_partition_unset_size; + fdisk_partition_unset_start; + fdisk_partname; + fdisk_parttype_get_code; + fdisk_parttype_get_name; + fdisk_parttype_get_string; + fdisk_parttype_is_unknown; + fdisk_parttype_set_code; + fdisk_parttype_set_name; + fdisk_parttype_set_typestr; + fdisk_ref_ask; + fdisk_ref_context; + fdisk_ref_partition; + fdisk_ref_parttype; + fdisk_ref_script; + fdisk_ref_table; + fdisk_reorder_partitions; + fdisk_reread_partition_table; + fdisk_reset_alignment; + fdisk_reset_device_properties; + fdisk_reset_iter; + fdisk_reset_partition; + fdisk_reset_table; + fdisk_save_user_geometry; + fdisk_save_user_sector_size; + fdisk_script_get_header; + fdisk_script_get_nlines; + fdisk_script_get_table; + fdisk_script_read_context; + fdisk_script_read_file; + fdisk_script_read_line; + fdisk_script_set_header; + fdisk_script_write_file; + fdisk_set_ask; + fdisk_set_disklabel_id; + fdisk_set_first_lba; + fdisk_set_last_lba; + fdisk_set_partition; + fdisk_set_partition_type; + fdisk_set_script; + fdisk_set_unit; + fdisk_sgi_create_info; + fdisk_sgi_set_bootfile; + fdisk_sun_set_alt_cyl; + fdisk_sun_set_ilfact; + fdisk_sun_set_pcylcount; + fdisk_sun_set_rspeed; + fdisk_sun_set_xcyl; + fdisk_table_add_partition; + fdisk_table_get_nents; + fdisk_table_get_partition; + fdisk_table_is_empty; + fdisk_table_next_partition; + fdisk_table_remove_partition; + fdisk_table_sort_partitions; + fdisk_table_wrong_order; + fdisk_unref_ask; + fdisk_unref_context; + fdisk_unref_partition; + fdisk_unref_parttype; + fdisk_unref_script; + fdisk_unref_table; + fdisk_use_cylinders; + fdisk_verify_disklabel; + fdisk_warn; + fdisk_warnx; + fdisk_write_disklabel; +local: + *; +}; diff --git a/libblkid/libfdisk/src/partition.c b/libblkid/libfdisk/src/partition.c new file mode 100644 index 000000000..8f8402716 --- /dev/null +++ b/libblkid/libfdisk/src/partition.c @@ -0,0 +1,963 @@ + +#include "c.h" +#include "strutils.h" + +#include "fdiskP.h" + +/** + * SECTION: partition + * @title: Partition + * @short_description: generic label independent partition abstraction + * + * The fdisk_partition provides label independent abstraction. The partitions + * are not directly connected with partition table (label) data. Any change to + * fdisk_partition does not affects in-memory or on-disk label data. + * + * The fdisk_partition is possible to use as a template for + * fdisk_add_partition() or fdisk_set_partition() operations. + */ + +static void init_partition(struct fdisk_partition *pa) +{ + FDISK_INIT_UNDEF(pa->size); + FDISK_INIT_UNDEF(pa->start); + FDISK_INIT_UNDEF(pa->partno); + FDISK_INIT_UNDEF(pa->parent_partno); + FDISK_INIT_UNDEF(pa->boot); + + INIT_LIST_HEAD(&pa->parts); +} + +/** + * fdisk_new_partition: + * + * Returns: new instance. + */ +struct fdisk_partition *fdisk_new_partition(void) +{ + struct fdisk_partition *pa = calloc(1, sizeof(*pa)); + + pa->refcount = 1; + init_partition(pa); + DBG(PART, ul_debugobj(pa, "alloc")); + return pa; +} + +/** + * fdisk_reset_partition: + * @pa: partition + * + * Resets partition content. + */ +void fdisk_reset_partition(struct fdisk_partition *pa) +{ + int ref; + + if (!pa) + return; + + DBG(PART, ul_debugobj(pa, "reset")); + ref = pa->refcount; + + fdisk_unref_parttype(pa->type); + free(pa->name); + free(pa->uuid); + free(pa->attrs); + + memset(pa, 0, sizeof(*pa)); + pa->refcount = ref; + + init_partition(pa); +} + +/** + * fdisk_ref_partition: + * @pa: partition pointer + * + * Incremparts reference counter. + */ +void fdisk_ref_partition(struct fdisk_partition *pa) +{ + if (pa) + pa->refcount++; +} + +/** + * fdisk_unref_partition: + * @pa: partition pointer + * + * De-incremparts reference counter, on zero the @pa is automatically + * deallocated. + */ +void fdisk_unref_partition(struct fdisk_partition *pa) +{ + if (!pa) + return; + + pa->refcount--; + if (pa->refcount <= 0) { + fdisk_reset_partition(pa); + list_del(&pa->parts); + DBG(PART, ul_debugobj(pa, "free")); + free(pa); + } +} + +/** + * fdisk_partition_set_start: + * @pa: partition + * @off: offset in sectors, maximal is UINT64_MAX-1 + * + * Note that zero is valid offset too. Use fdisk_partition_unset_start() to + * undefine the offset. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_set_start(struct fdisk_partition *pa, fdisk_sector_t off) +{ + if (!pa) + return -EINVAL; + if (FDISK_IS_UNDEF(off)) + return -ERANGE; + pa->start = off; + return 0; +} + +/** + * fdisk_partition_unset_start: + * @pa: partition + * + * Sets the size as undefined. See fdisk_partition_has_start(). + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_unset_start(struct fdisk_partition *pa) +{ + if (!pa) + return -EINVAL; + FDISK_INIT_UNDEF(pa->start); + return 0; +} + +/** + * fdisk_partition_get_start: + * @pa: partition + * + * The zero is also valid offset. The function may return random undefined + * value when start offset is undefined (for example after + * fdisk_partition_unset_start()). Always use fdisk_partition_has_start() to be + * sure that you work with valid numbers. + * + * Returns: start offset in sectors + */ +fdisk_sector_t fdisk_partition_get_start(struct fdisk_partition *pa) +{ + return pa->start; +} + +/** + * fdisk_partition_has_start: + * @pa: partition + * + * Returns: 1 or 0 + */ +int fdisk_partition_has_start(struct fdisk_partition *pa) +{ + return pa && !FDISK_IS_UNDEF(pa->start); +} + + +/** + * fdisk_partition_cmp_start: + * @a: partition + * @b: partition + * + * Compares partitons according to start offset, See fdisk_sort_table(). + * + * Return: 0 if the same, <0 if @b greater, >0 if @a greater. + */ +int fdisk_partition_cmp_start(struct fdisk_partition *a, + struct fdisk_partition *b) +{ + int no_a = FDISK_IS_UNDEF(a->start), + no_b = FDISK_IS_UNDEF(b->start); + + if (no_a && no_b) + return 0; + if (no_a) + return -1; + if (no_b) + return 1; + + return cmp_numbers(a->start, b->start); +} + +/** + * fdisk_partition_start_follow_default + * @pa: partition + * @enable: 0|1 + * + * When @pa used as a tempalate for fdisk_add_partition() when force label driver + * to use the first possible space for the new partition. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_start_follow_default(struct fdisk_partition *pa, int enable) +{ + if (!pa) + return -EINVAL; + pa->start_follow_default = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_partition_start_is_default: + * @pa: partition + * + * See fdisk_partition_start_follow_default(). + * + * Returns: 1 if the partition follows default + */ +int fdisk_partition_start_is_default(struct fdisk_partition *pa) +{ + assert(pa); + return pa->start_follow_default; +} + + +/** + * fdisk_partition_set_size: + * @pa: partition + * @sz: size in sectors, maximal is UIN64_MAX-1 + * + * Note that zero is valid size too. Use fdisk_partition_unset_size() to + * undefine the size. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_set_size(struct fdisk_partition *pa, fdisk_sector_t sz) +{ + if (!pa) + return -EINVAL; + if (FDISK_IS_UNDEF(sz)) + return -ERANGE; + pa->size = sz; + return 0; +} + +/** + * fdisk_partition_unset_size: + * @pa: partition + * + * Sets the size as undefined. See fdisk_partition_has_size(). + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_unset_size(struct fdisk_partition *pa) +{ + if (!pa) + return -EINVAL; + FDISK_INIT_UNDEF(pa->size); + return 0; +} + +/** + * fdisk_partition_get_size: + * @pa: partition + * + * The zero is also valid size. The function may return random undefined + * value when size is undefined (for example after fdisk_partition_unset_size()). + * Always use fdisk_partition_has_size() to be sure that you work with valid + * numbers. + * + * Returns: size offset in sectors + */ +fdisk_sector_t fdisk_partition_get_size(struct fdisk_partition *pa) +{ + return pa->size; +} + +/** + * fdisk_partition_has_size: + * @pa: partition + * + * Returns: 1 or 0 + */ +int fdisk_partition_has_size(struct fdisk_partition *pa) +{ + return pa && !FDISK_IS_UNDEF(pa->size); +} + +/** + * fdisk_partition_size_explicit: + * @pa: partition + * @enable: 0|1 + * + * By default libfdisk aligns the size when add the new partition (by + * fdisk_add_partrition()). If you want to disable this functionality use + * @enable = 1. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_size_explicit(struct fdisk_partition *pa, int enable) +{ + if (!pa) + return -EINVAL; + pa->size_explicit = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_partition_set_partno: + * @pa: partition + * @num: partitin number (0 is the first partition, maximal is SIZE_MAX-1) + * + * Note that zero is valid partno too. Use fdisk_partition_unset_partno() to + * undefine the partno. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_set_partno(struct fdisk_partition *pa, size_t num) +{ + if (!pa) + return -EINVAL; + if (FDISK_IS_UNDEF(num)) + return -ERANGE; + pa->partno = num; + return 0; +} + +/** + * fdisk_partition_unset_partno: + * @pa: partition + * + * Sets the partno as undefined. See fdisk_partition_has_partno(). + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_unset_partno(struct fdisk_partition *pa) +{ + if (!pa) + return -EINVAL; + FDISK_INIT_UNDEF(pa->partno); + return 0; +} + +/** + * fdisk_partition_get_partno: + * @pa: partition + * + * The zero is also valid parition number. The function may return random + * value when partno is undefined (for example after fdisk_partition_unset_partno()). + * Always use fdisk_partition_has_partno() to be sure that you work with valid + * numbers. + * + * Returns: partition number (0 is the first partition) + */ +size_t fdisk_partition_get_partno(struct fdisk_partition *pa) +{ + return pa->partno; +} + +/** + * fdisk_partition_has_partno: + * @pa: partition + * + * Returns: 1 or 0 + */ +int fdisk_partition_has_partno(struct fdisk_partition *pa) +{ + return pa && !FDISK_IS_UNDEF(pa->partno); +} + + +/** + * fdisk_partition_cmp_partno: + * @a: partition + * @b: partition + * + * Compares partitons according to partition number See fdisk_sort_table(). + * + * Return: 0 if the same, <0 if @b greater, >0 if @a greater. + */ +int fdisk_partition_cmp_partno(struct fdisk_partition *a, + struct fdisk_partition *b) +{ + return a->partno - b->partno; +} + +/** + * fdisk_partition_partno_follow_default + * @pa: partition + * @enable: 0|1 + * + * When @pa used as a tempalate for fdisk_add_partition() when force label driver + * to add a new partition to the default (next) position. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_partno_follow_default(struct fdisk_partition *pa, int enable) +{ + if (!pa) + return -EINVAL; + pa->partno_follow_default = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_partition_set_type: + * @pa: partition + * @type: partition type + * + * Sets parition type. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_set_type(struct fdisk_partition *pa, + struct fdisk_parttype *type) +{ + if (!pa) + return -EINVAL; + + fdisk_ref_parttype(type); + fdisk_unref_parttype(pa->type); + pa->type = type; + + return 0; +} + +/** + * fdisk_partition_get_type: + * @pa: partition + * + * Returns: pointer to partition type. + */ +struct fdisk_parttype *fdisk_partition_get_type(struct fdisk_partition *pa) +{ + return pa ? pa->type : NULL; +} + +int fdisk_partition_set_name(struct fdisk_partition *pa, const char *name) +{ + char *p = NULL; + + if (!pa) + return -EINVAL; + if (name) { + p = strdup(name); + if (!p) + return -ENOMEM; + } + free(pa->name); + pa->name = p; + return 0; +} + +const char *fdisk_partition_get_name(struct fdisk_partition *pa) +{ + return pa ? pa->name : NULL; +} + +int fdisk_partition_set_uuid(struct fdisk_partition *pa, const char *uuid) +{ + char *p = NULL; + + if (!pa) + return -EINVAL; + if (uuid) { + p = strdup(uuid); + if (!p) + return -ENOMEM; + } + free(pa->uuid); + pa->uuid = p; + return 0; +} + +/** + * fdisk_partition_has_end: + * @pa: partition + * + * Returns: 1 if the partition has defined last sector + */ +int fdisk_partition_has_end(struct fdisk_partition *pa) +{ + return pa && !FDISK_IS_UNDEF(pa->start) && !FDISK_IS_UNDEF(pa->size); +} + +/** + * fdisk_partition_get_end: + * @pa: partition + * + * This function may returns absolute non-sense, always check + * fdisk_partition_has_end(). + * + * Note that partition end is defined by fdisk_partition_set_start() and + * fdisk_partition_set_size(). + * + * Returns: last partition sector LBA. + */ +fdisk_sector_t fdisk_partition_get_end(struct fdisk_partition *pa) +{ + return pa->start + pa->size - (pa->size == 0 ? 0 : 1); +} + +/** + * fdisk_partition_end_follow_default + * @pa: partition + * @enable: 0|1 + * + * When @pa used as a tempalate for fdisk_add_partition() when force label driver + * to use all the possible space for the new partition. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_partition_end_follow_default(struct fdisk_partition *pa, int enable) +{ + if (!pa) + return -EINVAL; + pa->end_follow_default = enable ? 1 : 0; + return 0; +} + +/** + * fdisk_partition_end_is_default: + * @pa: partition + * + * Returns: 1 if the partition follows default + */ +int fdisk_partition_end_is_default(struct fdisk_partition *pa) +{ + assert(pa); + return pa->end_follow_default; +} + +const char *fdisk_partition_get_uuid(struct fdisk_partition *pa) +{ + return pa ? pa->uuid : NULL; +} + +const char *fdisk_partition_get_attrs(struct fdisk_partition *pa) +{ + return pa ? pa->attrs : NULL; +} + +int fdisk_partition_set_attrs(struct fdisk_partition *pa, const char *attrs) +{ + char *p = NULL; + + if (!pa) + return -EINVAL; + if (attrs) { + p = strdup(attrs); + if (!p) + return -ENOMEM; + } + free(pa->attrs); + pa->attrs = p; + return 0; +} + +int fdisk_partition_is_nested(struct fdisk_partition *pa) +{ + return pa && !FDISK_IS_UNDEF(pa->parent_partno); +} + +int fdisk_partition_is_container(struct fdisk_partition *pa) +{ + return pa && pa->container; +} + +int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent) +{ + if (pa && parent) + *parent = pa->parent_partno; + else + return -EINVAL; + return 0; +} + +int fdisk_partition_is_used(struct fdisk_partition *pa) +{ + return pa && pa->used; +} + +int fdisk_partition_is_bootable(struct fdisk_partition *pa) +{ + return pa && pa->boot == 1; +} + +int fdisk_partition_is_freespace(struct fdisk_partition *pa) +{ + return pa && pa->freespace; +} + +int fdisk_partition_next_partno( + struct fdisk_partition *pa, + struct fdisk_context *cxt, + size_t *n) +{ + assert(cxt); + assert(n); + + if (pa && pa->partno_follow_default) { + size_t i; + + DBG(PART, ul_debugobj(pa, "next partno (follow default)")); + + for (i = 0; i < cxt->label->nparts_max; i++) { + if (!fdisk_is_partition_used(cxt, i)) { + *n = i; + return 0; + } + } + return -ERANGE; + + } else if (pa && fdisk_partition_has_partno(pa)) { + + DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno)); + + if (pa->partno >= cxt->label->nparts_max) + return -ERANGE; + *n = pa->partno; + } else + return fdisk_ask_partnum(cxt, n, 1); + + return 0; +} + +/** + * fdisk_partition_to_string: + * @pa: partition + * @cxt: context + * @id: field (FDISK_FIELD_*) + * @data: returns string with allocated data + * + * Returns info about partition converted to printable string. + * + * For example + * <informalexample> + * <programlisting> + * struct fdisk_parition *pa; + * + * fdisk_get_partition(cxt, 0, &pa); + * fdisk_partition_to_string(pa, FDISK_FIELD_UUID, &data); + * printf("first partition uuid: %s\n", data); + * free(data); + * fdisk_unref_partition(pa); + * </programlisting> + * </informalexample> + * + * returns UUID for the first partition. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_partition_to_string(struct fdisk_partition *pa, + struct fdisk_context *cxt, + int id, + char **data) +{ + char *p = NULL; + int rc = 0; + uint64_t x; + + if (!pa || !cxt) + return -EINVAL; + + switch (id) { + case FDISK_FIELD_DEVICE: + if (pa->freespace) + p = strdup(_("Free space")); + else if (fdisk_partition_has_partno(pa) && cxt->dev_path) { + if (cxt->label->flags & FDISK_LABEL_FL_INCHARS_PARTNO) + rc = asprintf(&p, "%c", (int) pa->partno + 'a'); + else + p = fdisk_partname(cxt->dev_path, pa->partno + 1); + } + break; + case FDISK_FIELD_BOOT: + if (fdisk_partition_is_bootable(pa)) + rc = asprintf(&p, "%c", pa->boot ? '*' : ' '); + break; + case FDISK_FIELD_START: + if (fdisk_partition_has_start(pa)) { + x = fdisk_cround(cxt, pa->start); + rc = pa->start_post ? + asprintf(&p, "%ju%c", x, pa->start_post) : + asprintf(&p, "%ju", x); + } + break; + case FDISK_FIELD_END: + if (fdisk_partition_has_end(pa)) { + x = fdisk_cround(cxt, fdisk_partition_get_end(pa)); + rc = pa->end_post ? + asprintf(&p, "%ju%c", x, pa->end_post) : + asprintf(&p, "%ju", x); + } + break; + case FDISK_FIELD_SIZE: + if (fdisk_partition_has_size(pa)) { + uint64_t sz = pa->size * cxt->sector_size; + + if (fdisk_is_details(cxt)) { + rc = pa->size_post ? + asprintf(&p, "%ju%c", sz, pa->size_post) : + asprintf(&p, "%ju", sz); + } else { + p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz); + if (!p) + rc = -ENOMEM; + } + } + break; + case FDISK_FIELD_CYLINDERS: + rc = asprintf(&p, "%ju", (uintmax_t) + fdisk_cround(cxt, fdisk_partition_has_size(pa) ? pa->size : 0)); + break; + case FDISK_FIELD_SECTORS: + rc = asprintf(&p, "%ju", + fdisk_partition_has_size(pa) ? (uintmax_t) pa->size : 0); + break; + case FDISK_FIELD_BSIZE: + rc = asprintf(&p, "%ju", pa->bsize); + break; + case FDISK_FIELD_FSIZE: + rc = asprintf(&p, "%ju", pa->fsize); + break; + case FDISK_FIELD_CPG: + rc = asprintf(&p, "%ju", pa->cpg); + break; + case FDISK_FIELD_TYPE: + p = pa->type && pa->type->name ? strdup(pa->type->name) : NULL; + break; + case FDISK_FIELD_TYPEID: + if (pa->type && fdisk_parttype_get_string(pa->type)) + rc = asprintf(&p, "%s", fdisk_parttype_get_string(pa->type)); + else if (pa->type) + rc = asprintf(&p, "%x", fdisk_parttype_get_code(pa->type)); + break; + case FDISK_FIELD_UUID: + p = pa->uuid ? strdup(pa->uuid) : NULL; + break; + case FDISK_FIELD_NAME: + p = pa->name ? strdup(pa->name) : NULL; + break; + case FDISK_FIELD_ATTR: + p = pa->attrs ? strdup(pa->attrs) : NULL; + break; + case FDISK_FIELD_SADDR: + p = pa->start_chs ? strdup(pa->start_chs) : NULL; + break; + case FDISK_FIELD_EADDR: + p = pa->end_chs ? strdup(pa->end_chs) : NULL; + break; + default: + return -EINVAL; + } + + if (rc < 0) + rc = -ENOMEM; + else if (rc > 0) + rc = 0; + + if (data) + *data = p; + return rc; +} + +/** + * fdisk_get_partition: + * @cxt: context + * @partno: partition number (0 is the first partition) + * @pa: returns data about partition + * + * Reads disklabel and fills in @pa with data about partition @n. + * + * Note that partno may address unused partition and then this function does + * not fill anything to @pa. See fdisk_is_partition_used(). If @pa points to + * NULL then the function allocates a newly allocated fdisk_partition struct, + * use fdisk_unref_partition() to deallocate. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, + struct fdisk_partition **pa) +{ + int rc; + struct fdisk_partition *np = NULL; + + if (!cxt || !cxt->label || !pa) + return -EINVAL; + if (!cxt->label->op->get_part) + return -ENOSYS; + if (!fdisk_is_partition_used(cxt, partno)) + return -EINVAL; + + if (!*pa) { + np = *pa = fdisk_new_partition(); + if (!*pa) + return -ENOMEM; + } else + fdisk_reset_partition(*pa); + + (*pa)->partno = partno; + rc = cxt->label->op->get_part(cxt, partno, *pa); + + if (rc) { + if (np) { + fdisk_unref_partition(np); + *pa = NULL; + } else + fdisk_reset_partition(*pa); + } else + (*pa)->size_explicit = 1; + return rc; +} + +/** + * fdisk_set_partition: + * @cxt: context + * @partno: partition number (0 is the first partition) + * @pa: new partition setting + * + * Modifies disklabel according to setting with in @pa. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, + struct fdisk_partition *pa) +{ + if (!cxt || !cxt->label || !pa) + return -EINVAL; + if (!cxt->label->op->set_part) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju, " + "defaults(start=%s, end=%s, partno=%s)", + partno, pa, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa), + pa->start_follow_default ? "yes" : "no", + pa->end_follow_default ? "yes" : "no", + pa->partno_follow_default ? "yes" : "no")); + + return cxt->label->op->set_part(cxt, partno, pa); +} + +/** + * fdisk_add_partition: + * @cxt: fdisk context + * @pa: template for the partition (or NULL) + * @partno: NULL or returns new partition number + * + * If @pa is not specified or any @pa item is missiong the libfdisk will ask by + * fdisk_ask_ API. + * + * Adds a new partition to disklabel. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + int rc; + + assert(cxt); + assert(cxt->label); + + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->add_part) + return -ENOSYS; + if (fdisk_missing_geometry(cxt)) + return -EINVAL; + + if (pa) + DBG(CXT, ul_debugobj(cxt, "adding new partition %p (start=%ju, end=%ju, size=%ju, " + "defaults(start=%s, end=%s, partno=%s)", + pa, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa), + pa->start_follow_default ? "yes" : "no", + pa->end_follow_default ? "yes" : "no", + pa->partno_follow_default ? "yes" : "no")); + else + DBG(CXT, ul_debugobj(cxt, "adding partition")); + + rc = cxt->label->op->add_part(cxt, pa, partno); + + DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc)); + return rc; +} + +/** + * fdisk_delete_partition: + * @cxt: fdisk context + * @partno: partition number to delete (0 is the first partition) + * + * Deletes a @partno partition from disklabel. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_delete_partition(struct fdisk_context *cxt, size_t partno) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->del_part) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "deleting %s partition number %zd", + cxt->label->name, partno)); + return cxt->label->op->del_part(cxt, partno); +} + +/** + * fdisk_delete_all_partitions: + * @cxt: fdisk context + * + * Delete all used partitions from disklabel. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_delete_all_partitions(struct fdisk_context *cxt) +{ + size_t i; + int rc; + + if (!cxt || !cxt->label) + return -EINVAL; + + for (i = 0; i < cxt->label->nparts_max; i++) { + + if (!fdisk_is_partition_used(cxt, i)) + continue; + rc = fdisk_delete_partition(cxt, i); + if (rc) + break; + } + + return rc; +} + +/** + * fdisk_is_partition_used: + * @cxt: context + * @n: partition number (0 is the first partition) + * + * This is faster than fdisk_get_partition() + fdisk_partition_is_used(). + * + * Returns: 0 or 1 + */ +int fdisk_is_partition_used(struct fdisk_context *cxt, size_t n) +{ + if (!cxt || !cxt->label) + return -EINVAL; + if (!cxt->label->op->part_is_used) + return -ENOSYS; + + return cxt->label->op->part_is_used(cxt, n); +} + diff --git a/libblkid/libfdisk/src/parttype.c b/libblkid/libfdisk/src/parttype.c new file mode 100644 index 000000000..aedf4e83b --- /dev/null +++ b/libblkid/libfdisk/src/parttype.c @@ -0,0 +1,401 @@ + +#include <ctype.h> + +#include "nls.h" +#include "fdiskP.h" + +/** + * SECTION: parttype + * @title: Partition types + * @short_description: abstraction to partition types + * + * There are two basic types of parttypes, string based (e.g. GPT) + * and code/hex based (e.g. MBR). + */ + +/** + * fdisk_new_parttype: + * + * It's recommended to use fdisk_label_get_parttype_from_code() or + * fdisk_label_get_parttype_from_string() for well known types rather + * than allocate a new instance. + * + * Returns: new instance. + */ +struct fdisk_parttype *fdisk_new_parttype(void) +{ + struct fdisk_parttype *t = calloc(1, sizeof(*t)); + + t->refcount = 1; + t->flags = FDISK_PARTTYPE_ALLOCATED; + DBG(PARTTYPE, ul_debugobj(t, "alloc")); + return t; +} + +/** + * fdisk_ref_parttype: + * @t: partition type + * + * Incremparts reference counter for allocated types + */ +void fdisk_ref_parttype(struct fdisk_parttype *t) +{ + if (fdisk_parttype_is_allocated(t)) + t->refcount++; +} + +/** + * fdisk_unref_parttype + * @t: partition pointer + * + * De-incremparts reference counter, on zero the @t is automatically + * deallocated. + */ +void fdisk_unref_parttype(struct fdisk_parttype *t) +{ + if (!fdisk_parttype_is_allocated(t)) + return; + + t->refcount--; + if (t->refcount <= 0) { + DBG(PARTTYPE, ul_debugobj(t, "free")); + free(t->typestr); + free(t->name); + free(t); + } +} + +/** + * fdisk_parttype_set_name: + * @t: partition type + * @str: type name + * + * Sets type name to allocated partition type, for static types + * it returns -EINVAL. + * + * Return: 0 on success, <0 on error + */ +int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str) +{ + char *p = NULL; + + if (!t || !fdisk_parttype_is_allocated(t)) + return -EINVAL; + if (str) { + p = strdup(str); + if (!p) + return -ENOMEM; + } + + free(t->name); + t->name = p; + return 0; +} + +/** + * fdisk_parttype_set_typestr: + * @t: partition type + * @str: type identificator (e.g. GUID for GPT) + * + * Sets type string to allocated partition type, for static types + * it returns -EINVAL. Don't use this function for MBR, see + * fdisk_parttype_set_code(). + * + * Return: 0 on success, <0 on error + */ +int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str) +{ + char *p = NULL; + + if (!t || !fdisk_parttype_is_allocated(t)) + return -EINVAL; + if (str) { + p = strdup(str); + if (!p) + return -ENOMEM; + } + + free(t->typestr); + t->typestr = p; + return 0; +} + +/** + * fdisk_parttype_set_code: + * @t: partition type + * @code: type identificator (e.g. MBR type codes) + * + * Sets type code to allocated partition type, for static types it returns + * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr(). + * + * Return: 0 on success, <0 on error + */ +int fdisk_parttype_set_code(struct fdisk_parttype *t, int code) +{ + if (!t || !fdisk_parttype_is_allocated(t)) + return -EINVAL; + t->code = code; + return 0; +} + +/** + * fdisk_label_get_nparttypes: + * @lb: label + * + * Returns: number of types supported by label. + */ +size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb) +{ + if (!lb) + return 0; + return lb->nparttypes; +} + +/** + * fdisk_label_get_parttype: + * @lb: label + * @n: number + * + * Returns: return parttype + */ +struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n) +{ + if (!lb || n >= lb->nparttypes) + return NULL; + return &lb->parttypes[n]; +} + +/** + * fdisk_label_has_code_parttypes: + * @lb: label + * + * Returns: 1 if the label uses code as partition type + * identifiers (e.g. MBR) or 0. + */ +int fdisk_label_has_code_parttypes(const struct fdisk_label *lb) +{ + assert(lb); + + if (lb->parttypes && lb->parttypes[0].typestr) + return 0; + return 1; +} + + +/** + * fdisk_label_get_parttype_from_code: + * @lb: label + * @code: code to search for + * + * Search for partition type in label-specific table. The result + * is pointer to static array of label types. + * + * Returns: partition type or NULL upon failure or invalid @code. + */ +struct fdisk_parttype *fdisk_label_get_parttype_from_code( + const struct fdisk_label *lb, + unsigned int code) +{ + size_t i; + + assert(lb); + + if (!lb->nparttypes) + return NULL; + + for (i = 0; i < lb->nparttypes; i++) + if (lb->parttypes[i].code == code) + return &lb->parttypes[i]; + return NULL; +} + +/** + * fdisk_label_get_parttype_from_string: + * @lb: label + * @str: string to search for + * + * Search for partition type in label-specific table. The result + * is pointer to static array of label types. + * + * Returns: partition type or NULL upon failure or invalid @str. + */ +struct fdisk_parttype *fdisk_label_get_parttype_from_string( + const struct fdisk_label *lb, + const char *str) +{ + size_t i; + + assert(lb); + + if (!lb->nparttypes) + return NULL; + + for (i = 0; i < lb->nparttypes; i++) + if (lb->parttypes[i].typestr + && strcasecmp(lb->parttypes[i].typestr, str) == 0) + return &lb->parttypes[i]; + + return NULL; +} + +/** + * fdisk_new_unknown_parttype: + * @code: type as number + * @typestr: type as string + + * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to + * deallocate. + * + * Returns: newly allocated partition type, or NULL upon failure. + */ +struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code, + const char *typestr) +{ + struct fdisk_parttype *t = fdisk_new_parttype(); + + if (!t) + return NULL; + + fdisk_parttype_set_name(t, _("unknown")); + fdisk_parttype_set_code(t, code); + fdisk_parttype_set_typestr(t, typestr); + t->flags |= FDISK_PARTTYPE_UNKNOWN; + + return t; +} + +/** + * fdisk_copy_parttype: + * @type: type to copy + * + * Use fdisk_unref_parttype() to deallocate. + * + * Returns: newly allocated partition type, or NULL upon failure. + */ +struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type) +{ + struct fdisk_parttype *t = fdisk_new_parttype(); + + if (!t) + return NULL; + + fdisk_parttype_set_name(t, type->name); + fdisk_parttype_set_code(t, type->code); + fdisk_parttype_set_typestr(t, type->typestr); + + return t; +} + +/** + * fdisk_label_parse_parttype: + * @lb: label + * @str: string to parse from + * + * Parses partition type from @str according to the label. Thefunction returns + * a pointer to static table of the partition types, or newly allocated + * partition type for unknown types (see fdisk_parttype_is_unknown(). It's + * safe to call fdisk_unref_parttype() for all results. + * + * Returns: pointer to type or NULL on error. + */ +struct fdisk_parttype *fdisk_label_parse_parttype( + const struct fdisk_label *lb, + const char *str) +{ + struct fdisk_parttype *types, *ret; + unsigned int code = 0; + char *typestr = NULL, *end = NULL; + + assert(lb); + + if (!lb->nparttypes) + return NULL; + + DBG(LABEL, ul_debugobj((void *) lb, "parsing '%s' (%s) partition type", + str, lb->name)); + types = lb->parttypes; + + if (types[0].typestr == NULL && isxdigit(*str)) { + + errno = 0; + code = strtol(str, &end, 16); + + if (errno || *end != '\0') { + DBG(LABEL, ul_debugobj((void *) lb, "parsing failed: %m")); + return NULL; + } + ret = fdisk_label_get_parttype_from_code(lb, code); + if (ret) + goto done; + } else { + int i; + + /* maybe specified by type string (e.g. UUID) */ + ret = fdisk_label_get_parttype_from_string(lb, str); + if (ret) + goto done; + + /* maybe specified by order number */ + errno = 0; + i = strtol(str, &end, 0); + if (errno == 0 && *end == '\0' && i > 0 + && i - 1 < (int) lb->nparttypes) { + ret = &types[i - 1]; + goto done; + } + } + + ret = fdisk_new_unknown_parttype(code, typestr); +done: + DBG(PARTTYPE, ul_debugobj(ret, "returns parsed '%s' partition type", ret->name)); + return ret; +} + +/** + * fdisk_parttype_get_string: + * @t: type + * + * Returns: partition type string (e.g. GUID for GPT) + */ +const char *fdisk_parttype_get_string(const struct fdisk_parttype *t) +{ + assert(t); + return t->typestr && *t->typestr ? t->typestr : NULL; +} + +/** + * fdisk_parttype_get_code: + * @t: type + * + * Returns: partition type code (e.g. for MBR) + */ +unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t) +{ + assert(t); + return t->code; +} + +/** + * fdisk_parttype_get_name: + * @t: type + * + * Returns: partition type human readable name + */ +const char *fdisk_parttype_get_name(const struct fdisk_parttype *t) +{ + assert(t); + return t->name; +} + +/** + * fdisk_parttype_is_unknown: + * @t: type + * + * Checks for example result from fdisk_label_parse_parttype(). + * + * Returns: 1 is type is "unknonw" or 0. + */ +int fdisk_parttype_is_unknown(const struct fdisk_parttype *t) +{ + return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0; +} diff --git a/libblkid/libfdisk/src/script.c b/libblkid/libfdisk/src/script.c new file mode 100644 index 000000000..83bda995d --- /dev/null +++ b/libblkid/libfdisk/src/script.c @@ -0,0 +1,1235 @@ + +#include "fdiskP.h" +#include "strutils.h" + +/** + * SECTION: script + * @title: Script + * @short_description: text based sfdisk compatible description of partition table + * + * The libfdisk scripts are based on original sfdisk script (dumps). Each + * script has two parts: script headers and partition table entries + * (partitions). + * + * For more details about script format see sfdisk man page. + */ + +/* script header (e.g. unit: sectors) */ +struct fdisk_scriptheader { + struct list_head headers; + char *name; + char *data; +}; + +/* script control struct */ +struct fdisk_script { + struct fdisk_table *table; + struct list_head headers; + struct fdisk_context *cxt; + + int refcount; + + /* parser's state */ + size_t nlines; + int fmt; /* input format */ + struct fdisk_label *label; +}; + + +static void fdisk_script_free_header(struct fdisk_script *dp, struct fdisk_scriptheader *fi) +{ + if (!fi) + return; + + DBG(SCRIPT, ul_debugobj(fi, "free header %s", fi->name)); + free(fi->name); + free(fi->data); + list_del(&fi->headers); + free(fi); +} + +/** + * fdisk_new_script: + * @cxt: context + * + * The script hold fdisk_table and additional information to read/write + * script to the file. + * + * Returns: newly allocated script struct. + */ +struct fdisk_script *fdisk_new_script(struct fdisk_context *cxt) +{ + struct fdisk_script *dp = NULL; + + dp = calloc(1, sizeof(*dp)); + if (!dp) + return NULL; + + DBG(SCRIPT, ul_debugobj(dp, "alloc")); + dp->refcount = 1; + dp->cxt = cxt; + fdisk_ref_context(cxt); + + dp->table = fdisk_new_table(); + if (!dp->table) { + fdisk_unref_script(dp); + return NULL; + } + + INIT_LIST_HEAD(&dp->headers); + return dp; +} + +/** + * fdisk_new_script_from_file: + * @cxt: context + * @filename: path to the script file + * + * Allocates a new script and reads script from @filename. + * + * Returns: new script instance or NULL in case of error (check errno for more details). + */ +struct fdisk_script *fdisk_new_script_from_file(struct fdisk_context *cxt, + const char *filename) +{ + int rc; + FILE *f; + struct fdisk_script *dp, *res = NULL; + + assert(cxt); + assert(filename); + + DBG(SCRIPT, ul_debug("opening %s", filename)); + f = fopen(filename, "r"); + if (!f) + return NULL; + + dp = fdisk_new_script(cxt); + if (!dp) + goto done; + + rc = fdisk_script_read_file(dp, f); + if (rc) { + errno = -rc; + goto done; + } + + res = dp; +done: + fclose(f); + if (!res) + fdisk_unref_script(dp); + else + errno = 0; + + return res; +} + +/** + * fdisk_ref_script: + * @dp: script pointer + * + * Incremparts reference counter. + */ +void fdisk_ref_script(struct fdisk_script *dp) +{ + if (dp) + dp->refcount++; +} + +static void fdisk_reset_script(struct fdisk_script *dp) +{ + assert(dp); + + DBG(SCRIPT, ul_debugobj(dp, "reset")); + fdisk_unref_table(dp->table); + dp->table = NULL; + + while (!list_empty(&dp->headers)) { + struct fdisk_scriptheader *fi = list_entry(dp->headers.next, + struct fdisk_scriptheader, headers); + fdisk_script_free_header(dp, fi); + } + INIT_LIST_HEAD(&dp->headers); +} + +/** + * fdisk_unref_script: + * @dp: script pointer + * + * De-incremparts reference counter, on zero the @dp is automatically + * deallocated. + */ +void fdisk_unref_script(struct fdisk_script *dp) +{ + if (!dp) + return; + + dp->refcount--; + if (dp->refcount <= 0) { + fdisk_reset_script(dp); + fdisk_unref_context(dp->cxt); + DBG(SCRIPT, ul_debugobj(dp, "free script")); + free(dp); + } +} + +static struct fdisk_scriptheader *script_get_header(struct fdisk_script *dp, + const char *name) +{ + struct list_head *p; + + list_for_each(p, &dp->headers) { + struct fdisk_scriptheader *fi = list_entry(p, struct fdisk_scriptheader, headers); + + if (strcasecmp(fi->name, name) == 0) + return fi; + } + + return NULL; +} + +/** + * fdisk_script_get_header: + * @dp: script instance + * @name: header name + * + * Returns: pointer to header data or NULL. + */ +const char *fdisk_script_get_header(struct fdisk_script *dp, const char *name) +{ + struct fdisk_scriptheader *fi; + + assert(dp); + assert(name); + + fi = script_get_header(dp, name); + return fi ? fi->data : NULL; +} + + +/** + * fdisk_script_set_header: + * @dp: script instance + * @name: header name + * @data: header data (or NULL) + * + * The headers are used as global options (in script) for whole partition + * table, always one header per line. + * + * If no @data specified then the header is removed. If header does not exist + * and @data specified then a new header added. + * + * Note that libfdisk allows to specify arbitrary custom header, the default + * build-in headers are "unit" and "label", and some label specific headers + * (for example "uuid" and "name" for GPT). + * + * Returns: 0 on success, <0 on error + */ +int fdisk_script_set_header(struct fdisk_script *dp, + const char *name, + const char *data) +{ + struct fdisk_scriptheader *fi; + + assert(dp); + assert(name); + + if (!dp || !name) + return -EINVAL; + + fi = script_get_header(dp, name); + if (!fi && !data) + return 0; /* want to remove header that does not exist, success */ + + if (!data) { + /* no data, remove the header */ + fdisk_script_free_header(dp, fi); + return 0; + } + + if (!fi) { + /* new header */ + fi = calloc(1, sizeof(*fi)); + if (!fi) + return -ENOMEM; + INIT_LIST_HEAD(&fi->headers); + fi->name = strdup(name); + fi->data = strdup(data); + if (!fi->data || !fi->name) { + fdisk_script_free_header(dp, fi); + return -ENOMEM; + } + list_add_tail(&fi->headers, &dp->headers); + } else { + /* update existing */ + char *x = strdup(data); + + if (!x) + return -ENOMEM; + free(fi->data); + fi->data = x; + } + + if (strcmp(name, "label") == 0) + dp->label = NULL; + + return 0; +} + +/** + * fdisk_script_get_table: + * @dp: script + * + * The table (container with partitions) is possible to create by + * fdisk_script_read_context() or fdisk_script_read_file(), otherwise + * this function returns NULL. + * + * Returns: NULL or script. + */ +struct fdisk_table *fdisk_script_get_table(struct fdisk_script *dp) +{ + assert(dp); + return dp ? dp->table : NULL; +} + +static struct fdisk_label *script_get_label(struct fdisk_script *dp) +{ + assert(dp); + assert(dp->cxt); + + if (!dp->label) { + dp->label = fdisk_get_label(dp->cxt, + fdisk_script_get_header(dp, "label")); + DBG(SCRIPT, ul_debugobj(dp, "label '%s'", dp->label ? dp->label->name : "")); + } + return dp->label; +} + +/** + * fdisk_script_get_nlines: + * @dp: script + * + * Returns: number of parsed lines or <0 on error. + */ +int fdisk_script_get_nlines(struct fdisk_script *dp) +{ + assert(dp); + return dp->nlines; +} + +/** + * fdisk_script_read_context: + * @dp: script + * @cxt: context + * + * Reads data from the @cxt context (on disk partition table) into the script. + * If the context is no specified than defaults to context used for fdisk_new_script(). + * + * Return: 0 on success, <0 on error. + */ +int fdisk_script_read_context(struct fdisk_script *dp, struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + int rc; + char *p = NULL; + + assert(dp); + + if (!cxt) + cxt = dp->cxt; + + if (!dp || !cxt) + return -EINVAL; + + DBG(SCRIPT, ul_debugobj(dp, "reading context into script")); + fdisk_reset_script(dp); + + lb = fdisk_get_label(cxt, NULL); + if (!lb) + return -EINVAL; + + /* allocate and fill new table */ + rc = fdisk_get_partitions(cxt, &dp->table); + if (rc) + return rc; + + /* generate headers */ + rc = fdisk_script_set_header(dp, "label", fdisk_label_get_name(lb)); + + if (!rc && fdisk_get_disklabel_id(cxt, &p) == 0 && p) { + rc = fdisk_script_set_header(dp, "label-id", p); + free(p); + } + if (!rc && cxt->dev_path) + rc = fdisk_script_set_header(dp, "device", cxt->dev_path); + if (!rc) + rc = fdisk_script_set_header(dp, "unit", "sectors"); + + /* TODO: label specific headers (e.g. uuid for GPT) */ + + DBG(SCRIPT, ul_debugobj(dp, "read context done [rc=%d]", rc)); + return rc; +} + +/** + * fdisk_script_write_file: + * @dp: script + * @f: output file + * + * Writes script @dp to the ile @f. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_script_write_file(struct fdisk_script *dp, FILE *f) +{ + struct list_head *h; + struct fdisk_partition *pa; + struct fdisk_iter itr; + const char *devname = NULL; + + assert(dp); + assert(f); + + DBG(SCRIPT, ul_debugobj(dp, "writing script to file")); + + /* script headers */ + list_for_each(h, &dp->headers) { + struct fdisk_scriptheader *fi = list_entry(h, struct fdisk_scriptheader, headers); + fprintf(f, "%s: %s\n", fi->name, fi->data); + if (strcmp(fi->name, "device") == 0) + devname = fi->data; + } + + if (!dp->table) { + DBG(SCRIPT, ul_debugobj(dp, "script table empty")); + return 0; + } + + DBG(SCRIPT, ul_debugobj(dp, "%zu entries", fdisk_table_get_nents(dp->table))); + + fputc('\n', f); + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + while (fdisk_table_next_partition(dp->table, &itr, &pa) == 0) { + char *p = NULL; + + if (devname) + p = fdisk_partname(devname, pa->partno + 1); + if (p) { + DBG(SCRIPT, ul_debugobj(dp, "write %s entry", p)); + fprintf(f, "%s :", p); + } else + fprintf(f, "%zu :", pa->partno + 1); + + if (fdisk_partition_has_start(pa)) + fprintf(f, " start=%12ju", pa->start); + if (fdisk_partition_has_size(pa)) + fprintf(f, ", size=%12ju", pa->size); + + if (pa->type && fdisk_parttype_get_string(pa->type)) + fprintf(f, ", type=%s", fdisk_parttype_get_string(pa->type)); + else if (pa->type) + fprintf(f, ", type=%x", fdisk_parttype_get_code(pa->type)); + + if (pa->uuid) + fprintf(f, ", uuid=%s", pa->uuid); + if (pa->name && *pa->name) + fprintf(f, ", name=\"%s\"", pa->name); + + /* for MBR attr=80 means bootable */ + if (pa->attrs) { + struct fdisk_label *lb = script_get_label(dp); + + if (!lb || fdisk_label_get_type(lb) != FDISK_DISKLABEL_DOS) + fprintf(f, ", attrs=\"%s\"", pa->attrs); + } + if (fdisk_partition_is_bootable(pa)) + fprintf(f, ", bootable"); + fputc('\n', f); + } + + DBG(SCRIPT, ul_debugobj(dp, "write script done")); + return 0; +} + +static inline int is_header_line(const char *s) +{ + const char *p = strchr(s, ':'); + + if (!p || p == s || !*(p + 1) || strchr(s, '=')) + return 0; + + return 1; +} + +/* parses "<name>: value", note modifies @s*/ +static int parse_header_line(struct fdisk_script *dp, char *s) +{ + int rc = -EINVAL; + char *name, *value; + + DBG(SCRIPT, ul_debugobj(dp, " parse header '%s'", s)); + + if (!s || !*s) + return -EINVAL; + + name = s; + value = strchr(s, ':'); + if (!value) + goto done; + *value = '\0'; + value++; + + ltrim_whitespace((unsigned char *) name); + rtrim_whitespace((unsigned char *) name); + ltrim_whitespace((unsigned char *) value); + rtrim_whitespace((unsigned char *) value); + + if (strcmp(name, "label") == 0) { + if (dp->cxt && !fdisk_get_label(dp->cxt, value)) + goto done; /* unknown label name */ + } else if (strcmp(name, "unit") == 0) { + if (strcmp(value, "sectors") != 0) + goto done; /* only "sectors" supported */ + } else if (strcmp(name, "label-id") == 0 + || strcmp(name, "device") == 0) { + ; /* whatever is posssible */ + } else + goto done; /* unknown header */ + + if (*name && *value) + rc = fdisk_script_set_header(dp, name, value); +done: + if (rc) + DBG(SCRIPT, ul_debugobj(dp, "header parse error: " + "[rc=%d, name='%s', value='%s']", + rc, name, value)); + return rc; + +} + +/* returns zero terminated string with next token and @str is updated */ +static char *next_token(char **str) +{ + char *tk_begin = NULL, + *tk_end = NULL, + *end = NULL, + *p; + int open_quote = 0; + + for (p = *str; p && *p; p++) { + if (!tk_begin) { + if (isblank(*p)) + continue; + tk_begin = *p == '"' ? p + 1 : p; + } + if (*p == '"') + open_quote ^= 1; + if (open_quote) + continue; + if (isblank(*p) || *p == ',' || *p == ';' || *p == '"' ) + tk_end = p; + else if (*(p + 1) == '\0') + tk_end = p + 1; + if (tk_begin && tk_end) + break; + } + + if (!tk_end) + return NULL; + end = isblank(*tk_end) ? (char *) skip_blank(tk_end) : tk_end; + if (*end == ',' || *end == ';') + end++; + + *tk_end = '\0'; + *str = end; + return tk_begin; +} + +static int next_number(char **s, uint64_t *num, int *power) +{ + char *tk; + int rc = -EINVAL; + + assert(num); + assert(s); + + tk = next_token(s); + if (tk) + rc = parse_size(tk, (uintmax_t *) num, power); + return rc; +} + +static int next_string(char **s, char **str) +{ + char *tk; + int rc = -EINVAL; + + assert(s); + assert(str); + + tk = next_token(s); + if (tk) { + *str = strdup(tk); + rc = !*str ? -ENOMEM : 0; + } + return rc; +} + +static int partno_from_devname(char *s) +{ + int pno; + size_t sz; + char *end, *p; + + sz = rtrim_whitespace((unsigned char *)s); + p = s + sz - 1; + + while (p > s && isdigit(*(p - 1))) + p--; + + errno = 0; + pno = strtol(p, &end, 10); + if (errno || !end || p == end) + return -1; + return pno - 1; +} + +/* dump format + * <device>: start=<num>, size=<num>, type=<string>, ... + */ +static int parse_script_line(struct fdisk_script *dp, char *s) +{ + char *p, *x; + struct fdisk_partition *pa; + int rc = 0; + uint64_t num; + int pno; + + assert(dp); + assert(s); + + DBG(SCRIPT, ul_debugobj(dp, " parse script line: '%s'", s)); + + pa = fdisk_new_partition(); + if (!pa) + return -ENOMEM; + + fdisk_partition_start_follow_default(pa, 1); + fdisk_partition_end_follow_default(pa, 1); + fdisk_partition_partno_follow_default(pa, 1); + + /* set partno */ + p = strchr(s, ':'); + x = strchr(s, '='); + if (p && (!x || p < x)) { + *p = '\0'; + p++; + + pno = partno_from_devname(s); + if (pno >= 0) { + fdisk_partition_partno_follow_default(pa, 0); + fdisk_partition_set_partno(pa, pno); + } + } else + p = s; + + while (rc == 0 && p && *p) { + + DBG(SCRIPT, ul_debugobj(dp, " parsing '%s'", p)); + p = (char *) skip_blank(p); + + if (!strncasecmp(p, "start=", 6)) { + p += 6; + rc = next_number(&p, &num, NULL); + if (!rc) { + fdisk_partition_set_start(pa, num); + fdisk_partition_start_follow_default(pa, 0); + } + } else if (!strncasecmp(p, "size=", 5)) { + int pow = 0; + + p += 5; + rc = next_number(&p, &num, &pow); + if (!rc) { + if (pow) /* specified as <num><suffix> */ + num /= dp->cxt->sector_size; + else /* specified as number of sectors */ + fdisk_partition_size_explicit(pa, 1); + fdisk_partition_set_size(pa, num); + fdisk_partition_end_follow_default(pa, 0); + } + + } else if (!strncasecmp(p, "bootable", 8)) { + char *tk = next_token(&p); + if (strcmp(tk, "bootable") == 0) + pa->boot = 1; + else + rc = -EINVAL; + + } else if (!strncasecmp(p, "attrs=", 6)) { + p += 6; + rc = next_string(&p, &pa->attrs); + + } else if (!strncasecmp(p, "uuid=", 5)) { + p += 5; + rc = next_string(&p, &pa->uuid); + + } else if (!strncasecmp(p, "name=", 5)) { + p += 5; + rc = next_string(&p, &pa->name); + + } else if (!strncasecmp(p, "type=", 5) || + + !strncasecmp(p, "Id=", 3)) { /* backward compatiility */ + char *type; + + p += (*p == 'I' ? 3 : 5); /* "Id=" or "type=" */ + + rc = next_string(&p, &type); + if (rc) + break; + pa->type = fdisk_label_parse_parttype( + script_get_label(dp), type); + free(type); + + if (!pa->type || fdisk_parttype_is_unknown(pa->type)) { + rc = -EINVAL; + fdisk_unref_parttype(pa->type); + pa->type = NULL; + break; + } + + } else { + DBG(SCRIPT, ul_debugobj(dp, "script parse error: unknown field '%s'", p)); + rc = -EINVAL; + break; + } + } + + if (!rc) + rc = fdisk_table_add_partition(dp->table, pa); + if (rc) + DBG(SCRIPT, ul_debugobj(dp, "script parse error: [rc=%d]", rc)); + + fdisk_unref_partition(pa); + return rc; +} + +/* original sfdisk supports partition types shortcuts like 'L' = Linux native + */ +static struct fdisk_parttype *translate_type_shortcuts(struct fdisk_script *dp, char *str) +{ + struct fdisk_label *lb; + const char *type = NULL; + + if (strlen(str) != 1) + return NULL; + + lb = script_get_label(dp); + if (!lb) + return NULL; + + if (lb->id == FDISK_DISKLABEL_DOS) { + switch (*str) { + case 'L': /* Linux */ + type = "83"; + break; + case 'S': /* Swap */ + type = "82"; + break; + case 'E': /* Dos extended */ + type = "05"; + break; + case 'X': /* Linux extended */ + type = "85"; + break; + } + } else if (lb->id == FDISK_DISKLABEL_GPT) { + switch (*str) { + case 'L': /* Linux */ + type = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"; + break; + case 'S': /* Swap */ + type = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F"; + break; + case 'H': /* Home */ + type = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915"; + break; + } + } + + return type ? fdisk_label_parse_parttype(lb, type) : NULL; +} + +/* simple format: + * <start>, <size>, <type>, <bootable>, ... + */ +static int parse_commas_line(struct fdisk_script *dp, char *s) +{ + int rc = 0; + char *p = s, *str; + struct fdisk_partition *pa; + enum { ITEM_START, ITEM_SIZE, ITEM_TYPE, ITEM_BOOTABLE }; + int item = -1; + + assert(dp); + assert(s); + + pa = fdisk_new_partition(); + if (!pa) + return -ENOMEM; + + fdisk_partition_start_follow_default(pa, 1); + fdisk_partition_end_follow_default(pa, 1); + fdisk_partition_partno_follow_default(pa, 1); + + while (rc == 0 && p && *p) { + uint64_t num; + char *begin; + + p = (char *) skip_blank(p); + item++; + + DBG(SCRIPT, ul_debugobj(dp, " parsing item %d ('%s')", item, p)); + begin = p; + + switch (item) { + case ITEM_START: + if (*p == ',' || *p == ';') + fdisk_partition_start_follow_default(pa, 1); + else { + rc = next_number(&p, &num, NULL); + if (!rc) + fdisk_partition_set_start(pa, num); + fdisk_partition_start_follow_default(pa, 0); + } + break; + case ITEM_SIZE: + if (*p == ',' || *p == ';' || *p == '+') + fdisk_partition_end_follow_default(pa, 1); + else { + int pow = 0; + rc = next_number(&p, &num, &pow); + if (!rc) { + if (pow) /* specified as <size><suffix> */ + num /= dp->cxt->sector_size; + else /* specified as number of sectors */ + fdisk_partition_size_explicit(pa, 1); + fdisk_partition_set_size(pa, num); + } + fdisk_partition_end_follow_default(pa, 0); + } + break; + case ITEM_TYPE: + if (*p == ',' || *p == ';') + break; /* use default type */ + + rc = next_string(&p, &str); + if (rc) + break; + + pa->type = translate_type_shortcuts(dp, str); + if (!pa->type) + pa->type = fdisk_label_parse_parttype( + script_get_label(dp), str); + free(str); + + if (!pa->type || fdisk_parttype_is_unknown(pa->type)) { + rc = -EINVAL; + fdisk_unref_parttype(pa->type); + pa->type = NULL; + break; + } + break; + case ITEM_BOOTABLE: + if (*p == ',' || *p == ';') + break; + else { + char *tk = next_token(&p); + if (tk && *tk == '*' && *(tk + 1) == '\0') + pa->boot = 1; + else if (tk && *tk == '-' && *(tk + 1) == '\0') + pa->boot = 0; + else + rc = -EINVAL; + } + break; + default: + break; + } + + if (begin == p) + p++; + } + + if (!rc) + rc = fdisk_table_add_partition(dp->table, pa); + if (rc) + DBG(SCRIPT, ul_debugobj(dp, "script parse error: [rc=%d]", rc)); + + fdisk_unref_partition(pa); + return rc; +} + +/* modifies @s ! */ +int fdisk_script_read_buffer(struct fdisk_script *dp, char *s) +{ + int rc = 0; + + assert(dp); + assert(s); + + DBG(SCRIPT, ul_debugobj(dp, " parsing buffer")); + + s = (char *) skip_blank(s); + if (!s || !*s) + return 0; /* nothing baby, ignore */ + + if (!dp->table) { + dp->table = fdisk_new_table(); + if (!dp->table) + return -ENOMEM; + } + + /* parse header lines only if no partition specified yet */ + if (fdisk_table_is_empty(dp->table) && is_header_line(s)) + rc = parse_header_line(dp, s); + + /* parse script format */ + else if (strchr(s, '=')) + rc = parse_script_line(dp, s); + + /* parse simple <value>, ... format */ + else + rc = parse_commas_line(dp, s); + + if (rc) + DBG(SCRIPT, ul_debugobj(dp, "%zu: parse error [rc=%d]", + dp->nlines, rc)); + return rc; +} + +/** + * fdisk_script_read_line: + * @dp: script + * @f: file + * @buf: buffer to store one line of the file + * @bufsz: buffer size + * + * Reads next line into dump. + * + * Returns: 0 on success, <0 on error, 1 when nothing to read. + */ +int fdisk_script_read_line(struct fdisk_script *dp, FILE *f, char *buf, size_t bufsz) +{ + char *s; + + assert(dp); + assert(f); + + DBG(SCRIPT, ul_debugobj(dp, " parsing line %zu", dp->nlines)); + + /* read the next non-blank non-comment line */ + do { + if (fgets(buf, bufsz, f) == NULL) + return 1; + dp->nlines++; + s = strchr(buf, '\n'); + if (!s) { + /* Missing final newline? Otherwise an extremely */ + /* long line - assume file was corrupted */ + if (feof(f)) { + DBG(SCRIPT, ul_debugobj(dp, "no final newline")); + s = strchr(buf, '\0'); + } else { + DBG(SCRIPT, ul_debugobj(dp, + "%zu: missing newline at line", dp->nlines)); + return -EINVAL; + } + } + + *s = '\0'; + if (--s >= buf && *s == '\r') + *s = '\0'; + s = (char *) skip_blank(buf); + } while (*s == '\0' || *s == '#'); + + return fdisk_script_read_buffer(dp, s); +} + + +/** + * fdisk_script_read_file: + * @dp: script + * @f: input file + * + * Reads file @f into script @dp. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_script_read_file(struct fdisk_script *dp, FILE *f) +{ + char buf[BUFSIZ]; + int rc; + + assert(dp); + assert(f); + + DBG(SCRIPT, ul_debugobj(dp, "parsing file")); + + while (!feof(f)) { + rc = fdisk_script_read_line(dp, f, buf, sizeof(buf)); + if (rc) + break; + } + + if (rc == 1) + rc = 0; /* end of file */ + + DBG(SCRIPT, ul_debugobj(dp, "parsing file done [rc=%d]", rc)); + return rc; +} + +/** + * fdisk_set_script: + * @cxt: context + * @dp: script (or NULL to remove previous reference) + * + * Sets reference to the @dp script. The script headers might be used by label + * drivers to overwrite built-in defaults (for example disk label Id) and label + * driver might optimize the default semantic to be more usable for scripts + * (for example to not ask for primary/logical/extended partition type). + * + * Note that script also contains reference to the fdisk context (see + * fdisk_new_script()). This context may be completely independent on + * context used for fdisk_set_script(). + * + * Returns: <0 on error, 0 on success. + */ +int fdisk_set_script(struct fdisk_context *cxt, struct fdisk_script *dp) +{ + assert(cxt); + + /* unref old */ + if (cxt->script) + fdisk_unref_script(cxt->script); + + /* ref new */ + cxt->script = dp; + if (cxt->script) { + DBG(CXT, ul_debugobj(cxt, "setting reference to script %p", cxt->script)); + fdisk_ref_script(cxt->script); + } + + return 0; +} + +/** + * fdisk_get_script: + * @cxt: context + * + * Returns: the current script or NULL. + */ +struct fdisk_script *fdisk_get_script(struct fdisk_context *cxt) +{ + assert(cxt); + return cxt->script; +} + +/** + * fdisk_apply_script_headers: + * @cxt: context + * @dp: script + * + * Associte context @cxt with script @dp and creates a new empty disklabel. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_apply_script_headers(struct fdisk_context *cxt, struct fdisk_script *dp) +{ + const char *name; + + assert(cxt); + assert(dp); + + DBG(SCRIPT, ul_debugobj(dp, "applying script headers")); + fdisk_set_script(cxt, dp); + + /* create empty label */ + name = fdisk_script_get_header(dp, "label"); + if (!name) + return -EINVAL; + + return fdisk_create_disklabel(cxt, name); +} + +/** + * fdisk_apply_script: + * @cxt: context + * @dp: script + * + * This function creates a new disklabel and partition within context @cxt. You + * have to call fdisk_write_disklabel() to apply changes to the device. + * + * Returns: 0 on error, <0 on error. + */ +int fdisk_apply_script(struct fdisk_context *cxt, struct fdisk_script *dp) +{ + int rc; + struct fdisk_script *old; + + assert(dp); + assert(cxt); + + DBG(CXT, ul_debugobj(cxt, "applying script %p", dp)); + + old = fdisk_get_script(cxt); + + /* create empty disk label */ + rc = fdisk_apply_script_headers(cxt, dp); + + /* create partitions */ + if (!rc && dp->table) + rc = fdisk_apply_table(cxt, dp->table); + + fdisk_set_script(cxt, old); + DBG(CXT, ul_debugobj(cxt, "script done [rc=%d]", rc)); + return rc; +} + +#ifdef TEST_PROGRAM +int test_dump(struct fdisk_test *ts, int argc, char *argv[]) +{ + char *devname = argv[1]; + struct fdisk_context *cxt; + struct fdisk_script *dp; + + cxt = fdisk_new_context(); + fdisk_assign_device(cxt, devname, 1); + + dp = fdisk_new_script(cxt); + fdisk_script_read_context(dp, NULL); + + fdisk_script_write_file(dp, stdout); + fdisk_unref_script(dp); + fdisk_unref_context(cxt); + + return 0; +} + +int test_read(struct fdisk_test *ts, int argc, char *argv[]) +{ + char *filename = argv[1]; + struct fdisk_script *dp; + struct fdisk_context *cxt; + FILE *f; + + if (!(f = fopen(filename, "r"))) + err(EXIT_FAILURE, "%s: cannot open", filename); + + cxt = fdisk_new_context(); + dp = fdisk_new_script(cxt); + + fdisk_script_read_file(dp, f); + fclose(f); + + fdisk_script_write_file(dp, stdout); + fdisk_unref_script(dp); + fdisk_unref_context(cxt); + + return 0; +} + +int test_stdin(struct fdisk_test *ts, int argc, char *argv[]) +{ + char buf[BUFSIZ]; + struct fdisk_script *dp; + struct fdisk_context *cxt; + int rc = 0; + + cxt = fdisk_new_context(); + dp = fdisk_new_script(cxt); + fdisk_script_set_header(dp, "label", "dos"); + + printf("<start>, <size>, <type>, <bootable: *|->\n"); + do { + struct fdisk_partition *pa; + size_t n = fdisk_table_get_nents(dp->table); + + printf(" #%zu :\n", n + 1); + rc = fdisk_script_read_line(dp, stdin, buf, sizeof(buf)); + + if (rc == 0) { + pa = fdisk_table_get_partition(dp->table, n); + printf(" #%zu %12ju %12ju\n", n + 1, + fdisk_partition_get_start(pa), + fdisk_partition_get_size(pa)); + } + } while (rc == 0); + + if (!rc) + fdisk_script_write_file(dp, stdout); + fdisk_unref_script(dp); + fdisk_unref_context(cxt); + + return rc; +} + +int test_apply(struct fdisk_test *ts, int argc, char *argv[]) +{ + char *devname = argv[1], *scriptname = argv[2]; + struct fdisk_context *cxt; + struct fdisk_script *dp = NULL; + struct fdisk_table *tb = NULL; + struct fdisk_iter *itr = NULL; + struct fdisk_partition *pa = NULL; + int rc; + + cxt = fdisk_new_context(); + fdisk_assign_device(cxt, devname, 0); + + dp = fdisk_new_script_from_file(cxt, scriptname); + if (!dp) + return -errno; + + rc = fdisk_apply_script(cxt, dp); + if (rc) + goto done; + fdisk_unref_script(dp); + + /* list result */ + fdisk_list_disklabel(cxt); + fdisk_get_partitions(cxt, &tb); + + itr = fdisk_new_iter(FDISK_ITER_FORWARD); + while (fdisk_table_next_partition(tb, itr, &pa) == 0) { + printf(" #%zu %12ju %12ju\n", fdisk_partition_get_partno(pa), + fdisk_partition_get_start(pa), + fdisk_partition_get_size(pa)); + } + +done: + fdisk_free_iter(itr); + fdisk_unref_table(tb); + + /*fdisk_write_disklabel(cxt);*/ + fdisk_unref_context(cxt); + return 0; +} + +int main(int argc, char *argv[]) +{ + struct fdisk_test tss[] = { + { "--dump", test_dump, "<device> dump PT as script" }, + { "--read", test_read, "<file> read PT script from file" }, + { "--apply", test_apply, "<device> <file> try apply script from file to device" }, + { "--stdin", test_stdin, " read input like sfdisk" }, + { NULL } + }; + + return fdisk_run_test(tss, argc, argv); +} + +#endif diff --git a/libblkid/libfdisk/src/sgi.c b/libblkid/libfdisk/src/sgi.c new file mode 100644 index 000000000..cd4cedff0 --- /dev/null +++ b/libblkid/libfdisk/src/sgi.c @@ -0,0 +1,1185 @@ +/* + * + * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org> + * 2013 Karel Zak <kzak@redhat.com> + * + * This is a re-written version for libfdisk, the original was fdisksgilabel.c + * from util-linux fdisk, by: + * + * Andreas Neuper, Sep 1998, + * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999, + * Phillip Kesling <pkesling@sgi.com>, Mar 2003. + */ + +#include "c.h" +#include "nls.h" +#include "all-io.h" + +#include "blkdev.h" + +#include "bitops.h" +#include "pt-sgi.h" +#include "pt-mbr.h" +#include "fdiskP.h" + +/** + * SECTION: sgi + * @title: SGI + * @short_description: disk label specific functions + * + */ + +/* + * in-memory fdisk SGI stuff + */ +struct fdisk_sgi_label { + struct fdisk_label head; /* generic fdisk part */ + struct sgi_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */ + + struct sgi_freeblocks { + unsigned int first; + unsigned int last; + } freelist[SGI_MAXPARTITIONS + 1]; +}; + +static struct fdisk_parttype sgi_parttypes[] = +{ + {SGI_TYPE_VOLHDR, N_("SGI volhdr")}, + {SGI_TYPE_TRKREPL, N_("SGI trkrepl")}, + {SGI_TYPE_SECREPL, N_("SGI secrepl")}, + {SGI_TYPE_SWAP, N_("SGI raw")}, + {SGI_TYPE_BSD, N_("SGI bsd")}, + {SGI_TYPE_SYSV, N_("SGI sysv")}, + {SGI_TYPE_ENTIRE_DISK, N_("SGI volume")}, + {SGI_TYPE_EFS, N_("SGI efs")}, + {SGI_TYPE_LVOL, N_("SGI lvol")}, + {SGI_TYPE_RLVOL, N_("SGI rlvol")}, + {SGI_TYPE_XFS, N_("SGI xfs")}, + {SGI_TYPE_XFSLOG, N_("SGI xfslog")}, + {SGI_TYPE_XLV, N_("SGI xlv")}, + {SGI_TYPE_XVM, N_("SGI xvm")}, + {MBR_LINUX_SWAP_PARTITION, N_("Linux swap")}, + {MBR_LINUX_DATA_PARTITION, N_("Linux native")}, + {MBR_LINUX_LVM_PARTITION, N_("Linux LVM")}, + {MBR_LINUX_RAID_PARTITION, N_("Linux RAID")}, + {0, NULL } +}; + +static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i ); +static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i ); +static int sgi_get_bootpartition(struct fdisk_context *cxt); +static int sgi_get_swappartition(struct fdisk_context *cxt); + +/* Returns a pointer buffer with on-disk data. */ +static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + return ((struct fdisk_sgi_label *) cxt->label)->header; +} + +/* Returns in-memory fdisk data. */ +static inline struct fdisk_sgi_label *self_label(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + return (struct fdisk_sgi_label *) cxt->label; +} + +/* + * Information within second on-disk block + */ +#define SGI_INFO_MAGIC 0x00072959 + +struct sgi_info { + unsigned int magic; /* looks like a magic number */ + unsigned int a2; + unsigned int a3; + unsigned int a4; + unsigned int b1; + unsigned short b2; + unsigned short b3; + unsigned int c[16]; + unsigned short d[3]; + unsigned char scsi_string[50]; + unsigned char serial[137]; + unsigned short check1816; + unsigned char installer[225]; +}; + +static struct sgi_info *sgi_new_info(void) +{ + struct sgi_info *info = calloc(1, sizeof(struct sgi_info)); + + if (!info) + return NULL; + + info->magic = cpu_to_be32(SGI_INFO_MAGIC); + info->b1 = cpu_to_be32(-1); + info->b2 = cpu_to_be16(-1); + info->b3 = cpu_to_be16(1); + + /* You may want to replace this string !!!!!!! */ + strcpy((char *) info->scsi_string, "IBM OEM 0662S12 3 30"); + strcpy((char *) info->serial, "0000"); + info->check1816 = cpu_to_be16(18 * 256 + 16); + strcpy((char *) info->installer, "Sfx version 5.3, Oct 18, 1994"); + + return info; +} + +static void sgi_free_info(struct sgi_info *info) +{ + free(info); +} + +/** + * fdisk_sgi_create_info: + * @cxt: context + * + * This function add hint about SGI label (e.g. set "sgilabel" as volume name) + * to the first SGI volume. This is probably old SGI convention without any + * effect to the device partitioning. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_sgi_create_info(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + + /* I keep SGI's habit to write the sgilabel to the second block */ + sgilabel->volume[0].block_num = cpu_to_be32(2); + sgilabel->volume[0].num_bytes = cpu_to_be32(sizeof(struct sgi_info)); + strncpy((char *) sgilabel->volume[0].name, "sgilabel", 8); + + fdisk_info(cxt, _("SGI info created on second sector.")); + return 0; +} + + +/* + * only dealing with free blocks here + */ +static void set_freelist(struct fdisk_context *cxt, + size_t i, unsigned int f, unsigned int l) +{ + struct fdisk_sgi_label *sgi = self_label(cxt); + + if (i < ARRAY_SIZE(sgi->freelist)) { + sgi->freelist[i].first = f; + sgi->freelist[i].last = l; + } +} + +static void add_to_freelist(struct fdisk_context *cxt, + unsigned int f, unsigned int l) +{ + struct fdisk_sgi_label *sgi = self_label(cxt); + size_t i; + + for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) { + if (sgi->freelist[i].last == 0) + break; + } + set_freelist(cxt, i, f, l); +} + +static void clear_freelist(struct fdisk_context *cxt) +{ + struct fdisk_sgi_label *sgi = self_label(cxt); + + memset(sgi->freelist, 0, sizeof(sgi->freelist)); +} + +static unsigned int is_in_freelist(struct fdisk_context *cxt, unsigned int b) +{ + struct fdisk_sgi_label *sgi = self_label(cxt); + size_t i; + + for (i = 0; i < ARRAY_SIZE(sgi->freelist); i++) { + if (sgi->freelist[i].first <= b + && sgi->freelist[i].last >= b) + return sgi->freelist[i].last; + } + + return 0; +} + + +static int sgi_get_nsect(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be16_to_cpu(sgilabel->devparam.nsect); +} + +static int sgi_get_ntrks(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be16_to_cpu(sgilabel->devparam.ntrks); +} + +static size_t count_used_partitions(struct fdisk_context *cxt) +{ + size_t i, ct = 0; + + for (i = 0; i < cxt->label->nparts_max; i++) + ct += sgi_get_num_sectors(cxt, i) > 0; + + return ct; +} + +static int sgi_probe_label(struct fdisk_context *cxt) +{ + struct fdisk_sgi_label *sgi; + struct sgi_disklabel *sgilabel; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + assert(sizeof(struct sgi_disklabel) <= 512); + + /* map first sector to header */ + sgi = (struct fdisk_sgi_label *) cxt->label; + sgi->header = (struct sgi_disklabel *) cxt->firstsector; + sgilabel = sgi->header; + + if (be32_to_cpu(sgilabel->magic) != SGI_LABEL_MAGIC) { + sgi->header = NULL; + return 0; + } + + /* + * test for correct checksum + */ + if (sgi_pt_checksum(sgilabel) != 0) + fdisk_warnx(cxt, _("Detected an SGI disklabel with wrong checksum.")); + + clear_freelist(cxt); + cxt->label->nparts_max = SGI_MAXPARTITIONS; + cxt->label->nparts_cur = count_used_partitions(cxt); + return 1; +} + +static int sgi_list_table(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + struct sgi_device_parameter *sgiparam = &sgilabel->devparam; + int rc = 0; + + if (fdisk_is_details(cxt)) + fdisk_info(cxt, _( + "Label geometry: %d heads, %llu sectors\n" + " %llu cylinders, %d physical cylinders\n" + " %d extra sects/cyl, interleave %d:1\n"), + cxt->geom.heads, cxt->geom.sectors, + cxt->geom.cylinders, be16_to_cpu(sgiparam->pcylcount), + (int) sgiparam->sparecyl, be16_to_cpu(sgiparam->ilfact)); + + fdisk_info(cxt, _("Bootfile: %s"), sgilabel->boot_file); + return rc; +} + +static unsigned int sgi_get_start_sector(struct fdisk_context *cxt, int i) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be32_to_cpu(sgilabel->partitions[i].first_block); +} + +static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be32_to_cpu(sgilabel->partitions[i].num_blocks); +} + +static int sgi_get_sysid(struct fdisk_context *cxt, int i) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be32_to_cpu(sgilabel->partitions[i].type); +} + +static int sgi_get_bootpartition(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be16_to_cpu(sgilabel->root_part_num); +} + +static int sgi_get_swappartition(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + return be16_to_cpu(sgilabel->swap_part_num); +} + +static unsigned int sgi_get_lastblock(struct fdisk_context *cxt) +{ + return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders; +} + +static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n) +{ + struct fdisk_parttype *t; + + if (n >= cxt->label->nparts_max) + return NULL; + + t = fdisk_label_get_parttype_from_code(cxt->label, sgi_get_sysid(cxt, n)); + return t ? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL); +} + +/* fdisk_get_partition() backend */ +static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa) +{ + fdisk_sector_t start, len; + + pa->used = sgi_get_num_sectors(cxt, n) > 0; + if (!pa->used) + return 0; + + start = sgi_get_start_sector(cxt, n); + len = sgi_get_num_sectors(cxt, n); + + pa->type = sgi_get_parttype(cxt, n); + pa->size = len; + pa->start = start; + + if (pa->type && pa->type->code == SGI_TYPE_ENTIRE_DISK) + pa->wholedisk = 1; + + pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" : + sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL; + if (pa->attrs) + pa->attrs = strdup(pa->attrs); + + return 0; +} + + +static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name) +{ + size_t sz; + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + + sz = strlen(name); + + if (sz < 3) { + /* "/a\n" is minimum */ + fdisk_warnx(cxt, _("Invalid bootfile! The bootfile must " + "be an absolute non-zero pathname, " + "e.g. \"/unix\" or \"/unix.save\".")); + return -EINVAL; + + } else if (sz > sizeof(sgilabel->boot_file)) { + fdisk_warnx(cxt, P_("Name of bootfile is too long: %zu byte maximum.", + "Name of bootfile is too long: %zu bytes maximum.", + sizeof(sgilabel->boot_file)), + sizeof(sgilabel->boot_file)); + return -EINVAL; + + } else if (*name != '/') { + fdisk_warnx(cxt, _("Bootfile must have a fully qualified pathname.")); + return -EINVAL; + } + + if (strncmp(name, (char *) sgilabel->boot_file, + sizeof(sgilabel->boot_file))) { + fdisk_warnx(cxt, _("Be aware that the bootfile is not checked " + "for existence. SGI's default is \"/unix\", " + "and for backup \"/unix.save\".")); + return 0; /* filename is correct and did change */ + } + + return 1; /* filename did not change */ +} + +/** + * fdisk_sgi_set_bootfile: + * @cxt: context + * + * Allows to set SGI boot file. The function uses Ask API for dialog with + * user. + * + * Returns: 0 on success, <0 on error + */ +int fdisk_sgi_set_bootfile(struct fdisk_context *cxt) +{ + int rc = 0; + size_t sz; + char *name = NULL; + struct sgi_disklabel *sgilabel = self_disklabel(cxt); + + fdisk_info(cxt, _("The current boot file is: %s"), sgilabel->boot_file); + + rc = fdisk_ask_string(cxt, _("Enter of the new boot file"), &name); + if (rc == 0) + rc = sgi_check_bootfile(cxt, name); + if (rc) { + if (rc == 1) + fdisk_info(cxt, _("Boot file is unchanged.")); + goto done; + } + + memset(sgilabel->boot_file, 0, sizeof(sgilabel->boot_file)); + sz = strlen(name); + + assert(sz <= sizeof(sgilabel->boot_file)); /* see sgi_check_bootfile() */ + + memcpy(sgilabel->boot_file, name, sz); + + fdisk_info(cxt, _("Bootfile has been changed to \"%s\"."), name); +done: + free(name); + return rc; +} + +static int sgi_write_disklabel(struct fdisk_context *cxt) +{ + struct sgi_disklabel *sgilabel; + struct sgi_info *info = NULL; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + sgilabel = self_disklabel(cxt); + sgilabel->csum = 0; + sgilabel->csum = cpu_to_be32(sgi_pt_checksum(sgilabel)); + + assert(sgi_pt_checksum(sgilabel) == 0); + + if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0) + goto err; + if (write_all(cxt->dev_fd, sgilabel, DEFAULT_SECTOR_SIZE)) + goto err; + if (!strncmp((char *) sgilabel->volume[0].name, "sgilabel", 8)) { + /* + * Keep this habit of first writing the "sgilabel". + * I never tested whether it works without. (AN 1998-10-02) + */ + int infostartblock + = be32_to_cpu(sgilabel->volume[0].block_num); + + if (lseek(cxt->dev_fd, (off_t) infostartblock * + DEFAULT_SECTOR_SIZE, SEEK_SET) < 0) + goto err; + info = sgi_new_info(); + if (!info) + goto err; + if (write_all(cxt->dev_fd, info, sizeof(*info))) + goto err; + } + + sgi_free_info(info); + return 0; +err: + sgi_free_info(info); + return -errno; +} + +static int compare_start(struct fdisk_context *cxt, + const void *x, const void *y) +{ + /* + * Sort according to start sectors and prefer the largest partition: + * entry zero is the entire-disk entry. + */ + unsigned int i = *(int *) x; + unsigned int j = *(int *) y; + unsigned int a = sgi_get_start_sector(cxt, i); + unsigned int b = sgi_get_start_sector(cxt, j); + unsigned int c = sgi_get_num_sectors(cxt, i); + unsigned int d = sgi_get_num_sectors(cxt, j); + + if (a == b) + return (d > c) ? 1 : (d == c) ? 0 : -1; + return (a > b) ? 1 : -1; +} + +static void generic_swap(void *a0, void *b0, int size) +{ + char *a = a0, *b = b0; + + for (; size > 0; --size, a++, b++) { + char t = *a; + *a = *b; + *b = t; + } +} + + +/* heap sort, based on Matt Mackall's linux kernel version */ +static void sort(void *base0, size_t num, size_t size, struct fdisk_context *cxt, + int (*cmp_func)(struct fdisk_context *, const void *, const void *)) +{ + /* pre-scale counters for performance */ + int i = (num/2 - 1) * size; + size_t n = num * size, c, r; + char *base = base0; + + /* heapify */ + for ( ; i >= 0; i -= size) { + for (r = i; r * 2 + size < n; r = c) { + c = r * 2 + size; + if (c < n - size && + cmp_func(cxt, base + c, base + c + size) < 0) + c += size; + if (cmp_func(cxt, base + r, base + c) >= 0) + break; + generic_swap(base + r, base + c, size); + } + } + + /* sort */ + for (i = n - size; i > 0; i -= size) { + generic_swap(base, base + i, size); + for (r = 0; r * 2 + size < (size_t) i; r = c) { + c = r * 2 + size; + if (c < i - size && + cmp_func(cxt, base + c, base + c + size) < 0) + c += size; + if (cmp_func(cxt, base + r, base + c) >= 0) + break; + generic_swap(base + r, base + c, size); + } + } +} + +static int verify_disklabel(struct fdisk_context *cxt, int verbose) +{ + int Index[SGI_MAXPARTITIONS]; /* list of valid partitions */ + int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */ + int entire = 0, i = 0; + unsigned int start = 0; + long long gap = 0; /* count unused blocks */ + unsigned int lastblock = sgi_get_lastblock(cxt); + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + clear_freelist(cxt); + memset(Index, 0, sizeof(Index)); + + for (i=0; i < SGI_MAXPARTITIONS; i++) { + if (sgi_get_num_sectors(cxt, i) != 0) { + Index[sortcount++] = i; + if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK + && entire++ == 1) { + if (verbose) + fdisk_info(cxt, _("More than one entire " + "disk entry present.")); + } + } + } + if (sortcount == 0) { + if (verbose) + fdisk_info(cxt, _("No partitions defined.")); + if (lastblock) + add_to_freelist(cxt, 0, lastblock); + return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1; + } + + sort(Index, sortcount, sizeof(Index[0]), cxt, compare_start); + + if (sgi_get_sysid(cxt, Index[0]) == SGI_TYPE_ENTIRE_DISK) { + if (verbose && Index[0] != 10) + fdisk_info(cxt, _("IRIX likes it when partition 11 " + "covers the entire disk.")); + + if (verbose && sgi_get_start_sector(cxt, Index[0]) != 0) + fdisk_info(cxt, _("The entire disk partition should " + "start at block 0, not at block %d."), + sgi_get_start_sector(cxt, Index[0])); + + if (verbose && sgi_get_num_sectors(cxt, Index[0]) != lastblock) + DBG(LABEL, ul_debug( + "entire disk partition=%ds, but disk=%ds", + sgi_get_num_sectors(cxt, Index[0]), + lastblock)); + lastblock = sgi_get_num_sectors(cxt, Index[0]); + } else if (verbose) { + fdisk_info(cxt, _("Partition 11 should cover the entire disk.")); + DBG(LABEL, ul_debug("sysid=%d\tpartition=%d", + sgi_get_sysid(cxt, Index[0]), Index[0]+1)); + } + for (i=1, start=0; i<sortcount; i++) { + int cylsize = sgi_get_nsect(cxt) * sgi_get_ntrks(cxt); + + if (verbose && cylsize + && (sgi_get_start_sector(cxt, Index[i]) % cylsize) != 0) + DBG(LABEL, ul_debug("partition %d does not start on " + "cylinder boundary.", Index[i]+1)); + + if (verbose && cylsize + && sgi_get_num_sectors(cxt, Index[i]) % cylsize != 0) + DBG(LABEL, ul_debug("partition %d does not end on " + "cylinder boundary.", Index[i]+1)); + + /* We cannot handle several "entire disk" entries. */ + if (sgi_get_sysid(cxt, Index[i]) == SGI_TYPE_ENTIRE_DISK) + continue; + + if (start > sgi_get_start_sector(cxt, Index[i])) { + if (verbose) + fdisk_info(cxt, + P_("Partitions %d and %d overlap by %d sector.", + "Partitions %d and %d overlap by %d sectors.", + start - sgi_get_start_sector(cxt, Index[i])), + Index[i-1]+1, Index[i]+1, + start - sgi_get_start_sector(cxt, Index[i])); + if (gap > 0) gap = -gap; + if (gap == 0) gap = -1; + } + if (start < sgi_get_start_sector(cxt, Index[i])) { + if (verbose) + fdisk_info(cxt, + P_("Unused gap of %8u sector: sector %8u", + "Unused gap of %8u sectors: sectors %8u-%u", + sgi_get_start_sector(cxt, Index[i]) - start), + sgi_get_start_sector(cxt, Index[i]) - start, + start, sgi_get_start_sector(cxt, Index[i])-1); + gap += sgi_get_start_sector(cxt, Index[i]) - start; + add_to_freelist(cxt, start, + sgi_get_start_sector(cxt, Index[i])); + } + start = sgi_get_start_sector(cxt, Index[i]) + + sgi_get_num_sectors(cxt, Index[i]); + /* Align free space on cylinder boundary. */ + if (cylsize && start % cylsize) + start += cylsize - (start % cylsize); + + DBG(LABEL, ul_debug("%2d:%12d\t%12d\t%12d", Index[i], + sgi_get_start_sector(cxt, Index[i]), + sgi_get_num_sectors(cxt, Index[i]), + sgi_get_sysid(cxt, Index[i]))); + } + if (start < lastblock) { + if (verbose) + fdisk_info(cxt, P_("Unused gap of %8u sector: sector %8u", + "Unused gap of %8u sectors: sectors %8u-%u", + lastblock - start), + lastblock - start, start, lastblock-1); + gap += lastblock - start; + add_to_freelist(cxt, start, lastblock); + } + /* + * Done with arithmetics. Go for details now. + */ + if (verbose) { + if (sgi_get_bootpartition(cxt) < 0 + || !sgi_get_num_sectors(cxt, sgi_get_bootpartition(cxt))) + fdisk_info(cxt, _("The boot partition does not exist.")); + + if (sgi_get_swappartition(cxt) < 0 + || !sgi_get_num_sectors(cxt, sgi_get_swappartition(cxt))) + fdisk_info(cxt, _("The swap partition does not exist.")); + + else if (sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != SGI_TYPE_SWAP + && sgi_get_sysid(cxt, sgi_get_swappartition(cxt)) != MBR_LINUX_SWAP_PARTITION) + fdisk_info(cxt, _("The swap partition has no swap type.")); + + if (sgi_check_bootfile(cxt, "/unix")) + fdisk_info(cxt, _("You have chosen an unusual bootfile name.")); + } + + return (gap > 0) ? 1 : (gap == 0) ? 0 : -1; +} + +static int sgi_verify_disklabel(struct fdisk_context *cxt) +{ + return verify_disklabel(cxt, 1); +} + +static int sgi_gaps(struct fdisk_context *cxt) +{ + /* + * returned value is: + * = 0 : disk is properly filled to the rim + * < 0 : there is an overlap + * > 0 : there is still some vacant space + */ + return verify_disklabel(cxt, 0); +} + +/* Returns partition index of first entry marked as entire disk. */ +static int sgi_entire(struct fdisk_context *cxt) +{ + size_t i; + + for (i = 0; i < SGI_MAXPARTITIONS; i++) + if (sgi_get_sysid(cxt, i) == SGI_TYPE_ENTIRE_DISK) + return i; + return -1; +} + +static int set_partition(struct fdisk_context *cxt, size_t i, + unsigned int start, unsigned int length, int sys) +{ + struct sgi_disklabel *sgilabel; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + sgilabel = self_disklabel(cxt); + sgilabel->partitions[i].type = cpu_to_be32(sys); + sgilabel->partitions[i].num_blocks = cpu_to_be32(length); + sgilabel->partitions[i].first_block = cpu_to_be32(start); + + fdisk_label_set_changed(cxt->label, 1); + + if (sgi_gaps(cxt) < 0) /* rebuild freelist */ + fdisk_warnx(cxt, _("Partition overlap on the disk.")); + if (length) { + struct fdisk_parttype *t = + fdisk_label_get_parttype_from_code(cxt->label, sys); + fdisk_info_new_partition(cxt, i + 1, start, start + length, t); + } + + return 0; +} + +static void sgi_set_entire(struct fdisk_context *cxt) +{ + size_t n; + + for (n = 10; n < cxt->label->nparts_max; n++) { + if (!sgi_get_num_sectors(cxt, n)) { + set_partition(cxt, n, 0, sgi_get_lastblock(cxt), SGI_TYPE_ENTIRE_DISK); + break; + } + } +} + +static void sgi_set_volhdr(struct fdisk_context *cxt) +{ + size_t n; + + for (n = 8; n < cxt->label->nparts_max; n++) { + if (!sgi_get_num_sectors(cxt, n)) { + /* Choose same default volume header size as IRIX fx uses. */ + if (4096 < sgi_get_lastblock(cxt)) + set_partition(cxt, n, 0, 4096, SGI_TYPE_VOLHDR); + break; + } + } +} + +static int sgi_delete_partition(struct fdisk_context *cxt, size_t partnum) +{ + int rc; + + assert(cxt); + assert(cxt->label); + + if (partnum > cxt->label->nparts_max) + return -EINVAL; + + rc = set_partition(cxt, partnum, 0, 0, 0); + + cxt->label->nparts_cur = count_used_partitions(cxt); + + return rc; +} + +static int sgi_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + struct fdisk_sgi_label *sgi; + char mesg[256]; + unsigned int first = 0, last = 0; + struct fdisk_ask *ask; + int sys = pa && pa->type ? pa->type->code : SGI_TYPE_XFS; + int rc; + size_t n; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + rc = fdisk_partition_next_partno(pa, cxt, &n); + if (rc) + return rc; + if (n == 10) + sys = SGI_TYPE_ENTIRE_DISK; + else if (n == 8) + sys = 0; + + sgi = self_label(cxt); + + if (sgi_get_num_sectors(cxt, n)) { + fdisk_warnx(cxt, _("Partition %zu is already defined. " + "Delete it before re-adding it."), n + 1); + return -EINVAL; + } + if (!cxt->script && sgi_entire(cxt) == -1 && sys != SGI_TYPE_ENTIRE_DISK) { + fdisk_info(cxt, _("Attempting to generate entire disk entry automatically.")); + sgi_set_entire(cxt); + sgi_set_volhdr(cxt); + } + if (sgi_gaps(cxt) == 0 && sys != SGI_TYPE_ENTIRE_DISK) { + fdisk_warnx(cxt, _("The entire disk is already covered with partitions.")); + return -EINVAL; + } + if (sgi_gaps(cxt) < 0) { + fdisk_warnx(cxt, _("You got a partition overlap on the disk. Fix it first!")); + return -EINVAL; + } + + if (sys == SGI_TYPE_ENTIRE_DISK) { + first = 0; + last = sgi_get_lastblock(cxt); + } else { + first = sgi->freelist[0].first; + last = sgi->freelist[0].last; + } + + /* first sector */ + if (pa && pa->start_follow_default) + ; + else if (pa && fdisk_partition_has_start(pa)) { + first = pa->start; + last = is_in_freelist(cxt, first); + + if (sys != SGI_TYPE_ENTIRE_DISK && !last) + return -ERANGE; + } else { + snprintf(mesg, sizeof(mesg), _("First %s"), + fdisk_get_unit(cxt, FDISK_SINGULAR)); + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1); /* maximal */ + + rc = fdisk_do_ask(cxt, ask); + first = fdisk_ask_number_get_result(ask); + fdisk_unref_ask(ask); + + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) + first *= fdisk_get_units_per_sector(cxt); + } + + if (first && sys == SGI_TYPE_ENTIRE_DISK) + fdisk_info(cxt, _("It is highly recommended that the " + "eleventh partition covers the entire " + "disk and is of type 'SGI volume'.")); + if (!last) + last = is_in_freelist(cxt, first); + + /* last sector */ + if (pa && pa->end_follow_default) + last -= 1ULL; + else if (pa && fdisk_partition_has_size(pa)) { + if (first + pa->size - 1ULL > last) + return -ERANGE; + last = first + pa->size - 1ULL; + } else { + snprintf(mesg, sizeof(mesg), + _("Last %s or +%s or +size{K,M,G,T,P}"), + fdisk_get_unit(cxt, FDISK_SINGULAR), + fdisk_get_unit(cxt, FDISK_PLURAL)); + + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1);/* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + + if (fdisk_use_cylinders(cxt)) + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_get_units_per_sector(cxt)); + else + fdisk_ask_number_set_unit(ask,cxt->sector_size); + + rc = fdisk_do_ask(cxt, ask); + last = fdisk_ask_number_get_result(ask) + 1; + + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) + last *= fdisk_get_units_per_sector(cxt); + } + + if (sys == SGI_TYPE_ENTIRE_DISK + && (first != 0 || last != sgi_get_lastblock(cxt))) + fdisk_info(cxt, _("It is highly recommended that the " + "eleventh partition covers the entire " + "disk and is of type 'SGI volume'.")); + + set_partition(cxt, n, first, last - first, sys); + cxt->label->nparts_cur = count_used_partitions(cxt); + if (partno) + *partno = n; + return 0; +} + +static int sgi_create_disklabel(struct fdisk_context *cxt) +{ + struct fdisk_sgi_label *sgi; + struct sgi_disklabel *sgilabel; + int rc; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + +#ifdef HDIO_GETGEO + if (cxt->geom.heads && cxt->geom.sectors) { + fdisk_sector_t llsectors; + + if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) { + /* the get device size ioctl was successful */ + fdisk_sector_t llcyls; + int sec_fac = cxt->sector_size / 512; + + llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac); + cxt->geom.cylinders = llcyls; + if (cxt->geom.cylinders != llcyls) /* truncated? */ + cxt->geom.cylinders = ~0; + } else { + /* otherwise print error and use truncated version */ + fdisk_warnx(cxt, + _("BLKGETSIZE ioctl failed on %s. " + "Using geometry cylinder value of %llu. " + "This value may be truncated for devices " + "> 33.8 GB."), cxt->dev_path, cxt->geom.cylinders); + } + } +#endif + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + + sgi = (struct fdisk_sgi_label *) cxt->label; + sgi->header = (struct sgi_disklabel *) cxt->firstsector; + + sgilabel = sgi->header; + + sgilabel->magic = cpu_to_be32(SGI_LABEL_MAGIC); + sgilabel->root_part_num = cpu_to_be16(0); + sgilabel->swap_part_num = cpu_to_be16(1); + + /* sizeof(sgilabel->boot_file) = 16 > 6 */ + memset(sgilabel->boot_file, 0, 16); + strcpy((char *) sgilabel->boot_file, "/unix"); + + sgilabel->devparam.skew = (0); + sgilabel->devparam.gap1 = (0); + sgilabel->devparam.gap2 = (0); + sgilabel->devparam.sparecyl = (0); + sgilabel->devparam.pcylcount = cpu_to_be16(cxt->geom.cylinders); + sgilabel->devparam.head_vol0 = cpu_to_be16(0); + sgilabel->devparam.ntrks = cpu_to_be16(cxt->geom.heads); + /* tracks/cylinder (heads) */ + sgilabel->devparam.cmd_tag_queue_depth = (0); + sgilabel->devparam.unused0 = (0); + sgilabel->devparam.unused1 = cpu_to_be16(0); + sgilabel->devparam.nsect = cpu_to_be16(cxt->geom.sectors); + /* sectors/track */ + sgilabel->devparam.bytes = cpu_to_be16(cxt->sector_size); + sgilabel->devparam.ilfact = cpu_to_be16(1); + sgilabel->devparam.flags = cpu_to_be32( + SGI_DEVPARAM_TRACK_FWD + | SGI_DEVPARAM_IGNORE_ERRORS + | SGI_DEVPARAM_RESEEK); + sgilabel->devparam.datarate = cpu_to_be32(0); + sgilabel->devparam.retries_on_error = cpu_to_be32(1); + sgilabel->devparam.ms_per_word = cpu_to_be32(0); + sgilabel->devparam.xylogics_gap1 = cpu_to_be16(0); + sgilabel->devparam.xylogics_syncdelay = cpu_to_be16(0); + sgilabel->devparam.xylogics_readdelay = cpu_to_be16(0); + sgilabel->devparam.xylogics_gap2 = cpu_to_be16(0); + sgilabel->devparam.xylogics_readgate = cpu_to_be16(0); + sgilabel->devparam.xylogics_writecont = cpu_to_be16(0); + + memset(&(sgilabel->volume), 0, + sizeof(struct sgi_volume) * SGI_MAXVOLUMES); + memset(&(sgilabel->partitions), 0, + sizeof(struct sgi_partition) * SGI_MAXPARTITIONS); + cxt->label->nparts_max = SGI_MAXPARTITIONS; + + /* don't create default layout when a script defined */ + if (!cxt->script) { + sgi_set_entire(cxt); + sgi_set_volhdr(cxt); + } + cxt->label->nparts_cur = count_used_partitions(cxt); + + fdisk_info(cxt, _("Created a new SGI disklabel.")); + return 0; +} + +static int sgi_set_partition(struct fdisk_context *cxt, + size_t i, + struct fdisk_partition *pa) +{ + struct sgi_disklabel *sgilabel; + + if (i >= cxt->label->nparts_max) + return -EINVAL; + + sgilabel = self_disklabel(cxt); + + if (pa->type) { + struct fdisk_parttype *t = pa->type; + + if (t->code > UINT32_MAX) + return -EINVAL; + + if (sgi_get_num_sectors(cxt, i) == 0) /* caught already before, ... */ { + fdisk_warnx(cxt, _("Sorry, only for non-empty partitions you can change the tag.")); + return -EINVAL; + } + + if ((i == 10 && t->code != SGI_TYPE_ENTIRE_DISK) + || (i == 8 && t->code != 0)) + fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), " + "and partition 11 as entire volume (6), " + "as IRIX expects it.")); + + if (cxt->script == NULL + && ((t->code != SGI_TYPE_ENTIRE_DISK) && (t->code != SGI_TYPE_VOLHDR)) + && (sgi_get_start_sector(cxt, i) < 1)) { + int yes = 0; + fdisk_ask_yesno(cxt, + _("It is highly recommended that the partition at offset 0 " + "is of type \"SGI volhdr\", the IRIX system will rely on it to " + "retrieve from its directory standalone tools like sash and fx. " + "Only the \"SGI volume\" entire disk section may violate this. " + "Are you sure about tagging this partition differently?"), &yes); + if (!yes) + return 1; + } + + sgilabel->partitions[i].type = cpu_to_be32(t->code); + } + + if (fdisk_partition_has_start(pa)) + sgilabel->partitions[i].first_block = cpu_to_be32(pa->start); + if (fdisk_partition_has_size(pa)) + sgilabel->partitions[i].num_blocks = cpu_to_be32(pa->size); + + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + + +static int sgi_partition_is_used( + struct fdisk_context *cxt, + size_t i) +{ + assert(cxt); + assert(fdisk_is_label(cxt, SGI)); + + if (i >= cxt->label->nparts_max) + return 0; + return sgi_get_num_sectors(cxt, i) ? 1 : 0; +} + +static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag) +{ + struct sgi_disklabel *sgilabel; + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SGI)); + + if (i >= cxt->label->nparts_max) + return -EINVAL; + + sgilabel = self_disklabel(cxt); + + switch (flag) { + case SGI_FLAG_BOOT: + sgilabel->root_part_num = + be16_to_cpu(sgilabel->root_part_num) == i ? + 0 : cpu_to_be16(i); + fdisk_label_set_changed(cxt->label, 1); + break; + case SGI_FLAG_SWAP: + sgilabel->swap_part_num = + be16_to_cpu(sgilabel->swap_part_num) == i ? + 0 : cpu_to_be16(i); + fdisk_label_set_changed(cxt->label, 1); + break; + default: + return 1; + } + + return 0; +} + +static const struct fdisk_field sgi_fields[] = +{ + { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 }, + { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER | FDISK_FIELDFL_EYECANDY }, + { FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_TYPE, N_("Type"), 0.1, FDISK_FIELDFL_EYECANDY }, + { FDISK_FIELD_ATTR, N_("Attrs"), 0, FDISK_FIELDFL_NUMBER } +}; + +static const struct fdisk_label_operations sgi_operations = +{ + .probe = sgi_probe_label, + .write = sgi_write_disklabel, + .verify = sgi_verify_disklabel, + .create = sgi_create_disklabel, + .list = sgi_list_table, + + .get_part = sgi_get_partition, + .set_part = sgi_set_partition, + .add_part = sgi_add_partition, + .del_part = sgi_delete_partition, + + .part_is_used = sgi_partition_is_used, + .part_toggle_flag = sgi_toggle_partition_flag +}; + +/* Allocates an SGI label driver. */ +struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + struct fdisk_sgi_label *sgi; + + assert(cxt); + + sgi = calloc(1, sizeof(*sgi)); + if (!sgi) + return NULL; + + /* initialize generic part of the driver */ + lb = (struct fdisk_label *) sgi; + lb->name = "sgi"; + lb->id = FDISK_DISKLABEL_SGI; + lb->op = &sgi_operations; + lb->parttypes = sgi_parttypes; + lb->nparttypes = ARRAY_SIZE(sgi_parttypes) - 1; + lb->fields = sgi_fields; + lb->nfields = ARRAY_SIZE(sgi_fields); + + lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY; + + return lb; +} diff --git a/libblkid/libfdisk/src/sun.c b/libblkid/libfdisk/src/sun.c new file mode 100644 index 000000000..babff6263 --- /dev/null +++ b/libblkid/libfdisk/src/sun.c @@ -0,0 +1,1130 @@ +/* + * Copyright (C) 2013 Karel Zak <kzak@redhat.com> + * + * Based on original code from fdisk: + * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996 + * Merged with fdisk for other architectures, aeb, June 1998. + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> Mar 1999, Internationalization + */ +#include <stdio.h> /* stderr */ +#include <stdlib.h> /* qsort */ +#include <string.h> /* strstr */ +#include <unistd.h> /* write */ +#include <sys/ioctl.h> /* ioctl */ + +#include "nls.h" +#include "blkdev.h" +#include "bitops.h" + +#include "fdiskP.h" +#include "pt-sun.h" +#include "all-io.h" + + +/** + * SECTION: sun + * @title: SUN + * @short_description: disk label specific functions + * + */ + +/* + * in-memory fdisk SUN stuff + */ +struct fdisk_sun_label { + struct fdisk_label head; /* generic part */ + struct sun_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */ +}; + +static struct fdisk_parttype sun_parttypes[] = { + {SUN_TAG_UNASSIGNED, N_("Unassigned")}, + {SUN_TAG_BOOT, N_("Boot")}, + {SUN_TAG_ROOT, N_("SunOS root")}, + {SUN_TAG_SWAP, N_("SunOS swap")}, + {SUN_TAG_USR, N_("SunOS usr")}, + {SUN_TAG_WHOLEDISK, N_("Whole disk")}, + {SUN_TAG_STAND, N_("SunOS stand")}, + {SUN_TAG_VAR, N_("SunOS var")}, + {SUN_TAG_HOME, N_("SunOS home")}, + {SUN_TAG_ALTSCTR, N_("SunOS alt sectors")}, + {SUN_TAG_CACHE, N_("SunOS cachefs")}, + {SUN_TAG_RESERVED, N_("SunOS reserved")}, + {SUN_TAG_LINUX_SWAP, N_("Linux swap")}, + {SUN_TAG_LINUX_NATIVE, N_("Linux native")}, + {SUN_TAG_LINUX_LVM, N_("Linux LVM")}, + {SUN_TAG_LINUX_RAID, N_("Linux raid autodetect")}, + { 0, NULL } +}; + +/* return poiter buffer with on-disk data */ +static inline struct sun_disklabel *self_disklabel(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + return ((struct fdisk_sun_label *) cxt->label)->header; +} + +/* return in-memory sun fdisk data */ +static inline struct fdisk_sun_label *self_label(struct fdisk_context *cxt) +{ + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + return (struct fdisk_sun_label *) cxt->label; +} + +static void set_partition(struct fdisk_context *cxt, size_t i, + uint32_t start,uint32_t stop, uint16_t sysid) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + struct fdisk_parttype *t = + fdisk_label_get_parttype_from_code(cxt->label, sysid); + + sunlabel->vtoc.infos[i].id = cpu_to_be16(sysid); + sunlabel->vtoc.infos[i].flags = cpu_to_be16(0); + sunlabel->partitions[i].start_cylinder = + cpu_to_be32(start / (cxt->geom.heads * cxt->geom.sectors)); + sunlabel->partitions[i].num_sectors = cpu_to_be32(stop - start); + fdisk_label_set_changed(cxt->label, 1); + + fdisk_info_new_partition(cxt, i + 1, start, stop, t); +} + +static size_t count_used_partitions(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + size_t ct = 0, i; + + assert(sunlabel); + + for (i = 0; i < cxt->label->nparts_max; i++) { + if (sunlabel->partitions[i].num_sectors) + ct++; + } + return ct; +} + +static int sun_probe_label(struct fdisk_context *cxt) +{ + struct fdisk_sun_label *sun; + struct sun_disklabel *sunlabel; + unsigned short *ush; + int csum; + int need_fixing = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + /* map first sector to header */ + sun = (struct fdisk_sun_label *) cxt->label; + sun->header = (struct sun_disklabel *) cxt->firstsector; + sunlabel = sun->header; + + if (be16_to_cpu(sunlabel->magic) != SUN_LABEL_MAGIC) { + sun->header = NULL; + return 0; /* failed */ + } + + ush = ((unsigned short *) (sunlabel + 1)) - 1; + for (csum = 0; ush >= (unsigned short *)sunlabel;) + csum ^= *ush--; + + if (csum) { + fdisk_warnx(cxt, _("Detected sun disklabel with wrong checksum. " + "Probably you'll have to set all the values, " + "e.g. heads, sectors, cylinders and partitions " + "or force a fresh label (s command in main menu)")); + return 1; + } + + cxt->label->nparts_max = SUN_MAXPARTITIONS; + cxt->geom.heads = be16_to_cpu(sunlabel->nhead); + cxt->geom.cylinders = be16_to_cpu(sunlabel->ncyl); + cxt->geom.sectors = be16_to_cpu(sunlabel->nsect); + + if (be32_to_cpu(sunlabel->vtoc.version) != SUN_VTOC_VERSION) { + fdisk_warnx(cxt, _("Detected sun disklabel with wrong version [%d]."), + be32_to_cpu(sunlabel->vtoc.version)); + need_fixing = 1; + } + if (be32_to_cpu(sunlabel->vtoc.sanity) != SUN_VTOC_SANITY) { + fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."), + be32_to_cpu(sunlabel->vtoc.sanity)); + need_fixing = 1; + } + if (be16_to_cpu(sunlabel->vtoc.nparts) != SUN_MAXPARTITIONS) { + fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.nparts [%u]."), + be16_to_cpu(sunlabel->vtoc.nparts)); + need_fixing = 1; + } + if (need_fixing) { + fdisk_warnx(cxt, _("Warning: Wrong values need to be fixed up and " + "will be corrected by w(rite)")); + + sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION); + sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY); + sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS); + + ush = (unsigned short *)sunlabel; + csum = 0; + while(ush < (unsigned short *)(&sunlabel->csum)) + csum ^= *ush++; + sunlabel->csum = csum; + + fdisk_label_set_changed(cxt->label, 1); + } + + cxt->label->nparts_cur = count_used_partitions(cxt); + + return 1; +} + +static void ask_geom(struct fdisk_context *cxt) +{ + uintmax_t res; + + assert(cxt); + + if (fdisk_ask_number(cxt, 1, 1, 1024, _("Heads"), &res) == 0) + cxt->geom.heads = res; + if (fdisk_ask_number(cxt, 1, 1, 1024, _("Sectors/track"), &res) == 0) + cxt->geom.sectors = res; + if (fdisk_ask_number(cxt, 1, 1, USHRT_MAX, _("Cylinders"), &res) == 0) + cxt->geom.cylinders = res; +} + +static int sun_create_disklabel(struct fdisk_context *cxt) +{ + unsigned int ndiv; + struct fdisk_sun_label *sun; /* libfdisk sun handler */ + struct sun_disklabel *sunlabel; /* on disk data */ + int rc = 0; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + /* map first sector to header */ + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + + sun = (struct fdisk_sun_label *) cxt->label; + sun->header = (struct sun_disklabel *) cxt->firstsector; + + sunlabel = sun->header; + + cxt->label->nparts_max = SUN_MAXPARTITIONS; + + sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC); + sunlabel->vtoc.version = cpu_to_be32(SUN_VTOC_VERSION); + sunlabel->vtoc.sanity = cpu_to_be32(SUN_VTOC_SANITY); + sunlabel->vtoc.nparts = cpu_to_be16(SUN_MAXPARTITIONS); + +#ifdef HDIO_GETGEO + if (cxt->geom.heads && cxt->geom.sectors) { + fdisk_sector_t llsectors; + + if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) { + int sec_fac = cxt->sector_size / 512; + fdisk_sector_t llcyls; + + llcyls = llsectors / (cxt->geom.heads * cxt->geom.sectors * sec_fac); + cxt->geom.cylinders = llcyls; + if (cxt->geom.cylinders != llcyls) + cxt->geom.cylinders = ~0; + } else { + fdisk_warnx(cxt, + _("BLKGETSIZE ioctl failed on %s. " + "Using geometry cylinder value of %llu. " + "This value may be truncated for devices " + "> 33.8 GB."), + cxt->dev_path, cxt->geom.cylinders); + } + } else +#endif + ask_geom(cxt); + + sunlabel->acyl = cpu_to_be16(0); + sunlabel->pcyl = cpu_to_be16(cxt->geom.cylinders); + sunlabel->rpm = cpu_to_be16(5400); + sunlabel->intrlv = cpu_to_be16(1); + sunlabel->apc = cpu_to_be16(0); + + sunlabel->nhead = cpu_to_be16(cxt->geom.heads); + sunlabel->nsect = cpu_to_be16(cxt->geom.sectors); + sunlabel->ncyl = cpu_to_be16(cxt->geom.cylinders); + + snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id), + "Linux cyl %ju alt %u hd %u sec %ju", + (uintmax_t) cxt->geom.cylinders, + be16_to_cpu(sunlabel->acyl), + cxt->geom.heads, + (uintmax_t) cxt->geom.sectors); + + if (cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors >= 150 * 2048) { + ndiv = cxt->geom.cylinders - (50 * 2048 / (cxt->geom.heads * cxt->geom.sectors)); /* 50M swap */ + } else + ndiv = cxt->geom.cylinders * 2 / 3; + + /* create the default layout only if no-script defined */ + if (!cxt->script) { + set_partition(cxt, 0, 0, ndiv * cxt->geom.heads * cxt->geom.sectors, + SUN_TAG_LINUX_NATIVE); + set_partition(cxt, 1, ndiv * cxt->geom.heads * cxt->geom.sectors, + cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors, + SUN_TAG_LINUX_SWAP); + sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT); + + set_partition(cxt, 2, 0, + cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors, + SUN_TAG_WHOLEDISK); + } + + { + unsigned short *ush = (unsigned short *)sunlabel; + unsigned short csum = 0; + while(ush < (unsigned short *)(&sunlabel->csum)) + csum ^= *ush++; + sunlabel->csum = csum; + } + + fdisk_label_set_changed(cxt->label, 1); + cxt->label->nparts_cur = count_used_partitions(cxt); + + fdisk_info(cxt, _("Created a new Sun disklabel.")); + return 0; +} + +static int sun_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag) +{ + struct sun_disklabel *sunlabel; + struct sun_info *p; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + if (i >= cxt->label->nparts_max) + return -EINVAL; + + sunlabel = self_disklabel(cxt); + p = &sunlabel->vtoc.infos[i]; + + switch (flag) { + case SUN_FLAG_UNMNT: + p->flags ^= cpu_to_be16(SUN_FLAG_UNMNT); + fdisk_label_set_changed(cxt->label, 1); + break; + case SUN_FLAG_RONLY: + p->flags ^= cpu_to_be16(SUN_FLAG_RONLY); + fdisk_label_set_changed(cxt->label, 1); + break; + default: + return 1; + } + + return 0; +} + +static void fetch_sun(struct fdisk_context *cxt, + uint32_t *starts, + uint32_t *lens, + uint32_t *start, + uint32_t *stop) +{ + struct sun_disklabel *sunlabel; + int continuous = 1; + size_t i; + + assert(cxt); + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + sunlabel = self_disklabel(cxt); + + *start = 0; + *stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; + + for (i = 0; i < cxt->label->nparts_max; i++) { + struct sun_partition *part = &sunlabel->partitions[i]; + struct sun_info *info = &sunlabel->vtoc.infos[i]; + + if (part->num_sectors && + be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED && + be16_to_cpu(info->id) != SUN_TAG_WHOLEDISK) { + starts[i] = be32_to_cpu(part->start_cylinder) * + cxt->geom.heads * cxt->geom.sectors; + lens[i] = be32_to_cpu(part->num_sectors); + if (continuous) { + if (starts[i] == *start) + *start += lens[i]; + else if (starts[i] + lens[i] >= *stop) + *stop = starts[i]; + else + continuous = 0; + /* There will be probably more gaps + than one, so lets check afterwards */ + } + } else { + starts[i] = 0; + lens[i] = 0; + } + } +} + +#ifdef HAVE_QSORT_R +static int verify_sun_cmp(int *a, int *b, void *data) +{ + unsigned int *verify_sun_starts = (unsigned int *) data; + + if (*a == -1) + return 1; + if (*b == -1) + return -1; + if (verify_sun_starts[*a] > verify_sun_starts[*b]) + return 1; + return -1; +} +#endif + +static int sun_verify_disklabel(struct fdisk_context *cxt) +{ + uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS], start, stop; + uint32_t i,j,k,starto,endo; +#ifdef HAVE_QSORT_R + int array[SUN_MAXPARTITIONS]; + unsigned int *verify_sun_starts; +#endif + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + fetch_sun(cxt, starts, lens, &start, &stop); + + for (k = 0; k < 7; k++) { + for (i = 0; i < SUN_MAXPARTITIONS; i++) { + if (k && (lens[i] % (cxt->geom.heads * cxt->geom.sectors))) + fdisk_warnx(cxt, _("Partition %u doesn't end on cylinder boundary."), i+1); + if (lens[i]) { + for (j = 0; j < i; j++) + if (lens[j]) { + if (starts[j] == starts[i]+lens[i]) { + starts[j] = starts[i]; lens[j] += lens[i]; + lens[i] = 0; + } else if (starts[i] == starts[j]+lens[j]){ + lens[j] += lens[i]; + lens[i] = 0; + } else if (!k) { + if (starts[i] < starts[j]+lens[j] && + starts[j] < starts[i]+lens[i]) { + starto = starts[i]; + if (starts[j] > starto) + starto = starts[j]; + endo = starts[i]+lens[i]; + if (starts[j]+lens[j] < endo) + endo = starts[j]+lens[j]; + fdisk_warnx(cxt, _("Partition %u overlaps with others in " + "sectors %u-%u."), i+1, starto, endo); + } + } + } + } + } + } + +#ifdef HAVE_QSORT_R + for (i = 0; i < SUN_MAXPARTITIONS; i++) { + if (lens[i]) + array[i] = i; + else + array[i] = -1; + } + verify_sun_starts = starts; + + qsort_r(array,ARRAY_SIZE(array),sizeof(array[0]), + (int (*)(const void *,const void *,void *)) verify_sun_cmp, + verify_sun_starts); + + if (array[0] == -1) { + fdisk_info(cxt, _("No partitions defined.")); + return 0; + } + stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; + if (starts[array[0]]) + fdisk_warnx(cxt, _("Unused gap - sectors 0-%u."), starts[array[0]]); + for (i = 0; i < 7 && array[i+1] != -1; i++) { + fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."), + (starts[array[i]] + lens[array[i]]), + starts[array[i+1]]); + } + start = (starts[array[i]] + lens[array[i]]); + if (start < stop) + fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."), start, stop); +#endif + return 0; +} + + +static int is_free_sector(struct fdisk_context *cxt, + fdisk_sector_t s, uint32_t starts[], uint32_t lens[]) +{ + size_t i; + + for (i = 0; i < cxt->label->nparts_max; i++) { + if (lens[i] && starts[i] <= s + && starts[i] + lens[i] > s) + return 0; + } + return 1; +} + +static int sun_add_partition( + struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *partno) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS]; + struct sun_partition *part; + struct sun_info *info; + uint32_t start, stop, stop2; + int whole_disk = 0; + int sys = pa && pa->type ? pa->type->code : SUN_TAG_LINUX_NATIVE; + int rc; + size_t n; + + char mesg[256]; + size_t i; + unsigned int first, last; + + rc = fdisk_partition_next_partno(pa, cxt, &n); + if (rc) + return rc; + + part = &sunlabel->partitions[n]; + info = &sunlabel->vtoc.infos[n]; + + if (part->num_sectors && be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED) { + fdisk_info(cxt, _("Partition %zu is already defined. Delete " + "it before re-adding it."), n + 1); + return -EINVAL; + } + + fetch_sun(cxt, starts, lens, &start, &stop); + + if (stop <= start) { + if (n == 2) + whole_disk = 1; + else { + fdisk_info(cxt, _("Other partitions already cover the " + "whole disk. Delete some/shrink them before retry.")); + return -EINVAL; + } + } + + if (pa && pa->start_follow_default) + first = start; + else if (pa && fdisk_partition_has_start(pa)) { + first = pa->start; + + if (!whole_disk && !is_free_sector(cxt, first, starts, lens)) + return -ERANGE; + } else { + struct fdisk_ask *ask; + + snprintf(mesg, sizeof(mesg), _("First %s"), + fdisk_get_unit(cxt, FDISK_SINGULAR)); + for (;;) { + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + + if (whole_disk) { + fdisk_ask_number_set_low(ask, 0); /* minimal */ + fdisk_ask_number_set_default(ask, 0); /* default */ + fdisk_ask_number_set_high(ask, 0); /* maximal */ + } else { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, start)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, start)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ + } + rc = fdisk_do_ask(cxt, ask); + first = fdisk_ask_number_get_result(ask); + fdisk_unref_ask(ask); + if (rc) + return rc; + + if (fdisk_use_cylinders(cxt)) + first *= fdisk_get_units_per_sector(cxt); + + /* ewt asks to add: "don't start a partition at cyl 0" + However, edmundo@rano.demon.co.uk writes: + "In addition to having a Sun partition table, to be able to + boot from the disc, the first partition, /dev/sdX1, must + start at cylinder 0. This means that /dev/sdX1 contains + the partition table and the boot block, as these are the + first two sectors of the disc. Therefore you must be + careful what you use /dev/sdX1 for. In particular, you must + not use a partition starting at cylinder 0 for Linux swap, + as that would overwrite the partition table and the boot + block. You may, however, use such a partition for a UFS + or EXT2 file system, as these file systems leave the first + 1024 bytes undisturbed. */ + /* On the other hand, one should not use partitions + starting at block 0 in an md, or the label will + be trashed. */ + if (!is_free_sector(cxt, first, starts, lens) && !whole_disk) { + if (n == 2 && !first) { + whole_disk = 1; + break; + } + fdisk_warnx(cxt, _("Sector %d is already allocated"), first); + } else + break; + } + } + + if (n == 2 && first != 0) + fdisk_warnx(cxt, _("It is highly recommended that the " + "third partition covers the whole disk " + "and is of type `Whole disk'")); + + if (!fdisk_use_cylinders(cxt)) { + /* Starting sector has to be properly aligned */ + int cs = cxt->geom.heads * cxt->geom.sectors; + int x = first % cs; + + if (x) { + fdisk_info(cxt, _("Aligning the first sector from %u to %u " + "to be on cylinder boundary."), + first, first + cs - x); + first += cs - x; + } + } + + stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; /* ancient */ + stop2 = stop; + for (i = 0; i < cxt->label->nparts_max; i++) { + if (starts[i] > first && starts[i] < stop) + stop = starts[i]; + } + + /* last */ + if (pa && pa->end_follow_default) + last = whole_disk || (n == 2 && !first) ? stop2 : stop; + else if (pa && fdisk_partition_has_size(pa)) { + last = first + pa->size - 1ULL; + + if (!whole_disk && last > stop) + return -ERANGE; + } else { + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + + snprintf(mesg, sizeof(mesg), + _("Last %s or +%s or +size{K,M,G,T,P}"), + fdisk_get_unit(cxt, FDISK_SINGULAR), + fdisk_get_unit(cxt, FDISK_PLURAL)); + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + + if (whole_disk) { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, stop2)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ + fdisk_ask_number_set_base(ask, 0); + } else if (n == 2 && !first) { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + } else { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + } + + if (fdisk_use_cylinders(cxt)) + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_get_units_per_sector(cxt)); + else + fdisk_ask_number_set_unit(ask, cxt->sector_size); + + rc = fdisk_do_ask(cxt, ask); + last = fdisk_ask_number_get_result(ask); + + fdisk_unref_ask(ask); + if (rc) + return rc; + if (fdisk_use_cylinders(cxt)) + last *= fdisk_get_units_per_sector(cxt); + } + + if (n == 2 && !first) { + if (last >= stop2) { + whole_disk = 1; + last = stop2; + } else if (last > stop) { + fdisk_warnx(cxt, + _("You haven't covered the whole disk with the 3rd partition, but your value\n" + "%lu %s covers some other partition. Your entry has been changed\n" + "to %lu %s"), + (unsigned long) fdisk_scround(cxt, last), fdisk_get_unit(cxt, FDISK_SINGULAR), + (unsigned long) fdisk_scround(cxt, stop), fdisk_get_unit(cxt, FDISK_SINGULAR)); + last = stop; + } + } else if (!whole_disk && last > stop) + last = stop; + + if (whole_disk) + sys = SUN_TAG_WHOLEDISK; + + set_partition(cxt, n, first, last, sys); + cxt->label->nparts_cur = count_used_partitions(cxt); + if (partno) + *partno = n; + return 0; +} + +static int sun_delete_partition(struct fdisk_context *cxt, + size_t partnum) +{ + struct sun_disklabel *sunlabel; + struct sun_partition *part; + struct sun_info *info; + unsigned int nsec; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + sunlabel = self_disklabel(cxt); + part = &sunlabel->partitions[partnum]; + info = &sunlabel->vtoc.infos[partnum]; + + if (partnum == 2 && + be16_to_cpu(info->id) == SUN_TAG_WHOLEDISK && + !part->start_cylinder && + (nsec = be32_to_cpu(part->num_sectors)) + == cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders) + fdisk_info(cxt, _("If you want to maintain SunOS/Solaris compatibility, " + "consider leaving this " + "partition as Whole disk (5), starting at 0, with %u " + "sectors"), nsec); + info->id = cpu_to_be16(SUN_TAG_UNASSIGNED); + part->num_sectors = 0; + cxt->label->nparts_cur = count_used_partitions(cxt); + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + + +static int sun_list_disklabel(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + sunlabel = self_disklabel(cxt); + + if (fdisk_is_details(cxt)) { + fdisk_info(cxt, + _("Label geometry: %d rpm, %d alternate and %d physical cylinders,\n" + " %d extra sects/cyl, interleave %d:1"), + be16_to_cpu(sunlabel->rpm), + be16_to_cpu(sunlabel->acyl), + be16_to_cpu(sunlabel->pcyl), + be16_to_cpu(sunlabel->apc), + be16_to_cpu(sunlabel->intrlv)); + fdisk_info(cxt, _("Label ID: %s"), sunlabel->label_id); + fdisk_info(cxt, _("Volume ID: %s"), + *sunlabel->vtoc.volume_id ? sunlabel->vtoc.volume_id : _("<none>")); + } + + return 0; +} + +static struct fdisk_parttype *sun_get_parttype( + struct fdisk_context *cxt, + size_t n) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + struct fdisk_parttype *t; + + if (n >= cxt->label->nparts_max) + return NULL; + + t = fdisk_label_get_parttype_from_code(cxt->label, + be16_to_cpu(sunlabel->vtoc.infos[n].id)); + return t ? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel->vtoc.infos[n].id), NULL); +} + + +static int sun_get_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + struct sun_disklabel *sunlabel; + struct sun_partition *part; + uint16_t flags; + uint32_t start, len; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + if (n >= cxt->label->nparts_max) + return -EINVAL; + + sunlabel = self_disklabel(cxt); + part = &sunlabel->partitions[n]; + + pa->used = part->num_sectors ? 1 : 0; + if (!pa->used) + return 0; + + flags = be16_to_cpu(sunlabel->vtoc.infos[n].flags); + start = be32_to_cpu(part->start_cylinder) + * cxt->geom.heads * cxt->geom.sectors; + len = be32_to_cpu(part->num_sectors); + + pa->type = sun_get_parttype(cxt, n); + if (pa->type && pa->type->code == SUN_TAG_WHOLEDISK) + pa->wholedisk = 1; + + if (flags & SUN_FLAG_UNMNT || flags & SUN_FLAG_RONLY) { + if (asprintf(&pa->attrs, "%c%c", + flags & SUN_FLAG_UNMNT ? 'u' : ' ', + flags & SUN_FLAG_RONLY ? 'r' : ' ') < 0) + return -ENOMEM; + } + + pa->start = start; + pa->size = len; + + return 0; +} + +/** + * fdisk_sun_set_alt_cyl: + * @cxt: context + * + * Sets number of alternative cylinders. This function uses libfdisk Ask API + * for dialog with user. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uintmax_t res; + int rc = fdisk_ask_number(cxt, 0, /* low */ + be16_to_cpu(sunlabel->acyl), /* default */ + 65535, /* high */ + _("Number of alternate cylinders"), /* query */ + &res); /* result */ + if (rc) + return rc; + + sunlabel->acyl = cpu_to_be16(res); + return 0; +} + +/** + * fdisk_sun_set_xcyl: + * @cxt: context + * + * Sets number of extra sectors per cylinder. This function uses libfdisk Ask API + * for dialog with user. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_sun_set_xcyl(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uintmax_t res; + int rc = fdisk_ask_number(cxt, 0, /* low */ + be16_to_cpu(sunlabel->apc), /* default */ + cxt->geom.sectors, /* high */ + _("Extra sectors per cylinder"), /* query */ + &res); /* result */ + if (rc) + return rc; + sunlabel->apc = cpu_to_be16(res); + return 0; +} + +/** + * fdisk_sun_set_ilfact: + * @cxt: context + * + * Sets interleave factor. This function uses libfdisk Ask API for dialog with + * user. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_sun_set_ilfact(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uintmax_t res; + int rc = fdisk_ask_number(cxt, 1, /* low */ + be16_to_cpu(sunlabel->intrlv), /* default */ + 32, /* high */ + _("Interleave factor"), /* query */ + &res); /* result */ + if (rc) + return rc; + sunlabel->intrlv = cpu_to_be16(res); + return 0; +} + +/** + * fdisk_sun_set_rspeed + * @cxt: context + * + * Sets rotation speed. This function uses libfdisk Ask API for dialog with + * user. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_sun_set_rspeed(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uintmax_t res; + int rc = fdisk_ask_number(cxt, 1, /* low */ + be16_to_cpu(sunlabel->rpm), /* default */ + USHRT_MAX, /* high */ + _("Rotation speed (rpm)"), /* query */ + &res); /* result */ + if (rc) + return rc; + sunlabel->rpm = cpu_to_be16(res); + return 0; +} + +/** + * fdisk_sun_set_pcylcount + * @cxt: context + * + * Sets number of physical cylinders. This function uses libfdisk Ask API for + * dialog with user. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_sun_set_pcylcount(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel = self_disklabel(cxt); + uintmax_t res; + int rc = fdisk_ask_number(cxt, 0, /* low */ + be16_to_cpu(sunlabel->pcyl), /* default */ + USHRT_MAX, /* high */ + _("Number of physical cylinders"), /* query */ + &res); /* result */ + if (!rc) + return rc; + sunlabel->pcyl = cpu_to_be16(res); + return 0; +} + +static int sun_write_disklabel(struct fdisk_context *cxt) +{ + struct sun_disklabel *sunlabel; + unsigned short *ush; + unsigned short csum = 0; + const size_t sz = sizeof(struct sun_disklabel); + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + sunlabel = self_disklabel(cxt); + + /* Maybe geometry has been modified */ + sunlabel->nhead = cpu_to_be16(cxt->geom.heads); + sunlabel->nsect = cpu_to_be16(cxt->geom.sectors); + + if (cxt->geom.cylinders != be16_to_cpu(sunlabel->ncyl)) + sunlabel->ncyl = cpu_to_be16( cxt->geom.cylinders + - be16_to_cpu(sunlabel->acyl) ); + + ush = (unsigned short *) sunlabel; + + while(ush < (unsigned short *)(&sunlabel->csum)) + csum ^= *ush++; + sunlabel->csum = csum; + if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0) + return -errno; + if (write_all(cxt->dev_fd, sunlabel, sz) != 0) + return -errno; + + return 0; +} + +static int sun_set_partition( + struct fdisk_context *cxt, + size_t i, + struct fdisk_partition *pa) +{ + struct sun_disklabel *sunlabel; + struct sun_partition *part; + struct sun_info *info; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + sunlabel = self_disklabel(cxt); + + if (i >= cxt->label->nparts_max) + return -EINVAL; + + if (pa->type) { + struct fdisk_parttype *t = pa->type; + + if (t->code > UINT16_MAX) + return -EINVAL; + + if (i == 2 && t->code != SUN_TAG_WHOLEDISK) + fdisk_info(cxt, _("Consider leaving partition 3 as Whole disk (5),\n" + "as SunOS/Solaris expects it and even Linux likes it.\n")); + + part = &sunlabel->partitions[i]; + info = &sunlabel->vtoc.infos[i]; + + if (cxt->script == NULL && + t->code == SUN_TAG_LINUX_SWAP && !part->start_cylinder) { + int yes, rc; + + rc = fdisk_ask_yesno(cxt, + _("It is highly recommended that the partition at offset 0\n" + "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n" + "there may destroy your partition table and bootblock.\n" + "Are you sure you want to tag the partition as Linux swap?"), &yes); + if (rc) + return rc; + if (!yes) + return 1; + } + + switch (t->code) { + case SUN_TAG_SWAP: + case SUN_TAG_LINUX_SWAP: + /* swaps are not mountable by default */ + info->flags |= cpu_to_be16(SUN_FLAG_UNMNT); + break; + default: + /* assume other types are mountable; + user can change it anyway */ + info->flags &= ~cpu_to_be16(SUN_FLAG_UNMNT); + break; + } + info->id = cpu_to_be16(t->code); + } + + if (fdisk_partition_has_start(pa)) + sunlabel->partitions[i].start_cylinder = + cpu_to_be32(pa->start / (cxt->geom.heads * cxt->geom.sectors)); + if (fdisk_partition_has_size(pa)) + sunlabel->partitions[i].num_sectors = cpu_to_be32(pa->size); + + fdisk_label_set_changed(cxt->label, 1); + return 0; +} + + +static int sun_reset_alignment(struct fdisk_context *cxt __attribute__((__unused__))) +{ + return 0; +} + + +static int sun_partition_is_used( + struct fdisk_context *cxt, + size_t i) +{ + struct sun_disklabel *sunlabel; + + assert(cxt); + assert(cxt->label); + assert(fdisk_is_label(cxt, SUN)); + + if (i >= cxt->label->nparts_max) + return 0; + + sunlabel = self_disklabel(cxt); + return sunlabel->partitions[i].num_sectors ? 1 : 0; +} + +static const struct fdisk_field sun_fields[] = +{ + { FDISK_FIELD_DEVICE, N_("Device"), 10, 0 }, + { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_TYPEID, N_("Id"), 2, FDISK_FIELDFL_NUMBER }, + { FDISK_FIELD_TYPE, N_("Type"), 0.1, 0 }, + { FDISK_FIELD_ATTR, N_("Flags"), 0, FDISK_FIELDFL_NUMBER } +}; + +const struct fdisk_label_operations sun_operations = +{ + .probe = sun_probe_label, + .write = sun_write_disklabel, + .verify = sun_verify_disklabel, + .create = sun_create_disklabel, + .list = sun_list_disklabel, + + .get_part = sun_get_partition, + .set_part = sun_set_partition, + .add_part = sun_add_partition, + .del_part = sun_delete_partition, + + .part_is_used = sun_partition_is_used, + .part_toggle_flag = sun_toggle_partition_flag, + + .reset_alignment = sun_reset_alignment, +}; + +/* + * allocates SUN label driver + */ +struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt) +{ + struct fdisk_label *lb; + struct fdisk_sun_label *sun; + + assert(cxt); + + sun = calloc(1, sizeof(*sun)); + if (!sun) + return NULL; + + /* initialize generic part of the driver */ + lb = (struct fdisk_label *) sun; + lb->name = "sun"; + lb->id = FDISK_DISKLABEL_SUN; + lb->op = &sun_operations; + lb->parttypes = sun_parttypes; + lb->nparttypes = ARRAY_SIZE(sun_parttypes) - 1; + lb->fields = sun_fields; + lb->nfields = ARRAY_SIZE(sun_fields); + lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY; + + return lb; +} diff --git a/libblkid/libfdisk/src/table.c b/libblkid/libfdisk/src/table.c new file mode 100644 index 000000000..1add09fca --- /dev/null +++ b/libblkid/libfdisk/src/table.c @@ -0,0 +1,664 @@ + +#include "fdiskP.h" + +/** + * SECTION: table + * @title: Table + * @short_description: container for fdisk partitions + * + * The fdisk_table is simple container for fdisk_partitions. The table is no + * directly connected to label data (partition table), and table changes don't + * affect in-memory or on-disk data. + */ + +/** + * fdisk_new_table: + * + * The table is a container for struct fdisk_partition entries. The container + * does not have any real connection with label (partition table) and with + * real on-disk data. + * + * Returns: newly allocated table struct. + */ +struct fdisk_table *fdisk_new_table(void) +{ + struct fdisk_table *tb = NULL; + + tb = calloc(1, sizeof(*tb)); + if (!tb) + return NULL; + + DBG(TAB, ul_debugobj(tb, "alloc")); + tb->refcount = 1; + INIT_LIST_HEAD(&tb->parts); + return tb; +} + +/** + * fdisk_reset_table: + * @tb: tab pointer + * + * Removes all entries (partitions) from the table. The parititons with zero + * reference count will be deallocated. This function does not modify partition + * table. + * + * Returns: 0 on success or negative number in case of error. + */ +int fdisk_reset_table(struct fdisk_table *tb) +{ + if (!tb) + return -EINVAL; + + DBG(TAB, ul_debugobj(tb, "reset")); + + while (!list_empty(&tb->parts)) { + struct fdisk_partition *pa = list_entry(tb->parts.next, + struct fdisk_partition, parts); + fdisk_table_remove_partition(tb, pa); + } + + tb->nents = 0; + return 0; +} + +/** + * fdisk_ref_table: + * @tb: table pointer + * + * Incremparts reference counter. + */ +void fdisk_ref_table(struct fdisk_table *tb) +{ + if (tb) + tb->refcount++; +} + +/** + * fdisk_unref_table: + * @tb: table pointer + * + * De-incremparts reference counter, on zero the @tb is automatically + * deallocated. + */ +void fdisk_unref_table(struct fdisk_table *tb) +{ + if (!tb) + return; + + tb->refcount--; + if (tb->refcount <= 0) { + fdisk_reset_table(tb); + + DBG(TAB, ul_debugobj(tb, "free")); + free(tb); + } +} + +/** + * fdisk_table_is_empty: + * @tb: pointer to tab + * + * Returns: 1 if the table is without filesystems, or 0. + */ +int fdisk_table_is_empty(struct fdisk_table *tb) +{ + return tb == NULL || list_empty(&tb->parts) ? 1 : 0; +} + +/** + * fdisk_table_get_nents: + * @tb: pointer to tab + * + * Returns: number of entries in table. + */ +size_t fdisk_table_get_nents(struct fdisk_table *tb) +{ + return tb ? tb->nents : 0; +} + +/** + * fdisk_table_next_partition: + * @tb: tab pointer + * @itr: iterator + * @pa: returns the next tab entry + * + * Returns: 0 on success, negative number in case of error or 1 at the end of list. + * + * Example: + * <informalexample> + * <programlisting> + * while(fdisk_table_next_partition(tb, itr, &pa) == 0) { + * ... + * } + * </programlisting> + * </informalexample> + */ +int fdisk_table_next_partition( + struct fdisk_table *tb, + struct fdisk_iter *itr, + struct fdisk_partition **pa) +{ + int rc = 1; + + assert(tb); + assert(itr); + assert(pa); + + if (!tb || !itr || !pa) + return -EINVAL; + *pa = NULL; + + if (!itr->head) + FDISK_ITER_INIT(itr, &tb->parts); + if (itr->p != itr->head) { + FDISK_ITER_ITERATE(itr, *pa, struct fdisk_partition, parts); + rc = 0; + } + + return rc; +} + +struct fdisk_partition *fdisk_table_get_partition( + struct fdisk_table *tb, + size_t n) +{ + struct fdisk_partition *pa = NULL; + struct fdisk_iter itr; + + if (!tb) + return NULL; + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + + while (fdisk_table_next_partition(tb, &itr, &pa) == 0) { + if (n == 0) + return pa; + n--; + } + + return NULL; +} + +/** + * fdisk_table_add_partition + * @tb: tab pointer + * @pa: new entry + * + * Adds a new entry to table and increment @pa reference counter. Don't forget to + * use fdisk_unref_pa() after fdisk_table_add_partition() if you want to keep + * the @pa referenced by the table only. + * + * Returns: 0 on success or negative number in case of error. + */ +int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa) +{ + assert(tb); + assert(pa); + + if (!tb || !pa) + return -EINVAL; + + fdisk_ref_partition(pa); + list_add_tail(&pa->parts, &tb->parts); + tb->nents++; + + DBG(TAB, ul_debugobj(tb, "add entry %p [start=%ju, end=%ju, size=%ju, %s %s %s]", + pa, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa), + fdisk_partition_is_freespace(pa) ? "freespace" : "", + fdisk_partition_is_nested(pa) ? "nested" : "", + fdisk_partition_is_container(pa) ? "container" : "primary")); + return 0; +} + +/* inserts @pa after @poz */ +static int table_insert_partition( + struct fdisk_table *tb, + struct fdisk_partition *poz, + struct fdisk_partition *pa) +{ + assert(tb); + assert(pa); + + fdisk_ref_partition(pa); + if (poz) + list_add(&pa->parts, &poz->parts); + else + list_add(&pa->parts, &tb->parts); + tb->nents++; + + DBG(TAB, ul_debugobj(tb, "insert entry %p pre=%p [start=%ju, end=%ju, size=%ju, %s %s %s]", + pa, poz ? poz : NULL, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa), + fdisk_partition_is_freespace(pa) ? "freespace" : "", + fdisk_partition_is_nested(pa) ? "nested" : "", + fdisk_partition_is_container(pa) ? "container" : "")); + return 0; +} + +/** + * fdisk_table_remove_partition + * @tb: tab pointer + * @pa: new entry + * + * Removes the @pa from the table and de-increment reference counter of the @pa. The + * partition with zero reference counter will be deallocated. Don't forget to use + * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want + * to use @pa later. + * + * Returns: 0 on success or negative number in case of error. + */ +int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa) +{ + assert(tb); + assert(pa); + + if (!tb || !pa) + return -EINVAL; + + DBG(TAB, ul_debugobj(tb, "remove entry %p", pa)); + list_del(&pa->parts); + INIT_LIST_HEAD(&pa->parts); + + fdisk_unref_partition(pa); + tb->nents--; + + return 0; +} + +/** + * fdisk_get_partitions + * @cxt: fdisk context + * @tb: returns table + * + * This function adds partitions from disklabel to @table, it allocates a new + * table if if @table points to NULL. + * + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb) +{ + size_t i; + + if (!cxt || !cxt->label || !tb) + return -EINVAL; + if (!cxt->label->op->get_part) + return -ENOSYS; + + DBG(CXT, ul_debugobj(cxt, "get table")); + + if (!*tb && !(*tb = fdisk_new_table())) + return -ENOMEM; + + for (i = 0; i < cxt->label->nparts_max; i++) { + struct fdisk_partition *pa = NULL; + + if (fdisk_get_partition(cxt, i, &pa) != 0) + continue; + if (fdisk_partition_is_used(pa)) + fdisk_table_add_partition(*tb, pa); + fdisk_unref_partition(pa); + } + + return 0; +} + +static void debug_print_table(struct fdisk_table *tb) +{ + struct fdisk_iter itr; + struct fdisk_partition *pa; + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + while (fdisk_table_next_partition(tb, &itr, &pa) == 0) + ul_debugobj(tb, "partition %p [partno=%zu, start=%ju, end=%ju, size=%ju] ", + pa, pa->partno, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa), + (uintmax_t) fdisk_partition_get_size(pa)); + +} + + +typedef int (*fdisk_partcmp_t)(struct fdisk_partition *, struct fdisk_partition *); + +static int cmp_parts_wrapper(struct list_head *a, struct list_head *b, void *data) +{ + struct fdisk_partition *pa = list_entry(a, struct fdisk_partition, parts), + *pb = list_entry(b, struct fdisk_partition, parts); + + fdisk_partcmp_t cmp = (fdisk_partcmp_t) data; + + return cmp(pa, pb); +} + + +/** + * fdisk_table_sort_partitions: + * @tb: table + * @cmp: compare function + * + * Sort partition in the table. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_table_sort_partitions(struct fdisk_table *tb, + int (*cmp)(struct fdisk_partition *, + struct fdisk_partition *)) +{ + if (!tb) + return -EINVAL; + + DBG(TAB, ul_debugobj(tb, "Before sort:")); + ON_DBG(TAB, debug_print_table(tb)); + + list_sort(&tb->parts, cmp_parts_wrapper, (void *) cmp); + + DBG(TAB, ul_debugobj(tb, "After sort:")); + ON_DBG(TAB, debug_print_table(tb)); + + return 0; +} + +/* allocates a new freespace description */ +static int new_freespace(struct fdisk_context *cxt, + fdisk_sector_t start, + fdisk_sector_t end, + struct fdisk_partition *parent, + struct fdisk_partition **pa) +{ + assert(cxt); + assert(pa); + + *pa = NULL; + + if (start == end) + return 0; + *pa = fdisk_new_partition(); + if (!*pa) + return -ENOMEM; + + assert(start); + assert(end); + assert(end > start); + + (*pa)->freespace = 1; + (*pa)->start = fdisk_align_lba_in_range(cxt, start, start, end); + (*pa)->size = end - (*pa)->start + 1ULL; + + if (parent) + (*pa)->parent_partno = parent->partno; + return 0; +} + +/* add freespace description to the right place within @tb */ +static int table_add_freespace( + struct fdisk_context *cxt, + struct fdisk_table *tb, + fdisk_sector_t start, + fdisk_sector_t end, + struct fdisk_partition *parent) +{ + struct fdisk_partition *pa, *x, *real_parent = NULL, *best = NULL; + struct fdisk_iter itr; + int rc = 0; + + assert(tb); + + rc = new_freespace(cxt, start, end, parent, &pa); + if (rc) + return -ENOMEM; + if (!pa) + return 0; + + assert(fdisk_partition_has_start(pa)); + assert(fdisk_partition_has_end(pa)); + + DBG(TAB, ul_debugobj(tb, "adding freespace")); + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + if (parent && fdisk_partition_has_partno(parent)) { + while (fdisk_table_next_partition(tb, &itr, &x) == 0) { + if (!fdisk_partition_has_partno(x)) + continue; + if (x->partno == parent->partno) { + real_parent = x; + break; + } + } + if (!real_parent) { + DBG(TAB, ul_debugobj(tb, "not found freespace parent (partno=%zu)", + parent->partno)); + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + } + } + + while (fdisk_table_next_partition(tb, &itr, &x) == 0) { + fdisk_sector_t end, best_end = 0; + + if (!fdisk_partition_has_end(x)) + continue; + + end = fdisk_partition_get_end(x); + if (best) + best_end = fdisk_partition_get_end(best); + + if (end < pa->start && (!best || best_end < end)) + best = x; + } + + if (!best && real_parent) + best = real_parent; + rc = table_insert_partition(tb, best, pa); + + fdisk_unref_partition(pa); + + DBG(TAB, ul_debugobj(tb, "adding freespace DONE [rc=%d]", rc)); + return rc; +} + +/* analyze @cont(ainer) in @parts and add all detected freespace into @tb, note + * that @parts has to be sorted by partition starts */ +static int check_container_freespace(struct fdisk_context *cxt, + struct fdisk_table *parts, + struct fdisk_table *tb, + struct fdisk_partition *cont) +{ + struct fdisk_iter itr; + struct fdisk_partition *pa; + fdisk_sector_t x, last, grain, lastplusoff; + int rc = 0; + + assert(cxt); + assert(parts); + assert(tb); + assert(cont); + assert(fdisk_partition_has_start(cont)); + + DBG(TAB, ul_debugobj(tb, "analyze container 0x%p", cont)); + + last = fdisk_partition_get_start(cont); + grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1; + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + + DBG(CXT, ul_debugobj(cxt, "initialized: last=%ju, grain=%ju", last, grain)); + + while (fdisk_table_next_partition(parts, &itr, &pa) == 0) { + + DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju", pa->partno, pa->start)); + + if (!pa->used || !fdisk_partition_is_nested(pa) + || !fdisk_partition_has_start(pa)) + continue; + + DBG(CXT, ul_debugobj(cxt, "freespace container analyze: partno=%zu, start=%ju, end=%ju", + pa->partno, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa))); + + lastplusoff = last + cxt->first_lba; + if (pa->start > lastplusoff && pa->start - lastplusoff > grain) + rc = table_add_freespace(cxt, tb, lastplusoff, pa->start, cont); + if (rc) + goto done; + last = fdisk_partition_get_end(pa); + } + + /* free-space remaining in extended partition */ + x = fdisk_partition_get_start(cont) + fdisk_partition_get_size(cont) - 1; + lastplusoff = last + cxt->first_lba; + if (lastplusoff < x && x - lastplusoff > grain) { + DBG(TAB, ul_debugobj(tb, "add remaining space in container 0x%p", cont)); + rc = table_add_freespace(cxt, tb, lastplusoff, x, cont); + } + +done: + DBG(TAB, ul_debugobj(tb, "analyze container 0x%p DONE [rc=%d]", cont, rc)); + return rc; +} + + +/** + * fdisk_get_freespaces + * @cxt: fdisk context + * @tb: returns table + * + * This function adds freespace (described by fdisk_partition) to @table, it + * allocates a new table if the @table points to NULL. + * + * Note that free space smaller than grain (see fdisk_get_grain()) is ignored. + + * Returns: 0 on success, otherwise, a corresponding error. + */ +int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb) +{ + int rc = 0; + fdisk_sector_t last, grain; + struct fdisk_table *parts = NULL; + struct fdisk_partition *pa; + struct fdisk_iter itr; + + DBG(CXT, ul_debugobj(cxt, "get freespace")); + + if (!cxt || !cxt->label || !tb) + return -EINVAL; + if (!*tb && !(*tb = fdisk_new_table())) + return -ENOMEM; + + rc = fdisk_get_partitions(cxt, &parts); + if (rc) + goto done; + + fdisk_table_sort_partitions(parts, fdisk_partition_cmp_start); + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + last = cxt->first_lba; + grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1; + + DBG(CXT, ul_debugobj(cxt, "initialized: last=%ju, grain=%ju", last, grain)); + + /* analyze gaps between partitions */ + while (rc == 0 && fdisk_table_next_partition(parts, &itr, &pa) == 0) { + + DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju", pa->partno, pa->start)); + + if (!pa->used || pa->wholedisk || fdisk_partition_is_nested(pa) + || !fdisk_partition_has_start(pa)) + continue; + DBG(CXT, ul_debugobj(cxt, "freespace analyze: partno=%zu, start=%ju, end=%ju", + pa->partno, + (uintmax_t) fdisk_partition_get_start(pa), + (uintmax_t) fdisk_partition_get_end(pa))); + if (last + grain <= pa->start) { + rc = table_add_freespace(cxt, *tb, + last + (last > cxt->first_lba ? 1 : 0), + pa->start - 1, NULL); + } + /* add gaps between logical partitions */ + if (fdisk_partition_is_container(pa)) + rc = check_container_freespace(cxt, parts, *tb, pa); + last = fdisk_partition_get_end(pa); + } + + /* add free-space behind last partition to the end of the table (so + * don't use table_add_freespace()) */ + if (rc == 0 && last + grain < cxt->total_sectors - 1) { + DBG(CXT, ul_debugobj(cxt, "freespace behind last partition detected")); + rc = new_freespace(cxt, + last + (last > cxt->first_lba ? 1 : 0), + cxt->last_lba, NULL, &pa); + if (pa) { + fdisk_table_add_partition(*tb, pa); + fdisk_unref_partition(pa); + } + } + +done: + fdisk_unref_table(parts); + + DBG(CXT, ul_debugobj(cxt, "get freespace DONE [rc=%d]", rc)); + return rc; +} + +/** + * fdisk_table_wrong_order: + * @tb: table + * + * Returns: 1 of the table is not in disk order + */ +int fdisk_table_wrong_order(struct fdisk_table *tb) +{ + struct fdisk_partition *pa; + struct fdisk_iter itr; + fdisk_sector_t last = 0; + + DBG(TAB, ul_debugobj(tb, "wrong older check")); + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) { + if (!fdisk_partition_has_start(pa)) + continue; + if (pa->start < last) + return 1; + last = pa->start; + } + return 0; +} + +/** + * fdisk_apply_table: + * @cxt: context + * @tb: table + * + * Add partitions from table @tb to the in-memory disk label. See + * fdisk_add_partition(), fdisk_delete_all_partitions(). The partitons + * that does not define start (or does not follow the default start) + * are ingored. + * + * Returns: 0 on success, <0 on error. + */ +int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb) +{ + struct fdisk_partition *pa; + struct fdisk_iter itr; + int rc = 0; + + assert(cxt); + assert(tb); + + DBG(TAB, ul_debugobj(tb, "applying to context %p", cxt)); + + fdisk_reset_iter(&itr, FDISK_ITER_FORWARD); + while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) { + if (!fdisk_partition_has_start(pa) && !pa->start_follow_default) + continue; + rc = fdisk_add_partition(cxt, pa, NULL); + if (rc) + break; + } + + return rc; +} + diff --git a/libblkid/libfdisk/src/test.c b/libblkid/libfdisk/src/test.c new file mode 100644 index 000000000..31ed7e03a --- /dev/null +++ b/libblkid/libfdisk/src/test.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Routines for TEST_PROGRAMs + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifndef TEST_PROGRAM +#define TEST_PROGRAM +#endif + +#include "fdiskP.h" + +int fdisk_run_test(struct fdisk_test *tests, int argc, char *argv[]) +{ + int rc = -1; + struct fdisk_test *ts; + + assert(tests); + assert(argc); + assert(argv); + + if (argc < 2 || + strcmp(argv[1], "--help") == 0 || + strcmp(argv[1], "-h") == 0) + goto usage; + + fdisk_init_debug(0); + + for (ts = tests; ts->name; ts++) { + if (strcmp(ts->name, argv[1]) == 0) { + rc = ts->body(ts, argc - 1, argv + 1); + if (rc) + printf("FAILED [rc=%d]", rc); + break; + } + } + + if (rc < 0 && ts->name == NULL) + goto usage; + + return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +usage: + printf("\nUsage:\n\t%s <test> [testoptions]\nTests:\n", + program_invocation_short_name); + for (ts = tests; ts->name; ts++) { + printf("\t%-15s", ts->name); + if (ts->usage) + printf(" %s\n", ts->usage); + } + printf("\n"); + return EXIT_FAILURE; +} diff --git a/libblkid/libfdisk/src/utils.c b/libblkid/libfdisk/src/utils.c new file mode 100644 index 000000000..482a3062d --- /dev/null +++ b/libblkid/libfdisk/src/utils.c @@ -0,0 +1,154 @@ + +#include "fdiskP.h" +#include "pathnames.h" + +#include <ctype.h> + +/** + * SECTION: utils + * @title: Utils + * @short_description: misc fdisk functions + */ + +/* + * Zeros in-memory first sector buffer + */ +int fdisk_init_firstsector_buffer(struct fdisk_context *cxt) +{ + if (!cxt) + return -EINVAL; + + if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) { + /* Let's allocate a new buffer if no allocated yet, or the + * current buffer has incorrect size */ + if (!cxt->parent || cxt->parent->firstsector != cxt->firstsector) + free(cxt->firstsector); + + DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector " + "buffer [sector_size=%lu]", cxt->sector_size)); + cxt->firstsector = calloc(1, cxt->sector_size); + if (!cxt->firstsector) + return -ENOMEM; + + cxt->firstsector_bufsz = cxt->sector_size; + return 0; + } + + DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer")); + memset(cxt->firstsector, 0, cxt->firstsector_bufsz); + return 0; +} + +int fdisk_read_firstsector(struct fdisk_context *cxt) +{ + ssize_t r; + int rc; + + assert(cxt); + assert(cxt->sector_size); + + rc = fdisk_init_firstsector_buffer(cxt); + if (rc) + return rc; + + assert(cxt->sector_size == cxt->firstsector_bufsz); + + DBG(CXT, ul_debugobj(cxt, "reading first sector " + "buffer [sector_size=%lu]", cxt->sector_size)); + + r = lseek(cxt->dev_fd, 0, SEEK_SET); + if (r == -1) + { + DBG(CXT, ul_debugobj(cxt, "failed to seek to first sector %m")); + return -errno; + } + + r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size); + + if (r != cxt->sector_size) { + if (!errno) + errno = EINVAL; /* probably too small file/device */ + DBG(CXT, ul_debugobj(cxt, "failed to read first sector %m")); + return -errno; + } + + return 0; +} + +/** + * fdisk_partname: + * @dev: device name + * @partno: partition name + * + * Return: allocated buffer with partition name, use free() to deallocate. + */ +char *fdisk_partname(const char *dev, size_t partno) +{ + char *res = NULL; + const char *p = ""; + int w = 0; + + if (!dev || !*dev) { + if (asprintf(&res, "%zd", partno) > 0) + return res; + return NULL; + } + + w = strlen(dev); + if (isdigit(dev[w - 1])) +#ifdef __GNU__ + p = "s"; +#else + p = "p"; +#endif + + /* devfs kludge - note: fdisk partition names are not supposed + to equal kernel names, so there is no reason to do this */ + if (strcmp(dev + w - 4, "disc") == 0) { + w -= 4; + p = "part"; + } + + /* udev names partitions by appending -partN + e.g. ata-SAMSUNG_SV8004H_0357J1FT712448-part1 */ + if ((strncmp(dev, _PATH_DEV_BYID, sizeof(_PATH_DEV_BYID) - 1) == 0) || + strncmp(dev, _PATH_DEV_BYPATH, sizeof(_PATH_DEV_BYPATH) - 1) == 0) { + p = "-part"; + } + + if (asprintf(&res, "%.*s%s%zu", w, dev, p, partno) > 0) + return res; + + return NULL; +} + +#ifdef TEST_PROGRAM +struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; } +struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; } + +int test_partnames(struct fdisk_test *ts, int argc, char *argv[]) +{ + size_t i; + const char *disk = argv[1]; + + for (i = 0; i < 5; i++) { + char *p = fdisk_partname(disk, i + 1); + if (p) + printf("%zu: '%s'\n", i + 1, p); + free(p); + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct fdisk_test tss[] = { + { "--partnames", test_partnames, "<diskname>" }, + { NULL } + }; + + return fdisk_run_test(tss, argc, argv); +} + +#endif diff --git a/libblkid/libuuid/COPYING b/libblkid/libuuid/COPYING new file mode 100644 index 000000000..0e902cf8c --- /dev/null +++ b/libblkid/libuuid/COPYING @@ -0,0 +1,5 @@ +This library is free software; you can redistribute it and/or +modify it under the terms of the Modified BSD License. + +The complete text of the license is available in the +../Documentation/licenses/COPYING.BSD-3 file. diff --git a/libblkid/libuuid/Makemodule.am b/libblkid/libuuid/Makemodule.am new file mode 100644 index 000000000..166be5c26 --- /dev/null +++ b/libblkid/libuuid/Makemodule.am @@ -0,0 +1,10 @@ +if BUILD_LIBUUID + +include libuuid/man/Makemodule.am +include libuuid/src/Makemodule.am + +pkgconfig_DATA += libuuid/uuid.pc +PATHFILES += libuuid/uuid.pc +EXTRA_DIST += libuuid/COPYING + +endif # BUILD_LIBUUID diff --git a/libblkid/libuuid/man/.gitignore b/libblkid/libuuid/man/.gitignore new file mode 100644 index 000000000..7957ad2cc --- /dev/null +++ b/libblkid/libuuid/man/.gitignore @@ -0,0 +1,3 @@ +uuid_generate_random.3 +uuid_generate_time.3 +uuid_generate_time_safe.3 diff --git a/libblkid/libuuid/man/Makemodule.am b/libblkid/libuuid/man/Makemodule.am new file mode 100644 index 000000000..81287d5c7 --- /dev/null +++ b/libblkid/libuuid/man/Makemodule.am @@ -0,0 +1,14 @@ + +dist_man_MANS += \ + libuuid/man/uuid.3 \ + libuuid/man/uuid_clear.3 \ + libuuid/man/uuid_compare.3 \ + libuuid/man/uuid_copy.3 \ + libuuid/man/uuid_generate.3 \ + libuuid/man/uuid_is_null.3 \ + libuuid/man/uuid_parse.3 \ + libuuid/man/uuid_time.3 \ + libuuid/man/uuid_unparse.3 \ + libuuid/man/uuid_generate_random.3 \ + libuuid/man/uuid_generate_time.3 \ + libuuid/man/uuid_generate_time_safe.3 diff --git a/libblkid/libuuid/man/uuid.3 b/libblkid/libuuid/man/uuid.3 new file mode 100644 index 000000000..37b04995e --- /dev/null +++ b/libblkid/libuuid/man/uuid.3 @@ -0,0 +1,65 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid \- DCE compatible Universally Unique Identifier library +.SH SYNOPSIS +.B #include <uuid.h> +.SH DESCRIPTION +The UUID library is used to generate unique identifiers for objects +that may be accessible beyond the local system. This library +generates UUIDs compatible with those created by the Open Software +Foundation (OSF) Distributed Computing Environment (DCE) utility +.BR uuidgen . +.sp +The UUIDs generated by this library can be reasonably expected to be +unique within a system, and unique across all systems. They could +be used, for instance, to generate unique HTTP cookies across multiple +web servers without communication between the servers, and without fear +of a name clash. +.SH "CONFORMING TO" +OSF DCE 1.1 +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.SH "SEE ALSO" +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_time (3), +.BR uuid_unparse (3) diff --git a/libblkid/libuuid/man/uuid_clear.3 b/libblkid/libuuid/man/uuid_clear.3 new file mode 100644 index 000000000..70fca02b7 --- /dev/null +++ b/libblkid/libuuid/man/uuid_clear.3 @@ -0,0 +1,62 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_CLEAR 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_clear \- reset value of UUID variable to the NULL value +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "void uuid_clear(uuid_t " uu ); +.fi +.SH DESCRIPTION +The +.B uuid_clear +function sets the value of the supplied uuid variable +.I uu +to the NULL value. +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_compare.3 b/libblkid/libuuid/man/uuid_compare.3 new file mode 100644 index 000000000..f91181a4e --- /dev/null +++ b/libblkid/libuuid/man/uuid_compare.3 @@ -0,0 +1,68 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_COMPARE 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_compare \- compare whether two UUIDs are the same +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "int uuid_compare(uuid_t " uu1 ", uuid_t " uu2) +.fi +.SH DESCRIPTION +The +.B uuid_compare +function compares the two supplied uuid variables +.IR uu1 " and " uu2 +to each other. +.SH RETURN VALUE +Returns an integer less than, equal to, or greater than zero if +.I uu1 +is found, respectively, to be lexicographically less than, equal, or +greater than +.IR uu2 . +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_copy.3 b/libblkid/libuuid/man/uuid_copy.3 new file mode 100644 index 000000000..5159fa662 --- /dev/null +++ b/libblkid/libuuid/man/uuid_copy.3 @@ -0,0 +1,64 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_COPY 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_copy \- copy a UUID value +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "void uuid_copy(uuid_t " dst ", uuid_t " src); +.fi +.SH DESCRIPTION +The +.B uuid_copy +function copies the UUID variable +.IR src " to " dst . +.SH RETURN VALUE +The copied UUID is returned in the location pointed to by +.IR dst . +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_generate.3 b/libblkid/libuuid/man/uuid_generate.3 new file mode 100644 index 000000000..19904d7de --- /dev/null +++ b/libblkid/libuuid/man/uuid_generate.3 @@ -0,0 +1,126 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_GENERATE 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_generate, uuid_generate_random, uuid_generate_time, +uuid_generate_time_safe \- create a new unique UUID value +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "void uuid_generate(uuid_t " out ); +.BI "void uuid_generate_random(uuid_t " out ); +.BI "void uuid_generate_time(uuid_t " out ); +.BI "int uuid_generate_time_safe(uuid_t " out ); +.fi +.SH DESCRIPTION +The +.B uuid_generate +function creates a new universally unique identifier (UUID). The uuid will +be generated based on high-quality randomness from +.IR /dev/urandom , +if available. If it is not available, then +.B uuid_generate +will use an alternative algorithm which uses the current time, the +local ethernet MAC address (if available), and random data generated +using a pseudo-random generator. +.sp +The +.B uuid_generate_random +function forces the use of the all-random UUID format, even if +a high-quality random number generator (i.e., +.IR /dev/urandom ) +is not available, in which case a pseudo-random +generator will be substituted. Note that the use of a pseudo-random +generator may compromise the uniqueness of UUIDs +generated in this fashion. +.sp +The +.B uuid_generate_time +function forces the use of the alternative algorithm which uses the +current time and the local ethernet MAC address (if available). +This algorithm used to be the default one used to generate UUID, but +because of the use of the ethernet MAC address, it can leak +information about when and where the UUID was generated. This can cause +privacy problems in some applications, so the +.B uuid_generate +function only uses this algorithm if a high-quality source of +randomness is not available. To guarantee uniqueness of UUIDs generated +by concurrently running processes, the uuid library uses global +clock state counter (if the process has permissions to gain exclusive access +to this file) and/or the +.B uuidd +daemon, if it is running already or can be spawned by the process (if +installed and the process has enough permissions to run it). If neither of +these two synchronization mechanisms can be used, it is theoretically possible +that two concurrently running processes obtain the same UUID(s). To tell +whether the UUID has been generated in a safe manner, use +.BR uuid_generate_time_safe . +.sp +The +.B uuid_generate_time_safe +is similar to +.BR uuid_generate_time , +except that it returns a value which denotes whether any of the synchronization +mechanisms (see above) has been used. +.sp +The UUID is 16 bytes (128 bits) long, which gives approximately 3.4x10^38 +unique values (there are approximately 10^80 elementary particles in +the universe according to Carl Sagan's +.IR Cosmos ). +The new UUID can reasonably be considered unique among all UUIDs created +on the local system, and among UUIDs created on other systems in the past +and in the future. +.SH RETURN VALUE +The newly created UUID is returned in the memory location pointed to by +.IR out . +.B uuid_generate_time_safe +returns zero if the UUID has been generated in a safe manner, \-1 otherwise. +.SH "CONFORMING TO" +OSF DCE 1.1 +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.SH "SEE ALSO" +.BR uuid (3), +.BR uuidgen (1), +.BR uuidd (8), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_time (3), +.BR uuid_unparse (3) diff --git a/libblkid/libuuid/man/uuid_is_null.3 b/libblkid/libuuid/man/uuid_is_null.3 new file mode 100644 index 000000000..86a7a50fe --- /dev/null +++ b/libblkid/libuuid/man/uuid_is_null.3 @@ -0,0 +1,64 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_IS_NULL 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_is_null \- compare the value of the UUID to the NULL value +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "int uuid_is_null(uuid_t " uu ); +.fi +.SH DESCRIPTION +The +.B uuid_is_null +function compares the value of the supplied UUID variable +.I uu +to the NULL value. If the value is equal to the NULL UUID, 1 is returned, +otherwise 0 is returned. +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_time (3), +.BR uuid_parse (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_parse.3 b/libblkid/libuuid/man/uuid_parse.3 new file mode 100644 index 000000000..31a59267a --- /dev/null +++ b/libblkid/libuuid/man/uuid_parse.3 @@ -0,0 +1,73 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_PARSE 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_parse \- convert an input UUID string into binary representation +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "int uuid_parse( char *" in ", uuid_t " uu ); +.fi +.SH DESCRIPTION +The +.B uuid_parse +function converts the UUID string given by +.I in +into the binary representation. The input UUID is a string of the form +1b4e28ba\-2fa1\-11d2\-883f\-b9a761bde3fb (in +.BR printf (3) +format "%08x\-%04x\-%04x\-%04x\-%012x", 36 bytes plus the trailing '\e0'). +.SH RETURN VALUE +Upon successfully parsing the input string, 0 is returned, and the UUID is +stored in the location pointed to by +.IR uu , +otherwise \-1 is returned. +.SH "CONFORMING TO" +OSF DCE 1.1 +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_time (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_time.3 b/libblkid/libuuid/man/uuid_time.3 new file mode 100644 index 000000000..483676b5b --- /dev/null +++ b/libblkid/libuuid/man/uuid_time.3 @@ -0,0 +1,78 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_TIME 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_time \- extract the time at which the UUID was created +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "time_t uuid_time(uuid_t " uu ", struct timeval *" ret_tv ) +.fi +.SH DESCRIPTION +The +.B uuid_time +function extracts the time at which the supplied time-based UUID +.I uu +was created. Note that the UUID creation time is only encoded within +certain types of UUIDs. This function can only reasonably expect to +extract the creation time for UUIDs created with the +.BR uuid_generate_time (3) +and +.BR uuid_generate_time_safe (3) +functions. It may or may not work with UUIDs created by other mechanisms. +.SH "RETURN VALUES" +The time at which the UUID was created, in seconds since January 1, 1970 GMT +(the epoch), is returned (see +.BR time "(2))." +The time at which the UUID was created, in seconds and microseconds since +the epoch, is also stored in the location pointed to by +.I ret_tv +(see +.BR gettimeofday "(2))." +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_is_null (3), +.BR uuid_parse (3), +.BR uuid_unparse (3) +.ad diff --git a/libblkid/libuuid/man/uuid_unparse.3 b/libblkid/libuuid/man/uuid_unparse.3 new file mode 100644 index 000000000..1e0116d7a --- /dev/null +++ b/libblkid/libuuid/man/uuid_unparse.3 @@ -0,0 +1,81 @@ +.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) +.\" +.\" %Begin-Header% +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, and the entire permission notice in its entirety, +.\" including the disclaimer of warranties. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior +.\" written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +.\" DAMAGE. +.\" %End-Header% +.\" +.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger +.TH UUID_UNPARSE 3 "May 2009" "util-linux" "Libuuid API" +.SH NAME +uuid_unparse \- convert an UUID from binary representation to a string +.SH SYNOPSIS +.nf +.B #include <uuid.h> +.sp +.BI "void uuid_unparse(uuid_t " uu ", char *" out ); +.BI "void uuid_unparse_upper(uuid_t " uu ", char *" out ); +.BI "void uuid_unparse_lower(uuid_t " uu ", char *" out ); +.fi +.SH DESCRIPTION +The +.B uuid_unparse +function converts the supplied UUID +.I uu +from the binary representation into a 36-byte string (plus tailing '\e0') +of the form 1b4e28ba\-2fa1\-11d2\-883f\-0016d3cca427 and stores this +value in the character string pointed to by +.IR out . +The case of the hex digits returned by +.B uuid_unparse +may be upper or lower case, and is +dependent on the system-dependent local default. +.PP +If the case of the +hex digits is important then the functions +.B uuid_unparse_upper +and +.B uuid_unparse_lower +may be used. +.SH "CONFORMING TO" +OSF DCE 1.1 +.SH AUTHOR +Theodore Y.\& Ts'o +.SH AVAILABILITY +.B libuuid +is part of the util-linux package since version 2.15.1 and is available from +ftp://ftp.kernel.org/pub/linux/utils/util-linux/. +.na +.SH "SEE ALSO" +.BR uuid (3), +.BR uuid_clear (3), +.BR uuid_compare (3), +.BR uuid_copy (3), +.BR uuid_generate (3), +.BR uuid_time (3), +.BR uuid_is_null (3), +.BR uuid_parse (3) +.ad diff --git a/libblkid/libuuid/src/Makemodule.am b/libblkid/libuuid/src/Makemodule.am new file mode 100644 index 000000000..061aff21d --- /dev/null +++ b/libblkid/libuuid/src/Makemodule.am @@ -0,0 +1,61 @@ + +check_PROGRAMS += test_uuid +test_uuid_SOURCES = libuuid/src/test_uuid.c +test_uuid_LDADD = libuuid.la $(SOCKET_LIBS) +test_uuid_CFLAGS = -I$(ul_libuuid_incdir) + +# includes +uuidincdir = $(includedir)/uuid +uuidinc_HEADERS = libuuid/src/uuid.h + +usrlib_exec_LTLIBRARIES += libuuid.la + +libuuid_la_SOURCES = \ + libuuid/src/clear.c \ + libuuid/src/compare.c \ + libuuid/src/copy.c \ + libuuid/src/gen_uuid.c \ + libuuid/src/isnull.c \ + libuuid/src/pack.c \ + libuuid/src/parse.c \ + libuuid/src/unpack.c \ + libuuid/src/unparse.c \ + libuuid/src/uuidd.h \ + libuuid/src/uuidd.h \ + libuuid/src/uuidP.h \ + libuuid/src/uuid_time.c \ + $(uuidinc_HEADERS) \ + lib/randutils.c + +libuuid_la_DEPENDENCIES = libuuid/src/libuuid.sym +libuuid_la_LIBADD = $(SOCKET_LIBS) + +libuuid_la_CFLAGS = \ + $(SOLIB_CFLAGS) \ + -I$(ul_libuuid_incdir) \ + -Ilibuuid/src + +libuuid_la_LDFLAGS = \ + $(SOLIB_LDFLAGS) \ + -Wl,--version-script=$(top_srcdir)/libuuid/src/libuuid.sym \ + -version-info $(LIBUUID_VERSION_INFO) + +EXTRA_DIST += libuuid/src/libuuid.sym + +# move lib from $(usrlib_execdir) to $(libdir) if needed +install-exec-hook-libuuid: + if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libuuid.so"; then \ + mkdir -p $(DESTDIR)$(libdir); \ + mv $(DESTDIR)$(usrlib_execdir)/libuuid.so.* $(DESTDIR)$(libdir); \ + so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libuuid.so); \ + so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ + (cd $(DESTDIR)$(usrlib_execdir) && \ + rm -f libuuid.so && \ + $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libuuid.so); \ + fi + +uninstall-hook-libuuid: + rm -f $(DESTDIR)$(libdir)/libuuid.so* + +INSTALL_EXEC_HOOKS += install-exec-hook-libuuid +UNINSTALL_HOOKS += uninstall-hook-libuuid diff --git a/libblkid/libuuid/src/clear.c b/libblkid/libuuid/src/clear.c new file mode 100644 index 000000000..2d91fee93 --- /dev/null +++ b/libblkid/libuuid/src/clear.c @@ -0,0 +1,43 @@ +/* + * clear.c -- Clear a UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "string.h" + +#include "uuidP.h" + +void uuid_clear(uuid_t uu) +{ + memset(uu, 0, 16); +} + diff --git a/libblkid/libuuid/src/compare.c b/libblkid/libuuid/src/compare.c new file mode 100644 index 000000000..8f3437a2d --- /dev/null +++ b/libblkid/libuuid/src/compare.c @@ -0,0 +1,55 @@ +/* + * compare.c --- compare whether or not two UUIDs are the same + * + * Returns 0 if the two UUIDs are different, and 1 if they are the same. + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "uuidP.h" +#include <string.h> + +#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); + +int uuid_compare(const uuid_t uu1, const uuid_t uu2) +{ + struct uuid uuid1, uuid2; + + uuid_unpack(uu1, &uuid1); + uuid_unpack(uu2, &uuid2); + + UUCMP(uuid1.time_low, uuid2.time_low); + UUCMP(uuid1.time_mid, uuid2.time_mid); + UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); + UUCMP(uuid1.clock_seq, uuid2.clock_seq); + return memcmp(uuid1.node, uuid2.node, 6); +} + diff --git a/libblkid/libuuid/src/copy.c b/libblkid/libuuid/src/copy.c new file mode 100644 index 000000000..ead33aa26 --- /dev/null +++ b/libblkid/libuuid/src/copy.c @@ -0,0 +1,45 @@ +/* + * copy.c --- copy UUIDs + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "uuidP.h" + +void uuid_copy(uuid_t dst, const uuid_t src) +{ + unsigned char *cp1; + const unsigned char *cp2; + int i; + + for (i=0, cp1 = dst, cp2 = src; i < 16; i++) + *cp1++ = *cp2++; +} diff --git a/libblkid/libuuid/src/gen_uuid.c b/libblkid/libuuid/src/gen_uuid.c new file mode 100644 index 000000000..eb793391c --- /dev/null +++ b/libblkid/libuuid/src/gen_uuid.c @@ -0,0 +1,545 @@ +/* + * gen_uuid.c --- generate a DCE-compatible uuid + * + * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#define UUID MYUUID +#endif +#include <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <sys/stat.h> +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NET_IF_DL_H +#include <net/if_dl.h> +#endif +#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) +#include <sys/syscall.h> +#endif + +#include "all-io.h" +#include "uuidP.h" +#include "uuidd.h" +#include "randutils.h" +#include "c.h" + +#ifdef HAVE_TLS +#define THREAD_LOCAL static __thread +#else +#define THREAD_LOCAL static +#endif + +#ifdef _WIN32 +static void gettimeofday (struct timeval *tv, void *dummy) +{ + FILETIME ftime; + uint64_t n; + + GetSystemTimeAsFileTime (&ftime); + n = (((uint64_t) ftime.dwHighDateTime << 32) + + (uint64_t) ftime.dwLowDateTime); + if (n) { + n /= 10; + n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; + } + + tv->tv_sec = n / 1000000; + tv->tv_usec = n % 1000000; +} + +static int getuid (void) +{ + return 1; +} +#endif + +/* + * Get the ethernet hardware address, if we can find it... + * + * XXX for a windows version, probably should use GetAdaptersInfo: + * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 + * commenting out get_node_id just to get gen_uuid to compile under windows + * is not the right way to go! + */ +static int get_node_id(unsigned char *node_id) +{ +#ifdef HAVE_NET_IF_H + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; +#ifdef HAVE_NET_IF_DL_H + struct sockaddr_dl *sdlp; +#endif + +/* + * BSD 4.4 defines the size of an ifreq to be + * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len + * However, under earlier systems, sa_len isn't present, so the size is + * just sizeof(struct ifreq) + */ +#ifdef HAVE_SA_LEN +#define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else +#define ifreq_size(i) sizeof(struct ifreq) +#endif /* HAVE_SA_LEN */ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else +#ifdef HAVE_NET_IF_DL_H + sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; + if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) + continue; + a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; +#else + /* + * XXX we don't have a way of getting the hardware + * address + */ + close(sd); + return 0; +#endif /* HAVE_NET_IF_DL_H */ +#endif /* SIOCGENADDR */ +#endif /* SIOCGIFHWADDR */ + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + continue; + if (node_id) { + memcpy(node_id, a, 6); + close(sd); + return 1; + } + } + close(sd); +#endif + return 0; +} + +/* Assume that the gettimeofday() has microsecond granularity */ +#define MAX_ADJUSTMENT 10 + +/* + * Get clock from global sequence clock counter. + * + * Return -1 if the clock counter could not be opened/locked (in this case + * pseudorandom value is returned in @ret_clock_seq), otherwise return 0. + */ +static int get_clock(uint32_t *clock_high, uint32_t *clock_low, + uint16_t *ret_clock_seq, int *num) +{ + THREAD_LOCAL int adjustment = 0; + THREAD_LOCAL struct timeval last = {0, 0}; + THREAD_LOCAL int state_fd = -2; + THREAD_LOCAL FILE *state_f; + THREAD_LOCAL uint16_t clock_seq; + struct timeval tv; + uint64_t clock_reg; + mode_t save_umask; + int len; + int ret = 0; + + if (state_fd == -2) { + save_umask = umask(0); + state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660); + (void) umask(save_umask); + if (state_fd != -1) { + state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR); + if (!state_f) { + close(state_fd); + state_fd = -1; + ret = -1; + } + } + else + ret = -1; + } + if (state_fd >= 0) { + rewind(state_f); + while (flock(state_fd, LOCK_EX) < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) + continue; + fclose(state_f); + close(state_fd); + state_fd = -1; + ret = -1; + break; + } + } + if (state_fd >= 0) { + unsigned int cl; + unsigned long tv1, tv2; + int a; + + if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", + &cl, &tv1, &tv2, &a) == 4) { + clock_seq = cl & 0x3FFF; + last.tv_sec = tv1; + last.tv_usec = tv2; + adjustment = a; + } + } + + if ((last.tv_sec == 0) && (last.tv_usec == 0)) { + random_get_bytes(&clock_seq, sizeof(clock_seq)); + clock_seq &= 0x3FFF; + gettimeofday(&last, 0); + last.tv_sec--; + } + +try_again: + gettimeofday(&tv, 0); + if ((tv.tv_sec < last.tv_sec) || + ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec < last.tv_usec))) { + clock_seq = (clock_seq+1) & 0x3FFF; + adjustment = 0; + last = tv; + } else if ((tv.tv_sec == last.tv_sec) && + (tv.tv_usec == last.tv_usec)) { + if (adjustment >= MAX_ADJUSTMENT) + goto try_again; + adjustment++; + } else { + adjustment = 0; + last = tv; + } + + clock_reg = tv.tv_usec*10 + adjustment; + clock_reg += ((uint64_t) tv.tv_sec)*10000000; + clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + + if (num && (*num > 1)) { + adjustment += *num - 1; + last.tv_usec += adjustment / 10; + adjustment = adjustment % 10; + last.tv_sec += last.tv_usec / 1000000; + last.tv_usec = last.tv_usec % 1000000; + } + + if (state_fd >= 0) { + rewind(state_f); + len = fprintf(state_f, + "clock: %04x tv: %016lu %08lu adj: %08d\n", + clock_seq, last.tv_sec, last.tv_usec, adjustment); + fflush(state_f); + if (ftruncate(state_fd, len) < 0) { + fprintf(state_f, " \n"); + fflush(state_f); + } + rewind(state_f); + flock(state_fd, LOCK_UN); + } + + *clock_high = clock_reg >> 32; + *clock_low = clock_reg; + *ret_clock_seq = clock_seq; + return ret; +} + +#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) +/* + * Try using the uuidd daemon to generate the UUID + * + * Returns 0 on success, non-zero on failure. + */ +static int get_uuid_via_daemon(int op, uuid_t out, int *num) +{ + char op_buf[64]; + int op_len; + int s; + ssize_t ret; + int32_t reply_len = 0, expected = 16; + struct sockaddr_un srv_addr; + + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -1; + + srv_addr.sun_family = AF_UNIX; + strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH); + + if (connect(s, (const struct sockaddr *) &srv_addr, + sizeof(struct sockaddr_un)) < 0) + goto fail; + + op_buf[0] = op; + op_len = 1; + if (op == UUIDD_OP_BULK_TIME_UUID) { + memcpy(op_buf+1, num, sizeof(*num)); + op_len += sizeof(*num); + expected += sizeof(*num); + } + + ret = write(s, op_buf, op_len); + if (ret < 1) + goto fail; + + ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); + if (ret < 0) + goto fail; + + if (reply_len != expected) + goto fail; + + ret = read_all(s, op_buf, reply_len); + + if (op == UUIDD_OP_BULK_TIME_UUID) + memcpy(op_buf+16, num, sizeof(int)); + + memcpy(out, op_buf, 16); + + close(s); + return ((ret == expected) ? 0 : -1); + +fail: + close(s); + return -1; +} + +#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */ +static int get_uuid_via_daemon(int op, uuid_t out, int *num) +{ + return -1; +} +#endif + +int __uuid_generate_time(uuid_t out, int *num) +{ + static unsigned char node_id[6]; + static int has_init = 0; + struct uuid uu; + uint32_t clock_mid; + int ret; + + if (!has_init) { + if (get_node_id(node_id) <= 0) { + random_get_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts + * with IEEE 802 addresses obtained from + * network cards + */ + node_id[0] |= 0x01; + } + has_init = 1; + } + ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); + uu.clock_seq |= 0x8000; + uu.time_mid = (uint16_t) clock_mid; + uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; + memcpy(uu.node, node_id, 6); + uuid_pack(&uu, out); + return ret; +} + +/* + * Generate time-based UUID and store it to @out + * + * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon, + * or, if uuidd is not usable, by using the global clock state counter (see get_clock()). + * If neither of these is possible (e.g. because of insufficient permissions), it generates + * the UUID anyway, but returns -1. Otherwise, returns 0. + */ +static int uuid_generate_time_generic(uuid_t out) { +#ifdef HAVE_TLS + THREAD_LOCAL int num = 0; + THREAD_LOCAL struct uuid uu; + THREAD_LOCAL time_t last_time = 0; + time_t now; + + if (num > 0) { + now = time(0); + if (now > last_time+1) + num = 0; + } + if (num <= 0) { + num = 1000; + if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, + out, &num) == 0) { + last_time = time(0); + uuid_unpack(out, &uu); + num--; + return 0; + } + num = 0; + } + if (num > 0) { + uu.time_low++; + if (uu.time_low == 0) { + uu.time_mid++; + if (uu.time_mid == 0) + uu.time_hi_and_version++; + } + num--; + uuid_pack(&uu, out); + return 0; + } +#else + if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0) + return 0; +#endif + + return __uuid_generate_time(out, 0); +} + +/* + * Generate time-based UUID and store it to @out. + * + * Discards return value from uuid_generate_time_generic() + */ +void uuid_generate_time(uuid_t out) +{ + (void)uuid_generate_time_generic(out); +} + + +int uuid_generate_time_safe(uuid_t out) +{ + return uuid_generate_time_generic(out); +} + + +void __uuid_generate_random(uuid_t out, int *num) +{ + uuid_t buf; + struct uuid uu; + int i, n; + + if (!num || !*num) + n = 1; + else + n = *num; + + for (i = 0; i < n; i++) { + random_get_bytes(buf, sizeof(buf)); + uuid_unpack(buf, &uu); + + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) + | 0x4000; + uuid_pack(&uu, out); + out += sizeof(uuid_t); + } +} + +void uuid_generate_random(uuid_t out) +{ + int num = 1; + /* No real reason to use the daemon for random uuid's -- yet */ + + __uuid_generate_random(out, &num); +} + +/* + * Check whether good random source (/dev/random or /dev/urandom) + * is available. + */ +static int have_random_source(void) +{ + struct stat s; + + return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s)); +} + + +/* + * This is the generic front-end to uuid_generate_random and + * uuid_generate_time. It uses uuid_generate_random only if + * /dev/urandom is available, since otherwise we won't have + * high-quality randomness. + */ +void uuid_generate(uuid_t out) +{ + if (have_random_source()) + uuid_generate_random(out); + else + uuid_generate_time(out); +} diff --git a/libblkid/libuuid/src/isnull.c b/libblkid/libuuid/src/isnull.c new file mode 100644 index 000000000..931e7e7db --- /dev/null +++ b/libblkid/libuuid/src/isnull.c @@ -0,0 +1,48 @@ +/* + * isnull.c --- Check whether or not the UUID is null + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include "uuidP.h" + +/* Returns 1 if the uuid is the NULL uuid */ +int uuid_is_null(const uuid_t uu) +{ + const unsigned char *cp; + int i; + + for (i=0, cp = uu; i < 16; i++) + if (*cp++) + return 0; + return 1; +} + diff --git a/libblkid/libuuid/src/libuuid.sym b/libblkid/libuuid/src/libuuid.sym new file mode 100644 index 000000000..28a207684 --- /dev/null +++ b/libblkid/libuuid/src/libuuid.sym @@ -0,0 +1,48 @@ +/* + * The symbol versioning ensures that a new application requiring symbol 'foo' + * can't run with old libbrary.so not providing 'foo' - the global SONAME + * version info can't enforce this since we never change the SONAME. + * + * The original libuuid from e2fsprogs (<=1.41.5) does not to use + * symbol versioning -- all the original symbols are in UUID_1.0 now. + * + * Copyright (C) 2011-2014 Karel Zak <kzak@redhat.com> + */ +UUID_1.0 { +global: + uuid_clear; + uuid_compare; + uuid_copy; + uuid_generate; + uuid_generate_random; + uuid_generate_time; + uuid_is_null; + uuid_parse; + uuid_unparse; + uuid_unparse_lower; + uuid_unparse_upper; + uuid_time; + uuid_type; + uuid_variant; +}; + +/* + * version(s) since util-linux 2.20 + */ +UUID_2.20 { +global: + uuid_generate_time_safe; +} UUID_1.0; + + +/* + * __uuid_* this is not part of the official API, this is + * uuidd (uuid daemon) specific stuff. Hell. + */ +UUIDD_PRIVATE { +global: + __uuid_generate_time; + __uuid_generate_random; +local: + *; +}; diff --git a/libblkid/libuuid/src/pack.c b/libblkid/libuuid/src/pack.c new file mode 100644 index 000000000..6e1247669 --- /dev/null +++ b/libblkid/libuuid/src/pack.c @@ -0,0 +1,69 @@ +/* + * Internal routine for packing UUIDs + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include <string.h> +#include "uuidP.h" + +void uuid_pack(const struct uuid *uu, uuid_t ptr) +{ + uint32_t tmp; + unsigned char *out = ptr; + + tmp = uu->time_low; + out[3] = (unsigned char) tmp; + tmp >>= 8; + out[2] = (unsigned char) tmp; + tmp >>= 8; + out[1] = (unsigned char) tmp; + tmp >>= 8; + out[0] = (unsigned char) tmp; + + tmp = uu->time_mid; + out[5] = (unsigned char) tmp; + tmp >>= 8; + out[4] = (unsigned char) tmp; + + tmp = uu->time_hi_and_version; + out[7] = (unsigned char) tmp; + tmp >>= 8; + out[6] = (unsigned char) tmp; + + tmp = uu->clock_seq; + out[9] = (unsigned char) tmp; + tmp >>= 8; + out[8] = (unsigned char) tmp; + + memcpy(out+10, uu->node, 6); +} + diff --git a/libblkid/libuuid/src/parse.c b/libblkid/libuuid/src/parse.c new file mode 100644 index 000000000..074383efa --- /dev/null +++ b/libblkid/libuuid/src/parse.c @@ -0,0 +1,79 @@ +/* + * parse.c --- UUID parsing + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "uuidP.h" + +int uuid_parse(const char *in, uuid_t uu) +{ + struct uuid uuid; + int i; + const char *cp; + char buf[3]; + + if (strlen(in) != 36) + return -1; + for (i=0, cp = in; i <= 36; i++,cp++) { + if ((i == 8) || (i == 13) || (i == 18) || + (i == 23)) { + if (*cp == '-') + continue; + else + return -1; + } + if (i== 36) + if (*cp == 0) + continue; + if (!isxdigit(*cp)) + return -1; + } + uuid.time_low = strtoul(in, NULL, 16); + uuid.time_mid = strtoul(in+9, NULL, 16); + uuid.time_hi_and_version = strtoul(in+14, NULL, 16); + uuid.clock_seq = strtoul(in+19, NULL, 16); + cp = in+24; + buf[2] = 0; + for (i=0; i < 6; i++) { + buf[0] = *cp++; + buf[1] = *cp++; + uuid.node[i] = strtoul(buf, NULL, 16); + } + + uuid_pack(&uuid, uu); + return 0; +} diff --git a/libblkid/libuuid/src/test_uuid.c b/libblkid/libuuid/src/test_uuid.c new file mode 100644 index 000000000..e03138f7d --- /dev/null +++ b/libblkid/libuuid/src/test_uuid.c @@ -0,0 +1,180 @@ +/* + * tst_uuid.c --- test program from the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#define UUID MYUUID +#endif + +#include <stdio.h> +#include <stdlib.h> + +#include "uuid.h" + +static int test_uuid(const char * uuid, int isValid) +{ + static const char * validStr[2] = {"invalid", "valid"}; + uuid_t uuidBits; + int parsedOk; + + parsedOk = uuid_parse(uuid, uuidBits) == 0; + + printf("%s is %s", uuid, validStr[isValid]); + if (parsedOk != isValid) { + printf(" but uuid_parse says %s\n", validStr[parsedOk]); + return 1; + } + printf(", OK\n"); + return 0; +} + +#ifdef __GNUC__ +#define ATTR(x) __attribute__(x) +#else +#define ATTR(x) +#endif + +int +main(int argc ATTR((unused)) , char **argv ATTR((unused))) +{ + uuid_t buf, tst; + char str[100]; + struct timeval tv; + time_t time_reg; + unsigned char *cp; + int i; + int failed = 0; + int type, variant; + + uuid_generate(buf); + uuid_unparse(buf, str); + printf("UUID generate = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + printf("\n"); + + uuid_generate_random(buf); + uuid_unparse(buf, str); + printf("UUID random string = %s\n", str); + printf("UUID: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 4) { + printf("Incorrect UUID type; was expecting " + "4 (random type)!\n"); + failed++; + } + printf("\n"); + + uuid_generate_time(buf); + uuid_unparse(buf, str); + printf("UUID string = %s\n", str); + printf("UUID time: "); + for (i=0, cp = (unsigned char *) &buf; i < 16; i++) { + printf("%02x", *cp++); + } + printf("\n"); + type = uuid_type(buf); variant = uuid_variant(buf); + printf("UUID type = %d, UUID variant = %d\n", type, variant); + if (variant != UUID_VARIANT_DCE) { + printf("Incorrect UUID Variant; was expecting DCE!\n"); + failed++; + } + if (type != 1) { + printf("Incorrect UUID type; was expecting " + "1 (time-based type)!\\n"); + failed++; + } + tv.tv_sec = 0; + tv.tv_usec = 0; + time_reg = uuid_time(buf, &tv); + printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec, + ctime(&time_reg)); + uuid_parse(str, tst); + if (!uuid_compare(buf, tst)) + printf("UUID parse and compare succeeded.\n"); + else { + printf("UUID parse and compare failed!\n"); + failed++; + } + uuid_clear(tst); + if (uuid_is_null(tst)) + printf("UUID clear and is null succeeded.\n"); + else { + printf("UUID clear and is null failed!\n"); + failed++; + } + uuid_copy(buf, tst); + if (!uuid_compare(buf, tst)) + printf("UUID copy and compare succeeded.\n"); + else { + printf("UUID copy and compare failed!\n"); + failed++; + } + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981b", 1); + failed += test_uuid("84949CC5-4701-4A84-895B-354C584A981B", 1); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981bc", 0); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981", 0); + failed += test_uuid("84949cc5x4701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc504701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-470104a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a840895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a84-895b0354c584a981b", 0); + failed += test_uuid("g4949cc5-4701-4a84-895b-354c584a981b", 0); + failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981g", 0); + + if (failed) { + printf("%d failures.\n", failed); + exit(1); + } + return 0; +} diff --git a/libblkid/libuuid/src/unpack.c b/libblkid/libuuid/src/unpack.c new file mode 100644 index 000000000..beaaff3ca --- /dev/null +++ b/libblkid/libuuid/src/unpack.c @@ -0,0 +1,63 @@ +/* + * Internal routine for unpacking UUID + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include <string.h> +#include "uuidP.h" + +void uuid_unpack(const uuid_t in, struct uuid *uu) +{ + const uint8_t *ptr = in; + uint32_t tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + diff --git a/libblkid/libuuid/src/unparse.c b/libblkid/libuuid/src/unparse.c new file mode 100644 index 000000000..a95bbb042 --- /dev/null +++ b/libblkid/libuuid/src/unparse.c @@ -0,0 +1,76 @@ +/* + * unparse.c -- convert a UUID to string + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include <stdio.h> + +#include "uuidP.h" + +static const char *fmt_lower = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + +static const char *fmt_upper = + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; + +#ifdef UUID_UNPARSE_DEFAULT_UPPER +#define FMT_DEFAULT fmt_upper +#else +#define FMT_DEFAULT fmt_lower +#endif + +static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + sprintf(out, fmt, + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +void uuid_unparse_lower(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_lower); +} + +void uuid_unparse_upper(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, fmt_upper); +} + +void uuid_unparse(const uuid_t uu, char *out) +{ + uuid_unparse_x(uu, out, FMT_DEFAULT); +} diff --git a/libblkid/libuuid/src/uuid.h b/libblkid/libuuid/src/uuid.h new file mode 100644 index 000000000..30bd4c0e0 --- /dev/null +++ b/libblkid/libuuid/src/uuid.h @@ -0,0 +1,104 @@ +/* + * Public include file for the UUID library + * + * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifndef _UUID_UUID_H +#define _UUID_UUID_H + +#include <sys/types.h> +#ifndef _WIN32 +#include <sys/time.h> +#endif +#include <time.h> + +typedef unsigned char uuid_t[16]; + +/* UUID Variant definitions */ +#define UUID_VARIANT_NCS 0 +#define UUID_VARIANT_DCE 1 +#define UUID_VARIANT_MICROSOFT 2 +#define UUID_VARIANT_OTHER 3 + +/* UUID Type definitions */ +#define UUID_TYPE_DCE_TIME 1 +#define UUID_TYPE_DCE_RANDOM 4 + +/* Allow UUID constants to be defined */ +#ifdef __GNUC__ +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#else +#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \ + static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* clear.c */ +extern void uuid_clear(uuid_t uu); + +/* compare.c */ +extern int uuid_compare(const uuid_t uu1, const uuid_t uu2); + +/* copy.c */ +extern void uuid_copy(uuid_t dst, const uuid_t src); + +/* gen_uuid.c */ +extern void uuid_generate(uuid_t out); +extern void uuid_generate_random(uuid_t out); +extern void uuid_generate_time(uuid_t out); +extern int uuid_generate_time_safe(uuid_t out); + +/* isnull.c */ +extern int uuid_is_null(const uuid_t uu); + +/* parse.c */ +extern int uuid_parse(const char *in, uuid_t uu); + +/* unparse.c */ +extern void uuid_unparse(const uuid_t uu, char *out); +extern void uuid_unparse_lower(const uuid_t uu, char *out); +extern void uuid_unparse_upper(const uuid_t uu, char *out); + +/* uuid_time.c */ +extern time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); +extern int uuid_type(const uuid_t uu); +extern int uuid_variant(const uuid_t uu); + +#ifdef __cplusplus +} +#endif + +#endif /* _UUID_UUID_H */ diff --git a/libblkid/libuuid/src/uuidP.h b/libblkid/libuuid/src/uuidP.h new file mode 100644 index 000000000..86a5e266f --- /dev/null +++ b/libblkid/libuuid/src/uuidP.h @@ -0,0 +1,61 @@ +/* + * uuid.h -- private header file for uuids + * + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#include <inttypes.h> +#include <sys/types.h> + +#include "uuid.h" + +#define LIBUUID_CLOCK_FILE "/var/lib/libuuid/clock.txt" + +/* + * Offset between 15-Oct-1582 and 1-Jan-70 + */ +#define TIME_OFFSET_HIGH 0x01B21DD2 +#define TIME_OFFSET_LOW 0x13814000 + +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint16_t clock_seq; + uint8_t node[6]; +}; + + +/* + * prototypes + */ +void uuid_pack(const struct uuid *uu, uuid_t ptr); +void uuid_unpack(const uuid_t in, struct uuid *uu); diff --git a/libblkid/libuuid/src/uuid_time.c b/libblkid/libuuid/src/uuid_time.c new file mode 100644 index 000000000..f25f5c90f --- /dev/null +++ b/libblkid/libuuid/src/uuid_time.c @@ -0,0 +1,171 @@ +/* + * uuid_time.c --- Interpret the time field from a uuid. This program + * violates the UUID abstraction barrier by reaching into the guts + * of a UUID and interpreting it. + * + * Copyright (C) 1998, 1999 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#define UUID MYUUID +#endif + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <sys/types.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <time.h> + +#include "uuidP.h" + +time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) +{ + struct timeval tv; + struct uuid uuid; + uint32_t high; + uint64_t clock_reg; + + uuid_unpack(uu, &uuid); + + high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); + clock_reg = uuid.time_low | ((uint64_t) high << 32); + + clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; + tv.tv_sec = clock_reg / 10000000; + tv.tv_usec = (clock_reg % 10000000) / 10; + + if (ret_tv) + *ret_tv = tv; + + return tv.tv_sec; +} + +int uuid_type(const uuid_t uu) +{ + struct uuid uuid; + + uuid_unpack(uu, &uuid); + return ((uuid.time_hi_and_version >> 12) & 0xF); +} + +int uuid_variant(const uuid_t uu) +{ + struct uuid uuid; + int var; + + uuid_unpack(uu, &uuid); + var = uuid.clock_seq; + + if ((var & 0x8000) == 0) + return UUID_VARIANT_NCS; + if ((var & 0x4000) == 0) + return UUID_VARIANT_DCE; + if ((var & 0x2000) == 0) + return UUID_VARIANT_MICROSOFT; + return UUID_VARIANT_OTHER; +} + +#ifdef DEBUG +static const char *variant_string(int variant) +{ + switch (variant) { + case UUID_VARIANT_NCS: + return "NCS"; + case UUID_VARIANT_DCE: + return "DCE"; + case UUID_VARIANT_MICROSOFT: + return "Microsoft"; + default: + return "Other"; + } +} + + +int +main(int argc, char **argv) +{ + uuid_t buf; + time_t time_reg; + struct timeval tv; + int type, variant; + + if (argc != 2) { + fprintf(stderr, "Usage: %s uuid\n", argv[0]); + exit(1); + } + if (uuid_parse(argv[1], buf)) { + fprintf(stderr, "Invalid UUID: %s\n", argv[1]); + exit(1); + } + variant = uuid_variant(buf); + type = uuid_type(buf); + time_reg = uuid_time(buf, &tv); + + printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); + if (variant != UUID_VARIANT_DCE) { + printf("Warning: This program only knows how to interpret " + "DCE UUIDs.\n\tThe rest of the output is likely " + "to be incorrect!!\n"); + } + printf("UUID type is %d", type); + switch (type) { + case 1: + printf(" (time based)\n"); + break; + case 2: + printf(" (DCE)\n"); + break; + case 3: + printf(" (name-based)\n"); + break; + case 4: + printf(" (random)\n"); + break; + default: + printf("\n"); + } + if (type != 1) { + printf("Warning: not a time-based UUID, so UUID time " + "decoding will likely not work!\n"); + } + printf("UUID time is: (%ld, %ld): %s\n", tv.tv_sec, tv.tv_usec, + ctime(&time_reg)); + + return 0; +} +#endif diff --git a/libblkid/libuuid/src/uuidd.h b/libblkid/libuuid/src/uuidd.h new file mode 100644 index 000000000..2f709680b --- /dev/null +++ b/libblkid/libuuid/src/uuidd.h @@ -0,0 +1,54 @@ +/* + * Definitions used by the uuidd daemon + * + * Copyright (C) 2007 Theodore Ts'o. + * + * %Begin-Header% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * %End-Header% + */ + +#ifndef _UUID_UUIDD_H +#define _UUID_UUIDD_H + +#define UUIDD_DIR _PATH_LOCALSTATEDIR "/uuidd" +#define UUIDD_SOCKET_PATH UUIDD_DIR "/request" +#define UUIDD_PIDFILE_PATH UUIDD_DIR "/uuidd.pid" +#define UUIDD_PATH "/usr/sbin/uuidd" + +#define UUIDD_OP_GETPID 0 +#define UUIDD_OP_GET_MAXOP 1 +#define UUIDD_OP_TIME_UUID 2 +#define UUIDD_OP_RANDOM_UUID 3 +#define UUIDD_OP_BULK_TIME_UUID 4 +#define UUIDD_OP_BULK_RANDOM_UUID 5 +#define UUIDD_MAX_OP UUIDD_OP_BULK_RANDOM_UUID + +extern int __uuid_generate_time(uuid_t out, int *num); +extern void __uuid_generate_random(uuid_t out, int *num); + +#endif /* _UUID_UUID_H */ diff --git a/libblkid/libuuid/uuid.pc.in b/libblkid/libuuid/uuid.pc.in new file mode 100644 index 000000000..875de19bc --- /dev/null +++ b/libblkid/libuuid/uuid.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@usrlib_execdir@ +includedir=@includedir@ + +Name: uuid +Description: Universally unique id library +Version: @LIBUUID_VERSION@ +Requires: +Cflags: -I${includedir}/uuid +Libs: -L${libdir} -luuid diff --git a/libblkid/linux_raid.c b/libblkid/linux_raid.c deleted file mode 100644 index a3f9d67d5..000000000 --- a/libblkid/linux_raid.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct mdp0_super_block { - uint32_t md_magic; - uint32_t major_version; - uint32_t minor_version; - uint32_t patch_version; - uint32_t gvalid_words; - uint32_t set_uuid0; - uint32_t ctime; - uint32_t level; - uint32_t size; - uint32_t nr_disks; - uint32_t raid_disks; - uint32_t md_minor; - uint32_t not_persistent; - uint32_t set_uuid1; - uint32_t set_uuid2; - uint32_t set_uuid3; -}; - -/* - * Version-1, little-endian. - */ -struct mdp1_super_block { - /* constant array information - 128 bytes */ - uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ - uint32_t major_version; /* 1 */ - uint32_t feature_map; /* 0 for now */ - uint32_t pad0; /* always set to 0 when writing */ - - uint8_t set_uuid[16]; /* user-space generated. */ - unsigned char set_name[32]; /* set and interpreted by user-space */ - - uint64_t ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ - uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ - uint32_t layout; /* only for raid5 currently */ - uint64_t size; /* used size of component devices, in 512byte sectors */ - - uint32_t chunksize; /* in 512byte sectors */ - uint32_t raid_disks; - uint32_t bitmap_offset; /* sectors after start of superblock that bitmap starts - * NOTE: signed, so bitmap can be before superblock - * only meaningful of feature_map[0] is set. - */ - - /* These are only valid with feature bit '4' */ - uint32_t new_level; /* new level we are reshaping to */ - uint64_t reshape_position; /* next address in array-space for reshape */ - uint32_t delta_disks; /* change in number of raid_disks */ - uint32_t new_layout; /* new layout */ - uint32_t new_chunk; /* new chunk size (bytes) */ - uint8_t pad1[128-124]; /* set to 0 when written */ - - /* constant this-device information - 64 bytes */ - uint64_t data_offset; /* sector start of data, often 0 */ - uint64_t data_size; /* sectors in this device that can be used for data */ - uint64_t super_offset; /* sector start of this superblock */ - uint64_t recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ - uint32_t dev_number; /* permanent identifier of this device - not role in raid */ - uint32_t cnt_corrected_read; /* number of read errors that were corrected by re-writing */ - uint8_t device_uuid[16]; /* user-space setable, ignored by kernel */ - uint8_t devflags; /* per-device flags. Only one defined...*/ - uint8_t pad2[64-57]; /* set to 0 when writing */ - - /* array state information - 64 bytes */ - uint64_t utime; /* 40 bits second, 24 btes microseconds */ - uint64_t events; /* incremented when superblock updated */ - uint64_t resync_offset; /* data before this offset (from data_offset) known to be in sync */ - uint32_t sb_csum; /* checksum up to dev_roles[max_dev] */ - uint32_t max_dev; /* size of dev_roles[] array to consider */ - uint8_t pad3[64-32]; /* set to 0 when writing */ - - /* device state information. Indexed by dev_number. - * 2 bytes per device - * Note there are no per-device state flags. State information is rolled - * into the 'roles' value. If a device is spare or faulty, then it doesn't - * have a meaningful role. - */ - uint16_t dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ -}; - - -#define MD_RESERVED_BYTES 0x10000 -#define MD_SB_MAGIC 0xa92b4efc - -static int probe_raid0(blkid_probe pr, blkid_loff_t off) -{ - struct mdp0_super_block *mdp0; - union { - uint32_t ints[4]; - uint8_t bytes[16]; - } uuid; - uint32_t ma, mi, pa; - uint64_t size; - - if (pr->size < MD_RESERVED_BYTES) - return -1; - mdp0 = (struct mdp0_super_block *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct mdp0_super_block)); - if (!mdp0) - return -1; - - memset(uuid.ints, 0, sizeof(uuid.ints)); - - if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { - uuid.ints[0] = swab32(mdp0->set_uuid0); - if (le32_to_cpu(mdp0->minor_version) >= 90) { - uuid.ints[1] = swab32(mdp0->set_uuid1); - uuid.ints[2] = swab32(mdp0->set_uuid2); - uuid.ints[3] = swab32(mdp0->set_uuid3); - } - ma = le32_to_cpu(mdp0->major_version); - mi = le32_to_cpu(mdp0->minor_version); - pa = le32_to_cpu(mdp0->patch_version); - size = le32_to_cpu(mdp0->size); - - } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { - uuid.ints[0] = mdp0->set_uuid0; - if (be32_to_cpu(mdp0->minor_version) >= 90) { - uuid.ints[1] = mdp0->set_uuid1; - uuid.ints[2] = mdp0->set_uuid2; - uuid.ints[3] = mdp0->set_uuid3; - } - ma = be32_to_cpu(mdp0->major_version); - mi = be32_to_cpu(mdp0->minor_version); - pa = be32_to_cpu(mdp0->patch_version); - size = be32_to_cpu(mdp0->size); - } else - return 1; - - size <<= 10; /* convert KiB to bytes */ - - if (pr->size < 0 || (uint64_t) pr->size < size + MD_RESERVED_BYTES) - /* device is too small */ - return 1; - - if (off < 0 || (uint64_t) off < size) - /* no space before superblock */ - return 1; - - /* - * Check for collisions between RAID and partition table - * - * For example the superblock is at the end of the last partition, it's - * the same position as at the end of the disk... - */ - if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) && - blkid_probe_is_covered_by_pt(pr, - off - size, /* min. start */ - size + MD_RESERVED_BYTES)) { /* min. length */ - - /* ignore this superblock, it's within any partition and - * we are working with whole-disk now */ - return 1; - } - - if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0) - return -1; - if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic), - (unsigned char *) &mdp0->md_magic)) - return -1; - return 0; -} - -static int probe_raid1(blkid_probe pr, off_t off) -{ - struct mdp1_super_block *mdp1; - - mdp1 = (struct mdp1_super_block *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct mdp1_super_block)); - if (!mdp1) - return -1; - if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) - return -1; - if (le32_to_cpu(mdp1->major_version) != 1U) - return -1; - if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9) - return -1; - if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0) - return -1; - if (blkid_probe_set_uuid_as(pr, - (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0) - return -1; - if (blkid_probe_set_label(pr, mdp1->set_name, - sizeof(mdp1->set_name)) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic), - (unsigned char *) &mdp1->magic)) - return -1; - return 0; -} - -int probe_raid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - const char *ver = NULL; - - if (pr->size > MD_RESERVED_BYTES) { - /* version 0 at the end of the device */ - uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1)) - - MD_RESERVED_BYTES; - if (probe_raid0(pr, sboff) == 0) - return 0; - - /* version 1.0 at the end of the device */ - sboff = (pr->size & ~(0x1000 - 1)) - 0x2000; - if (probe_raid1(pr, sboff) == 0) - ver = "1.0"; - } - - if (!ver) { - /* version 1.1 at the start of the device */ - if (probe_raid1(pr, 0) == 0) - ver = "1.1"; - - /* version 1.2 at 4k offset from the start */ - else if (probe_raid1(pr, 0x1000) == 0) - ver = "1.2"; - } - - if (ver) { - blkid_probe_set_version(pr, ver); - return 0; - } - return -1; -} - - -const struct blkid_idinfo linuxraid_idinfo = { - .name = "linux_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_raid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/llseek.c b/libblkid/llseek.c deleted file mode 100644 index be4fdd323..000000000 --- a/libblkid/llseek.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * llseek.c -- stub calling the llseek system call - * - * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef __MSDOS__ -#include <io.h> -#endif - -#include "blkidP.h" - -#ifdef __linux__ - -#define my_llseek lseek64 -#include <linux/unistd.h> - -#ifndef __NR__llseek -#define __NR__llseek 140 -#endif - -blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence) -{ - blkid_loff_t result; - static int do_compat = 0; - - if ((sizeof(off_t) >= sizeof(blkid_loff_t)) || - (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1)))) - return lseek(fd, (off_t) offset, whence); - - if (do_compat) { - errno = EOVERFLOW; - return -1; - } - - if (result == -1 && errno == ENOSYS) { - /* - * Just in case this code runs on top of an old kernel - * which does not support the llseek system call - */ - do_compat++; - errno = EOVERFLOW; - } - return result; -} - -#else /* !linux */ - -#ifndef EOVERFLOW -#ifdef EXT2_ET_INVALID_ARGUMENT -#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT -#else -#define EOVERFLOW 112 -#endif -#endif - -blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin) -{ -#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) - return lseek64 (fd, offset, origin); -#else - if ((sizeof(off_t) < sizeof(blkid_loff_t)) && - (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) { - errno = EOVERFLOW; - return -1; - } - return lseek(fd, (off_t) offset, origin); -#endif -} - -#endif /* linux */ - - diff --git a/libblkid/loopdev.c b/libblkid/loopdev.c deleted file mode 100644 index a25a2fae4..000000000 --- a/libblkid/loopdev.c +++ /dev/null @@ -1,1559 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - * - * -- based on mount/losetup.c - * - * Simple library for work with loop devices. - * - * - requires kernel 2.6.x - * - reads info from /sys/block/loop<N>/loop/<attr> (new kernels) - * - reads info by ioctl - * - supports *unlimited* number of loop devices - * - supports /dev/loop<N> as well as /dev/loop/<N> - * - minimize overhead (fd, loopinfo, ... are shared for all operations) - * - setup (associate device and backing file) - * - delete (dis-associate file) - * - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported - * - extendible - */ -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <ctype.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <sys/sysmacros.h> -#include <inttypes.h> -#include <dirent.h> -#include <linux/posix_types.h> - -#include "linux_version.h" -#include "c.h" -#include "sysfs.h" -#include "pathnames.h" -#include "loopdev.h" -#include "canonicalize.h" -#include "at.h" - -#define CONFIG_LOOPDEV_DEBUG - -#ifdef CONFIG_LOOPDEV_DEBUG -# include <stdarg.h> - -# define DBG(l,x) do { \ - if ((l)->debug) {\ - fprintf(stderr, "loopdev: [%p]: ", (l)); \ - x; \ - } \ - } while(0) - -static inline void __attribute__ ((__format__ (__printf__, 1, 2))) -loopdev_debug(const char *mesg, ...) -{ - va_list ap; - va_start(ap, mesg); - vfprintf(stderr, mesg, ap); - va_end(ap); - fputc('\n', stderr); -} - -#else /* !CONFIG_LOOPDEV_DEBUG */ -# define DBG(m,x) do { ; } while(0) -#endif - -/* - * see loopcxt_init() - */ -#define loopcxt_ioctl_enabled(_lc) (!((_lc)->flags & LOOPDEV_FL_NOIOCTL)) -#define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \ - && !loopcxt_ioctl_enabled(_lc) - -/* - * @lc: context - * @device: device name, absolute device path or NULL to reset the current setting - * - * Sets device, absolute paths (e.g. "/dev/loop<N>") are unchanged, device - * names ("loop<N>") are converted to the path (/dev/loop<N> or to - * /dev/loop/<N>) - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) -{ - if (!lc) - return -EINVAL; - - if (lc->fd >= 0) { - close(lc->fd); - DBG(lc, loopdev_debug("closing old open fd")); - } - lc->fd = -1; - lc->mode = 0; - lc->has_info = 0; - lc->info_failed = 0; - *lc->device = '\0'; - memset(&lc->info, 0, sizeof(lc->info)); - - /* set new */ - if (device) { - if (*device != '/') { - const char *dir = _PATH_DEV; - - /* compose device name for /dev/loop<n> or /dev/loop/<n> */ - if (lc->flags & LOOPDEV_FL_DEVSUBDIR) { - if (strlen(device) < 5) - return -1; - device += 4; - dir = _PATH_DEV_LOOP "/"; /* _PATH_DEV uses tailing slash */ - } - snprintf(lc->device, sizeof(lc->device), "%s%s", - dir, device); - } else { - strncpy(lc->device, device, sizeof(lc->device)); - lc->device[sizeof(lc->device) - 1] = '\0'; - } - DBG(lc, loopdev_debug("%s successfully assigned", device)); - } - - sysfs_deinit(&lc->sysfs); - return 0; -} - -int loopcxt_has_device(struct loopdev_cxt *lc) -{ - return lc && *lc->device; -} - -/* - * @lc: context - * @flags: LOOPDEV_FL_* flags - * - * Initilize loop handler. - * - * We have two sets of the flags: - * - * * LOOPDEV_FL_* flags control loopcxt_* API behavior - * - * * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls - * - * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2) - * syscall to open loop device. By default is the device open read-only. - * - * The expection is loopcxt_setup_device(), where the device is open read-write - * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()). - * - * Returns: <0 on error, 0 on success. - */ -int loopcxt_init(struct loopdev_cxt *lc, int flags) -{ - int rc; - struct stat st; - struct loopdev_cxt dummy = UL_LOOPDEVCXT_EMPTY; - - if (!lc) - return -EINVAL; - - memcpy(lc, &dummy, sizeof(dummy)); - lc->flags = flags; - - if (getenv("LOOPDEV_DEBUG")) - loopcxt_enable_debug(lc, TRUE); - - rc = loopcxt_set_device(lc, NULL); - if (rc) - return rc; - - if (stat(_PATH_SYS_BLOCK, &st) || !S_ISDIR(st.st_mode)) { - lc->flags |= LOOPDEV_FL_NOSYSFS; - lc->flags &= ~LOOPDEV_FL_NOIOCTL; - DBG(lc, loopdev_debug("init: disable /sys usage")); - } - - if (!(lc->flags & LOOPDEV_FL_NOSYSFS) && - get_linux_version() >= KERNEL_VERSION(2,6,37)) { - /* - * Use only sysfs for basic information about loop devices - */ - lc->flags |= LOOPDEV_FL_NOIOCTL; - DBG(lc, loopdev_debug("init: ignore ioctls")); - } - - if (!(lc->flags & LOOPDEV_FL_CONTROL) && !stat(_PATH_DEV_LOOPCTL, &st)) { - lc->flags |= LOOPDEV_FL_CONTROL; - DBG(lc, loopdev_debug("init: loop-control detected ")); - } - - return 0; -} - -/* - * @lc: context - * - * Deinitialize loop context - */ -void loopcxt_deinit(struct loopdev_cxt *lc) -{ - int errsv = errno; - - if (!lc) - return; - - DBG(lc, loopdev_debug("de-initialize")); - - free(lc->filename); - lc->filename = NULL; - - ignore_result( loopcxt_set_device(lc, NULL) ); - loopcxt_deinit_iterator(lc); - - errno = errsv; -} - -/* - * @lc: context - * @enable: TRUE/FALSE - * - * Enabled/disables debug messages - */ -void loopcxt_enable_debug(struct loopdev_cxt *lc, int enable) -{ - if (lc) - lc->debug = enable ? 1 : 0; -} - -/* - * @lc: context - * - * Returns newly allocated device path. - */ -char *loopcxt_strdup_device(struct loopdev_cxt *lc) -{ - if (!lc || !lc->device || !*lc->device) - return NULL; - return strdup(lc->device); -} - -/* - * @lc: context - * - * Returns pointer device name in the @lc struct. - */ -const char *loopcxt_get_device(struct loopdev_cxt *lc) -{ - return lc && lc->device && *lc->device ? lc->device : NULL; -} - -/* - * @lc: context - * - * Returns pointer to the sysfs context (see lib/sysfs.c) - */ -struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc) -{ - if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS)) - return NULL; - - if (!lc->sysfs.devno) { - dev_t devno = sysfs_devname_to_devno(lc->device, NULL); - if (!devno) { - DBG(lc, loopdev_debug("sysfs: failed devname to devno")); - return NULL; - } - if (sysfs_init(&lc->sysfs, devno, NULL)) { - DBG(lc, loopdev_debug("sysfs: init failed")); - return NULL; - } - } - - return &lc->sysfs; -} - -/* - * @lc: context - * - * Returns: file descriptor to the open loop device or <0 on error. The mode - * depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is - * read-only. - */ -int loopcxt_get_fd(struct loopdev_cxt *lc) -{ - if (!lc || !*lc->device) - return -EINVAL; - - if (lc->fd < 0) { - lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY; - lc->fd = open(lc->device, lc->mode); - DBG(lc, loopdev_debug("open %s [%s]: %s", lc->device, - lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro", - lc->fd < 0 ? "failed" : "ok")); - } - return lc->fd; -} - -int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode) -{ - if (!lc) - return -EINVAL; - - lc->fd = fd; - lc->mode = mode; - return 0; -} - -/* - * @lc: context - * @flags: LOOPITER_FL_* flags - * - * Iterator allows to scan list of the free or used loop devices. - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags) -{ - struct loopdev_iter *iter; - struct stat st; - - if (!lc) - return -EINVAL; - - DBG(lc, loopdev_debug("iter: initialize")); - - iter = &lc->iter; - - /* always zeroize - */ - memset(iter, 0, sizeof(*iter)); - iter->ncur = -1; - iter->flags = flags; - iter->default_check = 1; - - if (!lc->extra_check) { - /* - * Check for /dev/loop/<N> subdirectory - */ - if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) && - stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode)) - lc->flags |= LOOPDEV_FL_DEVSUBDIR; - - lc->extra_check = 1; - } - return 0; -} - -/* - * @lc: context - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_deinit_iterator(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter; - - if (!lc) - return -EINVAL; - - DBG(lc, loopdev_debug("iter: de-initialize")); - - iter = &lc->iter; - - free(iter->minors); - if (iter->proc) - fclose(iter->proc); - if (iter->sysblock) - closedir(iter->sysblock); - iter->minors = NULL; - iter->proc = NULL; - iter->sysblock = NULL; - iter->done = 1; - return 0; -} - -/* - * Same as loopcxt_set_device, but also checks if the device is - * associeted with any file. - * - * Returns: <0 on error, 0 on success, 1 device does not match with - * LOOPITER_FL_{USED,FREE} flags. - */ -static int loopiter_set_device(struct loopdev_cxt *lc, const char *device) -{ - int rc = loopcxt_set_device(lc, device); - int used; - - if (rc) - return rc; - - if (!(lc->iter.flags & LOOPITER_FL_USED) && - !(lc->iter.flags & LOOPITER_FL_FREE)) - return 0; /* caller does not care about device status */ - - used = loopcxt_get_offset(lc, NULL) == 0; - - if ((lc->iter.flags & LOOPITER_FL_USED) && used) - return 0; - - if ((lc->iter.flags & LOOPITER_FL_FREE) && !used) - return 0; - - DBG(lc, loopdev_debug("iter: unset device")); - ignore_result( loopcxt_set_device(lc, NULL) ); - return 1; -} - -static int cmpnum(const void *p1, const void *p2) -{ - return (((* (int *) p1) > (* (int *) p2)) - - ((* (int *) p1) < (* (int *) p2))); -} - -/* - * The classic scandir() is more expensive and less portable. - * We needn't full loop device names -- loop numbers (loop<N>) - * are enough. - */ -static int loop_scandir(const char *dirname, int **ary, int hasprefix) -{ - DIR *dir; - struct dirent *d; - unsigned int n, count = 0, arylen = 0; - - if (!dirname || !ary) - return 0; - dir = opendir(dirname); - if (!dir) - return 0; - free(*ary); - *ary = NULL; - - while((d = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN && - d->d_type != DT_LNK) - continue; -#endif - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) - continue; - - if (hasprefix) { - /* /dev/loop<N> */ - if (sscanf(d->d_name, "loop%u", &n) != 1) - continue; - } else { - /* /dev/loop/<N> */ - char *end = NULL; - - n = strtol(d->d_name, &end, 10); - if (d->d_name == end || (end && *end) || errno) - continue; - } - if (n < LOOPDEV_DEFAULT_NNODES) - continue; /* ignore loop<0..7> */ - - if (count + 1 > arylen) { - int *tmp; - - arylen += 1; - - tmp = realloc(*ary, arylen * sizeof(int)); - if (!tmp) { - free(*ary); - closedir(dir); - return -1; - } - *ary = tmp; - } - if (*ary) - (*ary)[count++] = n; - } - if (count && *ary) - qsort(*ary, count, sizeof(int), cmpnum); - - closedir(dir); - return count; -} - -/* - * Set the next *used* loop device according to /proc/partitions. - * - * Loop devices smaller than 512 bytes are invisible for this function. - */ -static int loopcxt_next_from_proc(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter = &lc->iter; - char buf[BUFSIZ]; - - DBG(lc, loopdev_debug("iter: scan /proc/partitions")); - - if (!iter->proc) - iter->proc = fopen(_PATH_PROC_PARTITIONS, "r"); - if (!iter->proc) - return 1; - - while (fgets(buf, sizeof(buf), iter->proc)) { - unsigned int m; - char name[128 + 1]; - - - if (sscanf(buf, " %u %*s %*s %128[^\n ]", - &m, name) != 2 || m != LOOPDEV_MAJOR) - continue; - - DBG(lc, loopdev_debug("iter: check %s", name)); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } - - return 1; -} - -/* - * Set the next *used* loop device according to - * /sys/block/loopN/loop/backing_file (kernel >= 2.6.37 is required). - * - * This is preferred method. - */ -static int loopcxt_next_from_sysfs(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter = &lc->iter; - struct dirent *d; - int fd; - - DBG(lc, loopdev_debug("iter: scan /sys/block")); - - if (!iter->sysblock) - iter->sysblock = opendir(_PATH_SYS_BLOCK); - - if (!iter->sysblock) - return 1; - - fd = dirfd(iter->sysblock); - - while ((d = readdir(iter->sysblock))) { - char name[256]; - struct stat st; - - DBG(lc, loopdev_debug("iter: check %s", d->d_name)); - - if (strcmp(d->d_name, ".") == 0 - || strcmp(d->d_name, "..") == 0 - || strncmp(d->d_name, "loop", 4) != 0) - continue; - - snprintf(name, sizeof(name), "%s/loop/backing_file", d->d_name); - if (fstat_at(fd, _PATH_SYS_BLOCK, name, &st, 0) != 0) - continue; - - if (loopiter_set_device(lc, d->d_name) == 0) - return 0; - } - - return 1; -} - -/* - * @lc: context, has to initialized by loopcxt_init_iterator() - * - * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details - * about the current loop device are available by - * loopcxt_get_{fd,backing_file,device,offset, ...} functions. - */ -int loopcxt_next(struct loopdev_cxt *lc) -{ - struct loopdev_iter *iter; - - if (!lc) - return -EINVAL; - - DBG(lc, loopdev_debug("iter: next")); - - iter = &lc->iter; - if (iter->done) - return 1; - - /* A) Look for used loop devices in /proc/partitions ("losetup -a" only) - */ - if (iter->flags & LOOPITER_FL_USED) { - int rc; - - if (loopcxt_sysfs_available(lc)) - rc = loopcxt_next_from_sysfs(lc); - else - rc = loopcxt_next_from_proc(lc); - if (rc == 0) - return 0; - goto done; - } - - /* B) Classic way, try first eight loop devices (default number - * of loop devices). This is enough for 99% of all cases. - */ - if (iter->default_check) { - DBG(lc, loopdev_debug("iter: next: default check")); - for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES; - iter->ncur++) { - char name[16]; - snprintf(name, sizeof(name), "loop%d", iter->ncur); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } - iter->default_check = 0; - } - - /* C) the worst possibility, scan whole /dev or /dev/loop/<N> - */ - if (!iter->minors) { - DBG(lc, loopdev_debug("iter: next: scan /dev")); - iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ? - loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) : - loop_scandir(_PATH_DEV, &iter->minors, 1); - iter->ncur = -1; - } - for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) { - char name[16]; - snprintf(name, sizeof(name), "loop%d", iter->minors[iter->ncur]); - - if (loopiter_set_device(lc, name) == 0) - return 0; - } -done: - loopcxt_deinit_iterator(lc); - return 1; -} - -/* - * @device: path to device - */ -int is_loopdev(const char *device) -{ - struct stat st; - - if (!device) - return 0; - - return (stat(device, &st) == 0 && - S_ISBLK(st.st_mode) && - major(st.st_rdev) == LOOPDEV_MAJOR); -} - -/* - * @lc: context - * - * Returns result from LOOP_GET_STAT64 ioctl or NULL on error. - */ -struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc) -{ - int fd; - - if (!lc || lc->info_failed) - return NULL; - if (lc->has_info) - return &lc->info; - - fd = loopcxt_get_fd(lc); - if (fd < 0) - return NULL; - - if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) { - lc->has_info = 1; - lc->info_failed = 0; - DBG(lc, loopdev_debug("reading loop_info64 OK")); - return &lc->info; - } else { - lc->info_failed = 1; - DBG(lc, loopdev_debug("reading loop_info64 FAILED")); - } - - return NULL; -} - -/* - * @lc: context - * - * Returns (allocated) string with path to the file assicieted - * with the current loop device. - */ -char *loopcxt_get_backing_file(struct loopdev_cxt *lc) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - char *res = NULL; - - if (sysfs) - /* - * This is always preffered, the loop_info64 - * has too small buffer for the filename. - */ - res = sysfs_strdup(sysfs, "loop/backing_file"); - - if (!res && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - - if (lo) { - lo->lo_file_name[LO_NAME_SIZE - 2] = '*'; - lo->lo_file_name[LO_NAME_SIZE - 1] = '\0'; - res = strdup((char *) lo->lo_file_name); - } - } - - DBG(lc, loopdev_debug("get_backing_file [%s]", res)); - return res; -} - -/* - * @lc: context - * @offset: returns offset number for the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = -EINVAL; - - if (sysfs) - rc = sysfs_read_u64(sysfs, "loop/offset", offset); - - if (rc && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) { - if (offset) - *offset = lo->lo_offset; - rc = 0; - } - } - - DBG(lc, loopdev_debug("get_offset [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @sizelimit: returns size limit for the given device - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - int rc = -EINVAL; - - if (sysfs) - rc = sysfs_read_u64(sysfs, "loop/sizelimit", size); - - if (rc && loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) { - if (size) - *size = lo->lo_sizelimit; - rc = 0; - } - } - - DBG(lc, loopdev_debug("get_sizelimit [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @devno: returns encryption type - * - * Cryptoloop is DEPRECATED! - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc = -EINVAL; - - if (lo) { - if (type) - *type = lo->lo_encrypt_type; - rc = 0; - } - DBG(lc, loopdev_debug("get_encrypt_type [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @devno: returns crypt name - * - * Cryptoloop is DEPRECATED! - * - * Returns: <0 on error, 0 on success - */ -const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - - if (lo) - return (char *) lo->lo_crypt_name; - - DBG(lc, loopdev_debug("get_crypt_name failed")); - return NULL; -} - -/* - * @lc: context - * @devno: returns backing file devno - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc = -EINVAL; - - if (lo) { - if (devno) - *devno = lo->lo_device; - rc = 0; - } - DBG(lc, loopdev_debug("get_backing_devno [rc=%d]", rc)); - return rc; -} - -/* - * @lc: context - * @ino: returns backing file inode - * - * Returns: <0 on error, 0 on success - */ -int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino) -{ - struct loop_info64 *lo = loopcxt_get_info(lc); - int rc = -EINVAL; - - if (lo) { - if (ino) - *ino = lo->lo_inode; - rc = 0; - } - DBG(lc, loopdev_debug("get_backing_inode [rc=%d]", rc)); - return rc; -} - -/* - * Check if the kernel supports partitioned loop devices. - * - * Notes: - * - kernels < 3.2 support partitioned loop devices and PT scanning - * only if max_part= module paremeter is non-zero - * - * - kernels >= 3.2 always support partitioned loop devices - * - * - kernels >= 3.2 always support BLKPG_{ADD,DEL}_PARTITION ioctls - * - * - kernels >= 3.2 enable PT scanner only if max_part= is non-zero or if the - * LO_FLAGS_PARTSCAN flag is set for the device. The PT scanner is disabled - * by default. - * - * See kernel commit e03c8dd14915fabc101aa495828d58598dc5af98. - */ -int loopmod_supports_partscan(void) -{ - int rc, ret = 0; - FILE *f; - - if (get_linux_version() >= KERNEL_VERSION(3,2,0)) - return 1; - - f = fopen("/sys/module/loop/parameters/max_part", "r"); - if (!f) - return 0; - rc = fscanf(f, "%d", &ret); - fclose(f); - return rc == 1 ? ret : 0; -} - -/* - * @lc: context - * - * Returns: 1 if the partscan flags is set *or* (for old kernels) partitions - * scannig is enabled for all loop devices. - */ -int loopcxt_is_partscan(struct loopdev_cxt *lc) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - /* kernel >= 3.2 */ - int fl; - if (sysfs_read_int(sysfs, "loop/partscan", &fl) == 0) - return fl; - } - - /* old kernels (including kernels without loopN/loop/<flags> directory */ - return loopmod_supports_partscan(); -} - -/* - * @lc: context - * - * Returns: 1 if the autoclear flags is set. - */ -int loopcxt_is_autoclear(struct loopdev_cxt *lc) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - int fl; - if (sysfs_read_int(sysfs, "loop/autoclear", &fl) == 0) - return fl; - } - - if (loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - return lo->lo_flags & LO_FLAGS_AUTOCLEAR; - } - return 0; -} - -/* - * @lc: context - * - * Returns: 1 if the readonly flags is set. - */ -int loopcxt_is_readonly(struct loopdev_cxt *lc) -{ - struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc); - - if (sysfs) { - int fl; - if (sysfs_read_int(sysfs, "ro", &fl) == 0) - return fl; - } - - if (loopcxt_ioctl_enabled(lc)) { - struct loop_info64 *lo = loopcxt_get_info(lc); - if (lo) - return lo->lo_flags & LO_FLAGS_READ_ONLY; - } - return 0; -} - -/* - * @lc: context - * @st: backing file stat or NULL - * @backing_file: filename - * @offset: offset - * @flags: LOOPDEV_FL_OFFSET if @offset should not be ignored - * - * Returns 1 if the current @lc loopdev is associated with the given backing - * file. Note that the preferred way is to use devno and inode number rather - * than filename. The @backing_file filename is poor solution usable in case - * that you don't have rights to call stat(). - * - * Don't forget that old kernels provide very restricted (in size) backing - * filename by LOOP_GET_STAT64 ioctl only. - */ -int loopcxt_is_used(struct loopdev_cxt *lc, - struct stat *st, - const char *backing_file, - uint64_t offset, - int flags) -{ - ino_t ino; - dev_t dev; - - if (!lc) - return 0; - - DBG(lc, loopdev_debug("checking %s vs. %s", - loopcxt_get_device(lc), - backing_file)); - - if (st && loopcxt_get_backing_inode(lc, &ino) == 0 && - loopcxt_get_backing_devno(lc, &dev) == 0) { - - if (ino == st->st_ino && dev == st->st_dev) - goto found; - - /* don't use filename if we have devno and inode */ - return 0; - } - - /* poor man's solution */ - if (backing_file) { - char *name = loopcxt_get_backing_file(lc); - int rc = name && strcmp(name, backing_file) == 0; - - free(name); - if (rc) - goto found; - } - - return 0; -found: - if (flags & LOOPDEV_FL_OFFSET) { - uint64_t off; - - return loopcxt_get_offset(lc, &off) == 0 && off == offset; - } - return 1; -} - -/* - * The setting is removed by loopcxt_set_device() loopcxt_next()! - */ -int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset) -{ - if (!lc) - return -EINVAL; - lc->info.lo_offset = offset; - - DBG(lc, loopdev_debug("set offset=%jd", offset)); - return 0; -} - -/* - * The setting is removed by loopcxt_set_device() loopcxt_next()! - */ -int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit) -{ - if (!lc) - return -EINVAL; - lc->info.lo_sizelimit = sizelimit; - - DBG(lc, loopdev_debug("set sizelimit=%jd", sizelimit)); - return 0; -} - -/* - * @lc: context - * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - * - * Returns: 0 on success, <0 on error. - */ -int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags) -{ - if (!lc) - return -EINVAL; - lc->info.lo_flags = flags; - - DBG(lc, loopdev_debug("set flags=%u", (unsigned) flags)); - return 0; -} - -/* - * @lc: context - * @filename: backing file path (the path will be canonicalized) - * - * The setting is removed by loopcxt_set_device() loopcxt_next()! - * - * Returns: 0 on success, <0 on error. - */ -int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename) -{ - if (!lc) - return -EINVAL; - - lc->filename = canonicalize_path(filename); - if (!lc->filename) - return -errno; - - strncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE); - lc->info.lo_file_name[LO_NAME_SIZE- 1] = '\0'; - - DBG(lc, loopdev_debug("set backing file=%s", lc->info.lo_file_name)); - return 0; -} - -/* - * @cl: context - * - * Associate the current device (see loopcxt_{set,get}_device()) with - * a file (see loopcxt_set_backing_file()). - * - * The device is initialized read-write by default. If you want read-only - * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_* - * flags are ignored and modified according to LO_FLAGS_*. - * - * If the device is already open by loopcxt_get_fd() then this setup device - * function will re-open the device to fix read/write mode. - * - * The device is also initialized read-only if the backing file is not - * possible to open read-write (e.g. read-only FS). - * - * Returns: <0 on error, 0 on success. - */ -int loopcxt_setup_device(struct loopdev_cxt *lc) -{ - int file_fd, dev_fd, mode = O_RDWR, rc = -1; - - if (!lc || !*lc->device || !lc->filename) - return -EINVAL; - - DBG(lc, loopdev_debug("device setup requested")); - - /* - * Open backing file and device - */ - if (lc->info.lo_flags & LO_FLAGS_READ_ONLY) - mode = O_RDONLY; - - if ((file_fd = open(lc->filename, mode)) < 0) { - if (mode != O_RDONLY && (errno == EROFS || errno == EACCES)) - file_fd = open(lc->filename, mode = O_RDONLY); - - if (file_fd < 0) { - DBG(lc, loopdev_debug("open backing file failed: %m")); - return -errno; - } - } - DBG(lc, loopdev_debug("setup: backing file open: OK")); - - if (lc->fd != -1 && lc->mode != mode) { - DBG(lc, loopdev_debug("closing already open device (mode mismatch)")); - close(lc->fd); - lc->fd = -1; - lc->mode = 0; - } - - if (mode == O_RDONLY) { - lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */ - lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */ - } else { - lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */ - lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY; - lc->flags &= ~LOOPDEV_FL_RDONLY; - } - - dev_fd = loopcxt_get_fd(lc); - if (dev_fd < 0) { - rc = -errno; - goto err; - } - - DBG(lc, loopdev_debug("setup: device open: OK")); - - /* - * Set FD - */ - if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) { - rc = -errno; - DBG(lc, loopdev_debug("LOOP_SET_FD failed: %m")); - goto err; - } - - DBG(lc, loopdev_debug("setup: LOOP_SET_FD: OK")); - - close(file_fd); - file_fd = -1; - - if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) { - DBG(lc, loopdev_debug("LOOP_SET_STATUS64 failed: %m")); - goto err; - } - - DBG(lc, loopdev_debug("setup: LOOP_SET_STATUS64: OK")); - - memset(&lc->info, 0, sizeof(lc->info)); - lc->has_info = 0; - lc->info_failed = 0; - - DBG(lc, loopdev_debug("setup success [rc=0]")); - return 0; -err: - if (file_fd >= 0) - close(file_fd); - if (dev_fd >= 0) - ioctl(dev_fd, LOOP_CLR_FD, 0); - - DBG(lc, loopdev_debug("setup failed [rc=%d]", rc)); - return rc; -} - -int loopcxt_delete_device(struct loopdev_cxt *lc) -{ - int fd = loopcxt_get_fd(lc); - - if (fd < 0) - return -EINVAL; - - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - DBG(lc, loopdev_debug("LOOP_CLR_FD failed: %m")); - return -errno; - } - - DBG(lc, loopdev_debug("device removed")); - return 0; -} - -/* - * Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older - * kernels we have to check all loop devices to found unused one. - * - * See kernel commit 770fe30a46a12b6fb6b63fbe1737654d28e8484. - */ -int loopcxt_find_unused(struct loopdev_cxt *lc) -{ - int rc = -1; - - DBG(lc, loopdev_debug("find_unused requested")); - - if (lc->flags & LOOPDEV_FL_CONTROL) { - int ctl = open(_PATH_DEV_LOOPCTL, O_RDWR); - - if (ctl >= 0) - rc = ioctl(ctl, LOOP_CTL_GET_FREE); - if (rc >= 0) { - char name[16]; - snprintf(name, sizeof(name), "loop%d", rc); - - rc = loopiter_set_device(lc, name); - } - if (ctl >= 0) - close(ctl); - DBG(lc, loopdev_debug("find_unused by loop-control [rc=%d]", rc)); - } - - if (rc < 0) { - rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE); - if (rc) - return rc; - - rc = loopcxt_next(lc); - loopcxt_deinit_iterator(lc); - DBG(lc, loopdev_debug("find_unused by scan [rc=%d]", rc)); - } - return rc; -} - - - -/* - * Return: TRUE/FALSE - */ -int loopdev_is_autoclear(const char *device) -{ - struct loopdev_cxt lc; - int rc; - - if (!device) - return 0; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (!rc) - rc = loopcxt_is_autoclear(&lc); - - loopcxt_deinit(&lc); - return rc; -} - -char *loopdev_get_backing_file(const char *device) -{ - struct loopdev_cxt lc; - char *res = NULL; - - if (!device) - return NULL; - if (loopcxt_init(&lc, 0)) - return NULL; - if (loopcxt_set_device(&lc, device) == 0) - res = loopcxt_get_backing_file(&lc); - - loopcxt_deinit(&lc); - return res; -} - -/* - * Returns: TRUE/FALSE - */ -int loopdev_is_used(const char *device, const char *filename, - uint64_t offset, int flags) -{ - struct loopdev_cxt lc; - struct stat st; - int rc = 0; - - if (!device || !filename) - return 0; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (rc) - return rc; - - rc = !stat(filename, &st); - rc = loopcxt_is_used(&lc, rc ? &st : NULL, filename, offset, flags); - - loopcxt_deinit(&lc); - return rc; -} - -int loopdev_delete(const char *device) -{ - struct loopdev_cxt lc; - int rc; - - if (!device) - return -EINVAL; - - rc = loopcxt_init(&lc, 0); - if (!rc) - rc = loopcxt_set_device(&lc, device); - if (!rc) - rc = loopcxt_delete_device(&lc); - loopcxt_deinit(&lc); - return rc; -} - -/* - * Returns: 0 = success, < 0 error, 1 not found - */ -int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename, - uint64_t offset, int flags) -{ - int rc, hasst; - struct stat st; - - if (!filename) - return -EINVAL; - - hasst = !stat(filename, &st); - - rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED); - if (rc) - return rc; - - while ((rc = loopcxt_next(lc)) == 0) { - - if (loopcxt_is_used(lc, hasst ? &st : NULL, - filename, offset, flags)) - break; - } - - loopcxt_deinit_iterator(lc); - return rc; -} - -/* - * Returns allocated string with device name - */ -char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, int flags) -{ - struct loopdev_cxt lc; - char *res = NULL; - - if (!filename) - return NULL; - - if (loopcxt_init(&lc, 0)) - return NULL; - if (loopcxt_find_by_backing_file(&lc, filename, offset, flags) == 0) - res = loopcxt_strdup_device(&lc); - loopcxt_deinit(&lc); - - return res; -} - -/* - * Returns number of loop devices associated with @file, if only one loop - * device is associeted with the given @filename and @loopdev is not NULL then - * @loopdev returns name of the device. - */ -int loopdev_count_by_backing_file(const char *filename, char **loopdev) -{ - struct loopdev_cxt lc; - int count = 0, rc; - - if (!filename) - return -1; - - rc = loopcxt_init(&lc, 0); - if (rc) - return rc; - if (loopcxt_init_iterator(&lc, LOOPITER_FL_USED)) - return -1; - - while(loopcxt_next(&lc) == 0) { - char *backing = loopcxt_get_backing_file(&lc); - - if (!backing || strcmp(backing, filename)) { - free(backing); - continue; - } - - free(backing); - if (loopdev && count == 0) - *loopdev = loopcxt_strdup_device(&lc); - count++; - } - - loopcxt_deinit(&lc); - - if (loopdev && count > 1) { - free(*loopdev); - *loopdev = NULL; - } - return count; -} - - -#ifdef TEST_PROGRAM_LOOPDEV -#include <errno.h> -#include <err.h> - -static void test_loop_info(const char *device, int flags, int debug) -{ - struct loopdev_cxt lc; - char *p; - uint64_t u64; - - if (loopcxt_init(&lc, flags)) - return; - loopcxt_enable_debug(&lc, debug); - - if (loopcxt_set_device(&lc, device)) - err(EXIT_FAILURE, "failed to set device"); - - p = loopcxt_get_backing_file(&lc); - printf("\tBACKING FILE: %s\n", p); - free(p); - - if (loopcxt_get_offset(&lc, &u64) == 0) - printf("\tOFFSET: %jd\n", u64); - - if (loopcxt_get_sizelimit(&lc, &u64) == 0) - printf("\tSIZE LIMIT: %jd\n", u64); - - printf("\tAUTOCLEAR: %s\n", loopcxt_is_autoclear(&lc) ? "YES" : "NOT"); - - loopcxt_deinit(&lc); -} - -static void test_loop_scan(int flags, int debug) -{ - struct loopdev_cxt lc; - int rc; - - if (loopcxt_init(&lc, 0)) - return; - loopcxt_enable_debug(&lc, debug); - - if (loopcxt_init_iterator(&lc, flags)) - err(EXIT_FAILURE, "iterator initlization failed"); - - while((rc = loopcxt_next(&lc)) == 0) { - const char *device = loopcxt_get_device(&lc); - - if (flags & LOOPITER_FL_USED) { - char *backing = loopcxt_get_backing_file(&lc); - printf("\t%s: %s\n", device, backing); - free(backing); - } else - printf("\t%s\n", device); - } - - if (rc < 0) - err(EXIT_FAILURE, "loopdevs scanning failed"); - - loopcxt_deinit(&lc); -} - -static int test_loop_setup(const char *filename, const char *device, int debug) -{ - struct loopdev_cxt lc; - int rc; - - rc = loopcxt_init(&lc, 0); - if (rc) - return rc; - loopcxt_enable_debug(&lc, debug); - - if (device) { - rc = loopcxt_set_device(&lc, device); - if (rc) - err(EXIT_FAILURE, "failed to set device: %s", device); - } - - do { - if (!device) { - rc = loopcxt_find_unused(&lc); - if (rc) - err(EXIT_FAILURE, "failed to find unused device"); - printf("Trying to use '%s'\n", loopcxt_get_device(&lc)); - } - - if (loopcxt_set_backing_file(&lc, filename)) - err(EXIT_FAILURE, "failed to set backing file"); - - rc = loopcxt_setup_device(&lc); - if (rc == 0) - break; /* success */ - - if (device || rc != -EBUSY) - err(EXIT_FAILURE, "failed to setup device for %s", - lc.filename); - - printf("device stolen...trying again\n"); - } while (1); - - loopcxt_deinit(&lc); - - return 0; -} - -int main(int argc, char *argv[]) -{ - int dbg; - - if (argc < 2) - goto usage; - - dbg = getenv("LOOPDEV_DEBUG") == NULL ? 0 : 1; - - if (argc == 3 && strcmp(argv[1], "--info") == 0) { - printf("---sysfs & ioctl:---\n"); - test_loop_info(argv[2], 0, dbg); - printf("---sysfs only:---\n"); - test_loop_info(argv[2], LOOPDEV_FL_NOIOCTL, dbg); - printf("---ioctl only:---\n"); - test_loop_info(argv[2], LOOPDEV_FL_NOSYSFS, dbg); - - } else if (argc == 2 && strcmp(argv[1], "--used") == 0) { - printf("---all used devices---\n"); - test_loop_scan(LOOPITER_FL_USED, dbg); - - } else if (argc == 2 && strcmp(argv[1], "--free") == 0) { - printf("---all free devices---\n"); - test_loop_scan(LOOPITER_FL_FREE, dbg); - - } else if (argc >= 3 && strcmp(argv[1], "--setup") == 0) { - test_loop_setup(argv[2], argv[3], dbg); - - } else if (argc == 3 && strcmp(argv[1], "--delete") == 0) { - if (loopdev_delete(argv[2])) - errx(EXIT_FAILURE, "failed to deinitialize device %s", argv[2]); - } else - goto usage; - - return EXIT_SUCCESS; - -usage: - errx(EXIT_FAILURE, "usage: \n" - " %1$s --info <device>\n" - " %1$s --free\n" - " %1$s --used\n" - " %1$s --setup <filename> [<device>]\n" - " %1$s --delete\n", - argv[0]); -} - -#endif /* TEST_PROGRAM */ diff --git a/libblkid/loopdev.h b/libblkid/loopdev.h deleted file mode 100644 index 6efa0c78f..000000000 --- a/libblkid/loopdev.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef UTIL_LINUX_LOOPDEV_H -#define UTIL_LINUX_LOOPDEV_H - -#include "sysfs.h" - -/* - * loop_info.lo_encrypt_type - */ -#define LO_CRYPT_NONE 0 -#define LO_CRYPT_XOR 1 -#define LO_CRYPT_DES 2 -#define LO_CRYPT_CRYPTOAPI 18 - -#define LOOP_SET_FD 0x4C00 -#define LOOP_CLR_FD 0x4C01 -/* - * Obsolete (kernel < 2.6) - * - * #define LOOP_SET_STATUS 0x4C02 - * #define LOOP_GET_STATUS 0x4C03 - */ -#define LOOP_SET_STATUS64 0x4C04 -#define LOOP_GET_STATUS64 0x4C05 -/* #define LOOP_CHANGE_FD 0x4C06 */ -#define LOOP_SET_CAPACITY 0x4C07 - -/* /dev/loop-control interface */ -#ifndef LOOP_CTL_ADD -# define LOOP_CTL_ADD 0x4C80 -# define LOOP_CTL_REMOVE 0x4C81 -# define LOOP_CTL_GET_FREE 0x4C82 -#endif - -/* - * loop_info.lo_flags - */ -enum { - LO_FLAGS_READ_ONLY = 1, - LO_FLAGS_USE_AOPS = 2, - LO_FLAGS_AUTOCLEAR = 4, /* kernel >= 2.6.25 */ - LO_FLAGS_PARTSCAN = 8, /* kernel >= 3.2 */ -}; - -#define LO_NAME_SIZE 64 -#define LO_KEY_SIZE 32 - -/* - * Linux LOOP_{SET,GET}_STATUS64 ioclt struct - */ -struct loop_info64 { - uint64_t lo_device; - uint64_t lo_inode; - uint64_t lo_rdevice; - uint64_t lo_offset; - uint64_t lo_sizelimit; /* bytes, 0 == max available */ - uint32_t lo_number; - uint32_t lo_encrypt_type; - uint32_t lo_encrypt_key_size; - uint32_t lo_flags; - uint8_t lo_file_name[LO_NAME_SIZE]; - uint8_t lo_crypt_name[LO_NAME_SIZE]; - uint8_t lo_encrypt_key[LO_KEY_SIZE]; - uint64_t lo_init[2]; -}; - -#define LOOPDEV_MAJOR 7 /* loop major number */ -#define LOOPDEV_DEFAULT_NNODES 8 /* default number of loop devices */ - -struct loopdev_iter { - FILE *proc; /* /proc/partitions */ - DIR *sysblock; /* /sys/block */ - int ncur; /* current position */ - int *minors; /* ary of minor numbers (when scan whole /dev) */ - int nminors; /* number of items in *minors */ - int ct_perm; /* count permission problems */ - int ct_succ; /* count number of detected devices */ - - unsigned int done:1; /* scanning done */ - unsigned int default_check:1;/* check first LOOPDEV_NLOOPS */ - int flags; /* LOOPITER_FL_* flags */ -}; - -enum { - LOOPITER_FL_FREE = (1 << 0), - LOOPITER_FL_USED = (1 << 1) -}; - -/* - * handler for work with loop devices - */ -struct loopdev_cxt { - char device[128]; /* device path (e.g. /dev/loop<N>) */ - char *filename; /* backing file for loopcxt_set_... */ - int fd; /* open(/dev/looo<N>) */ - int mode; /* fd mode O_{RDONLY,RDWR} */ - - int flags; /* LOOPDEV_FL_* flags */ - unsigned int has_info:1; /* .info contains data */ - unsigned int extra_check:1; /* unusual stuff for iterator */ - unsigned int debug:1; /* debug mode ON/OFF */ - unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */ - - struct sysfs_cxt sysfs; /* pointer to /sys/dev/block/<maj:min>/ */ - struct loop_info64 info; /* for GET/SET ioctl */ - struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */ -}; - -#define UL_LOOPDEVCXT_EMPTY { .fd = -1, .sysfs = UL_SYSFSCXT_EMPTY } - -/* - * loopdev_cxt.flags - */ -enum { - LOOPDEV_FL_RDONLY = (1 << 0), /* open(/dev/loop) mode; default */ - LOOPDEV_FL_RDWR = (1 << 1), /* necessary for loop setup only */ - LOOPDEV_FL_OFFSET = (1 << 4), - LOOPDEV_FL_NOSYSFS = (1 << 5), - LOOPDEV_FL_NOIOCTL = (1 << 6), - LOOPDEV_FL_DEVSUBDIR = (1 << 7), - LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */ - LOOPDEV_FL_SIZELIMIT = (1 << 9) -}; - -/* - * High-level - */ -extern int loopmod_supports_partscan(void); - -extern int is_loopdev(const char *device); -extern int loopdev_is_autoclear(const char *device); - -extern char *loopdev_get_backing_file(const char *device); -extern int loopdev_is_used(const char *device, const char *filename, - uint64_t offset, int flags); -extern char *loopdev_find_by_backing_file(const char *filename, - uint64_t offset, int flags); -extern int loopcxt_find_unused(struct loopdev_cxt *lc); -extern int loopdev_delete(const char *device); -extern int loopdev_count_by_backing_file(const char *filename, char **loopdev); - -/* - * Low-level - */ -extern int loopcxt_init(struct loopdev_cxt *lc, int flags) - __attribute__ ((warn_unused_result)); -extern void loopcxt_deinit(struct loopdev_cxt *lc); -extern void loopcxt_enable_debug(struct loopdev_cxt *lc, int enable); - -extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) - __attribute__ ((warn_unused_result)); -extern int loopcxt_has_device(struct loopdev_cxt *lc); -extern char *loopcxt_strdup_device(struct loopdev_cxt *lc); -extern const char *loopcxt_get_device(struct loopdev_cxt *lc); -extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc); -extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc); - -extern int loopcxt_get_fd(struct loopdev_cxt *lc); -extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode); - -extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags); -extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc); -extern int loopcxt_next(struct loopdev_cxt *lc); - -extern int loopcxt_setup_device(struct loopdev_cxt *lc); -extern int loopcxt_delete_device(struct loopdev_cxt *lc); - -int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset); -int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit); -int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags); -int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename); - -extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc); -extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno); -extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino); -extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); -extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size); -extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type); -extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc); -extern int loopcxt_is_autoclear(struct loopdev_cxt *lc); -extern int loopcxt_is_readonly(struct loopdev_cxt *lc); -extern int loopcxt_is_partscan(struct loopdev_cxt *lc); -extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, - const char *filename, - uint64_t offset, int flags); - -extern int loopcxt_is_used(struct loopdev_cxt *lc, - struct stat *st, - const char *backing_file, - uint64_t offset, - int flags); - -#endif /* UTIL_LINUX_LOOPDEV_H */ diff --git a/libblkid/lsi_raid.c b/libblkid/lsi_raid.c deleted file mode 100644 index 56721dd71..000000000 --- a/libblkid/lsi_raid.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct lsi_metadata { - uint8_t sig[6]; -}; - - -#define LSI_SIGNATURE "$XIDE$" - -static int probe_lsiraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct lsi_metadata *lsi; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 1) * 0x200; - lsi = (struct lsi_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct lsi_metadata)); - if (!lsi) - return -1; - - if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig), - (unsigned char *) lsi->sig)) - return -1; - return 0; -} - -const struct blkid_idinfo lsiraid_idinfo = { - .name = "lsi_mega_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_lsiraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/luks.c b/libblkid/luks.c deleted file mode 100644 index f716e31c3..000000000 --- a/libblkid/luks.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -#define LUKS_CIPHERNAME_L 32 -#define LUKS_CIPHERMODE_L 32 -#define LUKS_HASHSPEC_L 32 -#define LUKS_DIGESTSIZE 20 -#define LUKS_SALTSIZE 32 -#define LUKS_MAGIC_L 6 -#define UUID_STRING_L 40 - -struct luks_phdr { - uint8_t magic[LUKS_MAGIC_L]; - uint16_t version; - uint8_t cipherName[LUKS_CIPHERNAME_L]; - uint8_t cipherMode[LUKS_CIPHERMODE_L]; - uint8_t hashSpec[LUKS_HASHSPEC_L]; - uint32_t payloadOffset; - uint32_t keyBytes; - uint8_t mkDigest[LUKS_DIGESTSIZE]; - uint8_t mkDigestSalt[LUKS_SALTSIZE]; - uint32_t mkDigestIterations; - uint8_t uuid[UUID_STRING_L]; -} __attribute__((packed)); - -static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct luks_phdr *header; - - header = blkid_probe_get_sb(pr, mag, struct luks_phdr); - if (header == NULL) - return -1; - - blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid, - sizeof(header->uuid)); - blkid_probe_sprintf_version(pr, "%u", be16_to_cpu(header->version)); - return 0; -} - -const struct blkid_idinfo luks_idinfo = -{ - .name = "crypto_LUKS", - .usage = BLKID_USAGE_CRYPTO, - .probefunc = probe_luks, - .magics = - { - { .magic = "LUKS\xba\xbe", .len = 6 }, - { NULL } - } -}; diff --git a/libblkid/lvm1.c b/libblkid/lvm1.c deleted file mode 100644 index 632c42b71..000000000 --- a/libblkid/lvm1.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * lvm topology - * -- this is fallback for old systems where the topology information is not - * exported by sysfs - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <errno.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "topology.h" - -#ifndef LVM_BLK_MAJOR -# define LVM_BLK_MAJOR 58 -#endif - -static int is_lvm_device(dev_t devno) -{ - if (major(devno) == LVM_BLK_MAJOR) - return 1; - return blkid_driver_has_major("lvm", major(devno)); -} - -static int probe_lvm_tp(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - const char *paths[] = { - "/usr/local/sbin/lvdisplay", - "/usr/sbin/lvdisplay", - "/sbin/lvdisplay" - }; - int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0; - FILE *stream = NULL; - char *cmd = NULL, *devname = NULL, buf[1024]; - size_t i; - dev_t devno = blkid_probe_get_devno(pr); - - if (!devno) - goto nothing; /* probably not a block device */ - if (!is_lvm_device(devno)) - goto nothing; - - for (i = 0; i < ARRAY_SIZE(paths); i++) { - struct stat sb; - if (stat(paths[i], &sb) == 0) { - cmd = (char *) paths[i]; - break; - } - } - - if (!cmd) - goto nothing; - - devname = blkid_devno_to_devname(devno); - if (!devname) - goto nothing; - - if (pipe(lvpipe) < 0) { - DBG(DEBUG_LOWPROBE, - printf("Failed to open pipe: errno=%d", errno)); - goto nothing; - } - - switch (fork()) { - case 0: - { - char *lvargv[3]; - - /* Plumbing */ - close(lvpipe[0]); - - if (lvpipe[1] != STDOUT_FILENO) - dup2(lvpipe[1], STDOUT_FILENO); - - /* The libblkid library could linked with setuid programs */ - if (setgid(getgid()) < 0) - exit(1); - if (setuid(getuid()) < 0) - exit(1); - - lvargv[0] = cmd; - lvargv[1] = devname; - lvargv[2] = NULL; - - execv(lvargv[0], lvargv); - - DBG(DEBUG_LOWPROBE, - printf("Failed to execute %s: errno=%d", cmd, errno)); - exit(1); - } - case -1: - DBG(DEBUG_LOWPROBE, - printf("Failed to forking: errno=%d", errno)); - goto nothing; - default: - break; - } - - stream = fdopen(lvpipe[0], "r"); - if (!stream) - goto nothing; - - while (fgets(buf, sizeof(buf), stream) != NULL) { - if (!strncmp(buf, "Stripes", 7)) - sscanf(buf, "Stripes %d", &stripes); - - if (!strncmp(buf, "Stripe size", 11)) - sscanf(buf, "Stripe size (KByte) %d", &stripesize); - } - - if (!stripes) - goto nothing; - - blkid_topology_set_minimum_io_size(pr, stripesize << 10); - blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10); - - free(devname); - fclose(stream); - close(lvpipe[1]); - return 0; - -nothing: - free(devname); - if (stream) - fclose(stream); - else if (lvpipe[0] != -1) - close(lvpipe[0]); - if (lvpipe[1] != -1) - close(lvpipe[1]); - return 1; -} - -const struct blkid_idinfo lvm_tp_idinfo = -{ - .name = "lvm", - .probefunc = probe_lvm_tp, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/lvm2.c b/libblkid/lvm2.c deleted file mode 100644 index 0afc77322..000000000 --- a/libblkid/lvm2.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * Copyright (C) 2012 Milan Broz <mbroz@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -#define LVM1_ID_LEN 128 -#define LVM2_ID_LEN 32 - -struct lvm2_pv_label_header { - /* label_header */ - uint8_t id[8]; /* LABELONE */ - uint64_t sector_xl; /* Sector number of this label */ - uint32_t crc_xl; /* From next field to end of sector */ - uint32_t offset_xl; /* Offset from start of struct to contents */ - uint8_t type[8]; /* LVM2 001 */ - /* pv_header */ - uint8_t pv_uuid[LVM2_ID_LEN]; -} __attribute__ ((packed)); - -struct lvm1_pv_label_header { - uint8_t id[2]; /* HM */ - uint16_t version; /* version 1 or 2 */ - uint32_t _notused[10]; /* lvm1 internals */ - uint8_t pv_uuid[LVM1_ID_LEN]; -} __attribute__ ((packed)); - -#define LVM2_LABEL_SIZE 512 -static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) -{ - static const unsigned int crctab[] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c - }; - unsigned int i, crc = 0xf597a6cf; - const uint8_t *data = (const uint8_t *) buf; - - for (i = 0; i < size; i++) { - crc ^= *data++; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - crc = (crc >> 4) ^ crctab[crc & 0xf]; - } - return crc; -} - -/* Length of real UUID is always LVM2_ID_LEN */ -static void format_lvm_uuid(char *dst_uuid, char *src_uuid) -{ - unsigned int i, b; - - for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) { - if (b & 0x4444440) - *dst_uuid++ = '-'; - *dst_uuid++ = *src_uuid++; - } - *dst_uuid = '\0'; -} - -static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) -{ - int sector = mag->kboff << 1; - struct lvm2_pv_label_header *label; - char uuid[LVM2_ID_LEN + 7]; - unsigned char *buf; - - buf = blkid_probe_get_buffer(pr, - mag->kboff << 10, - 512 + sizeof(struct lvm2_pv_label_header)); - if (!buf) - return -1; - - /* buf is at 0k or 1k offset; find label inside */ - if (memcmp(buf, "LABELONE", 8) == 0) { - label = (struct lvm2_pv_label_header *) buf; - } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { - label = (struct lvm2_pv_label_header *)(buf + 512); - sector++; - } else { - return 1; - } - - if (le64_to_cpu(label->sector_xl) != (unsigned) sector) - return 1; - - if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - - ((char *) &label->offset_xl - (char *) label)) != - le32_to_cpu(label->crc_xl)) { - DBG(DEBUG_PROBE, - printf("LVM2: label checksum incorrect at sector %d\n", - sector)); - return 1; - } - - format_lvm_uuid(uuid, (char *) label->pv_uuid); - blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), - "%s", uuid); - - /* the mag->magic is the same string as label->type, - * but zero terminated */ - blkid_probe_set_version(pr, mag->magic); - - /* LVM (pvcreate) wipes begin of the device -- let's remember this - * to resolve conflicts bettween LVM and partition tables, ... - */ - blkid_probe_set_wiper(pr, 0, 8 * 1024); - - return 0; -} - -static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct lvm1_pv_label_header *label; - char uuid[LVM2_ID_LEN + 7]; - unsigned int version; - - label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); - if (!label) - return -1; - - version = le16_to_cpu(label->version); - if (version != 1 && version != 2) - return 1; - - format_lvm_uuid(uuid, (char *) label->pv_uuid); - blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), - "%s", uuid); - - return 0; -} - -struct verity_sb { - uint8_t signature[8]; /* "verity\0\0" */ - uint32_t version; /* superblock version */ - uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */ - uint8_t uuid[16]; /* UUID of hash device */ - uint8_t algorithm[32];/* hash algorithm name */ - uint32_t data_block_size; /* data block in bytes */ - uint32_t hash_block_size; /* hash block in bytes */ - uint64_t data_blocks; /* number of data blocks */ - uint16_t salt_size; /* salt size */ - uint8_t _pad1[6]; - uint8_t salt[256]; /* salt */ - uint8_t _pad2[168]; -} __attribute__((packed)); - -static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct verity_sb *sb; - unsigned int version; - - sb = blkid_probe_get_sb(pr, mag, struct verity_sb); - if (sb == NULL) - return -1; - - version = le32_to_cpu(sb->version); - if (version != 1) - return 1; - - blkid_probe_set_uuid(pr, sb->uuid); - blkid_probe_sprintf_version(pr, "%u", version); - return 0; -} - -/* NOTE: the original libblkid uses "lvm2pv" as a name */ -const struct blkid_idinfo lvm2_idinfo = -{ - .name = "LVM2_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_lvm2, - .magics = - { - { .magic = "LVM2 001", .len = 8, .sboff = 0x218 }, - { .magic = "LVM2 001", .len = 8, .sboff = 0x018 }, - { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 }, - { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 }, - { NULL } - } -}; - -const struct blkid_idinfo lvm1_idinfo = -{ - .name = "LVM1_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_lvm1, - .magics = - { - { .magic = "HM", .len = 2 }, - { NULL } - } -}; - -const struct blkid_idinfo snapcow_idinfo = -{ - .name = "DM_snapshot_cow", - .usage = BLKID_USAGE_OTHER, - .magics = - { - { .magic = "SnAp", .len = 4 }, - { NULL } - } -}; - -const struct blkid_idinfo verity_hash_idinfo = -{ - .name = "DM_verity_hash", - .usage = BLKID_USAGE_CRYPTO, - .probefunc = probe_verity, - .magics = - { - { .magic = "verity\0\0", .len = 8 }, - { NULL } - } -}; diff --git a/libblkid/mac.c b/libblkid/mac.c deleted file mode 100644 index e18896cba..000000000 --- a/libblkid/mac.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * mac partitions parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -#define MAC_PARTITION_MAGIC 0x504d -#define MAC_PARTITION_MAGIC_OLD 0x5453 - -/* - * Mac partition entry - * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html - */ -struct mac_partition { - uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ - uint16_t reserved; /* reserved */ - uint32_t map_count; /* # blocks in partition map */ - uint32_t start_block; /* absolute starting block # of partition */ - uint32_t block_count; /* number of blocks in partition */ - char name[32]; /* partition name */ - char type[32]; /* string type description */ - uint32_t data_start; /* rel block # of first data block */ - uint32_t data_count; /* number of data blocks */ - uint32_t status; /* partition status bits */ - uint32_t boot_start; /* first logical block of boot code */ - uint32_t boot_size; /* size of boot code, in bytes */ - uint32_t boot_load; /* boot code load address */ - uint32_t boot_load2; /* reserved */ - uint32_t boot_entry; /* boot code entry point */ - uint32_t boot_entry2; /* reserved */ - uint32_t boot_cksum; /* boot code checksum */ - char processor[16]; /* identifies ISA of boot */ - - /* there is more stuff after this that we don't need */ -} __attribute__((packed)); - -/* - * Driver descriptor structure, in block 0 - * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html - */ -struct mac_driver_desc { - uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */ - uint16_t block_size; /* block size of the device */ - uint32_t block_count; /* number of blocks on the device */ - - /* there is more stuff after this that we don't need */ -} __attribute__((packed)); - -static inline unsigned char *get_mac_block( - blkid_probe pr, - uint16_t block_size, - uint32_t num) -{ - return blkid_probe_get_buffer(pr, - (blkid_loff_t) num * block_size, block_size); -} - -static inline int has_part_signature(struct mac_partition *p) -{ - return be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC || - be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD; -} - -static int probe_mac_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct mac_driver_desc *md; - struct mac_partition *p; - blkid_parttable tab = NULL; - blkid_partlist ls; - uint16_t block_size; - uint16_t ssf; /* sector size fragment */ - uint32_t nblks, i; - - - /* The driver descriptor record is always located at physical block 0, - * the first block on the disk. - */ - md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0); - if (!md) - goto nothing; - - block_size = be16_to_cpu(md->block_size); - - /* The partition map always begins at physical block 1, - * the second block on the disk. - */ - p = (struct mac_partition *) get_mac_block(pr, block_size, 1); - if (!p) - goto nothing; - - /* check the first partition signature */ - if (!has_part_signature(p)) - goto nothing; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "mac", 0); - if (!tab) - goto err; - - ssf = block_size / 512; - nblks = be32_to_cpu(p->map_count); - - for (i = 1; i <= nblks; ++i) { - blkid_partition par; - uint32_t start; - uint32_t size; - - p = (struct mac_partition *) get_mac_block(pr, block_size, i); - if (!p) - goto nothing; - if (!has_part_signature(p)) - goto nothing; - - if (be32_to_cpu(p->map_count) != nblks) { - DBG(DEBUG_LOWPROBE, printf( - "mac: inconsisten map_count in partition map, " - "entry[0]: %d, entry[%d]: %d\n", - nblks, i - 1, - be32_to_cpu(p->map_count))); - } - - /* - * note that libparted ignores some mac partitions according to - * the partition name (e.g. "Apple_Free" or "Apple_Void"). We - * follows Linux kernel and all partitions are visible - */ - - start = be32_to_cpu(p->start_block) * ssf; - size = be32_to_cpu(p->block_count) * ssf; - - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_name(par, (unsigned char *) p->name, - sizeof(p->name)); - - blkid_partition_set_type_string(par, (unsigned char *) p->type, - sizeof(p->type)); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - -/* - * Mac disk always begin with "Driver Descriptor Record" - * (struct mac_driver_desc) and magic 0x4552. - */ -const struct blkid_idinfo mac_pt_idinfo = -{ - .name = "mac", - .probefunc = probe_mac_pt, - .magics = - { - /* big-endian magic string */ - { .magic = "\x45\x52", .len = 2 }, - { NULL } - } -}; - diff --git a/libblkid/mbsalign.c b/libblkid/mbsalign.c deleted file mode 100644 index ea6851f29..000000000 --- a/libblkid/mbsalign.c +++ /dev/null @@ -1,291 +0,0 @@ -/* Align/Truncate a string in a given screen width - Copyright (C) 2009-2010 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -/* Written by Pádraig Brady. */ - -#include <config.h> - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stdbool.h> -#include <limits.h> - -#include "c.h" -#include "mbsalign.h" -#include "widechar.h" - - -#ifdef HAVE_WIDECHAR -/* Replace non printable chars. - Note \t and \n etc. are non printable. - Return 1 if replacement made, 0 otherwise. */ - -static bool -wc_ensure_printable (wchar_t *wchars) -{ - bool replaced = false; - wchar_t *wc = wchars; - while (*wc) - { - if (!iswprint ((wint_t) *wc)) - { - *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ - replaced = true; - } - wc++; - } - return replaced; -} - -/* Truncate wchar string to width cells. - * Returns number of cells used. */ - -static size_t -wc_truncate (wchar_t *wc, size_t width) -{ - size_t cells = 0; - int next_cells = 0; - - while (*wc) - { - next_cells = wcwidth (*wc); - if (next_cells == -1) /* non printable */ - { - *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */ - next_cells = 1; - } - if (cells + next_cells > width) - break; - cells += next_cells; - wc++; - } - *wc = L'\0'; - return cells; -} - -/* FIXME: move this function to gnulib as it's missing on: - OpenBSD 3.8, IRIX 5.3, Solaris 2.5.1, mingw, BeOS */ - -static int -rpl_wcswidth (const wchar_t *s, size_t n) -{ - int ret = 0; - - while (n-- > 0 && *s != L'\0') - { - int nwidth = wcwidth (*s++); - if (nwidth == -1) /* non printable */ - return -1; - if (ret > (INT_MAX - nwidth)) /* overflow */ - return -1; - ret += nwidth; - } - - return ret; -} -#endif - -/* Truncate multi-byte string to @width and returns number of - * bytes of the new string @str, and in @width returns number - * of cells. - */ -size_t -mbs_truncate(char *str, size_t *width) -{ - ssize_t bytes = strlen(str); -#ifdef HAVE_WIDECHAR - ssize_t sz = mbstowcs(NULL, str, 0); - wchar_t *wcs = NULL; - - if (sz == (ssize_t) -1) - goto done; - - wcs = malloc((sz + 1) * sizeof(wchar_t)); - if (!wcs) - goto done; - - if (!mbstowcs(wcs, str, sz)) - goto done; - *width = wc_truncate(wcs, *width); - bytes = wcstombs(str, wcs, bytes); -done: - free(wcs); -#else - if (*width < bytes) - bytes = *width; -#endif - if (bytes >= 0) - str[bytes] = '\0'; - return bytes; -} - -/* Write N_SPACES space characters to DEST while ensuring - nothing is written beyond DEST_END. A terminating NUL - is always added to DEST. - A pointer to the terminating NUL is returned. */ - -static char* -mbs_align_pad (char *dest, const char* dest_end, size_t n_spaces) -{ - /* FIXME: Should we pad with "figure space" (\u2007) - if non ascii data present? */ - while (n_spaces-- && (dest < dest_end)) - *dest++ = ' '; - *dest = '\0'; - return dest; -} - -/* Align a string, SRC, in a field of *WIDTH columns, handling multi-byte - characters; write the result into the DEST_SIZE-byte buffer, DEST. - ALIGNMENT specifies whether to left- or right-justify or to center. - If SRC requires more than *WIDTH columns, truncate it to fit. - When centering, the number of trailing spaces may be one less than the - number of leading spaces. The FLAGS parameter is unused at present. - Return the length in bytes required for the final result, not counting - the trailing NUL. A return value of DEST_SIZE or larger means there - wasn't enough space. DEST will be NUL terminated in any case. - Return (size_t) -1 upon error (invalid multi-byte sequence in SRC, - or malloc failure), unless MBA_UNIBYTE_FALLBACK is specified. - Update *WIDTH to indicate how many columns were used before padding. */ - -size_t -mbsalign (const char *src, char *dest, size_t dest_size, - size_t *width, mbs_align_t align, int flags) -{ - size_t ret = -1; - size_t src_size = strlen (src) + 1; - char *newstr = NULL; - wchar_t *str_wc = NULL; - const char *str_to_print = src; - size_t n_cols = src_size - 1; - size_t n_used_bytes = n_cols; /* Not including NUL */ - size_t n_spaces = 0; - bool conversion = false; - bool wc_enabled = false; - -#ifdef HAVE_WIDECHAR - /* In multi-byte locales convert to wide characters - to allow easy truncation. Also determine number - of screen columns used. */ - if (MB_CUR_MAX > 1) - { - size_t src_chars = mbstowcs (NULL, src, 0); - if (src_chars == (size_t) -1) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - src_chars += 1; /* make space for NUL */ - str_wc = malloc (src_chars * sizeof (wchar_t)); - if (str_wc == NULL) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - if (mbstowcs (str_wc, src, src_chars) != 0) - { - str_wc[src_chars - 1] = L'\0'; - wc_enabled = true; - conversion = wc_ensure_printable (str_wc); - n_cols = rpl_wcswidth (str_wc, src_chars); - } - } - - /* If we transformed or need to truncate the source string - then create a modified copy of it. */ - if (wc_enabled && (conversion || (n_cols > *width))) - { - if (conversion) - { - /* May have increased the size by converting - \t to \uFFFD for example. */ - src_size = wcstombs(NULL, str_wc, 0) + 1; - } - newstr = malloc (src_size); - if (newstr == NULL) - { - if (flags & MBA_UNIBYTE_FALLBACK) - goto mbsalign_unibyte; - else - goto mbsalign_cleanup; - } - str_to_print = newstr; - n_cols = wc_truncate (str_wc, *width); - n_used_bytes = wcstombs (newstr, str_wc, src_size); - } -#endif - -mbsalign_unibyte: - - if (n_cols > *width) /* Unibyte truncation required. */ - { - n_cols = *width; - n_used_bytes = n_cols; - } - - if (*width > n_cols) /* Padding required. */ - n_spaces = *width - n_cols; - - /* indicate to caller how many cells needed (not including padding). */ - *width = n_cols; - - /* indicate to caller how many bytes needed (not including NUL). */ - ret = n_used_bytes + (n_spaces * 1); - - /* Write as much NUL terminated output to DEST as possible. */ - if (dest_size != 0) - { - char *dest_end = dest + dest_size - 1; - size_t start_spaces = n_spaces / 2 + n_spaces % 2; - size_t end_spaces = n_spaces / 2; - - switch (align) - { - case MBS_ALIGN_CENTER: - start_spaces = n_spaces / 2 + n_spaces % 2; - end_spaces = n_spaces / 2; - break; - case MBS_ALIGN_LEFT: - start_spaces = 0; - end_spaces = n_spaces; - break; - case MBS_ALIGN_RIGHT: - start_spaces = n_spaces; - end_spaces = 0; - break; - default: - abort(); - } - - dest = mbs_align_pad (dest, dest_end, start_spaces); - size_t space_left = dest_end - dest; - //dest = mempcpy (dest, str_to_print, min (n_used_bytes, space_left)); - memcpy (dest, str_to_print, min (n_used_bytes, space_left)); - mbs_align_pad (dest, dest_end, end_spaces); - } - -mbsalign_cleanup: - - free (str_wc); - free (newstr); - - return ret; -} diff --git a/libblkid/mbsalign.h b/libblkid/mbsalign.h deleted file mode 100644 index fd957b398..000000000 --- a/libblkid/mbsalign.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Align/Truncate a string in a given screen width - Copyright (C) 2009-2010 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include <stddef.h> - -typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t; - -enum { - /* Use unibyte mode for invalid multibyte strings or - or when heap memory is exhausted. */ - MBA_UNIBYTE_FALLBACK = 0x0001, - -#if 0 /* Other possible options. */ - /* Skip invalid multibyte chars rather than failing */ - MBA_IGNORE_INVALID = 0x0002, - - /* Align multibyte strings using "figure space" (\u2007) */ - MBA_USE_FIGURE_SPACE = 0x0004, - - /* Don't add any padding */ - MBA_TRUNCATE_ONLY = 0x0008, - - /* Don't truncate */ - MBA_PAD_ONLY = 0x0010, -#endif -}; - -extern size_t mbs_truncate(char *str, size_t *width); - -extern size_t mbsalign (const char *src, char *dest, - size_t dest_size, size_t *width, - mbs_align_t align, int flags); diff --git a/libblkid/minix.h b/libblkid/minix.h deleted file mode 100644 index 57be23921..000000000 --- a/libblkid/minix.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef UTIL_LINUX_MINIX_H -#define UTIL_LINUX_MINIX_H - -#include <stdint.h> - -struct minix_inode { - uint16_t i_mode; - uint16_t i_uid; - uint32_t i_size; - uint32_t i_time; - uint8_t i_gid; - uint8_t i_nlinks; - uint16_t i_zone[9]; -}; - -struct minix2_inode { - uint16_t i_mode; - uint16_t i_nlinks; - uint16_t i_uid; - uint16_t i_gid; - uint32_t i_size; - uint32_t i_atime; - uint32_t i_mtime; - uint32_t i_ctime; - uint32_t i_zone[10]; -}; - -struct minix_super_block { - uint16_t s_ninodes; - uint16_t s_nzones; - uint16_t s_imap_blocks; - uint16_t s_zmap_blocks; - uint16_t s_firstdatazone; - uint16_t s_log_zone_size; - uint32_t s_max_size; - uint16_t s_magic; - uint16_t s_state; - uint32_t s_zones; -}; - -/* V3 minix super-block data on disk */ -struct minix3_super_block { - uint32_t s_ninodes; - uint16_t s_pad0; - uint16_t s_imap_blocks; - uint16_t s_zmap_blocks; - uint16_t s_firstdatazone; - uint16_t s_log_zone_size; - uint16_t s_pad1; - uint32_t s_max_size; - uint32_t s_zones; - uint16_t s_magic; - uint16_t s_pad2; - uint16_t s_blocksize; - uint8_t s_disk_version; -}; - -/* - * Minix subpartitions are always within primary dos partition. - */ -#define MINIX_MAXPARTITIONS 4 - -#define MINIX_BLOCK_SIZE_BITS 10 -#define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SIZE_BITS) - -#define MINIX_NAME_MAX 255 /* # chars in a file name */ -#define MINIX_MAX_INODES 65535 - -#define MINIX_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix_inode))) -#define MINIX2_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix2_inode))) - -/* minix_super_block.s_state */ -#define MINIX_VALID_FS 0x0001 /* Clean fs. */ -#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ - -#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ -#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ -#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ -#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ -#define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs (60 char names) */ - -#endif /* UTIL_LINUX_MINIX_H */ diff --git a/libblkid/minix1.c b/libblkid/minix1.c deleted file mode 100644 index 54e71396b..000000000 --- a/libblkid/minix1.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <string.h> -#include "superblocks.h" -#include "minix.h" - -static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag) -{ - unsigned char *ext; - int version; - - /* for more details see magic strings below */ - switch(mag->magic[1]) { - case '\023': - version = 1; - break; - case '\044': - version = 2; - break; - case '\115': - version = 3; - break; - default: - return -1; - break; - } - - if (version <= 2) { - struct minix_super_block *sb; - uint32_t zones; - - sb = blkid_probe_get_sb(pr, mag, struct minix_super_block); - if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) - return -1; - - zones = version == 2 ? sb->s_zones : sb->s_nzones; - - /* sanity checks to be sure that the FS is really minix */ - if (sb->s_imap_blocks * MINIX_BLOCK_SIZE * 8 < sb->s_ninodes + 1) - return -1; - if (sb->s_zmap_blocks * MINIX_BLOCK_SIZE * 8 < zones - sb->s_firstdatazone + 1) - return -1; - - } else if (version == 3) { - struct minix3_super_block *sb; - - sb = blkid_probe_get_sb(pr, mag, struct minix3_super_block); - if (!sb || sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) - return -1; - - } - - /* unfortunately, some parts of ext3 is sometimes possible to - * interpreted as minix superblock. So check for extN magic - * string. (For extN magic string and offsets see ext.c.) - */ - ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2); - if (ext && memcmp(ext, "\123\357", 2) == 0) - return -1; - - blkid_probe_sprintf_version(pr, "%d", version); - return 0; -} - -const struct blkid_idinfo minix_idinfo = -{ - .name = "minix", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_minix, - .magics = - { - /* version 1 */ - { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 }, - { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 }, - - /* version 2 */ - { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 }, - { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 }, - - /* version 3 */ - { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 }, - { NULL } - } -}; - diff --git a/libblkid/minix2.c b/libblkid/minix2.c deleted file mode 100644 index bd57a6d4b..000000000 --- a/libblkid/minix2.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Minix partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" -#include "dos.h" -#include "minix.h" - -static int probe_minix_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct dos_partition *p; - blkid_parttable tab = NULL; - blkid_partition parent; - blkid_partlist ls; - unsigned char *data; - int i; - - data = blkid_probe_get_sector(pr, 0); - if (!data) - goto nothing; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - /* Parent is required, because Minix uses the same PT as DOS and - * difference is only in primary partition (parent) type. - */ - parent = blkid_partlist_get_parent(ls); - if (!parent) - goto nothing; - - if (blkid_partition_get_type(parent) != BLKID_MINIX_PARTITION) - goto nothing; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - p = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET); - - tab = blkid_partlist_new_parttable(ls, "minix", BLKID_MSDOS_PT_OFFSET); - if (!tab) - goto err; - - for (i = 0; i < MINIX_MAXPARTITIONS; i++, p++) { - uint32_t start, size; - blkid_partition par; - - if (p->sys_type != BLKID_MINIX_PARTITION) - continue; - - start = dos_partition_start(p); - size = dos_partition_size(p); - - if (parent && !blkid_is_nested_dimension(parent, start, size)) { - DBG(DEBUG_LOWPROBE, printf( - "WARNING: minix partition (%d) overflow " - "detected, ignore\n", i)); - continue; - } - - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, p->sys_type); - blkid_partition_set_flags(par, p->boot_ind); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - -/* same as DOS */ -const struct blkid_idinfo minix_pt_idinfo = -{ - .name = "minix", - .probefunc = probe_minix_pt, - .magics = - { - { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, - { NULL } - } -}; - diff --git a/libblkid/namespace.h b/libblkid/namespace.h deleted file mode 100644 index 3a219ceba..000000000 --- a/libblkid/namespace.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Compat code so unshare and setns can be used with older libcs */ -#ifndef UTIL_LINUX_NAMESPACE_H -# define UTIL_LINUX_NAMESPACE_H - -# include <sched.h> - -# ifndef CLONE_NEWSNS -# define CLONE_NEWNS 0x00020000 -# endif -# ifndef CLONE_NEWUTS -# define CLONE_NEWUTS 0x04000000 -# endif -# ifndef CLONE_NEWIPC -# define CLONE_NEWIPC 0x08000000 -# endif -# ifndef CLONE_NEWNET -# define CLONE_NEWNET 0x40000000 -# endif -# ifndef CLONE_NEWUSER -# define CLONE_NEWUSER 0x10000000 -# endif -# ifndef CLONE_NEWPID -# define CLONE_NEWPID 0x20000000 -# endif - -# ifndef HAVE_UNSHARE -# include <sys/syscall.h> -static inline int unshare(int flags) -{ - return syscall(SYS_unshare, flags); -} -# endif - -# ifndef HAVE_SETNS -# include <sys/syscall.h> -static inline int setns(int fd, int nstype) -{ - return syscall(SYS_setns, fd, nstype); -} -# endif - -#endif /* UTIL_LINUX_NAMESPACE_H */ diff --git a/libblkid/netware.c b/libblkid/netware.c deleted file mode 100644 index 7ef216254..000000000 --- a/libblkid/netware.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct netware_super_block { - uint8_t SBH_Signature[4]; - uint16_t SBH_VersionMajor; - uint16_t SBH_VersionMinor; - uint16_t SBH_VersionMediaMajor; - uint16_t SBH_VersionMediaMinor; - uint32_t SBH_ItemsMoved; - uint8_t SBH_InternalID[16]; - uint32_t SBH_PackedSize; - uint32_t SBH_Checksum; - uint32_t supersyncid; - int64_t superlocation[4]; - uint32_t physSizeUsed; - uint32_t sizeUsed; - uint32_t superTimeStamp; - uint32_t reserved0[1]; - int64_t SBH_LoggedPoolDataBlk; - int64_t SBH_PoolDataBlk; - uint8_t SBH_OldInternalID[16]; - uint32_t SBH_PoolToLVStartUTC; - uint32_t SBH_PoolToLVEndUTC; - uint16_t SBH_VersionMediaMajorCreate; - uint16_t SBH_VersionMediaMinorCreate; - uint32_t SBH_BlocksMoved; - uint32_t SBH_TempBTSpBlk; - uint32_t SBH_TempFTSpBlk; - uint32_t SBH_TempFTSpBlk1; - uint32_t SBH_TempFTSpBlk2; - uint32_t nssMagicNumber; - uint32_t poolClassID; - uint32_t poolID; - uint32_t createTime; - int64_t SBH_LoggedVolumeDataBlk; - int64_t SBH_VolumeDataBlk; - int64_t SBH_SystemBeastBlkNum; - uint64_t totalblocks; - uint16_t SBH_Name[64]; - uint8_t SBH_VolumeID[16]; - uint8_t SBH_PoolID[16]; - uint8_t SBH_PoolInternalID[16]; - uint64_t SBH_Lsn; - uint32_t SBH_SS_Enabled; - uint32_t SBH_SS_CreateTime; - uint8_t SBH_SS_OriginalPoolID[16]; - uint8_t SBH_SS_OriginalVolumeID[16]; - uint8_t SBH_SS_Guid[16]; - uint16_t SBH_SS_OriginalName[64]; - uint32_t reserved2[64-(2+46)]; -} __attribute__((__packed__)); - -static int probe_netware(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct netware_super_block *nw; - - nw = blkid_probe_get_sb(pr, mag, struct netware_super_block); - if (!nw) - return -1; - - blkid_probe_set_uuid(pr, nw->SBH_PoolID); - - blkid_probe_sprintf_version(pr, "%u.%02u", - le16_to_cpu(nw->SBH_VersionMediaMajor), - le16_to_cpu(nw->SBH_VersionMediaMinor)); - - return 0; -} - -const struct blkid_idinfo netware_idinfo = -{ - .name = "nss", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_netware, - .magics = - { - { .magic = "SPB5", .len = 4, .kboff = 4 }, - { NULL } - } -}; - - diff --git a/libblkid/nilfs.c b/libblkid/nilfs.c deleted file mode 100644 index 1f8f3a69f..000000000 --- a/libblkid/nilfs.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2010 by Jiro SEKIBA <jir@unicus.jp> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License - */ -#include <stddef.h> -#include <string.h> - -#include "superblocks.h" -#include "crc32.h" - -struct nilfs_super_block { - uint32_t s_rev_level; - uint16_t s_minor_rev_level; - uint16_t s_magic; - - uint16_t s_bytes; - - uint16_t s_flags; - uint32_t s_crc_seed; - uint32_t s_sum; - - uint32_t s_log_block_size; - - uint64_t s_nsegments; - uint64_t s_dev_size; - uint64_t s_first_data_block; - uint32_t s_blocks_per_segment; - uint32_t s_r_segments_percentage; - - uint64_t s_last_cno; - uint64_t s_last_pseg; - uint64_t s_last_seq; - uint64_t s_free_blocks_count; - - uint64_t s_ctime; - - uint64_t s_mtime; - uint64_t s_wtime; - uint16_t s_mnt_count; - uint16_t s_max_mnt_count; - uint16_t s_state; - uint16_t s_errors; - uint64_t s_lastcheck; - - uint32_t s_checkinterval; - uint32_t s_creator_os; - uint16_t s_def_resuid; - uint16_t s_def_resgid; - uint32_t s_first_ino; - - uint16_t s_inode_size; - uint16_t s_dat_entry_size; - uint16_t s_checkpoint_size; - uint16_t s_segment_usage_size; - - uint8_t s_uuid[16]; - char s_volume_name[80]; - - uint32_t s_c_interval; - uint32_t s_c_block_max; - uint32_t s_reserved[192]; -}; - -/* nilfs2 magic string */ -#define NILFS_SB_MAGIC "\x34\x34" -/* nilfs2 super block offset */ -#define NILFS_SB_OFF 0x400 -/* nilfs2 super block offset in kB */ -#define NILFS_SB_KBOFF (NILFS_SB_OFF >> 10) -/* nilfs2 magic string offset within super block */ -#define NILFS_MAG_OFF 6 - -static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct nilfs_super_block *sb; - static unsigned char sum[4]; - const int sumoff = offsetof(struct nilfs_super_block, s_sum); - size_t bytes; - uint32_t crc; - - sb = blkid_probe_get_sb(pr, mag, struct nilfs_super_block); - if (!sb) - return -1; - - bytes = le16_to_cpu(sb->s_bytes); - crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff); - crc = crc32(crc, sum, 4); - crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4); - - if (crc != le32_to_cpu(sb->s_sum)) - return -1; - - if (strlen(sb->s_volume_name)) - blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name, - sizeof(sb->s_volume_name)); - - blkid_probe_set_uuid(pr, sb->s_uuid); - blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(sb->s_rev_level)); - - return 0; -} - -const struct blkid_idinfo nilfs2_idinfo = -{ - .name = "nilfs2", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_nilfs2, - .magics = - { - { - .magic = NILFS_SB_MAGIC, - .len = 2, - .kboff = NILFS_SB_KBOFF, - .sboff = NILFS_MAG_OFF - }, - { NULL } - } -}; diff --git a/libblkid/ntfs.c b/libblkid/ntfs.c deleted file mode 100644 index 41c6b9cd5..000000000 --- a/libblkid/ntfs.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <inttypes.h> - -#include "superblocks.h" - -struct ntfs_bios_parameters { - uint16_t sector_size; /* Size of a sector in bytes. */ - uint8_t sectors_per_cluster; /* Size of a cluster in sectors. */ - uint16_t reserved_sectors; /* zero */ - uint8_t fats; /* zero */ - uint16_t root_entries; /* zero */ - uint16_t sectors; /* zero */ - uint8_t media_type; /* 0xf8 = hard disk */ - uint16_t sectors_per_fat; /* zero */ - uint16_t sectors_per_track; /* irrelevant */ - uint16_t heads; /* irrelevant */ - uint32_t hidden_sectors; /* zero */ - uint32_t large_sectors; /* zero */ -} __attribute__ ((__packed__)); - -struct ntfs_super_block { - uint8_t jump[3]; - uint8_t oem_id[8]; /* magic string */ - - struct ntfs_bios_parameters bpb; - - uint16_t unused[2]; - uint64_t number_of_sectors; - uint64_t mft_cluster_location; - uint64_t mft_mirror_cluster_location; - int8_t clusters_per_mft_record; - uint8_t reserved1[3]; - int8_t cluster_per_index_record; - uint8_t reserved2[3]; - uint64_t volume_serial; - uint32_t checksum; -} __attribute__((packed)); - -struct master_file_table_record { - uint32_t magic; - uint16_t usa_ofs; - uint16_t usa_count; - uint64_t lsn; - uint16_t sequence_number; - uint16_t link_count; - uint16_t attrs_offset; - uint16_t flags; - uint32_t bytes_in_use; - uint32_t bytes_allocated; -} __attribute__((__packed__)); - -struct file_attribute { - uint32_t type; - uint32_t len; - uint8_t non_resident; - uint8_t name_len; - uint16_t name_offset; - uint16_t flags; - uint16_t instance; - uint32_t value_len; - uint16_t value_offset; -} __attribute__((__packed__)); - -#define MFT_RECORD_VOLUME 3 -#define NTFS_MAX_CLUSTER_SIZE (64 * 1024) - -enum { - MFT_RECORD_ATTR_VOLUME_NAME = cpu_to_le32(0x60), - MFT_RECORD_ATTR_END = cpu_to_le32(0xffffffff) -}; - -static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct ntfs_super_block *ns; - struct master_file_table_record *mft; - - uint32_t sectors_per_cluster, mft_record_size, attr_off; - uint16_t sector_size; - uint64_t nr_clusters, off; - unsigned char *buf_mft; - - ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); - if (!ns) - return -1; - - /* - * Check bios parameters block - */ - sector_size = le16_to_cpu(ns->bpb.sector_size); - sectors_per_cluster = ns->bpb.sectors_per_cluster; - - if (sector_size < 256 || sector_size > 4096) - return 1; - - switch (sectors_per_cluster) { - case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: - break; - default: - return 1; - } - - if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) * - ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE) - return 1; - - /* Unused fields must be zero */ - if (le16_to_cpu(ns->bpb.reserved_sectors) - || le16_to_cpu(ns->bpb.root_entries) - || le16_to_cpu(ns->bpb.sectors) - || le16_to_cpu(ns->bpb.sectors_per_fat) - || le32_to_cpu(ns->bpb.large_sectors) - || ns->bpb.fats) - return 1; - - if ((uint8_t) ns->clusters_per_mft_record < 0xe1 - || (uint8_t) ns->clusters_per_mft_record > 0xf7) { - - switch (ns->clusters_per_mft_record) { - case 1: case 2: case 4: case 8: case 16: case 32: case 64: - break; - default: - return 1; - } - } - - if (ns->clusters_per_mft_record > 0) - mft_record_size = ns->clusters_per_mft_record * - sectors_per_cluster * sector_size; - else - mft_record_size = 1 << (0 - ns->clusters_per_mft_record); - - nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster; - - if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) || - (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters)) - return 1; - - - off = le64_to_cpu(ns->mft_cluster_location) * sector_size * - sectors_per_cluster; - - DBG(DEBUG_LOWPROBE, printf("NTFS: sector_size=%d, mft_record_size=%d, " - "sectors_per_cluster=%d, nr_clusters=%ju " - "cluster_offset=%jd\n", - (int) sector_size, mft_record_size, - sectors_per_cluster, nr_clusters, - off)); - - buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); - if (!buf_mft) - return 1; - - if (memcmp(buf_mft, "FILE", 4)) - return 1; - - off += MFT_RECORD_VOLUME * mft_record_size; - - buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); - if (!buf_mft) - return 1; - - if (memcmp(buf_mft, "FILE", 4)) - return 1; - - mft = (struct master_file_table_record *) buf_mft; - attr_off = le16_to_cpu(mft->attrs_offset); - - while (attr_off < mft_record_size && - attr_off <= le32_to_cpu(mft->bytes_allocated)) { - - uint32_t attr_len; - struct file_attribute *attr; - - attr = (struct file_attribute *) (buf_mft + attr_off); - attr_len = le32_to_cpu(attr->len); - if (!attr_len) - break; - - if (attr->type == MFT_RECORD_ATTR_END) - break; - if (attr->type == MFT_RECORD_ATTR_VOLUME_NAME) { - unsigned int val_off = le16_to_cpu(attr->value_offset); - unsigned int val_len = le32_to_cpu(attr->value_len); - unsigned char *val = ((uint8_t *) attr) + val_off; - - blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE); - break; - } - - if (UINT_MAX - attr_len < attr_off) - break; - attr_off += attr_len; - } - - blkid_probe_sprintf_uuid(pr, - (unsigned char *) &ns->volume_serial, - sizeof(ns->volume_serial), - "%016" PRIX64, le64_to_cpu(ns->volume_serial)); - return 0; -} - - -const struct blkid_idinfo ntfs_idinfo = -{ - .name = "ntfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ntfs, - .magics = - { - { .magic = "NTFS ", .len = 8, .sboff = 3 }, - { NULL } - } -}; - diff --git a/libblkid/nvidia_raid.c b/libblkid/nvidia_raid.c deleted file mode 100644 index dd86cdcc6..000000000 --- a/libblkid/nvidia_raid.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct nv_metadata { - uint8_t vendor[8]; - uint32_t size; - uint32_t chksum; - uint16_t version; -} __attribute__((packed)); - -#define NVIDIA_SIGNATURE "NVIDIA" - -static int probe_nvraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct nv_metadata *nv; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 2) * 0x200; - nv = (struct nv_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct nv_metadata)); - if (!nv) - return -1; - - if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) - return -1; - if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor), - (unsigned char *) nv->vendor)) - return -1; - return 0; -} - -const struct blkid_idinfo nvraid_idinfo = { - .name = "nvidia_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_nvraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/ocfs.c b/libblkid/ocfs.c deleted file mode 100644 index 82170ace1..000000000 --- a/libblkid/ocfs.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 1999, 2001 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct ocfs_volume_header { - unsigned char minor_version[4]; - unsigned char major_version[4]; - unsigned char signature[128]; - char mount[128]; - unsigned char mount_len[2]; -} __attribute__((packed)); - -struct ocfs_volume_label { - unsigned char disk_lock[48]; - char label[64]; - unsigned char label_len[2]; - unsigned char vol_id[16]; - unsigned char vol_id_len[2]; -} __attribute__((packed)); - -#define ocfsmajor(o) ( (uint32_t) o.major_version[0] \ - + (((uint32_t) o.major_version[1]) << 8) \ - + (((uint32_t) o.major_version[2]) << 16) \ - + (((uint32_t) o.major_version[3]) << 24)) - -#define ocfsminor(o) ( (uint32_t) o.minor_version[0] \ - + (((uint32_t) o.minor_version[1]) << 8) \ - + (((uint32_t) o.minor_version[2]) << 16) \ - + (((uint32_t) o.minor_version[3]) << 24)) - -#define ocfslabellen(o) ((uint32_t)o.label_len[0] + (((uint32_t) o.label_len[1]) << 8)) -#define ocfsmountlen(o) ((uint32_t)o.mount_len[0] + (((uint32_t) o.mount_len[1]) << 8)) - -struct ocfs2_super_block { - uint8_t i_signature[8]; - uint32_t i_generation; - int16_t i_suballoc_slot; - uint16_t i_suballoc_bit; - uint32_t i_reserved0; - uint32_t i_clusters; - uint32_t i_uid; - uint32_t i_gid; - uint64_t i_size; - uint16_t i_mode; - uint16_t i_links_count; - uint32_t i_flags; - uint64_t i_atime; - uint64_t i_ctime; - uint64_t i_mtime; - uint64_t i_dtime; - uint64_t i_blkno; - uint64_t i_last_eb_blk; - uint32_t i_fs_generation; - uint32_t i_atime_nsec; - uint32_t i_ctime_nsec; - uint32_t i_mtime_nsec; - uint64_t i_reserved1[9]; - uint64_t i_pad1; - uint16_t s_major_rev_level; - uint16_t s_minor_rev_level; - uint16_t s_mnt_count; - int16_t s_max_mnt_count; - uint16_t s_state; - uint16_t s_errors; - uint32_t s_checkinterval; - uint64_t s_lastcheck; - uint32_t s_creator_os; - uint32_t s_feature_compat; - uint32_t s_feature_incompat; - uint32_t s_feature_ro_compat; - uint64_t s_root_blkno; - uint64_t s_system_dir_blkno; - uint32_t s_blocksize_bits; - uint32_t s_clustersize_bits; - uint16_t s_max_slots; - uint16_t s_reserved1; - uint32_t s_reserved2; - uint64_t s_first_cluster_group; - uint8_t s_label[64]; - uint8_t s_uuid[16]; -} __attribute__((packed)); - -struct oracle_asm_disk_label { - char dummy[32]; - char dl_tag[8]; - char dl_id[24]; -} __attribute__((packed)); - -static int probe_ocfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - unsigned char *buf; - struct ocfs_volume_header ovh; - struct ocfs_volume_label ovl; - uint32_t maj, min; - - /* header */ - buf = blkid_probe_get_buffer(pr, mag->kboff << 10, - sizeof(struct ocfs_volume_header)); - if (!buf) - return -1; - memcpy(&ovh, buf, sizeof(ovh)); - - /* label */ - buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512, - sizeof(struct ocfs_volume_label)); - if (!buf) - return -1; - memcpy(&ovl, buf, sizeof(ovl)); - - maj = ocfsmajor(ovh); - min = ocfsminor(ovh); - - if (maj == 1) - blkid_probe_set_value(pr, "SEC_TYPE", - (unsigned char *) "ocfs1", sizeof("ocfs1")); - else if (maj >= 9) - blkid_probe_set_value(pr, "SEC_TYPE", - (unsigned char *) "ntocfs", sizeof("ntocfs")); - - blkid_probe_set_label(pr, (unsigned char *) ovl.label, - ocfslabellen(ovl)); - blkid_probe_set_value(pr, "MOUNT", (unsigned char *) ovh.mount, - ocfsmountlen(ovh)); - blkid_probe_set_uuid(pr, ovl.vol_id); - blkid_probe_sprintf_version(pr, "%u.%u", maj, min); - return 0; -} - -static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct ocfs2_super_block *osb; - - osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block); - if (!osb) - return -1; - - blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label)); - blkid_probe_set_uuid(pr, osb->s_uuid); - - blkid_probe_sprintf_version(pr, "%u.%u", - le16_to_cpu(osb->s_major_rev_level), - le16_to_cpu(osb->s_minor_rev_level)); - - return 0; -} - -static int probe_oracleasm(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct oracle_asm_disk_label *dl; - - dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label); - if (!dl) - return -1; - - blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id)); - return 0; -} - - -const struct blkid_idinfo ocfs_idinfo = -{ - .name = "ocfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ocfs, - .minsz = 14000 * 1024, - .magics = - { - { .magic = "OracleCFS", .len = 9, .kboff = 8 }, - { NULL } - } -}; - -const struct blkid_idinfo ocfs2_idinfo = -{ - .name = "ocfs2", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ocfs2, - .minsz = 14000 * 1024, - .magics = - { - { .magic = "OCFSV2", .len = 6, .kboff = 1 }, - { .magic = "OCFSV2", .len = 6, .kboff = 2 }, - { .magic = "OCFSV2", .len = 6, .kboff = 4 }, - { .magic = "OCFSV2", .len = 6, .kboff = 8 }, - { NULL } - } -}; - -/* Oracle ASM (Automatic Storage Management) */ -const struct blkid_idinfo oracleasm_idinfo = -{ - .name = "oracleasm", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_oracleasm, - .magics = - { - { .magic = "ORCLDISK", .len = 8, .sboff = 32 }, - { NULL } - } -}; - diff --git a/libblkid/optutils.h b/libblkid/optutils.h deleted file mode 100644 index 28a54b2ab..000000000 --- a/libblkid/optutils.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef UTIL_LINUX_OPTUTILS_H -#define UTIL_LINUX_OPTUTILS_H - -#include "c.h" -#include "nls.h" - -static inline const char *option_to_longopt(int c, const struct option *opts) -{ - const struct option *o; - - for (o = opts; o->name; o++) - if (o->val == c) - return o->name; - return NULL; -} - -#ifndef OPTUTILS_EXIT_CODE -# define OPTUTILS_EXIT_CODE EXIT_FAILURE -#endif - -/* - * Check collisions between options. - * - * The conflicts between options are described in ul_excl_t array. The - * array contains groups of mutually exclusive options. For example - * - * static const ul_excl_t excl[] = { - * { 'Z','b','c' }, // first group - * { 'b','x' }, // second group - * { 0 } - * }; - * - * int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT; - * - * while ((c = getopt_long(argc, argv, "Zbcx", longopts, NULL)) != -1) { - * - * err_exclusive_options(c, longopts, excl, excl_st); - * - * switch (c) { - * case 'Z': - * .... - * } - * } - * - * The array excl[] defines two groups of the mutually exclusive options. The - * option '-b' is in the both groups. - * - * Note that the options in the group have to be in ASCII order (ABC..abc..) and - * groups have to be also in ASCII order. - * - * The current status of options is stored in excl_st array. The size of the array - * must be the same as number of the groups in the ul_excl_t array. - * - * If you're unsure then see sys-utils/mount.c or misc-utils/findmnt.c. - */ -#define UL_EXCL_STATUS_INIT { 0 } -typedef int ul_excl_t[16]; - -static inline void err_exclusive_options( - int c, - const struct option *opts, - const ul_excl_t *excl, - int *status) -{ - int e; - - for (e = 0; excl[e][0] && excl[e][0] <= c; e++) { - const int *op = excl[e]; - - for (; *op && *op <= c; op++) { - if (*op != c) - continue; - if (status[e] == 0) - status[e] = c; - else if (status[e] != c) { - fprintf(stderr, _("%s: options "), - program_invocation_short_name); - for (op = excl[e]; *op; op++) { - if (opts) - fprintf(stderr, "--%s ", - option_to_longopt(*op, opts)); - else - fprintf(stderr, "-%c ", *op); - } - fprintf(stderr, _("are mutually exclusive.")); - fputc('\n', stderr); - exit(OPTUTILS_EXIT_CODE); - } - break; - } - } -} - -#endif - diff --git a/libblkid/pager.c b/libblkid/pager.c deleted file mode 100644 index 5cf8c03b5..000000000 --- a/libblkid/pager.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Based on linux-perf/git scm - * - * Some modifications and simplifications for util-linux - * by Davidlohr Bueso <dave@xxxxxxx> - March 2012. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <err.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> - -#include "c.h" -#include "xalloc.h" -#include "nls.h" - -#define NULL_DEVICE "/dev/null" - -void setup_pager(void); - -static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; - -struct child_process { - const char **argv; - pid_t pid; - int in; - int out; - int err; - unsigned no_stdin:1; - void (*preexec_cb)(void); -}; -static struct child_process pager_process; - -static inline void close_pair(int fd[2]) -{ - close(fd[0]); - close(fd[1]); -} - -static inline void dup_devnull(int to) -{ - int fd = open(NULL_DEVICE, O_RDWR); - - if (fd < 0) - err(EXIT_FAILURE, _("cannot open %s"), NULL_DEVICE); - dup2(fd, to); - close(fd); -} - -static int start_command(struct child_process *cmd) -{ - int need_in; - int fdin[2]; - - /* - * In case of errors we must keep the promise to close FDs - * that have been passed in via ->in and ->out. - */ - need_in = !cmd->no_stdin && cmd->in < 0; - if (need_in) { - if (pipe(fdin) < 0) { - if (cmd->out > 0) - close(cmd->out); - return -1; - } - cmd->in = fdin[1]; - } - - fflush(NULL); - cmd->pid = fork(); - if (!cmd->pid) { - if (need_in) { - dup2(fdin[0], 0); - close_pair(fdin); - } else if (cmd->in > 0) { - dup2(cmd->in, 0); - close(cmd->in); - } - - cmd->preexec_cb(); - execvp(cmd->argv[0], (char *const*) cmd->argv); - exit(127); /* cmd not found */ - } - - if (cmd->pid < 0) { - if (need_in) - close_pair(fdin); - else if (cmd->in) - close(cmd->in); - return -1; - } - - if (need_in) - close(fdin[0]); - else if (cmd->in) - close(cmd->in); - return 0; -} - -static int wait_or_whine(pid_t pid) -{ - for (;;) { - int status, code; - pid_t waiting = waitpid(pid, &status, 0); - - if (waiting < 0) { - if (errno == EINTR) - continue; - err(EXIT_FAILURE, _("waitpid failed (%s)"), strerror(errno)); - } - if (waiting != pid) - return -1; - if (WIFSIGNALED(status)) - return -1; - - if (!WIFEXITED(status)) - return -1; - code = WEXITSTATUS(status); - switch (code) { - case 127: - return -1; - case 0: - return 0; - default: - return -1; - } - } -} - -static int finish_command(struct child_process *cmd) -{ - return wait_or_whine(cmd->pid); -} - -static void pager_preexec(void) -{ - /* - * Work around bug in "less" by not starting it until we - * have real input - */ - fd_set in; - - FD_ZERO(&in); - FD_SET(0, &in); - select(1, &in, NULL, &in, NULL); - - setenv("LESS", "FRSX", 0); -} - -static void wait_for_pager(void) -{ - fflush(stdout); - fflush(stderr); - /* signal EOF to pager */ - close(1); - close(2); - finish_command(&pager_process); -} - -static void wait_for_pager_signal(int signo) -{ - wait_for_pager(); - raise(signo); -} - -void setup_pager(void) -{ - const char *pager = getenv("PAGER"); - - if (!isatty(1)) - return; - - if (!pager) - pager = "less"; - else if (!*pager || !strcmp(pager, "cat")) - return; - - /* spawn the pager */ - pager_argv[2] = pager; - pager_process.argv = pager_argv; - pager_process.in = -1; - pager_process.preexec_cb = pager_preexec; - - if (start_command(&pager_process)) - return; - - /* original process continues, but writes to the pipe */ - dup2(pager_process.in, 1); - if (isatty(2)) - dup2(pager_process.in, 2); - close(pager_process.in); - - /* this makes sure that the parent terminates after the pager */ - signal(SIGINT, wait_for_pager_signal); - signal(SIGHUP, wait_for_pager_signal); - signal(SIGTERM, wait_for_pager_signal); - signal(SIGQUIT, wait_for_pager_signal); - signal(SIGPIPE, wait_for_pager_signal); - - atexit(wait_for_pager); -} - -#ifdef TEST_PROGRAM - -#define MAX 255 - -int main(int argc __attribute__ ((__unused__)), - char *argv[] __attribute__ ((__unused__))) -{ - int i; - - setup_pager(); - for (i = 0; i < MAX; i++) - printf("%d\n", i); - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/libblkid/pamfail.h b/libblkid/pamfail.h deleted file mode 100644 index e102df227..000000000 --- a/libblkid/pamfail.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#ifndef UTIL_LINUX_PAMFAIL_H -#include <security/pam_appl.h> -#include <security/pam_misc.h> -#include "c.h" - -static inline int -pam_fail_check(pam_handle_t *pamh, int retcode) -{ - if (retcode == PAM_SUCCESS) - return 0; - warnx("%s", pam_strerror(pamh, retcode)); - pam_end(pamh, retcode); - return 1; -} - -#endif /* UTIL_LINUX_PAMFAIL_H */ diff --git a/libblkid/partitions.c b/libblkid/partitions.c deleted file mode 100644 index 93ec4d224..000000000 --- a/libblkid/partitions.c +++ /dev/null @@ -1,1385 +0,0 @@ -/* - * partitions - partition tables parsing - * - * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <stdint.h> -#include <inttypes.h> -#include <stdarg.h> - -#include "partitions.h" -#include "sysfs.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. The libblkid prober is - * compatible with kernel partition tables parser. The parser does not return - * empty (size=0) partitions or special hidden partitions. - * - * NAME=value interface, supported tags: - * - * @PTTYPE: partition table type (dos, gpt, etc.). - * - * @PART_ENTRY_SCHEME: partition table type - * - * @PART_ENTRY_NAME: partition name (gpt and mac only) - * - * @PART_ENTRY_UUID: partition UUID (gpt only) - * - * @PART_ENTRY_TYPE: partition type, 0xNN (e.g 0x82) or type UUID (gpt only) or type string (mac) - * - * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or attributes (e.g. gpt attributes) - * - * @PART_ENTRY_NUMBER: partition number - * - * @PART_ENTRY_OFFSET: the begin of the partition - * - * @PART_ENTRY_SIZE: size of the partition - * - * @PART_ENTRY_DISK: whole-disk maj:min - * - * Example: - * - * <informalexample> - * <programlisting> - * blkid_probe pr; - * const char *ptname; - * - * pr = blkid_new_probe_from_filename(devname); - * if (!pr) - * err("%s: faild to open device", devname); - * - * 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); - * - * // don't forget to check return codes in your code! - * </programlisting> - * </informalexample> - * - * Binary interface: - * - * <informalexample> - * <programlisting> - * blkid_probe pr; - * blkid_partlist ls; - * int nparts, i; - * - * pr = blkid_new_probe_from_filename(devname); - * if (!pr) - * err("%s: faild to open device", devname); - * - * 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); - * - * // don't forget to check return codes in your code! - * </programlisting> - * </informalexample> - */ - -/* - * 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[] = -{ - &aix_pt_idinfo, - &sgi_pt_idinfo, - &sun_pt_idinfo, - &dos_pt_idinfo, - &gpt_pt_idinfo, - &mac_pt_idinfo, - &ultrix_pt_idinfo, - &bsd_pt_idinfo, - &unixware_pt_idinfo, - &solaris_x86_pt_idinfo, - &minix_pt_idinfo -}; - -/* - * 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 */ - char id[37]; /* PT identifier (e.g. UUID for GPT) */ - - 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 */ - char typestr[37]; /* partition type string (GPT and Mac) */ - - unsigned long long flags; /* partition flags / attributes */ - - 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 */ -}; - -static int blkid_partitions_probe_partition(blkid_probe pr); - -/** - * 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_reset_partitions_filter: - * @pr: prober - * - * Resets partitions probing filter - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_reset_partitions_filter(blkid_probe pr) -{ - return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS); -} - -/** - * blkid_probe_invert_partitions_filter: - * @pr: prober - * - * Inverts partitions probing filter - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_invert_partitions_filter(blkid_probe pr) -{ - return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS); -} - -/** - * blkid_probe_filter_partitions_type: - * @pr: prober - * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag - * @names: NULL terminated array of probing function names (e.g. "vfat"). - * - * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names - * - * %BLKID_FLTR_ONLYIN - probe for items which are IN @names - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]) -{ - return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names); -} - -/** - * 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. - * - * WARNING: the returned object will be overwritten by the next - * blkid_probe_get_partitions() call for the same @pr. If you want to - * use more blkid_partlist objects in the same time you have to create - * more blkid_probe handlers (see blkid_new_probe()). - * - * 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 blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls) -{ - pr->chains[BLKID_CHAIN_PARTS].data = ls; -} - -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_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 reset\n")); -} - -static blkid_partlist partitions_init_data(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(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 __attribute__((__unused__)), - 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=%"PRId64")\n", tab, type, 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 = blkid_partlist_increment_partno(ls); - - return par; -} - -blkid_partition blkid_partlist_add_partition(blkid_partlist ls, - blkid_parttable tab, - blkid_loff_t start, blkid_loff_t size) -{ - blkid_partition par = new_partition(ls, tab); - - if (!par) - return NULL; - - par->start = start; - par->size = size; - - DBG(DEBUG_LOWPROBE, - printf("parts: add partition (%p start=%" - PRId64 ", size=%" PRId64 ", table=%p)\n", - par, par->start, 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; -} - -int blkid_partlist_increment_partno(blkid_partlist ls) -{ - return ls ? ls->next_partno++ : -1; -} - -/* 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, - struct blkid_chain *chn) -{ - const struct blkid_idmag *mag = NULL; - blkid_loff_t off; - int rc = 1; /* = nothing detected */ - - if (pr->size <= 0 || (id->minsz && id->minsz > pr->size)) - goto nothing; /* the device is too small */ - - if (blkid_probe_get_idmag(pr, id, &off, &mag)) - 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(blkid_probe_get_partlist(pr)); - if (chn && !chn->binary) - blkid_probe_chain_reset_vals(pr, chn); - DBG(DEBUG_LOWPROBE, printf( - "%s probefunc failed\n", id->name)); - } - if (rc == 0 && mag && chn && !chn->binary) - rc = blkid_probe_set_magic(pr, off, mag->len, - (unsigned char *) mag->magic); - - 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 rc = 1; - size_t i; - - if (!pr || chn->idx < -1) - return -1; - blkid_probe_chain_reset_vals(pr, chn); - - if (chn->binary) - partitions_init_data(chn); - - if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT)) - goto details_only; - - DBG(DEBUG_LOWPROBE, - printf("--> starting probing loop [PARTS idx=%d]\n", - chn->idx)); - - i = chn->idx < 0 ? 0 : chn->idx + 1U; - - 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], chn) != 0) - continue; - - name = idinfos[i]->name; - - /* all checks passed */ - if (!chn->binary) - 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)); - rc = 0; - break; - } - - if (rc == 1) { - DBG(DEBUG_LOWPROBE, - printf("<-- leaving probing loop (failed) [PARTS idx=%d]\n", - chn->idx)); - } - -details_only: - /* - * Gather PART_ENTRY_* values if the current device is a partition. - */ - if (!chn->binary && - (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) { - - if (!blkid_partitions_probe_partition(pr)) - rc = 0; - } - - return rc; -} - -/* 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) -{ - blkid_probe prc; - int rc = 1; - blkid_partlist ls; - blkid_loff_t sz, off; - - DBG(DEBUG_LOWPROBE, printf( - "parts: ----> %s subprobe requested (parent=%p)\n", - id->name, parent)); - - if (!pr || !parent || !parent->size) - return -1; - - /* range defined by parent */ - sz = ((blkid_loff_t) parent->size) << 9; - off = ((blkid_loff_t) parent->start) << 9; - - if (off < pr->off || pr->off + pr->size < off + sz) { - DBG(DEBUG_LOWPROBE, printf( - "ERROR: parts: <---- '%s' subprobe: overflow detected.\n", - id->name)); - return -1; - } - - /* create private prober */ - prc = blkid_clone_probe(pr); - if (!prc) - return -1; - - blkid_probe_set_dimension(prc, off, sz); - - /* clone is always with reset chain, fix it */ - prc->cur_chain = blkid_probe_get_chain(pr); - - /* - * Set 'parent' to the current list of the partitions and use the list - * in cloned prober (so the cloned prober will extend the current list - * of partitions rather than create a new). - */ - ls = blkid_probe_get_partlist(pr); - blkid_partlist_set_parent(ls, parent); - - blkid_probe_set_partlist(prc, ls); - - rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr)); - - blkid_probe_set_partlist(prc, NULL); - blkid_partlist_set_parent(ls, NULL); - - blkid_free_probe(prc); /* free cloned prober */ - - DBG(DEBUG_LOWPROBE, printf( - "parts: <---- %s subprobe done (parent=%p, rc=%d)\n", - id->name, parent, rc)); - - return rc; -} - -static int blkid_partitions_probe_partition(blkid_probe pr) -{ - int rc = 1; - blkid_probe disk_pr = NULL; - blkid_partlist ls; - blkid_partition par; - dev_t devno; - - devno = blkid_probe_get_devno(pr); - if (!devno) - goto nothing; - - disk_pr = blkid_probe_get_wholedisk_probe(pr); - if (!disk_pr) - goto nothing; - - /* parse PT */ - ls = blkid_probe_get_partitions(disk_pr); - if (!ls) - goto nothing; - - par = blkid_partlist_devno_to_partition(ls, devno); - if (par) { - const char *v; - blkid_parttable tab = blkid_partition_get_table(par); - dev_t disk = blkid_probe_get_devno(disk_pr); - - if (tab) { - v = blkid_parttable_get_type(tab); - if (v) - blkid_probe_set_value(pr, "PART_ENTRY_SCHEME", - (unsigned char *) v, strlen(v) + 1); - } - - v = blkid_partition_get_name(par); - if (v) - blkid_probe_set_value(pr, "PART_ENTRY_NAME", - (unsigned char *) v, strlen(v) + 1); - - v = blkid_partition_get_uuid(par); - if (v) - blkid_probe_set_value(pr, "PART_ENTRY_UUID", - (unsigned char *) v, strlen(v) + 1); - - /* type */ - v = blkid_partition_get_type_string(par); - if (v) - blkid_probe_set_value(pr, "PART_ENTRY_TYPE", - (unsigned char *) v, strlen(v) + 1); - else - blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE", - "0x%x", blkid_partition_get_type(par)); - - if (blkid_partition_get_flags(par)) - blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS", - "0x%llx", blkid_partition_get_flags(par)); - - blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER", - "%d", blkid_partition_get_partno(par)); - - blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd", - blkid_partition_get_start(par)); - blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd", - blkid_partition_get_size(par)); - - blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u", - major(disk), minor(disk)); - } - rc = 0; -nothing: - return rc; -} - -/* - * Returns 1 if the device is whole-disk and the area specified by @offset and - * @size is covered by any partition. - */ -int blkid_probe_is_covered_by_pt(blkid_probe pr, - blkid_loff_t offset, blkid_loff_t size) -{ - blkid_probe prc; - blkid_partlist ls = NULL; - blkid_loff_t start, end; - int nparts, i, rc = 0; - - DBG(DEBUG_LOWPROBE, printf( - "=> checking if off=%jd size=%jd covered by PT\n", - offset, size)); - - prc = blkid_clone_probe(pr); - if (!prc) - goto done; - - ls = blkid_probe_get_partitions(prc); - if (!ls) - goto done; - - nparts = blkid_partlist_numof_partitions(ls); - if (!nparts) - goto done; - - end = (offset + size) >> 9; - start = offset >> 9; - - /* check if the partition table fits into the device */ - for (i = 0; i < nparts; i++) { - blkid_partition par = &ls->parts[i]; - - if (par->start + par->size > (pr->size >> 9)) { - DBG(DEBUG_LOWPROBE, printf("partition #%d overflows " - "device (off=%" PRId64 " size=%" PRId64 ")\n", - par->partno, par->start, par->size)); - goto done; - } - } - - /* check if the requested area is covered by PT */ - for (i = 0; i < nparts; i++) { - blkid_partition par = &ls->parts[i]; - - if (start >= par->start && end <= par->start + par->size) { - rc = 1; - break; - } - } -done: - blkid_free_probe(prc); - - DBG(DEBUG_LOWPROBE, printf("<= %s covered by PT\n", rc ? "IS" : "NOT")); - 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) -{ - size_t 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_table: - * @ls: partitions list - * - * Returns: top-level partition table or NULL of there is not a partition table - * on the device. - */ -blkid_parttable blkid_partlist_get_table(blkid_partlist ls) -{ - if (!ls || list_empty(&ls->l_tabs)) - return NULL; - - return list_entry(ls->l_tabs.next, - struct blkid_struct_parttable, t_tabs); -} - - -/** - * 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 or the partition table is empty. - * - * See also blkid_partlist_get_table(). - * - * 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_partlist_devno_to_partition: - * @ls: partitions list - * @devno: requested partition - * - * This function tries to get start and size for @devno from sysfs and - * returns a partition from @ls which matches with the values from sysfs. - * - * This function is necessary when you want to make a relation between an entry - * in the partition table (@ls) and block devices in your system. - * - * Returns: partition object or NULL in case or error. - */ -blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno) -{ - struct sysfs_cxt sysfs; - uint64_t start, size; - int i, rc, partno = 0; - - if (!ls) - return NULL; - - DBG(DEBUG_LOWPROBE, - printf("triyng to convert devno 0x%llx to partition\n", - (long long) devno)); - - if (sysfs_init(&sysfs, devno, NULL)) { - DBG(DEBUG_LOWPROBE, printf("failed t init sysfs context\n")); - return NULL; - } - rc = sysfs_read_u64(&sysfs, "size", &size); - if (!rc) { - rc = sysfs_read_u64(&sysfs, "start", &start); - if (rc) { - /* try to get partition number from DM uuid. - */ - char *uuid = sysfs_strdup(&sysfs, "dm/uuid"); - char *tmp = uuid; - char *prefix = uuid ? strsep(&tmp, "-") : NULL; - - if (prefix && strncasecmp(prefix, "part", 4) == 0) { - char *end = NULL; - - partno = strtol(prefix + 4, &end, 10); - if (prefix == end || (end && *end)) - partno = 0; - else - rc = 0; /* success */ - } - free(uuid); - } - } - - sysfs_deinit(&sysfs); - - if (rc) - return NULL; - - if (partno) { - DBG(DEBUG_LOWPROBE, printf("mapped by DM, using partno %d\n", partno)); - - /* - * Partition mapped by kpartx does not provide "start" offset - * in /sys, but if we know partno and size of the partition - * that we can probably make the releation bettween the device - * and an entry in partition table. - */ - for (i = 0; i < ls->nparts; i++) { - blkid_partition par = &ls->parts[i]; - - if (partno != blkid_partition_get_partno(par)) - continue; - - if ((blkid_loff_t) size == blkid_partition_get_size(par) || - (blkid_partition_is_extended(par) && size <= 1024)) - return par; - - } - return NULL; - } - - DBG(DEBUG_LOWPROBE, printf("searching by offset/size\n")); - - for (i = 0; i < ls->nparts; i++) { - blkid_partition par = &ls->parts[i]; - - if (blkid_partition_get_start(par) == (blkid_loff_t) start && - blkid_partition_get_size(par) == (blkid_loff_t) size) - return par; - - /* exception for extended dos partitions */ - if (blkid_partition_get_start(par) == (blkid_loff_t) start && - blkid_partition_is_extended(par) && size <= 1024) - return par; - - } - - DBG(DEBUG_LOWPROBE, printf("not found partition for device\n")); - return NULL; -} - -int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id) -{ - if (!tab) - return -1; - - if (strcmp(tab->type, "gpt") == 0) - blkid_unparse_uuid(id, tab->id, sizeof(tab->id)); - else if (strcmp(tab->type, "dos") == 0) - strncpy(tab->id, (const char *) id, sizeof(tab->id)); - - return 0; -} - -/** - * blkid_parttable_get_id: - * @tab: partition table - * - * The ID is GPT disk UUID or DOS disk ID (in hex format). - * - * Returns: partition table ID (for example GPT disk UUID) or NULL - */ -const char *blkid_parttable_get_id(blkid_parttable tab) -{ - return tab && tab->id && *tab->id ? tab->id : NULL; -} - - -int blkid_partition_set_type(blkid_partition par, int type) -{ - if (!par) - return -1; - par->type = type; - return 0; -} - -/** - * 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 - * - * 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. - * - * <informalexample> - * <programlisting> - * 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); - * </programlisting> - * </informalexample> - - * Returns: position (in bytes) of the partition table or -1 in case of error. - * - */ -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: - * - * <informalexample> - * <programlisting> - * - * -- 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 - * - * </programlisting> - * </informalexample> - * - * 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; -} - -static void set_string(unsigned char *item, size_t max, - const unsigned char *data, size_t len) -{ - if (len >= max) - len = max - 1; - - memcpy(item, data, len); - item[len] = '\0'; - - blkid_rtrim_whitespace(item); -} - -int blkid_partition_set_name(blkid_partition par, - const unsigned char *name, size_t len) -{ - if (!par) - return -1; - - set_string(par->name, sizeof(par->name), name, len); - 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); - blkid_rtrim_whitespace(par->name); - 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. - */ -int blkid_partition_get_type(blkid_partition par) -{ - return par->type; -} - -/* Sets partition 'type' for PT where the type is defined by string rather - * than by number - */ -int blkid_partition_set_type_string(blkid_partition par, - const unsigned char *type, size_t len) -{ - if (!par) - return -1; - - set_string((unsigned char *) par->typestr, - sizeof(par->typestr), type, len); - return 0; -} - -/* Sets partition 'type' for PT where the type is defined by UUIDrather - * than by number - */ -int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid) -{ - if (!par) - return -1; - - blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr)); - return 0; -} - -/** - * blkid_partition_get_type_string: - * @par: partition - * - * The type string is supported by a small subset of partition tables (e.g Mac - * and EFI GPT). Note that GPT uses type UUID and this function returns this - * UUID as string. - * - * Returns: partition type string or NULL. - */ -const char *blkid_partition_get_type_string(blkid_partition par) -{ - return par && *par->typestr ? par->typestr : NULL; -} - - -int blkid_partition_set_flags(blkid_partition par, unsigned long long flags) -{ - if (!par) - return -1; - par->flags = flags; - return 0; -} - -/** - * blkid_partition_get_flags - * @par: partition - * - * Returns: partition flags (or attributes for gpt). - */ -unsigned long long blkid_partition_get_flags(blkid_partition par) -{ - return par->flags; -} - diff --git a/libblkid/partitions.h b/libblkid/partitions.h deleted file mode 100644 index 496bd4a1e..000000000 --- a/libblkid/partitions.h +++ /dev/null @@ -1,64 +0,0 @@ -#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 int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id); - -extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls, - blkid_parttable tab, - blkid_loff_t start, blkid_loff_t size); - -extern int blkid_partlist_set_partno(blkid_partlist ls, int partno); -extern int blkid_partlist_increment_partno(blkid_partlist ls); - -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); - -extern int blkid_partition_set_type(blkid_partition par, int type); - -extern int blkid_partition_set_type_string(blkid_partition par, - const unsigned char *type, size_t len); - -extern int blkid_partition_set_type_uuid(blkid_partition par, - const unsigned char *uuid); - -extern int blkid_partition_set_flags(blkid_partition par, unsigned long long flags); - -/* - * partition probers - */ -extern const struct blkid_idinfo aix_pt_idinfo; -extern const struct blkid_idinfo bsd_pt_idinfo; -extern const struct blkid_idinfo unixware_pt_idinfo; -extern const struct blkid_idinfo solaris_x86_pt_idinfo; -extern const struct blkid_idinfo sun_pt_idinfo; -extern const struct blkid_idinfo sgi_pt_idinfo; -extern const struct blkid_idinfo mac_pt_idinfo; -extern const struct blkid_idinfo dos_pt_idinfo; -extern const struct blkid_idinfo minix_pt_idinfo; -extern const struct blkid_idinfo gpt_pt_idinfo; -extern const struct blkid_idinfo ultrix_pt_idinfo; - -#endif /* BLKID_PARTITIONS_H */ diff --git a/libblkid/path.c b/libblkid/path.c deleted file mode 100644 index 4f955d91c..000000000 --- a/libblkid/path.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Simple functions to access files, paths maybe be globally prefixed by a - * global prefix to read data from alternative destination (e.g. /proc dump for - * regression tests). - * - * Taken from lscpu.c - * - * Copyright (C) 2008 Cai Qian <qcai@redhat.com> - * Copyright (C) 2008-2012 Karel Zak <kzak@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <stdio.h> -#include <inttypes.h> -#include <errno.h> - -#include "all-io.h" -#include "path.h" -#include "nls.h" -#include "c.h" - -static size_t prefixlen; -static char pathbuf[PATH_MAX]; - -static const char * -path_vcreate(const char *path, va_list ap) -{ - if (prefixlen) - vsnprintf(pathbuf + prefixlen, - sizeof(pathbuf) - prefixlen, path, ap); - else - vsnprintf(pathbuf, sizeof(pathbuf), path, ap); - return pathbuf; -} - -static FILE * -path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap) -{ - FILE *f; - const char *p = path_vcreate(path, ap); - - f = fopen(p, mode); - if (!f && exit_on_error) - err(EXIT_FAILURE, _("cannot open %s"), p); - return f; -} - -static int -path_vopen(int flags, const char *path, va_list ap) -{ - int fd; - const char *p = path_vcreate(path, ap); - - fd = open(p, flags); - if (fd == -1) - err(EXIT_FAILURE, _("cannot open %s"), p); - return fd; -} - -FILE * -path_fopen(const char *mode, int exit_on_error, const char *path, ...) -{ - FILE *fd; - va_list ap; - - va_start(ap, path); - fd = path_vfopen(mode, exit_on_error, path, ap); - va_end(ap); - - return fd; -} - -void -path_read_str(char *result, size_t len, const char *path, ...) -{ - FILE *fd; - va_list ap; - - va_start(ap, path); - fd = path_vfopen("r", 1, path, ap); - va_end(ap); - - if (!fgets(result, len, fd)) - err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); - fclose(fd); - - len = strlen(result); - if (result[len - 1] == '\n') - result[len - 1] = '\0'; -} - -int -path_read_s32(const char *path, ...) -{ - FILE *fd; - va_list ap; - int result; - - va_start(ap, path); - fd = path_vfopen("r", 1, path, ap); - va_end(ap); - - if (fscanf(fd, "%d", &result) != 1) { - if (ferror(fd)) - err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); - else - errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); - } - fclose(fd); - return result; -} - -uint64_t -path_read_u64(const char *path, ...) -{ - FILE *fd; - va_list ap; - uint64_t result; - - va_start(ap, path); - fd = path_vfopen("r", 1, path, ap); - va_end(ap); - - if (fscanf(fd, "%"SCNu64, &result) != 1) { - if (ferror(fd)) - err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); - else - errx(EXIT_FAILURE, _("parse error: %s"), pathbuf); - } - fclose(fd); - return result; -} - -int -path_write_str(const char *str, const char *path, ...) -{ - int fd, result; - va_list ap; - - va_start(ap, path); - fd = path_vopen(O_WRONLY, path, ap); - va_end(ap); - result = write_all(fd, str, strlen(str)); - close(fd); - return result; -} - -int -path_exist(const char *path, ...) -{ - va_list ap; - const char *p; - - va_start(ap, path); - p = path_vcreate(path, ap); - va_end(ap); - - return access(p, F_OK) == 0; -} - -#ifdef HAVE_CPU_SET_T - -static cpu_set_t * -path_cpuparse(int maxcpus, int islist, const char *path, va_list ap) -{ - FILE *fd; - cpu_set_t *set; - size_t setsize, len = maxcpus * 7; - char buf[len]; - - fd = path_vfopen("r", 1, path, ap); - - if (!fgets(buf, len, fd)) - err(EXIT_FAILURE, _("failed to read: %s"), pathbuf); - fclose(fd); - - len = strlen(buf); - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - set = cpuset_alloc(maxcpus, &setsize, NULL); - if (!set) - err(EXIT_FAILURE, _("failed to callocate cpu set")); - - if (islist) { - if (cpulist_parse(buf, set, setsize, 0)) - errx(EXIT_FAILURE, _("failed to parse CPU list %s"), buf); - } else { - if (cpumask_parse(buf, set, setsize)) - errx(EXIT_FAILURE, _("failed to parse CPU mask %s"), buf); - } - return set; -} - -cpu_set_t * -path_read_cpuset(int maxcpus, const char *path, ...) -{ - va_list ap; - cpu_set_t *set; - - va_start(ap, path); - set = path_cpuparse(maxcpus, 0, path, ap); - va_end(ap); - - return set; -} - -cpu_set_t * -path_read_cpulist(int maxcpus, const char *path, ...) -{ - va_list ap; - cpu_set_t *set; - - va_start(ap, path); - set = path_cpuparse(maxcpus, 1, path, ap); - va_end(ap); - - return set; -} - -#endif /* HAVE_CPU_SET_T */ - -void -path_set_prefix(const char *prefix) -{ - prefixlen = strlen(prefix); - strncpy(pathbuf, prefix, sizeof(pathbuf)); - pathbuf[sizeof(pathbuf) - 1] = '\0'; -} diff --git a/libblkid/path.h b/libblkid/path.h deleted file mode 100644 index 615d28491..000000000 --- a/libblkid/path.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef UTIL_LINUX_PATH_H -#define UTIL_LINUX_PATH_H - -#include <stdio.h> -#include <stdint.h> - -extern FILE *path_fopen(const char *mode, int exit_on_err, const char *path, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern void path_read_str(char *result, size_t len, const char *path, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern int path_write_str(const char *str, const char *path, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); -extern int path_read_s32(const char *path, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern uint64_t path_read_u64(const char *path, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - -extern int path_exist(const char *path, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); - -#ifdef HAVE_CPU_SET_T -# include "cpuset.h" - -extern cpu_set_t *path_read_cpuset(int, const char *path, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); -extern cpu_set_t *path_read_cpulist(int, const char *path, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); -extern void path_set_prefix(const char *); -#endif /* HAVE_CPU_SET_T */ - -#endif /* UTIL_LINUX_PATH_H */ diff --git a/libblkid/pathnames.h b/libblkid/pathnames.h deleted file mode 100644 index 6d300a9e7..000000000 --- a/libblkid/pathnames.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Vaguely based on - * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 - * This code is in the public domain. - */ -#ifndef PATHNAMES_H -#define PATHNAMES_H - -#ifdef HAVE_PATHS_H -#include <paths.h> -#endif - -#ifndef __STDC__ -# error "we need an ANSI compiler" -#endif - -/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */ -#define PATH_DELETED_SUFFIX "\\040(deleted)" -#define PATH_DELETED_SUFFIX_SZ (sizeof(PATH_DELETED_SUFFIX) - 1) - -/* DEFPATHs from <paths.h> don't include /usr/local */ -#undef _PATH_DEFPATH -#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" - -#undef _PATH_DEFPATH_ROOT -#define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" - -#define _PATH_SECURETTY "/etc/securetty" -#define _PATH_WTMPLOCK "/etc/wtmplock" - -#define _PATH_HUSHLOGIN ".hushlogin" -#define _PATH_HUSHLOGINS "/etc/hushlogins" - -#ifndef _PATH_MAILDIR -#define _PATH_MAILDIR "/var/spool/mail" -#endif -#define _PATH_MOTDFILE "/etc/motd" -#define _PATH_NOLOGIN "/etc/nologin" - -#define _PATH_LOGIN "/bin/login" -#define _PATH_INITTAB "/etc/inittab" -#define _PATH_RC "/etc/rc" -#define _PATH_REBOOT "/sbin/reboot" -#define _PATH_SHUTDOWN "/sbin/shutdown" -#define _PATH_SINGLE "/etc/singleboot" -#define _PATH_SHUTDOWN_CONF "/etc/shutdown.conf" - -#define _PATH_SECURE "/etc/securesingle" -#define _PATH_USERTTY "/etc/usertty" - -/* used in login-utils/shutdown.c */ - -/* used in login-utils/setpwnam.h and login-utils/islocal.c */ -#define _PATH_PASSWD "/etc/passwd" - -/* used in login-utils/newgrp and login-utils/setpwnam.h*/ -#define _PATH_GSHADOW "/etc/gshadow" - -/* used in login-utils/setpwnam.h */ -#define _PATH_GROUP "/etc/group" -#define _PATH_SHADOW_PASSWD "/etc/shadow" -#define _PATH_SHELLS "/etc/shells" - -/* used in term-utils/agetty.c */ -#define _PATH_ISSUE "/etc/issue" -#define _PATH_NUMLOCK_ON _PATH_LOCALSTATEDIR "/numlock-on" - -#define _PATH_LOGINDEFS "/etc/login.defs" - -/* used in misc-utils/look.c */ -#define _PATH_WORDS "/usr/share/dict/words" -#define _PATH_WORDS_ALT "/usr/share/dict/web2" - -/* mount paths */ -#define _PATH_UMOUNT "/bin/umount" - -#define _PATH_FILESYSTEMS "/etc/filesystems" -#define _PATH_PROC_SWAPS "/proc/swaps" -#define _PATH_PROC_FILESYSTEMS "/proc/filesystems" -#define _PATH_PROC_MOUNTS "/proc/mounts" -#define _PATH_PROC_PARTITIONS "/proc/partitions" -#define _PATH_PROC_DEVICES "/proc/devices" -#define _PATH_PROC_MOUNTINFO "/proc/self/mountinfo" -#define _PATH_PROC_LOCKS "/proc/locks" -#define _PATH_PROC_CDROMINFO "/proc/sys/dev/cdrom/info" - -#define _PATH_PROC_ATTR_CURRENT "/proc/self/attr/current" -#define _PATH_PROC_ATTR_EXEC "/proc/self/attr/exec" -#define _PATH_PROC_CAPLASTCAP "/proc/sys/kernel/cap_last_cap" - - -#define _PATH_SYS_BLOCK "/sys/block" -#define _PATH_SYS_DEVBLOCK "/sys/dev/block" -#define _PATH_SYS_CLASS "/sys/class" -#define _PATH_SYS_SCSI "/sys/bus/scsi" - -#define _PATH_SYS_SELINUX "/sys/fs/selinux" -#define _PATH_SYS_APPARMOR "/sys/kernel/security/apparmor" - -#ifndef _PATH_MOUNTED -# ifdef MOUNTED /* deprecated */ -# define _PATH_MOUNTED MOUNTED -# else -# define _PATH_MOUNTED "/etc/mtab" -# endif -#endif - -#ifndef _PATH_MNTTAB -# ifdef MNTTAB /* deprecated */ -# define _PATH_MNTTAB MNTTAB -# else -# define _PATH_MNTTAB "/etc/fstab" -# endif -#endif - -#define _PATH_MNTTAB_DIR _PATH_MNTTAB ".d" - -#define _PATH_MOUNTED_LOCK _PATH_MOUNTED "~" -#define _PATH_MOUNTED_TMP _PATH_MOUNTED ".tmp" - -#ifndef _PATH_DEV - /* - * The tailing '/' in _PATH_DEV is there for compatibility with libc. - */ -# define _PATH_DEV "/dev/" -#endif - -#define _PATH_DEV_LOOP "/dev/loop" -#define _PATH_DEV_LOOPCTL "/dev/loop-control" -#define _PATH_DEV_TTY "/dev/tty" - - -/* udev paths */ -#define _PATH_DEV_BYLABEL "/dev/disk/by-label" -#define _PATH_DEV_BYUUID "/dev/disk/by-uuid" -#define _PATH_DEV_BYID "/dev/disk/by-id" -#define _PATH_DEV_BYPATH "/dev/disk/by-path" -#define _PATH_DEV_BYPARTLABEL "/dev/disk/by-partlabel" -#define _PATH_DEV_BYPARTUUID "/dev/disk/by-partuuid" - -/* hwclock paths */ -#define _PATH_ADJPATH "/etc/adjtime" -#define _PATH_LASTDATE "/var/lib/lastdate" -#ifdef __ia64__ -# define _PATH_RTC_DEV "/dev/efirtc" -#else -# define _PATH_RTC_DEV "/dev/rtc" -#endif - -#ifndef _PATH_BTMP -#define _PATH_BTMP "/var/log/btmp" -#endif - -/* raw paths*/ -#define _PATH_RAWDEVDIR "/dev/raw/" -#define _PATH_RAWDEVCTL _PATH_RAWDEVDIR "rawctl" -/* deprecated */ -#define _PATH_RAWDEVCTL_OLD "/dev/rawctl" - -/* wdctl path */ -#define _PATH_WATCHDOG_DEV "/dev/watchdog" - -/* ipc paths */ -#define _PATH_PROC_SYSV_MSG "/proc/sysvipc/msg" -#define _PATH_PROC_SYSV_SEM "/proc/sysvipc/sem" -#define _PATH_PROC_SYSV_SHM "/proc/sysvipc/shm" -#define _PATH_PROC_IPC_MSGMAX "/proc/sys/kernel/msgmax" -#define _PATH_PROC_IPC_MSGMNB "/proc/sys/kernel/msgmnb" -#define _PATH_PROC_IPC_MSGMNI "/proc/sys/kernel/msgmni" -#define _PATH_PROC_IPC_SEM "/proc/sys/kernel/sem" -#define _PATH_PROC_IPC_SHMALL "/proc/sys/kernel/shmall" -#define _PATH_PROC_IPC_SHMMAX "/proc/sys/kernel/shmmax" -#define _PATH_PROC_IPC_SHMMNI "/proc/sys/kernel/shmmni" - -/* kernel command line */ -#define _PATH_PROC_CMDLINE "/proc/cmdline" - -#endif /* PATHNAMES_H */ - diff --git a/libblkid/probe.c b/libblkid/probe.c deleted file mode 100644 index 77e8b860c..000000000 --- a/libblkid/probe.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* - * Low-level libblkid probing API - * - * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -/** - * SECTION: lowprobe - * @title: Low-level probing - * @short_description: low-level prober initialization - * - * The low-level probing routines always and directly read information from - * the selected (see blkid_probe_set_device()) device. - * - * The probing routines are grouped together into separate chains. Currently, - * the library provides superblocks, partitions and topology chains. - * - * The probing routines is possible to filter (enable/disable) by type (e.g. - * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID). - * These filters are per-chain. Note that always when you touch the chain - * filter the current probing position is reset and probing starts from - * scratch. It means that the chain filter should not be modified during - * probing, for example in loop where you call blkid_do_probe(). - * - * For more details see the chain specific documentation. - * - * The low-level API provides two ways how access to probing results. - * - * 1. The NAME=value (tag) interface. This interface is older and returns all data - * as strings. This interface is generic for all chains. - * - * 2. The binary interfaces. These interfaces return data in the native formats. - * The interface is always specific to the probing chain. - * - * Note that the previous probing result (binary or NAME=value) is always - * zeroized when a chain probing function is called. For example: - * - * <informalexample> - * <programlisting> - * blkid_probe_enable_partitions(pr, TRUE); - * blkid_probe_enable_superblocks(pr, FALSE); - * - * blkid_do_safeprobe(pr); - * </programlisting> - * </informalexample> - * - * overwrites the previous probing result for the partitions chain, the superblocks - * result is not modified. - */ - -/** - * SECTION: lowprobe-tags - * @title: Low-level tags - * @short_description: generic NAME=value interface. - * - * The probing routines inside the chain are mutually exclusive by default -- - * only few probing routines are marked as "tolerant". The "tolerant" probing - * routines are used for filesystem which can share the same device with any - * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag. - * - * The SUPERBLOCKS chain is enabled by default. The all others chains is - * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific - * documentation. - * - * The blkid_do_probe() function returns a result from only one probing - * routine, and the next call from the next probing routine. It means you need - * to call the function in loop, for example: - * - * <informalexample> - * <programlisting> - * while((blkid_do_probe(pr) == 0) - * ... use result ... - * </programlisting> - * </informalexample> - * - * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only - * first probing result for every enabled chain. This function checks for - * ambivalent results (e.g. more "intolerant" filesystems superblocks on the - * device). - * - * The probing result is set of NAME=value pairs (the NAME is always unique). - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#ifdef HAVE_LINUX_CDROM_H -#include <linux/cdrom.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <inttypes.h> -#include <stdint.h> -#include <stdarg.h> - -#ifdef HAVE_LIBUUID -# include <uuid.h> -#endif - -#include "blkidP.h" -#include "all-io.h" - -/* 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 - */ -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); -static void blkid_probe_reset_buffer(blkid_probe pr); - -/** - * blkid_new_probe: - * - * Returns: a pointer to the newly allocated probe struct or NULL in case of error. - */ -blkid_probe blkid_new_probe(void) -{ - int i; - blkid_probe pr; - - blkid_init_debug(0); - pr = calloc(1, sizeof(struct blkid_struct_probe)); - if (!pr) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a new probe %p\n", pr)); - - /* initialize chains */ - for (i = 0; i < BLKID_NCHAINS; i++) { - pr->chains[i].driver = chains_drvs[i]; - pr->chains[i].flags = chains_drvs[i]->dflt_flags; - pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; - } - INIT_LIST_HEAD(&pr->buffers); - return pr; -} - -/* - * Clone @parent, the new clone shares all, but except: - * - * - probing result - * - bufferes if another device (or offset) is set to the prober - */ -blkid_probe blkid_clone_probe(blkid_probe parent) -{ - blkid_probe pr; - - if (!parent) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a probe clone\n")); - - pr = blkid_new_probe(); - if (!pr) - return NULL; - - pr->fd = parent->fd; - pr->off = parent->off; - pr->size = parent->size; - pr->devno = parent->devno; - pr->disk_devno = parent->disk_devno; - pr->blkssz = parent->blkssz; - pr->flags = parent->flags; - pr->parent = parent; - - pr->flags &= ~BLKID_FL_PRIVATE_FD; - - return pr; -} - - - -/** - * blkid_new_probe_from_filename: - * @filename: device or regular file - * - * This function is same as call open(filename), blkid_new_probe() and - * blkid_probe_set_device(pr, fd, 0, 0). - * - * The @filename is closed by blkid_free_probe() or by the - * blkid_probe_set_device() call. - * - * Returns: a pointer to the newly allocated probe struct or NULL in case of - * error. - */ -blkid_probe blkid_new_probe_from_filename(const char *filename) -{ - int fd = -1; - blkid_probe pr = NULL; - - if (!filename) - return NULL; - - fd = open(filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return NULL; - - pr = blkid_new_probe(); - if (!pr) - goto err; - - if (blkid_probe_set_device(pr, fd, 0, 0)) - goto err; - - pr->flags |= BLKID_FL_PRIVATE_FD; - return pr; -err: - if (fd >= 0) - close(fd); - blkid_free_probe(pr); - return NULL; -} - -/** - * blkid_free_probe: - * @pr: probe - * - * Deallocates the probe struct, buffers and all allocated - * data that are associated with this probing control struct. - */ -void blkid_free_probe(blkid_probe pr) -{ - int i; - - if (!pr) - return; - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *ch = &pr->chains[i]; - - if (ch->driver->free_data) - ch->driver->free_data(pr, ch->data); - free(ch->fltr); - } - - if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) - close(pr->fd); - blkid_probe_reset_buffer(pr); - blkid_free_probe(pr->disk_probe); - - DBG(DEBUG_LOWPROBE, printf("free probe %p\n", pr)); - free(pr); -} - - -/* - * Removes chain values from probing result. - */ -void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) -{ - int nvals = pr->nvals; - int i, x; - - for (x = 0, i = 0; i < pr->nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->chain != chn && x == i) { - x++; - continue; - } - if (v->chain == chn) { - --nvals; - continue; - } - memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval)); - } - pr->nvals = nvals; -} - -static void blkid_probe_chain_reset_position(struct blkid_chain *chn) -{ - if (chn) - chn->idx = -1; -} - -/* - * Copies chain values from probing result to @vals, the max size of @vals is - * @nvals and returns real number of values. - */ -int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, - struct blkid_prval *vals, int nvals) -{ - int i, x; - - for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->chain != chn) - continue; - memcpy(&vals[x++], v, sizeof(struct blkid_prval)); - } - return x; -} - -/* - * Appends values from @vals to the probing result - */ -void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals) -{ - int i = 0; - - while (i < nvals && pr->nvals < BLKID_NVALS) { - memcpy(&pr->vals[pr->nvals++], &vals[i++], - sizeof(struct blkid_prval)); - } -} - -static void blkid_probe_reset_vals(blkid_probe pr) -{ - memset(pr->vals, 0, sizeof(pr->vals)); - pr->nvals = 0; -} - -struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) -{ - return pr->cur_chain; -} - -void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) -{ - int rc, org_prob_flags; - struct blkid_chain *org_chn; - - if (!pr || !chn) - return NULL; - - /* save the current setting -- the binary API has to be completely - * independent on the current probing status - */ - org_chn = pr->cur_chain; - org_prob_flags = pr->prob_flags; - - pr->cur_chain = chn; - pr->prob_flags = 0; - chn->binary = TRUE; - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->probe(pr, chn); - - chn->binary = FALSE; - blkid_probe_chain_reset_position(chn); - - /* restore the original setting - */ - pr->cur_chain = org_chn; - pr->prob_flags = org_prob_flags; - - if (rc != 0) - return NULL; - - DBG(DEBUG_LOWPROBE, - printf("returning %s binary data\n", chn->driver->name)); - return chn->data; -} - - -/** - * blkid_reset_probe: - * @pr: probe - * - * Zeroize probing results and resets the current probing (this has impact to - * blkid_do_probe() only). This function does not touch probing filters and - * keeps assigned device. - */ -void blkid_reset_probe(blkid_probe pr) -{ - int i; - - if (!pr) - return; - - blkid_probe_reset_vals(pr); - blkid_probe_set_wiper(pr, 0, 0); - - pr->cur_chain = NULL; - - for (i = 0; i < BLKID_NCHAINS; i++) - blkid_probe_chain_reset_position(&pr->chains[i]); -} - -/*** -static int blkid_probe_dump_filter(blkid_probe pr, int chain) -{ - struct blkid_chain *chn; - int i; - - if (!pr || chain < 0 || chain >= BLKID_NCHAINS) - return -1; - - chn = &pr->chains[chain]; - - if (!chn->fltr) - return -1; - - for (i = 0; i < chn->driver->nidinfos; i++) { - const struct blkid_idinfo *id = chn->driver->idinfos[i]; - - DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n", - i, - id->name, - blkid_bmp_get_item(chn->fltr, i) - ? "disabled" : "enabled <--")); - } - return 0; -} -***/ - -/* - * Returns properly initialized chain filter - */ -unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) -{ - struct blkid_chain *chn; - - if (!pr || chain < 0 || chain >= BLKID_NCHAINS) - return NULL; - - chn = &pr->chains[chain]; - - /* always when you touch the chain filter all indexes are reset and - * probing starts from scratch - */ - blkid_probe_chain_reset_position(chn); - pr->cur_chain = NULL; - - if (!chn->driver->has_fltr || (!chn->fltr && !create)) - return NULL; - - if (!chn->fltr) - chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos)); - else - memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos)); - - /* blkid_probe_dump_filter(pr, chain); */ - return chn->fltr; -} - -/* - * Generic private functions for filter setting - */ -int __blkid_probe_invert_filter(blkid_probe pr, int chain) -{ - size_t i; - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = &pr->chains[chain]; - - if (!chn->driver->has_fltr || !chn->fltr) - return -1; - - for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++) - chn->fltr[i] = ~chn->fltr[i]; - - DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); - /* blkid_probe_dump_filter(pr, chain); */ - return 0; -} - -int __blkid_probe_reset_filter(blkid_probe pr, int chain) -{ - return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1; -} - -int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) -{ - unsigned long *fltr; - struct blkid_chain *chn; - size_t i; - - fltr = blkid_probe_get_filter(pr, chain, TRUE); - if (!fltr) - return -1; - - chn = &pr->chains[chain]; - - for (i = 0; i < chn->driver->nidinfos; i++) { - int has = 0; - const struct blkid_idinfo *id = chn->driver->idinfos[i]; - char **n; - - for (n = names; *n; n++) { - if (!strcmp(id->name, *n)) { - has = 1; - break; - } - } - if (flag & BLKID_FLTR_ONLYIN) { - if (!has) - blkid_bmp_set_item(fltr, i); - } else if (flag & BLKID_FLTR_NOTIN) { - if (has) - blkid_bmp_set_item(fltr, i); - } - } - - DBG(DEBUG_LOWPROBE, - printf("%s: a new probing type-filter initialized\n", - chn->driver->name)); - /* blkid_probe_dump_filter(pr, chain); */ - return 0; -} - -unsigned char *blkid_probe_get_buffer(blkid_probe pr, - blkid_loff_t off, blkid_loff_t len) -{ - struct list_head *p; - struct blkid_bufinfo *bf = NULL; - - if (pr->size <= 0) - return NULL; - - if (pr->parent && - pr->parent->devno == pr->devno && - pr->parent->off <= pr->off && - pr->parent->off + pr->parent->size >= pr->off + pr->size) { - /* - * This is a cloned prober and points to the same area as - * parent. Let's use parent's buffers. - * - * Note that pr->off (and pr->parent->off) is always from the - * beginig of the device. - */ - return blkid_probe_get_buffer(pr->parent, - pr->off + off - pr->parent->off, len); - } - - list_for_each(p, &pr->buffers) { - struct blkid_bufinfo *x = - list_entry(p, struct blkid_bufinfo, bufs); - - if (x->off <= off && off + len <= x->off + x->len) { - DBG(DEBUG_LOWPROBE, - printf("\treuse buffer: off=%jd len=%jd pr=%p\n", - x->off, x->len, pr)); - bf = x; - break; - } - } - if (!bf) { - ssize_t ret; - - if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) - return NULL; - - /* allocate info and space for data by why call */ - bf = calloc(1, sizeof(struct blkid_bufinfo) + len); - if (!bf) - return NULL; - - bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); - bf->len = len; - bf->off = off; - INIT_LIST_HEAD(&bf->bufs); - - DBG(DEBUG_LOWPROBE, - printf("\tbuffer read: off=%jd len=%jd pr=%p\n", - off, len, pr)); - - ret = read(pr->fd, bf->data, len); - if (ret != (ssize_t) len) { - free(bf); - return NULL; - } - list_add_tail(&bf->bufs, &pr->buffers); - } - - return off ? bf->data + (off - bf->off) : bf->data; -} - - -static void blkid_probe_reset_buffer(blkid_probe pr) -{ - uint64_t read_ct = 0, len_ct = 0; - - if (!pr || list_empty(&pr->buffers)) - return; - - DBG(DEBUG_LOWPROBE, printf("reseting probing buffers pr=%p\n", pr)); - - while (!list_empty(&pr->buffers)) { - struct blkid_bufinfo *bf = list_entry(pr->buffers.next, - struct blkid_bufinfo, bufs); - read_ct++; - len_ct += bf->len; - list_del(&bf->bufs); - free(bf); - } - - DBG(DEBUG_LOWPROBE, - printf("buffers summary: %"PRIu64" bytes " - "by %"PRIu64" read() call(s)\n", - len_ct, read_ct)); - - INIT_LIST_HEAD(&pr->buffers); -} - -/* - * Small devices need a special care. - */ -int blkid_probe_is_tiny(blkid_probe pr) -{ - return pr && (pr->flags & BLKID_FL_TINY_DEV); -} - -/* - * CDROMs may fail when probed for RAID (last sector problem) - */ -int blkid_probe_is_cdrom(blkid_probe pr) -{ - return pr && (pr->flags & BLKID_FL_CDROM_DEV); -} - -/** - * blkid_probe_set_device: - * @pr: probe - * @fd: device file descriptor - * @off: begin of probing area - * @size: size of probing area (zero means whole device/file) - * - * Assigns the device to probe control struct, resets internal buffers and - * resets the current probing. - * - * Returns: -1 in case of failure, or 0 on success. - */ -int blkid_probe_set_device(blkid_probe pr, int fd, - blkid_loff_t off, blkid_loff_t size) -{ - struct stat sb; - - if (!pr) - return -1; - - blkid_reset_probe(pr); - blkid_probe_reset_buffer(pr); - - if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) - close(pr->fd); - - pr->flags &= ~BLKID_FL_PRIVATE_FD; - pr->flags &= ~BLKID_FL_TINY_DEV; - pr->flags &= ~BLKID_FL_CDROM_DEV; - pr->prob_flags = 0; - pr->fd = fd; - pr->off = off; - pr->size = 0; - pr->devno = 0; - pr->disk_devno = 0; - pr->mode = 0; - pr->blkssz = 0; - pr->wipe_off = 0; - pr->wipe_size = 0; - pr->wipe_chain = NULL; - -#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE) - /* Disable read-ahead */ - posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); -#endif - if (fstat(fd, &sb)) - goto err; - - if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode)) - goto err; - - pr->mode = sb.st_mode; - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) - pr->devno = sb.st_rdev; - - if (size) - pr->size = size; - else { - if (S_ISBLK(sb.st_mode)) { - if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) { - DBG(DEBUG_LOWPROBE, printf( - "failed to get device size\n")); - goto err; - } - } else if (S_ISCHR(sb.st_mode)) - pr->size = 1; /* UBI devices are char... */ - else if (S_ISREG(sb.st_mode)) - pr->size = sb.st_size; /* regular file */ - - if (pr->off > pr->size) - goto err; - - /* The probing area cannot be larger than whole device, pr->off - * is offset within the device */ - pr->size -= pr->off; - } - - if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode)) - pr->flags |= BLKID_FL_TINY_DEV; - -#ifdef CDROM_GET_CAPABILITY - if (S_ISBLK(sb.st_mode) && - !blkid_probe_is_tiny(pr) && - blkid_probe_is_wholedisk(pr) && - ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0) - pr->flags |= BLKID_FL_CDROM_DEV; -#endif - - DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%jd, size=%jd\n", - pr->off, pr->size)); - DBG(DEBUG_LOWPROBE, printf("whole-disk: %s, regfile: %s\n", - blkid_probe_is_wholedisk(pr) ?"YES" : "NO", - S_ISREG(pr->mode) ? "YES" : "NO")); - - return 0; -err: - DBG(DEBUG_LOWPROBE, - printf("failed to prepare a device for low-probing\n")); - return -1; - -} - -int blkid_probe_get_dimension(blkid_probe pr, - blkid_loff_t *off, blkid_loff_t *size) -{ - if (!pr) - return -1; - - *off = pr->off; - *size = pr->size; - return 0; -} - -int blkid_probe_set_dimension(blkid_probe pr, - blkid_loff_t off, blkid_loff_t size) -{ - if (!pr) - return -1; - - DBG(DEBUG_LOWPROBE, printf( - "changing probing area pr=%p: size=%llu, off=%llu " - "-to-> size=%llu, off=%llu\n", - pr, - (unsigned long long) pr->size, - (unsigned long long) pr->off, - (unsigned long long) size, - (unsigned long long) off)); - - pr->off = off; - pr->size = size; - pr->flags &= ~BLKID_FL_TINY_DEV; - - if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode)) - pr->flags |= BLKID_FL_TINY_DEV; - - blkid_probe_reset_buffer(pr); - - return 0; -} - -int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, - blkid_loff_t *offset, const struct blkid_idmag **res) -{ - const struct blkid_idmag *mag = NULL; - blkid_loff_t off = 0; - - if (id) - mag = &id->magics[0]; - if (res) - *res = NULL; - - /* try to detect by magic string */ - while(mag && mag->magic) { - unsigned char *buf; - - off = (mag->kboff + (mag->sboff >> 10)) << 10; - buf = blkid_probe_get_buffer(pr, off, 1024); - - if (buf && !memcmp(mag->magic, - buf + (mag->sboff & 0x3ff), mag->len)) { - DBG(DEBUG_LOWPROBE, printf( - "\tmagic sboff=%u, kboff=%ld\n", - mag->sboff, mag->kboff)); - if (offset) - *offset = off + (mag->sboff & 0x3ff); - if (res) - *res = mag; - return 0; - } - mag++; - } - - if (id && id->magics[0].magic) - /* magic string(s) defined, but not found */ - return 1; - - return 0; -} - -static inline void blkid_probe_start(blkid_probe pr) -{ - if (pr) { - DBG(DEBUG_LOWPROBE, printf("%p: start probe\n", pr)); - pr->cur_chain = NULL; - pr->prob_flags = 0; - blkid_probe_set_wiper(pr, 0, 0); - } -} - -static inline void blkid_probe_end(blkid_probe pr) -{ - if (pr) { - DBG(DEBUG_LOWPROBE, printf("%p: end probe\n", pr)); - pr->cur_chain = NULL; - pr->prob_flags = 0; - blkid_probe_set_wiper(pr, 0, 0); - } -} - -/** - * blkid_do_probe: - * @pr: prober - * - * Calls probing functions in all enabled chains. The superblocks chain is - * enabled by default. The blkid_do_probe() stores result from only one - * probing function. It's necessary to call this routine in a loop to get - * results from all probing functions in all chains. The probing is reset - * by blkid_reset_probe() or by filter functions. - * - * This is string-based NAME=value interface only. - * - * <example> - * <title>basic case - use the first result only</title> - * <programlisting> - * - * if (blkid_do_probe(pr) == 0) { - * int nvals = blkid_probe_numof_values(pr); - * for (n = 0; n < nvals; n++) { - * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) - * printf("%s = %s\n", name, data); - * } - * } - * </programlisting> - * </example> - * - * <example> - * <title>advanced case - probe for all signatures</title> - * <programlisting> - * - * while (blkid_do_probe(pr) == 0) { - * int nvals = blkid_probe_numof_values(pr); - * ... - * } - * </programlisting> - * </example> - * - * See also blkid_reset_probe(). - * - * Returns: 0 on success, 1 when probing is done and -1 in case of error. - */ -int blkid_do_probe(blkid_probe pr) -{ - int rc = 1; - - if (!pr) - return -1; - - do { - struct blkid_chain *chn = pr->cur_chain; - - if (!chn) { - blkid_probe_start(pr); - chn = pr->cur_chain = &pr->chains[0]; - } - /* we go to the next chain only when the previous probing - * result was nothing (rc == 1) and when the current chain is - * disabled or we are at end of the current chain (chain->idx + - * 1 == sizeof chain) or the current chain bailed out right at - * the start (chain->idx == -1) - */ - else if (rc == 1 && (chn->enabled == FALSE || - chn->idx + 1 == (int) chn->driver->nidinfos || - chn->idx == -1)) { - - size_t idx = chn->driver->id + 1; - - if (idx < BLKID_NCHAINS) - chn = pr->cur_chain = &pr->chains[idx]; - else { - blkid_probe_end(pr); - return 1; /* all chains already probed */ - } - } - - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain probe %s %s (idx=%d)\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED", - chn->idx)); - - if (!chn->enabled) - continue; - - /* rc: -1 = error, 0 = success, 1 = no result */ - rc = chn->driver->probe(pr, chn); - - } while (rc == 1); - - return rc; -} - -/** - * blkid_do_wipe: - * @pr: prober - * @dryrun: if TRUE then don't touch the device. - * - * This function erases the current signature detected by @pr. The @pr has to - * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags - * has to be enabled. - * - * After successful signature removing the @pr prober will be moved one step - * back and the next blkid_do_probe() call will again call previously called - * probing function. - * - * <example> - * <title>wipe all filesystems or raids from the device</title> - * <programlisting> - * fd = open(devname, O_RDWR|O_CLOEXEC); - * blkid_probe_set_device(pr, fd, 0, 0); - * - * blkid_probe_enable_superblocks(pr, 1); - * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); - * - * while (blkid_do_probe(pr) == 0) - * blkid_do_wipe(pr, FALSE); - * </programlisting> - * </example> - * - * See also blkid_probe_step_back() if you cannot use this build-in wipe - * function, but you want to use libblkid probing as a source for wiping. - * - * Returns: 0 on success, and -1 in case of error. - */ -int blkid_do_wipe(blkid_probe pr, int dryrun) -{ - const char *off = NULL; - size_t len = 0; - loff_t offset, l; - char buf[BUFSIZ]; - int fd, rc = 0; - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = pr->cur_chain; - if (!chn) - return -1; - - switch (chn->driver->id) { - case BLKID_CHAIN_SUBLKS: - rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); - if (!rc) - rc = blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); - break; - case BLKID_CHAIN_PARTS: - rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL); - if (!rc) - rc = blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); - break; - default: - return 0; - } - - if (rc || len == 0 || off == NULL) - return 0; - - offset = strtoll(off, NULL, 10); - fd = blkid_probe_get_fd(pr); - if (fd < 0) - return -1; - - if (len > sizeof(buf)) - len = sizeof(buf); - - DBG(DEBUG_LOWPROBE, printf( - "do_wipe [offset=0x%jx, len=%zd, chain=%s, idx=%d, dryrun=%s]\n", - offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not")); - - l = lseek(fd, offset, SEEK_SET); - if (l == (off_t) -1) - return -1; - - memset(buf, 0, len); - - if (!dryrun && len) { - if (write_all(fd, buf, len)) - return -1; - fsync(fd); - return blkid_probe_step_back(pr); - } - - return 0; -} - -/** - * blkid_probe_step_back(): - * @pr: prober - * - * This function move pointer to the probing chain one step back -- it means - * that the previously used probing function will be called again in the next - * blkid_do_probe() call. - * - * This is necessary for example if you erase or modify on-disk superblock - * according to the current libblkid probing result. - * - * <example> - * <title>wipe all superblock, but use libblkid only for probing</title> - * <programlisting> - * pr = blkid_new_probe_from_filename(devname); - * - * blkid_probe_enable_superblocks(pr, 1); - * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); - * - * while (blkid_do_probe(pr) == 0) { - * const char *ostr = NULL; - * size_t len = 0; - * - * // superblocks - * if (blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &ostr, NULL) == 0) - * blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); - * - * // partition tables - * if (len == 0 && blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &ostr, NULL) == 0) - * blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); - * - * if (!len || !str) - * continue; - * - * // convert ostr to the real offset by off = strtoll(ostr, NULL, 10); - * // use your stuff to errase @len bytes at the @off - * .... - * - * // retry the last probing to check for backup superblocks ..etc. - * blkid_probe_step_back(pr); - * } - * </programlisting> - * </example> - * - * Returns: 0 on success, and -1 in case of error. - */ -int blkid_probe_step_back(blkid_probe pr) -{ - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = pr->cur_chain; - if (!chn) - return -1; - - blkid_probe_reset_buffer(pr); - - if (chn->idx >= 0) { - chn->idx--; - DBG(DEBUG_LOWPROBE, - printf("step back: moving %s chain index to %d\n", - chn->driver->name, - chn->idx)); - } - - if (chn->idx == -1) { - /* blkid_do_probe() goes to the next chain if the index - * of the current chain is -1, so we have to set the - * chain pointer to the previous chain. - */ - size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0; - - DBG(DEBUG_LOWPROBE, printf("step back: moving to previous chain\n")); - - if (idx > 0) - pr->cur_chain = &pr->chains[idx]; - else if (idx == 0) - pr->cur_chain = NULL; - } - - return 0; -} - -/** - * blkid_do_safeprobe: - * @pr: prober - * - * This function gathers probing results from all enabled chains and checks - * for ambivalent results (e.g. more filesystems on the device). - * - * This is string-based NAME=value interface only. - * - * Note about suberblocks chain -- the function does not check for filesystems - * when a RAID signature is detected. The function also does not check for - * collision between RAIDs. The first detected RAID is returned. The function - * checks for collision between partition table and RAID signature -- it's - * recommended to enable partitions chain together with superblocks chain. - * - * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is - * detected and -1 on case of error. - */ -int blkid_do_safeprobe(blkid_probe pr) -{ - int i, count = 0, rc = 0; - - if (!pr) - return -1; - - blkid_probe_start(pr); - - pr->prob_flags |= BLKID_PROBE_FL_IGNORE_BACKUP; - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *chn; - - chn = pr->cur_chain = &pr->chains[i]; - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain safeprobe %s %s\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED")); - - if (!chn->enabled) - continue; - - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->safeprobe(pr, chn); - - blkid_probe_chain_reset_position(chn); - - /* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */ - if (rc < 0) - goto done; /* error */ - if (rc == 0) - count++; /* success */ - } - -done: - blkid_probe_end(pr); - if (rc < 0) - return rc; - return count ? 0 : 1; -} - -/** - * blkid_do_fullprobe: - * @pr: prober - * - * This function gathers probing results from all enabled chains. Same as - * blkid_do_safeprobe() but does not check for collision between probing - * result. - * - * This is string-based NAME=value interface only. - * - * Returns: 0 on success, 1 if nothing is detected or -1 on case of error. - */ -int blkid_do_fullprobe(blkid_probe pr) -{ - int i, count = 0, rc = 0; - - if (!pr) - return -1; - - blkid_probe_start(pr); - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *chn; - - chn = pr->cur_chain = &pr->chains[i]; - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain fullprobe %s: %s\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED")); - - if (!chn->enabled) - continue; - - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->probe(pr, chn); - - blkid_probe_chain_reset_position(chn); - - /* rc: -1 = error, 0 = success, 1 = no result */ - if (rc < 0) - goto done; /* error */ - if (rc == 0) - count++; /* success */ - } - -done: - blkid_probe_end(pr); - if (rc < 0) - return rc; - return count ? 0 : 1; -} - -/* same sa blkid_probe_get_buffer() but works with 512-sectors */ -unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) -{ - return pr ? blkid_probe_get_buffer(pr, - ((blkid_loff_t) sector) << 9, 0x200) : NULL; -} - -struct blkid_prval *blkid_probe_assign_value( - blkid_probe pr, const char *name) -{ - struct blkid_prval *v; - - if (!name) - return NULL; - if (pr->nvals >= BLKID_NVALS) - return NULL; - - v = &pr->vals[pr->nvals]; - v->name = name; - v->chain = pr->cur_chain; - pr->nvals++; - - DBG(DEBUG_LOWPROBE, - printf("assigning %s [%s]\n", name, v->chain->driver->name)); - return v; -} - -int blkid_probe_reset_last_value(blkid_probe pr) -{ - struct blkid_prval *v; - - if (pr == NULL || pr->nvals == 0) - return -1; - - v = &pr->vals[pr->nvals - 1]; - - DBG(DEBUG_LOWPROBE, - printf("un-assigning %s [%s]\n", v->name, v->chain->driver->name)); - - memset(v, 0, sizeof(struct blkid_prval)); - pr->nvals--; - - return 0; - -} - -int blkid_probe_set_value(blkid_probe pr, const char *name, - unsigned char *data, size_t len) -{ - struct blkid_prval *v; - - if (len > BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ; - - v = blkid_probe_assign_value(pr, name); - if (!v) - return -1; - - memcpy(v->data, data, len); - v->len = len; - return 0; -} - -int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, - const char *fmt, va_list ap) -{ - struct blkid_prval *v; - ssize_t len; - - v = blkid_probe_assign_value(pr, name); - if (!v) - return -1; - - len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); - - if (len <= 0 || (size_t) len >= sizeof(v->data)) { - blkid_probe_reset_last_value(pr); - return -1; - } - v->len = len + 1; - return 0; -} - -int blkid_probe_sprintf_value(blkid_probe pr, const char *name, - const char *fmt, ...) -{ - int rc; - va_list ap; - - va_start(ap, fmt); - rc = blkid_probe_vsprintf_value(pr, name, fmt, ap); - va_end(ap); - - return rc; -} - -int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset, - size_t len, unsigned char *magic) -{ - int rc = 0; - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - if (!chn || !magic || !len || chn->binary) - return 0; - - switch (chn->driver->id) { - case BLKID_CHAIN_SUBLKS: - if (!(chn->flags & BLKID_SUBLKS_MAGIC)) - return 0; - rc = blkid_probe_set_value(pr, "SBMAGIC", magic, len); - if (!rc) - rc = blkid_probe_sprintf_value(pr, - "SBMAGIC_OFFSET", "%llu", (unsigned long long)offset); - break; - case BLKID_CHAIN_PARTS: - if (!(chn->flags & BLKID_PARTS_MAGIC)) - return 0; - rc = blkid_probe_set_value(pr, "PTMAGIC", magic, len); - if (!rc) - rc = blkid_probe_sprintf_value(pr, - "PTMAGIC_OFFSET", "%llu", (unsigned long long)offset); - break; - default: - break; - } - - return rc; -} - -/** - * blkid_probe_get_devno: - * @pr: probe - * - * Returns: block device number, or 0 for regular files. - */ -dev_t blkid_probe_get_devno(blkid_probe pr) -{ - return pr->devno; -} - -/** - * blkid_probe_get_wholedisk_devno: - * @pr: probe - * - * Returns: device number of the wholedisk, or 0 for regular files. - */ -dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) -{ - if (!pr->disk_devno) { - dev_t devno, disk_devno = 0; - - devno = blkid_probe_get_devno(pr); - if (!devno) - return 0; - - if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk_devno) == 0) - pr->disk_devno = disk_devno; - } - return pr->disk_devno; -} - -/** - * blkid_probe_is_wholedisk: - * @pr: probe - * - * Returns: 1 if the device is whole-disk or 0. - */ -int blkid_probe_is_wholedisk(blkid_probe pr) -{ - dev_t devno, disk_devno; - - devno = blkid_probe_get_devno(pr); - if (!devno) - return 0; - - disk_devno = blkid_probe_get_wholedisk_devno(pr); - if (!disk_devno) - return 0; - - return devno == disk_devno; -} - -blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr) -{ - dev_t disk; - - if (blkid_probe_is_wholedisk(pr)) - return NULL; /* this is not partition */ - - if (pr->parent) - /* this is cloned blkid_probe, use parent's stuff */ - return blkid_probe_get_wholedisk_probe(pr->parent); - - disk = blkid_probe_get_wholedisk_devno(pr); - - if (pr->disk_probe && pr->disk_probe->devno != disk) { - /* we have disk prober, but for another disk... close it */ - blkid_free_probe(pr->disk_probe); - pr->disk_probe = NULL; - } - - if (!pr->disk_probe) { - /* Open a new disk prober */ - char *disk_path = blkid_devno_to_devname(disk); - - if (!disk_path) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a wholedisk probe\n")); - - pr->disk_probe = blkid_new_probe_from_filename(disk_path); - - free(disk_path); - - if (!pr->disk_probe) - return NULL; /* ENOMEM? */ - } - - return pr->disk_probe; -} - -/** - * blkid_probe_get_size: - * @pr: probe - * - * This function returns size of probing area as defined by blkid_probe_set_device(). - * If the size of the probing area is unrestricted then this function returns - * the real size of device. See also blkid_get_dev_size(). - * - * Returns: size in bytes or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_size(blkid_probe pr) -{ - return pr ? pr->size : -1; -} - -/** - * blkid_probe_get_offset: - * @pr: probe - * - * This function returns offset of probing area as defined by blkid_probe_set_device(). - * - * Returns: offset in bytes or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_offset(blkid_probe pr) -{ - return pr ? pr->off : -1; -} - -/** - * blkid_probe_get_fd: - * @pr: probe - * - * Returns: file descriptor for assigned device/file or -1 in case of error. - */ -int blkid_probe_get_fd(blkid_probe pr) -{ - return pr ? pr->fd : -1; -} - -/** - * blkid_probe_get_sectorsize: - * @pr: probe or NULL (for NULL returns 512) - * - * Returns: block device logical sector size (BLKSSZGET ioctl, default 512). - */ -unsigned int blkid_probe_get_sectorsize(blkid_probe pr) -{ - if (!pr) - return DEFAULT_SECTOR_SIZE; /*... and good luck! */ - - if (pr->blkssz) - return pr->blkssz; - - if (S_ISBLK(pr->mode) && - blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz) == 0) - return pr->blkssz; - - pr->blkssz = DEFAULT_SECTOR_SIZE; - return pr->blkssz; -} - -/** - * blkid_probe_get_sectors: - * @pr: probe - * - * Returns: 512-byte sector count or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_sectors(blkid_probe pr) -{ - return pr ? pr->size >> 9 : -1; -} - -/** - * blkid_probe_numof_values: - * @pr: probe - * - * Returns: number of values in probing result or -1 in case of error. - */ -int blkid_probe_numof_values(blkid_probe pr) -{ - if (!pr) - return -1; - return pr->nvals; -} - -/** - * blkid_probe_get_value: - * @pr: probe - * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1 - * @name: pointer to return value name or NULL - * @data: pointer to return value data or NULL - * @len: pointer to return value length or NULL - * - * Note, the @len returns length of the @data, including the terminating - * '\0' character. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_get_value(blkid_probe pr, int num, const char **name, - const char **data, size_t *len) -{ - struct blkid_prval *v = __blkid_probe_get_value(pr, num); - - if (!v) - return -1; - if (name) - *name = v->name; - if (data) - *data = (char *) v->data; - if (len) - *len = v->len; - - DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); - return 0; -} - -/** - * blkid_probe_lookup_value: - * @pr: probe - * @name: name of value - * @data: pointer to return value data or NULL - * @len: pointer to return value length or NULL - * - * Note, the @len returns length of the @data, including the terminating - * '\0' character. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_lookup_value(blkid_probe pr, const char *name, - const char **data, size_t *len) -{ - struct blkid_prval *v = __blkid_probe_lookup_value(pr, name); - - if (!v) - return -1; - if (data) - *data = (char *) v->data; - if (len) - *len = v->len; - return 0; -} - -/** - * blkid_probe_has_value: - * @pr: probe - * @name: name of value - * - * Returns: 1 if value exist in probing result, otherwise 0. - */ -int blkid_probe_has_value(blkid_probe pr, const char *name) -{ - if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) - return 1; - return 0; -} - -struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) -{ - if (!pr || num < 0 || num >= pr->nvals) - return NULL; - - return &pr->vals[num]; -} - -struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) -{ - int i; - - if (!pr || !pr->nvals || !name) - return NULL; - - for (i = 0; i < pr->nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->name && strcmp(name, v->name) == 0) { - DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); - return v; - } - } - return NULL; -} - - -/* converts DCE UUID (uuid[16]) to human readable string - * - the @len should be always 37 */ -#ifdef HAVE_LIBUUID -void blkid_unparse_uuid(const unsigned char *uuid, char *str, - size_t len __attribute__((__unused__))) -{ - uuid_unparse(uuid, str); -} -#else -void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) -{ - snprintf(str, len, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], - uuid[6], uuid[7], - uuid[8], uuid[9], - uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); -} -#endif - - -/* Removes whitespace from the right-hand side of a string (trailing - * whitespace). - * - * Returns size of the new string (without \0). - */ -size_t blkid_rtrim_whitespace(unsigned char *str) -{ - size_t i = strlen((char *) str); - - while (i--) { - if (!isspace(str[i])) - break; - } - str[++i] = '\0'; - return i; -} - -/* Removes whitespace from the left-hand side of a string. - * - * Returns size of the new string (without \0). - */ -size_t blkid_ltrim_whitespace(unsigned char *str) -{ - size_t len; - unsigned char *p; - - for (p = str; p && isspace(*p); p++); - - len = strlen((char *) p); - - if (len && p > str) - memmove(str, p, len + 1); - - return len; -} -/* - * Some mkfs-like utils wipe some parts (usually begin) of the device. - * For example LVM (pvcreate) or mkswap(8). This information could be used - * for later resolution to conflicts between superblocks. - * - * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of - * the device. If we found another signature (for example MBR) within the - * wiped area then the signature has been added later and LVM superblock - * should be ignore. - * - * Note that this heuristic is not 100% reliable, for example "pvcreate --zero - * n" allows to keep the begin of the device unmodified. It's probably better - * to use this heuristic for conflicts between superblocks and partition tables - * than for conflicts between filesystem superblocks -- existence of unwanted - * partition table is very unusual, because PT is pretty visible (parsed and - * interpreted by kernel). - * - * Note that we usually expect only one signature on the device, it means that - * we have to remember only one wiped area from previously successfully - * detected signature. - * - * blkid_probe_set_wiper() -- defines wiped area (e.g. LVM) - * blkid_probe_use_wiper() -- try to use area (e.g. MBR) - * - * Note that there is not relation between _wiper and blkid_to_wipe(). - * - */ -void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) -{ - struct blkid_chain *chn; - - if (!pr) - return; - - if (!size) { - DBG(DEBUG_LOWPROBE, printf("zeroize wiper\n")); - pr->wipe_size = pr->wipe_off = 0; - pr->wipe_chain = NULL; - return; - } - - chn = pr->cur_chain; - - if (!chn || !chn->driver || - chn->idx < 0 || (size_t) chn->idx >= chn->driver->nidinfos) - return; - - pr->wipe_size = size; - pr->wipe_off = off; - pr->wipe_chain = chn; - - DBG(DEBUG_LOWPROBE, - printf("wiper set to %s::%s off=%jd size=%jd\n", - chn->driver->name, - chn->driver->idinfos[chn->idx]->name, - pr->wipe_off, pr->wipe_size)); - return; -} - -/* - * Returns 1 if the <@off,@size> area was wiped - */ -int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, - blkid_loff_t off, blkid_loff_t size) -{ - if (!pr || !size) - return 0; - - if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) { - if (chn) - *chn = pr->wipe_chain; - return 1; - } - return 0; -} - -/* - * Try to use any area -- if the area has been previously wiped then the - * previous probing result should be ignored (reseted). - */ -void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) -{ - struct blkid_chain *chn = NULL; - - if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) { - DBG(DEBUG_LOWPROBE, printf("previously wiped area modified " - " -- ignore previous results\n")); - blkid_probe_set_wiper(pr, 0, 0); - blkid_probe_chain_reset_vals(pr, chn); - } -} - -int blkid_probe_ignore_backup(blkid_probe pr) -{ - return pr && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_BACKUP); -} diff --git a/libblkid/procutils.c b/libblkid/procutils.c deleted file mode 100644 index 52e9ee383..000000000 --- a/libblkid/procutils.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org> - * - * procutils.c: General purpose procfs parsing utilities - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program 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 Library Public License for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <dirent.h> -#include <ctype.h> - -#include "procutils.h" -#include "c.h" - -/* - * @pid: process ID for which we want to obtain the threads group - * - * Returns: newly allocated tasks structure - */ -struct proc_tasks *proc_open_tasks(pid_t pid) -{ - struct proc_tasks *tasks; - char path[PATH_MAX]; - - sprintf(path, "/proc/%d/task/", pid); - - tasks = malloc(sizeof(struct proc_tasks)); - if (tasks) { - tasks->dir = opendir(path); - if (tasks->dir) - return tasks; - } - - free(tasks); - return NULL; -} - -/* - * @tasks: allocated tasks structure - * - * Returns: nothing - */ -void proc_close_tasks(struct proc_tasks *tasks) -{ - if (tasks && tasks->dir) - closedir(tasks->dir); - free(tasks); -} - -/* - * @tasks: allocated task structure - * @tid: [output] one of the thread IDs belonging to the thread group - * If when an error occurs, it is set to 0. - * - * Returns: 0 on success, 1 on end, -1 on failure or no more threads - */ -int proc_next_tid(struct proc_tasks *tasks, pid_t *tid) -{ - struct dirent *d; - char *end; - - if (!tasks || !tid) - return -1; - - *tid = 0; - errno = 0; - - do { - d = readdir(tasks->dir); - if (!d) - return errno ? -1 : 1; /* error or end-of-dir */ - - if (!isdigit((unsigned char) *d->d_name)) - continue; - - *tid = (pid_t) strtol(d->d_name, &end, 10); - if (errno || d->d_name == end || (end && *end)) - return -1; - - } while (!*tid); - - return 0; -} - -#ifdef TEST_PROGRAM - -int main(int argc, char *argv[]) -{ - pid_t tid, pid; - struct proc_tasks *ts; - - if (argc != 2) { - fprintf(stderr, "usage: %s <pid>\n", argv[0]); - return EXIT_FAILURE; - } - - pid = strtol(argv[1], (char **) NULL, 10); - printf("PID=%d, TIDs:", pid); - - ts = proc_open_tasks(pid); - if (!ts) - err(EXIT_FAILURE, "open list of tasks failed"); - - while (proc_next_tid(ts, &tid) == 0) - printf(" %d", tid); - - printf("\n"); - proc_close_tasks(ts); - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/libblkid/procutils.h b/libblkid/procutils.h deleted file mode 100644 index ca7087a2b..000000000 --- a/libblkid/procutils.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef UTIL_LINUX_PROCUTILS -#define UTIL_LINUX_PROCUTILS - -#include <dirent.h> - -struct proc_tasks { - DIR *dir; -}; - -extern struct proc_tasks *proc_open_tasks(pid_t pid); -extern void proc_close_tasks(struct proc_tasks *tasks); -extern int proc_next_tid(struct proc_tasks *tasks, pid_t *tid); - -#endif /* UTIL_LINUX_PROCUTILS */ diff --git a/libblkid/promise_raid.c b/libblkid/promise_raid.c deleted file mode 100644 index 01e4e3752..000000000 --- a/libblkid/promise_raid.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -struct promise_metadata { - uint8_t sig[24]; -}; - -#define PDC_CONFIG_OFF 0x1200 -#define PDC_SIGNATURE "Promise Technology, Inc." - -static int probe_pdcraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - unsigned int i; - static unsigned int sectors[] = { - 63, 255, 256, 16, 399, 591, 675, 735, 911, 974, 991, 951, 3087, 0 - }; - - if (pr->size < 0x40000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - for (i = 0; sectors[i] != 0; i++) { - uint64_t off; - struct promise_metadata *pdc; - - off = ((pr->size / 0x200) - sectors[i]) * 0x200; - pdc = (struct promise_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct promise_metadata)); - if (!pdc) - return -1; - - if (memcmp(pdc->sig, PDC_SIGNATURE, - sizeof(PDC_SIGNATURE) - 1) == 0) { - - if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig), - (unsigned char *) pdc->sig)) - return -1; - return 0; - } - } - return -1; -} - -const struct blkid_idinfo pdcraid_idinfo = { - .name = "promise_fasttrack_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_pdcraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/randutils.c b/libblkid/randutils.c deleted file mode 100644 index 80893d3db..000000000 --- a/libblkid/randutils.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * General purpose random utilities - * - * Based on libuuid code. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> - -#include <sys/syscall.h> - -#include "randutils.h" - -#ifdef HAVE_TLS -#define THREAD_LOCAL static __thread -#else -#define THREAD_LOCAL static -#endif - -#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48) -#define DO_JRAND_MIX -THREAD_LOCAL unsigned short ul_jrand_seed[3]; -#endif - -int random_get_fd(void) -{ - int i, fd; - struct timeval tv; - - gettimeofday(&tv, 0); - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - fd = open("/dev/random", O_RDONLY | O_NONBLOCK); - if (fd >= 0) { - i = fcntl(fd, F_GETFD); - if (i >= 0) - fcntl(fd, F_SETFD, i | FD_CLOEXEC); - } - srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); - -#ifdef DO_JRAND_MIX - ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF); - ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF); - ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16; -#endif - /* Crank the random number generator a few times */ - gettimeofday(&tv, 0); - for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) - rand(); - return fd; -} - - -/* - * Generate a stream of random nbytes into buf. - * Use /dev/urandom if possible, and if not, - * use glibc pseudo-random functions. - */ -void random_get_bytes(void *buf, size_t nbytes) -{ - size_t i, n = nbytes; - int fd = random_get_fd(); - int lose_counter = 0; - unsigned char *cp = (unsigned char *) buf; - - if (fd >= 0) { - while (n > 0) { - ssize_t x = read(fd, cp, n); - if (x <= 0) { - if (lose_counter++ > 16) - break; - continue; - } - n -= x; - cp += x; - lose_counter = 0; - } - - close(fd); - } - - /* - * We do this all the time, but this is the only source of - * randomness if /dev/random/urandom is out to lunch. - */ - for (cp = buf, i = 0; i < nbytes; i++) - *cp++ ^= (rand() >> 7) & 0xFF; - -#ifdef DO_JRAND_MIX - { - unsigned short tmp_seed[3]; - - memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed)); - ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid); - for (cp = buf, i = 0; i < nbytes; i++) - *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF; - memcpy(ul_jrand_seed, tmp_seed, - sizeof(ul_jrand_seed)-sizeof(unsigned short)); - } -#endif - - return; -} - -#ifdef TEST_PROGRAM -int main(int argc __attribute__ ((__unused__)), - char *argv[] __attribute__ ((__unused__))) -{ - unsigned int v, i; - - /* generate and print 10 random numbers */ - for (i = 0; i < 10; i++) { - random_get_bytes(&v, sizeof(v)); - printf("%d\n", v); - } - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/libblkid/randutils.h b/libblkid/randutils.h deleted file mode 100644 index dec5e355a..000000000 --- a/libblkid/randutils.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef UTIL_LINUX_RANDUTILS -#define UTIL_LINUX_RANDUTILS - -#ifdef HAVE_SRANDOM -#define srand(x) srandom(x) -#define rand() random() -#endif - -extern int random_get_fd(void); -extern void random_get_bytes(void *buf, size_t nbytes); - -#endif diff --git a/libblkid/read.c b/libblkid/read.c deleted file mode 100644 index 8914cad69..000000000 --- a/libblkid/read.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * read.c - read the blkid cache from disk, to avoid scanning all devices - * - * Copyright (C) 2001, 2003 Theodore Y. Ts'o - * Copyright (C) 2001 Andreas Dilger - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - - -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -#include "blkidP.h" - -#ifdef HAVE_STDLIB_H -# ifndef _XOPEN_SOURCE -# define _XOPEN_SOURCE 600 /* for inclusion of strtoull */ -# endif -# include <stdlib.h> -#endif - -#ifdef HAVE_STRTOULL -#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */ -#else -/* FIXME: need to support real strtoull here */ -#define STRTOULL strtoul -#endif - -#ifdef TEST_PROGRAM -#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev)) -static void debug_dump_dev(blkid_dev dev); -#endif - -/* - * File format: - * - * <device [<NAME="value"> ...]>device_name</device> - * - * The following tags are required for each entry: - * <ID="id"> unique (within this file) ID number of this device - * <TIME="sec.usec"> (time_t and suseconds_t) time this entry was last - * read from disk - * <TYPE="type"> (detected) type of filesystem/data for this partition - * - * The following tags may be present, depending on the device contents - * <LABEL="label"> (user supplied) label (volume name, etc) - * <UUID="uuid"> (generated) universally unique identifier (serial no) - */ - -static char *skip_over_blank(char *cp) -{ - while (*cp && isspace(*cp)) - cp++; - return cp; -} - -static char *skip_over_word(char *cp) -{ - char ch; - - while ((ch = *cp)) { - /* If we see a backslash, skip the next character */ - if (ch == '\\') { - cp++; - if (*cp == '\0') - break; - cp++; - continue; - } - if (isspace(ch) || ch == '<' || ch == '>') - break; - cp++; - } - return cp; -} - -static char *strip_line(char *line) -{ - char *p; - - line = skip_over_blank(line); - - p = line + strlen(line) - 1; - - while (*line) { - if (isspace(*p)) - *p-- = '\0'; - else - break; - } - - return line; -} - -#if 0 -static char *parse_word(char **buf) -{ - char *word, *next; - - word = *buf; - if (*word == '\0') - return NULL; - - word = skip_over_blank(word); - next = skip_over_word(word); - if (*next) { - char *end = next - 1; - if (*end == '"' || *end == '\'') - *end = '\0'; - *next++ = '\0'; - } - *buf = next; - - if (*word == '"' || *word == '\'') - word++; - return word; -} -#endif - -/* - * Start parsing a new line from the cache. - * - * line starts with "<device" return 1 -> continue parsing line - * line starts with "<foo", empty, or # return 0 -> skip line - * line starts with other, return -BLKID_ERR_CACHE -> error - */ -static int parse_start(char **cp) -{ - char *p; - - p = strip_line(*cp); - - /* Skip comment or blank lines. We can't just NUL the first '#' char, - * in case it is inside quotes, or escaped. - */ - if (*p == '\0' || *p == '#') - return 0; - - if (!strncmp(p, "<device", 7)) { - DBG(DEBUG_READ, printf("found device header: %8s\n", p)); - p += 7; - - *cp = p; - return 1; - } - - if (*p == '<') - return 0; - - return -BLKID_ERR_CACHE; -} - -/* Consume the remaining XML on the line (cosmetic only) */ -static int parse_end(char **cp) -{ - *cp = skip_over_blank(*cp); - - if (!strncmp(*cp, "</device>", 9)) { - DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp)); - *cp += 9; - return 0; - } - - return -BLKID_ERR_CACHE; -} - -/* - * Allocate a new device struct with device name filled in. Will handle - * finding the device on lines of the form: - * <device foo=bar>devname</device> - * <device>devname<foo>bar</foo></device> - */ -static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp) -{ - char *start, *tmp, *end, *name; - int ret; - - if ((ret = parse_start(cp)) <= 0) - return ret; - - start = tmp = strchr(*cp, '>'); - if (!start) { - DBG(DEBUG_READ, - printf("blkid: short line parsing dev: %s\n", *cp)); - return -BLKID_ERR_CACHE; - } - start = skip_over_blank(start + 1); - end = skip_over_word(start); - - DBG(DEBUG_READ, printf("device should be %*s\n", - (int)(end - start), start)); - - if (**cp == '>') - *cp = end; - else - (*cp)++; - - *tmp = '\0'; - - if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) { - DBG(DEBUG_READ, - printf("blkid: missing </device> ending: %s\n", end)); - } else if (tmp) - *tmp = '\0'; - - if (end - start <= 1) { - DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp)); - return -BLKID_ERR_CACHE; - } - - name = strndup(start, end - start); - if (name == NULL) - return -BLKID_ERR_MEM; - - DBG(DEBUG_READ, printf("found dev %s\n", name)); - - if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) { - free(name); - return -BLKID_ERR_MEM; - } - - free(name); - return 1; -} - -/* - * Extract a tag of the form NAME="value" from the line. - */ -static int parse_token(char **name, char **value, char **cp) -{ - char *end; - - if (!name || !value || !cp) - return -BLKID_ERR_PARAM; - - if (!(*value = strchr(*cp, '='))) - return 0; - - **value = '\0'; - *name = strip_line(*cp); - *value = skip_over_blank(*value + 1); - - if (**value == '"') { - end = strchr(*value + 1, '"'); - if (!end) { - DBG(DEBUG_READ, - printf("unbalanced quotes at: %s\n", *value)); - *cp = *value; - return -BLKID_ERR_CACHE; - } - (*value)++; - *end = '\0'; - end++; - } else { - end = skip_over_word(*value); - if (*end) { - *end = '\0'; - end++; - } - } - *cp = end; - - return 1; -} - -/* - * Extract a tag of the form <NAME>value</NAME> from the line. - */ -/* -static int parse_xml(char **name, char **value, char **cp) -{ - char *end; - - if (!name || !value || !cp) - return -BLKID_ERR_PARAM; - - *name = strip_line(*cp); - - if ((*name)[0] != '<' || (*name)[1] == '/') - return 0; - - FIXME: finish this. -} -*/ - -/* - * Extract a tag from the line. - * - * Return 1 if a valid tag was found. - * Return 0 if no tag found. - * Return -ve error code. - */ -static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp) -{ - char *name = NULL; - char *value = NULL; - int ret; - - if (!cache || !dev) - return -BLKID_ERR_PARAM; - - if ((ret = parse_token(&name, &value, cp)) <= 0 /* && - (ret = parse_xml(&name, &value, cp)) <= 0 */) - return ret; - - /* Some tags are stored directly in the device struct */ - if (!strcmp(name, "DEVNO")) - dev->bid_devno = STRTOULL(value, 0, 0); - else if (!strcmp(name, "PRI")) - dev->bid_pri = strtol(value, 0, 0); - else if (!strcmp(name, "TIME")) { - char *end = NULL; - dev->bid_time = STRTOULL(value, &end, 0); - if (end && *end == '.') - dev->bid_utime = STRTOULL(end + 1, 0, 0); - } else - ret = blkid_set_tag(dev, name, value, strlen(value)); - - DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value)); - - return ret < 0 ? ret : 1; -} - -/* - * Parse a single line of data, and return a newly allocated dev struct. - * Add the new device to the cache struct, if one was read. - * - * Lines are of the form <device [TAG="value" ...]>/dev/foo</device> - * - * Returns -ve value on error. - * Returns 0 otherwise. - * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL - * (e.g. comment lines, unknown XML content, etc). - */ -static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp) -{ - blkid_dev dev; - int ret; - - if (!cache || !dev_p) - return -BLKID_ERR_PARAM; - - *dev_p = NULL; - - DBG(DEBUG_READ, printf("line: %s\n", cp)); - - if ((ret = parse_dev(cache, dev_p, &cp)) <= 0) - return ret; - - dev = *dev_p; - - while ((ret = parse_tag(cache, dev, &cp)) > 0) { - ; - } - - if (dev->bid_type == NULL) { - DBG(DEBUG_READ, - printf("blkid: device %s has no TYPE\n",dev->bid_name)); - blkid_free_dev(dev); - goto done; - } - - DBG(DEBUG_READ, blkid_debug_dump_dev(dev)); - -done: - return ret; -} - -/* - * Parse the specified filename, and return the data in the supplied or - * a newly allocated cache struct. If the file doesn't exist, return a - * new empty cache struct. - */ -void blkid_read_cache(blkid_cache cache) -{ - FILE *file; - char buf[4096]; - int fd, lineno = 0; - struct stat st; - - if (!cache) - return; - - /* - * If the file doesn't exist, then we just return an empty - * struct so that the cache can be populated. - */ - if ((fd = open(cache->bic_filename, O_RDONLY|O_CLOEXEC)) < 0) - return; - if (fstat(fd, &st) < 0) - goto errout; - if ((st.st_mtime == cache->bic_ftime) || - (cache->bic_flags & BLKID_BIC_FL_CHANGED)) { - DBG(DEBUG_CACHE, printf("skipping re-read of %s\n", - cache->bic_filename)); - goto errout; - } - - DBG(DEBUG_CACHE, printf("reading cache file %s\n", - cache->bic_filename)); - - file = fdopen(fd, "r"); - if (!file) - goto errout; - - while (fgets(buf, sizeof(buf), file)) { - blkid_dev dev; - unsigned int end; - - lineno++; - if (buf[0] == 0) - continue; - end = strlen(buf) - 1; - /* Continue reading next line if it ends with a backslash */ - while (end < (sizeof(buf) - 2) && buf[end] == '\\' && - fgets(buf + end, sizeof(buf) - end, file)) { - end = strlen(buf) - 1; - lineno++; - } - - if (blkid_parse_line(cache, &dev, buf) < 0) { - DBG(DEBUG_READ, - printf("blkid: bad format on line %d\n", lineno)); - continue; - } - } - fclose(file); - - /* - * Initially we do not need to write out the cache file. - */ - cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; - cache->bic_ftime = st.st_mtime; - - return; -errout: - close(fd); - return; -} - -#ifdef TEST_PROGRAM -static void debug_dump_dev(blkid_dev dev) -{ - struct list_head *p; - - if (!dev) { - printf(" dev: NULL\n"); - return; - } - - printf(" dev: name = %s\n", dev->bid_name); - printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); - printf(" dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); - printf(" dev: PRI=\"%d\"\n", dev->bid_pri); - printf(" dev: flags = 0x%08X\n", dev->bid_flags); - - list_for_each(p, &dev->bid_tags) { - blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); - if (tag) - printf(" tag: %s=\"%s\"\n", tag->bit_name, - tag->bit_val); - else - printf(" tag: NULL\n"); - } - printf("\n"); -} - -int main(int argc, char**argv) -{ - blkid_cache cache = NULL; - int ret; - - blkid_init_debug(DEBUG_ALL); - if (argc > 2) { - fprintf(stderr, "Usage: %s [filename]\n" - "Test parsing of the cache (filename)\n", argv[0]); - exit(1); - } - if ((ret = blkid_get_cache(&cache, argv[1])) < 0) - fprintf(stderr, "error %d reading cache file %s\n", ret, - argv[1] ? argv[1] : blkid_get_cache_filename(NULL)); - - blkid_put_cache(cache); - - return ret; -} -#endif diff --git a/libblkid/reiserfs.c b/libblkid/reiserfs.c deleted file mode 100644 index 152571f47..000000000 --- a/libblkid/reiserfs.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 1999, 2001 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -struct reiserfs_super_block { - uint32_t rs_blocks_count; - uint32_t rs_free_blocks; - uint32_t rs_root_block; - uint32_t rs_journal_block; - uint32_t rs_journal_dev; - uint32_t rs_orig_journal_size; - uint32_t rs_dummy2[5]; - uint16_t rs_blocksize; - uint16_t rs_dummy3[3]; - unsigned char rs_magic[12]; - uint32_t rs_dummy4[5]; - unsigned char rs_uuid[16]; - char rs_label[16]; -} __attribute__((packed)); - -struct reiser4_super_block { - unsigned char rs4_magic[16]; - uint16_t rs4_dummy[2]; - unsigned char rs4_uuid[16]; - unsigned char rs4_label[16]; - uint64_t rs4_dummy2; -} __attribute__((packed)); - -static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct reiserfs_super_block *rs; - unsigned int blocksize; - - rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block); - if (!rs) - return -1; - - blocksize = le16_to_cpu(rs->rs_blocksize); - - /* The blocksize must be at least 512B */ - if ((blocksize >> 9) == 0) - return -BLKID_ERR_PARAM; - - /* If the superblock is inside the journal, we have the wrong one */ - if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2) - return -BLKID_ERR_BIG; - - /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ - if (mag->magic[6] == '2' || mag->magic[6] == '3') { - if (*rs->rs_label) - blkid_probe_set_label(pr, - (unsigned char *) rs->rs_label, - sizeof(rs->rs_label)); - blkid_probe_set_uuid(pr, rs->rs_uuid); - } - - if (mag->magic[6] == '3') - blkid_probe_set_version(pr, "JR"); - else if (mag->magic[6] == '2') - blkid_probe_set_version(pr, "3.6"); - else - blkid_probe_set_version(pr, "3.5"); - - return 0; -} - -static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct reiser4_super_block *rs4; - - rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block); - if (!rs4) - return -1; - - if (*rs4->rs4_label) - blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label)); - blkid_probe_set_uuid(pr, rs4->rs4_uuid); - blkid_probe_set_version(pr, "4"); - - return 0; -} - - -const struct blkid_idinfo reiser_idinfo = -{ - .name = "reiserfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_reiser, - .minsz = 128 * 1024, - .magics = - { - { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 0x34 }, - { .magic = "ReIsEr2Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, - { .magic = "ReIsEr3Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, - { .magic = "ReIsErFs", .len = 8, .kboff = 64, .sboff = 0x34 }, - { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 20 }, - { NULL } - } -}; - -const struct blkid_idinfo reiser4_idinfo = -{ - .name = "reiser4", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_reiser4, - .minsz = 128 * 1024, - .magics = - { - { .magic = "ReIsEr4", .len = 7, .kboff = 64 }, - { NULL } - } -}; - - - - diff --git a/libblkid/resolve.c b/libblkid/resolve.c deleted file mode 100644 index 96749b3ec..000000000 --- a/libblkid/resolve.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * resolve.c - resolve names and tags into specific devices - * - * Copyright (C) 2001, 2003 Theodore Ts'o. - * Copyright (C) 2001 Andreas Dilger - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#include <stdio.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "blkidP.h" - -/* - * Find a tagname (e.g. LABEL or UUID) on a specific device. - */ -char *blkid_get_tag_value(blkid_cache cache, const char *tagname, - const char *devname) -{ - blkid_tag found; - blkid_dev dev; - blkid_cache c = cache; - char *ret = NULL; - - DBG(DEBUG_RESOLVE, printf("looking for %s on %s\n", tagname, devname)); - - if (!devname) - return NULL; - if (!cache && blkid_get_cache(&c, NULL) < 0) - return NULL; - - if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) && - (found = blkid_find_tag_dev(dev, tagname))) - ret = found->bit_val ? strdup(found->bit_val) : NULL; - - if (!cache) - blkid_put_cache(c); - - return ret; -} - -/* - * Locate a device name from a token (NAME=value string), or (name, value) - * pair. In the case of a token, value is ignored. If the "token" is not - * of the form "NAME=value" and there is no value given, then it is assumed - * to be the actual devname and a copy is returned. - */ -char *blkid_get_devname(blkid_cache cache, const char *token, - const char *value) -{ - blkid_dev dev; - blkid_cache c = cache; - char *t = 0, *v = 0; - char *ret = NULL; - - if (!token) - return NULL; - if (!cache && blkid_get_cache(&c, NULL) < 0) - return NULL; - - DBG(DEBUG_RESOLVE, - printf("looking for %s%s%s %s\n", token, value ? "=" : "", - value ? value : "", cache ? "in cache" : "from disk")); - - if (!value) { - if (!strchr(token, '=')) { - ret = strdup(token); - goto out; - } - blkid_parse_tag_string(token, &t, &v); - if (!t || !v) - goto out; - token = t; - value = v; - } - - dev = blkid_find_dev_with_tag(c, token, value); - if (!dev) - goto out; - - ret = dev->bid_name ? strdup(dev->bid_name) : NULL; -out: - free(t); - free(v); - if (!cache) - blkid_put_cache(c); - return ret; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - char *value; - blkid_cache cache; - - blkid_init_debug(DEBUG_ALL); - if (argc != 2 && argc != 3) { - fprintf(stderr, "Usage:\t%s tagname=value\n" - "\t%s tagname devname\n" - "Find which device holds a given token or\n" - "Find what the value of a tag is in a device\n", - argv[0], argv[0]); - exit(1); - } - if (blkid_get_cache(&cache, "/dev/null") < 0) { - fprintf(stderr, "Couldn't get blkid cache\n"); - exit(1); - } - - if (argv[2]) { - value = blkid_get_tag_value(cache, argv[1], argv[2]); - printf("%s has tag %s=%s\n", argv[2], argv[1], - value ? value : "<missing>"); - } else { - value = blkid_get_devname(cache, argv[1], NULL); - printf("%s has tag %s\n", value ? value : "<none>", argv[1]); - } - blkid_put_cache(cache); - return value ? 0 : 1; -} -#endif diff --git a/libblkid/romfs.c b/libblkid/romfs.c deleted file mode 100644 index 91ef996fe..000000000 --- a/libblkid/romfs.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 1999, 2001 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -struct romfs_super_block { - unsigned char ros_magic[8]; - uint32_t ros_dummy1[2]; - unsigned char ros_volume[16]; -} __attribute__((packed)); - -static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct romfs_super_block *ros; - - ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block); - if (!ros) - return -1; - - if (strlen((char *) ros->ros_volume)) - blkid_probe_set_label(pr, ros->ros_volume, - sizeof(ros->ros_volume)); - return 0; -} - -const struct blkid_idinfo romfs_idinfo = -{ - .name = "romfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_romfs, - .magics = - { - { .magic = "-rom1fs-", .len = 8 }, - { NULL } - } -}; - diff --git a/libblkid/samples/.gitignore b/libblkid/samples/.gitignore new file mode 100644 index 000000000..4efeb622f --- /dev/null +++ b/libblkid/samples/.gitignore @@ -0,0 +1,4 @@ +mkfs +partitions +superblocks +topology diff --git a/libblkid/samples/Makemodule.am b/libblkid/samples/Makemodule.am new file mode 100644 index 000000000..0ffbf1477 --- /dev/null +++ b/libblkid/samples/Makemodule.am @@ -0,0 +1,22 @@ + +check_PROGRAMS += \ + sample-mkfs \ + sample-partitions \ + sample-superblocks \ + sample-topology + +sample_mkfs_SOURCES = libblkid/samples/mkfs.c +sample_mkfs_LDADD = libblkid.la +sample_mkfs_CFLAGS = -I$(ul_libblkid_incdir) + +sample_partitions_SOURCES = libblkid/samples/partitions.c +sample_partitions_LDADD = libblkid.la +sample_partitions_CFLAGS = -I$(ul_libblkid_incdir) + +sample_superblocks_SOURCES = libblkid/samples/superblocks.c +sample_superblocks_LDADD = libblkid.la +sample_superblocks_CFLAGS = -I$(ul_libblkid_incdir) + +sample_topology_SOURCES = libblkid/samples/topology.c +sample_topology_LDADD = libblkid.la +sample_topology_CFLAGS = -I$(ul_libblkid_incdir) diff --git a/libblkid/samples/mkfs.c b/libblkid/samples/mkfs.c new file mode 100644 index 000000000..5c3ebe79e --- /dev/null +++ b/libblkid/samples/mkfs.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <blkid.h> + +#include "c.h" + +int main(int argc, char *argv[]) +{ + int rc; + char *devname; + blkid_probe pr; + blkid_topology tp; + + if (argc < 2) { + fprintf(stderr, "usage: %s <device> " + "-- checks based on libblkid for mkfs-like programs.\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + devname = argv[1]; + pr = blkid_new_probe_from_filename(devname); + if (!pr) + err(EXIT_FAILURE, "%s: faild to create a new libblkid probe", + devname); + + /* + * check Filesystems / Partitions overwrite + */ + + /* enable partitions probing (superblocks are enabled by default) */ + blkid_probe_enable_partitions(pr, TRUE); + + rc = blkid_do_fullprobe(pr); + if (rc == -1) + errx(EXIT_FAILURE, "%s: blkid_do_fullprobe() failed", devname); + else if (rc == 0) { + const char *type; + + if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) + errx(EXIT_FAILURE, "%s: appears to contain an existing " + "%s superblock", devname, type); + + if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) + errx(EXIT_FAILURE, "%s: appears to contain an partition " + "table (%s)", devname, type); + } + + /* + * get topology details + */ + tp = blkid_probe_get_topology(pr); + if (!tp) + errx(EXIT_FAILURE, "%s: failed to read topology", devname); + + + /* ... your mkfs.<type> code or so ... + + off = blkid_topology_get_alignment_offset(tp); + + */ + + blkid_free_probe(pr); + + return EXIT_SUCCESS; +} diff --git a/libblkid/samples/partitions.c b/libblkid/samples/partitions.c new file mode 100644 index 000000000..fe0ad4827 --- /dev/null +++ b/libblkid/samples/partitions.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <blkid.h> +#include "c.h" + +int main(int argc, char *argv[]) +{ + int i, nparts; + char *devname; + blkid_probe pr; + blkid_partlist ls; + blkid_parttable root_tab; + + if (argc < 2) { + fprintf(stderr, "usage: %s <device|file> " + "-- prints partitions\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + devname = argv[1]; + pr = blkid_new_probe_from_filename(devname); + if (!pr) + err(EXIT_FAILURE, "%s: faild to create a new libblkid probe", + devname); + /* Binary interface */ + ls = blkid_probe_get_partitions(pr); + if (!ls) + errx(EXIT_FAILURE, "%s: failed to read partitions\n", devname); + + /* + * Print info about the primary (root) partition table + */ + root_tab = blkid_partlist_get_table(ls); + if (!root_tab) + errx(EXIT_FAILURE, "%s: does not contains any " + "known partition table\n", devname); + + printf("size: %jd, sector size: %u, PT: %s, offset: %jd, id=%s\n---\n", + blkid_probe_get_size(pr), + blkid_probe_get_sectorsize(pr), + blkid_parttable_get_type(root_tab), + blkid_parttable_get_offset(root_tab), + blkid_parttable_get_id(root_tab)); + + /* + * List partitions + */ + nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + goto done; + + for (i = 0; i < nparts; i++) { + const char *p; + blkid_partition par = blkid_partlist_get_partition(ls, i); + blkid_parttable tab = blkid_partition_get_table(par); + + printf("#%d: %10llu %10llu 0x%x", + blkid_partition_get_partno(par), + (unsigned long long) blkid_partition_get_start(par), + (unsigned long long) blkid_partition_get_size(par), + blkid_partition_get_type(par)); + + if (root_tab != tab) + /* subpartition (BSD, Minix, ...) */ + printf(" (%s)", blkid_parttable_get_type(tab)); + + p = blkid_partition_get_name(par); + if (p) + printf(" name='%s'", p); + p = blkid_partition_get_uuid(par); + if (p) + printf(" uuid='%s'", p); + p = blkid_partition_get_type_string(par); + if (p) + printf(" type='%s'", p); + + putc('\n', stdout); + } + +done: + blkid_free_probe(pr); + return EXIT_SUCCESS; +} diff --git a/libblkid/samples/superblocks.c b/libblkid/samples/superblocks.c new file mode 100644 index 000000000..20e39c97e --- /dev/null +++ b/libblkid/samples/superblocks.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <blkid.h> + +#include "c.h" + +int main(int argc, char *argv[]) +{ + int rc; + char *devname; + blkid_probe pr; + + if (argc < 2) { + fprintf(stderr, "usage: %s <device> " + "-- prints superblocks details about the device\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + devname = argv[1]; + pr = blkid_new_probe_from_filename(devname); + if (!pr) + err(EXIT_FAILURE, "%s: faild to create a new libblkid probe", + devname); + + /* enable topology probing */ + blkid_probe_enable_superblocks(pr, TRUE); + + /* set all flags */ + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW | + BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | + BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION | + BLKID_SUBLKS_MAGIC); + + rc = blkid_do_safeprobe(pr); + if (rc == -1) + errx(EXIT_FAILURE, "%s: blkid_do_safeprobe() failed", devname); + else if (rc == 1) + warnx("%s: cannot gather information about superblocks", devname); + else { + int i, nvals = blkid_probe_numof_values(pr); + + for (i = 0; i < nvals; i++) { + const char *name, *data; + + blkid_probe_get_value(pr, i, &name, &data, NULL); + printf("\t%s = %s\n", name, data); + } + } + + blkid_free_probe(pr); + return EXIT_SUCCESS; +} diff --git a/libblkid/samples/topology.c b/libblkid/samples/topology.c new file mode 100644 index 000000000..de1c3a5e3 --- /dev/null +++ b/libblkid/samples/topology.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <blkid.h> + +#include "c.h" + +int main(int argc, char *argv[]) +{ + int rc; + char *devname; + blkid_probe pr; + blkid_topology tp; + + if (argc < 2) { + fprintf(stderr, "usage: %s <device> " + "-- prints topology details about the device\n", + program_invocation_short_name); + return EXIT_FAILURE; + } + + devname = argv[1]; + pr = blkid_new_probe_from_filename(devname); + if (!pr) + err(EXIT_FAILURE, "%s: faild to create a new libblkid probe", + devname); + /* + * Binary interface + */ + tp = blkid_probe_get_topology(pr); + if (tp) { + printf("----- binary interface:\n"); + printf("\talignment offset : %lu\n", + blkid_topology_get_alignment_offset(tp)); + printf("\tminimum io size : %lu\n", + blkid_topology_get_minimum_io_size(tp)); + printf("\toptimal io size : %lu\n", + blkid_topology_get_optimal_io_size(tp)); + printf("\tlogical sector size : %lu\n", + blkid_topology_get_logical_sector_size(tp)); + printf("\tphysical sector size : %lu\n", + blkid_topology_get_physical_sector_size(tp)); + } + + /* + * NAME=value interface + */ + + /* enable topology probing */ + blkid_probe_enable_topology(pr, TRUE); + + /* disable superblocks probing (enabled by default) */ + blkid_probe_enable_superblocks(pr, FALSE); + + rc = blkid_do_fullprobe(pr); + if (rc == -1) + errx(EXIT_FAILURE, "%s: blkid_do_fullprobe() failed", devname); + else if (rc == 1) + warnx("%s: missing topology information", devname); + else { + int i, nvals = blkid_probe_numof_values(pr); + + printf("----- NAME=value interface (values: %d):\n", nvals); + + for (i = 0; i < nvals; i++) { + const char *name, *data; + + blkid_probe_get_value(pr, i, &name, &data, NULL); + printf("\t%s = %s\n", name, data); + } + } + + blkid_free_probe(pr); + return EXIT_SUCCESS; +} diff --git a/libblkid/save.c b/libblkid/save.c deleted file mode 100644 index c94cc2a82..000000000 --- a/libblkid/save.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * save.c - write the cache struct to disk - * - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include "blkidP.h" - -static int save_dev(blkid_dev dev, FILE *file) -{ - struct list_head *p; - - if (!dev || dev->bid_name[0] != '/') - return 0; - - DBG(DEBUG_SAVE, - printf("device %s, type %s\n", dev->bid_name, dev->bid_type ? - dev->bid_type : "(null)")); - - fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"", - (unsigned long) dev->bid_devno, - (long) dev->bid_time, - (long) dev->bid_utime); - - if (dev->bid_pri) - fprintf(file, " PRI=\"%d\"", dev->bid_pri); - list_for_each(p, &dev->bid_tags) { - blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); - fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val); - } - fprintf(file, ">%s</device>\n", dev->bid_name); - - return 0; -} - -/* - * Write out the cache struct to the cache file on disk. - */ -int blkid_flush_cache(blkid_cache cache) -{ - struct list_head *p; - char *tmp = NULL; - char *opened = NULL; - char *filename; - FILE *file = NULL; - int fd, ret = 0; - struct stat st; - - if (!cache) - return -BLKID_ERR_PARAM; - - if (list_empty(&cache->bic_devs) || - !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { - DBG(DEBUG_SAVE, printf("skipping cache file write\n")); - return 0; - } - - filename = cache->bic_filename ? cache->bic_filename : - blkid_get_cache_filename(NULL); - if (!filename) - return -BLKID_ERR_PARAM; - - if (strncmp(filename, - BLKID_RUNTIME_DIR "/", sizeof(BLKID_RUNTIME_DIR)) == 0) { - - /* default destination, create the directory if necessary */ - if (stat(BLKID_RUNTIME_DIR, &st) - && errno == ENOENT - && mkdir(BLKID_RUNTIME_DIR, S_IWUSR| - S_IRUSR|S_IRGRP|S_IROTH| - S_IXUSR|S_IXGRP|S_IXOTH) != 0 - && errno != EEXIST) { - DBG(DEBUG_SAVE, - printf("can't create %s directory for cache file\n", - BLKID_RUNTIME_DIR)); - return 0; - } - } - - /* If we can't write to the cache file, then don't even try */ - if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || - (ret == 0 && access(filename, W_OK) < 0)) { - DBG(DEBUG_SAVE, - printf("can't write to cache file %s\n", filename)); - return 0; - } - - /* - * Try and create a temporary file in the same directory so - * that in case of error we don't overwrite the cache file. - * If the cache file doesn't yet exist, it isn't a regular - * file (e.g. /dev/null or a socket), or we couldn't create - * a temporary file then we open it directly. - */ - if (ret == 0 && S_ISREG(st.st_mode)) { - tmp = malloc(strlen(filename) + 8); - if (tmp) { - sprintf(tmp, "%s-XXXXXX", filename); - fd = mkstemp(tmp); - if (fd >= 0) { - if (fchmod(fd, 0644) != 0) - DBG(DEBUG_SAVE, printf("%s: fchmod failed\n", filename)); - else if ((file = fdopen(fd, "w"))) - opened = tmp; - if (!file) - close(fd); - } - } - } - - if (!file) { - file = fopen(filename, "w"); - opened = filename; - } - - DBG(DEBUG_SAVE, - printf("writing cache file %s (really %s)\n", - filename, opened)); - - if (!file) { - ret = errno; - goto errout; - } - - list_for_each(p, &cache->bic_devs) { - blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); - if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE)) - continue; - if ((ret = save_dev(dev, file)) < 0) - break; - } - - if (ret >= 0) { - cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; - ret = 1; - } - - fclose(file); - if (opened != filename) { - if (ret < 0) { - unlink(opened); - DBG(DEBUG_SAVE, - printf("unlinked temp cache %s\n", opened)); - } else { - char *backup; - - backup = malloc(strlen(filename) + 5); - if (backup) { - sprintf(backup, "%s.old", filename); - unlink(backup); - if (link(filename, backup)) { - DBG(DEBUG_SAVE, - printf("can't link %s to %s\n", - filename, backup)); - } - free(backup); - } - if (rename(opened, filename)) { - ret = errno; - DBG(DEBUG_SAVE, - printf("can't rename %s to %s\n", - opened, filename)); - } else { - DBG(DEBUG_SAVE, - printf("moved temp cache %s\n", opened)); - } - } - } - -errout: - free(tmp); - if (filename != cache->bic_filename) - free(filename); - return ret; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - blkid_cache cache = NULL; - int ret; - - blkid_init_debug(DEBUG_ALL); - if (argc > 2) { - fprintf(stderr, "Usage: %s [filename]\n" - "Test loading/saving a cache (filename)\n", argv[0]); - exit(1); - } - - if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - if ((ret = blkid_probe_all(cache)) < 0) { - fprintf(stderr, "error (%d) probing devices\n", ret); - exit(1); - } - cache->bic_filename = strdup(argv[1]); - - if ((ret = blkid_flush_cache(cache)) < 0) { - fprintf(stderr, "error (%d) saving cache\n", ret); - exit(1); - } - - blkid_put_cache(cache); - - return ret; -} -#endif diff --git a/libblkid/sgi.c b/libblkid/sgi.c deleted file mode 100644 index b89e46320..000000000 --- a/libblkid/sgi.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * sgi partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -#define SGI_MAXPARTITIONS 16 - -/* partition type */ -#define SGI_TYPE_VOLHDR 0x00 -#define SGI_TYPE_VOLULME 0x06 /* entire disk */ - -struct sgi_device_parameter { - unsigned char skew; - unsigned char gap1; - unsigned char gap2; - unsigned char sparecyl; - - uint16_t pcylcount; - uint16_t head_vol0; - uint16_t ntrks; /* tracks in cyl 0 or vol 0 */ - - unsigned char cmd_tag_queue_depth; - unsigned char unused0; - - uint16_t unused1; - uint16_t nsect; /* sectors/tracks in cyl 0 or vol 0 */ - uint16_t bytes; - uint16_t ilfact; - uint32_t flags; /* controller flags */ - uint32_t datarate; - uint32_t retries_on_error; - uint32_t ms_per_word; - uint16_t xylogics_gap1; - uint16_t xylogics_syncdelay; - uint16_t xylogics_readdelay; - uint16_t xylogics_gap2; - uint16_t xylogics_readgate; - uint16_t xylogics_writecont; -} __attribute__((packed)); - -struct sgi_disklabel { - uint32_t magic; /* magic number */ - uint16_t root_part_num; /* # root partition */ - uint16_t swap_part_num; /* # swap partition */ - unsigned char boot_file[16]; /* name of boot file */ - - struct sgi_device_parameter devparam; /* not used now */ - - struct sgi_volume { - unsigned char name[8]; /* name of volume */ - uint32_t block_num; /* logical block number */ - uint32_t num_bytes; /* how big, in bytes */ - } __attribute__((packed)) volume[15]; - - struct sgi_partition { - uint32_t num_blocks; /* size in logical blocks */ - uint32_t first_block; /* first logical block */ - uint32_t type; /* type of this partition */ - } __attribute__((packed)) partitions[SGI_MAXPARTITIONS]; - - /* checksum is the 32bit 2's complement sum of the disklabel */ - uint32_t csum; /* disk label checksum */ - uint32_t padding; /* padding */ -} __attribute__((packed)); - -static uint32_t count_checksum(struct sgi_disklabel *label) -{ - int i; - uint32_t *ptr = (uint32_t *) label; - uint32_t sum = 0; - - i = sizeof(*label) / sizeof(*ptr); - - while (i--) - sum += be32_to_cpu(ptr[i]); - - return sum; -} - - -static int probe_sgi_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct sgi_disklabel *l; - struct sgi_partition *p; - blkid_parttable tab = NULL; - blkid_partlist ls; - int i; - - l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0); - if (!l) - goto nothing; - - if (count_checksum(l)) { - DBG(DEBUG_LOWPROBE, printf( - "detected corrupted sgi disk label -- ignore\n")); - goto nothing; - } - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "sgi", 0); - if (!tab) - goto err; - - for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) { - uint32_t size = be32_to_cpu(p->num_blocks); - uint32_t start = be32_to_cpu(p->first_block); - uint32_t type = be32_to_cpu(p->type); - blkid_partition par; - - if (size == 0 || type == SGI_TYPE_VOLULME || - type == SGI_TYPE_VOLHDR) { - blkid_partlist_increment_partno(ls); - continue; - } - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, type); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - -const struct blkid_idinfo sgi_pt_idinfo = -{ - .name = "sgi", - .probefunc = probe_sgi_pt, - .magics = - { - { .magic = "\x0B\xE5\xA9\x41", .len = 4 }, - { NULL } - } -}; - diff --git a/libblkid/silicon_raid.c b/libblkid/silicon_raid.c deleted file mode 100644 index 496a3e7b0..000000000 --- a/libblkid/silicon_raid.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> -#include <stddef.h> - -#include "superblocks.h" - -struct silicon_metadata { - uint8_t unknown0[0x2E]; - uint8_t ascii_version[0x36 - 0x2E]; - int8_t diskname[0x56 - 0x36]; - int8_t unknown1[0x60 - 0x56]; - uint32_t magic; - int8_t unknown1a[0x6C - 0x64]; - uint32_t array_sectors_low; - uint32_t array_sectors_high; - int8_t unknown2[0x78 - 0x74]; - uint32_t thisdisk_sectors; - int8_t unknown3[0x100 - 0x7C]; - int8_t unknown4[0x104 - 0x100]; - uint16_t product_id; - uint16_t vendor_id; - uint16_t minor_ver; - uint16_t major_ver; - uint8_t seconds; - uint8_t minutes; - uint8_t hour; - uint8_t day; - uint8_t month; - uint8_t year; - uint16_t raid0_stride; - int8_t unknown6[0x116 - 0x114]; - uint8_t disk_number; - uint8_t type; /* SILICON_TYPE_* */ - int8_t drives_per_striped_set; - int8_t striped_set_number; - int8_t drives_per_mirrored_set; - int8_t mirrored_set_number; - uint32_t rebuild_ptr_low; - uint32_t rebuild_ptr_high; - uint32_t incarnation_no; - uint8_t member_status; - uint8_t mirrored_set_state; /* SILICON_MIRROR_* */ - uint8_t reported_device_location; - uint8_t idechannel; - uint8_t auto_rebuild; - uint8_t unknown8; - uint8_t text_type[0x13E - 0x12E]; - uint16_t checksum1; - int8_t assumed_zeros[0x1FE - 0x140]; - uint16_t checksum2; -} __attribute__((packed)); - -#define SILICON_MAGIC 0x2F000000 - -static int checksum(struct silicon_metadata *sil) -{ - int sum = 0; - unsigned short count = offsetof(struct silicon_metadata, checksum1) / 2; - uint16_t *p = (uint16_t *) sil; - - while (count--) - sum += *p++; - - return (-sum & 0xFFFF) == le16_to_cpu(sil->checksum1); -} - -static int probe_silraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct silicon_metadata *sil; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200) - 1) * 0x200; - - sil = (struct silicon_metadata *) - blkid_probe_get_buffer(pr, off, - sizeof(struct silicon_metadata)); - if (!sil) - return -1; - - if (le32_to_cpu(sil->magic) != SILICON_MAGIC) - return -1; - if (sil->disk_number >= 8) - return -1; - if (!checksum(sil)) { - DBG(DEBUG_LOWPROBE, printf("silicon raid: incorrect checksum\n")); - return -1; - } - - if (blkid_probe_sprintf_version(pr, "%u.%u", - le16_to_cpu(sil->major_ver), - le16_to_cpu(sil->minor_ver)) != 0) - return -1; - - if (blkid_probe_set_magic(pr, - off + offsetof(struct silicon_metadata, magic), - sizeof(sil->magic), - (unsigned char *) &sil->magic)) - return -1; - return 0; -} - -const struct blkid_idinfo silraid_idinfo = { - .name = "silicon_medley_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_silraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/solaris_x86.c b/libblkid/solaris_x86.c deleted file mode 100644 index 7824f4ee7..000000000 --- a/libblkid/solaris_x86.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Solaris x86 partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -/* - * Solaris-x86 is always within primary dos partition (nested PT table). The - * solaris-x86 vtoc allows to split the entire partition to "slices". The - * offset (start) of the slice is always relatively to the primary dos - * partition. - * - * Note that Solaris-SPARC uses entire disk with a different partitionning - * scheme. - */ - -/* some other implementation than Linux kernel assume 8 partitions only */ -#define SOLARIS_MAXPARTITIONS 16 - -/* disklabel (vtoc) location */ -#define SOLARIS_SECTOR 1 /* in 512-sectors */ -#define SOLARIS_OFFSET (SOLARIS_SECTOR << 9) /* in bytes */ -#define SOLARIS_MAGICOFFSET (SOLARIS_OFFSET + 12) /* v_sanity offset in bytes */ - -/* slice tags */ -#define SOLARIS_TAG_WHOLEDISK 5 - -struct solaris_slice { - uint16_t s_tag; /* ID tag of partition */ - uint16_t s_flag; /* permission flags */ - uint32_t s_start; /* start sector no of partition */ - uint32_t s_size; /* # of blocks in partition */ -} __attribute__((packed)); - -struct solaris_vtoc { - unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */ - - uint32_t v_sanity; /* to verify vtoc sanity */ - uint32_t v_version; /* layout version */ - char v_volume[8]; /* volume name */ - uint16_t v_sectorsz; /* sector size in bytes */ - uint16_t v_nparts; /* number of partitions */ - unsigned int v_reserved[10]; /* free space */ - - struct solaris_slice v_slice[SOLARIS_MAXPARTITIONS]; /* slices */ - - unsigned int timestamp[SOLARIS_MAXPARTITIONS]; /* timestamp (unsupported) */ - char v_asciilabel[128]; /* for compatibility */ -} __attribute__((packed)); - -static int probe_solaris_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct solaris_vtoc *l; /* disk label */ - struct solaris_slice *p; /* partitsion */ - blkid_parttable tab = NULL; - blkid_partition parent; - blkid_partlist ls; - int i; - uint16_t nparts; - - l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR); - if (!l) - goto nothing; - - if (le32_to_cpu(l->v_version) != 1) { - DBG(DEBUG_LOWPROBE, printf( - "WARNING: unsupported solaris x86 version %d, ignore\n", - le32_to_cpu(l->v_version))); - goto nothing; - } - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - parent = blkid_partlist_get_parent(ls); - - tab = blkid_partlist_new_parttable(ls, "solaris", SOLARIS_OFFSET); - if (!tab) - goto err; - - nparts = le16_to_cpu(l->v_nparts); - if (nparts > SOLARIS_MAXPARTITIONS) - nparts = SOLARIS_MAXPARTITIONS; - - for (i = 1, p = &l->v_slice[0]; i < nparts; i++, p++) { - - uint32_t start = le32_to_cpu(p->s_start); - uint32_t size = le32_to_cpu(p->s_size); - blkid_partition par; - - if (size == 0 || le16_to_cpu(p->s_tag) == SOLARIS_TAG_WHOLEDISK) - continue; - - if (parent) - /* Solaris slices are relative to the parent (primary - * DOS partition) */ - start += blkid_partition_get_start(parent); - - if (parent && !blkid_is_nested_dimension(parent, start, size)) { - DBG(DEBUG_LOWPROBE, printf( - "WARNING: solaris partition (%d) overflow " - "detected, ignore\n", i)); - continue; - } - - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, le16_to_cpu(p->s_tag)); - blkid_partition_set_flags(par, le16_to_cpu(p->s_flag)); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - -const struct blkid_idinfo solaris_x86_pt_idinfo = -{ - .name = "solaris", - .probefunc = probe_solaris_pt, - .magics = - { - { - .magic = "\xEE\xDE\x0D\x60", /* little-endian magic string */ - .len = 4, /* v_sanity size in bytes */ - .sboff = SOLARIS_MAGICOFFSET /* offset of v_sanity */ - }, - { NULL } - } -}; - diff --git a/libblkid/squashfs.c b/libblkid/squashfs.c deleted file mode 100644 index 45f102917..000000000 --- a/libblkid/squashfs.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "bitops.h" /* swab16() */ -#include "superblocks.h" - -struct sqsh_super_block { - uint32_t s_magic; - uint32_t inodes; - uint32_t bytes_used_2; - uint32_t uid_start_2; - uint32_t guid_start_2; - uint32_t inode_table_start_2; - uint32_t directory_table_start_2; - uint16_t s_major; - uint16_t s_minor; -} __attribute__((packed)); - -static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct sqsh_super_block *sq; - - sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block); - if (!sq) - return -1; - - if (strcmp(mag->magic, "sqsh") == 0 || - strcmp(mag->magic, "qshs") == 0) - blkid_probe_sprintf_version(pr, "%u.%u", - sq->s_major, - sq->s_minor); - else - blkid_probe_sprintf_version(pr, "%u.%u", - swab16(sq->s_major), - swab16(sq->s_minor)); - return 0; -} - -const struct blkid_idinfo squashfs_idinfo = -{ - .name = "squashfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_squashfs, - .magics = - { - { .magic = "sqsh", .len = 4 }, - { .magic = "hsqs", .len = 4 }, /* swap */ - - /* LZMA version */ - { .magic = "qshs", .len = 4 }, - { .magic = "shsq", .len = 4 }, /* swap */ - { NULL } - } -}; - - diff --git a/libblkid/src/.gitignore b/libblkid/src/.gitignore new file mode 100644 index 000000000..af34f58e0 --- /dev/null +++ b/libblkid/src/.gitignore @@ -0,0 +1 @@ +blkid.h diff --git a/libblkid/bitops.h b/libblkid/src/bitops.h index 7439ece91..7439ece91 100644 --- a/libblkid/bitops.h +++ b/libblkid/src/bitops.h diff --git a/libblkid/blkdev.h b/libblkid/src/blkdev.h index ade08878d..ade08878d 100644 --- a/libblkid/blkdev.h +++ b/libblkid/src/blkdev.h diff --git a/libblkid/src/blkid.h.in b/libblkid/src/blkid.h.in new file mode 100644 index 000000000..4f5fe2ae5 --- /dev/null +++ b/libblkid/src/blkid.h.in @@ -0,0 +1,414 @@ +/* + * blkid.h - Interface for libblkid, a library to identify block devices + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BLKID_BLKID_H +#define _BLKID_BLKID_H + +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLKID_VERSION "@LIBBLKID_VERSION@" +#define BLKID_DATE "@LIBBLKID_DATE@" + +/** + * blkid_dev: + * + * The device object keeps information about one device + */ +typedef struct blkid_struct_dev *blkid_dev; + +/** + * blkid_cache: + * + * information about all system devices + */ +typedef struct blkid_struct_cache *blkid_cache; + +/** + * blkid_probe: + * + * low-level probing setting + */ +typedef struct blkid_struct_probe *blkid_probe; + +/** + * blkid_topology: + * + * device topology information + */ +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; + +/** + * blkid_loff_t: + * + * 64-bit signed number for offsets and sizes + */ +typedef int64_t blkid_loff_t; + +/** + * blkid_tag_iterate: + * + * tags iterator for high-level (blkid_cache) API + */ +typedef struct blkid_struct_tag_iterate *blkid_tag_iterate; + +/** + * blkid_dev_iterate: + * + * devices iterator for high-level (blkid_cache) API + */ +typedef struct blkid_struct_dev_iterate *blkid_dev_iterate; + +/* + * Flags for blkid_get_dev + * + * BLKID_DEV_CREATE Create an empty device structure if not found + * in the cache. + * BLKID_DEV_VERIFY Make sure the device structure corresponds + * with reality. + * BLKID_DEV_FIND Just look up a device entry, and return NULL + * if it is not found. + * BLKID_DEV_NORMAL Get a valid device structure, either from the + * cache or by probing the device. + */ +#define BLKID_DEV_FIND 0x0000 +#define BLKID_DEV_CREATE 0x0001 +#define BLKID_DEV_VERIFY 0x0002 +#define BLKID_DEV_NORMAL (BLKID_DEV_CREATE | BLKID_DEV_VERIFY) + + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __ul_attribute__ +# if __GNUC_PREREQ (3, 4) +# define __ul_attribute__(_a_) __attribute__(_a_) +# else +# define __ul_attribute__(_a_) +# endif +#endif + +/* cache.c */ +extern void blkid_init_debug(int mask); +extern void blkid_put_cache(blkid_cache cache); +extern int blkid_get_cache(blkid_cache *cache, const char *filename); +extern void blkid_gc_cache(blkid_cache cache); + +/* dev.c */ +extern const char *blkid_dev_devname(blkid_dev dev) + __ul_attribute__((warn_unused_result)); + +extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache); +extern int blkid_dev_set_search(blkid_dev_iterate iter, + char *search_type, char *search_value); +extern int blkid_dev_next(blkid_dev_iterate iterate, blkid_dev *dev); +extern void blkid_dev_iterate_end(blkid_dev_iterate iterate); + +/* devno.c */ +extern char *blkid_devno_to_devname(dev_t devno) + __ul_attribute__((warn_unused_result)); +extern int blkid_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno) + __ul_attribute__((warn_unused_result)); + +/* devname.c */ +extern int blkid_probe_all(blkid_cache cache); +extern int blkid_probe_all_new(blkid_cache cache); +extern int blkid_probe_all_removable(blkid_cache cache); + +extern blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags); + +/* getsize.c */ +extern blkid_loff_t blkid_get_dev_size(int fd); + +/* verify.c */ +extern blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev); + +/* read.c */ + +/* resolve.c */ +extern char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname) + __ul_attribute__((warn_unused_result)); +extern char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value) + __ul_attribute__((warn_unused_result)); + +/* tag.c */ +extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev); +extern int blkid_tag_next(blkid_tag_iterate iterate, + const char **type, const char **value); +extern void blkid_tag_iterate_end(blkid_tag_iterate iterate); +extern int blkid_dev_has_tag(blkid_dev dev, const char *type, const char *value); + +extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value); + +extern int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val); + +/* version.c */ +extern int blkid_parse_version_string(const char *ver_string) + __ul_attribute__((nonnull)); +extern int blkid_get_library_version(const char **ver_string, + const char **date_string); + +/* encode.c */ +extern int blkid_encode_string(const char *str, char *str_enc, size_t len); +extern int blkid_safe_string(const char *str, char *str_safe, size_t len); + +/* evaluate.c */ +extern int blkid_send_uevent(const char *devname, const char *action); +extern char *blkid_evaluate_tag(const char *token, const char *value, + blkid_cache *cache) + __ul_attribute__((warn_unused_result)); +extern char *blkid_evaluate_spec(const char *spec, blkid_cache *cache) + __ul_attribute__((warn_unused_result)); + +/* probe.c */ +extern blkid_probe blkid_new_probe(void) + __ul_attribute__((warn_unused_result)); +extern blkid_probe blkid_new_probe_from_filename(const char *filename) + __ul_attribute__((warn_unused_result)); +extern void blkid_free_probe(blkid_probe pr); + +extern void blkid_reset_probe(blkid_probe pr); + +extern int blkid_probe_set_device(blkid_probe pr, int fd, + blkid_loff_t off, blkid_loff_t size); + +extern dev_t blkid_probe_get_devno(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern int blkid_probe_is_wholedisk(blkid_probe pr) + __ul_attribute__((nonnull)); + +extern blkid_loff_t blkid_probe_get_size(blkid_probe pr); +extern blkid_loff_t blkid_probe_get_offset(blkid_probe pr); +extern unsigned int blkid_probe_get_sectorsize(blkid_probe pr); +extern blkid_loff_t blkid_probe_get_sectors(blkid_probe pr); + +extern int blkid_probe_get_fd(blkid_probe pr); + +/* + * superblocks probing + */ +extern int blkid_known_fstype(const char *fstype); + +extern int blkid_superblocks_get_name(size_t idx, const char **name, int *usage); + +extern int blkid_probe_enable_superblocks(blkid_probe pr, int enable); + +#define BLKID_SUBLKS_LABEL (1 << 1) /* read LABEL from superblock */ +#define BLKID_SUBLKS_LABELRAW (1 << 2) /* read and define LABEL_RAW result value*/ +#define BLKID_SUBLKS_UUID (1 << 3) /* read UUID from superblock */ +#define BLKID_SUBLKS_UUIDRAW (1 << 4) /* read and define UUID_RAW result value */ +#define BLKID_SUBLKS_TYPE (1 << 5) /* define TYPE result value */ +#define BLKID_SUBLKS_SECTYPE (1 << 6) /* define compatible fs type (second type) */ +#define BLKID_SUBLKS_USAGE (1 << 7) /* define USAGE result value */ +#define BLKID_SUBLKS_VERSION (1 << 8) /* read FS type from superblock */ +#define BLKID_SUBLKS_MAGIC (1 << 9) /* define SBMAGIC and SBMAGIC_OFFSET */ +#define BLKID_SUBLKS_BADCSUM (1 << 10) /* allow a bad checksum */ + +#define BLKID_SUBLKS_DEFAULT (BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | \ + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE) + +extern int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags); +extern int blkid_probe_reset_superblocks_filter(blkid_probe pr); +extern int blkid_probe_invert_superblocks_filter(blkid_probe pr); + +/** + * BLKID_FLTR_NOTIN + */ +#define BLKID_FLTR_NOTIN 1 +/** + * BLKID_FLTR_ONLYIN + */ +#define BLKID_FLTR_ONLYIN 2 +extern int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]); + +#define BLKID_USAGE_FILESYSTEM (1 << 1) +#define BLKID_USAGE_RAID (1 << 2) +#define BLKID_USAGE_CRYPTO (1 << 3) +#define BLKID_USAGE_OTHER (1 << 4) +extern int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage); + +/* + * topology probing + */ +extern int blkid_probe_enable_topology(blkid_probe pr, int enable); + +/* binary interface */ +extern blkid_topology blkid_probe_get_topology(blkid_probe pr); + +extern unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) + __ul_attribute__((nonnull)); +extern unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) + __ul_attribute__((nonnull)); + +/* + * partitions probing + */ +extern int blkid_known_pttype(const char *pttype); + +extern int blkid_probe_enable_partitions(blkid_probe pr, int enable); + +extern int blkid_probe_reset_partitions_filter(blkid_probe pr); +extern int blkid_probe_invert_partitions_filter(blkid_probe pr); +extern int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]); + +/* partitions probing flags */ +#define BLKID_PARTS_FORCE_GPT (1 << 1) +#define BLKID_PARTS_ENTRY_DETAILS (1 << 2) +#define BLKID_PARTS_MAGIC (1 << 3) +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_parttable blkid_partlist_get_table(blkid_partlist ls); +extern blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n); +extern blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n); +extern blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno); +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) + __ul_attribute__((nonnull)); + +extern const char *blkid_partition_get_type_string(blkid_partition par); + +extern unsigned long long blkid_partition_get_flags(blkid_partition par) + __ul_attribute__((nonnull)); + +extern int blkid_partition_is_logical(blkid_partition par) + __ul_attribute__((nonnull)); +extern int blkid_partition_is_extended(blkid_partition par) + __ul_attribute__((nonnull)); +extern int blkid_partition_is_primary(blkid_partition par) + __ul_attribute__((nonnull)); + +extern const char *blkid_parttable_get_type(blkid_parttable tab); +extern const char *blkid_parttable_get_id(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 + */ +extern int blkid_do_probe(blkid_probe pr); +extern int blkid_do_safeprobe(blkid_probe pr); +extern int blkid_do_fullprobe(blkid_probe pr); + +extern int blkid_probe_numof_values(blkid_probe pr); +extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name, + const char **data, size_t *len); +extern int blkid_probe_lookup_value(blkid_probe pr, const char *name, + const char **data, size_t *len); +extern int blkid_probe_has_value(blkid_probe pr, const char *name) + __ul_attribute__((nonnull)); + +extern int blkid_do_wipe(blkid_probe pr, int dryrun); +extern int blkid_probe_step_back(blkid_probe pr); + +/* + * Deprecated functions/macros + */ +#ifndef BLKID_DISABLE_DEPRECATED + +#define BLKID_PROBREQ_LABEL BLKID_SUBLKS_LABEL +#define BLKID_PROBREQ_LABELRAW BLKID_SUBLKS_LABELRAW +#define BLKID_PROBREQ_UUID BLKID_SUBLKS_UUID +#define BLKID_PROBREQ_UUIDRAW BLKID_SUBLKS_UUIDRAW +#define BLKID_PROBREQ_TYPE BLKID_SUBLKS_TYPE +#define BLKID_PROBREQ_SECTYPE BLKID_SUBLKS_SECTYPE +#define BLKID_PROBREQ_USAGE BLKID_SUBLKS_USAGE +#define BLKID_PROBREQ_VERSION BLKID_SUBLKS_VERSION + +extern int blkid_probe_set_request(blkid_probe pr, int flags) + __ul_attribute__((deprecated)); + +extern int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) + __ul_attribute__((deprecated)); + +extern int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) + __ul_attribute__((deprecated)); + +extern int blkid_probe_invert_filter(blkid_probe pr) + __ul_attribute__((deprecated)); + +extern int blkid_probe_reset_filter(blkid_probe pr) + __ul_attribute__((deprecated)); + +#endif /* BLKID_DISABLE_DEPRECATED */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BLKID_BLKID_H */ diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h new file mode 100644 index 000000000..fbf4e719b --- /dev/null +++ b/libblkid/src/blkidP.h @@ -0,0 +1,545 @@ +/* + * blkidP.h - Internal interfaces for libblkid + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifndef _BLKID_BLKIDP_H +#define _BLKID_BLKIDP_H + +/* Always confirm that /dev/disk-by symlinks match with LABEL/UUID on device */ +/* #define CONFIG_BLKID_VERIFY_UDEV 1 */ + +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> + +#include "c.h" +#include "bitops.h" /* $(top_srcdir)/include/ */ +#include "blkdev.h" + +#include "debug.h" +#include "blkid.h" +#include "list.h" + +/* + * This describes the attributes of a specific device. + * We can traverse all of the tags by bid_tags (linking to the tag bit_names). + * The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag + * values, if they exist. + */ +struct blkid_struct_dev +{ + struct list_head bid_devs; /* All devices in the cache */ + struct list_head bid_tags; /* All tags for this device */ + blkid_cache bid_cache; /* Dev belongs to this cache */ + char *bid_name; /* Device inode pathname */ + char *bid_type; /* Preferred device TYPE */ + int bid_pri; /* Device priority */ + dev_t bid_devno; /* Device major/minor number */ + time_t bid_time; /* Last update time of device */ + suseconds_t bid_utime; /* Last update time (microseconds) */ + unsigned int bid_flags; /* Device status bitflags */ + char *bid_label; /* Shortcut to device LABEL */ + char *bid_uuid; /* Shortcut to binary UUID */ +}; + +#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */ +#define BLKID_BID_FL_INVALID 0x0004 /* Device is invalid */ +#define BLKID_BID_FL_REMOVABLE 0x0008 /* Device added by blkid_probe_all_removable() */ + +/* + * Each tag defines a NAME=value pair for a particular device. The tags + * are linked via bit_names for a single device, so that traversing the + * names list will get you a list of all tags associated with a device. + * They are also linked via bit_values for all devices, so one can easily + * search all tags with a given NAME for a specific value. + */ +struct blkid_struct_tag +{ + struct list_head bit_tags; /* All tags for this device */ + struct list_head bit_names; /* All tags with given NAME */ + char *bit_name; /* NAME of tag (shared) */ + char *bit_val; /* value of tag */ + blkid_dev bit_dev; /* pointer to device */ +}; +typedef struct blkid_struct_tag *blkid_tag; + +/* + * Chain IDs + */ +enum { + BLKID_CHAIN_SUBLKS, /* FS/RAID superblocks (enabled by default) */ + BLKID_CHAIN_TOPLGY, /* Block device topology */ + BLKID_CHAIN_PARTS, /* Partition tables */ + + BLKID_NCHAINS /* number of chains */ +}; + +struct blkid_chain { + const struct blkid_chaindrv *driver; /* chain driver */ + + int enabled; /* boolean */ + int flags; /* BLKID_<chain>_* */ + int binary; /* boolean */ + int idx; /* index of the current prober (or -1) */ + unsigned long *fltr; /* filter or NULL */ + void *data; /* private chain data or NULL */ +}; + +/* + * Chain driver + */ +struct blkid_chaindrv { + const size_t id; /* BLKID_CHAIN_* */ + const char *name; /* name of chain (for debug purpose) */ + const int dflt_flags; /* default chain flags */ + const int dflt_enabled; /* default enabled boolean */ + int has_fltr; /* boolean */ + + const struct blkid_idinfo **idinfos; /* description of probing functions */ + const size_t nidinfos; /* number of idinfos */ + + /* driver operations */ + int (*probe)(blkid_probe, struct blkid_chain *); + int (*safeprobe)(blkid_probe, struct blkid_chain *); + void (*free_data)(blkid_probe, void *); +}; + +/* + * Low-level probe result + */ +#define BLKID_PROBVAL_BUFSIZ 128 + +#define BLKID_NVALS_SUBLKS 18 +#define BLKID_NVALS_TOPLGY 5 +#define BLKID_NVALS_PARTS 13 + +/* Max number of all values in probing result */ +#define BLKID_NVALS (BLKID_NVALS_SUBLKS + \ + BLKID_NVALS_TOPLGY + \ + BLKID_NVALS_PARTS) + +struct blkid_prval +{ + const char *name; /* value name */ + unsigned char data[BLKID_PROBVAL_BUFSIZ]; /* value data */ + size_t len; /* length of value data */ + + struct blkid_chain *chain; /* owner */ +}; + +/* + * Filesystem / Raid magic strings + */ +struct blkid_idmag +{ + const char *magic; /* magic string */ + unsigned int len; /* length of magic */ + + long kboff; /* kilobyte offset of superblock */ + unsigned int sboff; /* byte offset within superblock */ +}; + +/* + * Filesystem / Raid description + */ +struct blkid_idinfo +{ + const char *name; /* fs, raid or partition table name */ + int usage; /* BLKID_USAGE_* flag */ + int flags; /* BLKID_IDINFO_* flags */ + int minsz; /* minimal device size */ + + /* probe function */ + int (*probefunc)(blkid_probe pr, const struct blkid_idmag *mag); + + struct blkid_idmag magics[]; /* NULL or array with magic strings */ +}; + +#define BLKID_NONE_MAGIC {{ NULL }} + +/* + * tolerant FS - can share the same device with more filesystems (e.g. typical + * on CD-ROMs). We need this flag to detect ambivalent results (e.g. valid fat + * and valid linux swap on the same device). + */ +#define BLKID_IDINFO_TOLERANT (1 << 1) + +struct blkid_bufinfo { + unsigned char *data; + blkid_loff_t off; + blkid_loff_t len; + struct list_head bufs; /* list of buffers */ +}; + +/* + * Low-level probing control struct + */ +struct blkid_struct_probe +{ + int fd; /* device file descriptor */ + blkid_loff_t off; /* begin of data on the device */ + blkid_loff_t size; /* end of data on the device */ + + dev_t devno; /* device number (st.st_rdev) */ + dev_t disk_devno; /* devno of the whole-disk or 0 */ + unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */ + mode_t mode; /* struct stat.sb_mode */ + + int flags; /* private libray flags */ + int prob_flags; /* always zeroized by blkid_do_*() */ + + blkid_loff_t wipe_off; /* begin of the wiped area */ + blkid_loff_t wipe_size; /* size of the wiped area */ + struct blkid_chain *wipe_chain; /* superblock, partition, ... */ + + struct list_head buffers; /* list of buffers */ + + struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ + struct blkid_chain *cur_chain; /* current chain */ + + struct blkid_prval vals[BLKID_NVALS]; /* results */ + int nvals; /* number of assigned vals */ + + struct blkid_struct_probe *parent; /* for clones */ + struct blkid_struct_probe *disk_probe; /* whole-disk probing */ +}; + +/* private flags library flags */ +#define BLKID_FL_PRIVATE_FD (1 << 1) /* see blkid_new_probe_from_filename() */ +#define BLKID_FL_TINY_DEV (1 << 2) /* <= 1.47MiB (floppy or so) */ +#define BLKID_FL_CDROM_DEV (1 << 3) /* is a CD/DVD drive */ +#define BLKID_FL_NOSCAN_DEV (1 << 4) /* do not scan this device */ + +/* private per-probing flags */ +#define BLKID_PROBE_FL_IGNORE_PT (1 << 1) /* ignore partition table */ + +extern blkid_probe blkid_clone_probe(blkid_probe parent); +extern blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr); + +/* + * Evaluation methods (for blkid_eval_* API) + */ +enum { + BLKID_EVAL_UDEV = 0, + BLKID_EVAL_SCAN, + + __BLKID_EVAL_LAST +}; + +/* + * Library config options + */ +struct blkid_config { + int eval[__BLKID_EVAL_LAST]; /* array with EVALUATION=<udev,cache> options */ + int nevals; /* number of elems in eval array */ + int uevent; /* SEND_UEVENT=<yes|not> option */ + char *cachefile; /* CACHE_FILE=<path> option */ +}; + +extern struct blkid_config *blkid_read_config(const char *filename) + __ul_attribute__((warn_unused_result)); +extern void blkid_free_config(struct blkid_config *conf); + +/* + * Minimum number of seconds between device probes, even when reading + * from the cache. This is to avoid re-probing all devices which were + * just probed by another program that does not share the cache. + */ +#define BLKID_PROBE_MIN 2 + +/* + * Time in seconds an entry remains verified in the in-memory cache + * before being reverified (in case of long-running processes that + * keep a cache in memory and continue to use it for a long time). + */ +#define BLKID_PROBE_INTERVAL 200 + +/* This describes an entire blkid cache file and probed devices. + * We can traverse all of the found devices via bic_list. + * We can traverse all of the tag types by bic_tags, which hold empty tags + * for each tag type. Those tags can be used as list_heads for iterating + * through all devices with a specific tag type (e.g. LABEL). + */ +struct blkid_struct_cache +{ + struct list_head bic_devs; /* List head of all devices */ + struct list_head bic_tags; /* List head of all tag types */ + time_t bic_time; /* Last probe time */ + time_t bic_ftime; /* Mod time of the cachefile */ + unsigned int bic_flags; /* Status flags of the cache */ + char *bic_filename; /* filename of cache */ + blkid_probe probe; /* low-level probing stuff */ +}; + +#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */ +#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */ + +/* config file */ +#define BLKID_CONFIG_FILE "/etc/blkid.conf" + +/* cache file on systemds with /run */ +#define BLKID_RUNTIME_TOPDIR "/run" +#define BLKID_RUNTIME_DIR BLKID_RUNTIME_TOPDIR "/blkid" +#define BLKID_CACHE_FILE BLKID_RUNTIME_DIR "/blkid.tab" + +/* old systems */ +#define BLKID_CACHE_FILE_OLD "/etc/blkid.tab" + +#define BLKID_PROBE_OK 0 +#define BLKID_PROBE_NONE 1 + +#define BLKID_ERR_IO 5 +#define BLKID_ERR_PROC 9 +#define BLKID_ERR_MEM 12 +#define BLKID_ERR_CACHE 14 +#define BLKID_ERR_DEV 19 +#define BLKID_ERR_PARAM 22 +#define BLKID_ERR_BIG 27 + +/* + * Priority settings for different types of devices + */ +#define BLKID_PRI_UBI 50 +#define BLKID_PRI_DM 40 +#define BLKID_PRI_EVMS 30 +#define BLKID_PRI_LVM 20 +#define BLKID_PRI_MD 10 + +#define BLKID_DEBUG_HELP (1 << 0) +#define BLKID_DEBUG_INIT (1 << 1) +#define BLKID_DEBUG_CACHE (1 << 2) +#define BLKID_DEBUG_CONFIG (1 << 3) +#define BLKID_DEBUG_DEV (1 << 4) +#define BLKID_DEBUG_DEVNAME (1 << 5) +#define BLKID_DEBUG_DEVNO (1 << 6) +#define BLKID_DEBUG_EVALUATE (1 << 7) +#define BLKID_DEBUG_LOWPROBE (1 << 8) +#define BLKID_DEBUG_PROBE (1 << 9) +#define BLKID_DEBUG_READ (1 << 10) +#define BLKID_DEBUG_SAVE (1 << 11) +#define BLKID_DEBUG_TAG (1 << 12) +#define BLKID_DEBUG_ALL 0xFFFF /* (1 << 16) aka FFFF is expected by API */ + +UL_DEBUG_DECLARE_MASK(libblkid); +#define DBG(m, x) __UL_DBG(libblkid, BLKID_DEBUG_, m, x) +#define ON_DBG(m, x) __UL_DBG_CALL(libblkid, BLKID_DEBUG_, m, x) + +extern void blkid_debug_dump_dev(blkid_dev dev); +extern void blkid_debug_dump_tag(blkid_tag tag); + + +/* devno.c */ +struct dir_list { + char *name; + struct dir_list *next; +}; +extern void blkid__scan_dir(char *, dev_t, struct dir_list **, char **) + __attribute__((nonnull(1,4))); +extern int blkid_driver_has_major(const char *drvname, int major) + __attribute__((warn_unused_result)); + +/* lseek.c */ +extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence); + +/* read.c */ +extern void blkid_read_cache(blkid_cache cache) + __attribute__((nonnull)); + +/* save.c */ +extern int blkid_flush_cache(blkid_cache cache) + __attribute__((nonnull)); + +/* cache */ +extern char *blkid_safe_getenv(const char *arg) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern char *blkid_get_cache_filename(struct blkid_config *conf) + __attribute__((warn_unused_result)); +/* + * Functions to create and find a specific tag type: tag.c + */ +extern void blkid_free_tag(blkid_tag tag); +extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int blkid_set_tag(blkid_dev dev, const char *name, + const char *value, const int vlength) + __attribute__((nonnull(1,2))); + +/* + * Functions to create and find a specific tag type: dev.c + */ +extern blkid_dev blkid_new_dev(void) + __attribute__((warn_unused_result)); +extern void blkid_free_dev(blkid_dev dev); + +/* probe.c */ +extern int blkid_probe_is_tiny(blkid_probe pr) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); +extern int blkid_probe_is_cdrom(blkid_probe pr) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern unsigned char *blkid_probe_get_buffer(blkid_probe pr, + blkid_loff_t off, blkid_loff_t len) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int blkid_probe_get_dimension(blkid_probe pr, + blkid_loff_t *off, blkid_loff_t *size) + __attribute__((nonnull)); + +extern int blkid_probe_set_dimension(blkid_probe pr, + blkid_loff_t off, blkid_loff_t size) + __attribute__((nonnull)); + +extern int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, + blkid_loff_t *offset, const struct blkid_idmag **res) + __attribute__((nonnull(1))); + +/* returns superblok according to 'struct blkid_idmag' */ +#define blkid_probe_get_sb(_pr, _mag, type) \ + ((type *) blkid_probe_get_buffer((_pr),\ + (_mag)->kboff << 10, sizeof(type))) + +extern blkid_partlist blkid_probe_get_partlist(blkid_probe pr) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int blkid_probe_is_covered_by_pt(blkid_probe pr, + blkid_loff_t offset, blkid_loff_t size) + __attribute__((warn_unused_result)); + +extern void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) + __attribute__((nonnull)); +extern int blkid_probe_chain_copy_vals(blkid_probe pr, + struct blkid_chain *chn, + struct blkid_prval *vals, + int nvals) + __attribute__((nonnull)); + +extern struct blkid_prval *blkid_probe_assign_value(blkid_probe pr, + const char *name) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int blkid_probe_reset_last_value(blkid_probe pr) + __attribute__((nonnull)); +extern void blkid_probe_append_vals(blkid_probe pr, + struct blkid_prval *vals, + int nvals) + __attribute__((nonnull)); + +extern struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int __blkid_probe_invert_filter(blkid_probe pr, int chain) + __attribute__((nonnull)); +extern int __blkid_probe_reset_filter(blkid_probe pr, int chain) + __attribute__((nonnull)); +extern int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) + __attribute__((nonnull)); + +extern void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); + +extern int blkid_probe_set_value(blkid_probe pr, const char *name, + unsigned char *data, size_t len) + __attribute__((nonnull)); + +extern int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, + const char *fmt, va_list ap) + __attribute__((nonnull)); + +extern int blkid_probe_sprintf_value(blkid_probe pr, const char *name, + const char *fmt, ...) + __attribute__((nonnull)) + __attribute__ ((__format__ (__printf__, 3, 4))); + +extern int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset, + size_t len, unsigned char *magic) + __attribute__((nonnull)); + +extern int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected) + __attribute__((nonnull)); + +extern void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) + __attribute__((nonnull)); +extern int blkid_uuid_is_empty(const unsigned char *buf, size_t len); + +extern size_t blkid_rtrim_whitespace(unsigned char *str) + __attribute__((nonnull)); +extern size_t blkid_ltrim_whitespace(unsigned char *str) + __attribute__((nonnull)); + +extern void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, + blkid_loff_t size) + __attribute__((nonnull)); +extern int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, + blkid_loff_t off, blkid_loff_t size) + __attribute__((nonnull)) + __attribute__((warn_unused_result)); +extern void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) + __attribute__((nonnull)); + +/* filter bitmap macros */ +#define blkid_bmp_wordsize (8 * sizeof(unsigned long)) +#define blkid_bmp_idx_bit(item) (1UL << ((item) % blkid_bmp_wordsize)) +#define blkid_bmp_idx_byte(item) ((item) / blkid_bmp_wordsize) + +#define blkid_bmp_set_item(bmp, item) \ + ((bmp)[ blkid_bmp_idx_byte(item) ] |= blkid_bmp_idx_bit(item)) + +#define blkid_bmp_unset_item(bmp, item) \ + ((bmp)[ blkid_bmp_idx_byte(item) ] &= ~blkid_bmp_idx_bit(item)) + +#define blkid_bmp_get_item(bmp, item) \ + ((bmp)[ blkid_bmp_idx_byte(item) ] & blkid_bmp_idx_bit(item)) + +#define blkid_bmp_nwords(max_items) \ + (((max_items) + blkid_bmp_wordsize) / blkid_bmp_wordsize) + +#define blkid_bmp_nbytes(max_items) \ + (blkid_bmp_nwords(max_items) * sizeof(unsigned long)) + +/* encode.c */ +extern size_t blkid_encode_to_utf8(int enc, unsigned char *dest, size_t len, + const unsigned char *src, size_t count) + __attribute__((nonnull)); + +#define BLKID_ENC_UTF16BE 0 +#define BLKID_ENC_UTF16LE 1 + +#endif /* _BLKID_BLKIDP_H */ diff --git a/libblkid/src/c.h b/libblkid/src/c.h new file mode 100644 index 000000000..6fcbc6da4 --- /dev/null +++ b/libblkid/src/c.h @@ -0,0 +1,295 @@ +/* + * Fundamental C definitions. + */ + +#ifndef UTIL_LINUX_C_H +#define UTIL_LINUX_C_H + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "blkid.h" +#ifdef HAVE_ERR_H +# include <err.h> +#endif + +#ifndef HAVE_USLEEP +# include <time.h> +#endif + +/* + * Compiler specific stuff + */ +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifdef __GNUC__ + +/* &a[0] degrades to a pointer: a different type from an array */ +# define __must_be_array(a) \ + UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0]))) + +# define ignore_result(x) ({ \ + __typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \ +}) + +#else /* !__GNUC__ */ +# define __must_be_array(a) 0 +# define __attribute__(_arg_) +# define ignore_result(x) ((void) (x)) +#endif /* !__GNUC__ */ + +/* + * Function attributes + */ +#ifndef __ul_alloc_size +# if __GNUC_PREREQ (4, 3) +# define __ul_alloc_size(s) __attribute__((alloc_size(s))) +# else +# define __ul_alloc_size(s) +# endif +#endif + +#ifndef __ul_calloc_size +# if __GNUC_PREREQ (4, 3) +# define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s))) +# else +# define __ul_calloc_size(n, s) +# endif +#endif + +/* Force a compilation error if condition is true, but also produce a + * result (of value 0 and type size_t), so the expression can be used + * e.g. in a structure initializer (or where-ever else comma expressions + * aren't permitted). + */ +#define UL_BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) +#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) +#endif + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef min +# define min(x, y) ({ \ + __typeof__(x) _min1 = (x); \ + __typeof__(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) +#endif + +#ifndef max +# define max(x, y) ({ \ + __typeof__(x) _max1 = (x); \ + __typeof__(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) +#endif + +#ifndef cmp_numbers +# define cmp_numbers(x, y) __extension__ ({ \ + __typeof__(x) _a = (x); \ + __typeof__(y) _b = (y); \ + (void) (&_a == &_b); \ + _a == _b ? 0 : _a > _b ? 1 : -1; }) +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME +# ifdef HAVE___PROGNAME +extern char *__progname; +# define program_invocation_short_name __progname +# else +# ifdef HAVE_GETEXECNAME +# define program_invocation_short_name \ + prog_inv_sh_nm_from_file(getexecname(), 0) +# else +# define program_invocation_short_name \ + prog_inv_sh_nm_from_file(__FILE__, 1) +# endif +static char prog_inv_sh_nm_buf[256]; +static inline char * +prog_inv_sh_nm_from_file(char *f, char stripext) +{ + char *t; + + if ((t = strrchr(f, '/')) != NULL) + t++; + else + t = f; + + strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1); + prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0'; + + if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL) + *t = '\0'; + + return prog_inv_sh_nm_buf; +} +# endif +#endif + + +#ifndef HAVE_ERR_H +static inline void +errmsg(char doexit, int excode, char adderr, const char *fmt, ...) +{ + fprintf(stderr, "%s: ", program_invocation_short_name); + if (fmt != NULL) { + va_list argp; + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); + if (adderr) + fprintf(stderr, ": "); + } + if (adderr) + fprintf(stderr, "%m"); + fprintf(stderr, "\n"); + if (doexit) + exit(excode); +} + +#ifndef HAVE_ERR +# define err(E, FMT...) errmsg(1, E, 1, FMT) +#endif + +#ifndef HAVE_ERRX +# define errx(E, FMT...) errmsg(1, E, 0, FMT) +#endif + +#ifndef HAVE_WARN +# define warn(FMT...) errmsg(0, 0, 1, FMT) +#endif + +#ifndef HAVE_WARNX +# define warnx(FMT...) errmsg(0, 0, 0, FMT) +#endif +#endif /* !HAVE_ERR_H */ + + +static inline __attribute__((const)) int is_power_of_2(unsigned long num) +{ + return (num != 0 && ((num & (num - 1)) == 0)); +} + +#ifndef HAVE_LOFF_T +typedef int64_t loff_t; +#endif + +#if !defined(HAVE_DIRFD) && (!defined(HAVE_DECL_DIRFD) || HAVE_DECL_DIRFD == 0) && defined(HAVE_DIR_DD_FD) +#include <sys/types.h> +#include <dirent.h> +static inline int dirfd(DIR *d) +{ + return d->dd_fd; +} +#endif + +/* + * Fallback defines for old versions of glibc + */ +#include <fcntl.h> + +#ifdef O_CLOEXEC +#define UL_CLOEXECSTR "e" +#else +#define UL_CLOEXECSTR "" +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0x0020 +#endif + +#ifndef IUTF8 +#define IUTF8 0040000 +#endif + +/* + * MAXHOSTNAMELEN replacement + */ +static inline size_t get_hostname_max(void) +{ + long len = sysconf(255); + + if (0 < len) + return len; + +#ifdef MAXHOSTNAMELEN + return MAXHOSTNAMELEN; +#elif HOST_NAME_MAX + return HOST_NAME_MAX; +#endif + return 64; +} + +/* + * Constant strings for usage() functions. For more info see + * Documentation/howto-usage-function.txt and sys-utils/arch.c + */ +#define USAGE_HEADER _("\nUsage:\n") +#define USAGE_OPTIONS _("\nOptions:\n") +#define USAGE_SEPARATOR _("\n") +#define USAGE_HELP _(" -h, --help display this help and exit\n") +#define USAGE_VERSION _(" -V, --version output version information and exit\n") +#define USAGE_MAN_TAIL(_man) _("\nFor more details see %s.\n"), _man + +#define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING + +/* + * scanf modifiers for "strings allocation" + */ +#ifdef HAVE_SCANF_MS_MODIFIER +#define UL_SCNsA "%ms" +#elif defined(HAVE_SCANF_AS_MODIFIER) +#define UL_SCNsA "%as" +#endif + +/* + * seek stuff + */ +#ifndef SEEK_DATA +# define SEEK_DATA 3 +#endif +#ifndef SEEK_HOLE +# define SEEK_HOLE 4 +#endif + +#endif /* UTIL_LINUX_C_H */ diff --git a/libblkid/src/cache.c b/libblkid/src/cache.c new file mode 100644 index 000000000..b576df8b4 --- /dev/null +++ b/libblkid/src/cache.c @@ -0,0 +1,226 @@ +/* + * cache.c - allocation/initialization/free routines for cache + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include "blkidP.h" +#include "env.h" + +/** + * SECTION:cache + * @title: Cache + * @short_description: basic routines to work with libblkid cache + * + * Block device information is normally kept in a cache file blkid.tab and is + * verified to still be valid before being returned to the user (if the user has + * read permission on the raw block device, otherwise not). The cache file also + * allows unprivileged users (normally anyone other than root, or those not in the + * "disk" group) to locate devices by label/id. The standard location of the + * cache file can be overridden by the environment variable BLKID_FILE. + * + * In situations where one is getting information about a single known device, it + * does not impact performance whether the cache is used or not (unless you are + * not able to read the block device directly). If you are dealing with multiple + * devices, use of the cache is highly recommended (even if empty) as devices will + * be scanned at most one time and the on-disk cache will be updated if possible. + * There is rarely a reason not to use the cache. + * + * In some cases (modular kernels), block devices are not even visible until after + * they are accessed the first time, so it is critical that there is some way to + * locate these devices without enumerating only visible devices, so the use of + * the cache file is required in this situation. + */ +static const char *get_default_cache_filename(void) +{ + struct stat st; + + if (stat(BLKID_RUNTIME_TOPDIR, &st) == 0 && S_ISDIR(st.st_mode)) + return BLKID_CACHE_FILE; /* cache in /run */ + + return BLKID_CACHE_FILE_OLD; /* cache in /etc */ +} + +/* returns allocated path to cache */ +char *blkid_get_cache_filename(struct blkid_config *conf) +{ + char *filename; + + filename = safe_getenv("BLKID_FILE"); + if (filename) + filename = strdup(filename); + else if (conf) + filename = conf->cachefile ? strdup(conf->cachefile) : NULL; + else { + struct blkid_config *c = blkid_read_config(NULL); + if (!c) + filename = strdup(get_default_cache_filename()); + else { + filename = c->cachefile; /* already allocated */ + c->cachefile = NULL; + blkid_free_config(c); + } + } + return filename; +} + +/** + * blkid_get_cache: + * @cache: pointer to return cache handler + * @filename: path to the cache file or NULL for the default path + * + * Allocates and initialize librray cache handler. + * + * Returns: 0 on success or number less than zero in case of error. + */ +int blkid_get_cache(blkid_cache *ret_cache, const char *filename) +{ + blkid_cache cache; + + if (!ret_cache) + return -BLKID_ERR_PARAM; + + blkid_init_debug(0); + + DBG(CACHE, ul_debug("creating blkid cache (using %s)", + filename ? filename : "default cache")); + + if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache)))) + return -BLKID_ERR_MEM; + + INIT_LIST_HEAD(&cache->bic_devs); + INIT_LIST_HEAD(&cache->bic_tags); + + if (filename && !*filename) + filename = NULL; + if (filename) + cache->bic_filename = strdup(filename); + else + cache->bic_filename = blkid_get_cache_filename(NULL); + + blkid_read_cache(cache); + *ret_cache = cache; + return 0; +} + +/** + * blkid_put_cache: + * @cache: cache handler + * + * Saves changes to cache file. + */ +void blkid_put_cache(blkid_cache cache) +{ + if (!cache) + return; + + (void) blkid_flush_cache(cache); + + DBG(CACHE, ul_debug("freeing cache struct")); + + /* DBG(CACHE, ul_debug_dump_cache(cache)); */ + + while (!list_empty(&cache->bic_devs)) { + blkid_dev dev = list_entry(cache->bic_devs.next, + struct blkid_struct_dev, + bid_devs); + blkid_free_dev(dev); + } + + while (!list_empty(&cache->bic_tags)) { + blkid_tag tag = list_entry(cache->bic_tags.next, + struct blkid_struct_tag, + bit_tags); + + while (!list_empty(&tag->bit_names)) { + blkid_tag bad = list_entry(tag->bit_names.next, + struct blkid_struct_tag, + bit_names); + + DBG(CACHE, ul_debug("warning: unfreed tag %s=%s", + bad->bit_name, bad->bit_val)); + blkid_free_tag(bad); + } + blkid_free_tag(tag); + } + + blkid_free_probe(cache->probe); + + free(cache->bic_filename); + free(cache); +} + +/** + * blkid_gc_cache: + * @cache: cache handler + * + * Removes garbage (non-existing devices) from the cache. + */ +void blkid_gc_cache(blkid_cache cache) +{ + struct list_head *p, *pnext; + struct stat st; + + if (!cache) + return; + + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + if (stat(dev->bid_name, &st) < 0) { + DBG(CACHE, ul_debug("freeing %s", dev->bid_name)); + blkid_free_dev(dev); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + } else { + DBG(CACHE, ul_debug("Device %s exists", dev->bid_name)); + } + } +} + +#ifdef TEST_PROGRAM +int main(int argc, char** argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(BLKID_DEBUG_ALL); + + if ((argc > 2)) { + fprintf(stderr, "Usage: %s [filename] \n", argv[0]); + exit(1); + } + + if ((ret = blkid_get_cache(&cache, argv[1])) < 0) { + fprintf(stderr, "error %d parsing cache file %s\n", ret, + argv[1] ? argv[1] : blkid_get_cache_filename(NULL)); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if ((ret = blkid_probe_all(cache)) < 0) + fprintf(stderr, "error probing devices\n"); + + blkid_put_cache(cache); + + return ret; +} +#endif diff --git a/libblkid/src/canonicalize.h b/libblkid/src/canonicalize.h new file mode 100644 index 000000000..7a18aca09 --- /dev/null +++ b/libblkid/src/canonicalize.h @@ -0,0 +1,21 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 Library Public License for more details. + */ +#ifndef CANONICALIZE_H +#define CANONICALIZE_H + +#include "c.h" /* for PATH_MAX */ + +extern char *canonicalize_path(const char *path); +extern char *canonicalize_path_restricted(const char *path); +extern char *canonicalize_dm_name(const char *ptname); + +#endif /* CANONICALIZE_H */ diff --git a/libblkid/src/closestream.h b/libblkid/src/closestream.h new file mode 100644 index 000000000..7842456fb --- /dev/null +++ b/libblkid/src/closestream.h @@ -0,0 +1,71 @@ +#ifndef UTIL_LINUX_CLOSESTREAM_H +#define UTIL_LINUX_CLOSESTREAM_H + +#include <stdio.h> +#ifdef HAVE_STDIO_EXT_H +#include <stdio_ext.h> +#endif +#include <unistd.h> + +#include "c.h" +#include "nls.h" + +#ifndef HAVE___FPENDING +static inline int +__fpending(FILE *stream __attribute__((__unused__))) +{ + return 0; +} +#endif + +static inline int +close_stream(FILE * stream) +{ + const int some_pending = (__fpending(stream) != 0); + const int prev_fail = (ferror(stream) != 0); + const int fclose_fail = (fclose(stream) != 0); + + if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) { + if (!fclose_fail && !(errno == EPIPE)) + errno = 0; + return EOF; + } + return 0; +} + +/* Meant to be used atexit(close_stdout); */ +static inline void +close_stdout(void) +{ + if (close_stream(stdout) != 0 && !(errno == EPIPE)) { + if (errno) + warn(_("write error")); + else + warnx(_("write error")); + _exit(EXIT_FAILURE); + } + + if (close_stream(stderr) != 0) + _exit(EXIT_FAILURE); +} + +#ifndef HAVE_FSYNC +static inline int +fsync(int fd __attribute__((__unused__))) +{ + return 0; +} +#endif + +static inline int +close_fd(int fd) +{ + const int fsync_fail = (fsync(fd) != 0); + const int close_fail = (close(fd) != 0); + + if (fsync_fail || close_fail) + return EOF; + return 0; +} + +#endif /* UTIL_LINUX_CLOSESTREAM_H */ diff --git a/libblkid/src/colors.h b/libblkid/src/colors.h new file mode 100644 index 000000000..97efc486a --- /dev/null +++ b/libblkid/src/colors.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2012-2014 Karel Zak <kzak@redhat.com> + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef UTIL_LINUX_COLORS_H +#define UTIL_LINUX_COLORS_H + +#include <stdio.h> +#include <unistd.h> + +#define UL_COLOR_RESET "\033[0m" +#define UL_COLOR_BOLD "\033[1m" +#define UL_COLOR_HALFBRIGHT "\033[2m" +#define UL_COLOR_UNDERSCORE "\033[4m" +#define UL_COLOR_BLINK "\033[5m" +#define UL_COLOR_REVERSE "\033[7m" + +/* Standard colors */ +#define UL_COLOR_BLACK "\033[30m" +#define UL_COLOR_RED "\033[31m" +#define UL_COLOR_GREEN "\033[32m" +#define UL_COLOR_BROWN "\033[33m" /* well, brown */ +#define UL_COLOR_BLUE "\033[34m" +#define UL_COLOR_MAGENTA "\033[35m" +#define UL_COLOR_CYAN "\033[36m" +#define UL_COLOR_GRAY "\033[37m" + +/* Bold variants */ +#define UL_COLOR_DARK_GRAY "\033[1;30m" +#define UL_COLOR_BOLD_RED "\033[1;31m" +#define UL_COLOR_BOLD_GREEN "\033[1;32m" +#define UL_COLOR_BOLD_YELLOW "\033[1;33m" +#define UL_COLOR_BOLD_BLUE "\033[1;34m" +#define UL_COLOR_BOLD_MAGENTA "\033[1;35m" +#define UL_COLOR_BOLD_CYAN "\033[1;36m" + +#define UL_COLOR_WHITE "\033[1;37m" + +/* --color[=WHEN] */ +enum colortmode { + UL_COLORMODE_AUTO = 0, + UL_COLORMODE_NEVER, + UL_COLORMODE_ALWAYS, + UL_COLORMODE_UNDEF, + + __UL_NCOLORMODES /* last */ +}; + +extern int colormode_from_string(const char *str); +extern int colormode_or_err(const char *str, const char *errmsg); + +/* Initialize the global variable UL_COLOR_TERM_OK */ +extern int colors_init(int mode, const char *util_name); + +/* Returns 1 or 0 */ +extern int colors_wanted(void); + +/* temporary enable/disable colors */ +extern void colors_off(void); +extern void colors_on(void); + + +/* Set the color */ +extern void color_fenable(const char *seq, FILE *f); + +extern void color_scheme_fenable(const char *name, const char *dflt, FILE *f); +extern const char *color_scheme_get_sequence(const char *name, const char *dflt); + +static inline void color_enable(const char *seq) +{ + color_fenable(seq, stdout); +} + +static inline void color_scheme_enable(const char *name, const char *dflt) +{ + color_scheme_fenable(name, dflt, stdout); +} + +/* Reset colors to default */ +extern void color_fdisable(FILE *f); + +static inline void color_disable(void) +{ + color_fdisable(stdout); +} + +/* converts "red" to UL_COLOR_RED, etc. */ +extern const char *color_sequence_from_colorname(const char *str); + + +#endif /* UTIL_LINUX_COLORS_H */ diff --git a/libblkid/src/config.c b/libblkid/src/config.c new file mode 100644 index 000000000..3c7f3124c --- /dev/null +++ b/libblkid/src/config.c @@ -0,0 +1,198 @@ +/* + * config.c - blkid.conf routines + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdint.h> +#include <stdarg.h> + +#include "blkidP.h" +#include "env.h" + +static int parse_evaluate(struct blkid_config *conf, char *s) +{ + while(s && *s) { + char *sep; + + if (conf->nevals >= __BLKID_EVAL_LAST) + goto err; + sep = strchr(s, ','); + if (sep) + *sep = '\0'; + if (strcmp(s, "udev") == 0) + conf->eval[conf->nevals] = BLKID_EVAL_UDEV; + else if (strcmp(s, "scan") == 0) + conf->eval[conf->nevals] = BLKID_EVAL_SCAN; + else + goto err; + conf->nevals++; + if (sep) + s = sep + 1; + else + break; + } + return 0; +err: + DBG(CONFIG, ul_debug( + "config file: unknown evaluation method '%s'.", s)); + return -1; +} + +static int parse_next(FILE *fd, struct blkid_config *conf) +{ + char buf[BUFSIZ]; + char *s; + + /* read the next non-blank non-comment line */ + do { + if (fgets (buf, sizeof(buf), fd) == NULL) + return feof(fd) ? 0 : -1; + s = strchr (buf, '\n'); + if (!s) { + /* Missing final newline? Otherwise extremely */ + /* long line - assume file was corrupted */ + if (feof(fd)) + s = strchr (buf, '\0'); + else { + DBG(CONFIG, ul_debug( + "config file: missing newline at line '%s'.", + buf)); + return -1; + } + } + *s = '\0'; + if (--s >= buf && *s == '\r') + *s = '\0'; + + s = buf; + while (*s == ' ' || *s == '\t') /* skip space */ + s++; + + } while (*s == '\0' || *s == '#'); + + if (!strncmp(s, "SEND_UEVENT=", 12)) { + s += 13; + if (*s && !strcasecmp(s, "yes")) + conf->uevent = TRUE; + else if (*s) + conf->uevent = FALSE; + } else if (!strncmp(s, "CACHE_FILE=", 11)) { + s += 11; + if (*s) + conf->cachefile = strdup(s); + } else if (!strncmp(s, "EVALUATE=", 9)) { + s += 9; + if (*s && parse_evaluate(conf, s) == -1) + return -1; + } else { + DBG(CONFIG, ul_debug( + "config file: unknown option '%s'.", s)); + return -1; + } + return 0; +} + +/* return real config data or built-in default */ +struct blkid_config *blkid_read_config(const char *filename) +{ + struct blkid_config *conf; + FILE *f; + + if (!filename) + filename = safe_getenv("BLKID_CONF"); + if (!filename) + filename = BLKID_CONFIG_FILE; + + conf = (struct blkid_config *) calloc(1, sizeof(*conf)); + if (!conf) + return NULL; + conf->uevent = -1; + + DBG(CONFIG, ul_debug("reading config file: %s.", filename)); + + f = fopen(filename, "r" UL_CLOEXECSTR); + if (!f) { + DBG(CONFIG, ul_debug("%s: does not exist, using built-in default", filename)); + goto dflt; + } + while (!feof(f)) { + if (parse_next(f, conf)) { + DBG(CONFIG, ul_debug("%s: parse error", filename)); + goto err; + } + } +dflt: + if (!conf->nevals) { + conf->eval[0] = BLKID_EVAL_UDEV; + conf->eval[1] = BLKID_EVAL_SCAN; + conf->nevals = 2; + } + if (!conf->cachefile) + conf->cachefile = strdup(BLKID_CACHE_FILE); + if (conf->uevent == -1) + conf->uevent = TRUE; + if (f) + fclose(f); + return conf; +err: + free(conf); + fclose(f); + return NULL; +} + +void blkid_free_config(struct blkid_config *conf) +{ + if (!conf) + return; + free(conf->cachefile); + free(conf); +} + +#ifdef TEST_PROGRAM +/* + * usage: tst_config [<filename>] + */ +int main(int argc, char *argv[]) +{ + int i; + struct blkid_config *conf; + char *filename = NULL; + + blkid_init_debug(BLKID_DEBUG_ALL); + + if (argc == 2) + filename = argv[1]; + + conf = blkid_read_config(filename); + if (!conf) + return EXIT_FAILURE; + + printf("EVALUATE: "); + for (i = 0; i < conf->nevals; i++) + printf("%s ", conf->eval[i] == BLKID_EVAL_UDEV ? "udev" : "scan"); + printf("\n"); + + printf("SEND UEVENT: %s\n", conf->uevent ? "TRUE" : "FALSE"); + printf("CACHE_FILE: %s\n", conf->cachefile); + + blkid_free_config(conf); + return EXIT_SUCCESS; +} +#endif diff --git a/libblkid/src/crc32.h b/libblkid/src/crc32.h new file mode 100644 index 000000000..26169109e --- /dev/null +++ b/libblkid/src/crc32.h @@ -0,0 +1,10 @@ +#ifndef UL_NG_CRC32_H +#define UL_NG_CRC32_H + +#include <sys/types.h> +#include <stdint.h> + +extern uint32_t crc32(uint32_t seed, const unsigned char *buf, size_t len); + +#endif + diff --git a/libblkid/src/debug.h b/libblkid/src/debug.h new file mode 100644 index 000000000..0229ab329 --- /dev/null +++ b/libblkid/src/debug.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 Ondrej Oprala <ooprala@redhat.com> + * Copyright (C) 2014 Karel Zak <kzak@redhat.com> + * + * This file may be distributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef UTIL_LINUX_DEBUG_H +#define UTIL_LINUX_DEBUG_H + + +/* + * util-linux debug macros + * + * The debug stuff is based on <name>_debug_mask that controls what outputs is + * expected. The mask is usually initialized by <NAME>_DEBUG= env.variable + * + * After successful initialization the flag <PREFIX>_DEBUG_INIT is always set + * to the mask (this flag is required). The <PREFIX> is usually library API + * prefix (e.g. MNT_) or program name (e.g. CFDISK_) + * + * In the code is possible to use + * + * DBG(FOO, ul_debug("this is output for foo")); + * + * where for the FOO has to be defined <PREFIX>_DEBUG_FOO. + * + * It's possible to initialize the mask by comma delimited strings with + * subsystem names (e.g. "LIBMOUNT_DEBUG=options,tab"). In this case is + * necessary to define mask names array. This functionality is optional. + * + * It's stringly recommended to use UL_* macros to define/declare/use + * the debug stuff. + * + * See disk-utils/cfdisk.c: cfdisk_init_debug() for programs debug + * or libmount/src/init.c: mnt_init_debug() for library debug + * + */ + +#include <stdarg.h> +#include <string.h> + +struct ul_debug_maskname { + const char *name; + int mask; + const char *help; +}; +#define UL_DEBUG_EMPTY_MASKNAMES {{ NULL, 0, NULL }} +#define UL_DEBUG_DEFINE_MASKNAMES(m) static const struct ul_debug_maskname m ## _masknames[] +#define UL_DEBUG_MASKNAMES(m) m ## _masknames + +#define UL_DEBUG_DEFINE_MASK(m) int m ## _debug_mask +#define UL_DEBUG_DECLARE_MASK(m) extern UL_DEBUG_DEFINE_MASK(m) + +/* p - flag prefix, m - flag postfix */ +#define UL_DEBUG_DEFINE_FLAG(p, m) p ## m + +/* l - library name, p - flag prefix, m - flag postfix, x - function */ +#define __UL_DBG(l, p, m, x) \ + do { \ + if ((p ## m) & l ## _debug_mask) { \ + fprintf(stderr, "%d: %s: %8s: ", getpid(), # l, # m); \ + x; \ + } \ + } while (0) + +#define __UL_DBG_CALL(l, p, m, x) \ + do { \ + if ((p ## m) & l ## _debug_mask) { \ + x; \ + } \ + } while (0) + +#define __UL_DBG_FLUSH(l, p) \ + do { \ + if (l ## _debug_mask && \ + l ## _debug_mask != p ## INIT) { \ + fflush(stderr); \ + } \ + } while (0) + + +#define __UL_INIT_DEBUG(lib, pref, mask, env) \ + do { \ + if (lib ## _debug_mask & pref ## INIT) \ + ; \ + else if (!mask) { \ + char *str = getenv(# env); \ + if (str) \ + lib ## _debug_mask = ul_debug_parse_envmask(lib ## _masknames, str); \ + } else \ + lib ## _debug_mask = mask; \ + lib ## _debug_mask |= pref ## INIT; \ + } while (0) + + +static inline void __attribute__ ((__format__ (__printf__, 1, 2))) +ul_debug(const char *mesg, ...) +{ + va_list ap; + va_start(ap, mesg); + vfprintf(stderr, mesg, ap); + va_end(ap); + fputc('\n', stderr); +} + +static inline void __attribute__ ((__format__ (__printf__, 2, 3))) +ul_debugobj(void *handler, const char *mesg, ...) +{ + va_list ap; + + if (handler) + fprintf(stderr, "[%p]: ", handler); + va_start(ap, mesg); + vfprintf(stderr, mesg, ap); + va_end(ap); + fputc('\n', stderr); +} + +static inline int ul_debug_parse_envmask( + const struct ul_debug_maskname flagnames[], + const char *mask) +{ + int res; + char *ptr; + + /* let's check for a numeric mask first */ + res = strtoul(mask, &ptr, 0); + + /* perhaps it's a comma-separated string? */ + if (ptr && *ptr && flagnames && flagnames[0].name) { + char *msbuf, *ms, *name; + res = 0; + + ms = msbuf = strdup(mask); + if (!ms) + return res; + + while ((name = strtok_r(ms, ",", &ptr))) { + const struct ul_debug_maskname *d; + ms = ptr; + + for (d = flagnames; d && d->name; d++) { + if (strcmp(name, d->name) == 0) { + res |= d->mask; + break; + } + } + /* nothing else we can do by OR-ing the mask */ + if (res == 0xffff) + break; + } + free(msbuf); + } else if (ptr && strcmp(ptr, "all") == 0) + res = 0xffff; + + return res; +} + +static inline void ul_debug_print_masks( + const char *env, + const struct ul_debug_maskname flagnames[]) +{ + const struct ul_debug_maskname *d; + + if (!flagnames) + return; + + fprintf(stderr, "Available \"%s=<name>[,...]|<mask>\" debug masks:\n", + env); + for (d = flagnames; d && d->name; d++) { + if (!d->help) + continue; + fprintf(stderr, " %-8s [0x%04x] : %s\n", + d->name, d->mask, d->help); + } +} + +#endif /* UTIL_LINUX_DEBUG_H */ diff --git a/libblkid/src/dev.c b/libblkid/src/dev.c new file mode 100644 index 000000000..9491331ab --- /dev/null +++ b/libblkid/src/dev.c @@ -0,0 +1,274 @@ +/* + * dev.c - allocation/initialization/free routines for dev + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdlib.h> +#include <string.h> + +#include "blkidP.h" + +/* + * NOTE: reference manual is not structured as code. The following section is a generic + * section for all high-level cache search+iterate routines. + */ + +/** + * SECTION:search + * @title: Search and iterate + * @short_description: search devices and iterate over devices in the cache. + * + * Note that high-level probing API provides information about superblocks + * (filesystems/raids) only. For partitions and topology is necessary to use + * the low-level API. + */ + +blkid_dev blkid_new_dev(void) +{ + blkid_dev dev; + + if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev)))) + return NULL; + + INIT_LIST_HEAD(&dev->bid_devs); + INIT_LIST_HEAD(&dev->bid_tags); + + return dev; +} + +void blkid_free_dev(blkid_dev dev) +{ + if (!dev) + return; + + DBG(DEV, + ul_debug(" freeing dev %s (%s)", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + DBG(DEV, blkid_debug_dump_dev(dev)); + + list_del(&dev->bid_devs); + while (!list_empty(&dev->bid_tags)) { + blkid_tag tag = list_entry(dev->bid_tags.next, + struct blkid_struct_tag, + bit_tags); + blkid_free_tag(tag); + } + free(dev->bid_name); + free(dev); +} + +/* + * Given a blkid device, return its name + */ +const char *blkid_dev_devname(blkid_dev dev) +{ + return dev ? dev->bid_name : NULL; +} + +void blkid_debug_dump_dev(blkid_dev dev) +{ + struct list_head *p; + + if (!dev) { + printf(" dev: NULL\n"); + return; + } + + fprintf(stderr, " dev: name = %s\n", dev->bid_name); + fprintf(stderr, " dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); + fprintf(stderr, " dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); + fprintf(stderr, " dev: PRI=\"%d\"\n", dev->bid_pri); + fprintf(stderr, " dev: flags = 0x%08X\n", dev->bid_flags); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + if (tag) + fprintf(stderr, " tag: %s=\"%s\"\n", tag->bit_name, + tag->bit_val); + else + fprintf(stderr, " tag: NULL\n"); + } +} + +/* + * dev iteration routines for the public libblkid interface. + * + * These routines do not expose the list.h implementation, which are a + * contamination of the namespace, and which force us to reveal far, far + * too much of our internal implemenation. I'm not convinced I want + * to keep list.h in the long term, anyway. It's fine for kernel + * programming, but performance is not the #1 priority for this + * library, and I really don't like the tradeoff of type-safety for + * performance for this application. [tytso:20030125.2007EST] + */ + +/* + * This series of functions iterate over all devices in a blkid cache + */ +#define DEV_ITERATE_MAGIC 0x01a5284c + +struct blkid_struct_dev_iterate { + int magic; + blkid_cache cache; + char *search_type; + char *search_value; + struct list_head *p; +}; + +blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache) +{ + blkid_dev_iterate iter; + + if (!cache) { + errno = EINVAL; + return NULL; + } + + iter = malloc(sizeof(struct blkid_struct_dev_iterate)); + if (iter) { + iter->magic = DEV_ITERATE_MAGIC; + iter->cache = cache; + iter->p = cache->bic_devs.next; + iter->search_type = 0; + iter->search_value = 0; + } + return iter; +} + +int blkid_dev_set_search(blkid_dev_iterate iter, + char *search_type, char *search_value) +{ + char *new_type, *new_value; + + if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type || + !search_value) + return -1; + new_type = malloc(strlen(search_type)+1); + new_value = malloc(strlen(search_value)+1); + if (!new_type || !new_value) { + free(new_type); + free(new_value); + return -1; + } + strcpy(new_type, search_type); + strcpy(new_value, search_value); + free(iter->search_type); + free(iter->search_value); + iter->search_type = new_type; + iter->search_value = new_value; + return 0; +} + +/* + * Return 0 on success, -1 on error + */ +int blkid_dev_next(blkid_dev_iterate iter, + blkid_dev *ret_dev) +{ + blkid_dev dev; + + if (!ret_dev || !iter || iter->magic != DEV_ITERATE_MAGIC) + return -1; + *ret_dev = 0; + while (iter->p != &iter->cache->bic_devs) { + dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs); + iter->p = iter->p->next; + if (iter->search_type && + !blkid_dev_has_tag(dev, iter->search_type, + iter->search_value)) + continue; + *ret_dev = dev; + return 0; + } + return -1; +} + +void blkid_dev_iterate_end(blkid_dev_iterate iter) +{ + if (!iter || iter->magic != DEV_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter->search_type); + free(iter->search_value); + free(iter); +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#else +extern char *optarg; +extern int optind; +#endif + +void __attribute__((__noreturn__)) usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); + fprintf(stderr, "\tList all devices and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_dev_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret; + char *tmp; + char *file = NULL; + char *search_type = NULL; + char *search_value = NULL; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + { + int mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + blkid_init_debug(mask); + break; + } + case '?': + usage(argv[0]); + } + if (argc >= optind+2) { + search_type = argv[optind]; + search_value = argv[optind+1]; + optind += 2; + } + if (argc != optind) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + iter = blkid_dev_iterate_begin(cache); + if (search_type) + blkid_dev_set_search(iter, search_type, search_value); + while (blkid_dev_next(iter, &dev) == 0) { + printf("Device: %s\n", blkid_dev_devname(dev)); + } + blkid_dev_iterate_end(iter); + + + blkid_put_cache(cache); + return (0); +} +#endif diff --git a/libblkid/src/devname.c b/libblkid/src/devname.c new file mode 100644 index 000000000..fdbb5c99a --- /dev/null +++ b/libblkid/src/devname.c @@ -0,0 +1,675 @@ +/* + * devname.c - get a dev by its device inode name + * + * Copyright (C) Andries Brouwer + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#include <dirent.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <time.h> + +#include "blkidP.h" + +#include "canonicalize.h" /* $(top_srcdir)/include */ +#include "pathnames.h" +#include "sysfs.h" +#include "at.h" + +/* + * Find a dev struct in the cache by device name, if available. + * + * If there is no entry with the specified device name, and the create + * flag is set, then create an empty device entry. + */ +blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) +{ + blkid_dev dev = NULL, tmp; + struct list_head *p, *pnext; + + if (!cache || !devname) + return NULL; + + list_for_each(p, &cache->bic_devs) { + tmp = list_entry(p, struct blkid_struct_dev, bid_devs); + if (strcmp(tmp->bid_name, devname)) + continue; + + DBG(DEVNAME, ul_debug("found devname %s in cache", tmp->bid_name)); + dev = tmp; + break; + } + + if (!dev && (flags & BLKID_DEV_CREATE)) { + if (access(devname, F_OK) < 0) + return NULL; + dev = blkid_new_dev(); + if (!dev) + return NULL; + dev->bid_time = INT_MIN; + dev->bid_name = strdup(devname); + dev->bid_cache = cache; + list_add_tail(&dev->bid_devs, &cache->bic_devs); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + } + + if (flags & BLKID_DEV_VERIFY) { + dev = blkid_verify(cache, dev); + if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) + return dev; + /* + * If the device is verified, then search the blkid + * cache for any entries that match on the type, uuid, + * and label, and verify them; if a cache entry can + * not be verified, then it's stale and so we remove + * it. + */ + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev dev2 = list_entry(p, struct blkid_struct_dev, bid_devs); + if (dev2->bid_flags & BLKID_BID_FL_VERIFIED) + continue; + if (!dev->bid_type || !dev2->bid_type || + strcmp(dev->bid_type, dev2->bid_type)) + continue; + if (dev->bid_label && dev2->bid_label && + strcmp(dev->bid_label, dev2->bid_label)) + continue; + if (dev->bid_uuid && dev2->bid_uuid && + strcmp(dev->bid_uuid, dev2->bid_uuid)) + continue; + if ((dev->bid_label && !dev2->bid_label) || + (!dev->bid_label && dev2->bid_label) || + (dev->bid_uuid && !dev2->bid_uuid) || + (!dev->bid_uuid && dev2->bid_uuid)) + continue; + dev2 = blkid_verify(cache, dev2); + if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED)) + blkid_free_dev(dev2); + } + } + return dev; +} + +/* Directories where we will try to search for device names */ +static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; + +static int is_dm_leaf(const char *devname) +{ + struct dirent *de, *d_de; + DIR *dir, *d_dir; + char path[256]; + int ret = 1; + + if ((dir = opendir("/sys/block")) == NULL) + return 0; + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || + !strcmp(de->d_name, devname) || + strncmp(de->d_name, "dm-", 3) || + strlen(de->d_name) > sizeof(path)-32) + continue; + sprintf(path, "/sys/block/%s/slaves", de->d_name); + if ((d_dir = opendir(path)) == NULL) + continue; + while ((d_de = readdir(d_dir)) != NULL) { + if (!strcmp(d_de->d_name, devname)) { + ret = 0; + break; + } + } + closedir(d_dir); + if (!ret) + break; + } + closedir(dir); + return ret; +} + +/* + * Probe a single block device to add to the device cache. + */ +static void probe_one(blkid_cache cache, const char *ptname, + dev_t devno, int pri, int only_if_new, int removable) +{ + blkid_dev dev = NULL; + struct list_head *p, *pnext; + const char **dir; + char *devname = NULL; + + /* See if we already have this device number in the cache. */ + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devno) { + if (only_if_new && !access(tmp->bid_name, F_OK)) + return; + dev = blkid_verify(cache, tmp); + if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) + break; + dev = 0; + } + } + if (dev && dev->bid_devno == devno) + goto set_pri; + + /* Try to translate private device-mapper dm-<N> names + * to standard /dev/mapper/<name>. + */ + if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { + devname = canonicalize_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (devname) + goto get_dev; + } + + /* + * Take a quick look at /dev/ptname for the device number. We check + * all of the likely device directories. If we don't find it, or if + * the stat information doesn't check out, use blkid_devno_to_devname() + * to find it via an exhaustive search for the device major/minor. + */ + for (dir = dirlist; *dir; dir++) { + struct stat st; + char device[256]; + + snprintf(device, sizeof(device), "%s/%s", *dir, ptname); + if ((dev = blkid_get_dev(cache, device, BLKID_DEV_FIND)) && + dev->bid_devno == devno) + goto set_pri; + + if (stat(device, &st) == 0 && + (S_ISBLK(st.st_mode) || + (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) && + st.st_rdev == devno) { + devname = strdup(device); + goto get_dev; + } + } + /* Do a short-cut scan of /dev/mapper first */ + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (!devname) { + devname = blkid_devno_to_devname(devno); + if (!devname) + return; + } + +get_dev: + dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); + free(devname); + +set_pri: + if (dev) { + if (pri) + dev->bid_pri = pri; + else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) { + dev->bid_pri = BLKID_PRI_DM; + if (is_dm_leaf(ptname)) + dev->bid_pri += 5; + } else if (!strncmp(ptname, "md", 2)) + dev->bid_pri = BLKID_PRI_MD; + if (removable) + dev->bid_flags |= BLKID_BID_FL_REMOVABLE; + } + return; +} + +#define PROC_PARTITIONS "/proc/partitions" +#define VG_DIR "/proc/lvm/VGs" + +/* + * This function initializes the UUID cache with devices from the LVM + * proc hierarchy. We currently depend on the names of the LVM + * hierarchy giving us the device structure in /dev. (XXX is this a + * safe thing to do?) + */ +#ifdef VG_DIR +static dev_t lvm_get_devno(const char *lvm_device) +{ + FILE *lvf; + char buf[1024]; + int ma, mi; + dev_t ret = 0; + + DBG(DEVNAME, ul_debug("opening %s", lvm_device)); + if ((lvf = fopen(lvm_device, "r" UL_CLOEXECSTR)) == NULL) { + DBG(DEVNAME, ul_debug("%s: (%d) %m", lvm_device, errno)); + return 0; + } + + while (fgets(buf, sizeof(buf), lvf)) { + if (sscanf(buf, "device: %d:%d", &ma, &mi) == 2) { + ret = makedev(ma, mi); + break; + } + } + fclose(lvf); + + return ret; +} + +static void lvm_probe_all(blkid_cache cache, int only_if_new) +{ + DIR *vg_list; + struct dirent *vg_iter; + int vg_len = strlen(VG_DIR); + dev_t dev; + + if ((vg_list = opendir(VG_DIR)) == NULL) + return; + + DBG(DEVNAME, ul_debug("probing LVM devices under %s", VG_DIR)); + + while ((vg_iter = readdir(vg_list)) != NULL) { + DIR *lv_list; + char *vdirname; + char *vg_name; + struct dirent *lv_iter; + + vg_name = vg_iter->d_name; + if (!strcmp(vg_name, ".") || !strcmp(vg_name, "..")) + continue; + vdirname = malloc(vg_len + strlen(vg_name) + 8); + if (!vdirname) + goto exit; + sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name); + + lv_list = opendir(vdirname); + free(vdirname); + if (lv_list == NULL) + continue; + + while ((lv_iter = readdir(lv_list)) != NULL) { + char *lv_name, *lvm_device; + + lv_name = lv_iter->d_name; + if (!strcmp(lv_name, ".") || !strcmp(lv_name, "..")) + continue; + + lvm_device = malloc(vg_len + strlen(vg_name) + + strlen(lv_name) + 8); + if (!lvm_device) { + closedir(lv_list); + goto exit; + } + sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name, + lv_name); + dev = lvm_get_devno(lvm_device); + sprintf(lvm_device, "%s/%s", vg_name, lv_name); + DBG(DEVNAME, ul_debug("LVM dev %s: devno 0x%04X", + lvm_device, + (unsigned int) dev)); + probe_one(cache, lvm_device, dev, BLKID_PRI_LVM, + only_if_new, 0); + free(lvm_device); + } + closedir(lv_list); + } +exit: + closedir(vg_list); +} +#endif + +#define PROC_EVMS_VOLUMES "/proc/evms/volumes" + +static int +evms_probe_all(blkid_cache cache, int only_if_new) +{ + char line[100]; + int ma, mi, sz, num = 0; + FILE *procpt; + char device[110]; + + procpt = fopen(PROC_EVMS_VOLUMES, "r" UL_CLOEXECSTR); + if (!procpt) + return 0; + while (fgets(line, sizeof(line), procpt)) { + if (sscanf (line, " %d %d %d %*s %*s %[^\n ]", + &ma, &mi, &sz, device) != 4) + continue; + + DBG(DEVNAME, ul_debug("Checking partition %s (%d, %d)", + device, ma, mi)); + + probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS, + only_if_new, 0); + num++; + } + fclose(procpt); + return num; +} + +static void +ubi_probe_all(blkid_cache cache, int only_if_new) +{ + const char **dirname; + + for (dirname = dirlist; *dirname; dirname++) { + DIR *dir; + struct dirent *iter; + + DBG(DEVNAME, ul_debug("probing UBI volumes under %s", + *dirname)); + + dir = opendir(*dirname); + if (dir == NULL) + continue ; + + while ((iter = readdir(dir)) != NULL) { + char *name; + struct stat st; + dev_t dev; + + name = iter->d_name; +#ifdef _DIRENT_HAVE_D_TYPE + if (iter->d_type != DT_UNKNOWN && + iter->d_type != DT_CHR && iter->d_type != DT_LNK) + continue; +#endif + if (!strcmp(name, ".") || !strcmp(name, "..") || + !strstr(name, "ubi")) + continue; + if (!strcmp(name, "ubi_ctrl")) + continue; + if (fstat_at(dirfd(dir), *dirname, name, &st, 0)) + continue; + + dev = st.st_rdev; + + if (!S_ISCHR(st.st_mode) || !minor(dev)) + continue; + DBG(DEVNAME, ul_debug("UBI vol %s/%s: devno 0x%04X", + *dirname, name, (int) dev)); + probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0); + } + closedir(dir); + } +} + +/* + * Read the device data for all available block devices in the system. + */ +static int probe_all(blkid_cache cache, int only_if_new) +{ + FILE *proc; + char line[1024]; + char ptname0[128 + 1], ptname1[128 + 1], *ptname = 0; + char *ptnames[2]; + dev_t devs[2]; + int ma, mi; + unsigned long long sz; + int lens[2] = { 0, 0 }; + int which = 0, last = 0; + struct list_head *p, *pnext; + + ptnames[0] = ptname0; + ptnames[1] = ptname1; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (cache->bic_flags & BLKID_BIC_FL_PROBED && + time(0) - cache->bic_time < BLKID_PROBE_INTERVAL) + return 0; + + blkid_read_cache(cache); + evms_probe_all(cache, only_if_new); +#ifdef VG_DIR + lvm_probe_all(cache, only_if_new); +#endif + ubi_probe_all(cache, only_if_new); + + proc = fopen(PROC_PARTITIONS, "r" UL_CLOEXECSTR); + if (!proc) + return -BLKID_ERR_PROC; + + while (fgets(line, sizeof(line), proc)) { + last = which; + which ^= 1; + ptname = ptnames[which]; + + if (sscanf(line, " %d %d %llu %128[^\n ]", + &ma, &mi, &sz, ptname) != 4) + continue; + devs[which] = makedev(ma, mi); + + DBG(DEVNAME, ul_debug("read partition name %s", ptname)); + + /* Skip whole disk devs unless they have no partitions. + * If base name of device has changed, also + * check previous dev to see if it didn't have a partn. + * heuristic: partition name ends in a digit, & partition + * names contain whole device name as substring. + * + * Skip extended partitions. + * heuristic: size is 1 + * + * FIXME: skip /dev/{ida,cciss,rd} whole-disk devs + */ + + lens[which] = strlen(ptname); + + /* ends in a digit, clearly a partition, so check */ + if (isdigit(ptname[lens[which] - 1])) { + DBG(DEVNAME, ul_debug("partition dev %s, devno 0x%04X", + ptname, (unsigned int) devs[which])); + + if (sz > 1) + probe_one(cache, ptname, devs[which], 0, + only_if_new, 0); + lens[which] = 0; /* mark as checked */ + } + + /* + * If last was a whole disk and we just found a partition + * on it, remove the whole-disk dev from the cache if + * it exists. + */ + if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) { + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp; + + /* find blkid dev for the whole-disk devno */ + tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devs[last]) { + DBG(DEVNAME, ul_debug("freeing %s", + tmp->bid_name)); + blkid_free_dev(tmp); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + break; + } + } + lens[last] = 0; + } + /* + * If last was not checked because it looked like a whole-disk + * dev, and the device's base name has changed, + * check last as well. + */ + if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { + DBG(DEVNAME, ul_debug("whole dev %s, devno 0x%04X", + ptnames[last], (unsigned int) devs[last])); + probe_one(cache, ptnames[last], devs[last], 0, + only_if_new, 0); + lens[last] = 0; + } + } + + /* Handle the last device if it wasn't partitioned */ + if (lens[which]) + probe_one(cache, ptname, devs[which], 0, only_if_new, 0); + + fclose(proc); + blkid_flush_cache(cache); + return 0; +} + +/* Don't use it by default -- it's pretty slow (because cdroms, floppy, ...) + */ +static int probe_all_removable(blkid_cache cache) +{ + DIR *dir; + struct dirent *d; + + if (!cache) + return -BLKID_ERR_PARAM; + + dir = opendir(_PATH_SYS_BLOCK); + if (!dir) + return -BLKID_ERR_PROC; + + while((d = readdir(dir))) { + struct sysfs_cxt sysfs = UL_SYSFSCXT_EMPTY; + int removable = 0; + dev_t devno; + +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK) + continue; +#endif + if (d->d_name[0] == '.' && + ((d->d_name[1] == 0) || + ((d->d_name[1] == '.') && (d->d_name[2] == 0)))) + continue; + + devno = sysfs_devname_to_devno(d->d_name, NULL); + if (!devno) + continue; + + if (sysfs_init(&sysfs, devno, NULL) == 0) { + if (sysfs_read_int(&sysfs, "removable", &removable) != 0) + removable = 0; + sysfs_deinit(&sysfs); + } + + if (removable) + probe_one(cache, d->d_name, devno, 0, 0, 1); + } + + closedir(dir); + return 0; +} + + +/** + * blkid_probe_all: + * @cache: cache handler + * + * Probes all block devices. + * + * Returns: 0 on success, or number less than zero in case of error. + */ +int blkid_probe_all(blkid_cache cache) +{ + int ret; + + DBG(PROBE, ul_debug("Begin blkid_probe_all()")); + ret = probe_all(cache, 0); + if (ret == 0) { + cache->bic_time = time(0); + cache->bic_flags |= BLKID_BIC_FL_PROBED; + } + DBG(PROBE, ul_debug("End blkid_probe_all() [rc=%d]", ret)); + return ret; +} + +/** + * blkid_probe_all_new: + * @cache: cache handler + * + * Probes all new block devices. + * + * Returns: 0 on success, or number less than zero in case of error. + */ +int blkid_probe_all_new(blkid_cache cache) +{ + int ret; + + DBG(PROBE, ul_debug("Begin blkid_probe_all_new()")); + ret = probe_all(cache, 1); + DBG(PROBE, ul_debug("End blkid_probe_all_new() [rc=%d]", ret)); + return ret; +} + +/** + * blkid_probe_all_removable: + * @cache: cache handler + * + * The libblkid probing is based on devices from /proc/partitions by default. + * This file usually does not contain removable devices (e.g. CDROMs) and this kind + * of devices are invisible for libblkid. + * + * This function adds removable block devices to @cache (probing is based on + * information from the /sys directory). Don't forget that removable devices + * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call + * this function by default. + * + * Note that devices which were detected by this function won't be written to + * blkid.tab cache file. + * + * Returns: 0 on success, or number less than zero in case of error. + */ +int blkid_probe_all_removable(blkid_cache cache) +{ + int ret; + + DBG(PROBE, ul_debug("Begin blkid_probe_all_removable()")); + ret = probe_all_removable(cache); + DBG(PROBE, ul_debug("End blkid_probe_all_removable() [rc=%d]", ret)); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(BLKID_DEBUG_ALL); + if (argc != 1) { + fprintf(stderr, "Usage: %s\n" + "Probe all devices and exit\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if (blkid_probe_all(cache) < 0) + printf("%s: error probing devices\n", argv[0]); + + if (blkid_probe_all_removable(cache) < 0) + printf("%s: error probing removable devices\n", argv[0]); + + blkid_put_cache(cache); + return (0); +} +#endif diff --git a/libblkid/src/devno.c b/libblkid/src/devno.c new file mode 100644 index 000000000..f4a36e4f5 --- /dev/null +++ b/libblkid/src/devno.c @@ -0,0 +1,375 @@ +/* + * devno.c - find a particular device by its device number (major/minor) + * + * Copyright (C) 2000, 2001, 2003 Theodore Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include <dirent.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif +#include <fcntl.h> +#include <inttypes.h> + +#include "blkidP.h" +#include "pathnames.h" +#include "at.h" +#include "sysfs.h" + +static char *blkid_strconcat(const char *a, const char *b, const char *c) +{ + char *res, *p; + size_t len, al, bl, cl; + + al = a ? strlen(a) : 0; + bl = b ? strlen(b) : 0; + cl = c ? strlen(c) : 0; + + len = al + bl + cl; + if (!len) + return NULL; + p = res = malloc(len + 1); + if (!res) + return NULL; + if (al) { + memcpy(p, a, al); + p += al; + } + if (bl) { + memcpy(p, b, bl); + p += bl; + } + if (cl) { + memcpy(p, c, cl); + p += cl; + } + *p = '\0'; + return res; +} + +/* + * This function adds an entry to the directory list + */ +static void add_to_dirlist(const char *dir, const char *subdir, + struct dir_list **list) +{ + struct dir_list *dp; + + dp = malloc(sizeof(struct dir_list)); + if (!dp) + return; + dp->name = subdir ? blkid_strconcat(dir, "/", subdir) : + dir ? strdup(dir) : NULL; + + if (!dp->name) { + free(dp); + return; + } + dp->next = *list; + *list = dp; +} + +/* + * This function frees a directory list + */ +static void free_dirlist(struct dir_list **list) +{ + struct dir_list *dp, *next; + + for (dp = *list; dp; dp = next) { + next = dp->next; + free(dp->name); + free(dp); + } + *list = NULL; +} + +void blkid__scan_dir(char *dirname, dev_t devno, struct dir_list **list, + char **devname) +{ + DIR *dir; + struct dirent *dp; + struct stat st; + + if ((dir = opendir(dirname)) == NULL) + return; + + while ((dp = readdir(dir)) != NULL) { +#ifdef _DIRENT_HAVE_D_TYPE + if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_BLK && + dp->d_type != DT_LNK && dp->d_type != DT_DIR) + continue; +#endif + if (dp->d_name[0] == '.' && + ((dp->d_name[1] == 0) || + ((dp->d_name[1] == '.') && (dp->d_name[2] == 0)))) + continue; + + if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 0)) + continue; + + if (S_ISBLK(st.st_mode) && st.st_rdev == devno) { + *devname = blkid_strconcat(dirname, "/", dp->d_name); + DBG(DEVNO, ul_debug("found 0x%llx at %s", (long long)devno, + *devname)); + break; + } + + if (!list || !S_ISDIR(st.st_mode)) + continue; + + /* add subdirectory (but not symlink) to the list */ +#ifdef _DIRENT_HAVE_D_TYPE + if (dp->d_type == DT_LNK) + continue; + if (dp->d_type == DT_UNKNOWN) +#endif + { + if (fstat_at(dirfd(dir), dirname, dp->d_name, &st, 1) || + !S_ISDIR(st.st_mode)) + continue; /* symlink or lstat() failed */ + } + + if (*dp->d_name == '.' || ( +#ifdef _DIRENT_HAVE_D_TYPE + dp->d_type == DT_DIR && +#endif + strcmp(dp->d_name, "shm") == 0)) + /* ignore /dev/.{udev,mount,mdadm} and /dev/shm */ + continue; + + add_to_dirlist(dirname, dp->d_name, list); + } + closedir(dir); + return; +} + +/* Directories where we will try to search for device numbers */ +static const char *devdirs[] = { "/devices", "/devfs", "/dev", NULL }; + +/** + * SECTION: misc + * @title: Miscellaneous utils + * @short_description: mix of various utils for low-level and high-level API + */ + + + +static char *scandev_devno_to_devpath(dev_t devno) +{ + struct dir_list *list = NULL, *new_list = NULL; + char *devname = NULL; + const char **dir; + + /* + * Add the starting directories to search in reverse order of + * importance, since we are using a stack... + */ + for (dir = devdirs; *dir; dir++) + add_to_dirlist(*dir, NULL, &list); + + while (list) { + struct dir_list *current = list; + + list = list->next; + DBG(DEVNO, ul_debug("directory %s", current->name)); + blkid__scan_dir(current->name, devno, &new_list, &devname); + free(current->name); + free(current); + if (devname) + break; + /* + * If we're done checking at this level, descend to + * the next level of subdirectories. (breadth-first) + */ + if (list == NULL) { + list = new_list; + new_list = NULL; + } + } + free_dirlist(&list); + free_dirlist(&new_list); + + return devname; +} + +/** + * blkid_devno_to_devname: + * @devno: device number + * + * This function finds the pathname to a block device with a given + * device number. + * + * Returns: a pointer to allocated memory to the pathname on success, + * and NULL on failure. + */ +char *blkid_devno_to_devname(dev_t devno) +{ + char *path = NULL; + char buf[PATH_MAX]; + + path = sysfs_devno_to_devpath(devno, buf, sizeof(buf)); + if (path) + path = strdup(path); + if (!path) + path = scandev_devno_to_devpath(devno); + + if (!path) { + DBG(DEVNO, ul_debug("blkid: couldn't find devno 0x%04lx", + (unsigned long) devno)); + } else { + DBG(DEVNO, ul_debug("found devno 0x%04llx as %s", (long long)devno, path)); + } + + return path; +} + + +/** + * blkid_devno_to_wholedisk: + * @dev: device number + * @diskname: buffer to return diskname (or NULL) + * @len: diskname buffer size (or 0) + * @diskdevno: pointer to returns devno of entire disk (or NULL) + * + * This function uses sysfs to convert the @devno device number to the *name* + * of the whole disk. The function DOES NOT return full device name. The @dev + * argument could be partition or whole disk -- both is converted. + * + * For example: sda1, 0x0801 --> sda, 0x0800 + * + * For conversion to the full disk *path* use blkid_devno_to_devname(), for + * example: + * + * <informalexample> + * <programlisting> + * + * dev_t dev = 0x0801, disk; // sda1 = 8:1 + * char *diskpath, diskname[32]; + * + * blkid_devno_to_wholedisk(dev, diskname, sizeof(diskname), &disk); + * diskpath = blkid_devno_to_devname(disk); + * + * // print "0x0801: sda, /dev/sda, 8:0 + * printf("0x%x: %s, %s, %d:%d\n", + * dev, diskname, diskpath, major(disk), minor(disk)); + * + * free(diskpath); + * + * </programlisting> + * </informalexample> + * + * Returns: 0 on success or -1 in case of error. + */ +int blkid_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno) +{ + return sysfs_devno_to_wholedisk( dev, diskname, len, diskdevno); +} + +/* + * Returns 1 if the @major number is associated with @drvname. + */ +int blkid_driver_has_major(const char *drvname, int major) +{ + FILE *f; + char buf[128]; + int match = 0; + + f = fopen(_PATH_PROC_DEVICES, "r" UL_CLOEXECSTR); + if (!f) + return 0; + + while (fgets(buf, sizeof(buf), f)) { /* skip to block dev section */ + if (strncmp("Block devices:\n", buf, sizeof(buf)) == 0) + break; + } + + while (fgets(buf, sizeof(buf), f)) { + int maj; + char name[64 + 1]; + + if (sscanf(buf, "%d %64[^\n ]", &maj, name) != 2) + continue; + + if (maj == major && strcmp(name, drvname) == 0) { + match = 1; + break; + } + } + + fclose(f); + + DBG(DEVNO, ul_debug("major %d %s associated with '%s' driver", + major, match ? "is" : "is NOT", drvname)); + return match; +} + +#ifdef TEST_PROGRAM +int main(int argc, char** argv) +{ + char *devname, *tmp; + char diskname[PATH_MAX]; + int major, minor; + dev_t devno, disk_devno; + const char *errmsg = "Couldn't parse %s: %s\n"; + + blkid_init_debug(BLKID_DEBUG_ALL); + if ((argc != 2) && (argc != 3)) { + fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n" + "Resolve a device number to a device name\n", + argv[0], argv[0]); + exit(1); + } + if (argc == 2) { + devno = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "device number", argv[1]); + exit(1); + } + } else { + major = strtoul(argv[1], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "major number", argv[1]); + exit(1); + } + minor = strtoul(argv[2], &tmp, 0); + if (*tmp) { + fprintf(stderr, errmsg, "minor number", argv[2]); + exit(1); + } + devno = makedev(major, minor); + } + printf("Looking for device 0x%04llx\n", (long long)devno); + devname = blkid_devno_to_devname(devno); + free(devname); + + printf("Looking for whole-device for 0x%04llx\n", (long long)devno); + if (blkid_devno_to_wholedisk(devno, diskname, + sizeof(diskname), &disk_devno) == 0) + printf("found devno 0x%04llx as /dev/%s\n", (long long) disk_devno, diskname); + + return 0; +} +#endif diff --git a/libblkid/encode.c b/libblkid/src/encode.c index ff57be4cb..ff57be4cb 100644 --- a/libblkid/encode.c +++ b/libblkid/src/encode.c diff --git a/libblkid/src/env.h b/libblkid/src/env.h new file mode 100644 index 000000000..a53d31027 --- /dev/null +++ b/libblkid/src/env.h @@ -0,0 +1,16 @@ +#ifndef UTIL_LINUX_ENV_H +#define UTIL_LINUX_ENV_H + +#include "c.h" + +extern void sanitize_env(void); +extern char *safe_getenv(const char *arg); + +static inline void xsetenv(char const *name, char const *val, int overwrite) +{ + if (setenv(name, val, overwrite) != 0) + err(EXIT_FAILURE, "failed to set the %s environment variable", name); +} + +#endif /* UTIL_LINUX_ENV_H */ + diff --git a/libblkid/src/evaluate.c b/libblkid/src/evaluate.c new file mode 100644 index 000000000..ffbe097e4 --- /dev/null +++ b/libblkid/src/evaluate.c @@ -0,0 +1,324 @@ +/* + * evaluate.c - very high-level API to evaluate LABELs or UUIDs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdint.h> +#include <stdarg.h> + +#include "pathnames.h" +#include "canonicalize.h" +#include "closestream.h" + +#include "blkidP.h" + +/** + * SECTION:evaluate + * @title: Tags and Spec evaluation + * @short_description: top-level API for LABEL and UUID evaluation. + * + * This API provides very simple and portable way how evaluate LABEL and UUID + * tags. The blkid_evaluate_tag() and blkid_evaluate_spec() work on 2.4 and + * 2.6 systems and on systems with or without udev. Currently, the libblkid + * library supports "udev" and "scan" methods. The "udev" method uses udev + * /dev/disk/by-* symlinks and the "scan" method scans all block devices from + * the /proc/partitions file. The evaluation could be controlled by the + * /etc/blkid.conf config file. The default is to try "udev" and then "scan" + * method. + * + * The blkid_evaluate_tag() also automatically informs udevd when an obsolete + * /dev/disk/by-* symlink is detected. + * + * If you are not sure how translate LABEL or UUID to the device name use this + * API. + */ + +#ifdef CONFIG_BLKID_VERIFY_UDEV +/* returns zero when the device has NAME=value (LABEL/UUID) */ +static int verify_tag(const char *devname, const char *name, const char *value) +{ + blkid_probe pr; + int fd = -1, rc = -1; + size_t len; + const char *data; + int errsv = 0; + + pr = blkid_new_probe(); + if (!pr) + return -1; + + blkid_probe_enable_superblocks(pr, TRUE); + blkid_probe_set_superblocks_flags(pr, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); + + blkid_probe_enable_partitions(pr, TRUE); + blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); + + fd = open(devname, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + errsv = errno; + goto done; + } + if (blkid_probe_set_device(pr, fd, 0, 0)) + goto done; + rc = blkid_do_safeprobe(pr); + if (rc) + goto done; + rc = blkid_probe_lookup_value(pr, name, &data, &len); + if (!rc) + rc = memcmp(value, data, len); +done: + DBG(EVALUATE, ul_debug("%s: %s verification %s", + devname, name, rc == 0 ? "PASS" : "FAILED")); + if (fd >= 0) + close(fd); + blkid_free_probe(pr); + + /* for non-root users we use unverified udev links */ + return errsv == EACCES ? 0 : rc; +} +#endif /* CONFIG_BLKID_VERIFY_UDEV*/ + +/** + * blkid_send_uevent: + * @devname: absolute path to the device + * @action: event string + * + * Returns: -1 in case of failure, or 0 on success. + */ +int blkid_send_uevent(const char *devname, const char *action) +{ + char uevent[PATH_MAX]; + struct stat st; + FILE *f; + int rc = -1; + + DBG(EVALUATE, ul_debug("%s: uevent '%s' requested", devname, action)); + + if (!devname || !action) + return -1; + if (stat(devname, &st) || !S_ISBLK(st.st_mode)) + return -1; + + snprintf(uevent, sizeof(uevent), "/sys/dev/block/%d:%d/uevent", + major(st.st_rdev), minor(st.st_rdev)); + + f = fopen(uevent, "w" UL_CLOEXECSTR); + if (f) { + rc = 0; + if (fputs(action, f) >= 0) + rc = 0; + if (close_stream(f) != 0) + DBG(EVALUATE, ul_debug("write failed: %s", uevent)); + } + DBG(EVALUATE, ul_debug("%s: send uevent %s", + uevent, rc == 0 ? "SUCCES" : "FAILED")); + return rc; +} + +static char *evaluate_by_udev(const char *token, const char *value, int uevent) +{ + char dev[PATH_MAX]; + char *path = NULL; + size_t len; + struct stat st; + + DBG(EVALUATE, ul_debug("evaluating by udev %s=%s", token, value)); + + if (!strcmp(token, "UUID")) + strcpy(dev, _PATH_DEV_BYUUID "/"); + else if (!strcmp(token, "LABEL")) + strcpy(dev, _PATH_DEV_BYLABEL "/"); + else if (!strcmp(token, "PARTLABEL")) + strcpy(dev, _PATH_DEV_BYPARTLABEL "/"); + else if (!strcmp(token, "PARTUUID")) + strcpy(dev, _PATH_DEV_BYPARTUUID "/"); + else { + DBG(EVALUATE, ul_debug("unsupported token %s", token)); + return NULL; /* unsupported tag */ + } + + len = strlen(dev); + if (blkid_encode_string(value, &dev[len], sizeof(dev) - len) != 0) + return NULL; + + DBG(EVALUATE, ul_debug("expected udev link: %s", dev)); + + if (stat(dev, &st)) + goto failed; /* link or device does not exist */ + + if (!S_ISBLK(st.st_mode)) + return NULL; + + path = canonicalize_path(dev); + if (!path) + return NULL; + +#ifdef CONFIG_BLKID_VERIFY_UDEV + if (verify_tag(path, token, value)) + goto failed; +#endif + return path; + +failed: + DBG(EVALUATE, ul_debug("failed to evaluate by udev")); + + if (uevent && path) + blkid_send_uevent(path, "change"); + free(path); + return NULL; +} + +static char *evaluate_by_scan(const char *token, const char *value, + blkid_cache *cache, struct blkid_config *conf) +{ + blkid_cache c = cache ? *cache : NULL; + char *res; + + DBG(EVALUATE, ul_debug("evaluating by blkid scan %s=%s", token, value)); + + if (!c) { + char *cachefile = blkid_get_cache_filename(conf); + blkid_get_cache(&c, cachefile); + free(cachefile); + } + if (!c) + return NULL; + + res = blkid_get_devname(c, token, value); + + if (cache) + *cache = c; + else + blkid_put_cache(c); + + return res; +} + +/** + * blkid_evaluate_tag: + * @token: token name (e.g "LABEL" or "UUID") or unparsed tag (e.g. "LABEL=foo") + * @value: token data (e.g. "foo") + * @cache: pointer to cache (or NULL when you don't want to re-use the cache) + * + * Returns: allocated string with a device name. + */ +char *blkid_evaluate_tag(const char *token, const char *value, blkid_cache *cache) +{ + struct blkid_config *conf = NULL; + char *t = NULL, *v = NULL; + char *ret = NULL; + int i; + + if (!token) + return NULL; + + if (!cache || !*cache) + blkid_init_debug(0); + + DBG(EVALUATE, ul_debug("evaluating %s%s%s", token, value ? "=" : "", + value ? value : "")); + + if (!value) { + if (!strchr(token, '=')) { + ret = strdup(token); + goto out; + } + blkid_parse_tag_string(token, &t, &v); + if (!t || !v) + goto out; + token = t; + value = v; + } + + conf = blkid_read_config(NULL); + if (!conf) + goto out; + + for (i = 0; i < conf->nevals; i++) { + if (conf->eval[i] == BLKID_EVAL_UDEV) + ret = evaluate_by_udev(token, value, conf->uevent); + else if (conf->eval[i] == BLKID_EVAL_SCAN) + ret = evaluate_by_scan(token, value, cache, conf); + if (ret) + break; + } + + DBG(EVALUATE, ul_debug("%s=%s evaluated as %s", token, value, ret)); +out: + blkid_free_config(conf); + free(t); + free(v); + return ret; +} + +/** + * blkid_evaluate_spec: + * @spec: unparsed tag (e.g. "LABEL=foo") or path (e.g. /dev/dm-0) + * @cache: pointer to cache (or NULL when you don't want to re-use the cache) + * + * All returned paths are canonicalized, device-mapper paths are converted + * to the /dev/mapper/name format. + * + * Returns: allocated string with a device name. + */ +char *blkid_evaluate_spec(const char *spec, blkid_cache *cache) +{ + char *t = NULL, *v = NULL, *res; + + if (!spec) + return NULL; + + if (strchr(spec, '=') && + blkid_parse_tag_string(spec, &t, &v) != 0) /* parse error */ + return NULL; + + if (v) + res = blkid_evaluate_tag(t, v, cache); + else + res = canonicalize_path(spec); + + free(t); + free(v); + return res; +} + + +#ifdef TEST_PROGRAM +int main(int argc, char *argv[]) +{ + blkid_cache cache = NULL; + char *res; + + if (argc < 2) { + fprintf(stderr, "usage: %s <tag> | <spec>\n", argv[0]); + return EXIT_FAILURE; + } + + blkid_init_debug(0); + + res = blkid_evaluate_spec(argv[1], &cache); + if (res) + printf("%s\n", res); + if (cache) + blkid_put_cache(cache); + + return res ? EXIT_SUCCESS : EXIT_FAILURE; +} +#endif diff --git a/libblkid/src/exec_shell.h b/libblkid/src/exec_shell.h new file mode 100644 index 000000000..a2aa757de --- /dev/null +++ b/libblkid/src/exec_shell.h @@ -0,0 +1 @@ +extern void __attribute__((__noreturn__)) exec_shell(void); diff --git a/libblkid/src/fileutils.h b/libblkid/src/fileutils.h new file mode 100644 index 000000000..3353f69a0 --- /dev/null +++ b/libblkid/src/fileutils.h @@ -0,0 +1,33 @@ +#ifndef UTIL_LINUX_FILEUTILS +#define UTIL_LINUX_FILEUTILS + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#include "c.h" + +extern int xmkstemp(char **tmpname, char *dir); + +static inline FILE *xfmkstemp(char **tmpname, char *dir) +{ + int fd; + FILE *ret; + + fd = xmkstemp(tmpname, dir); + if (fd == -1) + return NULL; + + if (!(ret = fdopen(fd, "w+" UL_CLOEXECSTR))) { + close(fd); + return NULL; + } + return ret; +} + +extern int get_fd_tabsize(void); + +extern int mkdir_p(const char *path, mode_t mode); +extern char *stripoff_last_component(char *path); + +#endif /* UTIL_LINUX_FILEUTILS */ diff --git a/libblkid/getsize.c b/libblkid/src/getsize.c index abe6ebc9c..abe6ebc9c 100644 --- a/libblkid/getsize.c +++ b/libblkid/src/getsize.c diff --git a/libblkid/src/init.c b/libblkid/src/init.c new file mode 100644 index 000000000..eead6c7df --- /dev/null +++ b/libblkid/src/init.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +/** + * SECTION: init + * @title: Library initialization + * @short_description: initialize debuging + */ + +#include <stdarg.h> + +#include "blkidP.h" + +UL_DEBUG_DEFINE_MASK(libblkid); +UL_DEBUG_DEFINE_MASKNAMES(libblkid) = +{ + { "all", BLKID_DEBUG_ALL, "info about all subsystems" }, + { "cache", BLKID_DEBUG_CACHE, "blkid tags cache" }, + { "config", BLKID_DEBUG_CONFIG, "config file utils" }, + { "dev", BLKID_DEBUG_DEV, "device utils" }, + { "devname", BLKID_DEBUG_DEVNAME, "/proc/partitions evaluation" }, + { "devno", BLKID_DEBUG_DEVNO, "convertions to device name" }, + { "evaluate", BLKID_DEBUG_EVALUATE, "tags resolving" }, + { "help", BLKID_DEBUG_HELP, "this help" }, + { "lowprobe", BLKID_DEBUG_LOWPROBE, "superblock/raids/partitions probing" }, + { "probe", BLKID_DEBUG_PROBE, "devices verification" }, + { "read", BLKID_DEBUG_READ, "cache parsing" }, + { "save", BLKID_DEBUG_SAVE, "cache writing" }, + { "tag", BLKID_DEBUG_TAG, "tags utils" }, + { NULL, 0, NULL } +}; + +/** + * blkid_init_debug: + * @mask: debug mask (0xffff to enable full debuging) + * + * If the @mask is not specified then this function reads + * LIBBLKID_DEBUG environment variable to get the mask. + * + * Already initialized debugging stuff cannot be changed. It does not + * have effect to call this function twice. + */ +void blkid_init_debug(int mask) +{ + if (libblkid_debug_mask) + return; + + __UL_INIT_DEBUG(libblkid, BLKID_DEBUG_, mask, LIBBLKID_DEBUG); + + if (libblkid_debug_mask != BLKID_DEBUG_INIT + && libblkid_debug_mask != (BLKID_DEBUG_HELP|BLKID_DEBUG_INIT)) { + const char *ver = NULL; + const char *date = NULL; + + blkid_get_library_version(&ver, &date); + DBG(INIT, ul_debug("library debug mask: 0x%04x", libblkid_debug_mask)); + DBG(INIT, ul_debug("library version: %s [%s]", ver, date)); + + } + ON_DBG(HELP, ul_debug_print_masks("LIBBLKID_DEBUG", + UL_DEBUG_MASKNAMES(libblkid))); +} diff --git a/libblkid/src/ismounted.h b/libblkid/src/ismounted.h new file mode 100644 index 000000000..57918cb3a --- /dev/null +++ b/libblkid/src/ismounted.h @@ -0,0 +1,14 @@ +#ifndef IS_MOUNTED_H +#define IS_MOUNTED_H + +#define MF_MOUNTED 1 +#define MF_ISROOT 2 +#define MF_READONLY 4 +#define MF_SWAP 8 +#define MF_BUSY 16 + +extern int is_mounted(const char *file); +extern int check_mount_point(const char *device, int *mount_flags, + char *mtpt, int mtlen); + +#endif /* IS_MOUNTED_H */ diff --git a/libblkid/src/libblkid.sym b/libblkid/src/libblkid.sym new file mode 100644 index 000000000..6b3cf0805 --- /dev/null +++ b/libblkid/src/libblkid.sym @@ -0,0 +1,166 @@ +/* + * The symbol versioning ensures that a new application requiring symbol 'foo' + * can't run with old library.so not providing 'foo' - the global SONAME + * version info can't enforce this since we never change the SONAME. + * + * The original libblkid from e2fsprogs (<=1.41.4) does not to use + * symbol versioning -- all the original symbols are in BLKID_1.0 now. + * + * Copyright (C) 2009-2014 Karel Zak <kzak@redhat.com> + */ +BLKID_1.0 { +global: + blkid_dev_devname; + blkid_dev_has_tag; + blkid_dev_iterate_begin; + blkid_dev_iterate_end; + blkid_dev_next; + blkid_devno_to_devname; + blkid_dev_set_search; + blkid_find_dev_with_tag; + blkid_gc_cache; + blkid_get_cache; + blkid_get_dev; + blkid_get_devname; + blkid_get_dev_size; + blkid_get_library_version; + blkid_get_tag_value; + blkid_known_fstype; + blkid_parse_tag_string; + blkid_parse_version_string; + blkid_probe_all; + blkid_probe_all_new; + blkid_put_cache; + blkid_tag_iterate_begin; + blkid_tag_iterate_end; + blkid_tag_next; + blkid_verify; +local: + *; +}; + + +/* + * symbols since util-linux 2.15 + */ +BLKID_2.15 { +global: + blkid_do_probe; + blkid_do_safeprobe; + blkid_encode_string; + blkid_evaluate_tag; + blkid_free_probe; + blkid_new_probe; + blkid_probe_filter_types; + blkid_probe_filter_usage; + blkid_probe_get_value; + blkid_probe_has_value; + blkid_probe_invert_filter; + blkid_probe_lookup_value; + blkid_probe_numof_values; + blkid_probe_reset_filter; + blkid_probe_set_device; + blkid_probe_set_request; + blkid_reset_probe; + blkid_safe_string; + blkid_send_uevent; +} BLKID_1.0; + +/* + * symbols since util-linux 2.17 + */ +BLKID_2.17 { +global: + blkid_devno_to_wholedisk; + blkid_do_fullprobe; + blkid_known_pttype; + blkid_new_probe_from_filename; + 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_type_string; + 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_partitions_type; + 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_sectors; + blkid_probe_get_size; + blkid_probe_get_topology; + blkid_probe_invert_partitions_filter; + blkid_probe_invert_superblocks_filter; + blkid_probe_reset_partitions_filter; + blkid_probe_reset_superblocks_filter; + blkid_probe_set_partitions_flags; + blkid_probe_set_superblocks_flags; + blkid_topology_get_alignment_offset; + blkid_topology_get_logical_sector_size; + blkid_topology_get_minimum_io_size; + blkid_topology_get_optimal_io_size; + blkid_topology_get_physical_sector_size; +} BLKID_2.15; + +/* + * symbols since util-linux 2.18 + */ +BLKID_2.18 { +global: + blkid_partition_get_flags; + blkid_partlist_devno_to_partition; + blkid_partlist_get_table; + blkid_probe_all_removable; + blkid_probe_get_fd; + blkid_probe_get_offset; + blkid_probe_get_wholedisk_devno; + blkid_probe_is_wholedisk; +} BLKID_2.17; + +/* + * symbols since util-linux 2.20 + */ +BLKID_2.20 { +global: + blkid_evaluate_spec; + blkid_superblocks_get_name; +} BLKID_2.18; + +/* + * symbols since util-linux 2.21 + */ +BLKID_2.21 { +global: + blkid_do_wipe; +} BLKID_2.20; + +/* + * symbols since util-linux 2.23 + */ +BLKID_2.23 { +global: + blkid_probe_step_back; + blkid_parttable_get_id; + blkid_init_debug; +} BLKID_2.21; + +/* + * symbols since util-linux 2.25 + */ +BLKID_2.25 { + blkid_partlist_get_partition_by_partno; +} BLKID_2.23; diff --git a/libblkid/src/linux_version.h b/libblkid/src/linux_version.h new file mode 100644 index 000000000..a6a1e99c7 --- /dev/null +++ b/libblkid/src/linux_version.h @@ -0,0 +1,14 @@ +#ifndef LINUX_VERSION_H +#define LINUX_VERSION_H + +#ifdef HAVE_LINUX_VERSION_H +# include <linux/version.h> +#endif + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +int get_linux_version(void); + +#endif /* LINUX_VERSION_H */ diff --git a/libblkid/list.h b/libblkid/src/list.h index 7b6067239..7b6067239 100644 --- a/libblkid/list.h +++ b/libblkid/src/list.h diff --git a/libblkid/src/llseek.c b/libblkid/src/llseek.c new file mode 100644 index 000000000..67334785a --- /dev/null +++ b/libblkid/src/llseek.c @@ -0,0 +1,142 @@ +/* + * llseek.c -- stub calling the llseek system call + * + * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef __MSDOS__ +#include <io.h> +#endif + +#include "blkidP.h" + +#ifdef __linux__ + +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + +#define my_llseek lseek64 + +#elif defined(HAVE_LLSEEK) +#include <syscall.h> + +#ifndef HAVE_LLSEEK_PROTOTYPE +extern long long llseek(int fd, long long offset, int origin); +#endif + +#define my_llseek llseek + +#else /* ! HAVE_LLSEEK */ + +#if SIZEOF_LONG == SIZEOF_LONG_LONG + +#define llseek lseek + +#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */ + +#include <linux/unistd.h> + +#ifndef __NR__llseek +#define __NR__llseek 140 +#endif + +#ifndef __i386__ +static int _llseek(unsigned int, unsigned long, unsigned long, + blkid_loff_t *, unsigned int); + +static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high, + unsigned long, offset_low, blkid_loff_t *, result, + unsigned int, origin) +#endif +/* +static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin) +{ + blkid_loff_t result; + int retval; + +#ifndef __i386__ + retval = _llseek(fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#else + retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32, + ((unsigned long long)offset) & 0xffffffff, + &result, origin); +#endif + return (retval == -1 ? (blkid_loff_t) retval : result); +} +*/ +#endif /* __alpha__ || __ia64__ */ + +#endif /* HAVE_LLSEEK */ + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence) +{ + blkid_loff_t result; + static int do_compat = 0; + + if ((sizeof(off_t) >= sizeof(blkid_loff_t)) || + (offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1)))) + return lseek(fd, (off_t) offset, whence); + + if (do_compat) { + errno = EOVERFLOW; + return -1; + } + + result = lseek64(fd, offset, whence); + if (result == -1 && errno == ENOSYS) { + /* + * Just in case this code runs on top of an old kernel + * which does not support the llseek system call + */ + do_compat++; + errno = EOVERFLOW; + } + return result; +} + +#else /* !linux */ + +#ifndef EOVERFLOW +#ifdef EXT2_ET_INVALID_ARGUMENT +#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT +#else +#define EOVERFLOW 112 +#endif +#endif + +blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin) +{ +#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) + return lseek64 (fd, offset, origin); +#else + if ((sizeof(off_t) < sizeof(blkid_loff_t)) && + (offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) { + errno = EOVERFLOW; + return -1; + } + return lseek(fd, (off_t) offset, origin); +#endif +} + +#endif /* linux */ + + diff --git a/libblkid/src/loopdev.h b/libblkid/src/loopdev.h new file mode 100644 index 000000000..573a5699d --- /dev/null +++ b/libblkid/src/loopdev.h @@ -0,0 +1,193 @@ +#ifndef UTIL_LINUX_LOOPDEV_H +#define UTIL_LINUX_LOOPDEV_H + +#include "sysfs.h" + +/* + * loop_info.lo_encrypt_type + */ +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 +#define LO_CRYPT_CRYPTOAPI 18 + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +/* + * Obsolete (kernel < 2.6) + * + * #define LOOP_SET_STATUS 0x4C02 + * #define LOOP_GET_STATUS 0x4C03 + */ +#define LOOP_SET_STATUS64 0x4C04 +#define LOOP_GET_STATUS64 0x4C05 +/* #define LOOP_CHANGE_FD 0x4C06 */ +#define LOOP_SET_CAPACITY 0x4C07 + +/* /dev/loop-control interface */ +#ifndef LOOP_CTL_ADD +# define LOOP_CTL_ADD 0x4C80 +# define LOOP_CTL_REMOVE 0x4C81 +# define LOOP_CTL_GET_FREE 0x4C82 +#endif + +/* + * loop_info.lo_flags + */ +enum { + LO_FLAGS_READ_ONLY = 1, + LO_FLAGS_USE_AOPS = 2, + LO_FLAGS_AUTOCLEAR = 4, /* kernel >= 2.6.25 */ + LO_FLAGS_PARTSCAN = 8, /* kernel >= 3.2 */ +}; + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +/* + * Linux LOOP_{SET,GET}_STATUS64 ioctl struct + */ +struct loop_info64 { + uint64_t lo_device; + uint64_t lo_inode; + uint64_t lo_rdevice; + uint64_t lo_offset; + uint64_t lo_sizelimit; /* bytes, 0 == max available */ + uint32_t lo_number; + uint32_t lo_encrypt_type; + uint32_t lo_encrypt_key_size; + uint32_t lo_flags; + uint8_t lo_file_name[LO_NAME_SIZE]; + uint8_t lo_crypt_name[LO_NAME_SIZE]; + uint8_t lo_encrypt_key[LO_KEY_SIZE]; + uint64_t lo_init[2]; +}; + +#define LOOPDEV_MAJOR 7 /* loop major number */ +#define LOOPDEV_DEFAULT_NNODES 8 /* default number of loop devices */ + +struct loopdev_iter { + FILE *proc; /* /proc/partitions */ + DIR *sysblock; /* /sys/block */ + int ncur; /* current position */ + int *minors; /* ary of minor numbers (when scan whole /dev) */ + int nminors; /* number of items in *minors */ + int ct_perm; /* count permission problems */ + int ct_succ; /* count number of detected devices */ + + unsigned int done:1; /* scanning done */ + unsigned int default_check:1;/* check first LOOPDEV_NLOOPS */ + int flags; /* LOOPITER_FL_* flags */ +}; + +enum { + LOOPITER_FL_FREE = (1 << 0), + LOOPITER_FL_USED = (1 << 1) +}; + +/* + * handler for work with loop devices + */ +struct loopdev_cxt { + char device[128]; /* device path (e.g. /dev/loop<N>) */ + char *filename; /* backing file for loopcxt_set_... */ + int fd; /* open(/dev/looo<N>) */ + int mode; /* fd mode O_{RDONLY,RDWR} */ + + int flags; /* LOOPDEV_FL_* flags */ + unsigned int has_info:1; /* .info contains data */ + unsigned int extra_check:1; /* unusual stuff for iterator */ + unsigned int info_failed:1; /* LOOP_GET_STATUS ioctl failed */ + unsigned int control_ok:1; /* /dev/loop-control success */ + + struct sysfs_cxt sysfs; /* pointer to /sys/dev/block/<maj:min>/ */ + struct loop_info64 info; /* for GET/SET ioctl */ + struct loopdev_iter iter; /* scans /sys or /dev for used/free devices */ +}; + +#define UL_LOOPDEVCXT_EMPTY { .fd = -1, .sysfs = UL_SYSFSCXT_EMPTY } + +/* + * loopdev_cxt.flags + */ +enum { + LOOPDEV_FL_RDONLY = (1 << 0), /* open(/dev/loop) mode; default */ + LOOPDEV_FL_RDWR = (1 << 1), /* necessary for loop setup only */ + LOOPDEV_FL_OFFSET = (1 << 4), + LOOPDEV_FL_NOSYSFS = (1 << 5), + LOOPDEV_FL_NOIOCTL = (1 << 6), + LOOPDEV_FL_DEVSUBDIR = (1 << 7), + LOOPDEV_FL_CONTROL = (1 << 8), /* system with /dev/loop-control */ + LOOPDEV_FL_SIZELIMIT = (1 << 9) +}; + +/* + * High-level + */ +extern int loopmod_supports_partscan(void); + +extern int is_loopdev(const char *device); +extern int loopdev_is_autoclear(const char *device); + +extern char *loopdev_get_backing_file(const char *device); +extern int loopdev_is_used(const char *device, const char *filename, + uint64_t offset, int flags); +extern char *loopdev_find_by_backing_file(const char *filename, + uint64_t offset, int flags); +extern int loopcxt_find_unused(struct loopdev_cxt *lc); +extern int loopdev_delete(const char *device); +extern int loopdev_count_by_backing_file(const char *filename, char **loopdev); + +/* + * Low-level + */ +extern int loopcxt_init(struct loopdev_cxt *lc, int flags) + __attribute__ ((warn_unused_result)); +extern void loopcxt_deinit(struct loopdev_cxt *lc); + +extern int loopcxt_set_device(struct loopdev_cxt *lc, const char *device) + __attribute__ ((warn_unused_result)); +extern int loopcxt_has_device(struct loopdev_cxt *lc); +extern int loopcxt_add_device(struct loopdev_cxt *lc); +extern char *loopcxt_strdup_device(struct loopdev_cxt *lc); +extern const char *loopcxt_get_device(struct loopdev_cxt *lc); +extern struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc); +extern struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc); + +extern int loopcxt_get_fd(struct loopdev_cxt *lc); +extern int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode); + +extern int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags); +extern int loopcxt_deinit_iterator(struct loopdev_cxt *lc); +extern int loopcxt_next(struct loopdev_cxt *lc); + +extern int loopcxt_setup_device(struct loopdev_cxt *lc); +extern int loopcxt_delete_device(struct loopdev_cxt *lc); +extern int loopcxt_set_capacity(struct loopdev_cxt *lc); + +int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset); +int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit); +int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags); +int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename); + +extern char *loopcxt_get_backing_file(struct loopdev_cxt *lc); +extern int loopcxt_get_backing_devno(struct loopdev_cxt *lc, dev_t *devno); +extern int loopcxt_get_backing_inode(struct loopdev_cxt *lc, ino_t *ino); +extern int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset); +extern int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size); +extern int loopcxt_get_encrypt_type(struct loopdev_cxt *lc, uint32_t *type); +extern const char *loopcxt_get_crypt_name(struct loopdev_cxt *lc); +extern int loopcxt_is_autoclear(struct loopdev_cxt *lc); +extern int loopcxt_is_readonly(struct loopdev_cxt *lc); +extern int loopcxt_is_partscan(struct loopdev_cxt *lc); +extern int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, + const char *filename, + uint64_t offset, int flags); + +extern int loopcxt_is_used(struct loopdev_cxt *lc, + struct stat *st, + const char *backing_file, + uint64_t offset, + int flags); + +#endif /* UTIL_LINUX_LOOPDEV_H */ diff --git a/libblkid/src/mangle.h b/libblkid/src/mangle.h new file mode 100644 index 000000000..ec492b556 --- /dev/null +++ b/libblkid/src/mangle.h @@ -0,0 +1,26 @@ +#ifndef UTIL_LINUX_MANGLE_H +#define UTIL_LINUX_MANGLE_H + +/* + * Functions for \oct encoding used in mtab/fstab/swaps/etc. + */ + +extern char *mangle(const char *s); + +extern void unmangle_to_buffer(const char *s, char *buf, size_t len); +void unhexmangle_to_buffer(const char *s, char *buf, size_t len); + +extern char *unmangle(const char *s, char **end); + +static inline void unmangle_string(char *s) +{ + unmangle_to_buffer(s, s, strlen(s) + 1); +} + +static inline void unhexmangle_string(char *s) +{ + unhexmangle_to_buffer(s, s, strlen(s) + 1); +} + +#endif /* UTIL_LINUX_MANGLE_H */ + diff --git a/libblkid/src/match.h b/libblkid/src/match.h new file mode 100644 index 000000000..94440c22e --- /dev/null +++ b/libblkid/src/match.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2011 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef UTIL_LINUX_MATCH_H +#define UTIL_LINUX_MATCH_H + +extern int match_fstype(const char *type, const char *pattern); + +#endif /* UTIL_LINUX_MATCH_H */ diff --git a/libblkid/src/mbsalign.h b/libblkid/src/mbsalign.h new file mode 100644 index 000000000..5eaf606e5 --- /dev/null +++ b/libblkid/src/mbsalign.h @@ -0,0 +1,56 @@ +/* Align/Truncate a string in a given screen width + Copyright (C) 2009-2010 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Karel Zak <kzak@redhat.com> + + This program 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 program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef UTIL_LINUX_MBSALIGN_H +# define UTIL_LINUX_MBSALIGN_H +# include <stddef.h> + +typedef enum { MBS_ALIGN_LEFT, MBS_ALIGN_RIGHT, MBS_ALIGN_CENTER } mbs_align_t; + +enum { + /* Use unibyte mode for invalid multibyte strings or + or when heap memory is exhausted. */ + MBA_UNIBYTE_FALLBACK = 0x0001, + +#if 0 /* Other possible options. */ + /* Skip invalid multibyte chars rather than failing */ + MBA_IGNORE_INVALID = 0x0002, + + /* Align multibyte strings using "figure space" (\u2007) */ + MBA_USE_FIGURE_SPACE = 0x0004, + + /* Don't add any padding */ + MBA_TRUNCATE_ONLY = 0x0008, + + /* Don't truncate */ + MBA_PAD_ONLY = 0x0010, +#endif +}; + +extern size_t mbs_truncate(char *str, size_t *width); + +extern size_t mbsalign (const char *src, char *dest, + size_t dest_size, size_t *width, + mbs_align_t align, int flags); + +extern size_t mbs_safe_nwidth(const char *buf, size_t bufsz, size_t *sz); +extern size_t mbs_safe_width(const char *s); + +extern char *mbs_safe_encode(const char *s, size_t *width); +extern char *mbs_safe_encode_to_buffer(const char *s, size_t *width, char *buf); +extern size_t mbs_safe_encode_size(size_t bytes); + +#endif /* UTIL_LINUX_MBSALIGN_H */ diff --git a/libblkid/src/md5.h b/libblkid/src/md5.h new file mode 100644 index 000000000..d997e379d --- /dev/null +++ b/libblkid/src/md5.h @@ -0,0 +1,29 @@ +#ifndef MD5_H +#define MD5_H + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#else +typedef unsigned int uint32_t; +#endif + +#define MD5LENGTH 16 + +struct MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[MD5LENGTH], struct MD5Context *context); +void MD5Transform(uint32_t buf[4], uint32_t const in[16]); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ diff --git a/libblkid/src/nls.h b/libblkid/src/nls.h new file mode 100644 index 000000000..3eabfe63b --- /dev/null +++ b/libblkid/src/nls.h @@ -0,0 +1,115 @@ +#ifndef UTIL_LINUX_NLS_H +#define UTIL_LINUX_NLS_H + +int main(int argc, char *argv[]); + +#ifndef LOCALEDIR +#define LOCALEDIR "/usr/share/locale" +#endif + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#else +# undef setlocale +# define setlocale(Category, Locale) /* empty */ +struct lconv +{ + char *decimal_point; +}; +# undef localeconv +# define localeconv() NULL +#endif + +#ifdef ENABLE_NLS +# include <libintl.h> +# define _(Text) gettext (Text) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +# define P_(Singular, Plural, n) ngettext (Singular, Plural, n) +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) (Text) +# define N_(Text) (Text) +# define P_(Singular, Plural, n) ((n) == 1 ? (Singular) : (Plural)) +#endif + +#ifdef HAVE_LANGINFO_H +# include <langinfo.h> +#else + +typedef int nl_item; +extern char *langinfo_fallback(nl_item item); + +# define nl_langinfo langinfo_fallback + +enum { + CODESET = 1, + RADIXCHAR, + THOUSEP, + D_T_FMT, + D_FMT, + T_FMT, + T_FMT_AMPM, + AM_STR, + PM_STR, + + DAY_1, + DAY_2, + DAY_3, + DAY_4, + DAY_5, + DAY_6, + DAY_7, + + ABDAY_1, + ABDAY_2, + ABDAY_3, + ABDAY_4, + ABDAY_5, + ABDAY_6, + ABDAY_7, + + MON_1, + MON_2, + MON_3, + MON_4, + MON_5, + MON_6, + MON_7, + MON_8, + MON_9, + MON_10, + MON_11, + MON_12, + + ABMON_1, + ABMON_2, + ABMON_3, + ABMON_4, + ABMON_5, + ABMON_6, + ABMON_7, + ABMON_8, + ABMON_9, + ABMON_10, + ABMON_11, + ABMON_12, + + ERA_D_FMT, + ERA_D_T_FMT, + ERA_T_FMT, + ALT_DIGITS, + CRNCYSTR, + YESEXPR, + NOEXPR +}; + +#endif /* !HAVE_LANGINFO_H */ + +#endif /* UTIL_LINUX_NLS_H */ diff --git a/libblkid/src/partitions/aix.c b/libblkid/src/partitions/aix.c new file mode 100644 index 000000000..4efdfa33d --- /dev/null +++ b/libblkid/src/partitions/aix.c @@ -0,0 +1,57 @@ +/* + * aix partitions + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" +#include "aix.h" + +static int probe_aix_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + blkid_partlist ls; + blkid_parttable tab; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + return BLKID_PROBE_NONE; + + tab = blkid_partlist_new_parttable(ls, "aix", 0); + if (!tab) + return -ENOMEM; + + return BLKID_PROBE_OK; +} + +/* + * We know nothing about AIX on-disk structures. Everything what we know is the + * magic number at begin of the disk. + * + * Note, Linux kernel is tring to be smart and AIX signature is ignored when + * there is a valid DOS partitions table. We don't support such behavior. All + * fdisk-like programs has to properly wipe the fist sector. Everything other + * is a bug. + */ +const struct blkid_idinfo aix_pt_idinfo = +{ + .name = "aix", + .probefunc = probe_aix_pt, + .magics = + { + { .magic = BLKID_AIX_MAGIC_STRING, .len = BLKID_AIX_MAGIC_STRLEN }, + { NULL } + } +}; + diff --git a/libblkid/aix.h b/libblkid/src/partitions/aix.h index f767c5a37..f767c5a37 100644 --- a/libblkid/aix.h +++ b/libblkid/src/partitions/aix.h diff --git a/libblkid/src/partitions/bsd.c b/libblkid/src/partitions/bsd.c new file mode 100644 index 000000000..d83f2cf02 --- /dev/null +++ b/libblkid/src/partitions/bsd.c @@ -0,0 +1,179 @@ +/* + * BSD/OSF partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" +#include "pt-bsd.h" + +/* Returns 'blkid_idmag' in 512-sectors */ +#define BLKID_MAG_SECTOR(_mag) (((_mag)->kboff / 2) + ((_mag)->sboff >> 9)) + +/* Returns 'blkid_idmag' in bytes */ +#define BLKID_MAG_OFFSET(_mag) ((_mag)->kboff << 10) + ((_mag)->sboff) + +/* Returns 'blkid_idmag' offset in bytes within the last sector */ +#define BLKID_MAG_LASTOFFSET(_mag) \ + (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9)) + +static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct bsd_disklabel *l; + struct bsd_partition *p; + const char *name = "bsd" ; + blkid_parttable tab = NULL; + blkid_partition parent; + blkid_partlist ls; + int i, nparts = BSD_MAXPARTITIONS; + unsigned char *data; + int rc = BLKID_PROBE_NONE; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return rc; + + data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag)); + if (!data) { + if (errno) + rc = -errno; + goto nothing; + } + + l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag); + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + /* try to determine the real type of BSD system according to + * (parental) primary partition */ + parent = blkid_partlist_get_parent(ls); + if (parent) { + switch(blkid_partition_get_type(parent)) { + case MBR_FREEBSD_PARTITION: + name = "freebsd"; + break; + case MBR_NETBSD_PARTITION: + name = "netbsd"; + break; + case MBR_OPENBSD_PARTITION: + name = "openbsd"; + break; + default: + DBG(LOWPROBE, ul_debug( + "WARNING: BSD label detected on unknown (0x%x) " + "primary partition", + blkid_partition_get_type(parent))); + break; + } + } + + tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag)); + if (!tab) { + rc = -ENOMEM; + goto nothing; + } + + if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS) + nparts = le16_to_cpu(l->d_npartitions); + + else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS) + DBG(LOWPROBE, ul_debug( + "WARNING: ignore %d more BSD partitions", + le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS)); + + for (i = 0, p = l->d_partitions; i < nparts; i++, p++) { + blkid_partition par; + uint32_t start, size; + + /* TODO: in fdisk-mode returns all non-zero (p_size) partitions */ + if (p->p_fstype == BSD_FS_UNUSED) + continue; + + start = le32_to_cpu(p->p_offset); + size = le32_to_cpu(p->p_size); + + if (parent && blkid_partition_get_start(parent) == start + && blkid_partition_get_size(parent) == size) { + DBG(LOWPROBE, ul_debug( + "WARNING: BSD partition (%d) same like parent, " + "ignore", i)); + continue; + } + if (parent && !blkid_is_nested_dimension(parent, start, size)) { + DBG(LOWPROBE, ul_debug( + "WARNING: BSD partition (%d) overflow " + "detected, ignore", i)); + continue; + } + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) { + rc = -ENOMEM; + goto nothing; + } + + blkid_partition_set_type(par, p->p_fstype); + } + + return BLKID_PROBE_OK; + +nothing: + return rc; +} + + +/* + * All BSD variants use the same magic string (little-endian), + * and the same disklabel. + * + * The difference between {Free,Open,...}BSD is in the (parental) + * primary partition type. + * + * See also: http://en.wikipedia.org/wiki/BSD_disklabel + * + * The location of BSD disk label is architecture specific and in defined by + * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location + * also depends on BSD variant, FreeBSD uses only one location, NetBSD and + * OpenBSD are more creative... + * + * The basic overview: + * + * arch | LABELSECTOR | LABELOFFSET + * ------------------------+-------------+------------ + * amd64 arm hppa hppa64 | | + * i386, macppc, mvmeppc | 1 | 0 + * sgi, aviion, sh, socppc | | + * ------------------------+-------------+------------ + * alpha luna88k mac68k | 0 | 64 + * sparc(OpenBSD) vax | | + * ------------------------+-------------+------------ + * sparc64 sparc(NetBSD) | 0 | 128 + * ------------------------+-------------+------------ + * + * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR) + * + */ +const struct blkid_idinfo bsd_pt_idinfo = +{ + .name = "bsd", + .probefunc = probe_bsd_pt, + .magics = + { + { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 }, + { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 }, + { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/dos.c b/libblkid/src/partitions/dos.c new file mode 100644 index 000000000..253990800 --- /dev/null +++ b/libblkid/src/partitions/dos.c @@ -0,0 +1,307 @@ +/* + * MS-DOS partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Inspired by fdisk, partx, Linux kernel and libparted. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" +#include "aix.h" + +/* see superblocks/vfat.c */ +extern int blkid_probe_is_vfat(blkid_probe pr); + +static const struct dos_subtypes { + unsigned char type; + const struct blkid_idinfo *id; +} dos_nested[] = { + { MBR_FREEBSD_PARTITION, &bsd_pt_idinfo }, + { MBR_NETBSD_PARTITION, &bsd_pt_idinfo }, + { MBR_OPENBSD_PARTITION, &bsd_pt_idinfo }, + { MBR_UNIXWARE_PARTITION, &unixware_pt_idinfo }, + { MBR_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo }, + { MBR_MINIX_PARTITION, &minix_pt_idinfo } +}; + +static inline int is_extended(struct dos_partition *p) +{ + return (p->sys_ind == MBR_DOS_EXTENDED_PARTITION || + p->sys_ind == MBR_W95_EXTENDED_PARTITION || + p->sys_ind == MBR_LINUX_EXTENDED_PARTITION); +} + +static int parse_dos_extended(blkid_probe pr, blkid_parttable tab, + uint32_t ex_start, uint32_t ex_size, int ssf) +{ + blkid_partlist ls = blkid_probe_get_partlist(pr); + uint32_t cur_start = ex_start, cur_size = ex_size; + unsigned char *data; + int ct_nodata = 0; /* count ext.partitions without data partitions */ + int i; + + while (1) { + struct dos_partition *p, *p0; + uint32_t start, size; + + if (++ct_nodata > 100) + return BLKID_PROBE_OK; + data = blkid_probe_get_sector(pr, cur_start); + if (!data) { + if (errno) + return -errno; + goto leave; /* malformed partition? */ + } + + if (!mbr_is_valid_magic(data)) + goto leave; + + p0 = mbr_get_partition(data, 0); + + /* Usually, the first entry is the real data partition, + * the 2nd entry is the next extended partition, or empty, + * and the 3rd and 4th entries are unused. + * However, DRDOS sometimes has the extended partition as + * the first entry (when the data partition is empty), + * and OS/2 seems to use all four entries. + * -- Linux kernel fs/partitions/dos.c + * + * See also http://en.wikipedia.org/wiki/Extended_boot_record + */ + + /* Parse data partition */ + for (p = p0, i = 0; i < 4; i++, p++) { + uint32_t abs_start; + blkid_partition par; + + /* the start is relative to the parental ext.partition */ + start = dos_partition_get_start(p) * ssf; + size = dos_partition_get_size(p) * ssf; + abs_start = cur_start + start; /* absolute start */ + + if (!size || is_extended(p)) + continue; + if (i >= 2) { + /* extra checks to detect real data on + * 3rd and 4th entries */ + if (start + size > cur_size) + continue; + if (abs_start < ex_start) + continue; + if (abs_start + size > ex_start + ex_size) + continue; + } + + par = blkid_partlist_add_partition(ls, tab, abs_start, size); + if (!par) + return -ENOMEM; + + blkid_partition_set_type(par, p->sys_ind); + blkid_partition_set_flags(par, p->boot_ind); + blkid_partition_gen_uuid(par); + ct_nodata = 0; + } + /* The first nested ext.partition should be a link to the next + * logical partition. Everything other (recursive ext.partitions) + * is junk. + */ + for (p = p0, i = 0; i < 4; i++, p++) { + start = dos_partition_get_start(p) * ssf; + size = dos_partition_get_size(p) * ssf; + + if (size && is_extended(p)) + break; + } + if (i == 4) + goto leave; + + cur_start = ex_start + start; + cur_size = size; + } +leave: + return BLKID_PROBE_OK; +} + +static int probe_dos_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + int i; + int ssf; + blkid_parttable tab = NULL; + blkid_partlist ls; + struct dos_partition *p0, *p; + unsigned char *data; + uint32_t start, size, id; + char idstr[37]; + + + data = blkid_probe_get_sector(pr, 0); + if (!data) { + if (errno) + return -errno; + goto nothing; + } + + /* ignore disks with AIX magic number -- for more details see aix.c */ + if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0) + goto nothing; + + /* + * Now that the 55aa signature is present, this is probably + * either the boot sector of a FAT filesystem or a DOS-type + * partition table. + */ + if (blkid_probe_is_vfat(pr) == 1) { + DBG(LOWPROBE, ul_debug("probably FAT -- ignore")); + goto nothing; + } + + p0 = mbr_get_partition(data, 0); + + /* + * Reject PT where boot indicator is not 0 or 0x80. + */ + for (p = p0, i = 0; i < 4; i++, p++) + if (p->boot_ind != 0 && p->boot_ind != 0x80) { + DBG(LOWPROBE, ul_debug("missing boot indicator -- ignore")); + goto nothing; + } + + /* + * GPT uses valid MBR + */ + for (p = p0, i = 0; i < 4; i++, p++) { + if (p->sys_ind == MBR_GPT_PARTITION) { + DBG(LOWPROBE, ul_debug("probably GPT -- ignore")); + goto nothing; + } + } + + blkid_probe_use_wiper(pr, MBR_PT_OFFSET, 512 - MBR_PT_OFFSET); + + id = mbr_get_id(data); + if (id) + snprintf(idstr, sizeof(idstr), "%08x", id); + + /* + * Well, all checks pass, it's MS-DOS partiton table + */ + if (blkid_partitions_need_typeonly(pr)) { + /* Non-binary interface -- caller does not ask for details + * about partitions, just set generic varibles only. */ + if (id) + blkid_partitions_strcpy_ptuuid(pr, idstr); + return 0; + } + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + /* sector size factor (the start and size are in the real sectors, but + * we need to convert all sizes to 512 logical sectors + */ + ssf = blkid_probe_get_sectorsize(pr) / 512; + + /* allocate a new partition table */ + tab = blkid_partlist_new_parttable(ls, "dos", MBR_PT_OFFSET); + if (!tab) + return -ENOMEM; + + if (id) + blkid_parttable_set_id(tab, (unsigned char *) idstr); + + /* Parse primary partitions */ + for (p = p0, i = 0; i < 4; i++, p++) { + blkid_partition par; + + start = dos_partition_get_start(p) * ssf; + size = dos_partition_get_size(p) * ssf; + + if (!size) { + /* Linux kernel ignores empty partitions, but partno for + * the empty primary partitions is not reused */ + blkid_partlist_increment_partno(ls); + continue; + } + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + return -ENOMEM; + + blkid_partition_set_type(par, p->sys_ind); + blkid_partition_set_flags(par, p->boot_ind); + blkid_partition_gen_uuid(par); + } + + /* Linux uses partition numbers greater than 4 + * for all logical partition and all nested partition tables (bsd, ..) + */ + blkid_partlist_set_partno(ls, 5); + + /* Parse logical partitions */ + for (p = p0, i = 0; i < 4; i++, p++) { + start = dos_partition_get_start(p) * ssf; + size = dos_partition_get_size(p) * ssf; + + if (!size) + continue; + if (is_extended(p) && + parse_dos_extended(pr, tab, start, size, ssf) == -1) + goto nothing; + } + + /* Parse subtypes (nested partitions) on large disks */ + if (!blkid_probe_is_tiny(pr)) { + for (p = p0, i = 0; i < 4; i++, p++) { + size_t n; + int rc; + + if (!dos_partition_get_size(p) || is_extended(p)) + continue; + + for (n = 0; n < ARRAY_SIZE(dos_nested); n++) { + if (dos_nested[n].type != p->sys_ind) + continue; + + rc = blkid_partitions_do_subprobe(pr, + blkid_partlist_get_partition(ls, i), + dos_nested[n].id); + if (rc < 0) + return rc; + break; + } + } + } + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +} + + +const struct blkid_idinfo dos_pt_idinfo = +{ + .name = "dos", + .probefunc = probe_dos_pt, + .magics = + { + /* DOS master boot sector: + * + * 0 | Code Area + * 440 | Optional Disk signature + * 446 | Partition table + * 510 | 0x55 + * 511 | 0xAA + */ + { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c new file mode 100644 index 000000000..665577fa4 --- /dev/null +++ b/libblkid/src/partitions/gpt.c @@ -0,0 +1,470 @@ +/* + * EFI GPT partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * This code is not copy & past from any other implementation. + * + * For more information about GPT start your study at: + * http://en.wikipedia.org/wiki/GUID_Partition_Table + * http://technet.microsoft.com/en-us/library/cc739412(WS.10).aspx + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> +#include <limits.h> + +#include "partitions.h" +#include "crc32.h" + +#define GPT_PRIMARY_LBA 1 + +/* Signature - “EFI PART” */ +#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL +#define GPT_HEADER_SIGNATURE_STR "EFI PART" + +/* basic types */ +typedef uint16_t efi_char16_t; + +/* UUID */ +typedef struct { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi; + uint8_t clock_seq_low; + uint8_t node[6]; +} efi_guid_t; + + +#define GPT_UNUSED_ENTRY_GUID \ + ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}) +struct gpt_header { + uint64_t signature; /* "EFI PART" */ + uint32_t revision; + uint32_t header_size; /* usually 92 bytes */ + uint32_t header_crc32; /* checksum of header with this + * field zeroed during calculation */ + uint32_t reserved1; + + uint64_t my_lba; /* location of this header copy */ + uint64_t alternate_lba; /* location of the other header copy */ + uint64_t first_usable_lba; /* lirst usable LBA for partitions */ + uint64_t last_usable_lba; /* last usable LBA for partitions */ + + efi_guid_t disk_guid; /* disk UUID */ + + uint64_t partition_entries_lba; /* always 2 in primary header copy */ + uint32_t num_partition_entries; + uint32_t sizeof_partition_entry; + uint32_t partition_entry_array_crc32; + + /* + * The rest of the block is reserved by UEFI and must be zero. EFI + * standard handles this by: + * + * uint8_t reserved2[ BLKSSZGET - 92 ]; + * + * This definition is useless in practice. It is necessary to read + * whole block from the device rather than sizeof(struct gpt_header) + * only. + */ +} __attribute__ ((packed)); + +/*** not used +struct gpt_entry_attributes { + uint64_t required_to_function:1; + uint64_t reserved:47; + uint64_t type_guid_specific:16; +} __attribute__ ((packed)); +***/ + +struct gpt_entry { + efi_guid_t partition_type_guid; /* type UUID */ + efi_guid_t unique_partition_guid; /* partition UUID */ + uint64_t starting_lba; + uint64_t ending_lba; + + /*struct gpt_entry_attributes attributes;*/ + + uint64_t attributes; + + efi_char16_t partition_name[72 / sizeof(efi_char16_t)]; /* UTF-16LE string*/ +} __attribute__ ((packed)); + + +/* + * EFI uses crc32 with ~0 seed and xor's with ~0 at the end. + */ +static inline uint32_t count_crc32(const unsigned char *buf, size_t len) +{ + return (crc32(~0L, buf, len) ^ ~0L); +} + +static inline unsigned char *get_lba_buffer(blkid_probe pr, + uint64_t lba, size_t bytes) +{ + return blkid_probe_get_buffer(pr, + blkid_probe_get_sectorsize(pr) * lba, bytes); +} + +static inline int guidcmp(efi_guid_t left, efi_guid_t right) +{ + return memcmp(&left, &right, sizeof (efi_guid_t)); +} + +/* + * UUID is traditionally 16 byte big-endian array, except Intel EFI + * specification where the UUID is a structure of little-endian fields. + */ +static void swap_efi_guid(efi_guid_t *uid) +{ + uid->time_low = swab32(uid->time_low); + uid->time_mid = swab16(uid->time_mid); + uid->time_hi_and_version = swab16(uid->time_hi_and_version); +} + +static int last_lba(blkid_probe pr, uint64_t *lba) +{ + blkid_loff_t sz = blkid_probe_get_size(pr); + unsigned int ssz = blkid_probe_get_sectorsize(pr); + + if (sz < ssz) + return -1; + + *lba = (sz / ssz) - 1ULL; + return 0; +} + +/* + * Protective (legacy) MBR. + * + * This MBR contains standard DOS partition table with a single partition, type + * of 0xEE. The partition usually encompassing the entire GPT drive - or 2TiB + * for large disks. + * + * Note that Apple uses GPT/MBR hybrid disks, where the DOS partition table is + * synchronized with GPT. This synchronization has many restriction of course + * (due DOS PT limitations). + * + * Note that the PMBR detection is optional (enabled by default) and could be + * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_paertitions_set_flags()). + */ +static int is_pmbr_valid(blkid_probe pr, int *has) +{ + int flags = blkid_partitions_get_flags(pr); + unsigned char *data; + struct dos_partition *p; + int i; + + if (has) + *has = 0; + if (flags & BLKID_PARTS_FORCE_GPT) + goto ok; /* skip PMBR check */ + + data = blkid_probe_get_sector(pr, 0); + if (!data) { + if (errno) + return -errno; + goto failed; + } + + if (!mbr_is_valid_magic(data)) + goto failed; + + for (i = 0, p = mbr_get_partition(data, 0); i < 4; i++, p++) { + if (p->sys_ind == MBR_GPT_PARTITION) + goto ok; + } +failed: + return 0; +ok: + if (has) + *has = 1; + return 1; +} + +/* + * Reads GPT header to @hdr and returns a pointer to @hdr or NULL in case of + * error. The function also returns GPT entries in @ents. + * + * Note, this function does not allocate any memory. The GPT header has fixed + * size so we use stack, and @ents returns memory from libblkid buffer (so the + * next blkid_probe_get_buffer() will overwrite this buffer). + * + * This function checks validity of header and entries array. A corrupted + * header is not returned. + */ +static struct gpt_header *get_gpt_header( + blkid_probe pr, struct gpt_header *hdr, + struct gpt_entry **ents, uint64_t lba, + uint64_t lastlba) +{ + struct gpt_header *h; + uint32_t crc, orgcrc; + uint64_t lu, fu; + size_t esz; + uint32_t hsz, ssz; + + ssz = blkid_probe_get_sectorsize(pr); + + /* whole sector is allocated for GPT header */ + h = (struct gpt_header *) get_lba_buffer(pr, lba, ssz); + if (!h) + return NULL; + + if (le64_to_cpu(h->signature) != GPT_HEADER_SIGNATURE) + return NULL; + + hsz = le32_to_cpu(h->header_size); + + /* EFI: The HeaderSize must be greater than 92 and must be less + * than or equal to the logical block size. + */ + if (hsz > ssz || hsz < sizeof(*h)) + return NULL; + + /* Header has to be verified when header_crc32 is zero */ + orgcrc = h->header_crc32; + h->header_crc32 = 0; + crc = count_crc32((unsigned char *) h, hsz); + h->header_crc32 = orgcrc; + + if (crc != le32_to_cpu(orgcrc)) { + DBG(LOWPROBE, ul_debug("GPT header corrupted")); + return NULL; + } + + /* Valid header has to be at MyLBA */ + if (le64_to_cpu(h->my_lba) != lba) { + DBG(LOWPROBE, ul_debug( + "GPT->MyLBA mismatch with real position")); + return NULL; + } + + fu = le64_to_cpu(h->first_usable_lba); + lu = le64_to_cpu(h->last_usable_lba); + + /* Check if First and Last usable LBA makes sense */ + if (lu < fu || fu > lastlba || lu > lastlba) { + DBG(LOWPROBE, ul_debug( + "GPT->{First,Last}UsableLBA out of range")); + return NULL; + } + + /* The header has to be outside usable range */ + if (fu < lba && lba < lu) { + DBG(LOWPROBE, ul_debug("GPT header is inside usable area")); + return NULL; + } + + if (le32_to_cpu(h->num_partition_entries) == 0 || + le32_to_cpu(h->sizeof_partition_entry) == 0 || + ULONG_MAX / le32_to_cpu(h->num_partition_entries) < le32_to_cpu(h->sizeof_partition_entry)) { + DBG(LOWPROBE, ul_debug("GPT entries undefined")); + return NULL; + } + + /* Size of blocks with GPT entries */ + esz = le32_to_cpu(h->num_partition_entries) * + le32_to_cpu(h->sizeof_partition_entry); + + /* The header seems valid, save it + * (we don't care about zeros in hdr->reserved2 area) */ + memcpy(hdr, h, sizeof(*h)); + h = hdr; + + /* Read GPT entries */ + *ents = (struct gpt_entry *) get_lba_buffer(pr, + le64_to_cpu(h->partition_entries_lba), esz); + if (!*ents) { + DBG(LOWPROBE, ul_debug("GPT entries unreadable")); + return NULL; + } + + /* Validate entries */ + crc = count_crc32((unsigned char *) *ents, esz); + if (crc != le32_to_cpu(h->partition_entry_array_crc32)) { + DBG(LOWPROBE, ul_debug("GPT entries corrupted")); + return NULL; + } + + return h; +} + +static int probe_gpt_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t lastlba = 0, lba; + struct gpt_header hdr, *h; + struct gpt_entry *e; + blkid_parttable tab = NULL; + blkid_partlist ls; + uint64_t fu, lu; + uint32_t ssf, i; + efi_guid_t guid; + int ret; + + if (last_lba(pr, &lastlba)) + goto nothing; + + ret = is_pmbr_valid(pr, NULL); + if (ret < 0) + return ret; + else if (ret == 0) + goto nothing; + + errno = 0; + h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba); + if (!h && !errno) + h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba); + + if (!h) { + if (errno) + return -errno; + goto nothing; + } + + blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8); + + if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba, + sizeof(GPT_HEADER_SIGNATURE_STR) - 1, + (unsigned char *) GPT_HEADER_SIGNATURE_STR)) + goto err; + + guid = h->disk_guid; + swap_efi_guid(&guid); + + if (blkid_partitions_need_typeonly(pr)) { + /* Non-binary interface -- caller does not ask for details + * about partitions, just set generic varibles only. */ + blkid_partitions_set_ptuuid(pr, (unsigned char *) &guid); + return BLKID_PROBE_OK; + } + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "gpt", + blkid_probe_get_sectorsize(pr) * lba); + if (!tab) + goto err; + + blkid_parttable_set_uuid(tab, (const unsigned char *) &guid); + + ssf = blkid_probe_get_sectorsize(pr) / 512; + + fu = le64_to_cpu(h->first_usable_lba); + lu = le64_to_cpu(h->last_usable_lba); + + for (i = 0; i < le32_to_cpu(h->num_partition_entries); i++, e++) { + + blkid_partition par; + uint64_t start = le64_to_cpu(e->starting_lba); + uint64_t size = le64_to_cpu(e->ending_lba) - + le64_to_cpu(e->starting_lba) + 1ULL; + + /* 00000000-0000-0000-0000-000000000000 entry */ + if (!guidcmp(e->partition_type_guid, GPT_UNUSED_ENTRY_GUID)) { + blkid_partlist_increment_partno(ls); + continue; + } + /* the partition has to inside usable range */ + if (start < fu || start + size - 1 > lu) { + DBG(LOWPROBE, ul_debug( + "GPT entry[%d] overflows usable area - ignore", + i)); + blkid_partlist_increment_partno(ls); + continue; + } + + par = blkid_partlist_add_partition(ls, tab, + start * ssf, size * ssf); + if (!par) + goto err; + + blkid_partition_set_utf8name(par, + (unsigned char *) e->partition_name, + sizeof(e->partition_name), BLKID_ENC_UTF16LE); + + guid = e->unique_partition_guid; + swap_efi_guid(&guid); + blkid_partition_set_uuid(par, (const unsigned char *) &guid); + + guid = e->partition_type_guid; + swap_efi_guid(&guid); + blkid_partition_set_type_uuid(par, (const unsigned char *) &guid); + + blkid_partition_set_flags(par, le64_to_cpu(e->attributes)); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; + +err: + return -ENOMEM; +} + + +const struct blkid_idinfo gpt_pt_idinfo = +{ + .name = "gpt", + .probefunc = probe_gpt_pt, + .minsz = 1024 * 1440 + 1, /* ignore floppies */ + + /* + * It would be possible to check for DOS signature (0xAA55), but + * unfortunately almost all EFI GPT implemenations allow to optionaly + * skip the legacy MBR. We follows this behavior and MBR is optional. + * See is_valid_pmbr(). + * + * It means we have to always call probe_gpt_pt(). + */ + .magics = BLKID_NONE_MAGIC +}; + + + +/* probe for *alone* protective MBR */ +static int probe_pmbr_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + int has = 0; + struct gpt_entry *e; + uint64_t lastlba = 0; + struct gpt_header hdr; + + if (last_lba(pr, &lastlba)) + goto nothing; + + is_pmbr_valid(pr, &has); + if (!has) + goto nothing; + + if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) && + !get_gpt_header(pr, &hdr, &e, lastlba, lastlba)) + return 0; +nothing: + return 1; +} + +const struct blkid_idinfo pmbr_pt_idinfo = +{ + .name = "PMBR", + .probefunc = probe_pmbr_pt, + .magics = + { + { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/mac.c b/libblkid/src/partitions/mac.c new file mode 100644 index 000000000..428260534 --- /dev/null +++ b/libblkid/src/partitions/mac.c @@ -0,0 +1,192 @@ +/* + * mac partitions parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" + +#define MAC_PARTITION_MAGIC 0x504d +#define MAC_PARTITION_MAGIC_OLD 0x5453 + +/* + * Mac partition entry + * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html + */ +struct mac_partition { + uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */ + uint16_t reserved; /* reserved */ + uint32_t map_count; /* # blocks in partition map */ + uint32_t start_block; /* absolute starting block # of partition */ + uint32_t block_count; /* number of blocks in partition */ + char name[32]; /* partition name */ + char type[32]; /* string type description */ + uint32_t data_start; /* rel block # of first data block */ + uint32_t data_count; /* number of data blocks */ + uint32_t status; /* partition status bits */ + uint32_t boot_start; /* first logical block of boot code */ + uint32_t boot_size; /* size of boot code, in bytes */ + uint32_t boot_load; /* boot code load address */ + uint32_t boot_load2; /* reserved */ + uint32_t boot_entry; /* boot code entry point */ + uint32_t boot_entry2; /* reserved */ + uint32_t boot_cksum; /* boot code checksum */ + char processor[16]; /* identifies ISA of boot */ + + /* there is more stuff after this that we don't need */ +} __attribute__((packed)); + +/* + * Driver descriptor structure, in block 0 + * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html + */ +struct mac_driver_desc { + uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */ + uint16_t block_size; /* block size of the device */ + uint32_t block_count; /* number of blocks on the device */ + + /* there is more stuff after this that we don't need */ +} __attribute__((packed)); + +static inline unsigned char *get_mac_block( + blkid_probe pr, + uint16_t block_size, + uint32_t num) +{ + return blkid_probe_get_buffer(pr, + (blkid_loff_t) num * block_size, block_size); +} + +static inline int has_part_signature(struct mac_partition *p) +{ + return be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC || + be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD; +} + +static int probe_mac_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct mac_driver_desc *md; + struct mac_partition *p; + blkid_parttable tab = NULL; + blkid_partlist ls; + uint16_t block_size; + uint16_t ssf; /* sector size fragment */ + uint32_t nblks, i; + + + /* The driver descriptor record is always located at physical block 0, + * the first block on the disk. + */ + md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0); + if (!md) { + if (errno) + return -errno; + goto nothing; + } + + block_size = be16_to_cpu(md->block_size); + + /* The partition map always begins at physical block 1, + * the second block on the disk. + */ + p = (struct mac_partition *) get_mac_block(pr, block_size, 1); + if (!p) { + if (errno) + return -errno; + goto nothing; + } + + /* check the first partition signature */ + if (!has_part_signature(p)) + goto nothing; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return 0; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "mac", 0); + if (!tab) + goto err; + + ssf = block_size / 512; + nblks = be32_to_cpu(p->map_count); + + for (i = 1; i <= nblks; ++i) { + blkid_partition par; + uint32_t start; + uint32_t size; + + p = (struct mac_partition *) get_mac_block(pr, block_size, i); + if (!p) { + if (errno) + return -errno; + goto nothing; + } + if (!has_part_signature(p)) + goto nothing; + + if (be32_to_cpu(p->map_count) != nblks) { + DBG(LOWPROBE, ul_debug( + "mac: inconsisten map_count in partition map, " + "entry[0]: %d, entry[%d]: %d", + nblks, i - 1, + be32_to_cpu(p->map_count))); + } + + /* + * note that libparted ignores some mac partitions according to + * the partition name (e.g. "Apple_Free" or "Apple_Void"). We + * follows Linux kernel and all partitions are visible + */ + + start = be32_to_cpu(p->start_block) * ssf; + size = be32_to_cpu(p->block_count) * ssf; + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + blkid_partition_set_name(par, (unsigned char *) p->name, + sizeof(p->name)); + + blkid_partition_set_type_string(par, (unsigned char *) p->type, + sizeof(p->type)); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +/* + * Mac disk always begin with "Driver Descriptor Record" + * (struct mac_driver_desc) and magic 0x4552. + */ +const struct blkid_idinfo mac_pt_idinfo = +{ + .name = "mac", + .probefunc = probe_mac_pt, + .magics = + { + /* big-endian magic string */ + { .magic = "\x45\x52", .len = 2 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/minix.c b/libblkid/src/partitions/minix.c new file mode 100644 index 000000000..43c9d9af1 --- /dev/null +++ b/libblkid/src/partitions/minix.c @@ -0,0 +1,102 @@ +/* + * Minix partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" +#include "minix.h" + +static int probe_minix_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct dos_partition *p; + blkid_parttable tab = NULL; + blkid_partition parent; + blkid_partlist ls; + unsigned char *data; + int i; + + data = blkid_probe_get_sector(pr, 0); + if (!data) { + if (errno) + return -errno; + goto nothing; + } + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + /* Parent is required, because Minix uses the same PT as DOS and + * difference is only in primary partition (parent) type. + */ + parent = blkid_partlist_get_parent(ls); + if (!parent) + goto nothing; + + if (blkid_partition_get_type(parent) != MBR_MINIX_PARTITION) + goto nothing; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + tab = blkid_partlist_new_parttable(ls, "minix", MBR_PT_OFFSET); + if (!tab) + goto err; + + for (i = 0, p = mbr_get_partition(data, 0); + i < MINIX_MAXPARTITIONS; i++, p++) { + + uint32_t start, size; + blkid_partition par; + + if (p->sys_ind != MBR_MINIX_PARTITION) + continue; + + start = dos_partition_get_start(p); + size = dos_partition_get_size(p); + + if (parent && !blkid_is_nested_dimension(parent, start, size)) { + DBG(LOWPROBE, ul_debug( + "WARNING: minix partition (%d) overflow " + "detected, ignore", i)); + continue; + } + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + blkid_partition_set_type(par, p->sys_ind); + blkid_partition_set_flags(par, p->boot_ind); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +/* same as DOS */ +const struct blkid_idinfo minix_pt_idinfo = +{ + .name = "minix", + .probefunc = probe_minix_pt, + .magics = + { + { .magic = "\x55\xAA", .len = 2, .sboff = 510 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c new file mode 100644 index 000000000..4853f97e2 --- /dev/null +++ b/libblkid/src/partitions/partitions.c @@ -0,0 +1,1512 @@ +/* + * partitions - partition tables parsing + * + * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdint.h> +#include <inttypes.h> +#include <stdarg.h> + +#include "partitions.h" +#include "sysfs.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. The libblkid prober is + * compatible with kernel partition tables parser. The parser does not return + * empty (size=0) partitions or special hidden partitions. + * + * NAME=value interface, supported tags: + * + * @PTTYPE: partition table type (dos, gpt, etc.). + * + * @PTUUID: partition table id (uuid for gpt, hex for dos). + + * @PART_ENTRY_SCHEME: partition table type + * + * @PART_ENTRY_NAME: partition name (gpt and mac only) + * + * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR) + * + * @PART_ENTRY_TYPE: partition type, 0xNN (e.g 0x82) or type UUID (gpt only) or type string (mac) + * + * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or attributes (e.g. gpt attributes) + * + * @PART_ENTRY_NUMBER: partition number + * + * @PART_ENTRY_OFFSET: the begin of the partition + * + * @PART_ENTRY_SIZE: size of the partition + * + * @PART_ENTRY_DISK: whole-disk maj:min + * + * Example: + * + * <informalexample> + * <programlisting> + * blkid_probe pr; + * const char *ptname; + * + * pr = blkid_new_probe_from_filename(devname); + * if (!pr) + * err("%s: faild to open device", devname); + * + * 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); + * + * // don't forget to check return codes in your code! + * </programlisting> + * </informalexample> + * + * Binary interface: + * + * <informalexample> + * <programlisting> + * blkid_probe pr; + * blkid_partlist ls; + * int nparts, i; + * + * pr = blkid_new_probe_from_filename(devname); + * if (!pr) + * err("%s: faild to open device", devname); + * + * 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); + * + * // don't forget to check return codes in your code! + * </programlisting> + * </informalexample> + */ + +/* + * 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[] = +{ + &aix_pt_idinfo, + &sgi_pt_idinfo, + &sun_pt_idinfo, + &dos_pt_idinfo, + &gpt_pt_idinfo, + &pmbr_pt_idinfo, /* always after GPT */ + &mac_pt_idinfo, + &ultrix_pt_idinfo, + &bsd_pt_idinfo, + &unixware_pt_idinfo, + &solaris_x86_pt_idinfo, + &minix_pt_idinfo +}; + +/* + * 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 (in bytes) */ + int nparts; /* number of partitions */ + blkid_partition parent; /* parent of nested partition table */ + char id[37]; /* PT identifier (e.g. UUID for GPT) */ + + 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 (512-bytes sectors) */ + blkid_loff_t size; /* size of the partitions (512-bytes sectors) */ + + int type; /* partition type */ + char typestr[37]; /* partition type string (GPT and Mac) */ + + unsigned long long flags; /* partition flags / attributes */ + + 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 */ +}; + +static int blkid_partitions_probe_partition(blkid_probe pr); + +/** + * 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_reset_partitions_filter: + * @pr: prober + * + * Resets partitions probing filter + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_reset_partitions_filter(blkid_probe pr) +{ + return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS); +} + +/** + * blkid_probe_invert_partitions_filter: + * @pr: prober + * + * Inverts partitions probing filter + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_invert_partitions_filter(blkid_probe pr) +{ + return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS); +} + +/** + * blkid_probe_filter_partitions_type: + * @pr: prober + * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag + * @names: NULL terminated array of probing function names (e.g. "vfat"). + * + * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names + * + * %BLKID_FLTR_ONLYIN - probe for items which are IN @names + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[]) +{ + return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names); +} + +/** + * 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. + * + * WARNING: the returned object will be overwritten by the next + * blkid_probe_get_partitions() call for the same @pr. If you want to + * use more blkid_partlist objects in the same time you have to create + * more blkid_probe handlers (see blkid_new_probe()). + * + * 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 blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls) +{ + pr->chains[BLKID_CHAIN_PARTS].data = ls; +} + +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_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(LOWPROBE, ul_debug("partlist reset")); +} + +static blkid_partlist partitions_init_data(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(ls); + + DBG(LOWPROBE, ul_debug("parts: initialized partitions list (%p, size=%d)", + ls, ls->nparts_max)); + return ls; +} + +static void partitions_free_data(blkid_probe pr __attribute__((__unused__)), + 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(LOWPROBE, ul_debug("parts: create a new partition table " + "(%p, type=%s, offset=%"PRId64")", tab, type, 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. + */ + void *tmp = realloc(ls->parts, (ls->nparts_max + 32) * + sizeof(struct blkid_struct_partition)); + if (!tmp) + return NULL; + ls->parts = tmp; + 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 = blkid_partlist_increment_partno(ls); + + return par; +} + +blkid_partition blkid_partlist_add_partition(blkid_partlist ls, + blkid_parttable tab, + blkid_loff_t start, blkid_loff_t size) +{ + blkid_partition par = new_partition(ls, tab); + + if (!par) + return NULL; + + par->start = start; + par->size = size; + + DBG(LOWPROBE, ul_debug("parts: add partition (%p start=%" + PRId64 ", size=%" PRId64 ", table=%p)", + par, par->start, 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; +} + +int blkid_partlist_increment_partno(blkid_partlist ls) +{ + return ls ? ls->next_partno++ : -1; +} + +/* 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, + struct blkid_chain *chn) +{ + const struct blkid_idmag *mag = NULL; + blkid_loff_t off; + int rc = BLKID_PROBE_NONE; /* default is nothing */ + + if (pr->size <= 0 || (id->minsz && id->minsz > pr->size)) + goto nothing; /* the device is too small */ + if (pr->flags & BLKID_FL_NOSCAN_DEV) + goto nothing; + + rc = blkid_probe_get_idmag(pr, id, &off, &mag); + if (rc != BLKID_PROBE_OK) + goto nothing; + + /* final check by probing function */ + if (id->probefunc) { + DBG(LOWPROBE, ul_debug( + "%s: ---> call probefunc()", id->name)); + rc = id->probefunc(pr, mag); + if (rc < 0) { + /* reset after error */ + reset_partlist(blkid_probe_get_partlist(pr)); + if (chn && !chn->binary) + blkid_probe_chain_reset_vals(pr, chn); + DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d", + id->name, rc)); + } + if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary) + rc = blkid_probe_set_magic(pr, off, mag->len, + (unsigned char *) mag->magic); + + DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc)); + } + + return rc; + +nothing: + return BLKID_PROBE_NONE; +} + +/* + * The blkid_do_probe() backend. + */ +static int partitions_probe(blkid_probe pr, struct blkid_chain *chn) +{ + int rc = BLKID_PROBE_NONE; + size_t i; + + if (!pr || chn->idx < -1) + return -EINVAL; + + blkid_probe_chain_reset_vals(pr, chn); + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return BLKID_PROBE_NONE; + + if (chn->binary) + partitions_init_data(chn); + + if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT)) + goto details_only; + + DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]", + chn->idx)); + + i = chn->idx < 0 ? 0 : chn->idx + 1U; + + 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 */ + rc = idinfo_probe(pr, idinfos[i], chn); + if (rc < 0) + break; + if (rc != BLKID_PROBE_OK) + continue; + + name = idinfos[i]->name; + + if (!chn->binary) + /* + * Non-binary interface, set generic variables. Note + * that the another variables could be set in prober + * functions. + */ + blkid_probe_set_value(pr, "PTTYPE", + (unsigned char *) name, + strlen(name) + 1); + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]", + name, chn->idx)); + rc = BLKID_PROBE_OK; + break; + } + + if (rc != BLKID_PROBE_OK) { + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]", + rc, chn->idx)); + } + +details_only: + /* + * Gather PART_ENTRY_* values if the current device is a partition. + */ + if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary && + (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) { + + int xrc = blkid_partitions_probe_partition(pr); + + /* partition entry probing is optional, and "not-found" from + * this sub-probing must not to overwrite previous success. */ + if (xrc < 0) + rc = xrc; /* always propagate errors */ + else if (rc == BLKID_PROBE_NONE) + rc = xrc; + } + + DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]", rc)); + return rc; +} + +/* 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) +{ + blkid_probe prc; + int rc; + blkid_partlist ls; + blkid_loff_t sz, off; + + DBG(LOWPROBE, ul_debug( + "parts: ----> %s subprobe requested (parent=%p)", + id->name, parent)); + + if (!pr || !parent || !parent->size) + return -EINVAL; + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return BLKID_PROBE_NONE; + + /* range defined by parent */ + sz = ((blkid_loff_t) parent->size) << 9; + off = ((blkid_loff_t) parent->start) << 9; + + if (off < pr->off || pr->off + pr->size < off + sz) { + DBG(LOWPROBE, ul_debug( + "ERROR: parts: <---- '%s' subprobe: overflow detected.", + id->name)); + return -ENOSPC; + } + + /* create private prober */ + prc = blkid_clone_probe(pr); + if (!prc) + return -ENOMEM; + + blkid_probe_set_dimension(prc, off, sz); + + /* clone is always with reset chain, fix it */ + prc->cur_chain = blkid_probe_get_chain(pr); + + /* + * Set 'parent' to the current list of the partitions and use the list + * in cloned prober (so the cloned prober will extend the current list + * of partitions rather than create a new). + */ + ls = blkid_probe_get_partlist(pr); + blkid_partlist_set_parent(ls, parent); + + blkid_probe_set_partlist(prc, ls); + + rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr)); + + blkid_probe_set_partlist(prc, NULL); + blkid_partlist_set_parent(ls, NULL); + + blkid_free_probe(prc); /* free cloned prober */ + + DBG(LOWPROBE, ul_debug( + "parts: <---- %s subprobe done (parent=%p, rc=%d)", + id->name, parent, rc)); + + return rc; +} + +static int blkid_partitions_probe_partition(blkid_probe pr) +{ + blkid_probe disk_pr = NULL; + blkid_partlist ls; + blkid_partition par; + dev_t devno; + + DBG(LOWPROBE, ul_debug("parts: start probing for partition entry")); + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + goto nothing; + + devno = blkid_probe_get_devno(pr); + if (!devno) + goto nothing; + + disk_pr = blkid_probe_get_wholedisk_probe(pr); + if (!disk_pr) + goto nothing; + + /* parse PT */ + ls = blkid_probe_get_partitions(disk_pr); + if (!ls) + goto nothing; + + par = blkid_partlist_devno_to_partition(ls, devno); + if (!par) + goto nothing; + else { + const char *v; + blkid_parttable tab = blkid_partition_get_table(par); + dev_t disk = blkid_probe_get_devno(disk_pr); + + if (tab) { + v = blkid_parttable_get_type(tab); + if (v) + blkid_probe_set_value(pr, "PART_ENTRY_SCHEME", + (unsigned char *) v, strlen(v) + 1); + } + + v = blkid_partition_get_name(par); + if (v) + blkid_probe_set_value(pr, "PART_ENTRY_NAME", + (unsigned char *) v, strlen(v) + 1); + + v = blkid_partition_get_uuid(par); + if (v) + blkid_probe_set_value(pr, "PART_ENTRY_UUID", + (unsigned char *) v, strlen(v) + 1); + + /* type */ + v = blkid_partition_get_type_string(par); + if (v) + blkid_probe_set_value(pr, "PART_ENTRY_TYPE", + (unsigned char *) v, strlen(v) + 1); + else + blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE", + "0x%x", blkid_partition_get_type(par)); + + if (blkid_partition_get_flags(par)) + blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS", + "0x%llx", blkid_partition_get_flags(par)); + + blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER", + "%d", blkid_partition_get_partno(par)); + + blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd", + blkid_partition_get_start(par)); + blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd", + blkid_partition_get_size(par)); + + blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u", + major(disk), minor(disk)); + } + + DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]")); + return BLKID_PROBE_OK; + +nothing: + DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]")); + return BLKID_PROBE_NONE; + + +} + +/* + * Returns 1 if the device is whole-disk and the area specified by @offset and + * @size is covered by any partition. + */ +int blkid_probe_is_covered_by_pt(blkid_probe pr, + blkid_loff_t offset, blkid_loff_t size) +{ + blkid_probe prc = NULL; + blkid_partlist ls = NULL; + blkid_loff_t start, end; + int nparts, i, rc = 0; + + DBG(LOWPROBE, ul_debug( + "=> checking if off=%jd size=%jd covered by PT", + offset, size)); + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + goto done; + + prc = blkid_clone_probe(pr); + if (!prc) + goto done; + + ls = blkid_probe_get_partitions(prc); + if (!ls) + goto done; + + nparts = blkid_partlist_numof_partitions(ls); + if (!nparts) + goto done; + + end = (offset + size) >> 9; + start = offset >> 9; + + /* check if the partition table fits into the device */ + for (i = 0; i < nparts; i++) { + blkid_partition par = &ls->parts[i]; + + if (par->start + par->size > (pr->size >> 9)) { + DBG(LOWPROBE, ul_debug("partition #%d overflows " + "device (off=%" PRId64 " size=%" PRId64 ")", + par->partno, par->start, par->size)); + goto done; + } + } + + /* check if the requested area is covered by PT */ + for (i = 0; i < nparts; i++) { + blkid_partition par = &ls->parts[i]; + + if (start >= par->start && end <= par->start + par->size) { + rc = 1; + break; + } + } +done: + blkid_free_probe(prc); + + DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT")); + 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) +{ + size_t 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_table: + * @ls: partitions list + * + * Returns: top-level partition table or NULL of there is not a partition table + * on the device. + */ +blkid_parttable blkid_partlist_get_table(blkid_partlist ls) +{ + if (!ls || list_empty(&ls->l_tabs)) + return NULL; + + return list_entry(ls->l_tabs.next, + struct blkid_struct_parttable, t_tabs); +} + + +/** + * 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 or the partition table is empty. + * + * See also blkid_partlist_get_table(). + * + * 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_partlist_get_partition_by_partno + * @ls: partitions list + * @n: the partition number (e.g. 'N' from sda'N') + * + * This does not assume any order of the input blkid_partlist. And correctly + * handles "out of order" partition tables. partition N is located after + * partition N+1 on the disk. + * + * Returns: partition object or NULL in case or error. + */ +blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n) +{ + int i, nparts; + blkid_partition par; + + if (!ls) + return NULL; + + nparts = blkid_partlist_numof_partitions(ls); + for (i = 0; i < nparts; i++) { + par = blkid_partlist_get_partition(ls, i); + if (n == blkid_partition_get_partno(par)) + return par; + } + return NULL; +} + + +/** + * blkid_partlist_devno_to_partition: + * @ls: partitions list + * @devno: requested partition + * + * This function tries to get start and size for @devno from sysfs and + * returns a partition from @ls which matches with the values from sysfs. + * + * This function is necessary when you want to make a relation between an entry + * in the partition table (@ls) and block devices in your system. + * + * Returns: partition object or NULL in case or error. + */ +blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno) +{ + struct sysfs_cxt sysfs; + uint64_t start, size; + int i, rc, partno = 0; + + if (!ls) + return NULL; + + DBG(LOWPROBE, ul_debug("triyng to convert devno 0x%llx to partition", + (long long) devno)); + + if (sysfs_init(&sysfs, devno, NULL)) { + DBG(LOWPROBE, ul_debug("failed t init sysfs context")); + return NULL; + } + rc = sysfs_read_u64(&sysfs, "size", &size); + if (!rc) { + rc = sysfs_read_u64(&sysfs, "start", &start); + if (rc) { + /* try to get partition number from DM uuid. + */ + char *uuid = sysfs_strdup(&sysfs, "dm/uuid"); + char *tmp = uuid; + char *prefix = uuid ? strsep(&tmp, "-") : NULL; + + if (prefix && strncasecmp(prefix, "part", 4) == 0) { + char *end = NULL; + + partno = strtol(prefix + 4, &end, 10); + if (prefix == end || (end && *end)) + partno = 0; + else + rc = 0; /* success */ + } + free(uuid); + } + } + + sysfs_deinit(&sysfs); + + if (rc) + return NULL; + + if (partno) { + DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno)); + + /* + * Partition mapped by kpartx does not provide "start" offset + * in /sys, but if we know partno and size of the partition + * that we can probably make the releation bettween the device + * and an entry in partition table. + */ + for (i = 0; i < ls->nparts; i++) { + blkid_partition par = &ls->parts[i]; + + if (partno != blkid_partition_get_partno(par)) + continue; + + if ((blkid_loff_t) size == blkid_partition_get_size(par) || + (blkid_partition_is_extended(par) && size <= 1024)) + return par; + + } + return NULL; + } + + DBG(LOWPROBE, ul_debug("searching by offset/size")); + + for (i = 0; i < ls->nparts; i++) { + blkid_partition par = &ls->parts[i]; + + if (blkid_partition_get_start(par) == (blkid_loff_t) start && + blkid_partition_get_size(par) == (blkid_loff_t) size) + return par; + + /* exception for extended dos partitions */ + if (blkid_partition_get_start(par) == (blkid_loff_t) start && + blkid_partition_is_extended(par) && size <= 1024) + return par; + + } + + DBG(LOWPROBE, ul_debug("not found partition for device")); + return NULL; +} + + +int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id) +{ + if (!tab) + return -1; + + blkid_unparse_uuid(id, tab->id, sizeof(tab->id)); + return 0; +} + +int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id) +{ + if (!tab) + return -1; + + strncpy(tab->id, (const char *) id, sizeof(tab->id)); + return 0; +} + +/* set PTUUID variable for non-binary API */ +int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + + if (chn->binary || blkid_uuid_is_empty(uuid, 16)) + return 0; + + v = blkid_probe_assign_value(pr, "PTUUID"); + + blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data)); + v->len = 37; + + return 0; +} + +/* set PTUUID variable for non-binary API for tables where + * the ID is just a string */ +int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + size_t len; + + if (chn->binary || !str || !*str) + return 0; + + len = strlen((char *) str); + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + v = blkid_probe_assign_value(pr, "PTUUID"); + if (v) { + if (len == BLKID_PROBVAL_BUFSIZ) + len--; /* make a space for \0 */ + + memcpy((char *) v->data, str, len); + v->data[len] = '\0'; + v->len = len + 1; + return 0; + } + return -1; +} + +/** + * blkid_parttable_get_id: + * @tab: partition table + * + * The ID is GPT disk UUID or DOS disk ID (in hex format). + * + * Returns: partition table ID (for example GPT disk UUID) or NULL + */ +const char *blkid_parttable_get_id(blkid_parttable tab) +{ + return tab && *tab->id ? tab->id : NULL; +} + + +int blkid_partition_set_type(blkid_partition par, int type) +{ + if (!par) + return -1; + par->type = type; + return 0; +} + +/** + * 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 + * + * 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. + * + * <informalexample> + * <programlisting> + * 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); + * </programlisting> + * </informalexample> + + * Returns: position (in bytes) of the partition table or -1 in case of error. + * + */ +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: + * + * <informalexample> + * <programlisting> + * + * -- 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 + * + * </programlisting> + * </informalexample> + * + * 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 == MBR_DOS_EXTENDED_PARTITION || + par->type == MBR_W95_EXTENDED_PARTITION || + par->type == MBR_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; +} + +static void set_string(unsigned char *item, size_t max, + const unsigned char *data, size_t len) +{ + if (len >= max) + len = max - 1; + + memcpy(item, data, len); + item[len] = '\0'; + + blkid_rtrim_whitespace(item); +} + +int blkid_partition_set_name(blkid_partition par, + const unsigned char *name, size_t len) +{ + if (!par) + return -1; + + set_string(par->name, sizeof(par->name), name, len); + 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); + blkid_rtrim_whitespace(par->name); + 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; +} + +int blkid_partition_gen_uuid(blkid_partition par) +{ + if (!par || !par->tab || !*par->tab->id) + return -1; + + snprintf(par->uuid, sizeof(par->uuid), "%s-%02x", + par->tab->id, par->partno); + 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. + */ +int blkid_partition_get_type(blkid_partition par) +{ + return par->type; +} + +/* Sets partition 'type' for PT where the type is defined by string rather + * than by number + */ +int blkid_partition_set_type_string(blkid_partition par, + const unsigned char *type, size_t len) +{ + if (!par) + return -1; + + set_string((unsigned char *) par->typestr, + sizeof(par->typestr), type, len); + return 0; +} + +/* Sets partition 'type' for PT where the type is defined by UUIDrather + * than by number + */ +int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid) +{ + if (!par) + return -1; + + blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr)); + return 0; +} + +/** + * blkid_partition_get_type_string: + * @par: partition + * + * The type string is supported by a small subset of partition tables (e.g Mac + * and EFI GPT). Note that GPT uses type UUID and this function returns this + * UUID as string. + * + * Returns: partition type string or NULL. + */ +const char *blkid_partition_get_type_string(blkid_partition par) +{ + return par && *par->typestr ? par->typestr : NULL; +} + + +int blkid_partition_set_flags(blkid_partition par, unsigned long long flags) +{ + if (!par) + return -1; + par->flags = flags; + return 0; +} + +/** + * blkid_partition_get_flags + * @par: partition + * + * Returns: partition flags (or attributes for gpt). + */ +unsigned long long blkid_partition_get_flags(blkid_partition par) +{ + return par->flags; +} + diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h new file mode 100644 index 000000000..3651bbb4d --- /dev/null +++ b/libblkid/src/partitions/partitions.h @@ -0,0 +1,71 @@ +#ifndef BLKID_PARTITIONS_H +#define BLKID_PARTITIONS_H + +#include "blkidP.h" +#include "pt-mbr.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 int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id); +extern int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id); + +extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls, + blkid_parttable tab, + blkid_loff_t start, blkid_loff_t size); + +extern int blkid_partlist_set_partno(blkid_partlist ls, int partno); +extern int blkid_partlist_increment_partno(blkid_partlist ls); + +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_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid); +extern int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str); + + +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); +extern int blkid_partition_gen_uuid(blkid_partition par); + +extern int blkid_partition_set_type(blkid_partition par, int type); + +extern int blkid_partition_set_type_string(blkid_partition par, + const unsigned char *type, size_t len); + +extern int blkid_partition_set_type_uuid(blkid_partition par, + const unsigned char *uuid); + +extern int blkid_partition_set_flags(blkid_partition par, unsigned long long flags); + +/* + * partition probers + */ +extern const struct blkid_idinfo aix_pt_idinfo; +extern const struct blkid_idinfo bsd_pt_idinfo; +extern const struct blkid_idinfo unixware_pt_idinfo; +extern const struct blkid_idinfo solaris_x86_pt_idinfo; +extern const struct blkid_idinfo sun_pt_idinfo; +extern const struct blkid_idinfo sgi_pt_idinfo; +extern const struct blkid_idinfo mac_pt_idinfo; +extern const struct blkid_idinfo dos_pt_idinfo; +extern const struct blkid_idinfo minix_pt_idinfo; +extern const struct blkid_idinfo gpt_pt_idinfo; +extern const struct blkid_idinfo pmbr_pt_idinfo; +extern const struct blkid_idinfo ultrix_pt_idinfo; + +#endif /* BLKID_PARTITIONS_H */ diff --git a/libblkid/src/partitions/sgi.c b/libblkid/src/partitions/sgi.c new file mode 100644 index 000000000..99c0bf1c7 --- /dev/null +++ b/libblkid/src/partitions/sgi.c @@ -0,0 +1,87 @@ +/* + * sgi partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" +#include "pt-sgi.h" + +static int probe_sgi_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct sgi_disklabel *l; + struct sgi_partition *p; + blkid_parttable tab = NULL; + blkid_partlist ls; + int i; + + l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0); + if (!l) { + if (errno) + return -errno; + goto nothing; + } + + if (sgi_pt_checksum(l)) { + DBG(LOWPROBE, ul_debug( + "detected corrupted sgi disk label -- ignore")); + goto nothing; + } + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "sgi", 0); + if (!tab) + goto err; + + for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) { + uint32_t size = be32_to_cpu(p->num_blocks); + uint32_t start = be32_to_cpu(p->first_block); + uint32_t type = be32_to_cpu(p->type); + blkid_partition par; + + if (!size) { + blkid_partlist_increment_partno(ls); + continue; + } + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + blkid_partition_set_type(par, type); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +const struct blkid_idinfo sgi_pt_idinfo = +{ + .name = "sgi", + .probefunc = probe_sgi_pt, + .magics = + { + { .magic = "\x0B\xE5\xA9\x41", .len = 4 }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/solaris_x86.c b/libblkid/src/partitions/solaris_x86.c new file mode 100644 index 000000000..4ac9be5fe --- /dev/null +++ b/libblkid/src/partitions/solaris_x86.c @@ -0,0 +1,154 @@ +/* + * Solaris x86 partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" + +/* + * Solaris-x86 is always within primary dos partition (nested PT table). The + * solaris-x86 vtoc allows to split the entire partition to "slices". The + * offset (start) of the slice is always relatively to the primary dos + * partition. + * + * Note that Solaris-SPARC uses entire disk with a different partitionning + * scheme. + */ + +/* some other implementation than Linux kernel assume 8 partitions only */ +#define SOLARIS_MAXPARTITIONS 16 + +/* disklabel (vtoc) location */ +#define SOLARIS_SECTOR 1 /* in 512-sectors */ +#define SOLARIS_OFFSET (SOLARIS_SECTOR << 9) /* in bytes */ +#define SOLARIS_MAGICOFFSET (SOLARIS_OFFSET + 12) /* v_sanity offset in bytes */ + +/* slice tags */ +#define SOLARIS_TAG_WHOLEDISK 5 + +struct solaris_slice { + uint16_t s_tag; /* ID tag of partition */ + uint16_t s_flag; /* permission flags */ + uint32_t s_start; /* start sector no of partition */ + uint32_t s_size; /* # of blocks in partition */ +} __attribute__((packed)); + +struct solaris_vtoc { + unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */ + + uint32_t v_sanity; /* to verify vtoc sanity */ + uint32_t v_version; /* layout version */ + char v_volume[8]; /* volume name */ + uint16_t v_sectorsz; /* sector size in bytes */ + uint16_t v_nparts; /* number of partitions */ + unsigned int v_reserved[10]; /* free space */ + + struct solaris_slice v_slice[SOLARIS_MAXPARTITIONS]; /* slices */ + + unsigned int timestamp[SOLARIS_MAXPARTITIONS]; /* timestamp (unsupported) */ + char v_asciilabel[128]; /* for compatibility */ +} __attribute__((packed)); + +static int probe_solaris_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct solaris_vtoc *l; /* disk label */ + struct solaris_slice *p; /* partitsion */ + blkid_parttable tab = NULL; + blkid_partition parent; + blkid_partlist ls; + int i; + uint16_t nparts; + + l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR); + if (!l) { + if (errno) + return -errno; + goto nothing; + } + + if (le32_to_cpu(l->v_version) != 1) { + DBG(LOWPROBE, ul_debug( + "WARNING: unsupported solaris x86 version %d, ignore", + le32_to_cpu(l->v_version))); + goto nothing; + } + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + parent = blkid_partlist_get_parent(ls); + + tab = blkid_partlist_new_parttable(ls, "solaris", SOLARIS_OFFSET); + if (!tab) + goto err; + + nparts = le16_to_cpu(l->v_nparts); + if (nparts > SOLARIS_MAXPARTITIONS) + nparts = SOLARIS_MAXPARTITIONS; + + for (i = 1, p = &l->v_slice[0]; i < nparts; i++, p++) { + + uint32_t start = le32_to_cpu(p->s_start); + uint32_t size = le32_to_cpu(p->s_size); + blkid_partition par; + + if (size == 0 || le16_to_cpu(p->s_tag) == SOLARIS_TAG_WHOLEDISK) + continue; + + if (parent) + /* Solaris slices are relative to the parent (primary + * DOS partition) */ + start += blkid_partition_get_start(parent); + + if (parent && !blkid_is_nested_dimension(parent, start, size)) { + DBG(LOWPROBE, ul_debug( + "WARNING: solaris partition (%d) overflow " + "detected, ignore", i)); + continue; + } + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + blkid_partition_set_type(par, le16_to_cpu(p->s_tag)); + blkid_partition_set_flags(par, le16_to_cpu(p->s_flag)); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +const struct blkid_idinfo solaris_x86_pt_idinfo = +{ + .name = "solaris", + .probefunc = probe_solaris_pt, + .magics = + { + { + .magic = "\xEE\xDE\x0D\x60", /* little-endian magic string */ + .len = 4, /* v_sanity size in bytes */ + .sboff = SOLARIS_MAGICOFFSET /* offset of v_sanity */ + }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/sun.c b/libblkid/src/partitions/sun.c new file mode 100644 index 000000000..22ee45042 --- /dev/null +++ b/libblkid/src/partitions/sun.c @@ -0,0 +1,125 @@ +/* + * sun (solaris-sparc) partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> + +#include "pt-sun.h" +#include "partitions.h" + +static int probe_sun_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct sun_disklabel *l; + struct sun_partition *p; + blkid_parttable tab = NULL; + blkid_partlist ls; + uint16_t nparts; + blkid_loff_t spc; + int i, use_vtoc; + + l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0); + if (!l) { + if (errno) + return -errno; + goto nothing; + } + + if (sun_pt_checksum(l)) { + DBG(LOWPROBE, ul_debug( + "detected corrupted sun disk label -- ignore")); + goto nothing; + } + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "sun", 0); + if (!tab) + goto err; + + /* sectors per cylinder (partition offset is in cylinders...) */ + spc = be16_to_cpu(l->nhead) * be16_to_cpu(l->nsect); + + DBG(LOWPROBE, ul_debug("Sun VTOC sanity=%u version=%u nparts=%u", + be32_to_cpu(l->vtoc.sanity), + be32_to_cpu(l->vtoc.version), + be16_to_cpu(l->vtoc.nparts))); + + /* Check to see if we can use the VTOC table */ + use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) && + (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) && + (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS)); + + /* Use 8 partition entries if not specified in validated VTOC */ + nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS; + + /* + * So that old Linux-Sun partitions continue to work, + * alow the VTOC to be used under the additional condition ... + */ + use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts); + + for (i = 0, p = l->partitions; i < nparts; i++, p++) { + + blkid_loff_t start, size; + uint16_t type = 0, flags = 0; + blkid_partition par; + + start = be32_to_cpu(p->start_cylinder) * spc; + size = be32_to_cpu(p->num_sectors); + if (use_vtoc) { + type = be16_to_cpu(l->vtoc.infos[i].id); + flags = be16_to_cpu(l->vtoc.infos[i].flags); + } + + if (type == SUN_TAG_WHOLEDISK || !size) { + blkid_partlist_increment_partno(ls); + continue; + } + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + if (type) + blkid_partition_set_type(par, type); + if (flags) + blkid_partition_set_flags(par, flags); + } + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + + +const struct blkid_idinfo sun_pt_idinfo = +{ + .name = "sun", + .probefunc = probe_sun_pt, + .magics = + { + { + .magic = "\xDA\xBE", /* big-endian magic string */ + .len = 2, + .sboff = offsetof(struct sun_disklabel, magic) + }, + { NULL } + } +}; + diff --git a/libblkid/src/partitions/ultrix.c b/libblkid/src/partitions/ultrix.c new file mode 100644 index 000000000..9c060be1d --- /dev/null +++ b/libblkid/src/partitions/ultrix.c @@ -0,0 +1,99 @@ +/* + * uktrix partition parsing code + * + * Copyright (C) 2010 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" + +#define ULTRIX_MAXPARTITIONS 8 + +#define ULTRIX_MAGIC 0x032957 +#define ULTRIX_MAGIC_STR "\x02\x29\x57" + +/* sector with partition table */ +#define ULTRIX_SECTOR ((16384 - sizeof(struct ultrix_disklabel)) >> 9) +/* position of partition table within ULTRIX_SECTOR */ +#define ULTRIX_OFFSET (512 - sizeof(struct ultrix_disklabel)) + +struct ultrix_disklabel { + int32_t pt_magic; /* magic no. indicating part. info exits */ + int32_t pt_valid; /* set by driver if pt is current */ + struct pt_info { + int32_t pi_nblocks; /* no. of sectors */ + uint32_t pi_blkoff; /* block offset for start */ + } pt_part[ULTRIX_MAXPARTITIONS]; +} __attribute__((packed)); + + +static int probe_ultrix_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + unsigned char *data; + struct ultrix_disklabel *l; + blkid_parttable tab = NULL; + blkid_partlist ls; + int i; + + data = blkid_probe_get_sector(pr, ULTRIX_SECTOR); + if (!data) { + if (errno) + return -errno; + goto nothing; + } + + l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET); + + if (l->pt_magic != ULTRIX_MAGIC || l->pt_valid != 1) + goto nothing; + + if (blkid_probe_set_magic(pr, (ULTRIX_SECTOR << 9) + ULTRIX_OFFSET, + sizeof(ULTRIX_MAGIC_STR) - 1, + (unsigned char *) ULTRIX_MAGIC_STR)) + goto err; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + tab = blkid_partlist_new_parttable(ls, "ultrix", 0); + if (!tab) + goto err; + + for (i = 0; i < ULTRIX_MAXPARTITIONS; i++) { + if (!l->pt_part[i].pi_nblocks) + blkid_partlist_increment_partno(ls); + else { + if (!blkid_partlist_add_partition(ls, tab, + l->pt_part[i].pi_blkoff, + l->pt_part[i].pi_nblocks)) + goto err; + } + } + + return BLKID_PROBE_OK; +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + +const struct blkid_idinfo ultrix_pt_idinfo = +{ + .name = "ultrix", + .probefunc = probe_ultrix_pt, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/partitions/unixware.c b/libblkid/src/partitions/unixware.c new file mode 100644 index 000000000..6742bcf36 --- /dev/null +++ b/libblkid/src/partitions/unixware.c @@ -0,0 +1,197 @@ +/* + * unixware partition parsing code + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * + * The intersting information about unixware PT: + * - Linux kernel / partx + * - vtoc(7) SCO UNIX command man page + * - evms source code (http://evms.sourceforge.net/) + * - vxtools source code (http://martin.hinner.info/fs/vxfs/) + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#include "partitions.h" + +/* disklabel location */ +#define UNIXWARE_SECTOR 29 +#define UNIXWARE_OFFSET (UNIXWARE_SECTOR << 9) /* offset in bytes */ +#define UNIXWARE_KBOFFSET (UNIXWARE_OFFSET >> 10) /* offset in 1024-blocks */ + +/* disklabel->d_magic offset within the last 1024 block */ +#define UNIXWARE_MAGICOFFSET (UNIXWARE_OFFSET - UNIXWARE_KBOFFSET + 4) + +#define UNIXWARE_VTOCMAGIC 0x600DDEEEUL +#define UNIXWARE_MAXPARTITIONS 16 + +/* unixware_partition->s_label flags */ +#define UNIXWARE_TAG_UNUSED 0x0000 /* unused partition */ +#define UNIXWARE_TAG_BOOT 0x0001 /* boot fs */ +#define UNIXWARE_TAG_ROOT 0x0002 /* root fs */ +#define UNIXWARE_TAG_SWAP 0x0003 /* swap fs */ +#define UNIXWARE_TAG_USER 0x0004 /* user fs */ +#define UNIXWARE_TAG_ENTIRE_DISK 0x0005 /* whole disk */ +#define UNIXWARE_TAG_ALT_S 0x0006 /* alternate sector space */ +#define UNIXWARE_TAG_OTHER 0x0007 /* non unix */ +#define UNIXWARE_TAG_ALT_T 0x0008 /* alternate track space */ +#define UNIXWARE_TAG_STAND 0x0009 /* stand partition */ +#define UNIXWARE_TAG_VAR 0x000a /* var partition */ +#define UNIXWARE_TAG_HOME 0x000b /* home partition */ +#define UNIXWARE_TAG_DUMP 0x000c /* dump partition */ +#define UNIXWARE_TAG_ALT_ST 0x000d /* alternate sector track */ +#define UNIXWARE_TAG_VM_PUBLIC 0x000e /* volume mgt public partition */ +#define UNIXWARE_TAG_VM_PRIVATE 0x000f /* volume mgt private partition */ + + +/* unixware_partition->s_flags flags */ +#define UNIXWARE_FLAG_VALID 0x0200 + +struct unixware_partition { + uint16_t s_label; /* partition label (tag) */ + uint16_t s_flags; /* permission flags */ + uint32_t start_sect; /* starting sector */ + uint32_t nr_sects; /* number of sectors */ +} __attribute__((packed)); + +struct unixware_disklabel { + uint32_t d_type; /* drive type */ + uint32_t d_magic; /* the magic number */ + uint32_t d_version; /* version number */ + char d_serial[12]; /* serial number of the device */ + uint32_t d_ncylinders; /* # of data cylinders per device */ + uint32_t d_ntracks; /* # of tracks per cylinder */ + uint32_t d_nsectors; /* # of data sectors per track */ + uint32_t d_secsize; /* # of bytes per sector */ + uint32_t d_part_start; /* # of first sector of this partition */ + uint32_t d_unknown1[12]; /* ? */ + uint32_t d_alt_tbl; /* byte offset of alternate table */ + uint32_t d_alt_len; /* byte length of alternate table */ + uint32_t d_phys_cyl; /* # of physical cylinders per device */ + uint32_t d_phys_trk; /* # of physical tracks per cylinder */ + uint32_t d_phys_sec; /* # of physical sectors per track */ + uint32_t d_phys_bytes; /* # of physical bytes per sector */ + uint32_t d_unknown2; /* ? */ + uint32_t d_unknown3; /* ? */ + uint32_t d_pad[8]; /* pad */ + + struct unixware_vtoc { + uint32_t v_magic; /* the magic number */ + uint32_t v_version; /* version number */ + char v_name[8]; /* volume name */ + uint16_t v_nslices; /* # of partitions */ + uint16_t v_unknown1; /* ? */ + uint32_t v_reserved[10]; /* reserved */ + + struct unixware_partition + v_slice[UNIXWARE_MAXPARTITIONS]; /* partition */ + } __attribute__((packed)) vtoc; +}; + +static int probe_unixware_pt(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct unixware_disklabel *l; + struct unixware_partition *p; + blkid_parttable tab = NULL; + blkid_partition parent; + blkid_partlist ls; + int i; + + l = (struct unixware_disklabel *) + blkid_probe_get_sector(pr, UNIXWARE_SECTOR); + if (!l) { + if (errno) + return -errno; + goto nothing; + } + + if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC) + goto nothing; + + if (blkid_partitions_need_typeonly(pr)) + /* caller does not ask for details about partitions */ + return BLKID_PROBE_OK; + + ls = blkid_probe_get_partlist(pr); + if (!ls) + goto nothing; + + parent = blkid_partlist_get_parent(ls); + + tab = blkid_partlist_new_parttable(ls, "unixware", UNIXWARE_OFFSET); + if (!tab) + goto err; + + /* Skip the first partition that describe whole disk + */ + for (i = 1, p = &l->vtoc.v_slice[1]; + i < UNIXWARE_MAXPARTITIONS; i++, p++) { + + uint32_t start, size; + uint16_t tag, flg; + blkid_partition par; + + tag = le16_to_cpu(p->s_label); + flg = le16_to_cpu(p->s_flags); + + if (tag == UNIXWARE_TAG_UNUSED || + tag == UNIXWARE_TAG_ENTIRE_DISK || + flg != UNIXWARE_FLAG_VALID) + continue; + + start = le32_to_cpu(p->start_sect); + size = le32_to_cpu(p->nr_sects); + + if (parent && !blkid_is_nested_dimension(parent, start, size)) { + DBG(LOWPROBE, ul_debug( + "WARNING: unixware partition (%d) overflow " + "detected, ignore", i)); + continue; + } + + par = blkid_partlist_add_partition(ls, tab, start, size); + if (!par) + goto err; + + blkid_partition_set_type(par, tag); + blkid_partition_set_flags(par, flg); + } + + return BLKID_PROBE_OK; + +nothing: + return BLKID_PROBE_NONE; +err: + return -ENOMEM; +} + + +/* + * The unixware partition table is within primary DOS partition. The PT is + * located on 29 sector, PT magic string is d_magic member of 'struct + * unixware_disklabel'. + */ +const struct blkid_idinfo unixware_pt_idinfo = +{ + .name = "unixware", + .probefunc = probe_unixware_pt, + .minsz = 1024 * 1440 + 1, /* ignore floppies */ + .magics = + { + { + .magic = "\x0D\x60\xE5\xCA", /* little-endian magic string */ + .len = 4, /* d_magic size in bytes */ + .kboff = UNIXWARE_KBOFFSET, + .sboff = UNIXWARE_MAGICOFFSET + }, + { NULL } + } +}; + diff --git a/libblkid/src/pathnames.h b/libblkid/src/pathnames.h new file mode 100644 index 000000000..0d21b980b --- /dev/null +++ b/libblkid/src/pathnames.h @@ -0,0 +1,196 @@ +/* + * Vaguely based on + * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 + * This code is in the public domain. + */ +#ifndef PATHNAMES_H +#define PATHNAMES_H + +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#ifndef __STDC__ +# error "we need an ANSI compiler" +#endif + +/* used by kernel in /proc (e.g. /proc/swaps) for deleted files */ +#define PATH_DELETED_SUFFIX "\\040(deleted)" +#define PATH_DELETED_SUFFIX_SZ (sizeof(PATH_DELETED_SUFFIX) - 1) + +/* DEFPATHs from <paths.h> don't include /usr/local */ +#undef _PATH_DEFPATH +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" + +#undef _PATH_DEFPATH_ROOT +#define _PATH_DEFPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" + +#define _PATH_SECURETTY "/etc/securetty" +#define _PATH_WTMPLOCK "/etc/wtmplock" + +#define _PATH_HUSHLOGIN ".hushlogin" +#define _PATH_HUSHLOGINS "/etc/hushlogins" + +#define _PATH_NOLOGIN_TXT "/etc/nologin.txt" + +#ifndef _PATH_MAILDIR +#define _PATH_MAILDIR "/var/spool/mail" +#endif +#define _PATH_MOTDFILE "/etc/motd" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_VAR_NOLOGIN "/var/run/nologin" + +#define _PATH_LOGIN "/bin/login" +#define _PATH_INITTAB "/etc/inittab" +#define _PATH_RC "/etc/rc" +#define _PATH_REBOOT "/sbin/reboot" +#define _PATH_SHUTDOWN "/sbin/shutdown" +#define _PATH_SINGLE "/etc/singleboot" +#define _PATH_SHUTDOWN_CONF "/etc/shutdown.conf" + +#define _PATH_SECURE "/etc/securesingle" +#define _PATH_USERTTY "/etc/usertty" + +#define _PATH_TERMCOLORS_DIRNAME "terminal-colors.d" +#define _PATH_TERMCOLORS_DIR "/etc/" _PATH_TERMCOLORS_DIRNAME + +/* used in login-utils/shutdown.c */ + +/* used in login-utils/setpwnam.h and login-utils/islocal.c */ +#define _PATH_PASSWD "/etc/passwd" + +/* used in login-utils/newgrp and login-utils/setpwnam.h*/ +#define _PATH_GSHADOW "/etc/gshadow" + +/* used in login-utils/setpwnam.h */ +#define _PATH_GROUP "/etc/group" +#define _PATH_SHADOW_PASSWD "/etc/shadow" +#define _PATH_SHELLS "/etc/shells" + +/* used in term-utils/agetty.c */ +#define _PATH_ISSUE "/etc/issue" +#define _PATH_OS_RELEASE "/etc/os-release" +#define _PATH_NUMLOCK_ON _PATH_LOCALSTATEDIR "/numlock-on" + +#define _PATH_LOGINDEFS "/etc/login.defs" + +/* used in misc-utils/look.c */ +#define _PATH_WORDS "/usr/share/dict/words" +#define _PATH_WORDS_ALT "/usr/share/dict/web2" + +/* mount paths */ +#define _PATH_UMOUNT "/bin/umount" + +#define _PATH_FILESYSTEMS "/etc/filesystems" +#define _PATH_PROC_SWAPS "/proc/swaps" +#define _PATH_PROC_FILESYSTEMS "/proc/filesystems" +#define _PATH_PROC_MOUNTS "/proc/mounts" +#define _PATH_PROC_PARTITIONS "/proc/partitions" +#define _PATH_PROC_DEVICES "/proc/devices" +#define _PATH_PROC_MOUNTINFO "/proc/self/mountinfo" +#define _PATH_PROC_LOCKS "/proc/locks" +#define _PATH_PROC_CDROMINFO "/proc/sys/dev/cdrom/info" + +#define _PATH_PROC_UIDMAP "/proc/self/uid_map" +#define _PATH_PROC_GIDMAP "/proc/self/gid_map" + +#define _PATH_PROC_ATTR_CURRENT "/proc/self/attr/current" +#define _PATH_PROC_ATTR_EXEC "/proc/self/attr/exec" +#define _PATH_PROC_CAPLASTCAP "/proc/sys/kernel/cap_last_cap" + + +#define _PATH_SYS_BLOCK "/sys/block" +#define _PATH_SYS_DEVBLOCK "/sys/dev/block" +#define _PATH_SYS_CLASS "/sys/class" +#define _PATH_SYS_SCSI "/sys/bus/scsi" + +#define _PATH_SYS_SELINUX "/sys/fs/selinux" +#define _PATH_SYS_APPARMOR "/sys/kernel/security/apparmor" + +#ifndef _PATH_MOUNTED +# ifdef MOUNTED /* deprecated */ +# define _PATH_MOUNTED MOUNTED +# else +# define _PATH_MOUNTED "/etc/mtab" +# endif +#endif + +#ifndef _PATH_MNTTAB +# ifdef MNTTAB /* deprecated */ +# define _PATH_MNTTAB MNTTAB +# else +# define _PATH_MNTTAB "/etc/fstab" +# endif +#endif + +#define _PATH_MNTTAB_DIR _PATH_MNTTAB ".d" + +#define _PATH_MOUNTED_LOCK _PATH_MOUNTED "~" +#define _PATH_MOUNTED_TMP _PATH_MOUNTED ".tmp" + +#ifndef _PATH_DEV + /* + * The tailing '/' in _PATH_DEV is there for compatibility with libc. + */ +# define _PATH_DEV "/dev/" +#endif + +#define _PATH_DEV_MEM "/dev/mem" + +#define _PATH_DEV_LOOP "/dev/loop" +#define _PATH_DEV_LOOPCTL "/dev/loop-control" +#define _PATH_DEV_TTY "/dev/tty" + + +/* udev paths */ +#define _PATH_DEV_BYLABEL "/dev/disk/by-label" +#define _PATH_DEV_BYUUID "/dev/disk/by-uuid" +#define _PATH_DEV_BYID "/dev/disk/by-id" +#define _PATH_DEV_BYPATH "/dev/disk/by-path" +#define _PATH_DEV_BYPARTLABEL "/dev/disk/by-partlabel" +#define _PATH_DEV_BYPARTUUID "/dev/disk/by-partuuid" + +/* hwclock paths */ +#ifdef CONFIG_ADJTIME_PATH +# define _PATH_ADJTIME CONFIG_ADJTIME_PATH +#else +# define _PATH_ADJTIME "/etc/adjtime" +#endif + +#define _PATH_LASTDATE "/var/lib/lastdate" +#ifdef __ia64__ +# define _PATH_RTC_DEV "/dev/efirtc" +#else +# define _PATH_RTC_DEV "/dev/rtc" +#endif + +#ifndef _PATH_BTMP +#define _PATH_BTMP "/var/log/btmp" +#endif + +/* raw paths*/ +#define _PATH_RAWDEVDIR "/dev/raw/" +#define _PATH_RAWDEVCTL _PATH_RAWDEVDIR "rawctl" +/* deprecated */ +#define _PATH_RAWDEVCTL_OLD "/dev/rawctl" + +/* wdctl path */ +#define _PATH_WATCHDOG_DEV "/dev/watchdog" + +/* ipc paths */ +#define _PATH_PROC_SYSV_MSG "/proc/sysvipc/msg" +#define _PATH_PROC_SYSV_SEM "/proc/sysvipc/sem" +#define _PATH_PROC_SYSV_SHM "/proc/sysvipc/shm" +#define _PATH_PROC_IPC_MSGMAX "/proc/sys/kernel/msgmax" +#define _PATH_PROC_IPC_MSGMNB "/proc/sys/kernel/msgmnb" +#define _PATH_PROC_IPC_MSGMNI "/proc/sys/kernel/msgmni" +#define _PATH_PROC_IPC_SEM "/proc/sys/kernel/sem" +#define _PATH_PROC_IPC_SHMALL "/proc/sys/kernel/shmall" +#define _PATH_PROC_IPC_SHMMAX "/proc/sys/kernel/shmmax" +#define _PATH_PROC_IPC_SHMMNI "/proc/sys/kernel/shmmni" + +/* kernel command line */ +#define _PATH_PROC_CMDLINE "/proc/cmdline" + +#endif /* PATHNAMES_H */ + diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c new file mode 100644 index 000000000..76ac099fc --- /dev/null +++ b/libblkid/src/probe.c @@ -0,0 +1,1834 @@ +/* + * Low-level libblkid probing API + * + * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +/** + * SECTION: lowprobe + * @title: Low-level probing + * @short_description: low-level prober initialization + * + * The low-level probing routines always and directly read information from + * the selected (see blkid_probe_set_device()) device. + * + * The probing routines are grouped together into separate chains. Currently, + * the library provides superblocks, partitions and topology chains. + * + * The probing routines is possible to filter (enable/disable) by type (e.g. + * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID). + * These filters are per-chain. Note that always when you touch the chain + * filter the current probing position is reset and probing starts from + * scratch. It means that the chain filter should not be modified during + * probing, for example in loop where you call blkid_do_probe(). + * + * For more details see the chain specific documentation. + * + * The low-level API provides two ways how access to probing results. + * + * 1. The NAME=value (tag) interface. This interface is older and returns all data + * as strings. This interface is generic for all chains. + * + * 2. The binary interfaces. These interfaces return data in the native formats. + * The interface is always specific to the probing chain. + * + * Note that the previous probing result (binary or NAME=value) is always + * zeroized when a chain probing function is called. For example: + * + * <informalexample> + * <programlisting> + * blkid_probe_enable_partitions(pr, TRUE); + * blkid_probe_enable_superblocks(pr, FALSE); + * + * blkid_do_safeprobe(pr); + * </programlisting> + * </informalexample> + * + * overwrites the previous probing result for the partitions chain, the superblocks + * result is not modified. + */ + +/** + * SECTION: lowprobe-tags + * @title: Low-level tags + * @short_description: generic NAME=value interface. + * + * The probing routines inside the chain are mutually exclusive by default -- + * only few probing routines are marked as "tolerant". The "tolerant" probing + * routines are used for filesystem which can share the same device with any + * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag. + * + * The SUPERBLOCKS chain is enabled by default. The all others chains is + * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific + * documentation. + * + * The blkid_do_probe() function returns a result from only one probing + * routine, and the next call from the next probing routine. It means you need + * to call the function in loop, for example: + * + * <informalexample> + * <programlisting> + * while((blkid_do_probe(pr) == 0) + * ... use result ... + * </programlisting> + * </informalexample> + * + * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only + * first probing result for every enabled chain. This function checks for + * ambivalent results (e.g. more "intolerant" filesystems superblocks on the + * device). + * + * The probing result is set of NAME=value pairs (the NAME is always unique). + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#ifdef HAVE_LINUX_CDROM_H +#include <linux/cdrom.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <inttypes.h> +#include <stdint.h> +#include <stdarg.h> +#include <limits.h> + +#ifdef HAVE_LIBUUID +# include <uuid.h> +#endif + +#include "blkidP.h" +#include <blkid.h> +#include "all-io.h" +#include "sysfs.h" +#include "strutils.h" + +/* 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 + */ +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); +static void blkid_probe_reset_buffer(blkid_probe pr); + +/** + * blkid_new_probe: + * + * Returns: a pointer to the newly allocated probe struct or NULL in case of error. + */ +blkid_probe blkid_new_probe(void) +{ + int i; + blkid_probe pr; + + blkid_init_debug(0); + pr = calloc(1, sizeof(struct blkid_struct_probe)); + if (!pr) + return NULL; + + DBG(LOWPROBE, ul_debug("allocate a new probe %p", pr)); + + /* initialize chains */ + for (i = 0; i < BLKID_NCHAINS; i++) { + pr->chains[i].driver = chains_drvs[i]; + pr->chains[i].flags = chains_drvs[i]->dflt_flags; + pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; + } + INIT_LIST_HEAD(&pr->buffers); + return pr; +} + +/* + * Clone @parent, the new clone shares all, but except: + * + * - probing result + * - bufferes if another device (or offset) is set to the prober + */ +blkid_probe blkid_clone_probe(blkid_probe parent) +{ + blkid_probe pr; + + if (!parent) + return NULL; + + DBG(LOWPROBE, ul_debug("allocate a probe clone")); + + pr = blkid_new_probe(); + if (!pr) + return NULL; + + pr->fd = parent->fd; + pr->off = parent->off; + pr->size = parent->size; + pr->devno = parent->devno; + pr->disk_devno = parent->disk_devno; + pr->blkssz = parent->blkssz; + pr->flags = parent->flags; + pr->parent = parent; + + pr->flags &= ~BLKID_FL_PRIVATE_FD; + + return pr; +} + + + +/** + * blkid_new_probe_from_filename: + * @filename: device or regular file + * + * This function is same as call open(filename), blkid_new_probe() and + * blkid_probe_set_device(pr, fd, 0, 0). + * + * The @filename is closed by blkid_free_probe() or by the + * blkid_probe_set_device() call. + * + * Returns: a pointer to the newly allocated probe struct or NULL in case of + * error. + */ +blkid_probe blkid_new_probe_from_filename(const char *filename) +{ + int fd = -1; + blkid_probe pr = NULL; + + if (!filename) + return NULL; + + fd = open(filename, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return NULL; + + pr = blkid_new_probe(); + if (!pr) + goto err; + + if (blkid_probe_set_device(pr, fd, 0, 0)) + goto err; + + pr->flags |= BLKID_FL_PRIVATE_FD; + return pr; +err: + if (fd >= 0) + close(fd); + blkid_free_probe(pr); + return NULL; +} + +/** + * blkid_free_probe: + * @pr: probe + * + * Deallocates the probe struct, buffers and all allocated + * data that are associated with this probing control struct. + */ +void blkid_free_probe(blkid_probe pr) +{ + int i; + + if (!pr) + return; + + for (i = 0; i < BLKID_NCHAINS; i++) { + struct blkid_chain *ch = &pr->chains[i]; + + if (ch->driver->free_data) + ch->driver->free_data(pr, ch->data); + free(ch->fltr); + } + + if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) + close(pr->fd); + blkid_probe_reset_buffer(pr); + blkid_free_probe(pr->disk_probe); + + DBG(LOWPROBE, ul_debug("free probe %p", pr)); + free(pr); +} + + +/* + * Removes chain values from probing result. + */ +void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) +{ + int nvals = pr->nvals; + int i, x; + + for (x = 0, i = 0; i < pr->nvals; i++) { + struct blkid_prval *v = &pr->vals[i]; + + if (v->chain != chn && x == i) { + x++; + continue; + } + if (v->chain == chn) { + --nvals; + continue; + } + memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval)); + } + pr->nvals = nvals; +} + +static void blkid_probe_chain_reset_position(struct blkid_chain *chn) +{ + if (chn) + chn->idx = -1; +} + +/* + * Copies chain values from probing result to @vals, the max size of @vals is + * @nvals and returns real number of values. + */ +int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, + struct blkid_prval *vals, int nvals) +{ + int i, x; + + for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) { + struct blkid_prval *v = &pr->vals[i]; + + if (v->chain != chn) + continue; + memcpy(&vals[x++], v, sizeof(struct blkid_prval)); + } + return x; +} + +/* + * Appends values from @vals to the probing result + */ +void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals) +{ + int i = 0; + + while (i < nvals && pr->nvals < BLKID_NVALS) { + memcpy(&pr->vals[pr->nvals++], &vals[i++], + sizeof(struct blkid_prval)); + } +} + +static void blkid_probe_reset_vals(blkid_probe pr) +{ + memset(pr->vals, 0, sizeof(pr->vals)); + pr->nvals = 0; +} + +struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) +{ + return pr->cur_chain; +} + +static const char *blkid_probe_get_probername(blkid_probe pr) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (chn && chn->idx >= 0 && chn->idx < chn->driver->nidinfos) + return chn->driver->idinfos[chn->idx]->name; + + return NULL; +} + +void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) +{ + int rc, org_prob_flags; + struct blkid_chain *org_chn; + + if (!pr || !chn) + return NULL; + + /* save the current setting -- the binary API has to be completely + * independent on the current probing status + */ + org_chn = pr->cur_chain; + org_prob_flags = pr->prob_flags; + + pr->cur_chain = chn; + pr->prob_flags = 0; + chn->binary = TRUE; + blkid_probe_chain_reset_position(chn); + + rc = chn->driver->probe(pr, chn); + + chn->binary = FALSE; + blkid_probe_chain_reset_position(chn); + + /* restore the original setting + */ + pr->cur_chain = org_chn; + pr->prob_flags = org_prob_flags; + + if (rc != 0) + return NULL; + + DBG(LOWPROBE, ul_debug("returning %s binary data", chn->driver->name)); + return chn->data; +} + + +/** + * blkid_reset_probe: + * @pr: probe + * + * Zeroize probing results and resets the current probing (this has impact to + * blkid_do_probe() only). This function does not touch probing filters and + * keeps assigned device. + */ +void blkid_reset_probe(blkid_probe pr) +{ + int i; + + if (!pr) + return; + + blkid_probe_reset_vals(pr); + blkid_probe_set_wiper(pr, 0, 0); + + pr->cur_chain = NULL; + + for (i = 0; i < BLKID_NCHAINS; i++) + blkid_probe_chain_reset_position(&pr->chains[i]); +} + +/*** +static int blkid_probe_dump_filter(blkid_probe pr, int chain) +{ + struct blkid_chain *chn; + int i; + + if (!pr || chain < 0 || chain >= BLKID_NCHAINS) + return -1; + + chn = &pr->chains[chain]; + + if (!chn->fltr) + return -1; + + for (i = 0; i < chn->driver->nidinfos; i++) { + const struct blkid_idinfo *id = chn->driver->idinfos[i]; + + DBG(LOWPROBE, ul_debug("%d: %s: %s", + i, + id->name, + blkid_bmp_get_item(chn->fltr, i) + ? "disabled" : "enabled <--")); + } + return 0; +} +***/ + +/* + * Returns properly initialized chain filter + */ +unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) +{ + struct blkid_chain *chn; + + if (!pr || chain < 0 || chain >= BLKID_NCHAINS) + return NULL; + + chn = &pr->chains[chain]; + + /* always when you touch the chain filter all indexes are reset and + * probing starts from scratch + */ + blkid_probe_chain_reset_position(chn); + pr->cur_chain = NULL; + + if (!chn->driver->has_fltr || (!chn->fltr && !create)) + return NULL; + + if (!chn->fltr) + chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos)); + else + memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos)); + + /* blkid_probe_dump_filter(pr, chain); */ + return chn->fltr; +} + +/* + * Generic private functions for filter setting + */ +int __blkid_probe_invert_filter(blkid_probe pr, int chain) +{ + size_t i; + struct blkid_chain *chn; + + if (!pr) + return -1; + + chn = &pr->chains[chain]; + + if (!chn->driver->has_fltr || !chn->fltr) + return -1; + + for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++) + chn->fltr[i] = ~chn->fltr[i]; + + DBG(LOWPROBE, ul_debug("probing filter inverted")); + /* blkid_probe_dump_filter(pr, chain); */ + return 0; +} + +int __blkid_probe_reset_filter(blkid_probe pr, int chain) +{ + return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1; +} + +int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) +{ + unsigned long *fltr; + struct blkid_chain *chn; + size_t i; + + fltr = blkid_probe_get_filter(pr, chain, TRUE); + if (!fltr) + return -1; + + chn = &pr->chains[chain]; + + for (i = 0; i < chn->driver->nidinfos; i++) { + int has = 0; + const struct blkid_idinfo *id = chn->driver->idinfos[i]; + char **n; + + for (n = names; *n; n++) { + if (!strcmp(id->name, *n)) { + has = 1; + break; + } + } + if (flag & BLKID_FLTR_ONLYIN) { + if (!has) + blkid_bmp_set_item(fltr, i); + } else if (flag & BLKID_FLTR_NOTIN) { + if (has) + blkid_bmp_set_item(fltr, i); + } + } + + DBG(LOWPROBE, ul_debug("%s: a new probing type-filter initialized", + chn->driver->name)); + /* blkid_probe_dump_filter(pr, chain); */ + return 0; +} + +unsigned char *blkid_probe_get_buffer(blkid_probe pr, + blkid_loff_t off, blkid_loff_t len) +{ + struct list_head *p; + struct blkid_bufinfo *bf = NULL; + + if (pr->size <= 0) { + errno = EINVAL; + return NULL; + } + + if (pr->parent && + pr->parent->devno == pr->devno && + pr->parent->off <= pr->off && + pr->parent->off + pr->parent->size >= pr->off + pr->size) { + /* + * This is a cloned prober and points to the same area as + * parent. Let's use parent's buffers. + * + * Note that pr->off (and pr->parent->off) is always from the + * beginig of the device. + */ + return blkid_probe_get_buffer(pr->parent, + pr->off + off - pr->parent->off, len); + } + + list_for_each(p, &pr->buffers) { + struct blkid_bufinfo *x = + list_entry(p, struct blkid_bufinfo, bufs); + + if (x->off <= off && off + len <= x->off + x->len) { + DBG(LOWPROBE, ul_debug("\treuse buffer: off=%jd len=%jd pr=%p", + x->off, x->len, pr)); + bf = x; + break; + } + } + if (!bf) { + ssize_t ret; + + if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) { + errno = 0; + return NULL; + } + + /* someone trying to overflow some buffers? */ + if (len > ULONG_MAX - sizeof(struct blkid_bufinfo)) { + errno = ENOMEM; + return NULL; + } + + /* allocate info and space for data by why call */ + bf = calloc(1, sizeof(struct blkid_bufinfo) + len); + if (!bf) { + errno = ENOMEM; + return NULL; + } + + bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); + bf->len = len; + bf->off = off; + INIT_LIST_HEAD(&bf->bufs); + + DBG(LOWPROBE, ul_debug("\tbuffer read: off=%jd len=%jd pr=%p", + off, len, pr)); + + ret = read(pr->fd, bf->data, len); + if (ret != (ssize_t) len) { + DBG(LOWPROBE, ul_debug("\tbuffer read: return %zd error %m", ret)); + free(bf); + if (ret >= 0) + errno = 0; + return NULL; + } + list_add_tail(&bf->bufs, &pr->buffers); + } + + errno = 0; + return off ? bf->data + (off - bf->off) : bf->data; +} + + +static void blkid_probe_reset_buffer(blkid_probe pr) +{ + uint64_t read_ct = 0, len_ct = 0; + + if (!pr || list_empty(&pr->buffers)) + return; + + DBG(LOWPROBE, ul_debug("reseting probing buffers pr=%p", pr)); + + while (!list_empty(&pr->buffers)) { + struct blkid_bufinfo *bf = list_entry(pr->buffers.next, + struct blkid_bufinfo, bufs); + read_ct++; + len_ct += bf->len; + list_del(&bf->bufs); + free(bf); + } + + DBG(LOWPROBE, ul_debug("buffers summary: %"PRIu64" bytes " + "by %"PRIu64" read() call(s)", + len_ct, read_ct)); + + INIT_LIST_HEAD(&pr->buffers); +} + +/* + * Small devices need a special care. + */ +int blkid_probe_is_tiny(blkid_probe pr) +{ + return pr && (pr->flags & BLKID_FL_TINY_DEV); +} + +/* + * CDROMs may fail when probed for RAID (last sector problem) + */ +int blkid_probe_is_cdrom(blkid_probe pr) +{ + return pr && (pr->flags & BLKID_FL_CDROM_DEV); +} + +/** + * blkid_probe_set_device: + * @pr: probe + * @fd: device file descriptor + * @off: begin of probing area + * @size: size of probing area (zero means whole device/file) + * + * Assigns the device to probe control struct, resets internal buffers and + * resets the current probing. + * + * Returns: -1 in case of failure, or 0 on success. + */ +int blkid_probe_set_device(blkid_probe pr, int fd, + blkid_loff_t off, blkid_loff_t size) +{ + struct stat sb; + + if (!pr) + return -1; + + blkid_reset_probe(pr); + blkid_probe_reset_buffer(pr); + + if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) + close(pr->fd); + + pr->flags &= ~BLKID_FL_PRIVATE_FD; + pr->flags &= ~BLKID_FL_TINY_DEV; + pr->flags &= ~BLKID_FL_CDROM_DEV; + pr->prob_flags = 0; + pr->fd = fd; + pr->off = off; + pr->size = 0; + pr->devno = 0; + pr->disk_devno = 0; + pr->mode = 0; + pr->blkssz = 0; + pr->wipe_off = 0; + pr->wipe_size = 0; + pr->wipe_chain = NULL; + +#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE) + /* Disable read-ahead */ + posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); +#endif + if (fstat(fd, &sb)) + goto err; + + if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode)) + goto err; + + + pr->mode = sb.st_mode; + if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) + pr->devno = sb.st_rdev; + + if (size) + pr->size = size; + else { + if (S_ISBLK(sb.st_mode)) { + if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) { + DBG(LOWPROBE, ul_debug("failed to get device size")); + goto err; + } + } else if (S_ISCHR(sb.st_mode)) + pr->size = 1; /* UBI devices are char... */ + else if (S_ISREG(sb.st_mode)) + pr->size = sb.st_size; /* regular file */ + + if (pr->off > pr->size) + goto err; + + /* The probing area cannot be larger than whole device, pr->off + * is offset within the device */ + pr->size -= pr->off; + } + + if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode)) + pr->flags |= BLKID_FL_TINY_DEV; + + if (S_ISBLK(sb.st_mode) && sysfs_devno_is_lvm_private(sb.st_rdev)) { + DBG(LOWPROBE, ul_debug("ignore private LVM device")); + pr->flags |= BLKID_FL_NOSCAN_DEV; + } + +#ifdef CDROM_GET_CAPABILITY + else if (S_ISBLK(sb.st_mode) && + !blkid_probe_is_tiny(pr) && + blkid_probe_is_wholedisk(pr) && + ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0) + pr->flags |= BLKID_FL_CDROM_DEV; +#endif + + DBG(LOWPROBE, ul_debug("ready for low-probing, offset=%jd, size=%jd", + pr->off, pr->size)); + DBG(LOWPROBE, ul_debug("whole-disk: %s, regfile: %s", + blkid_probe_is_wholedisk(pr) ?"YES" : "NO", + S_ISREG(pr->mode) ? "YES" : "NO")); + + return 0; +err: + DBG(LOWPROBE, ul_debug("failed to prepare a device for low-probing")); + return -1; + +} + +int blkid_probe_get_dimension(blkid_probe pr, + blkid_loff_t *off, blkid_loff_t *size) +{ + if (!pr) + return -1; + + *off = pr->off; + *size = pr->size; + return 0; +} + +int blkid_probe_set_dimension(blkid_probe pr, + blkid_loff_t off, blkid_loff_t size) +{ + if (!pr) + return -1; + + DBG(LOWPROBE, ul_debug( + "changing probing area pr=%p: size=%llu, off=%llu " + "-to-> size=%llu, off=%llu", + pr, + (unsigned long long) pr->size, + (unsigned long long) pr->off, + (unsigned long long) size, + (unsigned long long) off)); + + pr->off = off; + pr->size = size; + pr->flags &= ~BLKID_FL_TINY_DEV; + + if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode)) + pr->flags |= BLKID_FL_TINY_DEV; + + blkid_probe_reset_buffer(pr); + + return 0; +} + +/* + * Check for matching magic value. + * Returns BLKID_PROBE_OK if found, BLKID_PROBE_NONE if not found + * or no magic present, or negative value on error. + */ +int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, + blkid_loff_t *offset, const struct blkid_idmag **res) +{ + const struct blkid_idmag *mag = NULL; + blkid_loff_t off = 0; + + if (id) + mag = &id->magics[0]; + if (res) + *res = NULL; + + /* try to detect by magic string */ + while(mag && mag->magic) { + unsigned char *buf; + + off = (mag->kboff + (mag->sboff >> 10)) << 10; + buf = blkid_probe_get_buffer(pr, off, 1024); + + if (!buf && errno) + return -errno; + if (buf && !memcmp(mag->magic, + buf + (mag->sboff & 0x3ff), mag->len)) { + DBG(LOWPROBE, ul_debug("\tmagic sboff=%u, kboff=%ld", + mag->sboff, mag->kboff)); + if (offset) + *offset = off + (mag->sboff & 0x3ff); + if (res) + *res = mag; + return BLKID_PROBE_OK; + } + mag++; + } + + if (id && id->magics[0].magic) + /* magic string(s) defined, but not found */ + return BLKID_PROBE_NONE; + + return BLKID_PROBE_OK; +} + +static inline void blkid_probe_start(blkid_probe pr) +{ + if (pr) { + DBG(LOWPROBE, ul_debug("%p: start probe", pr)); + pr->cur_chain = NULL; + pr->prob_flags = 0; + blkid_probe_set_wiper(pr, 0, 0); + } +} + +static inline void blkid_probe_end(blkid_probe pr) +{ + if (pr) { + DBG(LOWPROBE, ul_debug("%p: end probe", pr)); + pr->cur_chain = NULL; + pr->prob_flags = 0; + blkid_probe_set_wiper(pr, 0, 0); + } +} + +/** + * blkid_do_probe: + * @pr: prober + * + * Calls probing functions in all enabled chains. The superblocks chain is + * enabled by default. The blkid_do_probe() stores result from only one + * probing function. It's necessary to call this routine in a loop to get + * results from all probing functions in all chains. The probing is reset + * by blkid_reset_probe() or by filter functions. + * + * This is string-based NAME=value interface only. + * + * <example> + * <title>basic case - use the first result only</title> + * <programlisting> + * + * if (blkid_do_probe(pr) == 0) { + * int nvals = blkid_probe_numof_values(pr); + * for (n = 0; n < nvals; n++) { + * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) + * printf("%s = %s\n", name, data); + * } + * } + * </programlisting> + * </example> + * + * <example> + * <title>advanced case - probe for all signatures</title> + * <programlisting> + * + * while (blkid_do_probe(pr) == 0) { + * int nvals = blkid_probe_numof_values(pr); + * ... + * } + * </programlisting> + * </example> + * + * See also blkid_reset_probe(). + * + * Returns: 0 on success, 1 when probing is done and -1 in case of error. + */ +int blkid_do_probe(blkid_probe pr) +{ + int rc = 1; + + if (!pr) + return -1; + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return 1; + + do { + struct blkid_chain *chn = pr->cur_chain; + + if (!chn) { + blkid_probe_start(pr); + chn = pr->cur_chain = &pr->chains[0]; + } + /* we go to the next chain only when the previous probing + * result was nothing (rc == 1) and when the current chain is + * disabled or we are at end of the current chain (chain->idx + + * 1 == sizeof chain) or the current chain bailed out right at + * the start (chain->idx == -1) + */ + else if (rc == 1 && (chn->enabled == FALSE || + chn->idx + 1 == (int) chn->driver->nidinfos || + chn->idx == -1)) { + + size_t idx = chn->driver->id + 1; + + if (idx < BLKID_NCHAINS) + chn = pr->cur_chain = &pr->chains[idx]; + else { + blkid_probe_end(pr); + return 1; /* all chains already probed */ + } + } + + chn->binary = FALSE; /* for sure... */ + + DBG(LOWPROBE, ul_debug("chain probe %s %s (idx=%d)", + chn->driver->name, + chn->enabled? "ENABLED" : "DISABLED", + chn->idx)); + + if (!chn->enabled) + continue; + + /* rc: -1 = error, 0 = success, 1 = no result */ + rc = chn->driver->probe(pr, chn); + + } while (rc == 1); + + return rc; +} + +/** + * blkid_do_wipe: + * @pr: prober + * @dryrun: if TRUE then don't touch the device. + * + * This function erases the current signature detected by @pr. The @pr has to + * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags + * has to be enabled (if you want to errase also superblock with broken check + * sums then use BLKID_SUBLKS_BADCSUM too). + * + * After successful signature removing the @pr prober will be moved one step + * back and the next blkid_do_probe() call will again call previously called + * probing function. + * + * <example> + * <title>wipe all filesystems or raids from the device</title> + * <programlisting> + * fd = open(devname, O_RDWR|O_CLOEXEC); + * blkid_probe_set_device(pr, fd, 0, 0); + * + * blkid_probe_enable_superblocks(pr, 1); + * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); + * + * while (blkid_do_probe(pr) == 0) + * blkid_do_wipe(pr, FALSE); + * </programlisting> + * </example> + * + * See also blkid_probe_step_back() if you cannot use this build-in wipe + * function, but you want to use libblkid probing as a source for wiping. + * + * Returns: 0 on success, and -1 in case of error. + */ +int blkid_do_wipe(blkid_probe pr, int dryrun) +{ + const char *off = NULL; + size_t len = 0; + loff_t offset, l; + char buf[BUFSIZ]; + int fd, rc = 0; + struct blkid_chain *chn; + + if (!pr) + return -1; + + chn = pr->cur_chain; + if (!chn) + return -1; + + switch (chn->driver->id) { + case BLKID_CHAIN_SUBLKS: + rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); + if (!rc) + rc = blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); + break; + case BLKID_CHAIN_PARTS: + rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL); + if (!rc) + rc = blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); + break; + default: + return 0; + } + + if (rc || len == 0 || off == NULL) + return 0; + + offset = strtoll(off, NULL, 10); + fd = blkid_probe_get_fd(pr); + if (fd < 0) + return -1; + + if (len > sizeof(buf)) + len = sizeof(buf); + + DBG(LOWPROBE, ul_debug( + "do_wipe [offset=0x%jx, len=%zd, chain=%s, idx=%d, dryrun=%s]\n", + offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not")); + + l = lseek(fd, offset, SEEK_SET); + if (l == (off_t) -1) + return -1; + + memset(buf, 0, len); + + if (!dryrun && len) { + if (write_all(fd, buf, len)) + return -1; + fsync(fd); + return blkid_probe_step_back(pr); + } + + return 0; +} + +/** + * blkid_probe_step_back: + * @pr: prober + * + * This function move pointer to the probing chain one step back -- it means + * that the previously used probing function will be called again in the next + * blkid_do_probe() call. + * + * This is necessary for example if you erase or modify on-disk superblock + * according to the current libblkid probing result. + * + * <example> + * <title>wipe all superblock, but use libblkid only for probing</title> + * <programlisting> + * pr = blkid_new_probe_from_filename(devname); + * + * blkid_probe_enable_superblocks(pr, 1); + * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); + * + * blkid_probe_enable_partitions(pr, 1); + * blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC); + * + * while (blkid_do_probe(pr) == 0) { + * const char *ostr = NULL; + * size_t len = 0; + * + * // superblocks + * if (blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &ostr, NULL) == 0) + * blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); + * + * // partition tables + * if (len == 0 && blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &ostr, NULL) == 0) + * blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); + * + * if (!len || !str) + * continue; + * + * // convert ostr to the real offset by off = strtoll(ostr, NULL, 10); + * // use your stuff to errase @len bytes at the @off + * .... + * + * // retry the last probing to check for backup superblocks ..etc. + * blkid_probe_step_back(pr); + * } + * </programlisting> + * </example> + * + * Returns: 0 on success, and -1 in case of error. + */ +int blkid_probe_step_back(blkid_probe pr) +{ + struct blkid_chain *chn; + + if (!pr) + return -1; + + chn = pr->cur_chain; + if (!chn) + return -1; + + blkid_probe_reset_buffer(pr); + + if (chn->idx >= 0) { + chn->idx--; + DBG(LOWPROBE, ul_debug("step back: moving %s chain index to %d", + chn->driver->name, + chn->idx)); + } + + if (chn->idx == -1) { + /* blkid_do_probe() goes to the next chain if the index + * of the current chain is -1, so we have to set the + * chain pointer to the previous chain. + */ + size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0; + + DBG(LOWPROBE, ul_debug("step back: moving to previous chain")); + + if (idx > 0) + pr->cur_chain = &pr->chains[idx]; + else if (idx == 0) + pr->cur_chain = NULL; + } + + return 0; +} + +/** + * blkid_do_safeprobe: + * @pr: prober + * + * This function gathers probing results from all enabled chains and checks + * for ambivalent results (e.g. more filesystems on the device). + * + * This is string-based NAME=value interface only. + * + * Note about suberblocks chain -- the function does not check for filesystems + * when a RAID signature is detected. The function also does not check for + * collision between RAIDs. The first detected RAID is returned. The function + * checks for collision between partition table and RAID signature -- it's + * recommended to enable partitions chain together with superblocks chain. + * + * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is + * detected and -1 on case of error. + */ +int blkid_do_safeprobe(blkid_probe pr) +{ + int i, count = 0, rc = 0; + + if (!pr) + return -1; + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return 1; + + blkid_probe_start(pr); + + for (i = 0; i < BLKID_NCHAINS; i++) { + struct blkid_chain *chn; + + chn = pr->cur_chain = &pr->chains[i]; + chn->binary = FALSE; /* for sure... */ + + DBG(LOWPROBE, ul_debug("chain safeprobe %s %s", + chn->driver->name, + chn->enabled? "ENABLED" : "DISABLED")); + + if (!chn->enabled) + continue; + + blkid_probe_chain_reset_position(chn); + + rc = chn->driver->safeprobe(pr, chn); + + blkid_probe_chain_reset_position(chn); + + /* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */ + if (rc < 0) + goto done; /* error */ + if (rc == 0) + count++; /* success */ + } + +done: + blkid_probe_end(pr); + if (rc < 0) + return rc; + return count ? 0 : 1; +} + +/** + * blkid_do_fullprobe: + * @pr: prober + * + * This function gathers probing results from all enabled chains. Same as + * blkid_do_safeprobe() but does not check for collision between probing + * result. + * + * This is string-based NAME=value interface only. + * + * Returns: 0 on success, 1 if nothing is detected or -1 on case of error. + */ +int blkid_do_fullprobe(blkid_probe pr) +{ + int i, count = 0, rc = 0; + + if (!pr) + return -1; + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return 1; + + blkid_probe_start(pr); + + for (i = 0; i < BLKID_NCHAINS; i++) { + struct blkid_chain *chn; + + chn = pr->cur_chain = &pr->chains[i]; + chn->binary = FALSE; /* for sure... */ + + DBG(LOWPROBE, ul_debug("chain fullprobe %s: %s", + chn->driver->name, + chn->enabled? "ENABLED" : "DISABLED")); + + if (!chn->enabled) + continue; + + blkid_probe_chain_reset_position(chn); + + rc = chn->driver->probe(pr, chn); + + blkid_probe_chain_reset_position(chn); + + /* rc: -1 = error, 0 = success, 1 = no result */ + if (rc < 0) + goto done; /* error */ + if (rc == 0) + count++; /* success */ + } + +done: + blkid_probe_end(pr); + if (rc < 0) + return rc; + return count ? 0 : 1; +} + +/* same sa blkid_probe_get_buffer() but works with 512-sectors */ +unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) +{ + return pr ? blkid_probe_get_buffer(pr, + ((blkid_loff_t) sector) << 9, 0x200) : NULL; +} + +struct blkid_prval *blkid_probe_assign_value( + blkid_probe pr, const char *name) +{ + struct blkid_prval *v; + + if (!name) + return NULL; + if (pr->nvals >= BLKID_NVALS) + return NULL; + + v = &pr->vals[pr->nvals]; + v->name = name; + v->chain = pr->cur_chain; + pr->nvals++; + + DBG(LOWPROBE, ul_debug("assigning %s [%s]", name, v->chain->driver->name)); + return v; +} + +int blkid_probe_reset_last_value(blkid_probe pr) +{ + struct blkid_prval *v; + + if (pr == NULL || pr->nvals == 0) + return -1; + + v = &pr->vals[pr->nvals - 1]; + + DBG(LOWPROBE, ul_debug("un-assigning %s [%s]", v->name, v->chain->driver->name)); + + memset(v, 0, sizeof(struct blkid_prval)); + pr->nvals--; + + return 0; + +} + +int blkid_probe_set_value(blkid_probe pr, const char *name, + unsigned char *data, size_t len) +{ + struct blkid_prval *v; + + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + v = blkid_probe_assign_value(pr, name); + if (!v) + return -1; + + memcpy(v->data, data, len); + v->len = len; + return 0; +} + +int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, + const char *fmt, va_list ap) +{ + struct blkid_prval *v; + ssize_t len; + + v = blkid_probe_assign_value(pr, name); + if (!v) + return -1; + + len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); + + if (len <= 0 || (size_t) len >= sizeof(v->data)) { + blkid_probe_reset_last_value(pr); + return -1; + } + v->len = len + 1; + return 0; +} + +int blkid_probe_sprintf_value(blkid_probe pr, const char *name, + const char *fmt, ...) +{ + int rc; + va_list ap; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, name, fmt, ap); + va_end(ap); + + return rc; +} + +int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset, + size_t len, unsigned char *magic) +{ + int rc = 0; + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (!chn || !magic || !len || chn->binary) + return 0; + + switch (chn->driver->id) { + case BLKID_CHAIN_SUBLKS: + if (!(chn->flags & BLKID_SUBLKS_MAGIC)) + return 0; + rc = blkid_probe_set_value(pr, "SBMAGIC", magic, len); + if (!rc) + rc = blkid_probe_sprintf_value(pr, + "SBMAGIC_OFFSET", "%llu", (unsigned long long)offset); + break; + case BLKID_CHAIN_PARTS: + if (!(chn->flags & BLKID_PARTS_MAGIC)) + return 0; + rc = blkid_probe_set_value(pr, "PTMAGIC", magic, len); + if (!rc) + rc = blkid_probe_sprintf_value(pr, + "PTMAGIC_OFFSET", "%llu", (unsigned long long)offset); + break; + default: + break; + } + + return rc; +} + +int blkid_probe_verify_csum(blkid_probe pr, uint64_t csum, uint64_t expected) +{ + if (csum != expected) { + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + DBG(LOWPROBE, ul_debug( + "incorrect checksum for type %s," + " got %jX, expected %jX", + blkid_probe_get_probername(pr), + csum, expected)); + /* + * Accept bad checksum if BLKID_SUBLKS_BADCSUM flags is set + */ + if (chn->driver->id == BLKID_CHAIN_SUBLKS + && (chn->flags & BLKID_SUBLKS_BADCSUM)) { + blkid_probe_set_value(pr, "SBBADCSUM", (unsigned char *) "1", 2); + goto accept; + } + return 0; /* bad checksum */ + } + +accept: + return 1; +} + +/** + * blkid_probe_get_devno: + * @pr: probe + * + * Returns: block device number, or 0 for regular files. + */ +dev_t blkid_probe_get_devno(blkid_probe pr) +{ + return pr->devno; +} + +/** + * blkid_probe_get_wholedisk_devno: + * @pr: probe + * + * Returns: device number of the wholedisk, or 0 for regular files. + */ +dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) +{ + if (!pr->disk_devno) { + dev_t devno, disk_devno = 0; + + devno = blkid_probe_get_devno(pr); + if (!devno) + return 0; + + if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk_devno) == 0) + pr->disk_devno = disk_devno; + } + return pr->disk_devno; +} + +/** + * blkid_probe_is_wholedisk: + * @pr: probe + * + * Returns: 1 if the device is whole-disk or 0. + */ +int blkid_probe_is_wholedisk(blkid_probe pr) +{ + dev_t devno, disk_devno; + + devno = blkid_probe_get_devno(pr); + if (!devno) + return 0; + + disk_devno = blkid_probe_get_wholedisk_devno(pr); + if (!disk_devno) + return 0; + + return devno == disk_devno; +} + +blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr) +{ + dev_t disk; + + if (blkid_probe_is_wholedisk(pr)) + return NULL; /* this is not partition */ + + if (pr->parent) + /* this is cloned blkid_probe, use parent's stuff */ + return blkid_probe_get_wholedisk_probe(pr->parent); + + disk = blkid_probe_get_wholedisk_devno(pr); + + if (pr->disk_probe && pr->disk_probe->devno != disk) { + /* we have disk prober, but for another disk... close it */ + blkid_free_probe(pr->disk_probe); + pr->disk_probe = NULL; + } + + if (!pr->disk_probe) { + /* Open a new disk prober */ + char *disk_path = blkid_devno_to_devname(disk); + + if (!disk_path) + return NULL; + + DBG(LOWPROBE, ul_debug("allocate a wholedisk probe")); + + pr->disk_probe = blkid_new_probe_from_filename(disk_path); + + free(disk_path); + + if (!pr->disk_probe) + return NULL; /* ENOMEM? */ + } + + return pr->disk_probe; +} + +/** + * blkid_probe_get_size: + * @pr: probe + * + * This function returns size of probing area as defined by blkid_probe_set_device(). + * If the size of the probing area is unrestricted then this function returns + * the real size of device. See also blkid_get_dev_size(). + * + * Returns: size in bytes or -1 in case of error. + */ +blkid_loff_t blkid_probe_get_size(blkid_probe pr) +{ + return pr ? pr->size : -1; +} + +/** + * blkid_probe_get_offset: + * @pr: probe + * + * This function returns offset of probing area as defined by blkid_probe_set_device(). + * + * Returns: offset in bytes or -1 in case of error. + */ +blkid_loff_t blkid_probe_get_offset(blkid_probe pr) +{ + return pr ? pr->off : -1; +} + +/** + * blkid_probe_get_fd: + * @pr: probe + * + * Returns: file descriptor for assigned device/file or -1 in case of error. + */ +int blkid_probe_get_fd(blkid_probe pr) +{ + return pr ? pr->fd : -1; +} + +/** + * blkid_probe_get_sectorsize: + * @pr: probe or NULL (for NULL returns 512) + * + * Returns: block device logical sector size (BLKSSZGET ioctl, default 512). + */ +unsigned int blkid_probe_get_sectorsize(blkid_probe pr) +{ + if (!pr) + return DEFAULT_SECTOR_SIZE; /*... and good luck! */ + + if (pr->blkssz) + return pr->blkssz; + + if (S_ISBLK(pr->mode) && + blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz) == 0) + return pr->blkssz; + + pr->blkssz = DEFAULT_SECTOR_SIZE; + return pr->blkssz; +} + +/** + * blkid_probe_get_sectors: + * @pr: probe + * + * Returns: 512-byte sector count or -1 in case of error. + */ +blkid_loff_t blkid_probe_get_sectors(blkid_probe pr) +{ + return pr ? pr->size >> 9 : -1; +} + +/** + * blkid_probe_numof_values: + * @pr: probe + * + * Returns: number of values in probing result or -1 in case of error. + */ +int blkid_probe_numof_values(blkid_probe pr) +{ + if (!pr) + return -1; + return pr->nvals; +} + +/** + * blkid_probe_get_value: + * @pr: probe + * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1 + * @name: pointer to return value name or NULL + * @data: pointer to return value data or NULL + * @len: pointer to return value length or NULL + * + * Note, the @len returns length of the @data, including the terminating + * '\0' character. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_get_value(blkid_probe pr, int num, const char **name, + const char **data, size_t *len) +{ + struct blkid_prval *v = __blkid_probe_get_value(pr, num); + + if (!v) + return -1; + if (name) + *name = v->name; + if (data) + *data = (char *) v->data; + if (len) + *len = v->len; + + DBG(LOWPROBE, ul_debug("returning %s value", v->name)); + return 0; +} + +/** + * blkid_probe_lookup_value: + * @pr: probe + * @name: name of value + * @data: pointer to return value data or NULL + * @len: pointer to return value length or NULL + * + * Note, the @len returns length of the @data, including the terminating + * '\0' character. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_lookup_value(blkid_probe pr, const char *name, + const char **data, size_t *len) +{ + struct blkid_prval *v = __blkid_probe_lookup_value(pr, name); + + if (!v) + return -1; + if (data) + *data = (char *) v->data; + if (len) + *len = v->len; + return 0; +} + +/** + * blkid_probe_has_value: + * @pr: probe + * @name: name of value + * + * Returns: 1 if value exist in probing result, otherwise 0. + */ +int blkid_probe_has_value(blkid_probe pr, const char *name) +{ + if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) + return 1; + return 0; +} + +struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) +{ + if (!pr || num < 0 || num >= pr->nvals) + return NULL; + + return &pr->vals[num]; +} + +struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) +{ + int i; + + if (!pr || !pr->nvals || !name) + return NULL; + + for (i = 0; i < pr->nvals; i++) { + struct blkid_prval *v = &pr->vals[i]; + + if (v->name && strcmp(name, v->name) == 0) { + DBG(LOWPROBE, ul_debug("returning %s value", v->name)); + return v; + } + } + return NULL; +} + + +/* converts DCE UUID (uuid[16]) to human readable string + * - the @len should be always 37 */ +#ifdef HAVE_LIBUUID +void blkid_unparse_uuid(const unsigned char *uuid, char *str, + size_t len __attribute__((__unused__))) +{ + uuid_unparse(uuid, str); +} +#else +void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) +{ + snprintf(str, len, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], + uuid[6], uuid[7], + uuid[8], uuid[9], + uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); +} +#endif + +/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */ +int blkid_uuid_is_empty(const unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + if (buf[i]) + return 0; + return 1; +} + +/* Removes whitespace from the right-hand side of a string (trailing + * whitespace). + * + * Returns size of the new string (without \0). + */ +size_t blkid_rtrim_whitespace(unsigned char *str) +{ + return rtrim_whitespace(str); +} + +/* Removes whitespace from the left-hand side of a string. + * + * Returns size of the new string (without \0). + */ +size_t blkid_ltrim_whitespace(unsigned char *str) +{ + return ltrim_whitespace(str); +} + +/* + * Some mkfs-like utils wipe some parts (usually begin) of the device. + * For example LVM (pvcreate) or mkswap(8). This information could be used + * for later resolution to conflicts between superblocks. + * + * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of + * the device. If we found another signature (for example MBR) within the + * wiped area then the signature has been added later and LVM superblock + * should be ignore. + * + * Note that this heuristic is not 100% reliable, for example "pvcreate --zero + * n" allows to keep the begin of the device unmodified. It's probably better + * to use this heuristic for conflicts between superblocks and partition tables + * than for conflicts between filesystem superblocks -- existence of unwanted + * partition table is very unusual, because PT is pretty visible (parsed and + * interpreted by kernel). + * + * Note that we usually expect only one signature on the device, it means that + * we have to remember only one wiped area from previously successfully + * detected signature. + * + * blkid_probe_set_wiper() -- defines wiped area (e.g. LVM) + * blkid_probe_use_wiper() -- try to use area (e.g. MBR) + * + * Note that there is not relation between _wiper and blkid_to_wipe(). + * + */ +void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) +{ + struct blkid_chain *chn; + + if (!pr) + return; + + if (!size) { + DBG(LOWPROBE, ul_debug("zeroize wiper")); + pr->wipe_size = pr->wipe_off = 0; + pr->wipe_chain = NULL; + return; + } + + chn = pr->cur_chain; + + if (!chn || !chn->driver || + chn->idx < 0 || (size_t) chn->idx >= chn->driver->nidinfos) + return; + + pr->wipe_size = size; + pr->wipe_off = off; + pr->wipe_chain = chn; + + DBG(LOWPROBE, + ul_debug("wiper set to %s::%s off=%jd size=%jd", + chn->driver->name, + chn->driver->idinfos[chn->idx]->name, + pr->wipe_off, pr->wipe_size)); + return; +} + +/* + * Returns 1 if the <@off,@size> area was wiped + */ +int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, + blkid_loff_t off, blkid_loff_t size) +{ + if (!pr || !size) + return 0; + + if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) { + if (chn) + *chn = pr->wipe_chain; + return 1; + } + return 0; +} + +/* + * Try to use any area -- if the area has been previously wiped then the + * previous probing result should be ignored (reseted). + */ +void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) +{ + struct blkid_chain *chn = NULL; + + if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) { + DBG(LOWPROBE, ul_debug("previously wiped area modified " + " -- ignore previous results")); + blkid_probe_set_wiper(pr, 0, 0); + blkid_probe_chain_reset_vals(pr, chn); + } +} diff --git a/libblkid/src/pt-bsd.h b/libblkid/src/pt-bsd.h new file mode 100644 index 000000000..9bf47a576 --- /dev/null +++ b/libblkid/src/pt-bsd.h @@ -0,0 +1,156 @@ +#ifndef UTIL_LINUX_PT_BSD_H +#define UTIL_LINUX_PT_BSD_H + +#define BSD_MAXPARTITIONS 16 +#define BSD_FS_UNUSED 0 + +#ifndef BSD_DISKMAGIC +# define BSD_DISKMAGIC ((uint32_t) 0x82564557) +#endif + +#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" + +#if defined (__alpha__) || defined (__powerpc__) || \ + defined (__ia64__) || defined (__hppa__) +# define BSD_LABELSECTOR 0 +# define BSD_LABELOFFSET 64 +#else +# define BSD_LABELSECTOR 1 +# define BSD_LABELOFFSET 0 +#endif + +#define BSD_BBSIZE 8192 /* size of boot area, with label */ +#define BSD_SBSIZE 8192 /* max size of fs superblock */ + +struct bsd_disklabel { + uint32_t d_magic; /* the magic number */ + int16_t d_type; /* drive type */ + int16_t d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + char d_packname[16]; /* pack identifier */ + + /* disk geometry: */ + uint32_t d_secsize; /* # of bytes per sector */ + uint32_t d_nsectors; /* # of data sectors per track */ + uint32_t d_ntracks; /* # of tracks per cylinder */ + uint32_t d_ncylinders; /* # of data cylinders per unit */ + uint32_t d_secpercyl; /* # of data sectors per cylinder */ + uint32_t d_secperunit; /* # of data sectors per unit */ + + /* + * Spares (bad sector replacements) below + * are not counted in d_nsectors or d_secpercyl. + * Spare sectors are assumed to be physical sectors + * which occupy space at the end of each track and/or cylinder. + */ + uint16_t d_sparespertrack; /* # of spare sectors per track */ + uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ + + /* + * Alternate cylinders include maintenance, replacement, + * configuration description areas, etc. + */ + uint32_t d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the formatter + * or controller when formatting. When interleaving is in use, + * logically adjacent sectors are not physically contiguous, + * but instead are separated by some number of sectors. + * It is specified as the ratio of physical sectors traversed + * per logical sector. Thus an interleave of 1:1 implies contiguous + * layout, while 2:1 implies that logical sector 0 is separated + * by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N + * relative to sector 0 on track N-1 on the same cylinder. + * Finally, d_cylskew is the offset of sector 0 on cylinder N + * relative to sector 0 on cylinder N-1. + */ + uint16_t d_rpm; /* rotational speed */ + uint16_t d_interleave; /* hardware sector interleave */ + uint16_t d_trackskew; /* sector 0 skew, per track */ + uint16_t d_cylskew; /* sector 0 skew, per cylinder */ + uint32_t d_headswitch; /* head switch time, usec */ + uint32_t d_trkseek; /* track-to-track seek, usec */ + uint32_t d_flags; /* generic flags */ + uint32_t d_drivedata[5]; /* drive-type specific information */ + uint32_t d_spare[5]; /* reserved for future use */ + uint32_t d_magic2; /* the magic number (again) */ + uint16_t d_checksum; /* xor of data incl. partitions */ + + /* filesystem and partition information: */ + uint16_t d_npartitions; /* number of partitions in following */ + uint32_t d_bbsize; /* size of boot area at sn0, bytes */ + uint32_t d_sbsize; /* max size of fs superblock, bytes */ + + struct bsd_partition { /* the partition table */ + uint32_t p_size; /* number of sectors in partition */ + uint32_t p_offset; /* starting sector */ + uint32_t p_fsize; /* filesystem basic fragment size */ + uint8_t p_fstype; /* filesystem type, see below */ + uint8_t p_frag; /* filesystem fragments per block */ + uint16_t p_cpg; /* filesystem cylinders per group */ + } __attribute__((packed)) d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +} __attribute__((packed)); + + +/* d_type values: */ +#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define BSD_DTYPE_MSCP 2 /* MSCP */ +#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define BSD_DTYPE_SCSI 4 /* SCSI */ +#define BSD_DTYPE_ESDI 5 /* ESDI interface */ +#define BSD_DTYPE_ST506 6 /* ST506 etc. */ +#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ +#define BSD_DTYPE_FLOPPY 10 /* floppy */ + +/* d_subtype values: */ +#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ +#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ +#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ + +/* + * Filesystem type and version. + * Used to interpret other filesystem-specific + * per-partition information. + */ +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ +#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ +#define BSD_FS_ISOFS BSD_FS_ISO9660 +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ +#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */ + +/* this is annoying, but it's also the way it is :-( */ +#ifdef __alpha__ +#define BSD_FS_EXT2 8 /* ext2 file system */ +#else +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#endif + +/* + * flags shared by various drives: + */ +#define BSD_D_REMOVABLE 0x01 /* removable media */ +#define BSD_D_ECC 0x02 /* supports ECC */ +#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ +#define BSD_D_RAMDISK 0x08 /* disk emulator */ +#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ +#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ + +#endif /* UTIL_LINUX_PT_BSD_H */ diff --git a/libblkid/src/pt-mbr.h b/libblkid/src/pt-mbr.h new file mode 100644 index 000000000..1279e3cf2 --- /dev/null +++ b/libblkid/src/pt-mbr.h @@ -0,0 +1,178 @@ +#ifndef UTIL_LINUX_PT_MBR_H +#define UTIL_LINUX_PT_MBR_H + +struct dos_partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char bh, bs, bc; /* begin CHS */ + unsigned char sys_ind; + unsigned char eh, es, ec; /* end CHS */ + unsigned char start_sect[4]; + unsigned char nr_sects[4]; +} __attribute__((packed)); + +#define MBR_PT_OFFSET 0x1be + +static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i) +{ + return (struct dos_partition *) + (mbr + MBR_PT_OFFSET + (i * sizeof(struct dos_partition))); +} + +/* assemble badly aligned little endian integer */ +static inline unsigned int __dos_assemble_4le(const unsigned char *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + +static inline void __dos_store_4le(unsigned char *p, unsigned int val) +{ + p[0] = (val & 0xff); + p[1] = ((val >> 8) & 0xff); + p[2] = ((val >> 16) & 0xff); + p[3] = ((val >> 24) & 0xff); +} + +static inline unsigned int dos_partition_get_start(struct dos_partition *p) +{ + return __dos_assemble_4le(&(p->start_sect[0])); +} + +static inline void dos_partition_set_start(struct dos_partition *p, unsigned int n) +{ + __dos_store_4le(p->start_sect, n); +} + +static inline unsigned int dos_partition_get_size(struct dos_partition *p) +{ + return __dos_assemble_4le(&(p->nr_sects[0])); +} + +static inline void dos_partition_set_size(struct dos_partition *p, unsigned int n) +{ + __dos_store_4le(p->nr_sects, n); +} + +static inline int mbr_is_valid_magic(const unsigned char *mbr) +{ + return mbr[510] == 0x55 && mbr[511] == 0xaa ? 1 : 0; +} + +static inline void mbr_set_magic(unsigned char *b) +{ + b[510] = 0x55; + b[511] = 0xaa; +} + +static inline unsigned int mbr_get_id(const unsigned char *mbr) +{ + return __dos_assemble_4le(&mbr[440]); +} + +static inline void mbr_set_id(unsigned char *b, unsigned int id) +{ + __dos_store_4le(&b[440], id); +} + +enum { + MBR_EMPTY_PARTITION = 0x00, + MBR_FAT12_PARTITION = 0x01, + MBR_XENIX_ROOT_PARTITION = 0x02, + MBR_XENIX_USR_PARTITION = 0x03, + MBR_FAT16_LESS32M_PARTITION = 0x04, + MBR_DOS_EXTENDED_PARTITION = 0x05, + MBR_FAT16_PARTITION = 0x06, /* DOS 16-bit >=32M */ + MBR_HPFS_NTFS_PARTITION = 0x07, /* OS/2 IFS, eg, HPFS or NTFS or QNX */ + MBR_AIX_PARTITION = 0x08, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ + MBR_AIX_BOOTABLE_PARTITION = 0x09, /* AIX data or Coherent */ + MBR_OS2_BOOTMNGR_PARTITION = 0x0a, /* OS/2 Boot Manager */ + MBR_W95_FAT32_PARTITION = 0x0b, + MBR_W95_FAT32_LBA_PARTITION = 0x0c, /* LBA really is `Extended Int 13h' */ + MBR_W95_FAT16_LBA_PARTITION = 0x0e, + MBR_W95_EXTENDED_PARTITION = 0x0f, + MBR_OPUS_PARTITION = 0x10, + MBR_HIDDEN_FAT12_PARTITION = 0x11, + MBR_COMPAQ_DIAGNOSTICS_PARTITION = 0x12, + MBR_HIDDEN_FAT16_L32M_PARTITION = 0x14, + MBR_HIDDEN_FAT16_PARTITION = 0x16, + MBR_HIDDEN_HPFS_NTFS_PARTITION = 0x17, + MBR_AST_SMARTSLEEP_PARTITION = 0x18, + MBR_HIDDEN_W95_FAT32_PARTITION = 0x1b, + MBR_HIDDEN_W95_FAT32LBA_PARTITION = 0x1c, + MBR_HIDDEN_W95_FAT16LBA_PARTITION = 0x1e, + MBR_NEC_DOS_PARTITION = 0x24, + MBR_PLAN9_PARTITION = 0x39, + MBR_PARTITIONMAGIC_PARTITION = 0x3c, + MBR_VENIX80286_PARTITION = 0x40, + MBR_PPC_PREP_BOOT_PARTITION = 0x41, + MBR_SFS_PARTITION = 0x42, + MBR_QNX_4X_PARTITION = 0x4d, + MBR_QNX_4X_2ND_PARTITION = 0x4e, + MBR_QNX_4X_3RD_PARTITION = 0x4f, + MBR_DM_PARTITION = 0x50, + MBR_DM6_AUX1_PARTITION = 0x51, /* (or Novell) */ + MBR_CPM_PARTITION = 0x52, /* CP/M or Microport SysV/AT */ + MBR_DM6_AUX3_PARTITION = 0x53, + MBR_DM6_PARTITION = 0x54, + MBR_EZ_DRIVE_PARTITION = 0x55, + MBR_GOLDEN_BOW_PARTITION = 0x56, + MBR_PRIAM_EDISK_PARTITION = 0x5c, + MBR_SPEEDSTOR_PARTITION = 0x61, + MBR_GNU_HURD_PARTITION = 0x63, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ + MBR_UNIXWARE_PARTITION = MBR_GNU_HURD_PARTITION, + MBR_NETWARE_286_PARTITION = 0x64, + MBR_NETWARE_386_PARTITION = 0x65, + MBR_DISKSECURE_MULTIBOOT_PARTITION = 0x70, + MBR_PC_IX_PARTITION = 0x75, + MBR_OLD_MINIX_PARTITION = 0x80, /* Minix 1.4a and earlier */ + MBR_MINIX_PARTITION = 0x81, /* Minix 1.4b and later */ + MBR_LINUX_SWAP_PARTITION = 0x82, + MBR_SOLARIS_X86_PARTITION = MBR_LINUX_SWAP_PARTITION, + MBR_LINUX_DATA_PARTITION = 0x83, + MBR_OS2_HIDDEN_DRIVE_PARTITION = 0x84, + MBR_LINUX_EXTENDED_PARTITION = 0x85, + MBR_NTFS_VOL_SET1_PARTITION = 0x86, + MBR_NTFS_VOL_SET2_PARTITION = 0x87, + MBR_LINUX_PLAINTEXT_PARTITION = 0x88, + MBR_LINUX_LVM_PARTITION = 0x8e, + MBR_AMOEBA_PARTITION = 0x93, + MBR_AMOEBA_BBT_PARTITION = 0x94, /* (bad block table) */ + MBR_BSD_OS_PARTITION = 0x9f, /* BSDI */ + MBR_THINKPAD_HIBERNATION_PARTITION = 0xa0, + MBR_FREEBSD_PARTITION = 0xa5, /* various BSD flavours */ + MBR_OPENBSD_PARTITION = 0xa6, + MBR_NEXTSTEP_PARTITION = 0xa7, + MBR_DARWIN_UFS_PARTITION = 0xa8, + MBR_NETBSD_PARTITION = 0xa9, + MBR_DARWIN_BOOT_PARTITION = 0xab, + MBR_HFS_HFS_PARTITION = 0xaf, + MBR_BSDI_FS_PARTITION = 0xb7, + MBR_BSDI_SWAP_PARTITION = 0xb8, + MBR_BOOTWIZARD_HIDDEN_PARTITION = 0xbb, + MBR_SOLARIS_BOOT_PARTITION = 0xbe, + MBR_SOLARIS_PARTITION = 0xbf, + MBR_DRDOS_FAT12_PARTITION = 0xc1, + MBR_DRDOS_FAT16_L32M_PARTITION = 0xc4, + MBR_DRDOS_FAT16_PARTITION = 0xc6, + MBR_SYRINX_PARTITION = 0xc7, + MBR_NONFS_DATA_PARTITION = 0xda, + MBR_CPM_CTOS_PARTITION = 0xdb, /* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */ + MBR_DELL_UTILITY_PARTITION = 0xde, /* Dell PowerEdge Server utilities */ + MBR_BOOTIT_PARTITION = 0xdf, /* BootIt EMBRM */ + MBR_DOS_ACCESS_PARTITION = 0xe1, /* DOS access or SpeedStor 12-bit FAT extended partition */ + MBR_DOS_RO_PARTITION = 0xe3, /* DOS R/O or SpeedStor */ + MBR_SPEEDSTOR_EXTENDED_PARTITION = 0xe4, /* SpeedStor 16-bit FAT extended partition < 1024 cyl. */ + MBR_BEOS_FS_PARTITION = 0xeb, + MBR_GPT_PARTITION = 0xee, /* Intel EFI GUID Partition Table */ + MBR_EFI_SYSTEM_PARTITION = 0xef, /* Intel EFI System Partition */ + MBR_LINUX_PARISC_BOOT_PARTITION = 0xf0, /* Linux/PA-RISC boot loader */ + MBR_SPEEDSTOR1_PARTITION = 0xf1, + MBR_SPEEDSTOR2_PARTITION = 0xf4, /* SpeedStor large partition */ + MBR_DOS_SECONDARY_PARTITION = 0xf2, /* DOS 3.3+ secondary */ + MBR_VMWARE_VMFS_PARTITION = 0xfb, + MBR_VMWARE_VMKCORE_PARTITION = 0xfc, /* VMware kernel dump partition */ + MBR_LINUX_RAID_PARTITION = 0xfd, /* New (2.2.x) raid partition with autodetect using persistent superblock */ + MBR_LANSTEP_PARTITION = 0xfe, /* SpeedStor >1024 cyl. or LANstep */ + MBR_XENIX_BBT_PARTITION = 0xff, /* Xenix Bad Block Table */ +}; + +#endif /* UTIL_LINUX_PT_MBR_H */ diff --git a/libblkid/src/read.c b/libblkid/src/read.c new file mode 100644 index 000000000..81ab0dfd6 --- /dev/null +++ b/libblkid/src/read.c @@ -0,0 +1,510 @@ +/* + * read.c - read the blkid cache from disk, to avoid scanning all devices + * + * Copyright (C) 2001, 2003 Theodore Y. Ts'o + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "blkidP.h" + +#ifdef HAVE_STDLIB_H +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 600 /* for inclusion of strtoull */ +# endif +# include <stdlib.h> +#endif + +#ifdef HAVE_STRTOULL +#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */ +#else +/* FIXME: need to support real strtoull here */ +#define STRTOULL strtoul +#endif + +#ifdef TEST_PROGRAM +#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev)) +static void debug_dump_dev(blkid_dev dev); +#endif + +/* + * File format: + * + * <device [<NAME="value"> ...]>device_name</device> + * + * The following tags are required for each entry: + * <ID="id"> unique (within this file) ID number of this device + * <TIME="sec.usec"> (time_t and suseconds_t) time this entry was last + * read from disk + * <TYPE="type"> (detected) type of filesystem/data for this partition + * + * The following tags may be present, depending on the device contents + * <LABEL="label"> (user supplied) label (volume name, etc) + * <UUID="uuid"> (generated) universally unique identifier (serial no) + */ + +static char *skip_over_blank(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + char ch; + + while ((ch = *cp)) { + /* If we see a backslash, skip the next character */ + if (ch == '\\') { + cp++; + if (*cp == '\0') + break; + cp++; + continue; + } + if (isspace(ch) || ch == '<' || ch == '>') + break; + cp++; + } + return cp; +} + +static char *strip_line(char *line) +{ + char *p; + + line = skip_over_blank(line); + + p = line + strlen(line) - 1; + + while (*line) { + if (isspace(*p)) + *p-- = '\0'; + else + break; + } + + return line; +} + +#if 0 +static char *parse_word(char **buf) +{ + char *word, *next; + + word = *buf; + if (*word == '\0') + return NULL; + + word = skip_over_blank(word); + next = skip_over_word(word); + if (*next) { + char *end = next - 1; + if (*end == '"' || *end == '\'') + *end = '\0'; + *next++ = '\0'; + } + *buf = next; + + if (*word == '"' || *word == '\'') + word++; + return word; +} +#endif + +/* + * Start parsing a new line from the cache. + * + * line starts with "<device" return 1 -> continue parsing line + * line starts with "<foo", empty, or # return 0 -> skip line + * line starts with other, return -BLKID_ERR_CACHE -> error + */ +static int parse_start(char **cp) +{ + char *p; + + p = strip_line(*cp); + + /* Skip comment or blank lines. We can't just NUL the first '#' char, + * in case it is inside quotes, or escaped. + */ + if (*p == '\0' || *p == '#') + return 0; + + if (!strncmp(p, "<device", 7)) { + DBG(READ, ul_debug("found device header: %8s", p)); + p += 7; + + *cp = p; + return 1; + } + + if (*p == '<') + return 0; + + return -BLKID_ERR_CACHE; +} + +/* Consume the remaining XML on the line (cosmetic only) */ +static int parse_end(char **cp) +{ + *cp = skip_over_blank(*cp); + + if (!strncmp(*cp, "</device>", 9)) { + DBG(READ, ul_debug("found device trailer %9s", *cp)); + *cp += 9; + return 0; + } + + return -BLKID_ERR_CACHE; +} + +/* + * Allocate a new device struct with device name filled in. Will handle + * finding the device on lines of the form: + * <device foo=bar>devname</device> + * <device>devname<foo>bar</foo></device> + */ +static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp) +{ + char *start, *tmp, *end, *name; + int ret; + + if ((ret = parse_start(cp)) <= 0) + return ret; + + start = tmp = strchr(*cp, '>'); + if (!start) { + DBG(READ, ul_debug("blkid: short line parsing dev: %s", *cp)); + return -BLKID_ERR_CACHE; + } + start = skip_over_blank(start + 1); + end = skip_over_word(start); + + DBG(READ, ul_debug("device should be %*s", + (int)(end - start), start)); + + if (**cp == '>') + *cp = end; + else + (*cp)++; + + *tmp = '\0'; + + if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) { + DBG(READ, ul_debug("blkid: missing </device> ending: %s", end)); + } else if (tmp) + *tmp = '\0'; + + if (end - start <= 1) { + DBG(READ, ul_debug("blkid: empty device name: %s", *cp)); + return -BLKID_ERR_CACHE; + } + + name = strndup(start, end - start); + if (name == NULL) + return -BLKID_ERR_MEM; + + DBG(READ, ul_debug("found dev %s", name)); + + if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) { + free(name); + return -BLKID_ERR_MEM; + } + + free(name); + return 1; +} + +/* + * Extract a tag of the form NAME="value" from the line. + */ +static int parse_token(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + if (!(*value = strchr(*cp, '='))) + return 0; + + **value = '\0'; + *name = strip_line(*cp); + *value = skip_over_blank(*value + 1); + + if (**value == '"') { + char *p = end = *value + 1; + + /* convert 'foo\"bar' to 'foo"bar' */ + while (*p) { + if (*p == '\\') { + p++; + *end = *p; + } else { + *end = *p; + if (*p == '"') + break; + } + p++; + end++; + } + + if (*end != '"') { + DBG(READ, ul_debug("unbalanced quotes at: %s", *value)); + *cp = *value; + return -BLKID_ERR_CACHE; + } + (*value)++; + *end = '\0'; + end = ++p; + } else { + end = skip_over_word(*value); + if (*end) { + *end = '\0'; + end++; + } + } + *cp = end; + + return 1; +} + +/* + * Extract a tag of the form <NAME>value</NAME> from the line. + */ +/* +static int parse_xml(char **name, char **value, char **cp) +{ + char *end; + + if (!name || !value || !cp) + return -BLKID_ERR_PARAM; + + *name = strip_line(*cp); + + if ((*name)[0] != '<' || (*name)[1] == '/') + return 0; + + FIXME: finish this. +} +*/ + +/* + * Extract a tag from the line. + * + * Return 1 if a valid tag was found. + * Return 0 if no tag found. + * Return -ve error code. + */ +static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp) +{ + char *name = NULL; + char *value = NULL; + int ret; + + if (!cache || !dev) + return -BLKID_ERR_PARAM; + + if ((ret = parse_token(&name, &value, cp)) <= 0 /* && + (ret = parse_xml(&name, &value, cp)) <= 0 */) + return ret; + + /* Some tags are stored directly in the device struct */ + if (!strcmp(name, "DEVNO")) + dev->bid_devno = STRTOULL(value, 0, 0); + else if (!strcmp(name, "PRI")) + dev->bid_pri = strtol(value, 0, 0); + else if (!strcmp(name, "TIME")) { + char *end = NULL; + dev->bid_time = STRTOULL(value, &end, 0); + if (end && *end == '.') + dev->bid_utime = STRTOULL(end + 1, 0, 0); + } else + ret = blkid_set_tag(dev, name, value, strlen(value)); + + DBG(READ, ul_debug(" tag: %s=\"%s\"", name, value)); + + return ret < 0 ? ret : 1; +} + +/* + * Parse a single line of data, and return a newly allocated dev struct. + * Add the new device to the cache struct, if one was read. + * + * Lines are of the form <device [TAG="value" ...]>/dev/foo</device> + * + * Returns -ve value on error. + * Returns 0 otherwise. + * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL + * (e.g. comment lines, unknown XML content, etc). + */ +static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp) +{ + blkid_dev dev; + int ret; + + if (!cache || !dev_p) + return -BLKID_ERR_PARAM; + + *dev_p = NULL; + + DBG(READ, ul_debug("line: %s", cp)); + + if ((ret = parse_dev(cache, dev_p, &cp)) <= 0) + return ret; + + dev = *dev_p; + + while ((ret = parse_tag(cache, dev, &cp)) > 0) { + ; + } + + if (dev->bid_type == NULL) { + DBG(READ, ul_debug("blkid: device %s has no TYPE",dev->bid_name)); + blkid_free_dev(dev); + goto done; + } + + DBG(READ, blkid_debug_dump_dev(dev)); + +done: + return ret; +} + +/* + * Parse the specified filename, and return the data in the supplied or + * a newly allocated cache struct. If the file doesn't exist, return a + * new empty cache struct. + */ +void blkid_read_cache(blkid_cache cache) +{ + FILE *file; + char buf[4096]; + int fd, lineno = 0; + struct stat st; + + if (!cache) + return; + + /* + * If the file doesn't exist, then we just return an empty + * struct so that the cache can be populated. + */ + if ((fd = open(cache->bic_filename, O_RDONLY|O_CLOEXEC)) < 0) + return; + if (fstat(fd, &st) < 0) + goto errout; + if ((st.st_mtime == cache->bic_ftime) || + (cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(CACHE, ul_debug("skipping re-read of %s", + cache->bic_filename)); + goto errout; + } + + DBG(CACHE, ul_debug("reading cache file %s", + cache->bic_filename)); + + file = fdopen(fd, "r" UL_CLOEXECSTR); + if (!file) + goto errout; + + while (fgets(buf, sizeof(buf), file)) { + blkid_dev dev; + unsigned int end; + + lineno++; + if (buf[0] == 0) + continue; + end = strlen(buf) - 1; + /* Continue reading next line if it ends with a backslash */ + while (end < (sizeof(buf) - 2) && buf[end] == '\\' && + fgets(buf + end, sizeof(buf) - end, file)) { + end = strlen(buf) - 1; + lineno++; + } + + if (blkid_parse_line(cache, &dev, buf) < 0) { + DBG(READ, ul_debug("blkid: bad format on line %d", lineno)); + continue; + } + } + fclose(file); + + /* + * Initially we do not need to write out the cache file. + */ + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + cache->bic_ftime = st.st_mtime; + + return; +errout: + close(fd); + return; +} + +#ifdef TEST_PROGRAM +static void debug_dump_dev(blkid_dev dev) +{ + struct list_head *p; + + if (!dev) { + printf(" dev: NULL\n"); + return; + } + + printf(" dev: name = %s\n", dev->bid_name); + printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno); + printf(" dev: TIME=\"%ld.%ld\"\n", (long)dev->bid_time, (long)dev->bid_utime); + printf(" dev: PRI=\"%d\"\n", dev->bid_pri); + printf(" dev: flags = 0x%08X\n", dev->bid_flags); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + if (tag) + printf(" tag: %s=\"%s\"\n", tag->bit_name, + tag->bit_val); + else + printf(" tag: NULL\n"); + } + printf("\n"); +} + +int main(int argc, char**argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(BLKID_DEBUG_ALL); + if (argc > 2) { + fprintf(stderr, "Usage: %s [filename]\n" + "Test parsing of the cache (filename)\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, argv[1])) < 0) + fprintf(stderr, "error %d reading cache file %s\n", ret, + argv[1] ? argv[1] : blkid_get_cache_filename(NULL)); + + blkid_put_cache(cache); + + return ret; +} +#endif diff --git a/libblkid/src/resolve.c b/libblkid/src/resolve.c new file mode 100644 index 000000000..59f0fea2b --- /dev/null +++ b/libblkid/src/resolve.c @@ -0,0 +1,130 @@ +/* + * resolve.c - resolve names and tags into specific devices + * + * Copyright (C) 2001, 2003 Theodore Ts'o. + * Copyright (C) 2001 Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "blkidP.h" + +/* + * Find a tagname (e.g. LABEL or UUID) on a specific device. + */ +char *blkid_get_tag_value(blkid_cache cache, const char *tagname, + const char *devname) +{ + blkid_tag found; + blkid_dev dev; + blkid_cache c = cache; + char *ret = NULL; + + DBG(TAG, ul_debug("looking for %s on %s", tagname, devname)); + + if (!devname) + return NULL; + if (!cache && blkid_get_cache(&c, NULL) < 0) + return NULL; + + if ((dev = blkid_get_dev(c, devname, BLKID_DEV_NORMAL)) && + (found = blkid_find_tag_dev(dev, tagname))) + ret = found->bit_val ? strdup(found->bit_val) : NULL; + + if (!cache) + blkid_put_cache(c); + + return ret; +} + +/* + * Locate a device name from a token (NAME=value string), or (name, value) + * pair. In the case of a token, value is ignored. If the "token" is not + * of the form "NAME=value" and there is no value given, then it is assumed + * to be the actual devname and a copy is returned. + */ +char *blkid_get_devname(blkid_cache cache, const char *token, + const char *value) +{ + blkid_dev dev; + blkid_cache c = cache; + char *t = 0, *v = 0; + char *ret = NULL; + + if (!token) + return NULL; + if (!cache && blkid_get_cache(&c, NULL) < 0) + return NULL; + + DBG(TAG, ul_debug("looking for %s%s%s %s", token, value ? "=" : "", + value ? value : "", cache ? "in cache" : "from disk")); + + if (!value) { + if (!strchr(token, '=')) { + ret = strdup(token); + goto out; + } + blkid_parse_tag_string(token, &t, &v); + if (!t || !v) + goto out; + token = t; + value = v; + } + + dev = blkid_find_dev_with_tag(c, token, value); + if (!dev) + goto out; + + ret = dev->bid_name ? strdup(dev->bid_name) : NULL; +out: + free(t); + free(v); + if (!cache) + blkid_put_cache(c); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *value; + blkid_cache cache; + + blkid_init_debug(BLKID_DEBUG_ALL); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage:\t%s tagname=value\n" + "\t%s tagname devname\n" + "Find which device holds a given token or\n" + "Find what the value of a tag is in a device\n", + argv[0], argv[0]); + exit(1); + } + if (blkid_get_cache(&cache, "/dev/null") < 0) { + fprintf(stderr, "Couldn't get blkid cache\n"); + exit(1); + } + + if (argv[2]) { + value = blkid_get_tag_value(cache, argv[1], argv[2]); + printf("%s has tag %s=%s\n", argv[2], argv[1], + value ? value : "<missing>"); + } else { + value = blkid_get_devname(cache, argv[1], NULL); + printf("%s has tag %s\n", value ? value : "<none>", argv[1]); + } + blkid_put_cache(cache); + return value ? 0 : 1; +} +#endif diff --git a/libblkid/src/save.c b/libblkid/src/save.c new file mode 100644 index 000000000..c2a975348 --- /dev/null +++ b/libblkid/src/save.c @@ -0,0 +1,244 @@ +/* + * save.c - write the cache struct to disk + * + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "closestream.h" + +#include "blkidP.h" + + +static void save_quoted(const char *data, FILE *file) +{ + const char *p; + + fputc('"', file); + for (p = data; p && *p; p++) { + if ((unsigned char) *p == 0x22 || /* " */ + (unsigned char) *p == 0x5c) /* \ */ + fputc('\\', file); + + fputc(*p, file); + } + fputc('"', file); +} +static int save_dev(blkid_dev dev, FILE *file) +{ + struct list_head *p; + + if (!dev || dev->bid_name[0] != '/') + return 0; + + DBG(SAVE, ul_debug("device %s, type %s", dev->bid_name, dev->bid_type ? + dev->bid_type : "(null)")); + + fprintf(file, "<device DEVNO=\"0x%04lx\" TIME=\"%ld.%ld\"", + (unsigned long) dev->bid_devno, + (long) dev->bid_time, + (long) dev->bid_utime); + + if (dev->bid_pri) + fprintf(file, " PRI=\"%d\"", dev->bid_pri); + + list_for_each(p, &dev->bid_tags) { + blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags); + + fputc(' ', file); /* space between tags */ + fputs(tag->bit_name, file); /* tag NAME */ + fputc('=', file); /* separator between NAME and VALUE */ + save_quoted(tag->bit_val, file); /* tag "VALUE" */ + } + fprintf(file, ">%s</device>\n", dev->bid_name); + + return 0; +} + +/* + * Write out the cache struct to the cache file on disk. + */ +int blkid_flush_cache(blkid_cache cache) +{ + struct list_head *p; + char *tmp = NULL; + char *opened = NULL; + char *filename; + FILE *file = NULL; + int fd, ret = 0; + struct stat st; + + if (!cache) + return -BLKID_ERR_PARAM; + + if (list_empty(&cache->bic_devs) || + !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) { + DBG(SAVE, ul_debug("skipping cache file write")); + return 0; + } + + filename = cache->bic_filename ? cache->bic_filename : + blkid_get_cache_filename(NULL); + if (!filename) + return -BLKID_ERR_PARAM; + + if (strncmp(filename, + BLKID_RUNTIME_DIR "/", sizeof(BLKID_RUNTIME_DIR)) == 0) { + + /* default destination, create the directory if necessary */ + if (stat(BLKID_RUNTIME_DIR, &st) + && errno == ENOENT + && mkdir(BLKID_RUNTIME_DIR, S_IWUSR| + S_IRUSR|S_IRGRP|S_IROTH| + S_IXUSR|S_IXGRP|S_IXOTH) != 0 + && errno != EEXIST) { + DBG(SAVE, ul_debug("can't create %s directory for cache file", + BLKID_RUNTIME_DIR)); + return 0; + } + } + + /* If we can't write to the cache file, then don't even try */ + if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) || + (ret == 0 && access(filename, W_OK) < 0)) { + DBG(SAVE, ul_debug("can't write to cache file %s", filename)); + return 0; + } + + /* + * Try and create a temporary file in the same directory so + * that in case of error we don't overwrite the cache file. + * If the cache file doesn't yet exist, it isn't a regular + * file (e.g. /dev/null or a socket), or we couldn't create + * a temporary file then we open it directly. + */ + if (ret == 0 && S_ISREG(st.st_mode)) { + tmp = malloc(strlen(filename) + 8); + if (tmp) { + sprintf(tmp, "%s-XXXXXX", filename); + fd = mkstemp(tmp); + if (fd >= 0) { + if (fchmod(fd, 0644) != 0) + DBG(SAVE, ul_debug("%s: fchmod failed", filename)); + else if ((file = fdopen(fd, "w" UL_CLOEXECSTR))) + opened = tmp; + if (!file) + close(fd); + } + } + } + + if (!file) { + file = fopen(filename, "w" UL_CLOEXECSTR); + opened = filename; + } + + DBG(SAVE, ul_debug("writing cache file %s (really %s)", + filename, opened)); + + if (!file) { + ret = errno; + goto errout; + } + + list_for_each(p, &cache->bic_devs) { + blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs); + if (!dev->bid_type || (dev->bid_flags & BLKID_BID_FL_REMOVABLE)) + continue; + if ((ret = save_dev(dev, file)) < 0) + break; + } + + if (ret >= 0) { + cache->bic_flags &= ~BLKID_BIC_FL_CHANGED; + ret = 1; + } + + if (close_stream(file) != 0) + DBG(SAVE, ul_debug("write failed: %s", filename)); + + if (opened != filename) { + if (ret < 0) { + unlink(opened); + DBG(SAVE, ul_debug("unlinked temp cache %s", opened)); + } else { + char *backup; + + backup = malloc(strlen(filename) + 5); + if (backup) { + sprintf(backup, "%s.old", filename); + unlink(backup); + if (link(filename, backup)) { + DBG(SAVE, ul_debug("can't link %s to %s", + filename, backup)); + } + free(backup); + } + if (rename(opened, filename)) { + ret = errno; + DBG(SAVE, ul_debug("can't rename %s to %s", + opened, filename)); + } else { + DBG(SAVE, ul_debug("moved temp cache %s", opened)); + } + } + } + +errout: + free(tmp); + if (filename != cache->bic_filename) + free(filename); + return ret; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_cache cache = NULL; + int ret; + + blkid_init_debug(BLKID_DEBUG_ALL); + if (argc > 2) { + fprintf(stderr, "Usage: %s [filename]\n" + "Test loading/saving a cache (filename)\n", argv[0]); + exit(1); + } + + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + if ((ret = blkid_probe_all(cache)) < 0) { + fprintf(stderr, "error (%d) probing devices\n", ret); + exit(1); + } + cache->bic_filename = strdup(argv[1]); + + if ((ret = blkid_flush_cache(cache)) < 0) { + fprintf(stderr, "error (%d) saving cache\n", ret); + exit(1); + } + + blkid_put_cache(cache); + + return ret; +} +#endif diff --git a/libblkid/src/strutils.h b/libblkid/src/strutils.h new file mode 100644 index 000000000..4d8463a6d --- /dev/null +++ b/libblkid/src/strutils.h @@ -0,0 +1,204 @@ +#ifndef UTIL_LINUX_STRUTILS +#define UTIL_LINUX_STRUTILS + +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <ctype.h> + +/* default strtoxx_or_err() exit code */ +#ifndef STRTOXX_EXIT_CODE +# define STRTOXX_EXIT_CODE EXIT_FAILURE +#endif + + +extern int parse_size(const char *str, uintmax_t *res, int *power); +extern int strtosize(const char *str, uintmax_t *res); +extern uintmax_t strtosize_or_err(const char *str, const char *errmesg); + +extern int16_t strtos16_or_err(const char *str, const char *errmesg); +extern uint16_t strtou16_or_err(const char *str, const char *errmesg); + +extern int32_t strtos32_or_err(const char *str, const char *errmesg); +extern uint32_t strtou32_or_err(const char *str, const char *errmesg); + +extern int64_t strtos64_or_err(const char *str, const char *errmesg); +extern uint64_t strtou64_or_err(const char *str, const char *errmesg); + +extern double strtod_or_err(const char *str, const char *errmesg); + +extern long strtol_or_err(const char *str, const char *errmesg); +extern unsigned long strtoul_or_err(const char *str, const char *errmesg); + +extern void strtotimeval_or_err(const char *str, struct timeval *tv, + const char *errmesg); + +extern int isdigit_string(const char *str); + +#ifndef HAVE_MEMPCPY +extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n); +#endif +#ifndef HAVE_STRNLEN +extern size_t strnlen(const char *s, size_t maxlen); +#endif +#ifndef HAVE_STRNDUP +extern char *strndup(const char *s, size_t n); +#endif +#ifndef HAVE_STRNCHR +extern char *strnchr(const char *s, size_t maxlen, int c); +#endif + +/* caller guarantees n > 0 */ +static inline void xstrncpy(char *dest, const char *src, size_t n) +{ + strncpy(dest, src, n-1); + dest[n-1] = 0; +} + +static inline char *strdup_to_offset(void *stru, size_t offset, const char *str) +{ + char *n = NULL; + char **o = (char **) ((char *) stru + offset); + + if (str) { + n = strdup(str); + if (!n) + return NULL; + } + + free(*o); + *o = n; + return n; +} + +#define strdup_to_struct_member(_s, _m, _str) \ + strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str) + +extern void strmode(mode_t mode, char *str); + +/* Options for size_to_human_string() */ +enum +{ + SIZE_SUFFIX_1LETTER = 0, + SIZE_SUFFIX_3LETTER = 1, + SIZE_SUFFIX_SPACE = 2 +}; + +extern char *size_to_human_string(int options, uint64_t bytes); + +extern int string_to_idarray(const char *list, int ary[], size_t arysz, + int (name2id)(const char *, size_t)); +extern int string_add_to_idarray(const char *list, int ary[], + size_t arysz, int *ary_pos, + int (name2id)(const char *, size_t)); + +extern int string_to_bitarray(const char *list, char *ary, + int (*name2bit)(const char *, size_t)); + +extern int string_to_bitmask(const char *list, + unsigned long *mask, + long (*name2flag)(const char *, size_t)); +extern int parse_range(const char *str, int *lower, int *upper, int def); + +extern int streq_except_trailing_slash(const char *s1, const char *s2); + +/* + * Match string beginning. + */ +static inline const char *startswith(const char *s, const char *prefix) +{ + size_t sz = prefix ? strlen(prefix) : 0; + + if (s && sz && strncmp(s, prefix, sz) == 0) + return s + sz; + return NULL; +} + +/* + * Case insensitive match string beginning. + */ +static inline const char *startswith_no_case(const char *s, const char *prefix) +{ + size_t sz = prefix ? strlen(prefix) : 0; + + if (s && sz && strncasecmp(s, prefix, sz) == 0) + return s + sz; + return NULL; +} + +/* + * Match string ending. + */ +static inline const char *endswith(const char *s, const char *postfix) +{ + size_t sl = s ? strlen(s) : 0; + size_t pl = postfix ? strlen(postfix) : 0; + + if (pl == 0) + return (char *)s + sl; + if (sl < pl) + return NULL; + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + return (char *)s + sl - pl; +} + +/* + * Skip leading white space. + */ +static inline const char *skip_space(const char *p) +{ + while (isspace(*p)) + ++p; + return p; +} + +static inline const char *skip_blank(const char *p) +{ + while (isblank(*p)) + ++p; + return p; +} + + +/* Removes whitespace from the right-hand side of a string (trailing + * whitespace). + * + * Returns size of the new string (without \0). + */ +static inline size_t rtrim_whitespace(unsigned char *str) +{ + size_t i = strlen((char *) str); + + while (i) { + i--; + if (!isspace(str[i])) { + i++; + break; + } + } + str[i] = '\0'; + return i; +} + +/* Removes whitespace from the left-hand side of a string. + * + * Returns size of the new string (without \0). + */ +static inline size_t ltrim_whitespace(unsigned char *str) +{ + size_t len; + unsigned char *p; + + for (p = str; p && isspace(*p); p++); + + len = strlen((char *) p); + + if (len && p > str) + memmove(str, p, len + 1); + + return len; +} + +#endif diff --git a/libblkid/src/superblocks/adaptec_raid.c b/libblkid/src/superblocks/adaptec_raid.c new file mode 100644 index 000000000..65fd5b8b4 --- /dev/null +++ b/libblkid/src/superblocks/adaptec_raid.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct adaptec_metadata { + + uint32_t b0idcode; + uint8_t lunsave[8]; + uint16_t sdtype; + uint16_t ssavecyl; + uint8_t ssavehed; + uint8_t ssavesec; + uint8_t sb0flags; + uint8_t jbodEnable; + uint8_t lundsave; + uint8_t svpdirty; + uint16_t biosInfo; + uint16_t svwbskip; + uint16_t svwbcln; + uint16_t svwbmax; + uint16_t res3; + uint16_t svwbmin; + uint16_t res4; + uint16_t svrcacth; + uint16_t svwcacth; + uint16_t svwbdly; + uint8_t svsdtime; + uint8_t res5; + uint16_t firmval; + uint16_t firmbln; + uint32_t firmblk; + uint32_t fstrsvrb; + uint16_t svBlockStorageTid; + uint16_t svtid; + uint8_t svseccfl; + uint8_t res6; + uint8_t svhbanum; + uint8_t resver; + uint32_t drivemagic; + uint8_t reserved[20]; + uint8_t testnum; + uint8_t testflags; + uint16_t maxErrorCount; + uint32_t count; + uint32_t startTime; + uint32_t interval; + uint8_t tstxt0; + uint8_t tstxt1; + uint8_t serNum[32]; + uint8_t res8[102]; + uint32_t fwTestMagic; + uint32_t fwTestSeqNum; + uint8_t fwTestRes[8]; + uint32_t smagic; + uint32_t raidtbl; + uint16_t raidline; + uint8_t res9[0xF6]; +} __attribute__((packed)); + +#define AD_SIGNATURE 0x4450544D /* "DPTM" */ +#define AD_MAGIC 0x37FC4D1E + +static int probe_adraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct adaptec_metadata *ad; + + if (pr->size < 0x10000) + return BLKID_PROBE_NONE; + + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return BLKID_PROBE_NONE; + + off = ((pr->size / 0x200)-1) * 0x200; + ad = (struct adaptec_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct adaptec_metadata)); + if (!ad) + return errno ? -errno : BLKID_PROBE_NONE;; + + if (ad->smagic != be32_to_cpu(AD_SIGNATURE)) + return BLKID_PROBE_NONE; + if (ad->b0idcode != be32_to_cpu(AD_MAGIC)) + return BLKID_PROBE_NONE; + if (blkid_probe_sprintf_version(pr, "%u", ad->resver) != 0) + return BLKID_PROBE_NONE; + if (blkid_probe_set_magic(pr, off, sizeof(ad->b0idcode), + (unsigned char *) &ad->b0idcode)) + return BLKID_PROBE_NONE; + + return BLKID_PROBE_OK; +} + +const struct blkid_idinfo adraid_idinfo = { + .name = "adaptec_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_adraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c new file mode 100644 index 000000000..b3e397ba1 --- /dev/null +++ b/libblkid/src/superblocks/bcache.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2013 Rolf Fokkens <rolf@fokkens.nl> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * Based on code fragments from bcache-tools by Kent Overstreet: + * http://evilpiepirate.org/git/bcache-tools.git + */ + +#include <stddef.h> +#include <stdio.h> + +#include "superblocks.h" +#include "crc64.h" + +#define SB_LABEL_SIZE 32 +#define SB_JOURNAL_BUCKETS 256U + +#define node(i, j) ((i)->d + (j)) +#define end(i) node(i, (i)->keys) + +static const char bcache_magic[] = { + 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, + 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 +}; + +struct bcache_super_block { + uint64_t csum; + uint64_t offset; /* sector where this sb was written */ + uint64_t version; + + uint8_t magic[16]; + + uint8_t uuid[16]; + union { + uint8_t set_uuid[16]; + uint64_t set_magic; + }; + uint8_t label[SB_LABEL_SIZE]; + + uint64_t flags; + uint64_t seq; + uint64_t pad[8]; + + union { + struct { + /* Cache devices */ + uint64_t nbuckets; /* device size */ + + uint16_t block_size; /* sectors */ + uint16_t bucket_size; /* sectors */ + + uint16_t nr_in_set; + uint16_t nr_this_dev; + }; + struct { + /* Backing devices */ + uint64_t data_offset; + + /* + * block_size from the cache device section is still used by + * backing devices, so don't add anything here until we fix + * things to not need it for backing devices anymore + */ + }; + }; + + uint32_t last_mount; /* time_t */ + + uint16_t first_bucket; + union { + uint16_t njournal_buckets; + uint16_t keys; + }; + uint64_t d[SB_JOURNAL_BUCKETS]; /* journal buckets */ +}; + +/* magic string */ +#define BCACHE_SB_MAGIC bcache_magic +/* magic string len */ +#define BCACHE_SB_MAGIC_LEN sizeof (bcache_magic) +/* super block offset */ +#define BCACHE_SB_OFF 0x1000 +/* supper block offset in kB */ +#define BCACHE_SB_KBOFF (BCACHE_SB_OFF >> 10) +/* magic string offset within super block */ +#define BCACHE_SB_MAGIC_OFF offsetof (struct bcache_super_block, magic) + +static uint64_t bcache_crc64(struct bcache_super_block *bcs) +{ + unsigned char *data = (unsigned char *) bcs; + size_t sz; + + data += 8; /* skip csum field */ + sz = (unsigned char *) end(bcs) - data; + + return crc64(0xFFFFFFFFFFFFFFFFULL, data, sz) ^ 0xFFFFFFFFFFFFFFFFULL; +} + +static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag) +{ + struct bcache_super_block *bcs; + + bcs = blkid_probe_get_sb(pr, mag, struct bcache_super_block); + if (!bcs) + return errno ? -errno : BLKID_PROBE_NONE; + + if (le64_to_cpu(bcs->offset) != BCACHE_SB_OFF / 512) + return BLKID_PROBE_NONE; + if (!blkid_probe_verify_csum(pr, bcache_crc64(bcs), le64_to_cpu(bcs->csum))) + return BLKID_PROBE_NONE; + + if (blkid_probe_set_uuid(pr, bcs->uuid) < 0) + return BLKID_PROBE_NONE; + + return BLKID_PROBE_OK; +}; + +const struct blkid_idinfo bcache_idinfo = +{ + .name = "bcache", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_bcache, + .minsz = 8192, + .magics = + { + { .magic = BCACHE_SB_MAGIC + , .len = BCACHE_SB_MAGIC_LEN + , .kboff = BCACHE_SB_KBOFF + , .sboff = BCACHE_SB_MAGIC_OFF + } , + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/befs.c b/libblkid/src/superblocks/befs.c new file mode 100644 index 000000000..e4453bc17 --- /dev/null +++ b/libblkid/src/superblocks/befs.c @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2010 Jeroen Oortwijn <oortwijn@gmail.com> + * + * Partly based on the Haiku BFS driver by + * Axel Dörfler <axeld@pinc-software.de> + * + * Also inspired by the Linux BeFS driver by + * Will Dyson <will_dyson@pobox.com>, et al. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "superblocks.h" + +#define B_OS_NAME_LENGTH 0x20 +#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ +#define SUPER_BLOCK_MAGIC2 0xdd121031 +#define SUPER_BLOCK_MAGIC3 0x15b6830e +#define SUPER_BLOCK_FS_ENDIAN 0x42494745 /* BIGE */ +#define INODE_MAGIC1 0x3bbe0ad9 +#define BPLUSTREE_MAGIC 0x69f6c2e8 +#define BPLUSTREE_NULL -1LL +#define NUM_DIRECT_BLOCKS 12 +#define B_UINT64_TYPE 0x554c4c47 /* ULLG */ +#define KEY_NAME "be:volume_id" +#define KEY_SIZE 8 + +#define FS16_TO_CPU(value, fs_is_le) (fs_is_le ? le16_to_cpu(value) \ + : be16_to_cpu(value)) +#define FS32_TO_CPU(value, fs_is_le) (fs_is_le ? le32_to_cpu(value) \ + : be32_to_cpu(value)) +#define FS64_TO_CPU(value, fs_is_le) (fs_is_le ? le64_to_cpu(value) \ + : be64_to_cpu(value)) + +typedef struct block_run { + int32_t allocation_group; + uint16_t start; + uint16_t len; +} __attribute__((packed)) block_run, inode_addr; + +struct befs_super_block { + char name[B_OS_NAME_LENGTH]; + int32_t magic1; + int32_t fs_byte_order; + uint32_t block_size; + uint32_t block_shift; + int64_t num_blocks; + int64_t used_blocks; + int32_t inode_size; + int32_t magic2; + int32_t blocks_per_ag; + int32_t ag_shift; + int32_t num_ags; + int32_t flags; + block_run log_blocks; + int64_t log_start; + int64_t log_end; + int32_t magic3; + inode_addr root_dir; + inode_addr indices; + int32_t pad[8]; +} __attribute__((packed)); + +typedef struct data_stream { + block_run direct[NUM_DIRECT_BLOCKS]; + int64_t max_direct_range; + block_run indirect; + int64_t max_indirect_range; + block_run double_indirect; + int64_t max_double_indirect_range; + int64_t size; +} __attribute__((packed)) data_stream; + +struct befs_inode { + int32_t magic1; + inode_addr inode_num; + int32_t uid; + int32_t gid; + int32_t mode; + int32_t flags; + int64_t create_time; + int64_t last_modified_time; + inode_addr parent; + inode_addr attributes; + uint32_t type; + int32_t inode_size; + uint32_t etc; + data_stream data; + int32_t pad[4]; + int32_t small_data[0]; +} __attribute__((packed)); + +struct small_data { + uint32_t type; + uint16_t name_size; + uint16_t data_size; + char name[0]; +} __attribute__((packed)); + +struct bplustree_header { + uint32_t magic; + uint32_t node_size; + uint32_t max_number_of_levels; + uint32_t data_type; + int64_t root_node_pointer; + int64_t free_node_pointer; + int64_t maximum_size; +} __attribute__((packed)); + +struct bplustree_node { + int64_t left_link; + int64_t right_link; + int64_t overflow_link; + uint16_t all_key_count; + uint16_t all_key_length; + char name[0]; +} __attribute__((packed)); + +static unsigned char *get_block_run(blkid_probe pr, const struct befs_super_block *bs, + const struct block_run *br, int fs_le) +{ + return blkid_probe_get_buffer(pr, + ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) + << FS32_TO_CPU(bs->ag_shift, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)), + (blkid_loff_t) FS16_TO_CPU(br->len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)); +} + +static unsigned char *get_custom_block_run(blkid_probe pr, + const struct befs_super_block *bs, + const struct block_run *br, + int64_t offset, uint32_t length, int fs_le) +{ + if (offset + length > (int64_t) FS16_TO_CPU(br->len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + return NULL; + + return blkid_probe_get_buffer(pr, + ((blkid_loff_t) FS32_TO_CPU(br->allocation_group, fs_le) + << FS32_TO_CPU(bs->ag_shift, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + + ((blkid_loff_t) FS16_TO_CPU(br->start, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + + offset, + length); +} + +static unsigned char *get_tree_node(blkid_probe pr, const struct befs_super_block *bs, + const struct data_stream *ds, + int64_t start, uint32_t length, int fs_le) +{ + if (start < (int64_t) FS64_TO_CPU(ds->max_direct_range, fs_le)) { + int64_t br_len; + size_t i; + + for (i = 0; i < NUM_DIRECT_BLOCKS; i++) { + br_len = (int64_t) FS16_TO_CPU(ds->direct[i].len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le); + if (start < br_len) + return get_custom_block_run(pr, bs, + &ds->direct[i], + start, length, fs_le); + else + start -= br_len; + } + } else if (start < (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le)) { + struct block_run *br; + int64_t max_br, br_len, i; + + start -= FS64_TO_CPU(ds->max_direct_range, fs_le); + max_br = ((int64_t) FS16_TO_CPU(ds->indirect.len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le)) + / sizeof(struct block_run); + + br = (struct block_run *) get_block_run(pr, bs, &ds->indirect, + fs_le); + if (!br) + return NULL; + + for (i = 0; i < max_br; i++) { + br_len = (int64_t) FS16_TO_CPU(br[i].len, fs_le) + << FS32_TO_CPU(bs->block_shift, fs_le); + if (start < br_len) + return get_custom_block_run(pr, bs, &br[i], + start, length, fs_le); + else + start -= br_len; + } + } else if (start < (int64_t) FS64_TO_CPU(ds->max_double_indirect_range, fs_le)) { + struct block_run *br; + int64_t di_br_size, br_per_di_br, di_index, i_index; + + start -= (int64_t) FS64_TO_CPU(ds->max_indirect_range, fs_le); + + di_br_size = (int64_t) FS16_TO_CPU(ds->double_indirect.len, + fs_le) << FS32_TO_CPU(bs->block_shift, fs_le); + if (di_br_size == 0) + return NULL; + + br_per_di_br = di_br_size / sizeof(struct block_run); + if (br_per_di_br == 0) + return NULL; + + di_index = start / (br_per_di_br * di_br_size); + i_index = (start % (br_per_di_br * di_br_size)) / di_br_size; + start = (start % (br_per_di_br * di_br_size)) % di_br_size; + + br = (struct block_run *) get_block_run(pr, bs, + &ds->double_indirect, fs_le); + if (!br) + return NULL; + + br = (struct block_run *) get_block_run(pr, bs, &br[di_index], + fs_le); + if (!br) + return NULL; + + return get_custom_block_run(pr, bs, &br[i_index], start, length, + fs_le); + } + return NULL; +} + +static int32_t compare_keys(const char keys1[], uint16_t keylengths1[], int32_t index, + const char *key2, uint16_t keylength2, int fs_le) +{ + const char *key1; + uint16_t keylength1; + int32_t result; + + key1 = &keys1[index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], + fs_le)]; + keylength1 = FS16_TO_CPU(keylengths1[index], fs_le) + - (index == 0 ? 0 : FS16_TO_CPU(keylengths1[index - 1], + fs_le)); + + result = strncmp(key1, key2, min(keylength1, keylength2)); + + if (result == 0) + return keylength1 - keylength2; + + return result; +} + +static int64_t get_key_value(blkid_probe pr, const struct befs_super_block *bs, + const struct befs_inode *bi, const char *key, int fs_le) +{ + struct bplustree_header *bh; + struct bplustree_node *bn; + uint16_t *keylengths; + int64_t *values; + int64_t node_pointer; + int32_t first, last, mid, cmp; + + errno = 0; + bh = (struct bplustree_header *) get_tree_node(pr, bs, &bi->data, 0, + sizeof(struct bplustree_header), fs_le); + if (!bh) + return errno ? -errno : -ENOENT; + + if ((int32_t) FS32_TO_CPU(bh->magic, fs_le) != BPLUSTREE_MAGIC) + return -ENOENT; + + node_pointer = FS64_TO_CPU(bh->root_node_pointer, fs_le); + + do { + errno = 0; + bn = (struct bplustree_node *) get_tree_node(pr, bs, &bi->data, + node_pointer, FS32_TO_CPU(bh->node_size, fs_le), fs_le); + if (!bn) + return errno ? -errno : -ENOENT; + + keylengths = (uint16_t *) ((uint8_t *) bn + + ((sizeof(struct bplustree_node) + + FS16_TO_CPU(bn->all_key_length, fs_le) + + sizeof(int64_t) - 1) + & ~(sizeof(int64_t) - 1))); + values = (int64_t *) ((uint8_t *) keylengths + + FS16_TO_CPU(bn->all_key_count, fs_le) + * sizeof(uint16_t)); + first = 0; + mid = 0; + last = FS16_TO_CPU(bn->all_key_count, fs_le) - 1; + + cmp = compare_keys(bn->name, keylengths, last, key, strlen(key), + fs_le); + if (cmp == 0) { + if ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) + == BPLUSTREE_NULL) + return FS64_TO_CPU(values[last], fs_le); + else + node_pointer = FS64_TO_CPU(values[last], fs_le); + } else if (cmp < 0) + node_pointer = FS64_TO_CPU(bn->overflow_link, fs_le); + else { + while (first <= last) { + mid = (first + last) / 2; + + cmp = compare_keys(bn->name, keylengths, mid, + key, strlen(key), fs_le); + if (cmp == 0) { + if ((int64_t) FS64_TO_CPU(bn->overflow_link, + fs_le) == BPLUSTREE_NULL) + return FS64_TO_CPU(values[mid], + fs_le); + else + break; + } else if (cmp < 0) + first = mid + 1; + else + last = mid - 1; + } + if (cmp < 0) + node_pointer = FS64_TO_CPU(values[mid + 1], + fs_le); + else + node_pointer = FS64_TO_CPU(values[mid], fs_le); + } + } while ((int64_t) FS64_TO_CPU(bn->overflow_link, fs_le) + != BPLUSTREE_NULL); + return 0; +} + +static int get_uuid(blkid_probe pr, const struct befs_super_block *bs, + uint64_t * const uuid, int fs_le) +{ + struct befs_inode *bi; + struct small_data *sd; + + bi = (struct befs_inode *) get_block_run(pr, bs, &bs->root_dir, fs_le); + if (!bi) + return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) + return BLKID_PROBE_NONE; + + sd = (struct small_data *) bi->small_data; + + do { + if (FS32_TO_CPU(sd->type, fs_le) == B_UINT64_TYPE + && FS16_TO_CPU(sd->name_size, fs_le) == strlen(KEY_NAME) + && FS16_TO_CPU(sd->data_size, fs_le) == KEY_SIZE + && strcmp(sd->name, KEY_NAME) == 0) { + + memcpy(uuid, + sd->name + FS16_TO_CPU(sd->name_size, fs_le) + 3, + sizeof(uint64_t)); + + break; + } else if (FS32_TO_CPU(sd->type, fs_le) == 0 + && FS16_TO_CPU(sd->name_size, fs_le) == 0 + && FS16_TO_CPU(sd->data_size, fs_le) == 0) + break; + + sd = (struct small_data *) ((uint8_t *) sd + + sizeof(struct small_data) + + FS16_TO_CPU(sd->name_size, fs_le) + 3 + + FS16_TO_CPU(sd->data_size, fs_le) + 1); + + } while ((intptr_t) sd < (intptr_t) bi + + (int32_t) FS32_TO_CPU(bi->inode_size, fs_le) + - (int32_t) sizeof(struct small_data)); + if (*uuid == 0 + && (FS32_TO_CPU(bi->attributes.allocation_group, fs_le) != 0 + || FS16_TO_CPU(bi->attributes.start, fs_le) != 0 + || FS16_TO_CPU(bi->attributes.len, fs_le) != 0)) { + int64_t value; + + bi = (struct befs_inode *) get_block_run(pr, bs, + &bi->attributes, fs_le); + if (!bi) + return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) + return BLKID_PROBE_NONE; + + value = get_key_value(pr, bs, bi, KEY_NAME, fs_le); + if (value < 0) + return value == -ENOENT ? BLKID_PROBE_NONE : value; + + else if (value > 0) { + bi = (struct befs_inode *) blkid_probe_get_buffer(pr, + value << FS32_TO_CPU(bs->block_shift, fs_le), + FS32_TO_CPU(bs->block_size, fs_le)); + if (!bi) + return errno ? -errno : BLKID_PROBE_NONE; + + if (FS32_TO_CPU(bi->magic1, fs_le) != INODE_MAGIC1) + return 1; + + if (FS32_TO_CPU(bi->type, fs_le) == B_UINT64_TYPE + && FS64_TO_CPU(bi->data.size, fs_le) == KEY_SIZE + && FS16_TO_CPU(bi->data.direct[0].len, fs_le) + == 1) { + uint64_t *attr_data; + + attr_data = (uint64_t *) get_block_run(pr, bs, + &bi->data.direct[0], fs_le); + if (!attr_data) + return errno ? -errno : BLKID_PROBE_NONE; + + *uuid = *attr_data; + } + } + } + return 0; +} + +static int probe_befs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct befs_super_block *bs; + const char *version = NULL; + uint64_t volume_id = 0; + int fs_le, ret; + + bs = (struct befs_super_block *) blkid_probe_get_buffer(pr, + mag->sboff - B_OS_NAME_LENGTH, + sizeof(struct befs_super_block)); + if (!bs) + return errno ? -errno : BLKID_PROBE_NONE; + + if (le32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 + && le32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 + && le32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 + && le32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { + fs_le = 1; + version = "little-endian"; + } else if (be32_to_cpu(bs->magic1) == SUPER_BLOCK_MAGIC1 + && be32_to_cpu(bs->magic2) == SUPER_BLOCK_MAGIC2 + && be32_to_cpu(bs->magic3) == SUPER_BLOCK_MAGIC3 + && be32_to_cpu(bs->fs_byte_order) == SUPER_BLOCK_FS_ENDIAN) { + fs_le = 0; + version = "big-endian"; + } else + return BLKID_PROBE_NONE; + + ret = get_uuid(pr, bs, &volume_id, fs_le); + + if (ret != 0) + return ret; + + /* + * all checks pass, set LABEL, VERSION and UUID + */ + if (strlen(bs->name)) + blkid_probe_set_label(pr, (unsigned char *) bs->name, + sizeof(bs->name)); + if (version) + blkid_probe_set_version(pr, version); + + if (volume_id) + blkid_probe_sprintf_uuid(pr, (unsigned char *) &volume_id, + sizeof(volume_id), "%016" PRIx64, + FS64_TO_CPU(volume_id, fs_le)); + return BLKID_PROBE_OK; +} + +const struct blkid_idinfo befs_idinfo = +{ + .name = "befs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_befs, + .minsz = 1024 * 1440, + .magics = { + { .magic = "BFS1", .len = 4, .sboff = B_OS_NAME_LENGTH }, + { .magic = "1SFB", .len = 4, .sboff = B_OS_NAME_LENGTH }, + { .magic = "BFS1", .len = 4, .sboff = 0x200 + + B_OS_NAME_LENGTH }, + { .magic = "1SFB", .len = 4, .sboff = 0x200 + + B_OS_NAME_LENGTH }, + { NULL } + } +}; diff --git a/libblkid/bfs.c b/libblkid/src/superblocks/bfs.c index 8a34c583a..8a34c583a 100644 --- a/libblkid/bfs.c +++ b/libblkid/src/superblocks/bfs.c diff --git a/libblkid/src/superblocks/btrfs.c b/libblkid/src/superblocks/btrfs.c new file mode 100644 index 000000000..7ce3dfff8 --- /dev/null +++ b/libblkid/src/superblocks/btrfs.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct btrfs_super_block { + uint8_t csum[32]; + uint8_t fsid[16]; + uint64_t bytenr; + uint64_t flags; + uint8_t magic[8]; + uint64_t generation; + uint64_t root; + uint64_t chunk_root; + uint64_t log_root; + uint64_t log_root_transid; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t root_dir_objectid; + uint64_t num_devices; + uint32_t sectorsize; + uint32_t nodesize; + uint32_t leafsize; + uint32_t stripesize; + uint32_t sys_chunk_array_size; + uint64_t chunk_root_generation; + uint64_t compat_flags; + uint64_t compat_ro_flags; + uint64_t incompat_flags; + uint16_t csum_type; + uint8_t root_level; + uint8_t chunk_root_level; + uint8_t log_root_level; + struct btrfs_dev_item { + uint64_t devid; + uint64_t total_bytes; + uint64_t bytes_used; + uint32_t io_align; + uint32_t io_width; + uint32_t sector_size; + uint64_t type; + uint64_t generation; + uint64_t start_offset; + uint32_t dev_group; + uint8_t seek_speed; + uint8_t bandwidth; + uint8_t uuid[16]; + uint8_t fsid[16]; + } __attribute__ ((__packed__)) dev_item; + uint8_t label[256]; +} __attribute__ ((__packed__)); + +static int probe_btrfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct btrfs_super_block *bfs; + + bfs = blkid_probe_get_sb(pr, mag, struct btrfs_super_block); + if (!bfs) + return errno ? -errno : 1; + + if (*bfs->label) + blkid_probe_set_label(pr, + (unsigned char *) bfs->label, + sizeof(bfs->label)); + + blkid_probe_set_uuid(pr, bfs->fsid); + blkid_probe_set_uuid_as(pr, bfs->dev_item.uuid, "UUID_SUB"); + + return 0; +} + +const struct blkid_idinfo btrfs_idinfo = +{ + .name = "btrfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_btrfs, + .minsz = 1024 * 1024, + .magics = + { + { .magic = "_BHRfS_M", .len = 8, .sboff = 0x40, .kboff = 64 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/cramfs.c b/libblkid/src/superblocks/cramfs.c new file mode 100644 index 000000000..6d01b0baa --- /dev/null +++ b/libblkid/src/superblocks/cramfs.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct cramfs_super +{ + uint8_t magic[4]; + uint32_t size; + uint32_t flags; + uint32_t future; + uint8_t signature[16]; + struct cramfs_info + { + uint32_t crc; + uint32_t edition; + uint32_t blocks; + uint32_t files; + } __attribute__((packed)) info; + uint8_t name[16]; +} __attribute__((packed)); + +static int probe_cramfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct cramfs_super *cs; + + cs = blkid_probe_get_sb(pr, mag, struct cramfs_super); + if (!cs) + return errno ? -errno : 1; + + blkid_probe_set_label(pr, cs->name, sizeof(cs->name)); + return 0; +} + +const struct blkid_idinfo cramfs_idinfo = +{ + .name = "cramfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_cramfs, + .magics = + { + { "\x45\x3d\xcd\x28", 4, 0, 0 }, + { "\x28\xcd\x3d\x45", 4, 0, 0 }, + { NULL } + } +}; + + diff --git a/libblkid/src/superblocks/ddf_raid.c b/libblkid/src/superblocks/ddf_raid.c new file mode 100644 index 000000000..fc2c39d3e --- /dev/null +++ b/libblkid/src/superblocks/ddf_raid.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +/* http://www.snia.org/standards/home */ +#define DDF_GUID_LENGTH 24 +#define DDF_REV_LENGTH 8 +#define DDF_MAGIC 0xDE11DE11 + + +struct ddf_header { + uint32_t signature; + uint32_t crc; + uint8_t guid[DDF_GUID_LENGTH]; + char ddf_rev[8]; /* 01.02.00 */ + uint32_t seq; /* starts at '1' */ + uint32_t timestamp; + uint8_t openflag; + uint8_t foreignflag; + uint8_t enforcegroups; + uint8_t pad0; /* 0xff */ + uint8_t pad1[12]; /* 12 * 0xff */ + /* 64 bytes so far */ + uint8_t header_ext[32]; /* reserved: fill with 0xff */ + uint64_t primary_lba; + uint64_t secondary_lba; + uint8_t type; + uint8_t pad2[3]; /* 0xff */ + uint32_t workspace_len; /* sectors for vendor space - + * at least 32768(sectors) */ + uint64_t workspace_lba; + uint16_t max_pd_entries; /* one of 15, 63, 255, 1023, 4095 */ + uint16_t max_vd_entries; /* 2^(4,6,8,10,12)-1 : i.e. as above */ + uint16_t max_partitions; /* i.e. max num of configuration + record entries per disk */ + uint16_t config_record_len; /* 1 +ROUNDUP(max_primary_element_entries + *12/512) */ + uint16_t max_primary_element_entries; /* 16, 64, 256, 1024, or 4096 */ + uint8_t pad3[54]; /* 0xff */ + /* 192 bytes so far */ + uint32_t controller_section_offset; + uint32_t controller_section_length; + uint32_t phys_section_offset; + uint32_t phys_section_length; + uint32_t virt_section_offset; + uint32_t virt_section_length; + uint32_t config_section_offset; + uint32_t config_section_length; + uint32_t data_section_offset; + uint32_t data_section_length; + uint32_t bbm_section_offset; + uint32_t bbm_section_length; + uint32_t diag_space_offset; + uint32_t diag_space_length; + uint32_t vendor_offset; + uint32_t vendor_length; + /* 256 bytes so far */ + uint8_t pad4[256]; /* 0xff */ +} __attribute__((packed)); + +static int probe_ddf(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + int hdrs[] = { 1, 257 }; + size_t i; + struct ddf_header *ddf = NULL; + char version[DDF_REV_LENGTH + 1]; + uint64_t off, lba; + + if (pr->size < 0x30000) + return 1; + + for (i = 0; i < ARRAY_SIZE(hdrs); i++) { + off = ((pr->size / 0x200) - hdrs[i]) * 0x200; + + ddf = (struct ddf_header *) blkid_probe_get_buffer(pr, + off, + sizeof(struct ddf_header)); + if (!ddf) + return errno ? -errno : 1; + if (ddf->signature == cpu_to_be32(DDF_MAGIC) || + ddf->signature == cpu_to_le32(DDF_MAGIC)) + break; + ddf = NULL; + } + + if (!ddf) + return 1; + + lba = ddf->signature == cpu_to_be32(DDF_MAGIC) ? + be64_to_cpu(ddf->primary_lba) : + le64_to_cpu(ddf->primary_lba); + + if (lba > 0) { + /* check primary header */ + unsigned char *buf; + + buf = blkid_probe_get_buffer(pr, + lba << 9, sizeof(ddf->signature)); + if (!buf) + return errno ? -errno : 1; + + if (memcmp(buf, &ddf->signature, 4) != 0) + return 1; + } + + blkid_probe_strncpy_uuid(pr, ddf->guid, sizeof(ddf->guid)); + + memcpy(version, ddf->ddf_rev, sizeof(ddf->ddf_rev)); + *(version + sizeof(ddf->ddf_rev)) = '\0'; + + if (blkid_probe_set_version(pr, version) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, + sizeof(ddf->signature), + (unsigned char *) &ddf->signature)) + return 1; + return 0; +} + +const struct blkid_idinfo ddfraid_idinfo = { + .name = "ddf_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_ddf, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/drbd.c b/libblkid/src/superblocks/drbd.c new file mode 100644 index 000000000..e88e9f353 --- /dev/null +++ b/libblkid/src/superblocks/drbd.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2009 by Bastian Friedrich <bastian.friedrich@collax.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * defines, structs taken from drbd source; file names represent drbd source + * files. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <inttypes.h> +#include <stddef.h> + +#include "superblocks.h" + +/* + * drbd/linux/drbd.h + */ +#define DRBD_MAGIC 0x83740267 + +/* + * user/drbdmeta.c + * We only support v08 for now + */ +#define DRBD_MD_MAGIC_08 (DRBD_MAGIC+4) +#define DRBD_MD_MAGIC_84_UNCLEAN (DRBD_MAGIC+5) + +/* + * drbd/linux/drbd.h + */ +enum drbd_uuid_index { + UI_CURRENT, + UI_BITMAP, + UI_HISTORY_START, + UI_HISTORY_END, + UI_SIZE, /* nl-packet: number of dirty bits */ + UI_FLAGS, /* nl-packet: flags */ + UI_EXTENDED_SIZE /* Everything. */ +}; + +/* + * user/drbdmeta.c + * Minor modifications wrt. types + */ +struct md_on_disk_08 { + uint64_t la_sect; /* last agreed size. */ + uint64_t uuid[UI_SIZE]; /* UUIDs */ + uint64_t device_uuid; + uint64_t reserved_u64_1; + uint32_t flags; + uint32_t magic; + uint32_t md_size_sect; + int32_t al_offset; /* signed sector offset to this block */ + uint32_t al_nr_extents; /* important for restoring the AL */ + int32_t bm_offset; /* signed sector offset to the bitmap, from here */ + uint32_t bm_bytes_per_bit; + uint32_t reserved_u32[4]; + + char reserved[8 * 512 - (8*(UI_SIZE+3)+4*11)]; +}; + + +static int probe_drbd(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct md_on_disk_08 *md; + off_t off; + + off = pr->size - sizeof(*md); + + /* Small devices cannot be drbd (?) */ + if (pr->size < 0x10000) + return 1; + + md = (struct md_on_disk_08 *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct md_on_disk_08)); + if (!md) + return errno ? -errno : 1; + + if (be32_to_cpu(md->magic) != DRBD_MD_MAGIC_08 && + be32_to_cpu(md->magic) != DRBD_MD_MAGIC_84_UNCLEAN) + return 1; + + /* + * DRBD does not have "real" uuids; the following resembles DRBD's + * notion of uuids (64 bit, see struct above) + */ + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &md->device_uuid, sizeof(md->device_uuid), + "%" PRIx64, be64_to_cpu(md->device_uuid)); + + blkid_probe_set_version(pr, "v08"); + + if (blkid_probe_set_magic(pr, + off + offsetof(struct md_on_disk_08, magic), + sizeof(md->magic), + (unsigned char *) &md->magic)) + return 1; + + return 0; +} + +const struct blkid_idinfo drbd_idinfo = +{ + .name = "drbd", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_drbd, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/superblocks/drbdproxy_datalog.c b/libblkid/src/superblocks/drbdproxy_datalog.c new file mode 100644 index 000000000..af597224f --- /dev/null +++ b/libblkid/src/superblocks/drbdproxy_datalog.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 by Philipp Marek <philipp.marek@linbit.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <inttypes.h> +#include <stddef.h> + +#include "superblocks.h" + + +struct log_header_t { + uint64_t magic; + uint64_t version; + + unsigned char uuid[16]; + + uint64_t flags; +} __attribute__((packed)); + + +static int probe_drbdproxy_datalog(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct log_header_t *lh; + + lh = (struct log_header_t *) blkid_probe_get_buffer(pr, 0, sizeof(*lh)); + if (!lh) + return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, lh->uuid); + blkid_probe_sprintf_version(pr, "v%jd", le64_to_cpu(lh->version)); + + return 0; +} + +const struct blkid_idinfo drbdproxy_datalog_idinfo = +{ + .name = "drbdproxy_datalog", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_drbdproxy_datalog, + .minsz = 16*1024, + .magics = + { + { .magic = "DRBDdlh*", .len = 8, .sboff = 0, .kboff = 0 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/exfat.c b/libblkid/src/superblocks/exfat.c new file mode 100644 index 000000000..b52656036 --- /dev/null +++ b/libblkid/src/superblocks/exfat.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2010 Andrew Nayenko <resver@gmail.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include "superblocks.h" + +struct exfat_super_block { + uint8_t jump[3]; + uint8_t oem_name[8]; + uint8_t __unused1[53]; + uint64_t block_start; + uint64_t block_count; + uint32_t fat_block_start; + uint32_t fat_block_count; + uint32_t cluster_block_start; + uint32_t cluster_count; + uint32_t rootdir_cluster; + uint8_t volume_serial[4]; + struct { + uint8_t minor; + uint8_t major; + } version; + uint16_t volume_state; + uint8_t block_bits; + uint8_t bpc_bits; + uint8_t fat_count; + uint8_t drive_no; + uint8_t allocated_percent; +} __attribute__((__packed__)); + +struct exfat_entry_label { + uint8_t type; + uint8_t length; + uint8_t name[30]; +} __attribute__((__packed__)); + +#define BLOCK_SIZE(sb) (1 << (sb)->block_bits) +#define CLUSTER_SIZE(sb) (BLOCK_SIZE(sb) << (sb)->bpc_bits) +#define EXFAT_FIRST_DATA_CLUSTER 2 +#define EXFAT_LAST_DATA_CLUSTER 0xffffff6 +#define EXFAT_ENTRY_SIZE 32 + +#define EXFAT_ENTRY_EOD 0x00 +#define EXFAT_ENTRY_LABEL 0x83 + +static blkid_loff_t block_to_offset(const struct exfat_super_block *sb, + blkid_loff_t block) +{ + return (blkid_loff_t) block << sb->block_bits; +} + +static blkid_loff_t cluster_to_block(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return le32_to_cpu(sb->cluster_block_start) + + ((blkid_loff_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) + << sb->bpc_bits); +} + +static blkid_loff_t cluster_to_offset(const struct exfat_super_block *sb, + uint32_t cluster) +{ + return block_to_offset(sb, cluster_to_block(sb, cluster)); +} + +static uint32_t next_cluster(blkid_probe pr, + const struct exfat_super_block *sb, uint32_t cluster) +{ + uint32_t *next; + blkid_loff_t fat_offset; + + fat_offset = block_to_offset(sb, le32_to_cpu(sb->fat_block_start)) + + (blkid_loff_t) cluster * sizeof(cluster); + next = (uint32_t *) blkid_probe_get_buffer(pr, fat_offset, + sizeof(uint32_t)); + if (!next) + return 0; + return le32_to_cpu(*next); +} + +static struct exfat_entry_label *find_label(blkid_probe pr, + const struct exfat_super_block *sb) +{ + uint32_t cluster = le32_to_cpu(sb->rootdir_cluster); + blkid_loff_t offset = cluster_to_offset(sb, cluster); + uint8_t *entry; + + for (;;) { + entry = (uint8_t *) blkid_probe_get_buffer(pr, offset, + EXFAT_ENTRY_SIZE); + if (!entry) + return NULL; + if (entry[0] == EXFAT_ENTRY_EOD) + return NULL; + if (entry[0] == EXFAT_ENTRY_LABEL) + return (struct exfat_entry_label *) entry; + offset += EXFAT_ENTRY_SIZE; + if (offset % CLUSTER_SIZE(sb) == 0) { + cluster = next_cluster(pr, sb, cluster); + if (cluster < EXFAT_FIRST_DATA_CLUSTER) + return NULL; + if (cluster > EXFAT_LAST_DATA_CLUSTER) + return NULL; + offset = cluster_to_offset(sb, cluster); + } + } +} + +static int probe_exfat(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct exfat_super_block *sb; + struct exfat_entry_label *label; + + sb = blkid_probe_get_sb(pr, mag, struct exfat_super_block); + if (!sb) + return errno ? -errno : BLKID_PROBE_NONE; + + label = find_label(pr, sb); + if (label) + blkid_probe_set_utf8label(pr, label->name, + min(label->length * 2, 30), BLKID_ENC_UTF16LE); + else if (errno) + return -errno; + + blkid_probe_sprintf_uuid(pr, sb->volume_serial, 4, + "%02hhX%02hhX-%02hhX%02hhX", + sb->volume_serial[3], sb->volume_serial[2], + sb->volume_serial[1], sb->volume_serial[0]); + + blkid_probe_sprintf_version(pr, "%u.%u", + sb->version.major, sb->version.minor); + + return BLKID_PROBE_OK; +} + +const struct blkid_idinfo exfat_idinfo = +{ + .name = "exfat", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_exfat, + .magics = + { + { .magic = "EXFAT ", .len = 8, .sboff = 3 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/ext.c b/libblkid/src/superblocks/ext.c new file mode 100644 index 000000000..5b1d179f3 --- /dev/null +++ b/libblkid/src/superblocks/ext.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> +#ifdef __linux__ +#include <sys/utsname.h> +#endif +#include <time.h> + +#include "superblocks.h" + +struct ext2_super_block { + uint32_t s_inodes_count; + uint32_t s_blocks_count; + uint32_t s_r_blocks_count; + uint32_t s_free_blocks_count; + uint32_t s_free_inodes_count; + uint32_t s_first_data_block; + uint32_t s_log_block_size; + uint32_t s_dummy3[7]; + unsigned char s_magic[2]; + uint16_t s_state; + uint16_t s_errors; + uint16_t s_minor_rev_level; + uint32_t s_lastcheck; + uint32_t s_checkinterval; + uint32_t s_creator_os; + uint32_t s_rev_level; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + uint32_t s_first_ino; + uint16_t s_inode_size; + uint16_t s_block_group_nr; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + unsigned char s_uuid[16]; + char s_volume_name[16]; + char s_last_mounted[64]; + uint32_t s_algorithm_usage_bitmap; + uint8_t s_prealloc_blocks; + uint8_t s_prealloc_dir_blocks; + uint16_t s_reserved_gdt_blocks; + uint8_t s_journal_uuid[16]; + uint32_t s_journal_inum; + uint32_t s_journal_dev; + uint32_t s_last_orphan; + uint32_t s_hash_seed[4]; + uint8_t s_def_hash_version; + uint8_t s_jnl_backup_type; + uint16_t s_reserved_word_pad; + uint32_t s_default_mount_opts; + uint32_t s_first_meta_bg; + uint32_t s_mkfs_time; + uint32_t s_jnl_blocks[17]; + uint32_t s_blocks_count_hi; + uint32_t s_r_blocks_count_hi; + uint32_t s_free_blocks_hi; + uint16_t s_min_extra_isize; + uint16_t s_want_extra_isize; + uint32_t s_flags; + uint16_t s_raid_stride; + uint16_t s_mmp_interval; + uint64_t s_mmp_block; + uint32_t s_raid_stripe_width; + uint32_t s_reserved[163]; +} __attribute__((packed)); + +/* magic string */ +#define EXT_SB_MAGIC "\123\357" +/* supper block offset */ +#define EXT_SB_OFF 0x400 +/* supper block offset in kB */ +#define EXT_SB_KBOFF (EXT_SB_OFF >> 10) +/* magic string offset within super block */ +#define EXT_MAG_OFF 0x38 + + + +/* for s_flags */ +#define EXT2_FLAGS_TEST_FILESYS 0x0004 + +/* for s_feature_compat */ +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 + +/* for s_feature_ro_compat */ +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 + +/* for s_feature_incompat */ +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 + +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP + +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP +#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP + +/* + * Starting in 2.6.29, ext4 can be used to support filesystems + * without a journal. + */ +#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29) + +/* + * reads superblock and returns: + * fc = feature_compat + * fi = feature_incompat + * frc = feature_ro_compat + */ +static struct ext2_super_block *ext_get_super( + blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc) +{ + struct ext2_super_block *es; + + es = (struct ext2_super_block *) + blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200); + if (!es) + return NULL; + if (fc) + *fc = le32_to_cpu(es->s_feature_compat); + if (fi) + *fi = le32_to_cpu(es->s_feature_incompat); + if (frc) + *frc = le32_to_cpu(es->s_feature_ro_compat); + + return es; +} + +static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X", + le32_to_cpu(es->s_feature_compat), + le32_to_cpu(es->s_feature_incompat), + le32_to_cpu(es->s_feature_ro_compat))); + + if (strlen(es->s_volume_name)) + blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name, + sizeof(es->s_volume_name)); + blkid_probe_set_uuid(pr, es->s_uuid); + + if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) + blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL"); + + if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) && + ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ext2", + sizeof("ext2")); + + blkid_probe_sprintf_version(pr, "%u.%u", + le32_to_cpu(es->s_rev_level), + le16_to_cpu(es->s_minor_rev_level)); +} + + +static int probe_jbd(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct ext2_super_block *es; + uint32_t fi; + + es = ext_get_super(pr, NULL, &fi, NULL); + if (!es) + return errno ? -errno : 1; + if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) + return 1; + + ext_get_info(pr, 2, es); + blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID"); + + return 0; +} + +static int probe_ext2(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return errno ? -errno : 1; + + /* Distinguish between ext3 and ext2 */ + if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) + return 1; + + /* Any features which ext2 doesn't understand */ + if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) + return 1; + + ext_get_info(pr, 2, es); + return 0; +} + +static int probe_ext3(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return errno ? -errno : 1; + + /* ext3 requires journal */ + if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) + return 1; + + /* Any features which ext3 doesn't understand */ + if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || + (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return 1; + + ext_get_info(pr, 3, es); + return 0; +} + + +static int probe_ext4dev(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return errno ? -errno : 1; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return 1; + + if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)) + return 1; + + ext_get_info(pr, 4, es); + return 0; +} + +static int probe_ext4(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct ext2_super_block *es; + uint32_t fc, frc, fi; + + es = ext_get_super(pr, &fc, &fi, &frc); + if (!es) + return errno ? -errno : 1; + + /* Distinguish from jbd */ + if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) + return 1; + + /* Ext4 has at least one feature which ext3 doesn't understand */ + if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && + !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) + return 1; + + /* + * If the filesystem is a OK for use by in-development + * filesystem code, and ext4dev is supported or ext4 is not + * supported, then don't call ourselves ext4, so we can redo + * the detection and mark the filesystem as ext4dev. + * + * If the filesystem is marked as in use by production + * filesystem, then it can only be used by ext4 and NOT by + * ext4dev. + */ + if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) + return 1; + + ext_get_info(pr, 4, es); + return 0; +} + +#define BLKID_EXT_MAGICS \ + { \ + { \ + .magic = EXT_SB_MAGIC, \ + .len = sizeof(EXT_SB_MAGIC) - 1, \ + .kboff = EXT_SB_KBOFF, \ + .sboff = EXT_MAG_OFF \ + }, \ + { NULL } \ + } + +const struct blkid_idinfo jbd_idinfo = +{ + .name = "jbd", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_jbd, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext2_idinfo = +{ + .name = "ext2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext2, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext3_idinfo = +{ + .name = "ext3", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext3, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext4_idinfo = +{ + .name = "ext4", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext4, + .magics = BLKID_EXT_MAGICS +}; + +const struct blkid_idinfo ext4dev_idinfo = +{ + .name = "ext4dev", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ext4dev, + .magics = BLKID_EXT_MAGICS +}; + diff --git a/libblkid/src/superblocks/f2fs.c b/libblkid/src/superblocks/f2fs.c new file mode 100644 index 000000000..2bf0f5e98 --- /dev/null +++ b/libblkid/src/superblocks/f2fs.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013 Alejandro Martinez Ruiz <alex@nowcomputing.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License + */ + +#include <stddef.h> +#include <string.h> + +#include "superblocks.h" + +#define F2FS_MAGIC "\x10\x20\xF5\xF2" +#define F2FS_MAGIC_OFF 0 +#define F2FS_UUID_SIZE 16 +#define F2FS_LABEL_SIZE 512 +#define F2FS_SB1_OFF 0x400 +#define F2FS_SB1_KBOFF (F2FS_SB1_OFF >> 10) +#define F2FS_SB2_OFF 0x1400 +#define F2FS_SB2_KBOFF (F2FS_SB2_OFF >> 10) + +struct f2fs_super_block { /* According to version 1.1 */ +/* 0x00 */ uint32_t magic; /* Magic Number */ +/* 0x04 */ uint16_t major_ver; /* Major Version */ +/* 0x06 */ uint16_t minor_ver; /* Minor Version */ +/* 0x08 */ uint32_t log_sectorsize; /* log2 sector size in bytes */ +/* 0x0C */ uint32_t log_sectors_per_block; /* log2 # of sectors per block */ +/* 0x10 */ uint32_t log_blocksize; /* log2 block size in bytes */ +/* 0x14 */ uint32_t log_blocks_per_seg; /* log2 # of blocks per segment */ +/* 0x18 */ uint32_t segs_per_sec; /* # of segments per section */ +/* 0x1C */ uint32_t secs_per_zone; /* # of sections per zone */ +/* 0x20 */ uint32_t checksum_offset; /* checksum offset inside super block */ +/* 0x24 */ uint64_t block_count; /* total # of user blocks */ +/* 0x2C */ uint32_t section_count; /* total # of sections */ +/* 0x30 */ uint32_t segment_count; /* total # of segments */ +/* 0x34 */ uint32_t segment_count_ckpt; /* # of segments for checkpoint */ +/* 0x38 */ uint32_t segment_count_sit; /* # of segments for SIT */ +/* 0x3C */ uint32_t segment_count_nat; /* # of segments for NAT */ +/* 0x40 */ uint32_t segment_count_ssa; /* # of segments for SSA */ +/* 0x44 */ uint32_t segment_count_main; /* # of segments for main area */ +/* 0x48 */ uint32_t segment0_blkaddr; /* start block address of segment 0 */ +/* 0x4C */ uint32_t cp_blkaddr; /* start block address of checkpoint */ +/* 0x50 */ uint32_t sit_blkaddr; /* start block address of SIT */ +/* 0x54 */ uint32_t nat_blkaddr; /* start block address of NAT */ +/* 0x58 */ uint32_t ssa_blkaddr; /* start block address of SSA */ +/* 0x5C */ uint32_t main_blkaddr; /* start block address of main area */ +/* 0x60 */ uint32_t root_ino; /* root inode number */ +/* 0x64 */ uint32_t node_ino; /* node inode number */ +/* 0x68 */ uint32_t meta_ino; /* meta inode number */ +/* 0x6C */ uint8_t uuid[F2FS_UUID_SIZE]; /* 128-bit uuid for volume */ +/* 0x7C */ uint16_t volume_name[F2FS_LABEL_SIZE]; /* volume name */ +#if 0 +/* 0x47C */ uint32_t extension_count; /* # of extensions below */ +/* 0x480 */ uint8_t extension_list[64][8]; /* extension array */ +#endif +} __attribute__((packed)); + +static int probe_f2fs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct f2fs_super_block *sb; + uint16_t major, minor; + + sb = blkid_probe_get_sb(pr, mag, struct f2fs_super_block); + if (!sb) + return errno ? -errno : 1; + + major = le16_to_cpu(sb->major_ver); + minor = le16_to_cpu(sb->minor_ver); + + /* For version 1.0 we cannot know the correct sb structure */ + if (major == 1 && minor == 0) + return 0; + + if (*((unsigned char *) sb->volume_name)) + blkid_probe_set_utf8label(pr, (unsigned char *) sb->volume_name, + sizeof(sb->volume_name), + BLKID_ENC_UTF16LE); + + blkid_probe_set_uuid(pr, sb->uuid); + blkid_probe_sprintf_version(pr, "%u.%u", major, minor); + return 0; +} + +const struct blkid_idinfo f2fs_idinfo = +{ + .name = "f2fs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_f2fs, + .magics = + { + { + .magic = F2FS_MAGIC, + .len = 4, + .kboff = F2FS_SB1_KBOFF, + .sboff = F2FS_MAGIC_OFF + }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/gfs.c b/libblkid/src/superblocks/gfs.c new file mode 100644 index 000000000..1b265581d --- /dev/null +++ b/libblkid/src/superblocks/gfs.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +/* Common gfs/gfs2 constants: */ +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 +/* gfs2 constants: */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +struct gfs2_meta_header { + uint32_t mh_magic; + uint32_t mh_type; + uint64_t __pad0; /* Was generation number in gfs1 */ + uint32_t mh_format; + uint32_t __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + uint64_t no_formal_ino; + uint64_t no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + uint32_t sb_fs_format; + uint32_t sb_multihost_format; + uint32_t __pad0; /* Was superblock flags in gfs1 */ + + uint32_t sb_bsize; + uint32_t sb_bsize_shift; + uint32_t __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + + struct gfs2_inum __pad3; /* Was quota inode in gfs1 */ + struct gfs2_inum __pad4; /* Was licence inode in gfs1 */ + uint8_t sb_uuid[16]; /* The UUID maybe 0 for backwards compat */ +} __attribute__((packed)); + +static int probe_gfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return errno ? -errno : 1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + + blkid_probe_set_uuid(pr, sbd->sb_uuid); + return 0; + } + + return 1; +} + +static int probe_gfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct gfs2_sb *sbd; + + sbd = blkid_probe_get_sb(pr, mag, struct gfs2_sb); + if (!sbd) + return errno ? -errno : 1; + + if (be32_to_cpu(sbd->sb_fs_format) == GFS2_FORMAT_FS && + be32_to_cpu(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) + { + if (*sbd->sb_locktable) + blkid_probe_set_label(pr, + (unsigned char *) sbd->sb_locktable, + sizeof(sbd->sb_locktable)); + blkid_probe_set_uuid(pr, sbd->sb_uuid); + blkid_probe_set_version(pr, "1"); + return 0; + } + return 1; +} + +const struct blkid_idinfo gfs_idinfo = +{ + .name = "gfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs, + .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + +const struct blkid_idinfo gfs2_idinfo = +{ + .name = "gfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_gfs2, + .minsz = 32 * 1024 * 1024, /* minimal size of GFS journal */ + .magics = + { + { .magic = "\x01\x16\x19\x70", .len = 4, .kboff = 64 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/hfs.c b/libblkid/src/superblocks/hfs.c new file mode 100644 index 000000000..fe57241c0 --- /dev/null +++ b/libblkid/src/superblocks/hfs.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "superblocks.h" +#include "md5.h" + +/* HFS / HFS+ */ +struct hfs_finder_info { + uint32_t boot_folder; + uint32_t start_app; + uint32_t open_folder; + uint32_t os9_folder; + uint32_t reserved; + uint32_t osx_folder; + uint8_t id[8]; +} __attribute__((packed)); + +struct hfs_mdb { + uint8_t signature[2]; + uint32_t cr_date; + uint32_t ls_Mod; + uint16_t atrb; + uint16_t nm_fls; + uint16_t vbm_st; + uint16_t alloc_ptr; + uint16_t nm_al_blks; + uint32_t al_blk_size; + uint32_t clp_size; + uint16_t al_bl_st; + uint32_t nxt_cnid; + uint16_t free_bks; + uint8_t label_len; + uint8_t label[27]; + uint32_t vol_bkup; + uint16_t vol_seq_num; + uint32_t wr_cnt; + uint32_t xt_clump_size; + uint32_t ct_clump_size; + uint16_t num_root_dirs; + uint32_t file_count; + uint32_t dir_count; + struct hfs_finder_info finder_info; + uint8_t embed_sig[2]; + uint16_t embed_startblock; + uint16_t embed_blockcount; +} __attribute__((packed)); + + +#define HFS_NODE_LEAF 0xff +#define HFSPLUS_POR_CNID 1 + +struct hfsplus_bnode_descriptor { + uint32_t next; + uint32_t prev; + uint8_t type; + uint8_t height; + uint16_t num_recs; + uint16_t reserved; +} __attribute__((packed)); + +struct hfsplus_bheader_record { + uint16_t depth; + uint32_t root; + uint32_t leaf_count; + uint32_t leaf_head; + uint32_t leaf_tail; + uint16_t node_size; +} __attribute__((packed)); + +struct hfsplus_catalog_key { + uint16_t key_len; + uint32_t parent_id; + uint16_t unicode_len; + uint8_t unicode[255 * 2]; +} __attribute__((packed)); + +struct hfsplus_extent { + uint32_t start_block; + uint32_t block_count; +} __attribute__((packed)); + +#define HFSPLUS_EXTENT_COUNT 8 +struct hfsplus_fork { + uint64_t total_size; + uint32_t clump_size; + uint32_t total_blocks; + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; +} __attribute__((packed)); + +struct hfsplus_vol_header { + uint8_t signature[2]; + uint16_t version; + uint32_t attributes; + uint32_t last_mount_vers; + uint32_t reserved; + uint32_t create_date; + uint32_t modify_date; + uint32_t backup_date; + uint32_t checked_date; + uint32_t file_count; + uint32_t folder_count; + uint32_t blocksize; + uint32_t total_blocks; + uint32_t free_blocks; + uint32_t next_alloc; + uint32_t rsrc_clump_sz; + uint32_t data_clump_sz; + uint32_t next_cnid; + uint32_t write_count; + uint64_t encodings_bmp; + struct hfs_finder_info finder_info; + struct hfsplus_fork alloc_file; + struct hfsplus_fork ext_file; + struct hfsplus_fork cat_file; + struct hfsplus_fork attr_file; + struct hfsplus_fork start_file; +} __attribute__((packed)); + +#define HFSPLUS_SECTOR_SIZE 512 + +static int hfs_set_uuid(blkid_probe pr, unsigned char const *hfs_info, size_t len) +{ + static unsigned char const hash_init[MD5LENGTH] = { + 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6, + 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac + }; + unsigned char uuid[MD5LENGTH]; + struct MD5Context md5c; + + if (memcmp(hfs_info, "\0\0\0\0\0\0\0\0", len) == 0) + return -1; + MD5Init(&md5c); + MD5Update(&md5c, hash_init, MD5LENGTH); + MD5Update(&md5c, hfs_info, len); + MD5Final(uuid, &md5c); + uuid[6] = 0x30 | (uuid[6] & 0x0f); + uuid[8] = 0x80 | (uuid[8] & 0x3f); + return blkid_probe_set_uuid(pr, uuid); +} + +static int probe_hfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hfs_mdb *hfs; + + hfs = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!hfs) + return errno ? -errno : 1; + + if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || + (memcmp(hfs->embed_sig, "HX", 2) == 0)) + return 1; /* Not hfs, but an embedded HFS+ */ + + hfs_set_uuid(pr, hfs->finder_info.id, sizeof(hfs->finder_info.id)); + + blkid_probe_set_label(pr, hfs->label, hfs->label_len); + return 0; +} + +static int probe_hfsplus(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; + struct hfsplus_bnode_descriptor *descr; + struct hfsplus_bheader_record *bnode; + struct hfsplus_catalog_key *key; + struct hfsplus_vol_header *hfsplus; + struct hfs_mdb *sbd; + unsigned int alloc_block_size; + unsigned int alloc_first_block; + unsigned int embed_first_block; + unsigned int off = 0; + unsigned int blocksize; + unsigned int cat_block; + unsigned int ext_block_start; + unsigned int ext_block_count; + unsigned int record_count; + unsigned int leaf_node_head; + unsigned int leaf_node_count; + unsigned int leaf_node_size; + unsigned int leaf_block; + int ext; + uint64_t leaf_off; + unsigned char *buf; + + sbd = blkid_probe_get_sb(pr, mag, struct hfs_mdb); + if (!sbd) + return errno ? -errno : 1; + + /* Check for a HFS+ volume embedded in a HFS volume */ + if (memcmp(sbd->signature, "BD", 2) == 0) { + if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && + (memcmp(sbd->embed_sig, "HX", 2) != 0)) + /* This must be an HFS volume, so fail */ + return 1; + + alloc_block_size = be32_to_cpu(sbd->al_blk_size); + alloc_first_block = be16_to_cpu(sbd->al_bl_st); + embed_first_block = be16_to_cpu(sbd->embed_startblock); + off = (alloc_first_block * 512) + + (embed_first_block * alloc_block_size); + + buf = blkid_probe_get_buffer(pr, + off + (mag->kboff * 1024), + sizeof(struct hfsplus_vol_header)); + hfsplus = (struct hfsplus_vol_header *) buf; + + } else + hfsplus = blkid_probe_get_sb(pr, mag, + struct hfsplus_vol_header); + + if (!hfsplus) + return errno ? -errno : 1; + + if ((memcmp(hfsplus->signature, "H+", 2) != 0) && + (memcmp(hfsplus->signature, "HX", 2) != 0)) + return 1; + + hfs_set_uuid(pr, hfsplus->finder_info.id, sizeof(hfsplus->finder_info.id)); + + blocksize = be32_to_cpu(hfsplus->blocksize); + if (blocksize < HFSPLUS_SECTOR_SIZE) + return 1; + + memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); + cat_block = be32_to_cpu(extents[0].start_block); + + buf = blkid_probe_get_buffer(pr, + off + ((blkid_loff_t) cat_block * blocksize), 0x2000); + if (!buf) + return errno ? -errno : 0; + + bnode = (struct hfsplus_bheader_record *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + leaf_node_head = be32_to_cpu(bnode->leaf_head); + leaf_node_size = be16_to_cpu(bnode->node_size); + leaf_node_count = be32_to_cpu(bnode->leaf_count); + if (leaf_node_count == 0) + return 0; + + leaf_block = (leaf_node_head * leaf_node_size) / blocksize; + + /* get physical location */ + for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { + ext_block_start = be32_to_cpu(extents[ext].start_block); + ext_block_count = be32_to_cpu(extents[ext].block_count); + if (ext_block_count == 0) + return 0; + + /* this is our extent */ + if (leaf_block < ext_block_count) + break; + + leaf_block -= ext_block_count; + } + if (ext == HFSPLUS_EXTENT_COUNT) + return 0; + + leaf_off = (ext_block_start + leaf_block) * blocksize; + + buf = blkid_probe_get_buffer(pr, + (blkid_loff_t) off + leaf_off, + leaf_node_size); + if (!buf) + return errno ? -errno : 0; + + descr = (struct hfsplus_bnode_descriptor *) buf; + record_count = be16_to_cpu(descr->num_recs); + if (record_count == 0) + return 0; + + if (descr->type != HFS_NODE_LEAF) + return 0; + + key = (struct hfsplus_catalog_key *) + &buf[sizeof(struct hfsplus_bnode_descriptor)]; + + if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID) + return 0; + + blkid_probe_set_utf8label(pr, key->unicode, + be16_to_cpu(key->unicode_len) * 2, + BLKID_ENC_UTF16BE); + return 0; +} + +const struct blkid_idinfo hfs_idinfo = +{ + .name = "hfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hfs, + .flags = BLKID_IDINFO_TOLERANT, + .magics = + { + { .magic = "BD", .len = 2, .kboff = 1 }, + { NULL } + } +}; + +const struct blkid_idinfo hfsplus_idinfo = +{ + .name = "hfsplus", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hfsplus, + .magics = + { + { .magic = "BD", .len = 2, .kboff = 1 }, + { .magic = "H+", .len = 2, .kboff = 1 }, + { .magic = "HX", .len = 2, .kboff = 1 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/highpoint_raid.c b/libblkid/src/superblocks/highpoint_raid.c new file mode 100644 index 000000000..ad3b538cd --- /dev/null +++ b/libblkid/src/superblocks/highpoint_raid.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct hpt45x_metadata { + uint32_t magic; +}; + +#define HPT45X_MAGIC_OK 0x5a7816f3 +#define HPT45X_MAGIC_BAD 0x5a7816fd + +static int probe_highpoint45x(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct hpt45x_metadata *hpt; + uint64_t off; + uint32_t magic; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 11) * 0x200; + hpt = (struct hpt45x_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct hpt45x_metadata)); + if (!hpt) + return errno ? -errno : 1; + magic = le32_to_cpu(hpt->magic); + if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(hpt->magic), + (unsigned char *) &hpt->magic)) + return 1; + return 0; +} + +static int probe_highpoint37x(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + return 0; +} + + +const struct blkid_idinfo highpoint45x_idinfo = { + .name = "hpt45x_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_highpoint45x, + .magics = BLKID_NONE_MAGIC +}; + +const struct blkid_idinfo highpoint37x_idinfo = { + .name = "hpt37x_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_highpoint37x, + .magics = { + /* + * Superblok offset: 4608 bytes (9 sectors) + * Magic string offset within superblock: 32 bytes + * + * kboff = (4608 + 32) / 1024 + * sboff = (4608 + 32) % kboff + */ + { .magic = "\xf0\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 }, + { .magic = "\xfd\x16\x78\x5a", .len = 4, .kboff = 4, .sboff = 544 }, + { NULL } + } +}; + + diff --git a/libblkid/src/superblocks/hpfs.c b/libblkid/src/superblocks/hpfs.c new file mode 100644 index 000000000..0565d370c --- /dev/null +++ b/libblkid/src/superblocks/hpfs.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct hpfs_boot_block +{ + uint8_t jmp[3]; + uint8_t oem_id[8]; + uint8_t bytes_per_sector[2]; + uint8_t sectors_per_cluster; + uint8_t n_reserved_sectors[2]; + uint8_t n_fats; + uint8_t n_rootdir_entries[2]; + uint8_t n_sectors_s[2]; + uint8_t media_byte; + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads_per_cyl; + uint32_t n_hidden_sectors; + uint32_t n_sectors_l; + uint8_t drive_number; + uint8_t mbz; + uint8_t sig_28h; + uint8_t vol_serno[4]; + uint8_t vol_label[11]; + uint8_t sig_hpfs[8]; + uint8_t pad[448]; + uint8_t magic[2]; +} __attribute__((packed)); + +struct hpfs_super_block +{ + uint8_t magic[4]; + uint8_t magic1[4]; + uint8_t version; +} __attribute__((packed)); + +struct hpfs_spare_super +{ + uint8_t magic[4]; + uint8_t magic1[4]; +} __attribute__((packed)); + + +#define HPFS_SB_OFFSET 0x2000 +#define HPFS_SBSPARE_OFFSET 0x2200 + +static int probe_hpfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct hpfs_super_block *hs; + struct hpfs_spare_super *hss; + struct hpfs_boot_block *hbb; + uint8_t version; + + /* super block */ + hs = blkid_probe_get_sb(pr, mag, struct hpfs_super_block); + if (!hs) + return errno ? -errno : 1; + version = hs->version; + + /* spare super block */ + hss = (struct hpfs_spare_super *) + blkid_probe_get_buffer(pr, + HPFS_SBSPARE_OFFSET, + sizeof(struct hpfs_spare_super)); + if (!hss) + return errno ? -errno : 1; + if (memcmp(hss->magic, "\x49\x18\x91\xf9", 4) != 0) + return 1; + + /* boot block (with UUID and LABEL) */ + hbb = (struct hpfs_boot_block *) + blkid_probe_get_buffer(pr, + 0, + sizeof(struct hpfs_boot_block)); + if (!hbb) + return errno ? -errno : 1; + if (memcmp(hbb->magic, "\x55\xaa", 2) == 0 && + memcmp(hbb->sig_hpfs, "HPFS", 4) == 0 && + hbb->sig_28h == 0x28) { + blkid_probe_set_label(pr, hbb->vol_label, sizeof(hbb->vol_label)); + blkid_probe_sprintf_uuid(pr, + hbb->vol_serno, sizeof(hbb->vol_serno), + "%02X%02X-%02X%02X", + hbb->vol_serno[3], hbb->vol_serno[2], + hbb->vol_serno[1], hbb->vol_serno[0]); + } + blkid_probe_sprintf_version(pr, "%u", version); + + return 0; +} + +const struct blkid_idinfo hpfs_idinfo = +{ + .name = "hpfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_hpfs, + .magics = + { + { + .magic = "\x49\xe8\x95\xf9", + .len = 4, + .kboff = (HPFS_SB_OFFSET >> 10) + }, + { NULL } + } +}; + + diff --git a/libblkid/src/superblocks/iso9660.c b/libblkid/src/superblocks/iso9660.c new file mode 100644 index 000000000..d099467a2 --- /dev/null +++ b/libblkid/src/superblocks/iso9660.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired also by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <ctype.h> + +#include "superblocks.h" + +struct iso9660_date { + unsigned char year[4]; + unsigned char month[2]; + unsigned char day[2]; + unsigned char hour[2]; + unsigned char minute[2]; + unsigned char second[2]; + unsigned char hundredth[2]; + unsigned char offset; +} __attribute__ ((packed)); + +/* PVD - Primary volume descriptor */ +struct iso_volume_descriptor { + unsigned char vd_type; + unsigned char vd_id[5]; + unsigned char vd_version; + unsigned char flags; + unsigned char system_id[32]; + unsigned char volume_id[32]; + unsigned char unused[8]; + unsigned char space_size[8]; + unsigned char escape_sequences[8]; + unsigned char unused1[222]; + unsigned char publisher_id[128]; + unsigned char unused2[128]; + unsigned char application_id[128]; + unsigned char unused3[111]; + struct iso9660_date created; + struct iso9660_date modified; +} __attribute__((packed)); + +/* Boot Record */ +struct boot_record { + unsigned char vd_type; + unsigned char vd_id[5]; + unsigned char vd_version; + unsigned char boot_system_id[32]; + unsigned char boot_id[32]; + unsigned char unused[1]; +} __attribute__((packed)); + +#define ISO_SUPERBLOCK_OFFSET 0x8000 +#define ISO_SECTOR_SIZE 0x800 +#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE) +#define ISO_VD_BOOT_RECORD 0x0 +#define ISO_VD_SUPPLEMENTARY 0x2 +#define ISO_VD_END 0xff +#define ISO_VD_MAX 16 + +struct high_sierra_volume_descriptor { + unsigned char foo[8]; + unsigned char type; + unsigned char id[5]; + unsigned char version; + unsigned char unused1; + unsigned char system_id[32]; + unsigned char volume_id[32]; +} __attribute__((packed)); + +/* returns 1 if the begin of @ascii is equal to @utf16 string. + */ +static int ascii_eq_utf16be(unsigned char *ascii, + unsigned char *utf16, size_t len) +{ + size_t a, u; + + for (a = 0, u = 0; u < len; a++, u += 2) { + if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1]) + return 0; + } + return 1; +} + +/* old High Sierra format */ +static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct high_sierra_volume_descriptor *iso; + + iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor); + if (!iso) + return errno ? -errno : 1; + + blkid_probe_set_version(pr, "High Sierra"); + blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id)); + return 0; +} + +static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date) +{ + unsigned char buffer[16]; + unsigned int i, zeros = 0; + + buffer[0] = date->year[0]; + buffer[1] = date->year[1]; + buffer[2] = date->year[2]; + buffer[3] = date->year[3]; + buffer[4] = date->month[0]; + buffer[5] = date->month[1]; + buffer[6] = date->day[0]; + buffer[7] = date->day[1]; + buffer[8] = date->hour[0]; + buffer[9] = date->hour[1]; + buffer[10] = date->minute[0]; + buffer[11] = date->minute[1]; + buffer[12] = date->second[0]; + buffer[13] = date->second[1]; + buffer[14] = date->hundredth[0]; + buffer[15] = date->hundredth[1]; + + /* count the number of zeros ('0') in the date buffer */ + for (i = 0, zeros = 0; i < sizeof(buffer); i++) + if (buffer[i] == '0') + zeros++; + + /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */ + if (zeros == sizeof(buffer) && date->offset == 0) + return 0; + + /* generate an UUID using this date and return success */ + blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer), + "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", + buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], + buffer[6], buffer[7], + buffer[8], buffer[9], + buffer[10], buffer[11], + buffer[12], buffer[13], + buffer[14], buffer[15]); + + return 1; +} + +static int is_str_empty(const unsigned char *str, size_t len) +{ + size_t i; + + if (!str || !*str) + return 1; + + for (i = 0; i < len; i++) + if (!isspace(str[i])) + return 0; + return 1; +} + +/* iso9660 [+ Microsoft Joliet Extension] */ +int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct iso_volume_descriptor *iso; + unsigned char label[32]; + int i; + int off; + + if (strcmp(mag->magic, "CDROM") == 0) + return probe_iso9660_hsfs(pr, mag); + + iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor); + if (!iso) + return errno ? -errno : 1; + + memcpy(label, iso->volume_id, sizeof(label)); + + if (!is_str_empty(iso->system_id, sizeof(iso->system_id))) + blkid_probe_set_id_label(pr, "SYSTEM_ID", + iso->system_id, sizeof(iso->system_id)); + + if (!is_str_empty(iso->publisher_id, sizeof(iso->publisher_id))) + blkid_probe_set_id_label(pr, "PUBLISHER_ID", + iso->publisher_id, sizeof(iso->publisher_id)); + + if (!is_str_empty(iso->application_id, sizeof(iso->application_id))) + blkid_probe_set_id_label(pr, "APPLICATION_ID", + iso->application_id, sizeof(iso->application_id)); + + /* create an UUID using the modified/created date */ + if (! probe_iso9660_set_uuid(pr, &iso->modified)) + probe_iso9660_set_uuid(pr, &iso->created); + + /* Joliet Extension and Boot Record */ + off = ISO_VD_OFFSET; + for (i = 0; i < ISO_VD_MAX; i++) { + struct boot_record *boot= (struct boot_record *) + blkid_probe_get_buffer(pr, + off, + max(sizeof(struct boot_record), + sizeof(struct iso_volume_descriptor))); + + if (boot == NULL || boot->vd_type == ISO_VD_END) + break; + + if (boot->vd_type == ISO_VD_BOOT_RECORD) { + if (!is_str_empty(boot->boot_system_id, + sizeof(boot->boot_system_id))) + blkid_probe_set_id_label(pr, "BOOT_SYSTEM_ID", + boot->boot_system_id, + sizeof(boot->boot_system_id)); + off += ISO_SECTOR_SIZE; + continue; + } + + /* Not a Boot record, lets see if its supplemntary volume descriptor */ + iso = (struct iso_volume_descriptor *) boot; + + if (iso->vd_type != ISO_VD_SUPPLEMENTARY) { + off += ISO_SECTOR_SIZE; + continue; + } + + if (memcmp(iso->escape_sequences, "%/@", 3) == 0 || + memcmp(iso->escape_sequences, "%/C", 3) == 0 || + memcmp(iso->escape_sequences, "%/E", 3) == 0) { + + blkid_probe_set_version(pr, "Joliet Extension"); + + /* Is the Joliet (UTF16BE) label equal to the label in + * the PVD? If yes, use PVD label. The Jolied version + * of the label could be trimed (because UTF16..). + */ + if (ascii_eq_utf16be(label, iso->volume_id, 32)) + break; + + blkid_probe_set_utf8label(pr, + iso->volume_id, + sizeof(iso->volume_id), + BLKID_ENC_UTF16BE); + goto has_label; + } + off += ISO_SECTOR_SIZE; + } + + /* Joliet not found, let use standard iso label */ + blkid_probe_set_label(pr, label, sizeof(label)); + +has_label: + return 0; +} + +const struct blkid_idinfo iso9660_idinfo = +{ + .name = "iso9660", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_iso9660, + .flags = BLKID_IDINFO_TOLERANT, + .magics = + { + { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 }, + { NULL } + } +}; + diff --git a/libblkid/iso9660.h b/libblkid/src/superblocks/iso9660.h index a8d729df6..a8d729df6 100644 --- a/libblkid/iso9660.h +++ b/libblkid/src/superblocks/iso9660.h diff --git a/libblkid/src/superblocks/isw_raid.c b/libblkid/src/superblocks/isw_raid.c new file mode 100644 index 000000000..065c2b208 --- /dev/null +++ b/libblkid/src/superblocks/isw_raid.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct isw_metadata { + uint8_t sig[32]; + uint32_t check_sum; + uint32_t mpb_size; + uint32_t family_num; + uint32_t generation_num; +}; + +#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. " + + +static int probe_iswraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct isw_metadata *isw; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 2) * 0x200; + isw = (struct isw_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct isw_metadata)); + if (!isw) + return errno ? -errno : 1; + + if (memcmp(isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0) + return 1; + if (blkid_probe_sprintf_version(pr, "%6s", + &isw->sig[sizeof(ISW_SIGNATURE)-1]) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(isw->sig), + (unsigned char *) isw->sig)) + return 1; + return 0; +} + +const struct blkid_idinfo iswraid_idinfo = { + .name = "isw_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_iswraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/jfs.c b/libblkid/src/superblocks/jfs.c new file mode 100644 index 000000000..ac684d8cd --- /dev/null +++ b/libblkid/src/superblocks/jfs.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +struct jfs_super_block { + unsigned char js_magic[4]; + uint32_t js_version; + uint64_t js_size; + uint32_t js_bsize; /* 4: aggregate block size in bytes */ + uint16_t js_l2bsize; /* 2: log2 of s_bsize */ + uint16_t js_l2bfactor; /* 2: log2(s_bsize/hardware block size) */ + uint32_t js_pbsize; /* 4: hardware/LVM block size in bytes */ + uint16_t js_l2pbsize; /* 2: log2 of s_pbsize */ + uint16_t js_pad; /* 2: padding necessary for alignment */ + uint32_t js_dummy2[26]; + unsigned char js_uuid[16]; + unsigned char js_label[16]; + unsigned char js_loguuid[16]; +}; + +static int probe_jfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct jfs_super_block *js; + + js = blkid_probe_get_sb(pr, mag, struct jfs_super_block); + if (!js) + return errno ? -errno : 1; + if (le32_to_cpu(js->js_bsize) != (1U << le16_to_cpu(js->js_l2bsize))) + return 1; + if (le32_to_cpu(js->js_pbsize) != (1U << le16_to_cpu(js->js_l2pbsize))) + return 1; + if ((le16_to_cpu(js->js_l2bsize) - le16_to_cpu(js->js_l2pbsize)) != + le16_to_cpu(js->js_l2bfactor)) + return 1; + + if (strlen((char *) js->js_label)) + blkid_probe_set_label(pr, js->js_label, sizeof(js->js_label)); + blkid_probe_set_uuid(pr, js->js_uuid); + return 0; +} + + +const struct blkid_idinfo jfs_idinfo = +{ + .name = "jfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_jfs, + .minsz = 16 * 1024 * 1024, + .magics = + { + { .magic = "JFS1", .len = 4, .kboff = 32 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/jmicron_raid.c b/libblkid/src/superblocks/jmicron_raid.c new file mode 100644 index 000000000..ca7986733 --- /dev/null +++ b/libblkid/src/superblocks/jmicron_raid.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct jm_metadata { + int8_t signature[2]; + uint8_t minor_version; + uint8_t major_version; + uint16_t checksum; +}; + +#define JM_SIGNATURE "JM" + +static int probe_jmraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct jm_metadata *jm; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + jm = (struct jm_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct jm_metadata)); + if (!jm) + return errno ? -errno : 1; + + if (memcmp(jm->signature, JM_SIGNATURE, sizeof(JM_SIGNATURE) - 1) != 0) + return 1; + if (blkid_probe_sprintf_version(pr, "%u.%u", + jm->major_version, jm->minor_version) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(jm->signature), + (unsigned char *) jm->signature)) + return 1; + return 0; +} + +const struct blkid_idinfo jmraid_idinfo = { + .name = "jmicron_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_jmraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/linux_raid.c b/libblkid/src/superblocks/linux_raid.c new file mode 100644 index 000000000..cf29141c6 --- /dev/null +++ b/libblkid/src/superblocks/linux_raid.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct mdp0_super_block { + uint32_t md_magic; + uint32_t major_version; + uint32_t minor_version; + uint32_t patch_version; + uint32_t gvalid_words; + uint32_t set_uuid0; + uint32_t ctime; + uint32_t level; + uint32_t size; + uint32_t nr_disks; + uint32_t raid_disks; + uint32_t md_minor; + uint32_t not_persistent; + uint32_t set_uuid1; + uint32_t set_uuid2; + uint32_t set_uuid3; +}; + +/* + * Version-1, little-endian. + */ +struct mdp1_super_block { + /* constant array information - 128 bytes */ + uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ + uint32_t major_version; /* 1 */ + uint32_t feature_map; /* 0 for now */ + uint32_t pad0; /* always set to 0 when writing */ + + uint8_t set_uuid[16]; /* user-space generated. */ + unsigned char set_name[32]; /* set and interpreted by user-space */ + + uint64_t ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ + uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ + uint32_t layout; /* only for raid5 currently */ + uint64_t size; /* used size of component devices, in 512byte sectors */ + + uint32_t chunksize; /* in 512byte sectors */ + uint32_t raid_disks; + uint32_t bitmap_offset; /* sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* These are only valid with feature bit '4' */ + uint32_t new_level; /* new level we are reshaping to */ + uint64_t reshape_position; /* next address in array-space for reshape */ + uint32_t delta_disks; /* change in number of raid_disks */ + uint32_t new_layout; /* new layout */ + uint32_t new_chunk; /* new chunk size (bytes) */ + uint8_t pad1[128-124]; /* set to 0 when written */ + + /* constant this-device information - 64 bytes */ + uint64_t data_offset; /* sector start of data, often 0 */ + uint64_t data_size; /* sectors in this device that can be used for data */ + uint64_t super_offset; /* sector start of this superblock */ + uint64_t recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ + uint32_t dev_number; /* permanent identifier of this device - not role in raid */ + uint32_t cnt_corrected_read; /* number of read errors that were corrected by re-writing */ + uint8_t device_uuid[16]; /* user-space setable, ignored by kernel */ + uint8_t devflags; /* per-device flags. Only one defined...*/ + uint8_t pad2[64-57]; /* set to 0 when writing */ + + /* array state information - 64 bytes */ + uint64_t utime; /* 40 bits second, 24 btes microseconds */ + uint64_t events; /* incremented when superblock updated */ + uint64_t resync_offset; /* data before this offset (from data_offset) known to be in sync */ + uint32_t sb_csum; /* checksum up to dev_roles[max_dev] */ + uint32_t max_dev; /* size of dev_roles[] array to consider */ + uint8_t pad3[64-32]; /* set to 0 when writing */ + + /* device state information. Indexed by dev_number. + * 2 bytes per device + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + uint16_t dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ +}; + + +#define MD_RESERVED_BYTES 0x10000 +#define MD_SB_MAGIC 0xa92b4efc + +static int probe_raid0(blkid_probe pr, blkid_loff_t off) +{ + struct mdp0_super_block *mdp0; + union { + uint32_t ints[4]; + uint8_t bytes[16]; + } uuid; + uint32_t ma, mi, pa; + uint64_t size; + + if (pr->size < MD_RESERVED_BYTES) + return 1; + mdp0 = (struct mdp0_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct mdp0_super_block)); + if (!mdp0) + return errno ? -errno : 1; + + memset(uuid.ints, 0, sizeof(uuid.ints)); + + if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = swab32(mdp0->set_uuid0); + if (le32_to_cpu(mdp0->minor_version) >= 90) { + uuid.ints[1] = swab32(mdp0->set_uuid1); + uuid.ints[2] = swab32(mdp0->set_uuid2); + uuid.ints[3] = swab32(mdp0->set_uuid3); + } + ma = le32_to_cpu(mdp0->major_version); + mi = le32_to_cpu(mdp0->minor_version); + pa = le32_to_cpu(mdp0->patch_version); + size = le32_to_cpu(mdp0->size); + + } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { + uuid.ints[0] = mdp0->set_uuid0; + if (be32_to_cpu(mdp0->minor_version) >= 90) { + uuid.ints[1] = mdp0->set_uuid1; + uuid.ints[2] = mdp0->set_uuid2; + uuid.ints[3] = mdp0->set_uuid3; + } + ma = be32_to_cpu(mdp0->major_version); + mi = be32_to_cpu(mdp0->minor_version); + pa = be32_to_cpu(mdp0->patch_version); + size = be32_to_cpu(mdp0->size); + } else + return 1; + + size <<= 10; /* convert KiB to bytes */ + + if (pr->size < 0 || (uint64_t) pr->size < size + MD_RESERVED_BYTES) + /* device is too small */ + return 1; + + if (off < 0 || (uint64_t) off < size) + /* no space before superblock */ + return 1; + + /* + * Check for collisions between RAID and partition table + * + * For example the superblock is at the end of the last partition, it's + * the same position as at the end of the disk... + */ + if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) && + blkid_probe_is_covered_by_pt(pr, + off - size, /* min. start */ + size + MD_RESERVED_BYTES)) { /* min. length */ + + /* ignore this superblock, it's within any partition and + * we are working with whole-disk now */ + return 1; + } + + if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0) + return 1; + if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic), + (unsigned char *) &mdp0->md_magic)) + return 1; + return 0; +} + +static int probe_raid1(blkid_probe pr, off_t off) +{ + struct mdp1_super_block *mdp1; + + mdp1 = (struct mdp1_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct mdp1_super_block)); + if (!mdp1) + return errno ? -errno : 1; + if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) + return 1; + if (le32_to_cpu(mdp1->major_version) != 1U) + return 1; + if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9) + return 1; + if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0) + return 1; + if (blkid_probe_set_uuid_as(pr, + (unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0) + return 1; + if (blkid_probe_set_label(pr, mdp1->set_name, + sizeof(mdp1->set_name)) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic), + (unsigned char *) &mdp1->magic)) + return 1; + return 0; +} + +int probe_raid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const char *ver = NULL; + int ret = BLKID_PROBE_NONE; + + if (pr->size > MD_RESERVED_BYTES) { + /* version 0 at the end of the device */ + uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1)) + - MD_RESERVED_BYTES; + ret = probe_raid0(pr, sboff); + if (ret < 1) + return ret; /* error */ + + /* version 1.0 at the end of the device */ + sboff = (pr->size & ~(0x1000 - 1)) - 0x2000; + ret = probe_raid1(pr, sboff); + if (ret < 0) + return ret; /* error */ + if (ret == 0) + ver = "1.0"; + } + + if (!ver) { + /* version 1.1 at the start of the device */ + ret = probe_raid1(pr, 0); + if (ret == 0) + ver = "1.1"; + + /* version 1.2 at 4k offset from the start */ + else if (ret == BLKID_PROBE_NONE) { + ret = probe_raid1(pr, 0x1000); + if (ret == 0) + ver = "1.2"; + } + } + + if (ver) { + blkid_probe_set_version(pr, ver); + return BLKID_PROBE_OK; + } + return ret; +} + + +const struct blkid_idinfo linuxraid_idinfo = { + .name = "linux_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_raid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/lsi_raid.c b/libblkid/src/superblocks/lsi_raid.c new file mode 100644 index 000000000..697b0fe89 --- /dev/null +++ b/libblkid/src/superblocks/lsi_raid.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct lsi_metadata { + uint8_t sig[6]; +}; + + +#define LSI_SIGNATURE "$XIDE$" + +static int probe_lsiraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct lsi_metadata *lsi; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + lsi = (struct lsi_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct lsi_metadata)); + if (!lsi) + return errno ? -errno : 1; + + if (memcmp(lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(lsi->sig), + (unsigned char *) lsi->sig)) + return 1; + return 0; +} + +const struct blkid_idinfo lsiraid_idinfo = { + .name = "lsi_mega_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lsiraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/luks.c b/libblkid/src/superblocks/luks.c new file mode 100644 index 000000000..00696f28c --- /dev/null +++ b/libblkid/src/superblocks/luks.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +#define LUKS_CIPHERNAME_L 32 +#define LUKS_CIPHERMODE_L 32 +#define LUKS_HASHSPEC_L 32 +#define LUKS_DIGESTSIZE 20 +#define LUKS_SALTSIZE 32 +#define LUKS_MAGIC_L 6 +#define UUID_STRING_L 40 + +struct luks_phdr { + uint8_t magic[LUKS_MAGIC_L]; + uint16_t version; + uint8_t cipherName[LUKS_CIPHERNAME_L]; + uint8_t cipherMode[LUKS_CIPHERMODE_L]; + uint8_t hashSpec[LUKS_HASHSPEC_L]; + uint32_t payloadOffset; + uint32_t keyBytes; + uint8_t mkDigest[LUKS_DIGESTSIZE]; + uint8_t mkDigestSalt[LUKS_SALTSIZE]; + uint32_t mkDigestIterations; + uint8_t uuid[UUID_STRING_L]; +} __attribute__((packed)); + +static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct luks_phdr *header; + + header = blkid_probe_get_sb(pr, mag, struct luks_phdr); + if (header == NULL) + return errno ? -errno : 1; + + blkid_probe_strncpy_uuid(pr, (unsigned char *) header->uuid, + sizeof(header->uuid)); + blkid_probe_sprintf_version(pr, "%u", be16_to_cpu(header->version)); + return 0; +} + +const struct blkid_idinfo luks_idinfo = +{ + .name = "crypto_LUKS", + .usage = BLKID_USAGE_CRYPTO, + .probefunc = probe_luks, + .magics = + { + { .magic = "LUKS\xba\xbe", .len = 6 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/lvm.c b/libblkid/src/superblocks/lvm.c new file mode 100644 index 000000000..3c6df743d --- /dev/null +++ b/libblkid/src/superblocks/lvm.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2012 Milan Broz <mbroz@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +#define LVM1_ID_LEN 128 +#define LVM2_ID_LEN 32 + +struct lvm2_pv_label_header { + /* label_header */ + uint8_t id[8]; /* LABELONE */ + uint64_t sector_xl; /* Sector number of this label */ + uint32_t crc_xl; /* From next field to end of sector */ + uint32_t offset_xl; /* Offset from start of struct to contents */ + uint8_t type[8]; /* LVM2 001 */ + /* pv_header */ + uint8_t pv_uuid[LVM2_ID_LEN]; +} __attribute__ ((packed)); + +struct lvm1_pv_label_header { + uint8_t id[2]; /* HM */ + uint16_t version; /* version 1 or 2 */ + uint32_t _notused[10]; /* lvm1 internals */ + uint8_t pv_uuid[LVM1_ID_LEN]; +} __attribute__ ((packed)); + +#define LVM2_LABEL_SIZE 512 +static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) +{ + static const unsigned int crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + unsigned int i, crc = 0xf597a6cf; + const uint8_t *data = (const uint8_t *) buf; + + for (i = 0; i < size; i++) { + crc ^= *data++; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + return crc; +} + +/* Length of real UUID is always LVM2_ID_LEN */ +static void format_lvm_uuid(char *dst_uuid, char *src_uuid) +{ + unsigned int i, b; + + for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) { + if (b & 0x4444440) + *dst_uuid++ = '-'; + *dst_uuid++ = *src_uuid++; + } + *dst_uuid = '\0'; +} + +static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) +{ + int sector = mag->kboff << 1; + struct lvm2_pv_label_header *label; + char uuid[LVM2_ID_LEN + 7]; + unsigned char *buf; + + buf = blkid_probe_get_buffer(pr, + mag->kboff << 10, + 512 + sizeof(struct lvm2_pv_label_header)); + if (!buf) + return errno ? -errno : 1; + + /* buf is at 0k or 1k offset; find label inside */ + if (memcmp(buf, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *) buf; + } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { + label = (struct lvm2_pv_label_header *)(buf + 512); + sector++; + } else { + return 1; + } + + if (le64_to_cpu(label->sector_xl) != (unsigned) sector) + return 1; + + if (!blkid_probe_verify_csum( + pr, lvm2_calc_crc( + &label->offset_xl, LVM2_LABEL_SIZE - + ((char *) &label->offset_xl - (char *) label)), + le32_to_cpu(label->crc_xl))) + return 1; + + format_lvm_uuid(uuid, (char *) label->pv_uuid); + blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), + "%s", uuid); + + /* the mag->magic is the same string as label->type, + * but zero terminated */ + blkid_probe_set_version(pr, mag->magic); + + /* LVM (pvcreate) wipes begin of the device -- let's remember this + * to resolve conflicts bettween LVM and partition tables, ... + */ + blkid_probe_set_wiper(pr, 0, 8 * 1024); + + return 0; +} + +static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct lvm1_pv_label_header *label; + char uuid[LVM2_ID_LEN + 7]; + unsigned int version; + + label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); + if (!label) + return errno ? -errno : 1; + + version = le16_to_cpu(label->version); + if (version != 1 && version != 2) + return 1; + + format_lvm_uuid(uuid, (char *) label->pv_uuid); + blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), + "%s", uuid); + + return 0; +} + +struct verity_sb { + uint8_t signature[8]; /* "verity\0\0" */ + uint32_t version; /* superblock version */ + uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */ + uint8_t uuid[16]; /* UUID of hash device */ + uint8_t algorithm[32];/* hash algorithm name */ + uint32_t data_block_size; /* data block in bytes */ + uint32_t hash_block_size; /* hash block in bytes */ + uint64_t data_blocks; /* number of data blocks */ + uint16_t salt_size; /* salt size */ + uint8_t _pad1[6]; + uint8_t salt[256]; /* salt */ + uint8_t _pad2[168]; +} __attribute__((packed)); + +static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct verity_sb *sb; + unsigned int version; + + sb = blkid_probe_get_sb(pr, mag, struct verity_sb); + if (sb == NULL) + return errno ? -errno : 1; + + version = le32_to_cpu(sb->version); + if (version != 1) + return 1; + + blkid_probe_set_uuid(pr, sb->uuid); + blkid_probe_sprintf_version(pr, "%u", version); + return 0; +} + +/* NOTE: the original libblkid uses "lvm2pv" as a name */ +const struct blkid_idinfo lvm2_idinfo = +{ + .name = "LVM2_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lvm2, + .magics = + { + { .magic = "LVM2 001", .len = 8, .sboff = 0x218 }, + { .magic = "LVM2 001", .len = 8, .sboff = 0x018 }, + { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 }, + { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 }, + { NULL } + } +}; + +const struct blkid_idinfo lvm1_idinfo = +{ + .name = "LVM1_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_lvm1, + .magics = + { + { .magic = "HM", .len = 2 }, + { NULL } + } +}; + +const struct blkid_idinfo snapcow_idinfo = +{ + .name = "DM_snapshot_cow", + .usage = BLKID_USAGE_OTHER, + .magics = + { + { .magic = "SnAp", .len = 4 }, + { NULL } + } +}; + +const struct blkid_idinfo verity_hash_idinfo = +{ + .name = "DM_verity_hash", + .usage = BLKID_USAGE_CRYPTO, + .probefunc = probe_verity, + .magics = + { + { .magic = "verity\0\0", .len = 8 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/minix.c b/libblkid/src/superblocks/minix.c new file mode 100644 index 000000000..9ea49fee8 --- /dev/null +++ b/libblkid/src/superblocks/minix.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <string.h> +#include "superblocks.h" +#include "minix.h" + +#define minix_swab16(doit, num) ((uint16_t) (doit ? swab16(num) : num)) +#define minix_swab32(doit, num) ((uint32_t) (doit ? swab32(num) : num)) + +static int get_minix_version(const unsigned char *data, int *other_endian) +{ + struct minix_super_block *sb = (struct minix_super_block *) data; + struct minix3_super_block *sb3 = (struct minix3_super_block *) data; + int version = 0; + + *other_endian = 0; + + switch (sb->s_magic) { + case MINIX_SUPER_MAGIC: + case MINIX_SUPER_MAGIC2: + version = 1; + break; + case MINIX2_SUPER_MAGIC: + case MINIX2_SUPER_MAGIC2: + version = 2; + break; + default: + if (sb3->s_magic == MINIX3_SUPER_MAGIC) + version = 3; + break; + } + + if (!version) { + *other_endian = 1; + + switch (swab16(sb->s_magic)) { + case MINIX_SUPER_MAGIC: + case MINIX_SUPER_MAGIC2: + version = 1; + break; + case MINIX2_SUPER_MAGIC: + case MINIX2_SUPER_MAGIC2: + version = 2; + break; + default: + if (sb3->s_magic == MINIX3_SUPER_MAGIC) + version = 3; + break; + } + } + if (!version) + return -1; + + DBG(LOWPROBE, ul_debug("minix version %d detected [%s]", version, +#if defined(WORDS_BIGENDIAN) + *other_endian ? "LE" : "BE" +#else + *other_endian ? "BE" : "LE" +#endif + )); + return version; +} + +static int probe_minix(blkid_probe pr, const struct blkid_idmag *mag) +{ + unsigned char *ext; + const unsigned char *data; + int version = 0, swabme = 0; + + data = blkid_probe_get_buffer(pr, 1024, + max(sizeof(struct minix_super_block), + sizeof(struct minix3_super_block))); + if (!data) + return errno ? -errno : 1; + version = get_minix_version(data, &swabme); + if (version < 1) + return 1; + + if (version <= 2) { + struct minix_super_block *sb = (struct minix_super_block *) data; + int zones, ninodes, imaps, zmaps, firstz; + + if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) + return 1; + + zones = version == 2 ? minix_swab32(swabme, sb->s_zones) : + minix_swab16(swabme, sb->s_nzones); + ninodes = minix_swab16(swabme, sb->s_ninodes); + imaps = minix_swab16(swabme, sb->s_imap_blocks); + zmaps = minix_swab16(swabme, sb->s_zmap_blocks); + firstz = minix_swab16(swabme, sb->s_firstdatazone); + + /* sanity checks to be sure that the FS is really minix */ + if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1) + return 1; + if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1) + return 1; + + } else if (version == 3) { + struct minix3_super_block *sb = (struct minix3_super_block *) data; + + if (sb->s_imap_blocks == 0 || sb->s_zmap_blocks == 0) + return 1; + } + + /* unfortunately, some parts of ext3 is sometimes possible to + * interpreted as minix superblock. So check for extN magic + * string. (For extN magic string and offsets see ext.c.) + */ + ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2); + if (!ext) + return errno ? -errno : 1; + else if (memcmp(ext, "\123\357", 2) == 0) + return 1; + + blkid_probe_sprintf_version(pr, "%d", version); + return 0; +} + +const struct blkid_idinfo minix_idinfo = +{ + .name = "minix", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_minix, + .magics = + { + /* version 1 - LE */ + { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 1 - BE */ + { .magic = "\023\177", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\023\217", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 2 - LE */ + { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 2 - BE */ + { .magic = "\044\150", .len = 2, .kboff = 1, .sboff = 0x10 }, + { .magic = "\044\170", .len = 2, .kboff = 1, .sboff = 0x10 }, + + /* version 3 - LE */ + { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 }, + + /* version 3 - BE */ + { .magic = "\115\132", .len = 2, .kboff = 1, .sboff = 0x18 }, + + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/netware.c b/libblkid/src/superblocks/netware.c new file mode 100644 index 000000000..af81cf5fd --- /dev/null +++ b/libblkid/src/superblocks/netware.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct netware_super_block { + uint8_t SBH_Signature[4]; + uint16_t SBH_VersionMajor; + uint16_t SBH_VersionMinor; + uint16_t SBH_VersionMediaMajor; + uint16_t SBH_VersionMediaMinor; + uint32_t SBH_ItemsMoved; + uint8_t SBH_InternalID[16]; + uint32_t SBH_PackedSize; + uint32_t SBH_Checksum; + uint32_t supersyncid; + int64_t superlocation[4]; + uint32_t physSizeUsed; + uint32_t sizeUsed; + uint32_t superTimeStamp; + uint32_t reserved0[1]; + int64_t SBH_LoggedPoolDataBlk; + int64_t SBH_PoolDataBlk; + uint8_t SBH_OldInternalID[16]; + uint32_t SBH_PoolToLVStartUTC; + uint32_t SBH_PoolToLVEndUTC; + uint16_t SBH_VersionMediaMajorCreate; + uint16_t SBH_VersionMediaMinorCreate; + uint32_t SBH_BlocksMoved; + uint32_t SBH_TempBTSpBlk; + uint32_t SBH_TempFTSpBlk; + uint32_t SBH_TempFTSpBlk1; + uint32_t SBH_TempFTSpBlk2; + uint32_t nssMagicNumber; + uint32_t poolClassID; + uint32_t poolID; + uint32_t createTime; + int64_t SBH_LoggedVolumeDataBlk; + int64_t SBH_VolumeDataBlk; + int64_t SBH_SystemBeastBlkNum; + uint64_t totalblocks; + uint16_t SBH_Name[64]; + uint8_t SBH_VolumeID[16]; + uint8_t SBH_PoolID[16]; + uint8_t SBH_PoolInternalID[16]; + uint64_t SBH_Lsn; + uint32_t SBH_SS_Enabled; + uint32_t SBH_SS_CreateTime; + uint8_t SBH_SS_OriginalPoolID[16]; + uint8_t SBH_SS_OriginalVolumeID[16]; + uint8_t SBH_SS_Guid[16]; + uint16_t SBH_SS_OriginalName[64]; + uint32_t reserved2[64-(2+46)]; +} __attribute__((__packed__)); + +static int probe_netware(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct netware_super_block *nw; + + nw = blkid_probe_get_sb(pr, mag, struct netware_super_block); + if (!nw) + return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, nw->SBH_PoolID); + + blkid_probe_sprintf_version(pr, "%u.%02u", + le16_to_cpu(nw->SBH_VersionMediaMajor), + le16_to_cpu(nw->SBH_VersionMediaMinor)); + + return 0; +} + +const struct blkid_idinfo netware_idinfo = +{ + .name = "nss", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_netware, + .magics = + { + { .magic = "SPB5", .len = 4, .kboff = 4 }, + { NULL } + } +}; + + diff --git a/libblkid/src/superblocks/nilfs.c b/libblkid/src/superblocks/nilfs.c new file mode 100644 index 000000000..3f0390126 --- /dev/null +++ b/libblkid/src/superblocks/nilfs.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2010 by Jiro SEKIBA <jir@unicus.jp> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License + */ +#include <stddef.h> +#include <string.h> + +#include "superblocks.h" +#include "crc32.h" + +struct nilfs_super_block { + uint32_t s_rev_level; + uint16_t s_minor_rev_level; + uint16_t s_magic; + + uint16_t s_bytes; + + uint16_t s_flags; + uint32_t s_crc_seed; + uint32_t s_sum; + + uint32_t s_log_block_size; + + uint64_t s_nsegments; + uint64_t s_dev_size; + uint64_t s_first_data_block; + uint32_t s_blocks_per_segment; + uint32_t s_r_segments_percentage; + + uint64_t s_last_cno; + uint64_t s_last_pseg; + uint64_t s_last_seq; + uint64_t s_free_blocks_count; + + uint64_t s_ctime; + + uint64_t s_mtime; + uint64_t s_wtime; + uint16_t s_mnt_count; + uint16_t s_max_mnt_count; + uint16_t s_state; + uint16_t s_errors; + uint64_t s_lastcheck; + + uint32_t s_checkinterval; + uint32_t s_creator_os; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + uint32_t s_first_ino; + + uint16_t s_inode_size; + uint16_t s_dat_entry_size; + uint16_t s_checkpoint_size; + uint16_t s_segment_usage_size; + + uint8_t s_uuid[16]; + char s_volume_name[80]; + + uint32_t s_c_interval; + uint32_t s_c_block_max; + uint32_t s_reserved[192]; +}; + +#define NILFS_SB_MAGIC 0x3434 +#define NILFS_SB_OFFSET 0x400 + +static int nilfs_valid_sb(blkid_probe pr, struct nilfs_super_block *sb) +{ + static unsigned char sum[4]; + const int sumoff = offsetof(struct nilfs_super_block, s_sum); + size_t bytes; + uint32_t crc; + + if (!sb || le16_to_cpu(sb->s_magic) != NILFS_SB_MAGIC) + return 0; + + bytes = le16_to_cpu(sb->s_bytes); + crc = crc32(le32_to_cpu(sb->s_crc_seed), (unsigned char *)sb, sumoff); + crc = crc32(crc, sum, 4); + crc = crc32(crc, (unsigned char *)sb + sumoff + 4, bytes - sumoff - 4); + + return blkid_probe_verify_csum(pr, crc, le32_to_cpu(sb->s_sum)); +} + +static int probe_nilfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct nilfs_super_block *sb, *sbp, *sbb; + int valid[2], swp = 0; + + /* primary */ + sbp = (struct nilfs_super_block *) blkid_probe_get_buffer( + pr, NILFS_SB_OFFSET, sizeof(struct nilfs_super_block)); + if (!sbp) + return errno ? -errno : 1; + /* backup */ + sbb = (struct nilfs_super_block *) blkid_probe_get_buffer( + pr, ((pr->size / 0x200) - 8) * 0x200, sizeof(struct nilfs_super_block)); + if (!sbb) + return errno ? -errno : 1; + + /* + * Compare two super blocks and set 1 in swp if the secondary + * super block is valid and newer. Otherwise, set 0 in swp. + */ + valid[0] = nilfs_valid_sb(pr, sbp); + valid[1] = nilfs_valid_sb(pr, sbb); + if (!valid[0] && !valid[1]) + return 1; + + swp = valid[1] && (!valid[0] || + le64_to_cpu(sbp->s_last_cno) > + le64_to_cpu(sbb->s_last_cno)); + sb = swp ? sbb : sbp; + + DBG(LOWPROBE, ul_debug("nilfs2: primary=%d, backup=%d, swap=%d", + valid[0], valid[1], swp)); + + if (strlen(sb->s_volume_name)) + blkid_probe_set_label(pr, (unsigned char *) sb->s_volume_name, + sizeof(sb->s_volume_name)); + + blkid_probe_set_uuid(pr, sb->s_uuid); + blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(sb->s_rev_level)); + + return 0; +} + +const struct blkid_idinfo nilfs2_idinfo = +{ + .name = "nilfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_nilfs2, + /* default min.size is 128MiB, but 1MiB for "mkfs.nilfs2 -b 1024 -B 16" */ + .minsz = (1024 * 1024), + .magics = BLKID_NONE_MAGIC +}; diff --git a/libblkid/src/superblocks/ntfs.c b/libblkid/src/superblocks/ntfs.c new file mode 100644 index 000000000..8ff9ccda1 --- /dev/null +++ b/libblkid/src/superblocks/ntfs.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "superblocks.h" + +struct ntfs_bios_parameters { + uint16_t sector_size; /* Size of a sector in bytes. */ + uint8_t sectors_per_cluster; /* Size of a cluster in sectors. */ + uint16_t reserved_sectors; /* zero */ + uint8_t fats; /* zero */ + uint16_t root_entries; /* zero */ + uint16_t sectors; /* zero */ + uint8_t media_type; /* 0xf8 = hard disk */ + uint16_t sectors_per_fat; /* zero */ + uint16_t sectors_per_track; /* irrelevant */ + uint16_t heads; /* irrelevant */ + uint32_t hidden_sectors; /* zero */ + uint32_t large_sectors; /* zero */ +} __attribute__ ((__packed__)); + +struct ntfs_super_block { + uint8_t jump[3]; + uint8_t oem_id[8]; /* magic string */ + + struct ntfs_bios_parameters bpb; + + uint16_t unused[2]; + uint64_t number_of_sectors; + uint64_t mft_cluster_location; + uint64_t mft_mirror_cluster_location; + int8_t clusters_per_mft_record; + uint8_t reserved1[3]; + int8_t cluster_per_index_record; + uint8_t reserved2[3]; + uint64_t volume_serial; + uint32_t checksum; +} __attribute__((packed)); + +struct master_file_table_record { + uint32_t magic; + uint16_t usa_ofs; + uint16_t usa_count; + uint64_t lsn; + uint16_t sequence_number; + uint16_t link_count; + uint16_t attrs_offset; + uint16_t flags; + uint32_t bytes_in_use; + uint32_t bytes_allocated; +} __attribute__((__packed__)); + +struct file_attribute { + uint32_t type; + uint32_t len; + uint8_t non_resident; + uint8_t name_len; + uint16_t name_offset; + uint16_t flags; + uint16_t instance; + uint32_t value_len; + uint16_t value_offset; +} __attribute__((__packed__)); + +#define MFT_RECORD_VOLUME 3 +#define NTFS_MAX_CLUSTER_SIZE (64 * 1024) + +enum { + MFT_RECORD_ATTR_VOLUME_NAME = 0x60, + MFT_RECORD_ATTR_END = 0xffffffff +}; + +static int probe_ntfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ntfs_super_block *ns; + struct master_file_table_record *mft; + + uint32_t sectors_per_cluster, mft_record_size, attr_off; + uint16_t sector_size; + uint64_t nr_clusters, off; + unsigned char *buf_mft; + + ns = blkid_probe_get_sb(pr, mag, struct ntfs_super_block); + if (!ns) + return errno ? -errno : 1; + + /* + * Check bios parameters block + */ + sector_size = le16_to_cpu(ns->bpb.sector_size); + sectors_per_cluster = ns->bpb.sectors_per_cluster; + + if (sector_size < 256 || sector_size > 4096) + return 1; + + switch (sectors_per_cluster) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: + break; + default: + return 1; + } + + if ((uint16_t) le16_to_cpu(ns->bpb.sector_size) * + ns->bpb.sectors_per_cluster > NTFS_MAX_CLUSTER_SIZE) + return 1; + + /* Unused fields must be zero */ + if (le16_to_cpu(ns->bpb.reserved_sectors) + || le16_to_cpu(ns->bpb.root_entries) + || le16_to_cpu(ns->bpb.sectors) + || le16_to_cpu(ns->bpb.sectors_per_fat) + || le32_to_cpu(ns->bpb.large_sectors) + || ns->bpb.fats) + return 1; + + if ((uint8_t) ns->clusters_per_mft_record < 0xe1 + || (uint8_t) ns->clusters_per_mft_record > 0xf7) { + + switch (ns->clusters_per_mft_record) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: + break; + default: + return 1; + } + } + + if (ns->clusters_per_mft_record > 0) + mft_record_size = ns->clusters_per_mft_record * + sectors_per_cluster * sector_size; + else + mft_record_size = 1 << (0 - ns->clusters_per_mft_record); + + nr_clusters = le64_to_cpu(ns->number_of_sectors) / sectors_per_cluster; + + if ((le64_to_cpu(ns->mft_cluster_location) > nr_clusters) || + (le64_to_cpu(ns->mft_mirror_cluster_location) > nr_clusters)) + return 1; + + + off = le64_to_cpu(ns->mft_cluster_location) * sector_size * + sectors_per_cluster; + + DBG(LOWPROBE, ul_debug("NTFS: sector_size=%d, mft_record_size=%d, " + "sectors_per_cluster=%d, nr_clusters=%ju " + "cluster_offset=%jd", + (int) sector_size, mft_record_size, + sectors_per_cluster, nr_clusters, + off)); + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) + return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + off += MFT_RECORD_VOLUME * mft_record_size; + + buf_mft = blkid_probe_get_buffer(pr, off, mft_record_size); + if (!buf_mft) + return errno ? -errno : 1; + + if (memcmp(buf_mft, "FILE", 4)) + return 1; + + mft = (struct master_file_table_record *) buf_mft; + attr_off = le16_to_cpu(mft->attrs_offset); + + while (attr_off < mft_record_size && + attr_off <= le32_to_cpu(mft->bytes_allocated)) { + + uint32_t attr_len; + struct file_attribute *attr; + + attr = (struct file_attribute *) (buf_mft + attr_off); + attr_len = le32_to_cpu(attr->len); + if (!attr_len) + break; + + if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_END) + break; + if (le32_to_cpu(attr->type) == MFT_RECORD_ATTR_VOLUME_NAME) { + unsigned int val_off = le16_to_cpu(attr->value_offset); + unsigned int val_len = le32_to_cpu(attr->value_len); + unsigned char *val = ((uint8_t *) attr) + val_off; + + blkid_probe_set_utf8label(pr, val, val_len, BLKID_ENC_UTF16LE); + break; + } + + if (UINT_MAX - attr_len < attr_off) + break; + attr_off += attr_len; + } + + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &ns->volume_serial, + sizeof(ns->volume_serial), + "%016" PRIX64, le64_to_cpu(ns->volume_serial)); + return 0; +} + + +const struct blkid_idinfo ntfs_idinfo = +{ + .name = "ntfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ntfs, + .magics = + { + { .magic = "NTFS ", .len = 8, .sboff = 3 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/nvidia_raid.c b/libblkid/src/superblocks/nvidia_raid.c new file mode 100644 index 000000000..5db8ec260 --- /dev/null +++ b/libblkid/src/superblocks/nvidia_raid.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct nv_metadata { + uint8_t vendor[8]; + uint32_t size; + uint32_t chksum; + uint16_t version; +} __attribute__((packed)); + +#define NVIDIA_SIGNATURE "NVIDIA" + +static int probe_nvraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct nv_metadata *nv; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 2) * 0x200; + nv = (struct nv_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct nv_metadata)); + if (!nv) + return errno ? -errno : 1; + + if (memcmp(nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0) + return 1; + if (blkid_probe_sprintf_version(pr, "%u", le16_to_cpu(nv->version)) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, sizeof(nv->vendor), + (unsigned char *) nv->vendor)) + return 1; + return 0; +} + +const struct blkid_idinfo nvraid_idinfo = { + .name = "nvidia_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_nvraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/ocfs.c b/libblkid/src/superblocks/ocfs.c new file mode 100644 index 000000000..3fe199d3f --- /dev/null +++ b/libblkid/src/superblocks/ocfs.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct ocfs_volume_header { + unsigned char minor_version[4]; + unsigned char major_version[4]; + unsigned char signature[128]; + char mount[128]; + unsigned char mount_len[2]; +} __attribute__((packed)); + +struct ocfs_volume_label { + unsigned char disk_lock[48]; + char label[64]; + unsigned char label_len[2]; + unsigned char vol_id[16]; + unsigned char vol_id_len[2]; +} __attribute__((packed)); + +#define ocfsmajor(o) ( (uint32_t) o.major_version[0] \ + + (((uint32_t) o.major_version[1]) << 8) \ + + (((uint32_t) o.major_version[2]) << 16) \ + + (((uint32_t) o.major_version[3]) << 24)) + +#define ocfsminor(o) ( (uint32_t) o.minor_version[0] \ + + (((uint32_t) o.minor_version[1]) << 8) \ + + (((uint32_t) o.minor_version[2]) << 16) \ + + (((uint32_t) o.minor_version[3]) << 24)) + +#define ocfslabellen(o) ((uint32_t)o.label_len[0] + (((uint32_t) o.label_len[1]) << 8)) +#define ocfsmountlen(o) ((uint32_t)o.mount_len[0] + (((uint32_t) o.mount_len[1]) << 8)) + +struct ocfs2_super_block { + uint8_t i_signature[8]; + uint32_t i_generation; + int16_t i_suballoc_slot; + uint16_t i_suballoc_bit; + uint32_t i_reserved0; + uint32_t i_clusters; + uint32_t i_uid; + uint32_t i_gid; + uint64_t i_size; + uint16_t i_mode; + uint16_t i_links_count; + uint32_t i_flags; + uint64_t i_atime; + uint64_t i_ctime; + uint64_t i_mtime; + uint64_t i_dtime; + uint64_t i_blkno; + uint64_t i_last_eb_blk; + uint32_t i_fs_generation; + uint32_t i_atime_nsec; + uint32_t i_ctime_nsec; + uint32_t i_mtime_nsec; + uint64_t i_reserved1[9]; + uint64_t i_pad1; + uint16_t s_major_rev_level; + uint16_t s_minor_rev_level; + uint16_t s_mnt_count; + int16_t s_max_mnt_count; + uint16_t s_state; + uint16_t s_errors; + uint32_t s_checkinterval; + uint64_t s_lastcheck; + uint32_t s_creator_os; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + uint64_t s_root_blkno; + uint64_t s_system_dir_blkno; + uint32_t s_blocksize_bits; + uint32_t s_clustersize_bits; + uint16_t s_max_slots; + uint16_t s_reserved1; + uint32_t s_reserved2; + uint64_t s_first_cluster_group; + uint8_t s_label[64]; + uint8_t s_uuid[16]; +} __attribute__((packed)); + +struct oracle_asm_disk_label { + char dummy[32]; + char dl_tag[8]; + char dl_id[24]; +} __attribute__((packed)); + +static int probe_ocfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + unsigned char *buf; + struct ocfs_volume_header ovh; + struct ocfs_volume_label ovl; + uint32_t maj, min; + + /* header */ + buf = blkid_probe_get_buffer(pr, mag->kboff << 10, + sizeof(struct ocfs_volume_header)); + if (!buf) + return errno ? -errno : 1; + memcpy(&ovh, buf, sizeof(ovh)); + + /* label */ + buf = blkid_probe_get_buffer(pr, (mag->kboff << 10) + 512, + sizeof(struct ocfs_volume_label)); + if (!buf) + return errno ? -errno : 1; + memcpy(&ovl, buf, sizeof(ovl)); + + maj = ocfsmajor(ovh); + min = ocfsminor(ovh); + + if (maj == 1) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ocfs1", sizeof("ocfs1")); + else if (maj >= 9) + blkid_probe_set_value(pr, "SEC_TYPE", + (unsigned char *) "ntocfs", sizeof("ntocfs")); + + blkid_probe_set_label(pr, (unsigned char *) ovl.label, + ocfslabellen(ovl)); + blkid_probe_set_value(pr, "MOUNT", (unsigned char *) ovh.mount, + ocfsmountlen(ovh)); + blkid_probe_set_uuid(pr, ovl.vol_id); + blkid_probe_sprintf_version(pr, "%u.%u", maj, min); + return 0; +} + +static int probe_ocfs2(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ocfs2_super_block *osb; + + osb = blkid_probe_get_sb(pr, mag, struct ocfs2_super_block); + if (!osb) + return errno ? -errno : 1; + + blkid_probe_set_label(pr, (unsigned char *) osb->s_label, sizeof(osb->s_label)); + blkid_probe_set_uuid(pr, osb->s_uuid); + + blkid_probe_sprintf_version(pr, "%u.%u", + le16_to_cpu(osb->s_major_rev_level), + le16_to_cpu(osb->s_minor_rev_level)); + + return 0; +} + +static int probe_oracleasm(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct oracle_asm_disk_label *dl; + + dl = blkid_probe_get_sb(pr, mag, struct oracle_asm_disk_label); + if (!dl) + return errno ? -errno : 1; + + blkid_probe_set_label(pr, (unsigned char *) dl->dl_id, sizeof(dl->dl_id)); + return 0; +} + + +const struct blkid_idinfo ocfs_idinfo = +{ + .name = "ocfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ocfs, + .minsz = 14000 * 1024, + .magics = + { + { .magic = "OracleCFS", .len = 9, .kboff = 8 }, + { NULL } + } +}; + +const struct blkid_idinfo ocfs2_idinfo = +{ + .name = "ocfs2", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ocfs2, + .minsz = 14000 * 1024, + .magics = + { + { .magic = "OCFSV2", .len = 6, .kboff = 1 }, + { .magic = "OCFSV2", .len = 6, .kboff = 2 }, + { .magic = "OCFSV2", .len = 6, .kboff = 4 }, + { .magic = "OCFSV2", .len = 6, .kboff = 8 }, + { NULL } + } +}; + +/* Oracle ASM (Automatic Storage Management) */ +const struct blkid_idinfo oracleasm_idinfo = +{ + .name = "oracleasm", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_oracleasm, + .magics = + { + { .magic = "ORCLDISK", .len = 8, .sboff = 32 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/promise_raid.c b/libblkid/src/superblocks/promise_raid.c new file mode 100644 index 000000000..678460a43 --- /dev/null +++ b/libblkid/src/superblocks/promise_raid.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +struct promise_metadata { + uint8_t sig[24]; +}; + +#define PDC_CONFIG_OFF 0x1200 +#define PDC_SIGNATURE "Promise Technology, Inc." + +static int probe_pdcraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + unsigned int i; + static unsigned int sectors[] = { + 63, 255, 256, 16, 399, 591, 675, 735, 911, 974, 991, 951, 3087, 0 + }; + + if (pr->size < 0x40000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + for (i = 0; sectors[i] != 0; i++) { + uint64_t off; + struct promise_metadata *pdc; + + off = ((pr->size / 0x200) - sectors[i]) * 0x200; + pdc = (struct promise_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct promise_metadata)); + if (!pdc) + return errno ? -errno : 1; + + if (memcmp(pdc->sig, PDC_SIGNATURE, + sizeof(PDC_SIGNATURE) - 1) == 0) { + + if (blkid_probe_set_magic(pr, off, sizeof(pdc->sig), + (unsigned char *) pdc->sig)) + return 1; + return 0; + } + } + return 1; +} + +const struct blkid_idinfo pdcraid_idinfo = { + .name = "promise_fasttrack_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_pdcraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/refs.c b/libblkid/src/superblocks/refs.c new file mode 100644 index 000000000..ea81f208c --- /dev/null +++ b/libblkid/src/superblocks/refs.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <inttypes.h> + +#include "superblocks.h" + + +const struct blkid_idinfo refs_idinfo = +{ + .name = "ReFS", + .usage = BLKID_USAGE_FILESYSTEM, + .magics = + { + { .magic = "\000\000\000ReFS\000", .len = 8 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/reiserfs.c b/libblkid/src/superblocks/reiserfs.c new file mode 100644 index 000000000..edbaaa946 --- /dev/null +++ b/libblkid/src/superblocks/reiserfs.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +struct reiserfs_super_block { + uint32_t rs_blocks_count; + uint32_t rs_free_blocks; + uint32_t rs_root_block; + uint32_t rs_journal_block; + uint32_t rs_journal_dev; + uint32_t rs_orig_journal_size; + uint32_t rs_dummy2[5]; + uint16_t rs_blocksize; + uint16_t rs_dummy3[3]; + unsigned char rs_magic[12]; + uint32_t rs_dummy4[5]; + unsigned char rs_uuid[16]; + char rs_label[16]; +} __attribute__((packed)); + +struct reiser4_super_block { + unsigned char rs4_magic[16]; + uint16_t rs4_dummy[2]; + unsigned char rs4_uuid[16]; + unsigned char rs4_label[16]; + uint64_t rs4_dummy2; +} __attribute__((packed)); + +static int probe_reiser(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct reiserfs_super_block *rs; + unsigned int blocksize; + + rs = blkid_probe_get_sb(pr, mag, struct reiserfs_super_block); + if (!rs) + return errno ? -errno : 1; + + blocksize = le16_to_cpu(rs->rs_blocksize); + + /* The blocksize must be at least 512B */ + if ((blocksize >> 9) == 0) + return 1; + + /* If the superblock is inside the journal, we have the wrong one */ + if (mag->kboff / (blocksize >> 9) > le32_to_cpu(rs->rs_journal_block) / 2) + return 1; + + /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ + if (mag->magic[6] == '2' || mag->magic[6] == '3') { + if (*rs->rs_label) + blkid_probe_set_label(pr, + (unsigned char *) rs->rs_label, + sizeof(rs->rs_label)); + blkid_probe_set_uuid(pr, rs->rs_uuid); + } + + if (mag->magic[6] == '3') + blkid_probe_set_version(pr, "JR"); + else if (mag->magic[6] == '2') + blkid_probe_set_version(pr, "3.6"); + else + blkid_probe_set_version(pr, "3.5"); + + return 0; +} + +static int probe_reiser4(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct reiser4_super_block *rs4; + + rs4 = blkid_probe_get_sb(pr, mag, struct reiser4_super_block); + if (!rs4) + return errno ? -errno : 1; + + if (*rs4->rs4_label) + blkid_probe_set_label(pr, rs4->rs4_label, sizeof(rs4->rs4_label)); + blkid_probe_set_uuid(pr, rs4->rs4_uuid); + blkid_probe_set_version(pr, "4"); + + return 0; +} + + +const struct blkid_idinfo reiser_idinfo = +{ + .name = "reiserfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_reiser, + .minsz = 128 * 1024, + .magics = + { + { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 0x34 }, + { .magic = "ReIsEr2Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsEr3Fs", .len = 9, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsErFs", .len = 8, .kboff = 64, .sboff = 0x34 }, + { .magic = "ReIsErFs", .len = 8, .kboff = 8, .sboff = 20 }, + { NULL } + } +}; + +const struct blkid_idinfo reiser4_idinfo = +{ + .name = "reiser4", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_reiser4, + .minsz = 128 * 1024, + .magics = + { + { .magic = "ReIsEr4", .len = 7, .kboff = 64 }, + { NULL } + } +}; + + + + diff --git a/libblkid/src/superblocks/romfs.c b/libblkid/src/superblocks/romfs.c new file mode 100644 index 000000000..8e63c100d --- /dev/null +++ b/libblkid/src/superblocks/romfs.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999, 2001 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +struct romfs_super_block { + unsigned char ros_magic[8]; + uint32_t ros_dummy1[2]; + unsigned char ros_volume[16]; +} __attribute__((packed)); + +static int probe_romfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct romfs_super_block *ros; + + ros = blkid_probe_get_sb(pr, mag, struct romfs_super_block); + if (!ros) + return errno ? -errno : 1; + + if (strlen((char *) ros->ros_volume)) + blkid_probe_set_label(pr, ros->ros_volume, + sizeof(ros->ros_volume)); + return 0; +} + +const struct blkid_idinfo romfs_idinfo = +{ + .name = "romfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_romfs, + .magics = + { + { .magic = "-rom1fs-", .len = 8 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/silicon_raid.c b/libblkid/src/superblocks/silicon_raid.c new file mode 100644 index 000000000..edbefbc09 --- /dev/null +++ b/libblkid/src/superblocks/silicon_raid.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> +#include <stddef.h> + +#include "superblocks.h" + +struct silicon_metadata { + uint8_t unknown0[0x2E]; + uint8_t ascii_version[0x36 - 0x2E]; + int8_t diskname[0x56 - 0x36]; + int8_t unknown1[0x60 - 0x56]; + uint32_t magic; + int8_t unknown1a[0x6C - 0x64]; + uint32_t array_sectors_low; + uint32_t array_sectors_high; + int8_t unknown2[0x78 - 0x74]; + uint32_t thisdisk_sectors; + int8_t unknown3[0x100 - 0x7C]; + int8_t unknown4[0x104 - 0x100]; + uint16_t product_id; + uint16_t vendor_id; + uint16_t minor_ver; + uint16_t major_ver; + uint8_t seconds; + uint8_t minutes; + uint8_t hour; + uint8_t day; + uint8_t month; + uint8_t year; + uint16_t raid0_stride; + int8_t unknown6[0x116 - 0x114]; + uint8_t disk_number; + uint8_t type; /* SILICON_TYPE_* */ + int8_t drives_per_striped_set; + int8_t striped_set_number; + int8_t drives_per_mirrored_set; + int8_t mirrored_set_number; + uint32_t rebuild_ptr_low; + uint32_t rebuild_ptr_high; + uint32_t incarnation_no; + uint8_t member_status; + uint8_t mirrored_set_state; /* SILICON_MIRROR_* */ + uint8_t reported_device_location; + uint8_t idechannel; + uint8_t auto_rebuild; + uint8_t unknown8; + uint8_t text_type[0x13E - 0x12E]; + uint16_t checksum1; + int8_t assumed_zeros[0x1FE - 0x140]; + uint16_t checksum2; +} __attribute__((packed)); + +#define SILICON_MAGIC 0x2F000000 + +static uint16_t silraid_checksum(struct silicon_metadata *sil) +{ + int sum = 0; + unsigned short count = offsetof(struct silicon_metadata, checksum1) / 2; + uint16_t *p = (uint16_t *) sil; + + while (count--) { + uint16_t x = *p++; + sum += le16_to_cpu(x); + } + + return (-sum & 0xFFFF); +} + +static int probe_silraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct silicon_metadata *sil; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200) - 1) * 0x200; + + sil = (struct silicon_metadata *) + blkid_probe_get_buffer(pr, off, + sizeof(struct silicon_metadata)); + if (!sil) + return errno ? -errno : 1; + + if (le32_to_cpu(sil->magic) != SILICON_MAGIC) + return 1; + if (sil->disk_number >= 8) + return 1; + if (!blkid_probe_verify_csum(pr, silraid_checksum(sil), le16_to_cpu(sil->checksum1))) + return 1; + + if (blkid_probe_sprintf_version(pr, "%u.%u", + le16_to_cpu(sil->major_ver), + le16_to_cpu(sil->minor_ver)) != 0) + return 1; + + if (blkid_probe_set_magic(pr, + off + offsetof(struct silicon_metadata, magic), + sizeof(sil->magic), + (unsigned char *) &sil->magic)) + return 1; + return 0; +} + +const struct blkid_idinfo silraid_idinfo = { + .name = "silicon_medley_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_silraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/squashfs.c b/libblkid/src/superblocks/squashfs.c new file mode 100644 index 000000000..8ed28385f --- /dev/null +++ b/libblkid/src/superblocks/squashfs.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "bitops.h" /* swab16() */ +#include "superblocks.h" + +struct sqsh_super_block { + uint32_t s_magic; + uint32_t inodes; + uint32_t bytes_used_2; + uint32_t uid_start_2; + uint32_t guid_start_2; + uint32_t inode_table_start_2; + uint32_t directory_table_start_2; + uint16_t s_major; + uint16_t s_minor; +} __attribute__((packed)); + +static int probe_squashfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct sqsh_super_block *sq; + uint16_t major; + uint16_t minor; + + sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block); + if (!sq) + return errno ? -errno : 1; + + major = le16_to_cpu(sq->s_major); + minor = le16_to_cpu(sq->s_minor); + if (major < 4) + return 1; + + blkid_probe_sprintf_version(pr, "%u.%u", major, minor); + + return 0; +} + +static int probe_squashfs3(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct sqsh_super_block *sq; + uint16_t major; + uint16_t minor; + + sq = blkid_probe_get_sb(pr, mag, struct sqsh_super_block); + if (!sq) + return errno ? -errno : 1; + + if (strcmp(mag->magic, "sqsh") == 0) { + major = be16_to_cpu(sq->s_major); + minor = be16_to_cpu(sq->s_minor); + } else { + major = le16_to_cpu(sq->s_major); + minor = le16_to_cpu(sq->s_minor); + } + + if (major > 3) + return 1; + + blkid_probe_sprintf_version(pr, "%u.%u", major, minor); + + return 0; +} + +const struct blkid_idinfo squashfs_idinfo = +{ + .name = "squashfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_squashfs, + .magics = + { + { .magic = "hsqs", .len = 4 }, + { NULL } + } +}; + +const struct blkid_idinfo squashfs3_idinfo = +{ + .name = "squashfs3", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_squashfs3, + .magics = + { + { .magic = "sqsh", .len = 4 }, /* big endian */ + { .magic = "hsqs", .len = 4 }, /* little endian */ + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c new file mode 100644 index 000000000..80bd6e596 --- /dev/null +++ b/libblkid/src/superblocks/superblocks.c @@ -0,0 +1,813 @@ +/* + * superblocks.c - reads information from filesystem and raid superblocks + * + * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdint.h> +#include <stdarg.h> + +#include "superblocks.h" + +/** + * SECTION:superblocks + * @title: Superblocks probing + * @short_description: filesystems and raids superblocks probing. + * + * The library API has been originally designed for superblocks probing only. + * This is reason why some *deprecated* superblock specific functions don't use + * '_superblocks_' namespace in the function name. Please, don't use these + * functions in new code. + * + * The 'superblocks' probers support NAME=value (tags) interface only. The + * superblocks probing is enabled by default (and controlled by + * blkid_probe_enable_superblocks()). + * + * Currently supported tags: + * + * @TYPE: filesystem type + * + * @SEC_TYPE: secondary filesystem type + * + * @LABEL: filesystem label + * + * @LABEL_RAW: raw label from FS superblock + * + * @UUID: filesystem UUID (lower case) + * + * @UUID_SUB: subvolume uuid (e.g. btrfs) + * + * @LOGUUID: external log UUID (e.g. xfs) + * + * @UUID_RAW: raw UUID from FS superblock + * + * @EXT_JOURNAL: external journal UUID + * + * @USAGE: usage string: "raid", "filesystem", ... + * + * @VERSION: filesystem version + * + * @MOUNT: cluster mount name (?) -- ocfs only + * + * @SBMAGIC: super block magic string + * + * @SBMAGIC_OFFSET: offset of SBMAGIC + * + * @FSSIZE: size of filessystem [not-implemented yet] + * + * @SYSTEM_ID: ISO9660 system identifier + * + * @PUBLISHER_ID: ISO9660 publisher identifier + * + * @APPLICATION_ID: ISO9660 application identifier + * + * @BOOT_SYSTEM_ID: ISO9660 boot system identifier + */ + +static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn); +static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn); + +static int blkid_probe_set_usage(blkid_probe pr, int usage); + + +/* + * Superblocks chains probing functions + */ +static const struct blkid_idinfo *idinfos[] = +{ + /* RAIDs */ + &linuxraid_idinfo, + &ddfraid_idinfo, + &iswraid_idinfo, + &lsiraid_idinfo, + &viaraid_idinfo, + &silraid_idinfo, + &nvraid_idinfo, + &pdcraid_idinfo, + &highpoint45x_idinfo, + &highpoint37x_idinfo, + &adraid_idinfo, + &jmraid_idinfo, + + &bcache_idinfo, + &drbd_idinfo, + &drbdproxy_datalog_idinfo, + &lvm2_idinfo, + &lvm1_idinfo, + &snapcow_idinfo, + &verity_hash_idinfo, + &luks_idinfo, + &vmfs_volume_idinfo, + + /* Filesystems */ + &vfat_idinfo, + &swsuspend_idinfo, + &swap_idinfo, + &xfs_idinfo, + &xfs_log_idinfo, + &ext4dev_idinfo, + &ext4_idinfo, + &ext3_idinfo, + &ext2_idinfo, + &jbd_idinfo, + &reiser_idinfo, + &reiser4_idinfo, + &jfs_idinfo, + &udf_idinfo, + &iso9660_idinfo, + &zfs_idinfo, + &hfsplus_idinfo, + &hfs_idinfo, + &ufs_idinfo, + &hpfs_idinfo, + &sysv_idinfo, + &xenix_idinfo, + &ntfs_idinfo, + &refs_idinfo, + &cramfs_idinfo, + &romfs_idinfo, + &minix_idinfo, + &gfs_idinfo, + &gfs2_idinfo, + &ocfs_idinfo, + &ocfs2_idinfo, + &oracleasm_idinfo, + &vxfs_idinfo, + &squashfs_idinfo, + &squashfs3_idinfo, + &netware_idinfo, + &btrfs_idinfo, + &ubifs_idinfo, + &bfs_idinfo, + &vmfs_fs_idinfo, + &befs_idinfo, + &nilfs2_idinfo, + &exfat_idinfo, + &f2fs_idinfo +}; + +/* + * Driver definition + */ +const struct blkid_chaindrv superblocks_drv = { + .id = BLKID_CHAIN_SUBLKS, + .name = "superblocks", + .dflt_enabled = TRUE, + .dflt_flags = BLKID_SUBLKS_DEFAULT, + .idinfos = idinfos, + .nidinfos = ARRAY_SIZE(idinfos), + .has_fltr = TRUE, + .probe = superblocks_probe, + .safeprobe = superblocks_safeprobe, +}; + +/** + * blkid_probe_enable_superblocks: + * @pr: probe + * @enable: TRUE/FALSE + * + * Enables/disables the superblocks probing for non-binary interface. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_enable_superblocks(blkid_probe pr, int enable) +{ + if (!pr) + return -1; + pr->chains[BLKID_CHAIN_SUBLKS].enabled = enable; + return 0; +} + +/** + * blkid_probe_set_superblocks_flags: + * @pr: prober + * @flags: BLKID_SUBLKS_* flags + * + * Sets probing flags to the superblocks prober. This function is optional, the + * default are BLKID_SUBLKS_DEFAULTS flags. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags) +{ + if (!pr) + return -1; + + pr->chains[BLKID_CHAIN_SUBLKS].flags = flags; + return 0; +} + +/** + * blkid_probe_reset_superblocks_filter: + * @pr: prober + * + * Resets superblocks probing filter + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_reset_superblocks_filter(blkid_probe pr) +{ + return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS); +} + +/** + * blkid_probe_invert_superblocks_filter: + * @pr: prober + * + * Inverts superblocks probing filter + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_invert_superblocks_filter(blkid_probe pr) +{ + return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS); +} + +/** + * blkid_probe_filter_superblocks_type: + * @pr: prober + * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag + * @names: NULL terminated array of probing function names (e.g. "vfat"). + * + * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names; + * + * %BLKID_FLTR_ONLYIN - probe for items which are IN @names + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]) +{ + return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names); +} + +/** + * blkid_probe_filter_superblocks_usage: + * @pr: prober + * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag + * @usage: BLKID_USAGE_* flags + * + * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @usage; + * + * %BLKID_FLTR_ONLYIN - probe for items which are IN @usage + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage) +{ + unsigned long *fltr; + struct blkid_chain *chn; + size_t i; + + fltr = blkid_probe_get_filter(pr, BLKID_CHAIN_SUBLKS, TRUE); + if (!fltr) + return -1; + + chn = &pr->chains[BLKID_CHAIN_SUBLKS]; + + for (i = 0; i < chn->driver->nidinfos; i++) { + const struct blkid_idinfo *id = chn->driver->idinfos[i]; + + if (id->usage & usage) { + if (flag & BLKID_FLTR_NOTIN) + blkid_bmp_set_item(chn->fltr, i); + } else if (flag & BLKID_FLTR_ONLYIN) + blkid_bmp_set_item(chn->fltr, i); + } + DBG(LOWPROBE, ul_debug("a new probing usage-filter initialized")); + return 0; +} + +/** + * blkid_known_fstype: + * @fstype: filesystem name + * + * Returns: 1 for known filesytems, or 0 for unknown filesystem. + */ +int blkid_known_fstype(const char *fstype) +{ + size_t i; + + if (!fstype) + return 0; + + for (i = 0; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + if (strcmp(id->name, fstype) == 0) + return 1; + } + return 0; +} + +/** + * blkid_superblocks_get_name: + * @idx: number >= 0 + * @name: returns name of supported filesystem/raid (optional) + * @usage: returns BLKID_USAGE_* flags, (optional) + * + * Returns: -1 if @idx is out of range, or 0 on success. + */ +int blkid_superblocks_get_name(size_t idx, const char **name, int *usage) +{ + if (idx < ARRAY_SIZE(idinfos)) { + if (name) + *name = idinfos[idx]->name; + if (usage) + *usage = idinfos[idx]->usage; + return 0; + } + return -1; +} + +/* + * The blkid_do_probe() backend. + */ +static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) +{ + size_t i; + int rc = BLKID_PROBE_NONE; + + if (!pr || chn->idx < -1) + return -EINVAL; + + blkid_probe_chain_reset_vals(pr, chn); + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return BLKID_PROBE_NONE; + + if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode))) + /* Ignore very very small block devices or regular files (e.g. + * extended partitions). Note that size of the UBI char devices + * is 1 byte */ + return BLKID_PROBE_NONE; + + DBG(LOWPROBE, ul_debug("--> starting probing loop [SUBLKS idx=%d]", + chn->idx)); + + i = chn->idx < 0 ? 0 : chn->idx + 1U; + + for ( ; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id; + const struct blkid_idmag *mag = NULL; + blkid_loff_t off = 0; + + chn->idx = i; + id = idinfos[i]; + + if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) { + DBG(LOWPROBE, ul_debug("filter out: %s", id->name)); + rc = BLKID_PROBE_NONE; + continue; + } + + if (id->minsz && id->minsz > pr->size) { + rc = BLKID_PROBE_NONE; + continue; /* the device is too small */ + } + + /* don't probe for RAIDs, swap or journal on CD/DVDs */ + if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) && + blkid_probe_is_cdrom(pr)) { + rc = BLKID_PROBE_NONE; + continue; + } + + /* don't probe for RAIDs on floppies */ + if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) { + rc = BLKID_PROBE_NONE; + continue; + } + + DBG(LOWPROBE, ul_debug("[%zd] %s:", i, id->name)); + + rc = blkid_probe_get_idmag(pr, id, &off, &mag); + if (rc < 0) + break; + if (rc != BLKID_PROBE_OK) + continue; + + /* final check by probing function */ + if (id->probefunc) { + DBG(LOWPROBE, ul_debug("\tcall probefunc()")); + rc = id->probefunc(pr, mag); + if (rc != BLKID_PROBE_OK) { + blkid_probe_chain_reset_vals(pr, chn); + if (rc < 0) + break; + continue; + } + } + + /* all cheks passed */ + if (chn->flags & BLKID_SUBLKS_TYPE) + rc = blkid_probe_set_value(pr, "TYPE", + (unsigned char *) id->name, + strlen(id->name) + 1); + + if (!rc) + rc = blkid_probe_set_usage(pr, id->usage); + + if (!rc && mag) + rc = blkid_probe_set_magic(pr, off, mag->len, + (unsigned char *) mag->magic); + if (rc) { + blkid_probe_chain_reset_vals(pr, chn); + DBG(LOWPROBE, ul_debug("failed to set result -- ignore")); + continue; + } + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]", + id->name, chn->idx)); + return BLKID_PROBE_OK; + } + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [SUBLKS idx=%d]", + rc, chn->idx)); + return rc; +} + +/* + * This is the same function as blkid_do_probe(), but returns only one result + * (cannot be used in while()) and checks for ambivalen results (more + * filesystems on the device) -- in such case returns -2. + * + * The function does not check for filesystems when a RAID or crypto signature + * is detected. The function also does not check for collision between RAIDs + * and crypto devices. The first detected RAID or crypto device is returned. + * + * The function does not probe for ambivalent results on very small devices + * (e.g. floppies), on small devices the first detected filesystem is returned. + */ +static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) +{ + struct blkid_prval vals[BLKID_NVALS_SUBLKS]; + int nvals = BLKID_NVALS_SUBLKS; + int idx = -1; + int count = 0; + int intol = 0; + int rc; + + if (pr->flags & BLKID_FL_NOSCAN_DEV) + return BLKID_PROBE_NONE; + + while ((rc = superblocks_probe(pr, chn)) == 0) { + + if (blkid_probe_is_tiny(pr) && !count) + return BLKID_PROBE_OK; /* floppy or so -- returns the first result. */ + + count++; + + if (chn->idx >= 0 && + idinfos[chn->idx]->usage & (BLKID_USAGE_RAID | BLKID_USAGE_CRYPTO)) + break; + + if (chn->idx >= 0 && + !(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT)) + intol++; + + if (count == 1) { + /* save the first result */ + nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals); + idx = chn->idx; + } + } + + if (rc < 0) + return rc; /* error */ + + if (count > 1 && intol) { + DBG(LOWPROBE, ul_debug("ERROR: superblocks chain: " + "ambivalent result detected (%d filesystems)!", + count)); + return -2; /* error, ambivalent result (more FS) */ + } + if (!count) + return BLKID_PROBE_NONE; + + if (idx != -1) { + /* restore the first result */ + blkid_probe_chain_reset_vals(pr, chn); + blkid_probe_append_vals(pr, vals, nvals); + chn->idx = idx; + } + + /* + * The RAID device could be partitioned. The problem are RAID1 devices + * where the partition table is visible from underlaying devices. We + * have to ignore such partition tables. + */ + if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID) + pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT; + + return BLKID_PROBE_OK; +} + +int blkid_probe_set_version(blkid_probe pr, const char *version) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (chn->flags & BLKID_SUBLKS_VERSION) + return blkid_probe_set_value(pr, "VERSION", + (unsigned char *) version, strlen(version) + 1); + return 0; +} + + +int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + int rc = 0; + + if (chn->flags & BLKID_SUBLKS_VERSION) { + va_list ap; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap); + va_end(ap); + } + return rc; +} + +static int blkid_probe_set_usage(blkid_probe pr, int usage) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + char *u = NULL; + + if (!(chn->flags & BLKID_SUBLKS_USAGE)) + return 0; + + if (usage & BLKID_USAGE_FILESYSTEM) + u = "filesystem"; + else if (usage & BLKID_USAGE_RAID) + u = "raid"; + else if (usage & BLKID_USAGE_CRYPTO) + u = "crypto"; + else if (usage & BLKID_USAGE_OTHER) + u = "other"; + else + u = "unknown"; + + return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1); +} + +int blkid_probe_set_id_label(blkid_probe pr, const char *name, + unsigned char *data, size_t len) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + + if (!(chn->flags & BLKID_SUBLKS_LABEL)) + return 0; + + v = blkid_probe_assign_value(pr, name); + if (!v) + return -1; + + if (len >= BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ - 1; /* make a space for \0 */ + + memcpy(v->data, data, len); + v->data[len] = '\0'; + + /* remove white spaces */ + v->len = blkid_rtrim_whitespace(v->data) + 1; + if (v->len > 1) + v->len = blkid_ltrim_whitespace(v->data) + 1; + + if (v->len <= 1) + blkid_probe_reset_last_value(pr); /* ignore empty */ + return 0; +} + +int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if ((chn->flags & BLKID_SUBLKS_LABELRAW) && + blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) + return -1; + if (!(chn->flags & BLKID_SUBLKS_LABEL)) + return 0; + v = blkid_probe_assign_value(pr, "LABEL"); + if (!v) + return -1; + + if (len == BLKID_PROBVAL_BUFSIZ) + len--; /* make a space for \0 */ + + memcpy(v->data, label, len); + v->data[len] = '\0'; + + v->len = blkid_rtrim_whitespace(v->data) + 1; + if (v->len == 1) + blkid_probe_reset_last_value(pr); + return 0; +} + +int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, + size_t len, int enc) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + + if ((chn->flags & BLKID_SUBLKS_LABELRAW) && + blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) + return -1; + if (!(chn->flags & BLKID_SUBLKS_LABEL)) + return 0; + v = blkid_probe_assign_value(pr, "LABEL"); + if (!v) + return -1; + + blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len); + v->len = blkid_rtrim_whitespace(v->data) + 1; + if (v->len == 1) + blkid_probe_reset_last_value(pr); + return 0; +} + +int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, + size_t len, const char *fmt, ...) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + int rc = -1; + va_list ap; + + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if (blkid_uuid_is_empty(uuid, len)) + return 0; + + if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0) + return -1; + if (!(chn->flags & BLKID_SUBLKS_UUID)) + return 0; + + va_start(ap, fmt); + rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap); + va_end(ap); + + /* convert to lower case (..be paranoid) */ + if (!rc) { + size_t i; + struct blkid_prval *v = __blkid_probe_get_value(pr, + blkid_probe_numof_values(pr)); + if (v) { + for (i = 0; i < v->len; i++) + if (v->data[i] >= 'A' && v->data[i] <= 'F') + v->data[i] = (v->data[i] - 'A') + 'a'; + } + } + return rc; +} + +/* function to set UUIDs that are in suberblocks stored as strings */ +int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + + if (str == NULL || *str == '\0') + return -1; + if (!len) + len = strlen((char *) str); + if (len > BLKID_PROBVAL_BUFSIZ) + len = BLKID_PROBVAL_BUFSIZ; + + if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0) + return -1; + if (!(chn->flags & BLKID_SUBLKS_UUID)) + return 0; + + v = blkid_probe_assign_value(pr, "UUID"); + if (v) { + if (len == BLKID_PROBVAL_BUFSIZ) + len--; /* make a space for \0 */ + + memcpy((char *) v->data, str, len); + v->data[len] = '\0'; + v->len = len + 1; + return 0; + } + return -1; +} + +/* default _set_uuid function to set DCE UUIDs */ +int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + struct blkid_prval *v; + + if (blkid_uuid_is_empty(uuid, 16)) + return 0; + + if (!name) { + if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && + blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0) + return -1; + if (!(chn->flags & BLKID_SUBLKS_UUID)) + return 0; + + v = blkid_probe_assign_value(pr, "UUID"); + } else + v = blkid_probe_assign_value(pr, name); + + blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data)); + v->len = 37; + + return 0; +} + +int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid) +{ + return blkid_probe_set_uuid_as(pr, uuid, NULL); +} + +/** + * blkid_probe_set_request: + * @pr: probe + * @flags: BLKID_PROBREQ_* (deprecated) or BLKID_SUBLKS_* flags + * + * Returns: 0 on success, or -1 in case of error. + * + * Deprecated: Use blkid_probe_set_superblocks_flags(). + */ +int blkid_probe_set_request(blkid_probe pr, int flags) +{ + return blkid_probe_set_superblocks_flags(pr, flags); +} + +/** + * blkid_probe_reset_filter: + * @pr: prober + * + * Returns: 0 on success, or -1 in case of error. + * + * Deprecated: Use blkid_probe_reset_superblocks_filter(). + */ +int blkid_probe_reset_filter(blkid_probe pr) +{ + return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS); +} + +/** + * blkid_probe_invert_filter: + * @pr: prober + * + * Returns: 0 on success, or -1 in case of error. + * + * Deprecated: Use blkid_probe_invert_superblocks_filter(). + */ +int blkid_probe_invert_filter(blkid_probe pr) +{ + return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS); +} + +/** + * blkid_probe_filter_types + * @pr: prober + * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag + * @names: NULL terminated array of probing function names (e.g. "vfat"). + * + * Returns: 0 on success, or -1 in case of error. + * + * Deprecated: Use blkid_probe_filter_superblocks_types(). + */ +int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) +{ + return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names); +} + +/** + * blkid_probe_filter_usage + * @pr: prober + * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag + * @usage: BLKID_USAGE_* flags + * + * Returns: 0 on success, or -1 in case of error. + * + * Deprecated: Use blkid_probe_filter_superblocks_usage(). + */ +int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) +{ + return blkid_probe_filter_superblocks_usage(pr, flag, usage); +} + + diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h new file mode 100644 index 000000000..3bbfb9c19 --- /dev/null +++ b/libblkid/src/superblocks/superblocks.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#ifndef _BLKID_SUPERBLOCKS_H +#define _BLKID_SUPERBLOCKS_H + +#include "blkidP.h" + +extern const struct blkid_idinfo cramfs_idinfo; +extern const struct blkid_idinfo swap_idinfo; +extern const struct blkid_idinfo swsuspend_idinfo; +extern const struct blkid_idinfo adraid_idinfo; +extern const struct blkid_idinfo ddfraid_idinfo; +extern const struct blkid_idinfo iswraid_idinfo; +extern const struct blkid_idinfo jmraid_idinfo; +extern const struct blkid_idinfo lsiraid_idinfo; +extern const struct blkid_idinfo nvraid_idinfo; +extern const struct blkid_idinfo pdcraid_idinfo; +extern const struct blkid_idinfo silraid_idinfo; +extern const struct blkid_idinfo viaraid_idinfo; +extern const struct blkid_idinfo linuxraid_idinfo; +extern const struct blkid_idinfo ext4dev_idinfo; +extern const struct blkid_idinfo ext4_idinfo; +extern const struct blkid_idinfo ext3_idinfo; +extern const struct blkid_idinfo ext2_idinfo; +extern const struct blkid_idinfo jbd_idinfo; +extern const struct blkid_idinfo jfs_idinfo; +extern const struct blkid_idinfo xfs_idinfo; +extern const struct blkid_idinfo xfs_log_idinfo; +extern const struct blkid_idinfo gfs_idinfo; +extern const struct blkid_idinfo gfs2_idinfo; +extern const struct blkid_idinfo romfs_idinfo; +extern const struct blkid_idinfo ocfs_idinfo; +extern const struct blkid_idinfo ocfs2_idinfo; +extern const struct blkid_idinfo oracleasm_idinfo; +extern const struct blkid_idinfo reiser_idinfo; +extern const struct blkid_idinfo reiser4_idinfo; +extern const struct blkid_idinfo hfs_idinfo; +extern const struct blkid_idinfo hfsplus_idinfo; +extern const struct blkid_idinfo ntfs_idinfo; +extern const struct blkid_idinfo refs_idinfo; +extern const struct blkid_idinfo iso9660_idinfo; +extern const struct blkid_idinfo udf_idinfo; +extern const struct blkid_idinfo vxfs_idinfo; +extern const struct blkid_idinfo minix_idinfo; +extern const struct blkid_idinfo vfat_idinfo; +extern const struct blkid_idinfo ufs_idinfo; +extern const struct blkid_idinfo hpfs_idinfo; +extern const struct blkid_idinfo lvm2_idinfo; +extern const struct blkid_idinfo lvm1_idinfo; +extern const struct blkid_idinfo snapcow_idinfo; +extern const struct blkid_idinfo verity_hash_idinfo; +extern const struct blkid_idinfo luks_idinfo; +extern const struct blkid_idinfo highpoint37x_idinfo; +extern const struct blkid_idinfo highpoint45x_idinfo; +extern const struct blkid_idinfo squashfs_idinfo; +extern const struct blkid_idinfo squashfs3_idinfo; +extern const struct blkid_idinfo netware_idinfo; +extern const struct blkid_idinfo sysv_idinfo; +extern const struct blkid_idinfo xenix_idinfo; +extern const struct blkid_idinfo btrfs_idinfo; +extern const struct blkid_idinfo ubifs_idinfo; +extern const struct blkid_idinfo zfs_idinfo; +extern const struct blkid_idinfo bfs_idinfo; +extern const struct blkid_idinfo vmfs_volume_idinfo; +extern const struct blkid_idinfo vmfs_fs_idinfo; +extern const struct blkid_idinfo drbd_idinfo; +extern const struct blkid_idinfo drbdproxy_datalog_idinfo; +extern const struct blkid_idinfo befs_idinfo; +extern const struct blkid_idinfo nilfs2_idinfo; +extern const struct blkid_idinfo exfat_idinfo; +extern const struct blkid_idinfo f2fs_idinfo; +extern const struct blkid_idinfo bcache_idinfo; + +/* + * superblock functions + */ +extern int blkid_probe_set_version(blkid_probe pr, const char *version); +extern int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + +extern int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len); +extern int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, + size_t len, int enc); +extern int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, + size_t len, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +extern int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len); + +extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid); +extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name); + +extern int blkid_probe_set_id_label(blkid_probe pr, const char *name, + unsigned char *data, size_t len); + +#endif /* _BLKID_SUPERBLOCKS_H */ diff --git a/libblkid/src/superblocks/swap.c b/libblkid/src/superblocks/swap.c new file mode 100644 index 000000000..3f21391c8 --- /dev/null +++ b/libblkid/src/superblocks/swap.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +/* linux-2.6/include/linux/swap.h */ +struct swap_header_v1_2 { + /* char bootbits[1024]; */ /* Space for disklabel etc. */ + uint32_t version; + uint32_t lastpage; + uint32_t nr_badpages; + unsigned char uuid[16]; + unsigned char volume[16]; + uint32_t padding[117]; + uint32_t badpages[1]; +} __attribute__((packed)); + +#define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */ +#define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */ + +#define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c" +#define TOI_MAGIC_STRLEN (sizeof(TOI_MAGIC_STRING) - 1) + +static int swap_set_info(blkid_probe pr, const char *version) +{ + struct swap_header_v1_2 *hdr; + + /* Swap header always located at offset of 1024 bytes */ + hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, + sizeof(struct swap_header_v1_2)); + if (!hdr) + return errno ? -errno : 1; + + /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ + if (strcmp(version, "1") == 0) { + if (hdr->version != 1 && swab32(hdr->version) != 1) { + DBG(LOWPROBE, ul_debug("incorrect swap version")); + return 1; + } + if (hdr->lastpage == 0) { + DBG(LOWPROBE, ul_debug("not set last swap page")); + return 1; + } + } + + /* arbitrary sanity check.. is there any garbage down there? */ + if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { + if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, + sizeof(hdr->volume)) < 0) + return 1; + if (blkid_probe_set_uuid(pr, hdr->uuid) < 0) + return 1; + } + + blkid_probe_set_version(pr, version); + return 0; +} + +static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag) +{ + unsigned char *buf; + + if (!mag) + return 1; + + /* TuxOnIce keeps valid swap header at the end of the 1st page */ + buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN); + if (!buf) + return errno ? -errno : 1; + + if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0) + return 1; /* Ignore swap signature, it's TuxOnIce */ + + if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) { + /* swap v0 doesn't support LABEL or UUID */ + blkid_probe_set_version(pr, "0"); + return 0; + + } else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) + return swap_set_info(pr, "1"); + + return 1; +} + +static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) +{ + if (!mag) + return 1; + if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) + return swap_set_info(pr, "s1suspend"); + if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) + return swap_set_info(pr, "s2suspend"); + if (!memcmp(mag->magic, "ULSUSPEND", mag->len)) + return swap_set_info(pr, "ulsuspend"); + if (!memcmp(mag->magic, TOI_MAGIC_STRING, mag->len)) + return swap_set_info(pr, "tuxonice"); + if (!memcmp(mag->magic, "LINHIB0001", mag->len)) + return swap_set_info(pr, "linhib0001"); + + return 1; /* no signature detected */ +} + +const struct blkid_idinfo swap_idinfo = +{ + .name = "swap", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_swap, + .minsz = 10 * 4096, /* 10 pages */ + .magics = + { + { "SWAP-SPACE", 10, 0, 0xff6 }, + { "SWAPSPACE2", 10, 0, 0xff6 }, + { "SWAP-SPACE", 10, 0, 0x1ff6 }, + { "SWAPSPACE2", 10, 0, 0x1ff6 }, + { "SWAP-SPACE", 10, 0, 0x3ff6 }, + { "SWAPSPACE2", 10, 0, 0x3ff6 }, + { "SWAP-SPACE", 10, 0, 0x7ff6 }, + { "SWAPSPACE2", 10, 0, 0x7ff6 }, + { "SWAP-SPACE", 10, 0, 0xfff6 }, + { "SWAPSPACE2", 10, 0, 0xfff6 }, + { NULL } + } +}; + + +const struct blkid_idinfo swsuspend_idinfo = +{ + .name = "swsuspend", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_swsuspend, + .minsz = 10 * 4096, /* 10 pages */ + .magics = + { + { TOI_MAGIC_STRING, TOI_MAGIC_STRLEN, 0, 0 }, + { "S1SUSPEND", 9, 0, 0xff6 }, + { "S2SUSPEND", 9, 0, 0xff6 }, + { "ULSUSPEND", 9, 0, 0xff6 }, + { "LINHIB0001",10,0, 0xff6 }, + + { "S1SUSPEND", 9, 0, 0x1ff6 }, + { "S2SUSPEND", 9, 0, 0x1ff6 }, + { "ULSUSPEND", 9, 0, 0x1ff6 }, + { "LINHIB0001",10,0, 0x1ff6 }, + + { "S1SUSPEND", 9, 0, 0x3ff6 }, + { "S2SUSPEND", 9, 0, 0x3ff6 }, + { "ULSUSPEND", 9, 0, 0x3ff6 }, + { "LINHIB0001",10,0, 0x3ff6 }, + + { "S1SUSPEND", 9, 0, 0x7ff6 }, + { "S2SUSPEND", 9, 0, 0x7ff6 }, + { "ULSUSPEND", 9, 0, 0x7ff6 }, + { "LINHIB0001",10,0, 0x7ff6 }, + + { "S1SUSPEND", 9, 0, 0xfff6 }, + { "S2SUSPEND", 9, 0, 0xfff6 }, + { "ULSUSPEND", 9, 0, 0xfff6 }, + { "LINHIB0001",10,0, 0xfff6 }, + + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/sysv.c b/libblkid/src/superblocks/sysv.c new file mode 100644 index 000000000..4b345910e --- /dev/null +++ b/libblkid/src/superblocks/sysv.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This is written from sratch according to Linux kernel fs/sysv/super.c file. + * It seems that sysv probing code in libvolume_id and also in the original + * blkid is useless. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <stddef.h> + +#include "superblocks.h" + +#define XENIX_NICINOD 100 +#define XENIX_NICFREE 100 + +struct xenix_super_block { + uint16_t s_isize; + uint32_t s_fsize; + uint16_t s_nfree; + uint32_t s_free[XENIX_NICFREE]; + uint16_t s_ninode; + uint16_t s_inode[XENIX_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_dinfo[4]; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint8_t s_clean; + uint8_t s_fill[371]; + uint32_t s_magic; + uint32_t s_type; +} __attribute__((packed)); + + +#define SYSV_NICINOD 100 +#define SYSV_NICFREE 50 + +struct sysv_super_block +{ + uint16_t s_isize; + uint16_t s_pad0; + uint32_t s_fsize; + uint16_t s_nfree; + uint16_t s_pad1; + uint32_t s_free[SYSV_NICFREE]; + uint16_t s_ninode; + uint16_t s_pad2; + uint16_t s_inode[SYSV_NICINOD]; + uint8_t s_flock; + uint8_t s_ilock; + uint8_t s_fmod; + uint8_t s_ronly; + uint32_t s_time; + uint16_t s_dinfo[4]; + uint32_t s_tfree; + uint16_t s_tinode; + uint16_t s_pad3; + uint8_t s_fname[6]; + uint8_t s_fpack[6]; + uint32_t s_fill[12]; + uint32_t s_state; + uint32_t s_magic; + uint32_t s_type; +}; + +static int probe_xenix(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct xenix_super_block *sb; + + sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block); + if (!sb) + return errno ? -errno : 1; + blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname)); + return 0; +} + +#define SYSV_BLOCK_SIZE 1024 + +/* Note that we don't probe for Coherent FS, this FS does not have + * magic string. (It requires to probe fname/fpack field..) + */ +static int probe_sysv(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct sysv_super_block *sb; + int blocks[] = {0, 9, 15, 18}; + size_t i; + + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + int off = blocks[i] * SYSV_BLOCK_SIZE + SYSV_BLOCK_SIZE/2; + + sb = (struct sysv_super_block *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct sysv_super_block)); + if (!sb) + return errno ? -errno : 1; + + if (sb->s_magic == cpu_to_le32(0xfd187e20) || + sb->s_magic == cpu_to_be32(0xfd187e20)) { + + if (blkid_probe_set_label(pr, sb->s_fname, + sizeof(sb->s_fname))) + return 1; + + if (blkid_probe_set_magic(pr, + off + offsetof(struct sysv_super_block, + s_magic), + sizeof(sb->s_magic), + (unsigned char *) &sb->s_magic)) + return 1; + + return 0; + } + } + return 1; +} + +const struct blkid_idinfo xenix_idinfo = +{ + .name = "xenix", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_xenix, + .magics = + { + { .magic = "\x2b\x55\x44", .len = 3, .kboff = 1, .sboff = 0x400 }, + { .magic = "\x44\x55\x2b", .len = 3, .kboff = 1, .sboff = 0x400 }, + { NULL } + } +}; + +const struct blkid_idinfo sysv_idinfo = +{ + .name = "sysv", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_sysv, + + /* SYSV is BE and LE and superblock could be on four positions. It's + * simpler to probe for the magic string by .probefunc(). + */ + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/superblocks/ubifs.c b/libblkid/src/superblocks/ubifs.c new file mode 100644 index 000000000..dc8426063 --- /dev/null +++ b/libblkid/src/superblocks/ubifs.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009 Corentin Chary <corentincj@iksaif.net> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> + +#include "superblocks.h" + +/* + * struct ubifs_ch - common header node. + * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) + * @crc: CRC-32 checksum of the node header + * @sqnum: sequence number + * @len: full node length + * @node_type: node type + * @group_type: node group type + * @padding: reserved for future, zeroes + * + * Every UBIFS node starts with this common part. If the node has a key, the + * key always goes next. + */ +struct ubifs_ch { + uint32_t magic; + uint32_t crc; + uint64_t sqnum; + uint32_t len; + uint8_t node_type; + uint8_t group_type; + uint8_t padding[2]; +} __attribute__ ((packed)); + +/* + * struct ubifs_sb_node - superblock node. + * @ch: common header + * @padding: reserved for future, zeroes + * @key_hash: type of hash function used in keys + * @key_fmt: format of the key + * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) + * @min_io_size: minimal input/output unit size + * @leb_size: logical eraseblock size in bytes + * @leb_cnt: count of LEBs used by file-system + * @max_leb_cnt: maximum count of LEBs used by file-system + * @max_bud_bytes: maximum amount of data stored in buds + * @log_lebs: log size in logical eraseblocks + * @lpt_lebs: number of LEBs used for lprops table + * @orph_lebs: number of LEBs used for recording orphans + * @jhead_cnt: count of journal heads + * @fanout: tree fanout (max. number of links per indexing node) + * @lsave_cnt: number of LEB numbers in LPT's save table + * @fmt_version: UBIFS on-flash format version + * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) + * @padding1: reserved for future, zeroes + * @rp_uid: reserve pool UID + * @rp_gid: reserve pool GID + * @rp_size: size of the reserved pool in bytes + * @padding2: reserved for future, zeroes + * @time_gran: time granularity in nanoseconds + * @uuid: UUID generated when the file system image was created + * @ro_compat_version: UBIFS R/O compatibility version + */ +struct ubifs_sb_node { + struct ubifs_ch ch; + uint8_t padding[2]; + uint8_t key_hash; + uint8_t key_fmt; + uint32_t flags; + uint32_t min_io_size; + uint32_t leb_size; + uint32_t leb_cnt; + uint32_t max_leb_cnt; + uint64_t max_bud_bytes; + uint32_t log_lebs; + uint32_t lpt_lebs; + uint32_t orph_lebs; + uint32_t jhead_cnt; + uint32_t fanout; + uint32_t lsave_cnt; + uint32_t fmt_version; + uint16_t default_compr; + uint8_t padding1[2]; + uint32_t rp_uid; + uint32_t rp_gid; + uint64_t rp_size; + uint32_t time_gran; + uint8_t uuid[16]; + uint32_t ro_compat_version; + uint8_t padding2[3968]; +} __attribute__ ((packed)); + +static int probe_ubifs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct ubifs_sb_node *sb; + + sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node); + if (!sb) + return errno ? -errno : 1; + + blkid_probe_set_uuid(pr, sb->uuid); + blkid_probe_sprintf_version(pr, "w%dr%d", + le32_to_cpu(sb->fmt_version), + le32_to_cpu(sb->ro_compat_version)); + return 0; +} + +const struct blkid_idinfo ubifs_idinfo = +{ + .name = "ubifs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ubifs, + .magics = + { + { .magic = "\x31\x18\x10\x06", .len = 4 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c new file mode 100644 index 000000000..5cde3cc2a --- /dev/null +++ b/libblkid/src/superblocks/udf.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" +#include "iso9660.h" + +struct volume_descriptor { + struct descriptor_tag { + uint16_t id; + uint16_t version; + uint8_t checksum; + uint8_t reserved; + uint16_t serial; + uint16_t crc; + uint16_t crc_len; + uint32_t location; + } __attribute__((packed)) tag; + + union { + struct anchor_descriptor { + uint32_t length; + uint32_t location; + } __attribute__((packed)) anchor; + + struct primary_descriptor { + uint32_t seq_num; + uint32_t desc_num; + struct dstring { + uint8_t clen; + uint8_t c[31]; + } __attribute__((packed)) ident; + } __attribute__((packed)) primary; + + } __attribute__((packed)) type; + +} __attribute__((packed)); + +struct volume_structure_descriptor { + uint8_t type; + uint8_t id[5]; + uint8_t version; +} __attribute__((packed)); + +#define UDF_VSD_OFFSET 0x8000LL + +static int probe_udf(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + struct volume_descriptor *vd; + struct volume_structure_descriptor *vsd; + unsigned int bs; + unsigned int pbs[2]; + unsigned int b; + unsigned int type; + unsigned int count; + unsigned int loc; + unsigned int i; + + /* The block size of a UDF filesystem is that of the underlying + * storage; we check later on for the special case of image files, + * which may have the 2048-byte block size of optical media. */ + pbs[0] = blkid_probe_get_sectorsize(pr); + pbs[1] = 0x800; + + /* check for a Volume Structure Descriptor (VSD); each is + * 2048 bytes long */ + for (b = 0; b < 0x8000; b += 0x800) { + vsd = (struct volume_structure_descriptor *) + blkid_probe_get_buffer(pr, + UDF_VSD_OFFSET + b, + sizeof(*vsd)); + if (!vsd) + return errno ? -errno : 1; + if (vsd->id[0] != '\0') + goto nsr; + } + return 1; + +nsr: + /* search the list of VSDs for a NSR descriptor */ + for (b = 0; b < 64; b++) { + vsd = (struct volume_structure_descriptor *) + blkid_probe_get_buffer(pr, + UDF_VSD_OFFSET + ((blkid_loff_t) b * 0x800), + sizeof(*vsd)); + if (!vsd) + return errno ? -errno : 1; + if (vsd->id[0] == '\0') + return 1; + if (memcmp(vsd->id, "NSR02", 5) == 0) + goto anchor; + if (memcmp(vsd->id, "NSR03", 5) == 0) + goto anchor; + } + return 1; + +anchor: + /* read Anchor Volume Descriptor (AVDP), checking block size */ + for (i = 0; i < 2; i++) { + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, 256 * pbs[i], sizeof(*vd)); + if (!vd) + return errno ? -errno : 1; + + type = le16_to_cpu(vd->tag.id); + if (type == 2) /* TAG_ID_AVDP */ + goto real_blksz; + } + return 0; + +real_blksz: + /* Use the actual block size from here on out */ + bs = pbs[i]; + + /* get descriptor list address and block count */ + count = le32_to_cpu(vd->type.anchor.length) / bs; + loc = le32_to_cpu(vd->type.anchor.location); + + /* check if the list is usable */ + for (b = 0; b < count; b++) { + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, + (blkid_loff_t) (loc + b) * bs, + sizeof(*vd)); + if (!vd) + return errno ? -errno : 1; + } + + /* Try extract all possible ISO9660 information -- if there is + * usable LABEL in ISO header then use it, otherwise read UDF + * specific LABEL */ + if (probe_iso9660(pr, mag) == 0 && + __blkid_probe_lookup_value(pr, "LABEL") != NULL) + return 0; + + /* Read UDF label */ + for (b = 0; b < count; b++) { + vd = (struct volume_descriptor *) + blkid_probe_get_buffer(pr, + (blkid_loff_t) (loc + b) * bs, + sizeof(*vd)); + if (!vd) + return errno ? -errno : 1; + type = le16_to_cpu(vd->tag.id); + if (type == 0) + break; + if (le32_to_cpu(vd->tag.location) != loc + b) + break; + if (type == 1) { /* TAG_ID_PVD */ + uint8_t clen = vd->type.primary.ident.clen; + + if (clen == 8) + blkid_probe_set_label(pr, + vd->type.primary.ident.c, 31); + else if (clen == 16) + blkid_probe_set_utf8label(pr, + vd->type.primary.ident.c, + 31, BLKID_ENC_UTF16BE); + + if (clen == 8 || clen == 16) + break; + } + } + + return 0; +} + + +const struct blkid_idinfo udf_idinfo = +{ + .name = "udf", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_udf, + .flags = BLKID_IDINFO_TOLERANT, + .magics = + { + { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 }, + { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/ufs.c b/libblkid/src/superblocks/ufs.c new file mode 100644 index 000000000..6ef2acddc --- /dev/null +++ b/libblkid/src/superblocks/ufs.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> +#include <stddef.h> + +#include "superblocks.h" + +struct ufs_super_block { + uint32_t fs_link; + uint32_t fs_rlink; + uint32_t fs_sblkno; + uint32_t fs_cblkno; + uint32_t fs_iblkno; + uint32_t fs_dblkno; + uint32_t fs_cgoffset; + uint32_t fs_cgmask; + uint32_t fs_time; + uint32_t fs_size; + uint32_t fs_dsize; + uint32_t fs_ncg; + uint32_t fs_bsize; + uint32_t fs_fsize; + uint32_t fs_frag; + uint32_t fs_minfree; + uint32_t fs_rotdelay; + uint32_t fs_rps; + uint32_t fs_bmask; + uint32_t fs_fmask; + uint32_t fs_bshift; + uint32_t fs_fshift; + uint32_t fs_maxcontig; + uint32_t fs_maxbpg; + uint32_t fs_fragshift; + uint32_t fs_fsbtodb; + uint32_t fs_sbsize; + uint32_t fs_csmask; + uint32_t fs_csshift; + uint32_t fs_nindir; + uint32_t fs_inopb; + uint32_t fs_nspf; + uint32_t fs_optim; + uint32_t fs_npsect_state; + uint32_t fs_interleave; + uint32_t fs_trackskew; + uint32_t fs_id[2]; + uint32_t fs_csaddr; + uint32_t fs_cssize; + uint32_t fs_cgsize; + uint32_t fs_ntrak; + uint32_t fs_nsect; + uint32_t fs_spc; + uint32_t fs_ncyl; + uint32_t fs_cpg; + uint32_t fs_ipg; + uint32_t fs_fpg; + struct ufs_csum { + uint32_t cs_ndir; + uint32_t cs_nbfree; + uint32_t cs_nifree; + uint32_t cs_nffree; + } fs_cstotal; + int8_t fs_fmod; + int8_t fs_clean; + int8_t fs_ronly; + int8_t fs_flags; + union { + struct { + int8_t fs_fsmnt[512]; + uint32_t fs_cgrotor; + uint32_t fs_csp[31]; + uint32_t fs_maxcluster; + uint32_t fs_cpc; + uint16_t fs_opostbl[16][8]; + } fs_u1; + struct { + int8_t fs_fsmnt[468]; + uint8_t fs_volname[32]; + uint64_t fs_swuid; + int32_t fs_pad; + uint32_t fs_cgrotor; + uint32_t fs_ocsp[28]; + uint32_t fs_contigdirs; + uint32_t fs_csp; + uint32_t fs_maxcluster; + uint32_t fs_active; + int32_t fs_old_cpc; + int32_t fs_maxbsize; + int64_t fs_sparecon64[17]; + int64_t fs_sblockloc; + struct ufs2_csum_total { + uint64_t cs_ndir; + uint64_t cs_nbfree; + uint64_t cs_nifree; + uint64_t cs_nffree; + uint64_t cs_numclusters; + uint64_t cs_spare[3]; + } fs_cstotal; + struct ufs_timeval { + int32_t tv_sec; + int32_t tv_usec; + } fs_time; + int64_t fs_size; + int64_t fs_dsize; + uint64_t fs_csaddr; + int64_t fs_pendingblocks; + int32_t fs_pendinginodes; + } __attribute__((packed)) fs_u2; + } fs_u11; + union { + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + int32_t fs_state; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } fs_sun; + struct { + int32_t fs_sparecon[53]; + int32_t fs_reclaim; + int32_t fs_sparecon2[1]; + uint32_t fs_npsect; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + } fs_sunx86; + struct { + int32_t fs_sparecon[50]; + int32_t fs_contigsumsize; + int32_t fs_maxsymlinklen; + int32_t fs_inodefmt; + uint32_t fs_maxfilesize[2]; + uint32_t fs_qbmask[2]; + uint32_t fs_qfmask[2]; + int32_t fs_state; + } fs_44; + } fs_u2; + int32_t fs_postblformat; + int32_t fs_nrpos; + int32_t fs_postbloff; + int32_t fs_rotbloff; + uint32_t fs_magic; + uint8_t fs_space[1]; +} __attribute__((packed)); + +#define UFS_MAGIC 0x00011954 +#define UFS2_MAGIC 0x19540119 +#define UFS_MAGIC_FEA 0x00195612 +#define UFS_MAGIC_LFN 0x00095014 +#define UFS_MAGIC_SEC 0x00612195 +#define UFS_MAGIC_4GB 0x05231994 + +static int probe_ufs(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + int offsets[] = { 0, 8, 64, 256 }; + uint32_t mags[] = { + UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN, + UFS_MAGIC_SEC, UFS_MAGIC_4GB + }; + size_t i; + uint32_t magic; + struct ufs_super_block *ufs; + int is_be; + + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + uint32_t magLE, magBE; + size_t y; + + ufs = (struct ufs_super_block *) + blkid_probe_get_buffer(pr, + offsets[i] * 1024, + sizeof(struct ufs_super_block)); + if (!ufs) + return errno ? -errno : 1; + + magBE = be32_to_cpu(ufs->fs_magic); + magLE = le32_to_cpu(ufs->fs_magic); + + for (y = 0; y < ARRAY_SIZE(mags); y++) { + if (magLE == mags[y] || magBE == mags[y]) { + magic = mags[y]; + is_be = (magBE == mags[y]); + goto found; + } + } + } + + return 1; + +found: + if (magic == UFS2_MAGIC) { + blkid_probe_set_version(pr, "2"); + blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname, + sizeof(ufs->fs_u11.fs_u2.fs_volname)); + } else + blkid_probe_set_version(pr, "1"); + if (ufs->fs_id[0] || ufs->fs_id[1]) + { + if (is_be) + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &ufs->fs_id, + sizeof(ufs->fs_id), + "%08x%08x", + be32_to_cpu(ufs->fs_id[0]), + be32_to_cpu(ufs->fs_id[1])); + else + blkid_probe_sprintf_uuid(pr, + (unsigned char *) &ufs->fs_id, + sizeof(ufs->fs_id), + "%08x%08x", + le32_to_cpu(ufs->fs_id[0]), + le32_to_cpu(ufs->fs_id[1])); + } + + if (blkid_probe_set_magic(pr, + (offsets[i] * 1024) + + offsetof(struct ufs_super_block, fs_magic), + sizeof(ufs->fs_magic), + (unsigned char *) &ufs->fs_magic)) + return 1; + + return 0; +} + +/* + * According to libvolume_id the UFS superblock could be on four positions. + * The original libblkid has checked one position (.kboff=8) only. + * + * We know four UFS magic strings and UFS could be both little-endian and + * big-endian. ... so we have: + * + * 4 position * 4 string * 2 version = 32 magic strings + * + * It seems simpler to check for these string in probing function that hardcode + * all in the .magic array. + */ +const struct blkid_idinfo ufs_idinfo = +{ + .name = "ufs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_ufs, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/superblocks/vfat.c b/libblkid/src/superblocks/vfat.c new file mode 100644 index 000000000..f38deac8b --- /dev/null +++ b/libblkid/src/superblocks/vfat.c @@ -0,0 +1,431 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +/* Yucky misaligned values */ +struct vfat_super_block { +/* 00*/ unsigned char vs_ignored[3]; +/* 03*/ unsigned char vs_sysid[8]; +/* 0b*/ unsigned char vs_sector_size[2]; +/* 0d*/ uint8_t vs_cluster_size; +/* 0e*/ uint16_t vs_reserved; +/* 10*/ uint8_t vs_fats; +/* 11*/ unsigned char vs_dir_entries[2]; +/* 13*/ unsigned char vs_sectors[2]; +/* 15*/ unsigned char vs_media; +/* 16*/ uint16_t vs_fat_length; +/* 18*/ uint16_t vs_secs_track; +/* 1a*/ uint16_t vs_heads; +/* 1c*/ uint32_t vs_hidden; +/* 20*/ uint32_t vs_total_sect; +/* 24*/ uint32_t vs_fat32_length; +/* 28*/ uint16_t vs_flags; +/* 2a*/ uint8_t vs_version[2]; +/* 2c*/ uint32_t vs_root_cluster; +/* 30*/ uint16_t vs_fsinfo_sector; +/* 32*/ uint16_t vs_backup_boot; +/* 34*/ uint16_t vs_reserved2[6]; +/* 40*/ unsigned char vs_unknown[3]; +/* 43*/ unsigned char vs_serno[4]; +/* 47*/ unsigned char vs_label[11]; +/* 52*/ unsigned char vs_magic[8]; +/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; +/*1fe*/ unsigned char vs_pmagic[2]; +} __attribute__((packed)); + +/* Yucky misaligned values */ +struct msdos_super_block { +/* 00*/ unsigned char ms_ignored[3]; +/* 03*/ unsigned char ms_sysid[8]; +/* 0b*/ unsigned char ms_sector_size[2]; +/* 0d*/ uint8_t ms_cluster_size; +/* 0e*/ uint16_t ms_reserved; +/* 10*/ uint8_t ms_fats; +/* 11*/ unsigned char ms_dir_entries[2]; +/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ +/* 15*/ unsigned char ms_media; +/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ +/* 18*/ uint16_t ms_secs_track; +/* 1a*/ uint16_t ms_heads; +/* 1c*/ uint32_t ms_hidden; +/* V3 BPB */ +/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ +/* V4 BPB */ +/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ +/* 27*/ unsigned char ms_serno[4]; +/* 2b*/ unsigned char ms_label[11]; +/* 36*/ unsigned char ms_magic[8]; +/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; +/*1fe*/ unsigned char ms_pmagic[2]; +} __attribute__((packed)); + +struct vfat_dir_entry { + uint8_t name[11]; + uint8_t attr; + uint16_t time_creat; + uint16_t date_creat; + uint16_t time_acc; + uint16_t date_acc; + uint16_t cluster_high; + uint16_t time_write; + uint16_t date_write; + uint16_t cluster_low; + uint32_t size; +} __attribute__((packed)); + +struct fat32_fsinfo { + uint8_t signature1[4]; + uint32_t reserved1[120]; + uint8_t signature2[4]; + uint32_t free_clusters; + uint32_t next_cluster; + uint32_t reserved2[4]; +} __attribute__((packed)); + +/* maximum number of clusters */ +#define FAT12_MAX 0xFF4 +#define FAT16_MAX 0xFFF4 +#define FAT32_MAX 0x0FFFFFF6 + +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIR 0x10 +#define FAT_ATTR_LONG_NAME 0x0f +#define FAT_ATTR_MASK 0x3f +#define FAT_ENTRY_FREE 0xe5 + +static const char *no_name = "NO NAME "; + +#define unaligned_le16(x) \ + (((unsigned char *) x)[0] + (((unsigned char *) x)[1] << 8)) + +/* + * Look for LABEL (name) in the FAT root directory. + */ +static unsigned char *search_fat_label(blkid_probe pr, + uint64_t offset, uint32_t entries) +{ + struct vfat_dir_entry *ent, *dir = NULL; + uint32_t i; + + DBG(LOWPROBE, ul_debug("\tlook for label in root-dir " + "(entries: %d, offset: %jd)", entries, offset)); + + if (!blkid_probe_is_tiny(pr)) { + /* large disk, read whole root directory */ + dir = (struct vfat_dir_entry *) + blkid_probe_get_buffer(pr, + offset, + (blkid_loff_t) entries * + sizeof(struct vfat_dir_entry)); + if (!dir) + return NULL; + } + + for (i = 0; i < entries; i++) { + /* + * The root directory could be relatively large (4-16kB). + * Fortunately, the LABEL is usually the first entry in the + * directory. On tiny disks we call read() per entry. + */ + if (!dir) + ent = (struct vfat_dir_entry *) + blkid_probe_get_buffer(pr, + (blkid_loff_t) offset + (i * + sizeof(struct vfat_dir_entry)), + sizeof(struct vfat_dir_entry)); + else + ent = &dir[i]; + + if (!ent || ent->name[0] == 0x00) + break; + + if ((ent->name[0] == FAT_ENTRY_FREE) || + (ent->cluster_high != 0 || ent->cluster_low != 0) || + ((ent->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) + continue; + + if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == + FAT_ATTR_VOLUME_ID) { + DBG(LOWPROBE, ul_debug("\tfound fs LABEL at entry %d", i)); + return ent->name; + } + } + return NULL; +} + +static int fat_valid_superblock(const struct blkid_idmag *mag, + struct msdos_super_block *ms, + struct vfat_super_block *vs, + uint32_t *cluster_count, uint32_t *fat_size) +{ + uint16_t sector_size, dir_entries, reserved; + uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length; + uint32_t max_count; + + /* extra check for FATs without magic strings */ + if (mag->len <= 2) { + /* Old floppies have a valid MBR signature */ + if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA) + return 0; + + /* + * OS/2 and apparently DFSee will place a FAT12/16-like + * pseudo-superblock in the first 512 bytes of non-FAT + * filesystems --- at least JFS and HPFS, and possibly others. + * So we explicitly check for those filesystems at the + * FAT12/16 filesystem magic field identifier, and if they are + * present, we rule this out as a FAT filesystem, despite the + * FAT-like pseudo-header. + */ + if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || + (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) + return 0; + } + + /* fat counts(Linux kernel expects at least 1 FAT table) */ + if (!ms->ms_fats) + return 0; + if (!ms->ms_reserved) + return 0; + if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0)) + return 0; + if (!is_power_of_2(ms->ms_cluster_size)) + return 0; + + sector_size = unaligned_le16(&ms->ms_sector_size); + if (!is_power_of_2(sector_size) || + sector_size < 512 || sector_size > 4096) + return 0; + + dir_entries = unaligned_le16(&ms->ms_dir_entries); + reserved = le16_to_cpu(ms->ms_reserved); + sect_count = unaligned_le16(&ms->ms_sectors); + + if (sect_count == 0) + sect_count = le32_to_cpu(ms->ms_total_sect); + + fat_length = le16_to_cpu(ms->ms_fat_length); + if (fat_length == 0) + fat_length = le32_to_cpu(vs->vs_fat32_length); + + __fat_size = fat_length * ms->ms_fats; + dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + + (sector_size-1)) / sector_size; + + __cluster_count = (sect_count - (reserved + __fat_size + dir_size)) / + ms->ms_cluster_size; + if (!ms->ms_fat_length && vs->vs_fat32_length) + max_count = FAT32_MAX; + else + max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX; + + if (__cluster_count > max_count) + return 0; + + if (fat_size) + *fat_size = __fat_size; + if (cluster_count) + *cluster_count = __cluster_count; + + return 1; /* valid */ +} + +/* + * This function is used by MBR partition table parser to avoid + * misinterpretation of FAT filesystem. + */ +int blkid_probe_is_vfat(blkid_probe pr) +{ + struct vfat_super_block *vs; + struct msdos_super_block *ms; + const struct blkid_idmag *mag = NULL; + int rc; + + rc = blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag); + if (rc < 0) + return rc; /* error */ + if (rc != BLKID_PROBE_OK || !mag) + return 0; + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) + return errno ? -errno : 0; + vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); + if (!vs) + return errno ? -errno : 0; + + return fat_valid_superblock(mag, ms, vs, NULL, NULL); +} + +/* FAT label extraction from the root directory taken from Kay + * Sievers's volume_id library */ +static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vfat_super_block *vs; + struct msdos_super_block *ms; + const unsigned char *vol_label = 0; + unsigned char *vol_serno = NULL, vol_label_buf[11]; + uint16_t sector_size = 0, reserved; + uint32_t cluster_count, fat_size; + const char *version = NULL; + + ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); + if (!ms) + return errno ? -errno : 1; + + vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); + if (!vs) + return errno ? -errno : 1; + + if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size)) + return 1; + + sector_size = unaligned_le16(&ms->ms_sector_size); + reserved = le16_to_cpu(ms->ms_reserved); + + if (ms->ms_fat_length) { + /* the label may be an attribute in the root directory */ + uint32_t root_start = (reserved + fat_size) * sector_size; + uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries); + + vol_label = search_fat_label(pr, root_start, root_dir_entries); + if (vol_label) { + memcpy(vol_label_buf, vol_label, 11); + vol_label = vol_label_buf; + } + + if (!vol_label || !memcmp(vol_label, no_name, 11)) + vol_label = ms->ms_label; + vol_serno = ms->ms_serno; + + blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos", + sizeof("msdos")); + + if (cluster_count < FAT12_MAX) + version = "FAT12"; + else if (cluster_count < FAT16_MAX) + version = "FAT16"; + + } else if (vs->vs_fat32_length) { + unsigned char *buf; + uint16_t fsinfo_sect; + int maxloop = 100; + + /* Search the FAT32 root dir for the label attribute */ + uint32_t buf_size = vs->vs_cluster_size * sector_size; + uint32_t start_data_sect = reserved + fat_size; + uint32_t entries = le32_to_cpu(vs->vs_fat32_length) * + sector_size / sizeof(uint32_t); + uint32_t next = le32_to_cpu(vs->vs_root_cluster); + + while (next && next < entries && --maxloop) { + uint32_t next_sect_off; + uint64_t next_off, fat_entry_off; + int count; + + next_sect_off = (next - 2) * vs->vs_cluster_size; + next_off = (uint64_t)(start_data_sect + next_sect_off) * + sector_size; + + count = buf_size / sizeof(struct vfat_dir_entry); + + vol_label = search_fat_label(pr, next_off, count); + if (vol_label) { + memcpy(vol_label_buf, vol_label, 11); + vol_label = vol_label_buf; + break; + } + + /* get FAT entry */ + fat_entry_off = ((uint64_t) reserved * sector_size) + + (next * sizeof(uint32_t)); + buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size); + if (buf == NULL) + break; + + /* set next cluster */ + next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; + } + + version = "FAT32"; + + if (!vol_label || !memcmp(vol_label, no_name, 11)) + vol_label = vs->vs_label; + vol_serno = vs->vs_serno; + + /* + * FAT32 should have a valid signature in the fsinfo block, + * but also allow all bytes set to '\0', because some volumes + * do not set the signature at all. + */ + fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector); + if (fsinfo_sect) { + struct fat32_fsinfo *fsinfo; + + buf = blkid_probe_get_buffer(pr, + (blkid_loff_t) fsinfo_sect * sector_size, + sizeof(struct fat32_fsinfo)); + if (buf == NULL) + return errno ? -errno : 1; + + fsinfo = (struct fat32_fsinfo *) buf; + if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && + memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 && + memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) + return 1; + if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && + memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) + return 1; + } + } + + if (vol_label && memcmp(vol_label, no_name, 11)) + blkid_probe_set_label(pr, (unsigned char *) vol_label, 11); + + /* We can't just print them as %04X, because they are unaligned */ + if (vol_serno) + blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X", + vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]); + if (version) + blkid_probe_set_version(pr, version); + + return 0; +} + + +const struct blkid_idinfo vfat_idinfo = +{ + .name = "vfat", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_vfat, + .magics = + { + { .magic = "MSWIN", .len = 5, .sboff = 0x52 }, + { .magic = "FAT32 ", .len = 8, .sboff = 0x52 }, + { .magic = "MSDOS", .len = 5, .sboff = 0x36 }, + { .magic = "FAT16 ", .len = 8, .sboff = 0x36 }, + { .magic = "FAT12 ", .len = 8, .sboff = 0x36 }, + { .magic = "FAT ", .len = 8, .sboff = 0x36 }, + { .magic = "\353", .len = 1, }, + { .magic = "\351", .len = 1, }, + { .magic = "\125\252", .len = 2, .sboff = 0x1fe }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/via_raid.c b/libblkid/src/superblocks/via_raid.c new file mode 100644 index 000000000..ee3ab658e --- /dev/null +++ b/libblkid/src/superblocks/via_raid.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * Inspired by libvolume_id by + * Kay Sievers <kay.sievers@vrfy.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +struct via_metadata { + uint16_t signature; + uint8_t version_number; + struct via_array { + uint16_t disk_bit_mask; + uint8_t disk_array_ex; + uint32_t capacity_low; + uint32_t capacity_high; + uint32_t serial_checksum; + } __attribute__((packed)) array; + uint32_t serial_checksum[8]; + uint8_t checksum; +} __attribute__((packed)); + +#define VIA_SIGNATURE 0xAA55 + +/* 8 bit checksum on first 50 bytes of metadata. */ +static uint8_t via_checksum(struct via_metadata *v) +{ + uint8_t i = 50, cs = 0; + + while (i--) + cs += ((uint8_t*) v)[i]; + + return cs; +} + +static int probe_viaraid(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t off; + struct via_metadata *v; + + if (pr->size < 0x10000) + return 1; + if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) + return 1; + + off = ((pr->size / 0x200)-1) * 0x200; + + v = (struct via_metadata *) + blkid_probe_get_buffer(pr, + off, + sizeof(struct via_metadata)); + if (!v) + return errno ? -errno : 1; + + if (le16_to_cpu(v->signature) != VIA_SIGNATURE) + return 1; + if (v->version_number > 2) + return 1; + if (!blkid_probe_verify_csum(pr, via_checksum(v), v->checksum)) + return 1; + + if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0) + return 1; + if (blkid_probe_set_magic(pr, off, + sizeof(v->signature), + (unsigned char *) &v->signature)) + return 1; + return 0; +} + +const struct blkid_idinfo viaraid_idinfo = { + .name = "via_raid_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_viaraid, + .magics = BLKID_NONE_MAGIC +}; + + diff --git a/libblkid/src/superblocks/vmfs.c b/libblkid/src/superblocks/vmfs.c new file mode 100644 index 000000000..fac87abe5 --- /dev/null +++ b/libblkid/src/superblocks/vmfs.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009 Mike Hommey <mh@glandium.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ +#include "superblocks.h" + +struct vmfs_fs_info { + uint32_t magic; + uint32_t volume_version; + uint8_t version; + uint8_t uuid[16]; + uint32_t mode; + char label[128]; +} __attribute__ ((__packed__)); + +struct vmfs_volume_info { + uint32_t magic; + uint32_t ver; + uint8_t irrelevant[122]; + uint8_t uuid[16]; +} __attribute__ ((__packed__)); + +static int probe_vmfs_fs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vmfs_fs_info *header; + + header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info); + if (header == NULL) + return errno ? -errno : 1; + + blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16, + "%02x%02x%02x%02x-%02x%02x%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + header->uuid[3], header->uuid[2], header->uuid[1], + header->uuid[0], header->uuid[7], header->uuid[6], + header->uuid[5], header->uuid[4], header->uuid[9], + header->uuid[8], header->uuid[10], header->uuid[11], + header->uuid[12], header->uuid[13], header->uuid[14], + header->uuid[15]); + + blkid_probe_set_label(pr, (unsigned char *) header->label, + sizeof(header->label)); + blkid_probe_sprintf_version(pr, "%u", header->version); + return 0; +} + +static int probe_vmfs_volume(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vmfs_volume_info *header; + unsigned char *lvm_uuid; + + header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info); + if (header == NULL) + return errno ? -errno : 1; + + blkid_probe_sprintf_value(pr, "UUID_SUB", + "%02x%02x%02x%02x-%02x%02x%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + header->uuid[3], header->uuid[2], header->uuid[1], + header->uuid[0], header->uuid[7], header->uuid[6], + header->uuid[5], header->uuid[4], header->uuid[9], + header->uuid[8], header->uuid[10], header->uuid[11], + header->uuid[12], header->uuid[13], header->uuid[14], + header->uuid[15]); + blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(header->ver)); + + lvm_uuid = blkid_probe_get_buffer(pr, + 1024 * 1024 /* Start of the volume info */ + + 512 /* Offset to lvm info */ + + 20 /* Offset in lvm info */, 35); + if (lvm_uuid) + blkid_probe_strncpy_uuid(pr, lvm_uuid, 35); + + return 0; +} + +const struct blkid_idinfo vmfs_fs_idinfo = +{ + .name = "VMFS", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_vmfs_fs, + .magics = + { + { .magic = "\x5e\xf1\xab\x2f", .len = 4, .kboff = 2048 }, + { NULL } + } +}; + +const struct blkid_idinfo vmfs_volume_idinfo = +{ + .name = "VMFS_volume_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_vmfs_volume, + .magics = + { + { .magic = "\x0d\xd0\x01\xc0", .len = 4, .kboff = 1024 }, + { NULL } + } +}; diff --git a/libblkid/src/superblocks/vxfs.c b/libblkid/src/superblocks/vxfs.c new file mode 100644 index 000000000..19d284cbf --- /dev/null +++ b/libblkid/src/superblocks/vxfs.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> + +#include "superblocks.h" + +struct vxfs_super_block { + uint32_t vs_magic; + int32_t vs_version; +}; + +static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct vxfs_super_block *vxs; + + vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block); + if (!vxs) + return errno ? -errno : 1; + + blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version); + return 0; +} + + +const struct blkid_idinfo vxfs_idinfo = +{ + .name = "vxfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_vxfs, + .magics = + { + { .magic = "\365\374\001\245", .len = 4, .kboff = 1 }, + { NULL } + } +}; + diff --git a/libblkid/src/superblocks/xfs.c b/libblkid/src/superblocks/xfs.c new file mode 100644 index 000000000..a6c04a2f0 --- /dev/null +++ b/libblkid/src/superblocks/xfs.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 1999 by Andries Brouwer + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o + * Copyright (C) 2001 by Andreas Dilger + * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * Copyright (C) 2013 Eric Sandeen <sandeen@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <stdint.h> + +#include "superblocks.h" + +struct xfs_super_block { + uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + uint32_t sb_blocksize; /* logical block size, bytes */ + uint64_t sb_dblocks; /* number of data blocks */ + uint64_t sb_rblocks; /* number of realtime blocks */ + uint64_t sb_rextents; /* number of realtime extents */ + unsigned char sb_uuid[16]; /* file system unique id */ + uint64_t sb_logstart; /* starting block of log if internal */ + uint64_t sb_rootino; /* root inode number */ + uint64_t sb_rbmino; /* bitmap inode for realtime extents */ + uint64_t sb_rsumino; /* summary inode for rt bitmap */ + uint32_t sb_rextsize; /* realtime extent size, blocks */ + uint32_t sb_agblocks; /* size of an allocation group */ + uint32_t sb_agcount; /* number of allocation groups */ + uint32_t sb_rbmblocks; /* number of rt bitmap blocks */ + uint32_t sb_logblocks; /* number of log blocks */ + + uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + uint16_t sb_sectsize; /* volume sector size, bytes */ + uint16_t sb_inodesize; /* inode size, bytes */ + uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + uint8_t sb_blocklog; /* log2 of sb_blocksize */ + uint8_t sb_sectlog; /* log2 of sb_sectsize */ + uint8_t sb_inodelog; /* log2 of sb_inodesize */ + uint8_t sb_inopblog; /* log2 of sb_inopblock */ + uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + uint8_t sb_rextslog; /* log2 of sb_rextents */ + uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + uint64_t sb_icount; /* allocated inodes */ + uint64_t sb_ifree; /* free inodes */ + uint64_t sb_fdblocks; /* free data blocks */ + uint64_t sb_frextents; /* free realtime extents */ + + /* this is not all... but enough for libblkid */ + +} __attribute__((packed)); + +#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) +#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ +#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) +#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) + +#define XFS_DINODE_MIN_LOG 8 +#define XFS_DINODE_MAX_LOG 11 +#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) +#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) + +#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ +#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ +#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ + +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MAX_DBLOCKS(s) ((uint64_t)(s)->sb_agcount * (s)->sb_agblocks) +#define XFS_MIN_DBLOCKS(s) ((uint64_t)((s)->sb_agcount - 1) * \ + (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) + + +static void sb_from_disk(struct xfs_super_block *from, + struct xfs_super_block *to) +{ + + to->sb_magicnum = be32_to_cpu(from->sb_magicnum); + to->sb_blocksize = be32_to_cpu(from->sb_blocksize); + to->sb_dblocks = be64_to_cpu(from->sb_dblocks); + to->sb_rblocks = be64_to_cpu(from->sb_rblocks); + to->sb_rextents = be64_to_cpu(from->sb_rextents); + to->sb_logstart = be64_to_cpu(from->sb_logstart); + to->sb_rootino = be64_to_cpu(from->sb_rootino); + to->sb_rbmino = be64_to_cpu(from->sb_rbmino); + to->sb_rsumino = be64_to_cpu(from->sb_rsumino); + to->sb_rextsize = be32_to_cpu(from->sb_rextsize); + to->sb_agblocks = be32_to_cpu(from->sb_agblocks); + to->sb_agcount = be32_to_cpu(from->sb_agcount); + to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); + to->sb_logblocks = be32_to_cpu(from->sb_logblocks); + to->sb_versionnum = be16_to_cpu(from->sb_versionnum); + to->sb_sectsize = be16_to_cpu(from->sb_sectsize); + to->sb_inodesize = be16_to_cpu(from->sb_inodesize); + to->sb_inopblock = be16_to_cpu(from->sb_inopblock); + to->sb_blocklog = from->sb_blocklog; + to->sb_sectlog = from->sb_sectlog; + to->sb_inodelog = from->sb_inodelog; + to->sb_inopblog = from->sb_inopblog; + to->sb_agblklog = from->sb_agblklog; + to->sb_rextslog = from->sb_rextslog; + to->sb_inprogress = from->sb_inprogress; + to->sb_imax_pct = from->sb_imax_pct; + to->sb_icount = be64_to_cpu(from->sb_icount); + to->sb_ifree = be64_to_cpu(from->sb_ifree); + to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); + to->sb_frextents = be64_to_cpu(from->sb_frextents); +} + +static int xfs_verify_sb(struct xfs_super_block *ondisk) +{ + struct xfs_super_block sb, *sbp = &sb; + + /* beXX_to_cpu(), but don't convert UUID and fsname! */ + sb_from_disk(ondisk, sbp); + + /* sanity checks, we don't want to rely on magic string only */ + if (sbp->sb_agcount <= 0 || + sbp->sb_sectsize < XFS_MIN_SECTORSIZE || + sbp->sb_sectsize > XFS_MAX_SECTORSIZE || + sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || + sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || + sbp->sb_sectsize != (1 << sbp->sb_sectlog) || + sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || + sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || + sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sbp->sb_blocksize != (1 << sbp->sb_blocklog) || + sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || + sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || + sbp->sb_inodelog < XFS_DINODE_MIN_LOG || + sbp->sb_inodelog > XFS_DINODE_MAX_LOG || + sbp->sb_inodesize != (1 << sbp->sb_inodelog) || + (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || + (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || + (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || + (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || + sbp->sb_dblocks == 0 || + sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || + sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp)) + return 0; + + /* TODO: version 5 has also checksum CRC32, maybe we can check it too */ + + return 1; +} + +static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag) +{ + struct xfs_super_block *xs; + + xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block); + if (!xs) + return errno ? -errno : 1; + + if (!xfs_verify_sb(xs)) + return 1; + + if (strlen(xs->sb_fname)) + blkid_probe_set_label(pr, (unsigned char *) xs->sb_fname, + sizeof(xs->sb_fname)); + blkid_probe_set_uuid(pr, xs->sb_uuid); + return 0; +} + +const struct blkid_idinfo xfs_idinfo = +{ + .name = "xfs", + .usage = BLKID_USAGE_FILESYSTEM, + .probefunc = probe_xfs, + .magics = + { + { .magic = "XFSB", .len = 4 }, + { NULL } + } +}; + +struct xlog_rec_header { + uint32_t h_magicno; + uint32_t h_dummy1[1]; + uint32_t h_version; + uint32_t h_len; + uint32_t h_dummy2[71]; + uint32_t h_fmt; + unsigned char h_uuid[16]; +} __attribute__((packed)); + +#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe + +/* + * For very small filesystems, the minimum log size + * can be smaller, but that seems vanishingly unlikely + * when used with an external log (which is used for + * performance reasons; tiny conflicts with that goal). + */ +#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024) + +#define XLOG_FMT_LINUX_LE 1 +#define XLOG_FMT_LINUX_BE 2 +#define XLOG_FMT_IRIX_BE 3 + +#define XLOG_VERSION_1 1 +#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ +#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) + +static int xlog_valid_rec_header(struct xlog_rec_header *rhead) +{ + uint32_t hlen; + + if (rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) + return 0; + + if (!rhead->h_version || + (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))) + return 0; + + /* LR body must have data or it wouldn't have been written */ + hlen = be32_to_cpu(rhead->h_len); + if (hlen <= 0 || hlen > INT_MAX) + return 0; + + if (rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_LE) && + rhead->h_fmt != cpu_to_be32(XLOG_FMT_LINUX_BE) && + rhead->h_fmt != cpu_to_be32(XLOG_FMT_IRIX_BE)) + return 0; + + return 1; +} + +/* xlog record header will be in some sector in the first 256k */ +static int probe_xfs_log(blkid_probe pr, const struct blkid_idmag *mag) +{ + int i; + struct xlog_rec_header *rhead; + unsigned char *buf; + + buf = blkid_probe_get_buffer(pr, 0, 256*1024); + if (!buf) + return errno ? -errno : 1; + + if (memcmp(buf, "XFSB", 4) == 0) + return 1; /* this is regular XFS, ignore */ + + /* check the first 512 512-byte sectors */ + for (i = 0; i < 512; i++) { + rhead = (struct xlog_rec_header *)&buf[i*512]; + + if (xlog_valid_rec_header(rhead)) { + blkid_probe_set_uuid_as(pr, rhead->h_uuid, "LOGUUID"); + return 0; + } + } + + return 1; +} + +const struct blkid_idinfo xfs_log_idinfo = +{ + .name = "xfs_external_log", + .usage = BLKID_USAGE_OTHER, + .probefunc = probe_xfs_log, + .magics = BLKID_NONE_MAGIC, + .minsz = XFS_MIN_LOG_BYTES, +}; diff --git a/libblkid/src/superblocks/zfs.c b/libblkid/src/superblocks/zfs.c new file mode 100644 index 000000000..86da59d4a --- /dev/null +++ b/libblkid/src/superblocks/zfs.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2009-2010 by Andreas Dilger <adilger@sun.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include <inttypes.h> +#include <limits.h> + +#include "superblocks.h" + +#define VDEV_LABEL_UBERBLOCK (128 * 1024ULL) +#define VDEV_LABEL_NVPAIR ( 16 * 1024ULL) +#define VDEV_LABEL_SIZE (256 * 1024ULL) + +/* #include <sys/uberblock_impl.h> */ +#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ +struct zfs_uberblock { + uint64_t ub_magic; /* UBERBLOCK_MAGIC */ + uint64_t ub_version; /* SPA_VERSION */ + uint64_t ub_txg; /* txg of last sync */ + uint64_t ub_guid_sum; /* sum of all vdev guids */ + uint64_t ub_timestamp; /* UTC time of last sync */ + char ub_rootbp; /* MOS objset_phys_t */ +} __attribute__((packed)); + +#define ZFS_TRIES 64 +#define ZFS_WANT 4 + +#define DATA_TYPE_UINT64 8 +#define DATA_TYPE_STRING 9 + +struct nvpair { + uint32_t nvp_size; + uint32_t nvp_unkown; + uint32_t nvp_namelen; + char nvp_name[0]; /* aligned to 4 bytes */ + /* aligned ptr array for string arrays */ + /* aligned array of data for value */ +}; + +struct nvstring { + uint32_t nvs_type; + uint32_t nvs_elem; + uint32_t nvs_strlen; + unsigned char nvs_string[0]; +}; + +struct nvuint64 { + uint32_t nvu_type; + uint32_t nvu_elem; + uint64_t nvu_value; +}; + +struct nvlist { + uint32_t nvl_unknown[3]; + struct nvpair nvl_nvpair; +}; + +#define nvdebug(fmt, ...) do { } while(0) +/*#define nvdebug(fmt, a...) fprintf(stderr, fmt, ##a)*/ + +static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) +{ + struct nvlist *nvl; + struct nvpair *nvp; + size_t left = 4096; + int found = 0; + + offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR; + + /* Note that we currently assume that the desired fields are within + * the first 4k (left) of the nvlist. This is true for all pools + * I've seen, and simplifies this code somewhat, because we don't + * have to handle an nvpair crossing a buffer boundary. */ + nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left); + if (nvl == NULL) + return; + + nvdebug("zfs_extract: nvlist offset %llu\n", offset); + + nvp = &nvl->nvl_nvpair; + while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) { + int avail; /* tracks that name/value data fits in nvp_size */ + int namesize; + + nvp->nvp_size = be32_to_cpu(nvp->nvp_size); + nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen); + avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp); + + nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size); + if (left < nvp->nvp_size || avail < 0) + break; + + namesize = (nvp->nvp_namelen + 3) & ~3; + + nvdebug("nvlist: size %u, namelen %u, name %*s\n", + nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen, + nvp->nvp_name); + if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) { + struct nvstring *nvs = (void *)(nvp->nvp_name+namesize); + + nvs->nvs_type = be32_to_cpu(nvs->nvs_type); + nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen); + if (nvs->nvs_strlen > UINT_MAX - sizeof(*nvs)) + break; + avail -= nvs->nvs_strlen + sizeof(*nvs); + nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type, + nvs->nvs_strlen, nvs->nvs_string); + if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0) + blkid_probe_set_label(pr, nvs->nvs_string, + nvs->nvs_strlen); + found++; + } else if (strncmp(nvp->nvp_name, "guid", + nvp->nvp_namelen) == 0) { + struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); + uint64_t nvu_value; + + memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); + nvu->nvu_type = be32_to_cpu(nvu->nvu_type); + nvu_value = be64_to_cpu(nvu_value); + avail -= sizeof(*nvu); + nvdebug("nvuint64: type %u value %"PRIu64"\n", + nvu->nvu_type, nvu_value); + if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) + blkid_probe_sprintf_value(pr, "UUID_SUB", + "%"PRIu64, nvu_value); + found++; + } else if (strncmp(nvp->nvp_name, "pool_guid", + nvp->nvp_namelen) == 0) { + struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); + uint64_t nvu_value; + + memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); + nvu->nvu_type = be32_to_cpu(nvu->nvu_type); + nvu_value = be64_to_cpu(nvu_value); + avail -= sizeof(*nvu); + nvdebug("nvuint64: type %u value %"PRIu64"\n", + nvu->nvu_type, nvu_value); + if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) + blkid_probe_sprintf_uuid(pr, (unsigned char *) + &nvu_value, + sizeof(nvu_value), + "%"PRIu64, nvu_value); + found++; + } + if (left > nvp->nvp_size) + left -= nvp->nvp_size; + else + left = 0; + nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size); + } +} + +#define zdebug(fmt, ...) do {} while(0) +/*#define zdebug(fmt, a...) fprintf(stderr, fmt, ##a)*/ + +/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start + * of the disk, and 2 areas at the end of the disk. Check only some of them... + * #4 (@ 132kB) is the first one written on a new filesystem. */ +static int probe_zfs(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); + struct zfs_uberblock *ub; + int swab_endian; + loff_t offset, ub_offset = 0; + int tried; + int found; + + zdebug("probe_zfs\n"); + /* Look for at least 4 uberblocks to ensure a positive match */ + for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK; + tried < ZFS_TRIES && found < ZFS_WANT; + tried++, offset += 4096) { + /* also try the second uberblock copy */ + if (tried == (ZFS_TRIES / 2)) + offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK; + + ub = (struct zfs_uberblock *) + blkid_probe_get_buffer(pr, offset, + sizeof(struct zfs_uberblock)); + if (ub == NULL) + return errno ? -errno : 1; + + if (ub->ub_magic == UBERBLOCK_MAGIC) { + ub_offset = offset; + found++; + } + + if ((swab_endian = (ub->ub_magic == swab_magic))) { + ub_offset = offset; + found++; + } + + zdebug("probe_zfs: found %s-endian uberblock at %llu\n", + swab_endian ? "big" : "little", offset >> 10); + } + + if (found < 4) + return 1; + + /* If we found the 4th uberblock, then we will have exited from the + * scanning loop immediately, and ub will be a valid uberblock. */ + blkid_probe_sprintf_version(pr, "%" PRIu64, swab_endian ? + swab64(ub->ub_version) : ub->ub_version); + + zfs_extract_guid_name(pr, offset); + + if (blkid_probe_set_magic(pr, ub_offset, + sizeof(ub->ub_magic), + (unsigned char *) &ub->ub_magic)) + return 1; + + return 0; +} + +const struct blkid_idinfo zfs_idinfo = +{ + .name = "zfs_member", + .usage = BLKID_USAGE_RAID, + .probefunc = probe_zfs, + .minsz = 64 * 1024 * 1024, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/src/sysfs.h b/libblkid/src/sysfs.h new file mode 100644 index 000000000..1de624aad --- /dev/null +++ b/libblkid/src/sysfs.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2011 Karel Zak <kzak@redhat.com> + */ +#ifndef UTIL_LINUX_SYSFS_H +#define UTIL_LINUX_SYSFS_H + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <inttypes.h> +#include <dirent.h> + +struct sysfs_cxt { + dev_t devno; + int dir_fd; /* /sys/block/<name> */ + char *dir_path; + struct sysfs_cxt *parent; + + unsigned int scsi_host, + scsi_channel, + scsi_target, + scsi_lun; + + unsigned int has_hctl : 1; +}; + +#define UL_SYSFSCXT_EMPTY { 0, -1, NULL, NULL, 0, 0, 0, 0, 0 } + +extern char *sysfs_devno_attribute_path(dev_t devno, char *buf, + size_t bufsiz, const char *attr); +extern int sysfs_devno_has_attribute(dev_t devno, const char *attr); +extern char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz); +extern char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz); +extern dev_t sysfs_devname_to_devno(const char *name, const char *parent); + +extern int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent) + __attribute__ ((warn_unused_result)); +extern void sysfs_deinit(struct sysfs_cxt *cxt); + +extern DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st); +extern ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr, + char *buf, size_t bufsiz); +extern int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, + const char *fmt, ...) + __attribute__ ((format (scanf, 3, 4))); + +extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res); +extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res); +extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res); + +extern int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str); +extern int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num); + +extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz); + +extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr); + +extern int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr); +extern int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname); +extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno); +extern char *sysfs_get_slave(struct sysfs_cxt *cxt); + +extern char *sysfs_get_devchain(struct sysfs_cxt *cxt, char *buf, size_t bufsz); +extern int sysfs_next_subsystem(struct sysfs_cxt *cxt, char *devchain, char **subsys); +extern int sysfs_is_hotpluggable(struct sysfs_cxt *cxt); + +extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, + const char *parent_name); + +extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, + size_t len, dev_t *diskdevno); + +extern int sysfs_devno_is_lvm_private(dev_t devno); +extern int sysfs_devno_is_wholedisk(dev_t devno); + +extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, + int *c, int *t, int *l); +extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, + const char *type, const char *attr); +extern int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type); +extern int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr); +extern int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern); + +#endif /* UTIL_LINUX_SYSFS_H */ diff --git a/libblkid/src/tag.c b/libblkid/src/tag.c new file mode 100644 index 000000000..6af806251 --- /dev/null +++ b/libblkid/src/tag.c @@ -0,0 +1,481 @@ +/* + * tag.c - allocation/initialization/free routines for tag structs + * + * Copyright (C) 2001 Andreas Dilger + * Copyright (C) 2003 Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * %End-Header% + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "blkidP.h" + +static blkid_tag blkid_new_tag(void) +{ + blkid_tag tag; + + if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag)))) + return NULL; + + INIT_LIST_HEAD(&tag->bit_tags); + INIT_LIST_HEAD(&tag->bit_names); + + return tag; +} + +void blkid_debug_dump_tag(blkid_tag tag) +{ + if (!tag) { + fprintf(stderr, " tag: NULL\n"); + return; + } + + fprintf(stderr, " tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); +} + +void blkid_free_tag(blkid_tag tag) +{ + if (!tag) + return; + + DBG(TAG, ul_debug(" freeing tag %s=%s", tag->bit_name, + tag->bit_val ? tag->bit_val : "(NULL)")); + DBG(TAG, blkid_debug_dump_tag(tag)); + + list_del(&tag->bit_tags); /* list of tags for this device */ + list_del(&tag->bit_names); /* list of tags with this type */ + + free(tag->bit_name); + free(tag->bit_val); + + free(tag); +} + +/* + * Find the desired tag on a device. If value is NULL, then the + * first such tag is returned, otherwise return only exact tag if found. + */ +blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) +{ + struct list_head *p; + + if (!dev || !type) + return NULL; + + list_for_each(p, &dev->bid_tags) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_tags); + + if (!strcmp(tmp->bit_name, type)) + return tmp; + } + return NULL; +} + +int blkid_dev_has_tag(blkid_dev dev, const char *type, + const char *value) +{ + blkid_tag tag; + + tag = blkid_find_tag_dev(dev, type); + if (!value) + return (tag != NULL); + if (!tag || strcmp(tag->bit_val, value)) + return 0; + return 1; +} + +/* + * Find the desired tag type in the cache. + * We return the head tag for this tag type. + */ +static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type) +{ + blkid_tag head = NULL, tmp; + struct list_head *p; + + if (!cache || !type) + return NULL; + + list_for_each(p, &cache->bic_tags) { + tmp = list_entry(p, struct blkid_struct_tag, bit_tags); + if (!strcmp(tmp->bit_name, type)) { + DBG(TAG, ul_debug(" found cache tag head %s", type)); + head = tmp; + break; + } + } + return head; +} + +/* + * Set a tag on an existing device. + * + * If value is NULL, then delete the tagsfrom the device. + */ +int blkid_set_tag(blkid_dev dev, const char *name, + const char *value, const int vlength) +{ + blkid_tag t = 0, head = 0; + char *val = 0; + char **dev_var = 0; + + if (!dev || !name) + return -BLKID_ERR_PARAM; + + if (value && !(val = strndup(value, vlength))) + return -BLKID_ERR_MEM; + + /* + * Certain common tags are linked directly to the device struct + * We need to know what they are before we do anything else because + * the function name parameter might get freed later on. + */ + if (!strcmp(name, "TYPE")) + dev_var = &dev->bid_type; + else if (!strcmp(name, "LABEL")) + dev_var = &dev->bid_label; + else if (!strcmp(name, "UUID")) + dev_var = &dev->bid_uuid; + + t = blkid_find_tag_dev(dev, name); + if (!value) { + if (t) + blkid_free_tag(t); + } else if (t) { + if (!strcmp(t->bit_val, val)) { + /* Same thing, exit */ + free(val); + return 0; + } + free(t->bit_val); + t->bit_val = val; + } else { + /* Existing tag not present, add to device */ + if (!(t = blkid_new_tag())) + goto errout; + t->bit_name = name ? strdup(name) : NULL; + t->bit_val = val; + t->bit_dev = dev; + + list_add_tail(&t->bit_tags, &dev->bid_tags); + + if (dev->bid_cache) { + head = blkid_find_head_cache(dev->bid_cache, + t->bit_name); + if (!head) { + head = blkid_new_tag(); + if (!head) + goto errout; + + DBG(TAG, ul_debug(" creating new cache tag head %s", name)); + head->bit_name = name ? strdup(name) : NULL; + if (!head->bit_name) + goto errout; + list_add_tail(&head->bit_tags, + &dev->bid_cache->bic_tags); + } + list_add_tail(&t->bit_names, &head->bit_names); + } + } + + /* Link common tags directly to the device struct */ + if (dev_var) + *dev_var = val; + + if (dev->bid_cache) + dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED; + return 0; + +errout: + if (t) + blkid_free_tag(t); + else + free(val); + if (head) + blkid_free_tag(head); + return -BLKID_ERR_MEM; +} + + +/* + * Parse a "NAME=value" string. This is slightly different than + * parse_token, because that will end an unquoted value at a space, while + * this will assume that an unquoted value is the rest of the token (e.g. + * if we are passed an already quoted string from the command-line we don't + * have to both quote and escape quote so that the quotes make it to + * us). + * + * Returns 0 on success, and -1 on failure. + */ +int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) +{ + char *name, *value, *cp; + + DBG(TAG, ul_debug("trying to parse '%s' as a tag", token)); + + if (!token || !(cp = strchr(token, '='))) + return -1; + + name = strdup(token); + if (!name) + return -1; + value = name + (cp - token); + *value++ = '\0'; + if (*value == '"' || *value == '\'') { + char c = *value++; + if (!(cp = strrchr(value, c))) + goto errout; /* missing closing quote */ + *cp = '\0'; + } + + if (ret_val) { + value = value && *value ? strdup(value) : NULL; + if (!value) + goto errout; + *ret_val = value; + } + + if (ret_type) + *ret_type = name; + else + free(name); + + return 0; + +errout: + DBG(TAG, ul_debug("parse error: '%s'", token)); + free(name); + return -1; +} + +/* + * Tag iteration routines for the public libblkid interface. + * + * These routines do not expose the list.h implementation, which are a + * contamination of the namespace, and which force us to reveal far, far + * too much of our internal implemenation. I'm not convinced I want + * to keep list.h in the long term, anyway. It's fine for kernel + * programming, but performance is not the #1 priority for this + * library, and I really don't like the tradeoff of type-safety for + * performance for this application. [tytso:20030125.2007EST] + */ + +/* + * This series of functions iterate over all tags in a device + */ +#define TAG_ITERATE_MAGIC 0x01a5284c + +struct blkid_struct_tag_iterate { + int magic; + blkid_dev dev; + struct list_head *p; +}; + +blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) +{ + blkid_tag_iterate iter; + + if (!dev) { + errno = EINVAL; + return NULL; + } + + iter = malloc(sizeof(struct blkid_struct_tag_iterate)); + if (iter) { + iter->magic = TAG_ITERATE_MAGIC; + iter->dev = dev; + iter->p = dev->bid_tags.next; + } + return (iter); +} + +/* + * Return 0 on success, -1 on error + */ +int blkid_tag_next(blkid_tag_iterate iter, + const char **type, const char **value) +{ + blkid_tag tag; + + if (!type || !value || + !iter || iter->magic != TAG_ITERATE_MAGIC || + iter->p == &iter->dev->bid_tags) + return -1; + + *type = 0; + *value = 0; + tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); + *type = tag->bit_name; + *value = tag->bit_val; + iter->p = iter->p->next; + return 0; +} + +void blkid_tag_iterate_end(blkid_tag_iterate iter) +{ + if (!iter || iter->magic != TAG_ITERATE_MAGIC) + return; + iter->magic = 0; + free(iter); +} + +/* + * This function returns a device which matches a particular + * type/value pair. If there is more than one device that matches the + * search specification, it returns the one with the highest priority + * value. This allows us to give preference to EVMS or LVM devices. + */ +blkid_dev blkid_find_dev_with_tag(blkid_cache cache, + const char *type, + const char *value) +{ + blkid_tag head; + blkid_dev dev; + int pri; + struct list_head *p; + int probe_new = 0; + + if (!cache || !type || !value) + return NULL; + + blkid_read_cache(cache); + + DBG(TAG, ul_debug("looking for %s=%s in cache", type, value)); + +try_again: + pri = -1; + dev = 0; + head = blkid_find_head_cache(cache, type); + + if (head) { + list_for_each(p, &head->bit_names) { + blkid_tag tmp = list_entry(p, struct blkid_struct_tag, + bit_names); + + if (!strcmp(tmp->bit_val, value) && + (tmp->bit_dev->bid_pri > pri) && + !access(tmp->bit_dev->bid_name, F_OK)) { + dev = tmp->bit_dev; + pri = dev->bid_pri; + } + } + } + if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) { + dev = blkid_verify(cache, dev); + if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))) + goto try_again; + } + + if (!dev && !probe_new) { + if (blkid_probe_all_new(cache) < 0) + return NULL; + probe_new++; + goto try_again; + } + + if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) { + if (blkid_probe_all(cache) < 0) + return NULL; + goto try_again; + } + return dev; +} + +#ifdef TEST_PROGRAM +#ifdef HAVE_GETOPT_H +#include <getopt.h> +#else +extern char *optarg; +extern int optind; +#endif + +void __attribute__((__noreturn__)) usage(char *prog) +{ + fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " + "[type value]\n", + prog); + fprintf(stderr, "\tList all tags for a device and exit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + blkid_tag_iterate iter; + blkid_cache cache = NULL; + blkid_dev dev; + int c, ret, found; + int flags = BLKID_DEV_FIND; + char *tmp; + char *file = NULL; + char *devname = NULL; + char *search_type = NULL; + char *search_value = NULL; + const char *type, *value; + + while ((c = getopt (argc, argv, "m:f:")) != EOF) + switch (c) { + case 'f': + file = optarg; + break; + case 'm': + { + int mask = strtoul (optarg, &tmp, 0); + if (*tmp) { + fprintf(stderr, "Invalid debug mask: %s\n", + optarg); + exit(1); + } + blkid_init_debug(mask); + break; + } + case '?': + usage(argv[0]); + } + if (argc > optind) + devname = argv[optind++]; + if (argc > optind) + search_type = argv[optind++]; + if (argc > optind) + search_value = argv[optind++]; + if (!devname || (argc != optind)) + usage(argv[0]); + + if ((ret = blkid_get_cache(&cache, file)) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + + dev = blkid_get_dev(cache, devname, flags); + if (!dev) { + fprintf(stderr, "%s: Can not find device in blkid cache\n", + devname); + exit(1); + } + if (search_type) { + found = blkid_dev_has_tag(dev, search_type, search_value); + printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev), + search_type, search_value ? search_value : "NULL", + found ? "FOUND" : "NOT FOUND"); + return(!found); + } + printf("Device %s...\n", blkid_dev_devname(dev)); + + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) { + printf("\tTag %s has value %s\n", type, value); + } + blkid_tag_iterate_end(iter); + + blkid_put_cache(cache); + return (0); +} +#endif diff --git a/libblkid/src/topology/dm.c b/libblkid/src/topology/dm.c new file mode 100644 index 000000000..e061632ca --- /dev/null +++ b/libblkid/src/topology/dm.c @@ -0,0 +1,135 @@ +/* + * device-mapper (dm) topology + * -- this is fallback for old systems where the topology information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +static int is_dm_device(dev_t devno) +{ + return blkid_driver_has_major("device-mapper", major(devno)); +} + +static int probe_dm_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const char *paths[] = { + "/usr/local/sbin/dmsetup", + "/usr/sbin/dmsetup", + "/sbin/dmsetup" + }; + int dmpipe[] = { -1, -1 }, stripes, stripesize; + char *cmd = NULL; + FILE *stream = NULL; + long long offset, size; + size_t i; + dev_t devno = blkid_probe_get_devno(pr); + + if (!devno) + goto nothing; /* probably not a block device */ + if (!is_dm_device(devno)) + goto nothing; + + for (i = 0; i < ARRAY_SIZE(paths); i++) { + struct stat sb; + if (stat(paths[i], &sb) == 0) { + cmd = (char *) paths[i]; + break; + } + } + + if (!cmd) + goto nothing; + if (pipe(dmpipe) < 0) { + DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); + goto nothing; + } + + switch (fork()) { + case 0: + { + char *dmargv[7], maj[16], min[16]; + + /* Plumbing */ + close(dmpipe[0]); + + if (dmpipe[1] != STDOUT_FILENO) + dup2(dmpipe[1], STDOUT_FILENO); + + /* The libblkid library could linked with setuid programs */ + if (setgid(getgid()) < 0) + exit(1); + if (setuid(getuid()) < 0) + exit(1); + + snprintf(maj, sizeof(maj), "%d", major(devno)); + snprintf(min, sizeof(min), "%d", minor(devno)); + + dmargv[0] = cmd; + dmargv[1] = "table"; + dmargv[2] = "-j"; + dmargv[3] = maj; + dmargv[4] = "-m"; + dmargv[5] = min; + dmargv[6] = NULL; + + execv(dmargv[0], dmargv); + + DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); + exit(1); + } + case -1: + DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); + goto nothing; + default: + break; + } + + stream = fdopen(dmpipe[0], "r" UL_CLOEXECSTR); + if (!stream) + goto nothing; + + if (fscanf(stream, "%lld %lld striped %d %d ", + &offset, &size, &stripes, &stripesize) != 0) + goto nothing; + + blkid_topology_set_minimum_io_size(pr, stripesize << 9); + blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 9); + + fclose(stream); + close(dmpipe[1]); + return 0; + +nothing: + if (stream) + fclose(stream); + else if (dmpipe[0] != -1) + close(dmpipe[0]); + if (dmpipe[1] != -1) + close(dmpipe[1]); + return 1; +} + +const struct blkid_idinfo dm_tp_idinfo = +{ + .name = "dm", + .probefunc = probe_dm_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/evms.c b/libblkid/src/topology/evms.c index 7a4fd554d..7a4fd554d 100644 --- a/libblkid/evms.c +++ b/libblkid/src/topology/evms.c diff --git a/libblkid/ioctl.c b/libblkid/src/topology/ioctl.c index 3aba09e4f..3aba09e4f 100644 --- a/libblkid/ioctl.c +++ b/libblkid/src/topology/ioctl.c diff --git a/libblkid/src/topology/lvm.c b/libblkid/src/topology/lvm.c new file mode 100644 index 000000000..bd079d47b --- /dev/null +++ b/libblkid/src/topology/lvm.c @@ -0,0 +1,147 @@ +/* + * lvm topology + * -- this is fallback for old systems where the topology information is not + * exported by sysfs + * + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "topology.h" + +#ifndef LVM_BLK_MAJOR +# define LVM_BLK_MAJOR 58 +#endif + +static int is_lvm_device(dev_t devno) +{ + if (major(devno) == LVM_BLK_MAJOR) + return 1; + return blkid_driver_has_major("lvm", major(devno)); +} + +static int probe_lvm_tp(blkid_probe pr, + const struct blkid_idmag *mag __attribute__((__unused__))) +{ + const char *paths[] = { + "/usr/local/sbin/lvdisplay", + "/usr/sbin/lvdisplay", + "/sbin/lvdisplay" + }; + int lvpipe[] = { -1, -1 }, stripes = 0, stripesize = 0; + FILE *stream = NULL; + char *cmd = NULL, *devname = NULL, buf[1024]; + size_t i; + dev_t devno = blkid_probe_get_devno(pr); + + if (!devno) + goto nothing; /* probably not a block device */ + if (!is_lvm_device(devno)) + goto nothing; + + for (i = 0; i < ARRAY_SIZE(paths); i++) { + struct stat sb; + if (stat(paths[i], &sb) == 0) { + cmd = (char *) paths[i]; + break; + } + } + + if (!cmd) + goto nothing; + + devname = blkid_devno_to_devname(devno); + if (!devname) + goto nothing; + + if (pipe(lvpipe) < 0) { + DBG(LOWPROBE, ul_debug("Failed to open pipe: errno=%d", errno)); + goto nothing; + } + + switch (fork()) { + case 0: + { + char *lvargv[3]; + + /* Plumbing */ + close(lvpipe[0]); + + if (lvpipe[1] != STDOUT_FILENO) + dup2(lvpipe[1], STDOUT_FILENO); + + /* The libblkid library could linked with setuid programs */ + if (setgid(getgid()) < 0) + exit(1); + if (setuid(getuid()) < 0) + exit(1); + + lvargv[0] = cmd; + lvargv[1] = devname; + lvargv[2] = NULL; + + execv(lvargv[0], lvargv); + + DBG(LOWPROBE, ul_debug("Failed to execute %s: errno=%d", cmd, errno)); + exit(1); + } + case -1: + DBG(LOWPROBE, ul_debug("Failed to forking: errno=%d", errno)); + goto nothing; + default: + break; + } + + stream = fdopen(lvpipe[0], "r" UL_CLOEXECSTR); + if (!stream) + goto nothing; + + while (fgets(buf, sizeof(buf), stream) != NULL) { + if (!strncmp(buf, "Stripes", 7)) + sscanf(buf, "Stripes %d", &stripes); + + if (!strncmp(buf, "Stripe size", 11)) + sscanf(buf, "Stripe size (KByte) %d", &stripesize); + } + + if (!stripes) + goto nothing; + + blkid_topology_set_minimum_io_size(pr, stripesize << 10); + blkid_topology_set_optimal_io_size(pr, (stripes * stripesize) << 10); + + free(devname); + fclose(stream); + close(lvpipe[1]); + return 0; + +nothing: + free(devname); + if (stream) + fclose(stream); + else if (lvpipe[0] != -1) + close(lvpipe[0]); + if (lvpipe[1] != -1) + close(lvpipe[1]); + return 1; +} + +const struct blkid_idinfo lvm_tp_idinfo = +{ + .name = "lvm", + .probefunc = probe_lvm_tp, + .magics = BLKID_NONE_MAGIC +}; + diff --git a/libblkid/md.c b/libblkid/src/topology/md.c index 5eba94787..5eba94787 100644 --- a/libblkid/md.c +++ b/libblkid/src/topology/md.c diff --git a/libblkid/sysfs2.c b/libblkid/src/topology/sysfs.c index a04b20a37..a04b20a37 100644 --- a/libblkid/sysfs2.c +++ b/libblkid/src/topology/sysfs.c diff --git a/libblkid/src/topology/topology.c b/libblkid/src/topology/topology.c new file mode 100644 index 000000000..93fa3802e --- /dev/null +++ b/libblkid/src/topology/topology.c @@ -0,0 +1,362 @@ +/* + * topology - gathers information about device topology + * + * Copyright 2009 Red Hat, Inc. All rights reserved. + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> + +#include "topology.h" + +/** + * SECTION:topology + * @title: Topology information + * @short_description: block device topology information. + * + * The topology chain provides details about Linux block devices, for more + * information see: + * + * Linux kernel Documentation/ABI/testing/sysfs-block + * + * NAME=value (tags) interface is enabled by blkid_probe_enable_topology(), + * and provides: + * + * @LOGICAL_SECTOR_SIZE: this is the smallest unit the storage device can + * address. It is typically 512 bytes. + * + * @PHYSICAL_SECTOR_SIZE: this is the smallest unit a physical storage device + * can write atomically. It is usually the same as the + * logical sector size but may be bigger. + * + * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O. + * For RAID arrays it is often the stripe chunk size. + * + * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero. For RAID arrays + * it is usually the stripe width or the internal track size. + * + * @ALIGNMENT_OFFSET: indicates how many bytes the beginning of the device is + * offset from the disk's natural alignment. + * + * The NAME=value tags are not defined when the corresponding topology value + * is zero. The MINIMUM_IO_SIZE should be always defined if kernel provides + * topology information. + * + * Binary interface: + * + * blkid_probe_get_topology() + * + * blkid_topology_get_'VALUENAME'() + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn); +static void topology_free(blkid_probe pr, void *data); +static int topology_is_complete(blkid_probe pr); +static int topology_set_logical_sector_size(blkid_probe pr); + +/* + * Binary interface + */ +struct blkid_struct_topology { + unsigned long alignment_offset; + unsigned long minimum_io_size; + unsigned long optimal_io_size; + unsigned long logical_sector_size; + unsigned long physical_sector_size; +}; + +/* + * Topology chain probing functions + */ +static const struct blkid_idinfo *idinfos[] = +{ +#ifdef __linux__ + &ioctl_tp_idinfo, + &sysfs_tp_idinfo, + &md_tp_idinfo, + &dm_tp_idinfo, + &lvm_tp_idinfo, + &evms_tp_idinfo +#endif +}; + + +/* + * Driver definition + */ +const struct blkid_chaindrv topology_drv = { + .id = BLKID_CHAIN_TOPLGY, + .name = "topology", + .dflt_enabled = FALSE, + .idinfos = idinfos, + .nidinfos = ARRAY_SIZE(idinfos), + .probe = topology_probe, + .safeprobe = topology_probe, + .free_data = topology_free +}; + +/** + * blkid_probe_enable_topology: + * @pr: probe + * @enable: TRUE/FALSE + * + * Enables/disables the topology probing for non-binary interface. + * + * Returns: 0 on success, or -1 in case of error. + */ +int blkid_probe_enable_topology(blkid_probe pr, int enable) +{ + if (!pr) + return -1; + pr->chains[BLKID_CHAIN_TOPLGY].enabled = enable; + return 0; +} + +/** + * blkid_probe_get_topology: + * @pr: probe + * + * This is a binary interface for topology values. See also blkid_topology_* + * functions. + * + * This function is independent on blkid_do_[safe,full]probe() and + * blkid_probe_enable_topology() calls. + * + * WARNING: the returned object will be overwritten by the next + * blkid_probe_get_topology() call for the same @pr. If you want to + * use more blkid_topopogy objects in the same time you have to create + * more blkid_probe handlers (see blkid_new_probe()). + * + * Returns: blkid_topopogy, or NULL in case of error. + */ +blkid_topology blkid_probe_get_topology(blkid_probe pr) +{ + return (blkid_topology) blkid_probe_get_binary_data(pr, + &pr->chains[BLKID_CHAIN_TOPLGY]); +} + +/* + * The blkid_do_probe() backend. + */ +static int topology_probe(blkid_probe pr, struct blkid_chain *chn) +{ + size_t i; + + if (!pr || chn->idx < -1) + return -1; + + if (!S_ISBLK(pr->mode)) + return -EINVAL; /* nothing, works with block devices only */ + + if (chn->binary) { + DBG(LOWPROBE, ul_debug("initialize topology binary data")); + + if (chn->data) + /* reset binary data */ + memset(chn->data, 0, + sizeof(struct blkid_struct_topology)); + else { + chn->data = calloc(1, + sizeof(struct blkid_struct_topology)); + if (!chn->data) + return -ENOMEM; + } + } + + blkid_probe_chain_reset_vals(pr, chn); + + DBG(LOWPROBE, ul_debug("--> starting probing loop [TOPOLOGY idx=%d]", + chn->idx)); + + i = chn->idx < 0 ? 0 : chn->idx + 1U; + + for ( ; i < ARRAY_SIZE(idinfos); i++) { + const struct blkid_idinfo *id = idinfos[i]; + + chn->idx = i; + + if (id->probefunc) { + DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name)); + if (id->probefunc(pr, NULL) != 0) + continue; + } + + if (!topology_is_complete(pr)) + continue; + + /* generic for all probing drivers */ + topology_set_logical_sector_size(pr); + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]", + id->name, chn->idx)); + return BLKID_PROBE_OK; + } + + DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]", + chn->idx)); + return BLKID_PROBE_NONE; +} + +static void topology_free(blkid_probe pr __attribute__((__unused__)), + void *data) +{ + free(data); +} + +static int topology_set_value(blkid_probe pr, const char *name, + size_t structoff, unsigned long data) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (!chn) + return -1; + if (!data) + return 0; /* ignore zeros */ + + if (chn->binary) { + memcpy(chn->data + structoff, &data, sizeof(data)); + return 0; + } + return blkid_probe_sprintf_value(pr, name, "%lu", data); +} + + +/* the topology info is complete when we have at least "minimum_io_size" which + * is provided by all blkid topology drivers */ +static int topology_is_complete(blkid_probe pr) +{ + struct blkid_chain *chn = blkid_probe_get_chain(pr); + + if (!chn) + return FALSE; + + if (chn->binary && chn->data) { + blkid_topology tp = (blkid_topology) chn->data; + if (tp->minimum_io_size) + return TRUE; + } + + return __blkid_probe_lookup_value(pr, "MINIMUM_IO_SIZE") ? TRUE : FALSE; +} + +int blkid_topology_set_alignment_offset(blkid_probe pr, int val) +{ + unsigned long xval; + + /* Welcome to Hell. The kernel is able to return -1 as an + * alignment_offset if no compatible sizes and alignments + * exist for stacked devices. + * + * There is no way how libblkid caller can respond to the value -1, so + * we will hide this corner case... + * + * (TODO: maybe we can export an extra boolean value 'misaligned' rather + * then complete hide this problem.) + */ + xval = val < 0 ? 0 : val; + + return topology_set_value(pr, + "ALIGNMENT_OFFSET", + offsetof(struct blkid_struct_topology, alignment_offset), + xval); +} + +int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "MINIMUM_IO_SIZE", + offsetof(struct blkid_struct_topology, minimum_io_size), + val); +} + +int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "OPTIMAL_IO_SIZE", + offsetof(struct blkid_struct_topology, optimal_io_size), + val); +} + +/* BLKSSZGET is provided on all systems since 2.3.3 -- so we don't have to + * waste time with sysfs. + */ +static int topology_set_logical_sector_size(blkid_probe pr) +{ + unsigned long val = blkid_probe_get_sectorsize(pr); + + if (!val) + return -1; + + return topology_set_value(pr, + "LOGICAL_SECTOR_SIZE", + offsetof(struct blkid_struct_topology, logical_sector_size), + val); +} + +int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val) +{ + return topology_set_value(pr, + "PHYSICAL_SECTOR_SIZE", + offsetof(struct blkid_struct_topology, physical_sector_size), + val); +} + +/** + * blkid_topology_get_alignment_offset: + * @tp: topology + * + * Returns: alignment offset in bytes or 0. + */ +unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) +{ + return tp->alignment_offset; +} + +/** + * blkid_topology_get_minimum_io_size: + * @tp: topology + * + * Returns: minimum io size in bytes or 0. + */ +unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) +{ + return tp->minimum_io_size; +} + +/** + * blkid_topology_get_optimal_io_size + * @tp: topology + * + * Returns: optimal io size in bytes or 0. + */ +unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) +{ + return tp->optimal_io_size; +} + +/** + * blkid_topology_get_logical_sector_size + * @tp: topology + * + * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. + */ +unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) +{ + return tp->logical_sector_size; +} + +/** + * blkid_topology_get_physical_sector_size + * @tp: topology + * + * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. + */ +unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) +{ + return tp->physical_sector_size; +} + diff --git a/libblkid/topology.h b/libblkid/src/topology/topology.h index 6d2f43345..6d2f43345 100644 --- a/libblkid/topology.h +++ b/libblkid/src/topology/topology.h diff --git a/libblkid/src/verify.c b/libblkid/src/verify.c new file mode 100644 index 000000000..06f6d53d5 --- /dev/null +++ b/libblkid/src/verify.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2008 Karel Zak <kzak@redhat.com> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#include "blkidP.h" +#include "sysfs.h" + +static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev) +{ + const char *data; + const char *name; + int nvals, n; + size_t len; + + nvals = blkid_probe_numof_values(pr); + + for (n = 0; n < nvals; n++) { + if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0) + continue; + if (strncmp(name, "PART_ENTRY_", 11) == 0) { + if (strcmp(name, "PART_ENTRY_UUID") == 0) + blkid_set_tag(dev, "PARTUUID", data, len); + else if (strcmp(name, "PART_ENTRY_NAME") == 0) + blkid_set_tag(dev, "PARTLABEL", data, len); + + } else if (!strstr(name, "_ID")) { + /* superblock UUID, LABEL, ... + * but not {SYSTEM,APPLICATION,..._ID} */ + blkid_set_tag(dev, name, data, len); + } + } +} + +/* + * Verify that the data in dev is consistent with what is on the actual + * block device (using the devname field only). Normally this will be + * called when finding items in the cache, but for long running processes + * is also desirable to revalidate an item before use. + * + * If we are unable to revalidate the data, we return the old data and + * do not set the BLKID_BID_FL_VERIFIED flag on it. + */ +blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) +{ + blkid_tag_iterate iter; + const char *type, *value; + struct stat st; + time_t diff, now; + int fd; + + if (!dev || !cache) + return NULL; + + now = time(0); + diff = now - dev->bid_time; + + if (stat(dev->bid_name, &st) < 0) { + DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while " + "trying to stat %s", errno, + dev->bid_name)); + open_err: + if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { + /* We don't have read permission, just return cache data. */ + DBG(PROBE, ul_debug("returning unverified data for %s", + dev->bid_name)); + return dev; + } + blkid_free_dev(dev); + return NULL; + } + + if (now >= dev->bid_time && +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + (st.st_mtime < dev->bid_time || + (st.st_mtime == dev->bid_time && + st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && +#else + st.st_mtime <= dev->bid_time && +#endif + (diff < BLKID_PROBE_MIN || + (dev->bid_flags & BLKID_BID_FL_VERIFIED && + diff < BLKID_PROBE_INTERVAL))) + return dev; + +#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu, stat time %lu,\t" + "time since last check %lu)", + dev->bid_name, (unsigned long)dev->bid_time, + (unsigned long)st.st_mtime, (unsigned long)diff)); +#else + DBG(PROBE, ul_debug("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\t" + "time since last check %lu)", + dev->bid_name, + (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime, + (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000, + (unsigned long)diff)); +#endif + + if (sysfs_devno_is_lvm_private(st.st_rdev)) { + blkid_free_dev(dev); + return NULL; + } + if (!cache->probe) { + cache->probe = blkid_new_probe(); + if (!cache->probe) { + blkid_free_dev(dev); + return NULL; + } + } + + fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + DBG(PROBE, ul_debug("blkid_verify: error %m (%d) while " + "opening %s", errno, + dev->bid_name)); + goto open_err; + } + + if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { + /* failed to read the device */ + close(fd); + blkid_free_dev(dev); + return NULL; + } + + /* remove old cache info */ + iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(iter, &type, &value) == 0) + blkid_set_tag(dev, type, NULL, 0); + blkid_tag_iterate_end(iter); + + /* enable superblocks probing */ + blkid_probe_enable_superblocks(cache->probe, TRUE); + blkid_probe_set_superblocks_flags(cache->probe, + BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | + BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE); + + /* enable partitions probing */ + blkid_probe_enable_partitions(cache->probe, TRUE); + blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS); + + /* probe */ + if (blkid_do_safeprobe(cache->probe)) { + /* found nothing or error */ + blkid_free_dev(dev); + dev = NULL; + } + + if (dev) { +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { + dev->bid_time = tv.tv_sec; + dev->bid_utime = tv.tv_usec; + } else +#endif + dev->bid_time = time(0); + + dev->bid_devno = st.st_rdev; + dev->bid_flags |= BLKID_BID_FL_VERIFIED; + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + + blkid_probe_to_tags(cache->probe, dev); + + DBG(PROBE, ul_debug("%s: devno 0x%04llx, type %s", + dev->bid_name, (long long)st.st_rdev, dev->bid_type)); + } + + blkid_reset_probe(cache->probe); + blkid_probe_reset_superblocks_filter(cache->probe); + close(fd); + return dev; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + blkid_dev dev; + blkid_cache cache; + int ret; + + if (argc != 2) { + fprintf(stderr, "Usage: %s device\n" + "Probe a single device to determine type\n", argv[0]); + exit(1); + } + if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { + fprintf(stderr, "%s: error creating cache (%d)\n", + argv[0], ret); + exit(1); + } + dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); + if (!dev) { + printf("%s: %s has an unsupported type\n", argv[0], argv[1]); + return (1); + } + printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); + if (dev->bid_label) + printf("LABEL='%s'\n", dev->bid_label); + if (dev->bid_uuid) + printf("UUID='%s'\n", dev->bid_uuid); + + blkid_free_dev(dev); + return (0); +} +#endif diff --git a/libblkid/src/version.c b/libblkid/src/version.c new file mode 100644 index 000000000..9d129f7ae --- /dev/null +++ b/libblkid/src/version.c @@ -0,0 +1,62 @@ +/* + * version.c --- Return the version of the blkid library + * + * Copyright (C) 2004 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Lesser General + * Public License. + * %End-Header% + */ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include <blkid.h> + +/* LIBBLKID_* defined in the global config.h */ +static const char *lib_version = LIBBLKID_VERSION; /* release version */ +static const char *lib_date = LIBBLKID_DATE; + +/** + * blkid_parse_version_string: + * @ver_string: version string (e.g. "2.16.0") + * + * Returns: release version code. + */ +int blkid_parse_version_string(const char *ver_string) +{ + const char *cp; + int version = 0; + + for (cp = ver_string; *cp; cp++) { + if (*cp == '.') + continue; + if (!isdigit(*cp)) + break; + version = (version * 10) + (*cp - '0'); + } + return version; +} + +/** + * blkid_get_library_version: + * @ver_string: returns relese version (!= SONAME version) + * @date_string: returns date + * + * Returns: release version code. + */ +int blkid_get_library_version(const char **ver_string, + const char **date_string) +{ + if (ver_string) + *ver_string = lib_version; + if (date_string) + *date_string = lib_date; + + return blkid_parse_version_string(lib_version); +} diff --git a/libblkid/src/widechar.h b/libblkid/src/widechar.h new file mode 100644 index 000000000..b023b5fb2 --- /dev/null +++ b/libblkid/src/widechar.h @@ -0,0 +1,38 @@ +/* Declarations for wide characters */ +/* This file must be included last because the redefinition of wchar_t may + cause conflicts when system include files were included after it. */ + +#ifdef HAVE_WIDECHAR + +# include <wchar.h> +# include <wctype.h> + +#else /* !HAVE_WIDECHAR */ + +# include <ctype.h> + /* Fallback for types */ +# define wchar_t char +# define wint_t int +# define WEOF EOF + /* Fallback for input operations */ +# define fgetwc fgetc +# define getwc getc +# define getwchar getchar +# define fgetws fgets + /* Fallback for output operations */ +# define fputwc fputc +# define putwc putc +# define putwchar putchar +# define fputws fputs + /* Fallback for character classification */ +# define iswgraph isgraph +# define iswprint isprint +# define iswspace isspace + /* Fallback for string functions */ +# define wcschr strchr +# define wcsdup strdup +# define wcslen strlen + +# define wcwidth(c) 1 + +#endif /* HAVE_WIDECHAR */ diff --git a/libblkid/src/xalloc.h b/libblkid/src/xalloc.h new file mode 100644 index 000000000..f012fb294 --- /dev/null +++ b/libblkid/src/xalloc.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org> + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + * + * General memory allocation wrappers for malloc, realloc, calloc and strdup + */ + +#ifndef UTIL_LINUX_XALLOC_H +#define UTIL_LINUX_XALLOC_H + +#include <stdlib.h> +#include <string.h> + +#include "c.h" + +#ifndef XALLOC_EXIT_CODE +# define XALLOC_EXIT_CODE EXIT_FAILURE +#endif + +static inline __ul_alloc_size(1) +void *xmalloc(const size_t size) +{ + void *ret = malloc(size); + + if (!ret && size) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline __ul_alloc_size(2) +void *xrealloc(void *ptr, const size_t size) +{ + void *ret = realloc(ptr, size); + + if (!ret && size) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline __ul_calloc_size(1, 2) +void *xcalloc(const size_t nelems, const size_t size) +{ + void *ret = calloc(nelems, size); + + if (!ret && size && nelems) + err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); + return ret; +} + +static inline char __attribute__((warn_unused_result)) *xstrdup(const char *str) +{ + char *ret; + + if (!str) + return NULL; + + ret = strdup(str); + + if (!ret) + err(XALLOC_EXIT_CODE, "cannot duplicate string"); + return ret; +} + +static inline char * __attribute__((warn_unused_result)) xstrndup(const char *str, size_t size) +{ + char *ret; + + if (!str) + return NULL; + + ret = strndup(str, size); + + if (!ret) + err(XALLOC_EXIT_CODE, "cannot duplicate string"); + return ret; +} + + +static inline int __attribute__ ((__format__(printf, 2, 3))) + xasprintf(char **strp, const char *fmt, ...) +{ + int ret; + va_list args; + va_start(args, fmt); + ret = vasprintf(&(*strp), fmt, args); + va_end(args); + if (ret < 0) + err(XALLOC_EXIT_CODE, "cannot allocate string"); + return ret; +} + +static inline int xvasprintf(char **strp, const char *fmt, va_list ap) +{ + int ret = vasprintf(&(*strp), fmt, ap); + if (ret < 0) + err(XALLOC_EXIT_CODE, "cannot allocate string"); + return ret; +} + + +static inline char * __attribute__((warn_unused_result)) xgethostname(void) +{ + char *name; + size_t sz = get_hostname_max() + 1; + + name = xmalloc(sizeof(char) * sz); + + if (gethostname(name, sz) != 0) { + free(name); + return NULL; + } + name[sz - 1] = '\0'; + return name; +} + +#endif diff --git a/libblkid/strutils.c b/libblkid/strutils.c deleted file mode 100644 index 2337b07b9..000000000 --- a/libblkid/strutils.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright (C) 2010 Karel Zak <kzak@redhat.com> - * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <inttypes.h> -#include <ctype.h> -#include <errno.h> -#include <sys/stat.h> -#include <string.h> - -#include "c.h" -#include "nls.h" -#include "strutils.h" -#include "bitops.h" - -static int do_scale_by_power (uintmax_t *x, int base, int power) -{ - while (power--) { - if (UINTMAX_MAX / base < *x) - return -2; - *x *= base; - } - return 0; -} - -/* - * strtosize() - convert string to size (uintmax_t). - * - * Supported suffixes: - * - * XiB or X for 2^N - * where X = {K,M,G,T,P,E,Y,Z} - * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only) - * for example: - * 10KiB = 10240 - * 10K = 10240 - * - * XB for 10^N - * where X = {K,M,G,T,P,E,Y,Z} - * for example: - * 10KB = 10000 - * - * Note that the function does not accept numbers with '-' (negative sign) - * prefix. - */ -int strtosize(const char *str, uintmax_t *res) -{ - char *p; - uintmax_t x; - int base = 1024, rc = 0; - - *res = 0; - - if (!str || !*str) - goto err; - - /* Only positive numbers are acceptable - * - * Note that this check is not perfect, it would be better to - * use lconv->negative_sign. But coreutils use the same solution, - * so it's probably good enough... - */ - p = (char *) str; - while (isspace((unsigned char) *p)) - p++; - if (*p == '-') - goto err; - p = NULL; - - errno = 0; - x = strtoumax(str, &p, 0); - - if (p == str || - (errno != 0 && (x == UINTMAX_MAX || x == 0))) - goto err; - - if (!p || !*p) - goto done; /* without suffix */ - - /* - * Check size suffixes - */ - if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3)) - base = 1024; /* XiB, 2^N */ - else if (*(p + 1) == 'B' && !*(p + 2)) - base = 1000; /* XB, 10^N */ - else if (*(p + 1)) - goto err; /* unexpected suffix */ - - switch(*p) { - case 'K': - case 'k': - rc = do_scale_by_power(&x, base, 1); - break; - case 'M': - case 'm': - rc = do_scale_by_power(&x, base, 2); - break; - case 'G': - case 'g': - rc = do_scale_by_power(&x, base, 3); - break; - case 'T': - case 't': - rc = do_scale_by_power(&x, base, 4); - break; - case 'P': - case 'p': - rc = do_scale_by_power(&x, base, 5); - break; - case 'E': - case 'e': - rc = do_scale_by_power(&x, base, 6); - break; - case 'Z': - rc = do_scale_by_power(&x, base, 7); - break; - case 'Y': - rc = do_scale_by_power(&x, base, 8); - break; - default: - goto err; - } - -done: - *res = x; - return rc; -err: - return -1; -} - -#ifndef HAVE_MEMPCPY -void *mempcpy(void *restrict dest, const void *restrict src, size_t n) -{ - return ((char *)memcpy(dest, src, n)) + n; -} -#endif - -#ifndef HAVE_STRNLEN -size_t strnlen(const char *s, size_t maxlen) -{ - int i; - - for (i = 0; i < maxlen; i++) { - if (s[i] == '\0') - return i + 1; - } - return maxlen; -} -#endif - -#ifndef HAVE_STRNCHR -char *strnchr(const char *s, size_t maxlen, int c) -{ - for (; maxlen-- && *s != '\0'; ++s) - if (*s == (char)c) - return (char *)s; - return NULL; -} -#endif - -#ifndef HAVE_STRNDUP -char *strndup(const char *s, size_t n) -{ - size_t len = strnlen(s, n); - char *new = (char *) malloc((len + 1) * sizeof(char)); - if (!new) - return NULL; - new[len] = '\0'; - return (char *) memcpy(new, s, len); -} -#endif - -int16_t strtos16_or_err(const char *str, const char *errmesg) -{ - int32_t num = strtos32_or_err(str, errmesg); - - if (num < INT16_MIN || num > INT16_MAX) - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - return num; -} - -uint16_t strtou16_or_err(const char *str, const char *errmesg) -{ - uint32_t num = strtou32_or_err(str, errmesg); - - if (num > UINT16_MAX) - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - return num; -} - -int32_t strtos32_or_err(const char *str, const char *errmesg) -{ - int64_t num = strtos64_or_err(str, errmesg); - - if (num < INT32_MIN || num > INT32_MAX) - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - return num; -} - -uint32_t strtou32_or_err(const char *str, const char *errmesg) -{ - uint64_t num = strtou64_or_err(str, errmesg); - - if (num > UINT32_MAX) - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - return num; -} - -int64_t strtos64_or_err(const char *str, const char *errmesg) -{ - int64_t num; - char *end = NULL; - - if (str == NULL || *str == '\0') - goto err; - errno = 0; - num = strtoimax(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -uint64_t strtou64_or_err(const char *str, const char *errmesg) -{ - uintmax_t num; - char *end = NULL; - - if (str == NULL || *str == '\0') - goto err; - errno = 0; - num = strtoumax(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - - -double strtod_or_err(const char *str, const char *errmesg) -{ - double num; - char *end = NULL; - - if (str == NULL || *str == '\0') - goto err; - errno = 0; - num = strtod(str, &end); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -long strtol_or_err(const char *str, const char *errmesg) -{ - long num; - char *end = NULL; - - if (str == NULL || *str == '\0') - goto err; - errno = 0; - num = strtol(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -unsigned long strtoul_or_err(const char *str, const char *errmesg) -{ - unsigned long num; - char *end = NULL; - - if (str == NULL || *str == '\0') - goto err; - errno = 0; - num = strtoul(str, &end, 10); - - if (errno || str == end || (end && *end)) - goto err; - - return num; -err: - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -uintmax_t strtosize_or_err(const char *str, const char *errmesg) -{ - uintmax_t num; - - if (strtosize(str, &num) == 0) - return num; - - if (errno) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); -} - -/* - * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must - * be 10 bytes. - */ -void strmode(mode_t mode, char *str) -{ - if (S_ISDIR(mode)) - str[0] = 'd'; - else if (S_ISLNK(mode)) - str[0] = 'l'; - else if (S_ISCHR(mode)) - str[0] = 'c'; - else if (S_ISBLK(mode)) - str[0] = 'b'; - else if (S_ISSOCK(mode)) - str[0] = 's'; - else if (S_ISFIFO(mode)) - str[0] = 'p'; - else if (S_ISREG(mode)) - str[0] = '-'; - - str[1] = mode & S_IRUSR ? 'r' : '-'; - str[2] = mode & S_IWUSR ? 'w' : '-'; - str[3] = (mode & S_ISUID - ? (mode & S_IXUSR ? 's' : 'S') - : (mode & S_IXUSR ? 'x' : '-')); - str[4] = mode & S_IRGRP ? 'r' : '-'; - str[5] = mode & S_IWGRP ? 'w' : '-'; - str[6] = (mode & S_ISGID - ? (mode & S_IXGRP ? 's' : 'S') - : (mode & S_IXGRP ? 'x' : '-')); - str[7] = mode & S_IROTH ? 'r' : '-'; - str[8] = mode & S_IWOTH ? 'w' : '-'; - str[9] = (mode & S_ISVTX - ? (mode & S_IXOTH ? 't' : 'T') - : (mode & S_IXOTH ? 'x' : '-')); - str[10] = '\0'; -} - -/* - * returns exponent (2^x=n) in range KiB..PiB - */ -static int get_exp(uint64_t n) -{ - int shft; - - for (shft = 10; shft <= 60; shft += 10) { - if (n < (1ULL << shft)) - break; - } - return shft - 10; -} - -char *size_to_human_string(int options, uint64_t bytes) -{ - char buf[32]; - int dec, exp; - uint64_t frac; - const char *letters = "BKMGTPE"; - char suffix[sizeof(" KiB")], *psuf = suffix; - char c; - - if (options & SIZE_SUFFIX_SPACE) - *psuf++ = ' '; - - exp = get_exp(bytes); - c = *(letters + (exp ? exp / 10 : 0)); - dec = exp ? bytes / (1ULL << exp) : bytes; - frac = exp ? bytes % (1ULL << exp) : 0; - - *psuf++ = c; - - if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) { - *psuf++ = 'i'; - *psuf++ = 'B'; - } - - *psuf = '\0'; - - /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n", - * exp, suffix[0], dec, frac); - */ - - if (frac) { - /* round */ - frac = (frac / (1ULL << (exp - 10)) + 50) / 100; - if (frac == 10) - dec++, frac = 0; - } - - if (frac) { - struct lconv const *l = localeconv(); - char *dp = l ? l->decimal_point : NULL; - - if (!dp || !*dp) - dp = "."; - snprintf(buf, sizeof(buf), "%d%s%jd%s", dec, dp, frac, suffix); - } else - snprintf(buf, sizeof(buf), "%d%s", dec, suffix); - - return strdup(buf); -} - -/* - * Parses comma delimited list to array with IDs, for example: - * - * "aaa,bbb,ccc" --> ary[0] = FOO_AAA; - * ary[1] = FOO_BBB; - * ary[3] = FOO_CCC; - * - * The function name2id() provides conversion from string to ID. - * - * Returns: >= 0 : number of items added to ary[] - * -1 : parse error or unknown item - * -2 : arysz reached - */ -int string_to_idarray(const char *list, int ary[], size_t arysz, - int (name2id)(const char *, size_t)) -{ - const char *begin = NULL, *p; - size_t n = 0; - - if (!list || !*list || !ary || !arysz || !name2id) - return -1; - - for (p = list; p && *p; p++) { - const char *end = NULL; - int id; - - if (n >= arysz) - return -2; - if (!begin) - begin = p; /* begin of the column name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - id = name2id(begin, end - begin); - if (id == -1) - return -1; - ary[ n++ ] = id; - begin = NULL; - if (end && !*end) - break; - } - return n; -} - -/* - * Parses the array like string_to_idarray but if format is "+aaa,bbb" - * it adds fields to array instead of replacing them. - */ -int string_add_to_idarray(const char *list, int ary[], size_t arysz, - int *ary_pos, int (name2id)(const char *, size_t)) -{ - const char *list_add; - int r; - - if (!list || !*list || !ary_pos || - *ary_pos < 0 || (size_t) *ary_pos > arysz) - return -1; - - if (list[0] == '+') - list_add = &list[1]; - else { - list_add = list; - *ary_pos = 0; - } - - r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id); - if (r > 0) - *ary_pos += r; - return r; -} - -/* - * LIST ::= <item> [, <item>] - * - * The <item> is translated to 'id' by name2id() function and the 'id' is used - * as a position in the 'ary' bit array. It means that the 'id' has to be in - * range <0..N> where N < sizeof(ary) * NBBY. - * - * Returns: 0 on success, <0 on error. - */ -int string_to_bitarray(const char *list, - char *ary, - int (*name2bit)(const char *, size_t)) -{ - const char *begin = NULL, *p; - - if (!list || !name2bit || !ary) - return -EINVAL; - - for (p = list; p && *p; p++) { - const char *end = NULL; - int bit; - - if (!begin) - begin = p; /* begin of the level name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - bit = name2bit(begin, end - begin); - if (bit < 0) - return bit; - setbit(ary, bit); - begin = NULL; - if (end && !*end) - break; - } - return 0; -} - -/* - * LIST ::= <item> [, <item>] - * - * The <item> is translated to 'id' by name2flag() function and the flags is - * set to the 'mask' -* - * Returns: 0 on success, <0 on error. - */ -int string_to_bitmask(const char *list, - unsigned long *mask, - long (*name2flag)(const char *, size_t)) -{ - const char *begin = NULL, *p; - - if (!list || !name2flag || !mask) - return -EINVAL; - - for (p = list; p && *p; p++) { - const char *end = NULL; - long flag; - - if (!begin) - begin = p; /* begin of the level name */ - if (*p == ',') - end = p; /* terminate the name */ - if (*(p + 1) == '\0') - end = p + 1; /* end of string */ - if (!begin || !end) - continue; - if (end <= begin) - return -1; - - flag = name2flag(begin, end - begin); - if (flag < 0) - return flag; /* error */ - *mask |= flag; - begin = NULL; - if (end && !*end) - break; - } - return 0; -} - -/* - * Parse the lower and higher values in a string containing - * "lower:higher" or "lower-higher" format. Note that either - * the lower or the higher values may be missing, and the def - * value will be assigned to it by default. - * - * Returns: 0 on success, <0 on error. - */ -int parse_range(const char *str, int *lower, int *upper, int def) -{ - char *end = NULL; - - if (!str) - return 0; - - *upper = *lower = def; - errno = 0; - - if (*str == ':') { /* <:N> */ - str++; - *upper = strtol(str, &end, 10); - if (errno || !end || *end || end == str) - return -1; - } else { - *upper = *lower = strtol(str, &end, 10); - if (errno || !end || end == str) - return -1; - - if (*end == ':' && !*(end + 1)) /* <M:> */ - *upper = 0; - else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */ - str = end + 1; - end = NULL; - errno = 0; - *upper = strtol(str, &end, 10); - - if (errno || !end || *end || end == str) - return -1; - } - } - return 0; -} - -/* - * Compare two strings for equality, ignoring at most one trailing - * slash. - */ -int streq_except_trailing_slash(const char *s1, const char *s2) -{ - int equal; - - if (!s1 && !s2) - return 1; - if (!s1 || !s2) - return 0; - - equal = !strcmp(s1, s2); - - if (!equal) { - size_t len1 = strlen(s1); - size_t len2 = strlen(s2); - - if (len1 && *(s1 + len1 - 1) == '/') - len1--; - if (len2 && *(s2 + len2 - 1) == '/') - len2--; - if (len1 != len2) - return 0; - - equal = !strncmp(s1, s2, len1); - } - - return equal; -} - - -#ifdef TEST_PROGRAM - -int main(int argc, char *argv[]) -{ - uintmax_t size = 0; - char *hum, *hum2; - - if (argc < 2) { - fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]); - exit(EXIT_FAILURE); - } - - if (strtosize(argv[1], &size)) - errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]); - - hum = size_to_human_string(SIZE_SUFFIX_1LETTER, size); - hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER | - SIZE_SUFFIX_SPACE, size); - - printf("%25s : %20ju : %8s : %12s\n", argv[1], size, hum, hum2); - free(hum); - free(hum2); - - return EXIT_SUCCESS; -} -#endif /* TEST_PROGRAM */ diff --git a/libblkid/strutils.h b/libblkid/strutils.h deleted file mode 100644 index 00598cf62..000000000 --- a/libblkid/strutils.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef UTIL_LINUX_STRUTILS -#define UTIL_LINUX_STRUTILS - -#include <inttypes.h> -#include <string.h> -#include <sys/types.h> - -/* default strtoxx_or_err() exit code */ -#ifndef STRTOXX_EXIT_CODE -# define STRTOXX_EXIT_CODE EXIT_FAILURE -#endif - - -extern int strtosize(const char *str, uintmax_t *res); -extern uintmax_t strtosize_or_err(const char *str, const char *errmesg); - -extern int16_t strtos16_or_err(const char *str, const char *errmesg); -extern uint16_t strtou16_or_err(const char *str, const char *errmesg); - -extern int32_t strtos32_or_err(const char *str, const char *errmesg); -extern uint32_t strtou32_or_err(const char *str, const char *errmesg); - -extern int64_t strtos64_or_err(const char *str, const char *errmesg); -extern uint64_t strtou64_or_err(const char *str, const char *errmesg); - -extern double strtod_or_err(const char *str, const char *errmesg); - -extern long strtol_or_err(const char *str, const char *errmesg); -extern unsigned long strtoul_or_err(const char *str, const char *errmesg); - -#ifndef HAVE_MEMPCPY -extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n); -#endif -#ifndef HAVE_STRNLEN -extern size_t strnlen(const char *s, size_t maxlen); -#endif -#ifndef HAVE_STRNDUP -extern char *strndup(const char *s, size_t n); -#endif -#ifndef HAVE_STRNCHR -extern char *strnchr(const char *s, size_t maxlen, int c); -#endif - -/* caller guarantees n > 0 */ -static inline void xstrncpy(char *dest, const char *src, size_t n) -{ - strncpy(dest, src, n-1); - dest[n-1] = 0; -} - -extern void strmode(mode_t mode, char *str); - -/* Options for size_to_human_string() */ -enum -{ - SIZE_SUFFIX_1LETTER = 0, - SIZE_SUFFIX_3LETTER = 1, - SIZE_SUFFIX_SPACE = 2 -}; - -extern char *size_to_human_string(int options, uint64_t bytes); - -extern int string_to_idarray(const char *list, int ary[], size_t arysz, - int (name2id)(const char *, size_t)); -extern int string_add_to_idarray(const char *list, int ary[], - size_t arysz, int *ary_pos, - int (name2id)(const char *, size_t)); - -extern int string_to_bitarray(const char *list, char *ary, - int (*name2bit)(const char *, size_t)); - -extern int string_to_bitmask(const char *list, - unsigned long *mask, - long (*name2flag)(const char *, size_t)); -extern int parse_range(const char *str, int *lower, int *upper, int def); - -extern int streq_except_trailing_slash(const char *s1, const char *s2); - -#endif diff --git a/libblkid/sun.c b/libblkid/sun.c deleted file mode 100644 index f151f46ae..000000000 --- a/libblkid/sun.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * sun (solaris-sparc) partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> -#include <stddef.h> - -#include "partitions.h" - -/* Supported VTOC setting */ -#define SUN_VTOC_SANITY 0x600DDEEE /* magic number */ -#define SUN_VTOC_VERSION 1 - -#define SUN_MAXPARTITIONS 8 - -/* Partition IDs */ -#define SUN_TAG_WHOLEDISK 0x05 - -struct sun_disklabel { - unsigned char info[128]; /* Informative text string */ - - struct sun_vtoc { - uint32_t version; /* version */ - char volume[8]; /* volume name */ - uint16_t nparts; /* num of partitions */ - - struct sun_info { /* partition information */ - uint16_t id; /* tag */ - uint16_t flags; - } __attribute__ ((packed)) infos[8]; - - uint16_t padding; /* padding */ - uint32_t bootinfo[3]; /* info needed by mboot */ - uint32_t sanity; /* magic number */ - uint32_t reserved[10]; /* padding */ - uint32_t timestamp[8]; /* partition timestamp */ - } __attribute__ ((packed)) vtoc; - - uint32_t write_reinstruct; /* sectors to skip, writes */ - uint32_t read_reinstruct; /* sectors to skip, reads */ - unsigned char spare[148]; /* padding */ - uint16_t rspeed; /* disk rotational speed */ - uint16_t pcylcount; /* physical cylinder count */ - uint16_t sparecyl; /* extra sects per cylinder */ - uint16_t obs1; - uint16_t obs2; - uint16_t ilfact; /* interleave factor */ - uint16_t ncyl; /* data cylinder count */ - uint16_t nacyl; /* alt. cylinder count */ - uint16_t ntrks; /* tracks per cylinder <---- */ - uint16_t nsect; /* sectors per track <---- */ - uint16_t obs3; - uint16_t obs4; - - struct sun_partition { /* partitions */ - uint32_t start_cylinder; - uint32_t num_sectors; - } __attribute__ ((packed)) partitions[8]; - - uint16_t magic; /* magic number */ - uint16_t csum; /* label xor'd checksum */ -} __attribute__ ((packed)); - - -uint16_t count_checksum(struct sun_disklabel *label) -{ - uint16_t *ptr = ((uint16_t *) (label + 1)) - 1; - uint16_t sum; - - for (sum = 0; ptr >= ((uint16_t *) label);) - sum ^= *ptr--; - - return sum; -} - -static int probe_sun_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct sun_disklabel *l; - struct sun_partition *p; - blkid_parttable tab = NULL; - blkid_partlist ls; - uint16_t nparts; - blkid_loff_t spc; - int i, use_vtoc; - - l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0); - if (!l) - goto nothing; - - if (count_checksum(l)) { - DBG(DEBUG_LOWPROBE, printf( - "detected corrupted sun disk label -- ignore\n")); - goto nothing; - } - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "sun", 0); - if (!tab) - goto err; - - /* sectors per cylinder (partition offset is in cylinders...) */ - spc = be16_to_cpu(l->ntrks) * be16_to_cpu(l->nsect); - - DBG(DEBUG_LOWPROBE, - printf("Sun VTOC sanity=%u version=%u nparts=%u\n", - be32_to_cpu(l->vtoc.sanity), - be32_to_cpu(l->vtoc.version), - be16_to_cpu(l->vtoc.nparts))); - - /* Check to see if we can use the VTOC table */ - use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) && - (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) && - (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS)); - - /* Use 8 partition entries if not specified in validated VTOC */ - nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS; - - /* - * So that old Linux-Sun partitions continue to work, - * alow the VTOC to be used under the additional condition ... - */ - use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts); - - for (i = 0, p = l->partitions; i < nparts; i++, p++) { - - blkid_loff_t start, size; - uint16_t type = 0, flags = 0; - blkid_partition par; - - start = be32_to_cpu(p->start_cylinder) * spc; - size = be32_to_cpu(p->num_sectors); - if (use_vtoc) { - type = be16_to_cpu(l->vtoc.infos[i].id); - flags = be16_to_cpu(l->vtoc.infos[i].flags); - } - - if (type == SUN_TAG_WHOLEDISK || !size) { - blkid_partlist_increment_partno(ls); - continue; - } - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - if (type) - blkid_partition_set_type(par, type); - if (flags) - blkid_partition_set_flags(par, flags); - } - return 0; - -nothing: - return 1; -err: - return -1; -} - - -const struct blkid_idinfo sun_pt_idinfo = -{ - .name = "sun", - .probefunc = probe_sun_pt, - .magics = - { - { - .magic = "\xDA\xBE", /* big-endian magic string */ - .len = 2, - .sboff = offsetof(struct sun_disklabel, magic) - }, - { NULL } - } -}; - diff --git a/libblkid/superblocks.c b/libblkid/superblocks.c deleted file mode 100644 index 384d2cad7..000000000 --- a/libblkid/superblocks.c +++ /dev/null @@ -1,804 +0,0 @@ -/* - * superblocks.c - reads information from filesystem and raid superblocks - * - * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <stdint.h> -#include <stdarg.h> - -#include "superblocks.h" - -/** - * SECTION:superblocks - * @title: Superblocks probing - * @short_description: filesystems and raids superblocks probing. - * - * The library API has been originally designed for superblocks probing only. - * This is reason why some *deprecated* superblock specific functions don't use - * '_superblocks_' namespace in the function name. Please, don't use these - * functions in new code. - * - * The 'superblocks' probers support NAME=value (tags) interface only. The - * superblocks probing is enabled by default (and controlled by - * blkid_probe_enable_superblocks()). - * - * Currently supported tags: - * - * @TYPE: filesystem type - * - * @SEC_TYPE: secondary filesystem type - * - * @LABEL: filesystem label - * - * @LABEL_RAW: raw label from FS superblock - * - * @UUID: filesystem UUID (lower case) - * - * @UUID_SUB: subvolume uuid (e.g. btrfs) - * - * @UUID_RAW: raw UUID from FS superblock - * - * @EXT_JOURNAL: external journal UUID - * - * @USAGE: usage string: "raid", "filesystem", ... - * - * @VERSION: filesystem version - * - * @MOUNT: cluster mount name (?) -- ocfs only - * - * @SBMAGIC: super block magic string - * - * @SBMAGIC_OFFSET: offset of SBMAGIC - * - * @FSSIZE: size of filessystem [not-implemented yet] - * - * @SYSTEM_ID: ISO9660 system identifier - * - * @PUBLISHER_ID: ISO9660 publisher identifier - * - * @APPLICATION_ID: ISO9660 application identifier - * - * @BOOT_SYSTEM_ID: ISO9660 boot system identifier - */ - -static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn); -static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn); - -static int blkid_probe_set_usage(blkid_probe pr, int usage); - - -/* - * Superblocks chains probing functions - */ -static const struct blkid_idinfo *idinfos[] = -{ - /* RAIDs */ - &linuxraid_idinfo, - &ddfraid_idinfo, - &iswraid_idinfo, - &lsiraid_idinfo, - &viaraid_idinfo, - &silraid_idinfo, - &nvraid_idinfo, - &pdcraid_idinfo, - &highpoint45x_idinfo, - &highpoint37x_idinfo, - &adraid_idinfo, - &jmraid_idinfo, - - &drbd_idinfo, - &drbdproxy_datalog_idinfo, - &lvm2_idinfo, - &lvm1_idinfo, - &snapcow_idinfo, - &verity_hash_idinfo, - &luks_idinfo, - &vmfs_volume_idinfo, - - /* Filesystems */ - &vfat_idinfo, - &swsuspend_idinfo, - &swap_idinfo, - &xfs_idinfo, - &ext4dev_idinfo, - &ext4_idinfo, - &ext3_idinfo, - &ext2_idinfo, - &jbd_idinfo, - &reiser_idinfo, - &reiser4_idinfo, - &jfs_idinfo, - &udf_idinfo, - &iso9660_idinfo, - &zfs_idinfo, - &hfsplus_idinfo, - &hfs_idinfo, - &ufs_idinfo, - &hpfs_idinfo, - &sysv_idinfo, - &xenix_idinfo, - &ntfs_idinfo, - &cramfs_idinfo, - &romfs_idinfo, - &minix_idinfo, - &gfs_idinfo, - &gfs2_idinfo, - &ocfs_idinfo, - &ocfs2_idinfo, - &oracleasm_idinfo, - &vxfs_idinfo, - &squashfs_idinfo, - &netware_idinfo, - &btrfs_idinfo, - &ubifs_idinfo, - &bfs_idinfo, - &vmfs_fs_idinfo, - &befs_idinfo, - &nilfs2_idinfo, - &exfat_idinfo, - &f2fs_idinfo -}; - -/* - * Driver definition - */ -const struct blkid_chaindrv superblocks_drv = { - .id = BLKID_CHAIN_SUBLKS, - .name = "superblocks", - .dflt_enabled = TRUE, - .dflt_flags = BLKID_SUBLKS_DEFAULT, - .idinfos = idinfos, - .nidinfos = ARRAY_SIZE(idinfos), - .has_fltr = TRUE, - .probe = superblocks_probe, - .safeprobe = superblocks_safeprobe, -}; - -/** - * blkid_probe_enable_superblocks: - * @pr: probe - * @enable: TRUE/FALSE - * - * Enables/disables the superblocks probing for non-binary interface. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_enable_superblocks(blkid_probe pr, int enable) -{ - if (!pr) - return -1; - pr->chains[BLKID_CHAIN_SUBLKS].enabled = enable; - return 0; -} - -/** - * blkid_probe_set_superblocks_flags: - * @pr: prober - * @flags: BLKID_SUBLKS_* flags - * - * Sets probing flags to the superblocks prober. This function is optional, the - * default are BLKID_SUBLKS_DEFAULTS flags. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_set_superblocks_flags(blkid_probe pr, int flags) -{ - if (!pr) - return -1; - - pr->chains[BLKID_CHAIN_SUBLKS].flags = flags; - return 0; -} - -/** - * blkid_probe_reset_superblocks_filter: - * @pr: prober - * - * Resets superblocks probing filter - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_reset_superblocks_filter(blkid_probe pr) -{ - return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS); -} - -/** - * blkid_probe_invert_superblocks_filter: - * @pr: prober - * - * Inverts superblocks probing filter - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_invert_superblocks_filter(blkid_probe pr) -{ - return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS); -} - -/** - * blkid_probe_filter_superblocks_type: - * @pr: prober - * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag - * @names: NULL terminated array of probing function names (e.g. "vfat"). - * - * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names; - * - * %BLKID_FLTR_ONLYIN - probe for items which are IN @names - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_filter_superblocks_type(blkid_probe pr, int flag, char *names[]) -{ - return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names); -} - -/** - * blkid_probe_filter_superblocks_usage: - * @pr: prober - * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag - * @usage: BLKID_USAGE_* flags - * - * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @usage; - * - * %BLKID_FLTR_ONLYIN - probe for items which are IN @usage - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_filter_superblocks_usage(blkid_probe pr, int flag, int usage) -{ - unsigned long *fltr; - struct blkid_chain *chn; - size_t i; - - fltr = blkid_probe_get_filter(pr, BLKID_CHAIN_SUBLKS, TRUE); - if (!fltr) - return -1; - - chn = &pr->chains[BLKID_CHAIN_SUBLKS]; - - for (i = 0; i < chn->driver->nidinfos; i++) { - const struct blkid_idinfo *id = chn->driver->idinfos[i]; - - if (id->usage & usage) { - if (flag & BLKID_FLTR_NOTIN) - blkid_bmp_set_item(chn->fltr, i); - } else if (flag & BLKID_FLTR_ONLYIN) - blkid_bmp_set_item(chn->fltr, i); - } - DBG(DEBUG_LOWPROBE, printf("a new probing usage-filter initialized\n")); - return 0; -} - -/** - * blkid_known_fstype: - * @fstype: filesystem name - * - * Returns: 1 for known filesytems, or 0 for unknown filesystem. - */ -int blkid_known_fstype(const char *fstype) -{ - size_t i; - - if (!fstype) - return 0; - - for (i = 0; i < ARRAY_SIZE(idinfos); i++) { - const struct blkid_idinfo *id = idinfos[i]; - if (strcmp(id->name, fstype) == 0) - return 1; - } - return 0; -} - -/** - * blkid_superblocks_get_name: - * @idx: number >= 0 - * @name: returns name of supported filesystem/raid (optional) - * @usage: returns BLKID_USAGE_* flags, (optional) - * - * Returns: -1 if @idx is out of range, or 0 on success. - */ -int blkid_superblocks_get_name(size_t idx, const char **name, int *usage) -{ - if (idx < ARRAY_SIZE(idinfos)) { - if (name) - *name = idinfos[idx]->name; - if (usage) - *usage = idinfos[idx]->usage; - return 0; - } - return -1; -} - -/* - * The blkid_do_probe() backend. - */ -static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) -{ - size_t i; - - if (!pr || chn->idx < -1) - return -1; - blkid_probe_chain_reset_vals(pr, chn); - - DBG(DEBUG_LOWPROBE, - printf("--> starting probing loop [SUBLKS idx=%d]\n", - chn->idx)); - - if (pr->size <= 0 || (pr->size <= 1024 && !S_ISCHR(pr->mode))) - /* Ignore very very small block devices or regular files (e.g. - * extended partitions). Note that size of the UBI char devices - * is 1 byte */ - goto nothing; - - i = chn->idx < 0 ? 0 : chn->idx + 1U; - - for ( ; i < ARRAY_SIZE(idinfos); i++) { - const struct blkid_idinfo *id; - const struct blkid_idmag *mag = NULL; - blkid_loff_t off = 0; - int rc = 0; - - chn->idx = i; - id = idinfos[i]; - - if (chn->fltr && blkid_bmp_get_item(chn->fltr, i)) { - DBG(DEBUG_LOWPROBE, printf("filter out: %s\n", id->name)); - continue; - } - - if (id->minsz && id->minsz > pr->size) - continue; /* the device is too small */ - - /* don't probe for RAIDs, swap or journal on CD/DVDs */ - if ((id->usage & (BLKID_USAGE_RAID | BLKID_USAGE_OTHER)) && - blkid_probe_is_cdrom(pr)) - continue; - - /* don't probe for RAIDs on floppies */ - if ((id->usage & BLKID_USAGE_RAID) && blkid_probe_is_tiny(pr)) - continue; - - DBG(DEBUG_LOWPROBE, printf("[%zd] %s:\n", i, id->name)); - - if (blkid_probe_get_idmag(pr, id, &off, &mag)) - continue; - - /* final check by probing function */ - if (id->probefunc) { - DBG(DEBUG_LOWPROBE, printf("\tcall probefunc()\n")); - if (id->probefunc(pr, mag) != 0) { - blkid_probe_chain_reset_vals(pr, chn); - continue; - } - } - - /* all cheks passed */ - if (chn->flags & BLKID_SUBLKS_TYPE) - rc = blkid_probe_set_value(pr, "TYPE", - (unsigned char *) id->name, - strlen(id->name) + 1); - - if (!rc) - rc = blkid_probe_set_usage(pr, id->usage); - - if (!rc && mag) - rc = blkid_probe_set_magic(pr, off, mag->len, - (unsigned char *) mag->magic); - if (rc) { - blkid_probe_chain_reset_vals(pr, chn); - DBG(DEBUG_LOWPROBE, printf("failed to set result -- ingnore\n")); - continue; - } - - DBG(DEBUG_LOWPROBE, - printf("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]\n", - id->name, chn->idx)); - return 0; - } - -nothing: - DBG(DEBUG_LOWPROBE, - printf("<-- leaving probing loop (failed) [SUBLKS idx=%d]\n", - chn->idx)); - return 1; -} - -/* - * This is the same function as blkid_do_probe(), but returns only one result - * (cannot be used in while()) and checks for ambivalen results (more - * filesystems on the device) -- in such case returns -2. - * - * The function does not check for filesystems when a RAID or crypto signature - * is detected. The function also does not check for collision between RAIDs - * and crypto devices. The first detected RAID or crypto device is returned. - * - * The function does not probe for ambivalent results on very small devices - * (e.g. floppies), on small devices the first detected filesystem is returned. - */ -static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn) -{ - struct blkid_prval vals[BLKID_NVALS_SUBLKS]; - int nvals = BLKID_NVALS_SUBLKS; - int idx = -1; - int count = 0; - int intol = 0; - int rc; - - while ((rc = superblocks_probe(pr, chn)) == 0) { - - if (blkid_probe_is_tiny(pr) && !count) - /* floppy or so -- returns the first result. */ - return 0; - - count++; - - if (chn->idx >= 0 && - idinfos[chn->idx]->usage & (BLKID_USAGE_RAID | BLKID_USAGE_CRYPTO)) - break; - - if (chn->idx >= 0 && - !(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT)) - intol++; - - if (count == 1) { - /* save the first result */ - nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals); - idx = chn->idx; - } - } - - if (rc < 0) - return rc; /* error */ - - if (count > 1 && intol) { - DBG(DEBUG_LOWPROBE, - printf("ERROR: superblocks chain: " - "ambivalent result detected (%d filesystems)!\n", - count)); - return -2; /* error, ambivalent result (more FS) */ - } - if (!count) - return 1; /* nothing detected */ - - if (idx != -1) { - /* restore the first result */ - blkid_probe_chain_reset_vals(pr, chn); - blkid_probe_append_vals(pr, vals, nvals); - chn->idx = idx; - } - - /* - * The RAID device could be partitioned. The problem are RAID1 devices - * where the partition table is visible from underlaying devices. We - * have to ignore such partition tables. - */ - if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID) - pr->prob_flags |= BLKID_PROBE_FL_IGNORE_PT; - - return 0; -} - -int blkid_probe_set_version(blkid_probe pr, const char *version) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - if (chn->flags & BLKID_SUBLKS_VERSION) - return blkid_probe_set_value(pr, "VERSION", - (unsigned char *) version, strlen(version) + 1); - return 0; -} - - -int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - int rc = 0; - - if (chn->flags & BLKID_SUBLKS_VERSION) { - va_list ap; - - va_start(ap, fmt); - rc = blkid_probe_vsprintf_value(pr, "VERSION", fmt, ap); - va_end(ap); - } - return rc; -} - -static int blkid_probe_set_usage(blkid_probe pr, int usage) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - char *u = NULL; - - if (!(chn->flags & BLKID_SUBLKS_USAGE)) - return 0; - - if (usage & BLKID_USAGE_FILESYSTEM) - u = "filesystem"; - else if (usage & BLKID_USAGE_RAID) - u = "raid"; - else if (usage & BLKID_USAGE_CRYPTO) - u = "crypto"; - else if (usage & BLKID_USAGE_OTHER) - u = "other"; - else - u = "unknown"; - - return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1); -} - -int blkid_probe_set_id_label(blkid_probe pr, const char *name, - unsigned char *data, size_t len) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - struct blkid_prval *v; - - if (!(chn->flags & BLKID_SUBLKS_LABEL)) - return 0; - - v = blkid_probe_assign_value(pr, name); - if (!v) - return -1; - - if (len >= BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ - 1; /* make a space for \0 */ - - memcpy(v->data, data, len); - v->data[len] = '\0'; - - /* remove white spaces */ - v->len = blkid_rtrim_whitespace(v->data) + 1; - if (v->len > 1) - v->len = blkid_ltrim_whitespace(v->data) + 1; - - if (v->len <= 1) - blkid_probe_reset_last_value(pr); /* ignore empty */ - return 0; -} - -int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - struct blkid_prval *v; - if (len > BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ; - - if ((chn->flags & BLKID_SUBLKS_LABELRAW) && - blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) - return -1; - if (!(chn->flags & BLKID_SUBLKS_LABEL)) - return 0; - v = blkid_probe_assign_value(pr, "LABEL"); - if (!v) - return -1; - - if (len == BLKID_PROBVAL_BUFSIZ) - len--; /* make a space for \0 */ - - memcpy(v->data, label, len); - v->data[len] = '\0'; - - v->len = blkid_rtrim_whitespace(v->data) + 1; - if (v->len == 1) - blkid_probe_reset_last_value(pr); - return 0; -} - -int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, - size_t len, int enc) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - struct blkid_prval *v; - - if ((chn->flags & BLKID_SUBLKS_LABELRAW) && - blkid_probe_set_value(pr, "LABEL_RAW", label, len) < 0) - return -1; - if (!(chn->flags & BLKID_SUBLKS_LABEL)) - return 0; - v = blkid_probe_assign_value(pr, "LABEL"); - if (!v) - return -1; - - blkid_encode_to_utf8(enc, v->data, sizeof(v->data), label, len); - v->len = blkid_rtrim_whitespace(v->data) + 1; - if (v->len == 1) - blkid_probe_reset_last_value(pr); - return 0; -} - -/* like uuid_is_null() from libuuid, but works with arbitrary size of UUID */ -static int uuid_is_empty(const unsigned char *buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) - if (buf[i]) - return 0; - return 1; -} - -int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, - size_t len, const char *fmt, ...) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - int rc = -1; - va_list ap; - - if (len > BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ; - - if (uuid_is_empty(uuid, len)) - return 0; - - if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && - blkid_probe_set_value(pr, "UUID_RAW", uuid, len) < 0) - return -1; - if (!(chn->flags & BLKID_SUBLKS_UUID)) - return 0; - - va_start(ap, fmt); - rc = blkid_probe_vsprintf_value(pr, "UUID", fmt, ap); - va_end(ap); - - /* convert to lower case (..be paranoid) */ - if (!rc) { - size_t i; - struct blkid_prval *v = __blkid_probe_get_value(pr, - blkid_probe_numof_values(pr)); - if (v) { - for (i = 0; i < v->len; i++) - if (v->data[i] >= 'A' && v->data[i] <= 'F') - v->data[i] = (v->data[i] - 'A') + 'a'; - } - } - return rc; -} - -/* function to set UUIDs that are in suberblocks stored as strings */ -int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - struct blkid_prval *v; - - if (str == NULL || *str == '\0') - return -1; - if (!len) - len = strlen((char *) str); - if (len > BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ; - - if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && - blkid_probe_set_value(pr, "UUID_RAW", str, len) < 0) - return -1; - if (!(chn->flags & BLKID_SUBLKS_UUID)) - return 0; - - v = blkid_probe_assign_value(pr, "UUID"); - if (v) { - if (len == BLKID_PROBVAL_BUFSIZ) - len--; /* make a space for \0 */ - - memcpy((char *) v->data, str, len); - v->data[len] = '\0'; - v->len = len + 1; - return 0; - } - return -1; -} - -/* default _set_uuid function to set DCE UUIDs */ -int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - struct blkid_prval *v; - - if (uuid_is_empty(uuid, 16)) - return 0; - - if (!name) { - if ((chn->flags & BLKID_SUBLKS_UUIDRAW) && - blkid_probe_set_value(pr, "UUID_RAW", uuid, 16) < 0) - return -1; - if (!(chn->flags & BLKID_SUBLKS_UUID)) - return 0; - - v = blkid_probe_assign_value(pr, "UUID"); - } else - v = blkid_probe_assign_value(pr, name); - - blkid_unparse_uuid(uuid, (char *) v->data, sizeof(v->data)); - v->len = 37; - - return 0; -} - -int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid) -{ - return blkid_probe_set_uuid_as(pr, uuid, NULL); -} - -/** - * blkid_probe_set_request: - * @pr: probe - * @flags: BLKID_PROBREQ_* (deprecated) or BLKID_SUBLKS_* flags - * - * Returns: 0 on success, or -1 in case of error. - * - * Deprecated: Use blkid_probe_set_superblocks_flags(). - */ -int blkid_probe_set_request(blkid_probe pr, int flags) -{ - return blkid_probe_set_superblocks_flags(pr, flags); -} - -/** - * blkid_probe_reset_filter: - * @pr: prober - * - * Returns: 0 on success, or -1 in case of error. - * - * Deprecated: Use blkid_probe_reset_superblocks_filter(). - */ -int blkid_probe_reset_filter(blkid_probe pr) -{ - return __blkid_probe_reset_filter(pr, BLKID_CHAIN_SUBLKS); -} - -/** - * blkid_probe_invert_filter: - * @pr: prober - * - * Returns: 0 on success, or -1 in case of error. - * - * Deprecated: Use blkid_probe_invert_superblocks_filter(). - */ -int blkid_probe_invert_filter(blkid_probe pr) -{ - return __blkid_probe_invert_filter(pr, BLKID_CHAIN_SUBLKS); -} - -/** - * blkid_probe_filter_types - * @pr: prober - * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag - * @names: NULL terminated array of probing function names (e.g. "vfat"). - * - * Returns: 0 on success, or -1 in case of error. - * - * Deprecated: Use blkid_probe_filter_superblocks_types(). - */ -int blkid_probe_filter_types(blkid_probe pr, int flag, char *names[]) -{ - return __blkid_probe_filter_types(pr, BLKID_CHAIN_SUBLKS, flag, names); -} - -/** - * blkid_probe_filter_usage - * @pr: prober - * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag - * @usage: BLKID_USAGE_* flags - * - * Returns: 0 on success, or -1 in case of error. - * - * Deprecated: Use blkid_probe_filter_superblocks_usage(). - */ -int blkid_probe_filter_usage(blkid_probe pr, int flag, int usage) -{ - return blkid_probe_filter_superblocks_usage(pr, flag, usage); -} - - diff --git a/libblkid/superblocks.h b/libblkid/superblocks.h deleted file mode 100644 index e45dc6a84..000000000 --- a/libblkid/superblocks.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#ifndef _BLKID_SUPERBLOCKS_H -#define _BLKID_SUPERBLOCKS_H - -#include "blkidP.h" - -extern const struct blkid_idinfo cramfs_idinfo; -extern const struct blkid_idinfo swap_idinfo; -extern const struct blkid_idinfo swsuspend_idinfo; -extern const struct blkid_idinfo adraid_idinfo; -extern const struct blkid_idinfo ddfraid_idinfo; -extern const struct blkid_idinfo iswraid_idinfo; -extern const struct blkid_idinfo jmraid_idinfo; -extern const struct blkid_idinfo lsiraid_idinfo; -extern const struct blkid_idinfo nvraid_idinfo; -extern const struct blkid_idinfo pdcraid_idinfo; -extern const struct blkid_idinfo silraid_idinfo; -extern const struct blkid_idinfo viaraid_idinfo; -extern const struct blkid_idinfo linuxraid_idinfo; -extern const struct blkid_idinfo ext4dev_idinfo; -extern const struct blkid_idinfo ext4_idinfo; -extern const struct blkid_idinfo ext3_idinfo; -extern const struct blkid_idinfo ext2_idinfo; -extern const struct blkid_idinfo jbd_idinfo; -extern const struct blkid_idinfo jfs_idinfo; -extern const struct blkid_idinfo xfs_idinfo; -extern const struct blkid_idinfo gfs_idinfo; -extern const struct blkid_idinfo gfs2_idinfo; -extern const struct blkid_idinfo romfs_idinfo; -extern const struct blkid_idinfo ocfs_idinfo; -extern const struct blkid_idinfo ocfs2_idinfo; -extern const struct blkid_idinfo oracleasm_idinfo; -extern const struct blkid_idinfo reiser_idinfo; -extern const struct blkid_idinfo reiser4_idinfo; -extern const struct blkid_idinfo hfs_idinfo; -extern const struct blkid_idinfo hfsplus_idinfo; -extern const struct blkid_idinfo ntfs_idinfo; -extern const struct blkid_idinfo iso9660_idinfo; -extern const struct blkid_idinfo udf_idinfo; -extern const struct blkid_idinfo vxfs_idinfo; -extern const struct blkid_idinfo minix_idinfo; -extern const struct blkid_idinfo vfat_idinfo; -extern const struct blkid_idinfo ufs_idinfo; -extern const struct blkid_idinfo hpfs_idinfo; -extern const struct blkid_idinfo lvm2_idinfo; -extern const struct blkid_idinfo lvm1_idinfo; -extern const struct blkid_idinfo snapcow_idinfo; -extern const struct blkid_idinfo verity_hash_idinfo; -extern const struct blkid_idinfo luks_idinfo; -extern const struct blkid_idinfo highpoint37x_idinfo; -extern const struct blkid_idinfo highpoint45x_idinfo; -extern const struct blkid_idinfo squashfs_idinfo; -extern const struct blkid_idinfo netware_idinfo; -extern const struct blkid_idinfo sysv_idinfo; -extern const struct blkid_idinfo xenix_idinfo; -extern const struct blkid_idinfo btrfs_idinfo; -extern const struct blkid_idinfo ubifs_idinfo; -extern const struct blkid_idinfo zfs_idinfo; -extern const struct blkid_idinfo bfs_idinfo; -extern const struct blkid_idinfo vmfs_volume_idinfo; -extern const struct blkid_idinfo vmfs_fs_idinfo; -extern const struct blkid_idinfo drbd_idinfo; -extern const struct blkid_idinfo drbdproxy_datalog_idinfo; -extern const struct blkid_idinfo befs_idinfo; -extern const struct blkid_idinfo nilfs2_idinfo; -extern const struct blkid_idinfo exfat_idinfo; -extern const struct blkid_idinfo f2fs_idinfo; - -/* - * superblock functions - */ -extern int blkid_probe_set_version(blkid_probe pr, const char *version); -extern int blkid_probe_sprintf_version(blkid_probe pr, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); - -extern int blkid_probe_set_label(blkid_probe pr, unsigned char *label, size_t len); -extern int blkid_probe_set_utf8label(blkid_probe pr, unsigned char *label, - size_t len, int enc); -extern int blkid_probe_sprintf_uuid(blkid_probe pr, unsigned char *uuid, - size_t len, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 4, 5))); -extern int blkid_probe_strncpy_uuid(blkid_probe pr, unsigned char *str, size_t len); - -extern int blkid_probe_set_uuid(blkid_probe pr, unsigned char *uuid); -extern int blkid_probe_set_uuid_as(blkid_probe pr, unsigned char *uuid, const char *name); - -extern int blkid_probe_set_id_label(blkid_probe pr, const char *name, - unsigned char *data, size_t len); - -#endif /* _BLKID_SUPERBLOCKS_H */ diff --git a/libblkid/swap.c b/libblkid/swap.c deleted file mode 100644 index 7ac119bed..000000000 --- a/libblkid/swap.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -/* linux-2.6/include/linux/swap.h */ -struct swap_header_v1_2 { - /* char bootbits[1024]; */ /* Space for disklabel etc. */ - uint32_t version; - uint32_t lastpage; - uint32_t nr_badpages; - unsigned char uuid[16]; - unsigned char volume[16]; - uint32_t padding[117]; - uint32_t badpages[1]; -} __attribute__((packed)); - -#define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */ -#define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */ - -#define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c" -#define TOI_MAGIC_STRLEN (sizeof(TOI_MAGIC_STRING) - 1) - -static int swap_set_info(blkid_probe pr, const char *version) -{ - struct swap_header_v1_2 *hdr; - - /* Swap header always located at offset of 1024 bytes */ - hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, - sizeof(struct swap_header_v1_2)); - if (!hdr) - return -1; - - /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ - if (strcmp(version, "2") == 0 && - (hdr->version != 1 || hdr->lastpage == 0)) - return -1; - - /* arbitrary sanity check.. is there any garbage down there? */ - if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { - if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, - sizeof(hdr->volume)) < 0) - return -1; - if (blkid_probe_set_uuid(pr, hdr->uuid) < 0) - return -1; - } - - blkid_probe_set_version(pr, version); - return 0; -} - -static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag) -{ - unsigned char *buf; - - if (!mag) - return -1; - - /* TuxOnIce keeps valid swap header at the end of the 1st page */ - buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN); - if (!buf) - return -1; - - if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0) - return 1; /* Ignore swap signature, it's TuxOnIce */ - - if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) { - /* swap v0 doesn't support LABEL or UUID */ - blkid_probe_set_version(pr, "1"); - return 0; - - } else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) - return swap_set_info(pr, "2"); - - return -1; -} - -static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) -{ - if (!mag) - return -1; - if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) - return swap_set_info(pr, "s1suspend"); - if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) - return swap_set_info(pr, "s2suspend"); - if (!memcmp(mag->magic, "ULSUSPEND", mag->len)) - return swap_set_info(pr, "ulsuspend"); - if (!memcmp(mag->magic, TOI_MAGIC_STRING, mag->len)) - return swap_set_info(pr, "tuxonice"); - if (!memcmp(mag->magic, "LINHIB0001", mag->len)) - return swap_set_info(pr, "linhib0001"); - - return -1; /* no signature detected */ -} - -const struct blkid_idinfo swap_idinfo = -{ - .name = "swap", - .usage = BLKID_USAGE_OTHER, - .probefunc = probe_swap, - .minsz = 10 * 4096, /* 10 pages */ - .magics = - { - { "SWAP-SPACE", 10, 0, 0xff6 }, - { "SWAPSPACE2", 10, 0, 0xff6 }, - { "SWAP-SPACE", 10, 0, 0x1ff6 }, - { "SWAPSPACE2", 10, 0, 0x1ff6 }, - { "SWAP-SPACE", 10, 0, 0x3ff6 }, - { "SWAPSPACE2", 10, 0, 0x3ff6 }, - { "SWAP-SPACE", 10, 0, 0x7ff6 }, - { "SWAPSPACE2", 10, 0, 0x7ff6 }, - { "SWAP-SPACE", 10, 0, 0xfff6 }, - { "SWAPSPACE2", 10, 0, 0xfff6 }, - { NULL } - } -}; - - -const struct blkid_idinfo swsuspend_idinfo = -{ - .name = "swsuspend", - .usage = BLKID_USAGE_OTHER, - .probefunc = probe_swsuspend, - .minsz = 10 * 4096, /* 10 pages */ - .magics = - { - { TOI_MAGIC_STRING, TOI_MAGIC_STRLEN, 0, 0 }, - { "S1SUSPEND", 9, 0, 0xff6 }, - { "S2SUSPEND", 9, 0, 0xff6 }, - { "ULSUSPEND", 9, 0, 0xff6 }, - { "LINHIB0001",10,0, 0xff6 }, - - { "S1SUSPEND", 9, 0, 0x1ff6 }, - { "S2SUSPEND", 9, 0, 0x1ff6 }, - { "ULSUSPEND", 9, 0, 0x1ff6 }, - { "LINHIB0001",10,0, 0x1ff6 }, - - { "S1SUSPEND", 9, 0, 0x3ff6 }, - { "S2SUSPEND", 9, 0, 0x3ff6 }, - { "ULSUSPEND", 9, 0, 0x3ff6 }, - { "LINHIB0001",10,0, 0x3ff6 }, - - { "S1SUSPEND", 9, 0, 0x7ff6 }, - { "S2SUSPEND", 9, 0, 0x7ff6 }, - { "ULSUSPEND", 9, 0, 0x7ff6 }, - { "LINHIB0001",10,0, 0x7ff6 }, - - { "S1SUSPEND", 9, 0, 0xfff6 }, - { "S2SUSPEND", 9, 0, 0xfff6 }, - { "ULSUSPEND", 9, 0, 0xfff6 }, - { "LINHIB0001",10,0, 0xfff6 }, - - { NULL } - } -}; - diff --git a/libblkid/swapheader.h b/libblkid/swapheader.h deleted file mode 100644 index 42d521a49..000000000 --- a/libblkid/swapheader.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _SWAPHEADER_H -#define _SWAPHEADER_H - -struct swap_header_v1 { - char bootbits[1024]; /* Space for disklabel etc. */ - unsigned int version; - unsigned int last_page; - unsigned int nr_badpages; - unsigned int padding[125]; - unsigned int badpages[1]; -}; - - -#define SWAP_UUID_LENGTH 16 -#define SWAP_LABEL_LENGTH 16 - -struct swap_header_v1_2 { - char bootbits[1024]; /* Space for disklabel etc. */ - unsigned int version; - unsigned int last_page; - unsigned int nr_badpages; - unsigned char uuid[SWAP_UUID_LENGTH]; - char volume_name[SWAP_LABEL_LENGTH]; - unsigned int padding[117]; - unsigned int badpages[1]; -}; - -#endif /* _SWAPHEADER_H */ diff --git a/libblkid/sysfs.h b/libblkid/sysfs.h deleted file mode 100644 index 739f9de12..000000000 --- a/libblkid/sysfs.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2011 Karel Zak <kzak@redhat.com> - */ -#ifndef UTIL_LINUX_SYSFS_H -#define UTIL_LINUX_SYSFS_H - - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <inttypes.h> -#include <dirent.h> - -struct sysfs_cxt { - dev_t devno; - int dir_fd; /* /sys/block/<name> */ - char *dir_path; - struct sysfs_cxt *parent; - - unsigned int scsi_host, - scsi_channel, - scsi_target, - scsi_lun; - - unsigned int has_hctl : 1; -}; - -#define UL_SYSFSCXT_EMPTY { 0, -1, NULL, NULL, 0, 0, 0, 0, 0 } - -extern char *sysfs_devno_attribute_path(dev_t devno, char *buf, - size_t bufsiz, const char *attr); -extern int sysfs_devno_has_attribute(dev_t devno, const char *attr); -extern char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz); -extern char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz); -extern dev_t sysfs_devname_to_devno(const char *name, const char *parent); - -extern int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent) - __attribute__ ((warn_unused_result)); -extern void sysfs_deinit(struct sysfs_cxt *cxt); - -extern DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr); - -extern int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st); -extern ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr, - char *buf, size_t bufsiz); -extern int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr); - -extern int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, - const char *fmt, ...) - __attribute__ ((format (scanf, 3, 4))); - -extern int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res); -extern int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res); -extern int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res); - -extern char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz); - -extern char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr); - -extern int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr); -extern int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname); -extern dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno); -extern char *sysfs_get_slave(struct sysfs_cxt *cxt); - -extern int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, - const char *parent_name); - -extern int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, - size_t len, dev_t *diskdevno); - -extern int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, - int *c, int *t, int *l); -extern char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, - const char *type, const char *attr); -extern int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type); -extern int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr); -extern int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern); - -#endif /* UTIL_LINUX_SYSFS_H */ diff --git a/libblkid/sysfs1.c b/libblkid/sysfs1.c deleted file mode 100644 index fd4ec6232..000000000 --- a/libblkid/sysfs1.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#include <ctype.h> -#include <fcntl.h> -#include <unistd.h> -#include "c.h" -#include "at.h" -#include "pathnames.h" -#include "sysfs.h" - -char *sysfs_devno_attribute_path(dev_t devno, char *buf, - size_t bufsiz, const char *attr) -{ - int len; - - if (attr) - len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d/%s", - major(devno), minor(devno), attr); - else - len = snprintf(buf, bufsiz, _PATH_SYS_DEVBLOCK "/%d:%d", - major(devno), minor(devno)); - - return (len < 0 || (size_t) len + 1 > bufsiz) ? NULL : buf; -} - -int sysfs_devno_has_attribute(dev_t devno, const char *attr) -{ - char path[PATH_MAX]; - struct stat info; - - if (!sysfs_devno_attribute_path(devno, path, sizeof(path), attr)) - return 0; - if (stat(path, &info) == 0) - return 1; - return 0; -} - -char *sysfs_devno_path(dev_t devno, char *buf, size_t bufsiz) -{ - return sysfs_devno_attribute_path(devno, buf, bufsiz, NULL); -} - -dev_t sysfs_devname_to_devno(const char *name, const char *parent) -{ - char buf[PATH_MAX], *path = NULL; - dev_t dev = 0; - - if (strncmp("/dev/", name, 5) == 0) { - /* - * Read from /dev - */ - struct stat st; - - if (stat(name, &st) == 0) - dev = st.st_rdev; - else - name += 5; /* unaccesible, or not node in /dev */ - } - - if (!dev && parent && strncmp("dm-", name, 3)) { - /* - * Create path to /sys/block/<parent>/<name>/dev - */ - int len = snprintf(buf, sizeof(buf), - _PATH_SYS_BLOCK "/%s/%s/dev", parent, name); - if (len < 0 || (size_t) len + 1 > sizeof(buf)) - return 0; - path = buf; - - } else if (!dev) { - /* - * Create path to /sys/block/<name>/dev - */ - int len = snprintf(buf, sizeof(buf), - _PATH_SYS_BLOCK "/%s/dev", name); - if (len < 0 || (size_t) len + 1 > sizeof(buf)) - return 0; - path = buf; - } - - if (path) { - /* - * read devno from sysfs - */ - FILE *f; - int maj = 0, min = 0; - - f = fopen(path, "r"); - if (!f) - return 0; - - if (fscanf(f, "%d:%d", &maj, &min) == 2) - dev = makedev(maj, min); - fclose(f); - } - return dev; -} - -/* - * Returns devname (e.g. "/dev/sda1") for the given devno. - * - * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min> - * symlinks. - * - * Please, use more robust blkid_devno_to_devname() in your applications. - */ -char *sysfs_devno_to_devpath(dev_t devno, char *buf, size_t bufsiz) -{ - struct sysfs_cxt cxt; - char *name; - size_t sz; - struct stat st; - - if (sysfs_init(&cxt, devno, NULL)) - return NULL; - - name = sysfs_get_devname(&cxt, buf, bufsiz); - sysfs_deinit(&cxt); - - if (!name) - return NULL; - - sz = strlen(name); - - if (sz + sizeof("/dev/") > bufsiz) - return NULL; - - /* create the final "/dev/<name>" string */ - memmove(buf + 5, name, sz + 1); - memcpy(buf, "/dev/", 5); - - if (!stat(buf, &st) && S_ISBLK(st.st_mode) && st.st_rdev == devno) - return buf; - - return NULL; -} - -int sysfs_init(struct sysfs_cxt *cxt, dev_t devno, struct sysfs_cxt *parent) -{ - char path[PATH_MAX]; - int fd, rc; - - memset(cxt, 0, sizeof(*cxt)); - cxt->dir_fd = -1; - - if (!sysfs_devno_path(devno, path, sizeof(path))) - goto err; - - fd = open(path, O_RDONLY); - if (fd < 0) - goto err; - cxt->dir_fd = fd; - - cxt->dir_path = strdup(path); - if (!cxt->dir_path) - goto err; - cxt->devno = devno; - cxt->parent = parent; - return 0; -err: - rc = errno > 0 ? -errno : -1; - sysfs_deinit(cxt); - return rc; -} - -void sysfs_deinit(struct sysfs_cxt *cxt) -{ - if (!cxt) - return; - - if (cxt->dir_fd >= 0) - close(cxt->dir_fd); - free(cxt->dir_path); - - memset(cxt, 0, sizeof(*cxt)); - - cxt->dir_fd = -1; -} - -int sysfs_stat(struct sysfs_cxt *cxt, const char *attr, struct stat *st) -{ - int rc = fstat_at(cxt->dir_fd, cxt->dir_path, attr, st, 0); - - if (rc != 0 && errno == ENOENT && - strncmp(attr, "queue/", 6) == 0 && cxt->parent) { - - /* Exception for "queue/<attr>". These attributes are available - * for parental devices only - */ - return fstat_at(cxt->parent->dir_fd, - cxt->parent->dir_path, attr, st, 0); - } - return rc; -} - -int sysfs_has_attribute(struct sysfs_cxt *cxt, const char *attr) -{ - struct stat st; - - return sysfs_stat(cxt, attr, &st) == 0; -} - -static int sysfs_open(struct sysfs_cxt *cxt, const char *attr) -{ - int fd = open_at(cxt->dir_fd, cxt->dir_path, attr, O_RDONLY); - - if (fd == -1 && errno == ENOENT && - strncmp(attr, "queue/", 6) == 0 && cxt->parent) { - - /* Exception for "queue/<attr>". These attributes are available - * for parental devices only - */ - fd = open_at(cxt->parent->dir_fd, cxt->dir_path, attr, O_RDONLY); - } - return fd; -} - -ssize_t sysfs_readlink(struct sysfs_cxt *cxt, const char *attr, - char *buf, size_t bufsiz) -{ - if (!cxt->dir_path) - return -1; - - if (attr) - return readlink_at(cxt->dir_fd, cxt->dir_path, attr, buf, bufsiz); - - /* read /sys/dev/block/<maj:min> link */ - return readlink(cxt->dir_path, buf, bufsiz); -} - -DIR *sysfs_opendir(struct sysfs_cxt *cxt, const char *attr) -{ - DIR *dir; - int fd = -1; - - if (attr) - fd = sysfs_open(cxt, attr); - - else if (cxt->dir_fd >= 0) - /* request to open root of device in sysfs (/sys/block/<dev>) - * -- we cannot use cxt->sysfs_fd directly, because closedir() - * will close this our persistent file descriptor. - */ - fd = dup(cxt->dir_fd); - - if (fd < 0) - return NULL; - - dir = fdopendir(fd); - if (!dir) { - close(fd); - return NULL; - } - if (!attr) - rewinddir(dir); - return dir; -} - - -static FILE *sysfs_fopen(struct sysfs_cxt *cxt, const char *attr) -{ - int fd = sysfs_open(cxt, attr); - - return fd < 0 ? NULL : fdopen(fd, "r"); -} - - -static struct dirent *xreaddir(DIR *dp) -{ - struct dirent *d; - - while ((d = readdir(dp))) { - if (!strcmp(d->d_name, ".") || - !strcmp(d->d_name, "..")) - continue; - - /* blacklist here? */ - break; - } - return d; -} - -int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name) -{ - char path[256]; - -#ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type != DT_DIR && - d->d_type != DT_LNK) - return 0; -#endif - if (parent_name) { - const char *p = parent_name; - size_t len; - - /* /dev/sda --> "sda" */ - if (*parent_name == '/') { - p = strrchr(parent_name, '/'); - if (!p) - return 0; - p++; - } - - len = strlen(p); - if (strlen(d->d_name) <= len) - return 0; - - /* partitions subdir name is - * "<parent>[:digit:]" or "<parent>p[:digit:]" - */ - return strncmp(p, d->d_name, len) == 0 && - ((*(d->d_name + len) == 'p' && isdigit(*(d->d_name + len + 1))) - || isdigit(*(d->d_name + len))); - } - - /* Cannot use /partition file, not supported on old sysfs */ - snprintf(path, sizeof(path), "%s/start", d->d_name); - - return access(path, R_OK) == 0; -} - -/* - * Converts @partno (partition number) to devno of the partition. - * The @cxt handles wholedisk device. - * - * Note that this code does not expect any special format of the - * partitions devnames. - */ -dev_t sysfs_partno_to_devno(struct sysfs_cxt *cxt, int partno) -{ - DIR *dir; - struct dirent *d; - char path[256]; - dev_t devno = 0; - - dir = sysfs_opendir(cxt, NULL); - if (!dir) - return 0; - - while ((d = xreaddir(dir))) { - int n, maj, min; - - if (!sysfs_is_partition_dirent(dir, d, NULL)) - continue; - - snprintf(path, sizeof(path), "%s/partition", d->d_name); - if (sysfs_read_int(cxt, path, &n)) - continue; - - if (n == partno) { - snprintf(path, sizeof(path), "%s/dev", d->d_name); - if (sysfs_scanf(cxt, path, "%d:%d", &maj, &min) == 2) - devno = makedev(maj, min); - break; - } - } - - closedir(dir); - return devno; -} - - -int sysfs_scanf(struct sysfs_cxt *cxt, const char *attr, const char *fmt, ...) -{ - FILE *f = sysfs_fopen(cxt, attr); - va_list ap; - int rc; - - if (!f) - return -EINVAL; - va_start(ap, fmt); - rc = vfscanf(f, fmt, ap); - va_end(ap); - - fclose(f); - return rc; -} - - -int sysfs_read_s64(struct sysfs_cxt *cxt, const char *attr, int64_t *res) -{ - int64_t x = 0; - - if (sysfs_scanf(cxt, attr, "%"SCNd64, &x) == 1) { - if (res) - *res = x; - return 0; - } - return -1; -} - -int sysfs_read_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t *res) -{ - uint64_t x = 0; - - if (sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1) { - if (res) - *res = x; - return 0; - } - return -1; -} - -int sysfs_read_int(struct sysfs_cxt *cxt, const char *attr, int *res) -{ - int x = 0; - - if (sysfs_scanf(cxt, attr, "%d", &x) == 1) { - if (res) - *res = x; - return 0; - } - return -1; -} - -char *sysfs_strdup(struct sysfs_cxt *cxt, const char *attr) -{ - char buf[1024]; - return sysfs_scanf(cxt, attr, "%1023[^\n]", buf) == 1 ? - strdup(buf) : NULL; -} - -int sysfs_count_dirents(struct sysfs_cxt *cxt, const char *attr) -{ - DIR *dir; - int r = 0; - - if (!(dir = sysfs_opendir(cxt, attr))) - return 0; - - while (xreaddir(dir)) r++; - - closedir(dir); - return r; -} - -int sysfs_count_partitions(struct sysfs_cxt *cxt, const char *devname) -{ - DIR *dir; - struct dirent *d; - int r = 0; - - if (!(dir = sysfs_opendir(cxt, NULL))) - return 0; - - while ((d = xreaddir(dir))) { - if (sysfs_is_partition_dirent(dir, d, devname)) - r++; - } - - closedir(dir); - return r; -} - -/* - * Returns slave name if there is only one slave, otherwise returns NULL. - * The result should be deallocated by free(). - */ -char *sysfs_get_slave(struct sysfs_cxt *cxt) -{ - DIR *dir; - struct dirent *d; - char *name = NULL; - - if (!(dir = sysfs_opendir(cxt, "slaves"))) - return NULL; - - while ((d = xreaddir(dir))) { - if (name) - goto err; /* more slaves */ - - name = strdup(d->d_name); - } - - closedir(dir); - return name; -err: - free(name); - closedir(dir); - return NULL; -} - -/* - * Note that the @buf has to be large enough to store /sys/dev/block/<maj:min> - * symlinks. - */ -char *sysfs_get_devname(struct sysfs_cxt *cxt, char *buf, size_t bufsiz) -{ - char *name = NULL; - ssize_t sz; - - sz = sysfs_readlink(cxt, NULL, buf, bufsiz - 1); - if (sz < 0) - return NULL; - - buf[sz] = '\0'; - name = strrchr(buf, '/'); - if (!name) - return NULL; - - name++; - sz = strlen(name); - - memmove(buf, name, sz + 1); - return buf; -} - -/* returns basename and keeps dirname in the @path */ -static char *stripoff_last_component(char *path) -{ - char *p = strrchr(path, '/'); - - if (!p) - return NULL; - *p = '\0'; - return ++p; -} - -static int get_dm_wholedisk(struct sysfs_cxt *cxt, char *diskname, - size_t len, dev_t *diskdevno) -{ - int rc = 0; - char *name; - - /* Note, sysfs_get_slave() returns the first slave only, - * if there is more slaves, then return NULL - */ - name = sysfs_get_slave(cxt); - if (!name) - return -1; - - if (diskname && len) { - strncpy(diskname, name, len); - diskname[len - 1] = '\0'; - } - - if (diskdevno) { - *diskdevno = sysfs_devname_to_devno(name, NULL); - if (!*diskdevno) - rc = -1; - } - - free(name); - return rc; -} - -int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, - size_t len, dev_t *diskdevno) -{ - struct sysfs_cxt cxt; - int is_part = 0; - - if (!dev || sysfs_init(&cxt, dev, NULL) != 0) - return -1; - - is_part = sysfs_has_attribute(&cxt, "partition"); - if (!is_part) { - /* - * Extra case for partitions mapped by device-mapper. - * - * All regualar partitions (added by BLKPG ioctl or kernel PT - * parser) have the /sys/.../partition file. The partitions - * mapped by DM don't have such file, but they have "part" - * prefix in DM UUID. - */ - char *uuid = sysfs_strdup(&cxt, "dm/uuid"); - char *tmp = uuid; - char *prefix = uuid ? strsep(&tmp, "-") : NULL; - - if (prefix && strncasecmp(prefix, "part", 4) == 0) - is_part = 1; - free(uuid); - - if (is_part && - get_dm_wholedisk(&cxt, diskname, len, diskdevno) == 0) - /* - * partitioned device, mapped by DM - */ - goto done; - - is_part = 0; - } - - if (!is_part) { - /* - * unpartitioned device - */ - if (diskname && len) { - if (!sysfs_get_devname(&cxt, diskname, len)) - goto err; - } - if (diskdevno) - *diskdevno = dev; - - } else { - /* - * partitioned device - * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1 - * - dirname ../../block/sda/sda1 = ../../block/sda - * - basename ../../block/sda = sda - */ - char linkpath[PATH_MAX]; - char *name; - int linklen; - - linklen = sysfs_readlink(&cxt, NULL, - linkpath, sizeof(linkpath) - 1); - if (linklen < 0) - goto err; - linkpath[linklen] = '\0'; - - stripoff_last_component(linkpath); /* dirname */ - name = stripoff_last_component(linkpath); /* basename */ - if (!name) - goto err; - - if (diskname && len) { - strncpy(diskname, name, len); - diskname[len - 1] = '\0'; - } - - if (diskdevno) { - *diskdevno = sysfs_devname_to_devno(name, NULL); - if (!*diskdevno) - goto err; - } - } - -done: - sysfs_deinit(&cxt); - return 0; -err: - sysfs_deinit(&cxt); - return -1; -} - - -int sysfs_scsi_get_hctl(struct sysfs_cxt *cxt, int *h, int *c, int *t, int *l) -{ - char buf[PATH_MAX], *hctl; - ssize_t len; - - if (!cxt) - return -EINVAL; - if (cxt->has_hctl) - goto done; - - len = sysfs_readlink(cxt, "device", buf, sizeof(buf) - 1); - if (len < 0) - return len; - - buf[len] = '\0'; - hctl = strrchr(buf, '/') + 1; - if (!hctl) - return -1; - - if (sscanf(hctl, "%d:%d:%d:%d", &cxt->scsi_host, &cxt->scsi_channel, - &cxt->scsi_target, &cxt->scsi_lun) != 4) - return -1; - - cxt->has_hctl = 1; -done: - if (h) - *h = cxt->scsi_host; - if (c) - *c = cxt->scsi_channel; - if (t) - *t = cxt->scsi_target; - if (l) - *l = cxt->scsi_lun; - return 0; -} - - -static char *sysfs_scsi_host_attribute_path(struct sysfs_cxt *cxt, - const char *type, char *buf, size_t bufsz, const char *attr) -{ - int len; - int host; - - if (sysfs_scsi_get_hctl(cxt, &host, NULL, NULL, NULL)) - return NULL; - - if (attr) - len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d/%s", - type, host, attr); - else - len = snprintf(buf, bufsz, _PATH_SYS_CLASS "/%s_host/host%d", - type, host); - - return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf; -} - -char *sysfs_scsi_host_strdup_attribute(struct sysfs_cxt *cxt, - const char *type, const char *attr) -{ - char buf[1024]; - int rc; - FILE *f; - - if (!attr || !type || - !sysfs_scsi_host_attribute_path(cxt, type, buf, sizeof(buf), attr)) - return NULL; - - if (!(f = fopen(buf, "r"))) - return NULL; - - rc = fscanf(f, "%1023[^\n]", buf); - fclose(f); - - return rc == 1 ? strdup(buf) : NULL; -} - -int sysfs_scsi_host_is(struct sysfs_cxt *cxt, const char *type) -{ - char buf[PATH_MAX]; - struct stat st; - - if (!type || !sysfs_scsi_host_attribute_path(cxt, type, - buf, sizeof(buf), NULL)) - return 0; - - return stat(buf, &st) == 0 && S_ISDIR(st.st_mode); -} - -static char *sysfs_scsi_attribute_path(struct sysfs_cxt *cxt, - char *buf, size_t bufsz, const char *attr) -{ - int len, h, c, t, l; - - if (sysfs_scsi_get_hctl(cxt, &h, &c, &t, &l) != 0) - return NULL; - - if (attr) - len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d/%s", - h,c,t,l, attr); - else - len = snprintf(buf, bufsz, _PATH_SYS_SCSI "/devices/%d:%d:%d:%d", - h,c,t,l); - return (len < 0 || (size_t) len + 1 > bufsz) ? NULL : buf; -} - -int sysfs_scsi_has_attribute(struct sysfs_cxt *cxt, const char *attr) -{ - char path[PATH_MAX]; - struct stat st; - - if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), attr)) - return 0; - - return stat(path, &st) == 0; -} - -int sysfs_scsi_path_contains(struct sysfs_cxt *cxt, const char *pattern) -{ - char path[PATH_MAX], linkc[PATH_MAX]; - struct stat st; - ssize_t len; - - if (!sysfs_scsi_attribute_path(cxt, path, sizeof(path), NULL)) - return 0; - - if (stat(path, &st) != 0) - return 0; - - len = readlink(path, linkc, sizeof(linkc) - 1); - if (len < 0) - return 0; - - linkc[len] = '\0'; - return strstr(linkc, pattern) != NULL; -} - -#ifdef TEST_PROGRAM_SYSFS -#include <errno.h> -#include <err.h> -#include <stdlib.h> - -int main(int argc, char *argv[]) -{ - struct sysfs_cxt cxt = UL_SYSFSCXT_EMPTY; - char *devname; - dev_t devno; - char path[PATH_MAX]; - int i, is_part; - uint64_t u64; - ssize_t len; - - if (argc != 2) - errx(EXIT_FAILURE, "usage: %s <devname>", argv[0]); - - devname = argv[1]; - devno = sysfs_devname_to_devno(devname, NULL); - - if (!devno) - err(EXIT_FAILURE, "failed to read devno"); - - is_part = sysfs_devno_has_attribute(devno, "partition"); - - printf("NAME: %s\n", devname); - printf("DEVNO: %u (%d:%d)\n", (unsigned int) devno, major(devno), minor(devno)); - printf("DEVNOPATH: %s\n", sysfs_devno_path(devno, path, sizeof(path))); - printf("DEVPATH: %s\n", sysfs_devno_to_devpath(devno, path, sizeof(path))); - printf("PARTITION: %s\n", is_part ? "YES" : "NOT"); - - if (sysfs_init(&cxt, devno, NULL)) - return EXIT_FAILURE; - - len = sysfs_readlink(&cxt, NULL, path, sizeof(path) - 1); - if (len > 0) { - path[len] = '\0'; - printf("DEVNOLINK: %s\n", path); - } - - if (!is_part) { - printf("First 5 partitions:\n"); - for (i = 1; i <= 5; i++) { - dev_t dev = sysfs_partno_to_devno(&cxt, i); - if (dev) - printf("\t#%d %d:%d\n", i, major(dev), minor(dev)); - } - } - - printf("SLAVES: %d\n", sysfs_count_dirents(&cxt, "slaves")); - - if (sysfs_read_u64(&cxt, "size", &u64)) - printf("read SIZE failed\n"); - else - printf("SIZE: %jd\n", u64); - - if (sysfs_read_int(&cxt, "queue/hw_sector_size", &i)) - printf("read SECTOR failed\n"); - else - printf("SECTOR: %d\n", i); - - printf("DEVNAME: %s\n", sysfs_get_devname(&cxt, path, sizeof(path))); - - sysfs_deinit(&cxt); - return EXIT_SUCCESS; -} -#endif diff --git a/libblkid/sysv.c b/libblkid/sysv.c deleted file mode 100644 index 80b0cc542..000000000 --- a/libblkid/sysv.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This is written from sratch according to Linux kernel fs/sysv/super.c file. - * It seems that sysv probing code in libvolume_id and also in the original - * blkid is useless. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <stddef.h> - -#include "superblocks.h" - -#define XENIX_NICINOD 100 -#define XENIX_NICFREE 100 - -struct xenix_super_block { - uint16_t s_isize; - uint32_t s_fsize; - uint16_t s_nfree; - uint32_t s_free[XENIX_NICFREE]; - uint16_t s_ninode; - uint16_t s_inode[XENIX_NICINOD]; - uint8_t s_flock; - uint8_t s_ilock; - uint8_t s_fmod; - uint8_t s_ronly; - uint32_t s_time; - uint32_t s_tfree; - uint16_t s_tinode; - uint16_t s_dinfo[4]; - uint8_t s_fname[6]; - uint8_t s_fpack[6]; - uint8_t s_clean; - uint8_t s_fill[371]; - uint32_t s_magic; - uint32_t s_type; -} __attribute__((packed)); - - -#define SYSV_NICINOD 100 -#define SYSV_NICFREE 50 - -struct sysv_super_block -{ - uint16_t s_isize; - uint16_t s_pad0; - uint32_t s_fsize; - uint16_t s_nfree; - uint16_t s_pad1; - uint32_t s_free[SYSV_NICFREE]; - uint16_t s_ninode; - uint16_t s_pad2; - uint16_t s_inode[SYSV_NICINOD]; - uint8_t s_flock; - uint8_t s_ilock; - uint8_t s_fmod; - uint8_t s_ronly; - uint32_t s_time; - uint16_t s_dinfo[4]; - uint32_t s_tfree; - uint16_t s_tinode; - uint16_t s_pad3; - uint8_t s_fname[6]; - uint8_t s_fpack[6]; - uint32_t s_fill[12]; - uint32_t s_state; - uint32_t s_magic; - uint32_t s_type; -}; - -static int probe_xenix(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct xenix_super_block *sb; - - sb = blkid_probe_get_sb(pr, mag, struct xenix_super_block); - if (!sb) - return -1; - blkid_probe_set_label(pr, sb->s_fname, sizeof(sb->s_fname)); - return 0; -} - -#define SYSV_BLOCK_SIZE 1024 - -/* Note that we don't probe for Coherent FS, this FS does not have - * magic string. (It requires to probe fname/fpack field..) - */ -static int probe_sysv(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct sysv_super_block *sb; - int blocks[] = {0, 9, 15, 18}; - size_t i; - - for (i = 0; i < ARRAY_SIZE(blocks); i++) { - int off = blocks[i] * SYSV_BLOCK_SIZE + SYSV_BLOCK_SIZE/2; - - sb = (struct sysv_super_block *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct sysv_super_block)); - if (!sb) - return -1; - - if (sb->s_magic == cpu_to_le32(0xfd187e20) || - sb->s_magic == cpu_to_be32(0xfd187e20)) { - - if (blkid_probe_set_label(pr, sb->s_fname, - sizeof(sb->s_fname))) - return -1; - - if (blkid_probe_set_magic(pr, - off + offsetof(struct sysv_super_block, - s_magic), - sizeof(sb->s_magic), - (unsigned char *) &sb->s_magic)) - return -1; - - return 0; - } - } - return 1; -} - -const struct blkid_idinfo xenix_idinfo = -{ - .name = "xenix", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_xenix, - .magics = - { - { .magic = "\x2b\x55\x44", .len = 3, .kboff = 1, .sboff = 0x400 }, - { .magic = "\x44\x55\x2b", .len = 3, .kboff = 1, .sboff = 0x400 }, - { NULL } - } -}; - -const struct blkid_idinfo sysv_idinfo = -{ - .name = "sysv", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_sysv, - - /* SYSV is BE and LE and superblock could be on four positions. It's - * simpler to probe for the magic string by .probefunc(). - */ - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/tag.c b/libblkid/tag.c deleted file mode 100644 index 9dbacef04..000000000 --- a/libblkid/tag.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * tag.c - allocation/initialization/free routines for tag structs - * - * Copyright (C) 2001 Andreas Dilger - * Copyright (C) 2003 Theodore Ts'o - * - * %Begin-Header% - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * %End-Header% - */ - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -#include "blkidP.h" - -static blkid_tag blkid_new_tag(void) -{ - blkid_tag tag; - - if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag)))) - return NULL; - - INIT_LIST_HEAD(&tag->bit_tags); - INIT_LIST_HEAD(&tag->bit_names); - - return tag; -} - -#ifdef CONFIG_BLKID_DEBUG -void blkid_debug_dump_tag(blkid_tag tag) -{ - if (!tag) { - printf(" tag: NULL\n"); - return; - } - - printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val); -} -#endif - -void blkid_free_tag(blkid_tag tag) -{ - if (!tag) - return; - - DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name, - tag->bit_val ? tag->bit_val : "(NULL)")); - DBG(DEBUG_TAG, blkid_debug_dump_tag(tag)); - - list_del(&tag->bit_tags); /* list of tags for this device */ - list_del(&tag->bit_names); /* list of tags with this type */ - - free(tag->bit_name); - free(tag->bit_val); - - free(tag); -} - -/* - * Find the desired tag on a device. If value is NULL, then the - * first such tag is returned, otherwise return only exact tag if found. - */ -blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type) -{ - struct list_head *p; - - if (!dev || !type) - return NULL; - - list_for_each(p, &dev->bid_tags) { - blkid_tag tmp = list_entry(p, struct blkid_struct_tag, - bit_tags); - - if (!strcmp(tmp->bit_name, type)) - return tmp; - } - return NULL; -} - -extern int blkid_dev_has_tag(blkid_dev dev, const char *type, - const char *value) -{ - blkid_tag tag; - - tag = blkid_find_tag_dev(dev, type); - if (!value) - return (tag != NULL); - if (!tag || strcmp(tag->bit_val, value)) - return 0; - return 1; -} - -/* - * Find the desired tag type in the cache. - * We return the head tag for this tag type. - */ -static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type) -{ - blkid_tag head = NULL, tmp; - struct list_head *p; - - if (!cache || !type) - return NULL; - - list_for_each(p, &cache->bic_tags) { - tmp = list_entry(p, struct blkid_struct_tag, bit_tags); - if (!strcmp(tmp->bit_name, type)) { - DBG(DEBUG_TAG, - printf(" found cache tag head %s\n", type)); - head = tmp; - break; - } - } - return head; -} - -/* - * Set a tag on an existing device. - * - * If value is NULL, then delete the tagsfrom the device. - */ -int blkid_set_tag(blkid_dev dev, const char *name, - const char *value, const int vlength) -{ - blkid_tag t = 0, head = 0; - char *val = 0; - char **dev_var = 0; - - if (!dev || !name) - return -BLKID_ERR_PARAM; - - if (value && !(val = strndup(value, vlength))) - return -BLKID_ERR_MEM; - - /* - * Certain common tags are linked directly to the device struct - * We need to know what they are before we do anything else because - * the function name parameter might get freed later on. - */ - if (!strcmp(name, "TYPE")) - dev_var = &dev->bid_type; - else if (!strcmp(name, "LABEL")) - dev_var = &dev->bid_label; - else if (!strcmp(name, "UUID")) - dev_var = &dev->bid_uuid; - - t = blkid_find_tag_dev(dev, name); - if (!value) { - if (t) - blkid_free_tag(t); - } else if (t) { - if (!strcmp(t->bit_val, val)) { - /* Same thing, exit */ - free(val); - return 0; - } - free(t->bit_val); - t->bit_val = val; - } else { - /* Existing tag not present, add to device */ - if (!(t = blkid_new_tag())) - goto errout; - t->bit_name = name ? strdup(name) : NULL; - t->bit_val = val; - t->bit_dev = dev; - - list_add_tail(&t->bit_tags, &dev->bid_tags); - - if (dev->bid_cache) { - head = blkid_find_head_cache(dev->bid_cache, - t->bit_name); - if (!head) { - head = blkid_new_tag(); - if (!head) - goto errout; - - DBG(DEBUG_TAG, - printf(" creating new cache tag head %s\n", name)); - head->bit_name = name ? strdup(name) : NULL; - if (!head->bit_name) - goto errout; - list_add_tail(&head->bit_tags, - &dev->bid_cache->bic_tags); - } - list_add_tail(&t->bit_names, &head->bit_names); - } - } - - /* Link common tags directly to the device struct */ - if (dev_var) - *dev_var = val; - - if (dev->bid_cache) - dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED; - return 0; - -errout: - if (t) - blkid_free_tag(t); - else - free(val); - if (head) - blkid_free_tag(head); - return -BLKID_ERR_MEM; -} - - -/* - * Parse a "NAME=value" string. This is slightly different than - * parse_token, because that will end an unquoted value at a space, while - * this will assume that an unquoted value is the rest of the token (e.g. - * if we are passed an already quoted string from the command-line we don't - * have to both quote and escape quote so that the quotes make it to - * us). - * - * Returns 0 on success, and -1 on failure. - */ -int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val) -{ - char *name, *value, *cp; - - DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token)); - - if (!token || !(cp = strchr(token, '='))) - return -1; - - name = strdup(token); - if (!name) - return -1; - value = name + (cp - token); - *value++ = '\0'; - if (*value == '"' || *value == '\'') { - char c = *value++; - if (!(cp = strrchr(value, c))) - goto errout; /* missing closing quote */ - *cp = '\0'; - } - if (value && *value) - value = strdup(value); - if (!value) - goto errout; - - if (ret_type) - *ret_type = name; - if (ret_val) - *ret_val = value; - - return 0; - -errout: - free(name); - return -1; -} - -/* - * Tag iteration routines for the public libblkid interface. - * - * These routines do not expose the list.h implementation, which are a - * contamination of the namespace, and which force us to reveal far, far - * too much of our internal implemenation. I'm not convinced I want - * to keep list.h in the long term, anyway. It's fine for kernel - * programming, but performance is not the #1 priority for this - * library, and I really don't like the tradeoff of type-safety for - * performance for this application. [tytso:20030125.2007EST] - */ - -/* - * This series of functions iterate over all tags in a device - */ -#define TAG_ITERATE_MAGIC 0x01a5284c - -struct blkid_struct_tag_iterate { - int magic; - blkid_dev dev; - struct list_head *p; -}; - -extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev) -{ - blkid_tag_iterate iter; - - iter = malloc(sizeof(struct blkid_struct_tag_iterate)); - if (iter) { - iter->magic = TAG_ITERATE_MAGIC; - iter->dev = dev; - iter->p = dev->bid_tags.next; - } - return (iter); -} - -/* - * Return 0 on success, -1 on error - */ -extern int blkid_tag_next(blkid_tag_iterate iter, - const char **type, const char **value) -{ - blkid_tag tag; - - if (!type || !value || - !iter || iter->magic != TAG_ITERATE_MAGIC || - iter->p == &iter->dev->bid_tags) - return -1; - - *type = 0; - *value = 0; - tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags); - *type = tag->bit_name; - *value = tag->bit_val; - iter->p = iter->p->next; - return 0; -} - -extern void blkid_tag_iterate_end(blkid_tag_iterate iter) -{ - if (!iter || iter->magic != TAG_ITERATE_MAGIC) - return; - iter->magic = 0; - free(iter); -} - -/* - * This function returns a device which matches a particular - * type/value pair. If there is more than one device that matches the - * search specification, it returns the one with the highest priority - * value. This allows us to give preference to EVMS or LVM devices. - */ -extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache, - const char *type, - const char *value) -{ - blkid_tag head; - blkid_dev dev; - int pri; - struct list_head *p; - int probe_new = 0; - - if (!cache || !type || !value) - return NULL; - - blkid_read_cache(cache); - - DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value)); - -try_again: - pri = -1; - dev = 0; - head = blkid_find_head_cache(cache, type); - - if (head) { - list_for_each(p, &head->bit_names) { - blkid_tag tmp = list_entry(p, struct blkid_struct_tag, - bit_names); - - if (!strcmp(tmp->bit_val, value) && - (tmp->bit_dev->bid_pri > pri) && - !access(tmp->bit_dev->bid_name, F_OK)) { - dev = tmp->bit_dev; - pri = dev->bid_pri; - } - } - } - if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) { - dev = blkid_verify(cache, dev); - if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))) - goto try_again; - } - - if (!dev && !probe_new) { - if (blkid_probe_all_new(cache) < 0) - return NULL; - probe_new++; - goto try_again; - } - - if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) { - if (blkid_probe_all(cache) < 0) - return NULL; - goto try_again; - } - return dev; -} - -#ifdef TEST_PROGRAM -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#else -extern char *optarg; -extern int optind; -#endif - -void __attribute__((__noreturn__)) usage(char *prog) -{ - fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " - "[type value]\n", - prog); - fprintf(stderr, "\tList all tags for a device and exit\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - blkid_tag_iterate iter; - blkid_cache cache = NULL; - blkid_dev dev; - int c, ret, found; - int flags = BLKID_DEV_FIND; - char *tmp; - char *file = NULL; - char *devname = NULL; - char *search_type = NULL; - char *search_value = NULL; - const char *type, *value; - - while ((c = getopt (argc, argv, "m:f:")) != EOF) - switch (c) { - case 'f': - file = optarg; - break; - case 'm': - { - int mask = strtoul (optarg, &tmp, 0); - if (*tmp) { - fprintf(stderr, "Invalid debug mask: %s\n", - optarg); - exit(1); - } - blkid_init_debug(mask); - break; - } - case '?': - usage(argv[0]); - } - if (argc > optind) - devname = argv[optind++]; - if (argc > optind) - search_type = argv[optind++]; - if (argc > optind) - search_value = argv[optind++]; - if (!devname || (argc != optind)) - usage(argv[0]); - - if ((ret = blkid_get_cache(&cache, file)) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - - dev = blkid_get_dev(cache, devname, flags); - if (!dev) { - fprintf(stderr, "%s: Can not find device in blkid cache\n", - devname); - exit(1); - } - if (search_type) { - found = blkid_dev_has_tag(dev, search_type, search_value); - printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev), - search_type, search_value ? search_value : "NULL", - found ? "FOUND" : "NOT FOUND"); - return(!found); - } - printf("Device %s...\n", blkid_dev_devname(dev)); - - iter = blkid_tag_iterate_begin(dev); - while (blkid_tag_next(iter, &type, &value) == 0) { - printf("\tTag %s has value %s\n", type, value); - } - blkid_tag_iterate_end(iter); - - blkid_put_cache(cache); - return (0); -} -#endif diff --git a/libblkid/topology.c b/libblkid/topology.c deleted file mode 100644 index 9d4e7bdf1..000000000 --- a/libblkid/topology.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * topology - gathers information about device topology - * - * Copyright 2009 Red Hat, Inc. All rights reserved. - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stddef.h> - -#include "topology.h" - -/** - * SECTION:topology - * @title: Topology information - * @short_description: block device topology information. - * - * The topology chain provides details about Linux block devices, for more - * information see: - * - * Linux kernel Documentation/ABI/testing/sysfs-block - * - * NAME=value (tags) interface is enabled by blkid_probe_enable_topology(), - * and provides: - * - * @LOGICAL_SECTOR_SIZE: this is the smallest unit the storage device can - * address. It is typically 512 bytes. - * - * @PHYSICAL_SECTOR_SIZE: this is the smallest unit a physical storage device - * can write atomically. It is usually the same as the - * logical sector size but may be bigger. - * - * @MINIMUM_IO_SIZE: minimum size which is the device's preferred unit of I/O. - * For RAID arrays it is often the stripe chunk size. - * - * @OPTIMAL_IO_SIZE: usually the stripe width for RAID or zero. For RAID arrays - * it is usually the stripe width or the internal track size. - * - * @ALIGNMENT_OFFSET: indicates how many bytes the beginning of the device is - * offset from the disk's natural alignment. - * - * The NAME=value tags are not defined when the corresponding topology value - * is zero. The MINIMUM_IO_SIZE should be always defined if kernel provides - * topology information. - * - * Binary interface: - * - * blkid_probe_get_topology() - * - * blkid_topology_get_'VALUENAME'() - */ -static int topology_probe(blkid_probe pr, struct blkid_chain *chn); -static void topology_free(blkid_probe pr, void *data); -static int topology_is_complete(blkid_probe pr); -static int topology_set_logical_sector_size(blkid_probe pr); - -/* - * Binary interface - */ -struct blkid_struct_topology { - unsigned long alignment_offset; - unsigned long minimum_io_size; - unsigned long optimal_io_size; - unsigned long logical_sector_size; - unsigned long physical_sector_size; -}; - -/* - * Topology chain probing functions - */ -static const struct blkid_idinfo *idinfos[] = -{ -#ifdef __linux__ - &ioctl_tp_idinfo, - &sysfs_tp_idinfo, - &md_tp_idinfo, - &dm_tp_idinfo, - &lvm_tp_idinfo, - &evms_tp_idinfo -#endif -}; - - -/* - * Driver definition - */ -const struct blkid_chaindrv topology_drv = { - .id = BLKID_CHAIN_TOPLGY, - .name = "topology", - .dflt_enabled = FALSE, - .idinfos = idinfos, - .nidinfos = ARRAY_SIZE(idinfos), - .probe = topology_probe, - .safeprobe = topology_probe, - .free_data = topology_free -}; - -/** - * blkid_probe_enable_topology: - * @pr: probe - * @enable: TRUE/FALSE - * - * Enables/disables the topology probing for non-binary interface. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_enable_topology(blkid_probe pr, int enable) -{ - if (!pr) - return -1; - pr->chains[BLKID_CHAIN_TOPLGY].enabled = enable; - return 0; -} - -/** - * blkid_probe_get_topology: - * @pr: probe - * - * This is a binary interface for topology values. See also blkid_topology_* - * functions. - * - * This function is independent on blkid_do_[safe,full]probe() and - * blkid_probe_enable_topology() calls. - * - * WARNING: the returned object will be overwritten by the next - * blkid_probe_get_topology() call for the same @pr. If you want to - * use more blkid_topopogy objects in the same time you have to create - * more blkid_probe handlers (see blkid_new_probe()). - * - * Returns: blkid_topopogy, or NULL in case of error. - */ -blkid_topology blkid_probe_get_topology(blkid_probe pr) -{ - return (blkid_topology) blkid_probe_get_binary_data(pr, - &pr->chains[BLKID_CHAIN_TOPLGY]); -} - -/* - * The blkid_do_probe() backend. - */ -static int topology_probe(blkid_probe pr, struct blkid_chain *chn) -{ - size_t i; - - if (!pr || chn->idx < -1) - return -1; - - if (!S_ISBLK(pr->mode)) - return -1; /* nothing, works with block devices only */ - - if (chn->binary) { - DBG(DEBUG_LOWPROBE, printf("initialize topology binary data\n")); - - if (chn->data) - /* reset binary data */ - memset(chn->data, 0, - sizeof(struct blkid_struct_topology)); - else { - chn->data = calloc(1, - sizeof(struct blkid_struct_topology)); - if (!chn->data) - return -1; - } - } - - blkid_probe_chain_reset_vals(pr, chn); - - DBG(DEBUG_LOWPROBE, - printf("--> starting probing loop [TOPOLOGY idx=%d]\n", - chn->idx)); - - i = chn->idx < 0 ? 0 : chn->idx + 1U; - - for ( ; i < ARRAY_SIZE(idinfos); i++) { - const struct blkid_idinfo *id = idinfos[i]; - - chn->idx = i; - - if (id->probefunc) { - DBG(DEBUG_LOWPROBE, printf( - "%s: call probefunc()\n", id->name)); - if (id->probefunc(pr, NULL) != 0) - continue; - } - - if (!topology_is_complete(pr)) - continue; - - /* generic for all probing drivers */ - topology_set_logical_sector_size(pr); - - DBG(DEBUG_LOWPROBE, - printf("<-- leaving probing loop (type=%s) [TOPOLOGY idx=%d]\n", - id->name, chn->idx)); - return 0; - } - - DBG(DEBUG_LOWPROBE, - printf("<-- leaving probing loop (failed) [TOPOLOGY idx=%d]\n", - chn->idx)); - return 1; -} - -static void topology_free(blkid_probe pr __attribute__((__unused__)), - void *data) -{ - free(data); -} - -static int topology_set_value(blkid_probe pr, const char *name, - size_t structoff, unsigned long data) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - if (!chn) - return -1; - if (!data) - return 0; /* ignore zeros */ - - if (chn->binary) { - memcpy(chn->data + structoff, &data, sizeof(data)); - return 0; - } - return blkid_probe_sprintf_value(pr, name, "%lu", data); -} - - -/* the topology info is complete when we have at least "minimum_io_size" which - * is provided by all blkid topology drivers */ -static int topology_is_complete(blkid_probe pr) -{ - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - if (!chn) - return FALSE; - - if (chn->binary && chn->data) { - blkid_topology tp = (blkid_topology) chn->data; - if (tp->minimum_io_size) - return TRUE; - } - - return __blkid_probe_lookup_value(pr, "MINIMUM_IO_SIZE") ? TRUE : FALSE; -} - -int blkid_topology_set_alignment_offset(blkid_probe pr, int val) -{ - unsigned long xval; - - /* Welcome to Hell. The kernel is able to return -1 as an - * alignment_offset if no compatible sizes and alignments - * exist for stacked devices. - * - * There is no way how libblkid caller can respond to the value -1, so - * we will hide this corner case... - * - * (TODO: maybe we can export an extra boolean value 'misaligned' rather - * then complete hide this problem.) - */ - xval = val < 0 ? 0 : val; - - return topology_set_value(pr, - "ALIGNMENT_OFFSET", - offsetof(struct blkid_struct_topology, alignment_offset), - xval); -} - -int blkid_topology_set_minimum_io_size(blkid_probe pr, unsigned long val) -{ - return topology_set_value(pr, - "MINIMUM_IO_SIZE", - offsetof(struct blkid_struct_topology, minimum_io_size), - val); -} - -int blkid_topology_set_optimal_io_size(blkid_probe pr, unsigned long val) -{ - return topology_set_value(pr, - "OPTIMAL_IO_SIZE", - offsetof(struct blkid_struct_topology, optimal_io_size), - val); -} - -/* BLKSSZGET is provided on all systems since 2.3.3 -- so we don't have to - * waste time with sysfs. - */ -static int topology_set_logical_sector_size(blkid_probe pr) -{ - unsigned long val = blkid_probe_get_sectorsize(pr); - - if (!val) - return -1; - - return topology_set_value(pr, - "LOGICAL_SECTOR_SIZE", - offsetof(struct blkid_struct_topology, logical_sector_size), - val); -} - -int blkid_topology_set_physical_sector_size(blkid_probe pr, unsigned long val) -{ - return topology_set_value(pr, - "PHYSICAL_SECTOR_SIZE", - offsetof(struct blkid_struct_topology, physical_sector_size), - val); -} - -/** - * blkid_topology_get_alignment_offset: - * @tp: topology - * - * Returns: alignment offset in bytes or 0. - */ -unsigned long blkid_topology_get_alignment_offset(blkid_topology tp) -{ - return tp->alignment_offset; -} - -/** - * blkid_topology_get_minimum_io_size: - * @tp: topology - * - * Returns: minimum io size in bytes or 0. - */ -unsigned long blkid_topology_get_minimum_io_size(blkid_topology tp) -{ - return tp->minimum_io_size; -} - -/** - * blkid_topology_get_optimal_io_size - * @tp: topology - * - * Returns: optimal io size in bytes or 0. - */ -unsigned long blkid_topology_get_optimal_io_size(blkid_topology tp) -{ - return tp->optimal_io_size; -} - -/** - * blkid_topology_get_logical_sector_size - * @tp: topology - * - * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. - */ -unsigned long blkid_topology_get_logical_sector_size(blkid_topology tp) -{ - return tp->logical_sector_size; -} - -/** - * blkid_topology_get_physical_sector_size - * @tp: topology - * - * Returns: logical sector size (BLKSSZGET ioctl) in bytes or 0. - */ -unsigned long blkid_topology_get_physical_sector_size(blkid_topology tp) -{ - return tp->physical_sector_size; -} - diff --git a/libblkid/tt.c b/libblkid/tt.c deleted file mode 100644 index cbe4e3b4d..000000000 --- a/libblkid/tt.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * TT - Table or Tree, features: - * - column width could be defined as absolute or relative to the terminal width - * - allows to truncate or wrap data in columns - * - prints tree if parent->child relation is defined - * - draws the tree by ASCII or UTF8 lines (depends on terminal setting) - * - * Copyright (C) 2010 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <termios.h> -#include <ctype.h> - -#include "c.h" -#include "nls.h" -#include "widechar.h" -#include "tt.h" -#include "mbsalign.h" -#include "ttyutils.h" - -struct tt_symbols { - const char *branch; - const char *vert; - const char *right; -}; - -static const struct tt_symbols ascii_tt_symbols = { - .branch = "|-", - .vert = "| ", - .right = "`-", -}; - -#ifdef HAVE_WIDECHAR -#define UTF_V "\342\224\202" /* U+2502, Vertical line drawing char */ -#define UTF_VR "\342\224\234" /* U+251C, Vertical and right */ -#define UTF_H "\342\224\200" /* U+2500, Horizontal */ -#define UTF_UR "\342\224\224" /* U+2514, Up and right */ - -static const struct tt_symbols utf8_tt_symbols = { - .branch = UTF_VR UTF_H, - .vert = UTF_V " ", - .right = UTF_UR UTF_H, -}; -#endif /* !HAVE_WIDECHAR */ - -#define is_last_column(_tb, _cl) \ - list_entry_is_last(&(_cl)->cl_columns, &(_tb)->tb_columns) - -/* - * Counts number of cells in multibyte string. For all control and - * non-printable chars is the result width enlarged to store \x?? hex - * sequence. See mbs_safe_encode(). - */ -static size_t mbs_safe_width(const char *s) -{ - mbstate_t st; - const char *p = s; - size_t width = 0; - - memset(&st, 0, sizeof(st)); - - while (p && *p) { - if (iscntrl((unsigned char) *p)) { - width += 4; /* *p encoded to \x?? */ - p++; - } -#ifdef HAVE_WIDECHAR - else { - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); - - if (len == 0) - break; - - if (len == (size_t) -1 || len == (size_t) -2) { - len = 1; - width += (isprint((unsigned char) *p) ? 1 : 4); - - } if (!iswprint(wc)) - width += len * 4; /* hex encode whole sequence */ - else - width += wcwidth(wc); /* number of cells */ - p += len; - } -#else - else if (!isprint((unsigned char) *p)) { - width += 4; /* *p encoded to \x?? */ - p++; - } else { - width++; - p++; - } -#endif - } - - return width; -} - -/* - * Returns allocated string where all control and non-printable chars are - * replaced with \x?? hex sequence. - */ -static char *mbs_safe_encode(const char *s, size_t *width) -{ - mbstate_t st; - const char *p = s; - char *res, *r; - size_t sz = s ? strlen(s) : 0; - - - if (!sz) - return NULL; - - memset(&st, 0, sizeof(st)); - - res = malloc((sz * 4) + 1); - if (!res) - return NULL; - - r = res; - *width = 0; - - while (p && *p) { - if (iscntrl((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - p++; - } -#ifdef HAVE_WIDECHAR - else { - wchar_t wc; - size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); - - if (len == 0) - break; /* end of string */ - - if (len == (size_t) -1 || len == (size_t) -2) { - len = 1; - /* - * Not valid multibyte sequence -- maybe it's - * printable char according to the current locales. - */ - if (!isprint((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - } else { - width++; - *r++ = *p; - } - } else if (!iswprint(wc)) { - size_t i; - for (i = 0; i < len; i++) { - sprintf(r, "\\x%02x", (unsigned char) *p); - r += 4; - *width += 4; - } - } else { - memcpy(r, p, len); - r += len; - *width += wcwidth(wc); - } - p += len; - } -#else - else if (!isprint((unsigned char) *p)) { - sprintf(r, "\\x%02x", (unsigned char) *p); - p++; - r += 4; - *width += 4; - } else { - *r++ = *p++; - *width++; - } -#endif - } - - *r = '\0'; - - return res; -} - -/* - * @flags: TT_FL_* flags (usually TT_FL_{ASCII,RAW}) - * - * Returns: newly allocated table - */ -struct tt *tt_new_table(int flags) -{ - struct tt *tb; - - tb = calloc(1, sizeof(struct tt)); - if (!tb) - return NULL; - - tb->flags = flags; - INIT_LIST_HEAD(&tb->tb_lines); - INIT_LIST_HEAD(&tb->tb_columns); - -#if defined(HAVE_WIDECHAR) - if (!(flags & TT_FL_ASCII) && !strcmp(nl_langinfo(CODESET), "UTF-8")) - tb->symbols = &utf8_tt_symbols; - else -#endif - tb->symbols = &ascii_tt_symbols; - - tb->first_run = TRUE; - return tb; -} - -void tt_remove_lines(struct tt *tb) -{ - if (!tb) - return; - - while (!list_empty(&tb->tb_lines)) { - struct tt_line *ln = list_entry(tb->tb_lines.next, - struct tt_line, ln_lines); - list_del(&ln->ln_lines); - free(ln->data); - free(ln); - } -} - -void tt_free_table(struct tt *tb) -{ - if (!tb) - return; - - tt_remove_lines(tb); - - while (!list_empty(&tb->tb_columns)) { - struct tt_column *cl = list_entry(tb->tb_columns.next, - struct tt_column, cl_columns); - list_del(&cl->cl_columns); - free(cl); - } - free(tb); -} - - -/* - * @tb: table - * @name: column header - * @whint: column width hint (absolute width: N > 1; relative width: N < 1) - * @flags: usually TT_FL_{TREE,TRUNCATE} - * - * The column width is possible to define by three ways: - * - * @whint = 0..1 : relative width, percent of terminal width - * - * @whint = 1..N : absolute width, empty colum will be truncated to - * the column header width - * - * @whint = 1..N - * @flags = TT_FL_STRICTWIDTH - * : absolute width, empty colum won't be truncated - * - * The column is necessary to address (for example for tt_line_set_data()) by - * sequential number. The first defined column has the colnum = 0. For example: - * - * tt_define_column(tab, "FOO", 0.5, 0); // colnum = 0 - * tt_define_column(tab, "BAR", 0.5, 0); // colnum = 1 - * . - * . - * tt_line_set_data(line, 0, "foo-data"); // FOO column - * tt_line_set_data(line, 1, "bar-data"); // BAR column - * - * Returns: newly allocated column definition - */ -struct tt_column *tt_define_column(struct tt *tb, const char *name, - double whint, int flags) -{ - struct tt_column *cl; - - if (!tb) - return NULL; - cl = calloc(1, sizeof(*cl)); - if (!cl) - return NULL; - - cl->name = name; - cl->width_hint = whint; - cl->flags = flags; - cl->seqnum = tb->ncols++; - - if (flags & TT_FL_TREE) - tb->flags |= TT_FL_TREE; - - INIT_LIST_HEAD(&cl->cl_columns); - list_add_tail(&cl->cl_columns, &tb->tb_columns); - return cl; -} - -/* - * @tb: table - * @parent: parental line or NULL - * - * Returns: newly allocate line - */ -struct tt_line *tt_add_line(struct tt *tb, struct tt_line *parent) -{ - struct tt_line *ln = NULL; - - if (!tb || !tb->ncols) - goto err; - ln = calloc(1, sizeof(*ln)); - if (!ln) - goto err; - ln->data = calloc(tb->ncols, sizeof(char *)); - if (!ln->data) - goto err; - - ln->table = tb; - ln->parent = parent; - INIT_LIST_HEAD(&ln->ln_lines); - INIT_LIST_HEAD(&ln->ln_children); - INIT_LIST_HEAD(&ln->ln_branch); - - list_add_tail(&ln->ln_lines, &tb->tb_lines); - - if (parent) - list_add_tail(&ln->ln_children, &parent->ln_branch); - return ln; -err: - free(ln); - return NULL; -} - -/* - * @tb: table - * @colnum: number of column (0..N) - * - * Returns: pointer to column or NULL - */ -struct tt_column *tt_get_column(struct tt *tb, size_t colnum) -{ - struct list_head *p; - - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - if (cl->seqnum == colnum) - return cl; - } - return NULL; -} - -/* - * @ln: line - * @colnum: number of column (0..N) - * @data: printable data - * - * Stores data that will be printed to the table cell. - */ -int tt_line_set_data(struct tt_line *ln, int colnum, const char *data) -{ - struct tt_column *cl; - - if (!ln) - return -1; - cl = tt_get_column(ln->table, colnum); - if (!cl) - return -1; - - if (ln->data[cl->seqnum]) { - size_t sz = strlen(ln->data[cl->seqnum]);; - ln->data_sz = ln->data_sz > sz ? ln->data_sz - sz : 0; - } - - ln->data[cl->seqnum] = data; - if (data) - ln->data_sz += strlen(data); - return 0; -} - -int tt_line_set_userdata(struct tt_line *ln, void *data) -{ - if (!ln) - return -1; - ln->userdata = data; - return 0; -} - -static char *line_get_ascii_art(struct tt_line *ln, char *buf, size_t *bufsz) -{ - const char *art; - size_t len; - - if (!ln->parent) - return buf; - - buf = line_get_ascii_art(ln->parent, buf, bufsz); - if (!buf) - return NULL; - - if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) - art = " "; - else - art = ln->table->symbols->vert; - - len = strlen(art); - if (*bufsz < len) - return NULL; /* no space, internal error */ - - memcpy(buf, art, len); - *bufsz -= len; - return buf + len; -} - -static char *line_get_data(struct tt_line *ln, struct tt_column *cl, - char *buf, size_t bufsz) -{ - const char *data = ln->data[cl->seqnum]; - const struct tt_symbols *sym; - char *p = buf; - - memset(buf, 0, bufsz); - - if (!data) - return NULL; - if (!(cl->flags & TT_FL_TREE)) { - strncpy(buf, data, bufsz); - buf[bufsz - 1] = '\0'; - return buf; - } - - /* - * Tree stuff - */ - if (ln->parent) { - p = line_get_ascii_art(ln->parent, buf, &bufsz); - if (!p) - return NULL; - } - - sym = ln->table->symbols; - - if (!ln->parent) - snprintf(p, bufsz, "%s", data); /* root node */ - else if (list_entry_is_last(&ln->ln_children, &ln->parent->ln_branch)) - snprintf(p, bufsz, "%s%s", sym->right, data); /* last chaild */ - else - snprintf(p, bufsz, "%s%s", sym->branch, data); /* any child */ - - return buf; -} - -/* - * This function counts column width. - * - * For the TT_FL_NOEXTREMES columns is possible to call this function two - * times. The first pass counts width and average width. If the column - * contains too large fields (width greater than 2 * average) then the column - * is marked as "extreme". In the second pass all extreme fields are ignored - * and column width is counted from non-extreme fields only. - */ -static void count_column_width(struct tt *tb, struct tt_column *cl, - char *buf, size_t bufsz) -{ - struct list_head *lp; - int count = 0; - size_t sum = 0; - - cl->width = 0; - - list_for_each(lp, &tb->tb_lines) { - struct tt_line *ln = list_entry(lp, struct tt_line, ln_lines); - char *data = line_get_data(ln, cl, buf, bufsz); - size_t len = data ? mbs_safe_width(data) : 0; - - if (len == (size_t) -1) /* ignore broken multibyte strings */ - len = 0; - - if (len > cl->width_max) - cl->width_max = len; - - if (cl->is_extreme && len > cl->width_avg * 2) - continue; - else if (cl->flags & TT_FL_NOEXTREMES) { - sum += len; - count++; - } - if (len > cl->width) - cl->width = len; - } - - if (count && cl->width_avg == 0) { - cl->width_avg = sum / count; - - if (cl->width_max > cl->width_avg * 2) - cl->is_extreme = 1; - } - - /* check and set minimal column width */ - if (cl->name) - cl->width_min = mbs_safe_width(cl->name); - - /* enlarge to minimal width */ - if (cl->width < cl->width_min && !(cl->flags & TT_FL_STRICTWIDTH)) - cl->width = cl->width_min; - - /* use relative size for large columns */ - else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint && - cl->width_min < (size_t) cl->width_hint) - - cl->width = (size_t) cl->width_hint; -} - -/* - * This is core of the tt_* voodo... - */ -static void recount_widths(struct tt *tb, char *buf, size_t bufsz) -{ - struct list_head *p; - size_t width = 0; /* output width */ - int trunc_only; - int extremes = 0; - - /* set basic columns width - */ - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - - count_column_width(tb, cl, buf, bufsz); - width += cl->width + (is_last_column(tb, cl) ? 0 : 1); - extremes += cl->is_extreme; - } - - if (!tb->is_term) - return; - - /* reduce columns with extreme fields - */ - if (width > tb->termwidth && extremes) { - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = list_entry(p, struct tt_column, cl_columns); - size_t org_width; - - if (!cl->is_extreme) - continue; - - org_width = cl->width; - count_column_width(tb, cl, buf, bufsz); - - if (org_width > cl->width) - width -= org_width - cl->width; - else - extremes--; /* hmm... nothing reduced */ - } - } - - if (width < tb->termwidth) { - /* try to found extreme column which fits into available space - */ - if (extremes) { - /* enlarge the first extreme column */ - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - size_t add; - - if (!cl->is_extreme) - continue; - - /* this column is tooo large, ignore? - if (cl->width_max - cl->width > - (tb->termwidth - width)) - continue; - */ - - add = tb->termwidth - width; - if (add && cl->width + add > cl->width_max) - add = cl->width_max - cl->width; - - cl->width += add; - width += add; - - if (width == tb->termwidth) - break; - } - } - if (width < tb->termwidth) { - /* enalarge the last column */ - struct tt_column *cl = list_entry( - tb->tb_columns.prev, struct tt_column, cl_columns); - - if (!(cl->flags & TT_FL_RIGHT) && tb->termwidth - width > 0) { - cl->width += tb->termwidth - width; - width = tb->termwidth; - } - } - } - - /* bad, we have to reduce output width, this is done in two steps: - * 1/ reduce columns with a relative width and with truncate flag - * 2) reduce columns with a relative width without truncate flag - */ - trunc_only = 1; - while (width > tb->termwidth) { - size_t org = width; - - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - - if (width <= tb->termwidth) - break; - if (cl->width_hint > 1 && !(cl->flags & TT_FL_TRUNC)) - continue; /* never truncate columns with absolute sizes */ - if (cl->flags & TT_FL_TREE) - continue; /* never truncate the tree */ - if (trunc_only && !(cl->flags & TT_FL_TRUNC)) - continue; - if (cl->width == cl->width_min) - continue; - - /* truncate column with relative sizes */ - if (cl->width_hint < 1 && cl->width > 0 && width > 0 && - cl->width > cl->width_hint * tb->termwidth) { - cl->width--; - width--; - } - /* truncate column with absolute size */ - if (cl->width_hint > 1 && cl->width > 0 && width > 0 && - !trunc_only) { - cl->width--; - width--; - } - - } - if (org == width) { - if (trunc_only) - trunc_only = 0; - else - break; - } - } - -/* - fprintf(stderr, "terminal: %d, output: %d\n", tb->termwidth, width); - - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - - fprintf(stderr, "width: %s=%zd [hint=%d, avg=%zd, max=%zd, extreme=%s]\n", - cl->name, cl->width, - cl->width_hint > 1 ? (int) cl->width_hint : - (int) (cl->width_hint * tb->termwidth), - cl->width_avg, - cl->width_max, - cl->is_extreme ? "yes" : "not"); - } -*/ - return; -} - -void tt_fputs_quoted(const char *data, FILE *out) -{ - const char *p; - - fputc('"', out); - for (p = data; p && *p; p++) { - if ((unsigned char) *p == 0x22 || /* " */ - (unsigned char) *p == 0x5c || /* \ */ - !isprint((unsigned char) *p) || - iscntrl((unsigned char) *p)) { - - fprintf(out, "\\x%02x", (unsigned char) *p); - } else - fputc(*p, out); - } - fputc('"', out); -} - -void tt_fputs_nonblank(const char *data, FILE *out) -{ - const char *p; - - for (p = data; p && *p; p++) { - if (isblank((unsigned char) *p) || - (unsigned char) *p == 0x5c || /* \ */ - !isprint((unsigned char) *p) || - iscntrl((unsigned char) *p)) { - - fprintf(out, "\\x%02x", (unsigned char) *p); - - } else - fputc(*p, out); - } -} - -/* - * Prints data, data maybe be printed in more formats (raw, NAME=xxx pairs) and - * control and non-printable chars maybe encoded in \x?? hex encoding. - */ -static void print_data(struct tt *tb, struct tt_column *cl, char *data) -{ - size_t len = 0, i, width; - char *buf; - - if (!data) - data = ""; - - /* raw mode */ - if (tb->flags & TT_FL_RAW) { - tt_fputs_nonblank(data, stdout); - if (!is_last_column(tb, cl)) - fputc(' ', stdout); - return; - } - - /* NAME=value mode */ - if (tb->flags & TT_FL_EXPORT) { - fprintf(stdout, "%s=", cl->name); - tt_fputs_quoted(data, stdout); - if (!is_last_column(tb, cl)) - fputc(' ', stdout); - return; - } - - /* note that 'len' and 'width' are number of cells, not bytes */ - buf = mbs_safe_encode(data, &len); - data = buf; - if (!data) - data = ""; - - if (!len || len == (size_t) -1) { - len = 0; - data = NULL; - } - width = cl->width; - - if (is_last_column(tb, cl) && len < width) - width = len; - - /* truncate data */ - if (len > width && (cl->flags & TT_FL_TRUNC)) { - if (data) - len = mbs_truncate(data, &width); - if (!data || len == (size_t) -1) { - len = 0; - data = NULL; - } - } - if (data) { - if (!(tb->flags & TT_FL_RAW) && (cl->flags & TT_FL_RIGHT)) { - size_t xw = cl->width; - fprintf(stdout, "%*s", (int) xw, data); - if (len < xw) - len = xw; - } - else - fputs(data, stdout); - } - for (i = len; i < width; i++) - fputc(' ', stdout); /* padding */ - - if (!is_last_column(tb, cl)) { - if (len > width && !(cl->flags & TT_FL_TRUNC)) { - fputc('\n', stdout); - for (i = 0; i <= (size_t) cl->seqnum; i++) { - struct tt_column *x = tt_get_column(tb, i); - printf("%*s ", -((int)x->width), " "); - } - } else - fputc(' ', stdout); /* columns separator */ - } - - free(buf); -} - -static void print_line(struct tt_line *ln, char *buf, size_t bufsz) -{ - struct list_head *p; - - /* set width according to the size of data - */ - list_for_each(p, &ln->table->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - - print_data(ln->table, cl, line_get_data(ln, cl, buf, bufsz)); - } - fputc('\n', stdout); -} - -static void print_header(struct tt *tb, char *buf, size_t bufsz) -{ - struct list_head *p; - - if (!tb->first_run || - (tb->flags & TT_FL_NOHEADINGS) || - (tb->flags & TT_FL_EXPORT) || - list_empty(&tb->tb_lines)) - return; - - /* set width according to the size of data - */ - list_for_each(p, &tb->tb_columns) { - struct tt_column *cl = - list_entry(p, struct tt_column, cl_columns); - - strncpy(buf, cl->name, bufsz); - buf[bufsz - 1] = '\0'; - print_data(tb, cl, buf); - } - fputc('\n', stdout); -} - -static void print_table(struct tt *tb, char *buf, size_t bufsz) -{ - struct list_head *p; - - print_header(tb, buf, bufsz); - - list_for_each(p, &tb->tb_lines) { - struct tt_line *ln = list_entry(p, struct tt_line, ln_lines); - - print_line(ln, buf, bufsz); - } -} - -static void print_tree_line(struct tt_line *ln, char *buf, size_t bufsz) -{ - struct list_head *p; - - print_line(ln, buf, bufsz); - - if (list_empty(&ln->ln_branch)) - return; - - /* print all children */ - list_for_each(p, &ln->ln_branch) { - struct tt_line *chld = - list_entry(p, struct tt_line, ln_children); - print_tree_line(chld, buf, bufsz); - } -} - -static void print_tree(struct tt *tb, char *buf, size_t bufsz) -{ - struct list_head *p; - - print_header(tb, buf, bufsz); - - list_for_each(p, &tb->tb_lines) { - struct tt_line *ln = list_entry(p, struct tt_line, ln_lines); - - if (ln->parent) - continue; - - print_tree_line(ln, buf, bufsz); - } -} - -/* - * @tb: table - * - * Prints the table to stdout - */ -int tt_print_table(struct tt *tb) -{ - char *line; - size_t line_sz; - struct list_head *p; - - if (!tb) - return -1; - - if (tb->first_run) { - tb->is_term = isatty(STDOUT_FILENO); - - if (tb->is_term && !tb->termwidth) - tb->termwidth = get_terminal_width(); - if (tb->termwidth <= 0) - tb->termwidth = 80; - } - - line_sz = tb->termwidth; - - list_for_each(p, &tb->tb_lines) { - struct tt_line *ln = list_entry(p, struct tt_line, ln_lines); - if (ln->data_sz > line_sz) - line_sz = ln->data_sz; - } - - line_sz++; /* make a space for \0 */ - line = malloc(line_sz); - if (!line) - return -1; - - if (tb->first_run && - !((tb->flags & TT_FL_RAW) || (tb->flags & TT_FL_EXPORT))) - recount_widths(tb, line, line_sz); - - if (tb->flags & TT_FL_TREE) - print_tree(tb, line, line_sz); - else - print_table(tb, line, line_sz); - - free(line); - - tb->first_run = FALSE; - return 0; -} - -#ifdef TEST_PROGRAM -#include <errno.h> - -enum { MYCOL_NAME, MYCOL_FOO, MYCOL_BAR, MYCOL_PATH }; - -int main(int argc, char *argv[]) -{ - struct tt *tb; - struct tt_line *ln, *pr, *root; - int flags = 0, notree = 0, i; - - if (argc == 2 && !strcmp(argv[1], "--help")) { - printf("%s [--ascii | --raw | --list]\n", - program_invocation_short_name); - return EXIT_SUCCESS; - } else if (argc == 2 && !strcmp(argv[1], "--ascii")) { - flags |= TT_FL_ASCII; - } else if (argc == 2 && !strcmp(argv[1], "--raw")) { - flags |= TT_FL_RAW; - notree = 1; - } else if (argc == 2 && !strcmp(argv[1], "--export")) { - flags |= TT_FL_EXPORT; - notree = 1; - } else if (argc == 2 && !strcmp(argv[1], "--list")) - notree = 1; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - - tb = tt_new_table(flags); - if (!tb) - err(EXIT_FAILURE, "table initialization failed"); - - tt_define_column(tb, "NAME", 0.3, notree ? 0 : TT_FL_TREE); - tt_define_column(tb, "FOO", 0.3, TT_FL_TRUNC); - tt_define_column(tb, "BAR", 0.3, 0); - tt_define_column(tb, "PATH", 0.3, 0); - - for (i = 0; i < 2; i++) { - root = ln = tt_add_line(tb, NULL); - tt_line_set_data(ln, MYCOL_NAME, "AAA"); - tt_line_set_data(ln, MYCOL_FOO, "a-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA"); - - pr = ln = tt_add_line(tb, ln); - tt_line_set_data(ln, MYCOL_NAME, "AAA.A"); - tt_line_set_data(ln, MYCOL_FOO, "a.a-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A"); - - ln = tt_add_line(tb, pr); - tt_line_set_data(ln, MYCOL_NAME, "AAA.A.AAA"); - tt_line_set_data(ln, MYCOL_FOO, "a.a.a-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.A"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/AAA"); - - ln = tt_add_line(tb, root); - tt_line_set_data(ln, MYCOL_NAME, "AAA.B"); - tt_line_set_data(ln, MYCOL_FOO, "a.b-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.B"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/B"); - - ln = tt_add_line(tb, pr); - tt_line_set_data(ln, MYCOL_NAME, "AAA.A.BBB"); - tt_line_set_data(ln, MYCOL_FOO, "a.a.b-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.BBB"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/BBB"); - - ln = tt_add_line(tb, pr); - tt_line_set_data(ln, MYCOL_NAME, "AAA.A.CCC"); - tt_line_set_data(ln, MYCOL_FOO, "a.a.c-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.A.CCC"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/A/CCC"); - - ln = tt_add_line(tb, root); - tt_line_set_data(ln, MYCOL_NAME, "AAA.C"); - tt_line_set_data(ln, MYCOL_FOO, "a.c-foo-foo"); - tt_line_set_data(ln, MYCOL_BAR, "barBar-A.C"); - tt_line_set_data(ln, MYCOL_PATH, "/mnt/AAA/C"); - } - - tt_print_table(tb); - tt_free_table(tb); - - return EXIT_SUCCESS; -} -#endif diff --git a/libblkid/tt.h b/libblkid/tt.h deleted file mode 100644 index 603844f66..000000000 --- a/libblkid/tt.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Prints table or tree. See lib/table.c for more details and example. - * - * Copyright (C) 2010 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#ifndef UTIL_LINUX_TT_H -#define UTIL_LINUX_TT_H - -#include "list.h" - -enum { - /* - * Global flags - */ - TT_FL_RAW = (1 << 1), - TT_FL_ASCII = (1 << 2), - TT_FL_NOHEADINGS = (1 << 3), - TT_FL_EXPORT = (1 << 4), - - /* - * Column flags - */ - TT_FL_TRUNC = (1 << 5), /* truncate fields data if necessary */ - TT_FL_TREE = (1 << 6), /* use tree "ascii art" */ - TT_FL_RIGHT = (1 << 7), /* align to the right */ - TT_FL_STRICTWIDTH = (1 << 8), /* don't reduce width if column is empty */ - TT_FL_NOEXTREMES = (1 << 9) /* ignore extreme fields when count column width*/ -}; - -struct tt { - size_t ncols; /* number of columns */ - size_t termwidth; /* terminal width */ - int is_term; /* is a tty? */ - int flags; - int first_run; - - struct list_head tb_columns; - struct list_head tb_lines; - - const struct tt_symbols *symbols; -}; - -struct tt_column { - const char *name; /* header */ - size_t seqnum; - - size_t width; /* real column width */ - size_t width_min; /* minimal width (usually header width) */ - size_t width_max; /* maximal width */ - size_t width_avg; /* average width, used to detect extreme fields */ - double width_hint; /* hint (N < 1 is in percent of termwidth) */ - - int flags; - int is_extreme; - - struct list_head cl_columns; -}; - -struct tt_line { - struct tt *table; - char const **data; - void *userdata; - size_t data_sz; /* strlen of all data */ - - struct list_head ln_lines; /* table lines */ - - struct list_head ln_branch; /* begin of branch (head of ln_children) */ - struct list_head ln_children; - - struct tt_line *parent; -}; - -extern struct tt *tt_new_table(int flags); -extern void tt_free_table(struct tt *tb); -extern void tt_remove_lines(struct tt *tb); -extern int tt_print_table(struct tt *tb); - -extern struct tt_column *tt_define_column(struct tt *tb, const char *name, - double whint, int flags); - -extern struct tt_column *tt_get_column(struct tt *tb, size_t colnum); - -extern struct tt_line *tt_add_line(struct tt *tb, struct tt_line *parent); - -extern int tt_line_set_data(struct tt_line *ln, int colnum, const char *data); -extern int tt_line_set_userdata(struct tt_line *ln, void *data); - -extern void tt_fputs_quoted(const char *data, FILE *out); -extern void tt_fputs_nonblank(const char *data, FILE *out); - -#endif /* UTIL_LINUX_TT_H */ diff --git a/libblkid/ttyutils.c b/libblkid/ttyutils.c deleted file mode 100644 index 3b5a68cd8..000000000 --- a/libblkid/ttyutils.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#include <ctype.h> - -#include "c.h" -#include "ttyutils.h" - -int get_terminal_width(void) -{ -#ifdef TIOCGSIZE - struct ttysize t_win; -#endif -#ifdef TIOCGWINSZ - struct winsize w_win; -#endif - const char *cp; - -#ifdef TIOCGSIZE - if (ioctl (0, TIOCGSIZE, &t_win) == 0) - return t_win.ts_cols; -#endif -#ifdef TIOCGWINSZ - if (ioctl (0, TIOCGWINSZ, &w_win) == 0) - return w_win.ws_col; -#endif - cp = getenv("COLUMNS"); - if (cp) { - char *end = NULL; - long c; - - errno = 0; - c = strtol(cp, &end, 10); - - if (errno == 0 && end && *end == '\0' && end > cp && - c > 0 && c <= INT_MAX) - return c; - } - return 0; -} - -int get_terminal_name(const char **path, - const char **name, - const char **number) -{ - const char *tty; - const char *p; - - if (name) - *name = NULL; - if (path) - *path = NULL; - if (number) - *number = NULL; - - tty = ttyname(STDERR_FILENO); - if (!tty) - return -1; - if (path) - *path = tty; - tty = strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty; - if (name) - *name = tty; - if (number) { - for (p = tty; p && *p; p++) { - if (isdigit(*p)) { - *number = p; - break; - } - } - } - return 0; -} - - -#ifdef TEST_PROGRAM -# include <stdlib.h> -int main(void) -{ - const char *path, *name, *num; - - if (get_terminal_name(&path, &name, &num) == 0) { - fprintf(stderr, "tty path: %s\n", path); - fprintf(stderr, "tty name: %s\n", name); - fprintf(stderr, "tty number: %s\n", num); - } - fprintf(stderr, "tty width: %d\n", get_terminal_width()); - - return EXIT_SUCCESS; -} -#endif diff --git a/libblkid/ttyutils.h b/libblkid/ttyutils.h deleted file mode 100644 index 021156d3e..000000000 --- a/libblkid/ttyutils.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#ifndef UTIL_LINUX_TTYUTILS_H -#define UTIL_LINUX_TTYUTILS_H - -#include <stdlib.h> -#include <termios.h> -#include <limits.h> -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -/* Some shorthands for control characters. */ -#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ -#define CR CTL('M') /* carriage return */ -#define NL CTL('J') /* line feed */ -#define BS CTL('H') /* back space */ -#define DEL CTL('?') /* delete */ - -/* Defaults for line-editing etc. characters; you may want to change these. */ -#define DEF_ERASE DEL /* default erase character */ -#define DEF_INTR CTL('C') /* default interrupt character */ -#define DEF_QUIT CTL('\\') /* default quit char */ -#define DEF_KILL CTL('U') /* default kill char */ -#define DEF_EOF CTL('D') /* default EOF char */ -#define DEF_EOL 0 -#define DEF_SWITCH 0 /* default switch char */ - -/* Storage for things detected while the login name was read. */ -struct chardata { - int erase; /* erase character */ - int kill; /* kill character */ - int eol; /* end-of-line character */ - int parity; /* what parity did we see */ - int capslock; /* upper case without lower case */ -}; - -#define INIT_CHARDATA(ptr) do { \ - (ptr)->erase = DEF_ERASE; \ - (ptr)->kill = DEF_KILL; \ - (ptr)->eol = CTRL('r'); \ - (ptr)->parity = 0; \ - (ptr)->capslock = 0; \ - } while (0) - -extern int get_terminal_width(void); -extern int get_terminal_name(const char **path, const char **name, const char **number); - -#define UL_TTY_KEEPCFLAGS (1 << 1) -#define UL_TTY_UTF8 (1 << 2) - -static inline void reset_virtual_console(struct termios *tp, int flags) -{ - /* Use defaults of <sys/ttydefaults.h> for base settings */ - tp->c_iflag |= TTYDEF_IFLAG; - tp->c_oflag |= TTYDEF_OFLAG; - tp->c_lflag |= TTYDEF_LFLAG; - - if ((flags & UL_TTY_KEEPCFLAGS) == 0) { -#ifdef CBAUD - tp->c_lflag &= ~CBAUD; -#endif - tp->c_cflag |= (B38400 | TTYDEF_CFLAG); - } - - /* Sane setting, allow eight bit characters, no carriage return delay - * the same result as `stty sane cr0 pass8' - */ - tp->c_iflag |= (BRKINT | ICRNL | IMAXBEL); - tp->c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP); - tp->c_oflag |= (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0); - tp->c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | \ - NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); - tp->c_lflag |= (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE); - tp->c_lflag &= ~(ECHONL|ECHOCTL|ECHOPRT | NOFLSH | TOSTOP); - - if ((flags & UL_TTY_KEEPCFLAGS) == 0) { - tp->c_cflag |= (CREAD | CS8 | HUPCL); - tp->c_cflag &= ~(PARODD | PARENB); - } -#ifdef OFDEL - tp->c_oflag &= ~OFDEL; -#endif -#ifdef XCASE - tp->c_lflag &= ~XCASE; -#endif -#ifdef IUTF8 - if (flags & UL_TTY_UTF8) - tp->c_iflag |= IUTF8; /* Set UTF-8 input flag */ - else - tp->c_iflag &= ~IUTF8; -#endif - /* VTIME and VMIN can overlap with VEOF and VEOL since they are - * only used for non-canonical mode. We just set the at the - * beginning, so nothing bad should happen. - */ - tp->c_cc[VTIME] = 0; - tp->c_cc[VMIN] = 1; - tp->c_cc[VINTR] = CINTR; - tp->c_cc[VQUIT] = CQUIT; - tp->c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */ - tp->c_cc[VKILL] = CKILL; - tp->c_cc[VEOF] = CEOF; -#ifdef VSWTC - tp->c_cc[VSWTC] = _POSIX_VDISABLE; -#elif defined(VSWTCH) - tp->c_cc[VSWTCH] = _POSIX_VDISABLE; -#endif - tp->c_cc[VSTART] = CSTART; - tp->c_cc[VSTOP] = CSTOP; - tp->c_cc[VSUSP] = CSUSP; - tp->c_cc[VEOL] = _POSIX_VDISABLE; - tp->c_cc[VREPRINT] = CREPRINT; - tp->c_cc[VDISCARD] = CDISCARD; - tp->c_cc[VWERASE] = CWERASE; - tp->c_cc[VLNEXT] = CLNEXT; - tp->c_cc[VEOL2] = _POSIX_VDISABLE; -} - - - -#endif /* UTIL_LINUX_TTYUTILS_H */ diff --git a/libblkid/ubifs.c b/libblkid/ubifs.c deleted file mode 100644 index 2d69c2bf3..000000000 --- a/libblkid/ubifs.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2009 Corentin Chary <corentincj@iksaif.net> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdint.h> - -#include "superblocks.h" - -/* - * struct ubifs_ch - common header node. - * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) - * @crc: CRC-32 checksum of the node header - * @sqnum: sequence number - * @len: full node length - * @node_type: node type - * @group_type: node group type - * @padding: reserved for future, zeroes - * - * Every UBIFS node starts with this common part. If the node has a key, the - * key always goes next. - */ -struct ubifs_ch { - uint32_t magic; - uint32_t crc; - uint64_t sqnum; - uint32_t len; - uint8_t node_type; - uint8_t group_type; - uint8_t padding[2]; -} __attribute__ ((packed)); - -/* - * struct ubifs_sb_node - superblock node. - * @ch: common header - * @padding: reserved for future, zeroes - * @key_hash: type of hash function used in keys - * @key_fmt: format of the key - * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) - * @min_io_size: minimal input/output unit size - * @leb_size: logical eraseblock size in bytes - * @leb_cnt: count of LEBs used by file-system - * @max_leb_cnt: maximum count of LEBs used by file-system - * @max_bud_bytes: maximum amount of data stored in buds - * @log_lebs: log size in logical eraseblocks - * @lpt_lebs: number of LEBs used for lprops table - * @orph_lebs: number of LEBs used for recording orphans - * @jhead_cnt: count of journal heads - * @fanout: tree fanout (max. number of links per indexing node) - * @lsave_cnt: number of LEB numbers in LPT's save table - * @fmt_version: UBIFS on-flash format version - * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) - * @padding1: reserved for future, zeroes - * @rp_uid: reserve pool UID - * @rp_gid: reserve pool GID - * @rp_size: size of the reserved pool in bytes - * @padding2: reserved for future, zeroes - * @time_gran: time granularity in nanoseconds - * @uuid: UUID generated when the file system image was created - * @ro_compat_version: UBIFS R/O compatibility version - */ -struct ubifs_sb_node { - struct ubifs_ch ch; - uint8_t padding[2]; - uint8_t key_hash; - uint8_t key_fmt; - uint32_t flags; - uint32_t min_io_size; - uint32_t leb_size; - uint32_t leb_cnt; - uint32_t max_leb_cnt; - uint64_t max_bud_bytes; - uint32_t log_lebs; - uint32_t lpt_lebs; - uint32_t orph_lebs; - uint32_t jhead_cnt; - uint32_t fanout; - uint32_t lsave_cnt; - uint32_t fmt_version; - uint16_t default_compr; - uint8_t padding1[2]; - uint32_t rp_uid; - uint32_t rp_gid; - uint64_t rp_size; - uint32_t time_gran; - uint8_t uuid[16]; - uint32_t ro_compat_version; - uint8_t padding2[3968]; -} __attribute__ ((packed)); - -static int probe_ubifs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct ubifs_sb_node *sb; - - sb = blkid_probe_get_sb(pr, mag, struct ubifs_sb_node); - if (!sb) - return -1; - - blkid_probe_set_uuid(pr, sb->uuid); - blkid_probe_sprintf_version(pr, "w%dr%d", - sb->fmt_version, sb->ro_compat_version); - return 0; -} - -const struct blkid_idinfo ubifs_idinfo = -{ - .name = "ubifs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ubifs, - .magics = - { - { .magic = "\x31\x18\x10\x06", .len = 4 }, - { NULL } - } -}; diff --git a/libblkid/udf.c b/libblkid/udf.c deleted file mode 100644 index 2cb471df2..000000000 --- a/libblkid/udf.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" -#include "iso9660.h" - -struct volume_descriptor { - struct descriptor_tag { - uint16_t id; - uint16_t version; - uint8_t checksum; - uint8_t reserved; - uint16_t serial; - uint16_t crc; - uint16_t crc_len; - uint32_t location; - } __attribute__((packed)) tag; - - union { - struct anchor_descriptor { - uint32_t length; - uint32_t location; - } __attribute__((packed)) anchor; - - struct primary_descriptor { - uint32_t seq_num; - uint32_t desc_num; - struct dstring { - uint8_t clen; - uint8_t c[31]; - } __attribute__((packed)) ident; - } __attribute__((packed)) primary; - - } __attribute__((packed)) type; - -} __attribute__((packed)); - -struct volume_structure_descriptor { - uint8_t type; - uint8_t id[5]; - uint8_t version; -} __attribute__((packed)); - -#define UDF_VSD_OFFSET 0x8000LL - -static int probe_udf(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct volume_descriptor *vd; - struct volume_structure_descriptor *vsd; - unsigned int bs; - unsigned int b; - unsigned int type; - unsigned int count; - unsigned int loc; - - /* search Volume Sequence Descriptor (VSD) to get the logical - * block size of the volume */ - for (bs = 0x800; bs < 0x8000; bs += 0x800) { - vsd = (struct volume_structure_descriptor *) - blkid_probe_get_buffer(pr, - UDF_VSD_OFFSET + bs, - sizeof(*vsd)); - if (!vsd) - return 1; - if (vsd->id[0] != '\0') - goto nsr; - } - return -1; - -nsr: - /* search the list of VSDs for a NSR descriptor */ - for (b = 0; b < 64; b++) { - vsd = (struct volume_structure_descriptor *) - blkid_probe_get_buffer(pr, - UDF_VSD_OFFSET + ((blkid_loff_t) b * bs), - sizeof(*vsd)); - if (!vsd) - return -1; - if (vsd->id[0] == '\0') - return -1; - if (memcmp(vsd->id, "NSR02", 5) == 0) - goto anchor; - if (memcmp(vsd->id, "NSR03", 5) == 0) - goto anchor; - } - return -1; - -anchor: - /* read Anchor Volume Descriptor (AVDP) */ - vd = (struct volume_descriptor *) - blkid_probe_get_buffer(pr, 256 * bs, sizeof(*vd)); - if (!vd) - return -1; - - type = le16_to_cpu(vd->tag.id); - if (type != 2) /* TAG_ID_AVDP */ - return 0; - - /* get desriptor list address and block count */ - count = le32_to_cpu(vd->type.anchor.length) / bs; - loc = le32_to_cpu(vd->type.anchor.location); - - /* check if the list is usable */ - for (b = 0; b < count; b++) { - vd = (struct volume_descriptor *) - blkid_probe_get_buffer(pr, - (blkid_loff_t) (loc + b) * bs, - sizeof(*vd)); - if (!vd) - return -1; - } - - /* Try extract all possible ISO9660 information -- if there is - * usable LABEL in ISO header then use it, otherwise read UDF - * specific LABEL */ - if (probe_iso9660(pr, mag) == 0 && - __blkid_probe_lookup_value(pr, "LABEL") != NULL) - return 0; - - /* Read UDF label */ - for (b = 0; b < count; b++) { - vd = (struct volume_descriptor *) - blkid_probe_get_buffer(pr, - (blkid_loff_t) (loc + b) * bs, - sizeof(*vd)); - - type = le16_to_cpu(vd->tag.id); - if (type == 0) - break; - if (le32_to_cpu(vd->tag.location) != loc + b) - break; - if (type == 1) { /* TAG_ID_PVD */ - uint8_t clen = vd->type.primary.ident.clen; - - if (clen == 8) - blkid_probe_set_label(pr, - vd->type.primary.ident.c, 31); - else if (clen == 16) - blkid_probe_set_utf8label(pr, - vd->type.primary.ident.c, - 31, BLKID_ENC_UTF16BE); - - if (clen == 8 || clen == 16) - break; - } - } - - return 0; -} - - -const struct blkid_idinfo udf_idinfo = -{ - .name = "udf", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_udf, - .flags = BLKID_IDINFO_TOLERANT, - .magics = - { - { .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "BOOT2", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "CDW02", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "NSR02", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "NSR03", .len = 5, .kboff = 32, .sboff = 1 }, - { .magic = "TEA01", .len = 5, .kboff = 32, .sboff = 1 }, - { NULL } - } -}; diff --git a/libblkid/ufs.c b/libblkid/ufs.c deleted file mode 100644 index 673a528bc..000000000 --- a/libblkid/ufs.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> -#include <stddef.h> - -#include "superblocks.h" - -struct ufs_super_block { - uint32_t fs_link; - uint32_t fs_rlink; - uint32_t fs_sblkno; - uint32_t fs_cblkno; - uint32_t fs_iblkno; - uint32_t fs_dblkno; - uint32_t fs_cgoffset; - uint32_t fs_cgmask; - uint32_t fs_time; - uint32_t fs_size; - uint32_t fs_dsize; - uint32_t fs_ncg; - uint32_t fs_bsize; - uint32_t fs_fsize; - uint32_t fs_frag; - uint32_t fs_minfree; - uint32_t fs_rotdelay; - uint32_t fs_rps; - uint32_t fs_bmask; - uint32_t fs_fmask; - uint32_t fs_bshift; - uint32_t fs_fshift; - uint32_t fs_maxcontig; - uint32_t fs_maxbpg; - uint32_t fs_fragshift; - uint32_t fs_fsbtodb; - uint32_t fs_sbsize; - uint32_t fs_csmask; - uint32_t fs_csshift; - uint32_t fs_nindir; - uint32_t fs_inopb; - uint32_t fs_nspf; - uint32_t fs_optim; - uint32_t fs_npsect_state; - uint32_t fs_interleave; - uint32_t fs_trackskew; - uint32_t fs_id[2]; - uint32_t fs_csaddr; - uint32_t fs_cssize; - uint32_t fs_cgsize; - uint32_t fs_ntrak; - uint32_t fs_nsect; - uint32_t fs_spc; - uint32_t fs_ncyl; - uint32_t fs_cpg; - uint32_t fs_ipg; - uint32_t fs_fpg; - struct ufs_csum { - uint32_t cs_ndir; - uint32_t cs_nbfree; - uint32_t cs_nifree; - uint32_t cs_nffree; - } fs_cstotal; - int8_t fs_fmod; - int8_t fs_clean; - int8_t fs_ronly; - int8_t fs_flags; - union { - struct { - int8_t fs_fsmnt[512]; - uint32_t fs_cgrotor; - uint32_t fs_csp[31]; - uint32_t fs_maxcluster; - uint32_t fs_cpc; - uint16_t fs_opostbl[16][8]; - } fs_u1; - struct { - int8_t fs_fsmnt[468]; - uint8_t fs_volname[32]; - uint64_t fs_swuid; - int32_t fs_pad; - uint32_t fs_cgrotor; - uint32_t fs_ocsp[28]; - uint32_t fs_contigdirs; - uint32_t fs_csp; - uint32_t fs_maxcluster; - uint32_t fs_active; - int32_t fs_old_cpc; - int32_t fs_maxbsize; - int64_t fs_sparecon64[17]; - int64_t fs_sblockloc; - struct ufs2_csum_total { - uint64_t cs_ndir; - uint64_t cs_nbfree; - uint64_t cs_nifree; - uint64_t cs_nffree; - uint64_t cs_numclusters; - uint64_t cs_spare[3]; - } fs_cstotal; - struct ufs_timeval { - int32_t tv_sec; - int32_t tv_usec; - } fs_time; - int64_t fs_size; - int64_t fs_dsize; - uint64_t fs_csaddr; - int64_t fs_pendingblocks; - int32_t fs_pendinginodes; - } __attribute__((packed)) fs_u2; - } fs_u11; - union { - struct { - int32_t fs_sparecon[53]; - int32_t fs_reclaim; - int32_t fs_sparecon2[1]; - int32_t fs_state; - uint32_t fs_qbmask[2]; - uint32_t fs_qfmask[2]; - } fs_sun; - struct { - int32_t fs_sparecon[53]; - int32_t fs_reclaim; - int32_t fs_sparecon2[1]; - uint32_t fs_npsect; - uint32_t fs_qbmask[2]; - uint32_t fs_qfmask[2]; - } fs_sunx86; - struct { - int32_t fs_sparecon[50]; - int32_t fs_contigsumsize; - int32_t fs_maxsymlinklen; - int32_t fs_inodefmt; - uint32_t fs_maxfilesize[2]; - uint32_t fs_qbmask[2]; - uint32_t fs_qfmask[2]; - int32_t fs_state; - } fs_44; - } fs_u2; - int32_t fs_postblformat; - int32_t fs_nrpos; - int32_t fs_postbloff; - int32_t fs_rotbloff; - uint32_t fs_magic; - uint8_t fs_space[1]; -} __attribute__((packed)); - -#define UFS_MAGIC 0x00011954 -#define UFS2_MAGIC 0x19540119 -#define UFS_MAGIC_FEA 0x00195612 -#define UFS_MAGIC_LFN 0x00095014 -#define UFS_MAGIC_SEC 0x00612195 -#define UFS_MAGIC_4GB 0x05231994 - -static int probe_ufs(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - int offsets[] = { 0, 8, 64, 256 }; - uint32_t mags[] = { - UFS2_MAGIC, UFS_MAGIC, UFS_MAGIC_FEA, UFS_MAGIC_LFN, - UFS_MAGIC_SEC, UFS_MAGIC_4GB - }; - size_t i; - uint32_t magic; - struct ufs_super_block *ufs; - int is_be; - - for (i = 0; i < ARRAY_SIZE(offsets); i++) { - uint32_t magLE, magBE; - size_t y; - - ufs = (struct ufs_super_block *) - blkid_probe_get_buffer(pr, - offsets[i] * 1024, - sizeof(struct ufs_super_block)); - if (!ufs) - return -1; - - magBE = be32_to_cpu(ufs->fs_magic); - magLE = le32_to_cpu(ufs->fs_magic); - - for (y = 0; y < ARRAY_SIZE(mags); y++) { - if (magLE == mags[y] || magBE == mags[y]) { - magic = mags[y]; - is_be = (magBE == mags[y]); - goto found; - } - } - } - - return 1; - -found: - if (magic == UFS2_MAGIC) { - blkid_probe_set_version(pr, "2"); - blkid_probe_set_label(pr, ufs->fs_u11.fs_u2.fs_volname, - sizeof(ufs->fs_u11.fs_u2.fs_volname)); - } else - blkid_probe_set_version(pr, "1"); - if (ufs->fs_id[0] || ufs->fs_id[1]) - { - if (is_be) - blkid_probe_sprintf_uuid(pr, - (unsigned char *) &ufs->fs_id, - sizeof(ufs->fs_id), - "%08x%08x", - be32_to_cpu(ufs->fs_id[0]), - be32_to_cpu(ufs->fs_id[1])); - else - blkid_probe_sprintf_uuid(pr, - (unsigned char *) &ufs->fs_id, - sizeof(ufs->fs_id), - "%08x%08x", - le32_to_cpu(ufs->fs_id[0]), - le32_to_cpu(ufs->fs_id[1])); - } - - if (blkid_probe_set_magic(pr, - (offsets[i] * 1024) + - offsetof(struct ufs_super_block, fs_magic), - sizeof(ufs->fs_magic), - (unsigned char *) &ufs->fs_magic)) - return -1; - - return 0; -} - -/* - * According to libvolume_id the UFS superblock could be on four positions. - * The original libblkid has checked one position (.kboff=8) only. - * - * We know four UFS magic strings and UFS could be both little-endian and - * big-endian. ... so we have: - * - * 4 position * 4 string * 2 version = 32 magic strings - * - * It seems simpler to check for these string in probing function that hardcode - * all in the .magic array. - */ -const struct blkid_idinfo ufs_idinfo = -{ - .name = "ufs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_ufs, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/ultrix.c b/libblkid/ultrix.c deleted file mode 100644 index 853ae6eed..000000000 --- a/libblkid/ultrix.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * uktrix partition parsing code - * - * Copyright (C) 2010 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -#define ULTRIX_MAXPARTITIONS 8 - -#define ULTRIX_MAGIC 0x032957 -#define ULTRIX_MAGIC_STR "\x02\x29\x57" - -/* sector with partition table */ -#define ULTRIX_SECTOR ((16384 - sizeof(struct ultrix_disklabel)) >> 9) -/* position of partition table within ULTRIX_SECTOR */ -#define ULTRIX_OFFSET (512 - sizeof(struct ultrix_disklabel)) - -struct ultrix_disklabel { - int32_t pt_magic; /* magic no. indicating part. info exits */ - int32_t pt_valid; /* set by driver if pt is current */ - struct pt_info { - int32_t pi_nblocks; /* no. of sectors */ - uint32_t pi_blkoff; /* block offset for start */ - } pt_part[ULTRIX_MAXPARTITIONS]; -} __attribute__((packed)); - - -static int probe_ultrix_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - unsigned char *data; - struct ultrix_disklabel *l; - blkid_parttable tab = NULL; - blkid_partlist ls; - int i; - - data = blkid_probe_get_sector(pr, ULTRIX_SECTOR); - if (!data) - goto nothing; - - l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET); - - if (l->pt_magic != ULTRIX_MAGIC || l->pt_valid != 1) - goto nothing; - - if (blkid_probe_set_magic(pr, (ULTRIX_SECTOR << 9) + ULTRIX_OFFSET, - sizeof(ULTRIX_MAGIC_STR) - 1, - (unsigned char *) ULTRIX_MAGIC_STR)) - goto err; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - tab = blkid_partlist_new_parttable(ls, "ultrix", 0); - if (!tab) - goto err; - - for (i = 0; i < ULTRIX_MAXPARTITIONS; i++) { - if (!l->pt_part[i].pi_nblocks) - blkid_partlist_increment_partno(ls); - else { - if (!blkid_partlist_add_partition(ls, tab, - l->pt_part[i].pi_blkoff, - l->pt_part[i].pi_nblocks)) - goto err; - } - } - - return 0; -nothing: - return 1; -err: - return -1; -} - -const struct blkid_idinfo ultrix_pt_idinfo = -{ - .name = "ultrix", - .probefunc = probe_ultrix_pt, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/libblkid/unixware.c b/libblkid/unixware.c deleted file mode 100644 index e9bcba358..000000000 --- a/libblkid/unixware.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * unixware partition parsing code - * - * Copyright (C) 2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * - * The intersting information about unixware PT: - * - Linux kernel / partx - * - vtoc(7) SCO UNIX command man page - * - evms source code (http://evms.sourceforge.net/) - * - vxtools source code (http://martin.hinner.info/fs/vxfs/) - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> - -#include "partitions.h" - -/* disklabel location */ -#define UNIXWARE_SECTOR 29 -#define UNIXWARE_OFFSET (UNIXWARE_SECTOR << 9) /* offset in bytes */ -#define UNIXWARE_KBOFFSET (UNIXWARE_OFFSET >> 10) /* offset in 1024-blocks */ - -/* disklabel->d_magic offset within the last 1024 block */ -#define UNIXWARE_MAGICOFFSET (UNIXWARE_OFFSET - UNIXWARE_KBOFFSET + 4) - -#define UNIXWARE_VTOCMAGIC 0x600DDEEEUL -#define UNIXWARE_MAXPARTITIONS 16 - -/* unixware_partition->s_label flags */ -#define UNIXWARE_TAG_UNUSED 0x0000 /* unused partition */ -#define UNIXWARE_TAG_BOOT 0x0001 /* boot fs */ -#define UNIXWARE_TAG_ROOT 0x0002 /* root fs */ -#define UNIXWARE_TAG_SWAP 0x0003 /* swap fs */ -#define UNIXWARE_TAG_USER 0x0004 /* user fs */ -#define UNIXWARE_TAG_ENTIRE_DISK 0x0005 /* whole disk */ -#define UNIXWARE_TAG_ALT_S 0x0006 /* alternate sector space */ -#define UNIXWARE_TAG_OTHER 0x0007 /* non unix */ -#define UNIXWARE_TAG_ALT_T 0x0008 /* alternate track space */ -#define UNIXWARE_TAG_STAND 0x0009 /* stand partition */ -#define UNIXWARE_TAG_VAR 0x000a /* var partition */ -#define UNIXWARE_TAG_HOME 0x000b /* home partition */ -#define UNIXWARE_TAG_DUMP 0x000c /* dump partition */ -#define UNIXWARE_TAG_ALT_ST 0x000d /* alternate sector track */ -#define UNIXWARE_TAG_VM_PUBLIC 0x000e /* volume mgt public partition */ -#define UNIXWARE_TAG_VM_PRIVATE 0x000f /* volume mgt private partition */ - - -/* unixware_partition->s_flags flags */ -#define UNIXWARE_FLAG_VALID 0x0200 - -struct unixware_partition { - uint16_t s_label; /* partition label (tag) */ - uint16_t s_flags; /* permission flags */ - uint32_t start_sect; /* starting sector */ - uint32_t nr_sects; /* number of sectors */ -} __attribute__((packed)); - -struct unixware_disklabel { - uint32_t d_type; /* drive type */ - uint32_t d_magic; /* the magic number */ - uint32_t d_version; /* version number */ - char d_serial[12]; /* serial number of the device */ - uint32_t d_ncylinders; /* # of data cylinders per device */ - uint32_t d_ntracks; /* # of tracks per cylinder */ - uint32_t d_nsectors; /* # of data sectors per track */ - uint32_t d_secsize; /* # of bytes per sector */ - uint32_t d_part_start; /* # of first sector of this partition */ - uint32_t d_unknown1[12]; /* ? */ - uint32_t d_alt_tbl; /* byte offset of alternate table */ - uint32_t d_alt_len; /* byte length of alternate table */ - uint32_t d_phys_cyl; /* # of physical cylinders per device */ - uint32_t d_phys_trk; /* # of physical tracks per cylinder */ - uint32_t d_phys_sec; /* # of physical sectors per track */ - uint32_t d_phys_bytes; /* # of physical bytes per sector */ - uint32_t d_unknown2; /* ? */ - uint32_t d_unknown3; /* ? */ - uint32_t d_pad[8]; /* pad */ - - struct unixware_vtoc { - uint32_t v_magic; /* the magic number */ - uint32_t v_version; /* version number */ - char v_name[8]; /* volume name */ - uint16_t v_nslices; /* # of partitions */ - uint16_t v_unknown1; /* ? */ - uint32_t v_reserved[10]; /* reserved */ - - struct unixware_partition - v_slice[UNIXWARE_MAXPARTITIONS]; /* partition */ - } __attribute__((packed)) vtoc; -}; - -static int probe_unixware_pt(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - struct unixware_disklabel *l; - struct unixware_partition *p; - blkid_parttable tab = NULL; - blkid_partition parent; - blkid_partlist ls; - int i; - - l = (struct unixware_disklabel *) - blkid_probe_get_sector(pr, UNIXWARE_SECTOR); - if (!l) - goto nothing; - - if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC) - goto nothing; - - if (blkid_partitions_need_typeonly(pr)) - /* caller does not ask for details about partitions */ - return 0; - - ls = blkid_probe_get_partlist(pr); - if (!ls) - goto err; - - parent = blkid_partlist_get_parent(ls); - - tab = blkid_partlist_new_parttable(ls, "unixware", UNIXWARE_OFFSET); - if (!tab) - goto err; - - /* Skip the first partition that describe whole disk - */ - for (i = 1, p = &l->vtoc.v_slice[1]; - i < UNIXWARE_MAXPARTITIONS; i++, p++) { - - uint32_t start, size; - uint16_t tag, flg; - blkid_partition par; - - tag = le16_to_cpu(p->s_label); - flg = le16_to_cpu(p->s_flags); - - if (tag == UNIXWARE_TAG_UNUSED || - tag == UNIXWARE_TAG_ENTIRE_DISK || - flg != UNIXWARE_FLAG_VALID) - continue; - - start = le32_to_cpu(p->start_sect); - size = le32_to_cpu(p->nr_sects); - - if (parent && !blkid_is_nested_dimension(parent, start, size)) { - DBG(DEBUG_LOWPROBE, printf( - "WARNING: unixware partition (%d) overflow " - "detected, ignore\n", i)); - continue; - } - - par = blkid_partlist_add_partition(ls, tab, start, size); - if (!par) - goto err; - - blkid_partition_set_type(par, tag); - blkid_partition_set_flags(par, flg); - } - - return 0; - -nothing: - return 1; -err: - return -1; -} - - -/* - * The unixware partition table is within primary DOS partition. The PT is - * located on 29 sector, PT magic string is d_magic member of 'struct - * unixware_disklabel'. - */ -const struct blkid_idinfo unixware_pt_idinfo = -{ - .name = "unixware", - .probefunc = probe_unixware_pt, - .minsz = 1024 * 1440 + 1, /* ignore floppies */ - .magics = - { - { - .magic = "\x0D\x60\xE5\xCA", /* little-endian magic string */ - .len = 4, /* d_magic size in bytes */ - .kboff = UNIXWARE_KBOFFSET, - .sboff = UNIXWARE_MAGICOFFSET - }, - { NULL } - } -}; - diff --git a/libblkid/verify.c b/libblkid/verify.c deleted file mode 100644 index bd756e7a7..000000000 --- a/libblkid/verify.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <sys/time.h> -#include <sys/types.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include "blkidP.h" - -static void blkid_probe_to_tags(blkid_probe pr, blkid_dev dev) -{ - const char *data; - const char *name; - int nvals, n; - size_t len; - - nvals = blkid_probe_numof_values(pr); - - for (n = 0; n < nvals; n++) { - if (blkid_probe_get_value(pr, n, &name, &data, &len) != 0) - continue; - if (strncmp(name, "PART_ENTRY_", 11) == 0) { - if (strcmp(name, "PART_ENTRY_UUID") == 0) - blkid_set_tag(dev, "PARTUUID", data, len); - else if (strcmp(name, "PART_ENTRY_NAME") == 0) - blkid_set_tag(dev, "PARTLABEL", data, len); - - } else if (!strstr(name, "_ID")) { - /* superblock UUID, LABEL, ... - * but not {SYSTEM,APPLICATION,..._ID} */ - blkid_set_tag(dev, name, data, len); - } - } -} - -/* - * Verify that the data in dev is consistent with what is on the actual - * block device (using the devname field only). Normally this will be - * called when finding items in the cache, but for long running processes - * is also desirable to revalidate an item before use. - * - * If we are unable to revalidate the data, we return the old data and - * do not set the BLKID_BID_FL_VERIFIED flag on it. - */ -blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) -{ - blkid_tag_iterate iter; - const char *type, *value; - struct stat st; - time_t diff, now; - int fd; - - if (!dev || !cache) - return NULL; - - now = time(0); - diff = now - dev->bid_time; - - if (stat(dev->bid_name, &st) < 0) { - DBG(DEBUG_PROBE, - printf("blkid_verify: error %m (%d) while " - "trying to stat %s\n", errno, - dev->bid_name)); - open_err: - if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { - /* We don't have read permission, just return cache data. */ - DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", - dev->bid_name)); - return dev; - } - blkid_free_dev(dev); - return NULL; - } - - if (now >= dev->bid_time && -#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - (st.st_mtime < dev->bid_time || - (st.st_mtime == dev->bid_time && - st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && -#else - st.st_mtime <= dev->bid_time && -#endif - (diff < BLKID_PROBE_MIN || - (dev->bid_flags & BLKID_BID_FL_VERIFIED && - diff < BLKID_PROBE_INTERVAL))) - return dev; - -#ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - DBG(DEBUG_PROBE, - printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" - "time since last check %lu)\n", - dev->bid_name, (unsigned long)dev->bid_time, - (unsigned long)st.st_mtime, (unsigned long)diff)); -#else - DBG(DEBUG_PROBE, - printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t" - "time since last check %lu)\n", - dev->bid_name, - (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime, - (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000, - (unsigned long)diff)); -#endif - - if (!cache->probe) { - cache->probe = blkid_new_probe(); - if (!cache->probe) { - blkid_free_dev(dev); - return NULL; - } - } - - fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC); - if (fd < 0) { - DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while " - "opening %s\n", errno, - dev->bid_name)); - goto open_err; - } - - if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { - /* failed to read the device */ - close(fd); - blkid_free_dev(dev); - return NULL; - } - - /* remove old cache info */ - iter = blkid_tag_iterate_begin(dev); - while (blkid_tag_next(iter, &type, &value) == 0) - blkid_set_tag(dev, type, NULL, 0); - blkid_tag_iterate_end(iter); - - /* enable superblocks probing */ - blkid_probe_enable_superblocks(cache->probe, TRUE); - blkid_probe_set_superblocks_flags(cache->probe, - BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | - BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE); - - /* enable partitions probing */ - blkid_probe_enable_partitions(cache->probe, TRUE); - blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS); - - /* probe */ - if (blkid_do_safeprobe(cache->probe)) { - /* found nothing or error */ - blkid_free_dev(dev); - dev = NULL; - } - - if (dev) { -#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC - struct timeval tv; - if (!gettimeofday(&tv, NULL)) { - dev->bid_time = tv.tv_sec; - dev->bid_utime = tv.tv_usec; - } else -#endif - dev->bid_time = time(0); - - dev->bid_devno = st.st_rdev; - dev->bid_flags |= BLKID_BID_FL_VERIFIED; - cache->bic_flags |= BLKID_BIC_FL_CHANGED; - - blkid_probe_to_tags(cache->probe, dev); - - DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", - dev->bid_name, (long long)st.st_rdev, dev->bid_type)); - } - - blkid_reset_probe(cache->probe); - blkid_probe_reset_superblocks_filter(cache->probe); - close(fd); - return dev; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - blkid_dev dev; - blkid_cache cache; - int ret; - - if (argc != 2) { - fprintf(stderr, "Usage: %s device\n" - "Probe a single device to determine type\n", argv[0]); - exit(1); - } - if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { - fprintf(stderr, "%s: error creating cache (%d)\n", - argv[0], ret); - exit(1); - } - dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); - if (!dev) { - printf("%s: %s has an unsupported type\n", argv[0], argv[1]); - return (1); - } - printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); - if (dev->bid_label) - printf("LABEL='%s'\n", dev->bid_label); - if (dev->bid_uuid) - printf("UUID='%s'\n", dev->bid_uuid); - - blkid_free_dev(dev); - return (0); -} -#endif diff --git a/libblkid/version.c b/libblkid/version.c deleted file mode 100644 index 9659b4c78..000000000 --- a/libblkid/version.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * version.c --- Return the version of the blkid library - * - * Copyright (C) 2004 Theodore Ts'o. - * - * %Begin-Header% - * This file may be redistributed under the terms of the GNU Lesser General - * Public License. - * %End-Header% - */ - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <string.h> -#include <stdio.h> -#include <ctype.h> - -#include "blkid.h" -#include "config.h" - -/* LIBBLKID_* defined in the global config.h */ -static const char *lib_version = LIBBLKID_VERSION; /* release version */ -static const char *lib_date = LIBBLKID_DATE; - -/** - * blkid_parse_version_string: - * @ver_string: version string (e.g. "2.16.0") - * - * Returns: release version code. - */ -int blkid_parse_version_string(const char *ver_string) -{ - const char *cp; - int version = 0; - - for (cp = ver_string; *cp; cp++) { - if (*cp == '.') - continue; - if (!isdigit(*cp)) - break; - version = (version * 10) + (*cp - '0'); - } - return version; -} - -/** - * blkid_get_library_version: - * @ver_string: returns relese version (!= SONAME version) - * @date_string: returns date - * - * Returns: release version code. - */ -int blkid_get_library_version(const char **ver_string, - const char **date_string) -{ - if (ver_string) - *ver_string = lib_version; - if (date_string) - *date_string = lib_date; - - return blkid_parse_version_string(lib_version); -} diff --git a/libblkid/vfat.c b/libblkid/vfat.c deleted file mode 100644 index 2feb818a9..000000000 --- a/libblkid/vfat.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -/* Yucky misaligned values */ -struct vfat_super_block { -/* 00*/ unsigned char vs_ignored[3]; -/* 03*/ unsigned char vs_sysid[8]; -/* 0b*/ unsigned char vs_sector_size[2]; -/* 0d*/ uint8_t vs_cluster_size; -/* 0e*/ uint16_t vs_reserved; -/* 10*/ uint8_t vs_fats; -/* 11*/ unsigned char vs_dir_entries[2]; -/* 13*/ unsigned char vs_sectors[2]; -/* 15*/ unsigned char vs_media; -/* 16*/ uint16_t vs_fat_length; -/* 18*/ uint16_t vs_secs_track; -/* 1a*/ uint16_t vs_heads; -/* 1c*/ uint32_t vs_hidden; -/* 20*/ uint32_t vs_total_sect; -/* 24*/ uint32_t vs_fat32_length; -/* 28*/ uint16_t vs_flags; -/* 2a*/ uint8_t vs_version[2]; -/* 2c*/ uint32_t vs_root_cluster; -/* 30*/ uint16_t vs_fsinfo_sector; -/* 32*/ uint16_t vs_backup_boot; -/* 34*/ uint16_t vs_reserved2[6]; -/* 40*/ unsigned char vs_unknown[3]; -/* 43*/ unsigned char vs_serno[4]; -/* 47*/ unsigned char vs_label[11]; -/* 52*/ unsigned char vs_magic[8]; -/* 5a*/ unsigned char vs_dummy2[0x1fe - 0x5a]; -/*1fe*/ unsigned char vs_pmagic[2]; -} __attribute__((packed)); - -/* Yucky misaligned values */ -struct msdos_super_block { -/* 00*/ unsigned char ms_ignored[3]; -/* 03*/ unsigned char ms_sysid[8]; -/* 0b*/ unsigned char ms_sector_size[2]; -/* 0d*/ uint8_t ms_cluster_size; -/* 0e*/ uint16_t ms_reserved; -/* 10*/ uint8_t ms_fats; -/* 11*/ unsigned char ms_dir_entries[2]; -/* 13*/ unsigned char ms_sectors[2]; /* =0 iff V3 or later */ -/* 15*/ unsigned char ms_media; -/* 16*/ uint16_t ms_fat_length; /* Sectors per FAT */ -/* 18*/ uint16_t ms_secs_track; -/* 1a*/ uint16_t ms_heads; -/* 1c*/ uint32_t ms_hidden; -/* V3 BPB */ -/* 20*/ uint32_t ms_total_sect; /* iff ms_sectors == 0 */ -/* V4 BPB */ -/* 24*/ unsigned char ms_unknown[3]; /* Phys drive no., resvd, V4 sig (0x29) */ -/* 27*/ unsigned char ms_serno[4]; -/* 2b*/ unsigned char ms_label[11]; -/* 36*/ unsigned char ms_magic[8]; -/* 3e*/ unsigned char ms_dummy2[0x1fe - 0x3e]; -/*1fe*/ unsigned char ms_pmagic[2]; -} __attribute__((packed)); - -struct vfat_dir_entry { - uint8_t name[11]; - uint8_t attr; - uint16_t time_creat; - uint16_t date_creat; - uint16_t time_acc; - uint16_t date_acc; - uint16_t cluster_high; - uint16_t time_write; - uint16_t date_write; - uint16_t cluster_low; - uint32_t size; -} __attribute__((packed)); - -struct fat32_fsinfo { - uint8_t signature1[4]; - uint32_t reserved1[120]; - uint8_t signature2[4]; - uint32_t free_clusters; - uint32_t next_cluster; - uint32_t reserved2[4]; -} __attribute__((packed)); - -/* maximum number of clusters */ -#define FAT12_MAX 0xFF4 -#define FAT16_MAX 0xFFF4 -#define FAT32_MAX 0x0FFFFFF6 - -#define FAT_ATTR_VOLUME_ID 0x08 -#define FAT_ATTR_DIR 0x10 -#define FAT_ATTR_LONG_NAME 0x0f -#define FAT_ATTR_MASK 0x3f -#define FAT_ENTRY_FREE 0xe5 - -static const char *no_name = "NO NAME "; - -#define unaligned_le16(x) \ - (((unsigned char *) x)[0] + (((unsigned char *) x)[1] << 8)) - -/* - * Look for LABEL (name) in the FAT root directory. - */ -static unsigned char *search_fat_label(blkid_probe pr, - uint64_t offset, uint32_t entries) -{ - struct vfat_dir_entry *ent, *dir = NULL; - uint32_t i; - - DBG(DEBUG_LOWPROBE, - printf("\tlook for label in root-dir " - "(entries: %d, offset: %jd)\n", entries, offset)); - - if (!blkid_probe_is_tiny(pr)) { - /* large disk, read whole root directory */ - dir = (struct vfat_dir_entry *) - blkid_probe_get_buffer(pr, - offset, - (blkid_loff_t) entries * - sizeof(struct vfat_dir_entry)); - if (!dir) - return NULL; - } - - for (i = 0; i < entries; i++) { - /* - * The root directory could be relatively large (4-16kB). - * Fortunately, the LABEL is usually the first entry in the - * directory. On tiny disks we call read() per entry. - */ - if (!dir) - ent = (struct vfat_dir_entry *) - blkid_probe_get_buffer(pr, - (blkid_loff_t) offset + (i * - sizeof(struct vfat_dir_entry)), - sizeof(struct vfat_dir_entry)); - else - ent = &dir[i]; - - if (!ent || ent->name[0] == 0x00) - break; - - if ((ent->name[0] == FAT_ENTRY_FREE) || - (ent->cluster_high != 0 || ent->cluster_low != 0) || - ((ent->attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) - continue; - - if ((ent->attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == - FAT_ATTR_VOLUME_ID) { - DBG(DEBUG_LOWPROBE, - printf("\tfound fs LABEL at entry %d\n", i)); - return ent->name; - } - } - return NULL; -} - -static int fat_valid_superblock(const struct blkid_idmag *mag, - struct msdos_super_block *ms, - struct vfat_super_block *vs, - uint32_t *cluster_count, uint32_t *fat_size) -{ - uint16_t sector_size, dir_entries, reserved; - uint32_t sect_count, __fat_size, dir_size, __cluster_count, fat_length; - uint32_t max_count; - - /* extra check for FATs without magic strings */ - if (mag->len <= 2) { - /* Old floppies have a valid MBR signature */ - if (ms->ms_pmagic[0] != 0x55 || ms->ms_pmagic[1] != 0xAA) - return 0; - - /* - * OS/2 and apparently DFSee will place a FAT12/16-like - * pseudo-superblock in the first 512 bytes of non-FAT - * filesystems --- at least JFS and HPFS, and possibly others. - * So we explicitly check for those filesystems at the - * FAT12/16 filesystem magic field identifier, and if they are - * present, we rule this out as a FAT filesystem, despite the - * FAT-like pseudo-header. - */ - if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || - (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) - return 0; - } - - /* fat counts(Linux kernel expects at least 1 FAT table) */ - if (!ms->ms_fats) - return 0; - if (!ms->ms_reserved) - return 0; - if (!(0xf8 <= ms->ms_media || ms->ms_media == 0xf0)) - return 0; - if (!is_power_of_2(ms->ms_cluster_size)) - return 0; - - sector_size = unaligned_le16(&ms->ms_sector_size); - if (!is_power_of_2(sector_size) || - sector_size < 512 || sector_size > 4096) - return 0; - - dir_entries = unaligned_le16(&ms->ms_dir_entries); - reserved = le16_to_cpu(ms->ms_reserved); - sect_count = unaligned_le16(&ms->ms_sectors); - - if (sect_count == 0) - sect_count = le32_to_cpu(ms->ms_total_sect); - - fat_length = le16_to_cpu(ms->ms_fat_length); - if (fat_length == 0) - fat_length = le32_to_cpu(vs->vs_fat32_length); - - __fat_size = fat_length * ms->ms_fats; - dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + - (sector_size-1)) / sector_size; - - __cluster_count = (sect_count - (reserved + __fat_size + dir_size)) / - ms->ms_cluster_size; - if (!ms->ms_fat_length && vs->vs_fat32_length) - max_count = FAT32_MAX; - else - max_count = __cluster_count > FAT12_MAX ? FAT16_MAX : FAT12_MAX; - - if (__cluster_count > max_count) - return 0; - - if (fat_size) - *fat_size = __fat_size; - if (cluster_count) - *cluster_count = __cluster_count; - - return 1; /* valid */ -} - -/* - * This function is used by MBR partition table parser to avoid - * misinterpretation of FAT filesystem. - */ -int blkid_probe_is_vfat(blkid_probe pr) -{ - struct vfat_super_block *vs; - struct msdos_super_block *ms; - const struct blkid_idmag *mag = NULL; - - if (blkid_probe_get_idmag(pr, &vfat_idinfo, NULL, &mag) || !mag) - return 0; - - ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); - if (!ms) - return 0; - vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); - if (!vs) - return 0; - - return fat_valid_superblock(mag, ms, vs, NULL, NULL); -} - -/* FAT label extraction from the root directory taken from Kay - * Sievers's volume_id library */ -static int probe_vfat(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct vfat_super_block *vs; - struct msdos_super_block *ms; - const unsigned char *vol_label = 0; - unsigned char *vol_serno = NULL, vol_label_buf[11]; - uint16_t sector_size = 0, reserved; - uint32_t cluster_count, fat_size; - const char *version = NULL; - - ms = blkid_probe_get_sb(pr, mag, struct msdos_super_block); - if (!ms) - return 0; - vs = blkid_probe_get_sb(pr, mag, struct vfat_super_block); - if (!vs) - return 0; - if (!fat_valid_superblock(mag, ms, vs, &cluster_count, &fat_size)) - return 1; - - sector_size = unaligned_le16(&ms->ms_sector_size); - reserved = le16_to_cpu(ms->ms_reserved); - - if (ms->ms_fat_length) { - /* the label may be an attribute in the root directory */ - uint32_t root_start = (reserved + fat_size) * sector_size; - uint32_t root_dir_entries = unaligned_le16(&vs->vs_dir_entries); - - vol_label = search_fat_label(pr, root_start, root_dir_entries); - if (vol_label) { - memcpy(vol_label_buf, vol_label, 11); - vol_label = vol_label_buf; - } - - if (!vol_label || !memcmp(vol_label, no_name, 11)) - vol_label = ms->ms_label; - vol_serno = ms->ms_serno; - - blkid_probe_set_value(pr, "SEC_TYPE", (unsigned char *) "msdos", - sizeof("msdos")); - - if (cluster_count < FAT12_MAX) - version = "FAT12"; - else if (cluster_count < FAT16_MAX) - version = "FAT16"; - - } else if (vs->vs_fat32_length) { - unsigned char *buf; - uint16_t fsinfo_sect; - int maxloop = 100; - - /* Search the FAT32 root dir for the label attribute */ - uint32_t buf_size = vs->vs_cluster_size * sector_size; - uint32_t start_data_sect = reserved + fat_size; - uint32_t entries = le32_to_cpu(vs->vs_fat32_length) * - sector_size / sizeof(uint32_t); - uint32_t next = le32_to_cpu(vs->vs_root_cluster); - - while (next && next < entries && --maxloop) { - uint32_t next_sect_off; - uint64_t next_off, fat_entry_off; - int count; - - next_sect_off = (next - 2) * vs->vs_cluster_size; - next_off = (uint64_t)(start_data_sect + next_sect_off) * - sector_size; - - count = buf_size / sizeof(struct vfat_dir_entry); - - vol_label = search_fat_label(pr, next_off, count); - if (vol_label) { - memcpy(vol_label_buf, vol_label, 11); - vol_label = vol_label_buf; - break; - } - - /* get FAT entry */ - fat_entry_off = ((uint64_t) reserved * sector_size) + - (next * sizeof(uint32_t)); - buf = blkid_probe_get_buffer(pr, fat_entry_off, buf_size); - if (buf == NULL) - break; - - /* set next cluster */ - next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff; - } - - version = "FAT32"; - - if (!vol_label || !memcmp(vol_label, no_name, 11)) - vol_label = vs->vs_label; - vol_serno = vs->vs_serno; - - /* - * FAT32 should have a valid signature in the fsinfo block, - * but also allow all bytes set to '\0', because some volumes - * do not set the signature at all. - */ - fsinfo_sect = le16_to_cpu(vs->vs_fsinfo_sector); - if (fsinfo_sect) { - struct fat32_fsinfo *fsinfo; - - buf = blkid_probe_get_buffer(pr, - (blkid_loff_t) fsinfo_sect * sector_size, - sizeof(struct fat32_fsinfo)); - if (buf == NULL) - return -1; - - fsinfo = (struct fat32_fsinfo *) buf; - if (memcmp(fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0 && - memcmp(fsinfo->signature1, "\x52\x52\x64\x41", 4) != 0 && - memcmp(fsinfo->signature1, "\x00\x00\x00\x00", 4) != 0) - return -1; - if (memcmp(fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0 && - memcmp(fsinfo->signature2, "\x00\x00\x00\x00", 4) != 0) - return -1; - } - } - - if (vol_label && memcmp(vol_label, no_name, 11)) - blkid_probe_set_label(pr, (unsigned char *) vol_label, 11); - - /* We can't just print them as %04X, because they are unaligned */ - if (vol_serno) - blkid_probe_sprintf_uuid(pr, vol_serno, 4, "%02X%02X-%02X%02X", - vol_serno[3], vol_serno[2], vol_serno[1], vol_serno[0]); - if (version) - blkid_probe_set_version(pr, version); - - return 0; -} - - -const struct blkid_idinfo vfat_idinfo = -{ - .name = "vfat", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_vfat, - .magics = - { - { .magic = "MSWIN", .len = 5, .sboff = 0x52 }, - { .magic = "FAT32 ", .len = 8, .sboff = 0x52 }, - { .magic = "MSDOS", .len = 5, .sboff = 0x36 }, - { .magic = "FAT16 ", .len = 8, .sboff = 0x36 }, - { .magic = "FAT12 ", .len = 8, .sboff = 0x36 }, - { .magic = "FAT ", .len = 8, .sboff = 0x36 }, - { .magic = "\353", .len = 1, }, - { .magic = "\351", .len = 1, }, - { .magic = "\125\252", .len = 2, .sboff = 0x1fe }, - { NULL } - } -}; - diff --git a/libblkid/via_raid.c b/libblkid/via_raid.c deleted file mode 100644 index eba7e4bf2..000000000 --- a/libblkid/via_raid.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * Inspired by libvolume_id by - * Kay Sievers <kay.sievers@vrfy.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -struct via_metadata { - uint16_t signature; - uint8_t version_number; - struct via_array { - uint16_t disk_bit_mask; - uint8_t disk_array_ex; - uint32_t capacity_low; - uint32_t capacity_high; - uint32_t serial_checksum; - } __attribute__((packed)) array; - uint32_t serial_checksum[8]; - uint8_t checksum; -} __attribute__((packed)); - -#define VIA_SIGNATURE 0xAA55 - -/* 8 bit checksum on first 50 bytes of metadata. */ -static uint8_t via_checksum(struct via_metadata *v) -{ - uint8_t i = 50, cs = 0; - - while (i--) - cs += ((uint8_t*) v)[i]; - - return cs == v->checksum; -} - -static int probe_viaraid(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t off; - struct via_metadata *v; - - if (pr->size < 0x10000) - return -1; - if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr)) - return -1; - - off = ((pr->size / 0x200)-1) * 0x200; - - v = (struct via_metadata *) - blkid_probe_get_buffer(pr, - off, - sizeof(struct via_metadata)); - if (!v) - return -1; - if (le16_to_cpu(v->signature) != VIA_SIGNATURE) - return -1; - if (v->version_number > 2) - return -1; - if (!via_checksum(v)) - return -1; - if (blkid_probe_sprintf_version(pr, "%u", v->version_number) != 0) - return -1; - if (blkid_probe_set_magic(pr, off, - sizeof(v->signature), - (unsigned char *) &v->signature)) - return -1; - return 0; -} - -const struct blkid_idinfo viaraid_idinfo = { - .name = "via_raid_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_viaraid, - .magics = BLKID_NONE_MAGIC -}; - - diff --git a/libblkid/vmfs.c b/libblkid/vmfs.c deleted file mode 100644 index ead09a8d1..000000000 --- a/libblkid/vmfs.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2009 Mike Hommey <mh@glandium.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#include "superblocks.h" - -struct vmfs_fs_info { - uint32_t magic; - uint32_t volume_version; - uint8_t version; - uint8_t uuid[16]; - uint32_t mode; - char label[128]; -} __attribute__ ((__packed__)); - -struct vmfs_volume_info { - uint32_t magic; - uint32_t ver; - uint8_t irrelevant[122]; - uint8_t uuid[16]; -} __attribute__ ((__packed__)); - -static int probe_vmfs_fs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct vmfs_fs_info *header; - - header = blkid_probe_get_sb(pr, mag, struct vmfs_fs_info); - if (header == NULL) - return -1; - - blkid_probe_sprintf_uuid(pr, (unsigned char *) header->uuid, 16, - "%02x%02x%02x%02x-%02x%02x%02x%02x-" - "%02x%02x-%02x%02x%02x%02x%02x%02x", - header->uuid[3], header->uuid[2], header->uuid[1], - header->uuid[0], header->uuid[7], header->uuid[6], - header->uuid[5], header->uuid[4], header->uuid[9], - header->uuid[8], header->uuid[10], header->uuid[11], - header->uuid[12], header->uuid[13], header->uuid[14], - header->uuid[15]); - - blkid_probe_set_label(pr, (unsigned char *) header->label, - sizeof(header->label)); - blkid_probe_sprintf_version(pr, "%u", header->version); - return 0; -} - -static int probe_vmfs_volume(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct vmfs_volume_info *header; - unsigned char *lvm_uuid; - - header = blkid_probe_get_sb(pr, mag, struct vmfs_volume_info); - if (header == NULL) - return -1; - - blkid_probe_sprintf_value(pr, "UUID_SUB", - "%02x%02x%02x%02x-%02x%02x%02x%02x-" - "%02x%02x-%02x%02x%02x%02x%02x%02x", - header->uuid[3], header->uuid[2], header->uuid[1], - header->uuid[0], header->uuid[7], header->uuid[6], - header->uuid[5], header->uuid[4], header->uuid[9], - header->uuid[8], header->uuid[10], header->uuid[11], - header->uuid[12], header->uuid[13], header->uuid[14], - header->uuid[15]); - blkid_probe_sprintf_version(pr, "%u", le32_to_cpu(header->ver)); - - lvm_uuid = blkid_probe_get_buffer(pr, - 1024 * 1024 /* Start of the volume info */ - + 512 /* Offset to lvm info */ - + 20 /* Offset in lvm info */, 35); - if (lvm_uuid) - blkid_probe_strncpy_uuid(pr, lvm_uuid, 35); - - return 0; -} - -const struct blkid_idinfo vmfs_fs_idinfo = -{ - .name = "VMFS", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_vmfs_fs, - .magics = - { - { .magic = "\x5e\xf1\xab\x2f", .len = 4, .kboff = 2048 }, - { NULL } - } -}; - -const struct blkid_idinfo vmfs_volume_idinfo = -{ - .name = "VMFS_volume_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_vmfs_volume, - .magics = - { - { .magic = "\x0d\xd0\x01\xc0", .len = 4, .kboff = 1024 }, - { NULL } - } -}; diff --git a/libblkid/vxfs.c b/libblkid/vxfs.c deleted file mode 100644 index fdab85a72..000000000 --- a/libblkid/vxfs.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> - -#include "superblocks.h" - -struct vxfs_super_block { - uint32_t vs_magic; - int32_t vs_version; -}; - -static int probe_vxfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct vxfs_super_block *vxs; - - vxs = blkid_probe_get_sb(pr, mag, struct vxfs_super_block); - if (!vxs) - return -1; - - blkid_probe_sprintf_version(pr, "%u", (unsigned int) vxs->vs_version); - return 0; -} - - -const struct blkid_idinfo vxfs_idinfo = -{ - .name = "vxfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_vxfs, - .magics = - { - { .magic = "\365\374\001\245", .len = 4, .kboff = 1 }, - { NULL } - } -}; - diff --git a/libblkid/wholedisk.c b/libblkid/wholedisk.c deleted file mode 100644 index 1dbb90c5c..000000000 --- a/libblkid/wholedisk.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * No copyright is claimed. This code is in the public domain; do with - * it what you wish. - * - * Written by Karel Zak <kzak@redhat.com> - */ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> - -#include "blkdev.h" -#include "wholedisk.h" - -int is_whole_disk_fd(int fd, const char *name) -{ -#ifdef HDIO_GETGEO - if (fd != -1) { - struct hd_geometry geometry; - int i = ioctl(fd, HDIO_GETGEO, &geometry); - if (i == 0) - return geometry.start == 0; - } -#endif - /* - * The "silly heuristic" is still sexy for us, because - * for example Xen doesn't implement HDIO_GETGEO for virtual - * block devices (/dev/xvda). - * - * -- kzak@redhat.com (23-Feb-2006) - */ - while (*name) - name++; - return !isdigit(name[-1]); -} - -int is_whole_disk(const char *name) -{ - int fd = -1, res = 0; -#ifdef HDIO_GETGEO - fd = open(name, O_RDONLY); - if (fd != -1) -#endif - res = is_whole_disk_fd(fd, name); - - if (fd != -1) - close(fd); - return res; -} - -#ifdef TEST_PROGRAM -int main(int argc, char **argv) -{ - if (argc < 2) { - fprintf(stderr, "usage: %s <device>\n", argv[0]); - exit(EXIT_FAILURE); - } - - printf("%s: is%s whole disk\n", argv[1], - is_whole_disk(argv[1]) ? "" : " NOT"); - exit(EXIT_SUCCESS); -} -#endif diff --git a/libblkid/wholedisk.h b/libblkid/wholedisk.h deleted file mode 100644 index 251479e76..000000000 --- a/libblkid/wholedisk.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef WHOLEDISK_H -#define WHOLEDISK_H - -extern int is_whole_disk(const char *name); -extern int is_whole_disk_fd(int fd, const char *name); - -#endif /* WHOLEDISK_H */ - diff --git a/libblkid/xalloc.h b/libblkid/xalloc.h deleted file mode 100644 index 7b685e718..000000000 --- a/libblkid/xalloc.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - * - * General memory allocation wrappers for malloc, realloc, calloc and strdup - */ - -#ifndef UTIL_LINUX_XALLOC_H -#define UTIL_LINUX_XALLOC_H - -#include <stdlib.h> -#include <string.h> - -#include "c.h" - -#ifndef XALLOC_EXIT_CODE -# define XALLOC_EXIT_CODE EXIT_FAILURE -#endif - -static inline __ul_alloc_size(1) -void *xmalloc(const size_t size) -{ - void *ret = malloc(size); - - if (!ret && size) - err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); - return ret; -} - -static inline __ul_alloc_size(2) -void *xrealloc(void *ptr, const size_t size) -{ - void *ret = realloc(ptr, size); - - if (!ret && size) - err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); - return ret; -} - -static inline __ul_calloc_size(1, 2) -void *xcalloc(const size_t nelems, const size_t size) -{ - void *ret = calloc(nelems, size); - - if (!ret && size && nelems) - err(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size); - return ret; -} - -static inline char *xstrdup(const char *str) -{ - char *ret; - - if (!str) - return NULL; - - ret = strdup(str); - - if (!ret) - err(XALLOC_EXIT_CODE, "cannot duplicate string"); - return ret; -} - -static inline int __attribute__ ((__format__(printf, 2, 3))) - xasprintf(char **strp, const char *fmt, ...) -{ - int ret; - va_list args; - va_start(args, fmt); - ret = vasprintf(&(*strp), fmt, args); - va_end(args); - if (ret < 0) - err(XALLOC_EXIT_CODE, "cannot allocate string"); - return ret; -} - - -static inline char *xgethostname(void) -{ - char *name; - size_t sz = get_hostname_max() + 1; - - name = xmalloc(sizeof(char) * sz); - if (gethostname(name, sz) != 0) - return NULL; - - name[sz - 1] = '\0'; - return name; -} - -#endif diff --git a/libblkid/xfs.c b/libblkid/xfs.c deleted file mode 100644 index 1399fe13a..000000000 --- a/libblkid/xfs.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o - * Copyright (C) 2001 by Andreas Dilger - * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2008 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <stdint.h> - -#include "superblocks.h" - -struct xfs_super_block { - unsigned char xs_magic[4]; - uint32_t xs_blocksize; - uint64_t xs_dblocks; - uint64_t xs_rblocks; - uint32_t xs_dummy1[2]; - unsigned char xs_uuid[16]; - uint32_t xs_dummy2[15]; - char xs_fname[12]; - uint32_t xs_dummy3[2]; - uint64_t xs_icount; - uint64_t xs_ifree; - uint64_t xs_fdblocks; -} __attribute__((packed)); - -static int probe_xfs(blkid_probe pr, const struct blkid_idmag *mag) -{ - struct xfs_super_block *xs; - - xs = blkid_probe_get_sb(pr, mag, struct xfs_super_block); - if (!xs) - return -1; - - if (strlen(xs->xs_fname)) - blkid_probe_set_label(pr, (unsigned char *) xs->xs_fname, - sizeof(xs->xs_fname)); - blkid_probe_set_uuid(pr, xs->xs_uuid); - return 0; -} - -const struct blkid_idinfo xfs_idinfo = -{ - .name = "xfs", - .usage = BLKID_USAGE_FILESYSTEM, - .probefunc = probe_xfs, - .magics = - { - { .magic = "XFSB", .len = 4 }, - { NULL } - } -}; - diff --git a/libblkid/xgetpass.c b/libblkid/xgetpass.c deleted file mode 100644 index ba2089470..000000000 --- a/libblkid/xgetpass.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * A function to read the passphrase either from the terminal or from - * an open file descriptor. - * - * Public domain. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/stat.h> - -#include "c.h" -#include "xgetpass.h" - -char *xgetpass(int pfd, const char *prompt) -{ - char *pass = NULL; - int len = 0, i; - - if (pfd < 0) /* terminal */ - return getpass(prompt); - - for (i=0; ; i++) { - if (i >= len-1) { - char *tmppass = pass; - len += 128; - - pass = realloc(tmppass, len); - if (!pass) { - pass = tmppass; /* the old buffer hasn't changed */ - break; - } - } - if (pass && (read(pfd, pass + i, 1) != 1 || - pass[i] == '\n' || pass[i] == 0)) - break; - } - - if (pass) - pass[i] = '\0'; - return pass; -} - diff --git a/libblkid/xgetpass.h b/libblkid/xgetpass.h deleted file mode 100644 index b5a3c87de..000000000 --- a/libblkid/xgetpass.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UTIL_LINUX_XGETPASS_H -#define UTIL_LINUX_XGETPASS_H - -extern char *xgetpass(int pfd, const char *prompt); - -#endif /* UTIL_LINUX_XGETPASS_H */ diff --git a/libblkid/zfs.c b/libblkid/zfs.c deleted file mode 100644 index b96c5df45..000000000 --- a/libblkid/zfs.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2009-2010 by Andreas Dilger <adilger@sun.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <inttypes.h> - -#include "superblocks.h" - -#define VDEV_LABEL_UBERBLOCK (128 * 1024ULL) -#define VDEV_LABEL_NVPAIR ( 16 * 1024ULL) -#define VDEV_LABEL_SIZE (256 * 1024ULL) - -/* #include <sys/uberblock_impl.h> */ -#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ -struct zfs_uberblock { - uint64_t ub_magic; /* UBERBLOCK_MAGIC */ - uint64_t ub_version; /* SPA_VERSION */ - uint64_t ub_txg; /* txg of last sync */ - uint64_t ub_guid_sum; /* sum of all vdev guids */ - uint64_t ub_timestamp; /* UTC time of last sync */ - char ub_rootbp; /* MOS objset_phys_t */ -} __attribute__((packed)); - -#define ZFS_TRIES 64 -#define ZFS_WANT 4 - -#define DATA_TYPE_UINT64 8 -#define DATA_TYPE_STRING 9 - -struct nvpair { - uint32_t nvp_size; - uint32_t nvp_unkown; - uint32_t nvp_namelen; - char nvp_name[0]; /* aligned to 4 bytes */ - /* aligned ptr array for string arrays */ - /* aligned array of data for value */ -}; - -struct nvstring { - uint32_t nvs_type; - uint32_t nvs_elem; - uint32_t nvs_strlen; - unsigned char nvs_string[0]; -}; - -struct nvuint64 { - uint32_t nvu_type; - uint32_t nvu_elem; - uint64_t nvu_value; -}; - -struct nvlist { - uint32_t nvl_unknown[3]; - struct nvpair nvl_nvpair; -}; - -#define nvdebug(fmt, ...) do { } while(0) -/*#define nvdebug(fmt, a...) printf(fmt, ##a)*/ - -static void zfs_extract_guid_name(blkid_probe pr, loff_t offset) -{ - struct nvlist *nvl; - struct nvpair *nvp; - size_t left = 4096; - int found = 0; - - offset = (offset & ~(VDEV_LABEL_SIZE - 1)) + VDEV_LABEL_NVPAIR; - - /* Note that we currently assume that the desired fields are within - * the first 4k (left) of the nvlist. This is true for all pools - * I've seen, and simplifies this code somewhat, because we don't - * have to handle an nvpair crossing a buffer boundary. */ - nvl = (struct nvlist *)blkid_probe_get_buffer(pr, offset, left); - if (nvl == NULL) - return; - - nvdebug("zfs_extract: nvlist offset %llu\n", offset); - - nvp = &nvl->nvl_nvpair; - while (left > sizeof(*nvp) && nvp->nvp_size != 0 && found < 3) { - int avail; /* tracks that name/value data fits in nvp_size */ - int namesize; - - nvp->nvp_size = be32_to_cpu(nvp->nvp_size); - nvp->nvp_namelen = be32_to_cpu(nvp->nvp_namelen); - avail = nvp->nvp_size - nvp->nvp_namelen - sizeof(*nvp); - - nvdebug("left %zd nvp_size %u\n", left, nvp->nvp_size); - if (left < nvp->nvp_size || avail < 0) - break; - - namesize = (nvp->nvp_namelen + 3) & ~3; - - nvdebug("nvlist: size %u, namelen %u, name %*s\n", - nvp->nvp_size, nvp->nvp_namelen, nvp->nvp_namelen, - nvp->nvp_name); - if (strncmp(nvp->nvp_name, "name", nvp->nvp_namelen) == 0) { - struct nvstring *nvs = (void *)(nvp->nvp_name+namesize); - - nvs->nvs_type = be32_to_cpu(nvs->nvs_type); - nvs->nvs_strlen = be32_to_cpu(nvs->nvs_strlen); - avail -= nvs->nvs_strlen + sizeof(*nvs); - nvdebug("nvstring: type %u string %*s\n", nvs->nvs_type, - nvs->nvs_strlen, nvs->nvs_string); - if (nvs->nvs_type == DATA_TYPE_STRING && avail >= 0) - blkid_probe_set_label(pr, nvs->nvs_string, - nvs->nvs_strlen); - found++; - } else if (strncmp(nvp->nvp_name, "guid", - nvp->nvp_namelen) == 0) { - struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); - uint64_t nvu_value; - - memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); - nvu->nvu_type = be32_to_cpu(nvu->nvu_type); - nvu_value = be64_to_cpu(nvu_value); - avail -= sizeof(*nvu); - nvdebug("nvuint64: type %u value %"PRIu64"\n", - nvu->nvu_type, nvu_value); - if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) - blkid_probe_sprintf_value(pr, "UUID_SUB", - "%"PRIu64, nvu_value); - found++; - } else if (strncmp(nvp->nvp_name, "pool_guid", - nvp->nvp_namelen) == 0) { - struct nvuint64 *nvu = (void *)(nvp->nvp_name+namesize); - uint64_t nvu_value; - - memcpy(&nvu_value, &nvu->nvu_value, sizeof(nvu_value)); - nvu->nvu_type = be32_to_cpu(nvu->nvu_type); - nvu_value = be64_to_cpu(nvu_value); - avail -= sizeof(*nvu); - nvdebug("nvuint64: type %u value %"PRIu64"\n", - nvu->nvu_type, nvu_value); - if (nvu->nvu_type == DATA_TYPE_UINT64 && avail >= 0) - blkid_probe_sprintf_uuid(pr, (unsigned char *) - &nvu_value, - sizeof(nvu_value), - "%"PRIu64, nvu_value); - found++; - } - if (left > nvp->nvp_size) - left -= nvp->nvp_size; - else - left = 0; - nvp = (struct nvpair *)((char *)nvp + nvp->nvp_size); - } -} - -#define zdebug(fmt, ...) do {} while(0) -/*#define zdebug(fmt, a...) printf(fmt, ##a)*/ - -/* ZFS has 128x1kB host-endian root blocks, stored in 2 areas at the start - * of the disk, and 2 areas at the end of the disk. Check only some of them... - * #4 (@ 132kB) is the first one written on a new filesystem. */ -static int probe_zfs(blkid_probe pr, - const struct blkid_idmag *mag __attribute__((__unused__))) -{ - uint64_t swab_magic = swab64(UBERBLOCK_MAGIC); - struct zfs_uberblock *ub; - int swab_endian; - loff_t offset; - int tried; - int found; - - zdebug("probe_zfs\n"); - /* Look for at least 4 uberblocks to ensure a positive match */ - for (tried = found = 0, offset = VDEV_LABEL_UBERBLOCK; - tried < ZFS_TRIES && found < ZFS_WANT; - tried++, offset += 4096) { - /* also try the second uberblock copy */ - if (tried == (ZFS_TRIES / 2)) - offset = VDEV_LABEL_SIZE + VDEV_LABEL_UBERBLOCK; - - ub = (struct zfs_uberblock *) - blkid_probe_get_buffer(pr, offset, - sizeof(struct zfs_uberblock)); - if (ub == NULL) - return -1; - - if (ub->ub_magic == UBERBLOCK_MAGIC) - found++; - - if ((swab_endian = (ub->ub_magic == swab_magic))) - found++; - - zdebug("probe_zfs: found %s-endian uberblock at %llu\n", - swab_endian ? "big" : "little", offset >> 10); - } - - if (found < 4) - return -1; - - /* If we found the 4th uberblock, then we will have exited from the - * scanning loop immediately, and ub will be a valid uberblock. */ - blkid_probe_sprintf_version(pr, "%" PRIu64, swab_endian ? - swab64(ub->ub_version) : ub->ub_version); - - zfs_extract_guid_name(pr, offset); - - if (blkid_probe_set_magic(pr, offset, - sizeof(ub->ub_magic), - (unsigned char *) &ub->ub_magic)) - return -1; - - return 0; -} - -const struct blkid_idinfo zfs_idinfo = -{ - .name = "zfs_member", - .usage = BLKID_USAGE_RAID, - .probefunc = probe_zfs, - .minsz = 64 * 1024 * 1024, - .magics = BLKID_NONE_MAGIC -}; - diff --git a/partition.cpp b/partition.cpp index 9770a5f14..8edf54a5d 100644 --- a/partition.cpp +++ b/partition.cpp @@ -31,7 +31,7 @@ #include "cutils/properties.h" #endif -#include "libblkid/blkid.h" +#include "libblkid/include/blkid.h" #include "variables.h" #include "twcommon.h" #include "partitions.hpp" @@ -2070,6 +2070,7 @@ uint64_t TWPartition::Get_Max_FileSize() { maxFileSize = 3.94 * constTB; //3.94 TB else maxFileSize = 100000000L; + LOGINFO("Get_Max_FileSize::maxFileSize: %\n", maxFileSize); return maxFileSize - 1; } diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk index d8ed87c81..86db949ac 100644 --- a/prebuilt/Android.mk +++ b/prebuilt/Android.mk @@ -38,7 +38,6 @@ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libusbhost.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgccdemangle.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutils.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libdl.so -RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_blkid.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_com_err.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2_e2p.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libext2fs.so @@ -57,6 +56,9 @@ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libminadbd.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libminzip.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmtdutils.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libtar.so +RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libutil-linux.so +RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libuuid.so +RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libfdisk.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libblkid.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmmcutils.so RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbmlutils.so |