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