Author Archives: eighthave

LD_LIBRARY_PATH and environment is essential in Android

I am working on an Android app that controls various UNIX daemons that need root access to work properly. Originally, I started with some scripts that had all sorts of little tricks to get su integrated in for controlling the root access. Then there was a file that contained a bunch of environment variables that needed to be set.

In my foolhardiness, I decided that the environment variables needed to be set in the java Runtime.exec() call, since it lets you do that. Since the original information to create these variable came from Java, it seemed the logical thing to do. After many struggles where it just didn’t work, su just hung with no warning or reason. It turns out that when running command line programs in Android, the environment is essential. Environment variables like LD_LIBRARY_PATH are essential for programs to find the shared libraries they need, since Android does not implement rpath in binaries for finding .so files.

So all I needed to do was first get the environment from Android, then add my stuff to it, then use that whole thing when calling Runtime.exec(). Here’s the commit. Seems so simple now, if only I could get all that time I spent banging my head against this back…


Debugging shared library linking in Android

So Android does let you run command line utilties, but they sure don’t make it easy. I am currently building gnupg for Android, and for some of the binaries I got, they worked fine, others I got this when I ran them:

# ./gpg-agent
link_image[1995]: failed to link gpg-agent-static
CANNOT LINK EXECUTABLE

So my guess was that there was some missing shared libs, I checked that using readelf -d gpg-agent. All of the libraries listed were included in my setup and they were found once I did:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/data/info.guardianproject.gpg/app_opt/lib

And yet, I still got this error. My final hunch was that my binaries included some symbols which Android’s libs did not provide. But how could I find out which symbols were the problem? I discovered you can use ld, so I did:

hans@palatschinken lib $ adb pull /system/lib /tmp/system-lib
hans@palatschinken lib $ cp *.so* /tmp/system-lib
hans@palatschinken lib $ for so in *.so; do echo $so; arm-linux-androideabi-ld $so -rpath=/tmp/system-lib; done
libassuan.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254
libgcrypt.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libgpg-error.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libksba.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254
liblber.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libldap_r.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libldap_r.so: undefined reference to `pthread_rwlock_rdlock'
libldap_r.so: undefined reference to `pthread_rwlock_init'
libldap_r.so: undefined reference to `pthread_rwlock_destroy'
libldap_r.so: undefined reference to `pthread_rwlock_unlock'
libldap_r.so: undefined reference to `pthread_rwlock_wrlock'
libldap_r.so: undefined reference to `pthread_rwlock_trywrlock'
libldap_r.so: undefined reference to `pthread_rwlock_tryrdlock'
libldap.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libnpth.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254

And voila! There were the symbols in question. Indeed, Android does not provide pthread_rwlock_*.


which macros does the Android NDK gcc define?

I’m working with a lot of cross-platform C code these days, and I find that when porting, its always best to use the macros that are automatically defined by the compiler for that platform. I’ve gotten very used to using __APPLE__ and _WIN32 (arg, yes, not WIN32 as we’d like it), then of course there is __gnu_linux__ for the OS and __linux__ for the kernel. No this is not RMS polemics, this is important, especially since there is now Debian GNU (with a Hurd kernel) and Debian GNU/kFreeBSD (no Linux there). And of course, the main feature of this post: Android.

Android uses the Linux kernel, but is definitely not GNU. The only GNU part of Android I’ve seen is the compiler: gcc.

So what macros does the Android gcc define? I wanted to know, so I ran a little test:

#include 

int main(void)
{
#ifdef __ANDROID__
    printf("__ANDROID__\n");
#endif
#ifdef ANDROID
    printf("ANDROID\n");
#endif
#ifdef android
    printf("android\n");
#endif
#ifdef __linux__
    printf("__linux__\n");
#endif
#ifdef __gnu_linux__
    printf("__gnu_linux__\n");
#endif
}

I ran that thru the cpp by running /usr/local/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=/usr/local/android-ndk/platforms/android-8/arch-arm/ -E -o /tmp/test.E /tmp/test.c and got:

...[snip]
int main(void)
{

    printf("__ANDROID__\n");
# 15 "/tmp/test.c"
    printf("__linux__\n");




}


automatically delete old things from the Downloads folder

Lots of OSs have a handy ~/Downloads folder where all downloaded files automatically go to. This is much cleaner than say, piling them up on the Desktop or elsewhere. I generally move something out of ~/Downloads if I need it, leaving the rest to pile up. Thanks to the very helpful tmpreaper, I have it automatically deleting any file older than 5 days from ~/Downloads. Now it manages itself. You can do this easily with Debian-based OSs (sudo apt-get install tmpreaper) or Mac OS X (fink install tmpreaper). You can cron it using a little script in the right folder:

/etc/cron.daily/tmpreaper_downloads (Debian)

#!/bin/sh
/usr/sbin/tmpreaper --all --protect .localized 5d /home/hans/Downloads

/etc/periodic/daily/900.tmpreaper_downloads (Mac OS X + Fink)

#!/bin/sh
/sw/sbin/tmpreaper --all --protect .localized 5d /Users/hans/Downloads

seeing the contents of the new .pkg format for Mac OS X

The original .pkg format for Mac OS X installer packages followed the old pattern established in NeXTSTEP of a special folder format with an extension to label it a file type. Inside of the .pkg folder, you could find the Contents/Archive.bom file, .bom meaning “Bill Of Materials”, i.e. a listing of the files that the package would install. Using the handy lsbom, you can get all of the info in a nice, scriptable way. The downside to this folder format is that in order to post it for download or other similar situations, it had to be turned into a single file, like a .zip or .tar.gz.

So Mac OS X 10.5 introduced a new format where it was already bundled up into a file, so there is no Contents/Archive.bom to use with lsbom. But there is a way! The new format is still a folder, but with a different layout, and then made into a file using xar, which is something like tar and it comes with Mac OS X. So we have to treat the new format .pkg like a tarball or zip:

tmp $ mkdir dnscrypt
tmp $ cd dnscrypt
dnscrypt $ xar -xzf ~/Downloads/dnscrypt-osx-client.pkg
dnscrypt $ ls
Distribution                            dnscrypt.pkg                  dnscryptproxy-1.pkg
Resources                               dnscryptClientPostflight.pkg  dnscryptproxy.pkg
comopendnsosxdnscryptconfigupdater.pkg  dnscryptClientPreflight.pkg   dnsupdater.pkg
comopendnsosxdnscryptmenubar.pkg        dnscryptmenubar.pkg

This package actually has multiple sub-packages, but they are all bundled together, so the one xar operation has expanded them all into folders again. There is no longer the extra Contents/ folder level, the files are just directly in the .pkg folder. And the Archive.bom file has been renamed to just Bom. And with a little bash script, we can see the whole contents:

for bom in */Bom; do echo --------------------; echo $bom; lsbom $bom; done


turning a series of tarballs into a series of git commits

I find that gitk, the git history browser, is immensely valuable for navigating code. I found myself wanting to navigate the history of code for which I only had the release tarballs. So I wanted to turn them into a series of git commits. The tricky thing here is that I wanted to include adds and deletes, so basically I rm -rf the contents of the git repo, then untar the tarball into the git repo, then you can see adds and deletes. Here’s the script that I actually used:

#!/bin/sh

for tarball in `\ls -1 Pd-0.42.5-extended-l2ork-dev-201*.tar.bz2 | sort`; do
	 date=`ls -l --time-style=long-iso $tarball | cut -b35-52`
	 echo --------------------------------
	 echo $tarball $date
	 rm -rf pd-l2ork.git/*
	 tar --exclude-vcs \
		  --exclude .svn \
		  --exclude .git \
		  --exclude pure-data/pd/.git \
		  --exclude \*~ \
		  --exclude pure-data/pd/bin \
		  --exclude pure-data/pd/obj \
		  --exclude \*.o \
		  --transform 's|pure-data/pd|pd-l2ork.git|' \
		  -xjf $tarball pure-data/pd
	 cd /export/storage/pd-l2ork/pd-l2ork.git/
	 echo "git add"
	 git add `find . -type f | grep -v .git`
	 echo "git commit"
	 git commit --date="$date" --author="Ivica Ico Bukvic " -am "$tarball"
	 cd /export/storage/pd-l2ork/
done

svn vs. HFS+ on GNU/Linux

I run Ubuntu and Mac OS X on a MacBook Pro as my main machine. I do most development work on Ubuntu and most emailing, calendaring, etc. on Mac OS X. But sometimes I want access to my source code in Mac OS X to do quick little fixes and the like. So I made a case-sensitive HFS+ partition that is mounted read/write in both Ubuntu and Mac OS X. Ubuntu can’t handle the HFS+ journalling yet, and HFS+ without journaling seems to explode every once in a while, so I didn’t want to mount my Mac OS X system read/write on Ubuntu, hence the separate partition.

It works quite well, especially when working with git, since the folder is the repo. With svn, its a bit of a different story. It mostly works, but there are some cases where SVN freaks out. If I do svn update in a folder, it all works fine. If I do svn update Makefile, i.e. only directly updating a file, I get:


hans@palatschinken externals $ svn up Makefile
svn: Can't open file 'Makefile/.svn/entries': Permission denied

Apparently this is a known issue to the SVN devs, but they don’t want to fix it: Re: svn diff issue: svn confuses files with dirs on hfsplus?


libtool error dumps

So GNU libtool and the whole autotools suite does seem to help a lot with complicated builds that need auto-detection of all sorts of things, but they can also be an exercise in totally obtuse errors, bizarre scripting, and frustration. I suppose all build systems really share those qualities in some respect. One thing that I’ve run into with puredata/pd-extended is this strange error dump from libtool that seems to be unfindable via search engines. Here’s a snippet:

../libtool: line 844: X--tag=CC: command not found
../libtool: line 844: X--tag=CC: command not found
../libtool: line 844: X--tag=CC: command not found
../libtool: line 844: X--tag=CC: command not found
../libtool: line 877: libtool: ignoring unknown tag : command not found
../libtool: line 877: libtool: ignoring unknown tag : command not found
../libtool: line 844: X--mode=compile: command not found
../libtool: line 844: X--mode=compile: command not found
../libtool: line 877: libtool: ignoring unknown tag : command not found
../libtool: line 877: libtool: ignoring unknown tag : command not found
../libtool: line 844: X--mode=compile: command not found
../libtool: line 844: X--mode=compile: command not found
../libtool: line 1011: *** Warning: inferring the mode of operation is deprecated.: command not found

Why on earth did libtool prepend that ‘X’ to the command line options and try to run them as commands? WTF? This has baffled me to no end… until I realized its because a one version of libtool does not like files generated by a different version of libtool! Arg. I solved this by deleting the m4 folder in my project, then restoring what files are needed in that folder by doing git reset --hard


backing up and restoring a Nokia N810

So I use a Nokia N810 running Maemo GNU/Linux as my main device, I send/receive SMS, IM, email, and phone calls with it. I not so long ago dropped my trusty N810 into a bucket of dirty mop water… if you check the archives, you’ll see that I revived it, and have been using it as my main device ever since. It made a miraculous recovery. But then… I was stupid enough to dropkick it into a wall. It was still running fine, but the screen had about a good 10% of it covered in technicolor gibberish. Then it started to heal! Well, the screen did at least, it healed completely, and the whole screen worked fine… but! The touchscreen started getting more and more out of whack until it finally died entirely. Hard to use a touchscreen device without a working touchscreen, even tho the keyboard is quite nice.

Enter William Ward, I put the call out for me to purchase someone’s old N810. He so kindly gave me his old N810 which he no longer used. Now I just wanted to clone my old device, its a heavily customized setup. Then I remembered, its just a linux box, sooo I can just rsync it! To make it a bit more reliable, I first rsynced the old device to my home server. I ran this command as root (to make sure the perms worked) on my home server:

rsync -axHAXv --progress -e ssh root@10.0.0.135:/ root/
rsync -axHAXv --progress -e ssh root@10.0.0.135:/media/mmc2 media_mmc2/

Then once that finished, I just rsynced over everything to my new N810 with working touchscreen, again running the command as root on my home server:

rsync -axHAXv --delete --progress -e ssh root/ root@10.0.0.140:/
rsync -axHAXv --delete --progress -e ssh media_mmc2/ root@10.0.0.140:/media/mmc2

Et viola! I had cloned my old install to the new hardware!


DO NOT try to run GNU/Linux on a MacBook without a working CD drive!

I’ve been happily dual booting between Ubuntu and Mac OS X on my 3rd gen MacBook Pro 3,1 for a while now. Its CD/DVD drive is barely functional, but I never use it, so I never thought about replacing it. Then I swapped out the hard drive for a new one, and messed up the grub 0.97 boot loader in the process. I tried installing grub on my new disk when it was in an external firewire/USB enclosure. I tried installing grub while the new disk was installed and booted into target disk mode. I tried making a bootable USB or Firewire drive to start Debian or Ubuntu. I tried, I tried, I tried… to no avail besides messing up my booting royally so I couldn’t boot to Mac OS X even without first booting to Target Disk Mode and running a Disk Utility “Repair Disk” on another MacBook on all my partitions. Sometimes my disk would not even show up in the other Mac’s Disk Utility, at all, like it didn’t even exist. Arg. Scary to say the least.

I tried booting CDs but failed. Arg. Then I finally found that my MacBook Pro’s hobbled “SuperDrive” could actually read and boot from a real, printed Ubuntu 9.10 install disk! Its nice and silvery since its printed in aluminum, not burned. So my hobbled read it find, and I did the standard grub install and voila! All is good:

grub-install --no-floppy --recheck --root-directory=/media/Ubuntu /dev/sda3

(yes indeed, that’s grub installing on the partition /dev/sda3, not the straight disk /dev/sda). And remember to read the instructions of these things and actually follow them. I kept wondering why rEFIt wasn’t installing again, with the cd /efi/refit/; ./enable.sh command. Duh, because I didn’t do as they say and reboot twice!.

Maybe now that I have finally made it out of the hell of trying to get my Ubuntu booting again, I might be willing to dive in again to get grub2 working. Booting .iso files directly would be pretty sweet!


Follow

Get every new post delivered to your Inbox.