Initial revision
authorroot <devnull@localhost>
Fri, 7 Jun 1996 18:32:10 +0000 (18:32 +0000)
committerroot <devnull@localhost>
Fri, 7 Jun 1996 18:32:10 +0000 (18:32 +0000)
CVS patchset: 620
CVS date: 1996/06/07 18:32:10

build/files.c [new file with mode: 0644]
build/files.h [new file with mode: 0644]
build/names.c [new file with mode: 0644]
build/names.h [new file with mode: 0644]
build/reqprov.c [new file with mode: 0644]
build/reqprov.h [new file with mode: 0644]

diff --git a/build/files.c b/build/files.c
new file mode 100644 (file)
index 0000000..79ff8be
--- /dev/null
@@ -0,0 +1,754 @@
+/* RPM - Copyright (C) 1995 Red Hat Software
+ * 
+ * prepack.c - routines for packaging
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ftw.h>
+#include <glob.h>
+
+#include "spec.h"
+#include "specP.h"
+#include "stringbuf.h"
+#include "build.h"
+#include "messages.h"
+#include "md5.h"
+#include "myftw.h"
+#include "header.h"
+#include "files.h"
+#include "names.h"
+#include "rpmerr.h"
+#include "rpmlead.h"
+#include "rpmlib.h"
+#include "misc.h"
+
+#define BINARY_HEADER 0
+#define SOURCE_HEADER 1
+
+struct file_entry {
+    char file[1024];
+    int isdoc;
+    int isconf;
+    int verify_flags;
+    char *uname;  /* reference -- do not free */
+    char *gname;  /* reference -- do not free */
+    struct stat statbuf;
+    struct file_entry *next;
+};
+
+static int add_file(struct file_entry **festack, const char *name,
+                   int isdoc, int isconf, int isdir, int verify_flags,
+                   char *Pmode, char *Uname, char *Gname);
+static int compare_fe(const void *ap, const void *bp);
+static int add_file_aux(const char *file, struct stat *sb, int flag);
+static int glob_error(const char *foo, int bar);
+static int glob_pattern_p (char *pattern);
+static int parseForVerify(char *buf, int *verify_flags);
+static int parseForAttr(char *origbuf, char **currPmode,
+                       char **currUname, char **currGname);
+
+static void resetDocdir(void);
+static void addDocdir(char *dirname);
+static int isDoc(char *filename);
+
+int process_filelist(Header header, struct PackageRec *pr,
+                    StringBuf sb, int *size, char *name,
+                    char *version, char *release, int type)
+{
+    char buf[1024];
+    char **files, **fp;
+    struct file_entry *fes, *fest;
+    struct file_entry **file_entry_array;
+    int isdoc, isconf, isdir, verify_flags;
+    char *currPmode=NULL;      /* hold info from %attr() */
+    char *currUname=NULL;      /* hold info from %attr() */
+    char *currGname=NULL;      /* hold info from %attr() */
+    char *filename, *s;
+    char *str;
+    int count = 0;
+    int c, x;
+    glob_t glob_result;
+    int special_doc;
+    int passed_special_doc = 0;
+    FILE *file;
+
+    fes = NULL;
+    *size = 0;
+
+    resetDocdir();
+
+    if (type == RPMLEAD_BINARY && pr->fileFile) {
+       sprintf(buf, "%s/%s/%s", getVar(RPMVAR_BUILDDIR),
+               build_subdir, pr->fileFile);
+       message(MESS_DEBUG, "Reading file names from: %sXX\n", buf);
+       if ((file = fopen(buf, "r")) == NULL) {
+           perror("open fileFile");
+           exit(1);
+       }
+       while (fgets(buf, sizeof(buf), file)) {
+           appendStringBuf(sb, buf);
+       }
+       fclose(file);
+    }
+    
+    str = getStringBuf(sb);
+    files = splitString(str, strlen(str), '\n');
+    fp = files;
+
+    while (*fp) {
+       strcpy(buf, *fp);  /* temp copy */
+       isdoc = 0;
+       special_doc = 0;
+       isconf = 0;
+       isdir = 0;
+       if (currPmode) {
+           free (currPmode);
+           currPmode = NULL;
+       }
+       if (currUname) {
+           free (currUname);
+           currUname = NULL;
+       }
+       if (currGname) {
+           free (currGname);
+           currGname = NULL;
+       }
+       verify_flags = VERIFY_ALL;
+       filename = NULL;
+
+       /* First preparse buf for %verify() */
+       if (!parseForVerify(buf, &verify_flags)) {
+           return(RPMERR_BADSPEC);
+       }
+       
+       /* Next parse for for %attr() */
+       if (!parseForAttr(buf, &currPmode, &currUname, &currGname)) {
+           return(RPMERR_BADSPEC);
+       }
+
+       s = strtok(buf, " \t\n");
+       while (s) {
+           if (!strcmp(s, "%docdir")) {
+               s = strtok(NULL, " \t\n");
+               addDocdir(s);
+               break;
+           } else if (!strcmp(s, "%doc")) {
+               isdoc = 1;
+           } else if (!strcmp(s, "%config")) {
+               isconf = 1;
+           } else if (!strcmp(s, "%dir")) {
+               isdir = 1;
+           } else {
+               if (isdoc && (*s != '/')) {
+                   /* This is a special %doc macro */
+                   special_doc = 1;
+               } else {
+                   filename = s;
+               }
+           }
+           s = strtok(NULL, " \t\n");
+       }
+       if (special_doc) {
+           if (passed_special_doc) {
+               fp++;
+               continue;
+           } else {
+               if (filename || isconf || isdir) {
+                   error(RPMERR_BADSPEC,
+                         "Can't mix special %%doc with other forms: %s", fp);
+                   return(RPMERR_BADSPEC);
+               }
+               sprintf(buf, "%s/%s-%s-%s", getVar(RPMVAR_DOCDIR),
+                       name, version, release);
+               filename = buf;
+               passed_special_doc = 1;
+           }
+       }
+       if (! filename) {
+           fp++;
+           continue;
+       }
+
+       if (type == RPMLEAD_BINARY) {
+           /* check that file starts with leading "/" */
+           if (*filename != '/') {
+               error(RPMERR_BADSPEC,
+                     "File needs leading \"/\": %s", filename);
+               return(RPMERR_BADSPEC);
+           }
+
+           if (glob_pattern_p(filename)) {
+               char fullname[1024];
+
+               if (getVar(RPMVAR_ROOT)) {
+                   sprintf(fullname, "%s%s", getVar(RPMVAR_ROOT), filename);
+               } else {
+                   strcpy(fullname, filename);
+               }
+
+               if (glob(fullname, 0, glob_error, &glob_result)) {
+                   error(RPMERR_BADSPEC, "No matches: %s", fullname);
+                   return(RPMERR_BADSPEC);
+               }
+               if (glob_result.gl_pathc < 1) {
+                   error(RPMERR_BADSPEC, "No matches: %s", fullname);
+                   return(RPMERR_BADSPEC);
+               }
+               x = 0;
+               c = 0;
+               while (x < glob_result.gl_pathc) {
+                   int offset = strlen(getVar(RPMVAR_ROOT) ? : "");
+                   c += add_file(&fes, &(glob_result.gl_pathv[x][offset]),
+                                 isdoc, isconf, isdir, verify_flags,
+                                 currPmode, currUname, currGname);
+                   x++;
+               }
+               globfree(&glob_result);
+           } else {
+               c = add_file(&fes, filename, isdoc, isconf, isdir,
+                            verify_flags, currPmode, currUname, currGname);
+           }
+       } else {
+           /* Source package are the simple case */
+           fest = malloc(sizeof(struct file_entry));
+           fest->isdoc = 0;
+           fest->isconf = 0;
+           fest->verify_flags = 0;  /* XXX - something else? */
+           stat(filename, &fest->statbuf);
+           fest->uname = getUname(fest->statbuf.st_uid);
+           fest->gname = getGname(fest->statbuf.st_gid);
+           strcpy(fest->file, filename);
+           fest->next = fes;
+           fes = fest;
+           c = 1;
+       }
+           
+       if (! c) {
+           error(RPMERR_BADSPEC, "File not found: %s", filename);
+           return(RPMERR_BADSPEC);
+       }
+       count += c;
+       
+       fp++;
+    }
+
+    /* If there are no files, don't add anything to the header */
+    if (count) {
+       char ** fileList;
+       char ** fileMD5List;
+       char ** fileLinktoList;
+       int_32 * fileSizeList;
+       int_32 * fileUIDList;
+       int_32 * fileGIDList;
+       char ** fileUnameList;
+       char ** fileGnameList;
+       int_32 * fileMtimesList;
+       int_32 * fileFlagsList;
+       int_16 * fileModesList;
+       int_16 * fileRDevsList;
+       int_32 * fileVerifyFlagsList;
+
+       fileList = malloc(sizeof(char *) * count);
+       fileLinktoList = malloc(sizeof(char *) * count);
+       fileMD5List = malloc(sizeof(char *) * count);
+       fileSizeList = malloc(sizeof(int_32) * count);
+       fileUIDList = malloc(sizeof(int_32) * count);
+       fileGIDList = malloc(sizeof(int_32) * count);
+       fileUnameList = malloc(sizeof(char *) * count);
+       fileGnameList = malloc(sizeof(char *) * count);
+       fileMtimesList = malloc(sizeof(int_32) * count);
+       fileFlagsList = malloc(sizeof(int_32) * count);
+       fileModesList = malloc(sizeof(int_16) * count);
+       fileRDevsList = malloc(sizeof(int_16) * count);
+       fileVerifyFlagsList = malloc(sizeof(int_32) * count);
+
+       /* Build a reverse sorted file array.  */
+       /* This makes uninstalls a lot easier. */
+       file_entry_array = malloc(sizeof(struct file_entry *) * count);
+       c = 0;
+       fest = fes;
+       while (fest) {
+           file_entry_array[c++] = fest;
+           fest = fest->next;
+       }
+       qsort(file_entry_array, count, sizeof(struct file_entry *),
+             compare_fe);
+       
+       c = 0;
+       while (c < count) {
+           fest = file_entry_array[c];
+           if (type == RPMLEAD_BINARY) {
+               fileList[c] = fest->file;
+           } else {
+               fileList[c] = strrchr(fest->file, '/') + 1;
+           }
+           fileUnameList[c] = fest->uname;
+           fileGnameList[c] = fest->gname;
+           *size += fest->statbuf.st_size;
+           if (S_ISREG(fest->statbuf.st_mode)) {
+               if (getVar(RPMVAR_ROOT)) {
+                   sprintf(buf, "%s%s", getVar(RPMVAR_ROOT), fest->file);
+               } else {
+                   strcpy(buf, fest->file);
+               }
+               mdfile(buf, buf);
+               fileMD5List[c] = strdup(buf);
+               message(MESS_DEBUG, "md5(%s) = %s\n", fest->file, buf);
+           } else {
+               /* This is stupid */
+               fileMD5List[c] = strdup("");
+           }
+           fileSizeList[c] = fest->statbuf.st_size;
+           fileUIDList[c] = fest->statbuf.st_uid;
+           fileGIDList[c] = fest->statbuf.st_gid;
+           fileMtimesList[c] = fest->statbuf.st_mtime;
+           fileFlagsList[c] = 0;
+           if (isDoc(fest->file))
+               fileFlagsList[c] |= RPMFILE_DOC;
+           if (fest->isdoc) 
+               fileFlagsList[c] |= RPMFILE_DOC;
+           if (fest->isconf)
+               fileFlagsList[c] |= RPMFILE_CONFIG;
+
+           fileModesList[c] = fest->statbuf.st_mode;
+           fileRDevsList[c] = fest->statbuf.st_rdev;
+           fileVerifyFlagsList[c] = fest->verify_flags;
+
+           if (S_ISLNK(fest->statbuf.st_mode)) {
+               if (getVar(RPMVAR_ROOT)) {
+                   sprintf(buf, "%s%s", getVar(RPMVAR_ROOT), fest->file);
+               } else {
+                   strcpy(buf, fest->file);
+               }
+               buf[readlink(buf, buf, 1024)] = '\0';
+               fileLinktoList[c] = strdup(buf);
+           } else {
+               /* This is stupid */
+               fileLinktoList[c] = strdup("");
+           }
+           c++;
+       }
+
+       /* Add the header entries */
+       c = count;
+       addEntry(header, RPMTAG_FILENAMES, STRING_ARRAY_TYPE, fileList, c);
+       addEntry(header, RPMTAG_FILELINKTOS, STRING_ARRAY_TYPE,
+                fileLinktoList, c);
+       addEntry(header, RPMTAG_FILEMD5S, STRING_ARRAY_TYPE, fileMD5List, c);
+       addEntry(header, RPMTAG_FILESIZES, INT32_TYPE, fileSizeList, c);
+       addEntry(header, RPMTAG_FILEUIDS, INT32_TYPE, fileUIDList, c);
+       addEntry(header, RPMTAG_FILEGIDS, INT32_TYPE, fileGIDList, c);
+       addEntry(header, RPMTAG_FILEUSERNAME, STRING_ARRAY_TYPE,
+                fileUnameList, c);
+       addEntry(header, RPMTAG_FILEGROUPNAME, STRING_ARRAY_TYPE,
+                fileGnameList, c);
+       addEntry(header, RPMTAG_FILEMTIMES, INT32_TYPE, fileMtimesList, c);
+       addEntry(header, RPMTAG_FILEFLAGS, INT32_TYPE, fileFlagsList, c);
+       addEntry(header, RPMTAG_FILEMODES, INT16_TYPE, fileModesList, c);
+       addEntry(header, RPMTAG_FILERDEVS, INT16_TYPE, fileRDevsList, c);
+       addEntry(header, RPMTAG_FILEVERIFYFLAGS, INT32_TYPE,
+                fileVerifyFlagsList, c);
+       
+       /* Free the allocated strings */
+       c = count;
+       while (c--) {
+           free(fileMD5List[c]);
+           free(fileLinktoList[c]);
+       }
+
+       /* Free all those lists */
+       free(fileList);
+       free(fileLinktoList);
+       free(fileMD5List);
+       free(fileSizeList);
+       free(fileUIDList);
+       free(fileGIDList);
+       free(fileUnameList);
+       free(fileGnameList);
+       free(fileMtimesList);
+       free(fileFlagsList);
+       free(fileModesList);
+       free(fileRDevsList);
+       free(fileVerifyFlagsList);
+       
+       /* Free the file entry array */
+       free(file_entry_array);
+       
+       /* Free the file entry stack */
+       fest = fes;
+       while (fest) {
+           fes = fest->next;
+           free(fest);
+           fest = fes;
+       }
+    }
+    
+    freeSplitString(files);
+    return 0;
+}
+
+/*************************************************************/
+/*                                                           */
+/* misc                                                      */
+/*                                                           */
+/*************************************************************/
+
+static int compare_fe(const void *ap, const void *bp)
+{
+    char *a, *b;
+
+    a = (*(struct file_entry **)ap)->file;
+    b = (*(struct file_entry **)bp)->file;
+
+    return strcmp(a, b);
+}
+
+/*************************************************************/
+/*                                                           */
+/* Doc dir stuff                                             */
+/*                                                           */
+/*************************************************************/
+
+/* XXX hard coded limit -- only 1024 %docdir allowed */
+static char *docdirs[1024];
+static int docdir_count;
+
+static void resetDocdir(void)
+{
+    while (docdir_count--) {
+        free(docdirs[docdir_count]);
+    }
+    docdir_count = 0;
+    docdirs[docdir_count++] = strdup("/usr/doc");
+    docdirs[docdir_count++] = strdup("/usr/man");
+    docdirs[docdir_count++] = strdup("/usr/info");
+}
+
+static void addDocdir(char *dirname)
+{
+    if (docdir_count == 1024) {
+       fprintf(stderr, "RPMERR_INTERNAL: Hit limit in addDocdir()\n");
+       exit(RPMERR_INTERNAL);
+    }
+    docdirs[docdir_count++] = strdup(dirname);
+}
+
+static int isDoc(char *filename)
+{
+    int x = 0;
+
+    while (x < docdir_count) {
+        if (strstr(filename, docdirs[x]) == filename) {
+           return 1;
+        }
+       x++;
+    }
+    return 0;
+}
+
+/*************************************************************/
+/*                                                           */
+/* File stating / tree walk                                  */
+/*                                                           */
+/*************************************************************/
+
+/* Need three globals to keep track of things in ftw() */
+static int Gisdoc;
+static int Gisconf;
+static int Gverify_flags;
+static int Gcount;
+static char *GPmode;
+static char *GUname;
+static char *GGname;
+static struct file_entry **Gfestack;
+
+static int add_file(struct file_entry **festack, const char *name,
+                   int isdoc, int isconf, int isdir, int verify_flags,
+                   char *Pmode, char *Uname, char *Gname)
+{
+    struct file_entry *p;
+    char fullname[1024];
+    int mode;
+
+    /* Set these up for ftw() */
+    Gfestack = festack;
+    Gisdoc = isdoc;
+    Gisconf = isconf;
+    Gverify_flags = verify_flags;
+    GPmode = Pmode;
+    GUname = Uname;
+    GGname = Gname;
+
+    p = malloc(sizeof(struct file_entry));
+    strcpy(p->file, name);
+    p->isdoc = isdoc;
+    p->isconf = isconf;
+    p->verify_flags = verify_flags;
+    if (getVar(RPMVAR_ROOT)) {
+       sprintf(fullname, "%s%s", getVar(RPMVAR_ROOT), name);
+    } else {
+       strcpy(fullname, name);
+    }
+    if (lstat(fullname, &p->statbuf)) {
+       return 0;
+    }
+
+    /*
+     * If %attr() was specified, then use those values instead of
+     * what lstat() returned.
+     */
+    if (Pmode && strcmp(Pmode, "-")) {
+       sscanf(Pmode, "%o", &mode);
+       mode |= p->statbuf.st_mode & S_IFMT;
+       p->statbuf.st_mode = (unsigned short)mode;
+    }
+    
+    if (Uname && strcmp(Uname, "-")) {
+       p->uname = getUnameS(Uname);
+    } else {
+       p->uname = getUname(p->statbuf.st_uid);
+    }
+    
+    if (Gname && strcmp(Gname, "-")) {
+       p->gname = getGnameS(Gname);
+    } else {
+       p->gname = getGname(p->statbuf.st_gid);
+    }
+    
+    if ((! isdir) && S_ISDIR(p->statbuf.st_mode)) {
+       /* This means we need to descend with ftw() */
+       Gcount = 0;
+       
+       /* We use our own ftw() call, because ftw() uses stat()    */
+       /* instead of lstat(), which causes it to follow symlinks! */
+       myftw(fullname, add_file_aux, 16);
+       
+       free(p);
+
+       return Gcount;
+    } else {
+       /* Link it in */
+       p->next = *festack;
+       *festack = p;
+
+       message(MESS_DEBUG, "ADDING: %s\n", name);
+
+       /* return number of entries added */
+       return 1;
+    }
+}
+
+static int add_file_aux(const char *file, struct stat *sb, int flag)
+{
+    const char *name = file;
+
+    if (getVar(RPMVAR_ROOT)) {
+       name += strlen(getVar(RPMVAR_ROOT));
+    }
+
+    /* The 1 will cause add_file() to *not* descend */
+    /* directories -- ftw() is already doing it!    */
+    Gcount += add_file(Gfestack, name, Gisdoc, Gisconf, 1, Gverify_flags,
+                       GPmode, GUname, GGname);
+
+    return 0; /* for ftw() */
+}
+
+/*************************************************************/
+/*                                                           */
+/* globbing                                                  */
+/*                                                           */
+/*************************************************************/
+
+/* glob_pattern_p() taken from bash
+ * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
+ */
+
+/* Return nonzero if PATTERN has any special globbing chars in it.  */
+static int glob_pattern_p (char *pattern)
+{
+    register char *p = pattern;
+    register char c;
+    int open = 0;
+  
+    while ((c = *p++) != '\0')
+       switch (c) {
+       case '?':
+       case '*':
+           return (1);
+       case '[':      /* Only accept an open brace if there is a close */
+           open++;    /* brace to match it.  Bracket expressions must be */
+           continue;  /* complete, according to Posix.2 */
+       case ']':
+           if (open)
+               return (1);
+           continue;      
+       case '\\':
+           if (*p++ == '\0')
+               return (0);
+       }
+
+    return (0);
+}
+
+static int glob_error(const char *foo, int bar)
+{
+    return 1;
+}
+
+/*************************************************************/
+/*                                                           */
+/* %attr parsing                                             */
+/*                                                           */
+/*************************************************************/
+
+static int parseForAttr(char *buf, char **currPmode,
+                       char **currUname, char **currGname)
+{
+    char *p, *start, *end;
+    char ourbuf[1024];
+    int mode, x;
+
+    if (!(p = start = strstr(buf, "%attr"))) {
+       return 1;
+    }
+
+    *currPmode = *currUname = *currGname = NULL;
+
+    p += 5;
+    while (*p && (*p == ' ' || *p == '\t')) {
+       p++;
+    }
+
+    if (*p != '(') {
+       error(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
+       return 0;
+    }
+    p++;
+
+    end = p;
+    while (*end && *end != ')') {
+       end++;
+    }
+
+    if (! *end) {
+       error(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
+       return 0;
+    }
+
+    strncpy(ourbuf, p, end-p);
+    ourbuf[end-p] = '\0';
+
+    *currPmode = strtok(ourbuf, ", \n\t");
+    *currUname = strtok(NULL, ", \n\t");
+    *currGname = strtok(NULL, ", \n\t");
+
+    if (! (*currPmode && *currUname && *currGname)) {
+       error(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf);
+       *currPmode = *currUname = *currGname = NULL;
+       return 0;
+    }
+
+    /* Do a quick test on the mode argument */
+    if (strcmp(*currPmode, "-")) {
+       x = sscanf(*currPmode, "%o", &mode);
+       if ((x == 0) || (mode >> 12)) {
+           error(RPMERR_BADSPEC, "Bad %%attr() mode spec: %s", buf);
+           *currPmode = *currUname = *currGname = NULL;
+           return 0;
+       }
+    }
+    
+    *currPmode = strdup(*currPmode);
+    *currUname = strdup(*currUname);
+    *currGname = strdup(*currGname);
+    
+    /* Set everything we just parsed to blank spaces */
+    while (start <= end) {
+       *start++ = ' ';
+    }
+
+    return 1;
+}
+
+/*************************************************************/
+/*                                                           */
+/* %verify parsing                                           */
+/*                                                           */
+/*************************************************************/
+
+static int parseForVerify(char *buf, int *verify_flags)
+{
+    char *p, *start, *end;
+    char ourbuf[1024];
+    int not;
+
+    if (!(p = start = strstr(buf, "%verify"))) {
+       return 1;
+    }
+
+    p += 7;
+    while (*p && (*p == ' ' || *p == '\t')) {
+       p++;
+    }
+
+    if (*p != '(') {
+       error(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf);
+       return 0;
+    }
+    p++;
+
+    end = p;
+    while (*end && *end != ')') {
+       end++;
+    }
+
+    if (! *end) {
+       error(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf);
+       return 0;
+    }
+
+    strncpy(ourbuf, p, end-p);
+    ourbuf[end-p] = '\0';
+    while (start <= end) {
+       *start++ = ' ';
+    }
+
+    p = strtok(ourbuf, ", \n\t");
+    not = 0;
+    *verify_flags = VERIFY_NONE;
+    while (p) {
+       if (!strcmp(p, "not")) {
+           not = 1;
+       } else if (!strcmp(p, "md5")) {
+           *verify_flags |= VERIFY_MD5;
+       } else if (!strcmp(p, "size")) {
+           *verify_flags |= VERIFY_FILESIZE;
+       } else if (!strcmp(p, "link")) {
+           *verify_flags |= VERIFY_LINKTO;
+       } else if (!strcmp(p, "user")) {
+           *verify_flags |= VERIFY_USER;
+       } else if (!strcmp(p, "group")) {
+           *verify_flags |= VERIFY_GROUP;
+       } else if (!strcmp(p, "mtime")) {
+           *verify_flags |= VERIFY_MTIME;
+       } else if (!strcmp(p, "mode")) {
+           *verify_flags |= VERIFY_MODE;
+       } else if (!strcmp(p, "rdev")) {
+           *verify_flags |= VERIFY_RDEV;
+       } else {
+           error(RPMERR_BADSPEC, "Invalid %%verify token: %s", p);
+           return 0;
+       }
+       p = strtok(NULL, ", \n\t");
+    }
+
+    if (not) {
+       *verify_flags = ~(*verify_flags);
+    }
+
+    return 1;
+}
diff --git a/build/files.h b/build/files.h
new file mode 100644 (file)
index 0000000..2ac335e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _FILES_H_
+#define _FILES_H_
+
+#include "spec.h"
+#include "specP.h"
+#include "stringbuf.h"
+
+int process_filelist(Header header, struct PackageRec *pr, StringBuf sb,
+                    int *size, char *name, char *version,
+                    char *release, int type);
+
+#endif _FILES_H_
diff --git a/build/names.c b/build/names.c
new file mode 100644 (file)
index 0000000..22564cd
--- /dev/null
@@ -0,0 +1,192 @@
+/* names.c -- user/group name/id chache (plus hostname and buildtime */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "names.h"
+#include "rpmlib.h"
+#include "rpmerr.h"
+
+static uid_t uids[1024];
+static char *unames[1024];
+static int uid_used = 0;
+
+static gid_t gids[1024];
+static char *gnames[1024];
+static int gid_used = 0;
+    
+static time_t buildtime;
+
+/*
+ * getUname() takes a uid, gets the username, and creates an entry in the
+ * table to hold a string containing the user name.
+ */
+char *getUname(uid_t uid)
+{
+    struct passwd *pw;
+    int x;
+
+    x = 0;
+    while (x < uid_used) {
+       if (uids[x] == uid) {
+           return unames[x];
+       }
+       x++;
+    }
+
+    /* XXX - This is the other hard coded limit */
+    if (x == 1024) {
+       fprintf(stderr, "RPMERR_INTERNAL: Hit limit in getUname()\n");
+       exit(RPMERR_INTERNAL);
+    }
+    
+    pw = getpwuid(uid);
+    uids[x] = uid;
+    uid_used++;
+    if (pw) {
+       unames[x] = strdup(pw->pw_name);
+    } else {
+       unames[x] = "";
+    }
+    return unames[x];
+}
+
+/*
+ * getUnameS() takes a username, gets the uid, and creates an entry in the
+ * table to hold a string containing the user name.
+ */
+char *getUnameS(char *uname)
+{
+    struct passwd *pw;
+    int x;
+
+    x = 0;
+    while (x < uid_used) {
+       if (!strcmp(unames[x],uname)) {
+           return unames[x];
+       }
+       x++;
+    }
+
+    /* XXX - This is the other hard coded limit */
+    if (x == 1024) {
+       fprintf(stderr, "RPMERR_INTERNAL: Hit limit in getUname()\n");
+       exit(RPMERR_INTERNAL);
+    }
+    
+    pw = getpwnam(uname);
+    uid_used++;
+    if (pw) {
+        uids[x] = pw->pw_uid;
+       unames[x] = strdup(pw->pw_name);
+    } else {
+        uids[x] = -1;
+       unames[x] = strdup(uname);
+    }
+    return unames[x];
+}
+
+/*
+ * getGname() takes a gid, gets the group name, and creates an entry in the
+ * table to hold a string containing the group name.
+ */
+char *getGname(gid_t gid)
+{
+    struct group *gr;
+    int x;
+
+    x = 0;
+    while (x < gid_used) {
+       if (gids[x] == gid) {
+           return gnames[x];
+       }
+       x++;
+    }
+
+    /* XXX - This is the other hard coded limit */
+    if (x == 1024) {
+       fprintf(stderr, "RPMERR_INTERNAL: Hit limit in getGname()\n");
+       exit(RPMERR_INTERNAL);
+    }
+    
+    gr = getgrgid(gid);
+    gids[x] = gid;
+    gid_used++;
+    if (gr) {
+       gnames[x] = strdup(gr->gr_name);
+    } else {
+       gnames[x] = "";
+    }
+    return gnames[x];
+}
+
+/*
+ * getGnameS() takes a group name, gets the gid, and creates an entry in the
+ * table to hold a string containing the group name.
+ */
+char *getGnameS(char *gname)
+{
+    struct group *gr;
+    int x;
+
+    x = 0;
+    while (x < gid_used) {
+       if (!strcmp(gnames[x], gname)) {
+           return gnames[x];
+       }
+       x++;
+    }
+
+    /* XXX - This is the other hard coded limit */
+    if (x == 1024) {
+       fprintf(stderr, "RPMERR_INTERNAL: Hit limit in getGname()\n");
+       exit(RPMERR_INTERNAL);
+    }
+    
+    gr = getgrnam(gname);
+    gid_used++;
+    if (gr) {
+       gids[x] = gr->gr_gid;
+       gnames[x] = strdup(gr->gr_name);
+    } else {
+       gids[x] = -1;
+       gnames[x] = strdup(gname);
+    }
+    return gnames[x];
+}
+
+void markBuildTime(void)
+{
+    buildtime = time(NULL);
+}
+
+time_t *getBuildTime(void)
+{
+    return &buildtime;
+}
+
+char *buildHost(void)
+{
+    static char hostname[1024];
+    static int gotit = 0;
+    struct hostent *hbn;
+
+    if (! gotit) {
+        gethostname(hostname, sizeof(hostname));
+       if ((hbn = gethostbyname(hostname))) {
+           strcpy(hostname, hbn->h_name);
+       } else {
+           message(MESS_WARNING, "Could not canonicalize hostname: %s\n",
+                   hostname);
+       }
+       gotit = 1;
+    }
+    return(hostname);
+}
diff --git a/build/names.h b/build/names.h
new file mode 100644 (file)
index 0000000..4e79744
--- /dev/null
@@ -0,0 +1,17 @@
+/* names.h -- user/group name/id cache plus hostname and buildtime */
+
+#ifndef _NAMES_H_
+#define _NAMES_H_
+
+#include <sys/types.h>
+
+char *getUname(uid_t uid);
+char *getUnameS(char *uname);
+char *getGname(gid_t gid);
+char *getGnameS(char *gname);
+
+char *buildHost(void);
+void markBuildTime(void);
+time_t *getBuildTime(void);
+
+#endif _NAMES_H_
diff --git a/build/reqprov.c b/build/reqprov.c
new file mode 100644 (file)
index 0000000..a154c73
--- /dev/null
@@ -0,0 +1,324 @@
+/* reqprov.c -- require/provide handling */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "specP.h"
+#include "reqprov.h"
+#include "messages.h"
+#include "rpmlib.h"
+#include "rpmerr.h"
+
+static void parseFileForProv(char *f, struct PackageRec *p);
+
+/*************************************************************/
+/*                                                           */
+/* Adding entries to the package reqprov list                */
+/* Handle duplicate entries                                  */
+/*                                                           */
+/*************************************************************/
+
+int addReqProv(struct PackageRec *p, int flags,
+              char *name, char *version)
+{
+    struct ReqProv *rd;
+    int same;
+
+    /* Frist see if the same entry is already there */
+    rd = p->reqprov;
+    while (rd) {
+       if (rd->flags == flags) {
+           if (rd->version == version) {
+               same = 1;
+           } else if (!rd->version || !version) {
+               same = 0;
+           } else if (!strcmp(rd->version, version)) {
+               same = 1;
+           } else {
+               same = 0;
+           }
+
+           if (same && !strcmp(rd->name, name)) {
+               /* They are exacty the same */
+               break;
+           }
+       }
+       rd = rd->next;
+    }
+    if (rd) {
+       /* already there */
+       message(MESS_DEBUG, "Already Got: %s\n", name);
+       return 0;
+    }
+    
+    rd = (struct ReqProv *)malloc(sizeof(*rd));
+    rd->flags = flags;
+    rd->name = strdup(name);
+    rd->version = version ? strdup(version) : NULL;
+    rd->next = p->reqprov;
+    p->reqprov = rd;
+
+    if (flags & REQUIRE_PROVIDES) {
+       message(MESS_DEBUG, "Adding provide: %s\n", name);
+       p->numProv++;
+    } else {
+       message(MESS_DEBUG, "Adding require: %s\n", name);
+       p->numReq++;
+    }
+
+    return 0;
+}
+
+/*************************************************************/
+/*                                                           */
+/* Add require/provides for the files in the header          */
+/*  (adds to the package structure)                          */
+/*                                                           */
+/*************************************************************/
+
+static void parseFileForProv(char *f, struct PackageRec *p)
+{
+    char file[1024];
+    char *s, *tok;
+
+    strcpy(file, f);
+    s = file + strlen(f) - 1;
+    while (*s != '/') {
+       s--;
+    }
+    s++;
+    tok = s;
+    
+    if ((s = strstr(s, ".so"))) {
+       s += 3;
+       *s = '\0';
+       addReqProv(p, REQUIRE_PROVIDES, tok, NULL);
+    }
+}
+
+int generateAutoReqProv(Header header, struct PackageRec *p)
+{
+    char **f, *s, *tok;
+    int count;
+    int lddPID;
+    int lddDead;
+    int toLdd[2];
+    int fromLdd[2];
+
+    StringBuf writeBuff;
+    StringBuf readBuff;
+    char *writePtr;
+    int writeBytesLeft, bytesWritten;
+
+    int bytes;
+    unsigned char buf[8193];
+
+    int status;
+    void *oldhandler;
+
+    message(MESS_VERBOSE, "Finding dependencies\n");
+
+    pipe(toLdd);
+    pipe(fromLdd);
+    
+    oldhandler = signal(SIGPIPE, SIG_IGN);
+
+    if (!(lddPID = fork())) {
+       close(0);
+       close(1);
+       close(toLdd[1]);
+       close(fromLdd[0]);
+       
+       dup2(toLdd[0], 0);   /* Make stdin the in pipe */
+       dup2(fromLdd[1], 1); /* Make stdout the out pipe */
+       close(2);            /* Toss stderr */
+
+       if (getVar(RPMVAR_ROOT)) {
+           if (chdir(getVar(RPMVAR_ROOT))) {
+               error(RPMERR_EXEC, "Couldn't chdir to %s",
+                     getVar(RPMVAR_ROOT));
+               exit(RPMERR_EXEC);
+           }
+       } else {
+           chdir("/");
+       }
+
+       execlp("xargs", "xargs", "ldd", NULL);
+       error(RPMERR_EXEC, "Couldn't exec ldd");
+       exit(RPMERR_EXEC);
+    }
+    if (lddPID < 0) {
+       error(RPMERR_FORK, "Couldn't fork ldd (xargs)");
+       return RPMERR_FORK;
+    }
+
+    close(toLdd[0]);
+    close(fromLdd[1]);
+
+    /* Do not block reading or writing from/to ldd. */
+    fcntl(fromLdd[0], F_SETFL, O_NONBLOCK);
+    fcntl(toLdd[1], F_SETFL, O_NONBLOCK);
+
+    if (!getEntry(header, RPMTAG_FILENAMES, NULL, (void **) &f, &count)) {
+       /* count may already be 0, but this is safer */
+       count = 0;
+    }
+
+    readBuff = newStringBuf();
+    
+    writeBuff = newStringBuf();
+    writeBytesLeft = 0;
+    while (count--) {
+        s = *f++;
+        writeBytesLeft += strlen(s) + 1;
+        appendLineStringBuf(writeBuff, s);
+       parseFileForProv(s, p);
+    }
+    writePtr = getStringBuf(writeBuff);
+   
+    lddDead = 0;
+    do {
+       if (waitpid(lddPID, &status, WNOHANG)) {
+           lddDead = 1;
+       }
+
+       /* Write some stuff to the ldd process if possible */
+        if (writeBytesLeft) {
+           if ((bytesWritten =
+                 write(toLdd[1], writePtr,
+                   (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) {
+               if (errno != EAGAIN) {
+                   perror("Damn!");
+                   exit(1);
+               }
+               bytesWritten = 0;
+           }
+           writeBytesLeft -= bytesWritten;
+           writePtr += bytesWritten;
+       } else {
+           close(toLdd[1]);
+       }
+       
+       /* Read any data from ldd */
+       bytes = read(fromLdd[0], buf, sizeof(buf)-1);
+       while (bytes > 0) {
+           buf[bytes] = '\0';
+           appendStringBuf(readBuff, buf);
+           bytes = read(fromLdd[0], buf, sizeof(buf)-1);
+       }
+
+       /* terminate when ldd dies */
+    } while (!lddDead);
+
+    close(toLdd[1]);
+    close(fromLdd[0]);
+    
+    signal(SIGPIPE, oldhandler);
+
+    if (writeBytesLeft) {
+       error(RPMERR_EXEC, "failed to write all data to ldd");
+       return 1;
+    }
+    waitpid(lddPID, &status, 0);
+    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+       error(RPMERR_EXEC, "ldd failed");
+       return 1;
+    }
+
+    freeStringBuf(writeBuff);
+    s = getStringBuf(readBuff);
+    while (*s) {
+       if (isspace(*s)) {
+           while (isspace(*s)) {
+               s++;
+           }
+           tok = s;
+           if ((s = strstr(s, ".so"))) {
+               s += 3;
+               *s = '\0';
+               addReqProv(p, REQUIRE_ANY, tok, NULL);
+           } else {
+               /* ACK! */
+               error(RPMERR_LDD, "ldd is babbling: %s", tok);
+               return 1;
+           }
+           s++;
+       }
+       while (*s && *s != '\n') {
+           s++;
+       }
+       if (*s) {
+           s++;
+       }
+    }
+    freeStringBuf(readBuff);
+    
+    return 0;
+}
+
+/*************************************************************/
+/*                                                           */
+/* Generate and add header entry from package record         */
+/*                                                           */
+/*************************************************************/
+
+int processReqProv(Header h, struct PackageRec *p)
+{
+    struct ReqProv *rd;
+    char **nameArray, **namePtr;
+    char **versionArray, **versionPtr;
+    int_32 *flagArray, *flagPtr;
+    
+
+    if (p->numProv) {
+       rd = p->reqprov;
+       nameArray = namePtr = malloc(p->numProv * sizeof(*nameArray));
+       message(MESS_VERBOSE, "Provides (%d):", p->numProv);
+       while (rd) {
+           if (rd->flags & REQUIRE_PROVIDES) {
+               message(MESS_VERBOSE, " %s", rd->name);
+               *namePtr++ = rd->name;
+           }
+           rd = rd->next;
+       }
+       addEntry(h, RPMTAG_PROVIDES, STRING_ARRAY_TYPE, nameArray, p->numProv);
+       free(nameArray);
+    }
+
+    if (p->numReq) {
+       rd = p->reqprov;
+       nameArray = namePtr = malloc(p->numReq * sizeof(*nameArray));
+       versionArray = versionPtr = malloc(p->numReq * sizeof(*versionArray));
+       flagArray = flagPtr = malloc(p->numReq * sizeof(*flagArray));
+       message(MESS_VERBOSE, "\nRequires (%d):", p->numReq);
+       while (rd) {
+           if (! (rd->flags & REQUIRE_PROVIDES)) {
+               message(MESS_VERBOSE, " %s", rd->name);
+               *namePtr++ = rd->name;
+               *versionPtr++ = rd->version ? rd->version : "";
+               *flagPtr++ = rd->flags;
+           }
+           rd = rd->next;
+       }
+       message(MESS_VERBOSE, "\n");
+
+       addEntry(h, RPMTAG_REQUIRENAME, STRING_ARRAY_TYPE,
+                nameArray, p->numReq);
+       addEntry(h, RPMTAG_REQUIREVERSION, STRING_ARRAY_TYPE,
+                versionArray, p->numReq);
+       addEntry(h, RPMTAG_REQUIREFLAGS, INT32_TYPE,
+                flagArray, p->numReq);
+
+       free(nameArray);
+       free(versionArray);
+       free(flagArray);
+    }
+
+    return 0;
+}
diff --git a/build/reqprov.h b/build/reqprov.h
new file mode 100644 (file)
index 0000000..f45e8a6
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _REQPROV_H_
+#define _REQPROV_H_
+
+#include "specP.h"
+
+int addReqProv(struct PackageRec *p, int flags,
+              char *name, char *version);
+int generateAutoReqProv(Header header, struct PackageRec *p);
+int processReqProv(Header h, struct PackageRec *p);
+
+#endif _REQPROV_H_