select() vs pselect()
All this time I had thought pselect() is simply a luxury, a waste of system call entry, something that i never expected from open source community. I should have blamed POSIX for introducing such a one, but, why would any open source operating system implement it. If you ever wanted to block a set of signal, just calling sigprocmask() before select would be sufficient.
This is where the need for ‘!’ operator helps. ie, right, pselect() is not meant for blocking signals, but rather to unblock them
. Such a requirement arises out in event loops, which normally anyone would expect to be implemented as:
while(1)
{
if(need_to_quit)
break;
if(select(…) == -1)
{if(errno == EINTR)
continue;
…
}
…
}
and in the SIGQUIT signal handler you would write :
sigquit_handler()
{
need_to_quit = 1;
}
The problem with such an approach is that if the event comes and get handled after the global volatile variable ‘need_to_quit’ is checked, but before select() is called, then the event loop would behave as if it has lost the event, and the select() will block till we again get an event.
POSIX recommends the solution to be to use pselect(). Now, how to use it would be what you are thinking, so, here it goes:
step 1 : you block all signals and save the current sigmask
step 2 : check the event condition and do what is required
step 3 : call pselect() and pass it a signal mask to enable all the signals that would provide you the events. when pselect() returns, it will restore the sigmask it had when it was entered(ie, here all the signals masked).
step 4 : you restore the old signal mask
thats it, the race condition is solved. This now makes sure that any signal that comes after checking the variable will be received only after select() has entered. You might now be wondering why we can not do the same thing by writing our own function than a system call. Well here is how it would look :
pselect(..)
{
sigprocmask(.., &new_mask, &old_mask); // enable the signals to be received
select();
sigprocmask(.., &old_mask, null);
}
YES.. If you have noticed, this still gives you a race condition when a signal arrives before select() is called and gets handled immediately after we set new_mask. So, this is the trick with pselect() : Once you call a system call(enter kernel space), you can not be interrupted by anyone else. ie, you can stay in the kernel mode as long as you want; inside the implementation of the system call, we can sleep on blocking functions which can get unblocked on signals if and only if the programmer wishes to do so.
So, the above shown code works when we place it in as a system call; being in kernel mode is itself enough to prevent the race condition
. So, if we are using pselect(), this is how our event loop will look like :
sigset_t new_set, old_set;
int ret;
sigfillmask(&new_set);
sigprocmask(.., null, &old_set);
while(1)
{
sigprocmask(.., &new_set, null);
if(need_to_quit)
break;
ret = pselect(.., &old_set) ;
sigprocmask(.., &old_set, null);
if(ret == -1)
{if(errno == EINTR)
continue;
…
}
…
sigprocmask(.., &old_set, null);
}
Reversing a linked list
So again, here is how you can reverse a singly-linked list :
reverse(struct node ** start)
{
struct node * prev = NULL;
struct node * curr = *start;while(curr)
{swap(&prev, &curr->next);
swap(&curr, &prev);}
*start = prev;
}
and here is for a doubly-linked list :
reverse(struct node **start)
{
struct node *curr = *start;
while(curr)
{swap(&curr->prev, &curr->next);
if(!curr->prev)*start = curr;
curr = curr->prev;
}
}
Power of 2
This is out of popular request.. nothing special about it. Below is a func that tells you whether the given number is a power of 2 :
int isPower(int i)
{
return !(i & (-i ^ i));
}
A game with array
Hi … I know that its been too long since I had last posted into my blog and the main reason for that was a lack of interesting topic to discuss on my page. But last day I happen to meet a person(named Rajesh) who coined a simple question of re-ordering numbers in an array.
The situation is like this: we have an array of integers which contains randomly ordered numbers. We would wanna move all odd numbers to the beginning of the array and the even numbers to the end – still the ordering doesn’t matter. Below is the code that I believe would do the job in the least number of iterations:
int arr[]={1,2,3,4,5,6,7,8,9,10};
swap(int *p, int *q)
{
*p = *p ^ *q;
*q = *p ^ *q;
*p = *p ^ *q;
}
int checkeven(int value)
{
return !(value & 0x1);
}
int checkodd(int value)
{
return (value & 0x1);
}
int *find(int *start, int *end, int step, int (*cond)(int) )
{
while(((step > 0) && (start <= end)) || ((step < 0) && (end <= start)))
{if(cond(*start))
break;
start += step;
}
return start;
}
reorder(int *start, int size)
{
int *end = start + size - 1;
while(1)
{// find an even no. starting from the front
start = find(start, end, 1, checkeven);//find an odd no. starting from the back
end = find(end, start, -1, checkodd);if(start >= end)
break;
swap(start, end);
}
}
main()
{
reorder(arr, sizeof(arr)/sizeof(arr[0]));
}
Listing out the sysconf() values
Ever wondered how you could list out the defined sysconf() arguments constants and the sysconf() values for them. Well here is a simple bash script that worked for me:
#!/bin/bash
rm -f test.c
echo “#include <unistd.h>” >> test.c
echo “#include <stdio.h>” >> test.c
echo “main()” >> test.c
echo “{” >> test.c
for x in `echo “#include <unistd.h>” | cpp | grep _SC_ | cut -d ‘,’ -f 1 | awk ‘{print $1}’`
do
echo “printf(\”$x : %d\\n\”, sysconf($x));” >> test.c
done
echo “}” >> test.c
gcc test.c -o test
./test
rm -f test{,.c}
ati-drivers on gentoo linux
So with much hard work I have successfully installed the great gentoo linux on my laptop (thanks to the LFS; it was a very useful experience). Unfortunately I have an amd turion based system and many packages in the gentoo portage still are masked with ~amd64 keyword. But, still I could install the complete gentoo without much trouble except with the display hardware which is the ATI Radeon XPRESS 200.
As usual, I did an emerge on the ati-drivers package which gave me pretty much all the normal output except the following:
————————— ACCESS VIOLATION SUMMARY —————————
LOG FILE = “/var/log/sandbox/sandbox-x11-drivers_-_ati-drivers-8.32.5-11100.log”
open_wr: /usr/src/linux-2.6.19-gentoo-r5/-.gcda
open_wr: /usr/src/linux-2.6.19-gentoo-r5/-.gcda
——————————————————————————–
With a lot of googling, I found that problem is with the sandbox USE flag and the solution seem to be adding the following lines to the /etc/portage/package.use :
x11-drivers/ati-drivers -sandbox -usersandbox
I hope this information would be useful to someone else too..
bye..
Macro arguments – be careful with them
Debugging applications that has lots of macro()s are considered to be very tough. And it seems that most people prefer to expand macros as blocks with new temporary variables. Let us try to find out why one would not prefer to use the macro arguments directly in their block code. Consider for example a macro that returns the square of a number. Normally, any careful programmer would write the macro as given below:
#define square(a) ((a) * (a))
And yes, what the macro will do is precisely what we would expect of it. The above macro is just perfect as long as what we provide as argument to it is a plain value – like a variable or a constant. For example:
int i = 10;
printf("square : %d\n", square(i));
would print 100 as we had desired. The preprocessed text is just the expression ((i) * (i)). This will continue to go on fine until you start to do some fancy tricks like the following:
int i = 10;
printf("square : %d\n", square(++i));
Obviously, what we had expected was the square of 11 but the one we got was that of 12(for gcc, can change for others). So, how did that happen? Yes.. after preprocessing, your code became ((++i) * (++i)) and according to gcc, the values of i used in the expression is that after doing all the pre-increments in the expression. Since there are 2 pre-increments, the compiler takes the expression as ((12) * (12)).
Apart from the wrong answer we got, another side effect that we have to acknowledge is that the variable i has been incremented twice after calling square(), instead of just once. So, what is the solution for such a situation? Simple, use only dummy variables for computations:
#define square(a) ({ typeof(a) var=(a); var*var; })
so thats it ! you dont need to worry at all about the new variable that you have created above – compilers are intelligent enough to nullify its overhead. Well, so now our problem is solved
we can create new ones
The essence of do{ } while(0)
This is something that I’ve been longing to document in my blog. Many times I have wondered why almost all the #define macros in linux kernel is made up of do-while blocks rather than simple {} blocks. The reason is illustrated below:
Consider for example a swap() macro defined in the two different ways as shown below:
#define swap(a,b) { \
typeof(a) tmp; \
tmp=a; a=b; b=tmp; \
}
and
#define swap(a,b) do { \
typeof(a) tmp; \
tmp=a;a=b;b=tmp; \
} while(0)
At a glance both seem to do the same job of creating a new block of code where the variable tmp is created and the values a and b are swapped through it. And they both will work similarly under all circumstances except the following:
if(a<b)
swap(a,b);
else
printf("a is already greater than b\n");
The above code when using the first form of swap() macro will expand as following:
if(a<b)
{
typeof(a) tmp;
tmp=a;a=b;b=tmp;
}
;
else
printf("a is already greater than b\n");
The issue here is that the semicolon (;) that we have put after swap() infact terminates the if block and remains as an empty statement. This causes the else keyword not to be attached to the if block anymore and will cause a compilation error saying that the else keyword is misplaced. huh !
Anyway, good that we got a workaround for this problem, otherwise writing system software would have become a hell
. By the way, if you are using gcc, you can use ({ }) blocks as well which would be very much helpful if your macro needs to return some value
– the return value is the last evaluated expression.
‘Expect’ as an administration tool
This is an article that I had posted in my livejournal on 6th-May-2006 06:58 pm. I’m trying to migrate the most valuable stuff to wordpress.
Last time we saw how to execute those special system tools(ssh, ftp, su, …) by providing the password through PTYs. But, the problem is that its not easy or ideal at all to write a C program to do such system maintenance or automation tasks. Also, if we need to process the output of the running child program and respond it with dynamic inputs, the task becomes very complicated. Then, the obvious guess would be… right, a script. Today, we’re going to see how ‘Expect’ can be used to do our task with ease.
Expect can be thought of as a tool which can run other programs in a PTY with the knowledge of what to expect from the child program. ie, Expect can be told how to behave towards the child program for its various outputs. And its being done through a script similar to Tcl. Unfortunately, I don’t know Tcl at all, but certainly know how to use expect for my needs. So here’s the code that does what we required when we wrote the last C program – ptymagic.c:
#!/usr/bin/expect
spawn [lrange $argv 0 0] [lrange $argv 1 $argc]
expect {
“Password:” {
expect_user -re “(.*)\n”
send_user “\n”
send “$expect_out(1,string)\r”
exp_continue}
}
Suppose you name the file as ptymagic, and give execute permission for the same, test it as we did previously:
echo “Your_Root_Password” | ./ptymagic su -c “cat /etc/shadow”
May be it’ll seem slow, but hey, we are here to write maintenance script for the system and not any scientific supercomputing simulations…
best of luck…
Using PTYs to fool getpass()
This is an article that I had posted in my livejournal on 4th-May-2006 03:08 pm. I’m trying to migrate the most valuable stuff to wordpress.
Today we’ll discuss the getpass() library function and the hurdles it presents for a system administrator for system automation. The usual bash pipe (‘|’) wont help us in providing password for tools like ssh, ftp, su, etc. The main reason is the way in which getpass works to get the password from the terminal. Unlike other library routines like getchar() or scanf() which read from stdin, this one opens the /dev/tty to read the user input.
The only solution been provided to overcome this is to create pseudo terminals(pty) and run your application in that. One of the most useful of the various functions used for this is forkpty(). Yes, here I’m talking about writing your own program to create a new pty, fork and run its child in that pty, and exec the application(like ssh, ftp,…) in the child. You will get a file descriptor which can be used to read or write data to the pty(ie, the application i/o). Below is given a program that tries to make a connection between you and your application.
// ptymagic.c
#include <pty.h>
#include <utmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int readtunnel(int pty) // thread for reading from appl
{
char ch;
while(read(pty,&ch,1) != -1)
write(1,&ch,1);
}
int writetunnel(int pty) // thread for writing to appl
{
char ch;
while(read(0,&ch,1))
write(pty,&ch,1);
}
main(int argc, char **argv)
{
int pty,child;
int ret;
pthread_t pread,pwrite;if(argc < 2)
{
exit(-1);
}
child = forkpty(&pty,0,0,0);
if(!child)
{
struct termios tios;tcgetattr(0, &tios);
tios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
tios.c_oflag &= ~(ONLCR);
tcsetattr(0, TCSANOW, &tios);execv(argv[1],&argv[1]);
exit(-1);
}
if(child == -1)
exit(-1);
read(pty,&ret,1); // wait till the child has outputted atleast one character
write(1,&ret,1);pthread_create(&pread,0,readtunnel,pty);
pthread_create(&pwrite,0, writetunnel,pty);pthread_join(pread,0);
wait(&ret);
if(ret >= 0 && ret <= 255)
exit(ret);
exit(-1);
}
Compile the program as:
gcc -l pthread -l util -o ptymagic ptymagic.c
And try to run as:
echo “Your_Root_Password” | ./ptymagic su -c “cat /etc/shadow”
and see the magic.
Here, the defect is that we have to write a c program for every different kind of application which is going to be a tedious task. A better alternative is also there about which I’ll explain later.
Till then,
BYE.