/*
* 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 <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <pkgstrct.h>
#include <pkginfo.h>
#include <pkglocs.h>
#include <locale.h>
#include <libintl.h>
#include <assert.h>
#include <cfext.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <install.h>
#include <libinst.h>
#include <libadm.h>
#include <messages.h>
extern int eptnum;
extern char *pkgdir;
extern char **environ;
/* quit.c */
extern sighdlrFunc_t *quitGetTrapHandler(void);
extern void quitSetZoneName(char *a_zoneName);
/* check.c */
extern void rcksetPreremoveCheck(boolean_t);
extern void rcksetZoneName(char *);
extern int rckpriv(void);
extern int rckdepend(void);
extern int rckrunlevel(void);
/* delmap.c */
#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 */
int started;
int dbchg;
char *msgtext;
/*
* The following variable is the name of the device to which stdin
* correct for all ABI compliant packages. For non-ABI-compliant
* to allow user interaction during these scripts. -- JST
*/
static void usage(void);
/*
* Set by -O debug: debug output is enabled?
*/
/*
* Set by -O preremovecheck: do remove dependency checking only
*/
/* Set by -O parent-zone-name= */
/* Set by -O parent-zone-type= */
int
{
char *abi_comp_ptr;
char *abi_sym_ptr;
char *p;
char *pt;
char *value;
int c;
int err;
int fd;
int i;
int n;
/* 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 */
}
/* Read PKG_INSTALL_ROOT from the environment, if it's there. */
exit(1);
}
/* parse command line options */
switch (c) {
/*
* Same as pkgrm: Allow admin to remove package objects from
* a shared area from a reference client.
*/
case 'A':
pkgrmremote++;
break;
/*
* Same as pkgrm: Use the installation
* administration file, admin, in place of the
* default admin file. pkgrm first looks in the
* current working directory for the administration
* file. If the specified administration file is not
* in the current working directory, pkgrm looks in
* administration file.
*/
case 'a':
break;
/*
* Same as pkgrm: location where package executables
*/
case 'b':
if (!path_valid(optarg)) {
exit(1);
}
exit(1);
}
break;
/*
* Same as pkgrm: suppresses the removal of any
* files and any class action scripts, and suppresses
* the running of any class action scripts. The
* package files remain but the package looks like it
* is not installed. This is mainly for use by the
* upgrade process.
*/
case 'F':
nodelete++;
break;
/*
* Same as pkgrm: Instruct pkgrm not to use the
* client's 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 pkgrm: specify program name to use
* for messages.
*/
case 'N':
(void) set_prog_name(optarg);
break;
/*
* Same as pkgrm: package removal occurs in
* non-interactive mode. Suppress output of the list of
* removed files. The default mode is interactive.
*/
case 'n':
nointeract++;
(void) echoSetFlag(B_FALSE);
break;
/*
* Almost same as pkgrm: the -O option allows the behavior
* of the package tools to be modified. Recognized options:
* -> debug
* ---> enable debugging output
* -> preremovecheck
* ---> perform a "pre removal" 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 "removability" 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 preremovecheck option */
if (strcmp(p, "preremovecheck") == 0) {
nointeract++; /* -n */
nodelete++; /* -F */
continue;
}
/* process addzonename option */
if (strcmp(p, "addzonename") == 0) {
zoneName = z_get_zonename();
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 pkgrm: This is an old non-ABI package
*/
case 'o':
break;
/*
* Same as pkgrm: defines 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.
*/
case 'R':
if (!set_inst_root(optarg)) {
exit(1);
}
break;
/*
* Same as pkgrm: allow admin to establish the client
* filesystem using a vfstab-like file of stable format.
*/
case 'V':
map_client = 1;
break;
/*
* Same as pkgrm: trace all of the scripts that
* get executed by pkgrm, located in the
* debugging the procedural and non-procedural
* scripts.
*/
case 'v':
pkgverbose++;
break;
/*
* Different from pkgrm: process this package using
* old non-ABI symlinks
*/
case 'y':
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);
}
}
/*
* ********************************************************************
* validate command line options
* ********************************************************************
*/
(void) echoDebugSetFlag(debugFlag);
(void) log_set_verbose(debugFlag);
if (z_running_in_global_zone()) {
} else {
z_get_zonename());
}
/* establish cmdbin path */
if (cmdbin[0] == '\0') {
}
/* Read the mount table */
quit(99);
}
/*
* This function defines the standard /var/... directories used later
* to construct the paths to the various databases.
*/
/*
* If this is being removed from 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))
} else {
pkgrmremote = 0; /* Makes no sense on local host. */
}
/*
* 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 */
usage();
}
/* validate package software database (contents) file */
if (vcfile() == 0) {
quit(99);
}
/*
* Acquire the package lock - currently at "remove initialization"
*/
quit(99);
}
/* establish temporary directory to use */
}
/*
* Initialize installation admin parameters by reading
* the adminfile.
*/
/*
* about to perform first operation that could be modified by the
* preremove check option - if preremove 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 (preremoveCheck == B_TRUE) {
(void) echoSetFlag(B_FALSE);
}
pkginst);
quit(99);
}
/*
* if a lock file is present, then a previous attempt to remove this
* package may have been unsuccessful.
*/
}
/*
* Process all parameters from the pkginfo file
* and place them in the execution environment
*/
/* Add DB retreival of the pkginfo parameters here */
quit(99);
}
/* Mount up the client if necessary. */
if (map_client && !mount_client()) {
}
/* Get mount point of client */
/*
* 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.
*/
if (nonABI_symlinks()) {
}
/*
* read the pkginfo file and fix any PKGSAV path - the correct
* install_root will be prepended to the existing path.
*/
param[0] = '\0';
int validx = 0;
char *newvalue;
/* strip out any setting of PATH */
param[0] = '\0';
continue;
}
/* if not PKGSAV then write out unchanged */
param[0] = '\0';
continue;
}
/*
* PKGSAV parameter found - interpret the directory:
* If in host:path format or marked with the leading "//",
* then there is no client-relative translation - take it
* literally later rather than use fixpath().
*/
/* no modification needed */
validx = 0;
validx = 1;
} else if (is_an_inst_root()) {
/* This PKGSAV needs to be made client-relative. */
}
param[0] = '\0';
}
/* write parent condition information to environment */
/*
* Now do all the various setups based on ABI compliance
*/
/* Read the environment provided by the pkginfo file */
/* if not ABI compliant set global flag */
}
/*
* If pkginfo says it's not compliant then set non_abi_scripts.
*/
}
/*
* Since this is a removal, we can tell whether it's absolute or
* not from the resident pkginfo file read above.
*/
pkginst, nointeract)) != 0) {
}
/*
* See if were are removing a package that only wants to update
* the database or only remove 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()) {
/*
* 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 removed.
*/
} else {
}
}
/* If client mount point, add it to pkgremove environment */
if (client_mntdir != NULL) {
}
/* Establish the class list and the class attributes. */
} else {
quit(99);
}
/* establish path and tmpdir */
if (cmdbin[0] == '\0') {
}
/*
* 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.
*/
warnflag++;
}
}
/*
* If only gathering dependencies, check and output status of all
* remaining dependencies and exit.
*/
if (preremoveCheck == B_TRUE) {
/*
* make sure current runlevel is appropriate
*/
/*
* determine if any packaging scripts provided with
* this package will execute as a priviledged user
*/
/*
* verify package dependencies
*/
/*
* ****** preremove check done - exit ******
*/
quit(0);
/*NOTREACHED*/
}
/*
* Not gathering dependencies only, proceed to check dependencies
* and continue with the package removal operation.
*/
/*
* make sure current runlevel is appropriate
*/
n = rckrunlevel();
if (n != 0) {
quit(n);
/* NOTREACHED */
}
/*
* determine if any packaging scripts provided with
* this package will execute as a priviledged user
*/
n = rckpriv();
if (n != 0) {
quit(n);
/* NOTREACHED */
}
/*
* verify package dependencies
*/
n = rckdepend();
if (n != 0) {
quit(n);
/* NOTREACHED */
}
/*
* *********************************************************************
* the actual removal of the package begins here
* *********************************************************************
*/
/*
* create lockfile to indicate start of removal
*/
started++;
quit(99);
} else {
}
} else {
zoneName);
}
quit(99);
}
/*
* Run a preremove script if one is provided by the package.
* Don't execute preremove script if only updating the DB.
* Don't execute preremove script if files are not being deleted.
*/
/* update the lock - at the preremove script */
lockupd("preremove");
/* execute preremove script if one is provided */
/* no script present */
} else if (nodelete) {
/* not deleting files: skip preremove script */
} else if (is_depend_pkginfo_DB()) {
/* updating db only: skip preremove script */
} else {
/* script present and ok to run: run the script */
} else {
zoneName);
}
if (pkgverbose) {
} else {
}
clr_ulimit();
}
/* update the lock - doing removal */
lockupd("remove");
/*
* Ensure that the contents file is updated even if the db has
* been upgraded, in the case that there are relevant entries
* in a special_contents file. The return value is ignored
* since we do not want special_contents operation to prevent
* pkgremove from succeeding. We do report errors to stderr.
*/
/*
* Remove all components belonging to this package.
* Don't remove components if only updating the DB.
* Don't remove components if files are not being deleted.
*/
if (nodelete) {
} else if (is_depend_pkginfo_DB()) {
} else {
/*
* remove package one class at a time
*/
/* reverse order of classes */
for (i = cl_getn() - 1; i >= 0; i--) {
}
}
/*
* Execute postremove script, if any
* Don't execute postremove script if only updating the DB.
* Don't execute postremove script if files are not being deleted.
*/
/* update the lock - at the postremove script */
lockupd("postremove");
/* execute postremove script if one is provided */
/* no script present */
} else if (nodelete) {
/* not deleting files: skip postremove script */
} else if (is_depend_pkginfo_DB()) {
/* updating db only: skip postremove script */
} else {
/* script present and ok to run: run the script */
} else {
zoneName);
}
if (pkgverbose) {
} else {
}
clr_ulimit();
}
} else {
}
quit(99);
}
(void) chdir("/");
warnflag++;
}
if ((z_running_in_global_zone() == B_TRUE) &&
boolean_t b;
if (b == B_FALSE) {
}
}
/* release the generic package lock */
(void) unlockinst();
quit(0);
/* LINTED: no return */
}
int
{
/*
* Obtain status of path; if symbolic link get link's status
*/
return (1); /* not symlink */
}
/*
* Status obtained - if symbolic link, return 0
*/
return (0); /* is a symlink */
}
/*
* Not a symbolic link - return 1
*/
return (1); /* not symlink */
}
static void
{
int i;
char *tmp_path;
for (i = 0; i < eptnum; i++) {
}
}
return;
}
/* locate class action script to execute */
script[0] = '\0';
}
if (script[0] != '\0') {
int td;
tmpdir);
if (td == -1) {
quit(99);
}
quit(99);
}
}
if (a_zoneName == (char *)NULL) {
} else {
}
/* process paths in reverse order */
i = eptnum;
while (--i >= 0) {
continue;
}
/* save the path, and prepend the ir */
if (is_an_inst_root()) {
}
/*
* A path owned by more than one package is marked with
* a NULL ftype (seems odd, but that's how it's
* done). Such files are sacro sanct. Shared editable
* files are a special case, and are marked with an
* ftype of '^'. These files should only be ignored if
* no class action script is present. It is the CAS's
* responsibility to not remove the editable object.
*/
/*
* If the path is provided to the client from a
* server, don't remove anything unless explicitly
* requested through the "-f" option.
*/
} else if (script[0]) {
/*
* If there's a class action script, just put the
* path name into the list.
*/
/* Directories are rmdir()'d. */
warnflag++;
}
} else {
} else {
}
}
} else {
/*
* Before removing this object one more
* check should be done to assure that a
* shared object is not removed.
* This can happen if the original object
* was incorrectly updated with the
* incorrect class identifier.
* This handles pathologcal cases that
* weren't handled above.
*/
continue;
}
/* Regular files are unlink()'d. */
warnflag++;
}
} else {
} else {
}
}
}
/* restore the original path */
if (is_an_inst_root()) {
}
/*
* free memory allocated for this entry memory used for
* pathnames will be freed later by a call to pathdup()
*/
if (eptlist[i]) {
}
}
if (script[0]) {
if (pkgverbose)
else
clr_ulimit();
}
}
}
static void
{
switch (retcode) {
case 2:
case 12:
case 22:
warnflag++;
/*FALLTHRU*/
if (msg)
case 10:
case 20:
if (retcode >= 10)
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:
/* NOT REACHED */
default:
if (msg)
quit(1);
}
}
static void
usage(void)
{
exit(1);
}
/*
* Name: path_valid
* Description: Checks a string for being a valid path
*
* Arguments: path - path to validate
*
* Returns : B_TRUE - success, B_FALSE otherwise.
* B_FALSE means path was null, too long (>PATH_MAX),
* or too short (<1)
*/
static boolean_t
{
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
} else {
/* path < 1 */
return (B_FALSE);
}
}