Home | History | Annotate | Line # | Download | only in libquota
      1  1.10   hannken /*	$NetBSD: quota_oldfiles.c,v 1.10 2022/04/26 15:36:42 hannken Exp $	*/
      2   1.1  dholland 
      3   1.1  dholland /*
      4   1.1  dholland  * Copyright (c) 1980, 1990, 1993
      5   1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      6   1.1  dholland  *
      7   1.1  dholland  * This code is derived from software contributed to Berkeley by
      8   1.1  dholland  * Robert Elz at The University of Melbourne.
      9   1.1  dholland  *
     10   1.1  dholland  * Redistribution and use in source and binary forms, with or without
     11   1.1  dholland  * modification, are permitted provided that the following conditions
     12   1.1  dholland  * are met:
     13   1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     14   1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     15   1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  dholland  *    documentation and/or other materials provided with the distribution.
     18   1.1  dholland  * 3. Neither the name of the University nor the names of its contributors
     19   1.1  dholland  *    may be used to endorse or promote products derived from this software
     20   1.1  dholland  *    without specific prior written permission.
     21   1.1  dholland  *
     22   1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23   1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26   1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1  dholland  * SUCH DAMAGE.
     33   1.1  dholland  */
     34   1.1  dholland 
     35   1.8  dholland #include <sys/cdefs.h>
     36  1.10   hannken __RCSID("$NetBSD: quota_oldfiles.c,v 1.10 2022/04/26 15:36:42 hannken Exp $");
     37   1.8  dholland 
     38   1.1  dholland #include <sys/types.h>
     39   1.1  dholland #include <sys/stat.h>
     40   1.1  dholland #include <stdio.h>
     41   1.1  dholland #include <stdlib.h>
     42   1.1  dholland #include <string.h>
     43   1.1  dholland #include <unistd.h>
     44   1.1  dholland #include <fcntl.h>
     45   1.1  dholland #include <limits.h>
     46   1.1  dholland #include <fstab.h>
     47   1.1  dholland #include <errno.h>
     48   1.1  dholland #include <err.h>
     49   1.1  dholland 
     50   1.1  dholland #include <ufs/ufs/quota1.h>
     51   1.1  dholland 
     52   1.1  dholland #include <quota.h>
     53   1.1  dholland #include "quotapvt.h"
     54   1.1  dholland 
     55   1.3  dholland struct oldfiles_fstabentry {
     56   1.3  dholland 	char *ofe_mountpoint;
     57   1.3  dholland 	int ofe_hasuserquota;
     58   1.3  dholland 	int ofe_hasgroupquota;
     59   1.3  dholland 	char *ofe_userquotafile;
     60   1.3  dholland 	char *ofe_groupquotafile;
     61   1.3  dholland };
     62   1.3  dholland 
     63   1.1  dholland struct oldfiles_quotacursor {
     64   1.1  dholland 	unsigned oqc_doingusers;
     65   1.1  dholland 	unsigned oqc_doinggroups;
     66   1.1  dholland 
     67   1.1  dholland 	unsigned oqc_numusers;
     68   1.1  dholland 	unsigned oqc_numgroups;
     69   1.1  dholland 
     70   1.1  dholland 	unsigned oqc_didusers;
     71   1.1  dholland 	unsigned oqc_didgroups;
     72   1.1  dholland 	unsigned oqc_diddefault;
     73   1.1  dholland 	unsigned oqc_pos;
     74   1.1  dholland 	unsigned oqc_didblocks;
     75   1.1  dholland };
     76   1.1  dholland 
     77   1.3  dholland static struct oldfiles_fstabentry *__quota_oldfiles_fstab;
     78   1.3  dholland static unsigned __quota_oldfiles_numfstab;
     79   1.3  dholland static unsigned __quota_oldfiles_maxfstab;
     80   1.3  dholland static int __quota_oldfiles_fstab_loaded;
     81   1.3  dholland 
     82   1.3  dholland static const struct oldfiles_fstabentry *
     83   1.3  dholland __quota_oldfiles_find_fstabentry(const char *mountpoint)
     84   1.3  dholland {
     85   1.3  dholland 	unsigned i;
     86   1.3  dholland 
     87   1.3  dholland 	for (i = 0; i < __quota_oldfiles_numfstab; i++) {
     88   1.3  dholland 		if (!strcmp(mountpoint,
     89   1.3  dholland 			    __quota_oldfiles_fstab[i].ofe_mountpoint)) {
     90   1.3  dholland 			return &__quota_oldfiles_fstab[i];
     91   1.3  dholland 		}
     92   1.3  dholland 	}
     93   1.3  dholland 	return NULL;
     94   1.3  dholland }
     95   1.3  dholland 
     96   1.3  dholland static int
     97   1.3  dholland __quota_oldfiles_add_fstabentry(struct oldfiles_fstabentry *ofe)
     98   1.3  dholland {
     99   1.3  dholland 	unsigned newmax;
    100   1.3  dholland 	struct oldfiles_fstabentry *newptr;
    101   1.3  dholland 
    102   1.3  dholland 	if (__quota_oldfiles_numfstab + 1 >= __quota_oldfiles_maxfstab) {
    103   1.3  dholland 		if (__quota_oldfiles_maxfstab == 0) {
    104   1.3  dholland 			newmax = 4;
    105   1.3  dholland 		} else {
    106   1.3  dholland 			newmax = __quota_oldfiles_maxfstab * 2;
    107   1.3  dholland 		}
    108   1.3  dholland 		newptr = realloc(__quota_oldfiles_fstab,
    109   1.3  dholland 				 newmax * sizeof(__quota_oldfiles_fstab[0]));
    110   1.3  dholland 		if (newptr == NULL) {
    111   1.3  dholland 			return -1;
    112   1.3  dholland 		}
    113   1.3  dholland 		__quota_oldfiles_maxfstab = newmax;
    114   1.3  dholland 		__quota_oldfiles_fstab = newptr;
    115   1.3  dholland 	}
    116   1.3  dholland 
    117   1.3  dholland 	__quota_oldfiles_fstab[__quota_oldfiles_numfstab++] = *ofe;
    118   1.3  dholland 	return 0;
    119   1.3  dholland }
    120   1.3  dholland 
    121   1.3  dholland static int
    122   1.3  dholland __quota_oldfiles_fill_fstabentry(const struct fstab *fs,
    123   1.3  dholland 				 struct oldfiles_fstabentry *ofe)
    124   1.3  dholland {
    125   1.4  dholland 	char buf[256];
    126   1.3  dholland 	char *opt, *state, *s;
    127   1.3  dholland 	int serrno;
    128   1.3  dholland 	int ret = 0;
    129   1.3  dholland 
    130   1.3  dholland 	/*
    131   1.3  dholland 	 * Inspect the mount options to find the quota files.
    132   1.3  dholland 	 * XXX this info should be gotten from the kernel.
    133   1.3  dholland 	 *
    134   1.3  dholland 	 * The options are:
    135   1.3  dholland 	 *    userquota[=path]          enable user quotas
    136   1.3  dholland 	 *    groupquota[=path]         enable group quotas
    137   1.3  dholland 	 */
    138   1.3  dholland 
    139   1.3  dholland 	ofe->ofe_mountpoint = NULL;
    140   1.3  dholland 	ofe->ofe_hasuserquota = ofe->ofe_hasgroupquota = 0;
    141   1.3  dholland 	ofe->ofe_userquotafile = ofe->ofe_groupquotafile = NULL;
    142   1.3  dholland 
    143   1.3  dholland 	strlcpy(buf, fs->fs_mntops, sizeof(buf));
    144   1.3  dholland 	for (opt = strtok_r(buf, ",", &state);
    145   1.3  dholland 	     opt != NULL;
    146   1.3  dholland 	     opt = strtok_r(NULL, ",", &state)) {
    147   1.3  dholland 		s = strchr(opt, '=');
    148   1.3  dholland 		if (s != NULL) {
    149   1.3  dholland 			*(s++) = '\0';
    150   1.3  dholland 		}
    151   1.3  dholland 		if (!strcmp(opt, "userquota")) {
    152   1.3  dholland 			ret = 1;
    153   1.3  dholland 			ofe->ofe_hasuserquota = 1;
    154   1.3  dholland 			if (s != NULL) {
    155   1.3  dholland 				ofe->ofe_userquotafile = strdup(s);
    156   1.3  dholland 				if (ofe->ofe_userquotafile == NULL) {
    157   1.3  dholland 					goto fail;
    158   1.3  dholland 				}
    159   1.3  dholland 			}
    160   1.3  dholland 		} else if (!strcmp(opt, "groupquota")) {
    161   1.3  dholland 			ret = 1;
    162   1.3  dholland 			ofe->ofe_hasgroupquota = 1;
    163   1.3  dholland 			if (s != NULL) {
    164   1.3  dholland 				ofe->ofe_groupquotafile = strdup(s);
    165   1.3  dholland 				if (ofe->ofe_groupquotafile == NULL) {
    166   1.3  dholland 					goto fail;
    167   1.3  dholland 				}
    168   1.3  dholland 			}
    169   1.3  dholland 		}
    170   1.3  dholland 	}
    171   1.3  dholland 
    172   1.3  dholland 	if (ret == 1) {
    173   1.3  dholland 		ofe->ofe_mountpoint = strdup(fs->fs_file);
    174   1.3  dholland 		if (ofe->ofe_mountpoint == NULL) {
    175   1.3  dholland 			goto fail;
    176   1.3  dholland 		}
    177   1.3  dholland 	}
    178   1.3  dholland 
    179   1.3  dholland 	return ret;
    180   1.3  dholland 
    181   1.3  dholland fail:
    182   1.3  dholland 	serrno = errno;
    183   1.3  dholland 	if (ofe->ofe_mountpoint != NULL) {
    184   1.3  dholland 		free(ofe->ofe_mountpoint);
    185   1.3  dholland 	}
    186   1.3  dholland 	if (ofe->ofe_groupquotafile != NULL) {
    187   1.3  dholland 		free(ofe->ofe_groupquotafile);
    188   1.3  dholland 	}
    189   1.3  dholland 	if (ofe->ofe_userquotafile != NULL) {
    190   1.3  dholland 		free(ofe->ofe_userquotafile);
    191   1.3  dholland 	}
    192   1.3  dholland 	errno = serrno;
    193   1.3  dholland 	return -1;
    194   1.3  dholland }
    195   1.3  dholland 
    196   1.3  dholland void
    197   1.3  dholland __quota_oldfiles_load_fstab(void)
    198   1.3  dholland {
    199   1.3  dholland 	struct oldfiles_fstabentry ofe;
    200   1.3  dholland 	struct fstab *fs;
    201   1.3  dholland 	int result;
    202   1.3  dholland 
    203   1.3  dholland 	if (__quota_oldfiles_fstab_loaded) {
    204   1.3  dholland 		return;
    205   1.3  dholland 	}
    206   1.3  dholland 
    207   1.3  dholland 	/*
    208   1.9     njoly 	 * Check if fstab file exists before trying to parse it.
    209   1.9     njoly 	 * Avoid warnings from {get,set}fsent() if missing.
    210   1.9     njoly 	 */
    211   1.9     njoly 	if (access(_PATH_FSTAB, F_OK) == -1 && errno == ENOENT)
    212   1.9     njoly 		return;
    213   1.9     njoly 
    214   1.9     njoly 	/*
    215   1.3  dholland 	 * XXX: should be able to handle ext2fs quota1 files too
    216   1.3  dholland 	 *
    217   1.3  dholland 	 * XXX: should use getfsent_r(), but there isn't one.
    218   1.3  dholland 	 */
    219   1.3  dholland 	setfsent();
    220   1.3  dholland 	while ((fs = getfsent()) != NULL) {
    221   1.3  dholland 		if (!strcmp(fs->fs_vfstype, "ffs") ||
    222   1.3  dholland 		    !strcmp(fs->fs_vfstype, "lfs")) {
    223   1.3  dholland 			result = __quota_oldfiles_fill_fstabentry(fs, &ofe);
    224   1.3  dholland 			if (result == -1) {
    225   1.3  dholland 				goto failed;
    226   1.3  dholland 			}
    227   1.3  dholland 			if (result == 0) {
    228   1.3  dholland 				continue;
    229   1.3  dholland 			}
    230   1.3  dholland 			if (__quota_oldfiles_add_fstabentry(&ofe)) {
    231   1.3  dholland 				goto failed;
    232   1.3  dholland 			}
    233   1.3  dholland 		}
    234   1.3  dholland 	}
    235   1.3  dholland 	endfsent();
    236   1.3  dholland 	__quota_oldfiles_fstab_loaded = 1;
    237   1.3  dholland 
    238   1.3  dholland 	return;
    239   1.3  dholland failed:
    240   1.3  dholland 	warn("Failed reading fstab");
    241   1.3  dholland 	return;
    242   1.3  dholland }
    243   1.3  dholland 
    244   1.3  dholland int
    245   1.3  dholland __quota_oldfiles_infstab(const char *mountpoint)
    246   1.3  dholland {
    247   1.3  dholland 	return __quota_oldfiles_find_fstabentry(mountpoint) != NULL;
    248   1.3  dholland }
    249   1.3  dholland 
    250   1.5  dholland static void
    251   1.5  dholland __quota_oldfiles_defquotafile(struct quotahandle *qh, int idtype,
    252   1.5  dholland 			      char *buf, size_t maxlen)
    253   1.5  dholland {
    254   1.5  dholland 	static const char *const names[] = INITQFNAMES;
    255   1.5  dholland 
    256   1.5  dholland 	(void)snprintf(buf, maxlen, "%s/%s.%s",
    257   1.5  dholland 		       qh->qh_mountpoint,
    258  1.10   hannken 		       QUOTAFILENAME, names[idtype]);
    259   1.5  dholland }
    260   1.5  dholland 
    261   1.5  dholland const char *
    262   1.5  dholland __quota_oldfiles_getquotafile(struct quotahandle *qh, int idtype,
    263   1.5  dholland 			      char *buf, size_t maxlen)
    264   1.5  dholland {
    265   1.5  dholland 	const struct oldfiles_fstabentry *ofe;
    266   1.5  dholland 	const char *file;
    267   1.5  dholland 
    268   1.5  dholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
    269   1.5  dholland 	if (ofe == NULL) {
    270   1.5  dholland 		errno = ENXIO;
    271   1.5  dholland 		return NULL;
    272   1.5  dholland 	}
    273   1.5  dholland 
    274   1.5  dholland 	switch (idtype) {
    275   1.5  dholland 	    case USRQUOTA:
    276   1.5  dholland 		if (!ofe->ofe_hasuserquota) {
    277   1.5  dholland 			errno = ENXIO;
    278   1.5  dholland 			return NULL;
    279   1.5  dholland 		}
    280   1.5  dholland 		file = ofe->ofe_userquotafile;
    281   1.5  dholland 		break;
    282   1.5  dholland 	    case GRPQUOTA:
    283   1.5  dholland 		if (!ofe->ofe_hasgroupquota) {
    284   1.5  dholland 			errno = ENXIO;
    285   1.5  dholland 			return NULL;
    286   1.5  dholland 		}
    287   1.5  dholland 		file = ofe->ofe_groupquotafile;
    288   1.5  dholland 		break;
    289   1.5  dholland 	    default:
    290   1.5  dholland 		errno = EINVAL;
    291   1.5  dholland 		return NULL;
    292   1.5  dholland 	}
    293   1.5  dholland 
    294   1.5  dholland 	if (file == NULL) {
    295   1.5  dholland 		__quota_oldfiles_defquotafile(qh, idtype, buf, maxlen);
    296   1.5  dholland 		file = buf;
    297   1.5  dholland 	}
    298   1.5  dholland 	return file;
    299   1.5  dholland }
    300   1.5  dholland 
    301   1.1  dholland static uint64_t
    302   1.2  dholland dqblk_getlimit(uint32_t val)
    303   1.1  dholland {
    304   1.1  dholland 	if (val == 0) {
    305   1.1  dholland 		return QUOTA_NOLIMIT;
    306   1.1  dholland 	} else {
    307   1.1  dholland 		return val - 1;
    308   1.1  dholland 	}
    309   1.1  dholland }
    310   1.1  dholland 
    311   1.2  dholland static uint32_t
    312   1.2  dholland dqblk_setlimit(uint64_t val)
    313   1.2  dholland {
    314   1.2  dholland 	if (val == QUOTA_NOLIMIT && val >= 0xffffffffUL) {
    315   1.2  dholland 		return 0;
    316   1.2  dholland 	} else {
    317   1.2  dholland 		return (uint32_t)val + 1;
    318   1.2  dholland 	}
    319   1.2  dholland }
    320   1.2  dholland 
    321   1.1  dholland static void
    322   1.1  dholland dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
    323   1.1  dholland {
    324   1.2  dholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_bhardlimit);
    325   1.2  dholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_bsoftlimit);
    326   1.1  dholland 	qv->qv_usage = dq->dqb_curblocks;
    327   1.1  dholland 	qv->qv_expiretime = dq->dqb_btime;
    328   1.1  dholland 	qv->qv_grace = QUOTA_NOTIME;
    329   1.1  dholland }
    330   1.1  dholland 
    331   1.1  dholland static void
    332   1.1  dholland dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
    333   1.1  dholland {
    334   1.2  dholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_ihardlimit);
    335   1.2  dholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_isoftlimit);
    336   1.1  dholland 	qv->qv_usage = dq->dqb_curinodes;
    337   1.1  dholland 	qv->qv_expiretime = dq->dqb_itime;
    338   1.1  dholland 	qv->qv_grace = QUOTA_NOTIME;
    339   1.1  dholland }
    340   1.1  dholland 
    341   1.2  dholland static void
    342   1.2  dholland dqblk_putblocks(const struct quotaval *qv, struct dqblk *dq)
    343   1.2  dholland {
    344   1.2  dholland 	dq->dqb_bhardlimit = dqblk_setlimit(qv->qv_hardlimit);
    345   1.2  dholland 	dq->dqb_bsoftlimit = dqblk_setlimit(qv->qv_softlimit);
    346   1.2  dholland 	dq->dqb_curblocks = qv->qv_usage;
    347   1.2  dholland 	dq->dqb_btime = qv->qv_expiretime;
    348   1.2  dholland 	/* ignore qv->qv_grace */
    349   1.2  dholland }
    350   1.2  dholland 
    351   1.2  dholland static void
    352   1.2  dholland dqblk_putfiles(const struct quotaval *qv, struct dqblk *dq)
    353   1.2  dholland {
    354   1.2  dholland 	dq->dqb_ihardlimit = dqblk_setlimit(qv->qv_hardlimit);
    355   1.2  dholland 	dq->dqb_isoftlimit = dqblk_setlimit(qv->qv_softlimit);
    356   1.2  dholland 	dq->dqb_curinodes = qv->qv_usage;
    357   1.2  dholland 	dq->dqb_itime = qv->qv_expiretime;
    358   1.2  dholland 	/* ignore qv->qv_grace */
    359   1.2  dholland }
    360   1.2  dholland 
    361   1.1  dholland static int
    362   1.1  dholland __quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
    363   1.1  dholland {
    364   1.1  dholland 	int fd;
    365   1.1  dholland 
    366   1.1  dholland 	fd = open(path, O_RDWR);
    367   1.1  dholland 	if (fd < 0 && (errno == EACCES || errno == EROFS)) {
    368   1.1  dholland 		fd = open(path, O_RDONLY);
    369   1.1  dholland 		if (fd < 0) {
    370   1.1  dholland 			return -1;
    371   1.1  dholland 		}
    372   1.1  dholland 	}
    373   1.1  dholland 	*fd_ret = fd;
    374   1.1  dholland 	return 0;
    375   1.1  dholland }
    376   1.1  dholland 
    377   1.1  dholland int
    378   1.1  dholland __quota_oldfiles_initialize(struct quotahandle *qh)
    379   1.1  dholland {
    380   1.3  dholland 	const struct oldfiles_fstabentry *ofe;
    381   1.1  dholland 	char path[PATH_MAX];
    382   1.1  dholland 	const char *userquotafile, *groupquotafile;
    383   1.1  dholland 
    384   1.3  dholland 	if (qh->qh_oldfilesopen) {
    385   1.1  dholland 		/* already initialized */
    386   1.1  dholland 		return 0;
    387   1.1  dholland 	}
    388   1.1  dholland 
    389   1.1  dholland 	/*
    390   1.1  dholland 	 * Find the fstab entry.
    391   1.1  dholland 	 */
    392   1.3  dholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
    393   1.3  dholland 	if (ofe == NULL) {
    394   1.1  dholland 		warnx("%s not found in fstab", qh->qh_mountpoint);
    395   1.1  dholland 		errno = ENXIO;
    396   1.1  dholland 		return -1;
    397   1.1  dholland 	}
    398   1.1  dholland 
    399   1.3  dholland 	if (!ofe->ofe_hasuserquota && !ofe->ofe_hasgroupquota) {
    400   1.1  dholland 		errno = ENXIO;
    401   1.1  dholland 		return -1;
    402   1.1  dholland 	}
    403   1.1  dholland 
    404   1.3  dholland 	if (ofe->ofe_hasuserquota) {
    405   1.3  dholland 		userquotafile = ofe->ofe_userquotafile;
    406   1.1  dholland 		if (userquotafile == NULL) {
    407   1.5  dholland 			__quota_oldfiles_defquotafile(qh, USRQUOTA,
    408   1.5  dholland 						      path, sizeof(path));
    409   1.1  dholland 			userquotafile = path;
    410   1.1  dholland 		}
    411   1.1  dholland 		if (__quota_oldfiles_open(qh, userquotafile,
    412   1.1  dholland 					  &qh->qh_userfile)) {
    413   1.1  dholland 			return -1;
    414   1.1  dholland 		}
    415   1.1  dholland 	}
    416   1.3  dholland 	if (ofe->ofe_hasgroupquota) {
    417   1.3  dholland 		groupquotafile = ofe->ofe_groupquotafile;
    418   1.1  dholland 		if (groupquotafile == NULL) {
    419   1.5  dholland 			__quota_oldfiles_defquotafile(qh, GRPQUOTA,
    420   1.5  dholland 						      path, sizeof(path));
    421   1.1  dholland 			groupquotafile = path;
    422   1.1  dholland 		}
    423   1.1  dholland 		if (__quota_oldfiles_open(qh, groupquotafile,
    424   1.1  dholland 					  &qh->qh_groupfile)) {
    425   1.1  dholland 			return -1;
    426   1.1  dholland 		}
    427   1.1  dholland 	}
    428   1.1  dholland 
    429   1.3  dholland 	qh->qh_oldfilesopen = 1;
    430   1.1  dholland 
    431   1.1  dholland 	return 0;
    432   1.1  dholland }
    433   1.1  dholland 
    434   1.1  dholland const char *
    435   1.1  dholland __quota_oldfiles_getimplname(struct quotahandle *qh)
    436   1.1  dholland {
    437   1.3  dholland 	return "ufs/ffs quota v1 file access";
    438   1.1  dholland }
    439   1.1  dholland 
    440   1.5  dholland int
    441   1.5  dholland __quota_oldfiles_quotaon(struct quotahandle *qh, int idtype)
    442   1.5  dholland {
    443   1.5  dholland 	int result;
    444   1.5  dholland 
    445   1.5  dholland 	/*
    446   1.5  dholland 	 * If we have the quota files open, close them.
    447   1.5  dholland 	 */
    448   1.5  dholland 
    449   1.5  dholland 	if (qh->qh_oldfilesopen) {
    450   1.5  dholland 		if (qh->qh_userfile >= 0) {
    451   1.5  dholland 			close(qh->qh_userfile);
    452   1.5  dholland 			qh->qh_userfile = -1;
    453   1.5  dholland 		}
    454   1.5  dholland 		if (qh->qh_groupfile >= 0) {
    455   1.5  dholland 			close(qh->qh_groupfile);
    456   1.5  dholland 			qh->qh_groupfile = -1;
    457   1.5  dholland 		}
    458   1.5  dholland 		qh->qh_oldfilesopen = 0;
    459   1.5  dholland 	}
    460   1.5  dholland 
    461   1.5  dholland 	/*
    462   1.5  dholland 	 * Go over to the syscall interface.
    463   1.5  dholland 	 */
    464   1.5  dholland 
    465   1.6  dholland 	result = __quota_kernel_quotaon(qh, idtype);
    466   1.5  dholland 	if (result < 0) {
    467   1.5  dholland 		return -1;
    468   1.5  dholland 	}
    469   1.5  dholland 
    470   1.5  dholland 	/*
    471   1.5  dholland 	 * We succeeded, so all further access should be via the
    472   1.5  dholland 	 * kernel.
    473   1.5  dholland 	 */
    474   1.5  dholland 
    475   1.6  dholland 	qh->qh_mode = QUOTA_MODE_KERNEL;
    476   1.5  dholland 	return 0;
    477   1.5  dholland }
    478   1.5  dholland 
    479   1.1  dholland static int
    480   1.1  dholland __quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
    481   1.1  dholland 		       struct quotaval *qv, int *isallzero)
    482   1.1  dholland {
    483   1.1  dholland 	int file;
    484   1.1  dholland 	off_t pos;
    485   1.1  dholland 	struct dqblk dq;
    486   1.1  dholland 	ssize_t result;
    487   1.1  dholland 
    488   1.3  dholland 	if (!qh->qh_oldfilesopen) {
    489   1.3  dholland 		if (__quota_oldfiles_initialize(qh)) {
    490   1.3  dholland 			return -1;
    491   1.3  dholland 		}
    492   1.3  dholland 	}
    493   1.3  dholland 
    494   1.1  dholland 	switch (qk->qk_idtype) {
    495   1.1  dholland 	    case QUOTA_IDTYPE_USER:
    496   1.1  dholland 		file = qh->qh_userfile;
    497   1.1  dholland 		break;
    498   1.1  dholland 	    case QUOTA_IDTYPE_GROUP:
    499   1.1  dholland 		file = qh->qh_groupfile;
    500   1.1  dholland 		break;
    501   1.1  dholland 	    default:
    502   1.1  dholland 		errno = EINVAL;
    503   1.1  dholland 		return -1;
    504   1.1  dholland 	}
    505   1.1  dholland 
    506   1.1  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    507   1.1  dholland 		pos = 0;
    508   1.1  dholland 	} else {
    509   1.1  dholland 		pos = qk->qk_id * sizeof(struct dqblk);
    510   1.1  dholland 	}
    511   1.1  dholland 
    512   1.1  dholland 	result = pread(file, &dq, sizeof(dq), pos);
    513   1.1  dholland 	if (result < 0) {
    514   1.1  dholland 		return -1;
    515   1.2  dholland 	} else if (result == 0) {
    516   1.2  dholland 		/* Past EOF; no quota info on file for this ID */
    517   1.2  dholland 		errno = ENOENT;
    518   1.2  dholland 		return -1;
    519   1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    520   1.1  dholland 		errno = EFTYPE;
    521   1.1  dholland 		return -1;
    522   1.1  dholland 	}
    523   1.1  dholland 
    524   1.1  dholland 	switch (qk->qk_objtype) {
    525   1.1  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    526   1.1  dholland 		dqblk_getblocks(&dq, qv);
    527   1.1  dholland 		break;
    528   1.1  dholland 	    case QUOTA_OBJTYPE_FILES:
    529   1.1  dholland 		dqblk_getfiles(&dq, qv);
    530   1.1  dholland 		break;
    531   1.1  dholland 	    default:
    532   1.1  dholland 		errno = EINVAL;
    533   1.1  dholland 		return -1;
    534   1.1  dholland 	}
    535   1.1  dholland 
    536   1.1  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    537   1.1  dholland 		qv->qv_usage = 0;
    538   1.1  dholland 		qv->qv_grace = qv->qv_expiretime;
    539   1.1  dholland 		qv->qv_expiretime = QUOTA_NOTIME;
    540   1.1  dholland 	} else if (qk->qk_id == 0) {
    541   1.1  dholland 		qv->qv_hardlimit = 0;
    542   1.1  dholland 		qv->qv_softlimit = 0;
    543   1.1  dholland 		qv->qv_expiretime = QUOTA_NOTIME;
    544   1.1  dholland 		qv->qv_grace = QUOTA_NOTIME;
    545   1.1  dholland 	}
    546   1.1  dholland 
    547   1.1  dholland 	if (isallzero != NULL) {
    548   1.1  dholland 		if (dq.dqb_bhardlimit == 0 &&
    549   1.1  dholland 		    dq.dqb_bsoftlimit == 0 &&
    550   1.1  dholland 		    dq.dqb_curblocks == 0 &&
    551   1.1  dholland 		    dq.dqb_ihardlimit == 0 &&
    552   1.1  dholland 		    dq.dqb_isoftlimit == 0 &&
    553   1.1  dholland 		    dq.dqb_curinodes == 0 &&
    554   1.1  dholland 		    dq.dqb_btime == 0 &&
    555   1.1  dholland 		    dq.dqb_itime == 0) {
    556   1.1  dholland 			*isallzero = 1;
    557   1.1  dholland 		} else {
    558   1.1  dholland 			*isallzero = 0;
    559   1.1  dholland 		}
    560   1.1  dholland 	}
    561   1.1  dholland 
    562   1.1  dholland 	return 0;
    563   1.1  dholland }
    564   1.1  dholland 
    565   1.2  dholland static int
    566   1.2  dholland __quota_oldfiles_doput(struct quotahandle *qh, const struct quotakey *qk,
    567   1.2  dholland 		       const struct quotaval *qv)
    568   1.2  dholland {
    569   1.2  dholland 	int file;
    570   1.2  dholland 	off_t pos;
    571   1.2  dholland 	struct quotaval qv2;
    572   1.2  dholland 	struct dqblk dq;
    573   1.2  dholland 	ssize_t result;
    574   1.2  dholland 
    575   1.3  dholland 	if (!qh->qh_oldfilesopen) {
    576   1.3  dholland 		if (__quota_oldfiles_initialize(qh)) {
    577   1.3  dholland 			return -1;
    578   1.3  dholland 		}
    579   1.3  dholland 	}
    580   1.3  dholland 
    581   1.2  dholland 	switch (qk->qk_idtype) {
    582   1.2  dholland 	    case QUOTA_IDTYPE_USER:
    583   1.2  dholland 		file = qh->qh_userfile;
    584   1.2  dholland 		break;
    585   1.2  dholland 	    case QUOTA_IDTYPE_GROUP:
    586   1.2  dholland 		file = qh->qh_groupfile;
    587   1.2  dholland 		break;
    588   1.2  dholland 	    default:
    589   1.2  dholland 		errno = EINVAL;
    590   1.2  dholland 		return -1;
    591   1.2  dholland 	}
    592   1.2  dholland 
    593   1.2  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    594   1.2  dholland 		pos = 0;
    595   1.2  dholland 	} else {
    596   1.2  dholland 		pos = qk->qk_id * sizeof(struct dqblk);
    597   1.2  dholland 	}
    598   1.2  dholland 
    599   1.2  dholland 	result = pread(file, &dq, sizeof(dq), pos);
    600   1.2  dholland 	if (result < 0) {
    601   1.2  dholland 		return -1;
    602   1.2  dholland 	} else if (result == 0) {
    603   1.2  dholland 		/* Past EOF; fill in a blank dq to start from */
    604   1.2  dholland 		dq.dqb_bhardlimit = 0;
    605   1.2  dholland 		dq.dqb_bsoftlimit = 0;
    606   1.2  dholland 		dq.dqb_curblocks = 0;
    607   1.2  dholland 		dq.dqb_ihardlimit = 0;
    608   1.2  dholland 		dq.dqb_isoftlimit = 0;
    609   1.2  dholland 		dq.dqb_curinodes = 0;
    610   1.2  dholland 		dq.dqb_btime = 0;
    611   1.2  dholland 		dq.dqb_itime = 0;
    612   1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    613   1.2  dholland 		errno = EFTYPE;
    614   1.2  dholland 		return -1;
    615   1.2  dholland 	}
    616   1.2  dholland 
    617   1.2  dholland 	switch (qk->qk_objtype) {
    618   1.2  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    619   1.2  dholland 		dqblk_getblocks(&dq, &qv2);
    620   1.2  dholland 		break;
    621   1.2  dholland 	    case QUOTA_OBJTYPE_FILES:
    622   1.2  dholland 		dqblk_getfiles(&dq, &qv2);
    623   1.2  dholland 		break;
    624   1.2  dholland 	    default:
    625   1.2  dholland 		errno = EINVAL;
    626   1.2  dholland 		return -1;
    627   1.2  dholland 	}
    628   1.2  dholland 
    629   1.2  dholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
    630   1.2  dholland 		qv2.qv_hardlimit = qv->qv_hardlimit;
    631   1.2  dholland 		qv2.qv_softlimit = qv->qv_softlimit;
    632   1.2  dholland 		/* leave qv2.qv_usage unchanged */
    633   1.2  dholland 		qv2.qv_expiretime = qv->qv_grace;
    634   1.2  dholland 		/* skip qv2.qv_grace */
    635   1.2  dholland 
    636   1.2  dholland 		/* ignore qv->qv_usage */
    637   1.2  dholland 		/* ignore qv->qv_expiretime */
    638   1.2  dholland 	} else if (qk->qk_id == 0) {
    639   1.2  dholland 		/* leave qv2.qv_hardlimit unchanged */
    640   1.2  dholland 		/* leave qv2.qv_softlimit unchanged */
    641   1.2  dholland 		qv2.qv_usage = qv->qv_usage;
    642   1.2  dholland 		/* leave qv2.qv_expiretime unchanged */
    643   1.2  dholland 		/* skip qv2.qv_grace */
    644   1.2  dholland 
    645   1.2  dholland 		/* ignore qv->qv_hardlimit */
    646   1.2  dholland 		/* ignore qv->qv_softlimit */
    647   1.2  dholland 		/* ignore qv->qv_expiretime */
    648   1.2  dholland 		/* ignore qv->qv_grace */
    649   1.2  dholland 	} else {
    650   1.2  dholland 		qv2 = *qv;
    651   1.2  dholland 	}
    652   1.2  dholland 
    653   1.2  dholland 	switch (qk->qk_objtype) {
    654   1.2  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    655   1.2  dholland 		dqblk_putblocks(&qv2, &dq);
    656   1.2  dholland 		break;
    657   1.2  dholland 	    case QUOTA_OBJTYPE_FILES:
    658   1.2  dholland 		dqblk_putfiles(&qv2, &dq);
    659   1.2  dholland 		break;
    660   1.2  dholland 	    default:
    661   1.2  dholland 		errno = EINVAL;
    662   1.2  dholland 		return -1;
    663   1.2  dholland 	}
    664   1.2  dholland 
    665   1.2  dholland 	result = pwrite(file, &dq, sizeof(dq), pos);
    666   1.2  dholland 	if (result < 0) {
    667   1.2  dholland 		return -1;
    668   1.2  dholland 	} else if ((size_t)result != sizeof(dq)) {
    669   1.2  dholland 		/* ? */
    670   1.2  dholland 		errno = EFTYPE;
    671   1.2  dholland 		return -1;
    672   1.2  dholland 	}
    673   1.2  dholland 
    674   1.2  dholland 	return 0;
    675   1.2  dholland }
    676   1.2  dholland 
    677   1.1  dholland int
    678   1.1  dholland __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
    679   1.1  dholland 		     struct quotaval *qv)
    680   1.1  dholland {
    681   1.1  dholland 	return __quota_oldfiles_doget(qh, qk, qv, NULL);
    682   1.1  dholland }
    683   1.1  dholland 
    684   1.2  dholland int
    685   1.2  dholland __quota_oldfiles_put(struct quotahandle *qh, const struct quotakey *qk,
    686   1.2  dholland 		     const struct quotaval *qv)
    687   1.2  dholland {
    688   1.2  dholland 	return __quota_oldfiles_doput(qh, qk, qv);
    689   1.2  dholland }
    690   1.2  dholland 
    691   1.2  dholland int
    692   1.2  dholland __quota_oldfiles_delete(struct quotahandle *qh, const struct quotakey *qk)
    693   1.2  dholland {
    694   1.2  dholland 	struct quotaval qv;
    695   1.2  dholland 
    696   1.2  dholland 	quotaval_clear(&qv);
    697   1.2  dholland 	return __quota_oldfiles_doput(qh, qk, &qv);
    698   1.2  dholland }
    699   1.2  dholland 
    700   1.1  dholland struct oldfiles_quotacursor *
    701   1.1  dholland __quota_oldfiles_cursor_create(struct quotahandle *qh)
    702   1.1  dholland {
    703   1.1  dholland 	struct oldfiles_quotacursor *oqc;
    704   1.1  dholland 	struct stat st;
    705   1.1  dholland 	int serrno;
    706   1.1  dholland 
    707   1.3  dholland 	/* quota_opencursor calls initialize for us, no need to do it here */
    708   1.3  dholland 
    709   1.1  dholland 	oqc = malloc(sizeof(*oqc));
    710   1.1  dholland 	if (oqc == NULL) {
    711   1.1  dholland 		return NULL;
    712   1.1  dholland 	}
    713   1.1  dholland 
    714   1.1  dholland 	oqc->oqc_didusers = 0;
    715   1.1  dholland 	oqc->oqc_didgroups = 0;
    716   1.1  dholland 	oqc->oqc_diddefault = 0;
    717   1.1  dholland 	oqc->oqc_pos = 0;
    718   1.1  dholland 	oqc->oqc_didblocks = 0;
    719   1.1  dholland 
    720   1.1  dholland 	if (qh->qh_userfile >= 0) {
    721   1.1  dholland 		oqc->oqc_doingusers = 1;
    722   1.1  dholland 	} else {
    723   1.1  dholland 		oqc->oqc_doingusers = 0;
    724   1.1  dholland 		oqc->oqc_didusers = 1;
    725   1.1  dholland 	}
    726   1.1  dholland 
    727   1.1  dholland 	if (qh->qh_groupfile >= 0) {
    728   1.1  dholland 		oqc->oqc_doinggroups = 1;
    729   1.1  dholland 	} else {
    730   1.1  dholland 		oqc->oqc_doinggroups = 0;
    731   1.1  dholland 		oqc->oqc_didgroups = 1;
    732   1.1  dholland 	}
    733   1.1  dholland 
    734   1.1  dholland 	if (fstat(qh->qh_userfile, &st) < 0) {
    735   1.1  dholland 		serrno = errno;
    736   1.1  dholland 		free(oqc);
    737   1.1  dholland 		errno = serrno;
    738   1.1  dholland 		return NULL;
    739   1.1  dholland 	}
    740   1.1  dholland 	oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
    741   1.1  dholland 
    742   1.1  dholland 	if (fstat(qh->qh_groupfile, &st) < 0) {
    743   1.1  dholland 		serrno = errno;
    744   1.1  dholland 		free(oqc);
    745   1.1  dholland 		errno = serrno;
    746   1.1  dholland 		return NULL;
    747   1.1  dholland 	}
    748   1.1  dholland 	oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
    749   1.1  dholland 
    750   1.1  dholland 	return oqc;
    751   1.1  dholland }
    752   1.1  dholland 
    753   1.1  dholland void
    754   1.1  dholland __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
    755   1.1  dholland {
    756   1.1  dholland 	free(oqc);
    757   1.1  dholland }
    758   1.1  dholland 
    759   1.1  dholland int
    760   1.1  dholland __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
    761   1.7  dholland 				   int idtype)
    762   1.1  dholland {
    763   1.1  dholland 	switch (idtype) {
    764   1.1  dholland 	    case QUOTA_IDTYPE_USER:
    765   1.1  dholland 		oqc->oqc_doingusers = 0;
    766   1.1  dholland 		oqc->oqc_didusers = 1;
    767   1.1  dholland 		break;
    768   1.1  dholland 	    case QUOTA_IDTYPE_GROUP:
    769   1.1  dholland 		oqc->oqc_doinggroups = 0;
    770   1.1  dholland 		oqc->oqc_didgroups = 1;
    771   1.1  dholland 		break;
    772   1.1  dholland 	    default:
    773   1.1  dholland 		errno = EINVAL;
    774   1.1  dholland 		return -1;
    775   1.1  dholland 	}
    776   1.1  dholland 	return 0;
    777   1.1  dholland }
    778   1.1  dholland 
    779   1.1  dholland int
    780   1.1  dholland __quota_oldfiles_cursor_get(struct quotahandle *qh,
    781   1.1  dholland 			    struct oldfiles_quotacursor *oqc,
    782   1.1  dholland 			    struct quotakey *key, struct quotaval *val)
    783   1.1  dholland {
    784   1.1  dholland 	unsigned maxpos;
    785   1.1  dholland 	int isallzero;
    786   1.1  dholland 
    787   1.1  dholland 	/* in case one of the sizes is zero */
    788   1.1  dholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
    789   1.1  dholland 		oqc->oqc_didusers = 1;
    790   1.1  dholland 	}
    791   1.1  dholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
    792   1.1  dholland 		oqc->oqc_didgroups = 1;
    793   1.1  dholland 	}
    794   1.1  dholland 
    795   1.1  dholland  again:
    796   1.1  dholland 	/*
    797   1.1  dholland 	 * Figure out what to get
    798   1.1  dholland 	 */
    799   1.1  dholland 
    800   1.1  dholland 	if (!oqc->oqc_didusers) {
    801   1.1  dholland 		key->qk_idtype = QUOTA_IDTYPE_USER;
    802   1.1  dholland 		maxpos = oqc->oqc_numusers;
    803   1.1  dholland 	} else if (!oqc->oqc_didgroups) {
    804   1.1  dholland 		key->qk_idtype = QUOTA_IDTYPE_GROUP;
    805   1.1  dholland 		maxpos = oqc->oqc_numgroups;
    806   1.1  dholland 	} else {
    807   1.1  dholland 		errno = ENOENT;
    808   1.1  dholland 		return -1;
    809   1.1  dholland 	}
    810   1.1  dholland 
    811   1.1  dholland 	if (!oqc->oqc_diddefault) {
    812   1.1  dholland 		key->qk_id = QUOTA_DEFAULTID;
    813   1.1  dholland 	} else {
    814   1.1  dholland 		key->qk_id = oqc->oqc_pos;
    815   1.1  dholland 	}
    816   1.1  dholland 
    817   1.1  dholland 	if (!oqc->oqc_didblocks) {
    818   1.1  dholland 		key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
    819   1.1  dholland 	} else {
    820   1.1  dholland 		key->qk_objtype = QUOTA_OBJTYPE_FILES;
    821   1.1  dholland 	}
    822   1.1  dholland 
    823   1.1  dholland 	/*
    824   1.1  dholland 	 * Get it
    825   1.1  dholland 	 */
    826   1.1  dholland 
    827   1.1  dholland 	if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
    828   1.1  dholland 		return -1;
    829   1.1  dholland 	}
    830   1.1  dholland 
    831   1.1  dholland 	/*
    832   1.1  dholland 	 * Advance the cursor
    833   1.1  dholland 	 */
    834   1.1  dholland 	if (!oqc->oqc_didblocks) {
    835   1.1  dholland 		oqc->oqc_didblocks = 1;
    836   1.1  dholland 	} else {
    837   1.1  dholland 		oqc->oqc_didblocks = 0;
    838   1.1  dholland 		if (!oqc->oqc_diddefault) {
    839   1.1  dholland 			oqc->oqc_diddefault = 1;
    840   1.1  dholland 		} else {
    841   1.1  dholland 			oqc->oqc_pos++;
    842   1.1  dholland 			if (oqc->oqc_pos >= maxpos) {
    843   1.1  dholland 				oqc->oqc_pos = 0;
    844   1.1  dholland 				oqc->oqc_diddefault = 0;
    845   1.1  dholland 				if (!oqc->oqc_didusers) {
    846   1.1  dholland 					oqc->oqc_didusers = 1;
    847   1.1  dholland 				} else {
    848   1.1  dholland 					oqc->oqc_didgroups = 1;
    849   1.1  dholland 				}
    850   1.1  dholland 			}
    851   1.1  dholland 		}
    852   1.1  dholland 	}
    853   1.1  dholland 
    854   1.1  dholland 	/*
    855   1.1  dholland 	 * If we got an all-zero dqblk (e.g. from the middle of a hole
    856   1.1  dholland 	 * in the quota file) don't bother returning it to the caller.
    857   1.1  dholland 	 *
    858   1.1  dholland 	 * ...unless we're at the end of the data, to avoid going past
    859   1.1  dholland 	 * the end and generating a spurious failure. There's no
    860   1.1  dholland 	 * reasonable way to make _atend detect empty entries at the
    861   1.1  dholland 	 * end of the quota files.
    862   1.1  dholland 	 */
    863   1.1  dholland 	if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
    864   1.1  dholland 		goto again;
    865   1.1  dholland 	}
    866   1.1  dholland 	return 0;
    867   1.1  dholland }
    868   1.1  dholland 
    869   1.1  dholland int
    870   1.1  dholland __quota_oldfiles_cursor_getn(struct quotahandle *qh,
    871   1.1  dholland 			     struct oldfiles_quotacursor *oqc,
    872   1.1  dholland 			     struct quotakey *keys, struct quotaval *vals,
    873   1.1  dholland 			     unsigned maxnum)
    874   1.1  dholland {
    875   1.1  dholland 	unsigned i;
    876   1.1  dholland 
    877   1.1  dholland 	if (maxnum > INT_MAX) {
    878   1.1  dholland 		/* joker, eh? */
    879   1.1  dholland 		errno = EINVAL;
    880   1.1  dholland 		return -1;
    881   1.1  dholland 	}
    882   1.1  dholland 
    883   1.1  dholland 	for (i=0; i<maxnum; i++) {
    884   1.1  dholland 		if (__quota_oldfiles_cursor_atend(oqc)) {
    885   1.1  dholland 			break;
    886   1.1  dholland 		}
    887   1.1  dholland 		if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
    888   1.1  dholland 			if (i > 0) {
    889   1.1  dholland 				/*
    890   1.1  dholland 				 * Succeed witih what we have so far;
    891   1.1  dholland 				 * the next attempt will hit the same
    892   1.1  dholland 				 * error again.
    893   1.1  dholland 				 */
    894   1.1  dholland 				break;
    895   1.1  dholland 			}
    896   1.1  dholland 			return -1;
    897   1.1  dholland 		}
    898   1.1  dholland 	}
    899   1.1  dholland 	return i;
    900   1.1  dholland 
    901   1.1  dholland }
    902   1.1  dholland 
    903   1.1  dholland int
    904   1.1  dholland __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
    905   1.1  dholland {
    906   1.1  dholland 	/* in case one of the sizes is zero */
    907   1.1  dholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
    908   1.1  dholland 		oqc->oqc_didusers = 1;
    909   1.1  dholland 	}
    910   1.1  dholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
    911   1.1  dholland 		oqc->oqc_didgroups = 1;
    912   1.1  dholland 	}
    913   1.1  dholland 
    914   1.1  dholland 	return oqc->oqc_didusers && oqc->oqc_didgroups;
    915   1.1  dholland }
    916   1.1  dholland 
    917   1.1  dholland int
    918   1.1  dholland __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
    919   1.1  dholland {
    920   1.1  dholland 	oqc->oqc_didusers = 0;
    921   1.1  dholland 	oqc->oqc_didgroups = 0;
    922   1.1  dholland 	oqc->oqc_diddefault = 0;
    923   1.1  dholland 	oqc->oqc_pos = 0;
    924   1.1  dholland 	oqc->oqc_didblocks = 0;
    925   1.1  dholland 	return 0;
    926   1.1  dholland }
    927