/* * This is a special fast verify which basically checks the attributes * and then, if all is OK, checks the size and mod time using the same * stat and statvfs structures. */ int fverify(int fix, char *ftype, char *path, struct ainfo *ainfo, struct cinfo *cinfo) { int retval; /* return success if attribute checks are disabled */ if (get_disable_attribute_check()) { return (0); } if ((retval = averify(fix, ftype, path, ainfo)) == 0) { if (*ftype == 'f' || *ftype == 'i') { if (cinfo->size != status.st_size) { reperr(pkg_gt(WRN_QV_SIZE), path); retval = VE_CONT; } /* pcfs doesn't support modification times */ if (strcmp(vfsstatus.f_basetype, "pcfs") != 0) { if (cinfo->modtime != status.st_mtime) { reperr(pkg_gt(WRN_QV_MTIME), path); retval = VE_CONT; } } } } return (retval); }
/* * This is the function that cleans up the installation of this class. * This is where hard links get put in since the stuff they're linking * probably exists by now. */ static void endofclass(struct cfextra **extlist, int myclass, int ckflag, VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp) { char *temppath; char *pspool_loc; char *relocpath = (char *)NULL; char scrpt_dst[PATH_MAX]; int flag; int idx; int n; struct cfent *ept; /* entry from the internal list */ struct cfextra entry; /* entry from the package database */ struct mergstat *mstat; /* merge status */ struct pinfo *pinfo; /* open the package database (contents) file */ if (!ocfile(a_cfVfp, a_cfTmpVfp, pkgmap_blks)) { quit(99); } echo(MSG_VERIFYING_CLASS, cl_nam(myclass)); for (idx = 0; /* void */; idx++) { /* find next package object in this class */ while (extlist[idx]) { if ((extlist[idx]->cf_ent.ftype != 'i') && extlist[idx]->cf_ent.pkg_class_idx == myclass) { break; } idx++; } if (extlist[idx] == NULL) { /* finish copying contents file and exit loop */ (void) srchcfile(&(entry.cf_ent), NULL, *a_cfVfp, *a_cfTmpVfp); break; } ept = &(extlist[idx]->cf_ent); mstat = &(extlist[idx]->mstat); temppath = extlist[idx] ? extlist[idx]->client_path : NULL; /* * At this point the only difference between the entry * in the contents file and the entry in extlist[] is * that the status indicator contains CONFIRM_CONT. * So for the new DB we use this knowledge and just * verify everything in accordance with extlist without * trying to retrieve the entry from the DB. */ n = srchcfile(&(entry.cf_ent), (ept ? temppath : NULL), *a_cfVfp, *a_cfTmpVfp); if (n == 0) { break; } else if (n < 0) { char *errstr = getErrstr(); progerr(ERR_CFBAD); logerr(gettext("pathname=%s\n"), entry.cf_ent.path && *entry.cf_ent.path ? entry.cf_ent.path : "Unknown"); logerr(gettext("problem=%s\n"), (errstr && *errstr) ? errstr : "Unknown"); quit(99); } else if (n != 1) { /* * Check if path should be in the package * database. */ if ((mstat->shared && nocnflct)) { continue; } progerr(ERR_CFMISSING, ept->path); quit(99); } /* * If merge was not appropriate for this object, now is the * time to choose one or the other. */ if (mstat->denied) { /* * If installation was denied AFTER the package * database was updated, skip this. We've already * announced the discrepancy and the verifications * that follow will make faulty decisions based on * the ftype, which may not be correct. */ progerr(ERR_COULD_NOT_INSTALL, ept->path); warnflag++; } else { if (mstat->replace) /* * This replaces the old entry with the new * one. This should never happen in the new * DB since the entries are already identical. */ repl_cfent(ept, &(entry.cf_ent)); /* * Validate this entry and change the status flag in * the package database. */ if (ept->ftype == RM_RDY) { (void) eptstat(&(entry.cf_ent), pkginst, STAT_NEXT); } else { /* check the hard link now. */ if (ept->ftype == 'l') { if (averify(0, &ept->ftype, ept->path, &ept->ainfo)) { echo(MSG_HRDLINK, ept->path); mstat->attrchg++; } } /* * Don't install or verify objects for * remote, read-only filesystems. We need * only flag them as shared from some server. * Otherwise, ok to do final check. */ if (is_remote_fs(ept->path, &(extlist[idx]->fsys_value)) && !is_fs_writeable(ept->path, &(extlist[idx]->fsys_value))) { flag = -1; } else { boolean_t inheritedFlag; inheritedFlag = z_path_is_inherited(ept->path, ept->ftype, get_inst_root()); flag = finalck(ept, mstat->attrchg, (ckflag ? mstat->contchg : (-1)), inheritedFlag); } pinfo = entry.cf_ent.pinfo; /* Find this package in the list. */ while (pinfo) { if (strcmp(pkginst, pinfo->pkg) == 0) { break; } pinfo = pinfo->next; } /* * If this package owns this file, then store * it in the database with the appropriate * status. Need to check pinfo in case it * points to NULL which could happen if * pinfo->next = NULL above. */ if (pinfo) { if (flag < 0 || is_served(ept->path, &(extlist[idx]->fsys_value))) { /* * This is provided to * clients by a server. */ pinfo->status = SERVED_FILE; } else { /* * It's either there or it's * not. */ pinfo->status = (flag ? NOT_FND : ENTRY_OK); } } } } /* * If not installing from a partially spooled package, the * "save/pspool" area, and the file contents can be * changed (type is 'e' or 'v'), and the class IS "none": * copy the installed volatile file into the appropriate * location in the packages destination "save/pspool" area. */ if ((!is_partial_inst()) && ((ept->ftype == 'e') || (ept->ftype == 'v')) && (strcmp(ept->pkg_class, "none") == 0)) { if (absolutepath(extlist[idx]->map_path) == B_TRUE && parametricpath(extlist[idx]->cf_ent.ainfo.local, &relocpath) == B_FALSE) { pspool_loc = ROOT; } else { pspool_loc = RELOC; } n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s", saveSpoolInstallDir, pspool_loc, relocpath ? relocpath : extlist[idx]->map_path); if (n >= PATH_MAX) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, extlist[idx]->map_path); quit(99); } /* copy, preserve source file mode */ if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) { warnflag++; } } /* * Now insert this potentially changed package database * entry. */ if (entry.cf_ent.npkgs) { if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) { quit(99); } } } n = swapcfile(a_cfVfp, a_cfTmpVfp, pkginst, dbchg); if (n == RESULT_WRN) { warnflag++; } else if (n == RESULT_ERR) { quit(99); } }
static int domerg(struct cfextra **extlist, int part, int nparts, int myclass, char **srcp, char **dstp, char **r_updated, char **r_skipped, char **r_anyPathLocal) { boolean_t stateFlag = B_FALSE; int i; int msg_ugid; static int maxvol = 0; static int svindx = 0; static int svpart = 0; struct cfent *ept = (struct cfent *)NULL; struct mergstat *mstat = (struct mergstat *)NULL; /* reset returned path pointers */ *dstp = (char *)NULL; *srcp = (char *)NULL; /* set to start or continue based on which part being processed */ if (part != 0) { maxvol = 0; svindx = 0; svpart = part; } else { i = svindx; part = svpart; } /* * This goes through the pkgmap entries one by one testing them * for inclusion in the package database as well as for validity * against existing files. */ for (i = svindx; extlist[i]; i++) { ept = &(extlist[i]->cf_ent); mstat = &(extlist[i]->mstat); /* * as paths are processed, if the "anyPathLocal" flag has not * been set, if the object is not of type 'i' (package script), * check to see if the object is in an area inherited from the * global zone - if not, set "anyPathLocal" to the path found, * indicating that at least one path is in an area that is not * inherited from the global zone. */ if ((r_anyPathLocal != (char **)NULL) && (*r_anyPathLocal == (char *)NULL) && (ept->ftype != 'i') && (z_path_is_inherited(ept->path, ept->ftype, get_inst_root()) == B_FALSE)) { echoDebug(DBG_INSTVOL_OBJ_LOCAL, ept->path); *r_anyPathLocal = ept->path; } /* if this isn't the class of current interest, skip it */ if (myclass != ept->pkg_class_idx) { continue; } /* if the class is invalid, announce it & exit */ if (ept->pkg_class_idx == -1) { progerr(ERR_CLIDX, ept->pkg_class_idx, (ept->path && *ept->path) ? ept->path : "unknown"); logerr(gettext("pathname=%s\n"), (ept->path && *ept->path) ? ept->path : "unknown"); logerr(gettext("class=<%s>\n"), (ept->pkg_class && *ept->pkg_class) ? ept->pkg_class : "Unknown"); logerr(gettext("CLASSES=<%s>\n"), getenv("CLASSES") ? getenv("CLASSES") : "Not Set"); quit(99); } /* * Next check to see if we are going to try to delete a * populated directory in some distressing way. */ if (mstat->dir2nondir) if (dir_is_populated(ept->path)) { logerr(WRN_INSTVOL_NOTDIR, ept->path); warnflag++; mstat->denied = 1; /* install denied! */ continue; } else { /* Replace is OK. */ /* * Remove this directory, so it won't * interfere with creation of the new object. */ if (rmdir(ept->path)) { /* * If it didn't work, there's nothing * we can do. To continue would * likely corrupt the filesystem * which is unacceptable. */ progerr(ERR_RMDIR, ept->path); quit(99); } repl_permitted = 1; /* flag it */ } /* adjust the max volume number appropriately */ if (ept->volno > maxvol) { maxvol = ept->volno; } /* if this part goes into another volume, skip it */ if (part != ept->volno) { continue; } /* * If it's a conflicting file and it's not supposed to be * installed, note it and skip. */ if (nocnflct && mstat->shared && ept->ftype != 'e') { if (mstat->contchg || mstat->attrchg) { echo(MSG_SHIGN, ept->path); } continue; } /* * If we want to set uid or gid but user says no, note it. * Remember that the actual mode bits in the structure have * already been adjusted and the mstat flag is telling us * about the original mode. */ if (nosetuid && (mstat->setuid || mstat->setgid)) { msg_ugid = 1; /* don't repeat attribute message. */ if (is_fs_writeable(ept->path, &(extlist[i]->fsys_value))) { if (!(mstat->contchg) && mstat->attrchg) { echo(MSG_UGMOD, ept->path); } else { echo(MSG_UGID, ept->path); } } } else { msg_ugid = 0; } switch (ept->ftype) { case 'l': /* hard link */ /* links treated as object "update/skip" */ stateFlag = B_TRUE; continue; /* defer to final proc */ case 's': /* for symlink, verify without fix first */ /* links treated as object "update/skip" */ stateFlag = B_TRUE; /* Do this only for default verify */ if (cl_dvfy(myclass) == DEFAULT) { if (averify(0, &ept->ftype, ept->path, &ept->ainfo)) echo(MSG_SLINK, ept->path); } /*FALLTHRU*/ case 'd': /* directory */ case 'x': /* exclusive directory */ case 'c': /* character special device */ case 'b': /* block special device */ case 'p': /* named pipe */ /* these NOT treated as object "update/skip" */ stateFlag = B_FALSE; /* * If we can't get to it for legitimate reasons, * don't try to verify it. */ if ((z_path_is_inherited(ept->path, ept->ftype, get_inst_root())) || is_remote_fs(ept->path, &(extlist[i]->fsys_value)) && !is_fs_writeable(ept->path, &(extlist[i]->fsys_value))) { mstat->attrchg = 0; mstat->contchg = 0; break; } if (averify(1, &ept->ftype, ept->path, &ept->ainfo) == 0) { mstat->contchg = mstat->attrchg = 0; } else { progerr(ERR_CREATE_PKGOBJ, ept->path); logerr(getErrbufAddr()); warnflag++; } break; case 'i': /* information file */ /* not treated as object "update/skip" */ stateFlag = B_FALSE; break; default: /* all files treated as object "update/skip" */ stateFlag = B_TRUE; break; } /* * Both contchg and shared flags have to be taken into * account. contchg is set if the file is already present * in the package database, if it does not exist or if it * exists and is modified. * The shared flag is set when 'e' or 'v' file is not * present in the package database, exists and is not * modified. It also has to be checked here. * Shared flag is also set when file is present in package * database and owned by more than one package, but for * this case contchg has already been set. */ if (mstat->contchg || (mstat->shared && ((ept->ftype == 'e') || (ept->ftype == 'v')))) { *dstp = ept->path; if ((ept->ftype == 'f') || (ept->ftype == 'e') || (ept->ftype == 'v')) { *srcp = ept->ainfo.local; if (is_partial_inst() != 0) { if (*srcp[0] == '~') { /* translate source pathname */ *srcp = srcpath(instdir, extlist[i]->map_path, part, nparts); } else { *srcp = extlist[i]->map_path; } } else { if (*srcp[0] == '~') { /* translate source pathname */ *srcp = srcpath(instdir, &(ept->ainfo.local[1]), part, nparts); } } echoDebug(DBG_DOMERG_NO_SUCH_FILE, ept->ftype, cl_nam(ept->pkg_class_idx), ept->path); } else { /* * At this point, we're returning a non-file * that couldn't be created in the standard * way. If it refers to a filesystem that is * not writeable by us, don't waste the * calling process's time. */ if (!is_fs_writeable(ept->path, &(extlist[i]->fsys_value))) { echoDebug(DBG_DOMERG_NOT_WRITABLE, ept->ftype, cl_nam(ept->pkg_class_idx), ept->path); continue; } *srcp = NULL; echoDebug(DBG_DOMERG_NOT_THERE, ept->ftype, cl_nam(ept->pkg_class_idx), ept->path); } svindx = i+1; backup(*dstp, 1); return (i); } if (mstat->attrchg) { backup(ept->path, 0); if (!msg_ugid) echo(MSG_ATTRIB, ept->path); /* fix the attributes now for robustness sake */ if (averify(1, &ept->ftype, ept->path, &ept->ainfo) == 0) { mstat->attrchg = 0; } } /* * package object exists, or does not need updating: if the path * is in an area inherited from the global zone, then treat * the object as if it were "skipped" - if the path is not in an * area inherited from the global zone, then treat the object as * if it were "updated" */ /* LINTED warning: statement has no consequent: if */ if ((stateFlag == B_FALSE) || (ept == (struct cfent *)NULL)) { /* * the object in question is a directory or special * file - the fact that this type of object already * exists or does not need updating must not trigger * the object updated/object skipped indication - * that would cause class action scripts to be run * when installing a new non-global zone - that action * must only be done when a file object that is in * an area inherited from the global zone is present. */ } else if (z_path_is_inherited(ept->path, ept->ftype, get_inst_root()) == B_TRUE) { if (r_skipped != (char **)NULL) { if (*r_skipped == (char *)NULL) { echoDebug(DBG_INSTVOL_OBJ_SKIPPED, ept->path); *r_skipped = ept->path; } } } else { if (r_updated != (char **)NULL) { if (*r_updated == (char *)NULL) { echoDebug(DBG_INSTVOL_OBJ_UPDATED, ept->path); } *r_updated = ept->path; } } } if (maxvol == part) { eocflag++; /* endofclass */ } return (DMRG_DONE); /* no remaining entries on this volume */ }
static void outvol(struct cfent **eptlist, int eptnum, int part, int nparts) { FILE *fp; char *svpt, *path, temp[PATH_MAX]; int i; if (nparts > 1) (void) fprintf(stderr, gettext(" -- part %2d:\n"), part); if (part == 1) { /* re-write pkgmap, but exclude local pathnames */ (void) snprintf(temp, sizeof (temp), "%s/pkgmap", pkgloc); if ((fp = fopen(temp, "w")) == NULL) { progerr(gettext(ERR_TEMP), errno); quit(99); } (void) fprintf(fp, ": %d %ld\n", nparts, limit); for (i = 0; eptlist[i]; i++) { svpt = eptlist[i]->ainfo.local; if (!strchr("sl", eptlist[i]->ftype)) eptlist[i]->ainfo.local = NULL; if (ppkgmap(eptlist[i], fp)) { progerr(gettext(ERR_TEMP), errno); quit(99); } eptlist[i]->ainfo.local = svpt; } (void) fclose(fp); (void) fprintf(stderr, "%s\n", temp); } (void) snprintf(temp, sizeof (temp), "%s/pkginfo", pkgloc); if (copyf(svept->ainfo.local, temp, svept->cinfo.modtime)) quit(1); (void) fprintf(stderr, "%s\n", temp); for (i = 0; i < eptnum; i++) { if (eptlist[i]->volno != part) continue; if (strchr("dxslcbp", eptlist[i]->ftype)) continue; if (eptlist[i]->ftype == 'i') { if (eptlist[i] == svept) continue; /* don't copy pkginfo file */ (void) snprintf(temp, sizeof (temp), "%s/install/%s", pkgloc, eptlist[i]->path); path = temp; } else path = srcpath(pkgloc, eptlist[i]->path, part, nparts); if (sflag) { if (slinkf(eptlist[i]->ainfo.local, path)) quit(1); } else if (copyf(eptlist[i]->ainfo.local, path, eptlist[i]->cinfo.modtime)) { quit(1); } /* * If the package file attributes can be sync'd up with * the pkgmap, we fix the attributes here. */ if (*(eptlist[i]->ainfo.owner) != '$' && *(eptlist[i]->ainfo.group) != '$' && getuid() == 0) { /* Clear dangerous bits. */ eptlist[i]->ainfo.mode= (eptlist[i]->ainfo.mode & S_IAMB); /* * Make sure it can be read by the world and written * by root. */ eptlist[i]->ainfo.mode |= 0644; if (!strchr("in", eptlist[i]->ftype)) { /* Set the safe attributes. */ averify(1, &(eptlist[i]->ftype), path, &(eptlist[i]->ainfo)); } } (void) fprintf(stderr, "%s\n", path); } }