1
0
Files
irix-657m-src/eoe/cmd/pathchk/pathchk.c
2022-09-29 17:59:04 +03:00

426 lines
12 KiB
C

/*
* pathchk
*
* pathchk - check pathnames
*
* Copyright 1995, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
*
* UNPUBLISHED -- Rights reserved under the copyright laws of the United
* States. Use of a copyright notice is precautionary only and does not
* imply publication or disclosure.
*
* U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
* in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
* in similar or successor clauses in the FAR, or the DOD or NASA FAR
* Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
* 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
*
* THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
* INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
* DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
* PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
* GRAPHICS, INC.
*/
#ident "$Revision: 1.1 $"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <pfmt.h>
#include <locale.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
/*--------------------------------------*
* Global extern *
*--------------------------------------*/
extern int optind;
/*--------------------------------------*
* Global constants and variables *
*--------------------------------------*/
const char msg_usage []=":849:pathchk [-p] pathname ...\n";
const char e_lng_path []=":850:Pathname %s longer than %s\n";
const char e_lng_comp []=":851:Component %s longer than %s\n";
const char e_non_port []=":852:Component %s contains non-portable character\n";
const char e_nac_spath[]=":853:Subpath %s is not searchable\n";
const char e_not_dir []=":854:%s is not a directory\n";
const char e_miss_arg []=":855:Missing arguments\n";
const char e_lak_mem []=":856:Lack of memory\n";
const char e_err_prg []=":857:Program error\n";
const char S_catal[]= "uxcore";
const char S_label[]= "UX:pathchk";
const char psx_legal_chars[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
const char psx_pmax[]= "_POSIX_PATH_MAX";
const char psx_nmax[]= "_POSIX_NAME_MAX";
const char fsys_pmax[]= "PATH_MAX";
const char fsys_nmax[]= "NAME_MAX";
const char delm_path[]= "/";
const char curdir[]= ".";
const char slash= '/';
const char minus= '-';
int p_flag=0;
/*--------------------------------------*
* Local definition *
*--------------------------------------*/
#define TRUE 1 /* true */
#define FALSE 0 /* false */
#define SUCCESS 0 /* legal pathname */
#define FAIL 1 /* illegal pathname */
#define MAX_ALLOC 10 /* max alloc memory */
#define ERR_USE_OPT 1 /* illegal option */
#define ERR_NO_ARG 2 /* missing arguments */
#define ERR_LK_MEM 3 /* lack of memory */
#define ERR_PRGM 4 /* program error */
#define ERR_RV_SIG 5 /* receive signal */
#define ERR_PATHNM 10 /* pathname error */
#define ERR_MAXPATH 255 /* max pathname error */
int opt_ana(int,char **),fsyscheck(char *),posixcheck(char *);
char *p_malloc(int),*piktok(char *,int *);
void p_free(),prev_pos(char *,int,int);
/*------------------------------------------------------------------
* Function : check pathname legal or not
* Process : 1) get option and analize it
* 2) check pathname legal or not
* Return : 0 = legal names
* ERR_USE_OPT = illegal option
* ERR_NO_ARG = missing arguments
* ERR_LK_MEM = lack of memory
* ERR_PRGM = program error
* ERR_PATHNM+n= illegal pathnames
* Usage : pathchk [-p] pathname ...
*------------------------------------------------------------------*/
main(int argc, char *argv[])
{
int i,rtn=0,arg_rtn,(*func)();
(void) setlocale(LC_ALL,"");
(void) setlabel (S_label);
(void) setcat (S_catal);
/* check input options */
arg_rtn = opt_ana(argc,argv);
if (arg_rtn)
{
if (arg_rtn == ERR_NO_ARG)
pfmt(stderr,MM_ERROR,e_miss_arg);
pfmt(stderr,MM_ACTION,msg_usage);
exit(arg_rtn);
}
/* check input pathnames */
if (! p_flag)
func = fsyscheck;
else
func = posixcheck;
for (i = optind; i < argc; i++)
{
rtn += (func)(argv[i]);
p_free();
}
if (rtn)
rtn += ERR_PATHNM - 1;
exit((rtn > ERR_MAXPATH) ? ERR_MAXPATH : rtn);
}
/*------------------------------------------------------------------
* Function : check input options legal or not
* Return : 0 = legal
* ERR_USE_OPT = illegal option
* ERR_NO_ARG = missing arguments
*------------------------------------------------------------------*/
int opt_ana(
int argc, /* (I) input argument number */
char *argv[]) /* (I) input argument list */
{
int c,rtn=0;
while ((c = getopt(argc,argv,"p")) != EOF)
{
switch(c)
{
case 'p':
p_flag++;
break;
default:
return(ERR_USE_OPT);
}
}
if (argc == optind)
rtn = ERR_NO_ARG;
return rtn;
}
/*------------------------------------------------------------------
* Function : check pathname of POSIX
* Process : 1) check (total pathname_length <= POSIX_PATH_MAX)
* 2) check (each component_length <= POSIX_NAME_MAX)
* 3) check each component include illegal_chars [^A-Za-z0-9.-_]
* Return : SUCCESS = legal pathname
* FAIL = illegal pathname
*------------------------------------------------------------------*/
int posixcheck(
char *pathname) /* (I) pathname */
{
char *component,*name=pathname;
int len,dumlen;
if ((int)strlen(pathname) > _POSIX_PATH_MAX)
{
pfmt(stderr,MM_WARNING,e_lng_path,pathname,psx_pmax);
return FAIL;
}
for (;;)
{
component = piktok(name,&dumlen);
if (component == NULL)
break;
len = strlen(component);
if (len > _POSIX_NAME_MAX)
{
pfmt(stderr,MM_WARNING,e_lng_comp,component,psx_nmax);
return FAIL;
}
if ((strspn(component,psx_legal_chars) != len) || (component[0] == minus))
{
pfmt(stderr,MM_WARNING,e_non_port,component);
return FAIL;
}
name = NULL;
}
return SUCCESS;
}
/*------------------------------------------------------------------
* Function : check pathname on local file system
* Spec : component is a directory
* last - OK
* midst + searchable - OK
* midst + not searchable - Error
* component is a file
* last - OK
* midst - Error
* component is not exist - check lenght only
* Return : SUCCESS = legal pathname
* FAIL = illegal pathname
* Exit : ERR_PRGM = program error
* Note : It is assumed that any character except / is legal.
*------------------------------------------------------------------*/
int fsyscheck(
char *pathname) /* (I) pathname */
{
int i,rtn=SUCCESS,len,staterr,pathexists=TRUE;
int contnamemax,contpathmax,dumlen=0;
int ttllen,cmplen=0;
char *pathsofar,*path,*component,*name;
const char *start;
struct stat buf;
len = strlen(pathname);
pathsofar = p_malloc(len+1);
path = p_malloc(len+1);
pathsofar[0]= '\0';
strcpy(path,pathname);
/* decide path_max and name_max of current system */
if (pathname[0] != slash) /* relative pathname */
start = curdir;
else /* absolute pathname */
start = delm_path;
component = (char *) start;
contnamemax = pathconf(start,_PC_NAME_MAX);
contpathmax = pathconf(start,_PC_PATH_MAX);
if ((contnamemax == -1) || (contpathmax == -1))
goto err_chk; /* never occured ?? */
/* check pathname status and length of component */
name = path;
for (;;)
{
component = piktok(name,&dumlen); /* pick up component */
if (component == NULL)
break;
if (name == NULL) /* without first time */
dumlen ++;
for (i = 0; i < dumlen; i++) /* make input pathname */
strcat(pathsofar,delm_path);
strcat(pathsofar,component);
cmplen = strlen(component);
if (pathexists) /* exist previous path */
{
staterr = stat(pathsofar,&buf); /* get file status */
if (staterr == -1)
{
err_chk:
ttllen = strlen(pathsofar);
switch (errno)
{
case EACCES: /* prohibit to access */
prev_pos(pathsofar,ttllen,dumlen); /* remove cur component */
case ELOOP: /* too many symbolic links */
case EMULTIHOP: /* need multihop but prohibit */
case ENOLINK: /* not active remote path */
pfmt(stderr,MM_WARNING,e_nac_spath,pathsofar);
return FAIL;
case ENAMETOOLONG: /* too long pathname or component */
if (ttllen > contpathmax)
pfmt(stderr,MM_WARNING,e_lng_path,pathsofar,fsys_pmax);
else
pfmt(stderr,MM_WARNING,e_lng_comp,component,fsys_nmax);
return FAIL;
case ENOENT: /* not exist or null pathname */
pathexists = FALSE;
break;
case ENOTDIR: /* path prefix is not a directory */
prev_pos(pathsofar,ttllen,dumlen); /* remove cur component */
pfmt(stderr,MM_WARNING,e_not_dir,pathsofar);
return FAIL;
case EOVERFLOW: /* component is too large to store */
assert("We stuffed up");
break;
default:
pfmt(stderr,MM_ERROR,e_err_prg);
exit(ERR_PRGM);
} /* end -- switch(errno) */
}
else /* staterr != 1 */
{
/* . . . decide path_max and name_max of current system */
contnamemax = pathconf(pathsofar,_PC_NAME_MAX);
contpathmax = pathconf(pathsofar,_PC_PATH_MAX);
if ((contnamemax == -1) || (contpathmax == -1))
goto err_chk; /* never occured ?? */
} /* end -- if (staterr == -1) */
} /* end -- if (pathexists) */
/* . check length of component */
if (cmplen > contnamemax)
{
pfmt(stderr,MM_WARNING,e_lng_comp,component,fsys_nmax);
return FAIL;
}
name = NULL;
} /* end -- for (;;) */
/* check total pathname length */
if (len > contpathmax)
{
pfmt(stderr,MM_WARNING,e_lng_path,pathname,fsys_pmax);
rtn = FAIL;
}
return rtn;
}
/*------------------------------------------------------------------
* Function : pick up token separated with '/'
* Same as strtok, but sets the number of skipped
* leading separators.
*------------------------------------------------------------------*/
char *piktok(
char *string, /* (I) 1st time address of data, others NULL */
int *dumlen) /* (O) number of skipped leading separators */
{
register char *q, *r;
static char *savept;
/*first or subsequent call*/
if (string == NULL)
string = savept;
if(string == 0) /* return if no tokens remaining */
return(NULL);
*dumlen = strspn(string, delm_path);
q = string + *dumlen; /* skip leading separators */
if(*q == '\0') /* return if no tokens remaining */
return(NULL);
if((r = strpbrk(q, delm_path)) == NULL) /* move past token */
savept = 0; /* indicate this is last token */
else
{
*r = '\0';
savept = r+1;
}
return(q);
}
/*------------------------------------------------------------------
* Function : search n-th prev pos of '/'
*------------------------------------------------------------------*/
void prev_pos(
char *name, /* (I) data string */
int ttllen, /* (I) length of string */
int skipno) /* (I) n-th previous position of '/' */
{
int prev,skip;
for (prev = ttllen-1,skip = 0; prev > 0 && skip < skipno ; prev--)
{
if (name[prev] == slash)
skip ++;
}
name[prev+1] = '\0';
}
static char *save[MAX_ALLOC];
static int sv_cnt=0;
/*------------------------------------------------------------------
* Function : alloc memory
*------------------------------------------------------------------*/
char *p_malloc(
int size) /* (I) allocation mempry size : byte */
{
char *mem;
mem = malloc(size);
if (mem == NULL)
{
pfmt(stderr,MM_ERROR,e_lak_mem);
exit(ERR_LK_MEM);
}
else
{
if (sv_cnt < MAX_ALLOC)
save[sv_cnt++] = mem;
return mem;
}
}
/*------------------------------------------------------------------
* Function : free alloc memory
*------------------------------------------------------------------*/
void p_free()
{
int i;
for (i = 0; i < sv_cnt; i++)
free(save[i]);
sv_cnt = 0;
}