Skip to main content

a silhouette of a person's head and shoulders, used as a default avatar

How developers see openSUSE

You probably know that a lot of openSUSE developers are sitting in the SUSE office in Prague, Czech Republic. They are also openSUSE users.

The whole story started by a flame on a mailing list why some of us are not happy with the current state of openSUSE. It turned out there is a lot of different issues. So, we’ve met on a raining winter Friday 3 weeks ago to collect those issues as well as things that people consider to be good about openSUSE.

The result of the hours-long discussion is a list of positive and negative things about openSUSE, very subjective view of the group of developers in Prague. Go, look at the list. There is a lot of problems that I personally see lurking in our community, spelled out loud. The range is wide, from basic community issues to very technical problems that are basically missing features in the distribution.

So, we have collected the feedback. But the question is, what to do with it?

Firstly, I believe the lists are great food for thought. You might not agree with everything, but still, there is some truth in it. At least, those are problems that people consider important enough to try to solve them – encouraging.

Secondly, consider this blog as call for contribution. If you believe some of the areas are really worth improving, get in touch with people listed on the wiki, improve the description  in the wiki, propose solutions. One restriction though – please, do not add additional items to the page. We want to keep the ideas where they belong – features eventually to end up in openFate, project-related problems on the mailing lists, …Also, this is not a general list of issues the openSUSE project needs to address. As I’ve written above – the page is a subjective view of a group of people. If you think we need a more general approach, please, bring the idea on openSUSE mailing lists.

Looking forward to your feedback!

a silhouette of a person's head and shoulders, used as a default avatar

Overloading library function

Sometimes during testing (especially while testing maintenance update), I come to a problem how to test the reaction of the program to an unusual function return value (e.g. special error), data, etc. The problem is, that I need to test the unmodified program binary and that it is almost impossible to set up a situation when the error "naturally" occurs.

If the function is in a shared library, there is a simple way to force the program to use another function instead of the one from the library. The program will call the new function, which will return the specific value (unusual error I need to test).

The magic "tool" is LD_PRELOAD variable. When the program is loaded to memory, libraries specified in LD_PRELOAD are loaded before libraries needed by the program. If I have function strdup() in my custom library (loaded by LD_PRELOAD), it will be used instead of strdup() from standard C library.

So for (very simplified) example, let's say I need to test program prog correctly checks whether strdup() returns NULL (I assume that prog segfaults on NULL access): I'll write simple library libexploit which will only contains my new strdup().

exploit.c:

char *strdup(const char *s)
{
      return NULL;
}

Makefile:

all: libexploit.so.1.0

clean:
      rm -f libexploit.so.1.0 *.o

libexploit.so.1.0: exploit.o
      gcc -shared -Wl,-soname,libexploit.so.1 -o libexploit.so.1.0 exploit.o

exploit.o: exploit.c
      gcc -Wall -fPIC -c exploit.c

Now when I make the simple library, I'll get result libexploit.so.1.0 which I'll preload to the program:

LD_PRELOAD="`pwd`/libexploit.so.1.0" prog

And it is all - the program got NULL from all calls to strdup().

Simple, right? There is one catch, however. Or two.

First problem is that the original function is replaced by the new one, so you cannot call the original one (not even from your "new" function).

Second problem is that even the original library will start using your function. So if the library is using the overloaded function, it uses the new one. This may result in unexpected library behavior.

Both these problems are not (AFAIK) solvable in a easy way. The only way I've found out so far is the re-factoring of the original library in following steps:

  1. Rename the original function - e.g. from strdup() to __strdup().
  2. Replace all calls of function strdup() with calls of function __strdup() in the library source - this will ensure that the library code will always call the correct function.
  3. Create new function strdup() which will contain the testing code (and can also call the original __strdup() function).
  4. Compile the library and load it with LD_PRELOAD as described above.

Now, that's finally all.

(This text has also been published on openSUSE wiki)

a silhouette of a person's head and shoulders, used as a default avatar

MonoDevelop 2.0 beta 1

