12
Hard Disk Metadata Hard Disk Metadata Finnbarr P. Murphy ([email protected])  Recently I was asked how to programmatically retrieve the serial number of a hard disk using C++ on a GNU/Linux platform. After a small amount of research, I wrote a short demonstration program and that was that or so I thought. However my curiosity was picqued and I decided to look at how to extract other metadata from a hard disk. To satisfy this curiosity I wrote a small utility that outputs selected metadata from hard disk in a number of formats, i.e. XML, TEXT and CSV (Comma Separated Values). Here is example of the output in TEXT mode: # ./hdm /dev/sda DEVICE: /dev/sda ---------------- Manufacturer Model: Hitachi HDP725050GLA360 Serial Number: GEA534RF1MUN5A Firmware Revision: GM4OA52A Transport Type: SATA Rev 2.6 Maximum RPM: 7200 Capacity: 500GB Number Cylinders: 60801 Partition Type: gpt No. Start End Size Type Filesystem Name Flags 01 17.9kB 210MB 210MB primary fat16 boot 02 210MB 419MB 210MB primary ext4 03 419MB 500GB 500GB primary lvm # You may be wondering what this disk is used for. It happens to be the boot disk for the Fedora 13 platform which I used to write this article. It uses GPT (GUID Partition Table) rather than the more common MBR partitioning scheme. I use EFI and GRUB2 instead of the traditional BIOS and Legacy GRUB to boot the operating system – hence the FAT16 partition for the ESP (EFI System Partition). As an aside, I like this arrangment because of the significantly faster boot time. The Fedora 13 initrd and kernel images and related files are on the second partition and the third partition is a logical volume which is split into a number of filesystems . If you look closely at the above output, you will see that it contains both the output from a utility such as hdparms or lshw and a partitioning utility such as gdisk or parted. Here is the XML output in newline mode for the same disk: [root@ultra hdparm]# ./hdm -x /dev/sda <disk dev="/dev/sda"><model>Hitachi HDP725050GLA360</model><serialno>GEA534RF1MUN5A</seria lno><firmware>GM4OA52A</firmware><t ransport>SAT A Rev 2.6</transport><rpm>7200</rpm><capaci ty>500GB</capacity><geometry><cylinders>60801</cylinders><heads>255</heads><sectors>63</se ctors></geom etry><parti tiontype>gpt <paritiontyp e><partitio ns><partitio n number="1"><start> 17.9kB</start><end>210MB</end><size>210MB</size><type>primary</type><filesystem>fat16</fil esystem><label></label><flags>boot</flags></partition><partition number="2"><start>210MB</ start><end>419MB</end><size>210MB</size><type>primary</type><filesystem>ext4</filesystem>< label></label><flags></flags></partition><partition number="3"><start>419MB</start><end>50 0GB</end><size>500GB</size><type>primary</type><filesystem></filesystem><label></label><fl ags>lvm</flags></partition></partitions></disk>[root@ultra hdparm]# 03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 1/12

Hard Disk Metadata

Embed Size (px)

Citation preview

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 1/12

Hard Disk Metadata

Hard Disk MetadataFinnbarr P. Murphy 

([email protected])

 

Recently I was asked how to programmatically retrieve the serial number of a hard disk using

C++ on a GNU/Linux platform. After a small amount of research, I wrote a short demonstration

program and that was that or so I thought. However my curiosity was picqued and I decided to

look at how to extract other metadata from a hard disk. To satisfy this curiosity I wrote a small

utility that outputs selected metadata from hard disk in a number of formats, i.e. XML, TEXT and

CSV (Comma Separated Values).

Here is example of the output in TEXT mode:

# ./hdm /dev/sda

DEVICE: /dev/sda

----------------

Manufacturer Model: Hitachi HDP725050GLA360

Serial Number: GEA534RF1MUN5A

Firmware Revision: GM4OA52A

Transport Type: SATA Rev 2.6

Maximum RPM: 7200

Capacity: 500GB

Number Cylinders: 60801

Partition Type: gpt

No. Start End Size Type Filesystem Name Flags

01 17.9kB 210MB 210MB primary fat16 boot

02 210MB 419MB 210MB primary ext403 419MB 500GB 500GB primary lvm

#

