Wednesday, April 29, 2009

Printing from DOS in VirtualBox

VirtualBox doesn't support LPT ports. DOS has limited ability to print to USB printers, and the program I am using definitely doesn't support it. Thus I need to find an automatic, or at least semi-automatic, user friendly way to print from DOS.

----------------------------------- The Mount Method -------------------------------------

My first approach was to print to a file in DOS, then simply mount the .vdi and read/print the file.

This has three drawbacks:

1. You need sudo to mount the .vdi.
2. You can't use it with snapshots or non fixed sized disks.
3. I don't like mounting a disk that is already in use.

The first problem can be solved by adding an entry in the fstab or using FUSE. The second and third problems can be solved by printing to a floppy image and then mounting that instead.

So the basic process is go to Devices and mount a floppy image, print to the floppy using filename "print", unmount the floppy, then run this script in Linux:


#!/bin/bash
#we need recode (sudo apt-get install recode)
#add the floppy image to fstab to avoid sudo.
#mount writable and erase the print file so DOS doesn't prompt to overwrite?

mkdir -p ~/dosprint/printtemp
sudo mount -o loop,ro ~/dosprint/flopppy.img ~/dosprint/printtemp/
cp ~/printtemp/print ~/dosprint/printing
recode IBM437/CR-LF ~/dosprint/printing
lpr ~/dosprint/printing
umount ~/dosprint/printtemp
rmdir ~/dosprint/printtemp
rm ~/dosprint/printing

Notice that I am calling recode to convert the old DOS formatting. Obviously you will have to change floppy.img to match the floppy image you printed to.

This isn't a terrible option, but it does make the user have to remember the exact filename to print to, or else the script won't work. The whole mount/unmount process is a bit tedious too.


----------------------------------- The Serial Port Method -------------------------------------

To fix this I started looking at VirtualBox's COM emulation. It can connect the VM's COM port to a socket on the filesystem (it calls it a pipe, but it is really a socket... I probably would have preferred a real pipe). Anyway, after fiddling with it a bit I came up with a, hopefully, better solution.

After enabling COM1 on the VM to output to a "pipe" start up the VM. Then run socat -u UNIX-CONNECT:$HOME/dosprint/printpipe GOPEN:$HOME/dosprint/printfile in a terminal. You may have to do a 'sudo apt-get install socat' if it isn't already installed. The DOS VM now can print to COM1. After printing in DOS simply run this script:


#!/bin/bash
printfile="$HOME/dosprint/printfile"

#check to make sure the file exists and is not empty.
if [ ! -f $printfile ] || [ "`stat -c %s $printfile`" -le "1" ]; then
zenity --error --text "The Print File is Empty or Does Not Exist\!"
echo "" > $printfile
exit 1
fi

lpr $printfile

#check to make sure it printed
if [ "$?" -ne "0" ]; then
zenity --error --text "Error Printing!"
echo "" > $printfile
exit 1
fi

echo "" > $printfile
zenity --info --text "Printing\!"


There are probably some better ways to use socat here, but this worked the best so far. I would prefer to use a pipe, but it didn't work as expected. Also notice I didn't have to use recode, which was nice; this however is dependent on the printer driver DOS is using. In one incarnation I had to use dos2unix; unix2dos; then recode to get it to print properly. (In Ubuntu dos2unix is in the package 'tofrodos'.)

The biggest drawback here is that socat has to be run every time the VM is started, and you can't even run it as a startup script because it returns immediately unless the VM is running. At least it gets rid of the mounting and naming issues.

Here is a simple script to start the VM and run socat automatically:


#!/bin/bash
VirtualBox --startvm DOS&
echo "" > ~/dosprint/printfile
sleep 5
socat -u UNIX-CONNECT:$HOME/dosprint/printpipe GOPEN:$HOME/dosprint/printfile


You can create a launcher (right click desktop or nautilus window) if you want to be able to open this script without being prompted to run in terminal or display.

P.S. Zenity is very nice :).

Thanks to Maciej BliziƄski for some nice info on VirtualBox's serial port pipes.

Update: I ended up using iconv rather than recode, since recode had some problems with some special characters. Careful with iconv, it changed between the version on Ubuntu 8.04 and 8.10 (mainly the overwrite in place functionality).

Monday, April 27, 2009

Mount Xen and VirtualBox Images in Linux

If you use Xen disk images then you can mount them fairly easily to directly modify them on dom0 or another system:

Use "fdisk -luC 530 WinXP.disk" to print the partition table of the disk (where WinXP.disk is your disk image...).
Then multiply sector size by the sector start of the partition you want, then simply mount using that offset:
"sudo mount -o loop,offset=32256 WinXP.disk /media/mountpoint"

For example:
fdisk -luC 530 WinXP.disk

Disk WinXP.disk: 0 MB, 0 bytes
255 heads, 63 sectors/track, 530 cylinders, total 0 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x6c896c89

Device Boot Start End Blocks Id System
WinXP.disk1 * 63 41913584 20956761 7 HPFS/NTFS
Partition 1 has different physical/logical endings:
phys=(1023, 254, 63) logical=(2608, 254, 63)


Then 63 sectors * 512 bytes per sector =32256, so:
sudo mount -o loop,offset=32256 WinXP.disk /media/mountpoint

This info was found here.


In VirtualBox the operation is similar, but since the .vdi format is different you have to jump through another hoop. Note this only works with fixed size images. First you have to find the start of the disk, then use that to find the start of the partition:

od -j344 -N4 -td4 image.vdi | awk 'NR==1{print $2;}'

Now use the number it returns as #offset# in:
dd if=image.vdi of=vdstart bs=1 skip=#offset# count=1b
/sbin/sfdisk -luS vdstart


