Get CPUID and hard disk serial number under Linux

In the development of many system software, it is necessary to use some unique information of the system. Therefore, it is a very important application to obtain the CPUID of the host, the serial number of the hard disk and the MAC address of the network card.

The required preparation knowledge is:

1. GCC embedded assembly, specific GCC embedded assembly knowledge, please refer to the relevant manual

2.ioctl system call, the specific call method, please check the man page

get CPUID

According to the instructions provided online, CPUID is not supported by all Intel CPUs. If supported, the assembly call is: eax is set to 0000_0003, and cpuid is called.

Here's the implementation code (on my CPU, didn't get it):

#define cpuid(in,a,b,c,d)  asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));

static int getcpuid (char *id, size_t max)
{
    int i;
    unsigned long li, maxi, maxei, ebx, ecx, edx, unused;

    cpuid (0, maxi, unused, unused, unused);
    maxi &= 0xffff;

    if (maxi < 3)
    {
        return -1;
    }

    cpuid (3, eax, ebx, ecx, edx);

    snprintf (id, max, "%08lx %08lx %08lx %08lx", eax, ebx, ecx, edx);
    fprintf (stdout, "get cpu id: %s/n", id);

    return 0;
}

Get hard drive serial number

The implementation of this is to read the /etc/mtab file, find the device file mounted on / (that is, the root directory), then open it, and then use the system call ioctl to achieve.

The second parameter of ioctl is HDIO_GET_IDENTITY, which gets the flag number of the specified file descriptor

The third parameter of ioctl is struct hd_driveid. In linux/hdreg.h, the declaration of struct hd_driveid has

struct hd_driveid {
	unsigned short	config;		/</em> lots of obsolete bit flags */
	unsigned short	cyls;		/* Obsolete, "physical" cyls */
	unsigned short	reserved2;	/* reserved (word 2) */
	unsigned short	heads;		/* Obsolete, "physical" heads */
	unsigned short	track_bytes;	/* unformatted bytes per track */
	unsigned short	sector_bytes;	/* unformatted bytes per sector */
	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
	unsigned short	vendor0;	/* vendor unique */
	unsigned short	vendor1;	/* vendor unique */
	unsigned short	vendor2;	/* Retired vendor unique */
	unsigned char	serial_no[20];	/* 0 = not_specified */
	unsigned short	buf_type;	/* Retired */
	unsigned short	buf_size;	/* Retired, 512 byte increments
					 * 0 = not_specified
					 */
        ……
};

Among them, serial_no is the serial number of the hard disk. If this is 0, it is not provided.

The idea is clear, the following is the implementation code:

#include <string.h>
#include<stdio.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <fcntl.h>
#include <stdlib.h>
#include<ctype.h>

static int getdiskid (char *id, size_t max)
{
    int fd;
    struct hd_driveid hid;
    FILE *fp;
    char line[0x100], *disk, *root, *p;

    fp = fopen ("/etc/mtab", "r");
    if (fp == NULL)
    {
        fprintf (stderr, "No /etc/mtab file.\n");
        return -1;
    }

    fd = -1;
    while (fgets (line, sizeof line, fp) != NULL)
    {
        disk = strtok (line, " ");
        if (disk == NULL)
	    {
	        continue;
	    }

        root = strtok (NULL, " ");
        if (root == NULL)
	    {
	        continue;
	    }

        if (strcmp (root, "/") == 0)
	    {
	        for (p = disk + strlen (disk) - 1; isdigit (*p); p --)
            {
                *p = '\0';
            }
	        fd = open (disk, O_RDONLY);
	        break;
	    }
    }

    fclose(fp);

    if(fd < 0)
    {
        fprintf(stderr, "open hard disk device failed.\n");
        return -1;
    }

    if(ioctl(fd, HDIO_GET_IDENTITY, &hid) < 0)
    {
        fprintf (stderr, "ioctl error.\n");
        return -1;
    }

    close (fd);

    snprintf (id, max, "%s", hid.serial_no);
    fprintf (stdout, "get hard disk serial number: %s/n", id);

    return 0;
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324360870&siteId=291194637