diff options
Diffstat (limited to 'usr/src/cmd/svr4pkg/installf')
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/Makefile | 49 | ||||
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/dofinal.c | 236 | ||||
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/installf.c | 308 | ||||
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/installf.h | 57 | ||||
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/main.c | 545 | ||||
| -rw-r--r-- | usr/src/cmd/svr4pkg/installf/removef.c | 127 |
6 files changed, 1322 insertions, 0 deletions
diff --git a/usr/src/cmd/svr4pkg/installf/Makefile b/usr/src/cmd/svr4pkg/installf/Makefile new file mode 100644 index 0000000000..da8ff4b2b7 --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/Makefile @@ -0,0 +1,49 @@ +# +# 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. +# + +PROG= installf + +OBJS= installf.o \ + main.o \ + removef.o \ + dofinal.o + +include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg + +ROOTUSRSBINLINK = $(ROOTUSRSBIN)/removef + +LDLIBS += -lpkg -linstzones -ladm +LDLIBS += -lnsl -lsocket + +.KEEP_STATE: + +all: $(PROG) +install: all $(ROOTUSRSBINPROG) $(ROOTUSRSBINLINK) + +$(ROOTUSRSBINLINK): $(ROOTUSRSBINPROG) + $(RM) $@; $(LN) $(ROOTUSRSBINPROG) $@ + +include $(SRC)/cmd/svr4pkg/Makefile.svr4pkg.targ diff --git a/usr/src/cmd/svr4pkg/installf/dofinal.c b/usr/src/cmd/svr4pkg/installf/dofinal.c new file mode 100644 index 0000000000..331ea43810 --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/dofinal.c @@ -0,0 +1,236 @@ +/* + * 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 2006 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 <errno.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <pkgstrct.h> +#include <locale.h> +#include <libintl.h> +#include <pkglib.h> +#include "install.h" +#include "libinst.h" +#include "libadm.h" + +extern struct cfextra **extlist; +extern struct cfent **eptlist; + +extern char *pkginst; + +#define ERR_WRITE "write of intermediate contents file failed" + +static char *check_db_entry(VFP_T *, struct cfextra *, int, char *, int *); + +/*ARGSUSED*/ +int +dofinal(VFP_T *vfp, VFP_T *vfpo, int rmflag, char *myclass, char *prog) +{ + struct cfextra entry; + int n, indx, dbchg; + char *save_path = NULL; + + entry.cf_ent.pinfo = NULL; + entry.fsys_value = BADFSYS; + entry.fsys_base = BADFSYS; + indx = 0; + + while (extlist && extlist[indx] && (extlist[indx]->cf_ent.ftype == 'i')) + indx++; + + dbchg = 0; + + while (n = srchcfile(&(entry.cf_ent), "*", vfp, vfpo)) { + if (n < 0) { + char *errstr = getErrstr(); + progerr(gettext + ("bad entry read in contents file")); + logerr(gettext("pathname=%s"), + (entry.cf_ent.path && + *(entry.cf_ent.path)) ? + entry.cf_ent.path : "Unknown"); + logerr(gettext("problem=%s"), + (errstr && *errstr) ? errstr : + "Unknown"); + quit(99); + } + save_path = check_db_entry( + vfpo, &entry, rmflag, myclass, &dbchg); + + /* Restore original server-relative path, if needed */ + if (save_path != NULL) { + entry.cf_ent.path = save_path; + save_path = NULL; + } + } + + return (dbchg); +} + +static char * +check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass, + int *dbchg) +{ + struct pinfo *pinfo; + int fs_entry; + char *save_path = NULL; + char *tp; + + /* write this entry to the contents file */ + + if (myclass && strcmp(myclass, entry->cf_ent.pkg_class)) { + if (putcvfpfile(&entry->cf_ent, vfpo)) { + progerr(gettext(ERR_WRITE)); + quit(99); + } + return (NULL); + } + + /* + * Now scan each package instance holding this file or + * directory and see if it matches the package we are + * updating here. + */ + pinfo = entry->cf_ent.pinfo; + while (pinfo) { + if (strcmp(pkginst, pinfo->pkg) == 0) + break; + pinfo = pinfo->next; + } + + /* + * If pinfo == NULL at this point, then this file or + * directory isn't part of the package of interest. + * So the loop below executes only on files in the package + * of interest. + */ + + save_path = NULL; + + if (pinfo) { + if (rmflag && (pinfo->status == RM_RDY)) { + *dbchg = 1; + + (void) eptstat(&(entry->cf_ent), pkginst, '@'); + + if (entry->cf_ent.npkgs) { + if (putcvfpfile(&(entry->cf_ent), vfpo)) { + progerr(gettext(ERR_WRITE)); + quit(99); + } + } + return (NULL); + + } else if (!rmflag && (pinfo->status == INST_RDY)) { + *dbchg = 1; + + /* tp is the server-relative path */ + tp = fixpath(entry->cf_ent.path); + /* save_path is the cmd line path */ + save_path = entry->cf_ent.path; + /* entry has the server-relative path */ + entry->cf_ent.path = tp; + + /* + * The next if statement figures out how + * the contents file entry should be + * annotated. + * + * Don't install or verify objects for + * remote, read-only filesystems. We + * need only verify their presence and + * flag them appropriately from some + * server. Otherwise, ok to do final + * check. + */ + fs_entry = fsys(entry->cf_ent.path); + + if (is_remote_fs_n(fs_entry) && + !is_fs_writeable_n(fs_entry)) { + /* + * Mark it shared whether it's present + * or not. life's too funny for me + * to explain. + */ + pinfo->status = SERVED_FILE; + + /* + * restore for now. This may + * chg soon. + */ + entry->cf_ent.path = save_path; + } else { + /* + * If the object is accessible, check + * the new entry for existence and + * attributes. If there's a problem, + * mark it NOT_FND; otherwise, + * ENTRY_OK. + */ + if (is_mounted_n(fs_entry)) { + int n; + + n = finalck((&entry->cf_ent), 1, 1, + B_FALSE); + + pinfo->status = ENTRY_OK; + if (n != 0) { + pinfo->status = NOT_FND; + } + } + + /* + * It's not remote, read-only but it + * may look that way to the client. + * If it does, overwrite the above + * result - mark it shared. + */ + if (is_served_n(fs_entry)) + pinfo->status = SERVED_FILE; + + /* restore original path */ + entry->cf_ent.path = save_path; + /* and clear save_path */ + save_path = NULL; + } + } + } + + /* Output entry to contents file. */ + if (putcvfpfile(&(entry->cf_ent), vfpo)) { + progerr(gettext(ERR_WRITE)); + quit(99); + } + + return (save_path); +} diff --git a/usr/src/cmd/svr4pkg/installf/installf.c b/usr/src/cmd/svr4pkg/installf/installf.c new file mode 100644 index 0000000000..b0eab9cedc --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/installf.c @@ -0,0 +1,308 @@ +/* + * 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 2006 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 <errno.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <pkgstrct.h> +#include <locale.h> +#include <libintl.h> +#include <pkglib.h> +#include <install.h> +#include <libinst.h> +#include <libadm.h> +#include "installf.h" + +#define LSIZE 1024 +#define MALSIZ 164 + +#define ERR_MAJOR "invalid major number <%s> specified for <%s>" +#define ERR_MINOR "invalid minor number <%s> specified for <%s>" +#define ERR_MODE "invalid mode <%s> specified for <%s>" +#define ERR_RELPATH "relative pathname <%s> not permitted" +#define ERR_NULLPATH "NULL or garbled pathname" +#define ERR_LINK "invalid link specification <%s>" +#define ERR_LINKFTYPE "ftype <%c> does not match link specification <%s>" +#define ERR_LINKARGS "extra arguments in link specification <%s>" +#define ERR_LINKREL "relative pathname in link specification <%s>" +#define ERR_FTYPE "invalid ftype <%c> for <%s>" +#define ERR_ARGC "invalid number of arguments for <%s>" +#define ERR_SPECALL "ftype <%c> requires all fields to be specified" + +static int validate(struct cfextra *ext, int argc, char *argv[]); +static void checkPaths(char *argv[]); + +int +installf(int argc, char *argv[]) +{ + struct cfextra *new; + char line[LSIZE]; + char *largv[8]; + int myerror; + + if (strcmp(argv[0], "-") != 0) { + if (argc < 1) + usage(); /* at least pathname is required */ + extlist = calloc(2, sizeof (struct cfextra *)); + extlist[0] = new = calloc(1, sizeof (struct cfextra)); + eptnum = 1; + + /* There is only one filename on the command line. */ + checkPaths(argv); + if (validate(new, argc, argv)) + quit(1); + return (0); + } + + /* Read stdin to obtain entries, which need to be sorted. */ + eptnum = 0; + myerror = 0; + extlist = calloc(MALSIZ, sizeof (struct cfextra *)); + while (fgets(line, LSIZE, stdin) != NULL) { + argc = 0; + argv = largv; + argv[argc++] = strtok(line, " \t\n"); + while (argv[argc] = strtok(NULL, " \t\n")) + argc++; + + if (argc < 1) + usage(); /* at least pathname is required */ + + new = calloc(1, sizeof (struct cfextra)); + if (new == NULL) { + progerr(strerror(errno)); + quit(99); + } + + checkPaths(argv); + + if (validate(new, argc, argv)) + myerror++; + + extlist[eptnum] = new; + if ((++eptnum % MALSIZ) == 0) { + extlist = realloc(extlist, + (sizeof (struct cfextra *) * (eptnum+MALSIZ))); + if (!extlist) { + progerr(strerror(errno)); + quit(99); + } + } + } + extlist[eptnum] = (struct cfextra *)NULL; + qsort((char *)extlist, (unsigned)eptnum, sizeof (struct cfextra *), + cfentcmp); + return (myerror); +} + +static int +validate(struct cfextra *ext, int argc, char *argv[]) +{ + char *ret, *pt; + int n, allspec, is_a_link; + struct cfent *ept; + + ept = &(ext->cf_ent); + + /* initialize cfent structure */ + ept->pinfo = NULL; + (void) gpkgmapvfp(ept, (VFP_T *)NULL); /* This just clears stuff. */ + + n = allspec = 0; + if (classname) + (void) strncpy(ept->pkg_class, classname, CLSSIZ); + + if (argv[n] == NULL || *(argv[n]) == '\000') { + progerr(gettext(ERR_NULLPATH)); + return (1); + } + + /* + * It would be a good idea to figure out how to get much of + * this done using facilities in procmap.c - JST + */ + if (pt = strchr(argv[n], '=')) { + *pt = '\0'; /* cut off pathname at the = sign */ + is_a_link = 1; + } else + is_a_link = 0; + + if (RELATIVE(argv[n])) { + progerr(gettext(ERR_RELPATH), + (argv[n] == NULL) ? "unknown" : argv[n]); + return (1); + } + + /* get the pathnames */ + if (eval_path(&(ext->server_path), &(ext->client_path), + &(ext->map_path), argv[n++]) == 0) + return (1); + + ept->path = ext->client_path; + + /* This isn't likely to happen; but, better safe than sorry. */ + if (RELATIVE(ept->path)) { + progerr(gettext(ERR_RELPATH), ept->path); + return (1); + } + + if (is_a_link) { + /* links specifications should be handled right here */ + ept->ftype = ((n >= argc) ? 'l' : argv[n++][0]); + + /* If nothing follows the '=', it's invalid */ + if (!pt[1]) { + progerr(gettext(ERR_LINK), ept->path); + return (1); + } + + /* Test for an argument after the link. */ + if (argc != n) { + progerr(gettext(ERR_LINKARGS), ept->path); + return (1); + } + + /* + * If it's a link but it's neither hard nor symbolic then + * it's bad. + */ + if (!strchr("sl", ept->ftype)) { + progerr(gettext(ERR_LINKFTYPE), ept->ftype, ept->path); + return (1); + } + + ext->server_local = pathdup(pt+1); + ext->client_local = ext->server_local; + + ept->ainfo.local = ext->client_local; + + return (0); + } else if (n >= argc) { + /* we are expecting to change object's contents */ + return (0); + } + + ept->ftype = argv[n++][0]; + if (strchr("sl", ept->ftype)) { + progerr(gettext(ERR_LINK), ept->path); + return (1); + } else if (!strchr("?fvedxcbp", ept->ftype)) { + progerr(gettext(ERR_FTYPE), ept->ftype, ept->path); + return (1); + } + + if (ept->ftype == 'b' || ept->ftype == 'c') { + if (n < argc) { + ept->ainfo.major = strtol(argv[n++], &ret, 0); + if (ret && *ret) { + progerr(gettext(ERR_MAJOR), argv[n-1], + ept->path); + return (1); + } + } + if (n < argc) { + ept->ainfo.minor = strtol(argv[n++], &ret, 0); + if (ret && *ret) { + progerr(gettext(ERR_MINOR), argv[n-1], + ept->path); + return (1); + } + allspec++; + } + } + + allspec = 0; + if (n < argc) { + ept->ainfo.mode = strtol(argv[n++], &ret, 8); + if (ret && *ret) { + progerr(gettext(ERR_MODE), argv[n-1], ept->path); + return (1); + } + } + if (n < argc) + (void) strncpy(ept->ainfo.owner, argv[n++], ATRSIZ); + if (n < argc) { + (void) strncpy(ept->ainfo.group, argv[n++], ATRSIZ); + allspec++; + } + if (strchr("dxbcp", ept->ftype) && !allspec) { + progerr(gettext(ERR_ARGC), ept->path); + progerr(gettext(ERR_SPECALL), ept->ftype); + return (1); + } + if (n < argc) { + progerr(gettext(ERR_ARGC), ept->path); + return (1); + } + return (0); +} + +int +cfentcmp(const void *p1, const void *p2) +{ + struct cfextra *ext1 = *((struct cfextra **)p1); + struct cfextra *ext2 = *((struct cfextra **)p2); + + return (strcmp(ext1->cf_ent.path, ext2->cf_ent.path)); +} + +/* + * If the path at argv[0] has the value of + * PKG_INSTALL_ROOT prepended, remove it + */ +static void +checkPaths(char *argv[]) +{ + char *root; + int rootLen; + + /* + * Note- No local copy of argv is needed since this + * function is guaranteed to replace argv with a subset of + * the original argv. + */ + + /* We only want to canonize the path if it contains multiple '/'s */ + + canonize_slashes(argv[0]); + + if ((root = get_inst_root()) == NULL) + return; + if (strcmp(root, "/") != 0) { + rootLen = strlen(root); + if (strncmp(argv[0], root, rootLen) == 0) { + argv[0] += rootLen; + } + } +} diff --git a/usr/src/cmd/svr4pkg/installf/installf.h b/usr/src/cmd/svr4pkg/installf/installf.h new file mode 100644 index 0000000000..6d473aa3af --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/installf.h @@ -0,0 +1,57 @@ +/* + * 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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _INSTALLF_H +#define _INSTALLF_H + + +/* + * Block comment that describes the contents of this file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <cfext.h> + +extern struct cfextra **extlist; +extern int eptnum; +extern int warnflag; +extern char *classname; + +extern int cfentcmp(const void *, const void *); +extern void quit(int); +extern void usage(void); +extern void removef(int, char *[]); +extern int installf(int, char *[]); +extern int dofinal(VFP_T *, VFP_T *, int, char *, char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _INSTALLF_H */ 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); +} diff --git a/usr/src/cmd/svr4pkg/installf/removef.c b/usr/src/cmd/svr4pkg/installf/removef.c new file mode 100644 index 0000000000..6b7f8bdead --- /dev/null +++ b/usr/src/cmd/svr4pkg/installf/removef.c @@ -0,0 +1,127 @@ +/* + * 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 2008 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 <errno.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <locale.h> +#include <libintl.h> +#include <pkglib.h> +#include <install.h> +#include <libinst.h> +#include <libadm.h> +#include "installf.h" + +void +removef(int argc, char *argv[]) +{ + struct cfextra *new; + char buf[PATH_MAX]; + char *path; + int flag; + int len; + int max_eptnum; + + flag = strcmp(argv[0], "-") == 0; + + eptnum = 0; + max_eptnum = 64; /* starting size of array */ + extlist = malloc(max_eptnum * sizeof (struct cfextra *)); + + for (;;) { + if (flag) { + if (fgets(buf, PATH_MAX, stdin) == NULL) + break; + + /* strip trailing new line */ + len = strlen(buf); + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + path = buf; + } else { + if (argc-- <= 0) + break; + path = argv[argc]; + } + + /* + * This strips the install root from the path using + * a questionable algorithm. This should go away as + * we define more precisely the command line syntax + * with our '-R' option. - JST + */ + path = orig_path_ptr(path); + + if (path == NULL) { + logerr(gettext("ERROR: no pathname was provided")); + warnflag++; + continue; + } + + if (*path != '/') { + logerr(gettext( + "WARNING: relative pathname <%s> ignored"), path); + warnflag++; + continue; + } + + new = calloc(1, sizeof (struct cfextra)); + if (new == NULL) { + progerr(strerror(errno)); + quit(99); + } + new->cf_ent.ftype = '-'; + + (void) eval_path(&(new->server_path), &(new->client_path), + &(new->map_path), path); + + new->cf_ent.path = new->client_path; + + extlist[eptnum++] = new; + if (eptnum >= max_eptnum) { + /* array size grows exponentially */ + max_eptnum <<= 1; + extlist = realloc(extlist, + max_eptnum * sizeof (struct cfextra *)); + if (extlist == NULL) { + progerr(strerror(errno)); + quit(99); + } + } + } + extlist[eptnum] = (struct cfextra *)NULL; + + qsort((char *)extlist, + (unsigned)eptnum, sizeof (struct cfextra *), cfentcmp); +} |
