/*
* 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
* 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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <stdio.h>
#include <time.h>
#include <wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <ulimit.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <signal.h>
#include <locale.h>
#include <libintl.h>
#include <pkgstrct.h>
#include <pkginfo.h>
#include <pkgdev.h>
#include <pkglocs.h>
#include <pwd.h>
#include <assert.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <pkgweb.h>
#include <install.h>
#include <libinst.h>
#include <libadm.h>
#include <dryrun.h>
#include <messages.h>
#include "pkginstall.h"
/* imported globals */
extern char **environ;
extern char *pkgabrv;
extern char *pkgname;
extern char *pkgarch;
extern char *pkgvers;
extern char pkgwild[];
/* libadm(3LIB) */
extern char *get_install_root(void);
/* quit.c */
extern sighdlrFunc_t *quitGetTrapHandler(void);
extern void quitSetDstreamTmpdir(char *a_dstreamTempDir);
extern void quitSetZoneName(char *a_zoneName);
/* static globals */
static int ck_instbase(void);
static int cp_pkgdirs(void);
static int merg_respfile(void);
static int mv_pkgdirs(void);
static int rdonly(char *p);
static void set_dryrun_dir_loc(void);
static void unpack(void);
static char *ro_params[] = {
"PATH", "NAME", "PKG", "PKGINST",
"VERSION", "ARCH",
"INSTDATE", "CATEGORY",
};
/*
* The following variable is the name of the device to which stdin
* is connected during execution of a procedure script. PROC_STDIN is
* correct for all ABI compliant packages. For non-ABI-compliant
* packages, the '-o' command line switch changes this to PROC_XSTDIN
* to allow user interaction during these scripts. -- JST
*/
static int non_abi_scripts = 0;
static int suppressCopyright = 0;
static int nointeract = 0;
/* exported globals */
char *msgtext;
int dbchg;
int dparts = 0;
int dreboot = 0;
int failflag = 0;
int ireboot = 0;
int nocnflct;
int nosetuid;
int pkgverbose = 0;
int rprcflag;
int warnflag = 0;
/*
* this global is referenced by:
* getinst - [RW] - incremented if:
* - installing same instance again
* - overwriting an existing instance
* - not installing a new instance
* quit - [RO] - if non-zero and started non-zero:
* - the new <PKGINST>/install directory and rename <PKGINST>/install.save
* - back to <PKGINST>/install
* main.c - [RO] - if non-zero:
* - alter manner in which parameters are setup for scripts
* - set UPDATE=yes in environment
*/
static int update = 0;
/* Set by -O debug: debug output is enabled? */
/* Set by the -G option: install packages in global zone only */
/* Set by -O preinstallcheck */
/* Set by -O parent-zone-name= */
/* Set by -O parent-zone-type= */
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
/* This is the text for the "-O parent-zone-name=" option */
/* This is the text for the "-O parent-zone-type=" option */
static char *cpio_names[] = {
"root",
"root.cpio",
"reloc",
"reloc.cpio",
"root.Z",
"root.cpio.Z",
"reloc.Z",
"reloc.cpio.Z",
0
};
int
{
char **np;
char *abi_comp_ptr;
char *abi_nm_ptr;
char *abi_sym_ptr;
char *device;
char *p;
char *pt;
char *temp;
int c;
int disableAttributes = 0;
int err;
int init_install = 0;
int is_comp_arch;
int live_continue = 0;
int n;
int nparts;
int npkgs;
int part;
int saveSpoolInstall = 0;
/* reset contents of all default paths */
/* initialize locale environment */
(void) textdomain(TEXT_DOMAIN);
/* initialize program name */
prog_full_name = argv[0];
(void) set_prog_name(argv[0]);
/* tell spmi zones interface how to access package output functions */
/* exit if not root */
if (getuid()) {
exit(1);
/* NOTREACHED */
}
/*
* determine how pkgmap() deals with environment variables:
* - MAPALL - resolve all variables
* - MAPBUILD - map only build variables
* - MAPINSTALL - map only install variables
* - MAPNONE - map no variables
*/
/* set sane umask */
(void) umask(0022);
/* initially no source "device" */
/* reset npkgs (used as pkg remaining count in quit.c) */
npkgs = 0;
/* Read PKG_INSTALL_ROOT from the environment, if it's there. */
exit(1);
}
/* parse command line options */
"?Aa:B:b:Cc:D:d:eFf:GhIiMm:N:noO:p:R:r:StV:vyz")) != EOF) {
switch (c) {
/*
* Same as pkgadd: This disables attribute checking.
* It speeds up installation a little bit.
*/
case 'A':
break;
/*
* Same as pkgadd: Define an installation administration
* file, admin, to be used in place of the default
* administration file. The token none overrides the use
* of any admin file, and thus forces interaction with the
* user. Unless a full path name is given, pkgadd first
* looks in the current working directory for the
* administration file. If the specified administration
* file is not in the current working directory, pkgadd
* administration file.
*/
case 'a':
break;
/*
* Same as pkgadd: control block size given to
* pkginstall - block size used in read()/write() loop;
* default is st_blksize from stat() of source file.
*/
case 'B':
break;
/*
* Same as pkgadd: location where executables needed
* by procedure scripts can be found
*/
case 'b':
if (!path_valid(optarg)) {
exit(1);
}
exit(1);
}
break;
/*
* Same as pkgadd: This disables checksum tests on
* the source files. It speeds up installation a little bit.
*/
case 'C':
(void) checksum_off();
break;
/*
* Same as pkgadd: This allows designation of a
* continuation file. It is the same format as a dryrun file
* but it is used to take up where the dryrun left off.
*/
case 'c':
pkgcontsrc = optarg;
break;
/*
* Same as pkgadd: This allows designation of a
* dryrun file. This pkgadd will create dryrun files
* in the directory provided.
*/
case 'D':
break;
/*
* Same as pkgadd: Install or copy a package from
* device. device can be a full path name to a directory
* or the identifiers for tape, floppy disk, or removable
* disk - for example, /var/tmp or /floppy/floppy_name.
* It can also be a device alias - for example,
*/
case 'd':
break;
/*
* Different from pkgadd: disable the 32 char name
* limit extension
*/
case 'e':
(void) set_ABI_namelngth();
break;
/*
* Different from pkgadd: specify file system type for
* the package device. Must be used with -m.
*/
case 'f':
break;
/*
* Same as pkgadd: install package in global zone only.
*/
case 'G':
break;
/*
* Same as pkgadd: Enable hollow package support. When
* specified, for any package that has SUNW_PKG_HOLLOW=true:
* Do not calculate and verify package size against target.
* Do not run any package procedure or class action scripts.
* Do not create any target directories.
* Do not perform any script locking.
* Do not install any components of any package.
* Do not output any status or database update messages.
*/
case 'h':
break;
/*
* Same as pkgadd: Informs scripts that this is
* an initial install by setting the environment parameter
* PKG_INIT_INSTALL=TRUE for all scripts. They may use it as
* they see fit, safe in the knowledge that the target
* filesystem is tabula rasa.
*/
case 'I':
init_install++;
break;
/*
* Different from pkgadd: use by pkgask.
*/
case 'i':
askflag++;
break;
/*
* Same as pkgadd: Instruct pkgadd not to use the
* mount points. This option assumes the mount points are
* correct on the server and it behaves consistently with
* Solaris 2.5 and earlier releases.
*/
case 'M':
map_client = 0;
break;
/*
* Different from pkgadd: specify device to use for package
* source.
*/
case 'm':
break;
/*
* Different from pkgadd: specify program name to use
* for messages.
*/
case 'N':
(void) set_prog_name(optarg);
break;
/*
* Same as pkgadd: installation occurs in
* non-interactive mode. Suppress output of the list of
* installed files. The default mode is interactive.
*/
case 'n':
nointeract++;
(void) echoSetFlag(B_FALSE);
break;
/*
* Almost same as pkgadd: the -O option allows the behavior
* of the package tools to be modified. Recognized options:
* -> debug
* ---> enable debugging output
* -> preinstallcheck
* ---> perform a "pre installation" check of the specified
* ---> package - suppress all regular output and cause a
* ---> series of one or more "name=value" pair format lines
* ---> to be output that describes the "installability" of
* ---> the specified package
* -> enable-hollow-package-support
* --> Enable hollow package support. When specified, for any
* --> package that has SUNW_PKG_HOLLOW=true:
* --> Do not calculate and verify package size against target
* --> Do not run any package procedure or class action scripts
* --> Do not create or remove any target directories
* --> Do not perform any script locking
* --> Do not install or uninstall any components of any package
* --> Do not output any status or database update messages
*/
case 'O':
/* process debug option */
if (strcmp(p, "debug") == 0) {
}
(void) echoDebugSetFlag(debugFlag);
/* debug info on arguments to pkgadd */
}
continue;
}
/* process enable-hollow-package-support opt */
if (strcmp(p,
"enable-hollow-package-support") == 0) {
continue;
}
/* process preinstallcheck option */
if (strcmp(p, "preinstallcheck") == 0) {
nointeract++; /* -n */
suppressCopyright++; /* -S */
continue;
}
/* process addzonename option */
if (strcmp(p, "addzonename") == 0) {
/*
* set zone name to add to messages;
* first look in the current environment
* and use the default package zone name
* if it is set; otherwise, use the name
* of the current zone
*/
zoneName =
(*zoneName == '\0')) {
zoneName = z_get_zonename();
}
if (*zoneName != '\0') {
zoneName);
} else {
}
}
continue;
}
/* process parent-zone-name option */
if (strncmp(p, PARENTZONENAME,
PARENTZONENAME_LEN) == 0) {
continue;
}
/* process parent-zone-type option */
if (strncmp(p, PARENTZONETYPE,
PARENTZONETYPE_LEN) == 0) {
continue;
}
if (strncmp(p, PKGSERV_MODE,
PKGSERV_MODE_LEN) == 0) {
continue;
}
/* option not recognized - issue warning */
continue;
}
break;
/*
* Different from pkgadd: This is an old non-ABI package
*/
case 'o':
break;
/*
* Different from pkgadd: specify number of parts to package.
*/
case 'p':
break;
/*
* Same as pkgadd: Define the full path name of a
* directory to use as the root_path. All files,
* including package system information files, are
* relocated to a directory tree starting in the specified
* root_path. The root_path may be specified when
* installing to a client from a server (for example,
*/
case 'R':
if (!set_inst_root(optarg)) {
exit(1);
}
break;
/*
* Same as pkgadd: Identify a file or directory which
* contains output from a previous pkgask(1M)
* session. This file supplies the interaction responses
* that would be requested by the package in interactive
* mode. response must be a full pathname.
*/
case 'r':
break;
/*
* Same as pkgadd: suppress copyright notice being
* output during installation.
*/
case 'S':
break;
/*
* Same as pkgadd: disable save spool area creation;
* do not spool any partial package contents, that is,
* suppress the creation and population of the package save
*/
case 't':
break;
/*
* Same as pkgadd: Specify an alternative fs_file to map
* the client's file systems. For example, used in
* non-existent or unreliable. Informs the pkginstall
* portion to mount up a client filesystem based upon the
* supplied vfstab-like file of stable format.
*/
case 'V':
map_client = 1;
break;
/*
* Same as pkgadd: Trace all of the scripts that get
* directory. This option is used for debugging the
* procedural and non-procedural scripts
*/
case 'v':
pkgverbose++;
break;
/*
* Different from pkgadd: process this package using
* old non-ABI symlinks
*/
case 'y':
break;
/*
* Same as pkgadd: perform fresh install from
* package save spool area. When set, the package contents
* are installed from the package spool save area instead
* of from the package root area, so that the original
* source packages are not required to install the
* package. If the -h option is also specified and the
* package is hollow, then this option is ignored. When -z
* is specified:
* - Editable files are installed from the package instance
* save area.
* - Volatile files are installed from the package instance
* save area.
* - Executable and data files are installed from the final
* installed location as specified in the pkgmap file.
* - Installation scripts are run from the package spool
* save area.
*/
case 'z':
break;
/*
* unrecognized option
*/
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);
}
}
/*
* ********************************************************************
* validate command line options
* ********************************************************************
*/
/* set "debug echo" flag according to setting of "-O debug" option */
(void) echoDebugSetFlag(debugFlag);
(void) log_set_verbose(debugFlag);
/* output entry debugging information */
if (z_running_in_global_zone()) {
} else {
z_get_zonename());
}
if (in_continue_mode() && !in_dryrun_mode()) {
usage();
/*NOTREACHED*/
}
/* pkgask requires a response file */
usage();
/*NOTREACHED*/
}
/* if device specified, set appropriate device in pkgdev */
if (device) {
} else {
}
}
/* if file system type specified, must have a device to mount */
usage();
/*NOTREACHED*/
}
/* BEGIN DATA GATHERING PHASE */
/*
* Get the mount table info and store internally.
*/
if (in_continue_mode()) {
int error;
if (error == -1) {
quit(99);
/*NOTREACHED*/
}
if (!in_dryrun_mode()) {
live_continue = 1;
}
}
/* Read the mount table if not done in continuation mode */
if (!cont_file_read) {
quit(99);
/*NOTREACHED*/
}
}
/*
* This function defines the standard /var/... directories used later
* to construct the paths to the various databases.
*/
/*
* 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;
if (use_srvr_map_n(fsys_value))
if (use_srvr_map_n(fsys_value))
}
/*
* Initialize pkginfo PKGSAV entry, just in case we dryrun to
* somewhere else.
*/
/* pull off directory and package name from end of command line */
case 0: /* missing directory and package instance */
usage();
/*NOTREACHED*/
case 1: /* missing package instance */
usage();
/*NOTREACHED*/
case 2: /* just right! */
break;
default: /* too many args! */
usage();
break;
}
/*
* Initialize installation admin parameters by reading
* the adminfile.
*/
if (!askflag && !live_continue) {
}
/*
* about to perform first operation that could be modified by the
* preinstall check option - if preinstall check is selected (that is,
* only gathering dependencies), then output a debug message to
* indicate that the check is beginning. Also turn echo() output
* off and set various other flags.
*/
if (preinstallCheck == B_TRUE) {
(void) echoSetFlag(B_FALSE);
/* inform quit that the install has started */
}
/*
* validate the "rscriptalt" admin file setting
* The rscriptalt admin file parameter may be set to either
* RSCRIPTALT_ROOT or RSCRIPTALT_NOACCESS:
* --> If rscriptalt is not set, or is set to RSCRIPTALT_NOACCESS,
* --> or is set to any value OTHER than RSCRIPTALT_ROOT, then
* --> assume that the parameter is set to RSCRIPTALT_NOACCESS
* If rscriptalt is set to RSCRIPTALT_ROOT, then run request scripts
* as the "root" user if user "install" is not defined.
* Otherwise, assume rscriptalt is set to RSCRIPTALT_NOACCESS, and run
* request scripts as the "alternative" user if user "install" is not
* defined, as appropriate for the current setting of the NONABI_SCRIPTS
* environment variable.
*/
if (ADMSET(RSCRIPTALT)) {
p = adm.RSCRIPTALT;
if (strcasecmp(p, RSCRIPTALT_ROOT) == 0) {
/* rscriptalt=root */
} else if (strcasecmp(p, RSCRIPTALT_NOACCESS) == 0) {
/* rscriptalt=noaccess */
} else {
/* rscriptalt=??? */
}
} else {
/* rscriptalt not set - assume rscriptalt=noaccess */
}
/*
* hook SIGINT and SIGHUP interrupts into quit.c's trap handler
*/
/* connect quit.c:trap() to SIGINT */
/* connect quit.c:trap() to SIGHUP */
/* release hold on signals */
/*
* create required /var... directories if they do not exist;
* this function will call quit(99) if any required path cannot
* be created.
*/
ckdirs();
tzset();
/*
* create path to temporary directory "installXXXXXX" - if TMPDIR
* environment variable is set, create the directory in $TMPDIR;
* otherwise, create the directory in P_tmpdir.
*/
quit(99);
/*NOTREACHED*/
}
/*
* if the package device is a file containing a package stream,
* unpack the stream into a temporary directory
*/
boolean_t b;
/*
* validate the package source device - return pkgdev info that
* describes the package source device.
*/
quit(99);
/* NOTREACHED */
}
/* generate the list of packages to verify */
1);
if (b == B_FALSE) {
quit(99);
/*NOTREACHED*/
}
/* make sure temporary directory is removed on exit */
/* unpack the package instance from the data stream */
if (b == B_FALSE) {
quit(99);
/*NOTREACHED*/
}
/* close the datastream - no longer needed */
(void) ds_close(1);
}
>= PATH_MAX) {
quit(99);
/*NOTREACHED*/
}
/*
* If the environment has a CLIENT_BASEDIR, that takes precedence
* over anything we will construct. We need to save it here because
* in three lines, the current environment goes away.
*/
(void) set_env_cbdir(); /* copy over environ */
/*
* current environment has been read; clear environment out
* so putparam() can be used to populate the new environment
* to be passed to any executables/scripts.
*/
/* write parent condition information to environment */
if (init_install) {
}
if (is_an_inst_root()) {
}
}
if (non_abi_scripts) {
}
if (nonABI_symlinks()) {
}
if (get_ABI_namelngth()) {
}
/* establish path and oambase */
if (cmdbin[0] == '\0') {
}
/* Read the environment (from pkginfo or '-e') ... */
/* Disable the 32 char name limit extension */
(void) set_ABI_namelngth();
}
/*
* This tests the pkginfo and pkgmap files for validity and
* puts all delivered pkginfo variables (except for PATH) into
* our environment. This is where a delivered pkginfo BASEDIR
* would come from. See set_basedirs() below.
*/
quit(1);
/*NOTREACHED*/
}
/*
* If this script was invoked by 'pkgask', just
* execute request script and quit (do_pkgask()).
*/
if (askflag) {
}
/* validate package contents file */
if (vcfile() == 0) {
quit(99);
}
/* if not in dryrun mode aquire packaging lock */
if (!in_dryrun_mode()) {
/* acquire the package lock - at install initialization */
quit(99);
/*NOTREACHED*/
}
}
/*
* Now do all the various setups based on ABI compliance
*/
/* Read the environment (from pkginfo or '-o') ... */
/* Read the environment (from pkginfo or '-y') ... */
/* bug id 4244631, not ABI compliant */
non_abi_scripts = 1;
}
/* Set symlinks to be processed the old way */
}
/*
* At this point, script_in, non_abi_scripts & the environment are
* all set correctly for the ABI status of the package.
*/
}
/*
* See if were are installing a package that only wants to update
* the database or only install files associated with CAS's. We
* only check the PKG_HOLLOW_VARIABLE variable if told to do so by
* the caller.
*/
if (is_depend_pkginfo_DB()) {
if (disableAttributes) {
}
/*
* this is a hollow package and hollow package support
* is enabled -- override admin settings to suppress
* checks that do not make sense since no scripts will
* be executed and no files will be installed.
*/
} else {
}
}
/*
* if performing a fresh install to a non-global zone, and doing
* more than just updating the package database (that is, the
* package to install is NOT "hollow"), then set the global flag
* that directs installation is from partially spooled packages
* (that is, packages installed in the global zone).
*/
if (saveSpoolInstall && (!is_depend_pkginfo_DB())) {
} else {
saveSpoolInstall = 0;
}
/*
* verify that we are not trying to install an
* INTONLY package with no interaction
*/
if (askflag || nointeract) {
quit(1);
/*NOTREACHED*/
}
}
copyright();
}
/*
* inspect the system to determine if any instances of the
* package being installed already exist on the system
*/
quit(99);
/*NOTREACHED*/
}
for (;;) {
break;
}
quit(99);
/*NOTREACHED*/
}
quit(99);
/*NOTREACHED*/
}
}
}
/*
* Determine the correct package instance based on how many packages are
* already installed. If there are none (npkgs == 0), getinst() just
* returns the package abbreviation. Otherwise, getinst() interacts with
* the user (or reads the admin file) to determine if an instance which
* is already installed should be overwritten, or possibly install a new
* instance of this package
*/
/* set "update flag" if updating an existing instance of this package */
if (update) {
setUpdate();
}
/*
* Some pkgs (SUNWcsr) already spooled to the zone, check the
* value of UPDATE in their postinstall script. After a pkg
* has been patched UPDATE exists statically in the pkginfo
* file and this value must be reset when installing a zone.
*/
if (saveSpoolInstall != 0 && !isUpdate()) {
}
/* inform quit() if updating existing or installing new instance */
if (respfile) {
}
pkginst) < 0) {
quit(99);
/*NOTREACHED*/
}
"%s/!I-Lock!", pkgloc);
"%s/!R-Lock!", pkgloc);
/*
* Be sure request script has access to PKG_INSTALL_ROOT if there is
* one
*/
if (!map_client) {
}
/*
* This maps the client filesystems into the server's space.
*/
if (map_client && !mount_client()) {
}
/*
* If this is an UPDATE then either this is exactly the same version
* and architecture of an installed package or a different package is
* intended to entirely replace an installed package of the same name
* with a different VERSION or ARCH string.
* Don't merge any databases if only gathering dependencies.
*/
/*
* If this version and architecture is already installed,
* merge the installed and installing parameters and inform
* all procedure scripts by defining UPDATE in the
* environment.
*/
if (is_samepkg()) {
/*
* If it's the same ARCH and VERSION, then a merge
* and copy operation is necessary.
*/
quit(n);
/*NOTREACHED*/
}
if (n = cp_pkgdirs()) {
quit(n);
/*NOTREACHED*/
}
} else {
/*
* is an "instance=overwrite" situation. The
* installed base needs to be confirmed and the
* package directories renamed.
*/
if (n = ck_instbase()) {
quit(n);
/*NOTREACHED*/
}
if (n = mv_pkgdirs()) {
quit(n);
/*NOTREACHED*/
}
}
}
if (in_dryrun_mode()) {
}
if (preinstallCheck == B_FALSE) {
/*
* Determine if the package has been partially installed on or
* removed from this system.
*/
/*
* make sure current runlevel is appropriate
*/
} else {
int r;
/*
* Just gathering dependencies - determine if the package has
* been partially installed on or removed from this system and
* output information to stdout
*/
r = ckpartial();
/*
* make sure current runlevel is appropriate
*/
r = ckrunlevel();
}
/* get first volume which contains info files */
unpack();
if (!suppressCopyright) {
copyright();
}
}
/* update the lock - at the request script */
lockupd("request");
/*
* If no response file has been provided, initialize response file by
* executing any request script provided by this package. Initialize
* the response file if not gathering dependencies only.
*/
if (in_dryrun_mode()) {
}
ckreturn(n, ERR_REQUEST);
}
/*
* Look for all parameters in response file which begin with a
* capital letter, and place them in the environment.
*/
if (n = merg_respfile()) {
quit(n);
/*NOTREACHED*/
}
}
/*
* Run a checkinstall script if one is provided by the package.
* Don't execute checkinstall script if we are only updating the DB.
* Don't execute checkinstall script if only gathering dependencies.
*/
/* update the lock - at the checkinstall script */
lockupd("checkinstall");
/* Execute checkinstall script if one is provided. */
instdir);
/* no script present */
} else if (is_depend_pkginfo_DB()) {
/* updating db only: skip checkinstall script */
} else if (preinstallCheck == B_TRUE) {
/* only gathering dependencies: skip checkinstall script */
} else {
/* script present and ok to run: run the script */
} else {
zoneName);
}
if (in_dryrun_mode()) {
set_dr_info(CHECKEXITCODE, n);
}
if (n == 3) {
} else if (n == 7) {
/* access returned error */
} else {
ckreturn(n, ERR_CHKINSTALL);
}
}
/*
* Now that the internal data structures are initialized, we can
* initialize the dryrun files (which may be the same files).
*/
if (pkgdrtarg) {
}
/*
* Look for all parameters in response file which begin with a
* capital letter, and place them in the environment.
*/
if (is_a_respfile()) {
if (n = merg_respfile()) {
quit(n);
/*NOTREACHED*/
}
}
/* update the lock - doing analysis */
lockupd("analysis");
/*
* Determine package base directory and client base directory
* if appropriate. Then encapsulate them for future retrieval.
*/
nointeract)) != 0) {
/*NOTREACHED*/
}
/*
* Create the base directory if specified.
* Don't create if we are only updating the DB.
* Don't create if only gathering dependencies.
*/
if (!is_depend_pkginfo_DB() &&
!preinstallCheck && is_a_basedir()) {
}
/*
* Store PKG_INSTALL_ROOT, BASEDIR & CLIENT_BASEDIR in our
* environment for later use by procedure scripts.
*/
/*
* the following two checks are done in the corresponding
* ck() routine, but are repeated here to avoid re-processing
* the database if we are administered to not include these
* processes
*/
}
nocnflct++; /* Don't install conflicting files. */
}
/*
* Get the filesystem space information for the filesystem on which
* the "contents" file resides.
*/
quit(99);
/*NOTREACHED*/
}
}
/*
* Get the number of blocks used by the pkgmap, ocfile()
* needs this to properly determine its space requirements.
*/
quit(99);
/*NOTREACHED*/
}
/*
* Merge information in memory with the "contents" file; this creates
* a temporary version of the "contents" file. Note that in dryrun
* mode, we still need to record the contents file data somewhere,
* but we do it in the dryrun directory.
*/
if (in_dryrun_mode()) {
quit(n);
/*NOTREACHED*/
}
} else {
quit(n);
/*NOTREACHED*/
}
}
quit(99);
/*NOTREACHED*/
}
/*
* if cpio is being used, tell pkgdbmerg since attributes will
* have to be check and repaired on all file and directories
*/
is_WOS_arch();
break;
}
}
/* Establish the class list and the class attributes. */
quit(99);
/*NOTREACHED*/
}
/*
* This modifies the path list entries in memory to reflect
* how they should look after the merg is complete
*/
if ((n = files_installed()) > 0) {
if (n > 1) {
echo(MSG_INST_MANY, n);
} else {
echo(MSG_INST_ONE, n);
}
}
/*
* Check ulimit requirement (provided in pkginfo). The purpose of
* this limit is to terminate pathological file growth resulting from
* file edits in scripts. It does not apply to files in the pkgmap
* and it does not apply to any database files manipulated by the
* installation service.
*/
quit(99);
/*NOTREACHED*/
}
}
/*
* If only gathering dependencies, check and output status of all
* remaining dependencies and exit.
*/
if (preinstallCheck == B_TRUE) {
/* update the lock file - final checking */
lockupd("preinstallcheck");
/* verify package information files are not corrupt */
/* verify package dependencies */
/* Check space requirements */
/*
* Determine if any objects provided by this package conflict
* with the files of previously installed packages.
*/
/*
* Determine if any objects provided by this package will be
* installed with setuid or setgid enabled.
*/
/*
* Determine if any packaging scripts provided with this package
* will execute as a priviledged user.
*/
/* Verify neccessary package installation directories exist */
/*
* ****** preinstall check done - exit ******
*/
quit(0);
/*NOTREACHED*/
}
/*
* Not gathering dependencies only, proceed to check dependencies
* and continue with the package installation operation.
*/
/*
* verify package information files are not corrupt
*/
/*
* verify package dependencies
*/
/*
* Check space requirements.
*/
/*
* Determine if any objects provided by this package conflict with
* the files of previously installed packages.
*/
/*
* Determine if any objects provided by this package will be
* installed with setuid or setgid enabled.
*/
/*
* Determine if any packaging scripts provided with this package will
* execute as a priviledged user.
*/
/*
* Verify neccessary package installation directories exist.
*/
/*
* If we have assumed that we were installing setuid or conflicting
* files, and the user chose to do otherwise, we need to read in the
* package map again and re-merg with the "contents" file
*/
if (rprcflag) {
}
/* BEGIN INSTALLATION PHASE */
if (in_dryrun_mode()) {
} else {
}
/* inform quit that the install has started */
/*
* This replaces the contents file with recently created temp version
* which contains information about the objects being installed.
* Under old lock protocol it closes both files and releases the
* locks. Beginning in Solaris 2.7, this lock method should be
* reviewed.
*/
if (n == RESULT_WRN) {
warnflag++;
} else if (n == RESULT_ERR) {
quit(99);
/*NOTREACHED*/
}
/*
* Create install-specific lockfile to indicate start of
* installation. This is really just an information file. If the
* process dies, the initial lockfile (from lockinst(), is
* relinquished by the kernel, but this one remains in support of the
* post-mortem.
*/
}
quit(99);
/*NOTREACHED*/
}
/*
* We do not want the time in locale in the pkginfo.
* save the LC_TIME and set it to C. Reset it with saved one
* after cftime().
*/
/* LINTED warning: do not use cftime(); ... */
/*
* Store information about package being installed;
* modify installation parameters as neccessary and
* copy contents of 'install' directory into $pkgloc
*/
/* If this was just a dryrun, then quit() will write out that file. */
if (in_dryrun_mode()) {
quit(0);
/*NOTREACHED*/
}
/*
* Execute preinstall script, if one was provided with the
* package. We check the package to avoid running an old
* preinstall script if one was provided with a prior instance.
* Don't execute preinstall script if we are only updating the DB.
*/
/* update the lock - at the preinstall altscript */
lockupd("preinstall");
/* preinstall script in the media (package source) */
instdir);
/* preinstall script in the pkgbin instead of media */
/* no script present */
/* no script present */
} else if (is_depend_pkginfo_DB()) {
/* updating db only: skip preinstall script */
} else {
/* script present and ok to run: run the script */
} else {
zoneName);
}
if (pkgverbose) {
} else {
}
clr_ulimit();
}
/*
* Check delivered package for a postinstall script while
* we're still on volume 1.
*/
"%s/install/postinstall", instdir);
"%s/postinstall", pkgbin);
} else {
script[0] = '\0';
}
/* update the lock - at the install phase */
lockupd("install");
/*
* install package one part (volume) at a time
*/
part = 1;
unpack();
}
break;
}
}
/*
* Now that all install class action scripts have been used, we
* delete them from the package directory.
*/
if (globalZoneOnly) {
boolean_t b;
if (b == B_FALSE) {
}
}
/*
* Execute postinstall script, if any
* Don't execute postinstall script if we are only updating the DB.
*/
/* update the lock - at the postinstall script */
lockupd("postinstall");
} else if (is_depend_pkginfo_DB()) {
/*
* fresh installing into non-global zone, no object was
* the postinstall script.
*/
} else {
/* script present and ok to run: run the script */
} else {
zoneName);
}
if (pkgverbose) {
} else {
}
clr_ulimit();
}
}
/* release the generic package lock */
(void) unlockinst();
quit(0);
/* LINTED: no return */
}
/*
* This function merges the environment data in the response file with the
* current environment.
*/
static int
{
int retcode = 0;
char *locbasedir;
return (99);
}
param[0] = '\0';
param[0] = '\0';
continue;
}
param[0] = '\0';
continue;
}
/*
* If this is an update, and the response file
* specifies the BASEDIR, make sure it matches the
* existing installation base. If it doesn't, we have
* to quit.
*/
char *dotptr;
/* Get srcinst down to a name. */
*dotptr = '\000';
locbasedir, value);
retcode = 99;
}
}
param[0] = '\0';
}
return (retcode);
}
/*
* This scans the installed pkginfo file for the current BASEDIR. If this
* BASEDIR is different from the current BASEDIR, there will definitely be
* problems.
*/
static int
ck_instbase(void)
{
int retcode = 0;
/* Open the old pkginfo file. */
return (99);
}
param[0] = '\000';
char *dotptr;
/*
* Get srcinst down to a name.
*/
*dotptr = '\000';
retcode = 4;
break;
}
/*
* If it's going to ask later, let it know
* that it *must* agree with the BASEDIR we
* just picked up.
*/
break;
}
param[0] = '\0';
}
return (retcode);
}
/*
* Since this is an overwrite of a different version of the package, none of
* the old files should remain, so we rename them.
*/
static int
mv_pkgdirs(void)
{
/*
* If we're not in dryrun mode and we can find an old set of package
* files over which the new ones will be written, do the rename.
*/
"%s/.save.%s", get_PKGLOC(),
pkginst);
(void) rrmdir(pkgloc_sav);
}
return (99);
}
}
return (0);
}
/*
* Name: merg_pkginfos
* Description: This function scans the installed pkginfo and merges that
* environment with the installing environment according to
* the following rules:
*
* 1. CLASSES is a union of the installed and installing CLASSES
* lists.
* 2. The installed BASEDIR takes precedence. If it doesn't agree
* with an administratively imposed BASEDIR, an ERROR is issued.
* 3. All other installing parameters are preserved.
* 4. All installed parameters are added if they do not overwrite
* an existing installing parameter.
*
* The current environment contains the pkginfo settings for the
* new package to be installed or to be updated.
*
* Arguments: pclass - returned list of current classes involved in install
* mpclass - pointer to returned list of current install classes
* Returns: int
* == 0 - all OK
* != 0 - an error code if a fatal error occurred
*/
static int
{
char *newValue;
char *oldValue;
char *pkgName;
char *pkgVersion;
int retcode = 0;
/* obtain the name of the package (for error messages) */
}
/* obtain the version of the package (for error messages) */
if (pkgVersion == NULL) {
}
/* open installed package pkginfo file */
return (99);
}
/* entry debugging info */
/*
* cycle through the currently installed package's pkginfo parameters
* and let the currently installed package's settings survive if the
* update to the package does not provide an overriding value
*/
param[0] = '\0') {
/* debug info - attribute currently set to value */
/*
* if zone package attribute is present in the currently
* installed package, then remember the value for the
* specific zone package attribute, and set the flag that
* indicates a zone package attribute is being processed.
*/
/* SUNW_PKG_THISZONE currently set */
sizeof (SUNW_PKG_THISZONE));
/* SUNW_PKG_ALLZONES currently set */
sizeof (SUNW_PKG_ALLZONES));
/* SUNW_PKG_THISZONE currently set */
sizeof (SUNW_PKG_HOLLOW));
}
/* handle CLASSES currently being set */
/* create a list of the current classes */
/* set pointer to list of current classes */
continue;
}
/* handle BASEDIR currently being set */
char *dotptr;
/* Get srcinst down to a* name */
*dotptr = '\000';
}
/* administration */
retcode = 4;
break;
}
/*
* If it's going to ask
* later, let it know that it
* *must* agree with the
* BASEDIR we just picked up.
*/
}
continue;
}
/*
* determine if there is a new value for this attribute.
*/
/*
* If there is no new value, and a zone attribute
* is being changed, it is the same as setting the zone package
* attribute to 'false' - make sure current setting is 'false'.
*/
(setZoneAttribute == B_TRUE) &&
/* unset existing non-"false" zone pkg attr */
retcode = 1;
break;
}
/* retain old value if no new value specified */
/* no new value - retain the old value */
continue;
}
/* note if the old and new values are the same */
/* set existing package parameter to same value */
continue;
}
/*
* Check if old and new values differ.
* Error if zone parameter
*/
if (setZoneAttribute == B_TRUE) {
/* illegal change to zone attribute */
/* set return code to "fatal error" */
retcode = 1;
break;
}
/* note valid change to existing package parameter */
}
/* close handle on currently installed package's pkginfo file */
/* return error if not successful up to this point */
if (retcode != 0) {
return (retcode);
}
/*
* verify that no zone attribute has been
* set to an invalid value
*/
/* SUNW_PKG_ALLZONES */
/*
* complain if setting SUNW_PKG_ALLZONES to other than "false"
*/
/* change ALLZONES from "true" to "false" (unset) */
return (1);
}
/* SUNW_PKG_THISZONE */
/*
* complain if setting SUNW_PKG_THISZONE to other than "false"
*/
/* change THISZONE from "true" to "false" (unset) */
return (1);
}
/* SUNW_PKG_HOLLOW */
/* complain if setting SUNW_PKG_HOLLOW to other than "false" */
/* change HOLLOW from "true" to 'false" (unset) */
return (1);
}
return (0);
}
static void
set_dryrun_dir_loc(void)
{
/* Set pkg location to the dryrun directory */
"%s/!I-Lock!", pkgloc);
"%s/!R-Lock!", pkgloc);
}
/*
* If we are updating a pkg, then we need to copy the "old" pkgloc so that
* any scripts that got removed in the new version aren't left around. So we
* copy it here to .save.pkgloc, then in quit() we can restore our state, or
* remove it.
*/
static int
cp_pkgdirs(void)
{
if (in_dryrun_mode()) {
}
/*
* If we're not in dryrun mode and we can find an old set of package
* files over which the new ones will be written, do the copy.
*/
int status;
int r;
get_PKGLOC(), pkginst);
/*
* Even though it takes a while, we use a recursive copy here
* because if the current pkgadd fails for any reason, we
* don't want to lose this data.
*/
(char *)NULL);
return (99);
}
}
return (0);
}
/*
* This implements the pkgask function. It just executes the request script
* and stores the results in a response file.
*/
static void
{
unpack();
if (!suppressCopyright) {
copyright();
}
}
quit(1);
/*NOTREACHED*/
}
if (is_a_respfile()) {
} else {
failflag++;
}
echo("\nResponse file <%s> was not created.",
get_respfile());
} else {
echo("\nResponse file <%s> was created.",
get_respfile());
}
quit(0);
/*NOTREACHED*/
}
/*
* This function runs a check utility and acts appropriately based upon the
* return code. It deals appropriately with the dryrun file if it is present.
*/
static void
{
int n;
n = func();
if (in_dryrun_mode())
set_dr_info(type, !n);
if (n) {
quit(n);
/*NOTREACHED*/
}
}
/*
* This function deletes all install class action scripts from the package
* directory on the root filesystem.
*/
static void
{
return;
continue;
}
}
}
void
{
switch (retcode) {
case 2:
case 12:
case 22:
warnflag++;
if (msg) {
}
/*FALLTHRU*/
case 10:
case 20:
dreboot++;
}
if (retcode >= 20) {
ireboot++;
}
/*FALLTHRU*/
case 0:
break; /* okay */
case -1:
retcode = 99;
/*FALLTHRU*/
case 99:
case 1:
case 11:
case 21:
case 4:
case 14:
case 24:
case 5:
case 15:
case 25:
if (msg) {
}
/*FALLTHRU*/
case 3:
case 13:
case 23:
/*NOTREACHED*/
default:
if (msg) {
}
quit(1);
/*NOTREACHED*/
}
}
static void
copyright(void)
{
/* Compose full path for copyright file */
} else {
}
}
static int
rdonly(char *p)
{
int i;
for (i = 0; ro_params[i]; i++) {
return (1);
}
return (0);
}
static void
unpack(void)
{
/*
* read in next part from stream, even if we decide
* later that we don't need it
*/
if (dparts < 1) {
quit(99);
/*NOTREACHED*/
}
quit(99);
/*NOTREACHED*/
}
quit(99);
/*NOTREACHED*/
}
quit(99);
/*NOTREACHED*/
}
if (!ds_fd_open()) {
if (dparts < 1) {
quit(99);
/*NOTREACHED*/
}
}
dparts--;
quit(99);
/*NOTREACHED*/
}
if (chdir(get_PKGADM())) {
quit(99);
/*NOTREACHED*/
}
ds_close(1);
}
static void
usage(void)
{
exit(1);
/*NOTREACHED*/
}