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