]> git.cameronkatri.com Git - apple_cmds.git/blob - diskdev_cmds/quota.tproj/quota.c
md5: Don't symlink non working bins, setuid appropriate bins
[apple_cmds.git] / diskdev_cmds / quota.tproj / quota.c
1 /*
2 * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1980, 1990, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Robert Elz at The University of Melbourne.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59
60 /*
61 * Disk quota reporting program.
62 */
63 #include <sys/param.h>
64 #include <sys/file.h>
65 #ifdef __APPLE__
66 #include <sys/mount.h>
67 #endif /* __APPLE */
68 #include <sys/stat.h>
69 #include <sys/queue.h>
70
71 #include <sys/quota.h>
72 #include <libkern/OSByteOrder.h>
73
74 #include <ctype.h>
75 #include <errno.h>
76 #include <fstab.h>
77 #include <grp.h>
78 #include <pwd.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <unistd.h>
83
84 char *qfname = QUOTAFILENAME;
85 char *qfextension[] = INITQFNAMES;
86
87 #ifdef __APPLE__
88 u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
89 #endif /* __APPLE__ */
90
91 struct quotause {
92 struct quotause *next;
93 long flags;
94 struct dqblk dqblk;
95 char fsname[MAXPATHLEN + 1];
96 } *getprivs();
97 #define FOUND 0x01
98
99 int qflag;
100 int vflag;
101
102 int alldigits __P((char *));
103 int hasquota __P((struct statfs *, int, char **));
104 void heading __P((int, u_long, char *, char *));
105 void showgid __P((u_long));
106 void showuid __P((u_long));
107 void showgrpname __P((char *));
108 void showquotas __P((int, u_long, char *));
109 void showusrname __P((char *));
110 void usage __P((void));
111
112 #ifdef __APPLE__
113 int qflookup(int, u_long, int, struct dqblk *);
114 #endif /* __APPLE__ */
115
116 int
117 main(argc, argv)
118 char *argv[];
119 {
120 int ngroups;
121 gid_t gidset[NGROUPS];
122 int i, gflag = 0, uflag = 0;
123 char ch;
124
125 #if 0
126 if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == ENOTSUP) {
127 fprintf(stderr, "There are no quotas on this system\n");
128 exit(0);
129 }
130 #endif
131
132 while ((ch = getopt(argc, argv, "ugvq")) != EOF) {
133 switch(ch) {
134 case 'g':
135 gflag++;
136 break;
137 case 'u':
138 uflag++;
139 break;
140 case 'v':
141 vflag++;
142 break;
143 case 'q':
144 qflag++;
145 break;
146 default:
147 usage();
148 }
149 }
150 argc -= optind;
151 argv += optind;
152 if (!uflag && !gflag)
153 uflag++;
154 if (argc == 0) {
155 if (uflag)
156 showuid(getuid());
157 if (gflag) {
158 ngroups = getgroups(NGROUPS, gidset);
159 if (ngroups < 0) {
160 perror("quota: getgroups");
161 exit(1);
162 }
163 for (i = 1; i < ngroups; i++)
164 showgid(gidset[i]);
165 }
166 exit(0);
167 }
168 if (uflag && gflag)
169 usage();
170 if (uflag) {
171 for (; argc > 0; argc--, argv++) {
172 if (alldigits(*argv))
173 showuid(atoi(*argv));
174 else
175 showusrname(*argv);
176 }
177 exit(0);
178 }
179 if (gflag) {
180 for (; argc > 0; argc--, argv++) {
181 if (alldigits(*argv))
182 showgid(atoi(*argv));
183 else
184 showgrpname(*argv);
185 }
186 exit(0);
187 }
188 exit(0);
189 }
190
191 void
192 usage()
193 {
194
195 fprintf(stderr, "%s\n%s\n%s\n",
196 "Usage: quota [-guqv]",
197 "\tquota [-qv] -u username ...",
198 "\tquota [-qv] -g groupname ...");
199 exit(1);
200 }
201
202 /*
203 * Print out quotas for a specified user identifier.
204 */
205 void
206 showuid(uid)
207 u_long uid;
208 {
209 struct passwd *pwd = getpwuid(uid);
210 u_long myuid;
211 char *name;
212
213 if (pwd == NULL)
214 name = "(no account)";
215 else
216 name = pwd->pw_name;
217 myuid = getuid();
218 if (uid != myuid && myuid != 0) {
219 printf("quota: %s (uid %ld): permission denied\n", name, uid);
220 return;
221 }
222 showquotas(USRQUOTA, uid, name);
223 }
224
225 /*
226 * Print out quotas for a specifed user name.
227 */
228 void
229 showusrname(name)
230 char *name;
231 {
232 struct passwd *pwd = getpwnam(name);
233 u_long myuid;
234
235 if (pwd == NULL) {
236 fprintf(stderr, "quota: %s: unknown user\n", name);
237 return;
238 }
239 myuid = getuid();
240 if (pwd->pw_uid != myuid && myuid != 0) {
241 fprintf(stderr, "quota: %s (uid %d): permission denied\n",
242 name, pwd->pw_uid);
243 return;
244 }
245 showquotas(USRQUOTA, pwd->pw_uid, name);
246 }
247
248 /*
249 * Print out quotas for a specified group identifier.
250 */
251 void
252 showgid(gid)
253 u_long gid;
254 {
255 struct group *grp = getgrgid(gid);
256 int ngroups;
257 gid_t gidset[NGROUPS];
258 register int i;
259 char *name;
260
261 if (grp == NULL)
262 name = "(no entry)";
263 else
264 name = grp->gr_name;
265 ngroups = getgroups(NGROUPS, gidset);
266 if (ngroups < 0) {
267 perror("quota: getgroups");
268 return;
269 }
270 for (i = 1; i < ngroups; i++)
271 if (gid == gidset[i])
272 break;
273 if (i >= ngroups && getuid() != 0) {
274 fprintf(stderr, "quota: %s (gid %ld): permission denied\n",
275 name, gid);
276 return;
277 }
278 showquotas(GRPQUOTA, gid, name);
279 }
280
281 /*
282 * Print out quotas for a specifed group name.
283 */
284 void
285 showgrpname(name)
286 char *name;
287 {
288 struct group *grp = getgrnam(name);
289 int ngroups;
290 gid_t gidset[NGROUPS];
291 register int i;
292
293 if (grp == NULL) {
294 fprintf(stderr, "quota: %s: unknown group\n", name);
295 return;
296 }
297 ngroups = getgroups(NGROUPS, gidset);
298 if (ngroups < 0) {
299 perror("quota: getgroups");
300 return;
301 }
302 for (i = 1; i < ngroups; i++)
303 if (grp->gr_gid == gidset[i])
304 break;
305 if (i >= ngroups && getuid() != 0) {
306 fprintf(stderr, "quota: %s (gid %d): permission denied\n",
307 name, grp->gr_gid);
308 return;
309 }
310 showquotas(GRPQUOTA, grp->gr_gid, name);
311 }
312
313 void
314 showquotas(type, id, name)
315 int type;
316 u_long id;
317 char *name;
318 {
319 register struct quotause *qup;
320 struct quotause *quplist, *getprivs();
321 char *msgi, *msgb, *timeprt();
322 int lines = 0;
323 static time_t now;
324
325 if (now == 0)
326 time(&now);
327 quplist = getprivs(id, type);
328 for (qup = quplist; qup; qup = qup->next) {
329 if (!vflag &&
330 qup->dqblk.dqb_isoftlimit == 0 &&
331 qup->dqblk.dqb_ihardlimit == 0 &&
332 qup->dqblk.dqb_bsoftlimit == 0 &&
333 qup->dqblk.dqb_bhardlimit == 0)
334 continue;
335 msgi = (char *)0;
336 if (qup->dqblk.dqb_ihardlimit &&
337 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) {
338 msgi = "File limit reached on";
339 } else if (qup->dqblk.dqb_isoftlimit &&
340 qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) {
341 if (qup->dqblk.dqb_itime > now) {
342 msgi = "In file grace period on";
343 } else {
344 msgi = "Over file quota on";
345 }
346 }
347 msgb = (char *)0;
348 #ifdef __APPLE__
349 if (qup->dqblk.dqb_bhardlimit &&
350 qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bhardlimit) {
351 msgb = "Block limit reached on";
352 } else if (qup->dqblk.dqb_bsoftlimit &&
353 qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bsoftlimit) {
354 if (qup->dqblk.dqb_btime > now) {
355 msgb = "In block grace period on";
356 } else {
357 msgb = "Over block quota on";
358 }
359 }
360 #else
361 if (qup->dqblk.dqb_bhardlimit &&
362 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) {
363 msgb = "Block limit reached on";
364 } else if (qup->dqblk.dqb_bsoftlimit &&
365 qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) {
366 if (qup->dqblk.dqb_btime > now) {
367 msgb = "In block grace period on";
368 } else {
369 msgb = "Over block quota on";
370 }
371 }
372 #endif /* __APPLE__ */
373
374 if (qflag) {
375 if ((msgi != (char *)0 || msgb != (char *)0) &&
376 lines++ == 0)
377 heading(type, id, name, "");
378 if (msgi != (char *)0)
379 printf("\t%s %s\n", msgi, qup->fsname);
380 if (msgb != (char *)0)
381 printf("\t%s %s\n", msgb, qup->fsname);
382 continue;
383 }
384 #ifdef __APPLE__
385 if (vflag ||
386 qup->dqblk.dqb_curbytes ||
387 qup->dqblk.dqb_curinodes) {
388 if (lines++ == 0)
389 heading(type, id, name, "");
390
391 printf("%15s %12qd%c %12qd %12qd %8s"
392 , qup->fsname
393 , qup->dqblk.dqb_curbytes / 1024
394 , (msgb == (char *)0) ? ' ' : '*'
395 , qup->dqblk.dqb_bsoftlimit / 1024
396 , qup->dqblk.dqb_bhardlimit / 1024
397 , (msgb == (char *)0) ? ""
398 : timeprt(qup->dqblk.dqb_btime));
399 #else
400 if (vflag ||
401 qup->dqblk.dqb_curblocks ||
402 qup->dqblk.dqb_curinodes) {
403 if (lines++ == 0)
404 heading(type, id, name, "");
405
406 printf("%15s%8d%c%7d%8d%8s"
407 , qup->fsname
408 , dbtob(qup->dqblk.dqb_curblocks) / 1024
409 , (msgb == (char *)0) ? ' ' : '*'
410 , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024
411 , dbtob(qup->dqblk.dqb_bhardlimit) / 1024
412 , (msgb == (char *)0) ? ""
413 : timeprt(qup->dqblk.dqb_btime));
414 #endif /* __APPLE__ */
415 printf("%8d%c%7d%8d%8s\n"
416 , qup->dqblk.dqb_curinodes
417 , (msgi == (char *)0) ? ' ' : '*'
418 , qup->dqblk.dqb_isoftlimit
419 , qup->dqblk.dqb_ihardlimit
420 , (msgi == (char *)0) ? ""
421 : timeprt(qup->dqblk.dqb_itime)
422 );
423 continue;
424 }
425 }
426 if (!qflag && lines == 0)
427 heading(type, id, name, "none");
428 }
429
430 void
431 heading(type, id, name, tag)
432 int type;
433 u_long id;
434 char *name, *tag;
435 {
436
437 printf("Disk quotas for %s %s (%cid %ld): %s\n", qfextension[type],
438 name, *qfextension[type], id, tag);
439 if (!qflag && tag[0] == '\0') {
440 #ifdef __APPLE__
441 printf("%15s %12s %12s %12s %8s%8s %7s%8s%8s\n"
442 , "Filesystem"
443 , "1K blocks"
444 #else
445 printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
446 , "Filesystem"
447 , "blocks"
448 #endif /* __APPLE __*/
449 , "quota"
450 , "limit"
451 , "grace"
452 , "files"
453 , "quota"
454 , "limit"
455 , "grace"
456 );
457 }
458 }
459
460 /*
461 * Calculate the grace period and return a printable string for it.
462 */
463 char *
464 timeprt(seconds)
465 time_t seconds;
466 {
467 time_t hours, minutes;
468 static char buf[20];
469 static time_t now;
470
471 if (now == 0)
472 time(&now);
473 if (now > seconds)
474 return ("none");
475 seconds -= now;
476 minutes = (seconds + 30) / 60;
477 hours = (minutes + 30) / 60;
478 if (hours >= 36) {
479 snprintf(buf, sizeof(buf), "%ddays", (int)((hours + 12) / 24));
480 return (buf);
481 }
482 if (minutes >= 60) {
483 snprintf(buf, sizeof(buf), "%2d:%d", (int)(minutes / 60), (int)(minutes % 60));
484 return (buf);
485 }
486 snprintf(buf, sizeof(buf), "%2d", (int)minutes);
487 return (buf);
488 }
489
490 typedef struct {
491 int alloced;
492 int nels;
493 char **strings;
494 } mount_list_t;
495
496 static void *
497 init_list(int max)
498 {
499 mount_list_t *retval = NULL;
500 retval = malloc(sizeof(*retval));
501 if (retval) {
502 retval->strings = malloc(sizeof(char*) * max);
503 if (retval->strings) {
504 retval->alloced = max;
505 } else {
506 retval->alloced = 0;
507 }
508 retval->nels = 0;
509 }
510 return retval;
511 }
512 static void
513 free_list(void *list)
514 {
515 mount_list_t *tmp = list;
516 int i;
517
518 if (tmp == NULL)
519 return;
520 for (i = 0; i < tmp->nels; i++) {
521 free(tmp->strings[i]);
522 }
523 free(tmp);
524 return;
525 }
526
527 static int
528 hasseen(void *tmp, const char *mp)
529 {
530 int retval = 0;
531 mount_list_t *list = tmp;
532 int i;
533
534 if (tmp == NULL || mp == NULL)
535 goto done;
536
537 /*
538 * This could also be a binary search, but then we'd have to sort
539 * after each addition. We may want to change the behaviour based
540 * on the number of elements in the array.
541 */
542
543 for (i = 0; i < list->nels; i++) {
544 if (strcmp(list->strings[i], mp) == 0) {
545 retval = 1;
546 goto done;
547 }
548 }
549 if (list->nels <= list->alloced) {
550 char **a = realloc(list->strings, (list->alloced + 10) * sizeof(char*));
551 if (a) {
552 list->alloced = list->alloced + 10;
553 list->strings = a;
554 } else {
555 goto done;
556 }
557 }
558 list->strings[list->nels++] = strdup(mp);
559
560 done:
561 return retval;
562 }
563
564 /*
565 * Collect the requested quota information.
566 */
567 #ifdef __APPLE__
568 struct quotause *
569 getprivs(id, quotatype)
570 register long id;
571 int quotatype;
572 {
573 struct statfs *fst;
574 register struct quotause *qup, *quptail;
575 struct quotause *quphead;
576 struct dqblk dqb;
577 char *qfpathname;
578 int qcmd, fd;
579 int nfst, i;
580 int error;
581 void *cache;
582
583 quptail = quphead = (struct quotause *)0;
584 qcmd = QCMD(Q_GETQUOTA, quotatype);
585
586 nfst = getmntinfo(&fst, MNT_WAIT);
587 if (nfst==0) {
588 fprintf(stderr, "quota: no mounted filesystems\n");
589 exit(1);
590 }
591
592 cache = init_list(nfst);
593
594 for (i=0; i<nfst; i++) {
595 if (hasseen(cache, fst[i].f_mntonname))
596 continue;
597 error = quotactl(fst[i].f_mntonname, qcmd, id, (char *)&dqb);
598 if (error) {
599 if (strcmp(fst[i].f_fstypename, "hfs"))
600 continue;
601 if (!hasquota(&fst[i], quotatype, &qfpathname))
602 continue;
603 }
604 if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
605 fprintf(stderr, "quota: out of memory\n");
606 exit(2);
607 }
608 if (!error) {
609 bcopy(&dqb, &qup->dqblk, sizeof(dqb));
610 } else {
611 if ((fd = open(qfpathname, O_RDONLY)) < 0) {
612 perror(qfpathname);
613 free(qup);
614 continue;
615 }
616 if ((error = qflookup(fd, id, quotatype, &qup->dqblk))) {
617 perror(qfpathname);
618 close(fd);
619 free(qup);
620 continue;
621 }
622 close(fd);
623 }
624 strlcpy(qup->fsname, fst[i].f_mntonname, sizeof(qup->fsname));
625 if (quphead == NULL)
626 quphead = qup;
627 else
628 quptail->next = qup;
629 quptail = qup;
630 qup->next = 0;
631 }
632 free_list(cache);
633
634 return (quphead);
635 }
636 #else
637 struct quotause *
638 getprivs(id, quotatype)
639 register long id;
640 int quotatype;
641 {
642 register struct fstab *fs;
643 register struct quotause *qup, *quptail;
644 struct quotause *quphead;
645 char *qfpathname;
646 int qcmd, fd;
647
648 setfsent();
649 quphead = (struct quotause *)0;
650 qcmd = QCMD(Q_GETQUOTA, quotatype);
651 while (fs = getfsent()) {
652 if (strcmp(fs->fs_vfstype, "ufs"))
653 continue;
654 if (!hasquota(fs, quotatype, &qfpathname))
655 continue;
656 if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
657 fprintf(stderr, "quota: out of memory\n");
658 exit(2);
659 }
660 if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
661 if ((fd = open(qfpathname, O_RDONLY)) < 0) {
662 perror(qfpathname);
663 free(qup);
664 continue;
665 }
666 lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
667 switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
668 case 0: /* EOF */
669 /*
670 * Convert implicit 0 quota (EOF)
671 * into an explicit one (zero'ed dqblk)
672 */
673 bzero((caddr_t)&qup->dqblk,
674 sizeof(struct dqblk));
675 break;
676
677 case sizeof(struct dqblk): /* OK */
678 break;
679
680 default: /* ERROR */
681 fprintf(stderr, "quota: read error");
682 perror(qfpathname);
683 close(fd);
684 free(qup);
685 continue;
686 }
687 close(fd);
688 }
689 strlcpy(qup->fsname, fs->fs_file, sizeof(qup->fsname));
690
691 if (quphead == NULL)
692 quphead = qup;
693 else
694 quptail->next = qup;
695 quptail = qup;
696 qup->next = 0;
697 }
698 endfsent();
699 return (quphead);
700 }
701 #endif /* __APPLE__ */
702
703
704 #ifdef __APPLE__
705 /*
706 * Lookup an entry in the quota file.
707 */
708 int
709 qflookup(fd, id, type, dqbp)
710 int fd;
711 u_long id;
712 int type;
713 struct dqblk *dqbp;
714 {
715 struct dqfilehdr dqhdr;
716 int i, skip, last, m;
717 u_long mask;
718
719 bzero(dqbp, sizeof(struct dqblk));
720
721 if (id == 0)
722 return (0);
723
724 lseek(fd, 0, L_SET);
725 if (read(fd, &dqhdr, sizeof(struct dqfilehdr)) != sizeof(struct dqfilehdr)) {
726 fprintf(stderr, "quota: read error\n");
727 return (errno);
728 }
729
730 /* Sanity check the quota file header. */
731 if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
732 (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) ||
733 (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
734 fprintf(stderr, "quota: invalid quota file header\n");
735 return (EINVAL);
736 }
737
738 m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
739 mask = m - 1;
740 i = dqhash1(id, dqhashshift(m), mask);
741 skip = dqhash2(id, mask);
742
743 for (last = (i + (m-1) * skip) & mask;
744 i != last;
745 i = (i + skip) & mask) {
746 lseek(fd, dqoffset(i), L_SET);
747 if (read(fd, dqbp, sizeof(struct dqblk)) < sizeof(struct dqblk)) {
748 fprintf(stderr, "quota: read error at index %d\n", i);
749 return (errno);
750 }
751 /*
752 * Stop when an empty entry is found
753 * or we encounter a matching id.
754 */
755 if (dqbp->dqb_id == 0 || OSSwapBigToHostInt32(dqbp->dqb_id) == id)
756 break;
757 }
758 /* Put data in host native byte order. */
759 dqbp->dqb_bhardlimit = OSSwapBigToHostInt64(dqbp->dqb_bhardlimit);
760 dqbp->dqb_bsoftlimit = OSSwapBigToHostInt64(dqbp->dqb_bsoftlimit);
761 dqbp->dqb_curbytes = OSSwapBigToHostInt64(dqbp->dqb_curbytes);
762 dqbp->dqb_ihardlimit = OSSwapBigToHostInt32(dqbp->dqb_ihardlimit);
763 dqbp->dqb_isoftlimit = OSSwapBigToHostInt32(dqbp->dqb_isoftlimit);
764 dqbp->dqb_curinodes = OSSwapBigToHostInt32(dqbp->dqb_curinodes);
765 dqbp->dqb_btime = OSSwapBigToHostInt32(dqbp->dqb_btime);
766 dqbp->dqb_itime = OSSwapBigToHostInt32(dqbp->dqb_itime);
767 dqbp->dqb_id = OSSwapBigToHostInt32(dqbp->dqb_id);
768
769 return (0);
770 }
771 #endif /* __APPLE__ */
772
773
774 /*
775 * Check to see if a particular quota is to be enabled.
776 */
777 #ifdef __APPLE__
778 int
779 hasquota(fst, type, qfnamep)
780 register struct statfs *fst;
781 int type;
782 char **qfnamep;
783 {
784 struct stat sb;
785 static char initname, usrname[100], grpname[100];
786 static char buf[BUFSIZ];
787
788 if (!initname) {
789 snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
790 snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
791 initname = 1;
792 }
793 /*
794 We only support the default path to the
795 on disk quota files.
796 */
797
798 (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
799 QUOTAOPSNAME, qfextension[type] );
800 if (stat(buf, &sb) != 0) {
801 /* There appears to be no mount option file */
802 return(0);
803 }
804
805 (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
806 *qfnamep = buf;
807 return (1);
808 }
809 #else
810 hasquota(fs, type, qfnamep)
811 register struct fstab *fs;
812 int type;
813 char **qfnamep;
814 {
815 register char *opt;
816 char *cp, *index(), *strtok();
817 static char initname, usrname[100], grpname[100];
818 static char buf[BUFSIZ];
819
820 if (!initname) {
821 snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
822 snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
823 initname = 1;
824 }
825 strlcpy(buf, fs->fs_mntops, sizeof(buf));
826 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
827 if (cp = index(opt, '='))
828 *cp++ = '\0';
829 if (type == USRQUOTA && strcmp(opt, usrname) == 0)
830 break;
831 if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
832 break;
833 }
834 if (!opt)
835 return (0);
836 if (cp) {
837 *qfnamep = cp;
838 return (1);
839 }
840 (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
841 *qfnamep = buf;
842 return (1);
843 }
844 #endif /* __APPLE__ */
845
846 int
847 alldigits(s)
848 register char *s;
849 {
850 register int c;
851
852 c = *s++;
853 do {
854 if (!isdigit(c))
855 return (0);
856 } while ((c = *s++));
857 return (1);
858 }