1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; version 2 of the License. 6 7 This program is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 GNU General Public License for more details. 11 12 You should have received a copy of the GNU General Public License 13 along with this program; if not, write to the Free Software 14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ 15 16 #include "mysys_priv.h" 17 #include "mysys_err.h" 18 #include <m_string.h> 19 #include <stdarg.h> 20 #include <m_ctype.h> 21 22 /* Max length of a error message. Should be kept in sync with MYSQL_ERRMSG_SIZE. */ 23 #define ERRMSGSIZE (512) 24 25 /* Define some external variables for error handling */ 26 27 /* 28 WARNING! 29 my_error family functions have to be used according following rules: 30 - if message have not parameters use my_message(ER_CODE, ER(ER_CODE), MYF(N)) 31 - if message registered use my_error(ER_CODE, MYF(N), ...). 32 - With some special text of errror message use: 33 my_printf_error(ER_CODE, format, MYF(N), ...) 34 */ 35 36 /* 37 Message texts are registered into a linked list of 'my_err_head' structs. 38 Each struct contains (1.) an array of pointers to C character strings with 39 '\0' termination, (2.) the error number for the first message in the array 40 (array index 0) and (3.) the error number for the last message in the array 41 (array index (last - first)). 42 The array may contain gaps with NULL pointers and pointers to empty strings. 43 Both kinds of gaps will be translated to "Unknown error %d.", if my_error() 44 is called with a respective error number. 45 The list of header structs is sorted in increasing order of error numbers. 46 Negative error numbers are allowed. Overlap of error numbers is not allowed. 47 Not registered error numbers will be translated to "Unknown error %d.". 48 */ 49 static struct my_err_head 50 { 51 struct my_err_head *meh_next; /* chain link */ 52 const char** (*get_errmsgs)(int nr); /* returns error message format */ 53 uint meh_first; /* error number matching array slot 0 */ 54 uint meh_last; /* error number matching last slot */ 55 } my_errmsgs_globerrs= 56 {NULL, get_global_errmsgs, EE_ERROR_FIRST, EE_ERROR_LAST}; 57 58 static struct my_err_head *my_errmsgs_list= &my_errmsgs_globerrs; 59 60 61 /** 62 @brief Get an error format string from one of the my_error_register()ed sets 63 64 @note 65 NULL values are possible even within a registered range. 66 67 @param nr Errno 68 69 @retval NULL if no message is registered for this error number 70 @retval str C-string 71 */ 72 73 const char *my_get_err_msg(uint nr) 74 { 75 const char *format; 76 struct my_err_head *meh_p; 77 78 /* Search for the range this error is in. */ 79 for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next) 80 if (nr <= meh_p->meh_last) 81 break; 82 83 /* 84 If we found the range this error number is in, get the format string. 85 If the string is empty, or a NULL pointer, or if we're out of return, 86 we return NULL. 87 */ 88 if (!(format= (meh_p && (nr >= meh_p->meh_first)) ? 89 meh_p->get_errmsgs(nr)[nr - meh_p->meh_first] : NULL) || 90 !*format) 91 return NULL; 92 93 return format; 94 } 95 96 97 /** 98 Fill in and print a previously registered error message. 99 100 @note 101 Goes through the (sole) function registered in error_handler_hook 102 103 @param nr error number 104 @param MyFlags Flags 105 @param ... variable list matching that error format string 106 */ 107 108 void my_error(uint nr, myf MyFlags, ...) 109 { 110 const char *format; 111 va_list args; 112 char ebuff[ERRMSGSIZE]; 113 DBUG_ENTER("my_error"); 114 DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d", nr, MyFlags, errno)); 115 116 if (!(format = my_get_err_msg(nr))) 117 (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr); 118 else 119 { 120 va_start(args,MyFlags); 121 (void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff, 122 sizeof(ebuff), format, args); 123 va_end(args); 124 } 125 (*error_handler_hook)(nr, ebuff, MyFlags); 126 DBUG_VOID_RETURN; 127 } 128 129 130 /** 131 Print an error message. 132 133 @note 134 Just like my_error, but for cases when the error message is not ER(error) 135 136 @param error error number 137 @param format format string 138 @param MyFlags Flags 139 @param ... variable list matching that error format string 140 */ 141 142 void my_printf_error(uint error, const char *format, myf MyFlags, ...) 143 { 144 va_list args; 145 char ebuff[ERRMSGSIZE]; 146 DBUG_ENTER("my_printf_error"); 147 DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d format: %s", 148 error, MyFlags, errno, format)); 149 150 va_start(args,MyFlags); 151 (void) my_vsnprintf_ex(&my_charset_utf8_general_ci, ebuff, 152 sizeof(ebuff), format, args); 153 va_end(args); 154 (*error_handler_hook)(error, ebuff, MyFlags); 155 DBUG_VOID_RETURN; 156 } 157 158 /** 159 Print an error message. 160 161 @note 162 Goes through the (sole) function registered in error_handler_hook 163 164 @param error error number 165 @param format format string 166 @param MyFlags Flags 167 @param ap variable list matching that error format string 168 */ 169 170 void my_printv_error(uint error, const char *format, myf MyFlags, va_list ap) 171 { 172 char ebuff[ERRMSGSIZE]; 173 DBUG_ENTER("my_printv_error"); 174 DBUG_PRINT("my", ("nr: %d MyFlags: %lu errno: %d format: %s", 175 error, MyFlags, errno, format)); 176 177 (void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap); 178 (*error_handler_hook)(error, ebuff, MyFlags); 179 DBUG_VOID_RETURN; 180 } 181 182 183 /** 184 Print an error message. 185 186 @note 187 Goes through the (sole) function registered in error_handler_hook 188 189 @param error error number 190 @param str error message 191 @param MyFlags Flags 192 */ 193 194 void my_message(uint error, const char *str, register myf MyFlags) 195 { 196 (*error_handler_hook)(error, str, MyFlags); 197 } 198 199 200 /** 201 Register error messages for use with my_error(). 202 203 @description 204 205 The pointer array is expected to contain addresses to NUL-terminated 206 C character strings. The array contains (last - first + 1) pointers. 207 NULL pointers and empty strings ("") are allowed. These will be mapped to 208 "Unknown error" when my_error() is called with a matching error number. 209 This function registers the error numbers 'first' to 'last'. 210 No overlapping with previously registered error numbers is allowed. 211 212 @param errmsgs array of pointers to error messages 213 @param first error number of first message in the array 214 @param last error number of last message in the array 215 216 @retval 0 OK 217 @retval != 0 Error 218 */ 219 220 int my_error_register(const char** (*get_errmsgs)(int error), uint first, 221 uint last) 222 { 223 struct my_err_head *meh_p; 224 struct my_err_head **search_meh_pp; 225 226 /* Allocate a new header structure. */ 227 if (! (meh_p= (struct my_err_head*) my_malloc(sizeof(struct my_err_head), 228 MYF(MY_WME)))) 229 return 1; 230 meh_p->get_errmsgs= get_errmsgs; 231 meh_p->meh_first= first; 232 meh_p->meh_last= last; 233 234 /* Search for the right position in the list. */ 235 for (search_meh_pp= &my_errmsgs_list; 236 *search_meh_pp; 237 search_meh_pp= &(*search_meh_pp)->meh_next) 238 { 239 if ((*search_meh_pp)->meh_last > first) 240 break; 241 } 242 243 /* Error numbers must be unique. No overlapping is allowed. */ 244 if (*search_meh_pp && ((*search_meh_pp)->meh_first <= last)) 245 { 246 my_free(meh_p); 247 return 1; 248 } 249 250 /* Insert header into the chain. */ 251 meh_p->meh_next= *search_meh_pp; 252 *search_meh_pp= meh_p; 253 return 0; 254 } 255 256 257 /** 258 Unregister formerly registered error messages. 259 260 @description 261 262 This function unregisters the error numbers 'first' to 'last'. 263 These must have been previously registered by my_error_register(). 264 'first' and 'last' must exactly match the registration. 265 If a matching registration is present, the header is removed from the 266 list and the pointer to the error messages pointers array is returned. 267 (The messages themselves are not released here as they may be static.) 268 Otherwise, NULL is returned. 269 270 @param first error number of first message 271 @param last error number of last message 272 273 @retval NULL Error, no such number range registered. 274 @retval non-NULL OK, returns address of error messages pointers array. 275 */ 276 277 my_bool my_error_unregister(uint first, uint last) 278 { 279 struct my_err_head *meh_p; 280 struct my_err_head **search_meh_pp; 281 282 /* Search for the registration in the list. */ 283 for (search_meh_pp= &my_errmsgs_list; 284 *search_meh_pp; 285 search_meh_pp= &(*search_meh_pp)->meh_next) 286 { 287 if (((*search_meh_pp)->meh_first == first) && 288 ((*search_meh_pp)->meh_last == last)) 289 break; 290 } 291 if (! *search_meh_pp) 292 return TRUE; 293 294 /* Remove header from the chain. */ 295 meh_p= *search_meh_pp; 296 *search_meh_pp= meh_p->meh_next; 297 298 my_free(meh_p); 299 300 return FALSE; 301 } 302 303 304 /** 305 Unregister all formerly registered error messages. 306 307 @description 308 309 This function unregisters all error numbers that previously have 310 been previously registered by my_error_register(). 311 All headers are removed from the list; the messages themselves are 312 not released here as they may be static. 313 */ 314 315 void my_error_unregister_all(void) 316 { 317 struct my_err_head *cursor, *saved_next; 318 319 for (cursor= my_errmsgs_globerrs.meh_next; cursor != NULL; cursor= saved_next) 320 { 321 /* We need this ptr, but we're about to free its container, so save it. */ 322 saved_next= cursor->meh_next; 323 324 my_free(cursor); 325 } 326 my_errmsgs_globerrs.meh_next= NULL; /* Freed in first iteration above. */ 327 328 my_errmsgs_list= &my_errmsgs_globerrs; 329 } 330