Created
December 7, 2011 21:47
-
-
Save mpage/1444832 to your computer and use it in GitHub Desktop.
Simple utility to report quota information (potentially a replacement for repquota)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <errno.h> | |
#include <fstab.h> | |
#include <inttypes.h> | |
#include <malloc.h> | |
#include <mntent.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/quota.h> | |
#define dqblk_print_field(dqblk, field) printf("%llu ", (dqblk).(field)) | |
/** | |
* Attempts to look up the device name associated with supplied mount point. | |
* | |
* @param dir Mount point to look up | |
* @param dev_name Where to place the device name. Caller must free. | |
* | |
* @return 0 on success | |
* -1 mount point not found | |
*/ | |
static int lookup_device(const char* dir, char** dev_name) { | |
FILE* mtab = NULL; | |
struct mntent* mtab_entry = NULL; | |
size_t fsname_len = 0; | |
int retval = -1; | |
/* Using /etc/mtab here is supposedly a no-no, but the macro we're supposed | |
* to use (_PATH_MNTTAB) resolves to "/etc/fstab" (at least on my Ubuntu system). | |
*/ | |
mtab = setmntent("/etc/mtab", "r"); | |
if (NULL == mtab) { | |
return -2; | |
} | |
/* Could move into conditional, but prefer this stylistically */ | |
mtab_entry = getmntent(mtab); | |
while (NULL != mtab_entry) { | |
if (!strcmp(mtab_entry->mnt_dir, dir)) { | |
fsname_len = strlen(mtab_entry->mnt_fsname) + 1; | |
*dev_name = malloc(fsname_len); | |
assert(NULL != *dev_name); | |
strncpy(*dev_name, mtab_entry->mnt_fsname, fsname_len); | |
retval = 0; | |
break; | |
} | |
mtab_entry = getmntent(mtab); | |
} | |
endmntent(mtab); | |
return retval; | |
} | |
/** | |
* Attempts to print a helpful error message to stderr. | |
* | |
* @param msg Error message to prepend. | |
*/ | |
static void print_quotactl_error(const char* msg) { | |
assert(NULL != msg); | |
switch (errno) { | |
case EFAULT: | |
fprintf(stderr, "%s: Block device invalid.\n", msg); | |
break; | |
case ENOENT: | |
fprintf(stderr, "%s: Block device doesn't exist.\n", msg); | |
break; | |
case ENOSYS: | |
fprintf(stderr, "%s: Kernel doesn't haven quota support.\n", msg); | |
break; | |
case ENOTBLK: | |
fprintf(stderr, "%s: Not a block device.\n", msg); | |
break; | |
case EPERM: | |
fprintf(stderr, "%s: Insufficient privilege.\n", msg); | |
break; | |
case ESRCH: | |
fprintf(stderr, "%s: No quota for supplied user.\n", msg); | |
break; | |
default: | |
perror(msg); | |
break; | |
} | |
} | |
/** | |
* Prints relevant quota information to stdout for the supplied uid. | |
* On failure, will attempt to print a helpful error messge to stderr. | |
* | |
* @param filesystem Filesystem to report quota information for | |
* @param uid Uid to report quota information for | |
* | |
* @return -1 on error, 0 otherwise | |
*/ | |
static int print_quota_usage(const char* filesystem, int uid) { | |
assert(NULL != filesystem); | |
char emsg[1024]; | |
struct dqblk quota_info; | |
memset("a_info, 0, sizeof(struct dqblk)); | |
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), filesystem, uid, (caddr_t) "a_info) < 0) { | |
sprintf(emsg, "Failed retrieving quota for uid=%d", uid); | |
print_quotactl_error(emsg); | |
return -1; | |
} | |
printf("%d ", uid); | |
/* Block info */ | |
printf("%llu %llu %llu %llu ", | |
(long long unsigned int) quota_info.dqb_curspace, | |
(long long unsigned int) quota_info.dqb_bsoftlimit, | |
(long long unsigned int) quota_info.dqb_bhardlimit, | |
(long long unsigned int) quota_info.dqb_btime); | |
/* Inode info */ | |
printf("%llu %llu %llu %llu\n", | |
(long long unsigned int) quota_info.dqb_curinodes, | |
(long long unsigned int) quota_info.dqb_isoftlimit, | |
(long long unsigned int) quota_info.dqb_ihardlimit, | |
(long long unsigned int) quota_info.dqb_itime); | |
return 0; | |
} | |
int | |
main(int argc, char* argv[]) { | |
char* device_name = NULL; | |
int* uids = NULL; | |
int ii = 0, num_uids = 0; | |
if (argc < 3) { | |
printf("Usage: report_quota [filesystem] [uid]+\n"); | |
printf("Reports quota information for the supplied uids on the given filesystem\n"); | |
printf("Format is: <uid> <blocks used> <soft> <hard> <grace> <inodes used> <soft> <hard> <grace>\n"); | |
exit(1); | |
} | |
if (lookup_device(argv[1], &device_name) < 0) { | |
printf("Couldn't find device for %s", argv[1]); | |
exit(1); | |
} | |
num_uids = argc - 2; | |
uids = malloc(sizeof(int) * num_uids); | |
if (NULL == uids) { | |
perror("malloc()"); | |
free(device_name); | |
exit(1); | |
} | |
memset(uids, 0, sizeof(int) * num_uids); | |
for (ii = 0; ii < num_uids; ii++) { | |
uids[ii] = atoi(argv[ii + 2]); | |
} | |
for (ii = 0; ii < num_uids; ii++) { | |
print_quota_usage(device_name, uids[ii]); | |
} | |
free(device_name); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment