Print this page
    
NEX-14051 Be careful with RPC groups
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
8085 Handle RPC groups better
Reviewed by: "Joshua M. Clulow" <josh@sysmgr.org>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/fs.d/nfs/rquotad/rpc.rquotad.c
          +++ new/usr/src/cmd/fs.d/nfs/rquotad/rpc.rquotad.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
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2017 Joyent Inc
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27   27  /* All Rights Reserved */
  28   28  
  29   29  #include <stdio.h>
  30   30  #include <stdlib.h>
  31   31  #include <signal.h>
  32   32  #include <syslog.h>
  33   33  #include <string.h>
  34   34  #include <stropts.h>
  35   35  #include <errno.h>
  36   36  #include <sys/netconfig.h>
  37   37  #include <sys/mntent.h>
  38   38  #include <sys/mnttab.h>
  39   39  #include <sys/param.h>
  40   40  #include <sys/time.h>
  41   41  #include <sys/debug.h>
  42   42  #ifdef notdef
  43   43  #include <netconfig.h>
  44   44  #endif
  45   45  #include <sys/stat.h>
  46   46  #include <sys/file.h>
  47   47  #include <sys/fs/ufs_quota.h>
  48   48  #include <netdir.h>
  49   49  #include <rpc/rpc.h>
  50   50  #include <rpcsvc/rquota.h>
  51   51  #include <tiuser.h>
  52   52  #include <unistd.h>
  53   53  #include <dlfcn.h>
  54   54  #include <libzfs.h>
  55   55  
  56   56  #define QFNAME          "quotas"        /* name of quota file */
  57   57  #define RPCSVC_CLOSEDOWN 120            /* 2 minutes */
  58   58  
  59   59  struct fsquot {
  60   60          char *fsq_fstype;
  61   61          struct fsquot *fsq_next;
  62   62          char *fsq_dir;
  63   63          char *fsq_devname;
  64   64          dev_t fsq_dev;
  65   65  };
  66   66  
  67   67  struct fsquot *fsqlist = NULL;
  68   68  
  69   69  typedef struct authunix_parms *authp;
  70   70  
  71   71  static int request_pending;             /* Request in progress ? */
  72   72  
  73   73  void closedown();
  74   74  void dispatch();
  75   75  struct fsquot *findfsq();
  76   76  void freefs();
  77   77  int  getdiskquota();
  78   78  void getquota();
  79   79  int  hasquota();
  80   80  void log_cant_reply();
  81   81  void setupfs();
  82   82  static void zexit(int) __NORETURN;
  83   83  
  84   84  static libzfs_handle_t *(*_libzfs_init)(void);
  85   85  static void (*_libzfs_fini)(libzfs_handle_t *);
  86   86  static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
  87   87  static void (*_zfs_close)(zfs_handle_t *);
  88   88  static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
  89   89      uint64_t *);
  90   90  static libzfs_handle_t *g_zfs = NULL;
  91   91  
  92   92  /*
  93   93   * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
  94   94   * packages.  'rquotad' supports zfs as an option.
  95   95   */
  96   96  static void
  97   97  load_libzfs(void)
  98   98  {
  99   99          void *hdl;
 100  100  
 101  101          if (g_zfs != NULL)
 102  102                  return;
 103  103  
 104  104          if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
 105  105                  _libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
 106  106                      "libzfs_init");
 107  107                  _libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
 108  108                  _zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
 109  109                  _zfs_close = (void (*)())dlsym(hdl, "zfs_close");
 110  110                  _zfs_prop_get_userquota_int = (int (*)())
 111  111                      dlsym(hdl, "zfs_prop_get_userquota_int");
 112  112  
 113  113                  if (_libzfs_init && _libzfs_fini && _zfs_open &&
 114  114                      _zfs_close && _zfs_prop_get_userquota_int)
 115  115                          g_zfs = _libzfs_init();
 116  116          }
 117  117  }
 118  118  
 119  119  /*ARGSUSED*/
 120  120  int
 121  121  main(int argc, char *argv[])
 122  122  {
 123  123          register SVCXPRT *transp;
 124  124  
 125  125          load_libzfs();
 126  126  
 127  127          /*
 128  128           * If stdin looks like a TLI endpoint, we assume
 129  129           * that we were started by a port monitor. If
 130  130           * t_getstate fails with TBADF, this is not a
 131  131           * TLI endpoint.
 132  132           */
 133  133          if (t_getstate(0) != -1 || t_errno != TBADF) {
 134  134                  char *netid;
 135  135                  struct netconfig *nconf = NULL;
 136  136  
 137  137                  openlog("rquotad", LOG_PID, LOG_DAEMON);
 138  138  
 139  139                  if ((netid = getenv("NLSPROVIDER")) == NULL) {
 140  140                          struct t_info tinfo;
 141  141  
 142  142                          if (t_sync(0) == -1) {
 143  143                                  syslog(LOG_ERR, "could not do t_sync");
 144  144                                  zexit(1);
 145  145                          }
 146  146                          if (t_getinfo(0, &tinfo) == -1) {
 147  147                                  syslog(LOG_ERR, "t_getinfo failed");
 148  148                                  zexit(1);
 149  149                          }
 150  150                          if (tinfo.servtype == T_CLTS) {
 151  151                                  if (tinfo.addr == INET_ADDRSTRLEN)
 152  152                                          netid = "udp";
 153  153                                  else
 154  154                                          netid = "udp6";
 155  155                          } else {
 156  156                                  syslog(LOG_ERR, "wrong transport");
 157  157                                  zexit(1);
 158  158                          }
 159  159                  }
 160  160                  if ((nconf = getnetconfigent(netid)) == NULL) {
 161  161                          syslog(LOG_ERR, "cannot get transport info");
 162  162                  }
 163  163  
 164  164                  if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
 165  165                          syslog(LOG_ERR, "cannot create server handle");
 166  166                          zexit(1);
 167  167                  }
 168  168                  if (nconf)
 169  169                          freenetconfigent(nconf);
 170  170  
 171  171                  if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, dispatch, 0)) {
 172  172                          syslog(LOG_ERR,
 173  173                              "unable to register (RQUOTAPROG, RQUOTAVERS).");
 174  174                          zexit(1);
 175  175                  }
 176  176  
 177  177                  (void) sigset(SIGALRM, (void(*)(int)) closedown);
 178  178                  (void) alarm(RPCSVC_CLOSEDOWN);
 179  179  
 180  180                  svc_run();
 181  181                  zexit(1);
 182  182                  /* NOTREACHED */
 183  183          }
 184  184  
 185  185          /*
 186  186           * Started from a shell - fork the daemon.
 187  187           */
 188  188  
 189  189          switch (fork()) {
 190  190          case 0:         /* child */
 191  191                  break;
 192  192          case -1:
 193  193                  perror("rquotad: can't fork");
 194  194                  zexit(1);
 195  195          default:        /* parent */
 196  196                  zexit(0);
 197  197          }
 198  198  
 199  199          /*
 200  200           * Close existing file descriptors, open "/dev/null" as
 201  201           * standard input, output, and error, and detach from
 202  202           * controlling terminal.
 203  203           */
 204  204          closefrom(0);
 205  205          (void) open("/dev/null", O_RDONLY);
 206  206          (void) open("/dev/null", O_WRONLY);
 207  207          (void) dup(1);
 208  208          (void) setsid();
 209  209  
 210  210          openlog("rquotad", LOG_PID, LOG_DAEMON);
 211  211  
 212  212          /*
 213  213           * Create datagram service
 214  214           */
 215  215          if (svc_create(dispatch, RQUOTAPROG, RQUOTAVERS, "datagram_v") == 0) {
 216  216                  syslog(LOG_ERR, "couldn't register datagram_v service");
 217  217                  zexit(1);
 218  218          }
 219  219  
 220  220          /*
 221  221           * Start serving
 222  222           */
 223  223          svc_run();
 224  224          syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
 225  225          return (1);
 226  226  }
 227  227  
 228  228  void
 229  229  dispatch(rqstp, transp)
 230  230          register struct svc_req *rqstp;
 231  231          register SVCXPRT *transp;
 232  232  {
 233  233  
 234  234          request_pending = 1;
 235  235  
 236  236          switch (rqstp->rq_proc) {
 237  237          case NULLPROC:
 238  238                  errno = 0;
 239  239                  if (!svc_sendreply(transp, xdr_void, 0))
 240  240                          log_cant_reply(transp);
 241  241                  break;
 242  242  
 243  243          case RQUOTAPROC_GETQUOTA:
 244  244          case RQUOTAPROC_GETACTIVEQUOTA:
 245  245                  getquota(rqstp, transp);
 246  246                  break;
 247  247  
 248  248          default:
 249  249                  svcerr_noproc(transp);
 250  250                  break;
 251  251          }
 252  252  
 253  253          request_pending = 0;
 254  254  }
 255  255  
 256  256  void
 257  257  closedown()
 258  258  {
 259  259          if (!request_pending) {
 260  260                  int i, openfd;
 261  261                  struct t_info tinfo;
 262  262  
 263  263                  if (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))
 264  264                          zexit(0);
 265  265  
 266  266                  for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++) {
 267  267                          if (svc_pollfd[i].fd >= 0)
 268  268                                  openfd++;
 269  269                  }
 270  270  
 271  271                  if (openfd <= 1)
 272  272                          zexit(0);
 273  273          }
 274  274          (void) alarm(RPCSVC_CLOSEDOWN);
 275  275  }
 276  276  
 277  277  static int
 278  278  getzfsquota(uid_t user, char *dataset, struct dqblk *zq)
 279  279  {
 280  280          zfs_handle_t *zhp = NULL;
 281  281          char propname[ZFS_MAXPROPLEN];
 282  282          uint64_t userquota, userused;
 283  283  
 284  284          if (g_zfs == NULL)
 285  285                  return (1);
 286  286  
 287  287          if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL) {
 288  288                  syslog(LOG_ERR, "can not open zfs dataset %s", dataset);
 289  289                  return (1);
 290  290          }
 291  291  
 292  292          (void) snprintf(propname, sizeof (propname), "userquota@%u", user);
 293  293          if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
 294  294                  _zfs_close(zhp);
 295  295                  return (1);
 296  296          }
 297  297  
 298  298          (void) snprintf(propname, sizeof (propname), "userused@%u", user);
 299  299          if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
 300  300                  _zfs_close(zhp);
 301  301                  return (1);
 302  302          }
 303  303  
 304  304          zq->dqb_bhardlimit = userquota / DEV_BSIZE;
 305  305          zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
 306  306          zq->dqb_curblocks = userused / DEV_BSIZE;
 307  307          _zfs_close(zhp);
 308  308          return (0);
 309  309  }
 310  310  
 311  311  void
 312  312  getquota(rqstp, transp)
  
    | 
      ↓ open down ↓ | 
    312 lines elided | 
    
      ↑ open up ↑ | 
  
 313  313          register struct svc_req *rqstp;
 314  314          register SVCXPRT *transp;
 315  315  {
 316  316          struct getquota_args gqa;
 317  317          struct getquota_rslt gqr;
 318  318          struct dqblk dqblk;
 319  319          struct fsquot *fsqp;
 320  320          struct timeval tv;
 321  321          bool_t qactive;
 322  322  
      323 +        CTASSERT(sizeof (authp) <= RQCRED_SIZE);
      324 +
 323  325          gqa.gqa_pathp = NULL;           /* let xdr allocate the storage */
 324  326          if (!svc_getargs(transp, xdr_getquota_args, (caddr_t)&gqa)) {
 325  327                  svcerr_decode(transp);
 326  328                  return;
 327  329          }
 328  330          /*
 329  331           * This authentication is really bogus with the current rpc
 330  332           * authentication scheme. One day we will have something for real.
 331  333           */
 332  334          CTASSERT(sizeof (authp) <= RQCRED_SIZE);
 333  335          if (rqstp->rq_cred.oa_flavor != AUTH_UNIX ||
 334  336              (((authp) rqstp->rq_clntcred)->aup_uid != 0 &&
 335  337                  ((authp) rqstp->rq_clntcred)->aup_uid != (uid_t)gqa.gqa_uid)) {
 336  338                  gqr.status = Q_EPERM;
 337  339                  goto sendreply;
 338  340          }
 339  341          fsqp = findfsq(gqa.gqa_pathp);
 340  342          if (fsqp == NULL) {
 341  343                  gqr.status = Q_NOQUOTA;
 342  344                  goto sendreply;
 343  345          }
 344  346  
 345  347          bzero(&dqblk, sizeof (dqblk));
 346  348          if (strcmp(fsqp->fsq_fstype, MNTTYPE_ZFS) == 0) {
 347  349                  if (getzfsquota(gqa.gqa_uid, fsqp->fsq_devname, &dqblk)) {
 348  350                          gqr.status = Q_NOQUOTA;
 349  351                          goto sendreply;
 350  352                  }
 351  353                  qactive = TRUE;
 352  354          } else {
 353  355                  if (quotactl(Q_GETQUOTA, fsqp->fsq_dir,
 354  356                      (uid_t)gqa.gqa_uid, &dqblk) != 0) {
 355  357                          qactive = FALSE;
 356  358                          if ((errno == ENOENT) ||
 357  359                              (rqstp->rq_proc != RQUOTAPROC_GETQUOTA)) {
 358  360                                  gqr.status = Q_NOQUOTA;
 359  361                                  goto sendreply;
 360  362                          }
 361  363  
 362  364                          /*
 363  365                           * If there is no quotas file, don't bother to sync it.
 364  366                           */
 365  367                          if (errno != ENOENT) {
 366  368                                  if (quotactl(Q_ALLSYNC, fsqp->fsq_dir,
 367  369                                      (uid_t)gqa.gqa_uid, &dqblk) < 0 &&
 368  370                                      errno == EINVAL)
 369  371                                          syslog(LOG_WARNING,
 370  372                                              "Quotas are not compiled "
 371  373                                              "into this kernel");
 372  374                                  if (getdiskquota(fsqp, (uid_t)gqa.gqa_uid,
 373  375                                      &dqblk) == 0) {
 374  376                                          gqr.status = Q_NOQUOTA;
 375  377                                          goto sendreply;
 376  378                                  }
 377  379                          }
 378  380                  } else {
 379  381                          qactive = TRUE;
 380  382                  }
 381  383                  /*
 382  384                   * We send the remaining time instead of the absolute time
 383  385                   * because clock skew between machines should be much greater
 384  386                   * than rpc delay.
 385  387                   */
 386  388  #define gqrslt getquota_rslt_u.gqr_rquota
 387  389  
 388  390                  gettimeofday(&tv, NULL);
 389  391                  gqr.gqrslt.rq_btimeleft = dqblk.dqb_btimelimit - tv.tv_sec;
 390  392                  gqr.gqrslt.rq_ftimeleft = dqblk.dqb_ftimelimit - tv.tv_sec;
 391  393          }
 392  394  
 393  395          gqr.status = Q_OK;
 394  396          gqr.gqrslt.rq_active    = qactive;
 395  397          gqr.gqrslt.rq_bsize     = DEV_BSIZE;
 396  398          gqr.gqrslt.rq_bhardlimit = dqblk.dqb_bhardlimit;
 397  399          gqr.gqrslt.rq_bsoftlimit = dqblk.dqb_bsoftlimit;
 398  400          gqr.gqrslt.rq_curblocks = dqblk.dqb_curblocks;
 399  401          gqr.gqrslt.rq_fhardlimit = dqblk.dqb_fhardlimit;
 400  402          gqr.gqrslt.rq_fsoftlimit = dqblk.dqb_fsoftlimit;
 401  403          gqr.gqrslt.rq_curfiles  = dqblk.dqb_curfiles;
 402  404  sendreply:
 403  405          errno = 0;
 404  406          if (!svc_sendreply(transp, xdr_getquota_rslt, (caddr_t)&gqr))
 405  407                  log_cant_reply(transp);
 406  408  }
 407  409  
 408  410  int
 409  411  quotactl(cmd, mountp, uid, dqp)
 410  412          int     cmd;
 411  413          char    *mountp;
 412  414          uid_t   uid;
 413  415          struct dqblk *dqp;
 414  416  {
 415  417          int             fd;
 416  418          int             status;
 417  419          struct quotctl  quota;
 418  420          char            mountpoint[256];
 419  421          FILE            *fstab;
 420  422          struct mnttab   mntp;
 421  423  
 422  424          if ((mountp == NULL) && (cmd == Q_ALLSYNC)) {
 423  425                  /*
 424  426                   * Find the mount point of any ufs file system. this is
 425  427                   * because the ioctl that implements the quotactl call has
 426  428                   * to go to a real file, and not to the block device.
 427  429                   */
 428  430                  if ((fstab = fopen(MNTTAB, "r")) == NULL) {
 429  431                          syslog(LOG_ERR, "can not open %s: %m ", MNTTAB);
 430  432                          return (-1);
 431  433                  }
 432  434                  fd = -1;
 433  435                  while ((status = getmntent(fstab, &mntp)) == NULL) {
 434  436                          if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
 435  437                                  !(hasmntopt(&mntp, MNTOPT_RQ) ||
 436  438                                  hasmntopt(&mntp, MNTOPT_QUOTA)))
 437  439                                  continue;
 438  440                          (void) strlcpy(mountpoint, mntp.mnt_mountp,
 439  441                              sizeof (mountpoint));
 440  442                          strcat(mountpoint, "/quotas");
 441  443                          if ((fd = open64(mountpoint, O_RDWR)) >= 0)
 442  444                                  break;
 443  445                  }
 444  446                  fclose(fstab);
 445  447                  if (fd == -1) {
 446  448                          errno = ENOENT;
 447  449                          return (-1);
 448  450                  }
 449  451          } else {
 450  452                  if (mountp == NULL || mountp[0] == '\0') {
 451  453                          errno = ENOENT;
 452  454                          return (-1);
 453  455                  }
 454  456                  (void) strlcpy(mountpoint, mountp, sizeof (mountpoint));
 455  457                  strcat(mountpoint, "/quotas");
 456  458  
 457  459                  if ((fd = open64(mountpoint, O_RDONLY)) < 0) {
 458  460                          errno = ENOENT;
 459  461                          syslog(LOG_ERR, "can not open %s: %m ", mountpoint);
 460  462                          return (-1);
 461  463                  }
 462  464          }
 463  465          quota.op = cmd;
 464  466          quota.uid = uid;
 465  467          quota.addr = (caddr_t)dqp;
 466  468  
 467  469          status = ioctl(fd, Q_QUOTACTL, "a);
 468  470  
 469  471          close(fd);
 470  472          return (status);
 471  473  }
 472  474  
 473  475  /*
 474  476   * Return the quota information for the given path.  Returns NULL if none
 475  477   * was found.
 476  478   */
 477  479  
 478  480  struct fsquot *
 479  481  findfsq(char *dir)
 480  482  {
 481  483          struct stat sb;
 482  484          struct fsquot *fsqp;
 483  485          static time_t lastmtime = 0;    /* mount table's previous mtime */
 484  486  
 485  487          /*
 486  488           * If we've never looked at the mount table, or it has changed
 487  489           * since the last time, rebuild the list of quota'd file systems
 488  490           * and remember the current mod time for the mount table.
 489  491           */
 490  492  
 491  493          if (stat(MNTTAB, &sb) < 0) {
 492  494                  syslog(LOG_ERR, "can't stat %s: %m", MNTTAB);
 493  495                  return (NULL);
 494  496          }
 495  497          if (lastmtime == 0 || sb.st_mtime != lastmtime) {
 496  498                  freefs();
 497  499                  setupfs();
 498  500                  lastmtime = sb.st_mtime;
 499  501          }
 500  502  
 501  503          /*
 502  504           * Try to find the given path in the list of file systems with
 503  505           * quotas.
 504  506           */
 505  507  
 506  508          if (fsqlist == NULL)
 507  509                  return (NULL);
 508  510          if (stat(dir, &sb) < 0)
 509  511                  return (NULL);
 510  512  
 511  513          for (fsqp = fsqlist; fsqp != NULL; fsqp = fsqp->fsq_next) {
 512  514                  if (sb.st_dev == fsqp->fsq_dev)
 513  515                          return (fsqp);
 514  516          }
 515  517  
 516  518          return (NULL);
 517  519  }
 518  520  
 519  521  static void
 520  522  setup_zfs(struct mnttab *mp)
 521  523  {
 522  524          struct fsquot *fsqp;
 523  525          struct stat sb;
 524  526  
 525  527          if (stat(mp->mnt_mountp, &sb) < 0)
 526  528                  return;
 527  529  
 528  530          fsqp = malloc(sizeof (struct fsquot));
 529  531          if (fsqp == NULL) {
 530  532                  syslog(LOG_ERR, "out of memory");
 531  533                  zexit(1);
 532  534          }
 533  535          fsqp->fsq_dir = strdup(mp->mnt_mountp);
 534  536          fsqp->fsq_devname = strdup(mp->mnt_special);
 535  537          if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
 536  538                  syslog(LOG_ERR, "out of memory");
 537  539                  zexit(1);
 538  540          }
 539  541  
 540  542          fsqp->fsq_fstype = MNTTYPE_ZFS;
 541  543          fsqp->fsq_dev = sb.st_dev;
 542  544          fsqp->fsq_next = fsqlist;
 543  545          fsqlist = fsqp;
 544  546  }
 545  547  
 546  548  void
 547  549  setupfs()
 548  550  {
 549  551          struct fsquot *fsqp;
 550  552          FILE *mt;
 551  553          struct mnttab m;
 552  554          struct stat sb;
 553  555          char qfilename[MAXPATHLEN];
 554  556  
 555  557          mt = fopen(MNTTAB, "r");
 556  558          if (mt == NULL) {
 557  559                  syslog(LOG_ERR, "can't read %s: %m", MNTTAB);
 558  560                  return;
 559  561          }
 560  562  
 561  563          while (getmntent(mt, &m) == 0) {
 562  564                  if (strcmp(m.mnt_fstype, MNTTYPE_ZFS) == 0) {
 563  565                          setup_zfs(&m);
 564  566                          continue;
 565  567                  }
 566  568  
 567  569                  if (strcmp(m.mnt_fstype, MNTTYPE_UFS) != 0)
 568  570                          continue;
 569  571                  if (!hasquota(m.mnt_mntopts)) {
 570  572                          snprintf(qfilename, sizeof (qfilename), "%s/%s",
 571  573                              m.mnt_mountp, QFNAME);
 572  574                          if (access(qfilename, F_OK) < 0)
 573  575                                  continue;
 574  576                  }
 575  577                  if (stat(m.mnt_special, &sb) < 0 ||
 576  578                      (sb.st_mode & S_IFMT) != S_IFBLK)
 577  579                          continue;
 578  580                  fsqp = malloc(sizeof (struct fsquot));
 579  581                  if (fsqp == NULL) {
 580  582                          syslog(LOG_ERR, "out of memory");
 581  583                          zexit(1);
 582  584                  }
 583  585                  fsqp->fsq_dir = strdup(m.mnt_mountp);
 584  586                  fsqp->fsq_devname = strdup(m.mnt_special);
 585  587                  if (fsqp->fsq_dir == NULL || fsqp->fsq_devname == NULL) {
 586  588                          syslog(LOG_ERR, "out of memory");
 587  589                          zexit(1);
 588  590                  }
 589  591                  fsqp->fsq_fstype = MNTTYPE_UFS;
 590  592                  fsqp->fsq_dev = sb.st_rdev;
 591  593                  fsqp->fsq_next = fsqlist;
 592  594                  fsqlist = fsqp;
 593  595          }
 594  596          (void) fclose(mt);
 595  597  }
 596  598  
 597  599  /*
 598  600   * Free the memory used by the current list of quota'd file systems.  Nulls
 599  601   * out the list.
 600  602   */
 601  603  
 602  604  void
 603  605  freefs()
 604  606  {
 605  607          register struct fsquot *fsqp;
 606  608  
 607  609          while ((fsqp = fsqlist) != NULL) {
 608  610                  fsqlist = fsqp->fsq_next;
 609  611                  free(fsqp->fsq_dir);
 610  612                  free(fsqp->fsq_devname);
 611  613                  free(fsqp);
 612  614          }
 613  615  }
 614  616  
 615  617  int
 616  618  getdiskquota(fsqp, uid, dqp)
 617  619          struct fsquot *fsqp;
 618  620          uid_t uid;
 619  621          struct dqblk *dqp;
 620  622  {
 621  623          int fd;
 622  624          char qfilename[MAXPATHLEN];
 623  625  
 624  626          snprintf(qfilename, sizeof (qfilename), "%s/%s", fsqp->fsq_dir, QFNAME);
 625  627          if ((fd = open64(qfilename, O_RDONLY)) < 0)
 626  628                  return (0);
 627  629          (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
 628  630          if (read(fd, dqp, sizeof (struct dqblk)) != sizeof (struct dqblk)) {
 629  631                  close(fd);
 630  632                  return (0);
 631  633          }
 632  634          close(fd);
 633  635          if (dqp->dqb_bhardlimit == 0 && dqp->dqb_bsoftlimit == 0 &&
 634  636              dqp->dqb_fhardlimit == 0 && dqp->dqb_fsoftlimit == 0) {
 635  637                  return (0);
 636  638          }
 637  639          return (1);
 638  640  }
 639  641  
 640  642  /*
 641  643   * Get the client's hostname from the transport handle
 642  644   * If the name is not available then return "(anon)".
 643  645   */
 644  646  struct nd_hostservlist *
 645  647  getclientsnames(transp)
 646  648          SVCXPRT *transp;
 647  649  {
 648  650          struct netbuf *nbuf;
 649  651          struct netconfig *nconf;
 650  652          static struct nd_hostservlist   *serv;
 651  653          static struct nd_hostservlist   anon_hsl;
 652  654          static struct nd_hostserv       anon_hs;
 653  655          static char anon_hname[] = "(anon)";
 654  656          static char anon_sname[] = "";
 655  657  
 656  658          /* Set up anonymous client */
 657  659          anon_hs.h_host = anon_hname;
 658  660          anon_hs.h_serv = anon_sname;
 659  661          anon_hsl.h_cnt = 1;
 660  662          anon_hsl.h_hostservs = &anon_hs;
 661  663  
 662  664          if (serv) {
 663  665                  netdir_free((char *)serv, ND_HOSTSERVLIST);
 664  666                  serv = NULL;
 665  667          }
 666  668          nconf = getnetconfigent(transp->xp_netid);
 667  669          if (nconf == NULL) {
 668  670                  syslog(LOG_ERR, "%s: getnetconfigent failed",
 669  671                          transp->xp_netid);
 670  672                  return (&anon_hsl);
 671  673          }
 672  674  
 673  675          nbuf = svc_getrpccaller(transp);
 674  676          if (nbuf == NULL) {
 675  677                  freenetconfigent(nconf);
 676  678                  return (&anon_hsl);
 677  679          }
 678  680          if (netdir_getbyaddr(nconf, &serv, nbuf)) {
 679  681                  freenetconfigent(nconf);
 680  682                  return (&anon_hsl);
 681  683          }
 682  684          freenetconfigent(nconf);
 683  685          return (serv);
 684  686  }
 685  687  
 686  688  void
 687  689  log_cant_reply(transp)
 688  690          SVCXPRT *transp;
 689  691  {
 690  692          int saverrno;
 691  693          struct nd_hostservlist *clnames;
 692  694          register char *name;
 693  695  
 694  696          saverrno = errno;       /* save error code */
 695  697          clnames = getclientsnames(transp);
 696  698          if (clnames == NULL)
 697  699                  return;
 698  700          name = clnames->h_hostservs->h_host;
 699  701  
 700  702          errno = saverrno;
 701  703          if (errno == 0)
 702  704                  syslog(LOG_ERR, "couldn't send reply to %s", name);
 703  705          else
 704  706                  syslog(LOG_ERR, "couldn't send reply to %s: %m", name);
 705  707  }
 706  708  
 707  709  char *mntopts[] = { MNTOPT_QUOTA, NULL };
 708  710  #define QUOTA    0
 709  711  
 710  712  /*
 711  713   * Return 1 if "quota" appears in the options string
 712  714   */
 713  715  int
 714  716  hasquota(opts)
 715  717          char *opts;
 716  718  {
 717  719          char *value;
 718  720  
 719  721          if (opts == NULL)
 720  722                  return (0);
 721  723          while (*opts != '\0') {
 722  724                  if (getsubopt(&opts, mntopts, &value) == QUOTA)
 723  725                          return (1);
 724  726          }
 725  727  
 726  728          return (0);
 727  729  }
 728  730  
 729  731  static void
 730  732  zexit(int n)
 731  733  {
 732  734          if (g_zfs != NULL)
 733  735                  _libzfs_fini(g_zfs);
 734  736          exit(n);
 735  737  }
  
    | 
      ↓ open down ↓ | 
    403 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX