/* * ata_id - reads product/serial number from ATA drives * * Copyright (C) 2005-2008 Kay Sievers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libudev.h" #include "libudev-private.h" static void log_fn(struct udev *udev, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { vsyslog(priority, format, args); } int main(int argc, char *argv[]) { struct udev *udev; struct hd_driveid id; char model[41]; char model_enc[256]; char serial[21]; char revision[9]; const char *node = NULL; int export = 0; int fd; int rc = 0; static const struct option options[] = { { "export", no_argument, NULL, 'x' }, { "help", no_argument, NULL, 'h' }, {} }; udev = udev_new(); if (udev == NULL) goto exit; udev_log_init("ata_id"); udev_set_log_fn(udev, log_fn); while (1) { int option; option = getopt_long(argc, argv, "xh", options, NULL); if (option == -1) break; switch (option) { case 'x': export = 1; break; case 'h': printf("Usage: ata_id [--export] [--help] \n" " --export print values as environment keys\n" " --help print this help text\n\n"); default: rc = 1; goto exit; } } node = argv[optind]; if (node == NULL) { err(udev, "no node specified\n"); rc = 1; goto exit; } fd = open(node, O_RDONLY|O_NONBLOCK); if (fd < 0) { err(udev, "unable to open '%s'\n", node); rc = 1; goto exit; } if (ioctl(fd, HDIO_GET_IDENTITY, &id)) { if (errno == ENOTTY) { info(udev, "HDIO_GET_IDENTITY unsupported for '%s'\n", node); rc = 2; } else { err(udev, "HDIO_GET_IDENTITY failed for '%s'\n", node); rc = 3; } goto close; } memcpy (model, id.model, 40); model[40] = '\0'; udev_util_encode_string(model, model_enc, sizeof(model_enc)); udev_util_replace_whitespace((char *) id.model, model, 40); udev_util_replace_chars(model, NULL); udev_util_replace_whitespace((char *) id.serial_no, serial, 20); udev_util_replace_chars(serial, NULL); udev_util_replace_whitespace((char *) id.fw_rev, revision, 8); udev_util_replace_chars(revision, NULL); if (export) { if ((id.config >> 8) & 0x80) { /* This is an ATAPI device */ switch ((id.config >> 8) & 0x1f) { case 0: printf("ID_TYPE=cd\n"); break; case 1: printf("ID_TYPE=tape\n"); break; case 5: printf("ID_TYPE=cd\n"); break; case 7: printf("ID_TYPE=optical\n"); break; default: printf("ID_TYPE=generic\n"); break; } } else { printf("ID_TYPE=disk\n"); } printf("ID_BUS=ata\n"); printf("ID_MODEL=%s\n", model); printf("ID_MODEL_ENC=%s\n", model_enc); printf("ID_REVISION=%s\n", revision); printf("ID_SERIAL=%s_%s\n", model, serial); printf("ID_SERIAL_SHORT=%s\n", serial); } else { if (serial[0] != '\0') printf("%s_%s\n", model, serial); else printf("%s\n", model); } close: close(fd); exit: udev_unref(udev); udev_log_close(); return rc; }