Yet another step towards 2.0 release. We released Beta 1 last week with many fixes and some new interesting features (here are the release notes).

The one I like more is the support for per-project policies. This feature has been planned for long time but other work has been delaying it. Me and Michael Hutchinson had a chance to talk quite a lot about it while I was at Boston a couple of months ago. The policies model allows setting properties at global, solution, folder and project levels. Settings such as tab width can be defined in any of those levels and will cascade down to the lower levels (where it can be overriden if required). Many settings are already available in this way, and many more will be in future releases.



Another new feature, or rather improvement, is the support for multiple frameworks. MD already had support for targeting the 1.1/2.0 CLR for quite a long time, but did not have the concept of 'target framework', which is more generic. For example, .NET 3.0 is based on the 2.0 CLR and it just includes some additional assemblies. What complicates things a bit is that Mono does not follow the .NET releases, so for example Mono 2.0 includes bits from all .NET versions. To simplify all this and to be compatible with MSBuild, it is now possible to select the target .NET framework, which includes 1.1, 2.0, 2.1 (Silverlight), 3.0 and 3.5. The project system is fully aware of the chosen target framework, so for example it won't let you reference a 3.5 project from a 3.0 project.

The source editor keeps improving in many ways. Mike Krueger has spent quite a lot of time fixing issues in code completion, which now works in many more contexts. My contribution on code completion (besides stabilization work in the parser database) is support for completion of generic types with constraints. For example, in the following class code completion is showing the Dispose method because there is a constraint forcing the generic argument to implement it:



There are other improvements, such as the new Go to File dialog I blogged about some time ago, better support for completion in ASP.NET projects, and fixes in the GTK# designer. There is still a lot of work to do, but we are getting close to 2.0.
a silhouette of a person's head and shoulders, used as a default avatar

Object Oriented UI for YaST

Hello!

After my last blog I worked on YaST (what a surprise) and didn't have any time to post anything until now.
Meanwhile I read some chapters from the "Thinking in Java" book. There are some chapters about OOP in general and it brings me to idea, how it would be great in YaST. As a side effect it also means get away from ycp ;-). Thanks to UI independence I can use Python with the YaST UI.

Here's some code example:

widget_library.py:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import yui

class MainDialog:
def __init__(self):
self.factory = yui.YUI.widgetFactory()
self.dialog = self.factory.createMainDialog()
def __del__(self):
self.dialog.destroy()

class Popup:
def __init__(self):
self.factory = yui.YUI.widgetFactory()
self.dialog = self.factory.createPopupDialog()
def __del__(self):
self.dialog.destroy()


class TableDialog:
def __init__(self, d):
self.f = d.factory
vbox1 =self.f.createVBox( d.dialog )
self.f.createVStretch(vbox1)
hbox1 =self.f.createHBox( vbox1 )
self.f.createHStretch(hbox1)
self.f.createHSpacing(hbox1,1)
vbox2 =self.f.createVBox( hbox1 )

self.Table( vbox2 )

vspace =self.f.createVSpacing(vbox1,2)
self.f.createHSpacing(hbox1,1)
self.f.createHStretch(hbox1)
self.f.createVStretch(vbox1)

etype=-1
while etype!=5:
event = d.dialog.waitForEvent()
etype = event.eventType()
self.HandleEvent( event )
print etype

def Table(self,parent):
vbox3 =self.f.createVBox( parent )
self.customWidget(vbox3)
theader = yui.YTableHeader()
theader.addColumn("Targets")
self.table =self.f.createTable( vbox3, theader )
hbox2 =self.f.createHBox( vbox3 )
self.pbAdd =self.f.createPushButton( hbox2, "&Add" )
self.pbEdit =self.f.createPushButton( hbox2, "&Edit" )
self.pbDel =self.f.createPushButton( hbox2, "&Delete")
self.enableDisableButtons()

def customWidget(self,parent):
pass

def HandleEvent(self,event):
if (event.widget()==self.pbAdd):
self.handleAdd(event)
elif (event.widget()==self.pbEdit):
self.handleEdit(event)
elif (event.widget()==self.pbDel):
self.handleDel(event)
self.enableDisableButtons()

