#!/usr/bin/env python3 # encoding: utf-8 # This file is part of steamos-devkit # SPDX-License-Identifier: LGPL-2.1+ # # Copyright 2017-2018 Collabora Ltd # # This package is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This package is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this package. If not, see # . # Sample script run to identify the machine we are running on. This # is used by the devkit daemon to choose an identity for the machine, # and can also be run directly. # # A script or binary (written in any language) named devkit-1-identify # can be placed in the same directory as this sample, and it will be # used preferentially. # # Execution environment: # - Runs as root, or as an ordinary user who can run games # - Part of a non-interactive secure shell session # Input: # - None # Output: # - Exit 0 on success or nonzero on error # - On success, must print JSON to stdout containing one object with # the following keys and string values, all of which are optional: # - "machine_id": The hexadecimal systemd/D-Bus machine-id(5) # (in the case of a conflict between systemd's /etc/machine-id and # D-Bus' traditional /var/lib/dbus/machine-id, the systemd version # should be preferred) # - "hostname": The machine-readable hostname as set by sethostname(2) # - "pretty_hostname": A human-friendly version of the hostname as # found in systemd's machine-info(5) # - "product_family", "product_name", "product_serial", "product_uuid", # "sys_vendor": as for /sys/devices/virtual/dmi/id # - "product": The best human-friendly description of the machine # hardware we can devise, for example "Alienware ASM100" # - "serial": The best hardware serial number we can devise # - "machine_name": The best unique name for the machine that we can # devise # - Any diagnostic messages must be printed to stderr only import json import os import re import socket import subprocess import sys _MACHINE_ID_RE = re.compile(r'^[0-9A-Fa-f]{32,32}$') _USELESS_HOSTNAMES = frozenset(( 'debian', 'host', 'localhost', 'steamos', 'ubuntu', )) # The case combination sometimes varies, so this is lowercased and we # use lower() to compare. _USELESS_DMI_NAMES = frozenset(( 'to be filled by o.e.m.', )) if __name__ == '__main__': info = {} steam_serialnumber = None for k in ('product_family', 'product_name', 'product_serial', 'product_uuid', 'sys_vendor'): try: with open('/sys/devices/virtual/dmi/id/{}'.format(k)) as reader: v = reader.read().strip() if v and v.lower() not in _USELESS_DMI_NAMES: info[k] = v except (IOError, OSError, UnicodeError): pass try: for f in ('/etc/machine-id', '/var/lib/dbus/machine-id'): with open(f) as reader: v = reader.read().strip() if _MACHINE_ID_RE.match(v): info['machine_id'] = v except (IOError, OSError, UnicodeError): pass if 'product_family' in info and 'sys_vendor' in info: info['product'] = '{sys_vendor} {product_family}'.format(**info) elif 'product_name' in info and 'sys_vendor' in info: info['product'] = '{sys_vendor} {product_name}'.format(**info) elif 'product_family' in info: info['product'] = info['product_family'] elif 'product_name' in info: info['product'] = info['product_name'] if os.access('/usr/bin/hostnamectl', os.X_OK): try: v = subprocess.check_output([ 'hostnamectl', '--pretty', ]).decode('utf-8').strip() except (subprocess.CalledProcessError, UnicodeError): pass else: if v: info['pretty_hostname'] = v v = subprocess.check_output([ 'hostnamectl', '--static', ]).decode('utf-8').strip() if v: info['hostname'] = v if 'hostname' not in info: try: info['hostname'] = socket.gethostname() except (IOError, OSError, UnicodeError): pass if steam_serialnumber: info['serial'] = steam_serialnumber elif 'product_serial' in info: info['serial'] = info['product_serial'] if 'product' in info: info['machine_name'] = info['product'] if 'hostname' in info and info['hostname'] not in _USELESS_HOSTNAMES: info['machine_name'] = info['hostname'] if 'pretty_hostname' in info: info['machine_name'] = info['pretty_hostname'] json.dump(info, sys.stdout, indent=4, sort_keys=True) print()