7dbc911718e14f80cf4c551ef9c8c126fbdaf2c6
[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 static int nrecs = 0;
11 static rpmlogRec recs = NULL;
12
13 struct rpmlogRec_s {
14     int         code;           /* unused */
15     rpmlogLvl   pri;            /* priority */ 
16     const char * message;       /* log message string */
17 };
18
19 int rpmlogGetNrecs(void)
20 {
21     return nrecs;
22 }
23
24 int rpmlogCode(void)
25 {
26     if (recs != NULL && nrecs > 0)
27         return recs[nrecs-1].code;
28     return -1;
29 }
30
31
32 const char * rpmlogMessage(void)
33 {
34     if (recs != NULL && nrecs > 0)
35         return recs[nrecs-1].message;
36     return _("(no error)");
37 }
38
39 void rpmlogPrint(FILE *f)
40 {
41     int i;
42
43     if (f == NULL)
44         f = stderr;
45
46     if (recs)
47     for (i = 0; i < nrecs; i++) {
48         rpmlogRec rec = recs + i;
49         if (rec->message && *rec->message)
50             fprintf(f, "    %s", rec->message);
51     }
52 }
53
54 void rpmlogClose (void)
55 {
56     int i;
57
58     if (recs)
59     for (i = 0; i < nrecs; i++) {
60         rpmlogRec rec = recs + i;
61         rec->message = _free(rec->message);
62     }
63     recs = _free(recs);
64     nrecs = 0;
65 }
66
67 void rpmlogOpen (const char *ident, int option,
68                 int facility)
69 {
70 }
71
72 static unsigned rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
73
74 #ifdef NOTYET
75 static unsigned rpmlogFacility = RPMLOG_USER;
76 #endif
77
78 int rpmlogSetMask (int mask)
79 {
80     int omask = rpmlogMask;
81     if (mask)
82         rpmlogMask = mask;
83     return omask;
84 }
85
86 static rpmlogCallback _rpmlogCallback = NULL;
87 static rpmlogCallbackData _rpmlogCallbackData = NULL;
88
89 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb, rpmlogCallbackData data)
90 {
91     rpmlogCallback ocb = _rpmlogCallback;
92     _rpmlogCallback = cb;
93     _rpmlogCallbackData = data;
94     return ocb;
95 }
96
97 static FILE * _stdlog = NULL;
98
99 static int rpmlogDefault(rpmlogRec rec)
100 {
101     FILE *msgout = (_stdlog ? _stdlog : stderr);
102
103     switch (rec->pri) {
104     case RPMLOG_INFO:
105     case RPMLOG_NOTICE:
106         msgout = (_stdlog ? _stdlog : stdout);
107         break;
108     case RPMLOG_EMERG:
109     case RPMLOG_ALERT:
110     case RPMLOG_CRIT:
111     case RPMLOG_ERR:
112     case RPMLOG_WARNING:
113     case RPMLOG_DEBUG:
114     default:
115         break;
116     }
117
118     (void) fputs(rpmlogLevelPrefix(rec->pri), msgout);
119
120     (void) fputs(rec->message, msgout);
121     (void) fflush(msgout);
122
123     return (rec->pri <= RPMLOG_CRIT ? RPMLOG_EXIT : 0);
124 }
125
126
127 FILE * rpmlogSetFile(FILE * fp)
128 {
129     FILE * ofp = _stdlog;
130     _stdlog = fp;
131     return ofp;
132 }
133
134 static const char *rpmlogMsgPrefix[] = {
135     N_("fatal error: "),/*!< RPMLOG_EMERG */
136     N_("fatal error: "),/*!< RPMLOG_ALERT */
137     N_("fatal error: "),/*!< RPMLOG_CRIT */
138     N_("error: "),      /*!< RPMLOG_ERR */
139     N_("warning: "),    /*!< RPMLOG_WARNING */
140     "",                 /*!< RPMLOG_NOTICE */
141     "",                 /*!< RPMLOG_INFO */
142     "D: ",              /*!< RPMLOG_DEBUG */
143 };
144
145 const char * rpmlogLevelPrefix(rpmlogLvl pri)
146 {
147     const char * prefix = "";
148     if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri]) 
149         prefix = _(rpmlogMsgPrefix[pri]);
150     return prefix;
151 }
152
153 #if !defined(HAVE_VSNPRINTF)
154 static inline int vsnprintf(char * buf, int nb,
155         const char * fmt, va_list ap)
156 {
157     return vsprintf(buf, fmt, ap);
158 }
159 #endif
160
161 /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */
162 /* FIX: rpmlogMsgPrefix[] may be NULL */
163 static void vrpmlog (unsigned code, const char *fmt, va_list ap)
164 {
165     unsigned pri = RPMLOG_PRI(code);
166     unsigned mask = RPMLOG_MASK(pri);
167 #ifdef NOTYET
168     unsigned fac = RPMLOG_FAC(code);
169 #endif
170     char *msgbuf, *msg;
171     int msgnb = BUFSIZ, nb;
172     int cbrc = RPMLOG_DEFAULT;
173     int needexit = 0;
174     struct rpmlogRec_s rec;
175
176     if ((mask & rpmlogMask) == 0)
177         return;
178
179     msgbuf = xmalloc(msgnb);
180     *msgbuf = '\0';
181
182     /* Allocate a sufficently large buffer for output. */
183     while (1) {
184         va_list apc;
185         va_copy(apc, ap);
186         nb = vsnprintf(msgbuf, msgnb, fmt, apc);
187         if (nb > -1 && nb < msgnb)
188             break;
189         if (nb > -1)            /* glibc 2.1 (and later) */
190             msgnb = nb+1;
191         else                    /* glibc 2.0 */
192             msgnb *= 2;
193         msgbuf = xrealloc(msgbuf, msgnb);
194         va_end(apc);
195     }
196     msgbuf[msgnb - 1] = '\0';
197     msg = msgbuf;
198
199     rec.code = code;
200     rec.message = msg;
201     rec.pri = pri;
202
203     /* Save copy of all messages at warning (or below == "more important"). */
204     if (pri <= RPMLOG_WARNING) {
205
206         if (recs == NULL)
207             recs = xmalloc((nrecs+2) * sizeof(*recs));
208         else
209             recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
210         recs[nrecs].code = rec.code;
211         recs[nrecs].pri = rec.pri;
212         recs[nrecs].message = msg = xrealloc(msgbuf, strlen(msgbuf)+1);
213         msgbuf = NULL;          /* XXX don't free at exit. */
214         recs[nrecs+1].code = 0;
215         recs[nrecs+1].message = NULL;
216         ++nrecs;
217     }
218
219     if (_rpmlogCallback) {
220         cbrc = _rpmlogCallback(&rec, _rpmlogCallbackData);
221         needexit += cbrc & RPMLOG_EXIT;
222     }
223
224     if (cbrc & RPMLOG_DEFAULT) {
225         cbrc = rpmlogDefault(&rec);
226         needexit += cbrc & RPMLOG_EXIT;
227     }
228     
229     msgbuf = _free(msgbuf);
230     if (needexit)
231         exit(EXIT_FAILURE);
232 }
233
234 void rpmlog (int code, const char *fmt, ...)
235 {
236     va_list ap;
237
238     va_start(ap, fmt);
239     /* FIX: shrug */
240     vrpmlog(code, fmt, ap);
241     va_end(ap);
242 }
243