4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
48 #include <sys/param.h>
49 #include <sys/types.h>
51 #include <sys/filio.h>
52 #include <sys/mntent.h>
54 #include <sys/fs/ufs_quota.h>
56 #include <sys/mnttab.h>
57 #include <sys/vfstab.h>
60 #define LOGINNAMESIZE 8
62 struct username
*u_next
;
64 char u_name
[LOGINNAMESIZE
+ 1];
67 static struct username
*uhead
[UHASH
];
69 static struct username
*lookup(uid_t
);
70 static struct username
*adduid(uid_t
);
71 static int repquota(char *, char *, char *);
72 static void prquota(uid_t
, struct dqblk
*);
73 static void header(void);
74 static void usage(void);
75 static void fmttime(char *, long);
76 static char *hasvfsopt(struct vfstab
*, char *);
77 static int quotactl(int, char *, uid_t
, caddr_t
);
78 static int oneof(char *, char **, int);
80 extern char *mntopt();
81 extern char *hasmntopt();
83 static int vflag
; /* verbose */
84 static int aflag
; /* all file systems */
85 static char **listbuf
;
87 #define QFNAME "quotas"
91 #define dbtok(x) ((x) / (1024 / DEV_BSIZE))
93 #define dbtok(x) ((x) * (DEV_BSIZE / 1024))
97 main(int argc
, char **argv
)
100 struct vfstab vfsbuf
;
104 char quotafile
[MAXPATHLEN
];
109 if ((listbuf
= malloc(sizeof (char *) * CHUNK
)) == NULL
) {
110 (void) fprintf(stderr
, "Can't alloc lisbuf array.");
114 while ((opt
= getopt(argc
, argv
, "avV")) != EOF
)
125 /* Print command line */
129 (void) printf("repquota -F ufs ");
130 for (optc
= 1; optc
< argc
; optc
++) {
133 (void) printf(" %s ", optt
);
135 (void) putchar('\n');
144 if (argc
<= optind
&& !aflag
)
148 * Sync quota information to disk (as userdata). On logging
149 * file systems, this operation does nothing because quota
150 * information is treated as metadata. Logging file systems
151 * are dealt with below in repquota().
153 if (quotactl(Q_ALLSYNC
, NULL
, 0, NULL
) < 0 && errno
== EINVAL
&& vflag
)
154 (void) printf("Warning: "
155 "Quotas are not available in this kernel\n");
158 * If aflag go through vfstab and make a list of appropriate
164 if ((vfstab
= fopen(VFSTAB
, "r")) == NULL
) {
165 (void) fprintf(stderr
, "Can't open ");
169 while (getvfsent(vfstab
, &vfsbuf
) == 0) {
171 if (strcmp(vfsbuf
.vfs_fstype
, MNTTYPE_UFS
) != 0 ||
172 (vfsbuf
.vfs_mntopts
== 0) ||
173 hasvfsopt(&vfsbuf
, MNTOPT_RO
) ||
174 (!hasvfsopt(&vfsbuf
, MNTOPT_RQ
) &&
175 !hasvfsopt(&vfsbuf
, MNTOPT_QUOTA
)))
178 *listp
= malloc(strlen(vfsbuf
.vfs_special
) + 1);
179 (void) strcpy(*listp
, vfsbuf
.vfs_special
);
182 /* grow listbuf if needed */
183 if (listcnt
>= listmax
) {
185 listbuf
= reallocarray(listbuf
, listmax
,
187 if (listbuf
== NULL
) {
188 (void) fprintf(stderr
,
189 "Can't grow listbuf.\n");
192 listp
= &listbuf
[listcnt
];
195 (void) fclose(vfstab
);
199 listp
= &argv
[optind
];
200 listcnt
= argc
- optind
;
202 if ((mtab
= fopen(MNTTAB
, "r")) == NULL
) {
203 (void) fprintf(stderr
, "Can't open ");
207 while (getmntent(mtab
, &mntp
) == 0) {
208 if (strcmp(mntp
.mnt_fstype
, MNTTYPE_UFS
) == 0 &&
209 !hasmntopt(&mntp
, MNTOPT_RO
) &&
210 (oneof(mntp
.mnt_special
, listp
, listcnt
) ||
211 oneof(mntp
.mnt_mountp
, listp
, listcnt
))) {
212 (void) snprintf(quotafile
, sizeof (quotafile
), "%s/%s",
213 mntp
.mnt_mountp
, QFNAME
);
214 errs
+= repquota(mntp
.mnt_special
,
215 mntp
.mnt_mountp
, quotafile
);
221 (void) fprintf(stderr
, "Cannot report on %s\n", *listp
);
230 repquota(char *fsdev
, char *fsfile
, char *qffile
)
238 (void) printf("%s (%s):\n", fsdev
, fsfile
);
239 qf
= fopen64(qffile
, "r");
244 if (fstat64(fileno(qf
), &statb
) < 0) {
250 * Flush the file system. On logging file systems, this makes
251 * sure that the quota information (as metadata) gets rolled
254 if (ioctl(fileno(qf
), _FIOFFS
, NULL
) == -1) {
256 (void) fprintf(stderr
, "%s: cannot flush file system.\n",
262 for (uid
= 0; uid
<= MAXUID
&& uid
>= 0; uid
++) {
263 (void) fread(&dqbuf
, sizeof (struct dqblk
), 1, qf
);
267 dqbuf
.dqb_curfiles
== 0 && dqbuf
.dqb_curblocks
== 0)
269 prquota(uid
, &dqbuf
);
278 (void) printf(" Block limits"
280 (void) printf("User used soft hard timeleft"
281 " used soft hard timeleft\n");
285 prquota(uid_t uid
, struct dqblk
*dqp
)
289 char ftimeleft
[80], btimeleft
[80];
291 if (dqp
->dqb_bsoftlimit
== 0 && dqp
->dqb_bhardlimit
== 0 &&
292 dqp
->dqb_fsoftlimit
== 0 && dqp
->dqb_fhardlimit
== 0)
294 (void) time(&(tv
.tv_sec
));
298 (void) printf("%-10s", up
->u_name
);
300 (void) printf("#%-9ld", uid
);
301 if (dqp
->dqb_bsoftlimit
&&
302 dqp
->dqb_curblocks
>= dqp
->dqb_bsoftlimit
) {
303 if (dqp
->dqb_btimelimit
== 0)
304 (void) strcpy(btimeleft
, "NOT STARTED");
305 else if (dqp
->dqb_btimelimit
> tv
.tv_sec
)
307 (long)(dqp
->dqb_btimelimit
- tv
.tv_sec
));
309 (void) strcpy(btimeleft
, "EXPIRED");
313 if (dqp
->dqb_fsoftlimit
&& dqp
->dqb_curfiles
>= dqp
->dqb_fsoftlimit
) {
314 if (dqp
->dqb_ftimelimit
== 0)
315 (void) strcpy(ftimeleft
, "NOT STARTED");
316 else if (dqp
->dqb_ftimelimit
> tv
.tv_sec
)
318 (long)(dqp
->dqb_ftimelimit
- tv
.tv_sec
));
320 (void) strcpy(ftimeleft
, "EXPIRED");
324 (void) printf("%c%c %6lu %6lu %6lu %11s %7lu %6lu %6lu %11s\n",
325 (dqp
->dqb_bsoftlimit
&&
326 dqp
->dqb_curblocks
>= dqp
->dqb_bsoftlimit
) ? '+' : '-',
327 (dqp
->dqb_fsoftlimit
&&
328 dqp
->dqb_curfiles
>= dqp
->dqb_fsoftlimit
) ? '+' : '-',
329 dbtok(dqp
->dqb_curblocks
),
330 dbtok(dqp
->dqb_bsoftlimit
),
331 dbtok(dqp
->dqb_bhardlimit
),
340 fmttime(char *buf
, long time
)
344 int c_secs
; /* conversion units in secs */
345 char *c_str
; /* unit string */
347 {60*60*24*28, "months"},
348 {60*60*24*7, "weeks"},
356 (void) strcpy(buf
, "EXPIRED");
359 for (i
= 0; i
< sizeof (cunits
) / sizeof (cunits
[0]); i
++) {
360 if (time
>= cunits
[i
].c_secs
)
363 (void) sprintf(buf
, "%.1f %s",
364 (double)time
/ cunits
[i
].c_secs
, cunits
[i
].c_str
);
368 oneof(char *target
, char **olistp
, int on
)
370 char **listp
= olistp
;
374 if (*listp
&& strcmp(target
, *listp
) == 0) {
383 static struct username
*
389 for (up
= uhead
[uid
% UHASH
]; up
!= 0; up
= up
->u_next
)
390 if (up
->u_uid
== uid
)
392 if ((pwp
= getpwuid((uid_t
)uid
)) == NULL
)
394 up
= adduid(pwp
->pw_uid
);
395 (void) strncpy(up
->u_name
, pwp
->pw_name
, sizeof (up
->u_name
));
400 * adduid() should *ONLY* be called from lookup in order
401 * to avoid duplicate entries.
403 static struct username
*
406 struct username
*up
, **uhp
;
408 up
= calloc(1, sizeof (struct username
));
410 (void) fprintf(stderr
,
411 "out of memory for username structures\n");
414 uhp
= &uhead
[uid
% UHASH
];
424 (void) fprintf(stderr
, "ufs usage:\n");
425 (void) fprintf(stderr
, "\trepquota [-v] -a \n");
426 (void) fprintf(stderr
, "\trepquota [-v] filesys ...\n");
431 quotactl(int cmd
, char *special
, uid_t uid
, caddr_t addr
)
435 struct quotctl quota
;
436 char qfile
[MAXPATHLEN
];
441 if ((special
== NULL
) && (cmd
== Q_ALLSYNC
)) {
443 * Find the mount point of the special device. This is
444 * because the ioctl that implements the quotactl call has
445 * to go to a real file, and not to the block device.
447 if ((fstab
= fopen(MNTTAB
, "r")) == NULL
) {
448 (void) fprintf(stderr
, "%s: ", MNTTAB
);
453 while ((status
= getmntent(fstab
, &mntp
)) == 0) {
455 if (strcmp(mntp
.mnt_fstype
, MNTTYPE_UFS
) != 0 ||
456 hasmntopt(&mntp
, MNTOPT_RO
))
459 if ((strlcpy(qfile
, mntp
.mnt_mountp
,
460 sizeof (qfile
)) >= sizeof (qfile
)) ||
461 (strlcat(qfile
, "/" QFNAME
, sizeof (qfile
)) >=
466 /* If we find *ANY* valid "quotas" file, use it */
467 if ((fd
= open64(qfile
, O_RDONLY
)) >= 0)
470 (void) fclose(fstab
);
473 (void) printf("quotactl: no quotas file "
474 "on any mounted file system\n");
481 status
= ioctl(fd
, Q_QUOTACTL
, "a
);
487 hasvfsopt(struct vfstab
*vfs
, char *opt
)
490 static char *tmpopts
;
493 tmpopts
= calloc(256, sizeof (char));
497 (void) strcpy(tmpopts
, vfs
->vfs_mntopts
);
500 for (; *f
; f
= mntopt(&opts
)) {
501 if (strncmp(opt
, f
, strlen(opt
)) == 0)
502 return (f
- tmpopts
+ vfs
->vfs_mntopts
);