/* * 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 (c) 2017 Peter Tribble. */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXPATHS 1024 #define MSG_CHK_STRM "Checking uninstalled stream format package " \ "<%s> from <%s>\n" #define MSG_CHK_DIR "Checking uninstalled directory format package " \ "<%s> from <%s>\n" #define MSG_NOTROOT "NOTE: \"root\" permission may be required to " \ "validate all objects in the client filesystem." #define MSG_CONT "Continuing." #define WRN_F_SPOOL "WARNING: %s is spooled. Ignoring \"f\" argument" #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_IOPEN "unable to open input file <%s>" #define ERR_IEMPTY "no pathnames in file specified by -i option" #define ERR_POPTION "no pathname included with -p option" #define ERR_PARTIAL_POPTION "no pathname included with -P option" #define ERR_MAXPATHS "too many pathnames in option list (limit is %d)" #define ERR_NOTROOT "You must be \"root\" for \"%s -f\" to" \ "execute properly." #define ERR_SEL_PKG "No packages selected for verification." #define ERR_CAT_LNGTH "The category argument exceeds the SVr4 ABI\n" \ " defined maximum supported length of 16 characters." #define ERR_CAT_FND "Category argument <%s> cannot be found." #define ERR_CAT_INV "Category argument <%s> is invalid." #define ERR_TOO_MANY "too many pathnames in list, limit is %d" #define ERR_PATHS_INVALID "Pathnames in %s are not valid." #define ERR_MKDIR "unable to make directory <%s>" #define ERR_USAGE "usage:\n" \ "\t%s [-l|vqacnxf] [-R rootdir] [-p path[, ...] | " \ "-P path[, ...]]\n" \ "\t\t[-i file] [options]\n" \ "\t%s -d device [-f][-l|v] [-p path[, ...] | " \ "-P path[, ...]]\n" \ "\t\t[-V ...] [-M] [-i file] [-Y category[, ...] | " \ "pkginst [...]]\n" \ "\twhere options may include ONE of the " \ "following:\n " \ "\t\t-m pkgmap [-e envfile]\n" \ "\t\tpkginst [...]\n" \ "\t\t-Y category[, ...]\n" #define LINK 1 char **pkg = NULL; int pkgcnt = 0; char *basedir; char *pathlist[MAXPATHS], *ppathlist[MAXPATHS], pkgspool[PATH_MAX]; short used[MAXPATHS]; short npaths; struct cfent **eptlist; int aflag = (-1); int cflag = (-1); int vflag = 0; int nflag = 0; int lflag = 0; int Lflag = 0; int fflag = 0; int xflag = 0; int qflag = 0; int Rflag = 0; int dflag = 0; char *device; char *uniTmp; static char *mapfile, *spooldir, *tmpdir, *envfile; static int errflg = 0; static int map_client = 1; void quit(int); static void setpathlist(char *); static void usage(void); extern char **environ; extern char *pkgdir; /* checkmap.c */ extern int checkmap(int, int, char *, char *, char *, char *, int); /* scriptvfy.c */ extern int checkscripts(char *inst_dir, int silent); int main(int argc, char *argv[]) { int pkgfmt = 0; /* Makes more sense as a pointer, but */ /* 18N is compromised. */ char file[PATH_MAX+1], *abi_sym_ptr, *vfstab_file = NULL; char *all_pkgs[4] = {"all", NULL}; char **category = NULL; char *catg_arg = NULL; int c; int n = 0; char *prog, *Rvalue = NULL, *dvalue = NULL; int pathtype; /* initialize locale mechanism */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); /* determine program name */ prog = set_prog_name(argv[0]); /* establish installation root directory */ if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { progerr(gettext(ERR_ROOT_SET)); quit(1); } /* check if not ABI compliant mode */ 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; while ((c = getopt(argc, argv, "Y:R:e:p:d:nLli:vaV:Mm:cqxfP:?")) != EOF) { switch (c) { case 'p': pathlist[npaths] = strtok(optarg, " , "); if (pathlist[npaths++] == NULL) { progerr(gettext(ERR_POPTION)); quit(1); } while (pathlist[npaths] = strtok(NULL, " , ")) { if (npaths++ >= MAXPATHS) { progerr(gettext(ERR_MAXPATHS), MAXPATHS); quit(1); } } break; case 'd': dvalue = optarg; dflag = 1; break; case 'n': nflag++; break; 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 'f': if (getuid()) { progerr(gettext(ERR_NOTROOT), prog); quit(1); } fflag++; break; case 'i': setpathlist(optarg); break; case 'v': vflag++; break; case 'l': lflag++; break; case 'L': Lflag++; break; case 'x': if (aflag < 0) aflag = 0; if (cflag < 0) cflag = 0; xflag++; break; case 'q': qflag++; break; case 'a': if (cflag < 0) cflag = 0; aflag = 1; break; case 'c': if (aflag < 0) aflag = 0; cflag = 1; break; case 'e': envfile = optarg; break; case 'm': mapfile = optarg; break; case 'R': Rvalue = optarg; Rflag = 1; break; case 'Y': catg_arg = strdup(optarg); if ((category = get_categories(catg_arg)) == NULL) { progerr(gettext(ERR_CAT_INV), catg_arg); quit(1); } else if (is_not_valid_length(category)) { progerr(gettext(ERR_CAT_LNGTH)); quit(1); } break; case 'P': ppathlist[npaths] = strtok(optarg, " , "); if ((ppathlist[npaths] == NULL) || (ppathlist[npaths][0] == '-')) { progerr(gettext(ERR_PARTIAL_POPTION)); quit(1); } npaths++; while (ppathlist[npaths] = strtok(NULL, " , ")) { if (npaths++ >= MAXPATHS) { progerr(gettext(ERR_MAXPATHS), MAXPATHS); quit(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); } } /* Check for incompatible options */ if (dflag && Rflag) usage(); /* Check for root dir and device dir if set */ if (Rflag) { if (!set_inst_root(Rvalue)) { progerr(gettext(ERR_ROOT_CMD)); quit(1); } } if (dflag) device = flex_device(dvalue, 1); if (lflag || Lflag) { /* we're only supposed to list information */ if ((cflag >= 0) || (aflag >= 0) || qflag || xflag || fflag || nflag || vflag) usage(); } set_PKGpaths(get_inst_root()); if (catg_arg != NULL && device == NULL) { if (argc - optind) { usage(); } pkg = gpkglist(pkgdir, all_pkgs, category); if (pkg == NULL) { progerr(gettext(ERR_CAT_FND), catg_arg); quit(1); } else { for (pkgcnt = 0; pkg[pkgcnt] != NULL; pkgcnt++) ; } } else if (catg_arg != NULL && optind < argc) { usage(); } else { pkg = &argv[optind]; pkgcnt = (argc - optind); } /* read the environment for the pkgserver */ pkgserversetmode(DEFAULTMODE); environ = NULL; /* Sever the parent environment. */ if (vcfile() == 0) { quit(99); } errflg = 0; if (mapfile) { /* check for incompatible options */ if (device || pkgcnt) usage(); put_path_params(); /* Restore what's needed. */ /* send pathtype if partial path */ pathtype = (ppathlist[0] != NULL) ? 1 : 0; if (checkmap(0, (device != NULL), mapfile, envfile, NULL, NULL, pathtype)) errflg++; } else if (device) { /* check for incompatible options */ if ((cflag >= 0) || (aflag >= 0)) usage(); if (qflag || xflag || nflag || envfile) usage(); tmpdir = NULL; if ((spooldir = devattr(device, "pathname")) == NULL) spooldir = device; if (isdir(spooldir)) { tmpdir = spooldir = qstrdup(tmpnam(NULL)); if (fflag) { logerr(gettext(WRN_F_SPOOL), *pkg); fflag = 0; } if (mkdir(spooldir, 0755)) { progerr(gettext(ERR_MKDIR), spooldir); quit(99); } if (n = pkgtrans(device, spooldir, pkg, PT_SILENT)) quit(n); if (catg_arg != NULL) pkg = gpkglist(spooldir, all_pkgs, category); else pkg = gpkglist(spooldir, all_pkgs, NULL); pkgfmt = 0; } else { if (catg_arg != NULL) pkg = gpkglist(spooldir, pkgcnt ? pkg : all_pkgs, category); else pkg = gpkglist(spooldir, pkgcnt ? pkg : all_pkgs, NULL); pkgfmt = 1; } /* * At this point pkg[] is the list of packages to check. They * are in directory format in spooldir. */ if (pkg == NULL) { if (catg_arg != NULL) { progerr(gettext(ERR_CAT_FND), catg_arg); quit(1); } else { progerr(gettext(ERR_SEL_PKG)); quit(1); } } aflag = 0; for (n = 0; pkg[n]; n++) { char locenv[PATH_MAX]; if (pkgfmt) (void) printf( gettext(MSG_CHK_DIR), pkg[n], device); else (void) printf( gettext(MSG_CHK_STRM), pkg[n], device); (void) snprintf(pkgspool, sizeof (pkgspool), "%s/%s", spooldir, pkg[n]); (void) snprintf(file, sizeof (file), "%s/install", pkgspool); /* Here we check the install scripts. */ (void) printf( gettext("## Checking control scripts.\n")); (void) checkscripts(file, 0); /* Verify consistency with the pkgmap. */ (void) printf( gettext("## Checking package objects.\n")); (void) snprintf(file, sizeof (file), "%s/pkgmap", pkgspool); (void) snprintf(locenv, sizeof (locenv), "%s/pkginfo", pkgspool); envfile = locenv; /* * NOTE : checkmap() frees the environ data and * pointer when it's through with them. */ if (checkmap(0, (device != NULL), file, envfile, pkg[n], NULL, 0)) errflg++; (void) printf( gettext("## Checking is complete.\n")); } } else { if (envfile) usage(); put_path_params(); /* Restore what's needed. */ /* * If this is a check of a client of some sort, we'll need to * mount up the client's filesystems. If the caller isn't * root, this may not be possible. */ if (is_an_inst_root()) { if (getuid()) { logerr(gettext(MSG_NOTROOT)); logerr(gettext(MSG_CONT)); } else { if (get_mntinfo(map_client, vfstab_file)) map_client = 0; if (map_client) mount_client(); } } (void) snprintf(file, sizeof (file), "%s/contents", get_PKGADM()); if (ppathlist[0] != NULL) { for (n = 0; ppathlist[n]; n++) { if (checkmap(1, (device != NULL), file, NULL, NULL, ppathlist[n], 1)) errflg++; } } else if (pkg[0] != NULL) { if (checkmap(1, (device != NULL), file, NULL, pkg[0], NULL, 0)) { errflg++; } } else { if (checkmap(1, (device != NULL), file, NULL, NULL, NULL, 0)) { errflg++; } } if (map_client) { unmount_client(); } } quit(errflg ? 1 : 0); /* LINTED: no return */ } static void setpathlist(char *file) { int fd; struct stat st; FILE *fplist; char pathname[PATH_MAX]; /* * This trap laid to catch a mismatch between the declaration above and * the hard-coded constant in the fscanf below */ #if PATH_MAX != 1024 #error "PATH_MAX changed, so we have a bug to fix" #endif if (strcmp(file, "-") == 0) { fplist = stdin; } else { if ((fd = open(file, O_RDONLY)) == -1) { progerr(gettext(ERR_IOPEN), file); quit(1); } if (fstat(fd, &st) == -1) { progerr(gettext(ERR_IOPEN), file); quit(1); } if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode)) { progerr(gettext(ERR_PATHS_INVALID), file); quit(1); } if ((fplist = fdopen(fd, "r")) == NULL) { progerr(gettext(ERR_IOPEN), file); quit(1); } } while (fscanf(fplist, "%1024s", pathname) == 1) { if (*pathname == '\0') { progerr(gettext(ERR_PATHS_INVALID), file); quit(1); } pathlist[npaths] = qstrdup(pathname); if (npaths++ > MAXPATHS) { progerr(gettext(ERR_TOO_MANY), MAXPATHS); quit(1); } } if (npaths == 0) { progerr(gettext(ERR_IEMPTY)); quit(1); } (void) fclose(fplist); } void quit(int n) { /* cleanup any temporary directories */ (void) chdir("/"); if (tmpdir != NULL) { (void) rrmdir(tmpdir); free(tmpdir); tmpdir = NULL; } (void) pkghead(NULL); exit(n); /*NOTREACHED*/ } static void usage(void) { char *prog = get_prog_name(); (void) fprintf(stderr, gettext(ERR_USAGE), prog, prog); quit(1); /*NOTREACHED*/ }