Tuesday, November 30, 2010

About .bashrc .bash_profile .profile .bash_login and /etc/profile

Have you ever wondered what is the purpose of ~/.bashrc ~/.bash_profile ~/.bash_login ~/.profile and /etc/profile files in Linux.

Bash is the default shell on most of the Linux distributions like Fedora and Ubuntu. If you take a look at man pages for Bash, you will get the following explanation:
When bash is invoked as an interactive login shell, or as a  non-interactive  shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.  
...
When  an  interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exist. 
Interactive shell is the one which is not running because of a script and lets you enter commands to interact with it. Login shell is the one where you are asked for user name and password before you can enter commands. An example of an interactive login shell is the one that you get after you login to a system using ssh. An example of non-login interactive shell is a shell that you get when you run terminal from menu item or some icon.

So when you login to a Linux system, first commands from /etc/profile (if it exists) will get executed. Then the system will look for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and execute commands from the first of these files that it founds. And when you open Konsole/Terminal from KDE or GDM, first commands from /etc/bash.bashrc (if it exists) will get executed and then commands from ~/.bashrc (if it exists) will get executed.

So if you want to execute a command for all users then you will need to add it to /etc/profile but if you want a command executed for a specific user then you can add it to .profile, .bash_profile, .bash_login or .bashrc in his/her home directory.

Please keep in mind that KDE and GDM are not login shells so there behavior is different. I dont know about KDE but GDM first executes command from /etc/profile and then from ~/.profile.

Tuesday, November 23, 2010

Extreme Programming is overrated

Xtreme Programming is a seriously flawed technique. As development methodology XP is nothing new. Iterative development was first explained by Spiral model which was introduced back in 1986. Also, few of its basic rules, most notably Peer Programming and Collective Ownership, are really against the management sense.

Peer programming simply wastes a resource. One guy writing the code and other just watching him write the code is just non-sense. Why not let both of them write their own code and review each-other's code at the end of the day? It is also very difficult to pair the right programmers together as not all programmers are made equal. So if you pair a good programmer with a not-so-good-programmer then the results will suffer, the productivity of the pair will be lesser than the productivity of the good programmer working alone as he will need to explain him self quite frequently. Programming is not an exact science. Its an art and programmers, like musicians, painters, writers, work well when left alone. You wouldn't want Picasso and Michael Angelo working on the same painting, would you?

Collective ownership diminishes the individual sense of ownership and responsibility. For a highly productive work environment, it is important to develop sense of ownership in the work force. As employees (developers in our case) develop sense of ownership there is an increased sense of pride, motivation and self-esteem. This results in increased productivity. If you want great software, let the developers own what they create.

In my opinion, XP is overrated and unpractical. Some of its ideas like Test First Development, Refactoring and Integrate Often work well but they are not specific to XP. Others like Pair Programming and Collective Ownership really make no sense.

Monday, November 15, 2010

Linux Directory Structure

The first thing that troubles a Linux newcomer is the Linux directory structure. First thing that people need to understand is that Linux has one directory tree which starts at "/" (also known as "root directory" or simply "root") in contrast Windows has multiple directory trees, one for each partition and removable media.

Every formatted hard drive partition has a file system on it. These file systems are not required to be the same. In Windows each file system is mounted to a different drive letter, thus starting a new directory tree, whereas on Linux one file system is mounted on root i.e "/" and other file systems are mounted on subdirectories of the root file system, creating a single directory tree. The file system mounted on "/" is called Root File System.

Given below are the most important subdirectories of root directory:

/bin
This directory contains the programs(binaries) that are required during bootup. These programs may be run by root user as well as a normal user. There must be no subdirectory in /bin.

/sbin
This directory is similar to /bin as it also contains binaries that are required during bootup but these binaries can only be run by super user i.e root user.

/lib
This directory contains library files that are required by different binaries in /bin and /sbin.

/usr/bin
Similar to /bin except that it contains programs which are not required during bootup.

/usr/sbin
Similar to /sbin except that it contains programs which are not required during bootup.

/usr/lib
This directory contains library files that are required by different binaries in /usr/bin and /usr/sbin.

/home
This directory is analogous to "Documents & Settings" directory in Windows. It contains 1 directory per user known as home directory of that user. All user specific files, configuration, documents and etc are stored in the users home directory.

/boot
This directory contains boot loader files. Boot loader is a program that boots Linux.

/etc
This directory contains system wide configuration files e.g network configuration, XWindows configuration and etc.

/var
This directory contains variable files i.e the files whose content changes continually during the operation of a system. An example of such files are log files which can be found at /var/log directory

More on Linux Directory Structure can be found at Filesystem Hierarchy Stadard website and on Wikipedia

Thursday, October 7, 2010

configure: error: no termcap library found

