[PATCH] udev_volume_id update

Here is a update to extras/volume_id/*

o The device is now specified by the DEVPATH in the environment,
  it's no longer needed to pass the major/minor to the callout.

o leading spaces and slashes are now removed from the returned string
  and spaces are replaced by underscore, to not to confuse udev.

o Arnd Bergmann <arnd@arndb.de> provided the code to recognize s390
  dasd disk labels. The -d switch tries to read the main block device
  instead of the partition.
This commit is contained in:
kay.sievers@vrfy.org 2004-05-12 00:52:52 -07:00 committed by Greg KH
parent 7f639ff99e
commit cde5a756ce
7 changed files with 437 additions and 51 deletions

View File

@ -1,6 +1,6 @@
# Makefile for udev_volume_id
#
# Copyright (C) 2004 Kay Sievers <kay@vrfy.org>
# Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -29,8 +29,19 @@ INSTALL_DATA = ${INSTALL} -m 644
INSTALL_SCRIPT = ${INSTALL_PROGRAM}
override CFLAGS+=-Wall -fno-builtin
OBJS = volume_id.o udev_volume_id.o
HEADERS = volume_id.h
SYSFS = ../../libsysfs/sysfs_bus.o \
../../libsysfs/sysfs_class.o \
../../libsysfs/sysfs_device.o \
../../libsysfs/sysfs_dir.o \
../../libsysfs/sysfs_driver.o \
../../libsysfs/sysfs_utils.o \
../../libsysfs/dlist.o
OBJS = volume_id.o udev_volume_id.o dasdlabel.o $(SYSFS)
HEADERS = volume_id.h dasdlabel.h
$(OBJS): $(HEADERS)

49
extras/volume_id/README Normal file
View File

@ -0,0 +1,49 @@
udev_volume_id - partition, filesystem, disklabel reader
This program is normally called from a udev rule, to provide udev with the
name, uuid or the filesystem type of a partition to name a device node.
udev_volume_id opens the blockdevice specified by the environment variable
DEVPATH and searches for a filesystem superblock to read the label. The
following commandline switches are supported to specify what udev_volume_id
should print to stdout:
no option prints all values
-h prints help text
-l prints the label of the partition
-u prints the uuid of the partition
-d read disk instead of partition
If -d is specified udev_volume_id tries to read the label from the main
block device where the partition belongs to. For now this is only useful
for s390 dasd labels.
udev_volume_id will only return successful if the string asked for, is not
empty. All trailing whitespace will be removed, spaces replaced by underscore
and slashes ignored.
The following rule will create a symlink named with the label string:
KERNEL="[hs]d*", PROGRAM="/sbin/udev_volume_id -l", SYMLINK="%c"
If no label is found udev_volume_id exits with nonzero and the rule will be
ignored.
To give it a try, you may call it on the commandline:
[root@pim udev.kay]# DEVPATH=/block/hda/hda3 extras/volume_id/udev_volume_id
T:ext3
L:Music Store
N:Music_Store
U:d2da42b5-bbd9-44eb-a72c-cc4542fcb71e
[root@pim udev.kay]# DEVPATH=/block/hda/hda3 extras/volume_id/udev_volume_id -l
Music_Store
[root@pim udev.kay]# DEVPATH=/block/hda/hda1 extras/volume_id/udev_volume_id -t
swap
Please send any comment/questions/concerns to me or:
linux-hotplug-devel@lists.sourceforge.net
Kay Sievers <kay.sievers@vrfy.org>

View File

@ -0,0 +1,178 @@
/*
* dasdlabel - read label from s390 block device
*
* Copyright (C) 2004 Arnd Bergmann <arnd@arndb.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "dasdlabel.h"
static unsigned 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
-ENP ->LF */
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
-IUS */
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
-INP */
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
-SW */
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 void vtoc_ebcdic_dec (unsigned char *source, unsigned char *target, int l)
{
int i;
for (i = 0; i < l; i++)
target[i]=EBCtoASC[(unsigned char)(source[i])];
}
/*
* struct dasd_information_t
* represents any data about the data, which is visible to userspace
*/
typedef struct dasd_information_t {
unsigned int devno; /* S/390 devno */
unsigned int real_devno; /* for aliases */
unsigned int schid; /* S/390 subchannel identifier */
unsigned int cu_type : 16; /* from SenseID */
unsigned int cu_model : 8; /* from SenseID */
unsigned int dev_type : 16; /* from SenseID */
unsigned int dev_model : 8; /* from SenseID */
unsigned int open_count;
unsigned int req_queue_len;
unsigned int chanq_len; /* length of chanq */
char type[4]; /* from discipline.name, 'none' for unknown */
unsigned int status; /* current device level */
unsigned int label_block; /* where to find the VOLSER */
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
unsigned int characteristics_size;
unsigned int confdata_size;
char characteristics[64]; /* from read_device_characteristics */
char configuration_data[256]; /* from read_configuration_data */
} dasd_information_t;
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
#define _IOC_SIZEBITS 14
#define _IOC_DIRBITS 2
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
#define _IOC_NRSHIFT 0
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
#define DASD_IOCTL_LETTER 'D'
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
#define BLKSSZGET _IO(0x12,104)
int probe_ibm_partition(int fd, char *out)
{
int blocksize;
dasd_information_t info;
char name[7] = {0,};
unsigned char data[16];
if (ioctl(fd, BIODASDINFO, (unsigned long)&info) != 0)
return -1;
if (ioctl(fd, BLKSSZGET, (unsigned long)&blocksize))
return -1;
lseek(fd, info.label_block * blocksize, SEEK_SET);
if (read(fd, &data, 16) != 16)
return -1;
if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
strncpy(name, data + 8, 6);
else
strncpy(name, data + 4, 6);
vtoc_ebcdic_dec(name, out, 6);
return 0;
}

