diff options
-rw-r--r-- | quotacheck.8 | 17 | ||||
-rw-r--r-- | quotacheck.c | 84 | ||||
-rw-r--r-- | quotacheck.h | 1 | ||||
-rw-r--r-- | quotacheck_v2.c | 6 | ||||
-rw-r--r-- | quotaon.c | 16 | ||||
-rw-r--r-- | quotasys.c | 25 |
6 files changed, 86 insertions, 63 deletions
diff --git a/quotacheck.8 b/quotacheck.8 index 7c5f5b2..1fe707b 100644 --- a/quotacheck.8 +++ b/quotacheck.8 @@ -4,7 +4,7 @@ quotacheck \- scan a filesystem for disk usage, create, check and repair quota f .SH SYNOPSIS .B quotacheck [ -.B \-gucfinvdMmR +.B \-gubcfinvdMmR ] [ .B \-F .I quota-format @@ -19,10 +19,10 @@ examines each filesystem, builds a table of current disk usage, and compares this table against that recorded in the disk quota file for the filesystem (this step is ommitted if option .B -c -is specified). If any inconsistencies are detected, both the quota file +is specified). If any inconsistencies are detected, both the quota file and the current system copy of the incorrect quotas are updated (the -latter only occurs if an active filesystem is checked). By default, -only user quotas are checked. +latter only occurs if an active filesystem is checked which is not advised). +By default, only user quotas are checked. .B quotacheck expects each filesystem to be checked to have quota files named .I [a]quota.user @@ -70,6 +70,11 @@ ignore the failure to remount the filesystem read-only with option .BR \-M . .SH OPTIONS .TP +.B \-b +Forces +.B quotacheck +to make backups of the quota file before writing the new data. +.TP .B \-v .B quotacheck reports its operation as it progresses. Normally it operates silently. @@ -91,6 +96,8 @@ or on the filesystems specified are to be checked. .TP .B \-c Don't read existing quota files. Just perform a new scan and save it to disk. +.B quotacheck +also skips scanning of old quota files when they are not found. .TP .B \-f Forces checking of filesystems with quotas enabled. This is not @@ -120,7 +127,7 @@ exits or asks user for input. When this option is set, the first entry found is always used (this option works in interactive mode too). .TP .B \-F \f2format-name\f1 -Check quota quota for specified format (ie. don't perform format +Check quota for specified format (ie. don't perform format auto-detection). This is recommended as detection might not work well on corrupted quota files. Possible format names are: .B vfsold diff --git a/quotacheck.c b/quotacheck.c index f12fadd..5bfb41a 100644 --- a/quotacheck.c +++ b/quotacheck.c @@ -8,7 +8,7 @@ * New quota format implementation - Jan Kara <jack@suse.cz> - Sponsored by SuSE CR */ -#ident "$Id: quotacheck.c,v 1.17 2001/08/30 10:11:24 jkar8572 Exp $" +#ident "$Id: quotacheck.c,v 1.18 2001/09/04 16:21:58 jkar8572 Exp $" #include <dirent.h> #include <stdio.h> @@ -286,8 +286,11 @@ static void parse_options(int argcnt, char **argstr) { int ret; - while ((ret = getopt(argcnt, argstr, "VhcvugidnfF:mMRa")) != -1) { - switch (ret) { + while ((ret = getopt(argcnt, argstr, "VhbcvugidnfF:mMRa")) != -1) { + switch (ret) { + case 'b': + flags |= FL_BACKUPS; + break; case 'g': gwant = 1; break; @@ -539,7 +542,7 @@ static int process_file(struct mntent *mnt, int type) char *qfname = NULL; int fd = -1, ret; - debug(FL_DEBUG | FL_VERBOSE, _("Going to check %s quota file of %s\n"), type2name(type), + debug(FL_DEBUG, _("Going to check %s quota file of %s\n"), type2name(type), mnt->mnt_dir); if (kern_quota_on(mnt->mnt_fsname, type, (1 << cfmt)) > 0) { /* Is quota enabled? */ @@ -605,32 +608,34 @@ static int rename_files(struct mntent *mnt, int type) if (!(filename = get_qf_name(mnt, type, cfmt))) die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->mnt_dir); - debug(FL_DEBUG | FL_VERBOSE, _("Data dumped.\nRenaming old quotafile to %s~\n"), filename); - if (stat(filename, &st) < 0) { /* File doesn't exist? */ - if (errno == ENOENT) { - debug(FL_DEBUG | FL_VERBOSE, _("Old file not found.\n")); - goto rename_new; + if (flags & FL_BACKUPS) { + debug(FL_DEBUG, _("Data dumped.\nRenaming old quotafile to %s~\n"), filename); + if (stat(filename, &st) < 0) { /* File doesn't exist? */ + if (errno == ENOENT) { + debug(FL_DEBUG | FL_VERBOSE, _("Old file not found.\n")); + goto rename_new; + } + errstr(_("Error while searching for old quota file %s: %s\n"), + filename, strerror(errno)); + free(filename); + return -1; + } + mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + /* Backup old file */ + strcpy(newfilename, filename); + /* Make backingup safe */ + sstrncat(newfilename, "~", PATH_MAX); + if (newfilename[strlen(newfilename) - 1] != '~') + die(8, _("Name of quota file too long. Contact %s.\n"), MY_EMAIL); + if (rename(filename, newfilename) < 0) { + errstr(_("Cannot rename old quotafile %s to %s: %s\n"), + filename, newfilename, strerror(errno)); + free(filename); + return -1; } - errstr(_("Error while searching for old quota file %s: %s\n"), - filename, strerror(errno)); - free(filename); - return -1; - } - mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - /* Backup old file */ - strcpy(newfilename, filename); - /* Make backingup safe */ - sstrncat(newfilename, "~", PATH_MAX); - if (newfilename[strlen(newfilename) - 1] != '~') - die(8, _("Name of quota file too long. Contact %s.\n"), MY_EMAIL); - if (rename(filename, newfilename) < 0) { - errstr(_("Cannot rename old quotafile %s to %s: %s\n"), - filename, newfilename, strerror(errno)); - free(filename); - return -1; } - debug(FL_DEBUG | FL_VERBOSE, _("Renaming new quotafile\n")); - rename_new: + debug(FL_DEBUG, _("Renaming new quotafile\n")); +rename_new: /* Rename new file to right name */ strcpy(newfilename, filename); sstrncat(newfilename, ".new", PATH_MAX); @@ -660,7 +665,7 @@ static int dump_to_file(struct mntent *mnt, int type) uint i; struct quota_handle *h; - debug(FL_DEBUG | FL_VERBOSE, _("Dumping gathered data for %ss.\n"), type2name(type)); + debug(FL_DEBUG, _("Dumping gathered data for %ss.\n"), type2name(type)); if (!(h = new_io(mnt, type, cfmt))) { errstr(_("Cannot initialize IO on new quotafile: %s\n"), strerror(errno)); @@ -684,7 +689,7 @@ static int dump_to_file(struct mntent *mnt, int type) return -1; } if (rename_files(mnt, type) < 0) - return -1; + return -1; if (cfmt == kern_quota_on(mnt->mnt_fsname, type, 1 << cfmt)) { /* Quota turned on? */ char *filename; @@ -734,25 +739,21 @@ static void check_dir(struct mntent *mnt) (NULL, mnt->mnt_dir, mnt->mnt_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->mnt_dir); if (!ask_yn(_("Should I continue"), 0)) { printf(_("As you wish... Canceling check of this file.\n")); goto out; } } 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); + 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); goto out; } } else remounted = 1; - debug(FL_DEBUG | FL_VERBOSE, _("Filesystem remounted read-only\n")); + debug(FL_DEBUG, _("Filesystem remounted read-only\n")); } debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->mnt_fsname, mnt->mnt_dir); #if defined(EXT2_DIRECT) @@ -775,7 +776,7 @@ Please stop all programs writing to filesystem or use -m flag to force checking. 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); - debug(FL_DEBUG | FL_VERBOSE, _("Filesystem remounted RW.\n")); + debug(FL_DEBUG, _("Filesystem remounted RW.\n")); } if (ucheck) dump_to_file(mnt, USRQUOTA); @@ -814,7 +815,8 @@ static int detect_filename_format(struct mntent *mnt, int type) snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSOLD], extensions[type]); if (!stat(namebuf, &statbuf)) return QF_VFSOLD; - /* Old quota files don't exist, just return newest format... */ + /* Old quota files don't exist, just create newest quotafile available */ + flags |= FL_NEWFILE; return QF_VFSV0; } @@ -849,7 +851,7 @@ static void check_all(void) mnt->mnt_fsname); continue; } - debug(FL_DEBUG | FL_VERBOSE, _("Detected quota format %s\n"), fmt2name(cfmt)); + debug(FL_DEBUG, _("Detected quota format %s\n"), fmt2name(cfmt)); } checked++; check_dir(mnt); diff --git a/quotacheck.h b/quotacheck.h index fd09aad..09a5c09 100644 --- a/quotacheck.h +++ b/quotacheck.h @@ -24,6 +24,7 @@ #define FL_NOREMOUNT 128 /* Don't try to remount filesystem RO */ #define FL_ALL 256 /* Scan all mountpoints with quota? */ #define FL_NOROOT 512 /* Scan all mountpoints except root */ +#define FL_BACKUPS 1024 /* Create backup of old quota file? */ extern int flags; /* Options from command line */ extern struct util_dqinfo old_info[MAXQUOTAS]; /* Loaded info from file */ diff --git a/quotacheck_v2.c b/quotacheck_v2.c index 8c88d79..6ede24e 100644 --- a/quotacheck_v2.c +++ b/quotacheck_v2.c @@ -48,7 +48,7 @@ static int check_info(char *filename, int fd, int type) off_t filesize; int err; - debug(FL_VERBOSE, _("Checking quotafile info...\n")); + debug(FL_DEBUG, _("Checking quotafile info...\n")); lseek(fd, V2_DQINFOOFF, SEEK_SET); err = read(fd, &dinfo, sizeof(struct v2_disk_dqinfo)); @@ -322,7 +322,7 @@ int v2_buffer_file(char *filename, int fd, int type) return 0; if (check_info(filename, fd, type) < 0) return 0; - debug(FL_DEBUG | FL_VERBOSE, _("Headers of file %s checked. Going to load data...\n"), + debug(FL_DEBUG, _("Headers of file %s checked. Going to load data...\n"), filename); blocks = old_info[type].u.v2_mdqi.dqi_blocks; blkbmp = xmalloc((blocks + 7) >> 3); @@ -341,7 +341,7 @@ int v2_buffer_file(char *filename, int fd, int type) errstr(_("WARNING - Some data might be changed due to corruption.\n")); } else - debug(FL_DEBUG | FL_VERBOSE, _("Not found any corrupted blocks. Congratulations.\n")); + debug(FL_DEBUG, _("Not found any corrupted blocks. Congratulations.\n")); return ret; } @@ -34,7 +34,7 @@ #ident "$Copyright: (c) 1980, 1990 Regents of the University of California $" #ident "$Copyright: All rights reserved. $" -#ident "$Id: quotaon.c,v 1.7 2001/08/30 10:11:24 jkar8572 Exp $" +#ident "$Id: quotaon.c,v 1.8 2001/09/04 16:21:58 jkar8572 Exp $" /* * Turn quota on/off for a filesystem. @@ -175,27 +175,27 @@ int main(int argc, char **argv) /* * Enable/disable VFS quota on given filesystem */ -static int quotaonoff(char *quotadev, char *quotafile, int type, int flags) +static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, int flags) { int qcmd; if (flags & STATEFLAG_OFF) { qcmd = QCMD(Q_QUOTAOFF, type); if (quotactl(qcmd, quotadev, 0, NULL) < 0) { - errstr(_("quotactl on %s: %s\n"), quotadev, strerror(errno)); + errstr(_("quotactl on %s [%s]: %s\n"), quotadev, quotadir, strerror(errno)); return 1; } if (flags & STATEFLAG_VERBOSE) - printf(_("%s: %s quotas turned off\n"), quotadev, type2name(type)); + printf(_("%s [%s]: %s quotas turned off\n"), quotadev, quotadir, type2name(type)); return 0; } qcmd = QCMD(Q_QUOTAON, type); if (quotactl(qcmd, quotadev, 0, (void *)quotafile) < 0) { - errstr(_("using %s on %s: %s\n"), quotafile, quotadev, strerror(errno)); + errstr(_("using %s on %s [%s]: %s\n"), quotafile, quotadev, quotadir, strerror(errno)); return 1; } if (flags & STATEFLAG_VERBOSE) - printf(_("%s: %s quotas turned on\n"), quotadev, type2name(type)); + printf(_("%s [%s]: %s quotas turned on\n"), quotadev, quotadir, type2name(type)); return 0; } @@ -233,7 +233,7 @@ int v1_newstate(struct mntent *mnt, int type, char *file, int flags) if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH)) errs += quotarsquashonoff(dev, type, flags); if (hasquota(mnt, type)) - errs += quotaonoff((char *)dev, file, type, flags); + errs += quotaonoff((char *)dev, mnt->mnt_dir, file, type, flags); if ((flags & STATEFLAG_ON) && hasmntopt(mnt, MNTOPT_RSQUASH)) errs += quotarsquashonoff(dev, type, flags); free((char *)dev); @@ -251,7 +251,7 @@ int v2_newstate(struct mntent *mnt, int type, char *file, int flags) if (!dev) return 1; if (hasquota(mnt, type)) - errs = quotaonoff((char *)dev, file, type, flags); + errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, flags); free((char *)dev); return errs; } @@ -657,27 +657,40 @@ static int process_dirs(int dcnt, char **dirs) check_dirs = smalloc(sizeof(struct searched_dir) * dcnt); for (i = 0; i < dcnt; i++) { if (stat(dirs[i], &st) < 0) { - errstr(_("Can't stat() given mountpoint %s: %s\n"), dirs[i], strerror(errno)); + errstr(_("Can't stat() given mountpoint %s: %s\nSkipping...\n"), dirs[i], strerror(errno)); continue; } check_dirs[check_dirs_cnt].sd_dir = S_ISDIR(st.st_mode); if (S_ISDIR(st.st_mode)) { check_dirs[check_dirs_cnt].sd_dev = st.st_dev; check_dirs[check_dirs_cnt].sd_ino = st.st_ino; + if (!realpath(dirs[i], mntpointbuf)) { + errstr(_("Can't resolve path %s: %s\n"), dirs[i], strerror(errno)); + continue; + } } - else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) + else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { + int mentry; + check_dirs[check_dirs_cnt].sd_dev = st.st_rdev; + for (mentry = 0; mentry < mnt_entries_cnt && mnt_entries[mentry].me_dev != st.st_rdev; mentry++); + if (mentry == mnt_entries_cnt) { + errstr(_("Can't find mountpoint for device %s\n"), dirs[i]); + continue; + } + strcpy(mntpointbuf, mnt_entries[mentry].me_dir); + } else { errstr(_("Specified path %s is not directory nor device.\n"), dirs[i]); continue; } - if (!realpath(dirs[i], mntpointbuf)) { - errstr(_("Can't resolve path %s: %s\n"), dirs[i], strerror(errno)); - continue; - } check_dirs[check_dirs_cnt].sd_name = sstrdup(mntpointbuf); check_dirs_cnt++; } + if (!check_dirs_cnt) { + errstr(_("No correct mountpoint specified.\n")); + return -1; + } } return 0; } |