Recently when I was trying to build gdbserver for embedded Linux running on MIPS target, I kept running in to this error.
configure: error: no termcap library found
I tried compiling and installing termcap to my cross-compiling tools but this error kept appearing. I tried copying the termpcap.a file to cross-compilers lib directory and setting environment variables so that the compiler can find it but it didnt work. Then I found a post on internet telling that although the error says termcap library, what the compiler is actually looking for is ncurses library and compiling ncurses for Mips and copying ncurses lib to my cross compiling tools did the trick for me but it really made me angry. Why cant the error say
configure: error: no ncurses library found
It wasted more than half of my workday :(. As a developer it made me learn that it is important to display correct and precise error messages.

Sunday, August 1, 2010

How to use Netlink Sockets

 After reading kernel source I finally managed to make netlink sockets work for me. Below is an example of Netlink socket basics i.e opening a netlink socket, reading and writing to it and closing it.



Kernel Module

#include <linux/module.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>

#define NETLINK_USER 31

struct sock *nl_sk = NULL;

static void hello_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int pid;
    struct sk_buff *skb_out;
    int msg_size;
    char *msg="Hello from kernel";
    int res;

    printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
    
    msg_size=strlen(msg);
    
    nlh=(struct nlmsghdr*)skb->data;
    printk(KERN_INFO "Netlink received msg payload: %s\n",(char*)nlmsg_data(nlh));
    pid = nlh->nlmsg_pid; /*pid of sending process */

    skb_out = nlmsg_new(msg_size,0);

    if(!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    } 
    nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);

    NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
    strncpy(nlmsg_data(nlh),msg,msg_size);
    
    res=nlmsg_unicast(nl_sk,skb_out,pid);
    
    if(res<0)
        printk(KERN_INFO "Error while sending bak to user\n");
}

static int __init hello_init(void)
{
    printk("Entering: %s\n",__FUNCTION__);
    nl_sk=netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
    if(!nl_sk)
    {
        printk(KERN_ALERT "Error creating socket.\n");
        return -10;
    }
    return 0;
}

static void __exit hello_exit(void){
    printk(KERN_INFO "exiting hello module\n");
    netlink_kernel_release(nl_sk);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");


User Program

#include <sys/socket.h>
#include <linux/netlink.h>

#define NETLINK_USER 31

#define MAX_PAYLOAD 1024  /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

void main() {
    sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
    if(sock_fd<0)
return -1;

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();  /* self pid */
    /* interested in group 1<<0 */
    bind(sock_fd, (struct sockaddr*)&src_addr,
        sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0;   /* For Linux Kernel */
    dest_addr.nl_groups = 0; /* unicast */
    
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello");
    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    printf("Sending message to kernel\n");
    sendmsg(sock_fd,&msg,0);
    printf("Waiting for message from kernel\n");

    /* Read message from kernel */
    recvmsg(sock_fd, &msg, 0);
    printf(" Received message payload: %s\n",
           NLMSG_DATA(nlh));
    close(sock_fd);
}

Friday, July 23, 2010

Interprocess communications between a Linux Kernel Module (LKM) and a user program

More ofter than not a Kernel Module will need to communicate with a user program. We really have following three options for communication between a user program and Kernel Module:
  1. A device file in /dev
  2. A file in /proc 
  3. A file in /sysfs
  4. Netlink sockets
/dev is usually used for device driver files i.e files that represent devices but these don't have to be "real" devices, they can be pseudo devices. A device file in /dev/ may be acceptable, even for modules that aren't really device drivers. So if your module is a driver or exposes a simple open/read/write/close interface then this is the your best option.

A file in /proc or /sysfs is not an actual file. Read or write operations on these files actually go to the associated kernel module. /proc was originally intended for processes related information but over the years it has become dumping ground for lot of other stuff, which kernel developers are not happy about. So its better to stay away from it unless you are providing some processes related information. If you want a file based mechanism of communication but dont want to create a device file then /sysfs is the better option.

Netlink sockets, in my opinion, is the best option if you are working on a Kernel Module which is not a device driver. It provides user programs with a familiar socket interface and does not requires the creation of any kind of file.

I will soon be posting a working example of how to use Netlink socket for communication between a user program and Linux Kernel Module

Friday, May 14, 2010

How to connect to Windows VPN from Ubuntu without the help of GUI

In Ubuntu, the easiest way to connect to VPN is using NetworkManager. But some times it is not possible. Like in my case NetworkManager wont detect my 3G Evdo modem, so I have to use gnome-ppp to connect to internet. And because of this NetworkManager thinks that there is no active connection and it wont let me connect to VPN. So I used pon and poff scripts to control my VPN connection. These scripts are provided by ppp package which is available in every Ubuntu installation by default. Given below is how I connected to a Windows PPTP VPN server.

First thing you need is to install pptp-linux package. So do
sudo apt-get install pptp-linux
Now create a file /etc/ppp/peers/vpnfile. You can change the file name vpnfile to any name you like but keep it simple as you will need it to connect to your VPN. Now add following lines to this file:

remotename myvpn
linkname myvpn
ipparam myvpn
pty "pptp  --nolaunchpppd "
name 
usepeerdns
require-mppe
refuse-eap
noauth
defaultroute

#defaults from the pptp-linux package
file /etc/ppp/options.pptp

The first three parameters provide name of the remote system, name for the link and a value to be passed to scripts in ip-up.d and ip-down.d directories, respectively. These values dont need to be same and can be different. The scripts in ip-up.d directories are called when a connection is established and the ones in ip-down.d are called when a connection is terminated. Next parameter i.e pty specifies that the given script should be used to communicate rather than any terminal device. Rest of the parameters control different attributes of the connection i.e what protocol to use or refuse or whether to use encryption or not and etc. The last parameter i.e defaultroute adds a default route to system routing table when this connection is established. This means that when this connection is active, by default all traffic is routed on this connection. If you dont need this behaviour, remove it and add scripts to ip-up.d and ip-down.d to add only your required routes.
More detailed explanation of these parameters can be found in manual entry for pppd i.e man pppd.

You will also need to add a line to file /etc/ppp/chap-secrets with username and password for this connection.

username connection-name password *


Connection name in this line must be same as remotename, which we have set to myvpn. 
Now to connect to vpn, issue command 
sudo pon vpnfile
and you are all set, connected to your vpn. To disconnect from the vpn, issue command
sudo poff vpnfile