mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Replace `UTIL_ARRAY_SIZE` with `ARRAY_SIZE` and remove it from `util_base.h`. Acked-by: Jan Höppner <hoeppner@linux.ibm.com> Reviewed-by: Philipp Rudo <prudo@linux.ibm.com> Reviewed-by: Stefan Haberland <sth@linux.ibm.com> Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
730 lines
18 KiB
C
730 lines
18 KiB
C
/*
|
|
* dasdinfo - Display unique DASD ID, either UID or volser
|
|
*
|
|
* Copyright IBM Corp. 2007, 2017
|
|
*
|
|
* 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 <dirent.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <ftw.h>
|
|
#include <getopt.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <sys/types.h>
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/dasd_base.h"
|
|
#include "lib/util_base.h"
|
|
#include "lib/util_file.h"
|
|
#include "lib/util_libc.h"
|
|
#include "lib/util_opt.h"
|
|
#include "lib/util_prg.h"
|
|
#include "lib/zt_common.h"
|
|
|
|
#define RD_BUFFER_SIZE 80
|
|
#define TEMP_DEV_MAX_RETRIES 1000
|
|
|
|
static const struct util_prg prg = {
|
|
.desc = "Display DASD volume serial number and ID information",
|
|
.args = "-i BUSID | -b BLOCKDEV | -d DEVNODE",
|
|
.copyright_vec = {
|
|
{
|
|
.owner = "IBM Corp.",
|
|
.pub_first = 2007,
|
|
},
|
|
UTIL_PRG_COPYRIGHT_END
|
|
}
|
|
};
|
|
|
|
static struct util_opt opt_vec[] = {
|
|
UTIL_OPT_SECTION("DEVICE"),
|
|
{
|
|
.option = { "block", required_argument, NULL, 'b' },
|
|
.argument = "BLOCKDEV",
|
|
.desc = "Block device name, e.g. dasdb",
|
|
},
|
|
{
|
|
.option = { "devnode", required_argument, NULL, 'd' },
|
|
.argument = "DEVNODE",
|
|
.desc = "Device node, e.g. /dev/dasda",
|
|
},
|
|
{
|
|
.option = { "busid", required_argument, NULL, 'i' },
|
|
.argument = "BUSID",
|
|
.desc = "Bus ID, e.g. 0.0.e910",
|
|
},
|
|
UTIL_OPT_SECTION("OPTIONS"),
|
|
{
|
|
.option = { "label", no_argument, NULL, 'l' },
|
|
.desc = "Print DASD volume label (volser)",
|
|
},
|
|
{
|
|
.option = { "uid", no_argument, NULL, 'u' },
|
|
.desc = "Print DASD uid (without z/VM minidisk token)",
|
|
},
|
|
{
|
|
.option = { "extended-uid", no_argument, NULL, 'x' },
|
|
.desc = "Print DASD uid (including z/VM minidisk token)",
|
|
},
|
|
{
|
|
.option = { "all", no_argument, NULL, 'a' },
|
|
.desc = "Same as -u -x -l",
|
|
},
|
|
{
|
|
.option = { "export", no_argument, NULL, 'e' },
|
|
.desc = "Export ID_BUS, ID_TYPE, ID_SERIAL for use in udev",
|
|
},
|
|
UTIL_OPT_HELP,
|
|
UTIL_OPT_VERSION,
|
|
UTIL_OPT_END
|
|
};
|
|
|
|
/* needed because ftw can not pass arbitrary arguments */
|
|
static char *searchbusid;
|
|
static char *busiddir;
|
|
|
|
struct volume_label {
|
|
char volkey[4];
|
|
char vollbl[4];
|
|
char volid[6];
|
|
} __attribute__ ((packed));
|
|
|
|
static char EBCtoASC[256] = {
|
|
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
|
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
|
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
|
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC */
|
|
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
|
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB */
|
|
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC */
|
|
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
|
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL */
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
|
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
|
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
|
/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
|
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
|
/* 0x40 SP RSP ? ---- */
|
|
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
|
/* 0x48 . < ( + | */
|
|
0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
|
/* 0x50 & ---- */
|
|
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
|
/* 0x58 ? ! $ * ) ; */
|
|
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
|
/* 0x60 - / ---- ? ---- ---- ---- */
|
|
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
|
/* 0x68 ---- , % _ > ? */
|
|
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
|
/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
|
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x78 * ` : # @ ' = " */
|
|
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
|
/* 0x80 * a b c d e f g */
|
|
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
/* 0x88 h i ---- ---- ---- */
|
|
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
|
/* 0x90 ? j k l m n o p */
|
|
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
|
/* 0x98 q r ---- ---- */
|
|
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
|
/* 0xA0 ~ s t u v w x */
|
|
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
|
/* 0xA8 y z ---- ---- ---- ---- */
|
|
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xB0 ^ ---- ? ---- */
|
|
0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
|
/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
|
0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xC0 { A B C D E F G */
|
|
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
/* 0xC8 H I ---- ? ---- */
|
|
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
|
/* 0xD0 } J K L M N O P */
|
|
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
|
/* 0xD8 Q R ---- ? */
|
|
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
|
/* 0xE0 \ S T U V W X */
|
|
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
/* 0xE8 Y Z ---- ? ---- ---- ---- */
|
|
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
|
/* 0xF0 0 1 2 3 4 5 6 7 */
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
/* 0xF8 8 9 ---- ---- ? ---- ---- ---- */
|
|
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
|
};
|
|
|
|
static char *dinfo_ebcdic_dec(char *source, char *target, int l)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < l; i++)
|
|
target[i] = EBCtoASC[(unsigned char)(source[i])];
|
|
|
|
return target;
|
|
}
|
|
|
|
static int dinfo_read_dasd_uid(char *uidfile, char *readbuf)
|
|
{
|
|
return util_file_read_line(readbuf, RD_BUFFER_SIZE, uidfile);
|
|
}
|
|
|
|
static int dinfo_read_dasd_vlabel(char *device, struct volume_label *vlabel,
|
|
char *readbuf)
|
|
{
|
|
struct volume_label tmp;
|
|
int vlsize = sizeof(struct volume_label);
|
|
dasd_information2_t dasd_info;
|
|
unsigned long vlabel_start;
|
|
unsigned int blksize;
|
|
char vollbl[5];
|
|
int f;
|
|
char *space;
|
|
|
|
if (dasd_get_blocksize(device, &blksize) != 0) {
|
|
warnx("Unable to figure out block size");
|
|
goto error;
|
|
}
|
|
|
|
if (dasd_get_info(device, &dasd_info) != 0) {
|
|
warnx("Unable to figure out DASD information");
|
|
goto error;
|
|
}
|
|
|
|
f = open(device, O_RDONLY);
|
|
if (f < 0) {
|
|
warnx("Could not open device node");
|
|
goto error;
|
|
}
|
|
|
|
vlabel_start = dasd_info.label_block * blksize;
|
|
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
|
goto error_close;
|
|
|
|
bzero(vlabel, vlsize);
|
|
|
|
if (read(f, vlabel, vlsize) != vlsize) {
|
|
warnx("Could not read volume label");
|
|
goto error_close;
|
|
}
|
|
|
|
if (dasd_info.FBA_layout) {
|
|
bzero(&tmp, vlsize);
|
|
memcpy(&tmp, vlabel, vlsize);
|
|
memcpy(vlabel->vollbl, &tmp, vlsize - 4);
|
|
}
|
|
|
|
close(f);
|
|
|
|
bzero(readbuf, 7);
|
|
bzero(vollbl, 5);
|
|
strncpy(vollbl, vlabel->vollbl, 4);
|
|
dinfo_ebcdic_dec(vollbl, vollbl, 4);
|
|
|
|
if ((strncmp(vollbl, "VOL1", 4) == 0) ||
|
|
(strncmp(vollbl, "LNX1", 4) == 0) ||
|
|
(strncmp(vollbl, "CMS1", 4) == 0)) {
|
|
strncpy(readbuf, vlabel->volid, 6);
|
|
dinfo_ebcdic_dec(readbuf, readbuf, 6);
|
|
space = strchr(readbuf, ' ');
|
|
if (space)
|
|
*space = 0;
|
|
} else {
|
|
strcpy(readbuf, "");
|
|
}
|
|
|
|
return 0;
|
|
error_close:
|
|
close(f);
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
static void *dinfo_malloc(size_t size)
|
|
{
|
|
void *result;
|
|
|
|
result = malloc(size);
|
|
if (result == NULL)
|
|
warnx("Could not allocate %lu bytes of memory", size);
|
|
|
|
return result;
|
|
}
|
|
|
|
static char *dinfo_make_path(char *dirname, char *filename)
|
|
{
|
|
char *result;
|
|
size_t len;
|
|
|
|
len = strlen(dirname) + strlen(filename) + 2;
|
|
result = (char *)dinfo_malloc(len);
|
|
if (result == NULL)
|
|
return NULL;
|
|
sprintf(result, "%s/%s", dirname, filename);
|
|
return result;
|
|
}
|
|
|
|
static int dinfo_create_devnode(dev_t dev, char **devno)
|
|
{
|
|
char *result;
|
|
char *pathname[] = { "/dev", getenv("TMPDIR"), "/tmp",
|
|
getenv("HOME"), ".", "/"};
|
|
char filename[] = "dasdinfo0000";
|
|
mode_t mode;
|
|
unsigned int path;
|
|
int retry;
|
|
int rc;
|
|
int fd;
|
|
|
|
mode = S_IFBLK | S_IRWXU;
|
|
|
|
/* Try several locations for the temporary device node. */
|
|
for (path = 0; path < ARRAY_SIZE(pathname); path++) {
|
|
if (pathname[path] == NULL)
|
|
continue;
|
|
for (retry = 0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
|
sprintf(filename, "dasdinfo%04d", retry);
|
|
result = dinfo_make_path(pathname[path], filename);
|
|
if (result == NULL)
|
|
return -1;
|
|
rc = mknod(result, mode, dev);
|
|
if (rc == 0) {
|
|
/* Need this test to cover
|
|
* 'nodev'-mounted
|
|
* filesystems.
|
|
*/
|
|
fd = open(result, O_RDONLY);
|
|
if (fd != -1) {
|
|
close(fd);
|
|
*devno = result;
|
|
return 0;
|
|
}
|
|
remove(result);
|
|
retry = TEMP_DEV_MAX_RETRIES;
|
|
} else if (errno != EEXIST) {
|
|
retry = TEMP_DEV_MAX_RETRIES;
|
|
}
|
|
free(result);
|
|
}
|
|
}
|
|
warnx("Error: Unable to create temporary device node");
|
|
return -1;
|
|
}
|
|
|
|
static void dinfo_free_devnode(char *device)
|
|
{
|
|
if (remove(device))
|
|
warnx("Warning: Could not remove temporary file %s", device);
|
|
}
|
|
|
|
static int dinfo_extract_dev(dev_t *dev, char *str)
|
|
{
|
|
char tmp[RD_BUFFER_SIZE];
|
|
char *p = NULL;
|
|
int ma, mi;
|
|
|
|
bzero(tmp, RD_BUFFER_SIZE);
|
|
util_strlcpy(tmp, str, RD_BUFFER_SIZE);
|
|
p = strchr(tmp, ':');
|
|
if (p == NULL) {
|
|
warnx("Error: unable to extract major/minor");
|
|
return -1;
|
|
}
|
|
|
|
*p = '\0';
|
|
ma = atoi(tmp);
|
|
mi = atoi(p + sizeof(char));
|
|
|
|
*dev = makedev(ma, mi);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dinfo_get_dev_from_blockdev(char *blockdev, dev_t *dev)
|
|
{
|
|
char *readbuf = NULL;
|
|
|
|
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
|
if (!readbuf) {
|
|
warnx("Error: Not enough memory to allocate readbuffer");
|
|
return -1;
|
|
}
|
|
if (util_file_read_line(readbuf, RD_BUFFER_SIZE,
|
|
"/sys/block/%s/dev", blockdev) < 0)
|
|
return -1;
|
|
if (dinfo_extract_dev(dev, readbuf) != 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
|
|
int tflag, struct FTW *ftwbuf)
|
|
{
|
|
char *tempdir;
|
|
char linkdir[128];
|
|
ssize_t i;
|
|
|
|
if (tflag != FTW_D || (strncmp((fpath + ftwbuf->base), searchbusid,
|
|
strlen(searchbusid)) != 0))
|
|
return FTW_CONTINUE;
|
|
/*
|
|
* ensure that the found entry is a busid and not a
|
|
* subchannel ID
|
|
* for large systems subchannel IDs may look like busids
|
|
*/
|
|
if (asprintf(&tempdir, "%s/driver", fpath) < 0)
|
|
return -1;
|
|
i = readlink(tempdir, linkdir, 128);
|
|
free(tempdir);
|
|
if ((i < 0) || (i >= 128))
|
|
return -1;
|
|
/* append '\0' because readlink returns non zero terminated string */
|
|
tempdir[i + 1] = '\0';
|
|
if (strstr(linkdir, "dasd") == NULL)
|
|
return FTW_CONTINUE;
|
|
free(busiddir);
|
|
busiddir = strdup(fpath);
|
|
if (busiddir == NULL)
|
|
return -1;
|
|
return FTW_STOP;
|
|
}
|
|
|
|
static int
|
|
dinfo_find_entry(const char *dir, const char *searchstring,
|
|
char type, char **result)
|
|
{
|
|
DIR *directory = NULL;
|
|
struct dirent *dir_entry = NULL;
|
|
|
|
directory = opendir(dir);
|
|
if (directory == NULL)
|
|
return -1;
|
|
while ((dir_entry = readdir(directory)) != NULL) {
|
|
/* compare if the found entry has exactly the same name and type
|
|
* as searched
|
|
*/
|
|
if ((strncmp(dir_entry->d_name, searchstring,
|
|
strlen(searchstring)) == 0) &&
|
|
(dir_entry->d_type & type)) {
|
|
*result = strdup(dir_entry->d_name);
|
|
if (*result == NULL)
|
|
goto out;
|
|
closedir(directory);
|
|
return 0; /* found */
|
|
}
|
|
}
|
|
out:
|
|
closedir(directory);
|
|
return -1; /* nothing found or error */
|
|
}
|
|
|
|
static int
|
|
dinfo_get_blockdev_from_busid(char *busid, char **blkdev)
|
|
{
|
|
int flags = FTW_PHYS; /* do not follow links */
|
|
int rc = -1;
|
|
|
|
char *tempdir = NULL;
|
|
char *result = NULL;
|
|
char *sysfsdir = "/sys/devices/";
|
|
|
|
/* dinfo_is_devnode needs to know the busid */
|
|
searchbusid = busid;
|
|
if (nftw(sysfsdir, dinfo_is_busiddir, 200, flags) != FTW_STOP)
|
|
goto out;
|
|
|
|
/*
|
|
* new sysfs: busid directory contains a directory 'block'
|
|
* which contains a directory 'dasdXXX'
|
|
*/
|
|
rc = dinfo_find_entry(busiddir, "block", DT_DIR, &result);
|
|
if (rc == 0) {
|
|
if (asprintf(&tempdir, "%s/%s/", busiddir, result) < 0) {
|
|
rc = -1;
|
|
goto out2;
|
|
}
|
|
rc = dinfo_find_entry(tempdir, "dasd", DT_DIR, blkdev);
|
|
} else {
|
|
/*
|
|
* old sysfs: entry for busiddir contain a link
|
|
* 'block:dasdXXX'
|
|
*/
|
|
rc = dinfo_find_entry(busiddir, "block:", DT_LNK, &result);
|
|
if (rc != 0)
|
|
goto out2;
|
|
*blkdev = strdup(strchr(result, ':') + 1);
|
|
if (*blkdev == NULL)
|
|
rc = -1;
|
|
}
|
|
|
|
out:
|
|
free(tempdir);
|
|
out2:
|
|
free(busiddir);
|
|
free(result);
|
|
return rc;
|
|
}
|
|
|
|
static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
|
{
|
|
struct stat stat_buffer;
|
|
char stat_dev[RD_BUFFER_SIZE];
|
|
char *readbuf;
|
|
DIR *directory = NULL;
|
|
struct dirent *dir_entry = NULL;
|
|
int rc = 0;
|
|
|
|
if (stat(devnode, &stat_buffer) != 0) {
|
|
warnx("Error: could not stat %s", devnode);
|
|
return -1;
|
|
}
|
|
|
|
sprintf(stat_dev, "%d:%d", major(stat_buffer.st_rdev),
|
|
minor(stat_buffer.st_rdev));
|
|
|
|
directory = opendir("/sys/block/");
|
|
if (directory == NULL) {
|
|
warnx("Error: could not open directory /sys/block");
|
|
return -1;
|
|
}
|
|
|
|
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
|
if (!readbuf) {
|
|
warnx("Error: Not enough memory to allocate readbuffer");
|
|
return -1;
|
|
}
|
|
|
|
while ((dir_entry = readdir(directory)) != NULL) {
|
|
if (util_file_read_line(readbuf, RD_BUFFER_SIZE,
|
|
"/sys/block/%s/dev",
|
|
dir_entry->d_name) < 0)
|
|
continue;
|
|
|
|
if (strncmp(stat_dev, readbuf,
|
|
MAX(strlen(stat_dev), strlen(readbuf) - 1)) == 0) {
|
|
rc = snprintf(*uidfile, RD_BUFFER_SIZE,
|
|
"/sys/block/%s/device/uid",
|
|
dir_entry->d_name);
|
|
if (rc >= RD_BUFFER_SIZE) {
|
|
fprintf(stderr,
|
|
"Error: Device name was truncated\n");
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
closedir(directory);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct utsname uname_buf;
|
|
int version, release;
|
|
char *uidfile = NULL;
|
|
char *device = NULL;
|
|
char *readbuf = NULL;
|
|
dev_t dev;
|
|
int export = 0;
|
|
int c;
|
|
int print_uid = 0;
|
|
int print_extended_uid = 0;
|
|
int print_vlabel = 0;
|
|
char *blockdev = NULL;
|
|
char *busid = NULL;
|
|
char *devnode = NULL;
|
|
struct volume_label vlabel;
|
|
char *srchuid;
|
|
int i, rc = 0;
|
|
|
|
util_prg_init(&prg);
|
|
util_opt_init(opt_vec, NULL);
|
|
|
|
while (1) {
|
|
c = util_opt_getopt_long(argc, argv);
|
|
if (c == -1)
|
|
break;
|
|
|
|
switch (c) {
|
|
case 'a':
|
|
print_uid = 1;
|
|
print_vlabel = 1;
|
|
print_extended_uid = 1;
|
|
break;
|
|
case 'u':
|
|
print_uid = 1;
|
|
break;
|
|
case 'x':
|
|
print_extended_uid = 1;
|
|
break;
|
|
case 'l':
|
|
print_vlabel = 1;
|
|
break;
|
|
case 'i':
|
|
busid = strdup(optarg);
|
|
break;
|
|
case 'b':
|
|
blockdev = strdup(optarg);
|
|
break;
|
|
case 'd':
|
|
devnode = strdup(optarg);
|
|
break;
|
|
case 'e':
|
|
export = 1;
|
|
break;
|
|
case 'h':
|
|
util_prg_print_help();
|
|
util_opt_print_help();
|
|
exit(EXIT_SUCCESS);
|
|
case 'v':
|
|
util_prg_print_version();
|
|
exit(EXIT_SUCCESS);
|
|
default:
|
|
fprintf(stderr, "Try 'dasdinfo --help' for more "
|
|
"information.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
uname(&uname_buf);
|
|
sscanf(uname_buf.release, "%d.%d", &version, &release);
|
|
if (strcmp(uname_buf.sysname, "Linux") ||
|
|
version < 2 || (version == 2 && release < 6)) {
|
|
warnx("%s %d.%d is not supported", uname_buf.sysname,
|
|
version, release);
|
|
exit(1);
|
|
}
|
|
|
|
if (!busid && !blockdev && !devnode) {
|
|
warnx("Error: please specify a device using either -b, -i or -d");
|
|
exit(1);
|
|
}
|
|
|
|
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode)) {
|
|
warnx("Error: please specify device only once, either -b, -i or -d");
|
|
exit(1);
|
|
}
|
|
|
|
if (!print_uid && !print_extended_uid && !print_vlabel) {
|
|
warnx("Error: no action specified (e.g. -u)");
|
|
exit(1);
|
|
}
|
|
|
|
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
|
uidfile = dinfo_malloc(RD_BUFFER_SIZE);
|
|
if (!(readbuf && uidfile))
|
|
exit(1);
|
|
|
|
/* try to read the uid attribute */
|
|
if (busid) {
|
|
sprintf(uidfile, "/sys/bus/ccw/devices/%s/uid", busid);
|
|
} else if (blockdev) {
|
|
sprintf(uidfile, "/sys/block/%s/device/uid", blockdev);
|
|
} else if (devnode) {
|
|
if (dinfo_get_uid_from_devnode(&uidfile, devnode) != 0)
|
|
goto error;
|
|
}
|
|
|
|
if (export) {
|
|
printf("ID_BUS=ccw\n");
|
|
printf("ID_TYPE=disk\n");
|
|
}
|
|
|
|
if (print_uid) {
|
|
if (dinfo_read_dasd_uid(uidfile, readbuf) == 0) {
|
|
/* look for the 4th '.' and cut there */
|
|
srchuid = readbuf - 1;
|
|
for (i = 0; i < 4; ++i) {
|
|
srchuid = index(srchuid + 1, '.');
|
|
if (!srchuid)
|
|
break;
|
|
}
|
|
if (srchuid)
|
|
srchuid[0] = '\0';
|
|
if (export)
|
|
printf("ID_UID=%s\n", readbuf);
|
|
else
|
|
printf("%s\n", readbuf);
|
|
if (!print_vlabel && !print_extended_uid)
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (print_extended_uid) {
|
|
if (dinfo_read_dasd_uid(uidfile, readbuf) == 0) {
|
|
if (export)
|
|
printf("ID_XUID=%s\n", readbuf);
|
|
else
|
|
printf("%s\n", readbuf);
|
|
if (!print_vlabel)
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* there is no uid, try to read the volume serial */
|
|
if (busid) {
|
|
char *blockdev_name = NULL;
|
|
|
|
if (dinfo_get_blockdev_from_busid(busid, &blockdev_name) != 0)
|
|
goto error;
|
|
|
|
if (dinfo_get_dev_from_blockdev(blockdev_name, &dev) != 0)
|
|
goto error;
|
|
|
|
if (dinfo_create_devnode(dev, &device) != 0)
|
|
goto error;
|
|
|
|
free(blockdev_name);
|
|
|
|
} else if (blockdev) {
|
|
if (dinfo_get_dev_from_blockdev(blockdev, &dev) != 0)
|
|
goto error;
|
|
|
|
if (dinfo_create_devnode(dev, &device) != 0)
|
|
goto error;
|
|
|
|
} else if (devnode) {
|
|
device = dinfo_malloc(RD_BUFFER_SIZE);
|
|
if (!device)
|
|
exit(1);
|
|
strcpy(device, devnode);
|
|
}
|
|
|
|
if (dinfo_read_dasd_vlabel(device, &vlabel, readbuf) == 0) {
|
|
if (export)
|
|
printf("ID_SERIAL=%s\n", readbuf);
|
|
else
|
|
printf("%s\n", readbuf);
|
|
goto out;
|
|
}
|
|
|
|
error:
|
|
warnx("Error: could not read unique DASD ID");
|
|
rc = 1;
|
|
|
|
out:
|
|
if (device && (busid || blockdev))
|
|
dinfo_free_devnode(device);
|
|
|
|
free(uidfile);
|
|
free(device);
|
|
free(readbuf);
|
|
|
|
exit(rc);
|
|
}
|