Main Content

Checking all the systems on a subnet, using Expect and Tk

Archive - Originally posted on "The Horse's Mouth" - 2011-09-18 21:05:12 - Graham Ellis

There are times that we want to check the connectivity of all the systems on our subnet - to see which machines are present, and which are not. Pinging them one at a time is a bit slow, but pinging them all at once in a simple script sets up too many connections and the script is likely to fall over. Then how do you display the results quickly and easily?

I have updated an "old favourite" script - "tkpingle" which check out a series of systems named on the command line - to test a complete subnet. Systems are "ping"ed 16 at a time, and layed out in a grid rather than a single column

Here's the initial display - with systems xxx.xxx.xxx.0 and xxx.xxx.xxx.255 greyed out as these are special "broadcast" addresses and not to be assigned to any system.


During operation, systems are tested out column by column. All systems still to be tested are shown in salmon, with systems going red as their test starts, then changing to orange, yellow and finally white if they respond to three pings. Note that the "run" button is disabled while the test is running.


When the testing is completed, the "run" button is re-enabled and the status report updated to show that the tests are complete. And I've turned the status report to yellow so that it's very clear to the user that the tests are completed.


The complete script is [here]

Some elements worthy of comment (even for people who have used a bit of Tk and expect before ...

* Making a grid uniform

The following - applied to one label in each row and each column - ensures that all cells are going to be of the same width and height.

  grid rowconfigure . .la_$syslab -weight 1 -uniform w
  grid columnconfigure . .la_$syslab -weight 1 -uniform w


* Closing out complete or incomplete pings

Spawning processes uses up system resources that need to be released if there's further resources needed (if there wasn't anything further to do, we could get away without doing this as the script will clean up on exit).

The use of catch is to avoid crashing the script if the script had closed the resource already, and the wait is to ensure that the resource truely is closed.

  foreach done $tidy {
    if { [catch {close -i $done} msg ] } {
      # ignore
    } else {
      wait -i $done
    }
  }


* Spawning parallel processes A

Processes that are spawned set their ID in the global variable $spawn_id. We save all the spawn_ids away so that we can check how all the processes are running in parallel later on.

  for {set k 0} {$k < 16} {incr k} {
    set val [expr $k + $j * 16]
    set system "$subnet.$val"
    spawn ping -c 3 $system
    set id($system) $spawn_id


* Modal buttons

In order to avoid a second series of test being started while the previous set is still running, we disable the "run" button as soon as its been pressed ...

  .redo config -state disabled

... and we re-enable it just as it finished its work.

  .redo config -state normal