Tuesday, December 13, 2005

Fun with SQLite - Embedded never so easy

Over the weekend, I had to help a friend out with a little assignment (again :-)), to write an address book in C. Anyways, I opted to use SQLite, my reasons being (in no particular order):

  1. I’d heard how simple it was
  2. I’d never tried it and was itching
  3. I’d written a production app with mysql embedded C library about 2 yrs ago, and was curious to see how SQLite felt like
  4. I just needed an excuse to try SQLite out, and the C API at that

 

My prognosis in a nutshell: AWESOME!!!

 

I basically was writing C SQLite code 5 minutes after reading their “Getting started in 5 minutes guide”, and though I was on the irc channel (#sqlite on freenode), I didn’t ask any questions… it was all clear and straight forward – except that part when my AUTOINCREMENT didn’t work on a field declared as *int*, till I realized it was supposed to be *integer* - meehhhh!!!

 

Anyways, the tipping point for me was how it deals with rows returned in a query.

 

Typedef for a function pointer sqlite3_callback, that looks like:

 

int func(void * data, int numcols, char** colvals, char** colnames);

 

Basically, if you pass this function pointer to sqlite3_exec when executing a query that returns rows, this call back will be called for each row returned! This is very cool really. It’s a massive relief from the pointer gymnastics I had to do with the mysql4 C api, to get at my returned rows back then.

 

Anyways, I don’t know if this exists yet, but with all the data structure work I’ve been doing recently, I have been thinking of a patch to SQLite that would instead take a call back that looks like this:

 

int func(void * data, int numrows, sqlite_list);

 

the sqlite_list, would actually be a linked list of hash tables. Each node in the list will be a returned row, and each node, would actually  be a hashtable of the columns. This would be even EASIER to program against.

 

Currently, I’m not even going to deceive myself and say I’m going to write that patch… I’m not even thinking about it in any of my main processing threads… instead its been swapped out into some fscked up area of my mind… where it will stay until such a time as I have a *voila* experience with the SQLite source code (which I intend to read anyways… but that intention is stored in that same fscked up area of my mind… so you get the real picture of things)

 

Anyways… I did finish the address book rather nicely, and it was fun to call over one of my C hating colleague to see how it worked. Ope just laffed me to smitherins :-)

 

The fun part of the project was modeling the entities in the application. We have this Object Persistence Framework we use in our C# apps in the office, and I basically built something close to that in C, to do the project… and it again reaffirmed my belief that learning various programming paradigms leaves you a MUCH better programmer. Taking a look at the Address Book source code, looks SOOOOO much like OOP code written in any modern language… the only difference will be that no member access operator is being used. Infact, it looked like doing Python without the namespaces :)

 

Conclusion… SQLite is cool, so am I :-)

 

Essien out.

 

 

yirae: lists complete

Yesternite, I was able to wrap up the episode on Singly and Doubly linked lists for libyirae. I’ll upload the code later in the evening.

Some cool things happened as usual during the coding process, that allowed me to refactor out more Node manipulations, like Make_Next_Node, Make_First_Node (this for doubly linked lists, as singly linked lists don’t have any differentiating features for the *first* node), etc.

 

Most important of all, was that implementing the Doubly Linked List class ydList.c allowed me to see my algorithms more clearly, and had me going back to ysList (the singly linked class), to clean stuff up.

 

Right now, I have a number of todo’s but my next target Data Structure is a Hashtable.

 

Just before I get there though, I have to refactor the core operations of the linked lists class, I have a lot of operations, push, pop, insert, insertsorted, etc, and I think its not necessary. I want to settle on some core ops that can be used to perform the rest. For instance. Insert(), should be able to be used to implement both Append() and Pop(), even though that’s not what I’m doing currently. But before I move on the larger issue of Hashtables I have to clean up that (and probably, since it will be childs play, implement a Stack and Queue class).

 

After cleaning up the operations, I want to make the lists, generic. Right now, the DATA member of the lists are just ints. I want to make these into void * so I can use the lists as a generic carrier for _any_ type of data class.

 

