3 * Utility for converting quota file from old to new format
18 #include <asm/byteorder.h>
26 #include "quotaio_v2.h"
29 #define ACT_FORMAT 1 /* Convert format from old to new */
30 #define ACT_ENDIAN 2 /* Convert endianity */
35 struct quota_handle *qn; /* Handle of new file */
36 int action; /* Action to be performed */
39 static void usage(void)
41 errstr(_("Utility for converting quota files.\nUsage:\n\t%s [options] mountpoint\n\n\
42 -u, --user convert user quota file\n\
43 -g, --group convert group quota file\n\
44 -e, --convert-endian convert quota file to correct endianity\n\
45 -f, --convert-format oldfmt,newfmt convert from old to VFSv0 quota format\n\
46 -h, --help show this help text and exit\n\
47 -V, --version output version information and exit\n\n"), progname);
48 errstr(_("Bugs to %s\n"), MY_EMAIL);
52 static inline unsigned int min(unsigned a, unsigned b)
59 #define MAX_FMTNAME_LEN 32
61 static void parse_options(int argcnt, char **argstr)
64 struct option long_opts[] = {
65 { "help", 0, NULL, 'h'},
66 { "version", 0, NULL, 'V'},
67 { "user", 0, NULL, 'u'},
68 { "group", 0, NULL, 'g'},
69 { "convert-endian", 0, NULL, 'e'},
70 { "convert-format", 1, NULL, 'f'},
74 char fmtbuf[MAX_FMTNAME_LEN];
76 while ((ret = getopt_long(argcnt, argstr, "Vugef:h", long_opts, NULL)) != -1) {
95 comma = strchr(optarg, ',');
97 errstr(_("You have to specify source and target format of conversion.\n"));
100 sstrncpy(fmtbuf, optarg, min(comma - optarg + 1, MAX_FMTNAME_LEN));
101 infmt = name2fmt(fmtbuf);
102 if (infmt == QF_ERROR)
104 outfmt = name2fmt(comma + 1);
105 if (outfmt == QF_ERROR)
111 if (optind + 1 != argcnt) {
112 errstr(_("Bad number of arguments.\n"));
119 errstr(_("You have to specify action to perform.\n"));
123 mntpoint = argstr[optind];
127 * Implementation of endian conversion
130 typedef char *dqbuf_t;
132 #define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7)))
133 #define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7)))
135 #define getdqbuf() smalloc(QT_BLKSIZE)
136 #define freedqbuf(buf) free(buf)
138 static inline void endian_disk2memdqblk(struct util_dqblk *m, struct v2r0_disk_dqblk *d)
140 m->dqb_ihardlimit = __be32_to_cpu(d->dqb_ihardlimit);
141 m->dqb_isoftlimit = __be32_to_cpu(d->dqb_isoftlimit);
142 m->dqb_bhardlimit = __be32_to_cpu(d->dqb_bhardlimit);
143 m->dqb_bsoftlimit = __be32_to_cpu(d->dqb_bsoftlimit);
144 m->dqb_curinodes = __be32_to_cpu(d->dqb_curinodes);
145 m->dqb_curspace = __be64_to_cpu(d->dqb_curspace);
146 m->dqb_itime = __be64_to_cpu(d->dqb_itime);
147 m->dqb_btime = __be64_to_cpu(d->dqb_btime);
150 /* Is given dquot empty? */
151 static int endian_empty_dquot(struct v2r0_disk_dqblk *d)
153 static struct v2r0_disk_dqblk fakedquot;
155 return !memcmp(d, &fakedquot, sizeof(fakedquot));
158 /* Read given block */
159 static void read_blk(int fd, uint blk, dqbuf_t buf)
163 lseek(fd, blk << QT_BLKSIZE_BITS, SEEK_SET);
164 err = read(fd, buf, QT_BLKSIZE);
166 die(2, _("Cannot read block %u: %s\n"), blk, strerror(errno));
167 else if (err != QT_BLKSIZE)
168 memset(buf + err, 0, QT_BLKSIZE - err);
171 static void endian_report_block(int fd, uint blk, char *bitmap)
173 dqbuf_t buf = getdqbuf();
174 struct qt_disk_dqdbheader *dh;
175 struct v2r0_disk_dqblk *ddata;
177 struct qtree_mem_dqinfo *info = &qn->qh_info.u.v2_mdqi.dqi_qtree;
180 set_bit(bitmap, blk);
181 read_blk(fd, blk, buf);
182 dh = (struct qt_disk_dqdbheader *)buf;
183 ddata = (struct v2r0_disk_dqblk *)(dh + 1);
184 for (i = 0; i < qtree_dqstr_in_blk(info); i++)
185 if (!endian_empty_dquot(ddata + i)) {
186 memset(&dquot, 0, sizeof(dquot));
188 endian_disk2memdqblk(&dquot.dq_dqb, ddata + i);
189 dquot.dq_id = __be32_to_cpu(ddata[i].dqb_id);
190 if (qn->qh_ops->commit_dquot(&dquot, COMMIT_ALL) < 0)
191 errstr(_("Cannot commit dquot for id %u: %s\n"),
192 (uint)dquot.dq_id, strerror(errno));
197 static void endian_report_tree(int fd, uint blk, int depth, char *bitmap)
200 dqbuf_t buf = getdqbuf();
201 u_int32_t *ref = (u_int32_t *) buf;
203 read_blk(fd, blk, buf);
204 if (depth == QT_TREEDEPTH - 1) {
205 for (i = 0; i < QT_BLKSIZE >> 2; i++) {
206 blk = __be32_to_cpu(ref[i]);
207 if (blk && !get_bit(bitmap, blk))
208 endian_report_block(fd, blk, bitmap);
212 for (i = 0; i < QT_BLKSIZE >> 2; i++)
213 if ((blk = __be32_to_cpu(ref[i])))
214 endian_report_tree(fd, blk, depth + 1, bitmap);
219 static int endian_scan_structures(int fd, int type)
222 loff_t blocks = (lseek(fd, 0, SEEK_END) + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS;
224 bitmap = smalloc((blocks + 7) >> 3);
225 memset(bitmap, 0, (blocks + 7) >> 3);
226 endian_report_tree(fd, QT_TREEOFF, 0, bitmap);
231 static int endian_check_header(int fd, int type)
233 struct v2_disk_dqheader head;
234 u_int32_t file_magics[] = INITQMAGICS;
235 u_int32_t known_versions[] = INIT_V2_VERSIONS;
237 lseek(fd, 0, SEEK_SET);
238 if (read(fd, &head, sizeof(head)) != sizeof(head)) {
239 errstr(_("Cannot read header of old quotafile.\n"));
242 if (__be32_to_cpu(head.dqh_magic) != file_magics[type] || __be32_to_cpu(head.dqh_version) > known_versions[type]) {
243 errstr(_("Bad file magic or version (probably not quotafile with bad endianity).\n"));
249 static int endian_load_info(int fd, int type)
251 struct v2_disk_dqinfo dinfo;
253 if (read(fd, &dinfo, sizeof(dinfo)) != sizeof(dinfo)) {
254 errstr(_("Cannot read information about old quotafile.\n"));
257 qn->qh_info.u.v2_mdqi.dqi_flags = __be32_to_cpu(dinfo.dqi_flags);
258 qn->qh_info.dqi_bgrace = __be32_to_cpu(dinfo.dqi_bgrace);
259 qn->qh_info.dqi_igrace = __be32_to_cpu(dinfo.dqi_igrace);
264 * End of endian conversion
267 static int convert_dquot(struct dquot *dquot, char *name)
269 struct dquot newdquot;
271 memset(&newdquot, 0, sizeof(newdquot));
272 newdquot.dq_id = dquot->dq_id;
274 newdquot.dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
275 newdquot.dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
276 newdquot.dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes;
277 newdquot.dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
278 newdquot.dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit;
279 newdquot.dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace;
280 newdquot.dq_dqb.dqb_btime = dquot->dq_dqb.dqb_btime;
281 newdquot.dq_dqb.dqb_itime = dquot->dq_dqb.dqb_itime;
282 if (qn->qh_ops->commit_dquot(&newdquot, COMMIT_ALL) < 0) {
283 errstr(_("Cannot commit dquot for id %u: %s\n"),
284 (uint)dquot->dq_id, strerror(errno));
290 static int rename_file(int type, int fmt, struct mntent *mnt)
292 char *qfname, namebuf[PATH_MAX];
295 if (get_qf_name(mnt, type, fmt, 0, &qfname) < 0) {
296 errstr(_("Cannot get name of new quotafile.\n"));
299 strcpy(namebuf, qfname);
300 sstrncat(namebuf, ".new", sizeof(namebuf));
301 if (rename(namebuf, qfname) < 0) {
302 errstr(_("Cannot rename new quotafile %s to name %s: %s\n"),
303 namebuf, qfname, strerror(errno));
310 static int convert_format(int type, struct mntent *mnt)
312 struct quota_handle *qo;
315 if (!(qo = init_io(mnt, type, infmt, IOI_OPENFILE))) {
316 errstr(_("Cannot open old format file for %ss on %s\n"),
317 type2name(type), mnt->mnt_dir);
320 if (!(qn = new_io(mnt, type, outfmt))) {
321 errstr(_("Cannot create file for %ss for new format on %s: %s\n"),
322 type2name(type), mnt->mnt_dir, strerror(errno));
326 if (qo->qh_ops->scan_dquots(qo, convert_dquot) >= 0) /* Conversion succeeded? */
327 ret = rename_file(type, outfmt, mnt);
335 static int convert_endian(int type, struct mntent *mnt)
341 if (get_qf_name(mnt, type, QF_VFSV0, NF_EXIST, &qfname) < 0)
343 if ((ofd = open(qfname, O_RDONLY)) < 0) {
344 errstr(_("Cannot open old quota file on %s: %s\n"), mnt->mnt_dir, strerror(errno));
349 if (endian_check_header(ofd, type) < 0) {
353 if (!(qn = new_io(mnt, type, QF_VFSV0))) {
354 errstr(_("Cannot create file for %ss for new format on %s: %s\n"),
355 type2name(type), mnt->mnt_dir, strerror(errno));
359 if (endian_load_info(ofd, type) < 0) {
364 ret = endian_scan_structures(ofd, type);
369 return rename_file(type, QF_VFSV0, mnt);
372 static int convert_file(int type, struct mntent *mnt)
376 return convert_format(type, mnt);
378 return convert_endian(type, mnt);
380 errstr(_("Unknown action should be performed.\n"));
384 int main(int argc, char **argv)
390 progname = basename(argv[0]);
392 parse_options(argc, argv);
393 init_kernel_interface();
394 if (init_mounts_scan(1, &mntpoint, 0) < 0)
396 if (!(mnt = get_next_mount())) {
401 ret |= convert_file(USRQUOTA, mnt);
403 ret |= convert_file(GRPQUOTA, mnt);