Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

LD_PRELOAD Tutorial

Dynamic linker will load the all the shared library one bye one in any order. LD_PRELOAD  is a environment variable containing libraries that the dynamic linker will load before loading any other libraries.

By using this we can override the function available in the later libraries. Even we can over ride the functions available in C programs libc libraries. Here i demonstrate the usage of LD_PRELOAD with simple example.

Simple C program named as ldmain.c 
#include <stdio.h>
int main()
{
        printf("PID = %d\n", getpid());
        return 0;
}

Above program will print the process id of the current process using libc function getpid.

Compile the above program using gcc compiler and run the program, it will print the process id.
sujinsr@fedo:~/workspace/c $ gcc -o main ldmain.c 

sujinsr@fedo:~/workspace/c $ ./main 
PID = 1082

Now you see how we can override the libc's getpid with our own. Write our own version of the getpid function. Here i named the file as ldpid.c
#include <stdio.h>
int getpid()
{
        printf("My own version of getpid() for testing it will return always 99999\n");
        return 99999;
}

Create the shared object of that function using gcc
sujinsr@fedo:~/workspace/c $ gcc -o ldpid.so ldpid.c -fPIC -shared 

Set the LD_PRELOAD envirnonment as new shared library we created before.
sujinsr@fedo:~/workspace/c $ export LD_PRELOAD=./ldpid.so

Run the program and see our own version of getpid called instead of libc's function.
sujinsr@fedo:~/workspace/c $ ./main 
My own version of getpid() for testing it will return always 99999
PID = 99999

If you want to remove shared library configured to LD_PRELOAD just unset the environment variable like below.
sujinsr@fedo:~/workspace/c $ unset LD_PRELOAD

sujinsr@fedo:~/workspace/c $ ./main
PID = 1638

Cheers !!!!!

Daemonizing Server Process in Linux

If we have the server it has to handle all the request and response without the help of 
user. So better running server process as background is good idea.

We can run the Linux process as foreground or background. A process is called daemon when it running in background
and doing necessary work.

Steps to make Server process as daemon:

1. Create child process and separate from parent - fork()

create child process using fork() system call, then exit parent process. Once parent exits new child process
will child of init process and behave as background process.

pid = fork()
if (pid < 0)
exit(1);

if (pid > 0)
exit(0);

/* child continue as daemon */


2. Make new child process independent - setsid()

When terminal receives signal, all the process connected to this terminal get signal. 
child process created through fork() system call will inherit process group of parent process. All the signal passed
to process group will passed to inherited process. 

daemon server should not get signal from where was started. 

We can make daemon process independent from parent using setsid() system call

setsid() /* get a new process group */

3. Handle standard I/O stream - getdtablesize(), open(), dup(), dup2()

fork system call will inherit all open file descriptor of parent. so close all the unnecessary open file 
descriptor.

for( fds=getdtablesize(); fds >=0; fd--)
close(fds);

standard libraries use standard stream for some work, better close all three standard ( stdin - 0, stdout - 1, stderr - 2)
for safety purpose redirect the out put to /dev/null.

i = open("/dev/null", O_RDWR);
dup(i);
dup(i);

for ease understanding read the man page of 'open', 'dup' & 'dup2'.

4. Change file creation mask - umask()

Most of the server run as root user mode(not mandatory). So it should protect the files it created when it run.
we can change the process privilege using umask system call.

umask(027);

This will restrict file creation mode to 750

5. Change working directory - chdir()

Server should be run from root directory (not mandatory), then only it can see all the files 
from system.

chdir("/");

"/" means root directory.

6. Run single copy of server

For a system it requires only one copy server at a time. File locking is a good method to achieve this by making
other process wait on the file lock. when process terminate lock on this file automatically released then server
which waiting on the lock will start work.

write the pid of the process to file, which will help to know the running pid of the server. 

lfp = open("lockfile.lock", O_RDWR|O_CREAT, 0650);
if (lfp < 0)
exit(1);
if (lockf(lfp, F_TLOCK, 0) < 0)
exit(1);
sprintf(strpid, "%d\n", getpid());
write(lfp, strpid, strlen(strpid));

7. Logging

When server is running some messages should be logged. This will help for developer to debug the server
if any problem arise.

