tech log on gentoo, linux, and random stuff

Archive for the ‘/usr/local/bin’ Category

pdf to gif conversion and optimization

leave a comment »

There have been several occasions that I need to generate some gif animations from a bunch of pdf plots (generated by gnuplot’s tikz terminal), so the following procedure merits documenting. Note that convert is part of ImageMagick, and gifsicle is a gif optimization tool.

  1. Converting pdfs to png:
    for f in *pdf; do convert -verbose -density 150x150 $f `basename $f .pdf`.png; done
  2. combining png to gif (and optimize):
    convert -verbose +dither -layers Optimize -colors 32 -delay 5 -loop 0 -dispose previous *png output.gif
    • if there are too many *png files, it’s probably better to divide and conquerer: assuming png files are frame_000 upto frame_139, then first:
      for i in `seq -f "%02g" 0 13`; do convert -verbose +dither -layer Optimize -delay 5 -loop 0 -dispose previous frame_${f}?.png frame_${f}.gif; done
      convert -verbose frame_??.gif all.gif
    • notice that I’ve dropped the -color 32, b/c in my case it actually increases the resulting file size.
  3. further optimization (YMMV) using gifsicle:
    gifsicle -O3 output.gif -o output_optimized.gif



p.s., a related operation is to combine say every 10th of the pdfs for closeup inspection:

pdfjam frame_??0.pdf --papersize '{12in,9in}' --outfile frames.pdf

pdfjam is a frontend to the latex package "pdfpages". The --papersize I used is the same as the one I had used in gnuplot when generating these plots (set term tikz size 12in,9in ...).

Written by zsh

September 14, 2011 at 12:06 am

openvpn over ad-hoc wireless connection

leave a comment »

