summaryrefslogtreecommitdiff
path: root/shlibs
diff options
context:
space:
mode:
Diffstat (limited to 'shlibs')
-rw-r--r--shlibs/Makefile.am9
-rw-r--r--shlibs/blkid/Makefile.am2
-rw-r--r--shlibs/blkid/libblkid.32
-rw-r--r--shlibs/blkid/src/Makefile.am7
-rw-r--r--shlibs/blkid/src/list.h179
-rw-r--r--shlibs/blkid/src/partitions/partitions.c13
-rw-r--r--shlibs/blkid/src/probe.c16
-rw-r--r--shlibs/blkid/src/superblocks/Makefile.am4
-rw-r--r--shlibs/blkid/src/superblocks/adaptec_raid.c3
-rw-r--r--shlibs/blkid/src/superblocks/ddf_raid.c71
-rw-r--r--shlibs/blkid/src/superblocks/exfat.c146
-rw-r--r--shlibs/blkid/src/superblocks/hfs.c1
-rw-r--r--shlibs/blkid/src/superblocks/highpoint_raid.c11
-rw-r--r--shlibs/blkid/src/superblocks/isw_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/jmicron_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/linux_raid.c124
-rw-r--r--shlibs/blkid/src/superblocks/lsi_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/nilfs.c120
-rw-r--r--shlibs/blkid/src/superblocks/nvidia_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/promise_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/silicon_raid.c2
-rw-r--r--shlibs/blkid/src/superblocks/superblocks.c120
-rw-r--r--shlibs/blkid/src/superblocks/superblocks.h2
-rw-r--r--shlibs/blkid/src/superblocks/udf.c3
-rw-r--r--shlibs/blkid/src/superblocks/via_raid.c2
-rw-r--r--shlibs/blkid/src/topology/evms.c5
-rw-r--r--shlibs/blkid/src/topology/md.c4
-rw-r--r--shlibs/mount/.gitignore2
-rw-r--r--shlibs/mount/COPYING.libmount508
-rw-r--r--shlibs/mount/Makefile.am13
-rw-r--r--shlibs/mount/docs/.gitignore17
-rw-r--r--shlibs/mount/docs/Makefile.am101
-rw-r--r--shlibs/mount/docs/libmount-docs.xml60
-rw-r--r--shlibs/mount/docs/libmount-sections.txt181
-rw-r--r--shlibs/mount/docs/libmount.types0
-rw-r--r--shlibs/mount/docs/version.xml.in1
-rw-r--r--shlibs/mount/mount.pc.in11
-rw-r--r--shlibs/mount/src/Makefile.am56
-rw-r--r--shlibs/mount/src/cache.c570
-rw-r--r--shlibs/mount/src/fs.c787
-rw-r--r--shlibs/mount/src/init.c45
-rw-r--r--shlibs/mount/src/iter.c78
-rw-r--r--shlibs/mount/src/lock.c528
-rw-r--r--shlibs/mount/src/mount.h.in407
-rw-r--r--shlibs/mount/src/mount.sym134
-rw-r--r--shlibs/mount/src/mountP.h222
-rw-r--r--shlibs/mount/src/optent.c735
-rw-r--r--shlibs/mount/src/optls.c791
-rw-r--r--shlibs/mount/src/optmap.c316
-rw-r--r--shlibs/mount/src/optstr.c426
-rw-r--r--shlibs/mount/src/tab.c929
-rw-r--r--shlibs/mount/src/tab_parse.c528
-rw-r--r--shlibs/mount/src/test.c59
-rw-r--r--shlibs/mount/src/utils.c349
-rw-r--r--shlibs/mount/src/version.c86
-rw-r--r--shlibs/uuid/Makefile.am2
-rw-r--r--shlibs/uuid/man/Makefile.am4
-rw-r--r--shlibs/uuid/man/uuid_generate.32
-rw-r--r--shlibs/uuid/src/compare.c4
-rw-r--r--shlibs/uuid/src/pack.c2
60 files changed, 8478 insertions, 332 deletions
diff --git a/shlibs/Makefile.am b/shlibs/Makefile.am
deleted file mode 100644
index 3e757885..00000000
--- a/shlibs/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-SUBDIRS =
-
-if BUILD_LIBUUID
-SUBDIRS += uuid
-endif
-
-if BUILD_LIBBLKID
-SUBDIRS += blkid
-endif
diff --git a/shlibs/blkid/Makefile.am b/shlibs/blkid/Makefile.am
index 041fa79b..59362cfe 100644
--- a/shlibs/blkid/Makefile.am
+++ b/shlibs/blkid/Makefile.am
@@ -12,5 +12,5 @@ pkgconfig_DATA = blkid.pc
dist_man_MANS = libblkid.3
-EXTRA_DIST = README.blkid blkid.pc.in libblkid.3
+EXTRA_DIST = COPYING.libblkid README.blkid blkid.pc.in libblkid.3
diff --git a/shlibs/blkid/libblkid.3 b/shlibs/blkid/libblkid.3
index 46eb868b..ab4c5736 100644
--- a/shlibs/blkid/libblkid.3
+++ b/shlibs/blkid/libblkid.3
@@ -9,7 +9,7 @@
.SH NAME
libblkid \- block device identification library
.SH SYNOPSIS
-.B #include <blkid/blkid.h>
+.B #include <blkid.h>
.sp
.B cc
.I file.c
diff --git a/shlibs/blkid/src/Makefile.am b/shlibs/blkid/src/Makefile.am
index 2d798b6a..bb395c71 100644
--- a/shlibs/blkid/src/Makefile.am
+++ b/shlibs/blkid/src/Makefile.am
@@ -24,14 +24,15 @@ nodist_blkidinc_HEADERS = blkid.h
usrlib_exec_LTLIBRARIES = libblkid.la
libblkid_la_SOURCES = cache.c dev.c devname.c devno.c getsize.c llseek.c \
probe.c read.c resolve.c save.c tag.c version.c verify.c \
- encode.c list.h blkidP.h superblocks/superblocks.h \
+ encode.c blkidP.h superblocks/superblocks.h \
config.c evaluate.c fat.h \
$(blkidinc_HEADERS) \
$(top_srcdir)/lib/blkdev.c \
$(top_srcdir)/lib/linux_version.c \
$(top_srcdir)/lib/canonicalize.c \
$(top_srcdir)/lib/md5.c \
- $(top_srcdir)/lib/crc32.c
+ $(top_srcdir)/lib/crc32.c \
+ $(top_srcdir)/include/list.h
nodist_libblkid_la_SOURCES = blkid.h
@@ -45,7 +46,7 @@ libblkid_la_DEPENDENCIES = $(libblkid_la_LIBADD) blkid.sym blkid.h.in
libblkid_la_LDFLAGS = -Wl,--version-script=$(ul_libblkid_srcdir)/blkid.sym \
-version-info $(LIBBLKID_VERSION_INFO)
-tests = test_cache test_config test_dev test_devname test_devno test_getsize \
+tests = test_cache test_config test_dev test_devname test_devno \
test_read test_resolve test_save test_tag test_verify test_evaluate
EXTRA_DIST = blkid.sym tst_types.c blkid.h.in
diff --git a/shlibs/blkid/src/list.h b/shlibs/blkid/src/list.h
deleted file mode 100644
index c1cbfec5..00000000
--- a/shlibs/blkid/src/list.h
+++ /dev/null
@@ -1,179 +0,0 @@
-#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
-#define _BLKID_LIST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#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_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) \
- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-/**
- * 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_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)
-
-#undef _INLINE_
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BLKID_LIST_H */
diff --git a/shlibs/blkid/src/partitions/partitions.c b/shlibs/blkid/src/partitions/partitions.c
index c670cc18..5597181a 100644
--- a/shlibs/blkid/src/partitions/partitions.c
+++ b/shlibs/blkid/src/partitions/partitions.c
@@ -829,6 +829,19 @@ int blkid_probe_is_covered_by_pt(blkid_probe pr,
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) {
+ DBG(DEBUG_LOWPROBE, printf("partition #%d overflows "
+ "device (off=%lu size=%lu)\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];
diff --git a/shlibs/blkid/src/probe.c b/shlibs/blkid/src/probe.c
index 89c59504..200a52c5 100644
--- a/shlibs/blkid/src/probe.c
+++ b/shlibs/blkid/src/probe.c
@@ -103,6 +103,7 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#include <inttypes.h>
#include <stdint.h>
#include <stdarg.h>
@@ -542,7 +543,7 @@ unsigned char *blkid_probe_get_buffer(blkid_probe pr,
static void blkid_probe_reset_buffer(blkid_probe pr)
{
- ssize_t read_ct = 0, len_ct = 0;
+ uint64_t read_ct = 0, len_ct = 0;
if (!pr || list_empty(&pr->buffers))
return;
@@ -560,7 +561,8 @@ static void blkid_probe_reset_buffer(blkid_probe pr)
}
DBG(DEBUG_LOWPROBE,
- printf("buffers summary: %jd bytes by %jd read() call(s)\n",
+ printf("buffers summary: %"PRIu64" bytes "
+ "by %"PRIu64" read() call(s)\n",
len_ct, read_ct));
INIT_LIST_HEAD(&pr->buffers);
@@ -650,9 +652,6 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
pr->size -= pr->off;
}
- DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%jd, size=%jd\n",
- pr->off, pr->size));
-
if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode))
pr->flags |= BLKID_TINY_DEV;
@@ -660,6 +659,13 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
if (S_ISBLK(sb.st_mode) && ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
pr->flags |= BLKID_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,
diff --git a/shlibs/blkid/src/superblocks/Makefile.am b/shlibs/blkid/src/superblocks/Makefile.am
index f5b88b8e..1501fab1 100644
--- a/shlibs/blkid/src/superblocks/Makefile.am
+++ b/shlibs/blkid/src/superblocks/Makefile.am
@@ -46,4 +46,6 @@ libblkid_superblocks_la_SOURCES = \
bfs.c \
drbd.c \
vmfs.c \
- befs.c
+ befs.c \
+ nilfs.c \
+ exfat.c
diff --git a/shlibs/blkid/src/superblocks/adaptec_raid.c b/shlibs/blkid/src/superblocks/adaptec_raid.c
index 73b146c6..570e75e9 100644
--- a/shlibs/blkid/src/superblocks/adaptec_raid.c
+++ b/shlibs/blkid/src/superblocks/adaptec_raid.c
@@ -81,6 +81,9 @@ static int probe_adraid(blkid_probe pr, const struct blkid_idmag *mag)
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,
diff --git a/shlibs/blkid/src/superblocks/ddf_raid.c b/shlibs/blkid/src/superblocks/ddf_raid.c
index a48735d2..c0ba3351 100644
--- a/shlibs/blkid/src/superblocks/ddf_raid.c
+++ b/shlibs/blkid/src/superblocks/ddf_raid.c
@@ -18,12 +18,57 @@
/* http://www.snia.org/standards/home */
#define DDF_GUID_LENGTH 24
#define DDF_REV_LENGTH 8
+#define DDF_MAGIC 0xDE11DE11
+
struct ddf_header {
- uint8_t signature[4];
+ uint32_t signature;
uint32_t crc;
uint8_t guid[DDF_GUID_LENGTH];
- uint8_t ddf_rev[DDF_REV_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)
@@ -32,7 +77,7 @@ static int probe_ddf(blkid_probe pr, const struct blkid_idmag *mag)
int i;
struct ddf_header *ddf = NULL;
char version[DDF_REV_LENGTH + 1];
- uint64_t off;
+ uint64_t off, lba;
if (pr->size < 0x30000)
return -1;
@@ -46,8 +91,8 @@ static int probe_ddf(blkid_probe pr, const struct blkid_idmag *mag)
if (!ddf)
return -1;
- if (memcmp(ddf->signature, "\x11\xde\x11\xde", 4) == 0 ||
- memcmp(ddf->signature, "\xde\x11\xde\x11", 4) == 0)
+ if (ddf->signature == cpu_to_be32(DDF_MAGIC) ||
+ ddf->signature == cpu_to_le32(DDF_MAGIC))
break;
ddf = NULL;
}
@@ -55,6 +100,20 @@ static int probe_ddf(blkid_probe pr, const struct blkid_idmag *mag)
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));
@@ -64,7 +123,7 @@ static int probe_ddf(blkid_probe pr, const struct blkid_idmag *mag)
return -1;
if (blkid_probe_set_magic(pr, off,
sizeof(ddf->signature),
- (unsigned char *) ddf->signature))
+ (unsigned char *) &ddf->signature))
return -1;
return 0;
}
diff --git a/shlibs/blkid/src/superblocks/exfat.c b/shlibs/blkid/src/superblocks/exfat.c
new file mode 100644
index 00000000..bada3a83
--- /dev/null
+++ b/shlibs/blkid/src/superblocks/exfat.c
@@ -0,0 +1,146 @@
+/*
+ * 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, "%hu.%hu",
+ 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/shlibs/blkid/src/superblocks/hfs.c b/shlibs/blkid/src/superblocks/hfs.c
index 8ebff68d..033a65de 100644
--- a/shlibs/blkid/src/superblocks/hfs.c
+++ b/shlibs/blkid/src/superblocks/hfs.c
@@ -291,6 +291,7 @@ 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 },
diff --git a/shlibs/blkid/src/superblocks/highpoint_raid.c b/shlibs/blkid/src/superblocks/highpoint_raid.c
index 98343c41..25e3114b 100644
--- a/shlibs/blkid/src/superblocks/highpoint_raid.c
+++ b/shlibs/blkid/src/superblocks/highpoint_raid.c
@@ -30,6 +30,8 @@ static int probe_highpoint45x(blkid_probe pr, const struct blkid_idmag *mag)
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 *)
@@ -47,6 +49,14 @@ static int probe_highpoint45x(blkid_probe pr, const struct blkid_idmag *mag)
return 0;
}
+static int probe_highpoint37x(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ 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,
@@ -57,6 +67,7 @@ const struct blkid_idinfo highpoint45x_idinfo = {
const struct blkid_idinfo highpoint37x_idinfo = {
.name = "hpt37x_raid_member",
.usage = BLKID_USAGE_RAID,
+ .probefunc = probe_highpoint37x,
.magics = {
/*
* Superblok offset: 4608 bytes (9 sectors)
diff --git a/shlibs/blkid/src/superblocks/isw_raid.c b/shlibs/blkid/src/superblocks/isw_raid.c
index 5149c38a..ac6251d7 100644
--- a/shlibs/blkid/src/superblocks/isw_raid.c
+++ b/shlibs/blkid/src/superblocks/isw_raid.c
@@ -33,6 +33,8 @@ static int probe_iswraid(blkid_probe pr, const struct blkid_idmag *mag)
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 *)
diff --git a/shlibs/blkid/src/superblocks/jmicron_raid.c b/shlibs/blkid/src/superblocks/jmicron_raid.c
index 24430bf9..d35b17f8 100644
--- a/shlibs/blkid/src/superblocks/jmicron_raid.c
+++ b/shlibs/blkid/src/superblocks/jmicron_raid.c
@@ -32,6 +32,8 @@ static int probe_jmraid(blkid_probe pr, const struct blkid_idmag *mag)
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 *)
diff --git a/shlibs/blkid/src/superblocks/linux_raid.c b/shlibs/blkid/src/superblocks/linux_raid.c
index 6f823f15..b73214a4 100644
--- a/shlibs/blkid/src/superblocks/linux_raid.c
+++ b/shlibs/blkid/src/superblocks/linux_raid.c
@@ -34,27 +34,82 @@ struct mdp0_super_block {
uint32_t set_uuid3;
};
+/*
+ * Version-1, little-endian.
+ */
struct mdp1_super_block {
- uint32_t magic;
- uint32_t major_version;
- uint32_t feature_map;
- uint32_t pad0;
- uint8_t set_uuid[16];
- uint8_t set_name[32];
+ /* 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 upto 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, off_t off)
+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 < 0x10000)
+ if (pr->size < MD_RESERVED_BYTES)
return -1;
mdp0 = (struct mdp0_super_block *)
blkid_probe_get_buffer(pr,
@@ -72,11 +127,10 @@ static int probe_raid0(blkid_probe pr, off_t off)
uuid.ints[2] = swab32(mdp0->set_uuid2);
uuid.ints[3] = swab32(mdp0->set_uuid3);
}
- if (blkid_probe_sprintf_version(pr, "%u.%u.%u",
- le32_to_cpu(mdp0->major_version),
- le32_to_cpu(mdp0->minor_version),
- le32_to_cpu(mdp0->patch_version)) != 0)
- return -1;
+ 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;
@@ -85,14 +139,41 @@ static int probe_raid0(blkid_probe pr, off_t off)
uuid.ints[2] = mdp0->set_uuid2;
uuid.ints[3] = mdp0->set_uuid3;
}
- if (blkid_probe_sprintf_version(pr, "%u.%u.%u",
- be32_to_cpu(mdp0->major_version),
- be32_to_cpu(mdp0->minor_version),
- be32_to_cpu(mdp0->patch_version)) != 0)
- return -1;
+ 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;
+ return 1;
+
+ size <<= 10; /* convert KiB to bytes */
+
+ if (pr->size < size + MD_RESERVED_BYTES)
+ /* device is too small */
+ return 1;
+
+ if (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 possition 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),
@@ -115,8 +196,13 @@ static int probe_raid1(blkid_probe pr, off_t off)
return -1;
if (le32_to_cpu(mdp1->major_version) != 1)
return -1;
+ if (le64_to_cpu(mdp1->super_offset) != 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;
diff --git a/shlibs/blkid/src/superblocks/lsi_raid.c b/shlibs/blkid/src/superblocks/lsi_raid.c
index 3010eb6b..5217a009 100644
--- a/shlibs/blkid/src/superblocks/lsi_raid.c
+++ b/shlibs/blkid/src/superblocks/lsi_raid.c
@@ -30,6 +30,8 @@ static int probe_lsiraid(blkid_probe pr, const struct blkid_idmag *mag)
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 *)
diff --git a/shlibs/blkid/src/superblocks/nilfs.c b/shlibs/blkid/src/superblocks/nilfs.c
new file mode 100644
index 00000000..bf169182
--- /dev/null
+++ b/shlibs/blkid/src/superblocks/nilfs.c
@@ -0,0 +1,120 @@
+/*
+ * 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 = le32_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/shlibs/blkid/src/superblocks/nvidia_raid.c b/shlibs/blkid/src/superblocks/nvidia_raid.c
index e75bec84..c3db949a 100644
--- a/shlibs/blkid/src/superblocks/nvidia_raid.c
+++ b/shlibs/blkid/src/superblocks/nvidia_raid.c
@@ -32,6 +32,8 @@ static int probe_nvraid(blkid_probe pr, const struct blkid_idmag *mag)
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 *)
diff --git a/shlibs/blkid/src/superblocks/promise_raid.c b/shlibs/blkid/src/superblocks/promise_raid.c
index 1cc70e65..0e91d3c2 100644
--- a/shlibs/blkid/src/superblocks/promise_raid.c
+++ b/shlibs/blkid/src/superblocks/promise_raid.c
@@ -33,6 +33,8 @@ static int probe_pdcraid(blkid_probe pr, const struct blkid_idmag *mag)
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;
diff --git a/shlibs/blkid/src/superblocks/silicon_raid.c b/shlibs/blkid/src/superblocks/silicon_raid.c
index 11277ad6..b72b7276 100644
--- a/shlibs/blkid/src/superblocks/silicon_raid.c
+++ b/shlibs/blkid/src/superblocks/silicon_raid.c
@@ -48,6 +48,8 @@ static int probe_silraid(blkid_probe pr, const struct blkid_idmag *mag)
if (pr->size < 0x10000)
return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
off = ((pr->size / 0x200) - 1) * 0x200;
diff --git a/shlibs/blkid/src/superblocks/superblocks.c b/shlibs/blkid/src/superblocks/superblocks.c
index 1d952737..3d66d98c 100644
--- a/shlibs/blkid/src/superblocks/superblocks.c
+++ b/shlibs/blkid/src/superblocks/superblocks.c
@@ -71,7 +71,6 @@
static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn);
static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn);
-static void superblocks_free(blkid_probe pr, void *data);
static int blkid_probe_set_usage(blkid_probe pr, int usage);
@@ -140,7 +139,9 @@ static const struct blkid_idinfo *idinfos[] =
&ubifs_idinfo,
&bfs_idinfo,
&vmfs_fs_idinfo,
- &befs_idinfo
+ &befs_idinfo,
+ &nilfs2_idinfo,
+ &exfat_idinfo
};
/*
@@ -156,23 +157,8 @@ const struct blkid_chaindrv superblocks_drv = {
.has_fltr = TRUE,
.probe = superblocks_probe,
.safeprobe = superblocks_safeprobe,
- .free_data = superblocks_free
};
-/*
- * Private chain data
- *
- * TODO: export this data by binary interface (see topology.c or partitions.c
- * for more details) by blkid_probe_get_superblock() or so.
- */
-struct blkid_struct_superblock {
- blkid_loff_t magic_off; /* offset of the magic string */
- int usage;
-};
-
-/* TODO: move to blkid.h */
-typedef struct blkid_struct_superblock *blkid_superblock;
-
/**
* blkid_probe_enable_superblocks:
* @pr: probe
@@ -311,39 +297,6 @@ int blkid_known_fstype(const char *fstype)
return 0;
}
-/* init and returns private data */
-static blkid_superblock superblocks_init_data(blkid_probe pr,
- struct blkid_chain *chn)
-{
- DBG(DEBUG_LOWPROBE, printf("initialize superblocks binary data\n"));
-
- if (chn->data)
- memset(chn->data, 0,
- sizeof(struct blkid_struct_superblock));
- else {
- chn->data = calloc(1,
- sizeof(struct blkid_struct_superblock));
- if (!chn->data)
- return NULL;
- }
- return chn->data;
-}
-
-static void superblocks_free(blkid_probe pr, void *data)
-{
- free(data);
-}
-
-static blkid_superblock superblocks_copy_data(blkid_superblock dest,
- blkid_superblock src)
-{
- if (!src || !dest)
- return NULL;
-
- memcpy(dest, src, sizeof(struct blkid_struct_superblock));
- return dest;
-}
-
/*
* The blkid_do_probe() backend.
*/
@@ -365,9 +318,6 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
* is 1 byte */
goto nothing;
- if (chn->binary)
- superblocks_init_data(pr, chn);
-
i = chn->idx + 1;
for ( ; i < ARRAY_SIZE(idinfos); i++) {
@@ -472,44 +422,37 @@ nothing:
*/
static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
{
- blkid_superblock sb = NULL;
- struct blkid_struct_superblock sb_buff;
-
struct blkid_prval vals[BLKID_NVALS_SUBLKS];
int nvals = BLKID_NVALS_SUBLKS;
int idx = -1;
int count = 0;
int intol = 0;
- int rc, bin_org = chn->binary;
-
- chn->binary = TRUE;
+ int rc;
while ((rc = superblocks_probe(pr, chn)) == 0) {
- if (blkid_probe_is_tiny(pr) && !count) {
+ if (blkid_probe_is_tiny(pr) && !count)
/* floppy or so -- returns the first result. */
- chn->binary = bin_org;
return 0;
- }
- if (!count) {
- /* save the first result */
- nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
- idx = chn->idx;
- if (chn->data)
- sb = superblocks_copy_data(&sb_buff, chn->data);
- }
+
count++;
if (idinfos[chn->idx]->usage & (BLKID_USAGE_RAID | BLKID_USAGE_CRYPTO))
break;
+
if (!(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT))
intol++;
- }
- chn->binary = bin_org;
+ 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: "
@@ -520,27 +463,11 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
if (!count)
return 1; /* nothing detected */
- /* restore the first result */
- blkid_probe_chain_reset_vals(pr, chn);
- blkid_probe_append_vals(pr, vals, nvals);
- if (sb && chn->data)
- superblocks_copy_data(chn->data, sb);
- chn->idx = idx;
-
- /*
- * Check for collisions between RAID and partition table
- */
- if (sb && sb->usage == BLKID_USAGE_RAID &&
- sb->magic_off > pr->size / 2 &&
- (S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
- blkid_probe_is_covered_by_pt(pr, sb->magic_off, 0x200)) {
- /*
- * Ignore the result if the detected RAID superblock is
- * within some existing partition (for example RAID on
- * the last partition).
- */
+ if (idx != -1) {
+ /* restore the first result */
blkid_probe_chain_reset_vals(pr, chn);
- return 1;
+ blkid_probe_append_vals(pr, vals, nvals);
+ chn->idx = idx;
}
/*
@@ -548,7 +475,7 @@ static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
* where the partition table is visible from underlaying devices. We
* have to ignore such partition tables.
*/
- if (sb && sb->usage == BLKID_USAGE_RAID)
+ if (chn->idx >= 0 && idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
pr->prob_flags |= BLKID_PARTS_IGNORE_PT;
return 0;
@@ -567,10 +494,6 @@ int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset,
rc = blkid_probe_sprintf_value(pr, "SBMAGIC_OFFSET",
"%llu", offset);
}
- if (!rc && chn->data) {
- blkid_superblock sb = (blkid_superblock) chn->data;
- sb->magic_off = offset;
- }
return rc;
}
@@ -604,11 +527,6 @@ 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->data) {
- blkid_superblock sb = (blkid_superblock) chn->data;
- sb->usage = usage;
- }
-
if (!(chn->flags & BLKID_SUBLKS_USAGE))
return 0;
diff --git a/shlibs/blkid/src/superblocks/superblocks.h b/shlibs/blkid/src/superblocks/superblocks.h
index b1fa49d5..a79d7cb6 100644
--- a/shlibs/blkid/src/superblocks/superblocks.h
+++ b/shlibs/blkid/src/superblocks/superblocks.h
@@ -65,6 +65,8 @@ 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 befs_idinfo;
+extern const struct blkid_idinfo nilfs2_idinfo;
+extern const struct blkid_idinfo exfat_idinfo;
/*
* superblock functions
diff --git a/shlibs/blkid/src/superblocks/udf.c b/shlibs/blkid/src/superblocks/udf.c
index 55c96adb..78ddda68 100644
--- a/shlibs/blkid/src/superblocks/udf.c
+++ b/shlibs/blkid/src/superblocks/udf.c
@@ -136,6 +136,9 @@ anchor:
blkid_probe_set_utf8label(pr,
vd->type.primary.ident.c,
31, BLKID_ENC_UTF16BE);
+
+ if (clen == 8 || clen == 16)
+ break;
}
}
diff --git a/shlibs/blkid/src/superblocks/via_raid.c b/shlibs/blkid/src/superblocks/via_raid.c
index 58650454..20131380 100644
--- a/shlibs/blkid/src/superblocks/via_raid.c
+++ b/shlibs/blkid/src/superblocks/via_raid.c
@@ -52,6 +52,8 @@ static int probe_viaraid(blkid_probe pr, const struct blkid_idmag *mag)
if (pr->size < 0x10000)
return -1;
+ if (!S_ISREG(pr->mode) && !blkid_probe_is_wholedisk(pr))
+ return -1;
off = ((pr->size / 0x200)-1) * 0x200;
diff --git a/shlibs/blkid/src/topology/evms.c b/shlibs/blkid/src/topology/evms.c
index baab16ed..574d9f55 100644
--- a/shlibs/blkid/src/topology/evms.c
+++ b/shlibs/blkid/src/topology/evms.c
@@ -23,6 +23,11 @@
#include "topology.h"
#define EVMS_MAJOR 117
+
+#ifndef _IOT__IOTBASE_u_int32_t
+#define _IOT__IOTBASE_u_int32_t IOT_SIMPLE(u_int32_t)
+#endif
+#define _IOT_evms_stripe_info _IOT (_IOTS(u_int32_t), 2, 0, 0, 0, 0)
#define EVMS_GET_STRIPE_INFO _IOR(EVMS_MAJOR, 0xF0, struct evms_stripe_info)
struct evms_stripe_info {
diff --git a/shlibs/blkid/src/topology/md.c b/shlibs/blkid/src/topology/md.c
index a761e170..d7275edd 100644
--- a/shlibs/blkid/src/topology/md.c
+++ b/shlibs/blkid/src/topology/md.c
@@ -26,6 +26,10 @@
#define MD_MAJOR 9
#endif
+#ifndef _IOT__IOTBASE_uint32_t
+#define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t)
+#endif
+#define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0)
#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info)
struct md_array_info {
diff --git a/shlibs/mount/.gitignore b/shlibs/mount/.gitignore
new file mode 100644
index 00000000..1c7879de
--- /dev/null
+++ b/shlibs/mount/.gitignore
@@ -0,0 +1,2 @@
+test_*
+mount.h
diff --git a/shlibs/mount/COPYING.libmount b/shlibs/mount/COPYING.libmount
new file mode 100644
index 00000000..89d4489c
--- /dev/null
+++ b/shlibs/mount/COPYING.libmount
@@ -0,0 +1,508 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+^L
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/shlibs/mount/Makefile.am b/shlibs/mount/Makefile.am
new file mode 100644
index 00000000..3fefce6e
--- /dev/null
+++ b/shlibs/mount/Makefile.am
@@ -0,0 +1,13 @@
+include $(top_srcdir)/config/include-Makefile.am
+
+SUBDIRS = src
+
+if ENABLE_GTK_DOC
+SUBDIRS += docs
+endif
+
+# pkg-config stuff
+pkgconfigdir = $(usrlib_execdir)/pkgconfig
+pkgconfig_DATA = mount.pc
+
+EXTRA_DIST = COPYING.libmount mount.pc.in
diff --git a/shlibs/mount/docs/.gitignore b/shlibs/mount/docs/.gitignore
new file mode 100644
index 00000000..917c8481
--- /dev/null
+++ b/shlibs/mount/docs/.gitignore
@@ -0,0 +1,17 @@
+*.args
+*.bak
+*-decl-list.txt
+*-decl.txt
+*.hierarchy
+html/*
+*.interfaces
+*-overrides.txt
+*.prerequisites
+*.signals
+*.stamp
+tmpl/*
+*-undeclared.txt
+*-undocumented.txt
+*-unused.txt
+version.xml
+xml/*
diff --git a/shlibs/mount/docs/Makefile.am b/shlibs/mount/docs/Makefile.am
new file mode 100644
index 00000000..13e1c655
--- /dev/null
+++ b/shlibs/mount/docs/Makefile.am
@@ -0,0 +1,101 @@
+include $(top_srcdir)/config/include-Makefile.am
+
+## 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=libmount
+
+# 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 mount
+
+# 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=$(ul_libmount_incdir)/mount.h
+CFILE_GLOB=$(ul_libmount_srcdir)/*.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=mountP.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 +=
+
+# Comment this out if you want your docs-status tested during 'make check'
+if ENABLE_GTK_DOC
+#TESTS_ENVIRONMENT = cd $(srcsrc)
+#TESTS = $(GTKDOC_CHECK)
+endif
diff --git a/shlibs/mount/docs/libmount-docs.xml b/shlibs/mount/docs/libmount-docs.xml
new file mode 100644
index 00000000..c1371d61
--- /dev/null
+++ b/shlibs/mount/docs/libmount-docs.xml
@@ -0,0 +1,60 @@
+<?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>libmount Reference Manual</title>
+ <releaseinfo>for libmount version &version;</releaseinfo>
+ <copyright>
+ <year>2010</year>
+ <holder>Karel Zak &lt;kzak@redhat.com&gt;</holder>
+ </copyright>
+ </bookinfo>
+
+ <part id="gtk">
+ <title>libmount Overview</title>
+ <partintro>
+ <para>
+The libmount library is used to parse /etc/fstab, /etc/mtab and
+/proc/self/mountinfo files, manage the mtab file, evaluate mount options, etc.
+ </para>
+ <para>
+The library is part of the util-linux-ng package since version 2.18 and is
+available from ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/.
+ </para>
+ </partintro>
+ </part>
+
+ <part>
+ <title>Files parsing</title>
+ <xi:include href="xml/tab.xml"/>
+ <xi:include href="xml/fs.xml"/>
+ </part>
+ <part>
+ <title>Mount options</title>
+ <xi:include href="xml/optstr.xml"/>
+ <xi:include href="xml/optls.xml"/>
+ <xi:include href="xml/optent.xml"/>
+ <xi:include href="xml/optmap.xml"/>
+ </part>
+ <part>
+ <title>Mtab management</title>
+ <xi:include href="xml/lock.xml"/>
+ </part>
+ <part>
+ <title>Misc</title>
+ <xi:include href="xml/init.xml"/>
+ <xi:include href="xml/cache.xml"/>
+ <xi:include href="xml/iter.xml"/>
+ <xi:include href="xml/utils.xml"/>
+ <xi:include href="xml/version.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/shlibs/mount/docs/libmount-sections.txt b/shlibs/mount/docs/libmount-sections.txt
new file mode 100644
index 00000000..59cdf47d
--- /dev/null
+++ b/shlibs/mount/docs/libmount-sections.txt
@@ -0,0 +1,181 @@
+<SECTION>
+<FILE>init</FILE>
+mnt_init_debug
+</SECTION>
+
+<SECTION>
+<FILE>version</FILE>
+mnt_parse_version_string
+mnt_get_library_version
+</SECTION>
+
+<SECTION>
+<FILE>utils</FILE>
+mnt_fstype_is_netfs
+mnt_fstype_is_pseudofs
+mnt_match_fstype
+mnt_match_options
+</SECTION>
+
+<SECTION>
+<FILE>cache</FILE>
+mnt_cache
+mnt_new_cache
+mnt_free_cache
+mnt_cache_find_path
+mnt_cache_find_tag
+mnt_cache_read_tags
+mnt_cache_device_has_tag
+mnt_cache_find_tag_value
+mnt_resolve_path
+mnt_resolve_tag
+mnt_resolve_spec
+</SECTION>
+
+<SECTION>
+<FILE>optstr</FILE>
+mnt_optstr_next_option
+mnt_optstr_append_option
+mnt_optstr_get_option
+mnt_optstr_set_option
+mnt_optstr_remove_option
+</SECTION>
+
+<SECTION>
+<FILE>iter</FILE>
+mnt_iter
+mnt_new_iter
+mnt_free_iter
+mnt_reset_iter
+mnt_iter_get_direction
+</SECTION>
+
+<SECTION>
+<FILE>optmap</FILE>
+mnt_optmap
+mnt_get_builtin_optmap
+</SECTION>
+
+<SECTION>
+<FILE>optent</FILE>
+mnt_optent
+mnt_optent_get_map
+mnt_optent_get_mapent
+mnt_optent_get_type
+mnt_optent_set_value
+mnt_optent_has_value
+mnt_optent_require_value
+mnt_optent_is_inverted
+mnt_optent_strtoul_value
+mnt_optent_strtol_value
+mnt_optent_strtoull_value
+mnt_optent_get_value
+mnt_optent_strlen_value
+mnt_optent_snprintf_value
+mnt_optent_dup_value
+mnt_optent_get_name
+mnt_optent_get_mask
+mnt_optent_get_id
+mnt_optent_get_flag
+mnt_optent_is_unknown
+mnt_optent_print_debug
+</SECTION>
+
+<SECTION>
+<FILE>optls</FILE>
+mnt_optls
+mnt_new_optls
+mnt_free_optls
+mnt_optls_add_map
+mnt_optls_add_builtin_map
+mnt_optls_add_option
+mnt_optls_parse_optstr
+mnt_optls_remove_option
+mnt_optls_remove_option_by_flags
+mnt_optls_remove_option_by_iflags
+mnt_optls_next_option
+mnt_optls_get_option
+mnt_optls_get_ids
+mnt_optls_create_mountflags
+mnt_optls_create_mountdata
+mnt_optls_create_mtab_optstr
+mnt_optls_create_userspace_optstr
+mnt_optls_print_debug
+</SECTION>
+
+
+<SECTION>
+<FILE>lock</FILE>
+mnt_lock
+mnt_new_lock
+mnt_free_lock
+mnt_lock_get_lockfile
+mnt_lock_get_linkfile
+mnt_unlock_file
+mnt_lock_file
+</SECTION>
+
+
+<SECTION>
+<FILE>fs</FILE>
+mnt_fs
+mnt_new_fs
+mnt_free_fs
+mnt_fs_get_userdata
+mnt_fs_set_userdata
+mnt_fs_get_source
+mnt_fs_set_source
+mnt_fs_get_srcpath
+mnt_fs_get_tag
+mnt_fs_get_target
+mnt_fs_set_target
+mnt_fs_get_fstype
+mnt_fs_set_fstype
+mnt_fs_get_optstr
+mnt_fs_set_optstr
+mnt_fs_get_fs_optstr
+mnt_fs_get_vfs_optstr
+mnt_fs_get_freq
+mnt_fs_set_freq
+mnt_fs_get_passno
+mnt_fs_set_passno
+mnt_fs_get_id
+mnt_fs_get_parent_id
+mnt_fs_get_devno
+mnt_fs_get_option
+mnt_fs_match_target
+mnt_fs_match_source
+mnt_fs_match_fstype
+mnt_fs_match_options
+mnt_fprintf_line
+mnt_fs_fprintf
+mnt_fs_print_debug
+</SECTION>
+
+<SECTION>
+<FILE>tab</FILE>
+mnt_tab
+mnt_new_tab_from_file
+mnt_tab_parse_file
+mnt_tab_strerror
+mnt_tab_get_nerrs
+mnt_new_tab
+mnt_free_tab
+mnt_tab_get_nents
+mnt_tab_set_cache
+mnt_tab_get_cache
+mnt_tab_get_name
+mnt_tab_add_fs
+mnt_tab_remove_fs
+mnt_tab_next_fs
+mnt_tab_next_child_fs
+mnt_tab_get_root_fs
+mnt_tab_set_iter
+mnt_tab_find_target
+mnt_tab_find_srcpath
+mnt_tab_find_tag
+mnt_tab_find_source
+mnt_tab_find_next_fs
+mnt_tab_fprintf
+mnt_tab_update_file
+</SECTION>
diff --git a/shlibs/mount/docs/libmount.types b/shlibs/mount/docs/libmount.types
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/shlibs/mount/docs/libmount.types
diff --git a/shlibs/mount/docs/version.xml.in b/shlibs/mount/docs/version.xml.in
new file mode 100644
index 00000000..d78bda93
--- /dev/null
+++ b/shlibs/mount/docs/version.xml.in
@@ -0,0 +1 @@
+@VERSION@
diff --git a/shlibs/mount/mount.pc.in b/shlibs/mount/mount.pc.in
new file mode 100644
index 00000000..94051b8b
--- /dev/null
+++ b/shlibs/mount/mount.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@usrlib_execdir@
+includedir=@includedir@
+
+Name: mount
+Description: mount library
+Version: @LIBMOUNT_VERSION@
+Requires.private: blkid
+Cflags: -I${includedir}/mount
+Libs: -L${libdir} -lmount
diff --git a/shlibs/mount/src/Makefile.am b/shlibs/mount/src/Makefile.am
new file mode 100644
index 00000000..aebd3cc5
--- /dev/null
+++ b/shlibs/mount/src/Makefile.am
@@ -0,0 +1,56 @@
+include $(top_srcdir)/config/include-Makefile.am
+
+AM_CPPFLAGS += -I$(ul_libmount_incdir) \
+ -I$(ul_libmount_srcdir) \
+ -I$(ul_libblkid_incdir)
+
+# includes
+mountincdir = $(includedir)/mount
+nodist_mountinc_HEADERS = mount.h
+
+usrlib_exec_LTLIBRARIES = libmount.la
+libmount_la_SOURCES = mountP.h version.c utils.c test.c init.c cache.c \
+ optstr.c optmap.c optent.c optls.c iter.c lock.c \
+ fs.c tab.c tab_parse.c \
+ $(mountinc_HEADERS) \
+ $(top_srcdir)/include/list.h \
+ $(top_srcdir)/lib/mangle.c \
+ $(top_srcdir)/lib/canonicalize.c
+
+nodist_libmount_la_SOURCES = mountP.h
+
+libmount_la_LIBADD = $(ul_libblkid_la)
+
+libmount_la_DEPENDENCIES = $(libmount_la_LIBADD) mount.sym mount.h.in
+
+libmount_la_LDFLAGS = -Wl,--version-script=$(ul_libmount_srcdir)/mount.sym \
+ -version-info $(LIBMOUNT_VERSION_INFO)
+
+EXTRA_DIST = mount.sym mount.h.in
+CLEANFILES = $(tests)
+
+# move lib from $(usrlib_execdir) to $(libdir) if needed
+install-exec-hook:
+ if test "$(usrlib_execdir)" != "$(libdir)"; then \
+ mkdir -p $(DESTDIR)$(libdir); \
+ mv $(DESTDIR)$(usrlib_execdir)/libmount.so.* $(DESTDIR)$(libdir); \
+ so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libmount.so); \
+ so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
+ (cd $(DESTDIR)$(usrlib_execdir) && \
+ rm -f libmount.so && \
+ $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libmount.so); \
+ fi
+
+uninstall-hook:
+ rm -f $(DESTDIR)$(libdir)/libmount.so*
+
+
+tests = test_version test_cache test_optstr test_optls test_lock \
+ test_tab test_utils
+
+tests: all $(tests)
+test_%: %.c
+ $(COMPILE) -DTEST_PROGRAM $< .libs/libmount.a \
+ $(ul_libblkid_builddir)/.libs/libblkid.a -o $@ \
+ $(UUID_LIBS)
+
diff --git a/shlibs/mount/src/cache.c b/shlibs/mount/src/cache.c
new file mode 100644
index 00000000..027fda44
--- /dev/null
+++ b/shlibs/mount/src/cache.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: cache
+ * @title: Cache
+ * @short_description: paths and tags (UUID/LABEL) caching
+ *
+ * The cache is a very simple API for work with tags (LABEL, UUID, ...) and
+ * paths. The cache uses libblkid as a backend from TAGs resolution.
+ *
+ * All returned paths are always canonicalized.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <blkid.h>
+
+#include "canonicalize.h"
+#include "mountP.h"
+
+/*
+ * Canonicalized (resolved) paths & tags cache
+ */
+#define MNT_CACHE_CHUNKSZ 128
+
+#define MNT_CACHE_ISTAG (1 << 1) /* entry is TAG */
+#define MNT_CACHE_ISPATH (1 << 2) /* entry is path */
+#define MNT_CACHE_TAGREAD (1 << 3) /* tag read by mnt_cache_read_tags() */
+
+/* path cache entry */
+struct mnt_cache_entry {
+ char *native; /* the original path */
+ char *real; /* canonicalized path */
+ int flag;
+};
+
+struct _mnt_cache {
+ struct mnt_cache_entry *ents;
+ size_t nents;
+ size_t nallocs;
+
+ /* blkid_evaluate_tag() works in two ways:
+ *
+ * 1/ all tags are evaluated by udev /dev/disk/by-* symlinks,
+ * then the blkid_cache is NULL.
+ *
+ * 2/ all tags are read from /etc/blkid.tab and verified by /dev
+ * scanning, then the blkid_cache is not NULL and then it's
+ * better to reuse the blkid_cache.
+ */
+ blkid_cache bc;
+};
+
+/**
+ * mnt_new_cache:
+ *
+ * Returns: new mnt_cache instance or NULL in case of ENOMEM error.
+ */
+mnt_cache *mnt_new_cache(void)
+{
+ return calloc(1, sizeof(struct _mnt_cache));
+}
+
+/**
+ * mnt_free_cache:
+ * @cache: pointer to mnt_cache instance
+ *
+ * Deallocates the cache.
+ */
+void mnt_free_cache(mnt_cache *cache)
+{
+ int i;
+
+ if (!cache)
+ return;
+ for (i = 0; i < cache->nents; i++) {
+ struct mnt_cache_entry *e = &cache->ents[i];
+ if (e->real != e->native)
+ free(e->real);
+ free(e->native);
+ }
+ free(cache->ents);
+ if (cache->bc)
+ blkid_put_cache(cache->bc);
+ free(cache);
+}
+
+/* note that the @native could be tha same pointer as @real */
+static int mnt_cache_add_entry(mnt_cache *cache, char *native,
+ char *real, int flag)
+{
+ struct mnt_cache_entry *e;
+
+ assert(cache);
+ assert(real);
+ assert(native);
+
+ if (cache->nents == cache->nallocs) {
+ size_t sz = cache->nallocs + MNT_CACHE_CHUNKSZ;
+
+ e = realloc(cache->ents, sz * sizeof(struct mnt_cache_entry));
+ if (!e)
+ return -1;
+ cache->ents = e;
+ cache->nallocs = sz;
+ }
+
+ e = &cache->ents[cache->nents];
+ e->native = native;
+ e->real = real;
+ e->flag = flag;
+ cache->nents++;
+
+ DBG(DEBUG_CACHE,
+ printf("cache: add entry[%2zd] (%s): %s: %s\n",
+ cache->nents,
+ (flag & MNT_CACHE_ISPATH) ? "path" : "tag",
+ real, native));
+ return 0;
+}
+
+/* add tag to the cache, @real has to be allocated string */
+static int mnt_cache_add_tag(mnt_cache *cache, const char *token,
+ const char *value, char *real, int flag)
+{
+ size_t tksz, vlsz;
+ char *native;
+
+ assert(cache);
+ assert(real);
+ assert(token);
+ assert(value);
+
+ /* add into cache -- cache format for TAGs is
+ * native = "NAME\0VALUE\0"
+ * real = "/dev/foo"
+ */
+ tksz = strlen(token);
+ vlsz = strlen(value);
+
+ native = malloc(tksz + vlsz + 2);
+ if (!native)
+ goto error;
+
+ memcpy(native, token, tksz + 1); /* include '\0' */
+ memcpy(native + tksz + 1, value, vlsz + 1);
+
+ if (mnt_cache_add_entry(cache, native, real, flag | MNT_CACHE_ISTAG))
+ goto error;
+ return 0;
+error:
+ free(native);
+ return -1;
+}
+
+
+/**
+ * mnt_cache_find_path:
+ * @cache: pointer to mnt_cache instance
+ * @path: "native" (non-canonicalized) path
+ *
+ * Returns: cached canonicalized path or NULL.
+ */
+const char *mnt_cache_find_path(mnt_cache *cache, const char *path)
+{
+ int i;
+
+ assert(cache);
+ assert(path);
+
+ if (!cache || !path)
+ return NULL;
+
+ for (i = 0; i < cache->nents; i++) {
+ struct mnt_cache_entry *e = &cache->ents[i];
+ if (!(e->flag & MNT_CACHE_ISPATH))
+ continue;
+ if (strcmp(path, e->native) == 0)
+ return e->real;
+ }
+ return NULL;
+}
+
+/**
+ * mnt_cache_find_tag:
+ * @cache: pointer to mnt_cache instance
+ * @token: tag name
+ * @value: tag value
+ *
+ * Returns: cached path or NULL.
+ */
+const char *mnt_cache_find_tag(mnt_cache *cache,
+ const char *token, const char *value)
+{
+ int i;
+ size_t tksz;
+
+ assert(cache);
+ assert(token);
+ assert(value);
+
+ if (!cache || !token || !value)
+ return NULL;
+
+ tksz = strlen(token);
+
+ for (i = 0; i < cache->nents; i++) {
+ struct mnt_cache_entry *e = &cache->ents[i];
+ if (!(e->flag & MNT_CACHE_ISTAG))
+ continue;
+ if (strcmp(token, e->native) == 0 &&
+ strcmp(value, e->native + tksz + 1) == 0)
+ return e->real;
+ }
+ return NULL;
+}
+
+/**
+ * mnt_cache_read_tags
+ * @cache: pointer to mnt_cache instance
+ * @devname: path device
+ *
+ * Reads @devname LABEL and UUID to the @cache.
+ *
+ * Returns: 0 if at least one tag was added, 1 if no tag was added or
+ * -1 in case of error.
+ */
+int mnt_cache_read_tags(mnt_cache *cache, const char *devname)
+{
+ int i, ntags = 0;
+ static blkid_probe pr;
+ const char *tags[] = { "LABEL", "UUID" };
+
+ assert(cache);
+ assert(devname);
+
+ if (!cache || !devname)
+ return -1;
+
+ DBG(DEBUG_CACHE, printf("cache: tags for %s requested\n", devname));
+
+ /* check is device is already cached */
+ for (i = 0; i < cache->nents; i++) {
+ struct mnt_cache_entry *e = &cache->ents[i];
+ if (!(e->flag & MNT_CACHE_TAGREAD))
+ continue;
+ if (strcmp(e->real, devname) == 0)
+ /* tags has been already read */
+ return 0;
+ }
+
+ DBG(DEBUG_CACHE,
+ printf("cache: reading tags for: %s\n", devname));
+
+ pr = blkid_new_probe_from_filename(devname);
+ if (!pr)
+ return -1;
+
+ blkid_probe_enable_superblocks(pr, 1);
+
+ blkid_probe_set_superblocks_flags(pr,
+ BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID);
+
+ if (blkid_do_safeprobe(pr))
+ goto error;
+
+ for (i = 0; i < ARRAY_SIZE(tags); i++) {
+ const char *data;
+ char *dev;
+
+ if (blkid_probe_lookup_value(pr, tags[i], &data, NULL))
+ continue;
+ if (mnt_cache_find_tag(cache, tags[i], data))
+ continue; /* already cached */
+
+ dev = strdup(devname);
+ if (!dev)
+ goto error;
+ if (mnt_cache_add_tag(cache, tags[i], data, dev,
+ MNT_CACHE_TAGREAD)) {
+ free(dev);
+ goto error;
+ }
+ ntags++;
+ }
+
+ return ntags ? 0 : 1;
+error:
+ blkid_free_probe(pr);
+ return -1;
+}
+
+/**
+ * mnt_cache_device_has_tag:
+ * @cache: paths cache
+ * @devname: path to the device
+ * @token: tag name (e.g "LABEL")
+ * @value: tag value
+ *
+ * Look up @cache to check it @tag+@value are associated with @devname.
+ *
+ * Returns: 1 on success or 0.
+ */
+int mnt_cache_device_has_tag(mnt_cache *cache, const char *devname,
+ const char *token, const char *value)
+{
+ const char *path = mnt_cache_find_tag(cache, token, value);
+
+ if (path && strcmp(path, devname) == 0)
+ return 1;
+ return 0;
+}
+
+/**
+ * mnt_cache_find_tag_value:
+ * @cache: cache for results
+ * @devname: device name
+ * @token: tag name ("LABEL" or "UUID")
+ *
+ * Returns: LABEL or UUID for the @devname or NULL in case of error.
+ */
+char *mnt_cache_find_tag_value(mnt_cache *cache,
+ const char *devname, const char *token)
+{
+ int i;
+
+ if (!cache || !devname || !token)
+ return NULL;
+
+ if (mnt_cache_read_tags(cache, devname) != 0)
+ return NULL;
+
+ for (i = 0; i < cache->nents; i++) {
+ struct mnt_cache_entry *e = &cache->ents[i];
+ if (!(e->flag & MNT_CACHE_ISTAG))
+ continue;
+ if (strcmp(e->real, devname) == 0 && /* dev name */
+ strcmp(token, e->native) == 0) /* tag name */
+ return e->native + strlen(token) + 1; /* tag value */
+ }
+
+ return NULL;
+}
+
+/**
+ * mnt_resolve_path:
+ * @path: "native" path
+ * @cache: cache for results or NULL
+ *
+ * Returns: absolute path or NULL in case of error. The result has to be
+ * deallocated by free() if @cache is NULL.
+ */
+char *mnt_resolve_path(const char *path, mnt_cache *cache)
+{
+ char *p = NULL;
+ char *native = NULL;
+ char *real = NULL;
+
+ assert(path);
+
+ if (!path)
+ return NULL;
+ if (cache)
+ p = (char *) mnt_cache_find_path(cache, path);
+
+ if (!p) {
+ p = canonicalize_path(path);
+
+ if (p && cache) {
+ native = strdup(path);
+ real = strcmp(path, p) == 0 ? native : p;
+
+ if (!native || !real)
+ goto error;
+
+ if (mnt_cache_add_entry(cache, native, real,
+ MNT_CACHE_ISPATH))
+ goto error;
+ }
+ }
+
+ return p;
+error:
+ if (real != native)
+ free(real);
+ free(native);
+ return NULL;
+}
+
+/**
+ * mnt_resolve_tag:
+ * @token: tag name
+ * @value: tag value
+ * @cache: for results or NULL
+ *
+ * Returns: device name or NULL in case of error. The result has to be
+ * deallocated by free() if @cache is NULL.
+ */
+char *mnt_resolve_tag(const char *token, const char *value, mnt_cache *cache)
+{
+ char *p = NULL;
+
+ assert(token);
+ assert(value);
+
+ if (!token || !value)
+ return NULL;
+
+ if (cache)
+ p = (char *) mnt_cache_find_tag(cache, token, value);
+
+ if (!p) {
+ /* returns newly allocated string */
+ p = blkid_evaluate_tag(token, value, cache ? &cache->bc : NULL);
+
+ if (p && cache &&
+ mnt_cache_add_tag(cache, token, value, p, 0))
+ goto error;
+ }
+
+ return p;
+error:
+ free(p);
+ return NULL;
+}
+
+
+
+/**
+ * mnt_resolve_spec:
+ * @spec: path or tag
+ * @cache: paths cache
+ *
+ * Returns: canonicalized path or NULL. The result has to be
+ * deallocated by free() if @cache is NULL.
+ */
+char *mnt_resolve_spec(const char *spec, mnt_cache *cache)
+{
+ char *cn = NULL;
+
+ if (!spec)
+ return NULL;
+
+ if (strchr(spec, '=')) {
+ char *tag, *val;
+
+ if (!blkid_parse_tag_string(spec, &tag, &val)) {
+ cn = mnt_resolve_tag(tag, val, cache);
+
+ free(tag);
+ free(val);
+ }
+ } else
+ cn = mnt_resolve_path(spec, cache);
+
+ return cn;
+}
+
+
+#ifdef TEST_PROGRAM
+
+int test_resolve_path(struct mtest *ts, int argc, char *argv[])
+{
+ char line[BUFSIZ];
+ mnt_cache *cache;
+
+ cache = mnt_new_cache();
+ if (!cache)
+ return -1;
+
+ while(fgets(line, sizeof(line), stdin)) {
+ size_t sz = strlen(line);
+ char *p;
+
+ if (line[sz - 1] == '\n')
+ line[sz - 1] = '\0';
+
+ p = mnt_resolve_path(line, cache);
+ printf("%s : %s\n", line, p);
+ }
+ mnt_free_cache(cache);
+ return 0;
+}
+
+int test_resolve_spec(struct mtest *ts, int argc, char *argv[])
+{
+ char line[BUFSIZ];
+ mnt_cache *cache;
+
+ cache = mnt_new_cache();
+ if (!cache)
+ return -1;
+
+ while(fgets(line, sizeof(line), stdin)) {
+ size_t sz = strlen(line);
+ char *p;
+
+ if (line[sz - 1] == '\n')
+ line[sz - 1] = '\0';
+
+ p = mnt_resolve_spec(line, cache);
+ printf("%s : %s\n", line, p);
+ }
+ mnt_free_cache(cache);
+ return 0;
+}
+
+int test_read_tags(struct mtest *ts, int argc, char *argv[])
+{
+ char line[BUFSIZ];
+ mnt_cache *cache;
+
+ cache = mnt_new_cache();
+ if (!cache)
+ return -1;
+
+ while(fgets(line, sizeof(line), stdin)) {
+ size_t sz = strlen(line);
+
+ if (line[sz - 1] == '\n')
+ line[sz - 1] = '\0';
+
+ if (*line == '/') {
+ if (mnt_cache_read_tags(cache, line) < 0)
+ fprintf(stderr, "%s: read tags faild\n", line);
+
+ } else if (strchr(line, '=')) {
+ char *tag, *val;
+ const char *cn = NULL;
+
+ if (!blkid_parse_tag_string(line, &tag, &val)) {
+ cn = mnt_cache_find_tag(cache, tag, val);
+
+ free(tag);
+ free(val);
+ }
+ if (cn)
+ printf("%s: %s\n", line, cn);
+ else
+ printf("%s: not cached\n", line);
+ }
+ }
+ mnt_free_cache(cache);
+ return 0;
+
+}
+
+int main(int argc, char *argv[])
+{
+ struct mtest ts[] = {
+ { "--resolve-path", test_resolve_path, " resolve paths from stdin" },
+ { "--resolve-spec", test_resolve_spec, " evaluate specs from stdin" },
+ { "--read-tags", test_read_tags, " read devname or TAG from stdin" },
+ { NULL }
+ };
+
+ return mnt_run_test(ts, argc, argv);
+}
+#endif
diff --git a/shlibs/mount/src/fs.c b/shlibs/mount/src/fs.c
new file mode 100644
index 00000000..63da2f20
--- /dev/null
+++ b/shlibs/mount/src/fs.c
@@ -0,0 +1,787 @@
+/*
+ * 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: fs
+ * @title: Filesystem
+ * @short_description: mnt_fs represents one entry in fstab/mtab/mountinfo
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <blkid.h>
+
+#include "nls.h"
+#include "mountP.h"
+
+/**
+ * mnt_new_fs:
+ *
+ * Returns: newly allocated mnt_file fs.
+ */
+mnt_fs *mnt_new_fs(void)
+{
+ mnt_fs *fs = calloc(1, sizeof(struct _mnt_fs));
+ if (!fs)
+ return NULL;
+
+ INIT_LIST_HEAD(&fs->ents);
+ return fs;
+}
+
+/**
+ * mnt_free_fs:
+ * @fs: fs pointer
+ *
+ * Deallocates the fs.
+ */
+void mnt_free_fs(mnt_fs *fs)
+{
+ if (!fs)
+ return;
+ list_del(&fs->ents);
+
+ free(fs->source);
+ free(fs->tagname);
+ free(fs->tagval);
+ free(fs->mntroot);
+ free(fs->target);
+ free(fs->fstype);
+ free(fs->optstr);
+ free(fs->vfs_optstr);
+ free(fs->fs_optstr);
+
+ free(fs);
+}
+
+/**
+ * mnt_fs_get_userdata:
+ * @fs: mnt_file instance
+ *
+ * Returns: private data set by mnt_fs_set_userdata() or NULL.
+ */
+void *mnt_fs_get_userdata(mnt_fs *fs)
+{
+ return fs ? fs->userdata : NULL;
+}
+
+/**
+ * mnt_fs_set_userdata:
+ * @fs: mnt_file instance
+ *
+ * The "userdata" are library independent data.
+ *
+ * Returns: 0 or -1 in case of error (if @fs is NULL).
+ */
+int mnt_fs_set_userdata(mnt_fs *fs, void *data)
+{
+ if (!fs)
+ return -1;
+ fs->userdata = data;
+ return 0;
+}
+
+/**
+ * mnt_fs_get_srcpath:
+ * @fs: mnt_file (fstab/mtab/mountinfo) fs
+ *
+ * The mount "source path" is:
+ * - a directory for 'bind' mounts (in fstab or mtab only)
+ * - a device name for standard mounts
+ *
+ * See also mnt_fs_get_tag() and mnt_fs_get_source().
+ *
+ * Returns: mount source path or NULL in case of error or when the path
+ * is not defined.
+ */
+const char *mnt_fs_get_srcpath(mnt_fs *fs)
+{
+ assert(fs);
+ if (!fs)
+ return NULL;
+
+ /* fstab-like fs */
+ if (fs->tagname)
+ return NULL; /* the source contains a "NAME=value" */
+ return fs->source;
+}
+
+/**
+ * mnt_fs_get_source:
+ * @fs: mnt_file (fstab/mtab/mountinfo) fs
+ *
+ * Returns: mount source. Note that the source could be unparsed TAG
+ * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag().
+ */
+const char *mnt_fs_get_source(mnt_fs *fs)
+{
+ return fs ? fs->source : NULL;
+}
+
+/* Used by parser mnt_file ONLY (@source has to be allocated) */
+int __mnt_fs_set_source(mnt_fs *fs, char *source)
+{
+ assert(fs);
+
+ if (!source)
+ return -1;
+
+ if (strchr(source, '=')) {
+ char *name, *val;
+
+ if (blkid_parse_tag_string(source, &name, &val) != 0)
+ return -1;
+
+ fs->tagval = val;
+ fs->tagname = name;
+ }
+
+ fs->source = source;
+ return 0;
+}
+
+/**
+ * mnt_fs_set_source:
+ * @fs: fstab/mtab/mountinfo entry
+ * @source: new source
+ *
+ * This function creates a private copy (strdup()) of @source.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_source(mnt_fs *fs, const char *source)
+{
+ char *p;
+
+ if (!fs && !source)
+ return -1;
+
+ p = strdup(source);
+ if (!p)
+ return -1;
+
+ free(fs->tagval);
+ free(fs->tagname);
+ free(fs->source);
+ fs->tagval = fs->tagname = fs->source = NULL;
+
+ return __mnt_fs_set_source(fs, p);
+}
+
+/**
+ * mnt_fs_get_tag:
+ * @fs: fs
+ * @name: returns pointer to NAME string
+ * @value: returns pointer to VALUE string
+ *
+ * "TAG" is NAME=VALUE (e.g. LABEL=foo)
+ *
+ * The TAG is the first column in the fstab file. The TAG or "srcpath" has to
+ * be always set for all entries.
+ *
+ * See also mnt_fs_get_source().
+ *
+ * <informalexample>
+ * <programlisting>
+ * char *src;
+ * mnt_fs *fs = mnt_tab_find_target(tb, "/home", MNT_ITER_FORWARD);
+ *
+ * if (!fs)
+ * goto err;
+ *
+ * src = mnt_fs_get_srcpath(fs);
+ * if (!src) {
+ * char *tag, *val;
+ * if (mnt_fs_get_tag(fs, &tag, &val) == 0)
+ * printf("%s: %s\n", tag, val); // LABEL or UUID
+ * } else
+ * printf("device: %s\n", src); // device or bind path
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success or -1 in case that a TAG is not defined.
+ */
+int mnt_fs_get_tag(mnt_fs *fs, const char **name, const char **value)
+{
+ if (fs == NULL || !fs->tagname)
+ return -1;
+ if (name)
+ *name = fs->tagname;
+ if (value)
+ *value = fs->tagval;
+ return 0;
+}
+
+/**
+ * mnt_fs_get_target:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: pointer to mountpoint path or NULL
+ */
+const char *mnt_fs_get_target(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->target : NULL;
+}
+
+/**
+ * mnt_fs_set_target:
+ * @fs: fstab/mtab/mountinfo entry
+ * @target: mountpoint
+ *
+ * This function creates a private copy (strdup()) of @target.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_target(mnt_fs *fs, const char *target)
+{
+ char *p;
+
+ assert(fs);
+
+ if (!fs || !target)
+ return -1;
+
+ p = strdup(target);
+ if (!p)
+ return -1;
+ free(fs->target);
+ fs->target = p;
+
+ return 0;
+}
+
+/**
+ * mnt_fs_get_fstype:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: pointer to filesystem type.
+ */
+const char *mnt_fs_get_fstype(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->fstype : NULL;
+}
+
+/* Used by mnt_file parser only */
+int __mnt_fs_set_fstype(mnt_fs *fs, char *fstype)
+{
+ assert(fs);
+
+ if (!fstype)
+ return -1;
+
+ fs->fstype = fstype;
+ fs->flags &= ~MNT_FS_PSEUDO;
+ fs->flags &= ~MNT_FS_NET;
+
+ /* save info about pseudo filesystems */
+ if (mnt_fstype_is_pseudofs(fs->fstype))
+ fs->flags |= MNT_FS_PSEUDO;
+ else if (mnt_fstype_is_netfs(fs->fstype))
+ fs->flags |= MNT_FS_NET;
+
+ return 0;
+}
+
+/**
+ * mnt_fs_set_fstype:
+ * @fs: fstab/mtab/mountinfo entry
+ * @fstype: filesystem type
+ *
+ * This function creates a private copy (strdup()) of @fstype.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_fstype(mnt_fs *fs, const char *fstype)
+{
+ char *p;
+
+ if (!fs || !fstype)
+ return -1;
+
+ p = strdup(fstype);
+ if (!p)
+ return -1;
+ free(fs->fstype);
+
+ return __mnt_fs_set_fstype(fs, p);
+}
+
+/**
+ * mnt_fs_get_optstr:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: pointer to mount option string with all options (FS and VFS)
+ */
+const char *mnt_fs_get_optstr(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->optstr : NULL;
+}
+
+/**
+ * mnt_fs_set_optstr:
+ * @fs: fstab/mtab/mountinfo entry
+ * @optstr: options string
+ *
+ * This function creates a private copy (strdup()) of @optstr.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_optstr(mnt_fs *fs, const char *optstr)
+{
+ char *p;
+
+ assert(fs);
+
+ if (!fs || !optstr)
+ return -1;
+ p = strdup(optstr);
+ if (!p)
+ return -1;
+
+ free(fs->optstr);
+ free(fs->fs_optstr);
+ free(fs->vfs_optstr);
+ fs->fs_optstr = fs->vfs_optstr = NULL;
+
+ /* TODO: it would be possible to use built-in maps of options
+ * and differentiate between VFS and FS options, then we can
+ * set fs_optstr and vfs_optstr */
+
+ fs->optstr = p;
+
+ return 0;
+}
+
+/**
+ * mnt_fs_get_fs_optstr:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * This function works for "mountinfo" files only.
+ *
+ * Returns: pointer to superblock (fs-depend) mount option string or NULL.
+ */
+const char *mnt_fs_get_fs_optstr(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->fs_optstr : NULL;
+}
+
+/**
+ * mnt_fs_get_vfs_optstr:
+ * @fs: fstab/mtab entry pointer
+ *
+ * This function works for "mountinfo" files only.
+ *
+ * Returns: pointer to fs-independent (VFS) mount option string or NULL.
+ */
+const char *mnt_fs_get_vfs_optstr(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->vfs_optstr : NULL;
+}
+
+
+/**
+ * mnt_fs_get_freq:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: dump frequency in days.
+ */
+int mnt_fs_get_freq(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->freq : 0;
+}
+
+/**
+ * mnt_fs_set_freq:
+ * @fs: fstab/mtab entry pointer
+ * @freq: dump frequency in days
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_freq(mnt_fs *fs, int freq)
+{
+ assert(fs);
+ if (!fs)
+ return -1;
+ fs->freq = freq;
+ return 0;
+}
+
+/**
+ * mnt_fs_get_passno:
+ * @fs: fstab/mtab entry pointer
+ *
+ * Returns: "pass number on parallel fsck".
+ */
+int mnt_fs_get_passno(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->passno: 0;
+}
+
+/**
+ * mnt_fs_set_passno:
+ * @fs: fstab/mtab entry pointer
+ * @passno: pass number
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_set_passno(mnt_fs *fs, int passno)
+{
+ assert(fs);
+ if (!fs)
+ return -1;
+ fs->passno = passno;
+ return 0;
+}
+
+/**
+ * mnt_fs_get_id:
+ * @fs: /proc/self/mountinfo entry
+ *
+ * Returns: mount ID (unique identifier of the mount) or -1 if ID undefined
+ * (for example if @fs is not mountinfo entry).
+ */
+int mnt_fs_get_id(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->id : -1;
+}
+
+/**
+ * mnt_fs_get_parent_id:
+ * @fs: /proc/self/mountinfo entry
+ *
+ * Returns: parent mount ID or -1 if ID undefined (for example if @fs is not
+ * mountinfo entry).
+ */
+int mnt_fs_get_parent_id(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->parent : -1;
+}
+
+/**
+ * mnt_fs_get_devno:
+ * @fs: /proc/self/mountinfo
+ *
+ * Returns: value of st_dev for files on filesystem or 0 in case of error.
+ */
+dev_t mnt_fs_get_devno(mnt_fs *fs)
+{
+ assert(fs);
+ return fs ? fs->devno : 0;
+}
+
+/**
+ * mnt_fs_get_option:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ * @name: option name
+ * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @valsz: returns size of options value or 0
+ *
+ * Returns: 0 on success, 1 when not found the @name or -1 in case of error.
+ */
+int mnt_fs_get_option(mnt_fs *fs, const char *name,
+ char **value, size_t *valsz)
+{
+ char *optstr = (char *) mnt_fs_get_optstr(fs);
+ return optstr ? mnt_optstr_get_option(optstr, name, value, valsz) : 1;
+}
+
+/**
+ * mnt_fs_match_target:
+ * @fs: filesystem
+ * @target: mountpoint path
+ * @cache: tags/paths cache or NULL
+ *
+ * Possible are three attempts:
+ * 1) compare @target with @fs->target
+ * 2) realpath(@target) with @fs->target
+ * 3) realpath(@target) with realpath(@fs->target).
+ *
+ * The 2nd and 3rd attempts are not performed when @cache is NULL.
+ *
+ * Returns: 1 if @fs target is equal to @target else 0.
+ */
+int mnt_fs_match_target(mnt_fs *fs, const char *target, mnt_cache *cache)
+{
+ int rc = 0;
+
+ if (!fs || !target || !fs->target)
+ return 0;
+
+ /* 1) native paths */
+ rc = !strcmp(target, fs->target);
+
+ if (!rc && cache) {
+ /* 2) - canonicalized and non-canonicalized */
+ char *cn = mnt_resolve_path(target, cache);
+ rc = (cn && strcmp(cn, fs->target) == 0);
+
+ /* 3) - canonicalized and canonicalized */
+ if (!rc && cn) {
+ char *tcn = mnt_resolve_path(fs->target, cache);
+ rc = (tcn && strcmp(cn, tcn) == 0);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * mnt_fs_match_source:
+ * @fs: filesystem
+ * @source: tag or path (device or so)
+ * @cache: tags/paths cache or NULL
+ *
+ * Possible are four attempts:
+ * 1) compare @source with @fs->source
+ * 2) compare realpath(@source) with @fs->source
+ * 3) compare realpath(@source) with realpath(@fs->source)
+ * 4) compare realpath(@source) with evaluated tag from @fs->source
+ *
+ * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
+ * 2nd and 3rd attempts are not performed if @fs->source is tag.
+ *
+ * Returns: 1 if @fs source is equal to @source else 0.
+ */
+int mnt_fs_match_source(mnt_fs *fs, const char *source, mnt_cache *cache)
+{
+ char *cn;
+ const char *src, *t, *v;
+
+ if (!fs || !source || !fs->source)
+ return 0;
+
+ /* 1) native paths/tags */
+ if (!strcmp(source, fs->source))
+ return 1;
+
+ if (!cache)
+ return 0;
+ if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
+ return 0;
+
+ cn = mnt_resolve_spec(source, cache);
+ if (!cn)
+ return 0;
+
+ /* 2) canonicalized and native */
+ src = mnt_fs_get_srcpath(fs);
+ if (src && !strcmp(cn, src))
+ return 1;
+
+ /* 3) canonicalized and canonicalized */
+ if (src) {
+ src = mnt_resolve_path(src, cache);
+ if (src && !strcmp(cn, src))
+ return 1;
+ }
+ if (src || mnt_fs_get_tag(fs, &t, &v))
+ /* src path does not match and tag is not defined */
+ return 0;
+
+ /* read @source's tags to the cache */
+ if (mnt_cache_read_tags(cache, cn) < 0) {
+ if (errno == EACCES) {
+ /* we don't have permissions to read TAGs from
+ * @source, but can translate @fs tag to devname.
+ *
+ * (because libblkid uses udev symlinks and this is
+ * accessible for non-root uses)
+ */
+ char *x = mnt_resolve_tag(t, v, cache);
+ if (x && !strcmp(x, cn))
+ return 1;
+ }
+ return 0;
+ }
+
+ /* 4) has the @source a tag that matches with tag from @fs ? */
+ if (mnt_cache_device_has_tag(cache, cn, t, v))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * mnt_fs_match_fstype:
+ * @fs: filesystem
+ * @types: filesystem name or comma delimited list of filesystems
+ *
+ * For more details see mnt_match_fstype().
+ *
+ * Returns: 1 if @fs type is matching to @types else 0. The function returns
+ * 0 when types is NULL.
+ */
+int mnt_fs_match_fstype(mnt_fs *fs, const char *types)
+{
+ return mnt_match_fstype(fs->fstype, types);
+}
+
+/**
+ * mnt_fs_match_options:
+ * @fs: filesystem
+ * @options: comma delimited list of options (and nooptions)
+ *
+ * For more details see mnt_match_options().
+ *
+ * Returns: 1 if @fs type is matching to @options else 0. The function returns
+ * 0 when types is NULL.
+ */
+int mnt_fs_match_options(mnt_fs *fs, const char *options)
+{
+ return mnt_match_options(fs->optstr, options);
+}
+
+/* Unfortunately the classical Unix /etc/mtab and /etc/fstab
+ do not handle directory names containing spaces.
+ Here we mangle them, replacing a space by \040.
+ What do other Unices do? */
+
+static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
+
+static char *mangle(const char *s)
+{
+ char *ss, *sp;
+ int n;
+
+ n = strlen(s);
+ ss = sp = malloc(4*n+1);
+ if (!sp)
+ return NULL;
+ while(1) {
+ for (n = 0; n < sizeof(need_escaping); n++) {
+ if (*s == need_escaping[n]) {
+ *sp++ = '\\';
+ *sp++ = '0' + ((*s & 0300) >> 6);
+ *sp++ = '0' + ((*s & 070) >> 3);
+ *sp++ = '0' + (*s & 07);
+ goto next;
+ }
+ }
+ *sp++ = *s;
+ if (*s == 0)
+ break;
+ next:
+ s++;
+ }
+ return ss;
+}
+
+/**
+ * mnt_fprintf_line:
+ * @f: FILE
+ * @fmt: printf-like format string (see MNT_TAB_PRINTFMT)
+ * @source: (spec) device name or tag=value
+ * @target: mountpoint
+ * @fstype: filesystem type
+ * @options: mount options
+ * @freq: dump frequency in days
+ * @passno: pass number on parallel fsck
+ *
+ * It's recommended to use this function rather than directly call fprintf() to
+ * write an entry to mtab/fstab. All data in these files has to be properly
+ * formatted (for example space within paths/tags has to be escaped, see
+ * fstab(5) for more details).
+ *
+ * Returns: return value from fprintf().
+ */
+int mnt_fprintf_line( FILE *f,
+ const char *fmt,
+ const char *source,
+ const char *target,
+ const char *fstype,
+ const char *options,
+ int freq,
+ int passno)
+{
+ char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
+ int rc = -1;
+
+ if (!f || !fmt || !source || !target || !fstype || !options)
+ return -1;
+
+ m1 = mangle(source);
+ m2 = mangle(target);
+ m3 = mangle(fstype);
+ m4 = mangle(options);
+
+ if (!m1 || !m2 || !m3 || !m4)
+ goto done;
+
+ rc = fprintf(f, fmt, m1, m2, m3, m4, freq, passno);
+done:
+ free(m1);
+ free(m2);
+ free(m3);
+ free(m4);
+
+ return rc;
+}
+
+/**
+ * mnt_fs_fprintf:
+ * @fs: fstab/mtab/mountinfo entry
+ * @f: FILE
+ * @fmt: printf-like format string (see MNT_TAB_PRINTFMT)
+ *
+ * Returns: return value from fprintf().
+ */
+int mnt_fs_fprintf(mnt_fs *fs, FILE *f, const char *fmt)
+{
+ assert(fs);
+ assert(f);
+ assert(fmt);
+
+ if (!fs || !f)
+ return -1;
+
+ return mnt_fprintf_line(f, fmt,
+ mnt_fs_get_source(fs),
+ mnt_fs_get_target(fs),
+ mnt_fs_get_fstype(fs),
+ mnt_fs_get_optstr(fs),
+ mnt_fs_get_freq(fs),
+ mnt_fs_get_passno(fs));
+}
+
+/**
+ * mnt_fs_print_debug
+ * @fs: fstab/mtab/mountinfo entry
+ * @file: output
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_fs_print_debug(mnt_fs *fs, FILE *file)
+{
+ if (!fs)
+ return -1;
+ fprintf(file, "------ fs: %p\n", fs);
+ fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
+ fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
+ fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
+ fprintf(file, "optstr: %s\n", mnt_fs_get_optstr(fs));
+ fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
+ fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
+ fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
+ fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
+ fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
+ minor(mnt_fs_get_devno(fs)));
+
+
+ return 0;
+}
diff --git a/shlibs/mount/src/init.c b/shlibs/mount/src/init.c
new file mode 100644
index 00000000..68c13f94
--- /dev/null
+++ b/shlibs/mount/src/init.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 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 <stdlib.h>
+
+#include "mountP.h"
+
+int libmount_debug_mask;
+
+/**
+ * mnt_init_debug:
+ * @mask: debug mask (0xffff to enable full debuging)
+ *
+ * If the @mask is not specified then this function reads
+ * LIBMOUNT_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 mnt_init_debug(int mask)
+{
+ if (libmount_debug_mask & DEBUG_INIT)
+ return;
+ if (!mask) {
+ char *str = mnt_getenv_safe("LIBMOUNT_DEBUG");
+ if (str)
+ libmount_debug_mask = strtoul(str, 0, 0);
+ } else
+ libmount_debug_mask = mask;
+
+ if (libmount_debug_mask)
+ printf("libmount: debug mask set to 0x%04x.\n",
+ libmount_debug_mask);
+ libmount_debug_mask |= DEBUG_INIT;
+}
diff --git a/shlibs/mount/src/iter.c b/shlibs/mount/src/iter.c
new file mode 100644
index 00000000..5c02c2a7
--- /dev/null
+++ b/shlibs/mount/src/iter.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.
+ */
+
+/**
+ * SECTION: iter
+ * @title: Iterator
+ * @short_description: unified iterator
+ *
+ * The iterator keeps direction and last position for access to the internal
+ * library tables/lists.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mountP.h"
+
+/**
+ * mnt_new_iter:
+ * @direction: MNT_INTER_{FOR,BACK}WARD direction
+ *
+ * Returns: newly allocated generic libmount iterator.
+ */
+mnt_iter *mnt_new_iter(int direction)
+{
+ mnt_iter *itr = calloc(1, sizeof(struct _mnt_iter));
+ if (!itr)
+ return NULL;
+ itr->direction = direction;
+ return itr;
+}
+
+/**
+ * mnt_free_iter:
+ * @itr: iterator pointer
+ *
+ * Deallocates iterator.
+ */
+void mnt_free_iter(mnt_iter *itr)
+{
+ free(itr);
+}
+
+/**
+ * mnt_reset_iter:
+ * @itr: iterator pointer
+ * @direction: MNT_INTER_{FOR,BACK}WARD or -1 to keep the derection unchanged
+ *
+ * Resets iterator.
+ */
+void mnt_reset_iter(mnt_iter *itr, int direction)
+{
+ assert(itr);
+
+ if (direction == -1)
+ direction = itr->direction;
+
+ if (itr) {
+ memset(itr, 0, sizeof(struct _mnt_iter));
+ itr->direction = direction;
+ }
+}
+
+/**
+ * mnt_iter_get_direction:
+ * @itr: iterator pointer
+ *
+ * Returns: MNT_INTER_{FOR,BACK}WARD or -1 in case of error.
+ */
+int mnt_iter_get_direction(mnt_iter *itr)
+{
+ assert(itr);
+ return itr ? itr->direction : -1;
+}
diff --git a/shlibs/mount/src/lock.c b/shlibs/mount/src/lock.c
new file mode 100644
index 00000000..0f35aa3b
--- /dev/null
+++ b/shlibs/mount/src/lock.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: lock
+ * @title: Mtab locking
+ * @short_description: locking methods for work with /etc/mtab
+ *
+ * The lock is backwardly compatible with the standard linux /etc/mtab locking.
+ * Note, it's necessary to use the same locking schema in all application that
+ * access the file.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include "pathnames.h"
+#include "nls.h"
+
+#include "mountP.h"
+
+/*
+ * lock handler
+ */
+struct _mnt_lock {
+ pid_t id; /* getpid() or so (see linkfile)... */
+ char *lockfile; /* path to lock file (e.g. /etc/mtab~) */
+ char *linkfile; /* path to link file (e.g. /etc/mtab~.<id>) */
+ int lockfile_fd; /* lock file descriptor */
+ int locked; /* do we own the lock? */
+};
+
+
+/**
+ * mnt_new_lock:
+ * @lockfile: path to lockfile or NULL (default is _PATH_MOUNTED_LOCK)
+ * @id: unique linkfile identifier or 0 (default is getpid())
+ *
+ * Returns: newly allocated lock handler or NULL on case of error.
+ */
+mnt_lock *mnt_new_lock(const char *lockfile, pid_t id)
+{
+ mnt_lock *ml = calloc(1, sizeof(struct _mnt_lock));
+
+ if (!ml)
+ return NULL;
+
+ ml->lockfile_fd = -1;
+ ml->id = id;
+ if (lockfile) {
+ ml->lockfile = strdup(lockfile);
+ if (!ml->lockfile) {
+ free(ml);
+ return NULL;
+ }
+ }
+ return ml;
+}
+
+/**
+ * mnt_free_lock:
+ * @ml: mnt_lock handler
+ *
+ * Deallocates mnt_lock.
+ */
+void mnt_free_lock(mnt_lock *ml)
+{
+ if (!ml)
+ return;
+ free(ml->lockfile);
+ free(ml->linkfile);
+ free(ml);
+}
+
+/**
+ * mnt_lock_get_lockfile:
+ * @ml: mnt_lock handler
+ *
+ * Returns: path to lockfile.
+ */
+const char *mnt_lock_get_lockfile(mnt_lock *ml)
+{
+ if (!ml)
+ return NULL;
+ if (ml->lockfile)
+ return ml->lockfile;
+ return _PATH_MOUNTED_LOCK;
+}
+
+/**
+ * mnt_lock_get_linkfile:
+ * @ml: mnt_lock handler
+ *
+ * Returns: unique (per process) path to linkfile.
+ */
+const char *mnt_lock_get_linkfile(mnt_lock *ml)
+{
+ if (!ml)
+ return NULL;
+
+ if (!ml->linkfile) {
+ const char *lf = mnt_lock_get_lockfile(ml);
+ size_t sz;
+
+ if (!lf)
+ return NULL;
+ sz = strlen(lf) + 32;
+
+ ml->linkfile = malloc(sz);
+ if (ml->linkfile)
+ snprintf(ml->linkfile, sz, "%s.%d",
+ lf, ml->id ? ml->id : getpid());
+ }
+ return ml->linkfile;
+}
+
+static void mnt_lockalrm_handler(int sig)
+{
+ /* do nothing, say nothing, be nothing */
+}
+
+/*
+ * Waits for F_SETLKW, unfortunately we have to use SIGALRM here to interrupt
+ * fcntl() to avoid never ending waiting.
+ *
+ * Returns: 0 on success, 1 on timeout, -errno on error.
+ */
+static int mnt_wait_lock(mnt_lock *ml, struct flock *fl, time_t maxtime)
+{
+ struct timeval now;
+ struct sigaction sa, osa;
+ int ret = 0;
+
+ gettimeofday(&now, NULL);
+
+ if (now.tv_sec >= maxtime)
+ return 1; /* timeout */
+
+ /* setup ALARM handler -- we don't want to wait forever */
+ sa.sa_flags = 0;
+ sa.sa_handler = mnt_lockalrm_handler;
+ sigfillset (&sa.sa_mask);
+
+ sigaction(SIGALRM, &sa, &osa);
+
+ DBG(DEBUG_LOCKS, fprintf(stderr,
+ "LOCK: (%d) waiting for F_SETLKW.\n", getpid()));
+
+ alarm(maxtime - now.tv_sec);
+ if (fcntl(ml->lockfile_fd, F_SETLKW, fl) == -1)
+ ret = errno == EINTR ? 1 : -errno;
+ alarm(0);
+
+ /* restore old sigaction */
+ sigaction(SIGALRM, &osa, NULL);
+
+ DBG(DEBUG_LOCKS, fprintf(stderr,
+ "LOCK: (%d) leaving mnt_wait_setlkw(), rc=%d.\n", getpid(), ret));
+ return ret;
+}
+
+/*
+ * Create the lock file.
+ *
+ * The old code here used flock on a lock file /etc/mtab~ and deleted
+ * this lock file afterwards. However, as rgooch remarks, that has a
+ * race: a second mount may be waiting on the lock and proceed as
+ * soon as the lock file is deleted by the first mount, and immediately
+ * afterwards a third mount comes, creates a new /etc/mtab~, applies
+ * flock to that, and also proceeds, so that the second and third mount
+ * now both are scribbling in /etc/mtab.
+ *
+ * The new code uses a link() instead of a creat(), where we proceed
+ * only if it was us that created the lock, and hence we always have
+ * to delete the lock afterwards. Now the use of flock() is in principle
+ * superfluous, but avoids an arbitrary sleep().
+ *
+ * Where does the link point to? Obvious choices are mtab and mtab~~.
+ * HJLu points out that the latter leads to races. Right now we use
+ * mtab~.<pid> instead.
+ *
+ *
+ * The original mount locking code has used sleep(1) between attempts and
+ * maximal number of attempts has been 5.
+ *
+ * There was very small number of attempts and extremely long waiting (1s)
+ * that is useless on machines with large number of mount processes.
+ *
+ * Now we wait few thousand microseconds between attempts and we have a global
+ * time limit (30s) rather than limit for number of attempts. The advantage
+ * is that this method also counts time which we spend in fcntl(F_SETLKW) and
+ * number of attempts is not restricted.
+ * -- kzak@redhat.com [Mar-2007]
+ *
+ *
+ * This mtab locking code has been refactored and moved to libmount. The mtab
+ * locking is really not perfect (e.g. SIGALRM), but it's stable, reliable and
+ * backwardly compatible code. Don't forget that this code has to be compatible
+ * with 3rd party mounts (/sbin/mount.<foo>) and has to work with NFS.
+ * -- kzak@redhat.com [May-2009]
+ */
+
+/* maximum seconds between first and last attempt */
+#define MOUNTLOCK_MAXTIME 30
+
+/* sleep time (in microseconds, max=999999) between attempts */
+#define MOUNTLOCK_WAITTIME 5000
+
+/* Remove lock file. */
+void mnt_unlock_file(mnt_lock *ml)
+{
+ if (!ml)
+ return;
+
+ DBG(DEBUG_LOCKS, fprintf(stderr, "LOCK: (%d) unlocking/cleaning.\n", getpid()));
+
+ if (ml->locked == 0 && ml->lockfile && ml->linkfile)
+ {
+ /* We have (probably) all files, but we don't own the lock,
+ * Really? Check it! Maybe ml->locked wasn't set properly
+ * because code was interrupted by signal. Paranoia? Yes.
+ *
+ * We own the lock when linkfile == lockfile.
+ */
+ struct stat lo, li;
+
+ if (!stat(ml->lockfile, &lo) && !stat(ml->linkfile, &li) &&
+ lo.st_dev == li.st_dev && lo.st_ino == li.st_ino)
+ ml->locked = 1;
+ }
+ if (ml->linkfile)
+ unlink(ml->linkfile);
+ if (ml->lockfile_fd >= 0)
+ close(ml->lockfile_fd);
+ if (ml->locked == 1 && ml->lockfile)
+ unlink(ml->lockfile);
+
+ ml->locked = 0;
+ ml->lockfile_fd = -1;
+}
+
+/**
+ * mnt_lock_file
+ * @ml: pointer to mnt_lock instance
+ *
+ * Creates lock file (e.g. /etc/mtab~). Note that this function uses
+ * alarm().
+ *
+ * Your application has to always call mnt_unlock_file() before exit.
+ *
+ * Locking scheme:
+ *
+ * 1. create linkfile (e.g. /etc/mtab~.$PID)
+ * 2. link linkfile --> lockfile (e.g. /etc/mtab~.$PID --> /etc/mtab~)
+ *
+ * 3. a) link() success: setups F_SETLK lock (see fcnlt(2))
+ * b) link() failed: wait (max 30s) on F_SETLKW lock, goto 2.
+ *
+ * Example:
+ *
+ * <informalexample>
+ * <programlisting>
+ * mnt_lock *ml;
+ *
+ * void unlock_fallback(void)
+ * {
+ * if (!ml)
+ * return;
+ * mnt_unlock_file(ml);
+ * mnt_free_lock(ml);
+ * }
+ *
+ * int update_mtab()
+ * {
+ * int sig = 0;
+ *
+ * atexit(unlock_fallback);
+ *
+ * ml = mnt_new_lock(NULL, 0);
+ *
+ * if (mnt_lock_file(ml) != 0) {
+ * printf(stderr, "cannot create %s lockfile\n",
+ * mnt_lock_get_lockfile(ml));
+ * return -1;
+ * }
+ *
+ * ... modify mtab ...
+ *
+ * mnt_unlock_file(ml);
+ * mnt_free_lock(ml);
+ * ml = NULL;
+ * return 0;
+ * }
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_lock_file(mnt_lock *ml)
+{
+ int i;
+ struct timespec waittime;
+ struct timeval maxtime;
+ const char *lockfile, *linkfile;
+
+ if (!ml)
+ return -1;
+ if (ml->locked)
+ return 0;
+
+ lockfile = mnt_lock_get_lockfile(ml);
+ if (!lockfile)
+ return -1;
+ linkfile = mnt_lock_get_linkfile(ml);
+ if (!linkfile)
+ return -1;
+
+ i = open(linkfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+ if (i < 0)
+ /* linkfile does not exist (as a file)
+ and we cannot create it. Read-only filesystem?
+ Too many files open in the system?
+ Filesystem full? */
+ goto failed;
+
+ close(i);
+
+ gettimeofday(&maxtime, NULL);
+ maxtime.tv_sec += MOUNTLOCK_MAXTIME;
+
+ waittime.tv_sec = 0;
+ waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
+
+ /* Repeat until it was us who made the link */
+ while (ml->locked == 0) {
+ struct timeval now;
+ struct flock flock;
+ int j;
+
+ j = link(linkfile, lockfile);
+ if (j == 0)
+ ml->locked = 1;
+
+ if (j < 0 && errno != EEXIST)
+ goto failed;
+
+ ml->lockfile_fd = open(lockfile, O_WRONLY);
+
+ if (ml->lockfile_fd < 0) {
+ /* Strange... Maybe the file was just deleted? */
+ int errsv = errno;
+ gettimeofday(&now, NULL);
+ if (errsv == ENOENT && now.tv_sec < maxtime.tv_sec) {
+ ml->locked = 0;
+ continue;
+ }
+ goto failed;
+ }
+
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+
+ if (ml->locked) {
+ /* We made the link. Now claim the lock. */
+ if (fcntl (ml->lockfile_fd, F_SETLK, &flock) == -1) {
+ DBG(DEBUG_LOCKS, fprintf(stderr,
+ "%s: can't F_SETLK lockfile, errno=%d\n",
+ lockfile, errno));
+ /* proceed, since it was us who created the lockfile anyway */
+ }
+ break;
+ } else {
+ /* Someone else made the link. Wait. */
+ int err = mnt_wait_lock(ml, &flock, maxtime.tv_sec);
+
+ if (err == 1) {
+ DBG(DEBUG_LOCKS, fprintf(stderr,
+ "%s: can't create link: time out (perhaps "
+ "there is a stale lock file?)", lockfile));
+ goto failed;
+
+ } else if (err < 0)
+ goto failed;
+
+ nanosleep(&waittime, NULL);
+ close(ml->lockfile_fd);
+ ml->lockfile_fd = -1;
+ }
+ }
+ DBG(DEBUG_LOCKS, fprintf(stderr,
+ "LOCK: %s: (%d) successfully locked\n",
+ ml->lockfile, getpid()));
+ unlink(linkfile);
+ return 0;
+
+failed:
+ mnt_unlock_file(ml);
+ return -1;
+}
+
+#ifdef TEST_PROGRAM
+#include <err.h>
+
+mnt_lock *lock;
+
+/*
+ * read number from @filename, increment the number and
+ * write the number back to the file
+ */
+void increment_data(const char *filename, int verbose, int loopno)
+{
+ long num;
+ FILE *f;
+ char buf[256];
+
+ if (!(f = fopen(filename, "r")))
+ err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
+
+ if (!fgets(buf, sizeof(buf), f))
+ err(EXIT_FAILURE, "%d failed read: %s", getpid(), filename);
+
+ fclose(f);
+ num = atol(buf) + 1;
+
+ if (!(f = fopen(filename, "w")))
+ err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
+
+ fprintf(f, "%ld", num);
+ fclose(f);
+
+ if (verbose)
+ fprintf(stderr, "%d: %s: %ld --> %ld (loop=%d)\n", getpid(),
+ filename, num - 1, num, loopno);
+}
+
+void clean_lock(void)
+{
+ fprintf(stderr, "%d: cleaning\n", getpid());
+ if (!lock)
+ return;
+ mnt_unlock_file(lock);
+ mnt_free_lock(lock);
+}
+
+void sig_handler(int sig)
+{
+ errx(EXIT_FAILURE, "\n%d: catch signal: %s\n", getpid(), strsignal(sig));
+}
+
+int test_lock(struct mtest *ts, int argc, char *argv[])
+{
+ const char *lockfile, *datafile;
+ int verbose = 0, loops, l;
+
+ if (argc < 4)
+ return -1;
+
+ lockfile = argv[1];
+ datafile = argv[2];
+ loops = atoi(argv[3]);
+
+ if (argc == 5 && strcmp(argv[4], "--verbose") == 0)
+ verbose = 1;
+
+ atexit(clean_lock);
+
+ /* be paranoid and call exit() (=clean_lock()) for all signals */
+ {
+ int sig = 0;
+ struct sigaction sa;
+
+ sa.sa_handler = sig_handler;
+ sa.sa_flags = 0;
+ sigfillset(&sa.sa_mask);
+
+ while (sigismember(&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD)
+ sigaction (sig, &sa, (struct sigaction *) 0);
+ }
+
+ for (l = 0; l < loops; l++) {
+ lock = mnt_new_lock(lockfile, 0);
+
+ if (mnt_lock_file(lock) == -1) {
+ fprintf(stderr, "%d: failed to create lock file: %s\n",
+ getpid(), lockfile);
+ return -1;
+ }
+
+ increment_data(datafile, verbose, l);
+
+ mnt_unlock_file(lock);
+ mnt_free_lock(lock);
+ lock = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Note that this test should be executed from a script that creates many
+ * parallel processes, otherwise this test does not make sense.
+ */
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--lock", test_lock, " <lockfile> <datafile> <loops> [--verbose] increment number in datafile" },
+ { NULL }
+ };
+
+ return mnt_run_test(tss, argc, argv);
+}
+
+#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in
new file mode 100644
index 00000000..cd9159cc
--- /dev/null
+++ b/shlibs/mount/src/mount.h.in
@@ -0,0 +1,407 @@
+/*
+ * mount.h - libmount API
+ *
+ * Copyright (C) 2008-2009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LIBMOUNT_MOUNT_H
+#define _LIBMOUNT_MOUNT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef USE_UNSTABLE_LIBMOUNT_API
+# warning libmount API is not stable yet!
+#endif
+
+#include <stdio.h>
+
+
+#define LIBMOUNT_VERSION "@LIBMOUNT_VERSION@"
+
+/**
+ * mnt_cache:
+ *
+ * Stores canonicalized paths and evaluated tags
+ */
+typedef struct _mnt_cache mnt_cache;
+
+/**
+ * mnt_lock:
+ *
+ * Stores information about locked file (e.g. /etc/mtab)
+ */
+typedef struct _mnt_lock mnt_lock;
+
+/**
+ * mnt_iter:
+ *
+ * Generic iterator (stores state about lists)
+ */
+typedef struct _mnt_iter mnt_iter;
+
+/**
+ * mnt_optls:
+ *
+ * Mount options list (stores parsed mount options)
+ */
+typedef struct _mnt_optls mnt_optls;
+
+/**
+ * mnt_optent:
+ *
+ * Parsed mount option - "mnt_optls" entry
+ */
+typedef struct _mnt_optent mnt_optent;
+
+/**
+ * mnt_optmap:
+ *
+ * Mount options description (map)
+ */
+struct mnt_optmap
+{
+ const char *name; /* option name[=%<type>] (e.g. "loop[=%s]") */
+ int id; /* option ID or MS_* flags (e.g MS_RDONLY) */
+ int mask; /* MNT_{MFLAG,MDATA,INVMASK,...} mask */
+};
+
+/*
+ * mount options map masks
+ */
+#define MNT_MFLAG (1 << 1) /* use the mask as mount(2) flag */
+#define MNT_MDATA (1 << 2) /* use the option as mount(2) data */
+#define MNT_INVERT (1 << 3) /* invert the mountflag */
+#define MNT_NOMTAB (1 << 4) /* skip in the mtab option string */
+
+/**
+ * mnt_fs:
+ *
+ * Parsed fstab/mtab/mountinfo entry
+ */
+typedef struct _mnt_fs mnt_fs;
+
+/**
+ * mnt_tab:
+ *
+ * List of mnt_fs entries (parsed fstab/mtab/mountinfo)
+ */
+typedef struct _mnt_tab mnt_tab;
+
+/* init.c */
+extern void mnt_init_debug(int mask);
+
+/* version.c */
+extern int mnt_parse_version_string(const char *ver_string);
+extern int mnt_get_library_version(const char **ver_string);
+
+/* utils.c */
+extern int mnt_fstype_is_netfs(const char *type);
+extern int mnt_fstype_is_pseudofs(const char *type);
+extern int mnt_match_fstype(const char *type, const char *pattern);
+extern int mnt_match_options(const char *optstr, const char *pattern);
+
+/* cache.c */
+extern mnt_cache *mnt_new_cache(void);
+extern void mnt_free_cache(mnt_cache *cache);
+extern const char *mnt_cache_find_path(mnt_cache *cache, const char *path);
+extern const char *mnt_cache_find_tag(mnt_cache *cache,
+ const char *token, const char *value);
+extern int mnt_cache_read_tags(mnt_cache *cache, const char *devname);
+extern int mnt_cache_device_has_tag(mnt_cache *cache, const char *devname,
+ const char *token, const char *value);
+
+extern char *mnt_cache_find_tag_value(mnt_cache *cache,
+ const char *devname, const char *token);
+
+extern char *mnt_resolve_path(const char *path, mnt_cache *cache);
+extern char *mnt_resolve_tag(const char *token, const char *value, mnt_cache *cache);
+extern char *mnt_resolve_spec(const char *spec, mnt_cache *cache);
+
+/* optstr.c */
+extern int mnt_optstr_next_option(char **optstr, char **name, size_t *namesz,
+ char **value, size_t *valuesz);
+extern int mnt_optstr_append_option(char **optstr, const char *name,
+ const char *value);
+extern int mnt_optstr_get_option(char *optstr, const char *name,
+ char **value, size_t *valsz);
+extern int mnt_optstr_set_option(char **optstr, const char *name,
+ const char *value);
+extern int mnt_optstr_remove_option(char **optstr, const char *name);
+
+/* iter.c */
+enum {
+
+ MNT_ITER_FORWARD = 0,
+ MNT_ITER_BACKWARD
+};
+extern mnt_iter *mnt_new_iter(int direction);
+extern void mnt_free_iter(mnt_iter *mi);
+extern void mnt_reset_iter(mnt_iter *mi, int direction);
+extern int mnt_iter_get_direction(mnt_iter *itr);
+
+/* optmap.c */
+enum {
+ MNT_LINUX_MAP = 1,
+ MNT_USERSPACE_MAP
+};
+extern const struct mnt_optmap *mnt_get_builtin_optmap(int id);
+
+/* optent.c */
+extern const struct mnt_optmap *mnt_optent_get_map(mnt_optent *op);
+extern const struct mnt_optmap *mnt_optent_get_mapent(mnt_optent *op);
+extern const char *mnt_optent_get_type(mnt_optent *op);
+extern int mnt_optent_set_value(mnt_optent *op, const char *data);
+extern int mnt_optent_has_value(mnt_optent *op);
+extern int mnt_optent_require_value(mnt_optent *op);
+extern int mnt_optent_is_inverted(mnt_optent *op);
+extern int mnt_optent_strtoul_value(mnt_optent *op, unsigned long int *number);
+extern int mnt_optent_strtol_value(mnt_optent *op, long int *number);
+extern int mnt_optent_strtoull_value(mnt_optent *op, unsigned long long int *number);
+extern const char *mnt_optent_get_value(mnt_optent *op);
+extern int mnt_optent_strlen_value(mnt_optent *op);
+extern int mnt_optent_snprintf_value(mnt_optent *op, char *str, size_t size);
+extern char *mnt_optent_dup_value(mnt_optent *op);
+extern const char *mnt_optent_get_name(mnt_optent *op);
+extern int mnt_optent_get_mask(mnt_optent *op);
+extern int mnt_optent_get_id(mnt_optent *op);
+extern int mnt_optent_get_flag(mnt_optent *op, int *flags);
+extern int mnt_optent_is_unknown(mnt_optent *op);
+extern int mnt_optent_print_debug(mnt_optent *op, FILE *file);
+
+/* optls.c */
+extern mnt_optls *mnt_new_optls(void);
+extern void mnt_free_optls(mnt_optls *ls);
+extern int mnt_optls_add_map(mnt_optls *ls, const struct mnt_optmap *map);
+extern int mnt_optls_add_builtin_map(mnt_optls *ls, int id);
+extern mnt_optent *mnt_optls_add_option(mnt_optls *ls,
+ const char *name, const char *value);
+extern int mnt_optls_parse_optstr(mnt_optls *ls, const char *optstr);
+extern int mnt_optls_remove_option(mnt_optls *ls, const char *name);
+extern int mnt_optls_remove_option_by_flags(mnt_optls *ls,
+ const struct mnt_optmap *map, const int flags);
+extern int mnt_optls_remove_option_by_iflags(mnt_optls *ls,
+ const struct mnt_optmap *map, const int flags);
+extern int mnt_optls_next_option(mnt_optls *ls, mnt_iter *itr,
+ const struct mnt_optmap *map, mnt_optent **option);
+extern mnt_optent *mnt_optls_get_option(mnt_optls *ls, const char *name);
+extern int mnt_optls_get_ids(mnt_optls *ls, const struct mnt_optmap *map);
+extern int mnt_optls_create_mountflags(mnt_optls *ls);
+extern char *mnt_optls_create_mountdata(mnt_optls *ls);
+extern char *mnt_optls_create_mtab_optstr(mnt_optls *ls);
+extern char *mnt_optls_create_userspace_optstr(mnt_optls *ls);
+extern int mnt_optls_print_debug(mnt_optls *ls, FILE *file);
+
+/* lock.c */
+extern mnt_lock *mnt_new_lock(const char *lockfile, pid_t id);
+extern void mnt_free_lock(mnt_lock *ml);
+extern const char *mnt_lock_get_lockfile(mnt_lock *ml);
+extern const char *mnt_lock_get_linkfile(mnt_lock *ml);
+extern void mnt_unlock_file(mnt_lock *ml);
+extern int mnt_lock_file(mnt_lock *ml);
+
+/* fs.c */
+extern mnt_fs *mnt_new_fs(void);
+extern void mnt_free_fs(mnt_fs *ent);
+extern void *mnt_fs_get_userdata(mnt_fs *fs);
+extern int mnt_fs_set_userdata(mnt_fs *fs, void *data);
+extern const char *mnt_fs_get_source(mnt_fs *ent);
+extern int mnt_fs_set_source(mnt_fs *ent, const char *source);
+extern const char *mnt_fs_get_srcpath(mnt_fs *ent);
+extern int mnt_fs_get_tag(mnt_fs *ent, const char **name, const char **value);
+extern const char *mnt_fs_get_target(mnt_fs *ent);
+extern int mnt_fs_set_target(mnt_fs *ent, const char *target);
+extern const char *mnt_fs_get_fstype(mnt_fs *ent);
+extern int mnt_fs_set_fstype(mnt_fs *ent, const char *fstype);
+extern const char *mnt_fs_get_optstr(mnt_fs *ent);
+extern int mnt_fs_set_optstr(mnt_fs *ent, const char *optstr);
+extern const char *mnt_fs_get_vfs_optstr(mnt_fs *ent);
+extern const char *mnt_fs_get_fs_optstr(mnt_fs *ent);
+extern int mnt_fs_get_freq(mnt_fs *ent);
+extern int mnt_fs_set_freq(mnt_fs *ent, int freq);
+extern int mnt_fs_get_passno(mnt_fs *ent);
+extern int mnt_fs_set_passno(mnt_fs *ent, int passno);
+extern int mnt_fs_get_id(mnt_fs *fs);
+extern int mnt_fs_get_parent_id(mnt_fs *fs);
+extern dev_t mnt_fs_get_devno(mnt_fs *fs);
+extern int mnt_fs_get_option(mnt_fs *ent, const char *name,
+ char **value, size_t *valsz);
+
+extern int mnt_fs_match_target(mnt_fs *fs, const char *target, mnt_cache *cache);
+extern int mnt_fs_match_source(mnt_fs *fs, const char *source, mnt_cache *cache);
+extern int mnt_fs_match_fstype(mnt_fs *fs, const char *types);
+extern int mnt_fs_match_options(mnt_fs *fs, const char *options);
+
+/* mtab/fstab line */
+#define MNT_TAB_PRINTFMT "%s %s %s %s %d %d\n"
+
+extern int mnt_fprintf_line(
+ FILE *f,
+ const char *fmt,
+ const char *source,
+ const char *target,
+ const char *fstype,
+ const char *options,
+ int freq,
+ int passno);
+
+extern int mnt_fs_fprintf(mnt_fs *ent, FILE *f, const char *fmt);
+extern int mnt_fs_print_debug(mnt_fs *ent, FILE *file);
+
+/* tab-parse.c */
+extern mnt_tab *mnt_new_tab_from_file(const char *filename);
+extern int mnt_tab_parse_file(mnt_tab *tb);
+extern char *mnt_tab_strerror(mnt_tab *tb, char *buf, size_t buflen);
+extern int mnt_tab_get_nerrs(mnt_tab *tb);
+
+/* tab.c */
+extern mnt_tab *mnt_new_tab(const char *filename);
+extern void mnt_free_tab(mnt_tab *tb);
+extern int mnt_tab_get_nents(mnt_tab *tb);
+extern int mnt_tab_set_cache(mnt_tab *tb, mnt_cache *mpc);
+extern mnt_cache *mnt_tab_get_cache(mnt_tab *tb);
+extern const char *mnt_tab_get_name(mnt_tab *tb);
+extern int mnt_tab_add_fs(mnt_tab *tb, mnt_fs *fs);
+extern int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs);
+extern int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs);
+extern int mnt_tab_next_child_fs(mnt_tab *tb, mnt_iter *itr,
+ mnt_fs *parent, mnt_fs **chld);
+extern int mnt_tab_get_root_fs(mnt_tab *tb, mnt_fs **root);
+extern int mnt_tab_set_iter(mnt_tab *tb, mnt_iter *itr, mnt_fs *fs);
+
+extern mnt_fs *mnt_tab_find_target(mnt_tab *tb, const char *path, int direction);
+extern mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction);
+extern mnt_fs *mnt_tab_find_tag(mnt_tab *tb, const char *tag,
+ const char *val, int direction);
+extern mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction);
+
+extern int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
+ int (*match_func)(mnt_fs *, void *), void *userdata,
+ mnt_fs **fs);
+
+extern int mnt_tab_fprintf(mnt_tab *tb, FILE *f, const char *fmt);
+extern int mnt_tab_update_file(mnt_tab *tb);
+
+
+/*
+ * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
+ */
+#define MNT_MS_DFLTS (1 << 1)
+#define MNT_MS_NOAUTO (1 << 2)
+#define MNT_MS_USER (1 << 3)
+#define MNT_MS_USERS (1 << 4)
+#define MNT_MS_OWNER (1 << 5)
+#define MNT_MS_GROUP (1 << 6)
+#define MNT_MS_NETDEV (1 << 7)
+#define MNT_MS_COMMENT (1 << 8)
+#define MNT_MS_LOOP (1 << 9)
+#define MNT_MS_NOFAIL (1 << 10)
+
+/*
+ * mount(2) MS_* masks (MNT_MAP_LINUX map)
+ */
+#ifndef MS_RDONLY
+#define MS_RDONLY 1 /* Mount read-only */
+#endif
+#ifndef MS_NOSUID
+#define MS_NOSUID 2 /* Ignore suid and sgid bits */
+#endif
+#ifndef MS_NODEV
+#define MS_NODEV 4 /* Disallow access to device special files */
+#endif
+#ifndef MS_NOEXEC
+#define MS_NOEXEC 8 /* Disallow program execution */
+#endif
+#ifndef MS_SYNCHRONOUS
+#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
+#endif
+#ifndef MS_REMOUNT
+#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
+#endif
+#ifndef MS_MANDLOCK
+#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
+#endif
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
+#endif
+#ifndef MS_NOATIME
+#define MS_NOATIME 0x400 /* 1024: Do not update access times. */
+#endif
+#ifndef MS_NODIRATIME
+#define MS_NODIRATIME 0x800 /* 2048: Don't update directory access times */
+#endif
+#ifndef MS_BIND
+#define MS_BIND 0x1000 /* 4096: Mount existing tree also elsewhere */
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE 0x2000 /* 8192: Atomically move tree */
+#endif
+#ifndef MS_REC
+#define MS_REC 0x4000 /* 16384: Recursive loopback */
+#endif
+#ifndef MS_VERBOSE
+#define MS_VERBOSE 0x8000 /* 32768 */
+#endif
+#ifndef MS_RELATIME
+#define MS_RELATIME 0x200000 /* 200000: Update access times relative
+ to mtime/ctime */
+#endif
+#ifndef MS_UNBINDABLE
+#define MS_UNBINDABLE (1<<17) /* 131072 unbindable*/
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18) /* 262144 Private*/
+#endif
+#ifndef MS_SLAVE
+#define MS_SLAVE (1<<19) /* 524288 Slave*/
+#endif
+#ifndef MS_SHARED
+#define MS_SHARED (1<<20) /* 1048576 Shared*/
+#endif
+#ifndef MS_I_VERSION
+#define MS_I_VERSION (1<<23) /* update inode I_version field */
+#endif
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME (1<<24) /* strict atime semantics */
+#endif
+
+/*
+ * Magic mount flag number. Had to be or-ed to the flag values.
+ */
+#ifndef MS_MGC_VAL
+#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */
+#endif
+#ifndef MS_MGC_MSK
+#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */
+#endif
+
+
+/* Shared-subtree options */
+#define MS_PROPAGATION (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
+
+/* Options that we make ordinary users have by default. */
+#define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
+
+/* Options that we make owner-mounted devices have by default */
+#define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBMOUNT_MOUNT_H */
diff --git a/shlibs/mount/src/mount.sym b/shlibs/mount/src/mount.sym
new file mode 100644
index 00000000..819be0f1
--- /dev/null
+++ b/shlibs/mount/src/mount.sym
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+MOUNT_2.18 {
+global:
+ mnt_cache_device_has_tag;
+ mnt_cache_find_path;
+ mnt_cache_find_tag;
+ mnt_cache_find_tag_value;
+ mnt_cache_read_tags;
+ mnt_fprintf_line;
+ mnt_free_cache;
+ mnt_free_fs;
+ mnt_free_iter;
+ mnt_free_lock;
+ mnt_free_optls;
+ mnt_free_tab;
+ mnt_fs_fprintf;
+ mnt_fs_get_devno;
+ mnt_fs_get_freq;
+ mnt_fs_get_fstype;
+ mnt_fs_get_id;
+ mnt_fs_get_fs_optstr;
+ mnt_fs_get_option;
+ mnt_fs_get_optstr;
+ mnt_fs_get_vfs_optstr;
+ mnt_fs_get_parent_id;
+ mnt_fs_get_passno;
+ mnt_fs_get_source;
+ mnt_fs_get_srcpath;
+ mnt_fs_get_tag;
+ mnt_fs_get_target;
+ mnt_fs_get_userdata;
+ mnt_fs_match_fstype;
+ mnt_fs_match_options;
+ mnt_fs_match_source;
+ mnt_fs_match_target;
+ mnt_fs_print_debug;
+ mnt_fs_set_freq;
+ mnt_fs_set_fstype;
+ mnt_fs_set_optstr;
+ mnt_fs_set_passno;
+ mnt_fs_set_source;
+ mnt_fs_set_target;
+ mnt_fs_set_userdata;
+ mnt_fstype_is_netfs;
+ mnt_fstype_is_pseudofs;
+ mnt_get_builtin_optmap;
+ mnt_get_library_version;
+ mnt_iter_get_direction;
+ mnt_lock_file;
+ mnt_lock_get_linkfile;
+ mnt_lock_get_lockfile;
+ mnt_match_fstype;
+ mnt_match_options;
+ mnt_new_cache;
+ mnt_new_fs;
+ mnt_new_iter;
+ mnt_new_lock;
+ mnt_new_optls;
+ mnt_new_tab;
+ mnt_new_tab_from_file;
+ mnt_optent_dup_value;
+ mnt_optent_get_flag;
+ mnt_optent_get_id;
+ mnt_optent_get_map;
+ mnt_optent_get_mapent;
+ mnt_optent_get_mask;
+ mnt_optent_get_name;
+ mnt_optent_get_type;
+ mnt_optent_get_value;
+ mnt_optent_has_value;
+ mnt_optent_is_inverted;
+ mnt_optent_is_unknown;
+ mnt_optent_print_debug;
+ mnt_optent_require_value;
+ mnt_optent_set_value;
+ mnt_optent_snprintf_value;
+ mnt_optent_strlen_value;
+ mnt_optent_strtol_value;
+ mnt_optent_strtoull_value;
+ mnt_optent_strtoul_value;
+ mnt_optls_add_builtin_map;
+ mnt_optls_add_map;
+ mnt_optls_add_option;
+ mnt_optls_create_mountdata;
+ mnt_optls_create_mountflags;
+ mnt_optls_create_mtab_optstr;
+ mnt_optls_create_userspace_optstr;
+ mnt_optls_get_ids;
+ mnt_optls_get_option;
+ mnt_optls_next_option;
+ mnt_optls_parse_optstr;
+ mnt_optls_print_debug;
+ mnt_optls_remove_option;
+ mnt_optls_remove_option_by_flags;
+ mnt_optls_remove_option_by_iflags;
+ mnt_optstr_append_option;
+ mnt_optstr_get_option;
+ mnt_optstr_next_option;
+ mnt_optstr_remove_option;
+ mnt_optstr_set_option;
+ mnt_parse_version_string;
+ mnt_reset_iter;
+ mnt_resolve_path;
+ mnt_resolve_spec;
+ mnt_resolve_tag;
+ mnt_tab_add_fs;
+ mnt_tab_find_next_fs;
+ mnt_tab_find_source;
+ mnt_tab_find_srcpath;
+ mnt_tab_find_tag;
+ mnt_tab_find_target;
+ mnt_tab_fprintf;
+ mnt_tab_get_cache;
+ mnt_tab_get_name;
+ mnt_tab_get_nents;
+ mnt_tab_get_nerrs;
+ mnt_tab_get_root_fs;
+ mnt_tab_next_child_fs;
+ mnt_tab_next_fs;
+ mnt_tab_parse_file;
+ mnt_tab_remove_fs;
+ mnt_tab_set_cache;
+ mnt_tab_set_iter;
+ mnt_tab_strerror;
+ mnt_tab_update_file;
+ mnt_unlock_file;
+ mnt_init_debug;
+local:
+ *;
+};
diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h
new file mode 100644
index 00000000..ddd86ea2
--- /dev/null
+++ b/shlibs/mount/src/mountP.h
@@ -0,0 +1,222 @@
+/*
+ * mountP.h - private library header file
+ *
+ * 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 _LIBMOUNT_PRIVATE_H
+#define _LIBMOUNT_PRIVATE_H
+
+#include <sys/types.h>
+
+#define USE_UNSTABLE_LIBMOUNT_API
+
+#include "mount.h"
+#include "list.h"
+
+/* features */
+#define CONFIG_LIBMOUNT_ASSERT
+#define CONFIG_LIBMOUNT_DEBUG
+
+#ifdef CONFIG_LIBMOUNT_ASSERT
+#include <assert.h>
+#endif
+
+/*
+ * Debug
+ */
+#if defined(TEST_PROGRAM) && !defined(LIBMOUNT_DEBUG)
+#define CONFIG_LIBMOUNT_DEBUG
+#endif
+
+#define DEBUG_INIT (1 << 1)
+#define DEBUG_CACHE (1 << 2)
+#define DEBUG_OPTIONS (1 << 3)
+#define DEBUG_LOCKS (1 << 4)
+#define DEBUG_TAB (1 << 5)
+#define DEBUG_ALL 0xFFFF
+
+#ifdef CONFIG_LIBMOUNT_DEBUG
+#include <stdio.h>
+extern int libmount_debug_mask;
+#define DBG(m,x) if ((m) & libmount_debug_mask) x
+#else
+#define DBG(m,x)
+#endif
+
+#ifdef TEST_PROGRAM
+struct mtest {
+ const char *name;
+ int (*body)(struct mtest *ts, int argc, char *argv[]);
+ const char *usage;
+};
+
+/* utils.c */
+extern int mnt_run_test(struct mtest *tests, int argc, char *argv[]);
+#endif
+
+/* utils.c */
+extern char *mnt_getenv_safe(const char *arg);
+#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
+extern char *mnt_get_username(const uid_t uid);
+extern char *mnt_strconcat3(char *s, const char *t, const char *u);
+
+
+/*
+ * Generic iterator
+ */
+struct _mnt_iter {
+ struct list_head *p; /* current position */
+ struct list_head *head; /* start position */
+ int direction; /* MNT_ITER_{FOR,BACK}WARD */
+};
+
+#define IS_ITER_FORWARD(_i) ((_i)->direction == MNT_ITER_FORWARD)
+#define IS_ITER_BACKWARD(_i) ((_i)->direction == MNT_ITER_BACKWARD)
+
+#define MNT_ITER_INIT(itr, list) \
+ do { \
+ (itr)->p = IS_ITER_FORWARD(itr) ? \
+ (list)->next : (list)->prev; \
+ (itr)->head = (list); \
+ } while(0)
+
+#define MNT_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)
+
+
+/*
+ * mnt_optls entry
+ */
+struct _mnt_optent {
+ char *name; /* option name (allcocated when mapent is NULL) */
+ char *value; /* option argument value */
+
+ int mask; /* MNT_{INVMASK,MDATA,MFLAG,NOMTAB,NOSYS}
+ * modifiable flags (initial value comes from map->mask)
+ */
+ const struct mnt_optmap *mapent;/* the option description (msp entry) */
+ const struct mnt_optmap *map; /* head of the map */
+
+ struct list_head opts; /* list of options */
+};
+
+/*
+ * Container (list) for mount options
+ */
+struct _mnt_optls {
+ struct mnt_optmap const **maps; /* array with option maps */
+ size_t nmaps; /* number of maps */
+
+ struct list_head opts; /* list of options */
+};
+
+/*
+ * This struct represents one entry in mtab/fstab/mountinfo file.
+ */
+struct _mnt_fs {
+ struct list_head ents;
+
+ int id; /* mountinfo[1]: ID */
+ int parent; /* moutninfo[2]: parent */
+ dev_t devno; /* moutninfo[3]: st_dev */
+
+ char *source; /* fstab[1]: mountinfo[10]:
+ * source dev, file, dir or TAG */
+ char *tagname; /* fstab[1]: tag name - "LABEL", "UUID", ..*/
+ char *tagval; /* tag value */
+
+ char *mntroot; /* mountinfo[4]: root of the mount within the FS */
+ char *target; /* mountinfo[5], fstab[2]: mountpoint */
+ char *fstype; /* mountinfo[9], fstab[3]: filesystem type */
+
+ char *optstr; /* mountinfo[6,11], fstab[4]: option string */
+ char *vfs_optstr; /* mountinfo[6]: fs-independent (VFS) options */
+ char *fs_optstr; /* mountinfo[11]: fs-depend options */
+
+ int freq; /* fstab[5]: dump frequency in days */
+ int passno; /* fstab[6]: pass number on parallel fsck */
+
+ int flags; /* MNT_FS_* flags */
+ int lineno; /* line number in the parental file */
+
+ void *userdata; /* library independent data */
+};
+
+/*
+ * fs flags
+ */
+#define MNT_FS_ERROR (1 << 1) /* broken entry */
+#define MNT_FS_PSEUDO (1 << 2) /* pseudo filesystem */
+#define MNT_FS_NET (1 << 3) /* network filesystem */
+
+/*
+ * File format
+ */
+enum {
+ MNT_FMT_FSTAB = 1, /* /etc/{fs,m}tab */
+ MNT_FMT_MOUNTINFO /* /proc/#/mountinfo */
+};
+
+/*
+ * mtab/fstab/mountinfo file
+ */
+struct _mnt_tab {
+ char *filename; /* file name or NULL */
+ int fmt; /* MNT_FMT_* file format */
+
+ int nlines; /* number of lines in the file (include commentrys) */
+ int nents; /* number of valid entries */
+ int nerrs; /* number of broken entries (parse errors) */
+
+ mnt_cache *cache; /* canonicalized paths/tags cache */
+
+ struct list_head ents; /* list of entries (mentry) */
+};
+
+
+/* optmap.c */
+extern const struct mnt_optmap *mnt_optmap_get_entry(struct mnt_optmap const **maps,
+ int nmaps, const char *name,
+ size_t namelen, const struct mnt_optmap **mapent);
+extern int mnt_optmap_enum_to_number(const struct mnt_optmap *mapent,
+ const char *rawdata, size_t len);
+extern const char *mnt_optmap_get_type(const struct mnt_optmap *mapent);
+extern int mnt_optmap_require_value(const struct mnt_optmap *mapent);
+
+/* optent.c */
+
+/* private option masks -- see mount.h.in for the publick masks */
+#define MNT_HASVAL (1 << 10)
+
+extern mnt_optent *mnt_new_optent(const char *name, size_t namesz,
+ const char *value, size_t valsz,
+ struct mnt_optmap const **maps, int nmaps);
+extern void mnt_free_optent(mnt_optent *op);
+extern mnt_optent *mnt_new_optent_from_optstr(char **optstr,
+ struct mnt_optmap const **maps, int nmaps);
+extern int mnt_optent_assign_map(mnt_optent *op,
+ struct mnt_optmap const **maps, int nmaps);
+
+/* fs.c */
+extern int __mnt_fs_set_source(mnt_fs *fs, char *source);
+extern int __mnt_fs_set_fstype(mnt_fs *fs, char *fstype);
+
+
+
+#endif /* _LIBMOUNT_PRIVATE_H */
diff --git a/shlibs/mount/src/optent.c b/shlibs/mount/src/optent.c
new file mode 100644
index 00000000..4b35b2d5
--- /dev/null
+++ b/shlibs/mount/src/optent.c
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: optent
+ * @title: Parsed option
+ * @short_description: the mnt_optent keeps one parsed mount option
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "nls.h"
+#include "mountP.h"
+
+static int mnt_init_optent(mnt_optent *op, const char *name, size_t namelen,
+ struct mnt_optmap const **maps, int nmaps);
+static int __mnt_optent_set_value(mnt_optent *op, const char *data, size_t len);
+
+
+/*
+ * Returns a new optent.
+ */
+mnt_optent *mnt_new_optent( const char *name, size_t namesz,
+ const char *value, size_t valsz,
+ struct mnt_optmap const **maps, int nmaps)
+{
+ mnt_optent *op;
+
+ op = calloc(1, sizeof(struct _mnt_optent));
+ if (!op)
+ return NULL;
+
+ INIT_LIST_HEAD(&op->opts);
+
+ if (mnt_init_optent(op, name, namesz, maps, nmaps))
+ goto err;
+
+ if (value) {
+ if (__mnt_optent_set_value(op, value, valsz))
+ goto err;
+ } else if (mnt_optent_require_value(op))
+ goto err;
+
+ return op;
+err:
+ free(op);
+ return NULL;
+}
+
+/*
+ * Deallocates the optent.
+ */
+void mnt_free_optent(mnt_optent *op)
+{
+ if (!op)
+ return;
+
+ if (!op->mapent || op->mapent->name != op->name)
+ free(op->name);
+
+ free(op->value);
+
+ if (!list_empty(&op->opts))
+ list_del(&op->opts);
+
+ free(op);
+}
+
+/*
+ * initialize or reinitialize the option entry -- note that the option
+ * name is set to @name and the old name is not free()ed. If the @name
+ * is NULL the already existing option name is used.
+ */
+static int mnt_init_optent(mnt_optent *op, const char *name, size_t namelen,
+ struct mnt_optmap const **maps, int nmaps)
+{
+ const struct mnt_optmap *mapent = NULL, *map = NULL;
+
+ assert(op);
+
+ if (!op)
+ return -1;
+
+ if (!name && op->name) {
+ name = op->name;
+ namelen = strlen(name);
+ }
+ if (!name)
+ return -1;
+
+ if (nmaps && maps)
+ map = mnt_optmap_get_entry(maps, nmaps, name, namelen, &mapent);
+
+ if (mapent == NULL || mnt_optmap_get_type(mapent) != NULL) {
+ /* we allocate the name for uknown options of for options with
+ * "=%<type>" argument. This is not perfect... */
+ if (op->name != name)
+ op->name = strndup(name, namelen);
+ } else
+ op->name = (char *) mapent->name;
+
+ op->mapent = mapent;
+ op->map = map;
+ op->mask = mapent ? mapent->mask : 0;
+ if (op->value)
+ op->mask |= MNT_HASVAL;
+
+ if (!op->name)
+ return -1; /* strdup() failed */
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s: initialized\n", op->name));
+
+ return 0;
+}
+
+static int mnt_optent_check_value(mnt_optent *op, const char *data, size_t len)
+{
+ const char *type;
+ char *end = NULL;
+
+ assert(op);
+ if (!op)
+ return -1;
+
+ type = mnt_optent_get_type(op);
+ if (!type)
+ goto err; /* value is unexpected */
+
+ if (!data) {
+ if (mnt_optent_require_value(op))
+ goto err;
+ } else if (!strncmp(type, "%s", 2)) {
+ /* string type */
+ ;
+ } else if (*type == '{') {
+ /* enum type */
+ if (mnt_optmap_enum_to_number(op->mapent, data, len) < 0)
+ goto err;
+ } else {
+ /* numbers */
+ int n; /* happy gcc */
+
+ errno = 0;
+ if (!strncmp(type, "%d", 2) || !strncmp(type, "%ld", 3))
+ n = strtol(data, &end, 10);
+ else if (!strncmp(type, "%u", 2) || !strncmp(type, "%lu", 3))
+ n = strtoul(data, &end, 10);
+ else if (!strncmp(type, "%lld", 4))
+ n = strtoll(data, &end, 10);
+ else if (!strncmp(type, "%llu", 4))
+ n = strtoull(data, &end, 10);
+ else if (!strncmp(type, "%o", 2))
+ n = strtoul(data, &end, 8);
+ else if (!strncmp(type, "%x", 2))
+ n = strtoul(data, &end, 16);
+
+ if (errno == EINVAL || errno == ERANGE || end != data + len)
+ goto err;
+ }
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s (type=%s): pass check\n",
+ op->name, type));
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s (type=%s): failed to check value %s\n",
+ op->name, type, data));
+ return -1;
+}
+
+/*
+ * Parses the first mount option from @optstr and move @optstr pointer
+ * to the next option.
+ *
+ * Returns new optent (parsed option) or NULL in case of error.
+ */
+mnt_optent *mnt_new_optent_from_optstr(char **optstr,
+ struct mnt_optmap const **maps, int nmaps)
+{
+ char *name, *value;
+ size_t nsz, vsz;
+
+ if (mnt_optstr_next_option(optstr, &name, &nsz, &value, &vsz) == 0)
+ return mnt_new_optent(name, nsz, value, vsz, maps, nmaps);
+
+ return NULL;
+}
+
+/*
+ * Lookups @maps and tries to found corresponding map entry for the @op option.
+ * If the map is found the option value is reverified.
+ *
+ * Returns 0 on success, 1 if map not found, -1 in case of error (revalidation
+ * failed or so).
+ */
+int mnt_optent_assign_map(mnt_optent *op,
+ struct mnt_optmap const **maps, int nmaps)
+{
+ char *oldval, *oldname = NULL;
+ const char *type;
+
+ assert(op);
+ assert(op->name);
+
+ if (!op || !op->name)
+ return -1;
+
+ if (op->mapent && op->name != op->mapent->name)
+ oldname = op->name; /* old name is allocated */
+
+ op->map = op->mapent = NULL;
+ oldval = op->value;
+
+ if (mnt_init_optent(op, NULL, 0, maps, nmaps))
+ return -1;
+
+ if (op->name != oldname)
+ free(oldname);
+
+ if (!op->map)
+ return 1; /* uknown option, it's not error */
+
+ /* the new type */
+ type = mnt_optent_get_type(op);
+
+ if (type == NULL && oldval)
+ goto err; /* value is unexpected */
+ if (mnt_optent_require_value(op) && !oldval)
+ goto err; /* value is required */
+ if (oldval && mnt_optent_check_value(op, oldval, strlen(oldval)) != 0)
+ goto err; /* bad value */
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s: assigned to \n", op->name));
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s: assign failed\n", op->name));
+ return -1;
+}
+
+/**
+ * mnt_optent_get_map:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: pointer to the head of the map that is associated with the option or
+ * NULL (for "extra options").
+ */
+const struct mnt_optmap *mnt_optent_get_map(mnt_optent *op)
+{
+ assert(op);
+ return op ? op->map : NULL;
+}
+
+/**
+ * mnt_optent_get_map_entry:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: pointer to the map entry that describes the option or NULL (for
+ * "extra options").
+ */
+const struct mnt_optmap *mnt_optent_get_mapent(mnt_optent *op)
+{
+ assert(op);
+ return op ? op->mapent : NULL;
+}
+
+/**
+ * mnt_optent_get_type:
+ * @op: mnt_optent instance
+ *
+ * Note that the @op has to be associated with any option map
+ * or the default "%s]" is returned.
+ *
+ * Returns: pointer to the begin of type format string or NULL. For example:
+ *
+ * "%s" --> string, required argument (definition in the map is: "foo=%s")
+ * "%s]" --> string, optional argument (definition in the map is: "foo[=%s]")
+ */
+const char *mnt_optent_get_type(mnt_optent *op)
+{
+ assert(op);
+ if (!op)
+ return NULL;
+ return op->mapent ? mnt_optmap_get_type(op->mapent) : "%s]";
+}
+
+
+
+/**
+ * mnt_optent_set_value:
+ * @op: mnt_optent instance
+ * @data: option argument data or NULL
+ *
+ * The function unset (zeroize) the option value if the @data pointer is NULL.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_optent_set_value(mnt_optent *op, const char *data)
+{
+ return __mnt_optent_set_value(op, data, data ? strlen(data) : 0);
+}
+
+static int __mnt_optent_set_value(mnt_optent *op, const char *data, size_t len)
+{
+ assert(op);
+ if (!op)
+ return -1;
+
+ free(op->value);
+ op->value = NULL;
+ op->mask &= ~MNT_HASVAL;
+
+ if (mnt_optent_check_value(op, data, len) != 0)
+ goto err;
+ if (data) {
+ op->value = strndup(data, len);
+ if (!op->value)
+ goto err;
+ op->mask |= MNT_HASVAL;
+ }
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s: set argument value: %s\n",
+ op->name, op->value));
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s: set argument value failed\n",
+ op->name));
+ return -1;
+
+}
+
+/**
+ * mnt_optent_has_value:
+ * @option: pointer to mnt_optent instance
+ *
+ * Returns: 1 if the option has actually set an argument value, or 0.
+ */
+int mnt_optent_has_value(mnt_optent *op)
+{
+ return op && (op->mask & MNT_HASVAL) ? 1 : 0;
+}
+
+/**
+ * mnt_optent_require_value:
+ * @op: pointer to mnt_optent instance
+ *
+ * Note that the @op has to be associated with any option map
+ * or 0 is returned.
+ *
+ * Returns: 1 if the option requires an argument (option=arg).
+ */
+int mnt_optent_require_value(mnt_optent *op)
+{
+ return op && op->mapent ? mnt_optmap_require_value(op->mapent) : 0;
+}
+
+/**
+ * mnt_optent_is_inverted:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: 1 if the option has MNT_INVERT mask or 0.
+ */
+int mnt_optent_is_inverted(mnt_optent *op)
+{
+ return (op && (op->mask & MNT_INVERT));
+}
+
+static int get_number_base(const char *type)
+{
+ int base = 10; /* default */
+
+ if (!strncmp(type, "%o", 2))
+ base = 8;
+ else if (!strncmp(type, "%x", 16))
+ base = 16;
+ return base;
+}
+
+/**
+ * mnt_optent_strtoul_value:
+ * @op: pointer to mnt_optent instance
+ * @number: resulting number
+ *
+ * Converts an option value to number. The strtoul() base (decimal, octan or
+ * hex) is determined from (%u, %o or %x) option format type -- default is
+ * decimal (for unknown options).
+ *
+ * The whole option value has to be possible to convert to the number
+ * (e.g "123ABC" returns -1).
+ *
+ * This function also converts {enum0,enumN} type to number 0..N. For more
+ * details see info about option maps.
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_optent_strtoul_value(mnt_optent *op, unsigned long int *number)
+{
+ const char *type = NULL;
+ char *end;
+ size_t len;
+
+ if (!mnt_optent_has_value(op) || !number)
+ goto err;;
+ type = mnt_optent_get_type(op);
+ if (!type)
+ goto err;
+
+ if (*type == '{') {
+ int n;
+
+ if (!op->mapent)
+ goto err;
+ n = mnt_optmap_enum_to_number(op->mapent, op->value,
+ strlen(op->value));
+ if (n < 0)
+ goto err;
+ *number = n;
+ } else {
+ errno = 0;
+ *number = strtoul(op->value, &end, get_number_base(type));
+
+ if (errno == EINVAL || errno == ERANGE)
+ goto err;
+ len = strlen(op->value);
+ if (end != op->value + len)
+ goto err;
+ }
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s (type=%s): strtoul failed\n",
+ op->name, type));
+ return -1;
+}
+
+/**
+ * mnt_optent_strtol_value:
+ * @op: pointer to mnt_optent instance
+ * @number: resulting number
+ *
+ * Converts an option value to number. The strtol() base (decimal, octan or
+ * hex) is determined from (%u, %o or %x) option format type -- default is
+ * decimal.
+ *
+ * The whole option value has to be possible to convert to the number
+ * (e.g "123ABC" returns -1).
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_optent_strtol_value(mnt_optent *op, long int *number)
+{
+ const char *type;
+ char *end;
+ size_t len;
+
+ if (!mnt_optent_has_value(op) || !number)
+ return -1;
+
+ type = mnt_optent_get_type(op);
+ if (!type)
+ goto err;
+
+ errno = 0;
+ *number = strtol(op->value, &end, get_number_base(type));
+
+ if (errno == EINVAL || errno == ERANGE)
+ goto err;
+ len = strlen(op->value);
+ if (end != op->value + len)
+ goto err;
+
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s (type=%s): strtol failed\n",
+ op->name, type));
+ return -1;
+}
+
+/**
+ * mnt_optent_strtoull_value:
+ * @op: pointer to mnt_optent instance
+ * @number: resulting number
+ *
+ * Converts an option value to number. The strtoull() base (decimal, octan or
+ * hex) is determined from (%u, %o or %x) option format type -- default is
+ * decimal.
+ *
+ * The whole option value has to be possible to convert to the number
+ * (e.g "123ABC" returns -1).
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_optent_strtoull_value(mnt_optent *op, unsigned long long int *number)
+{
+ const char *type;
+ char *end;
+ size_t len;
+
+ if (!mnt_optent_has_value(op) || !number)
+ return -1;
+
+ type = mnt_optent_get_type(op);
+ if (!type)
+ goto err;
+
+ errno = 0;
+ *number = strtoull(op->value, &end, get_number_base(type));
+
+ if (errno == EINVAL || errno == ERANGE)
+ goto err;
+ len = strlen(op->value);
+ if (end != op->value + len)
+ goto err;
+ return 0;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: option %s (type=%s): strtoull failed\n",
+ op->name, type));
+ return -1;
+
+}
+
+/**
+ * mnt_optent_get_value:
+ * @op: pointer to mnt_optent instance
+ *
+ * See also mnt_optent_has_value().
+ *
+ * Returns: pointer to value or NULL.
+ */
+const char *mnt_optent_get_value(mnt_optent *op)
+{
+ return op? op->value : NULL;
+}
+
+/**
+ * mnt_optent_strlen_value:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: length of string that is necessary to print option value or -1 in
+ * case of error.
+ */
+int mnt_optent_strlen_value(mnt_optent *op)
+{
+ assert(op);
+
+ if (!op)
+ return -1;
+ if (!mnt_optent_has_value(op))
+ return 0;
+ return strlen(op->value);
+}
+
+/**
+ * mnt_optent_snprintf_value:
+ * @op: pointer to mnt_optent instance
+ * @str: resulting string
+ * @size: size of string
+ *
+ * Returns: number of printed characters or negative number in case of error.
+ */
+int mnt_optent_snprintf_value(mnt_optent *op, char *str, size_t size)
+{
+ assert(op);
+ assert(str);
+
+ if (!op || !str || !size)
+ return -1;
+ if (!mnt_optent_has_value(op))
+ return -1;
+
+ /* TODO: use extra quotes for SELinux contexts */
+ return snprintf(str, size, "%s", op->value);
+}
+
+/**
+ * mnt_optent_dup_value:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: duplicate a option value.
+ */
+char *mnt_optent_dup_value(mnt_optent *op)
+{
+ assert(op);
+
+ if (mnt_optent_has_value(op))
+ return strdup(op->value);
+ return NULL;
+}
+
+/**
+ * mnt_optent_get_name:
+ * @op: pointer to mnt_optent instance
+ *
+ * Returns: option name or NULL in case of error.
+ */
+const char *mnt_optent_get_name(mnt_optent *op)
+{
+ assert(op);
+ return op ? op->name : NULL;
+}
+
+/**
+ * mnt_optent_get_mask:
+ * @op: pointer to mnt_optent instance
+ *
+ * The initial value of the option mask is a copy from map->mask.
+ * Note that the mask is NOT a mountflag/ID.
+ *
+ * Returns: option mask or 0.
+ */
+int mnt_optent_get_mask(mnt_optent *op)
+{
+ assert(op);
+ return op ? op->mask : 0;
+}
+
+/**
+ * mnt_optent_get_id:
+ * @op: pointer to mnt_optent instance
+ *
+ * Note that the ID is also mountflag for all options with MNT_MFLAG mask.
+ *
+ * WARNING: the ID is usually shared between "option" (e.g. exec) and
+ * "nooption" (e.g. noexec) -- you have to carefully check for MNT_INVERT in
+ * the option mask. See mnt_optent_get_flag().
+ *
+ * Returns: option ID/mountflag or 0 for extra options (options with undefined
+ * options map).
+ */
+int mnt_optent_get_id(mnt_optent *op)
+{
+ assert(op);
+ return op && op->mapent ? op->mapent->id : 0;
+}
+
+/**
+ * mnt_optent_get_flag:
+ * @op: pointer to mnt_optent instance
+ * @flags: resulting flags
+ *
+ * Adds option ID to @flags or removes the ID from @flags when the option
+ * is an inverted option (e.g. "norelatime")
+ *
+ * <informalexample>
+ * <programlisting>
+ * int flags = 0;
+ *
+ * while(mnt_optls_next_option(&itr, opts, map, &op) == 0)
+ * mnt_optent_get_flag(op, &flags);
+ *
+ * if (flags & MS_RELATIME)
+ * printf("relatime is set\n");
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_optent_get_flag(mnt_optent *op, int *flags)
+{
+ int id;
+
+ assert(op);
+ if (!op || !flags)
+ return -1;
+
+ id = mnt_optent_get_id(op);
+ if (op->mask & MNT_INVERT)
+ *flags &= ~id;
+ else
+ *flags |= id;
+ return 0;
+}
+
+/**
+ * mnt_optent_is_unknown:
+ * @op: pointer to mnt_optent instance
+ *
+ * The "extra options" are unknown options (undefined in any option map)
+ *
+ * Returns: 1 or 0.
+ */
+int mnt_optent_is_unknown(mnt_optent *op)
+{
+ assert(op);
+ return op && op->mapent ? 0 : 1;
+}
+
+/**
+ * mnt_optent_print_debug:
+ * @file: output
+ * @op: pointer to mnt_optent instance
+ *
+ * Prints details about the option.
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_optent_print_debug(mnt_optent *op, FILE *file)
+{
+ const struct mnt_optmap *map;
+ const char *type;
+
+ if (!op)
+ return -1;
+
+ fprintf(file, "------ option %p (%s):\n", op, mnt_optent_get_name(op));
+
+ fprintf(file, "\tID=0x%x\n", mnt_optent_get_id(op));
+ fprintf(file, "\tMASK=%d\n", mnt_optent_get_mask(op));
+
+ map = mnt_optent_get_map(op);
+ fprintf(file, "\tMAP=%p\n", map ? map : NULL);
+
+ map = mnt_optent_get_mapent(op);
+ fprintf(file, "\tMAPENT=%s\n", map ? map->name : NULL);
+
+ fprintf(file, "\tHAS_VALUE=%s\n",
+ mnt_optent_has_value(op) ? "yes" : "not");
+
+ type = mnt_optent_get_type(op);
+ fprintf(file, "\tTYPE=%s\n", type ? : "<none>");
+ fprintf(file, "\tVALUE=%s\n", op->value);
+ return 0;
+}
diff --git a/shlibs/mount/src/optls.c b/shlibs/mount/src/optls.c
new file mode 100644
index 00000000..ff2b912b
--- /dev/null
+++ b/shlibs/mount/src/optls.c
@@ -0,0 +1,791 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: optls
+ * @title: Options container
+ * @short_description: high-level API for work with parsed mount options
+ *
+ * The optls container allows to work with parsed mount options and generate
+ * arguments for mount(2) syscall, output to mtab or analyze userspace specific
+ * options.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "nls.h"
+#include "mountP.h"
+
+/**
+ * mnt_new_optls:
+ *
+ * Returns: newly allocated and initialized optls instance. The library
+ * uses this object as a container for mount options.
+ */
+mnt_optls *mnt_new_optls(void)
+{
+ mnt_optls *ls = calloc(1, sizeof(struct _mnt_optls));
+ if (!ls)
+ return NULL;
+ INIT_LIST_HEAD(&ls->opts);
+ return ls;
+}
+
+/**
+ * mnt_free_optls:
+ * @ls: pointer to mnt_optls instance.
+ *
+ * Deallocates mnt_optls and all stored options.
+ */
+void mnt_free_optls(mnt_optls *ls)
+{
+ if (!ls)
+ return;
+ while (!list_empty(&ls->opts)) {
+ mnt_optent *o = list_entry(ls->opts.next, mnt_optent, opts);
+ mnt_free_optent(o);
+ }
+
+ free(ls->maps);
+ free(ls);
+}
+
+/**
+ * mnt_optls_add_map:
+ * @ls: pointer to mnt_optls instance
+ * @map: pointer to the custom map
+ *
+ * Stores pointer to the custom options map (options description). The map has
+ * to be accessible all time when the libmount works with options. (The map is
+ * usually a static array.)
+ *
+ * All already stored unknown mount options are reverified against the new map.
+ * Note, it's recommented to add all maps to the @optls container before options
+ * parsing.
+ *
+ * Example (add new options "foo" and "bar=data"):
+ *
+ * <informalexample>
+ * <programlisting>
+ * #define MY_MS_FOO (1 << 1)
+ * #define MY_MS_BAR (1 << 2)
+ *
+ * mnt_optmap myoptions[] = {
+ * { "foo", MY_MS_FOO, MNT_MFLAG },
+ * { "nofoo", MY_MS_FOO, MNT_MFLAG | MNT_INVERT },
+ * { "bar=%s",MY_MS_BAR, MNT_MDATA },
+ * { NULL }
+ * };
+ *
+ * mnt_optls_add_map(ls, myoptions);
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success, 1 on failed verification, or -1 in case of error.
+ */
+int mnt_optls_add_map(mnt_optls *ls, const struct mnt_optmap *map)
+{
+ mnt_optent *op;
+ mnt_iter itr;
+
+ assert(ls);
+ assert(map || ls->maps == NULL);
+
+ ls->maps = realloc(ls->maps,
+ sizeof(struct mnt_optmap *) * (ls->nmaps + 1));
+ if (!ls->maps)
+ return -1;
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: optls %p: add map[%zd]", ls, ls->nmaps));
+ ls->maps[ls->nmaps] = map;
+ ls->nmaps++;
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ if (!mnt_optent_is_unknown(op))
+ continue;
+ if (mnt_optent_assign_map(op, &map, 1) == -1)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * mnt_optls_add_builtin_map:
+ * @ls: pointer to mnt_optls instance
+ * @id: built-in map id (see mnt_get_builtin_map())
+ *
+ * Same as mnt_optls_add_map(), but works with libmount built in maps.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_optls_add_builtin_map(mnt_optls *ls, int id)
+{
+ const struct mnt_optmap *m = mnt_get_builtin_optmap(id);
+
+ assert(ls);
+ assert(id);
+
+ return m ? mnt_optls_add_map(ls, m) : -1;
+}
+
+
+/*
+ * Append the option to "ls" container.
+ */
+static void mnt_optls_add_optent(mnt_optls *ls, mnt_optent *op)
+{
+ assert(ls);
+ assert(op);
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: add option %s",
+ ls, mnt_optent_get_name(op)));
+
+ list_add_tail(&op->opts, &ls->opts);
+}
+
+/**
+ * mnt_optls_add_option:
+ * @ls: pointer to mnt_optls instance
+ * @name: option name
+ * @value: option value
+ *
+ * Returns: new option or NULL in case of error.
+ */
+mnt_optent *mnt_optls_add_option(mnt_optls *ls,
+ const char *name, const char *value)
+{
+ mnt_optent *op;
+
+ if (!ls || !name)
+ return NULL;
+
+ op = mnt_new_optent(name, strlen(name),
+ value, value ? strlen(value) : 0,
+ ls->maps, ls->nmaps);
+ if (op)
+ mnt_optls_add_optent(ls, op);
+ return op;
+}
+
+/**
+ * mnt_optls_parse_optstr:
+ * @ls: pointer to mnt_optls instance.
+ * @optstr: zero terminated string with mount options (comma separaed list)
+ *
+ * Parses @optstr and all options from @optstr are added to the @optls. It's
+ * possible to call this function more than once. The new options from @optstr
+ * will be appended to the container.
+ *
+ * The options are accessible by mnt_optls_next_option().
+ *
+ * If the @optls container is associated with any options map(s), all new
+ * options are verified according to the descriptions from the map(s).
+ *
+ * For example:
+ *
+ * mnt_optls_parse_optstr(ls, "user=snake,noexec");
+ *
+ * is same like:
+ *
+ * mnt_optls_add_option(ls, "user", "snake");
+ * mnt_optls_add_option(ls, "noexec", NULL);
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_optls_parse_optstr(mnt_optls *ls, const char *optstr)
+{
+ char *p = (char *) optstr;
+
+ assert(ls);
+ assert(optstr);
+
+ if (!ls || !optstr)
+ return -1;
+
+ while(p && *p) {
+ mnt_optent *op = mnt_new_optent_from_optstr(&p,
+ ls->maps, ls->nmaps);
+ if (!op)
+ return -1;
+ mnt_optls_add_optent(ls, op);
+ }
+ return 0;
+}
+
+/**
+ * mnt_optls_remove_option:
+ * @ls: pointer to mnt_optls instance
+ * @name: option name
+ *
+ * Returns: 0 on success, 1 if @name not found and -1 in case of error.
+ */
+int mnt_optls_remove_option(mnt_optls *ls, const char *name)
+{
+ struct list_head *p, *pnext;
+
+ if (!ls || !name)
+ return -1;
+
+ list_for_each_safe(p, pnext, &ls->opts) {
+ mnt_optent *op;
+ const char *n;
+
+ if (!p)
+ break;
+ op = list_entry(p, mnt_optent, opts);
+ n = mnt_optent_get_name(op);
+ if (n && strcmp(name, n) == 0) {
+ mnt_free_optent(op);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/**
+ * mnt_optls_remove_option_by_flags:
+ * @ls: pointer to mnt_optls instance
+ * @map: pointer to the map with wanted options or NULL for all options
+ * @flags: option flags
+ *
+ * Removes options which match with @flags. The set of options could
+ * be restricted by @map. For exmaple:
+ *
+ * mnt_optls_remove_option_by_flags(ls, NULL, MS_NOEXEC);
+ *
+ * removes "noexec" option from "ls".
+ *
+ * Note that this function is useles for options with MNT_INVERT mask (e.g.
+ * "exec" is inverting MS_NOEXEC flag).
+ *
+ * See also mnt_optent_get_flag() and mnt_optls_remove_option_by_iflags().
+ *
+ * Returns: number of removed options or -1 in case of error.
+ */
+int mnt_optls_remove_option_by_flags(mnt_optls *ls,
+ const struct mnt_optmap *map, const int flags)
+{
+ struct list_head *p, *pnext;
+ int ct = 0;
+
+ if (!ls)
+ return -1;
+
+ list_for_each_safe(p, pnext, &ls->opts) {
+ mnt_optent *op;
+ int fl = 0;
+
+ if (!p)
+ break;
+ op = list_entry(p, mnt_optent, opts);
+
+ if (!map || mnt_optent_get_map(op) == map) {
+ mnt_optent_get_flag(op, &fl);
+ if (fl & flags) {
+ mnt_free_optent(op);
+ ct++;
+ }
+ }
+ }
+ return ct;
+}
+
+/**
+ * mnt_optls_remove_option_by_iflags:
+ * @ls: pointer to mnt_optls instance
+ * @map: pointer to the map with wanted options or NULL for all options
+ * @flags: option flags
+ *
+ * Removes options which inverting any id from @flags. The set of options could
+ * be restricted by @map. For exmaple:
+ *
+ * mnt_optls_remove_option_by_iflags(ls, NULL, MS_NOEXEC);
+ *
+ * removes "exec" option from "ls".
+ *
+ * Note that this function is useles for options without MNT_INVERT mask (e.g.
+ * "noexec").
+ *
+ * See also mnt_optent_get_flag() and mnt_optls_remove_option_by_flags().
+ *
+ * Returns: number of removed options or -1 in case of error.
+ */
+int mnt_optls_remove_option_by_iflags(mnt_optls *ls,
+ const struct mnt_optmap *map, const int flags)
+{
+ struct list_head *p, *pnext;
+ int ct = 0;
+
+ if (!ls)
+ return -1;
+
+ list_for_each_safe(p, pnext, &ls->opts) {
+ mnt_optent *op;
+ int fl = flags;
+
+ if (!p)
+ break;
+ op = list_entry(p, mnt_optent, opts);
+
+ if (!map || mnt_optent_get_map(op) == map) {
+ int id = mnt_optent_get_id(op);
+
+ if (!(id & fl))
+ continue;
+
+ mnt_optent_get_flag(op, &fl);
+
+ if (!(id & fl)) {
+ mnt_free_optent(op);
+ ct++;
+ }
+ }
+ }
+ return ct;
+}
+
+/**
+ * mnt_optls_next_option:
+ * @ls: pointer to mnt_optls instance
+ * @itr: iterator
+ * @map: pointer to the map of wanted options or NULL for all options
+ * @option: returns pointer to the option object
+ *
+ * Example (print all options):
+ * <informalexample>
+ * <programlisting>*
+ * mnt_optent *option;
+ * mnt_optls *ls = mnt_optls_new();
+ *
+ * mnt_optls_parse_optstr(ls, "noexec,nodev");
+ *
+ * while(mnt_optls_next_option(ls, itr, NULL, &option))
+ * printf("%s\n", mnt_optent_get_name(option)));
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on succes, -1 in case of error or 1 at end of list.
+ */
+int mnt_optls_next_option(mnt_optls *ls, mnt_iter *itr,
+ const struct mnt_optmap *map, mnt_optent **option)
+{
+ assert(itr);
+ assert(ls);
+ assert(option);
+
+ if (!itr || !ls || !option)
+ return -1;
+ if (!itr->head)
+ MNT_ITER_INIT(itr, &ls->opts);
+ while (itr->p != itr->head) {
+ MNT_ITER_ITERATE(itr, *option, struct _mnt_optent, opts);
+ if (map == NULL || (*option)->map == map)
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * mnt_optls_get_option:
+ * @ls: pointer to mnt_optls instance
+ * @name: options name
+ *
+ * Returns: the option or NULL.
+ */
+mnt_optent *mnt_optls_get_option(mnt_optls *ls, const char *name)
+{
+ mnt_optent *op;
+ mnt_iter itr;
+
+ assert(ls);
+ assert(name);
+
+ if (!ls || !name)
+ return NULL;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ const char *n = mnt_optent_get_name(op);
+
+ if (n && !strcmp(n, name))
+ return op;
+ }
+ return NULL;
+}
+
+/**
+ * mnt_optls_get_ids:
+ * @ls: pointer to mnt_optls instance
+ * @map: pointer to the map of wanted options or NULL for all options
+ *
+ * Note that ID has to be unique in all maps when the @map is NULL.
+ *
+ * Note also that this function works with ALL options -- see also
+ * mnt_optls_create_mountflags() that returns MNT_MFLAG options
+ * (mount(2) flags) only.
+ *
+ * Returns: IDs from all options.
+ */
+int mnt_optls_get_ids(mnt_optls *ls, const struct mnt_optmap *map)
+{
+ int flags = 0;
+ mnt_iter itr;
+ mnt_optent *op;
+
+ assert(ls);
+ if (!ls)
+ return 0;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, map, &op) == 0)
+ mnt_optent_get_flag(op, &flags);
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generated IDs 0x%08x", ls, flags));
+ return flags;
+}
+
+/**
+ * mnt_optls_create_mountflags:
+ * @ls: pointer to mnt_optls instance
+ *
+ * The mountflags are IDs from all MNT_MFLAG options. See "struct mnt_optmap".
+ * For more details about mountflags see mount(2) syscall.
+ *
+ * Returns: mount flags or 0.
+ */
+int mnt_optls_create_mountflags(mnt_optls *ls)
+{
+ int flags = 0;
+ mnt_iter itr;
+ mnt_optent *op;
+
+ assert(ls);
+ if (!ls)
+ return 0;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ if (!(op->mask & MNT_MFLAG))
+ continue;
+ mnt_optent_get_flag(op, &flags);
+ }
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generated mountflags 0x%08x", ls, flags));
+ return flags;
+}
+
+/**
+ * mnt_optls_create_mountdata:
+ * @ls: pointer to mnt_optls instance
+ *
+ * For more details about mountdata see mount(2) syscall.
+ *
+ * Returns: newly allocated string with mount options or NULL in case of error.
+ */
+char *mnt_optls_create_mountdata(mnt_optls *ls)
+{
+ mnt_iter itr;
+ mnt_optent *op;
+ char *optstr = NULL;
+
+ assert(ls);
+ if (!ls)
+ return NULL;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ if (!(op->mask & MNT_MDATA) && !mnt_optent_is_unknown(op))
+ continue;
+ if (mnt_optstr_append_option(&optstr,
+ mnt_optent_get_name(op),
+ mnt_optent_get_value(op)))
+ goto err;
+ }
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generated mountdata: %s", ls, optstr));
+ return optstr;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: ls %p: generate mountdata failed", ls));
+ free(optstr);
+ return NULL;
+}
+
+/**
+ * mnt_optls_create_mtab_optstr:
+ * @ls: pointer to mnt_optls instance
+ *
+ * Returns: newly allocated string with mount options for mtab.
+ */
+char *mnt_optls_create_mtab_optstr(mnt_optls *ls)
+{
+ mnt_iter itr;
+ mnt_optent *op;
+ char *optstr = NULL;
+
+ assert(ls);
+ if (!ls)
+ return NULL;
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ if (op->mask & MNT_NOMTAB)
+ continue;
+ if (mnt_optstr_append_option(&optstr,
+ mnt_optent_get_name(op),
+ mnt_optent_get_value(op)))
+ goto err;
+ }
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generated mtab options: %s", ls, optstr));
+ return optstr;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generate mtab optstr failed", ls));
+ free(optstr);
+ return NULL;
+}
+
+/**
+ * mnt_optls_create_userspace_optstr:
+ * @ls: pointer to mnt_optls instance
+ *
+ * Returns: newly allocated string with mount options that are
+ * userspace specific (e.g. uhelper=,loop=).
+ */
+char *mnt_optls_create_userspace_optstr(mnt_optls *ls)
+{
+ mnt_iter itr;
+ mnt_optent *op;
+ char *optstr = NULL;
+
+ assert(ls);
+ if (!ls)
+ return NULL;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0) {
+ if (mnt_optent_is_unknown(op))
+ continue;
+ if (op->mask & (MNT_MDATA | MNT_MFLAG | MNT_NOMTAB))
+ continue;
+ if (mnt_optstr_append_option(&optstr,
+ mnt_optent_get_name(op),
+ mnt_optent_get_value(op)))
+ goto err;
+ }
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generated userspace-only options: %s",
+ ls, optstr));
+ return optstr;
+err:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: opts %p: generate userspace optstr failed", ls));
+ free(optstr);
+ return NULL;
+}
+
+/**
+ * mnt_optls_print_debug:
+ * @file: output
+ * @ls: pointer to mnt_optls instance
+ *
+ * Prints details about options container.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_optls_print_debug(mnt_optls *ls, FILE *file)
+{
+ mnt_iter itr;
+ mnt_optent *op;
+
+ if (!ls)
+ return -1;
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ fprintf(file, "--- opts: %p\n", ls);
+ while(mnt_optls_next_option(ls, &itr, NULL, &op) == 0)
+ mnt_optent_print_debug(op, file);
+
+ return 0;
+}
+
+#ifdef TEST_PROGRAM
+mnt_optls *mk_optls(const char *optstr)
+{
+ mnt_optls *ls = mnt_new_optls();
+ if (!ls)
+ goto err;
+
+ mnt_optls_add_builtin_map(ls, MNT_LINUX_MAP);
+ mnt_optls_add_builtin_map(ls, MNT_USERSPACE_MAP);
+
+ if (mnt_optls_parse_optstr(ls, optstr) != 0) {
+ fprintf(stderr, "\tfailed to parse: %s\n", optstr);
+ goto err;
+ }
+ return ls;
+err:
+ mnt_free_optls(ls);
+ return NULL;
+}
+
+int test_parse(struct mtest *ts, int argc, char *argv[])
+{
+ mnt_optls *ls = NULL;
+ int rc = -1;
+
+ if (argc < 1)
+ goto done;
+ ls = mk_optls(argv[1]);
+ if (!ls)
+ goto done;
+
+ mnt_optls_print_debug(ls, stdout);
+ rc = 0;
+done:
+ mnt_free_optls(ls);
+ return rc;
+}
+
+int test_flags(struct mtest *ts, int argc, char *argv[])
+{
+ mnt_optls *ls = NULL;
+ int rc = -1;
+ int flags;
+ const struct mnt_optmap *map;
+
+ if (argc < 1)
+ goto done;
+ ls = mk_optls(argv[1]);
+ if (!ls)
+ goto done;
+
+ flags = mnt_optls_create_mountflags(ls);
+ printf("\tmount(2) flags: 0x%08x\n", flags);
+
+ map = mnt_get_builtin_optmap(MNT_LINUX_MAP);
+ flags = mnt_optls_get_ids(ls, map);
+ printf("\tMNT_MAP_LINUX IDs: 0x%08x (map %p)\n", flags, map);
+
+ map = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
+ flags = mnt_optls_get_ids(ls, map);
+ printf("\tMNT_USERSPACE_MAP IDs: 0x%08x (map %p)\n", flags, map);
+
+ rc = 0;
+done:
+ mnt_free_optls(ls);
+ return rc;
+}
+
+int test_data(struct mtest *ts, int argc, char *argv[])
+{
+ mnt_optls *ls = NULL;
+ char *optstr;
+ int rc = -1;
+
+ if (argc < 1)
+ goto done;
+ ls = mk_optls(argv[1]);
+ if (!ls)
+ goto done;
+
+ optstr = mnt_optls_create_mountdata(ls);
+ printf("\tmount(2) data: '%s'\n", optstr);
+ free(optstr);
+ rc = 0;
+done:
+ mnt_free_optls(ls);
+ return rc;
+}
+
+int test_mtabstr(struct mtest *ts, int argc, char *argv[])
+{
+ mnt_optls *ls = NULL;
+ char *optstr;
+ int rc = -1;
+
+ if (argc < 1)
+ goto done;
+ ls = mk_optls(argv[1]);
+ if (!ls)
+ goto done;
+
+ optstr = mnt_optls_create_mtab_optstr(ls);
+ printf("\tmtab options: '%s'\n", optstr);
+ free(optstr);
+ rc = 0;
+done:
+ mnt_free_optls(ls);
+ return rc;
+}
+
+int test_reparse(struct mtest *ts, int argc, char *argv[])
+{
+ const struct mnt_optmap *map;
+ mnt_optls *ls = NULL;
+ char *optstr;
+ int rc = -1;
+
+ if (argc < 1)
+ goto done;
+ optstr = argv[1];
+ ls = mnt_new_optls();
+ if (!ls)
+ goto done;
+
+ /* add description for kernel options */
+ mnt_optls_add_builtin_map(ls, MNT_LINUX_MAP);
+
+ if (mnt_optls_parse_optstr(ls, optstr) != 0) {
+ fprintf(stderr, "\tfailed to parse: %s\n", optstr);
+ goto done;
+ }
+
+ fprintf(stdout, "------ parse\n");
+ mnt_optls_print_debug(ls, stdout);
+
+ /* add description for userspace options */
+ map = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
+ mnt_optls_add_map(ls, map);
+
+ fprintf(stdout, "------ re-parse\n");
+ mnt_optls_print_debug(ls, stdout);
+
+ rc = 0;
+done:
+ mnt_free_optls(ls);
+ return rc;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--parse", test_parse, "<optstr> parse mount options string" },
+ { "--ls-data", test_data, "<optstr> parse and generate mountdata" },
+ { "--ls-flags", test_flags, "<optstr> parse and generate mountflags" },
+ { "--ls-mtabstr",test_mtabstr,"<optstr> parse and generate mtab options" },
+ { "--reparse", test_reparse, "<optstr> test extra options reparsing" },
+ { NULL }
+ };
+ return mnt_run_test(tss, argc, argv);
+}
+#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/optmap.c b/shlibs/mount/src/optmap.c
new file mode 100644
index 00000000..6eef332c
--- /dev/null
+++ b/shlibs/mount/src/optmap.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: optmap
+ * @title: Option maps
+ * @short_description: description for mount options
+ *
+ * The mount(2) linux syscall uses two arguments for mount options:
+ *
+ * @mountflags: (see MS_* macros in linux/fs.h)
+ *
+ * @mountdata: (usully a comma separated string of options)
+ *
+ * The libmount uses options-map(s) to describe mount options. The number of
+ * maps is unlimited. The libmount options parser could be easily extended
+ * (e.g. by mnt_optls_add_map()) to work with new options.
+ *
+ * The option description (map entry) includes:
+ *
+ * @name: and argument type (e.g. "loop[=%s]")
+ *
+ * @id: (in the map unique identifier or a mountflags, e.g MS_RDONLY)
+ *
+ * @mask: (MNT_INVERT, MNT_MDATA, MNT_MFLAG, MNT_NOMTAB)
+ *
+ * The option argument type is defined by:
+ *
+ * "=type" -- required argument
+ *
+ * "[=type]" -- optional argument
+ *
+ * where the 'type' is sscanf() format string or
+ *
+ * {item0,item1,...} -- enum (mnt_option_get_number() converts the value
+ * to 0..N number)
+ *
+ * The options argument format is used for parsing only. The library internally
+ * stores the option argument as a string. The conversion to the data type is
+ * on-demant by mnt_option_get_value_*() functions.
+ *
+ * The library checks options argument according to 'type' format for simple
+ * formats only:
+ *
+ * %s, %d, %ld, %lld, %u, %lu, %llu, %x, %o and {enum}
+ *
+ * Example:
+ *
+ * <informalexample>
+ * <programlisting>
+ * #define MY_MS_FOO (1 << 1)
+ * #define MY_MS_BAR (1 << 2)
+ *
+ * mnt_optmap myoptions[] = {
+ * { "foo", MY_MS_FOO, MNT_MFLAG },
+ * { "nofoo", MY_MS_FOO, MNT_MFLAG | MNT_INVERT },
+ * { "bar=%s",MY_MS_BAR, MNT_MDATA },
+ * { NULL }
+ * };
+ * </programlisting>
+ * </informalexample>
+ *
+ * The libmount defines two basic built-in options maps:
+ *
+ * @MNT_LINUX_MAP: fs-independent kernel mount options (usually MS_* flags)
+ *
+ * @MNT_USERSPACE_MAP: userspace specific mount options (e.g. "user", "loop")
+ *
+ * For more details about option map struct see "struct mnt_optmap" in
+ * mount/mount.h.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "nls.h"
+#include "mountP.h"
+
+/*
+ * fs-independent mount flags (built-in MNT_LINUX_MAP)
+ */
+static const struct mnt_optmap linux_flags_map[] =
+{
+ { "ro", MS_RDONLY, MNT_MFLAG }, /* read-only */
+ { "rw", MS_RDONLY, MNT_MFLAG | MNT_INVERT }, /* read-write */
+ { "exec", MS_NOEXEC, MNT_MFLAG | MNT_INVERT }, /* permit execution of binaries */
+ { "noexec", MS_NOEXEC, MNT_MFLAG }, /* don't execute binaries */
+ { "suid", MS_NOSUID, MNT_MFLAG | MNT_INVERT }, /* honor suid executables */
+ { "nosuid", MS_NOSUID, MNT_MFLAG }, /* don't honor suid executables */
+ { "dev", MS_NODEV, MNT_MFLAG | MNT_INVERT }, /* interpret device files */
+ { "nodev", MS_NODEV, MNT_MFLAG }, /* don't interpret devices */
+
+ { "sync", MS_SYNCHRONOUS, MNT_MFLAG }, /* synchronous I/O */
+ { "async", MS_SYNCHRONOUS, MNT_MFLAG | MNT_INVERT }, /* asynchronous I/O */
+
+ { "dirsync", MS_DIRSYNC, MNT_MFLAG }, /* synchronous directory modifications */
+ { "remount", MS_REMOUNT, MNT_MFLAG }, /* Alter flags of mounted FS */
+ { "bind", MS_BIND, MNT_MFLAG }, /* Remount part of tree elsewhere */
+ { "rbind", MS_BIND|MS_REC, MNT_MFLAG }, /* Idem, plus mounted subtrees */
+#ifdef MS_NOSUB
+ { "sub", MS_NOSUB, MNT_MFLAG | MNT_INVERT }, /* allow submounts */
+ { "nosub", MS_NOSUB, MNT_MFLAG }, /* don't allow submounts */
+#endif
+#ifdef MS_SILENT
+ { "quiet", MS_SILENT, MNT_MFLAG }, /* be quiet */
+ { "loud", MS_SILENT, MNT_MFLAG | MNT_INVERT }, /* print out messages. */
+#endif
+#ifdef MS_MANDLOCK
+ { "mand", MS_MANDLOCK, MNT_MFLAG }, /* Allow mandatory locks on this FS */
+ { "nomand", MS_MANDLOCK, MNT_MFLAG | MNT_INVERT },/* Forbid mandatory locks on this FS */
+#endif
+#ifdef MS_NOATIME
+ { "atime", MS_NOATIME, MNT_MFLAG | MNT_INVERT }, /* Update access time */
+ { "noatime", MS_NOATIME, MNT_MFLAG }, /* Do not update access time */
+#endif
+#ifdef MS_I_VERSION
+ { "iversion", MS_I_VERSION, MNT_MFLAG }, /* Update inode I_version time */
+ { "noiversion", MS_I_VERSION, MNT_MFLAG | MNT_INVERT}, /* Don't update inode I_version time */
+#endif
+#ifdef MS_NODIRATIME
+ { "diratime", MS_NODIRATIME, MNT_MFLAG | MNT_INVERT }, /* Update dir access times */
+ { "nodiratime", MS_NODIRATIME, MNT_MFLAG }, /* Do not update dir access times */
+#endif
+#ifdef MS_RELATIME
+ { "relatime", MS_RELATIME, MNT_MFLAG }, /* Update access times relative to mtime/ctime */
+ { "norelatime", MS_RELATIME, MNT_MFLAG | MNT_INVERT }, /* Update access time without regard to mtime/ctime */
+#endif
+#ifdef MS_STRICTATIME
+ { "strictatime", MS_STRICTATIME, MNT_MFLAG }, /* Strict atime semantics */
+ { "nostrictatime", MS_STRICTATIME, MNT_MFLAG | MNT_INVERT }, /* kernel default atime */
+#endif
+ { NULL, 0, 0 }
+};
+
+/*
+ * userspace mount option (built-in MNT_USERSPACE_MAP)
+ */
+static const struct mnt_optmap userspace_opts_map[] =
+{
+ { "defaults", MNT_MS_DFLTS, MNT_NOMTAB }, /* default options */
+
+ { "auto", MNT_MS_NOAUTO, MNT_INVERT | MNT_NOMTAB }, /* Can be mounted using -a */
+ { "noauto", MNT_MS_NOAUTO, MNT_NOMTAB }, /* Can only be mounted explicitly */
+
+ { "user[=%s]", MNT_MS_USER }, /* Allow ordinary user to mount (mtab) */
+ { "nouser", MNT_MS_USER, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary user to mount */
+
+ { "users", MNT_MS_USERS, MNT_NOMTAB }, /* Allow ordinary users to mount */
+ { "nousers", MNT_MS_USERS, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary users to mount */
+
+ { "owner", MNT_MS_OWNER, MNT_NOMTAB }, /* Let the owner of the device mount */
+ { "noowner", MNT_MS_OWNER, MNT_INVERT | MNT_NOMTAB }, /* Device owner has no special privs */
+
+ { "group", MNT_MS_GROUP, MNT_NOMTAB }, /* Let the group of the device mount */
+ { "nogroup", MNT_MS_GROUP, MNT_INVERT | MNT_NOMTAB }, /* Device group has no special privs */
+
+ { "_netdev", MNT_MS_NETDEV }, /* Device requires network */
+
+ { "comment=%s", MNT_MS_COMMENT, MNT_NOMTAB }, /* fstab comment only */
+
+ { "loop[=%s]", MNT_MS_LOOP }, /* use the loop device */
+
+ { "nofail", MNT_MS_NOFAIL, MNT_NOMTAB }, /* Do not fail if ENOENT on dev */
+
+ { NULL, 0, 0 }
+};
+
+/**
+ * mnt_get_builtin_map:
+ * @id: map id -- MNT_LINUX_MAP or MNT_USERSPACE_MAP
+ *
+ * MNT_LINUX_MAP - Linux kernel fs-independent mount options
+ * (usually MS_* flags, see linux/fs.h)
+ *
+ * MNT_USERSPACE_MAP - userpace mount(8) specific mount options
+ * (e.g user=, _netdev, ...)
+ *
+ * Returns: static built-in libmount map.
+ */
+const struct mnt_optmap *mnt_get_builtin_optmap(int id)
+{
+ assert(id);
+
+ if (id == MNT_LINUX_MAP)
+ return linux_flags_map;
+ else if (id == MNT_USERSPACE_MAP)
+ return userspace_opts_map;
+ return NULL;
+}
+
+/*
+ * Lookups for the @name in @maps and returns a map and in @mapent
+ * returns the map entry
+ */
+const struct mnt_optmap *mnt_optmap_get_entry(
+ struct mnt_optmap const **maps,
+ int nmaps,
+ const char *name,
+ size_t namelen,
+ const struct mnt_optmap **mapent)
+{
+ int i;
+
+ assert(maps);
+ assert(nmaps);
+ assert(name);
+ assert(namelen);
+ assert(mapent);
+
+ *mapent = NULL;
+
+ for (i = 0; i < nmaps; i++) {
+ const struct mnt_optmap *map = maps[i];
+ const struct mnt_optmap *ent;
+ const char *p;
+
+ for (ent = map; ent && ent->name; ent++) {
+ if (strncmp(ent->name, name, namelen))
+ continue;
+ p = ent->name + namelen;
+ if (*p == '\0' || *p == '=' || *p == '[') {
+ *mapent = ent;
+ return map;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Converts @rawdata to number according to enum definition in the @mapent.
+ */
+int mnt_optmap_enum_to_number(const struct mnt_optmap *mapent,
+ const char *rawdata, size_t len)
+{
+ const char *p, *end = NULL, *begin = NULL;
+ int n = -1;
+
+ if (!rawdata || !*rawdata || !mapent || !len)
+ return -1;
+
+ p = strrchr(mapent->name, '=');
+ if (!p || *(p + 1) == '{')
+ return -1; /* value unexpected or not "enum" */
+ p += 2;
+ if (!*p || *(p + 1) == '}')
+ return -1; /* hmm... option <type> is "={" or "={}" */
+
+ /* we cannot use strstr(), @rawdata is not terminated */
+ for (; p && *p; p++) {
+ if (!begin)
+ begin = p; /* begin of the item */
+ if (*p == ',')
+ end = p; /* terminate the item */
+ if (*(p + 1) == '}')
+ end = p + 1; /* end of enum definition */
+ if (!begin || !end)
+ continue;
+ if (end <= begin)
+ return -1;
+ n++;
+ if (len == end - begin && strncasecmp(begin, rawdata, len) == 0)
+ return n;
+ p = end;
+ }
+
+ return -1;
+}
+
+/*
+ * Returns data type defined in the @mapent.
+ */
+const char *mnt_optmap_get_type(const struct mnt_optmap *mapent)
+{
+ char *type;
+
+ assert(mapent);
+ assert(mapent->name);
+
+ type = strrchr(mapent->name, '=');
+ if (!type)
+ return NULL; /* value is unexpected */
+ if (type == mapent->name)
+ return NULL; /* wrong format of type definition */
+ type++;
+ if (*type != '%' && *type != '{')
+ return NULL; /* wrong format of type definition */
+ return type ? : NULL;
+}
+
+/*
+ * Does the option (that is described by @mntent) require any value? (e.g.
+ * uid=<foo>)
+ */
+int mnt_optmap_require_value(const struct mnt_optmap *mapent)
+{
+ char *type;
+
+ assert(mapent);
+ assert(mapent->name);
+
+ type = strchr(mapent->name, '=');
+ if (!type)
+ return 0; /* value is unexpected */
+ if (type == mapent->name)
+ return 0; /* wrong format of type definition */
+ if (*(type - 1) == '[')
+ return 0; /* optional */
+ return 1;
+}
diff --git a/shlibs/mount/src/optstr.c b/shlibs/mount/src/optstr.c
new file mode 100644
index 00000000..19efbf3f
--- /dev/null
+++ b/shlibs/mount/src/optstr.c
@@ -0,0 +1,426 @@
+/*
+ * 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: optstr
+ * @title: Options string
+ * @short_description: low-level API for work with mount options
+ *
+ * This is simple and low-level API to work with mount options that are stored
+ * in string. This API is independent on the high-level options container and
+ * option maps.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "nls.h"
+#include "mountP.h"
+
+/*
+ * Parses the first option from @optstr. The @optstr pointer is set to begin of
+ * the next option.
+ *
+ * Returns -1 on parse error, 1 at the end of optstr and 0 on success.
+ */
+static int mnt_optstr_parse_next(char **optstr, char **name, size_t *namesz,
+ char **value, size_t *valsz)
+{
+ int open_quote = 0;
+ char *start = NULL, *stop = NULL, *p, *sep = NULL;
+ char *optstr0;
+
+ assert(optstr);
+ assert(*optstr);
+
+ optstr0 = *optstr;
+
+ if (name)
+ *name = NULL;
+ if (namesz)
+ *namesz = 0;
+ if (value)
+ *value = NULL;
+ if (valsz)
+ *valsz = 0;
+
+ for (p = optstr0; p && *p; p++) {
+ if (!start)
+ start = p; /* begin of the option item */
+ if (*p == '"')
+ open_quote ^= 1; /* reverse the status */
+ if (open_quote)
+ continue; /* still in quoted block */
+ if (!sep && *p == '=')
+ sep = p; /* name and value separator */
+ if (*p == ',')
+ stop = p; /* terminate the option item */
+ else if (*(p + 1) == '\0')
+ stop = p + 1; /* end of optstr */
+ if (!start || !stop)
+ continue;
+ if (stop <= start)
+ goto error;
+
+ if (name)
+ *name = start;
+ if (namesz)
+ *namesz = sep ? sep - start : stop - start;
+ *optstr = *stop ? stop + 1 : stop;
+
+ if (sep) {
+ if (value)
+ *value = sep + 1;
+ if (valsz)
+ *valsz = stop - sep - 1;
+ }
+ return 0;
+ }
+
+ return 1; /* end of optstr */
+
+error:
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: parse error: \"%s\"\n", optstr0));
+ return -1;
+}
+
+/*
+ * Locates the first option that match with @name. The @end is set to
+ * char behind the option (it means ',' or \0).
+ *
+ * Returns -1 on parse error, 1 when not found and 0 on success.
+ */
+static int mnt_optstr_locate_option(char *optstr, const char *name, char **begin,
+ char **end, char **value, size_t *valsz)
+{
+ char *n;
+ size_t namesz, nsz;
+ int rc;
+
+ assert(name);
+ assert(optstr);
+
+ namesz = strlen(name);
+
+ do {
+ rc = mnt_optstr_parse_next(&optstr, &n, &nsz, value, valsz);
+ if (rc)
+ break;
+
+ if (namesz == nsz && strncmp(n, name, nsz) == 0) {
+ if (begin)
+ *begin = n;
+ if (end)
+ *end = *(optstr - 1) == ',' ?
+ optstr - 1 : optstr;
+ return 0;
+ }
+ } while(1);
+
+ DBG(DEBUG_OPTIONS, fprintf(stderr,
+ "libmount: can't found '%s' option\n", name));
+ return rc;
+}
+
+/**
+ * mnt_optstr_next_option:
+ * @optstr: option string, returns position to next option
+ * @name: returns option name
+ * @namesz: returns option name length
+ * @value: returns option value or NULL
+ * @valuesz: returns option value length or zero
+ *
+ * Parses the first option in @optstr or -1 in case of error.
+ *
+ * Returns: 0 on success, 1 at the end of @optstr or -1 in case of error.
+ */
+int mnt_optstr_next_option(char **optstr, char **name, size_t *namesz,
+ char **value, size_t *valuesz)
+{
+ if (!optstr || !*optstr)
+ return -1;
+ return mnt_optstr_parse_next(optstr, name, namesz, value, valuesz);
+}
+
+/**
+ * mnt_optstr_append_option:
+ * @optstr: option string or NULL
+ * @name: value name
+ * @value: value
+ *
+ * Returns: reallocated (or newly allocated) @optstr with ,name=value
+ */
+int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
+{
+ char *p;
+ size_t sz, vsz, osz, nsz;
+
+ if (!name)
+ return -1;
+
+ osz = *optstr ? strlen(*optstr) : 0;
+ nsz = strlen(name);
+ vsz = value ? strlen(value) : 0;
+
+ sz = osz + nsz + 1; /* 1: '\0' */
+ if (osz)
+ sz++; /* ',' options separator */
+ if (vsz)
+ sz += vsz + 1; /* 1: '=' */
+
+ p = realloc(*optstr, sz);
+ if (!p)
+ return -1;
+ *optstr = p;
+
+ if (osz) {
+ p += osz;
+ *p++ = ',';
+ }
+
+ memcpy(p, name, nsz);
+ p += nsz;
+
+ if (vsz) {
+ *p++ = '=';
+ memcpy(p, value, vsz);
+ p += vsz;
+ }
+ *p = '\0';
+
+ return 0;
+}
+
+/**
+ * mnt_optstr_get_option:
+ * @optstr: string with comma separated list of options
+ * @name: requested option name
+ * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @valsz: returns size of the value or 0
+ *
+ * Returns: 0 on success, 1 when not found the @name or -1 in case of error.
+ */
+int mnt_optstr_get_option(char *optstr, const char *name,
+ char **value, size_t *valsz)
+{
+ return mnt_optstr_locate_option(optstr, name, NULL, NULL, value, valsz);
+}
+
+/* Removes substring located between @begin and @end from @str
+ * -- result never starts or ends with comma or contains two commas
+ * (e.g. ",aaa,bbb" or "aaa,,bbb" or "aaa,")
+ */
+static void remove_substring(char *str, char *begin, char *end)
+{
+ size_t sz = strlen(end);
+
+ if ((begin == str || *(begin - 1) == ',') && *end == ',')
+ end++;
+
+ memmove(begin, end, sz + 1);
+ if (!*begin && *(begin - 1) == ',')
+ *(begin - 1) = '\0';
+}
+
+/* insert '=substr' to @str on position @pos */
+static int insert_substring(char **str, char *pos, const char *substr)
+{
+ char *p;
+ size_t ssz = strlen(substr); /* substring size */
+
+ p = realloc(*str, strlen(*str) + 1 + ssz);
+ if (!p)
+ return -1;
+ *str = p;
+
+ memmove(pos + ssz + 1, pos, strlen(pos) + 1);
+ *pos++ = '=';
+ memcpy(pos, substr, ssz);
+ return 0;
+}
+
+/**
+ * mnt_optstr_set_option:
+ * @optstr: string with comma separated list of options
+ * @name: requested option
+ * @value: new value or NULL
+ *
+ * Set or unset option @value.
+ *
+ * Returns: 0 on success, 1 when not found the @name or -1 in case of error.
+ */
+int mnt_optstr_set_option(char **optstr, const char *name, const char *value)
+{
+ char *val = NULL, *begin, *end, *nameend;
+ size_t valsz;
+ int rc = 1;
+
+ if (!optstr)
+ return -1;
+ if (*optstr)
+ rc = mnt_optstr_locate_option(*optstr, name,
+ &begin, &end, &val, &valsz);
+ if (rc == -1)
+ /* parse error */
+ return -1;
+ if (rc == 1)
+ /* not found */
+ return mnt_optstr_append_option(optstr, name, value);
+
+ nameend = begin + strlen(name);
+
+ if (value == NULL && val && valsz)
+ /* remove unwanted "=value" */
+ remove_substring(*optstr, nameend, end);
+
+ else if (value && val == NULL)
+ /* insert "=value" */
+ rc = insert_substring(optstr, nameend, value);
+
+ else if (value && val && strlen(value) == valsz)
+ /* simply replace =value */
+ memcpy(val, value, valsz);
+
+ else if (value && val) {
+ remove_substring(*optstr, nameend, end);
+ rc = insert_substring(optstr, nameend, value);
+ }
+
+
+ return 0;
+}
+
+/**
+ * mnt_optstr_remove_option:
+ * @optstr: string with comma separated list of options
+ * @name: requested option name
+ *
+ * Returns: 0 on success, 1 when not found the @name or -1 in case of error.
+ */
+int mnt_optstr_remove_option(char **optstr, const char *name)
+{
+ char *begin, *end;
+ int rc;
+
+ rc = mnt_optstr_locate_option(*optstr, name,
+ &begin, &end, NULL, NULL);
+ if (rc != 0)
+ return rc;
+
+ remove_substring(*optstr, begin, end);
+ return 0;
+}
+
+#ifdef TEST_PROGRAM
+
+int test_append(struct mtest *ts, int argc, char *argv[])
+{
+ const char *value = NULL, *name;
+ char *optstr;
+
+ if (argc < 3)
+ goto done;
+ optstr = strdup(argv[1]);
+ name = argv[2];
+
+ if (argc == 4)
+ value = argv[3];
+
+ if (mnt_optstr_append_option(&optstr, name, value) == 0) {
+ printf("result: >%s<\n", optstr);
+ return 0;
+ }
+done:
+ return -1;
+}
+
+int test_set(struct mtest *ts, int argc, char *argv[])
+{
+ const char *value = NULL, *name;
+ char *optstr;
+
+ if (argc < 3)
+ goto done;
+ optstr = strdup(argv[1]);
+ name = argv[2];
+
+ if (argc == 4)
+ value = argv[3];
+
+ if (mnt_optstr_set_option(&optstr, name, value) == 0) {
+ printf("result: >%s<\n", optstr);
+ return 0;
+ }
+done:
+ return -1;
+}
+
+int test_get(struct mtest *ts, int argc, char *argv[])
+{
+ char *optstr;
+ const char *name;
+ char *val = NULL;
+ size_t sz = 0;
+ int rc;
+
+ if (argc < 2)
+ goto done;
+ optstr = argv[1];
+ name = argv[2];
+
+ rc = mnt_optstr_get_option(optstr, name, &val, &sz);
+ if (rc == 0) {
+ printf("found; name: %s", name);
+ if (sz) {
+ printf(", argument: size=%zd data=", sz);
+ if (fwrite(val, 1, sz, stdout) != sz)
+ goto done;
+ }
+ printf("\n");
+ return 0;
+ } else if (rc == 1)
+ printf("%s: not found\n", name);
+ else
+ printf("parse error: %s\n", optstr);
+done:
+ return -1;
+}
+
+int test_remove(struct mtest *ts, int argc, char *argv[])
+{
+ const char *name;
+ char *optstr;
+
+ if (argc < 3)
+ goto done;
+ optstr = strdup(argv[1]);
+ name = argv[2];
+
+ if (mnt_optstr_remove_option(&optstr, name) == 0) {
+ printf("result: >%s<\n", optstr);
+ return 0;
+ }
+done:
+ return -1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--append", test_append, "<optstr> <name> [<value>] append value to optstr" },
+ { "--set", test_set, "<optstr> <name> [<value>] (un)set value" },
+ { "--get", test_get, "<optstr> <name> search name in optstr" },
+ { "--remove", test_remove, "<optstr> <name> remove name in optstr" },
+ { NULL }
+ };
+ return mnt_run_test(tss, argc, argv);
+}
+#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/tab.c b/shlibs/mount/src/tab.c
new file mode 100644
index 00000000..cb6a91d3
--- /dev/null
+++ b/shlibs/mount/src/tab.c
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2008-2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+/**
+ * SECTION: tab
+ * @title: FS container
+ * @short_description: container for entries from fstab/mtab/mountinfo
+ *
+ *
+ * Note that mnt_tab_find_* functions are mount(8) compatible. These functions
+ * try to found an entry in more iterations where the first attempt is always
+ * based on comparison with unmodified (non-canonicalized or un-evaluated)
+ * paths or tags. For example fstab with two entries:
+ * <informalexample>
+ * <programlisting>
+ * LABEL=foo /foo auto rw
+ * /dev/foo /foo auto rw
+ * </programlisting>
+ * </informalexample>
+ *
+ * where both lines are used for the *same* device, then
+ * <informalexample>
+ * <programlisting>
+ * mnt_tab_find_source(tb, "/dev/foo", &fs);
+ * </programlisting>
+ * </informalexample>
+ * will returns the second line, and
+ * <informalexample>
+ * <programlisting>
+ * mnt_tab_find_source(tb, "LABEL=foo", &fs);
+ * </programlisting>
+ * </informalexample>
+ * will returns the first entry, and
+ * <informalexample>
+ * <programlisting>
+ * mnt_tab_find_source(tb, "UUID=anyuuid", &fs);
+ * </programlisting>
+ * </informalexample>
+ * will returns the first entry (if UUID matches with the device).
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <blkid.h>
+
+#include "nls.h"
+#include "mountP.h"
+#include "c.h"
+
+/**
+ * mnt_new_tab:
+ * @filename: file name or NULL
+ *
+ * The tab is a container for mnt_fs entries that usually represents a fstab,
+ * mtab or mountinfo file from your system.
+ *
+ * Note that this function does not parse the file. See also
+ * mnt_tab_parse_file().
+ *
+ * Returns: newly allocated tab struct.
+ */
+mnt_tab *mnt_new_tab(const char *filename)
+{
+ mnt_tab *tb = NULL;
+
+ tb = calloc(1, sizeof(struct _mnt_tab));
+ if (!tb)
+ goto err;
+
+ if (filename) {
+ tb->filename = strdup(filename);
+ if (!tb->filename)
+ goto err;
+ }
+ INIT_LIST_HEAD(&tb->ents);
+ return tb;
+err:
+ free(tb);
+ return NULL;
+}
+
+/**
+ * mnt_free_tab:
+ * @tb: tab pointer
+ *
+ * Deallocates tab struct and all entries.
+ */
+void mnt_free_tab(mnt_tab *tb)
+{
+ if (!tb)
+ return;
+ free(tb->filename);
+
+ while (!list_empty(&tb->ents)) {
+ mnt_fs *fs = list_entry(tb->ents.next, mnt_fs, ents);
+ mnt_free_fs(fs);
+ }
+
+ free(tb);
+}
+
+/**
+ * mnt_tab_get_nents:
+ * @tb: pointer to tab
+ *
+ * Returns: number of valid entries in tab.
+ */
+int mnt_tab_get_nents(mnt_tab *tb)
+{
+ assert(tb);
+ return tb ? tb->nents : 0;
+}
+
+/**
+ * mnt_tab_set_cache:
+ * @tb: pointer to tab
+ * @mpc: pointer to mnt_cache instance
+ *
+ * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
+ * cache is recommended for mnt_tab_find_*() functions.
+ *
+ * The cache could be shared between more tabs. Be careful when you share the
+ * same cache between more threads -- currently the cache does not provide any
+ * locking method.
+ *
+ * See also mnt_new_cache().
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_tab_set_cache(mnt_tab *tb, mnt_cache *mpc)
+{
+ assert(tb);
+ if (!tb)
+ return -1;
+ tb->cache = mpc;
+ return 0;
+}
+
+/**
+ * mnt_tab_get_cache:
+ * @tb: pointer to tab
+ *
+ * Returns: pointer to mnt_cache instance or NULL.
+ */
+mnt_cache *mnt_tab_get_cache(mnt_tab *tb)
+{
+ assert(tb);
+ return tb ? tb->cache : NULL;
+}
+
+/**
+ * mnt_tab_get_name:
+ * @tb: tab pointer
+ *
+ * Returns: tab filename or NULL.
+ */
+const char *mnt_tab_get_name(mnt_tab *tb)
+{
+ assert(tb);
+ return tb ? tb->filename : NULL;
+}
+
+/**
+ * mnt_tab_add_fs:
+ * @tb: tab pointer
+ * @fs: new entry
+ *
+ * Adds a new entry to tab.
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_tab_add_fs(mnt_tab *tb, mnt_fs *fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -1;
+
+ list_add_tail(&fs->ents, &tb->ents);
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: add entry: %s %s\n",
+ tb->filename, mnt_fs_get_source(fs),
+ mnt_fs_get_target(fs)));
+
+ if (fs->flags & MNT_FS_ERROR)
+ tb->nerrs++;
+ else
+ tb->nents++;
+ return 0;
+}
+
+/**
+ * mnt_tab_remove_fs:
+ * @tb: tab pointer
+ * @fs: new entry
+ *
+ * Returns: 0 on success or -1 in case of error.
+ */
+int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -1;
+
+ list_del(&fs->ents);
+
+ if (fs->flags & MNT_FS_ERROR)
+ tb->nerrs--;
+ else
+ tb->nents--;
+ return 0;
+}
+
+/**
+ * mnt_tab_get_root_fs:
+ * @tb: mountinfo file (/proc/self/mountinfo)
+ * @root: returns pointer to the root filesystem (/)
+ *
+ * Returns: 0 on success or -1 case of error.
+ */
+int mnt_tab_get_root_fs(mnt_tab *tb, mnt_fs **root)
+{
+ mnt_iter itr;
+ mnt_fs *fs;
+ int root_id = 0;
+
+ assert(tb);
+ assert(root);
+
+ if (!tb || !root)
+ return -1;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup root fs\n", tb->filename));
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ int id = mnt_fs_get_parent_id(fs);
+ if (!id)
+ break; /* @tab is not mountinfo file? */
+
+ if (!*root || id < root_id) {
+ *root = fs;
+ root_id = id;
+ }
+ }
+
+ return root_id ? 0 : -1;
+}
+
+/**
+ * mnt_tab_next_child_fs:
+ * @tb: mountinfo file (/proc/self/mountinfo)
+ * @itr: iterator
+ * @parent: parental FS
+ * @chld: returns the next child filesystem
+ *
+ * Note that filesystems are returned in the order how was mounted (according to
+ * IDs in /proc/self/mountinfo).
+ *
+ * Returns: 0 on success, -1 in case of error or 1 at end of list.
+ */
+int mnt_tab_next_child_fs(mnt_tab *tb, mnt_iter *itr,
+ mnt_fs *parent, mnt_fs **chld)
+{
+ mnt_fs *fs;
+ int parent_id, lastchld_id = 0, chld_id = 0;
+
+ if (!tb || !itr || !parent)
+ return -1;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup next child of %s\n",
+ tb->filename, mnt_fs_get_target(parent)));
+
+ parent_id = mnt_fs_get_id(parent);
+ if (!parent_id)
+ return -1;
+
+ /* get ID of the previously returned child */
+ if (itr->head && itr->p != itr->head) {
+ MNT_ITER_ITERATE(itr, fs, struct _mnt_fs, ents);
+ lastchld_id = mnt_fs_get_id(fs);
+ }
+
+ *chld = NULL;
+
+ mnt_reset_iter(itr, MNT_ITER_FORWARD);
+ while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
+ int id;
+
+ if (mnt_fs_get_parent_id(fs) != parent_id)
+ continue;
+
+ id = mnt_fs_get_id(fs);
+
+ if ((!lastchld_id || id > lastchld_id) &&
+ (!*chld || id < chld_id)) {
+ *chld = fs;
+ chld_id = id;
+ }
+ }
+
+ if (!chld_id)
+ return 1; /* end of iterator */
+
+ /* set the iterator to the @chld for the next call */
+ mnt_tab_set_iter(tb, itr, *chld);
+
+ return 0;
+}
+
+/**
+ * mnt_tab_next_fs:
+ * @tb: tab pointer
+ * @itr: iterator
+ * @fs: returns the next tab entry
+ *
+ * Returns: 0 on success, -1 in case of error or 1 at end of list.
+ *
+ * Example (list all mountpoints from fstab in backward order):
+ * <informalexample>
+ * <programlisting>
+ * mnt_fs *fs;
+ * mnt_tab *tb = mnt_new_tab("/etc/fstab");
+ * mnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
+ *
+ * mnt_tab_parse_file(tb);
+ *
+ * while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
+ * const char *dir = mnt_fs_get_target(fs);
+ * printf("mount point: %s\n", dir);
+ * }
+ * mnt_free_tab(fi);
+ * </programlisting>
+ * </informalexample>
+ */
+int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs)
+{
+ int rc;
+
+ assert(tb);
+ assert(itr);
+ assert(fs);
+
+ if (!tb || !itr || !fs)
+ return -1;
+again:
+ rc = 1;
+ if (!itr->head)
+ MNT_ITER_INIT(itr, &tb->ents);
+ if (itr->p != itr->head) {
+ MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
+ rc = 0;
+ }
+
+ /* ignore broken entries */
+ if (*fs && ((*fs)->flags & MNT_FS_ERROR))
+ goto again;
+
+ return rc;
+}
+
+/**
+ * mnt_tab_find_next_fs:
+ * @tb: table
+ * @itr: iterator
+ * @match_func: function returns 1 or 0
+ * @userdata: extra data for match_func
+ * @fs: returns pointer to the next matching table entry
+ *
+ * This function allows search in @tb.
+ *
+ * Returns: -1 in case of error, 1 at end of table or 0 o success.
+ */
+int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
+ int (*match_func)(mnt_fs *, void *), void *userdata,
+ mnt_fs **fs)
+{
+ if (!tb || !itr || !fs || !match_func)
+ return -1;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup next fs\n", tb->filename));
+
+ if (!itr->head)
+ MNT_ITER_INIT(itr, &tb->ents);
+
+ do {
+ if (itr->p != itr->head)
+ MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
+ else
+ break; /* end */
+
+ if ((*fs)->flags & MNT_FS_ERROR)
+ continue;
+ if (match_func(*fs, userdata))
+ return 0;
+ } while(1);
+
+ *fs = NULL;
+ return 1;
+}
+
+/**
+ * mnt_tab_set_iter:
+ * @tb: tab pointer
+ * @itr: iterator
+ * @fs: tab entry
+ *
+ * Sets @iter to the position of @fs in the file @tb.
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_tab_set_iter(mnt_tab *tb, mnt_iter *itr, mnt_fs *fs)
+{
+ assert(tb);
+ assert(itr);
+ assert(fs);
+
+ if (!tb || !itr || !fs)
+ return -1;
+
+ MNT_ITER_INIT(itr, &tb->ents);
+ itr->p = &fs->ents;
+
+ return 0;
+}
+
+/**
+ * mnt_tab_find_target:
+ * @tb: tab pointer
+ * @path: mountpoint directory
+ * @direction: MNT_ITER_{FORWARD,BACKWARD}
+ *
+ * Try to lookup an entry in given tab, possible are three iterations, first
+ * with @path, second with realpath(@path) and third with realpath(@path)
+ * against realpath(fs->target). The 2nd and 3rd iterations are not performed
+ * when @tb cache is not set (see mnt_tab_set_cache()).
+ *
+ * Returns: a tab entry or NULL.
+ */
+mnt_fs *mnt_tab_find_target(mnt_tab *tb, const char *path, int direction)
+{
+ mnt_iter itr;
+ mnt_fs *fs = NULL;
+ char *cn;
+
+ assert(tb);
+ assert(path);
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup target: %s\n", tb->filename, path));
+
+ /* native @target */
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0)
+ if (fs->target && strcmp(fs->target, path) == 0)
+ return fs;
+
+ if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
+ return NULL;
+
+ /* canonicalized paths in mnt_tab */
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ if (fs->target && strcmp(fs->target, cn) == 0)
+ return fs;
+ }
+
+ /* non-canonicaled path in mnt_tab */
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ char *p;
+ if (!fs->target)
+ continue;
+ p = mnt_resolve_path(fs->target, tb->cache);
+ if (strcmp(cn, p) == 0)
+ return fs;
+ }
+ return NULL;
+}
+
+/**
+ * mnt_tab_find_srcpath:
+ * @tb: tab pointer
+ * @path: source path (devname or dirname)
+ * @direction: MNT_ITER_{FORWARD,BACKWARD}
+ *
+ * Try to lookup an entry in given tab, possible are four iterations, first
+ * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
+ * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
+ *
+ * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
+ * set (see mnt_tab_set_cache()).
+ *
+ * Returns: a tab entry or NULL.
+ */
+mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction)
+{
+ mnt_iter itr;
+ mnt_fs *fs = NULL;
+ int ntags = 0;
+ char *cn;
+ const char *p;
+
+ assert(tb);
+ assert(path);
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup srcpath: %s\n", tb->filename, path));
+
+ /* native paths */
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ p = mnt_fs_get_srcpath(fs);
+ if (p && strcmp(p, path) == 0)
+ return fs;
+ if (!p)
+ /* mnt_fs_get_srcpath() returs nothing, it's TAG */
+ ntags++;
+ }
+
+ if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
+ return NULL;
+
+ /* canonicalized paths in mnt_tab */
+ if (ntags < mnt_tab_get_nents(tb)) {
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ p = mnt_fs_get_srcpath(fs);
+ if (p && strcmp(p, cn) == 0)
+ return fs;
+ }
+ }
+
+ /* evaluated tag */
+ if (ntags) {
+ int rc = mnt_cache_read_tags(tb->cache, cn);
+
+ mnt_reset_iter(&itr, direction);
+
+ if (rc == 0) {
+ /* @path's TAGs are in the cache */
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ const char *t, *v;
+
+ if (mnt_fs_get_tag(fs, &t, &v))
+ continue;
+
+ if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
+ return fs;
+ }
+ } else if (rc < 0 && errno == EACCES) {
+ /* @path is unaccessible, try evaluate all TAGs in @tb
+ * by udev symlinks -- this could be expensive on systems
+ * with huge fstab/mtab */
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ const char *t, *v, *x;
+ if (mnt_fs_get_tag(fs, &t, &v))
+ continue;
+ x = mnt_resolve_tag(t, v, tb->cache);
+ if (x && !strcmp(x, cn))
+ return fs;
+ }
+ }
+ }
+
+ /* non-canonicalized paths in mnt_tab */
+ if (ntags <= mnt_tab_get_nents(tb)) {
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ p = mnt_fs_get_srcpath(fs);
+ if (p)
+ p = mnt_resolve_path(p, tb->cache);
+ if (p && strcmp(cn, p) == 0)
+ return fs;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * mnt_tab_find_tag:
+ * @tb: tab pointer
+ * @tag: tag name (e.g "LABEL", "UUID", ...)
+ * @val: tag value
+ * @direction: MNT_ITER_{FORWARD,BACKWARD}
+ *
+ * Try to lookup an entry in given tab, first attempt is lookup by @tag and
+ * @val, for the second attempt the tag is evaluated (converted to the device
+ * name) and mnt_tab_find_srcpath() is preformed. The second attempt is not
+ * performed when @tb cache is not set (see mnt_tab_set_cache()).
+
+ * Returns: a tab entry or NULL.
+ */
+mnt_fs *mnt_tab_find_tag(mnt_tab *tb, const char *tag,
+ const char *val, int direction)
+{
+ mnt_iter itr;
+ mnt_fs *fs = NULL;
+
+ assert(tb);
+ assert(tag);
+ assert(val);
+
+ if (!tb || !tag || !val)
+ return NULL;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup by TAG: %s %s\n", tb->filename, tag, val));
+
+ /* look up by TAG */
+ mnt_reset_iter(&itr, direction);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ if (fs->tagname && fs->tagval &&
+ strcmp(fs->tagname, tag) == 0 &&
+ strcmp(fs->tagval, val) == 0)
+ return fs;
+ }
+
+ if (tb->cache) {
+ /* look up by device name */
+ char *cn = mnt_resolve_tag(tag, val, tb->cache);
+ if (cn)
+ return mnt_tab_find_srcpath(tb, cn, direction);
+ }
+ return NULL;
+}
+
+/**
+ * mnt_tab_find_source:
+ * @tb: tab pointer
+ * @source: TAG or path
+ * @direction: MNT_ITER_{FORWARD,BACKWARD}
+ *
+ * This is high-level API for mnt_tab_find_{srcpath,tag}. You needn't to care
+ * about @source format (device, LABEL, UUID, ...). This function parses @source
+ * and calls mnt_tab_find_tag() or mnt_tab_find_srcpath().
+ *
+ * Returns: a tab entry or NULL.
+ */
+mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction)
+{
+ mnt_fs *fs = NULL;
+
+ assert(tb);
+ assert(source);
+
+ if (!tb || !source)
+ return NULL;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: lookup SOURCE: %s\n", tb->filename, source));
+
+ if (strchr(source, '=')) {
+ char *tag, *val;
+
+ if (blkid_parse_tag_string(source, &tag, &val) == 0) {
+
+ fs = mnt_tab_find_tag(tb, tag, val, direction);
+
+ free(tag);
+ free(val);
+ }
+ } else
+ fs = mnt_tab_find_srcpath(tb, source, direction);
+
+ return fs;
+}
+
+
+/**
+ * mnt_tab_fprintf:
+ * @tb: tab pointer
+ * @f: FILE
+ * @fmt: per line printf-like format string (see MNT_TAB_PRINTFMT)
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_tab_fprintf(mnt_tab *tb, FILE *f, const char *fmt)
+{
+ mnt_iter itr;
+ mnt_fs *fs;
+
+ assert(f);
+ assert(fmt);
+ assert(tb);
+
+ if (!f || !fmt || !tb)
+ return -1;
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ if (mnt_fs_fprintf(fs, f, fmt) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * mnt_tab_update_file
+ * @tb: tab pointer
+ *
+ * Writes tab to disk. Don't forget to lock the file (see mnt_lock()).
+ *
+ * Returns: 0 on success, -1 in case of error.
+ */
+int mnt_tab_update_file(mnt_tab *tb)
+{
+ FILE *f = NULL;
+ char tmpname[PATH_MAX];
+ const char *filename;
+ struct stat st;
+ int fd;
+
+ assert(tb);
+ if (!tb)
+ goto error;
+
+ filename = mnt_tab_get_name(tb);
+ if (!filename)
+ goto error;
+
+ if (snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename)
+ >= sizeof(tmpname))
+ goto error;
+
+ f = fopen(tmpname, "w");
+ if (!f)
+ goto error;
+
+ if (mnt_tab_fprintf(tb, f, MNT_TAB_PRINTFMT) != 0)
+ goto error;
+
+ fd = fileno(f);
+
+ if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ goto error;
+
+ /* Copy uid/gid from the present file before renaming. */
+ if (stat(filename, &st) == 0) {
+ if (fchown(fd, st.st_uid, st.st_gid) < 0)
+ goto error;
+ }
+
+ fclose(f);
+ f = NULL;
+
+ if (rename(tmpname, filename) < 0)
+ goto error;
+
+ return 0;
+error:
+ if (f)
+ fclose(f);
+ return -1;
+}
+
+#ifdef TEST_PROGRAM
+int test_strerr(struct mtest *ts, int argc, char *argv[])
+{
+ char buf[BUFSIZ];
+ mnt_tab *tb;
+ int i;
+
+ tb = mnt_new_tab("-test-");
+ if (!tb)
+ goto err;
+
+ for (i = 0; i < 10; i++) {
+ mnt_fs *fs = mnt_new_fs();
+ if (!fs)
+ goto err;
+ if (i % 2)
+ fs->flags |= MNT_FS_ERROR; /* mark entry as broken */
+ fs->lineno = i+1;
+ mnt_tab_add_fs(tb, fs);
+ }
+
+ printf("\tadded %d valid lines\n", mnt_tab_get_nents(tb));
+ printf("\tadded %d broken lines\n", mnt_tab_get_nerrs(tb));
+
+ if (!mnt_tab_get_nerrs(tb)) /* report broken entries */
+ goto err;
+ mnt_tab_strerror(tb, buf, sizeof(buf));
+ printf("\t%s\n", buf);
+
+ mnt_free_tab(tb);
+ return 0;
+err:
+ return -1;
+}
+
+mnt_tab *create_tab(const char *file)
+{
+ mnt_tab *tb;
+
+ if (!file)
+ return NULL;
+ tb = mnt_new_tab(file);
+ if (!tb)
+ goto err;
+ if (mnt_tab_parse_file(tb) != 0)
+ goto err;
+ if (mnt_tab_get_nerrs(tb)) {
+ char buf[BUFSIZ];
+ mnt_tab_strerror(tb, buf, sizeof(buf));
+ fprintf(stderr, "%s\n", buf);
+ goto err;
+ }
+ return tb;
+err:
+ mnt_free_tab(tb);
+ return NULL;
+}
+
+int test_parse(struct mtest *ts, int argc, char *argv[])
+{
+ mnt_tab *tb;
+ mnt_iter *itr;
+ mnt_fs *fs;
+
+ tb = create_tab(argv[1]);
+ if (!tb)
+ return -1;
+
+ itr = mnt_new_iter(MNT_ITER_FORWARD);
+ if (!itr)
+ goto err;
+ while(mnt_tab_next_fs(tb, itr, &fs) == 0)
+ mnt_fs_print_debug(fs, stdout);
+err:
+ mnt_free_iter(itr);
+ mnt_free_tab(tb);
+ return 0;
+}
+
+int test_find(struct mtest *ts, int argc, char *argv[], int dr)
+{
+ mnt_tab *tb;
+ mnt_fs *fs = NULL;
+ mnt_cache *mpc;
+ const char *file, *find, *what;
+
+ if (argc != 4) {
+ fprintf(stderr, "try --help\n");
+ goto err;
+ }
+
+ file = argv[1], find = argv[2], what = argv[3];
+
+ tb = create_tab(file);
+ if (!tb)
+ goto err;
+
+ /* create a cache for canonicalized paths */
+ mpc = mnt_new_cache();
+ if (!mpc)
+ goto err;
+ mnt_tab_set_cache(tb, mpc);
+
+ if (strcasecmp(find, "source") == 0)
+ fs = mnt_tab_find_source(tb, what, dr);
+ else if (strcasecmp(find, "target") == 0)
+ fs = mnt_tab_find_target(tb, what, dr);
+
+ if (!fs)
+ fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
+ else {
+ const char *s = mnt_fs_get_srcpath(fs);
+ if (s)
+ printf("%s", s);
+ else {
+ const char *tag, *val;
+ mnt_fs_get_tag(fs, &tag, &val);
+ printf("%s=%s", tag, val);
+ }
+ printf("|%s|%s\n", mnt_fs_get_target(fs),
+ mnt_fs_get_optstr(fs));
+ }
+ mnt_free_tab(tb);
+ mnt_free_cache(mpc);
+ return 0;
+err:
+ return -1;
+}
+
+int test_find_bw(struct mtest *ts, int argc, char *argv[])
+{
+ return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
+}
+
+int test_find_fw(struct mtest *ts, int argc, char *argv[])
+{
+ return test_find(ts, argc, argv, MNT_ITER_FORWARD);
+}
+
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--strerror", test_strerr, " test tab error reporting" },
+ { "--parse", test_parse, "<file> parse and print tab" },
+ { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
+ { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
+ { NULL }
+ };
+
+ return mnt_run_test(tss, argc, argv);
+}
+
+#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/tab_parse.c b/shlibs/mount/src/tab_parse.c
new file mode 100644
index 00000000..680e1fc1
--- /dev/null
+++ b/shlibs/mount/src/tab_parse.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "nls.h"
+#include "mangle.h"
+#include "mountP.h"
+
+static inline char *skip_spaces(char *s)
+{
+ assert(s);
+
+ while (*s == ' ' || *s == '\t')
+ s++;
+ return s;
+}
+
+static inline char *skip_nonspaces(char *s)
+{
+ assert(s);
+
+ while (*s && !(*s == ' ' || *s == '\t'))
+ s++;
+ return s;
+}
+
+static size_t next_word_size(char *s, char **start, char **end)
+{
+ char *e;
+
+ assert(s);
+
+ s = skip_spaces(s);
+ if (!*s)
+ return 0;
+ e = skip_nonspaces(s);
+
+ if (start)
+ *start = s;
+ if (end)
+ *end = e;
+
+ return e - s;
+}
+
+static char *next_word(char **s)
+{
+ size_t sz;
+ char *res, *end;
+
+ assert(s);
+
+ sz = next_word_size(*s, s, &end) + 1;
+ if (sz == 1)
+ return NULL;
+
+ res = malloc(sz);
+ if (!res)
+ return NULL;
+
+ unmangle_to_buffer(*s, res, sz);
+ *s = end + 1;
+ return res;
+}
+
+static int next_word_skip(char **s)
+{
+ *s = skip_spaces(*s);
+ if (!**s)
+ return 1;
+ *s = skip_nonspaces(*s);
+ return 0;
+}
+
+static int next_number(char **s, int *num)
+{
+ char *end = NULL;
+
+ assert(num);
+ assert(s);
+
+ *s = skip_spaces(*s);
+ if (!**s)
+ return -1;
+ *num = strtol(*s, &end, 10);
+ if (end == NULL || *s == end)
+ return -1;
+
+ *s = end;
+
+ /* valid end of number is space or terminator */
+ if (*end == ' ' || *end == '\t' || *end == '\0')
+ return 0;
+ return -1;
+}
+
+/*
+ * Parses one line from {fs,m}tab
+ */
+static int mnt_tab_parse_file_line(mnt_fs *fs, char *s)
+{
+ /* SOURCE */
+ if (__mnt_fs_set_source(fs, next_word(&s)) != 0)
+ return 1;
+
+ /* TARGET */
+ fs->target = next_word(&s);
+ if (!fs->target)
+ return 1;
+
+ /* TYPE */
+ if (__mnt_fs_set_fstype(fs, next_word(&s)) != 0)
+ return 1;
+
+ /* OPTS */
+ fs->optstr = next_word(&s);
+ if (!fs->optstr)
+ return 1;
+ /* default */
+ fs->passno = fs->freq = 0;
+
+ /* FREQ (optional) */
+ if (next_number(&s, &fs->freq) != 0) {
+ if (*s)
+ return 1;
+
+ /* PASSNO (optional) */
+ } else if (next_number(&s, &fs->passno) != 0 && *s)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Parses one line from mountinfo file
+ */
+static int mnt_parse_mountinfo_line(mnt_fs *fs, char *s)
+{
+ unsigned int maj, min;
+
+ /* ID */
+ if (next_number(&s, &fs->id) != 0)
+ return 1;
+
+ /* PARENT */
+ if (next_number(&s, &fs->parent) != 0)
+ return 1;
+
+ /* <maj>:<min> */
+ s = skip_spaces(s);
+ if (!*s || sscanf(s, "%u:%u", &maj, &min) != 2)
+ return 1;
+ fs->devno = makedev(maj, min);
+ next_word_skip(&s);
+
+ /* MOUNTROOT */
+ fs->mntroot = next_word(&s);
+ if (!fs->mntroot)
+ return 1;
+
+ /* TARGET (mountpoit) */
+ fs->target = next_word(&s);
+ if (!fs->target)
+ return 1;
+
+ /* OPTIONS (fs-independent) */
+ fs->vfs_optstr = next_word(&s);
+ if (!fs->vfs_optstr)
+ return 1;
+
+ /* optional fields (ignore) */
+ do {
+ s = skip_spaces(s);
+ if (s && *s == '-' &&
+ (*(s + 1) == ' ' || *(s + 1) == '\t')) {
+ s++;
+ break;
+ }
+ if (s && next_word_skip(&s) != 0)
+ return 1;
+ } while (s);
+
+ /* FSTYPE */
+ if (__mnt_fs_set_fstype(fs, next_word(&s)) != 0)
+ return 1;
+
+ /* SOURCE or "none" */
+ if (__mnt_fs_set_source(fs, next_word(&s)) != 0)
+ return 1;
+
+ /* OPTIONS (fs-dependent) */
+ fs->fs_optstr = next_word(&s);
+ if (!fs->fs_optstr)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Returns {m,fs}tab or mountinfo file format (MNT_FMT_*)
+ *
+ * The "mountinfo" format is always: "<number> <number> ... "
+ */
+static int detect_fmt(char *line)
+{
+ int num;
+
+ /* ID */
+ if (next_number(&line, &num) != 0)
+ return MNT_FMT_FSTAB;
+
+ /* PARENT */
+ if (next_number(&line, &num) != 0)
+ return MNT_FMT_FSTAB;
+
+ return MNT_FMT_MOUNTINFO;
+}
+
+
+/*
+ * Merges @vfs and @fs options strings into a new string.
+ * This function cares about 'ro/rw' options. The 'ro' is
+ * always used if @vfs or @fs is read-only.
+ * For example:
+ *
+ * mnt_merge_optstr("rw,noexec", "ro,journal=update")
+ *
+ * returns: "ro,noexec,journal=update"
+ *
+ * mnt_merge_optstr("rw,noexec", "rw,journal=update")
+ *
+ * returns: "rw,noexec,journal=update"
+
+ * We need this function for /proc/self/mountinfo parsing.
+ */
+static char *merge_optstr(const char *vfs, const char *fs)
+{
+ char *res, *p;
+ size_t sz;
+ int ro = 0, rw = 0;
+
+ if (!vfs && !fs)
+ return NULL;
+ if (!vfs || !fs)
+ return strdup(fs ? fs : vfs);
+ if (!strcmp(vfs, fs))
+ return strdup(vfs); /* e.g. "aaa" and "aaa" */
+
+ /* leave space for leading "r[ow],", "," and trailing zero */
+ sz = strlen(vfs) + strlen(fs) + 5;
+ res = malloc(sz);
+ if (!res)
+ return NULL;
+ p = res + 3; /* make a room for rw/ro flag */
+
+ snprintf(p, sz - 3, "%s,%s", vfs, fs);
+
+ /* remove 'rw' flags */
+ rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */
+ rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */
+
+ /* remove 'ro' flags if necessary */
+ if (rw != 2) {
+ ro += !mnt_optstr_remove_option(&p, "ro");
+ if (ro + rw < 2)
+ ro += !mnt_optstr_remove_option(&p, "ro");
+ }
+
+ if (!strlen(p))
+ memcpy(res, ro ? "ro" : "rw", 3);
+ else
+ memcpy(res, ro ? "ro," : "rw,", 3);
+ return res;
+}
+
+/*
+ * Read and parse the next line from {fs,m}tab or mountinfo
+ */
+static int mnt_tab_parse_next(mnt_tab *tb, FILE *f, mnt_fs *fs)
+{
+ char buf[BUFSIZ];
+ char *s;
+
+ assert(tb);
+ assert(f);
+ assert(fs);
+
+ /* read the next non-blank non-comment line */
+ do {
+ if (fgets(buf, sizeof(buf), f) == NULL)
+ return -1;
+ tb->nlines++;
+ s = index (buf, '\n');
+ if (!s) {
+ /* Missing final newline? Otherwise extremely */
+ /* long line - assume file was corrupted */
+ if (feof(f)) {
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: WARNING: no final newline at the end of %s\n",
+ tb->filename));
+ s = index (buf, '\0');
+ } else {
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: %d: missing newline at line\n",
+ tb->filename, tb->nlines));
+ goto err;
+ }
+ }
+ *s = '\0';
+ if (--s >= buf && *s == '\r')
+ *s = '\0';
+ s = skip_spaces(buf);
+ } while (*s == '\0' || *s == '#');
+
+ DBG(DEBUG_TAB, fprintf(stderr, "libmount: %s:%d: %s\n",
+ tb->filename, tb->nlines, s));
+
+ if (!tb->fmt)
+ tb->fmt = detect_fmt(s);
+
+ if (tb->fmt == MNT_FMT_FSTAB) {
+ /* parse /etc/{fs,m}tab */
+ if (mnt_tab_parse_file_line(fs, s) != 0)
+ goto err;
+ } else if (tb->fmt == MNT_FMT_MOUNTINFO) {
+ /* parse /proc/self/mountinfo */
+ if (mnt_parse_mountinfo_line(fs, s) != 0)
+ goto err;
+ }
+
+ /* merge fs_optstr and vfs_optstr into optstr (necessary for "mountinfo") */
+ if (!fs->optstr && (fs->vfs_optstr || fs->fs_optstr)) {
+ fs->optstr = merge_optstr(fs->vfs_optstr, fs->fs_optstr);
+ if (!fs->optstr)
+ goto err;
+ }
+
+ fs->lineno = tb->nlines;
+
+ DBG(DEBUG_TAB, fprintf(stderr,
+ "libmount: %s: %d: SOURCE:%s, MNTPOINT:%s, TYPE:%s, "
+ "OPTS:%s, FREQ:%d, PASSNO:%d\n",
+ tb->filename, fs->lineno,
+ fs->source, fs->target, fs->fstype,
+ fs->optstr, fs->freq, fs->passno));
+
+ return 0;
+err:
+ /* we don't report parse errors to caller; caller has to check
+ * errors by mnt_tab_get_nerrs() or internaly by MNT_ENTRY_ERR flag
+ */
+ fs->lineno = tb->nlines;
+ fs->flags |= MNT_FS_ERROR;
+ return 0;
+}
+
+/**
+ * mnt_tab_parse_file:
+ * @tb: tab pointer
+ *
+ * Parses whole table (e.g. /etc/fstab).
+ *
+ * <informalexample>
+ * <programlisting>
+ * mnt_tab *tb = mnt_new_tab("/etc/fstab");
+ * int rc;
+ *
+ * rc = mnt_tab_parse_file(tb);
+ * if (rc) {
+ * if (mnt_tab_get_nerrs(tb)) { / * parse error * /
+ * mnt_tab_strerror(tb, buf, sizeof(buf));
+ * fprintf(stderr, "%s: %s\n", progname, buf);
+ * } else
+ * perror(mnt_tab_get_name(tb)); / * system error * /
+ * } else
+ * mnt_fprintf_tab(tb, stdout, NULL);
+ *
+ * mnt_free_tab(tb);
+ * </programlisting>
+ * </informalexample>
+ *
+ * Returns: 0 on success and -1 in case of error. The parse errors is possible
+ * to detect by mnt_tab_get_nerrs() and error message is possible to create by
+ * mnt_tab_strerror().
+ */
+int mnt_tab_parse_file(mnt_tab *tb)
+{
+ FILE *f;
+
+ assert(tb);
+ assert(tb->filename);
+
+ if (!tb->filename)
+ return -1;
+
+ f = fopen(tb->filename, "r");
+ if (!f)
+ return -1;
+
+ while (!feof(f)) {
+ int rc;
+ mnt_fs *fs = mnt_new_fs();
+ if (!fs)
+ goto error;
+
+ rc = mnt_tab_parse_next(tb, f, fs);
+ if (!rc)
+ rc = mnt_tab_add_fs(tb, fs);
+ else if (feof(f)) {
+ mnt_free_fs(fs);
+ break;
+ }
+ if (rc) {
+ mnt_free_fs(fs);
+ goto error;
+ }
+ }
+
+ fclose(f);
+ return 0;
+error:
+ fclose(f);
+ return -1;
+}
+
+/**
+ * mnt_new_tab_parse:
+ * @filename: /etc/{m,fs}tab or /proc/self/mountinfo path
+ *
+ * Same as mnt_new_tab() + mnt_tab_parse_file(). Note that this function does
+ * not provide details (by mnt_tab_strerror()) about failed parsing -- so you
+ * should not to use this function for user-writeable files like /etc/fstab.
+ *
+ * Returns: newly allocated tab on success and NULL in case of error.
+ */
+mnt_tab *mnt_new_tab_from_file(const char *filename)
+{
+ mnt_tab *tb;
+
+ assert(filename);
+
+ if (!filename)
+ return NULL;
+ tb = mnt_new_tab(filename);
+ if (tb && mnt_tab_parse_file(tb) != 0) {
+ mnt_free_tab(tb);
+ tb = NULL;
+ }
+ return tb;
+}
+
+/**
+ * mnt_tab_get_nerrs:
+ * @tb: pointer to table
+ *
+ * Returns: number of broken (parse error) entries in the table.
+ */
+int mnt_tab_get_nerrs(mnt_tab *tb)
+{
+ assert(tb);
+ return tb->nerrs;
+}
+
+/**
+ * mnt_tab_strerror:
+ * @tb: pointer to table
+ * @buf: buffer to return error message
+ * @buflen: lenght of the buf
+ *
+ * Returns: error message for table (file) parse errors. For example:
+ *
+ * "/etc/fstab: parse error at line(s): 1, 2 and 3."
+ */
+char *mnt_tab_strerror(mnt_tab *tb, char *buf, size_t buflen)
+{
+ struct list_head *p;
+ int last = -1;
+ char *b = buf;
+ char *end = buf + buflen - 1;
+
+ assert(tb);
+ assert(buf);
+ assert(buflen);
+
+ if (!tb || !tb->nerrs || !buf || buflen <=0)
+ return NULL;
+
+ if (tb->filename) {
+ snprintf(b, end - b, "%s: ", tb->filename);
+ b += strnlen(b, end - b);
+ }
+
+ if (tb->nerrs > 1)
+ strncpy(b, _("parse error at lines: "), end - b);
+ else
+ strncpy(b, _("parse error at line: "), end - b);
+ b += strnlen(b, end - b);
+ *b = '\0';
+
+ list_for_each(p, &tb->ents) {
+ mnt_fs *fs = list_entry(p, mnt_fs, ents);
+ if (b == end)
+ goto done;
+ if (fs->flags & MNT_FS_ERROR) {
+ if (last != -1) {
+ snprintf(b, end - b, "%d, ", last);
+ b += strnlen(b, end - b);
+ }
+ last = fs->lineno;
+ }
+ }
+
+ if (tb->nerrs == 1)
+ snprintf(b, end - b, "%d.", last);
+ else
+ snprintf(b - 1, end - b, _(" and %d."), last);
+done:
+ return buf;
+}
+
diff --git a/shlibs/mount/src/test.c b/shlibs/mount/src/test.c
new file mode 100644
index 00000000..eb4f2d1d
--- /dev/null
+++ b/shlibs/mount/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 "mountP.h"
+
+int mnt_run_test(struct mtest *tests, int argc, char *argv[])
+{
+ int rc = -1;
+ struct mtest *ts;
+
+ assert(tests);
+ assert(argc);
+ assert(argv);
+
+ if (argc < 2 ||
+ strcmp(argv[1], "--help") == 0 ||
+ strcmp(argv[1], "-h") == 0)
+ goto usage;
+
+ mnt_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 == -1 && 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/shlibs/mount/src/utils.c b/shlibs/mount/src/utils.c
new file mode 100644
index 00000000..f487383a
--- /dev/null
+++ b/shlibs/mount/src/utils.c
@@ -0,0 +1,349 @@
+/*
+ * 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: utils
+ * @title: Utils
+ * @short_description: misc utils.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#include "mountP.h"
+
+char *mnt_getenv_safe(const char *arg)
+{
+ if ((getuid() != geteuid()) || (getgid() != getegid()))
+ return NULL;
+#if HAVE_PRCTL
+ if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+ if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
+ return NULL;
+#endif
+#endif
+
+#ifdef HAVE___SECURE_GETENV
+ return __secure_getenv(arg);
+#else
+ return getenv(arg);
+#endif
+}
+
+/* TODO: move strn<...> functions to top-level lib/strn.c */
+#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);
+
+ if (new == NULL)
+ return NULL;
+
+ new[len] = '\0';
+ return (char *) memcpy (new, s, len);
+}
+#endif
+
+
+/**
+ * mnt_fstype_is_pseudofs:
+ * @type: filesystem name
+ *
+ * Returns: 1 for filesystems like proc, sysfs, ... or 0.
+ */
+int mnt_fstype_is_pseudofs(const char *type)
+{
+ if (!type)
+ return 0;
+ if (strcmp(type, "none") == 0 ||
+ strcmp(type, "proc") == 0 ||
+ strcmp(type, "tmpfs") == 0 ||
+ strcmp(type, "sysfs") == 0 ||
+ strcmp(type, "devpts") == 0||
+ strcmp(type, "cgroups") == 0 ||
+ strcmp(type, "devfs") == 0 ||
+ strcmp(type, "dlmfs") == 0 ||
+ strcmp(type, "cpuset") == 0 ||
+ strcmp(type, "spufs") == 0)
+ return 1;
+ return 0;
+}
+
+/**
+ * mnt_fstype_is_netfs:
+ * @type: filesystem name
+ *
+ * Returns: 1 for filesystems like cifs, nfs, ... or 0.
+ */
+int mnt_fstype_is_netfs(const char *type)
+{
+ if (!type)
+ return 0;
+ if (strcmp(type, "cifs") == 0 ||
+ strcmp(type, "smbfs") == 0 ||
+ strncmp(type, "nfs", 3) == 0 ||
+ strcmp(type, "afs") == 0 ||
+ strcmp(type, "ncpfs") == 0)
+ return 1;
+ return 0;
+}
+
+/**
+ * mnt_match_fstype:
+ * @type: filesystem type
+ * @pattern: filesystem name or comma delimitted list of names
+ *
+ * The @pattern list of filesystem can be prefixed with a global
+ * "no" prefix to invert matching of the whole list. The "no" could
+ * also used for individual items in the @pattern list. So,
+ * "nofoo,bar" has the same meaning as "nofoo,nobar".
+ *
+ * "bar" : "nofoo,bar" -> False (global "no" prefix)
+ *
+ * "bar" : "foo,bar" -> True
+ *
+ * "bar" : "foo,nobar" -> False
+ *
+ * Returns: 1 if type is matching, else 0. This function also returns
+ * 0 if @pattern is NULL and @type is non-NULL.
+ */
+int mnt_match_fstype(const char *type, const char *pattern)
+{
+ int no = 0; /* negated types list */
+ int len;
+ const char *p;
+
+ if (!pattern && !type)
+ return 1;
+ if (!pattern)
+ return 0;
+
+ if (!strncmp(pattern, "no", 2)) {
+ no = 1;
+ pattern += 2;
+ }
+
+ /* Does type occur in types, separated by commas? */
+ len = strlen(type);
+ p = pattern;
+ while(1) {
+ if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
+ (p[len+2] == 0 || p[len+2] == ','))
+ return 0;
+ if (strncmp(p, type, len) == 0 && (p[len] == 0 || p[len] == ','))
+ return !no;
+ p = strchr(p,',');
+ if (!p)
+ break;
+ p++;
+ }
+ return no;
+}
+
+
+/* Returns 1 if needle found or noneedle not found in haystack
+ * Otherwise returns 0
+ */
+static int check_option(const char *haystack, size_t len,
+ const char *needle, size_t needle_len)
+{
+ const char *p;
+ int no = 0;
+
+ if (needle_len >= 2 && !strncmp(needle, "no", 2)) {
+ no = 1;
+ needle += 2;
+ needle_len -= 2;
+ }
+
+ for (p = haystack; p && p < haystack + len; p++) {
+ char *sep = strchr(p, ',');
+ size_t plen = sep ? sep - p : len - (p - haystack);
+
+ if (plen == needle_len) {
+ if (!strncmp(p, needle, plen))
+ return !no; /* foo or nofoo was found */
+ }
+ p += plen;
+ }
+
+ return no; /* foo or nofoo was not found */
+}
+
+/**
+ * mnt_match_options:
+ * @optstr: options string
+ * @pattern: comma delimitted list of options
+ *
+ * The "no" could used for individual items in the @options list. The "no"
+ * prefix does not have a global meanning.
+ *
+ * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
+ * DIFFERENT meanings; each option is matched explicitly as specified.
+ *
+ * "xxx,yyy,zzz" : "nozzz" -> False
+ *
+ * "xxx,yyy,zzz" : "xxx,noeee" -> True
+ *
+ * Returns: 1 if pattern is matching, else 0. This function also returns 0
+ * if @pattern is NULL and @optstr is non-NULL.
+ */
+int mnt_match_options(const char *optstr, const char *pattern)
+{
+ const char *p;
+ size_t len, optstr_len = 0;
+
+ if (!pattern && !optstr)
+ return 1;
+ if (!pattern)
+ return 0;
+
+ len = strlen(pattern);
+ if (optstr)
+ optstr_len = strlen(optstr);
+
+ for (p = pattern; p < pattern + len; p++) {
+ char *sep = strchr(p, ',');
+ size_t plen = sep ? sep - p : len - (p - pattern);
+
+ if (!plen)
+ continue; /* if two ',' appear in a row */
+
+ if (!check_option(optstr, optstr_len, p, plen))
+ return 0; /* any match failure means failure */
+
+ p += plen;
+ }
+
+ /* no match failures in list means success */
+ return 1;
+}
+
+/*
+ * Reallocates its first arg @s - typical use: s = mnt_strconcat3(s,t,u);
+ * Returns reallocated @s ion succes or NULL in case of error.
+ */
+char *mnt_strconcat3(char *s, const char *t, const char *u)
+{
+ size_t len = 0;
+
+ len = (s ? strlen(s) : 0) + (t ? strlen(t) : 0) + (u ? strlen(u) : 0);
+
+ if (!len)
+ return NULL;
+ if (!s) {
+ s = malloc(len + 1);
+ *s = '\0';
+ } else
+ s = realloc(s, len + 1);
+
+ if (!s)
+ return NULL;
+ if (t)
+ strcat(s, t);
+ if (u)
+ strcat(s, u);
+ return s;
+}
+
+/*
+ * Returns allocated string with username or NULL.
+ */
+char *mnt_get_username(const uid_t uid)
+{
+ struct passwd pwd;
+ struct passwd *res;
+ size_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
+ char *buf, *username = NULL;
+
+ if (sz <= 0)
+ sz = 16384; /* Should be more than enough */
+
+ buf = malloc(sz);
+ if (!buf)
+ return NULL;
+
+ if (!getpwuid_r(uid, &pwd, buf, sz, &res) && res)
+ username = strdup(pwd.pw_name);
+
+ free(buf);
+ return username;
+}
+
+#ifdef TEST_PROGRAM
+int test_match_fstype(struct mtest *ts, int argc, char *argv[])
+{
+ char *type = argv[1];
+ char *pattern = argv[2];
+
+ printf("%s\n", mnt_match_fstype(type, pattern) ? "MATCH" : "NOT-MATCH");
+ return 0;
+}
+
+int test_match_options(struct mtest *ts, int argc, char *argv[])
+{
+ char *optstr = argv[1];
+ char *pattern = argv[2];
+
+ printf("%s\n", mnt_match_options(optstr, pattern) ? "MATCH" : "NOT-MATCH");
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct mtest tss[] = {
+ { "--match-fstype", test_match_fstype, "<type> <pattern> FS types matching" },
+ { "--match-options", test_match_options, "<options> <pattern> options matching" },
+ { NULL }
+ };
+
+ return mnt_run_test(tss, argc, argv);
+}
+
+#endif /* TEST_PROGRAM */
diff --git a/shlibs/mount/src/version.c b/shlibs/mount/src/version.c
new file mode 100644
index 00000000..d00a1686
--- /dev/null
+++ b/shlibs/mount/src/version.c
@@ -0,0 +1,86 @@
+/*
+ * version.c - Return the version of the blkid library
+ *
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ * [Based on libblkid/version.c by Theodore Ts'o]
+ *
+ * See COPYING.libmount for the License of this software.
+ */
+
+/**
+ * SECTION: version
+ * @title: Version functions
+ * @short_description: functions to get library version.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "mountP.h"
+
+static const char *lib_version = LIBMOUNT_VERSION;
+
+/**
+ * mnt_parse_version_string:
+ * @ver_string: version string (e.g "2.18.0")
+ *
+ * Returns: release version code.
+ */
+int mnt_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;
+}
+
+/**
+ * mnt_get_library_version:
+ * @ver_string: return pointer to the static library version string
+ *
+ * Returns: release version number.
+ */
+int mnt_get_library_version(const char **ver_string)
+{
+ if (ver_string)
+ *ver_string = lib_version;
+
+ return mnt_parse_version_string(lib_version);
+}
+
+#ifdef TEST_PROGRAM
+int test_version(struct mtest *ts, int argc, char *argv[])
+{
+ const char *ver;
+
+ mnt_get_library_version(&ver);
+
+ printf("Library version: %s\n", ver);
+ printf("Library API version: " LIBMOUNT_VERSION "\n");
+
+ if (mnt_get_library_version(NULL) ==
+ mnt_parse_version_string(LIBMOUNT_VERSION))
+ return 0;
+
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mtest ts[] = {
+ { "--print", test_version, "print versions" },
+ { NULL }
+ };
+
+ return mnt_run_test(ts, argc, argv);
+}
+#endif
diff --git a/shlibs/uuid/Makefile.am b/shlibs/uuid/Makefile.am
index 2bdef334..66fe6909 100644
--- a/shlibs/uuid/Makefile.am
+++ b/shlibs/uuid/Makefile.am
@@ -6,5 +6,5 @@ SUBDIRS = src man
pkgconfigdir = $(usrlib_execdir)/pkgconfig
pkgconfig_DATA = uuid.pc
-EXTRA_DIST = uuid.pc.in
+EXTRA_DIST = COPYING.libuuid uuid.pc.in
diff --git a/shlibs/uuid/man/Makefile.am b/shlibs/uuid/man/Makefile.am
index ffaf0241..38809522 100644
--- a/shlibs/uuid/man/Makefile.am
+++ b/shlibs/uuid/man/Makefile.am
@@ -8,5 +8,5 @@ UUID_GENERATE_LINKS = uuid_generate_random.3 uuid_generate_time.3
man_MANS = $(UUID_GENERATE_LINKS)
CLEANFILES = $(man_MANS)
-$(UUID_GENERATE_LINKS): uuid_generate.3
- echo ".so man3/uuid_generate.3" > $@
+$(UUID_GENERATE_LINKS):
+ $(AM_V_GEN)echo ".so man3/uuid_generate.3" > $@
diff --git a/shlibs/uuid/man/uuid_generate.3 b/shlibs/uuid/man/uuid_generate.3
index 11f48ffd..e1b8143f 100644
--- a/shlibs/uuid/man/uuid_generate.3
+++ b/shlibs/uuid/man/uuid_generate.3
@@ -59,7 +59,7 @@ a high-quality random number generator (i.e.,
.IR /dev/urandom )
is not available, in which case a pseudo-random
generator will be subsituted. Note that the use of a pseudo-random
-generator may compromise the uniqueness of UUID's
+generator may compromise the uniqueness of UUIDs
generated in this fashion.
.sp
The
diff --git a/shlibs/uuid/src/compare.c b/shlibs/uuid/src/compare.c
index f28a7267..8f3437a2 100644
--- a/shlibs/uuid/src/compare.c
+++ b/shlibs/uuid/src/compare.c
@@ -1,7 +1,7 @@
/*
- * compare.c --- compare whether or not two UUID's are the same
+ * compare.c --- compare whether or not two UUIDs are the same
*
- * Returns 0 if the two UUID's are different, and 1 if they 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.
*
diff --git a/shlibs/uuid/src/pack.c b/shlibs/uuid/src/pack.c
index 097516d2..6e124766 100644
--- a/shlibs/uuid/src/pack.c
+++ b/shlibs/uuid/src/pack.c
@@ -1,5 +1,5 @@
/*
- * Internal routine for packing UUID's
+ * Internal routine for packing UUIDs
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*