28

I want to get from any Unix-like system (if this is possible) a unique id that will be persistent every time my application runs in the same machine. If it is possible, I want to get the same id from Linux or FreeBSD or Solaris, etc... I don't want to generate a new id for each machine, but get an already existent id, and I prefer this id to come from the operating system and I don't prefer to use something like the MAC address.

If there is no other option available, I can use MAC in combination with something else, for example the id can be the md5 hash of the combination of the MAC address and something else.

I would like to listen to your suggestions.

If it is useful, my application is written in C/C++.

The aim of all this is to prevent a user to run my application for two or more times. I want to run just once.

jww
  • 97,681
  • 90
  • 411
  • 885
Blue
  • 313
  • 1
  • 3
  • 5

15 Answers15

30

How about the UUID of the root filesystem? You can get the root filesystem device from /etc/fstab, either by manually parsing the file or by using getfsent (3) or getfsfile (3). Once you have the device, you can get the UUID by either checking the links in /dev/disk/by-uuid or from the blkid command.

Jason Day
  • 8,809
  • 1
  • 41
  • 46
  • http://tools.ietf.org/html/rfc4122 - This specification defines a Uniform Resource Name namespace for UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDentifier). A UUID is 128 bits long, and can guarantee uniqueness across space and time. – The Demz Aug 15 '13 at 14:36
  • 1
    http://liquidat.wordpress.com/2013/03/13/uuids-and-linux-everything-you-ever-need-to-know/ - UUIDs and Linux: Everything you ever need to know – The Demz Aug 15 '13 at 14:40
  • 1
    There are use cases when the entire rootfs is replaced during software upgrade. Quite common on embedded devices, so this is not universal. – dtoux Sep 23 '21 at 14:57
  • ...also, some filesystems do not have a unique id (FAT derivatives for instance). – dtoux Sep 23 '21 at 15:30
10

The best way is, as usual, to see how other people already solved the same problem.

FLEXlm also uses a host identifier for its node-locked licenses. The most common host identifier it uses is the ethernet MAC address for one of your network interfaces, smashed together without any separator.

It can also use (on Windows) the volume serial number of the C: drive (again smashed together without any separators), and on Solaris the output of the hostid command (IIRC, on Sun computers, this number is actually unique, and located on a small removable EEPROM on the system board).

While the MAC address is extremly easy to fake, it is a nearly universal identifer nowadays (almost all new computers have at least one ethernet port, and it is very common for them to be onboard), and actually intended to be globally unique (in fact, the Ethernet protocols depend on this uniqueness). The main problems you would have with this approach:

  • Some computers have several ethernet addresses; some of them are on the main board, some are on separate removable cards.
  • They are extremly easy to fake (and some protocols depend on being able to change them).
  • Some virtualized environment generate random ethernet addresses on each boot (but they usually have a way to force a fixed value).
CesarB
  • 43,947
  • 7
  • 63
  • 86
  • +1 - I was going to mention that if there was a reliable way to uniquely id a linux system, flexlm would use it, but they settle for the mac address. – JimB Nov 30 '08 at 17:48
9

Both Solaris and Linux provide the hostid(1) utility

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
  • 12
    On Linux glibc, gethostid() (which is what hostid uses) returns a value based on the IP address, which is neither unique nor unchanging. – CesarB Nov 30 '08 at 16:00
  • That quite depends on the application. – Martin v. Löwis Nov 30 '08 at 17:21
  • 10
    I just tested `hostid` on 3 different computers (but same distro): it returns the same value for all of them. – picrap Sep 16 '14 at 06:07
  • `hostid` is an inferior option to a MAC address because it is based on the system's IP address which can change at anytime. "On Unix-like operating systems, the hostid command the host identification number for the system. This unique number is based on the machine's IP address, and is represented in hexadecimal." – shrewmouse Jul 01 '20 at 15:39
6

