diff options
-rw-r--r-- | convertquota.c | 18 | ||||
-rw-r--r-- | quot.c | 22 | ||||
-rw-r--r-- | quot.h | 2 | ||||
-rw-r--r-- | quota.h | 2 | ||||
-rw-r--r-- | quotacheck.c | 130 | ||||
-rw-r--r-- | quotaio.c | 50 | ||||
-rw-r--r-- | quotaio.h | 7 | ||||
-rw-r--r-- | quotaon.c | 67 | ||||
-rw-r--r-- | quotaon.h | 4 | ||||
-rw-r--r-- | quotaon_xfs.c | 25 | ||||
-rw-r--r-- | quotasys.c | 307 | ||||
-rw-r--r-- | quotasys.h | 30 | ||||
-rw-r--r-- | rquota_server.c | 4 |
13 files changed, 349 insertions, 319 deletions
diff --git a/convertquota.c b/convertquota.c index 483abf1..7df948e 100644 --- a/convertquota.c +++ b/convertquota.c @@ -287,7 +287,7 @@ static int convert_dquot(struct dquot *dquot, char *name) return 0; } -static int rename_file(int type, int fmt, struct mntent *mnt) +static int rename_file(int type, int fmt, struct mount_entry *mnt) { char *qfname, namebuf[PATH_MAX]; int ret = 0; @@ -307,19 +307,19 @@ static int rename_file(int type, int fmt, struct mntent *mnt) return ret; } -static int convert_format(int type, struct mntent *mnt) +static int convert_format(int type, struct mount_entry *mnt) { struct quota_handle *qo; int ret = 0; if (!(qo = init_io(mnt, type, infmt, IOI_INITSCAN))) { errstr(_("Cannot open old format file for %ss on %s\n"), - type2name(type), mnt->mnt_dir); + type2name(type), mnt->me_dir); return -1; } if (!(qn = new_io(mnt, type, outfmt))) { errstr(_("Cannot create file for %ss for new format on %s: %s\n"), - type2name(type), mnt->mnt_dir, strerror(errno)); + type2name(type), mnt->me_dir, strerror(errno)); end_io(qo); return -1; } @@ -332,7 +332,7 @@ static int convert_format(int type, struct mntent *mnt) return ret; } -static int convert_endian(int type, struct mntent *mnt) +static int convert_endian(int type, struct mount_entry *mnt) { int ret = 0; int ofd; @@ -341,7 +341,7 @@ static int convert_endian(int type, struct mntent *mnt) if (get_qf_name(mnt, type, QF_VFSV0, NF_EXIST, &qfname) < 0) return -1; if ((ofd = open(qfname, O_RDONLY)) < 0) { - errstr(_("Cannot open old quota file on %s: %s\n"), mnt->mnt_dir, strerror(errno)); + errstr(_("Cannot open old quota file on %s: %s\n"), mnt->me_dir, strerror(errno)); free(qfname); return -1; } @@ -352,7 +352,7 @@ static int convert_endian(int type, struct mntent *mnt) } if (!(qn = new_io(mnt, type, QF_VFSV0))) { errstr(_("Cannot create file for %ss for new format on %s: %s\n"), - type2name(type), mnt->mnt_dir, strerror(errno)); + type2name(type), mnt->me_dir, strerror(errno)); close(ofd); return -1; } @@ -369,7 +369,7 @@ static int convert_endian(int type, struct mntent *mnt) return rename_file(type, QF_VFSV0, mnt); } -static int convert_file(int type, struct mntent *mnt) +static int convert_file(int type, struct mount_entry *mnt) { switch (action) { case ACT_FORMAT: @@ -383,7 +383,7 @@ static int convert_file(int type, struct mntent *mnt) int main(int argc, char **argv) { - struct mntent *mnt; + struct mount_entry *mnt; int ret = 0; gettexton(); @@ -73,8 +73,8 @@ char *progname; static void mounttable(void); static char *idname(__uint32_t, int); -static void report(const char *, char *, int); -static void creport(const char *, char *); +static void report(const char *, const char *, int); +static void creport(const char *, const char *); static void usage(void) { @@ -139,20 +139,20 @@ int main(int argc, char **argv) static void mounttable(void) { int doit = 0; - struct mntent *mntp; + struct mount_entry *mntp; while ((mntp = get_next_mount())) { /* Currently, only XFS is implemented... */ - if (strcmp(mntp->mnt_type, MNTTYPE_XFS) == 0) { - checkXFS(mntp->mnt_fsname, mntp->mnt_dir); + if (strcmp(mntp->me_type, MNTTYPE_XFS) == 0) { + checkXFS(mntp->me_devname, mntp->me_dir); doit = 1; } /* ...additional filesystems types here. */ if (doit) { - if (cflag) creport(mntp->mnt_fsname, mntp->mnt_dir); - if (!cflag && uflag) report(mntp->mnt_fsname, mntp->mnt_dir, 0); - if (!cflag && gflag) report(mntp->mnt_fsname, mntp->mnt_dir, 1); + if (cflag) creport(mntp->me_devname, mntp->me_dir); + if (!cflag && uflag) report(mntp->me_devname, mntp->me_dir, 0); + if (!cflag && gflag) report(mntp->me_devname, mntp->me_dir, 1); } } } @@ -170,7 +170,7 @@ static int qcmp(du_t * p1, du_t * p2) return 0; } -static void creport(const char *file, char *fsdir) +static void creport(const char *file, const char *fsdir) { int i; __uint64_t t = 0; @@ -188,7 +188,7 @@ static void creport(const char *file, char *fsdir) (unsigned long long) (overflow + t)); } -static void report(const char *file, char *fsdir, int type) +static void report(const char *file, const char *fsdir, int type) { du_t *dp; @@ -334,7 +334,7 @@ static void acctXFS(xfs_bstat_t *p) } } -static void checkXFS(const char *file, char *fsdir) +static void checkXFS(const char *file, const char *fsdir) { xfs_fsop_bulkreq_t bulkreq; __u64 last = 0; @@ -106,7 +106,7 @@ typedef struct xfs_fsop_bulkreq { #endif #define NBSTAT 4069 /* XFS bulkstat inodes */ -static void checkXFS(const char *file, char *fsdir); +static void checkXFS(const char *file, const char *fsdir); /* * === End of XFS specific types and definitions === @@ -95,6 +95,8 @@ struct if_dqblk { #define IIF_FLAGS 4 #define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) +#define DQF_SYS_FILE 0x10000 /* Quota stored in a system file */ + struct if_dqinfo { u_int64_t dqi_bgrace; u_int64_t dqi_igrace; diff --git a/quotacheck.c b/quotacheck.c index 129f838..2da562b 100644 --- a/quotacheck.c +++ b/quotacheck.c @@ -243,7 +243,7 @@ static void remove_list(void) } /* Get size used by file */ -static loff_t getqsize(char *fname, struct stat *st) +static loff_t getqsize(const char *fname, struct stat *st) { static char ioctl_fail_warn; int fd; @@ -269,7 +269,7 @@ static loff_t getqsize(char *fname, struct stat *st) /* * Show a blitting cursor as means of visual progress indicator. */ -static inline void blit(char *msg) +static inline void blit(const char *msg) { static int bitc = 0; static const char bits[] = "|/-\\"; @@ -413,7 +413,7 @@ static void parse_options(int argcnt, char **argstr) } #if defined(EXT2_DIRECT) -static int ext2_direct_scan(char *device) +static int ext2_direct_scan(const char *device) { ext2_ino_t i_num; ext2_filsys fs; @@ -490,7 +490,7 @@ static int ext2_direct_scan(char *device) * of the files to the appropriate quotas. When we find a dir we recursivly call * ourself to scan that dir. */ -static int scan_dir(char *pathname) +static int scan_dir(const char *pathname) { struct dirs *dir_stack = NULL; struct dirs *new_dir; @@ -613,18 +613,18 @@ int ask_yn(char *q, int def) } /* Do checks and buffer quota file into memory */ -static int process_file(struct mntent *mnt, int type) +static int process_file(struct mount_entry *mnt, int type) { char *qfname = NULL; int fd = -1, ret; debug(FL_DEBUG, _("Going to check %s quota file of %s\n"), type2name(type), - mnt->mnt_dir); + mnt->me_dir); - if (kern_quota_on(mnt->mnt_fsname, type, cfmt) >= 0) { /* Is quota enabled? */ + if (kern_quota_on(mnt, type, cfmt) >= 0) { /* Is quota enabled? */ if (!(flags & FL_FORCE)) { if (flags & FL_INTERACTIVE) { - printf(_("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n"), type2name(type), mnt->mnt_dir); + printf(_("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n"), type2name(type), mnt->me_dir); if (!ask_yn(_("Should I continue"), 0)) { printf(_("As you wish... Canceling check of this file.\n")); return -1; @@ -633,17 +633,17 @@ static int process_file(struct mntent *mnt, int type) else die(6, _("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n\ Please turn quotas off or use -f to force checking.\n"), - type2name(type), mnt->mnt_dir); + type2name(type), mnt->me_dir); } /* At least sync quotas so damage will be smaller */ if (quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type), - mnt->mnt_fsname, 0, NULL) < 0) - die(4, _("Error while syncing quotas on %s: %s\n"), mnt->mnt_fsname, strerror(errno)); + mnt->me_devname, 0, NULL) < 0) + die(4, _("Error while syncing quotas on %s: %s\n"), mnt->me_devname, strerror(errno)); } if (!(flags & FL_NEWFILE)) { /* Need to buffer file? */ if (get_qf_name(mnt, type, cfmt, 0, &qfname) < 0) { - errstr(_("Cannot get quotafile name for %s\n"), mnt->mnt_fsname); + errstr(_("Cannot get quotafile name for %s\n"), mnt->me_devname); return -1; } if ((fd = open(qfname, O_RDONLY)) < 0) { @@ -675,7 +675,7 @@ Please turn quotas off or use -f to force checking.\n"), } /* Backup old quotafile and rename new one to right name */ -static int rename_files(struct mntent *mnt, int type) +static int rename_files(struct mount_entry *mnt, int type) { char *filename, newfilename[PATH_MAX]; struct stat st; @@ -690,7 +690,7 @@ static int rename_files(struct mntent *mnt, int type) debug(FL_DEBUG, _("Renaming new files to proper names.\n")); if (get_qf_name(mnt, type, cfmt, 0, &filename) < 0) - die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->mnt_dir); + die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->me_dir); if (stat(filename, &st) < 0) { /* File doesn't exist? */ if (errno == ENOENT) { debug(FL_DEBUG | FL_VERBOSE, _("Old file not found.\n")); @@ -781,7 +781,7 @@ rename_new: * quota file. As quotafiles doesn't account to quotas we don't have to * bother about accounting new blocks for quota file */ -static int dump_to_file(struct mntent *mnt, int type) +static int dump_to_file(struct mount_entry *mnt, int type) { struct dquot *dquot; uint i; @@ -828,16 +828,16 @@ static int dump_to_file(struct mntent *mnt, int type) return -1; } debug(FL_DEBUG, _("Data dumped.\n")); - if (kern_quota_on(mnt->mnt_fsname, type, cfmt) >= 0) { /* Quota turned on? */ + if (kern_quota_on(mnt, type, cfmt) >= 0) { /* Quota turned on? */ char *filename; if (get_qf_name(mnt, type, cfmt, NF_FORMAT, &filename) < 0) - errstr(_("Cannot find checked quota file for %ss on %s!\n"), type2name(type), mnt->mnt_fsname); + errstr(_("Cannot find checked quota file for %ss on %s!\n"), type2name(type), mnt->me_devname); else { if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type), - mnt->mnt_fsname, 0, NULL) < 0) + mnt->me_devname, 0, NULL) < 0) errstr(_("Cannot turn %s quotas off on %s: %s\nKernel won't know about changes quotacheck did.\n"), - type2name(type), mnt->mnt_fsname, strerror(errno)); + type2name(type), mnt->me_devname, strerror(errno)); else { int ret; @@ -845,12 +845,12 @@ static int dump_to_file(struct mntent *mnt, int type) rename_files(mnt, type); if (kernel_iface == IFACE_GENERIC) - ret = quotactl(QCMD(Q_QUOTAON, type), mnt->mnt_fsname, util2kernfmt(cfmt), filename); + ret = quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, util2kernfmt(cfmt), filename); else - ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->mnt_fsname, 0, filename); + ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, 0, filename); if (ret < 0) errstr(_("Cannot turn %s quotas on on %s: %s\nKernel won't know about changes quotacheck did.\n"), - type2name(type), mnt->mnt_fsname, strerror(errno)); + type2name(type), mnt->me_devname, strerror(errno)); } free(filename); } @@ -863,7 +863,7 @@ static int dump_to_file(struct mntent *mnt, int type) /* Substract space used by old quota file from usage. * Return non-zero in case of failure, zero otherwise. */ -static int sub_quota_file(struct mntent *mnt, int qtype, int ftype) +static int sub_quota_file(struct mount_entry *mnt, int qtype, int ftype) { char *filename; struct stat st; @@ -901,16 +901,16 @@ static int sub_quota_file(struct mntent *mnt, int qtype, int ftype) /* Buffer quotafile, run filesystem scan, dump quotafiles. * Return non-zero value in case of failure, zero otherwise. */ -static int check_dir(struct mntent *mnt) +static int check_dir(struct mount_entry *mnt) { struct stat st; int remounted = 0; int failed = 0; - if (lstat(mnt->mnt_dir, &st) < 0) - die(2, _("Cannot stat mountpoint %s: %s\n"), mnt->mnt_dir, strerror(errno)); + if (lstat(mnt->me_dir, &st) < 0) + die(2, _("Cannot stat mountpoint %s: %s\n"), mnt->me_dir, strerror(errno)); if (!S_ISDIR(st.st_mode)) - die(2, _("Mountpoint %s is not a directory?!\n"), mnt->mnt_dir); + die(2, _("Mountpoint %s is not a directory?!\n"), mnt->me_dir); cur_dev = st.st_dev; files_done = dirs_done = 0; /* @@ -932,10 +932,10 @@ static int check_dir(struct mntent *mnt) if (!(flags & FL_NOREMOUNT)) { /* Now we try to remount fs read-only to prevent races when scanning filesystem */ if (mount - (NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, + (NULL, mnt->me_dir, mnt->me_type, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL) < 0 && !(flags & FL_FORCEREMOUNT)) { if (flags & FL_INTERACTIVE) { - printf(_("Cannot remount filesystem mounted on %s read-only. Counted values might not be right.\n"), mnt->mnt_dir); + printf(_("Cannot remount filesystem mounted on %s read-only. Counted values might not be right.\n"), mnt->me_dir); if (!ask_yn(_("Should I continue"), 0)) { printf(_("As you wish... Canceling check of this file.\n")); failed = -1; @@ -944,7 +944,7 @@ static int check_dir(struct mntent *mnt) } else { errstr(_("Cannot remount filesystem mounted on %s read-only so counted values might not be right.\n\ -Please stop all programs writing to filesystem or use -m flag to force checking.\n"), mnt->mnt_dir); +Please stop all programs writing to filesystem or use -m flag to force checking.\n"), mnt->me_dir); failed = -1; goto out; } @@ -954,19 +954,19 @@ Please stop all programs writing to filesystem or use -m flag to force checking. debug(FL_DEBUG, _("Filesystem remounted read-only\n")); } start_scan: - debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->mnt_fsname, mnt->mnt_dir); + debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->me_devname, mnt->me_dir); #if defined(EXT2_DIRECT) - if (!strcmp(mnt->mnt_type, MNTTYPE_EXT2) || !strcmp(mnt->mnt_type, MNTTYPE_EXT3) || !strcmp(mnt->mnt_type, MNTTYPE_NEXT3)) { - if ((failed = ext2_direct_scan(mnt->mnt_fsname)) < 0) + if (!strcmp(mnt->me_type, MNTTYPE_EXT2) || !strcmp(mnt->me_type, MNTTYPE_EXT3) || !strcmp(mnt->me_type, MNTTYPE_NEXT3)) { + if ((failed = ext2_direct_scan(mnt->me_devname)) < 0) goto out; } else { #else - if (mnt->mnt_dir) { + if (mnt->me_dir) { #endif if (flags & FL_VERYVERBOSE) putchar('\n'); - if ((failed = scan_dir(mnt->mnt_dir)) < 0) + if ((failed = scan_dir(mnt->me_dir)) < 0) goto out; } dirs_done++; @@ -983,8 +983,8 @@ start_scan: debug(FL_DEBUG | FL_VERBOSE, _("Checked %d directories and %d files\n"), dirs_done, files_done); if (remounted) { - if (mount(NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT, NULL) < 0) - die(4, _("Cannot remount filesystem %s read-write. cannot write new quota files.\n"), mnt->mnt_dir); + if (mount(NULL, mnt->me_dir, mnt->me_type, MS_MGC_VAL | MS_REMOUNT, NULL) < 0) + die(4, _("Cannot remount filesystem %s read-write. cannot write new quota files.\n"), mnt->me_dir); debug(FL_DEBUG, _("Filesystem remounted RW.\n")); } if (ucheck) @@ -997,7 +997,7 @@ out: } /* Detect quota format from filename of present files */ -static int detect_filename_format(struct mntent *mnt, int type) +static int detect_filename_format(struct mount_entry *mnt, int type) { char *option; struct stat statbuf; @@ -1005,36 +1005,36 @@ static int detect_filename_format(struct mntent *mnt, int type) int journal = 0; int fmt; - if (strcmp(mnt->mnt_type, MNTTYPE_XFS) == 0 || - strcmp(mnt->mnt_type, MNTTYPE_GFS2) == 0) + if (strcmp(mnt->me_type, MNTTYPE_XFS) == 0 || + strcmp(mnt->me_type, MNTTYPE_GFS2) == 0) return QF_XFS; if (type == USRQUOTA) { - if ((option = hasmntopt(mnt, MNTOPT_USRQUOTA))) + if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_USRQUOTA))) option += strlen(MNTOPT_USRQUOTA); - else if (hasmntopt(mnt, MNTOPT_USRJQUOTA)) { + else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_USRJQUOTA))) { journal = 1; option += strlen(MNTOPT_USRJQUOTA); } - else if ((option = hasmntopt(mnt, MNTOPT_QUOTA))) + else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_QUOTA))) option += strlen(MNTOPT_QUOTA); } else { - if ((option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) + if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPQUOTA))) option += strlen(MNTOPT_GRPQUOTA); - else if (hasmntopt(mnt, MNTOPT_GRPJQUOTA)) { + else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPJQUOTA))) { journal = 1; option += strlen(MNTOPT_GRPJQUOTA); } } if (!option) - die(2, _("Cannot find quota option on filesystem %s with quotas!\n"), mnt->mnt_dir); + die(2, _("Cannot find quota option on filesystem %s with quotas!\n"), mnt->me_dir); if (journal) { char fmtbuf[64], *space; - if (!(option = hasmntopt(mnt, MNTOPT_JQFMT))) { + if (!(option = str_hasmntopt(mnt->me_opts, MNTOPT_JQFMT))) { jquota_err: - errstr(_("Cannot detect quota format for journalled quota on %s\n"), mnt->mnt_dir); + errstr(_("Cannot detect quota format for journalled quota on %s\n"), mnt->me_dir); return -1; } option += strlen(MNTOPT_JQFMT); @@ -1053,7 +1053,7 @@ jquota_err: } else if (*option == '=') /* If the file name is specified we can't detect quota format from it... */ return -1; - snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSV0], extensions[type]); + snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->me_dir, basenames[QF_VFSV0], extensions[type]); if (!stat(namebuf, &statbuf)) { int fd = open(namebuf, O_RDONLY); if (fd < 0) @@ -1065,7 +1065,7 @@ jquota_err: } if (errno != ENOENT) return -1; - snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSOLD], extensions[type]); + snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->me_dir, basenames[QF_VFSOLD], extensions[type]); if (!stat(namebuf, &statbuf)) return QF_VFSOLD; /* Old quota files don't exist, just create VFSv0 format if available */ @@ -1128,7 +1128,7 @@ warn: /* Return 0 in case of success, non-zero otherwise. */ static int check_all(void) { - struct mntent *mnt; + struct mount_entry *mnt; int checked = 0; static int warned; int failed = 0; @@ -1136,18 +1136,18 @@ static int check_all(void) if (init_mounts_scan((flags & FL_ALL) ? 0 : 1, &mntpoint, 0) < 0) die(2, _("Cannot initialize mountpoint scan.\n")); while ((mnt = get_next_mount())) { - if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->mnt_dir, "/")) + if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->me_dir, "/")) continue; - if (!compatible_fs_qfmt(mnt->mnt_type, fmt)) { - debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->mnt_fsname, mnt->mnt_dir); + if (!compatible_fs_qfmt(mnt->me_type, fmt)) { + debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->me_devname, mnt->me_dir); continue; } cfmt = fmt; - if (uwant && hasquota(mnt, USRQUOTA, 0)) + if (uwant && me_hasquota(mnt, USRQUOTA)) ucheck = 1; else ucheck = 0; - if (gwant && hasquota(mnt, GRPQUOTA, 0)) + if (gwant && me_hasquota(mnt, GRPQUOTA)) gcheck = 1; else gcheck = 0; @@ -1157,20 +1157,22 @@ static int check_all(void) cfmt = detect_filename_format(mnt, ucheck ? USRQUOTA : GRPQUOTA); if (cfmt == -1) { errstr(_("Cannot guess format from filename on %s. Please specify format on commandline.\n"), - mnt->mnt_fsname); + mnt->me_devname); failed = -1; continue; } debug(FL_DEBUG, _("Detected quota format %s\n"), fmt2name(cfmt)); } - if (flags & FL_VERBOSE && !hasmntopt(mnt, MNTOPT_USRJQUOTA) && - !hasmntopt(mnt, MNTOPT_GRPJQUOTA) && !warned && - (!strcmp(mnt->mnt_type, MNTTYPE_EXT3) || - !strcmp(mnt->mnt_type, MNTTYPE_EXT4) || - !strcmp(mnt->mnt_type, MNTTYPE_NEXT3) || - !strcmp(mnt->mnt_type, MNTTYPE_EXT4DEV) || - !strcmp(mnt->mnt_type, MNTTYPE_REISER))) { + if (flags & FL_VERBOSE && + !str_hasmntopt(mnt->me_opts, MNTOPT_USRJQUOTA) && + !str_hasmntopt(mnt->me_opts, MNTOPT_GRPJQUOTA) && + !warned && + (!strcmp(mnt->me_type, MNTTYPE_EXT3) || + !strcmp(mnt->me_type, MNTTYPE_EXT4) || + !strcmp(mnt->me_type, MNTTYPE_NEXT3) || + !strcmp(mnt->me_type, MNTTYPE_EXT4DEV) || + !strcmp(mnt->me_type, MNTTYPE_REISER))) { warned = 1; warn_if_jquota_supported(); } @@ -37,19 +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) @@ -57,11 +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); - sstrncpy(h->qh_dir, mnt->mnt_dir, PATH_MAX); - 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; @@ -82,8 +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? */ - !strcmp(mnt->mnt_type, MNTTYPE_GFS2)) { /* 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; @@ -101,14 +97,14 @@ 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; @@ -193,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); @@ -218,16 +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)); - sstrncpy(h->qh_fstype, mnt->mnt_type, MAX_FSTYPE_LEN); - sstrncpy(h->qh_dir, mnt->mnt_dir, PATH_MAX); - 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)); @@ -40,6 +40,7 @@ #define QF_RPC 3 /* RPC should be used on given filesystem */ #define QF_XFS 4 /* XFS quota format */ #define QF_META 5 /* Quota files are hidden, we don't care about the format */ +#define QF_VFSUNKNOWN 6 /* Some VFS quotas, we didn't detect particular format yet */ static inline int is_tree_qfmt(int fmt) { @@ -164,11 +165,13 @@ static inline void mark_quotafile_info_dirty(struct quota_handle *h) #define QIO_ENABLED(h) ((h)->qh_io_flags & IOFL_QUOTAON) #define QIO_RO(h) ((h)->qh_io_flags & IOFL_RO) +struct mount_entry; + /* Check quota format used on specified medium and initialize it */ -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); /* 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); /* Close quotafile */ int end_io(struct quota_handle *h); @@ -197,7 +197,7 @@ static int quotarsquashonoff(const char *quotadev, int type, int flags) /* * Enable/disable VFS quota on given filesystem */ -static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, int fmt, int flags) +static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafile, int type, int fmt, int flags) { int qcmd, kqf; @@ -239,42 +239,31 @@ static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, /* * Enable/disable quota/rootsquash on given filesystem (version 1) */ -static int v1_newstate(struct mntent *mnt, int type, char *file, int flags, int fmt) +static int v1_newstate(struct mount_entry *mnt, int type, char *file, int flags, int fmt) { int errs = 0; - const char *dev = get_device_name(mnt->mnt_fsname); - if (!dev) - return 1; - if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH)) - errs += quotarsquashonoff(dev, type, flags); - errs += quotaonoff((char *)dev, mnt->mnt_dir, file, type, QF_VFSOLD, flags); - if ((flags & STATEFLAG_ON) && hasmntopt(mnt, MNTOPT_RSQUASH)) - errs += quotarsquashonoff(dev, type, flags); - free((char *)dev); + if ((flags & STATEFLAG_OFF) && str_hasmntopt(mnt->me_opts, MNTOPT_RSQUASH)) + errs += quotarsquashonoff(mnt->me_devname, type, flags); + errs += quotaonoff(mnt->me_devname, mnt->me_dir, file, type, QF_VFSOLD, flags); + if ((flags & STATEFLAG_ON) && str_hasmntopt(mnt->me_opts, MNTOPT_RSQUASH)) + errs += quotarsquashonoff(mnt->me_devname, type, flags); return errs; } /* * Enable/disable quota on given filesystem (generic VFS quota) */ -static int v2_newstate(struct mntent *mnt, int type, char *file, int flags, int fmt) +static int v2_newstate(struct mount_entry *mnt, int type, char *file, int flags, int fmt) { - const char *dev = get_device_name(mnt->mnt_fsname); - int errs = 0; - - if (!dev) - return 1; - errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, fmt, flags); - free((char *)dev); - return errs; + return quotaonoff(mnt->me_devname, mnt->me_dir, file, type, fmt, flags); } /* * For both VFS quota formats, need to pass in the quota file; * for XFS quota manager, pass on the -x command line option. */ -static int newstate(struct mntent *mnt, int type, char *extra) +static int newstate(struct mount_entry *mnt, int type, char *extra) { int sflags, ret = 0; @@ -282,26 +271,24 @@ static int newstate(struct mntent *mnt, int type, char *extra) if (flags & FL_ALL) sflags |= STATEFLAG_ALL; - if (!strcmp(mnt->mnt_type, MNTTYPE_GFS2)) { + if (!strcmp(mnt->me_type, MNTTYPE_GFS2)) { errstr(_("Cannot change state of GFS2 quota.\n")); return 1; - } else if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */ + } else if (!strcmp(mnt->me_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */ if (!kern_qfmt_supp(QF_XFS)) { errstr(_("Cannot change state of XFS quota. It's not compiled in kernel.\n")); return 1; } ret = xfs_newstate(mnt, type, extra, sflags); } - else if (meta_qf_fstype(mnt->mnt_type)) { - if (!hasquota(mnt, type, 0)) - return 0; + else if (mnt->me_qfmt[type] == QF_META) { /* Must be non-empty because empty path is always invalid. */ ret = v2_newstate(mnt, type, ".", sflags, QF_VFSV0); } else { int usefmt; - if (!hasquota(mnt, type, 0)) + if (!me_hasquota(mnt, type)) return 0; if (fmt == -1) { if (get_qf_name(mnt, type, QF_VFSV0, @@ -314,12 +301,12 @@ static int newstate(struct mntent *mnt, int type, char *extra) NF_FORMAT, &extra) >= 0) usefmt = QF_VFSOLD; else { - errstr(_("Cannot find quota file on %s [%s] to turn quotas on/off.\n"), mnt->mnt_dir, mnt->mnt_fsname); + errstr(_("Cannot find quota file on %s [%s] to turn quotas on/off.\n"), mnt->me_dir, mnt->me_devname); return 1; } } else { if (get_qf_name(mnt, type, fmt, NF_FORMAT, &extra) < 0) { - errstr(_("Quota file on %s [%s] does not exist or has wrong format.\n"), mnt->mnt_dir, mnt->mnt_fsname); + errstr(_("Quota file on %s [%s] does not exist or has wrong format.\n"), mnt->me_dir, mnt->me_devname); return 1; } usefmt = fmt; @@ -334,23 +321,23 @@ static int newstate(struct mntent *mnt, int type, char *extra) } /* Print state of quota (on/off) */ -static int print_state(struct mntent *mnt, int type) +static int print_state(struct mount_entry *mnt, int type) { int on = 0; - if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) || - !strcmp(mnt->mnt_type, MNTTYPE_GFS2)) { + if (!strcmp(mnt->me_type, MNTTYPE_XFS) || + !strcmp(mnt->me_type, MNTTYPE_GFS2)) { if (kern_qfmt_supp(QF_XFS)) - on = kern_quota_on(mnt->mnt_fsname, type, QF_XFS) != -1; + on = kern_quota_on(mnt, type, QF_XFS) != -1; } else if (kernel_iface == IFACE_GENERIC) - on = kern_quota_on(mnt->mnt_fsname, type, -1) != -1; + on = kern_quota_on(mnt, type, -1) != -1; else if (kern_qfmt_supp(QF_VFSV0)) - on = kern_quota_on(mnt->mnt_fsname, type, QF_VFSV0) != -1; + on = kern_quota_on(mnt, type, QF_VFSV0) != -1; else if (kern_qfmt_supp(QF_VFSOLD)) - on = kern_quota_on(mnt->mnt_fsname, type, QF_VFSOLD) != -1; + on = kern_quota_on(mnt, type, QF_VFSOLD) != -1; - printf(_("%s quota on %s (%s) is %s\n"), type2name(type), mnt->mnt_dir, mnt->mnt_fsname, + printf(_("%s quota on %s (%s) is %s\n"), type2name(type), mnt->me_dir, mnt->me_devname, on ? _("on") : _("off")); return on; @@ -358,7 +345,7 @@ static int print_state(struct mntent *mnt, int type) int main(int argc, char **argv) { - struct mntent *mnt; + struct mount_entry *mnt; int errs = 0; gettexton(); @@ -380,9 +367,9 @@ int main(int argc, char **argv) if (init_mounts_scan(mntcnt, mntpoints, MS_XFS_DISABLED | MS_LOCALONLY) < 0) return 1; while ((mnt = get_next_mount())) { - if (nfs_fstype(mnt->mnt_type)) { + if (nfs_fstype(mnt->me_type)) { if (!(flags & FL_ALL)) - errstr(_("%s: Quota cannot be turned on on NFS filesystem\n"), mnt->mnt_fsname); + errstr(_("%s: Quota cannot be turned on on NFS filesystem\n"), mnt->me_devname); continue; } @@ -14,6 +14,6 @@ #define STATEFLAG_OFF 0x02 #define STATEFLAG_ALL 0x04 -typedef int (newstate_t) (struct mntent * mnt, int type, char *file, int flags); -extern int xfs_newstate(struct mntent *mnt, int type, char *file, int flags); +typedef int (newstate_t) (struct mount_entry * mnt, int type, char *file, int flags); +extern int xfs_newstate(struct mount_entry *mnt, int type, char *file, int flags); extern int pinfo(char *fmt, ...); diff --git a/quotaon_xfs.c b/quotaon_xfs.c index 0028a88..a271e71 100644 --- a/quotaon_xfs.c +++ b/quotaon_xfs.c @@ -22,7 +22,7 @@ * Ensure we don't attempt to go into a dodgey state. */ -static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothack, int xopts) +static int xfs_state_check(int qcmd, int type, int flags, const char *dev, int roothack, int xopts) { struct xfs_mem_dqinfo info; int state; @@ -132,7 +132,7 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac return -1; } -static int xfs_onoff(char *dev, int type, int flags, int roothack, int xopts) +static int xfs_onoff(const char *dev, int type, int flags, int roothack, int xopts) { int qoff, qcmd, check; @@ -153,7 +153,7 @@ static int xfs_onoff(char *dev, int type, int flags, int roothack, int xopts) return 0; } -static int xfs_delete(char *dev, int type, int flags, int roothack, int xopts) +static int xfs_delete(const char *dev, int type, int flags, int roothack, int xopts) { int qcmd, check; @@ -178,15 +178,11 @@ static int xfs_delete(char *dev, int type, int flags, int roothack, int xopts) * root filesystem. * We are passed in the new requested state through "type" & "xarg". */ -int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags) +int xfs_newstate(struct mount_entry *mnt, int type, char *xarg, int flags) { int err = 1; int xopts = 0; int roothack = 0; - const char *dev = get_device_name(mnt->mnt_fsname); - - if (!dev) - return err; #ifdef XFS_ROOTHACK /* @@ -194,11 +190,11 @@ int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags) * hack to allow enabling quota on the root filesystem without * having to specify it at mount time. */ - if ((strcmp(mnt->mnt_dir, "/") == 0)) { + if ((strcmp(mnt->me_dir, "/") == 0)) { struct xfs_mem_dqinfo info; u_int16_t sbflags = 0; - if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) + if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, 0, (void *)&info)) sbflags = (info.qs_flags & 0xff00) >> 8; if ((type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) && @@ -210,22 +206,21 @@ int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags) if (xarg == NULL) { /* only enfd on/off */ xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; - err = xfs_onoff((char *)dev, type, flags, roothack, xopts); + err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts); } else if (strcmp(xarg, "account") == 0) { xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; - err = xfs_onoff((char *)dev, type, flags, roothack, xopts); + err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts); } else if (strcmp(xarg, "enforce") == 0) { xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; - err = xfs_onoff((char *)dev, type, flags, roothack, xopts); + err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts); } else if (strcmp(xarg, "delete") == 0) { xopts |= (type == USRQUOTA) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA; - err = xfs_delete((char *)dev, type, flags, roothack, xopts); + err = xfs_delete(mnt->me_devname, type, flags, roothack, xopts); } else die(1, _("Invalid argument \"%s\"\n"), xarg); - free((char *)dev); return err; } @@ -242,7 +242,7 @@ char *fmt2name(int fmt) /* * Convert kernel to utility quota format number */ -int kern2utilfmt(int kernfmt) +static int kern2utilfmt(int kernfmt) { switch (kernfmt) { case QFMT_VFS_OLD: @@ -385,41 +385,27 @@ void number2str(unsigned long long num, char *buf, int format) } /* + * Wrappers for mount options processing functions + */ + +/* * Check for XFS filesystem with quota accounting enabled */ -static int hasxfsquota(struct mntent *mnt, int type, int flags) +static int hasxfsquota(const char *dev, struct mntent *mnt, int type, int flags) { - int ret = 0; u_int16_t sbflags; struct xfs_mem_dqinfo info; - const char *dev; - char *opt, *endopt; if (flags & MS_XFS_DISABLED) - return 1; - - dev = get_device_name(mnt->mnt_fsname); - if (!dev) - return 0; - /* Loopback mounted device with a loopback device in the arguments? */ - if ((opt = hasmntopt(mnt, MNTOPT_LOOP)) && (opt = strchr(opt, '='))) { - free((char *)dev); - endopt = strchr(opt+1, ','); - if (!endopt) - dev = strdup(opt+1); - else - dev = strndup(opt+1, endopt-opt-1); - if (!dev) - return 0; - } + return QF_XFS; memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) { sbflags = (info.qs_flags & 0xff00) >> 8; if (type == USRQUOTA && (info.qs_flags & XFS_QUOTA_UDQ_ACCT)) - ret = 1; + return QF_XFS; else if (type == GRPQUOTA && (info.qs_flags & XFS_QUOTA_GDQ_ACCT)) - ret = 1; + return QF_XFS; #ifdef XFS_ROOTHACK /* * Old XFS filesystems (up to XFS 1.2 / Linux 2.5.47) had a @@ -427,21 +413,58 @@ static int hasxfsquota(struct mntent *mnt, int type, int flags) * having to specify it at mount time. */ else if (strcmp(mnt->mnt_dir, "/")) - ret = 0; + return QF_ERROR; else if (type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) - ret = 1; + return QF_XFS; else if (type == GRPQUOTA && (sbflags & XFS_QUOTA_GDQ_ACCT)) - ret = 1; + return QF_XFS; #endif /* XFS_ROOTHACK */ } - free((char *)dev); - return ret; + + return QF_ERROR; +} + +static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int flags) +{ + uint32_t fmt; + + if (!quotactl(QCMD(Q_GETFMT, type), dev, 0, (void *)&fmt)) + return QF_META; + return QF_ERROR; +} + +/* Return pointer to given mount option in mount option string */ +char *str_hasmntopt(const char *optstring, const char *opt) +{ + const char *p = optstring; + const char *s; + int len = strlen(opt); + + do { + s = p; + while (*p && *p != ',' && *p != '=') + p++; + /* Found option? */ + if (p - s == len && !strncmp(s, opt, len)) + return (char *)s; + /* Skip mount option argument if there's any */ + if (*p == '=') { + p++; + while (*p && *p != ',') + p++; + } + /* Skip separating ',' */ + if (*p) + p++; + } while (*p); + + return NULL; } /* Return if given option has nonempty argument */ -char *hasmntoptarg(struct mntent *mnt, char *opt) +static char *hasmntoptarg(const char *optstring, const char *opt) { - char *p = hasmntopt(mnt, opt); + char *p = str_hasmntopt(optstring, opt); if (!p) return NULL; @@ -451,27 +474,52 @@ char *hasmntoptarg(struct mntent *mnt, char *opt) return NULL; } +/* Copy out mount option argument to a buffer */ +static void copy_mntoptarg(char *buf, const char *optarg, int buflen) +{ + char *sep = strchr(optarg, ','); + + if (!sep) + sstrncpy(buf, optarg, min(buflen, strlen(optarg) + 1)); + else + sstrncpy(buf, optarg, min(buflen, sep - optarg + 1)); +} + /* * Check to see if a particular quota is to be enabled (filesystem mounted with proper option) */ -int hasquota(struct mntent *mnt, int type, int flags) +static int hasquota(const char *dev, struct mntent *mnt, int type, int flags) { - if (hasmntopt(mnt, MNTOPT_NOQUOTA)) - return 0; - if (!strcmp(mnt->mnt_type, MNTTYPE_GFS2) || !strcmp(mnt->mnt_type, MNTTYPE_XFS)) - return hasxfsquota(mnt, type, flags); - if (nfs_fstype(mnt->mnt_type)) /* NFS always has quota or better there is no good way how to detect it */ - return 1; - - if ((type == USRQUOTA) && (hasmntopt(mnt, MNTOPT_USRQUOTA) || hasmntoptarg(mnt, MNTOPT_USRJQUOTA))) - return 1; - if ((type == GRPQUOTA) && (hasmntopt(mnt, MNTOPT_GRPQUOTA) || hasmntoptarg(mnt, MNTOPT_GRPJQUOTA))) - return 1; + return hasxfsquota(dev, mnt, type, flags); + if (!strcmp(mnt->mnt_type, MNTTYPE_OCFS2)) + return hasvfsmetaquota(dev, mnt, type, flags); + /* + * For ext4 we check whether it has quota in system files and if not, + * we fall back on checking standard quotas. Furthermore we cannot use + * standard GETFMT quotactl because that does not distinguish between + * quota in system file and quota in ordinary file. + */ + if (!strcmp(mnt->mnt_type, MNTTYPE_EXT4)) { + struct if_dqinfo kinfo; + + if (quotactl(QCMD(Q_GETINFO, type), dev, 0, (void *)&kinfo) == 0) { + if (kinfo.dqi_flags & DQF_SYS_FILE) + return QF_META; + } + } + /* NFS always has quota or better there is no good way how to detect it */ + if (nfs_fstype(mnt->mnt_type)) + return QF_RPC; + + if ((type == USRQUOTA) && (hasmntopt(mnt, MNTOPT_USRQUOTA) || hasmntoptarg(mnt->mnt_opts, MNTOPT_USRJQUOTA))) + return QF_VFSUNKNOWN; + if ((type == GRPQUOTA) && (hasmntopt(mnt, MNTOPT_GRPQUOTA) || hasmntoptarg(mnt->mnt_opts, MNTOPT_GRPJQUOTA))) + return QF_VFSUNKNOWN; if ((type == USRQUOTA) && hasmntopt(mnt, MNTOPT_QUOTA)) - return 1; - return 0; + return QF_VFSUNKNOWN; + return -1; } /* Check whether quotafile for given format exists - return its name in namebuf */ @@ -513,36 +561,36 @@ static int check_fmtfile_ok(char *name, int type, int fmt, int flags) * otherwise return -1. * Note that formats without quotafile *must* be detected prior to calling this function */ -int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename) +int get_qf_name(struct mount_entry *mnt, int type, int fmt, int flags, char **filename) { char *option, *pathname, has_quota_file_definition = 0; char qfullname[PATH_MAX]; qfullname[0] = 0; - if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_USRQUOTA))) { + if (type == USRQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_USRQUOTA))) { if (*(pathname = option + strlen(MNTOPT_USRQUOTA)) == '=') has_quota_file_definition = 1; } - else if (type == USRQUOTA && (option = hasmntoptarg(mnt, MNTOPT_USRJQUOTA))) { + else if (type == USRQUOTA && (option = hasmntoptarg(mnt->me_opts, MNTOPT_USRJQUOTA))) { pathname = option; has_quota_file_definition = 1; - sstrncpy(qfullname, mnt->mnt_dir, sizeof(qfullname)); + sstrncpy(qfullname, mnt->me_dir, sizeof(qfullname)); sstrncat(qfullname, "/", sizeof(qfullname)); } - else if (type == GRPQUOTA && (option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) { + else if (type == GRPQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPQUOTA))) { pathname = option + strlen(MNTOPT_GRPQUOTA); if (*pathname == '=') { has_quota_file_definition = 1; pathname++; } } - else if (type == GRPQUOTA && (option = hasmntoptarg(mnt, MNTOPT_GRPJQUOTA))) { + else if (type == GRPQUOTA && (option = hasmntoptarg(mnt->me_opts, MNTOPT_GRPJQUOTA))) { pathname = option; has_quota_file_definition = 1; - sstrncpy(qfullname, mnt->mnt_dir, sizeof(qfullname)); + sstrncpy(qfullname, mnt->me_dir, sizeof(qfullname)); sstrncat(qfullname, "/", sizeof(qfullname)); } - else if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_QUOTA))) { + else if (type == USRQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_QUOTA))) { pathname = option + strlen(MNTOPT_QUOTA); if (*pathname == '=') { has_quota_file_definition = 1; @@ -553,14 +601,11 @@ int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filenam return -1; if (has_quota_file_definition) { - if ((option = strchr(pathname, ','))) { - int tocopy = min(option - pathname + 1, - sizeof(qfullname) - strlen(qfullname)); - sstrncpy(qfullname + strlen(qfullname), pathname, tocopy); - } else - sstrncat(qfullname, pathname, sizeof(qfullname)); + int len = strlen(qfullname); + + copy_mntoptarg(qfullname + len, pathname, sizeof(qfullname) - len); } else { - snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, + snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->me_dir, basenames[fmt], extensions[type]); } if (check_fmtfile_ok(qfullname, type, fmt, flags)) { @@ -579,7 +624,7 @@ int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filenam struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt, int ioflags, int mntflags) { - struct mntent *mnt; + struct mount_entry *mnt; int gotmnt = 0; static int hlist_allocated = 0; static struct quota_handle **hlist = NULL; @@ -613,18 +658,18 @@ add_entry: else { switch (fmt) { case QF_RPC: - if (nfs_fstype(mnt->mnt_type)) + if (nfs_fstype(mnt->me_type)) goto add_entry; break; case QF_XFS: - if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) || - !strcmp(mnt->mnt_type, MNTTYPE_GFS2)) + if (!strcmp(mnt->me_type, MNTTYPE_XFS) || + !strcmp(mnt->me_type, MNTTYPE_GFS2)) goto add_entry; break; default: - if (strcmp(mnt->mnt_type, MNTTYPE_XFS) && - strcmp(mnt->mnt_type, MNTTYPE_GFS2) && - !nfs_fstype(mnt->mnt_type)) + if (strcmp(mnt->me_type, MNTTYPE_XFS) && + strcmp(mnt->me_type, MNTTYPE_GFS2) && + !nfs_fstype(mnt->me_type)) goto add_entry; break; } @@ -818,13 +863,30 @@ static int xfs_kern_quota_on(const char *dev, int type) /* * Check whether is quota turned on on given device for given type */ -int kern_quota_on(const char *dev, int type, int fmt) +int kern_quota_on(struct mount_entry *mnt, int type, int fmt) { + if (mnt->me_qfmt[type] < 0) + return -1; + if (fmt == QF_RPC) + return -1; + if (mnt->me_qfmt[type] == QF_XFS) { + if ((fmt == -1 || fmt == QF_XFS) && + xfs_kern_quota_on(mnt->me_devname, type)) /* XFS quota format */ + return QF_XFS; + return -1; + } + /* No more chances for XFS format to succeed... */ + if (fmt == QF_XFS) + return -1; + /* Meta format is always enabled */ + if (mnt->me_qfmt[type] == QF_META) + return QF_META; + /* Check whether quota is turned on... */ if (kernel_iface == IFACE_GENERIC) { int actfmt; - if (quotactl(QCMD(Q_GETFMT, type), dev, 0, + if (quotactl(QCMD(Q_GETFMT, type), mnt->me_devname, 0, (void *)&actfmt) >= 0) { actfmt = kern2utilfmt(actfmt); if (actfmt >= 0) @@ -832,15 +894,12 @@ int kern_quota_on(const char *dev, int type, int fmt) } } else { if ((fmt == -1 || fmt == QF_VFSV0) && - v2_kern_quota_on(dev, type)) /* VFSv0 quota format */ + v2_kern_quota_on(mnt->me_devname, type)) return QF_VFSV0; if ((fmt == -1 || fmt == QF_VFSOLD) && - v1_kern_quota_on(dev, type)) /* Old quota format */ + v1_kern_quota_on(mnt->me_devname, type)) return QF_VFSOLD; } - if ((fmt == -1 || fmt == QF_XFS) && - xfs_kern_quota_on(dev, type)) /* XFS quota format */ - return QF_XFS; return -1; } @@ -850,15 +909,6 @@ int kern_quota_on(const char *dev, int type, int fmt) * */ -struct mount_entry { - char *me_type; /* Type of filesystem for given entry */ - char *me_opts; /* Options of filesystem */ - dev_t me_dev; /* Device filesystem is mounted on */ - ino_t me_ino; /* Inode number of root of filesystem */ - const char *me_devname; /* Name of device (after pass through get_device_name()) */ - const char *me_dir; /* One of mountpoints of filesystem */ -}; - struct searched_dir { int sd_dir; /* Is searched dir mountpoint or in fact device? */ dev_t sd_dev; /* Device mountpoint lies on */ @@ -906,6 +956,8 @@ alloc: allocated += ALLOC_ENTRIES_NUM; while ((mnt = getmntent(mntf))) { const char *devname; + char *opt; + int qfmt[MAXQUOTAS]; if (!(devname = get_device_name(mnt->mnt_fsname))) { errstr(_("Cannot get device name for %s\n"), mnt->mnt_fsname); @@ -936,10 +988,27 @@ alloc: free((char *)devname); continue; } + if (hasmntopt(mnt, MNTOPT_NOQUOTA)) { + free((char *)devname); + continue; + } + if (hasmntopt(mnt, MNTOPT_BIND)) { + free((char *)devname); + continue; /* We just ignore bind mounts... */ + } + if ((opt = hasmntoptarg(mnt->mnt_opts, MNTOPT_LOOP))) { + char loopdev[PATH_MAX]; + + copy_mntoptarg(opt, loopdev, PATH_MAX); + free((char *)devname); + devname = sstrdup(loopdev); + } /* Further we are not interested in mountpoints without quotas and we don't want to touch them */ - if (!hasquota(mnt, USRQUOTA, flags) && !hasquota(mnt, GRPQUOTA, flags)) { + qfmt[USRQUOTA] = hasquota(devname, mnt, USRQUOTA, flags); + qfmt[GRPQUOTA] = hasquota(devname, mnt, GRPQUOTA, flags); + if (qfmt[USRQUOTA] < 0 && qfmt[GRPQUOTA] < 0) { free((char *)devname); continue; } @@ -967,50 +1036,12 @@ alloc: free((char *)devname); continue; } - if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { - unsupporteddev: + if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { errstr(_("Device (%s) filesystem is mounted on unsupported device type. Skipping.\n"), devname); free((char *)devname); continue; - } else { - char *opt; - - if (hasmntopt(mnt, MNTOPT_BIND)) { - free((char *)devname); - continue; /* We just ignore bind mounts... */ - } - else if ((opt = hasmntopt(mnt, MNTOPT_LOOP))) { - char loopdev[PATH_MAX]; - int i; - - if (!(opt = strchr(opt, '='))) { - errstr(_("Cannot find device of loopback mount in options for %s. Skipping.\n"), devname); - free((char *)devname); - continue; - } - /* Copy the device name */ - for (opt++, i = 0; *opt && i < sizeof(loopdev)-1 && *opt != ','; opt++, i++) - loopdev[i] = *opt; - loopdev[i] = 0; - if (stat(loopdev, &st) < 0) { /* Can't stat loopback device? */ - errstr(_("Cannot stat() loopback device %s: %s\n"), opt, strerror(errno)); - free((char *)devname); - continue; - } - if (!S_ISBLK(st.st_mode)) { - errstr(_("Loopback device %s is not block device!\n"), opt); - free((char *)devname); - continue; - } - dev = st.st_rdev; - free((char *)devname); - devname = sstrdup(loopdev); - } else { - if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) - goto unsupporteddev; - dev = st.st_rdev; - } } + dev = st.st_rdev; for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); } /* Cope with network filesystems or new mountpoint */ @@ -1040,7 +1071,9 @@ alloc: mnt_entries[i].me_dev = dev; mnt_entries[i].me_ino = st.st_ino; mnt_entries[i].me_devname = devname; - mnt_entries[i].me_dir = sstrdup(mntpointbuf); + mnt_entries[i].me__dir = sstrdup(mntpointbuf); + mnt_entries[i].me_dir = NULL; + memcpy(&mnt_entries[i].me_qfmt, qfmt, sizeof(qfmt)); mnt_entries_cnt++; } else @@ -1059,7 +1092,7 @@ static const char *find_dir_mntpoint(struct stat *st) for (i = 0; i < mnt_entries_cnt; i++) if (mnt_entries[i].me_dev == st->st_dev) { st->st_ino = mnt_entries[i].me_ino; - return mnt_entries[i].me_dir; + return mnt_entries[i].me__dir; } return NULL; } @@ -1122,7 +1155,7 @@ static int process_dirs(int dcnt, char **dirs, int flags) errstr(_("Cannot find mountpoint for device %s\n"), dirs[i]); continue; } - sstrncpy(mntpointbuf, mnt_entries[mentry].me_dir, PATH_MAX-1); + sstrncpy(mntpointbuf, mnt_entries[mentry].me__dir, PATH_MAX-1); } else { errstr(_("Specified path %s is not directory nor device.\n"), dirs[i]); @@ -1158,14 +1191,8 @@ int init_mounts_scan(int dcnt, char **dirs, int flags) /* Find next usable mountpoint when scanning all mountpoints */ static int find_next_entry_all(int *pos) { - struct mntent mnt; - while (++act_checked < mnt_entries_cnt) { - mnt.mnt_fsname = (char *)mnt_entries[act_checked].me_devname; - mnt.mnt_type = mnt_entries[act_checked].me_type; - mnt.mnt_opts = mnt_entries[act_checked].me_opts; - mnt.mnt_dir = (char *)mnt_entries[act_checked].me_dir; - if (!hasmntopt(&mnt, MNTOPT_NOAUTO)) + if (!str_hasmntopt(mnt_entries[act_checked].me_opts, MNTOPT_NOAUTO)) break; } if (act_checked >= mnt_entries_cnt) @@ -1204,25 +1231,21 @@ restart: /* * Return next directory from the list */ -struct mntent *get_next_mount(void) +struct mount_entry *get_next_mount(void) { - static struct mntent mnt; int mntpos; if (!check_dirs_cnt) { /* Scan all mountpoints? */ if (!find_next_entry_all(&mntpos)) return NULL; - mnt.mnt_dir = (char *)mnt_entries[mntpos].me_dir; + mnt_entries[mntpos].me_dir = mnt_entries[mntpos].me__dir; } else { if (!find_next_entry_sel(&mntpos)) return NULL; - mnt.mnt_dir = (char *)check_dirs[act_checked].sd_name; + mnt_entries[mntpos].me_dir = check_dirs[act_checked].sd_name; } - mnt.mnt_fsname = (char *)mnt_entries[mntpos].me_devname; - mnt.mnt_type = mnt_entries[mntpos].me_type; - mnt.mnt_opts = mnt_entries[mntpos].me_opts; - return &mnt; + return &mnt_entries[mntpos]; } /* @@ -1236,7 +1259,7 @@ void end_mounts_scan(void) free(mnt_entries[i].me_type); free(mnt_entries[i].me_opts); free((char *)mnt_entries[i].me_devname); - free((char *)mnt_entries[i].me_dir); + free((char *)mnt_entries[i].me__dir); } free(mnt_entries); mnt_entries = NULL; @@ -36,6 +36,17 @@ /* Supported kernel interface */ extern int kernel_iface; +struct mount_entry { + char *me_type; /* Type of filesystem for given entry */ + char *me_opts; /* Options of filesystem */ + dev_t me_dev; /* Device filesystem is mounted on */ + ino_t me_ino; /* Inode number of root of filesystem */ + const char *me_devname; /* Name of device (after pass through get_device_name()) */ + const char *me__dir; /* One mountpoint of a filesystem (strdup()ed) */ + const char *me_dir; /* Current mountpoint of a filesystem to process */ + int me_qfmt[MAXQUOTAS]; /* Detected quota formats */ +}; + /* * Exported functions */ @@ -95,18 +106,23 @@ void space2str(qsize_t, char *, int); /* Convert number to short printable form */ void number2str(unsigned long long, char *, int); -/* Check to see if particular quota is to be enabled */ -/* Recognizes MS_XFS_DISABLED flag */ -int hasquota(struct mntent *mnt, int type, int flags); +/* Return pointer to given mount option in mount option string */ +char *str_hasmntopt(const char *optstring, const char *opt); + +/* Check to see if particular quota type is configured */ +static inline int me_hasquota(struct mount_entry *mnt, int type) +{ + return mnt->me_qfmt[type] >= 0; +} /* Flags for get_qf_name() */ #define NF_EXIST 1 /* Check whether file exists */ #define NF_FORMAT 2 /* Check whether file is in proper format */ /* Get quotafile name for given entry */ -int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename); +int get_qf_name(struct mount_entry *mnt, int type, int fmt, int flags, char **filename); /* Detect newest quota format with existing file */ -int detect_quota_files(struct mntent *mnt, int type, int fmt); +int detect_quota_files(struct mount_entry *mnt, int type, int fmt); /* Create NULL-terminated list of handles for quotafiles for given mountpoints */ struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt, @@ -124,7 +140,7 @@ int devcmp_handles(struct quota_handle *a, struct quota_handle *b); void init_kernel_interface(void); /* Check whether is quota turned on on given device for given type */ -int kern_quota_on(const char *dev, int type, int fmt); +int kern_quota_on(struct mount_entry *mnt, int type, int fmt); /* Return whether kernel is able to handle given format */ int kern_qfmt_supp(int fmt); @@ -141,7 +157,7 @@ int kern_qfmt_supp(int fmt); int init_mounts_scan(int dcnt, char **dirs, int flags); /* Return next mountpoint for scan */ -struct mntent *get_next_mount(void); +struct mount_entry *get_next_mount(void); /* Free all structures associated with mountpoints scan */ void end_mounts_scan(void); diff --git a/rquota_server.c b/rquota_server.c index 3293de7..bb270e6 100644 --- a/rquota_server.c +++ b/rquota_server.c @@ -147,7 +147,7 @@ setquota_rslt *setquotainfo(int lflags, caddr_t * argp, struct svc_req *rqstp) } arguments; struct util_dqblk dqblk; struct dquot *dquot; - struct mntent *mnt; + struct mount_entry *mnt; char pathname[PATH_MAX] = {0}; char *pathp = pathname; int id, qcmd, type; @@ -239,7 +239,7 @@ getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp) ext_getquota_args *ext_args; } arguments; struct dquot *dquot = NULL; - struct mntent *mnt; + struct mount_entry *mnt; char pathname[PATH_MAX] = {0}; char *pathp = pathname; int id, type; |