/*
* 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.
*/
/*
* This module contains all the code necessary to establish the key base
* directories to which the actual components of the package will be
* installed or removed. -- JST
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
#include <pkglib.h>
#include <install.h>
#include <libadm.h>
#include <libinst.h>
static char *expand_path(char *path);
static int set_client_basedir(void);
static char *fixpath_dup(char *path);
static int orig_offset_rel;
/*
* base_sepr and rel_fmt support construction of absolute paths from
* relative paths.
*/
extern int getmapmode();
"pathname: <%s>"
"environment CLIENT_BASEDIR <%s> do not match."
"duplicate installation at %s."
"base directories."
"directory."
"before installation is attempted."
"before installation is attempted, but a file " \
"already exists in it's place."
"created now"
"directory be available for installation of " \
"appropriate software. This directory may be part " \
"of any mounted filesystem, or may itself be a " \
"mount point. In general, it is unwise to select a " \
"base directory which already contains other files " \
/*
* Set the install root (-R option).
*/
int
{
/*
* If we've already set the install_root but no one has used it
* yet, we'll complain and allow the change. If it's been used
* then we'll deny the switch & return failed.
*/
if (install_root_exists)
/* If the two install_roots are different - problem */
/* We are trying to *change* the install_root */
if (ir_accessed) {
return (0);
} else { /* !ir_accessed */
install_root_exists = 0; /* reset */
install_root = NULL;
}
if (*path != '/') {
return (0);
}
install_root_exists = 1;
/* If install_root is '/' then it's trivial. */
if (install_root_len == 1)
install_root_len = 0;
else
} else
install_root_exists = 0;
return (1);
}
/*
* This routine returns a path with the correct install_root prepended.
* if the install_root has been set. NOTE : this allocates memory
* which will need to be freed at some point.
*/
char *
{
if (install_root_exists) {
if ((npath =
1)) == NULL) {
quit(99);
}
ir_ptr = get_inst_root();
while (*ir_ptr) /* for every char in install_root */
/*
* If install_root == "/", a concatenation will
* result in a return value of "//...", same goes
* for an install_root ending in '/'. So we back
* over a trailing '/' if it's there.
*/
npath_ptr--;
} else
/*
* If there's no install root & no client_basedir,
* then return the path
*/
} else
/*
* If there's no path specified, return the install root
* since no matter what happens, this is where the
* path will have to start.
*/
if (install_root_exists)
return (npath);
}
/*
* This routine does what fixpath() does except it's for high-volume
* stuff restricted to the instvol() function. By using
* pathdup() and pathalloc() memory fragmentation is reduced. Also, the
* memory allocated by pathdup() and pathalloc() gets freed at the end
* of each volume installed.
*/
char *
{
if (install_root_exists) {
ir_ptr = get_inst_root();
while (*ir_ptr) /* for every char in install_root */
/*
* If install_root == "/", a concatenation will
* result in a return value of "//...", same goes
* for an install_root ending in '/'. So we back
* over a trailing '/' if it's there.
*/
npath_ptr--;
} else
/*
* If there's no install root & no client_basedir,
* then return the path
*/
} else
/*
* If there's no path specified, return the install root
* since no matter what happens, this is where the
* path will have to start.
*/
if (install_root_exists)
return (npath);
}
/*
* This returns a pointer to a static name. This could be abused.
* -- JST (1993-07-21)
*/
char *
get_inst_root(void)
{
return (install_root);
}
/*
* This routine takes path and removes install_root from the path
* if it has already been prepended. If install_root is not prepended to
* path or install_root is '/' or path == NULL then path is returned
* as is. If the resulting path is somehow relative, a corrupt
* package name error is raised and the program quits. NOTE : This
* function usually returns a pointer into the original path
* argument. It doesn't allocate new memory. This is possible,
* of course, because the path being returned is guaranteed to
* be a subset of the original argument unless basedir = '/' in
* which case a pointer to a static "/" is returned. See
* orig_path() below if you want to be handed a new copy of the
* return value.
*/
char *
{
if (!install_root_exists) /* if no install_root */
/*
* Otherwise, if install_root is really prepended to the path
* then remove it dealing appropriately with special cases.
*/
retv = "/";
/*
* The result will be relative if install_root = '/'.
* If the basedir path was built legally, then moving
* the pointer back one character will make it
* absolute. If that fails then the path we got was
* incorrectly constructed in the first place.
*/
else if (*retv != '/') {
retv--;
if (*retv != '/') {
quit(99);
}
}
} else
}
return (retv);
}
/*
* This function does the same as orig_path_ptr() except that it mallocs
* new space and provides a new copy of the original basedir path which
* needs to be free()'d one way or another later.
*/
char *
{
char *retv;
}
/*
* This function lets us hold onto the environment's version of
* CLIENT_BASEDIR for later review by set_client_basedir().
*/
void
{
register char *cb_ptr;
}
}
/* ask for the basedir */
static int
{
int n;
if (nointeract) {
return (5);
} else {
path[0] = '\0';
return (n); /* FAIL */
}
return (0);
}
/*
* Set the basedir and client_basedir based on install root and config
* files. It returns 0 if all OK otherwise returns the error code base
* appropriate to the problem.
*/
int
{
int n;
relocatable = reloc;
/*
* If there are no relocatable files basedir is probably meaningless
* so we skip ahead to the simple tests. Otherwise we do the twisted
* stuff below. The BASEDIR is set based on the following heirarchy :
* 1. The entry in the admin file
* 2. The entry in the pkginfo file delivered on the medium
* 3. The entry in the already installed pkginfo file
* 4. ask
* If it's not a relocatable package, we go with whatever seems
* reasonable; if it's relocatable and we've exhausted our
* options, we ask.
*/
if (reloc) {
int is_update = 0;
int is_ask = 0;
if (is_adm_basedir) {
is_update = 1;
is_ask = 1;
is_ask = 1;
}
/*
* If there's a BASEDIR in the admin file & it's a valid
* absolute pathname, use it.
*/
/* If admin says 'ask regardless', ask and continue */
else if (is_adm_basedir && is_ask) {
return (n);
if (is_update &&
quit(4);
}
}
/*
* If it isn't the only other valid option,
* namely 'default', quit FAIL.
*/
else if (is_adm_basedir &&
return (1);
/*
* OK, the admin file has no preference, so we go to the
* other sources.
*/
} else {
/*
* Check to see if BASEDIR is set in the environment
* (probably from the pkginfo file on the installation
* medium).
*/
else {
/*
* Check to see if the package BASEDIR was
* already defined during a previous
* installation of this package instance. The
* function below looks for an installed
* pkginfo file and scans it.
*/
return (n);
}
}
} else { /* not relocatable */
/*
* Since all paths are absolute the only reason to have a
* basedir is if there's an install root meaning there's
* really a basedir relative to this host or this package is
* absolute only because it's sparse in which case we're
* interested in the prior basedir. So we next check for a
* prior basedir and then an install root.
*/
else if (install_root_exists)
/*
* If we have a basedir *only because*
* we have an install_root, we need to
* set orig_basedir to '/' to simplify
* later attempts to force
* client_basedir.
*/
orig_basedir = "/";
else {
eval_valid++; /* we can run eval_path() now */
return (0); /* fixpath below unnecessary */
}
}
basedir_exists = 1;
/*
* If basedir == "/" then there's no need for a "/" between
* it and the rest of the path.
*/
base_sepr = 0;
if (set_client_basedir() == 0) {
return (1);
}
eval_valid++; /* we've confirmed the validity of everything */
return (0);
}
/*
* Make a directory from a path and all necessary directories above it as
* needed.
*/
int
mkpath(char *p)
{
char *pt;
/* if entire path exists, return o.k. */
return (0);
}
/* entire path not there - check components and create */
do {
*pt = '\0';
}
return (-1);
}
if (pt) {
*pt++ = '/';
}
} while (pt);
return (0);
}
/* This makes the required base directory if necessary */
void
{
int n;
/*
* If a base directory is called for but there's no such directory on
* the system, deal with that issue.
*/
if (flag) { /* Interaction is OK. */
/*
* If there's a non-directory object in the way, ask.
*/
quit(n);
quit(3);
/*
* It isn't a directory, so we'll just unlink
* it.
*/
basedir);
quit(99);
}
} else {
quit(n);
quit(3);
}
}
quit(99);
}
}
}
/*
* Create a client_basedir if it is appropriate. If all goes well, resulting
* in either a valid client_basedir or a valid lack thereof, it returns 1.
* If there is an irreconcileable conflict, it returns 0.
*/
static int
set_client_basedir(void)
{
if (install_root_exists) {
if (basedir_exists)
else
client_basedir = "/";
}
/*
* In response to an agreement associated with bug report #1133956,
* CLIENT_BASEDIR will be defined in all cases where BASEDIR is
* defined until the on1094 release. For on1094 delete the else if
* and associated expressions below. -- JST (6/25/1993)
*/
else if (basedir_exists) {
}
/*
* At this point we may or may not have a client_basedir defined. Now
* we need to check for one in the environment & make sure it syncs
* up with prior findings. If there's no other client_basedir defined,
* the environment defines it.
*/
if (env_cl_bdir && *env_cl_bdir) {
if (client_basedir_exists) {
/* If the two client basedirs mismatch, return fail */
return (0);
}
} else {
}
}
return (1);
}
static char *
{
return (path);
}
char *
get_basedir(void)
{
return (basedir);
}
char *
get_client_basedir(void)
{
return (client_basedir);
}
/*
* This function returns the basedir that is appropriate for this package's
* pkginfo file.
*/
char *
get_info_basedir(void)
{
if (install_root_exists)
return (client_basedir);
else if (basedir_exists)
return (basedir);
else
return (NULL);
}
int
is_an_inst_root(void)
{
return (install_root_exists);
}
int
is_a_basedir(void)
{
return (basedir_exists);
}
int
is_relocatable(void)
{
return (relocatable);
}
int
is_a_cl_basedir(void)
{
return (client_basedir_exists);
}
/*
* Since calls to putparam() become valid long after much of the above
* code has run, this routine allows the insertion of these key
* environment variables without passing a bunch of pointers.
*/
void
put_path_params(void)
{
if (install_root_exists)
if (basedir_exists)
}
/*
* This fills three pointers and a buffer which contains the longest
* possible path (with install_root and basedir prepended. The pointers
* are to the subpaths within the string. This was added so that the
* eptlist could be produced with all relevant paths defined without
* repeated calls and string scans. For example, given a path of
* haberdasher/crute we may return
*
* | |
* client_ptr --------------------------- |
* map_ptr -------------------------------------------
*
* We construct the new path based upon the established environment
* and the type of path that was passed. Here are the possibilities:
*
* | | relative path | absolute path |
* | --------------------------------|---------------|---------------|
* | is_an_inst_root | 1 | 2 |
* V ! an_inst_root && is_a_basedir | 1 | 3 |
* ! an_inst_root && ! a_basedir | X | 3 |
*
* METHOD
* 1. Prepend the basedir to the path (the basedir is guaranteed to exist
* whenever there's an install_root).
*
* 2. Prepend the install_root (not the basedir) to the path
*
* 3. Return the path as unchanged.
*
* X. THIS CAN'T HAPPEN
*/
int
{
static int client_offset;
int path_size;
if (!offsets_valid) {
/*
* This is the offset from the beginning of the evaluated
* path to the start of the relative path. Note that we
* are accounting for the '/' inserted between the
* basedir and the path with the '+ 1'. If there is a
* relative path, then there is always a basedir. The
* only way this will come up '0' is if this is an
* absolute package.
*/
base_sepr) : 0;
/*
* This is the position of the client-relative path
* in that it points to the '/' beginning the base
* directory or the absolute path. Once the basedir has
* been afixed, the path is absolute. For that reason,
* the client path is the same thing as the original path
* if it were absolute.
*/
offsets_valid = 1;
}
/*
* If we've evaluated the base directory and come up trumps,
* then we can procede with this operation, otherwise, the
* available data is too ambiguous to resolve the issue.
*/
if (eval_valid) {
if (relocatable) {
/*
* Figure out how long our buffer will
* have to be.
*/
if (map_ptr)
*map_ptr = *server_ptr +
/* LINTED warning: variable format specifier */
} else {
retcode = 0;
}
} else { /* NOT RELATIVE */
*client_ptr = "/";
if (map_ptr)
*map_ptr = *client_ptr;
}
retcode = 1;
} else {
retcode = 0;
}
return (retcode);
}
void
{
char *inst_release_path;
char *key;
char *value;
/*
* Put the variables found in a clients INST_RELEASE file into the
* package environment so procedure scripts can know what
* doesn't return state since the INST_RELEASE file may not exist in
* some package installation environments
*/
}
*key = '\0';
}
}
}
/*
* Increment variable indicating the installation is from a partially spooled
* package.
*/
void
set_partial_inst(void)
{
partial_inst++;
}
/*
* Return variable indicating that the installation is from a partially spooled
* package.
* Returns: !0 for true
* 0 for false
*/
int
is_partial_inst(void)
{
return (partial_inst);
}
/*
* Increment variable indicating that only the depend and pkginfo DB's are to be
* updated
*/
void
{
}
/*
* Return variable indicating that the installation only updates the depend
* and pkginfo DB's.
* Returns: !0 for true
* 0 for false
*/
is_depend_pkginfo_DB(void)
{
return (depend_pkginfo_DB);
}
/*
* Increment variable indicating that packages should not be spooled in
*/
void
disable_spool_create(void)
{
}
/*
* Return variable indicating whether or not the partial spool directory
* should be created.
* Returns: 1 for true
* 0 for false
*/
int
is_spool_create(void)
{
return (partial_spool_create);
}