You may be wondering what this disk is used for. It happens to be the boot disk for the Fedora 13

platform which I used to write this article. It uses GPT (GUID Partition Table) rather than the

more common MBR partitioning scheme. I use EFI and GRUB2 instead of the traditional BIOS and

Legacy GRUB to boot the operating system – hence the FAT16 partition for the ESP (EFI System

Partition). As an aside, I like this arrangment because of the significantly faster boot time. The

Fedora 13 initrd and kernel images and related files are on the second partition and the third

partition is a logical volume which is split into a number of filesystems. If you look closely at the

above output, you will see that it contains both the output from a utility such as hdparms or lshwand a partitioning utility such as gdisk or parted.

Here is the XML output in newline mode for the same disk:

[root@ultra hdparm]# ./hdm -x /dev/sda

<disk dev="/dev/sda"><model>Hitachi HDP725050GLA360</model><serialno>GEA534RF1MUN5A</seria

lno><firmware>GM4OA52A</firmware><transport>SATA Rev 2.6</transport><rpm>7200</rpm><capaci

ty>500GB</capacity><geometry><cylinders>60801</cylinders><heads>255</heads><sectors>63</se

ctors></geometry><partitiontype>gpt<paritiontype><partitions><partition number="1"><start>

17.9kB</start><end>210MB</end><size>210MB</size><type>primary</type><filesystem>fat16</fil

esystem><label></label><flags>boot</flags></partition><partition number="2"><start>210MB</

start><end>419MB</end><size>210MB</size><type>primary</type><filesystem>ext4</filesystem><label></label><flags></flags></partition><partition number="3"><start>419MB</start><end>50

0GB</end><size>500GB</size><type>primary</type><filesystem></filesystem><label></label><fl

ags>lvm</flags></partition></partitions></disk>[root@ultra hdparm]#

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 1/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 2/12

Hard Disk Metadata

Here is the regular XML output for the same disk:

# ./hdm -x -n /dev/sda

<disk dev="/dev/sda">

<model>Hitachi HDP725050GLA360</model>

<serialno>GEA534RF1MUN5A</serialno>

<firmware>GM4OA52A</firmware>

<transport>SATA Rev 2.6</transport>

<rpm>7200</rpm>

<capacity>500GB</capacity>

<geometry>

<cylinders>60801</cylinders>

<heads>255</heads>

<sectors>63</sectors>

</geometry>

<partitiontype>gpt<paritiontype>

<partitions>

<partition number="1">

<start>17.9kB</start>

<end>210MB</end>

<size>210MB</size>

<type>primary</type>

<filesystem>fat16</filesystem>

<label></label>

<flags>boot</flags>

</partition>

<partition number="2">

<start>210MB</start>

<end>419MB</end>

<size>210MB</size>

<type>primary</type>

<filesystem>ext4</filesystem>

<label></label>

<flags></flags>

</partition>

<partition number="3">

<start>419MB</start>

<end>500GB</end>

<size>500GB</size>

<type>primary</type>

<filesystem></filesystem>

<label></label>

<flags>lvm</flags>

</partition>

</partitions>

</disk>

#

And, finally, here is the output for the same disk in CSV mode:

# ./hdm -c /dev/sda

"Hitachi HDP725050GLA360","GEA534RF1MUN5A","GM4OA52A","SATA Rev 2.6","7200","500GB","60801"

,"255","63"","gpt","01","17.9kB","210MB","210MB","primary","fat16","","boot","02","210MB",

"419MB","210MB","primary","ext4","","","03","419MB","500GB","500GB","primary","","","lvm"[

root@ultra hdparm]

#

I decided to use the routines in libparted to retrieve and manipulate the partitioning information.All these routines start with ped_ and are contained within the dump_partition() routine. Many of 

the ped_ routines return pointers to allocated memory (which contains ASCII strings) and

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 2/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 3/12

Hard Disk Metadata

therefore you need to free up this space after use.

For hardware information such as the serial number and firmware revision, it is necessary to use

and ioctl to retrieve the information. GNU/Linux provides a number of  ioctls and structures for

reading and writ ing metadata and control l ing disks. These are detai led in

/usr/include/linux/hdreg.h .

#define HDIO_GETGEO 0x0301 /* get device geometry */

