diff --git a/src/util/checkDvlNode.c b/src/util/checkDvlNode.c new file mode 100644 index 000000000..66423b9d5 --- /dev/null +++ b/src/util/checkDvlNode.c @@ -0,0 +1,312 @@ +/* + * 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); +}