Like Tree4Likes
  • 3 Post By Nominal Animal
  • 1 Post By Nominal Animal

getting model an serial information from SAS harddisk

This is a discussion on getting model an serial information from SAS harddisk within the Linux Programming forums, part of the Platform Specific Boards category; platform: linux I am writing a little program which requires to get the serial and model information out of harddisks. ...

  1. #1
    Registered User
    Join Date
    Feb 2014
    Posts
    18

    getting model an serial information from SAS harddisk

    platform: linux

    I am writing a little program which requires to get the serial and model information out of harddisks. (SAS, FC, SATA etc)

    for SATA it is very easy with an ioctl command (HDIO_GET_IDENTITY) which is defined in <linux/hdreg.h>.

    However this doesnt work on SAS and FC drives. So I thought to myself they are SCSI based and thus a SCSI inquiry would work. So I write a neat little function which sends and inquiry for me and retrieves the output.

    Now I get gibberish as the output from the inquiry(it doesnt 'fail' though). the drives are attached to a pci-e SAS card.
    I suspect the SAS card does something odd as I have tried to use my program on a virtual machine with virtual SAS drives and that seems to work...

    Also the SATA drives are hooked up to the same pci-e card (SAS offers backwards compatibility with SATA)

    is there another way to get serial and model information out of a harddisk besides the ways I have done?

    regards
    Last edited by thomas23; 02-15-2014 at 10:49 AM.

  2. #2
    Registered User
    Join Date
    Nov 2012
    Posts
    1,098
    This question is kind of Linux specific not exactly "C Programming" I would say. Have you tried hdparm? There are blog posts about it describing it in detail.

    Linux: Find out serial / model number and vendor information for SATA and IDE hard disk

    If you want to implement the same thing that such a program can do, the standard answer in this situation would be "use the source".

  3. #3
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    Quote Originally Posted by c99tutorial View Post
    This question is kind of Linux specific not exactly "C Programming" I would say. Have you tried hdparm? There are blog posts about it describing it in detail.

    Linux: Find out serial / model number and vendor information for SATA and IDE hard disk

    If you want to implement the same thing that such a program can do, the standard answer in this situation would be "use the source".
    hdparm uses ioctl. it doesnt work on scsi disks. There is a similair program called sdparm for scsi disks and that use a SCSI inquiry. so same result...
    Last edited by thomas23; 02-15-2014 at 08:12 PM.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,669
    Do you know of any existing tool that works? I would look at that source code...

    gg

  5. #5
    Registered User
    Join Date
    Oct 2011
    Posts
    847
    If you use udev and have /sys mounted, then use bash and udevadm:
    Code:
    for DEV in /sys/block/* ; do
        udevadm info --query=property --path=$DEV
        echo
    done
    to output all the features of known block devices.

    Note that most distributions have udev rules that generate symlinks in /dev/disk/by-id/ and /dev/disk/by/path/.

    For an abbreviated list of what you asked, you can use udevadm, bash, and awk. (Note that I'll use the device name instead of device path, just for illustration, in this case):
    Code:
    for DEV in /sys/block/* ; do
        udevadm info --query=property --name=${DEV##*/} | \
        awk '{ n=v=$0; sub(/=.*$/,"",n); sub(/^[^=]*=/, "", v); p[n]=v }
         END {
            if ("ID_MODEL" in p) {
                if ("ID_SERIAL_SHORT" in p)
                    s=p["ID_SERIAL_SHORT"];
                else
                    s=p["ID_SERIAL"];
                printf "%s\t%s\t%s\n", p["DEVNAME"], p["ID_MODEL"], s
            }
        }' ;
    done
    The /sys pseudo-filesystem does contain information on each block device, including size and vendor and model strings, e.g.
    Code:
    for DEV in /sys/block/* ; do
        printf "%s\t%s\t%s\t%s MiB\n" "${DEV##*/}" "$(cat $DEV/device/vendor 2>/dev/null)" "$(cat $DEV/device/model 2>/dev/null)" $[($(cat $DEV/size)-0)/2048];
    done
    The /sys/block/DEVICE/size pseudofile contains the size of the block device in 512 byte units, therefore dividing its value by 2048 yields the block device size in units of 1048576 bytes.

    In case you're wondering, the extra semicolons at the end of above lines are not needed if copy-pasted as it, but they allow you to paste the entire snippet as a single line command. That is, you can safely paste the above commands into a terminal, and run them as a non-root-user. The information does not require any special privileges to obtain.

    In an application written in C, I'd personally recommend using two helper scripts, executed externally by your application. First, /usr/lib/yourapp/blockdev-list would output the list of known block devices, separated by ASCII NULs:
    Code:
    #!/bin/bash
    udevadm info --export-db | awk 'BEGIN { split("", prop) }
        function show() {
            if (prop["SUBSYSTEM"]=="block")
                printf "%s\0", prop["DEVNAME"]
            split("", prop)
        }
        /^[^\t ]*$/ { show(); next }
        /^E:/ { s=$0; sub(/^E:[\t ]*/, "", s); n=v=s; sub(/=.*$/, "", n); sub(/^[^=]*=/, "", v); prop[n]=v; next }
        END { show() }'
    Note that this uses udev database for block devices, and therefore should include those devices that create their own subtrees instead of direct device nodes (making globbing their names harder than normal) -- I seem to recall most SAS drivers do this, but am too lazy to verify; in any case, this approach should list them all. I personally prefer this approach in all cases.

    Second, /usr/lib/yourapp/blockdev-info would output the interesting details of specified block devices. The below example outputs specific "lines" per device, with the first character defining the value type (N for device node (path), T for device type, M for device model, S for device serial number, and R for device revision), and ASCII NUL as the newline character:
    Code:
    #!/bin/bash
    for DEV in "$@" ; do
        udevadm info --query=property --name="$DEV" | awk 'BEGIN { split("", prop) }
        { n=v=$0; sub(/=.*$/, "", n); sub(/^[^=]*=/, "", v); prop[n]=v }
        END {
            if ("ID_SERIAL_SHORT" in prop)
                serial=prop["ID_SERIAL_SHORT"]
            else
                serial=prop["ID_SERIAL"]
            printf "N%s\0T%s\0M%s\0S%s\0R%s\0", prop["DEVNAME"], prop["DEVTYPE"], prop["ID_MODEL"], serial, prop["ID_REVISION"]
        }'        
    done
    The exact output format from the above is obviously up to you, but using ASCII NULs as the separator is the most reliable option, as the Linux kernel uses it internally as the end-of-string mark. Using the first character as the identifier makes it trivial to parse the entries. The output from above scripts is easy to parse using the POSIX.1-2008 getdelim() function (assuming the scripts were executed using e.g. popen(), and it is easily extended to include other properties you might need later, too.

    The reason I would split the operation into two scripts (for an application written in C or C++), is simply one of maintenance and portability. The /usr/lib/yourapp/ directory is the preferred location for these. This way, if there is some specific architecture or Linux distribution -- perhaps even a custom Linux distribution --, I could easily install target-specific scripts or even setuid binaries if necessary, to obtain the required information. Also, debugging and simulation of new devices becomes much simpler.

  6. #6
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    thank you. you are a godsend.

    I have chosen to implement it without bash scripting simply because it doesn't need to be portable. I use it on my own linux derivation. I wonder though how reliable it is. Here is some sample code I threw together quickly. no fancy checking etc yet. I don't use getdelim(); or getline(). because I think they are difficult do deal with and not really as flexible as just writing a short while loop.

    Code:
    #define DRIVEAMOUNT 20
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    int main() {
        /* initialize various vars.*/
        FILE                                    *driveptr,
                                                *sysstream; 
    
    
        int                                     i,j;
    
    
        char                                    OSpointer[9],
                                                sysstdout[256],
                                                serial[256],
                                                serial_short[256],
                                                model[256],
                                                syscmd[256];
       
    
    
        for (i=0;i<DRIVEAMOUNT;i++) {
            strcpy(OSpointer,"/dev/sdX");
            OSpointer[7]='a'+i;
    
    
            driveptr=fopen(OSpointer,"r");
            if (driveptr==NULL) {
                continue;
            }
            fclose(driveptr);
    
    
            sprintf(syscmd,"udevadm info --query=property --name=%s",OSpointer);
            sysstream=popen(syscmd,"r");
    
    
            do {
                j=0;do {
                    sysstdout[j]=fgetc(sysstream);
                    ++j;
                } while (sysstdout[j-1]!='\n'&&sysstdout[j-1]!=EOF);
                sscanf(sysstdout,"ID_SERIAL_SHORT=%s",&serial_short);
                sscanf(sysstdout,"ID_SERIAL=%s",&serial);
                sscanf(sysstdout,"ID_MODEL=%s",&model);
            } while(sysstdout[j-1]!=EOF);
            
            pclose(sysstream);
    
    
            printf("%s\n    |%s|\n    |%s|\n    |%s|\n\n",syscmd,serial_short,serial,model);
        }
    }

  7. #7
    Registered User
    Join Date
    Oct 2011
    Posts
    847
    Just for completeness:

    You could instead use the libudev interface (part of systemd).

    example.c:
    Code:
    #define  _POSIX_C_SOURCE 200809L
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #include <libudev.h>
    
    struct blockdev_stats {
        unsigned long long  read_ops;       /* Number of read I/Os processed */
        unsigned long long  read_merged;    /* Number of read I/Os merged with in-queue I/O */
        unsigned long long  read_512bytes;  /* Number of sectors read */
        unsigned long long  read_waits_ms;  /* Total wait time for read requests, milliseconds */
        unsigned long long  write_ops;      /* Number of write I/Os processed */
        unsigned long long  write_merged;   /* Number of write I/Os merged with in-queue I/O */
        unsigned long long  write_512bytes; /* Number of sectors written */
        unsigned long long  write_waits_ms; /* Total wait time for write requests, milliseconds */
        unsigned long long  in_flight;      /* Number of I/Os currently in flight */
        unsigned long long  active_ms;      /* Total active time, milliseconds */
        unsigned long long  waits_ms;       /* Total wait time, milliseconds */
    };
    
    /* Returns nonzero if stats is filled with the above values.
    */
    static inline int get_blockdev_stats(struct udev_device *const device, struct blockdev_stats *const stats)
    {
        if (device != NULL && stats != NULL) {
            const char *const s = udev_device_get_sysattr_value(device, "stat");
            if (s == NULL || *s == '\0')
                return 0;
            if (sscanf(s, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
                       &(stats->read_ops), &(stats->read_merged), &(stats->read_512bytes), &(stats->read_waits_ms),
                       &(stats->write_ops), &(stats->write_merged), &(stats->write_512bytes), &(stats->write_waits_ms),
                       &(stats->in_flight), &(stats->active_ms), &(stats->waits_ms)) >= 11)
                return 11;
        }
        return 0;
    }
    
    /* NULL pointer safe string comparison.
     * Returns 1 if neither pointer is NULL, and the strings they point to match.
    */
    static inline int eq(const char *const a, const char *const b)
    {
        if (a == NULL || b == NULL)
            return 0;
        else
            return !strcmp(a, b);
    }
    
    /* NULL pointer safe string to long long conversion.
    */
    static inline long long stoll(const char *const string, const long long error)
    {
        if (!string || *string == '\0')
            return error;
        return strtoll(string, NULL, 10);
    }
    
    int main(void)
    {
        struct udev            *udevhandle;
        struct udev_enumerate  *blockdevices;
        struct udev_list_entry *entry;
        const char             *devicepath;
        struct udev_device     *device;
    
        /* Get an udev handle. */
        udevhandle = udev_new();
        if (!udevhandle) {
            fprintf(stderr, "Cannot get udev handle.\n");
            return 1;
        }
    
        /* Enumerate block devices. */
        blockdevices = udev_enumerate_new(udevhandle);
        udev_enumerate_add_match_subsystem(blockdevices, "block");
        udev_enumerate_scan_devices(blockdevices);
    
        /* Iterate through the enumerated list. */
        udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(blockdevices)) {
            /* Use the devpath in the list to obtain a reference to the device. */
            devicepath = udev_list_entry_get_name(entry);
            device = udev_device_new_from_syspath(udevhandle, devicepath);
    
            /* Do the following only for "disk" devtypes in "block" subsystem: */
            if (eq("disk", udev_device_get_devtype(device))) {
    
                const char *const dev = udev_device_get_devnode(device); /* In /dev */
                const char *const bus = udev_device_get_property_value(device, "ID_BUS");
                const char *const model = udev_device_get_property_value(device, "ID_MODEL");
                const char *const serial = udev_device_get_property_value(device, "ID_SERIAL");
                const char *const serial_short = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
                const char *const revision = udev_device_get_property_value(device, "ID_REVISION");
                const char *const vendor = udev_device_get_sysattr_value(device, "device/vendor");
                const char *const rev = udev_device_get_sysattr_value(device, "device/rev");
                const long        size = stoll(udev_device_get_sysattr_value(device, "size"), -2048LL) / 2048LL;
                const long        removable = stoll(udev_device_get_sysattr_value(device, "removable"), -1LL);
                const long        readonly = stoll(udev_device_get_sysattr_value(device, "ro"), -1LL);
                struct blockdev_stats stats;
    
                if (dev)
                    printf("%s:\n", dev);
                else
                    printf("Unknown device:\n");
    
                if (size > 0L)
                    printf("\tSize: %ld MiB\n", size);
    
                if (removable == 0L)
                    printf("\tRemovable: No\n");
                else
                if (removable == 1L)
                    printf("\tRemovable: Yes\n");
    
                if (readonly == 0L)
                    printf("\tRead-only: No\n");
                else
                if (readonly == 1L)
                    printf("\tRead-only: Yes\n");
    
                if (bus)
                    printf("\tBus: '%s'\n", bus);
    
                if (vendor)
                    printf("\tVendor: '%s'\n", vendor);
    
                if (model)
                    printf("\tModel: '%s'\n", model);
    
                if (serial)
                    printf("\tSerial: '%s'\n", serial);
    
                if (serial_short)
                    printf("\tShort serial: '%s'\n", serial_short);
    
                if (revision)
                    printf("\tRevision: '%s' (udev)\n", revision);
    
                if (rev)
                    printf("\tRevision: '%s' (sys)\n", rev);
    
                if (get_blockdev_stats(device, &stats)) {
                    printf("\tRead: %llu requests, %llu MiB\n", stats.read_ops, stats.read_512bytes / 2048ULL);
                    printf("\tWritten: %llu requests, %llu MiB\n", stats.write_ops, stats.write_512bytes / 2048ULL);
                }
            }
    
            /* Drop the device reference. */
            udev_device_unref(device);
        }
    
        /* Release the enumerator object, and the udev handle. */
        udev_enumerate_unref(blockdevices);
        udev_unref(udevhandle);
    
        return 0;
    }
    Apologies for the very messy and inelegant code.

    Compile and run with e.g.
    Code:
    gcc -W -Wall -O3 example.c -ludev -o example
    ./example
    Here's what the output looks like on my machine with two Samsung HD103UJ drives and a Samsung DVD-RW drive:
    Code:
    /dev/sda:
    	Size: 953869 MiB
    	Removable: No
    	Read-only: No
    	Bus: 'ata'
    	Vendor: 'ATA     '
    	Model: 'SAMSUNG_HD103UJ'
    	Serial: 'SAMSUNG_HD103UJ_S13PJ90QA14955'
    	Short serial: 'S13PJ90QA14955'
    	Revision: '1AA01131' (udev)
    	Revision: '1AA0' (sys)
    	Read: 18678 requests, 523 MiB
    	Written: 43437 requests, 1385 MiB
    /dev/sdb:
    	Size: 953869 MiB
    	Removable: No
    	Read-only: No
    	Bus: 'ata'
    	Vendor: 'ATA     '
    	Model: 'SAMSUNG_HD103UJ'
    	Serial: 'SAMSUNG_HD103UJ_S13PJ9AQA16637'
    	Short serial: 'S13PJ9AQA16637'
    	Revision: '1AA01131' (udev)
    	Revision: '1AA0' (sys)
    	Read: 14348 requests, 431 MiB
    	Written: 42356 requests, 1328 MiB
    /dev/sr0:
    	Size: 1023 MiB
    	Removable: Yes
    	Read-only: No
    	Bus: 'ata'
    	Vendor: 'TSSTcorp'
    	Model: 'TSSTcorp_CDDVDW_SH-S202N'
    	Serial: 'TSSTcorp_CDDVDW_SH-S202N'
    	Revision: 'SB01' (udev)
    	Revision: 'SB01' (sys)
    	Read: 0 requests, 0 MiB
    	Written: 0 requests, 0 MiB
    The output actually includes logical devices like /dev/loop0 and so on, but I left those out for brevity. The statistics are only since the last bootup, of course. (These HD103UJ's actually have almost three years of power on time according to SMART attributes.)

    If portability were desired, I'd still recommend the two-script approach. With that, you could port the program to Busybox-based Linux distros (which have minimal udev support), and to even e.g. FreeBSD, just by using different scripts. As it is, the this program relies on both Linux kernel features (/sys hierarchy) and libudev.

    (But, since the OP mentioned this is only going to run on a customized Linux distribution, and if systemd-based udev is used, this is probably the easiest to maintain in the long run. Any udev updates or changes are handled by libudev, and the kernel interfaces are extremely unlikely to change in a way that would break interoperability.)
    thomas23 likes this.

  8. #8
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    is it possible to use it via the path of the device? my entire code is set-up to use the path as the identifier. I must admit I have 0 experience with udev. it seems to mee it uses a struct called 'device' as identification.

  9. #9
    Registered User
    Join Date
    Oct 2006
    Posts
    2,407
    keep in mind that if the drive is part of a RAID array, chances are you won't see the physical drive itself, but rather the array or logical drive.
    Code:
    namespace life
    {
        const bool change = true;
    }

  10. #10
    Registered User
    Join Date
    Oct 2011
    Posts
    847
    Elkvis had an excellent point. Some SAN (and hardware RAID) drivers are known to organize the storage in weird ways, which may complicate or hinder listing them correctly. However, using the device node (path to /dev/DEVICE or whatever it happens to be), should cut right through all that complexity. (Obviously you don't get access to any physical disks (unless it's a JBOD configured to do exactly that), but you certainly get access to exactly what the userspace uses, without any risk of confusion, and I think that's what's important here.) I think it is a good idea to use it as the identifier, thomas23.

    (Side note: udev uses "device path" to refer to the exact path in /sys hierarchy, whereas "device node" refers to the path in /dev. I'll try to keep to that same naming here.)

    If you have a device node, you can stat() it (to find out whether it is a block ('b' type) or character ('c' type) device, and the device ID (== packed major and minor numbers)). With those, you can use udev_device_new_from_devnum() to get a reference to the actual udev device.

    The below example defines udev_device_new_from_filename(), which does exactly that. It's not a perfect name, but I couldn't think of a better one just now. Also, it does require the device node to already exist. It works for all devices udev knows about, not just block devices.

    Code:
    #define  _POSIX_C_SOURCE 200809L
    #define  _BSD_SOURCE
    #include <stdlib.h>
    #include <stdint.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    #include <errno.h>
    #include <libudev.h>
    
    /* Save this file as example.c,
     * then compile using
     *      gcc -W -Wall -O3 example.c -ludev -o example
     *
     * Supply device file names as parameters to get their details.
    */
    
    struct udev_device *udev_device_new_from_filename(struct udev *const udevhandle,
                                                      const char *const filename)
    {
        struct stat info;
        struct udev_device *dev;
        int saved_errno, result;
        char type;
        dev_t devnum;
    
        saved_errno = errno;
    
        if (!filename || !*filename) {
            errno = EINVAL;
            return NULL;
        }
    
        /* Obtain the information on the specified filename. */
        result = stat(filename, &info);
        if (result == -1)
            return NULL; /* errno set by stat() call. */
    
        /* Construct udev device id. */
        if (S_ISBLK(info.st_mode)) {
            /* Block device. */
            type = 'b';
            devnum = info.st_rdev;
        } else
        if (S_ISCHR(info.st_mode)) {
            /* Character device. */
            type = 'c';
            devnum = info.st_rdev;
        } else {
            errno = ENODEV;
            return NULL;
        }
    
        /* No udev handle specified?
         * (Note: this way users can call (NULL, filename) to see
         *        if a filename might refer to a device.) */
        if (!udevhandle) {
            errno = EINVAL;
            return NULL;
        }
    
        /* Obtain udev device handle. */
        errno = ENOTSUP;
        dev = udev_device_new_from_devnum(udevhandle, type, devnum);
        if (!dev)
            return NULL; /* Hopefully errno set by the above call. */
    
        /* Success. */
        errno = saved_errno;
        return dev;
    }
    
    long long stoll(const char *const str, const long long invalid)
    {
        long long result;
        int saved_errno;
    
        if (!str || !*str)
            return invalid;
    
        saved_errno = errno;
        errno = 0;
    
        result = strtoll(str, NULL, 10);
        if (errno) {
            errno = saved_errno;
            return invalid;
        }
    
        errno = saved_errno;
        return result;
    }
    
    int main(int argc, char *argv[])
    {
        struct udev *udevhandle;
        struct udev_device *dev;
        const char *s;
        long long v;
        int arg;
    
        if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
            fprintf(stderr, "\n");
            fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
            fprintf(stderr, "       %s /dev/DEVICE ...\n", argv[0]);
            fprintf(stderr, "\n");
            return 1;
        }
    
        udevhandle = udev_new();
    
        for (arg = 1; arg < argc; arg++) {
    
            dev = udev_device_new_from_filename(udevhandle, argv[arg]);
            if (!dev) {
                const char *const errmsg = strerror(errno);
                fflush(stdout);
                fprintf(stderr, "%s: %s.\n", argv[arg], errmsg);
                udev_unref(udevhandle);
                return 1;
            }
    
            printf("%s:\n", argv[arg]);
    
            if ((s = udev_device_get_subsystem(dev)))
                printf("\tSubsystem: '%s'\n", s);
            if ((s = udev_device_get_property_value(dev, "ID_BUS")))
                printf("\tBus: '%s'\n", s);
            if ((v = stoll(udev_device_get_sysattr_value(dev, "size"), -2048LL) / 2048LL) >= 0LL)
                printf("\tSize: %lld MiB\n", v);
            if ((s = udev_device_get_devtype(dev)))
                printf("\tType: '%s'\n", s);
            if ((s = udev_device_get_sysattr_value(dev, "device/vendor")))
                printf("\tVendor: '%s'\n", s);
            if ((s = udev_device_get_property_value(dev, "ID_MODEL")))
                printf("\tModel: '%s'\n", s);
            if ((s = udev_device_get_property_value(dev, "ID_SERIAL")))
                printf("\tSerial: '%s'\n", s);
            if ((s = udev_device_get_property_value(dev, "ID_SERIAL_SHORT")))
                printf("\tShort serial: '%s'\n", s);
            if ((s = udev_device_get_property_value(dev, "ID_REVISION")))
                printf("\tRevision: '%s'\n", s);
    
            udev_device_unref(dev);
        }
    
        udev_unref(udevhandle);
    
        return 0;
    }
    Hope this helps.
    Last edited by Nominal Animal; 02-18-2014 at 03:52 PM.

  11. #11
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    thank you. I will have to buy you a beer sometime

    I wonder though how udev accomplishes this though. I can't seem to find the source for the udev codebase

  12. #12
    Registered User
    Join Date
    Oct 2011
    Posts
    847
    Quote Originally Posted by thomas23 View Post
    I will have to buy you a beer sometime
    Well, if you happen to come to Helsinki, Finland, I'm up for a beer or two, and exchanging some "war stories"..

    Quote Originally Posted by thomas23 View Post
    I wonder though how udev accomplishes this though.
    The Wikipedia udev article contains a pretty good overview. The kernel provides most of the information in the uevent messages it provides for udev when it finds each device.

    For ATA, SCSI, and CD-ROM devices, udev does contain code to probe the block devices deeper, to obtain for example the serial number (which is not included in the data provided by the kernel, since the kernel does not probe for it itself). These implementations are found in src/udev/ata_id/ata_id.c, src/udev/scsi_id/, and src/udev/cdrom_id/cdrom_id.c, respectively, in the systemd sources. Of these, you'll likely find the scsi_get_serial() and scsi_inquiry() functions in src/udev/scsi_id/scsi_serial.c most interesting, as it is the implementation of the actual SCSI probing via an SG_IO ioctl().

    The information the abovementioned files obtain from the block devices is included in udev properties.

    All of the SAN systems I've managed to get my mittens on have been based on SCSI or SATA disks, with controllers that support the above SCSI ioctl() for basic information at least. However, I don't currently manage any Linux HPC clusters, and do not even have any proper SAN hardware to test with, so my knowledge might be a year or two out of date. And besides, I find the simulation development side much more interesting than cluster management.

    Quote Originally Posted by thomas23 View Post
    I can't seem to find the source for the udev codebase
    It was merged into systemd, so grab the latest systemd-###.tar.xz tar archive (systemd-209.tar.xz as of 2014-02-19), see the src/libudev/ and src/udev/ directories in it.

  13. #13
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    Finland looks nice, but really cold especially this time of year

    Simulations are cool. I study physics currently which is all about simulating the universe with mathematics.

    Anyway it seems that on the OS I use, udev is kind of weird. It does not return an ID_MODEL,ID_SERIAL or ID_SERIAL_SHORT for ANY drive. be it SATA,SAS or even USB. It works perfectly on vms... its some hardware back from work so I can test at home since I usually am only a few hours a week onsite. I will try a few different OS`s and play a little with udevadm monitor and such. I will keep you guys posted I guess.

  14. #14
    Registered User
    Join Date
    Feb 2014
    Posts
    18
    it seems my OS was the one who didn`t provide ID_MODEL,ID_SERIAL or ID_SERIAL_SHORT.

    I switched to debian and it is fine...

    thanks for the help

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to get Memory Address of a File in HardDisk
    By zacless in forum C Programming
    Replies: 1
    Last Post: 09-12-2013, 11:13 PM
  2. Replies: 3
    Last Post: 04-08-2011, 06:26 AM
  3. Send and Recive Information through the serial Port RS232
    By amigoloko in forum C# Programming
    Replies: 4
    Last Post: 04-14-2006, 12:34 PM
  4. Looking for a file in the HardDisk
    By BianConiglio in forum C Programming
    Replies: 11
    Last Post: 03-15-2004, 11:52 AM
  5. Speed of Harddisk
    By Kelvin in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 07-16-2002, 04:45 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21