Also, related to the immediate above point, I’m not sure how to structure the Hashtable. I have two options…

 

  1. struct yHashTable {

void *data;

char *key;

struct yHashTable *next;

}

 

Or

 

  1. struct yhtData {

void *data;

char *key;

}

 

            Struct yHashTable {

                  struct yhtData *content;

                  struct yHashTable *next;

            }

 

 

There seem to be advantages for each implementation. In 1 above, I have simplicity of representation and initial implementation, but I will have to rewrite most of my linked list code to support stuff like sorting by key, etc. in 2 above, I can pass in a different function pointer each time I need to sort, one for sorting by data, one for sorting by keys, and I won’t need to modify my linked list code much when inheriting to create the HashTable. I tend to favour method 2 above though, but I’ve not made up my mind yet which way to go. I’ll finish that operations clean up first, and then when I get to that bridge, I’ll just have to cross it.

 

It appears I’m still on target for my end of yr goal for Data Structures… the one I’m apprehensive about is Binary Trees. I don’t know *anything* about them apart from the fact that they’re pretty tall, and come in two flavours (b i n a r y   t r e e s…. get? :;) ) I guess that pretty much sums up my understanding of those :D

 

Anyways… back to other things now… I’ll post when yirae-0.3 is uploaded.

 

Essien… out.

Wednesday, December 07, 2005

libyirae: API updated to clearly differentiate a list from a node

I put my words to action yesternite, and updated all the functions to properly differentiate b/w a Node and the List itself. The NODE objects are used internally in the List implementation, and keep things clean, for the user of the library, all you’ll ever need to do, is to use the LIST and its functions.

 

It was actually fun to do. The fun part was, change all the declarations, recompile, and run the test, see the SegFaults, and start making them all go away one at a time :-), it doesn’t get better than that… ohhh… it just did… VALGRIND!!! Yup, I also had to plug mem leaks and once again we’re VALGRIND certified to boot!!! :P. I’ve really learnt a tremendous lot doing all this.

 

There is a decision I’m dilly-dallying on… Currently, I have the NODE functions and LIST functions in one file still…. I have to do basic File Content refactoring obviously, the question is now… how closely do I couple the two? I’m trying to think ahead to when I start inheriting (tonite to be precise), close coupling will entail doing something like:

 

  1. Pull the list functions out of ysnode.c into yslist.c
  2. Define the move the struct _ysNode definition into ysnode.h
  3. beable to to call struct->next, etc from yslist.c

 

loose coupling will entail:

  1. Pull the list functions out of ysnode.c into yslist.c
  2. leave the struct _ysNode definition in ysnode.c (hence hiding it from yslist.c)
  3. defining accessor functions ysnGet_Next(), ysnSet_Next(), ysnGet_Data(), ysnSet_Data() for the NODE objects
  4. using these accessors from yslist.c

 

Why am I dilly-dallying? Theoritically, loose coupling is the way to go, but it just seems like an unnecessary hoop deep in my gut… hmmm… especially since I’m not even sure how the inheritance is going to work yet till I start coding. Anyway, I think I just made up my mind. I’ll stick with loose coupling, and be ready to change my mind if things start getting unnecessarily complex. Yup… that’s what I’ll do. That means, by tonite, I should start on the doubly linked lists implementation, then will release 0.3

 

I’m looking forward to close of work already :D (don’t tell Bunmi I said that ;) )

 

Essien out.

Directory Services for the rest of us.

If you've every worked with M$ Active Directory, you'll appreciate the need for directory services to be easy to deploy.

 

I've worked extensively with Active Directory, and maybe I was just being lazy, but I could never actually get myself gingered up to configure OpenLDAP.

 

I also kept hearing good things about Novell eDirectory, but heck, I can't lay my hands on it to try it (but I hear its pretty tite).

 

Last year, RedHat bought AOL's Directory Server, and planned to OpenSource it... I heard that news, and just put it at the back of my mind as probably one of the most important Linux announcements (for the back office), for last year. We didn't hear from them again till earlier this year, when they made a first release.

 

