| /* |
| * quota.c --- debugfs quota commands |
| * |
| * Copyright (C) 2014 Theodore Ts'o. This file may be redistributed |
| * under the terms of the GNU Public License. |
| */ |
| |
| #include "config.h" |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <time.h> |
| #ifdef HAVE_ERRNO_H |
| #include <errno.h> |
| #endif |
| #include <sys/types.h> |
| #ifdef HAVE_GETOPT_H |
| #include <getopt.h> |
| #else |
| extern int optind; |
| extern char *optarg; |
| #endif |
| |
| #include "debugfs.h" |
| |
| const char *quota_type[] = { "user", "group", NULL }; |
| |
| static int load_quota_ctx(char *progname) |
| { |
| errcode_t retval; |
| |
| if (check_fs_open(progname)) |
| return 1; |
| |
| if (!ext2fs_has_feature_quota(current_fs->super)) { |
| com_err(progname, 0, "quota feature not enabled"); |
| return 1; |
| } |
| |
| if (current_qctx) |
| return 0; |
| |
| retval = quota_init_context(¤t_qctx, current_fs, QUOTA_ALL_BIT); |
| if (retval) { |
| com_err(current_fs->device_name, retval, |
| "while trying to load quota information"); |
| return 1; |
| } |
| return 0; |
| } |
| |
| static int parse_quota_type(const char *cmdname, const char *str) |
| { |
| errcode_t retval; |
| char *t; |
| int flags = 0; |
| int i; |
| |
| for (i = 0; i < MAXQUOTAS; i++) { |
| if (strcasecmp(str, quota_type[i]) == 0) |
| break; |
| } |
| if (i >= MAXQUOTAS) { |
| i = strtol(str, &t, 0); |
| if (*t) |
| i = -1; |
| } |
| if (i < 0 || i >= MAXQUOTAS) { |
| com_err(0, 0, "Invalid quota type: %s", str); |
| printf("Valid quota types are: "); |
| for (i = 0; i < MAXQUOTAS; i++) |
| printf("%s ", quota_type[i]); |
| printf("\n"); |
| return -1; |
| } |
| |
| if (current_fs->flags & EXT2_FLAG_RW) |
| flags |= EXT2_FILE_WRITE; |
| |
| retval = quota_file_open(current_qctx, NULL, 0, i, -1, flags); |
| if (retval) { |
| com_err(cmdname, retval, |
| "while opening quota inode (type %d)", i); |
| return -1; |
| } |
| return i; |
| } |
| |
| |
| static int list_quota_callback(struct dquot *dq, |
| void *cb_data EXT2FS_ATTR((unused))) |
| { |
| printf("%8u %8lld %8lld %8lld %8lld %8lld %8lld\n", |
| dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, |
| (long long)dq->dq_dqb.dqb_bsoftlimit, |
| (long long)dq->dq_dqb.dqb_bhardlimit, |
| (long long)dq->dq_dqb.dqb_curinodes, |
| (long long)dq->dq_dqb.dqb_isoftlimit, |
| (long long)dq->dq_dqb.dqb_ihardlimit); |
| return 0; |
| } |
| |
| void do_list_quota(int argc, char *argv[]) |
| { |
| errcode_t retval; |
| int type; |
| struct quota_handle *qh; |
| |
| if (load_quota_ctx(argv[0])) |
| return; |
| |
| if (argc != 2) { |
| com_err(0, 0, "Usage: list_quota <quota_type>\n"); |
| return; |
| } |
| |
| type = parse_quota_type(argv[0], argv[1]); |
| if (type < 0) |
| return; |
| |
| printf("%8s %8s %8s %8s %8s %8s %8s\n", |
| (type == 0) ? "user id" : "group id", |
| "blocks", "quota", "limit", "inodes", "quota", "limit"); |
| qh = current_qctx->quota_file[type]; |
| retval = qh->qh_ops->scan_dquots(qh, list_quota_callback, NULL); |
| if (retval) { |
| com_err(argv[0], retval, "while scanning dquots"); |
| return; |
| } |
| } |
| |
| void do_get_quota(int argc, char *argv[]) |
| { |
| int err, type; |
| struct quota_handle *qh; |
| struct dquot *dq; |
| qid_t id; |
| |
| if (load_quota_ctx(argv[0])) |
| return; |
| |
| if (argc != 3) { |
| com_err(0, 0, "Usage: get_quota <quota_type> <id>\n"); |
| return; |
| } |
| |
| type = parse_quota_type(argv[0], argv[1]); |
| if (type < 0) |
| return; |
| |
| id = parse_ulong(argv[2], argv[0], "id", &err); |
| if (err) |
| return; |
| |
| printf("%8s %8s %8s %8s %8s %8s %8s\n", |
| (type == 0) ? "user id" : "group id", |
| "blocks", "quota", "limit", "inodes", "quota", "limit"); |
| |
| qh = current_qctx->quota_file[type]; |
| |
| dq = qh->qh_ops->read_dquot(qh, id); |
| if (dq) { |
| list_quota_callback(dq, NULL); |
| ext2fs_free_mem(&dq); |
| } else { |
| com_err(argv[0], 0, "couldn't read quota record"); |
| } |
| } |