home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / build / pack.c < prev    next >
C/C++ Source or Header  |  1997-09-17  |  21KB  |  757 lines

  1. /* The very final packaging steps */
  2.  
  3. #include "config.h"
  4. #include "miscfn.h"
  5.  
  6. #if HAVE_ALLOCA_H
  7. # include <alloca.h>
  8. #endif
  9.  
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <stdio.h>
  13. #include <sys/time.h>
  14. #include <sys/resource.h>
  15. #include <sys/stat.h>
  16. #include <sys/types.h>
  17. #include <sys/wait.h>
  18. #include <signal.h>
  19. #include <fcntl.h>
  20. #include <string.h>
  21. #include <errno.h>
  22.  
  23. #include <sys/time.h>  /* For 'select()' interfaces */
  24.  
  25. #include "cpio.h"
  26. #include "pack.h"
  27. #include "header.h"
  28. #include "spec.h"
  29. #include "specP.h"
  30. #include "signature.h"
  31. #include "rpmlead.h"
  32. #include "rpmlib.h"
  33. #include "misc.h"
  34. #include "stringbuf.h"
  35. #include "names.h"
  36. #include "files.h"
  37. #include "reqprov.h"
  38. #include "trigger.h"
  39. #include "messages.h"
  40.  
  41. static int writeMagic(int fd, char *name, unsigned short type);
  42. static int cpio_gzip(int fd, char *tempdir, char *writePtr,
  43.              int *archiveSize, char *prefix);
  44. static int generateRPM(char *name,       /* name-version-release         */
  45.                char *filename,   /* output filename              */
  46.                int type,         /* source or binary             */
  47.                Header header,    /* the header                   */
  48.                char *stempdir,   /* directory containing sources */
  49.                char *fileList,   /* list of files for cpio       */
  50.                char *passPhrase, /* PGP passphrase               */
  51.                char *prefix);
  52.  
  53.  
  54. static int generateRPM(char *name,       /* name-version-release         */
  55.                char *filename,   /* output filename              */
  56.                int type,         /* source or binary             */
  57.                Header header,    /* the header                   */
  58.                char *stempdir,   /* directory containing sources */
  59.                char *fileList,   /* list of files for cpio       */
  60.                char *passPhrase,
  61.                char *prefix)
  62. {
  63.     int_32 sigtype;
  64.     char *sigtarget;
  65.     int fd, ifd, count, archiveSize;
  66.     unsigned char buffer[8192];
  67.     Header sig;
  68.  
  69.     /* Add the a bogus archive size to the Header */
  70.     headerAddEntry(header, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE,
  71.            &archiveSize, 1);
  72.  
  73.     /* Write the header */
  74.     if (makeTempFile(NULL, &sigtarget, &fd))
  75.     return 1;
  76.  
  77.     headerWrite(fd, header, HEADER_MAGIC_YES);
  78.     
  79.     /* Write the archive and get the size */
  80.     if (cpio_gzip(fd, stempdir, fileList, &archiveSize, prefix)) {
  81.     close(fd);
  82.     unlink(sigtarget);
  83.     free(sigtarget);
  84.     return 1;
  85.     }
  86.  
  87.     /* Now set the real archive size in the Header */
  88.     headerModifyEntry(header, RPMTAG_ARCHIVESIZE,
  89.               RPM_INT32_TYPE, &archiveSize, 1);
  90.  
  91.     /* Rewind and rewrite the Header */
  92.     lseek(fd, 0,  SEEK_SET);
  93.     headerWrite(fd, header, HEADER_MAGIC_YES);
  94.     
  95.     close(fd);
  96.     
  97.     /* Now write the lead */
  98.     if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
  99.     fprintf(stderr, "Could not open %s\n", filename);
  100.     unlink(sigtarget);
  101.     free(sigtarget);
  102.     unlink(filename);
  103.     return 1;
  104.     }
  105.     if (writeMagic(fd, name, type)) {
  106.     close(fd);
  107.     unlink(sigtarget);
  108.     free(sigtarget);
  109.     unlink(filename);
  110.     return 1;
  111.     }
  112.  
  113.     /* Generate the signature */
  114.     sigtype = rpmLookupSignatureType();
  115.     rpmMessage(RPMMESS_VERBOSE, "Generating signature: %d\n", sigtype);
  116.     fflush(stdout);
  117.     sig = rpmNewSignature();
  118.     rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase);
  119.     rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
  120.     if (sigtype>0) {
  121.     rpmAddSignature(sig, sigtarget, sigtype, passPhrase);
  122.     }
  123.     if (rpmWriteSignature(fd, sig)) {
  124.     close(fd);
  125.     unlink(sigtarget);
  126.     free(sigtarget);
  127.     unlink(filename);
  128.     rpmFreeSignature(sig);
  129.     return 1;
  130.     }
  131.     rpmFreeSignature(sig);
  132.  
  133.     /* Append the header and archive */
  134.     ifd = open(sigtarget, O_RDONLY);
  135.     while ((count = read(ifd, buffer, sizeof(buffer))) > 0) {
  136.         if (count == -1) {
  137.         perror("Couldn't read sigtarget");
  138.         close(ifd);
  139.         close(fd);
  140.         unlink(sigtarget);
  141.         free(sigtarget);
  142.         unlink(filename);
  143.         return 1;
  144.         }
  145.         if (write(fd, buffer, count) < 0) {
  146.         perror("Couldn't write package");
  147.         close(ifd);
  148.         close(fd);
  149.         unlink(sigtarget);
  150.         free(sigtarget);
  151.         unlink(filename);
  152.         return 1;
  153.         }
  154.     }
  155.     close(ifd);
  156.     close(fd);
  157.     unlink(sigtarget);
  158.     free(sigtarget);
  159.  
  160.     rpmMessage(RPMMESS_VERBOSE, "Wrote: %s\n", filename);
  161.     
  162.     return 0;
  163. }
  164.  
  165. static int writeMagic(int fd, char *name,
  166.               unsigned short type)
  167. {
  168.     struct rpmlead lead;
  169.     int arch, os;
  170.  
  171.     rpmGetArchInfo(NULL, &arch);
  172.     rpmGetOsInfo(NULL, &os);
  173.  
  174.     /* There are the Major and Minor numbers */
  175.     lead.major = 3;
  176.     lead.minor = 0;
  177.     lead.type = type;
  178.     lead.archnum = arch;
  179.     lead.osnum = os;
  180.     lead.signature_type = RPMSIG_HEADERSIG;  /* New-style signature */
  181.     strncpy(lead.name, name, sizeof(lead.name));
  182.  
  183.     writeLead(fd, &lead);
  184.  
  185.     return 0;
  186. }
  187.  
  188. static int cpio_gzip(int fd, char *tempdir, char *writePtr,
  189.              int *archiveSize, char *prefix)
  190. {
  191.     int gzipPID;
  192.     int toGzip[2];
  193.     int rc;
  194.     char * gzipbin;
  195.     char * writebuf;
  196.     char * chptr;
  197.     int numMappings;
  198.     struct cpioFileMapping * cpioList;
  199.     int status;
  200.     void *oldhandler;
  201.     char savecwd[1024];
  202.     char * failedFile;
  203.  
  204.     gzipbin = rpmGetVar(RPMVAR_GZIPBIN);
  205.  
  206.     numMappings = 0;
  207.     chptr = writePtr;
  208.     while (chptr && *chptr) {
  209.     numMappings++;
  210.     chptr = strchr(chptr, '\n');
  211.     if (chptr) *chptr++ = '\n';
  212.     }
  213.  
  214.     writebuf = alloca(strlen(writePtr) + 1);
  215.     strcpy(writebuf, writePtr);
  216.  
  217.     cpioList = alloca(sizeof(*cpioList) * numMappings);
  218.     chptr = writebuf;
  219.     numMappings = 0;
  220.     while (chptr && *chptr) {
  221.     cpioList[numMappings].fsPath = chptr;
  222.     cpioList[numMappings].mapFlags = tempdir ? CPIO_FOLLOW_SYMLINKS : 0;
  223.  
  224.     chptr = strchr(chptr, '\n');
  225.     if (chptr) *chptr++ = '\0';
  226.  
  227.     /* hack */
  228.     if (!strlen(cpioList[numMappings].fsPath)) {
  229.         cpioList[numMappings].fsPath = ".";
  230.     }
  231.  
  232.     numMappings++;
  233.     }
  234.  
  235.     oldhandler = signal(SIGPIPE, SIG_IGN);
  236.  
  237.     pipe(toGzip);
  238.     
  239.     /* GZIP */
  240.     if (!(gzipPID = fork())) {
  241.     close(toGzip[1]);
  242.     
  243.     dup2(toGzip[0], 0);  /* Make stdin the in pipe       */
  244.     dup2(fd, 1);         /* Make stdout the passed-in fd */
  245.  
  246.     execlp(gzipbin, gzipbin, "-c9fn", NULL);
  247.     rpmError(RPMERR_EXEC, "Couldn't exec gzip");
  248.     _exit(RPMERR_EXEC);
  249.     }
  250.     if (gzipPID < 0) {
  251.     rpmError(RPMERR_FORK, "Couldn't fork gzip");
  252.     return RPMERR_FORK;
  253.     }
  254.  
  255.     close(toGzip[0]);
  256.  
  257.     getcwd(savecwd, 1024);
  258.     
  259.     if (tempdir) {
  260.     chdir(tempdir);
  261.     } else if (rpmGetVar(RPMVAR_ROOT)) {
  262.     if (chdir(rpmGetVar(RPMVAR_ROOT))) {
  263.         rpmError(RPMERR_EXEC, "Couldn't chdir to %s",
  264.           rpmGetVar(RPMVAR_ROOT));
  265.         exit(RPMERR_EXEC);
  266.     }
  267.     } else {
  268.     /* This is important! */
  269.     chdir("/");
  270.     }
  271.     if (prefix) {
  272.     if (chdir(prefix)) {
  273.         rpmError(RPMERR_EXEC, "Couldn't chdir to %s", prefix);
  274.         _exit(RPMERR_EXEC);
  275.     }
  276.     }
  277.  
  278.     rc = cpioBuildArchive(toGzip[1], cpioList, numMappings, NULL, NULL, 
  279.               archiveSize, &failedFile);
  280.  
  281.     chdir(savecwd);
  282.  
  283.     close(toGzip[1]); /* Terminates the gzip process */
  284.     
  285.     signal(SIGPIPE, oldhandler);
  286.  
  287.     waitpid(gzipPID, &status, 0);
  288.     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  289.     rpmError(RPMERR_GZIP, "gzip failed");
  290.     return 1;
  291.     }
  292.  
  293.     if (rc) {
  294.     if (rc & CPIO_CHECK_ERRNO)
  295.         rpmError(RPMERR_CPIO, "cpio failed on file %s: %d: %s", failedFile, 
  296.             rc, strerror(errno));
  297.     else
  298.         rpmError(RPMERR_CPIO, "cpio failed on file %s: %d", failedFile, rc);
  299.     return 1;
  300.     }
  301.  
  302.     return 0;
  303. }
  304.  
  305.  
  306. int packageBinaries(Spec s, char *passPhrase, int doPackage)
  307. {
  308.     char name[1024];
  309.     char *nametmp;
  310.     char filename[1024];
  311.     char sourcerpm[1024];
  312.     char * binrpm;
  313.     char *icon;
  314.     int iconFD;
  315.     struct stat statbuf;
  316.     struct PackageRec *pr;
  317.     Header outHeader;
  318.     HeaderIterator headerIter;
  319.     int_32 tag, type, c;
  320.     void *ptr;
  321.     char *version;
  322.     char *release;
  323.     char *vendor;
  324.     char *dist;
  325.     char *packager;
  326.     char *packageVersion, *packageRelease;
  327.     char *prefix, *prefixSave;
  328.     char * arch, * os;
  329.     char * binformat, * errorString;
  330.     int prefixLen;
  331.     int size;
  332.     StringBuf cpioFileList;
  333.     char **farray, *file;
  334.     int count;
  335.     
  336.     if (!headerGetEntry(s->packages->header, RPMTAG_VERSION, NULL,
  337.           (void *) &version, NULL)) {
  338.     rpmError(RPMERR_BADSPEC, "No version field");
  339.     return RPMERR_BADSPEC;
  340.     }
  341.     if (!headerGetEntry(s->packages->header, RPMTAG_RELEASE, NULL,
  342.           (void *) &release, NULL)) {
  343.     rpmError(RPMERR_BADSPEC, "No release field");
  344.     return RPMERR_BADSPEC;
  345.     }
  346.     /* after the headerGetEntry() these are just pointers into the   */
  347.     /* header structure, which can be moved around by headerAddEntry */
  348.     version = strdup(version);
  349.     release = strdup(release);
  350.  
  351.     sprintf(sourcerpm, "%s-%s-%s.%ssrc.rpm", s->name, version, release,
  352.         (s->numNoPatch + s->numNoSource) ? "no" : "");
  353.  
  354.     vendor = NULL;
  355.     if (!headerIsEntry(s->packages->header, RPMTAG_VENDOR)) {
  356.     vendor = rpmGetVar(RPMVAR_VENDOR);
  357.     }
  358.     dist = NULL;
  359.     if (!headerIsEntry(s->packages->header, RPMTAG_DISTRIBUTION)) {
  360.     dist = rpmGetVar(RPMVAR_DISTRIBUTION);
  361.     }
  362.     packager = NULL;
  363.     if (!headerIsEntry(s->packages->header, RPMTAG_PACKAGER)) {
  364.     packager = rpmGetVar(RPMVAR_PACKAGER);
  365.     }
  366.  
  367.     /* Look through for each package */
  368.     pr = s->packages;
  369.     while (pr) {
  370.     /* A file count of -1 means no package */
  371.     if (pr->files == -1) {
  372.         pr = pr->next;
  373.         continue;
  374.     }
  375.  
  376.     /* Handle subpackage version/release overrides */
  377.     if (!headerGetEntry(pr->header, RPMTAG_VERSION, NULL,
  378.               (void *) &packageVersion, NULL)) {
  379.         packageVersion = version;
  380.     }
  381.     if (!headerGetEntry(pr->header, RPMTAG_RELEASE, NULL,
  382.               (void *) &packageRelease, NULL)) {
  383.         packageRelease = release;
  384.     }
  385.         /* after the headerGetEntry() these are just pointers into the   */
  386.         /* header structure, which can be moved around by headerAddEntry */
  387.         packageVersion = strdup(packageVersion);
  388.         packageRelease = strdup(packageRelease);
  389.     
  390.     /* Figure out the name of this package */
  391.     if (!headerGetEntry(pr->header, RPMTAG_NAME, NULL, (void *)&nametmp, NULL)) {
  392.         rpmError(RPMERR_INTERNAL, "Package has no name!");
  393.         return RPMERR_INTERNAL;
  394.     }
  395.     sprintf(name, "%s-%s-%s", nametmp, packageVersion, packageRelease);
  396.  
  397.     if (doPackage == PACK_PACKAGE) {
  398.         rpmMessage(RPMMESS_VERBOSE, "Binary Packaging: %s\n", name);
  399.     } else {
  400.         rpmMessage(RPMMESS_VERBOSE, "File List Check: %s\n", name);
  401.     }
  402.        
  403.     /**** Generate the Header ****/
  404.     
  405.     /* Here's the plan: copy the package's header,  */
  406.     /* then add entries from the primary header     */
  407.     /* that don't already exist.                    */
  408.     outHeader = headerCopy(pr->header);
  409.     headerIter = headerInitIterator(s->packages->header);
  410.     while (headerNextIterator(headerIter, &tag, &type, &ptr, &c)) {
  411.         /* Some tags we don't copy */
  412.         switch (tag) {
  413.           case RPMTAG_PREIN:
  414.           case RPMTAG_POSTIN:
  415.           case RPMTAG_PREUN:
  416.           case RPMTAG_POSTUN:
  417.           case RPMTAG_PREINPROG:
  418.           case RPMTAG_POSTINPROG:
  419.           case RPMTAG_PREUNPROG:
  420.           case RPMTAG_POSTUNPROG:
  421.           case RPMTAG_VERIFYSCRIPT:
  422.           continue;
  423.           break;  /* Shouldn't need this */
  424.           default:
  425.           if (! headerIsEntry(outHeader, tag)) {
  426.               headerAddEntry(outHeader, tag, type, ptr, c);
  427.           }
  428.         }
  429.     }
  430.     headerFreeIterator(headerIter);
  431.  
  432.     headerRemoveEntry(outHeader, RPMTAG_BUILDARCHS);
  433.  
  434.     rpmGetArchInfo(&arch, NULL);
  435.     rpmGetOsInfo(&os, NULL);
  436.     
  437.     /* Add some final entries to the header */
  438.     headerAddEntry(outHeader, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
  439.     headerAddEntry(outHeader, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1);
  440.     headerAddEntry(outHeader, RPMTAG_BUILDTIME, RPM_INT32_TYPE, getBuildTime(), 1);
  441.     headerAddEntry(outHeader, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildHost(), 1);
  442.     headerAddEntry(outHeader, RPMTAG_SOURCERPM, RPM_STRING_TYPE, sourcerpm, 1);
  443.     headerAddEntry(outHeader, RPMTAG_RPMVERSION, RPM_STRING_TYPE, VERSION, 1);
  444.     if (pr->icon) {
  445.         sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), pr->icon);
  446.         stat(filename, &statbuf);
  447.         icon = malloc(statbuf.st_size);
  448.         iconFD = open(filename, O_RDONLY, 0644);
  449.         read(iconFD, icon, statbuf.st_size);
  450.         close(iconFD);
  451.         if (! strncmp(icon, "GIF", 3)) {
  452.         headerAddEntry(outHeader, RPMTAG_GIF, RPM_BIN_TYPE,
  453.              icon, statbuf.st_size);
  454.         } else if (! strncmp(icon, "/* XPM", 6)) {
  455.         headerAddEntry(outHeader, RPMTAG_XPM, RPM_BIN_TYPE,
  456.              icon, statbuf.st_size);
  457.         } else {
  458.            rpmError(RPMERR_BADSPEC, "Unknown icon type");
  459.            return 1;
  460.         }
  461.         free(icon);
  462.     }
  463.     if (vendor) {
  464.         headerAddEntry(outHeader, RPMTAG_VENDOR, RPM_STRING_TYPE, vendor, 1);
  465.     }
  466.     if (dist) {
  467.         headerAddEntry(outHeader, RPMTAG_DISTRIBUTION, RPM_STRING_TYPE, dist, 1);
  468.     }
  469.     if (packager) {
  470.         headerAddEntry(outHeader, RPMTAG_PACKAGER, RPM_STRING_TYPE, packager, 1);
  471.     }
  472.     
  473.     /**** Process the file list ****/
  474.  
  475.     prefixSave = prefix = NULL;
  476.     prefixLen = 0;
  477.     if (headerGetEntry(outHeader, RPMTAG_DEFAULTPREFIX,
  478.              NULL, (void **)&prefix, NULL)) {
  479.             /* after the headerGetEntry() this is just pointers into the     */
  480.             /* header structure, which can be moved around by headerAddEntry */
  481.         prefixSave = prefix = strdup(prefix);
  482.         while (*prefix && (*prefix == '/')) {
  483.         prefix++;
  484.         }
  485.         if (! *prefix) {
  486.         prefix = NULL;
  487.         prefixLen = 0;
  488.         } else {
  489.         prefixLen = strlen(prefix);
  490.             rpmMessage(RPMMESS_VERBOSE, "Package Prefix = %s\n", prefix);
  491.         }
  492.     }
  493.     
  494.     if (process_filelist(outHeader, pr, pr->filelist, &size, nametmp,
  495.                  packageVersion, packageRelease, RPMLEAD_BINARY,
  496.                  prefix, NULL)) {
  497.         return 1;
  498.     }
  499.  
  500.     if (!headerGetEntry(outHeader, RPMTAG_FILENAMES, NULL, (void **) &farray,
  501.               &count)) {
  502.         /* count may already be 0, but this is safer */
  503.         count = 0;
  504.     }
  505.  
  506.     cpioFileList = newStringBuf();
  507.     while (count--) {
  508.         file = *farray++;
  509.         while (*file == '/') {
  510.         file++;  /* Skip leading "/" */
  511.         }
  512.         if (prefix) {
  513.         if (strncmp(prefix, file, prefixLen)) {
  514.             rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s",
  515.               prefix, file);
  516.             return 1;
  517.         }
  518.         file += prefixLen + 1; /* 1 for "/" */
  519.         }
  520.         appendLineStringBuf(cpioFileList, file);
  521.     }
  522.     
  523.     /* Generate any automatic require/provide entries */
  524.     /* Then add the whole thing to the header         */
  525.     if (s->autoReqProv) {
  526.         generateAutoReqProv(outHeader, pr);
  527.     }
  528.     processReqProv(outHeader, pr);
  529.  
  530.     /* Generate the any trigger entries */
  531.     generateTriggerEntries(outHeader, pr);
  532.     
  533.     /* And add the final Header entry */
  534.     headerAddEntry(outHeader, RPMTAG_SIZE, RPM_INT32_TYPE, &size, 1);
  535.  
  536.     /**** Make the RPM ****/
  537.  
  538.     /* Make the output RPM filename */
  539.     if (doPackage == PACK_PACKAGE) {
  540.         binformat = rpmGetVar(RPMVAR_RPMFILENAME);
  541.         binrpm = headerSprintf(outHeader, binformat, rpmTagTable,
  542.                    rpmHeaderFormats, &errorString);
  543.  
  544.         if (!binrpm) {
  545.         rpmError(RPMERR_BADFILENAME, "could not generate output "
  546.              "filename for package %s: %s\n", name, binrpm);
  547.         }
  548.  
  549.         sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_RPMDIR), binrpm);
  550.         free(binrpm);
  551.  
  552.         if (generateRPM(name, filename, RPMLEAD_BINARY, outHeader, NULL,
  553.                 getStringBuf(cpioFileList), passPhrase, prefix)) {
  554.         /* Build failed */
  555.         return 1;
  556.         }
  557.     }
  558.  
  559.     freeStringBuf(cpioFileList);
  560.     headerFree(outHeader);
  561.        
  562.         if (prefixSave)
  563.         free(prefixSave);
  564.         free(packageVersion);
  565.         free(packageRelease);
  566.        
  567.     pr = pr->next;
  568.     }
  569.  
  570.     free(version);
  571.     free(release);
  572.    
  573.     return 0;
  574. }
  575.  
  576. /**************** SOURCE PACKAGING ************************/
  577.  
  578. int packageSource(Spec s, char *passPhrase)
  579. {
  580.     struct sources *source;
  581.     struct PackageRec *package;
  582.     char *tempdir;
  583.     char src[1024], dest[1024], fullname[1024], filename[1024], specFile[1024];
  584.     char *version;
  585.     char *release;
  586.     char *vendor;
  587.     char *dist;
  588.     char *p;
  589.     Header outHeader;
  590.     StringBuf filelist;
  591.     StringBuf cpioFileList;
  592.     int size;
  593.     char **sources;
  594.     char **patches;
  595.     char * arch, * os;
  596.     int scount, pcount;
  597.     int skipi;
  598.     int_32 *skip;
  599.  
  600.     /**** Create links for all the sources ****/
  601.     
  602.     tempdir = tempnam(rpmGetVar(RPMVAR_TMPPATH), "rpmbuild");
  603.     mkdir(tempdir, 0700);
  604.  
  605.     filelist = newStringBuf();     /* List in the header */
  606.     cpioFileList = newStringBuf(); /* List for cpio      */
  607.  
  608.     sources = malloc((s->numSources+1) * sizeof(char *));
  609.     patches = malloc((s->numPatches+1) * sizeof(char *));
  610.     
  611.     /* Link in the spec file and all the sources */
  612.     p = strrchr(s->specfile, '/');
  613.     sprintf(dest, "%s%s", tempdir, p);
  614.     strcpy(specFile, dest);
  615.     symlink(s->specfile, dest);
  616.     appendLineStringBuf(filelist, dest);
  617.     appendLineStringBuf(cpioFileList, p+1);
  618.     source = s->sources;
  619.     scount = 0;
  620.     pcount = 0;
  621.     while (source) {
  622.     if (source->ispatch) {
  623.         skipi = s->numNoPatch - 1;
  624.         skip = s->noPatch;
  625.     } else {
  626.         skipi = s->numNoSource - 1;
  627.         skip = s->noSource;
  628.     }
  629.     while (skipi >= 0) {
  630.         if (skip[skipi] == source->num) {
  631.         break;
  632.         }
  633.         skipi--;
  634.     }
  635.     sprintf(src, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), source->source);
  636.     sprintf(dest, "%s/%s", tempdir, source->source);
  637.     if (skipi < 0) {
  638.         symlink(src, dest);
  639.         appendLineStringBuf(cpioFileList, source->source);
  640.     } else {
  641.         rpmMessage(RPMMESS_VERBOSE, "Skipping source/patch (%d): %s\n",
  642.             source->num, source->source);
  643.     }
  644.     appendLineStringBuf(filelist, src);
  645.     if (source->ispatch) {
  646.         patches[pcount++] = source->fullSource;
  647.     } else {
  648.         sources[scount++] = source->fullSource;
  649.     }
  650.     source = source->next;
  651.     }
  652.     /* ... and icons */
  653.     package = s->packages;
  654.     while (package) {
  655.     if (package->icon) {
  656.         sprintf(src, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), package->icon);
  657.         sprintf(dest, "%s/%s", tempdir, package->icon);
  658.         appendLineStringBuf(filelist, dest);
  659.         appendLineStringBuf(cpioFileList, package->icon);
  660.         symlink(src, dest);
  661.     }
  662.     package = package->next;
  663.     }
  664.  
  665.     /**** Generate the Header ****/
  666.     
  667.     if (!headerGetEntry(s->packages->header, RPMTAG_VERSION, NULL,
  668.           (void *) &version, NULL)) {
  669.     rpmError(RPMERR_BADSPEC, "No version field");
  670.     return RPMERR_BADSPEC;
  671.     }
  672.     if (!headerGetEntry(s->packages->header, RPMTAG_RELEASE, NULL,
  673.           (void *) &release, NULL)) {
  674.     rpmError(RPMERR_BADSPEC, "No release field");
  675.     return RPMERR_BADSPEC;
  676.     }
  677.  
  678.     rpmGetArchInfo(&arch, NULL);
  679.     rpmGetOsInfo(&os, NULL);
  680.  
  681.     outHeader = headerCopy(s->packages->header);
  682.     headerAddEntry(outHeader, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
  683.     headerAddEntry(outHeader, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1);
  684.     headerAddEntry(outHeader, RPMTAG_BUILDTIME, RPM_INT32_TYPE, getBuildTime(), 1);
  685.     headerAddEntry(outHeader, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildHost(), 1);
  686.     headerAddEntry(outHeader, RPMTAG_RPMVERSION, RPM_STRING_TYPE, VERSION, 1);
  687.     if (scount) 
  688.         headerAddEntry(outHeader, RPMTAG_SOURCE, RPM_STRING_ARRAY_TYPE, sources, scount);
  689.     if (pcount)
  690.         headerAddEntry(outHeader, RPMTAG_PATCH, RPM_STRING_ARRAY_TYPE, patches, pcount);
  691.     if (s->numNoSource) {
  692.     headerAddEntry(outHeader, RPMTAG_NOSOURCE, RPM_INT32_TYPE, s->noSource,
  693.          s->numNoSource);
  694.     }
  695.     if (s->numNoPatch) {
  696.     headerAddEntry(outHeader, RPMTAG_NOPATCH, RPM_INT32_TYPE, s->noPatch,
  697.          s->numNoPatch);
  698.     }
  699.     if (!headerIsEntry(s->packages->header, RPMTAG_VENDOR)) {
  700.     if ((vendor = rpmGetVar(RPMVAR_VENDOR))) {
  701.         headerAddEntry(outHeader, RPMTAG_VENDOR, RPM_STRING_TYPE, vendor, 1);
  702.     }
  703.     }
  704.     if (!headerIsEntry(s->packages->header, RPMTAG_DISTRIBUTION)) {
  705.     if ((dist = rpmGetVar(RPMVAR_DISTRIBUTION))) {
  706.         headerAddEntry(outHeader, RPMTAG_DISTRIBUTION, RPM_STRING_TYPE, dist, 1);
  707.     }
  708.     }
  709.  
  710.     /* Process the file list */
  711.     if (process_filelist(outHeader, NULL, filelist, &size,
  712.              s->name, version, release, RPMLEAD_SOURCE,
  713.              NULL, specFile)) {
  714.     return 1;
  715.     }
  716.  
  717.     /* And add the final Header entry */
  718.     headerAddEntry(outHeader, RPMTAG_SIZE, RPM_INT32_TYPE, &size, 1);
  719.  
  720.     /**** Make the RPM ****/
  721.  
  722.     sprintf(fullname, "%s-%s-%s", s->name, version, release);
  723.     sprintf(filename, "%s/%s.%ssrc.rpm", rpmGetVar(RPMVAR_SRPMDIR), fullname,
  724.         (s->numNoPatch + s->numNoSource) ? "no" : "");
  725.     rpmMessage(RPMMESS_VERBOSE, "Source Packaging: %s\n", fullname);
  726.  
  727.     if (generateRPM(fullname, filename, RPMLEAD_SOURCE, outHeader,
  728.             tempdir, getStringBuf(cpioFileList), passPhrase, NULL)) {
  729.     return 1;
  730.     }
  731.     
  732.     /**** Now clean up ****/
  733.  
  734.     freeStringBuf(filelist);
  735.     freeStringBuf(cpioFileList);
  736.     
  737.     source = s->sources;
  738.     while (source) {
  739.     sprintf(dest, "%s/%s", tempdir, source->source);
  740.     unlink(dest);
  741.     source = source->next;
  742.     }
  743.     package = s->packages;
  744.     while (package) {
  745.     if (package->icon) {
  746.         sprintf(dest, "%s/%s", tempdir, package->icon);
  747.         unlink(dest);
  748.     }
  749.     package = package->next;
  750.     }
  751.     sprintf(dest, "%s%s", tempdir, strrchr(s->specfile, '/'));
  752.     unlink(dest);
  753.     rmdir(tempdir);
  754.     
  755.     return 0;
  756. }
  757.