File conkyconf.SUSE of Package conky
#!/bin/bash
#
# system
#
VERSION="0.1"
USER_CONFIG_FILE="$HOME/.config/conky/conky.conf"
DEFAULT_RSS_URL="https://www.novell.com/newsfeeds/rss/patches/security_notifications-daily.xml"
SYSTEM_LOG="| journalctl -q | tail -n 5"
USERS_LOG="| who"
ALIGNMENTS="|top_left|top_right|top_middle|bottom_left|bottom_right|bottom_middle|middle_left|middle_middle|middle_right,tl|tr|tm|bl|br|bm|ml|mm|mr|"
ip=ip
iwconfig=/usr/sbin/iwconfig
ss=/usr/sbin/ss
# log
function log()
{
verb=$1
msg="$2"
if [ $verb -le ${config[verbosity]} ]; then
echo "$msg" >&2
fi
}
# bail out
function die()
{
msg="$1"
log 0 "conkyconf: $msg"
log 2 "$0 unsuccessfully finished"
exit 1
}
# writing string to file
function sys_write_file()
{
file=$1
content=$2
dir=$(dirname $file)
if [ ! -d "$dir" ]; then
log 1 "creating $dir"
mkdir -p $dir || die "could not create $dir"
fi
log 1 "writing $file"
echo "$content" > "$file" || die "could not write $file"
return
}
# list of all network interfaces
function sys_all_network_interfaces()
{
interfaces=$($ip -br link show | sed 's:\s\+.*::' | grep -v 'tun\|lo' | tr '\n' ' ')
log 1 "detected interfaces: $interfaces"
echo $interfaces
}
# default interface
function sys_default_network_interface()
{
interface=$($ip route | grep default | sed 's:.*dev \(\S\+\) .*:\1:')
log 1 "detected default interface: $interface"
echo $interface
}
# wireless or wired network iterface?
function sys_network_interface_type()
{
interface=$1
type=$($iwconfig $1 2>&1 | grep -q 'no wireless' && echo "wired" || echo "wireless")
log 1 "network interface $interface is $type"
echo $type
}
# attached sdX drives
function sys_drives()
{
drives=$(find /dev -maxdepth 1 -type b -name "sd[a-z]" -exec basename "{}" ";" | sort)
log 1 "detected drives: $drives"
echo $drives
}
# processors
function sys_processors()
{
CPUS=$(getconf _NPROCESSORS_ONLN)
CPUS=${CPUS:=1}
cpus=$(seq 1 $CPUS | tr '\n' ' ')
log 1 "assuming numbers of CPUs: $cpus"
echo $cpus
}
# opened ports
function sys_opened_ports()
{
ports=$($ss -nlt | awk '{print $4}' | grep ':::\|\*:' | sed 's/:::\|\*://' | sort -u)
log 1 "opened ports: $ports"
echo $ports
}
#
# global config
#
function conky_config()
{
cat << EOS
conky.config = {
background = true,
update_interval = 1.5,
cpu_avg_samples = 2,
net_avg_samples = 2,
out_to_console = false,
override_utf8_locale = true,
double_buffer = true,
no_buffers = true,
text_buffer_size = 32768,
imlib_cache_size = 0,
own_window = true,
own_window_type = 'desktop',
own_window_argb_visual = true,
own_window_argb_value = 120,
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
border_inner_margin = 20,
border_outer_margin = 0,
alignment = '${config[alignment]}',
gap_x = ${config[gap_x]},
gap_y = ${config[gap_y]},
draw_shades = true,
draw_outline = false,
draw_borders = false,
draw_graph_borders = false,
use_xft = true,
font = 'monospace:size=9',
xftalpha = 0.8,
uppercase = false,
default_color = '#FFFFFF',
own_window_colour = '#000000',
maximum_width = 375
};
EOS
}
#
# contents of the window
#
# horizontal rule
function text_hr()
{
echo " \${goto 20}\${hr}"
}
# hostname, kernel, date and uptime
function text_preamble()
{
cat << EOS
\${goto 20}\${color #DD3A21}\${font monospace:bold:size=20}\${nodename}\${font}\${color}\${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${time %d/%m/%y}
\${goto 20}\${color #DD3A21}\${kernel}\${color}\${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${time %H:%M}
\${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${uptime}
EOS
}
# show one network interface info
function text_network_interface
{
if_name=$1
case $(sys_network_interface_type $if_name) in
"wired") icon= text="" ;;
"wireless") icon=; text="\${exec eval \$(/usr/sbin/iwconfig $if_name | grep 'Link Quality' | sed 's:.*Quality=\([0-9]\+\)/\([0-9]\+\).*:echo \$((\1*100/\2))%:')}" ;;
esac
cat << EOS
\${goto 20}\${font FontAwesome}$icon\${font}\${voffset -2} $if_name \${addrs $if_name} $text
\${goto 20}\${upspeedgraph $if_name 30,178 06E9F8 2104FA}\${goto 202}\${downspeedgraph $if_name 30,175 FFFF00 DD3A21}
\${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${upspeed $if_name}\${font FontAwesome}\${goto 202}\${font}\${voffset -2} \${downspeed $if_name}
EOS
}
# memory info
function text_memory
{
cat << EOS
\${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${mem}/\${memmax} (\${memperc}%) | Swap: \${swapperc}%
\${goto 20}\${memgraph 30,355 AAF5D0 00B35B}
EOS
}
# attached drive info
function text_drive
{
name=$1
cat << EOS
\${goto 20}\${font FontAwesome}\${font}\${voffset -2} $name
\${goto 20}\${diskiograph_read $name 30,178 06E9F8 2104FA}\${goto 202}\${diskiograph_write $name 30,175 FFFF00 DD3A21}
\${goto 20}\${font FontAwesome}\${goto 20}\${font}\${voffset -2} \${diskio_read $name}\${font FontAwesome}\${voffset -2}\${goto 202}\${font} \${diskio_write $name}
EOS
}
# processor info
function text_processor
{
name=$1
cat << EOS
\${goto 20}CPU$name: \${goto 90}\${cpu cpu$name}%\${goto 140}\${cpubar cpu$name 7,70}\${goto 230}\${freq_g $name} GHz
EOS
}
# process table
function text_processes
{
echo " \${color #FFFF00}\${goto 20}Name \${goto 200}Pid\${goto 255}Cpu%\${goto 310}Mem%\${color}"
for i in $(seq 1 5); do
echo " \${goto 20}\${top name $i} \${goto 180}\${top pid $i}\${goto 235}\${top cpu $i}\${goto 290}\${top mem $i}"
done
}
# rss feed
function text_rss
{
url=$1
cat << EOS
\${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${color #FFFF00}\${scroll 50 2 \${rss $url 10 item_titles 5}}\${color}
EOS
}
# port monitor
function text_portmon()
{
port_range=$1
echo -n " \${goto 20}"
if [[ $port_range =~ "-" ]]; then
echo -n "\${font FontAwesome}\${font}\${voffset -2} Port range $port_range"
port_range="$(tr '-' ' ')"
else
echo -n "\${font FontAwesome}\${font}\${voffset -2} Port $port_range"
port_range="$port_range $port_range"
echo -n ", service \${tcp_portmon $port_range lservice 0}"
fi
echo " (\${tcp_portmon $port_range count} connections)"
for i in $(seq 0 4); do
echo -n " \${goto 20}\${font monospace:size=8}"
echo -n "\${if_match \"\${tcp_portmon $port_range rip $i}\" != \"\"}"
echo -n "\${tcp_portmon $port_range rip $i}:"
echo -n "\${tcp_portmon $port_range rport $i} "
echo -n "\${tcp_portmon $port_range rhost $i} "
echo -n "\${if_match \"\${tcp_portmon $port_range rport $i}\" != \"\${tcp_portmon $port_range rservice $i}\"}"
echo -n "\${tcp_portmon $port_range rservice $i} "
echo -n "\${endif}"
echo -n "\${else}"
echo -n "-"
echo -n "\${endif}"
echo "\${font}"
done
}
# text when no port are defined
function text_portmon_no_ports()
{
echo " \${goto 20}Port monitor: no ports defined."
}
# logfile (including program outputs)
function text_log
{
logfile=$1
font_size=${2:-8}
echo -n " \${goto 20}\${font monospace:size=$font_size}"
if [[ "$logfile" =~ ^[[:space:]]*\| ]]; then
logfile=$(echo $logfile | sed 's:^\s*|\s*::')
log 1 "will read log from [$logfile] program"
echo -n \${texeci 10 $logfile}
else
log 1 "will read log from [$logfile] file"
echo -n \${tail $logfile 5}
fi
echo \${font}
}
function conky_text()
{
echo
echo "conky.text = [["
content_index=0
while [ -n "${contents[$content_index]}" ]; do
case "${contents[$content_index]}" in
preamble)
text_preamble
;;
hrule)
text_hr
;;
networkif*)
for nif in ${contents_arg[$content_index]}; do
text_network_interface $nif
done
;;
memory)
text_memory
;;
drives)
for d in ${contents_arg[$content_index]}; do
text_drive $d
done
;;
processors)
for p in ${contents_arg[$content_index]}; do
text_processor $p
done
;;
processes)
text_processes
;;
rss)
text_rss ${contents_arg[$content_index]}
;;
portmon)
if [ -n "${contents_arg[$content_index]}" ]; then
for range in ${contents_arg[$content_index]}; do
text_portmon $range
done
else
text_portmon_no_ports
fi
;;
log*)
fontsize=$(echo ${contents[$content_index]} | sed 's/.*://')
text_log "${contents_arg[$content_index]}" $fontsize
esac
content_index=$((content_index+1))
done
echo "]];"
}
# string is integer
function arg_is_numeric()
{
[[ "$1" =~ ^[0-9]+$ ]] && return 0 || return 1
}
# string is option
function arg_is_option()
{
arg=$1
[ ${arg:0:1} == '-' ] && return 0 || return 1
}
function arg_is_alignment()
{
[[ "$ALIGNMENTS" =~ "|$1|" ]] && return 0 || return 1
}
# end of argument list
function arg_is_end()
{
[ -z "$1" ] && return 0 || return 1
}
# split list argument, delimiters: [:,;]
function arg_split_list()
{
echo $1 | tr ':,;' ' '
}
# help on this script usage
function conkyconf_usage()
{
cat << EOS
$(echo ${0##*/} | tr [a-z] [A-Z]), version $VERSION
conky configuration example generator
USAGE
conkyconf --par1 [arg11 [arg12]] --par2 [arg21 [arg22]] ...
There are object parameters (as --memory, --networkif, --rule) and
non-object parameters (as --verbosity, --file). Object parameters
will add corresponding objects to conky configuration in that
order. Objects can be repeated for different arguments by
repeating it on command line.
More conky instantions can be launched, but then different configuration
files has to be used (see -f|--file option).
Configuration is written to
$USER_CONFIG_FILE
which has a precedence before system wide configuration file.
PARAMETERS
-h|--help this help
-v|--verbosity [verb] debug output of the script, 0 (just errors)
1 or 2
-f|--file <conffile> write the configuration to this file
-g|--geometry [a [x [y]]] geometry of conky window, parameters:
* a -- alignment top_left (tl), bottom_middle
(bm), middle_left (ml), middle_middle
(mm), etc.
* x -- gap between window and attached
vertical border
* y -- gap between window and attached
horizontal border
-r|--rule add horizontal rule
-p|--preamble host, kernel, time and uptime info
-n|--networkif [ifcs] network interface(s) info; arguments:
* 'all' -- all interfaces are monitored
* <no arg> -- default interface is chosen
* <list> -- comma, colon or semicolon
separated list of interfaces
-m|--memory memory info
-d|--drives [drvs] sdaX drives info; arguments:
* 'all' -- all drives are monitored
* <no arg> -- the same as 'all'
* <list> -- comma, colon or semicolon
separated list of drives
-c|--cpu add all CPUs info
-e|--processes show process table
-s|--rss [url] add a rss feed; if no url is given,
SUSE security rss feed is chosen
-t|--portmon [ports] display port monitor; arguments:
* <no arg> -- display opened ports
* <list> -- comma, colon or semicolon
separated list of ports
-l|--log [log [fs]] show tail of a log; arguments:
log:
* | <program> -- show output of the
program
* <file> -- show last 5 lines of
the log
* <noarg> -- $SYSTEM_LOG
fs: font size of the output
-u|--default choose default profile; objects can be added
or prepended
NOTE
Everytime some of monitored objects are changed, for example new port is
opened, usb stick is plugged in or connection is changed from wireless to
wired (and just default interface is monitored), then conkyconf has to be
rerun. conky then rereads the configuration automatically.
EXAMPLES
conkyconf --default
Uses built in preset.
conkyconf --preamble -r --networkif -r --drives -r --cpu
Shows preamble, default network interface, all attached
drives and cpu information, in that order.
conkyconf --preamble -r --drives sda:sdb -r --networkif em1 \\
-r --cpu -r --log '|who' 8 -r --log
Displays peramble, network drives sda and sdb, interface em1 and
cpu information and also output of who command in font size 8
and system log in default font size for logs.
EOS
}
declare -A contents
declare -A contents_arg
declare -A config
config[verbosity]=0
config[file]="$USER_CONFIG_FILE"
config[alignment]="bottom_right"
config[gap_x]="70"
config[gap_y]="70"
if [ -z "$1" ]; then
set -- "--help"
fi
content_index=0
while [ -n "$1" ]; do
arg_is_option "$1" || die "option starting with '-' or '--' expected ($1)"
case "$1" in
-h|--help)
conkyconf_usage
exit 0
;;
-v|--verbosity)
shift
if ! arg_is_end "$1" && arg_is_numeric "$1"; then
config[verbosity]="$1"
shift;
else
config[verbosity]=2
fi
log 1 "verbosity set to ${config[verbosity]}"
;;
-p|--preamble)
shift
log 2 'adding preamble'
contents[$content_index]="preamble"
content_index=$((content_index+1))
;;
-r|--hrule)
shift
log 2 'adding horizontal rule'
contents[$content_index]="hrule"
content_index=$((content_index+1))
;;
-n|--networkif)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if [ $1 == "all" ]; then
devices="$(sys_all_network_interfaces)"
else
devices="$(arg_split_list $1)"
fi
shift
else
devices="$(sys_default_network_interface)"
fi
log 2 "adding network interface monitor: $devices"
contents[$content_index]="networkif"
contents_arg[$content_index]="$devices"
content_index=$((content_index+1))
;;
-m|--memory)
shift
log 2 'adding memory info'
contents[$content_index]="memory"
content_index=$((content_index+1))
;;
-d|--drives)
shift
# -d and -d all the same effect
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if [ "$1" == "all" ]; then
drives="$(sys_drives)"
else
drives="$(arg_split_list $1)"
fi
shift
else
drives="$(sys_drives)"
fi
log 2 "adding hard drives: $drives"
contents[$content_index]="drives"
contents_arg[$content_index]="$drives"
content_index=$((content_index+1))
;;
-c|--cpu)
shift
processors="$(sys_processors)"
log 2 "adding cpu units: $processors"
contents[$content_index]="processors"
contents_arg[$content_index]="$processors"
content_index=$((content_index+1))
;;
-e|--processes)
shift
log 2 "adding process table"
contents[$content_index]="processes"
content_index=$((content_index+1))
;;
-s|--rss)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
url="$1"
else
url="$DEFAULT_RSS_URL"
fi
log 2 "adding rss feed: $url"
contents[$content_index]="rss"
contents_arg[$content_index]="$url"
content_index=$((content_index+1))
;;
-t|--portmon)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
port_ranges="$(arg_split_list $1)"
shift
else
port_ranges="$(sys_opened_ports)"
fi
log 2 "adding port monitor for port ranges: $port_ranges"
contents[$content_index]="portmon"
contents_arg[$content_index]="$port_ranges"
content_index=$((content_index+1))
;;
-l|--log)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1" && ! arg_is_numeric "$1"; then
log="$1"
shift
else
log="$SYSTEM_LOG"
fi
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if arg_is_numeric "$1"; then
font_size="$1"
shift
else
die "numeric argument (font size of the log) expected"
fi
else
font_size=6
fi
log 2 "adding logging: $log"
contents[$content_index]="log:$font_size"
contents_arg[$content_index]="$log"
content_index=$((content_index+1))
;;
-u|--default)
shift
contents[0]="preamble"
contents[1]="hrule"
contents[2]="networkif"
contents_arg[2]="$(sys_default_network_interface)"
contents[3]="hrule"
contents[4]="drives"
contents_arg[4]="$(sys_drives)"
contents[5]="hrule"
contents[6]="processors"
contents_arg[6]="$(sys_processors)"
contents[7]="hrule"
contents[8]="processes"
contents[9]="hrule"
contents[10]="portmon"
contents_arg[10]="$(sys_opened_ports)"
contents[11]="hrule"
contents[12]="log:8"
contents_arg[12]="$USERS_LOG"
contents[13]="hrule"
contents[14]="log:6"
contents_arg[14]="$SYSTEM_LOG"
contents[15]="hrule"
contents[16]="rss"
contents_arg[16]="$DEFAULT_RSS_URL"
content_index=17
;;
-f|--file)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
config[file]="$1"
shift
else
die "-f|--file requires an argument"
fi
;;
-g|--geometry)
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if ! arg_is_alignment "$1"; then
die "first argument of -g|--geometry has to be one of $ALIGNMENTS"
fi
config[alignment]="$1"
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if ! arg_is_numeric "$1"; then
die "second argument of -g|--geometry has to be a number"
fi
config[gap_x]="$1"
shift
if ! arg_is_end "$1" && ! arg_is_option "$1"; then
if ! arg_is_numeric "$1"; then
die "third argument of -g|--geometry has to be a number"
fi
config[gap_y]="$1"
shift
fi
fi
else
die "-g|--geometry requires an argument"
fi
;;
*)
die "unsupported option ($1)"
shift
;;
esac
done
log 2 "arguments parsed"
log 1 "geometry: ${config[alignment]}, ${config[gap_x]}, ${config[gap_y]}"
log 2 "creating configuration"
conky_configuration="$(conky_config)$(conky_text)"
log 2 "wrinting configuration"
sys_write_file ${config[file]} "$conky_configuration"
log 2 "$0 successfully finished"