Saturday, July 2, 2011

Writing My Own 'ls'


It was the 2nd assignment for System Programming Lab, we had to implement the "ls" directory listing program on our own.

However, it was not a hard task, but it was a bit time consuming, specially when it came around the output formatting for different type of options. We were asked to implement a limited amount of options, and all of those are short options. So, I've implemented accordingly, with some more short options, that the real "ls" has. According to most of my classmates, the real hard part seem to be implementing the "-R" i.e. recursive traversal option. But actually it is quite easy if you know how to implement a DFS algorithm.

So, it's basically simple, you start from starting parameter, use opendir() and readdir() to get the contents of the the directory, process them, and then recursively call on the child directories in a DFS fashion.

Well, there is a catch here. The dirent structure has a field "d_name" which will give you the name of the entry of a specific directory. As we know, in ls, we need various information regarding the entries which can be found using stat() or lstat() calls, which takes the path to the entry as a parameter, but not just the name. So, using the d_name directly will cause you run into troubles pretty easily (as I have seen this mistake was made commonly in lab). Obviously the first time it works if you test it on current directory (most of the cases), because, for the current directory, the relative path is actually just the entry name. So for all the other cases, you will need to provide the full path (also can be the relative path from pwd) to stat() or lstat() whatever you use.

Another thing was to follow or read symbolic links. Well, opendir() by defaults follow symbolic links, and thus this is not a problem at all. For long formatting, we had to print the target entry name as well, and readlink() did that for us. Be careful when using stat(), if a link is pointing to a directory, it will tell you that the link is also a directory, so to test whether it is actually a link, you have to use lstat().

The man page for stat() (as far as I remember, $ man 2 stat) contains a code that will show you how to use the bit flags on st_mode field. To manage everything, I created a switchboard first, then switch specific flags regarding which options are present in the argument list.

There are two more tiny works to do. for the "-1" option, you need to detect whether your output stream is tied to a terminal or not. This can be checked by isatty(fileno(stdout)), if it returns non-zero, then it is a terminal. Also, for some other options, you need to detect whether you are a super user or not. You can use geteuid() i.e. get effective user id to see if it is 0. In case you are not a super user, you will have a non-zero return.

This is pretty much the work, here is my implementation if you think it might help you.


Friday, July 1, 2011

Beginning Kernel Programming


I have started to learn kernel programming shortly, well, this thing is not much interesting to me, mostly due to academic purpose.

I have been following The Linux Kernel Module Programming Guide which was suggested by our instructor. However, I've found that this one is already a bit old and I faced a lot of trouble even to see the simple yet extremely popular "hello world" on my kernel log. As I use ubuntu distribution (version 11.04), there are lot of differences inside and outside. So I have cooked the first code as followed (as in the guide, it is explained there.)

#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void) {
    printk(KERN_ALERT "Hello world 1.\n");
    return 0;
}

void cleanup_module(void) {
    printk(KERN_ALERT "Goodbye cruel world 1.\n");
}

However, this goes quite well without any trouble. But I have to change the "Makefile" a bit to successfully compile this Hello World code (tabs will be expanded as spaces here).

obj-m += hello-1.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

I'm lucky that I figured out only pwd is not working, I had to add shell instruction with it.

After this, everything went on quite well:

$ sudo make

This generated the following output with no errors:

make -C /lib/modules/2.6.38-8-generic/build M=/home/zobayer/Lab/system/kernel modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.38-8-generic'
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: Leaving directory `/usr/src/linux-headers-2.6.38-8-generic'

Now to install the module:

$ sudo insmod ./hello-1.ko

So I opened the file /proc/modules to check if I was successful and whoa, it was there...

The I removed it from modules:

$ sudo rmmod hello-1.ko

Now I had to make another change, when I try to open /var/log/messages as the guide suggest, I've found that there is no such file, instead, I had to open /var/log/kern.log, and at the far bottom, I've found what I had been looking for:

... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 
Jul  1 14:17:38 zobayer kernel: [   48.569441] 
Jul  1 14:17:38 zobayer kernel: [   48.569447] nouveau 0000:01:00.0: VGA-1: EDID block 0 invalid.
Jul  1 14:17:38 zobayer kernel: [   48.569452] [drm] nouveau 0000:01:00.0: DDC responded, but no EDID for VGA-1
Jul  1 14:17:38 zobayer kernel: [   48.596016] [drm] nouveau 0000:01:00.0: Load detected on output A
Jul  1 14:18:12 zobayer kernel: [   82.640352] Marking TSC unstable due to cpufreq changes
Jul  1 14:18:12 zobayer kernel: [   82.640450] Switching to clocksource acpi_pm
Jul  1 15:23:31 zobayer kernel: [ 4001.644627] hello_1: module license 'unspecified' taints kernel.
Jul  1 15:23:31 zobayer kernel: [ 4001.644636] Disabling lock debugging due to kernel taint
Jul  1 15:23:31 zobayer kernel: [ 4001.647429] Hello world 1.
Jul  1 15:24:58 zobayer kernel: [ 4088.648118] Goodbye cruel world 1.

I think I have to change many things in future, but so far, this may be a good start...

Edit: An addition by Surid vai:

Mellowhost Surid

/var/log/messages is the general log file and kern.log is the kernel log file. In redhat system, until explicitly defined, there is no kern.log, I believe that book is written based on redhat kernels, that is why they are using messages. B...ut for any system, the command "dmesg" should print those module outputs. dmesg is the kernel ring buffer log. You are using Ubuntu, this is why by default it is using kern.log

If you would like to change the kernel log file, you would need to use klogd. It is a daemon to catch and handle kernel messages. Now find how can you make the change :)

http://linux.die.net/man/8/klogd


Tuesday, May 17, 2011

Writing My Own Shell


Hello everyone, I am back after a huge pause, actually I was busy for nothing the past few months, and felt the necessity to write something here. So I am going to note down something I recently did. I just finished writing my own shell program for linux, which is simple, doesn't support piping or redirection, but most of the features are available, so, it actually looks like the common "sh" shell. I am not going to describe the big code, you have to understand what it is doing :p

The source code. Its free to use. I have written the whole code by myself and surely I am not an expert, so if anything happens to your computer, I don't know you :p

To compile, you can use this makefile in su mode (note tab character is important).

Some features, you can invoke single commands like this:

$ doit <command [arguments...]>

Also, you can start the shell by simply calling it without any argument:

$ doit

Then it will behave like a shell program and you can give commands one by one just like a simple shell. It implements its own "cd", "pwd" and "jobs" command (you should know what they mean). You can call background processes by appending & at the end of the command... and so on. You can display resource utilizations as well. Just dig through the code, I will enhance it more if I get time :)