int parseScript(rpmSpec spec, int parsePart) { /* There are a few options to scripts: */ /* <pkg> */ /* -n <pkg> */ /* -p <sh> */ /* -p "<sh> <args>..." */ /* -f <file> */ const char *p; const char **progArgv = NULL; int progArgc; const char *partname = NULL; rpmTagVal reqtag = 0; rpmTagVal tag = 0; rpmsenseFlags tagflags = 0; rpmTagVal progtag = 0; rpmTagVal flagtag = 0; rpmscriptFlags scriptFlags = 0; int flag = PART_SUBNAME; Package pkg; StringBuf sb = NULL; int nextPart; int index; char * reqargs = NULL; int res = PART_ERROR; /* assume failure */ int rc, argc; int arg; const char **argv = NULL; poptContext optCon = NULL; const char *name = NULL; const char *prog = "/bin/sh"; const char *file = NULL; int priority = 1000000; struct poptOption optionsTable[] = { { NULL, 'p', POPT_ARG_STRING, &prog, 'p', NULL, NULL}, { NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL}, { NULL, 'f', POPT_ARG_STRING, &file, 'f', NULL, NULL}, { NULL, 'e', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_EXPAND, NULL, NULL}, { NULL, 'q', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_QFORMAT, NULL, NULL}, { NULL, 'c', POPT_BIT_SET, &scriptFlags, RPMSCRIPT_FLAG_CRITICAL, NULL, NULL}, { NULL, 'P', POPT_ARG_INT, &priority, 'P', NULL, NULL}, { 0, 0, 0, 0, 0, NULL, NULL} }; switch (parsePart) { case PART_PRE: tag = RPMTAG_PREIN; tagflags = RPMSENSE_SCRIPT_PRE; progtag = RPMTAG_PREINPROG; flagtag = RPMTAG_PREINFLAGS; partname = "%pre"; break; case PART_POST: tag = RPMTAG_POSTIN; tagflags = RPMSENSE_SCRIPT_POST; progtag = RPMTAG_POSTINPROG; flagtag = RPMTAG_POSTINFLAGS; partname = "%post"; break; case PART_PREUN: tag = RPMTAG_PREUN; tagflags = RPMSENSE_SCRIPT_PREUN; progtag = RPMTAG_PREUNPROG; flagtag = RPMTAG_PREUNFLAGS; partname = "%preun"; break; case PART_POSTUN: tag = RPMTAG_POSTUN; tagflags = RPMSENSE_SCRIPT_POSTUN; progtag = RPMTAG_POSTUNPROG; flagtag = RPMTAG_POSTUNFLAGS; partname = "%postun"; break; case PART_PRETRANS: tag = RPMTAG_PRETRANS; tagflags = RPMSENSE_PRETRANS; progtag = RPMTAG_PRETRANSPROG; flagtag = RPMTAG_PRETRANSFLAGS; partname = "%pretrans"; break; case PART_POSTTRANS: tag = RPMTAG_POSTTRANS; tagflags = RPMSENSE_POSTTRANS; progtag = RPMTAG_POSTTRANSPROG; flagtag = RPMTAG_POSTTRANSFLAGS; partname = "%posttrans"; break; case PART_VERIFYSCRIPT: tag = RPMTAG_VERIFYSCRIPT; tagflags = RPMSENSE_SCRIPT_VERIFY; progtag = RPMTAG_VERIFYSCRIPTPROG; flagtag = RPMTAG_VERIFYSCRIPTFLAGS; partname = "%verifyscript"; break; case PART_TRIGGERPREIN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERPREIN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerprein"; break; case PART_TRIGGERIN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERIN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerin"; break; case PART_TRIGGERUN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERUN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerun"; break; case PART_TRIGGERPOSTUN: tag = RPMTAG_TRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRIGGERPOSTUN; progtag = RPMTAG_TRIGGERSCRIPTPROG; flagtag = RPMTAG_TRIGGERSCRIPTFLAGS; partname = "%triggerpostun"; break; case PART_FILETRIGGERIN: tag = RPMTAG_FILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_FILETRIGGERIN; progtag = RPMTAG_FILETRIGGERSCRIPTPROG; flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS; partname = "%filetriggerin"; break; case PART_FILETRIGGERUN: tag = RPMTAG_FILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_FILETRIGGERUN; progtag = RPMTAG_FILETRIGGERSCRIPTPROG; flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS; partname = "%filetriggerun"; break; case PART_FILETRIGGERPOSTUN: tag = RPMTAG_FILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_FILETRIGGERPOSTUN; progtag = RPMTAG_FILETRIGGERSCRIPTPROG; flagtag = RPMTAG_FILETRIGGERSCRIPTFLAGS; partname = "%filetriggerpostun"; break; case PART_TRANSFILETRIGGERIN: tag = RPMTAG_TRANSFILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRANSFILETRIGGERIN; progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG; flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS; partname = "%transfiletriggerin"; break; case PART_TRANSFILETRIGGERUN: tag = RPMTAG_TRANSFILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRANSFILETRIGGERUN; progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG; flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS; partname = "%transfiletriggerun"; break; case PART_TRANSFILETRIGGERPOSTUN: tag = RPMTAG_TRANSFILETRIGGERSCRIPTS; tagflags = 0; reqtag = RPMTAG_TRANSFILETRIGGERPOSTUN; progtag = RPMTAG_TRANSFILETRIGGERSCRIPTPROG; flagtag = RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS; partname = "%transfiletriggerpostun"; break; } if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS || tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) { /* break line into two at the -- separator */ char *sep, *s = spec->line; while ((s = strstr(s, "--")) != NULL) { s += 2; if (risblank(*(s-3)) && risblank(*s)) break; } if (s == NULL) { rpmlog(RPMLOG_ERR, _("line %d: triggers must have --: %s\n"), spec->lineNum, spec->line); goto exit; } sep = s; SKIPSPACE(s); if (*s == '\0') { rpmlog(RPMLOG_ERR, _("line %d: missing trigger condition: %s\n"), spec->lineNum, spec->line); goto exit; } *sep = '\0'; reqargs = xstrdup(s); } if ((rc = poptParseArgvString(spec->line, &argc, &argv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"), spec->lineNum, partname, poptStrerror(rc)); goto exit; } optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); while ((arg = poptGetNextOpt(optCon)) > 0) { switch (arg) { case 'p': if (prog[0] == '<') { if (prog[strlen(prog)-1] != '>') { rpmlog(RPMLOG_ERR, _("line %d: internal script must end " "with \'>\': %s\n"), spec->lineNum, prog); goto exit; } } else if (prog[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: script program must begin " "with \'/\': %s\n"), spec->lineNum, prog); goto exit; } break; case 'n': flag = PART_NAME; break; case 'P': if (tag != RPMTAG_TRIGGERSCRIPTS && tag != RPMTAG_FILETRIGGERSCRIPTS && tag != RPMTAG_TRANSFILETRIGGERSCRIPTS) { rpmlog(RPMLOG_ERR, _("line %d: Priorities are allowed only for file " "triggers : %s\n"), spec->lineNum, prog); goto exit; } } } if (arg < -1) { rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"), spec->lineNum, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), spec->line); goto exit; } if (poptPeekArg(optCon)) { if (name == NULL) name = poptGetArg(optCon); if (poptPeekArg(optCon)) { rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"), spec->lineNum, spec->line); goto exit; } } if (lookupPackage(spec, name, flag, &pkg)) goto exit; if (tag != RPMTAG_TRIGGERSCRIPTS) { if (headerIsEntry(pkg->header, progtag)) { rpmlog(RPMLOG_ERR, _("line %d: Second %s\n"), spec->lineNum, partname); goto exit; } } if ((rc = poptParseArgvString(prog, &progArgc, &progArgv))) { rpmlog(RPMLOG_ERR, _("line %d: Error parsing %s: %s\n"), spec->lineNum, partname, poptStrerror(rc)); goto exit; } sb = newStringBuf(); if ((rc = readLine(spec, STRIP_NOTHING)) > 0) { nextPart = PART_NONE; } else if (rc < 0) { goto exit; } else { while (! (nextPart = isPart(spec->line))) { appendStringBuf(sb, spec->line); if ((rc = readLine(spec, STRIP_NOTHING)) > 0) { nextPart = PART_NONE; break; } else if (rc < 0) { goto exit; } } } stripTrailingBlanksStringBuf(sb); p = getStringBuf(sb); #ifdef WITH_LUA if (rstreq(progArgv[0], "<lua>")) { rpmlua lua = NULL; /* Global state. */ if (rpmluaCheckScript(lua, p, partname) != RPMRC_OK) { goto exit; } (void) rpmlibNeedsFeature(pkg, "BuiltinLuaScripts", "4.2.2-1"); } else #endif if (progArgv[0][0] == '<') { rpmlog(RPMLOG_ERR, _("line %d: unsupported internal script: %s\n"), spec->lineNum, progArgv[0]); goto exit; } else { (void) addReqProv(pkg, RPMTAG_REQUIRENAME, progArgv[0], NULL, (tagflags | RPMSENSE_INTERP), 0); } if (scriptFlags) { rpmlibNeedsFeature(pkg, "ScriptletExpansion", "4.9.0-1"); } /* Trigger script insertion is always delayed in order to */ /* get the index right. */ if (tag == RPMTAG_TRIGGERSCRIPTS || tag == RPMTAG_FILETRIGGERSCRIPTS || tag == RPMTAG_TRANSFILETRIGGERSCRIPTS) { if (tag != RPMTAG_TRIGGERSCRIPTS && *reqargs != '/') { rpmlog(RPMLOG_ERR, _("line %d: file trigger condition must begin with '/': %s"), spec->lineNum, reqargs); goto exit; } if (progArgc > 1) { rpmlog(RPMLOG_ERR, _("line %d: interpreter arguments not allowed in triggers: %s\n"), spec->lineNum, prog); goto exit; } /* Add file/index/prog triple to the trigger file list */ index = addTriggerIndex(pkg, file, p, progArgv[0], scriptFlags, tag, priority); /* Generate the trigger tags */ if (parseRCPOT(spec, pkg, reqargs, reqtag, index, tagflags, addReqProvPkg, NULL)) goto exit; } else { struct rpmtd_s td; /* * XXX Ancient rpm uses STRING, not STRING_ARRAY type here. Construct * the td manually and preserve legacy compat for now... */ rpmtdReset(&td); td.tag = progtag; td.count = progArgc; if (progArgc == 1) { td.data = (void *) *progArgv; td.type = RPM_STRING_TYPE; } else { (void) rpmlibNeedsFeature(pkg, "ScriptletInterpreterArgs", "4.0.3-1"); td.data = progArgv; td.type = RPM_STRING_ARRAY_TYPE; } headerPut(pkg->header, &td, HEADERPUT_DEFAULT); if (*p != '\0') { headerPutString(pkg->header, tag, p); } if (scriptFlags) { headerPutUint32(pkg->header, flagtag, &scriptFlags, 1); } if (file) { switch (parsePart) { case PART_PRE: pkg->preInFile = xstrdup(file); break; case PART_POST: pkg->postInFile = xstrdup(file); break; case PART_PREUN: pkg->preUnFile = xstrdup(file); break; case PART_POSTUN: pkg->postUnFile = xstrdup(file); break; case PART_PRETRANS: pkg->preTransFile = xstrdup(file); break; case PART_POSTTRANS: pkg->postTransFile = xstrdup(file); break; case PART_VERIFYSCRIPT: pkg->verifyFile = xstrdup(file); break; } } } res = nextPart; exit: free(reqargs); freeStringBuf(sb); free(progArgv); free(argv); poptFreeContext(optCon); return res; }
static int ds_ip4set_line(struct dataset *ds, char *s, struct dsctx *dsc) { struct dsdata *dsd = ds->ds_dsd; ip4addr_t a, b; const char *rr; unsigned rrl; int not; int bits; if (*s == ':') { if (!(rrl = parse_a_txt(s, &rr, def_rr, dsc))) return 1; if (!(dsd->def_rr = mp_dmemdup(ds->ds_mp, rr, rrl))) return 0; return 1; } if (*s == '!') { not = 1; ++s; SKIPSPACE(s); } else not = 0; if ((bits = ip4range(s, &a, &b, &s)) <= 0 || (*s && !ISSPACE(*s) && !ISCOMMENT(*s) && *s != ':')) { dswarn(dsc, "invalid address"); return 1; } if (accept_in_cidr) a &= ip4mask(bits); else if (a & ~ip4mask(bits)) { dswarn(dsc, "invalid range (non-zero host part)"); return 1; } if (dsc->dsc_ip4maxrange && dsc->dsc_ip4maxrange <= (b - a)) { dswarn(dsc, "too large range (%u) ignored (%u max)", b - a + 1, dsc->dsc_ip4maxrange); return 1; } if (not) rr = NULL; else { SKIPSPACE(s); if (!*s || ISCOMMENT(*s)) rr = dsd->def_rr; else if (!(rrl = parse_a_txt(s, &rr, dsd->def_rr, dsc))) return 1; else if (!(rr = mp_dmemdup(ds->ds_mp, rr, rrl))) return 0; } /*XXX some comments about funny ip4range_expand et al */ #define fn(idx,start,count) ds_ip4set_addent(dsd, idx, start, count, rr) /* helper macro for ip4range_expand: * deal with last octet, shifting a and b when done */ #define ip4range_expand_octet(bits) \ if ((a | 255u) >= b) { \ if (b - a == 255u) \ return fn((bits>>3)+1, a<<bits, 1); \ else \ return fn(bits>>3, a<<bits, b - a + 1); \ } \ if (a & 255u) { \ if (!fn(bits>>3, a<<bits, 256u - (a & 255u))) \ return 0; \ a = (a >> 8) + 1; \ } \ else \ a >>= 8; \ if ((b & 255u) != 255u) { \ if (!fn((bits>>3), (b & ~255u)<<bits, (b&255u)+1)) \ return 0; \ b = (b >> 8) - 1; \ } \ else \ b >>= 8 ip4range_expand_octet(0); ip4range_expand_octet(8); ip4range_expand_octet(16); return fn(3, a << 24, b - a + 1); }
/** * Add %changelog section to header. * @param h header * @param sb changelog strings * @return RPMRC_OK on success */ static rpmRC addChangelog(Header h, StringBuf sb) { char *s; int i; time_t time; time_t lastTime = 0; time_t trimtime = rpmExpandNumeric("%{?_changelog_trimtime}"); char *date, *name, *text, *next; s = getStringBuf(sb); /* skip space */ SKIPSPACE(s); while (*s != '\0') { if (*s != '*') { rpmlog(RPMLOG_ERR, _("%%changelog entries must start with *\n")); return RPMRC_FAIL; } /* find end of line */ date = s; while(*s && *s != '\n') s++; if (! *s) { rpmlog(RPMLOG_ERR, _("incomplete %%changelog entry\n")); return RPMRC_FAIL; } *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)) { rpmlog(RPMLOG_ERR, _("bad date in %%changelog: %s\n"), date); return RPMRC_FAIL; } if (lastTime && lastTime < time) { rpmlog(RPMLOG_ERR, _("%%changelog not in descending chronological order\n")); return RPMRC_FAIL; } lastTime = time; /* skip space to the name */ SKIPSPACE(s); if (! *s) { rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n")); return RPMRC_FAIL; } /* name */ name = s; while (*s != '\0') s++; while (s > name && risspace(*s)) { *s-- = '\0'; } if (s == name) { rpmlog(RPMLOG_ERR, _("missing name in %%changelog\n")); return RPMRC_FAIL; } /* text */ SKIPSPACE(text); if (! *text) { rpmlog(RPMLOG_ERR, _("no description in %%changelog\n")); return RPMRC_FAIL; } /* 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) && risspace(*s)) { *s-- = '\0'; } if ( !trimtime || time >= trimtime ) { addChangelogEntry(h, time, name, text); } else break; s = next; } return RPMRC_OK; }
/** * Parse date string to seconds. * @param datestr date string (e.g. 'Wed Jan 1 1997') * @retval secs secs since the unix epoch * @return 0 on success, -1 on error */ static int dateToTimet(const char * datestr, time_t * secs) { int rc = -1; /* assume failure */ struct tm time; const char * const * idx; char *p, *pe, *q, *date, *tz; static const char * const days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; static const char * const months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static const char const lengths[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; memset(&time, 0, sizeof(time)); date = xstrdup(datestr); pe = date; /* day of week */ p = pe; SKIPSPACE(p); if (*p == '\0') goto exit; pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; for (idx = days; *idx && !rstreq(*idx, p); idx++) {}; if (*idx == NULL) goto exit; /* month */ p = pe; SKIPSPACE(p); if (*p == '\0') goto exit; pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; for (idx = months; *idx && !rstreq(*idx, p); idx++) {}; if (*idx == NULL) goto exit; time.tm_mon = idx - months; /* day */ p = pe; SKIPSPACE(p); if (*p == '\0') goto exit; pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; /* make this noon so the day is always right (as we make this UTC) */ time.tm_hour = 12; time.tm_mday = strtol(p, &q, 10); if (!(q && *q == '\0')) goto exit; if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) goto exit; /* year */ p = pe; SKIPSPACE(p); if (*p == '\0') goto exit; pe = p; SKIPNONSPACE(pe); if (*pe != '\0') *pe++ = '\0'; time.tm_year = strtol(p, &q, 10); if (!(q && *q == '\0')) goto exit; if (time.tm_year < 1990 || time.tm_year >= 3000) goto exit; time.tm_year -= 1900; /* chnagelog date is always in UTC */ tz = getenv("TZ"); if (tz) tz = xstrdup(tz); setenv("TZ", "UTC", 1); *secs = mktime(&time); unsetenv("TZ"); if (tz) { setenv("TZ", tz, 1); free(tz); } if (*secs == -1) goto exit; rc = 0; exit: free(date); return rc; }
int readLine(rpmSpec spec, int strip) { char *s; int match; struct ReadLevelEntry *rl; OFI_t *ofi = spec->fileStack; int rc; if (!restoreFirstChar(spec)) { retry: if ((rc = readLineFromOFI(spec, ofi)) != 0) return rc; /* Copy next file line into the spec line buffer */ rc = copyNextLineFromOFI(spec, ofi); if (rc > 0) { goto retry; } else if (rc < 0) { return PART_ERROR; } } copyNextLineFinish(spec, strip); s = spec->line; SKIPSPACE(s); match = -1; if (!spec->readStack->reading && rstreqn("%if", s, sizeof("%if")-1)) { match = 0; } else if (rstreqn("%ifarch", s, sizeof("%ifarch")-1)) { char *arch = rpmExpand("%{_target_cpu}", NULL); s += 7; match = matchTok(arch, s); arch = _free(arch); } else if (rstreqn("%ifnarch", s, sizeof("%ifnarch")-1)) { char *arch = rpmExpand("%{_target_cpu}", NULL); s += 8; match = !matchTok(arch, s); arch = _free(arch); } else if (rstreqn("%ifos", s, sizeof("%ifos")-1)) { char *os = rpmExpand("%{_target_os}", NULL); s += 5; match = matchTok(os, s); os = _free(os); } else if (rstreqn("%ifnos", s, sizeof("%ifnos")-1)) { char *os = rpmExpand("%{_target_os}", NULL); s += 6; match = !matchTok(os, s); os = _free(os); } else if (rstreqn("%if", s, sizeof("%if")-1)) { s += 3; match = parseExpressionBoolean(spec, s); if (match < 0) { rpmlog(RPMLOG_ERR, _("%s:%d: parseExpressionBoolean returns %d\n"), ofi->fileName, ofi->lineNum, match); return PART_ERROR; } } else if (rstreqn("%else", s, sizeof("%else")-1)) { s += 5; if (! spec->readStack->next) { /* Got an else with no %if ! */ rpmlog(RPMLOG_ERR, _("%s:%d: Got a %%else with no %%if\n"), ofi->fileName, ofi->lineNum); return PART_ERROR; } spec->readStack->reading = spec->readStack->next->reading && ! spec->readStack->reading; spec->line[0] = '\0'; } else if (rstreqn("%endif", s, sizeof("%endif")-1)) { s += 6; if (! spec->readStack->next) { /* Got an end with no %if ! */ rpmlog(RPMLOG_ERR, _("%s:%d: Got a %%endif with no %%if\n"), ofi->fileName, ofi->lineNum); return PART_ERROR; } rl = spec->readStack; spec->readStack = spec->readStack->next; free(rl); spec->line[0] = '\0'; } else if (rstreqn("%include", s, sizeof("%include")-1)) { char *fileName, *endFileName, *p; s += 8; fileName = s; if (! risspace(*fileName)) { rpmlog(RPMLOG_ERR, _("malformed %%include statement\n")); return PART_ERROR; } SKIPSPACE(fileName); endFileName = fileName; SKIPNONSPACE(endFileName); p = endFileName; SKIPSPACE(p); if (*p != '\0') { rpmlog(RPMLOG_ERR, _("malformed %%include statement\n")); return PART_ERROR; } *endFileName = '\0'; forceIncludeFile(spec, fileName); ofi = spec->fileStack; goto retry; } if (match != -1) { rl = xmalloc(sizeof(*rl)); rl->reading = spec->readStack->reading && match; rl->next = spec->readStack; spec->readStack = rl; spec->line[0] = '\0'; } if (! spec->readStack->reading) { spec->line[0] = '\0'; } /* FIX: spec->readStack->next should be dependent */ return 0; }
void handleComments(char *s) { SKIPSPACE(s); if (*s == '#') *s = '\0'; }
static int parseLine2(char *line, int *embedArgc, char ***embedArgv, int option) { #define INCREASE 40 static int parsing = TRUE; static char **argBuf = NULL, *key; static int bufSize = 0; char *sp, *sQuote, *dQuote, quoteMark; if (argBuf == NULL) { if ((argBuf = (char **) malloc(INCREASE * sizeof(char *))) == NULL) { fprintf(stderr, (_i18n_msg_get(ls_catd,NL_SETN,803 , "Unable to allocate memory for options"))); /* catgets 803 */ return -1; } bufSize = INCREASE; *embedArgc = 1; *embedArgv = argBuf; if (option & EMBED_BSUB) { argBuf[0] = "bsub"; key = "BSUB"; } else if (option & EMBED_RESTART) { argBuf[0] = "brestart"; key = "BRESTART"; } else if (option & EMBED_QSUB) { argBuf[0] = "qsub"; key = "QSUB"; } else { fprintf(stderr, (_i18n_msg_get(ls_catd,NL_SETN,804 , "Invalid option"))); /* catgets 804 */ return -1; } argBuf[1] = NULL; } if (!parsing && !emptyCmd) return 0; SKIPSPACE(line); if (*line == '\0') return 0; if (*line != '#') { emptyCmd = FALSE; return 0; } if (!parsing) return 0; ++line; SKIPSPACE(line); if (strncmp (line, key, strlen(key)) == 0) { line += strlen(key); SKIPSPACE(line); if (*line != '-') { parsing = FALSE; return 0; } while (TRUE) { quoteMark = '"'; if ((sQuote = strchr(line, '\'')) != NULL) if ((dQuote = strchr(line, '"')) == NULL || sQuote < dQuote) quoteMark = '\''; if ((sp = getNextValueQ_(&line, quoteMark, quoteMark)) == NULL) return 0; if (*sp == '#') return 0; if (*embedArgc + 2 > bufSize) { char **tmp; bufSize += INCREASE; if ((tmp = (char **) realloc(argBuf, bufSize * sizeof(char *))) == NULL) { fprintf(stderr, _i18n_msg_get(ls_catd, NL_SETN, 803, "Unable to allocate memory for options")); return -1; } argBuf = tmp; } argBuf[*embedArgc] = putstr_(sp); (*embedArgc)++; argBuf[*embedArgc] = NULL; } } return 0; }
static int addSource(rpmSpec spec, Package pkg, const char *field, rpmTagVal tag) { struct Source *p; int flag = 0; const char *name = NULL; char *nump; char *fieldp = NULL; char *buf = NULL; uint32_t 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; fieldp = NULL; break; default: return -1; break; } /* Get the number */ if (tag != RPMTAG_ICON) { /* We already know that a ':' exists, and that there */ /* are no spaces before it. */ /* This also now allows for spaces and tabs between */ /* the number and the ':' */ char ch; char *fieldp_backup = fieldp; while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) { fieldp++; } ch = *fieldp; *fieldp = '\0'; nump = fieldp_backup; SKIPSPACE(nump); if (nump == NULL || *nump == '\0') { num = flag == RPMBUILD_ISSOURCE ? 0 : INT_MAX; } else { if (parseUnsignedNum(fieldp_backup, &num)) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"), spec->lineNum, name, spec->line); *fieldp = ch; return RPMRC_FAIL; } } *fieldp = ch; } /* Check whether tags of the same number haven't already been defined */ for (p = spec->sources; p != NULL; p = p->next) { if ( p->num != num ) continue; if ((tag == RPMTAG_SOURCE && p->flags == RPMBUILD_ISSOURCE) || (tag == RPMTAG_PATCH && p->flags == RPMBUILD_ISPATCH)) { rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num); return RPMRC_FAIL; } } /* Create the entry and link it in */ p = xmalloc(sizeof(*p)); p->num = num; p->fullSource = xstrdup(field); p->flags = flag; p->source = strrchr(p->fullSource, '/'); if (p->source) { if ((buf = strrchr(p->source,'='))) p->source = buf; p->source++; } else { p->source = p->fullSource; } if (tag != RPMTAG_ICON) { p->next = spec->sources; spec->sources = p; } else { p->next = pkg->icon; pkg->icon = p; } spec->numSources++; if (tag != RPMTAG_ICON) { char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL); struct stat st; int nofetch = (spec->flags & RPMSPEC_FORCE) || rpmExpandNumeric("%{_disable_source_fetch}"); /* try to download source/patch if it's missing */ if (lstat(body, &st) != 0 && errno == ENOENT && !nofetch) { char *url = NULL; if (urlIsURL(p->fullSource) != URL_IS_UNKNOWN) { url = rstrdup(p->fullSource); } else { url = rpmExpand("%{_default_source_url}", NULL); rstrcat(&url, p->source); if (*url == '%') url = _free(url); } if (url) { rpmlog(RPMLOG_WARNING, _("Downloading %s to %s\n"), url, body); if (urlGetFile(url, body) != 0) { free(url); rpmlog(RPMLOG_ERR, _("Couldn't download %s\n"), p->fullSource); return RPMRC_FAIL; } free(url); } } rasprintf(&buf, "%s%d", (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num); rpmPushMacro(spec->macros, buf, NULL, body, RMIL_SPEC); free(buf); rasprintf(&buf, "%sURL%d", (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num); rpmPushMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC); free(buf); #ifdef WITH_LUA { rpmlua lua = NULL; /* global state */ const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources"; rpmluaPushTable(lua, what); rpmluav var = rpmluavNew(); rpmluavSetListMode(var, 1); rpmluavSetValue(var, RPMLUAV_STRING, body); rpmluaSetVar(lua, var); rpmluavFree(var); rpmluaPop(lua); } #endif free(body); } return 0; }
static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag, const char *macro, const char *lang) /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ /*@modifies spec->macros, spec->st, spec->sources, spec->numSources, spec->noSource, spec->sourceHeader, spec->BANames, spec->BACount, spec->line, pkg->header, pkg->autoProv, pkg->autoReq, pkg->noarch, rpmGlobalMacroContext, fileSystem, internalState @*/ { HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); char * field = spec->line; char * end; int multiToken = 0; rpmsenseFlags tagflags; int len; rpmuint32_t num; int rc; int xx; if (field == NULL) return RPMRC_FAIL; /* XXX can't happen */ /* Find the start of the "field" and strip trailing space */ while ((*field) && (*field != ':')) field++; if (*field != ':') { rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } field++; SKIPSPACE(field); if (!*field) { /* Empty field */ rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } end = findLastChar(field); /* Validate tag data content. */ if (tagValidate(spec, tag, field) != RPMRC_OK) return RPMRC_FAIL; /* See if this is multi-token */ end = field; SKIPNONSPACE(end); if (*end != '\0') multiToken = 1; switch (tag) { case RPMTAG_NAME: case RPMTAG_VERSION: case RPMTAG_RELEASE: case RPMTAG_DISTEPOCH: case RPMTAG_URL: case RPMTAG_DISTTAG: case RPMTAG_REPOTAG: case RPMTAG_CVSID: case RPMTAG_BUGURL: SINGLE_TOKEN_ONLY; /* These macros are for backward compatibility */ if (tag == RPMTAG_VERSION) { if (strchr(field, '-') != NULL) { rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), spec->lineNum, "version", spec->line); return RPMRC_FAIL; } addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC); } else if (tag == RPMTAG_RELEASE) { if (strchr(field, '-') != NULL) { rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"), spec->lineNum, "release", spec->line); return RPMRC_FAIL; } addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1); } he->tag = tag; he->t = RPM_STRING_TYPE; he->p.str = field; he->c = 1; xx = headerPut(pkg->header, he, 0); break; case RPMTAG_GROUP: case RPMTAG_SUMMARY: #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */ case RPMTAG_CLASS: #endif (void) stashSt(spec, pkg->header, tag, lang); /*@fallthrough@*/ case RPMTAG_DISTRIBUTION: case RPMTAG_VENDOR: case RPMTAG_LICENSE: case RPMTAG_PACKAGER: if (!*lang) { he->tag = tag; he->t = RPM_STRING_TYPE; he->p.str = field; he->c = 1; xx = headerPut(pkg->header, he, 0); } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) { (void) headerAddI18NString(pkg->header, tag, field, lang); } break; /* XXX silently ignore BuildRoot: */ case RPMTAG_BUILDROOT: SINGLE_TOKEN_ONLY; macro = NULL; #ifdef DYING buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL); (void) urlPath(buildRootURL, &buildRoot); if (*buildRoot == '\0') buildRoot = "/"; if (!strcmp(buildRoot, "/")) { rpmlog(RPMLOG_ERR, _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL); buildRootURL = _free(buildRootURL); return RPMRC_FAIL; } buildRootURL = _free(buildRootURL); #endif break; case RPMTAG_KEYWORDS: case RPMTAG_VARIANTS: case RPMTAG_PREFIXES: addOrAppendListEntry(pkg->header, tag, field); he->tag = tag; xx = headerGet(pkg->header, he, 0); if (tag == RPMTAG_PREFIXES) while (he->c--) { if (he->p.argv[he->c][0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: Prefixes must begin with \"/\": %s\n"), spec->lineNum, spec->line); he->p.ptr = _free(he->p.ptr); return RPMRC_FAIL; } len = (int)strlen(he->p.argv[he->c]); if (he->p.argv[he->c][len - 1] == '/' && len > 1) { rpmlog(RPMLOG_ERR, _("line %d: Prefixes must not end with \"/\": %s\n"), spec->lineNum, spec->line); he->p.ptr = _free(he->p.ptr); return RPMRC_FAIL; } } he->p.ptr = _free(he->p.ptr); break; case RPMTAG_DOCDIR: SINGLE_TOKEN_ONLY; if (field[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } macro = NULL; delMacro(NULL, "_docdir"); addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); break; case RPMTAG_XMAJOR: case RPMTAG_XMINOR: case RPMTAG_EPOCH: SINGLE_TOKEN_ONLY; if (parseNum(field, &num)) { rpmlog(RPMLOG_ERR, _("line %d: %s takes an integer value: %s\n"), spec->lineNum, tagName(tag), spec->line); return RPMRC_FAIL; } he->tag = tag; he->t = RPM_UINT32_TYPE; he->p.ui32p = # he->c = 1; xx = headerPut(pkg->header, he, 0); break; case RPMTAG_AUTOREQPROV: pkg->autoReq = parseYesNo(field); pkg->autoProv = pkg->autoReq; break; case RPMTAG_AUTOREQ: pkg->autoReq = parseYesNo(field); break; case RPMTAG_AUTOPROV: pkg->autoProv = parseYesNo(field); break; case RPMTAG_SOURCE: case RPMTAG_PATCH: SINGLE_TOKEN_ONLY; macro = NULL; if ((rc = addSource(spec, pkg, field, tag))) return rc; break; case RPMTAG_ICON: SINGLE_TOKEN_ONLY; macro = NULL; if ((rc = addSource(spec, pkg, field, tag))) return rc; /* XXX the fetch/load of icon needs to be elsewhere. */ if ((rc = doIcon(spec, pkg->header))) return rc; break; case RPMTAG_NOSOURCE: case RPMTAG_NOPATCH: spec->noSource = 1; if ((rc = parseNoSource(spec, field, tag))) return rc; break; case RPMTAG_BUILDPREREQ: case RPMTAG_BUILDREQUIRES: if ((rc = parseBits(lang, buildScriptBits, &tagflags))) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"), spec->lineNum, tagName(tag), spec->line); return rc; } if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) return rc; break; case RPMTAG_PREREQ: case RPMTAG_REQUIREFLAGS: if ((rc = parseBits(lang, installScriptBits, &tagflags))) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"), spec->lineNum, tagName(tag), spec->line); return rc; } if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) return rc; break; /* Aliases for BuildRequires(hint): */ case RPMTAG_BUILDSUGGESTS: case RPMTAG_BUILDENHANCES: tagflags = RPMSENSE_MISSINGOK; if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) return rc; break; /* Aliases for Requires(hint): */ case RPMTAG_SUGGESTSFLAGS: case RPMTAG_ENHANCESFLAGS: tag = RPMTAG_REQUIREFLAGS; tagflags = RPMSENSE_MISSINGOK; if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) return rc; break; case RPMTAG_BUILDOBSOLETES: case RPMTAG_BUILDPROVIDES: case RPMTAG_BUILDCONFLICTS: case RPMTAG_CONFLICTFLAGS: case RPMTAG_OBSOLETEFLAGS: case RPMTAG_PROVIDEFLAGS: tagflags = RPMSENSE_ANY; if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags))) return rc; break; case RPMTAG_BUILDPLATFORMS: /* XXX needs pattern parsing */ case RPMTAG_EXCLUDEARCH: case RPMTAG_EXCLUSIVEARCH: case RPMTAG_EXCLUDEOS: case RPMTAG_EXCLUSIVEOS: addOrAppendListEntry(spec->sourceHeader, tag, field); break; case RPMTAG_BUILDARCHS: { const char ** BANames = NULL; int BACount = 0; if ((rc = poptParseArgvString(field, &BACount, &BANames))) { rpmlog(RPMLOG_ERR, _("line %d: Bad BuildArchitecture format: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } if (spec->toplevel) { if (BACount > 0 && BANames != NULL) { spec->BACount = BACount; spec->BANames = BANames; BANames = NULL; /* XXX don't free. */ } } else { if (BACount != 1 || strcmp(BANames[0], "noarch")) { rpmlog(RPMLOG_ERR, _("line %d: Only \"noarch\" sub-packages are supported: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); return RPMRC_FAIL; } pkg->noarch = 1; } BANames = _free(BANames); } break; default: macro = NULL; he->tag = tag; he->t = RPM_STRING_ARRAY_TYPE; he->p.argv= (const char **) &field; /* XXX NOCAST */ he->c = 1; he->append = 1; xx = headerPut(pkg->header, he, 0); he->append = 0; break; } /*@-usereleased@*/ if (macro) addMacro(spec->macros, macro, NULL, field, RMIL_SPEC); /*@=usereleased@*/ return RPMRC_OK; }
static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp, /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang) /*@modifies *tagp, *macro, *lang @*/ { PreambleRec p; char *s; size_t len = 0; /* Search for defined tags. */ for (p = preambleList; p->token != NULL; p++) { len = strlen(p->token); if (!(p->token && !xstrncasecmp(spec->line, p->token, len))) continue; if (p->obsolete) { rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"), p->token); p = NULL; } break; } if (p == NULL) return 1; /* Search for arbitrary tags. */ if (tagp && p->token == NULL) { ARGV_t aTags = NULL; int rc = 1; /* assume failure */ /*@-noeffect@*/ (void) tagName(0); /* XXX force arbitrary tags to be initialized. */ /*@=noeffect@*/ aTags = rpmTags->aTags; if (aTags != NULL && aTags[0] != NULL) { ARGV_t av; s = tagCanonicalize(spec->line); #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */ av = argvSearchLinear(aTags, s, argvFnmatchCasefold); #else av = argvSearch(aTags, s, argvStrcasecmp); #endif if (av != NULL) { *tagp = tagGenerate(s); rc = 0; } s = _free(s); } return rc; } s = spec->line + len; SKIPSPACE(s); switch (p->multiLang) { default: case 0: /* 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'; break; case 1: /* Parse optional ( <token> ). */ if (*s == ':') { strcpy(lang, RPMBUILD_DEFAULT_LANG); break; } if (*s != '(') return 1; s++; SKIPSPACE(s); while (!xisspace(*s) && *s != ')') *lang++ = *s++; *lang = '\0'; SKIPSPACE(s); if (*s != ')') return 1; s++; SKIPSPACE(s); if (*s != ':') return 1; break; } if (tagp) *tagp = p->tag; if (macro) /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */ *macro = p->token; /*@=onlytrans =observertrans =dependenttrans@*/ return 0; }
/* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */ int parsePreamble(Spec spec, int initialPackage) { HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); rpmParseState nextPart; int xx; char *linep; Package pkg; char NVR[BUFSIZ]; char lang[BUFSIZ]; rpmRC rc; strcpy(NVR, "(main package)"); pkg = newPackage(spec); if (spec->packages == NULL) { spec->packages = pkg; assert(initialPackage); } else if (! initialPackage) { char *name = NULL; rpmParseState flag; Package lastpkg; /* There is one option to %package: <pkg> or -n <pkg> */ flag = PART_NONE; if (parseSimplePart(spec, &name, &flag)) { rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"), spec->line); pkg = freePackages(pkg); return RPMRC_FAIL; } lastpkg = NULL; if (lookupPackage(spec, name, flag, &lastpkg) == RPMRC_OK) { pkg->next = lastpkg->next; } else { /* Add package to end of list */ for (lastpkg = spec->packages; lastpkg->next != NULL; lastpkg = lastpkg->next) {}; } assert(lastpkg != NULL); lastpkg->next = pkg; /* Construct the package */ if (flag == PART_SUBNAME) { he->tag = RPMTAG_NAME; xx = headerGet(spec->packages->header, he, 0); sprintf(NVR, "%s-%s", he->p.str, name); he->p.ptr = _free(he->p.ptr); } else strcpy(NVR, name); name = _free(name); he->tag = RPMTAG_NAME; he->t = RPM_STRING_TYPE; he->p.str = NVR; he->c = 1; xx = headerPut(pkg->header, he, 0); } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; } else { if (rc) return rc; while ((nextPart = isPart(spec)) == PART_NONE) { const char * macro = NULL; rpmTag tag = 0; /* Skip blank lines */ linep = spec->line; SKIPSPACE(linep); if (*linep != '\0') { if (findPreambleTag(spec, &tag, ¯o, lang)) { rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } if (handlePreambleTag(spec, pkg, tag, macro, lang)) return RPMRC_FAIL; if (spec->BANames && !spec->recursing && spec->toplevel) return PART_BUILDARCHITECTURES; } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; break; } if (rc) return rc; } } /* Do some final processing on the header */ /* * Expand buildroot one more time to get %{version} and the like * from the main package. */ if (initialPackage) { const char *s = rpmExpand("%{?buildroot}", NULL); if (s && *s) (void) addMacro(NULL, "buildroot", NULL, s, -1); s = _free(s); } /* XXX Skip valid arch check if not building binary package */ if (!spec->anyarch && checkForValidArchitectures(spec)) return RPMRC_FAIL; if (pkg == spec->packages) fillOutMainPackage(pkg->header); if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK) return RPMRC_FAIL; if (pkg != spec->packages) headerCopyTags(spec->packages->header, pkg->header, (void *)copyTagsDuringParse); #ifdef RPM_VENDOR_PLD /* rpm-epoch0 */ /* Add Epoch: 0 to package header if it was not set by spec */ he->tag = RPMTAG_NAME; if (headerGet(spec->packages->header, he, 0) == 0) { rpmuint32_t num = 0; he->tag = RPMTAG_EPOCH; he->t = RPM_UINT32_TYPE; he->p.ui32p = # he->c = 1; xx = headerPut(pkg->header, he, 0); /* also declare %{epoch} to be same */ addMacro(spec->macros, "epoch", NULL, "0", RMIL_SPEC); } #endif /* RPM_VENDOR_PLD rpm-epoch0 */ if (checkForRequired(pkg->header, NVR) != RPMRC_OK) return RPMRC_FAIL; return nextPart; }
int addSource(Spec spec, /*@unused@*/ Package pkg, const char *field, rpmTag tag) { struct Source *p; #if defined(RPM_VENDOR_OPENPKG) /* regular-ordered-sources */ struct Source *p_last; #endif int flag = 0; const char *name = NULL; const char *mdir = NULL; const char *fieldp = NULL; char buf[BUFSIZ]; uint32_t num = 0; buf[0] = '\0'; switch (tag) { case RPMTAG_SOURCE: flag = RPMFILE_SOURCE; name = "source"; fieldp = spec->line + strlen(name); break; case RPMTAG_PATCH: flag = RPMFILE_PATCH; name = "patch"; fieldp = spec->line + strlen(name); break; case RPMTAG_ICON: flag = RPMFILE_ICON; name = "icon"; fieldp = NULL; break; default: assert(0); /*@notreached@*/ break; } #if !defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */ mdir = getSourceDir(flag); assert(mdir != NULL); #endif /* Get the number */ if (fieldp != NULL) { char * end = NULL; num = strtoul(fieldp, &end, 10); SKIPSPACE(end); if (*end != ':') { rpmlog(RPMLOG_ERR, _("line %d: No ':' terminator: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } /* Check whether tags of the same number haven't already been defined */ for (p = spec->sources; p != NULL; p = p->next) { if ( p->num != num ) continue; if ((tag == RPMTAG_SOURCE && p->flags == RPMFILE_SOURCE) || (tag == RPMTAG_PATCH && p->flags == RPMFILE_PATCH)) { rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num); return RPMRC_FAIL; } } /* Create the entry and link it in */ p = xmalloc(sizeof(*p)); p->num = num; p->fullSource = xstrdup(field); p->flags = flag; p->source = strrchr(p->fullSource, '/'); if (p->source) p->source++; else p->source = p->fullSource; #if defined(RPM_VENDOR_OPENPKG) /* regular-ordered-sources */ p->next = NULL; p_last = spec->sources; while (p_last != NULL && p_last->next != NULL) p_last = p_last->next; if (p_last != NULL) p_last->next = p; else spec->sources = p; #else p->next = spec->sources; spec->sources = p; #endif spec->numSources++; /* XXX FIXME: need to add ICON* macros. */ #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */ mdir = getSourceDir(flag, p->source); #endif if (tag != RPMTAG_ICON) { const char *body = rpmGenPath(NULL, mdir, p->source); sprintf(buf, "%s%d", (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num); addMacro(spec->macros, buf, NULL, body, RMIL_SPEC); sprintf(buf, "%sURL%d", (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num); addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC); #ifdef WITH_LUA if (!spec->recursing) { rpmlua lua = NULL; /* global state */ const char * what = (flag & RPMFILE_PATCH) ? "patches" : "sources"; rpmluav var = rpmluavNew(); rpmluaPushTable(lua, what); rpmluavSetListMode(var, 1); rpmluavSetValue(var, RPMLUAV_STRING, body); rpmluaSetVar(lua, var); /*@-moduncon@*/ var = (rpmluav) rpmluavFree(var); /*@=moduncon@*/ rpmluaPop(lua); } #endif body = _free(body); } return RPMRC_OK; }
static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, const char *macro, const char *lang) { char * field = spec->line; char * end; int multiToken = 0; rpmsenseFlags tagflags = RPMSENSE_ANY; rpmRC rc = RPMRC_FAIL; if (field == NULL) /* XXX can't happen */ goto exit; /* Find the start of the "field" and strip trailing space */ while ((*field) && (*field != ':')) field++; if (*field != ':') { rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), spec->lineNum, spec->line); goto exit; } field++; SKIPSPACE(field); if (!*field) { /* Empty field */ rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), spec->lineNum, spec->line); goto exit; } end = findLastChar(field); *(end+1) = '\0'; /* See if this is multi-token */ end = field; SKIPNONSPACE(end); if (*end != '\0') multiToken = 1; switch (tag) { case RPMTAG_NAME: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, WHITELIST_NAME)) goto exit; headerPutString(pkg->header, tag, field); /* Main pkg name is unknown at the start, populate as soon as we can */ if (pkg == spec->packages) pkg->name = rpmstrPoolId(spec->pool, field, 1); break; case RPMTAG_VERSION: case RPMTAG_RELEASE: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, "._+%{}~")) goto exit; headerPutString(pkg->header, tag, field); break; case RPMTAG_URL: case RPMTAG_DISTTAG: case RPMTAG_BUGURL: /* XXX TODO: validate format somehow */ case RPMTAG_VCS: SINGLE_TOKEN_ONLY; headerPutString(pkg->header, tag, field); break; case RPMTAG_GROUP: case RPMTAG_SUMMARY: case RPMTAG_DISTRIBUTION: case RPMTAG_VENDOR: case RPMTAG_LICENSE: case RPMTAG_PACKAGER: if (addLangTag(spec, pkg->header, tag, field, lang)) goto exit; break; case RPMTAG_BUILDROOT: /* just silently ignore BuildRoot */ macro = NULL; break; case RPMTAG_PREFIXES: { struct rpmtd_s td; const char *str; if (addOrAppendListEntry(pkg->header, tag, field)) goto exit; headerGet(pkg->header, tag, &td, HEADERGET_MINMEM); while ((str = rpmtdNextString(&td))) { size_t len = strlen(str); if (len > 1 && str[len-1] == '/') { rpmlog(RPMLOG_ERR, _("line %d: Prefixes must not end with \"/\": %s\n"), spec->lineNum, spec->line); rpmtdFreeData(&td); goto exit; } } rpmtdFreeData(&td); break; } case RPMTAG_DOCDIR: SINGLE_TOKEN_ONLY; if (field[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"), spec->lineNum, spec->line); goto exit; } macro = NULL; rpmPopMacro(NULL, "_docdir"); rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); break; case RPMTAG_EPOCH: { SINGLE_TOKEN_ONLY; uint32_t epoch; if (parseUnsignedNum(field, &epoch)) { rpmlog(RPMLOG_ERR, _("line %d: Epoch field must be an unsigned number: %s\n"), spec->lineNum, spec->line); goto exit; } headerPutUint32(pkg->header, tag, &epoch, 1); break; } case RPMTAG_AUTOREQPROV: pkg->autoReq = parseYesNo(field); pkg->autoProv = pkg->autoReq; break; case RPMTAG_AUTOREQ: pkg->autoReq = parseYesNo(field); break; case RPMTAG_AUTOPROV: pkg->autoProv = parseYesNo(field); break; case RPMTAG_SOURCE: case RPMTAG_PATCH: macro = NULL; if (addSource(spec, pkg, field, tag)) goto exit; break; case RPMTAG_ICON: SINGLE_TOKEN_ONLY; if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field)) goto exit; break; case RPMTAG_NOSOURCE: case RPMTAG_NOPATCH: spec->noSource = 1; if (parseNoSource(spec, field, tag)) goto exit; break; case RPMTAG_ORDERFLAGS: case RPMTAG_REQUIREFLAGS: if (parseBits(lang, installScriptBits, &tagflags)) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"), spec->lineNum, rpmTagGetName(tag), spec->line); goto exit; } /* fallthrough */ case RPMTAG_PREREQ: case RPMTAG_RECOMMENDFLAGS: case RPMTAG_SUGGESTFLAGS: case RPMTAG_SUPPLEMENTFLAGS: case RPMTAG_ENHANCEFLAGS: case RPMTAG_CONFLICTFLAGS: case RPMTAG_OBSOLETEFLAGS: case RPMTAG_PROVIDEFLAGS: if (parseRCPOT(spec, pkg, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_BUILDPREREQ: case RPMTAG_BUILDREQUIRES: case RPMTAG_BUILDCONFLICTS: if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_EXCLUDEARCH: case RPMTAG_EXCLUSIVEARCH: case RPMTAG_EXCLUDEOS: case RPMTAG_EXCLUSIVEOS: if (addOrAppendListEntry(spec->buildRestrictions, tag, field)) goto exit; break; case RPMTAG_BUILDARCHS: { int BACount; const char **BANames = NULL; if (poptParseArgvString(field, &BACount, &BANames)) { rpmlog(RPMLOG_ERR, _("line %d: Bad BuildArchitecture format: %s\n"), spec->lineNum, spec->line); goto exit; } if (spec->packages == pkg) { if (spec->BANames) { rpmlog(RPMLOG_ERR, _("line %d: Duplicate BuildArch entry: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } spec->BACount = BACount; spec->BANames = BANames; } else { if (BACount != 1 || !rstreq(BANames[0], "noarch")) { rpmlog(RPMLOG_ERR, _("line %d: Only noarch subpackages are supported: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } headerPutString(pkg->header, RPMTAG_ARCH, "noarch"); } if (!BACount) spec->BANames = _free(spec->BANames); break; } case RPMTAG_REMOVEPATHPOSTFIXES: argvSplit(&pkg->removePostfixes, field, ":"); break; default: rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag); goto exit; } if (macro) { rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC); /* Add a separate uppercase macro for tags from the main package */ if (pkg == spec->packages) { char *m = xstrdup(macro); for (char *p = m; *p; ++p) *p = rtoupper(*p); rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC); free(m); } } rc = RPMRC_OK; exit: return rc; }
static void createRTags (void) { vString *vLine = vStringNew (); vString *name = vStringNew (); int ikind; const unsigned char *line; while ((line = fileReadLine ()) != NULL) { const unsigned char *cp = (const unsigned char *) line; vStringClear (name); while ((*cp != '\0') && (*cp != '#')) { /* iterate to the end of line or to a comment */ ikind = -1; switch (*cp) { case 'l': case 's': if (strncasecmp ((const char *) cp, "library", (size_t) 7) == 0) { /* load a library: library(tools) */ cp += 7; SKIPSPACE (cp); if (*cp == '(') ikind = K_LIBRARY; else cp -= 7; } else if (strncasecmp ((const char *) cp, "source", (size_t) 6) == 0) { /* load a source file: source("myfile.r") */ cp += 6; SKIPSPACE (cp); if (*cp == '(') ikind = K_SOURCE; else cp -= 6; } if (ikind != -1) { cp++; vStringClear (name); while ((!isspace ((int) *cp)) && *cp != '\0' && *cp != ')') { vStringPut (name, (int) *cp); cp++; } vStringTerminate (name); /* if the string really exists, make a tag of it */ if (vStringLength (name) > 0) makeRTag (name, ikind); /* prepare for the next iteration */ vStringClear (name); } else { vStringPut (name, (int) *cp); cp++; } break; case '<': cp++; if (*cp == '-') { /* assignment: ident <- someval */ cp++; SKIPSPACE (cp); if (*cp == '\0') { /* not in this line, read next */ /* sometimes functions are declared this way: * ident <- * function(...) * { * ... * } * I don't know if there is a reason to write the function keyword * in a new line */ if ((line = fileReadLine ()) != NULL) { cp = (const unsigned char *) line; SKIPSPACE (cp); } } if (strncasecmp ((const char *) cp, "function", (size_t) 8) == 0) { /* it's a function: ident <- function(args) */ cp += 8; vStringTerminate (name); /* if the string really exists, make a tag of it */ if (vStringLength (name) > 0) makeRTag (name, K_FUNCTION); /* prepare for the next iteration */ vStringClear (name); break; } else { /* it's a variable: ident <- value */ vStringTerminate (name); /* if the string really exists, make a tag of it */ if (vStringLength (name) > 0) { if (line[0] == ' ' || line[0] == '\t') makeRTag (name, K_FUNCVAR); else makeRTag (name, K_GLOBALVAR); } /* prepare for the next iteration */ vStringClear (name); break; } } case ' ': case '\x009': /* skip whitespace */ cp++; break; default: /* collect all characters that could be a part of an identifier */ vStringPut (name, (int) *cp); cp++; break; } } } vStringDelete (name); vStringDelete (vLine); }
/** * Parses attributes from opening text of the tag. This function does nothing * when node type is different from tag. The parser tries to be as tolerant * as possible (unquoted attribute values, extra spaces ...). When attribute * with no value is found (common in HTML, not in XHTML), its value is set * to its name (to ensure forward compatibility - e.g. in option tag it is * common to use <code>selected="selected"</code> in XHTML instead of * <code>selected</code> in HTML). * */ void HtmlNode::parseAttributes(bool normalizeAttributes) { #define SKIPSPACE(ptr) while (isspace(*ptr)) ptr++ if (type != TAG) { return; } if (attributesParsed_) { return; } const char *ptr = openingText_.c_str(); if ((ptr = strchr(ptr, '<')) == 0) { return; // no <, probably something weird is going on... } ptr++; SKIPSPACE(ptr); // here shall be the tag name (which shall be skipped // as well as following blanks if (!isalpha(*ptr)) { return; } while (isalnum(*ptr)) { ptr++; } SKIPSPACE(ptr); // iterate through attributes while (*ptr && (*ptr != '>')) { const char * attrStart; // skip garbage before attribute name while (*ptr && !isalpha(*ptr)) { ptr++; } if (*ptr == 0) { return; } // read in attribute name attrStart = ptr++; while (*ptr && (isalnum(*ptr) || (*ptr == '-'))) { ptr++; } if (*ptr == 0) { return; } std::string key(attrStart, ptr - attrStart); // skip '=' and spaces bool foundAssign = false; while (*ptr && (isspace(*ptr) || ((*ptr == '=') && (foundAssign=true)))) { ptr++; } if (*ptr == 0) { return; } // find the attribute value std::string val; if (!foundAssign) { // attribute without value // by this we somehow ensure compatibility (fingers crossed) // FIXME - how about extra parameter for this val = key; } else { char quitchar = 0; const char * start; if ((*ptr == '"') || (*ptr == '\'')) { quitchar = *ptr; start = ++ptr; } else { start = ptr; } // FIXME - how is it with escaped quotes? while (*ptr && ( ((quitchar == 0) && (!isspace(*ptr))) || (quitchar && (*ptr != quitchar)) )) { ptr++; } if (*ptr == 0) { return; } val = std::string(start, ptr - start); ptr++; //skip the space or the quote } // normalize (attribute name to lower case) if (normalizeAttributes) { // transform would be ideal here, thought it may not be // portable, so let's do it the ugly way // (see http://bytes.com/groups/c/60652-tolower-used-transform) std::string::iterator e = key.end(); for (std::string::iterator it = key.begin(); it != e; ++it) { *it = tolower(*it); } } // store the attribute attributes_[key] = val; } attributesParsed_ = true; #undef SKIPSPACE }
/* read XPM from either array or RWops */ static SDL_Surface *load_xpm(char **xpm, SDL_RWops *src) { Sint64 start = 0; SDL_Surface *image = NULL; int index; int x, y; int w, h, ncolors, cpp; int indexed; Uint8 *dst; struct color_hash *colors = NULL; SDL_Color *im_colors = NULL; char *keystrings = NULL, *nextkey; char *line; char ***xpmlines = NULL; int pixels_len; error = NULL; linebuf = NULL; buflen = 0; if (src) start = SDL_RWtell(src); if (xpm) xpmlines = &xpm; line = get_next_line(xpmlines, src, 0); if (!line) goto done; /* * The header string of an XPMv3 image has the format * * <width> <height> <ncolors> <cpp> [ <hotspot_x> <hotspot_y> ] * * where the hotspot coords are intended for mouse cursors. * Right now we don't use the hotspots but it should be handled * one day. */ if (SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { error = "Invalid format description"; goto done; } keystrings = (char *)SDL_malloc(ncolors * cpp); if (!keystrings) { error = "Out of memory"; goto done; } nextkey = keystrings; /* Create the new surface */ if (ncolors <= 256) { indexed = 1; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); im_colors = image->format->palette->colors; image->format->palette->ncolors = ncolors; } else { indexed = 0; image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, 0xff0000, 0x00ff00, 0x0000ff, 0); } if (!image) { /* Hmm, some SDL error (out of memory?) */ goto done; } /* Read the colors */ colors = create_colorhash(ncolors); if (!colors) { error = "Out of memory"; goto done; } for (index = 0; index < ncolors; ++index ) { char *p; line = get_next_line(xpmlines, src, 0); if (!line) goto done; p = line + cpp + 1; /* parse a colour definition */ for (;;) { char nametype; char *colname; Uint32 rgb, pixel; SKIPSPACE(p); if (!*p) { error = "colour parse error"; goto done; } nametype = *p; SKIPNONSPACE(p); SKIPSPACE(p); colname = p; SKIPNONSPACE(p); if (nametype == 's') continue; /* skip symbolic colour names */ if (!color_to_rgb(colname, p - colname, &rgb)) continue; SDL_memcpy(nextkey, line, cpp); if (indexed) { SDL_Color *c = im_colors + index; c->r = (Uint8)(rgb >> 16); c->g = (Uint8)(rgb >> 8); c->b = (Uint8)(rgb); pixel = index; } else pixel = rgb; add_colorhash(colors, nextkey, cpp, pixel); nextkey += cpp; if (rgb == 0xffffffff) SDL_SetColorKey(image, SDL_TRUE, pixel); break; } }
int parsePreamble(rpmSpec spec, int initialPackage) { int nextPart = PART_ERROR; int res = PART_ERROR; /* assume failure */ int rc; char *name, *linep; int flag = 0; Package pkg; char *NVR = NULL; char lang[BUFSIZ]; if (! initialPackage) { /* There is one option to %package: <pkg> or -n <pkg> */ if (parseSimplePart(spec->line, &name, &flag)) { rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"), spec->line); goto exit; } if (rpmCharCheck(spec, name, WHITELIST_NAME)) goto exit; if (!lookupPackage(spec, name, flag, NULL)) { free(name); goto exit; } /* Construct the package */ if (flag == PART_SUBNAME) { rasprintf(&NVR, "%s-%s", headerGetString(spec->packages->header, RPMTAG_NAME), name); } else NVR = xstrdup(name); free(name); pkg = newPackage(NVR, spec->pool, &spec->packages); headerPutString(pkg->header, RPMTAG_NAME, NVR); } else { NVR = xstrdup("(main package)"); pkg = newPackage(NULL, spec->pool, &spec->packages); spec->sourcePackage = newPackage(NULL, spec->pool, NULL); } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; } else if (rc < 0) { goto exit; } else { while (! (nextPart = isPart(spec->line))) { const char * macro; rpmTagVal tag; /* Skip blank lines */ linep = spec->line; SKIPSPACE(linep); if (*linep != '\0') { if (findPreambleTag(spec, &tag, ¯o, lang)) { if (spec->lineNum == 1 && (unsigned char)(spec->line[0]) == 0xed && (unsigned char)(spec->line[1]) == 0xab && (unsigned char)(spec->line[2]) == 0xee && (unsigned char)(spec->line[3]) == 0xdb) { rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n")); goto exit; } rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"), spec->lineNum, spec->line); goto exit; } if (handlePreambleTag(spec, pkg, tag, macro, lang)) { goto exit; } if (spec->BANames && !spec->recursing) { res = PART_BUILDARCHITECTURES; goto exit; } } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; break; } if (rc) { goto exit; } } } /* * Expand buildroot one more time to get %{version} and the like * from the main package, validate sanity. The spec->buildRoot could * still contain unexpanded macros but it cannot be empty or '/', and it * can't be messed with by anything spec does beyond this point. */ if (initialPackage) { char *buildRoot = rpmGetPath(spec->buildRoot, NULL); if (*buildRoot == '\0') { rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n")); goto exit; } if (rstreq(buildRoot, "/")) { rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n")); goto exit; } free(spec->buildRoot); spec->buildRoot = buildRoot; rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC); } /* XXX Skip valid arch check if not building binary package */ if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) { goto exit; } /* It is the main package */ if (pkg == spec->packages) { fillOutMainPackage(pkg->header); /* Define group tag to something when group is undefined in main package*/ if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) { headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified"); } } if (checkForDuplicates(pkg->header, NVR)) { goto exit; } if (pkg != spec->packages) { headerCopyTags(spec->packages->header, pkg->header, (rpmTagVal *)copyTagsDuringParse); } if (checkForRequired(pkg->header, NVR)) { goto exit; } /* if we get down here nextPart has been set to non-error */ res = nextPart; exit: free(NVR); return res; }