Recent releases of Fedora and other GNU/Linux distributions include a Hardware Abstraction Layer (HAL) which is used to support device plug-and-play capabilities. In this post I will show you how your shell scripts can use HAL to retrieve device and system information.
The term HAL is overloaded as it used to refer both to a specification and the actual software which implements the specification. From an application developers viewpoint, HAL is way to enumerate the capabilities and features of hardware attached to a system and receive notification when something about the hardware changes.
First, a very quick overview of HAL. Each item of physical hardware in a computer is regarded as being an device object which identified by a Unique Device Identifier (UDI). Associated with each device object is a variable set of well-defined typed key-value pairs (or metadata) called device properties which describe what each device object represents together with its properties. Some device properties are derived from the actual physical hardware, some are merged from XML-formatted files, known as Device Information Files, and some are derived from the actual device configuration. Mandatory device properties are defined in the HAL specification.
A HAL daemon< is used to maintain and update the list of device objects forming a hardware configuration and is notified when devices are added or removed. HAL also provides callbacks so that the operating system and applications can react to hardware configuration changes in order to maintain system policy. An example of such a callback and policy is when you plug in a USB memory stick HAL automatically creates a mount point and mounts the device.
For a good backgrounder on HAL, see this article Making Hardware Just Work by Havoc Pennington. For more detailed information, you should read the HAL Specification and the HAL project page at freedesktop.org.
A number of command line utilities are provided for accessing and manipulating device objects.
hal-disable-polling | disable polling on drives with removable media |
hal-find-by-capability | find device objects by capability matching |
hal-find-by-property | find device objects by property matching |
hal-get-property | get a property from a device object |
hal-is-caller-locked-out | determine if caller is locked out |
hal-is-caller-privileged | determine if caller is privileged |
hal-lock | lock an interface |
hal-set-property | set a property on a device object |
lshal | list devices objects and properties |
For the purposes of this post, we are only interested in a small number of the above utilities, i.e. those utilities which locate and return information about device objects.
Here is a simple use of the hal-find-by-property utility to retrieve a list of network interfaces.
$ hal-find-by-property --key linux.subsystem --string net
/org/freedesktop/Hal/devices/net_3a_67_56_92_fb_73
/org/freedesktop/Hal/devices/net_computer_loopback
/org/freedesktop/Hal/devices/net_00_1c_c0_6d_8a_f7
The HAL specification specifies a system namespace which contains information about a system and it’s currently running kernel. The following script retrieves certain information from the system namespace.
udi=$(hal-find-by-property --key info.product --string Computer) printf "Board Manufacturer: $(hal-get-property --udi $udi --key system.board.vendor)\n" printf " Model: $(hal-get-property --udi $udi --key system.board.product)\n" printf " Version: $(hal-get-property --udi $udi --key system.board.version)\n" printf " Serial No.: $(hal-get-property --udi $udi --key system.board.serial)\n" printf " Release Date: $(hal-get-property --udi $udi --key system.firmware.release_date)\n" printf " Bios Version: $(hal-get-property --udi $udi --key system.firmware.version)\n" printf " Motherboard UUID: $(hal-get-property --udi $udi --key system.hardware.uuid)\n"
Here is the output from the computer which I used to write this post.
Board Manufacturer: Intel Corporation Model: DX48BT2 Version: AAE26191-205 Serial No.: BQBQ8280004G Release Date: 08/07/2008 Bios Version: BTX3810J.86A.1814.2008.0807.2334 Motherboard UUID: 2237F666-4F75-11DD-894F-0007E9747DB3
The next example retrieves certain information about all the storage devices on a system using the volume capability. The volume namespace is for device objects that represent storage devices with a filesystem that are mountable. Such device objects have the capability volume.
for udi in $(/usr/bin/hal-find-by-capability --capability volume) do mount=$(hal-get-property --udi $udi --key volume.mount_point) device=$(hal-get-property --udi $udi --key block.device) label=$(hal- get-property --udi $udi --key volume.label) fstype=$(hal-get-property --udi $udi --key volume.fstype) echo "$device $mount $fstype $label" done
Here is sample output from this script.
/dev/sda1 /boot ext3 /boot /dev/sdb2 /abac ext3 /abac /dev/sdb1 /home/fpm ext3 fpm /dev/sda2 LVM2_member /dev/sdc1 LVM2_member /dev/sdc2 LVM2_member
You can also drill down and return information about specific devices such as an optical drive, i.e. device objects which have a capability of cdrom.
for i in $(hal-find-by-property --key storage.drive_type --string cdrom) do printf "Manufacturer: $(hal-get-property --udi $i --key storage.vendor)\n" printf " Model: $(hal-get-property --udi $i --key block.device)\n" printf " Bus: $(hal-get-property --udi $i --key storage.model)\n" printf " Path: $(hal-get-property --udi $i --key storage.bus)\n" done
Here is the output for the computer which I am using to write this post. It contains a single DVD RW drive.
Manufacturer: HP Model: /dev/sr0 Bus: DVD Writer 1070d Path: pci
In many cases there are multiple ways of retrieving the information you want. For example, here is another way of retrieving the same information, together with details of the volume label and mount point if there is a disk in the drive, using the storage.cdrom capability.
for udi in $(/usr/bin/hal-find-by-capability --capability storage.cdrom) do device=$(hal-get-property --udi $udi --key block.device) vendor=$(hal-get-property --udi $udi --key storage.vendor) model=$(hal-get-property --udi $udi --key storage.model) if [[ $(hal-get-property --udi $udi --key storage.removable.media_available) = true ]] then parent_udi=$(hal-find-by-property --key block.storage_device --string $udi) mount=$(hal-get-property --udi $parent_udi --key volume.mount_point) label=$(hal-get-property --udi $parent_udi --key volume.label) fi printf "$vendor $model $device $mount $label\n" done
Here is the output from this script when there is a DVD in the drive followed by when there is not a DVD in the drive.
$ ./findodrive HP DVD Writer 1070d /dev/sr0 /media/Kota_Kinabalu1 Kota_Kinabalu1 $ ./findodrive
HP DVD Writer 1070d /dev/sr0
Here is a script to list details about all removable USB storage drives that are currently installed on your system.
#!/bin/ksh93 # # list attached USB storage devices # for udi in $(/usr/bin/hal-find-by-capability --capability storage) do device=$(hal-get-property --udi $udi --key block.device) vendor=$(hal-get-property --udi $udi --key storage.vendor) model=$(hal-get-property --udi $udi --key storage.model) if [[ $(hal-get-property --udi $udi --key storage.bus) = "usb" ]] then parent_udi=$(hal-find-by-property --key block.storage_device --string $udi) mount=$(hal-get-property --udi $parent_udi --key volume.mount_point) label=$(hal-get-property --udi $parent_udi --key volume.label) media_size=$(hal-get-property --udi $udi --key storage.removable.media_size) size=$(( ceil(media_size/(1000*1000*1000)) )) printf "$vendor $model $device $mount $label "${size}GB" \n" fi done
And here is the output when two USB thumb drives are present.
$ ./listusb Kingston DataTraveler 2.0 /dev/sdd /media/KINGSTON KINGSTON 1GB Kingston DataTraveler 2.0 /dev/sdc /media/USB-4GB USB-4GB 4GB $
Well that is about all for now. You should have gained sufficient information from this post to go away and experiment on your own system.
Remember, however, that the HAL specification and it’s implementation in GNU/Linux distributions is still somewhat in a state of flux. The above examples worked on Fedora 10 as of the date of this post.
If an example does not work on your system, I recommend that you first check the output from the lshal utility to see if the device object and associated device properties are instantiated on your system. You can use udevadm –monitor to see what kernel events are being pushed out to user space. HAL monitors these events. You can also use lshal –monitor to see what events HAL emits to user space.
UPDATE 6/30/2009 HAL is going to be phased out – at least from the Fedora/Redhat/CenOS stream.
Date: Tue, 30 Jun 2009 16:06:44 +0200
From: Kay Sievers
Subject: HAL is in maintenance mode
To: hal
Message-ID: <1246370804.4911.172.camel@yio.site>
Content-Type: text/plainHey,
to clarify some confusion about HAL:The goal is to get entirely rid of HAL, at least on Linux systems.
We will no longer accept any new features, only bug fixes,
or hal-info entries and fixes. There will be no future release with
major new features, or support for new device types.If distros ship bug fixes for the current HAL in their packages,
please send them now, so we can integrate them and include them in
a new maintenance release. If distros already added new features
in their packages, please consider to dropping them, or let us
find out how to possibly integrate them now, if its simple enough.The development has moved and focuses on udev and the DeviceKit-*
projects, please integrate new features there.There is a separation between udev and the higher layer projects:
Udev will exist on almost every Linux system, and low-level users
can enumerate all current devices and listen to events with libudev.
Applications can expect udev to always be active on the system.For higher-level projects there are specific susbsystem services,
like DeviceKit-disks, DeviceKit-power, NetworkManager, PulseAudio,
… They all connect to the system device information with libudev,
but provide their higher-level interfaces.Unlike HAL, applications can not always expect that all these
services are available. Customized systems or large servers may
not be able to run them, or may not even want to install them for
whatever reasons. Usual desktop installations will likely pull-in
most of these services as dependencies though.Thanks,
Kay
Updated 3/16/09 to include example on how to list attached USB storage devices