1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)quota_sys.c 7.1.1 (2.11BSD GTE) 12/31/93 7: */ 8: 9: /* 10: * MELBOURNE QUOTAS 11: * 12: * System calls. 13: */ 14: #include "param.h" 15: #include "systm.h" 16: #include "user.h" 17: #include "proc.h" 18: #include "inode.h" 19: #include "quota.h" 20: #include "fs.h" 21: #include "mount.h" 22: #include "uio.h" 23: 24: /* 25: * The sys call that tells the system about a quota file. 26: */ 27: setquota() 28: { 29: register struct a { 30: char *fblk; 31: char *fname; 32: } *uap = (struct a *)u.u_ap; 33: register struct mount *mp; 34: dev_t dev; 35: 36: #ifdef QUOTA 37: u.u_error = getmdev(&dev, uap->fblk); 38: if (u.u_error) 39: return; 40: for (mp = mount; mp < &mount[NMOUNT]; mp++) 41: #ifdef pdp11 42: if (mp->m_inodp && mp->m_dev == dev) { 43: #else 44: if (mp->m_bufp && mp->m_dev == dev) { 45: #endif 46: #ifdef pdp11 47: QUOTAMAP(); 48: #endif 49: if (uap->fname == NULL) 50: closedq(mp); 51: else 52: opendq(mp, (caddr_t)uap->fname); 53: #ifdef pdp11 54: QUOTAUNMAP(); 55: #endif 56: return; 57: } 58: #else 59: u.u_error = EINVAL; 60: #endif 61: } 62: 63: /* 64: * Sys call to allow users to find out 65: * their current position wrt quota's 66: * and to allow super users to alter it. 67: */ 68: qquota() 69: { 70: register struct a { 71: int cmd; 72: int uid; 73: int arg; 74: caddr_t addr; 75: } *uap = (struct a *)u.u_ap; 76: register struct quota *q; 77: 78: #ifdef QUOTA 79: if (uap->uid < 0) 80: uap->uid = u.u_ruid; 81: #ifdef pdp11 82: QUOTAMAP(); 83: #endif 84: if (uap->uid != u.u_ruid && uap->uid != u.u_quota->q_uid && !suser()) 85: #ifdef pdp11 86: { 87: QUOTAUNMAP(); 88: return; 89: } 90: #else 91: return; 92: #endif 93: if (uap->cmd != Q_SYNC && uap->cmd != Q_SETUID) { 94: q = getquota((uid_t)uap->uid, uap->cmd == Q_DOWARN, 0); 95: if (q == NOQUOTA) { 96: #ifdef pdp11 97: QUOTAUNMAP(); 98: #endif 99: u.u_error = ESRCH; 100: return; 101: } 102: if (u.u_error) 103: goto bad; 104: } 105: switch (uap->cmd) { 106: 107: case Q_SETDLIM: 108: u.u_error = setdlim(q, (dev_t)uap->arg, uap->addr); 109: break; 110: 111: case Q_GETDLIM: 112: u.u_error = getdlim(q, (dev_t)uap->arg, uap->addr); 113: break; 114: 115: case Q_SETDUSE: 116: u.u_error = setduse(q, (dev_t)uap->arg, uap->addr); 117: break; 118: 119: case Q_SETWARN: 120: u.u_error = setwarn(q, (dev_t)uap->arg, uap->addr); 121: break; 122: 123: case Q_DOWARN: 124: u.u_error = dowarn(q, (dev_t)uap->arg); 125: break; 126: 127: case Q_SYNC: 128: u.u_error = qsync((dev_t)uap->arg); 129: #ifdef pdp11 130: QUOTAUNMAP(); 131: #endif 132: return; 133: 134: case Q_SETUID: 135: u.u_error = qsetuid((uid_t)uap->uid, uap->arg); 136: #ifdef pdp11 137: QUOTAUNMAP(); 138: #endif 139: return; 140: 141: default: 142: u.u_error = EINVAL; 143: break; 144: } 145: bad: 146: delquota(q); 147: #ifdef pdp11 148: QUOTAUNMAP(); 149: #endif 150: #else 151: u.u_error = EINVAL; 152: #endif 153: } 154: 155: #ifdef QUOTA 156: /* 157: * Q_SETDLIM - assign an entire dqblk structure. 158: */ 159: setdlim(q, dev, addr) 160: register struct quota *q; 161: dev_t dev; 162: caddr_t addr; 163: { 164: register struct inode *ip; 165: register struct dquot *dq, *odq; 166: struct dqblk newlim; 167: int index, error = 0; 168: 169: if (!suser()) 170: return (u.u_error); /* XXX */ 171: index = getfsx(dev); 172: if (index < 0 || index >= NMOUNT) 173: return (ENODEV); 174: dq = dqp(q, dev); 175: if (dq == NODQUOT) { 176: dq = dqalloc(q->q_uid, dev); 177: if (dq == NODQUOT) 178: return (error); 179: dq->dq_cnt++; 180: dq->dq_own = q; 181: q->q_dq[index] = dq; 182: odq = NODQUOT; 183: } else 184: odq = dq; 185: 186: if (dq->dq_uid != q->q_uid) 187: panic("setdlim"); 188: while (dq->dq_flags & DQ_LOCK) { 189: dq->dq_flags |= DQ_WANT; 190: #ifdef pdp11 191: QUOTAUNMAP(); 192: sleep((caddr_t)dq, PINOD+1); 193: QUOTAMAP(); 194: #else 195: sleep((caddr_t)dq, PINOD+1); 196: #endif 197: } 198: error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)); 199: if (error) { 200: if (dq != odq) { 201: q->q_dq[index] = odq; 202: dq->dq_cnt--; 203: } 204: dqrele(dq); 205: return (error); 206: } 207: #ifdef pdp11 208: /* we speak bytes not blocks, so convert the structure here */ 209: newlim.dqb_bsoftlimit = (long)dbtob(newlim.dqb_bsoftlimit); 210: newlim.dqb_bhardlimit = (long)dbtob(newlim.dqb_bhardlimit); 211: newlim.dqb_curblocks = (long)dbtob(newlim.dqb_curblocks); 212: #endif 213: dq->dq_dqb = newlim; 214: dq->dq_flags |= DQ_MOD; 215: dqrele(dq); 216: if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0) { 217: q->q_dq[index] = NODQUOT; 218: dq->dq_own = NOQUOTA; 219: dqrele(dq); 220: if (dq->dq_cnt == 0) /* no files open using quota */ 221: return (error); 222: dq = NODQUOT; 223: } 224: if (dq == odq) 225: return (error); 226: for (ip = inode; ip < inodeNINODE; ip++) 227: if (ip->i_uid == q->q_uid && ip->i_dev == dev && ip->i_mode) { 228: if (dq == NODQUOT) 229: #ifdef pdp11 230: dqrele(ix_dquot[ip - inode]); 231: #else 232: dqrele(ip->i_dquot); 233: #endif 234: else 235: dq->dq_cnt++; 236: #ifdef pdp11 237: ix_dquot[ip - inode] = dq; 238: #else 239: ip->i_dquot = dq; 240: #endif 241: } 242: return (error); 243: } 244: 245: /* 246: * Q_GETDLIM - return current values in a dqblk structure. 247: */ 248: getdlim(q, dev, addr) 249: struct quota *q; 250: dev_t dev; 251: caddr_t addr; 252: { 253: register struct dquot *dq; 254: int error; 255: 256: dq = dqp(q, dev); 257: if (dq == NODQUOT) 258: return (ESRCH); 259: #ifdef pdp11 260: /* we do bytes not blocks, so convert the structure here */ 261: { 262: struct dqblk dqb; 263: 264: dqb = dq->dq_dqb; 265: dqb.dqb_bhardlimit = (long)btodb(dqb.dqb_bhardlimit); 266: dqb.dqb_bsoftlimit = (long)btodb(dqb.dqb_bsoftlimit); 267: dqb.dqb_curblocks = (long)btodb(dqb.dqb_curblocks); 268: error = copyout((caddr_t)&dqb, addr, sizeof(struct dqblk)); 269: } 270: #else 271: error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk)); 272: #endif 273: dqrele(dq); 274: return (error); 275: } 276: 277: /* 278: * Q_SETDUSE - set current inode and disc block totals. 279: * Resets warnings and associated flags. 280: */ 281: setduse(q, dev, addr) 282: register struct quota *q; 283: dev_t dev; 284: caddr_t addr; 285: { 286: register struct dquot *dq; 287: struct dqusage usage; 288: int error = 0; 289: 290: if (!suser()) 291: return (u.u_error); 292: dq = dqp(q, dev); 293: if (dq == NODQUOT) 294: return (ESRCH); 295: while (dq->dq_flags & DQ_LOCK) { 296: dq->dq_flags |= DQ_WANT; 297: #ifdef pdp11 298: QUOTAUNMAP(); 299: sleep((caddr_t)dq, PINOD+1); 300: QUOTAMAP(); 301: #else 302: sleep((caddr_t)dq, PINOD+1); 303: #endif 304: } 305: if (dq->dq_uid != q->q_uid) 306: panic("setduse"); 307: error = copyin(addr, (caddr_t)&usage, sizeof (usage)); 308: if (error == 0) { 309: dq->dq_curinodes = usage.du_curinodes; 310: #ifdef pdp11 311: dq->dq_curblocks = dbtob(usage.du_curblocks); 312: #else 313: dq->dq_curblocks = usage.du_curblocks; 314: #endif 315: if (dq->dq_curinodes < dq->dq_isoftlimit) 316: dq->dq_iwarn = MAX_IQ_WARN; 317: if (dq->dq_curblocks < dq->dq_bsoftlimit) 318: dq->dq_bwarn = MAX_DQ_WARN; 319: dq->dq_flags &= ~(DQ_INODS | DQ_BLKS); 320: dq->dq_flags |= DQ_MOD; 321: } 322: dqrele(dq); 323: return (error); 324: } 325: 326: /* 327: * Q_SETWARN - set warning counters. 328: */ 329: setwarn(q, dev, addr) 330: register struct quota *q; 331: dev_t dev; 332: caddr_t addr; 333: { 334: register struct dquot *dq; 335: int error = 0; 336: struct dqwarn warn; 337: 338: if (!suser()) 339: return (u.u_error); /* XXX */ 340: dq = dqp(q, dev); 341: if (dq == NODQUOT) 342: return (ESRCH); 343: while (dq->dq_flags & DQ_LOCK) { 344: dq->dq_flags |= DQ_WANT; 345: #ifdef pdp11 346: QUOTAUNMAP(); 347: sleep((caddr_t)dq, PINOD+1); 348: QUOTAMAP(); 349: #else 350: sleep((caddr_t)dq, PINOD+1); 351: #endif 352: } 353: if (dq->dq_uid != q->q_uid) 354: panic("setwarn"); 355: error = copyin(addr, (caddr_t)&warn, sizeof (warn)); 356: if (error == 0) { 357: dq->dq_iwarn = warn.dw_iwarn; 358: dq->dq_bwarn = warn.dw_bwarn; 359: dq->dq_flags &= ~(DQ_INODS | DQ_BLKS); 360: dq->dq_flags |= DQ_MOD; 361: } 362: dqrele(dq); 363: return (error); 364: } 365: 366: /* 367: * Q_DOWARN - force warning(s) to user(s). 368: */ 369: dowarn(q, dev) 370: register struct quota *q; 371: dev_t dev; 372: { 373: register struct dquot *dq, **dqq; 374: 375: if (!suser() || u.u_ttyp == NULL) 376: return (u.u_error); /* XXX */ 377: if (dev != NODEV) { 378: dq = dqp(q, dev); 379: if (dq != NODQUOT) { 380: qwarn(dq); 381: dqrele(dq); 382: } 383: return (0); 384: } 385: for (dqq = q->q_dq; dqq < &q->q_dq[NMOUNT]; dqq++) { 386: dq = *dqq; 387: if (dq != NODQUOT && dq != LOSTDQUOT) 388: qwarn(dq); 389: } 390: return (0); 391: } 392: 393: /* 394: * Q_SYNC - sync quota files to disc. 395: */ 396: qsync(dev) 397: dev_t dev; 398: { 399: register struct quota *q; 400: register struct mount *mp; 401: register index; 402: 403: if (!suser()) 404: return (u.u_error); /* XXX */ 405: for (mp = mount, index = 0; mp < &mount[NMOUNT]; mp++, index++) 406: #ifdef pdp11 407: if (mp->m_inodp && mp->m_qinod && 408: #else 409: if (mp->m_bufp && mp->m_qinod && 410: #endif 411: (dev == NODEV || dev == mp->m_dev)) { 412: for (q = quota; q < quotaNQUOTA; q++) 413: if (q->q_cnt) { 414: q->q_cnt++; 415: putdq(mp, q->q_dq[index], 0); 416: delquota(q); 417: } 418: } 419: return (0); 420: } 421: 422: /* 423: * Q_SETUID - change quota to a particular uid. 424: */ 425: qsetuid(uid, noquota) 426: uid_t uid; 427: int noquota; 428: { 429: register struct quota *q; 430: 431: if (uid == u.u_quota->q_uid) 432: return (0); 433: if (!suser()) 434: return (u.u_error); /* XXX */ 435: q = getquota(uid, 0, noquota ? Q_NDQ : 0); 436: qclean(); 437: qstart(q); 438: return (0); 439: } 440: #endif