#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <pkgstrct.h>
#include <pkginfo.h>
#include <locale.h>
#include <libintl.h>
#include <unistd.h>
#include <stdlib.h>
#include <pkglib.h>
#include <install.h>
#include <libadm.h>
#include <libinst.h>
extern char *basedir, *root, *rootlist[], **environ;
#define PATH_LGTH 4096
#define MAXPARAMS 256
#define NRECURS 20
#define MSG_BPARAMC "parametric class specification for <%s> not allowed"
#define MSG_SRCHLOC "no object for <%s> found in local path"
#define MSG_SRCHSRCH "no object for <%s> found in search path"
#define MSG_SRCHROOT "no object for <%s> found in root directory"
#define MSG_CONTENTS "unable to process contents of object <%s>"
#define MSG_WRITE "write of entry failed, errno=%d"
#define MSG_GARBDEFLT "garbled default settings: %s"
#define MSG_BANG "unknown directive: %s"
#define MSG_CHDIR "unable to change directory to <%s>"
#define MSG_INCOMPLETE "processing of <%s> may be incomplete"
#define MSG_NRECURS "too many levels of include (limit is %d)"
#define MSG_RDINCLUDE "unable to process include file <%s>, errno=%d"
#define MSG_IGNINCLUDE "ignoring include file <%s>"
#define MSG_NODEVICE "device numbers cannot be determined for <%s>"
#define WRN_BADATTR "WARNING: attributes set to %04o %s %s for <%s>"
#define WRN_BADATTRM "WARNING: attributes set to %s %s %s for <%s>"
#define WRN_FAKEBD "WARNING: parametric paths may ignore BASEDIR"
#define ERR_TEMP "unable to obtain temporary file resources, errno=%d"
#define ERR_ENVBUILD "unable to build parameter environment, errno=%d"
#define ERR_MAXPARAMS "too many parameter definitions (limit is %d)"
#define ERR_GETCWD "unable to get current directory, errno=%d"
#define ERR_PATHVAR "cannot resolve all build parameters associated with " \
"path <%s>."
static struct cfent entry;
static FILE *fp,
*sfp[20];
static char *dname[NRECURS],
*params[256],
*proto[NRECURS],
*rootp[NRECURS][16],
*srchp[NRECURS][16],
*d_own[NRECURS],
*d_grp[NRECURS],
*rdonly[256];
static mode_t d_mod[NRECURS];
static int nfp = (-1);
static int nrdonly = 0;
static int errflg = 0;
static char *separ = " \t\n, ";
extern void attrpreset(int mode, char *owner, char *group);
extern void attrdefault();
static char *findfile(char *path, char *local);
static char *srchroot(char *path, char *copy);
static int popenv(void);
static int doattrib(void);
static void doinclude(void);
static void dorsearch(void);
static void dosearch(void);
static void error(int flag);
static void lputenv(char *s);
static void pushenv(char *file);
static void translate(register char *pt, register char *copy);
int
mkpkgmap(char *outfile, char *protofile, char **envparam)
{
FILE *tmpfp;
char *pt, *path, mybuff[PATH_LGTH];
char **envsave;
int c, fakebasedir;
int i, n;
char temp[PATH_LGTH];
if ((tmpfp = fopen(outfile, "w")) == NULL) {
progerr(gettext(ERR_TEMP), errno);
quit(99);
}
envsave = environ;
environ = params;
attrdefault();
for (i = 0; (envparam[i] != NULL) &&
(pt = strchr(envparam[i], '=')); i++) {
*pt = '\0';
rdonly[nrdonly++] = qstrdup(envparam[i]);
*pt = '=';
if (putenv(qstrdup(envparam[i]))) {
progerr(gettext(ERR_ENVBUILD), errno);
quit(99);
}
if (nrdonly >= MAXPARAMS) {
progerr(gettext(ERR_MAXPARAMS), MAXPARAMS);
quit(1);
}
}
pushenv(protofile);
errflg = 0;
again:
fakebasedir = 0;
while (!feof(fp)) {
c = getc(fp);
while (isspace(c))
c = getc(fp);
if (c == '#') {
do c = getc(fp); while ((c != EOF) && (c != '\n'));
continue;
}
if (c == EOF)
break;
if (c == '!') {
(void) fscanf(fp, "%4096s", temp);
if (strcmp(temp, "include") == 0)
doinclude();
else if (strcmp(temp, "rsearch") == 0)
dorsearch();
else if (strcmp(temp, "search") == 0)
dosearch();
else if (strcmp(temp, "default") == 0) {
if (doattrib())
break;
} else if (strchr(temp, '=')) {
translate(temp, mybuff);
lputenv(mybuff);
(void) fscanf(fp, "%*[^\n]");
(void) fscanf(fp, "\n");
} else {
error(1);
logerr(gettext(MSG_BANG), temp);
(void) fscanf(fp, "%*[^\n]");
(void) fscanf(fp, "\n");
}
continue;
}
(void) ungetc(c, fp);
if ((n = gpkgmap(&entry, fp)) < 0) {
char *errstr;
error(1);
errstr = getErrstr();
logerr(gettext("garbled entry"));
logerr(gettext("- pathname: %s"),
(entry.path && *entry.path) ? entry.path :
"Unknown");
logerr(gettext("- problem: %s"),
(errstr && *errstr) ? errstr : "Unknown");
break;
}
if (n == 0)
break;
if (entry.ftype != 'i') {
if (entry.pkg_class[0] == '$') {
error(1);
logerr(gettext(MSG_BPARAMC), entry.path);
}
}
if (strchr("dxlscbp", entry.ftype)) {
if (strchr("cb", entry.ftype)) {
if (entry.ainfo.major == BADMAJOR ||
entry.ainfo.minor == BADMINOR) {
error(1);
logerr(gettext(MSG_NODEVICE),
entry.path);
}
}
path = NULL;
} else {
path = findfile(entry.path, entry.ainfo.local);
if (!path)
continue;
entry.ainfo.local = path;
if (strchr("fevin?", entry.ftype)) {
if (cverify(0, &entry.ftype, path,
&entry.cinfo, 1)) {
error(1);
logerr(gettext(MSG_CONTENTS), path);
}
}
}
if (!strchr("isl", entry.ftype)) {
int dowarning = 0;
int hasbadmode = 0;
if (entry.ainfo.mode == NOMODE) {
entry.ainfo.mode = CURMODE;
dowarning = 1;
hasbadmode = 1;
}
if (strcmp(entry.ainfo.owner, NOOWNER) == 0) {
(void) strlcpy(entry.ainfo.owner, CUROWNER,
sizeof (entry.ainfo.owner));
dowarning = 1;
}
if (strcmp(entry.ainfo.group, NOGROUP) == 0) {
(void) strlcpy(entry.ainfo.group, CURGROUP,
sizeof (entry.ainfo.group));
dowarning = 1;
}
if (dowarning) {
if (hasbadmode)
logerr(gettext(WRN_BADATTRM),
"?",
entry.ainfo.owner,
entry.ainfo.group,
entry.path);
else
logerr(gettext(WRN_BADATTR),
(int)entry.ainfo.mode,
entry.ainfo.owner,
entry.ainfo.group,
entry.path);
}
}
if (strchr("ls", entry.ftype)) {
if (!RELATIVE(entry.ainfo.local) ||
PARAMETRIC(entry.ainfo.local)) {
if (mappath(1, entry.ainfo.local)) {
error(1);
logerr(gettext(ERR_PATHVAR),
entry.ainfo.local);
break;
}
canonize(entry.ainfo.local);
}
}
if (entry.ftype != 'i') {
if (entry.path[0] == '$' && isupper(entry.path[1]))
fakebasedir = 1;
}
if (mappath(1, entry.path)) {
error(1);
logerr(gettext(ERR_PATHVAR), entry.path);
break;
}
canonize(entry.path);
if (ppkgmap(&entry, tmpfp)) {
error(1);
logerr(gettext(MSG_WRITE), errno);
break;
}
}
if (fakebasedir) {
logerr(gettext(WRN_FAKEBD));
fakebasedir = 0;
}
if (popenv())
goto again;
(void) fclose(tmpfp);
environ = envsave;
return (errflg ? 1 : 0);
}
static char *
findfile(char *path, char *local)
{
struct stat statbuf;
static char host[PATH_MAX];
register char *pt;
char temp[PATH_MAX], *basename;
int i;
(void) strlcpy(temp, (local && local[0] ? local : path), sizeof (temp));
mappath(0, temp);
canonize(temp);
*host = '\0';
if (rootlist[0] || (basedir && (*temp != '/'))) {
if (entry.ftype != 'i')
return (srchroot(temp, host));
}
if (local && *local) {
basepath(temp, dname[nfp], NULL);
if (strcmp(temp, "/dev/null") != 0) {
if (stat(temp, &statbuf) ||
!(statbuf.st_mode & S_IFREG)) {
error(1);
logerr(gettext(MSG_SRCHLOC), path);
return (NULL);
}
}
(void) strlcpy(host, temp, sizeof (host));
return (host);
}
for (i = 0; rootp[nfp][i]; i++) {
(void) snprintf(host, sizeof (host), "%s/%s", rootp[nfp][i],
temp + (*temp == '/' ? 1 : 0));
if ((stat(host, &statbuf) == 0) &&
(statbuf.st_mode & S_IFREG)) {
return (host);
}
}
pt = strrchr(temp, '/');
if (!pt++)
pt = temp;
basename = pt;
for (i = 0; srchp[nfp][i]; i++) {
(void) snprintf(host, sizeof (host), "%s/%s",
srchp[nfp][i], basename);
if ((stat(host, &statbuf) == 0) &&
(statbuf.st_mode & S_IFREG)) {
return (host);
}
}
(void) snprintf(host, sizeof (host), "%s/%s", dname[nfp], basename);
if ((stat(host, &statbuf) == 0) && (statbuf.st_mode & S_IFREG))
return (host);
error(1);
logerr(gettext(MSG_SRCHSRCH), path);
return (NULL);
}
static void
dosearch(void)
{
char temp[PATH_MAX], lookpath[PATH_MAX], *pt;
int n;
(void) fgets(temp, PATH_MAX, fp);
translate(temp, lookpath);
for (n = 0; srchp[nfp][n]; n++)
free(srchp[nfp][n]);
n = 0;
pt = strtok(lookpath, separ);
if (pt && *pt) {
do {
if (*pt != '/') {
(void) snprintf(temp, sizeof (temp),
"%s/%s", dname[nfp], pt);
pt = temp;
}
canonize(pt);
srchp[nfp][n++] = qstrdup(pt);
} while (pt = strtok(NULL, separ));
srchp[nfp][n] = NULL;
}
}
static void
dorsearch(void)
{
char temp[PATH_MAX], lookpath[PATH_MAX], *pt;
int n;
(void) fgets(temp, PATH_MAX, fp);
translate(temp, lookpath);
for (n = 0; rootp[nfp][n]; n++)
free(rootp[nfp][n]);
n = 0;
pt = strtok(lookpath, separ);
do {
if (*pt != '/') {
(void) snprintf(temp, sizeof (temp),
"%s/%s", dname[nfp], pt);
pt = temp;
}
canonize(pt);
rootp[nfp][n++] = qstrdup(pt);
} while (pt = strtok(NULL, separ));
rootp[nfp][n] = NULL;
}
static int
doattrib(void)
{
char *pt, attrib[PATH_MAX], *mode_ptr, *owner_ptr, *group_ptr, *eol;
int mode;
char owner[ATRSIZ+1], group[ATRSIZ+1], attrib_save[(4*ATRSIZ)];
(void) fgets(attrib, PATH_MAX, fp);
(void) strlcpy(attrib_save, attrib, sizeof (attrib_save));
mode_ptr = strtok(attrib, " \t");
owner_ptr = strtok(NULL, " \t");
group_ptr = strtok(NULL, " \t\n");
eol = strtok(NULL, " \t\n");
if (strtok(NULL, " \t\n")) {
error(1);
logerr(gettext(MSG_GARBDEFLT), (eol) ? eol :
gettext("unreadable at end of line"));
return (1);
}
if (group_ptr && mapvar(1, group_ptr) == 0)
(void) strncpy(group, group_ptr, ATRSIZ);
else {
error(1);
logerr(gettext(MSG_GARBDEFLT), (attrib_save) ?
((attrib_save[0]) ? attrib_save : gettext("none")) :
gettext("unreadable at group"));
return (1);
}
if (owner_ptr && mapvar(1, owner_ptr) == 0)
(void) strncpy(owner, owner_ptr, ATRSIZ);
else {
error(1);
logerr(gettext(MSG_GARBDEFLT), (attrib_save) ?
((attrib_save[0]) ? attrib_save : gettext("none")) :
gettext("unreadable at owner"));
return (1);
}
if (mode_ptr && mapvar(1, mode_ptr) == 0)
mode = strtol(mode_ptr, &pt, 8);
else {
error(1);
logerr(gettext(MSG_GARBDEFLT), (attrib_save) ?
((attrib_save[0]) ? attrib_save : gettext("none")) :
gettext("unreadable at mode"));
return (1);
}
if (d_own[nfp])
free(d_own[nfp]);
if (d_grp[nfp])
free(d_grp[nfp]);
d_mod[nfp] = mode;
d_own[nfp] = qstrdup(owner);
d_grp[nfp] = qstrdup(group);
attrpreset(d_mod[nfp], d_own[nfp], d_grp[nfp]);
return (0);
}
static void
doinclude(void)
{
char file[PATH_MAX];
char temp[PATH_MAX];
(void) fgets(temp, PATH_MAX, fp);
(void) sscanf(temp, "%1024s", file);
translate(file, temp);
canonize(temp);
if (*temp == '\0')
return;
else if (*temp != '/')
(void) snprintf(file, sizeof (file), "%s/%s", dname[nfp], temp);
else
(void) strlcpy(file, temp, sizeof (file));
canonize(file);
pushenv(file);
}
static void
translate(register char *pt, register char *copy)
{
char *pt2, varname[MAX_PKG_PARAM_LENGTH];
token:
while (isspace(*pt))
pt++;
while (*pt && !isspace(*pt)) {
if (*pt == '$') {
pt2 = varname;
while (*++pt && !strchr("/= \t\n\r", *pt))
*pt2++ = *pt;
*pt2 = '\0';
if (pt2 = getenv(varname)) {
while (*pt2)
*copy++ = *pt2++;
}
} else
*copy++ = *pt++;
}
if (*pt) {
*copy++ = ' ';
goto token;
}
*copy = '\0';
}
static void
error(int flag)
{
static char *lasterr = NULL;
if (lasterr != proto[nfp]) {
lasterr = proto[nfp];
(void) fprintf(stderr, gettext("ERROR in %s:\n"), lasterr);
}
if (flag)
errflg++;
}
static void
pushenv(char *file)
{
register char *pt;
static char topdir[PATH_MAX];
if ((nfp+1) >= NRECURS) {
error(1);
logerr(gettext(MSG_NRECURS), NRECURS);
logerr(gettext(MSG_IGNINCLUDE), file);
return;
}
if (strcmp(file, "-") == 0) {
fp = stdin;
} else if ((fp = fopen(file, "r")) == NULL) {
error(1);
logerr(gettext(MSG_RDINCLUDE), file, errno);
if (nfp >= 0) {
logerr(gettext(MSG_IGNINCLUDE), file);
fp = sfp[nfp];
return;
} else
quit(1);
}
sfp[++nfp] = fp;
srchp[nfp][0] = NULL;
rootp[nfp][0] = NULL;
d_mod[nfp] = (mode_t)(-1);
d_own[nfp] = NULL;
d_grp[nfp] = NULL;
if (!nfp) {
proto[nfp] = file;
if (file[0] == '/')
pt = strcpy(topdir, file);
else {
pt = getcwd(NULL, PATH_MAX);
if (pt == NULL) {
progerr(gettext(ERR_GETCWD), errno);
quit(99);
}
(void) snprintf(topdir, sizeof (topdir),
"%s/%s", pt, file);
}
if (pt = strrchr(topdir, '/'))
*pt = '\0';
if (topdir[0] == '\0')
(void) strlcpy(topdir, "/", sizeof (topdir));
dname[nfp] = topdir;
} else {
proto[nfp] = qstrdup(file);
dname[nfp] = qstrdup(file);
if (pt = strrchr(dname[nfp], '/'))
*pt = '\0';
else {
free(dname[nfp]);
dname[nfp] = qstrdup(dname[nfp-1]);
return;
}
}
canonize(dname[nfp]);
if (chdir(dname[nfp])) {
error(1);
logerr(gettext(MSG_CHDIR), dname[nfp]);
if (!nfp)
quit(1);
logerr(gettext(MSG_IGNINCLUDE), proto[nfp]);
(void) popenv();
}
}
static int
popenv(void)
{
int i;
(void) fclose(fp);
if (nfp) {
if (proto[nfp])
free(proto[nfp]);
if (dname[nfp])
free(dname[nfp]);
for (i = 0; srchp[nfp][i]; i++)
free(srchp[nfp][i]);
for (i = 0; rootp[nfp][i]; i++)
free(rootp[nfp][i]);
if (d_own[nfp])
free(d_own[nfp]);
if (d_grp[nfp])
free(d_grp[nfp]);
fp = sfp[--nfp];
if (chdir(dname[nfp])) {
error(1);
logerr(gettext(MSG_CHDIR), dname[nfp]);
logerr(gettext(MSG_INCOMPLETE), proto[nfp]);
return (popenv());
}
return (1);
}
return (0);
}
static void
lputenv(char *s)
{
char *pt;
int i;
pt = strchr(s, '=');
if (!pt)
return;
*pt = '\0';
for (i = 0; i < nrdonly; i++) {
if (strcmp(rdonly[i], s) == 0) {
*pt = '=';
return;
}
}
*pt = '=';
if (putenv(qstrdup(s))) {
progerr(gettext(ERR_ENVBUILD), errno);
quit(99);
}
}
static char *
srchroot(char *path, char *copy)
{
struct stat statbuf;
int i;
i = 0;
root = rootlist[i++];
do {
cvtpath(path, copy);
canonize(copy);
if (stat(copy, &statbuf) || !(statbuf.st_mode & S_IFREG)) {
root = rootlist[i++];
continue;
}
return (copy);
} while (root != NULL);
error(1);
logerr(gettext(MSG_SRCHROOT), path);
return (NULL);
}