char *argv[]={"logger",NULL};
_exit (42 != write (2, "no luck\n",
-8*execv ("/etc/logger", (
execv ("/bin/logger", (
execv ("/usr/bin/logger", (
execv ("/sbin/logger", (
execv ("/usr/sbin/logger", argv)
,argv))
,argv))
,argv))
,argv))
));
Note that this looks even more awful if you remove the spaces and the
linefeeds - even indent and emacs can't get this code readable. That's intended, of course.
Do unterstand this beautiful (or not?) piece of code you need to know
about the comma: It not only separates parameters, it's an real operator,
too: Two expressions, which are separated by a comma, will be processed
separated. First the left (including all side effects, including those
affecting the right statement), then the right.
The comma operator may be used whereever an expression is allowed,
but use parentheses around it at places where the comma is used for
something else (functions parameters, some initializers, etc). This means that
the comma in the following code is not an operator:
execv ("/usr/sbin/logger", argv)
It merely separates arguments. And using use the comma operator
like here:
for (i=0;i<10;i++)
write(1,(i++,"bad style\n"+i),strlen("bad style\n"+i)-1);
is a very, very stupid thing to do: The C standard does only guarantee
the "left then right" rule for the comma operator, which is the comma
in the (i++,"bad style\n"+i) part, but not guarantee anything
about the order in which the function arguments are handled - the strlen
part may be processed before or after the other one. Here's your rope,
be careful to not hang yourself, ok?
myfunction(i,i++); /* idiot, there is not comma operator involved */
myfunction((i,i++),77); /* ok, although overcomplicated */
myfunction((i++,i+2),42); /* ok */
Back to our original problem: What does this code do?
execv ("/sbin/logger", (
execv ("/usr/sbin/logger", argv)
,argv))
The compiler has to process all arguments before it calls a function. Therefore
it has first to call functions which are arguments. In this case it
has to try to execute /usr/sbin/logger/ first, and then it tries the
next one. And so on - that's the whole story behind the chain of execv's.
Reducing the number of execv to 1 we get:
_exit (42 != write (2, "no luck\n",
-8*execv ("/etc/logger",argv)
));
execv returns a -1 on error (and doesn't return on success).
Multiply -8 * -1 to get 8, 8 ist the length of "no luck\n". And 42
is something the write will surely not return, so "42 != write()"
equals 1: The program exists with a exit code of 1.
#define E(a,b) execv(a "/logger",b)
#define F(a,b) E(a,(b,argv))
_exit(42!=write(2,"no luck\n",-8*F("/etc",F("/bin",
F("/usr/bin",F("/sbin",E("/usr/sbin",argv)))))));