#!/usr/bin/ruby
#
# Copyright (c) 2006 Peter Palfrader
#
#%# family=auto
#%# capabilities=autoconf suggest
#
# Munin plugin to moniture temperatures reported by 1-wire devices
# 
# I use owfs to mount the 1-wire bus to /var/lib/owfs
#   http://owfs.sourceforge.net/
#
# Add the following to your /etc/munin/plugin-conf.d/munin-node:
# [owfs_temperature_10.D234EE000800]
# user root
# env.title in rack 3
# env.label rack 3
#

$owfs_path = '/var/lib/owfs'
$owfs_path = ENV['OWFSPATH'] if ENV['OWFSPATH']

def bail_out(m)
	STDERR.puts "#{$0}: #{m}"
	exit 1
end

def autoconf
	if File.directory?($owfs_path)
		if File.directory?($owfs_path + '/structure')
			puts "yes"
		else
			puts "no (#{$owfs_path}/structure does not exist or permission denied - owfs not mounted?)"
		end
	else
		puts "no (#{$owfs_path} does not exist or permission denied)"
	end
end
def suggest
	Dir.glob($owfs_path+'/[0-9A-F][0-9A-F].*/temperature').each do |path|
		puts File.basename(File.dirname(path))
	end
end

def normalize_sensor(s)
	s = s.downcase
	s = s.tr('-', 'M')
	s = s.tr('+', 'P')
	s.tr('^a-zA-Z0-9', '_')
end

def query_device
	match = /_([0-9A-F][0-9A-F]\..*?)$/.match($0)
	unless match
		bail_out "Could not figure out which device you want based on executeable name."
	end
	match[1]
end

def config
	device = query_device
	title = ENV['title'] ?
	        ENV['title'] :
	        'Temperatures #{device}'
	label = ENV['label'] ?
	        ENV['label'] :
	        device
	puts "graph_title #{title}"
	puts "graph_args --base 1000"
	puts "graph_vlabel degrees Celsius";
	puts "graph_category sensors"
	puts "graph_info Temperature reported by 1-wire devices"
	n = normalize_sensor device
	puts "#{n}.label #{label}"
end


def runcmd(command, input)
	rdin , wrin  = IO.pipe
	rdout, wrout = IO.pipe
	rderr, wrerr = IO.pipe

	pid = fork
	unless pid
		# child
		wrin.close
		rdout.close
		rderr.close
		STDIN.reopen rdin
		STDOUT.reopen wrout
		STDERR.reopen wrerr
		exec(*command)
		throw("fell through exec(). WTF.")
	end
	rdin.close
	wrout.close
	wrerr.close

	out = []
	err = []
	tin  = Thread.new { wrin.print input; wrin.close }
	tout = Thread.new { out = rdout.readlines }
	terr = Thread.new { err = rderr.readlines }
	tin.join
	tout.join
	terr.join
	Process.wait pid

	exitstatus = $?.exitstatus

	[exitstatus, out, err]
end

def report
	device = query_device
	Process.gid=0
	Process.egid=0

	# fuse does weird checks.  this fails:
	# File.new($owfs_path+'/'+device+'/temperature', "r") ---> FAILS: in `initialize': Permission denied - /var/lib/owfs/10.D234EE000800/temperature (Errno::EACCES)

	# Sometimes the directory in OWFS does not exist, and cat will say
	# cat: /var/lib/owfs/10.D234EE000800/temperature: Invalid argument
	# so retry it a few times, since ls'ing the directory helps on the command line at least
	5.times do
		exitstatus, out, err = runcmd(['cat', $owfs_path+'/'+device+'/temperature'], '')
		if exitstatus != 0
			STDERR.puts "Child exited with non-zero exit code(%d): %s"%[exitstatus >> 8, err.join]
			runcmd(['ls', $owfs_path], '')
			sleep 1
		else
			STDERR.puts "command succeeded but returned something on stderr: #{err.join}" if err.size > 0
			n = normalize_sensor device
			puts "#{n}.value #{out.join}"
			return
		end
	end
	STDERR.puts "Could not get data."
end


case ARGV[0]
	when "autoconf"
		autoconf
	when "suggest"
		suggest
	when "config"
		config
	else
		report
end