github.com/openebs/node-disk-manager@v1.9.1-0.20230225014141-4531f06ffa1e/pkg/udev/common.go (about) 1 /* 2 Copyright 2018 OpenEBS Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // +build linux,cgo 18 19 package udev 20 21 /* 22 #cgo LDFLAGS: -ludev 23 #include <stdlib.h> 24 */ 25 import "C" 26 import ( 27 "os" 28 "strconv" 29 "strings" 30 "unsafe" 31 32 "github.com/openebs/node-disk-manager/pkg/util" 33 ) 34 35 const ( 36 NDMBlockDevicePrefix = "blockdevice-" // NDMBlockDevicePrefix used as device's uuid prefix 37 UDEV_SUBSYSTEM = "block" // udev to filter this device type 38 UDEV_SYSTEM = "disk" // used to filter devices other than disk which udev tracks (eg. CD ROM) 39 UDEV_PARTITION = "partition" // used to filter out partitions 40 UDEV_PATH = "DEVPATH" // udev attribute to get device path 41 UDEV_WWN = "ID_WWN" // udev attribute to get device WWN number 42 UDEV_SERIAL = "ID_SERIAL_SHORT" // udev attribute to get device serial number 43 UDEV_SERIAL_FULL = "ID_SERIAL" // udev attribute to get - separated vendor, model, serial 44 UDEV_BUS = "ID_BUS" // udev attribute to get bus name 45 UDEV_MODEL = "ID_MODEL" // udev attribute to get device model number 46 UDEV_VENDOR = "ID_VENDOR" // udev attribute to get device vendor details 47 UDEV_TYPE = "ID_TYPE" // udev attribute to get device type 48 UDEV_MAJOR = "MAJOR" // udev attribute to get device major no 49 UDEV_MINOR = "MINOR" // udev attribute to get device minor no 50 UDEV_UUID = "UDEV_UUID" // ndm attribute to get device uuid 51 UDEV_SYSPATH = "UDEV_SYSPATH" // udev attribute to get device syspath 52 UDEV_ACTION = "UDEV_ACTION" // udev attribute to get monitor device action 53 UDEV_ACTION_ADD = "add" // udev attribute constant for add action 54 UDEV_ACTION_REMOVE = "remove" // udev attribute constant for remove action 55 UDEV_ACTION_CHANGE = "change" // udev attribute constant for change action 56 UDEV_DEVTYPE = "DEVTYPE" // udev attribute to get device device type ie - disk or part 57 UDEV_SOURCE = "udev" // udev source constant 58 UDEV_SYSPATH_PREFIX = "/sys/dev/block/" // udev syspath prefix 59 UDEV_DEVNAME = "DEVNAME" // udev attribute contain disk name given by kernel 60 UDEV_DEVLINKS = "DEVLINKS" // udev attribute contain devlinks of a disk 61 BY_ID_LINK = "by-id" // by-path devlink contains this string 62 BY_PATH_LINK = "by-path" // by-path devlink contains this string 63 BY_UUID_LINK = "by-uuid" // by-uuid devlink contains the string 64 BY_PARTUUID_LINK = "by-partuuid" // by-partuuid devlink contains the string 65 LINK_ID_INDEX = 4 // this is used to get link index from dev link 66 UDEV_FS_TYPE = "ID_FS_TYPE" // file system type the partition 67 UDEV_FS_UUID = "ID_FS_UUID" // UUID of the filesystem present 68 UDEV_PARTITION_TABLE_TYPE = "ID_PART_TABLE_TYPE" // udev attribute to get partition table type(gpt/dos) 69 UDEV_PARTITION_TABLE_UUID = "ID_PART_TABLE_UUID" // udev attribute to get partition table UUID 70 UDEV_PARTITION_NUMBER = "ID_PART_ENTRY_NUMBER" // udev attribute to get partition number 71 UDEV_PARTITION_UUID = "ID_PART_ENTRY_UUID" // udev attribute to get partition uuid 72 UDEV_PARTITION_TYPE = "ID_PART_ENTRY_TYPE" // udev attribute to get partition type 73 UDEV_DM_UUID = "DM_UUID" // udev attribute to get the device mapper uuid 74 // UDEV_DM_NAME is udev attribute to get the name of the dm device. This is used to generate the device mapper path 75 UDEV_DM_NAME = "DM_NAME" 76 // SYMLINK is used to represent any manually created device symlinks 77 SYMLINK = "symlink" 78 ) 79 80 // UdevDiskDetails struct contain different attribute of disk. 81 type UdevDiskDetails struct { 82 WWN string 83 Model string // Model is Model of disk. 84 Serial string // Serial is Serial of a disk. 85 Vendor string // Vendor is Vendor of a disk. 86 Path string // Path is Path of a disk. 87 ByIdDevLinks []string // ByIdDevLinks contains by-id devlinks 88 ByPathDevLinks []string // ByPathDevLinks contains by-path devlinks 89 SymLinks []string // SymLinks contains device symlinks if any 90 DiskType string // DeviceType can be disk, partition 91 // IDType is used for uuid generation using the legacy algorithm 92 IDType string 93 FileSystem string // FileSystem on the disk 94 // Partitiontype on the disk/device 95 PartitionType string 96 // PartitionNumber is the partition number, for /dev/sdb1, partition number is 1 97 PartitionNumber uint8 98 // PartitionTableType is the type of the partition table (dos/gpt) 99 PartitionTableType string 100 // DMPath is the /dev/mapper path if this is a dm device 101 DMPath string 102 } 103 104 // freeCharPtr frees c pointer 105 func freeCharPtr(s *C.char) { 106 C.free(unsafe.Pointer(s)) 107 } 108 109 //DiskInfoFromLibudev returns disk attribute extracted using libudev apicalls. 110 func (device *UdevDevice) DiskInfoFromLibudev() UdevDiskDetails { 111 devLinks := device.GetDevLinks() 112 diskDetails := UdevDiskDetails{ 113 WWN: device.GetPropertyValue(UDEV_WWN), 114 Model: device.GetPropertyValue(UDEV_MODEL), 115 Serial: device.GetPropertyValue(UDEV_SERIAL), 116 Vendor: device.GetPropertyValue(UDEV_VENDOR), 117 Path: device.GetPropertyValue(UDEV_DEVNAME), 118 ByIdDevLinks: devLinks[BY_ID_LINK], 119 ByPathDevLinks: devLinks[BY_PATH_LINK], 120 SymLinks: devLinks[SYMLINK], 121 DiskType: device.GetDevtype(), 122 IDType: device.GetPropertyValue(UDEV_TYPE), 123 FileSystem: device.GetFileSystemInfo(), 124 PartitionType: device.GetPartitionType(), 125 PartitionNumber: device.GetPartitionNumber(), 126 PartitionTableType: device.GetPropertyValue(UDEV_PARTITION_TABLE_TYPE), 127 } 128 // get the devicemapper path from the dm name 129 dmName := device.GetPropertyValue(UDEV_DM_NAME) 130 if len(dmName) != 0 { 131 diskDetails.DMPath = "/dev/mapper/" + dmName 132 } 133 return diskDetails 134 } 135 136 // GetUid returns unique id for the disk block device 137 func (device *UdevDevice) GetUid() string { 138 uid := device.GetPropertyValue(UDEV_WWN) + 139 device.GetPropertyValue(UDEV_MODEL) + 140 device.GetPropertyValue(UDEV_SERIAL) + 141 device.GetPropertyValue(UDEV_VENDOR) 142 143 idtype := device.GetPropertyValue(UDEV_TYPE) 144 145 model := device.GetPropertyValue(UDEV_MODEL) 146 147 // Virtual disks either have no attributes or they all have 148 // the same attributes. Adding hostname in uid so that disks from different 149 // nodes can be differentiated. Also, putting devpath in uid so that disks 150 // from the same node also can be differentiated. 151 // On Gke, we have the ID_TYPE property, but still disks will have 152 // same attributes. We have to put a special check to handle it and process 153 // it like a Virtual disk. 154 localDiskModels := make([]string, 0) 155 localDiskModels = append(localDiskModels, "EphemeralDisk") 156 localDiskModels = append(localDiskModels, "Virtual_disk") 157 localDiskModels = append(localDiskModels, "QEMU_HARDDISK") 158 if len(idtype) == 0 || util.Contains(localDiskModels, model) { 159 // as hostNetwork is true, os.Hostname will give you the node's Hostname 160 host, _ := os.Hostname() 161 uid += host + device.GetPropertyValue(UDEV_DEVNAME) 162 } 163 164 return NDMBlockDevicePrefix + util.Hash(uid) 165 } 166 167 // IsDisk returns true if device is a disk 168 func (device *UdevDevice) IsDisk() bool { 169 return device.GetDevtype() == UDEV_SYSTEM 170 } 171 172 // IsPartition return true if device is a partition 173 func (device *UdevDevice) IsParitition() bool { 174 return device.GetDevtype() == UDEV_PARTITION 175 } 176 177 // GetFileSystemInfo returns filesystem type on disk/partition if it exists. 178 func (device *UdevDevice) GetFileSystemInfo() string { 179 fileSystem := device.GetPropertyValue(UDEV_FS_TYPE) 180 return fileSystem 181 } 182 183 // GetPartitionType returns the partition type of the partition, like DOS, lvm2 etc 184 func (device *UdevDevice) GetPartitionType() string { 185 partitionType := device.GetPropertyValue(UDEV_PARTITION_TYPE) 186 return partitionType 187 } 188 189 // GetPartitionNumber returns the partition number of the device, if the device is partition 190 // eg: /dev/sdb2 -> 2 191 func (device *UdevDevice) GetPartitionNumber() uint8 { 192 partNo, err := strconv.Atoi(device.GetPropertyValue(UDEV_PARTITION_NUMBER)) 193 if err != nil { 194 return 0 195 } 196 return uint8(partNo) 197 } 198 199 // GetSyspath returns syspath of a disk using syspath we can fell details 200 // in diskInfo struct using udev probe 201 func (device *UdevDevice) GetSyspath() string { 202 major := device.GetPropertyValue(UDEV_MAJOR) 203 minor := device.GetPropertyValue(UDEV_MINOR) 204 syspath := UDEV_SYSPATH_PREFIX + major + ":" + minor 205 return syspath 206 } 207 208 // GetPath returns the path of device in /dev directory 209 func (device *UdevDevice) GetPath() string { 210 return device.GetPropertyValue(UDEV_DEVNAME) 211 } 212 213 // GetDevLinks returns syspath of a disk using syspath we can fell details 214 // in diskInfo struct using udev probe 215 func (device *UdevDevice) GetDevLinks() map[string][]string { 216 devLinkMap := make(map[string][]string) 217 byIdLink := make([]string, 0) 218 byPathLink := make([]string, 0) 219 symLink := make([]string, 0) 220 for _, link := range strings.Split(device.GetPropertyValue(UDEV_DEVLINKS), " ") { 221 /* 222 devlink is like - /dev/disk/by-id/scsi-0Google_PersistentDisk_demo-disk 223 parts = ["", "dev", "disk", "by-id", "scsi-0Google_PersistentDisk_demo-disk"] 224 parts[4] contains link index like model or wwn or sysPath (wwn-0x5000c5009e3a8d2b) (ata-ST500LM021-1KJ152_W6HFGR) 225 */ 226 parts := strings.Split(link, "/") 227 if util.Contains(parts, BY_ID_LINK) { 228 /* 229 A default by-id link is observed to be created for all types of disks (physical, virtual and cloud). 230 This link has the format - bus, vendor, model, serial - all appended in the same order. Keeping this 231 link as the first element of array for consistency purposes. 232 */ 233 if strings.HasPrefix(parts[LINK_ID_INDEX], device.GetPropertyValue(UDEV_BUS)) && strings.HasSuffix(parts[LINK_ID_INDEX], device.GetPropertyValue(UDEV_SERIAL_FULL)) { 234 byIdLink = append([]string{link}, byIdLink...) 235 } else { 236 byIdLink = append(byIdLink, link) 237 } 238 } else if util.Contains(parts, BY_PATH_LINK) { 239 byPathLink = append(byPathLink, link) 240 } 241 // we can add very dev link in symlink map as there is a 1:1 mapping between the two links 242 symLink = append(symLink, link) 243 } 244 devLinkMap[BY_ID_LINK] = byIdLink 245 devLinkMap[BY_PATH_LINK] = byPathLink 246 devLinkMap[SYMLINK] = symLink 247 return devLinkMap 248 }