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 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 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