#!/usr/bin/perl
#
#	sysinfo - System information banner
#	Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2005 - 2009
#
#	This program is free software; you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation; either version 2 or 3 of the license.
#
use POSIX;
use strict;

do_hostname();
do_version();
do_loc();
do_cpuinfo();
do_loadavg();
do_meminfo();
do_disk();
do_gfx();

print "\n";


sub do_cpuinfo
{
	my($cpu_mhz, $cpu_max_mhz, $cpu_model, $cpu_vendor, $cpu_arch, $cpu_num);
	local *IN;

	chomp(my $karch = `uname -m 2>/dev/null`);

	if (!open(IN, "</proc/cpuinfo")) {
		return;
	}

	while (defined(my $l = <IN>)) {
		chomp $l;
		if ($l =~ /^processor\s+:/i) {
			++$cpu_num;
		} elsif ($l =~ /^vendor\s+:\s+(.*)/i) {
			$cpu_vendor = $1;
		} elsif ($l =~ /^arch\s+:\s+(.*)/i) {
			$cpu_arch = $1;
		} elsif ($l =~ /^(?:cpu|model name)\s+:\s+(.*)/i) {
			$cpu_model = $1;
			$cpu_model =~ s/\@?\s*\d+\.\d+[GM]Hz//s;
		} elsif ($l =~ /^cpu mhz\s+:\s+(.*)/i) {
			$cpu_mhz = $1;
		} elsif ($l =~ /^ncpus active\s+:\s+(\d+)/i) {
			$cpu_num = $1;
		}
	}
	$cpu_mhz =~ s/\..*//;
	if ($cpu_model eq "") {
		$cpu_model = "$cpu_vendor $cpu_arch";
	}
	$cpu_model =~ s/^\s*(?:dual|quad)(?:\s+core)?\s*//i;
	$cpu_model =~ s/ +/ /g;
	$cpu_model =~ s/ +$//g;
	if ($karch ne "") {
		print " $karch";
	}
	print " | ";
	if ($cpu_num > 1) {
		print "${cpu_num}x ";
	}
	close IN;

	if (open(IN, "cpufreq-info -f 2>/dev/null |")) {
		chomp(my $l = <IN>);
		if ($l != 0) {
			$cpu_mhz = int($l / 1000);
		}
		close IN;
	}

	if (open(IN, "cpufreq-info -l 2>/dev/null |")) {
		(undef, $cpu_max_mhz) = split(/\s+/, <IN>);
		$cpu_max_mhz = int($cpu_max_mhz / 1000);
		close IN;
	}

	print $cpu_model;
	if ($cpu_mhz != 0) {
		if ($cpu_max_mhz != 0) {
			print " \@$cpu_mhz/$cpu_max_mhz";
		} else {
			print " ", $cpu_mhz;
		}
		print " MHz";
	}
}

sub do_loc
{
	my $loc;

	if (!open(IN, "</proc/interrupts")) {
		return;
	}

	while (defined(my $line = <IN>)) {
		if ($line =~ /^LOC:\s*(\d+)/) {
			$loc = $1;
			last;
		}
	}

	close IN;
	if (!defined($loc)) {
		return;
	}

	sleep 1;
	if (!open(IN, "</proc/interrupts")) {
		return;
	}

	while (defined(my $line = <IN>)) {
		if ($line =~ /^LOC:\s*(\d+)/) {
			print " \@", $1 - $loc, "Hz";
			last;
		}
	}

	close IN;
}

sub do_disk
{
	if (!open(IN, "df 2>/dev/null |")) {
		return;
	}

	my($disk_total, $disk_used);
	while (defined(my $l = <IN>)) {
		chomp $l;
		if ($l =~ m{^/dev/\S+\s+(\d+)\s+(\d+)}) {
			$disk_total += $1;
			$disk_used += $2;
		}
	}
	close IN;
	printf " | DiskUse: %u/%uGB", $disk_used / 1048576,
	       $disk_total / 1048576;
}

sub do_gfx
{
	local *IN;

	if (!open(IN, "/sbin/lspci | grep 'VGA compatible controller:' |")) {
		return;
	}

	my $dev;
	chomp($dev = <IN>);
	close IN;
	if (!defined($dev)) {
		return;
	}
	$dev =~ s/^.*VGA compatible controller:\s+//;
	print " | Gfx: $dev";

	my($scr_res, $scr_virt);

	if (open(IN, "xdpyinfo 2>/dev/null |")) {
		while (defined(my $l = <IN>)) {
			if ($l =~ /\s+dimensions\s*:\s+(\S+)/i) {
				$scr_virt = $1;
			}
			chomp $l;
		}
		close IN;
	}

	if ($scr_virt ne "") {
		print " \@ $scr_virt";
	}
	if ($scr_res ne "") {
		print " \@ $scr_res";
	}
	close IN;
}

sub do_hostname
{
	local *IN;

	if (!open(IN, "hostname --fqdn 2>/dev/null |")) {
		return;
	}
	chomp(my $l = <IN>);
	print "[$l] ";
	close IN;
}

sub do_loadavg
{
	local *IN;

	if (!open(IN, "</proc/loadavg")) {
		return;
	}

	my($load1, $load5, $load15, $rtask, $stask) =
		(<IN> =~ /^(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\/(.+?)\s/);
	my $total = $rtask + $stask;
	printf " | Load: $load1 Tasks: $total";
	close IN;
}

sub do_meminfo
{
	if (!open(IN, "</proc/meminfo")) {
		return;
	}

	my($mem_total, $mem_free, $mem_buf, $mem_cac, $mem_used);
	while (defined(my $l = <IN>)) {
		chomp $l;
		if ($l =~ /^memtotal\s*:\s*(\d+)/i) {
			$mem_total = $1;
		} elsif ($l =~ /^memfree\s*:\s*(\d+)/i) {
			$mem_free = $1;
		} elsif ($l =~ /^buffers\s*:\s*(\d+)/i) {
			$mem_buf = $1;
		} elsif ($l =~ /^cached\s*:\s*(\d+)/i) {
			$mem_cac = $1;
		}
	}
	$mem_used = $mem_total - ($mem_free + $mem_buf + $mem_cac);
	printf " | MemUse: %u/%uMB", $mem_used / 1024, $mem_total / 1024;
	close IN;
}

sub do_uptime
{
	local *IN;

	if (!open(IN, "</proc/uptime")) {
		return;
	}

	my($up) = (<IN> =~ /^(\d+\.\d+)/);
	my $days = floor($up / 86400);
	my $hours = floor($up / 3600 % 24);
	my $minutes = floor($up / 60 % 60);
	my $seconds = floor($up % 60);
	printf " | Up:";
	if ($days > 0 ) {
		printf " %ud", $days;
	} elsif ($hours > 0) {
		printf " %uh", $hours;
	} elsif ($minutes > 0) {
		printf " %um", $minutes;
	} elsif ($seconds > 0) {
		printf " %us", $seconds;
	}
	close IN;
}

sub do_version
{
	local *IN;

	if (!open(IN, "< /proc/version")) {
		return;
	}

	my ($os, $ver) = (<IN> =~ /^(\w+)\s+\w+\s+(\S+)/i);
	print "$os $ver";
	close IN;
}