View File

@ -0,0 +1,26 @@
/*
* dasdlabel - read label from s390 block device
*
* Copyright (C) 2004 Arnd Bergmann <arnd@arndb.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _DASDLABEL_H_
#define _DASDLABEL_H_
extern int probe_ibm_partition(int fd, char *out);
#endif

View File

@ -0,0 +1,7 @@
# s390 block devices named by disk label
KERNEL="dasd*[a-z]", PROGRAM="/sbin/udev_volume_id -d -l" RESULT="[0-9A-Z]*", SYMLINK="dasd/%c/disc dasd/%b/disc"
KERNEL="dasd*[0-9]", PROGRAM="/sbin/udev_volume_id -d -l" RESULT="[0-9A-Z]*", SYMLINK="dasd/%c/part%n dasd/%b/part%n"
KERNEL="dasd*[a-z]", SYMLINK="dasd/%b/disc"
KERNEL="dasd*[0-9]", SYMLINK="dasd/%b/part%n"
KERNEL="dcssblk*", NAME="%k", SYMLINK="dcssblk/%b"

View File

@ -4,7 +4,7 @@
* Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
*
* sample udev rule for creation of a symlink with the filsystem uuid:
* KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -M%M -m%m -u", SYMLINK="%c"
* KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -u", SYMLINK="%c"
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -24,21 +24,75 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include "../../libsysfs/sysfs/libsysfs.h"
#include "../../udev_lib.h"
#include "../../logging.h"
#include "volume_id.h"
#include "dasdlabel.h"
#ifdef LOG
unsigned char logname[LOGNAME_SIZE];
void log_message(int level, const char *format, ...)
{
va_list args;
va_start(args, format);
vsyslog(level, format, args);
va_end(args);
}
#endif
static struct volume_id *open_classdev(struct sysfs_class_device *class_dev)
{
struct volume_id *vid;
struct sysfs_attribute *attr;
int major, minor;
attr = sysfs_get_classdev_attr(class_dev, "dev");
if (attr == NULL) {
printf("error reading 'dev' attribute\n");
return NULL;
}
if (sscanf(attr->value, "%u:%u", &major, &minor) != 2) {
printf("error getting major/minor number\n");
return NULL;
}
vid = volume_id_open_dev_t(makedev(major, minor));
if (vid == NULL) {
printf("error open volume\n");
return NULL;
}
return vid;
}
int main(int argc, char *argv[])
{
struct volume_id *vid;
const char help[] = "usage: udev_volume_id -m<minor> -M<major> [-t|-l|-u]\n";
int major = -1;
int minor = -1;
char *tail;
static const char short_options[] = "M:m:htlu";
const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
" -t filesystem type\n"
" -l filesystem label\n"
" -u filesystem uuid\n"
" -d disk label from main device\n"
"\n";
static const char short_options[] = "htlud";
int option;
char print = '\0';
int rc;
char sysfs_path[SYSFS_PATH_MAX];
char dev_path[SYSFS_PATH_MAX];
struct sysfs_class_device *class_dev = NULL;
struct sysfs_class_device *class_dev_parent = NULL;
struct volume_id *vid = NULL;
char *devpath;
char probe = 'p';
char print = 'a';
char dasd_label[7];
static char name[VOLUME_ID_LABEL_SIZE];
int len, i, j;
int rc = 1;
while (1) {
option = getopt(argc, argv, short_options);
@ -46,29 +100,18 @@ int main(int argc, char *argv[])
break;
switch (option) {
case 'M':
major = (int) strtoul(optarg, &tail, 10);
if (tail[0] != '\0') {
printf("invalid major\n");
exit(1);
}
break;
case 'm':
minor = (int) strtoul(optarg, &tail, 10);
if (tail[0] != '\0') {
printf("invalid minor\n");
exit(1);
}
break;
case 't':
print = 't';
break;
continue;
case 'l':
print = 'l';
break;
continue;
case 'u':
print = 'u';
break;
continue;
case 'd':
probe = 'd';
continue;
case 'h':
case '?':
default:
@ -77,44 +120,115 @@ int main(int argc, char *argv[])
}
}
if (major == -1 || minor == -1) {
printf(help);
exit(1);
devpath = getenv("DEVPATH");
if (devpath == NULL) {
printf("error DEVPATH empty\n");
goto exit;
}
vid = volume_id_open_dev_t(makedev(major, minor));
if (vid == NULL) {
printf("error open volume\n");
exit(1);
if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
printf("error getting sysfs mount path\n");
goto exit;
}
rc = volume_id_probe(vid, ALL);
if (rc != 0) {
printf("error probing volume\n");
exit(1);
strfieldcpy(dev_path, sysfs_path);
strfieldcat(dev_path, devpath);
class_dev = sysfs_open_class_device_path(dev_path);
if (class_dev == NULL) {
printf("error getting class device\n");
goto exit;
}
switch(probe) {
case 'p' :
/* open block device */
vid = open_classdev(class_dev);
if (vid == NULL)
goto exit;
if (volume_id_probe(vid, ALL) == 0)
goto print;
break;
case 'd' :
/* if we are on a partition, close it and open main block device */
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent != NULL) {
volume_id_close(vid);
vid = open_classdev(class_dev_parent);
} else {
vid = open_classdev(class_dev_parent);
}
if (vid == NULL)
goto exit;
if (probe_ibm_partition(vid->fd, dasd_label) == 0) {
vid->fs_name = "dasd";
strncpy(vid->label_string, dasd_label, 6);
vid->label_string[6] = '\0';
goto print;
}
break;
}
printf("unknown volume type\n");
goto exit;
print:
len = strnlen(vid->label_string, VOLUME_ID_LABEL_SIZE);
/* remove trailing spaces */
while (len > 0 && isspace(vid->label_string[len-1]))
len--;
name[len] = '\0';
/* substitute chars */
i = 0;
j = 0;
while (j < len) {
switch(vid->label_string[j]) {
case '/' :
break;
case ' ' :
name[i++] = '_';
break;
default :
name[i++] = vid->label_string[j];
}
j++;
}
name[i] = '\0';
switch (print) {
case 't':
printf("%s\n", vid->fs_name);
break;
case 'l':
if (vid->label_string[0] == '\0')
exit(2);
printf("%s\n", vid->label_string);
if (name[0] == '\0') {
rc = 2;
goto exit;
}
printf("%s\n", name);
break;
case 'u':
if (vid->uuid_string[0] == '\0')
exit(2);
if (vid->uuid_string[0] == '\0') {
rc = 2;
goto exit;
}
printf("%s\n", vid->uuid_string);
break;
default:
case 'a':
printf("T:%s\n", vid->fs_name);
printf("L:%s\n", vid->label_string);
printf("N:%s\n", name);
printf("U:%s\n", vid->uuid_string);
}
rc = 0;
volume_id_close(vid);
exit:
if (class_dev != NULL)
sysfs_close_class_device(class_dev);
if (vid != NULL)
volume_id_close(vid);
exit(0);
exit(rc);
}

View File

@ -82,7 +82,7 @@ static void set_label_string(struct volume_id *id, char *buf, int count)
memcpy(id->label_string, buf, count);
/* remove trailing whitespace */
i = strlen(id->label_string);
i = strnlen(id->label_string, count);
while (i--) {
if (! isspace(id->label_string[i]))
break;
@ -839,10 +839,11 @@ struct volume_id *volume_id_open_dev_t(dev_t devt)
char tmp_node[VOLUME_ID_PATH_MAX];
snprintf(tmp_node, VOLUME_ID_PATH_MAX,
"/tmp/volume-%u-%u", major(devt), minor(devt));
"/tmp/volume-%u-%u-%u", getpid(), major(devt), minor(devt));
tmp_node[VOLUME_ID_PATH_MAX] = '\0';
/* create tempory node to open the block device */
unlink(tmp_node);
if (mknod(tmp_node, (S_IFBLK | 0600), devt) != 0)
return NULL;