示例#1
0
文件: parseSpec.c 项目: tomhughes/rpm
static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
                         const char *buildRoot, int recursing)
{
    int parsePart = PART_PREAMBLE;
    int initialPackage = 1;
    rpmSpec spec;

    /* Set up a new Spec structure with no packages. */
    spec = newSpec();

    spec->specFile = rpmGetPath(specFile, NULL);
    pushOFI(spec, spec->specFile);
    /* If buildRoot not specified, use default %{buildroot} */
    if (buildRoot) {
        spec->buildRoot = xstrdup(buildRoot);
    } else {
        spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL);
    }
    addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
    addMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC);
    spec->recursing = recursing;
    spec->flags = flags;

    /* All the parse*() functions expect to have a line pre-read */
    /* in the spec's line buffer.  Except for parsePreamble(),   */
    /* which handles the initial entry into a spec file.         */

    while (parsePart != PART_NONE) {
        int goterror = 0;
        switch (parsePart) {
        case PART_ERROR: /* fallthrough */
        default:
            goterror = 1;
            break;
        case PART_PREAMBLE:
            parsePart = parsePreamble(spec, initialPackage);
            initialPackage = 0;
            break;
        case PART_PREP:
            parsePart = parsePrep(spec);
            break;
        case PART_BUILD:
        case PART_INSTALL:
        case PART_CHECK:
        case PART_CLEAN:
            parsePart = parseBuildInstallClean(spec, parsePart);
            break;
        case PART_CHANGELOG:
            parsePart = parseChangelog(spec);
            break;
        case PART_DESCRIPTION:
            parsePart = parseDescription(spec);
            break;

        case PART_PRE:
        case PART_POST:
        case PART_PREUN:
        case PART_POSTUN:
        case PART_PRETRANS:
        case PART_POSTTRANS:
        case PART_VERIFYSCRIPT:
        case PART_TRIGGERPREIN:
        case PART_TRIGGERIN:
        case PART_TRIGGERUN:
        case PART_TRIGGERPOSTUN:
        case PART_FILETRIGGERIN:
        case PART_FILETRIGGERUN:
        case PART_FILETRIGGERPOSTUN:
        case PART_TRANSFILETRIGGERIN:
        case PART_TRANSFILETRIGGERUN:
        case PART_TRANSFILETRIGGERPOSTUN:
            parsePart = parseScript(spec, parsePart);
            break;

        case PART_FILES:
            parsePart = parseFiles(spec);
            break;

        case PART_POLICIES:
            parsePart = parsePolicies(spec);
            break;

        case PART_NONE:		/* XXX avoid gcc whining */
        case PART_LAST:
        case PART_BUILDARCHITECTURES:
            break;
        }

        if (goterror || parsePart >= PART_LAST) {
            goto errxit;
        }

        if (parsePart == PART_BUILDARCHITECTURES) {
            int index;
            int x;

            closeSpec(spec);

            spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
            index = 0;
            if (spec->BANames != NULL)
                for (x = 0; x < spec->BACount; x++) {

                    /* Skip if not arch is not compatible. */
                    if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
                        continue;
                    addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
                    spec->BASpecs[index] = parseSpec(specFile, flags, buildRoot, 1);
                    if (spec->BASpecs[index] == NULL) {
                        spec->BACount = index;
                        goto errxit;
                    }
                    delMacro(NULL, "_target_cpu");
                    index++;
                }

            spec->BACount = index;
            if (! index) {
                rpmlog(RPMLOG_ERR,
                       _("No compatible architectures found for build\n"));
                goto errxit;
            }

            /*
             * Return the 1st child's fully parsed Spec structure.
             * The restart of the parse when encountering BuildArch
             * causes problems for "rpm -q --specfile". This is
             * still a hack because there may be more than 1 arch
             * specified (unlikely but possible.) There's also the
             * further problem that the macro context, particularly
             * %{_target_cpu}, disagrees with the info in the header.
             */
            if (spec->BACount >= 1) {
                rpmSpec nspec = spec->BASpecs[0];
                spec->BASpecs = _free(spec->BASpecs);
                rpmSpecFree(spec);
                spec = nspec;
            }

            goto exit;
        }
    }

    if (spec->clean == NULL) {
        char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL);
        spec->clean = newStringBuf();
        appendLineStringBuf(spec->clean, body);
        free(body);
    }

    /* Check for description in each package */
    for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
        if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
            rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
                   headerGetString(pkg->header, RPMTAG_NAME));
            goto errxit;
        }
    }

    /* Add arch, os and platform, self-provides etc for each package */
    addTargets(spec->packages);

    /* Check for encoding in each package unless disabled */
    if (!(spec->flags & RPMSPEC_NOUTF8)) {
        int badenc = 0;
        for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
            if (checkForEncoding(pkg->header, 0) != RPMRC_OK) {
                badenc = 1;
            }
        }
        if (badenc)
            goto errxit;
    }

    closeSpec(spec);
exit:
    /* Assemble source header from parsed components */
    initSourceHeader(spec);

    return spec;

errxit:
    rpmSpecFree(spec);
    return NULL;
}
示例#2
0
文件: pack.c 项目: nforro/rpm
/*
 * This is more than just a little insane:
 * In order to write the signature, we need to know the size and
 * the size and digests of the header and payload, which are located
 * after the signature on disk. We also need a digest of the compressed
 * payload for the main header, and of course the payload is after the
 * header on disk. So we need to create placeholders for both the
 * signature and main header that exactly match the final sizes, calculate
 * the payload digest, then generate and write the real main header to
 * be able to FINALLY calculate the digests we need for the signature
 * header. In other words, we need to write things in the exact opposite
 * order to how the RPM format is laid on disk.
 */
static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp,
		      const char *fileName, char **cookie)
{
    FD_t fd = NULL;
    char * rpmio_flags = NULL;
    char * SHA1 = NULL;
    char * SHA256 = NULL;
    uint8_t * MD5 = NULL;
    char * pld = NULL;
    uint32_t pld_algo = PGPHASHALGO_SHA256; /* TODO: macro configuration */
    rpmRC rc = RPMRC_FAIL; /* assume failure */
    rpm_loff_t archiveSize = 0;
    off_t sigStart, hdrStart, payloadStart, payloadEnd;

    if (pkgidp)
	*pkgidp = NULL;

    rpmio_flags = getIOFlags(pkg);
    if (!rpmio_flags)
	goto exit;

    finalizeDeps(pkg);

    /* Create and add the cookie */
    if (cookie) {
	rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
	headerPutString(pkg->header, RPMTAG_COOKIE, *cookie);
    }

    /* Create a dummy payload digest to get the header size right */
    pld = nullDigest(pld_algo, 1);
    headerPutUint32(pkg->header, RPMTAG_PAYLOADDIGESTALGO, &pld_algo, 1);
    headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
    pld = _free(pld);
    
    /* Check for UTF-8 encoding of string tags, add encoding tag if all good */
    if (checkForEncoding(pkg->header, 1))
	goto exit;

    /* Open the output file */
    fd = Fopen(fileName, "w+.ufdio");
    if (fd == NULL || Ferror(fd)) {
	rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
		fileName, Fstrerror(fd));
	goto exit;
    }

    /* Write the lead section into the package. */
    if (rpmLeadWrite(fd, pkg->header)) {
	rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd));
	goto exit;
    }

    /* Save the position of signature section */
    sigStart = Ftell(fd);

    /* Generate and write a placeholder signature header */
    SHA1 = nullDigest(PGPHASHALGO_SHA1, 1);
    SHA256 = nullDigest(PGPHASHALGO_SHA256, 1);
    MD5 = nullDigest(PGPHASHALGO_MD5, 0);
    if (rpmGenerateSignature(SHA256, SHA1, MD5, 0, 0, fd))
	goto exit;
    SHA1 = _free(SHA1);
    SHA256 = _free(SHA256);
    MD5 = _free(MD5);

    /* Write a placeholder header. */
    hdrStart = Ftell(fd);
    if (writeHdr(fd, pkg->header))
	goto exit;

    /* Write payload section (cpio archive) */
    payloadStart = Ftell(fd);
    if (cpio_doio(fd, pkg, rpmio_flags, &archiveSize))
	goto exit;
    payloadEnd = Ftell(fd);

    /* Re-read payload to calculate compressed digest */
    fdInitDigestID(fd, pld_algo, RPMTAG_PAYLOADDIGEST, 0);
    if (fdConsume(fd, payloadStart, payloadEnd - payloadStart))
	goto exit;
    fdFiniDigest(fd, RPMTAG_PAYLOADDIGEST, (void **)&pld, NULL, 1);

    /* Insert the payload digest in main header */
    headerDel(pkg->header, RPMTAG_PAYLOADDIGEST);
    headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
    pld = _free(pld);

    /* Write the final header */
    if (fdJump(fd, hdrStart))
	goto exit;
    if (writeHdr(fd, pkg->header))
	goto exit;

    /* Calculate digests: SHA on header, legacy MD5 on header + payload */
    fdInitDigestID(fd, PGPHASHALGO_MD5, RPMTAG_SIGMD5, 0);
    fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMTAG_SHA1HEADER, 0);
    fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMTAG_SHA256HEADER, 0);
    if (fdConsume(fd, hdrStart, payloadStart - hdrStart))
	goto exit;
    fdFiniDigest(fd, RPMTAG_SHA1HEADER, (void **)&SHA1, NULL, 1);
    fdFiniDigest(fd, RPMTAG_SHA256HEADER, (void **)&SHA256, NULL, 1);

    if (fdConsume(fd, 0, payloadEnd - payloadStart))
	goto exit;
    fdFiniDigest(fd, RPMTAG_SIGMD5, (void **)&MD5, NULL, 0);

    if (fdJump(fd, sigStart))
	goto exit;

    /* Generate the signature. Now with right values */
    if (rpmGenerateSignature(SHA256, SHA1, MD5, payloadEnd - hdrStart, archiveSize, fd))
	goto exit;

    rc = RPMRC_OK;

exit:
    free(rpmio_flags);
    free(SHA1);
    free(SHA256);

    /* XXX Fish the pkgid out of the signature header. */
    if (pkgidp != NULL) {
	if (MD5 != NULL) {
	    *pkgidp = MD5;
	}
    } else {
	free(MD5);
    }

    Fclose(fd);

    if (rc == RPMRC_OK)
	rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
    else
	(void) unlink(fileName);

    return rc;
}