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