Search
Enter Keywords:
Thursday, 24 July 2008
Home arrow All
All
Show UTC as a location in Gnome International Clock
Written by Dan   
Tuesday, 15 July 2008
I love the new international clock applet in Gnome.  It makes it easy to see a list of alternate time zones for coordinating with colleagues.  However, it seems to be missing the ability to add UTC as a timezone.  UTC, GMT, and Zulu are missing from the zone list, even though they're present in /usr/share/zoneinfo.  Attempting to add a zone manually just results in a silent failure for some reason.

I'm sure there is a less insane way to do this, but hacking the gconf entries works.  First, figure out which applet number represents your clock.  To find out, I searched gconf for one of my configured locations:

% grep -lr Hillsboro .gconf
.gconf/apps/panel/applets/applet_7/prefs/%gconf.xml

This tells me that my clock is applet_7.  Next, fire up gconf-editor and navigate to apps/panel/applets/applet_7/prefs.  Edit the cities key and add a value of the following:

<location name="Zulu" timezone="UTC" code="UTC" current="false"/>

Save, quit gconf-editor, and pop open your location list to verify.

 
Ubuntu from a USB key on a Samsung Q1 Ultra
Written by Dan   
Monday, 12 May 2008
Man I love Linux.  Uh-lot.

I am setting up these extremely sweet Samsung Q1 Ultra machines for a D-RATS demo.  These uber-slick ultra-portable tablet PCs are pretty amazingly small.  The biggest problem is that they run Vista.  I've read all the stuff out there about being extremely horrible, but this was my first hands-on experience.  I thought "Sure, it's horrible, but it's Windows so horrible is the name of the game."  I had no idea of the level of suckiness I was in for.

To make a long story short, the Prolific USB-to-Serial adapters, which are in just about everything, don't work well in Vista.  Prolific seems to be ignoring Vista in favor of pushing support for the new version to the resellers.  However, most of the resellers that Prolific recommends to people seeking Vista support don't have updated drivers.  Thus, a significant amount of serial activity with these devices in Vista leaves you with a locked machine that won't even shutdown.  It's pathetic.  Luckily Keyspan, continuing with their reputation of high-quality everything, has Vista drivers and their devices work well. 

For the demo, however, I thought it might be nice to have a backup plan.  I don't want to alter these machines, of course, since they're not mine, so I can't install another OS to the hard drive, even for a dual-boot.  This, however, doesn't stop me from booting something like a live CD.  Luckily, the ubuntu live environment is transferrable to a USB key with a few steps .  The result is a wonderful thing: Ubuntu booting completely from a USB key.  I can copy a few of the libraries I need to the key and install them from a script on boot to run D-RATS:

Image

The tablet stylus doesn't work out of the box, and I won't spend the time to fix it since this is just a backup plan.  However, the on-board pointing stick or a USB mouse would suffice.  The sad part is, it boots to this environment just a hair slower than Vista boots from the hard drive.


 
Making a KVM-bootable image
Written by Dan   
Thursday, 06 March 2008
I've lost count of how many times I've had to re-learn how to create a bootable image from a filesystem tree (such as a tarball of a root filesystem, or a Xen partition image).  If for no other reason than recording it for next time, here it is.

Create an image file (lets assume 4MB will do it), partition it, mount the partition, and copy in the root filesystem

% dd if=/dev/zero of=test.img bs=1M count=4
% parted test.img mklabel msdos
% parted test.img mkpart primary 0 4
% losetup /dev/loop0 test.img
% kpartx -a /dev/loop0
% mount /dev/mapper/loop0p1 /mnt
% cp -rav /path/to/root /mnt/

Now, you need to put a kernel and an initrd on it.  Assuming a RedHat-like system:

% mkdir -p /mnt/boot/grub
% cp /boot/vmlinuz-`uname -r` /mnt/boot/vmlinuz
% mkinitrd --with ata_piix --with rtl8139 /mnt/boot/initrd `uname -r`

Next, you need a bootloader:

% cat >/mnt/boot/grub/grub.conf <<EOF
default 0
timeout 5
title My System
    kernel /boot/vmlinuz root=/dev/sda1
    initrd /boot/initrd
EOF
% cat >/tmp/grub_setup <<EOF
device (hd0) /path/to/image       # NB: Put your full path here
root (hd0,0)
setup (hd0)
EOF
% grub < /tmp/grub_setup

That's it!  Now you can unmount your image:

% umount /mnt
% kpartx -d /dev/loop0
% losetup -d /dev/loop0

The resulting image should boot normally in QEMU, KVM, etc.
 
When is foo == &foo?
Written by Dan   
Friday, 08 February 2008
The answer is "in the CMPI interface specification".

So, CMPI defines this massive union of every possible data type, called CMPIValue.  It looks something like this (but with many more types):
union {
    uint32_t uint32;
    uint64_t uint64;
    char *chars;
    CMPIString *string;
} CMPIValue;
This is then thrown around way too much, using an enumeration called CMPIType to indicate which interpretation of CMPIValue you intend to use.  For example, to set a property of an instance, you would do something like this for an integer:
uint32_t myint = 123;
CMSetProperty(inst, "MyIntProperty", (CMPIValue *)&myint, CMPI_uint32);
or this for a string:
const char *mystring = "We're really asking for trouble here...";
CMSetProperty(inst, "MyStrProperty", (CMPIValue *)mystring, CMPI_chars);
Makes sense, right?  The above usage in the string case is, of course, the scenario intended by the interface designer, and it is (in my experience) almost exclusively used that way.  However, assuming you want to do something a little more complicated, such as write a CIMXML instance parser, you might want to pass around their CMPIValue and CMPIType objects.