Another option is to use information derived from dmidecode, a command present on linux. This information is decoded from /dev/mem, therefore requiring root access.

The information dmidecode reads is known to be flawed, as some motherboard manufacturers lie or fake some of the fields.

Phillip Whelan
  • 1,697
  • 2
  • 17
  • 28
  • 1
    dmidecode is not available on all linux systems. For example IBM POWER systems with SLES installed on them. – woverton Mar 30 '16 at 15:39
5

There is no general and reliable way to get what you want.

  • There is always a way. One could do SHA256(/etc/machine-id | /sys/class/net/eth0/address). I'd say it's a pretty good unique device id, reliable and generic. – Alex D Dec 08 '22 at 14:51
2

You can get the UUID of the root filesystem /, that is fairly reliable, yet it won't differentiate between chroots and possibly vms running on the same disk.

If you are mainly dealing with internal or static HDD's that are dedicated to running a particular OS then you should be able to use the UUID of the root filesystem to detect the system.

You can get the UUID of the root fs with something like this: alias sys_guid='sudo /sbin/blkid | grep "$(df -h / | sed -n 2p | cut -d" " -f1):" | grep -o "UUID=\"[^\"]*\" " | sed "s/UUID=\"//;s/\"//"'

If you need to further differentiate between kernel versions of the same OS, or different OS's running on the same disk you can use data from uname and/or combine them with the root fs UUID.

2

I don't think it's possible. The closest you can get is to create a very long random string (like MS do with GUIDs) and store it somewhere on your system.

Yoni Roit
  • 28,280
  • 7
  • 36
  • 32
  • +1 to cancel down vote. This was better than Blue could have expected at the beginning. – dmckee --- ex-moderator kitten Nov 30 '08 at 16:16
  • GUIDs aren't random, per se. How MS generates them, though, they won't say. They are supposedly non-repeating on the machine that they are generated on. – Joseph Ferris Nov 30 '08 at 16:18
  • Just a quick correction; GUIDs *can* be random, depending on the type of the GUID (specifically, version 4 GUIDs are random), and the generation algorithm is standardised in ITU-T Rec. X.667 (aka ISO/IEC 9834-8) and RFC 4122. – al45tair May 07 '20 at 14:53
2

You have to consider that a lot of setups may have created a filesystem image and cloned to many machines, rather than setting them up individually. In other cases, a machine could get re-setup many times. In other words, anything the OS provided can't be trusted.

However, the CPU does keep a unique serial number, but access to it should be different on different systems.

ironfroggy
  • 7,991
  • 7
  • 33
  • 44
  • That depends on what type of cpu you've got. A while back, Intel started implementing a serial number on Pentium processors that you could get with the cpuid instruction, but they got a lot of blowback from privacy groups about it. I'm not sure they still do it. What if the computer has 2 procs? – Die in Sente Nov 30 '08 at 20:29
2

As someone else stated, the dmidecode command is an option.

[root@sri-0000-0003 WebGui]# dmidecode -s system-uuid
03001234-1234-1234-1234-000700012345

I edited the output to hide the UUID of the system I tested on.

There are other things that you can get from dmidecode. dmidecode -t will tell you the categories.

[root@sri-0000-0003 WebGui]# dmidecode -t
dmidecode: option requires an argument -- 't'
Type number or keyword expected
Valid type keywords are:
  bios
  system
  baseboard
  chassis
  processor
  memory
  cache
  connect

If you're using actual hardware instead of a virtual machine then dmidecode -t processor would be a good option.

[root@sri-0000-0003 WebGui]# dmidecode -t processor
# dmidecode 3.1
Getting SMBIOS data from sysfs.
SMBIOS 3.0.0 present.

Handle 0x0041, DMI type 4, 48 bytes
Processor Information
        Socket Designation: U3E1
        Type: Central Processor
        Family: Core i3
        Manufacturer: Intel(R) Corporation
        ID: E3 00 00 00 11 22 33 44

