5 # include "misc-glob.h"
11 #include <sys/types.h>
28 #define MAXDOCDIR 1024
31 char *diskName; /* get file from here */
32 char *fileName; /* filename in cpio archive */
71 int currentVerifyFlags;
72 struct AttrRec current;
77 /* Hard coded limit of MAXDOCDIR docdirs. */
78 /* If you break it you are doing something wrong. */
79 char *docDirs[MAXDOCDIR];
82 struct FileListRec *fileList;
83 int fileListRecsAlloced;
87 static int processPackageFiles(Spec spec, Package pkg,
88 int installSpecialDoc, int test);
89 static void freeFileList(struct FileListRec *fileList, int count);
90 static int compareFileListRecs(const void *ap, const void *bp);
91 static int isDoc(struct FileList *fl, char *fileName);
92 static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName);
93 static int addFile(struct FileList *fl, char *name, struct stat *statp);
94 static int parseForSimple(Spec spec, Package pkg, char *buf,
95 struct FileList *fl, char **fileName);
96 static int parseForVerify(char *buf, struct FileList *fl);
97 static int parseForLang(char *buf, struct FileList *fl);
98 static int parseForAttr(char *buf, struct FileList *fl);
99 static int parseForConfig(char *buf, struct FileList *fl);
100 static int parseForRegexLang(char *fileName, char **lang);
101 static int myGlobPatternP(char *pattern);
102 static int glob_error(const char *foo, int bar);
103 static void timeCheck(int tc, Header h);
104 static void genCpioListAndHeader(struct FileList *fl,
105 struct cpioFileMapping **cpioList,
106 int *cpioCount, Header h, int isSrc);
107 static char *strtokWithQuotes(char *s, char *delim);
109 int processSourceFiles(Spec spec)
111 struct Source *srcPtr;
113 StringBuf sourceFiles;
116 char *s, **files, **fp, *fn;
119 int tag, type, count;
123 sourceFiles = newStringBuf();
124 spec->sourceHeader = headerNew();
126 /* Only specific tags are added to the source package header */
127 hi = headerInitIterator(spec->packages->header);
128 while (headerNextIterator(hi, &tag, &type, &ptr, &count)) {
135 case RPMTAG_DESCRIPTION:
136 case RPMTAG_PACKAGER:
137 case RPMTAG_DISTRIBUTION:
139 case RPMTAG_COPYRIGHT:
143 case RPMTAG_CHANGELOGTIME:
144 case RPMTAG_CHANGELOGNAME:
145 case RPMTAG_CHANGELOGTEXT:
147 case HEADER_I18NTABLE:
148 headerAddEntry(spec->sourceHeader, tag, type, ptr, count);
154 if (type == RPM_STRING_ARRAY_TYPE || type == RPM_I18NSTRING_TYPE) {
158 headerFreeIterator(hi);
160 /* Construct the file list and source entries */
161 appendLineStringBuf(sourceFiles, spec->specFile);
162 srcPtr = spec->sources;
164 if (srcPtr->flags & RPMBUILD_ISSOURCE) {
165 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE,
166 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
167 if (srcPtr->flags & RPMBUILD_ISNO) {
168 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE,
169 RPM_INT32_TYPE, &srcPtr->num, 1);
172 if (srcPtr->flags & RPMBUILD_ISPATCH) {
173 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH,
174 RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1);
175 if (srcPtr->flags & RPMBUILD_ISNO) {
176 headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH,
177 RPM_INT32_TYPE, &srcPtr->num, 1);
180 sprintf(buf, "%s%s/%s",
181 srcPtr->flags & RPMBUILD_ISNO ? "!" : "",
182 rpmGetVar(RPMVAR_SOURCEDIR), srcPtr->source);
183 appendLineStringBuf(sourceFiles, buf);
184 srcPtr = srcPtr->next;
187 pkg = spec->packages;
191 sprintf(buf, "%s%s/%s",
192 srcPtr->flags & RPMBUILD_ISNO ? "!" : "",
193 rpmGetVar(RPMVAR_SOURCEDIR), srcPtr->source);
194 appendLineStringBuf(sourceFiles, buf);
195 srcPtr = srcPtr->next;
200 spec->sourceCpioList = NULL;
201 spec->sourceCpioCount = 0;
203 fl.fileList = malloc((spec->numSources + 1) * sizeof(struct FileListRec));
204 fl.processingFailed = 0;
205 fl.fileListRecsUsed = 0;
206 fl.totalFileSize = 0;
209 s = getStringBuf(sourceFiles);
210 files = splitString(s, strlen(s), '\n');
213 /* The first source file is the spec file */
222 fl.fileList[x].flags = isSpec ? RPMFILE_SPECFILE : 0;
223 /* files with leading ! are no source files */
225 fl.fileList[x].flags |= RPMFILE_GHOST;
228 fl.fileList[x].diskName = strdup(s);
229 fn = strrchr(s, '/');
235 fl.fileList[x].fileName = strdup(fn);
236 fl.fileList[x].verifyFlags = RPMVERIFY_ALL;
238 fl.fileList[x].mode = sb.st_mode;
239 fl.fileList[x].uid = sb.st_uid;
240 fl.fileList[x].gid = sb.st_gid;
241 fl.fileList[x].uname = getUname(sb.st_uid);
242 fl.fileList[x].gname = getGname(sb.st_gid);
243 fl.fileList[x].size = sb.st_size;
244 fl.fileList[x].mtime = sb.st_mtime;
245 fl.fileList[x].rdev = sb.st_rdev;
246 fl.fileList[x].device = sb.st_dev;
247 fl.fileList[x].inode = sb.st_ino;
248 fl.fileList[x].lang = strdup("");
250 fl.totalFileSize += sb.st_size;
252 if (! (fl.fileList[x].uname && fl.fileList[x].gname)) {
253 rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", s);
254 fl.processingFailed = 1;
261 fl.fileListRecsUsed = x;
262 freeSplitString(files);
264 if (! fl.processingFailed) {
265 genCpioListAndHeader(&fl, &(spec->sourceCpioList),
266 &(spec->sourceCpioCount), spec->sourceHeader, 1);
269 freeStringBuf(sourceFiles);
270 freeFileList(fl.fileList, fl.fileListRecsUsed);
271 return fl.processingFailed;
274 int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
280 pkg = spec->packages;
283 if (!pkg->fileList) {
288 headerGetEntry(pkg->header, RPMTAG_NAME, NULL, (void **)&name, NULL);
289 rpmMessage(RPMMESS_NORMAL, "Processing files: %s\n", name);
291 if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) {
295 generateAutoReqProv(spec, pkg, pkg->cpioList, pkg->cpioCount);
296 printReqs(spec, pkg);
304 static int processPackageFiles(Spec spec, Package pkg,
305 int installSpecialDoc, int test)
308 char *s, **files, **fp, *fileName;
312 struct AttrRec specialDocAttrRec;
313 char *specialDoc = NULL;
315 pkg->cpioList = NULL;
319 sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR),
320 spec->buildSubdir, pkg->fileFile);
321 if ((f = fopen(buf, "r")) == NULL) {
322 rpmError(RPMERR_BADFILENAME,
323 "Could not open %%files file: %s", pkg->fileFile);
324 return RPMERR_BADFILENAME;
326 while (fgets(buf, sizeof(buf), f)) {
328 if (expandMacros(&spec->macros, buf)) {
329 rpmError(RPMERR_BADSPEC, "line: %s", buf);
330 return RPMERR_BADSPEC;
332 appendStringBuf(pkg->fileList, buf);
337 /* Init the file list structure */
339 fl.buildRoot = spec->buildRoot ? spec->buildRoot : "";
340 if (headerGetEntry(pkg->header, RPMTAG_DEFAULTPREFIX,
341 NULL, (void *)&fl.prefix, NULL)) {
342 fl.prefix = strdup(fl.prefix);
348 fl.totalFileSize = 0;
349 fl.processingFailed = 0;
351 fl.passedSpecialDoc = 0;
353 fl.current.PmodeString = NULL;
354 fl.current.PdirmodeString = NULL;
355 fl.current.Uname = NULL;
356 fl.current.Gname = NULL;
357 fl.def.PmodeString = NULL;
358 fl.def.PdirmodeString = NULL;
363 fl.currentLang = NULL;
365 fl.defVerifyFlags = RPMVERIFY_ALL;
368 fl.docDirs[fl.docDirCount++] = strdup("/usr/doc");
369 fl.docDirs[fl.docDirCount++] = strdup("/usr/man");
370 fl.docDirs[fl.docDirCount++] = strdup("/usr/info");
371 fl.docDirs[fl.docDirCount++] = strdup("/usr/X11R6/man");
372 fl.docDirs[fl.docDirCount++] = strdup(spec->docDir);
375 fl.fileListRecsAlloced = 0;
376 fl.fileListRecsUsed = 0;
378 s = getStringBuf(pkg->fileList);
379 files = splitString(s, strlen(s), '\n');
391 /* Reset for a new line in %files */
395 fl.currentVerifyFlags = fl.defVerifyFlags;
396 fl.current.Pmode = fl.def.Pmode;
397 fl.current.Pdirmode = fl.def.Pdirmode;
399 FREE(fl.current.PmodeString);
400 FREE(fl.current.PdirmodeString);
401 FREE(fl.current.Uname);
402 FREE(fl.current.Gname);
403 FREE(fl.currentLang);
404 if (fl.def.PmodeString) {
405 fl.current.PmodeString = strdup(fl.def.PmodeString);
407 if (fl.def.PdirmodeString) {
408 fl.current.PdirmodeString = strdup(fl.def.PdirmodeString);
411 fl.current.Uname = strdup(fl.def.Uname);
414 fl.current.Gname = strdup(fl.def.Gname);
417 if (parseForVerify(buf, &fl)) {
420 if (parseForAttr(buf, &fl)) {
423 if (parseForConfig(buf, &fl)) {
426 if (parseForLang(buf, &fl)) {
429 if (parseForSimple(spec, pkg, buf, &fl, &fileName)) {
436 if (fl.isSpecialDoc) {
437 /* Save this stuff for last */
438 specialDoc = strdup(fileName);
439 specialDocAttrRec = fl.current;
440 if (specialDocAttrRec.PmodeString) {
441 specialDocAttrRec.PmodeString =
442 strdup(specialDocAttrRec.PmodeString);
444 if (specialDocAttrRec.PdirmodeString) {
445 specialDocAttrRec.PdirmodeString =
446 strdup(specialDocAttrRec.PdirmodeString);
448 if (specialDocAttrRec.Uname) {
449 specialDocAttrRec.Uname = strdup(specialDocAttrRec.Uname);
451 if (specialDocAttrRec.Gname) {
452 specialDocAttrRec.Gname = strdup(specialDocAttrRec.Gname);
455 processBinaryFile(pkg, &fl, fileName);
461 /* Now process special doc, if there is one */
463 if (installSpecialDoc) {
464 doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, test);
467 /* fl.current now takes on "ownership" of the specialDocAttrRec */
468 /* allocated string data. */
469 fl.current = specialDocAttrRec;
470 processBinaryFile(pkg, &fl, specialDoc);
474 freeSplitString(files);
476 if (! fl.processingFailed) {
477 genCpioListAndHeader(&fl, &(pkg->cpioList), &(pkg->cpioCount),
480 if (spec->timeCheck) {
481 timeCheck(spec->timeCheck, pkg->header);
487 FREE(fl.current.PmodeString);
488 FREE(fl.current.PdirmodeString);
489 FREE(fl.current.Uname);
490 FREE(fl.current.Gname);
491 FREE(fl.def.PmodeString);
492 FREE(fl.def.PdirmodeString);
495 FREE(fl.currentLang);
496 freeFileList(fl.fileList, fl.fileListRecsUsed);
497 while (fl.docDirCount--) {
498 FREE(fl.docDirs[fl.docDirCount]);
500 return fl.processingFailed;
503 static void timeCheck(int tc, Header h)
507 int count, x, currentTime;
509 headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &file, &count);
510 headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
512 currentTime = time(NULL);
516 if (currentTime - mtime[x] > tc) {
517 rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n", file[x]);
523 static void genCpioListAndHeader(struct FileList *fl,
524 struct cpioFileMapping **cpioList,
525 int *cpioCount, Header h, int isSrc)
528 struct FileListRec *p;
530 struct cpioFileMapping *cpioListPtr;
531 char *s, buf[BUFSIZ];
533 /* Sort the big list */
534 qsort(fl->fileList, fl->fileListRecsUsed,
535 sizeof(*(fl->fileList)), compareFileListRecs);
537 /* Generate the cpio list and the header */
540 skipLen = 1 + strlen(fl->prefix);
545 *cpioList = malloc(sizeof(**cpioList) * fl->fileListRecsUsed);
547 cpioListPtr = *cpioList;
549 count = fl->fileListRecsUsed;
551 if ((count > 1) && !strcmp(p->fileName, p[1].fileName)) {
552 rpmError(RPMERR_BADSPEC, "File listed twice: %s", p->fileName);
553 fl->processingFailed = 1;
556 /* Make the cpio list */
557 if (! (p->flags & RPMFILE_GHOST)) {
558 cpioListPtr->fsPath = strdup(p->diskName);
559 cpioListPtr->archivePath = strdup(p->fileName + skipLen);
560 cpioListPtr->finalMode = p->mode;
561 cpioListPtr->finalUid = p->uid;
562 cpioListPtr->finalGid = p->gid;
563 cpioListPtr->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE |
564 CPIO_MAP_UID | CPIO_MAP_GID;
569 /* Make the header */
570 headerAddOrAppendEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE,
572 headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE,
574 headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
576 headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
578 headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE,
580 if (sizeof(p->mode) != sizeof(uint_16)) {
581 uint_16 pmode = (uint_16)p->mode;
582 headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
585 headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE,
588 if (sizeof(p->rdev) != sizeof(uint_16)) {
589 uint_16 prdev = (uint_16)p->rdev;
590 headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
593 headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE,
596 if (sizeof(p->device) != sizeof(uint_32)) {
597 uint_32 pdevice = (uint_32)p->device;
598 headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
601 headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE,
604 headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE,
606 headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE,
609 /* We used to add these, but they should not be needed */
610 /* headerAddOrAppendEntry(h, RPMTAG_FILEUIDS,
611 * RPM_INT32_TYPE, &(p->uid), 1);
612 * headerAddOrAppendEntry(h, RPMTAG_FILEGIDS,
613 * RPM_INT32_TYPE, &(p->gid), 1);
618 if (S_ISREG(p->mode)) {
619 mdfile(p->diskName, buf);
621 headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE,
626 if (S_ISLNK(p->mode)) {
627 buf[readlink(p->diskName, buf, BUFSIZ)] = '\0';
629 headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
632 if (p->flags & RPMFILE_GHOST) {
633 p->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE |
634 RPMVERIFY_LINKTO | RPMVERIFY_MTIME);
636 headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
637 &(p->verifyFlags), 1);
639 if (!isSrc && isDoc(fl, p->fileName)) {
640 p->flags |= RPMFILE_DOC;
642 if (p->mode & S_IFDIR) {
643 p->flags &= ~RPMFILE_CONFIG;
644 p->flags &= ~RPMFILE_DOC;
646 headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE,
652 headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE,
653 &(fl->totalFileSize), 1);
656 static void freeFileList(struct FileListRec *fileList, int count)
659 FREE(fileList[count].diskName);
660 FREE(fileList[count].fileName);
661 FREE(fileList[count].lang);
666 void freeCpioList(struct cpioFileMapping *cpioList, int cpioCount)
668 struct cpioFileMapping *p = cpioList;
670 while (cpioCount--) {
671 rpmMessage(RPMMESS_DEBUG, "archive = %s, fs = %s\n",
672 p->archivePath, p->fsPath);
673 FREE(p->archivePath);
680 static int compareFileListRecs(const void *ap, const void *bp)
684 a = ((struct FileListRec *)ap)->fileName;
685 b = ((struct FileListRec *)bp)->fileName;
690 static int isDoc(struct FileList *fl, char *fileName)
692 int x = fl->docDirCount;
695 if (strstr(fileName, fl->docDirs[x]) == fileName) {
702 static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName)
704 char fullname[BUFSIZ];
706 int x, offset, rc = 0;
708 /* check that file starts with leading "/" */
709 if (*fileName != '/') {
710 rpmError(RPMERR_BADSPEC, "File needs leading \"/\": %s", *fileName);
711 fl->processingFailed = 1;
715 if (myGlobPatternP(fileName)) {
717 sprintf(fullname, "%s%s", fl->buildRoot, fileName);
718 offset = strlen(fl->buildRoot);
720 strcpy(fullname, fileName);
724 if (glob(fullname, 0, glob_error, &glob_result) ||
725 (glob_result.gl_pathc < 1)) {
726 rpmError(RPMERR_BADSPEC, "File not found: %s", fullname);
727 fl->processingFailed = 1;
728 globfree(&glob_result);
733 while (x < glob_result.gl_pathc) {
734 rc = addFile(fl, &(glob_result.gl_pathv[x][offset]), NULL);
737 globfree(&glob_result);
739 rc = addFile(fl, fileName, NULL);
745 static int addFile(struct FileList *fl, char *name, struct stat *statp)
747 char fileName[BUFSIZ];
748 char diskName[BUFSIZ];
749 char *prefixTest, *prefixPtr;
752 int fileUid, fileGid;
753 char *fileUname, *fileGname;
756 strcpy(fileName, cleanFileName(name));
759 /* Any buildRoot is already prepended */
760 strcpy(diskName, fileName);
762 strcpy(fileName, diskName + strlen(fl->buildRoot));
766 sprintf(diskName, "%s%s", fl->buildRoot, fileName);
768 strcpy(diskName, fileName);
772 /* If we are using a prefix, validate the file */
773 if (!fl->inFtw && fl->prefix) {
774 prefixTest = fileName;
775 prefixPtr = fl->prefix;
777 while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
781 if (*prefixPtr || (*prefixTest && *prefixTest != '/')) {
782 rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s",
783 fl->prefix, fileName);
784 fl->processingFailed = 1;
785 return RPMERR_BADSPEC;
791 if (lstat(diskName, statp)) {
792 rpmError(RPMERR_BADSPEC, "File not found: %s", diskName);
793 fl->processingFailed = 1;
794 return RPMERR_BADSPEC;
798 if ((! fl->isDir) && S_ISDIR(statp->st_mode)) {
799 /* We use our own ftw() call, because ftw() uses stat() */
800 /* instead of lstat(), which causes it to follow symlinks! */
801 /* It also has better callback support. */
803 fl->inFtw = 1; /* Flag to indicate file has buildRoot prefixed */
804 fl->isDir = 1; /* Keep it from following myftw() again */
805 myftw(diskName, 16, (myftwFunc) addFile, fl);
809 fileMode = statp->st_mode;
810 fileUid = statp->st_uid;
811 fileGid = statp->st_gid;
814 if (S_ISDIR(fileMode) && fl->current.PdirmodeString) {
815 if (fl->current.PdirmodeString[0] != '-') {
817 fileMode |= fl->current.Pdirmode;
820 if (fl->current.PmodeString) {
822 fileMode |= fl->current.Pmode;
825 if (fl->current.Uname) {
826 fileUname = getUnameS(fl->current.Uname);
828 fileUname = getUname(fileUid);
830 if (fl->current.Gname) {
831 fileGname = getGnameS(fl->current.Gname);
833 fileGname = getGname(fileGid);
836 if (! (fileUname && fileGname)) {
837 rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", diskName);
838 fl->processingFailed = 1;
839 return RPMERR_BADSPEC;
842 rpmMessage(RPMMESS_DEBUG, "File %d: %s\n", fl->fileCount, fileName);
844 /* Add to the file list */
845 if (fl->fileListRecsUsed == fl->fileListRecsAlloced) {
846 fl->fileListRecsAlloced += 128;
847 fl->fileList = realloc(fl->fileList,
848 fl->fileListRecsAlloced *
849 sizeof(*(fl->fileList)));
852 fl->fileList[fl->fileListRecsUsed].fileName = strdup(fileName);
853 fl->fileList[fl->fileListRecsUsed].diskName = strdup(diskName);
854 fl->fileList[fl->fileListRecsUsed].mode = fileMode;
855 fl->fileList[fl->fileListRecsUsed].uid = fileUid;
856 fl->fileList[fl->fileListRecsUsed].gid = fileGid;
857 fl->fileList[fl->fileListRecsUsed].uname = fileUname;
858 fl->fileList[fl->fileListRecsUsed].gname = fileGname;
860 if (fl->currentLang) {
861 fl->fileList[fl->fileListRecsUsed].lang = strdup(fl->currentLang);
862 } else if (! parseForRegexLang(fileName, &lang)) {
863 fl->fileList[fl->fileListRecsUsed].lang = strdup(lang);
865 fl->fileList[fl->fileListRecsUsed].lang = strdup("");
868 fl->fileList[fl->fileListRecsUsed].flags = fl->currentFlags;
869 fl->fileList[fl->fileListRecsUsed].verifyFlags =
870 fl->currentVerifyFlags;
871 fl->fileList[fl->fileListRecsUsed].size = statp->st_size;
872 fl->fileList[fl->fileListRecsUsed].mtime = statp->st_mtime;
873 fl->fileList[fl->fileListRecsUsed].rdev = statp->st_rdev;
874 fl->fileList[fl->fileListRecsUsed].device = statp->st_dev;
875 fl->fileList[fl->fileListRecsUsed].inode = statp->st_ino;
876 fl->fileListRecsUsed++;
878 fl->totalFileSize += statp->st_size;
885 static int parseForSimple(Spec spec, Package pkg, char *buf,
886 struct FileList *fl, char **fileName)
889 int res, specialDoc = 0;
890 char *name, *version;
891 char specialDocBuf[BUFSIZ];
893 specialDocBuf[0] = '\0';
896 s = strtokWithQuotes(buf, " \t\n");
898 if (!strcmp(s, "%docdir")) {
899 s = strtokWithQuotes(NULL, " \t\n");
900 if (fl->docDirCount == MAXDOCDIR) {
901 rpmError(RPMERR_INTERNAL, "Hit limit for %%docdir");
902 fl->processingFailed = 1;
905 fl->docDirs[fl->docDirCount++] = strdup(s);
906 if (strtokWithQuotes(NULL, " \t\n")) {
907 rpmError(RPMERR_INTERNAL, "Only one arg for %%docdir");
908 fl->processingFailed = 1;
912 } else if (!strcmp(s, "%doc")) {
913 fl->currentFlags |= RPMFILE_DOC;
914 } else if (!strcmp(s, "%ghost")) {
915 fl->currentFlags |= RPMFILE_GHOST;
916 } else if (!strcmp(s, "%dir")) {
920 /* We already got a file -- error */
921 rpmError(RPMERR_BADSPEC,
922 "Two files on one line: %s", *fileName);
923 fl->processingFailed = 1;
927 if (fl->currentFlags & RPMFILE_DOC) {
929 strcat(specialDocBuf, " ");
930 strcat(specialDocBuf, s);
932 /* not in %doc, does not begin with / -- error */
933 rpmError(RPMERR_BADSPEC,
934 "File must begin with \"/\": %s", s);
935 fl->processingFailed = 1;
942 s = strtokWithQuotes(NULL, " \t\n");
946 if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
947 rpmError(RPMERR_BADSPEC,
948 "Can't mix special %%doc with other forms: %s",
950 fl->processingFailed = 1;
953 headerGetEntry(pkg->header, RPMTAG_NAME, NULL,
954 (void *) &name, NULL);
955 headerGetEntry(pkg->header, RPMTAG_VERSION, NULL,
956 (void *) &version, NULL);
957 sprintf(buf, "%s/%s-%s", spec->docDir, name, version);
959 if (! fl->passedSpecialDoc) {
960 pkg->specialDoc = newStringBuf();
961 appendStringBuf(pkg->specialDoc, "DOCDIR=$RPM_BUILD_ROOT");
962 appendLineStringBuf(pkg->specialDoc, buf);
963 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
964 appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR");
965 appendLineStringBuf(pkg->specialDoc, MKDIR_P " $DOCDIR");
968 fl->passedSpecialDoc = 1;
969 fl->isSpecialDoc = 1;
972 appendStringBuf(pkg->specialDoc, "cp -pr ");
973 appendStringBuf(pkg->specialDoc, specialDocBuf);
974 appendLineStringBuf(pkg->specialDoc, " $DOCDIR");
981 static int parseForVerify(char *buf, struct FileList *fl)
983 char *p, *start, *end, *name;
985 int not, verifyFlags;
988 if (!(p = start = strstr(buf, "%verify"))) {
989 if (!(p = start = strstr(buf, "%defverify"))) {
993 resultVerify = &(fl->defVerifyFlags);
997 resultVerify = &(fl->currentVerifyFlags);
1004 rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf);
1005 fl->processingFailed = 1;
1006 return RPMERR_BADSPEC;
1011 while (*end && *end != ')') {
1016 rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf);
1017 fl->processingFailed = 1;
1018 return RPMERR_BADSPEC;
1021 strncpy(ourbuf, p, end-p);
1022 ourbuf[end-p] = '\0';
1023 while (start <= end) {
1027 p = strtok(ourbuf, ", \n\t");
1029 verifyFlags = RPMVERIFY_NONE;
1031 if (!strcmp(p, "not")) {
1033 } else if (!strcmp(p, "md5")) {
1034 verifyFlags |= RPMVERIFY_MD5;
1035 } else if (!strcmp(p, "size")) {
1036 verifyFlags |= RPMVERIFY_FILESIZE;
1037 } else if (!strcmp(p, "link")) {
1038 verifyFlags |= RPMVERIFY_LINKTO;
1039 } else if (!strcmp(p, "user")) {
1040 verifyFlags |= RPMVERIFY_USER;
1041 } else if (!strcmp(p, "group")) {
1042 verifyFlags |= RPMVERIFY_GROUP;
1043 } else if (!strcmp(p, "mtime")) {
1044 verifyFlags |= RPMVERIFY_MTIME;
1045 } else if (!strcmp(p, "mode")) {
1046 verifyFlags |= RPMVERIFY_MODE;
1047 } else if (!strcmp(p, "rdev")) {
1048 verifyFlags |= RPMVERIFY_RDEV;
1050 rpmError(RPMERR_BADSPEC, "Invalid %s token: %s", name, p);
1051 fl->processingFailed = 1;
1052 return RPMERR_BADSPEC;
1054 p = strtok(NULL, ", \n\t");
1057 *resultVerify = not ? ~(verifyFlags) : verifyFlags;
1062 static int parseForRegexLang(char *fileName, char **lang)
1064 static int initialized = 0;
1065 static int hasRegex = 0;
1066 static regex_t compiledPatt;
1067 static char buf[BUFSIZ];
1069 regmatch_t matches[2];
1072 if (! initialized) {
1074 patt = rpmGetVar(RPMVAR_LANGPATT);
1078 if (regcomp(&compiledPatt, patt, REG_EXTENDED)) {
1088 if (! regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL)) {
1090 s = fileName + matches[1].rm_eo - 1;
1091 x = matches[1].rm_eo - matches[1].rm_so;
1103 static int parseForLang(char *buf, struct FileList *fl)
1105 char *p, *start, *end;
1108 if (!(p = start = strstr(buf, "%lang"))) {
1116 rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf);
1117 fl->processingFailed = 1;
1118 return RPMERR_BADSPEC;
1123 while (*end && *end != ')') {
1128 rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf);
1129 fl->processingFailed = 1;
1130 return RPMERR_BADSPEC;
1133 strncpy(ourbuf, p, end-p);
1134 ourbuf[end-p] = '\0';
1135 while (start <= end) {
1139 p = strtok(ourbuf, ", \n\t");
1141 rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf);
1142 fl->processingFailed = 1;
1143 return RPMERR_BADSPEC;
1145 if (strlen(p) != 2) {
1146 rpmError(RPMERR_BADSPEC, "%%lang() entries are 2 characters: %s", buf);
1147 fl->processingFailed = 1;
1148 return RPMERR_BADSPEC;
1150 if (strtok(NULL, ", \n\t")) {
1151 rpmError(RPMERR_BADSPEC, "Only one entry in %%lang(): %s", buf);
1152 fl->processingFailed = 1;
1153 return RPMERR_BADSPEC;
1155 fl->currentLang = strdup(p);
1160 static int parseForAttr(char *buf, struct FileList *fl)
1162 char *p, *s, *start, *end, *name;
1165 struct AttrRec *resultAttr;
1167 if (!(p = start = strstr(buf, "%attr"))) {
1168 if (!(p = start = strstr(buf, "%defattr"))) {
1173 resultAttr = &(fl->def);
1177 resultAttr = &(fl->current);
1181 resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL;
1186 rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf);
1187 fl->processingFailed = 1;
1188 return RPMERR_BADSPEC;
1193 while (*end && *end != ')') {
1198 rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf);
1199 fl->processingFailed = 1;
1200 return RPMERR_BADSPEC;
1208 rpmError(RPMERR_BADSPEC,
1209 "No files after %%defattr(): %s", buf);
1210 fl->processingFailed = 1;
1211 return RPMERR_BADSPEC;
1215 strncpy(ourbuf, p, end-p);
1216 ourbuf[end-p] = '\0';
1218 resultAttr->PmodeString = strtok(ourbuf, ", \n\t");
1219 resultAttr->Uname = strtok(NULL, ", \n\t");
1220 resultAttr->Gname = strtok(NULL, ", \n\t");
1221 resultAttr->PdirmodeString = strtok(NULL, ", \n\t");
1223 if (! (resultAttr->PmodeString &&
1224 resultAttr->Uname && resultAttr->Gname)) {
1225 rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf);
1226 resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL;
1227 fl->processingFailed = 1;
1228 return RPMERR_BADSPEC;
1231 /* Do a quick test on the mode argument and adjust for "-" */
1232 if (!strcmp(resultAttr->PmodeString, "-")) {
1233 resultAttr->PmodeString = NULL;
1235 x = sscanf(resultAttr->PmodeString, "%o", &(resultAttr->Pmode));
1236 if ((x == 0) || (resultAttr->Pmode >> 12)) {
1237 rpmError(RPMERR_BADSPEC, "Bad %s() mode spec: %s", name, buf);
1238 resultAttr->PmodeString = resultAttr->Uname =
1239 resultAttr->Gname = NULL;
1240 fl->processingFailed = 1;
1241 return RPMERR_BADSPEC;
1243 resultAttr->PmodeString = strdup(resultAttr->PmodeString);
1245 if (resultAttr->PdirmodeString) {
1246 /* The processing here is slightly different to maintain */
1247 /* compatibility with old spec files. */
1248 if (!strcmp(resultAttr->PdirmodeString, "-")) {
1249 resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString);
1251 x = sscanf(resultAttr->PdirmodeString, "%o",
1252 &(resultAttr->Pdirmode));
1253 if ((x == 0) || (resultAttr->Pdirmode >> 12)) {
1254 rpmError(RPMERR_BADSPEC,
1255 "Bad %s() dirmode spec: %s", name, buf);
1256 resultAttr->PmodeString = resultAttr->Uname =
1257 resultAttr->Gname = resultAttr->PdirmodeString = NULL;
1258 fl->processingFailed = 1;
1259 return RPMERR_BADSPEC;
1261 resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString);
1264 if (!strcmp(resultAttr->Uname, "-")) {
1265 resultAttr->Uname = NULL;
1267 resultAttr->Uname = strdup(resultAttr->Uname);
1269 if (!strcmp(resultAttr->Gname, "-")) {
1270 resultAttr->Gname = NULL;
1272 resultAttr->Gname = strdup(resultAttr->Gname);
1275 /* Set everything we just parsed to blank spaces */
1276 while (start <= end) {
1283 static int parseForConfig(char *buf, struct FileList *fl)
1285 char *p, *start, *end;
1288 if (!(p = start = strstr(buf, "%config"))) {
1291 fl->currentFlags = RPMFILE_CONFIG;
1305 while (*end && *end != ')') {
1310 rpmError(RPMERR_BADSPEC, "Bad %%config() syntax: %s", buf);
1311 fl->processingFailed = 1;
1312 return RPMERR_BADSPEC;
1315 strncpy(ourbuf, p, end-p);
1316 ourbuf[end-p] = '\0';
1317 while (start <= end) {
1321 p = strtok(ourbuf, ", \n\t");
1323 if (!strcmp(p, "missingok")) {
1324 fl->currentFlags |= RPMFILE_MISSINGOK;
1325 } else if (!strcmp(p, "noreplace")) {
1326 fl->currentFlags |= RPMFILE_NOREPLACE;
1328 rpmError(RPMERR_BADSPEC, "Invalid %%config token: %s", p);
1329 fl->processingFailed = 1;
1330 return RPMERR_BADSPEC;
1332 p = strtok(NULL, ", \n\t");
1338 /* glob_pattern_p() taken from bash
1339 * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
1341 * Return nonzero if PATTERN has any special globbing chars in it.
1343 static int myGlobPatternP (char *pattern)
1345 register char *p = pattern;
1349 while ((c = *p++) != '\0')
1354 case '[': /* Only accept an open brace if there is a close */
1355 open++; /* brace to match it. Bracket expressions must be */
1356 continue; /* complete, according to Posix.2 */
1369 static int glob_error(const char *foo, int bar)
1374 /* strtokWithQuotes() modified from glibc strtok() */
1375 /* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
1376 This file is part of the GNU C Library.
1378 The GNU C Library is free software; you can redistribute it and/or
1379 modify it under the terms of the GNU Library General Public License as
1380 published by the Free Software Foundation; either version 2 of the
1381 License, or (at your option) any later version.
1383 The GNU C Library is distributed in the hope that it will be useful,
1384 but WITHOUT ANY WARRANTY; without even the implied warranty of
1385 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1386 Library General Public License for more details.
1388 You should have received a copy of the GNU Library General Public
1389 License along with the GNU C Library; see the file COPYING.LIB. If
1390 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1391 Boston, MA 02111-1307, USA. */
1393 static char *strtokWithQuotes(char *s, char *delim)
1395 static char *olds = NULL;
1402 /* Skip leading delimiters */
1403 s += strspn(s, delim);
1408 /* Find the end of the token. */
1410 if (*token == '"') {
1412 /* Find next " char */
1413 s = strchr(token, '"');
1415 s = strpbrk(token, delim);
1420 /* This token finishes the string */
1421 olds = strchr(token, '\0');
1423 /* Terminate the token and make olds point past it */