问题
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.
回答1:
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.
回答2:
Both Solaris and Linux provide the hostid
(1) utility
回答3:
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).
回答4:
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.
回答5:
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.
回答6:
There is no general and reliable way to get what you want.
回答7:
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.
回答8:
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...
回答9:
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.
回答10:
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.
回答11:
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.
回答12:
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).
回答13:
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.
回答14:
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.
来源:https://stackoverflow.com/questions/328936/getting-a-unique-id-from-a-unix-like-system