No, we are not debating how to hack who will succeed Queen Elizabeth II to the throne here, sorry. What we are referring to is this: How can you correctly specify the name of the successor process; that is, can we programmatically change it to whatever we like?
At first glance, it looks trivial indeed: The second parameter to the execl is the argv[0] argument to pass to the successor; in effect, it appears, its name! So, let's try it out: We write a couple of C programs; the first one, the predecessor (ch9/predcs_name.c) is passed a name parameter from the user. It then execs another program of ours, successor_setnm via the execl passing along the user-supplied name as the first parameter (within the API, it sets the successor argv[0] parameter to the predecessor's argv[1]), like so: execl("./successor_setnm", argv[1], argv[1], (char *)0);
Recall the execl syntax: execl(pathname_to_successor_program, argv0, argv1, ..., argvn, 0);
So, the thinking here is: The predecessor has set the successor's argv[0] value to argv[1], and thus the successor's name should be the predecessor's argv[1]. However, it does not work out; see the output from a sample run:
$ ./predcs_name
Usage: ./predcs_name {successor_name} [do-it-right]
$ ./predcs_name UseThisAsName &
[1] 12571
UseThisAsName:parameters received:
argv[0]=UseThisAsName
argv[1]=UseThisAsName
UseThisAsName: attempt to set name to 1st param "UseThisAsName" [Wrong]
UseThisAsName: pausing now...
$
$ ps
PID TTY TIME CMD
1392 pts/0 00:00:01 Bash
12571 pts/0 00:00:00 successor_setnm
12576 pts/0 00:00:00 ps
$
We deliberately have the successor process invoke the pause(2) system call (it simply causes it to sleep until it receives a signal). This way, we can run it in the background, and then run ps to lookup the successor PID and name!
Interesting: We find that, though the name is not what we want in ps output (above), it is correct in the printf; implying that argv[0] has been correctly received and set to the successor.
OK, we must clean up; lets kill off the background process now:
$ jobs
[1]+ Running ./predcs_name UseThisAsName &
$ kill %1
[1]+ Terminated ./predcs_name UseThisAsName
$
So, as is now apparent, what we've done preceding is not enough: To reflect the name we want at the level of the OS, we need an alternate API; one such API is the prctl(2) system call (or even the pthread_setname_np(3) pthreads API). Without getting into too much detail here, we use it with the PR_SET_NAME parameter (as usual, please see the man page on prctl(2) for full details). Hence, the correct code using the prctl(2) system call (only the relevant code snippet from successor_setnm.c is displayed here):
[...]
if (argc == 3) { /* the "do-it-right" case! */
printf("%s: setting name to "%s" via prctl(2)"
" [Right] ", argv[0], argv[2]);
if (prctl(PR_SET_NAME, argv[2], 0, 0, 0) < 0)
FATAL("prctl failed ");
} else { /* wrong way... */
printf("%s: attempt to implicitly set name to "%s""
" via the argv[0] passed to execl [Wrong] ",
argv[0], argv[1]);
}
[...]
$ ./predcs_name
Usage: ./predcs_name {successor_name} [do-it-right]
$
So, we now run it the right way (the logic involves passing along an optional second parameter which will be used to _correctly_ set the successor process name):
$ ./predcs_name NotThis ThisNameIsRight &
[1] 12621
ThisNameIsRight:parameters received:
argv[0]=ThisNameIsRight
argv[1]=NotThis
argv[2]=ThisNameIsRight
ThisNameIsRight: setting name to "ThisNameIsRight" via prctl(2) [Right]
ThisNameIsRight: pausing now...
$ ps
PID TTY TIME CMD
1392 pts/0 00:00:01 Bash
12621 pts/0 00:00:00 ThisNameIsRight
12626 pts/0 00:00:00 ps
$ kill %1
[1]+ Terminated ./predcs_name NotThis ThisNameIsRight
$
This time it works exactly as expected.