/*
Program  : watchd
Created  : 20.08.2001
Modified : $Date: 2005/05/10 04:08:15 $
Author   : Peter Turczak <p_turczak@wiwa.de>
Syntax   : watchd

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define __USE_BSD

#include <sys/types.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "inifile.h"
#include "chain.h"
#include "filedb.h"

#define FL_ACT_CHANGE		1
#define FL_ACT_EXISTENCE	2
#define FL_ACT_NOMOVE		4
#define FL_ACT_COPY		8
#define FL_ACT_DELETE		16

#define FL_LOG_SYSLOG		64
#define FL_LOG_FILE		128
#define FL_LOG_MAIL		256
#define FL_LOG_ALWAYS		512

typedef struct Twatchfolder 
		{
		 char* runprg;
		 char* dir;
		 element *filechain;
		 uid_t user;
		 
		 int flags;
		 char *notify;
		 char *logfile;
		
		 int gracetime;          // Remaining time 'till scanchain
		 int interval, curcount; // Interval will stay constant, 
		 			 // curcount-- until exec then curcount=interval
		} Twatchfolder;

Twatchfolder defaultfolder;
Twatchfolder *curfolder=&defaultfolder;
element *folders; //Chain of folders

int interval=1; // Global rescan interval in seconds
int timeofgrace;// Time in intervals between calls to scanchain 
char *tmpdir;   // Directory where the processing dirs are created. Default=/tmp
char *mvprg;    // Program that is used to move the files around. Default=mv 
char *cpprg;    // Program that is used to move the files around. Default=cp 
char *rmprg;    // Program that is used to remove the files. Default=rm 

char *config_file = NULL;

static char default_config_filename[] = "/usr/local/etc/watchd.conf";

#ifdef HAS_NO_MKSTEMP
int mkstemp(char *template)
{
int r;
char *dir=strdup(template);
char *prefix=NULL;

if (strrchr(dir, '/')!=0)
 {
  file=strrchr(dir, '/');
  file=0x00;
  file++;
  
  if (strstr(file, "XXXXXX"))
   {
    (strstr(file, "XXXXXX"))[0]=0x00;
   }
 }
r=open(tempnam(dir, prefix), O_CREAT | O_RDWR | S_IRWXU);

return(r);
}
#endif       

int get_filestate(char *fn)
{
int fd=open(fn,O_RDWR);
             /* l_type   l_whence  l_start  l_len  l_pid   */
struct flock fl = { F_WRLCK, SEEK_SET, 0,       0,     0 };

if (fd>0)
 {
 fl.l_pid = getpid();
 fl.l_type = F_WRLCK;

 if (fcntl(fd, F_SETLK, &fl) == -1) 
  {
   close(fd);
#ifdef DEBUG
   printf("get_filestate(%s)=%d\n",fn,0);
#endif 
  return(0);  
  } else {
   close(fd);
#ifdef DEBUG
   printf("get_filestate(%s)=%d\n",fn,1);
 #endif 
   fl.l_type = F_UNLCK;  /* set to unlock same region */
   if (fcntl(fd, F_SETLK, &fl) == -1) 
    {
    close(fd);
#ifdef DEBUG
    printf("Strange unlock behavior..\n");
#endif
    }
   return(1);
  }
 } else // open() failed...
 { 
   if (isdir(fn))
   {
#ifdef DEBUG
    printf("Directory %s not processed...\n",fn);
#endif
    return(2);
   }
   else 
    return(1);
 }	 

}

int splits(char *s, char* p1, char* p2)
{
 char *equal=strchr(s,'=');
 char *p2tmp;
 int pos1 = (((equal==NULL)||(equal<s))?0:(equal-s)); 

 s[pos1]=0x00;			// Needed, because strncpy is too stupid to 
 				// null-terminate a substring by itself!
 strcpy(p1,"");
 strcpy(p2,"");

 if (pos1==0) return(1); else 
 {
 strncpy(p1, s, pos1+1);
 strcpy(p2, equal+1);

// p2tmp=malloc(strlen(p2));
// strncpy(p2tmp,p2,strlen(p2)-1);
// strcpy(p2,p2tmp);
// free(p2tmp);

 p2tmp=strchr(p2,0xa);		// Not very nice,
 p2[(int)p2tmp-(int)p2]=0x00;	// but in fact: It works ;)

 while (p2[0]==' ') {p2++;}       		     // Again, quick and dirty..
 while (p1[strlen(p1)-1]==' ') {p1[strlen(p1)-1]=0;} // Need to say anything?;)

 #ifdef DEBUG
 printf("split(s='%s',p1='%s',p2='%s',pos1=%d);\n",s,p1,p2,pos1); 
 #endif
 return(0);
 }
 
}

