"Fossies" - the Fresh Open Source Software Archive

Member "rpm-4.15.0/rpmio/rpmlog.c" (26 Jun 2019, 9598 Bytes) of package /linux/misc/rpm-4.15.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpmlog.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.14.2.1_vs_4.15.0.

    1 /** \ingroup rpmio
    2  * \file rpmio/rpmlog.c
    3  */
    4 
    5 #include "system.h"
    6 #include <stdarg.h>
    7 #include <stdlib.h>
    8 #include <pthread.h>
    9 #include <errno.h>
   10 #include <rpm/rpmlog.h>
   11 #include <rpm/rpmmacro.h>
   12 #include "debug.h"
   13 
   14 typedef struct rpmlogCtx_s * rpmlogCtx;
   15 struct rpmlogCtx_s {
   16     pthread_rwlock_t lock;
   17     unsigned mask;
   18     int nrecs;
   19     rpmlogRec recs;
   20     rpmlogCallback cbfunc;
   21     rpmlogCallbackData cbdata;
   22     FILE *stdlog;
   23 };
   24 
   25 struct rpmlogRec_s {
   26     int     code;       /* unused */
   27     rpmlogLvl   pri;        /* priority */ 
   28     char * message;     /* log message string */
   29 };
   30 
   31 /* Force log context acquisition through a function */
   32 static rpmlogCtx rpmlogCtxAcquire(int write)
   33 {
   34     static struct rpmlogCtx_s _globalCtx = { PTHREAD_RWLOCK_INITIALIZER,
   35                          RPMLOG_UPTO(RPMLOG_NOTICE),
   36                          0, NULL, NULL, NULL, NULL };
   37     rpmlogCtx ctx = &_globalCtx;
   38     int xx;
   39 
   40     /* XXX Silently failing is bad, but we can't very well use log here... */
   41     if (write)
   42     xx = pthread_rwlock_wrlock(&ctx->lock);
   43     else
   44     xx = pthread_rwlock_rdlock(&ctx->lock);
   45 
   46     return (xx == 0) ? ctx : NULL;
   47 }
   48 
   49 /* Release log context */
   50 static rpmlogCtx rpmlogCtxRelease(rpmlogCtx ctx)
   51 {
   52     if (ctx)
   53     pthread_rwlock_unlock(&ctx->lock);
   54     return NULL;
   55 }
   56 
   57 int rpmlogGetNrecs(void)
   58 {
   59     rpmlogCtx ctx = rpmlogCtxAcquire(0);
   60     int nrecs = -1;
   61     if (ctx)
   62     nrecs = ctx->nrecs;
   63     rpmlogCtxRelease(ctx);
   64     return nrecs;
   65 }
   66 
   67 int rpmlogCode(void)
   68 {
   69     int code = -1;
   70     rpmlogCtx ctx = rpmlogCtxAcquire(0);
   71     
   72     if (ctx && ctx->recs != NULL && ctx->nrecs > 0)
   73     code = ctx->recs[ctx->nrecs-1].code;
   74 
   75     rpmlogCtxRelease(ctx);
   76     return code;
   77 }
   78 
   79 const char * rpmlogMessage(void)
   80 {
   81     const char *msg = _("(no error)");
   82     rpmlogCtx ctx = rpmlogCtxAcquire(0);
   83 
   84     if (ctx && ctx->recs != NULL && ctx->nrecs > 0)
   85     msg = ctx->recs[ctx->nrecs-1].message;
   86 
   87     rpmlogCtxRelease(ctx);
   88     return msg;
   89 }
   90 
   91 const char * rpmlogRecMessage(rpmlogRec rec)
   92 {
   93     return (rec != NULL) ? rec->message : NULL;
   94 }
   95 
   96 rpmlogLvl rpmlogRecPriority(rpmlogRec rec)
   97 {
   98     return (rec != NULL) ? rec->pri : (rpmlogLvl)-1;
   99 }
  100 
  101 void rpmlogPrint(FILE *f)
  102 {
  103     rpmlogCtx ctx = rpmlogCtxAcquire(0);
  104 
  105     if (ctx == NULL)
  106     return;
  107 
  108     if (f == NULL)
  109     f = stderr;
  110 
  111     for (int i = 0; i < ctx->nrecs; i++) {
  112     rpmlogRec rec = ctx->recs + i;
  113     if (rec->message && *rec->message)
  114         fprintf(f, "    %s", rec->message);
  115     }
  116 
  117     rpmlogCtxRelease(ctx);
  118 }
  119 
  120 void rpmlogClose (void)
  121 {
  122     rpmlogCtx ctx = rpmlogCtxAcquire(1);
  123 
  124     if (ctx == NULL)
  125     return;
  126 
  127     for (int i = 0; i < ctx->nrecs; i++) {
  128     rpmlogRec rec = ctx->recs + i;
  129     rec->message = _free(rec->message);
  130     }
  131     ctx->recs = _free(ctx->recs);
  132     ctx->nrecs = 0;
  133 
  134     rpmlogCtxRelease(ctx);
  135 }
  136 
  137 void rpmlogOpen (const char *ident, int option,
  138         int facility)
  139 {
  140 }
  141 
  142 #ifdef NOTYET
  143 static unsigned rpmlogFacility = RPMLOG_USER;
  144 #endif
  145 
  146 int rpmlogSetMask (int mask)
  147 {
  148     rpmlogCtx ctx = rpmlogCtxAcquire(mask ? 1 : 0);
  149 
  150     int omask = -1;
  151     if (ctx) {
  152     omask = ctx->mask;
  153     if (mask)
  154         ctx->mask = mask;
  155     }
  156 
  157     rpmlogCtxRelease(ctx);
  158     return omask;
  159 }
  160 
  161 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb, rpmlogCallbackData data)
  162 {
  163     rpmlogCtx ctx = rpmlogCtxAcquire(1);
  164 
  165     rpmlogCallback ocb = NULL;
  166     if (ctx) {
  167     ocb = ctx->cbfunc;
  168     ctx->cbfunc = cb;
  169     ctx->cbdata = data;
  170     }
  171 
  172     rpmlogCtxRelease(ctx);
  173     return ocb;
  174 }
  175 
  176 FILE * rpmlogSetFile(FILE * fp)
  177 {
  178     rpmlogCtx ctx = rpmlogCtxAcquire(1);
  179 
  180     FILE * ofp = NULL;
  181     if (ctx) {
  182     ofp = ctx->stdlog;
  183     ctx->stdlog = fp;
  184     }
  185 
  186     rpmlogCtxRelease(ctx);
  187     return ofp;
  188 }
  189 
  190 static const char * const rpmlogMsgPrefix[] = {
  191     N_("fatal error: "),/*!< RPMLOG_EMERG */
  192     N_("fatal error: "),/*!< RPMLOG_ALERT */
  193     N_("fatal error: "),/*!< RPMLOG_CRIT */
  194     N_("error: "),  /*!< RPMLOG_ERR */
  195     N_("warning: "),    /*!< RPMLOG_WARNING */
  196     "",         /*!< RPMLOG_NOTICE */
  197     "",         /*!< RPMLOG_INFO */
  198     "D: ",      /*!< RPMLOG_DEBUG */
  199 };
  200 
  201 #define ANSI_COLOR_BLACK    "\x1b[30m"
  202 #define ANSI_COLOR_RED      "\x1b[31m"
  203 #define ANSI_COLOR_GREEN    "\x1b[32m"
  204 #define ANSI_COLOR_YELLOW   "\x1b[33m"
  205 #define ANSI_COLOR_BLUE     "\x1b[34m"
  206 #define ANSI_COLOR_MAGENTA  "\x1b[35m"
  207 #define ANSI_COLOR_CYAN     "\x1b[36m"
  208 #define ANSI_COLOR_WHITE    "\x1b[37m"
  209 
  210 #define ANSI_BRIGHT_BLACK   "\x1b[30;1m"
  211 #define ANSI_BRIGHT_RED     "\x1b[31;1m"
  212 #define ANSI_BRIGHT_GREEN   "\x1b[32;1m"
  213 #define ANSI_BRIGHT_YELLOW  "\x1b[33;1m"
  214 #define ANSI_BRIGHT_BLUE    "\x1b[34;1m"
  215 #define ANSI_BRIGHT_MAGENTA "\x1b[35;1m"
  216 #define ANSI_BRIGHT_CYAN    "\x1b[36;1m"
  217 #define ANSI_BRIGHT_WHITE   "\x1b[37;1m"
  218 
  219 #define ANSI_COLOR_BOLD     "\x1b[1m"
  220 #define ANSI_COLOR_RESET    "\x1b[0m"
  221 
  222 static const char *rpmlogMsgPrefixColor[] = {
  223     ANSI_BRIGHT_RED,    /*!< RPMLOG_EMERG */
  224     ANSI_BRIGHT_RED,    /*!< RPMLOG_ALERT */
  225     ANSI_BRIGHT_RED,    /*!< RPMLOG_CRIT */
  226     ANSI_BRIGHT_RED,    /*!< RPMLOG_ERR */
  227     ANSI_BRIGHT_MAGENTA,/*!< RPMLOG_WARNING */
  228     "",         /*!< RPMLOG_NOTICE */
  229     "",         /*!< RPMLOG_INFO */
  230     ANSI_BRIGHT_BLUE,   /*!< RPMLOG_DEBUG */
  231 };
  232 
  233 const char * rpmlogLevelPrefix(rpmlogLvl pri)
  234 {
  235     const char * prefix = "";
  236     if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri]) 
  237     prefix = _(rpmlogMsgPrefix[pri]);
  238     return prefix;
  239 }
  240 
  241 static const char * rpmlogLevelColor(rpmlogLvl pri)
  242 {
  243     return rpmlogMsgPrefixColor[pri&0x7];
  244 }
  245 
  246 enum {
  247     COLOR_NO = 0,
  248     COLOR_AUTO = 1,
  249     COLOR_ALWAYS = 2,
  250 };
  251 
  252 static int getColorConfig(void)
  253 {
  254     int rc = COLOR_NO;
  255     char * color = rpmExpand("%{?_color_output}%{!?_color_output:auto}", NULL);
  256     if (rstreq(color, "auto"))
  257     rc = COLOR_AUTO;
  258     else if (rstreq(color, "always"))
  259     rc = COLOR_ALWAYS;
  260     free(color);
  261     return rc;
  262 }
  263 
  264 static void logerror(void)
  265 {
  266     static __thread int lasterr = 0;
  267     if (errno != EPIPE && errno != lasterr) {
  268     lasterr = errno;
  269     perror(_("Error writing to log"));
  270     }
  271 }
  272 
  273 static int rpmlogDefault(FILE *stdlog, rpmlogRec rec)
  274 {
  275     FILE *msgout = (stdlog ? stdlog : stderr);
  276     static __thread int color = -1;
  277     const char * colorOn = NULL;
  278 
  279     if (color < 0)
  280     color = getColorConfig();
  281 
  282     if (color == COLOR_ALWAYS ||
  283         (color == COLOR_AUTO && isatty(fileno(msgout))))
  284     colorOn = rpmlogLevelColor(rec->pri);
  285 
  286     switch (rec->pri) {
  287     case RPMLOG_INFO:
  288     case RPMLOG_NOTICE:
  289     msgout = (stdlog ? stdlog : stdout);
  290     break;
  291     case RPMLOG_EMERG:
  292     case RPMLOG_ALERT:
  293     case RPMLOG_CRIT:
  294     case RPMLOG_ERR:
  295     case RPMLOG_WARNING:
  296     case RPMLOG_DEBUG:
  297     if (colorOn && *colorOn)
  298         if (fputs(rpmlogLevelColor(rec->pri), msgout) == EOF)
  299         logerror();
  300     break;
  301     default:
  302     break;
  303     }
  304 
  305     if (fputs(rpmlogLevelPrefix(rec->pri), msgout) == EOF)
  306     logerror();
  307 
  308     switch (rec->pri) {
  309     case RPMLOG_INFO:
  310     case RPMLOG_NOTICE:
  311     break;
  312     case RPMLOG_EMERG:
  313     case RPMLOG_ALERT:
  314     case RPMLOG_CRIT:
  315     case RPMLOG_ERR:
  316     case RPMLOG_WARNING:
  317     if (colorOn && *colorOn) {
  318         if (fputs(ANSI_COLOR_RESET, msgout) == EOF)
  319         logerror();
  320         if (fputs(ANSI_COLOR_BOLD, msgout) == EOF)
  321         logerror();
  322     }
  323     case RPMLOG_DEBUG:
  324     default:
  325     break;
  326     }
  327 
  328     if (rec->message)
  329     if (fputs(rec->message, msgout) == EOF)
  330         logerror();
  331 
  332     switch (rec->pri) {
  333     case RPMLOG_INFO:
  334     case RPMLOG_NOTICE:
  335     break;
  336     case RPMLOG_EMERG:
  337     case RPMLOG_ALERT:
  338     case RPMLOG_CRIT:
  339     case RPMLOG_ERR:
  340     case RPMLOG_WARNING:
  341     case RPMLOG_DEBUG:
  342     if (colorOn && *colorOn)
  343         if (fputs(ANSI_COLOR_RESET, msgout) == EOF)
  344         logerror();
  345     break;
  346     default:
  347     break;
  348     }
  349 
  350     if (fflush(msgout) == EOF)
  351     logerror();
  352 
  353     return (rec->pri <= RPMLOG_CRIT ? RPMLOG_EXIT : 0);
  354 }
  355 
  356 /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */
  357 /* FIX: rpmlogMsgPrefix[] may be NULL */
  358 static void dolog(struct rpmlogRec_s *rec, int saverec)
  359 {
  360     static pthread_mutex_t serialize = PTHREAD_MUTEX_INITIALIZER;
  361 
  362     int cbrc = RPMLOG_DEFAULT;
  363     int needexit = 0;
  364     FILE *clog = NULL;
  365     rpmlogCallbackData *cbdata = NULL;
  366     rpmlogCallback cbfunc = NULL;
  367     rpmlogCtx ctx = rpmlogCtxAcquire(saverec);
  368 
  369     if (ctx == NULL)
  370     return;
  371 
  372     /* Save copy of all messages at warning (or below == "more important"). */
  373     if (saverec) {
  374     ctx->recs = xrealloc(ctx->recs, (ctx->nrecs+2) * sizeof(*ctx->recs));
  375     ctx->recs[ctx->nrecs].code = rec->code;
  376     ctx->recs[ctx->nrecs].pri = rec->pri;
  377     ctx->recs[ctx->nrecs].message = xstrdup(rec->message);
  378     ctx->recs[ctx->nrecs+1].code = 0;
  379     ctx->recs[ctx->nrecs+1].message = NULL;
  380     ctx->nrecs++;
  381     }
  382     cbfunc = ctx->cbfunc;
  383     cbdata = ctx->cbdata;
  384     clog = ctx->stdlog;
  385 
  386     /* Free the context for callback and actual log output */
  387     ctx = rpmlogCtxRelease(ctx);
  388 
  389     /* Always serialize callback and output to avoid interleaved messages. */
  390     if (pthread_mutex_lock(&serialize) == 0) {
  391     if (cbfunc) {
  392         cbrc = cbfunc(rec, cbdata);
  393         needexit += cbrc & RPMLOG_EXIT;
  394     }
  395 
  396     if (cbrc & RPMLOG_DEFAULT) {
  397         cbrc = rpmlogDefault(clog, rec);
  398         needexit += cbrc & RPMLOG_EXIT;
  399     }
  400     pthread_mutex_unlock(&serialize);
  401     }
  402     
  403     if (needexit)
  404     exit(EXIT_FAILURE);
  405 
  406 }
  407 
  408 void rpmlog (int code, const char *fmt, ...)
  409 {
  410     int saved_errno = errno;
  411     unsigned pri = RPMLOG_PRI(code);
  412     unsigned mask = RPMLOG_MASK(pri);
  413     int saverec = (pri <= RPMLOG_WARNING);
  414     va_list ap;
  415     int n;
  416 
  417     if ((mask & rpmlogSetMask(0)) == 0)
  418     goto exit;
  419 
  420     va_start(ap, fmt);
  421     n = vsnprintf(NULL, 0, fmt, ap);
  422     va_end(ap);
  423 
  424     if (n >= -1) {
  425     struct rpmlogRec_s rec;
  426     size_t nb = n + 1;
  427     char *msg = xmalloc(nb);
  428 
  429     va_start(ap, fmt);
  430     n = vsnprintf(msg, nb, fmt, ap);
  431     va_end(ap);
  432 
  433     rec.code = code;
  434     rec.pri = pri;
  435     rec.message = msg;
  436 
  437     dolog(&rec, saverec);
  438 
  439     free(msg);
  440     }
  441 exit:
  442     errno = saved_errno;
  443 }