1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License (the "License").
7 * You may not use this file except in compliance with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or https://opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 *
27 * Copyright (c) 2016, Intel Corporation.
28 */
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <libudev.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <fcntl.h>
39
40 /*
41 * Linux persistent device strings for vdev labels
42 *
43 * based on udev_device_get_devid() at zfs/lib/libzfs/libzfs_import.c
44 */
45
46 #define DEV_BYID_PATH "/dev/disk/by-id/"
47
48 static int
udev_device_get_devid(struct udev_device * dev,char * bufptr,size_t buflen)49 udev_device_get_devid(struct udev_device *dev, char *bufptr, size_t buflen)
50 {
51 struct udev_list_entry *entry;
52 const char *bus;
53 char devbyid[MAXPATHLEN];
54
55 /* The bus based by-id path is preferred */
56 bus = udev_device_get_property_value(dev, "ID_BUS");
57
58 if (bus == NULL) {
59 const char *dm_uuid;
60
61 /*
62 * For multipath nodes use the persistent uuid based identifier
63 *
64 * Example: 'dm-uuid-mpath-35000c5006304de3f'
65 */
66 dm_uuid = udev_device_get_property_value(dev, "DM_UUID");
67 if (dm_uuid != NULL) {
68 (void) snprintf(bufptr, buflen, "dm-uuid-%s", dm_uuid);
69 return (0);
70 }
71 return (ENODATA);
72 }
73
74 /*
75 * locate the bus specific by-id link
76 *
77 * Example: 'scsi-MG03SCA300_350000494a8cb3d67-part1'
78 */
79 (void) snprintf(devbyid, sizeof (devbyid), "%s%s-", DEV_BYID_PATH, bus);
80 entry = udev_device_get_devlinks_list_entry(dev);
81 while (entry != NULL) {
82 const char *name;
83
84 name = udev_list_entry_get_name(entry);
85 if (strncmp(name, devbyid, strlen(devbyid)) == 0) {
86 name += strlen(DEV_BYID_PATH);
87 (void) stpncpy(bufptr, name, buflen - 1);
88 bufptr[buflen - 1] = '\0';
89 return (0);
90 }
91 entry = udev_list_entry_get_next(entry);
92 }
93
94 return (ENODATA);
95 }
96
97 /*
98 * Usage: devname2devid <devicepath>
99 *
100 * Examples:
101 * # ./devname2devid /dev/sda1
102 * devid scsi-350000394a8caede4-part1
103 *
104 * # ./devname2devid /dev/dm-1
105 * devid: 'dm-uuid-mpath-35000c5006304de3f'
106 *
107 * This program accepts a disk or disk slice path and prints a
108 * device id.
109 *
110 * Exit values:
111 * 0 - means success
112 * 1 - means failure
113 *
114 */
115 int
main(int argc,char * argv[])116 main(int argc, char *argv[])
117 {
118 struct udev *udev;
119 struct udev_device *dev = NULL;
120 char devid[128], nodepath[MAXPATHLEN];
121 char *device, *sysname;
122 int ret;
123
124 if (argc == 1) {
125 (void) printf("%s <devicepath> [search path]\n", argv[0]);
126 exit(1);
127 }
128 device = argv[1];
129
130 if ((udev = udev_new()) == NULL) {
131 perror("udev_new");
132 exit(1);
133 }
134
135 /* resolve path to a runtime device node instance */
136 if (realpath(device, nodepath) == NULL) {
137 perror("realpath");
138 exit(1);
139 }
140 sysname = strrchr(nodepath, '/') + 1;
141
142 if ((dev = udev_device_new_from_subsystem_sysname(udev, "block",
143 sysname)) == NULL) {
144 perror(sysname);
145 exit(1);
146 }
147
148 if ((ret = udev_device_get_devid(dev, devid, sizeof (devid))) != 0) {
149 udev_device_unref(dev);
150 errno = ret;
151 perror(sysname);
152 exit(1);
153 }
154
155 (void) printf("devid %s\n", devid);
156
157 udev_device_unref(dev);
158 udev_unref(udev);
159
160 return (0);
161 }
162