(root)/
util-linux-2.39/
misc-utils/
lsfd-bdev.c
       1  /*
       2   * lsfd-bdev.c - handle associations opening block devices
       3   *
       4   * Copyright (C) 2021 Red Hat, Inc. All rights reserved.
       5   * Written by Masatake YAMATO <yamato@redhat.com>
       6   *
       7   * This program is free software; you can redistribute it and/or modify
       8   * it under the terms of the GNU General Public License as published by
       9   * the Free Software Foundation; either version 2 of the License, or
      10   * (at your option) any later version.
      11   *
      12   * This program is distributed in the hope that it would be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15   * GNU General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU General Public License
      18   * along with this program; if not, write to the Free Software Foundation,
      19   * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      20   */
      21  
      22  #include "xalloc.h"
      23  #include "nls.h"
      24  #include "libsmartcols.h"
      25  
      26  #include "lsfd.h"
      27  
      28  static struct list_head partitions;
      29  
      30  struct partition {
      31  	struct list_head partitions;
      32  	dev_t dev;
      33  	char *name;
      34  };
      35  
      36  static bool bdev_fill_column(struct proc *proc __attribute__((__unused__)),
      37  			     struct file *file __attribute__((__unused__)),
      38  			     struct libscols_line *ln,
      39  			     int column_id,
      40  			     size_t column_index)
      41  {
      42  	char *str = NULL;
      43  	const char *partition, *devdrv;
      44  
      45  	switch(column_id) {
      46  	case COL_TYPE:
      47  		if (scols_line_set_data(ln, column_index, "BLK"))
      48  			err(EXIT_FAILURE, _("failed to add output data"));
      49  		return true;
      50  	case COL_BLKDRV:
      51  		devdrv = get_blkdrv(major(file->stat.st_rdev));
      52  		if (devdrv)
      53  			str = xstrdup(devdrv);
      54  		else
      55  			xasprintf(&str, "%u",
      56  				  major(file->stat.st_rdev));
      57  		break;
      58  	case COL_DEVTYPE:
      59  		if (scols_line_set_data(ln, column_index,
      60  					"blk"))
      61  			err(EXIT_FAILURE, _("failed to add output data"));
      62  		return true;
      63  	case COL_SOURCE:
      64  	case COL_PARTITION:
      65  		partition = get_partition(file->stat.st_rdev);
      66  		if (partition) {
      67  			str = xstrdup(partition);
      68  			break;
      69  		}
      70  		devdrv = get_blkdrv(major(file->stat.st_rdev));
      71  		if (devdrv) {
      72  			xasprintf(&str, "%s:%u", devdrv,
      73  				  minor(file->stat.st_rdev));
      74  			break;
      75  		}
      76  		/* FALL THROUGH */
      77  	case COL_MAJMIN:
      78  		xasprintf(&str, "%u:%u",
      79  			  major(file->stat.st_rdev),
      80  			  minor(file->stat.st_rdev));
      81  		break;
      82  	default:
      83  		return false;
      84  	}
      85  
      86  	if (!str)
      87  		err(EXIT_FAILURE, _("failed to add output data"));
      88  	if (scols_line_refer_data(ln, column_index, str))
      89  		err(EXIT_FAILURE, _("failed to add output data"));
      90  	return true;
      91  }
      92  
      93  static struct partition *new_partition(dev_t dev, const char *name)
      94  {
      95  	struct partition *partition = xcalloc(1, sizeof(*partition));
      96  
      97  	INIT_LIST_HEAD(&partition->partitions);
      98  
      99  	partition->dev = dev;
     100  	partition->name = xstrdup(name);
     101  
     102  	return partition;
     103  }
     104  
     105  static void free_partition(struct partition *partition)
     106  {
     107  	free(partition->name);
     108  	free(partition);
     109  }
     110  
     111  static void read_partitions(struct list_head *partitions_list, FILE *part_fp)
     112  {
     113  	unsigned int major, minor;
     114  	char line[256];
     115  	char name[sizeof(line)];
     116  
     117  	while (fgets(line, sizeof(line), part_fp)) {
     118  		struct partition *partition;
     119  
     120  		if (sscanf(line, "%u %u %*u %s", &major, &minor, name) != 3)
     121  			continue;
     122  		partition = new_partition(makedev(major, minor), name);
     123  		list_add_tail(&partition->partitions, partitions_list);
     124  	}
     125  }
     126  
     127  static void bdev_class_initialize(void)
     128  {
     129  	FILE *part_fp;
     130  
     131  	INIT_LIST_HEAD(&partitions);
     132  
     133  	part_fp = fopen("/proc/partitions", "r");
     134  	if (part_fp) {
     135  		read_partitions(&partitions, part_fp);
     136  		fclose(part_fp);
     137  	}
     138  }
     139  
     140  static void bdev_class_finalize(void)
     141  {
     142  	list_free(&partitions, struct partition,  partitions, free_partition);
     143  }
     144  
     145  const char *get_partition(dev_t dev)
     146  {
     147  	struct list_head *p;
     148  	list_for_each(p, &partitions) {
     149  		struct partition *partition = list_entry(p, struct partition, partitions);
     150  		if (partition->dev == dev)
     151  			return partition->name;
     152  	}
     153  	return NULL;
     154  }
     155  
     156  const struct file_class bdev_class = {
     157  	.super = &file_class,
     158  	.size = sizeof(struct file),
     159  	.initialize_class = bdev_class_initialize,
     160  	.finalize_class = bdev_class_finalize,
     161  	.fill_column = bdev_fill_column,
     162  	.free_content = NULL,
     163  };