From c5991b48a017ed775da893b6f20553ff838ddb5e Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Tue, 28 Apr 2009 13:28:25 +0000 Subject: [PATCH] /proc/scsi is being deprecated in the Linux kernel; use sysfs for SCSI device enumeration in sanei_scsi_find_devices() by default, keep sanei_proc_scsi_find_devices() as a fallback option. --- ChangeLog | 6 + sanei/sanei_scsi.c | 279 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 274 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index e87d4517b..ec8fd81f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-04-28 Julien Blache + * sanei/sanei_scsi.c: /proc/scsi is being deprecated in the Linux + kernel; use sysfs for SCSI device enumeration in + sanei_scsi_find_devices() by default, keep + sanei_proc_scsi_find_devices() as a fallback option. + 2009-04-27 Gerhard Jaeger * backend/plustek-usbdevs.c: Tweaked highspeed settings for Epson 1260 diff --git a/sanei/sanei_scsi.c b/sanei/sanei_scsi.c index 2546dfba1..69d5859b7 100644 --- a/sanei/sanei_scsi.c +++ b/sanei/sanei_scsi.c @@ -220,6 +220,10 @@ # define USE STUBBED_INTERFACE #endif +#if USE == LINUX_INTERFACE +# include +#endif + #include "../include/sane/sanei.h" #include "../include/sane/sanei_config.h" #include "../include/sane/sanei_scsi.h" @@ -2681,13 +2685,13 @@ issue (struct req *req) return 0; } - void /* calls 'attach' function pointer with sg device file name iff match */ - - sanei_scsi_find_devices (const char *findvendor, const char *findmodel, - const char *findtype, - int findbus, int findchannel, int findid, - int findlun, - SANE_Status (*attach) (const char *dev)) +/* Legacy /proc/scsi/scsi */ +static void /* calls 'attach' function pointer with sg device file name iff match */ +sanei_proc_scsi_find_devices (const char *findvendor, const char *findmodel, + const char *findtype, + int findbus, int findchannel, int findid, + int findlun, + SANE_Status (*attach) (const char *dev)) { #define FOUND_VENDOR 1 #define FOUND_MODEL 2 @@ -2699,6 +2703,8 @@ issue (struct req *req) #define FOUND_LUN 128 #define FOUND_ALL 255 + char *me = "sanei_proc_scsi_find_devices"; + size_t findvendor_len = 0, findmodel_len = 0, findtype_len = 0; char vendor[32], model[32], type[32], revision[32]; int bus, channel, id, lun; @@ -2786,7 +2792,7 @@ issue (struct req *req) proc_fp = fopen (PROCFILE, "r"); if (!proc_fp) { - DBG (1, "could not open %s for reading\n", PROCFILE); + DBG (1, "%s: could not open %s for reading\n", me, PROCFILE); return; } @@ -2875,9 +2881,10 @@ issue (struct req *req) && (findid == -1 || id == findid) && (findlun == -1 || lun == findlun)) { - DBG (2, "sanei_scsi_find_devices: vendor=%s model=%s type=%s\n\t" - "bus=%d chan=%d id=%d lun=%d num=%d\n", findvendor, - findmodel, findtype, bus, channel, id, lun, number); + DBG (2, "%s: found: vendor=%s model=%s type=%s\n\t" + "bus=%d chan=%d id=%d lun=%d num=%d\n", + me, findvendor, findmodel, findtype, + bus, channel, id, lun, number); if (lx_chk_devicename (number, dev_name, sizeof (dev_name), bus, channel, id, lun) && ((*attach) (dev_name) != SANE_STATUS_GOOD)) @@ -2885,12 +2892,262 @@ issue (struct req *req) DBG(1,"sanei_scsi_find_devices: bad attach\n"); } } + else + { + DBG (2, "%s: no match\n", me); + } vendor[0] = model[0] = type[0] = 0; bus = channel = id = lun = -1; } fclose (proc_fp); } +#define SYSFS_SCSI_DEVICES "/sys/bus/scsi/devices" + +/* From linux/drivers/scsi/scsi.c */ +static char *lnxscsi_device_types[] = { + "Direct-Access ", + "Sequential-Access", + "Printer ", + "Processor ", + "WORM ", + "CD-ROM ", + "Scanner ", + "Optical Device ", + "Medium Changer ", + "Communications ", + "ASC IT8 ", + "ASC IT8 ", + "RAID ", + "Enclosure ", + "Direct-Access-RBC", + "Optical card ", + "Bridge controller", + "Object storage ", + "Automation/Drive " +}; + +void /* calls 'attach' function pointer with sg device file name iff match */ +sanei_scsi_find_devices (const char *findvendor, const char *findmodel, + const char *findtype, + int findbus, int findchannel, int findid, + int findlun, + SANE_Status (*attach) (const char *dev)) + { + char *me = "sanei_scsi_find_devices"; + char path[PATH_MAX]; + char dev_name[128]; + struct dirent buf; + struct dirent *de; + DIR *scsidevs; + FILE *fp; + char *ptr; + char *end; + int bcil[4]; /* bus, channel, id, lun */ + char vmt[3][33]; /* vendor, model, type */ + int vmt_len[3]; + char *vmtfiles[3] = { "vendor", "model", "type" }; + int lastbus; + int number; + int i; + long val; + int ret; + + DBG_INIT (); + + DBG (2, "%s: looking for: v=%s m=%s t=%s b=%d c=%d i=%d l=%d\n", + me, findvendor, findmodel, findtype, + findbus, findchannel, findid, findlun); + + scsidevs = opendir (SYSFS_SCSI_DEVICES); + if (!scsidevs) + { + DBG (1, "%s: could not open %s; falling back to /proc\n", + me, SYSFS_SCSI_DEVICES); + + sanei_proc_scsi_find_devices (findvendor, findmodel, findtype, + findbus, findchannel, findid, findlun, + attach); + return; + } + + vmt_len[0] = (findvendor) ? strlen(findvendor) : 0; + vmt_len[1] = (findmodel) ? strlen(findmodel) : 0; + vmt_len[2] = (findtype) ? strlen(findtype) : 0; + + lastbus = -1; + number = -1; + for (;;) + { + ret = readdir_r(scsidevs, &buf, &de); + if (ret != 0) + { + DBG (1, "%s: could not read directory %s: %s\n", + me, SYSFS_SCSI_DEVICES, strerror(errno)); + + break; + } + + if (de == NULL) + break; + + if (buf.d_name[0] == '.') + continue; + + /* Extract bus, channel, id, lun from directory name b:c:i:l */ + ptr = buf.d_name; + for (i = 0; i < 4; i++) + { + errno = 0; + val = strtol (ptr, &end, 10); + if (((errno == ERANGE) && ((val == LONG_MAX) || (val == LONG_MIN))) + || ((errno != 0) && (val == 0))) + { + DBG (1, "%s: invalid integer in string (%s): %s\n", + me, ptr, strerror(errno)); + + i = 12; /* Skip */ + break; + } + + if (end == ptr) + { + DBG (1, "%s: no integer found in string: %s (%d)\n", me, ptr, i); + + i = 12; /* Skip */ + break; + } + + if (*end && (*end != ':')) + { + DBG (1, "%s: parse error on string %s (%d)\n", me, buf.d_name, i); + + i = 12; /* Skip */ + break; + } + + if (val > INT_MAX) + { + DBG (1, "%s: integer value too large (%s)\n", me, buf.d_name); + + i = 12; /* Skip */ + break; + } + + bcil[i] = (int) val; + ptr = end + 1; + } + + /* Skip this one */ + if (i == 12) + continue; + + if (bcil[0] != lastbus) + { + lastbus = bcil[0]; + number++; + } + + for (i = 0; i < 3; i++) + { + ret = snprintf (path, PATH_MAX, "%s/%s/%s", + SYSFS_SCSI_DEVICES, buf.d_name, vmtfiles[i]); + if ((ret < 0) || (ret >= PATH_MAX)) + { + DBG (1, "%s: skipping %s/%s, PATH_MAX exceeded on %s\n", + me, SYSFS_SCSI_DEVICES, buf.d_name, vmtfiles[i]); + + i = 12; /* Skip */ + break; + } + + memset (vmt[i], 0, sizeof(vmt[i])); + + fp = fopen(path, "r"); + if (!fp) + { + DBG (1, "%s: could not open %s: %s\n", me, path, strerror(errno)); + + i = 12; /* Skip */ + break; + } + + ret = fread (vmt[i], 1, sizeof(vmt[i]) - 1, fp); + if (ret <= 0) + { + if (ferror(fp)) + { + DBG (1, "%s: error reading %s\n", me, path); + + i = 12; /* Skip */ + break; + } + } + + if (vmt[i][ret - 1] == '\n') + vmt[i][ret - 1] = '\0'; + + fclose (fp); + } + + /* Skip this one */ + if (i == 12) + continue; + + /* Type is a numeric string and must be converted back to a well-known string */ + errno = 0; + val = strtol (vmt[2], &end, 10); + if (((errno == ERANGE) && ((val == LONG_MAX) || (val == LONG_MIN))) + || ((errno != 0) && (val == 0))) + { + DBG (1, "%s: invalid integer in type string (%s): %s\n", + me, vmt[2], strerror(errno)); + continue; + } + + if (end == vmt[2]) + { + DBG (1, "%s: no integer found in type string: %s\n", me, vmt[2]); + continue; + } + + if ((val < 0) || (val >= (int)(sizeof(lnxscsi_device_types) / sizeof(lnxscsi_device_types[0])))) + { + DBG (1, "%s: invalid type %ld\n", me, val); + continue; + } + + strncpy(vmt[2], lnxscsi_device_types[val], sizeof(vmt[2]) - 1); + + if ((!findvendor || strncmp (vmt[0], findvendor, vmt_len[0]) == 0) + && (!findmodel || strncmp (vmt[1], findmodel, vmt_len[1]) == 0) + && (!findtype || strncmp (vmt[2], findtype, vmt_len[2]) == 0) + && (findbus == -1 || bcil[0] == findbus) + && (findchannel == -1 || bcil[1] == findchannel) + && (findid == -1 || bcil[2] == findid) + && (findlun == -1 || bcil[3] == findlun)) + { + DBG (2, "%s: found: vendor=%s model=%s type=%s\n\t" + "bus=%d chan=%d id=%d lun=%d num=%d\n", + me, vmt[0], vmt[1], vmt[2], + bcil[0], bcil[1], bcil[2], bcil[3], number); + + if (lx_chk_devicename (number, dev_name, sizeof (dev_name), + bcil[0], bcil[1], bcil[2], bcil[3]) + && ((*attach) (dev_name) != SANE_STATUS_GOOD)) + { + DBG (1, "%s: bad attach\n", me); + } + } + else + { + DBG (2, "%s: no match\n", me); + } + } + + closedir(scsidevs); + } + #endif /* USE == LINUX_INTERFACE */