perror.c 9.76 KB
Newer Older
1
/*
2
   Copyright (c) 2000, 2012, Oracle and/or its affiliates.
unknown's avatar
unknown committed
3 4 5

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
6
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
7 8

   This program is distributed in the hope that it will be useful,
unknown's avatar
unknown committed
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
unknown's avatar
unknown committed
16

17
/* Return error-text for system error messages and handler messages */
unknown's avatar
unknown committed
18

19
#define PERROR_VERSION "2.11"
unknown's avatar
unknown committed
20

unknown's avatar
unknown committed
21
#include <my_global.h>
unknown's avatar
unknown committed
22 23 24
#include <my_sys.h>
#include <m_string.h>
#include <errno.h>
25
#include <my_getopt.h>
26
#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
unknown's avatar
unknown committed
27

28
static my_bool verbose, print_all_codes;
unknown's avatar
unknown committed
29

30 31
#include <my_base.h>
#include <my_handler_errors.h>
32

33
static struct my_option my_long_options[] =
unknown's avatar
unknown committed
34
{
35 36
  {"help", '?', "Displays this help and exits.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
37
  {"info", 'I', "Synonym for --help.",  0, 0, 0, GET_NO_ARG,
38 39
   NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_SYS_ERRLIST
Guilhem Bichot's avatar
Guilhem Bichot committed
40 41
  {"all", 'a', "Print all the error messages and the number. Deprecated,"
   " will be removed in a future release.",
42
   &print_all_codes, &print_all_codes, 0, GET_BOOL, NO_ARG,
43 44
   0, 0, 0, 0, 0, 0},
#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 48
  {"verbose", 'v', "Print error code and message (default).", &verbose,
   &verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
49 50 51
  {"version", 'V', "Displays version information and exits.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
unknown's avatar
unknown committed
52 53
};

54

unknown's avatar
unknown committed
55 56 57 58 59 60 61 62
typedef struct ha_errors {
  int errcode;
  const char *msg;
} HA_ERRORS;


static HA_ERRORS ha_errlist[]=
{
63 64 65 66 67 68 69 70 71 72 73 74
  { -30999, "DB_INCOMPLETE: Sync didn't finish"},
  { -30998, "DB_KEYEMPTY: Key/data deleted or never created"},
  { -30997, "DB_KEYEXIST: The key/data pair already exists"},
  { -30996, "DB_LOCK_DEADLOCK: Deadlock"},
  { -30995, "DB_LOCK_NOTGRANTED: Lock unavailable"},
  { -30994, "DB_NOSERVER: Server panic return"},
  { -30993, "DB_NOSERVER_HOME: Bad home sent to server"},
  { -30992, "DB_NOSERVER_ID: Bad ID sent to server"},
  { -30991, "DB_NOTFOUND: Key/data pair not found (EOF)"},
  { -30990, "DB_OLD_VERSION: Out-of-date version"},
  { -30989, "DB_RUNRECOVERY: Panic return"},
  { -30988, "DB_VERIFY_BAD: Verify failed; bad format"},
unknown's avatar
unknown committed
75 76 77 78 79 80 81 82 83 84
  { 0,NullS },
};


static void print_version(void)
{
  printf("%s Ver %s, for %s (%s)\n",my_progname,PERROR_VERSION,
	 SYSTEM_TYPE,MACHINE_TYPE);
}

unknown's avatar
unknown committed
85

unknown's avatar
unknown committed
86 87 88
static void usage(void)
{
  print_version();
89
  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
90
  printf("Print a description for a system error code or a MariaDB 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");
unknown's avatar
unknown committed
92
  printf("Usage: %s [OPTIONS] [ERRORCODE [ERRORCODE...]]\n",my_progname);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
}


static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument __attribute__((unused)))
{
  switch (optid) {
  case 's':
    verbose=0;
    break;
  case 'V':
    print_version();
108
    my_end(0);
109 110 111 112 113
    exit(0);
    break;
  case 'I':
  case '?':
    usage();
114
    my_end(0);
115 116 117 118
    exit(0);
    break;
  }
  return 0;
unknown's avatar
unknown committed
119
}
unknown's avatar
unknown committed
120 121 122 123


static int get_options(int *argc,char ***argv)
{
124
  int ho_error;
unknown's avatar
unknown committed
125

126
  if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
127 128
  {
    my_end(0);
129
    exit(ho_error);
130
  }
131

unknown's avatar
unknown committed
132 133 134 135 136 137 138 139 140 141 142 143 144
  if (!*argc && !print_all_codes)
  {
    usage();
    return 1;
  }
  return 0;
} /* get_options */


static const char *get_ha_error_msg(int code)
{
  HA_ERRORS *ha_err_ptr;

145 146 147 148 149 150 151 152 153 154 155
  /*
    If you got compilation error here about compile_time_assert array, check
    that every HA_ERR_xxx constant has a corresponding error message in
    handler_error_messages[] list (check mysys/ma_handler_errors.h and
    include/my_base.h).
  */
  compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
                      HA_ERR_LAST + 1);
  if (code >= HA_ERR_FIRST && code <= HA_ERR_LAST)
    return handler_error_messages[code - HA_ERR_FIRST];

unknown's avatar
unknown committed
156 157 158 159 160 161
  for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
    if (ha_err_ptr->errcode == code)
      return ha_err_ptr->msg;
  return NullS;
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
typedef struct
{
  const char *name;
  uint        code;
  const char *text;
} st_error;

static st_error global_error_names[] =
{
#include <mysqld_ername.h>
  { 0, 0, 0 }
};

/**
  Lookup an error by code in the global_error_names array.
  @param code the code to lookup
  @param [out] name_ptr the error name, when found
  @param [out] msg_ptr the error text, when found
  @return 1 when found, otherwise 0
*/
int get_ER_error_msg(uint code, const char **name_ptr, const char **msg_ptr)
{
  st_error *tmp_error;

  tmp_error= & global_error_names[0];

  while (tmp_error->name != NULL)
  {
    if (tmp_error->code == code)
    {
      *name_ptr= tmp_error->name;
      *msg_ptr= tmp_error->text;
      return 1;
    }
    tmp_error++;
  }

  return 0;
}
unknown's avatar
unknown committed
201

202 203 204 205 206 207 208 209 210 211
#if defined(__WIN__)
static my_bool print_win_error_msg(DWORD error, my_bool verbose)
{
  LPTSTR s;
  if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                    FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, error, 0, (LPTSTR)&s, 0,
                    NULL))
  {
    if (verbose)
212
      printf("Win32 error code %lu: %s", error, s);
213 214 215 216 217 218 219 220 221
    else
      puts(s);
    LocalFree(s);
    return 0;
  }
  return 1;
}
#endif

222 223
/*
  Register handler error messages for usage with my_error()
224

225 226 227 228 229
  NOTES
    This is safe to call multiple times as my_error_register()
    will ignore calls to register already registered error numbers.
*/

230
static const char **get_handler_error_messages(int e __attribute__((unused)))
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
{
  return handler_error_messages;
}

void my_handler_error_register(void)
{
  /*
    If you got compilation error here about compile_time_assert array, check
    that every HA_ERR_xxx constant has a corresponding error message in
    handler_error_messages[] list (check mysys/ma_handler_errors.h and
    include/my_base.h).
  */
  compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) ==
                      HA_ERR_LAST + 1);
  my_error_register(get_handler_error_messages, HA_ERR_FIRST,
                    HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
}