def enableDisableButtons(self):
self.pbEdit.setEnabled(self.table.itemsCount()>0)
self.pbDel.setEnabled(self.table.itemsCount()>0)


main.py:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import yui
from widget_library import *

class TargetDialog(TableDialog):
def __init__(self,d):
TableDialog.__init__(self,d)

def customWidget(self,parent):
hbox =self.f.createHBox( parent )
self.f.createInputField(hbox, "Target")
self.f.createInputField(hbox, "Identifier")

def handleAdd(self, event):
print "add target item"
def handleEdit(self,event):
print "edit target item ..."
def handleDel(self,event):
print "delete target item ..."

class MyTable(TableDialog):
def __init__(self,d):
TableDialog.__init__(self,d)

def handleAdd(self,event):
print "adding ..."
TargetDialog(Popup())

def handleEdit(self,event):
print "edit item ..."
def handleDel(self,event):
print "delete item ..."

if __name__== "__main__":
td = TargetDialog(MainDialog())



I know that code is not nice and not very useful, but here's some nice OOP examples:
inheritance, composition, etc ...

Easily put into constructor, what kind of dialog I want:
TableDialog(MainDialog()) or TargetDialog(Popup())

Inherit some class and override methods you want (see MyTable.handle*())
This is much better than generate file from template (as we do now).

I like this way and I'll keep working on it during my ITO.

Bye,
Michal
a silhouette of a person's head and shoulders, used as a default avatar
the avatar of Sandy Armstrong

Tomboy 0.13.5 Brings a Better Windows Installation Experience

Today I released Tomboy 0.13.5. It has a bunch of nice fixes, including updates to Benjamin Podszun's Gtk.Print rewrite of Tomboy's printing add-in (making printing available on all platforms). For Windows users, this is the first time that you should be able to easily install gtk-sharp and Tomboy without having to muck around with your system. But we wouldn't want it to be too easy, so there are some caveats.

From http://live.gnome.org/Tomboy/Installing/Windows :

Instructions for installing a Tomboy Windows release

Upgrading from Tomboy 0.13.4 or earlier
  1. Uninstall Tomboy.
  2. Uninstall any existing versions of gtk-sharp you may have installed.
  3. Continue with Installation instructions.
Installation
  1. Install Novell's gtk-sharp 2.12.8 or newer.
  2. Restart.
  3. Run Tomboy installer 0.13.5 or newer.
  4. Enjoy!
Importing notes from Linux (optional)
  1. On your Linux box, copy all of the *.note files out of ~/.tomboy .
  2. On your Windows box, quit Tomboy.
  3. On your Windows box, copy all the *.note files from Linux into %APPDATA%\tomboy .
Please please please don't hesitate to file bugs for any problems you experience.

Thanks so much to Mike Kestner for working his ass off (on his own time) updating the gtk-sharp installers, making them easier to develop and build, and fixing the issues reported by Tomboy users. Apps like Tomboy, Banshee, and GNOME Do would simply not exist without all of his hard work.

the avatar of Matthias Hopf

More r6xx mysteries

I have used up half of my weekend to understand an issue with r6xx chips - when sending two draw commands on my laptop, I got system freezes, DRM oopses, and kernel panics - though the code was actually pretty simple.

It really took a long night (and approx. a hundred reboots) to find this:


When you want to
  • change VGT_INDX_OFFSET / VGT_MIN_VTX_INDX / VGT_MAX_VTX_INDX or
  • switch to a different shader
you have to re-set the Render target (CB_COLORx_BASE / CB_COLORx_SIZE / CB_COLORx_VIEW / CB_COLORx_INFO / CB_COLORx_TILE / CB_COLORx_FRAG / CB_COLORx_MASK, to be verified which actually influence anything), either before or after setting the registers for VGT or shaders.


Today in the office I found out that this is only necessary on my laptop's M72, on RV610, on RV630, and on RV635 - but not on RV670 or RV770. So this is chipset specific, but not VC releated...

