May 11, 2007 13:57
I'm going to try to make this an occasional series. The hacks aren't neccessarly written today, but something made me think of them on this purticular day.
Today's is a simple script to let things know what machine you're currently on, if you move about -- not what machine you are currently *running* on, but what machine you are actually sitting at -- hopefully, anyway. I tend to run a screen session on my desktop, and attach to it from my laptop when I'm not at my desk. This lets audio announcements happen where I'll hear them, and lets X applications show up where they need to.
Anyway, on to the code:
This is run from a cronjob, once per minute:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dump::Streamer;
$|=1;
my @lines = `w`;
my %positions;
#uptime, loadavg, etc.
shift @lines;
my $line = shift @lines;
pos($line)=0;
while (pos($line) < length($line)) {
my $start = pos($line);
#print "$line\n";
#print "Pos start: ", pos($line), "\n";
#print "Length: ", length($line), "\n";
$line =~ m/\G(\S+)\s*/g;
#print "Captured: $1\n";
# print "HEADER: $start: $1\n";
$positions{$start} = $1;
}
my @logins;
for my $line (@lines) {
my %login;
chomp $line;
pos($line) = 0;
while (pos($line) < length($line)) {
my $startpos = pos($line);
$line =~ m/\G(\S+)\s*/g;
my $str = $1;
#print "$startpos: $str\n";
my $header;
my $fakestartpos = $startpos;
while (!$header) {
$header=$positions{$fakestartpos};
$fakestartpos++;
}
if ($header eq 'WHAT') {
$str = substr($line, $startpos);
pos($line) = length($line);
}
if ($header =~ /^(IDLE|JCPU|PCPU)$/) {
if ($str =~ m/^(\d+(?:\.\d+)?)s$/) {
$str = $1;
} elsif ($str =~ m/^(\d+):(\d+)m$/) {
$str = $1*60 + $2;
} elsif ($str =~ m/^(\d+):(\d+)$/) {
$str = $1*60*60 + $2*60;
} elsif ($str =~ m/^(\d+)days$/) {
$str = $1*60*60*24;
} else {
warn "Nonparse of rel time: $str";
}
}
#print "$startpos: $str: $header\n";
$login{lc $header}=$str;
}
push @logins, \%login;
}
my $n = 0;
for my $login (sort {$a->{idle} <=> $b->{idle}} @logins) {
# Dump $login;
# print "Idle: $login->{idle}\n";
my $from = $login->{from};
my $host;
if (($host, my $screen) = $from =~ m/^(.*?):S\.(\d+)$/) {
if ($host =~ m/(.*?):(\d+)/) {
$host = $1;
}
$host ||= 'localhost';
# print "Screen session, attached from $host, number $screen\n";
} elsif ($from eq '-') {
$host = 'localhost';
} else {
$host = $from;
}
# print "Host is $host\n";
if ($n == 0) {
open my $fh, ">".glob("~/current-machine");
print $fh "$host\n";
close $fh;
utime time-$login->{idle}, time-$login->{idle}, glob("~/current-machine");
}
$n++;
}
Not exactly the most elegant of code, because I couldn't figure out a way to get the data without running w from a command prompt and then parsing it's output. All my attempts to gather the data myself ended in slight, but significant, changes, mostly in the idle time.
This is combined with a small bash hack to keep my DISPLAY variable up-to-date, to make X applications show up where I want them: export PROMPT_COMMAND='eval export DISPLAY=`cat ~/current-machine`:0'
(Note that the DISPLAY hack doesn't attempt to check if there actually is an X server running on that machine. There's not really anything sane to do if there isn't one anyway.)
Note also that all that is neccessary to keep current-machine up-to-date is to do screen -rd and wait a minute. On the other hand, updating DISPLAY requires hitting enter in a bash. Though it's mostly accidental, that matches when I actually want them updated.
(Later, I'll probably post say.pl, which uses current-machine give me audio announcements where they're needed.)