1 1.45 christos /* $NetBSD: repquota.c,v 1.45 2015/06/16 23:04:14 christos Exp $ */ 2 1.27 christos 3 1.1 cgd /* 4 1.4 mycroft * Copyright (c) 1980, 1990, 1993 5 1.4 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Robert Elz at The University of Melbourne. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.20 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.10 mrg #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.23 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ 38 1.23 lukem The Regents of the University of California. All rights reserved."); 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd #ifndef lint 42 1.10 mrg #if 0 43 1.10 mrg static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94"; 44 1.10 mrg #else 45 1.45 christos __RCSID("$NetBSD: repquota.c,v 1.45 2015/06/16 23:04:14 christos Exp $"); 46 1.10 mrg #endif 47 1.1 cgd #endif /* not lint */ 48 1.1 cgd 49 1.1 cgd /* 50 1.1 cgd * Quota report 51 1.1 cgd */ 52 1.1 cgd #include <sys/param.h> 53 1.1 cgd #include <sys/stat.h> 54 1.26 bouyer #include <sys/types.h> 55 1.26 bouyer #include <sys/statvfs.h> 56 1.26 bouyer 57 1.11 lukem #include <errno.h> 58 1.26 bouyer #include <err.h> 59 1.1 cgd #include <fstab.h> 60 1.11 lukem #include <grp.h> 61 1.1 cgd #include <pwd.h> 62 1.1 cgd #include <stdio.h> 63 1.11 lukem #include <stdlib.h> 64 1.6 cgd #include <string.h> 65 1.11 lukem #include <unistd.h> 66 1.1 cgd 67 1.34 dholland #include <quota.h> 68 1.26 bouyer 69 1.27 christos #include "printquota.h" 70 1.1 cgd 71 1.38 dholland /* 72 1.38 dholland * XXX. Ideally we shouldn't compile either of these in, but it's a 73 1.38 dholland * nontrivial rework to avoid it and it'll work ok for now. 74 1.38 dholland */ 75 1.38 dholland #define REPQUOTA_NUMIDTYPES 2 76 1.38 dholland #define REPQUOTA_NUMOBJTYPES 2 77 1.38 dholland 78 1.1 cgd struct fileusage { 79 1.1 cgd struct fileusage *fu_next; 80 1.38 dholland struct quotaval fu_qv[REPQUOTA_NUMOBJTYPES]; 81 1.27 christos uint32_t fu_id; 82 1.1 cgd char fu_name[1]; 83 1.1 cgd /* actually bigger */ 84 1.1 cgd }; 85 1.38 dholland 86 1.1 cgd #define FUHASH 1024 /* must be power of two */ 87 1.38 dholland static struct fileusage *fuhead[REPQUOTA_NUMIDTYPES][FUHASH]; 88 1.38 dholland 89 1.38 dholland /* highest addid()'ed identifier per idtype */ 90 1.38 dholland static uint32_t highid[REPQUOTA_NUMIDTYPES]; 91 1.38 dholland 92 1.38 dholland int valid[REPQUOTA_NUMIDTYPES]; 93 1.38 dholland 94 1.38 dholland static struct quotaval defaultqv[REPQUOTA_NUMIDTYPES][REPQUOTA_NUMOBJTYPES]; 95 1.1 cgd 96 1.27 christos static int vflag = 0; /* verbose */ 97 1.27 christos static int aflag = 0; /* all file systems */ 98 1.27 christos static int hflag = 0; /* humanize */ 99 1.27 christos static int xflag = 0; /* export */ 100 1.27 christos 101 1.38 dholland /* 102 1.38 dholland * XXX this should go away and be replaced with a call to 103 1.38 dholland * quota_idtype_getname(), but that needs a quotahandle and requires 104 1.38 dholland * the same nontrivial rework as getting rid of REPQUOTA_NUMIDTYPES. 105 1.38 dholland */ 106 1.38 dholland static const char *const repquota_idtype_names[REPQUOTA_NUMIDTYPES] = { 107 1.38 dholland "user", 108 1.38 dholland "group", 109 1.38 dholland }; 110 1.27 christos 111 1.27 christos static struct fileusage *addid(uint32_t, int, const char *); 112 1.27 christos static struct fileusage *lookup(uint32_t, int); 113 1.27 christos static struct fileusage *qremove(uint32_t, int); 114 1.35 dholland static int repquota(struct quotahandle *, int); 115 1.27 christos static void usage(void) __attribute__((__noreturn__)); 116 1.35 dholland static void printquotas(int, struct quotahandle *); 117 1.27 christos static void exportquotas(void); 118 1.37 dholland static int oneof(const char *, char *[], int cnt); 119 1.41 dholland static int isover(struct quotaval *qv, time_t now); 120 1.11 lukem 121 1.11 lukem int 122 1.27 christos main(int argc, char **argv) 123 1.1 cgd { 124 1.1 cgd int gflag = 0, uflag = 0, errs = 0; 125 1.1 cgd long i, argnum, done = 0; 126 1.9 mark int ch; 127 1.26 bouyer struct statvfs *fst; 128 1.26 bouyer int nfst; 129 1.35 dholland struct quotahandle *qh; 130 1.1 cgd 131 1.43 dholland if (!strcmp(getprogname(), "quotadump")) { 132 1.43 dholland xflag = 1; 133 1.43 dholland } 134 1.43 dholland 135 1.44 dholland while ((ch = getopt(argc, argv, "aguhvx")) != -1) { 136 1.1 cgd switch(ch) { 137 1.1 cgd case 'a': 138 1.1 cgd aflag++; 139 1.1 cgd break; 140 1.1 cgd case 'g': 141 1.1 cgd gflag++; 142 1.1 cgd break; 143 1.1 cgd case 'u': 144 1.1 cgd uflag++; 145 1.1 cgd break; 146 1.26 bouyer case 'h': 147 1.26 bouyer hflag++; 148 1.26 bouyer break; 149 1.1 cgd case 'v': 150 1.1 cgd vflag++; 151 1.1 cgd break; 152 1.26 bouyer case 'x': 153 1.26 bouyer xflag++; 154 1.26 bouyer break; 155 1.1 cgd default: 156 1.1 cgd usage(); 157 1.1 cgd } 158 1.1 cgd } 159 1.1 cgd argc -= optind; 160 1.1 cgd argv += optind; 161 1.26 bouyer if (xflag && (argc != 1 || aflag)) 162 1.26 bouyer usage(); 163 1.1 cgd if (argc == 0 && !aflag) 164 1.1 cgd usage(); 165 1.1 cgd if (!gflag && !uflag) { 166 1.1 cgd if (aflag) 167 1.1 cgd gflag++; 168 1.1 cgd uflag++; 169 1.1 cgd } 170 1.26 bouyer 171 1.26 bouyer nfst = getmntinfo(&fst, MNT_WAIT); 172 1.26 bouyer if (nfst == 0) 173 1.27 christos errx(1, "no filesystems mounted!"); 174 1.26 bouyer for (i = 0; i < nfst; i++) { 175 1.26 bouyer if ((fst[i].f_flag & ST_QUOTA) == 0) 176 1.1 cgd continue; 177 1.35 dholland /* check if we want this volume */ 178 1.35 dholland if (!aflag) { 179 1.35 dholland argnum = oneof(fst[i].f_mntonname, argv, argc); 180 1.35 dholland if (argnum < 0) { 181 1.35 dholland argnum = oneof(fst[i].f_mntfromname, 182 1.35 dholland argv, argc); 183 1.35 dholland } 184 1.35 dholland if (argnum < 0) { 185 1.35 dholland continue; 186 1.35 dholland } 187 1.35 dholland done |= 1U << argnum; 188 1.35 dholland } 189 1.35 dholland 190 1.35 dholland qh = quota_open(fst[i].f_mntonname); 191 1.35 dholland if (qh == NULL) { 192 1.35 dholland /* XXX: check this errno */ 193 1.35 dholland if (errno == EOPNOTSUPP || errno == ENXIO) { 194 1.35 dholland continue; 195 1.35 dholland } 196 1.35 dholland warn("%s: quota_open", fst[i].f_mntonname); 197 1.1 cgd continue; 198 1.1 cgd } 199 1.35 dholland 200 1.35 dholland if (gflag) 201 1.35 dholland errs += repquota(qh, QUOTA_IDTYPE_GROUP); 202 1.35 dholland if (uflag) 203 1.35 dholland errs += repquota(qh, QUOTA_IDTYPE_USER); 204 1.35 dholland 205 1.35 dholland quota_close(qh); 206 1.1 cgd } 207 1.26 bouyer if (xflag) 208 1.26 bouyer exportquotas(); 209 1.1 cgd for (i = 0; i < argc; i++) 210 1.27 christos if ((done & (1U << i)) == 0) 211 1.27 christos warnx("%s not mounted", argv[i]); 212 1.27 christos return errs; 213 1.1 cgd } 214 1.1 cgd 215 1.27 christos static void 216 1.27 christos usage(void) 217 1.27 christos { 218 1.27 christos const char *p = getprogname(); 219 1.27 christos fprintf(stderr, "usage: %s [-D] [-v] [-g] [-u] -a\n" 220 1.27 christos "\t%s [-D] [-v] [-g] [-u] filesys ...\n" 221 1.27 christos "\t%s -x [-D] [-g] [-u] filesys\n", p, p, p); 222 1.1 cgd exit(1); 223 1.1 cgd } 224 1.1 cgd 225 1.27 christos static int 226 1.35 dholland repquota(struct quotahandle *qh, int idtype) 227 1.26 bouyer { 228 1.36 dholland struct quotacursor *qc; 229 1.36 dholland struct quotakey qk; 230 1.36 dholland struct quotaval qv; 231 1.35 dholland struct quotaval *qvp; 232 1.35 dholland struct fileusage *fup; 233 1.35 dholland 234 1.36 dholland qc = quota_opencursor(qh); 235 1.36 dholland if (qc == NULL) { 236 1.35 dholland return 1; 237 1.35 dholland } 238 1.26 bouyer 239 1.36 dholland if (idtype == QUOTA_IDTYPE_USER) { 240 1.36 dholland quotacursor_skipidtype(qc, QUOTA_IDTYPE_GROUP); 241 1.36 dholland } 242 1.36 dholland if (idtype == QUOTA_IDTYPE_GROUP) { 243 1.36 dholland quotacursor_skipidtype(qc, QUOTA_IDTYPE_USER); 244 1.36 dholland } 245 1.36 dholland 246 1.36 dholland valid[idtype] = 0; 247 1.36 dholland while (!quotacursor_atend(qc)) { 248 1.36 dholland if (quotacursor_get(qc, &qk, &qv)) { 249 1.36 dholland err(1, "%s: quotacursor_get", quota_getmountpoint(qh)); 250 1.36 dholland } 251 1.36 dholland if (qk.qk_idtype != idtype) { 252 1.36 dholland continue; 253 1.36 dholland } 254 1.36 dholland 255 1.36 dholland valid[idtype] = 1; 256 1.36 dholland if (qk.qk_id == QUOTA_DEFAULTID) { 257 1.36 dholland qvp = defaultqv[idtype]; 258 1.36 dholland } else { 259 1.36 dholland if ((fup = lookup(qk.qk_id, idtype)) == 0) 260 1.36 dholland fup = addid(qk.qk_id, idtype, (char *)0); 261 1.36 dholland qvp = fup->fu_qv; 262 1.36 dholland } 263 1.36 dholland if (qk.qk_objtype == QUOTA_OBJTYPE_BLOCKS) { 264 1.36 dholland qvp[QUOTA_OBJTYPE_BLOCKS] = qv; 265 1.36 dholland } else if (qk.qk_objtype == QUOTA_OBJTYPE_FILES) { 266 1.36 dholland qvp[QUOTA_OBJTYPE_FILES] = qv; 267 1.26 bouyer } 268 1.36 dholland } 269 1.35 dholland 270 1.34 dholland if (xflag == 0 && valid[idtype]) 271 1.35 dholland printquotas(idtype, qh); 272 1.35 dholland 273 1.27 christos return 0; 274 1.26 bouyer } 275 1.26 bouyer 276 1.27 christos static void 277 1.35 dholland printquotas(int idtype, struct quotahandle *qh) 278 1.26 bouyer { 279 1.26 bouyer static int multiple = 0; 280 1.27 christos uint32_t id; 281 1.26 bouyer int i; 282 1.26 bouyer struct fileusage *fup; 283 1.33 dholland struct quotaval *q; 284 1.38 dholland const char *timemsg[REPQUOTA_NUMOBJTYPES]; 285 1.38 dholland char overchar[REPQUOTA_NUMOBJTYPES]; 286 1.27 christos time_t now; 287 1.29 bouyer char b0[2][20], b1[20], b2[20], b3[20]; 288 1.38 dholland int ok, objtype; 289 1.38 dholland int isbytes, width; 290 1.26 bouyer 291 1.34 dholland switch (idtype) { 292 1.34 dholland case QUOTA_IDTYPE_GROUP: 293 1.26 bouyer { 294 1.26 bouyer struct group *gr; 295 1.26 bouyer setgrent(); 296 1.26 bouyer while ((gr = getgrent()) != 0) 297 1.34 dholland (void)addid(gr->gr_gid, idtype, gr->gr_name); 298 1.26 bouyer endgrent(); 299 1.26 bouyer break; 300 1.26 bouyer } 301 1.34 dholland case QUOTA_IDTYPE_USER: 302 1.26 bouyer { 303 1.26 bouyer struct passwd *pw; 304 1.26 bouyer setpwent(); 305 1.26 bouyer while ((pw = getpwent()) != 0) 306 1.34 dholland (void)addid(pw->pw_uid, idtype, pw->pw_name); 307 1.26 bouyer endpwent(); 308 1.26 bouyer break; 309 1.26 bouyer } 310 1.26 bouyer default: 311 1.34 dholland errx(1, "Unknown quota ID type %d", idtype); 312 1.1 cgd } 313 1.26 bouyer 314 1.27 christos time(&now); 315 1.26 bouyer 316 1.26 bouyer if (multiple++) 317 1.26 bouyer printf("\n"); 318 1.26 bouyer if (vflag) 319 1.35 dholland printf("*** Report for %s quotas on %s (%s: %s)\n", 320 1.38 dholland repquota_idtype_names[idtype], quota_getmountpoint(qh), 321 1.35 dholland quota_getmountdevice(qh), quota_getimplname(qh)); 322 1.27 christos printf(" Block limits " 323 1.27 christos "File limits\n"); 324 1.34 dholland printf(idtype == QUOTA_IDTYPE_USER ? "User " : "Group"); 325 1.27 christos printf(" used soft hard grace used" 326 1.39 dholland " soft hard grace\n"); 327 1.34 dholland for (id = 0; id <= highid[idtype]; id++) { 328 1.34 dholland fup = qremove(id, idtype); 329 1.33 dholland q = fup->fu_qv; 330 1.1 cgd if (fup == 0) 331 1.1 cgd continue; 332 1.38 dholland for (i = 0; i < REPQUOTA_NUMOBJTYPES; i++) { 333 1.41 dholland if (isover(&q[i], now)) { 334 1.29 bouyer timemsg[i] = timeprt(b0[i], 8, now, 335 1.33 dholland q[i].qv_expiretime); 336 1.26 bouyer overchar[i] = '+'; 337 1.41 dholland } else { 338 1.35 dholland if (vflag && q[i].qv_grace != QUOTA_NOTIME) { 339 1.35 dholland timemsg[i] = timeprt(b0[i], 8, 0, 340 1.35 dholland q[i].qv_grace); 341 1.35 dholland } else { 342 1.35 dholland timemsg[i] = ""; 343 1.35 dholland } 344 1.26 bouyer overchar[i] = '-'; 345 1.26 bouyer } 346 1.26 bouyer } 347 1.26 bouyer 348 1.38 dholland ok = 1; 349 1.38 dholland for (objtype = 0; objtype < REPQUOTA_NUMOBJTYPES; objtype++) { 350 1.38 dholland if (q[objtype].qv_usage != 0 || 351 1.38 dholland overchar[objtype] != '-') { 352 1.38 dholland ok = 0; 353 1.38 dholland } 354 1.38 dholland } 355 1.38 dholland if (ok && vflag == 0) 356 1.1 cgd continue; 357 1.22 jdolecek if (strlen(fup->fu_name) > 9) 358 1.22 jdolecek printf("%s ", fup->fu_name); 359 1.22 jdolecek else 360 1.22 jdolecek printf("%-10s", fup->fu_name); 361 1.38 dholland for (objtype = 0; objtype < REPQUOTA_NUMOBJTYPES; objtype++) { 362 1.38 dholland printf("%c", overchar[objtype]); 363 1.38 dholland } 364 1.38 dholland for (objtype = 0; objtype < REPQUOTA_NUMOBJTYPES; objtype++) { 365 1.38 dholland isbytes = quota_objtype_isbytes(qh, objtype); 366 1.38 dholland width = isbytes ? 9 : 8; 367 1.38 dholland printf("%*s%*s%*s%7s", 368 1.38 dholland width, 369 1.38 dholland intprt(b1, width+1, q[objtype].qv_usage, 370 1.38 dholland isbytes ? HN_B : 0, hflag), 371 1.38 dholland width, 372 1.38 dholland intprt(b2, width+1, q[objtype].qv_softlimit, 373 1.38 dholland isbytes ? HN_B : 0, hflag), 374 1.38 dholland width, 375 1.38 dholland intprt(b3, width+1, q[objtype].qv_hardlimit, 376 1.38 dholland isbytes ? HN_B : 0, hflag), 377 1.38 dholland timemsg[objtype]); 378 1.38 dholland 379 1.38 dholland if (objtype + 1 < REPQUOTA_NUMOBJTYPES) { 380 1.38 dholland printf(" "); 381 1.38 dholland } else { 382 1.38 dholland printf("\n"); 383 1.38 dholland } 384 1.38 dholland } 385 1.26 bouyer free(fup); 386 1.26 bouyer } 387 1.26 bouyer } 388 1.26 bouyer 389 1.27 christos static void 390 1.40 dholland exportquotaval(const struct quotaval *qv) 391 1.26 bouyer { 392 1.40 dholland if (qv->qv_hardlimit == QUOTA_NOLIMIT) { 393 1.40 dholland printf(" -"); 394 1.40 dholland } else { 395 1.40 dholland printf(" %llu", (unsigned long long)qv->qv_hardlimit); 396 1.40 dholland } 397 1.40 dholland 398 1.40 dholland if (qv->qv_softlimit == QUOTA_NOLIMIT) { 399 1.40 dholland printf(" -"); 400 1.40 dholland } else { 401 1.40 dholland printf(" %llu", (unsigned long long)qv->qv_softlimit); 402 1.40 dholland } 403 1.26 bouyer 404 1.40 dholland printf(" %llu", (unsigned long long)qv->qv_usage); 405 1.26 bouyer 406 1.40 dholland if (qv->qv_expiretime == QUOTA_NOTIME) { 407 1.40 dholland printf(" -"); 408 1.40 dholland } else { 409 1.40 dholland printf(" %lld", (long long)qv->qv_expiretime); 410 1.26 bouyer } 411 1.26 bouyer 412 1.40 dholland if (qv->qv_grace == QUOTA_NOTIME) { 413 1.40 dholland printf(" -"); 414 1.40 dholland } else { 415 1.40 dholland printf(" %lld", (long long)qv->qv_grace); 416 1.40 dholland } 417 1.40 dholland } 418 1.40 dholland 419 1.40 dholland static void 420 1.40 dholland exportquotas(void) 421 1.40 dholland { 422 1.40 dholland int idtype; 423 1.40 dholland id_t id; 424 1.40 dholland struct fileusage *fup; 425 1.40 dholland 426 1.40 dholland /* header */ 427 1.40 dholland printf("@format netbsd-quota-dump v1\n"); 428 1.40 dholland printf("# idtype id objtype hard soft usage expire grace\n"); 429 1.26 bouyer 430 1.38 dholland for (idtype = 0; idtype < REPQUOTA_NUMIDTYPES; idtype++) { 431 1.34 dholland if (valid[idtype] == 0) 432 1.26 bouyer continue; 433 1.40 dholland 434 1.43 dholland printf("%s default block ", repquota_idtype_names[idtype]); 435 1.40 dholland exportquotaval(&defaultqv[idtype][QUOTA_OBJTYPE_BLOCKS]); 436 1.40 dholland printf("\n"); 437 1.40 dholland 438 1.43 dholland printf("%s default file ", repquota_idtype_names[idtype]); 439 1.40 dholland exportquotaval(&defaultqv[idtype][QUOTA_OBJTYPE_FILES]); 440 1.40 dholland printf("\n"); 441 1.26 bouyer 442 1.34 dholland for (id = 0; id <= highid[idtype]; id++) { 443 1.34 dholland fup = qremove(id, idtype); 444 1.26 bouyer if (fup == 0) 445 1.26 bouyer continue; 446 1.40 dholland 447 1.43 dholland printf("%s %u block ", repquota_idtype_names[idtype], 448 1.40 dholland id); 449 1.40 dholland exportquotaval(&fup->fu_qv[QUOTA_OBJTYPE_BLOCKS]); 450 1.40 dholland printf("\n"); 451 1.40 dholland 452 1.43 dholland printf("%s %u file ", repquota_idtype_names[idtype], 453 1.40 dholland id); 454 1.40 dholland exportquotaval(&fup->fu_qv[QUOTA_OBJTYPE_FILES]); 455 1.40 dholland printf("\n"); 456 1.40 dholland 457 1.26 bouyer free(fup); 458 1.26 bouyer } 459 1.1 cgd } 460 1.40 dholland printf("@end\n"); 461 1.1 cgd } 462 1.1 cgd 463 1.1 cgd /* 464 1.1 cgd * Routines to manage the file usage table. 465 1.1 cgd * 466 1.34 dholland * Lookup an id of a specific id type. 467 1.1 cgd */ 468 1.1 cgd struct fileusage * 469 1.34 dholland lookup(uint32_t id, int idtype) 470 1.1 cgd { 471 1.11 lukem struct fileusage *fup; 472 1.1 cgd 473 1.34 dholland for (fup = fuhead[idtype][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 474 1.1 cgd if (fup->fu_id == id) 475 1.27 christos return fup; 476 1.27 christos return NULL; 477 1.1 cgd } 478 1.26 bouyer /* 479 1.34 dholland * Lookup and remove an id of a specific id type. 480 1.26 bouyer */ 481 1.27 christos static struct fileusage * 482 1.34 dholland qremove(uint32_t id, int idtype) 483 1.26 bouyer { 484 1.26 bouyer struct fileusage *fup, **fupp; 485 1.26 bouyer 486 1.34 dholland for (fupp = &fuhead[idtype][id & (FUHASH-1)]; *fupp != 0;) { 487 1.26 bouyer fup = *fupp; 488 1.26 bouyer if (fup->fu_id == id) { 489 1.26 bouyer *fupp = fup->fu_next; 490 1.27 christos return fup; 491 1.26 bouyer } 492 1.26 bouyer fupp = &fup->fu_next; 493 1.26 bouyer } 494 1.27 christos return NULL; 495 1.26 bouyer } 496 1.1 cgd 497 1.1 cgd /* 498 1.1 cgd * Add a new file usage id if it does not already exist. 499 1.1 cgd */ 500 1.27 christos static struct fileusage * 501 1.34 dholland addid(uint32_t id, int idtype, const char *name) 502 1.1 cgd { 503 1.1 cgd struct fileusage *fup, **fhp; 504 1.26 bouyer struct group *gr = NULL; 505 1.26 bouyer struct passwd *pw = NULL; 506 1.27 christos size_t len; 507 1.1 cgd 508 1.34 dholland if ((fup = lookup(id, idtype)) != NULL) { 509 1.27 christos return fup; 510 1.26 bouyer } 511 1.26 bouyer if (name == NULL) { 512 1.34 dholland switch(idtype) { 513 1.34 dholland case QUOTA_IDTYPE_GROUP: 514 1.26 bouyer gr = getgrgid(id); 515 1.26 bouyer 516 1.26 bouyer if (gr != NULL) 517 1.26 bouyer name = gr->gr_name; 518 1.26 bouyer break; 519 1.34 dholland case QUOTA_IDTYPE_USER: 520 1.26 bouyer pw = getpwuid(id); 521 1.26 bouyer if (pw) 522 1.26 bouyer name = pw->pw_name; 523 1.26 bouyer break; 524 1.26 bouyer default: 525 1.45 christos errx(1, "Unknown quota ID type %d", idtype); 526 1.26 bouyer } 527 1.26 bouyer } 528 1.26 bouyer 529 1.1 cgd if (name) 530 1.1 cgd len = strlen(name); 531 1.1 cgd else 532 1.1 cgd len = 10; 533 1.27 christos if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) 534 1.27 christos err(1, "out of memory for fileusage structures"); 535 1.34 dholland fhp = &fuhead[idtype][id & (FUHASH - 1)]; 536 1.1 cgd fup->fu_next = *fhp; 537 1.1 cgd *fhp = fup; 538 1.1 cgd fup->fu_id = id; 539 1.34 dholland if (id > highid[idtype]) 540 1.34 dholland highid[idtype] = id; 541 1.1 cgd if (name) { 542 1.12 lukem memmove(fup->fu_name, name, len + 1); 543 1.1 cgd } else { 544 1.28 christos snprintf(fup->fu_name, len + 1, "%u", id); 545 1.1 cgd } 546 1.36 dholland /* 547 1.36 dholland * XXX nothing guarantees the default limits have been loaded yet 548 1.36 dholland */ 549 1.38 dholland fup->fu_qv[QUOTA_OBJTYPE_BLOCKS] = defaultqv[idtype][QUOTA_OBJTYPE_BLOCKS]; 550 1.38 dholland fup->fu_qv[QUOTA_OBJTYPE_FILES] = defaultqv[idtype][QUOTA_OBJTYPE_FILES]; 551 1.27 christos return fup; 552 1.1 cgd } 553 1.37 dholland 554 1.37 dholland /* 555 1.37 dholland * Check to see if target appears in list of size cnt. 556 1.37 dholland */ 557 1.37 dholland static int 558 1.37 dholland oneof(const char *target, char *list[], int cnt) 559 1.37 dholland { 560 1.37 dholland int i; 561 1.37 dholland 562 1.37 dholland for (i = 0; i < cnt; i++) 563 1.37 dholland if (strcmp(target, list[i]) == 0) 564 1.37 dholland return i; 565 1.37 dholland return -1; 566 1.37 dholland } 567 1.41 dholland 568 1.41 dholland static int 569 1.41 dholland isover(struct quotaval *qv, time_t now) 570 1.41 dholland { 571 1.41 dholland return (qv->qv_usage >= qv->qv_hardlimit || 572 1.41 dholland qv->qv_usage >= qv->qv_softlimit); 573 1.41 dholland } 574