File conkyconf.SUSE of Package conky

713
 
1
#!/bin/bash
2
#
3
# system
4
#
5
6
VERSION="0.1"
7
USER_CONFIG_FILE="$HOME/.config/conky/conky.conf"
8
DEFAULT_RSS_URL="https://www.novell.com/newsfeeds/rss/patches/security_notifications-daily.xml"
9
SYSTEM_LOG="| journalctl -q | tail -n 5"
10
USERS_LOG="| who"
11
12
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|"
13
14
ip=ip
15
iwconfig=/usr/sbin/iwconfig
16
ss=/usr/sbin/ss
17
18
# log
19
function log()
20
{
21
  verb=$1
22
  msg="$2"
23
24
  if [ $verb -le ${config[verbosity]} ]; then
25
    echo "$msg" >&2
26
  fi
27
}
28
29
# bail out
30
function die()
31
{
32
  msg="$1"
33
  log 0 "conkyconf: $msg"
34
  log 2 "$0 unsuccessfully finished"
35
  exit 1
36
}
37
38
# writing string to file
39
function sys_write_file()
40
{
41
  file=$1
42
  content=$2
43
44
  dir=$(dirname $file)
45
  if [ ! -d "$dir" ]; then
46
    log 1 "creating $dir"
47
    mkdir -p $dir || die "could not create $dir"
48
  fi
49
50
  log 1 "writing $file"
51
52
  echo "$content" > "$file" || die "could not write $file"
53
  return
54
}
55
56
# list of all network interfaces
57
function sys_all_network_interfaces()
58
{
59
  interfaces=$($ip -br link show | sed 's:\s\+.*::' | grep -v 'tun\|lo' | tr '\n' ' ')
60
  log 1 "detected interfaces: $interfaces"
61
  echo $interfaces
62
}
63
64
# default interface
65
function sys_default_network_interface()
66
{
67
  interface=$($ip route | grep default | sed 's:.*dev \(\S\+\) .*:\1:')
68
  log 1 "detected default interface: $interface"
69
  echo $interface
70
}
71
72
# wireless or wired network iterface?
73
function sys_network_interface_type()
74
{
75
  interface=$1
76
  type=$($iwconfig $1 2>&1 | grep -q 'no wireless' && echo "wired" || echo "wireless")
77
  log 1 "network interface $interface is $type"
78
  echo $type
79
}
80
81
# attached sdX drives
82
function sys_drives()
83
{
84
  drives=$(find /dev -maxdepth 1 -type b -name "sd[a-z]" -exec basename "{}" ";" | sort)
85
  log 1 "detected drives: $drives"
86
  echo $drives
87
}
88
89
# processors
90
function sys_processors()
91
{
92
  CPUS=$(getconf _NPROCESSORS_ONLN)
93
  CPUS=${CPUS:=1}
94
  cpus=$(seq 1 $CPUS | tr '\n' ' ')
95
  log 1 "assuming numbers of CPUs: $cpus"
96
  echo $cpus
97
}
98
99
# opened ports
100
function sys_opened_ports()
101
{
102
  ports=$($ss -nlt | awk '{print $4}' | grep ':::\|\*:' | sed 's/:::\|\*://' | sort -u)
103
  log 1 "opened ports: $ports"
104
  echo $ports
105
}
106
107
#
108
# global config
109
#
110
111
function conky_config()
112
{
113
  cat << EOS
114
conky.config = {
115
        background = true,
116
        update_interval = 1.5,
117
        cpu_avg_samples = 2,
118
        net_avg_samples = 2,
119
        out_to_console = false,
120
        override_utf8_locale = true,
121
        double_buffer = true,
122
        no_buffers = true,
123
        text_buffer_size = 32768,
124
        imlib_cache_size = 0,
125
        own_window = true,
126
        own_window_type = 'desktop',
127
        own_window_argb_visual = true,
128
        own_window_argb_value = 120,
129
        own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
130
        border_inner_margin = 20,
131
        border_outer_margin = 0,
132
        alignment = '${config[alignment]}',
133
        gap_x = ${config[gap_x]},
134
        gap_y = ${config[gap_y]},
135
        draw_shades = true,
136
        draw_outline = false,
137
        draw_borders = false,
138
        draw_graph_borders = false,
139
        use_xft = true,
140
        font = 'monospace:size=9',
141
        xftalpha = 0.8,
142
        uppercase = false,
143
        default_color = '#FFFFFF',
144
        own_window_colour = '#000000',
145
        maximum_width = 375
146
};
147
148
EOS
149
}
150
151
#
152
# contents of the window
153
#
154
155
# horizontal rule
156
function text_hr()
157
{
158
  echo "        \${goto 20}\${hr}"
159
}
160
161
# hostname, kernel, date and uptime
162
function text_preamble()
163
{
164
  cat << EOS
165
        \${goto 20}\${color #DD3A21}\${font monospace:bold:size=20}\${nodename}\${font}\${color}\${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${time %d/%m/%y}
166
        \${goto 20}\${color #DD3A21}\${kernel}\${color}\${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${time %H:%M}
167
        \${goto 250}\${font FontAwesome}\${font}\${voffset -2} \${uptime}
168
EOS
169
}
170
171
# show one network interface info
172
function text_network_interface
173
{
174
  if_name=$1
175
  case $(sys_network_interface_type $if_name) in
176
    "wired")    icon=  text="" ;;
177
    "wireless") icon=; text="\${exec eval \$(/usr/sbin/iwconfig $if_name | grep 'Link Quality' | sed 's:.*Quality=\([0-9]\+\)/\([0-9]\+\).*:echo \$((\1*100/\2))%:')}" ;;
178
  esac
179
  cat << EOS
180
        \${goto 20}\${font FontAwesome}$icon\${font}\${voffset -2} $if_name \${addrs $if_name} $text
181
        \${goto 20}\${upspeedgraph $if_name 30,178 06E9F8 2104FA}\${goto 202}\${downspeedgraph $if_name 30,175 FFFF00 DD3A21}
182
        \${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${upspeed $if_name}\${font FontAwesome}\${goto 202}\${font}\${voffset -2} \${downspeed $if_name}
183
EOS
184
}
185
186
# memory info
187
function text_memory
188
{
189
  cat << EOS
190
        \${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${mem}/\${memmax} (\${memperc}%) | Swap: \${swapperc}%
191
        \${goto 20}\${memgraph 30,355 AAF5D0 00B35B}
192
EOS
193
}
194
195
# attached drive info
196
function text_drive
197
{
198
  name=$1  
199
200
201
  cat << EOS
202
        \${goto 20}\${font FontAwesome}\${font}\${voffset -2} $name 
203
        \${goto 20}\${diskiograph_read $name 30,178 06E9F8 2104FA}\${goto 202}\${diskiograph_write $name 30,175 FFFF00 DD3A21} 
204
        \${goto 20}\${font FontAwesome}\${goto 20}\${font}\${voffset -2} \${diskio_read $name}\${font FontAwesome}\${voffset -2}\${goto 202}\${font} \${diskio_write $name}
205
EOS
206
}
207
208
# processor info
209
function text_processor
210
{
211
  name=$1
212
  cat << EOS
213
        \${goto 20}CPU$name: \${goto 90}\${cpu cpu$name}%\${goto 140}\${cpubar cpu$name 7,70}\${goto 230}\${freq_g $name} GHz
214
EOS
215
}
216
217
# process table
218
function text_processes
219
{  
220
  echo  "        \${color #FFFF00}\${goto 20}Name \${goto 200}Pid\${goto 255}Cpu%\${goto 310}Mem%\${color}"
221
  for i in $(seq 1 5); do
222
    echo "        \${goto 20}\${top name $i} \${goto 180}\${top pid $i}\${goto 235}\${top cpu $i}\${goto 290}\${top mem $i}"
223
  done
224
}
225
226
# rss feed
227
function text_rss
228
{
229
  url=$1
230
  cat << EOS
231
        \${goto 20}\${font FontAwesome}\${font}\${voffset -2} \${color #FFFF00}\${scroll 50 2 \${rss $url 10 item_titles 5}}\${color}
232
EOS
233
}
234
235
# port monitor
236
function text_portmon()
237
{
238
  port_range=$1
239
  
240
  echo -n "        \${goto 20}"
241
  if [[ $port_range =~ "-" ]]; then
242
    echo -n "\${font FontAwesome}\${font}\${voffset -2} Port range $port_range"
243
    port_range="$(tr '-' ' ')"
244
  else
245
    echo -n "\${font FontAwesome}\${font}\${voffset -2} Port $port_range"
246
    port_range="$port_range $port_range"
247
    echo -n ", service \${tcp_portmon $port_range lservice 0}"
248
  fi
249
  echo " (\${tcp_portmon $port_range count} connections)"
250
251
  for i in $(seq 0 4); do
252
    echo -n "        \${goto 20}\${font monospace:size=8}"
253
    echo -n "\${if_match \"\${tcp_portmon $port_range rip $i}\" != \"\"}"
254
    echo -n "\${tcp_portmon $port_range rip $i}:"
255
    echo -n "\${tcp_portmon $port_range rport $i} "
256
    echo -n "\${tcp_portmon $port_range rhost $i} "
257
    echo -n "\${if_match \"\${tcp_portmon $port_range rport $i}\" != \"\${tcp_portmon $port_range rservice $i}\"}"
258
    echo -n "\${tcp_portmon $port_range rservice $i} "
259
    echo -n "\${endif}"
260
    echo -n "\${else}"
261
    echo -n "-"
262
    echo -n "\${endif}"
263
    echo "\${font}"
264
 done
265
266
}
267
268
# text when no port are defined
269
function text_portmon_no_ports()
270
{
271
  echo "        \${goto 20}Port monitor: no ports defined."
272
}
273
274
# logfile (including program outputs)
275
function text_log
276
{
277
  logfile=$1
278
  font_size=${2:-8}
279
280
  echo -n "        \${goto 20}\${font monospace:size=$font_size}"
281
  if [[ "$logfile" =~ ^[[:space:]]*\| ]]; then
282
     logfile=$(echo $logfile | sed 's:^\s*|\s*::')
283
     log 1 "will read log from [$logfile] program"
284
    echo -n \${texeci 10 $logfile}
285
  else
286
    log 1 "will read log from [$logfile] file"
287
    echo -n \${tail $logfile 5}
288
  fi
289
  echo \${font}
290
}
291
292
function conky_text()
293
{
294
  echo
295
  echo "conky.text = [["
296
  content_index=0
297
  while [ -n "${contents[$content_index]}" ]; do
298
    case "${contents[$content_index]}" in
299
      preamble)
300
        text_preamble
301
        ;;
302
      hrule)
303
        text_hr
304
        ;;
305
      networkif*)
306
        for nif in ${contents_arg[$content_index]}; do
307
          text_network_interface $nif
308
        done
309
        ;;
310
      memory)
