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