How to obtain (almost) unique system identifier in a cross platform way?
To generate a mostly unique machine id, you can get a few serial numbers from various pieces of hardware on the system. Most processors will have a CPU serial number, the hard disks each have a number, and each network card will have a unique MAC address.
You can get these and build a fingerprint for the machine. You might want to allow some of these numbers to change before declaring it a new machine. ( e.g. if the 2 out of three are the same, then the machine is the same ). So you can deal somewhat gracefully from having a component upgraded.
I've clipped some code from one of my projects that gets these numbers.
Windows:
#include "machine_id.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <intrin.h>
#include <iphlpapi.h>
#ifndef _MSC_VER
#include <cpuid.h>
#else
#include <intrin.h>
#endif
// we just need this for purposes of unique machine id. So any one or two mac's is
// fine.
u16 hashMacAddress( PIP_ADAPTER_INFO info )
{
u16 hash = 0;
for ( u32 i = 0; i < info->AddressLength; i++ )
{
hash += ( info->Address[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( u16& mac1, u16& mac2 )
{
IP_ADAPTER_INFO AdapterInfo[32];
DWORD dwBufLen = sizeof( AdapterInfo );
DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );
if ( dwStatus != ERROR_SUCCESS )
return; // no adapters.
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
mac1 = hashMacAddress( pAdapterInfo );
if ( pAdapterInfo->Next )
mac2 = hashMacAddress( pAdapterInfo->Next );
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
u16 tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
u16 getVolumeHash()
{
DWORD serialNum = 0;
// Determine if this volume uses an NTFS file system.
GetVolumeInformation( "c:\\", NULL, 0, &serialNum, NULL, NULL, NULL, 0 );
u16 hash = (u16)(( serialNum + ( serialNum >> 16 )) & 0xFFFF );
return hash;
}
u16 getCpuHash()
{
int cpuinfo[4] = { 0, 0, 0, 0 };
__cpuid( cpuinfo, 0 );
u16 hash = 0;
u16* ptr = (u16*)(&cpuinfo[0]);
for ( u32 i = 0; i < 8; i++ )
hash += ptr[i];
return hash;
}
const char* getMachineName()
{
static char computerName[1024];
DWORD size = 1024;
GetComputerName( computerName, &size );
return &(computerName[0]);
}
Linux and OsX:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <assert.h>
#ifdef DARWIN
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/if_types.h>
#else //!DARWIN
// #include <linux/if.h>
// #include <linux/sockios.h>
#endif //!DARWIN
const char* getMachineName()
{
static struct utsname u;
if ( uname( &u ) < 0 )
{
assert(0);
return "unknown";
}
return u.nodename;
}
//---------------------------------get MAC addresses ------------------------------------unsigned short-unsigned short----------
// we just need this for purposes of unique machine id. So any one or two mac's is fine.
unsigned short hashMacAddress( unsigned char* mac )
{
unsigned short hash = 0;
for ( unsigned int i = 0; i < 6; i++ )
{
hash += ( mac[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( unsigned short& mac1, unsigned short& mac2 )
{
mac1 = 0;
mac2 = 0;
#ifdef DARWIN
struct ifaddrs* ifaphead;
if ( getifaddrs( &ifaphead ) != 0 )
return;
// iterate over the net interfaces
bool foundMac1 = false;
struct ifaddrs* ifap;
for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next )
{
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ))
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
} else {
mac2 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );
break;
}
}
}
freeifaddrs( ifaphead );
#else // !DARWIN
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );
if ( sock < 0 ) return;
// enumerate all IP addresses of the system
struct ifconf conf;
char ifconfbuf[ 128 * sizeof(struct ifreq) ];
memset( ifconfbuf, 0, sizeof( ifconfbuf ));
conf.ifc_buf = ifconfbuf;
conf.ifc_len = sizeof( ifconfbuf );
if ( ioctl( sock, SIOCGIFCONF, &conf ))
{
assert(0);
return;
}
// get MAC address
bool foundMac1 = false;
struct ifreq* ifr;
for ( ifr = conf.ifc_req; (char*)ifr < (char*)conf.ifc_req + conf.ifc_len; ifr++ )
{
if ( ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data )
continue; // duplicate, skip it
if ( ioctl( sock, SIOCGIFFLAGS, ifr ))
continue; // failed to get flags, skip it
if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 )
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));
} else {
mac2 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));
break;
}
}
}
close( sock );
#endif // !DARWIN
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
unsigned short tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
unsigned short getVolumeHash()
{
// we don't have a 'volume serial number' like on windows. Lets hash the system name instead.
unsigned char* sysname = (unsigned char*)getMachineName();
unsigned short hash = 0;
for ( unsigned int i = 0; sysname[i]; i++ )
hash += ( sysname[i] << (( i & 1 ) * 8 ));
return hash;
}
#ifdef DARWIN
#include <mach-o/arch.h>
unsigned short getCpuHash()
{
const NXArchInfo* info = NXGetLocalArchInfo();
unsigned short val = 0;
val += (unsigned short)info->cputype;
val += (unsigned short)info->cpusubtype;
return val;
}
#else // !DARWIN
static void getCpuid( unsigned int* p, unsigned int ax )
{
__asm __volatile
( "movl %%ebx, %%esi\n\t"
"cpuid\n\t"
"xchgl %%ebx, %%esi"
: "=a" (p[0]), "=S" (p[1]),
"=c" (p[2]), "=d" (p[3])
: "0" (ax)
);
}
unsigned short getCpuHash()
{
unsigned int cpuinfo[4] = { 0, 0, 0, 0 };
getCpuid( cpuinfo, 0 );
unsigned short hash = 0;
unsigned int* ptr = (&cpuinfo[0]);
for ( unsigned int i = 0; i < 4; i++ )
hash += (ptr[i] & 0xFFFF) + ( ptr[i] >> 16 );
return hash;
}
#endif // !DARWIN
int main()
{
printf("Machine: %s\n", getMachineName());
printf("CPU: %d\n", getCpuHash());
printf("Volume: %d\n", getVolumeHash());
return 0;
}
How can I generate system-wide unique IDs under Linux
This sounds like a job for... ...uuidgen
:
% uuidgen
975DA04B-9A5A-4816-8780-C051E37D1414
If you want to build it into your own application or service, you'll need libuuid
:
#include <uuid/uuid.h>
#include <iostream>
int main()
{
uuid_t uu;
uuid_generate(uu);
char uuid[37];
uuid_unparse(uu, uuid);
std::cout << uuid << std::endl;
}
Solaris and Unix unique identifier
look at removing /etc/sysidcfg
once removed, when the system boots it will prompt for identification information, unless provided via the network, or a populated sysidcfg.
the sysidcfg manpage from oracle may be of assistance to you?
http://docs.oracle.com/cd/E19253-01/816-5174/6mbb98ujq/index.html
How do I generate unique IDs on the Mac/Linux without any external ruby dependencies (i.e. no gems)?
To follow Catnapper's comment, uuidgen is available on Linux systems, including Darwin.
Just make a call to it in your Ruby script:
irb(main):001:0> `uuidgen`
=> "613C66FE-F609-4389-8A70-A59D245070AE\n"
Best way to get machine id on Linux?
Depending on your kernel, the DMI information may be available via sysfs.
Try those:
# cat /sys/class/dmi/id/board_serial
xxxxxxxxxxxxxxx
# cat /sys/class/dmi/id/product_uuid
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
or using a tool
# dmidecode -s baseboard-serial-number
...
# dmidecode -s system-uuid
...
Related Topics
Nasm Segmentation Fault on Ret in _Start
Cannot Connect to the Docker Daemon At Unix:/Var/Run/Docker.Sock. Is the Docker Daemon Running
How to Parse a CSV File in Bash
How to Preserve Quotes in Printing a Bash Script'S Arguments
How to Copy Commits from One Git Repo to Another
How to Change 'Rpath' in an Already Compiled Binary
Difference Between Using 'Sh' and 'Source'
What's the Difference Between Nohup and Ampersand
How to Get the Total Cpu Usage of an Application from /Proc/Pid/Stat
How to Ensure Only One Instance of a Bash Script Is Running
How to Compile a 32-Bit Binary on a 64-Bit Linux Machine With Gcc/Cmake
Ld Cannot Find an Existing Library
Linux and I/O Completion Ports
How to Specify the Library Version to Use At Link Time