#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

#define PID_MISM	0x01
#define PPID_MISM	0x02
#define PGRP_MISM	0x04
#define SID_MISM	0x08

int eq_sid = 0, eq_pgrp = 0, eq_ppid = 0;

parse_credentials(int ret, char *name,pid_t pid, pid_t ppid, pid_t pgrp, pid_t sid){
	char buf[256];
	int len = 0;
	len += sprintf(buf,"%s: mismatch in: ",name);
	if( (ret & PID_MISM) )
		len += sprintf(buf + len,"PID(%d,%d) ",pid,getpid());
	if( (ret & PPID_MISM) && eq_ppid )
		len += sprintf(buf + len,"PPID(%d,%d) ",ppid,getppid());
	if( ret & PGRP_MISM && eq_pgrp )
		len += sprintf(buf + len,"PGRP(%d,%d) ",pgrp,getpgrp());
	if( ret & SID_MISM && eq_sid )
		len += sprintf(buf + len,"SID(%d,%d) ",sid,getsid(0));
	printf("%s\n",buf);
}


int check_credentials(pid_t pid, pid_t ppid, pid_t pgrp, pid_t sid)
{
	int ret = 0;
	if( pid != getpid() )
		ret |= PID_MISM;
	if( ppid != getppid() )
		ret |= PPID_MISM;
	if( pgrp != getpgrp() )
		ret |= PGRP_MISM;
	if( sid != getsid(0) )
		ret |= SID_MISM;
	return ret;
}

process(char *name,pid_t *cids, int cnum){
	pid_t pid = getpid();
	pid_t ppid = getppid();
	pid_t pgrp = getpgrp();
	pid_t sid = getsid(0);

	FILE *fp;
	fp = fopen(name,"w");
	fprintf(fp,"pid/spid\tppid/sppid\tsid/ssid\n");
	fclose(fp);
	while(1){
		int ret = 0,i;

		fp = fopen(name,"a");
		fprintf(fp,"%d/%d\t%d/%d\t%d/%d\n",
			getpid(),pid,
			getppid(),ppid,
			getsid(0),sid);
		fclose(fp);
		
		ret = check_credentials(pid,ppid,pgrp,sid);
		if( ret )
			parse_credentials(ret,name,pid,ppid,pgrp,sid);
		for(i=0;i<cnum;i++){
			if( kill(cids[i],0) < 0 ){
				printf("%s: no child #%d\n",i);
			}
		}
		sleep(1);
	}
}

int main()
{
	pid_t p1_cids[3];
	int ret;

	if( !(p1_cids[0] = fork()) ){
		eq_ppid = 1; // after restart we should find the same PPID
		process("p11",NULL,0);
	}

	if( !(p1_cids[1] = fork()) ){
		eq_ppid = 1; // after restart we should find the same PPID
		process("p12",NULL,0);
	}

	if( !(p1_cids[2] = fork()) ){
		// p13
		eq_ppid = 1; // after restart we should find the same PPID
		eq_sid = 1; // after restart we should find the same PPID
		setsid();
		process("p13",NULL,0);
	}
	process("p1",p1_cids,1);
}