311
        text_memory
312
        ;;
313
      drives)
314
        for d in ${contents_arg[$content_index]}; do
315
          text_drive $d
316
        done
317
        ;;
318
      processors)
319
        for p in ${contents_arg[$content_index]}; do
320
          text_processor $p
321
        done
322
        ;;
323
      processes)
324
        text_processes
325
        ;;
326
      rss)
327
        text_rss ${contents_arg[$content_index]}
328
        ;;
329
      portmon)
330
        if [ -n "${contents_arg[$content_index]}" ]; then
331
          for range in ${contents_arg[$content_index]}; do
332
            text_portmon $range
333
          done
334
        else
335
          text_portmon_no_ports
336
        fi
337
        ;;
338
      log*)
339
        fontsize=$(echo ${contents[$content_index]} | sed 's/.*://')
340
        text_log "${contents_arg[$content_index]}" $fontsize
341
    esac
342
    content_index=$((content_index+1))
343
  done
344
  echo "]];"
345
}
346
347
# string is integer
348
function arg_is_numeric()
349
{
350
  [[ "$1" =~ ^[0-9]+$ ]] && return 0 || return 1
351
}
352
353
# string is option
354
function arg_is_option()
355
{
356
  arg=$1
357
  [ ${arg:0:1} == '-' ] && return 0 || return 1
358
}
359
360
function arg_is_alignment()
361
{
362
  [[ "$ALIGNMENTS" =~ "|$1|" ]] && return 0 || return 1
363
}
364
365
# end of argument list
366
function arg_is_end()
367
{
368
  [ -z "$1" ] && return 0 || return 1
369
}
370
371
# split list argument, delimiters: [:,;]
372
function arg_split_list()
373
{
374
  echo $1 | tr ':,;' ' '
375
}
376
377
# help on this script usage
378
function conkyconf_usage()
379
{
380
  cat << EOS
381
$(echo ${0##*/} | tr [a-z] [A-Z]), version $VERSION
382
383
 conky configuration example generator
384
385
 USAGE  
386
387
     conkyconf --par1 [arg11 [arg12]] --par2 [arg21 [arg22]] ...
388
389
 There are object parameters (as --memory, --networkif, --rule) and 
390
 non-object parameters (as --verbosity, --file). Object parameters
391
 will add corresponding objects to conky configuration in that
392
 order. Objects can be repeated for different arguments by 
393
 repeating it on command line.
394
395
 More conky instantions can be launched, but then different configuration
396
 files has to be used (see -f|--file option).
397
398
 Configuration is written to
399
400
 $USER_CONFIG_FILE
401
402
 which has a precedence before system wide configuration file.
403
404
 PARAMETERS
405
406
     -h|--help                  this help
407
     -v|--verbosity [verb]      debug output of the script, 0 (just errors)
408
                                1 or 2
409
     -f|--file <conffile>       write the configuration to this file
410
     -g|--geometry [a [x [y]]]  geometry of conky window, parameters:
411
                                * a -- alignment top_left (tl), bottom_middle 
412
                                       (bm), middle_left (ml), middle_middle 
413
                                       (mm), etc.
414
                                * x -- gap between window and attached 
415
                                       vertical border
416
                                * y -- gap between window and attached 
417
                                       horizontal border
418
419
420
     -r|--rule                  add horizontal rule
421
     -p|--preamble              host, kernel, time and uptime info
422
     -n|--networkif [ifcs]      network interface(s) info; arguments:
423
                                * 'all'    -- all interfaces are monitored
424
                                * <no arg> -- default interface is chosen
425
                                * <list>   -- comma, colon or semicolon
426
                                          separated list of interfaces
427
     -m|--memory                memory info
428
     -d|--drives [drvs]         sdaX drives info; arguments:
429
                                * 'all'    -- all drives are monitored
430
                                * <no arg> -- the same as 'all'
431
                                * <list>   -- comma, colon or semicolon
432
                                          separated list of drives
433
     -c|--cpu                   add all CPUs info
434
     -e|--processes             show process table
435
     -s|--rss [url]             add a rss feed; if no url is given,
436
                                SUSE security rss feed is chosen
437
     -t|--portmon [ports]       display port monitor; arguments:
438
                                * <no arg> -- display opened ports
439
                                * <list>   -- comma, colon or semicolon
440
                                              separated list of ports
441
     -l|--log [log [fs]]       show tail of a log; arguments:
442
                               log:
443
                                * | <program> -- show output of the 
444
                                                 program
445
                                * <file>      -- show last 5 lines of 
446
                                                 the log
447
                                * <noarg>     -- $SYSTEM_LOG
448
                               fs: font size of the output
449
450
451
      -u|--default             choose default profile; objects can be added
452
                               or prepended
453
454
 NOTE
455
456
 Everytime some of monitored objects are changed, for example new port is 
457
 opened, usb stick is plugged in or connection is changed from wireless to 
458
 wired (and just default interface is monitored), then conkyconf has to be
459
 rerun. conky then rereads the configuration automatically.
460
461
 EXAMPLES
462
463
   conkyconf --default
464
465
      Uses built in preset.
466
467
   conkyconf --preamble -r --networkif -r --drives -r --cpu
468
469
      Shows preamble, default network interface, all attached
470
      drives and cpu information, in that order.
471
472
   conkyconf --preamble -r --drives sda:sdb -r --networkif em1 \\
473
             -r --cpu -r --log '|who' 8  -r --log
474
      
475
      Displays peramble, network drives sda and sdb, interface em1 and
476
      cpu information and also output of who command in font size 8
477
      and system log in default font size for logs.
478
EOS
479
}
480
481
482
483
declare -A contents
484
declare -A contents_arg
485
declare -A config
486
487
config[verbosity]=0
488
config[file]="$USER_CONFIG_FILE"
489
config[alignment]="bottom_right"
490
config[gap_x]="70"
491
config[gap_y]="70"
492
493
if [ -z "$1" ]; then
494
  set -- "--help"
495
fi
496
497
content_index=0
498
while [ -n "$1" ]; do
499
  arg_is_option "$1" || die "option starting with '-' or '--' expected ($1)"
500
501
  case "$1" in
502
    -h|--help)
503
      conkyconf_usage
504
      exit 0
505
      ;;
506
    -v|--verbosity)
