summaryrefslogtreecommitdiff
path: root/usr/src/cmd/svr4pkg/installf
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/svr4pkg/installf')
-rw-r--r--usr/src/cmd/svr4pkg/installf/Makefile49
-rw-r--r--usr/src/cmd/svr4pkg/installf/dofinal.c236
-rw-r--r--usr/src/cmd/svr4pkg/installf/installf.c308
-rw-r--r--usr/src/cmd/svr4pkg/installf/installf.h57
-rw-r--r--usr/src/cmd/svr4pkg/installf/main.c545
-rw-r--r--usr/src/cmd/svr4pkg/installf/removef.c127
6 files changed, 1322 insertions, 0 deletions
diff --git a/usr/src/cmd/svr4pkg/installf/Makefile b/usr/src/cmd/svr4pkg/installf/Makefile
new file mode 100644
index 0000000000..da8ff4b2b7
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+PROG= installf
+
+OBJS= installf.o \
+ main.o \
+ removef.o \
+ dofinal.o
+
+include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg
+
+ROOTUSRSBINLINK = $(ROOTUSRSBIN)/removef
+
+LDLIBS += -lpkg -linstzones -ladm
+LDLIBS += -lnsl -lsocket
+
+.KEEP_STATE:
+
+all: $(PROG)
+install: all $(ROOTUSRSBINPROG) $(ROOTUSRSBINLINK)
+
+$(ROOTUSRSBINLINK): $(ROOTUSRSBINPROG)
+ $(RM) $@; $(LN) $(ROOTUSRSBINPROG) $@
+
+include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg.targ
diff --git a/usr/src/cmd/svr4pkg/installf/dofinal.c b/usr/src/cmd/svr4pkg/installf/dofinal.c
new file mode 100644
index 0000000000..331ea43810
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/dofinal.c
@@ -0,0 +1,236 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#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"
+
+extern struct cfextra **extlist;
+extern struct cfent **eptlist;
+
+extern char *pkginst;
+
+#define ERR_WRITE "write of intermediate contents file failed"
+
+static char *check_db_entry(VFP_T *, struct cfextra *, int, char *, int *);
+
+/*ARGSUSED*/
+int
+dofinal(VFP_T *vfp, VFP_T *vfpo, int rmflag, char *myclass, char *prog)
+{
+ struct cfextra entry;
+ int n, indx, dbchg;
+ char *save_path = NULL;
+
+ entry.cf_ent.pinfo = NULL;
+ entry.fsys_value = BADFSYS;
+ entry.fsys_base = BADFSYS;
+ indx = 0;
+
+ while (extlist && extlist[indx] && (extlist[indx]->cf_ent.ftype == 'i'))
+ indx++;
+
+ dbchg = 0;
+
+ while (n = srchcfile(&(entry.cf_ent), "*", vfp, vfpo)) {
+ if (n < 0) {
+ char *errstr = getErrstr();
+ progerr(gettext
+ ("bad entry read in contents file"));
+ logerr(gettext("pathname=%s"),
+ (entry.cf_ent.path &&
+ *(entry.cf_ent.path)) ?
+ entry.cf_ent.path : "Unknown");
+ logerr(gettext("problem=%s"),
+ (errstr && *errstr) ? errstr :
+ "Unknown");
+ quit(99);
+ }
+ save_path = check_db_entry(
+ vfpo, &entry, rmflag, myclass, &dbchg);
+
+ /* Restore original server-relative path, if needed */
+ if (save_path != NULL) {
+ entry.cf_ent.path = save_path;
+ save_path = NULL;
+ }
+ }
+
+ return (dbchg);
+}
+
+static char *
+check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass,
+ int *dbchg)
+{
+ struct pinfo *pinfo;
+ int fs_entry;
+ char *save_path = NULL;
+ char *tp;
+
+ /* write this entry to the contents file */
+
+ if (myclass && strcmp(myclass, entry->cf_ent.pkg_class)) {
+ if (putcvfpfile(&entry->cf_ent, vfpo)) {
+ progerr(gettext(ERR_WRITE));
+ quit(99);
+ }
+ return (NULL);
+ }
+
+ /*
+ * Now scan each package instance holding this file or
+ * directory and see if it matches the package we are
+ * updating here.
+ */
+ pinfo = entry->cf_ent.pinfo;
+ while (pinfo) {
+ if (strcmp(pkginst, pinfo->pkg) == 0)
+ break;
+ pinfo = pinfo->next;
+ }
+
+ /*
+ * If pinfo == NULL at this point, then this file or
+ * directory isn't part of the package of interest.
+ * So the loop below executes only on files in the package
+ * of interest.
+ */
+
+ save_path = NULL;
+
+ if (pinfo) {
+ if (rmflag && (pinfo->status == RM_RDY)) {
+ *dbchg = 1;
+
+ (void) eptstat(&(entry->cf_ent), pkginst, '@');
+
+ if (entry->cf_ent.npkgs) {
+ if (putcvfpfile(&(entry->cf_ent), vfpo)) {
+ progerr(gettext(ERR_WRITE));
+ quit(99);
+ }
+ }
+ return (NULL);
+
+ } else if (!rmflag && (pinfo->status == INST_RDY)) {
+ *dbchg = 1;
+
+ /* tp is the server-relative path */
+ tp = fixpath(entry->cf_ent.path);
+ /* save_path is the cmd line path */
+ save_path = entry->cf_ent.path;
+ /* entry has the server-relative path */
+ entry->cf_ent.path = tp;
+
+ /*
+ * The next if statement figures out how
+ * the contents file entry should be
+ * annotated.
+ *
+ * Don't install or verify objects for
+ * remote, read-only filesystems. We
+ * need only verify their presence and
+ * flag them appropriately from some
+ * server. Otherwise, ok to do final
+ * check.
+ */
+ fs_entry = fsys(entry->cf_ent.path);
+
+ if (is_remote_fs_n(fs_entry) &&
+ !is_fs_writeable_n(fs_entry)) {
+ /*
+ * Mark it shared whether it's present
+ * or not. life's too funny for me
+ * to explain.
+ */
+ pinfo->status = SERVED_FILE;
+
+ /*
+ * restore for now. This may
+ * chg soon.
+ */
+ entry->cf_ent.path = save_path;
+ } else {
+ /*
+ * If the object is accessible, check
+ * the new entry for existence and
+ * attributes. If there's a problem,
+ * mark it NOT_FND; otherwise,
+ * ENTRY_OK.
+ */
+ if (is_mounted_n(fs_entry)) {
+ int n;
+
+ n = finalck((&entry->cf_ent), 1, 1,
+ B_FALSE);
+
+ pinfo->status = ENTRY_OK;
+ if (n != 0) {
+ pinfo->status = NOT_FND;
+ }
+ }
+
+ /*
+ * It's not remote, read-only but it
+ * may look that way to the client.
+ * If it does, overwrite the above
+ * result - mark it shared.
+ */
+ if (is_served_n(fs_entry))
+ pinfo->status = SERVED_FILE;
+
+ /* restore original path */
+ entry->cf_ent.path = save_path;
+ /* and clear save_path */
+ save_path = NULL;
+ }
+ }
+ }
+
+ /* Output entry to contents file. */
+ if (putcvfpfile(&(entry->cf_ent), vfpo)) {
+ progerr(gettext(ERR_WRITE));
+ quit(99);
+ }
+
+ return (save_path);
+}
diff --git a/usr/src/cmd/svr4pkg/installf/installf.c b/usr/src/cmd/svr4pkg/installf/installf.c
new file mode 100644
index 0000000000..b0eab9cedc
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/installf.c
@@ -0,0 +1,308 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#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(); /* at least pathname is required */
+ extlist = calloc(2, sizeof (struct cfextra *));
+ extlist[0] = new = calloc(1, sizeof (struct cfextra));
+ eptnum = 1;
+
+ /* There is only one filename on the command line. */
+ checkPaths(argv);
+ if (validate(new, argc, argv))
+ quit(1);
+ return (0);
+ }
+
+ /* Read stdin to obtain entries, which need to be sorted. */
+ 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(); /* at least pathname is required */
+
+ 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);
+
+ /* initialize cfent structure */
+ ept->pinfo = NULL;
+ (void) gpkgmapvfp(ept, (VFP_T *)NULL); /* This just clears stuff. */
+
+ 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);
+ }
+
+ /*
+ * It would be a good idea to figure out how to get much of
+ * this done using facilities in procmap.c - JST
+ */
+ if (pt = strchr(argv[n], '=')) {
+ *pt = '\0'; /* cut off pathname at the = sign */
+ 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);
+ }
+
+ /* get the pathnames */
+ if (eval_path(&(ext->server_path), &(ext->client_path),
+ &(ext->map_path), argv[n++]) == 0)
+ return (1);
+
+ ept->path = ext->client_path;
+
+ /* This isn't likely to happen; but, better safe than sorry. */
+ if (RELATIVE(ept->path)) {
+ progerr(gettext(ERR_RELPATH), ept->path);
+ return (1);
+ }
+
+ if (is_a_link) {
+ /* links specifications should be handled right here */
+ ept->ftype = ((n >= argc) ? 'l' : argv[n++][0]);
+
+ /* If nothing follows the '=', it's invalid */
+ if (!pt[1]) {
+ progerr(gettext(ERR_LINK), ept->path);
+ return (1);
+ }
+
+ /* Test for an argument after the link. */
+ if (argc != n) {
+ progerr(gettext(ERR_LINKARGS), ept->path);
+ return (1);
+ }
+
+ /*
+ * If it's a link but it's neither hard nor symbolic then
+ * it's bad.
+ */
+ 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) {
+ /* we are expecting to change object's contents */
+ 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));
+}
+
+/*
+ * If the path at argv[0] has the value of
+ * PKG_INSTALL_ROOT prepended, remove it
+ */
+static void
+checkPaths(char *argv[])
+{
+ char *root;
+ int rootLen;
+
+ /*
+ * Note- No local copy of argv is needed since this
+ * function is guaranteed to replace argv with a subset of
+ * the original argv.
+ */
+
+ /* We only want to canonize the path if it contains multiple '/'s */
+
+ 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;
+ }
+ }
+}
diff --git a/usr/src/cmd/svr4pkg/installf/installf.h b/usr/src/cmd/svr4pkg/installf/installf.h
new file mode 100644
index 0000000000..6d473aa3af
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/installf.h
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _INSTALLF_H
+#define _INSTALLF_H
+
+
+/*
+ * Block comment that describes the contents of this file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cfext.h>
+
+extern struct cfextra **extlist;
+extern int eptnum;
+extern int warnflag;
+extern char *classname;
+
+extern int cfentcmp(const void *, const void *);
+extern void quit(int);
+extern void usage(void);
+extern void removef(int, char *[]);
+extern int installf(int, char *[]);
+extern int dofinal(VFP_T *, VFP_T *, int, char *, char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INSTALLF_H */
diff --git a/usr/src/cmd/svr4pkg/installf/main.c b/usr/src/cmd/svr4pkg/installf/main.c
new file mode 100644
index 0000000000..8c70add8ed
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/main.c
@@ -0,0 +1,545 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#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; /* libinst/pkgdbmerg.c */
+
+struct cfextra **extlist;
+struct pinfo **eptlist;
+
+char *classname = NULL;
+char *pkginst;
+char *uniTmp;
+char *abi_sym_ptr;
+char *ulim;
+char *script;
+
+int eptnum;
+int sortflag;
+int nosetuid;
+int nocnflct;
+int warnflag = 0;
+
+/* libadm/pkgparam.c */
+extern void set_PKGADM(char *newpath);
+extern void set_PKGLOC(char *newpath);
+
+extern void set_limit(void);
+
+int
+main(int argc, char **argv)
+{
+ FILE *pp;
+ VFP_T *cfTmpVfp;
+ VFP_T *cfVfp;
+ char *cmd;
+ char *tp;
+ char *prog;
+ char *pt;
+ char *vfstab_file = NULL;
+ char line[1024];
+ char outbuf[PATH_MAX];
+ int c;
+ int dbchg;
+ int err;
+ int fflag = 0;
+ int map_client = 1;
+ int n;
+ int pkgrmremote = 0; /* don't remove remote files */
+ struct cfent *ept;
+
+ /* hookup signals */
+
+ (void) signal(SIGHUP, exit);
+ (void) signal(SIGINT, exit);
+ (void) signal(SIGQUIT, exit);
+
+ /* initialize locale mechanism */
+
+ (void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST"
+#endif /* !defined(TEXT_DOMAIN) */
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* determine program name */
+
+ prog = set_prog_name(argv[0]);
+
+ /* tell instzones interface how to access package output functions */
+
+ z_set_output_functions(echo, echoDebug, progerr);
+
+ /* only allow root to run this program */
+
+ 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();
+ }
+
+ /* bug id 4244631, not ABI compliant */
+ abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
+ if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0)
+ set_nonABI_symlinks();
+
+ /* bugId 4012147 */
+ 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;
+ /* validate that classname is acceptable */
+ 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;
+
+ /*
+ * Don't map the client filesystem onto the server's. Assume
+ * the mounts have been made for us.
+ */
+ case 'M':
+ map_client = 0;
+ break;
+
+ /*
+ * Allow admin to establish the client filesystem using a
+ * vfstab-like file of stable format.
+ */
+ case 'V':
+ vfstab_file = flex_device(optarg, 2);
+ map_client = 1;
+ break;
+
+ case 'A':
+ pkgrmremote++;
+ break;
+
+ case 'R': /* added for newroot option */
+ if (!set_inst_root(optarg)) {
+ progerr(gettext(ERR_ROOT_CMD));
+ exit(1);
+ }
+ break;
+
+ default:
+ usage();
+ /*NOTREACHED*/
+ /*
+ * Although usage() calls a noreturn function,
+ * needed to add return (1); so that main() would
+ * pass compilation checks. The statement below
+ * should never be executed.
+ */
+ return (1);
+ }
+ }
+
+ if (pkgrmremote && (!is_an_inst_root() || fflag || INSTALF)) {
+ usage();
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Get the mount table info and store internally.
+ */
+ if (get_mntinfo(map_client, vfstab_file))
+ exit(1);
+
+ /*
+ * This function defines the standard /var/... directories used later
+ * to construct the paths to the various databases.
+ */
+ (void) set_PKGpaths(get_inst_root());
+
+ /*
+ * If this is being installed on a client whose /var filesystem is
+ * mounted in some odd way, remap the administrative paths to the
+ * real filesystem. This could be avoided by simply mounting up the
+ * client now; but we aren't yet to the point in the process where
+ * modification of the filesystem is permitted.
+ */
+ 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));
+ }
+
+ sortflag = 0;
+
+ /*
+ * get the package name and verify length is not too long
+ */
+
+ pkginst = argv[optind++];
+ if (pkginst == NULL) {
+ usage();
+ /*NOTREACHED*/
+
+ }
+
+ n = strlen(pkginst);
+ if (n > PKGSIZ) {
+ progerr(gettext(ERR_PKGNAME_TOO_LONG), PKGSIZ, n, n-PKGSIZ,
+ PKGSIZ);
+ usage();
+ /*NOTREACHED*/
+ }
+
+ /*
+ * The following is used to setup the environment. Note that the
+ * variable 'BASEDIR' is only meaningful for this utility if there
+ * is an install root, recorded in PKG_INSTALL_ROOT. Otherwise, this
+ * utility can create a file or directory anywhere unfettered by
+ * the basedir associated with the package instance.
+ */
+ if ((err = set_basedirs(0, NULL, pkginst, 1)) != 0)
+ exit(err);
+
+ if (INSTALF)
+ mkbasedir(0, get_basedir());
+
+ if (fflag) {
+ /* installf and removef must only have pkginst */
+ if (optind != argc) {
+ usage();
+ /*NOTREACHED*/
+ }
+ } else {
+ /*
+ * installf and removef must have at minimum
+ * pkginst & pathname specified on command line
+ */
+ if (optind >= argc) {
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ 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);
+ }
+
+#ifdef ALLOW_EXCEPTION_PKG_LIST
+ /*
+ * *********************************************************************
+ * this feature is removed starting with Solaris 10 - there is no built
+ * in list of packages that should be run "the old way"
+ * *********************************************************************
+ */
+ /* Until 2.9, set it from the execption list */
+ if (pkginst && exception_pkg(pkginst, LINK))
+ set_nonABI_symlinks();
+#endif
+ /*
+ * This maps the client filesystems into the server's space.
+ */
+ if (map_client && !mount_client())
+ logerr(gettext(MSG_MANMOUNT));
+
+ /* open the package database (contents) file */
+
+ if (!ocfile(&cfVfp, &cfTmpVfp, 0L)) {
+ quit(1);
+ }
+
+ if (fflag) {
+ dbchg = dofinal(cfVfp, 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(cfVfp, cfTmpVfp, extlist, 0);
+ if (dbchg < 0) {
+ progerr(gettext(ERR_MERG));
+ quit(99);
+ }
+ }
+
+ if (dbchg) {
+ if ((n = swapcfile(&cfVfp, &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);
+
+ /* Skip duplicated paths */
+ if ((n > 0) && (strncmp(ept->path,
+ extlist[n-1]->cf_ent.path, PATH_MAX) == 0)) {
+ continue;
+ }
+
+ if (!extlist[n]->mstat.shared) {
+ /*
+ * Only output paths that can be deleted.
+ * so need to skip if the object is owned
+ * by a remote server and removal is not
+ * being forced.
+ */
+ if (ept->pinfo &&
+ (ept->pinfo->status == SERVED_FILE) &&
+ !pkgrmremote)
+ continue;
+
+ c = 0;
+ if (is_a_cl_basedir() && !is_an_inst_root()) {
+ c = strlen(get_client_basedir());
+ (void) snprintf(outbuf, sizeof (outbuf),
+ "%s/%s\n", get_basedir(),
+ &(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);
+ }
+ }
+ }
+
+ /* Sort the contents files if needed */
+ if (sortflag) {
+ int n;
+
+ warnflag += (ocfile(&cfVfp, &cfTmpVfp, 0L)) ? 0 : 1;
+ if (!warnflag) {
+ size_t len;
+
+ len = strlen(CMD_SORT) + strlen(get_PKGADM()) +
+ strlen("/contents") + 5;
+ cmd = (char *)malloc(len);
+ (void) snprintf(cmd, len, "%s %s/contents",
+ CMD_SORT, get_PKGADM());
+ pp = popen(cmd, "r");
+ if (pp == NULL) {
+ (void) vfpClose(&cfVfp);
+ (void) vfpClose(&cfTmpVfp);
+ free(cmd);
+ progerr(gettext(ERR_SORT));
+ quit(1);
+ }
+ while (fgets(line, 1024, pp) != NULL) {
+ if (line[0] != DUP_ENTRY) {
+ vfpPuts(cfTmpVfp, line);
+ }
+ }
+ free(cmd);
+ (void) pclose(pp);
+ n = swapcfile(&cfVfp, &cfTmpVfp, pkginst, 1);
+ if (n == RESULT_WRN) {
+ warnflag++;
+ } else if (n == RESULT_ERR) {
+ quit(99);
+ }
+
+ relslock(); /* Unlock the database. */
+ }
+ }
+
+ z_destroyMountTable();
+
+ quit(warnflag ? 1 : 0);
+ /* LINTED: no return */
+}
+
+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);
+}
diff --git a/usr/src/cmd/svr4pkg/installf/removef.c b/usr/src/cmd/svr4pkg/installf/removef.c
new file mode 100644
index 0000000000..6b7f8bdead
--- /dev/null
+++ b/usr/src/cmd/svr4pkg/installf/removef.c
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <locale.h>
+#include <libintl.h>
+#include <pkglib.h>
+#include <install.h>
+#include <libinst.h>
+#include <libadm.h>
+#include "installf.h"
+
+void
+removef(int argc, char *argv[])
+{
+ struct cfextra *new;
+ char buf[PATH_MAX];
+ char *path;
+ int flag;
+ int len;
+ int max_eptnum;
+
+ flag = strcmp(argv[0], "-") == 0;
+
+ eptnum = 0;
+ max_eptnum = 64; /* starting size of array */
+ extlist = malloc(max_eptnum * sizeof (struct cfextra *));
+
+ for (;;) {
+ if (flag) {
+ if (fgets(buf, PATH_MAX, stdin) == NULL)
+ break;
+
+ /* strip trailing new line */
+ len = strlen(buf);
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ path = buf;
+ } else {
+ if (argc-- <= 0)
+ break;
+ path = argv[argc];
+ }
+
+ /*
+ * This strips the install root from the path using
+ * a questionable algorithm. This should go away as
+ * we define more precisely the command line syntax
+ * with our '-R' option. - JST
+ */
+ path = orig_path_ptr(path);
+
+ if (path == NULL) {
+ logerr(gettext("ERROR: no pathname was provided"));
+ warnflag++;
+ continue;
+ }
+
+ if (*path != '/') {
+ logerr(gettext(
+ "WARNING: relative pathname <%s> ignored"), path);
+ warnflag++;
+ continue;
+ }
+
+ new = calloc(1, sizeof (struct cfextra));
+ if (new == NULL) {
+ progerr(strerror(errno));
+ quit(99);
+ }
+ new->cf_ent.ftype = '-';
+
+ (void) eval_path(&(new->server_path), &(new->client_path),
+ &(new->map_path), path);
+
+ new->cf_ent.path = new->client_path;
+
+ extlist[eptnum++] = new;
+ if (eptnum >= max_eptnum) {
+ /* array size grows exponentially */
+ max_eptnum <<= 1;
+ extlist = realloc(extlist,
+ max_eptnum * sizeof (struct cfextra *));
+ if (extlist == NULL) {
+ progerr(strerror(errno));
+ quit(99);
+ }
+ }
+ }
+ extlist[eptnum] = (struct cfextra *)NULL;
+
+ qsort((char *)extlist,
+ (unsigned)eptnum, sizeof (struct cfextra *), cfentcmp);
+}