Blue
Blue

Reputation: 323

Getting a unique id from a unix-like system

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.

Upvotes: 29

Views: 55577

Answers (15)

shrewmouse
shrewmouse

Reputation: 6030

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.

Upvotes: 2

user4401178
user4401178

Reputation:

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.

Upvotes: 2

Chris Johnson
Chris Johnson

Reputation: 21956

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.

Upvotes: 0

Jason Day
Jason Day

Reputation: 8839

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.

Upvotes: 30

Reputation:

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.

Upvotes: -2

oliver
oliver

Reputation: 6771

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

Upvotes: 0

Phillip Whelan
Phillip Whelan

Reputation: 1727

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.

Upvotes: 6

user3850
user3850

Reputation:

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

Upvotes: 5

CesarB
CesarB

Reputation: 45555

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

Upvotes: 10

ConcernedOfTunbridgeWells
ConcernedOfTunbridgeWells

Reputation: 66612

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.

Upvotes: -1

genehack
genehack

Reputation: 140728

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

Upvotes: 1

csexton
csexton

Reputation: 24783

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.

Upvotes: -1

ironfroggy
ironfroggy

Reputation: 8119

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.

Upvotes: 2

Martin v. Löwis
Martin v. Löwis

Reputation: 127467

Both Solaris and Linux provide the hostid(1) utility

Upvotes: 9

Yoni Roit
Yoni Roit

Reputation: 28686

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.

Upvotes: 2

Related Questions