1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/param.h>
25#include <sys/attr.h>
26#include <sys/quota.h>
27#include <sys/vnode.h>
28
29#include <err.h>
30#include <errno.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
35
36#include "quotacheck.h"
37
38
39/*
40 * Query is based on uid
41 */
42#define QQ_COMMON	(ATTR_CMN_OWNERID)
43
44struct quota_query {
45	u_int32_t	qq_len;
46	uid_t		qq_uid;
47};
48
49/*
50 * Desired atttributes for quota checking
51 */
52#define QA_COMMON	(ATTR_CMN_OBJTYPE | ATTR_CMN_OWNERID | ATTR_CMN_GRPID)
53#define QA_FILE		(ATTR_FILE_ALLOCSIZE)
54#define QA_DIR		(0)
55
56struct quota_attr {
57	u_int32_t	qa_attrlen;
58	fsobj_type_t	qa_type;
59	uid_t		qa_uid;
60	gid_t		qa_gid;
61	off_t		qa_bytes;
62};
63
64#define ITEMS_PER_SEARCH  2500
65
66void collectdata(const char*, struct quotaname *);
67
68
69/*
70 * Scan an HFS filesystem to check quota(s) present on it.
71 */
72int
73chkquota_hfs(fsname, mntpt, qnp)
74	char *fsname, *mntpt;
75	register struct quotaname *qnp;
76{
77	int errs = 0;
78
79	sync();
80
81	collectdata(mntpt, qnp);
82
83	if (qnp->flags & HASUSR)
84		errs = update(mntpt, qnp->usrqfname, USRQUOTA);
85	if (qnp->flags & HASGRP)
86		errs = update(mntpt, qnp->grpqfname, GRPQUOTA);
87
88	return (errs);
89}
90
91
92void
93collectdata(const char* path, struct quotaname *qnp)
94{
95	struct fssearchblock searchblk = {0};
96	struct attrlist	attrlist = {0};
97	struct searchstate state;
98	struct quota_attr *qap;
99	struct quota_query query;
100	u_long nummatches;
101	u_int options;
102
103	int i;
104	int result;
105	int vntype;
106	off_t filebytes;
107	register struct fileusage *fup;
108
109	qap = malloc(ITEMS_PER_SEARCH * sizeof(struct quota_attr));
110	if (qap == NULL)
111		err(1, "%s", strerror(errno));
112
113	options = SRCHFS_START |SRCHFS_MATCHDIRS | SRCHFS_MATCHFILES;
114
115	/* Search for items with uid != 0 */
116	query.qq_len = sizeof(struct quota_query);
117	query.qq_uid = 0;
118	options |= SRCHFS_NEGATEPARAMS | SRCHFS_SKIPLINKS;
119	searchblk.searchattrs.bitmapcount = ATTR_BIT_MAP_COUNT;
120	searchblk.searchattrs.commonattr = QQ_COMMON;
121	searchblk.searchparams1 = &query;
122	searchblk.searchparams2 = &query;
123	searchblk.sizeofsearchparams1 = sizeof(query);
124	searchblk.sizeofsearchparams2 = sizeof(query);
125
126	/* Ask for type, uid, gid and file bytes */
127	searchblk.returnattrs = &attrlist;
128	attrlist.bitmapcount  = ATTR_BIT_MAP_COUNT;
129	attrlist.commonattr   = QA_COMMON;
130	attrlist.dirattr      = QA_DIR;
131	attrlist.fileattr     = QA_FILE;
132
133	/* Collect 2,500 items at a time (~60K) */
134 	searchblk.returnbuffer = qap;
135	searchblk.returnbuffersize = ITEMS_PER_SEARCH * sizeof(struct quota_attr);
136	searchblk.maxmatches = ITEMS_PER_SEARCH;
137
138	for (;;) {
139		nummatches = 0;
140		result = searchfs(path, &searchblk, &nummatches, 0, options, &state);
141		if (result && errno != EAGAIN && errno != EBUSY) {
142			fprintf(stderr, "%d \n", errno);
143			err(1, "searchfs %s", strerror(errno));
144		}
145		if (result == 0 && nummatches == 0)
146			break;  /* all done */
147		options &= ~SRCHFS_START;
148
149		for (i = 0; i < nummatches; ++i) {
150			vntype = qap[i].qa_type;
151			filebytes = (vntype == VDIR) ? 0 : qap[i].qa_bytes;
152
153			if (qnp->flags & HASGRP) {
154				fup = addid(qap[i].qa_gid, GRPQUOTA);
155				fup->fu_curinodes++;
156				if (vntype == VREG || vntype == VDIR || vntype == VLNK)
157					fup->fu_curbytes += filebytes;
158			}
159			if (qnp->flags & HASUSR) {
160				fup = addid(qap[i].qa_uid, USRQUOTA);
161				fup->fu_curinodes++;
162				if (vntype == VREG || vntype == VDIR || vntype == VLNK)
163					fup->fu_curbytes += filebytes;
164			}
165		}
166	}
167
168	free(qap);
169}
170