What - as I assume - happens is that only a write to the render target registers stalls writing to the VGT and shader registers, so this seems to be some kind of flaw in the pipelining logic on some of the chips. As setting the render target again doesn't have a too big performance impact, I assume it's best to do it regardless of the chipset.
a silhouette of a person's head and shoulders, used as a default avatar

Latest and greatest(untested)?!

Linus released
  • 2.6.24 on January 24th 2008,
  • 2.6.26 on July 13th, 2008, and
  • 2.6.27 on October 9 2008

Here is when it reached the users
  • Gentoo 2008.0 released on July 6, 2008 has linux 2.6.24 which was ~5.5 months old.

Distros used by power-users seems to be always running slightly older version compared to the distros aimed at the layman! Yeah, but power users^Wdevelopers use the unstable/development/factory/head version of their favourite distro and not the released stable. But Ubuntu stable(!) is based on debian unstable! And debian stable is so outdated. opensuse seems to be quiet the latest but not straight from the unstable development snapshot.

p.s: I use only opensuse regularly among these distros. So any mis-information and bias is likely. ;)

the avatar of Katarina Machalkova

Install more packages? ["Yes"]["No"]

When it comes to software, its users are usually very picky creatures :-) Put feature X in and hear them complaining how bad and user-unfriendly you actually made it. If they complain long/loudly enough, finally decide to remove it and be sure that so-far silent majority starts to complain even more.

It was the same with YaST package manager and pop-up question from the title of this post. I'm sure we all remember that one:



It was introduced in openSUSE 10.1 (aka BrokenSwManagement edition) in order to alleviate suffering of the poor users forced to use our package management (powered by zmd and baby-libzypp) with ultra-slow start-up. libzypp grew faster and faster over the time, but the pop-up question remained and (quite reasonably) it started to annoy users. "Why do I have to click to have this crappy pop-up disappear?" they asked. "I've made my choice, installed all packages I wanted, so I want to answer no further questions."

After many heated discussions, we finally made the pop-up go away in openSUSE 11.1 After clicking on 'Accept' and installing all packages, package manager simply ended. That, of course, made the other half of the users speak up: "Why YaST does not ask anymore whether I want to install more packages? I don't want to start package manager anew each time. I simply want to have an option to install something more I forgot about in the first round."

In openSUSE 11.2, my colleague lslezak (now the link to his blog should be here, but he is too shy to have one :)) used really ingenious way of cutting the Gordian knot - he made the behaviour on exit from package manager configurable. And not only that - besides an option to close package manager (for those who want to be done with it) and option to restart it (for those who may want to come back and select something more), he added a third one. When the package installation is over, you can choose to display a neat summary of what has been installed/deleted, how long did it take and view some detailed logs. Then, you can either finish, or go back to install more packages:


Now all you have to do is to open /etc/sysconfig/yast2 file in your favourite editor and set PKGMGR_ACTION_AT_EXIT variable to some reasonable value. Please find more detailed information here.

"But I don't want to edit some cryptic file manually," you might think. "Isn't there any other way?" Well, of course there is. YaST ncurses package manager has a brand new menu that allows you to pick the exit action of your choice in a few key presses:


There are some minor things left to polish, but it basically works by now. Better don't ask me how the sysconfig variable is actually written :-) It took me by surprise to realize that libzypp's interface to sysconfig is read-only, so I'm impatienly waiting for Augeas ;-)
a silhouette of a person's head and shoulders, used as a default avatar

Riding the D-Bus with Ruby

Riding the D-Bus with Ruby

The last time I looked at D-Bus is a couple of years ago. What I saw back then was promising in technology but ugly in (C-)programming. D-Bus has come a long way 'til then.

And so have my programming skills with scripting languages, esp. with Ruby. The ruby-dbus project provides a nice and easy-to-use programming API, once one has mastered the lack of examples and the D-Bus nomenclature.

About D-Bus

There is plenty of information available on D-Bus. I personally found the Introduction to D-Bus most valuable from a developers point of view.

D-Bus originates from the freedesktop.org initiative and is hosted at www.freedesktop.org

