static int collectError(int *r_numZones, char **r_zoneNames, char *a_packageName, depckl_t *a_dck, int a_depIndex, depckErrorRecord_t *a_eir, int a_errIndex) { char msgbuf[4096]; char *zn = *r_zoneNames; if (a_dck[a_depIndex].ignore_values == (char *)NULL) { if (a_dck[a_depIndex].err_msg == (char **)NULL) { (void) snprintf(msgbuf, sizeof (msgbuf), ERR_DEPENDENCY_REPORT, a_eir->ier_values[a_errIndex], "package", a_packageName, "zone", a_eir->ier_zones[a_errIndex]); } else { /* LINTED variable format specifier to snprintf(); */ (void) snprintf(msgbuf, sizeof (msgbuf), *a_dck[a_depIndex].err_msg, a_eir->ier_values[a_errIndex], "package", a_packageName, "zone", a_eir->ier_zones[a_errIndex]); } if (a_dck[a_depIndex].depcklFunc != NULL) { int err; err = (a_dck[a_depIndex].depcklFunc)(msgbuf, a_packageName); echoDebug(DBG_DEPCHK_COLLECT_ERROR, err, a_packageName, msgbuf); if (err != 0) { return (err); } } else { echoDebug(DBG_DEPCHK_COLLECT_IGNORE, a_packageName, msgbuf); ptext(stderr, "\\n%s", msgbuf); } return (0); } *r_numZones = (*r_numZones)+1; if (zn == (char *)NULL) { zn = strdup(a_eir->ier_zones[a_errIndex]); } else { char *p; int len = strlen(zn)+strlen(a_eir->ier_zones[a_errIndex])+3; p = calloc(1, len); (void) snprintf(p, len, "%s, %s", zn, a_eir->ier_zones[a_errIndex]); free(zn); zn = p; } *r_zoneNames = zn; return (0); }
boolean_t setup_temporary_directory(char **r_dirname, char *a_tmpdir, char *a_suffix) { char *dirname; /* entry assertions */ assert(a_tmpdir != (char *)NULL); /* error if no pointer provided to return temporary name in */ if (r_dirname == (char **)NULL) { errno = EFAULT; /* bad address */ return (B_FALSE); } /* generate temporary directory name */ dirname = tempnam(a_tmpdir, a_suffix); if (dirname == (char *)NULL) { return (B_FALSE); } /* create the temporary directory */ if (mkdir(dirname, 0755) != 0) { return (B_FALSE); } echoDebug(DBG_SETUP_TEMPDIR, dirname); *r_dirname = dirname; return (B_TRUE); }
boolean_t setup_temporary_directory(char **r_dirname, char *a_tmpdir, char *a_suffix) { char *dirname; /* entry assertions */ assert(a_tmpdir != (char *)NULL); /* error if no pointer provided to return temporary name in */ if (r_dirname == (char **)NULL) { errno = EFAULT; /* bad address */ return (B_FALSE); } /* generate temporary directory name */ dirname = malloc(strlen(a_tmpdir) + strlen(a_suffix) + 8); sprintf(dirname, "%s/%sXXXXXX", a_tmpdir, a_suffix); if (close(mkstemp(dirname)) < 0 || unlink(dirname) < 0) { return (B_FALSE); } /* create the temporary directory */ if (mkdir(dirname, 0755) != 0) { return (B_FALSE); } echoDebug(DBG_SETUP_TEMPDIR, dirname); *r_dirname = dirname; return (B_TRUE); }
void merginfo(struct cl_attr **pclass, int install_from_pspool) { DIR *pdirfp; FILE *fp; FILE *pkginfoFP; char path[PATH_MAX]; char cmd[PATH_MAX]; char pkginfoPath[PATH_MAX]; char temp[PATH_MAX]; int i; int nc; int out; /* remove savelog from previous attempts */ (void) unlink(savlog); /* * create path to appropriate pkginfo file for the package that is * already installed - is_spool_create() will be set (!= 0) if the * -t option is presented to pkginstall - the -t option is used to * disable save spool area creation; do not spool any partial package * contents, that is, suppress the creation and population of the * package save spool area (var/sadm/pkg/PKG/save/pspool/PKG). This * option is set only when a non-global zone is being created. */ if (is_spool_create() == 0) { /* * normal package install (not a non-global zone install); * use the standard installed pkginfo file for this package: * --> /var/sadm/pkg/PKGINST/pkginfo * as the source pkginfo file to scan. */ i = snprintf(pkginfoPath, sizeof (pkginfoPath), "%s/var/sadm/pkg/%s/%s", ((get_inst_root()) && (strcmp(get_inst_root(), "/") != 0)) ? get_inst_root() : "", pkginst, PKGINFO); if (i > sizeof (pkginfoPath)) { progerr(ERR_CREATE_PATH_2, ((get_inst_root()) && (strcmp(get_inst_root(), "/") != 0)) ? get_inst_root() : "/", pkginst); quit(1); } } else { /* * non-global zone installation - use the "saved" pspool * pkginfo file in the global zone for this package: * --> /var/sadm/install/PKG/save/pspool/PKG/pkginfo * as the source pkginfo file to scan. */ i = snprintf(pkginfoPath, sizeof (pkginfoPath), "%s/%s", saveSpoolInstallDir, PKGINFO); if (i > sizeof (pkginfoPath)) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, PKGINFO); quit(1); } } i = snprintf(path, PATH_MAX, "%s/%s", pkgloc, PKGINFO); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_2, pkgloc, PKGINFO); quit(1); } /* entry debugging info */ echoDebug(DBG_MERGINFO_ENTRY, instdir ? instdir : "??", ((get_inst_root()) && (strcmp(get_inst_root(), "/") != 0)) ? get_inst_root() : "??", saveSpoolInstallDir ? saveSpoolInstallDir : "??", pkgloc ? pkgloc : "??", is_spool_create(), get_info_basedir() ? get_info_basedir() : "??", pkginfoPath, path); /* * open the pkginfo file: * if the source pkginfo file to check is the same as the merged one * (e.g. /var/sadm/pkg/PKGINST/pkginfo) then do not open the source * pkginfo file to "verify" */ if (strcmp(pkginfoPath, path) == 0) { pkginfoFP = (FILE *)NULL; echoDebug(DBG_MERGINFO_SAME, path); } else { echoDebug(DBG_MERGINFO_DIFFERENT, pkginfoPath, path); pkginfoFP = fopen(pkginfoPath, "r"); if (pkginfoFP == (FILE *)NULL) { echoDebug(ERR_NO_PKG_INFOFILE, pkginst, pkginfoPath, strerror(errno)); } } /* * output packaging environment to create a pkginfo file in pkgloc[] */ if ((fp = fopen(path, "w")) == NULL) { progerr(ERR_CANNOT_OPEN_FOR_WRITING, path, strerror(errno)); quit(99); } /* * output CLASSES attribute */ out = 0; (void) fputs("CLASSES=", fp); if (pclass) { (void) fputs(pclass[0]->name, fp); out++; for (i = 1; pclass[i]; i++) { (void) putc(' ', fp); (void) fputs(pclass[i]->name, fp); out++; } } nc = cl_getn(); for (i = 0; i < nc; i++) { int found = 0; if (pclass) { int j; for (j = 0; pclass[j]; ++j) { if (cl_nam(i) != NULL && strcmp(cl_nam(i), pclass[j]->name) == 0) { found++; break; } } } if (!found) { if (out > 0) { (void) putc(' ', fp); } (void) fputs(cl_nam(i), fp); out++; } } (void) putc('\n', fp); /* * NOTE : BASEDIR below is relative to the machine that * *runs* the package. If there's an install root, this * is actually the CLIENT_BASEDIR wrt the machine * doing the pkgadd'ing here. -- JST */ if (is_a_basedir()) { static char *txs1 = "BASEDIR="; (void) fputs(txs1, fp); (void) fputs(get_info_basedir(), fp); (void) putc('\n', fp); } else { (void) fputs("BASEDIR=/", fp); (void) putc('\n', fp); } /* * output all other environment attributes except those which * are relevant only to install. */ for (i = 0; environ[i] != (char *)NULL; i++) { char *ep = environ[i]; int attrPos = -1; int incr = (ATTRTBL_SIZE >> 1)+1; /* searches possible */ int pos = ATTRTBL_SIZE >> 1; /* start in middle */ NAMELIST_T *pp = (NAMELIST_T *)NULL; /* * find this attribute in the table - accept the attribute if it * is outside of the bounds of the table; otherwise, do a binary * search looking for this attribute. */ if (strncmp(ep, attrTbl[0]._nlName, attrTbl[0]._nlLen) < 0) { /* entry < first entry in attribute table */ echoDebug(DBG_MERGINFO_LESS_THAN, ep, attrTbl[0]._nlName); } else if (strncmp(ep, attrTbl[ATTRTBL_SIZE-1]._nlName, attrTbl[ATTRTBL_SIZE-1]._nlLen) > 0) { /* entry > last entry in attribute table */ echoDebug(DBG_MERGINFO_GREATER_THAN, ep, attrTbl[ATTRTBL_SIZE-1]._nlName); } else { /* first entry < entry < last entry in table: search */ echoDebug(DBG_MERGINFO_SEARCHING, ep, attrTbl[0]._nlName, attrTbl[ATTRTBL_SIZE-1]._nlName); while (incr > 0) { /* while possible to divide */ int r; pp = &attrTbl[pos]; /* compare current attr with this table entry */ r = strncmp(pp->_nlName, ep, pp->_nlLen); /* break out of loop if match */ if (r == 0) { /* save location/break if match found */ attrPos = pos; break; } /* no match search to next/prev half */ incr = incr >> 1; pos += (r < 0) ? incr : -incr; continue; } } /* handle excluded attribute found */ if ((attrPos >= 0) && (pp->_nlFlag == FLAG_EXCLUDE)) { /* attribute is excluded */ echoDebug(DBG_MERGINFO_EXCLUDING, ep); continue; } /* handle fixed attribute found */ if ((pkginfoFP != (FILE *)NULL) && (attrPos >= 0) && (pp->_nlFlag == FLAG_IDENTICAL)) { /* attribute must not change */ char *src = ep+pp->_nlLen; char *trg; char theAttr[PATH_MAX+1]; /* isolate attribute name only without '=' at end */ (void) strncpy(theAttr, pp->_nlName, pp->_nlLen-1); theAttr[pp->_nlLen-1] = '\0'; /* lookup attribute in installed package pkginfo file */ rewind(pkginfoFP); trg = fpkgparam(pkginfoFP, theAttr); echoDebug(DBG_MERGINFO_ATTRCOMP, theAttr, trg ? trg : ""); /* if target not found attribute is being added */ if (trg == (char *)NULL) { progerr(ERR_PKGINFO_ATTR_ADDED, pkginst, ep); quit(1); } /* error if two values are not the same */ if (strcmp(src, trg) != 0) { progerr(ERR_PKGINFO_ATTR_CHANGED, pkginst, theAttr, src, trg); quit(1); } } /* attribute not excluded/has not changed - process */ if ((strncmp(ep, "PKGSAV=", 7) == 0)) { (void) fputs("PKGSAV=", fp); (void) fputs(infoloc, fp); (void) putc('/', fp); (void) fputs(pkginst, fp); (void) fputs("/save\n", fp); continue; } if ((strncmp(ep, "UPDATE=", 7) == 0) && install_from_pspool != 0 && !isPatchUpdate() && !isUpdate()) { continue; } echoDebug(DBG_MERGINFO_FINAL, ep); (void) fputs(ep, fp); (void) putc('\n', fp); } (void) fclose(fp); (void) fclose(pkginfoFP); /* * copy all packaging scripts to appropriate directory */ i = snprintf(path, PATH_MAX, "%s/install", instdir); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_2, instdir, "/install"); quit(1); } if ((pdirfp = opendir(path)) != NULL) { struct dirent *dp; while ((dp = readdir(pdirfp)) != NULL) { if (dp->d_name[0] == '.') continue; i = snprintf(path, PATH_MAX, "%s/install/%s", instdir, dp->d_name); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_3, instdir, "/install/", dp->d_name); quit(1); } i = snprintf(temp, PATH_MAX, "%s/%s", pkgbin, dp->d_name); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_2, pkgbin, dp->d_name); quit(1); } if (cppath(MODE_SRC|DIR_DISPLAY, path, temp, 0644)) { progerr(ERR_CANNOT_COPY, dp->d_name, pkgbin); quit(99); } } (void) closedir(pdirfp); } /* * copy all packaging scripts to the partial spool directory */ if (!is_spool_create()) { /* packages are being spooled to ../save/pspool/.. */ i = snprintf(path, PATH_MAX, "%s/install", instdir); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_2, instdir, "/install"); quit(1); } if (((pdirfp = opendir(path)) != NULL) && !isPatchUpdate()) { struct dirent *dp; while ((dp = readdir(pdirfp)) != NULL) { if (dp->d_name[0] == '.') continue; /* * Don't copy i.none since if it exists it * contains Class Archive Format procedure * for installing archives. Only Directory * Format packages can exist * in a global spooled area. */ if (strcmp(dp->d_name, "i.none") == 0) continue; i = snprintf(path, PATH_MAX, "%s/install/%s", instdir, dp->d_name); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_3, instdir, "/install/", dp->d_name); quit(1); } i = snprintf(temp, PATH_MAX, "%s/install/%s", saveSpoolInstallDir, dp->d_name); if (i > PATH_MAX) { progerr(ERR_CREATE_PATH_3, saveSpoolInstallDir, "/install/", dp->d_name); quit(1); } if (cppath(MODE_SRC, path, temp, 0644)) { progerr(ERR_CANNOT_COPY, path, temp); (void) closedir(pdirfp); quit(99); } } (void) closedir(pdirfp); } /* * Now copy the original pkginfo and pkgmap files from the * installing package to the spooled directory. */ i = snprintf(path, sizeof (path), "%s/%s", instdir, PKGINFO); if (i > sizeof (path)) { progerr(ERR_CREATE_PATH_2, instdir, PKGINFO); quit(1); } i = snprintf(temp, sizeof (temp), "%s/%s", saveSpoolInstallDir, PKGINFO); if (i > sizeof (temp)) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, PKGINFO); quit(1); } if (cppath(MODE_SRC, path, temp, 0644)) { progerr(ERR_CANNOT_COPY, path, temp); quit(99); } /* * Only want to copy the FCS pkgmap if this is not a * patch installation. */ if (!isPatchUpdate()) { i = snprintf(path, sizeof (path), "%s/pkgmap", instdir); if (i > sizeof (path)) { progerr(ERR_CREATE_PATH_2, instdir, "pkgmap"); quit(1); } i = snprintf(temp, sizeof (temp), "%s/pkgmap", saveSpoolInstallDir); if (i > sizeof (path)) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, "pkgmap"); quit(1); } if (cppath(MODE_SRC, path, temp, 0644)) { progerr(ERR_CANNOT_COPY, path, temp); quit(99); } } } /* * If we are installing from a spool directory * copy the save directory from it, it may have * been patched. Duplicate it only if this * installation isn't an update and is not to * an alternate root. */ if (strstr(instdir, "pspool") != NULL) { struct stat status; i = snprintf(path, sizeof (path), "%s/save", instdir); if (i > sizeof (path)) { progerr(ERR_CREATE_PATH_2, instdir, "save"); quit(1); } if ((stat(path, &status) == 0) && (status.st_mode & S_IFDIR) && !isPatchUpdate()) { i = snprintf(cmd, sizeof (cmd), "cp -pr %s/* %s", path, pkgsav); if (i > sizeof (cmd)) { progerr(ERR_SNPRINTF, "cp -pr %s/* %s"); quit(1); } if (system(cmd)) { progerr(ERR_PKGBINCP, path, pkgsav); quit(99); } } } }
void quit(int retcode) { /* disable interrupts */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); /* process return code if not quit(99) */ if (retcode != 99) { if (ckreturnFunc != (ckreturnFunc_t *)NULL) { (ckreturnFunc)(retcode); } if (failflag) { retcode = 1; } else if (warnflag) { retcode = 2; } else if (intrflag) { retcode = 3; } else if (admnflag) { retcode = 4; } else if (nullflag) { retcode = 5; } else { retcode = 0; } if (ireboot) { retcode += 20; } if (doreboot) { retcode += 10; } } if (doreboot || ireboot) { ptext(stderr, gettext(MSG_REBOOT)); } if (pkgdev.mount) { (void) chdir("/"); (void) pkgumount(&pkgdev); } /* if set remove zone temporary directory */ if (zoneTempDir != (char *)NULL) { echoDebug(DBG_REMOVING_ZONE_TMPDIR, zoneTempDir); (void) rrmdir(zoneTempDir); zoneTempDir = (char *)NULL; } /* * issue final exit message depending on number of packages left * to process */ if (npkgs == 1) { echo(MSG_1_PKG_NOT_PROCESSED); } else if (npkgs) { echo(MSG_N_PKGS_NOT_PROCESSED, npkgs); } /* call intf_reloc function if registered */ if (intfRelocFunc != (intfRelocFunc_t *)NULL) { (intfRelocFunc)(); } /* if a zone list exists, unlock all zones */ if (zoneList != (zoneList_t)NULL) { (void) z_unlock_zones(zoneList, ZLOCKS_ALL); } else { (void) z_unlock_this_zone(ZLOCKS_ALL); } /* final exit debugging message */ echoDebug(DBG_EXIT_WITH_CODE, retcode); exit(retcode); /* NOTREACHED */ }
void quit(int retcode) { /* disable interrupts */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); /* process return code if not quit(99) */ if (retcode != 99) { if ((retcode % 10) == 0) { if (failflag) { retcode += 1; } else if (warnflag) { retcode += 2; } } if (ireboot) { retcode = (retcode % 10) + 20; } if (dreboot) { retcode = (retcode % 10) + 10; } } /* if set remove dstream temporary directory */ if (dstreamTempDir != (char *)NULL) { echoDebug(DBG_REMOVING_DSTREAM_TMPDIR, dstreamTempDir); (void) rrmdir(dstreamTempDir); dstreamTempDir = (char *)NULL; } /* If we're in dryrun mode, write out the dryrun file(s). */ if (in_dryrun_mode()) { char exit_msg[200]; set_dr_info(EXITCODE, retcode); if (failflag || warnflag) { set_dr_exitmsg(msgtext); } else { /* LINTED variable format specified */ (void) snprintf(exit_msg, sizeof (exit_msg), qreason(1, retcode, installStarted, includeZonename), (pkginst ? pkginst : "unknown"), zoneName); set_dr_exitmsg(exit_msg); } write_dryrun_file(extlist); ptext(stderr, MSG_DRYRUN_DONE); ptext(stderr, MSG_NOCHANGE); if (tmpdir[0] != NULL) (void) rrmdir(tmpdir); } else { /* fix bug #1082589 that deletes root file */ if (tmpdir[0] != NULL) { (void) rrmdir(tmpdir); } /* send mail to appropriate user list */ mailmsg(retcode); /* display message about this installation */ quitmsg(retcode); } /* * In the event that this quit() was called prior to completion of * the task, do an unlockinst() just in case. */ unlockinst(); /* Unmount anything that's our responsibility. */ (void) unmount_client(); /* * No need to umount device since calling process * was responsible for original mount */ if (!updatingExistingPackage) { if (!installStarted && pkgloc[0]) { /* * install not yet started; if package install * location is defined, remove the package. */ echoDebug(DBG_QUIT_REMOVING_PKGDIR, pkgloc); (void) chdir("/"); if (pkgloc[0]) { (void) rrmdir(pkgloc); } } } else { if (!installStarted) { /* * If we haven't started, but have already done * the <PKGINST>/install directory rename, then * remove the new <PKGINST>/install directory * and rename <PKGINST>/install.save back to * <PKGINST>/install. */ if (pkgloc_sav[0] && !access(pkgloc_sav, F_OK)) { if (pkgloc[0] && !access(pkgloc, F_OK)) (void) rrmdir(pkgloc); if (rename(pkgloc_sav, pkgloc) == -1) { progerr(ERR_PACKAGEBINREN, pkgloc_sav, pkgloc); } } } else { if (pkgloc_sav[0] && !access(pkgloc_sav, F_OK)) { echoDebug(DBG_QUIT_REMOVING_PKGSAV, pkgloc_sav); (void) rrmdir(pkgloc_sav); } } } /* * pkginst can be null if an administration setting doesn't all * the package to be installed. Make sure pkginst exeists before * updating the DB */ if (dparts > 0) ds_skiptoend(pkgdev.cdevice); (void) ds_close(1); /* Free the filesystem table. */ fs_tab_free(); /* Free the package information lists. */ pinfo_free(); /* Free all stragglers. */ bl_free(BL_ALL); (void) pathdup(NULL); /* Free regfiles. */ regfiles_free(); /* final exit debugging message */ echoDebug(DBG_EXIT_WITH_CODE, retcode); exit(retcode); /*NOTREACHED*/ }
boolean_t unpack_package_from_stream(char *a_idsName, char *a_pkginst, char *a_tempDir) { int dparts; char instdir[PATH_MAX]; /* entry assertions */ assert(a_idsName != (char *)NULL); assert(a_pkginst != (char *)NULL); assert(a_tempDir != (char *)NULL); /* entry debug information */ echoDebug(DBG_UNPACKSTRM_ENTRY); echoDebug(DBG_UNPACKSTRM_ARGS, a_pkginst, a_idsName, a_tempDir); /* find the specified package in the datastream */ dparts = ds_findpkg(a_idsName, a_pkginst); if (dparts < 1) { progerr(gettext(ERR_DSARCH), a_pkginst); return (B_FALSE); /*NOTREACHED*/ } /* * read in next part from stream, even if we decide * later that we don't need it */ /* create directory to hold this package instance */ if (snprintf(instdir, sizeof (instdir), "%s/%s", a_tempDir, a_pkginst) >= PATH_MAX) { progerr(ERR_CREATE_PATH_2, a_tempDir, a_pkginst); return (B_FALSE); } switch (fmkdir(instdir, 0755)) { case 0: /* directory created */ break; case 1: /* could not remove existing non-directory node */ progerr(ERR_REMOVE, instdir, strerror(errno)); return (B_FALSE); case 2: /* could not create specified new directory */ default: progerr(ERR_UNPACK_FMKDIR, instdir, strerror(errno)); return (B_FALSE); } /* unpack package instance from stream to dir created */ echoDebug(DBG_UNPACKSTRM_UNPACKING, a_pkginst, a_idsName, instdir); if (chdir(instdir)) { progerr(ERR_CHDIR, instdir); return (B_FALSE); } dparts--; if (ds_next(a_idsName, instdir)) { progerr(ERR_UNPACK_DSREAD, dparts+1, a_idsName, instdir, a_pkginst); return (B_FALSE); } if (chdir(get_PKGADM())) { progerr(gettext(ERR_CHDIR), get_PKGADM()); return (B_FALSE); } return (B_TRUE); }
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 */ }
/* * This is the function that actually installs one volume (usually that's * all there is). Upon entry, the extlist is entirely correct: * * 1. It contains only those files which are to be installed * from all volumes. * 2. The mode bits in the ainfo structure for each file are set * correctly in accordance with administrative defaults. * 3. mstat.setuid/setgid reflect what the status *was* before * pkgdbmerg() processed compliance. */ void instvol(struct cfextra **extlist, char *srcinst, int part, int nparts, VFP_T **a_cfVfp, VFP_T **a_cfTmpVfp, char **r_updated, char **r_skipped, char *a_zoneName) { FILE *listfp; char *updated = (char *)NULL; char *skipped = (char *)NULL; char *anyPathLocal = (char *)NULL; char *relocpath = (char *)NULL; char *dstp; char *listfile; char *srcp; char *pspool_loc; char scrpt_dst[PATH_MAX]; int count; int entryidx; /* array of current package objects */ int n; int nc = 0; int pass; /* pass count through the for loop. */ int tcount; struct cfent *ept; struct cfextra *ext; struct mergstat *mstat; struct reg_files *rfp = NULL; /* * r_updated and r_skipped are optional parameters that can be passed in * by the caller if the caller wants to know if any objects are either * updated or skipped. Do not initialize either r_updated or r_skipped; * the call to instvol could be cumulative and any previous update or * skipped indication must not be disturbed - these flags are only set, * they must never be reset. These flags are "char *" pointers so that * the object that was skipped or updated can be displayed in debugging * output. */ if (part == 1) { pkgvolume(&pkgdev, srcinst, part, nparts); } tcount = 0; nc = cl_getn(); /* * For each class in this volume, install those files. * * NOTE : This loop index may be decremented by code below forcing a * second trip through for the same class. This happens only when a * class is split between an archive and the tree. Examples would be * old WOS packages and the occasional class containing dynamic * libraries which require special treatment. */ if (is_depend_pkginfo_DB() == B_FALSE) { int classidx; /* the current class */ for (classidx = 0; classidx < nc; classidx++) { int pass_relative = 0; int rel_init = 0; eocflag = count = pass = 0; listfp = (FILE *)0; listfile = NULL; /* Now what do we pass to the class action script */ if (cl_pthrel(classidx) == REL_2_CAS) { pass_relative = 1; } for (;;) { if (!tcount++) { /* first file to install */ if (a_zoneName == (char *)NULL) { echo(MSG_INS_N_N, part, nparts); } else { echo(MSG_INS_N_N_LZ, part, nparts, a_zoneName); } } /* * If there's an install class action script and no * list file has been created yet, create that file * and provide the pointer in listfp. */ if (cl_iscript(classidx) && !listfp) { /* create list file */ putparam("TMPDIR", tmpdir); listfile = tempnam(tmpdir, "list"); if ((listfp = fopen(listfile, "w")) == NULL) { progerr(ERR_WTMPFILE, listfile); quit(99); } } /* * The following function goes through the package * object list returning the array index of the next * regular file. If it encounters a directory, * symlink, named pipe or device, it just creates it. */ entryidx = domerg(extlist, (pass++ ? 0 : part), nparts, classidx, &srcp, &dstp, &updated, &skipped, &anyPathLocal); /* Evaluate the return code */ if (entryidx == DMRG_DONE) { /* * Set ept to the first entry in extlist * which is guaranteed to exist so * later checks against ept->ftype are * not compared to NULL. */ ext = extlist[0]; ept = &(ext->cf_ent); break; /* no more entries to process */ } ext = extlist[entryidx]; ept = &(ext->cf_ent); mstat = &(ext->mstat); /* * 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 not * "none": copy the file from the package (in pristine * state with no actions performed) 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(ext->map_path) == B_TRUE && parametricpath(ext->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 : ext->map_path); if (n >= PATH_MAX) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, ext->map_path); quit(99); } /* copy, preserve source file mode */ if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) { warnflag++; } } /* * If this isn't writeable anyway, it's not going * into the list file. Only count it if it's going * into the list file. */ if (is_fs_writeable(ext->cf_ent.path, &(ext->fsys_value))) count++; pkgvolume(&pkgdev, srcinst, part, nparts); /* * If source verification is OK for this class, make * sure the source we're passing to the class action * script is useable. */ if (cl_svfy(classidx) != NOVERIFY) { if (cl_iscript(classidx) || ((ept->ftype == 'e') || (ept->ftype == 'n'))) { if (ck_efile(srcp, ept)) { progerr(ERR_CORRUPT, srcp); logerr(getErrbufAddr()); warnflag++; continue; } } } /* * If there's a class action script for this class, * just collect names in a temporary file * that will be used as the stdin when the * class action script is invoked. */ if ((cl_iscript(classidx)) && ((is_fs_writeable(ept->path, &(ext->fsys_value))))) { if (pass_relative) { if (!rel_init) { (void) fputs(instdir, listfp); (void) putc('\n', listfp); rel_init++; } (void) fputs(ext->map_path, listfp); (void) putc('\n', listfp); } else { (void) fputs(srcp ? srcp : "/dev/null", listfp); (void) putc(' ', listfp); (void) fputs(dstp, listfp); (void) putc('\n', listfp); } /* * Note which entries in extlist are regular * files to be installed via the class action * script. */ if (regfiles_head == NULL) { assert(rfp == NULL); regfiles_head = malloc(sizeof (struct reg_files)); if (regfiles_head == NULL) { progerr(ERR_MEMORY, errno); quit(99); } regfiles_head->next = NULL; regfiles_head->val = entryidx; rfp = regfiles_head; } else { assert(rfp != NULL); rfp->next = malloc(sizeof (struct reg_files)); if (rfp->next == NULL) { progerr(ERR_MEMORY, errno); quit(99); } rfp = rfp->next; rfp->next = NULL; rfp->val = entryidx; } /* * A warning message about unwritable targets * in a class may be appropriate here. */ continue; } /* * 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 * identifier is not "none": copy the file from the * package (in pristine state with no actions performed) * 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(ext->map_path) == B_TRUE && parametricpath(ext->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 : ext->map_path); if (n >= PATH_MAX) { progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir, ext->map_path); quit(99); } /* copy, preserve source file mode */ if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) { warnflag++; } } /* * There are several tests here to determine * how we're going to deal with objects * intended for remote read-only filesystems. * We don't use is_served() because this may be * a server. We're actually interested in if * it's *really* remote and *really* not * writeable. */ n = is_remote_fs(ept->path, &(ext->fsys_value)); if ((n != 0) && !is_fs_writeable(ept->path, &(ext->fsys_value))) { /* * Don't change the file, we can't write * to it anyway. */ mstat->attrchg = 0; mstat->contchg = 0; /* * If it's currently mounted, we can * at least test it for existence. */ if (is_mounted(ept->path, &(ext->fsys_value))) { if (!isfile(NULL, dstp)) { echo(MSG_IS_PRESENT, dstp); } else { echo(WRN_INSTVOL_NONE, dstp); } } else { char *server_host; server_host = get_server_host( ext->fsys_value); /* If not, we're just stuck. */ echo(WRN_INSTVOL_NOVERIFY, dstp, server_host); } continue; } /* echo output destination name */ echo("%s", dstp); /* * if no source then no need to copy/verify */ if (srcp == (char *)NULL) { continue; } /* * If doing a partial installation (creating a * non-global zone), extra steps need to be taken: * * 1) if the file is not type 'e' and not type 'v' and * the class is "none": then the file must already * exist (as a result of the initial non-global zone * installation which caused all non-e/v files to be * copied from the global zone to the non-global * zone). If this is the case, verify that the file * exists and has the correct attributes. * * 2) if the file is not type 'e' and not type 'v' * and the class is NOT "none", *OR* if the file is * type 'e' or type 'v': then check to see if the * file is located in an area inherited from the * global zone. If so, then there is no ability to * change the file since inherited file systems are * "read only" - just verify that the file exists and * verify attributes only if not 'e' or 'v'. */ if (is_partial_inst() != 0) { /* * determine if the destination package is in an * area inherited from the global zone */ n = pkgMatchInherited(srcp, dstp, get_inst_root(), ept->ainfo.mode, ept->cinfo.modtime, ept->ftype, ept->cinfo.cksum); echoDebug(DBG_INSTVOL_PARTIAL_INST, srcp ? srcp : "", dstp ? dstp: "", ((get_inst_root()) && (strcmp(get_inst_root(), "/") != 0)) ? get_inst_root() : "", ept->ainfo.mode, ept->cinfo.modtime, ept->ftype, ept->cinfo.cksum, n); /* * if not type 'e|v' and class 'none', then the * file must already exist. */ if ((ept->ftype != 'e') && (ept->ftype != 'v') && (strcmp(cl_nam(ept->pkg_class_idx), "none") == 0)) { /* * if the file is in a space inherited * from the global zone, and if the * contents or attributes are incorrect, * then generate a warning that the * global zone file contents and/or file * attributes have been modified and * that the modifications are extended * to the non-global zone (inherited * from the global zone). */ if (n == 0) { /* is file changed? */ n = finalck(ept, 1, 1, B_TRUE); /* no - ok - continue */ if (n == 0) { continue; } /* output warning message */ logerr(NOTE_INSTVOL_FINALCKFAIL, pkginst, ext->map_path, a_zoneName, ept->path); continue; } else if (!finalck(ept, 1, 1, B_FALSE)) { /* * non-e/v file of class "none" * not inherited from the global * zone: verify file already * exists:everything checks here */ mstat->attrchg = 0; mstat->contchg = 0; } continue; } /* * non-e/v file with class action script, or * e/v file: if the file is in an area inherited * from the global zone, then no need (or the * ability) to update just accept the file as is */ if (n == B_TRUE) { /* * the object is in an area inherited * from the global zone and the objects * attributes are verified */ mstat->attrchg = 0; mstat->contchg = 0; /* NOTE: package object skipped */ if (skipped == (char *)NULL) { skipped = dstp; echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped); } continue; } } /* * Copy from source media to target path and fix file * mode and permission now in case installation halted. */ if (z_path_is_inherited(dstp, ept->ftype, get_inst_root()) == B_FALSE) { n = cppath(MODE_SET|DIR_DISPLAY, srcp, dstp, ept->ainfo.mode); if (n != 0) { warnflag++; } else if (!finalck(ept, 1, 1, B_FALSE)) { /* * everything checks here */ mstat->attrchg = 0; mstat->contchg = 0; } } /* NOTE: a package object was updated */ if (updated == (char *)NULL) { echoDebug(DBG_INSTVOL_OBJ_UPDATED, dstp); updated = dstp; } } /* * We have now completed processing of all pathnames * associated with this volume and class. */ if (cl_iscript(classidx)) { /* * Execute appropriate class action script * with list of source/destination pathnames * as the input to the script. */ if (chdir(pkgbin)) { progerr(ERR_CHGDIR, pkgbin); quit(99); } if (listfp) { (void) fclose(listfp); } /* * if the object associated with the class action script * is in an area inherited from the global zone, then * there is no need to run the class action script - * assume that anything the script would do has already * been done in the area shared from the global zone. */ /* nothing updated, nothing skipped */ echoDebug(DBG_INSTVOL_CAS_INFO, is_partial_inst(), updated ? updated : "", skipped ? skipped : "", anyPathLocal ? anyPathLocal : ""); if ((is_partial_inst() != 0) && (updated == (char *)NULL) && (anyPathLocal == (char *)NULL)) { /* * installing in non-global zone, and no object * has been updated (installed/verified in non- * inherited area), and no path delivered by the * package is in an area not inherited from the * global zone (all paths delivered are in * areas inherited from the global zone): do not * run the class action script because the only * affected areas are inherited (read only). */ echoDebug(DBG_INSTVOL_NOT_RUNNING_CAS, a_zoneName ? a_zoneName : "?", eocflag ? "ENDOFCLASS" : cl_iscript(classidx), cl_nam(classidx), cl_iscript(classidx)); if ((r_skipped != (char **)NULL) && (*r_skipped == (char *)NULL) && (skipped == (char *)NULL)) { skipped = "postinstall"; echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped); } } else { /* run the class action script */ echoDebug(DBG_INSTVOL_RUNNING_CAS, a_zoneName ? a_zoneName : "?", eocflag ? "ENDOFCLASS" : cl_iscript(classidx), cl_nam(classidx), cl_iscript(classidx)); /* Use ULIMIT if supplied. */ set_ulimit(cl_iscript(classidx), ERR_CASFAIL); if (eocflag) { /* * end of class detected. * Since there are no more volumes which * contain pathnames associated with * this class, execute class action * script with the ENDOFCLASS argument; * we do this even if none of the path * names associated with this class and * volume needed installation to * guarantee the class action script is * executed at least once during package * installation. */ if (pkgverbose) { n = pkgexecl((listfp ? listfile : CAS_STDIN), CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, "-x", cl_iscript(classidx), "ENDOFCLASS", NULL); } else { n = pkgexecl( (listfp ? listfile : CAS_STDIN), CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, cl_iscript(classidx), "ENDOFCLASS", NULL); } ckreturn(n, ERR_CASFAIL); } else if (count) { /* execute class action script */ if (pkgverbose) { n = pkgexecl(listfile, CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, "-x", cl_iscript(classidx), NULL); } else { n = pkgexecl(listfile, CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, cl_iscript(classidx), NULL); } ckreturn(n, ERR_CASFAIL); } /* * Ensure the mod times on disk match those * in the pkgmap. In this case, call cverify * with checksumming disabled, since the only * action that needs to be done is to verify * that the attributes are correct. */ if ((rfp = regfiles_head) != NULL) { while (rfp != NULL) { ept = &(extlist[rfp->val]->cf_ent); cverify(1, &ept->ftype, ept->path, &ept->cinfo, 0); rfp = rfp->next; } regfiles_free(); } clr_ulimit(); if ((r_updated != (char **)NULL) && (*r_updated == (char *)NULL) && (updated == (char *)NULL)) { updated = "postinstall"; echoDebug(DBG_INSTVOL_OBJ_UPDATED, updated); } } if (listfile) { (void) remove(listfile); } } if (eocflag && (!is_partial_inst() || (is_partial_inst() && strcmp(cl_nam(classidx), "none") != 0))) { if (cl_dvfy(classidx) == QKVERIFY && !repl_permitted) { /* * The quick verify just fixes everything. * If it returns 0, all is well. If it * returns 1, then the class installation * was incomplete and we retry on the * stuff that failed in the conventional * way (without a CAS). this is primarily * to accomodate old archives such as are * found in pre-2.5 WOS; but, it is also * used when a critical dynamic library * is not archived with its class. */ if (!fix_attributes(extlist, classidx)) { /* * Reset the CAS pointer. If the * function returns 0 then there * was no script there in the first * place and we'll just have to * call this a miss. */ if (cl_deliscript(classidx)) /* * Decrement classidx for * next pass. */ classidx--; } } else { /* * Finalize merge. This checks to make sure * file attributes are correct and any links * specified are created. */ (void) endofclass(extlist, classidx, (cl_iscript(classidx) ? 0 : 1), a_cfVfp, a_cfTmpVfp); } } } } /* * Instead of creating links back to the GZ files the logic is * to let zdo recreate the files from the GZ then invoke pkgadd to * install the editable files and skip over any 'f'type files. * The commented out block is to create the links which should be * removed once the current code is tested to be correct. */ /* * Go through extlist creating links for 'f'type files * if we're in a global zone. Note that this code lies * here instead of in the main loop to support CAF packages. * In a CAF package the files are installed by the i.none script * and don't exist until all files are done being processed, thus * the additional loop through extlist. */ /* * output appropriate completion message */ if (is_depend_pkginfo_DB() == B_TRUE) { /* updating database only (hollow package) */ if (a_zoneName == (char *)NULL) { echo(MSG_DBUPD_N_N, part, nparts); } else { echo(MSG_DBUPD_N_N_LZ, part, nparts, a_zoneName); } } else if (tcount == 0) { /* updating package (non-hollow package) */ if (a_zoneName == (char *)NULL) { echo(MSG_INST_N_N, part, nparts); } else { echo(MSG_INST_N_N_LZ, part, nparts, a_zoneName); } } /* * if any package objects were updated (not inherited from the * global zone or otherwise already in existence), set the updated * flag as appropriate */ if (updated != (char *)NULL) { echoDebug(DBG_INSTVOL_OBJ_UPDATED, updated); if (r_updated != (char **)NULL) { *r_updated = updated; } } /* * if any package objects were skipped (verified inherited from the * global zone), set the skipped flag as appropriate */ if (skipped != (char *)NULL) { echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped); if (r_skipped != (char **)NULL) { *r_skipped = skipped; } } }
int cppath(int a_ctrl, char *a_srcPath, char *a_dstPath, mode_t a_mode) { char *linknam = (char *)NULL; int dstFd; int len; int srcFd; long status; struct stat srcStatbuf; struct utimbuf times; /* entry debugging info */ echoDebug(DBG_CPPATH_ENTRY, a_ctrl, a_mode, a_srcPath, a_dstPath); /* open source file for reading */ srcFd = open(a_srcPath, O_RDONLY); if (srcFd < 0) { progerr(ERR_OPEN_READ, a_srcPath, errno, strerror(errno)); return (1); } /* obtain file status of source file */ if (fstat(srcFd, &srcStatbuf) != 0) { progerr(ERR_FSTAT, srcFd, a_srcPath, errno, strerror(errno)); (void) close(srcFd); return (1); } /* * Determine the permissions mode for the destination: * - if MODE_SET is specified: * --> use a_mode (do not mask off any portion) * --> If a_mode is unknown (? in the pkgmap), then the file gets * --> installed with the default 0644 mode * - if MODE_SRC is specified: * --> use the mode of the source (srcStatbuf.st_mode) but mask off all * --> non-access mode bits (remove SET?UID bits) * - otherwise: * --> use 0666 */ if (a_ctrl & MODE_SET) { mode_t usemode; usemode = (a_mode ^ BADMODE) ? a_mode : 0644; if (a_mode != usemode && usemode == 0644) { logerr(WRN_DEF_MODE, a_dstPath); a_mode = usemode; } } else if (a_ctrl & MODE_SRC) { a_mode = (srcStatbuf.st_mode & S_IAMB); } else { a_mode = 0666; } /* * Get fd of newly created destination file or, if this * is an overwrite, a temporary file (linknam). */ dstFd = write_file(&linknam, a_ctrl, a_mode, a_dstPath); if (dstFd < 0) { (void) close(srcFd); return (1); } /* * source and target files are open: copy data */ status = copyFile(srcFd, dstFd, a_srcPath, a_dstPath, &srcStatbuf, 0); (void) close(srcFd); (void) close(dstFd); if (status != 0) { progerr(ERR_INPUT, a_srcPath, errno, strerror(errno)); if (linknam) { (void) remove(linknam); } return (1); } /* * If this is an overwrite, rename temp over original */ if ((linknam != (char *)NULL) && (rename(linknam, a_dstPath) != 0)) { FILE *logfp = (FILE *)NULL; char busylog[PATH_MAX]; /* output log message if busy else program error */ if (errno == ETXTBSY) { logerr(MSG_PROCMV, linknam); } else { progerr(ERR_OUTPUT_WRITING, a_dstPath, errno, strerror(errno)); } (void) remove(linknam); /* open the log file and append log entry */ len = snprintf(busylog, sizeof (busylog), "%s/textbusy", get_PKGADM()); if (len > sizeof (busylog)) { progerr(ERR_CREATE_PATH_2, get_PKGADM(), "textbusy"); } else { logfp = fopen(busylog, "a"); if (logfp == NULL) { progerr(ERR_LOG, busylog, errno, strerror(errno)); } else { (void) fprintf(logfp, "%s\n", linknam); (void) fclose(logfp); } } } /* set access/modification times for target */ times.actime = srcStatbuf.st_atime; times.modtime = srcStatbuf.st_mtime; if (utime(a_dstPath, ×) != 0) { progerr(ERR_MODTIM, a_dstPath, errno, strerror(errno)); return (1); } /* success! */ return (0); }
static int write_file(char **r_linknam, int a_ctrl, mode_t a_mode, char *a_file) { int len; int fd = -1; static char loc_link[PATH_MAX]; /* entry debugging */ echoDebug(DBG_WRITEFILE_ENTRY, a_ctrl, a_mode, a_file); /* reset pointer to returned 'temporary file name' */ *r_linknam = (char *)NULL; /* * If we are overwriting an existing file, arrange to replace * it transparently. */ if (access(a_file, F_OK) == 0) { /* * link the file to be copied to a temporary name in case * it is executing or it is being written/used (e.g., a shell * script currently being executed */ if (!RELATIVE(a_file)) { len = snprintf(loc_link, sizeof (loc_link), "%sXXXXXX", a_file); if (len > sizeof (loc_link)) { progerr(ERR_CREATE_PATH_2, a_file, "XXXXXX"); } } else { logerr(WRN_RELATIVE, a_file); len = snprintf(loc_link, sizeof (loc_link), "./%sXXXXXX", a_file); if (len > sizeof (loc_link)) { progerr(ERR_CREATE_PATH_3, "./", a_file, "XXXXXX"); } } /* create and open temporary file */ fd = mkstemp(loc_link); if (fd == -1) { progerr(ERR_MKTEMP, loc_link, errno, strerror(errno)); return (-1); } /* remember name of temporary file */ *r_linknam = loc_link; /* make sure temporary file has correct mode */ if (fchmod(fd, a_mode) < 0) { progerr(ERR_FCHMOD, loc_link, a_mode, errno, strerror(errno)); } return (fd); } /* * We are not overwriting an existing file, create a new one directly. */ fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); if (fd == -1) { if (create_path(a_ctrl, a_file) == 0) { fd = open(a_file, O_WRONLY | O_CREAT | O_TRUNC, a_mode); } } if (fd == -1) { progerr(ERR_OPEN_WRITE, a_file, errno, strerror(errno)); } return (fd); }
int main(int argc, char *argv[]) { FILE *fp; char *abi_comp_ptr; char *abi_sym_ptr; char *p; char *prog_full_name = NULL; char *pt; char *value; char *vfstab_file = NULL; char *zoneName = (char *)NULL; char cmdbin[PATH_MAX]; char param[MAX_PKG_PARAM_LENGTH]; char path[PATH_MAX]; char script[PATH_MAX]; int c; int err; int fd; int i; int map_client = 1; int n; int nodelete = 0; /* do not delete file or run scripts */ int pkgrmremote = 0; /* dont remove remote objects */ struct sigaction nact; struct sigaction oact; PKGserver pkgserver = NULL; VFP_T *tmpfp; /* reset contents of all default paths */ (void) memset(cmdbin, '\0', sizeof (cmdbin)); /* initialize locale environment */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* initialize program name */ prog_full_name = argv[0]; (void) set_prog_name(argv[0]); /* tell spmi zones interface how to access package output functions */ z_set_output_functions(echo, echoDebug, progerr); /* exit if not root */ if (getuid()) { progerr(ERR_NOT_ROOT, get_prog_name()); exit(1); /* NOTREACHED */ } /* Read PKG_INSTALL_ROOT from the environment, if it's there. */ if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) { progerr(ERR_ROOT_SET); exit(1); } pkgserversetmode(DEFAULTMODE); /* parse command line options */ while ((c = getopt(argc, argv, "?Aa:b:FMN:nO:oR:V:vy")) != EOF) { switch (c) { /* * Same as pkgrm: Allow admin to remove package objects from * a shared area from a reference client. */ case 'A': pkgrmremote++; break; /* * Same as pkgrm: Use the installation * administration file, admin, in place of the * default admin file. pkgrm first looks in the * current working directory for the administration * file. If the specified administration file is not * in the current working directory, pkgrm looks in * the /var/sadm/install/admin directory for the * administration file. */ case 'a': admnfile = flex_device(optarg, 0); break; /* * Same as pkgrm: location where package executables * can be found - default is /usr/sadm/install/bin. */ case 'b': if (!path_valid(optarg)) { progerr(ERR_PATH, optarg); exit(1); } if (isdir(optarg) != 0) { char *p = strerror(errno); progerr(ERR_CANNOT_USE_DIR, optarg, p); exit(1); } (void) strlcpy(cmdbin, optarg, sizeof (cmdbin)); break; /* * Same as pkgrm: suppresses the removal of any * files and any class action scripts, and suppresses * the running of any class action scripts. The * package files remain but the package looks like it * is not installed. This is mainly for use by the * upgrade process. */ case 'F': nodelete++; break; /* * Same as pkgrm: Instruct pkgrm not to use the * $root_path/etc/vfstab file for determining the * client's mount points. This option assumes the * mount points are correct on the server and it * behaves consistently with Solaris 2.5 and earlier * releases. */ case 'M': map_client = 0; break; /* * Different from pkgrm: specify program name to use * for messages. */ case 'N': (void) set_prog_name(optarg); break; /* * Same as pkgrm: package removal occurs in * non-interactive mode. Suppress output of the list of * removed files. The default mode is interactive. */ case 'n': nointeract++; (void) echoSetFlag(B_FALSE); break; /* * Almost same as pkgrm: the -O option allows the behavior * of the package tools to be modified. Recognized options: * -> debug * ---> enable debugging output * -> preremovecheck * ---> perform a "pre removal" check of the specified * ---> package - suppress all regular output and cause a * ---> series of one or more "name=value" pair format lines * ---> to be output that describes the "removability" of * ---> the specified package * -> enable-hollow-package-support * --> Enable hollow package support. When specified, for any * --> package that has SUNW_PKG_HOLLOW=true: * --> Do not calculate and verify package size against target * --> Do not run any package procedure or class action scripts * --> Do not create or remove any target directories * --> Do not perform any script locking * --> Do not install or uninstall any components of any package * --> Do not output any status or database update messages */ case 'O': for (p = strtok(optarg, ","); p != (char *)NULL; p = strtok(NULL, ",")) { /* process debug option */ if (strcmp(p, "debug") == 0) { /* set debug flag/enable debug output */ debugFlag = B_TRUE; (void) echoDebugSetFlag(debugFlag); /* debug info on arguments to pkgadd */ for (n = 0; n < argc && argv[n]; n++) { echoDebug(DBG_ARG, n, argv[n]); } continue; } /* process enable-hollow-package-support opt */ if (strcmp(p, "enable-hollow-package-support") == 0) { set_depend_pkginfo_DB(B_TRUE); continue; } /* process preremovecheck option */ if (strcmp(p, "preremovecheck") == 0) { preremoveCheck = B_TRUE; nointeract++; /* -n */ nodelete++; /* -F */ quitSetSilentExit(B_TRUE); continue; } /* process addzonename option */ if (strcmp(p, "addzonename") == 0) { zoneName = z_get_zonename(); quitSetZoneName(zoneName); continue; } /* process parent-zone-name option */ if (strncmp(p, PARENTZONENAME, PARENTZONENAME_LEN) == 0) { parentZoneName = p+PARENTZONENAME_LEN; continue; } /* process parent-zone-type option */ if (strncmp(p, PARENTZONETYPE, PARENTZONETYPE_LEN) == 0) { parentZoneType = p+PARENTZONETYPE_LEN; continue; } if (strncmp(p, PKGSERV_MODE, PKGSERV_MODE_LEN) == 0) { pkgserversetmode(pkgparsemode(p + PKGSERV_MODE_LEN)); continue; } /* option not recognized - issue warning */ progerr(ERR_INVALID_O_OPTION, p); continue; } break; /* * Different from pkgrm: This is an old non-ABI package */ case 'o': script_in = PROC_XSTDIN; break; /* * Same as pkgrm: defines the full path name of a * directory to use as the root_path. All files, * including package system information files, are * relocated to a directory tree starting in the * specified root_path. */ case 'R': if (!set_inst_root(optarg)) { progerr(ERR_ROOT_CMD); exit(1); } break; /* * Same as pkgrm: 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; /* * Same as pkgrm: trace all of the scripts that * get executed by pkgrm, located in the * pkginst/install directory. This option is used for * debugging the procedural and non-procedural * scripts. */ case 'v': pkgverbose++; break; /* * Different from pkgrm: process this package using * old non-ABI symlinks */ case 'y': set_nonABI_symlinks(); 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); } } /* * ******************************************************************** * validate command line options * ******************************************************************** */ (void) echoDebugSetFlag(debugFlag); (void) log_set_verbose(debugFlag); if (z_running_in_global_zone()) { echoDebug(DBG_ENTRY_IN_GZ, prog_full_name); } else { echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(), z_get_zonename()); } /* establish cmdbin path */ if (cmdbin[0] == '\0') { (void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin)); } /* Read the mount table */ if (get_mntinfo(map_client, vfstab_file)) { quit(99); } /* * This function defines the standard /var/... directories used later * to construct the paths to the various databases. */ set_PKGpaths(get_inst_root()); /* * If this is being removed from 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)); } else { pkgrmremote = 0; /* Makes no sense on local host. */ } /* * hook SIGINT and SIGHUP interrupts into quit.c's trap handler */ /* hold SIGINT/SIGHUP interrupts */ (void) sighold(SIGHUP); (void) sighold(SIGINT); /* connect quit.c:trap() to SIGINT */ nact.sa_handler = quitGetTrapHandler(); nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGINT, &nact, &oact); /* connect quit.c:trap() to SIGHUP */ nact.sa_handler = quitGetTrapHandler(); nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGHUP, &nact, &oact); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); pkginst = argv[optind++]; if (optind != argc) { usage(); } /* validate package software database (contents) file */ if (vcfile() == 0) { quit(99); } /* * Acquire the package lock - currently at "remove initialization" */ if (!lockinst(get_prog_name(), pkginst, "remove-initial")) { quit(99); } /* establish temporary directory to use */ tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) { tmpdir = P_tmpdir; } echoDebug(DBG_PKGREMOVE_TMPDIR, tmpdir); /* * Initialize installation admin parameters by reading * the adminfile. */ echoDebug(DBG_PKGREMOVE_ADMINFILE, admnfile ? admnfile : ""); setadminFile(admnfile); /* * about to perform first operation that could be modified by the * preremove check option - if preremove check is selected (that is, * only gathering dependencies), then output a debug message to * indicate that the check is beginning. Also turn echo() output * off and set various other flags. */ if (preremoveCheck == B_TRUE) { (void) echoSetFlag(B_FALSE); echoDebug(DBG_PKGREMOVE_PRERMCHK, pkginst ? pkginst : "", zoneName ? zoneName : "global"); rcksetPreremoveCheck(B_TRUE); rcksetZoneName(zoneName); } (void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s", get_PKGLOC(), pkginst); (void) snprintf(pkgbin, sizeof (pkgbin), "%s/install", pkgloc); (void) snprintf(rlockfile, sizeof (rlockfile), "%s/!R-Lock!", pkgloc); if (chdir(pkgbin)) { progerr(ERR_CHDIR, pkgbin); quit(99); } echo(MSG_PREREMOVE_REMINST, pkginst); /* * if a lock file is present, then a previous attempt to remove this * package may have been unsuccessful. */ if (access(rlockfile, F_OK) == 0) { echo(ERR_UNSUCC); echoDebug(DBG_PKGINSTALL_HAS_LOCKFILE, pkginst, rlockfile, zoneName ? zoneName : "global"); } /* * Process all parameters from the pkginfo file * and place them in the execution environment */ /* Add DB retreival of the pkginfo parameters here */ (void) snprintf(path, sizeof (path), "%s/pkginfo", pkgloc); if ((fp = fopen(path, "r")) == NULL) { progerr(ERR_PKGINFO, path); quit(99); } /* Mount up the client if necessary. */ if (map_client && !mount_client()) { logerr(MSG_MANMOUNT); } /* Get mount point of client */ client_mntdir = getenv("CLIENT_MNTDIR"); getuserlocale(); /* * current environment has been read; clear environment out * so putparam() can be used to populate the new environment * to be passed to any executables/scripts. */ environ = NULL; if (nonABI_symlinks()) { putparam("PKG_NONABI_SYMLINKS", "TRUE"); } /* * read the pkginfo file and fix any PKGSAV path - the correct * install_root will be prepended to the existing path. */ param[0] = '\0'; while (value = fpkgparam(fp, param)) { int validx = 0; char *newvalue; /* strip out any setting of PATH */ if (strcmp(param, "PATH") == 0) { free(value); param[0] = '\0'; continue; } /* if not PKGSAV then write out unchanged */ if (strcmp(param, "PKGSAV") != 0) { putparam(param, value); free(value); param[0] = '\0'; continue; } /* * PKGSAV parameter found - interpret the directory: * If in host:path format or marked with the leading "//", * then there is no client-relative translation - take it * literally later rather than use fixpath(). */ if (strstr(value, ":/")) { /* no modification needed */ validx = 0; } else if (strstr(value, "//") == value) { validx = 1; } else if (is_an_inst_root()) { /* This PKGSAV needs to be made client-relative. */ newvalue = fixpath(value); free(value); value = newvalue; } putparam(param, value+validx); free(value); param[0] = '\0'; } (void) fclose(fp); /* write parent condition information to environment */ putConditionInfo(parentZoneName, parentZoneType); putuserlocale(); /* * Now do all the various setups based on ABI compliance */ /* Read the environment provided by the pkginfo file */ abi_comp_ptr = getenv("NONABI_SCRIPTS"); /* if not ABI compliant set global flag */ abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS"); if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) { set_nonABI_symlinks(); } /* * If pkginfo says it's not compliant then set non_abi_scripts. */ if (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0) { script_in = PROC_XSTDIN; } /* * Since this is a removal, we can tell whether it's absolute or * not from the resident pkginfo file read above. */ if ((err = set_basedirs((getenv("BASEDIR") != NULL), adm.basedir, pkginst, nointeract)) != 0) { quit(err); } /* * See if were are removing a package that only wants to update * the database or only remove files associated with CAS's. We * only check the PKG_HOLLOW_VARIABLE variable if told to do so by * the caller. */ if (is_depend_pkginfo_DB()) { pt = getenv(PKG_HOLLOW_VARIABLE); if ((pt != NULL) && (strncasecmp(pt, "true", 4) == 0)) { echoDebug(DBG_PKGREMOVE_HOLLOW_ENABLED); /* * this is a hollow package and hollow package support * is enabled -- override admin settings to suppress * checks that do not make sense since no scripts will * be executed and no files will be removed. */ setadminSetting("conflict", "nocheck"); setadminSetting("setuid", "nocheck"); setadminSetting("action", "nocheck"); setadminSetting("partial", "nocheck"); setadminSetting("space", "nocheck"); setadminSetting("authentication", "nocheck"); } else { echoDebug(DBG_PKGREMOVE_HOLLOW_DISABLED); set_depend_pkginfo_DB(B_FALSE); } } put_path_params(); /* If client mount point, add it to pkgremove environment */ if (client_mntdir != NULL) { putparam("CLIENT_MNTDIR", client_mntdir); } /* Establish the class list and the class attributes. */ if ((value = getenv("CLASSES")) != NULL) { cl_sets(qstrdup(value)); } else { progerr(ERR_CLASSES, path); quit(99); } /* establish path and tmpdir */ if (cmdbin[0] == '\0') { (void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin)); } (void) snprintf(path, sizeof (path), "%s:%s", DEFPATH, cmdbin); putparam("PATH", path); putparam("TMPDIR", tmpdir); /* * Check ulimit requirement (provided in pkginfo). The purpose of * this limit is to terminate pathological file growth resulting from * file edits in scripts. It does not apply to files in the pkgmap * and it does not apply to any database files manipulated by the * installation service. */ if (value = getenv("ULIMIT")) { if (assign_ulimit(value) == -1) { progerr(ERR_BADULIMIT, value); warnflag++; } putparam("PKG_ULIMIT", "TRUE"); } /* * If only gathering dependencies, check and output status of all * remaining dependencies and exit. */ if (preremoveCheck == B_TRUE) { /* * make sure current runlevel is appropriate */ (void) fprintf(stdout, "rckrunlevel=%d\n", rckrunlevel()); /* * determine if any packaging scripts provided with * this package will execute as a priviledged user */ (void) fprintf(stdout, "rckpriv=%d\n", rckpriv()); /* * verify package dependencies */ (void) fprintf(stdout, "rckdepend=%d\n", rckdepend()); /* * ****** preremove check done - exit ****** */ echoDebug(DBG_PKGREMOVE_PRERMCHK_OK); quit(0); /*NOTREACHED*/ } /* * Not gathering dependencies only, proceed to check dependencies * and continue with the package removal operation. */ /* * make sure current runlevel is appropriate */ n = rckrunlevel(); if (n != 0) { quit(n); /* NOTREACHED */ } /* * determine if any packaging scripts provided with * this package will execute as a priviledged user */ n = rckpriv(); if (n != 0) { quit(n); /* NOTREACHED */ } /* * verify package dependencies */ n = rckdepend(); if (n != 0) { quit(n); /* NOTREACHED */ } /* * ********************************************************************* * the actual removal of the package begins here * ********************************************************************* */ /* * create lockfile to indicate start of removal */ started++; if ((fd = open(rlockfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { progerr(ERR_LOCKFILE, rlockfile); quit(99); } else { (void) close(fd); } if (zoneName == (char *)NULL) { echo(MSG_PKGREMOVE_PROCPKG_GZ); echoDebug(DBG_PKGREMOVE_PROCPKG_GZ, pkginst, rlockfile); } else { echo(MSG_PKGREMOVE_PROCPKG_LZ, zoneName); echoDebug(DBG_PKGREMOVE_PROCPKG_LZ, pkginst, rlockfile, zoneName); } if (delmap(0, pkginst, &pkgserver, &tmpfp) != 0) { progerr(ERR_DB_QUERY, pkginst); quit(99); } /* * Run a preremove script if one is provided by the package. * Don't execute preremove script if only updating the DB. * Don't execute preremove script if files are not being deleted. */ /* update the lock - at the preremove script */ lockupd("preremove"); /* execute preremove script if one is provided */ (void) snprintf(script, sizeof (script), "%s/preremove", pkgbin); if (access(script, F_OK) != 0) { /* no script present */ echoDebug(DBG_PKGREMOVE_POC_NONE, pkginst, zoneName ? zoneName : "global"); } else if (nodelete) { /* not deleting files: skip preremove script */ echoDebug(DBG_PKGREMOVE_POC_NODEL, pkginst, script, zoneName ? zoneName : "global"); } else if (is_depend_pkginfo_DB()) { /* updating db only: skip preremove script */ echoDebug(DBG_PKGREMOVE_POC_DBUPD, pkginst, script, zoneName ? zoneName : "global"); } else { /* script present and ok to run: run the script */ set_ulimit("preremove", ERR_PREREMOVE); if (zoneName == (char *)NULL) { echo(MSG_PKGREMOVE_EXEPOC_GZ); echoDebug(DBG_PKGREMOVE_EXEPOC_GZ, pkginst, script); } else { echo(MSG_PKGREMOVE_EXEPOC_LZ, zoneName); echoDebug(DBG_PKGREMOVE_EXEPOC_LZ, pkginst, script, zoneName); } putparam("PKG_PROC_SCRIPT", "preremove"); if (pkgverbose) { ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, PROC_GRP, SHELL, "-x", script, NULL), ERR_PREREMOVE); } else { ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, PROC_GRP, SHELL, script, NULL), ERR_PREREMOVE); } clr_ulimit(); } /* update the lock - doing removal */ lockupd("remove"); /* * Remove all components belonging to this package. * Don't remove components if only updating the DB. * Don't remove components if files are not being deleted. */ if (nodelete) { echoDebug(DBG_PKGREMOVE_REM_NODEL, pkginst, zoneName ? zoneName : "global"); } else if (is_depend_pkginfo_DB()) { echoDebug(DBG_PKGREMOVE_REM_DBUPD, pkginst, zoneName ? zoneName : "global"); } else { echoDebug(DBG_PKGREMOVE_REM, pkginst, zoneName ? zoneName : "global"); /* * remove package one class at a time */ /* reverse order of classes */ for (i = cl_getn() - 1; i >= 0; i--) { rmclass(cl_nam(i), pkgrmremote, zoneName); } rmclass(NULL, pkgrmremote, zoneName); } z_destroyMountTable(); /* * Execute postremove script, if any * Don't execute postremove script if only updating the DB. * Don't execute postremove script if files are not being deleted. */ /* update the lock - at the postremove script */ lockupd("postremove"); /* execute postremove script if one is provided */ (void) snprintf(script, sizeof (script), "%s/postremove", pkgbin); if (access(script, F_OK) != 0) { /* no script present */ echoDebug(DBG_PKGREMOVE_PIC_NONE, pkginst, zoneName ? zoneName : "global"); } else if (nodelete) { /* not deleting files: skip postremove script */ echoDebug(DBG_PKGREMOVE_PIC_NODEL, pkginst, script, zoneName ? zoneName : "global"); } else if (is_depend_pkginfo_DB()) { /* updating db only: skip postremove script */ echoDebug(DBG_PKGREMOVE_PIC_DBUPD, pkginst, script, zoneName ? zoneName : "global"); } else { /* script present and ok to run: run the script */ set_ulimit("postremove", ERR_POSTREMOVE); if (zoneName == (char *)NULL) { echo(MSG_PKGREMOVE_EXEPIC_GZ); echoDebug(DBG_PKGREMOVE_EXEPIC_GZ, pkginst, script); } else { echo(MSG_PKGREMOVE_EXEPIC_LZ, zoneName); echoDebug(DBG_PKGREMOVE_EXEPIC_LZ, pkginst, script, zoneName); } putparam("PKG_PROC_SCRIPT", "postremove"); putparam("TMPDIR", tmpdir); if (pkgverbose) { ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, PROC_GRP, SHELL, "-x", script, NULL), ERR_POSTREMOVE); } else { ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER, PROC_GRP, SHELL, script, NULL), ERR_POSTREMOVE); } clr_ulimit(); } if (zoneName == (char *)NULL) { echo(MSG_PKGREMOVE_UPDINF_GZ); } else { echo(MSG_PKGREMOVE_UPDINF_LZ, zoneName); } if (delmap(1, pkginst, &pkgserver, &tmpfp) != 0) { progerr(ERR_DB_QUERY, pkginst); quit(99); } if (!warnflag && !failflag) { (void) chdir("/"); if (rrmdir(pkgloc)) warnflag++; } if ((z_running_in_global_zone() == B_TRUE) && (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE)) { boolean_t b; b = pkgRemovePackageFromGzonlyList(get_inst_root(), pkginst); if (b == B_FALSE) { progerr(ERR_PKGREMOVE_GZONLY_REMOVE, pkginst); ckreturn(1, NULL); } } /* release the generic package lock */ (void) unlockinst(); pkgcloseserver(pkgserver); quit(0); /* LINTED: no return */ }
int depchkReportErrors(depckl_t *a_dck) { char *packageName; char *zonenames; char msgbuf[4096]; int err; int i; int numzones = 0; /* entry assertions */ assert(a_dck != (depckl_t *)NULL); /* entry debugging info */ echoDebug(DBG_DEPCHK_ENTRY); zonenames = (char *)NULL; /* go through dependency table, collect, collapse, report errors */ for (i = 0; a_dck[i].name != (char *)NULL; i++) { int j; depckError_t *erc; if (zonenames != (char *)NULL) { free(zonenames); zonenames = (char *)NULL; } erc = a_dck[i].record; if (erc->er_numEntries == 0) { continue; } for (j = 0; j < erc->er_numEntries; j++) { int k; depckErrorRecord_t *eir; if (zonenames != (char *)NULL) { free(zonenames); zonenames = (char *)NULL; } eir = &erc->er_theEntries[j]; packageName = eir->ier_packageName; for (k = 0; k < eir->ier_numZones; k++) { int err; err = collectError(&numzones, &zonenames, packageName, a_dck, i, eir, k); if (err != 0) { if (zonenames != (char *)NULL) { free(zonenames); zonenames = (char *)NULL; } return (err); } } if (a_dck[i].ignore_values == (char *)NULL) { continue; } if (a_dck[i].err_msg == (char **)NULL) { (void) snprintf(msgbuf, sizeof (msgbuf), ERR_DEPENDENCY_IGNORED, a_dck[i].name, packageName, numzones == 1 ? "zone" : "zones", zonenames ? zonenames : "?"); } else { /* LINTED variable format specifier to ... */ (void) snprintf(msgbuf, sizeof (msgbuf), *a_dck[i].err_msg, "package", packageName, numzones == 1 ? "zone" : "zones", zonenames ? zonenames : "??"); } if (a_dck[i].depcklFunc != NULL) { /* call check function */ err = (a_dck[i].depcklFunc)(msgbuf, packageName); echoDebug(DBG_DEPCHK_REPORT_ERROR, a_dck[i].ignore_values, err, packageName, msgbuf); if (err != 0) { if (zonenames != (char *)NULL) { free(zonenames); zonenames = (char *)NULL; } return (err); } } else { /* no check function - just report message */ echoDebug(DBG_DEPCHK_IGNORE_ERROR, a_dck[i].ignore_values, packageName, msgbuf); ptext(stderr, "\\n%s", msgbuf); } } } if (zonenames != (char *)NULL) { free(zonenames); zonenames = (char *)NULL; } return (0); }
void depchkRecordError(depckError_t *a_erc, char *a_pkginst, char *a_zoneName, char *a_value) { depckErrorRecord_t *erc; int i; /* * create new error record and entry if first entry * record will look like this: * err->er_#entry=1 * err->entry[0]->record->ier_numZones=1 * err->entry[0]->record->ier_packageName=a_pkginst * err->entry[0]->record->ier_zones[0]=a_zoneName * err->entry[0]->record->ier_values[0]=a_value */ if (a_erc->er_numEntries == 0) { depckErrorRecord_t *eir; eir = (depckErrorRecord_t *)calloc(1, sizeof (depckErrorRecord_t)); eir->ier_packageName = strdup(a_pkginst); eir->ier_numZones = 1; eir->ier_zones = (char **)calloc(1, sizeof (char **)); (eir->ier_zones)[eir->ier_numZones-1] = strdup(a_zoneName); eir->ier_values = (char **)calloc(1, sizeof (char *)); (eir->ier_values)[eir->ier_numZones-1] = strdup(a_value); a_erc->er_numEntries = 1; a_erc->er_theEntries = eir; echoDebug(DBG_DEPCHK_RECORD_ERROR, (long)a_erc, a_pkginst, a_zoneName, a_value); return; } /* see if this package already has an entry if so add zone to list */ for (i = 0; i < a_erc->er_numEntries; i++) { erc = &a_erc->er_theEntries[i]; if (strcmp(erc->ier_packageName, a_pkginst) != 0) { continue; } echoDebug(DBG_DEPCHK_RECORD_ZERROR, (long)a_erc, a_zoneName, a_value, erc->ier_packageName, erc->ier_numZones, erc->ier_zones[0]); /* * this package already has an entry - add zone to * existing package entry the modified records will * look like this: * err->er_#entry++; * err->entry[0]->... * err->entry[i]-> * -------------->record-> * ---------------------->ier_numZones++; * ---------------------->ier_packageName=a_pkginst * ---------------------->ier_zones[0]=... * ---------------------->ier_zones[...]=... * ---------------------->ier_zones[ier_numZones-1]=a_zoneName * ---------------------->ier_values[0]=... * ---------------------->ier_values[...]=... * ---------------------->ier_values[ier_numZones-1]=a_value * err->entry[i+1]->... */ erc->ier_numZones++; erc->ier_zones = (char **)realloc(erc->ier_zones, sizeof (char **)*erc->ier_numZones); (erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName); erc->ier_values = (char **)realloc(erc->ier_values, sizeof (char **)*erc->ier_numZones); (erc->ier_values)[erc->ier_numZones-1] = strdup(a_value); return; } /* * this packages does not have an entry - add new package * entry for this zone the modified records will look like this: * err->er_#entry++; * err->entry[0]->record->ier_numZones=... * err->entry[0]->record->ier_packageName=... * err->entry[0]->record->ier_zones[0]=... * err->entry[0]->record->ier_values[0]=... * err->entry[er_#entry-1]->record->ier_numZones=1 * err->entry[er_#entry-1]->record->ier_packageName=a_pkginst * err->entry[er_#entry-1]->record->ier_zones[0]=a_zoneName * err->entry[er_#entry-1]->record->ier_values[0]=a_value */ echoDebug(DBG_DEPCHK_RECORD_PERROR, (long)a_erc, a_erc->er_numEntries, a_pkginst, a_zoneName, a_value); a_erc->er_numEntries++; a_erc->er_theEntries = realloc(a_erc->er_theEntries, sizeof (depckErrorRecord_t)*a_erc->er_numEntries); erc = &a_erc->er_theEntries[a_erc->er_numEntries-1]; erc->ier_packageName = strdup(a_pkginst); erc->ier_numZones = 1; erc->ier_zones = (char **)calloc(1, sizeof (char *)); (erc->ier_zones)[erc->ier_numZones-1] = strdup(a_zoneName); erc->ier_values = (char **)calloc(1, sizeof (char *)); (erc->ier_values)[erc->ier_numZones-1] = strdup(a_value); }