mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
include ../common.mak
|
||||
|
||||
libs = $(rootdir)/libu2s/libu2s.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
|
||||
all: dasdinfo
|
||||
|
||||
dasdinfo: dasdinfo.o $(libs)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 dasdinfo $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 dasdinfo.8 \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ dasdinfo core
|
||||
|
||||
.PHONY: all install clean
|
||||
@@ -0,0 +1,97 @@
|
||||
.\" Copyright 2017 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
.TH DASDINFO 8 "Febr 2007" "s390-tools" "Linux Administrator's Manual"
|
||||
.SH NAME
|
||||
.B "dasdinfo "
|
||||
\- tool to read unique id from s390 DASD device
|
||||
.SH SYNOPSIS
|
||||
.BI "dasdinfo [-a] [-l] [-u] [-x] [-e] {-i " <busid>
|
||||
.BI "| -b " <blockdev>
|
||||
.BI " | -d " <devnode>
|
||||
.BI "}"
|
||||
.sp
|
||||
.BI "dasdinfo [-h] [-v]"
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dasdinfo
|
||||
displays specific information about a specified DASD device.
|
||||
It is normally called from a udev rule, to provide udev with a unique id string and
|
||||
additional information (type, serial) for an S390 DASD drive. Udev can use this
|
||||
information to create symlinks in /dev/disk/by-id and /dev/disk/by-label
|
||||
to the real device node.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.BI "-a|--all"
|
||||
Same as -u -x -l
|
||||
.TP
|
||||
.BI "-x|--extended-uid"
|
||||
Print DASD uid
|
||||
|
||||
This option prints the full uid of the DASD. When z/VM provides two
|
||||
virtual devices that are actually located on the same real device, the
|
||||
first four tokens of the uid will be identical for both devices. z/VM
|
||||
may provide an additional token that allows to distinguish between
|
||||
different minidisks. You need both support in the Linux kernel and
|
||||
z/VM to receive such an additional token.
|
||||
|
||||
For z/VM: VM support for the hypervisor injected Special Node Element
|
||||
Qualifier (SNEQ) (or hypervisor injected self-description data) is
|
||||
available by applying the PTFs for VM APAR VM64273 on z/VM 5.2.0 and higher.
|
||||
.TP
|
||||
.BI "-u|--uid"
|
||||
Print DASD uid without z/VM minidisk token
|
||||
|
||||
z/VM may provide an additional token that allows to distinguish
|
||||
between different minidisks (see --extended-uid option). To remain
|
||||
compatibile with systems that were installed on older Linux or z/VM
|
||||
levels, the -u option will print the uid excluding any z/VM-provided
|
||||
minidisk token.
|
||||
|
||||
For example, if the extended uid is
|
||||
IBM.75000000092461.e900.10.00000000000037400000000000000000 then the
|
||||
uid is IBM.75000000092461.e900.10. If the extended uid contains no
|
||||
minidisk token, e.g. in an LPAR environment, then both uids are the
|
||||
same.
|
||||
.TP
|
||||
.BI "-l|--label"
|
||||
Print DASD volume label (volser).
|
||||
.TP
|
||||
.BI "-i|--busid " <busid>
|
||||
Use the bus ID as input parameter, e.g. 0.0.e910.
|
||||
.TP
|
||||
.BI "-b|--block " <blockdev>
|
||||
Use the block device name as input parameter, e.g. dasdb.
|
||||
.TP
|
||||
.BI "-d|--devnode " <devnode>
|
||||
Use a device node as input parameter, e.g. /dev/dasdb.
|
||||
.TP
|
||||
.BI "-e|--export"
|
||||
Print all values (ID_BUS, ID_TYPE, ID_SERIAL).
|
||||
.TP
|
||||
.BI "-h|--help"
|
||||
Print usage text.
|
||||
.TP
|
||||
.BI "-v|--version"
|
||||
Print version number.
|
||||
|
||||
.SH EXAMPLES
|
||||
dasdinfo -u -i 0.0.e910
|
||||
|
||||
dasdinfo -u -b dasdb
|
||||
|
||||
dasdinfo -u -d /dev/dasdb
|
||||
|
||||
All three examples should return the same unique ID for
|
||||
the same DASD device, e.g. IBM.75000000092461.e900.10.
|
||||
|
||||
In case this uid is not available, dasdinfo will return
|
||||
the volume label instead, e.g. 0XE910.
|
||||
.SH SEE ALSO
|
||||
.BR udev (7)
|
||||
.SH AUTHORS
|
||||
Volker Sameske <sameske@de.ibm.com>
|
||||
|
||||
@@ -0,0 +1,837 @@
|
||||
/*
|
||||
* 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/util_base.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define READCHUNK 80
|
||||
#define BLKSSZGET _IO(0x12,104)
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,struct dasd_information)
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,struct dasd_information2)
|
||||
#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));
|
||||
|
||||
struct dasd_information2 {
|
||||
unsigned int devno;
|
||||
unsigned int real_devno;
|
||||
unsigned int schid;
|
||||
unsigned int cu_type : 16;
|
||||
unsigned int cu_model : 8;
|
||||
unsigned int dev_type : 16;
|
||||
unsigned int dev_model : 8;
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len;
|
||||
char type[4];
|
||||
unsigned int status;
|
||||
unsigned int label_block;
|
||||
unsigned int FBA_layout;
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64];
|
||||
char configuration_data[256];
|
||||
unsigned int format;
|
||||
unsigned int features;
|
||||
unsigned int reserved0;
|
||||
unsigned int reserved1;
|
||||
unsigned int reserved2;
|
||||
unsigned int reserved3;
|
||||
unsigned int reserved4;
|
||||
unsigned int reserved5;
|
||||
unsigned int reserved6;
|
||||
unsigned int reserved7;
|
||||
};
|
||||
|
||||
struct dasd_information {
|
||||
unsigned int devno;
|
||||
unsigned int real_devno;
|
||||
unsigned int schid;
|
||||
unsigned int cu_type : 16;
|
||||
unsigned int cu_model : 8;
|
||||
unsigned int dev_type : 16;
|
||||
unsigned int dev_model : 8;
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len;
|
||||
char type[4];
|
||||
unsigned int status;
|
||||
unsigned int label_block;
|
||||
unsigned int FBA_layout;
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64];
|
||||
char configuration_data[256];
|
||||
};
|
||||
|
||||
struct dasd_data
|
||||
{
|
||||
struct dasd_information2 dasd_info;
|
||||
int dasd_info_version;
|
||||
int blksize;
|
||||
};
|
||||
|
||||
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, int readbuflen)
|
||||
{
|
||||
FILE *dasduid;
|
||||
int offset = 0;
|
||||
|
||||
if ((dasduid = fopen(uidfile,"r")) == NULL)
|
||||
return -1;
|
||||
|
||||
while (fgets(readbuf + offset, READCHUNK, dasduid) &&
|
||||
readbuf[strlen(readbuf)-1] != '\n' ) {
|
||||
offset += READCHUNK-1;
|
||||
if ( offset+READCHUNK-1 >= readbuflen ) {
|
||||
readbuf = realloc(readbuf,
|
||||
readbuflen + READCHUNK-1);
|
||||
readbuflen += READCHUNK-1;
|
||||
}
|
||||
}
|
||||
fclose(dasduid);
|
||||
|
||||
if (strlen(readbuf) <= 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dinfo_read_dasd_vlabel (char *device, struct volume_label *vlabel,
|
||||
char *readbuf)
|
||||
{
|
||||
struct dasd_data data;
|
||||
struct volume_label tmp;
|
||||
int vlsize = sizeof(struct volume_label);
|
||||
unsigned long vlabel_start;
|
||||
char vollbl[5];
|
||||
int f;
|
||||
char *space;
|
||||
|
||||
if ((f = open(device, O_RDONLY)) < 0) {
|
||||
printf("Could not open device node.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(f, BLKSSZGET, &data.blksize) != 0) {
|
||||
printf("Unable to figure out block size.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(f, BIODASDINFO2, &data.dasd_info) == 0)
|
||||
data.dasd_info_version = 2;
|
||||
else {
|
||||
if (ioctl(f, BIODASDINFO, &data.dasd_info) != 0) {
|
||||
printf("Unable to figure out DASD informations.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
vlabel_start = data.dasd_info.label_block * data.blksize;
|
||||
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
||||
goto error;
|
||||
|
||||
bzero(vlabel, vlsize);
|
||||
|
||||
if (read(f, vlabel, vlsize) != vlsize) {
|
||||
printf("Could not read volume label.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (data.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(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *dinfo_malloc(size_t size)
|
||||
{
|
||||
void *result;
|
||||
|
||||
result = malloc(size);
|
||||
if (result == NULL) {
|
||||
printf("Could not allocate %lld bytes of memory",
|
||||
(unsigned long long) 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 < sizeof(pathname) / sizeof(pathname[0]); 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);
|
||||
}
|
||||
}
|
||||
printf("Error: Unable to create temporary device node");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dinfo_free_devnode(char *device)
|
||||
{
|
||||
if (remove(device)) {
|
||||
printf("Warning: Could not remove "
|
||||
"temporary file %s", device);
|
||||
}
|
||||
}
|
||||
|
||||
static int dinfo_extract_dev(dev_t *dev, char *str, int readbuflen)
|
||||
{
|
||||
char tmp[readbuflen];
|
||||
char *p = NULL;
|
||||
int ma, mi;
|
||||
|
||||
bzero(tmp, readbuflen);
|
||||
strncpy(tmp, str, readbuflen);
|
||||
if ((p = strchr(tmp, ':')) == NULL) {
|
||||
printf("Error: unable to extract major/minor\n");
|
||||
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)
|
||||
{
|
||||
FILE *dasddev;
|
||||
int offset = 0;
|
||||
char *devfile = NULL;
|
||||
char *readbuf = NULL;
|
||||
int readbuflen = READCHUNK;
|
||||
|
||||
if ((devfile = dinfo_malloc(readbuflen)) == NULL)
|
||||
return -1;
|
||||
|
||||
sprintf(devfile,"/sys/block/%s/dev", blockdev);
|
||||
|
||||
if ((readbuf = dinfo_malloc(readbuflen)) == NULL) {
|
||||
printf("Error: Not enough memory to allocate readbuffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((dasddev = fopen(devfile,"r")) == NULL)
|
||||
return -1;
|
||||
|
||||
while (fgets(readbuf + offset, READCHUNK, dasddev) &&
|
||||
readbuf[strlen(readbuf)-1] != '\n' ) {
|
||||
offset += READCHUNK-1;
|
||||
if (offset+READCHUNK-1 >= readbuflen) {
|
||||
readbuf = realloc(readbuf,
|
||||
readbuflen + READCHUNK-1);
|
||||
readbuflen += READCHUNK-1;
|
||||
}
|
||||
}
|
||||
fclose(dasddev);
|
||||
|
||||
if (dinfo_extract_dev(dev, readbuf, readbuflen) != 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[READCHUNK];
|
||||
char sys_dev_path[READCHUNK];
|
||||
char *readbuf;
|
||||
DIR *directory = NULL;
|
||||
struct dirent *dir_entry = NULL;
|
||||
FILE *block_dev;
|
||||
int readbuflen = READCHUNK;
|
||||
int offset;
|
||||
|
||||
if (stat(devnode, &stat_buffer) != 0) {
|
||||
printf("Error: could not stat %s\n", devnode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(stat_dev, "%d:%d", major(stat_buffer.st_rdev),
|
||||
minor(stat_buffer.st_rdev));
|
||||
|
||||
if ((directory = opendir("/sys/block/")) == NULL) {
|
||||
printf("Error: could not open directory /sys/block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((readbuf = dinfo_malloc(readbuflen)) == NULL) {
|
||||
printf("Error: Not enough memory to allocate readbuffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((dir_entry = readdir(directory)) != NULL) {
|
||||
sprintf(sys_dev_path, "/sys/block/%s/dev", dir_entry->d_name);
|
||||
|
||||
if ((block_dev = fopen(sys_dev_path,"r")) == NULL)
|
||||
continue;
|
||||
|
||||
offset = 0;
|
||||
while (fgets(readbuf + offset, READCHUNK, block_dev) &&
|
||||
readbuf[strlen(readbuf)-1] != '\n' ) {
|
||||
offset += READCHUNK-1;
|
||||
if ( offset+READCHUNK-1 >= readbuflen ) {
|
||||
readbuf = realloc(readbuf,
|
||||
readbuflen + READCHUNK-1);
|
||||
readbuflen += READCHUNK-1;
|
||||
}
|
||||
}
|
||||
fclose(block_dev);
|
||||
|
||||
if (strncmp(stat_dev, readbuf,
|
||||
MAX(strlen(stat_dev), strlen(readbuf)-1)) == 0) {
|
||||
sprintf(*uidfile,"/sys/block/%s/device/uid",
|
||||
dir_entry->d_name);
|
||||
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;
|
||||
int readbuflen = READCHUNK;
|
||||
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)) {
|
||||
printf("%s %d.%d is not supported\n", uname_buf.sysname,
|
||||
version,release);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!busid && !blockdev && !devnode) {
|
||||
printf("Error: please specify a device using either -b, -i "
|
||||
"or -d\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode)) {
|
||||
printf("Error: please specify device only once, either -b, -i "
|
||||
"or -d\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!print_uid && !print_extended_uid && !print_vlabel) {
|
||||
printf("Error: no action specified (e.g. -u)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (((readbuf = dinfo_malloc(readbuflen)) == NULL) ||
|
||||
((uidfile = dinfo_malloc(readbuflen)) == NULL))
|
||||
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, readbuflen) == 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] = '\n';
|
||||
srchuid[1] = 0;
|
||||
}
|
||||
if (export) {
|
||||
printf("ID_UID=%s",readbuf);
|
||||
} else
|
||||
printf("%s",readbuf);
|
||||
if (!print_vlabel && !print_extended_uid)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (print_extended_uid) {
|
||||
if (dinfo_read_dasd_uid(uidfile, readbuf, readbuflen) == 0) {
|
||||
if (export) {
|
||||
printf("ID_XUID=%s",readbuf);
|
||||
} else
|
||||
printf("%s",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) {
|
||||
if ((device = dinfo_malloc(readbuflen)) == NULL)
|
||||
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:
|
||||
printf("Error: could not read unique DASD ID\n");
|
||||
rc = 1;
|
||||
|
||||
out:
|
||||
if (device && (busid || blockdev))
|
||||
dinfo_free_devnode(device);
|
||||
|
||||
free(uidfile);
|
||||
free(device);
|
||||
free(readbuf);
|
||||
|
||||
exit(rc);
|
||||
}
|
||||
Reference in New Issue
Block a user