This takes the partition table of the virtual disk, dumps it to a file, then reads the partition table to tell you where the partition starts. Now the process is similar to Xen, multiply the sector size by the sector offset of the partition to find the start of the partition, but you also have to add the vdi offset you found before. You can then use that offset to mount the partition:
mount -o loop,offset=39424,ro image.vdi /media/image/

For Example:

$ od -j344 -N4 -td4 DOS.vdi | awk 'NR==1{print $2;}'
7168
$ dd if=DOS.vdi of=vdstart bs=1 skip=7168 count=1b
512+0 records in
512+0 records out
512 bytes (512 B) copied, 0.00523881 s, 97.7 kB/s
$sfdisk -luS vdstart
Disk vdstart: cannot get geometry

Disk vdstart: 0 cylinders, 255 heads, 63 sectors/track
Warning: The partition table looks like it was made
for C/H/S=*/64/63 (instead of 0/255/63).
For this listing I'll assume that geometry.
Units = sectors of 512 bytes, counting from 0

Device Boot Start End #sectors Id System
vdstart1 * 63 3253823 3253761 6 FAT16
vdstart2 0 - 0 0 Empty
vdstart3 0 - 0 0 Empty
vdstart4 0 - 0 0 Empty
$sudo mount -o loop,offset=39424,ro DOS.vdi /media/dos/


The mount offset was calculated by: 7168 (vdi header) + 63 (sectors) * 512 (bytes per sector) = 39424


Works like a charm :) Thanks Przemoc. More info can be found here.

I am still looking for a way to do it with Snapshots though :/. On a different note, this looks like it could be useful.

Sunday, April 12, 2009

WPA Enterprise on Android HTC G1 Dream

Unfortunately Android still does not have a GUI interface for connecting to corporate/enterprise networks; however, it does support it. While this isn't a solution for most users, it is fairly easy for those who have already rooted their phone or aren't scared of the command line.

First, you need to root your phone or else you can't get to the files you need to configure. Newer firmwares aren't as easy to root as older ones; either way this tutorial should walk you through what you need to do. It is very user friendly, and if you have any problems then it is probably addressed later in the forum comments. I had two problems when I did it:

1) I skipped the reformatting of the SD card since mine was already FAT. For some reason the phone needs FAT32 in order to recognize boot files... So don't skip this step.

2) The first link, and corresponding MD5 sum, to the modified OS images are to the BuildEnvironments rather than the actual OS image. Just go to the second link and download the actual image (it will be a zip file and 40.5MB rather than a .tar.gz that is 7.5MB). Hopefully Koush will update the post and fix this.

Anyway, after your device is rooted pull up a command prompt on the phone somehow. If you already know how to do this then skip ahead. You have a couple options:

1) All on the phone: I am pretty sure the terminal emulator comes pre-installed on that image. If not then you can just download it from the Market. You can just use this, but I wouldn't recommend it unless you really like typing on your phone.

2) Through telnetd: Use the terminal emulator then type "su" then enter. This will pull up the super user whitelist prompt. Tell it "Yes" that is okay for the Terminal to run as super user. Meanwhile the terminal may timeout, in which case you need to type it again. You can that you are root by running "whoami" which will tell you that you are uid 0 if you are root. Make sure the phone is connected to wifi. You can get the IP from the Wireless gui or running "ip a". Now run "telnetd". From another computer on the network run "telnet #android_IP#" where #android_IP# is the IP of the phone.

3) Using the debugger: This involves doing this then looking at this. If your device is all set up and plugged in to a computer this entails basically running "adb shell".


Now all you have to do is edit the /data/misc/wifi/wpa_supplicant.conf file. You can do this by copying it to your sdcard, editing it on a computer, then copying it back. I prefer just to edit in place. Update: Sorry I forgot to mention you need to run "su" first, or else you will get permission denied errors.

Regardless, you probably first want to backup the existing wpa_supplicant.conf file:

cd /data/misc/wifi/
cp wpa_supplicant.conf wpa_supplicant.conf.orig


To copy to sdcard (make sure you have one in there):

cd /data/mis/wifi/
cp wpa_supplicant.conf /sdcard


To edit in place:

cd /data/mis/wifi/
vi wpa_supplicant.conf


The wpa_supplicant file will contain all of your remembered wifi networks. Something like:

ctrl_interface=tiwlan0
update_config=1

network={
ssid="linksys"
key_mgmt=NONE
priority=11
}


Now add the parameters for your network. Many schools/business will provide this config for you, so you can just copy it over. Mine looks like:

ctrl_interface=tiwlan0
update_config=1

eapol_version=1
fast_reauth=1
network={
ssid="Some SSID"
scan_ssid=1
key_mgmt=WPA-EAP
eap=TTLS
identity="USERID"
password="PASSWORD"
phase2="auth=PAP"
priority=1
}

network={
ssid="linksys"
key_mgmt=NONE
priority=11
}


This will now make "Some SSID" show up as remembered on the WiFi config GUI screen, and when in range, if everything is configured right, it will connect automatically. Note that in this case my password is stored in plain text on a file in my phone. This is bad, but I'm not sure there is a way around it at this point.

More information on how to configure this can be found here.

Notably Android automatically deleted the eapol_version=1 and fast_reauth=1 lines, however it still works fine.

There is a relate Google code issue here.

Update: I am having problems with the phone rapidly associating and disassociating from every AP in range. I filed a bug report here.

Update: This is fixed in Haykuro's latest build.

Update:
Allegedly there is a program in the market that can do all of this from a GUI (although you still need a rooted phone). It is called Wifi Helper by Fan Zhang; I haven't tested it personally yet. I kind of doubt it fixes the AP hopping issue on older versions.