I often use dd to copy large files or make images from hard drives. It's annoying to watch something without any progress indicator, so I use the little known kill switch on dd.

From the man page:

Sending a USR1 signal to a running ‘dd’ process makes it print I/O statistics to standard error and then resume copying.

$ dd if=/dev/zero of=/dev/null& pid=$!
$ kill -USR1 $pid; sleep 1; kill $pid

I'll often make a for loop and keep killing dd to get the stats, I decided to make a little script to do the whole thing in one, making it even lazier...

<br />
<p># run dd and kill with USR1 every 5 seconds.</p>
<p>term_dd() {<br />
  echo "killing dd"<br />
  kill $dd<br />
  exit 1<br />
<p>trap term_dd SIGINT SIGTERM</p>
<p>if [ ${#args} -lt 2 ]; then<br />
	echo "usage: $0 infile outfile [other options]"<br />
	exit<br />
<p>tmp=$(mktemp /tmp/ddk.XXXXXXXX)</p>
<p>echo dd if=$1 of=$2 ${args[@]:2}<br />
dd if=$1 of=$2 ${args[@]:2} >$tmp 2>&1 &<br />
dd=$!<br />
echo "dd if=$1 of=$2 ${args[@]:2} $dd"<br />
sleep 1<br />
while /bin/true<br />
do<br />
    if [ -d /proc/$dd ];<br />
    then<br />
      kill -USR1 $dd<br />
    else<br />
      echo "no dd $dd"<br />
      break<br />
    fi<br />
    clear<br />
    echo "dd if=$1 of=$2 ${args[@]:2}"<br />
    tail -3 $tmp<br />
    sleep 1<br />
done<br />
rm $tmp<br />
exit<br />

The only caveat here is that the sleep right before starting the while loop appears to be necessary, without it, the whole thing won't work sometimes, I can't quite figure out why...The $! doesn't seem to be populated quick enough and the script dies at that point since the first kill files to find the /proc/$! directory.

I wanted to monitor the ambient temperature in my computer room and decided to try using the built in sensors on my servers. ipmitool showed an ambient temperature, so I did some sed to get just the temperature.

[thomas@hotstuff: ~] $ sudo ipmitool sdr type "Temperature" |grep Ambient
Ambient Temp | 08h | ok | 7.1 | 22 degrees C

Some of my machines have multiple Ambient Temperature sensors, I did some looking on the google and the ones marked 7.1 appear to be the one to look at, the rest are power supply temp sensors and show much higher temps.

To have just the ambient temp show I changed the above to:

[thomas@hotstuff: ~] $ sudo ipmitool sdr type "Temperature" |grep Ambient |grep 7.1 |sed -e 's/.*7.1 | \([0-9]\+\).*/\1/'

To have this monitored in zabbix, I just put it into zabbix_agentd.conf

UserParameter=ambient.temp,sudo ipmitool sdr type "Temperature" |grep Ambient |grep 7.1 |sed -e 's/.*7.1 | \([0-9]\+\).*/\1/'

After adding ambient.temp to a host and waiting a while I have the following graph. I also set a trigger if ambient.temp > 30.

A talk I gave at PICC 12 on mock

Slides available here

Update: I noticed that the syntax for vacationStart and vacationEnd do not permit integer comparisons. So I changed them from to This change allows you to make a gnarwl search string that uses the current time to check if a vacation is active.

I'm in the process of setting up gnarwl with our 389 (fedora directory server) and needed to import the vacation attributes and objectclass into 389. I only added the attributes I needed for vacation from the included ISP schema file.

Here is the ldif for putting into /etc/dirsrv/[instance]/schema:

dn: cn=schema
attributeTypes: (
NAME 'vacationActive'
DESC 'A flag, for marking the user as being away'
EQUALITY booleanMatch
attributeTypes: (
NAME 'vacationInfo'
DESC 'Absentee note to leave behind, while on vacation'
EQUALITY octetStringMatch
attributeTypes: (
NAME 'vacationStart'
DESC 'Beginning of vacation'
attributeTypes: (
NAME 'vacationEnd'
DESC 'End of vacation'
attributeTypes: (
NAME 'maildropPlace'
DESC 'Location of the mailbox'
EQUALITY caseExactIA5Match
SUBSTR caseExactIA5SubstringsMatch
attributeTypes: (
NAME 'mailForward'
DESC 'Address to forward email to'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
#attributeTypes: (
# NAME 'mailHost'
# DESC 'Fully qualified hostname of a mailserver'
# EQUALITY caseIgnoreIA5Match
# SUBSTR caseIgnoreIA5SubstringsMatch
# SYNTAX{256}
attributeTypes: (
NAME 'vacationForward'
DESC 'Where to forward mails to, while on vacation'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
# Objects start here
objectClasses: (
NAME 'Vacation'
SUP top
DESC 'Users vacation status information'
MUST ( vacationActive )
MAY ( vacationInfo $ vacationStart $ vacationEnd $ vacationForward )
objectClasses: (
NAME 'mailAccount'
SUP top
DESC 'Emailaccount, associated with a user'
MAY ( mailForward $ mailHost $ cn $ maildropPlace )
# end

389 complains if there are empty lines anywhere in that file and it likes spaces at the beginning of the lines (not tabs). I also took out mailHost, it's defined elsewhere.

I called mine 99vacation.ldif (download it)

This is just a case of RTFM but I thought I'd share...
I'm setting up ingo with dovecot sieve. I first verified that dovecot's sieve server is working properly by using the thunderbird sieve plugin (which is a sort of pointless plugin, you end up having to write in sieve language anyway, i'd expect a nicer gui front end like ingo has).

After making my backends.local.php in ingo's config directory, I did a tcpdump to verify that the web server was talking to the sieve server. Sadly it wasn't. (Sidebar here - the port number changed from 2000 to 4190 and my services file didn't have the new port so I was opening the wrong port on the firewall for about half an hour).

The problem was that the default backends.php file has the imap backend on by default. To add insult to injury, it's in all *caps* too.

/* IMAP Example */
$backends['imap'] = array(
// ENABLED by default
$disabled => false,

After changing that false to true, horde started talking to sieve. I think this breaks the notion of making local configs in backends.local.php and leaving backends.php alone.

While playing around with getting host entries to work with ldap, I found that my previous code for using gethostbyname was not running clean on puias6. Here is an updated version

<br />
#include <stdio.h><br />
#include <netdb.h><br />
#include <stdlib.h><br />
#include <sys/socket.h><br />
#include <netinet/in.h><br />
#include <arpa/inet.h></p>
<p>int main(int argc, char **argv) {<br />
	int i;<br />
	struct hostent *hp;<br />
	struct in_addr **addr_list;</p>
<p>	if (argc < 2) {<br />
		printf("Usage: %s hostname\n", argv[0]);<br />
		exit(1);<br />
<p>	hp = gethostbyname(argv[1]);<br />
	if (hp == NULL) {<br />
		printf("gethostbyname(%s) failed\n",argv[1]);<br />
	} else {<br />
		printf("%s has address ", hp->h_name, argv[1],hp->h_addrtype);<br />
		addr_list = (struct in_addr **)hp->h_addr_list;</p>
<p>		for(i = 0; addr_list[i] != NULL; i++) {<br />
			printf("%s ",inet_ntoa(*addr_list[i]));<br />
			}<br />
	printf("\n");<br />
  }<br />
}<br />

compile this with gcc -o gethostbyname gethostbyname.c

We store our host information in ldap. Previously using ldap for host lookups was done by adding the appropriate entries to /etc/ldap.conf and changing nsswitch.conf.

With 6, nss_ldap has been replaced by nslcd, so I needed to change our setup a little.
I put the following into nslcd.conf

uid nslcd
gid ldap
uri ldap://ldap2.example.com
uri ldap://ldap.example.com
base dc=example,dc=com
# this is only host information, no need to use ssl
#ssl start_tls
#tls_cacertfile /etc/pki/tls/certs/ca-bundle.crt
base hosts ou=hosts,dc=example,dc=com
scope hosts sub

We use scope hosts sub because we take advantage of the hierarchy of ldap and organise our hosts into different subou's within the hosts ou.

Next update nsswitch.conf to use ldap

passwd: files sss
shadow: files sss
group: files sss

hosts: files ldap dns [NOTFOUND=return]

Next restart nslcd to see the change.

<br />
[<a href="mailto:root@host">root@host</a> ~]# getent hosts<br />       localhost localhost.localdomain localhost4 localhost4.localdomain4<br />       localhost localhost.localdomain localhost6 localhost6.localdomain6<br />
[<a href="mailto:root@host">root@host</a> ~]# service nslcd start<br />
Starting nslcd:                                            [  OK  ]<br />
[<a href="mailto:root@host">root@host</a> ~]# getent hosts<br />       localhost localhost.localdomain localhost4 localhost4.localdomain4<br />       localhost localhost.localdomain localhost6 localhost6.localdomain6<br />   fs.example.com fs<br />   ldap ldap.example.com<br />    ldap2 ldap2.example.com<br />

The ldap entry (ldif) for one of these hosts would look like this:

# fs.example.com, hardware, hosts, example.com
dn: cn=fs.example.com,ou=hardware,ou=hosts,dc=example,dc=com
objectClass: top
objectClass: iphost
cn: fs.example.com
cn: fs

I configure nsswitch.conf with augeas, the augtool lines to do this and the corresponding puppet config are below.

augtool> set /files/etc/nsswitch.conf/*[self::database = 'hosts']/service[1] files
augtool> set /files/etc/nsswitch.conf/*[self::database = 'hosts']/service[2] ldap
augtool> set /files/etc/nsswitch.conf/*[self::database = 'hosts']/service[3] dns
augtool> set /files/etc/nsswitch.conf/*[self::database = 'hosts']/reaction/status NOTFOUND
augtool> set /files/etc/nsswitch.conf/*[self::database = 'hosts']/reaction/status/action return


augeas {"nsswitch ldap first":
context => "/files/etc/nsswitch.conf",
changes => [
"set *[self::database = 'hosts']/service[1] files",
"set *[self::database = 'hosts']/service[2] ldap",
"set *[self::database = 'hosts']/service[3] dns",
"set *[self::database = 'hosts']/reaction/status NOTFOUND",
"set *[self::database = 'hosts']/reaction/status/action return"
notify => Service["nslcd"]

A friend of mine was talking about his design for a shell that would allow you to programatically reuse arguments. I started looking and found that bash can do this but not programatically (at least as far as I know). The syntax was slighty confusing but here is the summary, it blew my mind when I started using it (but I'll probably forget it again soon enough, like all the awesome things you can do in vi if you can remember...)

Here goes, lets copy a file from a deeply nested path to our location by first tab-completing the filename with ls

[thomas@host ~]$ ls /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd

Now type cp on the new line and then Meta-Control-y
(That is, hold down Meta, Control and then type y ((hopefully you know where your Meta key is, on my keyboard it's the left-alt)))

[thomas@host ~]$ cp /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd .

Cool, now what about a line with many arguments:

[thomas@host ~]$ ls /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd /usr/share/texmf/tex/plain/plgraph/picture.tex /usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty
/usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd /usr/share/texmf/tex/plain/plgraph/picture.tex

To get the last argument, type cp then Meta-.

[thomas@host ~]$ cp /usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty .

Now the one that was somwhat tricky to get would be how to change the argument number

[thomas@host ~]$ ls /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd /usr/share/texmf/tex/plain/plgraph/picture.tex /usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty
/usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd /usr/share/texmf/tex/plain/plgraph/picture.tex

To get the second argument: Meta-2 then (without letting go of Meta) Meta-Control-y

[thomas@host ~]$ ls /usr/share/texmf/tex/latex/mathdesign/mdput/ts1mdput.fd /usr/share/texmf/tex/plain/plgraph/picture.tex /usr/share/texmf/tex/latex/gnuplottex/gnuplottex.sty
(arg: 2) ls
[thomas@host ~]$ ls /usr/share/texmf/tex/plain/plgraph/picture.tex

After upgrading to horde 4.0.8 and imp 5.0.9 a few users had issues reading email. There were some messages missing, or for some users no messages at all.

In dimp/Dynamic the mailbox would fail to load and the message "Error communicating with Server" would be displayed, this was triggered by ajax_error (that's about as far as we got debugging).

In imp the mailbox would show thousands of messages but they would mostly say "Invalid Address" and "Unknown Date" with "No Subject".

Looking around we finally found this bug that shows it's due to bugginess in the UW-Imap server (time for dovecot).

The fix was the following line in imp/config/backends.local.php:

'capability_ignore' => array('ESEARCH')

After that we restarted apache and all was well.

I published a Thing on @thingiverse! https://t.co/IYpRyEb7Hz #thingalert Tue Jul 23 19:27:57 +0000 2019

Nokogiri install on MacOSX https://t.co/v3An0miW9L Fri Jul 12 15:06:49 +0000 2019

HTML email with plain mailer plugin on Jenkins https://t.co/Z6FSDMDjy8 Thu Jul 11 21:07:25 +0000 2019

git sparse checkout within Jenkinsfile https://t.co/tcL7V8mzFK Thu Jul 11 20:40:53 +0000 2019

#lfnw node red looks like fun Sun Apr 28 21:02:11 +0000 2019