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

574 lines
12 KiB
C

/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
/*LINTLIBRARY*/
#ident "$Revision: 1.4 $"
#include <stdio.h>
#include <limits.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pkginfo.h>
#include <pkgstrct.h>
#include <pkglocs.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include "libadm.h"
extern char *pkgdir;
extern int errno;
static void initpkg(struct pkginfo *);
static char *svr4inst(char *);
static int rdconfig(struct pkginfo *, char *, char *),
svr4info(struct pkginfo *, char *, char *),
ckinfo(char *, char *, char *),
ckinst(char *, char *, char *, char *, char *),
verscmp(char *, char *),
archcmp(char *, char *),
compver(char *, char *);
char *fpkginst(char *pkg, ...);
int fpkginfo(struct pkginfo *, char *);
/*
* Globals:
* pkgdir - specifies the directory where information about packages
* resides, i.e. the pkginfo file is located in a subdirectory
*
* Caveats:
* The structure provided via "info" will contain malloc'd information;
* this will be free'd upon the next call to pkginfo with this
* same structure. Application calls must make sure this structure
* is null on the first call, or else we'll free static memory areas
* If the "pkg" argument is a wildcard specification, the next found
* instance available which matches the request will be returned
* If the "pkg" argument is a NULL pointer, the structure pointed to
* via "info" will have its elements deallocated and all files
* associated with this routine will be closed
*
* Return codes:
* A non-zero exit code indicates error with "errno" appropriately set:
* EINVAL - invalid argument
* ESRCH - there are no more instances of this package around
* EACCESS - unable to access files which should have been there
*/
/*VARARGS*/
int
pkginfo(struct pkginfo *info, char *pkginst, ...)
{
char *ckarch, *ckvers;
int check;
va_list ap;
va_start(ap, pkginst);
if(info == NULL) {
va_end(ap);
errno = EINVAL;
return(-1);
}
if(pkginst == NULL) {
va_end(ap);
(void) fpkginfo(info, NULL);
(void) fpkginst(NULL);
return(0);
}
ckarch = va_arg(ap, char *);
ckvers = va_arg(ap, char *);
va_end(ap);
check = 0;
if(pkgnmchk(pkginst, "all", 1)) {
/* wild card specification */
pkginst = fpkginst(pkginst, ckarch, ckvers);
if(pkginst == NULL)
return(-1);
} else {
/* request to check indicated instance */
if(ckarch || ckvers)
check++;
}
if(fpkginfo(info, pkginst))
return(-1);
if(check) {
/*
* verify that the provided instance matches
* any arch & vers specs that were provided
*/
if(ckinst(pkginst, info->arch, info->version, ckarch, ckvers)) {
errno = ESRCH;
return(-1);
}
}
return(0);
}
/*ARGSUSED*/
int
fpkginfo(struct pkginfo *info, char *pkginst)
{
if(info == NULL) {
errno = EINVAL;
return(-1);
}
initpkg(info);
if(pkginst == NULL)
return(0);
else if(pkgnmchk(pkginst, "all", 1)) {
errno = EINVAL; /* not an instance identifier */
return(-1);
}
if(pkgdir == NULL)
pkgdir = PKGLOC;
if(rdconfig(info, pkginst, NULL)) {
initpkg(info);
return(-1);
}
return(0);
}
static void
initpkg(struct pkginfo *info)
{
/* free previously allocated space */
if(info->pkginst) {
free(info->pkginst);
if(info->arch)
free(info->arch);
if(info->version)
free(info->version);
if(info->basedir)
free(info->basedir);
if(info->name)
free(info->name);
if(info->vendor)
free(info->vendor);
if(info->catg)
free(info->catg);
}
info->pkginst = NULL;
info->arch = info->version = NULL;
info->basedir = info->name = NULL;
info->vendor = info->catg = NULL;
info->status = PI_UNKNOWN;
}
static int
rdconfig(struct pkginfo *info, char *pkginst, char *ckvers)
{
FILE *fp;
char temp[256];
char *value, *pt, *copy, **memloc;
int count;
(void) sprintf(temp, "%s/%s/pkginfo", pkgdir, pkginst);
if((fp = fopen(temp, "r")) == NULL) {
if((errno == ENOENT) && !strcmp(pkgdir, PKGLOC))
return(svr4info(info, pkginst, ckvers));
errno = EACCES;
return(-1);
}
*temp = '\0';
count = 0;
while(value = fpkgparam(fp, temp)) {
if(!strcmp(temp, "ARCH") || !strcmp(temp, "CATEGORY")) {
/* remove all whitespace from value */
pt = copy = value;
while(*pt) {
if(!isspace(*pt))
*copy++ = *pt;
pt++;
}
*copy = '\0';
}
count++;
memloc = NULL;
if(!strcmp(temp, "NAME"))
memloc = &info->name;
else if(!strcmp(temp, "VERSION"))
memloc = &info->version;
else if(!strcmp(temp, "ARCH"))
memloc = &info->arch;
else if(!strcmp(temp, "VENDOR"))
memloc = &info->vendor;
else if(!strcmp(temp, "BASEDIR"))
memloc = &info->basedir;
else if(!strcmp(temp, "CATEGORY"))
memloc = &info->catg;
temp[0] = '\0';
if(memloc == NULL)
continue; /* not a parameter we're looking for */
*memloc = strdup(value);
if(!*memloc) {
fclose(fp);
errno = ENOMEM;
return(-1); /* malloc from strdup failed */
}
}
fclose(fp);
if(!count) {
errno = ESRCH;
return(-1);
}
info->status = (strcmp(pkgdir, PKGLOC) ? PI_SPOOLED : PI_INSTALLED);
if(info->status == PI_INSTALLED) {
(void) sprintf(temp, "%s/%s/!I-Lock!", pkgdir, pkginst);
if(access(temp, 0) == 0)
info->status = PI_PARTIAL;
else {
(void) sprintf(temp, "%s/%s/!R-Lock!", pkgdir, pkginst);
if(access(temp, 0) == 0)
info->status = PI_PARTIAL;
}
}
info->pkginst = strdup(pkginst);
return(0);
}
static int
svr4info(struct pkginfo *info, char *pkginst, char *ckvers)
{
static DIR *pdirfp;
struct stat status;
FILE *fp;
char *pt, path[128], line[128];
char temp[PKGSIZ+1];
if(strcmp(pkginst, "all")) {
if(pdirfp) {
closedir(pdirfp);
pdirfp = NULL;
}
/* determine pkginst - remove '.*' extension, if any */
(void) strncpy(temp, pkginst, PKGSIZ);
if((pt = strchr(temp, '.')) && !strcmp(pt, ".*"))
*pt = '\0';
}
/* look in /usr/options direcotry for 'name' file */
(void) sprintf(path, "%s/%s.name", PKGOLD, temp);
if(lstat(path, &status)) {
errno = (errno == ENOENT) ? ESRCH : EACCES;
return(-1);
}
if((status.st_mode & S_IFMT) != S_IFREG) {
errno = ESRCH;
return(-1);
}
if((fp = fopen(path, "r")) == NULL) {
errno = (errno == ENOENT) ? ESRCH : EACCES;
return(-1);
}
/* /usr/options/xxx.name exists */
(void) fgets(line, 128, fp);
(void) fclose(fp);
if(pt = strchr(line, '\n'))
*pt = '\0'; /* remove trailing newline */
if(pt = strchr(line, ':'))
*pt++ = '\0'; /* assumed version specification */
if(info) {
info->name = strdup(line);
info->pkginst = strdup(temp);
if(!info->name || !info->pkginst) {
errno = ENOMEM;
return(-1);
}
info->status = PI_PRESVR4;
info->version = NULL;
}
if(pt) {
/* eat leading space off of version spec */
while(isspace(*pt))
pt++;
}
if(ckvers && verscmp(ckvers, pt)) {
errno = ESRCH;
return(-1);
}
if(info && *pt)
info->version = strdup(pt);
return(0);
}
static int
ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers)
{
if(ckarch && archcmp(ckarch, pkgarch))
return(-1);
if(ckvers) {
if(ckvers[0] == '~') {
ckvers++;
/* check for compatable version */
if(verscmp(ckvers, pkgvers) &&
compver(pkginst, ckvers))
return(-1);
} else if(verscmp(ckvers, pkgvers))
return(-1);
}
return(0);
}
/*VARARGS*/
char *
fpkginst(char *pkg, ...)
{
static char pkginst[PKGSIZ+1];
static DIR *pdirfp;
struct dirent *dp;
char *pt, *ckarch, *ckvers;
va_list ap;
va_start(ap, pkg);
if(pkg == NULL) {
/* request to close or rewind the file */
if(pdirfp) {
(void) closedir(pdirfp);
pdirfp = NULL;
}
svr4inst(NULL); /* close any files used here */
va_end(ap);
return(NULL);
}
ckarch = va_arg(ap, char *);
ckvers = va_arg(ap, char *);
va_end(ap);
if(!pkgdir)
pkgdir = PKGLOC;
if(!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) {
errno = EACCES;
return(NULL);
}
while((dp = readdir(pdirfp)) != NULL) {
if(dp->d_name[0] == '.')
continue;
if(pkgnmchk(dp->d_name, pkg, 0))
continue; /* ignore invalid SVR4 package names */
if(ckinfo(dp->d_name, ckarch, ckvers))
continue;
/* leave directory open in case user requests another instance
*/
strcpy(pkginst, dp->d_name);
return(pkginst);
}
/* if we are searching the directory which contains info
* about installed packages, check the pre-svr4 directory
* for an instance and be sure it matches any version
* specification provided to us
*/
if(!strcmp(pkgdir, PKGLOC) && (ckarch == NULL)) {
/* search for pre-SVR4 instance */
if(pt = svr4inst(pkg))
return(pt);
}
errno = ESRCH;
/* close any file we might have open */
(void) closedir(pdirfp);
pdirfp = NULL;
return(NULL);
}
/*ARGSUSED*/
static char *
svr4inst(char *pkg)
{
static char pkginst[PKGSIZ];
static DIR *pdirfp;
struct dirent *dp;
struct stat status; /* file status buffer */
char *pt;
char path[PATH_MAX];
if(pkg == NULL) {
if(pdirfp) {
closedir(pdirfp);
pdirfp = NULL;
}
return(NULL);
}
if(!pdirfp && ((pdirfp = opendir(PKGOLD)) == NULL))
return(NULL);
while((dp = readdir(pdirfp)) != NULL) {
if(dp->d_name[0] == '.')
continue;
pt = strchr(dp->d_name, '.');
if(pt && !strcmp(pt, ".name")) {
/* the pkgnmchk function works on .name extensions */
if(pkgnmchk(dp->d_name, pkg, 1))
continue;
(void) sprintf(path, "%s/%s", PKGOLD, dp->d_name);
if(lstat(path, &status))
continue;
if((status.st_mode & S_IFMT) != S_IFREG)
continue;
*pt = '\0';
(void) strcpy(pkginst, dp->d_name);
return(pkginst);
}
}
closedir(pdirfp);
pdirfp = NULL;
return(NULL);
}
static int
verscmp(char *request, char *actual)
{
/* eat leading white space */
while(isspace(*actual))
actual++;
while(isspace(*request))
request++;
while(*request) {
if(isspace(*request)) {
if(*actual && !isspace(*actual))
break;
while(isspace(*request))
request++;
while(isspace(*actual))
actual++;
continue;
}
if(*request++ != *actual)
break;
actual++;
}
while(isspace(*actual))
actual++;
return(*actual ? -1 : 0);
}
static int
compver(char *pkginst, char *version)
{
FILE *fp;
char temp[256];
(void) sprintf(temp, "%s/%s/install/compver", PKGLOC, pkginst);
if((fp = fopen(temp, "r")) == NULL)
return(-1);
while(fgets(temp, 256, fp)) {
if(*temp == '#')
continue;
if(verscmp(temp, version) == 0) {
(void) fclose(fp);
return(0);
}
}
(void) fclose(fp);
return(-1);
}
static int
archcmp(char *arch, char *archlist)
{
register char *pt;
if(arch == NULL)
return(0);
/* arch and archlist must not contain whitespace! */
while(*archlist) {
for(pt=arch; *pt && (*pt == *archlist);)
pt++, archlist++;
if(!*pt && (!*archlist || (*archlist == ',')))
return(0);
while(*archlist) {
if(*archlist++ == ',')
break;
}
}
return(-1);
}
static int
ckinfo(char *inst, char *arch, char *vers)
{
FILE *fp;
char temp[128];
char file[PATH_MAX];
char *pt, *copy, *value, *myarch, *myvers;
int errflg;
(void) sprintf(file, "%s/%s/pkginfo", pkgdir, inst);
if((fp = fopen(file, "r")) == NULL)
return(1);
if((arch == NULL) && (vers == NULL)) {
fclose(fp);
return(0);
}
temp[0] = '\0';
myarch = myvers = NULL;
while(value = fpkgparam(fp, temp)) {
if(!strcmp(temp, "ARCH")) {
/* remove all whitespace from value */
pt = copy = value;
while(*pt) {
if(!isspace(*pt))
*copy++ = *pt;
pt++;
}
*copy = '\0';
myarch = value;
if(myvers)
break;
} else if(!strcmp(temp, "VERSION")) {
myvers = value;
if(myarch)
break;
} else
(void) free(value);
temp[0] = '\0';
}
fclose(fp);
errflg = 0;
if(ckinst(inst, myarch, myvers, arch, vers))
errflg++;
if(myarch)
(void) free(myarch);
if(myvers)
(void) free(myvers);
return(errflg);
}