]>
git.ipfire.org Git - thirdparty/systemd.git/blob - extras/path_id/path_id.c
2 * compose persistent device path
4 * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org>
6 * Logic based on Hannes Reinecke's shell script.
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include "libudev-private.h"
38 static void log_fn(struct udev
*udev
, int priority
,
39 const char *file
, int line
, const char *fn
,
40 const char *format
, va_list args
)
43 fprintf(stderr
, "%s: ", fn
!= NULL
? fn
: file
);
44 vfprintf(stderr
, format
, args
);
46 vsyslog(priority
, format
, args
);
50 static int path_prepend(char **path
, const char *fmt
, ...)
60 err
= vasprintf(&pre
, fmt
, va
);
66 err
= asprintf(path
, "%s-%s", pre
, old
);
78 static struct udev_device
*skip_subsystem(struct udev_device
*dev
, const char *subsys
)
80 struct udev_device
*parent
= dev
;
82 while (parent
!= NULL
) {
83 const char *subsystem
;
85 subsystem
= udev_device_get_subsystem(parent
);
86 if (subsystem
== NULL
|| strcmp(subsystem
, subsys
) != 0)
89 parent
= udev_device_get_parent(parent
);
94 static struct udev_device
*handle_scsi_fibre_channel(struct udev_device
*parent
, char **path
)
96 struct udev
*udev
= udev_device_get_udev(parent
);
97 struct udev_device
*targetdev
;
98 struct udev_device
*fcdev
= NULL
;
102 targetdev
= udev_device_get_parent_with_subsystem_devtype(parent
, "scsi", "scsi_target");
103 if (targetdev
== NULL
)
106 fcdev
= udev_device_new_from_subsystem_sysname(udev
, "fc_transport", udev_device_get_sysname(targetdev
));
109 port
= udev_device_get_sysattr_value(fcdev
, "port_name");
115 lun
= strtoul(udev_device_get_sysnum(parent
), NULL
, 10);
116 path_prepend(path
, "fc-%s:0x%04x%04x00000000", port
, lun
& 0xffff, (lun
>> 16) & 0xffff);
118 udev_device_unref(fcdev
);
122 static struct udev_device
*handle_scsi_sas(struct udev_device
*parent
, char **path
)
127 static struct udev_device
*handle_scsi_iscsi(struct udev_device
*parent
, char **path
)
129 struct udev
*udev
= udev_device_get_udev(parent
);
130 struct udev_device
*transportdev
;
131 struct udev_device
*sessiondev
= NULL
;
134 struct udev_device
*conndev
= NULL
;
138 /* find iscsi session */
139 transportdev
= parent
;
141 transportdev
= udev_device_get_parent(transportdev
);
142 if (transportdev
== NULL
)
144 if (strncmp(udev_device_get_sysname(transportdev
), "session", 7) == 0)
147 if (transportdev
== NULL
)
150 /* find iscsi session device */
151 sessiondev
= udev_device_new_from_subsystem_sysname(udev
, "iscsi_session", udev_device_get_sysname(transportdev
));
152 if (sessiondev
== NULL
)
154 target
= udev_device_get_sysattr_value(sessiondev
, "targetname");
155 if (target
== NULL
) {
160 if (asprintf(&connname
, "connection%s:0", udev_device_get_sysnum(transportdev
)) < 0) {
164 conndev
= udev_device_new_from_subsystem_sysname(udev
, "iscsi_connection", connname
);
166 if (conndev
== NULL
) {
170 addr
= udev_device_get_sysattr_value(conndev
, "persistent_address");
171 port
= udev_device_get_sysattr_value(conndev
, "persistent_port");
172 if (addr
== NULL
|| port
== NULL
) {
177 path_prepend(path
, "ip-%s:%s-iscsi-%s-lun-%s", addr
, port
, target
, udev_device_get_sysnum(parent
));
179 udev_device_unref(sessiondev
);
180 udev_device_unref(conndev
);
184 static struct udev_device
*handle_scsi_default(struct udev_device
*parent
, char **path
)
186 struct udev_device
*hostdev
;
187 int host
, bus
, target
, lun
;
195 hostdev
= udev_device_get_parent_with_subsystem_devtype(parent
, "scsi", "scsi_host");
199 name
= udev_device_get_sysname(parent
);
200 if (sscanf(name
, "%d:%d:%d:%d", &host
, &bus
, &target
, &lun
) != 4)
203 /* rebase host offset to get the local relative number */
205 base
= strdup(udev_device_get_syspath(hostdev
));
208 pos
= strrchr(base
, '/');
219 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
223 if (dent
->d_name
[0] == '.')
225 if (dent
->d_type
!= DT_DIR
&& dent
->d_type
!= DT_LNK
)
227 if (strncmp(dent
->d_name
, "host", 4) != 0)
229 i
= strtoul(&dent
->d_name
[4], &rest
, 10);
232 if (basenum
== -1 || i
< basenum
)
242 path_prepend(path
, "scsi-%u:%u:%u:%u", host
, bus
, target
, lun
);
248 static struct udev_device
*handle_scsi(struct udev_device
*parent
, char **path
)
254 devtype
= udev_device_get_devtype(parent
);
255 if (devtype
== NULL
|| strcmp(devtype
, "scsi_device") != 0)
259 id
= udev_device_get_sysattr_value(parent
, "ieee1394_id");
261 parent
= skip_subsystem(parent
, "scsi");
262 path_prepend(path
, "ieee1394-0x%s", id
);
266 /* lousy scsi sysfs does not have a "subsystem" for the transport */
267 name
= udev_device_get_syspath(parent
);
269 if (strstr(name
, "/rport-") != NULL
) {
270 parent
= handle_scsi_fibre_channel(parent
, path
);
274 if (strstr(name
, "/end_device-") != NULL
) {
275 parent
= handle_scsi_sas(parent
, path
);
279 if (strstr(name
, "/session") != NULL
) {
280 parent
= handle_scsi_iscsi(parent
, path
);
284 parent
= handle_scsi_default(parent
, path
);
289 static void handle_scsi_tape(struct udev_device
*dev
, char **suffix
)
293 name
= udev_device_get_sysname(dev
);
294 if (strncmp(name
, "nst", 3) == 0 && strchr("lma", name
[3]) != NULL
)
295 asprintf(suffix
, "nst%c", name
[3]);
296 else if (strncmp(name
, "st", 2) == 0 && strchr("lma", name
[2]) != NULL
)
297 asprintf(suffix
, "st%c", name
[2]);
300 static struct udev_device
*handle_usb(struct udev_device
*parent
, char **path
)
306 devtype
= udev_device_get_devtype(parent
);
307 if (devtype
== NULL
|| strcmp(devtype
, "usb_interface") != 0)
310 str
= udev_device_get_sysname(parent
);
311 port
= strchr(str
, '-');
316 parent
= skip_subsystem(parent
, "usb");
317 path_prepend(path
, "usb-0:%s", port
);
321 static struct udev_device
*handle_cciss(struct udev_device
*parent
, char **path
)
326 static struct udev_device
*handle_ccw(struct udev_device
*parent
, struct udev_device
*dev
, char **path
)
328 struct udev_device
*scsi_dev
;
330 scsi_dev
= udev_device_get_parent_with_subsystem_devtype(dev
, "scsi", "scsi_device");
331 if (scsi_dev
!= NULL
) {
336 hba_id
= udev_device_get_sysattr_value(scsi_dev
, "hba_id");
337 wwpn
= udev_device_get_sysattr_value(scsi_dev
, "wwpn");
338 lun
= udev_device_get_sysattr_value(scsi_dev
, "fcp_lun");
339 if (hba_id
!= NULL
&& lun
!= NULL
&& wwpn
!= NULL
) {
340 path_prepend(path
, "ccw-%s-zfcp-%s:%s", hba_id
, wwpn
, lun
);
345 path_prepend(path
, "ccw-%s", udev_device_get_sysname(parent
));
347 parent
= skip_subsystem(parent
, "ccw");
351 int main(int argc
, char **argv
)
353 static const struct option options
[] = {
354 { "debug", no_argument
, NULL
, 'd' },
355 { "help", no_argument
, NULL
, 'h' },
359 struct udev_device
*dev
;
360 struct udev_device
*parent
;
361 char syspath
[UTIL_PATH_SIZE
];
371 udev_log_init("path_id");
372 udev_set_log_fn(udev
, log_fn
);
377 option
= getopt_long(argc
, argv
, "dh", options
, NULL
);
384 if (udev_get_log_priority(udev
) < LOG_INFO
)
385 udev_set_log_priority(udev
, LOG_INFO
);
388 printf("Usage: path_id [--debug] [--help] <devpath>\n"
389 " --debug print debug information\n"
390 " --help print this help text\n\n");
397 devpath
= argv
[optind
];
398 if (devpath
== NULL
) {
399 fprintf(stderr
, "No device specified\n");
404 util_strscpyl(syspath
, sizeof(syspath
), udev_get_sys_path(udev
), devpath
, NULL
);
405 dev
= udev_device_new_from_syspath(udev
, syspath
);
407 fprintf(stderr
, "unable to access '%s'\n", devpath
);
416 parent
= udev_device_get_parent_with_subsystem_devtype(dev
, "ccw", NULL
);
417 if (parent
!= NULL
) {
418 handle_ccw(parent
, dev
, &path
);
422 /* walk up the chain of devices and compose path */
424 while (parent
!= NULL
) {
427 subsys
= udev_device_get_subsystem(parent
);
429 if (subsys
== NULL
) {
431 } else if (strcmp(subsys
, "scsi_tape") == 0) {
432 handle_scsi_tape(parent
, &path_suffix
);
433 } else if (strcmp(subsys
, "scsi") == 0) {
434 parent
= handle_scsi(parent
, &path
);
435 } else if (strcmp(subsys
, "cciss") == 0) {
436 handle_cciss(parent
, &path
);
437 } else if (strcmp(subsys
, "usb") == 0) {
438 parent
= handle_usb(parent
, &path
);
439 } else if (strcmp(subsys
, "serio") == 0) {
440 path_prepend(&path
, "serio-%s", udev_device_get_sysnum(parent
));
441 parent
= skip_subsystem(parent
, "serio");
442 } else if (strcmp(subsys
, "pci") == 0) {
443 path_prepend(&path
, "pci-%s", udev_device_get_sysname(parent
));
444 parent
= skip_subsystem(parent
, "pci");
445 } else if (strcmp(subsys
, "platform") == 0) {
446 path_prepend(&path
, "platform-%s", udev_device_get_sysname(parent
));
447 parent
= skip_subsystem(parent
, "platform");
448 } else if (strcmp(subsys
, "xen") == 0) {
449 path_prepend(&path
, "xen-%s", udev_device_get_sysname(parent
));
450 parent
= skip_subsystem(parent
, "xen");
453 parent
= udev_device_get_parent(parent
);
457 if (path_suffix
!= NULL
) {
458 printf("ID_PATH=%s%s\n", path
, path_suffix
);
461 printf("ID_PATH=%s\n", path
);
467 udev_device_unref(dev
);