mirror of
https://github.com/AuxXxilium/eudev.git
synced 2025-01-27 01:20:00 +07:00
path_id: implement in C using libudev
This commit is contained in:
parent
4950b6e6a8
commit
185ea6a76d
1
TODO
1
TODO
@ -1,4 +1,5 @@
|
||||
|
||||
o kill path_id.sh (add fc, sas, iscsi to C version)
|
||||
o add tests for kernel provided DEVNAME logic
|
||||
o drop modprobe floppy alias (SUSE), it will be in the module (2.6.30)
|
||||
o remove MMC rules, they got a modalias now (2.6.30)
|
||||
|
1
extras/path_id/.gitignore
vendored
Normal file
1
extras/path_id/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
path_id
|
@ -2,7 +2,19 @@ include $(top_srcdir)/Makefile.am.inc
|
||||
|
||||
udevhomedir = $(udev_prefix)/lib/udev
|
||||
dist_udevhome_SCRIPTS = \
|
||||
path_id.sh
|
||||
|
||||
udevhome_PROGRAMS = \
|
||||
path_id
|
||||
|
||||
path_id_SOURCES = \
|
||||
path_id.c \
|
||||
../../udev/lib/libudev.h \
|
||||
../../udev/lib/libudev.c \
|
||||
../../udev/lib/libudev-device.c \
|
||||
../../udev/lib/libudev-enumerate.c \
|
||||
../../udev/lib/libudev-list.c \
|
||||
../../udev/lib/libudev-util.c
|
||||
|
||||
dist_man_MANS = \
|
||||
path_id.8
|
||||
|
365
extras/path_id/path_id.c
Normal file
365
extras/path_id/path_id.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* compose persisistent device path
|
||||
*
|
||||
* Copyright (C) 2009 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
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <libudev.h>
|
||||
#include <../../udev/udev.h>
|
||||
|
||||
int debug;
|
||||
|
||||
static void log_fn(struct udev *udev, int priority,
|
||||
const char *file, int line, const char *fn,
|
||||
const char *format, va_list args)
|
||||
{
|
||||
if (debug) {
|
||||
fprintf(stderr, "%s: ", fn != NULL ? fn : file);
|
||||
vfprintf(stderr, format, args);
|
||||
} else {
|
||||
vsyslog(priority, format, args);
|
||||
}
|
||||
}
|
||||
|
||||
static int path_prepend(char **path, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char *old;
|
||||
char *pre;
|
||||
int err;
|
||||
|
||||
old = *path;
|
||||
|
||||
va_start(va, fmt);
|
||||
err = vasprintf(&pre, fmt, va);
|
||||
va_end(va);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (old != NULL) {
|
||||
err = asprintf(path, "%s-%s", pre, old);
|
||||
if (err < 0)
|
||||
return err;
|
||||
free(pre);
|
||||
} else {
|
||||
*path = pre;
|
||||
}
|
||||
|
||||
free(old);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys)
|
||||
{
|
||||
struct udev_device *parent = dev;
|
||||
|
||||
while (parent != NULL) {
|
||||
const char *subsystem;
|
||||
|
||||
subsystem = udev_device_get_subsystem(parent);
|
||||
if (subsystem == NULL || strcmp(subsystem, subsys) != 0)
|
||||
break;
|
||||
dev = parent;
|
||||
parent = udev_device_get_parent(parent);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* find smallest number of instances of <syspath>/<name><number> */
|
||||
static int base_number(const char *syspath, const char *name)
|
||||
{
|
||||
char *base;
|
||||
char *pos;
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
size_t len;
|
||||
int number = -1;
|
||||
|
||||
base = strdup(syspath);
|
||||
if (base == NULL)
|
||||
goto out;
|
||||
|
||||
pos = strrchr(base, '/');
|
||||
if (pos == NULL)
|
||||
goto out;
|
||||
pos[0] = '\0';
|
||||
|
||||
len = strlen(name);
|
||||
dir = opendir(base);
|
||||
if (dir == NULL)
|
||||
goto out;
|
||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
||||
char *rest;
|
||||
int i;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
if (dent->d_type != DT_DIR && dent->d_type != DT_LNK)
|
||||
continue;
|
||||
if (strncmp(dent->d_name, name, len) != 0)
|
||||
continue;
|
||||
i = strtoul(&dent->d_name[len], &rest, 10);
|
||||
if (rest[0] != '\0')
|
||||
continue;
|
||||
if (number == -1 || i < number)
|
||||
number = i;
|
||||
}
|
||||
closedir(dir);
|
||||
out:
|
||||
free(base);
|
||||
return number;
|
||||
}
|
||||
|
||||
static struct udev_device *handle_scsi(struct udev_device *dev, char **path)
|
||||
{
|
||||
const char *devtype;
|
||||
struct udev_device *hostdev;
|
||||
const char *name;
|
||||
int host, bus, target, lun;
|
||||
int base;
|
||||
|
||||
devtype = udev_device_get_devtype(dev);
|
||||
if (devtype == NULL || strcmp(devtype, "scsi_device") != 0)
|
||||
return dev;
|
||||
|
||||
hostdev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_host");
|
||||
if (hostdev == NULL)
|
||||
return dev;
|
||||
|
||||
name = udev_device_get_sysname(dev);
|
||||
if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4)
|
||||
return dev;
|
||||
|
||||
/* rebase host offset to get the local relative number */
|
||||
base = base_number(udev_device_get_syspath(hostdev), "host");
|
||||
if (base < 0)
|
||||
return dev;
|
||||
host -= base;
|
||||
|
||||
path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun);
|
||||
dev = skip_subsystem(dev, "scsi");
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void handle_scsi_tape(struct udev_device *dev, char **suffix)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = udev_device_get_sysname(dev);
|
||||
if (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL)
|
||||
asprintf(suffix, "nst%c", name[3]);
|
||||
else if (strncmp(name, "st", 2) == 0 && strchr("lma", name[2]) != NULL)
|
||||
asprintf(suffix, "st%c", name[2]);
|
||||
}
|
||||
|
||||
static struct udev_device *handle_usb(struct udev_device *dev, char **path)
|
||||
{
|
||||
const char *devtype;
|
||||
const char *str;
|
||||
const char *port;
|
||||
|
||||
devtype = udev_device_get_devtype(dev);
|
||||
if (devtype == NULL || strcmp(devtype, "usb_interface") != 0)
|
||||
return dev;
|
||||
|
||||
str = udev_device_get_sysname(dev);
|
||||
port = strchr(str, '-');
|
||||
if (port == NULL)
|
||||
return dev;
|
||||
port++;
|
||||
|
||||
dev = skip_subsystem(dev, "usb");
|
||||
path_prepend(path, "usb-0:%s", port);
|
||||
return dev;
|
||||
}
|
||||
|
||||
static struct udev_device *handle_firewire(struct udev_device *parent, struct udev_device *dev, char **path)
|
||||
{
|
||||
struct udev_device *scsi_dev;
|
||||
|
||||
scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
|
||||
if (scsi_dev != NULL) {
|
||||
const char *id;
|
||||
|
||||
id = udev_device_get_sysattr_value(scsi_dev, "ieee1394_id");
|
||||
if (id != NULL)
|
||||
path_prepend(path, "ieee1394-0x%s", id);
|
||||
}
|
||||
|
||||
parent = skip_subsystem(parent, "firewire");
|
||||
return parent;
|
||||
}
|
||||
|
||||
static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path)
|
||||
{
|
||||
struct udev_device *scsi_dev;
|
||||
|
||||
scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
|
||||
if (scsi_dev != NULL) {
|
||||
const char *wwpn;
|
||||
const char *lun;
|
||||
const char *hba_id;
|
||||
|
||||
hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id");
|
||||
wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn");
|
||||
lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun");
|
||||
if (hba_id != NULL && lun != NULL && wwpn != NULL) {
|
||||
path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
path_prepend(path, "ccw-%s", udev_device_get_sysname(parent));
|
||||
out:
|
||||
parent = skip_subsystem(parent, "ccw");
|
||||
return parent;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static const struct option options[] = {
|
||||
{ "debug", no_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{}
|
||||
};
|
||||
struct udev *udev;
|
||||
struct udev_device *dev;
|
||||
struct udev_device *parent;
|
||||
char syspath[UTIL_PATH_SIZE];
|
||||
const char *devpath;
|
||||
char *path;
|
||||
char *path_suffix;
|
||||
int rc = 1;
|
||||
|
||||
udev = udev_new();
|
||||
if (udev == NULL)
|
||||
goto exit;
|
||||
|
||||
logging_init("usb_id");
|
||||
udev_set_log_fn(udev, log_fn);
|
||||
|
||||
while (1) {
|
||||
int option;
|
||||
|
||||
option = getopt_long(argc, argv, "dh", options, NULL);
|
||||
if (option == -1)
|
||||
break;
|
||||
|
||||
switch (option) {
|
||||
case 'd':
|
||||
debug = 1;
|
||||
if (udev_get_log_priority(udev) < LOG_INFO)
|
||||
udev_set_log_priority(udev, LOG_INFO);
|
||||
break;
|
||||
case 'h':
|
||||
printf("Usage: path_id [--debug] [--help] <devpath>\n"
|
||||
" --debug print debug information\n"
|
||||
" --help print this help text\n\n");
|
||||
default:
|
||||
rc = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
devpath = argv[optind];
|
||||
if (devpath == NULL) {
|
||||
fprintf(stderr, "No device specified\n");
|
||||
rc = 2;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
|
||||
dev = udev_device_new_from_syspath(udev, syspath);
|
||||
if (dev == NULL) {
|
||||
fprintf(stderr, "unable to access '%s'\n", devpath);
|
||||
rc = 3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
path = NULL;
|
||||
path_suffix = NULL;
|
||||
|
||||
parent = dev;
|
||||
while (parent != NULL) {
|
||||
const char *subsys;
|
||||
|
||||
subsys = udev_device_get_subsystem(parent);
|
||||
|
||||
if (subsys == NULL) {
|
||||
;
|
||||
} else if (strcmp(subsys, "scsi_tape") == 0) {
|
||||
handle_scsi_tape(parent, &path_suffix);
|
||||
} else if (strcmp(subsys, "scsi") == 0) {
|
||||
parent = handle_scsi(parent, &path);
|
||||
} else if (strcmp(subsys, "fc_transport") == 0) {
|
||||
; //handle_fc();
|
||||
} else if (strcmp(subsys, "sas_end_device") == 0) {
|
||||
; //handle_sas();
|
||||
} else if (strcmp(subsys, "iscsi_session") == 0) {
|
||||
; //handle_iscsi()
|
||||
} else if (strcmp(subsys, "ccw") == 0) {
|
||||
handle_ccw(parent, dev, &path);
|
||||
} else if (strcmp(subsys, "cciss") == 0) {
|
||||
; //handle_cciss();
|
||||
} else if (strcmp(subsys, "usb") == 0) {
|
||||
parent = handle_usb(parent, &path);
|
||||
} else if (strcmp(subsys, "serio") == 0) {
|
||||
path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent));
|
||||
parent = skip_subsystem(parent, "serio");
|
||||
} else if (strcmp(subsys, "firewire") == 0 || strcmp(subsys, "ieee1394") == 0) {
|
||||
parent = handle_firewire(parent, dev, &path);
|
||||
} else if (strcmp(subsys, "pci") == 0) {
|
||||
path_prepend(&path, "pci-%s", udev_device_get_sysname(parent));
|
||||
parent = skip_subsystem(parent, "pci");
|
||||
} else if (strcmp(subsys, "platform") == 0) {
|
||||
path_prepend(&path, "platform-%s", udev_device_get_sysname(parent));
|
||||
parent = skip_subsystem(parent, "platform");
|
||||
} else if (strcmp(subsys, "xen") == 0) {
|
||||
path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
|
||||
parent = skip_subsystem(parent, "xen");
|
||||
}
|
||||
|
||||
parent = udev_device_get_parent(parent);
|
||||
}
|
||||
|
||||
if (path != NULL) {
|
||||
if (path_suffix != NULL) {
|
||||
printf("ID_PATH=%s%s\n", path, path_suffix);
|
||||
free(path_suffix);
|
||||
} else {
|
||||
printf("ID_PATH=%s\n", path);
|
||||
}
|
||||
free(path);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
udev_device_unref(dev);
|
||||
exit:
|
||||
udev_unref(udev);
|
||||
logging_close();
|
||||
return rc;
|
||||
}
|
@ -17,7 +17,7 @@ KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$en
|
||||
KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst"
|
||||
|
||||
# by-path (parent device path)
|
||||
KERNEL=="st*[0-9]|nst*[0-9]", IMPORT{program}="path_id %p"
|
||||
KERNEL=="st*[0-9]|nst*[0-9]", IMPORT{program}="path_id.sh %p"
|
||||
KERNEL=="st*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}"
|
||||
KERNEL=="nst*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}"
|
||||
|
||||
|
@ -47,7 +47,9 @@ KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=
|
||||
KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
|
||||
|
||||
# by-path (parent device path)
|
||||
ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{program}="path_id %p"
|
||||
# old shell script for fc, sas, iscsi, s390, ide
|
||||
ENV{DEVTYPE}=="disk", DEVPATH=="*/css0/*|*/rport-[0-9]*|*/end_device-*|*/session[0-9]*|*/ide[0-9]*", IMPORT{program}="path_id.sh %p"
|
||||
ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="", DEVPATH!="*/virtual/*", IMPORT{program}="path_id %p"
|
||||
ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
|
||||
ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user