/*
 *	DMI System Info 1.0
 *
 *	(C) 2000,2001 Alan Cox <alan@redhat.com>
 *      
 *      5-July-2001 Matt Domsch <Matt_Domsch@dell.com>
 *      Based on DMI Decode v1.2 (patch from 1.1 to 1.2 submitted
 *                                by Matt Domsch)
 *      Removed all unnecessary code, leaving only code relevant to
 *      rhn_register for determining system type.
 *
 *	Licensed under the GNU General Public license.
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

struct dmi_header
{
	u8	type;
	u8	length;
	u16	handle;
};

static char *dmi_string(struct dmi_header *dm, u8 s)
{
	u8 *bp=(u8 *)dm;
	if (!s) return "";
	
	bp+=dm->length;
	while(s>1)
	{
		bp+=strlen(bp);
		bp++;
		s--;
	}
	return bp;
}


static void dmi_table(int fd, u32 base, int len, int num)
{
	char *buf=malloc(len);
	struct dmi_header *dm;
	u8 *data;
	int i=0;
	
	if(lseek(fd, (long)base, 0)==-1)
	{
		perror("dmi: lseek");
		return;
	}
	if(read(fd, buf, len)!=len)
	{
		perror("dmi: read");
		return;
	}
	data = buf;
	while(i<num)
	{
		dm=(struct dmi_header *)data;
		switch(dm->type)
		{
		case 1:
			printf("Vendor: %s\n", 
			       dmi_string(dm, data[4]));
			printf("Product: %s\n",
			       dmi_string(dm, data[5]));
			break;
		case 3:
			printf("Serial Number: %s\n",
			       dmi_string(dm, data[7]));
			printf("Asset Tag: %s\n",
			       dmi_string(dm, data[8]));
			break;
			
		default:
			break;
			
		}
		data+=dm->length;
		while(*data || data[1])
			data++;
		data+=2;
		i++;
	}
	free(buf);
}

int main(int argc, char *argv[])
{
	unsigned char buf[20];
	int fd=open("/dev/mem", O_RDONLY);
	long fp=0xE0000L;
	if(fd==-1)
	{
		perror("/dev/mem");
		exit(1);
	}
	if(lseek(fd,fp,0)==-1)
	{
		perror("seek");
		exit(1);
	}
	
	
	fp -= 16;
	
	while( fp < 0xFFFFF)
	{
		fp+=16;
		if(read(fd, buf, 16)!=16)
			perror("read");
		if(memcmp(buf, "_DMI_", 5)==0)
		{
			u16 num=buf[13]<<8|buf[12];
			u16 len=buf[7]<<8|buf[6];
			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
			
			dmi_table(fd, base,len, num);
		}
	}
	close(fd);
	return 0;
}
