Greg Briggs' Technical Articles | Article Index |
Suppose you have a program that forks into multiple threads or something. Suppose you want to change the argv[0] for each child so you can tell them apart in `ps`, but you didn't know how to. The code to do this is below:
int argv0size = strlen(argv[0]); //Take note of how many chars have been allocated ... strncpy(argv[0],"main-thread-name",argv0size); //replace argv[0][0..argv0size] ... fork(); //make child process ... strncpy(argv[0],"child-thread-name",argv0size); //replace argv[0][0..argv0size] |
Hope this is useful. There is a catch, which is that "ps" and "top" can show you either the "command line" or the "program name", and we can only modify the command line. If you are running top, you can hit the "c" key to switch between which one it shows. On my Linux box, "ps u" shows the command line, but "ps" shows the program name. However, on my Solaris 8 machine, both ps and top refuse to show you the new argv[0], so this technique probably only works on Linux (anyone try any other OSes?).
You'll notice that we save the size of argv[0] at the beginning. This is because its size has already been allocated for us, but if we give the parent thread a short name, we still would like the child thread to take full advantage of the space allocated, rather than assuming the current strlen(argv[0]) is the size limit. We can't just allocate a new string, as assigning argv[0] = "newstring" will not be visible to ps and top.
Here is a test program that renames its child:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> int main(int argc, char **argv) { int argv0size = strlen(argv[0]); sleep(3); strncpy(argv[0],"main",argv0size); sleep(3); pid_t p = fork(); if(p) { strncpy(argv[0],"parent",argv0size); } else { strncpy(argv[0],"child",argv0size); } if(argc>1){ /* The point of this is to show that the child thread still has * the full original size of argv[0] available for use, even * though we reduced the size of argv[0] prior to the fork */ printf("argv[0] at 0x%lX and argv[1] at 0x%lX (difference %d bytes)\n", argv[0],argv[1],argv[1]-argv[0]); } sleep(3); if(!p) _exit(0); //child exits here waitpid(p); exit(EXIT_SUCCESS); //parent exits here } |
If you run the program with an argument, then it will demonstrate the allocation for argv[0]. It will also show you that both processes after the fork still think they are modifying the same memory address, but it is actually different copies of that memory.
"My problem in a nut shell is to start child process that have different command line in a ps listing with the undesired lose of certain resources incurred with using exec()."
"The eventual implementation will be a utility method."
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <alloca.h> int argsLength; char ** args; int child(void) { int ii; fprintf(stderr,"I am child starting\n"); args[0] = "tt -worker"; fprintf(stderr,"I am child sleeping\n"); for(ii = 60;ii = sleep(ii);) ; fprintf(stderr,"I am child terminating\n"); return(0); } // int child(void) int parent(pid_t pid) { int ii; fprintf(stderr,"child %p running\n",pid); fprintf(stderr,"parent is sleeping\n"); for(ii = 60;ii = sleep(ii);) ; fprintf(stderr,"parent is terminating\n"); return(0); } // int parent(void) int main(int argc,char *argv[]) { pid_t pid = -1; int exitCode; char buf[4 * 1024]; int fds[2]; char * bp; int ii; sscanf(basename(argv[0]),"%s",buf); strcat(buf," -ipl "); if (strncmp(argv[0],buf,strlen(buf))) { char *newArgv[2] = {0}; for(*buf=0,bp=buf,ii=1;ii < argc;ii++) bp += sprintf(bp,"%s ",argv[ii]); fprintf(stderr,"starting\n"); ii = strlen(argv[0]) + strlen(buf) + 40; bp = alloca(ii); sprintf(bp,"%s -ipl %-*.*s",argv[0],ii,ii,buf); newArgv[0] = bp; execvp(argv[0],newArgv); exit(99); } else { char *cmd = alloca(strlen(argv[0])); char *arg = alloca(strlen(argv[0])); sscanf(argv[0],"%s -ipl %[^\n]",cmd,arg); for(bp=arg + strlen(arg) -1;bp > arg;bp--) { if (' ' == *bp) *bp = 0; else break; } // for(bp=arg + strlen(arg) -1;bp > arg;bp--) sprintf(argv[0],"%s %s",cmd,arg); fprintf(stderr,"restarting\n"); } // if ((argv[1]) && 79 > strlen(argv[1])) argsLength = argc; args = argv; pid = fork(); if (0 > pid) { perror("fork"); exit(1); } // if (0 > pid) if (!(pid)) { char *cmd = alloca(strlen(argv[0])); char *arg = alloca(strlen(argv[0])); sscanf(argv[0],"%s %[^\n]",cmd,arg); sprintf(argv[0],"%s -child -a -b -etc %s",cmd,arg); child(); } else { char *cmd = alloca(strlen(argv[0])); char *arg = alloca(strlen(argv[0])); sscanf(argv[0],"%s %[^\n]",cmd,arg); sprintf(argv[0],"%s -parent %s",cmd,arg); } // if (!(pid)) parent(pid); wait(&exitCode); return(exitCode); } // int main(int argc,char *argv[]) |
Read more computer-related articles
© 2002-2017 Greg Briggs except where attributed otherwise