So, lets say you do something like the following:
CMPIType parse_integer(char *string, CMPIValue *val) {
    val->uint32 = 123;
    return CMPI_uint32;
}

CMPIType parse_string(char *string, CMPIValue *val) {
    val->chars = strdup("Oh, boy, here we go");
    return CMPI_chars;
}

int set_property(char *string, char *name, CMPIInstance *inst) {
    CMPIValue value;
    CMPIType type;

    if (/* value looks like an integer */)
        type = parse_integer(string, &value);
    else
        type = parse_string(string, &value);

    CMSetProperty(inst, name, &value, type);
}
That's all fine, right?  We set the CMPIValue in our handler functions, and then we pass a pointer to our value to CMSetProperty().  Obviously nothing to see here, CMSetProperty() takes a CMPIValue *......doesn't it?

The answer is a big fat "NO, no it doesn't".  If you were paying close attention before, we passed in the pointer to a CMPIValue stack variable in the integer case, but in the string case, we passed in a pointer to an actual string buffer.  Thus, if we put that string pointer in the CMPIValue itself, and then pass a pointer to it, you get a double pointer, the equivalent of a char **.  Because the type is correct, the compiler doesn't complain, but the CIMOM explodes.

I'm really shocked and horrified that the CMPI interface includes this semantic difference in the setProperty() broker call.  To verify that I wasn't just hallucinating on a Friday afternoon, I tracked the call down to the following bit of truly spectacular OpenPegasus code:
CIMValue value2CIMValue(const CMPIValue* data, ...) {
    . . .
    else if (type==CMPI_chars) {
          if (data) v.set(String((char*)data));
          else return CIMValue(CIMTYPE_STRING,false);
    }
Right there, they take the CMPIValue and cast it directly to a char * if you tell them that you're passing in CMPI_chars!  Just to illustrate how the interpretation of the CMPIValue parameter fundamentally changes depending on the type you passed in, the following appears directly below:
   else if (type==CMPI_charsptr) {
      if (data && *(char**)data) v.set(String(*(char**)data));
      else return CIMValue(CIMTYPE_STRING,false);
   }
So, if you pass in CMPI_chars, then it expects a char*.  If you pass in CMPI_charsptr, then it expects a char ** (which would actually cast a the example above to the correct thing).  IMHO, it would have been better for them to just call it a void * and be done with it.  They think they have made it cleaner, but they've actually made it worse.

What a great way to end a Friday.

 
Python programs for Windows with py2exe
Written by Dan   
Wednesday, 23 January 2008
If you know me, you know that I don't often acknowledge the existence of Windows as an OS worth my attention.  However, I'm working on some code for a group of people who are predominantly Windows users that, aside from their choice of OS, are pretty quality individuals.  Since I would certainly not spend my time writing a native win32 application, I decided to use Python, which is one of my preferred languages for Linux.

I knew that Python ran on Windows, but I didn't realize how extensive the list of necessary add-on packages would be; I'm spoiled by modern Linux distributions.  For this app, I would need Python, pyGTK, and pySerial.  Those packages require the GTK runtime, the win32all package, pygobject, and pycairo.  Thus, any poor Windows user would be stuck installing a raft of packages totalling about 50MB (download size) before they could run the app.

I figured there had to be a better way.  I had considered getting the source for all of the python code and putting it into a single tree and rebuilding the installer to install them all at once, but that wouldn't cover GTK and would be a bit of a pain.  After a bit of searching, I came across py2exe.

This nifty little tool extends the python distutils and gives you a new build target.  During the build process, it determines all of the required Python packages that your app will need and copies them into a distribution directory.  It then copies in the Python runtime itself, as well as any necessary DLLs to run.  Finally, it turns your toplevel .py file into a .exe.  Zip that up and post it.  All someone needs to do is extract it and run your .exe file.  How nice is that?

Given that pyGTK is rather large and complex, it didn't go as smoothly as it should have.  I had to do two extra things: Add a list of required packages to assist the detection and copy in the GTK share files.  My setup.py ended up like this:

from distutils.core import setup
import py2exe

opts = {
    "py2exe" : {
    "includes" : "pango,atk,gobject,cairo,pangocairo",
    }
    }

setup(windows=["mainapp.py"], options=opts)

After building, you get a nice "dist/" (or, in the backwards Windows world, "\dist") directory.  To complete the GTK distribution, I copied the share, etc, and lib directories from C:\GTK into dist.  To cut down on the extra crap, I also deleted everything but "en" from the "share/locale" directory.  The result is a nice and neat little package that OS-challenged people can handle.  I think I'll also need to figure out how MacOS distributes such things at some point, but I'm sure there will be less groaning and eye-rolling during that process.
 
<< Start < Prev 1 2 3 4 5 Next > End >>

Results 1 - 9 of 37

© 2008 danplanet
Joomla! is Free Software released under the GNU/GPL License.