3 * Generic IO operations on quotafiles
5 * Jan Kara <jack@suse.cz> - sponsored by SuSE CR
15 #include <sys/types.h>
18 #include <asm/byteorder.h>
28 #include "dqblk_rpc.h"
29 #include "dqblk_xfs.h"
31 /* Header in all newer quotafiles */
32 struct disk_dqheader {
34 u_int32_t dqh_version;
35 } __attribute__ ((packed));
38 * Detect quota format and initialize quota IO
40 struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
44 struct quota_handle *h = smalloc(sizeof(struct quota_handle));
45 const char *mnt_fsname = NULL;
47 if (!hasquota(mnt, type, 0))
49 if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
51 if (stat(mnt_fsname, &h->qh_stat) < 0)
52 memset(&h->qh_stat, 0, sizeof(struct stat));
54 if (flags & IOI_READONLY)
55 h->qh_io_flags |= IOFL_RO;
56 if (flags & IOI_NFS_MIXED_PATHS)
57 h->qh_io_flags |= IOFL_NFS_MIXED_PATHS;
59 sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
60 free((char *)mnt_fsname);
61 sstrncpy(h->qh_fstype, mnt->mnt_type, MAX_FSTYPE_LEN);
62 if (nfs_fstype(mnt->mnt_type)) { /* NFS filesystem? */
63 if (fmt != -1 && fmt != QF_RPC) { /* User wanted some other format? */
64 errstr(_("Only RPC quota format is allowed on NFS filesystem.\n"));
70 h->qh_ops = "afile_ops_rpc;
73 errstr(_("RPC quota format not compiled.\n"));
76 } else if (fmt == QF_RPC) {
77 errstr(_("RPC quota format specified for non-NFS filesystem.\n"));
81 if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem? */
82 if (fmt != -1 && fmt != QF_XFS) { /* User wanted some other format? */
83 errstr(_("Only XFS quota format is allowed on XFS filesystem.\n"));
88 h->qh_ops = "afile_ops_xfs;
89 memset(&h->qh_info, 0, sizeof(h->qh_info));
90 h->qh_ops->init_io(h);
93 else if (fmt == QF_XFS) {
94 errstr(_("XFS quota allowed only on XFS filesystem.\n"));
97 if (kern_qfmt_supp(fmt)) { /* Quota compiled and desired format available? */
98 /* Quota turned on? */
99 kernfmt = kern_quota_on(h->qh_quotadev, type, fmt);
101 h->qh_io_flags |= IOFL_QUOTAON;
102 fmt = kernfmt; /* Default is kernel used format */
106 if (meta_qf_fstype(mnt->mnt_type)) {
107 if (!QIO_ENABLED(h)) {
108 errstr(_("Quota not supported by the filesystem.\n"));
111 if (flags & IOI_OPENFILE) {
112 errstr(_("Operation not supported for filesystems with hidden quota files!\n"));
121 /* Let's try any VFSv0 quota format... */
122 if (get_qf_name(mnt, type, QF_VFSV0,
123 (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
126 /* And then VFSv1 quota format... */
127 else if (get_qf_name(mnt, type, QF_VFSV1,
128 (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
131 /* And then old quota format... */
132 else if (get_qf_name(mnt, type, QF_VFSOLD,
133 (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
136 else { /* Don't know... */
137 errstr(_("Cannot find any quota file to work on.\n"));
141 if (get_qf_name(mnt, type, fmt,
142 (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
144 errstr(_("Quota file not found or has wrong format.\n"));
148 if (!QIO_ENABLED(h) || flags & IOI_OPENFILE) { /* Need to open file? */
149 /* We still need to open file for operations like 'repquota' */
150 if ((fd = open(qfname, QIO_RO(h) ? O_RDONLY : O_RDWR)) < 0) {
151 errstr(_("Cannot open quotafile %s: %s\n"),
152 qfname, strerror(errno));
155 flock(fd, QIO_RO(h) ? LOCK_SH : LOCK_EX);
163 free(qfname); /* We don't need it anymore */
167 if (fmt == QF_VFSOLD)
168 h->qh_ops = "afile_ops_1;
169 else if (is_tree_qfmt(fmt))
170 h->qh_ops = "afile_ops_2;
171 else if (fmt == QF_META)
172 h->qh_ops = "afile_ops_meta;
173 memset(&h->qh_info, 0, sizeof(h->qh_info));
175 if (h->qh_ops->init_io && h->qh_ops->init_io(h) < 0) {
176 errstr(_("Cannot initialize quota on %s: %s\n"), h->qh_quotadev, strerror(errno));
191 * Create new quotafile of specified format on given filesystem
193 struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
197 struct quota_handle *h;
198 const char *mnt_fsname;
199 char namebuf[PATH_MAX];
203 else if (fmt == QF_RPC || fmt == QF_XFS || meta_qf_fstype(mnt->mnt_type)) {
204 errstr(_("Creation of %s quota format is not supported.\n"),
208 if (get_qf_name(mnt, type, fmt, 0, &qfname) < 0)
210 sstrncpy(namebuf, qfname, PATH_MAX);
211 sstrncat(namebuf, ".new", PATH_MAX);
213 if ((fd = open(namebuf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) {
214 errstr(_("Cannot create new quotafile %s: %s\n"),
215 namebuf, strerror(errno));
218 if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
220 h = smalloc(sizeof(struct quota_handle));
224 sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
225 free((char *)mnt_fsname);
228 memset(&h->qh_info, 0, sizeof(h->qh_info));
229 if (fmt == QF_VFSOLD)
230 h->qh_ops = "afile_ops_1;
232 h->qh_ops = "afile_ops_2;
235 if (h->qh_ops->new_io && h->qh_ops->new_io(h) < 0) {
247 * Close quotafile and release handle
249 int end_io(struct quota_handle *h)
251 if (h->qh_io_flags & IOFL_INFODIRTY) {
252 if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0)
254 h->qh_io_flags &= ~IOFL_INFODIRTY;
256 if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0)
258 if (h->qh_fd != -1) {
259 flock(h->qh_fd, LOCK_UN);
267 * Create empty quota structure
269 struct dquot *get_empty_dquot(void)
271 struct dquot *dquot = smalloc(sizeof(struct dquot));
273 memset(dquot, 0, sizeof(*dquot));