libcam: resolve symbolic links before processing device name

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Wed, 29 Sep 2021 09:42:38 UTC
The CAM subsystem uses bus:taget:lun tuple to address peripherals.
But for convenience many userland programs such as camcontrol accept devices 
names such as da0.
There is a libcam function, cam_open_device, to support that.
It first calls cam_get_device() to parse the device name as a driver name and 
unit (and handle some special device name prefixes) and then uses 
cam_lookup_pass() to find a matching pass device.

I would like to propose to extend cam_get_device() to apply realpath(3) to the 
device name before parsing it.  This will allow to use tools such as camcontrol 
and smartctl with symbolic links that could be friendlier (more distinguished) 
names for devices.

The patch:
diff --git a/lib/libcam/camlib.c b/lib/libcam/camlib.c
index 438b0e502fe0..6ebdb30ab82b 100644
--- a/lib/libcam/camlib.c
+++ b/lib/libcam/camlib.c
@@ -128,10 +128,13 @@ cam_get_device(const char *path, char *dev_name, int 
devnamelen, int *unit)
  	}

  	/*
-	 * We can be rather destructive to the path string.  Make a copy of
-	 * it so we don't hose the user's string.
+	 * Resolve the given path to a real device path in case we are given
+	 * an alias or other symbolic link.  If the path cannot be resolved
+	 * then try to parse it as is.
  	 */
-	newpath = (char *)strdup(path);
+	newpath = realpath(path, NULL);
+	if (newpath == NULL)
+		newpath = strdup(path);
  	if (newpath == NULL)
  		return (-1);



What it "unlocks" (the example works only if /dev/diskid/DISK-QM00015 is a symlink):
root@freebsd:~ # smartctl -iA /dev/diskid/DISK-QM00015
smartctl 7.2 2020-12-30 r5155 [FreeBSD 13.0-STABLE amd64] (local build)
Copyright (C) 2002-20, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Device Model:     QEMU HARDDISK
Serial Number:    QM00015
Firmware Version: 2.5+
User Capacity:    1,073,741,824 bytes [1.07 GB]
Sector Size:      512 bytes logical/physical
TRIM Command:     Available, deterministic
Device is:        Not in smartctl database [for details use: -P showall]
ATA Version is:   ATA/ATAPI-7, ATA/ATAPI-5 published, ANSI NCITS 340-2000
Local Time is:    Wed Sep 29 09:39:30 2021 UTC
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

=== START OF READ SMART DATA SECTION ===
SMART Attributes Data Structure revision number: 1
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED 
WHEN_FAILED RAW_VALUE
   1 Raw_Read_Error_Rate     0x0003   100   100   006    Pre-fail  Always 
-       0
   3 Spin_Up_Time            0x0003   100   100   000    Pre-fail  Always 
-       16
   4 Start_Stop_Count        0x0002   100   100   020    Old_age   Always 
-       100
   5 Reallocated_Sector_Ct   0x0003   100   100   036    Pre-fail  Always 
-       0
   9 Power_On_Hours          0x0003   100   100   000    Pre-fail  Always 
-       1
  12 Power_Cycle_Count       0x0003   100   100   000    Pre-fail  Always 
-       0
190 Airflow_Temperature_Cel 0x0003   069   069   050    Pre-fail  Always       - 
       31 (Min/Max 31/31)


-- 
Andriy Gapon