1 /* 2 * quota.c --- debugfs quota commands 3 * 4 * Copyright (C) 2014 Theodore Ts'o. This file may be redistributed 5 * under the terms of the GNU Public License. 6 */ 7 8 #include "config.h" 9 #include <stdio.h> 10 #include <unistd.h> 11 #include <stdlib.h> 12 #include <ctype.h> 13 #include <string.h> 14 #include <time.h> 15 #ifdef HAVE_ERRNO_H 16 #include <errno.h> 17 #endif 18 #include <sys/types.h> 19 #ifdef HAVE_GETOPT_H 20 #include <getopt.h> 21 #else 22 extern int optind; 23 extern char *optarg; 24 #endif 25 26 #include "debugfs.h" 27 28 const char *quota_type[] = { "user", "group", NULL }; 29 30 static int load_quota_ctx(char *progname) 31 { 32 errcode_t retval; 33 34 if (check_fs_open(progname)) 35 return 1; 36 37 if (!ext2fs_has_feature_quota(current_fs->super)) { 38 com_err(progname, 0, "quota feature not enabled"); 39 return 1; 40 } 41 42 if (current_qctx) 43 return 0; 44 45 retval = quota_init_context(¤t_qctx, current_fs, QUOTA_ALL_BIT); 46 if (retval) { 47 com_err(current_fs->device_name, retval, 48 "while trying to load quota information"); 49 return 1; 50 } 51 return 0; 52 } 53 54 static int parse_quota_type(const char *cmdname, const char *str) 55 { 56 errcode_t retval; 57 char *t; 58 int flags = 0; 59 int i; 60 61 for (i = 0; i < MAXQUOTAS; i++) { 62 if (strcasecmp(str, quota_type[i]) == 0) 63 break; 64 } 65 if (i >= MAXQUOTAS) { 66 i = strtol(str, &t, 0); 67 if (*t) 68 i = -1; 69 } 70 if (i < 0 || i >= MAXQUOTAS) { 71 com_err(0, 0, "Invalid quota type: %s", str); 72 printf("Valid quota types are: "); 73 for (i = 0; i < MAXQUOTAS; i++) 74 printf("%s ", quota_type[i]); 75 printf("\n"); 76 return -1; 77 } 78 79 if (current_fs->flags & EXT2_FLAG_RW) 80 flags |= EXT2_FILE_WRITE; 81 82 retval = quota_file_open(current_qctx, NULL, 0, i, -1, flags); 83 if (retval) { 84 com_err(cmdname, retval, 85 "while opening quota inode (type %d)", i); 86 return -1; 87 } 88 return i; 89 } 90 91 92 static int list_quota_callback(struct dquot *dq, 93 void *cb_data EXT2FS_ATTR((unused))) 94 { 95 printf("%8u %8lld %8lld %8lld %8lld %8lld %8lld\n", 96 dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, 97 (long long)dq->dq_dqb.dqb_bsoftlimit, 98 (long long)dq->dq_dqb.dqb_bhardlimit, 99 (long long)dq->dq_dqb.dqb_curinodes, 100 (long long)dq->dq_dqb.dqb_isoftlimit, 101 (long long)dq->dq_dqb.dqb_ihardlimit); 102 return 0; 103 } 104 105 void do_list_quota(int argc, char *argv[]) 106 { 107 errcode_t retval; 108 int type; 109 struct quota_handle *qh; 110 111 if (load_quota_ctx(argv[0])) 112 return; 113 114 if (argc != 2) { 115 com_err(0, 0, "Usage: list_quota <quota_type>\n"); 116 return; 117 } 118 119 type = parse_quota_type(argv[0], argv[1]); 120 if (type < 0) 121 return; 122 123 printf("%8s %8s %8s %8s %8s %8s %8s\n", 124 (type == 0) ? "user id" : "group id", 125 "blocks", "quota", "limit", "inodes", "quota", "limit"); 126 qh = current_qctx->quota_file[type]; 127 retval = qh->qh_ops->scan_dquots(qh, list_quota_callback, NULL); 128 if (retval) { 129 com_err(argv[0], retval, "while scanning dquots"); 130 return; 131 } 132 } 133 134 void do_get_quota(int argc, char *argv[]) 135 { 136 int err, type; 137 struct quota_handle *qh; 138 struct dquot *dq; 139 qid_t id; 140 141 if (load_quota_ctx(argv[0])) 142 return; 143 144 if (argc != 3) { 145 com_err(0, 0, "Usage: get_quota <quota_type> <id>\n"); 146 return; 147 } 148 149 type = parse_quota_type(argv[0], argv[1]); 150 if (type < 0) 151 return; 152 153 id = parse_ulong(argv[2], argv[0], "id", &err); 154 if (err) 155 return; 156 157 printf("%8s %8s %8s %8s %8s %8s %8s\n", 158 (type == 0) ? "user id" : "group id", 159 "blocks", "quota", "limit", "inodes", "quota", "limit"); 160 161 qh = current_qctx->quota_file[type]; 162 163 dq = qh->qh_ops->read_dquot(qh, id); 164 if (dq) { 165 list_quota_callback(dq, NULL); 166 ext2fs_free_mem(&dq); 167 } else { 168 com_err(argv[0], 0, "couldn't read quota record"); 169 } 170 } 171