/*
 * Copyright (c) 1980, 1990 Regents of the University of California. All
 * rights reserved.
 * 
 * This code is derived from software contributed to Berkeley by Robert Elz at
 * The University of Melbourne.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer. 2.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution. 3. All advertising
 * materials mentioning features or use of this software must display the
 * following acknowledgement: This product includes software developed by the
 * University of California, Berkeley and its contributors. 4. Neither the
 * name of the University nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific
 * prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
char copyright[] =
   "@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char rcsid[] = "$Id: setquota.c,v 1.4 2000/09/05 18:47:15 mvw Exp mvw $";
#endif /* not lint */

/*
 * set disk quota from command line 
 */
#include <rpc/rpc.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/quota.h>
#include <errno.h>
#include <mntent.h>
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <quotaops.h>
#if defined(RPC)
#include <rquota.h>
#endif

#include "pot.h"

static char *quotatypes[] = INITQFNAMES;

static int usage(void)
{
#if defined(RPC_SETQUOTA)
   fprintf(stderr, _("Usage:\n"
                   "\tsetquota [-u|-g] [-n] [-r] <username|groupname> <filesystem>\n"
                   "\t\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit>\n"
                   "\tsetquota [-u|-g] [-n] [-r] <-p protousername|protogroupname> <username|groupname> <filesystem>\n"));
#else
   fprintf(stderr, _("Usage:\n"
                   "\tsetquota [-u|-g] [-n] <username|groupname> <filesystem>\n"
                   "\t\t<block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit>\n"
                   "\tsetquota [-u|-g] [-n] <-p protousername|protogroupname> <username|groupname> <filesystem>\n"));
#endif
   exit(1);
}

/*
 * Check whether a string is completely composed of digits.
 */
static int alldigits(char *s)
{
   int c;
   
   c = *s++;
   do {
      if (!isdigit(c))
         return (0);
   } while (c = *s++);
   return (1);
}

static int getentry(char *name, int quotatype)
{
   struct passwd *pw;
   struct group *gr;
   
   switch (quotatype) {
      case USRQUOTA:
         if (pw = getpwnam(name))
            return (pw->pw_uid);
         fprintf(stderr, _("%s: no such user\n"), name);
         break;
      case GRPQUOTA:
         if (gr = getgrnam(name))
            return (gr->gr_gid);
         fprintf(stderr, _("%s: no such group\n"), name);
         break;
      default:
         fprintf(stderr, _("%d: unknown quota type\n"), quotatype);
         break;
   }
   return (-1);
}

