#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <pkginfo.h>
#include <pkgstrct.h>
#include <pkglocs.h>
#include <locale.h>
#include <libintl.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <install.h>
#include <libadm.h>
#include <libinst.h>
#include "installf.h"
#define BASEDIR "/BASEDIR/"
#define INSTALF (*prog == 'i')
#define REMOVEF (*prog == 'r')
#define MSG_MANMOUNT "Assuming mounts were provided."
#define ERR_PKGNAME_TOO_LONG \
"The package name specified on the command line\n" \
"exceeds the maximum package name length: a package name may contain a\n" \
"maximum of <%d> characters; however, the package name specified on\n" \
"the command line contains <%d> characters, which exceeds the maximum\n" \
"package name length by <%d> characters. Please specify a package name\n" \
"that contains no more than <%d> characters."
#define ERR_DB_GET "unable to retrieve entries from the database."
#define ERR_DB_PUT "unable to update the package database."
#define ERR_ROOT_SET "Could not set install root from the environment."
#define ERR_ROOT_CMD "Command line install root contends with environment."
#define ERR_CLASSLONG "classname argument too long"
#define ERR_CLASSCHAR "bad character in classname"
#define ERR_INVAL "package instance <%s> is invalid"
#define ERR_NOTINST "package instance <%s> is not installed"
#define ERR_MERG "unable to merge contents file"
#define ERR_SORT "unable to sort contents file"
#define ERR_I_FAIL "installf did not complete successfully"
#define ERR_R_FAIL "removef did not complete successfully"
#define ERR_NOTROOT "You must be \"root\" for %s to execute properly."
#define ERR_USAGE0 "usage:\n" \
"\t%s [[-M|-A] -R host_path] [-V ...] pkginst path " \
"[path ...]\n" \
"\t%s [[-M|-A] -R host_path] [-V ...] pkginst path\n"
#define ERR_USAGE1 "usage:\n" \
"\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \
"<path>\n" \
"\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \
"<path> <specs>\n" \
"\t where <specs> may be defined as:\n" \
"\t\tf <mode> <owner> <group>\n" \
"\t\tv <mode> <owner> <group>\n" \
"\t\te <mode> <owner> <group>\n" \
"\t\td <mode> <owner> <group>\n" \
"\t\tx <mode> <owner> <group>\n" \
"\t\tp <mode> <owner> <group>\n" \
"\t\tc <major> <minor> <mode> <owner> <group>\n" \
"\t\tb <major> <minor> <mode> <owner> <group>\n" \
"\t\ts <path>=<srcpath>\n" \
"\t\tl <path>=<srcpath>\n" \
"\t%s [[-M] -R host_path] [-V ...] [-c class] -f pkginst\n"
#define CMD_SORT "sort +0 -1"
#define LINK 1
extern char dbst;
struct cfextra **extlist;
struct pinfo **eptlist;
char *classname = NULL;
char *pkginst;
char *uniTmp;
char *abi_sym_ptr;
char *ulim;
char *script;
int nosetuid;
int nocnflct;
int warnflag = 0;
extern void set_PKGADM(char *newpath);
extern void set_PKGLOC(char *newpath);
extern void set_limit(void);
int
main(int argc, char **argv)
{
VFP_T *cfTmpVfp;
PKGserver pkgserver = NULL;
char *tp;
char *prog;
char *pt;
char *vfstab_file = NULL;
char *temp_cl_basedir;
char outbuf[PATH_MAX];
int c;
int dbchg;
int err;
int fflag = 0;
int map_client = 1;
int n;
int pkgrmremote = 0;
struct cfent *ept;
(void) signal(SIGHUP, exit);
(void) signal(SIGINT, exit);
(void) signal(SIGQUIT, exit);
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
prog = set_prog_name(argv[0]);
z_set_output_functions(echo, echoDebug, progerr);
if (getuid() != 0) {
progerr(gettext(ERR_NOTROOT), prog);
exit(1);
}
ulim = getenv("PKG_ULIMIT");
script = getenv("PKG_PROC_SCRIPT");
if (ulim && script) {
set_limit();
clr_ulimit();
}
abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0)
set_nonABI_symlinks();
if ((uniTmp = getenv("PKG_NO_UNIFIED")) != NULL)
map_client = 0;
if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
progerr(gettext(ERR_ROOT_SET));
exit(1);
}
while ((c = getopt(argc, argv, "c:V:fAMR:?")) != EOF) {
switch (c) {
case 'f':
fflag++;
break;
case 'c':
classname = optarg;
if (strlen(classname) > (size_t)CLSSIZ) {
progerr(gettext(ERR_CLASSLONG));
exit(1);
}
for (pt = classname; *pt; pt++) {
if (!isalpha(*pt) && !isdigit(*pt)) {
progerr(gettext(ERR_CLASSCHAR));
exit(1);
}
}
break;
case 'M':
map_client = 0;
break;
case 'V':
vfstab_file = flex_device(optarg, 2);
map_client = 1;
break;
case 'A':
pkgrmremote++;
break;
case 'R':
if (!set_inst_root(optarg)) {
progerr(gettext(ERR_ROOT_CMD));
exit(1);
}
break;
default:
usage();
return (1);
}
}
if (pkgrmremote && (!is_an_inst_root() || fflag || INSTALF)) {
usage();
}
if (get_mntinfo(map_client, vfstab_file))
exit(1);
(void) set_PKGpaths(get_inst_root());
if (is_an_inst_root()) {
int fsys_value;
fsys_value = fsys(get_PKGLOC());
if (use_srvr_map_n(fsys_value))
set_PKGLOC(server_map(get_PKGLOC(), fsys_value));
fsys_value = fsys(get_PKGADM());
if (use_srvr_map_n(fsys_value))
set_PKGADM(server_map(get_PKGADM(), fsys_value));
}
pkginst = argv[optind++];
if (pkginst == NULL) {
usage();
}
n = strlen(pkginst);
if (n > PKGSIZ) {
progerr(gettext(ERR_PKGNAME_TOO_LONG), PKGSIZ, n, n-PKGSIZ,
PKGSIZ);
usage();
}
if ((err = set_basedirs(0, NULL, pkginst, 1)) != 0)
exit(err);
if (INSTALF)
mkbasedir(0, get_basedir());
if (fflag) {
if (optind != argc) {
usage();
}
} else {
if (optind >= argc) {
usage();
}
}
if (REMOVEF) {
if (classname) {
usage();
}
}
if (pkgnmchk(pkginst, "all", 0)) {
progerr(gettext(ERR_INVAL), pkginst);
exit(1);
}
if (fpkginst(pkginst, NULL, NULL) == NULL) {
progerr(gettext(ERR_NOTINST), pkginst);
exit(1);
}
if (map_client && !mount_client())
logerr(gettext(MSG_MANMOUNT));
if (!ocfile(&pkgserver, &cfTmpVfp, 0L)) {
quit(1);
}
if (fflag) {
dbchg = dofinal(pkgserver, cfTmpVfp, REMOVEF, classname, prog);
} else {
if (INSTALF) {
dbst = INST_RDY;
if (installf(argc-optind, &argv[optind]))
quit(1);
} else {
dbst = RM_RDY;
removef(argc-optind, &argv[optind]);
}
dbchg = pkgdbmerg(pkgserver, cfTmpVfp, extlist);
if (dbchg < 0) {
progerr(gettext(ERR_MERG));
quit(99);
}
}
if (dbchg) {
if ((n = swapcfile(pkgserver, &cfTmpVfp, pkginst, 1))
== RESULT_WRN) {
warnflag++;
} else if (n == RESULT_ERR) {
quit(99);
}
}
relslock();
if (REMOVEF && !fflag) {
for (n = 0; extlist[n]; n++) {
ept = &(extlist[n]->cf_ent);
if ((n > 0) && (strncmp(ept->path,
extlist[n-1]->cf_ent.path, PATH_MAX) == 0)) {
continue;
}
if (!extlist[n]->mstat.shared) {
if (ept->pinfo &&
(ept->pinfo->status == SERVED_FILE) &&
!pkgrmremote)
continue;
c = 0;
if (is_a_cl_basedir() && !is_an_inst_root()) {
temp_cl_basedir = get_client_basedir();
if (strncmp(ept->path, temp_cl_basedir,
strlen(temp_cl_basedir)) == 0) {
c = strlen(temp_cl_basedir);
(void) snprintf(outbuf,
sizeof (outbuf), "%s/%s\n",
get_basedir(),
&(ept->path[c]));
} else {
(void) snprintf(outbuf,
sizeof (outbuf),
"%s\n", &(ept->path[c]));
}
} else if (is_an_inst_root()) {
(void) snprintf(outbuf, sizeof (outbuf),
"%s/%s\n", get_inst_root(),
&(ept->path[c]));
} else {
(void) snprintf(outbuf, sizeof (outbuf),
"%s\n", &(ept->path[c]));
}
canonize(outbuf);
(void) printf("%s", outbuf);
}
}
} else if (INSTALF && !fflag) {
for (n = 0; extlist[n]; n++) {
ept = &(extlist[n]->cf_ent);
if (strchr("dxcbp", ept->ftype)) {
tp = fixpath(ept->path);
(void) averify(1, &ept->ftype, tp, &ept->ainfo);
}
}
}
pkgcloseserver(pkgserver);
z_destroyMountTable();
quit(warnflag ? 1 : 0);
}
void
quit(int n)
{
char *prog = get_prog_name();
unmount_client();
if (ulim && script) {
if (REMOVEF) {
set_ulimit(script, gettext(ERR_R_FAIL));
} else {
set_ulimit(script, gettext(ERR_I_FAIL));
}
}
exit(n);
}
void
usage(void)
{
char *prog = get_prog_name();
if (REMOVEF) {
(void) fprintf(stderr, gettext(ERR_USAGE0), prog, prog);
} else {
(void) fprintf(stderr, gettext(ERR_USAGE1), prog, prog, prog);
}
exit(1);
}