Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/common/brand/lx/tools/gen_errno.c
          +++ new/usr/src/common/brand/lx/tools/gen_errno.c
   1    1  /*
   2    2   * This file and its contents are supplied under the terms of the
   3    3   * Common Development and Distribution License ("CDDL"), version 1.0.
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13   13   * Copyright 2015 Joyent, Inc.
  14   14   */
  15   15  
  16   16  /*
  17   17   * Take the error number definitions from a foreign system and generate a
  18   18   * translation table that converts illumos native error numbers to foreign
  19   19   * system error numbers.
  20   20   */
  21   21  
  22   22  #include <ctype.h>
  23   23  #include <stdlib.h>
  24   24  #include <stdio.h>
  25   25  #include <unistd.h>
  26   26  #include <errno.h>
  27   27  #include <err.h>
  28   28  #include <sys/sysmacros.h>
  29   29  #include <libcmdutils.h>
  30   30  #include <libnvpair.h>
  31   31  
  32   32  nvlist_t *native_errors;
  33   33  nvlist_t *foreign_errors;
  34   34  
  35   35  struct override {
  36   36          const char *ovr_from;
  37   37          const char *ovr_to;
  38   38  } overrides[] = {
  39   39          { "ENOTSUP", "ENOSYS" },
  40   40          { 0 }
  41   41  };
  42   42  
  43   43  static const char *
  44   44  lookup_override(const char *from)
  45   45  {
  46   46          int i;
  47   47  
  48   48          for (i = 0; overrides[i].ovr_from != NULL; i++) {
  49   49                  if (strcmp(overrides[i].ovr_from, from) == 0) {
  50   50                          return (overrides[i].ovr_to);
  51   51                  }
  52   52          }
  53   53  
  54   54          return (NULL);
  55   55  }
  56   56  
  57   57  static int
  58   58  parse_int(const char *number, int *rval)
  59   59  {
  60   60          long n;
  61   61          char *endpos;
  62   62  
  63   63          errno = 0;
  64   64          if ((n = strtol(number, &endpos, 10)) == 0 && errno != 0) {
  65   65                  return (-1);
  66   66          }
  67   67  
  68   68          if (endpos != NULL && *endpos != '\0') {
  69   69                  errno = EINVAL;
  70   70                  return (-1);
  71   71          }
  72   72  
  73   73          if (n > INT_MAX || n < INT_MIN) {
  74   74                  errno = EOVERFLOW;
  75   75                  return (-1);
  76   76          }
  77   77  
  78   78          *rval = (int)n;
  79   79          return (0);
  80   80  }
  81   81  
  82   82  static int
  83   83  errnum_add(nvlist_t *nvl, const char *name, const char *number)
  84   84  {
  85   85          int val;
  86   86  
  87   87          if (nvlist_exists(nvl, name)) {
  88   88                  (void) fprintf(stderr, "ERROR: duplicate definition: %s -> "
  89   89                      "%s\n", name, number);
  90   90                  errno = EEXIST;
  91   91                  return (-1);
  92   92          }
  93   93  
  94   94          /*
  95   95           * Try and parse the error number:
  96   96           */
  97   97          if (parse_int(number, &val) == 0) {
  98   98                  /*
  99   99                   * The name refers to a number.
 100  100                   */
 101  101                  if (nvlist_add_int32(nvl, name, val) != 0) {
 102  102                          (void) fprintf(stderr, "ERROR: nvlist_add_int32: %s\n",
 103  103                              strerror(errno));
 104  104                          return (-1);
 105  105                  }
 106  106          } else {
 107  107                  /*
 108  108                   * The name refers to another definition.
 109  109                   */
 110  110                  if (nvlist_add_string(nvl, name, number) != 0) {
 111  111                          (void) fprintf(stderr, "ERROR: nvlist_add_string: %s\n",
 112  112                              strerror(errno));
 113  113                          return (-1);
 114  114                  }
 115  115          }
 116  116  
 117  117          return (0);
 118  118  }
 119  119  
 120  120  static int
 121  121  errnum_max(nvlist_t *nvl)
 122  122  {
 123  123          int max = 0;
 124  124          nvpair_t *nvp = NULL;
 125  125  
 126  126          while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
 127  127                  if (nvpair_type(nvp) != DATA_TYPE_INT32) {
 128  128                          continue;
 129  129                  }
 130  130  
 131  131                  max = MAX(fnvpair_value_int32(nvp), max);
 132  132          }
 133  133  
 134  134          return (max);
 135  135  }
 136  136  
 137  137  static int
 138  138  errname_by_num(nvlist_t *nvl, int num, const char **name)
 139  139  {
 140  140          nvpair_t *nvp = NULL;
 141  141  
 142  142          while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
 143  143                  if (nvpair_type(nvp) != DATA_TYPE_INT32) {
 144  144                          continue;
 145  145                  }
 146  146  
 147  147                  if (fnvpair_value_int32(nvp) == num) {
 148  148                          *name = nvpair_name(nvp);
 149  149                          return (0);
 150  150                  }
 151  151          }
 152  152  
 153  153          errno = ENOENT;
 154  154          return (-1);
 155  155  }
 156  156  
 157  157  static int
 158  158  errno_by_name(nvlist_t *nvl, const char *name, int *rval, const char **rname)
 159  159  {
 160  160          nvpair_t *nvp = NULL;
 161  161  
 162  162          if (nvlist_lookup_nvpair(nvl, name, &nvp) != 0) {
 163  163                  errno = ENOENT;
 164  164                  return (-1);
 165  165          }
 166  166  
 167  167          if (nvpair_type(nvp) == DATA_TYPE_STRING) {
 168  168                  return (errno_by_name(nvl, fnvpair_value_string(nvp), rval,
 169  169                      rname));
 170  170          } else {
 171  171                  *rval = fnvpair_value_int32(nvp);
 172  172                  if (rname != NULL) {
 173  173                          *rname = name;
 174  174                  }
 175  175                  return (0);
 176  176          }
 177  177  }
 178  178  
 179  179  static int
 180  180  process_line(const char *line, nvlist_t *nvl)
 181  181  {
 182  182          custr_t *nam = NULL, *num = NULL;
 183  183          const char *c = line;
 184  184  
 185  185          if (custr_alloc(&nam) != 0 || custr_alloc(&num) != 0) {
 186  186                  int en = errno;
 187  187  
 188  188                  custr_free(nam);
 189  189                  custr_free(num);
 190  190  
 191  191                  errno = en;
 192  192                  return (-1);
 193  193          }
 194  194  
 195  195          /*
 196  196           * Valid lines begin with "#define":
 197  197           */
 198  198          if (*c++ != '#' || *c++ != 'd' || *c++ != 'e' || *c++ != 'f' ||
 199  199              *c++ != 'i' || *c++ != 'n' || *c++ != 'e') {
 200  200                  return (0);
 201  201          }
 202  202  
 203  203          /*
 204  204           * Eat whitespace:
 205  205           */
 206  206          for (;;) {
 207  207                  if (*c == '\0') {
 208  208                          return (0);
 209  209                  }
 210  210  
 211  211                  if (*c != ' ' && *c != '\t') {
 212  212                          break;
 213  213                  }
 214  214  
 215  215                  c++;
 216  216          }
 217  217  
 218  218          /*
 219  219           * Read error number token:
 220  220           */
 221  221          for (;;) {
 222  222                  if (*c == '\0') {
 223  223                          return (0);
 224  224                  }
 225  225  
 226  226                  if (*c == ' ' || *c == '\t') {
 227  227                          break;
 228  228                  }
 229  229  
 230  230                  if (custr_appendc(nam, *c) != 0) {
 231  231                          return (-1);
 232  232                  }
 233  233  
 234  234                  c++;
 235  235          }
 236  236  
 237  237          /*
 238  238           * Eat whitespace:
 239  239           */
 240  240          for (;;) {
 241  241                  if (*c == '\0') {
 242  242                          return (0);
 243  243                  }
 244  244  
 245  245                  if (*c != ' ' && *c != '\t') {
 246  246                          break;
 247  247                  }
 248  248  
 249  249                  c++;
 250  250          }
 251  251  
 252  252          /*
 253  253           * Read error number token:
 254  254           */
 255  255          for (;;) {
 256  256                  if (*c == '\0') {
 257  257                          break;
 258  258                  }
 259  259  
 260  260                  if (*c == ' ' || *c == '\t') {
 261  261                          break;
 262  262                  }
 263  263  
 264  264                  if (custr_appendc(num, *c) != 0) {
 265  265                          return (-1);
 266  266                  }
 267  267  
 268  268                  c++;
 269  269          }
 270  270  
 271  271          return (errnum_add(nvl, custr_cstr(nam), custr_cstr(num)));
 272  272  }
 273  273  
 274  274  static int
 275  275  read_file_into_list(const char *path, nvlist_t *nvl)
 276  276  {
 277  277          int rval = 0, en = 0;
 278  278          FILE *f;
 279  279          custr_t *cu = NULL;
 280  280  
 281  281          if (custr_alloc(&cu) != 0) {
 282  282                  return (-1);
 283  283          }
 284  284  
 285  285          if ((f = fopen(path, "r")) == NULL) {
 286  286                  custr_free(cu);
 287  287                  return (-1);
 288  288          }
 289  289  
 290  290          for (;;) {
 291  291                  int c;
 292  292  
 293  293                  errno = 0;
 294  294                  switch (c = fgetc(f)) {
 295  295                  case '\n':
 296  296                  case EOF:
 297  297                          if (errno != 0) {
 298  298                                  en = errno;
 299  299                                  rval = -1;
 300  300                                  goto out;
 301  301                          }
 302  302                          if (process_line(custr_cstr(cu), nvl) != 0) {
 303  303                                  en = errno;
 304  304                                  rval = -1;
 305  305                                  goto out;
 306  306                          }
 307  307                          custr_reset(cu);
 308  308                          if (c == EOF) {
 309  309                                  goto out;
 310  310                          }
 311  311                          break;
 312  312  
 313  313                  case '\r':
 314  314                  case '\0':
 315  315                          /*
 316  316                           * Ignore these characters.
 317  317                           */
 318  318                          break;
 319  319  
 320  320                  default:
 321  321                          if (custr_appendc(cu, c) != 0) {
 322  322                                  en = errno;
 323  323                                  rval = -1;
 324  324                                  goto out;
 325  325                          }
 326  326                          break;
 327  327                  }
 328  328          }
 329  329  
 330  330  out:
 331  331          (void) fclose(f);
 332  332          custr_free(cu);
 333  333          errno = en;
 334  334          return (rval);
 335  335  }
 336  336  
 337  337  int
 338  338  main(int argc, char **argv)
 339  339  {
 340  340          int max;
 341  341          int fval;
 342  342          int c;
 343  343  
 344  344          if (nvlist_alloc(&native_errors, NV_UNIQUE_NAME, 0) != 0 ||
 345  345              nvlist_alloc(&foreign_errors, NV_UNIQUE_NAME, 0) != 0) {
 346  346                  err(1, "could not allocate memory");
 347  347          }
 348  348  
 349  349          while ((c = getopt(argc, argv, ":N:F:")) != -1) {
 350  350                  switch (c) {
 351  351                  case 'N':
 352  352                          if (read_file_into_list(optarg, native_errors) != 0) {
 353  353                                  err(1, "could not read file: %s", optarg);
 354  354                          }
 355  355                          break;
 356  356  
 357  357                  case 'F':
 358  358                          if (read_file_into_list(optarg, foreign_errors) != 0) {
 359  359                                  err(1, "could not read file: %s", optarg);
 360  360                          }
 361  361                          break;
 362  362  
 363  363                  case ':':
 364  364                          errx(1, "option -%c requires an operand", c);
 365  365                          break;
 366  366  
 367  367                  case '?':
 368  368                          errx(1, "option -%c unrecognised", c);
 369  369                          break;
 370  370                  }
 371  371          }
 372  372  
 373  373          /*
 374  374           * Print an array entry for each error number:
 375  375           */
 376  376          max = errnum_max(native_errors);
 377  377          for (fval = 0; fval <= max; fval++) {
 378  378                  const char *fname;
 379  379                  const char *tname = NULL;
 380  380                  int32_t tval;
 381  381                  const char *msg = NULL;
 382  382                  const char *comma = (fval != max) ? "," : "";
 383  383  
 384  384                  if (errname_by_num(native_errors, fval, &fname) == -1) {
 385  385                          fname = NULL;
 386  386                  }
 387  387  
 388  388                  if (fval == 0) {
 389  389                          /*
 390  390                           * The error number "0" is special: it means no worries.
 391  391                           */
 392  392                          msg = "No Error";
 393  393                          tval = 0;
 394  394                  } else if (fname == NULL) {
 395  395                          /*
 396  396                           * There is no defined name for this error number; it
 397  397                           * is unused.
 398  398                           */
 399  399                          msg = "Unused Number";
 400  400                          tval = -1;
 401  401                  } else {
 402  402                          /*
 403  403                           * Check if we want to override the name of this error
 404  404                           * in the foreign error number lookup:
 405  405                           */
 406  406                          const char *oname = lookup_override(fname);
 407  407  
 408  408                          /*
 409  409                           * Do the lookup:
 410  410                           */
 411  411                          if (errno_by_name(foreign_errors, oname != NULL ?
 412  412                              oname : fname, &tval, &tname) != 0) {
 413  413                                  /*
 414  414                                   * There was no foreign error number by that
 415  415                                   * name.
 416  416                                   */
 417  417                                  tname = "No Analogue";
 418  418                                  tval = -2;
 419  419                          }
 420  420                  }
 421  421  
 422  422                  if (msg == NULL) {
 423  423                          size_t flen = strlen(fname);
 424  424                          size_t tlen = strlen(tname);
 425  425                          const char *t = flen > 7 ? "\t" : "\t\t";
 426  426                          const char *tt = tlen < 7 ? "\t\t\t" : tlen < 15 ?
 427  427                              "\t\t" : "\t";
 428  428  
 429  429                          (void) fprintf(stdout, "\t%d%s\t/* %3d: %s%s--> %3d: "
 430  430                              "%s%s*/\n", tval, comma, fval, fname, t, tval,
 431  431                              tname, tt);
 432  432                  } else {
 433  433                          const char *t = "\t\t\t\t\t";
 434  434  
 435  435                          (void) fprintf(stdout, "\t%d%s\t/* %3d: %s%s*/\n", tval,
 436  436                              comma, fval, msg, t);
 437  437                  }
 438  438          }
 439  439  
 440  440          (void) nvlist_free(native_errors);
 441  441          (void) nvlist_free(foreign_errors);
 442  442  
 443  443          return (0);
 444  444  }
  
    | 
      ↓ open down ↓ | 
    444 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX