Dec 10, 2010

Automatic squashing of last git commits

I have written before about my workflow in Fedora. This workflow includes a relatively high number of rebasing where I squash last two commits into one. I use it to quickly refine and test patches. My history then usually looks something like this:
$ git log --format=oneline --decorate=no | head -3
2db8eacd7f7c20be88824caae5f5af16b9520d34 temp
443bb0f019c87f0090bb9da295a019c0eee23729 Add conditional BRs to enable ff merge between f14
b4c602f9f044598544cff3d68710f68b9447ea0f Fix installation of pom files for artifact jars
  
Where 443bb0f is my first attempt at the fix and 2db8eac is a fixed fix :-). Before pushing this into upstream repository I usually squash last two commits to look like this:
$ git log --format=oneline --decorate=no | head -2
f852c3e260d21bbc642f861e6fa6ea62caa7b69b Add conditional BRs to enable ff merge between f14
b4c602f9f044598544cff3d68710f68b9447ea0f Fix installation of pom files for artifact jars
  
I used to do it manually, but I do it often enough it made sense to automate this. So without further ado:
#!/bin/sh

export EDITOR="sed -i '2s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'"

git rebase -i HEAD~2
Save this somewhere inside your $PATH and chmod +x (or set up shell alias). Then just running this will automatically squash last two commits, using HEAD~1 commit message and discarding last commit message. No warranties though :-)

Edit: Benjamin suggested to use "fixup" instead of "squash". This is new thing in git 1.7+. For more information on this see this blogpost.

Share/Save/Bookmark
Nov 30, 2010

Fedora has Freemind

During past few months I have been reviewing packages for Fedora with approximate speed of 1.53 package per week :-)

Most of packages I reviewed were libraries and other things that are not so interesting to users. But one of last packages I reviewed is different. It is one of the best mind-mapping software in existence :-) Yes, it's Freemind. If you've never tried mind-mapping before, let me quote first paragraph from wikipedia:
A mind map is a diagram used to represent words, ideas, tasks, or other items linked to and arranged around a central key word or idea. Mind maps are used to generate, visualize, structure, and classify ideas, and as an aid to studying and organizing information, solving problems, making decisions, and writing.
So what are you waiting for? Try it out!

There were attempts to package Freemind before, but all would-be maintainers gave up when they noticed how many dependencies are needed and how Java packaging actually works (I don't really blame them). So everyone please. Let's. Have. A. Staaaaanding. Ovaaation. Fooor. Johannes Lips. He made it! If you live close by, buy him a beer will you? :-)

Share/Save/Bookmark
Nov 11, 2010
I recently encountered weird problems with my network connection at home. Everything worked, but was unbelievably slooooow. Ping showed times of ~30 ms, but I could easily see it took more time for those packets to go there and back.

I took me some time to figure out what was happening. Looking back, checking DNS server should have been one of the first things to do. Seems like first DNS server provided by my provider has been down. That meant that every DNS query timed out and then went to the second DNS which got me my response. For some reason ping did DNS query before every new package being sent. That explains its weird behaviour.

This problem got me to finally install local caching dns. I was thinking about doing it before, but I never got around to do it until now. I always thought it's gonna be a few-hour nightmare. Now I blame my previous experience with bind :-D For simple local caching bind would be overkill, so I chose dnsmasq. Using it was as simple as installing, running dnsmasq and executing
$ echo 'nameserver 127.0.0.1' > /etc/resolv.conf.head

From that point on every resolv.conf file generated by dhcpcd will have my local DNS as first DNS server to try. For this time you can add it there manually. Then you can verify your setup works by running following command twice in a row:
$ dig randomserver.com
First execution should have Query time: XX msec with XX being few tens of miliseconds. Query time for second run should be zero or very close to zero.

Congratulations. You have your very own caching server. Who knows...maybe you'll even notice some improvements in your network connection :-)

Share/Save/Bookmark
Nov 10, 2010

PyQTrailer revisited

Some time ago, I wrote about my little project: apple.com trailer downloader. Apple is still not very open-source friendly as far as its trailer website is concerned. So all points I made in my original post still stand. To my surprise this little project is still alive and kicking, with new ideas for improvements coming and coming :-). What is even more important: it seems that so far no breakage happened due to apple changing something on the web.

Since the first version I released almost 6 months ago several new features appeared. Some of them include:
  • Parallel downloading of trailers
  • Ability to run movie player (mplayer, vlc, etc) without downloading file to HDD
  • Lot of customisation/performance options added
  • Working support for trailer search
  • Localisation support
  • Python 3 support
Latest version (0.5.2) is available in Gentoo repositories already, and should hit Fedora updates in next day or so (this will be delayed due to new package acceptance criteria though). Enjoy.

Share/Save/Bookmark
Oct 20, 2010
As I was recently adding support for Python 3 to my little trailer downloader application that I mentioned before (PyQTrailer) I encountered a strange problem with PyQt4 that only occurred in Python 3.

Let's take this simple python example:
$ python
>>> from PyQt4.QtCore import QString
>>>
That same code snippet doesn't work in python3 interpreter though:
$ python3
>>> from PyQt4.QtCore import QString
Traceback (most recent call last):
  File "", line 1, in 
ImportError: cannot import name QString
>>>
My first instinct was: Bug! Gentoo PyQt4 ebuild was doing something terrible and somehow made PyQt4 unusable in python3 interpreter. Turns out my gut instinct was wrong (once again :-) ).

PyQt4 since version 4.6 changed API of QString and QVariant for python 3.x. For QString this is due to fact that from Python 3.0, string literals are unicode objects (no need for u'unicode' magic anymore). This means that you can use ordinary Python strings in place for QString. But I wanted my QString for something like this:
  ...
  downloadClicked = pyqtSignal((QString, ))
  ...
This snippet creates Qt signals that you can then emit. Question is... How can we update this for Python 3.x? We could probably just replace QString with type(""), but for a change that wouldn't work with Python 2.x. So? Python dynamic nature to the rescue!
Edit: simplified QString definition (thanks Arfrever)
try:
    from PyQt4.QtCore import QString
except ImportError:
    # we are using Python3 so QString is not defined
    QString = str
If we put previous code sample to the beginning of our Python file we can use QString in our code and it will keep working both in Python 3.x and Python 2.x. Case closed dear Watson.

Share/Save/Bookmark

Fedora RPG - Three level badge system?

I stumbled upon one great idea on Fedora Planet. It is nothing other than Fedora RPG!

In short, it's a system to create characters similar as they are in Role-playing games (RPGs) with levels, skill points and more.

You might think it doesn't make sense to give contributors "points" for non-gaming activities but you would be wrong. Most communities have created ways to reward their members this way. Look no further than my favourite stackoverflow.com. It also uses badge and skill point system for various actions on the website. In one of earliest blog posts about how stackoverflow will work, Jeff Atwood shared his vision: three levels of badges (bronze, silver, gold). Each level with unique badges tailored to the purpose of stackoverflow.

I guess Fedora RPG will go a bit further in this regard. I would love to know how it will all turn out and how the levels will work. Let the games begin!


Share/Save/Bookmark
Oct 15, 2010
Big part of my job is packaging for Fedora Linux (I am pretty sure I haven't mentioned this before :-) ). I have spent last 6 months working on various Java packages, adding new packages to Fedora, updating dependencies etc. I have developed certain workflow which I believe might be of interest to other packagers. So here goes. Most of these hints are about managing patches for your packages. I'll also try to work on concrete package so it won't be completely theoretical.

Let's assume your project already has some history and patches. Let's fix velocity bug 640660 for example. I'll start with steps I took and what they meant, and I'll summarize in the end with rationale what I have gained by using my workflow (and what could be improved).

After modifying BuildRequires and Requires to tomcat6 servlet api I tried to build velocity:
$ fedpkg mock
This is what I got:
---snip----
compile-test:
    [javac] Compiling 125 source files to /builddir/build/BUILD/velocity-1.6.3/bin/test-classes
    [javac] /builddir/build/BUILD/velocity-1.6.3/bin/test-src/org/apache/velocity/test/VelocityServletTestCase.java:135: org.apache.velocity.test.VelocityServletTestCase.MockServletContext is not abstract and does not override abstract method getContextPath() in javax.servlet.ServletContext
    [javac]     static class MockServletContext implements ServletContext
    [javac]            ^
    [javac] Note: /builddir/build/BUILD/velocity-1.6.3/bin/test-src/org/apache/velocity/test/VelocityServletTestCase.java uses or overrides a deprecated API.
    [javac] Note: Recompile with -Xlint:deprecation for details.
    [javac] Note: Some input files use unchecked or unsafe operations.
    [javac] Note: Recompile with -Xlint:unchecked for details.
    [javac] 1 error
BUILD FAILED
/builddir/build/BUILD/velocity-1.6.3/build/build.xml:251: Compile failed; see the compiler error output for details.
Total time: 47 seconds
---snip---
The issue seems simple to fix, just missing stub function in a test case, right? So what now?
$ fedpkg prep
$ mv velocity-1.6.3 velocity-1.6.3.git
$ cd velocity-1.6.3.git
$ git init && git add . && git commit -m 'init'
This effectively created my small git repository for sources and populated it with all files. Using fedpkg prep step we extracted the tarball and applied already existing patches to unpacked sources. I suggest you create shell alias for last three commands as you'll be using it a lot. We moved directory to velocity-1.6.3.git so that next (accidental?) fedpkg prep won't erase our complicated changes (yes it happened to me once. I've had better days). Note that velocity-1.6.3.git is not a temporary directory. I will keep it around after fixing this bug so that I can use git history, diffs and other features in the future. It is especially nice when you have packages with lot of patches on top.

Now we can easily work in our new git repository, edit source file in question and do:
$ git add src/test/org/apache/velocity/test/VelocityServletTestCase.java
$ git commit -m 'Fix test for servlet api 2.5'
$ git format-patch HEAD~1
This created commit with descriptive message and generated a patch file 0001-Fix-test-for-servlet-api-2.5.patch in our current directory. This is how the patch looks like:
From 8758e3c83411ffadc084d241217fc25f1fd31f42 Mon Sep 17 00:00:00 2001
From: Stanislav Ochotnicky <sochotnicky@redhat.com>
Date: Thu, 14 Oct 2010 10:20:52 +0200
Subject: [PATCH] Fix test for servlet api 2.5

---
 .../velocity/test/VelocityServletTestCase.java     |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/src/test/org/apache/velocity/test/VelocityServletTestCase.java b/src/test/org/apache/velocity/test/VelocityServletTestCase.java
index 824583e..ac0ab5c 100644
--- a/src/test/org/apache/velocity/test/VelocityServletTestCase.java
+++ b/src/test/org/apache/velocity/test/VelocityServletTestCase.java
@@ -16,7 +16,7 @@ package org.apache.velocity.test;
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
- * under the License.    
+ * under the License.
  */
 
 import java.io.IOException;
@@ -149,6 +149,11 @@ public class VelocityServletTestCase extends TestCase
             return this;
         }
 
+        public String getContextPath()
+        {
+            return "";
+        }
+
         public String getServletContextName()
         {
             return "VelocityTestContext";
-- 
1.7.2.3

Now that we have patch prepared for velocity we need to use it in the spec file and we're done.

Let's say our first attempted patch wouldn't work as expected and build (or test) still failed. We modify the sources again and do another commit. What we have now is:
$ git log --format=oneline
c15f7e02eaae93b755cc0bfde6def3d6e67d2b0f (HEAD, master) Fix previous commit
3e3d654c142c7028c9c7895579fba204c4c4bf08 Fix test for servlet api 2.5
2f32554ddf892f4cca3f78b1f82a7c3ab169c357 init

We don't want two patches in the spec file for one fix so: time for git magic. You've probably heard of git rebase if you've been using git for a while. What we want to do now is merge last two commits into one, or in git-speak "squash" them. To do this you have to do:
$ git rebase -i HEAD~2
Now your editor should pop-up with this text:
pick 3e3d654 Fix test for servlet api 2.5
pick c15f7e0 Fix previous commit

# Rebase 2f32554..c15f7e0 onto 2f32554
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

So we just need to change "pick c15f7e0 Fix previous commit" into "squash c15f7e0 Fix previous commit" (you can also use just 's' instead of 'squash'). Save. Close. Another editor window will open with something like this:
# This is a combination of 2 commits.
# The first commit's message is:

Fix test for servlet api 2.5

# This is the 2nd commit message:

Fix previous commit

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

For this case we will delete second message because we just want to pretend our first attempt was perfect :-). Save. Close. Now we have:
$ git log --format=oneline
cbabb6ac43f7bdb8e52ccd09c25cfd0a032b553c (HEAD, master) Fix test for servlet api 2.5
2f32554ddf892f4cca3f78b1f82a7c3ab169c357 init

Repeat as many times as you want. You can also re-order commits and change commit messages with rebase (note that if you just want to change last commit message you can do "git commit --amend"). I generally don't create commits until I have working patch though.

So why do I think all this mumbo-jumbo improves my workflow? Let's see:
  • I can have long comments for every patch I create (instead a line or two in spec file)
  • I can use the same patches to send directly to upstream
  • I don't have to juggle around with diff and remember what files I changed where
  • Probably several other things I haven't even realized
I have a few things that bother me of course. git format-patch generates filenames that are different from standard practice of %{name}-%{version}-message.patch. This is not a git problem. For packages where only my patches exist I stick with git naming, but when there are different patches I stick with naming they started. Another thing that is bothering me is that creating initial repository by using "fedpkg prep" hides patches that were applied to sources. That's why I am thinking about re-working my packages so that all patches will be in my git repositories as commits with descriptive messages. No need for comments in the spec file anymore. Perhaps someone can suggest other improvements to my approach.

Share/Save/Bookmark
Aug 28, 2010
I have been using Digikam for managing my photos for some time. It's pretty neat software and development is progressing quite fast. You can think of it as Lightroom, just without the neat non-destructive editing. But that is coming too, thanks to Google and another round of Summer of Code participants. But I wouldn't be writing this blog post if Digikam was flawless would I? :-)

First I'll describe my work-flow in few short bullet-points :-)
  • Shoot a LOT of photos
  • Delete almost as many photos
  • Geotag, tag/keyword and rate remaining photos
  • If it was party or something similar upload to Facebook right away
  • Pick few photos and improve them a bit with Gimp (nothing fancy, just crop/levels)
  • Upload all photos to Flickr as a backup/sharing place
Digikam enables me to work like this, except the last point. Why? Because apparently Digikam developers don't think anyone would update their photos to Flickr without first resizing/recompressing them. This  how flickr export dialog looks like this:


See the problem? Even if I don't chose "Resize photos before uploading" Digikam will still re-compress them which is a Really-Bad-Thing(tm) to do with jpeg files. I had some previous experience with Qt3 and even Qt4. so I though it might be a good idea to look into fixing this small annoyance. I will not bore you with the details how I checked out svn repository with git and rest of the stuff. Here is the result:


If you un-check "Send original file (no resizing)" original settings will appear and you can resize/recompress as much as you want (Blasphemy! Madness!). The patch is not flawless, because it won't prevent you from trying to upload RAW files to Flickr, but it's good enough for me :-) It's not even that big, stats are like this:

 flickrexport/flickrtalker.cpp |   18 ++++++++++++------
 flickrexport/flickrtalker.h   |    2 +-
 flickrexport/flickrwidget.cpp |   34 ++++++++++++++++++++++++++--------
 flickrexport/flickrwidget.h   |    5 +++++
 flickrexport/flickrwindow.cpp |    4 ++++
 flickrexport/flickrwindow.h   |    1 +
 6 files changed, 49 insertions(+), 15 deletions(-)

You can download the patch from my Dropbox for now until the bugreport I created some time ago will get sorted out (don't hold your breath too much though). The patch applies cleanly across all versions of kipi-plugins I tried (from 0.8.something to 1.4.0). Happy uploading.



Share/Save/Bookmark
May 10, 2010
I love films. All of them to be exact. I believe you just have to be in the right mood and you would enjoy even few of the worst movies ever made. Even though I am a proponent of open source philosophy, we as a society are obviously not ready to embrace it in entertainment industry just yet.

This is where www.apple.com/trailers comes into play. Apple made great deals with movie studios and you can watch/download newest movie trailers. Well...sort of. Apple employs variety of restrictions which makes this site next to useless on a Linux desktop. It hides links to trailers themselves behind reference files so that when you download with your favorite browser, you will only get small reference file not the trailer itself. And that is after you circumvent user-agent protection. Because apple believes nothing but iTunes/iPad/iOtherAppleStuff should access these trailers. There are scripts around that can make downloading possible for Linux users. I have been using Apple Trailer Download script for Greasemonkey for quite some time, but it always stopped working after some time.

Another opportunity for me I guess. I have been trying to improve my Python-fu for some time so what better way then a small project like this? I started last weekend after I found out Apple actually publishes JSON data of trailers on its site. This made access quite easy from python and is quite error-prone to changes of website itself (as long as Apple doesn't pull whole JSON thingy...but they are actively using it too). Long story short...there are two outputs from this endeavor:
  • pytrailer - python module to simplify access to movies on apple.com/trailers
  • pyqtrailer - Qt4 interface that displays poster, movie information and enables downloading of trailers
You can report bugs on respective websites (there are quite a few now, but basic downloading for hd trailers works). If you want to try it out just running:
# easy_install pyqtrailer
should work as long as you have PyQt4 installed. You can just run pyqtrailer now and you should see something like this:


That's it. I will improve/fix it a bit but don't expect too much :-)

Share/Save/Bookmark
Mar 27, 2010
What better way to celebrate summer solstice, than by making my computer able to hibernate? Since my last post a lot has happened with me. I got a new phone (HTC Hero FTW!), I finished university, went traveling a bit and I also got a new notebook (because the old one died on me). R.I.P. Thinkpad R51, welcome Thinkpad T500. There are several things I could start writing about now. Starting with how great Hero and Android is to use all the way to today's blog post: How to make my computer hibernate?

Linux has had support for hibernating for quite a few years now and although it's not perfect, it usually works out of the box. What it needs however is swap device big enough so that it can store image of memory for hibernating. Now I hit a problem. When I got my new Thinkpad I thought "Hey, I have 4GB of RAM...why would I need a swap?". And even if I REALLY needed more than 4GB RAM I can still create temporary swap by using swapfile. Unfortunately I couldn't make swapfile on LVM work with TuxOnIce. TuxOnIce also has another alternative to swap or swapfile for hibernating: Using filewriter, which is quite similar to swapfile support, I managed to get it to work (after some work, kernel debugging and one small patch to TuxOnIce).

I set FilewriterLocation in hibernate.conf to point to a place where I wanted to store hibernation file and I set the size to 4GB. As instructed in TuxOnIce HOWTO, I then ran
hibernate --no-suspend
to create this image. It created the file as expected, but when it was supposed to tell me settings for bootloader (resume argument) it silently failed. When I tried again, whole computer froze. I was puzzled. How could this happen? I am using Linux so things like this don't happen! But hey, I should be able to figure out what's wrong with it right? I set up my kernel to include netconsole, and ran hibernate again. This time I caught where the bug happened. The output was something like this:

TuxOnIce: No image found.
BUG: unable to handle kernel paging request at 6539207a
IP: [<c10763a6>] toi_attr_store+0x186/0x2a0
*pdpt = 0000000032732001 *pde = 0000000000000000
Oops: 0000 [#1] PREEMPT SMP
last sysfs file: /sys/power/tuxonice/file/target
Modules linked in: netconsole aes_i586 aes_generic radeon ttm drm_kms_helper drm
i2c_algo_bit sco bnep ipt_MASQUERADE iptable_nat nf_nat ipt_LOG nf_conntrack_ip
v4 nf_defrag_ipv4 xt_state nf_conntrack ipt_REJECT xt_tcpudp iptable_filter ip_t
ables x_tables rfcomm l2cap vboxnetadp vboxnetflt vboxdrv arc4 iwlagn iwlcore ma
c80211 sdhci_pci snd_hda_codec_conexant sdhci pcmcia e1000e uvcvideo mmc_core cf
g80211 snd_hda_intel yenta_socket btusb rsrc_nonstatic tpm_tis pcspkr pcmcia_cor
e videodev v4l1_compat intel_agp wmi agpgart tpm snd_hda_codec tpm_bios video fu
se xfs raid10 raid1 raid0 md_mod scsi_wait_scan sbp2 ohci1394 ieee1394 usbhid uh
ci_hcd usb_storage ehci_hcd usbcore sr_mod sg uvesafb cfbfillrect cfbimgblt cn c
fbcopyarea [last unloaded: microcode]

Pid: 12870, comm: hibernate Not tainted 2.6.33.1-w0rm #16 2082BRG/2082BRG
EIP: 0060:[<c10763a6>] EFLAGS: 00010202 CPU: 0
EIP is at toi_attr_store+0x186/0x2a0
EAX: 00000000 EBX: 36203430 ECX: 00000000 EDX: f231f200
ESI: 65392066 EDI: 00f60062 EBP: f6006331 ESP: f62a7f14
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process hibernate (pid: 12870, ti=f62a6000 task=f20a0270 task.ti=f62a6000)
Stack:
00000000 fffffff4 00000001 c1790ca0 00000000 f6e8ab64 c16c75a4 f6d1c380
<0> f62a7f64 c114298d 00000015 00000015 b7709000 f21385c0 f6d1c394 c16c75a4
<0> f6ec7ac0 f21385c0 b7709000 00000015 f62a7f8c c10f207c f62a7f98 00000000
Call Trace:
[<c114298d>] ? sysfs_write_file+0x9d/0x100
[<c10f207c>] ? vfs_write+0x9c/0x180
[<c11428f0>] ? sysfs_write_file+0x0/0x100
[<c10f221d>] ? sys_write+0x3d/0x70
[<c1002ccc>] ? sysenter_do_call+0x12/0x22
Code: c7 45 e0 00 00 00 00 3b 5d 08 0f 85 e9 fe ff ff 8b 46 20 85 c0 0f 84 de fe
ff ff ff d0 8b 7d e0 85 ff 8d 76 00 0f 84 d9 fe ff ff <8b> 46 14 31 d2 e8 60 03
05 00 8b 46 10 c7 46 14 00 00 00 00 a8
EIP: [<c10763a6>] toi_attr_store+0x186/0x2a0 SS:ESP 0068:f62a7f14
CR2: 000000006539207a
---[ end trace 124a5ee29ef71277 ]---

So what can we deduce from this bug output? Let's go from the top. Bug name (unable to handle kernel paging request) means that it is likely a memory corruption issue. Someone accessed memory that he was not supposed to. IP tells us that function where the error occurred was toi_attr_store in unknown file, unknown line (I don't have debug information included in kernel). There are other information we can get from that output, but I didn't really need them. Quick search through kernel sources told me that toi_attr_store is a function inside kernel/power/tuxonice_sysfs.c. I scanned the code, learning what approximately it did. Then I placed printk statements thorough the function so that I could approximate where inside the function the code fails. After some time I narrowed it down to following snippet:

if (!result)
result = count;

/* Side effect routine? */
if (result == count && sysfs_data->write_side_effect)
sysfs_data->write_side_effect();

/* Free temporary buffers */
if (assigned_temp_buffer) {
toi_free_page(31,
(unsigned long) sysfs_data->data.string.variable);
sysfs_data->data.string.variable = NULL;
}


Kernel crashed when it tried to call toi_free_page. After a few reboots and printks later I found out that this was just a coincidence, and sysfs_data variable itself became corrupt even before the call to the toi_free_page. Good candidate? Of course: write_side_effect. But what exactly was write_side_effect? This function was passed as an argument, and therefore I wasn't able to easily find out what was real code executed at this point. Time to find out! From my previous debugging attempts I knew code failed while it tried to write location of my resume file into /sys/power/tuxonince/file/target. TuxOnIce code defined handling for string sysfs arguments as such:

#define SYSFS_STRING(_name, _mode, _string, _max_len, _flags, _wse) { \
.attr = {.name = _name , .mode = _mode }, \
.type = TOI_SYSFS_DATA_STRING, \
.flags = _flags, \
.data = { .string = { .variable = _string, .max_length = _max_len } }, \
.write_side_effect = _wse }


I found this macro used inside tuxonice_file.c source code like this:
 
SYSFS_STRING("target", SYSFS_RW, toi_file_target, 256,
SYSFS_NEEDS_SM_FOR_WRITE, test_toi_file_target)


So we found our write_side_effect code inside test_toi_file_target function. In one part this function was calling hex_dump_to_buffer to convert device UUID into hexadecimal string. The call looked like this:
 
hex_dump_to_buffer(fs_info->uuid, 16, 32, 1, buf, 50, 0);


This should convert input (fs_info->uuid) into hexadecimal string and store it inside buf. Author of the original code correctly thought about function adding spaces between bytes and therefore need to have more space in the buffer (argument 50 is telling hex_dump_to_buffer how big is output buffer). Unfortunately that same author declared buf as 33 char array. hex_dump_to_buffer therefore stepped outside the buffer and corrupted memory, causing all the problems. I fixed this bug, and sent a patch to the tuxonice-devel mailing list. As of now, it is already in the git repository ready to be released with next bugfix release of TuxOnIce.

That is everything for today, but as I already noted I am using LVM on my system (except root partition) and also use fbsplash for nice animations while rebooting. I am using initrd for this, and I will have another post on that topic.

Share/Save/Bookmark