Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / comerr / error_msg.c
CommitLineData
805e021f
CE
1/*
2 * $Locker$
3 *
4 * Copyright 1987 by the Student Information Processing Board
5 * of the Massachusetts Institute of Technology
6 *
7 * For copyright info, see "mit-sipb-cr.h".
8 */
9
10#include <afsconfig.h>
11#include <afs/param.h>
12
13#include <roken.h>
14
15#ifdef HAVE_LIBINTL
16#include <libintl.h>
17#endif
18#ifdef AFS_DARWIN_ENV
19#include <CoreFoundation/CoreFoundation.h>
20#endif
21
22#include <afs/opr.h>
23#include <afs/errors.h>
24#include <afs/afsutil.h>
25
26#include "internal.h"
27#include "error_table.h"
28#include "mit-sipb-cr.h"
29#include "com_err.h"
30
31static char buffer[64];
32
33static struct et_list *_et_list = NULL;
34
35#ifdef AFS_PTHREAD_ENV
36#include <pthread.h>
37#include <assert.h>
38
39/*
40 * This mutex protects the following variables:
41 * _et_list
42 */
43
44static pthread_mutex_t et_list_mutex;
45static int et_list_done = 0;
46static pthread_once_t et_list_once = PTHREAD_ONCE_INIT;
47
48/*
49 * Function to initialize the et_list_mutex
50 */
51
52static void
53et_mutex_once(void)
54{
55 opr_Verify(!pthread_mutex_init(&et_list_mutex, NULL));
56 et_list_done = 1;
57}
58
59#define LOCK_ET_LIST \
60 do { \
61 if (!et_list_done) \
62 pthread_once(&et_list_once, et_mutex_once); \
63 opr_Verify(pthread_mutex_lock(&et_list_mutex)==0); \
64 } while (0)
65#define UNLOCK_ET_LIST opr_Verify(pthread_mutex_unlock(&et_list_mutex)==0)
66#else
67#define LOCK_ET_LIST
68#define UNLOCK_ET_LIST
69#endif /* AFS_PTHREAD_ENV */
70
71
72static char *vmsgs[] = {
73 "volume needs to be salvaged", /* 101, in Pittsburghese */
74 "no such entry (vnode)", /* 102 */
75 "volume does not exist / did not salvage", /* 103 */
76 "volume already exists", /* 104 */
77 "volume out of service", /* 105 */
78 "volume offline (utility running)", /* 106 */
79 "volume already online", /* 107 */
80 "unknown volume error 108", /* 108 */
81 "unknown volume error 109", /* 109 */
82 "volume temporarily busy", /* 110 */
83 "volume moved", /* 111 */
84 (char *)0
85};
86
87static char *
88negative_message(int code)
89{
90 if (code == -1)
91 return "server or network not responding";
92 else if (code == -2)
93 return "invalid RPC (RX) operation";
94 else if (code == -3)
95 return "server not responding promptly";
96 else if (code == -7)
97 return "port address already in use";
98 else if (code <= -450 && code > -500) {
99 sprintf(buffer, "RPC interface mismatch (%d)", code);
100 return buffer;
101 } else {
102 sprintf(buffer, "unknown RPC error (%d)", code);
103 return buffer;
104 }
105}
106
107static char *
108volume_message(int code)
109{
110 if (code >= 101 && code <= 111)
111 return vmsgs[code - 101];
112 else
113 return "unknown volume error";
114}
115
116#ifdef AFS_DARWIN_ENV
117static_inline const char *
118_intlize(const char *msg, int base, char *str, size_t len)
119{
120 char domain[12 +20];
121 CFStringRef cfstring = CFStringCreateWithCString(kCFAllocatorSystemDefault,
122 msg,
123 kCFStringEncodingUTF8);
124 CFStringRef cfdomain;
125 CFBundleRef OpenAFSBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.openafs.filesystems.afs"));
126
127 if (!str) {
128 CFRelease(cfstring);
129 return msg;
130 }
131
132 snprintf(domain, sizeof(domain), "heim_com_err%d", base);
133 cfdomain = CFStringCreateWithCString(kCFAllocatorSystemDefault, domain,
134 kCFStringEncodingUTF8);
135 if (OpenAFSBundle != NULL) {
136 CFStringRef cflocal;
137
138 cflocal = CFBundleCopyLocalizedString(OpenAFSBundle, cfstring,
139 cfstring, cfdomain);
140 CFStringGetCString(cflocal, str, len, kCFStringEncodingUTF8);
141 CFRelease(cflocal);
142 } else {
143 CFStringGetCString(cfstring, str, len, kCFStringEncodingUTF8);
144 }
145
146 CFRelease(cfstring);
147 CFRelease(cfdomain);
148 return str;
149}
150#else
151static_inline const char *
152_intlize(const char *msg, int base, char *str, size_t len)
153{
154#if defined(HAVE_LIBINTL)
155 char domain[12 +20];
156#endif
157 if (!str)
158 return msg;
159#if defined(HAVE_LIBINTL)
160 snprintf(domain, sizeof(domain), "heim_com_err%d", base);
161 strlcpy(str, dgettext(domain, msg), len);
162#else
163 strlcpy(str, msg, len);
164#endif
165 return str;
166}
167#endif
168
169static const char *
170afs_error_message_int(struct et_list *list, afs_int32 code, char *str, size_t len)
171{
172 int offset;
173 struct et_list *et;
174 int table_num, unlock = 0;
175 int started = 0;
176 char *cp;
177 const char *err_msg;
178
179 /* check for rpc errors first */
180 if (code < 0)
181 return _intlize(negative_message(code), -1, str, len);
182
183 offset = code & ((1 << ERRCODE_RANGE) - 1);
184 table_num = code - offset;
185 if (!table_num) {
186 if ((err_msg = strerror(offset)) != NULL)
187 return _intlize(err_msg, 0, str, len);
188 else if (offset < 140)
189 return _intlize(volume_message(code), 0, str, len);
190 else
191 goto oops;
192 }
193 if (list) {
194 et = list;
195 } else {
196 LOCK_ET_LIST;
197 unlock = 1;
198 et = _et_list;
199 }
200 for (; et; et = et->next) {
201 if (et->table->base == table_num) {
202 /* This is the right table */
203 if (et->table->n_msgs <= offset)
204 goto oops;
205 err_msg = _intlize(et->table->msgs[offset], et->table->base,
206 str, len);
207 if (unlock)
208 UNLOCK_ET_LIST;
209 return err_msg;
210 }
211 }
212 oops:
213 if (unlock)
214 UNLOCK_ET_LIST;
215 /* Unknown code can be included in the negative errors catalog */
216 _intlize("Unknown code ", -1, buffer, sizeof buffer);
217 if (table_num) {
218 strlcat(buffer, afs_error_table_name(table_num), sizeof buffer);
219 strlcat(buffer, " ", sizeof buffer);
220 }
221 for (cp = buffer; *cp; cp++);
222 if (offset >= 100) {
223 *cp++ = '0' + offset / 100;
224 offset %= 100;
225 started++;
226 }
227 if (started || offset >= 10) {
228 *cp++ = '0' + offset / 10;
229 offset %= 10;
230 }
231 *cp++ = '0' + offset;
232 if (code > -10000)
233 sprintf(cp, " (%d)", code);
234 else
235 *cp = '\0';
236 return (buffer);
237}
238
239const char *
240afs_error_message_localize(afs_int32 code, char *str, size_t len)
241{
242 return afs_error_message_int((struct et_list *)0, code, str, len);
243}
244
245const char *
246afs_com_right_r(struct et_list *list, long code, char *str, size_t len)
247{
248 return afs_error_message_int(list, (afs_int32)code, str, len);
249}
250
251const char *
252afs_com_right(struct et_list *list, long code)
253{
254 return afs_error_message_int(list, (afs_int32)code, (char *)0, 0);
255}
256
257const char *
258afs_error_message(afs_int32 code)
259{
260 return afs_error_message_int((struct et_list *)0, code, (char *)0, 0);
261}
262
263void
264afs_add_to_error_table(struct et_list *new_table)
265{
266 struct et_list *et;
267
268 LOCK_ET_LIST;
269 /*
270 * Protect against adding the same error table twice
271 */
272 for (et = _et_list; et; et = et->next) {
273 if (et->table->base == new_table->table->base) {
274 UNLOCK_ET_LIST;
275 return;
276 }
277 }
278
279 new_table->next = _et_list;
280 _et_list = new_table;
281 UNLOCK_ET_LIST;
282}