I\'m on Linux and I am forking/execing a new process out of my C spawn application. Is it possible to also change the naming of these new child processes?
I want to
This is a non-portable hack:
/*
* Sets process title, truncating if there is not enough space,
* rather than causing memory corruption.
*/
void set_title_np(int argc, char **argv, const char *title) {
// calculate available size
size_t space = 0;
for (int i = 0; i < argc; i++) {
size_t length = strlen(argv[i]);
space += length + 1; // because of terminating zero
}
memset(argv[0], '\0', space); // wipe existing args
strncpy(argv[0], title, space - 1); // -1: leave null termination, if title bigger than space
}
One of the comments mentions prctl
, but this really deserves its own answer, because setting argv[0]
will not work in all cases (it does nothing on my system).
There are at least two library calls to set the name of a thread in Linux, both limited to 15 characters plus the terminating NUL
byte:
pthread_setname_np(...)
where the np
stands for "non-portable", but this might be present on some other OSes: https://linux.die.net/man/3/pthread_setname_npprctl(PR_SET_NAME...)
which is also non-portable: https://linux.die.net/man/2/prctlHere's a test of the different methods (with no error handling):
// gcc pstest.c -o pstest -O2 -Wall -Wextra -Werror -Wno-unused -Wno-unused-result -std=gnu99 -pthread -D_GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/prctl.h>
int main(int argc, char *argv[])
{
puts("Initial ps output:");
system("ps | grep pstest");
puts("\npthread_setname_np");
pthread_setname_np(pthread_self(), "setname");
system("ps | grep setname");
puts("\nprctl");
prctl(PR_SET_NAME, (unsigned long)"prctl", 0, 0, 0);
system("ps | grep prctl");
puts("\nargv[0]");
argv[0] = "argv0";
system("ps | grep argv0");
return 0;
}
Notice the lack of output after argv[0]
:
./pstest
Initial ps output:
17169 pts/0 00:00:00 pstest
pthread_setname_np
17169 pts/0 00:00:00 setname
prctl
17169 pts/0 00:00:00 prctl
argv[0]
Here's an example in production code (as always, be sure to take note of the license when looking at code on GitHub)
See also these questions and answers:
I think this should work, to illustrate the principle...
#include <stdio.h>
int main(int argc, char *argv[]) {
argv[0][0] = 65;
sleep(10);
}
will change the name, and put an "A" instead of the first letter. CtrlZ to pause, then run ps
to see the name changed. I have no clue, but it seems somewhat dangerous, since some things might depend on argv[0]
.
Also, I tried replacing the pointer itself to another string; no cigar. So this would only work with strcpy
and strings shorter or equal than the original name.
There might or might not be a better way for this. I don't know.
EDIT: nonliteral solution: If you're forking, you know the child's PID (getpid()
in the child, result of fork()
in the parent). Just output it somewhere where you can read it, and kill the child by PID.
another nonliteral solution: make softlinks to the executable with another name (ln -s a.out kill_this_a.out
), then when you exec, exec the link. The name will be the link's name.
According to this comment, prctl(PR_SET_NAME)
only affects the "short name" of a thread. It has the same effect as writing into /proc/self/comm
.
To change the "long name" (/proc/self/cmdline
which is actually used by htop
and ps u
) you need some ugly hack (which is mentioned in that comment but the link is dead). An example of this kind of hack can be found in Chromium source code: https://cs.chromium.org/chromium/src/services/service_manager/embedder/set_process_title_linux.cc?sq=package:chromium&g=0
The below code sample would change the name of the process to "Testing".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
char* temp = (char*) malloc (20);
strcpy(temp, "Testing");
temp[7] = 0;
printf("Argv[0] --> %s\n", argv[0]);
argv[0] = temp;
printf("Argv[0] --> %s\n", argv[0]);
return 0;
}
The output of above program is:
./a.out
Argv[0] --> ./a.out
Argv[0] --> Testing
The argv[0] contains the name of the process.