Update to latest version of quota.
[profile/ivi/quota.git] / quotaio_xfs.c
1 /*
2  *      Implementation of XFS quota manager.
3  *      Copyright (c) 2001 Silicon Graphics, Inc.
4  */
5
6 #include "config.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include "pot.h"
15 #include "common.h"
16 #include "bylabel.h"
17 #include "quotaio.h"
18 #include "quotasys.h"
19 #include "dqblk_xfs.h"
20 #include "quotaio_generic.h"
21
22 #define XFS_USRQUOTA(h) ((h)->qh_type == USRQUOTA && \
23                         (h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_UDQ_ACCT)
24 #define XFS_GRPQUOTA(h) ((h)->qh_type == GRPQUOTA && \
25                         (h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_GDQ_ACCT)
26
27 static int xfs_init_io(struct quota_handle *h);
28 static int xfs_write_info(struct quota_handle *h);
29 static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id);
30 static int xfs_commit_dquot(struct dquot *dquot, int flags);
31 static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname));
32 static int xfs_report(struct quota_handle *h, int verbose);
33
34 struct quotafile_ops quotafile_ops_xfs = {
35 init_io:        xfs_init_io,
36 write_info:     xfs_write_info,
37 read_dquot:     xfs_read_dquot,
38 commit_dquot:   xfs_commit_dquot,
39 scan_dquots:    xfs_scan_dquots,
40 report:         xfs_report
41 };
42
43 /*
44  *      Convert XFS kernel quota format to utility format
45  */
46 static inline void xfs_kern2utildqblk(struct util_dqblk *u, struct xfs_kern_dqblk * k)
47 {
48         u->dqb_ihardlimit = k->d_ino_hardlimit;
49         u->dqb_isoftlimit = k->d_ino_softlimit;
50         u->dqb_bhardlimit = k->d_blk_hardlimit >> 1;
51         u->dqb_bsoftlimit = k->d_blk_softlimit >> 1;
52         u->dqb_curinodes = k->d_icount;
53         u->dqb_curspace = ((qsize_t)k->d_bcount) << 9;
54         u->dqb_itime = k->d_itimer;
55         u->dqb_btime = k->d_btimer;
56 }
57
58 /*
59  *      Convert utility quota format to XFS kernel format
60  */
61 static inline void xfs_util2kerndqblk(struct xfs_kern_dqblk *k, struct util_dqblk *u)
62 {
63         memset(k, 0, sizeof(struct xfs_kern_dqblk));
64         k->d_ino_hardlimit = u->dqb_ihardlimit;
65         k->d_ino_softlimit = u->dqb_isoftlimit;
66         k->d_blk_hardlimit = u->dqb_bhardlimit << 1;
67         k->d_blk_softlimit = u->dqb_bsoftlimit << 1;
68         k->d_icount = u->dqb_curinodes;
69         k->d_bcount = u->dqb_curspace >> 9;
70         k->d_itimer = u->dqb_itime;
71         k->d_btimer = u->dqb_btime;
72 }
73
74 /*
75  *      Initialize quota information
76  */
77 static int xfs_init_io(struct quota_handle *h)
78 {
79         struct xfs_mem_dqinfo info;
80         int qcmd;
81
82         qcmd = QCMD(Q_XFS_GETQSTAT, 0);
83         memset(&info, 0, sizeof(struct xfs_mem_dqinfo));
84         if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&info) < 0)
85                 return -1;
86         h->qh_info.dqi_bgrace = info.qs_btimelimit;
87         h->qh_info.dqi_igrace = info.qs_itimelimit;
88         h->qh_info.u.xfs_mdqi = info;
89         return 0;
90 }
91
92 /*
93  *      Write information (grace times)
94  */
95 static int xfs_write_info(struct quota_handle *h)
96 {
97         struct xfs_kern_dqblk xdqblk;
98         int qcmd;
99
100         if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
101                 return 0;
102
103         memset(&xdqblk, 0, sizeof(struct xfs_kern_dqblk));
104
105         xdqblk.d_btimer = h->qh_info.dqi_bgrace;
106         xdqblk.d_itimer = h->qh_info.dqi_igrace;
107         xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK;
108         qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type);
109         if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&xdqblk) < 0)
110                 return -1;
111         return 0;
112 }
113
114 /*
115  *      Read a dqblk struct from the quota manager
116  */
117 static struct dquot *xfs_read_dquot(struct quota_handle *h, qid_t id)
118 {
119         struct dquot *dquot = get_empty_dquot();
120         struct xfs_kern_dqblk xdqblk;
121         int qcmd;
122
123         dquot->dq_id = id;
124         dquot->dq_h = h;
125
126         if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
127                 return dquot;
128
129         qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type);
130         if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) {
131                 ;
132         }
133         else {
134                 xfs_kern2utildqblk(&dquot->dq_dqb, &xdqblk);
135         }
136         return dquot;
137 }
138
139 /*
140  *      Write a dqblk struct to the XFS quota manager
141  */
142 static int xfs_commit_dquot(struct dquot *dquot, int flags)
143 {
144         struct quota_handle *h = dquot->dq_h;
145         struct xfs_kern_dqblk xdqblk;
146         qid_t id = dquot->dq_id;
147         int qcmd;
148
149         if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
150                 return 0;
151
152         xfs_util2kerndqblk(&xdqblk, &dquot->dq_dqb);
153         xdqblk.d_flags |= XFS_USRQUOTA(h) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
154         xdqblk.d_id = id;
155         if (strcmp(h->qh_fstype, MNTTYPE_GFS2) == 0) {
156                 if (flags & COMMIT_LIMITS) /* warn/limit */
157                         xdqblk.d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
158                 if (flags & COMMIT_USAGE) /* block usage */
159                         xdqblk.d_fieldmask |= FS_DQ_BCOUNT;
160         } else {
161                 xdqblk.d_fieldmask |= FS_DQ_LIMIT_MASK;
162         }
163
164         qcmd = QCMD(Q_XFS_SETQLIM, h->qh_type);
165         if (quotactl(qcmd, h->qh_quotadev, id, (void *)&xdqblk) < 0) {
166                 ;
167         }
168         else {
169                 return 0;
170         }
171         return -1;
172 }
173
174 /*
175  *      xfs_scan_dquots helper - processes a single dquot
176  */
177 static int xfs_get_dquot(struct dquot *dq)
178 {
179         struct xfs_kern_dqblk d;
180         int qcmd = QCMD(Q_XFS_GETQUOTA, dq->dq_h->qh_type);
181         int ret;
182
183         memset(&d, 0, sizeof(d));
184         ret = quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_id, (void *)&d);
185         if (ret < 0) {
186                 if (errno == ENOENT)
187                         return 0;
188                 return -1;
189         }
190         xfs_kern2utildqblk(&dq->dq_dqb, &d);
191         return 0;
192 }
193
194 /*
195  *      Scan all known dquots and call callback on each
196  */
197 static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname))
198 {
199         if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
200                 return 0;
201
202         return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
203 }
204
205 /*
206  *      Report information about XFS quota on given filesystem
207  */
208 static int xfs_report(struct quota_handle *h, int verbose)
209 {
210         u_int16_t sbflags;
211         struct xfs_mem_dqinfo *info = &h->qh_info.u.xfs_mdqi;
212
213         if (!verbose)
214                 return 0;
215
216         /* quotaon/off flags */
217         printf(_("*** Status for %s quotas on device %s\n"), type2name(h->qh_type), h->qh_quotadev);
218
219 #define XQM_ON(flag) ((info->qs_flags & (flag)) ? _("ON") : _("OFF"))
220         if (h->qh_type == USRQUOTA) {
221                 printf(_("Accounting: %s; Enforcement: %s\n"),
222                        XQM_ON(XFS_QUOTA_UDQ_ACCT), XQM_ON(XFS_QUOTA_UDQ_ENFD));
223         }
224         else {                  /* qh_type == USRQUOTA */
225                 printf(_("Accounting: %s; Enforcement: %s\n"),
226                        XQM_ON(XFS_QUOTA_GDQ_ACCT), XQM_ON(XFS_QUOTA_GDQ_ENFD));
227         }
228 #undef XQM_ON
229
230         /*
231          * If this is the root file system, it is possible that quotas are
232          * on ondisk, but not incore. Those flags will be in the HI 8 bits.
233          */
234 #define XQM_ONDISK(flag) ((sbflags & (flag)) ? _("ON") : _("OFF"))
235         if ((sbflags = (info->qs_flags & 0xff00) >> 8) != 0) {
236                 if (h->qh_type == USRQUOTA) {
237                         printf(_("Accounting [ondisk]: %s; Enforcement [ondisk]: %s\n"),
238                                XQM_ONDISK(XFS_QUOTA_UDQ_ACCT), XQM_ONDISK(XFS_QUOTA_UDQ_ENFD));
239                 }
240                 else {          /* qh_type == USRQUOTA */
241                         printf(_("Accounting [ondisk]: %s; Enforcement [ondisk]: %s\n"),
242                                XQM_ONDISK(XFS_QUOTA_GDQ_ACCT), XQM_ONDISK(XFS_QUOTA_GDQ_ENFD));
243                 }
244 #undef XQM_ONDISK
245         }
246
247         /* user and group quota file status information */
248         if (h->qh_type == USRQUOTA) {
249                 if (info->qs_uquota.qfs_ino == -1 || info->qs_uquota.qfs_ino == 0)
250                         printf(_("Inode: none\n"));
251                 else
252                         printf(_("Inode: #%llu (%llu blocks, %u extents)\n"),
253                                (unsigned long long)info->qs_uquota.qfs_ino,
254                                (unsigned long long)info->qs_uquota.qfs_nblks,
255                                info->qs_uquota.qfs_nextents);
256         }
257         else {                  /* qh_type == GRPQUOTA */
258                 if (info->qs_gquota.qfs_ino == -1)
259                         printf(_("Inode: none\n"));
260                 else
261                         printf(_("Inode: #%llu (%llu blocks, %u extents)\n"),
262                                (unsigned long long)info->qs_gquota.qfs_ino,
263                                (unsigned long long)info->qs_gquota.qfs_nblks,
264                                info->qs_gquota.qfs_nextents);
265         }
266         return 0;
267 }