#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */

#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */

#define HDIO_GET_QDMA 0x0305 /* get use-qdma flag */

#define HDIO_SET_XFER 0x0306 /* set transfer rate via proc */

#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */

#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */

#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */

#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */

#define HDIO_GET_DMA 0x030b /* get use-dma flag */

#define HDIO_GET_NICE 0x030c /* get nice flags */

#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */

#define HDIO_GET_WCACHE 0x030e /* get write cache mode on|off */#define HDIO_GET_ACOUSTIC 0x030f /* get acoustic value */

#define HDIO_GET_ADDRESS 0x0310 /* */

#define HDIO_GET_BUSSTATE 0x031a /* get the bus state of the hwif */

#define HDIO_TRISTATE_HWIF 0x031b /* execute a channel tristate */

#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */

#define HDIO_DRIVE_TASKFILE 0x031d /* execute raw taskfile */

#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */

#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */

#define HDIO_DRIVE_CMD_AEB HDIO_DRIVE_TASK

/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */

#define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */

#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */

#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */

#define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */#define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */

#define HDIO_SET_DMA 0x0326 /* change use-dma flag */

#define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */

#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */

#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */

#define HDIO_SET_NICE 0x0329 /* set nice flags */

#define HDIO_SET_WCACHE 0x032b /* change write cache enable-disable */

#define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */

#define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */

#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */

#define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */

The ioctls that I used in the util ity are HDIO_DRIVE_CMD, HDIO_GETGEO andHDIO_GET_IDENTITY. The last two ioctls are relativly simple to use. HDIO_DRIVE_CMD, on the

other hard, is a complicated routine like many other general purpose ioctls. Read

kernel/Documentation/ioctl/hdio.txt for detailed information and examine the code in

drivers/ide/ide.c and drivers/block/scsi_ioctl.c for starters and look at the various published hard

disk interface specifications. I fully agree with the warning in the section on the

HDIO_DRIVE_CMD ioctl, that “If you don’t have a copy of the ANSI ATA specification handy, you

should probably ignore this ioctl.”

Here are the inputs and outputs for HDIO_DRIVE_CMD:

__u8[4+512}

ioctl(fd, HDIO_DRIVE_CMD, args);

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 3/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 4/12

Hard Disk Metadata

INPUTS:

args[0] COMMAND

args[1] NSECTOR

args[2] FEATURE

args[3] NSECTOR

OUTPUTS:

args[0] status

args[1] error

args[2] NSECTOR

args[3] undefined

args[4+] NSECTOR * 512 bytes of data returned by the command.

When a drive is sent the IDENTIFY_DRIVE (0xEC) command, it returns 256 words (512 bytes) of 

information. The words are numbered 0-255. Word 255 is the checksum and signature (0xA5). For

ASCII strings each word contains two characters, the high order byte the first, the low order byte

the second. For 32-bit values the low order word is first. That is why I used the kernel

__le16_to_cpus() routine to byte swap the words.

Look at the get_diskinfo() routine for a working example of HDIO_DRIVE_CMD, main() for

HDIO_GET_IDENTITY and get_geometry() for HDIO_GETGEO. Note that the CHS (Cylinder Head

Sector) values returned by HDIO_GETGEO may or may not be accurate. It also has a 2TB limit for

the starting sector offset of a hard disk partition. A better way is to use the default LBA (Logical

Block Addressing) capacity value returned in words 57-58 or the current LBA capacity value

returned in words 60-61, or better still the maximum capacity returned in LBA48 (words 100-103),

after a successful HDIO_DRIVE_CMD IDENTIFY_DRIVE command. You can use

HDIO_GET_ADDRESS to figure out the current addressing mode. I show you 2 ways of 

determining the capacity in the get_capacity() routine.

Here is the source code for the utility:

/*

* hdm.c - Hard Disk Metadata

*

* Copyright (C) Finnbarr P. Murphy 2010 <fpm[AT]fpmurphy.com>

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License Version 2 as

* published by the Free Software Foundation.

*

* 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.*

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <fcntl.h>

#include <getopt.h>

#include <linux/fs.h>

#include <asm/byteorder.h>

#include <sys/ioctl.h>

#include <linux/hdreg.h>

#include <parted/parted.h>

#define DUMPXML 1#define DUMPTXT 2

#define DUMPCSV 3

#define NONEWLINE 0

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 4/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 5/12

Hard Disk Metadata

#define DI_VERSION "1.0"

#define TRANSPORT_MAJOR 0xDE

#define TRANSPORT_MINOR 0xDF

#define ATA_PIDENTIFY 0xA1

#define ATA_IDENTIFY 0xEC

#define NMRR 0xD9

#define CAPAB 0x31

#define CMDS_SUPP_1 0x53

#define VALID 0xC000#define VALID_VAL 0x4000

#define SUPPORT_48_BIT 0x0400

#define LBA_SUP 0x0200

#define LBA_LSB 0x64

#define LBA_MID 0x65

#define LBA_48_MSB 0x66

#define LBA_64_MSB 0x67

/* yes - these are shortcuts! */

static __u16 *id = (void *)NULL;

static struct hd_geometry *g;

static int fd = 0;

struct hd_geometry *

get_geometry(int fd)

{static struct hd_geometry geometry;

if (ioctl(fd, HDIO_GETGEO, &amp;geometry)) {

perror("ERROR: HDIO_GETGEO failed");

}

return &amp;geometry;

}

void *

get_diskinfo(int fd)

{

static __u8 args[4+512];

__u16 *id = (void *)(args + 4);

int i;

memset(args, 0, sizeof(args));

args[0] = ATA_IDENTIFY;args[3] = 1;

if (ioctl(fd, HDIO_DRIVE_CMD, args)) {

args[0] = ATA_PIDENTIFY;

args[1] = 0;

args[2] = 0;

args[3] = 1;

if (ioctl(fd, HDIO_DRIVE_CMD, args)) {

perror("ERROR: HDIO_DRIVE_CMD failed");

return "";

}

}

/* byte-swap data to match host endianness */

for (i = 0; i < 0x100; ++i)

__le16_to_cpus(&amp;id[i]);return id;

}

//

// Routine currently only handles SATA drives. Extra code needs to be added to support PA

TA, SCSI, USB, etc.

//

char *

get_transport(__u16 id[])

{

__u16 major, minor;

unsigned int ttype, stype;

major = id[TRANSPORT_MAJOR];

minor = id[TRANSPORT_MINOR];

if (major == 0x0000 || major == 0xffff)return "";

ttype = major >> 12; /* transport type */

stype = major &amp; 0xfff; /* subtype */

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 5/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 6/12

Hard Disk Metadata

if (ttype == 1) {

if (stype &amp; 0x2f) {

if (stype &amp; (1<<5))

return "SATA Rev 3.0";

else if (stype &amp; (1<<4))

return "SATA Rev 2.6";

else if (stype &amp; (1<<3))

return "SATA Rev 2.5";

else if (stype &amp; (1<<2))return "SATA II Extensions";

else if (stype &amp; (1<<1))

return "SATA 1.0a";

}

}

}

char *

get_rpm(__u16 id[])

{

static char str[6];

__u16 i = id[NMRR];

sprintf(str,"%u", i);

return str;

}char *

ascii_string(__u16 *p,

unsigned int len)

{

__u8 i, c;

char cl;

static char str[60];

char *s = str;

memset(&amp;str, 0, sizeof(str));

/* find first character */

for (i = 0; i < len; i++) {

if (( (char)0x00ff &amp; ((*p) >> 8)) != ' ')

break;

if ((cl = (char) 0x00ff &amp; (*p)) != ' ') {if (cl != '&#92;&#48;') *s++ = cl;

p++; i++;

break;

}

p++;

}

/* copy from here to end */

for (; i < len; i++) {

c = (*p) >> 8;

if (c) *s++ = c;

c = (*p);

if (c) *s++ = c;

p++;

}/* remove trailing blanks */

s = str;

while(*s) s++;

while(*--s == ' ') *s= 0;

return str;

}

#define USE_CAPAB

char *

get_capacity(int fd, __u16 id[])