void addfolder(Twatchfolder *f, char *dir, char *prg, uid_t uid, int interval, int flags)
{

if (f==NULL)
 { 
  folders=addelement(&defaultfolder, sizeof(defaultfolder), folders);
  folders=tail(folders);
  curfolder=(Twatchfolder *)folders->cur;
  curfolder->filechain=newchain();
  f=curfolder;
 }
 if (prg!=NULL) f->runprg=strdup(prg);  
 if (dir!=NULL) f->dir=strdup(dir);  
 if (uid!=-1) f->user=uid;
 if (flags!=0) f->flags=flags;
 if (interval!=-1) 
  {
   f->interval=interval;
   f->curcount=interval;
  }
}

int flags2int(char *c)
{
int r=0;
char *i=(char *)malloc(strlen(c)+3);
char *s=i;
char *p;

strcpy(s, c);
strcat(s, " ");

while ((p=strstr(s," "))!=NULL)
 {
  p[0]=0x00;
  if (strncasecmp("CHANGE",s, 6)==0)
   r|=FL_ACT_CHANGE;

  if (strncasecmp("EXIST",s, 5)==0)
   r|=FL_ACT_EXISTENCE;

  if (strncasecmp("COPY",s, 4)==0)
   r|=FL_ACT_COPY;

  if (strncasecmp("DELETE",s, 6)==0)
   r|=FL_ACT_DELETE;

  if (strncasecmp("SYSLOG",s, 6)==0)
   r|=FL_LOG_SYSLOG;
   
  if (strncasecmp("FILELOG",s, 7)==0)
   r|=FL_LOG_FILE;

  if (strncasecmp("MAILLOG",s, 7)==0)
  {
   r|=FL_LOG_MAIL;
   printf("While parsing logfile: Warning: MAILLOG is not yet implemented!\n");
  } 

  if (strncasecmp("ALWAYSLOG",s, 9)==0)
   r|=FL_LOG_ALWAYS;

  #ifdef DEBUG
   printf("flags2int('%s') : parsed '%s', r=%d\n", c, s, r);
  #endif 
  s=++p;
 }

free(i);
return(r);
}

void lowercase(char *c)
{
int i;

for (i=0;i<strlen(c);i++)
 {
  c[i]=tolower(c[i]);
 }
}

