main.c revision 382f00c9f2bd34208f10bb7d2be96bc6696eb8c4
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson/*
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * CDDL HEADER START
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * The contents of this file are subject to the terms of the
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Common Development and Distribution License (the "License").
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * You may not use this file except in compliance with the License.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews *
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * or http://www.opensolaris.org/os/licensing.
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * See the License for the specific language governing permissions
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * and limitations under the License.
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson *
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * When distributing Covered Code, include this CDDL HEADER in each
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * If applicable, add the following below this CDDL HEADER, with the
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * fields enclosed by brackets "[]" replaced with your own identifying
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * information: Portions Copyright [yyyy] [name of copyright owner]
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson *
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * CDDL HEADER END
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson */
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson/*
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson * Use is subject to license terms.
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson */
2b43d1d8c508d7e7be388d85e8bf83ff0aed1e11Automatic Updater
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson/* All Rights Reserved */
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <stdio.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <fcntl.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <ctype.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <errno.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <string.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <signal.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <stdlib.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <unistd.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <pkginfo.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <pkgstrct.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <pkglocs.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <locale.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <libintl.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <instzones_api.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <pkglib.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <install.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <libadm.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include <libinst.h>
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#include "installf.h"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define BASEDIR "/BASEDIR/"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define INSTALF (*prog == 'i')
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define REMOVEF (*prog == 'r')
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define MSG_MANMOUNT "Assuming mounts were provided."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_PKGNAME_TOO_LONG \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"The package name specified on the command line\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"exceeds the maximum package name length: a package name may contain a\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"maximum of <%d> characters; however, the package name specified on\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"the command line contains <%d> characters, which exceeds the maximum\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"package name length by <%d> characters. Please specify a package name\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson"that contains no more than <%d> characters."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_DB_GET "unable to retrieve entries from the database."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_DB_PUT "unable to update the package database."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_ROOT_SET "Could not set install root from the environment."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_ROOT_CMD "Command line install root contends with environment."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_CLASSLONG "classname argument too long"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_CLASSCHAR "bad character in classname"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_INVAL "package instance <%s> is invalid"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_NOTINST "package instance <%s> is not installed"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_MERG "unable to merge contents file"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_SORT "unable to sort contents file"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_I_FAIL "installf did not complete successfully"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_R_FAIL "removef did not complete successfully"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_NOTROOT "You must be \"root\" for %s to execute properly."
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_USAGE0 "usage:\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t%s [[-M|-A] -R host_path] [-V ...] pkginst path " \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "[path ...]\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t%s [[-M|-A] -R host_path] [-V ...] pkginst path\n"
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson#define ERR_USAGE1 "usage:\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "<path>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "<path> <specs>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t where <specs> may be defined as:\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t\tf <mode> <owner> <group>\n" \
c73d8c1b72ddc3330cfc21e2070dffabca324bf7Mark Andrews "\t\tv <mode> <owner> <group>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t\te <mode> <owner> <group>\n" \
c73d8c1b72ddc3330cfc21e2070dffabca324bf7Mark Andrews "\t\td <mode> <owner> <group>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t\tx <mode> <owner> <group>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t\tp <mode> <owner> <group>\n" \
473ca0bf8c73e5fc3132df074b2d4e14be5eaa1eAndreas Gustafsson "\t\tc <major> <minor> <mode> <owner> <group>\n" \
"\t\tb <major> <minor> <mode> <owner> <group>\n" \
"\t\ts <path>=<srcpath>\n" \
"\t\tl <path>=<srcpath>\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);
}
/*
* 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);
}