summaryrefslogtreecommitdiff
path: root/usr/src/cmd/svr4pkg/installf/main.c
diff options
context:
space:
mode:
authorMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
committerMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
commit5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch)
tree0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/cmd/svr4pkg/installf/main.c
parent2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff)
downloadillumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/cmd/svr4pkg/installf/main.c')
-rw-r--r--usr/src/cmd/svr4pkg/installf/main.c545
1 files changed, 545 insertions, 0 deletions
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);
+}