- fix: clean relocation path for --prefix=/.
[platform/upstream/rpm.git] / rpmio / rpmlog.c
1 /*@-boundsread@*/
2 /** \ingroup rpmio
3  * \file rpmio/rpmlog.c
4  */
5
6 #include "system.h"
7 #include <stdarg.h>
8 #include "rpmlog.h"
9 #include "debug.h"
10
11 #ifndef va_copy
12 # ifdef __va_copy
13 #  define va_copy(DEST,SRC) __va_copy((DEST),(SRC))
14 # else
15 #  ifdef HAVE_VA_LIST_AS_ARRAY
16 #   define va_copy(DEST,SRC) (*(DEST) = *(SRC))
17 #  else
18 #   define va_copy(DEST,SRC) ((DEST) = (SRC))
19 #  endif
20 # endif
21 #endif
22
23 /*@access rpmlogRec @*/
24
25 /*@unchecked@*/
26 static int nrecs = 0;
27 /*@unchecked@*/
28 static /*@only@*/ /*@null@*/ rpmlogRec recs = NULL;
29
30 /**
31  * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
32  * @param p             memory to free
33  * @retval              NULL always
34  */
35 /*@unused@*/ static inline /*@null@*/ void *
36 _free(/*@only@*/ /*@null@*/ /*@out@*/ const void * p) /*@modifies p@*/
37 {
38     if (p != NULL)      free((void *)p);
39     return NULL;
40 }
41
42 int rpmlogGetNrecs(void)
43 {
44     return nrecs;
45 }
46
47 int rpmlogCode(void)
48 {
49     if (recs != NULL && nrecs > 0)
50         return recs[nrecs-1].code;
51     return -1;
52 }
53
54
55 const char * rpmlogMessage(void)
56 {
57     if (recs != NULL && nrecs > 0)
58         return recs[nrecs-1].message;
59     return _("(no error)");
60 }
61
62 /*@-modfilesys@*/
63 void rpmlogPrint(FILE *f)
64 {
65     int i;
66
67     if (f == NULL)
68         f = stderr;
69
70     if (recs)
71     for (i = 0; i < nrecs; i++) {
72         rpmlogRec rec = recs + i;
73         if (rec->message && *rec->message)
74             fprintf(f, "    %s", rec->message);
75     }
76 }
77 /*@=modfilesys@*/
78
79 void rpmlogClose (void)
80         /*@globals recs, nrecs @*/
81         /*@modifies recs, nrecs @*/
82 {
83     int i;
84
85     if (recs)
86     for (i = 0; i < nrecs; i++) {
87         rpmlogRec rec = recs + i;
88         rec->message = _free(rec->message);
89     }
90     recs = _free(recs);
91     nrecs = 0;
92 }
93
94 void rpmlogOpen (/*@unused@*/ const char *ident, /*@unused@*/ int option,
95                 /*@unused@*/ int facility)
96 {
97 }
98
99 /*@unchecked@*/
100 static unsigned rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
101
102 /*@unchecked@*/
103 static /*@unused@*/ unsigned rpmlogFacility = RPMLOG_USER;
104
105 int rpmlogSetMask (int mask)
106         /*@globals rpmlogMask @*/
107         /*@modifies rpmlogMask @*/
108 {
109     int omask = rpmlogMask;
110     if (mask)
111         rpmlogMask = mask;
112     return omask;
113 }
114
115 /*@unchecked@*/
116 static /*@null@*/ rpmlogCallback _rpmlogCallback = NULL;
117
118 rpmlogCallback rpmlogSetCallback(rpmlogCallback cb)
119         /*@globals _rpmlogCallback @*/
120         /*@modifies _rpmlogCallback @*/
121 {
122     rpmlogCallback ocb = _rpmlogCallback;
123     _rpmlogCallback = cb;
124     return ocb;
125 }
126
127 /*@unchecked@*/ /*@null@*/
128 static FILE * _stdlog = NULL;
129
130 FILE * rpmlogSetFile(FILE * fp)
131         /*@globals _stdlog @*/
132         /*@modifies _stdlog @*/
133 {
134     FILE * ofp = _stdlog;
135     _stdlog = fp;
136     return ofp;
137 }
138
139 /*@-readonlytrans@*/    /* FIX: double indirection. */
140 /*@observer@*/ /*@unchecked@*/
141 static char *rpmlogMsgPrefix[] = {
142     N_("fatal error: "),/*!< RPMLOG_EMERG */
143     N_("fatal error: "),/*!< RPMLOG_ALERT */
144     N_("fatal error: "),/*!< RPMLOG_CRIT */
145     N_("error: "),      /*!< RPMLOG_ERR */
146     N_("warning: "),    /*!< RPMLOG_WARNING */
147     "",                 /*!< RPMLOG_NOTICE */
148     "",                 /*!< RPMLOG_INFO */
149     "D: ",              /*!< RPMLOG_DEBUG */
150 };
151 /*@=readonlytrans@*/
152
153 #if !defined(HAVE_VSNPRINTF)
154 static inline int vsnprintf(char * buf, /*@unused@*/ int nb,
155         const char * fmt, va_list ap)
156 {
157     return vsprintf(buf, fmt, ap);
158 }
159 #endif
160
161 /*@-modfilesys@*/
162 /*@-compmempass@*/ /* FIX: rpmlogMsgPrefix[] dependent, not unqualified */
163 /*@-nullstate@*/ /* FIX: rpmlogMsgPrefix[] may be NULL */
164 static void vrpmlog (unsigned code, const char *fmt, va_list ap)
165         /*@globals nrecs, recs, internalState @*/
166         /*@modifies nrecs, recs, internalState @*/
167 {
168     unsigned pri = RPMLOG_PRI(code);
169     unsigned mask = RPMLOG_MASK(pri);
170     /*@unused@*/ unsigned fac = RPMLOG_FAC(code);
171     char *msgbuf, *msg;
172     int msgnb = BUFSIZ, nb;
173     FILE * msgout = (_stdlog ? _stdlog : stderr);
174
175     if ((mask & rpmlogMask) == 0)
176         return;
177
178 /*@-boundswrite@*/
179     msgbuf = xmalloc(msgnb);
180     *msgbuf = '\0';
181
182     /* Allocate a sufficently large buffer for output. */
183     while (1) {
184         va_list apc;
185         /*@-sysunrecog -usedef@*/ va_copy(apc, ap); /*@=sysunrecog =usedef@*/
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 /*@-mods@*/
195         va_end(apc);
196 /*@=mods@*/
197     }
198     msgbuf[msgnb - 1] = '\0';
199     msg = msgbuf;
200
201     /* Save copy of all messages at warning (or below == "more important"). */
202     /*@-branchstate@*/
203     if (pri <= RPMLOG_WARNING) {
204
205         if (recs == NULL)
206             recs = xmalloc((nrecs+2) * sizeof(*recs));
207         else
208             recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
209         recs[nrecs].code = code;
210         recs[nrecs].message = msg = xrealloc(msgbuf, strlen(msgbuf)+1);
211         msgbuf = NULL;          /* XXX don't free at exit. */
212         recs[nrecs+1].code = 0;
213         recs[nrecs+1].message = NULL;
214         ++nrecs;
215
216         if (_rpmlogCallback) {
217             /*@-noeffectuncon@*/ /* FIX: useless callback */
218             _rpmlogCallback();
219             /*@=noeffectuncon@*/
220             return;     /* XXX Preserve legacy rpmError behavior. */
221         }
222     }
223     /*@=branchstate@*/
224 /*@=boundswrite@*/
225
226     /* rpmMessage behavior */
227
228     switch (pri) {
229     case RPMLOG_INFO:
230     case RPMLOG_NOTICE:
231         msgout = (_stdlog ? _stdlog : stdout);
232         break;
233
234     case RPMLOG_EMERG:
235     case RPMLOG_ALERT:
236     case RPMLOG_CRIT:
237     case RPMLOG_ERR: /* XXX Legacy rpmError behavior used stdout w/o prefix. */
238     case RPMLOG_WARNING:
239     case RPMLOG_DEBUG:
240         break;
241     }
242
243     if (rpmlogMsgPrefix[pri] && *rpmlogMsgPrefix[pri])
244         (void) fputs(_(rpmlogMsgPrefix[pri]), msgout);
245
246     (void) fputs(msg, msgout);
247     (void) fflush(msgout);
248     msgbuf = _free(msgbuf);
249     if (pri <= RPMLOG_CRIT)
250         exit(EXIT_FAILURE);
251 }
252 /*@=compmempass =nullstate@*/
253 /*@=modfilesys@*/
254
255 void rpmlog (int code, const char *fmt, ...)
256 {
257     va_list ap;
258
259     va_start(ap, fmt);
260     /*@-internalglobs@*/ /* FIX: shrug */
261     vrpmlog(code, fmt, ap);
262     /*@=internalglobs@*/
263     va_end(ap);
264 }
265
266 int rpmErrorCode(void)
267 {
268     return rpmlogCode();
269 }
270
271 const char * rpmErrorString(void)
272 {
273     return rpmlogMessage();
274 }
275
276 rpmlogCallback rpmErrorSetCallback(rpmlogCallback cb)
277 {
278     return rpmlogSetCallback(cb);
279 }
280 /*@=boundsread@*/