It really comes down to what makes up a process in Unix. A process can come into existence in one of 2 ways. Either via the fork()
function or through one of the exec()
functions in C.
fork()
fork()
basically just makes a copy of the current process, but assigns it a new process ID (PID). It's a child of the original process. You can see this relationship in the output of ps
:
$ ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 5255 1964 1964 ? -1 Sl 500 0:39 gnome-terminal
5255 5259 1964 1964 ? -1 S 500 0:00 \_ gnome-pty-helper
5255 18422 18422 18422 pts/1 18422 Ss+ 500 0:01 \_ bash
5255 30473 30473 30473 pts/4 30473 Ss+ 500 0:00 \_ bash
30473 782 782 30473 pts/4 30473 Sl 500 1:14 | \_ evince s.pdf
Here you can see that gnome-terminal
is the parent process (PID = 5255) and that bash
is it's child (PID = 18422, PPID = 5255).
NOTE: PPID = Parent Process ID.
When a process forks from its parent, it "inherits" certain things, such as copies of all the file descriptors that the parent currently has for open files and the parent's user and group IDs.
NOTE: The last 2 are what identify what file and group permissions this process will have when accessing the file system.
So if a process just inherits its user and group ID from its parent, then why isn't everything just owned by root or a single user? This is where exec()
comes in.
exec()
Part #1
The exec()
family of functions, specifically execve()
, "replace" a current process image with a new process image. The terminology "process image" is really just a file, i.e. an executable on disk. So this is how a bash script can execute a program such as /usr/bin/time
.
So what about the user ID and group ID? Well to understand that let's first discuss the concept of "Persona".
Persona
At any time, each process has an effective user ID, an effective group ID, and a set of supplementary group IDs. These IDs determine the privileges of the process. They are collectively called the persona of the process, because they determine "who it is" for purposes of access control.
exec()
Part #2
So in addition to being able to swap out the "process image", exec()
can also change the user & group IDs from the original "real" ones to "effective" ones.
An example
For this demonstration I'm going to show you what happens when we start out in a shell as our default UID/GID, and then spawn a child shell using one of my supplementary GIDs, making it the child shell's effective GID.
To perform this I'm going to make use of the unix command newgrp
. newgrp
allows you to spawn a new shell passing it the supplementary group that I'd like to make my effective GID.
For starters:
$ id -a
uid=500(saml) gid=501(saml) groups=501(saml),502(vboxusers),503(jupiter)
We can see that this shell is currently configured with my default UID/GID of saml
& saml
. Touching some files shows that this is the case as well:
$ touch afile1
$ touch afile2
$ ls -l
total 0
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile1
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile2
Now we make our supplementary group jupiter
the effective GID:
$ newgrp jupiter
$ id -a
uid=500(saml) gid=503(jupiter) groups=501(saml),502(vboxusers),503(jupiter)
Now if we touch some files:
$ touch afile3
$ touch afile4
$ ls -l
total 0
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile1
-rw-rw-r-- 1 saml saml 0 May 21 23:47 afile2
-rw-r--r-- 1 saml jupiter 0 May 21 23:49 afile3
-rw-r--r-- 1 saml jupiter 0 May 21 23:49 afile4
We see that the shell's effective GID is jupiter
, so any interactions with the disk result in files being created with jupiter
rather than my normal default group of saml
.
References
It looks to me as if you are trying to replace a RUNNING process from OUTSIDE the process. That's some radical stuff.
When I first looked at the question, it seemed that you are looking exactly for exec
. But exec
is called by the program itself. So unless you have coded the process so that you can force it to just exec another process, you can't do that while it is running.
You could potentially create a signal trap in your Program-A to exec
a program with predefined name (which you can then set to be whatever you want) and then use kill
on this process to force it to exec
. From the outside, it will look like the process kept running - it does, it just becomes someone else. However, if you haven't done that and you want to do this on a running process, I don't think you can do anything.
However, if the outer shell is running, but it hasn't started the critical process yet, you can just replace the file of the problematic process.
Best Answer
This was implemented to the Linux kernel 3.4 as a flag of the system call prctl().
From the
prctl(2)
manpage:A process can define itself as a subreaper with
prctl(PR_SET_CHILD_SUBREAPER)
. If so, it's notinit
(PID 1) that will become the parent of orphaned child processes, instead the nearest living grandparent that is marked as a subreaper will become the new parent. If there is no living grandparent,init
does.The reason to implement this mechanism was that userspace service managers/supervisors (like
upstart
,systemd
) need to track their started services. Many services daemonize by double-forking and get implicitly re-parented to PID 1. The service manager will no longer be able to receive theSIGCHLD
signals for them, and is no longer in charge of reaping the children withwait()
. All information about the children is lost at the moment PID 1 cleans up the re-parented processes. Now, a service manager process can mark itself as a sort of "sub-init", and is now able to stay as the parent for all orphaned processes created by the started services. AllSIGCHLD
signals will be delivered to the service manager.In Linux, a daemon is typically created by forking twice with the intermediate process exiting after forking the grandchild. This is a common technique to avoid zombie processes. The init script calls a child. That child forks again and thus exits immediately. The grandchild will be adopted by
init
, which continuously callswait()
to collect the exit status of his children to avoid zombies. With the concept of subreapers, the userspace service manager now becomes the new parent, instead ofinit
.