void parseequal(char* buf) 
{
 char *tmpc1;
 char *tmpc2;
 char *tmpc3;
 int tmpi;   // a place to store temorary integers ...

 tmpc1=malloc(strlen(buf)+1);
 tmpc2=malloc(strlen(buf)+1);

 splits(buf, tmpc1, tmpc2);
 
 lowercase(tmpc1);      // Drop the case on the left side...
 
 #ifdef DEBUG
 printf("lowercase returned '%s'!\n",tmpc1);
 #endif 
 
 if (strncmp(tmpc1,"prg",3)==0) 
  {
   #ifdef DEBUG
   printf("'prg' line found. Adding program...\n");
   #endif
   addfolder(curfolder, NULL, tmpc2, -1, -1, 0);
  }

 if (strncmp(tmpc1,"dir",3)==0) 
  {
   #ifdef DEBUG
   printf("'dir' line found. Adding directory...\n");
   #endif
   addfolder(curfolder, tmpc2, NULL, -1, -1, 0);
  }
 
 if (strncmp(tmpc1,"uid",3)==0) 
  {
   #ifdef DEBUG
   printf("'uid' line found. Modifying program...\n");
   #endif
   addfolder(curfolder,NULL,NULL,atoi(tmpc2), -1, 0);
  }

 if (strncmp(tmpc1,"flags",5)==0) 
  {
   #ifdef DEBUG
   printf("'flags' line found. Modifying program...\n");
   #endif
   addfolder(curfolder,NULL,NULL, -1, -1, flags2int(tmpc2));
  }

 if (strncmp(tmpc1,"interval",8)==0) 
  {
   #ifdef DEBUG
   printf("'interval' line found. Trying to set interval...\n");
   #endif
   
   tmpc3=tmpc2;
   tmpi=atoi(tmpc3);
   if (tmpi>0) {
   		addfolder(curfolder, NULL, NULL, -1, tmpi, 0);
	       } // set interval if the value is not completely
   		 // brain-damaged!
   #ifdef DEBUG
   printf("set to %d!\n",interval);
   #endif
  }
 
 if (strncmp(tmpc1,"tempdir",7)==0) 
  {
   #ifdef DEBUG
   printf("'tempdir' line found. Trying to set tempdir...");
   #endif
   strcpy(tmpdir,tmpc2);
   if (tmpdir[strlen(tmpdir)-1]!='/') {strcat(tmpdir,"/");}
   #ifdef DEBUG
   printf("set to %s!\n",tmpdir);
   #endif
  }

 if (strncmp(tmpc1,"mv",2)==0) 
  {
   #ifdef DEBUG
   printf("'mv' line found. Trying to set mvprg...");
   #endif
   strcpy(mvprg,tmpc2);
   #ifdef DEBUG
   printf("set to %s!\n",mvprg);
   #endif
  }
   
 if (strncmp(tmpc1,"rm",2)==0) 
  {
   #ifdef DEBUG
   printf("'rm' line found. Trying to set rmprg...");
   #endif
   strcpy(rmprg,tmpc2);
   #ifdef DEBUG
   printf("set to %s!\n",rmprg);
   #endif
  }
   
 if (strncmp(tmpc1,"cp",2)==0) 
  {
   #ifdef DEBUG
   printf("'cp' line found. Trying to set cpprg...");
   #endif
   strcpy(cpprg,tmpc2);
   #ifdef DEBUG
   printf("set to %s!\n",cpprg);
   #endif
  }
   
 if (strncmp(tmpc1,"mail",4)==0) 
  {
   #ifdef DEBUG
   printf("'mail' line found. Trying to set notify...");
   #endif
   curfolder->notify=strdup(tmpc2);
   #ifdef DEBUG
   printf("set to %s!\n",cpprg);
   #endif
  }
   
 if (strncmp(tmpc1,"logfile",7)==0) 
  {
   #ifdef DEBUG
   printf("'logfile' line found. Trying to set logfile...");
   #endif
   curfolder->logfile=strdup(tmpc2);
   #ifdef DEBUG
   printf("set to %s!\n",curfolder->logfile);
   #endif
  }

 free(tmpc1);
 free(tmpc2);
}

void defraglst()
{
// FOO BAR 
}

void parsecommon(inifile *i)
{
 char *s=NULL;
 
 while ((s=ini_nextline(i))!=NULL)
  {
   if (strchr(s, '=')!=NULL)
    parseequal(s);
   free(s);
  }
}

void dumpfolders()
{
element *c=head(folders);

 while (c->next!=NULL)
  {
   c=c->next;
   curfolder=(Twatchfolder *)c->cur;
   if (c->cur!=NULL)
    printf("Will watch dir '%s' for files and run '%s' on them with uid='%d' flags: %d\n",curfolder->dir, curfolder->runprg, curfolder->user, curfolder->flags);
  }
}

void consolidate()
{
element *c=head(folders);

while (c->next!=NULL)
  {
   c=c->next;
   curfolder=(Twatchfolder *)c->cur;
   if (((Twatchfolder *)c->cur)->dir==NULL)
    {
     folders=unchain(c);
     c=head(folders);
    }
  }
}