507
      shift
508
      if ! arg_is_end "$1" && arg_is_numeric "$1"; then 
509
        config[verbosity]="$1"
510
        shift; 
511
      else
512
        config[verbosity]=2
513
      fi
514
      log 1 "verbosity set to ${config[verbosity]}"
515
      ;;
516
    -p|--preamble)
517
      shift
518
      log 2 'adding preamble'
519
      contents[$content_index]="preamble"
520
      content_index=$((content_index+1))
521
      ;;
522
    -r|--hrule)
523
      shift
524
      log 2 'adding horizontal rule'
525
      contents[$content_index]="hrule"
526
      content_index=$((content_index+1))
527
      ;;
528
    -n|--networkif)
529
      shift
530
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
531
        if [ $1 == "all" ]; then
532
          devices="$(sys_all_network_interfaces)"
533
        else
534
          devices="$(arg_split_list $1)"
535
        fi
536
        shift
537
      else
538
        devices="$(sys_default_network_interface)"
539
      fi
540
      log 2 "adding network interface monitor: $devices"
541
      contents[$content_index]="networkif"
542
      contents_arg[$content_index]="$devices"
543
      content_index=$((content_index+1))
544
      ;;
545
    -m|--memory)
546
      shift
547
      log 2 'adding memory info'
548
      contents[$content_index]="memory"
