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