void init()
{
 inifile *f;
 char *buf;
 int i;

 tmpdir=malloc(1024); 
 strcpy(tmpdir,"/tmp/");
 
 mvprg=malloc(1024); 
 strcpy(mvprg,"/bin/mv");
 
 rmprg=malloc(1024); 
 strcpy(rmprg,"/bin/rm");

 cpprg=malloc(1024); 
 strcpy(cpprg,"/bin/cp");

 
 timeofgrace=30;
 
 defaultfolder.flags=(FL_ACT_EXISTENCE | FL_ACT_COPY | FL_ACT_DELETE);
 defaultfolder.gracetime=timeofgrace;
 defaultfolder.logfile=strdup("/dev/stdout");

 folders=newchain();

 buf=malloc(1024);
 
f=ini_open(config_file);

 if (!f) 
  {
   printf("Error: Could not open /usr/local/etc/watchd.conf (%s) , exiting..\n", strerror(errno));
   
   
   free (defaultfolder.logfile);
   
   free (buf);
   free (cpprg);
   free (rmprg);
   free (mvprg);
   free (tmpdir);
   
   clearlst (folders);
   
   exit(1);
  }
 
 
 #ifdef DEBUG
 printf("Stage 1 : Read common options..\n");
 #endif
 
 i=ini_goto_grp(f, "common");
 if (i!=-1)
  {
   parsecommon(f);
  }

 #ifdef DEBUG
 else printf("Waring: could't read common options\n");
 #endif
 
 
 #ifdef DEBUG
 printf("Stage 2 : Read folders..\n");
 #endif

 ini_rewind(f);
 while ((ini_nextgrp(f)!=-1))
 {
 addfolder(NULL, NULL, NULL, -1, -1, 0);
 if (strcasecmp(f->sts.cur_grp,"common")!=0)
  while ((buf=ini_nextline(f))!=NULL)
   {
    if (strstr(buf,"=")!=NULL) 
      parseequal(buf); 
    free(buf);
   }
 }
  
 ini_close(f);

 consolidate();

 #ifdef DEBUG
  dumpfolders();
 #endif
}

void deinit()
{
element *e=head(folders);
Twatchfolder *w;

#ifdef DEBUG
printf("deinit");
#endif

while (e!=NULL)
 {
  #ifdef DEBUG
   printf(".");
  #endif
  w=(Twatchfolder *)e->cur;
  if (w!=NULL)
   {
    free(w->runprg);
    free(w->dir);
    killfilechain(w->filechain);
   } 
  e=unchain(e); 
 }
 
#ifdef DEBUG
printf("deinited\n");
#endif
}

int run(char* cmd, char* arg1, char* arg2, char* arg3, char* arg4, uid_t uid, int logfd)
{
 char **args;
 int f;
 int r;
 
 #ifdef DEBUG
 printf("run(cmd=%s,arg1=%s,arg2=%s,arg3=%s,arg4=%s)\n",cmd, arg1, arg2, arg3, arg4);
 #endif
 f=fork();
 if (f==0) {
  if (logfd>0) 
  {
   dup2(logfd, STDOUT_FILENO);
   dup2(STDOUT_FILENO , STDERR_FILENO);
   close(logfd);
  } 
  args=malloc(sizeof(args)*5); // allocate ram for 4 arguments...
  args[0]=strdup(cmd);
  args[1]=arg1!=NULL?strdup(arg1):NULL;
  args[2]=arg2!=NULL?strdup(arg2):NULL;
  args[3]=arg3!=NULL?strdup(arg3):NULL;
  args[4]=arg4!=NULL?strdup(arg4):NULL;
  deinit();
  cmd=args[0];
 #ifdef DEBUG
  fprintf(stderr,"forked of, uid=%d...\n", uid);
 #endif
   if (uid!=-1)
    {
     #ifdef DEBUG
     fprintf(stderr, "Doing setuid(%d)...",uid);
     #endif
     if (setuid(uid)!=0)
      {
       #ifdef DEBUG
       printf("failed!\n");
       #endif
       syslog(LOG_WARNING||LOG_DAEMON,"Could not setuid(%d): %s", uid, strerror(errno));
      }
     #ifdef DEBUG
     printf("ok..\n");
     #endif
    }
  #ifdef DEBUG 
  printf("Executing %s...\n", cmd);  
  #endif
  execvp(cmd,args);
  printf("Something went wrong! Could not execute %s... (%s) ",cmd, strerror(errno));
  syslog(LOG_WARNING||LOG_DAEMON,"Could not execute %s",cmd);
  exit(0); // Should never occur, but we are paranoid...
 } else 
 {
 #ifdef DEBUG
  printf("pid of child=%d\n",f);
 #endif
  waitpid(f,&r,0); // wait for process to finish..
 #ifdef DEBUG
  printf("child died: pid=%d return=%d\n", f, r);
 #endif
 }

 return(r);
}

char *prepare_logfd(Twatchfolder *folder, int *fd)
{
int r=-1;
char *name=strdup("/tmp/watchdrun.XXXXXX");

if ((folder->flags & (FL_LOG_SYSLOG|FL_LOG_FILE|FL_LOG_MAIL))!=0)
 {
  r=mkstemp(name);
 }

*fd=r;

return(name);
}