That release was the basic LDAP engine without the admin console and a few other extras. The reason they gave was there are still parts of the code that are not able to be opensourced at that time, and they were still working to make it good to go.

 

Anyway, this morning, I saw this via an article on lxer.com: http://directory.fedora.redhat.com/wiki/FDS10Announcement

 

I'm yet to play with it, but this is a version 1.0 release, with everything feature complete for a first milestone. Its a great acheivement for RedHat, and the OpenSource community in general. I want to thank the guys at RedHat for being a great OpenSource company (even though i still think Fedora is bloated ;) - I mean, everyone is entitled to _MY_ own opinion right? :P).

 

Anyway, getting serious, I'm going to definitely try this baby out. Then I'll be able to know if the wait was worth it (in my guts, i feel it was).

 

Once more... thank you RedHat.

 

Essien out.

Tuesday, December 06, 2005

Listening To Code: The importance of proper nomenclature

Is that even the spelling of Nomenclature up there? ;;)

[hmm… it apparently is correct]

 

Yesterday nite, as I implemented Pop() for yirae singly linked lists, I realized that my return value couldn’t be a ysNode as all my other functions till then had been doing.

Basically, I’d been doing stuff like:

 

ysNode n = NULL;

n = ysNode(n, 5);

 

As you can see, I pass in the node (which is actually the head node of the linked list), and I return the new head of the list. This works well, until I get to POP(), which needs to pull off the first item on the list, and traditionally return it, but unlink it from the list. I couldn’t do:

 

n = ysPop(n);

 

Doing that will loose the data I’m popping. Eventually, I had to do this instead:

 

int data = ysPop(&n);

 

And my declaration for ysPop is:

 

int ysPop(ysNode*);

 

I notice that this is very neat and efficient, and I don’t like my functions having conflicting calling semantics, so I start to implement all my other functions to match this semantic, since I can’t make Pop() match their semantics, so Push() becomes:

 

ysNode n = NULL;

ysPush(&n, 5);

 

succinct and powerfull!!!

 

There is just one problem… now, I have to remember to append the ampersand infront of all my nodes that I’m passing to the various functions… like so: ‘&n’ instead of just ‘n’, since I’m now passing a pointer to a ysNode. Ofcourse, I’m apt to forget that, and infact, many of my ‘make’ invocations remind me of that with an error/warning. Thinking of how to solve this, I begin to think of creating a typedef for ysNode*.

 

Before I continue, a bit of background on ysNode.

 

The definitions if you look in ysnode.c:

 

struct _ysNode {

            int data;

            struct _ysNode* next;

}

 

typedef _ysNode* ysNode;

 

Now, you can see what my basic Node element struct looks like. Ofcourse, I could have been using struct _ysNode throughout my functions, but my code will quickly become ungainly, so according to SAGE advice, I typedef struct _ysNode* as ysNode, and I’m using it throughout. Now, I realize I also have to have a ysNode*, which is essentially a struct ysNode**, I sat back and started thinking… hmm…. Have I made a mistake somewhere? Why do I find myself having to define ysNode*?

 

BAAMM!!! It struck me.

 

A linked list is a collection of items, each item having a reference (or knowing how) to find the next item. Each of these items is a NODE, but the NODES are a distinct ENTITY from the LIST itself. From the way my code is starting to look, there seems to be a LinkedList type struggling to emerge, infact, its shadow is already present in &n (which is a ysNode*), but I hadn’t recognized it yet. Immediately I realized this, I also realized that my public functions were doing the wrong things, namely: exposing nodes to the user of the library.

 

What do I mean. From what I just said previously, it would seem obvious that a NODE is contained in a LIST, but that could as well as just be an IMPLEMENTATION detail… I could by stroke of Genius (AKA Insanity ;) ), also come up with an implementation of Lists that doesn’t use NODES :), I just wonder what would be used, but anyway, the point is that the design is porous as it is exposing the NODES to all eyes. My *public* functions then, SHOULD operate on Lists, and not Nodes. The question is then, what is a list, and what is a node?

 

At the Domain level, a LIST is a collection of Nodes, but at the programmatic level, a LIST is just a pointer to the HEAD of a node… does this sound familiar? Try this, an Array is C, is just a Pointer to the first element of an Array!!! Yup, that a nice zinger… once I realized this, a lot of things just fell into place.

 

The title of this article, is taken from the fact that I WOULD have missed this, if I wasn’t paying attention to what the code was trying to say to me. And the code was able to talk to me clearer because I gave it a good voice to start with – THE NAMES OF THE VARIABLES N STRUCTURES. Its very important to properly name your objects to as accurately as possible model the problem domain you’re trying to solve. If you do this, the code gains a voice, so to speak, and you can read it back and learn from it. Just imagine if I’d stuck to my earlier plan of calling ysNode, yLinkedList. I would NEVER have had the paradigm shift I had in the way I did. Infact, immediately after naming it yLinkedList, I just thought… no… this doesn’t feel right, all I’m passing around are nodes, so I renamed them, and its come back to pay me good for that decision.

 

Its like this, I start out implementing functionality, with a particular rule of thumbs, along the way, I happen to implement some stuff that I don’t exactly plan for from the scratch (b/cos I’m paying attention to refactorings and good coding techniques), then a pattern emerges which I didn’t set out to create. I recognize the pattern and want to optimize it or at least refactor it properly, and in so doing I set out to understand the pattern. The understanding of this pattern, then teaches me something much more than what I knew at the onset of the project. This is my code beginning to talk to me.

 

This may all sound poetic and stuff, but in practice, these things happen all the time… your domain problem becomes clearer as you set out to define the problem in terms of a programmable solution. This is where bottoms-up coding is strongest… as you build small units, you can recognize the patterns that are forming and seek to understand them. If you follow Tops-Down coding, chances are that most of what you’re doing, you’ve already thought of it outside the advantage of being embedded in the problem’s solution, therefore, you’ll miss the tiny details, which are likely to make the solution *elegant*. Ofcourse you may argue that elegance in software is an unreal panacea, or a Holy Grail of sorts, and can’t be achieved in production scenarios, but only in small one on one projects… my answer to that is that, in a proper dev house, the *production software* is just a combination of many *one on one* modules – any project manager will agree with that description. The question then is how to make the coders benefit from the fact that they still end up working on their individual one-on-one projects.

 

Well… I’m still learning, and still growing, and by Jove… Data Structures seems to be a wonderfull way to end 2005 :-)

 

Essien

yirae: uploaded

The code to yirae is uploaded:

http://datavibe.net/~essiene/downloads/yirae-0.2.tar.gz

 

 

 

libyirae: simple sorting of singly linked lists

And so the story goes…

I have finally done it yippee!!! :-) Source will be available at http://datavibe.net/~essiene/downloads/yirae-0.2-tar.gz before the end of the day.

(needless to say, i built this on a GNU system, so gcc in any of its incarnations will work [cygwin, ming, etc]

After my last ungainly experience with those-pesky-lists™, I had to go follow most of the links I had bookmarked to see how guys have been tackling sorting of singly linked lists. Everyone seemed to agree that they were harder than sorting doubly linked lists (at least I have to believe that, so I don’t feel dumber than I’m feeling presently :)). Anyways, there are a number of approaches, but I’ll try to explain the one I like best.

First imagine you have a list like:

1->3->2

When traversing this list, and you come across 2, you just have to swap it with 3 and you’re done. Imagine instead that you have:

1->3->2->5->1->7

A single pass would go something like this:

You don’t touch 1, then you swap 3 and 2, you then swap 5 and 1 and you don’t touch 7… the result looks like:

1->2->3->1->5->7

Tada… its still not sorted, you’ll have to pass thru this list at least two more times, before you get the desired:

1->1->2->3->5->7

This raises a number of issues… 1st you have to repeat this process basically till you can verify that all your elements are in order… for a long list, this is just not acceptable. Anyways… this was the most obvious approach, and its ridden with a number of issues.