549
      content_index=$((content_index+1))
550
      ;;
551
    -d|--drives)
552
      shift
553
      # -d and -d all the same effect
554
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
555
        if [ "$1" == "all" ]; then
556
          drives="$(sys_drives)"
557
        else
558
          drives="$(arg_split_list $1)"
559
        fi
560
        shift
561
      else
562
        drives="$(sys_drives)"
563
      fi
564
      log 2 "adding hard drives: $drives"
565
      contents[$content_index]="drives"
566
      contents_arg[$content_index]="$drives"
567
      content_index=$((content_index+1))
568
      ;;
569
    -c|--cpu)
570
      shift
571
      processors="$(sys_processors)"
572
      log 2 "adding cpu units: $processors"
573
      contents[$content_index]="processors"
574
      contents_arg[$content_index]="$processors"
575
      content_index=$((content_index+1))
576
      ;;
577
    -e|--processes)
578
      shift
579
      log 2 "adding process table"
580
      contents[$content_index]="processes"
581
      content_index=$((content_index+1))
582
      ;;
583
    -s|--rss)
584
      shift
585
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
586
        url="$1"
587
      else
588
        url="$DEFAULT_RSS_URL"
589
      fi
590
      log 2 "adding rss feed: $url"
591
      contents[$content_index]="rss"
