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