/* * CHECKDVLNODE.C * * must be run from the top of an EPICS development node * * Reports to stdout: * Regular files in this node that are out-for-edit. * These are errors if uid doesn't agree. * Regular files in this node that should be links to epics * Links that point to a dest. outside of this node and the final * dest. is not in an EPICS node (Note: vw should be excluded). * Other Directories containing Regular files not under sccs control. * These directories should be manually checked for private * Imakefiles/Makefiles ... * * BUGS - only checks final destination of links. * if a link points outside of the current node * but the final real file/directory resides in epics * it is not reported. Then if it is changed in the outside * node you won't know it w/o running this tool again. * * 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. * rcz */ #include #include #include #include #include #include #include #include void procDirEntries(); int processFile(); int getRealEpicsPath(); int checkLink(); int dirwalk(); int verbose; extern int errno; #define BSIZE 128 #define MAXMSG 256 #define TRUE 1 #define FALSE 0 #define SAME 0 static char pdot[] = "SCCS/p."; static char sdot[] = "SCCS/s."; static char msgbuff[MAXMSG]; static caddr_t pEpics = (caddr_t)NULL; static caddr_t pDvl = (caddr_t)NULL; static int lenEpics; static int lenDev; static char *dirList[] = { "share", "Unix", "Vx", "config", "release" }; #define DIR_COUNT (sizeof(dirList) / sizeof(caddr_t)) /**************************************************************************** MAIN PROGRAM ****************************************************************************/ main(argc, argv) int argc; char **argv; { char *getcwd(); char **pt; char name[20]; int i; pt = dirList; if ((argc > 1) && ((strncmp(argv[1], "-v", 2)) == 0)) verbose = TRUE; else verbose = FALSE; if ((pDvl = getcwd((char *)NULL, 128)) == NULL) { fprintf(stdout, "getcwd failed\n"); return; } lenDev = strlen(pDvl); if ((getRealEpicsPath()) < 0 ) return; fprintf(stdout, "\n\n\n%s:\nSTARTING SEARCH FROM NODE: %s\n",argv[0], pDvl); for (i = 0; i < DIR_COUNT; i++, pt++) { strcpy(name, *pt); fprintf(stdout, "Descending node --------------- %s\n",name); procDirEntries(name, name); } return; } /**************************************************************************** GETREALEPICSPATH returns -1 - error, 0 - OK ****************************************************************************/ getRealEpicsPath() { caddr_t pt2; char resolved_path[MAXPATHLEN]; FILE *fp; char *epath_file = ".epicsShadowSrc"; char epath[BSIZE];/* contents of 1st line of p.dot */ if ((fp = fopen(epath_file, "r")) == NULL) { fprintf(stdout, "checkDvlNode: can't fopen %s\n", epath_file); fprintf(stdout, "Probably not at root of shadow node\n"); return(-1); } if ((fgets(epath, BSIZE, fp)) == NULL) { fprintf(stdout, "checkDvlNode: FATAL ERROR - reading %s\n", epath_file); return(-1); } fclose(fp); lenEpics = strlen(epath); if ( epath[lenEpics-1] == '\n' ) { epath[lenEpics-1] = '\0'; } /* reset epics to real path if not on server */ if(( pt2 = (caddr_t)realpath(epath, resolved_path)) == NULL) { fprintf(stdout, "FATAL ERROR - failed link component of %s=%s\n", epath, resolved_path); return (-1); } lenEpics = strlen(pt2); pEpics = (caddr_t)calloc(1,lenEpics+1); strcpy(pEpics,pt2); return(0); } /**************************************************************************** PROCESSFILE for each regular file: if s.dot !exist - skip file if s.dot exist && p.dot !exist - print error else print dir file and contents of p.dot ****************************************************************************/ int processFile(name, dir, pfirstTime) char *name; /* regular file */ char *dir; /* current directory */ int *pfirstTime; /* ptr to firstTime flag*/ { char sccsDir[MAXNAMLEN]; char dotName[MAXNAMLEN]; char *pbeg; /* beg of file pathname */ char *pend; /* beg of filename */ struct stat stbuf; struct stat lstbuf; FILE *fp; char ibuf[BSIZE];/* contents of 1st line of p.dot */ int hasSccsDir = FALSE; int len, j; pbeg = name; len = strlen(name); if (len + 7 > MAXNAMLEN) { fprintf(stdout, "processFile: pathname %s too long\n", name); return (0); } /* search for last slash '/' in pathname */ for (j = len, pend = pbeg + len; j > 0; j--, pend--) { if (*pend == '/') break; } pend++; /* points to filename */ /* determine if dir has an SCCS sub directory */ strcpy(sccsDir, dir); strcat(sccsDir, "/SCCS"); if (lstat(sccsDir, &lstbuf) == -1) { hasSccsDir = FALSE; } else hasSccsDir = TRUE; if (!hasSccsDir) { if (!verbose) { if (*pfirstTime) { fprintf(stdout, "WARNING regular files in dir: %s\n", dir); *pfirstTime = FALSE; } } else { fprintf(stdout, "WARNING regular file %s\n", name); } return; } /* form p.dot name */ strcpy(dotName, dir); strcat(dotName, "/"); strcat(dotName, pdot); strcat(dotName, pend); if (stat(dotName, &stbuf) == -1) { /* no p.dot file */ /* form s.dot name */ strcpy(dotName, dir); strcat(dotName, "/"); strcat(dotName, sdot); strcat(dotName, pend); if (stat(dotName, &stbuf) == -1) { /* no s.dot file */ if (verbose) { fprintf(stdout, "WARNING regular file %s\n", name); } } else { /* has an s.dot */ fprintf(stdout, "FATAL ERROR - file %s should be a link\n", name); } return; } if ((fp = fopen(dotName, "r")) == NULL) { fprintf(stdout, "processFile: can't fopen %s\n", dotName); return; } if ((fgets(ibuf, BSIZE, fp)) != NULL) { fprintf(stdout, "%-20s %-25s EDIT - %s", dir, pend, ibuf); } else fprintf(stdout, "FATAL ERROR - reading %s%s\n", pdot, pend); fclose(fp); return; } /**************************************************************************** PROCDIRENTRIES process directory entries ****************************************************************************/ void procDirEntries(name, dir, pfirstTime) char *name; /* entry name */ char *dir; /* current directory */ int *pfirstTime; /* ptr to firstTime flag*/ { struct stat stbuf; if (lstat(name, &stbuf) == -1) { fprintf(stdout, "procDirEntries: can't access %s\n", name); return; } if ((stbuf.st_mode & S_IFMT) == S_IFLNK) { checkLink(name); return; } if ((stbuf.st_mode & S_IFMT) == S_IFREG) { processFile(name, dir, pfirstTime); return; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { dirwalk(name, procDirEntries); } return; } /**************************************************************************** CHECKLINK checks valid symbolic link for EPICS ****************************************************************************/ int checkLink(path) char *path; { char resolved_path[MAXPATHLEN]; caddr_t pt; /* skip any path with "/templates/" in it */ if ((strstr(path,"/templates/")) != NULL ) { return; } if(( pt = (caddr_t)realpath(path, resolved_path)) == NULL) { fprintf(stdout, "FATAL ERROR - failed link component of %s=%s\n", path, resolved_path); return; } /* compare $epics or beg of shadow with beg of dest */ /* if neither present in dest - fail */ if (((strncmp(pEpics, resolved_path, lenEpics)) == SAME ) || ((strncmp(pDvl, resolved_path, lenDev)) == SAME )) { return; } else { fprintf(stdout, "FATAL ERROR - link '%s' must point to epics or shadow area\n\t dest='%s'\n",path,resolved_path); } return; } /**************************************************************************** DIRWALK applies a function to each file in a directory ****************************************************************************/ int dirwalk(dir, fcn) char *dir; void (*fcn) (); { char name[MAXNAMLEN]; struct dirent *dp; DIR *dfd; int firstTime; if ((dfd = opendir(dir)) == NULL) { fprintf(stdout, "dirwalk: can't open %s\n", dir); return; } firstTime = TRUE; while ((dp = readdir(dfd)) != NULL) { if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; /* skip self and parent */ if (strlen(dir) + strlen(dp->d_name) + 2 > sizeof(name)) fprintf(stdout, "dirwalk: name %s/%s too long\n", dir, dp->d_name); else { sprintf(name, "%s/%s", dir, dp->d_name); (*fcn) (name, dir, &firstTime); } } closedir(dfd); }