int main(int argc, char **argv)
{
   struct quotause *qup, *protoqup, *protoprivs, *curprivs;
   extern char *optarg;
   extern int optind;
   long id, protoid;
   int quotatype, tmpfd;
   char *protoname, ch;
   int nflag, pflag, rflag;
   char *fsys;
   char gotfs;
   u_int32_t block_hardlimit, block_softlimit, inode_hardlimit, inode_softlimit;
   char *cnum;

   gettexton();
   
   /*
    * Initialize flags.
    */
   nflag = 0;
   pflag = 0;
#if defined(RPC_SETQUOTA)
   rflag = 1;
#else
   rflag = 0;
#endif
   
   if (getuid()) {
      fprintf(stderr, _("setquota: permission denied\n"));
      exit(1);
   }
   
   quotatype = USRQUOTA;

#if defined(RPC_SETQUOTA)
   while ((ch = getopt(argc, argv, "igp:ur")) != EOF) {
#else
   while ((ch = getopt(argc, argv, "igp:u")) != EOF) {
#endif
      switch (ch) {
         case 'g':
            quotatype = GRPQUOTA;
            break;
         case 'n':
            nflag=1;
            break;
         case 'p':
            protoname = optarg;
            pflag++;
            break;
         case 'u':
            quotatype = USRQUOTA;
            break;
#if defined(RPC_SETQUOTA)
         case 'r':
            rflag = 0;
            break;
#endif
         default:
            fprintf(stderr, _("Unknown option -%c\n"), ch);
            break;
      }
   }

   argv += optind;
   argc -= optind;

   if (pflag) {
      if (argc != 2)
         usage();

      if (nflag) {
         protoid = atoi(protoname);
      } else {
         if ((protoid = getentry(protoname, quotatype)) == -1) {
            fprintf(stderr, _("Unknown protoname %s for quotatype %s\n"), protoname, quotatypes[quotatype]);
            exit(1);
         }
      }

      if (nflag) {
         id = atoi(*argv);
      } else {
         if ((id = getentry(*argv, quotatype)) == -1)
            exit(-1);
      }
   
      argv++;
      fsys = *argv;

      gotfs = 0;
      protoprivs = getprivs(protoid, quotatype, (rflag == 0));
      for (qup = protoprivs; qup; qup = qup->next) {
         if (strcmp(qup->fsname, fsys) == 0) {
            protoqup = qup;
            gotfs++;
         }
      }

      if (!gotfs) {
         fprintf (stderr, _("File system %s not found\n"), fsys);
         exit(-1);
      }
   
      gotfs = 0;
      curprivs = getprivs(id, quotatype, (rflag == 0));
      for (qup = curprivs; qup; qup = qup->next) {
         if (strcmp(qup->fsname, fsys) == 0) {
            gotfs++;
         
            qup->dqblk.dqb_bsoftlimit = protoqup->dqblk.dqb_bsoftlimit;
            qup->dqblk.dqb_bhardlimit = protoqup->dqblk.dqb_bhardlimit;
            qup->dqblk.dqb_isoftlimit = protoqup->dqblk.dqb_isoftlimit;
            qup->dqblk.dqb_ihardlimit = protoqup->dqblk.dqb_ihardlimit;
         }
      }

      if (!gotfs) {
         fprintf (stderr, _("File system %s not found\n"), fsys);
         exit(-1);
      }
   
      putprivs(id, quotatype, curprivs); 
      freeprivs(protoprivs);
      freeprivs(curprivs);
   } else {
      if (argc != 6)
         usage();
   
      if (nflag) {
         id = atoi(*argv);
      } else {
         if ((id = getentry(*argv, quotatype)) == -1)
            exit(-1);
      }
   
      argv++;
      fsys = *argv;
   
      argv++;
      if (alldigits(*argv))
         block_softlimit = atoi(*argv);
      else {
         fprintf(stderr, _("Invalid number: block-soft\n"));
         exit(-1);
      }
   
      argv++;
      if (alldigits(*argv))
         block_hardlimit = atoi(*argv);
      else {
         fprintf(stderr, _("Invalid number: block-hard\n"));
         exit(-1);
      }
   
      argv++;
      if (alldigits(*argv))
         inode_softlimit = atoi(*argv);
      else {
         fprintf(stderr, _("Invalid number: inode-soft\n"));
         exit(-1);
      }
   
      argv++;
      if (alldigits(*argv))
         inode_hardlimit = atoi(*argv);
      else {
         fprintf(stderr, _("Invalid number: inode-hard\n"));
         exit(-1);
      }

      curprivs = getprivs(id, quotatype, (rflag == 0));
      for (qup = curprivs; qup; qup = qup->next) {
         if (strcmp(qup->fsname, fsys) == 0) {
            gotfs++;
         
            qup->dqblk.dqb_bsoftlimit = block_softlimit;
            qup->dqblk.dqb_bhardlimit = block_hardlimit;
            qup->dqblk.dqb_isoftlimit = inode_softlimit;
            qup->dqblk.dqb_ihardlimit = inode_hardlimit;
         }
      }

      if (!gotfs) {
         fprintf (stderr, _("File system not found\n"));
         exit(-1);
      }
   
      putprivs(id, quotatype, curprivs); 
      freeprivs(curprivs);
   }
   
   exit(0);
}