The other not so obvious approach is this. First, imagine that you have an InsertSorted() function that will insert an element such as to keep its place. It doesn’t sort an existing list, but it will not add to the confusion if its not sorted. So if I have:

1->5->7->3

And I call InsertSorted(2) on this list, it will result in:

1->2->5->7->3

Once I have a method like that, I can proceed to one of two implementations for the sorting:

Method 1 – the least brain tickling path
=============================
1. iterate thru the list
2. POP each node you meet, OFF the list (remember POP removes a node)
3. InsertSorted each node you POP into a new list
4. return the new list :)

Nice and easy, this is the current implementation I have. Though, I’ve been wondering about the cost of the new list in the whole process. Also, my current implementation has another Node memory overhead (I’ve explained that one in the code). There is a second method, that at first glance, seems more efficient, though after thinking thru it, the efficiency can just to tied down to the process of creating a new linked list that the first method incurs, if that cost can be shown to be zero, then there is basically no loss or gain as far as I can think, anyway, the second method goes thus:

Method 2 – using only one list
============================
1. iterate thru the list
2. if you find any node out of sorted order, Unlink the Node (unlink doesn’t destroy the Node, just removes it from the list and returns the Node to you)
3. InsertSorted the node back into the list.
4. return the list

This method seems to be more efficient than the method 1, but I’ve not done any testing/profiling so I don’t know for sure. After thinking for a while, there is really no memory usage difference, as in the first case, when the new list grows as the old list decreases. Also, the creation of a new list isn’t a costly operation at all by my implementation.

If you look thru the code, you’ll see that my public functions deal with data not nodes, so I POP data, and I Insert data hence I always have to create an underlying Node object to help me out… I’m thinking of having utility versions of all these operations that pop Nodes and Insert Nodes, so I can reuse the memory without free’ing one only to allocate it later…

Anyways, the code is free to look at. I hope it helps some other person, especially if (s)he’s doing an assignment ;)

Oh finally, the thing that makes me happy is that ynode_test.c is totally valgrind approved :D, I hear LinkedLists are always a point where guys leak memory, but I guessed I closed mine up well… maybe not NewsWorthy™, but definitely something for me to be proud about.

Essien out!

Monday, December 05, 2005

Singly Linked List Class - libyirae genesis

/*-------------------ABOUT--------------------*/
A collection of data structures, implemented for the sake of learning. Yirae, is a contamination of the Efik work Y're, which means to link or join. I chose the name b/cos the first structures implemented for yirae was a singly linked list. The library is called libyirae :)

*---------------------------------------------------*/

/*-----------------Makefile--------------------*/
all: libyirae.a test
@echo "All Done"

test: ysnode_test
@echo "All Test Done"

ysnode_test: ysnode_test.c libyirae.a
gcc -o ysnode_test ysnode_test.c -I. -L. -lyirae


libyirae.a: ysnode.c ysnode.h
gcc -c ysnode.c
ar -rcs libyirae.a ysnode.o


clean:
rm *.o
rm *.a

/*---------------------------------------------------*/

/*-------------------ynode.h-------------------*/
#ifndef YNODE_H
#define YNODE_H

typedef struct _ysNode *ysNode;

ysNode ysCreate(void);
void ysFree(ysNode);

ysNode ysPush(ysNode, int);
ysNode ysRemove(ysNode, int);

void ysSwapNodes(ysNode*, ysNode*);
ysNode ysSwap12(ysNode);

int ysLength(ysNode);
void ysPrint(const ysNode);


#endif
/*---------------------------------------------------*/


/*----------------ysnode.c---------------------*/
#include

struct _ysNode {
int data;
struct _ysNode *next;
};

typedef struct _ysNode *ysNode;

ysNode ysCreate()
{
ysNode head = malloc(sizeof(struct _ysNode));

if(head) {
head->data = 0;
head->next = NULL;
}

return head;
}

void ysFree(ysNode head)
{
ysNode current = head;
ysNode next;

while(current) {
next = current->next;
free(current);
current = next;
}
}

