lsblk: use generic sysfs functions

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2011-05-16 15:24:26 +02:00
parent 7fe16fdaf4
commit 766ab9b08d
2 changed files with 50 additions and 202 deletions

View File

@ -58,7 +58,9 @@ lsblk_SOURCES = lsblk.c \
$(top_srcdir)/lib/ismounted.c \
$(top_srcdir)/lib/tt.c \
$(top_srcdir)/lib/mbsalign.c \
$(top_srcdir)/lib/strutils.c
$(top_srcdir)/lib/strutils.c \
$(top_srcdir)/lib/sysfs.c \
$(top_srcdir)/lib/at.c
lsblk_LDADD = $(ul_libblkid_la)
lsblk_CFLAGS = $(AM_CFLAGS) -I$(ul_libblkid_incdir)
endif

View File

@ -52,6 +52,7 @@
#include "xalloc.h"
#include "strutils.h"
#include "c.h"
#include "sysfs.h"
/* column IDs */
enum {
@ -147,7 +148,8 @@ struct blkdev_cxt {
char *dm_name; /* DM name (dm/block) */
char *filename; /* path to device node */
int sysfs_fd; /* O_RDONLY file desciptor to /sys/block/<dev> */
struct sysfs_cxt sysfs;
int partition; /* is partition? TRUE/FALSE */
@ -176,7 +178,6 @@ static int is_maj_excluded(int maj)
return 0;
}
/* array with IDs of enabled columns */
static int get_column_id(int num)
{
@ -191,7 +192,6 @@ static struct colinfo *get_column_info(int num)
return &infos[ get_column_id(num) ];
}
static int column_name_to_id(const char *name, size_t namesz)
{
int i;
@ -217,8 +217,7 @@ static void reset_blkdev_cxt(struct blkdev_cxt *cxt)
free(cxt->uuid);
free(cxt->label);
if (cxt->sysfs_fd >= 0)
close(cxt->sysfs_fd);
sysfs_deinit(&cxt->sysfs);
memset(cxt, 0, sizeof(*cxt));
}
@ -245,27 +244,6 @@ static struct dirent *xreaddir(DIR *dp)
return d;
}
static int is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
{
char path[256];
assert(dir);
assert(d);
#ifdef _DIRENT_HAVE_D_TYPE
if (d->d_type != DT_DIR)
return 0;
#endif
if (strncmp(parent_name, d->d_name, strlen(parent_name)))
return 0;
/* Cannot use /partition file, not supported on old sysfs */
snprintf(path, sizeof(path), "%s/start", d->d_name);
return faccessat(dirfd(dir), path, R_OK, 0) == 0;
}
static char *get_device_path(struct blkdev_cxt *cxt)
{
char path[PATH_MAX];
@ -280,141 +258,6 @@ static char *get_device_path(struct blkdev_cxt *cxt)
return xstrdup(path);
}
static char *get_sysfs_path(struct blkdev_cxt *cxt)
{
char path[PATH_MAX];
assert(cxt);
assert(cxt->name);
if (cxt->partition && cxt->parent)
snprintf(path, sizeof(path), _PATH_SYS_BLOCK "/%s/%s",
cxt->parent->name, cxt->name);
else
snprintf(path, sizeof(path), _PATH_SYS_BLOCK "/%s", cxt->name);
return xstrdup(path);
}
static int sysfs_open(struct blkdev_cxt *cxt, const char *attr)
{
int fd;
assert(cxt);
assert(cxt->sysfs_fd >= 0);
fd = openat(cxt->sysfs_fd, attr, O_RDONLY);
if (fd == -1 && errno == ENOENT && !strncmp(attr, "queue/", 6) && cxt->parent) {
fd = openat(cxt->parent->sysfs_fd, attr, O_RDONLY);
}
return fd;
}
static FILE *sysfs_fopen(struct blkdev_cxt *cxt, const char *attr)
{
int fd = sysfs_open(cxt, attr);
return fd < 0 ? NULL : fdopen(fd, "r");
}
static DIR *sysfs_opendir(struct blkdev_cxt *cxt, const char *attr)
{
DIR *dir;
int fd;
if (attr)
fd = sysfs_open(cxt, attr);
else {
/* request to open root of device in sysfs (/sys/block/<dev>)
* -- we cannot use cxt->sysfs_fd directly, because closedir()
* will close this our persistent file descriptor.
*/
assert(cxt);
assert(cxt->sysfs_fd >= 0);
fd = dup(cxt->sysfs_fd);
}
if (fd < 0)
return NULL;
dir = fdopendir(fd);
if (!dir) {
close(fd);
return NULL;
}
if (!attr)
rewinddir(dir);
return dir;
}
static __attribute__ ((format (scanf, 3, 4)))
int sysfs_scanf(struct blkdev_cxt *cxt, const char *attr, const char *fmt, ...)
{
FILE *f = sysfs_fopen(cxt, attr);
va_list ap;
int rc;
if (!f)
return -EINVAL;
va_start(ap, fmt);
rc = vfscanf(f, fmt, ap);
va_end(ap);
fclose(f);
return rc;
}
static uint64_t sysfs_read_u64(struct blkdev_cxt *cxt, const char *attr)
{
uint64_t x;
return sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1 ? x : 0;
}
static int sysfs_read_int(struct blkdev_cxt *cxt, const char *attr)
{
int x;
return sysfs_scanf(cxt, attr, "%d", &x) == 1 ? x : 0;
}
static char *sysfs_strdup(struct blkdev_cxt *cxt, const char *attr)
{
char buf[1024];
return sysfs_scanf(cxt, attr, "%1024[^\n]", buf) == 1 ?
xstrdup(buf) : NULL;
}
static int sysfs_count_dirents(struct blkdev_cxt *cxt, const char *attr)
{
DIR *dir;
int r = 0;
if (!(dir = sysfs_opendir(cxt, attr)))
return 0;
while (xreaddir(dir)) r++;
closedir(dir);
return r;
}
static int sysfs_count_partitions(struct blkdev_cxt *cxt)
{
DIR *dir;
struct dirent *d;
int r = 0;
if (!(dir = sysfs_opendir(cxt, NULL)))
return 0;
while ((d = xreaddir(dir))) {
if (is_partition_dirent(dir, d, cxt->name))
r++;
}
closedir(dir);
return r;
}
static char *get_device_mountpoint(struct blkdev_cxt *cxt)
{
int fl = 0;
@ -478,7 +321,7 @@ static int is_readonly_device(struct blkdev_cxt *cxt)
{
int fd, ro = 0;
if (sysfs_scanf(cxt, "ro", "%d", &ro) == 0)
if (sysfs_scanf(&cxt->sysfs, "ro", "%d", &ro) == 0)
return ro;
/* fallback if "ro" attribute does not exist */
@ -492,7 +335,7 @@ static int is_readonly_device(struct blkdev_cxt *cxt)
static char *get_scheduler(struct blkdev_cxt *cxt)
{
char *str = sysfs_strdup(cxt, "queue/scheduler");
char *str = sysfs_strdup(&cxt->sysfs, "queue/scheduler");
char *p, *res = NULL;
if (!str)
@ -516,7 +359,7 @@ static char *get_type(struct blkdev_cxt *cxt)
char *res = NULL, *p;
if (is_dm(cxt->name)) {
char *dm_uuid = sysfs_strdup(cxt, "dm/uuid");
char *dm_uuid = sysfs_strdup(&cxt->sysfs, "dm/uuid");
/* The DM_UUID prefix should be set to subsystem owning
* the device - LVM, CRYPT, DMRAID, MPATH, PART */
@ -542,13 +385,13 @@ static char *get_type(struct blkdev_cxt *cxt)
res = xstrdup("loop");
} else if (!strncmp(cxt->name, "md", 2)) {
char *md_level = sysfs_strdup(cxt, "md/level");
char *md_level = sysfs_strdup(&cxt->sysfs, "md/level");
res = md_level ? md_level : xstrdup("md");
} else {
const char *type = cxt->partition ? "part" : "disk";
switch (sysfs_read_int(cxt, "device/type")) {
switch (sysfs_read_int(&cxt->sysfs, "device/type")) {
case 0x0c: /* TYPE_RAID */
type = "raid"; break;
case 0x01: /* TYPE_TAPE */
@ -646,20 +489,20 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line
xstrdup("1") : xstrdup("0"));
break;
case COL_RM:
p = sysfs_strdup(cxt, "removable");
p = sysfs_strdup(&cxt->sysfs, "removable");
if (!p && cxt->parent)
p = sysfs_strdup(cxt->parent, "removable");
p = sysfs_strdup(&cxt->parent->sysfs, "removable");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_ROTA:
p = sysfs_strdup(cxt, "queue/rotational");
p = sysfs_strdup(&cxt->sysfs, "queue/rotational");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_MODEL:
if (!cxt->partition && cxt->nslaves == 0) {
p = sysfs_strdup(cxt, "device/model");
p = sysfs_strdup(&cxt->sysfs, "device/model");
if (p)
tt_line_set_data(ln, col, p);
}
@ -676,27 +519,27 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line
}
break;
case COL_ALIOFF:
p = sysfs_strdup(cxt, "alignment_offset");
p = sysfs_strdup(&cxt->sysfs, "alignment_offset");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_MINIO:
p = sysfs_strdup(cxt, "queue/minimum_io_size");
p = sysfs_strdup(&cxt->sysfs, "queue/minimum_io_size");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_OPTIO:
p = sysfs_strdup(cxt, "queue/optimal_io_size");
p = sysfs_strdup(&cxt->sysfs, "queue/optimal_io_size");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_PHYSEC:
p = sysfs_strdup(cxt, "queue/physical_block_size");
p = sysfs_strdup(&cxt->sysfs, "queue/physical_block_size");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_LOGSEC:
p = sysfs_strdup(cxt, "queue/logical_block_size");
p = sysfs_strdup(&cxt->sysfs, "queue/logical_block_size");
if (p)
tt_line_set_data(ln, col, p);
break;
@ -711,19 +554,19 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line
tt_line_set_data(ln, col, p);
break;
case COL_DALIGN:
p = sysfs_strdup(cxt, "discard_alignment");
p = sysfs_strdup(&cxt->sysfs, "discard_alignment");
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_DGRAN:
p = sysfs_strdup(cxt, "queue/discard_granularity");
p = sysfs_strdup(&cxt->sysfs, "queue/discard_granularity");
if (!lsblk->bytes)
p = size_to_human_string(atoi(p));
if (p)
tt_line_set_data(ln, col, p);
break;
case COL_DMAX:
p = sysfs_strdup(cxt, "queue/discard_max_bytes");
p = sysfs_strdup(&cxt->sysfs, "queue/discard_max_bytes");
if (!lsblk->bytes)
p = size_to_human_string(atoi(p));
@ -731,7 +574,7 @@ static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line
tt_line_set_data(ln, col, p);
break;
case COL_DZERO:
p = sysfs_strdup(cxt, "queue/discard_zeroes_data");
p = sysfs_strdup(&cxt->sysfs, "queue/discard_zeroes_data");
if (p)
tt_line_set_data(ln, col, p);
break;
@ -753,7 +596,7 @@ static int set_cxt(struct blkdev_cxt *cxt,
const char *name,
int partition)
{
char *p;
dev_t devno;
cxt->parent = parent;
cxt->name = xstrdup(name);
@ -761,28 +604,32 @@ static int set_cxt(struct blkdev_cxt *cxt,
cxt->filename = get_device_path(cxt);
/* open /sys/block/<name> */
p = get_sysfs_path(cxt);
cxt->sysfs_fd = open(p, O_RDONLY);
if (cxt->sysfs_fd < 0)
err(EXIT_FAILURE, _("%s: open failed"), p);
free(p);
devno = sysfs_devname_to_devno(name,
partition && parent ? parent->name : NULL);
if (!devno)
err(EXIT_FAILURE, _("%s: unknown device name"), name);
if (sysfs_scanf(cxt, "dev", "%u:%u", &cxt->maj, &cxt->min) != 2)
return -1;
if (sysfs_init(&cxt->sysfs, devno, &parent->sysfs))
err(EXIT_FAILURE, _("%s: failed to initialize sysfs handler"), name);
cxt->size = sysfs_read_u64(cxt, "size") << 9;
cxt->maj = major(devno);
cxt->min = minor(devno);
cxt->size = sysfs_read_u64(&cxt->sysfs, "size") << 9;
/* Ignore devices of zero size */
if (!lsblk->all_devices && cxt->size == 0)
return -1;
if (is_dm(name))
cxt->dm_name = sysfs_strdup(cxt, "dm/name");
if (is_dm(name)) {
cxt->dm_name = sysfs_strdup(&cxt->sysfs, "dm/name");
if (!cxt->dm_name)
err(XALLOC_EXIT_CODE, _("cannot duplicate string"));
}
cxt->nholders = sysfs_count_dirents(&cxt->sysfs, "holders") +
sysfs_count_partitions(&cxt->sysfs, name);
cxt->nholders = sysfs_count_dirents(cxt, "holders") +
sysfs_count_partitions(cxt);
cxt->nslaves = sysfs_count_dirents(cxt, "slaves");
cxt->nslaves = sysfs_count_dirents(&cxt->sysfs, "slaves");
return 0;
}
@ -797,7 +644,6 @@ static int list_holders(struct blkdev_cxt *cxt)
struct blkdev_cxt holder = {};
assert(cxt);
assert(cxt->sysfs_fd >= 0);
if (lsblk->nodeps)
return 0;
@ -806,12 +652,12 @@ static int list_holders(struct blkdev_cxt *cxt)
return 0;
/* Partitions */
dir = sysfs_opendir(cxt, NULL);
dir = sysfs_opendir(&cxt->sysfs, NULL);
if (!dir)
err(EXIT_FAILURE, _("failed to open device directory in sysfs"));
while ((d = xreaddir(dir))) {
if (!is_partition_dirent(dir, d, cxt->name))
if (!sysfs_is_partition_dirent(dir, d, cxt->name))
continue;
set_cxt(&holder, cxt, d->d_name, 1);
@ -822,7 +668,7 @@ static int list_holders(struct blkdev_cxt *cxt)
closedir(dir);
/* Holders */
dir = sysfs_opendir(cxt, "holders");
dir = sysfs_opendir(&cxt->sysfs, "holders");
if (!dir)
return 0;
@ -897,10 +743,10 @@ static int process_one_device(char *devname)
ssize_t len;
char path[PATH_MAX], *diskname, *name;
snprintf(path, sizeof(path), "/sys/dev/block/%d:%d",
major(st.st_rdev), minor(st.st_rdev));
diskname = xstrdup(buf);
if (!sysfs_devno_path(st.st_rdev, path, sizeof(path)))
err(EXIT_FAILURE, _("failed to compose sysfs path for %s"), devname);
diskname = xstrdup(buf);
len = readlink(path, buf, PATH_MAX);
if (len < 0) {
warn(_("%s: failed to read link"), path);