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