1  /*
       2   * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved.
       3   * Written by Milan Broz <gmazyland@gmail.com>
       4   *            Karel Zak <kzak@redhat.com>
       5   */
       6  #ifndef UTIL_LINUX_LSBLK_H
       7  #define UTIL_LINUX_LSBLK_H
       8  
       9  #include <stdint.h>
      10  #include <inttypes.h>
      11  #include <sys/stat.h>
      12  #include <sys/statvfs.h>
      13  
      14  #include <libsmartcols.h>
      15  #include <libmount.h>
      16  
      17  #include "c.h"
      18  #include "list.h"
      19  #include "debug.h"
      20  
      21  #define LSBLK_DEBUG_INIT	(1 << 1)
      22  #define LSBLK_DEBUG_FILTER	(1 << 2)
      23  #define LSBLK_DEBUG_DEV		(1 << 3)
      24  #define LSBLK_DEBUG_TREE	(1 << 4)
      25  #define LSBLK_DEBUG_DEP		(1 << 5)
      26  #define LSBLK_DEBUG_ALL		0xFFFF
      27  
      28  UL_DEBUG_DECLARE_MASK(lsblk);
      29  #define DBG(m, x)       __UL_DBG(lsblk, LSBLK_DEBUG_, m, x)
      30  #define ON_DBG(m, x)    __UL_DBG_CALL(lsblk, LSBLK_DEBUG_, m, x)
      31  
      32  #define UL_DEBUG_CURRENT_MASK	UL_DEBUG_MASK(lsblk)
      33  #include "debugobj.h"
      34  
      35  struct lsblk {
      36  	struct libscols_table *table;	/* output table */
      37  	struct libscols_column *sort_col;/* sort output by this column */
      38  
      39  	int sort_id;			/* id of the sort column */
      40  	int tree_id;			/* od of column used for tree */
      41  
      42  	int dedup_id;
      43  
      44  
      45  	const char *sysroot;
      46  	int flags;			/* LSBLK_* */
      47  
      48  	unsigned int all_devices:1;	/* print all devices, including empty */
      49  	unsigned int bytes:1;		/* print SIZE in bytes */
      50  	unsigned int inverse:1;		/* print inverse dependencies */
      51  	unsigned int merge:1;           /* merge sub-trees */
      52  	unsigned int nodeps:1;		/* don't print slaves/holders */
      53  	unsigned int scsi:1;		/* print only device with HCTL (SCSI) */
      54  	unsigned int nvme:1;		/* print NVMe device only */
      55  	unsigned int virtio:1;		/* print virtio device only */
      56  	unsigned int paths:1;		/* print devnames with "/dev" prefix */
      57  	unsigned int sort_hidden:1;	/* sort column not between output columns */
      58  	unsigned int dedup_hidden :1;	/* deduplication column not between output columns */
      59  	unsigned int force_tree_order:1;/* sort lines by parent->tree relation */
      60  	unsigned int noempty:1;		/* hide empty devices */
      61  };
      62  
      63  extern struct lsblk *lsblk;     /* global handler */
      64  
      65  struct lsblk_devprop {
      66  	/* udev / blkid based */
      67  	char *fstype;		/* detected fs, NULL or "?" if cannot detect */
      68  	char *fsversion;	/* filesystem version */
      69  	char *uuid;		/* filesystem UUID (or stack uuid) */
      70  	char *ptuuid;		/* partition table UUID */
      71  	char *pttype;		/* partition table type */
      72  	char *label;		/* filesystem label */
      73  	char *parttype;		/* partition type UUID */
      74  	char *partuuid;		/* partition UUID */
      75  	char *partlabel;	/* partition label */
      76  	char *partflags;	/* partition flags */
      77  	char *partn;		/* partition number */
      78  	char *wwn;		/* storage WWN */
      79  	char *serial;		/* disk serial number */
      80  	char *model;		/* disk model */
      81  	char *idlink;		/* /dev/disk/by-id/<name> */
      82  	char *revision;		/* firmware revision/version */
      83  
      84  	/* lsblk specific (for --sysroot only)  */
      85  	char *owner;		/* user name */
      86  	char *group;		/* group name */
      87  	char *mode;		/* access mode in ls(1)-like notation */
      88  };
      89  
      90  /* Device dependence
      91   *
      92   * Note that the same device may be slave/holder for more another devices. It
      93   * means we need to allocate list member rather than use @child directly.
      94   */
      95  struct lsblk_devdep {
      96  	struct list_head        ls_childs;	/* item in parent->childs */
      97  	struct list_head	ls_parents;	/* item in child->parents */
      98  
      99  	struct lsblk_device	*child;
     100  	struct lsblk_device	*parent;
     101  };
     102  
     103  struct lsblk_device {
     104  	int	refcount;
     105  
     106  	struct list_head	childs;		/* list with lsblk_devdep */
     107  	struct list_head	parents;
     108  	struct list_head	ls_roots;	/* item in devtree->roots list */
     109  	struct list_head	ls_devices;	/* item in devtree->devices list */
     110  
     111  	struct lsblk_device	*wholedisk;	/* for partitions */
     112  
     113  	struct libscols_line	*scols_line;
     114  
     115  	struct lsblk_devprop	*properties;
     116  	struct stat	st;
     117  
     118  	char *name;		/* kernel name in /sys/block */
     119  	char *dm_name;		/* DM name (dm/block) */
     120  
     121  	char *filename;		/* path to device node */
     122  	char *dedupkey;		/* de-duplication key */
     123  
     124  	struct path_cxt	*sysfs;
     125  
     126  	struct libmnt_fs **fss;	/* filesystems attached to the device */
     127  	size_t nfss;		/* number of items in fss[] */
     128  
     129  	struct statvfs fsstat;	/* statvfs() result */
     130  
     131  	int npartitions;	/* # of partitions this device has */
     132  	int nholders;		/* # of devices mapped directly to this device
     133  				 * /sys/block/.../holders */
     134  	int nslaves;		/* # of devices this device maps to */
     135  	int maj, min;		/* devno */
     136  
     137  	uint64_t discard_granularity;	/* sunknown:-1, yes:1, not:0 */
     138  
     139  	uint64_t size;		/* device size */
     140  	int removable;		/* unknown:-1, yes:1, not:0 */
     141  
     142  	unsigned int	is_mounted : 1,
     143  			is_swap : 1,
     144  			is_printed : 1,
     145  			udev_requested : 1,
     146  			blkid_requested : 1,
     147  			file_requested : 1;
     148  };
     149  
     150  #define device_is_partition(_x)		((_x)->wholedisk != NULL)
     151  
     152  /* Unfortunately, pktcdvd dependence on block device is not defined by
     153   * slave/holder symlinks. The struct lsblk_devnomap represents one line in
     154   * /sys/class/pktcdvd/device_map
     155   */
     156  struct lsblk_devnomap {
     157  	dev_t slave;		/* packet device devno */
     158  	dev_t holder;		/* block device devno */
     159  
     160  	struct list_head ls_devnomap;
     161  };
     162  
     163  
     164  /*
     165   * Note that lsblk tree uses bottom devices (devices without slaves) as root
     166   * of the tree, and partitions are interpreted as a dependence too; it means:
     167   *    sda -> sda1 -> md0
     168   *
     169   * The flag 'is_inverted' turns the tree over (root is device without holders):
     170   *    md0 -> sda1 -> sda
     171   */
     172  struct lsblk_devtree {
     173  	int	refcount;
     174  
     175  	struct list_head	roots;		/* tree root devices */
     176  	struct list_head	devices;	/* all devices */
     177  	struct list_head	pktcdvd_map;	/* devnomap->ls_devnomap */
     178  
     179  	unsigned int	is_inverse : 1,		/* inverse tree */
     180  			pktcdvd_read : 1;
     181  };
     182  
     183  
     184  /*
     185   * Generic iterator
     186   */
     187  struct lsblk_iter {
     188  	struct list_head        *p;		/* current position */
     189  	struct list_head        *head;		/* start position */
     190  	int			direction;	/* LSBLK_ITER_{FOR,BACK}WARD */
     191  };
     192  
     193  #define LSBLK_ITER_FORWARD	0
     194  #define LSBLK_ITER_BACKWARD	1
     195  
     196  #define IS_ITER_FORWARD(_i)	((_i)->direction == LSBLK_ITER_FORWARD)
     197  #define IS_ITER_BACKWARD(_i)	((_i)->direction == LSBLK_ITER_BACKWARD)
     198  
     199  #define LSBLK_ITER_INIT(itr, list) \
     200  	do { \
     201  		(itr)->p = IS_ITER_FORWARD(itr) ? \
     202  				(list)->next : (list)->prev; \
     203  		(itr)->head = (list); \
     204  	} while(0)
     205  
     206  #define LSBLK_ITER_ITERATE(itr, res, restype, member) \
     207  	do { \
     208  		res = list_entry((itr)->p, restype, member); \
     209  		(itr)->p = IS_ITER_FORWARD(itr) ? \
     210  				(itr)->p->next : (itr)->p->prev; \
     211  	} while(0)
     212  
     213  
     214  /* lsblk-mnt.c */
     215  extern void lsblk_mnt_init(void);
     216  extern void lsblk_mnt_deinit(void);
     217  
     218  extern void lsblk_device_free_filesystems(struct lsblk_device *dev);
     219  extern const char *lsblk_device_get_mountpoint(struct lsblk_device *dev);
     220  extern struct libmnt_fs **lsblk_device_get_filesystems(struct lsblk_device *dev, size_t *n);
     221  
     222  /* lsblk-properties.c */
     223  extern void lsblk_device_free_properties(struct lsblk_devprop *p);
     224  extern struct lsblk_devprop *lsblk_device_get_properties(struct lsblk_device *dev);
     225  extern void lsblk_properties_deinit(void);
     226  
     227  extern const char *lsblk_parttype_code_to_string(const char *code, const char *pttype);
     228  
     229  /* lsblk-devtree.c */
     230  void lsblk_reset_iter(struct lsblk_iter *itr, int direction);
     231  struct lsblk_device *lsblk_new_device(void);
     232  void lsblk_ref_device(struct lsblk_device *dev);
     233  void lsblk_unref_device(struct lsblk_device *dev);
     234  int lsblk_device_new_dependence(struct lsblk_device *parent, struct lsblk_device *child);
     235  int lsblk_device_has_child(struct lsblk_device *dev, struct lsblk_device *child);
     236  int lsblk_device_next_child(struct lsblk_device *dev,
     237                            struct lsblk_iter *itr,
     238                            struct lsblk_device **child);
     239  
     240  dev_t lsblk_devtree_pktcdvd_get_mate(struct lsblk_devtree *tr, dev_t devno, int is_slave);
     241  
     242  int lsblk_device_is_last_parent(struct lsblk_device *dev, struct lsblk_device *parent);
     243  int lsblk_device_next_parent(
     244                          struct lsblk_device *dev,
     245                          struct lsblk_iter *itr,
     246                          struct lsblk_device **parent);
     247  
     248  struct lsblk_devtree *lsblk_new_devtree(void);
     249  void lsblk_ref_devtree(struct lsblk_devtree *tr);
     250  void lsblk_unref_devtree(struct lsblk_devtree *tr);
     251  int lsblk_devtree_add_root(struct lsblk_devtree *tr, struct lsblk_device *dev);
     252  int lsblk_devtree_remove_root(struct lsblk_devtree *tr, struct lsblk_device *dev);
     253  int lsblk_devtree_next_root(struct lsblk_devtree *tr,
     254                              struct lsblk_iter *itr,
     255                              struct lsblk_device **dev);
     256  int lsblk_devtree_add_device(struct lsblk_devtree *tr, struct lsblk_device *dev);
     257  int lsblk_devtree_next_device(struct lsblk_devtree *tr,
     258                              struct lsblk_iter *itr,
     259                              struct lsblk_device **dev);
     260  int lsblk_devtree_has_device(struct lsblk_devtree *tr, struct lsblk_device *dev);
     261  struct lsblk_device *lsblk_devtree_get_device(struct lsblk_devtree *tr, const char *name);
     262  int lsblk_devtree_remove_device(struct lsblk_devtree *tr, struct lsblk_device *dev);
     263  int lsblk_devtree_deduplicate_devices(struct lsblk_devtree *tr);
     264  
     265  #endif /* UTIL_LINUX_LSBLK_H */