This makes it easier for consumers to use the individual pieces of information instead of having to parse path_id's output. --- extras/Makefile.am | 1 + extras/fc_id/.gitignore | 1 + extras/fc_id/Makefile.am | 13 +++ extras/fc_id/fc_id.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 286 insertions(+), 0 deletions(-) create mode 100644 extras/fc_id/.gitignore create mode 100644 extras/fc_id/Makefile.am create mode 100644 extras/fc_id/fc_id.c diff --git a/extras/Makefile.am b/extras/Makefile.am index b7c9fe8..5377a8e 100644 --- a/extras/Makefile.am +++ b/extras/Makefile.am @@ -5,6 +5,7 @@ SUBDIRS = \ cdrom_id \ edd_id \ path_id \ + fc_id \ firmware \ collect \ floppy \ diff --git a/extras/fc_id/.gitignore b/extras/fc_id/.gitignore new file mode 100644 index 0000000..1d7d107 --- /dev/null +++ b/extras/fc_id/.gitignore @@ -0,0 +1 @@ +fc_id diff --git a/extras/fc_id/Makefile.am b/extras/fc_id/Makefile.am new file mode 100644 index 0000000..ae90d3c --- /dev/null +++ b/extras/fc_id/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/Makefile.am.inc + +libexec_PROGRAMS = \ + fc_id + +path_id_SOURCES = \ + fc_id.c \ + ../../libudev/libudev.h \ + ../../libudev/libudev.c \ + ../../libudev/libudev-device.c \ + ../../libudev/libudev-enumerate.c \ + ../../libudev/libudev-list.c \ + ../../libudev/libudev-util.c diff --git a/extras/fc_id/fc_id.c b/extras/fc_id/fc_id.c new file mode 100644 index 0000000..d8cb597 --- /dev/null +++ b/extras/fc_id/fc_id.c @@ -0,0 +1,271 @@ +/* + * report Fibre Channel Path Name and Lun + * + * Copyright (C) 2009 Kay Sievers <kay.sievers@xxxxxxxx> + * Copyright 2009 Red Hat, Inc. + * + * 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 "libudev-private.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 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; +} + +static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent) +{ + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; + struct udev_device *fcdev = NULL; + const char *port; + unsigned int lun; + + targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); + if (targetdev == NULL) + return NULL; + + fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); + if (fcdev == NULL) + return NULL; + port = udev_device_get_sysattr_value(fcdev, "port_name"); + if (port == NULL) { + parent = NULL; + goto out; + } + lun = strtoul(udev_device_get_sysnum(parent), NULL, 10); + + printf("ID_PORT_NAME=%s\n", port); + printf("ID_LUN=%08x\n", lun); +out: + udev_device_unref(fcdev); + return parent; +} + +static struct udev_device *handle_scsi_sas(struct udev_device *parent) +{ + return NULL; +} + +static struct udev_device *handle_scsi_iscsi(struct udev_device *parent) +{ + return NULL; +} + +static struct udev_device *handle_scsi(struct udev_device *parent) +{ + const char *devtype; + const char *name; + const char *id; + + devtype = udev_device_get_devtype(parent); + if (devtype == NULL || strcmp(devtype, "scsi_device") != 0) + return parent; + + /* firewire */ + id = udev_device_get_sysattr_value(parent, "ieee1394_id"); + if (id != NULL) { + parent = skip_subsystem(parent, "scsi"); + goto out; + } + + /* lousy scsi sysfs does not have a "subsystem" for the transport */ + name = udev_device_get_syspath(parent); + + if (strstr(name, "/rport-") != NULL) { + parent = handle_scsi_fibre_channel(parent); + goto out; + } + + if (strstr(name, "/end_device-") != NULL) { + parent = handle_scsi_sas(parent); + goto out; + } + + if (strstr(name, "/session") != NULL) { + parent = handle_scsi_iscsi(parent); + goto out; + } + + parent = skip_subsystem(parent, "scsi"); +out: + return parent; +} + +static struct udev_device *handle_cciss(struct udev_device *parent) +{ + return NULL; +} + +static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev) +{ + 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"); + if (hba_id != NULL) + printf("ID_HDA=%s\n", hba_id); + wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn"); + if (wwpn != NULL) + printf("ID_PORT_NAME=%s\n", wwpn); + lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun"); + if (lun != NULL) + printf("ID_LUN=%s\n", lun); + } + + 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; + int rc = 1; + + udev = udev_new(); + if (udev == NULL) + goto exit; + + udev_log_init("fc_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: fc_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; + } + + /* S390 ccw bus */ + parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); + if (parent != NULL) { + handle_ccw(parent, dev); + goto out; + } + + /* walk up the chain of devices and compose path */ + parent = dev; + while (parent != NULL) { + const char *subsys; + + subsys = udev_device_get_subsystem(parent); + + if (subsys == NULL) { + ; + } else if (strcmp(subsys, "scsi") == 0) { + parent = handle_scsi(parent); + } else if (strcmp(subsys, "cciss") == 0) { + handle_cciss(parent); + } else if (strcmp(subsys, "serio") == 0) { + parent = skip_subsystem(parent, "serio"); + } else if (strcmp(subsys, "pci") == 0) { + parent = skip_subsystem(parent, "pci"); + } else if (strcmp(subsys, "platform") == 0) { + parent = skip_subsystem(parent, "platform"); + } else if (strcmp(subsys, "xen") == 0) { + parent = skip_subsystem(parent, "xen"); + } + + parent = udev_device_get_parent(parent); + } +out: + udev_device_unref(dev); +exit: + udev_unref(udev); + udev_log_close(); + return rc; +} -- 1.6.2.2 -- To unsubscribe from this list: send the line "unsubscribe linux-hotplug" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html