Merge changes from rpm-4.0.2.
[platform/upstream/rpm.git] / rpmio / rpmlog.c
1 /** \ingroup rpmio
2  * \file rpmio/rpmlog.c
3  */
4
5 #include "system.h"
6 #include <stdarg.h>
7 #include "rpmlog.h"
8 #include "debug.h"
9
10 /*@access rpmlogRec @*/
11
12 static int nrecs = 0;
13 static /*@only@*/ /*@null@*/ rpmlogRec recs = NULL;
14
15 int rpmlogGetNrecs(void)
16 {
17     return nrecs;
18 }
19
20 int rpmlogCode(void)
21 {
22     if (nrecs > 0)
23         return recs[nrecs-1].code;
24     return -1;
25 }
26
27
28 const char * rpmlogMessage(void)
29 {
30     if (nrecs > 0)
31         return recs[nrecs-1].message;
32     return _("(no error)");
33 }
34
35 void rpmlogPrint(FILE *f)
36 {
37     int i;
38
39     if (f == NULL)
40         f = stderr;
41
42     for (i = 0; i < nrecs; i++) {
43         rpmlogRec rec = recs + i;
44         if (rec->message && *rec->message)
45             fprintf(f, "    %s", rec->message);
46     }
47 }
48
49 void rpmlogClose (void)
50 {
51     int i;
52
53     for (i = 0; i < nrecs; i++) {
54         rpmlogRec rec = recs + i;
55         if (rec->message) {
56             free((void *)rec->message);
57             rec->message = NULL;
58         }
59     }
60     free(recs);
61     recs = NULL;
62     nrecs = 0;
63 }
64
65 void rpmlogOpen (/*@unused@*/ const char *ident, /*@unused@*/ int option,
66                 /*@unused@*/ int facility)
67 {
68 }
69
70 static int rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
71 static /*@unused@*/ int rpmlogFacility = RPMLOG_USER;
72
73 int rpmlogSetMask (int mask)
74 {
75     int omask = rpmlogMask;
76     if (mask)
77         rpmlogMask = mask;
78     return omask;
79 }
80
81 static /*@null@*/ rpmlogCallback _rpmlogCallback = NULL;
82
83 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb)
84 {
85     rpmlogCallback ocb = _rpmlogCallback;
86     _rpmlogCallback = cb;
87     return ocb;
88 }
89
90 static char *rpmlogMsgPrefix[] = {
91     N_("fatal error: "),/*!< RPMLOG_EMERG */
92     N_("fatal error: "),/*!< RPMLOG_ALERT */
93     N_("fatal error: "),/*!< RPMLOG_CRIT */
94     N_("error: "),      /*!< RPMLOG_ERR */
95     N_("warning: "),    /*!< RPMLOG_WARNING */
96     "",                 /*!< RPMLOG_NOTICE */
97     "",                 /*!< RPMLOG_INFO */
98     "D: ",              /*!< RPMLOG_DEBUG */
99 };
100
101 static void vrpmlog (unsigned code, const char *fmt, va_list ap)
102 {
103     int pri = RPMLOG_PRI(code);
104     int mask = RPMLOG_MASK(pri);
105     /*@unused@*/ int fac = RPMLOG_FAC(code);
106     char *msgbuf, *msg;
107     int msgnb = BUFSIZ, nb;
108     FILE * msgout = stderr;
109     rpmlogRec rec;
110
111     if ((mask & rpmlogMask) == 0)
112         return;
113
114     msgbuf = xmalloc(msgnb);
115     *msgbuf = '\0';
116
117     /* Allocate a sufficently large buffer for output. */
118     while (1) {
119         /*@-unrecog@*/
120         nb = vsnprintf(msgbuf, msgnb, fmt, ap);
121         /*@=unrecog@*/
122         if (nb > -1 && nb < msgnb)
123             break;
124         if (nb > -1)            /* glibc 2.1 */
125             msgnb = nb+1;
126         else                    /* glibc 2.0 */
127             msgnb *= 2;
128         msgbuf = xrealloc(msgbuf, msgnb);
129     }
130     msgbuf[msgnb - 1] = '\0';
131     msg = msgbuf;
132
133     /* Save copy of all messages at warning (or below == "more important"). */
134     if (pri <= RPMLOG_WARNING) {
135
136         if (recs == NULL)
137             recs = xmalloc((nrecs+2) * sizeof(*recs));
138         else
139             recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
140         recs[nrecs+1].code = 0;
141         recs[nrecs+1].message = NULL;
142         rec = recs + nrecs;
143         ++nrecs;
144
145         rec->code = code;
146         rec->message = msgbuf;
147         msgbuf = NULL;
148
149         if (_rpmlogCallback) {
150             _rpmlogCallback();
151             if (msgbuf)
152                 free(msgbuf);
153             return;     /* XXX Preserve legacy rpmError behavior. */
154         }
155     }
156
157     /* rpmMessage behavior */
158
159     switch (pri) {
160     case RPMLOG_INFO:
161     case RPMLOG_NOTICE:
162         msgout = stdout;
163         break;
164
165     case RPMLOG_EMERG:
166     case RPMLOG_ALERT:
167     case RPMLOG_CRIT:
168     case RPMLOG_ERR: /* XXX Legacy rpmError behavior used stdout w/o prefix. */
169     case RPMLOG_WARNING:
170     case RPMLOG_DEBUG:
171         break;
172     }
173
174     /* Silly FORTRAN-like carriage control. */
175     if (*msg == '+')
176         msg++;
177     else if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri])
178         fputs(_(rpmlogMsgPrefix[pri]), msgout);
179
180     fputs(msg, msgout);
181     fflush(msgout);
182     if (msgbuf)
183         free(msgbuf);
184     if (pri <= RPMLOG_CRIT)
185         exit(EXIT_FAILURE);
186 }
187
188 void rpmlog (int code, const char *fmt, ...)
189 {
190     va_list ap;
191
192     va_start(ap, fmt);
193     vrpmlog(code, fmt, ap);
194     va_end(ap);
195 }
196
197 int rpmErrorCode(void)
198 {
199     return rpmlogCode();
200 }
201
202 const char * rpmErrorString(void)
203 {
204     return rpmlogMessage();
205 }
206
207 rpmlogCallback rpmErrorSetCallback(rpmlogCallback cb)
208 {
209     return rpmlogSetCallback(cb);
210 }