Categories
Software

Simple Wake-on-LAN Wrapper Script

Our home network includes a number of Linux-based systems and one Apple iMac. Because the Mac hosts all of our family photos, and because printing from a Mac to a Linux printer is a headache, it made the most sense for us to connect the printer directly to the Mac. However, this creates an issue when printing from one of the other computers: if the Mac is asleep, the shared printer does not respond to requests.

The workaround is simple: get up, walk over to the Mac, and hit the space bar or click the mouse to wake up the machine before trying to print. But we don’t want to get up, so we’ll issue a Wake-on-LAN packet to the Mac instead, using **wakeonlan**.

**wakeonlan** is a simple Perl script written by Jose Pedro Oliveira and maintained by Ico Doornekamp. It is available from the repositories for most Linux distributions. The script broadcasts “magic packets” over the network that are read by WOL-compatible interfaces. If the interface recognizes its own MAC address in the magic packet, the interface signals the host machine to “wake up.”

Sure, it’s a neat trick, but we have to know the destination machine’s MAC address. So we can either make MAC address flash cards for our LAN, or we can write a wrapper script to find the MAC address for us and issue the packet.

### Finding the MAC Address ###

To find the MAC address we can use **arp**, a standard Linux utility, to read the local host’s ARP cache. The ARP cache is an important part of any Ethernet network–it stores a table of every known host on the network by IP and MAC address. Essentially, it serves as the local host’s “address book,” making sure requests to a given IP address are sent to the appropriate network interface. Most of the time, this translation is done in the background while the user remains happily oblivious. But Wake-on-LAN packets are special, and they need our help to get to where they’re going.

The output of **arp** looks something like this:

$ arp
Address HWtype HWaddress Flags Mask Iface
server ether ab:cd:ef:01:23:45 C eth0
bobs-machine ether 11:22:33:44:55:66 C eth0
arpeggio ether 56:45:34:23:12:01 C eth0
My-iMac.domain ether c8:2a:14:ff:ff:ff C eth0
My-iMac.local ether e4:ce:8f:00:00:00 C eth0

We’re interested in the third column–the MAC address–of the machine called `My-iMac`. Because the iMac’s Ethernet and Wi-Fi interfaces are both enabled, the same hostname shows up twice (albeit with different domains). We’re only interested in the Ethernet interface, which, fortunately, shows up first (the output of **arp** does not tell us which is which–in my case, I know this because I’ve set up static DHCP leases on my home network–finding this out may require some digging or trial and error). This means that we can write our script to search for the first line matching the hostname, then to extract the third column from that line. We accomplish this using **grep** and **awk**, respectively.

$ arp | grep -i -m1 imac
My-iMac.domain ether c8:2a:14:ff:ff:ff C eth0
$ arp | grep -i -m1 imac | awk ‘{print $3}’
c8:2a:14:ff:ff:ff

For this discussion we’ll bypass a detailed explanation of the **grep** and **awk** commands. See the Linux man pages for details.

Now that we have a command line string that finds the right MAC address, we can write our script.

### The Script ###

Below is our Wake-on-LAN wrapper script, saved in a file named **wol**:

#!/bin/sh

MACADDR=`arp | grep -i -m1 $1 | awk ‘{print $3}’`
wakeonlan $MACADDR

All we’ve done is taken our command line string and replaced the hostname search string (`imac`) with the variable `$1`, which is interpreted by the shell as the first argument passed to the script by the user. This way we can use the same script to send WOL packets to any machine on the network. Executing the script looks like this:


$ ./wol imac

There. Wasn’t that easier than getting up and hitting the space bar?

### Further Reading ###
* [Wake-on-LAN at Wikipedia](http://en.wikipedia.org/wiki/Wake-on-LAN)
* [ARP cache: What is it and how can it help you?](http://www.petri.co.il/csc_arp_cache.htm)

Categories
Software

Printing in Booklet Format from the Linux Command Line

Here is a Linux command to take a PDF of half-letter-sized pages
(5.5″x8.5″) and arrange them, two pages per side, for booklet printing:

$ pdftops -level3 source.pdf – | psbook | psnup -2 -W5.5in -H8.5in | ps2pdf – booklet.pdf

All of these utilities are standard on a Debian-based system. Several filters are tied together using [pipes](http://en.wikipedia.org/wiki/Pipeline_%28Unix%29 “Learn more about Unix Pipelines”) to produce a properly-formatted PDF.

### A Closer Look ###

Here’s a pipe-by-pipe breakdown of the command:

$ pdftops -level3 source.pdf

convert the source PDF to a level 3 postscript file (this is necessary
because the remaining steps require a postscript source file).

| psbook

rearrange the pages from the resulting postscript source file into the
appropriate order for notebook printing.

| psnup -2 -W5.5in -H8.5in

read in the reordered source file and arrange the reordered pages so
that two logical pages are printed on one physical sheet. If your
source pages are a different size, change the values of the `-W` and
`-H` options. You can use the `-p` option (or lowercase `-w` and `-h`)
to specify the output page size, but on Debian-based systems this value
is automatically read from `/etc/papersize`.

| ps2pdf – booklet.pdf

convert the resulting postscript file back into a PDF using the
filename specified. This step is not necessary if you know that the
machine you will print from can handle postscript files. If you leave
this step out, replace it with `> booklet.ps` to write the output to
a file named `booklet.ps`.

This method comes in handy because you don’t have to rely on printer
driver options to handle the booklet reordering. In my experience,
those driver options are terribly fussy and hard to work with.
Further, many printer drivers don’t offer this ability.

I hope you find this info helpful.

Based on info from
[Scribus Wiki](http://wiki.scribus.net/index.php/How_to_make_a_booklet#Method_A-1:_using_psutils_only).

**Update:** I experienced a bug in postscript that was causing a single
page to be rendered upside-down (rotated 180 degrees) when converted to
PDF. Unable to trace the source of the bug, I did find out that
filtering the postscript through `ps2ps` immediately after the initial
conversion from PDF, fixed the problem. `ps2ps` is a postscript
“distiller” which optimizes postscript into simpler form. This does
result in the loss of anti-aliasing, which uglies up the result on the
screen, but it does not affect printed copies.

If you experience rendering bugs, try adding `ps2ps`, as in the
following command:

$ pdftops -level3 source.pdf – | ps2ps – – | psbook | psnup -2 -W5.5in -H8.5in | ps2pdf – booklet.pdf