xref: /netbsd-src/lib/libquota/quota_oldfiles.c (revision 48747c6894707b2bfb10031f3eca4bcf90da46c4)
1*48747c68Shannken /*	$NetBSD: quota_oldfiles.c,v 1.10 2022/04/26 15:36:42 hannken Exp $	*/
28d70e807Sdholland 
38d70e807Sdholland /*
48d70e807Sdholland  * Copyright (c) 1980, 1990, 1993
58d70e807Sdholland  *	The Regents of the University of California.  All rights reserved.
68d70e807Sdholland  *
78d70e807Sdholland  * This code is derived from software contributed to Berkeley by
88d70e807Sdholland  * Robert Elz at The University of Melbourne.
98d70e807Sdholland  *
108d70e807Sdholland  * Redistribution and use in source and binary forms, with or without
118d70e807Sdholland  * modification, are permitted provided that the following conditions
128d70e807Sdholland  * are met:
138d70e807Sdholland  * 1. Redistributions of source code must retain the above copyright
148d70e807Sdholland  *    notice, this list of conditions and the following disclaimer.
158d70e807Sdholland  * 2. Redistributions in binary form must reproduce the above copyright
168d70e807Sdholland  *    notice, this list of conditions and the following disclaimer in the
178d70e807Sdholland  *    documentation and/or other materials provided with the distribution.
188d70e807Sdholland  * 3. Neither the name of the University nor the names of its contributors
198d70e807Sdholland  *    may be used to endorse or promote products derived from this software
208d70e807Sdholland  *    without specific prior written permission.
218d70e807Sdholland  *
228d70e807Sdholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
238d70e807Sdholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248d70e807Sdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258d70e807Sdholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
268d70e807Sdholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
278d70e807Sdholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
288d70e807Sdholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
298d70e807Sdholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
308d70e807Sdholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
318d70e807Sdholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328d70e807Sdholland  * SUCH DAMAGE.
338d70e807Sdholland  */
348d70e807Sdholland 
351ce78a5fSdholland #include <sys/cdefs.h>
36*48747c68Shannken __RCSID("$NetBSD: quota_oldfiles.c,v 1.10 2022/04/26 15:36:42 hannken Exp $");
371ce78a5fSdholland 
388d70e807Sdholland #include <sys/types.h>
398d70e807Sdholland #include <sys/stat.h>
408d70e807Sdholland #include <stdio.h>
418d70e807Sdholland #include <stdlib.h>
428d70e807Sdholland #include <string.h>
438d70e807Sdholland #include <unistd.h>
448d70e807Sdholland #include <fcntl.h>
458d70e807Sdholland #include <limits.h>
468d70e807Sdholland #include <fstab.h>
478d70e807Sdholland #include <errno.h>
488d70e807Sdholland #include <err.h>
498d70e807Sdholland 
508d70e807Sdholland #include <ufs/ufs/quota1.h>
518d70e807Sdholland 
528d70e807Sdholland #include <quota.h>
538d70e807Sdholland #include "quotapvt.h"
548d70e807Sdholland 
55fa577c93Sdholland struct oldfiles_fstabentry {
56fa577c93Sdholland 	char *ofe_mountpoint;
57fa577c93Sdholland 	int ofe_hasuserquota;
58fa577c93Sdholland 	int ofe_hasgroupquota;
59fa577c93Sdholland 	char *ofe_userquotafile;
60fa577c93Sdholland 	char *ofe_groupquotafile;
61fa577c93Sdholland };
62fa577c93Sdholland 
638d70e807Sdholland struct oldfiles_quotacursor {
648d70e807Sdholland 	unsigned oqc_doingusers;
658d70e807Sdholland 	unsigned oqc_doinggroups;
668d70e807Sdholland 
678d70e807Sdholland 	unsigned oqc_numusers;
688d70e807Sdholland 	unsigned oqc_numgroups;
698d70e807Sdholland 
708d70e807Sdholland 	unsigned oqc_didusers;
718d70e807Sdholland 	unsigned oqc_didgroups;
728d70e807Sdholland 	unsigned oqc_diddefault;
738d70e807Sdholland 	unsigned oqc_pos;
748d70e807Sdholland 	unsigned oqc_didblocks;
758d70e807Sdholland };
768d70e807Sdholland 
77fa577c93Sdholland static struct oldfiles_fstabentry *__quota_oldfiles_fstab;
78fa577c93Sdholland static unsigned __quota_oldfiles_numfstab;
79fa577c93Sdholland static unsigned __quota_oldfiles_maxfstab;
80fa577c93Sdholland static int __quota_oldfiles_fstab_loaded;
81fa577c93Sdholland 
82fa577c93Sdholland static const struct oldfiles_fstabentry *
__quota_oldfiles_find_fstabentry(const char * mountpoint)83fa577c93Sdholland __quota_oldfiles_find_fstabentry(const char *mountpoint)
84fa577c93Sdholland {
85fa577c93Sdholland 	unsigned i;
86fa577c93Sdholland 
87fa577c93Sdholland 	for (i = 0; i < __quota_oldfiles_numfstab; i++) {
88fa577c93Sdholland 		if (!strcmp(mountpoint,
89fa577c93Sdholland 			    __quota_oldfiles_fstab[i].ofe_mountpoint)) {
90fa577c93Sdholland 			return &__quota_oldfiles_fstab[i];
91fa577c93Sdholland 		}
92fa577c93Sdholland 	}
93fa577c93Sdholland 	return NULL;
94fa577c93Sdholland }
95fa577c93Sdholland 
96fa577c93Sdholland static int
__quota_oldfiles_add_fstabentry(struct oldfiles_fstabentry * ofe)97fa577c93Sdholland __quota_oldfiles_add_fstabentry(struct oldfiles_fstabentry *ofe)
98fa577c93Sdholland {
99fa577c93Sdholland 	unsigned newmax;
100fa577c93Sdholland 	struct oldfiles_fstabentry *newptr;
101fa577c93Sdholland 
102fa577c93Sdholland 	if (__quota_oldfiles_numfstab + 1 >= __quota_oldfiles_maxfstab) {
103fa577c93Sdholland 		if (__quota_oldfiles_maxfstab == 0) {
104fa577c93Sdholland 			newmax = 4;
105fa577c93Sdholland 		} else {
106fa577c93Sdholland 			newmax = __quota_oldfiles_maxfstab * 2;
107fa577c93Sdholland 		}
108fa577c93Sdholland 		newptr = realloc(__quota_oldfiles_fstab,
109fa577c93Sdholland 				 newmax * sizeof(__quota_oldfiles_fstab[0]));
110fa577c93Sdholland 		if (newptr == NULL) {
111fa577c93Sdholland 			return -1;
112fa577c93Sdholland 		}
113fa577c93Sdholland 		__quota_oldfiles_maxfstab = newmax;
114fa577c93Sdholland 		__quota_oldfiles_fstab = newptr;
115fa577c93Sdholland 	}
116fa577c93Sdholland 
117fa577c93Sdholland 	__quota_oldfiles_fstab[__quota_oldfiles_numfstab++] = *ofe;
118fa577c93Sdholland 	return 0;
119fa577c93Sdholland }
120fa577c93Sdholland 
121fa577c93Sdholland static int
__quota_oldfiles_fill_fstabentry(const struct fstab * fs,struct oldfiles_fstabentry * ofe)122fa577c93Sdholland __quota_oldfiles_fill_fstabentry(const struct fstab *fs,
123fa577c93Sdholland 				 struct oldfiles_fstabentry *ofe)
124fa577c93Sdholland {
125dfbeb140Sdholland 	char buf[256];
126fa577c93Sdholland 	char *opt, *state, *s;
127fa577c93Sdholland 	int serrno;
128fa577c93Sdholland 	int ret = 0;
129fa577c93Sdholland 
130fa577c93Sdholland 	/*
131fa577c93Sdholland 	 * Inspect the mount options to find the quota files.
132fa577c93Sdholland 	 * XXX this info should be gotten from the kernel.
133fa577c93Sdholland 	 *
134fa577c93Sdholland 	 * The options are:
135fa577c93Sdholland 	 *    userquota[=path]          enable user quotas
136fa577c93Sdholland 	 *    groupquota[=path]         enable group quotas
137fa577c93Sdholland 	 */
138fa577c93Sdholland 
139fa577c93Sdholland 	ofe->ofe_mountpoint = NULL;
140fa577c93Sdholland 	ofe->ofe_hasuserquota = ofe->ofe_hasgroupquota = 0;
141fa577c93Sdholland 	ofe->ofe_userquotafile = ofe->ofe_groupquotafile = NULL;
142fa577c93Sdholland 
143fa577c93Sdholland 	strlcpy(buf, fs->fs_mntops, sizeof(buf));
144fa577c93Sdholland 	for (opt = strtok_r(buf, ",", &state);
145fa577c93Sdholland 	     opt != NULL;
146fa577c93Sdholland 	     opt = strtok_r(NULL, ",", &state)) {
147fa577c93Sdholland 		s = strchr(opt, '=');
148fa577c93Sdholland 		if (s != NULL) {
149fa577c93Sdholland 			*(s++) = '\0';
150fa577c93Sdholland 		}
151fa577c93Sdholland 		if (!strcmp(opt, "userquota")) {
152fa577c93Sdholland 			ret = 1;
153fa577c93Sdholland 			ofe->ofe_hasuserquota = 1;
154fa577c93Sdholland 			if (s != NULL) {
155fa577c93Sdholland 				ofe->ofe_userquotafile = strdup(s);
156fa577c93Sdholland 				if (ofe->ofe_userquotafile == NULL) {
157fa577c93Sdholland 					goto fail;
158fa577c93Sdholland 				}
159fa577c93Sdholland 			}
160fa577c93Sdholland 		} else if (!strcmp(opt, "groupquota")) {
161fa577c93Sdholland 			ret = 1;
162fa577c93Sdholland 			ofe->ofe_hasgroupquota = 1;
163fa577c93Sdholland 			if (s != NULL) {
164fa577c93Sdholland 				ofe->ofe_groupquotafile = strdup(s);
165fa577c93Sdholland 				if (ofe->ofe_groupquotafile == NULL) {
166fa577c93Sdholland 					goto fail;
167fa577c93Sdholland 				}
168fa577c93Sdholland 			}
169fa577c93Sdholland 		}
170fa577c93Sdholland 	}
171fa577c93Sdholland 
172fa577c93Sdholland 	if (ret == 1) {
173fa577c93Sdholland 		ofe->ofe_mountpoint = strdup(fs->fs_file);
174fa577c93Sdholland 		if (ofe->ofe_mountpoint == NULL) {
175fa577c93Sdholland 			goto fail;
176fa577c93Sdholland 		}
177fa577c93Sdholland 	}
178fa577c93Sdholland 
179fa577c93Sdholland 	return ret;
180fa577c93Sdholland 
181fa577c93Sdholland fail:
182fa577c93Sdholland 	serrno = errno;
183fa577c93Sdholland 	if (ofe->ofe_mountpoint != NULL) {
184fa577c93Sdholland 		free(ofe->ofe_mountpoint);
185fa577c93Sdholland 	}
186fa577c93Sdholland 	if (ofe->ofe_groupquotafile != NULL) {
187fa577c93Sdholland 		free(ofe->ofe_groupquotafile);
188fa577c93Sdholland 	}
189fa577c93Sdholland 	if (ofe->ofe_userquotafile != NULL) {
190fa577c93Sdholland 		free(ofe->ofe_userquotafile);
191fa577c93Sdholland 	}
192fa577c93Sdholland 	errno = serrno;
193fa577c93Sdholland 	return -1;
194fa577c93Sdholland }
195fa577c93Sdholland 
196fa577c93Sdholland void
__quota_oldfiles_load_fstab(void)197fa577c93Sdholland __quota_oldfiles_load_fstab(void)
198fa577c93Sdholland {
199fa577c93Sdholland 	struct oldfiles_fstabentry ofe;
200fa577c93Sdholland 	struct fstab *fs;
201fa577c93Sdholland 	int result;
202fa577c93Sdholland 
203fa577c93Sdholland 	if (__quota_oldfiles_fstab_loaded) {
204fa577c93Sdholland 		return;
205fa577c93Sdholland 	}
206fa577c93Sdholland 
207fa577c93Sdholland 	/*
208addd71bdSnjoly 	 * Check if fstab file exists before trying to parse it.
209addd71bdSnjoly 	 * Avoid warnings from {get,set}fsent() if missing.
210addd71bdSnjoly 	 */
211addd71bdSnjoly 	if (access(_PATH_FSTAB, F_OK) == -1 && errno == ENOENT)
212addd71bdSnjoly 		return;
213addd71bdSnjoly 
214addd71bdSnjoly 	/*
215fa577c93Sdholland 	 * XXX: should be able to handle ext2fs quota1 files too
216fa577c93Sdholland 	 *
217fa577c93Sdholland 	 * XXX: should use getfsent_r(), but there isn't one.
218fa577c93Sdholland 	 */
219fa577c93Sdholland 	setfsent();
220fa577c93Sdholland 	while ((fs = getfsent()) != NULL) {
221fa577c93Sdholland 		if (!strcmp(fs->fs_vfstype, "ffs") ||
222fa577c93Sdholland 		    !strcmp(fs->fs_vfstype, "lfs")) {
223fa577c93Sdholland 			result = __quota_oldfiles_fill_fstabentry(fs, &ofe);
224fa577c93Sdholland 			if (result == -1) {
225fa577c93Sdholland 				goto failed;
226fa577c93Sdholland 			}
227fa577c93Sdholland 			if (result == 0) {
228fa577c93Sdholland 				continue;
229fa577c93Sdholland 			}
230fa577c93Sdholland 			if (__quota_oldfiles_add_fstabentry(&ofe)) {
231fa577c93Sdholland 				goto failed;
232fa577c93Sdholland 			}
233fa577c93Sdholland 		}
234fa577c93Sdholland 	}
235fa577c93Sdholland 	endfsent();
236fa577c93Sdholland 	__quota_oldfiles_fstab_loaded = 1;
237fa577c93Sdholland 
238fa577c93Sdholland 	return;
239fa577c93Sdholland failed:
240fa577c93Sdholland 	warn("Failed reading fstab");
241fa577c93Sdholland 	return;
242fa577c93Sdholland }
243fa577c93Sdholland 
244fa577c93Sdholland int
__quota_oldfiles_infstab(const char * mountpoint)245fa577c93Sdholland __quota_oldfiles_infstab(const char *mountpoint)
246fa577c93Sdholland {
247fa577c93Sdholland 	return __quota_oldfiles_find_fstabentry(mountpoint) != NULL;
248fa577c93Sdholland }
249fa577c93Sdholland 
2505f0d2c5fSdholland static void
__quota_oldfiles_defquotafile(struct quotahandle * qh,int idtype,char * buf,size_t maxlen)2515f0d2c5fSdholland __quota_oldfiles_defquotafile(struct quotahandle *qh, int idtype,
2525f0d2c5fSdholland 			      char *buf, size_t maxlen)
2535f0d2c5fSdholland {
2545f0d2c5fSdholland 	static const char *const names[] = INITQFNAMES;
2555f0d2c5fSdholland 
2565f0d2c5fSdholland 	(void)snprintf(buf, maxlen, "%s/%s.%s",
2575f0d2c5fSdholland 		       qh->qh_mountpoint,
258*48747c68Shannken 		       QUOTAFILENAME, names[idtype]);
2595f0d2c5fSdholland }
2605f0d2c5fSdholland 
2615f0d2c5fSdholland const char *
__quota_oldfiles_getquotafile(struct quotahandle * qh,int idtype,char * buf,size_t maxlen)2625f0d2c5fSdholland __quota_oldfiles_getquotafile(struct quotahandle *qh, int idtype,
2635f0d2c5fSdholland 			      char *buf, size_t maxlen)
2645f0d2c5fSdholland {
2655f0d2c5fSdholland 	const struct oldfiles_fstabentry *ofe;
2665f0d2c5fSdholland 	const char *file;
2675f0d2c5fSdholland 
2685f0d2c5fSdholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
2695f0d2c5fSdholland 	if (ofe == NULL) {
2705f0d2c5fSdholland 		errno = ENXIO;
2715f0d2c5fSdholland 		return NULL;
2725f0d2c5fSdholland 	}
2735f0d2c5fSdholland 
2745f0d2c5fSdholland 	switch (idtype) {
2755f0d2c5fSdholland 	    case USRQUOTA:
2765f0d2c5fSdholland 		if (!ofe->ofe_hasuserquota) {
2775f0d2c5fSdholland 			errno = ENXIO;
2785f0d2c5fSdholland 			return NULL;
2795f0d2c5fSdholland 		}
2805f0d2c5fSdholland 		file = ofe->ofe_userquotafile;
2815f0d2c5fSdholland 		break;
2825f0d2c5fSdholland 	    case GRPQUOTA:
2835f0d2c5fSdholland 		if (!ofe->ofe_hasgroupquota) {
2845f0d2c5fSdholland 			errno = ENXIO;
2855f0d2c5fSdholland 			return NULL;
2865f0d2c5fSdholland 		}
2875f0d2c5fSdholland 		file = ofe->ofe_groupquotafile;
2885f0d2c5fSdholland 		break;
2895f0d2c5fSdholland 	    default:
2905f0d2c5fSdholland 		errno = EINVAL;
2915f0d2c5fSdholland 		return NULL;
2925f0d2c5fSdholland 	}
2935f0d2c5fSdholland 
2945f0d2c5fSdholland 	if (file == NULL) {
2955f0d2c5fSdholland 		__quota_oldfiles_defquotafile(qh, idtype, buf, maxlen);
2965f0d2c5fSdholland 		file = buf;
2975f0d2c5fSdholland 	}
2985f0d2c5fSdholland 	return file;
2995f0d2c5fSdholland }
3005f0d2c5fSdholland 
3018d70e807Sdholland static uint64_t
dqblk_getlimit(uint32_t val)30284ed28bfSdholland dqblk_getlimit(uint32_t val)
3038d70e807Sdholland {
3048d70e807Sdholland 	if (val == 0) {
3058d70e807Sdholland 		return QUOTA_NOLIMIT;
3068d70e807Sdholland 	} else {
3078d70e807Sdholland 		return val - 1;
3088d70e807Sdholland 	}
3098d70e807Sdholland }
3108d70e807Sdholland 
31184ed28bfSdholland static uint32_t
dqblk_setlimit(uint64_t val)31284ed28bfSdholland dqblk_setlimit(uint64_t val)
31384ed28bfSdholland {
31484ed28bfSdholland 	if (val == QUOTA_NOLIMIT && val >= 0xffffffffUL) {
31584ed28bfSdholland 		return 0;
31684ed28bfSdholland 	} else {
31784ed28bfSdholland 		return (uint32_t)val + 1;
31884ed28bfSdholland 	}
31984ed28bfSdholland }
32084ed28bfSdholland 
3218d70e807Sdholland static void
dqblk_getblocks(const struct dqblk * dq,struct quotaval * qv)3228d70e807Sdholland dqblk_getblocks(const struct dqblk *dq, struct quotaval *qv)
3238d70e807Sdholland {
32484ed28bfSdholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_bhardlimit);
32584ed28bfSdholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_bsoftlimit);
3268d70e807Sdholland 	qv->qv_usage = dq->dqb_curblocks;
3278d70e807Sdholland 	qv->qv_expiretime = dq->dqb_btime;
3288d70e807Sdholland 	qv->qv_grace = QUOTA_NOTIME;
3298d70e807Sdholland }
3308d70e807Sdholland 
3318d70e807Sdholland static void
dqblk_getfiles(const struct dqblk * dq,struct quotaval * qv)3328d70e807Sdholland dqblk_getfiles(const struct dqblk *dq, struct quotaval *qv)
3338d70e807Sdholland {
33484ed28bfSdholland 	qv->qv_hardlimit = dqblk_getlimit(dq->dqb_ihardlimit);
33584ed28bfSdholland 	qv->qv_softlimit = dqblk_getlimit(dq->dqb_isoftlimit);
3368d70e807Sdholland 	qv->qv_usage = dq->dqb_curinodes;
3378d70e807Sdholland 	qv->qv_expiretime = dq->dqb_itime;
3388d70e807Sdholland 	qv->qv_grace = QUOTA_NOTIME;
3398d70e807Sdholland }
3408d70e807Sdholland 
34184ed28bfSdholland static void
dqblk_putblocks(const struct quotaval * qv,struct dqblk * dq)34284ed28bfSdholland dqblk_putblocks(const struct quotaval *qv, struct dqblk *dq)
34384ed28bfSdholland {
34484ed28bfSdholland 	dq->dqb_bhardlimit = dqblk_setlimit(qv->qv_hardlimit);
34584ed28bfSdholland 	dq->dqb_bsoftlimit = dqblk_setlimit(qv->qv_softlimit);
34684ed28bfSdholland 	dq->dqb_curblocks = qv->qv_usage;
34784ed28bfSdholland 	dq->dqb_btime = qv->qv_expiretime;
34884ed28bfSdholland 	/* ignore qv->qv_grace */
34984ed28bfSdholland }
35084ed28bfSdholland 
35184ed28bfSdholland static void
dqblk_putfiles(const struct quotaval * qv,struct dqblk * dq)35284ed28bfSdholland dqblk_putfiles(const struct quotaval *qv, struct dqblk *dq)
35384ed28bfSdholland {
35484ed28bfSdholland 	dq->dqb_ihardlimit = dqblk_setlimit(qv->qv_hardlimit);
35584ed28bfSdholland 	dq->dqb_isoftlimit = dqblk_setlimit(qv->qv_softlimit);
35684ed28bfSdholland 	dq->dqb_curinodes = qv->qv_usage;
35784ed28bfSdholland 	dq->dqb_itime = qv->qv_expiretime;
35884ed28bfSdholland 	/* ignore qv->qv_grace */
35984ed28bfSdholland }
36084ed28bfSdholland 
3618d70e807Sdholland static int
__quota_oldfiles_open(struct quotahandle * qh,const char * path,int * fd_ret)3628d70e807Sdholland __quota_oldfiles_open(struct quotahandle *qh, const char *path, int *fd_ret)
3638d70e807Sdholland {
3648d70e807Sdholland 	int fd;
3658d70e807Sdholland 
3668d70e807Sdholland 	fd = open(path, O_RDWR);
3678d70e807Sdholland 	if (fd < 0 && (errno == EACCES || errno == EROFS)) {
3688d70e807Sdholland 		fd = open(path, O_RDONLY);
3698d70e807Sdholland 		if (fd < 0) {
3708d70e807Sdholland 			return -1;
3718d70e807Sdholland 		}
3728d70e807Sdholland 	}
3738d70e807Sdholland 	*fd_ret = fd;
3748d70e807Sdholland 	return 0;
3758d70e807Sdholland }
3768d70e807Sdholland 
3778d70e807Sdholland int
__quota_oldfiles_initialize(struct quotahandle * qh)3788d70e807Sdholland __quota_oldfiles_initialize(struct quotahandle *qh)
3798d70e807Sdholland {
380fa577c93Sdholland 	const struct oldfiles_fstabentry *ofe;
3818d70e807Sdholland 	char path[PATH_MAX];
3828d70e807Sdholland 	const char *userquotafile, *groupquotafile;
3838d70e807Sdholland 
384fa577c93Sdholland 	if (qh->qh_oldfilesopen) {
3858d70e807Sdholland 		/* already initialized */
3868d70e807Sdholland 		return 0;
3878d70e807Sdholland 	}
3888d70e807Sdholland 
3898d70e807Sdholland 	/*
3908d70e807Sdholland 	 * Find the fstab entry.
3918d70e807Sdholland 	 */
392fa577c93Sdholland 	ofe = __quota_oldfiles_find_fstabentry(qh->qh_mountpoint);
393fa577c93Sdholland 	if (ofe == NULL) {
3948d70e807Sdholland 		warnx("%s not found in fstab", qh->qh_mountpoint);
3958d70e807Sdholland 		errno = ENXIO;
3968d70e807Sdholland 		return -1;
3978d70e807Sdholland 	}
3988d70e807Sdholland 
399fa577c93Sdholland 	if (!ofe->ofe_hasuserquota && !ofe->ofe_hasgroupquota) {
4008d70e807Sdholland 		errno = ENXIO;
4018d70e807Sdholland 		return -1;
4028d70e807Sdholland 	}
4038d70e807Sdholland 
404fa577c93Sdholland 	if (ofe->ofe_hasuserquota) {
405fa577c93Sdholland 		userquotafile = ofe->ofe_userquotafile;
4068d70e807Sdholland 		if (userquotafile == NULL) {
4075f0d2c5fSdholland 			__quota_oldfiles_defquotafile(qh, USRQUOTA,
4085f0d2c5fSdholland 						      path, sizeof(path));
4098d70e807Sdholland 			userquotafile = path;
4108d70e807Sdholland 		}
4118d70e807Sdholland 		if (__quota_oldfiles_open(qh, userquotafile,
4128d70e807Sdholland 					  &qh->qh_userfile)) {
4138d70e807Sdholland 			return -1;
4148d70e807Sdholland 		}
4158d70e807Sdholland 	}
416fa577c93Sdholland 	if (ofe->ofe_hasgroupquota) {
417fa577c93Sdholland 		groupquotafile = ofe->ofe_groupquotafile;
4188d70e807Sdholland 		if (groupquotafile == NULL) {
4195f0d2c5fSdholland 			__quota_oldfiles_defquotafile(qh, GRPQUOTA,
4205f0d2c5fSdholland 						      path, sizeof(path));
4218d70e807Sdholland 			groupquotafile = path;
4228d70e807Sdholland 		}
4238d70e807Sdholland 		if (__quota_oldfiles_open(qh, groupquotafile,
4248d70e807Sdholland 					  &qh->qh_groupfile)) {
4258d70e807Sdholland 			return -1;
4268d70e807Sdholland 		}
4278d70e807Sdholland 	}
4288d70e807Sdholland 
429fa577c93Sdholland 	qh->qh_oldfilesopen = 1;
4308d70e807Sdholland 
4318d70e807Sdholland 	return 0;
4328d70e807Sdholland }
4338d70e807Sdholland 
4348d70e807Sdholland const char *
__quota_oldfiles_getimplname(struct quotahandle * qh)4358d70e807Sdholland __quota_oldfiles_getimplname(struct quotahandle *qh)
4368d70e807Sdholland {
437fa577c93Sdholland 	return "ufs/ffs quota v1 file access";
4388d70e807Sdholland }
4398d70e807Sdholland 
4405f0d2c5fSdholland int
__quota_oldfiles_quotaon(struct quotahandle * qh,int idtype)4415f0d2c5fSdholland __quota_oldfiles_quotaon(struct quotahandle *qh, int idtype)
4425f0d2c5fSdholland {
4435f0d2c5fSdholland 	int result;
4445f0d2c5fSdholland 
4455f0d2c5fSdholland 	/*
4465f0d2c5fSdholland 	 * If we have the quota files open, close them.
4475f0d2c5fSdholland 	 */
4485f0d2c5fSdholland 
4495f0d2c5fSdholland 	if (qh->qh_oldfilesopen) {
4505f0d2c5fSdholland 		if (qh->qh_userfile >= 0) {
4515f0d2c5fSdholland 			close(qh->qh_userfile);
4525f0d2c5fSdholland 			qh->qh_userfile = -1;
4535f0d2c5fSdholland 		}
4545f0d2c5fSdholland 		if (qh->qh_groupfile >= 0) {
4555f0d2c5fSdholland 			close(qh->qh_groupfile);
4565f0d2c5fSdholland 			qh->qh_groupfile = -1;
4575f0d2c5fSdholland 		}
4585f0d2c5fSdholland 		qh->qh_oldfilesopen = 0;
4595f0d2c5fSdholland 	}
4605f0d2c5fSdholland 
4615f0d2c5fSdholland 	/*
4625f0d2c5fSdholland 	 * Go over to the syscall interface.
4635f0d2c5fSdholland 	 */
4645f0d2c5fSdholland 
46559b296daSdholland 	result = __quota_kernel_quotaon(qh, idtype);
4665f0d2c5fSdholland 	if (result < 0) {
4675f0d2c5fSdholland 		return -1;
4685f0d2c5fSdholland 	}
4695f0d2c5fSdholland 
4705f0d2c5fSdholland 	/*
4715f0d2c5fSdholland 	 * We succeeded, so all further access should be via the
4725f0d2c5fSdholland 	 * kernel.
4735f0d2c5fSdholland 	 */
4745f0d2c5fSdholland 
47559b296daSdholland 	qh->qh_mode = QUOTA_MODE_KERNEL;
4765f0d2c5fSdholland 	return 0;
4775f0d2c5fSdholland }
4785f0d2c5fSdholland 
4798d70e807Sdholland static int
__quota_oldfiles_doget(struct quotahandle * qh,const struct quotakey * qk,struct quotaval * qv,int * isallzero)4808d70e807Sdholland __quota_oldfiles_doget(struct quotahandle *qh, const struct quotakey *qk,
4818d70e807Sdholland 		       struct quotaval *qv, int *isallzero)
4828d70e807Sdholland {
4838d70e807Sdholland 	int file;
4848d70e807Sdholland 	off_t pos;
4858d70e807Sdholland 	struct dqblk dq;
4868d70e807Sdholland 	ssize_t result;
4878d70e807Sdholland 
488fa577c93Sdholland 	if (!qh->qh_oldfilesopen) {
489fa577c93Sdholland 		if (__quota_oldfiles_initialize(qh)) {
490fa577c93Sdholland 			return -1;
491fa577c93Sdholland 		}
492fa577c93Sdholland 	}
493fa577c93Sdholland 
4948d70e807Sdholland 	switch (qk->qk_idtype) {
4958d70e807Sdholland 	    case QUOTA_IDTYPE_USER:
4968d70e807Sdholland 		file = qh->qh_userfile;
4978d70e807Sdholland 		break;
4988d70e807Sdholland 	    case QUOTA_IDTYPE_GROUP:
4998d70e807Sdholland 		file = qh->qh_groupfile;
5008d70e807Sdholland 		break;
5018d70e807Sdholland 	    default:
5028d70e807Sdholland 		errno = EINVAL;
5038d70e807Sdholland 		return -1;
5048d70e807Sdholland 	}
5058d70e807Sdholland 
5068d70e807Sdholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
5078d70e807Sdholland 		pos = 0;
5088d70e807Sdholland 	} else {
5098d70e807Sdholland 		pos = qk->qk_id * sizeof(struct dqblk);
5108d70e807Sdholland 	}
5118d70e807Sdholland 
5128d70e807Sdholland 	result = pread(file, &dq, sizeof(dq), pos);
5138d70e807Sdholland 	if (result < 0) {
5148d70e807Sdholland 		return -1;
51584ed28bfSdholland 	} else if (result == 0) {
51684ed28bfSdholland 		/* Past EOF; no quota info on file for this ID */
51784ed28bfSdholland 		errno = ENOENT;
51884ed28bfSdholland 		return -1;
51984ed28bfSdholland 	} else if ((size_t)result != sizeof(dq)) {
5208d70e807Sdholland 		errno = EFTYPE;
5218d70e807Sdholland 		return -1;
5228d70e807Sdholland 	}
5238d70e807Sdholland 
5248d70e807Sdholland 	switch (qk->qk_objtype) {
5258d70e807Sdholland 	    case QUOTA_OBJTYPE_BLOCKS:
5268d70e807Sdholland 		dqblk_getblocks(&dq, qv);
5278d70e807Sdholland 		break;
5288d70e807Sdholland 	    case QUOTA_OBJTYPE_FILES:
5298d70e807Sdholland 		dqblk_getfiles(&dq, qv);
5308d70e807Sdholland 		break;
5318d70e807Sdholland 	    default:
5328d70e807Sdholland 		errno = EINVAL;
5338d70e807Sdholland 		return -1;
5348d70e807Sdholland 	}
5358d70e807Sdholland 
5368d70e807Sdholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
5378d70e807Sdholland 		qv->qv_usage = 0;
5388d70e807Sdholland 		qv->qv_grace = qv->qv_expiretime;
5398d70e807Sdholland 		qv->qv_expiretime = QUOTA_NOTIME;
5408d70e807Sdholland 	} else if (qk->qk_id == 0) {
5418d70e807Sdholland 		qv->qv_hardlimit = 0;
5428d70e807Sdholland 		qv->qv_softlimit = 0;
5438d70e807Sdholland 		qv->qv_expiretime = QUOTA_NOTIME;
5448d70e807Sdholland 		qv->qv_grace = QUOTA_NOTIME;
5458d70e807Sdholland 	}
5468d70e807Sdholland 
5478d70e807Sdholland 	if (isallzero != NULL) {
5488d70e807Sdholland 		if (dq.dqb_bhardlimit == 0 &&
5498d70e807Sdholland 		    dq.dqb_bsoftlimit == 0 &&
5508d70e807Sdholland 		    dq.dqb_curblocks == 0 &&
5518d70e807Sdholland 		    dq.dqb_ihardlimit == 0 &&
5528d70e807Sdholland 		    dq.dqb_isoftlimit == 0 &&
5538d70e807Sdholland 		    dq.dqb_curinodes == 0 &&
5548d70e807Sdholland 		    dq.dqb_btime == 0 &&
5558d70e807Sdholland 		    dq.dqb_itime == 0) {
5568d70e807Sdholland 			*isallzero = 1;
5578d70e807Sdholland 		} else {
5588d70e807Sdholland 			*isallzero = 0;
5598d70e807Sdholland 		}
5608d70e807Sdholland 	}
5618d70e807Sdholland 
5628d70e807Sdholland 	return 0;
5638d70e807Sdholland }
5648d70e807Sdholland 
56584ed28bfSdholland static int
__quota_oldfiles_doput(struct quotahandle * qh,const struct quotakey * qk,const struct quotaval * qv)56684ed28bfSdholland __quota_oldfiles_doput(struct quotahandle *qh, const struct quotakey *qk,
56784ed28bfSdholland 		       const struct quotaval *qv)
56884ed28bfSdholland {
56984ed28bfSdholland 	int file;
57084ed28bfSdholland 	off_t pos;
57184ed28bfSdholland 	struct quotaval qv2;
57284ed28bfSdholland 	struct dqblk dq;
57384ed28bfSdholland 	ssize_t result;
57484ed28bfSdholland 
575fa577c93Sdholland 	if (!qh->qh_oldfilesopen) {
576fa577c93Sdholland 		if (__quota_oldfiles_initialize(qh)) {
577fa577c93Sdholland 			return -1;
578fa577c93Sdholland 		}
579fa577c93Sdholland 	}
580fa577c93Sdholland 
58184ed28bfSdholland 	switch (qk->qk_idtype) {
58284ed28bfSdholland 	    case QUOTA_IDTYPE_USER:
58384ed28bfSdholland 		file = qh->qh_userfile;
58484ed28bfSdholland 		break;
58584ed28bfSdholland 	    case QUOTA_IDTYPE_GROUP:
58684ed28bfSdholland 		file = qh->qh_groupfile;
58784ed28bfSdholland 		break;
58884ed28bfSdholland 	    default:
58984ed28bfSdholland 		errno = EINVAL;
59084ed28bfSdholland 		return -1;
59184ed28bfSdholland 	}
59284ed28bfSdholland 
59384ed28bfSdholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
59484ed28bfSdholland 		pos = 0;
59584ed28bfSdholland 	} else {
59684ed28bfSdholland 		pos = qk->qk_id * sizeof(struct dqblk);
59784ed28bfSdholland 	}
59884ed28bfSdholland 
59984ed28bfSdholland 	result = pread(file, &dq, sizeof(dq), pos);
60084ed28bfSdholland 	if (result < 0) {
60184ed28bfSdholland 		return -1;
60284ed28bfSdholland 	} else if (result == 0) {
60384ed28bfSdholland 		/* Past EOF; fill in a blank dq to start from */
60484ed28bfSdholland 		dq.dqb_bhardlimit = 0;
60584ed28bfSdholland 		dq.dqb_bsoftlimit = 0;
60684ed28bfSdholland 		dq.dqb_curblocks = 0;
60784ed28bfSdholland 		dq.dqb_ihardlimit = 0;
60884ed28bfSdholland 		dq.dqb_isoftlimit = 0;
60984ed28bfSdholland 		dq.dqb_curinodes = 0;
61084ed28bfSdholland 		dq.dqb_btime = 0;
61184ed28bfSdholland 		dq.dqb_itime = 0;
61284ed28bfSdholland 	} else if ((size_t)result != sizeof(dq)) {
61384ed28bfSdholland 		errno = EFTYPE;
61484ed28bfSdholland 		return -1;
61584ed28bfSdholland 	}
61684ed28bfSdholland 
61784ed28bfSdholland 	switch (qk->qk_objtype) {
61884ed28bfSdholland 	    case QUOTA_OBJTYPE_BLOCKS:
61984ed28bfSdholland 		dqblk_getblocks(&dq, &qv2);
62084ed28bfSdholland 		break;
62184ed28bfSdholland 	    case QUOTA_OBJTYPE_FILES:
62284ed28bfSdholland 		dqblk_getfiles(&dq, &qv2);
62384ed28bfSdholland 		break;
62484ed28bfSdholland 	    default:
62584ed28bfSdholland 		errno = EINVAL;
62684ed28bfSdholland 		return -1;
62784ed28bfSdholland 	}
62884ed28bfSdholland 
62984ed28bfSdholland 	if (qk->qk_id == QUOTA_DEFAULTID) {
63084ed28bfSdholland 		qv2.qv_hardlimit = qv->qv_hardlimit;
63184ed28bfSdholland 		qv2.qv_softlimit = qv->qv_softlimit;
63284ed28bfSdholland 		/* leave qv2.qv_usage unchanged */
63384ed28bfSdholland 		qv2.qv_expiretime = qv->qv_grace;
63484ed28bfSdholland 		/* skip qv2.qv_grace */
63584ed28bfSdholland 
63684ed28bfSdholland 		/* ignore qv->qv_usage */
63784ed28bfSdholland 		/* ignore qv->qv_expiretime */
63884ed28bfSdholland 	} else if (qk->qk_id == 0) {
63984ed28bfSdholland 		/* leave qv2.qv_hardlimit unchanged */
64084ed28bfSdholland 		/* leave qv2.qv_softlimit unchanged */
64184ed28bfSdholland 		qv2.qv_usage = qv->qv_usage;
64284ed28bfSdholland 		/* leave qv2.qv_expiretime unchanged */
64384ed28bfSdholland 		/* skip qv2.qv_grace */
64484ed28bfSdholland 
64584ed28bfSdholland 		/* ignore qv->qv_hardlimit */
64684ed28bfSdholland 		/* ignore qv->qv_softlimit */
64784ed28bfSdholland 		/* ignore qv->qv_expiretime */
64884ed28bfSdholland 		/* ignore qv->qv_grace */
64984ed28bfSdholland 	} else {
65084ed28bfSdholland 		qv2 = *qv;
65184ed28bfSdholland 	}
65284ed28bfSdholland 
65384ed28bfSdholland 	switch (qk->qk_objtype) {
65484ed28bfSdholland 	    case QUOTA_OBJTYPE_BLOCKS:
65584ed28bfSdholland 		dqblk_putblocks(&qv2, &dq);
65684ed28bfSdholland 		break;
65784ed28bfSdholland 	    case QUOTA_OBJTYPE_FILES:
65884ed28bfSdholland 		dqblk_putfiles(&qv2, &dq);
65984ed28bfSdholland 		break;
66084ed28bfSdholland 	    default:
66184ed28bfSdholland 		errno = EINVAL;
66284ed28bfSdholland 		return -1;
66384ed28bfSdholland 	}
66484ed28bfSdholland 
66584ed28bfSdholland 	result = pwrite(file, &dq, sizeof(dq), pos);
66684ed28bfSdholland 	if (result < 0) {
66784ed28bfSdholland 		return -1;
66884ed28bfSdholland 	} else if ((size_t)result != sizeof(dq)) {
66984ed28bfSdholland 		/* ? */
67084ed28bfSdholland 		errno = EFTYPE;
67184ed28bfSdholland 		return -1;
67284ed28bfSdholland 	}
67384ed28bfSdholland 
67484ed28bfSdholland 	return 0;
67584ed28bfSdholland }
67684ed28bfSdholland 
6778d70e807Sdholland int
__quota_oldfiles_get(struct quotahandle * qh,const struct quotakey * qk,struct quotaval * qv)6788d70e807Sdholland __quota_oldfiles_get(struct quotahandle *qh, const struct quotakey *qk,
6798d70e807Sdholland 		     struct quotaval *qv)
6808d70e807Sdholland {
6818d70e807Sdholland 	return __quota_oldfiles_doget(qh, qk, qv, NULL);
6828d70e807Sdholland }
6838d70e807Sdholland 
68484ed28bfSdholland int
__quota_oldfiles_put(struct quotahandle * qh,const struct quotakey * qk,const struct quotaval * qv)68584ed28bfSdholland __quota_oldfiles_put(struct quotahandle *qh, const struct quotakey *qk,
68684ed28bfSdholland 		     const struct quotaval *qv)
68784ed28bfSdholland {
68884ed28bfSdholland 	return __quota_oldfiles_doput(qh, qk, qv);
68984ed28bfSdholland }
69084ed28bfSdholland 
69184ed28bfSdholland int
__quota_oldfiles_delete(struct quotahandle * qh,const struct quotakey * qk)69284ed28bfSdholland __quota_oldfiles_delete(struct quotahandle *qh, const struct quotakey *qk)
69384ed28bfSdholland {
69484ed28bfSdholland 	struct quotaval qv;
69584ed28bfSdholland 
69684ed28bfSdholland 	quotaval_clear(&qv);
69784ed28bfSdholland 	return __quota_oldfiles_doput(qh, qk, &qv);
69884ed28bfSdholland }
69984ed28bfSdholland 
7008d70e807Sdholland struct oldfiles_quotacursor *
__quota_oldfiles_cursor_create(struct quotahandle * qh)7018d70e807Sdholland __quota_oldfiles_cursor_create(struct quotahandle *qh)
7028d70e807Sdholland {
7038d70e807Sdholland 	struct oldfiles_quotacursor *oqc;
7048d70e807Sdholland 	struct stat st;
7058d70e807Sdholland 	int serrno;
7068d70e807Sdholland 
707fa577c93Sdholland 	/* quota_opencursor calls initialize for us, no need to do it here */
708fa577c93Sdholland 
7098d70e807Sdholland 	oqc = malloc(sizeof(*oqc));
7108d70e807Sdholland 	if (oqc == NULL) {
7118d70e807Sdholland 		return NULL;
7128d70e807Sdholland 	}
7138d70e807Sdholland 
7148d70e807Sdholland 	oqc->oqc_didusers = 0;
7158d70e807Sdholland 	oqc->oqc_didgroups = 0;
7168d70e807Sdholland 	oqc->oqc_diddefault = 0;
7178d70e807Sdholland 	oqc->oqc_pos = 0;
7188d70e807Sdholland 	oqc->oqc_didblocks = 0;
7198d70e807Sdholland 
7208d70e807Sdholland 	if (qh->qh_userfile >= 0) {
7218d70e807Sdholland 		oqc->oqc_doingusers = 1;
7228d70e807Sdholland 	} else {
7238d70e807Sdholland 		oqc->oqc_doingusers = 0;
7248d70e807Sdholland 		oqc->oqc_didusers = 1;
7258d70e807Sdholland 	}
7268d70e807Sdholland 
7278d70e807Sdholland 	if (qh->qh_groupfile >= 0) {
7288d70e807Sdholland 		oqc->oqc_doinggroups = 1;
7298d70e807Sdholland 	} else {
7308d70e807Sdholland 		oqc->oqc_doinggroups = 0;
7318d70e807Sdholland 		oqc->oqc_didgroups = 1;
7328d70e807Sdholland 	}
7338d70e807Sdholland 
7348d70e807Sdholland 	if (fstat(qh->qh_userfile, &st) < 0) {
7358d70e807Sdholland 		serrno = errno;
7368d70e807Sdholland 		free(oqc);
7378d70e807Sdholland 		errno = serrno;
7388d70e807Sdholland 		return NULL;
7398d70e807Sdholland 	}
7408d70e807Sdholland 	oqc->oqc_numusers = st.st_size / sizeof(struct dqblk);
7418d70e807Sdholland 
7428d70e807Sdholland 	if (fstat(qh->qh_groupfile, &st) < 0) {
7438d70e807Sdholland 		serrno = errno;
7448d70e807Sdholland 		free(oqc);
7458d70e807Sdholland 		errno = serrno;
7468d70e807Sdholland 		return NULL;
7478d70e807Sdholland 	}
7488d70e807Sdholland 	oqc->oqc_numgroups = st.st_size / sizeof(struct dqblk);
7498d70e807Sdholland 
7508d70e807Sdholland 	return oqc;
7518d70e807Sdholland }
7528d70e807Sdholland 
7538d70e807Sdholland void
__quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor * oqc)7548d70e807Sdholland __quota_oldfiles_cursor_destroy(struct oldfiles_quotacursor *oqc)
7558d70e807Sdholland {
7568d70e807Sdholland 	free(oqc);
7578d70e807Sdholland }
7588d70e807Sdholland 
7598d70e807Sdholland int
__quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor * oqc,int idtype)7608d70e807Sdholland __quota_oldfiles_cursor_skipidtype(struct oldfiles_quotacursor *oqc,
761832d4ca7Sdholland 				   int idtype)
7628d70e807Sdholland {
7638d70e807Sdholland 	switch (idtype) {
7648d70e807Sdholland 	    case QUOTA_IDTYPE_USER:
7658d70e807Sdholland 		oqc->oqc_doingusers = 0;
7668d70e807Sdholland 		oqc->oqc_didusers = 1;
7678d70e807Sdholland 		break;
7688d70e807Sdholland 	    case QUOTA_IDTYPE_GROUP:
7698d70e807Sdholland 		oqc->oqc_doinggroups = 0;
7708d70e807Sdholland 		oqc->oqc_didgroups = 1;
7718d70e807Sdholland 		break;
7728d70e807Sdholland 	    default:
7738d70e807Sdholland 		errno = EINVAL;
7748d70e807Sdholland 		return -1;
7758d70e807Sdholland 	}
7768d70e807Sdholland 	return 0;
7778d70e807Sdholland }
7788d70e807Sdholland 
7798d70e807Sdholland int
__quota_oldfiles_cursor_get(struct quotahandle * qh,struct oldfiles_quotacursor * oqc,struct quotakey * key,struct quotaval * val)7808d70e807Sdholland __quota_oldfiles_cursor_get(struct quotahandle *qh,
7818d70e807Sdholland 			    struct oldfiles_quotacursor *oqc,
7828d70e807Sdholland 			    struct quotakey *key, struct quotaval *val)
7838d70e807Sdholland {
7848d70e807Sdholland 	unsigned maxpos;
7858d70e807Sdholland 	int isallzero;
7868d70e807Sdholland 
7878d70e807Sdholland 	/* in case one of the sizes is zero */
7888d70e807Sdholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
7898d70e807Sdholland 		oqc->oqc_didusers = 1;
7908d70e807Sdholland 	}
7918d70e807Sdholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
7928d70e807Sdholland 		oqc->oqc_didgroups = 1;
7938d70e807Sdholland 	}
7948d70e807Sdholland 
7958d70e807Sdholland  again:
7968d70e807Sdholland 	/*
7978d70e807Sdholland 	 * Figure out what to get
7988d70e807Sdholland 	 */
7998d70e807Sdholland 
8008d70e807Sdholland 	if (!oqc->oqc_didusers) {
8018d70e807Sdholland 		key->qk_idtype = QUOTA_IDTYPE_USER;
8028d70e807Sdholland 		maxpos = oqc->oqc_numusers;
8038d70e807Sdholland 	} else if (!oqc->oqc_didgroups) {
8048d70e807Sdholland 		key->qk_idtype = QUOTA_IDTYPE_GROUP;
8058d70e807Sdholland 		maxpos = oqc->oqc_numgroups;
8068d70e807Sdholland 	} else {
8078d70e807Sdholland 		errno = ENOENT;
8088d70e807Sdholland 		return -1;
8098d70e807Sdholland 	}
8108d70e807Sdholland 
8118d70e807Sdholland 	if (!oqc->oqc_diddefault) {
8128d70e807Sdholland 		key->qk_id = QUOTA_DEFAULTID;
8138d70e807Sdholland 	} else {
8148d70e807Sdholland 		key->qk_id = oqc->oqc_pos;
8158d70e807Sdholland 	}
8168d70e807Sdholland 
8178d70e807Sdholland 	if (!oqc->oqc_didblocks) {
8188d70e807Sdholland 		key->qk_objtype = QUOTA_OBJTYPE_BLOCKS;
8198d70e807Sdholland 	} else {
8208d70e807Sdholland 		key->qk_objtype = QUOTA_OBJTYPE_FILES;
8218d70e807Sdholland 	}
8228d70e807Sdholland 
8238d70e807Sdholland 	/*
8248d70e807Sdholland 	 * Get it
8258d70e807Sdholland 	 */
8268d70e807Sdholland 
8278d70e807Sdholland 	if (__quota_oldfiles_doget(qh, key, val, &isallzero)) {
8288d70e807Sdholland 		return -1;
8298d70e807Sdholland 	}
8308d70e807Sdholland 
8318d70e807Sdholland 	/*
8328d70e807Sdholland 	 * Advance the cursor
8338d70e807Sdholland 	 */
8348d70e807Sdholland 	if (!oqc->oqc_didblocks) {
8358d70e807Sdholland 		oqc->oqc_didblocks = 1;
8368d70e807Sdholland 	} else {
8378d70e807Sdholland 		oqc->oqc_didblocks = 0;
8388d70e807Sdholland 		if (!oqc->oqc_diddefault) {
8398d70e807Sdholland 			oqc->oqc_diddefault = 1;
8408d70e807Sdholland 		} else {
8418d70e807Sdholland 			oqc->oqc_pos++;
8428d70e807Sdholland 			if (oqc->oqc_pos >= maxpos) {
8438d70e807Sdholland 				oqc->oqc_pos = 0;
8448d70e807Sdholland 				oqc->oqc_diddefault = 0;
8458d70e807Sdholland 				if (!oqc->oqc_didusers) {
8468d70e807Sdholland 					oqc->oqc_didusers = 1;
8478d70e807Sdholland 				} else {
8488d70e807Sdholland 					oqc->oqc_didgroups = 1;
8498d70e807Sdholland 				}
8508d70e807Sdholland 			}
8518d70e807Sdholland 		}
8528d70e807Sdholland 	}
8538d70e807Sdholland 
8548d70e807Sdholland 	/*
8558d70e807Sdholland 	 * If we got an all-zero dqblk (e.g. from the middle of a hole
8568d70e807Sdholland 	 * in the quota file) don't bother returning it to the caller.
8578d70e807Sdholland 	 *
8588d70e807Sdholland 	 * ...unless we're at the end of the data, to avoid going past
8598d70e807Sdholland 	 * the end and generating a spurious failure. There's no
8608d70e807Sdholland 	 * reasonable way to make _atend detect empty entries at the
8618d70e807Sdholland 	 * end of the quota files.
8628d70e807Sdholland 	 */
8638d70e807Sdholland 	if (isallzero && (!oqc->oqc_didusers || !oqc->oqc_didgroups)) {
8648d70e807Sdholland 		goto again;
8658d70e807Sdholland 	}
8668d70e807Sdholland 	return 0;
8678d70e807Sdholland }
8688d70e807Sdholland 
8698d70e807Sdholland int
__quota_oldfiles_cursor_getn(struct quotahandle * qh,struct oldfiles_quotacursor * oqc,struct quotakey * keys,struct quotaval * vals,unsigned maxnum)8708d70e807Sdholland __quota_oldfiles_cursor_getn(struct quotahandle *qh,
8718d70e807Sdholland 			     struct oldfiles_quotacursor *oqc,
8728d70e807Sdholland 			     struct quotakey *keys, struct quotaval *vals,
8738d70e807Sdholland 			     unsigned maxnum)
8748d70e807Sdholland {
8758d70e807Sdholland 	unsigned i;
8768d70e807Sdholland 
8778d70e807Sdholland 	if (maxnum > INT_MAX) {
8788d70e807Sdholland 		/* joker, eh? */
8798d70e807Sdholland 		errno = EINVAL;
8808d70e807Sdholland 		return -1;
8818d70e807Sdholland 	}
8828d70e807Sdholland 
8838d70e807Sdholland 	for (i=0; i<maxnum; i++) {
8848d70e807Sdholland 		if (__quota_oldfiles_cursor_atend(oqc)) {
8858d70e807Sdholland 			break;
8868d70e807Sdholland 		}
8878d70e807Sdholland 		if (__quota_oldfiles_cursor_get(qh, oqc, &keys[i], &vals[i])) {
8888d70e807Sdholland 			if (i > 0) {
8898d70e807Sdholland 				/*
8908d70e807Sdholland 				 * Succeed witih what we have so far;
8918d70e807Sdholland 				 * the next attempt will hit the same
8928d70e807Sdholland 				 * error again.
8938d70e807Sdholland 				 */
8948d70e807Sdholland 				break;
8958d70e807Sdholland 			}
8968d70e807Sdholland 			return -1;
8978d70e807Sdholland 		}
8988d70e807Sdholland 	}
8998d70e807Sdholland 	return i;
9008d70e807Sdholland 
9018d70e807Sdholland }
9028d70e807Sdholland 
9038d70e807Sdholland int
__quota_oldfiles_cursor_atend(struct oldfiles_quotacursor * oqc)9048d70e807Sdholland __quota_oldfiles_cursor_atend(struct oldfiles_quotacursor *oqc)
9058d70e807Sdholland {
9068d70e807Sdholland 	/* in case one of the sizes is zero */
9078d70e807Sdholland 	if (!oqc->oqc_didusers && oqc->oqc_pos >= oqc->oqc_numusers) {
9088d70e807Sdholland 		oqc->oqc_didusers = 1;
9098d70e807Sdholland 	}
9108d70e807Sdholland 	if (!oqc->oqc_didgroups && oqc->oqc_pos >= oqc->oqc_numgroups) {
9118d70e807Sdholland 		oqc->oqc_didgroups = 1;
9128d70e807Sdholland 	}
9138d70e807Sdholland 
9148d70e807Sdholland 	return oqc->oqc_didusers && oqc->oqc_didgroups;
9158d70e807Sdholland }
9168d70e807Sdholland 
9178d70e807Sdholland int
__quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor * oqc)9188d70e807Sdholland __quota_oldfiles_cursor_rewind(struct oldfiles_quotacursor *oqc)
9198d70e807Sdholland {
9208d70e807Sdholland 	oqc->oqc_didusers = 0;
9218d70e807Sdholland 	oqc->oqc_didgroups = 0;
9228d70e807Sdholland 	oqc->oqc_diddefault = 0;
9238d70e807Sdholland 	oqc->oqc_pos = 0;
9248d70e807Sdholland 	oqc->oqc_didblocks = 0;
9258d70e807Sdholland 	return 0;
9268d70e807Sdholland }
927