| 1 | #ifndef lint |
| 2 | static char sccsid[] = "@(#)quota.c 4.4 (Berkeley, from Melbourne) %G%"; |
| 3 | #endif |
| 4 | |
| 5 | /* |
| 6 | * Disk quota reporting program. |
| 7 | */ |
| 8 | #include <stdio.h> |
| 9 | #include <fstab.h> |
| 10 | #include <ctype.h> |
| 11 | #include <pwd.h> |
| 12 | |
| 13 | #include <sys/param.h> |
| 14 | #include <sys/quota.h> |
| 15 | #include <sys/file.h> |
| 16 | #include <sys/stat.h> |
| 17 | |
| 18 | int qflag; |
| 19 | int vflag; |
| 20 | int done; |
| 21 | int morethanone; |
| 22 | char *qfname = "quotas"; |
| 23 | |
| 24 | main(argc, argv) |
| 25 | char *argv[]; |
| 26 | { |
| 27 | register char *cp; |
| 28 | |
| 29 | argc--,argv++; |
| 30 | while (argc > 0) { |
| 31 | if (argv[0][0] == '-') |
| 32 | for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { |
| 33 | |
| 34 | case 'v': |
| 35 | vflag++; |
| 36 | break; |
| 37 | |
| 38 | case 'q': |
| 39 | qflag++; |
| 40 | break; |
| 41 | |
| 42 | default: |
| 43 | fprintf(stderr, "quota: %c: unknown option\n", |
| 44 | *cp); |
| 45 | exit(1); |
| 46 | } |
| 47 | else |
| 48 | break; |
| 49 | argc--, argv++; |
| 50 | } |
| 51 | morethanone = argc > 1; |
| 52 | if (argc == 0) { |
| 53 | showuid(getuid()); |
| 54 | exit(0); |
| 55 | } |
| 56 | for (; argc > 0; argc--, argv++) { |
| 57 | if (alldigits(*argv)) |
| 58 | showuid(atoi(*argv)); |
| 59 | else |
| 60 | showname(*argv); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | showuid(uid) |
| 65 | int uid; |
| 66 | { |
| 67 | struct passwd *pwd = getpwuid(uid); |
| 68 | |
| 69 | if (pwd == NULL) |
| 70 | showquotas(uid, "(no account)"); |
| 71 | else |
| 72 | showquotas(uid, pwd->pw_name); |
| 73 | } |
| 74 | |
| 75 | showname(name) |
| 76 | char *name; |
| 77 | { |
| 78 | struct passwd *pwd = getpwnam(name); |
| 79 | |
| 80 | if (pwd == NULL) { |
| 81 | fprintf(stderr, "quota: %s: unknown user\n", name); |
| 82 | return; |
| 83 | } |
| 84 | showquotas(pwd->pw_uid, name); |
| 85 | } |
| 86 | |
| 87 | showquotas(uid, name) |
| 88 | int uid; |
| 89 | char *name; |
| 90 | { |
| 91 | register char c, *p; |
| 92 | register struct fstab *fs; |
| 93 | int myuid; |
| 94 | |
| 95 | myuid = getuid(); |
| 96 | if (uid != myuid && myuid != 0) { |
| 97 | printf("quota: %s (uid %d): permission denied\n", name, uid); |
| 98 | return; |
| 99 | } |
| 100 | done = 0; |
| 101 | setfsent(); |
| 102 | while (fs = getfsent()) { |
| 103 | register char *msgi = (char *)0, *msgb = (char *)0; |
| 104 | register enab = 1; |
| 105 | dev_t fsdev; |
| 106 | struct stat statb; |
| 107 | struct dqblk dqblk; |
| 108 | char qfilename[MAXPATHLEN + 1], iwarn[8], dwarn[8]; |
| 109 | |
| 110 | if (stat(fs->fs_spec, &statb) < 0) |
| 111 | continue; |
| 112 | fsdev = statb.st_rdev; |
| 113 | (void) sprintf(qfilename, "%s/%s", fs->fs_file, qfname); |
| 114 | if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev) |
| 115 | continue; |
| 116 | if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) { |
| 117 | register fd = open(qfilename, O_RDONLY); |
| 118 | |
| 119 | if (fd < 0) |
| 120 | continue; |
| 121 | lseek(fd, (long)(uid * sizeof (dqblk)), L_SET); |
| 122 | if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) { |
| 123 | close(fd); |
| 124 | continue; |
| 125 | } |
| 126 | close(fd); |
| 127 | if (dqblk.dqb_isoftlimit == 0 && |
| 128 | dqblk.dqb_bsoftlimit == 0) |
| 129 | continue; |
| 130 | enab = 0; |
| 131 | } |
| 132 | if (dqblk.dqb_ihardlimit && |
| 133 | dqblk.dqb_curinodes >= dqblk.dqb_ihardlimit) |
| 134 | msgi = "File count limit reached on %s"; |
| 135 | else if (enab && dqblk.dqb_iwarn == 0) |
| 136 | msgi = "Out of inode warnings on %s"; |
| 137 | else if (dqblk.dqb_isoftlimit && |
| 138 | dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit) |
| 139 | msgi = "Too many files on %s"; |
| 140 | if (dqblk.dqb_bhardlimit && |
| 141 | dqblk.dqb_curblocks >= dqblk.dqb_bhardlimit) |
| 142 | msgb = "Block limit reached on %s"; |
| 143 | else if (enab && dqblk.dqb_bwarn == 0) |
| 144 | msgb = "Out of block warnings on %s"; |
| 145 | else if (dqblk.dqb_bsoftlimit && |
| 146 | dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit) |
| 147 | msgb = "Over disc quota on %s"; |
| 148 | if (dqblk.dqb_iwarn < MAX_IQ_WARN) |
| 149 | sprintf(iwarn, "%d", dqblk.dqb_iwarn); |
| 150 | else |
| 151 | iwarn[0] = '\0'; |
| 152 | if (dqblk.dqb_bwarn < MAX_DQ_WARN) |
| 153 | sprintf(dwarn, "%d", dqblk.dqb_bwarn); |
| 154 | else |
| 155 | dwarn[0] = '\0'; |
| 156 | if (qflag) { |
| 157 | if (msgi != (char *)0 || msgb != (char *)0) |
| 158 | heading(uid, name); |
| 159 | if (msgi != (char *)0) |
| 160 | xprintf(msgi, fs->fs_file); |
| 161 | if (msgb != (char *)0) |
| 162 | xprintf(msgb, fs->fs_file); |
| 163 | continue; |
| 164 | } |
| 165 | if (vflag || dqblk.dqb_curblocks || dqblk.dqb_curinodes) { |
| 166 | heading(uid, name); |
| 167 | printf("%10s%8d%c%7d%8d%8s%8d%c%7d%8d%8s\n" |
| 168 | , fs->fs_file |
| 169 | , (dqblk.dqb_curblocks / btodb(1024)) |
| 170 | , (msgb == (char *)0) ? ' ' : '*' |
| 171 | , (dqblk.dqb_bsoftlimit / btodb(1024)) |
| 172 | , (dqblk.dqb_bhardlimit / btodb(1024)) |
| 173 | , dwarn |
| 174 | , dqblk.dqb_curinodes |
| 175 | , (msgi == (char *)0) ? ' ' : '*' |
| 176 | , dqblk.dqb_isoftlimit |
| 177 | , dqblk.dqb_ihardlimit |
| 178 | , iwarn |
| 179 | ); |
| 180 | } |
| 181 | } |
| 182 | endfsent(); |
| 183 | if (!done && !qflag) { |
| 184 | if (morethanone) |
| 185 | putchar('\n'); |
| 186 | xprintf("Disc quotas for %s (uid %d):", name, uid); |
| 187 | xprintf("none."); |
| 188 | } |
| 189 | xprintf(0); |
| 190 | } |
| 191 | |
| 192 | heading(uid, name) |
| 193 | int uid; |
| 194 | char *name; |
| 195 | { |
| 196 | |
| 197 | if (done++) |
| 198 | return; |
| 199 | xprintf(0); |
| 200 | if (qflag) { |
| 201 | if (!morethanone) |
| 202 | return; |
| 203 | xprintf("User %s (uid %d):", name, uid); |
| 204 | xprintf(0); |
| 205 | return; |
| 206 | } |
| 207 | putchar('\n'); |
| 208 | xprintf("Disc quotas for %s (uid %d):", name, uid); |
| 209 | xprintf(0); |
| 210 | printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n" |
| 211 | , "Filsys" |
| 212 | , "current" |
| 213 | , "quota" |
| 214 | , "limit" |
| 215 | , "#warns" |
| 216 | , "files" |
| 217 | , "quota" |
| 218 | , "limit" |
| 219 | , "#warns" |
| 220 | ); |
| 221 | } |
| 222 | |
| 223 | xprintf(fmt, arg1, arg2, arg3, arg4, arg5, arg6) |
| 224 | char *fmt; |
| 225 | { |
| 226 | char buf[100]; |
| 227 | static int column; |
| 228 | |
| 229 | if (fmt == 0 && column || column >= 40) { |
| 230 | putchar('\n'); |
| 231 | column = 0; |
| 232 | } |
| 233 | if (fmt == 0) |
| 234 | return; |
| 235 | sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6); |
| 236 | if (column != 0 && strlen(buf) < 39) |
| 237 | while (column++ < 40) |
| 238 | putchar(' '); |
| 239 | else if (column) { |
| 240 | putchar('\n'); |
| 241 | column = 0; |
| 242 | } |
| 243 | printf("%s", buf); |
| 244 | column += strlen(buf); |
| 245 | } |
| 246 | |
| 247 | alldigits(s) |
| 248 | register char *s; |
| 249 | { |
| 250 | register c; |
| 251 | |
| 252 | c = *s++; |
| 253 | do { |
| 254 | if (!isdigit(c)) |
| 255 | return (0); |
| 256 | } while (c = *s++); |
| 257 | return (1); |
| 258 | } |