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

  1. /* RPM - Copyright (C) 1995 Red Hat Software
  2.  * 
  3.  * prepack.c - routines for packaging
  4.  */
  5.  
  6. #include "miscfn.h"
  7.  
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include <sys/stat.h>
  12. #include <time.h>
  13.  
  14. #include "spec.h"
  15. #include "specP.h"
  16. #include "stringbuf.h"
  17. #include "build.h"
  18. #include "messages.h"
  19. #include "md5.h"
  20. #include "myftw.h"
  21. #include "header.h"
  22. #include "files.h"
  23. #include "names.h"
  24. #include "rpmlead.h"
  25. #include "rpmlib.h"
  26. #include "misc.h"
  27. #include "macro.h"
  28.  
  29. #define BINARY_HEADER 0
  30. #define SOURCE_HEADER 1
  31.  
  32. struct file_entry {
  33.     char file[1024];
  34.     int isdoc;
  35.     int conf;
  36.     int isspecfile;
  37.     int verify_flags;
  38.     char *uname;  /* reference -- do not free */
  39.     char *gname;  /* reference -- do not free */
  40.     struct stat statbuf;
  41.     struct file_entry *next;
  42. };
  43.  
  44. static int add_file(struct file_entry **festack, const char *name,
  45.             int isdoc, int isconf, int isdir, int verify_flags,
  46.             char *Pmode, char *Uname, char *Gname, char *prefix);
  47. static int compare_fe(const void *ap, const void *bp);
  48. static int add_file_aux(const char *file, struct stat *sb, int flag);
  49. static int glob_error(const char *foo, int bar);
  50. static int glob_pattern_p (char *pattern);
  51. static int parseForVerify(char *buf, int *verify_flags);
  52. static int parseForConfig(char *buf, int *conf);
  53. static int parseForAttr(char *origbuf, char **currPmode,
  54.             char **currUname, char **currGname);
  55.  
  56. static void resetDocdir(void);
  57. static void addDocdir(char *dirname);
  58. static int isDoc(char *filename);
  59.  
  60. static int processFileListFailed;
  61.  
  62. static void parseForDocFiles(struct PackageRec *package, char *line)
  63. {
  64.     if (! (line = strstr(line, "%doc"))) {
  65.     return;
  66.     }
  67.  
  68.     line += 4;
  69.     if ((*line != ' ') && (*line != '\t')) {
  70.     return;
  71.     }
  72.     line += strspn(line, " \t\n");
  73.     if ((! *line) || (*line == '/')) {
  74.     return;
  75.     }
  76.     
  77.     appendLineStringBuf(package->doc, "mkdir -p $DOCDIR");
  78.     appendStringBuf(package->doc, "cp -pr ");
  79.     appendStringBuf(package->doc, line);
  80.     appendLineStringBuf(package->doc, " $DOCDIR");
  81. }
  82.  
  83. int finish_filelists(Spec spec)
  84. {
  85.     char buf[1024];
  86.     FILE *file;
  87.     struct PackageRec *pr = spec->packages;
  88.     char *s, **files, **line;
  89.     char *version, *release, *packageVersion, *packageRelease, *docs, *name;
  90.  
  91.     headerGetEntry(spec->packages->header, RPMTAG_VERSION, NULL,
  92.          (void *) &version, NULL);
  93.     headerGetEntry(spec->packages->header, RPMTAG_RELEASE, NULL,
  94.          (void *) &release, NULL);
  95.     
  96.     while (pr) {
  97.     if (pr->fileFile) {
  98.         sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR),
  99.             build_subdir, pr->fileFile);
  100.         rpmMessage(RPMMESS_DEBUG, "Reading file names from: %s\n", buf);
  101.         if ((file = fopen(buf, "r")) == NULL) {
  102.         rpmError(RPMERR_BADSPEC, "unable to open filelist: %s\n", buf);
  103.         return(RPMERR_BADSPEC);
  104.         }
  105.         while (fgets(buf, sizeof(buf), file)) {
  106.         expandMacros(buf);
  107.         appendStringBuf(pr->filelist, buf);
  108.         }
  109.         fclose(file);
  110.     }
  111.  
  112.     /* parse for %doc wierdness */
  113.     s = getStringBuf(pr->filelist);
  114.     files = splitString(s, strlen(s), '\n');
  115.     line = files;
  116.     while (*line) {
  117.         parseForDocFiles(pr, *line);
  118.         line++;
  119.     }
  120.     freeSplitString(files);
  121.  
  122.     /* Handle subpackage version/release overrides */
  123.         if (!headerGetEntry(pr->header, RPMTAG_VERSION, NULL,
  124.               (void *) &packageVersion, NULL)) {
  125.             packageVersion = version;
  126.     }
  127.         if (!headerGetEntry(pr->header, RPMTAG_RELEASE, NULL,
  128.               (void *) &packageRelease, NULL)) {
  129.             packageRelease = release;
  130.     }
  131.  
  132.     /* Generate the doc script */
  133.     appendStringBuf(spec->doc, "DOCDIR=$RPM_ROOT_DIR/$RPM_DOC_DIR/");
  134.     headerGetEntry(pr->header, RPMTAG_NAME, NULL, (void *) &name, NULL);
  135.     sprintf(buf, "%s-%s-%s", name, packageVersion, packageRelease);
  136.     appendLineStringBuf(spec->doc, buf);
  137.     docs = getStringBuf(pr->doc);
  138.     if (*docs) {
  139.         appendLineStringBuf(spec->doc, "rm -rf $DOCDIR");
  140.         appendLineStringBuf(spec->doc, docs);
  141.     }
  142.  
  143.     pr = pr->next;
  144.     }
  145.  
  146.     return 0;
  147. }
  148.  
  149. int process_filelist(Header header, struct PackageRec *pr,
  150.              StringBuf sb, int *size, char *name,
  151.              char *version, char *release, int type,
  152.              char *prefix, char *specFile)
  153. {
  154.     char buf[1024];
  155.     char **files, **fp;
  156.     struct file_entry *fes, *fest;
  157.     struct file_entry **file_entry_array;
  158.     int isdoc, conf, isdir, verify_flags;
  159.     char *currPmode=NULL;    /* hold info from %attr() */
  160.     char *currUname=NULL;    /* hold info from %attr() */
  161.     char *currGname=NULL;    /* hold info from %attr() */
  162.     char *filename, *s;
  163.     char *str;
  164.     int count = 0;
  165.     int c, x;
  166.     glob_t glob_result;
  167.     int special_doc;
  168.     int passed_special_doc = 0;
  169.     int tc;
  170.     char *tcs;
  171.     int currentTime;
  172.  
  173.     processFileListFailed = 0;
  174.     fes = NULL;
  175.     *size = 0;
  176.  
  177.     resetDocdir();
  178.  
  179.     str = getStringBuf(sb);
  180.     files = splitString(str, strlen(str), '\n');
  181.     fp = files;
  182.  
  183.     while (*fp) {
  184.     strcpy(buf, *fp);  /* temp copy */
  185.     isdoc = 0;
  186.     special_doc = 0;
  187.     conf = 0;
  188.     isdir = 0;
  189.     if (currPmode) {
  190.         free (currPmode);
  191.         currPmode = NULL;
  192.     }
  193.     if (currUname) {
  194.         free (currUname);
  195.         currUname = NULL;
  196.     }
  197.     if (currGname) {
  198.         free (currGname);
  199.         currGname = NULL;
  200.     }
  201.     verify_flags = RPMVERIFY_ALL;
  202.     filename = NULL;
  203.  
  204.     /* First preparse buf for %verify() */
  205.     if (parseForVerify(buf, &verify_flags)) {
  206.         processFileListFailed = 1;
  207.         fp++; continue;
  208.     }
  209.     
  210.     /* Next parse for %attr() */
  211.     if (parseForAttr(buf, &currPmode, &currUname, &currGname)) {
  212.         processFileListFailed = 1;
  213.         fp++; continue;
  214.     }
  215.  
  216.     /* Then parse for %config or %config() */
  217.     if (parseForConfig(buf, &conf)) {
  218.         processFileListFailed = 1;
  219.         fp++; continue;
  220.     }
  221.  
  222.     s = strtok(buf, " \t\n");
  223.     while (s) {
  224.         if (!strcmp(s, "%docdir")) {
  225.             s = strtok(NULL, " \t\n");
  226.         addDocdir(s);
  227.         break;
  228.         } else if (!strcmp(s, "%doc")) {
  229.         isdoc = 1;
  230.         } else if (!strcmp(s, "%dir")) {
  231.         isdir = 1;
  232.         } else {
  233.         if (filename) {
  234.             /* We already got a file -- error */
  235.             rpmError(RPMERR_BADSPEC,
  236.               "Two files on one line: %s", filename);
  237.             processFileListFailed = 1;
  238.         }
  239.         if (*s != '/') {
  240.             if (isdoc) {
  241.             special_doc = 1;
  242.             } else {
  243.             /* not in %doc, does not begin with / -- error */
  244.             rpmError(RPMERR_BADSPEC,
  245.                   "File must begin with \"/\": %s", s);
  246.             processFileListFailed = 1;
  247.             }
  248.         } else {
  249.             filename = s;
  250.         }
  251.         }
  252.         s = strtok(NULL, " \t\n");
  253.     }
  254.     if (special_doc) {
  255.         if (passed_special_doc) {
  256.         fp++;
  257.         continue;
  258.         } else {
  259.         if (filename || conf || isdir) {
  260.             rpmError(RPMERR_BADSPEC,
  261.               "Can't mix special %%doc with other forms: %s", fp);
  262.             processFileListFailed = 1;
  263.             fp++; continue;
  264.         }
  265.         sprintf(buf, "%s/%s-%s-%s", rpmGetVar(RPMVAR_DEFAULTDOCDIR), 
  266.             name, version, release);
  267.         filename = buf;
  268.         passed_special_doc = 1;
  269.         }
  270.     }
  271.     if (! filename) {
  272.         fp++;
  273.         continue;
  274.     }
  275.  
  276.     if (type == RPMLEAD_BINARY) {
  277.         /* check that file starts with leading "/" */
  278.         if (*filename != '/') {
  279.         rpmError(RPMERR_BADSPEC,
  280.               "File needs leading \"/\": %s", filename);
  281.         processFileListFailed = 1;
  282.         fp++; continue;
  283.         }
  284.  
  285.         if (glob_pattern_p(filename)) {
  286.         char fullname[1024];
  287.  
  288.         if (rpmGetVar(RPMVAR_ROOT)) {
  289.             sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), filename);
  290.         } else {
  291.             strcpy(fullname, filename);
  292.         }
  293.  
  294.             if (glob(fullname, 0, glob_error, &glob_result) ||
  295.             (glob_result.gl_pathc < 1)) {
  296.             rpmError(RPMERR_BADSPEC, "No matches: %s", fullname);
  297.             processFileListFailed = 1;
  298.             globfree(&glob_result);
  299.             fp++; continue;
  300.         }
  301.         
  302.         c = 0;
  303.         x = 0;
  304.         while (x < glob_result.gl_pathc) {
  305.             int offset = strlen(rpmGetVar(RPMVAR_ROOT) ? : "");
  306.             c += add_file(&fes, &(glob_result.gl_pathv[x][offset]),
  307.                   isdoc, conf, isdir, verify_flags,
  308.                   currPmode, currUname, currGname, prefix);
  309.             x++;
  310.         }
  311.         globfree(&glob_result);
  312.         } else {
  313.             c = add_file(&fes, filename, isdoc, conf, isdir,
  314.                  verify_flags, currPmode, currUname,
  315.                  currGname, prefix);
  316.         }
  317.     } else {
  318.         /* Source package are the simple case */
  319.         fest = malloc(sizeof(struct file_entry));
  320.         fest->isdoc = 0;
  321.         fest->conf = 0;
  322.         if (!strcmp(filename, specFile)) {
  323.         fest->isspecfile = 1;
  324.         } else {
  325.         fest->isspecfile = 0;
  326.         }
  327.         fest->verify_flags = 0;  /* XXX - something else? */
  328.         stat(filename, &fest->statbuf);
  329.         fest->uname = getUname(fest->statbuf.st_uid);
  330.         fest->gname = getGname(fest->statbuf.st_gid);
  331.         if (! (fest->uname && fest->gname)) {
  332.         rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", filename);
  333.         fest->uname = "";
  334.         fest->gname = "";
  335.         processFileListFailed = 1;
  336.         }
  337.         strcpy(fest->file, filename);
  338.         fest->next = fes;
  339.         fes = fest;
  340.         c = 1;
  341.     }
  342.         
  343.     if (! c) {
  344.         rpmError(RPMERR_BADSPEC, "File not found: %s", filename);
  345.         processFileListFailed = 1;
  346.     }
  347.     count += c;
  348.     
  349.     fp++;
  350.     }
  351.  
  352.     /* If there are no files, don't add anything to the header */
  353.     if (count) {
  354.     char ** fileList;
  355.     char ** fileMD5List;
  356.     char ** fileLinktoList;
  357.     int_32 * fileSizeList;
  358.     int_32 * fileUIDList;
  359.     int_32 * fileGIDList;
  360.     char ** fileUnameList;
  361.     char ** fileGnameList;
  362.     int_32 * fileMtimesList;
  363.     int_32 * fileFlagsList;
  364.     int_16 * fileModesList;
  365.     int_16 * fileRDevsList;
  366.      int_32 * fileVerifyFlagsList;
  367.  
  368.     fileList = malloc(sizeof(char *) * count);
  369.     fileLinktoList = malloc(sizeof(char *) * count);
  370.     fileMD5List = malloc(sizeof(char *) * count);
  371.     fileSizeList = malloc(sizeof(int_32) * count);
  372.     fileUIDList = malloc(sizeof(int_32) * count);
  373.     fileGIDList = malloc(sizeof(int_32) * count);
  374.     fileUnameList = malloc(sizeof(char *) * count);
  375.     fileGnameList = malloc(sizeof(char *) * count);
  376.     fileMtimesList = malloc(sizeof(int_32) * count);
  377.     fileFlagsList = malloc(sizeof(int_32) * count);
  378.     fileModesList = malloc(sizeof(int_16) * count);
  379.     fileRDevsList = malloc(sizeof(int_16) * count);
  380.     fileVerifyFlagsList = malloc(sizeof(int_32) * count);
  381.  
  382.     /* Build a reverse sorted file array.  */
  383.     /* This makes uninstalls a lot easier. */
  384.     file_entry_array = malloc(sizeof(struct file_entry *) * count);
  385.     c = 0;
  386.     fest = fes;
  387.     while (fest) {
  388.         file_entry_array[c++] = fest;
  389.         fest = fest->next;
  390.     }
  391.     qsort(file_entry_array, count, sizeof(struct file_entry *),
  392.           compare_fe);
  393.         
  394.     /* Do timecheck */
  395.     tc = 0;
  396.     currentTime = time(NULL);
  397.     if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) {
  398.         tc = strtoul(tcs, NULL, 10);
  399.     }
  400.     
  401.     c = 0;
  402.     while (c < count) {
  403.         fest = file_entry_array[c];
  404.         if (type == RPMLEAD_BINARY) {
  405.         x = strlen(fest->file) - 1;
  406.         if (x && fest->file[x] == '/') {
  407.             fest->file[x] = '\0';
  408.         }
  409.         fileList[c] = fest->file;
  410.         } else {
  411.         fileList[c] = strrchr(fest->file, '/') + 1;
  412.         }
  413.         if ((c > 0) && !strcmp(fileList[c], fileList[c-1])) {
  414.         rpmError(RPMERR_BADSPEC, "File listed twice: %s", fileList[c]);
  415.         processFileListFailed = 1;
  416.         }
  417.         
  418.         fileUnameList[c] = fest->uname;
  419.         fileGnameList[c] = fest->gname;
  420.         *size += fest->statbuf.st_size;
  421.         if (S_ISREG(fest->statbuf.st_mode)) {
  422.         if ((type == RPMLEAD_BINARY) &&
  423.             rpmGetVar(RPMVAR_ROOT)) {
  424.             sprintf(buf, "%s%s", rpmGetVar(RPMVAR_ROOT), fest->file);
  425.         } else {
  426.             strcpy(buf, fest->file);
  427.         }
  428.         mdfile(buf, buf);
  429.         fileMD5List[c] = strdup(buf);
  430.         rpmMessage(RPMMESS_DEBUG, "md5(%s) = %s\n", fest->file, buf);
  431.         } else {
  432.         /* This is stupid */
  433.         fileMD5List[c] = strdup("");
  434.         }
  435.         fileSizeList[c] = fest->statbuf.st_size;
  436.         fileUIDList[c] = fest->statbuf.st_uid;
  437.         fileGIDList[c] = fest->statbuf.st_gid;
  438.         fileMtimesList[c] = fest->statbuf.st_mtime;
  439.  
  440.         /* Do timecheck */
  441.         if (tc && (type == RPMLEAD_BINARY)) {
  442.         if (currentTime - fest->statbuf.st_mtime > tc) {
  443.             rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n",
  444.                 fest->file);
  445.         }
  446.         }
  447.     
  448.         fileFlagsList[c] = 0;
  449.         if (isDoc(fest->file))
  450.             fileFlagsList[c] |= RPMFILE_DOC;
  451.         if (fest->isdoc) 
  452.         fileFlagsList[c] |= RPMFILE_DOC;
  453.         if (fest->conf && !(fest->statbuf.st_mode & S_IFDIR))
  454.         fileFlagsList[c] |= fest->conf;
  455.         if (fest->isspecfile)
  456.         fileFlagsList[c] |= RPMFILE_SPECFILE;
  457.  
  458.         fileModesList[c] = fest->statbuf.st_mode;
  459.         fileRDevsList[c] = fest->statbuf.st_rdev;
  460.         fileVerifyFlagsList[c] = fest->verify_flags;
  461.  
  462.         if (S_ISLNK(fest->statbuf.st_mode)) {
  463.         if (rpmGetVar(RPMVAR_ROOT)) {
  464.             sprintf(buf, "%s%s", rpmGetVar(RPMVAR_ROOT), fest->file);
  465.         } else {
  466.             strcpy(buf, fest->file);
  467.         }
  468.             buf[readlink(buf, buf, 1024)] = '\0';
  469.         fileLinktoList[c] = strdup(buf);
  470.         } else {
  471.         /* This is stupid */
  472.         fileLinktoList[c] = strdup("");
  473.         }
  474.         c++;
  475.     }
  476.  
  477.     /* Add the header entries */
  478.     c = count;
  479.     headerAddEntry(header, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, fileList, c);
  480.     headerAddEntry(header, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE,
  481.          fileLinktoList, c);
  482.     headerAddEntry(header, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE, fileMD5List, c);
  483.     headerAddEntry(header, RPMTAG_FILESIZES, RPM_INT32_TYPE, fileSizeList, c);
  484.     headerAddEntry(header, RPMTAG_FILEUIDS, RPM_INT32_TYPE, fileUIDList, c);
  485.     headerAddEntry(header, RPMTAG_FILEGIDS, RPM_INT32_TYPE, fileGIDList, c);
  486.     headerAddEntry(header, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE,
  487.          fileUnameList, c);
  488.     headerAddEntry(header, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE,
  489.          fileGnameList, c);
  490.     headerAddEntry(header, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, fileMtimesList, c);
  491.     headerAddEntry(header, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, fileFlagsList, c);
  492.     headerAddEntry(header, RPMTAG_FILEMODES, RPM_INT16_TYPE, fileModesList, c);
  493.     headerAddEntry(header, RPMTAG_FILERDEVS, RPM_INT16_TYPE, fileRDevsList, c);
  494.     headerAddEntry(header, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE,
  495.          fileVerifyFlagsList, c);
  496.     
  497.     /* Free the allocated strings */
  498.     c = count;
  499.     while (c--) {
  500.         free(fileMD5List[c]);
  501.         free(fileLinktoList[c]);
  502.     }
  503.  
  504.     /* Free all those lists */
  505.     free(fileList);
  506.     free(fileLinktoList);
  507.     free(fileMD5List);
  508.     free(fileSizeList);
  509.     free(fileUIDList);
  510.     free(fileGIDList);
  511.     free(fileUnameList);
  512.     free(fileGnameList);
  513.     free(fileMtimesList);
  514.     free(fileFlagsList);
  515.     free(fileModesList);
  516.     free(fileRDevsList);
  517.     free(fileVerifyFlagsList);
  518.     
  519.     /* Free the file entry array */
  520.     free(file_entry_array);
  521.     
  522.     /* Free the file entry stack */
  523.     fest = fes;
  524.     while (fest) {
  525.         fes = fest->next;
  526.         free(fest);
  527.         fest = fes;
  528.     }
  529.     }
  530.     
  531.     freeSplitString(files);
  532.     return processFileListFailed;
  533. }
  534.  
  535. /*************************************************************/
  536. /*                                                           */
  537. /* misc                                                      */
  538. /*                                                           */
  539. /*************************************************************/
  540.  
  541. static int compare_fe(const void *ap, const void *bp)
  542. {
  543.     char *a, *b;
  544.  
  545.     a = (*(struct file_entry **)ap)->file;
  546.     b = (*(struct file_entry **)bp)->file;
  547.  
  548.     return strcmp(a, b);
  549. }
  550.  
  551. /*************************************************************/
  552. /*                                                           */
  553. /* Doc dir stuff                                             */
  554. /*                                                           */
  555. /*************************************************************/
  556.  
  557. /* XXX hard coded limit -- only 1024 %docdir allowed */
  558. static char *docdirs[1024];
  559. static int docdir_count;
  560.  
  561. static void resetDocdir(void)
  562. {
  563.     while (docdir_count--) {
  564.         free(docdirs[docdir_count]);
  565.     }
  566.     docdir_count = 0;
  567.     docdirs[docdir_count++] = strdup("/usr/doc");
  568.     docdirs[docdir_count++] = strdup("/usr/man");
  569.     docdirs[docdir_count++] = strdup("/usr/info");
  570.     docdirs[docdir_count++] = strdup("/usr/X11R6/man");
  571. }
  572.  
  573. static void addDocdir(char *dirname)
  574. {
  575.     if (docdir_count == 1024) {
  576.     fprintf(stderr, "RPMERR_INTERNAL: Hit limit in addDocdir()\n");
  577.     exit(RPMERR_INTERNAL);
  578.     }
  579.     docdirs[docdir_count++] = strdup(dirname);
  580. }
  581.  
  582. static int isDoc(char *filename)
  583. {
  584.     int x = 0;
  585.  
  586.     while (x < docdir_count) {
  587.         if (strstr(filename, docdirs[x]) == filename) {
  588.         return 1;
  589.         }
  590.     x++;
  591.     }
  592.     return 0;
  593. }
  594.  
  595. /*************************************************************/
  596. /*                                                           */
  597. /* File stating / tree walk                                  */
  598. /*                                                           */
  599. /*************************************************************/
  600.  
  601. /* Need three globals to keep track of things in ftw() */
  602. static int Gisdoc;
  603. static int Gconf;
  604. static int Gverify_flags;
  605. static int Gcount;
  606. static char *GPmode;
  607. static char *GUname;
  608. static char *GGname;
  609. static struct file_entry **Gfestack;
  610. static char *Gprefix;
  611.  
  612. static int add_file(struct file_entry **festack, const char *name,
  613.             int isdoc, int conf, int isdir, int verify_flags,
  614.             char *Pmode, char *Uname, char *Gname, char *prefix)
  615. {
  616.     struct file_entry *p;
  617.     char *copyTo, copied;
  618.     const char *prefixTest, *prefixPtr;
  619.     const char *copyFrom;
  620.     char fullname[1024];
  621.     int mode;
  622.  
  623.     /* Set these up for ftw() */
  624.     Gfestack = festack;
  625.     Gisdoc = isdoc;
  626.     Gconf = conf;
  627.     Gverify_flags = verify_flags;
  628.     GPmode = Pmode;
  629.     GUname = Uname;
  630.     GGname = Gname;
  631.     Gprefix = prefix;
  632.  
  633.     p = malloc(sizeof(struct file_entry));
  634.  
  635.     copyTo = p->file;
  636.     copied = '\0';
  637.     copyFrom = name;
  638.     while (*copyFrom) {
  639.     if (*copyFrom != '/' || copied != '/') {
  640.         *copyTo++ = copied = *copyFrom;
  641.     }
  642.     copyFrom++;
  643.     }
  644.     *copyTo = '\0';
  645.  
  646.     p->isdoc = isdoc;
  647.     p->conf = conf;
  648.     p->isspecfile = 0;  /* source packages are done by hand */
  649.     p->verify_flags = verify_flags;
  650.     if (rpmGetVar(RPMVAR_ROOT)) {
  651.     sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), name);
  652.     } else {
  653.     strcpy(fullname, name);
  654.     }
  655.  
  656.     /* If we are using a prefix, validate the file */
  657.     if (prefix) {
  658.     prefixTest = name;
  659.     prefixPtr = prefix;
  660.     while (*prefixTest == '/') {
  661.         prefixTest++;  /* Skip leading "/" */
  662.     }
  663.     while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) {
  664.         prefixPtr++;
  665.         prefixTest++;
  666.     }
  667.     if (*prefixPtr) {
  668.         rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s",
  669.           prefix, name);
  670.         return 0;
  671.     }
  672.     }
  673.  
  674.     /* OK, finally stat() the file */
  675.     if (lstat(fullname, &p->statbuf)) {
  676.     return 0;
  677.     }
  678.  
  679.     /*
  680.      * If %attr() was specified, then use those values instead of
  681.      * what lstat() returned.
  682.      */
  683.     if (Pmode && strcmp(Pmode, "-")) {
  684.      sscanf(Pmode, "%o", &mode);
  685.      mode |= p->statbuf.st_mode & S_IFMT;
  686.      p->statbuf.st_mode = (unsigned short)mode;
  687.     }
  688.  
  689.     if (Uname && strcmp(Uname, "-")) {
  690.      p->uname = getUnameS(Uname);
  691.     } else {
  692.      p->uname = getUname(p->statbuf.st_uid);
  693.     }
  694.     
  695.     if (Gname && strcmp(Gname, "-")) {
  696.      p->gname = getGnameS(Gname);
  697.     } else {
  698.      p->gname = getGname(p->statbuf.st_gid);
  699.     }
  700.     
  701.     if (! (p->uname && p->gname)) {
  702.     rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", fullname);
  703.     p->uname = "";
  704.     p->gname = "";
  705.     return 0;
  706.     }
  707.     
  708.     if ((! isdir) && S_ISDIR(p->statbuf.st_mode)) {
  709.     /* This means we need to descend with ftw() */
  710.     Gcount = 0;
  711.     
  712.     /* We use our own ftw() call, because ftw() uses stat()    */
  713.     /* instead of lstat(), which causes it to follow symlinks! */
  714.     myftw(fullname, add_file_aux, 16);
  715.     
  716.     free(p);
  717.  
  718.     return Gcount;
  719.     } else {
  720.     /* Link it in */
  721.     p->next = *festack;
  722.     *festack = p;
  723.  
  724.     rpmMessage(RPMMESS_DEBUG, "ADDING: %s\n", name);
  725.  
  726.     /* return number of entries added */
  727.     return 1;
  728.     }
  729. }
  730.  
  731. static int add_file_aux(const char *file, struct stat *sb, int flag)
  732. {
  733.     const char *name = file;
  734.  
  735.     if (rpmGetVar(RPMVAR_ROOT)) {
  736.     name += strlen(rpmGetVar(RPMVAR_ROOT));
  737.     }
  738.  
  739.     /* The 1 will cause add_file() to *not* descend */
  740.     /* directories -- ftw() is already doing it!    */
  741.     Gcount += add_file(Gfestack, name, Gisdoc, Gconf, 1, Gverify_flags,
  742.             GPmode, GUname, GGname, Gprefix);
  743.  
  744.     return 0; /* for ftw() */
  745. }
  746.  
  747. /*************************************************************/
  748. /*                                                           */
  749. /* globbing                                                  */
  750. /*                                                           */
  751. /*************************************************************/
  752.  
  753. /* glob_pattern_p() taken from bash
  754.  * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
  755.  */
  756.  
  757. /* Return nonzero if PATTERN has any special globbing chars in it.  */
  758. static int glob_pattern_p (char *pattern)
  759. {
  760.     register char *p = pattern;
  761.     register char c;
  762.     int open = 0;
  763.   
  764.     while ((c = *p++) != '\0')
  765.     switch (c) {
  766.     case '?':
  767.     case '*':
  768.         return (1);
  769.     case '[':      /* Only accept an open brace if there is a close */
  770.         open++;    /* brace to match it.  Bracket expressions must be */
  771.         continue;  /* complete, according to Posix.2 */
  772.     case ']':
  773.         if (open)
  774.         return (1);
  775.         continue;      
  776.     case '\\':
  777.         if (*p++ == '\0')
  778.         return (0);
  779.     }
  780.  
  781.     return (0);
  782. }
  783.  
  784. static int glob_error(const char *foo, int bar)
  785. {
  786.     return 1;
  787. }
  788.  
  789. /*************************************************************/
  790. /*                                                           */
  791. /* %attr parsing                                             */
  792. /*                                                           */
  793. /*************************************************************/
  794.  
  795. static int parseForAttr(char *buf, char **currPmode,
  796.             char **currUname, char **currGname)
  797. {
  798.     char *p, *start, *end;
  799.     char ourbuf[1024];
  800.     int mode, x;
  801.  
  802.     if (!(p = start = strstr(buf, "%attr"))) {
  803.     return 0;
  804.     }
  805.  
  806.     *currPmode = *currUname = *currGname = NULL;
  807.  
  808.     p += 5;
  809.     while (*p && (*p == ' ' || *p == '\t')) {
  810.     p++;
  811.     }
  812.  
  813.     if (*p != '(') {
  814.     rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
  815.     return RPMERR_BADSPEC;
  816.     }
  817.     p++;
  818.  
  819.     end = p;
  820.     while (*end && *end != ')') {
  821.     end++;
  822.     }
  823.  
  824.     if (! *end) {
  825.     rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
  826.     return RPMERR_BADSPEC;
  827.     }
  828.  
  829.     strncpy(ourbuf, p, end-p);
  830.     ourbuf[end-p] = '\0';
  831.  
  832.     *currPmode = strtok(ourbuf, ", \n\t");
  833.     *currUname = strtok(NULL, ", \n\t");
  834.     *currGname = strtok(NULL, ", \n\t");
  835.  
  836.     if (! (*currPmode && *currUname && *currGname)) {
  837.     rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
  838.     *currPmode = *currUname = *currGname = NULL;
  839.     return RPMERR_BADSPEC;
  840.     }
  841.  
  842.     /* Do a quick test on the mode argument */
  843.     if (strcmp(*currPmode, "-")) {
  844.     x = sscanf(*currPmode, "%o", &mode);
  845.     if ((x == 0) || (mode >> 12)) {
  846.         rpmError(RPMERR_BADSPEC, "Bad %%attr() mode spec: %s", buf);
  847.         *currPmode = *currUname = *currGname = NULL;
  848.         return RPMERR_BADSPEC;
  849.     }
  850.     }
  851.     
  852.     *currPmode = strdup(*currPmode);
  853.     *currUname = strdup(*currUname);
  854.     *currGname = strdup(*currGname);
  855.     
  856.     /* Set everything we just parsed to blank spaces */
  857.     while (start <= end) {
  858.     *start++ = ' ';
  859.     }
  860.  
  861.     return 0;
  862. }
  863.  
  864. /*************************************************************/
  865. /*                                                           */
  866. /* %verify parsing                                           */
  867. /*                                                           */
  868. /*************************************************************/
  869.  
  870. static int parseForVerify(char *buf, int *verify_flags)
  871. {
  872.     char *p, *start, *end;
  873.     char ourbuf[1024];
  874.     int not;
  875.  
  876.     if (!(p = start = strstr(buf, "%verify"))) {
  877.     return 0;
  878.     }
  879.  
  880.     p += 7;
  881.     while (*p && (*p == ' ' || *p == '\t')) {
  882.     p++;
  883.     }
  884.  
  885.     if (*p != '(') {
  886.     rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf);
  887.     return RPMERR_BADSPEC;
  888.     }
  889.     p++;
  890.  
  891.     end = p;
  892.     while (*end && *end != ')') {
  893.     end++;
  894.     }
  895.  
  896.     if (! *end) {
  897.     rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf);
  898.     return RPMERR_BADSPEC;
  899.     }
  900.  
  901.     strncpy(ourbuf, p, end-p);
  902.     ourbuf[end-p] = '\0';
  903.     while (start <= end) {
  904.     *start++ = ' ';
  905.     }
  906.  
  907.     p = strtok(ourbuf, ", \n\t");
  908.     not = 0;
  909.     *verify_flags = RPMVERIFY_NONE;
  910.     while (p) {
  911.     if (!strcmp(p, "not")) {
  912.         not = 1;
  913.     } else if (!strcmp(p, "md5")) {
  914.         *verify_flags |= RPMVERIFY_MD5;
  915.     } else if (!strcmp(p, "size")) {
  916.         *verify_flags |= RPMVERIFY_FILESIZE;
  917.     } else if (!strcmp(p, "link")) {
  918.         *verify_flags |= RPMVERIFY_LINKTO;
  919.     } else if (!strcmp(p, "user")) {
  920.         *verify_flags |= RPMVERIFY_USER;
  921.     } else if (!strcmp(p, "group")) {
  922.         *verify_flags |= RPMVERIFY_GROUP;
  923.     } else if (!strcmp(p, "mtime")) {
  924.         *verify_flags |= RPMVERIFY_MTIME;
  925.     } else if (!strcmp(p, "mode")) {
  926.         *verify_flags |= RPMVERIFY_MODE;
  927.     } else if (!strcmp(p, "rdev")) {
  928.         *verify_flags |= RPMVERIFY_RDEV;
  929.     } else {
  930.         rpmError(RPMERR_BADSPEC, "Invalid %%verify token: %s", p);
  931.         return RPMERR_BADSPEC;
  932.     }
  933.     p = strtok(NULL, ", \n\t");
  934.     }
  935.  
  936.     if (not) {
  937.     *verify_flags = ~(*verify_flags);
  938.     }
  939.  
  940.     return 0;
  941. }
  942.  
  943. static int parseForConfig(char *buf, int *conf)
  944. {
  945.     char *p, *start, *end;
  946.     char ourbuf[1024];
  947.  
  948.     if (!(p = start = strstr(buf, "%config"))) {
  949.     return 0;
  950.     }
  951.     *conf = RPMFILE_CONFIG;
  952.  
  953.     p += 7;
  954.     while (*p && (*p == ' ' || *p == '\t')) {
  955.     p++;
  956.     }
  957.  
  958.     if (*p != '(') {
  959.     while (start < p) {
  960.         *start++ = ' ';
  961.     }
  962.     return 0;
  963.     }
  964.     p++;
  965.  
  966.     end = p;
  967.     while (*end && *end != ')') {
  968.     end++;
  969.     }
  970.  
  971.     if (! *end) {
  972.     rpmError(RPMERR_BADSPEC, "Bad %%config() syntax: %s", buf);
  973.     return RPMERR_BADSPEC;
  974.     }
  975.  
  976.     strncpy(ourbuf, p, end-p);
  977.     ourbuf[end-p] = '\0';
  978.     while (start <= end) {
  979.     *start++ = ' ';
  980.     }
  981.  
  982.     p = strtok(ourbuf, ", \n\t");
  983.     while (p) {
  984.     if (!strcmp(p, "missingok")) {
  985.         *conf |= RPMFILE_MISSINGOK;
  986.     } else if (!strcmp(p, "noreplace")) {
  987.         *conf |= RPMFILE_NOREPLACE;
  988.     } else {
  989.         rpmError(RPMERR_BADSPEC, "Invalid %%config token: %s", p);
  990.         return RPMERR_BADSPEC;
  991.     }
  992.     p = strtok(NULL, ", \n\t");
  993.     }
  994.  
  995.     return 0;
  996. }
  997.