592
      contents_arg[$content_index]="$url"
593
      content_index=$((content_index+1))
594
      ;;
595
    -t|--portmon)
596
      shift
597
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
598
        port_ranges="$(arg_split_list $1)"
599
        shift
600
      else
601
        port_ranges="$(sys_opened_ports)"
602
      fi
603
      log 2 "adding port monitor for port ranges: $port_ranges"
604
      contents[$content_index]="portmon"
605
      contents_arg[$content_index]="$port_ranges"
606
      content_index=$((content_index+1))
607
      ;;
608
    -l|--log)
609
      shift
610
      if ! arg_is_end "$1" && ! arg_is_option "$1" && ! arg_is_numeric "$1"; then
611
        log="$1"
612
        shift
613
      else
614
        log="$SYSTEM_LOG"
615
      fi
616
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
617
        if arg_is_numeric "$1"; then
618
          font_size="$1"
619
          shift
620
        else
621
          die "numeric argument (font size of the log) expected"
622
        fi
623
      else
624
        font_size=6
625
      fi
626
      log 2 "adding logging: $log"
627
      contents[$content_index]="log:$font_size"
628
      contents_arg[$content_index]="$log"
629
      content_index=$((content_index+1))
630
      ;;
631
    -u|--default)
632
      shift
633
      contents[0]="preamble"
