/*
 * QUOTA   An implementation of the diskquota system for the LINUX
 * operating system.  QUOTA is implemented using the BSD systemcall interface
 * as the means of communication with the user level. Should work for all
 * filesystems because of integration into the VFS layer of the operating
 * system. This is based on the Melbourne quota system wich uses both user
 * and group quota files.
 * 
 * System-call interface to the user-level.
 * 
 * Version:    $Id: sys.c,v 1.1 1993/05/22 17:18:08 root Exp root $
 * 
 * Authors:   Marco van Wieringen <v892273@si.hhs.nl>
 *            Edvard Tuinder <v892231@si.hhs.nl>
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 */

#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>

#ifdef CONFIG_QUOTA
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/quota.h>
#include <linux/stat.h>

extern int quota_on(dev_t, int, char *);
extern int quota_off(dev_t, int);
extern int get_quota(dev_t, int, int, struct dqblk *);
extern int set_quota(dev_t, int, int, struct dqblk *);
extern int set_use(dev_t, int, int, struct dqblk *);
extern int set_qlimit(dev_t, int, int, struct dqblk *);

extern "C" int sys_quotactl(int cmd, const char *special, int id, caddr_t * addr)
{
   int cmds = 0, type = 0;
   struct inode *ino;
   dev_t dev;

   cmds = cmd >> SUBCMDSHIFT;
   switch (cmds) {
      case Q_GETQUOTA:
      case Q_SYNC:
         if (((type == USRQUOTA && current->uid != id) ||
              (type == GRPQUOTA && current->gid != id)) && !suser())
            return -EPERM;
      default:
         if (!suser())
            return -EPERM;
   }

   if (special == (char *)0 && cmds == Q_SYNC)
      dev = 0;
   else {
      if (namei(special, &ino))
         return -EINVAL;
      dev = ino->i_rdev;
      if (!S_ISBLK(ino->i_mode)) {
         iput(ino);
         return -ENOTBLK;
      }
      iput(ino);
   }

   type = cmd & SUBCMDMASK;
   if ((u_int) type >= MAXQUOTAS)
      return -EINVAL;

   switch (cmds) {
      case Q_QUOTAON:
         return quota_on(dev, type, (char *) addr);
      case Q_QUOTAOFF:
         return quota_off(dev, type);
      case Q_GETQUOTA:
         return get_quota(dev, id, type, (struct dqblk *) addr);
      case Q_SETQUOTA:
         return set_quota(dev, id, type, (struct dqblk *) addr);
      case Q_SETUSE:
         return set_use(dev, id, type, (struct dqblk *) addr);
      case Q_SETQLIM:
         return set_qlimit(dev, id, type, (struct dqblk *) addr);
      case Q_SYNC:
         return sync_quota(dev, type);
      default:
         return -EINVAL;
   }
   /* NOTREACHED */
}
#else
int sys_quotactl(int cmd, const char *special, int id, char *addr)
{
   return -EINVAL;
}
#endif /* CONFIG_QUOTA */
