mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Avoid code duplication and inconsistent error handling by replacing readlink() with util_readlink(), which is used project-wide to standardize readlink() usage. Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com> Signed-off-by: Jan Polensky <japo@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
176 lines
3.8 KiB
C
176 lines
3.8 KiB
C
/*
|
|
* util - Utility function library
|
|
*
|
|
* SysFS helper functions
|
|
*
|
|
* Copyright IBM Corp. 2019
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <linux/fs.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/util_file.h"
|
|
#include "lib/util_libc.h"
|
|
#include "lib/util_path.h"
|
|
#include "lib/util_sys.h"
|
|
|
|
#define PAGE_SIZE 4096
|
|
|
|
/**
|
|
* Return the partition number of a given partition.
|
|
*
|
|
* @param[in] dev Device node of interest
|
|
*
|
|
* @retval int Partition number of the device
|
|
* @retval -1 Error when trying to read the partition number.
|
|
*/
|
|
int util_sys_get_partnum(dev_t dev)
|
|
{
|
|
int partnum = -1;
|
|
char *path;
|
|
|
|
path = util_path_sysfs("dev/block/%u:%u/partition",
|
|
major(dev), minor(dev));
|
|
if (util_file_read_i(&partnum, 10, path)) {
|
|
warnx("Could not read from path '%s'", path);
|
|
goto out;
|
|
}
|
|
if (partnum <= 0) {
|
|
warnx("Bad partition number in '%s'", path);
|
|
partnum = -1;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
free(path);
|
|
return partnum;
|
|
}
|
|
|
|
/**
|
|
* Determine if the given device is a partition.
|
|
*
|
|
* @param[in] dev Device node of interest
|
|
*
|
|
* @retval true Device is partition
|
|
* @retval false Device is not a partition
|
|
*/
|
|
bool util_sys_dev_is_partition(dev_t dev)
|
|
{
|
|
bool is_part;
|
|
char *path;
|
|
|
|
path = util_path_sysfs("dev/block/%u:%u/partition",
|
|
major(dev), minor(dev));
|
|
is_part = util_path_exists(path);
|
|
free(path);
|
|
|
|
return is_part;
|
|
}
|
|
|
|
/**
|
|
* Determine base device
|
|
*
|
|
* This function determines the base device \p base_dev of a given
|
|
* device \p dev. If \p dev is a base device, \p base_dev becomes \p dev.
|
|
*
|
|
* @param[in] dev Device node of interest
|
|
* @param[out] base_dev Identified base device
|
|
*
|
|
* @retval 0 Success
|
|
* @retval -1 Error while reading device information or
|
|
* constructed path
|
|
*/
|
|
int util_sys_get_base_dev(dev_t dev, dev_t *base_dev)
|
|
{
|
|
int base_major, base_minor;
|
|
char buf[PAGE_SIZE];
|
|
char *path;
|
|
|
|
/* check if the device already is a base device */
|
|
if (!util_sys_dev_is_partition(dev)) {
|
|
*base_dev = makedev(major(dev), minor(dev));
|
|
return 0;
|
|
}
|
|
path = util_path_sysfs("dev/block/%d:%d/../dev",
|
|
major(dev), minor(dev));
|
|
if (util_file_read_line(buf, sizeof(buf), path)) {
|
|
warnx("Could not read from path '%s'", path);
|
|
free(path);
|
|
return -1;
|
|
}
|
|
free(path);
|
|
if (sscanf(buf, "%i:%i", &base_major, &base_minor) != 2) {
|
|
warn("Could not parse major:minor from string '%s'", buf);
|
|
return -1;
|
|
}
|
|
*base_dev = makedev(base_major, base_minor);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Identify device address
|
|
*
|
|
* Identifying the device address with this function works for almost any
|
|
* character and block device (e.g. NVMe, SCSI, DASD, etc).
|
|
* The user must provide a buffer that is large enough for the desired device
|
|
* address to be read into \p addr.
|
|
*
|
|
* @param[in] dev Device node of interest
|
|
* @param[out] addr Identified device address
|
|
*
|
|
* @retval 0 Success
|
|
* @retval -1 Error while reading device information or
|
|
* constructed path
|
|
*/
|
|
int util_sys_get_dev_addr(const char *dev, char *addr)
|
|
{
|
|
unsigned int maj, min;
|
|
struct stat s;
|
|
char *linkdir;
|
|
char *result;
|
|
dev_t base;
|
|
char *path;
|
|
|
|
if (stat(dev, &s) != 0)
|
|
return -1;
|
|
|
|
if (util_sys_get_base_dev(s.st_rdev, &base))
|
|
return -1;
|
|
|
|
maj = major(base);
|
|
min = minor(base);
|
|
|
|
if (S_ISBLK(s.st_mode))
|
|
path = util_path_sysfs("dev/block/%u:%u/device", maj, min);
|
|
else if (S_ISCHR(s.st_mode))
|
|
path = util_path_sysfs("dev/char/%u:%u/device", maj, min);
|
|
else
|
|
return -1;
|
|
|
|
linkdir = util_readlink(path);
|
|
free(path);
|
|
if (!linkdir)
|
|
return -1;
|
|
|
|
result = strrchr(linkdir, '/');
|
|
if (result)
|
|
result++;
|
|
else
|
|
result = linkdir;
|
|
strcpy(addr, result);
|
|
free(linkdir);
|
|
|
|
return 0;
|
|
}
|