634
      contents[1]="hrule"
635
      contents[2]="networkif"
636
      contents_arg[2]="$(sys_default_network_interface)"
637
      contents[3]="hrule"
638
      contents[4]="drives"
639
      contents_arg[4]="$(sys_drives)"
640
      contents[5]="hrule"
641
      contents[6]="processors"
642
      contents_arg[6]="$(sys_processors)"
643
      contents[7]="hrule"
644
      contents[8]="processes"
645
      contents[9]="hrule"
646
      contents[10]="portmon"
647
      contents_arg[10]="$(sys_opened_ports)"
648
      contents[11]="hrule"
649
      contents[12]="log:8"
650
      contents_arg[12]="$USERS_LOG"
651
      contents[13]="hrule"
652
      contents[14]="log:6"
653
      contents_arg[14]="$SYSTEM_LOG"
654
      contents[15]="hrule"
655
      contents[16]="rss"
656
      contents_arg[16]="$DEFAULT_RSS_URL"
657
      content_index=17
658
      ;;
659
    -f|--file)
660
      shift
661
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
662
        config[file]="$1"
663
        shift
664
      else
665
        die "-f|--file requires an argument"
666
      fi
667
      ;;
668
    -g|--geometry)
669
      shift
670
      if ! arg_is_end "$1" && ! arg_is_option "$1"; then
671
        if ! arg_is_alignment "$1"; then
672
          die "first argument of -g|--geometry has to be one of $ALIGNMENTS"
673
        fi
674
        config[alignment]="$1"
675
        shift
676
        if ! arg_is_end "$1" && ! arg_is_option "$1"; then
677
          if ! arg_is_numeric "$1"; then
678
            die "second argument of -g|--geometry has to be a number"
679
          fi
680
          config[gap_x]="$1"
681
          shift
682
          if ! arg_is_end "$1" && ! arg_is_option "$1"; then
683
            if ! arg_is_numeric "$1"; then
684
              die "third argument of -g|--geometry has to be a number"
685
            fi
686
            config[gap_y]="$1"
687
            shift
688
          fi
689
        fi
690
      else
691
        die "-g|--geometry requires an argument"
692
      fi
693
      ;;
694
    *)
695
      die "unsupported option ($1)"
696
      shift
697
      ;;
698
  esac
699
done
700
701
log 2 "arguments parsed"
702
703
log 1 "geometry: ${config[alignment]}, ${config[gap_x]}, ${config[gap_y]}"
704
705
log 2 "creating configuration"
706
conky_configuration="$(conky_config)$(conky_text)"
707
708
log 2 "wrinting configuration"
709
sys_write_file ${config[file]} "$conky_configuration"
710
711
log 2 "$0 successfully finished"
712
713