cleanups, add manual page
[unix-history] / usr / src / usr.bin / quota / quota.c
CommitLineData
2a18434a
KM
1/*
2 * Copyright (c) 1980 Regents of the University of California.
f9ac90b4
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
5e8b0e60
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2a18434a
KM
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1980 Regents of the University of California.\n\
21 All rights reserved.\n";
f9ac90b4 22#endif /* not lint */
2a18434a 23
304d49a2 24#ifndef lint
5e8b0e60 25static char sccsid[] = "@(#)quota.c 5.6 (Berkeley) %G%";
f9ac90b4 26#endif /* not lint */
304d49a2
KM
27
28/*
29 * Disk quota reporting program.
30 */
31#include <stdio.h>
32#include <fstab.h>
33#include <ctype.h>
34#include <pwd.h>
879c30d3 35#include <errno.h>
304d49a2
KM
36
37#include <sys/param.h>
304d49a2
KM
38#include <sys/quota.h>
39#include <sys/file.h>
40#include <sys/stat.h>
41
42int qflag;
43int vflag;
44int done;
45int morethanone;
a233b96c 46char *qfname = "quotas";
304d49a2
KM
47
48main(argc, argv)
49 char *argv[];
50{
51 register char *cp;
879c30d3 52 extern int errno;
304d49a2 53
509d661f 54 if (quota(Q_SYNC, 0, 0, (caddr_t)0) < 0 && errno == EINVAL) {
879c30d3
KM
55 fprintf(stderr, "There are no quotas on this system\n");
56 exit(0);
57 }
304d49a2
KM
58 argc--,argv++;
59 while (argc > 0) {
60 if (argv[0][0] == '-')
61 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
62
63 case 'v':
64 vflag++;
65 break;
66
67 case 'q':
68 qflag++;
69 break;
70
71 default:
72 fprintf(stderr, "quota: %c: unknown option\n",
73 *cp);
74 exit(1);
75 }
76 else
77 break;
78 argc--, argv++;
79 }
80 morethanone = argc > 1;
81 if (argc == 0) {
82 showuid(getuid());
83 exit(0);
84 }
85 for (; argc > 0; argc--, argv++) {
86 if (alldigits(*argv))
87 showuid(atoi(*argv));
88 else
89 showname(*argv);
90 }
91}
92
93showuid(uid)
94 int uid;
95{
96 struct passwd *pwd = getpwuid(uid);
97
98 if (pwd == NULL)
99 showquotas(uid, "(no account)");
100 else
101 showquotas(uid, pwd->pw_name);
102}
103
104showname(name)
105 char *name;
106{
107 struct passwd *pwd = getpwnam(name);
108
109 if (pwd == NULL) {
110 fprintf(stderr, "quota: %s: unknown user\n", name);
111 return;
112 }
113 showquotas(pwd->pw_uid, name);
114}
115
116showquotas(uid, name)
117 int uid;
118 char *name;
119{
304d49a2 120 register struct fstab *fs;
509d661f 121 register char *msgi, *msgb;
879c30d3
KM
122 register enab = 1;
123 dev_t fsdev;
124 struct stat statb;
125 struct dqblk dqblk;
126 int myuid, fd;
127 char qfilename[MAXPATHLEN + 1], iwarn[8], dwarn[8];
304d49a2
KM
128
129 myuid = getuid();
130 if (uid != myuid && myuid != 0) {
131 printf("quota: %s (uid %d): permission denied\n", name, uid);
132 return;
133 }
134 done = 0;
509d661f 135 (void) setfsent();
304d49a2 136 while (fs = getfsent()) {
304d49a2
KM
137 if (stat(fs->fs_spec, &statb) < 0)
138 continue;
509d661f 139 msgi = msgb = (char *) 0;
304d49a2 140 fsdev = statb.st_rdev;
a233b96c
KM
141 (void) sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
142 if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
304d49a2 143 continue;
509d661f 144 if (quota(Q_GETDLIM, uid, fsdev, (caddr_t)&dqblk) != 0) {
879c30d3 145 fd = open(qfilename, O_RDONLY);
304d49a2
KM
146 if (fd < 0)
147 continue;
509d661f
JL
148 (void) lseek(fd, (off_t)(uid * sizeof (dqblk)), L_SET);
149 switch (read(fd, (char *)&dqblk, sizeof dqblk)) {
605f81f3
S
150 case 0: /* EOF */
151 /*
152 * Convert implicit 0 quota (EOF)
153 * into an explicit one (zero'ed dqblk).
154 */
155 bzero((caddr_t)&dqblk, sizeof dqblk);
156 break;
157
158 case sizeof dqblk: /* OK */
159 break;
160
161 default: /* ERROR */
162 fprintf(stderr, "quota: read error in ");
163 perror(qfilename);
509d661f 164 (void) close(fd);
304d49a2
KM
165 continue;
166 }
509d661f 167 (void) close(fd);
605f81f3 168 if (!vflag && dqblk.dqb_isoftlimit == 0 &&
304d49a2
KM
169 dqblk.dqb_bsoftlimit == 0)
170 continue;
171 enab = 0;
172 }
173 if (dqblk.dqb_ihardlimit &&
174 dqblk.dqb_curinodes >= dqblk.dqb_ihardlimit)
175 msgi = "File count limit reached on %s";
176 else if (enab && dqblk.dqb_iwarn == 0)
177 msgi = "Out of inode warnings on %s";
178 else if (dqblk.dqb_isoftlimit &&
179 dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit)
180 msgi = "Too many files on %s";
181 if (dqblk.dqb_bhardlimit &&
182 dqblk.dqb_curblocks >= dqblk.dqb_bhardlimit)
183 msgb = "Block limit reached on %s";
184 else if (enab && dqblk.dqb_bwarn == 0)
185 msgb = "Out of block warnings on %s";
186 else if (dqblk.dqb_bsoftlimit &&
187 dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit)
188 msgb = "Over disc quota on %s";
189 if (dqblk.dqb_iwarn < MAX_IQ_WARN)
509d661f 190 (void) sprintf(iwarn, "%d", dqblk.dqb_iwarn);
304d49a2
KM
191 else
192 iwarn[0] = '\0';
193 if (dqblk.dqb_bwarn < MAX_DQ_WARN)
509d661f 194 (void) sprintf(dwarn, "%d", dqblk.dqb_bwarn);
304d49a2
KM
195 else
196 dwarn[0] = '\0';
197 if (qflag) {
198 if (msgi != (char *)0 || msgb != (char *)0)
199 heading(uid, name);
200 if (msgi != (char *)0)
201 xprintf(msgi, fs->fs_file);
202 if (msgb != (char *)0)
203 xprintf(msgb, fs->fs_file);
204 continue;
205 }
206 if (vflag || dqblk.dqb_curblocks || dqblk.dqb_curinodes) {
207 heading(uid, name);
c085c6e0 208 printf("%10s%8d%c%7d%8d%8s%8d%c%7d%8d%8s\n"
304d49a2 209 , fs->fs_file
285a6d40 210 , dbtob(dqblk.dqb_curblocks) / 1024
304d49a2 211 , (msgb == (char *)0) ? ' ' : '*'
285a6d40
JB
212 , dbtob(dqblk.dqb_bsoftlimit) / 1024
213 , dbtob(dqblk.dqb_bhardlimit) / 1024
304d49a2
KM
214 , dwarn
215 , dqblk.dqb_curinodes
216 , (msgi == (char *)0) ? ' ' : '*'
217 , dqblk.dqb_isoftlimit
96b539f0 218 , dqblk.dqb_ihardlimit
304d49a2
KM
219 , iwarn
220 );
221 }
222 }
509d661f 223 (void) endfsent();
304d49a2
KM
224 if (!done && !qflag) {
225 if (morethanone)
509d661f 226 (void) putchar('\n');
304d49a2
KM
227 xprintf("Disc quotas for %s (uid %d):", name, uid);
228 xprintf("none.");
229 }
605f81f3 230 xprintf((char *)0);
304d49a2
KM
231}
232
233heading(uid, name)
234 int uid;
235 char *name;
236{
237
238 if (done++)
239 return;
605f81f3 240 xprintf((char *)0);
304d49a2
KM
241 if (qflag) {
242 if (!morethanone)
243 return;
244 xprintf("User %s (uid %d):", name, uid);
605f81f3 245 xprintf((char *)0);
304d49a2
KM
246 return;
247 }
509d661f 248 (void) putchar('\n');
304d49a2 249 xprintf("Disc quotas for %s (uid %d):", name, uid);
605f81f3 250 xprintf((char *)0);
c085c6e0 251 printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n"
304d49a2
KM
252 , "Filsys"
253 , "current"
254 , "quota"
255 , "limit"
256 , "#warns"
257 , "files"
258 , "quota"
259 , "limit"
260 , "#warns"
261 );
262}
263
605f81f3 264/*VARARGS1*/
304d49a2
KM
265xprintf(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
266 char *fmt;
267{
268 char buf[100];
269 static int column;
270
271 if (fmt == 0 && column || column >= 40) {
509d661f 272 (void) putchar('\n');
304d49a2
KM
273 column = 0;
274 }
275 if (fmt == 0)
276 return;
509d661f 277 (void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
304d49a2
KM
278 if (column != 0 && strlen(buf) < 39)
279 while (column++ < 40)
509d661f 280 (void) putchar(' ');
304d49a2 281 else if (column) {
509d661f 282 (void) putchar('\n');
304d49a2
KM
283 column = 0;
284 }
285 printf("%s", buf);
286 column += strlen(buf);
287}
288
289alldigits(s)
290 register char *s;
291{
292 register c;
293
294 c = *s++;
295 do {
296 if (!isdigit(c))
297 return (0);
298 } while (c = *s++);
299 return (1);
300}