xref: /original-bsd/usr.bin/quota/quota.c (revision 94c97675)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
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.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)quota.c	5.6 (Berkeley) 06/29/88";
26 #endif /* not lint */
27 
28 /*
29  * Disk quota reporting program.
30  */
31 #include <stdio.h>
32 #include <fstab.h>
33 #include <ctype.h>
34 #include <pwd.h>
35 #include <errno.h>
36 
37 #include <sys/param.h>
38 #include <sys/quota.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 
42 int	qflag;
43 int	vflag;
44 int	done;
45 int	morethanone;
46 char	*qfname = "quotas";
47 
48 main(argc, argv)
49 	char *argv[];
50 {
51 	register char *cp;
52 	extern int errno;
53 
54 	if (quota(Q_SYNC, 0, 0, (caddr_t)0) < 0 && errno == EINVAL) {
55 		fprintf(stderr, "There are no quotas on this system\n");
56 		exit(0);
57 	}
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 
93 showuid(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 
104 showname(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 
116 showquotas(uid, name)
117 	int uid;
118 	char *name;
119 {
120 	register struct fstab *fs;
121 	register char *msgi, *msgb;
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];
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;
135 	(void) setfsent();
136 	while (fs = getfsent()) {
137 		if (stat(fs->fs_spec, &statb) < 0)
138 			continue;
139 		msgi = msgb = (char *) 0;
140 		fsdev = statb.st_rdev;
141 		(void) sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
142 		if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
143 			continue;
144 		if (quota(Q_GETDLIM, uid, fsdev, (caddr_t)&dqblk) != 0) {
145 			fd = open(qfilename, O_RDONLY);
146 			if (fd < 0)
147 				continue;
148 			(void) lseek(fd, (off_t)(uid * sizeof (dqblk)), L_SET);
149 			switch (read(fd, (char *)&dqblk, sizeof dqblk)) {
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);
164 				(void) close(fd);
165 				continue;
166 			}
167 			(void) close(fd);
168 			if (!vflag && dqblk.dqb_isoftlimit == 0 &&
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)
190 			(void) sprintf(iwarn, "%d", dqblk.dqb_iwarn);
191 		else
192 			iwarn[0] = '\0';
193 		if (dqblk.dqb_bwarn < MAX_DQ_WARN)
194 			(void) sprintf(dwarn, "%d", dqblk.dqb_bwarn);
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);
208 			printf("%10s%8d%c%7d%8d%8s%8d%c%7d%8d%8s\n"
209 				, fs->fs_file
210 				, dbtob(dqblk.dqb_curblocks) / 1024
211 				, (msgb == (char *)0) ? ' ' : '*'
212 				, dbtob(dqblk.dqb_bsoftlimit) / 1024
213 				, dbtob(dqblk.dqb_bhardlimit) / 1024
214 				, dwarn
215 				, dqblk.dqb_curinodes
216 				, (msgi == (char *)0) ? ' ' : '*'
217 				, dqblk.dqb_isoftlimit
218 				, dqblk.dqb_ihardlimit
219 				, iwarn
220 			);
221 		}
222 	}
223 	(void) endfsent();
224 	if (!done && !qflag) {
225 		if (morethanone)
226 			(void) putchar('\n');
227 		xprintf("Disc quotas for %s (uid %d):", name, uid);
228 		xprintf("none.");
229 	}
230 	xprintf((char *)0);
231 }
232 
233 heading(uid, name)
234 	int uid;
235 	char *name;
236 {
237 
238 	if (done++)
239 		return;
240 	xprintf((char *)0);
241 	if (qflag) {
242 		if (!morethanone)
243 			return;
244 		xprintf("User %s (uid %d):", name, uid);
245 		xprintf((char *)0);
246 		return;
247 	}
248 	(void) putchar('\n');
249 	xprintf("Disc quotas for %s (uid %d):", name, uid);
250 	xprintf((char *)0);
251 	printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n"
252 		, "Filsys"
253 		, "current"
254 		, "quota"
255 		, "limit"
256 		, "#warns"
257 		, "files"
258 		, "quota"
259 		, "limit"
260 		, "#warns"
261 	);
262 }
263 
264 /*VARARGS1*/
265 xprintf(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) {
272 		(void) putchar('\n');
273 		column = 0;
274 	}
275 	if (fmt == 0)
276 		return;
277 	(void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
278 	if (column != 0 && strlen(buf) < 39)
279 		while (column++ < 40)
280 			(void) putchar(' ');
281 	else if (column) {
282 		(void) putchar('\n');
283 		column = 0;
284 	}
285 	printf("%s", buf);
286 	column += strlen(buf);
287 }
288 
289 alldigits(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 }
301