int main(int argc, char** argv) { char *dev = "/dev/sda"; if( argc > 1 ) dev = argv[1]; char scsi_serial[255]; int rc; int fd; fd = open(dev, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror(dev); } memset(scsi_serial, 0, sizeof (scsi_serial)); rc = scsi_get_serial(fd, scsi_serial, 255); // scsi_serial[3] is the length of the serial number // scsi_serial[4] is serial number (raw, NOT null terminated) if (rc < 0) { printf("FAIL, rc=%d, errno=%d\n", rc, errno); } else if (rc == 1) { printf("FAIL, rc=%d, drive doesn't report serial number\n", rc); } else { if (!scsi_serial[3]) { printf("Failed to retrieve serial for %s\n", dev); return -1; } printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]); } close(fd); return (EXIT_SUCCESS); }
/* * scsi_id: try to get an id, if one is found, printf it to stdout. * returns a value passed to exit() - 0 if printed an id, else 1. */ static int scsi_id(char *maj_min_dev) { struct scsi_id_device dev_scsi = {}; int good_dev; int page_code; int retval = 0; if (set_inq_values(&dev_scsi, maj_min_dev) < 0) { retval = 1; goto out; } /* get per device (vendor + model) options from the config file */ per_dev_options(&dev_scsi, &good_dev, &page_code); if (!good_dev) { retval = 1; goto out; } /* read serial number from mode pages (no values for optical drives) */ scsi_get_serial(&dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); if (export) { char serial_str[MAX_SERIAL_LEN]; printf("ID_SCSI=1\n"); printf("ID_VENDOR=%s\n", vendor_str); printf("ID_VENDOR_ENC=%s\n", vendor_enc_str); printf("ID_MODEL=%s\n", model_str); printf("ID_MODEL_ENC=%s\n", model_enc_str); printf("ID_REVISION=%s\n", revision_str); printf("ID_TYPE=%s\n", type_str); if (dev_scsi.serial[0] != '\0') { util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); util_replace_chars(serial_str, NULL); printf("ID_SERIAL=%s\n", serial_str); util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)-1); util_replace_chars(serial_str, NULL); printf("ID_SERIAL_SHORT=%s\n", serial_str); } if (dev_scsi.wwn[0] != '\0') { printf("ID_WWN=0x%s\n", dev_scsi.wwn); if (dev_scsi.wwn_vendor_extension[0] != '\0') { printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension); printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension); } else printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn); } if (dev_scsi.tgpt_group[0] != '\0') printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group); if (dev_scsi.unit_serial_number[0] != '\0') printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); goto out; } if (dev_scsi.serial[0] == '\0') { retval = 1; goto out; } if (reformat_serial) { char serial_str[MAX_SERIAL_LEN]; util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); util_replace_chars(serial_str, NULL); printf("%s\n", serial_str); goto out; } printf("%s\n", dev_scsi.serial); out: return retval; }
/* * scsi_id: try to get an id, if one is found, printf it to stdout. * returns a value passed to exit() - 0 if printed an id, else 1. This * could be expanded, for example, if we want to report a failure like no * memory etc. return 2, and return 1 for expected cases (like broken * device found) that do not print an id. */ static int scsi_id(const char *devpath, char *maj_min_dev) { int retval; int dev_type = 0; char *serial, *unaligned_buf; struct sysfs_device *dev; struct sysfs_device *dev_scsi; int good_dev; int page_code; dbg("devpath %s\n", devpath); dev = sysfs_device_get(devpath); if (dev == NULL) { err("unable to access '%s'", devpath); return 1; } if (strcmp(dev->subsystem, "block") == 0) dev_type = S_IFBLK; else dev_type = S_IFCHR; /* get scsi parent device */ dev_scsi = sysfs_device_get_parent_with_subsystem(dev, "scsi"); if (dev_scsi == NULL) { err("unable to access parent device of '%s'", devpath); return 1; } /* mknod a temp dev to communicate with the device */ if (!dev_specified && create_tmp_dev(dev->devpath, maj_min_dev, dev_type)) { dbg("create_tmp_dev failed\n"); return 1; } /* get per device (vendor + model) options from the config file */ retval = per_dev_options(dev_scsi, &good_dev, &page_code); dbg("per dev options: good %d; page code 0x%x", good_dev, page_code); #define ALIGN 512 unaligned_buf = malloc(MAX_SERIAL_LEN + ALIGN); serial = (char*) (((unsigned long) unaligned_buf + (ALIGN - 1)) & ~(ALIGN - 1)); dbg("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial); #undef ALIGN if (!good_dev) { retval = 1; } else if (scsi_get_serial(dev_scsi, maj_min_dev, page_code, serial, MAX_SERIAL_LEN)) { retval = always_info?0:1; } else { retval = 0; } if (!retval) { if (export) { static char serial_str[64]; printf("ID_VENDOR=%s\n", vendor_str); printf("ID_MODEL=%s\n", model_str); printf("ID_REVISION=%s\n", revision_str); set_str(serial_str, serial, sizeof(serial_str)); printf("ID_SERIAL=%s\n", serial_str); printf("ID_TYPE=%s\n", type_str); printf("ID_BUS=scsi\n"); } else { if (reformat_serial) format_serial(serial); if (display_bus_id) printf("%s: ", dev_scsi->kernel); printf("%s\n", serial); } dbg("%s\n", serial); retval = 0; }