diff --git a/build/build.c b/build/build.c index e50c3784ea..e8340a2f96 100644 --- a/build/build.c +++ b/build/build.c @@ -170,8 +170,10 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name, goto exit; } - buildTemplate = rpmExpand(mTemplate, NULL); - buildPost = rpmExpand(mPost, NULL); + if ((buildTemplate = rpmExpand(mTemplate, NULL)) == NULL) + goto exit; + if ((buildPost = rpmExpand(mPost, NULL)) == NULL) + goto exit; (void) fputs(buildTemplate, fp); @@ -196,7 +198,8 @@ rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name, goto exit; } - buildCmd = rpmExpand(mCmd, " ", scriptName, NULL); + if ((buildCmd = rpmExpand(mCmd, " ", scriptName, NULL)) == NULL) + goto exit; (void) poptParseArgvString(buildCmd, &argc, &argv); rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd); @@ -424,11 +427,20 @@ static rpmRC buildSpec(rpmts ts, BTA_t buildArgs, rpmSpec spec, int what) freeStringBuf(sink); free(cookie); spec->rootDir = NULL; - if (rc != RPMRC_OK && rc != RPMRC_MISSINGBUILDREQUIRES && - rpmlogGetNrecs() > 0) { - rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n")); - rpmlogPrint(NULL); + + /* Print a warning/error summary */ + int nrecs = rpmlogGetNrecs(); + if (nrecs && rc != RPMRC_MISSINGBUILDREQUIRES) { + int mkwarn = RPMLOG_MASK(RPMLOG_WARNING); + int mkerrs = RPMLOG_MASK(RPMLOG_ERR); + int nwarn = rpmlogGetNrecsByMask(mkwarn); + rpmlog(RPMLOG_NOTICE, + _("\n\nRPM build problems (%i warnings, %i errors):\n"), + nwarn, nrecs - nwarn); + rpmlogPrettyPrint(NULL, mkwarn, 1); + rpmlogPrettyPrint(NULL, mkerrs, 1); } + rpmugFree(); if (missing_buildreqs && !rc) { rc = RPMRC_MISSINGBUILDREQUIRES; diff --git a/build/parseSpec.c b/build/parseSpec.c index 2fd29e178c..c5ca68a0e5 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -25,6 +25,7 @@ #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; } #define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; } +#define NOEOL(s) strclen(s, '\n'), s #define ISMACRO(s,m,len) (rstreqn((s), (m), len) && !risalpha((s)[len])) #define ISMACROWITHARG(s,m,len) (rstreqn((s), (m), len) && (risblank((s)[len]) || !(s)[len])) @@ -97,6 +98,18 @@ int isPart(const char *line) return (p->token ? p->part : PART_NONE); } +/* Calculate length of s until c, for use within printf(3) precision */ +static inline int strclen(const char *s, char c) +{ + char *p = strrchr(s, c); + if (!p) + return -1; + ptrdiff_t len = p - s; + if (len > INT_MAX) + return -1; + return (int)len; +} + /** */ static int matchTok(const char *token, const char *line) @@ -229,8 +242,8 @@ static int expandMacrosInSpecBuf(rpmSpec spec, int strip) SKIPSPACE(s); if (s[0]) rpmlog(RPMLOG_WARNING, - _("extra tokens at the end of %s directive in line %d: %s\n"), - condition->text, spec->lineNum, lbuf); + _("extra tokens at the end of %s directive in line %d: %.*s\n"), + condition->text, spec->lineNum, NOEOL(lbuf)); } /* Don't expand macros after %elif (resp. %elifarch, %elifos) in a false branch */ @@ -263,8 +276,8 @@ static int expandMacrosInSpecBuf(rpmSpec spec, int strip) if (*bufA != '\0' || *bufB != '\0') rpmlog(RPMLOG_WARNING, - _("Macro expanded in comment on line %d: %s\n"), - spec->lineNum, bufA); + _("Macro expanded in comment on line %d: %.*s\n"), + spec->lineNum, NOEOL(bufA)); } free(spec->lbuf); @@ -291,6 +304,11 @@ static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi, int strip) spec->lbuf = realloc(spec->lbuf, spec->lbufSize); } } + if (ch != '\n') { + spec->lbuf[spec->lbufOff++] = '\n'; + if (spec->lbufOff == spec->lbufSize) + spec->lbuf = realloc(spec->lbuf, ++spec->lbufSize); + } spec->lbuf[spec->lbufOff] = '\0'; ofi->readPtr = from; @@ -509,8 +527,9 @@ int readLine(rpmSpec spec, int strip) match = rpmExprBoolFlags(s, 0); if (match < 0) { rpmlog(RPMLOG_ERR, - _("%s:%d: bad %s condition: %s\n"), - ofi->fileName, ofi->lineNum, lineType->text, s); + _("%s:%d: bad %s condition: %.*s\n"), + ofi->fileName, ofi->lineNum, lineType->text, + NOEOL(s)); return PART_ERROR; } } @@ -841,15 +860,15 @@ static int parseEmpty(rpmSpec spec, int prevParsePart) SKIPSPACE(line); if (line[0] != '\0') { rpmlog(RPMLOG_ERR, - _("line %d: %%end doesn't take any arguments: %s\n"), - spec->lineNum, spec->line); + _("line %d: %%end doesn't take any arguments: %.*s\n"), + spec->lineNum, NOEOL(spec->line)); goto exit; } if (prevParsePart == PART_EMPTY) { rpmlog(RPMLOG_ERR, - _("line %d: %%end not expected here, no section to close: %s\n"), - spec->lineNum, spec->line); + _("line %d: %%end not expected here, no section to close: %.*s\n"), + spec->lineNum, NOEOL(spec->line)); goto exit; } diff --git a/rpmio/macro.c b/rpmio/macro.c index 7a75e3b653..df1feba4e3 100644 --- a/rpmio/macro.c +++ b/rpmio/macro.c @@ -2005,6 +2005,7 @@ rpmExpand(const char *arg, ...) const char *s; va_list ap; rpmMacroContext mc; + int rc = 1; if (arg == NULL) { ret = xstrdup(""); @@ -2026,9 +2027,14 @@ rpmExpand(const char *arg, ...) va_end(ap); mc = rpmmctxAcquire(NULL); - (void) doExpandMacros(mc, buf, 0, &ret); + rc = doExpandMacros(mc, buf, 0, &ret); rpmmctxRelease(mc); + if (rc) { + free(ret); + ret = NULL; + } + free(buf); exit: return ret; diff --git a/rpmio/rpmlog.c b/rpmio/rpmlog.c index d52b897fc3..2434ef176e 100644 --- a/rpmio/rpmlog.c +++ b/rpmio/rpmlog.c @@ -11,11 +11,15 @@ #include #include "debug.h" +#define each(rec, ctx) \ + (rpmlogRec rec = ctx->recs; rec < &(ctx->recs[ctx->nrecs]); rec++) + typedef struct rpmlogCtx_s * rpmlogCtx; struct rpmlogCtx_s { pthread_rwlock_t lock; unsigned mask; int nrecs; + int nrecsPri[RPMLOG_NPRIORITIES]; rpmlogRec recs; rpmlogCallback cbfunc; rpmlogCallbackData cbdata; @@ -33,7 +37,7 @@ static rpmlogCtx rpmlogCtxAcquire(int write) { static struct rpmlogCtx_s _globalCtx = { PTHREAD_RWLOCK_INITIALIZER, RPMLOG_UPTO(RPMLOG_NOTICE), - 0, NULL, NULL, NULL, NULL }; + 0, {0}, NULL, NULL, NULL, NULL }; rpmlogCtx ctx = &_globalCtx; int xx; @@ -55,11 +59,27 @@ static rpmlogCtx rpmlogCtxRelease(rpmlogCtx ctx) } int rpmlogGetNrecs(void) +{ + return rpmlogGetNrecsByMask(0); +} + +int rpmlogGetNrecsByMask(unsigned mask) { rpmlogCtx ctx = rpmlogCtxAcquire(0); int nrecs = -1; - if (ctx) - nrecs = ctx->nrecs; + if (ctx) { + if (!mask) { + nrecs = ctx->nrecs; + } else { + nrecs = 0; + int bit = 1; + for (int i = 0; i < RPMLOG_NPRIORITIES; i++) { + if (mask & bit) + nrecs += ctx->nrecsPri[i]; + bit <<= 1; + } + } + } rpmlogCtxRelease(ctx); return nrecs; } @@ -98,20 +118,19 @@ rpmlogLvl rpmlogRecPriority(rpmlogRec rec) return (rec != NULL) ? rec->pri : (rpmlogLvl)-1; } -void rpmlogPrint(FILE *f) +static void rpmlogForeach(void (*func) (rpmlogRec, void*), void *data, + unsigned mask) { rpmlogCtx ctx = rpmlogCtxAcquire(0); if (ctx == NULL) return; - if (f == NULL) - f = stderr; - - for (int i = 0; i < ctx->nrecs; i++) { - rpmlogRec rec = ctx->recs + i; + for each(rec, ctx) { + if (mask && ((RPMLOG_MASK(rec->pri) & mask) == 0)) + continue; if (rec->message && *rec->message) - fprintf(f, " %s", rec->message); + func(rec, data); } rpmlogCtxRelease(ctx); @@ -124,12 +143,12 @@ void rpmlogClose (void) if (ctx == NULL) return; - for (int i = 0; i < ctx->nrecs; i++) { - rpmlogRec rec = ctx->recs + i; + for each(rec, ctx) { rec->message = _free(rec->message); } ctx->recs = _free(ctx->recs); ctx->nrecs = 0; + memset(ctx->nrecsPri, 0, sizeof(ctx->nrecsPri)); rpmlogCtxRelease(ctx); } @@ -270,7 +289,29 @@ static void logerror(void) } } -static int rpmlogDefault(FILE *stdlog, rpmlogRec rec) +static int ifprint(FILE *f, const char *str, int indent, int lead) +{ + int total = 0; + int nprinted = 0; + const char *p = str; + int count = 0; + while (*str) { + p = strchr(str, '\n'); + count = p ? p - str + 1 : -1; + nprinted = fprintf(f, "%*s%.*s", + (lead || total) ? indent : 0, "", + count, str); + if (nprinted < 0) + return nprinted; + total += nprinted; + if (count < 0) + break; + str = p + 1; + } + return total; +} + +static int rpmlogDefault(FILE *stdlog, rpmlogRec rec, int indent, int bold) { FILE *msgout = (stdlog ? stdlog : stderr); static __thread int color = -1; @@ -302,7 +343,7 @@ static int rpmlogDefault(FILE *stdlog, rpmlogRec rec) break; } - if (fputs(rpmlogLevelPrefix(rec->pri), msgout) == EOF) + if (ifprint(msgout, rpmlogLevelPrefix(rec->pri), indent, 1) < 0) logerror(); switch (rec->pri) { @@ -317,7 +358,7 @@ static int rpmlogDefault(FILE *stdlog, rpmlogRec rec) if (colorOn && *colorOn) { if (fputs(ANSI_COLOR_RESET, msgout) == EOF) logerror(); - if (fputs(ANSI_COLOR_BOLD, msgout) == EOF) + if (bold && (fputs(ANSI_COLOR_BOLD, msgout) == EOF)) logerror(); } case RPMLOG_DEBUG: @@ -326,8 +367,8 @@ static int rpmlogDefault(FILE *stdlog, rpmlogRec rec) } if (rec->message) - if (fputs(rec->message, msgout) == EOF) - logerror(); + if (ifprint(msgout, rec->message, indent, 0) < 0) + logerror(); switch (rec->pri) { case RPMLOG_INFO: @@ -353,6 +394,29 @@ static int rpmlogDefault(FILE *stdlog, rpmlogRec rec) return (rec->pri <= RPMLOG_CRIT ? RPMLOG_EXIT : 0); } +static void rpmlogRecPrettyPrint(rpmlogRec rec, void *data) +{ + FILE *f = (FILE *)data; + rpmlogDefault(f, rec, 4, 0); +} + +static void rpmlogRecPrint(rpmlogRec rec, void *data) +{ + fprintf((FILE *)data, " %s", rec->message); +} + +void rpmlogPrettyPrint(FILE *f, unsigned mask, int color) +{ + if (f == NULL) + f = stderr; + rpmlogForeach(color ? rpmlogRecPrettyPrint : rpmlogRecPrint, f, mask); +} + +void rpmlogPrint(FILE *f) +{ + rpmlogPrettyPrint(f, 0, 0); +} + /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */ /* FIX: rpmlogMsgPrefix[] may be NULL */ static void dolog(struct rpmlogRec_s *rec, int saverec) @@ -378,6 +442,7 @@ static void dolog(struct rpmlogRec_s *rec, int saverec) ctx->recs[ctx->nrecs+1].code = 0; ctx->recs[ctx->nrecs+1].message = NULL; ctx->nrecs++; + ctx->nrecsPri[rec->pri]++; } cbfunc = ctx->cbfunc; cbdata = ctx->cbdata; @@ -394,7 +459,7 @@ static void dolog(struct rpmlogRec_s *rec, int saverec) } if (cbrc & RPMLOG_DEFAULT) { - cbrc = rpmlogDefault(clog, rec); + cbrc = rpmlogDefault(clog, rec, 0, 1); needexit += cbrc & RPMLOG_EXIT; } pthread_mutex_unlock(&serialize); diff --git a/rpmio/rpmlog.h b/rpmio/rpmlog.h index 6f3da1d5dd..da818f3c66 100644 --- a/rpmio/rpmlog.h +++ b/rpmio/rpmlog.h @@ -35,6 +35,7 @@ typedef enum rpmlogLvl_e { RPMLOG_NOTICE = 5, /*!< normal but significant condition */ RPMLOG_INFO = 6, /*!< informational */ RPMLOG_DEBUG = 7 /*!< debug-level messages */ +#define RPMLOG_NPRIORITIES 8 /*!< current number of priorities */ } rpmlogLvl; #define RPMLOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ @@ -132,12 +133,27 @@ typedef void * rpmlogCallbackData; */ typedef int (*rpmlogCallback) (rpmlogRec rec, rpmlogCallbackData data); +/** \ingroup rpmlog + * Return number of rpmError() messages matching a log mask. + * @param mask log mask to filter by (0 is no filtering) + * @return number of messages matching the mask + */ +int rpmlogGetNrecsByMask(unsigned mask); + /** \ingroup rpmlog * Return number of rpmError() ressages. * @return number of messages */ int rpmlogGetNrecs(void) ; +/** \ingroup rpmlog + * Print all rpmError() messages matching a log mask, possibly in color. + * @param f file handle (NULL uses stderr) + * @param mask log mask to filter by (0 is no filtering) + * @param color should color be used if available? + */ +void rpmlogPrettyPrint(FILE *f, unsigned mask, int color); + /** \ingroup rpmlog * Print all rpmError() messages. * @param f file handle (NULL uses stderr)