Print this page
    
10106 libreparse needs smatch fixes
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/libreparse/common/fs_reparse_lib.c
          +++ new/usr/src/lib/libreparse/common/fs_reparse_lib.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
       27 +/*
       28 + * Copyright (c) 2018, Joyent, Inc.
       29 + */
       30 +
  27   31  #include <stdio.h>
  28   32  #include <stdlib.h>
  29   33  #include <unistd.h>
  30   34  #include <strings.h>
  31   35  #include <string.h>
  32   36  #include <dirent.h>
  33   37  #include <sys/types.h>
  34   38  #include <sys/stat.h>
  35   39  #include <sys/param.h>
  36   40  #include <sys/errno.h>
  37   41  #include <limits.h>
  38   42  #include <libnvpair.h>
  39   43  #include <dlfcn.h>
  40   44  #include <libintl.h>
  41   45  #include <sys/systeminfo.h>
  42   46  #include <sys/fs_reparse.h>
  43   47  #include "rp_plugin.h"
  44   48  
  45   49  #define MAXISALEN       257     /* based on sysinfo(2) man page */
  46   50  
  47   51  static rp_proto_handle_t rp_proto_handle;
  48   52  static rp_proto_plugin_t *rp_proto_list;
  49   53  
  50   54  int rp_plugin_init(void);
  51   55  static void proto_plugin_fini(void);
  52   56  static rp_plugin_ops_t *rp_find_protocol(const char *svctype);
  53   57  
  54   58  extern int errno;
  55   59  static int rp_plugin_inited = 0;
  56   60  
  57   61  /*
  58   62   * reparse_create()
  59   63   *
  60   64   * Create a symlink at the specified 'path' as a reparse point.
  61   65   * This function will fail if path refers to an existing file system
  62   66   * object or an object named string already exists at the given path.
  63   67   *
  64   68   * return 0 if ok else return error code.
  65   69   */
  66   70  int
  67   71  reparse_create(const char *path, const char *data)
  68   72  {
  69   73          int err;
  70   74          struct stat sbuf;
  71   75  
  72   76          if (path == NULL || data == NULL)
  73   77                  return (EINVAL);
  74   78  
  75   79          if ((err = reparse_validate(data)) != 0)
  76   80                  return (err);
  77   81  
  78   82          /* check if object exists */
  79   83          if (lstat(path, &sbuf) == 0)
  80   84                  return (EEXIST);
  81   85  
  82   86          return (symlink(data, path) ? errno : 0);
  83   87  }
  84   88  
  85   89  /*
  86   90   * reparse_unparse()
  87   91   *
  88   92   * Convert an nvlist back to a string format suitable to write
  89   93   * to the reparse point symlink body.  The string returned is in
  90   94   * allocated memory and must be freed by the caller.
  91   95   *
  92   96   * return 0 if ok else return error code.
  93   97   */
  94   98  int
  95   99  reparse_unparse(nvlist_t *nvl, char **stringp)
  96  100  {
  97  101          int err, buflen;
  98  102          char *buf, *stype, *val;
  99  103          nvpair_t *curr;
 100  104  
 101  105          if (nvl == NULL || stringp == NULL ||
 102  106              ((curr = nvlist_next_nvpair(nvl, NULL)) == NULL))
 103  107                  return (EINVAL);
 104  108  
 105  109          buflen = SYMLINK_MAX;
 106  110          if ((buf = malloc(buflen)) == NULL)
 107  111                  return (ENOMEM);
 108  112  
 109  113          err = 0;
 110  114          (void) snprintf(buf, buflen, "%s", FS_REPARSE_TAG_STR);
 111  115          while (curr != NULL) {
 112  116                  if (!(stype = nvpair_name(curr))) {
 113  117                          err = EINVAL;
 114  118                          break;
 115  119                  }
 116  120                  if ((strlcat(buf, FS_TOKEN_START_STR, buflen) >= buflen) ||
 117  121                      (strlcat(buf, stype, buflen) >= buflen) ||
 118  122                      (strlcat(buf, ":", buflen) >= buflen) ||
 119  123                      (nvpair_value_string(curr, &val) != 0) ||
 120  124                      (strlcat(buf, val, buflen) >= buflen) ||
 121  125                      (strlcat(buf, FS_TOKEN_END_STR, buflen) >= buflen)) {
 122  126                          err = E2BIG;
 123  127                          break;
 124  128                  }
 125  129                  curr = nvlist_next_nvpair(nvl, curr);
 126  130          }
 127  131          if (err != 0) {
 128  132                  free(buf);
 129  133                  return (err);
 130  134          }
 131  135          if (strlcat(buf, FS_REPARSE_TAG_END_STR, buflen) >= buflen) {
 132  136                  free(buf);
 133  137                  return (E2BIG);
 134  138          }
 135  139  
 136  140          *stringp = buf;
 137  141          return (0);
 138  142  }
 139  143  
 140  144  /*
 141  145   * reparse_deref()
 142  146   *
 143  147   * Accepts the service-specific item from the reparse point and returns
 144  148   * the service-specific data requested.  The caller specifies the size
 145  149   * of the buffer provided via *bufsz.
 146  150   *
 147  151   * if ok return 0 and *bufsz is updated to contain the actual length of
 148  152   * the returned results, else return error code. If the error code is
 149  153   * EOVERFLOW; results do not fit in the buffer, *bufsz will be updated
 150  154   * to contain the number of bytes needed to hold the results.
 151  155   */
 152  156  int
 153  157  reparse_deref(const char *svc_type, const char *svc_data, char *buf,
 154  158      size_t *bufsz)
 155  159  {
 156  160          rp_plugin_ops_t *ops;
 157  161  
 158  162          if ((svc_type == NULL) || (svc_data == NULL) || (buf == NULL) ||
 159  163              (bufsz == NULL))
 160  164                  return (EINVAL);
 161  165  
 162  166          ops = rp_find_protocol(svc_type);
 163  167          if ((ops != NULL) && (ops->rpo_deref != NULL))
 164  168                  return (ops->rpo_deref(svc_type, svc_data, buf, bufsz));
 165  169  
 166  170          /* no plugin, return error */
 167  171          return (ENOTSUP);
 168  172  }
 169  173  
 170  174  /*
 171  175   * reparse_delete()
 172  176   *
 173  177   * Delete a reparse point at a given pathname.  It will fail if
 174  178   * a reparse point does not exist at the given path or the pathname
 175  179   * is not a symlink.
 176  180   *
 177  181   * return 0 if ok else return error code.
 178  182   */
 179  183  int
 180  184  reparse_delete(const char *path)
 181  185  {
 182  186          struct stat sbuf;
 183  187  
 184  188          if (path == NULL)
 185  189                  return (EINVAL);
 186  190  
 187  191          /* check if object exists */
 188  192          if (lstat(path, &sbuf) != 0)
 189  193                  return (errno);
 190  194  
 191  195          if ((sbuf.st_mode & S_IFLNK) != S_IFLNK)
 192  196                  return (EINVAL);
 193  197  
 194  198          return (unlink(path) ? errno : 0);
 195  199  }
 196  200  
 197  201  /*
 198  202   * reparse_add()
 199  203   *
 200  204   * Add a service type entry to a nvlist with a copy of svc_data,
 201  205   * replacing one of the same type if already present.
 202  206   *
 203  207   * return 0 if ok else return error code.
 204  208   */
 205  209  int
 206  210  reparse_add(nvlist_t *nvl, const char *svc_type, const char *svc_data)
 207  211  {
 208  212          int err;
 209  213          char *buf;
 210  214          size_t bufsz;
 211  215          rp_plugin_ops_t *ops;
 212  216  
 213  217          if ((nvl == NULL) || (svc_type == NULL) || (svc_data == NULL))
 214  218                  return (EINVAL);
 215  219  
 216  220          bufsz = SYMLINK_MAX;            /* no need to mess around */
 217  221          if ((buf = malloc(bufsz)) == NULL)
 218  222                  return (ENOMEM);
 219  223  
 220  224          ops = rp_find_protocol(svc_type);
 221  225          if ((ops != NULL) && (ops->rpo_form != NULL))
 222  226                  err = ops->rpo_form(svc_type, svc_data, buf, &bufsz);
 223  227          else
 224  228                  err = ENOTSUP;          /* no plugin */
 225  229  
 226  230          if (err != 0) {
 227  231                  free(buf);
 228  232                  return (err);
 229  233          }
 230  234  
 231  235          err =  nvlist_add_string(nvl, svc_type, buf);
 232  236          free(buf);
 233  237          return (err);
 234  238  }
 235  239  
 236  240  /*
 237  241   * reparse_remove()
 238  242   *
 239  243   * Remove a service type entry from the nvlist, if present.
 240  244   *
 241  245   * return 0 if ok else return error code.
 242  246   */
 243  247  int
 244  248  reparse_remove(nvlist_t *nvl, const char *svc_type)
 245  249  {
 246  250          if ((nvl == NULL) || (svc_type == NULL))
 247  251                  return (EINVAL);
 248  252  
 249  253          return (nvlist_remove_all(nvl, svc_type));
 250  254  }
 251  255  
 252  256  /*
 253  257   * Returns true if name is "." or "..", otherwise returns false.
 254  258   */
 255  259  static boolean_t
 256  260  rp_is_dot_or_dotdot(const char *name)
 257  261  {
 258  262          if (*name != '.')
 259  263                  return (B_FALSE);
 260  264  
 261  265          if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))
 262  266                  return (B_TRUE);
 263  267  
 264  268          return (B_FALSE);
 265  269  }
 266  270  
  
    | 
      ↓ open down ↓ | 
    230 lines elided | 
    
      ↑ open up ↑ | 
  
 267  271  static void
 268  272  proto_plugin_fini()
 269  273  {
 270  274          rp_proto_plugin_t *p;
 271  275  
 272  276          /*
 273  277           * Protocols may call this framework during _fini
 274  278           */
 275  279          for (p = rp_proto_list; p != NULL; p = p->plugin_next) {
 276  280                  if (p->plugin_ops->rpo_fini)
 277      -                        p->plugin_ops->rpo_fini();
      281 +                        (void) p->plugin_ops->rpo_fini();
 278  282          }
 279  283          while ((p = rp_proto_list) != NULL) {
 280  284                  rp_proto_list = p->plugin_next;
 281  285                  if (p->plugin_handle != NULL)
 282  286                          (void) dlclose(p->plugin_handle);
 283  287                  free(p);
 284  288          }
 285  289  
 286  290          if (rp_proto_handle.rp_ops != NULL) {
 287  291                  free(rp_proto_handle.rp_ops);
 288  292                  rp_proto_handle.rp_ops = NULL;
 289  293          }
 290  294          rp_proto_handle.rp_num_proto = 0;
 291  295  }
 292  296  
 293  297  /*
 294  298   * rp_plugin_init()
 295  299   *
 296  300   * Initialize the service type specific plugin modules.
 297  301   * For each reparse service type, there should be a plugin library for it.
 298  302   * This function walks /usr/lib/reparse directory for plugin libraries.
 299  303   * For each plugin library found, initialize it and add it to the internal
 300  304   * list of service type plugin. These are used for service type specific
 301  305   * operations.
 302  306   */
 303  307  int
 304  308  rp_plugin_init()
 305  309  {
 306  310          int err, ret = RP_OK;
 307  311          char isa[MAXISALEN], dirpath[MAXPATHLEN], path[MAXPATHLEN];
 308  312          int num_protos = 0;
 309  313          rp_proto_handle_t *rp_hdl;
 310  314          rp_proto_plugin_t *proto, *tmp;
 311  315          rp_plugin_ops_t *plugin_ops;
 312  316          struct stat st;
 313  317          void *dlhandle;
 314  318          DIR *dir;
 315  319          struct dirent *dent;
 316  320  
 317  321  #if defined(_LP64)
 318  322          if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
 319  323                  isa[0] = '\0';
 320  324  #else
 321  325          isa[0] = '\0';
 322  326  #endif
 323  327  
 324  328          (void) snprintf(dirpath, MAXPATHLEN,
 325  329              "%s/%s", RP_LIB_DIR, isa);
 326  330  
 327  331          if ((dir = opendir(dirpath)) == NULL)
 328  332                  return (RP_NO_PLUGIN_DIR);
 329  333  
 330  334          while ((dent = readdir(dir)) != NULL) {
 331  335                  if (rp_is_dot_or_dotdot(dent->d_name))
 332  336                          continue;
 333  337  
 334  338                  (void) snprintf(path, MAXPATHLEN,
 335  339                      "%s/%s", dirpath, dent->d_name);
 336  340  
 337  341                  /*
 338  342                   * If file doesn't exist, don't try to map it
 339  343                   */
 340  344                  if (stat(path, &st) < 0)
 341  345                          continue;
 342  346                  if ((dlhandle = dlopen(path, RTLD_FIRST|RTLD_LAZY)) == NULL)
 343  347                          continue;
 344  348  
 345  349                  plugin_ops = (rp_plugin_ops_t *)
 346  350                      dlsym(dlhandle, "rp_plugin_ops");
 347  351                  if (plugin_ops == NULL) {
 348  352                          (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
 349  353                              "Error in plugin ops for service type %s\n%s\n"),
 350  354                              dent->d_name, dlerror());
 351  355                          (void) dlclose(dlhandle);
 352  356                          continue;
 353  357                  }
 354  358                  proto = (rp_proto_plugin_t *)
 355  359                      calloc(1, sizeof (rp_proto_plugin_t));
 356  360                  if (proto == NULL) {
 357  361                          (void) dlclose(dlhandle);
 358  362                          (void) fprintf(stderr,
 359  363                              dgettext(TEXT_DOMAIN, "No memory for plugin %s\n"),
 360  364                              dent->d_name);
 361  365                          ret = RP_NO_MEMORY;
 362  366                          break;
 363  367                  }
 364  368  
 365  369                  proto->plugin_ops = plugin_ops;
 366  370                  proto->plugin_handle = dlhandle;
 367  371                  num_protos++;
 368  372                  proto->plugin_next = rp_proto_list;
 369  373                  rp_proto_list = proto;
 370  374          }
 371  375  
 372  376          (void) closedir(dir);
 373  377  
 374  378          if ((num_protos == 0) && (ret == 0))
 375  379                  ret = RP_NO_PLUGIN;
 376  380          /*
 377  381           * There was an error, so cleanup prior to return of failure.
 378  382           */
 379  383          if (ret != RP_OK) {
 380  384                  proto_plugin_fini();
 381  385                  return (ret);
 382  386          }
 383  387  
 384  388          rp_proto_handle.rp_ops = (rp_plugin_ops_t **)calloc(num_protos,
 385  389              sizeof (rp_plugin_ops_t *));
 386  390          if (!rp_proto_handle.rp_ops) {
 387  391                  proto_plugin_fini();
 388  392                  return (RP_NO_MEMORY);
 389  393          }
 390  394  
 391  395          rp_hdl = &rp_proto_handle;
 392  396          rp_hdl->rp_num_proto = 0;
 393  397          for (tmp = rp_proto_list; rp_hdl->rp_num_proto < num_protos &&
 394  398              tmp != NULL; tmp = tmp->plugin_next) {
 395  399  
 396  400                  err = RP_OK;
 397  401                  if (tmp->plugin_ops->rpo_init != NULL)
 398  402                          err = tmp->plugin_ops->rpo_init();
 399  403                  if (err != RP_OK)
 400  404                          continue;
 401  405                  rp_hdl->rp_ops[rp_hdl->rp_num_proto++] = tmp->plugin_ops;
 402  406          }
 403  407  
 404  408          return (rp_hdl->rp_num_proto > 0 ? RP_OK : RP_NO_PLUGIN);
 405  409  }
 406  410  
 407  411  
 408  412  /*
 409  413   * find_protocol()
 410  414   *
 411  415   * Search the plugin list for the specified protocol and return the
 412  416   * ops vector.  return NULL if protocol is not defined.
 413  417   */
 414  418  static rp_plugin_ops_t *
 415  419  rp_find_protocol(const char *svc_type)
 416  420  {
 417  421          int i;
 418  422          rp_plugin_ops_t *ops = NULL;
 419  423  
 420  424          if (svc_type == NULL)
 421  425                  return (NULL);
 422  426  
 423  427          if (rp_plugin_inited == 0) {
 424  428                  if (rp_plugin_init() == RP_OK)
 425  429                          rp_plugin_inited = 1;
 426  430                  else
 427  431                          return (NULL);
 428  432          }
 429  433  
 430  434          for (i = 0; i < rp_proto_handle.rp_num_proto; i++) {
 431  435                  ops = rp_proto_handle.rp_ops[i];
 432  436                  if (ops->rpo_supports_svc(svc_type))
 433  437                          return (ops);
 434  438  
 435  439          }
 436  440          return (NULL);
 437  441  }
  
    | 
      ↓ open down ↓ | 
    150 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX