00001
00007 #include "system.h"
00008
00009 #define MYALLPERMS 07777
00010
00011 #include <regex.h>
00012
00013 #include <rpmio_internal.h>
00014 #include <fts.h>
00015
00016 #include <rpmbuild.h>
00017
00018 #include "cpio.h"
00019
00020 #include "argv.h"
00021 #include "rpmfc.h"
00022
00023 #define _RPMFI_INTERNAL
00024 #include "rpmfi.h"
00025
00026 #include "rpmsx.h"
00027
00028
00029 #define _RPMTE_INTERNAL
00030 #include "rpmte.h"
00031
00032 #include "buildio.h"
00033
00034 #include "legacy.h"
00035 #include "misc.h"
00036 #include "debug.h"
00037
00038
00039
00040
00041
00042
00043
00044 #define SKIPWHITE(_x) {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00045 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00046
00047 #define MAXDOCDIR 1024
00048
00051 typedef enum specdFlags_e {
00052 SPECD_DEFFILEMODE = (1 << 0),
00053 SPECD_DEFDIRMODE = (1 << 1),
00054 SPECD_DEFUID = (1 << 2),
00055 SPECD_DEFGID = (1 << 3),
00056 SPECD_DEFVERIFY = (1 << 4),
00057
00058 SPECD_FILEMODE = (1 << 8),
00059 SPECD_DIRMODE = (1 << 9),
00060 SPECD_UID = (1 << 10),
00061 SPECD_GID = (1 << 11),
00062 SPECD_VERIFY = (1 << 12)
00063 } specdFlags;
00064
00067 typedef struct FileListRec_s {
00068 struct stat fl_st;
00069 #define fl_dev fl_st.st_dev
00070 #define fl_ino fl_st.st_ino
00071 #define fl_mode fl_st.st_mode
00072 #define fl_nlink fl_st.st_nlink
00073 #define fl_uid fl_st.st_uid
00074 #define fl_gid fl_st.st_gid
00075 #define fl_rdev fl_st.st_rdev
00076 #define fl_size fl_st.st_size
00077 #define fl_mtime fl_st.st_mtime
00078
00079
00080 const char *diskURL;
00081
00082 const char *fileURL;
00083
00084 const char *uname;
00085
00086 const char *gname;
00087 unsigned flags;
00088 specdFlags specdFlags;
00089 unsigned verifyFlags;
00090
00091 const char *langs;
00092 } * FileListRec;
00093
00096 typedef struct AttrRec_s {
00097
00098 const char *ar_fmodestr;
00099
00100 const char *ar_dmodestr;
00101
00102 const char *ar_user;
00103
00104 const char *ar_group;
00105 mode_t ar_fmode;
00106 mode_t ar_dmode;
00107 } * AttrRec;
00108
00109
00110
00111 static struct AttrRec_s root_ar = { NULL, NULL, "root", "root", 0, 0 };
00112
00113
00114
00115
00116 static StringBuf check_fileList = NULL;
00117
00121 typedef struct FileList_s {
00122
00123 const char * buildRootURL;
00124
00125 const char * prefix;
00126
00127 int fileCount;
00128 int totalFileSize;
00129 int processingFailed;
00130
00131 int passedSpecialDoc;
00132 int isSpecialDoc;
00133
00134 int noGlob;
00135 unsigned devtype;
00136 unsigned devmajor;
00137 int devminor;
00138
00139 int isDir;
00140 int inFtw;
00141 int currentFlags;
00142 specdFlags currentSpecdFlags;
00143 int currentVerifyFlags;
00144 struct AttrRec_s cur_ar;
00145 struct AttrRec_s def_ar;
00146 specdFlags defSpecdFlags;
00147 int defVerifyFlags;
00148 int nLangs;
00149
00150 const char ** currentLangs;
00151
00152
00153
00154 const char * docDirs[MAXDOCDIR];
00155 int docDirCount;
00156
00157
00158 FileListRec fileList;
00159 int fileListRecsAlloced;
00160 int fileListRecsUsed;
00161 } * FileList;
00162
00165 static void nullAttrRec( AttrRec ar)
00166 {
00167 ar->ar_fmodestr = NULL;
00168 ar->ar_dmodestr = NULL;
00169 ar->ar_user = NULL;
00170 ar->ar_group = NULL;
00171 ar->ar_fmode = 0;
00172 ar->ar_dmode = 0;
00173 }
00174
00177 static void freeAttrRec(AttrRec ar)
00178 {
00179 ar->ar_fmodestr = _free(ar->ar_fmodestr);
00180 ar->ar_dmodestr = _free(ar->ar_dmodestr);
00181 ar->ar_user = _free(ar->ar_user);
00182 ar->ar_group = _free(ar->ar_group);
00183
00184
00185 return;
00186
00187 }
00188
00191 static void dupAttrRec(const AttrRec oar, AttrRec nar)
00192
00193 {
00194 if (oar == nar)
00195 return;
00196 freeAttrRec(nar);
00197 nar->ar_fmodestr = (oar->ar_fmodestr ? xstrdup(oar->ar_fmodestr) : NULL);
00198 nar->ar_dmodestr = (oar->ar_dmodestr ? xstrdup(oar->ar_dmodestr) : NULL);
00199 nar->ar_user = (oar->ar_user ? xstrdup(oar->ar_user) : NULL);
00200 nar->ar_group = (oar->ar_group ? xstrdup(oar->ar_group) : NULL);
00201 nar->ar_fmode = oar->ar_fmode;
00202 nar->ar_dmode = oar->ar_dmode;
00203 }
00204
00205 #if 0
00206
00208 static void dumpAttrRec(const char * msg, AttrRec ar)
00209
00210
00211 {
00212 if (msg)
00213 fprintf(stderr, "%s:\t", msg);
00214 fprintf(stderr, "(%s, %s, %s, %s)\n",
00215 ar->ar_fmodestr,
00216 ar->ar_user,
00217 ar->ar_group,
00218 ar->ar_dmodestr);
00219 }
00220 #endif
00221
00226
00227
00228 static char *strtokWithQuotes( char *s, char *delim)
00229
00230 {
00231 static char *olds = NULL;
00232 char *token;
00233
00234 if (s == NULL)
00235 s = olds;
00236 if (s == NULL)
00237 return NULL;
00238
00239
00240 s += strspn(s, delim);
00241 if (*s == '\0')
00242 return NULL;
00243
00244
00245 token = s;
00246 if (*token == '"') {
00247 token++;
00248
00249 s = strchr(token, '"');
00250 } else {
00251 s = strpbrk(token, delim);
00252 }
00253
00254
00255 if (s == NULL) {
00256
00257 olds = strchr(token, '\0');
00258 } else {
00259
00260 *s = '\0';
00261 olds = s+1;
00262 }
00263
00264
00265 return token;
00266
00267 }
00268
00269
00272 static void timeCheck(int tc, Header h)
00273
00274
00275 {
00276 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00277 HFD_t hfd = headerFreeData;
00278 int * mtime;
00279 const char ** files;
00280 rpmTagType fnt;
00281 int count, x;
00282 time_t currentTime = time(NULL);
00283
00284 x = hge(h, RPMTAG_OLDFILENAMES, &fnt, (void **) &files, &count);
00285 x = hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL);
00286
00287
00288 for (x = 0; x < count; x++) {
00289 if ((currentTime - mtime[x]) > tc)
00290 rpmMessage(RPMMESS_WARNING, _("TIMECHECK failure: %s\n"), files[x]);
00291 }
00292 files = hfd(files, fnt);
00293
00294 }
00295
00298 typedef struct VFA {
00299 const char * attribute;
00300 int not;
00301 int flag;
00302 } VFA_t;
00303
00306
00307
00308 VFA_t verifyAttrs[] = {
00309 { "md5", 0, RPMVERIFY_MD5 },
00310 { "size", 0, RPMVERIFY_FILESIZE },
00311 { "link", 0, RPMVERIFY_LINKTO },
00312 { "user", 0, RPMVERIFY_USER },
00313 { "group", 0, RPMVERIFY_GROUP },
00314 { "mtime", 0, RPMVERIFY_MTIME },
00315 { "mode", 0, RPMVERIFY_MODE },
00316 { "rdev", 0, RPMVERIFY_RDEV },
00317 { NULL, 0, 0 }
00318 };
00319
00320
00327
00328 static int parseForVerify(char * buf, FileList fl)
00329
00330
00331
00332 {
00333 char *p, *pe, *q;
00334 const char *name;
00335 int *resultVerify;
00336 int negated;
00337 int verifyFlags;
00338 specdFlags * specdFlags;
00339
00340 if ((p = strstr(buf, (name = "%verify"))) != NULL) {
00341 resultVerify = &(fl->currentVerifyFlags);
00342 specdFlags = &fl->currentSpecdFlags;
00343 } else if ((p = strstr(buf, (name = "%defverify"))) != NULL) {
00344 resultVerify = &(fl->defVerifyFlags);
00345 specdFlags = &fl->defSpecdFlags;
00346 } else
00347 return 0;
00348
00349 for (pe = p; (pe-p) < strlen(name); pe++)
00350 *pe = ' ';
00351
00352 SKIPSPACE(pe);
00353
00354 if (*pe != '(') {
00355 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00356 fl->processingFailed = 1;
00357 return RPMERR_BADSPEC;
00358 }
00359
00360
00361 *pe++ = ' ';
00362 for (p = pe; *pe && *pe != ')'; pe++)
00363 {};
00364
00365 if (*pe == '\0') {
00366 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00367 fl->processingFailed = 1;
00368 return RPMERR_BADSPEC;
00369 }
00370
00371
00372 q = alloca((pe-p) + 1);
00373 strncpy(q, p, pe-p);
00374 q[pe-p] = '\0';
00375 while (p <= pe)
00376 *p++ = ' ';
00377
00378 negated = 0;
00379 verifyFlags = RPMVERIFY_NONE;
00380
00381 for (p = q; *p != '\0'; p = pe) {
00382 SKIPWHITE(p);
00383 if (*p == '\0')
00384 break;
00385 pe = p;
00386 SKIPNONWHITE(pe);
00387 if (*pe != '\0')
00388 *pe++ = '\0';
00389
00390 { VFA_t *vfa;
00391 for (vfa = verifyAttrs; vfa->attribute != NULL; vfa++) {
00392 if (strcmp(p, vfa->attribute))
00393 continue;
00394 verifyFlags |= vfa->flag;
00395 break;
00396 }
00397 if (vfa->attribute)
00398 continue;
00399 }
00400
00401 if (!strcmp(p, "not")) {
00402 negated ^= 1;
00403 } else {
00404 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00405 fl->processingFailed = 1;
00406 return RPMERR_BADSPEC;
00407 }
00408 }
00409
00410 *resultVerify = negated ? ~(verifyFlags) : verifyFlags;
00411 *specdFlags |= SPECD_VERIFY;
00412
00413 return 0;
00414 }
00415
00416
00417 #define isAttrDefault(_ars) ((_ars)[0] == '-' && (_ars)[1] == '\0')
00418
00425
00426 static int parseForDev(char * buf, FileList fl)
00427
00428
00429 {
00430 const char * name;
00431 const char * errstr = NULL;
00432 char *p, *pe, *q;
00433 int rc = RPMERR_BADSPEC;
00434
00435 if ((p = strstr(buf, (name = "%dev"))) == NULL)
00436 return 0;
00437
00438 for (pe = p; (pe-p) < strlen(name); pe++)
00439 *pe = ' ';
00440 SKIPSPACE(pe);
00441
00442 if (*pe != '(') {
00443 errstr = "'('";
00444 goto exit;
00445 }
00446
00447
00448 *pe++ = ' ';
00449 for (p = pe; *pe && *pe != ')'; pe++)
00450 {};
00451 if (*pe != ')') {
00452 errstr = "')'";
00453 goto exit;
00454 }
00455
00456
00457 q = alloca((pe-p) + 1);
00458 strncpy(q, p, pe-p);
00459 q[pe-p] = '\0';
00460 while (p <= pe)
00461 *p++ = ' ';
00462
00463 p = q; SKIPWHITE(p);
00464 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00465 if (*p == 'b')
00466 fl->devtype = 'b';
00467 else if (*p == 'c')
00468 fl->devtype = 'c';
00469 else {
00470 errstr = "devtype";
00471 goto exit;
00472 }
00473
00474 p = pe; SKIPWHITE(p);
00475 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00476 for (pe = p; *pe && xisdigit(*pe); pe++)
00477 {} ;
00478 if (*pe == '\0') {
00479 fl->devmajor = atoi(p);
00480
00481 if (!(fl->devmajor >= 0 && fl->devmajor < 256)) {
00482 errstr = "devmajor";
00483 goto exit;
00484 }
00485
00486 pe++;
00487 } else {
00488 errstr = "devmajor";
00489 goto exit;
00490 }
00491
00492 p = pe; SKIPWHITE(p);
00493 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00494 for (pe = p; *pe && xisdigit(*pe); pe++)
00495 {} ;
00496 if (*pe == '\0') {
00497 fl->devminor = atoi(p);
00498 if (!(fl->devminor >= 0 && fl->devminor < 256)) {
00499 errstr = "devminor";
00500 goto exit;
00501 }
00502 pe++;
00503 } else {
00504 errstr = "devminor";
00505 goto exit;
00506 }
00507
00508 fl->noGlob = 1;
00509
00510 rc = 0;
00511
00512 exit:
00513 if (rc) {
00514 rpmError(RPMERR_BADSPEC, _("Missing %s in %s %s\n"), errstr, name, p);
00515 fl->processingFailed = 1;
00516 }
00517 return rc;
00518 }
00519
00520
00527
00528 static int parseForAttr(char * buf, FileList fl)
00529
00530
00531
00532 {
00533 const char *name;
00534 char *p, *pe, *q;
00535 int x;
00536 struct AttrRec_s arbuf;
00537 AttrRec ar = &arbuf, ret_ar;
00538 specdFlags * specdFlags;
00539
00540 if ((p = strstr(buf, (name = "%attr"))) != NULL) {
00541 ret_ar = &(fl->cur_ar);
00542 specdFlags = &fl->currentSpecdFlags;
00543 } else if ((p = strstr(buf, (name = "%defattr"))) != NULL) {
00544 ret_ar = &(fl->def_ar);
00545 specdFlags = &fl->defSpecdFlags;
00546 } else
00547 return 0;
00548
00549 for (pe = p; (pe-p) < strlen(name); pe++)
00550 *pe = ' ';
00551
00552 SKIPSPACE(pe);
00553
00554 if (*pe != '(') {
00555 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00556 fl->processingFailed = 1;
00557 return RPMERR_BADSPEC;
00558 }
00559
00560
00561 *pe++ = ' ';
00562 for (p = pe; *pe && *pe != ')'; pe++)
00563 {};
00564
00565 if (ret_ar == &(fl->def_ar)) {
00566 q = pe;
00567 q++;
00568 SKIPSPACE(q);
00569 if (*q != '\0') {
00570 rpmError(RPMERR_BADSPEC,
00571 _("Non-white space follows %s(): %s\n"), name, q);
00572 fl->processingFailed = 1;
00573 return RPMERR_BADSPEC;
00574 }
00575 }
00576
00577
00578 q = alloca((pe-p) + 1);
00579 strncpy(q, p, pe-p);
00580 q[pe-p] = '\0';
00581 while (p <= pe)
00582 *p++ = ' ';
00583
00584 nullAttrRec(ar);
00585
00586 p = q; SKIPWHITE(p);
00587 if (*p != '\0') {
00588 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00589 ar->ar_fmodestr = p;
00590 p = pe; SKIPWHITE(p);
00591 }
00592 if (*p != '\0') {
00593 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00594 ar->ar_user = p;
00595 p = pe; SKIPWHITE(p);
00596 }
00597 if (*p != '\0') {
00598 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00599 ar->ar_group = p;
00600 p = pe; SKIPWHITE(p);
00601 }
00602 if (*p != '\0' && ret_ar == &(fl->def_ar)) {
00603 pe = p; SKIPNONWHITE(pe); if (*pe != '\0') *pe++ = '\0';
00604 ar->ar_dmodestr = p;
00605 p = pe; SKIPWHITE(p);
00606 }
00607
00608 if (!(ar->ar_fmodestr && ar->ar_user && ar->ar_group) || *p != '\0') {
00609 rpmError(RPMERR_BADSPEC, _("Bad syntax: %s(%s)\n"), name, q);
00610 fl->processingFailed = 1;
00611 return RPMERR_BADSPEC;
00612 }
00613
00614
00615 if (ar->ar_fmodestr && !isAttrDefault(ar->ar_fmodestr)) {
00616 unsigned int ui;
00617 x = sscanf(ar->ar_fmodestr, "%o", &ui);
00618 if ((x == 0) || (ar->ar_fmode & ~MYALLPERMS)) {
00619 rpmError(RPMERR_BADSPEC, _("Bad mode spec: %s(%s)\n"), name, q);
00620 fl->processingFailed = 1;
00621 return RPMERR_BADSPEC;
00622 }
00623 ar->ar_fmode = ui;
00624 } else
00625 ar->ar_fmodestr = NULL;
00626
00627 if (ar->ar_dmodestr && !isAttrDefault(ar->ar_dmodestr)) {
00628 unsigned int ui;
00629 x = sscanf(ar->ar_dmodestr, "%o", &ui);
00630 if ((x == 0) || (ar->ar_dmode & ~MYALLPERMS)) {
00631 rpmError(RPMERR_BADSPEC, _("Bad dirmode spec: %s(%s)\n"), name, q);
00632 fl->processingFailed = 1;
00633 return RPMERR_BADSPEC;
00634 }
00635 ar->ar_dmode = ui;
00636 } else
00637 ar->ar_dmodestr = NULL;
00638
00639 if (!(ar->ar_user && !isAttrDefault(ar->ar_user)))
00640 ar->ar_user = NULL;
00641
00642 if (!(ar->ar_group && !isAttrDefault(ar->ar_group)))
00643 ar->ar_group = NULL;
00644
00645 dupAttrRec(ar, ret_ar);
00646
00647
00648 *specdFlags |= SPECD_UID | SPECD_GID | SPECD_FILEMODE | SPECD_DIRMODE;
00649
00650 return 0;
00651 }
00652
00653
00660
00661 static int parseForConfig(char * buf, FileList fl)
00662
00663 {
00664 char *p, *pe, *q;
00665 const char *name;
00666
00667 if ((p = strstr(buf, (name = "%config"))) == NULL)
00668 return 0;
00669
00670 fl->currentFlags |= RPMFILE_CONFIG;
00671
00672
00673 for (pe = p; (pe-p) < strlen(name); pe++)
00674 *pe = ' ';
00675 SKIPSPACE(pe);
00676 if (*pe != '(')
00677 return 0;
00678
00679
00680 *pe++ = ' ';
00681 for (p = pe; *pe && *pe != ')'; pe++)
00682 {};
00683
00684 if (*pe == '\0') {
00685 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00686 fl->processingFailed = 1;
00687 return RPMERR_BADSPEC;
00688 }
00689
00690
00691 q = alloca((pe-p) + 1);
00692 strncpy(q, p, pe-p);
00693 q[pe-p] = '\0';
00694 while (p <= pe)
00695 *p++ = ' ';
00696
00697 for (p = q; *p != '\0'; p = pe) {
00698 SKIPWHITE(p);
00699 if (*p == '\0')
00700 break;
00701 pe = p;
00702 SKIPNONWHITE(pe);
00703 if (*pe != '\0')
00704 *pe++ = '\0';
00705 if (!strcmp(p, "missingok")) {
00706 fl->currentFlags |= RPMFILE_MISSINGOK;
00707 } else if (!strcmp(p, "noreplace")) {
00708 fl->currentFlags |= RPMFILE_NOREPLACE;
00709 } else {
00710 rpmError(RPMERR_BADSPEC, _("Invalid %s token: %s\n"), name, p);
00711 fl->processingFailed = 1;
00712 return RPMERR_BADSPEC;
00713 }
00714 }
00715
00716 return 0;
00717 }
00718
00719
00722 static int langCmp(const void * ap, const void * bp)
00723
00724 {
00725
00726 return strcmp(*(const char **)ap, *(const char **)bp);
00727
00728 }
00729
00736
00737 static int parseForLang(char * buf, FileList fl)
00738
00739
00740 {
00741 char *p, *pe, *q;
00742 const char *name;
00743
00744 while ((p = strstr(buf, (name = "%lang"))) != NULL) {
00745
00746 for (pe = p; (pe-p) < strlen(name); pe++)
00747 *pe = ' ';
00748 SKIPSPACE(pe);
00749
00750 if (*pe != '(') {
00751 rpmError(RPMERR_BADSPEC, _("Missing '(' in %s %s\n"), name, pe);
00752 fl->processingFailed = 1;
00753 return RPMERR_BADSPEC;
00754 }
00755
00756
00757 *pe++ = ' ';
00758 for (pe = p; *pe && *pe != ')'; pe++)
00759 {};
00760
00761 if (*pe == '\0') {
00762 rpmError(RPMERR_BADSPEC, _("Missing ')' in %s(%s\n"), name, p);
00763 fl->processingFailed = 1;
00764 return RPMERR_BADSPEC;
00765 }
00766
00767
00768 q = alloca((pe-p) + 1);
00769 strncpy(q, p, pe-p);
00770 q[pe-p] = '\0';
00771 while (p <= pe)
00772 *p++ = ' ';
00773
00774
00775 for (p = q; *p != '\0'; p = pe) {
00776 char *newp;
00777 size_t np;
00778 int i;
00779
00780 SKIPWHITE(p);
00781 pe = p;
00782 SKIPNONWHITE(pe);
00783
00784 np = pe - p;
00785
00786
00787 if (np < 1 || (np == 1 && *p != 'C') || np >= 32) {
00788 rpmError(RPMERR_BADSPEC,
00789 _("Unusual locale length: \"%.*s\" in %%lang(%s)\n"),
00790 (int)np, p, q);
00791 fl->processingFailed = 1;
00792 return RPMERR_BADSPEC;
00793 }
00794
00795
00796 if (fl->currentLangs != NULL)
00797 for (i = 0; i < fl->nLangs; i++) {
00798 if (strncmp(fl->currentLangs[i], p, np))
00799 continue;
00800 rpmError(RPMERR_BADSPEC, _("Duplicate locale %.*s in %%lang(%s)\n"),
00801 (int)np, p, q);
00802 fl->processingFailed = 1;
00803 return RPMERR_BADSPEC;
00804 }
00805
00806
00807 fl->currentLangs = xrealloc(fl->currentLangs,
00808 (fl->nLangs + 1) * sizeof(*fl->currentLangs));
00809 newp = xmalloc( np+1 );
00810 strncpy(newp, p, np);
00811 newp[np] = '\0';
00812 fl->currentLangs[fl->nLangs++] = newp;
00813 if (*pe == ',') pe++;
00814 }
00815 }
00816
00817
00818 if (fl->currentLangs)
00819 qsort(fl->currentLangs, fl->nLangs, sizeof(*fl->currentLangs), langCmp);
00820
00821 return 0;
00822 }
00823
00824
00827
00828 static int parseForRegexLang(const char * fileName, char ** lang)
00829
00830
00831 {
00832 static int initialized = 0;
00833 static int hasRegex = 0;
00834 static regex_t compiledPatt;
00835 static char buf[BUFSIZ];
00836 int x;
00837 regmatch_t matches[2];
00838 const char *s;
00839
00840 if (! initialized) {
00841 const char *patt = rpmExpand("%{?_langpatt}", NULL);
00842 int rc = 0;
00843 if (!(patt && *patt != '\0'))
00844 rc = 1;
00845 else if (regcomp(&compiledPatt, patt, REG_EXTENDED))
00846 rc = -1;
00847 patt = _free(patt);
00848 if (rc)
00849 return rc;
00850 hasRegex = 1;
00851 initialized = 1;
00852 }
00853
00854 memset(matches, 0, sizeof(matches));
00855 if (! hasRegex || regexec(&compiledPatt, fileName, 2, matches, REG_NOTEOL))
00856 return 1;
00857
00858
00859 s = fileName + matches[1].rm_eo - 1;
00860 x = matches[1].rm_eo - matches[1].rm_so;
00861 buf[x] = '\0';
00862 while (x) {
00863 buf[--x] = *s--;
00864 }
00865 if (lang)
00866 *lang = buf;
00867 return 0;
00868 }
00869
00870
00873
00874
00875 VFA_t virtualFileAttributes[] = {
00876 { "%dir", 0, 0 },
00877 { "%doc", 0, RPMFILE_DOC },
00878 { "%ghost", 0, RPMFILE_GHOST },
00879 { "%exclude", 0, RPMFILE_EXCLUDE },
00880 { "%readme", 0, RPMFILE_README },
00881 { "%license", 0, RPMFILE_LICENSE },
00882 { "%pubkey", 0, RPMFILE_PUBKEY },
00883 { "%policy", 0, RPMFILE_POLICY },
00884
00885 #if WHY_NOT
00886 { "%icon", 0, RPMFILE_ICON },
00887 { "%spec", 0, RPMFILE_SPEC },
00888 { "%config", 0, RPMFILE_CONFIG },
00889 { "%missingok", 0, RPMFILE_CONFIG|RPMFILE_MISSINGOK },
00890 { "%noreplace", 0, RPMFILE_CONFIG|RPMFILE_NOREPLACE },
00891 #endif
00892
00893 { NULL, 0, 0 }
00894 };
00895
00896
00906
00907 static int parseForSimple(Spec spec, Package pkg, char * buf,
00908 FileList fl, const char ** fileName)
00909
00910
00911
00912
00913
00914
00915 {
00916 char *s, *t;
00917 int res, specialDoc = 0;
00918 char specialDocBuf[BUFSIZ];
00919
00920 specialDocBuf[0] = '\0';
00921 *fileName = NULL;
00922 res = 0;
00923
00924 t = buf;
00925 while ((s = strtokWithQuotes(t, " \t\n")) != NULL) {
00926 t = NULL;
00927 if (!strcmp(s, "%docdir")) {
00928 s = strtokWithQuotes(NULL, " \t\n");
00929 if (fl->docDirCount == MAXDOCDIR) {
00930 rpmError(RPMERR_INTERNAL, _("Hit limit for %%docdir\n"));
00931 fl->processingFailed = 1;
00932 res = 1;
00933 }
00934
00935 if (s != NULL)
00936 fl->docDirs[fl->docDirCount++] = xstrdup(s);
00937 if (s == NULL || strtokWithQuotes(NULL, " \t\n")) {
00938 rpmError(RPMERR_INTERNAL, _("Only one arg for %%docdir\n"));
00939 fl->processingFailed = 1;
00940 res = 1;
00941 }
00942 break;
00943 }
00944 #if defined(__LCLINT__)
00945 assert(s != NULL);
00946 #endif
00947
00948
00949 { VFA_t *vfa;
00950 for (vfa = virtualFileAttributes; vfa->attribute != NULL; vfa++) {
00951 if (strcmp(s, vfa->attribute))
00952 continue;
00953 if (!vfa->flag) {
00954 if (!strcmp(s, "%dir"))
00955 fl->isDir = 1;
00956 } else {
00957 if (vfa->not)
00958 fl->currentFlags &= ~vfa->flag;
00959 else
00960 fl->currentFlags |= vfa->flag;
00961 }
00962
00963 break;
00964 }
00965
00966 if (vfa->attribute != NULL)
00967 continue;
00968 }
00969
00970 if (*fileName) {
00971
00972 rpmError(RPMERR_BADSPEC, _("Two files on one line: %s\n"),
00973 *fileName);
00974 fl->processingFailed = 1;
00975 res = 1;
00976 }
00977
00978
00979 if (*s != '/') {
00980 if (fl->currentFlags & RPMFILE_DOC) {
00981 specialDoc = 1;
00982 strcat(specialDocBuf, " ");
00983 strcat(specialDocBuf, s);
00984 } else
00985 if (fl->currentFlags & (RPMFILE_POLICY|RPMFILE_PUBKEY|RPMFILE_ICON))
00986 {
00987 *fileName = s;
00988 } else {
00989 const char * sfn = NULL;
00990 int urltype = urlPath(s, &sfn);
00991 switch (urltype) {
00992 default:
00993 rpmError(RPMERR_BADSPEC,
00994 _("File must begin with \"/\": %s\n"), s);
00995 fl->processingFailed = 1;
00996 res = 1;
00997 break;
00998 case URL_IS_PATH:
00999 *fileName = s;
01000 break;
01001 }
01002 }
01003 } else {
01004 *fileName = s;
01005 }
01006
01007 }
01008
01009 if (specialDoc) {
01010 if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) {
01011 rpmError(RPMERR_BADSPEC,
01012 _("Can't mix special %%doc with other forms: %s\n"),
01013 (*fileName ? *fileName : ""));
01014 fl->processingFailed = 1;
01015 res = 1;
01016 } else {
01017
01018 { static char *_docdir_fmt= 0;
01019 static int oneshot = 0;
01020 const char *ddir, *fmt, *errstr;
01021 if (!oneshot) {
01022 _docdir_fmt = rpmExpand("%{?_docdir_fmt}", NULL);
01023 if (!_docdir_fmt || !*_docdir_fmt)
01024 _docdir_fmt = "%{NAME}-%{VERSION}";
01025 oneshot = 1;
01026 }
01027 fmt = headerSprintf(pkg->header, _docdir_fmt, rpmTagTable, rpmHeaderFormats, &errstr);
01028 if (!fmt) {
01029 rpmError(RPMERR_BADSPEC, _("illegal _docdir_fmt: %s\n"), errstr);
01030 fl->processingFailed = 1;
01031 res = 1;
01032 }
01033 ddir = rpmGetPath("%{_docdir}/", fmt, NULL);
01034 strcpy(buf, ddir);
01035 ddir = _free(ddir);
01036 }
01037
01038
01039
01040 if (! fl->passedSpecialDoc) {
01041 char *compress_doc;
01042
01043 pkg->specialDoc = newStringBuf();
01044 appendStringBuf(pkg->specialDoc, "DOCDIR=\"$RPM_BUILD_ROOT\"");
01045 appendLineStringBuf(pkg->specialDoc, buf);
01046 appendLineStringBuf(pkg->specialDoc, "export DOCDIR");
01047 appendLineStringBuf(pkg->specialDoc, "rm -rf \"$DOCDIR\"");
01048 appendLineStringBuf(pkg->specialDoc, MKDIR_P " \"$DOCDIR\"");
01049
01050 compress_doc = rpmExpand("%{__compress_doc}", NULL);
01051 if (compress_doc && *compress_doc != '%')
01052 appendLineStringBuf(pkg->specialDoc, compress_doc);
01053 compress_doc = _free(compress_doc);
01054
01055
01056 *fileName = buf;
01057
01058 fl->passedSpecialDoc = 1;
01059 fl->isSpecialDoc = 1;
01060 }
01061
01062 appendStringBuf(pkg->specialDoc, "cp -pr ");
01063 appendStringBuf(pkg->specialDoc, specialDocBuf);
01064 appendLineStringBuf(pkg->specialDoc, " \"$DOCDIR\"");
01065 }
01066 }
01067
01068 return res;
01069 }
01070
01071
01074 static int compareFileListRecs(const void * ap, const void * bp)
01075 {
01076 const char *aurl = ((FileListRec)ap)->fileURL;
01077 const char *a = NULL;
01078 const char *burl = ((FileListRec)bp)->fileURL;
01079 const char *b = NULL;
01080 (void) urlPath(aurl, &a);
01081 (void) urlPath(burl, &b);
01082 return strcmp(a, b);
01083 }
01084
01092 static int isDoc(FileList fl, const char * fileName)
01093 {
01094 int x = fl->docDirCount;
01095
01096 while (x--) {
01097 if (strstr(fileName, fl->docDirs[x]) == fileName)
01098 return 1;
01099 }
01100 return 0;
01101 }
01102
01109 static int