Basically, D-Bus is a RPC (remote procedure call) mechanism, allowing different programs to talk to each other and provide services in a standardized way.

The transport used for talking is called a bus, meaning everyone can ride (connect to) it. Usually there are two independent buses available

  • System bus
    This is for system-wide services, like hardware information (usually provided by HAL)
  • Session bus
    This is for per-login services, like a Gnome Desktop session.
Talking is done in a client/server fashion. The server code connects to the bus offering a service to be used by the clients. In order to find each other, services are names in a dotted syntax. E.g. org.freedesktop.Hal is offered by the HAL daemon providing hardware information.

The nice thing about D-Bus is that it allows introspection. You can ask a service about its capabilities. And the D-Bus itself is a service, so you just need to know about org.freedesktop.DBus to find all other services.

Services provide objects. These are organized in a tree-like fashion and typically addressed using slash-separated paths, just like filenames. Iterating over the objects of org.freedesktop.Hal gives you all devices.

Objects then have members. Members are methods to call, providing the functionality of the service. To make things more complicatedstructured, members are grouped in interfaces. Interfaces are comparable to capabilities of an object. For example the Hal object /org/freedesktop/Hal/devices/storage_model_DVDRW_LH_20A1S has the org.freedesktop.Hal.Device.Storage.Removable interface with the bool CheckForMedia() method.

Putting it all together gives you this chain
Bus (System/Session)
   -> Service (e.g. org.freedesktop.Hal)
   -> Object (e.g. /org/freedesktop/Hal/devices/storage_model_DVDRW_LH_20A1S)
   -> Interface (e.g. org.freedesktop.Hal.Device.Storage.Removable)
   -> Member (e.g. bool CheckForMedia())

There's more to D-Bus, like signals and signatures and activation and ... follow the documentation links given above if you want to learn it all. The explanation up to now should be sufficient to understand the basics of the ruby-dbus interface, however.

Using ruby-dbus

Connecting to the bus in Ruby is as easy as
require 'dbus'

bus = DBus::SystemBus.instance
# resp. 'bus = DBus::SessionBus.instance'
DBus::SystemBus is a Singleton, hence the .instance instead of the usual .new for creating the object.

Now you can create a proxy object. Its named 'proxy' because the real object lives on the other side of the connection, in the service. The proxy object is in your application and proxy-ing calls via D-Bus to the service object. You can use this to find all services on the bus

require 'dbus'

bus = DBus::SystemBus.instance

bus.proxy.ListNames[0].each do |service|
  puts "Service: #{service}"
end
Given a known service, D-Bus introspection allows to find its objects, subnodes and interfaces
require 'dbus'

bus = DBus::SystemBus.instance

# Create the proxy object
proxy = bus.introspect "org.freedesktop.Hal", "/"

# proxy.bus gives you the bus
# proxy.path is the object path
# proxy.destination is the service name

# Print object interfaces
proxy.interfaces.each do |interface|
  puts "Object #{proxy.path} provides #{interface}"
end

# Print object subnodes
proxy.subnodes.each do |path|
  puts "-> #{proxy.path}/#{path}"
end
A specific interface of an object can be accessed by the [] operator. And the interface knows about the signature of its methods.
require 'dbus'

bus = DBus::SystemBus.instance
# create proxy for the 'computer' device
proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer"

# Print object interfaces
proxy.interfaces.each do |interface|
  puts "Object #{proxy.path} provides #{interface}"
  proxy[interface].methods.each do |key,value|
    puts "  #{value.rets} #{key}( #{value.params} )"
  end
end
Due to the dynamic nature of Ruby, Object methods are directly accessible in normal Ruby conventions. One just has to select the right interface first.
require 'dbus'

bus = DBus::SystemBus.instance
proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer"

iface = proxy["org.freedesktop.Hal.Device.CPUFreq"]
freq = iface.GetCPUFreqPerformance
gov = iface.GetCPUFreqGovernor
puts "Frequency #{freq}, Governor #{gov}"
Riding the D-Bus with Ruby is easy and fun !