/* Program : watchd Created : 20.08.2001 Modified : 25.09.2002 Author : Peter Turczak 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 #include #include #include #include #include #include #include #include #include #include #include #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 typedef struct Twatchfolder { char* runprg; char* dir; element *filechain; uid_t user; int flags; 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 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 *rmprg; // Program that is used to remove the files. Default=rm int nolock(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 }; fl.l_pid = getpid(); fl.l_type = F_WRLCK; if (fcntl(fd, F_SETLK, &fl) == -1) { #ifdef DEBUG printf("nolock(%s)=%d\n",fn,0); #endif return(0); } else { #ifdef DEBUG printf("nolock(%s)=%d\n",fn,1); #endif fl.l_type = F_UNLCK; /* set to unlock same region */ if (fcntl(fd, F_SETLK, &fl) == -1) { #ifdef DEBUG printf("Strange unlock behavior..\n"); #endif } return(1); } } int splits(char *s, char* p1, char* p2) { char *equal=strchr(s,'='); char *p2tmp; int pos1 = (((equal==NULL)||(equalcur; curfolder->filechain=newchain(); curfolder->flags=0; f=curfolder; } if (prg!=NULL) f->runprg=strdup(prg); f(tchfolderir!=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; #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;i0) { 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",7)==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",7)==0) { #ifdef DEBUG printf("'rm' line found. Trying to set mvprg..."); #endif strcpy(rmprg,tmpc2); #ifdef DEBUG printf("set to %s!\n",rmprg); #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"); folders=newchain(); buf=malloc(1024); f=ini_open("/etc/watchd.conf"); if (!f) { printf("Error: Could not open /etc/watchd.conf (%s) , exiting..\n", strerror(errno)); 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 } void run(char* cmd, char* arg1, char* arg2, char* arg3, char* arg4, uid_t uid) { char **args; int f; #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) { deinit(); args=malloc(sizeof(args)*5); // allocate ram for 4 arguments... args[0]=cmd; args[1]=arg1; args[2]=arg2; args[3]=arg3; args[4]=arg4; #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 } 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,NULL,0); // wait for process to finish.. #ifdef DEBUG printf("child died: pid=%d\n",f); #endif } } //void processfile(char *file, char *srcdir, char *cmd, uid_t uid) void processfile(char *file, Twatchfolder *folder) { char *complete; char *srcfile; struct timeb tp; Twatchfolder w; memcpy(&w,folder,sizeof(w)); #ifdef DEBUG printf("processfile called! (folder=%s, flags=%d\n", w.dir, w.flags); #endif complete=malloc(255); srcfile=malloc(255); strcpy(srcfile,w.dir); strcat(srcfile,"/"); strcat(srcfile,file); if (folder->flags != FL_ACT_CHANGE) { if (nolock(srcfile)) { syslog(LOG_NOTICE||LOG_DAEMON,"processing %s with %s",file,w.runprg); ftime(&tp); sprintf(complete, "%s/watchdtmp.%d%d", tmpdir, tp.time, tp.millitm); mkdir(complete,0700); #ifdef DEBUG printf("created tempdir : %s\n",complete); #endif #ifdef DEBUG printf("runing mv...\n"); #endif run(mvprg,srcfile,complete, NULL, NULL, w.user); strcpy(srcfile,complete); strcat(srcfile,"/"); strcat(srcfile,file); run(w.runprg,srcfile, NULL, NULL, NULL, w.user); run(rmprg,"-rf",complete, NULL, NULL, w.user); } else { 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); } else // So, flags==FL_ACT_LEAVE { #ifdef DEBUG printf("calling checkfile...\n"); #endif if (checkfile(srcfile, 0, w.filechain)==2) { syslog(LOG_NOTICE||LOG_DAEMON,"processing %s with %s",file,w.runprg); run(w.runprg,srcfile, NULL, NULL, NULL, w.user); } free(complete); free(srcfile); //printf("flushing...\n"); fflush(stdout); fflush(stdin); fflush(stderr); } } int isdir(char *name) { struct stat *st; #ifdef DEBUG printf("isdir(%s)=", name); #endif st=malloc(sizeof(stat)); stat(name, st); if (S_ISDIR(st->st_mode)) { free(st); #ifdef DEBUG printf("1\n"); #endif return(1); } else { free(st); #ifdef DEBUG printf("0\n"); #endif return(0); } } void processdir(Twatchfolder *f) { DIR* dir; 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); } } 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); closedir(dir); } void sighandler(int signal) { if (signal==SIGHUP) { init(); // Reread config file! } } int main(int argc, char *argv[] ) { int i; element *c; // 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)->curcount--<1) { processdir((Twatchfolder *)c->cur); ((Twatchfolder *)c->cur)->curcount=((Twatchfolder *)c->cur)->interval-1; } } } sleep(interval); } #ifndef DEBUG } return(0); #endif }