I have a spare zd1211rw usb WLAN dongle that I’d like to use to turn my desktop into some kind of AP, so that I can freely move around with my laptop. Sadly, the zd1211rw driver doesn’t support master mode, nor wpa over ad-hoc. My first thought is to encrypt the ad-hoc connection somehow through an ssh tunnel, but after fiddling around with dante (for `transparent socks proxy’) + ssh -D (socks5 proxy via ssh) combination for a while, I didn’t find the setup to be as transparent as I though it could be–e.g., socksify firefox doesn’t work quite well. It seems finally it’s time to dip my foot into the VPN pond.

The setup is quite straightforward though a little bit tedius. Following is exported from my installation journal in org-mode

openvpn over ad-hoc wireless

1 setup openvpn on desktop running Arch linux (as vpn server)

1.1 pacman -Sy openvpn


  1. example conf in /etc/openvpn/examples
  2. easy-rsa scripts in /usr/share/openvpn/easy-rsa

now follow openvpn howto

1.2 generate certificates & keys

  1. cp -r {/usr/share,/etc}/openvpn/easy-rsa/
  2. edit vars file
  3. (cd /etc/openvpn; . ./vars; ./clean-all; ./build-ca)
  4. ./build-key-server server
    i also used a challenging password
  5. ./build-key alfred
    where `alfred’ is the name of my laptop. i also used a
    different challenging password
  6. ./build-dh (Diffie-Hellman parameters)
  7. Summary of key files:

    Filename Needed By Purpose Secret
    ca.crt server + all clients Root CA certificate NO
    ca.key key signing machine only Root CA key YES
    dh{n}.pem server only Diffie Hellman parameters NO
    server.crt server only Server Certificate NO
    server.key server only Server Key YES
    alfred.crt “alfred” only “alfred” Certificate NO
    alfred.key “alfred” only “alfred” Key YES
  8. now cp key/{ca.crt,alfred*} /mnt/usbstick, to be transfered
    to alfred

1.3 configuring server

  1. cd /etc/openvpn
  2. cp examples/server.conf ./
  3. linking appropriate certificate files generated previously:
    for f in dh1024.pem ca.crt server.crt server.key; do ln -s easy-rsa/keys/$f ./$f; done
  4. edit server.conf file.

    server.conf with most comments stripped. Note that a verbatim
    DNS server address is used

    # address to listen to
    port 1194
    ;proto tcp
    proto udp
    # we are using routing instead of bridging. see the online howto
    ;dev tap
    dev tun
    # certificates and keys
    ca ca.crt
    cert server.crt
    key server.key  # This file should be kept secret
    dh dh1024.pem
    # flag this as a server
    ifconfig-pool-persist ipp.txt
    # not using bridging
    ;push "route"
    ;push "route"
    push "redirect-gateway local def1"
    push "dhcp-option DNS"
    ;push "dhcp-option WINS"
    # allow duplicate certificates
    keepalive 10 120
    # use tls for extra security
    ;tls-auth ta.key 0 # This file is secret
    ;cipher BF-CBC        # Blowfish (default)
    ;cipher AES-128-CBC   # AES
    ;cipher DES-EDE3-CBC  # Triple-DES
    max-clients 2
    # run unprivileged
    user nobody
    group nobody
    status openvpn-status.log
    ;log         openvpn.log
    ;log-append  openvpn.log
    # verbosity
    verb 3
    ;mute 20

1.4 running server

manually, cd /etc/openvpn; openvpn --config server.conf.

A script to run the server and set up appropriate NAT routing:

$OPENVPN --daemon --config $OVDIR/server.conf --cd $OVDIR

2 setup openvpn on laptop running Gentoo (as vpn client)

2.1 emerge openvpn

Note: enable the `examples’ USE flag to get vendor-provided
skeleton conf files (in /usr/share/doc/openvpn-*/examples/)

2.2 configuring client

cp the skeleton client.conf to /etc/openvpn/home.conf (home
being the profile name), mod it.


# flag this as client

;dev tap
dev tun

;proto tcp
proto udp

# vpn server's ip address
remote 1194
;remote my-server-2 1194

# Keep trying indefinitely to resolve the
# host name of the OpenVPN server.  Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite

# Most clients don't need to bind to
# a specific local port number.

# Downgrade privileges after initialization (non-Windows only)
;user nobody
;group nobody

# Try to preserve some state across restarts.

# Wireless networks often produce a lot
# of duplicate packets.  Set this flag
# to silence duplicate packet warnings.

# certificates/keys
ca homekeys/ca.crt
cert homekeys/alfred.crt
key homekeys/alfred.key 

# Verify server certificate by checking
# that the certicate has the nsCertType
# field set to "server".  This is an
# important precaution to protect against
# a potential attack discussed here:
#  http://openvpn.net/howto.html#mitm
# To use this feature, you will need to generate
# your server certificates with the nsCertType
# field set to "server".  The build-key-server
# script in the easy-rsa folder will do this.
ns-cert-type server

# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1

# no compression

# Set log file verbosity.
verb 3

# Silence repeating messages
;mute 20

2.3 running client

gentoo’s openvpn package has an init script. Just ln -s /etc/init.d/openvpn{,.home}, (home being your profile name) and
rc-service start openvpn.home

3 networking

In the server-side runvpn script, NAT routing has already been set
up. Note that ip-forwarding must be enabled (manually by echo "1" > /proc/sys/net/ip_forward or through sysctl: sysctl -w net/ipv4/ip_forward=1)

At the client side, after bringing up the vpn client, I still have
to route add default gw where is the p2p end
of tun0. It’s possible that this can be pushed by the server but I’m
tired of reading the openvpn manual, so this is done in a script
runvpn on my laptop (not to be confused with the script on the
server side bearing the same name). The script is setup to also ssh
to the server on its WLAN address and start up the vpn server.

ssh home sudo bin/runvpn
sudo rc-service openvpn.home restart
sleep 10
TUN=`sudo /sbin/ifconfig tun0 | sed -n 's/.*P-t-P:\([^ ]\+\).*/\1/p'`
sudo route add default gw $TUN

4 real-world operation

  1. plug in the USB WLAN card on the desktop. With the following
    /etc/udev/rules.d/10-zd1211.rules and ~/bin/adhoc, the card
    is automatically set in ad-hoc mode and assigned

  2. on the laptop, run adhoc && sleep 5 && runvpn. the sleep 5 is
    to allow some time for the WLAN to be fully associated to an
    ad-hoc cell

    10-zd1211.rules (on server)

    ACTION=="add", ATTR{manufacturer}=="ZyDAS", ATTR{product}=="USB2.0 WLAN", SYSFS{idVendor}=="0ace", SYSFS{idProduct}=="1215", SYMLINK+="net/wireless-usb-zd1211", RUN+="/hoard/home/bin/zd-inserted"

    ~/bin/adhoc (on server)

    # ref: http://forums.gentoo.org/viewtopic-t-274790-highlight-adhoc+wireless.html
    /sbin/rmmod zd1211rw && /sbin/modprobe zd1211rw
    # need to set abs. path for script to work when called by e.g. udev
    IFCONFIG=/sbin/ifconfig && \
    IWCONFIG=/usr/sbin/iwconfig && \
    $IFCONFIG wlan0 down && \
    $IWCONFIG wlan0 mode ad-hoc && \
    $IWCONFIG wlan0 essid soc channel 1 && \
    $IFCONFIG wlan0 && \
    $IWCONFIG wlan0 txpower 14dbm

    ~/bin/adhoc (on client)

    IFCONFIG="sudo /sbin/ifconfig"
    IWCONFIG="sudo /sbin/iwconfig"
    $IFCONFIG wlan0 down && \
    $IWCONFIG wlan0 mode ad-hoc && \
    $IFCONFIG wlan0 && \
    $IWCONFIG wlan0 essid soc channel 1 txpower 10dbm

HTML generated by org-mode 6.27a in emacs 23

Written by zsh

June 28, 2009 at 3:40 am

Posted in /etc, /usr/local/bin

Tagged with , , ,

awesome 3.2 battery monitoring widget

leave a comment »

Lua code to monitor battery status through thinkpad’s smapi. It generates, e.g., [-] 02:15 (86%) if the battery is 86% full, discharging and has an estimated remaining time of 2 hours 15 mins, [+] 00:30 (50%) if it’s expected to be fully charged in 30 mins, etc. Also, use 100:green:50:yellow:20:red bg color setup. Use with e.g. a textbox widget.

function read_file (path, ...)
   -- read a text file and return its content
   -- ... can be, e.g., "*n" for a number or "*a" for all, etc.
   local f = io.open(path)
   local result = f:read(...)
   return result
function format_time(num)
   local h,m = math.floor(num/60),num%60
   return string.format("%02d:%02d", h,m)

function battery_status (bat)
   -- bat should be, e.g., BAT0
   local path = "/sys/devices/platform/smapi/"

   if read_file(path .. bat .. "/installed") == "0" then
      -- battery not installed
      return "[N/A]"

   local percent = tonumber(read_file(path .. bat .. "/remaining_percent"))
   local state = read_file(path .. bat .. "/state")
   local msg
   if state == "charging" then
      msg = "[+] " .. format_time(
	 read_file(path .. bat .. "/remaining_charging_time"))
   elseif state == "discharging" then
      msg = "[-] " .. format_time(
	 read_file(path .. bat .. "/remaining_running_time"))
   elseif state == "idle" then
      msg = "[ ]"
      msg = "*" .. state .. "* "

   local pre,post
   if percent > 50 then
      pre,post = '<span font="mono" bgcolor="green" color="black">', '</span>'
   elseif percent > 20 then
      pre,post = '<span font="mono" bgcolor="yellow" color="black">','</span>'
      pre,post = '<span font="mono" bgcolor="red" color="yellow">','</span>'
   return pre .. msg .. " (" .. percent .. "%)" .. post
-- print(battery_status("BAT0"))

Written by zsh

May 5, 2009 at 5:47 pm

Posted in /etc, /usr/local/bin

Tagged with , , ,


leave a comment »

After my X61 tablet arrived, I needed a keyboard daemon that can take care of hotkey events both under console and in X (I’d like to have control of brightness and volume level, etc., in both). After some search, I settled with actkbd, which to me is a good balance of speed (pure C), functionality and complexity (take a look at, say, gizmo daemon). It monitors evdev keyboard (e.g., /dev/input/event1. so need kernel evdev support), and reponds according to a config file.

  1. Simple config example
    A typical snippet in actkbd’s configuration file looks like this:
    ## mute key
    # hard mute if pressed long, otherwise toggle
    #code   event   attrib          ext command
    113	:rep	:grab,noexec	:
    113	:rel	:grabbed,ungrab	:/home/bin/mute
    113	:rel	:ungrabbed	:/home/bin/toggle
    # hard unmute (all muters)if shift+
    42+113:key::/home/bin/unmute Master Headphone Speaker

    With the helper scripts mute and toggle, this snippet either mutes or toggles the mute status of my soundcard depending on whether the Mute key (113) is just pressed or hold for a while.

    Each config line has four fields,

    • code: keycode as shown in showkey. multiple keys concatenated by ‘+’
    • event: one of key, rep (repeat), and rel (release)
    • attrib: (un)grab to block/release device from/to other programs, (un)grabbed to ensure action taking place only when (un)grabbed. This is the major featureset of actkbd. For a complete list, see the official README
    • ext command: external command to call. It could be better if actkbd can export relevant info as some sort of variable that can be passed to external commands (so that e.g. a general purpose hook program can handle all events).
  2. Tablet screen rotation
    The X61 tablet has some buttons alongside the tablet panel. When in tablet mode, these are the only keys accessible as the whole keyboard is covered under the tablet, so we want to use these keys wisely. With an external helper script rotate, the following snippet will
    • reset screen to normal orientation if “rotate” button hold for long
    • rotate screen 90 degrees clock-wise if “rotate” button is merely pressed
    • rotate screen to a relative orientation (left, right, or invert) if the “rotate” button is hold while the orientation arrow keys are pressed
    ## grab as `clean' bit, detectable
    # 191: "rotate" button
    # rotate clockwise if only hold short
    191	:key	:grab,noexec	:
    191	:rel	:grabbed,ungrab	:/home/bin/rotate
    ## 192 as `hold' bit
    # reset orientation if hold long
    191+192	:rel	:grabbed,ungrab,unset(192)	:/home/bin/rotate monitor
    191+192	:rel	:ungrabbed,unset(192),noexec	:
    ## u/d/l/r/enter: 103/108/105/106/28
    # u/d: invert; l/r: rotate; enter: pin down
    # relative rotation
    191+103		:rel	:ungrab	:/home/bin/rotate i
    191+108		:rel	:ungrab	:/home/bin/rotate i
    191+105		:rel	:ungrab	:/home/bin/rotate l
    191+106		:rel	:ungrab	:/home/bin/rotate r
    191+28		:rel	:ungrab	:/home/bin/rotate c
    191+192+103	:rel	:ungrab	:/home/bin/rotate i
    191+192+108	:rel	:ungrab	:/home/bin/rotate i
    191+192+105	:rel	:ungrab	:/home/bin/rotate l
    191+192+106	:rel	:ungrab	:/home/bin/rotate r
    191+192+28	:rel	:ungrab	:/home/bin/rotate c

    Here, the trick is to use ‘grab’ to indicate whether the current 191 key event is being processed or not, and use the ficticious 192 key to indicate whether it’s a long hold or a short one.

  3. LCD brightness control
    Similar trick can be used to control screen brightness. The master button to use now is “application” button right next to the “rotate” button.
    • short and long hold: reserverd for future use (:D)
    • app + up/down: turn brightness up/down by 1.
      app + left/right: turn brightness to min/max
      app + enter: turn brightness midway (7)
    ## similar `grab' and `hold' trick, but for 152
    152	:key	:grab,noexec			:
    152	:rel	:grabbed,ungrab			:echo "short press"
    152	:rep	:grabbed,set(153),noexec	:
    152+153	:rel	:grabbed,ungrab,unset(153)	:echo "long press"
    152+153	:rel	:ungrabbed,unset(153),noexec	:
    ## adjust brightness
    152+103		:rel	:ungrab	:echo up > /proc/acpi/ibm/brightness
    152+108		:rel	:ungrab	:echo down > /proc/acpi/ibm/brightness
    152+105		:rel	:ungrab	:echo level 0 > /proc/acpi/ibm/brightness
    152+106		:rel	:ungrab	:echo level 15 > /proc/acpi/ibm/brightness
    152+28		:rel	:ungrab	:echo level 7 > /proc/acpi/ibm/brightness
    152+153+103	:rel	:ungrab	:echo up > /proc/acpi/ibm/brightness
    152+153+108	:rel	:ungrab	:echo down > /proc/acpi/ibm/brightness
    152+153+105	:rel	:ungrab	:echo level 0 > /proc/acpi/ibm/brightness
    152+153+106	:rel	:ungrab	:echo level 15 > /proc/acpi/ibm/brightness
    152+153+28	:rel	:ungrab	:echo level 7 > /proc/acpi/ibm/brightness
  4. Microsoft Natural Ergonomic Keyboard 4000 (NE4k)
    The problem with NE4k, which I use on my desktop, is that kernel exports it as two devices, one for the normal keys (a,o,e,u,… yes I use dvorak), say /dev/input/event3, and one for all the multimedia/net/hot keys, say /dev/input/event4. Since each process of actkbd can only monitor a single device, there will be no way to capture something like shift+mute, which involves both devices. Even if you run two actkbd daemons monitoring both, there’s no easy way for them to crosstalk. A possible workaround is to somehow combine the two devices into one, or even one further step back, to “redirect” all events from one device to the other. Maybe I was using the wrong keywords, but a google search doesn’t reveal any such things, so here comes the stitch works: a simple “event replicator” which basically is a stripped down version of actkbd. Just gcc evpipe.c -o evpipe, and use ./evpipe /dev/input/event{4,3} to redirect event4 to event3. NB: although I “grabbed” the incoming device, it’d be a good idea to redirect the hotkey device to the standard keyboard instead of the other way around, so that even if something goes wrong you’ll still have a usable device. (I made the mistake of not “grabbing” the incoming device AND redirected the normal keyboard to the hotkeys, making each keypress of “a” generating “aa” and ended up having to kill the process from my laptop).

    * evpipe.c: *
    * basically c-k c-y of linux.c in actkbd. *
    * NO ERROR HANDLING!! (almost) *

    #include #include

    static FILE *from;
    static FILE *to;
    struct input_event ev;
    int grabbed=0;

    int main(int argc, char* argv[]){
    /* Allow SIGTERM to cause graceful termination */
    void close_and_quit(int signum) {
    if (to)
    if (from)
    if (grabbed)

    int pipe(char* ffrom, char* fto){
    signal(SIGTERM, close_and_quit);
    signal(SIGINT, close_and_quit);
    from = fopen(ffrom, “a+”);
    if (from == NULL)
    return 1;
    to = fopen(fto, “a+”);
    if (to == NULL)
    return 2;

    while (get_key() == 0) {
    // printf(“.”);
    // fflush(stdout);

    int get_key(){
    int ret;

    do {
    ret = fread(&ev, sizeof(ev), 1, from);
    if (ret < 1) return -1; /* read error */ } while (ev.type != EV_KEY); return 0; } int snd_key() { int ret; ret = fwrite(&ev, sizeof(ev), 1, to); fflush(to); if (ret < 1) return -2; /* write error */ return 0; } int grab_dev() { int ret; if (grabbed) return 0; ret = ioctl(fileno(from), EVIOCGRAB, (void *)1); if (ret == 0) grabbed = 1; // else // lprintf("Error: could not grab %s: %s\n", device, strerror(errno)); return ret; } int ungrab_dev() { int ret; if (!grabbed) return 0; ret = ioctl(fileno(from), EVIOCGRAB, (void *)0); if (ret == 0) grabbed = 0; // else // lprintf("Error: could not ungrab %s: %s\n", device, strerror(errno)); return ret; } [/sourcecode] Before I forget, there's also a ruby evdev binding. I myself am not using the code above, nor the ruby evdev binding, since I don’t urgently need shift + VolUp, etc.

Written by zsh

March 26, 2009 at 11:28 pm