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