Author Archive

Undeleting opened files on ext3

I'm a specialist when it comes to delete files I didn't intend to. 3 years ago, I did an rm -rf that cost me most of my ${HOME}, and I wrote some software (which i really should work on, BTW) which helped recover most of it (it's tricky to get files back from ext3 once they are removed from the filesystem, since ext3 clears the block pointers from the inodes then).

Today, I somehow managed to remove log files. Fortunately the log files were still in use by a process, so they were still in the filesystem. Unfortunately they were still in use by a process, filling and filling and filling... and in no way i wanted to lose all this data.

Let's consider, for the needs of the demonstration, the following case:
mh@namakemono:/mnt/test$ while true; do date; sleep 1; done > log

That fills a 'log' file every second with the current date.
mh@namakemono:/mnt/test$ tail -2 log
2006年 7月 4日 火曜日 20:48:02 CEST
2006年 7月 4日 火曜日 20:48:03 CEST

The file keeps growing and growing. Now, let's remove it.
mh@namakemono:/mnt/test$ rm log

The file is not in the directory any more, but remains in the filesystem. It is actually readable through /proc:
mh@namakemono:/mnt/test$ ls -l /proc/10724/fd
合計 5
lrwx------ 1 mh users 64 2006-07-04 20:52 0 -> /dev/pts/1
l-wx------ 1 mh users 64 2006-07-04 20:52 1 -> /mnt/test/log (deleted)
lrwx------ 1 mh users 64 2006-07-04 20:52 10 -> /dev/pts/1
lrwx------ 1 mh users 64 2006-07-04 20:45 2 -> /dev/pts/1
lrwx------ 1 mh users 64 2006-07-04 20:52 255 -> /dev/pts/1
mh@namakemono:/mnt/test$ tail -2 /proc/10724/fd/1
2006年 7月 4日 火曜日 20:52:45 CEST
2006年 7月 4日 火曜日 20:52:46 CEST

As you can see, it kept filling while deleted. The usual technique to recover such a file is to copy it from /proc. I happen to have done so some times before, it works pretty well for static files. But that doesn't in our case: we'll get a new copy of the file, frozen at some point in time. Here, we'd want to 're-link' the file.

Basically, that can be done with debugfs. The problem is that I didn't find a clean way to get the inode number from the /proc/10724/fd/1 file. But that can be worked around. You need root access (what a surprise), and hope your filesystem was mostly clean before removing the file.

namakemono:/mnt/test# e2fsck -n /dev/namakemono/tmp
e2fsck 1.39 (29-May-2006)
Warning! /dev/namakemono/tmp is mounted.
Warning: skipping journal recovery because doing a read-only filesystem check.
/dev/namakemono/tmp contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Deleted inode 113570 has zero dtime. Fix? no
(...)

Don't worry, the -n option will make the filesystem opened read-only, so there's no risk for your data.
The interesting part of the output is obvious: the number of the deleted inode. You now only need to link the inode:
namakemono:/mnt/test# debugfs -w /dev/namakemono/tmp
debugfs 1.39 (29-May-2006)
debugfs: cd test
debugfs: ln <113570> log
debugfs: q

And see how it worked:
namakemono:/mnt/test# tail -2 log
2006年 7月 4日 火曜日 20:58:40 CEST
2006年 7月 4日 火曜日 20:58:41 CEST

You can tail again, it will show you the file is being appended to.

I guess you can do something along these lines to restore a file from ext2. I don't know for other filesystems.

If someone knows how to get the inode number without e2fsck, comments are opened :)

Update: Well, it didn't take long for me to actually find a better way:
namakemono:/mnt/test$ lsof -p 10724 -a -d 1
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash 10724 mh 1w REG 254,3 13552 113570 /mnt/test/toto (deleted)

Basically, when the file can be found in /proc/$pid/fd/$fd, run lsof -p $pid -a -d $fd.

2006-07-04 21:17:08+0900

ext3rminator, miscellaneous | 4 Comments »

Long live the battery

After playing around with gnome-power-manager so that it can support spicctrl (which is to be done in hal, actually) to be able to adjust LCD brightness according to whether the AC adapter is plugged or not, I wanted to go a bit further in my quest for battery life. To be honest, I was already adjusting the LCD brightness with a custom acpid event script, but it's still nicer to have it out of the box.

Anyway, the main issue I remembered for battery life, apart from LCD backlight and Wi-Fi, is CPU power states.

When on battery, the CPU in my laptop can handle 4 such states. From C1 to C4 (According to the acpi docs there's actually a C0 state, so that'd make 5). But when on battery, the CPU never goes past level C2. I did some basic check a long time ago, by removing modules, and after removing Firewire, PCMCIA, and USB support, the CPU would go in C3 and C4 states. Though this definitely saves battery because it turns off parts of the computer, I wanted to know exactly what was sucking the CPU, and to keep at least USB, that I use more than the rest.

After selectively removing the modules, it turns out the uhci_hcd support (USB1) is somehow responsible. Which is sad, because my USB mouse is USB1. But it also turns out there's always a peripheral connected to the USB1 hub on my laptop. Indeed, the internal bluetooth support, which is activated at the same time as Wi-Fi, is connected internally through USB1. If I turn off Wi-Fi, it disconects the BT USB device. It appears that in this configuration, having uhci_hcd loaded doesn't have an influence on the CPU. It still reaches C3 and C4 levels. Problem is I don't want to turn off Wi-Fi.

So, with the help of my friend google, I found out that it's possible to unbind drivers from devices, and successfully unbound the USB port the BT device is connected to, without deactivating all the other (external) ports. The sad thing is that when doing such, it also automagically disables the Wi-Fi device (an ipw2200) IRQ, but modprobing ipw2200 again enables it without enabling the BT device.

Next step was to find a way to have this set-up applied automatically at boot-time. I tried to add the following to my udev rules:
ACTION=="add", SUBSYSTEM=="pci", ID=="0000:00:1d.2", ENV{UDEV_START}==1, OPTIONS="ignore_device"
which i'd have expected to do what i want, but it doesn't. I also tried:
ACTION=="add", DRIVER=="uhci_hcd", RUN+="/bin/echo -n 0000:00:1d.2 > /sys/bus/pci/drivers/uhci_hcd/unbind"
which doesn't work either. But:
ACTION=="add", DRIVER=="uhci_hcd", RUN+="/some/script/containing/the/previous/echo"
does. Well, it does work when you restart udev, but not when you reboot. Unfortunately, the initramfs (built with the initramfs-tools) loads a lot of modules, including USB. Meaning that udev doesn't load these and doesn't apply the rules then. Unless I write my own list of modules to load at boot time, initramfs-tools won't produce a useful initramfs for my case. Yaird, on the other hand, did what I wanted it to do, except that it still lacks support for resuming from suspend-to-disk.

In the end, I put a script in /etc/rcS.d. This script unbinds the uhci_hcd driver from the BT device port and re-modprobes ipw2200.

I got a bad surprise, though. After a fresh startup, the CPU would be stuck on C2 state again. Remember how the OpenGL performance would drop if I switch to console and back to X ? It also turns out that it also makes the CPU able to reach C3 and C4 states. There seems to be something odd with the radeon driver...

2006-07-02 09:53:01+0900

miscellaneous, p.d.o | Comments Off on Long live the battery

I hate soccer

And hooting like crazy until late at night when France somehow beats Brasil is not going to change my mind. Dumbass.

2006-07-02 09:10:33+0900

miscellaneous | 1 Comment »

WordPress and daylight saving

WordPress has a wonderful feature: instead of providing a timezone where you live, you tell it how much hours your local time differs from GMT. Which just fails when dealing with daylight saving.

And I just noticed that my setting was still 1 hour, instead of 2. I remembered to change time on my wallclocks, mobile phone, but I forgot my blog... But changing that will change it only for future posts and comments.

So, for people who forgot like me, here are two SQL queries to fix the database:

update wp_posts set post_date = convert_tz(post_date_gmt, 'GMT', 'Europe/Paris'), post_modified = convert_tz(post_modified_gmt, 'GMT', 'Europe/Paris');
update wp_comments set comment_date = convert_tz(comment_date_gmt, 'GMT', 'Europe/Paris');

Don't forget to replace Europe/Paris with whatever your timezone is ;) . Note that this will require you to run, if you've never done it before, something like
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -p -u root mysql

2006-06-25 22:39:02+0900

p.d.o, website | 2 Comments »

OpenGL performance and the importance of configuration

Until recently, I wasn't really bothered by the poor OpenGL performance of my laptop. Though it has a Radeon Mobility 9200, the OpenGL "experience" was really bad. But since I was not using GL enabled applications, that was not an issue.

Then, I tried Google Earth and thought "well, it's slow, but it's huge, I don't know, maybe it's normal". A few days later I heard about neverball and gave it a try. It was even slower than Google Earth, and that seemed pretty hard to believe this time.

Thanks to clues from people on #d-d, I figured out I didn't have the libgl1-mesa-dri package installed. Quite simple to know if you are in the same case : first, grep "Direct rendering" in your X.org log file to be sure DRI is enabled on the server side. Then check for "direct rendering" in glxinfo's output to know if it's enabled on the client side. If not, try to apt-get install libgl1-mesa-dri.

Trying neverball again was delightful: the game was playable.

I thought I was done with my OpenGL settings until yesterday, when, for some reason, I read the X.org log and noticed AGP mode was 1x. I didn't know exactly about nowadays, but I was pretty sure 4x was reached at some point, and that the chip in my laptop might support it.

My friend google helped me finding something about "xorg.conf radeon 9200 mobility agp", and gave me hints about three parameters to add to the xorg.conf file that might improve GL performance:

Option "AGPMode" "8"
Option "AGPFastWrite" "on"
Option "EnablePageFlip" "true"

Glxgears is not a benchmark, but still, it helps to make self comparisons. Before: ~260fps. After: ~1350fps. WAW ! Now Google Earth is really fast.

Though I have a strange bug which appears whenever an X window (popup, balloon help, etc.) gets on top of the 3D frame: only the rightmost part appears... on the left. It appears on neverball, on glxgears, on Google Earth, but NOT on foobillard... moving or resizing the window usually fixes the display.

Update: When switching to console and back to X, the glxgear performance gets back to ~260fps...

Update 2: It seems my "before" score is not as bad as claimed. It's actually ~950fps. Still a good improvement, though. The reason why i got ~260fps is that i almost never reboot my laptop nor restart X, and hibernate instead of shutting down the system. Which means I'm in the switched back from console case most of the time.

Update 3: Thanks to Robert Hart for pointing to bug #363995. The patch from there works perfectly \o/. (If you can't wait and want a patched .deb, send me a mail)

2006-06-25 21:37:36+0900

miscellaneous, p.d.o | 2 Comments »

Anti comment spam measures

In the past months, I was getting more and more comment spam. Even though the configuration was set to moderate comments containing a link. It was a good filtering measure at the beginning, but became less and less handleable. When I decided to act, I was getting more than a hundred comment spams in my "Awaiting moderation" list. Per day. Maybe even more, I can't remember. And about the same amount were actually able to go past the moderation filtering, by not putting links in the comment itself, but in the homepage field of the comment form.

While wordpress' comment moderation interface is pretty efficient at deleting a lot of spam, the comment management interface just sucks, even in the "massive editing" mode. So, after having spent quite some time in this sucky interface, I decided I didn't want to resort to it any more.

First I had to remove all these comment spams. I had to use use the SQL delete command myself, since WordPress is useless. I basically deleted all comments posted after the last real one I saw. Sorry if someone posted one I didn't see. The tricky part was that the comment count for articles is kept in a field of the wp_posts table. Which means there was a difference between the actual comment count and the count displayed. For those who'd want to do the same at home, here is the magical SQL query to refresh the comment count:
update wp_posts set comment_count = (select count(*) from wp_comments where comment_post_ID = id and comment_approved = '1');

Next step was to avoid getting more spam. I didn't want to use captchas or any turing tests, because they basically all fail to be accessible in some way. So, I took a balanced decision. While I appreciate to get comments, I can't stand any more the spam that get in posts as old as the blog. The best thing to do then, I think, was to allow comments on recent posts only. Sorry for those who'd like to comment on old stuff, but being able to comment on the newer posts is still better than nothing. I also kept the link moderation policy, which seemed to be helpful at the beginning.

For the little story, again, WordPress was not very helpful, so I had to resort to an SQL query to close comments on all the posts.

It's been 3 weeks or so, now, since I switched to this new policy. I got only 1 spam to moderate and none directly in the comments. Let's hope it will last.

2006-06-25 20:27:18+0900

p.d.o, website | 6 Comments »

Targetted Spam

This morning, I got one of these standard cialis/viagra/xanax/valium/whatever spam you get numerous times in a day, but with a "test xul" subject. Well, that's targetted.

2006-06-05 10:13:23+0900

miscellaneous, p.d.o | Comments Off on Targetted Spam

The Windows way

Imagine an application that writes in its application directory, and if it fails to write there, write in a user profile directory.

Imagine a wide-spread operating system where the default settings allow any user to write almost anywhere on the file system.

Enjoy the result (Comment #7 gives a good overview of the problem).

2006-03-22 16:54:01+0900

firefox | Comments Off on The Windows way

What kind of language is that ?

Consider the following code :


for (var i = 0; i < 20; i++) {
var j = i;
}
alert(i + ' ' + j);

That's javascript. It gives "20 19". Would you expect that from a decent language ?

Update: Same result with a var j = 0; before the for loop. No surprise, actually.

Update 2: It seems what I'm complaining about has not been well received ;). I'm not complaining about the values, I'm complaining about the fact that there are values...

2006-03-11 19:20:42+0900

p.d.o, website | 7 Comments »

More work on xulrunner

Xulrunner finally reached unstable on sunday, and it already needed some adjustments. I forgot a conflict, misnamed the libsmjs-dev package, the hppa assembler code got somehow duplicated, so xulrunner failed to build on hppa, and some preference files needed to be moved around the packages.

It also fails to build on alpha, but that's not my fault.

I also changed the way we identify a Debian built xulrunner in the user agent. I replaced the "Gecko/yyyymmdd" string with "Gecko/Debian/x.y.z.t-r". That has several advantages over the previous "Gecko/yyyymmdd Debian/x.y.z.t-r" string:

  • It shortens the already long user agent string so that additions such as product name are not painful,
  • removes pointless information (the date in the original string indicates the date of the build, not that of the API),
  • keeps the "Gecko" string (which some site might want, seing how Apple and Konqueror did put a "like Gecko" string),
  • and finally avoid confusion with other Debian release informations that may be present in the product specific part (I think Galeon puts one, for instance).

That needed 2 updates, because I realized in between that while you can set the general.useragent.product and general.usergagent.productSub variables, they are not actually taken into account until you change them a first time... The HTTP protocol initialization in xulrunner forces the respective values Gecko and yyyymmdd... I just completely removed that part of the code in xulrunner.

I took advantage of this needed fix to work even more on the package, enabling the typeaheadfind module, needed by galeon and epiphany, removing some old perl code that does nothing except producing useless errors during the build, and, last but not the least, enabling the "flat style" chrome, meaning that instead of being stuck in .jar files, everything is just here in a standard tree.

It appears upstream provides a way to build such trees (option --enable-chrome-format=flat to configure), but it's useless because it doesn't install the trees when running make install. In addition to that, the configure script still requires zip, even if it doesn't use it, except for some obscure .jar files in libnss, that are not installed either. So after disabling the build of these useless files and removing the zip strict requirement if we build flat chrome, and fixing the script responsible for installation of the chrome files, everything got much better.

These changes have been applied to firefox as well, so stay tuned, it's for next upload.

Having highjacked spidermonkey, I did some bug triage there as well. It appeared they could all be closed by the fact libmozjs0d is there. I still need to make some triage in my patches to xulrunner and send upstream those that I still have not sent, if they are of any interest there.

Apart from this xulrunner stuff, I also did some bug clean-up on libxml2 and libxslt, which I've been somehow neglecting for some time.

2006-02-22 21:06:21+0900

p.d.o, xulrunner | 6 Comments »