Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / comerr / error_msg.c
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
31 static char buffer[64];
32
33 static 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
44 static pthread_mutex_t et_list_mutex;
45 static int et_list_done = 0;
46 static pthread_once_t et_list_once = PTHREAD_ONCE_INIT;
47
48 /*
49 * Function to initialize the et_list_mutex
50 */
51
52 static void
53 et_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
72 static 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
87 static char *
88 negative_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
107 static char *
108 volume_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
117 static_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
151 static_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
169 static const char *
170 afs_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
239 const char *
240 afs_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
245 const char *
246 afs_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
251 const char *
252 afs_com_right(struct et_list *list, long code)
253 {
254 return afs_error_message_int(list, (afs_int32)code, (char *)0, 0);
255 }
256
257 const char *
258 afs_error_message(afs_int32 code)
259 {
260 return afs_error_message_int((struct et_list *)0, code, (char *)0, 0);
261 }
262
263 void
264 afs_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 }