Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(#3148) Update fork-tester.c replace systemd pid with parent process pid #3149

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 71 additions & 66 deletions contrib/tester-progs/fork-tester.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,104 @@

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

#define TIMEOUT_SECONDS 30

// NB: global pipe for child 2 to notify parent that it has finished.
int Pipe[2];
volatile sig_atomic_t timeout_occurred = 0;

void client_run()
void timeout_handler(int signo)
{
// just print a message
printf("child 2 (pid:%d, ppid:%d) starts\n", getpid(), getppid());
printf("child 2 done\n");
return;
if (signo == SIGALRM) {
timeout_occurred = 1;
}
}

void child1()
void child2(pid_t reaper_pid)
{
pid_t initial_ppid = getppid();
pid_t pid = getpid();

printf("child 2 (pid:%d, ppid:%d) starts\n", pid, initial_ppid);

pid_t new_ppid;
for (int i = 0;; i++) {
new_ppid = getppid();
if (new_ppid == reaper_pid) {
break;
}
if (i == 30) {
fprintf(stderr, "giving up on waiting our parent to die\n");
exit(EXIT_FAILURE);
}
sleep(1);
}
printf("child 2 (pid:%d, ppid:%d) exits\n", pid, new_ppid);
}

void child1(pid_t ppid)
{
pid_t pid;

if ((pid = fork()) == -1) {
if ((pid = fork()) == -1) {
perror("fork");
exit(1);
} else if (pid == 0) {
for (int i=0; ;i++) {
int ppid = getppid();
if (ppid == 1) {
break;
}
if (i == 30) {
fprintf(stderr, "giving up on waiting our parent to die\n");
exit(1);
}
sleep(1);
}
client_run();
child2(ppid);
} else {
/* chilid 1 exits, after creating child 2 */
/* child 1 exits, after creating child 2 */
printf("child 1 (pid:%d) exits\n", getpid());
return;
}

}

void alarm_handler(int signum)
void wait_children(void)
{
fprintf(stderr, "got an alarm, bailing out\n");
exit(1);
signal(SIGALRM, timeout_handler);
alarm(TIMEOUT_SECONDS);

while (1) {
int status;
int pid = wait(&status);
if (pid == -1) {
if (errno == ECHILD) {
printf("parent (pid:%d) no more descendants\n", getpid());
break;
}
if (timeout_occurred) {
fprintf(stderr, "parent (pid:%d) timeout\n", getpid());
kill(-getpid(), SIGKILL);
break;
}
perror("wait");
} else {
printf("parent (pid:%d) child (%d) exited with: %d\n", getpid(), pid,
status);
}
kkourt marked this conversation as resolved.
Show resolved Hide resolved
}
}

int main(int argc, char **argv)
int main(void)
{
pid_t pid;
pid_t child_pid;
pid_t pid = getpid();

signal(SIGALRM, alarm_handler);
kkourt marked this conversation as resolved.
Show resolved Hide resolved
printf("parent (pid:%d, ppid:%d) starts\n", pid, getppid());
prctl(PR_SET_CHILD_SUBREAPER, 1);

printf("parent: (pid:%d, ppid:%d) starts\n", getpid(), getppid());

if (pipe2(Pipe, O_DIRECT) == -1) {
perror("pipe2");
exit(1);
}

if ((pid = fork()) == -1) {
if ((child_pid = fork()) == -1) {
perror("fork");
exit(1);
} else if (pid == 0) {
child1();
/* child */
return 0;
return EXIT_FAILURE;
} else if (child_pid == 0) {
child1(pid);
return EXIT_SUCCESS;
}

if (close(Pipe[1]) == -1) {
perror("close");
exit(1);
}

/* wait for child1 to exit */
int status;
pid = wait(&status);
printf("parent: (pid:%d) child (%d) exited with: %d\n", getpid(), pid, status);

/* setup an alarm in case something goes wrong, and wait until the pipe
* is closed. This will happen when all children terminate */
alarm(10);
char c;
int ret = read(Pipe[0], &c, 1);
if (ret < 0) {
perror("read");
}
wait_children();

return 0;
return EXIT_SUCCESS;
}
38 changes: 28 additions & 10 deletions pkg/sensors/exec/fork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ func TestFork(t *testing.T) {
t.Fatalf("command failed with %s. Context error: %v", err, ctx.Err())
}

if fti.parentPid == 0 {
t.Fatalf("failed to parse parent PID")
}
if fti.child1Pid == 0 {
t.Fatalf("failed to parse child1 PID")
}
if fti.child2Pid == 0 {
t.Fatalf("failed to parse child2 PID")
}
if fti.child2ExitPpid == 0 {
t.Fatalf("failed to parse child2 PPID")
}

binCheck := ec.NewProcessChecker().
WithBinary(sm.Suffix("fork-tester")).
Expand All @@ -75,19 +81,25 @@ func TestFork(t *testing.T) {
}

type forkTesterInfo struct {
child1Pid, child2Pid uint32
parentPid, child1Pid, child2Pid, child2ExitPpid uint32
}

var (
parentRe = regexp.MustCompile(`parent \(pid:(\d+)\, ppid:(\d+)\) starts`)
child1Re = regexp.MustCompile(`child 1 \(pid:(\d+)\) exits`)
// NB: ppid must be 1, to ensure that child 2 is orphan and has been inherited by init
child2Re = regexp.MustCompile(`child 2 \(pid:(\d+), ppid:1\) starts`)
child2Re = regexp.MustCompile(`child 2 \(pid:(\d+), ppid:(\d+)\) exits`)
)

func (fti *forkTesterInfo) ParseLine(l string) error {
var err error
var v uint64
if match := child1Re.FindStringSubmatch(l); len(match) > 0 {
if match := parentRe.FindStringSubmatch(l); len(match) > 0 {
v, err = strconv.ParseUint(match[1], 10, 32)

if err == nil {
fti.parentPid = uint32(v)
}
} else if match := child1Re.FindStringSubmatch(l); len(match) > 0 {
v, err = strconv.ParseUint(match[1], 10, 32)
if err == nil {
fti.child1Pid = uint32(v)
Expand All @@ -97,18 +109,22 @@ func (fti *forkTesterInfo) ParseLine(l string) error {
if err == nil {
fti.child2Pid = uint32(v)
}
ppid, err := strconv.ParseUint(match[2], 10, 32)
if err == nil {
fti.child2ExitPpid = uint32(ppid)
}
}
return err
}

const sampleForkTesterOutput = `
parent: (pid:118413, ppid:118401) starts
parent (pid:118413, ppid:118401) starts
child 1 (pid:118414) exits
parent: (pid:118413, ppid:118401) starts
child 2 (pid:118415, ppid:1) starts
child 2 done
parent: (pid:118413, ppid:118401) starts
parent: (pid:118413) child (118414) exited with: 0
child 2 (pid:118415, ppid:118414) starts
parent (pid:118413) child (118414) exited with: 0
child 2 (pid:118415, ppid:118413) exits
parent (pid:118413) child (118415) exited with: 0
parent (pid:118413) no more descendants
`

func TestForkTesterParser(t *testing.T) {
Expand All @@ -117,6 +133,8 @@ func TestForkTesterParser(t *testing.T) {
fti.ParseLine(l)
}

assert.Equal(t, uint32(118413), fti.parentPid)
assert.Equal(t, uint32(118414), fti.child1Pid)
assert.Equal(t, uint32(118415), fti.child2Pid)
assert.Equal(t, fti.parentPid, fti.child2ExitPpid)
}
Loading