diff options
-rw-r--r-- | Changelog | 5 | ||||
-rw-r--r-- | quota_tree.h | 51 | ||||
-rw-r--r-- | quotaio.c | 3 | ||||
-rw-r--r-- | quotaio_tree.c | 519 | ||||
-rw-r--r-- | quotasys.c | 25 |
5 files changed, 596 insertions, 7 deletions
@@ -1,6 +1,7 @@ Changes in quota-tools from 3.17 to 4.00-pre1 -* convert quota limits using rq_bsize from RPC request (Jan Kara) -* added noreturn attribute to die to avoid false warnings (Jan Kara) +* Fixed error reporting when rpc format specified on command line (Jan Kara) +* Convert quota limits using rq_bsize from RPC request (Jan Kara) +* Added noreturn attribute to die to avoid false warnings (Jan Kara) * 64-bit quota support, rewritten some code to allow clean integration (Jan Kara) * Improved header of quota an repquota output when -s option is used (Jan Kara) * Fixed mountpoint scanning when NFS mountpoint is specified on command line (Jan Kara) diff --git a/quota_tree.h b/quota_tree.h new file mode 100644 index 0000000..9dd1b8b --- /dev/null +++ b/quota_tree.h @@ -0,0 +1,51 @@ +#ifndef _QUOTA_TREE_H +#define _QUOTA_TREE_H + +#include <sys/types.h> +#include "quota.h" + +#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ +#define QT_TREEDEPTH 4 /* Depth of quota tree */ +#define QT_BLKSIZE_BITS 10 +#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota structures */ + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct qt_disk_dqdbheader { + u_int32_t dqdh_next_free; /* Number of next block with free entry */ + u_int32_t dqdh_prev_free; /* Number of previous block with free entry */ + u_int16_t dqdh_entries; /* Number of valid entries in block */ + u_int16_t dqdh_pad1; + u_int32_t dqdh_pad2; +} __attribute__ ((packed)); + +struct dquot; +struct quota_handle; + +/* Operations */ +struct qtree_fmt_operations { + void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); /* Convert given entry from in memory format to disk one */ + void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); /* Convert given entry from disk format to in memory one */ + int (*is_id)(void *disk, struct dquot *dquot); /* Is this structure for given id? */ +}; + +/* Inmemory copy of version specific information */ +struct qtree_mem_dqinfo { + unsigned int dqi_blocks; /* # of blocks in quota file */ + unsigned int dqi_free_blk; /* First block in list of free blocks */ + unsigned int dqi_free_entry; /* First block with free entry */ + unsigned int dqi_entry_size; /* Size of quota entry in quota file */ + struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */ +}; + +void qtree_write_dquot(struct dquot *dquot); +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); +void qtree_delete_dquot(struct dquot *dquot); +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); +int qtree_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *, char *)); + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); + +#endif @@ -71,6 +71,9 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags) errstr(_("RPC quota format not compiled.\n")); goto out_handle; #endif + } else if (fmt == QF_RPC) { + errstr(_("RPC quota format specified for non-NFS filesystem.\n")); + goto out_handle; } if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem? */ diff --git a/quotaio_tree.c b/quotaio_tree.c new file mode 100644 index 0000000..deef04e --- /dev/null +++ b/quotaio_tree.c @@ -0,0 +1,519 @@ +/* + * Implementation of new quotafile format + * + * Jan Kara <jack@suse.cz> - sponsored by SuSE CR + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <asm/byteorder.h> + +#include "pot.h" +#include "common.h" +#include "quota_tree.h" +#include "quotaio.h" +#include "quotasys.h" +#include "quotaio_generic.h" + +typedef char *dqbuf_t; + +#define getdqbuf() smalloc(QT_BLKSIZE) +#define freedqbuf(buf) free(buf) + +/* Is given dquot empty? */ +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) +{ + int i; + + for (i = 0; i < info->dqi_entry_size; i++) + if (disk[i]) + return 0; + return 1; +} + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) +{ + return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / info->dqi_entry_size; +} + +static int get_index(qid_t id, int depth) +{ + return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; +} + +/* Read given block */ +static void read_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +{ + int err; + + lseek(h->qh_fd, blk << QT_BLKSIZE_BITS, SEEK_SET); + err = read(h->qh_fd, buf, QT_BLKSIZE); + if (err < 0) + die(2, _("Cannot read block %u: %s\n"), blk, strerror(errno)); + else if (err != QT_BLKSIZE) + memset(buf + err, 0, QT_BLKSIZE - err); +} + +/* Write block */ +static int write_blk(struct quota_handle *h, uint blk, dqbuf_t buf) +{ + int err; + + lseek(h->qh_fd, blk << QT_BLKSIZE_BITS, SEEK_SET); + err = write(h->qh_fd, buf, QT_BLKSIZE); + if (err < 0 && errno != ENOSPC) + die(2, _("Cannot write block (%u): %s\n"), blk, strerror(errno)); + if (err != QT_BLKSIZE) + return -ENOSPC; + return 0; +} + +/* Get free block in file (either from free list or create new one) */ +static int get_free_dqblk(struct quota_handle *h) +{ + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + int blk; + + if (info->dqi_free_blk) { + blk = info->dqi_free_blk; + read_blk(h, blk, buf); + info->dqi_free_blk = __le32_to_cpu(dh->dqdh_next_free); + } + else { + memset(buf, 0, QT_BLKSIZE); + if (write_blk(h, info->dqi_blocks, buf) < 0) { /* Assure block allocation... */ + freedqbuf(buf); + errstr(_("Cannot allocate new quota block (out of disk space).\n")); + return -ENOSPC; + } + blk = info->dqi_blocks++; + } + mark_quotafile_info_dirty(h); + freedqbuf(buf); + return blk; +} + +/* Put given block to free list */ +static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_blk); + dh->dqdh_prev_free = __cpu_to_le32(0); + dh->dqdh_entries = __cpu_to_le16(0); + info->dqi_free_blk = blk; + mark_quotafile_info_dirty(h); + write_blk(h, blk, buf); +} + +/* Remove given block from the list of blocks with free entries */ +static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + uint nextblk = __le32_to_cpu(dh->dqdh_next_free), prevblk = + + __le32_to_cpu(dh->dqdh_prev_free); + + if (nextblk) { + read_blk(h, nextblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; + write_blk(h, nextblk, tmpbuf); + } + if (prevblk) { + read_blk(h, prevblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; + write_blk(h, prevblk, tmpbuf); + } + else { + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; + mark_quotafile_info_dirty(h); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = __cpu_to_le32(0); + write_blk(h, blk, buf); /* No matter whether write succeeds block is out of list */ +} + +/* Insert given block to the beginning of list with free entries */ +static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + dh->dqdh_next_free = __cpu_to_le32(info->dqi_free_entry); + dh->dqdh_prev_free = __cpu_to_le32(0); + write_blk(h, blk, buf); + if (info->dqi_free_entry) { + read_blk(h, info->dqi_free_entry, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = __cpu_to_le32(blk); + write_blk(h, info->dqi_free_entry, tmpbuf); + } + freedqbuf(tmpbuf); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); +} + +/* Find space for dquot */ +static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, int *err) +{ + int blk, i; + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + char *ddquot; + dqbuf_t buf; + + *err = 0; + buf = getdqbuf(); + dh = (struct qt_disk_dqdbheader *)buf; + if (info->dqi_free_entry) { + blk = info->dqi_free_entry; + read_blk(h, blk, buf); + } + else { + blk = get_free_dqblk(h); + if (blk < 0) { + freedqbuf(buf); + *err = blk; + return 0; + } + memset(buf, 0, QT_BLKSIZE); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); + } + if (__le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) /* Block will be full? */ + remove_free_dqentry(h, buf, blk); + dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) + 1); + /* Find free structure in block */ + ddquot = buf + sizeof(struct qt_disk_dqdbheader); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); + i++, ddquot += info->dqi_entry_size); + if (i == qtree_dqstr_in_blk(info)) + die(2, _("find_free_dqentry(): Data block full but it shouldn't.\n")); + write_blk(h, blk, buf); + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; + freedqbuf(buf); + return blk; +} + +/* Insert reference to structure into the trie */ +static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, uint * treeblk, int depth) +{ + dqbuf_t buf; + int newson = 0, newact = 0; + u_int32_t *ref; + uint newblk; + int ret = 0; + + buf = getdqbuf(); + if (!*treeblk) { + ret = get_free_dqblk(h); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, QT_BLKSIZE); + newact = 1; + } + else + read_blk(h, *treeblk, buf); + ref = (u_int32_t *) buf; + newblk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == QT_TREEDEPTH - 1) { + if (newblk) + die(2, _("Inserting already present quota entry (block %u).\n"), + ref[get_index(dquot->dq_id, depth)]); + newblk = find_free_dqentry(h, dquot, &ret); + } + else + ret = do_insert_tree(h, dquot, &newblk, depth + 1); + if (newson && ret >= 0) { + ref[get_index(dquot->dq_id, depth)] = __cpu_to_le32(newblk); + write_blk(h, *treeblk, buf); + } + else if (newact && ret < 0) + put_free_dqblk(h, buf, *treeblk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) +{ + uint tmp = QT_TREEOFF; + + if (do_insert_tree(h, dquot, &tmp, 0) < 0) + die(2, _("Cannot write quota (id %u): %s\n"), (uint) dquot->dq_id, strerror(errno)); +} + +/* Write dquot to file */ +void qtree_write_dquot(struct dquot *dquot) +{ + ssize_t ret; + struct qtree_mem_dqinfo *info = &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + char *ddquot = smalloc(info->dqi_entry_size); + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) + dq_insert_tree(dquot->dq_h, dquot); + lseek(dquot->dq_h->qh_fd, dquot->dq_dqb.u.v2_mdqb.dqb_off, SEEK_SET); + info->dqi_ops->mem2disk_dqblk(ddquot, dquot); + ret = write(dquot->dq_h->qh_fd, ddquot, info->dqi_entry_size); + if (ret != info->dqi_entry_size) { + if (ret > 0) + errno = ENOSPC; + die(2, _("Quota write failed (id %u): %s\n"), (uint)dquot->dq_id, strerror(errno)); + } +} + +/* Free dquot entry in data block */ +static void free_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) +{ + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + + if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) + die(2, _("Quota structure has offset to other block (%u) than it should (%u).\n"), blk, + (uint) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS)); + read_blk(h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + dh->dqdh_entries = __cpu_to_le16(__le16_to_cpu(dh->dqdh_entries) - 1); + if (!__le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + remove_free_dqentry(h, buf, blk); + put_free_dqblk(h, buf, blk); + } + else { + memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & ((1 << QT_BLKSIZE_BITS) - 1)), 0, + info->dqi_entry_size); + + if (__le16_to_cpu(dh->dqdh_entries) == qtree_dqstr_in_blk(info) - 1) /* First free entry? */ + insert_free_dqentry(h, buf, blk); /* This will also write data block */ + else + write_blk(h, blk, buf); + } + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + freedqbuf(buf); +} + +/* Remove reference to dquot from tree */ +static void remove_tree(struct quota_handle *h, struct dquot *dquot, uint * blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + uint newblk; + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(h, *blk, buf); + newblk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (depth == QT_TREEDEPTH - 1) { + free_dqentry(h, dquot, newblk); + newblk = 0; + } + else + remove_tree(h, dquot, &newblk, depth + 1); + if (!newblk) { + int i; + + ref[get_index(dquot->dq_id, depth)] = __cpu_to_le32(0); + for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); /* Block got empty? */ + /* Don't put the root block into the free block list */ + if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { + put_free_dqblk(h, buf, *blk); + *blk = 0; + } + else + write_blk(h, *blk, buf); + } + freedqbuf(buf); +} + +/* Delete dquot from tree */ +void qtree_delete_dquot(struct dquot *dquot) +{ + uint tmp = QT_TREEOFF; + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ + return; + remove_tree(dquot->dq_h, dquot, &tmp, 0); +} + +/* Find entry in block */ +static loff_t find_block_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + int i; + char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); + + read_blk(h, blk, buf); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); + i++, ddquot += info->dqi_entry_size); + if (i == qtree_dqstr_in_blk(info)) + die(2, _("Quota for id %u referenced but not present.\n"), dquot->dq_id); + freedqbuf(buf); + return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; +} + +/* Find entry for given id in the tree */ +static loff_t find_tree_dqentry(struct quota_handle *h, struct dquot *dquot, uint blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + loff_t ret = 0; + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(h, blk, buf); + ret = 0; + blk = __le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < QT_TREEDEPTH - 1) + ret = find_tree_dqentry(h, dquot, blk, depth + 1); + else + ret = find_block_dqentry(h, dquot, blk); + out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline loff_t find_dqentry(struct quota_handle *h, struct dquot *dquot) +{ + return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); +} + +/* + * Read dquot (either from disk or from kernel) + * User can use errno to detect errstr when NULL is returned + */ +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + loff_t offset; + ssize_t ret; + char *ddquot = smalloc(info->dqi_entry_size); + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_id = id; + dquot->dq_h = h; + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + + offset = find_dqentry(h, dquot); + if (offset > 0) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; + lseek(h->qh_fd, offset, SEEK_SET); + ret = read(h->qh_fd, ddquot, info->dqi_entry_size); + if (ret != info->dqi_entry_size) { + if (ret > 0) + errno = EIO; + die(2, _("Cannot read quota structure for id %u: %s\n"), dquot->dq_id, + strerror(errno)); + } + info->dqi_ops->disk2mem_dqblk(dquot, ddquot); + } + return dquot; +} + +/* + * Scan all dquots in file and call callback on each + */ +#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) +#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) + +static int report_block(struct dquot *dquot, uint blk, char *bitmap, + int (*process_dquot) (struct dquot *, char *)) +{ + struct qtree_mem_dqinfo *info = &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh; + char *ddata; + int entries, i; + + set_bit(bitmap, blk); + read_blk(dquot->dq_h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + ddata = buf + sizeof(struct qt_disk_dqdbheader); + entries = __le16_to_cpu(dh->dqdh_entries); + for (i = 0; i < qtree_dqstr_in_blk(info); i++, ddata += info->dqi_entry_size) + if (!qtree_entry_unused(info, ddata)) { + info->dqi_ops->disk2mem_dqblk(dquot, ddata); + if (process_dquot(dquot, NULL) < 0) + break; + } + freedqbuf(buf); + return entries; +} + +static void check_reference(struct quota_handle *h, uint blk) +{ + if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) + die(2, _("Illegal reference (%u >= %u) in %s quota file on %s. Quota file is probably corrupted.\nPlease run quotacheck(8) and try again.\n"), blk, h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, type2name(h->qh_type), h->qh_quotadev); +} + +static int report_tree(struct dquot *dquot, uint blk, int depth, char *bitmap, + int (*process_dquot) (struct dquot *, char *)) +{ + int entries = 0, i; + dqbuf_t buf = getdqbuf(); + u_int32_t *ref = (u_int32_t *) buf; + + read_blk(dquot->dq_h, blk, buf); + if (depth == QT_TREEDEPTH - 1) { + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = __le32_to_cpu(ref[i]); + check_reference(dquot->dq_h, blk); + if (blk && !get_bit(bitmap, blk)) + entries += report_block(dquot, blk, bitmap, process_dquot); + } + } + else { + for (i = 0; i < QT_BLKSIZE >> 2; i++) + if ((blk = __le32_to_cpu(ref[i]))) { + check_reference(dquot->dq_h, blk); + entries += + report_tree(dquot, blk, depth + 1, bitmap, process_dquot); + } + } + freedqbuf(buf); + return entries; +} + +static uint find_set_bits(char *bmp, int blocks) +{ + uint i, used = 0; + + for (i = 0; i < blocks; i++) + if (get_bit(bmp, i)) + used++; + return used; +} + +int qtree_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *, char *)) +{ + char *bitmap; + struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; + struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; + struct dquot *dquot = get_empty_dquot(); + + dquot->dq_h = h; + bitmap = smalloc((info->dqi_blocks + 7) >> 3); + memset(bitmap, 0, (info->dqi_blocks + 7) >> 3); + v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, process_dquot); + v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); + free(bitmap); + free(dquot); + return 0; +} @@ -629,7 +629,11 @@ struct quota_handle **create_handle_list(int count, char **mntpoints, int type, if (init_mounts_scan(count, mntpoints, mntflags) < 0) die(2, _("Cannot initialize mountpoint scan.\n")); while ((mnt = get_next_mount())) { - if (!nfs_fstype(mnt->mnt_type)) { /* No NFS? */ +#ifndef RPC + if (nfs_fstype(mnt->mnt_type)) + continue; +#endif + if (fmt == -1 || count) { add_entry: if (gotmnt+1 >= hlist_allocated) { hlist_allocated += START_MNT_POINTS; @@ -639,10 +643,21 @@ add_entry: continue; gotmnt++; } - else if (fmt == -1 || fmt == QF_RPC) { /* Use NFS? */ -#ifdef RPC - goto add_entry; -#endif + else { + switch (fmt) { + case QF_RPC: + if (nfs_fstype(mnt->mnt_type)) + goto add_entry; + break; + case QF_XFS: + if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) + goto add_entry; + break; + default: + if (strcmp(mnt->mnt_type, MNTTYPE_XFS) && !nfs_fstype(mnt->mnt_type)) + goto add_entry; + break; + } } } end_mounts_scan(); |