1#!/usr/local/bin/perl
2use strict;
3use Irssi 20011210.0250 ();
4use vars qw($VERSION %IRSSI);
5$VERSION = "1.3";
6%IRSSI = (
7    authors     => 'David Leadbeater',
8    contact     => 'dgl@dgl.cx',
9    name        => 'sysinfo-dg',
10    description => 'Adds a /sysinfo command which prints system information (linux only).',
11    license     => 'GNU GPLv2 or later',
12    url         => 'http://irssi.dgl.cx/',
13);
14
15#This script is mostly my own work but some ideas where taken from /sinfo by
16#Laurens Buhler and Alain van Acker. Please leave this credit in the script and
17#if you edit it and think the change is worthwhile tell me and i may add it into
18#the script and credit you
19
20use vars qw/$colour $graphs $graphs2 $colour2 $style/;
21Irssi::command_bind("sysinfo","sysinfo");
22
23sub sysinfo{
24   my @options = split(/ /,$_[0]);
25   my %info;
26   my($hostname,$uname,$procs) = basicinfo();
27   my($distro) = distro();
28   my($uptime,$users,$loadavg) = uptime();
29   my($memsize,$memfree) = meminfo();
30   my($swapsize,$swapfree) = swapinfo();
31   my($cpumodel,$cpumhz,$cpucache,$bogomips) = cpuinfo();
32   my %netinfo = netinfo();
33   my($disktotal,$diskused,$hddtype) = df();
34   my($videocard,$ethernet) = pciinfo();
35   my($screenres,$screendepth);
36   ($screenres,$screendepth) = screenres() if $ENV{DISPLAY};
37
38   ($colour,$graphs,$graphs2,$colour2,$style) = parseoptions(\%netinfo,@options);
39
40   %info = (
41      'os' => "$uname - $distro",
42      'up' => $uptime,
43      'cpu' => "$cpumodel, $cpumhz MHz ($bogomips bogomips)",
44      'cache' => $cpucache,
45      'mem' => ($memsize-$memfree) . "/$memsize MB (" . percent(($memsize-$memfree),$memsize) . ")",
46      'host' => $hostname,
47      'users' => $users,
48      'load' => $loadavg,
49      'procs' => $procs,
50      'swap' => ($swapsize-$swapfree) . "/$swapsize MB (" . percent(($swapsize-$swapfree),$swapsize) . ")",
51      'disk' => "$diskused/$disktotal MB (" . percent($diskused,$disktotal) . ") ($hddtype)",
52      'video' => "$videocard at $screenres ($screendepth bits)",
53      'ethernet' => $ethernet,
54   );
55
56   for(keys %netinfo){
57      $info{$_} = "in: $netinfo{$_}{in} MB, out: $netinfo{$_}{out} MB";
58   }
59
60   my $tmp;
61   for(split(/ /,$style)){
62      $tmp .= ircbit($_,$info{$_}) . " ";
63   }
64   $tmp =~ s/ $//;
65   Irssi::active_win()->command('say ' . $tmp);
66   ($colour,$graphs,$graphs2,$colour2,$style) = undef;
67}
68
69sub parseoptions{
70   my($netinfo,@options) = @_;
71
72   my $tmp = shift(@options) if $options[0] =~ /^\-/;
73   $tmp =~ s/^\-//;
74   for(split //,$tmp){
75	  if($_ eq "c"){
76		 $tmp =~ /c(\d+)/;
77		 $colour = $1;
78		 if(!$colour){
79			$colour = 3;
80		 }
81	  }elsif($_ eq "g"){
82		 $tmp =~ /g(\d+)/;
83		 $graphs = $1;
84		 if(!$graphs){
85			$graphs = 9;
86		 }
87	  }elsif($_ eq "G"){
88		 $tmp =~ /G(\d+)/;
89		 $graphs2 = $1;
90	  }elsif($_ eq "C"){
91		 $tmp =~ /C(\d+)/;
92		 $colour2 = $1;
93	  }
94   }
95   if(!defined $colour2 && $colour){
96	  $colour2 = 15;
97   }
98   if(defined $graphs && !defined $graphs2){
99	  $graphs2 = 3;
100   }
101
102# We got the names on the command line
103   if($options[1]){
104      $style = join(" ",@options);
105# style name
106   }elsif($options[0]){
107      if($options[0] eq "std"){
108	     $style = "os up cpu mem video";
109      }elsif($options[0] eq "bigger"){
110	     $style = "os up cpu cache mem load procs disk video";
111      }elsif($options[0] eq "full"){
112	     $style = "host os up cpu cache mem users load procs swap disk video ethernet ".join(" ",keys %{$netinfo});
113      }elsif($options[0] eq "net"){
114	     $style = join(" ",keys %{$netinfo});
115      }elsif($options[0] eq "uptime"){
116	     $style = "os up";
117      }elsif($options[0] eq "use"){
118	     $style = "mem swap disk";
119      }
120   }else{
121# no input - default
122      $style = "os up cpu mem video";
123   }
124
125   return($colour,$graphs,$graphs2,$colour2,$style);
126}
127
128sub ircbit{
129   my($name,$text) = @_;
130   $name = " " . $name if $name =~ /^\d/;
131   $text = " " . $text if $text =~ /^\d/;
132   if($colour){
133	  return "$colour$name$colour2\[$text$colour2\]";
134   }else{
135      return "$name\[$text\]";
136   }
137}
138
139sub percent{
140   my $percent = ($_[1] != 0) ? sprintf("%.1f",(($_[0]/$_[1])*100)) : 0;
141   if($graphs){
142	  my $tmp = "[";
143	  for(1..10){
144	     if($_ > sprintf("%.0f",$percent / 10)){
145			$tmp .= "-" if !defined $colour;
146			$tmp .= "$graphs2-" if defined $colour;
147	     }else{
148		    $tmp .= "|" if !defined $colour;
149		    $tmp .= "$graphs|" if defined $colour;
150	     }
151	  }
152	  $tmp .= "]";
153	  return $percent."% ".$tmp;
154   }
155   return $percent."%";
156}
157
158sub uptime{
159   my $uptimeinfo = `uptime`;
160   if ($uptimeinfo =~ /^\s+(\d+:\d+\w+|\d+:\d+:\d+)\s+up\s+(\d+)\s+day.?\W\s+(\d+):(\d+)\W\s+(\d+)\s+\w+\W\s+\w+\s+\w+\W\s+(\d+).(\d+)/igx) {
161     return("$2 days, $3 hours, $4 minutes", $5, "$6.$7");
162   }elsif ($uptimeinfo =~ /^\s+(\d+:\d+\w+|\d+:\d+:\d+)\s+up+\s+(\d+):(\d+)\W\s+(\d+)\s+\w+\W\s+\w+\s+\w+\W\s+(\d+).(\d+)/igx) {
163	  return("$2 hours, $3 minutes", $4, "$5.$6");
164   }elsif ($uptimeinfo =~ /^\s+(\d+:\d+\w+|\d+:\d+:\d+)\s+up\s+(\d+)\s+day.?\W\s+(\d+)\s+min\W\s+(\d+)\s+\w+\W\s+\w+\s+\w+\W\s+(\d+).(\d+)/igx) {
165	  return("$2 days, $3 minutes", $4, "$5.$6");
166   }elsif ($uptimeinfo =~ /^\s+(\d+:\d+\w+|\d+:\d+:\d+)\s+up+\s+(\d+)\s+min\W\s+(\d+)\s+\w+\W\s+\w+\s+\w+\W\s+(\d+).(\d+)/igx) {
167	  return("$2 minutes", $3, "$4.$5");
168   }
169   return undef;
170}
171
172sub meminfo{
173   my($memsize,$memfree);
174   open(MEMINFO, "<", "/proc/meminfo") or return undef;
175   while(<MEMINFO>){
176      chomp;
177      if(/^MemTotal:\s+(\d+)/){
178	     $memsize = sprintf("%.2f",$1/1024);
179      }elsif(/^MemFree:\s+(\d+)/){
180	     $memfree = sprintf("%.2f",$1/1024);
181      }
182   }
183   close(MEMINFO);
184   return($memsize,$memfree);
185}
186
187sub swapinfo{
188   my($swapsize,$swapused);
189   open(SWAPINFO, "<", "/proc/swaps");
190   while(<SWAPINFO>){
191	  chomp;
192	  next if !/^\//;
193	  /\S+\s+\S+\s+(\S+)\s+(\S+)/;
194	  $swapsize += $1;
195	  $swapused += $2;
196   }
197   close(SWAPINFO);
198   my $swapfree =  sprintf("%.2f",($swapsize - $swapused) / 1024);
199   $swapsize = sprintf("%.2f", $swapsize / 1024);
200   return($swapsize,$swapfree);
201}
202
203sub netinfo{
204   my(%netinfo);
205   open(NETINFO, "<", "/proc/net/dev") or return undef;
206   while(<NETINFO>){
207	  chomp;
208	  next if /^(\s+)?(Inter|face|lo)/;
209	  /^\s*(\w+):\s*(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+/;
210	  $netinfo{$1}{in} = sprintf("%.2f",$2 / 1048576);
211	  $netinfo{$1}{out} = sprintf("%.2f",$3 / 1048576);
212   }
213   close(NETINFO);
214   return %netinfo;
215}
216
217sub distro{
218   my $distro;
219   if(-f "/etc/coas"){
220      $distro = firstline("/etc/coas");
221   }elsif(-f "/etc/environment.corel"){
222      $distro = firstline("/etc/environment.corel");
223   }elsif(-f "/etc/debian_version"){
224      $distro = "Debian ".firstline("/etc/debian_version");
225   }elsif(-f "/etc/mandrake-release"){
226      $distro = firstline("/etc/mandrake-release");
227   }elsif(-f "/etc/SuSE-release"){
228      $distro = firstline("/etc/SuSE-release");
229   }elsif(-f "/etc/turbolinux-release"){
230      $distro = firstline("/etc/turbolinux-release");
231   }elsif(-f "/etc/slackware-release"){
232      $distro = firstline("/etc/slackware-release");
233   }elsif(-f "/etc/redhat-release"){
234      $distro = firstline("/etc/redhat-release");
235   }
236   return $distro;
237}
238
239sub df{
240   my($disktotal,$diskused,$mainhd);
241   for(`df`){
242      chomp;
243      next if !/^\/dev\/\S+/;
244      next if /(cd|cdrom|fd|floppy)/;
245      /^(\S+)\s+(\S+)\s+(\S+)/;
246	  $mainhd = $1 if !defined $mainhd;
247	  next if not defined $1 or not defined $2;
248      $disktotal += $2;
249      $diskused += $3;
250   }
251   $disktotal = sprintf("%.2f",$disktotal / 1024);
252   $diskused = sprintf("%.2f",$diskused / 1024);
253
254   $mainhd =~ s/\/dev\/([a-z]+)\d+/$1/;
255   my $hddtype = firstline("/proc/ide/$mainhd/model");
256
257   return($disktotal,$diskused,$hddtype);
258}
259
260sub basicinfo{
261   my($hostname,$sysinfo,$procs);
262   chomp($hostname = `hostname`);
263   chomp($sysinfo = `uname -sr`);
264   opendir(PROC, "/proc");
265   $procs = scalar grep(/^\d/,readdir PROC);
266   return($hostname,$sysinfo,$procs);
267}
268
269sub cpuinfo{
270   my($cpumodel,$cpusmp,$cpumhz,$cpucache,$bogomips);
271   open(CPUINFO, "<", "/proc/cpuinfo") or return undef;
272   while(<CPUINFO>){
273      if(/^model name\s+\:\s+(.*?)$/){
274	     if(defined $cpumodel){
275		    if(defined $cpusmp){
276			   $cpusmp++;
277		    }else{
278		       $cpusmp=2;
279		    }
280	     }else{
281	        $cpumodel = $1;
282	     }
283      }elsif(/^cpu MHz\s+:\s+([\d\.]*)/){
284	     $cpumhz = $1;
285      }elsif(/^cache size\s+:\s+(.*)/){
286	     $cpucache = $1;
287      }elsif(/^bogomips\s+:\s+([\d\.]*)/){
288		 $bogomips += $1;
289	  }
290   }
291   $cpumodel .= " SMP ($cpusmp processors)" if defined $cpusmp;
292   return($cpumodel,$cpumhz,$cpucache,$bogomips);
293}
294
295sub pciinfo{
296   my($videocard,$ethernet);
297   open(PCI, "-|", "/sbin/lspci") or return undef;
298   while(<PCI>){
299      chomp;
300      if(/VGA compatible controller: (.*?)$/){
301         $videocard .= "${1}+ ";
302      }elsif(/(Ethernet|Network) controller: (.*?)$/){
303	     $ethernet = $1;
304      }
305   }
306   close(PCI);
307   $videocard =~ s/\+ $//;
308   return($videocard,$ethernet);
309}
310
311sub screenres{
312   my ($res,$depth);
313   for(`xdpyinfo`){
314	  if(/\s+dimensions:\s+(\S+)/){
315		 $res = $1;
316	  }elsif(/\s+depth:\s+(\S+)/){
317		 $depth = $1;
318	  }
319   }
320   return($res,$depth);
321}
322
323sub firstline{
324   my $file = shift;
325   open(FILE, "<", $file) or return undef;
326   chomp(my $line = <FILE>);
327   close(FILE);
328   return $line;
329}
330
331