(root)/
util-linux-2.39/
misc-utils/
lsfd-cdev.c
       1  /*
       2   * lsfd-cdev.c - handle associations opening character 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 miscdevs;
      29  
      30  struct miscdev {
      31  	struct list_head miscdevs;
      32  	unsigned long minor;
      33  	char *name;
      34  };
      35  
      36  static bool cdev_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 *devdrv;
      44  	const char *miscdev;
      45  
      46  	switch(column_id) {
      47  	case COL_TYPE:
      48  		if (scols_line_set_data(ln, column_index, "CHR"))
      49  			err(EXIT_FAILURE, _("failed to add output data"));
      50  		return true;
      51  	case COL_MISCDEV:
      52  		devdrv = get_chrdrv(major(file->stat.st_rdev));
      53  		if (devdrv && strcmp(devdrv, "misc") == 0) {
      54  			miscdev = get_miscdev(minor(file->stat.st_rdev));
      55  			if (miscdev)
      56  				str = xstrdup(miscdev);
      57  			else
      58  				xasprintf(&str, "%u",
      59  					  minor(file->stat.st_rdev));
      60  			break;
      61  		}
      62  		return true;
      63  	case COL_DEVTYPE:
      64  		if (scols_line_set_data(ln, column_index,
      65  					"char"))
      66  			err(EXIT_FAILURE, _("failed to add output data"));
      67  		return true;
      68  	case COL_CHRDRV:
      69  		devdrv = get_chrdrv(major(file->stat.st_rdev));
      70  		if (devdrv)
      71  			str = xstrdup(devdrv);
      72  		else
      73  			xasprintf(&str, "%u",
      74  				  major(file->stat.st_rdev));
      75  		break;
      76  	case COL_SOURCE:
      77  		devdrv = get_chrdrv(major(file->stat.st_rdev));
      78  		miscdev = NULL;
      79  		if (devdrv && strcmp(devdrv, "misc") == 0)
      80  			miscdev = get_miscdev(minor(file->stat.st_rdev));
      81  		if (devdrv) {
      82  			if (miscdev) {
      83  				xasprintf(&str, "misc:%s", miscdev);
      84  			} else {
      85  				xasprintf(&str, "%s:%u", devdrv,
      86  					  minor(file->stat.st_rdev));
      87  			}
      88  			break;
      89  		}
      90  		/* FALL THROUGH */
      91  	case COL_MAJMIN:
      92  		xasprintf(&str, "%u:%u",
      93  			  major(file->stat.st_rdev),
      94  			  minor(file->stat.st_rdev));
      95  		break;
      96  	default:
      97  		return false;
      98  	}
      99  
     100  	if (!str)
     101  		err(EXIT_FAILURE, _("failed to add output data"));
     102  	if (scols_line_refer_data(ln, column_index, str))
     103  		err(EXIT_FAILURE, _("failed to add output data"));
     104  	return true;
     105  }
     106  
     107  static struct miscdev *new_miscdev(unsigned long minor, const char *name)
     108  {
     109  	struct miscdev *miscdev = xcalloc(1, sizeof(*miscdev));
     110  
     111  	INIT_LIST_HEAD(&miscdev->miscdevs);
     112  
     113  	miscdev->minor = minor;
     114  	miscdev->name = xstrdup(name);
     115  
     116  	return miscdev;
     117  }
     118  
     119  static void free_miscdev(struct miscdev *miscdev)
     120  {
     121  	free(miscdev->name);
     122  	free(miscdev);
     123  }
     124  
     125  static void read_misc(struct list_head *miscdevs_list, FILE *misc_fp)
     126  {
     127  	unsigned long minor;
     128  	char line[256];
     129  	char name[sizeof(line)];
     130  
     131  	while (fgets(line, sizeof(line), misc_fp)) {
     132  		struct miscdev *miscdev;
     133  
     134  		if (sscanf(line, "%lu %s", &minor, name) != 2)
     135  			continue;
     136  
     137  		miscdev = new_miscdev(minor, name);
     138  		list_add_tail(&miscdev->miscdevs, miscdevs_list);
     139  	}
     140  }
     141  
     142  static void cdev_class_initialize(void)
     143  {
     144  	FILE *misc_fp;
     145  
     146  	INIT_LIST_HEAD(&miscdevs);
     147  
     148  	misc_fp = fopen("/proc/misc", "r");
     149  	if (misc_fp) {
     150  		read_misc(&miscdevs, misc_fp);
     151  		fclose(misc_fp);
     152  	}
     153  }
     154  
     155  static void cdev_class_finalize(void)
     156  {
     157  	list_free(&miscdevs, struct miscdev, miscdevs, free_miscdev);
     158  }
     159  
     160  const char *get_miscdev(unsigned long minor)
     161  {
     162  	struct list_head *c;
     163  	list_for_each(c, &miscdevs) {
     164  		struct miscdev *miscdev = list_entry(c, struct miscdev, miscdevs);
     165  		if (miscdev->minor == minor)
     166  			return miscdev->name;
     167  	}
     168  	return NULL;
     169  }
     170  
     171  const struct file_class cdev_class = {
     172  	.super = &file_class,
     173  	.size = sizeof(struct file),
     174  	.initialize_class = cdev_class_initialize,
     175  	.finalize_class = cdev_class_finalize,
     176  	.fill_column = cdev_fill_column,
     177  	.free_content = NULL,
     178  };