diff options
author | ewt <devnull@localhost> | 1998-01-12 21:31:29 +0000 |
---|---|---|
committer | ewt <devnull@localhost> | 1998-01-12 21:31:29 +0000 |
commit | 757e50ffc827297e36f793cf79ddc471878f6d0b (patch) | |
tree | dc29d9ef04a9462998bdfaaa3ee7054585fe01c8 | |
parent | ec07f9df959c911c60727ba68c455f4ff20497bf (diff) | |
download | rpm-757e50ffc827297e36f793cf79ddc471878f6d0b.tar.gz rpm-757e50ffc827297e36f793cf79ddc471878f6d0b.tar.bz2 rpm-757e50ffc827297e36f793cf79ddc471878f6d0b.zip |
merged in Marc's new build code
CVS patchset: 1956
CVS date: 1998/01/12 21:31:29
-rw-r--r-- | CHANGES | 31 | ||||
-rw-r--r-- | Makefile.in | 13 | ||||
-rw-r--r-- | Makefile.inc.in | 10 | ||||
-rw-r--r-- | build.c | 132 | ||||
-rw-r--r-- | build.h | 7 | ||||
-rw-r--r-- | build/Makefile.in | 17 | ||||
-rw-r--r-- | build/TODO | 44 | ||||
-rw-r--r-- | build/build.c | 881 | ||||
-rw-r--r-- | build/build.h | 33 | ||||
-rw-r--r-- | build/files.c | 1800 | ||||
-rw-r--r-- | build/files.h | 16 | ||||
-rw-r--r-- | build/macro.c | 168 | ||||
-rw-r--r-- | build/macro.h | 23 | ||||
-rw-r--r-- | build/misc.c | 202 | ||||
-rw-r--r-- | build/misc.h | 27 | ||||
-rw-r--r-- | build/myftw.c | 20 | ||||
-rw-r--r-- | build/myftw.h | 9 | ||||
-rw-r--r-- | build/names.c | 15 | ||||
-rw-r--r-- | build/names.h | 1 | ||||
-rw-r--r-- | build/pack.c | 902 | ||||
-rw-r--r-- | build/pack.h | 14 | ||||
-rw-r--r-- | build/package.c | 128 | ||||
-rw-r--r-- | build/package.h | 9 | ||||
-rw-r--r-- | build/parse.h | 17 | ||||
-rw-r--r-- | build/parseBuildInstallClean.c | 46 | ||||
-rw-r--r-- | build/parseChangelog.c | 211 | ||||
-rw-r--r-- | build/parseDescription.c | 110 | ||||
-rw-r--r-- | build/parseFiles.c | 103 | ||||
-rw-r--r-- | build/parsePreamble.c | 631 | ||||
-rw-r--r-- | build/parsePrep.c | 480 | ||||
-rw-r--r-- | build/parseReqs.c | 125 | ||||
-rw-r--r-- | build/parseScript.c | 199 | ||||
-rw-r--r-- | build/parseSpec.c | 186 | ||||
-rw-r--r-- | build/parseTrigger.c (renamed from build/trigger.c) | 56 | ||||
-rw-r--r-- | build/part.c | 56 | ||||
-rw-r--r-- | build/part.h | 24 | ||||
-rw-r--r-- | build/read.c | 138 | ||||
-rw-r--r-- | build/read.h | 16 | ||||
-rw-r--r-- | build/reqprov.c | 474 | ||||
-rw-r--r-- | build/reqprov.h | 14 | ||||
-rw-r--r-- | build/spec.c | 1857 | ||||
-rw-r--r-- | build/spec.h | 130 | ||||
-rw-r--r-- | build/specP.h | 97 | ||||
-rw-r--r-- | build/trigger.h | 13 | ||||
-rw-r--r-- | build/vspec.c | 206 | ||||
-rw-r--r-- | lib/Makefile.in | 6 | ||||
-rw-r--r-- | lib/misc.c | 2 | ||||
-rwxr-xr-x | rpm.c | 201 | ||||
-rw-r--r-- | rpm.spec | 2 |
49 files changed, 5129 insertions, 4773 deletions
@@ -1,5 +1,36 @@ 2.4.11 -> 2.5: - added many more i18n strings + - merged in large rewrite of build code, which includes the following + changes: + - all scripts can now take -p <prog> + - all scripts can now take -p "<prog> <arg>..." + - more strict about %package placement and use of main package + preamble + - %attr(mode, user, group [, dirmode]) + - %defattr() + - %defverify() + - Root: is depricated. Use BuildRoot: instead + - "nosrc" sources arn't deleted when sources are removed + - New tag DocDir: <dir> to set alternate doc dir (default is + /usr/doc) + - %doc should work as expected with buildroot, prefix, DocDir: + - all file processing is done before any packaging + - should work with modern patch programs (later than 2.1) + - %patch -z <arg> same as %patch -b <arg> + - %define only defines a macro if it starts a line + - script prog entries are now arrays (ie with arguments) + - standard macros: tag names, buildarch, buildos, buildarch_lc, + buildos_lc, PATCHn, SOURCEn, PATCHURLn, SOURCEURLn, sourcedir, + builddir, optflags + - deprecate require_distribution, require_icon, require_vendor + - add RPMTAG_FILEDEVICES and RPMTAG_FILEINODES to header + - export variables in scripts + - fixed tag:field bug + - %lang() in %files + - %description -l <lang> + - Summary(<lang>): + - fixed read_line() termination usage + - Makefile changes to shorten compiler lines 2.4.11 -> 2.4.12: - intialize reserved portion of lead when writing packages diff --git a/Makefile.in b/Makefile.in index 2e0abccc4..ecdb4fd44 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,10 +33,11 @@ ETCDIR=$(ROOT)/etc SUBDIRS = popt @MISCDIR@ lib build tools @PO@ INSTSUBDIRS = lib @PO@ OTHERSUBDIRS = docs autodeps -OBJS = rpm.o query.o install.o verify.o checksig.o ftp.o url.o @GETTEXTSTUB@ +OBJS = rpm.o query.o install.o verify.o checksig.o ftp.o url.o build.o \ + @GETTEXTSTUB@ PROGS = @RPM@ rpm2cpio LIBS = @LIBS@ @LIBINTL@ @LIBDL@ -LOADLIBES = -lbuild popt/libpopt.a $(topdir)/lib/librpm.a -L$(topdir)/misc @LIBMISC@ +LOADLIBES = -lrpmbuild -lpopt -lrpm @LIBMISC@ SOURCES = $(subst .o,.c,$(OBJS)) @@ -48,11 +49,11 @@ endif all: $(TARGET) -rpm: lib/librpm.a build/libbuild.a @MISCPATH@ $(OBJS) - $(CC) -o rpm -static $(LDFLAGS) $(OBJS) $(LOADLIBES) $(LIBS) \ +rpm: lib/librpm.a build/librpmbuild.a @MISCPATH@ $(OBJS) + $(CC) -o rpm -static $(OBJS) $(LDFLAGS) $(LOADLIBES) $(LIBS) \ $(LIBEFENCE) -rpm.shared: lib/librpm.a build/libbuild.a $(OBJS) +rpm.shared: lib/librpm.a build/rpmlibbuild.a $(OBJS) $(CC) -o rpm.shared $(LDFLAGS) $(OBJS) $(LOADLIBES) $(LIBS) \ $(LIBEFENCE) @@ -68,6 +69,8 @@ rpm2cpio: lib/librpm.a rpm2cpio.o rpm.o: rpm.c query.h install.h lib/rpmlib.h Makefile $(CC) $(CFLAGS) -DRPMNLSPACKAGE=\"$(RPMNLSPACKAGE)\" \ -DRPMNLSDIR=\"$(RPMNLSDIR)\" \ + -DVERSION=\"$(VERSION)\" \ + -DLIBRPMALIAS_FILENAME="\"$(LIBRPMALIAS_FILENAME)"\" \ -c $(srcdir)/rpm.c # these rules should be in here, but they drive me batty diff --git a/Makefile.inc.in b/Makefile.inc.in index 10c4cb8a3..fcc42e086 100644 --- a/Makefile.inc.in +++ b/Makefile.inc.in @@ -12,12 +12,8 @@ LIBRPMALIAS_FILENAME=$(libdir)/rpmpopt RPMNLSDIR=@datadir@/locale RPMNLSPACKAGE=rpm CFLAGS = @CFLAGS@ @INCPATH@ $(WARNINGS) $(OPTS) -I$(topdir) \ - -I$(topdir)/lib -I$(topdir)/misc -Wall -Wstrict-prototypes \ - -DLIBRPMRC_FILENAME="\"$(LIBRPMRC_FILENAME)"\" \ - -DLIBRPMALIAS_FILENAME="\"$(LIBRPMALIAS_FILENAME)"\" \ - -DVERSION=\"$(VERSION)\" -LDFLAGS = @LDFLAGS@ -Llib -Lbuild -Lmisc -L$(topdir)/lib \ - -L$(topdir)/build -L$(topdir)/misc -VERSION = 2.4.12 + -I$(topdir)/lib -I$(topdir)/misc -Wall -Wstrict-prototypes +LDFLAGS = @LDFLAGS@ -L$(topdir)/lib -L$(topdir)/build -L$(topdir)/misc +VERSION = 2.4.99 CC = @CC@ diff --git a/build.c b/build.c new file mode 100644 index 000000000..24c1d80a3 --- /dev/null +++ b/build.c @@ -0,0 +1,132 @@ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "build.h" +#include "intl.h" +#include "lib/rpmlib.h" +#include "build/build.h" +#include "build/parse.h" +#include "build/spec.h" + +int build(char *arg, int buildAmount, char *passPhrase, + char *buildRoot, int fromTarball, int test, char *cookie) { + FILE *f; + char * specfile; + int res = 0; + struct stat statbuf; + char * specDir; + char * tmpSpecFile; + char * cmd; + char * s; + int count, fd; + char buf[BUFSIZ]; + Spec spec = NULL; + + if (fromTarball) { + specDir = rpmGetVar(RPMVAR_SPECDIR); + tmpSpecFile = alloca(BUFSIZ); + sprintf(tmpSpecFile, "%s/rpm-spec-file-%d", specDir, (int) getpid()); + + cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile)); + sprintf(cmd, "gunzip < %s | tar xOvf - \\*.spec 2>&1 > %s", arg, + tmpSpecFile); + if (!(f = popen(cmd, "r"))) { + fprintf(stderr, _("Failed to open tar pipe: %s\n"), + strerror(errno)); + return 1; + } + if (!fgets(buf, sizeof(buf) - 1, f)) { + fprintf(stderr, _("Failed to read spec file from %s\n"), arg); + unlink(tmpSpecFile); + return 1; + } + pclose(f); + + cmd = specfile = buf; + while (*cmd) { + if (*cmd == '/') specfile = cmd + 1; + cmd++; + } + + cmd = specfile; + + /* remove trailing \n */ + specfile = cmd + strlen(cmd) - 1; + *specfile = '\0'; + + specfile = alloca(strlen(specDir) + strlen(cmd) + 5); + sprintf(specfile, "%s/%s", specDir, cmd); + + if (rename(tmpSpecFile, specfile)) { + fprintf(stderr, _("Failed to rename %s to %s: %s\n"), + tmpSpecFile, specfile, strerror(errno)); + unlink(tmpSpecFile); + return 1; + } + + /* Make the directory which contains the tarball the source + directory for this run */ + + if (*arg != '/') { + getcwd(buf, BUFSIZ); + strcat(buf, "/"); + strcat(buf, arg); + } else + strcpy(buf, arg); + + cmd = buf + strlen(buf) - 1; + while (*cmd != '/') cmd--; + *cmd = '\0'; + + rpmSetVar(RPMVAR_SOURCEDIR, buf); + } else if (arg[0] == '/') { + specfile = arg; + } else { + specfile = alloca(BUFSIZ); + getcwd(specfile, BUFSIZ); + strcat(specfile, "/"); + strcat(specfile, arg); + } + + stat(specfile, &statbuf); + if (! S_ISREG(statbuf.st_mode)) { + fprintf(stderr, _("File is not a regular file: %s\n"), specfile); + return 1; + } + + if (!(fd = open(specfile, O_RDONLY))) { + fprintf(stderr, _("Unable to open spec file: %s\n"), specfile); + return 1; + } + count = read(fd, buf, sizeof(buf)); + close(fd); + s = buf; + while(count--) { + if (! (isprint(*s) || isspace(*s))) { + fprintf(stderr, _("File contains non-printable characters(%c): %s\n"), *s, + specfile); + return 1; + } + s++; + } + + if (parseSpec(&spec, specfile, buildRoot, 0, passPhrase, cookie)) { + return 1; + } + + if (buildSpec(spec, buildAmount, test)) { + freeSpec(spec); + return 1; + } + + if (fromTarball) unlink(specfile); + + freeSpec(spec); + + return res; +} diff --git a/build.h b/build.h new file mode 100644 index 000000000..0cc4e3cb3 --- /dev/null +++ b/build.h @@ -0,0 +1,7 @@ +#ifndef H_BUILD +#define H_BUILD + +int build(char *arg, int buildAmount, char *passPhrase, + char *buildRoot, int fromTarball, int test, char *cookie); + +#endif diff --git a/build/Makefile.in b/build/Makefile.in index 947268d10..29fdb0763 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -1,10 +1,16 @@ srcdir = @srcdir@ VPATH = $(srcdir) -LIBOBJECTS = spec.o vspec.o build.o files.o names.o pack.o myftw.o \ - reqprov.o trigger.o macro.o -LIBBUILD = libbuild.a -LOADLIBES = -lrpm $(LIBEFENCE) +LIBOBJECTS = \ +misc.o parsePreamble.o part.o \ +package.o parseDescription.o parsePrep.o read.o \ +parseFiles.o parseReqs.o reqprov.o \ +parseChangelog.o parseSpec.o spec.o \ +parseScript.o parseBuildInstallClean.o build.o \ +files.o myftw.o names.o pack.o macro.o + +LIBBUILD = librpmbuild.a +LOADLIBES = -lrpm -lz ../popt/libpopt.a $(LIBEFENCE) # ----------------------------------------------------------------------- @@ -26,6 +32,9 @@ $(LIBBUILD): $(LIBOBJECTS) $(PROGS): $(LIBOBJECTS) +pack.o: + $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -o $@ -c $< + clean: rm -f *.a *.o *~ $(PROGS) diff --git a/build/TODO b/build/TODO new file mode 100644 index 000000000..14d0f4bbb --- /dev/null +++ b/build/TODO @@ -0,0 +1,44 @@ +> Most of my spec files have empty Distribution: and Vendor: tag because I +> really don't care. Now, empty tags are frowned upon. So, I try to comment +> out the lines and get a funny error message: +> +> Distribution field must be present in package: solaris2.6 +> Vendor field must be present in package: solaris2.6 +> +> This happens to be my value of 'Build Os' which gets into the error message! + +posix %attr + +Add Shell: rpmrc entry + +some /foo/*/*.foo entries don't get matches + +detect multiple summary/description entries + +verify langs + +===================================================================== +i18n strings + +triggers + +custom find-requires, find-provides + +messages (normal, verbose, debug) + +deprecate require_distribution, require_icon, require_vendor +deprecate RPMVAR_ROOT, and the RPMVAR_REQUIRE* stuff above + +======================================================================= +* i18n + +headerGetRawEntry() -> i18n string +headerAddI18nString(Header, tag, string, lang) + +Summary(...): +%description -l ... + +%lang(...) <file> + +"intl.h" +_("...") diff --git a/build/build.c b/build/build.c index d432a0f5a..087737955 100644 --- a/build/build.c +++ b/build/build.c @@ -1,751 +1,236 @@ -/* RPM - Copyright (C) 1995 Red Hat Software - * - * build.c - routines for preparing and building the sources - */ - -#include "miscfn.h" - -#include <stdlib.h> -#include <stdio.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <limits.h> +#include <sys/stat.h> +#include <malloc.h> -#include "build.h" -#include "files.h" -#include "header.h" +#include "misc.h" #include "spec.h" -#include "specP.h" +#include "build.h" +#include "lib/misc.h" +#include "lib/messages.h" #include "rpmlib.h" -#include "messages.h" -#include "stringbuf.h" -#include "misc.h" #include "pack.h" -#include "popt/popt.h" -#include "config.h" - -#include "names.h" - -struct Script { - char *name; - FILE *file; -}; - -struct Script *openScript(Spec spec, int builddir, char *name); -void writeScript(struct Script *script, char *s); -int execScript(struct Script *script); -void freeScript(struct Script *script, int test); -int execPart(Spec s, char *sb, char *name, int builddir, int test); -static int doSetupMacro(Spec spec, StringBuf sb, char *line); -static int doPatchMacro(Spec spec, StringBuf sb, char *line); -static char *do_untar(Spec spec, int c, int quietly); -static char *do_patch(Spec spec, int c, int strip, char *dashb, - int reverse, int removeEmpties); -int isCompressed(char *file); -static void doSweep(Spec s); -static int doRmSource(Spec s); +#include "files.h" -char build_subdir[1024]; +static void doRmSource(Spec spec); +static int writeVars(Spec spec, FILE *f); -struct Script *openScript(Spec spec, int builddir, char *name) +int buildSpec(Spec spec, int what, int test) { - struct Script *script = malloc(sizeof(struct Script)); - struct PackageRec *main_package = spec->packages; - char *s, * arch, * os; - int fd; - int_32 foo; - - rpmGetArchInfo(&arch, NULL); - rpmGetOsInfo(&os, NULL); - - if (! main_package) { - rpmError(RPMERR_INTERNAL, "Empty main package"); - exit(RPMERR_INTERNAL); - } - - if (makeTempFile(NULL, &script->name, &fd)) - exit(1); - script->file = fdopen(fd, "w"); - - /* Prepare the script */ - fprintf(script->file, - "# Script generated by rpm\n\n"); + int x, rc; - fprintf(script->file, "RPM_SOURCE_DIR=\"%s\"\n", rpmGetVar(RPMVAR_SOURCEDIR)); - fprintf(script->file, "RPM_BUILD_DIR=\"%s\"\n", rpmGetVar(RPMVAR_BUILDDIR)); - fprintf(script->file, "RPM_DOC_DIR=\"%s\"\n", rpmGetVar(RPMVAR_DEFAULTDOCDIR)); - fprintf(script->file, "RPM_OPT_FLAGS=\"%s\"\n", rpmGetVar(RPMVAR_OPTFLAGS)); - fprintf(script->file, "RPM_ARCH=\"%s\"\n", arch); - fprintf(script->file, "RPM_OS=\"%s\"\n", os); - if (rpmGetVar(RPMVAR_ROOT)) { - fprintf(script->file, "RPM_ROOT_DIR=\"%s\"\n", rpmGetVar(RPMVAR_ROOT)); - } else { - fprintf(script->file, "RPM_ROOT_DIR=\"\"\n"); - } - if (rpmGetVar(RPMVAR_BUILDROOT)) { - fprintf(script->file, "RPM_BUILD_ROOT=\"%s\"\n", - rpmGetVar(RPMVAR_BUILDROOT)); - } else { - fprintf(script->file, "RPM_BUILD_ROOT=\"\"\n"); - } - - fprintf(script->file, "RPM_PACKAGE_NAME=\"%s\"\n", spec->name); - headerGetEntry(main_package->header, RPMTAG_VERSION, &foo, (void **)&s, &foo); - fprintf(script->file, "RPM_PACKAGE_VERSION=\"%s\"\n", s); - headerGetEntry(main_package->header, RPMTAG_RELEASE, &foo, (void **)&s, &foo); - fprintf(script->file, "RPM_PACKAGE_RELEASE=\"%s\"\n", s); - - if (rpmIsVerbose()) { - fprintf(script->file, "set -x\n\n"); + if (!spec->inBuildArchitectures && spec->buildArchitectureCount) { + /* When iterating over buildArchitectures, do the source */ + /* packaging on the first run, and skip RMSOURCE altogether */ + x = 0; + while (x < spec->buildArchitectureCount) { + if ((rc = buildSpec(spec->buildArchitectureSpecs[x], + (what & ~RPMBUILD_RMSOURCE) | + (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)), + test))) { + return rc; + } + x++; + } } else { - fprintf(script->file, "exec > /dev/null\n\n"); - } - - /* Set the umask to a known value */ - fprintf(script->file, "umask 022\n"); - - fprintf(script->file, "\necho Executing: %s\n", name); - fprintf(script->file, "cd %s\n\n", rpmGetVar(RPMVAR_BUILDDIR)); - if (builddir) { - /* Need to cd to the actual build directory. */ - /* Note that this means we have to parse the */ - /* %prep section even if we aren't using it. */ - fprintf(script->file, "cd %s\n\n", build_subdir); - } - - /* We do a litte sanity check here just to make sure we do not wipe */ - /* the system by accident... */ - if (rpmGetVar(RPMVAR_BUILDROOT)) { - fprintf(script->file, "if [ -z \"$RPM_BUILD_ROOT\" -o \"$RPM_BUILD_ROOT\" = \"/\" ]; then\n"); - fprintf(script->file, " echo\n"); - fprintf(script->file, " echo 'Warning: Spec contains BuildRoot: tag that is either empty or is set to \"/\"'\n"); - fprintf(script->file, " echo\n"); - fprintf(script->file, " exit 1\n"); - fprintf(script->file, "fi\n"); - } - - return script; -} - -void writeScript(struct Script *script, char *s) -{ - fprintf(script->file, "%s", s); -} - -int execScript(struct Script *script) -{ - int pid; - int status; - - writeScript(script, "\nexit 0;\n"); - fclose(script->file); - script->file = NULL; - chmod(script->name, 0600); - - if (!(pid = fork())) { - execl("/bin/sh", "/bin/sh", "-e", script->name, script->name, NULL); - rpmError(RPMERR_SCRIPT, "Exec failed"); - _exit(RPMERR_SCRIPT); - } - wait(&status); - if (! WIFEXITED(status) || WEXITSTATUS(status)) { - rpmError(RPMERR_SCRIPT, "Bad exit status"); - exit(RPMERR_SCRIPT); - } - return 0; -} - -void freeScript(struct Script *script, int test) -{ - if (script->file) - fclose(script->file); - if (! test) - unlink(script->name); - free(script->name); - free(script); -} - -int execPart(Spec s, char *sb, char *name, int builddir, int test) -{ - struct Script *script; - - rpmMessage(RPMMESS_DEBUG, "RUNNING: %s\n", name); - script = openScript(s, builddir, name); - writeScript(script, sb); - if (!test) { - execScript(script); - } - freeScript(script, test); - return 0; -} - -static void doSweep(Spec s) -{ - char buf[1024]; - - if (strcmp(build_subdir, ".")) { - struct Script *script; - script = openScript(s, 0, "sweep"); - sprintf(buf, "rm -rf %s\n", build_subdir); - writeScript(script, buf); - execScript(script); - freeScript(script, 0); - } -} - -static int doRmSource(Spec s) -{ - char filename[1024]; - struct sources *source; - struct PackageRec *package; - - /* spec file */ - sprintf(filename, "%s%s", rpmGetVar(RPMVAR_SPECDIR), - strrchr(s->specfile, '/')); - unlink(filename); - - /* sources and patches */ - source = s->sources; - while (source) { - sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), source->source); - unlink(filename); - source = source->next; - } - - /* icons */ - package = s->packages; - while (package) { - if (package->icon) { - sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), - package->icon); - unlink(filename); + if (what & RPMBUILD_PREP) { + if ((rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test))) { + return rc; + } } - package = package->next; - } - - return 0; -} - -static int doSetupMacro(Spec spec, StringBuf sb, char *line) -{ - char *version; - int leaveDirs = 0, skipDefaultAction = 0; - int createDir = 0, quietly = 0; - char * dirName = NULL; - char buf[1024]; - StringBuf before; - StringBuf after; - poptContext optCon; - int argc; - char ** argv; - int arg; - char * optArg; - char * chptr; - int rc; - int num; - struct poptOption optionsTable[] = { - { NULL, 'a', POPT_ARG_STRING, NULL, 'a' }, - { NULL, 'b', POPT_ARG_STRING, NULL, 'b' }, - { NULL, 'c', 0, &createDir, 0 }, - { NULL, 'D', 0, &leaveDirs, 0 }, - { NULL, 'n', POPT_ARG_STRING, &dirName, 0 }, - { NULL, 'T', 0, &skipDefaultAction, 0 }, - { NULL, 'q', 0, &quietly, 0 }, - { 0, 0, 0, 0, 0 } - }; - - if ((rc = poptParseArgvString(line, &argc, &argv))) { - rpmError(RPMERR_BADSPEC, "Error parsing %%setup: %s", - poptStrerror(rc)); - return RPMERR_BADSPEC; - } - - before = newStringBuf(); - after = newStringBuf(); - - optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); - while ((arg = poptGetNextOpt(optCon)) > 0) { - optArg = poptGetOptArg(optCon); - - /* We only parse -a and -b here */ - - num = strtoul(optArg, &chptr, 10); - if ((*chptr) || (chptr == optArg) || (num == ULONG_MAX)) { - rpmError(RPMERR_BADSPEC, "Bad arg to %%setup %c: %s", num, optArg); - free(argv); - freeStringBuf(before); - freeStringBuf(after); - poptFreeContext(optCon); - return(RPMERR_BADSPEC); + if (what & RPMBUILD_BUILD) { + if ((rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test))) { + return rc; + } } - - chptr = do_untar(spec, num, quietly); - if (!chptr) return 1; - - if (arg == 'a') - appendLineStringBuf(after, chptr); - else - appendLineStringBuf(before, chptr); - } - - if (arg < -1) { - rpmError(RPMERR_BADSPEC, "Bad %%setup option %s: %s", - poptBadOption(optCon, POPT_BADOPTION_NOALIAS), - poptStrerror(arg)); - free(argv); - freeStringBuf(before); - freeStringBuf(after); - poptFreeContext(optCon); - return(RPMERR_BADSPEC); - } - - if (dirName) { - strcpy(build_subdir, dirName); - } else { - strcpy(build_subdir, spec->name); - strcat(build_subdir, "-"); - /* We should already have a version field */ - headerGetEntry(spec->packages->header, RPMTAG_VERSION, NULL, - (void *) &version, NULL); - strcat(build_subdir, version); - } - - free(argv); - poptFreeContext(optCon); - - /* cd to the build dir */ - sprintf(buf, "cd %s", rpmGetVar(RPMVAR_BUILDDIR)); - appendLineStringBuf(sb, buf); - - /* delete any old sources */ - if (!leaveDirs) { - sprintf(buf, "rm -rf %s", build_subdir); - appendLineStringBuf(sb, buf); - } - - /* if necessary, create and cd into the proper dir */ - if (createDir) { - sprintf(buf, "mkdir -p %s\ncd %s", build_subdir, build_subdir); - appendLineStringBuf(sb, buf); - } - - /* do the default action */ - if (!createDir && !skipDefaultAction) { - chptr = do_untar(spec, 0, quietly); - if (!chptr) return 1; - appendLineStringBuf(sb, chptr); - } - - appendStringBuf(sb, getStringBuf(before)); - freeStringBuf(before); - - if (!createDir) { - sprintf(buf, "cd %s", build_subdir); - appendLineStringBuf(sb, buf); - } - - if (createDir && !skipDefaultAction) { - chptr = do_untar(spec, 0, quietly); - if (!chptr) return 1; - appendLineStringBuf(sb, chptr); - } - - appendStringBuf(sb, getStringBuf(after)); - freeStringBuf(after); - - /* clean up permissions etc */ - if (!geteuid()) { - appendLineStringBuf(sb, "chown -R root ."); - appendLineStringBuf(sb, "chgrp -R root ."); - } - - if (rpmGetVar(RPMVAR_FIXPERMS)) { - appendStringBuf(sb, "chmod -R "); - appendStringBuf(sb, rpmGetVar(RPMVAR_FIXPERMS)); - appendLineStringBuf(sb, " ."); - } - - return 0; -} - -int isCompressed(char *file) -{ - int fd; - unsigned char magic[4]; - - fd = open(file, O_RDONLY); - read(fd, magic, 4); - close(fd); - - if (((magic[0] == 0037) && (magic[1] == 0213)) || /* gzip */ - ((magic[0] == 0037) && (magic[1] == 0236)) || /* old gzip */ - ((magic[0] == 0037) && (magic[1] == 0036)) || /* pack */ - ((magic[0] == 0037) && (magic[1] == 0240)) || /* SCO lzh */ - ((magic[0] == 0037) && (magic[1] == 0235)) || /* compress */ - ((magic[0] == 0120) && (magic[1] == 0113) && - (magic[2] == 0003) && (magic[3] == 0004)) /* pkzip */ - ) { - return 1; - } - - return 0; -} - -static char *do_untar(Spec spec, int c, int quietly) -{ - static char buf[1024]; - char file[1024]; - char *s, *taropts; - struct sources *sp; - - s = NULL; - sp = spec->sources; - while (sp) { - if ((sp->ispatch == 0) && (sp->num == c)) { - s = sp->source; - break; + if (what & RPMBUILD_INSTALL) { + if ((rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test))) { + return rc; + } } - sp = sp->next; - } - if (! s) { - rpmError(RPMERR_BADSPEC, "No source number %d", c); - return NULL; - } - - sprintf(file, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), s); - taropts = (rpmIsVerbose() && !quietly ? "-xvvf" : "-xf"); - - if (isCompressed(file)) { - sprintf(buf, - "%s -dc %s | tar %s -\n" - "if [ $? -ne 0 ]; then\n" - " exit $?\n" - "fi", - rpmGetVar(RPMVAR_GZIPBIN), file, taropts); - } else { - sprintf(buf, "tar %s %s", taropts, file); - } - return buf; -} - -static char *do_patch(Spec spec, int c, int strip, char *db, - int reverse, int removeEmpties) -{ - static char buf[1024]; - char file[1024]; - char args[1024]; - char *s; - struct sources *sp; - - s = NULL; - sp = spec->sources; - while (sp) { - if ((sp->ispatch == 1) && (sp->num == c)) { - s = sp->source; - break; + if (what & RPMBUILD_PACKAGESOURCE) { + if ((rc = processSourceFiles(spec))) { + return rc; + } } - sp = sp->next; - } - if (! s) { - rpmError(RPMERR_BADSPEC, "No patch number %d", c); - return NULL; - } - - sprintf(file, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), s); - - args[0] = '\0'; - if (db) { -#if HAVE_OLDPATCH_21 == 0 - strcat(args, "-b "); -#endif - strcat(args, "--suffix "); - strcat(args, db); - } - if (reverse) { - strcat(args, " -R"); - } - if (removeEmpties) { - strcat(args, " -E"); - } - - if (isCompressed(file)) { - sprintf(buf, - "echo \"Patch #%d:\"\n" - "%s -dc %s | patch -p%d %s -s\n" - "if [ $? -ne 0 ]; then\n" - " exit $?\n" - "fi", - c, rpmGetVar(RPMVAR_GZIPBIN), file, strip, args); - } else { - sprintf(buf, - "echo \"Patch #%d:\"\n" - "patch -p%d %s -s < %s", c, strip, args, file); - } - return buf; -} - -static int doPatchMacro(Spec spec, StringBuf sb, char *line) -{ - char *opt_b; - int opt_P, opt_p, opt_R, opt_E; - char *s, *s1; - char buf[1024]; - int patch_nums[1024]; /* XXX - we can only handle 1024 patches! */ - int patch_index, x; - - opt_P = opt_p = opt_R = opt_E = 0; - opt_b = NULL; - patch_index = 0; - - if (! strchr(" \t\n", line[6])) { - /* %patchN */ - sprintf(buf, "%%patch -P %s", line + 6); - } else { - strcpy(buf, line); - } - - strtok(buf, " \t\n"); /* remove %patch */ - while ((s = strtok(NULL, " \t\n"))) { - if (!strcmp(s, "-P")) { - opt_P = 1; - } else if (!strcmp(s, "-R")) { - opt_R = 1; - } else if (!strcmp(s, "-E")) { - opt_E = 1; - } else if (!strcmp(s, "-b")) { - /* orig suffix */ - opt_b = strtok(NULL, " \t\n"); - if (! opt_b) { - rpmError(RPMERR_BADSPEC, "Need arg to %%patch -b"); - return(RPMERR_BADSPEC); + if ((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) || + (what & RPMBUILD_FILECHECK)) { + if ((rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL))) { + return rc; } - } else if (!strncmp(s, "-p", 2)) { - /* unfortunately, we must support -pX */ - if (! strchr(" \t\n", s[2])) { - s = s + 2; - } else { - s = strtok(NULL, " \t\n"); - if (! s) { - rpmError(RPMERR_BADSPEC, "Need arg to %%patch -p"); - return(RPMERR_BADSPEC); - } + } + + if (what & RPMBUILD_PACKAGESOURCE) { + if ((rc = packageSources(spec))) { + return rc; } - s1 = NULL; - opt_p = strtoul(s, &s1, 10); - if ((*s1) || (s1 == s) || (opt_p == ULONG_MAX)) { - rpmError(RPMERR_BADSPEC, "Bad arg to %%patch -p: %s", s); - return(RPMERR_BADSPEC); + } + if (what & RPMBUILD_PACKAGEBINARY) { + if ((rc = packageBinaries(spec))) { + return rc; } - } else { - /* Must be a patch num */ - if (patch_index == 1024) { - rpmError(RPMERR_BADSPEC, "Too many patches!"); - return(RPMERR_BADSPEC); + } + + if (what & RPMBUILD_CLEAN) { + if ((rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test))) { + return rc; } - s1 = NULL; - patch_nums[patch_index] = strtoul(s, &s1, 10); - if ((*s1) || (s1 == s) || (patch_nums[patch_index] == ULONG_MAX)) { - rpmError(RPMERR_BADSPEC, "Bad arg to %%patch: %s", s); - return(RPMERR_BADSPEC); + } + if (what & RPMBUILD_RMBUILD) { + if ((rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test))) { + return rc; } - patch_index++; } } - /* All args processed */ - - if (! opt_P) { - s = do_patch(spec, 0, opt_p, opt_b, opt_R, opt_E); - if (! s) { - return 1; - } - appendLineStringBuf(sb, s); + if (what & RPMBUILD_RMSOURCE) { + doRmSource(spec); } - x = 0; - while (x < patch_index) { - s = do_patch(spec, patch_nums[x], opt_p, opt_b, opt_R, opt_E); - if (! s) { - return 1; - } - appendLineStringBuf(sb, s); - x++; - } - return 0; } -static int checkSources(Spec s) +int doScript(Spec spec, int what, char *name, StringBuf sb, int test) { - struct sources *source; - struct PackageRec *package; - char buf[1024]; - - /* Check that we can access all the sources */ - source = s->sources; - while (source) { - sprintf(buf, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), source->source); - if (access(buf, R_OK)) { - rpmError(RPMERR_BADSPEC, "missing source or patch: %s", buf); - return RPMERR_BADSPEC; - } - source = source->next; + int fd; + FILE *f; + char *scriptName; + int pid; + int status; + + switch (what) { + case RPMBUILD_PREP: + name = "%prep"; + sb = spec->prep; + break; + case RPMBUILD_BUILD: + name = "%build"; + sb = spec->build; + break; + case RPMBUILD_INSTALL: + name = "%install"; + sb = spec->install; + break; + case RPMBUILD_CLEAN: + name = "%clean"; + sb = spec->clean; + break; + case RPMBUILD_RMBUILD: + name = "--clean"; + break; + case RPMBUILD_STRINGBUF: + break; + } + if ((what != RPMBUILD_RMBUILD) && !sb) { + return 0; } - - /* ... and icons */ - package = s->packages; - while (package) { - if (package->icon) { - sprintf(buf, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), package->icon); - if (access(buf, R_OK)) { - rpmError(RPMERR_BADSPEC, "missing icon: %s", buf); - return RPMERR_BADSPEC; - } - } - package = package->next; + + if (makeTempFile(NULL, &scriptName, &fd)) { + rpmError(RPMERR_SCRIPT, "Unable to open temp file"); + return RPMERR_SCRIPT; } + f = fdopen(fd, "w"); - return 0; -} - -int execPrep(Spec s, int really_exec, int test) -{ - char **lines, **lines1, *p; - StringBuf out; - int res; - - if (checkSources(s)) { - return 1; + if (writeVars(spec, f)) { + fclose(f); + FREE(scriptName); + return RPMERR_SCRIPT; } - out = newStringBuf(); - p = getStringBuf(s->prep); - lines = splitString(p, strlen(p), '\n'); - lines1 = lines; - while (*lines) { - if (! strncmp(*lines, "%setup", 6)) { - if (doSetupMacro(s, out, *lines)) { - return 1; - } - } else if (! strncmp(*lines, "%patch", 6)) { - if (doPatchMacro(s, out, *lines)) { - return 1; - } - } else { - appendLineStringBuf(out, *lines); - } - lines++; + fprintf(f, rpmIsVerbose() ? "set -x\n\n" : "exec > /dev/null\n\n"); + fprintf(f, "umask 022\n"); + fprintf(f, "cd %s\n", rpmGetVar(RPMVAR_BUILDDIR)); + if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD) { + fprintf(f, "cd %s\n", spec->buildSubdir); + } + if (what == RPMBUILD_RMBUILD) { + fprintf(f, "rm -rf %s\n", spec->buildSubdir); + } else { + fprintf(f, "%s", getStringBuf(sb)); } + fprintf(f, "\nexit 0\n"); + + fclose(f); + chmod(scriptName, 0600); - freeSplitString(lines1); - res = 0; - if (really_exec) { - res = execPart(s, getStringBuf(out), "%prep", 0, test); + if (test) { + FREE(scriptName); + return 0; } - freeStringBuf(out); - return res; -} - -int execBuild(Spec s, int test) -{ - return execPart(s, getStringBuf(s->build), "%build", 1, test); -} - -int execInstall(Spec s, int test) -{ - int res; - - if ((res = execPart(s, getStringBuf(s->install), "%install", 1, test))) { - return res; + + rpmMessage(RPMMESS_NORMAL, "Executing: %s\n", name); + if (!(pid = fork())) { + execl("/bin/sh", "/bin/sh", "-e", scriptName, scriptName, NULL); + rpmError(RPMERR_SCRIPT, "Exec of %s failed (%s)", + scriptName, name); + FREE(scriptName); + return RPMERR_SCRIPT; } - if ((res = finish_filelists(s))) { - return res; + wait(&status); + if (! WIFEXITED(status) || WEXITSTATUS(status)) { + rpmError(RPMERR_SCRIPT, "Bad exit status from %s (%s)", + scriptName, name); + FREE(scriptName); + return RPMERR_SCRIPT; } - return execPart(s, getStringBuf(s->doc), "special doc", 1, test); -} + + unlink(scriptName); + FREE(scriptName); -int execClean(Spec s) -{ - return execPart(s, getStringBuf(s->clean), "%clean", 1, 0); + return 0; } -int verifyList(Spec s) +static int writeVars(Spec spec, FILE *f) { - int res; + char *arch, *os, *s; + + rpmGetArchInfo(&arch, NULL); + rpmGetOsInfo(&os, NULL); - if ((res = finish_filelists(s))) { - return res; - } - return packageBinaries(s, NULL, PACK_NOPACKAGE); + fprintf(f, "export RPM_SOURCE_DIR=\"%s\"\n", rpmGetVar(RPMVAR_SOURCEDIR)); + fprintf(f, "export RPM_BUILD_DIR=\"%s\"\n", rpmGetVar(RPMVAR_BUILDDIR)); + fprintf(f, "export RPM_DOC_DIR=\"%s\"\n", spec->docDir); + fprintf(f, "export RPM_OPT_FLAGS=\"%s\"\n", rpmGetVar(RPMVAR_OPTFLAGS)); + fprintf(f, "export RPM_ARCH=\"%s\"\n", arch); + fprintf(f, "export RPM_OS=\"%s\"\n", os); + + if (spec->buildRoot) { + fprintf(f, "export RPM_BUILD_ROOT=\"%s\"\n", spec->buildRoot); + /* This could really be checked internally */ + fprintf(f, "if [ -z \"$RPM_BUILD_ROOT\" -o -z \"`echo $RPM_BUILD_ROOT | sed -e 's#/##g'`\" ]; then\n"); + fprintf(f, " echo 'Warning: Spec contains BuildRoot: tag that is either empty or is set to \"/\"'\n"); + fprintf(f, " exit 1\n"); + fprintf(f, "fi\n"); + } + + headerGetEntry(spec->packages->header, RPMTAG_NAME, + NULL, (void **)&s, NULL); + fprintf(f, "export RPM_PACKAGE_NAME=\"%s\"\n", s); + headerGetEntry(spec->packages->header, RPMTAG_VERSION, + NULL, (void **)&s, NULL); + fprintf(f, "export RPM_PACKAGE_VERSION=\"%s\"\n", s); + headerGetEntry(spec->packages->header, RPMTAG_RELEASE, + NULL, (void **)&s, NULL); + fprintf(f, "export RPM_PACKAGE_RELEASE=\"%s\"\n", s); + + return 0; } -int doBuild(Spec s, int flags, char *passPhrase) +static void doRmSource(Spec spec) { - int test; - - test = flags & RPMBUILD_TEST; - - strcpy(build_subdir, "."); - - if (s->buildArch) { - rpmSetMachine(s->buildArch, NULL); - } - - /* We always need to parse the %prep section */ - if (execPrep(s, (flags & RPMBUILD_PREP), test)) { - return 1; - } - - if (flags & RPMBUILD_LIST) - return verifyList(s); - - if (flags & RPMBUILD_BUILD) { - if (execBuild(s, test)) { - return 1; - } - } - - if (flags & RPMBUILD_INSTALL) { - if (execInstall(s, test)) { - return 1; - } - } - - if (test) { - return 0; - } + struct Source *p; + char buf[BUFSIZ]; - markBuildTime(); - - if (flags & RPMBUILD_BINARY) { - if (packageBinaries(s, passPhrase, PACK_PACKAGE)) { - return 1; - } - if (execClean(s)) { - return 1; - } - } + unlink(spec->specFile); - if (flags & RPMBUILD_SOURCE) { - if (packageSource(s, passPhrase)) { - return 1; + p = spec->sources; + while (p) { + if (! (p->flags & RPMBUILD_ISNO)) { + sprintf(buf, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), p->source); + unlink(buf); } + p = p->next; } - - if (flags & RPMBUILD_SWEEP) { - doSweep(s); - } - - if (flags & RPMBUILD_RMSOURCE) { - doRmSource(s); - } - - return 0; } diff --git a/build/build.h b/build/build.h index aa984a5f3..62c27fe94 100644 --- a/build/build.h +++ b/build/build.h @@ -1,25 +1,16 @@ -#ifndef _BUILD_H_ -#define _BUILD_H_ - #include "spec.h" -int doBuild(Spec s, int flags, char *passPhrase); -int execPrep(Spec s, int really_exec, int test); -int execBuild(Spec s, int test); -int execInstall(Spec s, int test); -int execClean(Spec s); -int verifyList(Spec s); - -extern char build_subdir[1024]; +#define RPMBUILD_PREP (1 << 0) +#define RPMBUILD_BUILD (1 << 1) +#define RPMBUILD_INSTALL (1 << 2) +#define RPMBUILD_CLEAN (1 << 3) +#define RPMBUILD_FILECHECK (1 << 4) +#define RPMBUILD_PACKAGESOURCE (1 << 5) +#define RPMBUILD_PACKAGEBINARY (1 << 6) +#define RPMBUILD_RMSOURCE (1 << 7) +#define RPMBUILD_RMBUILD (1 << 8) +#define RPMBUILD_STRINGBUF (1 << 9) /* only for doScript() */ -#define RPMBUILD_PREP 1 -#define RPMBUILD_BUILD (1 << 1) -#define RPMBUILD_INSTALL (1 << 2) -#define RPMBUILD_BINARY (1 << 3) -#define RPMBUILD_SOURCE (1 << 4) -#define RPMBUILD_SWEEP (1 << 5) -#define RPMBUILD_LIST (1 << 6) -#define RPMBUILD_RMSOURCE (1 << 7) -#define RPMBUILD_TEST (1 << 8) +int buildSpec(Spec spec, int what, int test); -#endif _BUILD_H_ +int doScript(Spec spec, int what, char *name, StringBuf sb, int test); diff --git a/build/files.c b/build/files.c index 1159ff6f6..fe2023b40 100644 --- a/build/files.c +++ b/build/files.c @@ -1,651 +1,703 @@ -/* RPM - Copyright (C) 1995 Red Hat Software - * - * prepack.c - routines for packaging - */ - -#include "miscfn.h" - -#include <stdlib.h> -#include <unistd.h> #include <string.h> -#include <sys/stat.h> +#include <malloc.h> +#include <stdlib.h> +#include <glob.h> #include <time.h> #include "spec.h" -#include "specP.h" -#include "stringbuf.h" -#include "build.h" -#include "messages.h" -#include "md5.h" +#include "package.h" +#include "rpmlib.h" +#include "misc.h" +#include "lib/misc.h" #include "myftw.h" +#include "lib/cpio.h" #include "header.h" -#include "files.h" +#include "md5.h" #include "names.h" -#include "rpmlead.h" -#include "rpmlib.h" -#include "misc.h" +#include "messages.h" #include "macro.h" +#include "build.h" -#define BINARY_HEADER 0 -#define SOURCE_HEADER 1 - -struct file_entry { - char file[1024]; - int isdoc; - int conf; - int isspecfile; - int isghost; - int verify_flags; - char *uname; /* reference -- do not free */ - char *gname; /* reference -- do not free */ - struct stat statbuf; - struct file_entry *next; +#define MAXDOCDIR 1024 + +struct FileListRec { + char *diskName; /* get file from here */ + char *fileName; /* filename in cpio archive */ + mode_t mode; + uid_t uid; + gid_t gid; + dev_t device; + ino_t inode; + char *uname; + char *gname; + int flags; + int verifyFlags; + int size; + int mtime; + dev_t rdev; + char *lang; }; -static int add_file(struct file_entry **festack, const char *name, - int isdoc, int isconf, int isdir, int isghost, - int verify_flags, - char *Pmode, char *Uname, char *Gname, char *prefix); -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 parseForConfig(char *buf, int *conf); -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); +struct AttrRec { + char *PmodeString; + int Pmode; + char *PdirmodeString; + int Pdirmode; + char *Uname; + char *Gname; +}; -static int processFileListFailed; +struct FileList { + char *buildRoot; + char *prefix; -static void parseForDocFiles(struct PackageRec *package, char *line) -{ - if (! (line = strstr(line, "%doc"))) { - return; - } + int fileCount; + int totalFileSize; + int processingFailed; - line += 4; - if ((*line != ' ') && (*line != '\t')) { - return; - } - line += strspn(line, " \t\n"); - if ((! *line) || (*line == '/')) { - return; - } + int passedSpecialDoc; + int isSpecialDoc; - appendLineStringBuf(package->doc, "mkdir -p $DOCDIR"); - appendStringBuf(package->doc, "cp -pr "); - appendStringBuf(package->doc, line); - appendLineStringBuf(package->doc, " $DOCDIR"); -} + int isDir; + int inFtw; + int currentFlags; + int currentVerifyFlags; + struct AttrRec current; + struct AttrRec def; + int defVerifyFlags; + char *currentLang; + + /* Hard coded limit of MAXDOCDIR docdirs. */ + /* If you break it you are doing something wrong. */ + char *docDirs[MAXDOCDIR]; + int docDirCount; + + struct FileListRec *fileList; + int fileListRecsAlloced; + int fileListRecsUsed; +}; + +static int processPackageFiles(Spec spec, Package pkg, int installSpecialDoc); +static void freeFileList(struct FileListRec *fileList, int count); +static int compareFileListRecs(const void *ap, const void *bp); +static int isDoc(struct FileList *fl, char *fileName); +static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName); +static int addFile(struct FileList *fl, char *name, struct stat *statp); +static int parseForSimple(Spec spec, Package pkg, char *buf, + struct FileList *fl, char **fileName); +static int parseForVerify(char *buf, struct FileList *fl); +static int parseForLang(char *buf, struct FileList *fl); +static int parseForAttr(char *buf, struct FileList *fl); +static int parseForConfig(char *buf, struct FileList *fl); +static int myGlobPatternP(char *pattern); +static int glob_error(const char *foo, int bar); +static void timeCheck(int tc, Header h); +static void genCpioListAndHeader(struct FileList *fl, + struct cpioFileMapping **cpioList, + int *cpioCount, Header h, int isSrc); -int finish_filelists(Spec spec) +int processSourceFiles(Spec spec) { - char buf[1024]; - FILE *file; - struct PackageRec *pr = spec->packages; - char *s, **files, **line; - char *version, *release, *packageVersion, *docs, *name; - - headerGetEntry(spec->packages->header, RPMTAG_VERSION, NULL, - (void *) &version, NULL); - headerGetEntry(spec->packages->header, RPMTAG_RELEASE, NULL, - (void *) &release, NULL); - - while (pr) { - if (pr->fileFile) { - sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR), - build_subdir, pr->fileFile); - rpmMessage(RPMMESS_DEBUG, "Reading file names from: %s\n", buf); - if ((file = fopen(buf, "r")) == NULL) { - rpmError(RPMERR_BADSPEC, "unable to open filelist: %s\n", buf); - return(RPMERR_BADSPEC); + struct Source *srcPtr; + char buf[BUFSIZ]; + StringBuf sourceFiles; + int x, isSpec = 1; + struct FileList fl; + char *s, **files, **fp, *fn; + struct stat sb; + HeaderIterator hi; + int tag, type, count; + void * ptr; + + sourceFiles = newStringBuf(); + spec->sourceHeader = headerNew(); + + /* Only specific tags are added to the source package header */ + hi = headerInitIterator(spec->packages->header); + while (headerNextIterator(hi, &tag, &type, &ptr, &count)) { + switch (tag) { + case RPMTAG_NAME: + case RPMTAG_VERSION: + case RPMTAG_RELEASE: + case RPMTAG_SERIAL: + case RPMTAG_SUMMARY: + case RPMTAG_DESCRIPTION: + case RPMTAG_PACKAGER: + case RPMTAG_DISTRIBUTION: + case RPMTAG_VENDOR: + case RPMTAG_COPYRIGHT: + case RPMTAG_GROUP: + case RPMTAG_OS: + case RPMTAG_ARCH: + case RPMTAG_CHANGELOGTIME: + case RPMTAG_CHANGELOGNAME: + case RPMTAG_CHANGELOGTEXT: + case RPMTAG_URL: + headerAddEntry(spec->sourceHeader, tag, type, ptr, count); + break; + default: + /* do not copy */ + break; + } + if (type == RPM_STRING_ARRAY_TYPE) { + FREE(ptr); + } + } + headerFreeIterator(hi); + + /* Construct the file list and source entries */ + appendLineStringBuf(sourceFiles, spec->specFile); + srcPtr = spec->sources; + while (srcPtr) { + if (srcPtr->flags & RPMBUILD_ISSOURCE) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_SOURCE, + RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); + if (srcPtr->flags & RPMBUILD_ISNO) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOSOURCE, + RPM_INT32_TYPE, &srcPtr->num, 1); } - while (fgets(buf, sizeof(buf), file)) { - expandMacros(buf); - appendStringBuf(pr->filelist, buf); + } + if (srcPtr->flags & RPMBUILD_ISPATCH) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_PATCH, + RPM_STRING_ARRAY_TYPE, &srcPtr->source, 1); + if (srcPtr->flags & RPMBUILD_ISNO) { + headerAddOrAppendEntry(spec->sourceHeader, RPMTAG_NOPATCH, + RPM_INT32_TYPE, &srcPtr->num, 1); } - fclose(file); } + sprintf(buf, "%s%s/%s", + srcPtr->flags & RPMBUILD_ISNO ? "!" : "", + rpmGetVar(RPMVAR_SOURCEDIR), srcPtr->source); + appendLineStringBuf(sourceFiles, buf); + srcPtr = srcPtr->next; + } + + spec->sourceCpioList = NULL; + spec->sourceCpioCount = 0; - /* parse for %doc wierdness */ - s = getStringBuf(pr->filelist); - files = splitString(s, strlen(s), '\n'); - line = files; - while (*line) { - parseForDocFiles(pr, *line); - line++; + fl.fileList = malloc((spec->numSources + 1) * sizeof(struct FileListRec)); + fl.processingFailed = 0; + fl.fileListRecsUsed = 0; + fl.totalFileSize = 0; + fl.prefix = NULL; + + s = getStringBuf(sourceFiles); + files = splitString(s, strlen(s), '\n'); + fp = files; + + /* The first source file is the spec file */ + x = 0; + while (*fp) { + s = *fp; + SKIPSPACE(s); + if (! *s) { + fp++; continue; } - freeSplitString(files); - /* Handle subpackage version overrides */ - if (!headerGetEntry(pr->header, RPMTAG_VERSION, NULL, - (void *) &packageVersion, NULL)) { - packageVersion = version; + fl.fileList[x].flags = isSpec ? RPMFILE_SPECFILE : 0; + /* files with leading ! are no source files */ + if (*s == '!') { + fl.fileList[x].flags |= RPMFILE_GHOST; + s++; + } + fl.fileList[x].diskName = strdup(s); + fn = strrchr(s, '/'); + if (fn) { + fn++; + } else { + fn = s; } + fl.fileList[x].fileName = strdup(fn); + fl.fileList[x].verifyFlags = RPMVERIFY_ALL; + lstat(s, &sb); + fl.fileList[x].mode = sb.st_mode; + fl.fileList[x].uid = sb.st_uid; + fl.fileList[x].gid = sb.st_gid; + fl.fileList[x].uname = getUname(sb.st_uid); + fl.fileList[x].gname = getGname(sb.st_gid); + fl.fileList[x].size = sb.st_size; + fl.fileList[x].mtime = sb.st_mtime; + fl.fileList[x].rdev = sb.st_rdev; + fl.fileList[x].device = sb.st_dev; + fl.fileList[x].inode = sb.st_ino; + fl.fileList[x].lang = strdup(""); + + fl.totalFileSize += sb.st_size; + + if (! (fl.fileList[x].uname && fl.fileList[x].gname)) { + rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", s); + fl.processingFailed = 1; + } + + isSpec = 0; + fp++; + x++; + } + fl.fileListRecsUsed = x; + FREE(files); - /* Generate the doc script */ - appendStringBuf(spec->doc, "DOCDIR=$RPM_ROOT_DIR/$RPM_DOC_DIR/"); - headerGetEntry(pr->header, RPMTAG_NAME, NULL, (void *) &name, NULL); - sprintf(buf, "%s-%s", name, packageVersion); - appendLineStringBuf(spec->doc, buf); - docs = getStringBuf(pr->doc); - if (*docs) { - appendLineStringBuf(spec->doc, "rm -rf $DOCDIR"); - appendLineStringBuf(spec->doc, docs); + if (! fl.processingFailed) { + genCpioListAndHeader(&fl, &(spec->sourceCpioList), + &(spec->sourceCpioCount), spec->sourceHeader, 1); + } + + freeStringBuf(sourceFiles); + freeFileList(fl.fileList, fl.fileListRecsUsed); + return fl.processingFailed; +} + +int processBinaryFiles(Spec spec, int installSpecialDoc) +{ + Package pkg; + int rc; + + pkg = spec->packages; + while (pkg) { + if (!pkg->fileList) { + pkg = pkg->next; + continue; + } + + if ((rc = processPackageFiles(spec, pkg, installSpecialDoc))) { + return rc; } - pr = pr->next; + pkg = pkg->next; } return 0; } -int process_filelist(Header header, struct PackageRec *pr, - StringBuf sb, int *size, char *name, - char *version, char *release, int type, - char *prefix, char *specFile) +static int processPackageFiles(Spec spec, Package pkg, int installSpecialDoc) { - char buf[1024]; - char **files, **fp; - struct file_entry *fes, *fest; - struct file_entry **file_entry_array; - int isdoc, conf, isdir, verify_flags, isghost; - 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; - int tc; - char *tcs; - int currentTime; + struct FileList fl; + char *s, **files, **fp, *fileName; + char buf[BUFSIZ]; + FILE *f; - processFileListFailed = 0; - fes = NULL; - *size = 0; + struct AttrRec specialDocAttrRec; + char *specialDoc = NULL; + + pkg->cpioList = NULL; + pkg->cpioCount = 0; + + if (pkg->fileFile) { + sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR), + spec->buildSubdir, pkg->fileFile); + if ((f = fopen(buf, "r")) == NULL) { + rpmError(RPMERR_BADFILENAME, + "Could not open %%files file: %s", pkg->fileFile); + return RPMERR_BADFILENAME; + } + while (fgets(buf, sizeof(buf), f)) { + expandMacros(&spec->macros, buf); + appendStringBuf(pkg->fileList, buf); + } + fclose(f); + } + + /* Init the file list structure */ + + fl.buildRoot = spec->buildRoot ? spec->buildRoot : ""; + if (headerGetEntry(pkg->header, RPMTAG_DEFAULTPREFIX, + NULL, (void *)&fl.prefix, NULL)) { + fl.prefix = strdup(fl.prefix); + } else { + fl.prefix = NULL; + } - resetDocdir(); + fl.fileCount = 0; + fl.totalFileSize = 0; + fl.processingFailed = 0; - str = getStringBuf(sb); - files = splitString(str, strlen(str), '\n'); + fl.passedSpecialDoc = 0; + + fl.current.PmodeString = NULL; + fl.current.PdirmodeString = NULL; + fl.current.Uname = NULL; + fl.current.Gname = NULL; + fl.def.PmodeString = NULL; + fl.def.PdirmodeString = NULL; + fl.def.Uname = NULL; + fl.def.Gname = NULL; + fl.currentLang = NULL; + + fl.defVerifyFlags = RPMVERIFY_ALL; + + fl.docDirCount = 0; + fl.docDirs[fl.docDirCount++] = strdup("/usr/doc"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/man"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/info"); + fl.docDirs[fl.docDirCount++] = strdup("/usr/X11R6/man"); + fl.docDirs[fl.docDirCount++] = strdup(spec->docDir); + + fl.fileList = NULL; + fl.fileListRecsAlloced = 0; + fl.fileListRecsUsed = 0; + + s = getStringBuf(pkg->fileList); + files = splitString(s, strlen(s), '\n'); fp = files; while (*fp) { - strcpy(buf, *fp); /* temp copy */ - isdoc = 0; - special_doc = 0; - conf = 0; - isdir = 0; - isghost = 0; - if (currPmode) { - free (currPmode); - currPmode = NULL; - } - if (currUname) { - free (currUname); - currUname = NULL; - } - if (currGname) { - free (currGname); - currGname = NULL; - } - verify_flags = RPMVERIFY_ALL; - filename = NULL; - - /* First preparse buf for %verify() */ - if (parseForVerify(buf, &verify_flags)) { - processFileListFailed = 1; + s = *fp; + SKIPSPACE(s); + if (! *s) { fp++; continue; } + fileName = NULL; + strcpy(buf, s); - /* Next parse for %attr() */ - if (parseForAttr(buf, &currPmode, &currUname, &currGname)) { - processFileListFailed = 1; - fp++; continue; + /* Reset for a new line in %files */ + fl.isDir = 0; + fl.inFtw = 0; + fl.currentFlags = 0; + fl.currentVerifyFlags = fl.defVerifyFlags; + fl.current.Pmode = fl.def.Pmode; + fl.current.Pdirmode = fl.def.Pdirmode; + fl.isSpecialDoc = 0; + FREE(fl.current.PmodeString); + FREE(fl.current.PdirmodeString); + FREE(fl.current.Uname); + FREE(fl.current.Gname); + FREE(fl.currentLang); + if (fl.def.PmodeString) { + fl.current.PmodeString = strdup(fl.def.PmodeString); + } + if (fl.def.PdirmodeString) { + fl.current.PdirmodeString = strdup(fl.def.PdirmodeString); + } + if (fl.def.Uname) { + fl.current.Uname = strdup(fl.def.Uname); + } + if (fl.def.Gname) { + fl.current.Gname = strdup(fl.def.Gname); } - /* Then parse for %config or %config() */ - if (parseForConfig(buf, &conf)) { - processFileListFailed = 1; + if (parseForVerify(buf, &fl)) { fp++; continue; } - - 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, "%dir")) { - isdir = 1; - } else if (!strcmp(s, "%ghost")) { - isghost = 1; - } else { - if (filename) { - /* We already got a file -- error */ - rpmError(RPMERR_BADSPEC, - "Two files on one line: %s", filename); - processFileListFailed = 1; - } - if (*s != '/') { - if (isdoc) { - special_doc = 1; - } else { - /* not in %doc, does not begin with / -- error */ - rpmError(RPMERR_BADSPEC, - "File must begin with \"/\": %s", s); - processFileListFailed = 1; - } - } else { - filename = s; - } - } - s = strtok(NULL, " \t\n"); + if (parseForAttr(buf, &fl)) { + fp++; continue; } - if (special_doc) { - if (passed_special_doc) { - fp++; - continue; - } else { - if (filename || conf || isdir || isghost) { - rpmError(RPMERR_BADSPEC, - "Can't mix special %%doc with other forms: %s", fp); - processFileListFailed = 1; - fp++; continue; - } - sprintf(buf, "%s/%s-%s", rpmGetVar(RPMVAR_DEFAULTDOCDIR), - name, version); - filename = buf; - passed_special_doc = 1; - } + if (parseForConfig(buf, &fl)) { + fp++; continue; } - if (! filename) { - fp++; - continue; + if (parseForLang(buf, &fl)) { + fp++; continue; + } + if (parseForSimple(spec, pkg, buf, &fl, &fileName)) { + fp++; continue; + } + if (! fileName) { + fp++; continue; } - if (type == RPMLEAD_BINARY) { - /* check that file starts with leading "/" */ - if (*filename != '/') { - rpmError(RPMERR_BADSPEC, - "File needs leading \"/\": %s", filename); - processFileListFailed = 1; - fp++; continue; + if (fl.isSpecialDoc) { + /* Save this stuff for last */ + specialDoc = strdup(fileName); + specialDocAttrRec = fl.current; + if (specialDocAttrRec.PmodeString) { + specialDocAttrRec.PmodeString = + strdup(specialDocAttrRec.PmodeString); } - - if (glob_pattern_p(filename)) { - char fullname[1024]; - - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), filename); - } else { - strcpy(fullname, filename); - } - - if (glob(fullname, 0, glob_error, &glob_result) || - (glob_result.gl_pathc < 1)) { - rpmError(RPMERR_BADSPEC, "No matches: %s", fullname); - processFileListFailed = 1; - globfree(&glob_result); - fp++; continue; - } - - c = 0; - x = 0; - while (x < glob_result.gl_pathc) { - int offset = strlen(rpmGetVar(RPMVAR_ROOT) ? : ""); - c += add_file(&fes, &(glob_result.gl_pathv[x][offset]), - isdoc, conf, isdir, isghost, verify_flags, - currPmode, currUname, currGname, prefix); - x++; - } - globfree(&glob_result); - } else { - c = add_file(&fes, filename, isdoc, conf, isdir, isghost, - verify_flags, currPmode, currUname, - currGname, prefix); + if (specialDocAttrRec.PdirmodeString) { + specialDocAttrRec.PdirmodeString = + strdup(specialDocAttrRec.PdirmodeString); } - } else { - /* Source package are the simple case */ - fest = malloc(sizeof(struct file_entry)); - fest->isdoc = 0; - fest->conf = 0; - fest->isghost = 0; - if (!strcmp(filename, specFile)) { - fest->isspecfile = 1; - } else { - fest->isspecfile = 0; + if (specialDocAttrRec.Uname) { + specialDocAttrRec.Uname = strdup(specialDocAttrRec.Uname); } - 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); - if (! (fest->uname && fest->gname)) { - rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", filename); - fest->uname = ""; - fest->gname = ""; - processFileListFailed = 1; + if (specialDocAttrRec.Gname) { + specialDocAttrRec.Gname = strdup(specialDocAttrRec.Gname); } - strcpy(fest->file, filename); - fest->next = fes; - fes = fest; - c = 1; - } - - if (! c) { - rpmError(RPMERR_BADSPEC, "File not found: %s", filename); - processFileListFailed = 1; + } else { + processBinaryFile(pkg, &fl, fileName); } - 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); - - /* Do timecheck */ - tc = 0; - currentTime = time(NULL); - if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) { - tc = strtoul(tcs, NULL, 10); + /* Now process special doc, if there is one */ + if (specialDoc) { + if (installSpecialDoc) { + doScript(spec, RPMBUILD_STRINGBUF, "%doc", pkg->specialDoc, 0); } + fl.current = specialDocAttrRec; + processBinaryFile(pkg, &fl, specialDoc); + FREE(specialDoc); + FREE(specialDocAttrRec.PmodeString); + FREE(specialDocAttrRec.PdirmodeString); + FREE(specialDocAttrRec.Uname); + FREE(specialDocAttrRec.Gname); + } - c = 0; - while (c < count) { - fest = file_entry_array[c]; - if (type == RPMLEAD_BINARY) { - x = strlen(fest->file) - 1; - if (x && fest->file[x] == '/') { - fest->file[x] = '\0'; - } - fileList[c] = fest->file; - } else { - fileList[c] = strrchr(fest->file, '/') + 1; - } - if ((c > 0) && !strcmp(fileList[c], fileList[c-1])) { - rpmError(RPMERR_BADSPEC, "File listed twice: %s", fileList[c]); - processFileListFailed = 1; - } - - fileUnameList[c] = fest->uname; - fileGnameList[c] = fest->gname; - *size += fest->statbuf.st_size; - if (S_ISREG(fest->statbuf.st_mode)) { - if ((type == RPMLEAD_BINARY) && - rpmGetVar(RPMVAR_ROOT)) { - sprintf(buf, "%s%s", rpmGetVar(RPMVAR_ROOT), fest->file); - } else { - strcpy(buf, fest->file); - } - mdfile(buf, buf); - fileMD5List[c] = strdup(buf); - rpmMessage(RPMMESS_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; - - /* Do timecheck */ - if (tc && (type == RPMLEAD_BINARY)) { - if (currentTime - fest->statbuf.st_mtime > tc) { - rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n", - fest->file); - } - } - - fileFlagsList[c] = 0; - if (isDoc(fest->file)) - fileFlagsList[c] |= RPMFILE_DOC; - if (fest->isdoc) - fileFlagsList[c] |= RPMFILE_DOC; - if (fest->isghost) - fileFlagsList[c] |= RPMFILE_GHOST; - if (fest->conf && !(fest->statbuf.st_mode & S_IFDIR)) - fileFlagsList[c] |= fest->conf; - if (fest->isspecfile) - fileFlagsList[c] |= RPMFILE_SPECFILE; - - fileModesList[c] = fest->statbuf.st_mode; - fileRDevsList[c] = fest->statbuf.st_rdev; - if (! fest->isghost) { - fileVerifyFlagsList[c] = fest->verify_flags; - } else { - fileVerifyFlagsList[c] = fest->verify_flags & - ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | - RPMVERIFY_LINKTO | RPMVERIFY_MTIME); - } + FREE(files); - if (S_ISLNK(fest->statbuf.st_mode)) { - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(buf, "%s%s", rpmGetVar(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; - headerAddEntry(header, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, fileList, c); - headerAddEntry(header, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE, - fileLinktoList, c); - headerAddEntry(header, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE, fileMD5List, c); - headerAddEntry(header, RPMTAG_FILESIZES, RPM_INT32_TYPE, fileSizeList, c); - headerAddEntry(header, RPMTAG_FILEUIDS, RPM_INT32_TYPE, fileUIDList, c); - headerAddEntry(header, RPMTAG_FILEGIDS, RPM_INT32_TYPE, fileGIDList, c); - headerAddEntry(header, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE, - fileUnameList, c); - headerAddEntry(header, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE, - fileGnameList, c); - headerAddEntry(header, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, fileMtimesList, c); - headerAddEntry(header, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, fileFlagsList, c); - headerAddEntry(header, RPMTAG_FILEMODES, RPM_INT16_TYPE, fileModesList, c); - headerAddEntry(header, RPMTAG_FILERDEVS, RPM_INT16_TYPE, fileRDevsList, c); - headerAddEntry(header, RPMTAG_FILEVERIFYFLAGS, RPM_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; + if (! fl.processingFailed) { + genCpioListAndHeader(&fl, &(pkg->cpioList), &(pkg->cpioCount), + pkg->header, 0); + + if (spec->timeCheck) { + timeCheck(spec->timeCheck, pkg->header); } } - freeSplitString(files); - return processFileListFailed; + /* Clean up */ + FREE(fl.prefix); + FREE(fl.current.PmodeString); + FREE(fl.current.PdirmodeString); + FREE(fl.current.Uname); + FREE(fl.current.Gname); + FREE(fl.def.PmodeString); + FREE(fl.def.PdirmodeString); + FREE(fl.def.Uname); + FREE(fl.def.Gname); + FREE(fl.currentLang); + freeFileList(fl.fileList, fl.fileListRecsUsed); + while (fl.docDirCount--) { + FREE(fl.docDirs[fl.docDirCount]); + } + return fl.processingFailed; } -/*************************************************************/ -/* */ -/* misc */ -/* */ -/*************************************************************/ - -static int compare_fe(const void *ap, const void *bp) +static void timeCheck(int tc, Header h) { - char *a, *b; + int *mtime; + char **file; + int count, x, currentTime; - a = (*(struct file_entry **)ap)->file; - b = (*(struct file_entry **)bp)->file; + headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &file, &count); + headerGetEntry(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtime, NULL); - return strcmp(a, b); + currentTime = time(NULL); + + x = 0; + while (x < count) { + if (currentTime - mtime[x] > tc) { + rpmMessage(RPMMESS_WARNING, "TIMECHECK failure: %s\n", file[x]); + } + x++; + } } -/*************************************************************/ -/* */ -/* Doc dir stuff */ -/* */ -/*************************************************************/ - -/* XXX hard coded limit -- only 1024 %docdir allowed */ -static char *docdirs[1024]; -static int docdir_count; +static void genCpioListAndHeader(struct FileList *fl, + struct cpioFileMapping **cpioList, + int *cpioCount, Header h, int isSrc) +{ + int skipLen = 0; + struct FileListRec *p; + int count; + struct cpioFileMapping *cpioListPtr; + char *s, buf[BUFSIZ]; + + /* Sort the big list */ + qsort(fl->fileList, fl->fileListRecsUsed, + sizeof(*(fl->fileList)), compareFileListRecs); + + /* Generate the cpio list and the header */ + if (! isSrc) { + if (fl->prefix) { + skipLen = 1 + strlen(fl->prefix); + } else { + skipLen = 1; + } + } + *cpioList = malloc(sizeof(**cpioList) * fl->fileListRecsUsed); + *cpioCount = 0; + cpioListPtr = *cpioList; + p = fl->fileList; + count = fl->fileListRecsUsed; + while (count) { + if ((count > 1) && !strcmp(p->fileName, p[1].fileName)) { + rpmError(RPMERR_BADSPEC, "File listed twice: %s", p->fileName); + fl->processingFailed = 1; + } + + /* Make the cpio list */ + if (! (p->flags & RPMFILE_GHOST)) { + cpioListPtr->fsPath = strdup(p->diskName); + cpioListPtr->archivePath = strdup(p->fileName + skipLen); + cpioListPtr->finalMode = p->mode; + cpioListPtr->finalUid = p->uid; + cpioListPtr->finalGid = p->gid; + cpioListPtr->mapFlags = CPIO_MAP_PATH | CPIO_MAP_MODE | + CPIO_MAP_UID | CPIO_MAP_GID; + cpioListPtr++; + (*cpioCount)++; + } + + /* Make the header */ + headerAddOrAppendEntry(h, RPMTAG_FILENAMES, RPM_STRING_ARRAY_TYPE, + &(p->fileName), 1); + headerAddOrAppendEntry(h, RPMTAG_FILESIZES, RPM_INT32_TYPE, + &(p->size), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEUSERNAME, RPM_STRING_ARRAY_TYPE, + &(p->uname), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEGROUPNAME, RPM_STRING_ARRAY_TYPE, + &(p->gname), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEMTIMES, RPM_INT32_TYPE, + &(p->mtime), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEMODES, RPM_INT16_TYPE, + &(p->mode), 1); + headerAddOrAppendEntry(h, RPMTAG_FILERDEVS, RPM_INT16_TYPE, + &(p->rdev), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEDEVICES, RPM_INT32_TYPE, + &(p->device), 1); + headerAddOrAppendEntry(h, RPMTAG_FILEINODES, RPM_INT32_TYPE, + &(p->inode), 1); + headerAddOrAppendEntry(h, RPMTAG_FILELANGS, RPM_STRING_ARRAY_TYPE, + &(p->lang), 1); + + /* We used to add these, but they should not be needed */ + /* headerAddOrAppendEntry(h, RPMTAG_FILEUIDS, + * RPM_INT32_TYPE, &(p->uid), 1); + * headerAddOrAppendEntry(h, RPMTAG_FILEGIDS, + * RPM_INT32_TYPE, &(p->gid), 1); + */ + + buf[0] = '\0'; + s = buf; + if (S_ISREG(p->mode)) { + mdfile(p->diskName, buf); + } + headerAddOrAppendEntry(h, RPMTAG_FILEMD5S, RPM_STRING_ARRAY_TYPE, + &s, 1); + + buf[0] = '\0'; + s = buf; + if (S_ISLNK(p->mode)) { + buf[readlink(p->diskName, buf, BUFSIZ)] = '\0'; + } + headerAddOrAppendEntry(h, RPMTAG_FILELINKTOS, RPM_STRING_ARRAY_TYPE, + &s, 1); + + if (p->flags & RPMFILE_GHOST) { + p->verifyFlags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | + RPMVERIFY_LINKTO | RPMVERIFY_MTIME); + } + headerAddOrAppendEntry(h, RPMTAG_FILEVERIFYFLAGS, RPM_INT32_TYPE, + &(p->verifyFlags), 1); + + if (!isSrc && isDoc(fl, p->fileName)) { + p->flags |= RPMFILE_DOC; + } + if (p->mode & S_IFDIR) { + p->flags &= ~RPMFILE_CONFIG; + p->flags &= ~RPMFILE_DOC; + } + headerAddOrAppendEntry(h, RPMTAG_FILEFLAGS, RPM_INT32_TYPE, + &(p->flags), 1); + + p++; + count--; + } + headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, + &(fl->totalFileSize), 1); +} -static void resetDocdir(void) +static void freeFileList(struct FileListRec *fileList, int count) { - 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"); - docdirs[docdir_count++] = strdup("/usr/X11R6/man"); + while (count--) { + FREE(fileList[count].diskName); + FREE(fileList[count].fileName); + FREE(fileList[count].lang); + } + FREE(fileList); } -static void addDocdir(char *dirname) +void freeCpioList(struct cpioFileMapping *cpioList, int cpioCount) { - if (docdir_count == 1024) { - fprintf(stderr, "RPMERR_INTERNAL: Hit limit in addDocdir()\n"); - exit(RPMERR_INTERNAL); + struct cpioFileMapping *p = cpioList; + + while (cpioCount--) { + rpmMessage(RPMMESS_DEBUG, "archive = %s, fs = %s\n", + p->archivePath, p->fsPath); + FREE(p->archivePath); + FREE(p->fsPath); + p++; } - docdirs[docdir_count++] = strdup(dirname); + FREE(cpioList); +} + +static int compareFileListRecs(const void *ap, const void *bp) +{ + char *a, *b; + + a = ((struct FileListRec *)ap)->fileName; + b = ((struct FileListRec *)bp)->fileName; + + return strcmp(a, b); } -static int isDoc(char *filename) +static int isDoc(struct FileList *fl, char *fileName) { - int x = 0; + int x = fl->docDirCount; - while (x < docdir_count) { - if (strstr(filename, docdirs[x]) == filename) { + while (x--) { + if (strstr(fileName, fl->docDirs[x]) == fileName) { return 1; } - x++; } return 0; } -/*************************************************************/ -/* */ -/* File stating / tree walk */ -/* */ -/*************************************************************/ - -/* Need a bunch of globals to keep track of things in ftw() */ -static int Gisdoc; -static int Gisghost; -static int Gconf; -static int Gverify_flags; -static int Gcount; -static char *GPmode; -static char *GUname; -static char *GGname; -static struct file_entry **Gfestack; -static char *Gprefix; - -static int add_file(struct file_entry **festack, const char *name, - int isdoc, int conf, int isdir, int isghost, - int verify_flags, - char *Pmode, char *Uname, char *Gname, char *prefix) +static int processBinaryFile(Package pkg, struct FileList *fl, char *fileName) +{ + char fullname[BUFSIZ]; + glob_t glob_result; + int x, offset, rc = 0; + + /* check that file starts with leading "/" */ + if (*fileName != '/') { + rpmError(RPMERR_BADSPEC, "File needs leading \"/\": %s", *fileName); + fl->processingFailed = 1; + return 1; + } + + if (myGlobPatternP(fileName)) { + if (fl->buildRoot) { + sprintf(fullname, "%s%s", fl->buildRoot, fileName); + offset = strlen(fl->buildRoot); + } else { + strcpy(fullname, fileName); + offset = 0; + } + + if (glob(fullname, 0, glob_error, &glob_result) || + (glob_result.gl_pathc < 1)) { + rpmError(RPMERR_BADSPEC, "File not found: %s", fullname); + fl->processingFailed = 1; + globfree(&glob_result); + return 1; + } + + x = 0; + while (x < glob_result.gl_pathc) { + rc = addFile(fl, &(glob_result.gl_pathv[x][offset]), NULL); + x++; + } + globfree(&glob_result); + } else { + rc = addFile(fl, fileName, NULL); + } + + return rc; +} + +static int addFile(struct FileList *fl, char *name, struct stat *statp) { - struct file_entry *p; - char *copyTo, copied; - const char *prefixTest, *prefixPtr; - const char *copyFrom; - char fullname[1024]; - int mode; - - /* Set these up for ftw() */ - Gfestack = festack; - Gisdoc = isdoc; - Gconf = conf; - Gisghost = isghost; - Gverify_flags = verify_flags; - GPmode = Pmode; - GUname = Uname; - GGname = Gname; - Gprefix = prefix; - - p = malloc(sizeof(struct file_entry)); - - copyTo = p->file; + char fileName[BUFSIZ]; + char diskName[BUFSIZ]; + char *copyTo, *copyFrom, copied; + char *prefixTest, *prefixPtr; + struct stat statbuf; + int_16 fileMode; + int fileUid, fileGid; + char *fileUname, *fileGname; + + /* Copy to fileName, eliminate duplicate "/" and trailing "/" */ + copyTo = fileName; copied = '\0'; copyFrom = name; while (*copyFrom) { @@ -655,178 +707,325 @@ static int add_file(struct file_entry **festack, const char *name, copyFrom++; } *copyTo = '\0'; + copyTo--; + if ((copyTo != fileName) && (*copyTo == '/')) { + *copyTo = '\0'; + } - p->isdoc = isdoc; - p->conf = conf; - p->isghost = isghost; - p->isspecfile = 0; /* source packages are done by hand */ - p->verify_flags = verify_flags; - if (rpmGetVar(RPMVAR_ROOT)) { - sprintf(fullname, "%s%s", rpmGetVar(RPMVAR_ROOT), name); + if (fl->inFtw) { + /* Any buildRoot is already prepended */ + strcpy(diskName, fileName); + if (fl->buildRoot) { + strcpy(fileName, diskName + strlen(fl->buildRoot)); + } } else { - strcpy(fullname, name); + if (fl->buildRoot) { + sprintf(diskName, "%s%s", fl->buildRoot, fileName); + } else { + strcpy(diskName, fileName); + } } /* If we are using a prefix, validate the file */ - if (prefix) { - prefixTest = name; - prefixPtr = prefix; - while (*prefixTest == '/') { - prefixTest++; /* Skip leading "/" */ - } + if (!fl->inFtw && fl->prefix) { + prefixTest = fileName; + prefixPtr = fl->prefix; + while (*prefixPtr && *prefixTest && (*prefixTest == *prefixPtr)) { prefixPtr++; prefixTest++; } - if (*prefixPtr) { + if (*prefixPtr || (*prefixTest && *prefixTest != '/')) { rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s", - prefix, name); - return 0; + fl->prefix, fileName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } } - /* OK, finally stat() the file */ - 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 (! statp) { + statp = &statbuf; + if (lstat(diskName, statp)) { + rpmError(RPMERR_BADSPEC, "File not found: %s", diskName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } } - 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 (! (p->uname && p->gname)) { - rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", fullname); - p->uname = ""; - p->gname = ""; - return 0; - } - - if ((! isdir) && S_ISDIR(p->statbuf.st_mode)) { - /* This means we need to descend with ftw() */ - Gcount = 0; - + if ((! fl->isDir) && S_ISDIR(statp->st_mode)) { /* 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); + /* It also has better callback support. */ - free(p); - - return Gcount; + fl->inFtw = 1; /* Flag to indicate file has buildRoot prefixed */ + fl->isDir = 1; /* Keep it from following myftw() again */ + myftw(diskName, 16, addFile, fl); + fl->isDir = 0; + fl->inFtw = 0; } else { - /* Link it in */ - p->next = *festack; - *festack = p; + fileMode = statp->st_mode; + fileUid = statp->st_uid; + fileGid = statp->st_gid; + + /* %attr ? */ + if (S_ISDIR(fileMode) && fl->current.PdirmodeString) { + if (fl->current.PdirmodeString[0] != '-') { + fileMode &= S_IFMT; + fileMode |= fl->current.Pdirmode; + } + } else { + if (fl->current.PmodeString) { + fileMode &= S_IFMT; + fileMode |= fl->current.Pmode; + } + } + if (fl->current.Uname) { + fileUname = getUnameS(fl->current.Uname); + } else { + fileUname = getUname(fileUid); + } + if (fl->current.Gname) { + fileGname = getGnameS(fl->current.Gname); + } else { + fileGname = getGname(fileGid); + } + + if (! (fileUname && fileGname)) { + rpmError(RPMERR_BADSPEC, "Bad owner/group: %s\n", diskName); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + + rpmMessage(RPMMESS_DEBUG, "File %d: %s\n", fl->fileCount, fileName); + + /* Add to the file list */ + if (fl->fileListRecsUsed == fl->fileListRecsAlloced) { + fl->fileListRecsAlloced += 128; + fl->fileList = realloc(fl->fileList, + fl->fileListRecsAlloced * + sizeof(*(fl->fileList))); + } + + fl->fileList[fl->fileListRecsUsed].fileName = strdup(fileName); + fl->fileList[fl->fileListRecsUsed].diskName = strdup(diskName); + fl->fileList[fl->fileListRecsUsed].mode = fileMode; + fl->fileList[fl->fileListRecsUsed].uid = fileUid; + fl->fileList[fl->fileListRecsUsed].gid = fileGid; + fl->fileList[fl->fileListRecsUsed].uname = fileUname; + fl->fileList[fl->fileListRecsUsed].gname = fileGname; + + fl->fileList[fl->fileListRecsUsed].lang = + strdup(fl->currentLang ? fl->currentLang : ""); + + fl->fileList[fl->fileListRecsUsed].flags = fl->currentFlags; + fl->fileList[fl->fileListRecsUsed].verifyFlags = + fl->currentVerifyFlags; + fl->fileList[fl->fileListRecsUsed].size = statp->st_size; + fl->fileList[fl->fileListRecsUsed].mtime = statp->st_mtime; + fl->fileList[fl->fileListRecsUsed].rdev = statp->st_rdev; + fl->fileList[fl->fileListRecsUsed].device = statp->st_dev; + fl->fileList[fl->fileListRecsUsed].inode = statp->st_ino; + fl->fileListRecsUsed++; + + fl->totalFileSize += statp->st_size; + fl->fileCount++; + } - rpmMessage(RPMMESS_DEBUG, "ADDING: %s\n", name); + return 0; +} - /* return number of entries added */ - return 1; +static int parseForSimple(Spec spec, Package pkg, char *buf, + struct FileList *fl, char **fileName) +{ + char *s; + int res, specialDoc = 0; + char *name, *version; + char specialDocBuf[BUFSIZ]; + + specialDocBuf[0] = '\0'; + *fileName = NULL; + res = 0; + s = strtok(buf, " \t\n"); + while (s) { + if (!strcmp(s, "%docdir")) { + s = strtok(NULL, " \t\n"); + if (fl->docDirCount == MAXDOCDIR) { + rpmError(RPMERR_INTERNAL, "Hit limit for %%docdir"); + fl->processingFailed = 1; + res = 1; + } + fl->docDirs[fl->docDirCount++] = strdup(s); + if (strtok(NULL, " \t\n")) { + rpmError(RPMERR_INTERNAL, "Only one arg for %%docdir"); + fl->processingFailed = 1; + res = 1; + } + break; + } else if (!strcmp(s, "%doc")) { + fl->currentFlags |= RPMFILE_DOC; + } else if (!strcmp(s, "%ghost")) { + fl->currentFlags |= RPMFILE_GHOST; + } else if (!strcmp(s, "%dir")) { + fl->isDir = 1; + } else { + if (*fileName) { + /* We already got a file -- error */ + rpmError(RPMERR_BADSPEC, + "Two files on one line: %s", *fileName); + fl->processingFailed = 1; + res = 1; + } + if (*s != '/') { + if (fl->currentFlags & RPMFILE_DOC) { + specialDoc = 1; + strcat(specialDocBuf, " "); + strcat(specialDocBuf, s); + } else { + /* not in %doc, does not begin with / -- error */ + rpmError(RPMERR_BADSPEC, + "File must begin with \"/\": %s", s); + fl->processingFailed = 1; + res = 1; + } + } else { + *fileName = s; + } + } + s = strtok(NULL, " \t\n"); + } + + if (specialDoc) { + if (*fileName || (fl->currentFlags & ~(RPMFILE_DOC))) { + rpmError(RPMERR_BADSPEC, + "Can't mix special %%doc with other forms: %s", + *fileName); + fl->processingFailed = 1; + res = 1; + } else { + headerGetEntry(pkg->header, RPMTAG_NAME, NULL, + (void *) &name, NULL); + headerGetEntry(pkg->header, RPMTAG_VERSION, NULL, + (void *) &version, NULL); + sprintf(buf, "%s/%s-%s", spec->docDir, name, version); + + if (! fl->passedSpecialDoc) { + pkg->specialDoc = newStringBuf(); + appendStringBuf(pkg->specialDoc, + "export DOCDIR=$RPM_BUILD_ROOT"); + appendLineStringBuf(pkg->specialDoc, buf); + appendLineStringBuf(pkg->specialDoc, "rm -rf $DOCDIR"); + appendLineStringBuf(pkg->specialDoc, "mkdir -p $DOCDIR"); + + *fileName = buf; + fl->passedSpecialDoc = 1; + fl->isSpecialDoc = 1; + } + + appendStringBuf(pkg->specialDoc, "cp -pr "); + appendStringBuf(pkg->specialDoc, specialDocBuf); + appendLineStringBuf(pkg->specialDoc, " $DOCDIR"); + } } + + return res; } -static int add_file_aux(const char *file, struct stat *sb, int flag) +static int parseForVerify(char *buf, struct FileList *fl) { - const char *name = file; + char *p, *start, *end, *name; + char ourbuf[BUFSIZ]; + int not, verifyFlags; + int *resultVerify; - if (rpmGetVar(RPMVAR_ROOT)) { - name += strlen(rpmGetVar(RPMVAR_ROOT)); + if (!(p = start = strstr(buf, "%verify"))) { + if (!(p = start = strstr(buf, "%defverify"))) { + return 0; + } + name = "%defverify"; + resultVerify = &(fl->defVerifyFlags); + p += 10; + } else { + name = "%verify"; + resultVerify = &(fl->currentVerifyFlags); + p += 7; } - /* The 1 will cause add_file() to *not* descend */ - /* directories -- ftw() is already doing it! */ - Gcount += add_file(Gfestack, name, Gisdoc, Gconf, 1, Gisghost, - Gverify_flags, - GPmode, GUname, GGname, Gprefix); + SKIPSPACE(p); - return 0; /* for ftw() */ -} + if (*p != '(') { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + p++; -/*************************************************************/ -/* */ -/* globbing */ -/* */ -/*************************************************************/ + end = p; + while (*end && *end != ')') { + end++; + } -/* glob_pattern_p() taken from bash - * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc. - */ + if (! *end) { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } -/* 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); + strncpy(ourbuf, p, end-p); + ourbuf[end-p] = '\0'; + while (start <= end) { + *start++ = ' '; + } + + p = strtok(ourbuf, ", \n\t"); + not = 0; + verifyFlags = RPMVERIFY_NONE; + while (p) { + if (!strcmp(p, "not")) { + not = 1; + } else if (!strcmp(p, "md5")) { + verifyFlags |= RPMVERIFY_MD5; + } else if (!strcmp(p, "size")) { + verifyFlags |= RPMVERIFY_FILESIZE; + } else if (!strcmp(p, "link")) { + verifyFlags |= RPMVERIFY_LINKTO; + } else if (!strcmp(p, "user")) { + verifyFlags |= RPMVERIFY_USER; + } else if (!strcmp(p, "group")) { + verifyFlags |= RPMVERIFY_GROUP; + } else if (!strcmp(p, "mtime")) { + verifyFlags |= RPMVERIFY_MTIME; + } else if (!strcmp(p, "mode")) { + verifyFlags |= RPMVERIFY_MODE; + } else if (!strcmp(p, "rdev")) { + verifyFlags |= RPMVERIFY_RDEV; + } else { + rpmError(RPMERR_BADSPEC, "Invalid %s token: %s", name, p); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } + p = strtok(NULL, ", \n\t"); + } - return (0); -} + *resultVerify = not ? ~(verifyFlags) : verifyFlags; -static int glob_error(const char *foo, int bar) -{ - return 1; + return 0; } -/*************************************************************/ -/* */ -/* %attr parsing */ -/* */ -/*************************************************************/ - -static int parseForAttr(char *buf, char **currPmode, - char **currUname, char **currGname) +static int parseForLang(char *buf, struct FileList *fl) { char *p, *start, *end; char ourbuf[1024]; - int mode, x; - if (!(p = start = strstr(buf, "%attr"))) { + if (!(p = start = strstr(buf, "%lang"))) { return 0; } - *currPmode = *currUname = *currGname = NULL; - p += 5; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + SKIPSPACE(p); if (*p != '(') { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p++; @@ -837,68 +1036,66 @@ static int parseForAttr(char *buf, char **currPmode, } if (! *end) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } strncpy(ourbuf, p, end-p); ourbuf[end-p] = '\0'; + while (start <= end) { + *start++ = ' '; + } - *currPmode = strtok(ourbuf, ", \n\t"); - *currUname = strtok(NULL, ", \n\t"); - *currGname = strtok(NULL, ", \n\t"); - - if (! (*currPmode && *currUname && *currGname)) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() syntax: %s", buf); - *currPmode = *currUname = *currGname = NULL; + p = strtok(ourbuf, ", \n\t"); + if (!p) { + rpmError(RPMERR_BADSPEC, "Bad %%lang() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } - - /* Do a quick test on the mode argument */ - if (strcmp(*currPmode, "-")) { - x = sscanf(*currPmode, "%o", &mode); - if ((x == 0) || (mode >> 12)) { - rpmError(RPMERR_BADSPEC, "Bad %%attr() mode spec: %s", buf); - *currPmode = *currUname = *currGname = NULL; - return RPMERR_BADSPEC; - } + if (strlen(p) != 2) { + rpmError(RPMERR_BADSPEC, "%%lang() entries are 2 characters: %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - - *currPmode = strdup(*currPmode); - *currUname = strdup(*currUname); - *currGname = strdup(*currGname); - - /* Set everything we just parsed to blank spaces */ - while (start <= end) { - *start++ = ' '; + if (strtok(NULL, ", \n\t")) { + rpmError(RPMERR_BADSPEC, "Only one entry in %%lang(): %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - + fl->currentLang = strdup(p); + return 0; } -/*************************************************************/ -/* */ -/* %verify parsing */ -/* */ -/*************************************************************/ - -static int parseForVerify(char *buf, int *verify_flags) +static int parseForAttr(char *buf, struct FileList *fl) { - char *p, *start, *end; + char *p, *s, *start, *end, *name; char ourbuf[1024]; - int not; + int x, defattr = 0; + struct AttrRec *resultAttr; - if (!(p = start = strstr(buf, "%verify"))) { - return 0; + if (!(p = start = strstr(buf, "%attr"))) { + if (!(p = start = strstr(buf, "%defattr"))) { + return 0; + } + defattr = 1; + name = "%defattr"; + resultAttr = &(fl->def); + p += 8; + } else { + name = "%attr"; + resultAttr = &(fl->current); + p += 5; } - p += 7; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL; + + SKIPSPACE(p); if (*p != '(') { - rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p++; @@ -909,53 +1106,92 @@ static int parseForVerify(char *buf, int *verify_flags) } if (! *end) { - rpmError(RPMERR_BADSPEC, "Bad %%verify() syntax: %s", buf); + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } + if (defattr) { + s = end; + s++; + SKIPSPACE(s); + if (*s) { + rpmError(RPMERR_BADSPEC, + "No files after %%defattr(): %s", buf); + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + } + strncpy(ourbuf, p, end-p); ourbuf[end-p] = '\0'; - while (start <= end) { - *start++ = ' '; + + resultAttr->PmodeString = strtok(ourbuf, ", \n\t"); + resultAttr->Uname = strtok(NULL, ", \n\t"); + resultAttr->Gname = strtok(NULL, ", \n\t"); + resultAttr->PdirmodeString = strtok(NULL, ", \n\t"); + + if (! (resultAttr->PmodeString && + resultAttr->Uname && resultAttr->Gname)) { + rpmError(RPMERR_BADSPEC, "Bad %s() syntax: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = resultAttr->Gname = NULL; + fl->processingFailed = 1; + return RPMERR_BADSPEC; } - p = strtok(ourbuf, ", \n\t"); - not = 0; - *verify_flags = RPMVERIFY_NONE; - while (p) { - if (!strcmp(p, "not")) { - not = 1; - } else if (!strcmp(p, "md5")) { - *verify_flags |= RPMVERIFY_MD5; - } else if (!strcmp(p, "size")) { - *verify_flags |= RPMVERIFY_FILESIZE; - } else if (!strcmp(p, "link")) { - *verify_flags |= RPMVERIFY_LINKTO; - } else if (!strcmp(p, "user")) { - *verify_flags |= RPMVERIFY_USER; - } else if (!strcmp(p, "group")) { - *verify_flags |= RPMVERIFY_GROUP; - } else if (!strcmp(p, "mtime")) { - *verify_flags |= RPMVERIFY_MTIME; - } else if (!strcmp(p, "mode")) { - *verify_flags |= RPMVERIFY_MODE; - } else if (!strcmp(p, "rdev")) { - *verify_flags |= RPMVERIFY_RDEV; - } else { - rpmError(RPMERR_BADSPEC, "Invalid %%verify token: %s", p); + /* Do a quick test on the mode argument and adjust for "-" */ + if (!strcmp(resultAttr->PmodeString, "-")) { + resultAttr->PmodeString = NULL; + } else { + x = sscanf(resultAttr->PmodeString, "%o", &(resultAttr->Pmode)); + if ((x == 0) || (resultAttr->Pmode >> 12)) { + rpmError(RPMERR_BADSPEC, "Bad %s() mode spec: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = + resultAttr->Gname = NULL; + fl->processingFailed = 1; return RPMERR_BADSPEC; } - p = strtok(NULL, ", \n\t"); + resultAttr->PmodeString = strdup(resultAttr->PmodeString); } - - if (not) { - *verify_flags = ~(*verify_flags); + if (resultAttr->PdirmodeString) { + /* The processing here is slightly different to maintain */ + /* compatibility with old spec files. */ + if (!strcmp(resultAttr->PdirmodeString, "-")) { + resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString); + } else { + x = sscanf(resultAttr->PdirmodeString, "%o", + &(resultAttr->Pdirmode)); + if ((x == 0) || (resultAttr->Pdirmode >> 12)) { + rpmError(RPMERR_BADSPEC, + "Bad %s() dirmode spec: %s", name, buf); + resultAttr->PmodeString = resultAttr->Uname = + resultAttr->Gname = resultAttr->PdirmodeString = NULL; + fl->processingFailed = 1; + return RPMERR_BADSPEC; + } + resultAttr->PdirmodeString = strdup(resultAttr->PdirmodeString); + } + } + if (!strcmp(resultAttr->Uname, "-")) { + resultAttr->Uname = NULL; + } else { + resultAttr->Uname = strdup(resultAttr->Uname); + } + if (!strcmp(resultAttr->Gname, "-")) { + resultAttr->Gname = NULL; + } else { + resultAttr->Gname = strdup(resultAttr->Gname); + } + + /* Set everything we just parsed to blank spaces */ + while (start <= end) { + *start++ = ' '; } return 0; } -static int parseForConfig(char *buf, int *conf) +static int parseForConfig(char *buf, struct FileList *fl) { char *p, *start, *end; char ourbuf[1024]; @@ -963,12 +1199,10 @@ static int parseForConfig(char *buf, int *conf) if (!(p = start = strstr(buf, "%config"))) { return 0; } - *conf = RPMFILE_CONFIG; + fl->currentFlags = RPMFILE_CONFIG; p += 7; - while (*p && (*p == ' ' || *p == '\t')) { - p++; - } + SKIPSPACE(p); if (*p != '(') { while (start < p) { @@ -985,6 +1219,7 @@ static int parseForConfig(char *buf, int *conf) if (! *end) { rpmError(RPMERR_BADSPEC, "Bad %%config() syntax: %s", buf); + fl->processingFailed = 1; return RPMERR_BADSPEC; } @@ -997,11 +1232,12 @@ static int parseForConfig(char *buf, int *conf) p = strtok(ourbuf, ", \n\t"); while (p) { if (!strcmp(p, "missingok")) { - *conf |= RPMFILE_MISSINGOK; + fl->currentFlags |= RPMFILE_MISSINGOK; } else if (!strcmp(p, "noreplace")) { - *conf |= RPMFILE_NOREPLACE; + fl->currentFlags |= RPMFILE_NOREPLACE; } else { rpmError(RPMERR_BADSPEC, "Invalid %%config token: %s", p); + fl->processingFailed = 1; return RPMERR_BADSPEC; } p = strtok(NULL, ", \n\t"); @@ -1009,3 +1245,39 @@ static int parseForConfig(char *buf, int *conf) return 0; } + +/* 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 myGlobPatternP (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; +} diff --git a/build/files.h b/build/files.h index 235e05a82..61239e2ea 100644 --- a/build/files.h +++ b/build/files.h @@ -1,14 +1,8 @@ -#ifndef _FILES_H_ -#define _FILES_H_ - #include "spec.h" -#include "specP.h" -#include "stringbuf.h" - -int finish_filelists(Spec spec); +#include "package.h" +#include "lib/cpio.h" -int process_filelist(Header header, struct PackageRec *pr, StringBuf sb, - int *size, char *name, char *version, - char *release, int type, char *prefix, char *specFile); -#endif _FILES_H_ +int processBinaryFiles(Spec spec, int installSpecialDoc); +int processSourceFiles(Spec spec); +void freeCpioList(struct cpioFileMapping *cpioList, int cpioCount); diff --git a/build/macro.c b/build/macro.c index 19a4fd878..17319161c 100644 --- a/build/macro.c +++ b/build/macro.c @@ -4,48 +4,42 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> + #include "macro.h" +#include "misc.h" -#ifdef DEBUG +#ifdef DEBUG_MACROS #include <stdio.h> #define rpmError fprintf #define RPMERR_BADSPEC stderr static void dumpTable(void); #else -#include "rpmlib.h" +#include "lib/rpmlib.h" #endif -static void expandMacroTable(void); +static void expandMacroTable(struct MacroContext *mc); static int compareMacros(const void *ap, const void *bp); -static struct macroEntry *findEntry(char *name); -static int handleDefine(char *buf); +static struct MacroEntry *findEntry(struct MacroContext *mc, char *name); +static int handleDefine(struct MacroContext *mc, char *buf); static int parseMacro(char *p, char **macro, char **next); -/* This should be a hash table, but I doubt anyone will ever notice */ +/* This should be a hash table, but I doubt anyone would ever */ +/* notice the increase is speed. */ #define MACRO_CHUNK_SIZE 16 -struct macroEntry { - char *name; - char *expansion; -}; - -static struct macroEntry *macroTable = NULL; -static int macrosAllocated = 0; -static int firstFree = 0; - /*************************************************************************/ /* */ /* Parsing routines */ /* */ /*************************************************************************/ -int expandMacros(char *buf) +int expandMacros(struct MacroContext *mc, char *buf) { char bufA[1024]; char *copyTo, *copyFrom; char *name, *rest, *first; - struct macroEntry *p; + struct MacroEntry *p; if (! buf) { return 0; @@ -57,6 +51,7 @@ int expandMacros(char *buf) first++; } if (*first == '#') { + buf[0] = '\0'; return 0; } @@ -70,8 +65,8 @@ int expandMacros(char *buf) if (parseMacro(copyFrom+1, &name, &rest)) { return 1; } - if (!strcmp(name, "define")) { - if (handleDefine(rest)) { + if (copyFrom == buf && !strcmp(name, "define")) { + if (handleDefine(mc, rest)) { return 1; } /* result is empty */ @@ -83,7 +78,7 @@ int expandMacros(char *buf) copyFrom = rest; } else { /* a real live macro! */ - p = findEntry(name); + p = findEntry(mc, name); if (! p) { /* undefined - just leave it */ *copyTo++ = '%'; @@ -116,7 +111,7 @@ static int parseMacro(char *p, char **macro, char **next) if (! p) { /* empty macro name */ - rpmError(RPMERR_BADSPEC, "Empty macro name\n"); + rpmError(RPMERR_BADSPEC, "Empty macro name"); return 2; } @@ -124,14 +119,14 @@ static int parseMacro(char *p, char **macro, char **next) *next = strchr(p, '}'); if (! *next) { /* unterminated */ - rpmError(RPMERR_BADSPEC, "Unterminated {: %s\n", p); + rpmError(RPMERR_BADSPEC, "Unterminated {: %s", p); return 1; } **next = '\0'; *macro = strtok(p+1, " \n\t"); if (! *macro) { /* empty macro name */ - rpmError(RPMERR_BADSPEC, "Empty macro name\n"); + rpmError(RPMERR_BADSPEC, "Empty macro name"); return 2; } (*next)++; @@ -146,7 +141,7 @@ static int parseMacro(char *p, char **macro, char **next) if (isspace(*p) || ! *p) { /* illegal % syntax */ - rpmError(RPMERR_BADSPEC, "Illegal %% syntax: %s\n", p); + rpmError(RPMERR_BADSPEC, "Illegal %% syntax: %s", p); return 3; } @@ -165,7 +160,7 @@ static int parseMacro(char *p, char **macro, char **next) return 0; } -static int handleDefine(char *buf) +static int handleDefine(struct MacroContext *mc, char *buf) { char *last, *name, *expansion; @@ -177,7 +172,7 @@ static int handleDefine(char *buf) } if (! *name) { /* missing macro name */ - rpmError(RPMERR_BADSPEC, "Unfinished %%define\n"); + rpmError(RPMERR_BADSPEC, "Unfinished %%define"); return 1; } expansion = name; @@ -201,106 +196,115 @@ static int handleDefine(char *buf) } } - expandMacros(expansion); - addMacro(name, expansion); + expandMacros(mc, expansion); + addMacro(mc, name, expansion); return 0; } -#ifdef DEBUG -static void dumpTable() -{ - int i; - - for (i = 0; i < firstFree; i++) { - printf("%s->%s.\n", macroTable[i].name, - macroTable[i].expansion); - } -} - -void main(void) -{ - char buf[1024]; - int x; - - while(gets(buf)) { - x = expandMacros(buf); - printf("%d->%s<-\n", x, buf); - } -} -#endif - /*************************************************************************/ /* */ /* Table handling routines */ /* */ /*************************************************************************/ -void resetMacros(void) +void initMacros(struct MacroContext *mc) +{ + mc->macrosAllocated = 0; + mc->firstFree = 0; + mc->macroTable = NULL; + expandMacroTable(mc); + +} + +void freeMacros(struct MacroContext *mc) { int i; - if (! macrosAllocated) { - expandMacroTable(); - return; - } - - for (i = 0; i < firstFree; i++) { - free(macroTable[i].name); - free(macroTable[i].expansion); + for (i = 0; i < mc->firstFree; i++) { + FREE(mc->macroTable[i].name); + FREE(mc->macroTable[i].expansion); } - firstFree = 0; + FREE(mc->macroTable); } -void addMacro(char *name, char *expansion) +void addMacro(struct MacroContext *mc, char *name, char *expansion) { - struct macroEntry *p; + struct MacroEntry *p; - p = findEntry(name); + p = findEntry(mc, name); if (p) { free(p->expansion); p->expansion = strdup(expansion); return; } - if (firstFree == macrosAllocated) { - expandMacroTable(); + if (mc->firstFree == mc->macrosAllocated) { + expandMacroTable(mc); } - p = macroTable + firstFree++; + p = mc->macroTable + mc->firstFree++; p->name = strdup(name); p->expansion = strdup(expansion); - qsort(macroTable, firstFree, sizeof(*macroTable), compareMacros); + qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)), + compareMacros); } -static struct macroEntry *findEntry(char *name) +static struct MacroEntry *findEntry(struct MacroContext *mc, char *name) { - struct macroEntry key; + struct MacroEntry key; - if (! firstFree) { + if (! mc->firstFree) { return NULL; } key.name = name; - return bsearch(&key, macroTable, firstFree, - sizeof(*macroTable), compareMacros); + return bsearch(&key, mc->macroTable, mc->firstFree, + sizeof(*(mc->macroTable)), compareMacros); } static int compareMacros(const void *ap, const void *bp) { - return strcmp(((struct macroEntry *)ap)->name, - ((struct macroEntry *)bp)->name); + return strcmp(((struct MacroEntry *)ap)->name, + ((struct MacroEntry *)bp)->name); } -static void expandMacroTable() +static void expandMacroTable(struct MacroContext *mc) { - macrosAllocated += MACRO_CHUNK_SIZE; - if (! macrosAllocated) { - macroTable = malloc(sizeof(*macroTable) * macrosAllocated); - firstFree = 0; + mc->macrosAllocated += MACRO_CHUNK_SIZE; + if (! mc->macrosAllocated) { + mc->macroTable = malloc(sizeof(*(mc->macroTable)) * + mc->macrosAllocated); + mc->firstFree = 0; } else { - macroTable = realloc(macroTable, - sizeof(*macroTable) * macrosAllocated); + mc->macroTable = realloc(mc->macroTable, sizeof(*(mc->macroTable)) * + mc->macrosAllocated); + } +} + +/***********************************************************************/ + +#ifdef DEBUG_MACROS +static void dumpTable() +{ + int i; + + for (i = 0; i < firstFree; i++) { + printf("%s->%s.\n", macroTable[i].name, + macroTable[i].expansion); + } +} + +void main(void) +{ + char buf[1024]; + int x; + + while(gets(buf)) { + x = expandMacros(buf); + printf("%d->%s<-\n", x, buf); } } +#endif + diff --git a/build/macro.h b/build/macro.h index ad9b35277..8d3b8d0d2 100644 --- a/build/macro.h +++ b/build/macro.h @@ -1,8 +1,25 @@ +#ifndef _MACRO_H_ +#define _MACRO_H_ + /* macro.h - %macro handling */ -void resetMacros(void); +struct MacroEntry { + char *name; + char *expansion; +}; + +struct MacroContext { + struct MacroEntry *macroTable; + int macrosAllocated; + int firstFree; +}; -void addMacro(char *name, char *expansion); +void initMacros(struct MacroContext *mc); +void freeMacros(struct MacroContext *mc); + +void addMacro(struct MacroContext *mc, char *name, char *expansion); /* Expand all macros in buf, in place */ -int expandMacros(char *buf); +int expandMacros(struct MacroContext *mc, char *buf); + +#endif diff --git a/build/misc.c b/build/misc.c new file mode 100644 index 000000000..7437f3d2a --- /dev/null +++ b/build/misc.c @@ -0,0 +1,202 @@ +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +#include "misc.h" +#include "spec.h" +#include "rpmlib.h" +#include "header.h" +#include "popt/popt.h" + +void addOrAppendListEntry(Header h, int_32 tag, char *line) +{ + int argc; + char **argv; + + poptParseArgvString(line, &argc, &argv); + if (argc) { + headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, argv, argc); + } + FREE(argv); +} + +/* Parse a simple part line that only take -n <pkg> or <pkg> */ +/* <pkg> is return in name as a pointer into a static buffer */ + +int parseSimplePart(char *line, char **name, int *flag) +{ + char *tok; + char linebuf[BUFSIZ]; + static char buf[BUFSIZ]; + + strcpy(linebuf, line); + + /* Throw away the first token (the %xxxx) */ + strtok(linebuf, " \t\n"); + + if (!(tok = strtok(NULL, " \t\n"))) { + *name = NULL; + return 0; + } + + if (!strcmp(tok, "-n")) { + if (!(tok = strtok(NULL, " \t\n"))) { + return 1; + } + *flag = PART_NAME; + } else { + *flag = PART_SUBNAME; + } + strcpy(buf, tok); + *name = buf; + + return (strtok(NULL, " \t\n")) ? 1 : 0; +} + +int parseYesNo(char *s) +{ + if (!s || (s[0] == 'n' || s[0] == 'N') || + !strcasecmp(s, "false") || + !strcasecmp(s, "off") || + !strcmp(s, "0")) { + return 0; + } + + return 1; +} + +char *findLastChar(char *s) +{ + char *res = s; + + while (*s) { + if (! isspace(*s)) { + res = s; + } + s++; + } + + return res; +} + +int parseNum(char *line, int *res) +{ + char *s1; + + s1 = NULL; + *res = strtoul(line, &s1, 10); + if ((*s1) || (s1 == line) || (*res == ULONG_MAX)) { + return 1; + } + + return 0; +} + +StringBuf getOutputFrom(char *dir, char *argv[], + char *writePtr, int writeBytesLeft, + int failNonZero) +{ + int progPID; + int progDead; + int toProg[2]; + int fromProg[2]; + int status; + void *oldhandler; + int bytesWritten; + StringBuf readBuff; + int bytes; + unsigned char buf[8193]; + + oldhandler = signal(SIGPIPE, SIG_IGN); + + pipe(toProg); + pipe(fromProg); + + if (!(progPID = fork())) { + close(toProg[1]); + close(fromProg[0]); + + dup2(toProg[0], 0); /* Make stdin the in pipe */ + dup2(fromProg[1], 1); /* Make stdout the out pipe */ + + close(toProg[0]); + close(fromProg[1]); + + if (dir) { + chdir(dir); + } + + execvp(argv[0], argv); + rpmError(RPMERR_EXEC, "Couldn't exec %s", argv[0]); + _exit(RPMERR_EXEC); + } + if (progPID < 0) { + rpmError(RPMERR_FORK, "Couldn't fork %s", argv[0]); + return NULL; + } + + close(toProg[0]); + close(fromProg[1]); + + /* Do not block reading or writing from/to prog. */ + fcntl(fromProg[0], F_SETFL, O_NONBLOCK); + fcntl(toProg[1], F_SETFL, O_NONBLOCK); + + readBuff = newStringBuf(); + + progDead = 0; + do { + if (waitpid(progPID, &status, WNOHANG)) { + progDead = 1; + } + + /* Write some stuff to the process if possible */ + if (writeBytesLeft) { + if ((bytesWritten = + write(toProg[1], writePtr, + (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) { + if (errno != EAGAIN) { + perror("getOutputFrom()"); + exit(1); + } + bytesWritten = 0; + } + writeBytesLeft -= bytesWritten; + writePtr += bytesWritten; + } else { + close(toProg[1]); + } + + /* Read any data from prog */ + bytes = read(fromProg[0], buf, sizeof(buf)-1); + while (bytes > 0) { + buf[bytes] = '\0'; + appendStringBuf(readBuff, buf); + bytes = read(fromProg[0], buf, sizeof(buf)-1); + } + + /* terminate when prog dies */ + } while (!progDead); + + close(toProg[1]); + close(fromProg[0]); + signal(SIGPIPE, oldhandler); + + if (writeBytesLeft) { + rpmError(RPMERR_EXEC, "failed to write all data to %s", argv[0]); + return NULL; + } + waitpid(progPID, &status, 0); + if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) { + rpmError(RPMERR_EXEC, "%s failed", argv[0]); + return NULL; + } + + return readBuff; +} diff --git a/build/misc.h b/build/misc.h new file mode 100644 index 000000000..1ac941509 --- /dev/null +++ b/build/misc.h @@ -0,0 +1,27 @@ +#ifndef _MISC_H_ +#define _MISC_H_ + +#include "spec.h" +#include "ctype.h" + +#define FREE(x) { if (x) free(x); x = NULL; } + +#define SKIPSPACE(s) { while (*(s) && isspace(*(s))) (s)++; } + +#define SKIPNONSPACE(s) { while (*(s) && !isspace(*(s))) (s)++; } + +#define SKIPTONEWLINE(s) { while (*s && *s != '\n') s++; } + +#define PART_SUBNAME 0 +#define PART_NAME 1 + +void addOrAppendListEntry(Header h, int_32 tag, char *line); +int parseSimplePart(char *line, char **name, int *flag); +char *findLastChar(char *s); +int parseYesNo(char *s); +int parseNum(char *line, int *res); +StringBuf getOutputFrom(char *dir, char *argv[], + char *writePtr, int writeBytesLeft, + int failNonZero); + +#endif diff --git a/build/myftw.c b/build/myftw.c index 28173b5b3..c7a69e8a0 100644 --- a/build/myftw.c +++ b/build/myftw.c @@ -56,9 +56,8 @@ Cambridge, MA 02139, USA. */ static int myftw_dir (DIR **dirs, int level, int descriptors, char *dir, size_t len, - int (*func) (const char *file, - struct stat *status, - int flag)) + int (*func) (void *fl, char *name, struct stat *statp), + void *fl) { int got; struct dirent *entry; @@ -127,13 +126,13 @@ myftw_dir (DIR **dirs, int level, int descriptors, else flag = MYFTW_F; - retval = (*func) (dir, &s, flag); + retval = (*func) (fl, dir, &s); if (flag == MYFTW_D) { if (retval == 0) retval = myftw_dir (dirs, newlev, descriptors, dir, - d_namlen + len, func); + d_namlen + len, func, fl); if (dirs[newlev] != NULL) { int save; @@ -175,10 +174,9 @@ myftw_dir (DIR **dirs, int level, int descriptors, int myftw (const char *dir, - int (*func) (const char *file, - struct stat *status, - int flag), - int descriptors) + int descriptors, + int (*func) (void *fl, char *name, struct stat *statp), + void *fl) { DIR **dirs; size_t len; @@ -223,12 +221,12 @@ int myftw (const char *dir, len = strlen (dir); memcpy ((void *) buf, (void *) dir, len + 1); - retval = (*func) (buf, &s, flag); + retval = (*func) (fl, buf, &s); if (flag == MYFTW_D) { if (retval == 0) - retval = myftw_dir (dirs, 0, descriptors, buf, len, func); + retval = myftw_dir (dirs, 0, descriptors, buf, len, func, fl); if (dirs[0] != NULL) { int save; diff --git a/build/myftw.h b/build/myftw.h index fd82d7609..05bec77ed 100644 --- a/build/myftw.h +++ b/build/myftw.h @@ -3,6 +3,8 @@ #ifndef _MYFTW_H_ #define _MYFTW_H_ +#include <sys/stat.h> + /* The FLAG argument to the user function passed to ftw. */ #define MYFTW_F 0 /* Regular file. */ #define MYFTW_D 1 /* Directory. */ @@ -10,9 +12,8 @@ #define MYFTW_NS 3 /* Unstatable file. */ int myftw (const char *dir, - int (*func) (const char *file, - struct stat *status, - int flag), - int descriptors); + int descriptors, + int (*func) (void *fl, char *name, struct stat *statp), + void *fl); #endif _MYFTW_H_ diff --git a/build/names.c b/build/names.c index 77cb8fe30..c619c692c 100644 --- a/build/names.c +++ b/build/names.c @@ -22,8 +22,6 @@ 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. @@ -162,14 +160,15 @@ char *getGnameS(char *gname) return gnames[x]; } -void markBuildTime(void) -{ - buildtime = time(NULL); -} - time_t *getBuildTime(void) { - return &buildtime; + static time_t buildTime = 0; + + if (! buildTime) { + buildTime = time(NULL); + } + + return &buildTime; } char *buildHost(void) diff --git a/build/names.h b/build/names.h index 4e797448f..d23adca31 100644 --- a/build/names.h +++ b/build/names.h @@ -11,7 +11,6 @@ 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/pack.c b/build/pack.c index 0320246ca..ad149dccf 100644 --- a/build/pack.c +++ b/build/pack.c @@ -1,243 +1,290 @@ -/* The very final packaging steps */ - -#include "config.h" -#include "miscfn.h" - -#if HAVE_ALLOCA_H -# include <alloca.h> -#endif - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/stat.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/wait.h> -#include <signal.h> #include <fcntl.h> +#include <malloc.h> #include <string.h> #include <errno.h> +#include <signal.h> +#include <time.h> -#include <sys/time.h> /* For 'select()' interfaces */ - -#include "cpio.h" -#include "pack.h" -#include "header.h" #include "spec.h" -#include "specP.h" -#include "signature.h" -#include "rpmlead.h" -#include "rpmlib.h" +#include "header.h" #include "misc.h" -#include "stringbuf.h" +#include "reqprov.h" #include "names.h" +#include "macro.h" + +#include "rpmlib.h" #include "files.h" -#include "reqprov.h" -#include "trigger.h" -#include "messages.h" - -static int writeMagic(int fd, char *name, unsigned short type); -static int cpio_gzip(int fd, char *tempdir, char *writePtr, - int *archiveSize, char *prefix); -static int generateRPM(char *name, /* name-version-release */ - char *filename, /* output filename */ - int type, /* source or binary */ - Header header, /* the header */ - char *stempdir, /* directory containing sources */ - char *fileList, /* list of files for cpio */ - char *passPhrase, /* PGP passphrase */ - char *prefix); - - -static int generateRPM(char *name, /* name-version-release */ - char *filename, /* output filename */ - int type, /* source or binary */ - Header header, /* the header */ - char *stempdir, /* directory containing sources */ - char *fileList, /* list of files for cpio */ - char *passPhrase, - char *prefix) +#include "lib/cpio.h" +#include "lib/misc.h" +#include "lib/signature.h" +#include "lib/rpmlead.h" +#include "lib/messages.h" + +#define RPM_MAJOR_NUMBER 3 + +static int processScriptFiles(Spec spec, Package pkg); +static int addFileToTag(Spec spec, char *file, Header h, int tag); +static int writeRPM(Header header, char *fileName, int type, + struct cpioFileMapping *cpioList, int cpioCount, + char *passPhrase, char **cookie); +static int cpio_gzip(int fd, struct cpioFileMapping *cpioList, + int cpioCount, int *archiveSize); + +int packageSources(Spec spec) +{ + char *name, *version, *release; + char fileName[BUFSIZ]; + HeaderIterator iter; + int_32 tag, count; + char **ptr; + + /* Add some cruft */ + headerAddEntry(spec->sourceHeader, RPMTAG_RPMVERSION, + RPM_STRING_TYPE, VERSION, 1); + headerAddEntry(spec->sourceHeader, RPMTAG_BUILDHOST, + RPM_STRING_TYPE, buildHost(), 1); + headerAddEntry(spec->sourceHeader, RPMTAG_BUILDTIME, + RPM_INT32_TYPE, getBuildTime(), 1); + + headerGetEntry(spec->sourceHeader, RPMTAG_NAME, + NULL, (void **)&name, NULL); + headerGetEntry(spec->sourceHeader, RPMTAG_VERSION, + NULL, (void **)&version, NULL); + headerGetEntry(spec->sourceHeader, RPMTAG_RELEASE, + NULL, (void **)&release, NULL); + sprintf(fileName, "%s-%s-%s.%ssrc.rpm", name, version, release, + spec->noSource ? "no" : ""); + spec->sourceRpmName = strdup(fileName); + sprintf(fileName, "%s/%s", rpmGetVar(RPMVAR_SRPMDIR), spec->sourceRpmName); + + /* Add the build restrictions */ + iter = headerInitIterator(spec->buildRestrictions); + while (headerNextIterator(iter, &tag, NULL, (void **)&ptr, &count)) { + headerAddEntry(spec->sourceHeader, tag, + RPM_STRING_ARRAY_TYPE, ptr, count); + FREE(ptr); + } + headerFreeIterator(iter); + if (spec->buildArchitectureCount) { + headerAddEntry(spec->sourceHeader, RPMTAG_BUILDARCHS, + RPM_STRING_ARRAY_TYPE, + spec->buildArchitectures, spec->buildArchitectureCount); + } + + FREE(spec->cookie); + + return writeRPM(spec->sourceHeader, fileName, RPMLEAD_SOURCE, + spec->sourceCpioList, spec->sourceCpioCount, + spec->passPhrase, &(spec->cookie)); +} + +int packageBinaries(Spec spec) +{ + int rc; + char *binFormat, *binRpm, *errorString; + char *name, fileName[BUFSIZ]; + Package pkg; + + pkg = spec->packages; + while (pkg) { + if (!pkg->fileList) { + pkg = pkg->next; + continue; + } + + if ((rc = processScriptFiles(spec, pkg))) { + return rc; + } + + generateAutoReqProv(spec, pkg, pkg->cpioList, pkg->cpioCount); + printReqs(spec, pkg); + + if (spec->cookie) { + headerAddEntry(pkg->header, RPMTAG_COOKIE, + RPM_STRING_TYPE, spec->cookie, 1); + } + + headerAddEntry(pkg->header, RPMTAG_RPMVERSION, + RPM_STRING_TYPE, VERSION, 1); + headerAddEntry(pkg->header, RPMTAG_BUILDHOST, + RPM_STRING_TYPE, buildHost(), 1); + headerAddEntry(pkg->header, RPMTAG_BUILDTIME, + RPM_INT32_TYPE, getBuildTime(), 1); + headerAddEntry(pkg->header, RPMTAG_SOURCERPM, RPM_STRING_TYPE, + spec->sourceRpmName ? + spec->sourceRpmName : "(unknown)", 1); + + binFormat = rpmGetVar(RPMVAR_RPMFILENAME); + binRpm = headerSprintf(pkg->header, binFormat, rpmTagTable, + rpmHeaderFormats, &errorString); + if (!binRpm) { + headerGetEntry(pkg->header, RPMTAG_NAME, NULL, + (void **)&name, NULL); + rpmError(RPMERR_BADFILENAME, "Could not generate output " + "filename for package %s: %s\n", name, errorString); + return RPMERR_BADFILENAME; + } + sprintf(fileName, "%s/%s", rpmGetVar(RPMVAR_RPMDIR), binRpm); + FREE(binRpm); + + if ((rc = writeRPM(pkg->header, fileName, RPMLEAD_BINARY, + pkg->cpioList, pkg->cpioCount, + spec->passPhrase, NULL))) { + return rc; + } + + pkg = pkg->next; + } + + return 0; +} + +static int writeRPM(Header header, char *fileName, int type, + struct cpioFileMapping *cpioList, int cpioCount, + char *passPhrase, char **cookie) { - int_32 sigtype; - char *sigtarget; - int fd, ifd, count, archiveSize; - unsigned char buffer[8192]; + int archiveSize, fd, ifd, rc, count, arch, os, sigtype; + char *sigtarget, *name, *version, *release; + char buf[BUFSIZ]; Header sig; + struct rpmlead lead; /* Add the a bogus archive size to the Header */ headerAddEntry(header, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE, &archiveSize, 1); + /* Create and add the cookie */ + if (cookie) { + sprintf(buf, "%s %d", buildHost(), (int) time(NULL)); + *cookie = strdup(buf); + headerAddEntry(header, RPMTAG_COOKIE, RPM_STRING_TYPE, *cookie, 1); + } + /* Write the header */ - if (makeTempFile(NULL, &sigtarget, &fd)) - return 1; - + if (makeTempFile(NULL, &sigtarget, &fd)) { + rpmError(RPMERR_CREATE, "Unable to open temp file"); + return RPMERR_CREATE; + } headerWrite(fd, header, HEADER_MAGIC_YES); - + /* Write the archive and get the size */ - if (cpio_gzip(fd, stempdir, fileList, &archiveSize, prefix)) { + if ((rc = cpio_gzip(fd, cpioList, cpioCount, &archiveSize))) { close(fd); unlink(sigtarget); free(sigtarget); - return 1; + return rc; } /* Now set the real archive size in the Header */ headerModifyEntry(header, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE, &archiveSize, 1); - - /* Rewind and rewrite the Header */ lseek(fd, 0, SEEK_SET); headerWrite(fd, header, HEADER_MAGIC_YES); - + close(fd); - - /* Now write the lead */ - if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { - fprintf(stderr, "Could not open %s\n", filename); + + /* Open the output file */ + if ((fd = open(fileName, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { + rpmError(RPMERR_CREATE, "Could not open %s\n", fileName); unlink(sigtarget); free(sigtarget); - unlink(filename); - return 1; + return RPMERR_CREATE; } - if (writeMagic(fd, name, type)) { + + /* Now write the lead */ + headerGetEntry(header, RPMTAG_NAME, NULL, (void **)&name, NULL); + headerGetEntry(header, RPMTAG_VERSION, NULL, (void **)&version, NULL); + headerGetEntry(header, RPMTAG_RELEASE, NULL, (void **)&release, NULL); + sprintf(buf, "%s-%s-%s", name, version, release); + rpmGetArchInfo(NULL, &arch); + rpmGetOsInfo(NULL, &os); + lead.major = RPM_MAJOR_NUMBER; + lead.minor = 0; + lead.type = type; + lead.archnum = arch; + lead.osnum = os; + lead.signature_type = RPMSIG_HEADERSIG; /* New-style signature */ + strncpy(lead.name, buf, sizeof(lead.name)); + if (writeLead(fd, &lead)) { + rpmError(RPMERR_NOSPACE, "Unable to write package: %s", + strerror(errno)); close(fd); unlink(sigtarget); free(sigtarget); - unlink(filename); - return 1; + unlink(fileName); + return rc; } /* Generate the signature */ sigtype = rpmLookupSignatureType(); - rpmMessage(RPMMESS_VERBOSE, "Generating signature: %d\n", sigtype); fflush(stdout); sig = rpmNewSignature(); rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase); rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase); - if (sigtype>0) { + if (sigtype > 0) { + rpmMessage(RPMMESS_NORMAL, "Generating signature: %d\n", sigtype); rpmAddSignature(sig, sigtarget, sigtype, passPhrase); } - if (rpmWriteSignature(fd, sig)) { + if ((rc = rpmWriteSignature(fd, sig))) { close(fd); unlink(sigtarget); free(sigtarget); - unlink(filename); + unlink(fileName); rpmFreeSignature(sig); - return 1; + return rc; } rpmFreeSignature(sig); - + /* Append the header and archive */ ifd = open(sigtarget, O_RDONLY); - while ((count = read(ifd, buffer, sizeof(buffer))) > 0) { - if (count == -1) { - perror("Couldn't read sigtarget"); + while ((count = read(ifd, buf, sizeof(buf))) > 0) { + if (count == -1) { + rpmError(RPMERR_READERROR, "Unable to read sigtarget: %s", + strerror(errno)); close(ifd); close(fd); unlink(sigtarget); free(sigtarget); - unlink(filename); - return 1; - } - if (write(fd, buffer, count) < 0) { - perror("Couldn't write package"); + unlink(fileName); + return RPMERR_READERROR; + } + if (write(fd, buf, count) < 0) { + rpmError(RPMERR_NOSPACE, "Unable to write package: %s", + strerror(errno)); close(ifd); close(fd); unlink(sigtarget); free(sigtarget); - unlink(filename); - return 1; - } + unlink(fileName); + return RPMERR_NOSPACE; + } } close(ifd); close(fd); unlink(sigtarget); free(sigtarget); - rpmMessage(RPMMESS_VERBOSE, "Wrote: %s\n", filename); - - return 0; -} - -static int writeMagic(int fd, char *name, - unsigned short type) -{ - struct rpmlead lead; - int arch, os; - - rpmGetArchInfo(NULL, &arch); - rpmGetOsInfo(NULL, &os); - - /* There are the Major and Minor numbers */ - lead.major = 3; - lead.minor = 0; - lead.type = type; - lead.archnum = arch; - lead.osnum = os; - lead.signature_type = RPMSIG_HEADERSIG; /* New-style signature */ - strncpy(lead.name, name, sizeof(lead.name)); - memset(lead.reserved, 0, sizeof(lead.reserved)); - - writeLead(fd, &lead); + rpmMessage(RPMMESS_NORMAL, "Wrote: %s\n", fileName); return 0; } -static int cpio_gzip(int fd, char *tempdir, char *writePtr, - int *archiveSize, char *prefix) +static int cpio_gzip(int fd, struct cpioFileMapping *cpioList, + int cpioCount, int *archiveSize) { - int gzipPID; - int toGzip[2]; - int rc; - char * gzipbin; - char * writebuf; - char * chptr; - int numMappings; - struct cpioFileMapping * cpioList; - int status; + char *gzipbin; void *oldhandler; - char savecwd[1024]; - char * failedFile; + int rc, gzipPID, toGzip[2], status; + char *failedFile; gzipbin = rpmGetVar(RPMVAR_GZIPBIN); - - numMappings = 0; - chptr = writePtr; - while (chptr && *chptr) { - numMappings++; - chptr = strchr(chptr, '\n'); - if (chptr) *chptr++ = '\n'; - } - - writebuf = alloca(strlen(writePtr) + 1); - strcpy(writebuf, writePtr); - - cpioList = alloca(sizeof(*cpioList) * numMappings); - chptr = writebuf; - numMappings = 0; - while (chptr && *chptr) { - cpioList[numMappings].fsPath = chptr; - cpioList[numMappings].mapFlags = tempdir ? CPIO_FOLLOW_SYMLINKS : 0; - - chptr = strchr(chptr, '\n'); - if (chptr) *chptr++ = '\0'; - - /* hack */ - if (!strlen(cpioList[numMappings].fsPath)) { - cpioList[numMappings].fsPath = "."; - } - - numMappings++; - } - oldhandler = signal(SIGPIPE, SIG_IGN); - pipe(toGzip); - /* GZIP */ + pipe(toGzip); if (!(gzipPID = fork())) { close(toGzip[1]); @@ -248,520 +295,105 @@ static int cpio_gzip(int fd, char *tempdir, char *writePtr, rpmError(RPMERR_EXEC, "Couldn't exec gzip"); _exit(RPMERR_EXEC); } + close(toGzip[0]); if (gzipPID < 0) { + close(toGzip[1]); rpmError(RPMERR_FORK, "Couldn't fork gzip"); return RPMERR_FORK; } - close(toGzip[0]); - - getcwd(savecwd, 1024); - - if (tempdir) { - chdir(tempdir); - } else if (rpmGetVar(RPMVAR_ROOT)) { - if (chdir(rpmGetVar(RPMVAR_ROOT))) { - rpmError(RPMERR_EXEC, "Couldn't chdir to %s", - rpmGetVar(RPMVAR_ROOT)); - exit(RPMERR_EXEC); - } - } else { - /* This is important! */ - chdir("/"); - } - if (prefix) { - if (chdir(prefix)) { - rpmError(RPMERR_EXEC, "Couldn't chdir to %s", prefix); - _exit(RPMERR_EXEC); - } - } - - rc = cpioBuildArchive(toGzip[1], cpioList, numMappings, NULL, NULL, + rc = cpioBuildArchive(fd, cpioList, cpioCount, NULL, NULL, archiveSize, &failedFile); - chdir(savecwd); - - close(toGzip[1]); /* Terminates the gzip process */ - + close(toGzip[1]); signal(SIGPIPE, oldhandler); - waitpid(gzipPID, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status)) { - rpmError(RPMERR_GZIP, "gzip failed"); + rpmError(RPMERR_GZIP, "Execution of gzip failed"); return 1; } if (rc) { if (rc & CPIO_CHECK_ERRNO) - rpmError(RPMERR_CPIO, "cpio failed on file %s: %d: %s", failedFile, - rc, strerror(errno)); + rpmError(RPMERR_CPIO, "cpio failed on file %s: %s", + failedFile, strerror(errno)); else - rpmError(RPMERR_CPIO, "cpio failed on file %s: %d", failedFile, rc); + rpmError(RPMERR_CPIO, "cpio failed on file %s: %d", + failedFile, rc); return 1; } return 0; } - -int packageBinaries(Spec s, char *passPhrase, int doPackage) +static int addFileToTag(Spec spec, char *file, Header h, int tag) { - char name[1024]; - char *nametmp; - char filename[1024]; - char sourcerpm[1024]; - char * binrpm; - char *icon; - int iconFD; - struct stat statbuf; - struct PackageRec *pr; - Header outHeader; - HeaderIterator headerIter; - int_32 tag, type, c; - void *ptr; - char *version; - char *release; - char *vendor; - char *dist; - char *packager; - char *packageVersion, *packageRelease; - char *prefix, *prefixSave; - char * arch, * os; - char * binformat, * errorString; - int prefixLen; - int size; - StringBuf cpioFileList; - char **farray, *file; - int count; - int *fflagarray; - - if (!headerGetEntry(s->packages->header, RPMTAG_VERSION, NULL, - (void *) &version, NULL)) { - rpmError(RPMERR_BADSPEC, "No version field"); - return RPMERR_BADSPEC; - } - if (!headerGetEntry(s->packages->header, RPMTAG_RELEASE, NULL, - (void *) &release, NULL)) { - rpmError(RPMERR_BADSPEC, "No release field"); - return RPMERR_BADSPEC; - } - /* after the headerGetEntry() these are just pointers into the */ - /* header structure, which can be moved around by headerAddEntry */ - version = strdup(version); - release = strdup(release); - - sprintf(sourcerpm, "%s-%s-%s.%ssrc.rpm", s->name, version, release, - (s->numNoPatch + s->numNoSource) ? "no" : ""); - - vendor = NULL; - if (!headerIsEntry(s->packages->header, RPMTAG_VENDOR)) { - vendor = rpmGetVar(RPMVAR_VENDOR); - } - dist = NULL; - if (!headerIsEntry(s->packages->header, RPMTAG_DISTRIBUTION)) { - dist = rpmGetVar(RPMVAR_DISTRIBUTION); + StringBuf sb; + char *s; + char buf[BUFSIZ]; + FILE *f; + + sb = newStringBuf(); + if (headerGetEntry(h, tag, NULL, (void **)&s, NULL)) { + appendLineStringBuf(sb, s); + headerRemoveEntry(h, tag); + } + sprintf(buf, "%s/%s/%s", rpmGetVar(RPMVAR_BUILDDIR), + spec->buildSubdir, file); + if ((f = fopen(buf, "r")) == NULL) { + freeStringBuf(sb); + return 1; } - packager = NULL; - if (!headerIsEntry(s->packages->header, RPMTAG_PACKAGER)) { - packager = rpmGetVar(RPMVAR_PACKAGER); - } - - /* Look through for each package */ - pr = s->packages; - while (pr) { - /* A file count of -1 means no package */ - if (pr->files == -1) { - pr = pr->next; - continue; - } - - /* Handle subpackage version/release overrides */ - if (!headerGetEntry(pr->header, RPMTAG_VERSION, NULL, - (void *) &packageVersion, NULL)) { - packageVersion = version; - } - if (!headerGetEntry(pr->header, RPMTAG_RELEASE, NULL, - (void *) &packageRelease, NULL)) { - packageRelease = release; - } - /* after the headerGetEntry() these are just pointers into the */ - /* header structure, which can be moved around by headerAddEntry */ - packageVersion = strdup(packageVersion); - packageRelease = strdup(packageRelease); - - /* Figure out the name of this package */ - if (!headerGetEntry(pr->header, RPMTAG_NAME, NULL, (void *)&nametmp, NULL)) { - rpmError(RPMERR_INTERNAL, "Package has no name!"); - return RPMERR_INTERNAL; - } - sprintf(name, "%s-%s-%s", nametmp, packageVersion, packageRelease); - - if (doPackage == PACK_PACKAGE) { - rpmMessage(RPMMESS_VERBOSE, "Binary Packaging: %s\n", name); - } else { - rpmMessage(RPMMESS_VERBOSE, "File List Check: %s\n", name); - } - - /**** Generate the Header ****/ - - /* Here's the plan: copy the package's header, */ - /* then add entries from the primary header */ - /* that don't already exist. */ - outHeader = headerCopy(pr->header); - headerIter = headerInitIterator(s->packages->header); - while (headerNextIterator(headerIter, &tag, &type, &ptr, &c)) { - /* Some tags we don't copy */ - switch (tag) { - case RPMTAG_PREIN: - case RPMTAG_POSTIN: - case RPMTAG_PREUN: - case RPMTAG_POSTUN: - case RPMTAG_PREINPROG: - case RPMTAG_POSTINPROG: - case RPMTAG_PREUNPROG: - case RPMTAG_POSTUNPROG: - case RPMTAG_VERIFYSCRIPT: - continue; - break; /* Shouldn't need this */ - default: - if (! headerIsEntry(outHeader, tag)) { - headerAddEntry(outHeader, tag, type, ptr, c); - } - } - } - headerFreeIterator(headerIter); - - headerRemoveEntry(outHeader, RPMTAG_BUILDARCHS); - - rpmGetArchInfo(&arch, NULL); - rpmGetOsInfo(&os, NULL); - - /* Add some final entries to the header */ - headerAddEntry(outHeader, RPMTAG_OS, RPM_STRING_TYPE, os, 1); - headerAddEntry(outHeader, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1); - headerAddEntry(outHeader, RPMTAG_BUILDTIME, RPM_INT32_TYPE, getBuildTime(), 1); - headerAddEntry(outHeader, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildHost(), 1); - headerAddEntry(outHeader, RPMTAG_SOURCERPM, RPM_STRING_TYPE, sourcerpm, 1); - headerAddEntry(outHeader, RPMTAG_RPMVERSION, RPM_STRING_TYPE, VERSION, 1); - if (pr->icon) { - sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), pr->icon); - stat(filename, &statbuf); - icon = malloc(statbuf.st_size); - iconFD = open(filename, O_RDONLY, 0644); - read(iconFD, icon, statbuf.st_size); - close(iconFD); - if (! strncmp(icon, "GIF", 3)) { - headerAddEntry(outHeader, RPMTAG_GIF, RPM_BIN_TYPE, - icon, statbuf.st_size); - } else if (! strncmp(icon, "/* XPM", 6)) { - headerAddEntry(outHeader, RPMTAG_XPM, RPM_BIN_TYPE, - icon, statbuf.st_size); - } else { - rpmError(RPMERR_BADSPEC, "Unknown icon type"); - return 1; - } - free(icon); - } - if (vendor) { - headerAddEntry(outHeader, RPMTAG_VENDOR, RPM_STRING_TYPE, vendor, 1); - } - if (dist) { - headerAddEntry(outHeader, RPMTAG_DISTRIBUTION, RPM_STRING_TYPE, dist, 1); - } - if (packager) { - headerAddEntry(outHeader, RPMTAG_PACKAGER, RPM_STRING_TYPE, packager, 1); - } - - /**** Process the file list ****/ - - prefixSave = prefix = NULL; - prefixLen = 0; - if (headerGetEntry(outHeader, RPMTAG_DEFAULTPREFIX, - NULL, (void **)&prefix, NULL)) { - /* after the headerGetEntry() this is just pointers into the */ - /* header structure, which can be moved around by headerAddEntry */ - prefixSave = prefix = strdup(prefix); - while (*prefix && (*prefix == '/')) { - prefix++; - } - if (! *prefix) { - prefix = NULL; - prefixLen = 0; - } else { - prefixLen = strlen(prefix); - rpmMessage(RPMMESS_VERBOSE, "Package Prefix = %s\n", prefix); - } - } - - if (process_filelist(outHeader, pr, pr->filelist, &size, nametmp, - packageVersion, packageRelease, RPMLEAD_BINARY, - prefix, NULL)) { - return 1; - } - - if (!headerGetEntry(outHeader, RPMTAG_FILENAMES, NULL, - (void **) &farray, &count)) { - /* count may already be 0, but this is safer */ - count = 0; - } - headerGetEntry(outHeader, RPMTAG_FILEFLAGS, NULL, - (void **) &fflagarray, NULL); - - cpioFileList = newStringBuf(); - while (count--) { - file = *farray++; - while (*file == '/') { - file++; /* Skip leading "/" */ - } - if (prefix) { - if (strncmp(prefix, file, prefixLen)) { - rpmError(RPMERR_BADSPEC, "File doesn't match prefix (%s): %s", - prefix, file); - return 1; - } - file += prefixLen; - if (*file) { - file++; /* 1 for "/" */ - } - } - - if (! (*fflagarray & RPMFILE_GHOST)) { - appendLineStringBuf(cpioFileList, file); - } - fflagarray++; - } - - /* Generate any automatic require/provide entries */ - /* Then add the whole thing to the header */ - if (s->autoReqProv) { - generateAutoReqProv(outHeader, pr); - } - processReqProv(outHeader, pr); - - /* Generate the any trigger entries */ - generateTriggerEntries(outHeader, pr); - - /* And add the final Header entry */ - headerAddEntry(outHeader, RPMTAG_SIZE, RPM_INT32_TYPE, &size, 1); - - /**** Make the RPM ****/ - - /* Make the output RPM filename */ - if (doPackage == PACK_PACKAGE) { - binformat = rpmGetVar(RPMVAR_RPMFILENAME); - binrpm = headerSprintf(outHeader, binformat, rpmTagTable, - rpmHeaderFormats, &errorString); - - if (!binrpm) { - rpmError(RPMERR_BADFILENAME, "could not generate output " - "filename for package %s: %s\n", name, binrpm); - } - - sprintf(filename, "%s/%s", rpmGetVar(RPMVAR_RPMDIR), binrpm); - free(binrpm); - - if (generateRPM(name, filename, RPMLEAD_BINARY, outHeader, NULL, - getStringBuf(cpioFileList), passPhrase, prefix)) { - /* Build failed */ - return 1; - } - } - - freeStringBuf(cpioFileList); - headerFree(outHeader); - - if (prefixSave) - free(prefixSave); - free(packageVersion); - free(packageRelease); - - pr = pr->next; + while (fgets(buf, sizeof(buf), f)) { + expandMacros(&spec->macros, buf); + appendStringBuf(sb, buf); } + fclose(f); + + headerAddEntry(h, tag, RPM_STRING_TYPE, getStringBuf(sb), 1); - free(version); - free(release); - + freeStringBuf(sb); return 0; } -/**************** SOURCE PACKAGING ************************/ - -int packageSource(Spec s, char *passPhrase) +static int processScriptFiles(Spec spec, Package pkg) { - struct sources *source; - struct PackageRec *package; - char *tempdir; - char src[1024], dest[1024], fullname[1024], filename[1024], specFile[1024]; - char *version; - char *release; - char *vendor; - char *dist; - char *p; - Header outHeader; - StringBuf filelist; - StringBuf cpioFileList; - int size; - char **sources; - char **patches; - char * arch, * os; - int scount, pcount; - int skipi; - int_32 *skip; - - /**** Create links for all the sources ****/ - - tempdir = tempnam(rpmGetVar(RPMVAR_TMPPATH), "rpmbuild"); - mkdir(tempdir, 0700); - - filelist = newStringBuf(); /* List in the header */ - cpioFileList = newStringBuf(); /* List for cpio */ - - sources = malloc((s->numSources+1) * sizeof(char *)); - patches = malloc((s->numPatches+1) * sizeof(char *)); - - /* Link in the spec file and all the sources */ - p = strrchr(s->specfile, '/'); - sprintf(dest, "%s%s", tempdir, p); - strcpy(specFile, dest); - symlink(s->specfile, dest); - appendLineStringBuf(filelist, dest); - appendLineStringBuf(cpioFileList, p+1); - source = s->sources; - scount = 0; - pcount = 0; - while (source) { - if (source->ispatch) { - skipi = s->numNoPatch - 1; - skip = s->noPatch; - } else { - skipi = s->numNoSource - 1; - skip = s->noSource; - } - while (skipi >= 0) { - if (skip[skipi] == source->num) { - break; - } - skipi--; - } - sprintf(src, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), source->source); - sprintf(dest, "%s/%s", tempdir, source->source); - if (skipi < 0) { - symlink(src, dest); - appendLineStringBuf(cpioFileList, source->source); - } else { - rpmMessage(RPMMESS_VERBOSE, "Skipping source/patch (%d): %s\n", - source->num, source->source); - } - appendLineStringBuf(filelist, src); - if (source->ispatch) { - patches[pcount++] = source->fullSource; - } else { - sources[scount++] = source->fullSource; + if (pkg->preInFile) { + if (addFileToTag(spec, pkg->preInFile, pkg->header, RPMTAG_PREIN)) { + rpmError(RPMERR_BADFILENAME, + "Could not open PreIn file: %s", pkg->preInFile); + return RPMERR_BADFILENAME; } - source = source->next; } - /* ... and icons */ - package = s->packages; - while (package) { - if (package->icon) { - sprintf(src, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), package->icon); - sprintf(dest, "%s/%s", tempdir, package->icon); - appendLineStringBuf(filelist, dest); - appendLineStringBuf(cpioFileList, package->icon); - symlink(src, dest); + if (pkg->preUnFile) { + if (addFileToTag(spec, pkg->preUnFile, pkg->header, RPMTAG_PREUN)) { + rpmError(RPMERR_BADFILENAME, + "Could not open PreUn file: %s", pkg->preUnFile); + return RPMERR_BADFILENAME; } - package = package->next; } - - /**** Generate the Header ****/ - - if (!headerGetEntry(s->packages->header, RPMTAG_VERSION, NULL, - (void *) &version, NULL)) { - rpmError(RPMERR_BADSPEC, "No version field"); - return RPMERR_BADSPEC; - } - if (!headerGetEntry(s->packages->header, RPMTAG_RELEASE, NULL, - (void *) &release, NULL)) { - rpmError(RPMERR_BADSPEC, "No release field"); - return RPMERR_BADSPEC; - } - - rpmGetArchInfo(&arch, NULL); - rpmGetOsInfo(&os, NULL); - - outHeader = headerCopy(s->packages->header); - headerAddEntry(outHeader, RPMTAG_OS, RPM_STRING_TYPE, os, 1); - headerAddEntry(outHeader, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1); - headerAddEntry(outHeader, RPMTAG_BUILDTIME, RPM_INT32_TYPE, getBuildTime(), 1); - headerAddEntry(outHeader, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildHost(), 1); - headerAddEntry(outHeader, RPMTAG_RPMVERSION, RPM_STRING_TYPE, VERSION, 1); - if (scount) - headerAddEntry(outHeader, RPMTAG_SOURCE, RPM_STRING_ARRAY_TYPE, sources, scount); - if (pcount) - headerAddEntry(outHeader, RPMTAG_PATCH, RPM_STRING_ARRAY_TYPE, patches, pcount); - if (s->numNoSource) { - headerAddEntry(outHeader, RPMTAG_NOSOURCE, RPM_INT32_TYPE, s->noSource, - s->numNoSource); - } - if (s->numNoPatch) { - headerAddEntry(outHeader, RPMTAG_NOPATCH, RPM_INT32_TYPE, s->noPatch, - s->numNoPatch); - } - if (!headerIsEntry(s->packages->header, RPMTAG_VENDOR)) { - if ((vendor = rpmGetVar(RPMVAR_VENDOR))) { - headerAddEntry(outHeader, RPMTAG_VENDOR, RPM_STRING_TYPE, vendor, 1); + if (pkg->postInFile) { + if (addFileToTag(spec, pkg->postInFile, pkg->header, RPMTAG_POSTIN)) { + rpmError(RPMERR_BADFILENAME, + "Could not open PostIn file: %s", pkg->postInFile); + return RPMERR_BADFILENAME; } } - if (!headerIsEntry(s->packages->header, RPMTAG_DISTRIBUTION)) { - if ((dist = rpmGetVar(RPMVAR_DISTRIBUTION))) { - headerAddEntry(outHeader, RPMTAG_DISTRIBUTION, RPM_STRING_TYPE, dist, 1); + if (pkg->postUnFile) { + if (addFileToTag(spec, pkg->postUnFile, pkg->header, RPMTAG_POSTUN)) { + rpmError(RPMERR_BADFILENAME, + "Could not open PostUn file: %s", pkg->postUnFile); + return RPMERR_BADFILENAME; } } - - /* Process the file list */ - if (process_filelist(outHeader, NULL, filelist, &size, - s->name, version, release, RPMLEAD_SOURCE, - NULL, specFile)) { - return 1; - } - - /* And add the final Header entry */ - headerAddEntry(outHeader, RPMTAG_SIZE, RPM_INT32_TYPE, &size, 1); - - /**** Make the RPM ****/ - - sprintf(fullname, "%s-%s-%s", s->name, version, release); - sprintf(filename, "%s/%s.%ssrc.rpm", rpmGetVar(RPMVAR_SRPMDIR), fullname, - (s->numNoPatch + s->numNoSource) ? "no" : ""); - rpmMessage(RPMMESS_VERBOSE, "Source Packaging: %s\n", fullname); - - if (generateRPM(fullname, filename, RPMLEAD_SOURCE, outHeader, - tempdir, getStringBuf(cpioFileList), passPhrase, NULL)) { - return 1; - } - - /**** Now clean up ****/ - - freeStringBuf(filelist); - freeStringBuf(cpioFileList); - - source = s->sources; - while (source) { - sprintf(dest, "%s/%s", tempdir, source->source); - unlink(dest); - source = source->next; - } - package = s->packages; - while (package) { - if (package->icon) { - sprintf(dest, "%s/%s", tempdir, package->icon); - unlink(dest); + if (pkg->verifyFile) { + if (addFileToTag(spec, pkg->verifyFile, pkg->header, + RPMTAG_VERIFYSCRIPT)) { + rpmError(RPMERR_BADFILENAME, + "Could not open VerifyScript file: %s", pkg->verifyFile); + return RPMERR_BADFILENAME; } - package = package->next; } - sprintf(dest, "%s%s", tempdir, strrchr(s->specfile, '/')); - unlink(dest); - rmdir(tempdir); - + return 0; } diff --git a/build/pack.h b/build/pack.h index d144484cf..51905e209 100644 --- a/build/pack.h +++ b/build/pack.h @@ -1,14 +1,4 @@ -/* pack.h -- final packing steps */ - -#ifndef _PACK_H_ -#define _PACK_H_ - #include "spec.h" -#define PACK_PACKAGE 1 -#define PACK_NOPACKAGE 0 - -int packageBinaries(Spec s, char *passPhrase, int doPackage); -int packageSource(Spec s, char *passPhrase); - -#endif _PACK_H_ +int packageBinaries(Spec spec); +int packageSources(Spec spec); diff --git a/build/package.c b/build/package.c new file mode 100644 index 000000000..9184282a1 --- /dev/null +++ b/build/package.c @@ -0,0 +1,128 @@ +#include "spec.h" +#include "package.h" +#include "misc.h" +#include "rpmlib.h" +#include "files.h" + +#include <malloc.h> + +int lookupPackage(Spec spec, char *name, int flag, Package *pkg) +{ + char buf[BUFSIZ]; + char *n, *fullName; + Package p; + + /* "main" package */ + if (! name) { + if (pkg) { + *pkg = spec->packages; + } + return 0; + } + + /* Construct package name */ + if (flag == PART_SUBNAME) { + headerGetEntry(spec->packages->header, RPMTAG_NAME, + NULL, (void *) &n, NULL); + sprintf(buf, "%s-%s", n, name); + fullName = buf; + } else { + fullName = name; + } + + p = spec->packages; + while (p) { + headerGetEntry(p->header, RPMTAG_NAME, NULL, (void *) &n, NULL); + if (n && (! strcmp(fullName, n))) { + if (pkg) { + *pkg = p; + } + return 0; + } + p = p->next; + } + + if (pkg) { + *pkg = NULL; + } + return 1; +} + +Package newPackage(Spec spec) +{ + Package p; + Package pp; + + p = malloc(sizeof(*p)); + + p->header = headerNew(); + p->icon = NULL; + p->autoReqProv = 1; + +#if 0 + p->reqProv = NULL; + p->triggers = NULL; + p->triggerScripts = NULL; +#endif + + p->fileFile = NULL; + p->fileList = NULL; + p->next = NULL; + + p->cpioList = NULL; + p->cpioCount = 0; + + p->preInFile = NULL; + p->postInFile = NULL; + p->preUnFile = NULL; + p->postUnFile = NULL; + p->verifyFile = NULL; + + p->specialDoc = NULL; + + if (! spec->packages) { + spec->packages = p; + } else { + /* Always add package to end of list */ + pp = spec->packages; + while (pp->next) { + pp = pp->next; + } + pp->next = p; + } + + return p; +} + +void freePackages(Spec spec) +{ + Package p; + + while (spec->packages) { + p = spec->packages; + spec->packages = p->next; + freePackage(p); + } +} + +void freePackage(Package p) +{ + if (! p) { + return; + } + + FREE(p->preInFile); + FREE(p->postInFile); + FREE(p->preUnFile); + FREE(p->postUnFile); + FREE(p->verifyFile); + + headerFree(p->header); + freeStringBuf(p->fileList); + FREE(p->fileFile); + freeCpioList(p->cpioList, p->cpioCount); + + freeStringBuf(p->specialDoc); + + free(p); +} diff --git a/build/package.h b/build/package.h new file mode 100644 index 000000000..908638612 --- /dev/null +++ b/build/package.h @@ -0,0 +1,9 @@ +#ifndef _PACKAGE_H_ +#define _PACKAGE_H_ + +int lookupPackage(Spec spec, char *name, int flag, Package *pkg); +Package newPackage(Spec spec); +void freePackages(Spec spec); +void freePackage(Package p); + +#endif diff --git a/build/parse.h b/build/parse.h new file mode 100644 index 000000000..4b748282a --- /dev/null +++ b/build/parse.h @@ -0,0 +1,17 @@ +#ifndef _PARSE_H_ +#define _PARSE_H_ + +int parseChangelog(Spec spec); +int parseDescription(Spec spec); +int parseFiles(Spec spec); +int parsePreamble(Spec spec, int initialPackage); +int parsePrep(Spec spec); +int parseRequiresConflicts(Spec spec, Package pkg, char *field, int tag); +int parseProvidesObsoletes(Spec spec, Package pkg, char *field, int tag); +int parseScript(Spec spec, int parsePart); +int parseBuildInstallClean(Spec spec, int parsePart); + +int parseSpec(Spec *specp, char *specFile, char *buildRoot, + int inBuildArch, char *passPhrase, char *cookie); + +#endif diff --git a/build/parseBuildInstallClean.c b/build/parseBuildInstallClean.c new file mode 100644 index 000000000..fbb94401c --- /dev/null +++ b/build/parseBuildInstallClean.c @@ -0,0 +1,46 @@ +#include "read.h" +#include "part.h" +#include "rpmlib.h" + +int parseBuildInstallClean(Spec spec, int parsePart) +{ + int nextPart; + StringBuf *sbp = NULL; + char *name = NULL; + + switch (parsePart) { + case PART_BUILD: + sbp = &(spec->build); + name = "%build"; + break; + case PART_INSTALL: + sbp = &(spec->install); + name = "%install"; + break; + case PART_CLEAN: + sbp = &(spec->clean); + name = "%clean"; + break; + } + + if (*sbp) { + rpmError(RPMERR_BADSPEC, "line %d: second %s", spec->lineNum, name); + return RPMERR_BADSPEC; + } + + *sbp = newStringBuf(); + + /* There are no options to %build, %install, or %clean */ + if (readLine(spec, STRIP_NOTHING) > 0) { + return PART_NONE; + } + + while (! (nextPart = isPart(spec->line))) { + appendLineStringBuf(*sbp, spec->line); + if (readLine(spec, STRIP_NOTHING) > 0) { + return PART_NONE; + } + } + + return nextPart; +} diff --git a/build/parseChangelog.c b/build/parseChangelog.c new file mode 100644 index 000000000..7de812cf3 --- /dev/null +++ b/build/parseChangelog.c @@ -0,0 +1,211 @@ +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <sys/types.h> + + +#include "read.h" +#include "part.h" +#include "stringbuf.h" +#include "misc.h" +#include "header.h" +#include "rpmlib.h" + +static void addChangelogEntry(Header h, int time, char *name, char *text); +static int addChangelog(Header h, StringBuf sb); +static int dateToTimet(const char * datestr, time_t * secs); + +int parseChangelog(Spec spec) +{ + int nextPart, res; + StringBuf sb; + + sb = newStringBuf(); + + /* There are no options to %changelog */ + if (readLine(spec, STRIP_NOTHING) > 0) { + freeStringBuf(sb); + return PART_NONE; + } + + while (! (nextPart = isPart(spec->line))) { + appendLineStringBuf(sb, spec->line); + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + break; + } + } + + res = addChangelog(spec->packages->header, sb); + freeStringBuf(sb); + + return (res) ? res : nextPart; +} + +static int addChangelog(Header h, StringBuf sb) +{ + char *s; + int i; + int time, lastTime = 0; + char *date, *name, *text, *next; + + s = getStringBuf(sb); + + /* skip space */ + SKIPSPACE(s); + + while (*s) { + if (*s != '*') { + rpmError(RPMERR_BADSPEC, "%%changelog entries must start with *"); + return RPMERR_BADSPEC; + } + + /* find end of line */ + date = s; + SKIPTONEWLINE(s); + if (! *s) { + rpmError(RPMERR_BADSPEC, "incomplete %%changelog entry"); + return RPMERR_BADSPEC; + } + *s = '\0'; + text = s + 1; + + /* 4 fields of date */ + date++; + s = date; + for (i = 0; i < 4; i++) { + SKIPSPACE(s); + SKIPNONSPACE(s); + } + SKIPSPACE(date); + if (dateToTimet(date, (time_t *)&time)) { + rpmError(RPMERR_BADSPEC, "bad date in %%changelog: %s", date); + return RPMERR_BADSPEC; + } + if (lastTime && lastTime < time) { + rpmError(RPMERR_BADSPEC, + "%%changelog not in decending chronological order"); + return RPMERR_BADSPEC; + } + lastTime = time; + + /* skip space to the name */ + SKIPSPACE(s); + if (! *s) { + rpmError(RPMERR_BADSPEC, "missing name in %%changelog"); + return RPMERR_BADSPEC; + } + + /* name */ + name = s; + while (*s) s++; + while (s > name && isspace(*s)) { + *s-- = '\0'; + } + if (s == name) { + rpmError(RPMERR_BADSPEC, "missing name in %%changelog"); + return RPMERR_BADSPEC; + } + + /* text */ + SKIPSPACE(text); + if (! *text) { + rpmError(RPMERR_BADSPEC, "no description in %%changelog"); + return RPMERR_BADSPEC; + } + + /* find the next leading '*' (or eos) */ + s = text; + do { + s++; + } while (*s && (*(s-1) != '\n' || *s != '*')); + next = s; + s--; + + /* backup to end of description */ + while ((s > text) && isspace(*s)) { + *s-- = '\0'; + } + + addChangelogEntry(h, time, name, text); + s = next; + } + + return 0; +} + +static void addChangelogEntry(Header h, int time, char *name, char *text) +{ + if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) { + headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, + &time, 1); + headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, + &name, 1); + headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, + &text, 1); + } else { + headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, + &time, 1); + headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, + &name, 1); + headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, + &text, 1); + } +} + +/* datestr is of the form 'Wed Jan 1 1997' */ +static int dateToTimet(const char * datestr, time_t * secs) +{ + struct tm time; + char * chptr, * end, ** idx; + char * date = strcpy(alloca(strlen(datestr) + 1), datestr); + static char * days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + NULL }; + static char * months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; + static char lengths[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + memset(&time, 0, sizeof(time)); + + end = chptr = date; + + /* day of week */ + if ((chptr = strtok(date, " \t\n")) == NULL) return -1; + idx = days; + while (*idx && strcmp(*idx, chptr)) idx++; + if (!*idx) return -1; + + /* month */ + if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; + idx = months; + while (*idx && strcmp(*idx, chptr)) idx++; + if (!*idx) return -1; + + time.tm_mon = idx - months; + + /* day */ + if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; + + /* make this noon so the day is always right (as we make this UTC) */ + time.tm_hour = 12; + + time.tm_mday = strtol(chptr, &chptr, 10); + if (*chptr) return -1; + if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1; + + /* year */ + if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; + + time.tm_year = strtol(chptr, &chptr, 10); + if (*chptr) return -1; + if (time.tm_year < 1997 || time.tm_year >= 3000) return -1; + time.tm_year -= 1900; + + *secs = mktime(&time); + if (*secs == -1) return -1; + + /* adjust to GMT */ + *secs += timezone; + + return 0; +} diff --git a/build/parseDescription.c b/build/parseDescription.c new file mode 100644 index 000000000..01af29edc --- /dev/null +++ b/build/parseDescription.c @@ -0,0 +1,110 @@ +#include <malloc.h> + +#include "spec.h" +#include "header.h" +#include "read.h" +#include "part.h" +#include "misc.h" +#include "rpmlib.h" +#include "package.h" +#include "popt/popt.h" + +int parseDescription(Spec spec) +{ + int nextPart; + StringBuf sb; + char *name = NULL; + char *lang = RPMBUILD_DEFAULT_LANG; + int flag = PART_SUBNAME; + Package pkg; + int rc, argc; + char arg, **argv = NULL; + poptContext optCon = NULL; + struct poptOption optionsTable[] = { + { NULL, 'n', POPT_ARG_STRING, &name, 'n' }, + { NULL, 'l', POPT_ARG_STRING, &lang, 'l' }, + { 0, 0, 0, 0, 0 } + }; + + if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { + rpmError(RPMERR_BADSPEC, "line %d: Error parsing %%description: %s", + spec->lineNum, poptStrerror(rc)); + return RPMERR_BADSPEC; + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((arg = poptGetNextOpt(optCon)) > 0) { + if (arg == 'n') { + flag = PART_NAME; + } + } + + if (arg < -1) { + rpmError(RPMERR_BADSPEC, "line %d: Bad option %s: %s", + spec->lineNum, + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (poptPeekArg(optCon)) { + if (! name) { + name = poptGetArg(optCon); + } + if (poptPeekArg(optCon)) { + rpmError(RPMERR_BADSPEC, "line %d: Too many names: %s", + spec->lineNum, + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + } + + if (lookupPackage(spec, name, flag, &pkg)) { + rpmError(RPMERR_BADSPEC, "line %d: Package does not exist: %s", + spec->lineNum, spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + + /******************/ + +#if 0 + if (headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) { + rpmError(RPMERR_BADSPEC, "line %d: Second description", spec->lineNum); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } +#endif + + sb = newStringBuf(); + + if (readLine(spec, STRIP_TRAILINGSPACE) > 0) { + nextPart = PART_NONE; + } else { + while (! (nextPart = isPart(spec->line))) { + appendLineStringBuf(sb, spec->line); + if (readLine(spec, STRIP_TRAILINGSPACE) > 0) { + nextPart = PART_NONE; + break; + } + } + } + + stripTrailingBlanksStringBuf(sb); + headerAddI18NString(pkg->header, RPMTAG_DESCRIPTION, + getStringBuf(sb), lang); + + freeStringBuf(sb); + + FREE(argv); + poptFreeContext(optCon); + + return nextPart; +} diff --git a/build/parseFiles.c b/build/parseFiles.c new file mode 100644 index 000000000..68cd72e84 --- /dev/null +++ b/build/parseFiles.c @@ -0,0 +1,103 @@ +#include <string.h> +#include <malloc.h> + +#include "header.h" +#include "read.h" +#include "part.h" +#include "misc.h" +#include "rpmlib.h" +#include "package.h" +#include "stringbuf.h" +#include "popt/popt.h" + +int parseFiles(Spec spec) +{ + int nextPart; + Package pkg; + char *name = NULL; + char *file = NULL; + int rc, argc; + char arg, **argv = NULL; + int flag = PART_SUBNAME; + poptContext optCon = NULL; + struct poptOption optionsTable[] = { + { NULL, 'n', POPT_ARG_STRING, &name, 'n' }, + { NULL, 'f', POPT_ARG_STRING, &file, 'f' }, + { 0, 0, 0, 0, 0 } + }; + + if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { + rpmError(RPMERR_BADSPEC, "line %d: Error parsing %%files: %s", + spec->lineNum, poptStrerror(rc)); + return RPMERR_BADSPEC; + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((arg = poptGetNextOpt(optCon)) > 0) { + if (arg == 'n') { + flag = PART_NAME; + } + } + + if (arg < -1) { + rpmError(RPMERR_BADSPEC, "line %d: Bad option %s: %s", + spec->lineNum, + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (poptPeekArg(optCon)) { + if (! name) { + name = poptGetArg(optCon); + } + if (poptPeekArg(optCon)) { + rpmError(RPMERR_BADSPEC, "line %d: Too many names: %s", + spec->lineNum, + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + } + + if (lookupPackage(spec, name, flag, &pkg)) { + rpmError(RPMERR_BADSPEC, "line %d: Package does not exist: %s", + spec->lineNum, spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (pkg->fileList) { + rpmError(RPMERR_BADSPEC, "line %d: Second %%files list", + spec->lineNum); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (file) { + pkg->fileFile = strdup(file); + } + pkg->fileList = newStringBuf(); + + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + } else { + while (! (nextPart = isPart(spec->line))) { + appendLineStringBuf(pkg->fileList, spec->line); + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + break; + } + } + } + + FREE(argv); + poptFreeContext(optCon); + + return nextPart; +} diff --git a/build/parsePreamble.c b/build/parsePreamble.c new file mode 100644 index 000000000..cf87f9ef2 --- /dev/null +++ b/build/parsePreamble.c @@ -0,0 +1,631 @@ +#include <string.h> +#include <malloc.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> + +#include "read.h" +#include "part.h" +#include "rpmlib.h" +#include "spec.h" +#include "package.h" +#include "misc.h" +#include "reqprov.h" +#include "parse.h" +#include "popt/popt.h" + +static int copyTags[] = { + RPMTAG_VERSION, + RPMTAG_RELEASE, + RPMTAG_COPYRIGHT, + RPMTAG_PACKAGER, + RPMTAG_DISTRIBUTION, + RPMTAG_VENDOR, + RPMTAG_ICON, + 0 +}; + +static int requiredTags[] = { + RPMTAG_NAME, + RPMTAG_VERSION, + RPMTAG_RELEASE, + RPMTAG_SUMMARY, + RPMTAG_GROUP, + RPMTAG_COPYRIGHT, + RPMTAG_PACKAGER, + RPMTAG_DISTRIBUTION, + RPMTAG_VENDOR, + 0 +}; + +static int handlePreambleTag(Spec spec, Package pkg, int tag, char *macro, + char *lang); +static void initPreambleList(void); +static int findPreambleTag(Spec spec, int *tag, char **macro, char *lang); +static int checkForRequired(Header h, char *name); +static void copyFromMain(Spec spec, Package pkg); +static int checkForDuplicates(Header h, char *name); +static void fillOutMainPackage(Header h); +static char *tagName(int tag); +static int checkForValidArchitectures(Spec spec); +static int isMemberInEntry(Header header, char *name, int tag); +static int readIcon(Header h, char *file); + +int parsePreamble(Spec spec, int initialPackage) +{ + int nextPart; + int tag; + char *name, *mainName, *linep, *macro; + int flag; + Package pkg; + char fullName[BUFSIZ]; + char lang[BUFSIZ]; + + strcpy(fullName, "(main package)"); + + pkg = newPackage(spec); + + if (! initialPackage) { + /* There is one option to %package: <pkg> or -n <pkg> */ + if (parseSimplePart(spec->line, &name, &flag)) { + rpmError(RPMERR_BADSPEC, "Bad package specification: %s", + spec->line); + return RPMERR_BADSPEC; + } + + if (!lookupPackage(spec, name, flag, NULL)) { + rpmError(RPMERR_BADSPEC, "Package already exists: %s", spec->line); + return RPMERR_BADSPEC; + } + + /* Construct the package */ + if (flag == PART_SUBNAME) { + headerGetEntry(spec->packages->header, RPMTAG_NAME, + NULL, (void *) &mainName, NULL); + sprintf(fullName, "%s-%s", mainName, name); + } else { + strcpy(fullName, name); + } + headerAddEntry(pkg->header, RPMTAG_NAME, RPM_STRING_TYPE, fullName, 1); + } + + if (readLine(spec, STRIP_TRAILINGSPACE) > 0) { + nextPart = PART_NONE; + } else { + while (! (nextPart = isPart(spec->line))) { + /* Skip blank lines */ + linep = spec->line; + SKIPSPACE(linep); + if (*linep) { + if (findPreambleTag(spec, &tag, ¯o, lang)) { + rpmError(RPMERR_BADSPEC, "line %d: Unknown tag: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + if (handlePreambleTag(spec, pkg, tag, macro, lang)) { + return RPMERR_BADSPEC; + } + if (spec->buildArchitectures && !spec->inBuildArchitectures) { + return PART_BUILDARCHITECTURES; + } + } + if (readLine(spec, STRIP_TRAILINGSPACE) > 0) { + nextPart = PART_NONE; + break; + } + } + } + + /* Do some final processing on the header */ + + if (!spec->gotBuildRoot && spec->buildRoot) { + rpmError(RPMERR_BADSPEC, "Spec file can't use BuildRoot"); + return RPMERR_BADSPEC; + } + + if (checkForValidArchitectures(spec)) { + return RPMERR_BADSPEC; + } + + if (pkg == spec->packages) { + fillOutMainPackage(pkg->header); + } + + if (checkForDuplicates(pkg->header, fullName)) { + return RPMERR_BADSPEC; + } + + if (pkg != spec->packages) { + copyFromMain(spec, pkg); + } + + if (checkForRequired(pkg->header, fullName)) { + return RPMERR_BADSPEC; + } + + return nextPart; +} + +static int isMemberInEntry(Header header, char *name, int tag) +{ + char **names; + int count; + + if (headerGetEntry(header, tag, NULL, (void **)&names, &count)) { + while (count--) { + if (!strcmp(names[count], name)) { + FREE(names); + return 1; + } + } + FREE(names); + return 0; + } + + return -1; +} + +static int checkForValidArchitectures(Spec spec) +{ + char *arch, *os; + + rpmGetArchInfo(&arch, NULL); + rpmGetOsInfo(&os, NULL); + + if (isMemberInEntry(spec->buildRestrictions, + arch, RPMTAG_EXCLUDEARCH) == 1) { + rpmError(RPMERR_BADSPEC, "Architecture is excluded: %s", arch); + return RPMERR_BADSPEC; + } + if (isMemberInEntry(spec->buildRestrictions, + arch, RPMTAG_EXCLUSIVEARCH) == 0) { + rpmError(RPMERR_BADSPEC, "Architecture is not included: %s", arch); + return RPMERR_BADSPEC; + } + if (isMemberInEntry(spec->buildRestrictions, + os, RPMTAG_EXCLUDEOS) == 1) { + rpmError(RPMERR_BADSPEC, "OS is excluded: %s", os); + return RPMERR_BADSPEC; + } + if (isMemberInEntry(spec->buildRestrictions, + os, RPMTAG_EXCLUSIVEOS) == 0) { + rpmError(RPMERR_BADSPEC, "OS is not included: %s", os); + return RPMERR_BADSPEC; + } + + return 0; +} + +static int checkForRequired(Header h, char *name) +{ + int res = 0; + int *p = requiredTags; + + while (*p) { + if (!headerIsEntry(h, *p)) { + rpmError(RPMERR_BADSPEC, "%s field must be present in package: %s", + tagName(*p), name); + res = 1; + } + p++; + } + + return res; +} + +static void copyFromMain(Spec spec, Package pkg) +{ + Header headerFrom, headerTo; + int *p = copyTags; + char *s; + int type, count; + + headerFrom = spec->packages->header; + headerTo = pkg->header; + + while (*p) { + if (!headerIsEntry(headerTo, *p)) { + if (headerGetEntry(headerFrom, *p, &type, (void **) &s, &count)) { + headerAddEntry(headerTo, *p, type, s, count); + if (type == RPM_STRING_ARRAY_TYPE) { + FREE(s); + } + } + } + p++; + } +} + +static int checkForDuplicates(Header h, char *name) +{ + int res = 0; + int lastTag, tag; + HeaderIterator hi; + + headerSort(h); + hi = headerInitIterator(h); + lastTag = 0; + while (headerNextIterator(hi, &tag, NULL, NULL, NULL)) { + if (tag == lastTag) { + rpmError(RPMERR_BADSPEC, "Duplicate %s entries in package: %s", + tagName(tag), name); + res = 1; + } + lastTag = tag; + } + headerFreeIterator(hi); + + return res; +} + +static void fillOutMainPackage(Header h) +{ + if (!headerIsEntry(h, RPMTAG_VENDOR)) { + if (rpmGetVar(RPMVAR_VENDOR)) { + headerAddEntry(h, RPMTAG_VENDOR, RPM_STRING_TYPE, + rpmGetVar(RPMVAR_VENDOR), 1); + } + } + if (!headerIsEntry(h, RPMTAG_PACKAGER)) { + if (rpmGetVar(RPMVAR_PACKAGER)) { + headerAddEntry(h, RPMTAG_PACKAGER, RPM_STRING_TYPE, + rpmGetVar(RPMVAR_PACKAGER), 1); + } + } + if (!headerIsEntry(h, RPMTAG_DISTRIBUTION)) { + if (rpmGetVar(RPMVAR_DISTRIBUTION)) { + headerAddEntry(h, RPMTAG_DISTRIBUTION, RPM_STRING_TYPE, + rpmGetVar(RPMVAR_DISTRIBUTION), 1); + } + } +} + +#define SINGLE_TOKEN_ONLY \ +if (multiToken) { \ + rpmError(RPMERR_BADSPEC, "line %d: Tag takes single token only: %s", \ + spec->lineNum, spec->line); \ + return RPMERR_BADSPEC; \ +} + +static int handlePreambleTag(Spec spec, Package pkg, int tag, char *macro, + char *lang) +{ + char *field = spec->line; + char *end; + int multiToken = 0; + int num, rc; + + /* Find the start of the "field" and strip trailing space */ + while ((*field) && (*field != ':')) { + field++; + } + if (*field != ':') { + rpmError(RPMERR_BADSPEC, "line %d: Malformed tag: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + field++; + SKIPSPACE(field); + if (! *field) { + /* Empty field */ + rpmError(RPMERR_BADSPEC, "line %d: Empty tag: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + end = findLastChar(field); + *(end+1) = '\0'; + + /* See if this is multi-token */ + end = field; + SKIPNONSPACE(end); + if (*end) { + multiToken = 1; + } + + if (macro) { + addMacro(&spec->macros, macro, field); + } + + switch (tag) { + case RPMTAG_NAME: + case RPMTAG_VERSION: + case RPMTAG_RELEASE: + case RPMTAG_GROUP: + case RPMTAG_URL: + SINGLE_TOKEN_ONLY; + /* These are for backward compatibility */ + if (tag == RPMTAG_VERSION) { + addMacro(&spec->macros, "PACKAGE_VERSION", field); + } else if (tag == RPMTAG_RELEASE) { + addMacro(&spec->macros, "PACKAGE_RELEASE", field); + } + /* fall through */ + case RPMTAG_SUMMARY: + case RPMTAG_DISTRIBUTION: + case RPMTAG_VENDOR: + case RPMTAG_COPYRIGHT: + case RPMTAG_PACKAGER: + if (! *lang) { + headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1); + } else { + headerAddI18NString(pkg->header, tag, field, lang); + } + break; + case RPMTAG_BUILDROOT: + SINGLE_TOKEN_ONLY; + if (! spec->buildRoot) { + if (rpmGetVar(RPMVAR_BUILDROOT)) { + spec->buildRoot = strdup(rpmGetVar(RPMVAR_BUILDROOT)); + } else { + spec->buildRoot = strdup(field); + } + } + if (!strcmp(spec->buildRoot, "/")) { + rpmError(RPMERR_BADSPEC, + "line %d: BuildRoot can not be \"/\": %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + spec->gotBuildRoot = 1; + break; + case RPMTAG_DEFAULTPREFIX: + SINGLE_TOKEN_ONLY; + if (field[0] != '/') { + rpmError(RPMERR_BADSPEC, + "line %d: Prefix must begin with '/': %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, field, 1); + break; + case RPMTAG_DOCDIR: + SINGLE_TOKEN_ONLY; + FREE(spec->docDir); + if (field[0] != '/') { + rpmError(RPMERR_BADSPEC, + "line %d: Docdir must begin with '/': %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + spec->docDir = strdup(field); + break; + case RPMTAG_SERIAL: + SINGLE_TOKEN_ONLY; + if (parseNum(field, &num)) { + rpmError(RPMERR_BADSPEC, + "line %d: Serial field must be a number: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + headerAddEntry(pkg->header, tag, RPM_INT32_TYPE, &num, 1); + break; + case RPMTAG_AUTOREQPROV: + spec->autoReqProv = parseYesNo(field); + break; + case RPMTAG_SOURCE: + case RPMTAG_PATCH: + SINGLE_TOKEN_ONLY; + if ((rc = addSource(spec, pkg, field, tag))) { + return rc; + } + break; + case RPMTAG_ICON: + SINGLE_TOKEN_ONLY; + if ((rc = addSource(spec, pkg, field, tag))) { + return rc; + } + if ((rc = readIcon(pkg->header, field))) { + return RPMERR_BADSPEC; + } + break; + case RPMTAG_NOSOURCE: + case RPMTAG_NOPATCH: + spec->noSource = 1; + if ((rc = parseNoSource(spec, field, tag))) { + return rc; + } + break; + case RPMTAG_OBSOLETES: + case RPMTAG_PROVIDES: + if ((rc = parseProvidesObsoletes(spec, pkg, field, tag))) { + return rc; + } + break; + case RPMTAG_REQUIREFLAGS: + case RPMTAG_CONFLICTFLAGS: + case RPMTAG_PREREQ: + if ((rc = parseRequiresConflicts(spec, pkg, field, tag))) { + return rc; + } + break; + case RPMTAG_EXCLUDEARCH: + case RPMTAG_EXCLUSIVEARCH: + case RPMTAG_EXCLUDEOS: + case RPMTAG_EXCLUSIVEOS: + addOrAppendListEntry(spec->buildRestrictions, tag, field); + break; + case RPMTAG_BUILDARCHS: + if ((rc = poptParseArgvString(field, + &(spec->buildArchitectureCount), + &(spec->buildArchitectures)))) { + rpmError(RPMERR_BADSPEC, + "line %d: Bad BuildArchitecture format: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + if (! spec->buildArchitectureCount) { + FREE(spec->buildArchitectures); + } + break; + + default: + rpmError(RPMERR_INTERNAL, "Internal error: Bogus tag %d", tag); + return RPMERR_INTERNAL; + } + + return 0; +} + +static struct PreambleRec { + int tag; + int len; + int multiLang; + char *token; +} preambleList[] = { + {RPMTAG_NAME, 0, 0, "name"}, + {RPMTAG_VERSION, 0, 0, "version"}, + {RPMTAG_RELEASE, 0, 0, "release"}, + {RPMTAG_SERIAL, 0, 0, "serial"}, +/* {RPMTAG_DESCRIPTION, 0, "description"}, */ + {RPMTAG_SUMMARY, 0, 1, "summary"}, + {RPMTAG_COPYRIGHT, 0, 0, "copyright"}, + {RPMTAG_COPYRIGHT, 0, 0, "license"}, + {RPMTAG_DISTRIBUTION, 0, 0, "distribution"}, + {RPMTAG_VENDOR, 0, 0, "vendor"}, + {RPMTAG_GROUP, 0, 0, "group"}, + {RPMTAG_PACKAGER, 0, 0, "packager"}, + {RPMTAG_URL, 0, 0, "url"}, +/* {RPMTAG_ROOT, 0, "root"}, */ + {RPMTAG_SOURCE, 0, 0, "source"}, + {RPMTAG_PATCH, 0, 0, "patch"}, + {RPMTAG_NOSOURCE, 0, 0, "nosource"}, + {RPMTAG_NOPATCH, 0, 0, "nopatch"}, + {RPMTAG_EXCLUDEARCH, 0, 0, "excludearch"}, + {RPMTAG_EXCLUSIVEARCH, 0, 0, "exclusivearch"}, + {RPMTAG_EXCLUDEOS, 0, 0, "excludeos"}, + {RPMTAG_EXCLUSIVEOS, 0, 0, "exclusiveos"}, +/* {RPMTAG_EXCLUDE, 0, "exclude"}, */ +/* {RPMTAG_EXCLUSIVE, 0, "exclusive"}, */ + {RPMTAG_ICON, 0, 0, "icon"}, + {RPMTAG_PROVIDES, 0, 0, "provides"}, + {RPMTAG_REQUIREFLAGS, 0, 0, "requires"}, + {RPMTAG_PREREQ, 0, 0, "prereq"}, + {RPMTAG_CONFLICTFLAGS, 0, 0, "conflicts"}, + {RPMTAG_OBSOLETES, 0, 0, "obsoletes"}, + {RPMTAG_DEFAULTPREFIX, 0, 0, "prefix"}, + {RPMTAG_BUILDROOT, 0, 0, "buildroot"}, + {RPMTAG_BUILDARCHS, 0, 0, "buildarchitectures"}, + {RPMTAG_AUTOREQPROV, 0, 0, "autoreqprov"}, + {RPMTAG_DOCDIR, 0, 0, "docdir"}, + {0, 0, 0, 0} +}; + +static void initPreambleList(void) +{ + struct PreambleRec *p = preambleList; + + while (p->token) { + p->len = strlen(p->token); + p++; + } +} + +static int findPreambleTag(Spec spec, int *tag, char **macro, char *lang) +{ + char *s; + struct PreambleRec *p = preambleList; + + if (! p->len) { + initPreambleList(); + } + + while (p->token && strncasecmp(spec->line, p->token, p->len)) { + p++; + } + + if (!p->token) { + return 1; + } + + s = spec->line + p->len; + SKIPSPACE(s); + + if (! p->multiLang) { + /* Unless this is a source or a patch, a ':' better be next */ + if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) { + if (*s != ':') { + return 1; + } + } + *lang = '\0'; + } else { + if (*s != ':') { + if (*s != '(') return 1; + s++; + SKIPSPACE(s); + while (! isspace(*s) && *s != ')') { + *lang++ = *s++; + } + *lang = '\0'; + SKIPSPACE(s); + if (*s != ')') return 1; + s++; + SKIPSPACE(s); + if (*s != ':') return 1; + } else { + strcpy(lang, RPMBUILD_DEFAULT_LANG); + } + } + + *tag = p->tag; + if (macro) { + *macro = p->token; + } + return 0; +} + +static char *tagName(int tag) +{ + int i = 0; + static char nameBuf[1024]; + char *s; + + strcpy(nameBuf, "(unknown)"); + while (i < rpmTagTableSize) { + if (tag == rpmTagTable[i].val) { + strcpy(nameBuf, rpmTagTable[i].name + 7); + s = nameBuf+1; + while (*s) { + *s = tolower(*s); + s++; + } + } + i++; + } + + return nameBuf; +} + +static int readIcon(Header h, char *file) +{ + char buf[BUFSIZ], *icon; + struct stat statbuf; + int fd; + + sprintf(buf, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), file); + if (stat(buf, &statbuf)) { + rpmError(RPMERR_BADSPEC, "Unable to read icon: %s", file); + return RPMERR_BADSPEC; + } + icon = malloc(statbuf.st_size); + fd = open(buf, O_RDONLY); + if (read(fd, icon, statbuf.st_size) != statbuf.st_size) { + close(fd); + rpmError(RPMERR_BADSPEC, "Unable to read icon: %s", file); + return RPMERR_BADSPEC; + } + close(fd); + + if (! strncmp(icon, "GIF", 3)) { + headerAddEntry(h, RPMTAG_GIF, RPM_BIN_TYPE, icon, statbuf.st_size); + } else if (! strncmp(icon, "/* XPM", 6)) { + headerAddEntry(h, RPMTAG_XPM, RPM_BIN_TYPE, icon, statbuf.st_size); + } else { + rpmError(RPMERR_BADSPEC, "Unknown icon type: %s", file); + return RPMERR_BADSPEC; + } + free(icon); + + return 0; +} diff --git a/build/parsePrep.c b/build/parsePrep.c new file mode 100644 index 000000000..bf611ea64 --- /dev/null +++ b/build/parsePrep.c @@ -0,0 +1,480 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <malloc.h> +#include <errno.h> + +#include "spec.h" +#include "read.h" +#include "part.h" +#include "rpmlib.h" +#include "lib/misc.h" +#include "popt/popt.h" +#include "names.h" +#include "misc.h" +#include "config.h" + +static int doSetupMacro(Spec spec, char *line); +static int doPatchMacro(Spec spec, char *line); +static char *doPatch(Spec spec, int c, int strip, char *db, + int reverse, int removeEmpties); +static int isCompressed(char *file, int *compressed); +static int checkOwners(char *file); +static char *doUntar(Spec spec, int c, int quietly); + +int parsePrep(Spec spec) +{ + int nextPart, res; + StringBuf buf; + char **lines, **saveLines; + + if (spec->prep) { + rpmError(RPMERR_BADSPEC, "line %d: second %%prep", spec->lineNum); + return RPMERR_BADSPEC; + } + + spec->prep = newStringBuf(); + + buf = newStringBuf(); + + /* There are no options to %prep */ + if (readLine(spec, STRIP_NOTHING) > 0) { + return PART_NONE; + } + + while (! (nextPart = isPart(spec->line))) { + /* Need to expand the macros inline. That way we */ + /* can give good line number information on error. */ + appendLineStringBuf(buf, spec->line); + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + break; + } + } + + lines = splitString(getStringBuf(buf), strlen(getStringBuf(buf)), '\n'); + saveLines = lines; + while (*lines) { + res = 0; + if (! strncmp(*lines, "%setup", 6)) { + res = doSetupMacro(spec, *lines); + } else if (! strncmp(*lines, "%patch", 6)) { + res = doPatchMacro(spec, *lines); + } else { + appendLineStringBuf(spec->prep, *lines); + } + if (res) { + freeSplitString(saveLines); + return res; + } + lines++; + } + freeSplitString(saveLines); + + return nextPart; +} + +static int doSetupMacro(Spec spec, char *line) +{ + char *version, *name; + int leaveDirs = 0, skipDefaultAction = 0; + int createDir = 0, quietly = 0; + char * dirName = NULL; + char buf[BUFSIZ]; + StringBuf before; + StringBuf after; + poptContext optCon; + int argc; + char ** argv; + int arg; + char * optArg; + char * chptr; + int rc; + int num; + struct poptOption optionsTable[] = { + { NULL, 'a', POPT_ARG_STRING, NULL, 'a' }, + { NULL, 'b', POPT_ARG_STRING, NULL, 'b' }, + { NULL, 'c', 0, &createDir, 0 }, + { NULL, 'D', 0, &leaveDirs, 0 }, + { NULL, 'n', POPT_ARG_STRING, &dirName, 0 }, + { NULL, 'T', 0, &skipDefaultAction, 0 }, + { NULL, 'q', 0, &quietly, 0 }, + { 0, 0, 0, 0, 0 } + }; + + if ((rc = poptParseArgvString(line, &argc, &argv))) { + rpmError(RPMERR_BADSPEC, "Error parsing %%setup: %s", + poptStrerror(rc)); + return RPMERR_BADSPEC; + } + + before = newStringBuf(); + after = newStringBuf(); + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((arg = poptGetNextOpt(optCon)) > 0) { + optArg = poptGetOptArg(optCon); + + /* We only parse -a and -b here */ + + if (parseNum(optArg, &num)) { + rpmError(RPMERR_BADSPEC, "line %d: Bad arg to %%setup %c: %s", + spec->lineNum, num, optArg); + free(argv); + freeStringBuf(before); + freeStringBuf(after); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + chptr = doUntar(spec, num, quietly); + if (!chptr) { + return RPMERR_BADSPEC; + } + + if (arg == 'a') + appendLineStringBuf(after, chptr); + else + appendLineStringBuf(before, chptr); + } + + if (arg < -1) { + rpmError(RPMERR_BADSPEC, "line %d: Bad %%setup option %s: %s", + spec->lineNum, + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(arg)); + free(argv); + freeStringBuf(before); + freeStringBuf(after); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (dirName) { + spec->buildSubdir = strdup(dirName); + } else { + headerGetEntry(spec->packages->header, RPMTAG_VERSION, NULL, + (void *) &version, NULL); + headerGetEntry(spec->packages->header, RPMTAG_NAME, NULL, + (void *) &name, NULL); + sprintf(buf, "%s-%s", name, version); + spec->buildSubdir = strdup(buf); + } + + free(argv); + poptFreeContext(optCon); + + /* cd to the build dir */ + sprintf(buf, "cd %s", rpmGetVar(RPMVAR_BUILDDIR)); + appendLineStringBuf(spec->prep, buf); + + /* delete any old sources */ + if (!leaveDirs) { + sprintf(buf, "rm -rf %s", spec->buildSubdir); + appendLineStringBuf(spec->prep, buf); + } + + /* if necessary, create and cd into the proper dir */ + if (createDir) { + sprintf(buf, "mkdir -p %s\ncd %s", + spec->buildSubdir, spec->buildSubdir); + appendLineStringBuf(spec->prep, buf); + } + + /* do the default action */ + if (!createDir && !skipDefaultAction) { + chptr = doUntar(spec, 0, quietly); + if (!chptr) { + return RPMERR_BADSPEC; + } + appendLineStringBuf(spec->prep, chptr); + } + + appendStringBuf(spec->prep, getStringBuf(before)); + freeStringBuf(before); + + if (!createDir) { + sprintf(buf, "cd %s", spec->buildSubdir); + appendLineStringBuf(spec->prep, buf); + } + + if (createDir && !skipDefaultAction) { + chptr = doUntar(spec, 0, quietly); + if (!chptr) { + return RPMERR_BADSPEC; + } + appendLineStringBuf(spec->prep, chptr); + } + + appendStringBuf(spec->prep, getStringBuf(after)); + freeStringBuf(after); + + /* clean up permissions etc */ + if (!geteuid()) { + appendLineStringBuf(spec->prep, "chown -R root ."); + appendLineStringBuf(spec->prep, "chgrp -R root ."); + } + + if (rpmGetVar(RPMVAR_FIXPERMS)) { + appendStringBuf(spec->prep, "chmod -R "); + appendStringBuf(spec->prep, rpmGetVar(RPMVAR_FIXPERMS)); + appendLineStringBuf(spec->prep, " ."); + } + + return 0; +} + +static char *doUntar(Spec spec, int c, int quietly) +{ + static char buf[BUFSIZ]; + char file[BUFSIZ]; + char *s, *taropts; + struct Source *sp; + int compressed; + + s = NULL; + sp = spec->sources; + while (sp) { + if ((sp->flags & RPMBUILD_ISSOURCE) && (sp->num == c)) { + s = sp->source; + break; + } + sp = sp->next; + } + if (! s) { + rpmError(RPMERR_BADSPEC, "No source number %d", c); + return NULL; + } + + sprintf(file, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), s); + taropts = (rpmIsVerbose() && !quietly ? "-xvvf" : "-xf"); + + if (isCompressed(file, &compressed)) { + return NULL; + } + if (checkOwners(file)) { + return NULL; + } + if (compressed) { + sprintf(buf, + "%s -dc %s | tar %s -\n" + "if [ $? -ne 0 ]; then\n" + " exit $?\n" + "fi", + rpmGetVar(RPMVAR_GZIPBIN), file, taropts); + } else { + sprintf(buf, "tar %s %s", taropts, file); + } + + return buf; +} + +static int doPatchMacro(Spec spec, char *line) +{ + char *opt_b; + int opt_P, opt_p, opt_R, opt_E; + char *s; + char buf[BUFSIZ]; + int patch_nums[1024]; /* XXX - we can only handle 1024 patches! */ + int patch_index, x; + + opt_P = opt_p = opt_R = opt_E = 0; + opt_b = NULL; + patch_index = 0; + + if (! strchr(" \t\n", line[6])) { + /* %patchN */ + sprintf(buf, "%%patch -P %s", line + 6); + } else { + strcpy(buf, line); + } + + strtok(buf, " \t\n"); /* remove %patch */ + while ((s = strtok(NULL, " \t\n"))) { + if (!strcmp(s, "-P")) { + opt_P = 1; + } else if (!strcmp(s, "-R")) { + opt_R = 1; + } else if (!strcmp(s, "-E")) { + opt_E = 1; + } else if (!strcmp(s, "-b")) { + /* orig suffix */ + opt_b = strtok(NULL, " \t\n"); + if (! opt_b) { + rpmError(RPMERR_BADSPEC, "line %d: Need arg to %%patch -b: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + } else if (!strcmp(s, "-z")) { + /* orig suffix */ + opt_b = strtok(NULL, " \t\n"); + if (! opt_b) { + rpmError(RPMERR_BADSPEC, "line %d: Need arg to %%patch -z: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + } else if (!strncmp(s, "-p", 2)) { + /* unfortunately, we must support -pX */ + if (! strchr(" \t\n", s[2])) { + s = s + 2; + } else { + s = strtok(NULL, " \t\n"); + if (! s) { + rpmError(RPMERR_BADSPEC, + "line %d: Need arg to %%patch -p: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + } + if (parseNum(s, &opt_p)) { + rpmError(RPMERR_BADSPEC, "line %d: Bad arg to %%patch -p: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + } else { + /* Must be a patch num */ + if (patch_index == 1024) { + rpmError(RPMERR_BADSPEC, "Too many patches!"); + return RPMERR_BADSPEC; + } + if (parseNum(s, &(patch_nums[patch_index]))) { + rpmError(RPMERR_BADSPEC, "line %d: Bad arg to %%patch: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + patch_index++; + } + } + + /* All args processed */ + + if (! opt_P) { + s = doPatch(spec, 0, opt_p, opt_b, opt_R, opt_E); + if (! s) { + return RPMERR_BADSPEC; + } + appendLineStringBuf(spec->prep, s); + } + + x = 0; + while (x < patch_index) { + s = doPatch(spec, patch_nums[x], opt_p, opt_b, opt_R, opt_E); + if (! s) { + return RPMERR_BADSPEC; + } + appendLineStringBuf(spec->prep, s); + x++; + } + + return 0; +} + +static char *doPatch(Spec spec, int c, int strip, char *db, + int reverse, int removeEmpties) +{ + static char buf[BUFSIZ]; + char file[BUFSIZ]; + char args[BUFSIZ]; + char *s; + struct Source *sp; + int compressed; + + s = NULL; + sp = spec->sources; + while (sp) { + if ((sp->flags & RPMBUILD_ISPATCH) && (sp->num == c)) { + s = sp->source; + break; + } + sp = sp->next; + } + if (! s) { + rpmError(RPMERR_BADSPEC, "No patch number %d", c); + return NULL; + } + + sprintf(file, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), s); + + args[0] = '\0'; + if (db) { +#if HAVE_OLDPATCH_21 == 0 + strcat(args, "-b "); +#endif + strcat(args, "--suffix "); + strcat(args, db); + } + if (reverse) { + strcat(args, " -R"); + } + if (removeEmpties) { + strcat(args, " -E"); + } + + if (isCompressed(file, &compressed)) { + return NULL; + } + if (checkOwners(file)) { + return NULL; + } + if (compressed) { + sprintf(buf, + "echo \"Patch #%d:\"\n" + "%s -dc %s | patch -p%d %s -s\n" + "if [ $? -ne 0 ]; then\n" + " exit $?\n" + "fi", + c, rpmGetVar(RPMVAR_GZIPBIN), file, strip, args); + } else { + sprintf(buf, + "echo \"Patch #%d:\"\n" + "patch -p%d %s -s < %s", c, strip, args, file); + } + + return buf; +} + +static int checkOwners(char *file) +{ + struct stat sb; + + if (lstat(file, &sb)) { + rpmError(RPMERR_BADSPEC, "Bad source: %s: %s", file, strerror(errno)); + return RPMERR_BADSPEC; + } + if (!getUname(sb.st_uid) || !getGname(sb.st_gid)) { + rpmError(RPMERR_BADSPEC, "Bad owner/group: %s", file); + return RPMERR_BADSPEC; + } + + return 0; +} + +static int isCompressed(char *file, int *compressed) +{ + int fd; + unsigned char magic[4]; + + *compressed = 0; + + if (!(fd = open(file, O_RDONLY))) { + return 1; + } + if (! read(fd, magic, 4)) { + return 1; + } + close(fd); + + if (((magic[0] == 0037) && (magic[1] == 0213)) || /* gzip */ + ((magic[0] == 0037) && (magic[1] == 0236)) || /* old gzip */ + ((magic[0] == 0037) && (magic[1] == 0036)) || /* pack */ + ((magic[0] == 0037) && (magic[1] == 0240)) || /* SCO lzh */ + ((magic[0] == 0037) && (magic[1] == 0235)) || /* compress */ + ((magic[0] == 0120) && (magic[1] == 0113) && + (magic[2] == 0003) && (magic[3] == 0004)) /* pkzip */ + ) { + *compressed = 1; + } + + return 0; +} diff --git a/build/parseReqs.c b/build/parseReqs.c new file mode 100644 index 000000000..87241ade2 --- /dev/null +++ b/build/parseReqs.c @@ -0,0 +1,125 @@ +#include <string.h> + +#include "spec.h" +#include "rpmlib.h" +#include "reqprov.h" + +static struct ReqComp { + char *token; + int sense; +} ReqComparisons[] = { + { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL}, + { "<=S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL}, + { "=<S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + { "<", RPMSENSE_LESS}, + { "<S", RPMSENSE_LESS | RPMSENSE_SERIAL}, + + { "=", RPMSENSE_EQUAL}, + { "=S", RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + + { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL}, + { ">=S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL}, + { "=>S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + { ">", RPMSENSE_GREATER}, + { ">S", RPMSENSE_GREATER | RPMSENSE_SERIAL}, + { NULL, 0 }, +}; + +int parseRequiresConflicts(Spec spec, Package pkg, char *field, int tag) +{ + char buf[BUFSIZ], *bufp, *version, *name; + int flags; + char *req = NULL; + struct ReqComp *rc; + + strcpy(buf, field); + bufp = buf; + + while (req || (req = strtok(bufp, " ,\t\n"))) { + bufp = NULL; + + if (tag == RPMTAG_CONFLICTFLAGS) { + if (req[0] == '/') { + rpmError(RPMERR_BADSPEC, + "line %d: No file names in Conflicts: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + flags = RPMSENSE_CONFLICTS; + name = "Conflicts"; + } else if (tag == RPMTAG_PREREQ) { + flags = RPMSENSE_PREREQ; + name = "PreReq"; + } else { + flags = RPMSENSE_ANY; + name = "Requires"; + } + + if ((version = strtok(NULL, " ,\t\n"))) { + rc = ReqComparisons; + while (rc->token && strcmp(version, rc->token)) { + rc++; + } + if (rc->token) { + if (req[0] == '/') { + rpmError(RPMERR_BADSPEC, + "line %d: No versions on file names in %s: %s", + spec->lineNum, name, spec->line); + return RPMERR_BADSPEC; + } + if (tag == RPMTAG_PREREQ) { + rpmError(RPMERR_BADSPEC, + "line %d: No versions in PreReq: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; + } + /* read a version */ + flags |= rc->sense; + version = strtok(NULL, " ,\t\n"); + } + } + + if ((flags & RPMSENSE_SENSEMASK) && !version) { + rpmError(RPMERR_BADSPEC, + "line %d: Version required in %s: %s", + spec->lineNum, name, spec->line); + return RPMERR_BADSPEC; + } + + addReqProv(spec, pkg, flags, req, + (flags & RPMSENSE_SENSEMASK) ? version : NULL); + + /* If there is no sense, we just read the next token */ + req = (flags & RPMSENSE_SENSEMASK) ? NULL : version; + } + + return 0; +} + +int parseProvidesObsoletes(Spec spec, Package pkg, char *field, int tag) +{ + char *prov, buf[BUFSIZ], *line; + int flags; + + flags = (tag == RPMTAG_PROVIDES) ? RPMSENSE_PROVIDES : RPMSENSE_OBSOLETES; + + strcpy(buf, field); + line = buf; + + while ((prov = strtok(line, " ,\t\n"))) { + if (prov[0] == '/') { + rpmError(RPMERR_BADSPEC, + "line %d: No file names in %s: %s", + spec->lineNum, + (tag == RPMTAG_PROVIDES) ? "Provides" : "Obsoletes", + spec->line); + return RPMERR_BADSPEC; + } + addReqProv(spec, pkg, flags, prov, NULL); + line = NULL; + } + + return 0; +} diff --git a/build/parseScript.c b/build/parseScript.c new file mode 100644 index 000000000..b2f604f37 --- /dev/null +++ b/build/parseScript.c @@ -0,0 +1,199 @@ +#include <malloc.h> +#include <string.h> + +#include "header.h" +#include "read.h" +#include "part.h" +#include "misc.h" +#include "rpmlib.h" +#include "popt/popt.h" +#include "reqprov.h" +#include "package.h" + +/* Define this to be 1 to turn on -p "<prog> <args>..." ability */ +#define USE_PROG_STRING_ARRAY 0 + +int parseScript(Spec spec, int parsePart) +{ + /* There are a few options to scripts: */ + /* <pkg> */ + /* -n <pkg> */ + /* -p <sh> */ + /* -p "<sh> <args>..." */ + /* -f <file> */ + + char *p; + char *name = NULL; + char *prog = "/bin/sh"; + char *file = NULL; + char **progArgv = NULL; + int progArgc; + char *partname = NULL; + int tag = 0; + int progtag = 0; + int flag = PART_SUBNAME; + Package pkg; + StringBuf sb; + int nextPart; + + int rc, argc; + char arg, **argv = NULL; + poptContext optCon = NULL; + struct poptOption optionsTable[] = { + { NULL, 'p', POPT_ARG_STRING, &prog, 'p' }, + { NULL, 'n', POPT_ARG_STRING, &name, 'n' }, + { NULL, 'f', POPT_ARG_STRING, &file, 'f' }, + { 0, 0, 0, 0, 0 } + }; + + switch (parsePart) { + case PART_PRE: + tag = RPMTAG_PREIN; + progtag = RPMTAG_PREINPROG; + partname = "%pre"; + break; + case PART_POST: + tag = RPMTAG_POSTIN; + progtag = RPMTAG_POSTINPROG; + partname = "%post"; + break; + case PART_PREUN: + tag = RPMTAG_PREUN; + progtag = RPMTAG_PREUNPROG; + partname = "%preun"; + break; + case PART_POSTUN: + tag = RPMTAG_POSTUN; + progtag = RPMTAG_POSTUNPROG; + partname = "%postun"; + break; + case PART_VERIFYSCRIPT: + tag = PART_VERIFYSCRIPT; + progtag = RPMTAG_VERIFYSCRIPTPROG; + partname = "%verifyscript"; + } + + if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { + rpmError(RPMERR_BADSPEC, "line %d: Error parsing %s: %s", + spec->lineNum, partname, poptStrerror(rc)); + return RPMERR_BADSPEC; + } + + optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + while ((arg = poptGetNextOpt(optCon)) > 0) { + if (arg == 'p') { + if (prog[0] != '/') { + rpmError(RPMERR_BADSPEC, + "line %d: script program must begin " + "with \'/\': %s", prog); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + } else if (arg == 'n') { + flag = PART_NAME; + } + } + + if (arg < -1) { + rpmError(RPMERR_BADSPEC, "line %d: Bad option %s: %s", + spec->lineNum, + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (poptPeekArg(optCon)) { + if (! name) { + name = poptGetArg(optCon); + } + if (poptPeekArg(optCon)) { + rpmError(RPMERR_BADSPEC, "line %d: Too many names: %s", + spec->lineNum, + spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + } + + if (lookupPackage(spec, name, flag, &pkg)) { + rpmError(RPMERR_BADSPEC, "line %d: Package does not exist: %s", + spec->lineNum, spec->line); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if (headerIsEntry(pkg->header, progtag)) { + rpmError(RPMERR_BADSPEC, "line %d: Second %s", + spec->lineNum, partname); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) { + rpmError(RPMERR_BADSPEC, "line %d: Error parsing %s: %s", + spec->lineNum, partname, poptStrerror(rc)); + FREE(argv); + poptFreeContext(optCon); + return RPMERR_BADSPEC; + } + + sb = newStringBuf(); + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + } else { + while (! (nextPart = isPart(spec->line))) { + appendLineStringBuf(sb, spec->line); + if (readLine(spec, STRIP_NOTHING) > 0) { + nextPart = PART_NONE; + break; + } + } + } + stripTrailingBlanksStringBuf(sb); + p = getStringBuf(sb); + +#if USE_PROG_STRING_ARRAY + addReqProv(spec, pkg, RPMSENSE_PREREQ, progArgv[0], NULL); + headerAddEntry(pkg->header, progtag, RPM_STRING_ARRAY_TYPE, + progArgv, progArgc); +#else + addReqProv(spec, pkg, RPMSENSE_PREREQ, prog, NULL); + headerAddEntry(pkg->header, progtag, RPM_STRING_TYPE, prog, 1); +#endif + if (*p) { + headerAddEntry(pkg->header, tag, RPM_STRING_TYPE, p, 1); + } + + if (file) { + switch (parsePart) { + case PART_PRE: + pkg->preInFile = strdup(file); + break; + case PART_POST: + pkg->postInFile = strdup(file); + break; + case PART_PREUN: + pkg->preUnFile = strdup(file); + break; + case PART_POSTUN: + pkg->postUnFile = strdup(file); + break; + case PART_VERIFYSCRIPT: + pkg->verifyFile = strdup(file); + break; + } + } + + freeStringBuf(sb); + FREE(progArgv); + FREE(argv); + poptFreeContext(optCon); + + return nextPart; +} diff --git a/build/parseSpec.c b/build/parseSpec.c new file mode 100644 index 000000000..a3badbb18 --- /dev/null +++ b/build/parseSpec.c @@ -0,0 +1,186 @@ +#include <ctype.h> +#include <unistd.h> +#include <string.h> +#include <malloc.h> + +#include "header.h" +#include "rpmlib.h" +#include "part.h" +#include "spec.h" +#include "parse.h" +#include "read.h" +#include "misc.h" + +static void setStandardMacros(Spec spec, char *arch, char *os); + +int parseSpec(Spec *specp, char *specFile, char *buildRoot, + int inBuildArch, char *passPhrase, char *cookie) +{ + int parsePart = PART_PREAMBLE; + int initialPackage = 1; + char *name, *arch, *os; + Package pkg; + int x, index; + Spec spec; + + /* Set up a new Spec structure with no packages. */ + spec = newSpec(); + + spec->specFile = strdup(specFile); + if (buildRoot) { + spec->gotBuildRoot = 1; + spec->buildRoot = strdup(buildRoot); + } + spec->docDir = strdup(rpmGetVar(RPMVAR_DEFAULTDOCDIR)); + spec->inBuildArchitectures = inBuildArch; + if (passPhrase) { + spec->passPhrase = strdup(passPhrase); + } + if (cookie) { + spec->cookie = strdup(cookie); + } + + if (rpmGetVar(RPMVAR_TIMECHECK)) { + if (parseNum(rpmGetVar(RPMVAR_TIMECHECK), &(spec->timeCheck))) { + rpmError(RPMERR_BADSPEC, "Timecheck value must be an integer: %s", + rpmGetVar(RPMVAR_TIMECHECK)); + freeSpec(spec); + return RPMERR_BADSPEC; + } + } else { + spec->timeCheck = 0; + } + + /* Add some standard macros */ + rpmGetArchInfo(&arch, NULL); + rpmGetOsInfo(&os, NULL); + setStandardMacros(spec, arch, os); + + /* All the parse*() functions expect to have a line pre-read */ + /* in the spec's line buffer. Except for parsePreamble(), */ + /* which handles the initial entry into a spec file. */ + + while (parsePart != PART_NONE) { + switch (parsePart) { + case PART_PREAMBLE: + parsePart = parsePreamble(spec, initialPackage); + initialPackage = 0; + break; + case PART_PREP: + parsePart = parsePrep(spec); + break; + case PART_BUILD: + case PART_INSTALL: + case PART_CLEAN: + parsePart = parseBuildInstallClean(spec, parsePart); + break; + case PART_CHANGELOG: + parsePart = parseChangelog(spec); + break; + case PART_DESCRIPTION: + parsePart = parseDescription(spec); + break; + case PART_PRE: + case PART_POST: + case PART_PREUN: + case PART_POSTUN: + case PART_VERIFYSCRIPT: + parsePart = parseScript(spec, parsePart); + break; + + case PART_FILES: + parsePart = parseFiles(spec); + break; + + case PART_TRIGGERIN: + case PART_TRIGGERUN: + printf("Triggers are not supported yet.\n"); + exit(1); + /*parsePart = parseTrigger(spec, parsePart);*/ + break; + } + + if (parsePart < 0) { + freeSpec(spec); + return parsePart; + } + + if (parsePart == PART_BUILDARCHITECTURES) { + spec->buildArchitectureSpecs = + malloc(sizeof(Spec) * spec->buildArchitectureCount); + x = 0; + index = 0; + while (x < spec->buildArchitectureCount) { + if (rpmMachineScore(RPM_MACHTABLE_BUILDARCH, + spec->buildArchitectures[x])) { + rpmSetMachine(spec->buildArchitectures[x], NULL); + if (parseSpec(&(spec->buildArchitectureSpecs[index]), + specFile, buildRoot, 1, + passPhrase, cookie)) { + spec->buildArchitectureCount = index; + freeSpec(spec); + return RPMERR_BADSPEC; + } + index++; + } + x++; + } + spec->buildArchitectureCount = index; + if (! index) { + freeSpec(spec); + rpmError(RPMERR_BADSPEC, "No buildable architectures"); + return RPMERR_BADSPEC; + } + closeSpec(spec); + *specp = spec; + return 0; + } + } + + /* Check for description in each package and add arch and os */ + pkg = spec->packages; + while (pkg) { + headerGetEntry(pkg->header, RPMTAG_NAME, NULL, (void **) &name, NULL); + if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) { + rpmError(RPMERR_BADSPEC, "Package has no %%description: %s", name); + freeSpec(spec); + return RPMERR_BADSPEC; + } + + headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1); + headerAddEntry(pkg->header, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1); + + pkg = pkg->next; + } + + closeSpec(spec); + *specp = spec; + return 0; +} + +static void setStandardMacros(Spec spec, char *arch, char *os) +{ + char buf[BUFSIZ]; + int x; + + addMacro(&spec->macros, "sourcedir", rpmGetVar(RPMVAR_SOURCEDIR)); + addMacro(&spec->macros, "builddir", rpmGetVar(RPMVAR_BUILDDIR)); + addMacro(&spec->macros, "optflags", rpmGetVar(RPMVAR_OPTFLAGS)); + addMacro(&spec->macros, "buildarch", arch); + addMacro(&spec->macros, "buildos", os); + + x = 0; + while (arch[x]) { + buf[x] = tolower(arch[x]); + x++; + } + buf[x] = '\0'; + addMacro(&spec->macros, "buildarch_lc", buf); + x = 0; + while (os[x]) { + buf[x] = tolower(os[x]); + x++; + } + buf[x] = '\0'; + addMacro(&spec->macros, "buildos_lc", buf); +} diff --git a/build/trigger.c b/build/parseTrigger.c index ea6e94a2d..1d18c1a77 100644 --- a/build/trigger.c +++ b/build/parseTrigger.c @@ -1,22 +1,50 @@ /* handle triggers */ -#include "config.h" -#include "miscfn.h" - #include <stdlib.h> #include <string.h> -#include "trigger.h" -#include "header.h" -#include "spec.h" -#include "specP.h" -#include "messages.h" -#include "rpmlib.h" -#include "stringbuf.h" -#include "misc.h" - -#define FREE(x) { if (x) free(x); } -#define CHUNK 8 +/* %trigger is a strange combination of %pre and Requires: behavior */ +/* We can handle it by handing the args before "--" to parseScript, */ +/* which in the case of triggers should return an index. We then */ +/* can pass the remaining arguments to parseReqProv, along with the */ +/* index we just obtained. In theory, then, all script arguments */ +/* and behavior is in parseScript, and the require behavior is in */ +/* parseReqProv, with just a little glue used here. */ + +int parseTrigger(Spec spec, int parsePart) +{ + int nextPart; + char **lineArgv, **triggerArgv; + int lineArgc, triggerArgc; + int rc, dash; + + if ((rc = poptParseArgvString(spec->line, &lineArgc, &lineArgv))) { + rpmError(RPMERR_BADSPEC, "line %d: Error parsing trigger options: %s", + spec->lineNum, partname, poptStrerror(rc)); + return RPMERR_BADSPEC; + } + triggerArgv = lineArgv; + triggerArgc = lineArgc; + + dash = 0; + while (dash <= lineArgc) { + if (!strcmp(lineArgv[dash], "--")) { + lineArgv[dash] = NULL; + if ((rc = parseScriptArgs(spec, dash, lineArgv, + &prog, &name, &flag))) { + free(lineArgv); + return rc; + } + triggerArgv = &(lineArgv[dash + 1]); + triggerArgc = lineArgc - dash - 1; + break; + } + dash++; + } + + if ((rc = parseReqArgs(spec, triggerArgc, triggerArgv, + +} int addTrigger(struct PackageRec *package, int sense, char *script, char *args) diff --git a/build/part.c b/build/part.c new file mode 100644 index 000000000..ca3ce2e6b --- /dev/null +++ b/build/part.c @@ -0,0 +1,56 @@ +#include <string.h> + +#include "part.h" + +static struct PartRec { + int part; + int len; + char *token; +} partList[] = { + {PART_PREAMBLE, 0, "%package"}, + {PART_PREP, 0, "%prep"}, + {PART_BUILD, 0, "%build"}, + {PART_INSTALL, 0, "%install"}, + {PART_CLEAN, 0, "%clean"}, + {PART_PREUN, 0, "%preun"}, + {PART_POSTUN, 0, "%postun"}, + {PART_PRE, 0, "%pre"}, + {PART_POST, 0, "%post"}, + {PART_FILES, 0, "%files"}, + {PART_CHANGELOG, 0, "%changelog"}, + {PART_DESCRIPTION, 0, "%description"}, + {PART_TRIGGERUN, 0, "%triggerun"}, + {PART_TRIGGERIN, 0, "%trigger"}, + {PART_VERIFYSCRIPT, 0, "%verifyscript"}, + {0, 0, 0} +}; + +static void initParts(void) +{ + struct PartRec *p = partList; + + while (p->token) { + p->len = strlen(p->token); + p++; + } +} + +int isPart(char *line) +{ + struct PartRec *p = partList; + + if (p->len == 0) { + initParts(); + } + + while (p->token && strncmp(line, p->token, p->len)) { + p++; + } + + if (p->token) { + return p->part; + } else { + return PART_NONE; + } +} + diff --git a/build/part.h b/build/part.h new file mode 100644 index 000000000..6ddae3238 --- /dev/null +++ b/build/part.h @@ -0,0 +1,24 @@ +#ifndef _PART_H_ +#define _PART_H_ + +#define PART_NONE 0 +#define PART_PREAMBLE 1 +#define PART_PREP 2 +#define PART_BUILD 3 +#define PART_INSTALL 4 +#define PART_CLEAN 5 +#define PART_FILES 6 +#define PART_PRE 7 +#define PART_POST 8 +#define PART_PREUN 9 +#define PART_POSTUN 10 +#define PART_DESCRIPTION 11 +#define PART_CHANGELOG 12 +#define PART_TRIGGERIN 13 +#define PART_TRIGGERUN 14 +#define PART_VERIFYSCRIPT 15 +#define PART_BUILDARCHITECTURES 16 + +int isPart(char *line); + +#endif diff --git a/build/read.c b/build/read.c new file mode 100644 index 000000000..b5790fe3a --- /dev/null +++ b/build/read.c @@ -0,0 +1,138 @@ +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#include "spec.h" +#include "rpmlib.h" +#include "messages.h" +#include "macro.h" +#include "misc.h" + +static int matchTok(char *token, char *line); + +/* returns 0 - success */ +/* 1 - EOF */ +/* <0 - error */ + +int readLine(Spec spec, int strip) +{ + char *from, *to, *last, *s, *arch, *os; + int match; + char ch; + struct ReadLevelEntry *rl; + + /* Make sure the spec file is open */ + if (!spec->file) { + if (!(spec->file = fopen(spec->specFile, "r"))) { + rpmError(RPMERR_BADSPEC, "Unable to open: %s\n", spec->specFile); + return RPMERR_BADSPEC; + } + spec->lineNum = 0; + } + + /* Make sure we have something in the read buffer */ + if (!spec->readPtr || ! *(spec->readPtr)) { + if (!fgets(spec->readBuf, BUFSIZ, spec->file)) { + /* EOF */ + if (spec->readStack->next) { + rpmError(RPMERR_UNMATCHEDIF, "Unclosed %%if"); + return RPMERR_UNMATCHEDIF; + } + return 1; + } + spec->readPtr = spec->readBuf; + spec->lineNum++; + /*rpmMessage(RPMMESS_DEBUG, "LINE: %s", spec->readBuf);*/ + } + + /* Copy a single line to the line buffer */ + from = spec->readPtr; + to = last = spec->line; + ch = ' '; + while (*from && ch != '\n') { + ch = *to++ = *from++; + if (!isspace(ch)) { + last = to; + } + } + *to = '\0'; + spec->readPtr = from; + + if (strip) { + *last = '\0'; + } + + rpmGetArchInfo(&arch, NULL); + rpmGetOsInfo(&os, NULL); + s = spec->line; + SKIPSPACE(s); + match = -1; + if (! strncmp("%ifarch", s, 7)) { + match = matchTok(arch, s); + } else if (! strncmp("%ifnarch", s, 8)) { + match = !matchTok(arch, s); + } else if (! strncmp("%ifos", s, 5)) { + match = matchTok(os, s); + } else if (! strncmp("%ifnos", s, 6)) { + match = !matchTok(os, s); + } else if (! strncmp("%else", s, 5)) { + if (! spec->readStack->next) { + /* Got an else with no %if ! */ + rpmError(RPMERR_UNMATCHEDIF, "line %d: Got a %%else with no if", + spec->lineNum); + return RPMERR_UNMATCHEDIF; + } + spec->readStack->reading = + spec->readStack->next->reading && ! spec->readStack->reading; + spec->line[0] = '\0'; + } else if (! strncmp("%endif", s, 6)) { + if (! spec->readStack->next) { + /* Got an end with no %if ! */ + rpmError(RPMERR_UNMATCHEDIF, "line %d: Got a %%endif with no if", + spec->lineNum); + return RPMERR_UNMATCHEDIF; + } + rl = spec->readStack; + spec->readStack = spec->readStack->next; + free(rl); + spec->line[0] = '\0'; + } + if (match != -1) { + rl = malloc(sizeof(struct ReadLevelEntry)); + rl->reading = spec->readStack->reading && match; + rl->next = spec->readStack; + spec->readStack = rl; + spec->line[0] = '\0'; + } + + if (spec->readStack->reading) { + expandMacros(&spec->macros, spec->line); + } else { + spec->line[0] = '\0'; + } + + return 0; +} + +static int matchTok(char *token, char *line) +{ + char buf[BUFSIZ], *tok; + + strcpy(buf, line); + strtok(buf, " \n\t"); + while ((tok = strtok(NULL, " \n\t"))) { + if (! strcmp(tok, token)) { + return 1; + } + } + + return 0; +} + +void closeSpec(Spec spec) +{ + if (spec->file) { + fclose(spec->file); + } + spec->file = NULL; +} diff --git a/build/read.h b/build/read.h new file mode 100644 index 000000000..041125d98 --- /dev/null +++ b/build/read.h @@ -0,0 +1,16 @@ +#ifndef _READ_H_ +#define _READ_H_ + +#include "spec.h" + +#define STRIP_NOTHING 0 +#define STRIP_TRAILINGSPACE 1 + +/* returns 0 - success */ +/* 1 - EOF */ +/* <0 - error */ + +int readLine(Spec spec, int strip); +void closeSpec(Spec spec); + +#endif diff --git a/build/reqprov.c b/build/reqprov.c index b06e930ea..0a2abfb6f 100644 --- a/build/reqprov.c +++ b/build/reqprov.c @@ -1,413 +1,211 @@ /* 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/time.h> -#include <sys/resource.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <errno.h> +#include <malloc.h> -#include "specP.h" +#include "spec.h" #include "reqprov.h" #include "messages.h" #include "rpmlib.h" #include "misc.h" +#include "lib/misc.h" -static StringBuf getOutputFrom(char *dir, char *argv[], - char *writePtr, int writeBytesLeft, - int failNonZero); - -/*************************************************************/ -/* */ -/* Adding entries to the package reqprov list */ -/* Handle duplicate entries */ -/* */ -/*************************************************************/ - -int addReqProv(struct PackageRec *p, int flags, - char *name, char *version) +int addReqProv(Spec spec, Package pkg, int flag, 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 */ - rpmMessage(RPMMESS_DEBUG, "Already Got: %s\n", name); - return 0; - } + char **names; + char **versions = NULL; + int *flags = NULL; + int nametag = 0; + int versiontag = 0; + int flagtag = 0; + int len; + int extra = 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 & RPMSENSE_PROVIDES) { - rpmMessage(RPMMESS_DEBUG, "Adding provide: %s\n", name); - p->numProv++; - } else if (flags & RPMSENSE_CONFLICTS) { - rpmMessage(RPMMESS_DEBUG, "Adding conflict: %s\n", name); - p->numConflict++; - } else if (flags & RPMSENSE_PREREQ) { - rpmMessage(RPMMESS_DEBUG, "Adding prereq: %s\n", name); - p->numPreReq++; - } else if (flags & RPMSENSE_OBSOLETES) { - rpmMessage(RPMMESS_DEBUG, "Adding obsoletes: %s\n", name); - p->numObsoletes++; + if (flag & RPMSENSE_PROVIDES) { + nametag = RPMTAG_PROVIDES; + } else if (flag & RPMSENSE_OBSOLETES) { + nametag = RPMTAG_OBSOLETES; + } else if (flag & RPMSENSE_CONFLICTS) { + nametag = RPMTAG_CONFLICTNAME; + versiontag = RPMTAG_CONFLICTVERSION; + flagtag = RPMTAG_CONFLICTFLAGS; + } else if (flag & RPMSENSE_PREREQ) { + nametag = RPMTAG_REQUIRENAME; + versiontag = RPMTAG_REQUIREVERSION; + flagtag = RPMTAG_REQUIREFLAGS; + extra = RPMSENSE_PREREQ; } else { - rpmMessage(RPMMESS_DEBUG, "Adding require: %s\n", name); - p->numReq++; + nametag = RPMTAG_REQUIRENAME; + versiontag = RPMTAG_REQUIREVERSION; + flagtag = RPMTAG_REQUIREFLAGS; } - return 0; -} - -/*************************************************************/ -/* */ -/* Add require/provides for the files in the header */ -/* (adds to the package structure) */ -/* */ -/*************************************************************/ - -static StringBuf getOutputFrom(char *dir, char *argv[], - char *writePtr, int writeBytesLeft, - int failNonZero) -{ - int progPID; - int progDead; - int toProg[2]; - int fromProg[2]; - int status; - void *oldhandler; - int bytesWritten; - StringBuf readBuff; - int bytes; - unsigned char buf[8193]; - - oldhandler = signal(SIGPIPE, SIG_IGN); - - pipe(toProg); - pipe(fromProg); - - if (!(progPID = fork())) { - close(toProg[1]); - close(fromProg[0]); - - dup2(toProg[0], 0); /* Make stdin the in pipe */ - dup2(fromProg[1], 1); /* Make stdout the out pipe */ - - close(toProg[0]); - close(fromProg[1]); - - chdir(dir); - - execvp(argv[0], argv); - rpmError(RPMERR_EXEC, "Couldn't exec %s", argv[0]); - _exit(RPMERR_EXEC); - } - if (progPID < 0) { - rpmError(RPMERR_FORK, "Couldn't fork %s", argv[0]); - return NULL; + flag = (flag & RPMSENSE_SENSEMASK) | extra; + if (!version) { + version = ""; } - - close(toProg[0]); - close(fromProg[1]); - - /* Do not block reading or writing from/to prog. */ - fcntl(fromProg[0], F_SETFL, O_NONBLOCK); - fcntl(toProg[1], F_SETFL, O_NONBLOCK); - readBuff = newStringBuf(); - - progDead = 0; - do { - if (waitpid(progPID, &status, WNOHANG)) { - progDead = 1; + if (headerGetEntry(pkg->header, nametag, NULL, (void *) &names, &len)) { + if (flagtag) { + headerGetEntry(pkg->header, versiontag, NULL, + (void *) &versions, NULL); + headerGetEntry(pkg->header, flagtag, NULL, (void *) &flags, NULL); } - - /* Write some stuff to the process if possible */ - if (writeBytesLeft) { - if ((bytesWritten = - write(toProg[1], writePtr, - (1024<writeBytesLeft) ? 1024 : writeBytesLeft)) < 0) { - if (errno != EAGAIN) { - perror("getOutputFrom()"); - exit(1); + while (len) { + len--; + if (!strcmp(names[len], name)) { + if (!flagtag || + (!strcmp(versions[len], version) && flags[len] == flag)) { + /* The same */ + FREE(names); + FREE(versions); + return 0; } - bytesWritten = 0; } - writeBytesLeft -= bytesWritten; - writePtr += bytesWritten; - } else { - close(toProg[1]); } - - /* Read any data from prog */ - bytes = read(fromProg[0], buf, sizeof(buf)-1); - while (bytes > 0) { - buf[bytes] = '\0'; - appendStringBuf(readBuff, buf); - bytes = read(fromProg[0], buf, sizeof(buf)-1); - } - - /* terminate when prog dies */ - } while (!progDead); - - close(toProg[1]); - close(fromProg[0]); - signal(SIGPIPE, oldhandler); - - if (writeBytesLeft) { - rpmError(RPMERR_EXEC, "failed to write all data to %s", argv[0]); - return NULL; + FREE(names); + FREE(versions); } - waitpid(progPID, &status, 0); - if (failNonZero && (!WIFEXITED(status) || WEXITSTATUS(status))) { - rpmError(RPMERR_EXEC, "%s failed", argv[0]); - return NULL; + + headerAddOrAppendEntry(pkg->header, nametag, + RPM_STRING_ARRAY_TYPE, &name, 1); + if (flagtag) { + headerAddOrAppendEntry(pkg->header, versiontag, + RPM_STRING_ARRAY_TYPE, &version, 1); + headerAddOrAppendEntry(pkg->header, flagtag, + RPM_INT32_TYPE, &flag, 1); } - return readBuff; + return 0; } -int generateAutoReqProv(Header header, struct PackageRec *p) +int generateAutoReqProv(Spec spec, Package pkg, + struct cpioFileMapping *cpioList, int cpioCount) { - char **f, **fsave, *s; - int count; - int_16 *modes; - - StringBuf writeBuff; - StringBuf readBuff; - char *writePtr; + StringBuf writeBuf; int writeBytes; - char dir[1024]; - char *argv[8]; - - rpmMessage(RPMMESS_VERBOSE, "Finding dependencies...\n"); - - /*** Get root directory ***/ - - if (rpmGetVar(RPMVAR_ROOT)) { - strcpy(dir, rpmGetVar(RPMVAR_ROOT)); - } else { - strcpy(dir, "/"); - } + StringBuf readBuf; + char *argv[2]; + char **f, **fsave; - /*** Generate File List ***/ - - if (!headerGetEntry(header, RPMTAG_FILENAMES, NULL, (void **) &f, &count)) { - return 0; - } - if (!count) { + if (!cpioCount) { return 0; } - fsave = f; - headerGetEntry(header, RPMTAG_FILEMODES, NULL, (void **) &modes, NULL); - writeBuff = newStringBuf(); + writeBuf = newStringBuf(); writeBytes = 0; - while (count--) { - s = *f++; - /* We skip the leading "/" (already normalized) */ - writeBytes += strlen(s); - appendLineStringBuf(writeBuff, s + 1); - } - if (fsave) { - free(fsave); + while (cpioCount--) { + writeBytes += strlen(cpioList->fsPath) + 1; + appendLineStringBuf(writeBuf, cpioList->fsPath); + cpioList++; } - writePtr = getStringBuf(writeBuff); /*** Do Provides ***/ + + rpmMessage(RPMMESS_NORMAL, "Finding provides...\n"); argv[0] = "find-provides"; argv[1] = NULL; - readBuff = getOutputFrom(dir, argv, writePtr, writeBytes, 1); - if (!readBuff) { + readBuf = getOutputFrom(NULL, argv, + getStringBuf(writeBuf), writeBytes, 1); + if (!readBuf) { rpmError(RPMERR_EXEC, "Failed to find provides"); - exit(1); + freeStringBuf(writeBuf); + return RPMERR_EXEC; } - s = getStringBuf(readBuff); - f = fsave = splitString(s, strlen(s), '\n'); - freeStringBuf(readBuff); + f = fsave = splitString(getStringBuf(readBuf), + strlen(getStringBuf(readBuf)), '\n'); + freeStringBuf(readBuf); while (*f) { if (**f) { - addReqProv(p, RPMSENSE_PROVIDES, *f, NULL); + addReqProv(spec, pkg, RPMSENSE_PROVIDES, *f, NULL); } f++; } - free(fsave); + FREE(fsave); /*** Do Requires ***/ + rpmMessage(RPMMESS_NORMAL, "Finding requires...\n"); + argv[0] = "find-requires"; argv[1] = NULL; - readBuff = getOutputFrom(dir, argv, writePtr, writeBytes, 0); - if (!readBuff) { + readBuf = getOutputFrom(NULL, argv, + getStringBuf(writeBuf), writeBytes, 0); + if (!readBuf) { rpmError(RPMERR_EXEC, "Failed to find requires"); - exit(1); + freeStringBuf(writeBuf); + return RPMERR_EXEC; } - s = getStringBuf(readBuff); - f = fsave = splitString(s, strlen(s), '\n'); - freeStringBuf(readBuff); + f = fsave = splitString(getStringBuf(readBuf), + strlen(getStringBuf(readBuf)), '\n'); + freeStringBuf(readBuf); while (*f) { if (**f) { - addReqProv(p, RPMSENSE_ANY, *f, NULL); + addReqProv(spec, pkg, RPMSENSE_ANY, *f, NULL); } f++; } - free(fsave); + FREE(fsave); /*** Clean Up ***/ - freeStringBuf(writeBuff); + freeStringBuf(writeBuf); return 0; } -/*************************************************************/ -/* */ -/* Generate and add header entry from package record */ -/* */ -/*************************************************************/ - -int processReqProv(Header h, struct PackageRec *p) +void printReqs(Spec spec, Package pkg) { - struct ReqProv *rd; - char **nameArray, **namePtr; - char **versionArray, **versionPtr; - int_32 *flagArray, *flagPtr; - int x; - - if (p->numProv) { - rd = p->reqprov; - nameArray = namePtr = malloc(p->numProv * sizeof(*nameArray)); - rpmMessage(RPMMESS_VERBOSE, "Provides (%d):", p->numProv); - while (rd) { - if (rd->flags & RPMSENSE_PROVIDES) { - rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); - *namePtr++ = rd->name; - } - rd = rd->next; + int startedPreReq = 0; + int startedReq = 0; + + char **names; + int x, count; + int *flags; + + if (headerGetEntry(pkg->header, RPMTAG_PROVIDES, + NULL, (void **) &names, &count)) { + rpmMessage(RPMMESS_NORMAL, "Provides:"); + x = 0; + while (x < count) { + rpmMessage(RPMMESS_NORMAL, " %s", names[x]); + x++; } - rpmMessage(RPMMESS_VERBOSE, "\n"); - - headerAddEntry(h, RPMTAG_PROVIDES, RPM_STRING_ARRAY_TYPE, nameArray, p->numProv); - free(nameArray); - } - - if (p->numObsoletes) { - rd = p->reqprov; - nameArray = namePtr = malloc(p->numObsoletes * sizeof(*nameArray)); - rpmMessage(RPMMESS_VERBOSE, "Obsoletes (%d):", p->numObsoletes); - while (rd) { - if (rd->flags & RPMSENSE_OBSOLETES) { - rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); - *namePtr++ = rd->name; - } - rd = rd->next; - } - rpmMessage(RPMMESS_VERBOSE, "\n"); - - headerAddEntry(h, RPMTAG_OBSOLETES, RPM_STRING_ARRAY_TYPE, nameArray, p->numObsoletes); - free(nameArray); - } - - if (p->numConflict) { - rd = p->reqprov; - nameArray = namePtr = malloc(p->numConflict * sizeof(*nameArray)); - versionArray = versionPtr = - malloc(p->numConflict * sizeof(*versionArray)); - flagArray = flagPtr = malloc(p->numConflict * sizeof(*flagArray)); - rpmMessage(RPMMESS_VERBOSE, "Conflicts (%d):", p->numConflict); - while (rd) { - if (rd->flags & RPMSENSE_CONFLICTS) { - rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); - *namePtr++ = rd->name; - *versionPtr++ = rd->version ? rd->version : ""; - *flagPtr++ = rd->flags & RPMSENSE_SENSEMASK; + rpmMessage(RPMMESS_NORMAL, "\n"); + FREE(names); + } + + if (headerGetEntry(pkg->header, RPMTAG_REQUIRENAME, + NULL, (void **) &names, &count)) { + headerGetEntry(pkg->header, RPMTAG_REQUIREFLAGS, + NULL, (void **) &flags, NULL); + x = 0; + while (x < count) { + if (flags[x] & RPMSENSE_PREREQ) { + if (! startedPreReq) { + rpmMessage(RPMMESS_NORMAL, "Prereqs:"); + startedPreReq = 1; + } + rpmMessage(RPMMESS_NORMAL, " %s", names[x]); } - rd = rd->next; + x++; } - rpmMessage(RPMMESS_VERBOSE, "\n"); - - headerAddEntry(h, RPMTAG_CONFLICTNAME, RPM_STRING_ARRAY_TYPE, - nameArray, p->numConflict); - headerAddEntry(h, RPMTAG_CONFLICTVERSION, RPM_STRING_ARRAY_TYPE, - versionArray, p->numConflict); - headerAddEntry(h, RPMTAG_CONFLICTFLAGS, RPM_INT32_TYPE, - flagArray, p->numConflict); - - free(nameArray); - free(versionArray); - free(flagArray); - } - - x = p->numReq + p->numPreReq; - if (x) { - rd = p->reqprov; - nameArray = namePtr = malloc(x * sizeof(*nameArray)); - versionArray = versionPtr = malloc(x * sizeof(*versionArray)); - flagArray = flagPtr = malloc(x * sizeof(*flagArray)); - rpmMessage(RPMMESS_VERBOSE, "[Pre]Requires (%d):", x); - while (rd) { - if (! ((rd->flags & RPMSENSE_PROVIDES) || - (rd->flags & RPMSENSE_OBSOLETES) || - (rd->flags & RPMSENSE_CONFLICTS))) { - if (rd->flags & RPMSENSE_PREREQ) { - rpmMessage(RPMMESS_VERBOSE, " [%s]", rd->name); - } else { - rpmMessage(RPMMESS_VERBOSE, " %s", rd->name); + rpmMessage(RPMMESS_NORMAL, "\n"); + x = 0; + while (x < count) { + if (! (flags[x] & RPMSENSE_PREREQ)) { + if (! startedReq) { + rpmMessage(RPMMESS_NORMAL, "Requires:"); + startedReq = 1; } - *namePtr++ = rd->name; - *versionPtr++ = rd->version ? rd->version : ""; - *flagPtr++ = (rd->flags & RPMSENSE_SENSEMASK) | - (rd->flags & RPMSENSE_PREREQ); + rpmMessage(RPMMESS_NORMAL, " %s", names[x]); } - rd = rd->next; + x++; } - rpmMessage(RPMMESS_VERBOSE, "\n"); - - headerAddEntry(h, RPMTAG_REQUIRENAME, RPM_STRING_ARRAY_TYPE, - nameArray, x); - headerAddEntry(h, RPMTAG_REQUIREVERSION, RPM_STRING_ARRAY_TYPE, - versionArray, x); - headerAddEntry(h, RPMTAG_REQUIREFLAGS, RPM_INT32_TYPE, - flagArray, x); - - free(nameArray); - free(versionArray); - free(flagArray); + rpmMessage(RPMMESS_NORMAL, "\n"); + FREE(names); } - return 0; } diff --git a/build/reqprov.h b/build/reqprov.h index f45e8a6ad..7069c47d3 100644 --- a/build/reqprov.h +++ b/build/reqprov.h @@ -1,11 +1,13 @@ #ifndef _REQPROV_H_ #define _REQPROV_H_ -#include "specP.h" +#include "spec.h" +#include "package.h" +#include "lib/cpio.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); +int addReqProv(Spec spec, Package pkg, int flag, char *name, char *version); +int generateAutoReqProv(Spec spec, Package pkg, + struct cpioFileMapping *cpioList, int cpioCount); +void printReqs(Spec spec, Package pkg); -#endif _REQPROV_H_ +#endif diff --git a/build/spec.c b/build/spec.c index 6bc047617..1be377c75 100644 --- a/build/spec.c +++ b/build/spec.c @@ -1,1750 +1,289 @@ -/* RPM - Copyright (C) 1995 Red Hat Software - * - * spec.c - routines for parsing a spec file - */ - -/***************************** -TODO: - -. should be able to drop the -n in non-%package parts - -******************************/ - -#include "config.h" -#include "miscfn.h" - -#if HAVE_ALLOCA_H -# include <alloca.h> -#endif - #include <stdlib.h> +#include <malloc.h> #include <string.h> -#include <sys/types.h> -#include <time.h> -#include <sys/time.h> -#include <limits.h> -#include <ctype.h> -#include "header.h" #include "spec.h" -#include "specP.h" -#include "messages.h" -#include "rpmlib.h" -#include "stringbuf.h" #include "misc.h" -#include "reqprov.h" -#include "trigger.h" +#include "rpmlib.h" +#include "package.h" +#include "read.h" +#include "files.h" #include "macro.h" -#define LINE_BUF_SIZE 1024 -#define FREE(x) { if (x) free(x); } - -static struct PackageRec *new_packagerec(void); -static int read_line(FILE *f, char *line); -static int match_arch(char *s); -static int match_os(char *s); -static void free_packagerec(struct PackageRec *p); -static void generateNames(Spec s); -static void reset_spec(void); -static int find_preamble_line(char *line, char **s); -static int check_part(char *line, char **s); -static int lookup_package(Spec s, struct PackageRec **pr, - char *name, int flags); -static void dumpPackage(struct PackageRec *p, FILE *f); - -static int dateToTimet(const char * datestr, time_t * secs); -static void addChangelogEntry(Header h, int time, char *name, char *text); -static int addChangelog(Header h, StringBuf sb); - -static int parseProvides(struct PackageRec *p, char *line, int tag); -static int parseRequiresConflicts(struct PackageRec *p, char *line, - int flag); -static void free_reqprov(struct ReqProv *p); -static int noSourcePatch(Spec s, char *line, int_32 tag); +static char *getSourceAux(Spec spec, int num, int flag, int full); +static struct Source *findSource(Spec spec, int num, int flag); -static void addListEntry(Header h, int_32 tag, char *line); -static int finishCurrentPart(Spec spec, StringBuf sb, - struct PackageRec *cur_package, - int cur_part, char *triggerArgs, - char *scriptProg); - -Spec parseSpecAux(FILE *f, char *specfile, char *buildRootOverride, - char ***buildArchs); - -/**********************************************************************/ -/* */ -/* Source and patch structure creation/deletion/lookup */ -/* */ -/**********************************************************************/ - -static int addSource(Spec spec, char *line) +Spec newSpec(void) { - struct sources *p; - char *s, *s1, c; - char *file; - unsigned long int x; - char name[1024], expansion[1024]; - - p = malloc(sizeof(struct sources)); - p->next = spec->sources; - spec->sources = p; - - if (! strncasecmp(line, "source", 6)) { - spec->numSources++; - p->ispatch = 0; - s = line + 6; - } else if (! strncasecmp(line, "patch", 5)) { - spec->numPatches++; - p->ispatch = 1; - s = line + 5; - } else { - rpmError(RPMERR_BADSPEC, "Not a source/patch line: %s\n", line); - return(RPMERR_BADSPEC); - } - - s += strspn(s, " \t\n"); - p->num = 0; - if (*s != ':') { - x = strspn(s, "0123456789"); - if (! x) { - rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line); - return(RPMERR_BADSPEC); - } - c = s[x]; - s[x] = '\0'; - s1 = NULL; - p->num = strtoul(s, &s1, 10); - if ((*s1) || (s1 == s) || (p->num == ULONG_MAX)) { - s[x] = c; - rpmError(RPMERR_BADSPEC, "Bad source/patch number: %s\n", s); - return(RPMERR_BADSPEC); - } - s[x] = c; - s += x; - /* skip spaces */ - s += strspn(s, " \t\n"); - } + Spec spec; - if (*s != ':') { - rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line); - return(RPMERR_BADSPEC); - } + spec = (Spec)malloc(sizeof *spec); - /* skip to actual source */ - s++; - s += strspn(s, " \t\n"); + spec->specFile = NULL; + spec->sourceRpmName = NULL; + + spec->file = NULL; + spec->readBuf[0] = '\0'; + spec->readPtr = NULL; + spec->line[0] = '\0'; + spec->readStack = malloc(sizeof(struct ReadLevelEntry)); + spec->readStack->next = NULL; + spec->readStack->reading = 1; + + spec->prep = NULL; + spec->build = NULL; + spec->install = NULL; + spec->clean = NULL; - file = strtok(s, " \t\n"); - if (! file) { - rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line); - return(RPMERR_BADSPEC); - } - p->fullSource = strdup(file); - p->source = strrchr(p->fullSource, '/'); - if (p->source) { - p->source++; - } else { - p->source = p->fullSource; - } + spec->sources = NULL; + spec->packages = NULL; + spec->noSource = 0; + spec->numSources = 0; - sprintf(expansion, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), p->source); - sprintf(name, "%s%d", (p->ispatch) ? "PATCH" : "SOURCE", p->num); - addMacro(name, expansion); - sprintf(name, "%sURL%d", (p->ispatch) ? "PATCH" : "SOURCE", p->num); - addMacro(name, p->fullSource); + spec->sourceHeader = NULL; + + spec->sourceCpioCount = 0; + spec->sourceCpioList = NULL; - if (p->ispatch) { - rpmMessage(RPMMESS_DEBUG, "Patch(%d) = %s\n", p->num, p->fullSource); - } else { - rpmMessage(RPMMESS_DEBUG, "Source(%d) = %s\n", p->num, p->fullSource); - } + spec->gotBuildRoot = 0; + spec->buildRoot = NULL; - return 0; -} - -static void freeSources(Spec s) -{ - struct sources *p1, *p2; - - p1 = s->sources; - while (p1) { - p2 = p1; - p1 = p1->next; - free(p2->fullSource); - free(p2); - } -} + spec->buildSubdir = NULL; -char *getSource(Spec s, int ispatch, int num) -{ - struct sources *p = s->sources; + spec->docDir = NULL; - while (p) { - if ((ispatch == p->ispatch) && - (num == p->num)) { - break; - } else { - p = p->next; - } - } - - if (p) { - return(p->source); - } else { - return(NULL); - } -} + spec->passPhrase = NULL; + spec->timeCheck = 0; + spec->cookie = NULL; -char *getFullSource(Spec s, int ispatch, int num) -{ - struct sources *p = s->sources; + spec->buildRestrictions = headerNew(); + spec->buildArchitectures = NULL; + spec->buildArchitectureCount = 0; + spec->inBuildArchitectures = 0; + spec->buildArchitectureSpecs = NULL; - while (p) { - if ((ispatch == p->ispatch) && - (num == p->num)) { - break; - } else { - p = p->next; - } - } + initMacros(&spec->macros); + + spec->autoReqProv = 1; - if (p) { - return(p->fullSource); - } else { - return(NULL); - } + return spec; } -int noSourcePatch(Spec s, char *line, int_32 tag) +void freeSpec(Spec spec) { - int_32 array[1024]; /* XXX - max 1024 sources or patches */ - int_32 num; - int count; - char *t, *te; - - if (((tag == RPMTAG_NOSOURCE) && s->numNoSource) || - ((tag == RPMTAG_NOPATCH) && s->numNoPatch)) { - rpmError(RPMERR_BADSPEC, "Only one nosource/nopatch line allowed\n"); - return(RPMERR_BADSPEC); - } + struct ReadLevelEntry *rl; - count = 0; - while ((t = strtok(line, ", \t"))) { - num = strtoul(t, &te, 10); - if ((*te) || (te == t) || (num == ULONG_MAX)) { - rpmError(RPMERR_BADSPEC, "Bad source/patch number: %s\n", t); - return(RPMERR_BADSPEC); - } - array[count++] = num; - rpmMessage(RPMMESS_DEBUG, "Skipping source/patch number: %d\n", num); - line = NULL; - } - - if (count) { - if (tag == RPMTAG_NOSOURCE) { - s->numNoSource = count; - s->noSource = malloc(sizeof(int_32) * count); - memcpy(s->noSource, array, sizeof(int_32) * count); - } else { - s->numNoPatch = count; - s->noPatch = malloc(sizeof(int_32) * count); - memcpy(s->noPatch, array, sizeof(int_32) * count); - } + freeStringBuf(spec->prep); + freeStringBuf(spec->build); + freeStringBuf(spec->install); + freeStringBuf(spec->clean); + + FREE(spec->buildRoot); + FREE(spec->buildSubdir); + FREE(spec->specFile); + FREE(spec->sourceRpmName); + FREE(spec->docDir); + + while (spec->readStack) { + rl = spec->readStack; + spec->readStack = spec->readStack->next; + free(rl); } - - return 0; -} - -/**********************************************************************/ -/* */ -/* Provide/Require handling */ -/* */ -/**********************************************************************/ - -static void free_reqprov(struct ReqProv *p) -{ - struct ReqProv *s; - while (p) { - s = p; - p = p->next; - FREE(s->name); - FREE(s->version); - free(s); + if (spec->sourceHeader) { + headerFree(spec->sourceHeader); } -} -struct ReqComp ReqComparisons[] = { - { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL}, - { "<=S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, - { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL}, - { "=<S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, - { "<", RPMSENSE_LESS}, - { "<S", RPMSENSE_LESS | RPMSENSE_SERIAL}, - - { "=", RPMSENSE_EQUAL}, - { "=S", RPMSENSE_EQUAL | RPMSENSE_SERIAL}, + freeCpioList(spec->sourceCpioList, spec->sourceCpioCount); - { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL}, - { ">=S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, - { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL}, - { "=>S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL}, - { ">", RPMSENSE_GREATER}, - { ">S", RPMSENSE_GREATER | RPMSENSE_SERIAL}, - { NULL, 0 }, -}; - -static int parseRequiresConflicts(struct PackageRec *p, char *line, - int flag) -{ - char *req = NULL; - char *version = NULL; - int flags; - struct ReqComp *rc; - - while (req || (req = strtok(line, " ,\t\n"))) { - switch (flag) { - case RPMTAG_CONFLICTFLAGS: - flags = RPMSENSE_CONFLICTS; - break; - case RPMTAG_PREREQ: - flags = RPMSENSE_PREREQ; - break; - default: - flags = RPMSENSE_ANY; - break; - } - if (flag == RPMTAG_CONFLICTFLAGS && req[0] == '/') { - rpmError(RPMERR_BADSPEC, - "No file names in Conflicts: %s", req); - return RPMERR_BADSPEC; - } - if ((version = strtok(NULL, " ,\t\n"))) { - rc = ReqComparisons; - while (rc->token && strcmp(version, rc->token)) { - rc++; - } - if (rc->token) { - if (req[0] == '/') { - rpmError(RPMERR_BADSPEC, - "No versions on file names in Requires: %s", req); - return RPMERR_BADSPEC; - } - if (flag == RPMTAG_PREREQ) { - rpmError(RPMERR_BADSPEC, - "No versions in PreReq: %s", req); - return RPMERR_BADSPEC; - } - /* read a version */ - flags |= rc->flags; - version = strtok(NULL, " ,\t\n"); - } - } - if ((flags & RPMSENSE_SENSEMASK) && !version) { - rpmError(RPMERR_BADSPEC, "Version required in require/conflict"); - return RPMERR_BADSPEC; - } - - addReqProv(p, flags, req, - (flags & RPMSENSE_SENSEMASK) ? version : NULL); + headerFree(spec->buildRestrictions); + FREE(spec->buildArchitectures); - req = NULL; - if (! (flags & RPMSENSE_SENSEMASK)) { - /* No version -- we just read a name */ - req = version; + if (!spec->inBuildArchitectures) { + while (spec->buildArchitectureCount--) { + freeSpec( + spec->buildArchitectureSpecs[spec->buildArchitectureCount]); } - line = NULL; } - - return 0; -} + FREE(spec->buildArchitectures); -static int parseProvides(struct PackageRec *p, char *line, int tag) -{ - char *prov; - int flags; + FREE(spec->passPhrase); + FREE(spec->cookie); - flags = (tag == RPMTAG_PROVIDES) ? RPMSENSE_PROVIDES : RPMSENSE_OBSOLETES; + freeMacros(&spec->macros); - while ((prov = strtok(line, " ,\t\n"))) { - if (prov[0] == '/') { - rpmError(RPMERR_BADSPEC, - "No file names in %s: %s", - (tag == RPMTAG_PROVIDES) ? "provides" : "obsoletes", - prov); - return RPMERR_BADSPEC; - } - addReqProv(p, flags, prov, NULL); - line = NULL; - } - return 0; -} - -/**********************************************************************/ -/* */ -/* Spec and package structure creation/deletion/lookup */ -/* */ -/**********************************************************************/ - -static struct PackageRec *new_packagerec(void) -{ - struct PackageRec *p = malloc(sizeof(struct PackageRec)); - - p->subname = NULL; - p->newname = NULL; - p->icon = NULL; - p->header = headerNew(); - p->filelist = newStringBuf(); - p->files = -1; /* -1 means no %files, thus no package */ - p->fileFile = NULL; - p->doc = newStringBuf(); - p->reqprov = NULL; - p->numReq = 0; - p->numProv = 0; - p->numConflict = 0; - p->numPreReq = 0; - p->numObsoletes = 0; - p->trigger.alloced = 0; - p->trigger.used = 0; - p->trigger.triggerScripts = NULL; - p->trigger.trigger = NULL; - p->trigger.triggerCount = 0; - p->next = NULL; - - return p; -} - -void free_packagerec(struct PackageRec *p) -{ - if (! p ) return; + freeSources(spec); + freePackages(spec); + closeSpec(spec); - headerFree(p->header); - freeStringBuf(p->filelist); - freeStringBuf(p->doc); - FREE(p->subname); - FREE(p->newname); - FREE(p->icon); - FREE(p->fileFile); - free_reqprov(p->reqprov); - freeTriggers(p->trigger); - if (p->next) { - free_packagerec(p->next); - } - free(p); + free(spec); } -void freeSpec(Spec s) +int addSource(Spec spec, Package pkg, char *field, int tag) { - FREE(s->name); - FREE(s->specfile); - FREE(s->noSource); - FREE(s->noPatch); - FREE(s->buildroot); - FREE(s->buildArch); - freeSources(s); - freeStringBuf(s->prep); - freeStringBuf(s->build); - freeStringBuf(s->install); - freeStringBuf(s->doc); - freeStringBuf(s->clean); - free_packagerec(s->packages); - free(s); -} - -#define LP_CREATE 1 -#define LP_FAIL_EXISTS (1 << 1) -#define LP_SUBNAME (1 << 2) -#define LP_NEWNAME (1 << 3) - -int lookup_package(Spec s, struct PackageRec **pr, char *name, int flags) -{ - struct PackageRec *package; - struct PackageRec **ppp; - - package = s->packages; - while (package) { - if (flags & LP_SUBNAME) { - if (! package->subname) { - package = package->next; - continue; - } - if (! strcmp(package->subname, name)) { - break; - } - } else if (flags & LP_NEWNAME) { - if (! package->newname) { - package = package->next; - continue; - } - if (! strcmp(package->newname, name)) { - break; - } - } else { - /* Base package */ - if ((! package->newname) && (! package->subname)) { - break; - } - } - package = package->next; - } - - if (package && (flags & LP_FAIL_EXISTS)) { - return 0; - } - - if (package) { - *pr = package; - return 1; + struct Source *p; + int flag = 0; + char *name = NULL; + char *nump, *fieldp = NULL; + char buf[BUFSIZ]; + char expansion[BUFSIZ]; + int num = 0; + + switch (tag) { + case RPMTAG_SOURCE: + flag = RPMBUILD_ISSOURCE; + name = "source"; + fieldp = spec->line + 6; + break; + case RPMTAG_PATCH: + flag = RPMBUILD_ISPATCH; + name = "patch"; + fieldp = spec->line + 5; + break; + case RPMTAG_ICON: + flag = RPMBUILD_ISICON; + break; } - /* At this point the package does not exist */ - - if (! (flags & LP_CREATE)) { - return 0; - } + /* Get the number */ + if (tag != RPMTAG_ICON) { + /* We already know that a ':' exists, and that there */ + /* are no spaces before it. */ - /* Create it */ - package = new_packagerec(); - if (name) { - if (flags & LP_SUBNAME) { - package->subname = strdup(name); - } else if (flags & LP_NEWNAME) { - package->newname = strdup(name); + nump = buf; + while (*fieldp != ':') { + *nump++ = *fieldp++; } - } - - /* Link it in to the spec */ - ppp = &(s->packages); - while (*ppp) { - ppp = &((*ppp)->next); - } - *ppp = package; + *nump = '\0'; - *pr = package; - return 1; -} - -static void generateNames(Spec s) -{ - struct PackageRec *package; - char buf[1024]; - char *name; - - package = s->packages; - while (package) { - if (package->subname) { - sprintf(buf, "%s-%s", s->name, package->subname); - name = buf; - } else if (package->newname) { - name = package->newname; + nump = buf; + SKIPSPACE(nump); + if (! *nump) { + num = 0; } else { - /* Must be the main package */ - name = s->name; + if (parseNum(buf, &num)) { + rpmError(RPMERR_BADSPEC, "line %d: Bad %s number: %s\n", + spec->lineNum, name, spec->line); + return RPMERR_BADSPEC; + } } - headerAddEntry(package->header, RPMTAG_NAME, RPM_STRING_TYPE, name, 1); - - package = package->next; } -} - -/* datestr is of the form 'Wed Jan 1 1997' */ -static int dateToTimet(const char * datestr, time_t * secs) -{ - struct tm time; - char * chptr, * end, ** idx; - char * date = strcpy(alloca(strlen(datestr) + 1), datestr); - static char * days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", - NULL }; - static char * months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; - static char lengths[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - memset(&time, 0, sizeof(time)); - - end = chptr = date; - - /* day of week */ - if ((chptr = strtok(date, " \t\n")) == NULL) return -1; - idx = days; - while (*idx && strcmp(*idx, chptr)) idx++; - if (!*idx) return -1; - - /* month */ - if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; - idx = months; - while (*idx && strcmp(*idx, chptr)) idx++; - if (!*idx) return -1; - - time.tm_mon = idx - months; - - /* day */ - if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; - - /* make this noon so the day is always right (as we make this UTC) */ - time.tm_hour = 12; - - time.tm_mday = strtol(chptr, &chptr, 10); - if (*chptr) return -1; - if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1; - /* year */ - if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1; - - time.tm_year = strtol(chptr, &chptr, 10); - if (*chptr) return -1; - if (time.tm_year < 1997 || time.tm_year >= 3000) return -1; - time.tm_year -= 1900; - - *secs = mktime(&time); - if (*secs == -1) return -1; - - /* adjust to GMT */ - *secs += timezone; - - return 0; -} - -static void addChangelogEntry(Header h, int time, char *name, char *text) -{ - if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) { - headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, - &time, 1); - headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, - &name, 1); - headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, - &text, 1); + /* Create the entry and link it in */ + p = malloc(sizeof(struct Source)); + p->num = num; + p->fullSource = strdup(field); + p->source = strrchr(p->fullSource, '/'); + p->flags = flag; + if (p->source) { + p->source++; } else { - headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, - &time, 1); - headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, - &name, 1); - headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, - &text, 1); - } -} - -static int addChangelog(Header h, StringBuf sb) -{ - char *s; - int i; - int time, lastTime = 0; - char *date, *name, *text, *next; - - s = getStringBuf(sb); - - /* skip space */ - while (*s && isspace(*s)) s++; - - while (*s) { - if (*s != '*') { - rpmError(RPMERR_BADSPEC, "%%changelog entries must start with *"); - return RPMERR_BADSPEC; - } - - /* find end of line */ - date = s; - while (*s && *s != '\n') s++; - if (! *s) { - rpmError(RPMERR_BADSPEC, "incomplete %%changelog entry"); - return RPMERR_BADSPEC; - } - *s = '\0'; - text = s + 1; - - /* 4 fields of date */ - date++; - s = date; - for (i = 0; i < 4; i++) { - while (*s && isspace(*s)) s++; - while (*s && !isspace(*s)) s++; - } - while (isspace(*date)) date++; - if (dateToTimet(date, (time_t *)&time)) { - rpmError(RPMERR_BADSPEC, "bad date in %%changelog: %s", date); - return RPMERR_BADSPEC; - } - if (lastTime && lastTime < time) { - rpmError(RPMERR_BADSPEC, - "%%changelog not in decending chronological order"); - return RPMERR_BADSPEC; - } - lastTime = time; - - /* skip space to the name */ - while (*s && isspace(*s)) s++; - if (! *s) { - rpmError(RPMERR_BADSPEC, "missing name in %%changelog"); - return RPMERR_BADSPEC; - } - - /* name */ - name = s; - while (*s) s++; - while (s > name && isspace(*s)) { - *s-- = '\0'; - } - if (s == name) { - rpmError(RPMERR_BADSPEC, "missing name in %%changelog"); - return RPMERR_BADSPEC; - } - - /* text */ - while (*text && isspace(*text)) text++; - if (! *text) { - rpmError(RPMERR_BADSPEC, "no description in %%changelog"); - return RPMERR_BADSPEC; - } - - /* find the next leading '*' (or eos) */ - s = text; - do { - s++; - } while (*s && (*(s-1) != '\n' || *s != '*')); - next = s; - s--; - - /* backup to end of description */ - while ((s > text) && isspace(*s)) { - *s-- = '\0'; - } - - addChangelogEntry(h, time, name, text); - s = next; + p->source = p->fullSource; } - return 0; -} - -/**********************************************************************/ -/* */ -/* Line reading */ -/* */ -/**********************************************************************/ - -static int match_arch(char *s) -{ - char *tok, *arch; - int sense, match; - - rpmGetArchInfo(&arch, NULL); - match = 0; - - tok = strtok(s, " \n\t"); - sense = (! strcmp(tok, "%ifarch")) ? 1 : 0; - - while ((tok = strtok(NULL, " \n\t"))) { - if (! strcmp(tok, arch)) { - match |= 1; - } + if (tag != RPMTAG_ICON) { + p->next = spec->sources; + spec->sources = p; + } else { + p->next = pkg->icon; + pkg->icon = p; } - return (sense == match); -} - -static int match_os(char *s) -{ - char *tok, *os; - int sense, match; - - rpmGetOsInfo(&os, NULL); - match = 0; - - tok = strtok(s, " \n\t"); - sense = (! strcmp(tok, "%ifos")) ? 1 : 0; + spec->numSources++; - while ((tok = strtok(NULL, " \n\t"))) { - if (! strcmp(tok, os)) { - match |= 1; - } + if (tag != RPMTAG_ICON) { + sprintf(expansion, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), p->source); + sprintf(buf, "%s%d", + (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num); + addMacro(&spec->macros, buf, expansion); + sprintf(buf, "%sURL%d", + (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num); + addMacro(&spec->macros, buf, p->fullSource); } - - return (sense == match); -} - -static struct read_level_entry { - int reading; /* 1 if we are reading at this level */ - struct read_level_entry *next; -} *read_level = NULL; - -static int read_line(FILE *f, char *line) -{ - static struct read_level_entry *rl; - int gotline; - char *r; - char *firstChar; - - do { - gotline = 0; - if (! fgets(line, LINE_BUF_SIZE, f)) { - /* the end */ - if (read_level->next) { - rpmError(RPMERR_UNMATCHEDIF, "Unclosed %%if"); - return RPMERR_UNMATCHEDIF; - } else { - return 0; - } - } - firstChar = line; - while (*firstChar && isspace(*firstChar)) { - firstChar++; - } - if ((! strncmp("%ifarch", firstChar, 7)) || - (! strncmp("%ifnarch", firstChar, 8))) { - expandMacros(line); - rl = malloc(sizeof(struct read_level_entry)); - rl->next = read_level; - rl->reading = read_level->reading && match_arch(line); - read_level = rl; - } else if ((! strncmp("%ifos", firstChar, 5)) || - (! strncmp("%ifnos", firstChar, 6))) { - expandMacros(line); - rl = malloc(sizeof(struct read_level_entry)); - rl->next = read_level; - rl->reading = read_level->reading && match_os(line); - read_level = rl; - } else if (! strncmp("%else", firstChar, 5)) { - expandMacros(line); - if (! read_level->next) { - /* Got an else with no %if ! */ - rpmError(RPMERR_UNMATCHEDIF, "Got a %%else with no if"); - return RPMERR_UNMATCHEDIF; - } - read_level->reading = - read_level->next->reading && ! read_level->reading; - } else if (! strncmp("%endif", firstChar, 6)) { - expandMacros(line); - if (! read_level->next) { - rpmError(RPMERR_UNMATCHEDIF, "Got a %%endif with no if"); - return RPMERR_UNMATCHEDIF; - } - rl = read_level; - read_level = rl->next; - free(rl); - } else { - if (read_level->reading) { - expandMacros(line); - } - gotline = 1; - } - } while (! (gotline && read_level->reading)); - r = line + (strlen(line)) - 1; - while (isspace(*r)) { - *(r--) = '\0'; - } - return 1; + return 0; } -/**********************************************************************/ -/* */ -/* Line parsing */ -/* */ -/**********************************************************************/ - -struct preamble_line { - int tag; - int len; - char *token; -} preamble_spec[] = { - {RPMTAG_NAME, 0, "name"}, - {RPMTAG_VERSION, 0, "version"}, - {RPMTAG_RELEASE, 0, "release"}, - {RPMTAG_SERIAL, 0, "serial"}, - {RPMTAG_DESCRIPTION, 0, "description"}, - {RPMTAG_SUMMARY, 0, "summary"}, - {RPMTAG_COPYRIGHT, 0, "copyright"}, - {RPMTAG_COPYRIGHT, 0, "license"}, - {RPMTAG_DISTRIBUTION, 0, "distribution"}, - {RPMTAG_VENDOR, 0, "vendor"}, - {RPMTAG_GROUP, 0, "group"}, - {RPMTAG_PACKAGER, 0, "packager"}, - {RPMTAG_URL, 0, "url"}, - {RPMTAG_ROOT, 0, "root"}, - {RPMTAG_SOURCE, 0, "source"}, - {RPMTAG_PATCH, 0, "patch"}, - {RPMTAG_NOSOURCE, 0, "nosource"}, - {RPMTAG_NOPATCH, 0, "nopatch"}, - {RPMTAG_EXCLUDEARCH, 0, "excludearch"}, - {RPMTAG_EXCLUSIVEARCH, 0, "exclusivearch"}, - {RPMTAG_EXCLUDEOS, 0, "excludeos"}, - {RPMTAG_EXCLUSIVEOS, 0, "exclusiveos"}, - {RPMTAG_EXCLUDE, 0, "exclude"}, - {RPMTAG_EXCLUSIVE, 0, "exclusive"}, - {RPMTAG_ICON, 0, "icon"}, - {RPMTAG_PROVIDES, 0, "provides"}, - {RPMTAG_REQUIREFLAGS, 0, "requires"}, - {RPMTAG_PREREQ, 0, "prereq"}, - {RPMTAG_CONFLICTFLAGS, 0, "conflicts"}, - {RPMTAG_OBSOLETES, 0, "obsoletes"}, - {RPMTAG_DEFAULTPREFIX, 0, "prefix"}, - {RPMTAG_BUILDROOT, 0, "buildroot"}, - {RPMTAG_BUILDARCHS, 0, "buildarchitectures"}, - {RPMTAG_AUTOREQPROV, 0, "autoreqprov"}, - {0, 0, 0} -}; - -static int find_preamble_line(char *line, char **s) +char *getSource(Spec spec, int num, int flag) { - struct preamble_line *p = preamble_spec; - - while (p->token && strncasecmp(line, p->token, p->len)) { - p++; - } - if (!p->token) return 0; - *s = line + p->len; - - /* Unless this is a source or a patch, a ':' better be next */ - if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) { - *s += strspn(*s, " \t"); - if (**s != ':') { - return 0; - } - } - - *s += strspn(*s, ": \t"); - return p->tag; + return getSourceAux(spec, num, flag, 0); } -/* None of these can be 0 !! */ -#define PREAMBLE_PART 1 -#define PREP_PART 2 -#define BUILD_PART 3 -#define INSTALL_PART 4 -#define CLEAN_PART 5 -#define PREIN_PART 6 -#define POSTIN_PART 7 -#define PREUN_PART 8 -#define POSTUN_PART 9 -#define FILES_PART 10 -#define CHANGELOG_PART 11 -#define DESCRIPTION_PART 12 -#define TRIGGERIN_PART 13 -#define TRIGGERUN_PART 14 -#define VERIFYSCRIPT_PART 15 - -static struct part_rec { - int part; - int len; - char *s; -} part_list[] = { - {PREAMBLE_PART, 0, "%package"}, - {PREP_PART, 0, "%prep"}, - {BUILD_PART, 0, "%build"}, - {INSTALL_PART, 0, "%install"}, - {CLEAN_PART, 0, "%clean"}, - {PREUN_PART, 0, "%preun"}, - {POSTUN_PART, 0, "%postun"}, - {PREIN_PART, 0, "%pre"}, - {POSTIN_PART, 0, "%post"}, - {FILES_PART, 0, "%files"}, - {CHANGELOG_PART, 0, "%changelog"}, - {DESCRIPTION_PART, 0, "%description"}, - {TRIGGERUN_PART, 0, "%triggerun"}, - {TRIGGERIN_PART, 0, "%trigger"}, - {VERIFYSCRIPT_PART, 0, "%verifyscript"}, - {0, 0, 0} -}; - -static int check_part(char *line, char **s) +char *getFullSource(Spec spec, int num, int flag) { - struct part_rec *p = part_list; - - while (p->s && strncmp(line, p->s, p->len)) { - p++; - } - if (!p) return 0; - *s = line + p->len; - *s += strspn(*s, " \t"); - if (**s == '\0') { - *s = NULL; - } - return p->part; + return getSourceAux(spec, num, flag, 1); } -#if 0 -static char *chop_line(char *s) +static char *getSourceAux(Spec spec, int num, int flag, int full) { - char *p, *e; - - p = s; - p += strspn(s, " \t"); - if (*p == '\0') { - return NULL; - } - e = s + strlen(s) - 1; - while (index(" \t", *e)) { - e--; - } - return p; -} -#endif + struct Source *p = spec->sources; -static void addListEntry(Header h, int_32 tag, char *line) -{ - int argc; - char **argv; - char **argvs; - char *s; + p = findSource(spec, num, flag); - argvs = argv = malloc(strlen(line) * sizeof(char *)); - argc = 0; - while ((s = strtok(line, " \t"))) { - *argv = s; - argc++; - argv++; - line = NULL; - } - if (argc) { - headerAddEntry(h, tag, RPM_STRING_ARRAY_TYPE, argvs, argc); - } - free(argvs); + return (p) ? (full ? p->fullSource : p->source) : NULL; } -static int finishCurrentPart(Spec spec, StringBuf sb, - struct PackageRec *cur_package, - int cur_part, char *triggerArgs, - char *scriptProg) +static struct Source *findSource(Spec spec, int num, int flag) { - int t1 = 0; - int t2 = 0; - - stripTrailingBlanksStringBuf(sb); - - switch (cur_part) { - case PREIN_PART: - t1 = RPMTAG_PREIN; - t2 = RPMTAG_PREINPROG; - break; - case POSTIN_PART: - t1 = RPMTAG_POSTIN; - t2 = RPMTAG_POSTINPROG; - break; - case PREUN_PART: - t1 = RPMTAG_PREUN; - t2 = RPMTAG_PREUNPROG; - break; - case POSTUN_PART: - t1 = RPMTAG_POSTUN; - t2 = RPMTAG_POSTUNPROG; - break; - case VERIFYSCRIPT_PART: - t1 = RPMTAG_VERIFYSCRIPT; - break; - case DESCRIPTION_PART: - t1 = RPMTAG_DESCRIPTION; - break; - case CHANGELOG_PART: - /* %changelog is a little special. It goes in the */ - /* "main" package no matter where it appears, and it */ - /* ends up in all the packages. */ - if (addChangelog(spec->packages->header, sb)) { - return 1; - } - break; - case TRIGGERIN_PART: - if (addTrigger(cur_package, RPMSENSE_TRIGGER_IN, - getStringBuf(sb), triggerArgs)) { - return 1; - } - break; - case TRIGGERUN_PART: - if (addTrigger(cur_package, RPMSENSE_TRIGGER_UN, - getStringBuf(sb), triggerArgs)) { - return 1; - } - break; - } - if (t1 && (*(getStringBuf(sb)) != '\0')) { - headerAddEntry(cur_package->header, t1, - RPM_STRING_TYPE, getStringBuf(sb), 1); - } - if (t2) { - addReqProv(cur_package, RPMSENSE_PREREQ, scriptProg, NULL); - headerAddEntry(cur_package->header, t2, - RPM_STRING_TYPE, scriptProg, 1); - } - return 0; -} + struct Source *p = spec->sources; -/**********************************************************************/ -/* */ -/* Main specfile parsing routine */ -/* */ -/**********************************************************************/ - -Spec *parseSpec(FILE *f, char *specfile, char *buildRootOverride) -{ - Spec *res; - Spec s; - char **archs = NULL; - char **arch; - int i, count; - - s = parseSpecAux(f, specfile, buildRootOverride, &archs); - - if (s) { - /* No BuildArchitectures field */ - res = (Spec *) malloc(2 * sizeof(Spec)); - res[0] = s; - res[1] = NULL; - return res; - } - - if (! archs) { - /* Error */ - return NULL; - } - - /* We have a BuildArchitectures field */ - count = 0; - while (archs[count]) { - count++; - } - res = (Spec *) malloc(count * sizeof(Spec)); - - i = 0; - arch = archs; - while (*arch) { - if (rpmMachineScore(RPM_MACHTABLE_BUILDARCH, *arch)) { - rewind(f); - rpmSetMachine(*arch, NULL); - res[i] = parseSpecAux(f, specfile, buildRootOverride, NULL); - if (! res[i]) { - /* Error */ - freeSplitString(archs); - while (i) { - i--; - freeSpec(res[i]); - } - free(res); - return NULL; - } - headerAddEntry(res[i]->packages->header, RPMTAG_BUILDARCHS, - RPM_STRING_ARRAY_TYPE, archs, count); - res[i]->buildArch = strdup(*arch); - i++; + while (p) { + if ((num == p->num) && (p->flags & flag)) { + return p; } - arch++; + p = p->next; } - res[i] = NULL; - freeSplitString(archs); - - return res; + return NULL; } -Spec parseSpecAux(FILE *f, char *specfile, char *buildRootOverride, - char ***buildArchs) +void freeSources(Spec spec) { - char buf[LINE_BUF_SIZE]; /* read buffer */ - char buf2[LINE_BUF_SIZE]; - char fileFile[LINE_BUF_SIZE]; - char scriptProg[LINE_BUF_SIZE]; - char triggerArgs[LINE_BUF_SIZE]; - char *line; /* "parsed" read buffer */ - - int x, serial, tag, cur_part; - int lookupopts; - StringBuf sb; - char *s = NULL; - char *s1, *s2; - int gotBuildroot = 0; - int gotRoot = 0; - int versionMacroSet = 0; - int releaseMacroSet = 0; - char *arch, *os; - - struct PackageRec *cur_package = NULL; - Spec spec = (struct SpecRec *) malloc(sizeof(struct SpecRec)); - - spec->name = NULL; - spec->specfile = strdup(specfile); - spec->numSources = 0; - spec->numPatches = 0; - spec->sources = NULL; - spec->prep = newStringBuf(); - spec->build = newStringBuf(); - spec->install = newStringBuf(); - spec->doc = newStringBuf(); - spec->clean = newStringBuf(); - spec->packages = NULL; - spec->noSource = NULL; - spec->noPatch = NULL; - spec->numNoSource = 0; - spec->numNoPatch = 0; - spec->buildroot = NULL; - spec->autoReqProv = 1; - spec->buildArch = NULL; - - sb = newStringBuf(); - reset_spec(); /* Reset the parser */ + struct Source *p1, *p2; - rpmGetArchInfo(&arch, NULL); - rpmGetOsInfo(&os, NULL); - addMacro("buildarch", arch); - addMacro("buildos", os); - - scriptProg[0] = '\0'; - cur_part = PREAMBLE_PART; - while ((x = read_line(f, buf)) > 0) { - line = buf; - s = NULL; - if ((tag = check_part(line, &s))) { - rpmMessage(RPMMESS_DEBUG, "Switching to part: %d\n", tag); - if (finishCurrentPart(spec, sb, cur_package, - cur_part, triggerArgs, scriptProg)) { - return NULL; - } - cur_part = tag; - truncStringBuf(sb); - - /* Now switch the current package to s */ - if (s) { - switch (tag) { - case PREP_PART: - case BUILD_PART: - case INSTALL_PART: - case CLEAN_PART: - case CHANGELOG_PART: - rpmError(RPMERR_BADARG, "Tag takes no arguments: %s", s); - return NULL; - } - } - - /* Rip through s for -f in %files */ - /* not only is this code disgusting, but it allows -f on any tag */ - fileFile[0] = '\0'; - s1 = NULL; - if (s && - ((s1 = strstr(s, " -f ")) || - (!strncmp(s, "-f ", 3)))) { - if (s1) { - s1[0] = ' '; - s1++; - } else { - s1 = s; - } - s1[0] = ' '; s1[1] = ' '; s1[2] = ' '; - s1 += 3; - while (isspace(*s1)) { - s1++; - } - - s2 = fileFile; - while (*s1 && !isspace(*s1)) { - *s2 = *s1; - *s1 = ' '; - s1++; - s2++; - } - *s2 = '\0'; - while (isspace(*s)) { - s++; - } - if (! *s) { - s = NULL; - } - } - - rpmMessage(RPMMESS_DEBUG, "fileFile = %s\n", - fileFile[0] ? fileFile : "(null)"); - - /* If trigger, pull off the args */ - if (tag == TRIGGERIN_PART || tag == TRIGGERUN_PART) { - s1 = strstr(s, "--"); - if (s1) { - strcpy(triggerArgs, s1+2); - *s1 = '\0'; - s = strtok(s, " \n\t"); - } else { - strcpy(triggerArgs, s); - s = NULL; - } - } - - /* find possible -p <prog> */ - if ((tag == PREIN_PART) || - (tag == POSTIN_PART) || - (tag == PREUN_PART) || - (tag == POSTUN_PART)) { - - scriptProg[0] = '\0'; - s1 = NULL; - - if (s && - ((s1 = strstr(s, " -p ")) || - (!strncmp(s, "-p ", 3)))) { - - if (s1) { - s1[0] = ' '; - s1++; - } else { - s1 = s; - } - s1[0] = ' '; s1[1] = ' '; s1[2] = ' '; - s1 += 3; - while (isspace(*s1)) { - s1++; - } - - s2 = scriptProg; - while (*s1 && !isspace(*s1)) { - *s2 = *s1; - *s1 = ' '; - s1++; - s2++; - } - - *s2 = '\0'; - while (isspace(*s)) { - s++; - } - if (! *s) { - s = NULL; - } - } - - /* defaults to /bin/sh */ - if (! scriptProg[0]) { - strcpy(scriptProg, "/bin/sh"); - } else { - if (scriptProg[0] != '/') { - rpmError(RPMERR_BADSPEC, "pre/post -p arg must begin with \'/\': %s", scriptProg); - return NULL; - } - } - rpmMessage(RPMMESS_DEBUG, "scriptProg = %s\n", scriptProg); - } - - /* At this point s is the remaining args, which can only */ - /* be -n <pkg>, or simply <pkg>. */ - - /* Handle -n in part tags */ - lookupopts = 0; - if (s) { - if (!strncmp(s, "-n", 2)) { - s += 2; - s += strspn(s, ": \t"); - if (*s == '\0') { - rpmError(RPMERR_BADARG, "-n takes argument"); - return NULL; - } - lookupopts = LP_NEWNAME; - } else { - lookupopts = LP_SUBNAME; - } - /* Handle trailing whitespace */ - s1 = s + strlen(s) - 1; - while (*s1 == ' ' || *s1 == '\n' || *s1 == '\t') { - s1--; - } - s1++; - *s1 = '\0'; - } - - switch (tag) { - case PREP_PART: - case BUILD_PART: - case INSTALL_PART: - case CLEAN_PART: - case CHANGELOG_PART: - /* Do not switch parts for these */ - break; - case PREAMBLE_PART: - lookupopts |= LP_CREATE | LP_FAIL_EXISTS; - /* Fall through */ - default: - /* XXX - should be able to drop the -n in non-%package parts */ - if (! lookup_package(spec, &cur_package, s, lookupopts)) { - rpmError(RPMERR_INTERNAL, "Package lookup failed: %s", - (s) ? s : "(main)"); - return NULL; - } - rpmMessage(RPMMESS_DEBUG, "Switched to package: %s\n", - s ? s : "(main)"); - } - - if (cur_part == FILES_PART) { - /* set files to 0 (current -1 means no %files, no package */ - cur_package->files = 0; - if (fileFile[0]) { - cur_package->fileFile = strdup(fileFile); - } - } - - /* This line has no content -- it was just a control line */ - continue; - } - - /* Check for implicit "base" package. */ - /* That means that the specfile does not start with %package */ - if (! cur_package) { - lookupopts = 0; - if (cur_part == PREAMBLE_PART) { - lookupopts = LP_CREATE | LP_FAIL_EXISTS; - } - if (! lookup_package(spec, &cur_package, NULL, lookupopts)) { - rpmError(RPMERR_INTERNAL, "Base package lookup failed!"); - return NULL; - } - rpmMessage(RPMMESS_DEBUG, "Switched to BASE package\n"); - } - - switch (cur_part) { - case PREAMBLE_PART: - if ((tag = find_preamble_line(line, &s))) { - switch (tag) { - case RPMTAG_EXCLUDE: - case RPMTAG_EXCLUSIVE: - rpmMessage(RPMMESS_WARNING, - "Exclude/Exclusive are depricated.\n" - "Use ExcludeArch/ExclusiveArch instead.\n"); - sprintf(buf2, "%s %s", - (tag == RPMTAG_EXCLUDE) ? "%ifarch" : "%ifnarch", - s); - if (match_arch(buf2)) { - rpmError(RPMERR_BADARCH, "Arch mismatch!"); - return NULL; - } - addListEntry(cur_package->header, - (tag == RPMTAG_EXCLUDE) ? - RPMTAG_EXCLUDEARCH : RPMTAG_EXCLUSIVEARCH, - s); - break; - case RPMTAG_EXCLUDEARCH: - case RPMTAG_EXCLUSIVEARCH: - sprintf(buf2, "%s %s", (tag == RPMTAG_EXCLUDEARCH) ? - "%ifarch" : "%ifnarch", s); - if (match_arch(buf2)) { - rpmError(RPMERR_BADARCH, "Arch mismatch!"); - return NULL; - } - addListEntry(cur_package->header, tag, s); - break; - case RPMTAG_EXCLUDEOS: - case RPMTAG_EXCLUSIVEOS: - sprintf(buf2, "%s %s", (tag == RPMTAG_EXCLUDEOS) ? - "%ifos" : "%ifnos", s); - if (match_os(buf2)) { - rpmError(RPMERR_BADOS, "OS mismatch!"); - return NULL; - } - addListEntry(cur_package->header, tag, s); - break; - case RPMTAG_NAME: - s1 = s; - while (*s1 && *s1 != ' ' && *s1 != '\t') s1++; - *s1 = '\0'; - if (!spec->name) { - spec->name = strdup(s); - } - /* The NAME entries must be generated after */ - /* the whole spec file is parsed. */ - break; - case RPMTAG_VERSION: - case RPMTAG_RELEASE: - s1 = s; - while (*s1 && *s1 != ' ' && *s1 != '\t') s1++; - *s1 = '\0'; - if (s1 == s) { - rpmError(RPMERR_BADSPEC, (tag == RPMTAG_VERSION) ? - "Empty version field." : - "Empty release field."); - return NULL; - } - if (tag == RPMTAG_VERSION) { - if (! versionMacroSet) { - versionMacroSet = 1; - addMacro("PACKAGE_VERSION", s); - } - } else { - if (! releaseMacroSet) { - releaseMacroSet = 1; - addMacro("PACKAGE_RELEASE", s); - } - } - case RPMTAG_SUMMARY: - case RPMTAG_DISTRIBUTION: - case RPMTAG_VENDOR: - case RPMTAG_COPYRIGHT: - case RPMTAG_PACKAGER: - case RPMTAG_GROUP: - case RPMTAG_URL: - headerAddEntry(cur_package->header, tag, RPM_STRING_TYPE, s, 1); - break; - case RPMTAG_BUILDARCHS: - if (buildArchs) { - *buildArchs = splitString(s, strlen(s), ' '); - freeSpec(spec); - freeStringBuf(sb); - return NULL; - } - break; - case RPMTAG_BUILDROOT: - gotBuildroot = 1; - spec->buildroot = strdup(s); - break; - case RPMTAG_DEFAULTPREFIX: - headerAddEntry(cur_package->header, tag, RPM_STRING_TYPE, s, 1); - break; - case RPMTAG_SERIAL: - serial = atoi(s); - headerAddEntry(cur_package->header, tag, RPM_INT32_TYPE, &serial, 1); - break; - case RPMTAG_DESCRIPTION: - /* Special case -- need to handle backslash */ - truncStringBuf(sb); - while (1) { - s1 = s + strlen(s) - 1; - if (*s1 != '\\') { - break; - } - *s1 = '\0'; - appendLineStringBuf(sb, s); - read_line(f, buf); - s = buf; - } - appendStringBuf(sb, s); - headerAddEntry(cur_package->header, RPMTAG_DESCRIPTION, - RPM_STRING_TYPE, getStringBuf(sb), 1); - break; - case RPMTAG_ROOT: - /* special case */ - gotRoot = 1; - rpmMessage(RPMMESS_DEBUG, "Got root: %s\n", s); - rpmMessage(RPMMESS_WARNING, "The Root: tag is depricated. Use Buildroot: instead\n"); - rpmSetVar(RPMVAR_ROOT, s); - break; - case RPMTAG_ICON: - cur_package->icon = strdup(s); - break; - case RPMTAG_NOPATCH: - case RPMTAG_NOSOURCE: - if (noSourcePatch(spec, s, tag)) { - return NULL; - } - break; - case RPMTAG_SOURCE: - case RPMTAG_PATCH: - if (addSource(spec, line)) { - return NULL; - } - break; - case RPMTAG_OBSOLETES: - case RPMTAG_PROVIDES: - if (parseProvides(cur_package, s, tag)) { - return NULL; - } - break; - case RPMTAG_REQUIREFLAGS: - case RPMTAG_CONFLICTFLAGS: - case RPMTAG_PREREQ: - if (parseRequiresConflicts(cur_package, s, tag)) { - return NULL; - } - break; - case RPMTAG_AUTOREQPROV: - s1 = strtok(s, " \t\n"); - if (!s1) { - spec->autoReqProv = 0; - } else if (s1[0] == 'n' || s1[0] == 'N') { - spec->autoReqProv = 0; - } else if (!strcasecmp(s1, "false")) { - spec->autoReqProv = 0; - } else if (!strcasecmp(s1, "off")) { - spec->autoReqProv = 0; - } else if (!strcmp(s1, "0")) { - spec->autoReqProv = 0; - } - break; - default: - /* rpmMessage(RPMMESS_DEBUG, "Skipping: %s\n", line); */ - /* This shouldn't happen? */ - rpmError(RPMERR_INTERNAL, "Bogus token"); - return NULL; - } - } else { - /* Not a recognized preamble part */ - s1 = line; - while (*s1 && (*s1 == ' ' || *s1 == '\t')) s1++; - /* Handle blanks lines and comments */ - if (*s1 && (*s1 != '#')) { - /*rpmMessage(RPMMESS_WARNING, "Unknown Field: %s\n", line);*/ - rpmError(RPMERR_BADSPEC, "Unknown Field: %s\n", line); - return NULL; - } - } - break; - case PREP_PART: - appendLineStringBuf(spec->prep, line); - break; - case BUILD_PART: - appendLineStringBuf(spec->build, line); - break; - case INSTALL_PART: - appendLineStringBuf(spec->install, line); - break; - case CLEAN_PART: - appendLineStringBuf(spec->clean, line); - break; - case DESCRIPTION_PART: - case CHANGELOG_PART: - case PREIN_PART: - case POSTIN_PART: - case PREUN_PART: - case POSTUN_PART: - case VERIFYSCRIPT_PART: - appendLineStringBuf(sb, line); - break; - case TRIGGERIN_PART: - case TRIGGERUN_PART: - appendLineStringBuf(sb, line); - break; - case FILES_PART: - s1 = line; - while (*s1 && (*s1 == ' ' || *s1 == '\t')) s1++; - /* Handle blanks lines and comments */ - if (*s1 && (*s1 != '#')) { - cur_package->files++; - appendLineStringBuf(cur_package->filelist, line); - } - break; - default: - rpmError(RPMERR_INTERNAL, "Bad part"); - return NULL; - } /* switch */ - } - if (x < 0) { - return NULL; - } - - /* finish current part */ - if (finishCurrentPart(spec, sb, cur_package, - cur_part, triggerArgs, - scriptProg)) { - return NULL; - } - - freeStringBuf(sb); - - if (gotRoot && gotBuildroot) { - freeSpec(spec); - rpmError(RPMERR_BADSPEC, - "Spec file can not have both Root: and Buildroot:"); - return NULL; - } - if (spec->buildroot) { - /* This package can do build roots */ - if (buildRootOverride) { - rpmSetVar(RPMVAR_ROOT, buildRootOverride); - rpmSetVar(RPMVAR_BUILDROOT, buildRootOverride); - } else { - if ((s = rpmGetVar(RPMVAR_BUILDROOT))) { - /* Take build prefix from rpmrc */ - rpmSetVar(RPMVAR_ROOT, s); - } else { - /* Use default */ - rpmSetVar(RPMVAR_ROOT, spec->buildroot); - rpmSetVar(RPMVAR_BUILDROOT, spec->buildroot); - } - } - } else { - /* Package can not do build prefixes */ - if (buildRootOverride) { - freeSpec(spec); - rpmError(RPMERR_BADARG, "Package can not do build prefixes"); - return NULL; - } + p1 = spec->sources; + while (p1) { + p2 = p1; + p1 = p1->next; + FREE(p2->fullSource); + free(p2); } - - generateNames(spec); - return spec; } -/**********************************************************************/ -/* */ -/* Resets the parser */ -/* */ -/**********************************************************************/ - -static void reset_spec() +int parseNoSource(Spec spec, char *field, int tag) { - static done = 0; - struct read_level_entry *rl; - struct preamble_line *p = preamble_spec; - struct part_rec *p1 = part_list; - - rpmSetVar(RPMVAR_ROOT, NULL); - - while (read_level) { - rl = read_level; - read_level = read_level->next; - free(rl); + char buf[BUFSIZ]; + char *s, *name; + int num, flag; + struct Source *p; + + if (tag == RPMTAG_NOSOURCE) { + flag = RPMBUILD_ISSOURCE; + name = "source"; + } else { + flag = RPMBUILD_ISPATCH; + name = "patch"; } - read_level = malloc(sizeof(struct read_level_entry)); - read_level->next = NULL; - read_level->reading = 1; - - resetMacros(); - if (! done) { - /* Put one time only things in here */ - while (p->tag) { - p->len = strlen(p->token); - p++; - } - while (p1->part) { - p1->len = strlen(p1->s); - p1++; + strcpy(buf, field); + field = buf; + while ((s = strtok(field, ", \t"))) { + if (parseNum(s, &num)) { + rpmError(RPMERR_BADSPEC, "line %d: Bad number: %s", + spec->lineNum, spec->line); + return RPMERR_BADSPEC; } - done = 1; - } -} - -/**********************************************************************/ -/* */ -/* Spec struct dumping (for debugging) */ -/* */ -/**********************************************************************/ + if (! (p = findSource(spec, num, flag))) { + rpmError(RPMERR_BADSPEC, "line %d: Bad no%s number: %d", + spec->lineNum, name, num); + return RPMERR_BADSPEC; + } -void dumpSpec(Spec s, FILE *f) -{ - struct PackageRec *p; - - fprintf(f, "########################################################\n"); - fprintf(f, "SPEC NAME = (%s)\n", s->name); - fprintf(f, "PREP =v\n"); - fprintf(f, "%s", getStringBuf(s->prep)); - fprintf(f, "PREP =^\n"); - fprintf(f, "BUILD =v\n"); - fprintf(f, "%s", getStringBuf(s->build)); - fprintf(f, "BUILD =^\n"); - fprintf(f, "INSTALL =v\n"); - fprintf(f, "%s", getStringBuf(s->install)); - fprintf(f, "INSTALL =^\n"); - fprintf(f, "CLEAN =v\n"); - fprintf(f, "%s", getStringBuf(s->clean)); - fprintf(f, "CLEAN =^\n"); + p->flags |= RPMBUILD_ISNO; - p = s->packages; - while (p) { - dumpPackage(p, f); - p = p->next; + field = NULL; } -} - -static void dumpPackage(struct PackageRec *p, FILE *f) -{ - fprintf(f, "_________________________________________________________\n"); - fprintf(f, "SUBNAME = (%s)\n", p->subname); - fprintf(f, "NEWNAME = (%s)\n", p->newname); - fprintf(f, "FILES = %d\n", p->files); - fprintf(f, "FILES =v\n"); - fprintf(f, "%s", getStringBuf(p->filelist)); - fprintf(f, "FILES =^\n"); - fprintf(f, "HEADER =v\n"); - headerDump(p->header, f, 1, rpmTagTable); - fprintf(f, "HEADER =^\n"); + return 0; } diff --git a/build/spec.h b/build/spec.h index d6d967c0e..28d73697a 100644 --- a/build/spec.h +++ b/build/spec.h @@ -1,23 +1,127 @@ -/* RPM - Copyright (C) 1995 Red Hat Software - * - * spec.h - routines for parsing are looking up info in a spec file - */ - #ifndef _SPEC_H_ #define _SPEC_H_ -#include <stdio.h> +#include "header.h" +#include "stringbuf.h" +#include "macro.h" + +#if 0 +struct ReqProvTrigger { + int flags; + char *name; + char *version; + int index; /* Only used for triggers */ + struct ReqProvTrigger *next; +}; +#endif + +#define RPMBUILD_ISSOURCE 1 +#define RPMBUILD_ISPATCH (1 << 1) +#define RPMBUILD_ISICON (1 << 2) +#define RPMBUILD_ISNO (1 << 3) + +#define RPMBUILD_DEFAULT_LANG "C" + +struct Source { + char *fullSource; + char *source; /* Pointer into fullSource */ + int flags; + int num; + struct Source *next; +}; + +struct ReadLevelEntry { + int reading; + struct ReadLevelEntry *next; +}; + +struct SpecStruct { + char *specFile; + char *sourceRpmName; + + FILE *file; + char readBuf[BUFSIZ]; + char *readPtr; + char line[BUFSIZ]; + int lineNum; + + struct ReadLevelEntry *readStack; + + Header buildRestrictions; + struct SpecStruct **buildArchitectureSpecs; + char ** buildArchitectures; + int buildArchitectureCount; + int inBuildArchitectures; + + int gotBuildRoot; + char *buildRoot; + char *buildSubdir; + + char *docDir; + + char *passPhrase; + int timeCheck; + char *cookie; + + struct Source *sources; + int numSources; + int noSource; + + Header sourceHeader; + int sourceCpioCount; + struct cpioFileMapping *sourceCpioList; + + struct MacroContext macros; + + int autoReqProv; + + StringBuf prep; + StringBuf build; + StringBuf install; + StringBuf clean; + + struct PackageStruct *packages; +}; + +struct PackageStruct { + Header header; + + int cpioCount; + struct cpioFileMapping *cpioList; + + struct Source *icon; + + int autoReqProv; + + char *preInFile; + char *postInFile; + char *preUnFile; + char *postUnFile; + char *verifyFile; -typedef struct SpecRec *Spec; + StringBuf specialDoc; + +#if 0 + struct ReqProvTrigger *triggers; + char *triggerScripts; +#endif + + char *fileFile; + StringBuf fileList; /* If NULL, package will not be written */ -Spec *parseSpec(FILE *f, char *specfile, char *buildRootOverride); -void freeSpec(Spec s); + struct PackageStruct *next; +}; -void dumpSpec(Spec s, FILE *f); +typedef struct SpecStruct *Spec; +typedef struct PackageStruct *Package; -char *getSource(Spec s, int ispatch, int num); -char *getFullSource(Spec s, int ispatch, int num); +Spec newSpec(void); +void freeSpec(Spec spec); -int verifySpec(Spec s); +int addSource(Spec spec, Package pkg, char *field, int tag); +char *getSource(Spec spec, int num, int flag); +char *getFullSource(Spec spec, int num, int flag); +void freeSources(Spec spec); +int parseNoSource(Spec spec, char *field, int tag); #endif _SPEC_H_ diff --git a/build/specP.h b/build/specP.h deleted file mode 100644 index a90ed7f41..000000000 --- a/build/specP.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _SPECP_H_ -#define _SPECP_H_ - -#include "spec.h" -#include "header.h" -#include "stringbuf.h" - -typedef struct sources { - char *fullSource; - char *source; - int ispatch; - int num; - struct sources *next; -} *Sources; - -struct ReqProv { - int flags; - char *name; - char *version; - struct ReqProv *next; -}; - -struct TriggerEntry { - int flags; - char *name; - char *version; - int index; - struct TriggerEntry *next; -}; - -struct TriggerStruct { - char **triggerScripts; - int alloced; - int used; - int triggerCount; - struct TriggerEntry *trigger; -}; - -struct SpecRec { - char *name; /* package base name */ - char *specfile; - - int numSources; - int numPatches; - Sources sources; - - int numNoSource; - int numNoPatch; - int_32 *noSource; - int_32 *noPatch; - - int autoReqProv; - - StringBuf prep; - StringBuf build; - StringBuf install; - StringBuf doc; - StringBuf clean; - - char *buildroot; - char *buildArch; - - struct PackageRec *packages; - /* The first package record is the "main" package and contains - * the bulk of the preamble information. Subsequent package - * records "inherit" from the main record. Note that the - * "main" package may be, in pre-rpm-2.0 terms, a "subpackage". - */ -}; - -struct PackageRec { - char *subname; /* If both of these are NULL, then this is */ - char *newname; /* the main package. subname concats with name */ - Header header; - char *icon; - int files; /* If -1, package has no files, and won't be written */ - char *fileFile; - StringBuf filelist; - StringBuf doc; /* Used to buffer up %doc lines until fully parsed */ - int numReq; - int numPreReq; - int numProv; - int numConflict; - int numObsoletes; - struct ReqProv *reqprov; - struct PackageRec *next; - struct TriggerStruct trigger; -}; - -struct ReqComp { - char *token; - int flags; -}; - -extern struct ReqComp ReqComparisons[]; - -#endif _SPECP_H_ diff --git a/build/trigger.h b/build/trigger.h deleted file mode 100644 index 00fc483f4..000000000 --- a/build/trigger.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _TRIGGER_H_ -#define _TRIGGER_H_ - -#include "specP.h" - -int addTrigger(struct PackageRec *package, - int sense, char *script, char *args); - -void generateTriggerEntries(Header h, struct PackageRec *p); - -void freeTriggers(struct TriggerStruct t); - -#endif _TRIGGER_H_ diff --git a/build/vspec.c b/build/vspec.c deleted file mode 100644 index cc3f35510..000000000 --- a/build/vspec.c +++ /dev/null @@ -1,206 +0,0 @@ -/* Routine to "verify" a parsed spec file */ - -/*************** - -Here's what we do - -. check for duplicate fields -. make sure a certain set of fields are present -. in subpackages, make sure a certain set of fields are present -. in subpackages, make sure certain fields are *not* present - -. check for duplicate sources/patch numbers -. do some checking on the field values for legit characters - -****************/ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <string.h> - -#include "header.h" -#include "spec.h" -#include "specP.h" -#include "messages.h" -#include "rpmlib.h" -#include "stringbuf.h" -#include "misc.h" - -#define EMPTY(s) ((!(s)) || (!(*(s)))) -#define OOPS(s) {fprintf(stderr, "verifySpec: %s\n", s); res = 1;} -#define MUST 1 - -struct packageFieldsRec { - int tag; - int present; - int shouldBePresent; -}; - -struct fieldNamesRec { - int tag; - char *name; -}; - -static int checkHeaderTags(Header inh, struct packageFieldsRec *pfr); -static char *tagName(int tag); - -/* This is a list of tags related to the "main" package. */ -/* Only list those that must or must not be present. */ - -static struct packageFieldsRec packageFields[] = { - { RPMTAG_NAME, 0, MUST }, - { RPMTAG_VERSION, 0, MUST }, - { RPMTAG_RELEASE, 0, MUST }, -/* { RPMTAG_SUMMARY, 0, MUST }, */ - { RPMTAG_DESCRIPTION, 0, MUST }, - { RPMTAG_COPYRIGHT, 0, MUST }, -/* { RPMTAG_PACKAGER, 0, MUST }, */ - { RPMTAG_GROUP, 0, MUST }, - { 0, 0, 0 }, -}; - -/* This is a list of tags related to "sub" packages. */ -/* Only list those that must or must not be present. */ - -static struct packageFieldsRec subpackageFields[] = { - { RPMTAG_NAME, 0, MUST }, /* This is inserted automaticaly */ - { RPMTAG_SUMMARY, 0, MUST }, - { RPMTAG_DESCRIPTION, 0, MUST }, - { RPMTAG_GROUP, 0, MUST }, - { RPMTAG_NAME, 0, 0 }, -/* { RPMTAG_COPYRIGHT, 0, 0 }, */ - { RPMTAG_PACKAGER, 0, 0 }, - { RPMTAG_BUILDROOT, 0, 0 }, - { 0, 0, 0 }, -}; - -static struct packageFieldsRec *findTag(int tag, struct packageFieldsRec *pfr) -{ - struct packageFieldsRec *p = pfr; - - while (p->tag) { - if (p->tag == tag) - return p; - p++; - } - - return NULL; -} - -static char *tagName(int tag) -{ - int i = 0; - static char nameBuf[1024]; - char *s; - - strcpy(nameBuf, "(unknown)"); - while (i < rpmTagTableSize) { - if (tag == rpmTagTable[i].val) { - strcpy(nameBuf, rpmTagTable[i].name + 7); - s = nameBuf+1; - while (*s) { - *s = tolower(*s); - s++; - } - } - i++; - } - - return nameBuf; -} - -static int checkHeaderTags(Header inh, struct packageFieldsRec *pfr) -{ - Header h; - HeaderIterator headerIter; - int res = 0; - int_32 tag, lastTag, type, c; - void *ptr; - struct packageFieldsRec *p; - - /* Sort the index, so it'll be easy to catch dups */ - h = headerCopy(inh); - headerSort(h); - - headerIter = headerInitIterator(h); - lastTag = 0; - while (headerNextIterator(headerIter, &tag, &type, &ptr, &c)) { - if (tag == lastTag) { - rpmError(RPMERR_BADSPEC, "Duplicate fields for : %s", - tagName(tag)); - res = 1; - } - p = findTag(tag, pfr); - if (p) - p->present = 1; - lastTag = tag; - } - headerFreeIterator(headerIter); - headerFree(h); - - p = pfr; - while (p->tag) { - if (p->shouldBePresent != p->present) { - rpmError(RPMERR_BADSPEC, "Field must%s be present%s: %s", - p->present ? " NOT" : "", p->present ? "" : " ", - tagName(p->tag)); - res = 1; - } - p->present = 0; /* hack to clear it for next time :-) */ - p++; - } - - return res; -} - -int verifySpec(Spec s) -{ - int res = 0; - struct PackageRec *pr; - struct packageFieldsRec *fields; - char name[1024]; - char *val; - - if (EMPTY(s->name)) { - OOPS("No Name field"); - } - - /* Check each package/subpackage */ - pr = s->packages; - fields = packageFields; - while (pr) { - if (! pr->subname) { - if (pr->newname) { - strcpy(name, pr->newname); - } else { - strcpy(name, s->name); - } - } else { - sprintf(name, "%s-%s", s->name, pr->subname); - } - printf("* Package: %s\n", name); - - if (checkHeaderTags(pr->header, fields)) { - res = 1; - } - - val = NULL; - headerGetEntry(pr->header, RPMTAG_VERSION, NULL, (void *) &val, NULL); - if (val && strchr(val, '-')) { - rpmError(RPMERR_BADSPEC, "Illegal '-' char in version: %s\n", val); - res = 1; - } - val = NULL; - headerGetEntry(pr->header, RPMTAG_RELEASE, NULL, (void *) &val, NULL); - if (val && strchr(val, '-')) { - rpmError(RPMERR_BADSPEC, "Illegal '-' char in release: %s\n", val); - res = 1; - } - - pr = pr->next; - fields = subpackageFields; - } - - return res; -} diff --git a/lib/Makefile.in b/lib/Makefile.in index 4f2999e90..c24fe493e 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -34,6 +34,12 @@ all: $(TARGET) allprogs: $(LIBRPM) $(PROGS) +misc.o: + $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -o $@ -c $< + +rpmrc.o: + $(CC) $(CFLAGS) -DLIBRPMRC_FILENAME="\"$(LIBRPMRC_FILENAME)"\" -o $@ -c $< + $(PROGS): $(LIBRPM) $(LIBRPM): $(LIBRPM)($(LIBOBJECTS) $(TAGTABLE)) diff --git a/lib/misc.c b/lib/misc.c index 0f65333cc..7127b5ed0 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -23,7 +23,7 @@ #include "rpmlib.h" #include "messages.h" -char * RPMVERSION = VERSION; +char * RPMVERSION = VERSION; /* just to put a marker in librpm.a */ char ** splitString(char * str, int length, char sep) { char * s, * source, * dest; @@ -17,6 +17,7 @@ #include <sys/stat.h> #include <sys/types.h> +#include "build.h" #include "build/build.h" #include "checksig.h" #include "install.h" @@ -42,6 +43,7 @@ #define GETOPT_TIMECHECK 1012 #define GETOPT_REBUILDDB 1013 #define GETOPT_INSTALL 1014 +#define GETOPT_RMSOURCE 1015 char * version = VERSION; @@ -62,8 +64,6 @@ static void printVersion(void); static void printBanner(void); static void printUsage(void); static void printHelpLine(char * prefix, char * help); -static int build(char *arg, int buildAmount, char *passPhrase, - char *buildRootOverride, int fromTarball); static void printVersion(void) { printf(_("RPM version %s\n"), version); @@ -113,7 +113,8 @@ static void printUsage(void) { puts(_(" [--justdb] package1 ... packageN")); puts(_(" rpm {-b|t}[plciba] [-v] [--short-circuit] [--clean] [--rcfile <file>]")); puts(_(" [--sign] [--test] [--timecheck <s>] [--buildos <os>]")); - puts(_(" [--buildarch <arch>] specfile")); + puts(_(" [--buildarch <arch>] [--rmsource] specfile")); + puts(_(" rpm {--rmsource} [--rcfile <file>] [-v] specfile")); puts(_(" rpm {--rebuild} [--rcfile <file>] [-v] source1.rpm ... sourceN.rpm")); puts(_(" rpm {--recompile} [--rcfile <file>] [-v] source1.rpm ... sourceN.rpm")); puts(_(" rpm {--resign} [--rcfile <file>] package1 package2 ... packageN")); @@ -325,6 +326,8 @@ static void printHelp(void) { _("skip straight to specified stage (only for c,i)")); printHelpLine(" --clean ", _("remove build tree when done")); + printHelpLine(" --rmsource ", + _("remove sources and spec file when done")); printHelpLine(" --sign ", _("generate PGP signature")); printHelpLine(" --buildroot <dir> ", @@ -340,6 +343,8 @@ static void printHelp(void) { puts(""); printHelpLine(" --rebuild <src_pkg> ", _("install source package, build binary package and remove spec file, sources, patches, and icons.")); + printHelpLine(" --rmsource <spec> ", + _("remove sources and spec file")); printHelpLine(" --recompile <src_pkg> ", _("like --rebuild, but don't build any package")); printHelpLine(" --resign <pkg>+ ", @@ -365,144 +370,6 @@ static void printHelp(void) { _("use <dir> as the top level directory")); } -static int build(char *arg, int buildAmount, char *passPhrase, - char *buildRootOverride, int fromTarball) { - FILE *f; - Spec *s, *specArray; - char * specfile; - int res = 0; - struct stat statbuf; - char * specDir; - char * tmpSpecFile; - char * cmd; - char buf[1024]; - int flags; - - if (fromTarball) { - specDir = rpmGetVar(RPMVAR_SPECDIR); - tmpSpecFile = alloca(1024); - sprintf(tmpSpecFile, "%s/rpm-spec-file-%d", specDir, (int) getpid()); - - cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile)); - sprintf(cmd, "gunzip < %s | tar xOvf - \\*.spec 2>&1 > %s", arg, - tmpSpecFile); - if (!(f = popen(cmd, "r"))) { - fprintf(stderr, _("Failed to open tar pipe: %s\n"), - strerror(errno)); - return 1; - } - if (!fgets(buf, sizeof(buf) - 1, f)) { - fprintf(stderr, _("Failed to read spec file from %s\n"), arg); - unlink(tmpSpecFile); - return 1; - } - pclose(f); - - cmd = specfile = buf; - while (*cmd) { - if (*cmd == '/') specfile = cmd + 1; - cmd++; - } - - cmd = specfile; - - /* remove trailing \n */ - specfile = cmd + strlen(cmd) - 1; - *specfile = '\0'; - - specfile = alloca(strlen(specDir) + strlen(cmd) + 5); - sprintf(specfile, "%s/%s", specDir, cmd); - - if (rename(tmpSpecFile, specfile)) { - fprintf(stderr, _("Failed to rename %s to %s: %s\n"), - tmpSpecFile, specfile, strerror(errno)); - unlink(tmpSpecFile); - return 1; - } - - /* Make the directory which contains the tarball the source - directory for this run */ - - if (*arg != '/') { - /* XXX this is broken if PWD is near 1024 */ - getcwd(buf, 1024); - strcat(buf, "/"); - strcat(buf, arg); - } else - strcpy(buf, arg); - - cmd = buf + strlen(buf) - 1; - while (*cmd != '/') cmd--; - *cmd = '\0'; - - rpmSetVar(RPMVAR_SOURCEDIR, buf); - } else if (arg[0] == '/') { - specfile = arg; - } else { - /* XXX this is broken if PWD is near 1024 */ - specfile = alloca(1024); - getcwd(specfile, 1024); - strcat(specfile, "/"); - strcat(specfile, arg); - } - - stat(specfile, &statbuf); - if (! S_ISREG(statbuf.st_mode)) { - rpmError(RPMERR_BADSPEC, _("File is not a regular file: %s\n"), - specfile); - return 1; - } - - if (!(f = fopen(specfile, "r"))) { - fprintf(stderr, _("unable to open: %s\n"), specfile); - return 1; - } - - s = specArray = parseSpec(f, specfile, buildRootOverride); - fclose(f); - if (! specArray) { - /* Spec parse failed -- could be Exclude: Exclusive: */ - res = 1; - if (rpmErrorCode() == RPMERR_BADARCH) { - fprintf(stderr, _("%s doesn't build on this architecture\n"), arg); - } else { - fprintf(stderr, _("Build failed.\n")); - } - } else { - while (*s && !res) { - if (verifySpec(*s)) { - fprintf(stderr, _("\n%cSpec file check failed!!\n"), 7); - fprintf(stderr, - _("Tell rpm-list@redhat.com if this is incorrect.\n\n")); - res = 1; - } else { - flags = buildAmount; - /* Don't build source package or remove sources */ - /* unless this is the last package being built. */ - if (*(s+1)) { - flags = flags & ~RPMBUILD_SOURCE; - flags = flags & ~RPMBUILD_RMSOURCE; - } - if (doBuild(*s, flags, passPhrase)) { - fprintf(stderr, _("Build failed.\n")); - res = 1; - } - } - s++; - } - - s = specArray; - while (*s) { - freeSpec(*s++); - } - free(specArray); - } - - if (fromTarball) unlink(specfile); - - return res; -} - int main(int argc, char ** argv) { enum modes bigMode = MODE_UNKNOWN; enum querysources querySource = QUERY_PACKAGE; @@ -516,9 +383,8 @@ int main(int argc, char ** argv) { int incldocs = 0, noScripts = 0, noDeps = 0, allMatches = 0, noOrder = 0; int noPgp = 0, dump = 0, initdb = 0, ignoreArch = 0, showrc = 0; int gotDbpath = 0, building = 0, ignoreOs = 0, noFiles = 0, verifyFlags; - int noMd5 = 0, allFiles = 0, justdb = 0; + int noMd5 = 0, allFiles = 0, justdb = 0, rmsource = 0; int checksigFlags = 0; - char *tce; int timeCheck = 0; int addSign = NEW_SIGNATURE; char * rcfile = NULL, * queryFormat = NULL, * prefix = NULL; @@ -526,11 +392,12 @@ int main(int argc, char ** argv) { char * rootdir = "/"; char * pipeOutput = NULL; char * specFile; - char *passPhrase = ""; - char *buildRootOverride = NULL; - char *arch = NULL; + char * tce; + char * passPhrase = ""; + char * buildRootOverride = NULL, * cookie = NULL; + char * arch = NULL; char * ftpProxy = NULL, * ftpPort = NULL; - char *os = NULL; + char * os = NULL; char * optArg; pid_t pipeChild = 0; char * pkg; @@ -599,6 +466,7 @@ int main(int argc, char ** argv) { { "replacefiles", '\0', 0, &replaceFiles, 0 }, { "replacepkgs", '\0', 0, &replacePackages, 0 }, { "resign", '\0', 0, 0, GETOPT_RESIGN }, + { "rmsource", '\0', 0, 0, GETOPT_RMSOURCE }, { "root", 'r', POPT_ARG_STRING, &rootdir, 0 }, { "short-circuit", '\0', 0, &shortCircuit, 0 }, { "showrc", '\0', 0, 0, 0 }, @@ -643,6 +511,7 @@ int main(int argc, char ** argv) { !strcmp(*currarg, "--tarbuild") || !strcmp(*currarg, "--build") || !strcmp(*currarg, "--rebuild") || + !strcmp(*currarg, "--rmsource") || !strcmp(*currarg, "--recompile")) { building = 1; } @@ -839,10 +708,17 @@ int main(int argc, char ** argv) { bigMode = MODE_REBUILD; break; + case GETOPT_RMSOURCE: + if (bigMode != MODE_UNKNOWN && bigMode != MODE_BUILD) + argerror(_("only one major mode may be specified")); + bigMode = MODE_BUILD; + break; + case GETOPT_RECOMPILE: if (bigMode != MODE_UNKNOWN && bigMode != MODE_RECOMPILE) argerror(_("only one major mode may be specified")); bigMode = MODE_RECOMPILE; + rmsource = 1; break; case GETOPT_BUILDROOT: @@ -890,6 +766,7 @@ int main(int argc, char ** argv) { argerror("Argument to --timecheck must be integer"); } rpmSetVar(RPMVAR_TIMECHECK, optArg); + timeCheck = 1; break; case GETOPT_REBUILDDB: @@ -1042,6 +919,9 @@ int main(int argc, char ** argv) { if (bigMode != MODE_BUILD && bigMode != MODE_TARBUILD && clean) argerror(_("--clean may only be used during package building")); + if (bigMode != MODE_BUILD && bigMode != MODE_TARBUILD && rmsource) + argerror(_("--rmsource may only be used during package building")); + if (bigMode != MODE_BUILD && bigMode != MODE_TARBUILD && shortCircuit) argerror(_("--short-circuit may only be used during package building")); @@ -1164,19 +1044,21 @@ int main(int argc, char ** argv) { argerror(_("no packages files given for rebuild")); buildAmount = RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | - RPMBUILD_SWEEP | RPMBUILD_RMSOURCE; + RPMBUILD_CLEAN | RPMBUILD_RMSOURCE; if (bigMode == MODE_REBUILD) { - buildAmount |= RPMBUILD_BINARY; + buildAmount |= RPMBUILD_PACKAGEBINARY; } while ((pkg = poptGetArg(optCon))) { - if (doSourceInstall("/", pkg, &specFile, NULL)) + if (doSourceInstall("/", pkg, &specFile, &cookie)) exit(1); if (build(specFile, buildAmount, passPhrase, buildRootOverride, - 0)) { + 0, test, cookie)) { exit(1); } + free(cookie); + free(specFile); } break; @@ -1188,9 +1070,10 @@ int main(int argc, char ** argv) { switch (buildChar) { /* these fallthroughs are intentional */ case 'a': - buildAmount |= RPMBUILD_SOURCE; + buildAmount |= RPMBUILD_PACKAGESOURCE; case 'b': - buildAmount |= RPMBUILD_BINARY; + buildAmount |= RPMBUILD_PACKAGEBINARY; + buildAmount |= RPMBUILD_CLEAN; case 'i': buildAmount |= RPMBUILD_INSTALL; if ((buildChar == 'i') && shortCircuit) @@ -1204,15 +1087,15 @@ int main(int argc, char ** argv) { break; case 'l': - buildAmount |= RPMBUILD_LIST; + buildAmount |= RPMBUILD_FILECHECK; break; } - if (clean) - buildAmount |= RPMBUILD_SWEEP; + if (rmsource) + buildAmount |= RPMBUILD_RMSOURCE; - if (test) - buildAmount |= RPMBUILD_TEST; + if (clean) + buildAmount |= RPMBUILD_RMBUILD; if (!poptPeekArg(optCon)) if (bigMode == MODE_BUILD) @@ -1222,7 +1105,7 @@ int main(int argc, char ** argv) { while ((pkg = poptGetArg(optCon))) if (build(pkg, buildAmount, passPhrase, buildRootOverride, - bigMode == MODE_TARBUILD)) { + bigMode == MODE_TARBUILD, test, NULL)) { exit(1); } break; @@ -1,6 +1,6 @@ Summary: Red Hat Package Manager Name: rpm -%define version 2.4.12 +%define version 2.4.99 Version: %{version} Release: 1 Group: Utilities/System |