1/*
2 Copyright (c) 2000, 2012, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17/* Return error-text for system error messages and handler messages */
18
19#define PERROR_VERSION "2.11"
20
21#include <my_global.h>
22#include <my_sys.h>
23#include <m_string.h>
24#include <errno.h>
25#include <my_getopt.h>
26#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
27
28static my_bool verbose, print_all_codes;
29
30#include <my_base.h>
31#include <my_handler_errors.h>
32
33static struct my_option my_long_options[] =
34{
35 {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG,
36 NO_ARG, 0, 0, 0, 0, 0, 0},
37 {"info", 'I', "Synonym for --help.", 0, 0, 0, GET_NO_ARG,
38 NO_ARG, 0, 0, 0, 0, 0, 0},
39#ifdef HAVE_SYS_ERRLIST
40 {"all", 'a', "Print all the error messages and the number. Deprecated,"
41 " will be removed in a future release.",
42 &print_all_codes, &print_all_codes, 0, GET_BOOL, NO_ARG,
43 0, 0, 0, 0, 0, 0},
44#endif
45 {"silent", 's', "Only print the error message.", 0, 0, 0, GET_NO_ARG, NO_ARG,
46 0, 0, 0, 0, 0, 0},
47 {"verbose", 'v', "Print error code and message (default).", &verbose,
48 &verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
49 {"version", 'V', "Displays version information and exits.",
50 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
51 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
52};
53
54
55typedef struct ha_errors {
56 int errcode;
57 const char *msg;
58} HA_ERRORS;
59
60
61static HA_ERRORS ha_errlist[]=
62{
63 { -30999, "DB_INCOMPLETE: Sync didn't finish"},
64 { -30998, "DB_KEYEMPTY: Key/data deleted or never created"},
65 { -30997, "DB_KEYEXIST: The key/data pair already exists"},
66 { -30996, "DB_LOCK_DEADLOCK: Deadlock"},
67 { -30995, "DB_LOCK_NOTGRANTED: Lock unavailable"},
68 { -30994, "DB_NOSERVER: Server panic return"},
69 { -30993, "DB_NOSERVER_HOME: Bad home sent to server"},
70 { -30992, "DB_NOSERVER_ID: Bad ID sent to server"},
71 { -30991, "DB_NOTFOUND: Key/data pair not found (EOF)"},
72 { -30990, "DB_OLD_VERSION: Out-of-date version"},
73 { -30989, "DB_RUNRECOVERY: Panic return"},
74 { -30988, "DB_VERIFY_BAD: Verify failed; bad format"},
75 { 0,NullS },
76};
77
78
79static void print_version(void)
80{
81 printf("%s Ver %s, for %s (%s)\n",my_progname,PERROR_VERSION,
82 SYSTEM_TYPE,MACHINE_TYPE);
83}
84
85
86static void usage(void)
87{
88 print_version();
89 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
90 printf("Print a description for a system error code or a MySQL error code.\n");
91 printf("If you want to get the error for a negative error code, you should use\n-- before the first error code to tell perror that there was no more options.\n\n");
92 printf("Usage: %s [OPTIONS] [ERRORCODE [ERRORCODE...]]\n",my_progname);
93 my_print_help(my_long_options);
94 my_print_variables(my_long_options);
95}
96
97
98static my_bool
99get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
100 char *argument __attribute__((unused)))
101{
102 switch (optid) {
103 case 's':
104 verbose=0;
105 break;
106 case 'V':
107 print_version();
108 exit(0);
109 break;
110 case 'I':
111 case '?':
112 usage();
113 exit(0);
114 break;
115 }
116 return 0;
117}
118
119
120static int get_options(int *argc,char ***argv)
121{
122 int ho_error;
123
124 if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
125 exit(ho_error);
126
127 if (!*argc && !print_all_codes)
128 {
129 usage();
130 return 1;
131 }
132 return 0;
133} /* get_options */
134
135
136static const char *get_ha_error_msg(int code)
137{
138 HA_ERRORS *ha_err_ptr;
139
140 /*
141 If you got compilation error here about compile_time_assert array, check
142 that every HA_ERR_xxx constant has a corresponding error message in
143 handler_error_messages[] list (check mysys/ma_handler_errors.h and
144 include/my_base.h).
145 */
146 compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
147 HA_ERR_LAST + 1);
148 if (code >= HA_ERR_FIRST && code <= HA_ERR_LAST)
149 return handler_error_messages[code - HA_ERR_FIRST];
150
151 for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
152 if (ha_err_ptr->errcode == code)
153 return ha_err_ptr->msg;
154 return NullS;
155}
156
157typedef struct
158{
159 const char *name;
160 uint code;
161 const char *text;
162} st_error;
163
164static st_error global_error_names[] =
165{
166#include <mysqld_ername.h>
167 { 0, 0, 0 }
168};
169
170/**
171 Lookup an error by code in the global_error_names array.
172 @param code the code to lookup
173 @param [out] name_ptr the error name, when found
174 @param [out] msg_ptr the error text, when found
175 @return 1 when found, otherwise 0
176*/
177int get_ER_error_msg(uint code, const char **name_ptr, const char **msg_ptr)
178{
179 st_error *tmp_error;
180
181 tmp_error= & global_error_names[0];
182
183 while (tmp_error->name != NULL)
184 {
185 if (tmp_error->code == code)
186 {
187 *name_ptr= tmp_error->name;
188 *msg_ptr= tmp_error->text;
189 return 1;
190 }
191 tmp_error++;
192 }
193
194 return 0;
195}
196
197#if defined(__WIN__)
198static my_bool print_win_error_msg(DWORD error, my_bool verbose)
199{
200 LPTSTR s;
201 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
202 FORMAT_MESSAGE_FROM_SYSTEM,
203 NULL, error, 0, (LPTSTR)&s, 0,
204 NULL))
205 {
206 if (verbose)
207 printf("Win32 error code %lu: %s", error, s);
208 else
209 puts(s);
210 LocalFree(s);
211 return 0;
212 }
213 return 1;
214}
215#endif
216
217/*
218 Register handler error messages for usage with my_error()
219
220 NOTES
221 This is safe to call multiple times as my_error_register()
222 will ignore calls to register already registered error numbers.
223*/
224
225static const char **get_handler_error_messages(int e __attribute__((unused)))
226{
227 return handler_error_messages;
228}
229
230void my_handler_error_register(void)
231{
232 /*
233 If you got compilation error here about compile_time_assert array, check
234 that every HA_ERR_xxx constant has a corresponding error message in
235 handler_error_messages[] list (check mysys/ma_handler_errors.h and
236 include/my_base.h).
237 */
238 compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
239 HA_ERR_LAST + 1);
240 my_error_register(get_handler_error_messages, HA_ERR_FIRST,
241 HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
242}
243
244
245void my_handler_error_unregister(void)
246{
247 my_error_unregister(HA_ERR_FIRST,
248 HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
249}
250
251int main(int argc,char *argv[])
252{
253 int error,code,found;
254 const char *msg;
255 const char *name;
256 char *unknown_error = 0;
257#if defined(__WIN__)
258 my_bool skip_win_message= 0;
259#endif
260 MY_INIT(argv[0]);
261
262 if (get_options(&argc,&argv))
263 exit(1);
264
265 my_handler_error_register();
266
267 error=0;
268#ifdef HAVE_SYS_ERRLIST
269 if (print_all_codes)
270 {
271 HA_ERRORS *ha_err_ptr;
272 printf("WARNING: option '-a/--all' is deprecated and will be removed in a"
273 " future release.\n");
274 for (code=1 ; code < sys_nerr ; code++)
275 {
276 if (sys_errlist[code] && sys_errlist[code][0])
277 { /* Skip if no error-text */
278 printf("%3d = %s\n",code,sys_errlist[code]);
279 }
280 }
281 for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
282 printf("%3d = %s\n",ha_err_ptr->errcode,ha_err_ptr->msg);
283 }
284 else
285#endif
286 {
287 /*
288 On some system, like Linux, strerror(unknown_error) returns a
289 string 'Unknown Error'. To avoid printing it we try to find the
290 error string by asking for an impossible big error message.
291
292 On Solaris 2.8 it might return NULL
293 */
294 if ((msg= strerror(10000)) == NULL)
295 msg= "Unknown Error";
296
297 /*
298 Allocate a buffer for unknown_error since strerror always returns
299 the same pointer on some platforms such as Windows
300 */
301 unknown_error= malloc(strlen(msg)+1);
302 strmov(unknown_error, msg);
303
304 for ( ; argc-- > 0 ; argv++)
305 {
306
307 found=0;
308 code=atoi(*argv);
309 msg = strerror(code);
310
311 /*
312 We don't print the OS error message if it is the same as the
313 unknown_error message we retrieved above, or it starts with
314 'Unknown Error' (without regard to case).
315 */
316 if (msg &&
317 my_strnncoll(&my_charset_latin1, (const uchar*) msg, 13,
318 (const uchar*) "Unknown Error", 13) &&
319 (!unknown_error || strcmp(msg, unknown_error)))
320 {
321 found= 1;
322 if (verbose)
323 printf("OS error code %3d: %s\n", code, msg);
324 else
325 puts(msg);
326 }
327 if ((msg= get_ha_error_msg(code)))
328 {
329 found= 1;
330 if (verbose)
331 printf("MySQL error code %3d: %s\n", code, msg);
332 else
333 puts(msg);
334 }
335 if (get_ER_error_msg(code, & name, & msg))
336 {
337 found= 1;
338 if (verbose)
339 printf("MySQL error code %3d (%s): %s\n", code, name, msg);
340 else
341 puts(msg);
342 }
343 if (!found)
344 {
345#if defined(__WIN__)
346 if (!(skip_win_message= !print_win_error_msg((DWORD)code, verbose)))
347 {
348#endif
349 fprintf(stderr,"Illegal error code: %d\n",code);
350 error=1;
351#if defined(__WIN__)
352 }
353#endif
354 }
355#if defined(__WIN__)
356 if (!skip_win_message)
357 print_win_error_msg((DWORD)code, verbose);
358#endif
359 }
360 }
361
362 /* if we allocated a buffer for unknown_error, free it now */
363 if (unknown_error)
364 free(unknown_error);
365
366 my_handler_error_unregister();
367 my_end(0);
368 exit(error);
369 return error;
370}
371