#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <pkgstrct.h>
#include <pkginfo.h>
#include <pkglocs.h>
#include <stdlib.h>
#include <unistd.h>
#include "libadm.h"
#define VALSIZ 128
#define NEWLINE '\n'
#define ESCAPE '\\'
static char sepset[] = ":=\n";
static char qset[] = "'\"";
static char *pkg_inst_root = NULL;
char *pkgdir = NULL;
char *pkgfile = NULL;
static char Adm_pkgloc[PATH_MAX] = { 0 };
static char Adm_pkgadm[PATH_MAX] = { 0 };
int
pkginfofind(char *path, char *pkg_dir, char *pkginst)
{
int len = 0;
len = snprintf(path, PATH_MAX, "%s/.save.%s/pkginfo", pkg_dir,
pkginst);
if (len > PATH_MAX)
return (0);
if (access(path, 0)) {
len = snprintf(path, PATH_MAX, "%s/%s/pkginfo", pkg_dir,
pkginst);
if (len > PATH_MAX)
return (0);
if (access(path, 0))
return (0);
}
return (1);
}
FILE *
pkginfopen(char *pkg_dir, char *pkginst)
{
FILE *fp = NULL;
char temp[PATH_MAX];
if (pkginfofind(temp, pkg_dir, pkginst))
fp = fopen(temp, "r");
return (fp);
}
char *
fpkgparam(FILE *fp, char *param)
{
char ch, buffer[VALSIZ];
char *mempt, *copy;
int c, n;
boolean_t check_end_quote = B_FALSE;
boolean_t begline, quoted, escape;
int idx = 0;
if (param == NULL) {
errno = ENOENT;
return (NULL);
}
mempt = NULL;
for (;;) {
copy = buffer;
n = 0;
while ((c = getc(fp)) != EOF) {
ch = (char)c;
if (strchr(sepset, ch))
break;
if (++n < VALSIZ)
*copy++ = ch;
}
if (c == EOF) {
errno = EINVAL;
return (NULL);
} else if (c == NEWLINE)
continue;
*copy = '\0';
if (buffer[0] == '#')
copy = NULL;
else {
if (param[0] == '\0') {
(void) strcpy(param, buffer);
copy = buffer;
} else if (strcmp(param, buffer))
copy = NULL;
else
copy = buffer;
}
n = 0;
quoted = escape = B_FALSE;
begline = B_TRUE;
while ((c = getc(fp)) != EOF) {
ch = (char)c;
if (begline && ((ch == ' ') || (ch == '\t')))
continue;
if (ch != NEWLINE && ch != ' ' && ch != ESCAPE &&
ch != '\t' && check_end_quote)
check_end_quote = B_FALSE;
if (ch == NEWLINE) {
if (!escape) {
if (check_end_quote) {
copy -= n - idx;
n = idx;
check_end_quote = B_FALSE;
quoted = B_FALSE;
}
break;
}
if (check_end_quote) {
copy -= n - idx;
n = idx;
check_end_quote = B_FALSE;
} else if (copy) {
copy--;
n--;
}
escape = B_FALSE;
begline = B_TRUE;
continue;
} else {
if (!escape && strchr(qset, ch)) {
if (begline) {
quoted = B_TRUE;
begline = B_FALSE;
continue;
} else if (quoted) {
check_end_quote = B_TRUE;
idx = n;
}
}
if (ch == ESCAPE)
escape = B_TRUE;
else if (escape)
escape = B_FALSE;
if (copy) *copy++ = ch;
begline = B_FALSE;
}
if (copy && ((++n % VALSIZ) == 0)) {
if (mempt) {
mempt = realloc(mempt,
(n+VALSIZ)*sizeof (char));
if (!mempt)
return (NULL);
} else {
mempt = calloc((size_t)(2*VALSIZ),
sizeof (char));
if (!mempt)
return (NULL);
(void) strncpy(mempt, buffer, n);
}
copy = &mempt[n];
}
}
while (copy && isspace((unsigned char)*(copy - 1)) && n-- > 0)
copy--;
if (quoted) {
if (mempt)
(void) free(mempt);
errno = EFAULT;
return (NULL);
}
if (copy) {
*copy = '\0';
break;
}
if (c == EOF) {
errno = EINVAL;
return (NULL);
}
}
if (!mempt)
mempt = strdup(buffer);
else
mempt = realloc(mempt, (strlen(mempt)+1)*sizeof (char));
return (mempt);
}
char *
pkgparam(char *pkg, char *param)
{
static char lastfname[PATH_MAX];
static FILE *fp = NULL;
char *pt, *copy, *value, line[PATH_MAX];
if (!pkgdir)
pkgdir = get_PKGLOC();
if (!pkg) {
if (fp) {
(void) fclose(fp);
fp = NULL;
}
return (NULL);
}
if (!param) {
errno = ENOENT;
return (NULL);
}
if (pkgfile)
(void) strcpy(line, pkgfile);
else
(void) pkginfofind(line, pkgdir, pkg);
if (fp && strcmp(line, lastfname)) {
(void) fclose(fp);
fp = NULL;
}
if (!fp) {
(void) strcpy(lastfname, line);
if ((fp = fopen(lastfname, "r")) == NULL)
return (NULL);
}
if (param[0]) {
if (fseek(fp, 0L, 0))
return (NULL);
}
if (pt = fpkgparam(fp, param)) {
if (strcmp(param, "ARCH") == 0 ||
strcmp(param, "CATEGORY") == 0) {
value = copy = pt;
while (*value) {
if (!isspace((unsigned char)*value))
*copy++ = *value;
value++;
}
*copy = '\0';
}
return (pt);
}
return (NULL);
}
static void canonize_name(char *);
void
set_PKGpaths(char *path)
{
if (path && *path) {
(void) snprintf(Adm_pkgloc, sizeof (Adm_pkgloc),
"%s%s", path, PKGLOC);
(void) snprintf(Adm_pkgadm, sizeof (Adm_pkgadm),
"%s%s", path, PKGADM);
set_install_root(path);
} else {
(void) snprintf(Adm_pkgloc, sizeof (Adm_pkgloc), "%s", PKGLOC);
(void) snprintf(Adm_pkgadm, sizeof (Adm_pkgadm), "%s", PKGADM);
}
canonize_name(Adm_pkgloc);
canonize_name(Adm_pkgadm);
pkgdir = Adm_pkgloc;
}
char *
get_PKGLOC(void)
{
if (Adm_pkgloc[0] == '\0')
return (PKGLOC);
else
return (Adm_pkgloc);
}
char *
get_PKGADM(void)
{
if (Adm_pkgadm[0] == '\0')
return (PKGADM);
else
return (Adm_pkgadm);
}
void
set_PKGADM(char *newpath)
{
(void) strcpy(Adm_pkgadm, newpath);
}
void
set_PKGLOC(char *newpath)
{
(void) strcpy(Adm_pkgloc, newpath);
}
#define isdot(x) ((x[0] == '.')&&(!x[1]||(x[1] == '/')))
#define isdotdot(x) ((x[0] == '.')&&(x[1] == '.')&&(!x[2]||(x[2] == '/')))
static void
canonize_name(char *file)
{
char *pt, *last;
int level;
for (pt = file; *pt; ) {
if (isdot(pt))
(void) strcpy(pt, pt[1] ? pt+2 : pt+1);
else if (isdotdot(pt)) {
level = 0;
last = pt;
do {
level++;
last += 2;
if (*last)
last++;
} while (isdotdot(last));
--pt;
while (level--) {
if (pt <= file)
return;
while ((*--pt != '/') && (pt > file))
;
}
if (*pt == '/')
pt++;
(void) strcpy(pt, last);
} else {
while (*pt && (*pt != '/'))
pt++;
if (*pt == '/') {
while (pt[1] == '/')
(void) strcpy(pt, pt+1);
pt++;
}
}
}
if ((--pt > file) && (*pt == '/'))
*pt = '\0';
}
void
set_install_root(char *path)
{
pkg_inst_root = strdup(path);
}
char *
get_install_root()
{
return (pkg_inst_root);
}