/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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] " \ "\n" \ "\t%s [[-M] -R host_path] [-V ...] [-c class] " \ " \n" \ "\t where may be defined as:\n" \ "\t\tf \n" \ "\t\tv \n" \ "\t\te \n" \ "\t\td \n" \ "\t\tx \n" \ "\t\tp \n" \ "\t\tc \n" \ "\t\tb \n" \ "\t\ts =\n" \ "\t\tl =\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 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) { 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; /* 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)); } /* * 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(&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); /* 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()) { /* * A path in contents db might have * other prefix than BASEDIR of the * package */ 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); /* 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); }