void logging(char *filename, char* log)
{
FILE *fp;
fp = open(filename, "a");
if (fp == NULL) 
return;
fprintf(logfile, "%s\n", log);
fclose(fp);
}

/* log messages as below */
logging("logfile.txt", "This is server log");


Program:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#define WORKING_DIR "/home/sujin/c"
#define LOCK_FILE "lockfile.lock"
#define LOG_FILE "logfile.log"

void make_daemon();
void logging(char *file, char *log);

void logging(char *file, char *log)
{
        FILE *fp;
        if ((fp = fopen(file, "a")) == NULL)
                return;
        fprintf(fp, "%s\n", log);
        fclose(fp);
}

void make_daemon()
{
        int pid, lockfd, i;
        char pidstr[16];

        pid = fork();
        if (pid < 0) {
                printf("fork error.\n");
                exit(1);
        }
        if (pid > 0)
                exit(0);

        setsid();

        for (i = getdtablesize(); i >= 0; i--)
                close(i);

        i = open("/dev/null", O_RDWR);
        dup(i);
        dup(i);

        umask(027);

        chdir(WORKING_DIR);

        lockfd = open(LOCK_FILE, O_RDWR|O_CREAT, 0640);
        if (lockfd < 0)
                exit(1);

        if (lockf(lockfd, F_TLOCK, 0) < 0)
                exit(1);

        sprintf(pidstr, "%d\n", getpid());
        write(lockfd, pidstr, strlen(pidstr));

}

int main(int argc, char *argv[])
{
        make_daemon();
        sleep(5);
        while(1)
        {
                /* Do server work */
                logging(LOG_FILE, "This is write from main server.\n");
        }

        return 0;
}


I am not full owner of this article. I grabbed some details from other articles. Full credits goes to author of Unix Daemon Server Programming


Introduction to GNU profiler

Introduction:

Profiling is the process of finding the time complexity of program.

Profiler will find the time taken by the parts of the code. It will help to programmer
to reconstruct the code if the parts of the code consumed more time.

There is many profiling tools available. But this article give idea on native GNU profiler(gprof)

Step 1:

Write a simple program called proftest.c

#include <stdio.h>
void firstFunction(int );
void secondFunction(int );

int main(int argc, char *argv[])
{
        int a = 10;
        int *b = &a;
        firstFunction(a);
        return 0;
}

void firstFunction(int a)
{
        a += 10;
        sleep(1);
        secondFunction(a);
        return;
}

void secondFunction(int b)
{
        sleep(5);
        printf("final value : %d\n", b);
        return;
}

step 2:
Compile the program with '-pg' option using gcc

gcc -pg proftest.c -o profout

Step 3:
Execute the program

./profout

It will create the gmon.out file in current directory

step 4:
run the gprof with gmon.out

 gprof -b profout gmon.out

You will get the output as below

Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

  %   cumulative   self              self     total
 time   seconds   seconds    calls  Ts/call  Ts/call  name
  0.00      0.00     0.00        1     0.00     0.00  firstFunction
  0.00      0.00     0.00        1     0.00     0.00  secondFunction

                        Call graph


granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name
                0.00    0.00       1/1           main [7]
[1]      0.0    0.00    0.00       1         firstFunction [1]
                0.00    0.00       1/1           secondFunction [2]
-----------------------------------------------
                0.00    0.00       1/1           firstFunction [1]
[2]      0.0    0.00    0.00       1         secondFunction [2]
-----------------------------------------------

Index by function name

   [1] firstFunction           [2] secondFunction

C Program To Reverse Singly Linked List

PROGRAM:
#include <stdio.h>
#include <stdlib.h>

typedef struct _list {
int data;
struct _list *next;
}list;

int main(int argc, char **argv)
{
printf("\n.. Start of singly linked list reverse program .. \n\n");

list *head=NULL, *head_start=NULL, *display = NULL;
list *newnode;
int a = 0;

/* Add 5 elements to linked list */
for (; a<10; a++)
{
newnode = malloc(sizeof(list));
newnode->data = a+1;
newnode->next = NULL;
if (a==0) {
head = newnode;
head_start = newnode;
}
else {
head->next = newnode;
head = head->next;
}
}

C program to check file available in a path


PROGRAM:
#include <stdio.h>
#include <unistd.h>
 
int main(void) {
    if( access("/home/pc/test.txt", F_OK) != 0 )
                printf("File not available\n");
        else
                printf("File available\n");
        return 0;
}
OUTPUT:
File not available

C program to reverse the sring

PROGRAM : 
#include <stdio.h>
 
int main(int argc, char *argv[])
{
    char str[1024];
        char revStr[1024];
        int charCount = 0, x = 0, i = 0;
        
        printf("Enter the string : ");
        gets(str);
        while(str[charCount] != '\0')
                charCount++;
                
        for(x=charCount-1; x >= 0; x--){
                revStr[i] = str[x];
                i++;
        }
        revStr[i] = '\0';
        printf("\nReversed string : %s \n\n", revStr);
}
OUTPUT : 
Enter the string : TESTSTRING

 Reversed string : GNIRTSTSET 

Create shared library for C program in Linux

Consider you c program has two file, which are functions.c and main.c

Consider your current working directory is /home/sujin/shared/

functions.c
int add(int x, int y)
{
    return x + y;
}
 
int sub(int x, int y)
{
        return x - y;
}
 
int mul(int x, int y)
{
        return x * y;
}
 
int div(int x, int y)
{
        return x / y;
}
main.c
#include <stdio.h>
int add(int x, int y);
int sub(int x, int y);
int mul(int x, int y);
int div(int x, int y);
 
int main(int argc, char *argv[])
{
    printf("%d\n", add(10, 15));
        printf("%d\n", sub(50, 15));
        printf("%d\n", mul(10, 3));
        printf("%d\n", div(100, 4));
        return 0;
}

1. Compile library source file(functions.c) into position independent code
gcc -c -fpic functions.c -Wall
2. Create shared library from the object file generated
gcc -shared -o libfun.so functions.o 
3. Compile the main program with shared library
gcc -o output main.c -lfun
/usr/bin/ld: cannot find -lfun
collect2: ld returned 1 exit status
4. Compile with giving path of shared library
gcc -L/home/sujin/shared/ -Wall -o output main.c -lfun
5. Run the program
./output 
./output: error while loading shared libraries: libfun.so: cannot open shared object file: No such file or directory
6. Check current LD_LIBRARY_PATH. 
echo $LD_LIBRARY_PATH
7. If LD_LIBRARY_PATH is not current working directory or empty then set the LD_LIBRARY_PATHS as current working directory
LD_LIBRARY_PATH=/home/sujin/shared:$LD_LIBRARY_PATH
8. Run the program
./output 
./output: error while loading shared libraries: libfun.so: cannot open shared object file: No such file or directory
9. Export the LD_LIBRARY_PATH. In linux we need to export the changes in the environment variable
export LD_LIBRARY_PATH=/home/sujin/shared/:$LD_LIBRARY_PATH
10. Run the program
./output
25
35
30
25

Implementing switch using function pointer in C

PROGRAM : 
#include <stdio.h>
int add(int, int);
int sub(int, int);
int mul(int, int);
int div(int, int);
 
int add(int var1, int var2)
{
    return var1 + var2;
}
 
int sub(int var1, int var2)
{
        return var1 - var2;
}
 
int mul(int var1, int var2)
{
        return var1 * var2;
}
 
int div(int var1, int var2)
{
        return var1 / var2;
}
 
int main(int argc, char **argv)
{
        int (*fun_table[4]) ();
        int result = 0, var1 = 0, var2 = 0, choice = 0;
        fun_table[0] = add;
        fun_table[1] = sub;
        fun_table[2] = mul;
        fun_table[3] = div;
        printf("\nSelect : 1.add 2.sub 3.mul 4.div\n\n");
        printf("Enter your choice : ");
                scanf("%d", &choice);
                if(choice <= 4){
                        printf("\nEnter the first variable  : ");
                        scanf("%d", &var1);
                        printf("Enter the second variable : ");
                        scanf("%d", &var2);
                
                        result = (*fun_table[choice-1])(var1, var2);
                        printf("\nResult = %d\n\n", result);
                }
                else
                        printf("\nInvalid choice\n\n");
        return 0;
}
OUTPUT :
Select : 1.add 2.sub 3.mul 4.div

Enter your choice : 1

Enter the first variable  : 23
Enter the second variable : 20

Result = 43