Given that the number of processor manufactures is small, this seems like a good alternate to dmidecode -s system-uuid. However, under virtualbox, dmidecode -t processor won't give you anything useful. I don't know about any other virtual platforms.

I'm willing to bet that dmidecode -s system-uuid will also work inside a docker container too but, I can't verify that.

shrewmouse
  • 5,338
  • 3
  • 38
  • 43
1

You don't mention how stable the unique identifier needs to be -- do you always want the same host to produce the same ID each time your code is run?

If no, then fuzzymonk's suggestion of uuidgen is what you want.

If yes, then you need to decide what constitutes "same" as far as the host as concerned. One way would be as you suggest, the MD5 sum of the MAC of the first ethernet interface and "something". For "something" in that case I would consider the FQDN, unless your notion of "same host" includes the FQDN changing...

genehack
  • 136,130
  • 1
  • 24
  • 24
0

You mentioned that on Windows you use some GUID... Do you have some details about how it is created?

Apart from that, you could try something like CPU ID, or hard disk ID... I suppose those cannot be changed (but you will run into trouble if a faulty hard disk is replaced).

oliver
  • 6,204
  • 9
  • 46
  • 50
0

The answers from Jason Day and A.Danischewski seem to be on the right track but don't meet your criteria of any "Unix-like system" since /sbin/blkid and /etc/fstab don't exist on OSX.

The only 100% portable approach would be to choose a standard location for a file that your own application will create, e.g. /etc/YOURAPP.cfg and store a UUID there if one doesn't already exist.

Far from ideal, since another person or application could delete the file or change it, or if the user changed out the root file system you could lose the ID from the current machine, or it could come into being on another machine. Not to mention issues with read and write permissions and so on.

But in the end there is no such thing as "the same machine". Any computer is no more and no less than its components + current configuration. I don't think you can do any better than this, portably.

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
-1

Sounds like you are looking for UUID. This is a common universally unique id (really, the same thing as a GUID)

There are many C++ implementations of this in diffrent libs, or you could use the uuidgen command and capture the output.

csexton
  • 24,061
  • 15
  • 54
  • 57
  • 1
    Err, no, a UUID is different every time it's generated: "unique id that will be persistent every time my application runs in the same machine" – user23167 Nov 30 '08 at 21:33
-1

Most unix-like machines have a random number generator accessible through /dev/random. You will need something like a MAC address and a time to give a genuine uniqueness to the GUID generator (this is what the GUID generator on Windows does). On top of this, getting something from /dev/random will get you a reasonably good GUID type construct. In practice, the UUID libraries do this sort of thing behind the scenes.

If you just need one number per machine, than a MAC address will probably be sufficient. These are administered by a central body and one can reasonably assume that no two MAC addresses will be the same. However, if you are trying to use this to tie a software installation to a MAC address be aware that some components have programmable MAC addresses or programmable components of the MAC address. Unix-like Operating systems, particularly open-source ones tend not to have hard-wired serial numbers. This approach may also cause issues with running multiple instances of the software in VM's.

One option might be a USB dongle, which can be obtained from several manufacturers. Another option might be a license server, where the unique code is supplied to the server. Again, several canned solutions for this are available from different sources.

ConcernedOfTunbridgeWells
  • 64,444
  • 15
  • 143
  • 197
  • I need one number per machine, which will be persistent. I know all these about MAC addresses and because they can change, they are my last solution. – Blue Nov 30 '08 at 16:15
-2

You can use a lockfile in places like:

  • /var/run/yourapp.pid (if program run by root)
  • $HOME/.yourapp.pid (if run by user and local filesystem)
  • $HOME/.yourapp.$(hostname -f).pid (home on nfs)

When your program is run, it shall do something like:

lock = open(filename, O_CREAT | O_EXCL);
dprintf(lock, "%u", getpid());

If the open fails, check if the process is still running and if not: delete the file and try again.