2008-05-20

Skipping to merge install phase in Paludis

Don't you hate it when building a lengthy package succeeds, installs all right into the image, only to fail for some trivial reason (like out of disk space) when merging into the filesystem? In portage you could just use the ebuild(1) command to short-circuit it right to merge. It's not that easy with Paludis, unfortunately.

But worry not, undocumented environment variables to the rescue! The SKIP_FUNCTIONS environment variable allows you to force paludis not to execute some phases of the install action. The magic combo is SKIP_FUNCTIONS="init killold setup saveenv unpack compile install". It fails on loadenv just before postrm for some reason (probably because we barred it from saveenv, but there seems to be no way to skip one saveenv and not another), but by that point the package is already merged.

But really, they ought to make it easier to do such tricks (or at least document the freakin' variable). I can only imagine how hard it must be to debug ebuilds with paludis... Or maybe there is something I don't know about?

2008-02-25

Really nice system administration console

When you're like me, you don't like your CPU cycles waste — and if you're using Gentoo, you like to be constantly merging something in the background. The problem is that the CPU and IO load really can be a major PITA, rendering the machine essentially unusable to do any real work when compilation is running.

Luckily, Linux kernel offer a great deal of flexibility when it comes to scheduling and prioritizing processes. And using that, I hereby present you The Really Nice SysAdmin Console:

alias suscreen="sudo screen -drU || sudo nice -n19 ionice -c3 chrt -b 0 su - -c 'screen -U'"

What this code does, is to:

  • try to attach to an existing root screen (won't work for more than one, sorry),
  • in case that fails (ie. no screen running) it sets up a root login screen, scheduled on
    • lowest nice priority,
    • idle io priority class,
    • BATCH scheduler class.

Maybe chrt -b 0 and nice -n19 are a bit redundant, but you're never too sure. The bottom line is — you can have your compilation running in that screen and it doesn't go in the way with whatever you do; when need be, it just yields any CPU and IO to higher-class (ie. your) processes. So you can have your cake and eat it too.

2008-01-07

Hardware hacking or how I learned to love the DRM

[a photo of the device]My friend, roommate and/or wife (pick two) has a Sony Network Walkman NW-E507. Quite nice piece of hardware in and of itself—gotta love the shiny bright OLED (or whatever) display.

It has only one forthcoming, and a huge one at that. Designed from grounds-up with DRM in mind, it seems that the only way to upload music is to use Sony SonicStage software; it converts files to ATRAC3 (supposedly the only format the device can play), encrypts them and only after such preparation (and adding to a proprietary-binary-formatted directory files) they could be played back. Quite amazingly odd, if you ask me—especially given it's a USB Storage device.

What's worse, the software is only available for Windows and doesn't seem to work in wine at all. (appdb.winehq says someone succeeded in running it, but I have no patience trying different wines and crazy config files + dlls mix and match. Sorry.) This is quite a major headache, as recently I've convinced her to switch to Ubuntu (and now we're running a 100% windows-free household) and now she's effectively unable to use the player (well, only as a really cool looking portable radio).

After some googling, there seemed there is no way to drive it with linux. But then again, it seems to semiofficially support playing MP3 files—but they have to be encrypted, too. Looking deeper, I've found mlsony—an open-source plugin for winamp allowing to upload and download mp3s to the Walkman. It is written in rather clean C++, so it wouldn't be hard to port.

Now, what's cool is that it seems they have succeeded in reverse-engineering the encryption format; alas, the plugin needs a key, and to get the device key, you have to run another proprietary Sony program.

As it wouldn't work in wine either, I've had a choice: either going through hell of installing (or downloading a VM, anyways) and running windows just to get those fricking 16 bytes, or reverse engineering the app. Obviously the latter seemed more fun, so that's just what I've done.

After some fun with freeIDA, assembly and WINAPI (thank you ReactOS for a clean reference and clean header files!) I've finally revealed that getting the key is a piece of cake. Everything that needs to be done is to send special SCSI commands to the device; first to authorize you, and then to read the key.

You can even do that from command line. Just make sure you have sg3-utils and xxdinstalled and just do
echo 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | xxd -r -p | sg_raw -s 20 /dev/sg2 a3 00 00 00 00 00 00 bc 00 14 30 00; sg_raw -r 18 -o sonydid /dev/sg2 a4 00 00 00 00 00 00 bc 00 12 3f 00; cat sonydid | tail -c16 > key

There, you have your device key in the key file! Just be sure to substitute your walkman device for /dev/sg2.

(Keep in mind that I have not tested the key yet; I have disassembled the validation procedure of the Sony software, and the string I've obtained seems all right. If you need to know, the magic value is 03 01 01 00 00 00.)

2007-09-19

Tray icons in DWM

DWM is a pretty neat window manager—it's very flexible and can be customized exactly to suit one's needs: I've tried several dynamic tiling managers, and so far only DWM doesn't get in my way and actually is more comfortable than traditional WMs.

Configurability of DWM may sound strange to some: there is none. All customization is done through editing the source code. This may seem daunting, but it really isn't: there isn't much code (below 2000 SLOC) and it's all so clear, that even someone without a background on X11 can get to hacking and learn something in the process. Plus, many immediately configurable settings are gathered in a single header file.

Given this, even though DWM may be mean-and-lean, it's easy to extend it with any feature one would dream of. For me, it was system tray support (you know, those little 22×22 applets docked near your clock). As I'm a KDE user, I'm very much used to little conveniences such as klipper. (Yes, that's right, I'm using DWM with KDE, just by setting KDEWM environment variable.) And vanilla DWM can't handle those properly—every tray icon gets its own ordinary window, which, as you can see, isn't terribly convenient:

[a screenshot showing tray icons on vanilla DWM]

To fix that, we first need to see how tray icons are handled in X11. It turns out there is no single standard of doing that. Well, there is the FreeDesktop one, but it's overly complicated and (fortunately) not really used (yet), except maybe for Gnome. KDE3 and third-party apps use a simpler method: they set certain window property, which get spotted by the WM (or other program) which then position and/or swallow the window accordingly.

Two atoms seem to be used for that: WM_WINDOW_ROLE set to Tray Icon and _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR pointing to the parent window. Some programs use both.

So all we need to do is spot appropriate properties and check if they're right; if either the role is tray icon, or the KDE-specific property is set at all, we can put the tray window to the right side of the screen. Here, much better:

[improved tray handling]

2007-09-11

Cross-compiling Qt4/Win on Linux

I've recently been playing rediscovering Qt with Qt4. Qt is a great cross-platform programming environment for GUI apps—the best I've used, at least. Anyway, as I put my app together, I thought that I should release it as a windows binary as well—both to use (and test!) this Qt cross-platform compatibility and because I expect the majority of the tool users would be windows users. Alas, I don't have a working windows os (I do have installed some 120-day evaluation version of win2003 somewhere, but even if it works, which I doubt, given some hardware changes since I've last launched it, I think the evaluation period is over anyway), let alone windows development environment.

So, I immediately thought about cross-compiling. Cross-compiling is compiling for another target platform than the host platform (where we run compilation). Generally, mingw32-gcc works marvels for linux-to-win32 cross-compilation and I've been using it some time ago for GTK apps. That was easier, because GTK/win is available in compiled form, so I just needed to cross-compile my own apps. For Qt4/win, no mingw32 binaries are readily available. So I had to take a go at compiling it myself.

After some googling, I've found that although some people tried to achieve that, none of them succeeded. This turned me down a little bit, but I'm not a person which would run away from a challenge.

The main problem with this cross-compilation is Qt4 build system. Although it seems to support cross-compilation, it really can only do it out-of-the-box between different Unix platforms. Since mingw32 is not strictly a Unix platform and different codepaths need to be compiled, this approach fails. So what we need to do is trick the buildsystem into thinking that win32 codepaths apply to unix.

Without further ado, I present you with step-by-step instructions on how to cross-compile Qt4/win. First, though, you need to obtain cross-compiling environment. On gentoo it's simple. Run the following as root:
emerge crossdev
crossdev -t mingw32

Well, simple as it may be, compilation was broken on my box on one step. It seems that it didn't find the right compiler to compile win32api. What was needed is
gcc-config mingw32-4.2.0
source /etc/profile

After that I've re-issued the crossdev -t mingw32 command and everything worked.

Now for the compilation of Qt4/win. You need to have Qt4/X11 already installed on your system, as we'll use Qt utilities already available on the system. Make sure you don't the following as root, because the build system for some reason insists on installing DLLs in /usr/bin (doesn't break if it can't, so no harm).

  1. Get Qt4/win sources. I've used 4.3.1 edition.
  2. Unpack them. Enter the directory.
  3. Trick the buildsystem into using win32 feature files:
    cd mkspecs/features
    ln -s win32 unix
    cd ../..
  4. Download the patch. Apply it.
    patch -p1 < qt4win-cross-mingw.patch
  5. Make sure qmake doesn't use compilation paths meant for unix
    find src -name '*.pro' -o -name '*.pri' | xargs sed -i -e 's/\(^\|[^_/]\)unix/\1linux/g;'
  6. Make qmake use compilation paths meant for Windows.
    find src -name '*.pro' -o -name '*.pri' | xargs sed -i -e 's/\(^\|[^_/]\)win32\([^-]\|$\)/\1unix\2/g;'
  7. Trick configure into using system utilities. for f in moc rcc uic qmake; do ln -s `which $f` bin; done
  8. Make sure we don't build them:
    echo qmake: > qmake/Makefile.unix
    for f in `ls src/tools`; do echo TEMPLATE = subdirs > src/tools/$f/$f.pro; done
  9. We need some files from the Qt/X11 source, specifically configure script and config.tests directory. I've got them from my qt-copy (from KDE repo); you can use that or download Qt/X11 sources. Put them in the main source directory.
  10. Configure. These options are carefully chosen not to break compilation (except -prefix and -prefix-install; the latter doesn't seem to work anyway).
    ./configure -prefix $PWD -xplatform win32-g++ -no-largefile -exceptions -no-accessibility -no-qt3support -make libs -prefix-install $PWD -no-reduce-exports
  11. Make a missing makefile.
    qmake -spec $PWD/mkspecs/win32-g++ src/winmain/winmain.pro -o src/winmain/Makefile
  12. Build.
    make
  13. Done!

If you have Wine, you can even test it. Just make sure the dlls are where Wine can find them: cp /usr/mingw32/usr/bin/mingwm10.dll lib/*.dll /home/divide/.wine/c/windows/system/. To compile the demos, do
cd demos
qmake -spec ../mkspecs/win32-g++ demos.pro
make
wine demos/affine/affine.exe

A screenshot of affine Qt4 demo under wine

The only problem I've found with using Qt4 in wine is that the latter doesn't implement some font handling functions and it sometimes breaks font rendering where text is laid out dynamically—esp. QGraphicsView and QTextEdit seem to be the worst offenders.