ysNode ysFind_Last(ysNode head)
{
ysNode current = head;

while(current) {
if(current->next == NULL) {
return current;
}

current = current->next;
}
}

ysNode ysPush(ysNode head, int data)
{
ysNode n = ysCreate();

if(n) {
n->data = data;
n->next = head;
head = n;
}

return head;
}

ysNode ysRemove(ysNode head, int data)
{
ysNode current = head;
ysNode prev = NULL;

while(current) {
if(current->data == data) {
if(prev) {
prev->next = current->next;
free(current);
break;
} else {
head = current->next;
free(current);
break;
}
}

prev = current;
current = current->next;
}

return head;
}

ysNode ysCopy(ysNode node)
{
ysNode n = ysCreate();
if(n) {
n->data = node->data;
n->next = node->next;
}
return n;
}


int ysLength(ysNode head) {
int count = 0;
ysNode current = head;

while(current) {
count++;
current = current->next;
}

return count;
}

void ysPrint(ysNode head)
{
if(!head) {
printf("(null)\n");
} else {
ysNode current = head;
while(current) {
printf("%d->", current->data);
current = current->next;
}
printf(".\n");
}
}


/*-------------------------------------------------------*/


/*-------------------ynode_test.c----------------*/

#include
#include

int main()
{
ysNode l = NULL;

/* using ysPush() eventually, faster than Append, that has to Find_Last() first, before appending*/
l = ysPush(l, 5);
l = ysPush(l, 10);
l = ysPush(l, 7);
l = ysPush(l, 23);

printf("The list is now %d nodes long as shown below: \n", ysLength(l));
ysPrint(l);

printf("Starting removals\n");

l = ysRemove(l, 7);
ysPrint(l);

l = ysRemove(l, 23);
ysPrint(l);

l = ysRemove(l, 5);
ysPrint(l);

l = ysRemove(l, 10);
ysPrint(l);

printf("Removals finished\n");

ysFree(l);
return 0;
}

/*------------------------------------------------*/

On implementing singly linked lists

This weekend, on account of a friend’s assignment, I had to delve into implementing linked lists. (Yeah, I admit, I’ve never taken time to study the implementation of these babies, all I knew was the concept). Jumping in with my usual optimistic, how hard can it be… I mean, I’ve written kernel modules to boot ;)

 

Anyways, to be honest… the singly linked list was not hard to implement at all. I got all the basic operations, Create(), Free() (oh… I love to valgrind my stuff, it gives me a good feeling ;) ), Add() and Remove(), these were relatively painless (for the Add(), I had to implement a Find_Last(), so I could always append at the end of the list, being that I wasn’t holding a tail pointer anywheres).

 

Anyway, the other requirement was for the list to be always sorted in ascending order. And away I went, I mean, how hard can sorting and swapping of pointers and s*** be? I’ll just add this teeny… weeny… BAAAM!!! I hit a road block!!! Suddenly, my understanding of pointers is being stretched to the limit, and much as I would hate to admit on OpenInterWeb™, I DON’T KNOW POINTERS LIKE I THOUGHT I DID!!!

 

It was a sobering moment, as I kept deceiving myself, fighting with a very annoying segment of code, trying to get the sorting to work and I finally admitted to myself… I’ve been butt kickd!!! DAMN!!! You can imagine how intelligent I was feeling then.

 

Anyways, I’ve managed to bookmark a lot of articles on advanced pointers and linked lists, and data structures in general (I mean, when I kick this guy in the patella, I’m off to the Races with Hash Tables, and binary trees!!!).

 

One of the good things I found out tho, was that traversing a list with a for is not quite so neat as with a while. I’ve been so used to all the foreach, for foo in bar ;), constructs, my initial reaction was to traverse with a for loop. When doing things like Remove(), that need a reference to a previous pointer, its somehow *cleaner* to use a while loop, at least, it made my code cleaner when I changed the fors to whiles.

 

