313 lines
9.7 KiB
C
313 lines
9.7 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
|
|
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);
|
|
}
|