afa0c971fc280428293a776a7e3133c77c184bbe
[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
14 #include "internal.h"
15 #include <stdio.h>
16 #include "error_table.h"
17 #include "mit-sipb-cr.h"
18 #include <afs/errors.h>
19 #include <afs/afsutil.h>
20 #include <string.h>
21 #include "com_err.h"
22
23 static const char copyright[] =
24     "Copyright 1986, 1987, 1988 by the Student Information Processing Board\nand the department of Information Systems\nof the Massachusetts Institute of Technology";
25
26 static char buffer[64];
27
28 static struct et_list *_et_list = (struct et_list *)NULL;
29
30 #ifdef AFS_PTHREAD_ENV
31 #include <pthread.h>
32 #include <assert.h>
33
34 /*
35  * This mutex protects the following variables:
36  * _et_list
37  */
38
39 static pthread_mutex_t et_list_mutex;
40 static int et_list_done = 0;
41 static pthread_once_t et_list_once = PTHREAD_ONCE_INIT;
42
43 /*
44  * Function to initialize the et_list_mutex
45  */
46
47 static void
48 et_mutex_once(void)
49 {
50     assert(!pthread_mutex_init
51            (&et_list_mutex, (const pthread_mutexattr_t *)0));
52     et_list_done = 1;
53 }
54
55 #define LOCK_ET_LIST \
56         do { \
57             if (!et_list_done) \
58                 pthread_once(&et_list_once, et_mutex_once); \
59             assert(pthread_mutex_lock(&et_list_mutex)==0); \
60         } while (0)
61 #define UNLOCK_ET_LIST assert(pthread_mutex_unlock(&et_list_mutex)==0)
62 #else
63 #define LOCK_ET_LIST
64 #define UNLOCK_ET_LIST
65 #endif /* AFS_PTHREAD_ENV */
66
67
68 static char *vmsgs[] = {
69     "volume needs to be salvaged",      /* 101, in Pittsburghese */
70     "no such entry (vnode)",    /* 102 */
71     "volume does not exist / did not salvage",  /* 103 */
72     "volume already exists",    /* 104 */
73     "volume out of service",    /* 105 */
74     "volume offline (utility running)", /* 106 */
75     "volume already online",    /* 107 */
76     "unknown volume error 108", /* 108 */
77     "unknown volume error 109", /* 109 */
78     "volume temporarily busy",  /* 110 */
79     "volume moved",             /* 111 */
80     (char *)0
81 };
82
83 static char *
84 negative_message(int code)
85 {
86     if (code == -1)
87         return "server or network not responding";
88     else if (code == -2)
89         return "invalid RPC (RX) operation";
90     else if (code == -3)
91         return "server not responding promptly";
92     else if (code == -7)
93         return "port address already in use";
94     else if (code <= -450 && code > -500) {
95         sprintf(buffer, "RPC interface mismatch (%d)", code);
96         return buffer;
97     } else {
98         sprintf(buffer, "unknown RPC error (%d)", code);
99         return buffer;
100     }
101 }
102
103 static char *
104 volume_message(int code)
105 {
106     if (code >= 101 && code <= 111)
107         return vmsgs[code - 101];
108     else
109         return "unknown volume error";
110 }
111
112 const char *
113 afs_error_message(afs_int32 code)
114 {
115     int offset;
116     struct et_list *et;
117     int table_num;
118     int started = 0;
119     char *cp;
120     char *err_msg;
121
122     /* check for rpc errors first */
123     if (code < 0)
124         return negative_message(code);
125
126     offset = code & ((1 << ERRCODE_RANGE) - 1);
127     table_num = code - offset;
128     if (!table_num) {
129         if ((err_msg = strerror(offset)) != NULL)
130             return (err_msg);
131         else if (offset < 140)
132             return volume_message(code);
133         else
134             goto oops;
135     }
136     LOCK_ET_LIST;
137     for (et = _et_list; et; et = et->next) {
138         if (et->table->base == table_num) {
139             /* This is the right table */
140             if (et->table->n_msgs <= offset)
141                 goto oops;
142             UNLOCK_ET_LIST;
143             return (et->table->msgs[offset]);
144         }
145     }
146   oops:
147     UNLOCK_ET_LIST;
148     strlcpy(buffer, "Unknown code ", sizeof buffer);
149     if (table_num) {
150         strlcat(buffer, afs_error_table_name(table_num), sizeof buffer);
151         strlcat(buffer, " ", sizeof buffer);
152     }
153     for (cp = buffer; *cp; cp++);
154     if (offset >= 100) {
155         *cp++ = '0' + offset / 100;
156         offset %= 100;
157         started++;
158     }
159     if (started || offset >= 10) {
160         *cp++ = '0' + offset / 10;
161         offset %= 10;
162     }
163     *cp++ = '0' + offset;
164     if (code > -10000)
165         sprintf(cp, " (%d)", code);
166     else
167         *cp = '\0';
168     return (buffer);
169 }
170
171 void
172 afs_add_to_error_table(struct et_list *new_table)
173 {
174     struct et_list *et;
175
176     LOCK_ET_LIST;
177     /*
178      * Protect against adding the same error table twice
179      */
180     for (et = _et_list; et; et = et->next) {
181         if (et->table->base == new_table->table->base) {
182             UNLOCK_ET_LIST;
183             return;
184         }
185     }
186
187     new_table->next = _et_list;
188     _et_list = new_table;
189     UNLOCK_ET_LIST;
190 }