#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pkgstrct.h>
#include <locale.h>
#include <libintl.h>
#include <pkglib.h>
#include <install.h>
#include <libinst.h>
#include <libadm.h>
#include "installf.h"
#define LSIZE 1024
#define MALSIZ 164
#define ERR_MAJOR "invalid major number <%s> specified for <%s>"
#define ERR_MINOR "invalid minor number <%s> specified for <%s>"
#define ERR_MODE "invalid mode <%s> specified for <%s>"
#define ERR_RELPATH "relative pathname <%s> not permitted"
#define ERR_NULLPATH "NULL or garbled pathname"
#define ERR_LINK "invalid link specification <%s>"
#define ERR_LINKFTYPE "ftype <%c> does not match link specification <%s>"
#define ERR_LINKARGS "extra arguments in link specification <%s>"
#define ERR_LINKREL "relative pathname in link specification <%s>"
#define ERR_FTYPE "invalid ftype <%c> for <%s>"
#define ERR_ARGC "invalid number of arguments for <%s>"
#define ERR_SPECALL "ftype <%c> requires all fields to be specified"
static int validate(struct cfextra *ext, int argc, char *argv[]);
static void checkPaths(char *argv[]);
int
installf(int argc, char *argv[])
{
struct cfextra *new;
char line[LSIZE];
char *largv[8];
int myerror;
if (strcmp(argv[0], "-") != 0) {
if (argc < 1)
usage();
extlist = calloc(2, sizeof (struct cfextra *));
extlist[0] = new = calloc(1, sizeof (struct cfextra));
eptnum = 1;
checkPaths(argv);
if (validate(new, argc, argv))
quit(1);
return (0);
}
eptnum = 0;
myerror = 0;
extlist = calloc(MALSIZ, sizeof (struct cfextra *));
while (fgets(line, LSIZE, stdin) != NULL) {
argc = 0;
argv = largv;
argv[argc++] = strtok(line, " \t\n");
while (argv[argc] = strtok(NULL, " \t\n"))
argc++;
if (argc < 1)
usage();
new = calloc(1, sizeof (struct cfextra));
if (new == NULL) {
progerr(strerror(errno));
quit(99);
}
checkPaths(argv);
if (validate(new, argc, argv))
myerror++;
extlist[eptnum] = new;
if ((++eptnum % MALSIZ) == 0) {
extlist = realloc(extlist,
(sizeof (struct cfextra *) * (eptnum+MALSIZ)));
if (!extlist) {
progerr(strerror(errno));
quit(99);
}
}
}
extlist[eptnum] = (struct cfextra *)NULL;
qsort((char *)extlist, (unsigned)eptnum, sizeof (struct cfextra *),
cfentcmp);
return (myerror);
}
static int
validate(struct cfextra *ext, int argc, char *argv[])
{
char *ret, *pt;
int n, allspec, is_a_link;
struct cfent *ept;
ept = &(ext->cf_ent);
ept->pinfo = NULL;
(void) gpkgmapvfp(ept, (VFP_T *)NULL);
n = allspec = 0;
if (classname)
(void) strncpy(ept->pkg_class, classname, CLSSIZ);
if (argv[n] == NULL || *(argv[n]) == '\000') {
progerr(gettext(ERR_NULLPATH));
return (1);
}
if (pt = strchr(argv[n], '=')) {
*pt = '\0';
is_a_link = 1;
} else
is_a_link = 0;
if (RELATIVE(argv[n])) {
progerr(gettext(ERR_RELPATH),
(argv[n] == NULL) ? "unknown" : argv[n]);
return (1);
}
if (eval_path(&(ext->server_path), &(ext->client_path),
&(ext->map_path), argv[n++]) == 0)
return (1);
ept->path = ext->client_path;
if (RELATIVE(ept->path)) {
progerr(gettext(ERR_RELPATH), ept->path);
return (1);
}
if (is_a_link) {
ept->ftype = ((n >= argc) ? 'l' : argv[n++][0]);
if (!pt[1]) {
progerr(gettext(ERR_LINK), ept->path);
return (1);
}
if (argc != n) {
progerr(gettext(ERR_LINKARGS), ept->path);
return (1);
}
if (!strchr("sl", ept->ftype)) {
progerr(gettext(ERR_LINKFTYPE), ept->ftype, ept->path);
return (1);
}
ext->server_local = pathdup(pt+1);
ext->client_local = ext->server_local;
ept->ainfo.local = ext->client_local;
return (0);
} else if (n >= argc) {
return (0);
}
ept->ftype = argv[n++][0];
if (strchr("sl", ept->ftype)) {
progerr(gettext(ERR_LINK), ept->path);
return (1);
} else if (!strchr("?fvedxcbp", ept->ftype)) {
progerr(gettext(ERR_FTYPE), ept->ftype, ept->path);
return (1);
}
if (ept->ftype == 'b' || ept->ftype == 'c') {
if (n < argc) {
ept->ainfo.major = strtol(argv[n++], &ret, 0);
if (ret && *ret) {
progerr(gettext(ERR_MAJOR), argv[n-1],
ept->path);
return (1);
}
}
if (n < argc) {
ept->ainfo.minor = strtol(argv[n++], &ret, 0);
if (ret && *ret) {
progerr(gettext(ERR_MINOR), argv[n-1],
ept->path);
return (1);
}
allspec++;
}
}
allspec = 0;
if (n < argc) {
ept->ainfo.mode = strtol(argv[n++], &ret, 8);
if (ret && *ret) {
progerr(gettext(ERR_MODE), argv[n-1], ept->path);
return (1);
}
}
if (n < argc)
(void) strncpy(ept->ainfo.owner, argv[n++], ATRSIZ);
if (n < argc) {
(void) strncpy(ept->ainfo.group, argv[n++], ATRSIZ);
allspec++;
}
if (strchr("dxbcp", ept->ftype) && !allspec) {
progerr(gettext(ERR_ARGC), ept->path);
progerr(gettext(ERR_SPECALL), ept->ftype);
return (1);
}
if (n < argc) {
progerr(gettext(ERR_ARGC), ept->path);
return (1);
}
return (0);
}
int
cfentcmp(const void *p1, const void *p2)
{
struct cfextra *ext1 = *((struct cfextra **)p1);
struct cfextra *ext2 = *((struct cfextra **)p2);
return (strcmp(ext1->cf_ent.path, ext2->cf_ent.path));
}
static void
checkPaths(char *argv[])
{
char *root;
int rootLen;
canonize_slashes(argv[0]);
if ((root = get_inst_root()) == NULL)
return;
if (strcmp(root, "/") != 0) {
rootLen = strlen(root);
if (strncmp(argv[0], root, rootLen) == 0) {
argv[0] += rootLen;
}
}
}