Anyways, I think every hacker worth his salt, should try to implement a couple of things just for the fun of understanding them. And if possible, eat your own dog **** on a couple of projects, so I’m making up a list of stuff I NEED to do before this year runz out finally J

 

  1. Complete the Darned Sorted Singly Linked lists,
  2. Inherit and implement Doubly Linked Lists
  3. Implement Basic Hashtables
  4. implement a Basic Binary tree

 

Wow!!! Now that’s a tall order!!! That means, I’m parking/suspending all other hacking endeavours for the next two weeks :(

 

The other thing I started thinking of, and I’m not so fixated on it now, but I wouldn’t mind attempting an implementation, is a Garbage Collector. This one is really of interest to me, as I’m very MemoryLeak conscious these days.

 

Oh well… lets see what happens in the next two weeks. I must win I tell you.

Friday, December 02, 2005

Sourceforge New Look

I've been lazying my behind and didn't even know sourceforge has a brand
new look!!! WHEEEEEEEEEEEEEe!!!!!

It really looks cool. I just got the monthly mail sent to project admins
today, and looked at the site, and its really cool. I hope other aspects
of usability in the backend have been worked on as well... for instance,
I just couldn't get my sourceforge webspace to work :(

Anyways, I'll be checking that out later.

Oh... Pysystray looks even cooler now :)

https://sourceforge.net/projects/pysystray/

Essien out.

Thursday, December 01, 2005

INIT Issues : More reasons why I love Linux

A couple of days ago, I was playing with the LIVE CD image i've created. It boots properly off the HDD when I vector to it using a basic initrd image. The problem is that once It gets written to a CD, funky stuff begin to happen, all b/cos a CD is a read-only medium.

When I started playing with the LIVE CD creation, I hadn't really taken that into consideration. So I had to scourge the web looking for ideas on how ppl handled that. Why I was scouring, I was trying to take the lazy way out - I went into my /etc/rc.sysinit, and started commenting out lines that would cause a disk write (I just wanted to see a darned login screen... i mean... what's wrong with that? :) )

Anyway, after one of my many chroots into the image, i tried to boot into the image, and realised i'd borked something badly. I then tried to boot back into my system and TADA!!!!! i got:

INIT: "cannot execute /etc/rc.sysinit"

Anyway, to cut out all the dramatics, I had a very unusable system.

Now, lemme qualify, when Linux doesn't boot normally, there are a MYRIAD of ways to boot and access your files, especially when you use GRUB as your bootloader. Anyway, I tried doing a chroot from the original install cd which can serve as a minimal rescue cd, and all the permissions where in place... nothing looked out of the ordinary, still i got the silly message!!!

I did what i normally do with Linux problems, I just let it alone, and for a the last few days, i didn't get to boot linux when i got back home from work (I work on .NET on M$ by day anyways ;) ). Finally I decided to give it one last shot. I sent a message to the archlinux mailing list, asking for an idea on what could be wrong. While waiting for an answer, i hit google, and i came across a nearly similar thread in a RedHat ml and on the Arch forums. Both just confirmed my suspicions, something WAS amiss, in the case of the RedHat guy, the file that INIT was looking for, wasn't physically there... in the case of the ArchLinux guy, the file was there, but permissions were denied, and none of these was my scenario. To make matters worse, I'd been running /etc/rc.sysinit on that partition when accessed from the install cd without issues.

Finally, i decided to take it home. I just used grub to set my init=/bin/bash, once i got the bash prompt, i attempted to run /etc/rc.sysinit, and BOOP!!!, it borked nicely. It couldn't find /bin/sh!!! This was the problem... the intepreter at the shebang was /bin/sh!!! I looked, and it wasn't there... i prolly symlinked it out without knowing when i was doing multiple chroots from the root image :((

Anyway, I had to reboot the kernel in rw mode (other than the default ro mode), and use pacman to reinstall bash, and get back that symlink, and voila... its all good my man!!! All GOOD!!!

The moral lesson? Use a flexible OS, that allows you to know all about it without buying expensive books etc... this was what saved me, and this is Why i LOVE Linux.

with BlinDvws, i would prolly have had to reinstall (at least a repair install of XP :( )

Anyway... Linux R0ckz and so do I :)

Essien out