diff options
author | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
---|---|---|
committer | Moriah Waterland <Moriah.Waterland@Sun.COM> | 2009-06-03 20:16:25 -0600 |
commit | 5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch) | |
tree | 0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/cmd/svr4pkg/installf/main.c | |
parent | 2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff) | |
download | illumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz |
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/cmd/svr4pkg/installf/main.c')
-rw-r--r-- | usr/src/cmd/svr4pkg/installf/main.c | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/usr/src/cmd/svr4pkg/installf/main.c b/usr/src/cmd/svr4pkg/installf/main.c new file mode 100644 index 0000000000..8c70add8ed --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/main.c @@ -0,0 +1,545 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#include <stdio.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <pkginfo.h> +#include <pkgstrct.h> +#include <pkglocs.h> +#include <locale.h> +#include <libintl.h> +#include <instzones_api.h> +#include <pkglib.h> +#include <install.h> +#include <libadm.h> +#include <libinst.h> +#include "installf.h" + +#define BASEDIR "/BASEDIR/" + +#define INSTALF (*prog == 'i') +#define REMOVEF (*prog == 'r') + +#define MSG_MANMOUNT "Assuming mounts were provided." + +#define ERR_PKGNAME_TOO_LONG \ +"The package name specified on the command line\n" \ +"exceeds the maximum package name length: a package name may contain a\n" \ +"maximum of <%d> characters; however, the package name specified on\n" \ +"the command line contains <%d> characters, which exceeds the maximum\n" \ +"package name length by <%d> characters. Please specify a package name\n" \ +"that contains no more than <%d> characters." + +#define ERR_DB_GET "unable to retrieve entries from the database." +#define ERR_DB_PUT "unable to update the package database." +#define ERR_ROOT_SET "Could not set install root from the environment." +#define ERR_ROOT_CMD "Command line install root contends with environment." +#define ERR_CLASSLONG "classname argument too long" +#define ERR_CLASSCHAR "bad character in classname" +#define ERR_INVAL "package instance <%s> is invalid" +#define ERR_NOTINST "package instance <%s> is not installed" +#define ERR_MERG "unable to merge contents file" +#define ERR_SORT "unable to sort contents file" +#define ERR_I_FAIL "installf did not complete successfully" +#define ERR_R_FAIL "removef did not complete successfully" +#define ERR_NOTROOT "You must be \"root\" for %s to execute properly." +#define ERR_USAGE0 "usage:\n" \ + "\t%s [[-M|-A] -R host_path] [-V ...] pkginst path " \ + "[path ...]\n" \ + "\t%s [[-M|-A] -R host_path] [-V ...] pkginst path\n" + +#define ERR_USAGE1 "usage:\n" \ + "\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \ + "<path>\n" \ + "\t%s [[-M] -R host_path] [-V ...] [-c class] <pkginst> " \ + "<path> <specs>\n" \ + "\t where <specs> may be defined as:\n" \ + "\t\tf <mode> <owner> <group>\n" \ + "\t\tv <mode> <owner> <group>\n" \ + "\t\te <mode> <owner> <group>\n" \ + "\t\td <mode> <owner> <group>\n" \ + "\t\tx <mode> <owner> <group>\n" \ + "\t\tp <mode> <owner> <group>\n" \ + "\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 sortflag; +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) +{ + FILE *pp; + VFP_T *cfTmpVfp; + VFP_T *cfVfp; + char *cmd; + char *tp; + char *prog; + char *pt; + char *vfstab_file = NULL; + char line[1024]; + 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)); + } + + sortflag = 0; + + /* + * 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); + } + +#ifdef ALLOW_EXCEPTION_PKG_LIST + /* + * ********************************************************************* + * this feature is removed starting with Solaris 10 - there is no built + * in list of packages that should be run "the old way" + * ********************************************************************* + */ + /* Until 2.9, set it from the execption list */ + if (pkginst && exception_pkg(pkginst, LINK)) + set_nonABI_symlinks(); +#endif + /* + * 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(&cfVfp, &cfTmpVfp, 0L)) { + quit(1); + } + + if (fflag) { + dbchg = dofinal(cfVfp, 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(cfVfp, cfTmpVfp, extlist, 0); + if (dbchg < 0) { + progerr(gettext(ERR_MERG)); + quit(99); + } + } + + if (dbchg) { + if ((n = swapcfile(&cfVfp, &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()) { + c = strlen(get_client_basedir()); + (void) snprintf(outbuf, sizeof (outbuf), + "%s/%s\n", get_basedir(), + &(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); + } + } + } + + /* Sort the contents files if needed */ + if (sortflag) { + int n; + + warnflag += (ocfile(&cfVfp, &cfTmpVfp, 0L)) ? 0 : 1; + if (!warnflag) { + size_t len; + + len = strlen(CMD_SORT) + strlen(get_PKGADM()) + + strlen("/contents") + 5; + cmd = (char *)malloc(len); + (void) snprintf(cmd, len, "%s %s/contents", + CMD_SORT, get_PKGADM()); + pp = popen(cmd, "r"); + if (pp == NULL) { + (void) vfpClose(&cfVfp); + (void) vfpClose(&cfTmpVfp); + free(cmd); + progerr(gettext(ERR_SORT)); + quit(1); + } + while (fgets(line, 1024, pp) != NULL) { + if (line[0] != DUP_ENTRY) { + vfpPuts(cfTmpVfp, line); + } + } + free(cmd); + (void) pclose(pp); + n = swapcfile(&cfVfp, &cfTmpVfp, pkginst, 1); + if (n == RESULT_WRN) { + warnflag++; + } else if (n == RESULT_ERR) { + quit(99); + } + + relslock(); /* Unlock the database. */ + } + } + + 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); +} |