void finalize_logfd(int fd, int r, Twatchfolder *folder, char *logname)
{
int log,l;
char buf[512];
FILE *f;

#ifdef DEBUG
 printf("Entering  finalize_logfd(fd=%i, r=%d, folder, logname='%s');\n", fd, r, logname);
#endif
if (fd>0)
 {
 
  if ((folder->flags&FL_LOG_ALWAYS) | (r!=0))
   {
    if (folder->flags&FL_LOG_FILE)
    {
     log=open(curfolder->logfile, O_CREAT | O_WRONLY | O_APPEND );
     if (log>0)
      {
       lseek(fd, SEEK_SET, 0); // Rewind temp log file..
       snprintf(buf, 511, "Program %s returned %d, stdout/err follows:\n", folder->runprg, r);
       write(log, buf, strlen(buf));
       l=222222;
       while (l>0)
        {
         l=read(fd, buf, 512);
   	 write(log, buf, l);
         }
       if (close(fd))     // Close the tempfile
        {
	 #ifdef DEBUG
	 printf("Error closing fd=%d!\n",fd);
	 #endif
	}
        
       fd=0;
       close(log);
      }
    }
    
    if (folder->flags&FL_LOG_SYSLOG)
     {
      lseek(fd, SEEK_SET, 0); // Rewind temp log file..
      snprintf(buf, 511, "Program %s returned %d, stdout/err follows:\n", folder->runprg, r);
      openlog(folder->runprg, LOG_PID, LOG_DAEMON);
      f=fdopen(fd, "r");
      while (!feof(f))
       {
        if (fgets(buf, 511, f)!=NULL) 
         syslog((r==0)?LOG_NOTICE:LOG_WARNING, "%s\n", buf);
       }
      closelog(); 
      fclose(f);
       if (close(fd))     // Close the tempfile
        {
	 #ifdef DEBUG
	 printf("Error closing fd=%d!\n",fd);
	 #endif
	} 
      fd=0;
     }
     
   }
   
 if (fd!=0) 
  close(fd);
 unlink(logname);  // Kill it!
 }
}

//void processfile(char *file, char *srcdir, char *cmd, uid_t uid)
int processfile(char *file, Twatchfolder *folder)
{
char *complete;
char *srcfile;
char *logname;
struct timeval tp;
Twatchfolder w;
int logfd,r;

memcpy(&w,folder,sizeof(w));

#ifdef DEBUG
 printf("processfile called! (folder=%s, flags=%d\n)\n", w.dir, w.flags);
#endif

complete=malloc(1024);
srcfile=malloc(1024);

strcpy(srcfile,w.dir);
strcat(srcfile,"/");
strcat(srcfile,file);
 
#ifdef DEBUG
 printf("calling checkfile...\n");
#endif

if ((w.flags & FL_ACT_CHANGE)!=0)
 if (checkfile(srcfile, 0, w.filechain)!=2)
 {
  // Happens in case a folder should be watched for changes 
  // an there is no demand of processing
  free(complete);
  free(srcfile);
  return(0);
 }
 
 if ((r=get_filestate(srcfile))==1) {
  syslog(LOG_NOTICE||LOG_DAEMON,"processing %s with %s",file,w.runprg);
  
  if ((w.flags & FL_ACT_COPY)!=0)
  {
   gettimeofday(&tp,NULL);
   sprintf(complete, "%s/watchdtmp.%d%d", tmpdir, tp.tv_sec, tp.tv_usec);
  
   mkdir(complete,0700);
   #ifdef DEBUG
    printf("created tempdir : %s\n",complete);
   #endif

   chown(complete, w.user, 0);
   #ifdef DEBUG
    printf("doing  chown(%d, %d)", w.user, 0);
   #endif
  
   #ifdef DEBUG
    printf("running cp...\n");
   #endif
   run(cpprg,srcfile,complete, NULL, NULL, w.user, -1);
   
   if ((w.flags & FL_ACT_DELETE)!=0)
    {
     #ifdef DEBUG
      printf("running rm...\n");
     #endif
     run(rmprg, srcfile, NULL, NULL, NULL, w.user, -1);
    }
   strcpy(srcfile,complete);
   strcat(srcfile,"/");
   strcat(srcfile,file);
  } 
  
  logname=prepare_logfd(folder, &logfd);
  r=run(w.runprg, srcfile, NULL, NULL, NULL, w.user, logfd);
  finalize_logfd(logfd, r, folder, logname);
  
  if ((w.flags & FL_ACT_COPY) == FL_ACT_COPY)
   run(rmprg,"-rf",complete, NULL, NULL, w.user, -1);
  
  if ((w.flags & FL_ACT_DELETE)!=0)
    run(rmprg,"-rf",srcfile, NULL, NULL, w.user, -1);
   
 } else {
  if (r!=2)
   syslog(LOG_NOTICE||LOG_DAEMON,"file %s is locked, not processed",file,w.runprg);
 }
 free(complete);
 free(srcfile);
 //printf("flushing...\n");
 fflush(stdout);
 fflush(stdin);
 fflush(stderr);
 return 0;

}

