Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <signal.h>
#include <sched.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
volatile int g_other_process_found_it = 0;
volatile int firstToEnd = 0;
struct args {
char pathname[4096];
char keyString[256];
};
typedef struct args Args;
void replaceChar(char *str, char old, char new)
{
while (*str!='\0')
{
if (*str==old)
{
*str=new;
}
str++;
}
}
void handlTERM(int signo)
{
++g_other_process_found_it;
printf("SIGTERM received by %d.\n",(int)getpid());
}
void handlerUSR1(int signo)
{
printf("SIGUSR1 received from %d\n",(int)firstToEnd);
}
void printfilecontent(int fd)
{
lseek(fd,0,SEEK_SET);
char ch;
while (read(fd,&ch,1)==1)
{
printf("%c",ch);
}
}
int clone_func(void *arguments)
{
Args *a=(Args *) arguments;
pid_t pid=getpid(),ppid=getppid();
char filename[256],scanning[256];
size_t scanlen;
int fd;
*scanning='\0';
strcpy(filename, a->pathname);
replaceChar(filename,'/','_');
printf("I am %d, son of %d, and I'll search for files whose name contains %s into %s. The results of my scan will be available in file '%s'\n",
(int)pid,(int)ppid,a->keyString,a->pathname,filename);
//I register here my handler
struct sigaction saTERM ={.sa_handler=handlTERM};
sigaction (SIGTERM,&saTERM,NULL);
fd = open (filename,O_CREAT|O_WRONLY|O_TRUNC,0666);
if (fd<0)
{
printf("BAD FILE OPEN in CLONE\n");
return 1;
}
struct dirent *entry;
DIR *dir;
struct stat statbuff;
dir=opendir(a->pathname);
if (dir==NULL)
{
printf("BAD OPENDIR. Probably directory doesn't exist\n");
return 1;
}
chdir(a->pathname); //I change the CWD of the process to its target
while (!g_other_process_found_it&&(entry=readdir(dir))!=NULL)
{
sleep(1);
if (lstat(entry->d_name,&statbuff)<0)
{
printf("BAD lstat\n");
return 1;
}
if (S_ISREG(statbuff.st_mode))
{
if (strcmp(".",entry->d_name)!=0 && strcmp ("..",entry->d_name)!=0) //I don't consider . and .. entries
{
//First I do write the filename into the file
strcpy(scanning,entry->d_name);
strcat(scanning,"\n");
scanlen = strlen(scanning);
write(fd,scanning,scanlen);
//then I chech whether I'm finished
if (strstr(scanning, a->keyString))
{
strcpy(scanning,"String found!!\n");
scanlen=strlen(scanning);
write(fd,scanning,scanlen);
//I don't care of coming back to my old CWD
close(fd);
firstToEnd=pid;
kill(ppid,SIGUSR1);// I notify the father
return 0;
}
}
}
}
//The search finished in an unsuccessfull way (file not found or another process found it)
strcpy(scanning,"String NOT found!!\n");
scanlen=strlen(scanning);
write(fd,scanning,scanlen);
close(fd);
return 0;
}
int main (int argc, char *argv[])
{
if (argc<3)
{
printf("usage: filename keystring searchdir1 searchdir2 ...\n");
return 1;
}
int numClones=argc-2;
int *stackClones;
stackClones = malloc(sizeof(int)*1024*numClones);
if (stackClones==NULL)
{
return 1;
}
pid_t *pidClones;
pidClones = malloc (sizeof(pid_t)*numClones);
if (pidClones==NULL)
{
return 1;
}
struct sigaction sa={.sa_handler=handlerUSR1};
sigaction (SIGUSR1,&sa,0);
int i;
Args *ar;
ar=malloc (sizeof(Args)*numClones);
if (ar==NULL)
{
return 1;
}
for (i=0;i<numClones;i++)
{
strcpy(ar[i].pathname,argv[2+i]);
strcpy(ar[i].keyString,argv[1]);
pidClones[i]=clone(clone_func,stackClones+((i+1)*1023)*sizeof(int),CLONE_VM,&ar[i]);
if (pidClones[i]<0)
{
printf("BAD CLONE\n");
return 1;
}
}
pid_t pid;
int j;
//I do wait all the children to finish (supposing that none of them will find the file)
for (i=0;i<numClones;i++)
{
pid=waitpid(-1,NULL,__WCLONE);
if (firstToEnd!=0) break;
printf("CLONE %d ENDED NORMALLY\n",(int)pid);
//Now I set the pid of the normally terminated clone to 0 so that I'll not send a SIGTERM to it in the case another clone will
//find the file
for(j=0;j<numClones;j++)
if (pidClones[j]==pid) pidClones[j]=0;
}
//I am here either because I received a SIGUSR1 either because all the clones terminated
for (i=0;i<numClones;i++)
{
if (pidClones[i]!=firstToEnd&&pidClones[i]>0)
{
kill(pidClones[i],SIGTERM);
printf("SIGTERM sent to %d\n",(int)pidClones[i]);
}
}
printf("PROGRAM TERMINATED\n");
return 0;
}