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); } }
static int add_anchor(int msgnum, int quoting_msgnum, int quote_num, const char *anchor, char *line, int find_substr, int count_quoted_lines, const String_Match * match_info) { char *filename; char *tmpfilename; char buffer[MAXLINE]; FILE *fp1, *fp2; int matches = 0; int in_body = FALSE; int cmp_len = strlen(line); struct emailinfo *ep; struct body *bp = hashnumlookup(msgnum, &ep); char *ptr; char *tmpptr; while (bp && (!strncmp(bp->line, "Date:", 5) || !strncmp(bp->line, "From:", 5) || !strncmp(bp->line, "From:", 5) || !strncasecmp(bp->line, "Message-Id:", 11) || !strncmp(bp->line, "Subject:", 8) || !strncasecmp(bp->line, "In-Reply-To:", 12) || !strncasecmp(bp->line, "References:", 11) || !strncmp(bp->line, "To:", 3))) bp = bp->next; /* skip over header info */ ptr = bp ? bp->line : NULL; while (ptr && !*ptr) { bp = bp->next; if (!bp) break; ptr = bp->line; } filename = articlehtmlfilename(ep); if ((fp1 = fopen(filename, "r")) == NULL) { free(filename); if (msgnum > quoting_msgnum) return 0; /* just a forward ref */ if (set_showprogress) fprintf(stderr, "Couldn't read message number %d (linked from %d). " "May mean message deleted with delete_level = 0.\n", msgnum, quoting_msgnum); return -1; } tmpfilename = htmlfilename("tmp", ep, "tmp"); /* AUDIT biege: where is the tmp-file created? cwd? what about checking the return-value */ if ((fp2 = fopen(tmpfilename, "w")) == NULL) { snprintf(errmsg, sizeof(errmsg), "Couldn't write \"%s\".", tmpfilename); progerr(errmsg); } while (fgets(buffer, sizeof(buffer), fp1)) { if ((find_substr && str_similar_str(buffer, line)) || (!find_substr && !strncmp(buffer, line, cmp_len))) { int wrote_a_end = FALSE; ++matches; bp = place_anchor(match_info, bp, buffer, fp2, &ptr, anchor); if (set_link_to_replies) { struct emailinfo *ep2; if (hashnumlookup(quoting_msgnum, &ep2)) { char *path = get_path(ep, ep2); fprintf(fp2, "<a href=\"%s%.4d.%s#qlink%d\">%s</a>", path, quoting_msgnum, set_htmlsuffix, quote_num, set_link_to_replies); if (*path) free(path); } } /* Now find end of quoted text: */ do { if (!strcmp(buffer, "<!-- body=\"end\" -->\n")) { count_quoted_lines = -1; break; /* reply quoted more lines than exist? */ } if (match_info && place_a_end(match_info, &bp, buffer, fp2, &ptr)) { wrote_a_end = TRUE; count_quoted_lines = 0; if (bp) bp = bp->next; if (bp) ptr = bp->line; break; } fputs(buffer, fp2); /* surpress decrement for lines inserted by html conversion: */ if (!strcasecmp(buffer, "<p>\n")) ++count_quoted_lines; else { char *tptr = remove_hypermail_tags(buffer); if (tptr) free(tptr); else ++count_quoted_lines; } } while (--count_quoted_lines > 0 && fgets(buffer, sizeof(buffer), fp1)); if (!wrote_a_end) fputs("</a>", fp2); if (count_quoted_lines > 0) /* got eof? */ break; /* avoid last fputs */ else if (count_quoted_lines == 0 && !fgets(buffer, sizeof(buffer), fp1)) break; } else if (in_body && bp && (tmpptr = remove_hypermail_tags(buffer))) { char *tmpptr2 = unconvchars(tmpptr); if (tmpptr2 && str_similar_str(tmpptr, bp->line)) bp = bp->next; if (bp) ptr = bp->line; if (tmpptr2) free(tmpptr2); free(tmpptr); } else if (!in_body && !strcmp(buffer, "<!-- body=\"start\" -->\n")) in_body = TRUE; fputs(buffer, fp2); } fclose(fp1); fclose(fp2); if (matches != 1) remove(tmpfilename); else { if (rename(tmpfilename, filename) == -1) { snprintf(errmsg, sizeof(errmsg), "Couldn't rename \"%s\" to %s.", tmpfilename, filename); progerr(errmsg); } if (chmod(filename, set_filemode) == -1) { snprintf(errmsg, sizeof(errmsg), "Couldn't chmod \"%s\" to %o.", filename, set_filemode); progerr(errmsg); } } free(filename); free(tmpfilename); return matches == 1; }
/* will return 0, 1, 3, or 99 */ static int _pkgtrans(char *device1, char *device2, char **pkg, int options, keystore_handle_t keystore, char *keystore_alias) { #ifdef USE_KEYSTORE BIO *p7_bio = NULL; EVP_PKEY *privkey = NULL; #endif PKCS7 *sec_pkcs7 = NULL; #ifdef USE_KEYSTORE PKCS7_SIGNER_INFO *sec_signerinfo = NULL; PKG_ERR *err; STACK_OF(X509) *cacerts = NULL; STACK_OF(X509) *clcerts = NULL; STACK_OF(X509) *sec_chain = NULL; X509 *pubcert = NULL; #endif boolean_t making_sig = B_FALSE; char *src, *dst; int errflg, i, n; struct dm_buf *hdr; making_sig = (keystore != NULL) ? B_TRUE : B_FALSE; #ifdef USE_KEYSTORE if (making_sig) { /* new error object */ err = pkgerr_new(); /* find matching cert and key */ if (find_key_cert_pair(err, keystore, keystore_alias, &privkey, &pubcert) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* get CA certificates */ if (find_ca_certs(err, keystore, &cacerts) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* get CL (aka "chain") certificates */ if (find_cl_certs(err, keystore, &clcerts) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* initialize PKCS7 object to be filled in later */ sec_pkcs7 = PKCS7_new(); PKCS7_set_type(sec_pkcs7, NID_pkcs7_signed); sec_signerinfo = PKCS7_add_signature(sec_pkcs7, pubcert, privkey, EVP_sha1()); if (sec_signerinfo == NULL) { progerr(gettext(ERR_SEC), keystore_alias); ERR_print_errors_fp(stderr); pkgerr_free(err); return (1); } /* add signer cert into signature */ PKCS7_add_certificate(sec_pkcs7, pubcert); /* attempt to resolve cert chain starting at the signer cert */ if (get_cert_chain(err, pubcert, clcerts, cacerts, &sec_chain) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* * add the verification chain of certs into the signature. * The first cert is the user cert, which we don't need, * since it's baked in already, so skip it */ for (i = 1; i < sk_X509_num(sec_chain); i++) { PKCS7_add_certificate(sec_pkcs7, sk_X509_value(sec_chain, i)); } pkgerr_free(err); err = NULL; } #endif /* USE_KEYSTORE */ if (signal_received > 0) { return (1); } /* transfer spool to appropriate device */ if (devtype(device1, &srcdev)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADDEV), device1); return (1); } srcdev.rdonly++; /* check for datastream */ ids_name = NULL; if (srcdev.bdevice) { if (ds_readbuf(srcdev.cdevice)) ids_name = srcdev.cdevice; } if (srcdev.cdevice && !srcdev.bdevice) ids_name = srcdev.cdevice; else if (srcdev.pathname) { ids_name = srcdev.pathname; if (access(ids_name, 0) == -1) { progerr(ERR_TRANSFER); logerr(pkg_gt(MSG_GETVOL)); return (1); } } if (!ids_name && device2 == (char *)0) { if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { cleanup(); return (n); } if (srcdev.mount && *srcdev.mount) pkgdir = strdup(srcdev.mount); return (0); } if (ids_name && device2 == (char *)0) { char template[] = "/var/tmp/ptXXXXXX";
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 */ }
void getdefaults(SWISH * sw, char *conffile, int *hasdir, int *hasindex, int hasverbose) { int i, gotdir, gotindex; char *line = NULL; FILE *fp; int linenumber = 0; int baddirective = 0; StringList *sl; IndexFILE *indexf = NULL; unsigned char *StringValue = NULL; struct swline *tmplist; char *w0; gotdir = gotindex = 0; if ((fp = fopen(conffile, F_READ_TEXT)) == NULL || !isfile(conffile)) progerrno("Couldn't open the configuration file '%s': ", conffile); if ( sw->verbose >= 2 ) printf("Parsing config file '%s'\n", conffile ); /* Init default index file */ addindexfile(sw, INDEXFILE); indexf = sw->indexlist; sl = NULL; while ( !feof( fp ) ) { /* Free previous line */ if ( line ) efree( line ); /* Read a line */ line = read_line_from_file( &linenumber, fp ); if ( sl ) freeStringList(sl); /* Parse line */ if (!(sl = parse_line(line))) continue; if (!sl->n) continue; w0 = sl->word[0]; /* Config Direct. = 1. word */ if (w0[0] == '#') continue; /* comment */ if (strcasecmp(w0, "IndexDir") == 0) { if (sl->n > 1) { if (!*hasdir) { gotdir = 1; grabCmdOptions(sl, 1, &sw->dirlist); } } else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "IncludeConfigFile") == 0) { if (sl->n == 2) { normalize_path( sl->word[1] ); getdefaults(sw, sl->word[1], hasdir, hasindex, hasverbose); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "NoContents") == 0) { if (sl->n > 1) { grabCmdOptions(sl, 1, &sw->nocontentslist); } else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "IndexFile") == 0) { if (!(*hasindex)) { if (sl->n == 2) { gotindex = 1; if (indexf->line) efree(indexf->line); indexf->line = estrdup(sl->word[1]); normalize_path( indexf->line ); } else progerr("%s: requires one value", w0); } continue; } if (strcasecmp(w0, "IndexReport") == 0) { if (sl->n == 2) { if (!hasverbose) sw->verbose = read_integer( sl->word[1], w0, 0, 4 ); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "ParserWarnLevel") == 0) { if (sl->n == 2) sw->parser_warn_level = read_integer( sl->word[1], w0, 0, 9 ); else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "obeyRobotsNoIndex") == 0) { sw->obeyRobotsNoIndex = getYesNoOrAbort(sl, 1, 1); continue; } if (strcasecmp(w0, "AbsoluteLinks") == 0) { sw->AbsoluteLinks = getYesNoOrAbort(sl, 1, 1); continue; } if (strcasecmp(w0, "MinWordLimit") == 0) { if (sl->n == 2) { indexf->header.minwordlimit = read_integer( sl->word[1], w0, 0, INT_MAX ); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "MaxWordLimit") == 0) { if (sl->n == 2) { indexf->header.maxwordlimit = read_integer( sl->word[1], w0, 0, INT_MAX ); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "IndexComments") == 0) { sw->indexComments = getYesNoOrAbort(sl, 1, 1); continue; } if (strcasecmp(w0, "IgnoreNumberChars") == 0) { if (sl->n == 2) { indexf->header.numberchars = SafeStrCopy(indexf->header.numberchars, sl->word[1], &indexf->header.lennumberchars); sortstring(indexf->header.numberchars); makelookuptable(indexf->header.numberchars, indexf->header.numbercharslookuptable); indexf->header.numberchars_used_flag = 1; /* Flag that it is used */ } else progerr("%s: requires one value (a set of characters)", w0); continue; } if (strcasecmp(w0, "WordCharacters") == 0) { if (sl->n == 2) { indexf->header.wordchars = SafeStrCopy(indexf->header.wordchars, sl->word[1], &indexf->header.lenwordchars); sortstring(indexf->header.wordchars); makelookuptable(indexf->header.wordchars, indexf->header.wordcharslookuptable); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "BeginCharacters") == 0) { if (sl->n == 2) { indexf->header.beginchars = SafeStrCopy(indexf->header.beginchars, sl->word[1], &indexf->header.lenbeginchars); sortstring(indexf->header.beginchars); makelookuptable(indexf->header.beginchars, indexf->header.begincharslookuptable); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "EndCharacters") == 0) { if (sl->n == 2) { indexf->header.endchars = SafeStrCopy(indexf->header.endchars, sl->word[1], &indexf->header.lenendchars); sortstring(indexf->header.endchars); makelookuptable(indexf->header.endchars, indexf->header.endcharslookuptable); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "IgnoreLastChar") == 0) { if (sl->n == 2) { indexf->header.ignorelastchar = SafeStrCopy(indexf->header.ignorelastchar, sl->word[1], &indexf->header.lenignorelastchar); sortstring(indexf->header.ignorelastchar); makelookuptable(indexf->header.ignorelastchar, indexf->header.ignorelastcharlookuptable); } /* Do nothing */ /* else progerr("%s: requires one value",w0); */ continue; } if (strcasecmp(w0, "IgnoreFirstChar") == 0) { if (sl->n == 2) { indexf->header.ignorefirstchar = SafeStrCopy(indexf->header.ignorefirstchar, sl->word[1], &indexf->header.lenignorefirstchar); sortstring(indexf->header.ignorefirstchar); makelookuptable(indexf->header.ignorefirstchar, indexf->header.ignorefirstcharlookuptable); } /* Do nothing */ /* else progerr("%s: requires one value",w0); */ continue; } if (strcasecmp(w0, "ReplaceRules") == 0) { if (sl->n > 2) Build_ReplaceRules( w0, sl->word, &sw->replaceRegexps ); else progerr("%s: requires at least two values", w0); continue; } if (strcasecmp(w0, "IndexName") == 0) { if (sl->n > 1) { StringValue = StringListToString(sl, 1); indexf->header.indexn = SafeStrCopy(indexf->header.indexn, (char *)StringValue, &indexf->header.lenindexn); efree(StringValue); } else progerr("%s: requires a value", w0); continue; } if (strcasecmp(w0, "IndexDescription") == 0) { if (sl->n > 1) { StringValue = StringListToString(sl, 1); indexf->header.indexd = SafeStrCopy(indexf->header.indexd, (char *)StringValue, &indexf->header.lenindexd); efree(StringValue); } else progerr("%s: requires a value", w0); continue; } if (strcasecmp(w0, "IndexPointer") == 0) { if (sl->n > 1) { StringValue = StringListToString(sl, 1); indexf->header.indexp = SafeStrCopy(indexf->header.indexp, (char *)StringValue, &indexf->header.lenindexp); efree(StringValue); } else progerr("%s: requires a value", w0); continue; } if (strcasecmp(w0, "IndexAdmin") == 0) { if (sl->n > 1) { StringValue = StringListToString(sl, 1); indexf->header.indexa = SafeStrCopy(indexf->header.indexa, (char *)StringValue, &indexf->header.lenindexa); efree(StringValue); } else progerr("%s: requires one value", w0); continue; } if (strcasecmp(w0, "UseStemming") == 0) { progwarn("UseStemming is deprecated. See FuzzyIndexingMode in the docs"); if ( getYesNoOrAbort(sl, 1, 1) ) fuzzy_or_die( indexf, "Stemming_en" ); continue; } if (strcasecmp(w0, "UseSoundex") == 0) { if ( getYesNoOrAbort(sl, 1, 1) ) fuzzy_or_die( indexf, "Soundex" ); continue; } if (strcasecmp(w0, "FuzzyIndexingMode") == 0) { if (sl->n != 2) progerr("%s: requires one value", w0); fuzzy_or_die( indexf, sl->word[1] ); continue; } if (strcasecmp(w0, "IgnoreTotalWordCountWhenRanking") == 0) { indexf->header.ignoreTotalWordCountWhenRanking = getYesNoOrAbort(sl, 1, 1); continue; } if (strcasecmp(w0, "TranslateCharacters") == 0) { if (sl->n >= 2) { if (!BuildTranslateChars(indexf->header.translatecharslookuptable, (unsigned char *)sl->word[1], (unsigned char *)sl->word[2])) { progerr("%s: requires two values (same length) or one translation rule", w0); } } continue; } if (strcasecmp(w0, "ExtractPath") == 0) { struct metaEntry *m; char **words; if (sl->n < 4) progerr("%s: requires at least three values: metaname expression type and a expression/strings", w0); if ( !( m = getMetaNameByName( &indexf->header, sl->word[1])) ) m = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0); words = sl->word; words++; /* past metaname */ add_ExtractPath( w0, sw, m, words ); continue; } if (strcasecmp(w0, "ExtractPathDefault") == 0) { struct metaEntry *m; if (sl->n != 3) progerr("%s: requires two values: metaname default_value", w0); if ( !( m = getMetaNameByName( &indexf->header, sl->word[1])) ) m = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0); if ( m->extractpath_default ) progerr("%s already defined for meta '%s' as '%s'", w0, m->metaName, m->extractpath_default ); m->extractpath_default = estrdup( sl->word[2] ); continue; } if (strcasecmp(w0, "MetaNames") == 0) { if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( getMetaNameByName( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a MetaName", w0, sl->word[i] ); addMetaEntry(&indexf->header, sl->word[i], META_INDEX, 0); } continue; } if (strcasecmp(w0, "MetaNameAlias") == 0) { struct metaEntry *meta_entry; struct metaEntry *new_meta; if (sl->n < 3) progerr("%s: requires at least two values", w0); /* Make sure first entry is not an alias */ /* Lookup entry, and do not follow alias */ if ( !(meta_entry = getMetaNameByNameNoAlias( &indexf->header, sl->word[1]) ) ) progerr("%s - name '%s' not a MetaName", w0, sl->word[1] ); if ( meta_entry->alias ) progerr("%s - name '%s' must not be an alias", w0, sl->word[1] ); for (i = 2; i < sl->n; i++) { if ( getMetaNameByNameNoAlias( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a MetaName or MetaNameAlias", w0, sl->word[i] ); new_meta = addMetaEntry(&indexf->header, sl->word[i], meta_entry->metaType, 0); new_meta->alias = meta_entry->metaID; } continue; } /* Allow setting a bias on MetaNames */ if (strcasecmp(w0, "MetaNamesRank") == 0) { struct metaEntry *meta_entry; int rank = 0; if (sl->n < 3) progerr("%s: requires only two or more values, a rank (integer) and a list of property names", w0); rank = read_integer( sl->word[1], w0, -RANK_BIAS_RANGE, RANK_BIAS_RANGE ); // NOTE: if this is changed db.c must match for (i = 2; i < sl->n; i++) { /* already exists? */ if ( (meta_entry = getMetaNameByNameNoAlias( &indexf->header, sl->word[i])) ) { if ( meta_entry->alias ) progerr("Can't assign a rank to metaname '%s': it is an alias", meta_entry->metaName ); if ( meta_entry->rank_bias ) progwarn("Why are you redefining the rank of metaname '%s'?", meta_entry->metaName ); } else meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_INDEX, 0); meta_entry->rank_bias = rank; } continue; } /* Meta name to extract out <a href> links */ if (strcasecmp(w0, "HTMLLinksMetaName") == 0) { if (sl->n <= 1) progerr("%s: requires one value", w0); if ( !( sw->links_meta = getMetaNameByName( &indexf->header, sl->word[1]) )) sw->links_meta = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0); continue; } /* What to do with IMG ATL tags? */ if (strcasecmp(w0, "IndexAltTagMetaName") == 0) { if (sl->n <= 1) progerr("%s: requires one value", w0); if ( strcasecmp( sl->word[1], "as-text" ) == 0) { sw->IndexAltTag = 1; if ( sw->IndexAltTagMeta ) { efree( sw->IndexAltTagMeta ); sw->IndexAltTagMeta = NULL; } } else { sw->IndexAltTag = 1; if ( sw->IndexAltTagMeta ) { efree( sw->IndexAltTagMeta ); sw->IndexAltTagMeta = NULL; } sw->IndexAltTagMeta = estrdup( sl->word[1] ); } continue; } /* Meta name to extract out <img src> links */ if (strcasecmp(w0, "ImageLinksMetaName") == 0) { if (sl->n <= 1) progerr("%s: requires one value", w0); if ( !( sw->images_meta = getMetaNameByName( &indexf->header, sl->word[1]) )) sw->images_meta = addMetaEntry(&indexf->header, sl->word[1], META_INDEX, 0); continue; } if (strcasecmp(w0, "PropCompressionLevel") == 0) { #ifdef HAVE_ZLIB if (sl->n == 2) { sw->PropCompressionLevel = read_integer( sl->word[1], w0, 0, 9 ); } else progerr("%s: requires one value", w0); #else progwarn("%s: Swish not built with zlib support -- cannot compress", w0); #endif continue; } if (strcasecmp(w0, "PropertyNames") == 0) { if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( getPropNameByName( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] ); addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0); } continue; } if (strcasecmp(w0, "PropertyNamesIgnoreCase") == 0) { struct metaEntry *m; if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) ) addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0); else { if ( !is_meta_string( m ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); m->metaType |= META_IGNORE_CASE; } } continue; } if (strcasecmp(w0, "PropertyNamesCompareCase") == 0) { struct metaEntry *m; if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) ) addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0); else { if ( !is_meta_string( m ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); m->metaType &= ~META_IGNORE_CASE; } } continue; } /* --- this is duplicating.. */ if (strcasecmp(w0, "PropertyNamesNoStripChars") == 0) { struct metaEntry *m; if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) ) addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE|META_NOSTRIP, 0); else { if ( !is_meta_string( m ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); m->metaType |= META_NOSTRIP; } } continue; } if (strcasecmp(w0, "PropertyNamesStripChars") == 0) { struct metaEntry *m; if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( !(m = getPropNameByName( &indexf->header, sl->word[i])) ) addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING|META_IGNORE_CASE, 0); else { if ( !is_meta_string( m ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); m->metaType &= ~META_NOSTRIP; } } continue; } if (strcasecmp(w0, "PropertyNamesNumeric") == 0) { if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( getPropNameByName( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] ); addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_NUMBER, 0); } continue; } if (strcasecmp(w0, "PropertyNamesDate") == 0) { if (sl->n <= 1) progerr("%s: requires at least one value", w0); for (i = 1; i < sl->n; i++) { if ( getPropNameByName( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a PropertyName", w0, sl->word[i] ); addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_DATE, 0); } continue; } if (strcasecmp(w0, "PropertyNameAlias") == 0) { struct metaEntry *meta_entry; struct metaEntry *new_meta; if (sl->n < 3) progerr("%s: requires at least two values", w0); /* Make sure first entry is not an alias */ /* Lookup entry, and do not follow alias */ if ( !(meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[1]) ) ) progerr("%s - name '%s' not a PropertyName", w0, sl->word[1] ); if ( meta_entry->alias ) progerr("%s - name '%s' must not be an alias", w0, sl->word[1] ); for (i = 2; i < sl->n; i++) { if ( getPropNameByNameNoAlias( &indexf->header, sl->word[i]) ) progerr("%s - name '%s' is already a PropertyName or PropertyNameAlias", w0, sl->word[i] ); new_meta = addMetaEntry(&indexf->header, sl->word[i], meta_entry->metaType, 0); new_meta->alias = meta_entry->metaID; } continue; } /* This allows setting a limit on a property's string length */ // One question would be if this should set the length on the alias, or the real property. */ // If on the alias then you could really fine tune: // PropertyNames description // PropertyNameAlias description td h1 h2 h3 // PropertyNameMaxLength 5000 description // PropertyNameMaxLength 100 td // PropertyNameMaxLength 10 h1 h2 h3 // then the total length would be 5000, but each one would be limited, too. I find that hard to imagine // it would be useful. So the current design is you can only assign to a non-alias. if (strcasecmp(w0, "PropertyNamesMaxLength") == 0) { struct metaEntry *meta_entry; int max_length = 0; if (sl->n < 3) progerr("%s: requires only two or more values, a length and a list of property names", w0); max_length = read_integer( sl->word[1], w0, 0, INT_MAX ); for (i = 2; i < sl->n; i++) { /* already exists? */ if ( (meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[i])) ) { if ( meta_entry->alias ) progerr("Can't assign a length to property '%s': it is an alias", meta_entry->metaName ); if ( meta_entry->max_len ) progwarn("Why are you redefining the max length of property '%s'?", meta_entry->metaName ); if ( !is_meta_string( meta_entry ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); } else meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0); meta_entry->max_len = max_length; } continue; } /* Set the sort length */ if (strcasecmp(w0, "PropertyNamesSortKeyLength") == 0) { struct metaEntry *meta_entry; int max_length = 0; if (sl->n < 3) progerr("%s: requires only two or more values, a length and a list of property names", w0); max_length = read_integer( sl->word[1], w0, 1, INT_MAX ); for (i = 2; i < sl->n; i++) { /* already exists? */ if ( (meta_entry = getPropNameByNameNoAlias( &indexf->header, sl->word[i])) ) { if ( meta_entry->alias ) progerr("Can't assign a length to property '%s': it is an alias", meta_entry->metaName ); if ( meta_entry->max_len ) progwarn("Why are you redefining the max sort key length of property '%s'?", meta_entry->metaName ); if ( !is_meta_string( meta_entry ) ) progerr("%s - name '%s' is not a STRING type of Property", w0, sl->word[i] ); } else meta_entry = addMetaEntry(&indexf->header, sl->word[i], META_PROP|META_STRING, 0); meta_entry->sort_len = max_length; } continue; } /* Hashed word lists */ if ( !strcasecmp(w0, "IgnoreWords") || !strcasecmp(w0, "StopWords")) { word_hash_config( sl, &indexf->header.hashstoplist ); continue; } if (strcasecmp(w0, "BuzzWords") == 0) /* 2001-04-24 moseley */ { word_hash_config( sl, &indexf->header.hashbuzzwordlist ); continue; } if (strcasecmp(w0, "UseWords") == 0) { word_hash_config( sl, &indexf->header.hashuselist ); continue; } /* IndexVerbose is supported for backwards compatibility */ if (strcasecmp(w0, "IndexVerbose") == 0) { sw->verbose = getYesNoOrAbort(sl, 1, 1); if (sw->verbose) sw->verbose = 3; continue; } if (strcasecmp(w0, "IndexOnly") == 0) { if (sl->n > 1) { grabCmdOptions(sl, 1, &sw->suffixlist); } else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "IndexContents") == 0) { if (sl->n > 2) { struct IndexContents *ic = (struct IndexContents *) emalloc(sizeof(struct IndexContents)); ic->DocType = getDocTypeOrAbort(sl, 1); ic->patt = NULL; for (i = 2; i < sl->n; i++) ic->patt = addswline(ic->patt, sl->word[i]); if (sw->indexcontents) ic->next = sw->indexcontents; else ic->next = NULL; sw->indexcontents = ic; } else progerr("%s: requires at least two values", w0); continue; } /* $$$ this needs fixing */ if (strcasecmp(w0, "StoreDescription") == 0) { if (sl->n == 3 || sl->n == 4) { struct StoreDescription *sd = (struct StoreDescription *) emalloc(sizeof(struct StoreDescription)); sd->DocType = getDocTypeOrAbort(sl, 1); sd->size = 0; sd->field = NULL; i = 2; if (sl->word[i][0] == '<' && sl->word[i][strlen(sl->word[i]) - 1] == '>') { sl->word[i][strlen(sl->word[i]) - 1] = '\0'; sd->field = estrdup(sl->word[i] + 1); i++; } if (i < sl->n && isnumstring( (unsigned char *)sl->word[i] )) { sd->size = read_integer( sl->word[i], w0, 0, INT_MAX ); } if (sl->n == 3 && !sd->field && !sd->size) progerr("%s: second parameter must be <fieldname> or a number", w0); if (sl->n == 4 && sd->field && !sd->size) progerr("%s: third parameter must be empty or a number", w0); if (sw->storedescription) sd->next = sw->storedescription; else sd->next = NULL; sw->storedescription = sd; /* Make sure there's a property name */ if ( !getPropNameByName( &indexf->header, AUTOPROPERTY_SUMMARY) ) addMetaEntry(&indexf->header, AUTOPROPERTY_SUMMARY, META_PROP|META_STRING, 0); } else progerr("%s: requires two or three values", w0); continue; } if (strcasecmp(w0, "DefaultContents") == 0) { if (sl->n == 2 ) { sw->DefaultDocType = getDocTypeOrAbort(sl, 1); } else progerr("%s: requires one value -- a parser type", w0); continue; } if (strcasecmp(w0, "BumpPositionCounterCharacters") == 0) { if (sl->n > 1) { indexf->header.bumpposchars = SafeStrCopy(indexf->header.bumpposchars, sl->word[1], &indexf->header.lenbumpposchars); sortstring(indexf->header.bumpposchars); makelookuptable(indexf->header.bumpposchars, indexf->header.bumpposcharslookuptable); } else progerr("%s: requires at least one value", w0); continue; } /* #### Added UndefinedMetaTags as defined by Bill Moseley */ if (strcasecmp(w0, "UndefinedMetaTags") == 0) { get_undefined_meta_flags( w0, sl, &sw->UndefinedMetaTags ); if ( !sw->UndefinedMetaTags ) progerr("%s: possible values are error, ignore, index or auto", w0); continue; } if (strcasecmp(w0, "UndefinedXMLAttributes") == 0) { get_undefined_meta_flags( w0, sl, &sw->UndefinedXMLAttributes ); continue; } if (strcasecmp(w0, "IgnoreMetaTags") == 0) { if (sl->n > 1) { grabCmdOptions(sl, 1, &sw->ignoremetalist); /* Go lowercase */ for (tmplist = sw->ignoremetalist; tmplist; tmplist = tmplist->next) (void)strtolower(tmplist->line); } else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "XMLClassAttributes") == 0) { if (sl->n > 1) { grabCmdOptions(sl, 1, &sw->XMLClassAttributes); /* Go lowercase */ for (tmplist = sw->XMLClassAttributes; tmplist; tmplist = tmplist->next) (void)strtolower(tmplist->line); } else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "DontBumpPositionOnStartTags") == 0) { if (sl->n > 1) grabCmdOptions(sl, 1, &sw->dontbumpstarttagslist); else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "DontBumpPositionOnEndTags") == 0) { if (sl->n > 1) grabCmdOptions(sl, 1, &sw->dontbumpendtagslist); else progerr("%s: requires at least one value", w0); continue; } if (strcasecmp(w0, "TruncateDocSize") == 0) { /* rasc 2001-03 */ if (sl->n == 2 && isnumstring( (unsigned char *)sl->word[1] )) sw->truncateDocSize = atol(sl->word[1]); else progerr("%s: requires size parameter in bytes", w0); continue; } if (strcasecmp(w0, "CompressPositions") == 0) { sw->compressPositions = getYesNoOrAbort(sl, 1, 1); continue; } else if (configModule_Entities(sw, sl)); else if (configModule_Filter(sw, sl)); /* rasc */ else if (configModule_ResultOutput(sw, sl)); /* rasc */ else if (configModule_ResultSort(sw, sl)); /* jmruiz */ else if (configModule_Index(sw, sl)); /* jmruiz */ else if (configModule_Prog(sw, sl)); else if (!parseconfline(sw, sl)) { printf("Bad directive on line #%d of file %s: %s\n", linenumber, conffile, line); if ( ++baddirective > 30 ) progerr("Too many errors. Can not continue."); } } freeStringList(sl); fclose(fp); if (baddirective) exit(1); if (gotdir && !(*hasdir)) *hasdir = 1; if (gotindex && !(*hasindex)) *hasindex = 1; }
int find_max_msgnum() { DIR *dir; #ifdef HAVE_DIRENT_H struct dirent *entry; #else struct direct *entry; #endif int max_num = -1; int num; char *s_dir = strsav(set_dir); int len = (int)strlen(s_dir); if (len > 0 && s_dir[len - 1] == PATH_SEPARATOR) s_dir[len - 1] = 0; dir = opendir(s_dir); if (dir == NULL) return -1; #ifdef GDBM if (set_folder_by_date && set_usegdbm) { return loadoldheadersfromGDBMindex(set_dir, 1) - 1; } #endif if (set_msgsperfolder) { int max_folder = -1; char *tmpptr; while ((entry = readdir(dir))) { const char *p = entry->d_name; while (isdigit(*p)) ++p; if (!*p && p > entry->d_name) { num = atoi(entry->d_name); if (num > max_folder) { char *full_path; trio_asprintf(&full_path, "%s%d", set_dir, num); if (isdir(full_path)) max_folder = num; free(full_path); } } } closedir(dir); trio_asprintf(&tmpptr, "%s%d", set_dir, max_folder); free(s_dir); s_dir = tmpptr; if (max_folder == -1) return -1; dir = opendir(s_dir); if (dir == NULL) { snprintf(errmsg, sizeof(errmsg), "internal error find_max_msgnum opening \"%s\".", s_dir); progerr(errmsg); } } while ((entry = readdir(dir))) { const char *p = entry->d_name; while (isdigit(*p)) ++p; if (*p == '.' && p >= entry->d_name + 4) { ++p; if (!strcmp(p, set_htmlsuffix)) { num = atoi(entry->d_name); if (num > max_num) max_num = num; } } } closedir(dir); free(s_dir); return max_num; }
int rckrunlevel(void) { struct utmpx utmpx; struct utmpx *putmpx; char ans[MAX_INPUT]; char *pt; char *rstates; int n; char *uxstate; if (ADM(runlevel, "nocheck")) { return (0); } pt = getenv("RSTATES"); if (pt == NULL) { return (0); } utmpx.ut_type = RUN_LVL; putmpx = getutxid(&utmpx); if (putmpx == NULL) { progerr(ERR_RUNSTATE); return (99); } uxstate = strtok(&putmpx->ut_line[10], " \t\n"); rstates = qstrdup(pt); if ((pt = strtok(pt, " \t\n, ")) == NULL) return (0); /* no list is no list */ do { if (strcmp(pt, uxstate) == 0) { free(rstates); return (0); } } while (pt = strtok(NULL, " \t\n, ")); if (preremoveCheck == B_FALSE) { msgtext = MSG_PKGREMOVE_RUNLEVEL; ptext(stderr, msgtext, uxstate); } else { (void) fprintf(stdout, "runlevel=%s", uxstate); } pt = strtok(rstates, " \t\n, "); do { if (preremoveCheck == B_FALSE) { ptext(stderr, "\\t%s", pt); } else { (void) fprintf(stdout, ":%s", pt); } } while (pt = strtok(NULL, " \t\n, ")); if (preremoveCheck == B_TRUE) { (void) fprintf(stdout, "\n"); } free(rstates); if (ADM(runlevel, "quit")) { return (4); } if (echoGetFlag() == B_FALSE) { return (5); } msgtext = NULL; n = ckyorn(ans, NULL, NULL, HLP_PKGREMOVE_RUNLEVEL, ASK_PKGREMOVE_CONTINUE); if (n != 0) { return (n); } if (strchr("yY", *ans) == NULL) { return (3); } return (0); }
int checkmap(int maptyp, int uninst, char *mapfile, char *envfile, char *pkginst, char *path, int pathtype) { FILE *fp; char *cl = NULL; char *value; char param[MAX_PKG_PARAM_LENGTH]; int count; int errflg; int n; int selected; struct pinfo *pinfo; VFP_T *vfp = (VFP_T *)NULL; PKGserver server; if (envfile != NULL) { if ((fp = fopen(envfile, "r")) == NULL) { progerr(gettext(ERR_ENVFILE), envfile); return (-1); } param[0] = '\0'; while (value = fpkgparam(fp, param)) { if (strcmp("PATH", param) != 0) { /* * If checking an uninstalled package, we * only want two parameters. If we took all * of them, including path definitions, we * wouldn't be looking in the right places in * the reloc and root directories. */ if (uninst) { if ((strncmp("PKG_SRC_NOVERIFY", param, 16) == 0) && value) { logerr(gettext(MSG_ARCHIVE)); putparam(param, value); } if ((strncmp("CLASSES", param, 7) == 0) && value) putparam(param, value); } else putparam(param, value); } free(value); param[0] = '\0'; } (void) fclose(fp); basedir = getenv("BASEDIR"); } /* * If we are using a contents file for the map, this locks the * contents file in order to freeze the database and assure it * remains synchronized with the file system against which it is * being compared. There is no practical way to lock another pkgmap * on some unknown medium so we don't bother. */ if (maptyp) { /* If this is the contents file */ if (!socfile(&server, B_FALSE) || pkgopenfilter(server, pkgcnt == 1 ? pkginst : NULL) != 0) { progerr(gettext(ERR_PKGMAP), "contents"); return (-1); } } else { if (vfpOpen(&vfp, mapfile, "r", VFP_NONE) != 0) { progerr(gettext(ERR_PKGMAP), mapfile); return (-1); } } if ((cl = getenv("CLASSES")) != NULL) cl_sets(qstrdup(cl)); errflg = count = 0; do { if ((n = NXTENTRY(&entry, vfp, server)) == 0) { break; } /* * Search for partial paths in the ext DB. */ if (pathtype) { /* LINTED warning: statement has no consequent: if */ if (is_partial_path_in_DB(entry.path, path)) { /* Check this entry */ ; } else if (entry.ftype == 's' || entry.ftype == 'l') { if (is_partial_path_in_DB( /* LINTED warning: statement has no consequen */ entry.ainfo.local, path)) { /* Check this entry */ ; } else { continue; } } else { /* Skip to next DB entry */ continue; } } if (n < 0) { char *errstr = getErrstr(); logerr(gettext("ERROR: garbled entry")); logerr(gettext("pathname: %s"), (entry.path && *entry.path) ? entry.path : "Unknown"); logerr(gettext("problem: %s"), (errstr && *errstr) ? errstr : "Unknown"); exit(99); } if (n == 0) break; /* done with file */ /* * The class list may not be complete for good reason, so * there's no complaining if this returns an index of -1. */ if (cl != NULL) entry.pkg_class_idx = cl_idx(entry.pkg_class); if (maptyp && pkginst != NULL) { /* * check to see if the entry we just read * is associated with one of the packages * we have listed on the command line */ selected = 0; pinfo = entry.pinfo; while (pinfo) { if (selpkg(pinfo->pkg)) { selected++; break; } pinfo = pinfo->next; } if (!selected) continue; /* not selected */ } /* * Check to see if the pathname associated with the entry * we just read is associated with the list of paths we * supplied on the command line */ if (!selpath(entry.path, pathtype)) continue; /* not selected */ /* * Determine if this is a package object wanting * verification. Metafiles are always checked, otherwise, we * rely on the class to discriminate. */ if (entry.ftype != 'i') /* If there's no class list... */ if (cl != NULL) /* * ... or this entry isn't in that class list * or it's in a private format, then don't * check it. */ if (entry.pkg_class_idx == -1 || cl_svfy(entry.pkg_class_idx) == NOVERIFY) continue; count++; if (ckentry((envfile ? 1 : 0), maptyp, &entry, vfp, server)) errflg++; } while (n != 0); if (maptyp) relslock(); else (void) vfpClose(&vfp); if (environ) { /* free up environment resources */ for (n = 0; environ[n]; n++) free(environ[n]); free(environ); environ = NULL; } if (maptyp) { /* * make sure each listed package was associated with * an entry from the prototype or pkgmap */ (void) selpkg(NULL); } if (!qflag && !lflag && !Lflag) { /* * make sure each listed pathname was associated with an entry * from the prototype or pkgmap */ (void) selpath(NULL, pathtype); } return (errflg); }
/* * get_special_contents * * Retrieves the special contents file entries, if they exist. These * are sorted. We do not assume the special_contents file is in sorted * order. * * pcroot The root of the install database. If NULL assume '/'. * pppcSC A pointer to a char **. This pointer will be set to * point at NULL if there is no special_contents file or * to a sorted array of strings, NULL terminated, otherwise. * piMax The # of entries in the special contents result. * * Returns: 0 on no error, nonzero on error. * Side effects: the pppcSC pointer is set to point at a newly * allocated array of pointers to strings.. The caller must * free this buffer. The value of *piMax is set to the # of * entries in ppcSC. */ static int get_special_contents(const char *pcroot, char ***pppcSC, int *piMax) { int e, i; FILE *fp; char line[2048]; char **ppc; char *pc = "var/sadm/install/special_contents"; char path[PATH_MAX]; struct stat s; /* Initialize the return values. */ *piMax = 0; *pppcSC = NULL; if (pcroot == NULL) { pcroot = "/"; } if (pcroot[strlen(pcroot) - 1] == '/') { if (snprintf(path, PATH_MAX, "%s%s", pcroot, pc) >= PATH_MAX) { progerr(gettext(SPECIAL_INPUT)); return (1); } } else { if (snprintf(path, PATH_MAX, "%s/%s", pcroot, pc) >= PATH_MAX) { progerr(gettext(SPECIAL_INPUT)); return (1); } } errno = 0; e = stat(path, &s); if (e != 0 && errno == ENOENT) return (0); /* No special contents file. Do nothing. */ if (access(path, R_OK) != 0 || (fp = fopen(path, "r")) == NULL) { /* Could not open special contents which exists */ progerr(gettext(SPECIAL_ACCESS)); return (1); } for (i = 0; fgets(line, 2048, fp) != NULL; i++); rewind(fp); if ((ppc = (char **) calloc(i + 1, sizeof (char *))) == NULL) { progerr(gettext(SPECIAL_MALLOC)); return (1); } for (i = 0; fgets(line, 2048, fp) != NULL; ) { int n; if (line[0] == '#' || line[0] == ' ' || line[0] == '\n' || line[0] == '\t' || line[0] == '\r') continue; n = strlen(line); if (line[n - 1] == '\n') line[n - 1] = '\0'; ppc[i++] = strdup(line); } qsort(ppc, i, sizeof (char *), strcompare); *pppcSC = ppc; *piMax = i; return (0); }
/* * special_contents_remove * * Given a set of entries to remove and an alternate root, this function * will do everything required to ensure that the entries are removed * from the contents file if they are listed in the special_contents * file. The contents file will get changed only in the case that the * entire operation has succeeded. * * ient The number of entries. * ppcfent The entries to remove. * pcroot The alternate install root. Could be NULL. In this * case, assume root is '/' * * Result: 0 on success, nonzero on failure. If an error occurs, an * error string will get output to standard error alerting the user. * Side effects: The contents file may change as a result of this call, * such that lines in the in the file will be changed or removed. * If the call fails, a t.contents file may be left behind. This * temporary file should be removed subsequently. */ int special_contents_remove(int ient, struct cfent **ppcfent, const char *pcroot) { int result = 0; /* Assume we will succeed. Return result. */ char **ppcSC = NULL; /* The special contents rules, sorted. */ int i, j; /* Indexes into contents & special contents */ FILE *fpi = NULL, /* Input of contents file */ *fpo = NULL; /* Output to temp contents file */ char cpath[PATH_MAX], /* Contents file path */ tcpath[PATH_MAX]; /* Temp contents file path */ const char *pccontents = "var/sadm/install/contents"; const char *pctcontents = "var/sadm/install/t.contents"; char line[LINESZ]; /* Reads in and writes out contents lines. */ time_t t; /* Used to create a timestamp comment. */ int max; /* Max number of special contents entries. */ int *piIndex; /* An index to ppcfents to remove from cfile */ cpath[0] = tcpath[0] = '\0'; if (ient == 0 || ppcfent == NULL || ppcfent[0] == NULL) { goto remove_done; } if ((get_special_contents(pcroot, &ppcSC, &max)) != 0) { result = 1; goto remove_done; } /* Check if there are no special contents actions to take. */ if (ppcSC == NULL) { goto remove_done; } if (pcroot == NULL) pcroot = "/"; if (pcroot[strlen(pcroot) - 1] == '/') { if (snprintf(cpath, PATH_MAX, "%s%s", pcroot, pccontents) >= PATH_MAX || snprintf(tcpath, PATH_MAX, "%s%s", pcroot, pctcontents) >= PATH_MAX) { progerr(gettext(SPECIAL_INPUT)); result = -1; goto remove_done; } } else { if (snprintf(cpath, PATH_MAX, "%s/%s", pcroot, pccontents) >= PATH_MAX || snprintf(tcpath, PATH_MAX, "%s/%s", pcroot, pctcontents) >= PATH_MAX) { progerr(gettext(SPECIAL_INPUT)); result = -1; goto remove_done; } } /* Open the temporary contents file to write, contents to read. */ if (access(cpath, F_OK | R_OK) != 0) { /* * This is not a problem since no contents means nothing * to remove due to special contents rules. */ result = 0; cpath[0] = '\0'; /* This signals omission of 'rename cleanup' */ goto remove_done; } if (access(cpath, W_OK) != 0) { /* can't write contents file, something is wrong. */ progerr(gettext(SPECIAL_ACCESS)); result = 1; goto remove_done; } if ((fpi = fopen(cpath, "r")) == NULL) { /* Given the access test above, this should not happen. */ progerr(gettext(SPECIAL_ACCESS)); result = 1; goto remove_done; } if ((fpo = fopen(tcpath, "w")) == NULL) { /* open t.contents failed */ progerr(gettext(SPECIAL_ACCESS)); result = 1; goto remove_done; } if (generate_special_contents_rules(ient, ppcfent, ppcSC, max, &piIndex) != 0) { result = 1; goto remove_done; } /* * Copy contents to t.contents unless there is an entry in * the ppcfent array which corresponds to an index set to 1. * * These items are the removed package contents which matche an * entry in ppcSC (the special_contents rules). * * Since both the contents and rules are sorted, we can * make a single efficient pass. */ (void) memset(line, 0, LINESZ); for (i = 0, j = 0; fgets(line, LINESZ, fpi) != NULL; ) { char *pcpath = NULL; /* * Note: This could be done better: We should figure out * which are the last 2 lines and only trim those off. * This will suffice to do this and will only be done as * part of special_contents handling. */ if (line[0] == '#') continue; /* Do not copy the final 2 comment lines */ pcpath = get_path(line); if (pcpath != NULL && i < ient) { int k; while (piIndex[i] == 0) i++; if (i < ient) k = pathcmp(pcpath, ppcfent[i]); if (k < 0 || i >= ient) { /* Just copy contents -> t.contents */ /*EMPTY*/ } else if (k == 0) { /* We have a match. Do not copy the content. */ i++; free(pcpath); (void) memset(line, 0, LINESZ); continue; } else while (i < ient) { /* * This is a complex case: The content * entry is further along alphabetically * than the rule. Skip over all rules which * apply until we come to a rule which is * greater than the current entry, or equal * to it. If equal, do not copy, otherwise * do copy the entry. */ if (piIndex[i] == 0) { i++; continue; } else if ((k = pathcmp(pcpath, ppcfent[i])) >= 0) { i++; if (k == 0) { free(pcpath); (void) memset(line, 0, LINESZ); break; } } else { /* path < rule, end special case */ break; } } /* * Avoid copying the old content when path == rule * This occurs when the complex case ends on a match. */ if (k == 0) continue; } if (fprintf(fpo, "%s", line) < 0) { /* Failing to write output would be catastrophic. */ progerr(gettext(SPECIAL_ACCESS)); result = 1; break; } (void) memset(line, 0, LINESZ); } t = time(NULL); (void) fprintf(fpo, "# Last modified by pkgremove\n"); (void) fprintf(fpo, "# %s", ctime(&t)); remove_done: free_special_contents(&ppcSC, max); if (fpi != NULL) (void) fclose(fpi); if (fpo != NULL) (void) fclose(fpo); if (result == 0) { if (tcpath[0] != '\0' && cpath[0] != '\0' && rename(tcpath, cpath) != 0) { progerr(gettext(SPECIAL_ACCESS)); result = 1; } } else { if (tcpath[0] != '\0' && remove(tcpath) != 0) { /* * Do not output a diagnostic message. This condition * occurs only when we are unable to clean up after * a failure. A temporary file will linger. */ result = 1; } } return (result); }
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 struct metaEntry *getHTMLMeta(IndexFILE * indexf, char *tag, SWISH *sw, char *name, char **parsed_tag, char *filename) { char *temp; int lenword = 0; char *word = NULL; char buffer[MAXSTRLEN + 1]; int i; struct metaEntry *e = NULL; word = buffer; lenword = sizeof(buffer) - 1; if (!name) { if (!(temp = (char *) lstrstr((char *) tag, (char *) "NAME"))) return NULL; } else temp = name; temp += 4; /* strlen("NAME") */ /* Get to the '=' sign disreguarding any other char */ while (*temp) { if (*temp && (*temp != '=')) /* TAB */ temp++; else { temp++; break; } } /* Get to the beginning of the word disreguarding blanks and quotes */ /* TAB */ while (*temp) { if (*temp == ' ' || *temp == '"') temp++; else break; } /* Copy the word and convert to lowercase */ /* TAB */ /* while (temp !=NULL && strncmp(temp," ",1) */ /* && strncmp(temp,"\"",1) && i<= MAXWORDLEN ) { */ /* and the above <= was wrong, should be < which caused the null insertion below to be off by two bytes */ for (i = 0; temp != NULL && *temp && *temp != ' ' && *temp != '"';) { if (i == lenword) { lenword *= 2; if(word == buffer) { word = (char *) emalloc(lenword + 1); memcpy(word,buffer,sizeof(buffer)); } else word = (char *) erealloc(word, lenword + 1); } word[i] = *temp++; i++; } if (i == lenword) { lenword *= 2; word = (char *) erealloc(word, lenword + 1); } word[i] = '\0'; /* Use Rainer's routine */ strtolower(word); *parsed_tag = word; if ((e = getMetaNameByName(&indexf->header, word))) return e; if ( (sw->UndefinedMetaTags == UNDEF_META_AUTO) && word && *word) { if (sw->verbose) printf("Adding automatic MetaName '%s' found in file '%s'\n", word, filename); return addMetaEntry(&indexf->header, word, META_INDEX, 0); } /* If it is ok not to have the name listed, just index as no-name */ if (sw->UndefinedMetaTags == UNDEF_META_ERROR) progerr("UndefinedMetaNames=error. Found meta name '%s' in file '%s', not listed as a MetaNames in config", word, filename); if(word != buffer) efree(word); return NULL; }
/* * valid_zone_attr: Validates the zone attributes specified in * pkginfo file for this package. The package * can not be created with certain combinations * of the attributes. */ static boolean_t valid_zone_attr(struct cfent **eptlist) { FILE *pkginfoFP; boolean_t all_zones; /* pkg is "all zones" only */ boolean_t is_hollow; /* pkg is "hollow" */ boolean_t this_zone; /* pkg is "this zone" only */ char pkginfoPath[PATH_MAX]; /* pkginfo file path */ char *pkgInst; int i; /* Path to pkginfo file within the package to be installed */ this_zone = B_FALSE; for (i = 0; eptlist[i]; i++) { if (eptlist[i]->ftype != 'i') continue; if (strcmp(eptlist[i]->path, "pkginfo") == 0) (void) strcpy(pkginfoPath, eptlist[i]->ainfo.local); /* * Check to see if this package has a request script. If this * package does have a request script, then mark the package * for installation in this zone only. Any package with a * request script cannot be installed outside of the zone the * pkgadd command is being run in, nor can such a package be * installed as part of a new zone install. A new zone install * must be non-interactive, which is required by all packages * integrated into the Solaris WOS. * If request file is set in prototype, then this_zone is TRUE. */ if (strcmp(eptlist[i]->path, "request") == 0) this_zone = B_TRUE; } /* Gather information from the pkginfo file */ pkginfoFP = fopen(pkginfoPath, "r"); if (pkginfoFP == NULL) { progerr(ERR_NO_PKG_INFOFILE, pkginfoPath, strerror(errno)); return (B_FALSE); } if ((pkgInst = fpkgparam(pkginfoFP, "PKG")) == NULL) { progerr(gettext(ERR_NOPARAM), "PKG", pkginfoPath); return (B_FALSE); } /* Determine "HOLLOW" setting for this package */ is_hollow = pkginfoParamTruth(pkginfoFP, PKG_HOLLOW_VARIABLE, "true", B_FALSE); /* Determine "ALLZONES" setting for this package */ all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE, "true", B_FALSE); /* Determine "THISZONE" setting for this package, if no request file */ if (!this_zone) this_zone = pkginfoParamTruth(pkginfoFP, PKG_THISZONE_VARIABLE, "true", B_FALSE); /* Close pkginfo file */ (void) fclose(pkginfoFP); /* * Validate zone attributes based on information gathered, * and validate the three SUNW_PKG_ options: * * -----------------------------|---------------| * <ALLZONES><HOLLOW><THISZONE> | If Allowed | * ----1------------------------|---------------| * F F F | OK | * F F T | OK | * F T * | NO | * ----2------------------------|---------------| * T F F | OK | * T T F | OK | * T * T | NO | * -----------------------------|---------------| */ /* pkg "all zones" && "this zone" (#2) */ if (all_zones && this_zone) { progerr(ERR_ALLZONES_AND_THISZONE, pkgInst, PKG_ALLZONES_VARIABLE, PKG_THISZONE_VARIABLE); return (B_FALSE); } /* pkg "!all zones" && "hollow" (#1) */ if ((!all_zones) && is_hollow) { progerr(ERR_NO_ALLZONES_AND_HOLLOW, pkgInst, PKG_ALLZONES_VARIABLE, PKG_HOLLOW_VARIABLE); return (B_FALSE); } return (B_TRUE); }
void replace_maybe_replies(const char *filename, struct emailinfo *ep, int new_reply_to) { char tmpfilename[MAXFILELEN]; char buffer[MAXLINE]; FILE *fp1, *fp2; struct emailinfo *ep2; int in_body = 0; char *ptr; static const char *prev_patt0 = ".html\">[ Previous ]</a>"; if (!hashnumlookup(new_reply_to, &ep2)) return; snprintf(tmpfilename, sizeof(tmpfilename), "%s/aaaa.tmp", set_dir); /* AUDIT biege: poss. BOF. */ if ((fp1 = fopen(filename, "r")) == NULL) { snprintf(errmsg, sizeof(errmsg), "Couldn't read \"%s\".", filename); progerr(errmsg); } if ((fp2 = fopen(tmpfilename, "w")) == NULL) { snprintf(errmsg, sizeof(errmsg), "Couldn't write \"%s\".", tmpfilename); progerr(errmsg); } while (fgets(buffer, sizeof(buffer), fp1)) { if (strstr(buffer, "<!-- body=\"end\" -->\n")) in_body = 0; if (!strcmp(buffer, "<!-- body=\"start\" -->\n")) in_body = 1; if (!in_body) { if (!strcmp(buffer, "<!-- unextthread=\"start\" -->\n")) { char *tmpptr = convchars(ep2->subject, ep2->charset); if (tmpptr) { char *path = get_path(ep, ep2); fprintf(fp2,"[ <a href=\"%s%.4d.%s\" title=\"%s: "%s"\">%s</a> ]\n", path, new_reply_to, set_htmlsuffix, lang[MSG_LTITLE_IN_REPLY_TO], ep2->name, tmpptr ? tmpptr : ""); free(tmpptr); } } else if (!strcmp(buffer, "<!-- lnextthread=\"start\" -->\n")) { char *tmpptr = convchars(ep2->subject, ep2->charset); if (tmpptr) { char *path = get_path(ep, ep2); fprintf(fp2, "<li><dfn>%s</dfn> " "<a href=\"%s%.4d.%s\" title=\"%s\">%s: \"%s\"</a></li>\n", lang[MSG_IN_REPLY_TO], path, new_reply_to, set_htmlsuffix, lang[MSG_LTITLE_IN_REPLY_TO], ep2->name, tmpptr ? tmpptr : ""); free(tmpptr); } } else if (!strcmp(buffer, "<!-- nextthread=\"start\" -->\n")) { char *tmpptr = convchars(ep2->subject, ep2->charset); if (tmpptr) { char *path = get_path(ep, ep2); fprintf(fp2, "<li> <strong>%s:</strong> " "<a href=\"%s%.4d.%s\">%s: \"%s\"</a>\n", lang[MSG_IN_REPLY_TO], path, new_reply_to, set_htmlsuffix, ep2->name, tmpptr ? tmpptr : ""); free(tmpptr); } } else { static const char *patts[] = { "<b>Maybe in reply to:</b>", "<strong>%s:</strong>", "<b>In reply to:</b>", "<strong>%s:</strong>", "<li> <b>Previous message:</b> <a href=\"", "<li> <strong>%s:</strong> <a href=\"", "<li><dfn>%s</dfn>: <a href=\"", "<li><dfn>%s</dfn>: <a href=\"", "<li><dfn>%s</dfn>: <a href=\"", NULL }; static const int indices[] = { MSG_MAYBE_IN_REPLY_TO, MSG_MAYBE_IN_REPLY_TO, MSG_IN_REPLY_TO, MSG_IN_REPLY_TO, MSG_PREVIOUS_MESSAGE, MSG_PREVIOUS_MESSAGE, MSG_MAYBE_IN_REPLY_TO, MSG_IN_REPLY_TO, MSG_PREVIOUS_MESSAGE }; int i; int surpress = 0; for (i = 0; patts[i]; ++i) { char temp[256]; snprintf(temp,sizeof(temp), patts[i], lang[indices[i]]); if ((ptr = strcasestr(buffer, temp)) && (i < 4 || new_reply_to == atoi(ptr + strlen(temp)))) { surpress = 1; break; } } if (surpress) continue; } /* check for old critmail format */ if ((ptr = strstr(buffer, prev_patt0)) && new_reply_to == atoi(ptr - 4) && !strncasecmp(ptr - 13, "<a href", 7)) { ptr[-13] = 0; } } fputs(buffer, fp2); } fclose(fp1); fclose(fp2); if (rename(tmpfilename, filename) == -1) { snprintf(errmsg, sizeof(errmsg), "Couldn't rename \"%s\" to %s.", tmpfilename, filename); progerr(errmsg); } }
/* * This scans the admin directories for the class acton scripts associated * with the classes to be installed. It will look for install or remove * scripts and place appropriate pointers into the cl_Classes list. There's * no reason why it couldn't look for both except that I haven't seen a * need for it yet. */ void find_CAS(int CAS_type, char *pkgbin, char *instdir) { int i; char path[PATH_MAX]; if (instdir == NULL || pkgbin == NULL) { progerr(gettext(ERR_NO_PATH)); quit(99); } if (CAS_type == I_ONLY) { for (i = 0; i < cl_NClasses; i++) { /* * Locate appropriate installation class action * script, if any; look on media for script, * since it might be on the system due to a * previous installation. */ (void) sprintf(path, "%s/install/i.%s", instdir, cl_nam(i)); if (access(path, R_OK) == 0) { (void) sprintf(path, "%s/i.%s", pkgbin, cl_nam(i)); cl_Classes[i]->inst_script = qstrdup(path); continue; } (void) sprintf(path, "%s/i.%s", PKGSCR, cl_nam(i)); if (access(path, R_OK) == 0) { cl_Classes[i]->inst_script = qstrdup(path); continue; } /* * Provide CAS to uncompress and distribute a * compressed cpio archive for those older packages * that don't include their own. This is the first * point at which we know, it's an old package * without all the various pkginfo items set. * The default script is provided for all classes * in an old package which do not have their own * class action script. These are the criteria used * by the script that packs the archives. */ (void) sprintf(path, "%s/%s", PKGSCR, DEF_NONE_SCR); if (pkg_has_arch && cl_Classes[i]->inst_script == NULL) { cl_Classes[i]->src_verify = NOVERIFY; cl_Classes[i]->dst_verify = QKVERIFY; cl_Classes[i]->relpath_2_CAS = REL_2_CAS; if (access(path, R_OK) == 0) { cl_Classes[i]->inst_script = qstrdup(path); continue; } else { progerr(gettext(ERR_NO_NONE)); quit(99); } } } } else if (CAS_type == R_ONLY) { for (i = 0; i < cl_NClasses; i++) { (void) sprintf(path, "%s/install/r.%s", instdir, cl_nam(i)); if (access(path, R_OK) == 0) { (void) sprintf(path, "%s/r.%s", pkgbin, cl_nam(i)); cl_Classes[i]->rem_script = qstrdup(path); continue; } (void) sprintf(path, "%s/r.%s", PKGSCR, cl_nam(i)); if (access(path, R_OK) == 0) { cl_Classes[i]->rem_script = qstrdup(path); continue; } } } else { progerr(gettext(ERR_INVALID_CAS), CAS_type); quit(99); } }
int selpkg(char *p) { static char *selected; char buf[80]; char *root; register int i; if (p == NULL) { if (selected == NULL) { if (pkgcnt) { for (i = 0; i < pkgcnt; ++i) { /* bugid 1227628 */ root = get_inst_root(); if (root) (void) snprintf(buf, sizeof (buf), "%s/var/sadm/pkg/%s/pkginfo", root, pkg[i]); else (void) snprintf(buf, sizeof (buf), "/var/sadm/pkg/%s/pkginfo", pkg[i]); if (access(buf, F_OK)) logerr(gettext(WRN_NOPKG), pkg[i]); else logerr(gettext(EMPTY_PKG), pkg[i]); } } } else { for (i = 0; i < pkgcnt; ++i) { if (selected[i] == NULL) { root = get_inst_root(); if (root) (void) snprintf(buf, sizeof (buf), "%s/var/sadm/pkg/%s/pkginfo", root, pkg[i]); else (void) snprintf(buf, sizeof (buf), "/var/sadm/pkg/%s/pkginfo", pkg[i]); if (access(buf, F_OK)) logerr(gettext(WRN_NOPKG), pkg[i]); else logerr(gettext(EMPTY_PKG), pkg[i]); } } } return (0); /* return value not important */ } else if (pkgcnt == 0) return (1); else if (selected == NULL) { selected = (char *)calloc((unsigned)(pkgcnt+1), sizeof (char)); if (selected == NULL) { progerr(gettext(ERR_NOMEM), errno); exit(99); /*NOTREACHED*/ } } for (i = 0; i < pkgcnt; ++i) { if (pkgnmchk(p, pkg[i], 0) == 0) { if (selected != NULL) selected[i] = 'b'; return (1); } } return (0); }
/* * 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); } }
void fuzzy_or_die( IndexFILE *indexf, char *mode ) { indexf->header.fuzzy_data = set_fuzzy_mode( indexf->header.fuzzy_data, mode ); if ( !indexf->header.fuzzy_data ) progerr("Invalid FuzzyIndexingMode '%s' in config file", mode ); }
/* * 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 = malloc(strlen(tmpdir) + 12); sprintf(listfile, "%s/listXXXXXX", tmpdir); close(mkstemp(listfile)); 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; } } }
/* * This function confirms the presence of pkgmap and pkginfo and verifies * that the mandatory parameters are available in the environment. */ int pkgenv(char *pkginst, char *p_pkginfo, char *p_pkgmap) { FILE *fp; char *value, path[PATH_MAX], param[MAX_PKG_PARAM_LENGTH]; int errflg; errflg = 0; if (access(p_pkgmap, 0)) { progerr(gettext(ERR_PKGMAP), p_pkgmap); return (1); } if ((fp = fopen(p_pkginfo, "r")) == NULL) { progerr(gettext(ERR_PKGINFO), p_pkginfo); return (1); } param[0] = '\0'; while (value = fpkgparam(fp, param)) { if (strcmp("PATH", param)) putparam(param, value); free(value); param[0] = '\0'; } (void) fclose(fp); /* * verify that required parameters are now present in * the environment */ if ((pkgabrv = getenv("PKG")) == NULL) { progerr(gettext(ERR_NOPARAM), "PKG", path); errflg++; } if (pkgnmchk(pkgabrv, NULL, 0) || strchr(pkgabrv, '.')) { progerr(gettext(ERR_PKGBAD), pkgabrv); errflg++; } (void) snprintf(pkgwild, sizeof (pkgwild), "%s.*", pkgabrv); if ((pkgname = getenv("NAME")) == NULL) { progerr(gettext(ERR_NOPARAM), "NAME", path); errflg++; } if ((pkgarch = getenv("ARCH")) == NULL) { progerr(gettext(ERR_NOPARAM), "ARCH", path); errflg++; } if ((pkgvers = getenv("VERSION")) == NULL) { progerr(gettext(ERR_NOPARAM), "VERSION", path); errflg++; } if (getenv("CATEGORY") == NULL) { progerr(gettext(ERR_NOPARAM), "CATEGORY", path); errflg++; } /* * verify consistency between PKG parameter and pkginst that * was determined from the directory structure */ (void) snprintf(param, sizeof (param), "%s.*", pkgabrv); if (pkgnmchk(pkginst, param, 0)) { progerr(gettext(ERR_PKGMTCH), pkgabrv, pkginst); errflg++; } return (errflg); }
/* * This function goes through and fixes all the attributes. This is called * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary * use for this is to fix up files installed by a class action script * which is time-critical and reliable enough to assume likely success. * The first such format was for WOS compressed-cpio'd file sets. * The second format is the Class Archive Format. */ static int fix_attributes(struct cfextra **extlist, int idx) { struct cfextra *ext; int i, retval = 1; int nc = cl_getn(); int n; struct cfent *ept; struct mergstat *mstat; char scrpt_dst[PATH_MAX]; char *pspool_loc; char *relocpath = (char *)NULL; for (i = 0; extlist[i]; i++) { ext = extlist[i]; ept = &(extlist[i]->cf_ent); mstat = &(extlist[i]->mstat); /* * We don't care about 'i'nfo files because, they * aren't laid down, 'e'ditable files can change * anyway, so who cares and 's'ymlinks were already * fixed in domerg(); however, certain old WOS * package symlinks depend on a bug in the old * pkgadd which has recently been expunged. For * those packages in 2.2, we repeat the verification * of symlinks. * * By 2.6 or so, ftype == 's' should be added to this. */ if (ept->ftype == 'i' || ept->ftype == 'e' || (mstat->shared && nocnflct)) continue; if (mstat->denied) { progerr(ERR_COULD_NOT_INSTALL, ept->path); warnflag++; continue; } if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) { progerr(ERR_CLIDX, ept->pkg_class_idx, (ept->path && *ept->path) ? ept->path : "unknown"); continue; } /* If this is the right class, do the fast verify. */ if (ept->pkg_class_idx == idx) { if (fverify(1, &ept->ftype, ept->path, &ept->ainfo, &ept->cinfo) == 0) { mstat->attrchg = 0; mstat->contchg = 0; } else /* We'll try full verify later */ retval = 0; } /* * Need to copy the installed volitale file back to the * partial spooled area if we are installing to a local zone * or similar installation method. */ 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, ept->path, scrpt_dst, 0644)) { warnflag++; } } } return (retval); }
void check1dir(char *dir) { struct stat sbuf; if (stat(dir, &sbuf)) { /* ** LCC only has the short mkdir(). Fortunately, we do a chmod ** immediately afterward, so it's a don't care. */ #ifdef __LCC__ if (errno != ENOENT || mkdir(dir) < 0) { #else if (errno != ENOENT || mkdir(dir, set_dirmode) < 0) { #endif if (errno != EEXIST) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\".", lang[MSG_CANNOT_CREATE_DIRECTORY], dir); progerr(errmsg); } } if (set_showprogress) printf(" %s \"%s\", %s %o.\n", lang[MSG_CREATING_DIRECTORY], dir, lang[MSG_MODE], set_dirmode); if (chmod(dir, set_dirmode) == -1) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\" to %o.", lang[MSG_CANNOT_CHMOD], dir, set_dirmode); progerr(errmsg); } } } /* ** This tries to create and chmod a path to a directory. */ void checkdir(char *dir) { register char *p; struct stat sbuf; int ch; p = dir; if (*p && *p == '/') /* get off root */ p++; for (;; ++p) { if (!*p || *p == '/') { ch = *p; *p = '\0'; if (stat(dir, &sbuf)) { /* See comment in check1dir */ #ifdef __LCC__ if (errno != ENOENT || mkdir(dir) < 0) { #else if (errno != ENOENT || mkdir(dir, set_dirmode) < 0) { #endif if (errno != EEXIST) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\".", lang[MSG_CANNOT_CREATE_DIRECTORY], dir); progerr(errmsg); } } if (set_report_new_folder) { printf("%s\n", dir); } if (set_showprogress) printf(" %s \"%s\", %s %o.\n", lang[MSG_CREATING_DIRECTORY], dir, lang[MSG_MODE], set_dirmode); if (chmod(dir, set_dirmode) == -1) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\" to %o.", lang[MSG_CANNOT_CHMOD], dir, set_dirmode); progerr(errmsg); } } *p = ch; if (!*p) break; } } } char *getfilecontents(char *filename) { FILE *infile; struct stat finfo; char *retval; if ((infile = fopen(filename, "r")) == NULL) return (NULL); if (fstat(fileno(infile), &finfo) != 0) { (void)fclose(infile); return (NULL); } if (finfo.st_size == 0) { (void)fclose(infile); return (NULL); } else { if (!(retval = (char *)malloc((unsigned)finfo.st_size + 1))) { (void)fclose(infile); return (NULL); } if (!fread(retval, (size_t) finfo.st_size, 1, infile)) { (void)fclose(infile); free(retval); return (NULL); } *(retval + finfo.st_size) = '\0'; } (void)fclose(infile); return (retval); } /* ** expand_path - fill in values substituting for magic cookies ** ** Substitution cookies supported ** ** %d - two digit day of month (1-28/30/31) ** %D - three letter day of the week ** %m - two digit month of year (1-12) ** %M - three letter month of year (Jan, Feb, ..., Dec) ** %y - four digit year (1990,..2001) ** ** Returns: expanded path string */ char *dirpath(char *frmptr) { register char *aptr; char dtstr[DATESTRLEN]; char c; struct tm *now; time_t clk; struct Push buff; INIT_PUSH(buff); clk = time((time_t *)0); now = localtime(&clk); aptr = frmptr; while ((c = *aptr++)) { if (c == '%') { switch (*aptr++) { case '%': /* Add the % character */ PushByte(&buff, '%'); continue; case 'd': /* two digit day of month (1-31) */ sprintf(dtstr, "%.2d", now->tm_mday); PushString(&buff, dtstr); continue; case 'D': /* three letter day of week */ PushString(&buff, days[now->tm_wday]); continue; case 'j': /* julian date */ sprintf(dtstr, "%.3d", now->tm_yday); PushString(&buff, dtstr); continue; case 'm': /* two digit month of year (1-12) */ sprintf(dtstr, "%.2d", now->tm_mon + 1); PushString(&buff, dtstr); continue; case 'M': /* three letter month of year */ PushString(&buff, months[now->tm_mon]); continue; case 'y': /* 4 digit year */ sprintf(dtstr, "%.4d", now->tm_year + 1900); PushString(&buff, dtstr); continue; default: PushString(&buff, "%?"); continue; } /* end switch */ } PushByte(&buff, c); } /* end while */ RETURN_PUSH(buff); } /* ** Reads a configuration file if it exists and puts all the right ** values into the right variables. */ void readconfigs(char *path, int cmd_show_variables) { if (path && path[0] == '~') { char *ep; char tmppath[MAXFILELEN]; /*AUDIT biege: pathname + filename is more then 4KB long on linux */ struct passwd *pp; #ifndef __LCC__ /* ** Getting password data from /etc/passwd is pretty silly in ** Win9x systems since nearly everybody builds this file after ** they set up $HOME. Just skip this try at finding a default ** location for the config file and go on to try $HOME. */ if ((pp = getpwuid(getuid())) != NULL) { snprintf(tmppath, sizeof(tmppath), "%s%s", pp->pw_dir, path + 1); /* AUDIT biege: who gurantees that path+1 contains data? */ ConfigInit(tmppath); } else #endif if ((ep = getenv("HOME")) != NULL) { /* AUDIT biege: possible BOF.. but it's not setuid.. so why to care? */ snprintf(tmppath, sizeof(tmppath), "%s%s", ep, path + 1); /* AUDIT biege: who gurantees that path+1 contains data? */ ConfigInit(tmppath); } /* * So what happens here if the above two conditions fail ???? * Simply use the compiled in defaults ? */ } else { ConfigInit(path); if (set_showprogress && !cmd_show_variables) printf("%s: %s\n", lang[MSG_PATH], path); } } void symlink_latest() { /* ** Symlinks work so differently in Windows that I think we'll just ** skip that whole thing and ignore that option. */ #ifdef __LCC__ snprintf(errmsg, sizeof(errmsg), "WARNING: latest_folder not supported in Win32 environment.\n"); fprintf(stderr, "%s", errmsg); #else char filename[MAXFILELEN]; struct stat stbuf; if (!latest_folder_path) return; /* haven't created new folder this time? */ trio_snprintf(filename, MAXFILELEN, "%s%s", set_dir, set_latest_folder); if (!stat(filename, &stbuf) && unlink(filename)) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\" (latest_folder option).", lang[MSG_CANNOT_UNLINK], filename); progerr(errmsg); return; } if (symlink(latest_folder_path, filename)) { snprintf(errmsg, sizeof(errmsg), "%s \"%s\" (latest_folder option).", lang[MSG_CANNOT_CREATE_SYMLINK], filename); progerr(errmsg); return; } #endif }
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 (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 rmclass(char *aclass, int rm_remote, char *a_zoneName) { struct cfent *ept; FILE *fp; char tmpfile[PATH_MAX]; char script[PATH_MAX]; int i; char *tmp_path; char *save_path = NULL; struct stat st; if (aclass == NULL) { for (i = 0; i < eptnum; i++) { if (eptlist[i] != NULL) { rmclass(eptlist[i]->pkg_class, rm_remote, a_zoneName); } } return; } /* locate class action script to execute */ (void) snprintf(script, sizeof (script), "%s/r.%s", pkgbin, aclass); if (access(script, F_OK) != 0) { (void) snprintf(script, sizeof (script), "%s/r.%s", PKGSCR, aclass); if (access(script, F_OK) != 0) script[0] = '\0'; } if (script[0] != '\0') { int td; (void) snprintf(tmpfile, sizeof (tmpfile), "%s/RMLISTXXXXXX", tmpdir); td = mkstemp(tmpfile); if (td == -1) { progerr(ERR_TMPFILE); quit(99); } if ((fp = fdopen(td, "w")) == NULL) { progerr(ERR_WTMPFILE, tmpfile); quit(99); } } if (a_zoneName == (char *)NULL) { echo(MSG_PKGREMOVE_REMPATHCLASS_GZ, aclass); } else { echo(MSG_PKGREMOVE_REMPATHCLASS_LZ, aclass, a_zoneName); } /* process paths in reverse order */ i = eptnum; while (--i >= 0) { ept = eptlist[i]; if ((ept == NULL) || strcmp(aclass, ept->pkg_class)) { continue; } /* save the path, and prepend the ir */ if (is_an_inst_root()) { save_path = ept->path; tmp_path = fixpath(ept->path); ept->path = tmp_path; } if (!ept->ftype || (ept->ftype == '^' && !script[0])) { /* * A path owned by more than one package is marked with * a NULL ftype (seems odd, but that's how it's * done). Such files are sacro sanct. Shared editable * files are a special case, and are marked with an * ftype of '^'. These files should only be ignored if * no class action script is present. It is the CAS's * responsibility to not remove the editable object. */ echo(MSG_SHARED, ept->path); } else if (ept->pinfo->status == SERVED_FILE && !rm_remote) { /* * If the path is provided to the client from a * server, don't remove anything unless explicitly * requested through the "-f" option. */ echo(MSG_SERVER, ept->path); } else if (script[0]) { /* * If there's a class action script, just put the * path name into the list. */ (void) fprintf(fp, "%s\n", ept->path); } else if (strchr("dx", ept->ftype) != NULL || (lstat(ept->path, &st) == 0 && S_ISDIR(st.st_mode))) { /* Directories are rmdir()'d. */ if (rmdir(ept->path)) { if (errno == EBUSY) { echo(MSG_DIRBUSY, ept->path); } else if (errno == EEXIST) { echo(MSG_NOTEMPTY, ept->path); } else if (errno != ENOENT) { progerr(ERR_RMDIR, ept->path); warnflag++; } } else { if (ept->pinfo->status == SERVED_FILE) { echo(MSG_RMSRVR, ept->path); } else { echo("%s", ept->path); } } } else { /* * Before removing this object one more * check should be done to assure that a * shared object is not removed. * This can happen if the original object * was incorrectly updated with the * incorrect class identifier. * This handles pathologcal cases that * weren't handled above. */ if (ept->npkgs > 1) { echo(MSG_SHARED, ept->path); continue; } /* Regular files are unlink()'d. */ if (unlink(ept->path)) { if (errno != ENOENT) { progerr(ERR_RMPATH, ept->path); warnflag++; } } else { if (ept->pinfo->status == SERVED_FILE) { echo(MSG_RMSRVR, ept->path); } else { echo("%s", ept->path); } } } /* restore the original path */ if (is_an_inst_root()) { ept->path = save_path; } /* * free memory allocated for this entry memory used for * pathnames will be freed later by a call to pathdup() */ if (eptlist[i]) { free(eptlist[i]); } eptlist[i] = NULL; } if (script[0]) { (void) fclose(fp); set_ulimit(script, ERR_CASFAIL); if (pkgverbose) ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, "-x", script, NULL), ERR_CASFAIL); else ckreturn(pkgexecl(tmpfile, CAS_STDOUT, CAS_USER, CAS_GRP, SHELL, script, NULL), ERR_CASFAIL); clr_ulimit(); if (isfile(NULL, tmpfile) == 0) { if (unlink(tmpfile) == -1) progerr(ERR_RMPATH, tmpfile); } } }
static char * check_db_entry(VFP_T *vfpo, struct cfextra *entry, int rmflag, char *myclass, int *dbchg) { struct pinfo *pinfo; int fs_entry; char *save_path = NULL; char *tp; /* write this entry to the contents file */ if (myclass && strcmp(myclass, entry->cf_ent.pkg_class)) { if (putcvfpfile(&entry->cf_ent, vfpo)) { progerr(gettext(ERR_WRITE)); quit(99); } return (NULL); } /* * Now scan each package instance holding this file or * directory and see if it matches the package we are * updating here. */ pinfo = entry->cf_ent.pinfo; while (pinfo) { if (strcmp(pkginst, pinfo->pkg) == 0) break; pinfo = pinfo->next; } /* * If pinfo == NULL at this point, then this file or * directory isn't part of the package of interest. * So the loop below executes only on files in the package * of interest. */ save_path = NULL; if (pinfo) { if (rmflag && (pinfo->status == RM_RDY)) { *dbchg = 1; (void) eptstat(&(entry->cf_ent), pkginst, '@'); if (entry->cf_ent.npkgs) { if (putcvfpfile(&(entry->cf_ent), vfpo)) { progerr(gettext(ERR_WRITE)); quit(99); } } return (NULL); } else if (!rmflag && (pinfo->status == INST_RDY)) { *dbchg = 1; /* tp is the server-relative path */ tp = fixpath(entry->cf_ent.path); /* save_path is the cmd line path */ save_path = entry->cf_ent.path; /* entry has the server-relative path */ entry->cf_ent.path = tp; /* * The next if statement figures out how * the contents file entry should be * annotated. * * Don't install or verify objects for * remote, read-only filesystems. We * need only verify their presence and * flag them appropriately from some * server. Otherwise, ok to do final * check. */ fs_entry = fsys(entry->cf_ent.path); if (is_remote_fs_n(fs_entry) && !is_fs_writeable_n(fs_entry)) { /* * Mark it shared whether it's present * or not. life's too funny for me * to explain. */ pinfo->status = SERVED_FILE; /* * restore for now. This may * chg soon. */ entry->cf_ent.path = save_path; } else { /* * If the object is accessible, check * the new entry for existence and * attributes. If there's a problem, * mark it NOT_FND; otherwise, * ENTRY_OK. */ if (is_mounted_n(fs_entry)) { int n; n = finalck((&entry->cf_ent), 1, 1, B_FALSE); pinfo->status = ENTRY_OK; if (n != 0) { pinfo->status = NOT_FND; } } /* * It's not remote, read-only but it * may look that way to the client. * If it does, overwrite the above * result - mark it shared. */ if (is_served_n(fs_entry)) pinfo->status = SERVED_FILE; /* restore original path */ entry->cf_ent.path = save_path; /* and clear save_path */ save_path = NULL; } } } /* Output entry to contents file. */ if (putcvfpfile(&(entry->cf_ent), vfpo)) { progerr(gettext(ERR_WRITE)); quit(99); } return (save_path); }
void print_all_threads(FILE *fp, int year, int month, struct emailinfo *email) { int level = 0; int newlevel; int i; int prev = -1; int hide_level = 0; int thread_file_depth = (year == -1 && month == -1 ? set_thread_file_depth : 0); static int reply_list_count = 0; int stack[MAXSTACK + 1]; /* should be dynamic - this will do for now */ FILE *fp_stack[MAXSTACK + 1]; int num_replies[MAXSTACK + 1]; char *filename_stack[MAXSTACK + 1]; char *subject_stack[MAXSTACK + 1]; struct emailsubdir *subdir = email ? email->subdir : NULL; struct emailinfo *last_email; FILE *fp_body = NULL; char *filenameb = NULL; int threadnum = 0; bool is_first = TRUE; struct reply *rp = threadlist; last_email = rp->data; if (!last_email && rp->msgnum == -1 && set_files_by_thread) { progerr("files_by_thread error start with rp->msgnum == -1"); } for (i = 0; i <= MAXSTACK; i++) num_replies[i] = num_open_li[i] = 0; while (rp != NULL) { #if DEBUG_THREAD fprintf(stderr, "print_all_threads: message %d prev %d level %d\n", rp->msgnum, prev, level); #endif if (rp->msgnum == -1) { level = finish_thread_levels(&fp, level, 0, num_replies, fp_stack, filename_stack, subject_stack, thread_file_depth, email, last_email, filenameb, fp_body); filenameb = NULL; rp = rp->next; continue; } else if(level == 0 && subdir && rp->data->subdir != subdir) { rp = rp->next; continue; } #if DEBUG_THREAD fprintf(stderr, "print_all_threads: %d: %s\n", rp->msgnum, rp->data->name); #endif if (prev == -1) { level = finish_thread_levels(&fp, level, 0, num_replies, fp_stack, filename_stack, subject_stack, thread_file_depth, email, rp->data, filenameb, fp_body); filenameb = NULL; stack[level] = rp->msgnum; } else if (hide_level) { ; /* don't change level */ } else if (rp->frommsgnum == prev) { if (level < MAXSTACK) level++; else fprintf(stderr, "thread level too deep - sticking at %d\n", MAXSTACK); stack[level] = rp->msgnum; num_replies[level] = 0; if (!set_indextable) { if (level < set_thrdlevels) { if (level > thread_file_depth) { fprintf(fp, "<ul>\n"); } else if (level < MAXSTACK) { char *filename; char subject[TITLESTRLEN]; trio_asprintf(&filename_stack[level], "%u%s", reply_list_count, index_name[subdir != NULL][THREAD_INDEX]); filename = htmlfilename(filename_stack[level], email, ""); /* AUDIT biege: What about using remove() to handle direc.c too? */ unlink(filename); /* so chmod won't fail if someone else owned it */ fp_stack[level - 1] = fp; if ((fp = fopen(filename, "w")) == NULL) { snprintf(errmsg,sizeof(errmsg),"Couldn't write \"%s\".", filename); progerr(errmsg); } sprintf(subject, "thread index level %d", level + 1); subject_stack[level] = strsav(subject); print_index_header(fp, set_label, set_dir, subject, filename); fprintf(fp, "<ul>\n"); free(filename); ++reply_list_count; } } else { /* if we go over the thread limit, we just close the last open li */ if (!set_indextable && num_open_li[level - 1] != 0) { fprintf (fp, "</li>\n"); num_open_li[level - 1]--; } } } } else { /* There are (I think) some optimisations possible here. * 1. could start loop at level-1 * Previous branch is just a special case of this branch - * possibly more efficient - probably not worth worrying about. * Paul 12-may-1999 */ for (i = level; i >= 0; i--) { if (stack[i] == rp->frommsgnum) { break; } } newlevel = i + 1; if (newlevel == level) { /* same level, close the previous item */ if (!set_indextable && num_open_li[level] != 0) { fprintf (fp, "</li>\n"); num_open_li[level]--; } } else if (newlevel > level) { /* I don't think this branch will be used - do the right thing anyway */ #if DEBUG_THREAD fprintf(stderr, "print_all_threads: unexpected: message %d - level changing from %d to %d\n", rp->msgnum, level, newlevel); #endif if (newlevel >= MAXSTACK) { fprintf(stderr, "thread level too deep - sticking at %d\n", MAXSTACK); newlevel = MAXSTACK; } if (!set_indextable) { while (level < newlevel) { if (level < set_thrdlevels) { fprintf(fp, "<li><ul>\n"); ++num_open_li[level]; } level++; } } } else { level = finish_thread_levels(&fp, level, newlevel, num_replies, fp_stack, filename_stack, subject_stack, thread_file_depth, email, rp->data, filenameb, fp_body); if (newlevel == 0) filenameb = NULL; } stack[newlevel] = rp->msgnum; } if (set_files_by_thread && level == 0) { char thread_id[256]; if (filenameb && last_email) { finish_thread_file(fp_body, last_email, filenameb); filenameb = NULL; } sprintf(thread_id, "thread_body%d", ++threadnum); filenameb = htmlfilename(thread_id, email, set_htmlsuffix); if ((fp_body = fopen(filenameb, "w")) == NULL) { snprintf(errmsg, sizeof(errmsg), "Couldn't write \"%s\".", filenameb); progerr(errmsg); } print_index_header(fp_body, set_label, set_dir, lang[MSG_BY_THREAD], filenameb); fprint_menu0(fp_body, rp->data, PAGE_TOP); } /* Now print this mail */ if ((year == -1 || year_of_datenum(rp->data->date) == year) && (month == -1 || month_of_datenum(rp->data->date) == month) && !rp->data->is_deleted) { format_thread_info(fp, rp->data, level, num_replies, email, fp_body, threadnum, is_first); if (is_first) is_first = FALSE; } prev = rp->msgnum; hide_level = (rp->data->is_deleted && rp->frommsgnum != rp->msgnum); last_email = rp->data; rp = rp->next; } if (!set_indextable && num_open_li[0] != 0) fprintf (fp, "</li>\n"); if (set_files_by_thread && filenameb && last_email) { finish_thread_file(fp_body, last_email, filenameb); filenameb = NULL; } }
int main(int argc, char *argv[]) { struct utsname utsbuf; struct statvfs64 svfsb; struct cfent **eptlist; FILE *fp; VFP_T *vfp; int i, c, n, eptnum, found, part, nparts, npkgs, objects; char buf[MAX_PKG_PARAM_LENGTH]; char temp[MAX_PKG_PARAM_LENGTH]; char param[MAX_PKG_PARAM_LENGTH]; char *pt, *value, *pkginst, *tmpdir, *abi_sym_ptr, **cmdparam; char *pkgname; char *pkgvers; char *pkgarch; char *pkgcat; void (*func)(); time_t clock; fsblkcnt_t bsize = 0; fsblkcnt_t frsize = 0; struct cl_attr **allclass = NULL; struct cl_attr **order; /* initialize locale environment */ (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); /* initialize program name */ (void) set_prog_name(argv[0]); /* tell spmi zones interface how to access package output functions */ z_set_output_functions(echo, echoDebug, progerr); func = sigset(SIGINT, trap); if (func != SIG_DFL) func = sigset(SIGINT, func); func = sigset(SIGHUP, trap); setmapmode(MAPBUILD); /* variable binding */ if (func != SIG_DFL) func = sigset(SIGHUP, func); environ = NULL; while ((c = getopt(argc, argv, "osnp:l:r:b:d:f:a:v:?")) != EOF) { switch (c) { case 'n': nflag++; break; case 's': sflag++; break; case 'o': overwrite++; break; case 'p': putparam("PSTAMP", optarg); break; case 'l': llimit = atol(optarg); break; case 'r': pt = strtok(optarg, " \t\n, "); n = 0; do { rootlist[n++] = flex_device(pt, 0); if (n >= NROOT) { progerr(gettext(ERR_NROOT), NROOT); quit(1); } } while (pt = strtok(NULL, " \t\n, ")); rootlist[n] = NULL; break; case 'b': basedir = optarg; break; case 'f': protofile = optarg; break; case 'd': device = flex_device(optarg, 1); break; case 'a': putparam("ARCH", optarg); break; case 'v': putparam("VERSION", optarg); break; default: usage(); } } /* * Store command line variable assignments for later * incorporation into the environment. */ cmdparam = &argv[optind]; /* Skip past equates. */ while (argv[optind] && strchr(argv[optind], '=')) optind++; /* Confirm that the instance name is valid */ if ((pkginst = argv[optind]) != NULL) { if (pkgnmchk(pkginst, "all", 0)) { progerr(gettext(ERR_PKGINST), pkginst); quit(1); } argv[optind++] = NULL; } if (optind != argc) usage(); tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = P_tmpdir; /* bug id 4244631, not ABI compliant */ abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS"); if (abi_sym_ptr && (strncasecmp(abi_sym_ptr, "TRUE", 4) == 0)) { set_nonABI_symlinks(); } if (device == NULL) { device = devattr(SPOOLDEV, "pathname"); if (device == NULL) { progerr(gettext(ERR_DEVICE), SPOOLDEV); exit(99); } } if (protofile == NULL) { if (access("prototype", 0) == 0) protofile = "prototype"; else if (access("Prototype", 0) == 0) protofile = "Prototype"; else { progerr(gettext(ERR_PROTOTYPE)); quit(1); } } if (devtype(device, &pkgdev)) { progerr(gettext(ERR_BADDEV), device); quit(1); } if (pkgdev.norewind) { /* initialize datastream */ progerr(gettext(ERR_DSTREAM), device); quit(1); } if (pkgdev.mount) { if (n = pkgmount(&pkgdev, NULL, 0, 0, 1)) quit(n); } /* * convert prototype file to a pkgmap, while locating * package objects in the current environment */ t_pkgmap = tempnam(tmpdir, "tmpmap"); if (t_pkgmap == NULL) { progerr(gettext(ERR_TEMP), errno); exit(99); } (void) fprintf(stderr, gettext(MSG_PROTOTYPE)); if (n = mkpkgmap(t_pkgmap, protofile, cmdparam)) { progerr(gettext(ERR_BUILD)); quit(1); } setmapmode(MAPNONE); /* All appropriate variables are now bound */ if (vfpOpen(&vfp, t_pkgmap, "r", VFP_NEEDNOW) != 0) { progerr(gettext(ERR_TEMP), errno); quit(99); } eptlist = procmap(vfp, 0, NULL); if (eptlist == NULL) { quit(1); } (void) vfpClose(&vfp); /* Validate the zone attributes in pkginfo, before creation */ if (!valid_zone_attr(eptlist)) { progerr(ERR_PKGINFO_INVALID_OPTION_COMB); quit(1); } (void) fprintf(stderr, gettext(MSG_PKGINFO)); pt = NULL; for (i = 0; eptlist[i]; i++) { ckmissing(eptlist[i]->path, eptlist[i]->ftype); if (eptlist[i]->ftype != 'i') continue; if (strcmp(eptlist[i]->path, "pkginfo") == 0) svept = eptlist[i]; } if (svept == NULL) { progerr(gettext(ERR_NOPKGINFO)); quit(99); } eptnum = i; /* * process all parameters from the pkginfo file * and place them in the execution environment */ if ((fp = fopen(svept->ainfo.local, "r")) == NULL) { progerr(gettext(ERR_RDPKGINFO), svept->ainfo.local); quit(99); } param[0] = '\0'; while (value = fpkgparam(fp, param)) { if (getenv(param) == NULL) putparam(param, value); free((void *)value); param[0] = '\0'; } (void) fclose(fp); /* add command line variables */ while (*cmdparam && (value = strchr(*cmdparam, '=')) != NULL) { *value = NULL; /* terminate the parameter */ value++; /* value is now the value (not '=') */ putparam(*cmdparam++, value); /* store it in environ */ } /* make sure parameters are valid */ (void) time(&clock); if (pt = getenv("PKG")) { if (pkgnmchk(pt, NULL, 0) || strchr(pt, '.')) { progerr(gettext(ERR_PKGABRV), pt); quit(1); } if (pkginst == NULL) pkginst = pt; } else { progerr(gettext(ERR_NOPARAM), "PKG", svept->path); quit(1); } /* * verify consistency between PKG parameter and pkginst */ (void) snprintf(param, sizeof (param), "%s.*", pt); if (pkgnmchk(pkginst, param, 0)) { progerr(gettext(ERR_PKGMTCH), pt, pkginst); quit(1); } /* * ********************************************************************* * this feature is removed starting with Solaris 10 - there is no built * in list of packages that should be run "the old way" * ********************************************************************* */ #ifdef ALLOW_EXCEPTION_PKG_LIST /* Until 2.9, set it from the execption list */ if (exception_pkg(pkginst, LINK)) set_nonABI_symlinks(); #endif if ((pkgname = getenv("NAME")) == NULL) { progerr(gettext(ERR_NOPARAM), "NAME", svept->path); quit(1); } if (ckparam("NAME", pkgname)) quit(1); if ((pkgvers = getenv("VERSION")) == NULL) { /* XXX - I18n */ /* LINTED do not use cftime(); use strftime instead */ (void) cftime(buf, "\045m/\045d/\045Y", &clock); (void) snprintf(temp, sizeof (temp), gettext("Dev Release %s"), buf); putparam("VERSION", temp); pkgvers = getenv("VERSION"); logerr(gettext(WRN_SETPARAM), "VERSION", temp); } if (ckparam("VERSION", pkgvers)) quit(1); if ((pkgarch = getenv("ARCH")) == NULL) { (void) uname(&utsbuf); putparam("ARCH", utsbuf.machine); pkgarch = getenv("ARCH"); logerr(gettext(WRN_SETPARAM), "ARCH", utsbuf.machine); } if (ckparam("ARCH", pkgarch)) quit(1); if (getenv("PSTAMP") == NULL) { /* use octal value of '%' to fight sccs expansion */ /* XXX - I18n */ /* LINTED do not use cftime(); use strftime instead */ (void) cftime(buf, "\045Y\045m\045d\045H\045M\045S", &clock); (void) uname(&utsbuf); (void) snprintf(temp, sizeof (temp), "%s%s", utsbuf.nodename, buf); putparam("PSTAMP", temp); logerr(gettext(WRN_SETPARAM), "PSTAMP", temp); } if ((pkgcat = getenv("CATEGORY")) == NULL) { progerr(gettext(ERR_NOPARAM), "CATEGORY", svept->path); quit(1); } if (ckparam("CATEGORY", pkgcat)) quit(1); /* * warn user of classes listed in package which do * not appear in CLASSES variable in pkginfo file */ objects = 0; for (i = 0; eptlist[i]; i++) { if (eptlist[i]->ftype != 'i') { objects++; addlist(&allclass, eptlist[i]->pkg_class); } } if ((pt = getenv("CLASSES")) == NULL) { if (allclass && *allclass) { cl_setl(allclass); cl_putl("CLASSES", allclass); logerr(gettext(WRN_SETPARAM), "CLASSES", getenv("CLASSES")); } } else { cl_sets(qstrdup(pt)); if (allclass && *allclass) { for (i = 0; allclass[i]; i++) { found = 0; if (cl_idx(allclass[i]->name) != -1) { found++; break; } if (!found) { logerr(gettext(WRN_CLASSES), (char *)allclass[i]); } } } } (void) fprintf(stderr, gettext(MSG_VOLUMIZE), objects); order = (struct cl_attr **)0; if (pt = getenv("ORDER")) { pt = qstrdup(pt); (void) setlist(&order, pt); cl_putl("ORDER", order); } /* stat the intended output filesystem to get blocking information */ if (pkgdev.dirname == NULL) { progerr(gettext(ERR_WHATVFS), device); quit(99); } if (statvfs64(pkgdev.dirname, &svfsb)) { progerr(gettext(ERR_STATVFS), pkgdev.dirname); quit(99); } if (bsize == 0) { bsize = svfsb.f_bsize; } if (frsize == 0) { frsize = svfsb.f_frsize; } if (limit == 0) /* * bavail is in terms of fragment size blocks - change * to 512 byte blocks */ limit = (((long)frsize > 0) ? howmany(frsize, DEV_BSIZE) : howmany(bsize, DEV_BSIZE)) * svfsb.f_bavail; if (ilimit == 0) { ilimit = (svfsb.f_favail > 0) ? svfsb.f_favail : svfsb.f_ffree; } nparts = splpkgmap(eptlist, eptnum, (char **)order, bsize, frsize, &limit, &ilimit, &llimit); if (nparts <= 0) { progerr(gettext(ERR_SPLIT)); quit(1); } if (nflag) { for (i = 0; eptlist[i]; i++) (void) ppkgmap(eptlist[i], stdout); exit(0); /*NOTREACHED*/ } (void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s", pkgdev.dirname, pkginst); if (!isdir(pkgloc) && !overwrite) { progerr(gettext(ERR_OVERWRITE), pkgloc); quit(1); } /* output all environment install parameters */ t_pkginfo = tempnam(tmpdir, "pkginfo"); if ((fp = fopen(t_pkginfo, "w")) == NULL) { progerr(gettext(ERR_TEMP), errno); exit(99); } for (i = 0; environ[i]; i++) { if (isupper(*environ[i])) { (void) fputs(environ[i], fp); (void) fputc('\n', fp); } } (void) fclose(fp); started++; (void) rrmdir(pkgloc); if (mkdir(pkgloc, 0755)) { progerr(gettext(ERR_MKDIR), pkgloc); quit(1); } /* determine how many packages already reside on the medium */ pkgdir = pkgdev.dirname; npkgs = 0; while (pt = fpkginst("all", NULL, NULL)) npkgs++; (void) fpkginst(NULL); /* free resource usage */ if (nparts > 1) { if (pkgdev.mount && npkgs) { progerr(gettext(ERR_ONEVOL)); quit(1); } } /* * update pkgmap entry for pkginfo file, since it may * have changed due to command line or failure to * specify all neccessary parameters */ for (i = 0; eptlist[i]; i++) { if (eptlist[i]->ftype != 'i') continue; if (strcmp(eptlist[i]->path, "pkginfo") == 0) { svept = eptlist[i]; svept->ftype = '?'; svept->ainfo.local = t_pkginfo; (void) cverify(0, &svept->ftype, t_pkginfo, &svept->cinfo, 1); svept->ftype = 'i'; break; } } if (nparts > 1) (void) fprintf(stderr, gettext(MSG_PACKAGEM), nparts); else (void) fprintf(stderr, gettext(MSG_PACKAGE1)); for (part = 1; part <= nparts; part++) { if ((part > 1) && pkgdev.mount) { if (pkgumount(&pkgdev)) { progerr(gettext(ERR_UMOUNT), pkgdev.mount); quit(99); } if (n = pkgmount(&pkgdev, NULL, part, nparts, 1)) quit(n); (void) rrmdir(pkgloc); if (mkdir(pkgloc, 0555)) { progerr(gettext(ERR_MKDIR), pkgloc); quit(99); } } outvol(eptlist, eptnum, part, nparts); /* Validate (as much as possible) the control scripts. */ if (part == 1) { char inst_path[PATH_MAX]; (void) fprintf(stderr, gettext(MSG_VALSCRIPTS)); (void) snprintf(inst_path, sizeof (inst_path), "%s/install", pkgloc); checkscripts(inst_path, 0); } } quit(0); /*NOTREACHED*/ }