int isdir(char *name)
{
 struct stat st;

 #ifdef DEBUG
 printf("isdir(%s)=", name);
 #endif
 
 stat(name, &st);
 if (S_ISDIR(st.st_mode)) { 
 #ifdef DEBUG
   printf("1\n");
 #endif
   return(1); 
  } else { 
 #ifdef DEBUG
   printf("0\n");
 #endif
   return(0); 
   }
}

void processdir(Twatchfolder *f)
{
 DIR* dir=NULL;
 struct dirent *de;
 char* tmpS;
//  int child;
 
 #ifdef DEBUG
  printf("Processing dir '%s' prg='%s' uid='%d' interval='%d' curcount='%d'...\n", f->dir, f->runprg, f->user, f->interval, f->curcount);
 #endif
 if (f->dir!=NULL) dir=opendir(f->dir); else dir=NULL;
 tmpS=malloc(1024);
 if (dir!=NULL) 
  {
   de=readdir(dir);
   while (de!=NULL)
   { 
    if ((strcmp(de->d_name,".")!=0) && (strcmp(de->d_name,"..")!=0))  { // we don't process dirs, yet...
       #ifdef DEBUG
	printf("Processing '%s' (de->d_name).\n ", de->d_name);
       #endif
       processfile(de->d_name,f); 
//       if (isdir(de->d_name)==0) {
         #ifdef DEBUG
         printf("Entering processdir()...");
	 #endif
//         processfile(de->d_name,f->dir,f->runprg, f->user); 
/*	} else
	{
         syslog(LOG_WARNING||LOG_DAEMON,"sorry, cannot read dirs, currently ",folders[n].dir);
	 printf("Found a dir!\n");
	 //processdir(de->d_name);
	} */
      
    } 
     de=readdir(dir);
   }
   closedir(dir);
  } else 
  { printf("Warning: Could not read directory '%s'\n",f->dir); 
    syslog(LOG_WARNING||LOG_DAEMON,"could not read directory %s",f->dir);
  }
  free(tmpS);
}

void sighandler(int signal)
{
 if (signal==SIGHUP) 
  {
   init();  // Reread config file! 
  }
}


int process_args (int argc, char *argv[])
{
	if (argc < 2)
	{
		printf ("Usage: %s [config file]\n", argv[0]);
		config_file = default_config_filename;
		printf ("Using config file: %s\n", config_file);
		
		
//		exit (1);
	}
	else
	{
		config_file = argv[1];
		printf ("Using config file: %s\n", config_file);
	}
	return 0;
}

int main(int argc, char *argv[])
{
//  int i;
 element *c;
 
 process_args (argc, argv);
 
// signal(SIGHUP, sighandler);
 
 init();
 
 #ifndef DEBUG
 if (fork()==0) {
 #endif
 while (1) 
 { 
 c=head(folders);
  while (c->next!=NULL)
  {
   c=c->next;
   if (c->cur!=NULL)
    {
     if (((Twatchfolder *)c->cur)->gracetime--<1)
      {
       #ifdef DEBUG
        printf("scanchain()\n");
       #endif
       ((Twatchfolder *)c->cur)->filechain=scanchain(((Twatchfolder *)c->cur)->filechain);
       ((Twatchfolder *)c->cur)->gracetime=timeofgrace;
      }
     if (((Twatchfolder *)c->cur)->curcount--<1)
      {
       processdir((Twatchfolder *)c->cur);
       ((Twatchfolder *)c->cur)->curcount=((Twatchfolder *)c->cur)->interval-1;
      } 
    } 
  }
  sleep(interval);
 }
 #ifndef DEBUG
 }
 return(0); 
 #endif 
}


syntax highlighted by Code2HTML, v. 0.9.1