Update to 4.01.
[profile/ivi/quota.git] / quotaio.c
index e857328..d3c7cb6 100644 (file)
--- a/quotaio.c
+++ b/quotaio.c
@@ -37,18 +37,16 @@ struct disk_dqheader {
 /*
  *     Detect quota format and initialize quota IO
  */
-struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
+struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int flags)
 {
        char *qfname = NULL;
        int fd = -1, kernfmt;
        struct quota_handle *h = smalloc(sizeof(struct quota_handle));
-       const char *mnt_fsname = NULL;
+       int nameflag;
 
-       if (!hasquota(mnt, type, 0))
+       if (!me_hasquota(mnt, type))
                goto out_handle;
-       if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
-               goto out_handle;
-       if (stat(mnt_fsname, &h->qh_stat) < 0)
+       if (stat(mnt->me_devname, &h->qh_stat) < 0)
                memset(&h->qh_stat, 0, sizeof(struct stat));
        h->qh_io_flags = 0;
        if (flags & IOI_READONLY)
@@ -56,10 +54,10 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
        if (flags & IOI_NFS_MIXED_PATHS)
                h->qh_io_flags |= IOFL_NFS_MIXED_PATHS;
        h->qh_type = type;
-       sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
-       free((char *)mnt_fsname);
-       sstrncpy(h->qh_fstype, mnt->mnt_type, MAX_FSTYPE_LEN);
-       if (nfs_fstype(mnt->mnt_type)) {        /* NFS filesystem? */
+       sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
+       sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
+       sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
+       if (nfs_fstype(mnt->me_type)) { /* NFS filesystem? */
                if (fmt != -1 && fmt != QF_RPC) {       /* User wanted some other format? */
                        errstr(_("Only RPC quota format is allowed on NFS filesystem.\n"));
                        goto out_handle;
@@ -68,6 +66,8 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
                h->qh_fd = -1;
                h->qh_fmt = QF_RPC;
                h->qh_ops = &quotafile_ops_rpc;
+               memset(&h->qh_info, 0, sizeof(h->qh_info));
+               h->qh_ops->init_io(h);
                return h;
 #else
                errstr(_("RPC quota format not compiled.\n"));
@@ -78,7 +78,8 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
                goto out_handle;
        }
 
-       if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) {      /* XFS filesystem? */
+       if (!strcmp(mnt->me_type, MNTTYPE_XFS) ||       /* XFS filesystem? */
+           !strcmp(mnt->me_type, MNTTYPE_GFS2)) {      /* XFS filesystem? */
                if (fmt != -1 && fmt != QF_XFS) {       /* User wanted some other format? */
                        errstr(_("Only XFS quota format is allowed on XFS filesystem.\n"));
                        goto out_handle;
@@ -96,56 +97,54 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
        }
        if (kern_qfmt_supp(fmt)) {      /* Quota compiled and desired format available? */
                /* Quota turned on? */
-               kernfmt = kern_quota_on(h->qh_quotadev, type, fmt);
+               kernfmt = kern_quota_on(mnt, type, fmt);
                if (kernfmt >= 0) {
                        h->qh_io_flags |= IOFL_QUOTAON;
                        fmt = kernfmt;  /* Default is kernel used format */
                }
        }
 
-       if (meta_qf_fstype(mnt->mnt_type)) {
+       if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
                if (!QIO_ENABLED(h)) {
                        errstr(_("Quota not supported by the filesystem.\n"));
                        goto out_handle;
                }
-               if (flags & IOI_OPENFILE) {
-                       errstr(_("Operation not supported for filesystems with hidden quota files!\n"));
-                       goto out_handle;
-               }
                h->qh_fd = -1;
                h->qh_fmt = fmt;
                goto set_ops;
        }
 
+       nameflag = (!QIO_ENABLED(h) || flags & IOI_INITSCAN) ? NF_FORMAT : 0;
        if (fmt == -1) {
                /* Let's try any VFSv0 quota format... */
-               if (get_qf_name(mnt, type, QF_VFSV0,
-                               (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
-                               &qfname) >= 0)
+               if (get_qf_name(mnt, type, QF_VFSV0, nameflag, &qfname) >= 0)
                        fmt = QF_VFSV0;
                /* And then VFSv1 quota format... */
-               else if (get_qf_name(mnt, type, QF_VFSV1,
-                               (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
-                               &qfname) >= 0)
+               else if (get_qf_name(mnt, type, QF_VFSV1, nameflag, &qfname) >= 0)
                        fmt = QF_VFSV1;
                /* And then old quota format... */
-               else if (get_qf_name(mnt, type, QF_VFSOLD,
-                                (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
-                                &qfname) >= 0)
+               else if (get_qf_name(mnt, type, QF_VFSOLD, nameflag, &qfname) >= 0)
                        fmt = QF_VFSOLD;
                else {  /* Don't know... */
                        errstr(_("Cannot find any quota file to work on.\n"));
                        goto out_handle;
                }
        } else {
-               if (get_qf_name(mnt, type, fmt,
-                               (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
-                               &qfname) < 0) {
+               if (get_qf_name(mnt, type, fmt, nameflag, &qfname) < 0) {
                        errstr(_("Quota file not found or has wrong format.\n"));
                        goto out_handle;
                }
        }
-       if (!QIO_ENABLED(h) || flags & IOI_OPENFILE) {  /* Need to open file? */
+       if (!QIO_ENABLED(h) || flags & IOI_INITSCAN) {  /* Need to open file? */
+               if (QIO_ENABLED(h)) {   /* Kernel uses same file? */
+                       unsigned int cmd =
+                               (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC;
+                       if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
+                                    0, NULL) < 0) {
+                               die(4, _("Cannot sync quotas on device %s: %s\n"),
+                                   h->qh_quotadev, strerror(errno));
+                       }
+               }
                /* We still need to open file for operations like 'repquota' */
                if ((fd = open(qfname, QIO_RO(h) ? O_RDONLY : O_RDWR)) < 0) {
                        errstr(_("Cannot open quotafile %s: %s\n"),
@@ -190,21 +189,30 @@ out_handle:
 /*
  *     Create new quotafile of specified format on given filesystem
  */
-struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
+struct quota_handle *new_io(struct mount_entry *mnt, int type, int fmt)
 {
        char *qfname;
        int fd;
        struct quota_handle *h;
-       const char *mnt_fsname;
        char namebuf[PATH_MAX];
 
        if (fmt == -1)
                fmt = QF_VFSV0;
-       else if (fmt == QF_RPC || fmt == QF_XFS || meta_qf_fstype(mnt->mnt_type)) {
+       else if (fmt == QF_RPC || fmt == QF_XFS) {
                errstr(_("Creation of %s quota format is not supported.\n"),
                        fmt2name(fmt));
                return NULL;
        }
+       /*
+        * For filesystems which never have quotas in quota files or for
+        * filesystems which have quotas already stored in system files we
+        * refuse to create anything.
+        */
+       if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
+               errstr(_("Quota on %s is stored in system files and must"
+                        " be manipulated by fs tools.\n"), mnt->me_dir);
+               return NULL;
+       }
        if (get_qf_name(mnt, type, fmt, 0, &qfname) < 0)
                return NULL;
        sstrncpy(namebuf, qfname, PATH_MAX);
@@ -215,14 +223,13 @@ struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
                        namebuf, strerror(errno));
                return NULL;
        }
-       if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
-               goto out_fd;
        h = smalloc(sizeof(struct quota_handle));
 
        h->qh_fd = fd;
        h->qh_io_flags = 0;
-       sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
-       free((char *)mnt_fsname);
+       sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
+       sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
+       sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
        h->qh_type = type;
        h->qh_fmt = fmt;
        memset(&h->qh_info, 0, sizeof(h->qh_info));
@@ -274,3 +281,27 @@ struct dquot *get_empty_dquot(void)
        dquot->dq_id = -1;
        return dquot;
 }
+
+/*
+ *     Check whether values in current dquot can be stored on disk
+ */
+int check_dquot_range(struct dquot *dquot)
+{
+       struct util_dqinfo *info = &dquot->dq_h->qh_info;
+
+       if (dquot->dq_dqb.dqb_bhardlimit > info->dqi_max_b_limit ||
+           dquot->dq_dqb.dqb_bsoftlimit > info->dqi_max_b_limit ||
+           dquot->dq_dqb.dqb_ihardlimit > info->dqi_max_i_limit ||
+           dquot->dq_dqb.dqb_isoftlimit > info->dqi_max_i_limit) {
+               errstr(_("Trying to set quota limits out of range "
+                                "supported by quota format on %s.\n"), dquot->dq_h->qh_quotadev);
+               return -1;
+       }
+       if (dquot->dq_dqb.dqb_curinodes > info->dqi_max_i_usage ||
+           dquot->dq_dqb.dqb_curspace > info->dqi_max_b_usage) {
+               errstr(_("Trying to set quota usage out of range "
+                        "supported by quota format on %s.\n"), dquot->dq_h->qh_quotadev);
+               return -1;
+       }
+       return 0;
+}