Skip to content

machine: Retrieve an unique identifier if one is known.#1095

Open
agatti wants to merge 1 commit intomicropython:masterfrom
agatti:unix-ffi-machine-unique-id
Open

machine: Retrieve an unique identifier if one is known.#1095
agatti wants to merge 1 commit intomicropython:masterfrom
agatti:unix-ffi-machine-unique-id

Conversation

@agatti
Copy link
Contributor

@agatti agatti commented Mar 15, 2026

Summary

This PR adds a proper implementation for machine.unique_id for selected systems, as opposed to returning a fixed value in every case.

On a Unix system there are several incompatible ways to retrieve something that can be called an unique machine identifier. However, the only semblance of a specification comes from freedesktop.org, which says that a file called /etc/machine-id has to exist and must contain a 32-digits long hexadecimal identifier - thus having a 128 bits unique identifier value.

Given that the current specification is the DBus unique identifier retrieval mechanism made official, if the identifier file is not found the code will attempt to read the file provided by DBus.

These changes only apply to Linux and recent BSD systems. On other systems the old, fixed value for the machine identifier will be returned instead, to avoid breaking compatibility with existing code.

The specification used in this commit is available at https://www.freedesktop.org/software/systemd/man/latest/machine-id.html.


The manifest's version was bumped up by 0.0.1 since these changes only affect the behaviour of the module without making changes to the existing API.

Testing

This was tested on current MicroPython master, by adding require("machine") to ports/unix/variants/manifest.py and rebuilding the standard variant of the interpreter.

Then the output of import machine; machine.unique_id() was checked against the contents of /etc/machine-id on the host system. The fallback was tested by changing /etc into something else, and I/O error passthrough was tested by adding a directory that is not accessible by the running user to the front of the list of paths to check.

Trade-offs and Alternatives

These changes add 198 bytes to the machine module. Things could be made smaller by removing the identifier validation and skipping the DBus fallback.

Preliminary identifier value validation in theory could be removed, since the "unhexlification" step will raise an exception if the input data is not a series of hexadecimal digits. The current behaviour is to ignore the data read from the current machine identifier file and try the next one in the list. If stopping the identification process on unexpected data at any point is acceptable rather than gracefully handling the condition, this could shrink down by 43 bytes.

However, since there is an existing specification and a known alternative path for the same data, maybe it's not a bad idea to keep those two bits of code in.

Generative AI

I did not use generative AI tools when creating this PR.

This commit adds a proper implementation for "machine.unique_id" for
selected systems, as opposed to returning a fixed value in every case.

On a Unix system there are several incompatible ways to retrieve
something that can be called an unique machine identifier.  However, the
only semblance of a specification comes from freedesktop.org, which says
that a file called "/etc/machine-id" has to exist and must contain a
32-digits long hexadecimal identifier.

Given that the current specification is the DBus unique identifier
retrieval mechanism made official, if the identifier file is not found
the code will attempt to read the file provided by DBus.

These changes only apply to Linux and recent BSD systems.  On other
systems the old, fixed value for the machine identifier will be returned
instead - to avoid breaking compatibility with existing code.

The specification used in this commit is available at
https://www.freedesktop.org/software/systemd/man/latest/machine-id.html.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
@agatti agatti force-pushed the unix-ffi-machine-unique-id branch from 1ba9531 to 12410fd Compare March 15, 2026 16:55
@dpgeorge
Copy link
Member

Thanks for the patch! I never knew about /etc/machine-id until now.

Preliminary identifier value validation in theory could be removed

I think it's worth removing that validation step, to save code size.

if len(data) == 32:
for byte in data:
if byte not in b"0123456789abcdef":
break
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest keeping the len(data) == 32 check but removing the hex char validation loop.

(If the file exists and has at least 32 bytes, it's highly likely to be a well formed hex number.)

if byte not in b"0123456789abcdef":
break
# unhexlify might not be available
return bytes([int(data[i : i + 2], 16) for i in range(0, len(data), 2)])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest replacing len(data) with 32, since that 32 is validated above (and it'll reduce code size).

return bytes([int(data[i : i + 2], 16) for i in range(0, len(data), 2)])
except OSError as e:
if "ENOENT" not in str(e):
raise
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to just do pass here in the except clause, ie silently ignore any error. That'll allow it to try the DBus file if anything fails in the etc file, it'll reduce code size, and also work correctly on targets that cannot render exceptions (ie MICROPY_PY_ERRNO is disabled).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants