GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/repquota/repquota.c Lines: 0 171 0.0 %
Date: 2017-11-13 Branches: 0 141 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1980, 1990, 1993
3
 *	The Regents of the University of California.  All rights reserved.
4
 *
5
 * This code is derived from software contributed to Berkeley by
6
 * Robert Elz at The University of Melbourne.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * Quota report
35
 */
36
#include <sys/param.h>	/* dbtob */
37
#include <sys/stat.h>
38
#include <ufs/ufs/quota.h>
39
#include <fstab.h>
40
#include <pwd.h>
41
#include <grp.h>
42
#include <stdio.h>
43
#include <unistd.h>
44
#include <string.h>
45
#include <errno.h>
46
#include <stdlib.h>
47
48
char *qfname = QUOTAFILENAME;
49
char *qfextension[] = INITQFNAMES;
50
51
struct fileusage {
52
	struct	fileusage *fu_next;
53
	struct	dqblk fu_dqblk;
54
	uid_t	fu_id;
55
	char	fu_name[1];
56
	/* actually bigger */
57
};
58
#define FUHASH 1024	/* must be power of two */
59
struct fileusage *fuhead[MAXQUOTAS][FUHASH];
60
struct fileusage *lookup(uid_t, int);
61
struct fileusage *addid(uid_t id, int type, char *name);
62
uid_t highid[MAXQUOTAS];	/* highest addid()'ed identifier per type */
63
64
int	vflag;			/* verbose */
65
int	aflag;			/* all file systems */
66
67
void	usage(void);
68
int	repquota(struct fstab *, int, char *);
69
int	hasquota(struct fstab *, int, char **);
70
int	oneof(char *, char *[], int);
71
char	*timeprt(time_t);
72
int
73
main(int argc, char *argv[])
74
{
75
	struct fstab *fs;
76
	struct passwd *pw;
77
	struct group *gr;
78
	int gflag = 0, uflag = 0, errs = 0;
79
	long i, argnum, done = 0;
80
	extern char *optarg;
81
	extern int optind;
82
	char *qfnp;
83
	int ch;
84
85
	while ((ch = getopt(argc, argv, "aguv")) != -1) {
86
		switch(ch) {
87
		case 'a':
88
			aflag++;
89
			break;
90
		case 'g':
91
			gflag++;
92
			break;
93
		case 'u':
94
			uflag++;
95
			break;
96
		case 'v':
97
			vflag++;
98
			break;
99
		default:
100
			usage();
101
		}
102
	}
103
	argc -= optind;
104
	argv += optind;
105
	if ((argc == 0) == (aflag == 0))
106
		usage();
107
	if (!gflag && !uflag) {
108
		if (aflag)
109
			gflag++;
110
		uflag++;
111
	}
112
	if (gflag) {
113
		setgrent();
114
		while ((gr = getgrent()) != 0)
115
			(void) addid((uid_t)gr->gr_gid, GRPQUOTA, gr->gr_name);
116
		endgrent();
117
	}
118
	if (uflag) {
119
		setpwent();
120
		while ((pw = getpwent()) != 0)
121
			(void) addid(pw->pw_uid, USRQUOTA, pw->pw_name);
122
		endpwent();
123
	}
124
	setfsent();
125
	while ((fs = getfsent()) != NULL) {
126
		if (strcmp(fs->fs_vfstype, "ffs") &&
127
		    strcmp(fs->fs_vfstype, "ufs") &&
128
		    strcmp(fs->fs_vfstype, "mfs"))
129
			continue;
130
		if (aflag) {
131
			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
132
				errs += repquota(fs, GRPQUOTA, qfnp);
133
			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
134
				errs += repquota(fs, USRQUOTA, qfnp);
135
			continue;
136
		}
137
		if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
138
		    (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
139
			done |= 1 << argnum;
140
			if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
141
				errs += repquota(fs, GRPQUOTA, qfnp);
142
			if (uflag && hasquota(fs, USRQUOTA, &qfnp))
143
				errs += repquota(fs, USRQUOTA, qfnp);
144
		}
145
	}
146
	endfsent();
147
	for (i = 0; i < argc; i++)
148
		if ((done & (1 << i)) == 0)
149
			fprintf(stderr, "%s not found in fstab\n", argv[i]);
150
	exit(errs);
151
}
152
153
void
154
usage(void)
155
{
156
	extern char *__progname;
157
	fprintf(stderr, "usage: %s [-aguv] filesystem ...\n", __progname);
158
	exit(1);
159
}
160
161
int
162
repquota(struct fstab *fs, int type, char *qfpathname)
163
{
164
	struct fileusage *fup;
165
	FILE *qf;
166
	uid_t id;
167
	struct dqblk dqbuf;
168
	char *timeprt(time_t);
169
	static struct dqblk zerodqblk;
170
	static int warned = 0;
171
	static int multiple = 0;
172
173
	if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
174
	    errno == EOPNOTSUPP && !warned && vflag) {
175
		warned++;
176
		fprintf(stdout,
177
		    "*** Warning: Quotas are not compiled into this kernel\n");
178
	}
179
	if (multiple++)
180
		printf("\n");
181
	if (vflag)
182
		fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
183
		    qfextension[type], fs->fs_file, fs->fs_spec);
184
	if ((qf = fopen(qfpathname, "r")) == NULL) {
185
		perror(qfpathname);
186
		return (1);
187
	}
188
	for (id = 0; ; id++) {
189
		fread(&dqbuf, sizeof(struct dqblk), 1, qf);
190
		if (feof(qf))
191
			break;
192
		if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
193
			continue;
194
		if ((fup = lookup(id, type)) == 0)
195
			fup = addid(id, type, NULL);
196
		fup->fu_dqblk = dqbuf;
197
	}
198
	fclose(qf);
199
	printf("                        KByte limits               File limits\n");
200
	printf("User            used    soft    hard  grace    used  soft  hard  grace\n");
201
	for (id = 0; id <= highid[type]; id++) {
202
		fup = lookup(id, type);
203
		if (fup == 0)
204
			continue;
205
		if (fup->fu_dqblk.dqb_curinodes == 0 &&
206
		    fup->fu_dqblk.dqb_curblocks == 0)
207
			continue;
208
		printf("%-10s", fup->fu_name);
209
		printf("%c%c %7d %7d %7d %6s",
210
			fup->fu_dqblk.dqb_bsoftlimit &&
211
			    fup->fu_dqblk.dqb_curblocks >=
212
			    fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-',
213
			fup->fu_dqblk.dqb_isoftlimit &&
214
			    fup->fu_dqblk.dqb_curinodes >=
215
			    fup->fu_dqblk.dqb_isoftlimit ? '+' : '-',
216
			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_curblocks)
217
			    / 1024),
218
			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bsoftlimit)
219
			    / 1024),
220
			(int)(dbtob((u_quad_t)fup->fu_dqblk.dqb_bhardlimit)
221
			    / 1024),
222
			fup->fu_dqblk.dqb_bsoftlimit &&
223
			    fup->fu_dqblk.dqb_curblocks >=
224
			    fup->fu_dqblk.dqb_bsoftlimit ?
225
			    timeprt(fup->fu_dqblk.dqb_btime) : "");
226
		printf("  %6d %5d %5d %6s\n",
227
			fup->fu_dqblk.dqb_curinodes,
228
			fup->fu_dqblk.dqb_isoftlimit,
229
			fup->fu_dqblk.dqb_ihardlimit,
230
			fup->fu_dqblk.dqb_isoftlimit &&
231
			    fup->fu_dqblk.dqb_curinodes >=
232
			    fup->fu_dqblk.dqb_isoftlimit ?
233
			    timeprt(fup->fu_dqblk.dqb_itime) : "");
234
		fup->fu_dqblk = zerodqblk;
235
	}
236
	return (0);
237
}
238
239
/*
240
 * Check to see if target appears in list of size cnt.
241
 */
242
int
243
oneof(char *target, char *list[], int cnt)
244
{
245
	int i;
246
247
	for (i = 0; i < cnt; i++)
248
		if (strcmp(target, list[i]) == 0)
249
			return (i);
250
	return (-1);
251
}
252
253
/*
254
 * Check to see if a particular quota is to be enabled.
255
 */
256
int
257
hasquota(struct fstab *fs, int type, char **qfnamep)
258
{
259
	char *opt;
260
	char *cp;
261
	static char initname, usrname[100], grpname[100];
262
	static char buf[BUFSIZ];
263
264
	if (!initname) {
265
		(void)snprintf(usrname, sizeof usrname, "%s%s",
266
		    qfextension[USRQUOTA], qfname);
267
		(void)snprintf(grpname, sizeof grpname, "%s%s",
268
		    qfextension[GRPQUOTA], qfname);
269
		initname = 1;
270
	}
271
	strlcpy(buf, fs->fs_mntops, sizeof buf);
272
	for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
273
		if ((cp = strchr(opt, '=')))
274
			*cp++ = '\0';
275
		if (type == USRQUOTA && strcmp(opt, usrname) == 0)
276
			break;
277
		if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
278
			break;
279
	}
280
	if (!opt)
281
		return (0);
282
	if (cp) {
283
		*qfnamep = cp;
284
		return (1);
285
	}
286
	(void)snprintf(buf, sizeof buf, "%s/%s.%s",
287
	    fs->fs_file, qfname, qfextension[type]);
288
	*qfnamep = buf;
289
	return (1);
290
}
291
292
/*
293
 * Routines to manage the file usage table.
294
 *
295
 * Lookup an id of a specific type.
296
 */
297
struct fileusage *
298
lookup(uid_t id, int type)
299
{
300
	struct fileusage *fup;
301
302
	for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
303
		if (fup->fu_id == id)
304
			return (fup);
305
	return (NULL);
306
}
307
308
/*
309
 * Add a new file usage id if it does not already exist.
310
 */
311
struct fileusage *
312
addid(uid_t id, int type, char *name)
313
{
314
	struct fileusage *fup, **fhp;
315
	size_t len;
316
317
	if ((fup = lookup(id, type)))
318
		return (fup);
319
	if (name)
320
		len = strlen(name);
321
	else
322
		len = 10;
323
	if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) {
324
		fprintf(stderr, "out of memory for fileusage structures\n");
325
		exit(1);
326
	}
327
	fhp = &fuhead[type][id & (FUHASH - 1)];
328
	fup->fu_next = *fhp;
329
	*fhp = fup;
330
	fup->fu_id = id;
331
	if (id > highid[type])
332
		highid[type] = id;
333
	if (name) {
334
		bcopy(name, fup->fu_name, len + 1);
335
	} else {
336
		snprintf(fup->fu_name, len, "%u", id);
337
	}
338
	return (fup);
339
}
340
341
/*
342
 * Calculate the grace period and return a printable string for it.
343
 */
344
char *
345
timeprt(time_t seconds)
346
{
347
	int hours, minutes;
348
	static char buf[20];
349
	static time_t now;
350
351
	if (now == 0)
352
		time(&now);
353
	if (now > seconds)
354
		return ("none");
355
	seconds -= now;
356
	minutes = (seconds + 30) / 60;
357
	hours = (minutes + 30) / 60;
358
	if (hours >= 36) {
359
		snprintf(buf, sizeof buf, "%ddays", (hours + 12) / 24);
360
		return (buf);
361
	}
362
	if (minutes >= 60) {
363
		snprintf(buf, sizeof buf, "%2d:%d", minutes / 60,
364
		    minutes % 60);
365
		return (buf);
366
	}
367
	snprintf(buf, sizeof buf, "%2d", minutes);
368
	return (buf);
369
}