/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <locale.h>
#include <libintl.h>
#include <pkgstrct.h>
#include <pkglocs.h>
#include <assert.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <messages.h>
#include <install.h>
#include <libinst.h>
#include <libadm.h>
extern int npkgs; /* the number of packages yet to be installed */
/*
* ckquit is a global that controls 'ckyorn' (defined in libadm)
* If ckquit is non-zero, then "quit" is allowed as an answer when
* ckyorn is called. If is it zero, then "quit" is not an allowed answer.
*/
extern int ckquit;
/*
* each one of these represents a single kind of dependency check
*/
/*
* each one of these represents a localized message for a single kind
* of dependency check
*/
static char *IMSG_ATTRIB;
static char *IMSG_SETUIDF;
static char *IMSG_SETGIDF;
static char *IMSG_OVERWR;
/*
* each one of these represents a function to handle a single kind of
* dependency check
*/
/*
* name, ignore_values, err_msg, depcklFunc, recrd
* ---
* ignore_values == NULL:
* package and zone information is collected in the "record" object for
* each occurance - then a message is constructed for each zone that
* reported the condition - the message includes that portion of the
* check past the "=" - then the specified "depcklFunc" is called to
* process each message.
* Message format:
* %s %s <%s> %s <%s>
* Message arguments:
* ---
* ignore-values == "???":
* these checks are ignored if they return one of the listed values
* if they do NOT return one of the listed values, then the package
* and zone information is collected in the "record" object for each
* occurance - then a single unified message is constructed for all
* zones that report the same condition; then the specified "depcklFunc"
* is called to process the resulting combined message.
* Message format:
* %s <%s> %s <%s>
* Message arguments:
* ---
* ignore-values="":
* same as above BUT no check to ignore is done; message always reported
*/
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
};
/*
* Name: preinstall_verify
* Description: verify results of preinstallation dependency checking
* Arguments: a_pkglist - pointer to array of strings representing the names
* of all the packages that have been checked
* a_zlst - list of zones that dependencies were checked on
* a_zoneTempDir - pointer to string representing the path where
* the files containing the preinstallation dependency
* check data are located
* Returns: int
* == 0 - continue processing
* != 0 - do not continue processing
*/
int
{
char *pkginst;
int i;
/*
* entry assertions
*/
/*
* entry debugging info
*/
/*
* localize messages
*/
"by installation of %s\n<%s> on %s <%s>.\n");
/*
* outer loop - process each package first
*/
char *zoneName;
int zoneIndex;
/*
* if this package is marked "install in this zone only", then
* do not check dependencies in any zone
*/
continue;
}
/*
* inner loop - for each package process each zone second
*/
for (zoneIndex = 0;
int len;
/* skip the zone if it is NOT bootable */
continue;
}
/* create path to this packages preinstall check data */
sizeof (preinstallcheckPath),
"%s/%s.%s.preinstallcheck.txt", a_zoneTempDir,
if (len > sizeof (preinstallcheckPath)) {
continue;
}
/* error if preinstall check data path is not a file */
continue;
}
/* open the preinstall check data file */
continue;
}
/* read and process each preinstall check data line */
int j;
int len;
/* remove all new-lines from end of line */
}
/* ignore comment lines */
if (line[0] == '#') {
continue;
}
/* ignore empty lines */
if (line[0] == '\0') {
continue;
}
/* scan dependency list for this item */
for (j = 0;
len) == 0) {
break;
}
}
zoneName);
/* ignore line if not found */
continue;
}
continue;
}
/* found match - record this dependency issue */
}
/* close preinstall check data file */
}
}
/*
* all dependency issues have been recorded; report results
*/
i = depchkReportErrors(DEPCKL);
/* restore "npkgs" */
return (i);
}
/*
* Name: getyorn
* Description: Deliver dependency check reason; ask question; return response
* Arguments: a_msg - pointer to string representing the message to output
* such as 'The package <..> contains <...>'
* a_pkg - pointer to string representing the package for which
* the question is being asked
* a_nocheck - should the message be output?
* == 0 - do not output the message
* != 0 - output the message
* a_quit - should the question NOT be asked?
* == 0 - ask the question
* != 0 - do not ask the question - return "no"
* a_helpMsg - pointer to string representing help message to be
* made available if the question is asked
* == NULL - no help message is available
* a_adminMsg - pointer to string representing the dependency check
* failure 'reason' - such as "Privilege checking failed."
* == NULL - no failure reason is available
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
char *a_helpMsg, char *a_adminMsg)
{
int n;
int saveCkquit;
/*
* entry assertions
*/
/*
* entry debugging info
*/
/* return success (0) if "nocheck" is non-zero */
if (a_nocheck != 0) {
return (0);
}
/* output reason for this particular failure */
}
/* return "4 (administration)" if "quit" is non-zero */
if (a_quit != 0) {
/* output failure "admin reason" if available */
}
return (4);
}
/* return "5 (administration interaction required)" if -n */
if (echoGetFlag() == B_FALSE) {
return (5);
}
/* prepare question to ask "continue with pkg <xxx>?" */
/* ask question */
saveCkquit = ckquit;
ckquit = 0;
ckquit = saveCkquit;
if (n != 0) {
return (n);
}
/* return "3 (interruption) if not "y" or "Y" */
return (3);
}
/* return "0 - success" */
return (0);
}
/*
* Trigger: prerequisite-incomplete=<<package>>
* Sequence: - one or more: prerequisite-incomplete=<<package>>
* - one: ckdepend=<<n>>
* Actions: Output message if "idepend!=nocheck"
* Return 0
* Terminate when 'ckdepend' processed
*/
static int
{
}
return (0);
}
/*
* Trigger: prerequisite-installed=<<package>>
* Sequence: - one or more: prerequisite-installed=<<package>>
* - one: ckdepend=<<n>>
* Actions: Output message if "idepend!=nocheck"
* Return 0
* Terminate when 'ckdepend' processed
*/
static int
{
}
return (0);
}
/*
* Trigger: ckpartialinstall=<<n>>
* Sequence: - one: ckpartialinstall=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: ckpartialremove=<<n>>
* Sequence: - one: ckpartialremove=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
* 99 - fatal error
*/
static int
{
return (0);
}
/*
* Trigger: conflict-contents=<<n>>
* Sequence: - one or more of:
* -- conflict-contents=<<path>>
* -- conflict-attributes=<<path>>
* - one: ckconflict=<<n>>
* Actions: output message
* Return value: int
* 0 - success
*/
static int
{
return (0);
}
/*
* Trigger: ckinstance=<<n>>
* Sequence: - one or more of:
* -- install-instance=true
* -- install-new-only=true\n
* -- install-same-instance=true\n
* -- install-ovewrite=true\n
* -- install-too-many-instances=true\n
* -- install-new-instance=true\n
* - one: ckpdepend=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: ckdepend=<<n>>
* Sequence: - one or more of:
* -- incompat=<<package>>
* -- prerequisite-incomplete=<<package>>
* -- prerequisite-installed=<<package>>
* -- dependson=<<package>>
* -- dependsonme=<<package>>
* - one: ckpdepend=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: ckspace=<<n>>
* Sequence: - one: ckspace=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: ckpkgdirs=<<n>>
* Sequence: - one: ckpkgdirs=<<n>>
* Actions: output message
* Return 4
*/
static int
{
return (4);
}
/*
* Trigger: ckdirs=<<path>>
* Sequence: - one: ckdirs=<<path>>
* Actions: output message
* Return 4
*/
static int
{
return (4);
}
/*
* Trigger: ckpkgfilebad=<<path>>
* Sequence: - one or more:
* -- ckpkgfilebad=<<path>>
* - one ckpkgfiles=<n>
* Actions: output message
* Return 0
*/
static int
{
return (0);
}
/*
* Trigger: ckconflict=<<n>>
* Sequence: - one or more:
* -- conflict-contents=<<path>>
* -- conflict-attributes=<<path>>
* - one: ckconflict=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: cksetuid=<<n>>
* Sequence: - one or more:
* -- setuid=<path>:<owner>
* -- setgid=<path>:<group>
* -- setuid-overwrite=true
* - one: cksetuid=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
int n;
int saveCkquit;
/* if user did not answer "n" return answer given */
if (n != 3) {
return (n);
}
saveCkquit = ckquit;
ckquit = 0;
ckquit = saveCkquit;
if (n != 0) {
return (n);
}
/* return "3 (interruption) if not "y" or "Y" */
return (3);
}
/* return "0 - success" */
return (0);
}
/*
* Trigger: ckpriv=<<n>>
* Sequence: - one: ckpriv=<<n>>
* Actions: process according to settings
* Return value: int
* 0 - success
* 1 - end of file
* 2 - undefined error
* 3 - answer was not "y"/was "q"
* 4 - quit action taken
* 5 - interactive mode required
*/
static int
{
}
/*
* Trigger: ckpkgfiles=<<n>>
* Sequence: - one or more:
* -- ckpkgfilebad=<path>
* - one: ckpkgfiles=<<n>>
* Return value: int
* 0 - success
* 4 - failure
*/
static int
{
return (4);
}
static int
{
}
/* ARGSUSED1 */
static int
{
char *cp;
*cp = ' ';
return (0);
}
/* ARGSUSED1 */
static int
{
char *cp;
*cp = ' ';
return (0);
}
static int
{
}