(This is ported from old blog.)

I had been frustrated for probably 15 years or so about the logging output of syslong on my FreeBSD server.

I did not do much to fix it. It is something you can ignore, but it was frustrating nonetheless.

Last night, after seeing

Sep 23 23:08:22 nile imap[95035]: IOERROR: opening /servers/cyrus/imap/user_deny.db: No such file or directory
Sep 23 23:08:22 nile imap[73920]: IOERROR: opening /servers/cyrus/imap/user_deny.db: No such file or directory
Sep 23 23:08:22 nile last message repeated 23 times

in /var/log/debug.log, cluttered by this logging, I had enough. I need to take the control back from all thouse wacky syslogging.

in /usr/ports/sysutils/, there are a few alternatives, and I decided the first one I see, syslog-ng.

The result was a great success. So, if you want to tidy up the /var/log/*, I hope this helps.

Here is what I wanted to do.

  1. I don’t need to change much from what it is now.
  2. I, however want all of email related message to go into /var/log/maillog
  3. That means that I have to filter out the entries based on the application name, not the syslog facility.

I use Cyrus IMAP server and Cyrus does not fall into “mail” syslog facility, therefore, the log entry goes all sorts of places. This has been annoying me for over a decade. (and I’m lazy enough to not do anything about it.)

Using portinstall -PP sysutils/syslog-ngI’m ready to go. I made the following config file, /usr/local/etc/syslog-ng.conf.

It’s pretty close to the sample file, but here is my tweak.

  • I don’t want any of Cyrus logs to go into any of logs except /var/log/maillog.
  • I do want to see lmtp logging in /var/log/maillog.

So, I created a few filters.

filter f_not_cyrus { not program("(imap.*|ctl_cyrusdb|master|lmtp)"); };
filter f_cyrus { program("(imap.*|ctl_cyrusdb|master|lmtp)"); };
filter f_lmtp { program("lmtp"); };

f_not_cyrus is used to block the Cyrus application to send the log to /var/log/message.

log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_kern); filter(f_debug); destination(messages); };
log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_lpr); filter(f_info); destination(messages); };

This reads – for all evetns, add entry to “message” only when the application is not cyurs “filter(f_not_cyrus)”.

f_not_cyrus is shown above. It is dead simple.

The rest is that, I want to log the Cyrus and all mail related logging to /var/log/maillog.

log { source(events); filter(f_cyrus); filter(f_notice); destination(maillog); };
log { source(events); filter(f_lmtp); destination(maillog); };
log { source(events); filter(f_mail); destination(maillog); };

So, this reads, if it’s Cyrus, and notice or above, log. If you are lmtp, log. All “mail” facility logging to into maillog.

Again, this is really simple, yet I don’t know how I can do this with the syslog that comes with FreeBSD.

Here is the entire syslog-ng.conf file.

# options
options { long_hostnames(off); flush_lines(0); };

# sources
source events {
unix-dgram("/var/run/logpriv" perm(0600));

# destinations
destination messages { file("/var/log/messages"); };
destination security { file("/var/log/security"); };
destination authlog { file("/var/log/auth.log"); };
destination maillog { file("/var/log/maillog"); };
destination lpd-errs { file("/var/log/lpd-errs"); };
destination xferlog { file("/var/log/xferlog"); };
destination cron { file("/var/log/cron"); };
destination debuglog { file("/var/log/debug.log"); };
destination consolelog { file("/var/log/console.log"); };
destination all { file("/var/log/all.log"); };
destination newscrit { file("/var/log/news/news.crit"); };
destination newserr { file("/var/log/news/news.err"); };
destination newsnotice { file("/var/log/news/news.notice"); };
destination slip { file("/var/log/slip.log"); };
destination ppp { file("/var/log/ppp.log"); };
destination console { file("/dev/console"); };
destination allusers { usertty("*"); };
destination loghost { udp("loghost" port(514)); };

# log facility filters
filter f_auth { facility(auth); };
filter f_authpriv { facility(authpriv); };
filter f_not_authpriv { not facility(authpriv); };
filter f_console { facility(console); };
filter f_cron { facility(cron); };
filter f_daemon { facility(daemon); };
filter f_ftp { facility(ftp); };
filter f_kern { facility(kern); };
filter f_lpr { facility(lpr); };
filter f_mail { facility(mail); };
filter f_not_mail { not facility(mail); };
filter f_news { facility(news); };
filter f_security { facility(security); };
filter f_user { facility(user); };
filter f_uucp { facility(uucp); };
filter f_local0 { facility(local0); };
filter f_local1 { facility(local1); };
filter f_local2 { facility(local2); };
filter f_local3 { facility(local3); };
filter f_local4 { facility(local4); };
filter f_local5 { facility(local5); };
filter f_local6 { facility(local6); };
filter f_local7 { facility(local7); };

# log level filters
filter f_emerg { level(emerg); };
filter f_alert { level(alert..emerg); };
filter f_crit { level(crit..emerg); };
filter f_err { level(err..emerg); };
filter f_warning { level(warning..emerg); };
filter f_notice { level(notice..emerg); };
filter f_info { level(info..emerg); };
filter f_debug { level(debug..emerg); };
filter f_is_debug { level(debug); };

# program filters
filter f_ppp { program("ppp"); };
filter f_slip { program("startslip"); };

filter f_cyrus { program("(imap.*|ctl_cyrusdb|master|lmtp|cyr_*|tls_prune)"); };
filter f_not_cyrus { not filter(f_cyrus); };
filter f_lmtp { program("lmtp"); };

filter f_afpd { program("afpd"); };
filter f_not_afpd { not filter(f_afpd); };

# *.err;kern.warning;auth.notice;mail.crit /dev/console
log { source(events); filter(f_not_cyrus); filter(f_err); destination(console); };
log { source(events); filter(f_not_cyrus); filter(f_kern); filter(f_warning); destination(console); };
log { source(events); filter(f_not_cyrus); filter(f_auth); filter(f_notice); destination(console); };
log { source(events); filter(f_not_cyrus); filter(f_mail); filter(f_crit); destination(console); };

# *.notice;authpriv.none;kern.debug;lpr.info;news.err /var/log/messages
log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_notice); filter(f_not_authpriv); destination(messages); };
log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_kern); filter(f_debug); destination(messages); };
log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_lpr); filter(f_info); destination(messages); };
log { source(events); filter(f_not_cyrus); filter(f_not_mail); filter(f_news); filter(f_err); destination(messages); };

# security.* /var/log/security
log { source(events); filter(f_security); destination(security); };

# auth.info;authpriv.info /var/log/auth.log
log { source(events); filter(f_auth); filter(f_info); destination(authlog); };
log { source(events); filter(f_authpriv); filter(f_info); destination(authlog); };

# mail.* /var/log/maillog
log { source(events); filter(f_cyrus); filter(f_notice); destination(maillog); };
log { source(events); filter(f_lmtp); destination(maillog); };
log { source(events); filter(f_mail); destination(maillog); };

# lpr.info /var/log/lpd-errs
log { source(events); filter(f_lpr); filter(f_info); destination(lpd-errs); };

# ftp.info /var/log/xferlog
log { source(events); filter(f_ftp); filter(f_info); destination(xferlog); };

# cron.* /var/log/cron
log { source(events); filter(f_cron); destination(cron); };

# *.=debug /var/log/debug.log
# except imap, afpd
log { source(events); filter(f_is_debug); filter(f_not_cyrus); filter(f_not_afpd); destination(debuglog); };

# *.emerg *
log { source(events); filter(f_emerg); destination(allusers); };

# uncomment this to log all writes to /dev/console to /var/log/console.log
# console.info /var/log/console.log
#log { source(events); filter(f_console); filter(f_info); destination(consolelog); };

# uncomment this to enable logging of all log messages to /var/log/all.log
# touch /var/log/all.log and chmod it to mode 600 before it will work
# *.* /var/log/all.log
#log { source(events); destination(all); };

# uncomment this to enable logging to a remote loghost named loghost
# *.* @loghost
#log { source(events); destination(loghost); };

# uncomment these if you're running inn
# news.crit /var/log/news/news.crit
# news.err /var/log/news/news.err
# news.notice /var/log/news/news.notice
#log { source(events); filter(f_news); filter(f_crit); destination(newscrit); };
#log { source(events); filter(f_news); filter(f_err); destination(newserr); };
#log { source(events); filter(f_news); filter(f_notice); destination(newsnotice); };

# !startslip
# *.* /var/log/slip.log
log { source(events); filter(f_slip); destination(slip); };

# !ppp
# *.* /var/log/ppp.log
log { source(events); filter(f_ppp); destination(ppp); };

It worked for a day, and the logs all stop. I scratched my head. After another round of googling, the syslogd process needs a singal, but the default installation of syslog-ng creates a pid file as “/var/run/syslog-ng.pid”, not “/var/run/syslog.pid” which FreeBSD’s log rotation look for. You can change either the log rotation, or syslog-ng’s setting, and I took the syslog-ng’s setting route. I put following lines into /etc/rc.conf

# syslogd is replaced with syslog-ng
syslog_ng_config="-u root"
This really cleaned up the logging. No more annoying warnings from Cyrus, and I can really tell what’s going on with fetchmail/exim/cyrus imap combination by just looking at /var/log/maillog.
I probably want to tweak some more, like some of Cyrus utilities are still logged in /var/log/messages, but overall, my frustration level is now minimul. It was a good couple of hours of investment to finally solve the frustration of 15 years.

Assign specific device name and group to Arduino

I built a PWM fan controller using Arduino. It’s for my file server’s external fans. I wrote a small python script for setting PWM values to it.

I also wanted to control it from a web page, so I wrote a CGI script. The CGI script did not work because the Apache server is running with Apache’s user/group ID which is www-data/www-data while the Arduino’s serial port is root/dialout.

Since the Arduino is a “finished product” and I want a stable name, I can use the Arduino product name and serial number to assign a specific name. For this, you use a udev rule. Here is the one I created for it.

SUBSYSTEM=="tty", ACTION=="add", ATTRS{manufacturer}=="Arduino*", ATTRS{serial}=="64131383331351F09291", GROUP:="www-data", SYMLINK+="serverfan"

and I named it /etc/udev/rules.d/75-arduino.rules.
After that, you unplug and plug back in the Arduino.
Now the CGI script can talk to the Arduino.

How to get to the Arduino serial number

It’s a good thing that Arduino has a serial number so that you can spot a specific one. Here is how you get the serial number.

$ sudo udevadm info  --attribute-walk  --name=/dev/ttyACM0 | grep serial

So I copy & paste the ATTRS{serial}==”64131383331351F09291″ part in the udev rule.

Dymo LabelManager PnP on Linux CUPS

I’m into organization these days, and one thing I really wanted was to print a nice labels on folders and boxes. So, I bought myself a Dymo LabelManager PnP.
I printed a couple of labels on Mac, and out of curiosity, I wanted to use it on Mint box. (I don’t know I should call Mint box Ubuntu box or Linux box. I am so not religious purist.)

Here is the step you need to use the Dymo on it.

Step 1: Download Dymo Linux SDK.

You’d get something like “dymo-cups-drivers-1.4.0.tar.gz“.

Step 2: Install libcups2-dev libcupsimage2-dev

sudo apt-get install libcups2-dev libcupsimage2-dev gcc g++

Step 3: Install the SDK

mkdir dymo
cd dymo
tar xzf dymo-cups-drivers-1.4.0.tar.gz
cd ./dymo-cups-drivers-
sudo make install

Now the driver is installed.

Step 4: Set up the CUPS
Now, go to the CUPS admin page. Don’t forget to connect the Dymo to your machine.

Here are the screen shots of how I set it up.


Step 5: Install gLabels

gLabels is a GNOME application for printing labels. Thanks for whoever developed this. It is well designed and made. I tried LibreOffice writer and was totally lost at beginning. It was just a matter of “aptitude search label” and gLabels showed up.

Step 6: Set up the template

I had to try a few times to get the template working. Ones showing here is not 100%, but it is working OK.

010-tempate 1011-template 2012-template 3013-template 4

After that, you hit a couple of “Continue” buttons. If you see the template carefully, the layout is not horizontal. I tried the horizontal layout and could not make it work. You’ll see the “bad template” result in later.

Step 7: Create a label.

020-new label or card021-choose normal

Now, in gLabels, you create a label. New document and pick the template you created. So, this results in somewhat awkward label design screen.

040-design screen

This is the only way I can make it work for now. I printed a label. This is for a AC adapter for my rechargeable LED flash light. There are so many adapters that only way to keep track of them is to label them all.


Ones on the left is the failed attempts. One on right is the result of this post. Apparently, the margin is not right, and the end is too close to the cutting blade. The adjustments are probably increase the margin all around and for the label’s template, “waste” needs to be set up some. But, at least it’s printed and the letters are right.
I think this is an OK start.


Replacing Panasonic Toughbook CF-W4 keyboard

Photo on 2-23-13 at 10.03 PM

Disclaimer: I will be not responsible for any damage caused by following the instruction in this blog entry. You are your own.

As World Computer Exchange’s work, I had an opportunity to repair Toughbook W4’s keyboard. I eBayed a replacement.

This is how the keyboard was bad. “R” key top was coming off, and “F” was sticky. I suspect the laptop did a face plant, damaing “R” and “F” key.

As any repair, remove the laptop from power source. Unplug power adapter and battery. Then, let the fun begin. Actually, you have to remove the battery in order to remove the keyboard.

001-removalHere is the things you want to remove. A clip and 4 screws are holding down half the keyboard.

As you can see, the clip is in the battery bay. 4 screws are Phillips #00. Be sure to use a good one, since you really don’t want to damage. Now, going to the front. These two front screws in blue — NO NEED TO REMOVE, but you could. It might make shifting the keyboard at the end a little bit easier, but not by much. (Well, I removed them since I did not know better.)


At this point, the keyboard is held down by double-sided tape in 3 locations and two craws on the right side of keyboard.

So, you need to be brave to ply off the double sided tapes. It does not require a lot of force but it is rather held down pretty well. Please be carefully forceful to ply off the keyboard from the top cover.toughbook-w4-ply-off You can use a small flat head screw driver sticking into the top right side. Behind it, there is a thin strip of double side tape, about 2-3 mm x 100 mm.

There are also small piece of double side tapes under “P” key and “down arrow” key.

After plying off the upper side double site tape, you kind of need to shift the whole key toward “ESC” key, because there are two clips holding down the keyboard at the right side of toughbook-w4-clipskeyboard. After removing the keyboard, you can clearly see these two as in the picture here. So you need to slide the whole keyboard just a little to the left. It’s very difficult to do when the tapes are holding down. So, all 3 locations of tape needs to kind of come off. However, if you have no intention of saving the keyboard, you’d rather pull the keyboard in the very middle to save the clips here.

Now, the keyboard should come off. Very careful. The ribbon cable is hooked up, and you want to not break the connector.

toughbook-w4-keyboard-off toughbook-w4-connectortoughbook-w4-disengage

The keyboard connector is behind the thin metal thing that has 2 joints. You can gently move it up. When you peek in, you can see the center notch in the keyboard connector. The whole upper side slides out about 2mm or so. With a small flat head screwdriver, using the notch, you can push it out. Once it moves out a little, you can use the flat head to move them. Once the connector becomes disengaged like the picture on the above right, the cable should come out with any resistance. You are now half way home.


Obviously, I don’t have the same double side tape to replace, so I used a double-sided scrapbooking tape. I assume it is less acidic and pretty sticky, and thin. I put it on a scrap plexiglass so that I can cut precisely to the original shape. If you have a real glass, it would make things even easier. You cut it the shape with a knife. I decided to put the 3 pieces to the laptop side, not keyboard side.

Only thing left is to reverse the steps. You slide in the ribbon cable to the connector, and close the connector. You don’t need a lot of force but firm. Pushing it in the finger is just fine. No need for the screw driver.

Put in the keyboard from “ESC” side in the air, slide just a little so that the two clips on the right side catches the keyboard. Also, the bottom sides have a couple of tabs that catches the case. Take time and be patient. The left top side is all secured by the clip and 4 screws. So, use the flexibility of keyboard and push it toward right bottom, while making sure the space bar side’s tab goes in.

Once everything is in place, you press down the keyboard so that the double side tapes sticks, and then the 4 screws and the clip.

Now, you are done! Good luck.

It took me less than an hour. I first thought the right side has something mechanical thing holding down, but it turns out they are all tapes.  When you know the damaged one is going to be thrown away, you can be a little brave.

— Tai