June 10, 2011

Detecting cables being plugged/unplugged from a Linux box

I wanted to get notified whenever a network or USB cable was physically plugged in or unplugged from my machine. On Linux, there are a number of ways to skin this cat, but D-Bus seemed like a reasonable (and reasonably modern) way to go. It's a sort of introspectable message bus for the system, and various standard components (notably the HAL and the NetworkManager) are willing to talk to it.

There are D-Bus APIs for Python and Ruby, among others. The ruby-dbus gem is an odd bird, but I got it to work, after some pain.


#!/usr/bin/env ruby

require 'rubygems'
require 'pp'
require 'dbus'

$system_bus = DBus::SystemBus.instance

# For the given dbus service, grab the chosen object and apply one of its interfaces
# A strange API.
def dbus_interface (dbus_path, dbus_obj=nil, dbus_iface=nil)
  dbus_obj   ||= "/" + dbus_path.gsub(".", "/")
  dbus_iface ||= dbus_path
  puts("Dbus service path: #{dbus_path}\n  obj: #{dbus_obj}\n  interface: #{dbus_iface}")
  o = $system_bus.service(dbus_path).object(dbus_obj)
  o.introspect
  o.default_iface = dbus_iface
  o
end

def nth_wired_device (n)
  # GetDevices returns a list of lists; first element has what we want
  devices = dbus_interface("org.freedesktop.NetworkManager").GetDevices[0]
  dbus_interface("org.freedesktop.NetworkManager", devices[n],
                 "org.freedesktop.NetworkManager.Device.Wired")
end

def detect_wired_network_evts
  # Get the wired network device otherwise known as eth0
  d = nth_wired_device(0)

  d.on_signal("PropertiesChanged") do |info|
    puts "Network wire properties changed.  Changed properties:\n   "
    pp info
  end

  # Show properties of the wired device
  #d.default_iface = "org.freedesktop.DBus.Properties"
  #pp d.GetAll("org.freedesktop.NetworkManager.Device.Wired")
  # If plugged in, shows e.g. 
  #     [{"Carrier"=>true, "HwAddress"=>"6C:62:6D:46:A0:D0", "Speed"=>1000}]

  # Show more general properties of the network device
  #d.default_iface = "org.freedesktop.DBus.Properties"
  #pp d.GetAll("org.freedesktop.NetworkManager.Device")
end

def detect_hal_device_events
  hal_o = dbus_interface("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager",
                         "org.freedesktop.Hal.Manager")
  hal_o.on_signal("DeviceAdded") do |u|
    puts "HAL device added: #{u}"
  end
  hal_o.on_signal("DeviceRemoved") do |u|
    puts "HAL device removed: #{u}"
  end
end

detect_wired_network_evts
detect_hal_device_events

main = DBus::Main.new
main << $system_bus
main.run

0 comments:

Post a Comment