void my_handler_error_unregister(void)
{
  my_error_unregister(HA_ERR_FIRST,
                      HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
}
255

unknown's avatar
unknown committed
256 257 258 259
int main(int argc,char *argv[])
{
  int error,code,found;
  const char *msg;
260
  const char *name;
unknown's avatar
unknown committed
261
  char *unknown_error = 0;
262 263 264
#if defined(__WIN__)
  my_bool skip_win_message= 0;
#endif
unknown's avatar
unknown committed
265 266 267
  MY_INIT(argv[0]);

  if (get_options(&argc,&argv))
268 269
  {
    my_end(0);
unknown's avatar
unknown committed
270
    exit(1);
271
  }
unknown's avatar
unknown committed
272

273 274
  my_handler_error_register();

unknown's avatar
unknown committed
275 276 277 278 279
  error=0;
#ifdef HAVE_SYS_ERRLIST
  if (print_all_codes)
  {
    HA_ERRORS *ha_err_ptr;
Guilhem Bichot's avatar
Guilhem Bichot committed
280 281
    printf("WARNING: option '-a/--all' is deprecated and will be removed in a"
           " future release.\n");
unknown's avatar
unknown committed
282 283
    for (code=1 ; code < sys_nerr ; code++)
    {
284
      if (sys_errlist[code] && sys_errlist[code][0])
285
      {						/* Skip if no error-text */
unknown's avatar
unknown committed
286 287 288 289 290 291 292 293 294
	printf("%3d = %s\n",code,sys_errlist[code]);
      }
    }
    for (ha_err_ptr=ha_errlist ; ha_err_ptr->errcode ;ha_err_ptr++)
      printf("%3d = %s\n",ha_err_ptr->errcode,ha_err_ptr->msg);
  }
  else
#endif
  {
unknown's avatar
unknown committed
295
    /*
296
      On some system, like Linux, strerror(unknown_error) returns a
unknown's avatar
unknown committed
297 298
      string 'Unknown Error'.  To avoid printing it we try to find the
      error string by asking for an impossible big error message.
299 300

      On Solaris 2.8 it might return NULL
unknown's avatar
unknown committed
301
    */
302 303
    if ((msg= strerror(10000)) == NULL)
      msg= "Unknown Error";
unknown's avatar
unknown committed
304

305 306 307 308 309 310
    /*
      Allocate a buffer for unknown_error since strerror always returns
      the same pointer on some platforms such as Windows
    */
    unknown_error= malloc(strlen(msg)+1);
    strmov(unknown_error, msg);
unknown's avatar
unknown committed
311

unknown's avatar
unknown committed
312 313
    for ( ; argc-- > 0 ; argv++)
    {
314

unknown's avatar
unknown committed
315 316
      found=0;
      code=atoi(*argv);
317
      msg = strerror(code);
unknown's avatar
unknown committed
318 319

      /*
320 321 322
        We don't print the OS error message if it is the same as the
        unknown_error message we retrieved above, or it starts with
        'Unknown Error' (without regard to case).
unknown's avatar
unknown committed
323
      */
324
      if (msg &&
325 326
          my_strnncoll(&my_charset_latin1, (const uchar*) msg, 13,
                       (const uchar*) "Unknown Error", 13) &&
unknown's avatar
unknown committed
327
          (!unknown_error || strcmp(msg, unknown_error)))
unknown's avatar
unknown committed
328
      {
329
	found= 1;
unknown's avatar
unknown committed
330
	if (verbose)
331
	  printf("OS error code %3d:  %s\n", code, msg);
unknown's avatar
unknown committed
332 333 334
	else
	  puts(msg);
      }
335
      if ((msg= get_ha_error_msg(code)))
unknown's avatar
unknown committed
336
      {
337 338
        found= 1;
        if (verbose)
339
          printf("MariaDB error code %3d: %s\n", code, msg);
340
        else
341 342
          puts(msg);
      }
343 344 345 346
      if (get_ER_error_msg(code, & name, & msg))
      {
        found= 1;
        if (verbose)
347
          printf("MariaDB error code %3d (%s): %s\n", code, name, msg);
348 349 350
        else
          puts(msg);
      }
351 352
      if (!found)
      {
353
#if defined(__WIN__)
354 355
        if (!(skip_win_message= !print_win_error_msg((DWORD)code, verbose)))
        {
356
#endif
357 358
          fprintf(stderr,"Illegal error code: %d\n",code);
          error=1;
359
#if defined(__WIN__)
360
        }
361
#endif
unknown's avatar
unknown committed
362
      }
363 364 365 366
#if defined(__WIN__)
      if (!skip_win_message)
        print_win_error_msg((DWORD)code, verbose);
#endif
unknown's avatar
unknown committed
367 368
    }
  }
unknown's avatar
unknown committed
369 370 371

  /* if we allocated a buffer for unknown_error, free it now */
  if (unknown_error)
372
    free(unknown_error);
unknown's avatar
unknown committed
373

374 375
  my_handler_error_unregister();
  my_end(0);
unknown's avatar
unknown committed
376 377 378
  exit(error);
  return error;
}