]> diplodocus.org Git - nmh/blob - sbr/error.c
Fix invalid pointer arithmetic.
[nmh] / sbr / error.c
1 /* error.c -- main error handling routines
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include <h/mh.h>
9
10 #include <sys/types.h>
11 #include <sys/uio.h>
12 #include "h/done.h"
13
14 /* inform calls advertise() with no what and no tail.
15 * Thus the simple "[invo_name: ]fmt\n" results. */
16 void inform(char *fmt, ...)
17 {
18 va_list ap;
19
20 va_start(ap, fmt);
21 advertise(NULL, NULL, fmt, ap);
22 va_end(ap);
23 }
24
25
26 /* advise calls advertise() with no tail to print fmt, and perhaps what,
27 * to stderr.
28 * Thus "[invo_name: ]fmt[[ what]: errno]\n" results. */
29 void
30 advise (const char *what, const char *fmt, ...)
31 {
32 va_list ap;
33
34 va_start(ap, fmt);
35 advertise (what, NULL, fmt, ap);
36 va_end(ap);
37 }
38
39
40 /* adios is the same as advise(), but then "ends" the program.
41 * It calls advertise() with no tail to print fmt, and perhaps what, to
42 * stderr, and exits the program with an error status.
43 * Thus "[invo_name: ]fmt[[ what]: errno]\n" results.
44 * The route to exit is via the done function pointer and may not be
45 * straightforward, e.g. longjmp(3), but it must not return to adios().
46 * If it does then it's a bug and adios() will abort(3) as callers do
47 * not expect execution to continue. */
48 void NORETURN
49 adios (const char *what, const char *fmt, ...)
50 {
51 va_list ap;
52
53 va_start(ap, fmt);
54 advertise (what, NULL, fmt, ap);
55 va_end(ap);
56 done (1);
57 abort();
58 }
59
60
61 /* die is the same as adios(), but without the what as that's commonly
62 * NULL. */
63 void NORETURN
64 die(const char *fmt, ...)
65 {
66 va_list ap;
67
68 va_start(ap, fmt);
69 advertise(NULL, NULL, fmt, ap);
70 va_end(ap);
71 done(1);
72 abort();
73 }
74
75
76 /* admonish calls advertise() with a tail indicating the program
77 * continues.
78 * Thus "[invo_name: ]fmt[[ what]: errno], continuing...\n" results. */
79 void
80 admonish (char *what, char *fmt, ...)
81 {
82 va_list ap;
83
84 va_start(ap, fmt);
85 advertise (what, "continuing...", fmt, ap);
86 va_end(ap);
87 }
88
89
90 /* advertise prints fmt and ap to stderr after flushing stdout.
91 * If invo_name isn't NULL or empty then "invo_name: " precedes fmt.
92 * If what isn't NULL or empty then " what" is appended.
93 * If what isn't NULL then ": errno" is appended.
94 * If tail isn't NULL or empty then ", tail" is appended.
95 * A "\n" finishes the output to stderr.
96 * In summary: "[invo_name: ]fmt[[ what]: errno][, tail]\n". */
97 void
98 advertise (const char *what, char *tail, const char *fmt, va_list ap)
99 {
100 int eindex = errno;
101 char buffer[NMH_BUFSIZ], *err;
102 struct iovec iob[10], *iov;
103 size_t niov;
104
105 iov = iob;
106
107 #define APPEND_IOV(p, len) \
108 iov->iov_base = (p); \
109 iov->iov_len = (len); \
110 iov++
111
112 #define ADD_LITERAL(s) APPEND_IOV((s), LEN(s))
113 #define ADD_VAR(s) APPEND_IOV((s), strlen(s))
114
115 if (invo_name && *invo_name) {
116 ADD_VAR(invo_name);
117 ADD_LITERAL(": ");
118 }
119
120 vsnprintf (buffer, sizeof(buffer), fmt, ap);
121 ADD_VAR(buffer);
122 if (what) {
123 if (*what) {
124 ADD_LITERAL(" ");
125 ADD_VAR((void *)what);
126 }
127 ADD_LITERAL(": ");
128 err = strerror(eindex);
129 ADD_VAR(err);
130 }
131 if (tail && *tail) {
132 ADD_LITERAL(", ");
133 ADD_VAR(tail);
134 }
135 ADD_LITERAL("\n");
136
137 #undef ADD_LITERAL
138 #undef ADD_VAR
139
140 niov = iov - iob;
141 assert(niov <= DIM(iob));
142
143 fflush (stdout);
144 fflush (stderr);
145 if (writev(fileno(stderr), iob, niov) == -1) {
146 snprintf(buffer, sizeof buffer, "%s: write stderr failed: %d\n",
147 invo_name && *invo_name ? invo_name : "nmh", errno);
148 if (write(2, buffer, strlen(buffer)) == -1) {
149 /* Ignore. if-statement needed to shut up compiler. */
150 }
151 }
152 }