1 1.50 dholland /* $NetBSD: quota.c,v 1.50 2014/07/13 01:46:04 dholland Exp $ */ 2 1.12 tls 3 1.1 cgd /* 4 1.5 mycroft * Copyright (c) 1980, 1990, 1993 5 1.5 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.26 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.16 lukem #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.32 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1990, 1993\ 38 1.32 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.15 mrg #if 0 43 1.15 mrg static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95"; 44 1.15 mrg #else 45 1.50 dholland __RCSID("$NetBSD: quota.c,v 1.50 2014/07/13 01:46:04 dholland Exp $"); 46 1.15 mrg #endif 47 1.1 cgd #endif /* not lint */ 48 1.1 cgd 49 1.1 cgd /* 50 1.1 cgd * Disk quota reporting program. 51 1.1 cgd */ 52 1.1 cgd #include <sys/param.h> 53 1.6 deraadt #include <sys/types.h> 54 1.1 cgd #include <sys/file.h> 55 1.1 cgd #include <sys/stat.h> 56 1.6 deraadt #include <sys/mount.h> 57 1.6 deraadt #include <sys/socket.h> 58 1.15 mrg 59 1.42 dholland #include <assert.h> 60 1.15 mrg #include <ctype.h> 61 1.16 lukem #include <err.h> 62 1.15 mrg #include <errno.h> 63 1.15 mrg #include <fstab.h> 64 1.15 mrg #include <grp.h> 65 1.15 mrg #include <netdb.h> 66 1.15 mrg #include <pwd.h> 67 1.1 cgd #include <stdio.h> 68 1.7 cgd #include <stdlib.h> 69 1.16 lukem #include <string.h> 70 1.18 kleink #include <time.h> 71 1.16 lukem #include <unistd.h> 72 1.1 cgd 73 1.44 dholland #include <quota.h> 74 1.6 deraadt 75 1.36 christos #include "printquota.h" 76 1.1 cgd 77 1.1 cgd struct quotause { 78 1.1 cgd struct quotause *next; 79 1.37 bouyer uid_t id; 80 1.43 dholland struct quotaval *qvs; 81 1.43 dholland unsigned numqvs; 82 1.1 cgd char fsname[MAXPATHLEN + 1]; 83 1.44 dholland struct quotahandle *qh; 84 1.6 deraadt }; 85 1.1 cgd 86 1.42 dholland static int anyusage(struct quotaval *, unsigned); 87 1.42 dholland static int anyover(struct quotaval *, unsigned, time_t); 88 1.42 dholland static const char *getovermsg(struct quotaval *, const char *, time_t); 89 1.39 dholland static struct quotause *getprivs(id_t, int); 90 1.44 dholland static void heading(int, const char *, id_t, const char *, const char *); 91 1.42 dholland static int isover(struct quotaval *qv, time_t now); 92 1.44 dholland static void printqv(struct quotaval *, int, time_t); 93 1.35 christos static void showgid(gid_t); 94 1.35 christos static void showgrpname(const char *); 95 1.44 dholland static void showonequota(int, const char *, id_t, const char *, 96 1.44 dholland struct quotause *); 97 1.44 dholland static void showquotas(int, const char *, id_t, const char *); 98 1.35 christos static void showuid(uid_t); 99 1.35 christos static void showusrname(const char *); 100 1.42 dholland static int unlimited(struct quotaval *qvs, unsigned numqvs); 101 1.40 dholland static void usage(void) __dead; 102 1.35 christos 103 1.35 christos static int qflag = 0; 104 1.35 christos static int vflag = 0; 105 1.35 christos static int hflag = 0; 106 1.35 christos static int dflag = 0; 107 1.35 christos static uid_t myuid; 108 1.41 dholland static int needheading; 109 1.1 cgd 110 1.16 lukem int 111 1.35 christos main(int argc, char *argv[]) 112 1.1 cgd { 113 1.3 jtc int ngroups; 114 1.8 mycroft gid_t mygid, gidset[NGROUPS]; 115 1.1 cgd int i, gflag = 0, uflag = 0; 116 1.11 mark int ch; 117 1.1 cgd 118 1.19 mrg myuid = getuid(); 119 1.49 dholland while ((ch = getopt(argc, argv, "dhugvq")) != -1) { 120 1.1 cgd switch(ch) { 121 1.1 cgd case 'g': 122 1.1 cgd gflag++; 123 1.1 cgd break; 124 1.1 cgd case 'u': 125 1.1 cgd uflag++; 126 1.1 cgd break; 127 1.1 cgd case 'v': 128 1.1 cgd vflag++; 129 1.1 cgd break; 130 1.1 cgd case 'q': 131 1.1 cgd qflag++; 132 1.1 cgd break; 133 1.34 bouyer case 'h': 134 1.34 bouyer hflag++; 135 1.34 bouyer break; 136 1.34 bouyer case 'd': 137 1.34 bouyer dflag++; 138 1.34 bouyer break; 139 1.1 cgd default: 140 1.1 cgd usage(); 141 1.1 cgd } 142 1.1 cgd } 143 1.1 cgd argc -= optind; 144 1.1 cgd argv += optind; 145 1.1 cgd if (!uflag && !gflag) 146 1.1 cgd uflag++; 147 1.34 bouyer if (dflag) { 148 1.34 bouyer #if 0 149 1.35 christos if (myuid != 0) 150 1.35 christos errx(1, "-d: permission denied"); 151 1.34 bouyer #endif 152 1.34 bouyer if (uflag) 153 1.44 dholland showquotas(QUOTA_IDTYPE_USER, "user", 0, ""); 154 1.34 bouyer if (gflag) 155 1.44 dholland showquotas(QUOTA_IDTYPE_GROUP, "group", 0, ""); 156 1.35 christos return 0; 157 1.34 bouyer } 158 1.1 cgd if (argc == 0) { 159 1.1 cgd if (uflag) 160 1.19 mrg showuid(myuid); 161 1.1 cgd if (gflag) { 162 1.34 bouyer if (dflag) 163 1.34 bouyer showgid(0); 164 1.34 bouyer else { 165 1.34 bouyer mygid = getgid(); 166 1.34 bouyer ngroups = getgroups(NGROUPS, gidset); 167 1.34 bouyer if (ngroups < 0) 168 1.34 bouyer err(1, "getgroups"); 169 1.34 bouyer showgid(mygid); 170 1.34 bouyer for (i = 0; i < ngroups; i++) 171 1.34 bouyer if (gidset[i] != mygid) 172 1.34 bouyer showgid(gidset[i]); 173 1.34 bouyer } 174 1.1 cgd } 175 1.35 christos return 0; 176 1.1 cgd } 177 1.1 cgd if (uflag && gflag) 178 1.1 cgd usage(); 179 1.1 cgd if (uflag) { 180 1.1 cgd for (; argc > 0; argc--, argv++) { 181 1.1 cgd if (alldigits(*argv)) 182 1.35 christos showuid((uid_t)atoi(*argv)); 183 1.1 cgd else 184 1.1 cgd showusrname(*argv); 185 1.1 cgd } 186 1.35 christos return 0; 187 1.1 cgd } 188 1.1 cgd if (gflag) { 189 1.1 cgd for (; argc > 0; argc--, argv++) { 190 1.1 cgd if (alldigits(*argv)) 191 1.35 christos showgid((gid_t)atoi(*argv)); 192 1.1 cgd else 193 1.1 cgd showgrpname(*argv); 194 1.1 cgd } 195 1.35 christos return 0; 196 1.1 cgd } 197 1.16 lukem /* NOTREACHED */ 198 1.35 christos return 0; 199 1.1 cgd } 200 1.1 cgd 201 1.35 christos static void 202 1.35 christos usage(void) 203 1.1 cgd { 204 1.35 christos const char *p = getprogname(); 205 1.35 christos fprintf(stderr, "Usage: %s [-Dhguqv]\n" 206 1.35 christos "\t%s [-Dhqv] -u username ...\n" 207 1.35 christos "\t%s [-Dhqv] -g groupname ...\n" 208 1.35 christos "\t%s -d [-Dhguqv]\n", p, p, p, p); 209 1.1 cgd exit(1); 210 1.1 cgd } 211 1.1 cgd 212 1.1 cgd /* 213 1.1 cgd * Print out quotas for a specified user identifier. 214 1.1 cgd */ 215 1.35 christos static void 216 1.35 christos showuid(uid_t uid) 217 1.1 cgd { 218 1.1 cgd struct passwd *pwd = getpwuid(uid); 219 1.20 mycroft const char *name; 220 1.1 cgd 221 1.1 cgd if (pwd == NULL) 222 1.1 cgd name = "(no account)"; 223 1.1 cgd else 224 1.1 cgd name = pwd->pw_name; 225 1.1 cgd if (uid != myuid && myuid != 0) { 226 1.35 christos warnx("%s (uid %d): permission denied", name, uid); 227 1.1 cgd return; 228 1.1 cgd } 229 1.44 dholland showquotas(QUOTA_IDTYPE_USER, "user", uid, name); 230 1.1 cgd } 231 1.1 cgd 232 1.1 cgd /* 233 1.24 wiz * Print out quotas for a specified user name. 234 1.1 cgd */ 235 1.35 christos static void 236 1.35 christos showusrname(const char *name) 237 1.1 cgd { 238 1.1 cgd struct passwd *pwd = getpwnam(name); 239 1.1 cgd 240 1.1 cgd if (pwd == NULL) { 241 1.16 lukem warnx("%s: unknown user", name); 242 1.1 cgd return; 243 1.1 cgd } 244 1.1 cgd if (pwd->pw_uid != myuid && myuid != 0) { 245 1.16 lukem warnx("%s (uid %d): permission denied", name, pwd->pw_uid); 246 1.1 cgd return; 247 1.1 cgd } 248 1.44 dholland showquotas(QUOTA_IDTYPE_USER, "user", pwd->pw_uid, name); 249 1.1 cgd } 250 1.1 cgd 251 1.1 cgd /* 252 1.1 cgd * Print out quotas for a specified group identifier. 253 1.1 cgd */ 254 1.35 christos static void 255 1.35 christos showgid(gid_t gid) 256 1.1 cgd { 257 1.1 cgd struct group *grp = getgrgid(gid); 258 1.3 jtc int ngroups; 259 1.8 mycroft gid_t mygid, gidset[NGROUPS]; 260 1.16 lukem int i; 261 1.20 mycroft const char *name; 262 1.1 cgd 263 1.1 cgd if (grp == NULL) 264 1.1 cgd name = "(no entry)"; 265 1.1 cgd else 266 1.1 cgd name = grp->gr_name; 267 1.8 mycroft mygid = getgid(); 268 1.1 cgd ngroups = getgroups(NGROUPS, gidset); 269 1.1 cgd if (ngroups < 0) { 270 1.16 lukem warn("getgroups"); 271 1.1 cgd return; 272 1.1 cgd } 273 1.8 mycroft if (gid != mygid) { 274 1.8 mycroft for (i = 0; i < ngroups; i++) 275 1.8 mycroft if (gid == gidset[i]) 276 1.8 mycroft break; 277 1.19 mrg if (i >= ngroups && myuid != 0) { 278 1.16 lukem warnx("%s (gid %d): permission denied", name, gid); 279 1.8 mycroft return; 280 1.8 mycroft } 281 1.1 cgd } 282 1.44 dholland showquotas(QUOTA_IDTYPE_GROUP, "group", gid, name); 283 1.1 cgd } 284 1.1 cgd 285 1.1 cgd /* 286 1.24 wiz * Print out quotas for a specified group name. 287 1.1 cgd */ 288 1.35 christos static void 289 1.35 christos showgrpname(const char *name) 290 1.1 cgd { 291 1.1 cgd struct group *grp = getgrnam(name); 292 1.3 jtc int ngroups; 293 1.8 mycroft gid_t mygid, gidset[NGROUPS]; 294 1.16 lukem int i; 295 1.1 cgd 296 1.1 cgd if (grp == NULL) { 297 1.16 lukem warnx("%s: unknown group", name); 298 1.1 cgd return; 299 1.1 cgd } 300 1.8 mycroft mygid = getgid(); 301 1.1 cgd ngroups = getgroups(NGROUPS, gidset); 302 1.1 cgd if (ngroups < 0) { 303 1.16 lukem warn("getgroups"); 304 1.1 cgd return; 305 1.1 cgd } 306 1.8 mycroft if (grp->gr_gid != mygid) { 307 1.8 mycroft for (i = 0; i < ngroups; i++) 308 1.8 mycroft if (grp->gr_gid == gidset[i]) 309 1.8 mycroft break; 310 1.19 mrg if (i >= ngroups && myuid != 0) { 311 1.16 lukem warnx("%s (gid %d): permission denied", 312 1.8 mycroft name, grp->gr_gid); 313 1.8 mycroft return; 314 1.8 mycroft } 315 1.1 cgd } 316 1.44 dholland showquotas(QUOTA_IDTYPE_GROUP, "group", grp->gr_gid, name); 317 1.1 cgd } 318 1.1 cgd 319 1.35 christos static void 320 1.44 dholland showquotas(int idtype, const char *idtypename, id_t id, const char *idname) 321 1.1 cgd { 322 1.16 lukem struct quotause *qup; 323 1.6 deraadt struct quotause *quplist; 324 1.41 dholland 325 1.41 dholland needheading = 1; 326 1.41 dholland 327 1.44 dholland quplist = getprivs(id, idtype); 328 1.41 dholland for (qup = quplist; qup; qup = qup->next) { 329 1.44 dholland showonequota(idtype, idtypename, id, idname, qup); 330 1.41 dholland } 331 1.41 dholland if (!qflag) { 332 1.41 dholland /* In case nothing printed, issue a header saying "none" */ 333 1.44 dholland heading(idtype, idtypename, id, idname, "none"); 334 1.41 dholland } 335 1.41 dholland } 336 1.41 dholland 337 1.41 dholland static void 338 1.44 dholland showonequota(int idtype, const char *idtypename, id_t id, const char *idname, 339 1.44 dholland struct quotause *qup) 340 1.41 dholland { 341 1.1 cgd static time_t now; 342 1.42 dholland struct quotaval *qvs; 343 1.42 dholland unsigned numqvs, i; 344 1.42 dholland const char *msg; 345 1.42 dholland 346 1.43 dholland qvs = qup->qvs; 347 1.43 dholland numqvs = qup->numqvs; 348 1.1 cgd 349 1.41 dholland if (now == 0) { 350 1.1 cgd time(&now); 351 1.41 dholland } 352 1.41 dholland 353 1.42 dholland if (!vflag && unlimited(qvs, numqvs)) { 354 1.41 dholland return; 355 1.41 dholland } 356 1.42 dholland 357 1.41 dholland if (qflag) { 358 1.42 dholland for (i=0; i<numqvs; i++) { 359 1.44 dholland msg = getovermsg(&qvs[i], 360 1.44 dholland quota_idtype_getname(qup->qh, i), 361 1.42 dholland now); 362 1.42 dholland if (msg != NULL) { 363 1.44 dholland heading(idtype, idtypename, id, idname, ""); 364 1.42 dholland printf("\t%s %s\n", msg, qup->fsname); 365 1.42 dholland } 366 1.21 ross } 367 1.41 dholland return; 368 1.41 dholland } 369 1.42 dholland 370 1.42 dholland /* 371 1.44 dholland * XXX this behavior appears to be demanded by the ATF tests, 372 1.44 dholland * although it seems to be at variance with the preexisting 373 1.44 dholland * logic in quota.c. 374 1.44 dholland */ 375 1.44 dholland if (unlimited(qvs, numqvs) && !anyusage(qvs, numqvs)) { 376 1.44 dholland return; 377 1.44 dholland } 378 1.44 dholland 379 1.44 dholland /* 380 1.42 dholland * XXX: anyover can in fact be true if anyusage is not true, 381 1.42 dholland * if there's a quota of zero set on some volume. This is 382 1.42 dholland * because the check we do checks if adding one more thing 383 1.44 dholland * will go over. That is reasonable, I suppose, but arguably 384 1.42 dholland * the resulting behavior with usage 0 is a bug. (Also, what 385 1.42 dholland * reason do we have to believe that the reported grace expire 386 1.42 dholland * time is valid if we aren't in fact over yet?) 387 1.42 dholland */ 388 1.42 dholland 389 1.42 dholland if (vflag || dflag || anyover(qvs, numqvs, now) || 390 1.42 dholland anyusage(qvs, numqvs)) { 391 1.44 dholland heading(idtype, idtypename, id, idname, ""); 392 1.41 dholland if (strlen(qup->fsname) > 4) { 393 1.41 dholland printf("%s\n", qup->fsname); 394 1.42 dholland printf("%12s", ""); 395 1.42 dholland } else { 396 1.42 dholland printf("%12s", qup->fsname); 397 1.42 dholland } 398 1.42 dholland 399 1.42 dholland for (i=0; i<numqvs; i++) { 400 1.44 dholland printqv(&qvs[i], 401 1.44 dholland quota_objtype_isbytes(qup->qh, i), now); 402 1.42 dholland } 403 1.42 dholland printf("\n"); 404 1.1 cgd } 405 1.1 cgd } 406 1.1 cgd 407 1.35 christos static void 408 1.44 dholland heading(int idtype, const char *idtypename, id_t id, const char *idname, 409 1.44 dholland const char *tag) 410 1.1 cgd { 411 1.41 dholland if (needheading == 0) 412 1.41 dholland return; 413 1.41 dholland needheading = 0; 414 1.41 dholland 415 1.34 bouyer if (dflag) 416 1.44 dholland printf("Default %s disk quotas: %s\n", idtypename, tag); 417 1.34 bouyer else 418 1.35 christos printf("Disk quotas for %s %s (%cid %u): %s\n", 419 1.44 dholland idtypename, idname, idtypename[0], id, tag); 420 1.1 cgd 421 1.1 cgd if (!qflag && tag[0] == '\0') { 422 1.22 bouyer printf("%12s%9s %8s%9s%8s%8s %7s%8s%8s\n" 423 1.22 bouyer , "Filesystem" 424 1.22 bouyer , "blocks" 425 1.22 bouyer , "quota" 426 1.22 bouyer , "limit" 427 1.22 bouyer , "grace" 428 1.22 bouyer , "files" 429 1.22 bouyer , "quota" 430 1.22 bouyer , "limit" 431 1.22 bouyer , "grace" 432 1.1 cgd ); 433 1.1 cgd } 434 1.1 cgd } 435 1.1 cgd 436 1.42 dholland static void 437 1.44 dholland printqv(struct quotaval *qv, int isbytes, time_t now) 438 1.42 dholland { 439 1.42 dholland char buf[20]; 440 1.42 dholland const char *str; 441 1.42 dholland int intprtflags, over, width; 442 1.42 dholland 443 1.42 dholland /* 444 1.42 dholland * The assorted finagling of width is to match the previous 445 1.42 dholland * open-coded formatting for exactly two quota object types, 446 1.42 dholland * which was chosen to make the default report fit in 80 447 1.42 dholland * columns. 448 1.42 dholland */ 449 1.42 dholland 450 1.42 dholland width = isbytes ? 9 : 8; 451 1.42 dholland intprtflags = isbytes ? HN_B : 0; 452 1.42 dholland over = isover(qv, now); 453 1.42 dholland 454 1.42 dholland str = intprt(buf, width, qv->qv_usage, intprtflags, hflag); 455 1.42 dholland printf("%*s", width, str); 456 1.42 dholland 457 1.42 dholland printf("%c", over ? '*' : ' '); 458 1.42 dholland 459 1.42 dholland str = intprt(buf, width, qv->qv_softlimit, intprtflags, hflag); 460 1.42 dholland printf("%*s", width-1, str); 461 1.42 dholland 462 1.42 dholland str = intprt(buf, width, qv->qv_hardlimit, intprtflags, hflag); 463 1.42 dholland printf("%*s", width, str); 464 1.42 dholland 465 1.42 dholland if (over) { 466 1.42 dholland str = timeprt(buf, 9, now, qv->qv_expiretime); 467 1.44 dholland } else if (vflag && qv->qv_grace != QUOTA_NOTIME) { 468 1.42 dholland str = timeprt(buf, 9, 0, qv->qv_grace); 469 1.42 dholland } else { 470 1.42 dholland str = ""; 471 1.42 dholland } 472 1.42 dholland printf("%8s", str); 473 1.42 dholland } 474 1.42 dholland 475 1.1 cgd /* 476 1.1 cgd * Collect the requested quota information. 477 1.1 cgd */ 478 1.35 christos static struct quotause * 479 1.44 dholland getprivs(id_t id, int idtype) 480 1.1 cgd { 481 1.16 lukem struct quotause *qup, *quptail; 482 1.1 cgd struct quotause *quphead; 483 1.29 christos struct statvfs *fst; 484 1.44 dholland struct quotakey qk; 485 1.6 deraadt int nfst, i; 486 1.44 dholland unsigned j; 487 1.6 deraadt 488 1.16 lukem qup = quphead = quptail = NULL; 489 1.1 cgd 490 1.6 deraadt nfst = getmntinfo(&fst, MNT_WAIT); 491 1.16 lukem if (nfst == 0) 492 1.16 lukem errx(2, "no filesystems mounted!"); 493 1.19 mrg for (i = 0; i < nfst; i++) { 494 1.6 deraadt if (qup == NULL) { 495 1.35 christos if ((qup = malloc(sizeof *qup)) == NULL) 496 1.43 dholland err(1, "Out of memory"); 497 1.1 cgd } 498 1.44 dholland qup->qh = quota_open(fst[i].f_mntonname); 499 1.44 dholland if (qup->qh == NULL) { 500 1.44 dholland if (errno == EOPNOTSUPP || errno == ENXIO) { 501 1.44 dholland continue; 502 1.44 dholland } 503 1.44 dholland err(1, "%s: quota_open", fst[i].f_mntonname); 504 1.44 dholland } 505 1.44 dholland qup->numqvs = quota_getnumidtypes(qup->qh); 506 1.44 dholland qup->qvs = malloc(qup->numqvs * sizeof(qup->qvs[0])); 507 1.44 dholland if (qup->qvs == NULL) { 508 1.44 dholland err(1, "Out of memory"); 509 1.44 dholland } 510 1.44 dholland qk.qk_idtype = idtype; 511 1.44 dholland if (dflag) { 512 1.44 dholland qk.qk_id = QUOTA_DEFAULTID; 513 1.44 dholland } else { 514 1.44 dholland qk.qk_id = id; 515 1.44 dholland } 516 1.44 dholland for (j=0; j<qup->numqvs; j++) { 517 1.44 dholland qk.qk_objtype = j; 518 1.44 dholland if (quota_get(qup->qh, &qk, &qup->qvs[j]) < 0) { 519 1.45 dholland if (errno != ENOENT && errno != ENODEV) { 520 1.44 dholland warn("%s: quota_get (objtype %u)", 521 1.44 dholland fst[i].f_mntonname, j); 522 1.44 dholland } 523 1.44 dholland quotaval_clear(&qup->qvs[j]); 524 1.44 dholland } 525 1.44 dholland } 526 1.44 dholland (void)strlcpy(qup->fsname, fst[i].f_mntonname, 527 1.44 dholland sizeof(qup->fsname)); 528 1.1 cgd if (quphead == NULL) 529 1.1 cgd quphead = qup; 530 1.1 cgd else 531 1.1 cgd quptail->next = qup; 532 1.1 cgd quptail = qup; 533 1.6 deraadt quptail->next = 0; 534 1.6 deraadt qup = NULL; 535 1.1 cgd } 536 1.35 christos free(qup); 537 1.35 christos return quphead; 538 1.1 cgd } 539 1.42 dholland 540 1.42 dholland static int 541 1.42 dholland unlimited(struct quotaval *qvs, unsigned numqvs) 542 1.42 dholland { 543 1.42 dholland unsigned i; 544 1.42 dholland 545 1.42 dholland for (i=0; i<numqvs; i++) { 546 1.44 dholland if (qvs[i].qv_softlimit != QUOTA_NOLIMIT || 547 1.44 dholland qvs[i].qv_hardlimit != QUOTA_NOLIMIT) { 548 1.42 dholland return 0; 549 1.42 dholland } 550 1.42 dholland } 551 1.42 dholland return 1; 552 1.42 dholland } 553 1.42 dholland 554 1.42 dholland static int 555 1.42 dholland anyusage(struct quotaval *qvs, unsigned numqvs) 556 1.42 dholland { 557 1.42 dholland unsigned i; 558 1.42 dholland 559 1.42 dholland for (i=0; i<numqvs; i++) { 560 1.42 dholland if (qvs[i].qv_usage > 0) { 561 1.42 dholland return 1; 562 1.42 dholland } 563 1.42 dholland } 564 1.42 dholland return 0; 565 1.42 dholland } 566 1.42 dholland 567 1.42 dholland static int 568 1.42 dholland anyover(struct quotaval *qvs, unsigned numqvs, time_t now) 569 1.42 dholland { 570 1.42 dholland unsigned i; 571 1.42 dholland 572 1.42 dholland for (i=0; i<numqvs; i++) { 573 1.42 dholland if (isover(&qvs[i], now)) { 574 1.42 dholland return 1; 575 1.42 dholland } 576 1.42 dholland } 577 1.42 dholland return 0; 578 1.42 dholland } 579 1.42 dholland 580 1.42 dholland static int 581 1.42 dholland isover(struct quotaval *qv, time_t now) 582 1.42 dholland { 583 1.47 dholland return (qv->qv_usage >= qv->qv_hardlimit || 584 1.47 dholland qv->qv_usage >= qv->qv_softlimit); 585 1.42 dholland } 586 1.42 dholland 587 1.42 dholland static const char * 588 1.42 dholland getovermsg(struct quotaval *qv, const char *what, time_t now) 589 1.42 dholland { 590 1.42 dholland static char buf[64]; 591 1.42 dholland 592 1.47 dholland if (qv->qv_usage >= qv->qv_hardlimit) { 593 1.42 dholland snprintf(buf, sizeof(buf), "%c%s limit reached on", 594 1.42 dholland toupper((unsigned char)what[0]), what+1); 595 1.47 dholland return buf; 596 1.47 dholland } 597 1.47 dholland 598 1.47 dholland if (qv->qv_usage < qv->qv_softlimit) { 599 1.47 dholland /* Ok */ 600 1.47 dholland return NULL; 601 1.47 dholland } 602 1.47 dholland 603 1.47 dholland if (now > qv->qv_expiretime) { 604 1.42 dholland snprintf(buf, sizeof(buf), "Over %s quota on", what); 605 1.47 dholland return buf; 606 1.42 dholland } 607 1.47 dholland 608 1.47 dholland snprintf(buf, sizeof(buf), "In %s grace period on", what); 609 1.42 dholland return buf; 610 1.42 dholland } 611