{

unsigned int sector_bytes = 512;

static char str[20];

__u64 sectors = 0;

#ifdef USE_CAPABmemset(&amp;str, 0, sizeof(str));

if (id[CAPAB] &amp; LBA_SUP) {

if (((id[CMDS_SUPP_1] &amp; VALID) == VALID_VAL) &amp;&amp; (id[CMDS_SUPP_1] &amp;

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 6/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 7/12

Hard Disk Metadata

SUPPORT_48_BIT) ) {

sectors = (__u64)id[LBA_64_MSB] << 48 | (__u64)id[LBA_48_MSB] << 32 |

(__u64)id[LBA_MID] << 16 | id[LBA_LSB] ;

}

}

#else

unsigned int sector32 = 0;

if (!(ioctl(fd, BLKGETSIZE64, &amp;sectors))) { // bytes

sectors /= sector_bytes;} else if (!(ioctl(fd, BLKGETSIZE, &amp;sector32))) { // sectors

sectors = sector32;

} else

return "";

#endif

sectors *= (sector_bytes /512);

sectors = (sectors << 9)/1000000;

if (sectors > 1000)

sprintf(str, "%lluGB", (unsigned long long) sectors/1000);

else

sprintf(str, "%lluMB", (unsigned long long) sectors);

return str;

}

voiddump_partitions(char *device, int dumpmode, int nlmode)

{

PedDevice *dev = (PedDevice *)NULL;

PedDiskType* type;

PedDisk* disk = (PedDisk *)NULL;

PedPartition* part;

PedPartitionFlag flag;

PedUnit default_unit;

int has_free_arg = 0;

char *start;

char *end;

char *size;

char flags[100];

const char *partname;const char *parttype;

const char *partlabel;

const char *partflags;

int first_flag;

dev = ped_device_get(device);

if (!ped_device_open (dev)) {

fprintf(stderr, "ERROR: ped-device-opem\n");

exit(1);

}

disk = ped_disk_new(dev);

if (!disk) {

fprintf(stderr, "ERROR: ped-disk-new\n");

exit(1);

}start = ped_unit_format(dev, 0);

default_unit = ped_unit_get_default();

end = ped_unit_format_byte (dev, dev->length * dev->sector_size

- (default_unit == PED_UNIT_CHS || default_unit == PED_UNIT_CYLINDER));

switch (dumpmode) {

case DUMPXML:

if (nlmode) printf("\n ");

printf("<partitiontype>%s<paritiontype>", disk->type->name);

if (nlmode) printf("\n ");

printf("<partitions>");

break;

case DUMPTXT:

printf(" Partition Type: %s\n", disk->type->name);

printf(" No. Start End Size Type Filesystem Name Flags\n");

break;

case DUMPCSV:

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 7/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 8/12

Hard Disk Metadata

putchar('"'); putchar(','); putchar('"');

printf("%s", disk->type->name );

break;

}

free(start);

free(end);

for (part = ped_disk_next_partition (disk, NULL); part;

part = ped_disk_next_partition (disk, part)) {

if ((!has_free_arg &amp;&amp; !ped_partition_is_active(part)) ||part->type &amp; PED_PARTITION_METADATA)

continue;

start = ped_unit_format (dev, part->geom.start);

end = ped_unit_format_byte (dev, (part->geom.end + 1) * (dev)->sector_size - 1);

size = ped_unit_format (dev, part->geom.length);

if (!(part->type &amp; PED_PARTITION_FREESPACE)) {

parttype = ped_partition_type_get_name (part->type);

partlabel = ped_partition_get_name(part);

} else {

parttype = "";

partlabel = "";

}

// flags

memset(&amp;flags, 0, sizeof(flags));first_flag = 1;

for (flag = ped_partition_flag_next(0); flag;

flag = ped_partition_flag_next(flag)) {

if (ped_partition_get_flag(part, flag)) {

if (first_flag) {

first_flag = 0;

} else {

strcat (flags, ", ");

}

partflags = ped_partition_flag_get_name(flag);

strcat(flags, partflags);

}

}

switch (dumpmode) {case DUMPXML:

if (nlmode) printf("\n ");

if (part->num >= 0)

printf("<partition number=\"%d\">", part->num);

else

printf("<partition number=\"0\">");

if (nlmode) printf("\n ");

printf("<start>%s</start>", start);

if (nlmode) printf("\n ");

printf("<end>%s</end>", end);

if (nlmode) printf("\n ");

printf("<size>%s</size>", size);

if (nlmode) printf("\n ");

printf("<type>%s</type>", parttype);if (nlmode) printf("\n ");

printf("<filesystem>%s</filesystem>", part->fs_type ? part->fs_type->name

: "");

if (nlmode) printf("\n ");

printf("<label>%s</label>", partlabel);

if (nlmode) printf("\n ");

printf("<flags>%s</flags>", flags);

if (nlmode) printf("\n ");

printf("</partition>");

break;

case DUMPTXT:

if (part->num >= 0)

printf(" %02d", part->num);

elseprintf(" ");

printf(" %6s %6s %6s %10s", start, end, size, parttype);

printf(" %6s", part->fs_type ? part->fs_type->name : "");

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 8/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 9/12

Hard Disk Metadata

printf(" %10s %s\n", partlabel, flags);

break;

case DUMPCSV:

putchar('"'); putchar(','); putchar('"');

if (part->num >= 0) printf("%02d", part->num);

putchar('"'); putchar(','); putchar('"');

printf("%s", start);

putchar('"'); putchar(','); putchar('"');

printf("%s", end);putchar('"'); putchar(','); putchar('"');

printf("%s", size);

putchar('"'); putchar(','); putchar('"');

printf("%s", parttype);

putchar('"'); putchar(','); putchar('"');

if (part->fs_type) printf("%s", part->fs_type->name);

putchar('"'); putchar(','); putchar('"');

printf("%s", partlabel);

putchar('"'); putchar(','); putchar('"');

printf("%s", flags);

break;

}

free(start);

free(end);free(size);

}

switch (dumpmode) {

case DUMPXML:

if (nlmode) printf("\n ");

printf("</partitions>");

break;

case DUMPTXT:

break;

case DUMPCSV:

putchar('"');

break;

}

}void

dump(char *device)

{

int len = strlen(device) + 8;

int i = 0;

printf("\nDEVICE: %s\n", device);

while(i++ < len) putchar('-');

putchar('\n');

printf("Manufacturer Model: %s\n", ascii_string(&amp;id[27],20));

printf(" Serial Number: %s\n", ascii_string(&amp;id[10],10));

printf(" Firmware Revision: %s\n", ascii_string(&amp;id[23],4));

printf(" Transport Type: %s\n", get_transport(id));

printf(" Maximum RPM: %s\n", get_rpm(id));

printf(" Capacity: %s\n", get_capacity(fd, id));printf(" Number Cylinders: %u\n", g->cylinders);

dump_partitions(device, DUMPTXT, NONEWLINE);

}

void

dumpxml(char *device, int nlmode)

{

printf("<disk dev=\"%s\">", device);

if (nlmode) printf("\n ");

printf("<model>%s</model>", ascii_string(&amp;id[27],20));

if (nlmode) printf("\n ");

printf("<serialno>%s</serialno>", ascii_string(&amp;id[10],10));

if (nlmode) printf("\n ");

printf("<firmware>%s</firmware>", ascii_string(&amp;id[23],4));

if (nlmode) printf("\n ");printf("<transport>%s</transport>", get_transport(id));

if (nlmode) printf("\n ");

printf("<rpm>%s</rpm>", get_rpm(id));

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 9/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 10/12

Hard Disk Metadata

if (nlmode) printf("\n ");

printf("<capacity>%s</capacity>", get_capacity(fd, id));

if (nlmode) printf("\n ");

printf("<geometry>");

if (nlmode) printf("\n ");

printf("<cylinders>%u</cylinders>", (unsigned short) g->cylinders);

if (nlmode) printf("\n ");

printf("<heads>%u</heads>", (unsigned char) g->heads);

if (nlmode) printf("\n ");printf("<sectors>%u</sectors>", (unsigned char) g->sectors);

if (nlmode) printf("\n ");

printf("</geometry>");

dump_partitions(device, DUMPXML, nlmode);

if (nlmode) putchar('\n');

printf("</disk>");

if (nlmode) putchar('\n');

}

void

dumpcsv(char *device)

{

putchar('"');

printf("%s", ascii_string(&amp;id[27],20));

putchar('"'); putchar(','); putchar('"');printf("%s", ascii_string(&amp;id[10],10));

putchar('"'); putchar(','); putchar('"');

printf("%s", ascii_string(&amp;id[23],4));

putchar('"'); putchar(','); putchar('"');

printf("%s", get_transport(id));

putchar('"'); putchar(','); putchar('"');

printf("%s", get_rpm(id));

putchar('"'); putchar(','); putchar('"');

printf("%s", get_capacity(fd, id));

putchar('"'); putchar(','); putchar('"');

printf("%u", g->cylinders);

putchar('"'); putchar(','); putchar('"');

printf("%u", g->heads);

putchar('"'); putchar(','); putchar('"');printf("%u", g->sectors);

putchar('"');

dump_partitions(device, DUMPCSV, NONEWLINE);

}

void

usage()

{

printf("usage: di [-n] [-c|-csv|-x|--xml] devicepath\n");

printf("usage: di [-v |--version ]\n");

}

int

main(int argc,

char *argv[])

{static struct hd_driveid hd;

int option_index = 0, c;

int xmlmode = 0, nlmode = 0, csvmode = 0;

char *device;

static struct option long_options[] = {

{"csv", no_argument, 0, 'c'},

{"help", no_argument, 0, 'h'},

{"newline", no_argument, 0, 'n'},

{"version", no_argument, 0, 'v'},

{"xml", no_argument, 0, 'x'},

{0, 0, 0, 0}

};

while ((c = getopt_long(argc, argv, "chnvx", long_options, &amp;option_index)) != -1)

{switch (c) {

case 'h':

usage();

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 10/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 11/12

Hard Disk Metadata

exit(EXIT_SUCCESS);

case 'c':

csvmode = 1;

break;

case 'n':

nlmode = 1;

break;

case 'x':

xmlmode = 1;break;

case 'v':

fprintf(stdout, "version %s\n", DI_VERSION);

exit(EXIT_SUCCESS);

default: /* '?' */

usage();

exit(EXIT_FAILURE);

}

}

if (csvmode &amp;&amp; xmlmode) {

fprintf(stderr, "ERROR: Select either XML or CVS for formatted output\n");

exit(EXIT_FAILURE);

}

if (optind >= argc) {fprintf(stderr, "ERROR: No devicepath provided\n");

exit(EXIT_FAILURE);

}

if (geteuid() > 0) {

fprintf(stderr, "ERROR: Must be root to use\n");

exit(EXIT_FAILURE);

}

device = argv[optind];

if ((fd = open(device, O_RDONLY|O_NONBLOCK)) < 0) {

fprintf(stderr, "ERROR: Cannot open device %s\n", argv[1]);

exit(EXIT_FAILURE);

}

id = get_diskinfo(fd);

g = get_geometry(fd);if (ioctl(fd, HDIO_GET_IDENTITY, &amp;hd) < 0 ) {

if (errno == -ENOMSG) {

fprintf(stderr, "ERROR: No hard disk identification information available\n");

} else {

perror("ERROR: HDIO_GET_IDENTITY");

exit(1);

}

}

close(fd);

if (csvmode)

dumpcsv(device);

else if (xmlmode)

dumpxml(device, nlmode);

elsedump(device);

exit(EXIT_SUCCESS);

}

To compile this code, you need to include libparted. If libparted is not available on your platform,

download the source code for the parted utility from the GNU Project and build it .

Please feel free to use the source code included in this post for whatever purpose you want to use

it for – provided you include the license text. If you use it on platforms which contain PATA, SAS or

SCSI drives obviously you will need to extend the code to include those drive types but that is not

difficult to do with the right information. One of the best places to find this sort of information is in

the various INCITS (International Committee for Information Technology Standards) standards

and working groups. For example, the INCITS Technical Committe T10 is a good place to learn

about SCSI storage interfaces.

03-10-2011 Copyright 2004-2011 Finnbarr P. Murphy. All rights reserved. 11/12

8/7/2019 Hard Disk Metadata

http://slidepdf.com/reader/full/hard-disk-metadata 12/12

Hard Disk Metadata

Enjoy!

 

03-10-2011 Copyright 2004-2011 Finnbarr P Murphy All rights reserved 12/12