17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5d1a180b0Smaheshvs * Common Development and Distribution License (the "License").
6d1a180b0Smaheshvs * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*ace833a0Scasper * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
277c478bd9Sstevel@tonic-gate /* All Rights Reserved */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
317c478bd9Sstevel@tonic-gate * The Regents of the University of California
327c478bd9Sstevel@tonic-gate * All Rights Reserved
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
357c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
367c478bd9Sstevel@tonic-gate * contributors.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate * Disk quota editor.
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate #include <stdlib.h>
457c478bd9Sstevel@tonic-gate #include <stdio.h>
467c478bd9Sstevel@tonic-gate #include <signal.h>
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <pwd.h>
497c478bd9Sstevel@tonic-gate #include <ctype.h>
507c478bd9Sstevel@tonic-gate #include <fcntl.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <strings.h>
537c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
547c478bd9Sstevel@tonic-gate #include <sys/param.h>
557c478bd9Sstevel@tonic-gate #include <sys/types.h>
567c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
577c478bd9Sstevel@tonic-gate #include <sys/stat.h>
587c478bd9Sstevel@tonic-gate #include <sys/file.h>
597c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h>
607c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
617c478bd9Sstevel@tonic-gate #include <sys/wait.h>
627c478bd9Sstevel@tonic-gate #include <unistd.h>
637c478bd9Sstevel@tonic-gate #include <iso/limits_iso.h>
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate #define DEFEDITOR "/usr/bin/vi"
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate #if DEV_BSIZE < 1024
687c478bd9Sstevel@tonic-gate #define dbtok(x) ((x) / (1024 / DEV_BSIZE))
697c478bd9Sstevel@tonic-gate #define ktodb(x) ((x) * (1024 / DEV_BSIZE))
707c478bd9Sstevel@tonic-gate #else
717c478bd9Sstevel@tonic-gate #define dbtok(x) ((x) * (DEV_BSIZE / 1024))
727c478bd9Sstevel@tonic-gate #define ktodb(x) ((x) / (DEV_BSIZE / 1024))
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate struct fsquot {
767c478bd9Sstevel@tonic-gate struct fsquot *fsq_next;
777c478bd9Sstevel@tonic-gate struct dqblk fsq_dqb;
787c478bd9Sstevel@tonic-gate char *fsq_fs;
797c478bd9Sstevel@tonic-gate char *fsq_dev;
807c478bd9Sstevel@tonic-gate char *fsq_qfile;
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate static struct fsquot *fsqlist;
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate static char tmpfil[] = "/tmp/EdP.aXXXXXX";
867c478bd9Sstevel@tonic-gate #define QFNAME "quotas"
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate static uid_t getentry(char *);
897c478bd9Sstevel@tonic-gate static int editit(void);
907c478bd9Sstevel@tonic-gate static void getprivs(uid_t);
917c478bd9Sstevel@tonic-gate static void putprivs(uid_t);
927c478bd9Sstevel@tonic-gate static void gettimes(uid_t);
937c478bd9Sstevel@tonic-gate static void puttimes(uid_t);
947c478bd9Sstevel@tonic-gate static char *next(char *, char *);
957c478bd9Sstevel@tonic-gate static int alldigits(char *);
967c478bd9Sstevel@tonic-gate static void fmttime(char *, ulong_t);
977c478bd9Sstevel@tonic-gate static int unfmttime(double, char *, uint32_t *);
987c478bd9Sstevel@tonic-gate static void setupfs(void);
997c478bd9Sstevel@tonic-gate static void getdiscq(uid_t);
1007c478bd9Sstevel@tonic-gate static void putdiscq(uid_t);
1017c478bd9Sstevel@tonic-gate static void sigsetmask(uint_t);
1027c478bd9Sstevel@tonic-gate static uint_t sigblock(uint_t);
1037c478bd9Sstevel@tonic-gate static void usage(void);
1047c478bd9Sstevel@tonic-gate static int quotactl(int, char *, uid_t, caddr_t);
1057c478bd9Sstevel@tonic-gate
106d1a180b0Smaheshvs int
main(int argc,char ** argv)1077c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate uid_t uid;
1107c478bd9Sstevel@tonic-gate char *basename;
1117c478bd9Sstevel@tonic-gate int opt;
1127c478bd9Sstevel@tonic-gate int i;
1137c478bd9Sstevel@tonic-gate int tmpfd = -1;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate basename = argv[0];
1167c478bd9Sstevel@tonic-gate if (argc < 2) {
1177c478bd9Sstevel@tonic-gate usage();
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate if (quotactl(Q_SYNC, (char *)NULL, 0, (caddr_t)NULL) < 0 &&
1207c478bd9Sstevel@tonic-gate errno == EINVAL) {
1217c478bd9Sstevel@tonic-gate (void) printf("Warning: "
1227c478bd9Sstevel@tonic-gate "Quotas are not compiled into this kernel\n");
1237c478bd9Sstevel@tonic-gate (void) sleep(3);
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate if (getuid()) {
1267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: permission denied\n", basename);
1277c478bd9Sstevel@tonic-gate exit(32);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate setupfs();
1307c478bd9Sstevel@tonic-gate if (fsqlist == NULL) {
1317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: no UFS filesystems with %s file\n",
1327c478bd9Sstevel@tonic-gate MNTTAB, QFNAME);
1337c478bd9Sstevel@tonic-gate exit(32);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate tmpfd = mkstemp(tmpfil);
1367c478bd9Sstevel@tonic-gate if (tmpfd == -1 || fchown(tmpfd, getuid(), getgid()) == -1) {
1377c478bd9Sstevel@tonic-gate fprintf(stderr, "failure in temporary file %s\n", tmpfil);
1387c478bd9Sstevel@tonic-gate exit(32);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate (void) close(tmpfd);
1417c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "p:tV")) != EOF)
1427c478bd9Sstevel@tonic-gate switch (opt) {
1437c478bd9Sstevel@tonic-gate case 't':
1447c478bd9Sstevel@tonic-gate gettimes(0);
1457c478bd9Sstevel@tonic-gate if (editit())
1467c478bd9Sstevel@tonic-gate puttimes(0);
1477c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
1487c478bd9Sstevel@tonic-gate exit(0);
1497c478bd9Sstevel@tonic-gate /*NOTREACHED*/
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate case 'p':
1527c478bd9Sstevel@tonic-gate uid = getentry(optarg);
153*ace833a0Scasper if (uid > MAXUID) {
1547c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
1557c478bd9Sstevel@tonic-gate exit(32);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate getprivs(uid);
1587c478bd9Sstevel@tonic-gate if (optind == argc) {
1597c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
1607c478bd9Sstevel@tonic-gate usage();
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate for (i = optind; i < argc; i++) {
1637c478bd9Sstevel@tonic-gate uid = getentry(argv[i]);
164*ace833a0Scasper if (uid > MAXUID) {
1657c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
1667c478bd9Sstevel@tonic-gate exit(32);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate getdiscq(uid);
1697c478bd9Sstevel@tonic-gate putprivs(uid);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
1727c478bd9Sstevel@tonic-gate exit(0);
1737c478bd9Sstevel@tonic-gate /*NOTREACHED*/
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate case 'V': /* Print command line */
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate char *optt;
1787c478bd9Sstevel@tonic-gate int optc;
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate (void) printf("edquota -F UFS");
1817c478bd9Sstevel@tonic-gate for (optc = 1; optc < argc; optc++) {
1827c478bd9Sstevel@tonic-gate optt = argv[optc];
1837c478bd9Sstevel@tonic-gate if (optt)
1847c478bd9Sstevel@tonic-gate (void) printf(" %s ", optt);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate (void) putchar('\n');
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate break;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate case '?':
1917c478bd9Sstevel@tonic-gate usage();
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate for (i = optind; i < argc; i++) {
1957c478bd9Sstevel@tonic-gate uid = getentry(argv[i]);
196*ace833a0Scasper if (uid > MAXUID)
1977c478bd9Sstevel@tonic-gate continue;
1987c478bd9Sstevel@tonic-gate getprivs(uid);
1997c478bd9Sstevel@tonic-gate if (editit())
2007c478bd9Sstevel@tonic-gate putprivs(uid);
2017c478bd9Sstevel@tonic-gate if (uid == 0) {
2027c478bd9Sstevel@tonic-gate (void) printf("edquota: Note that uid 0's quotas "
2037c478bd9Sstevel@tonic-gate "are used as default values for other users,\n");
2047c478bd9Sstevel@tonic-gate (void) printf("not as a limit on the uid 0 user.\n");
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
2087c478bd9Sstevel@tonic-gate return (0);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate static uid_t
getentry(char * name)2127c478bd9Sstevel@tonic-gate getentry(char *name)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate struct passwd *pw;
2157c478bd9Sstevel@tonic-gate uid_t uid;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate if (alldigits(name)) {
2187c478bd9Sstevel@tonic-gate errno = 0;
2197c478bd9Sstevel@tonic-gate uid = strtol(name, NULL, 10);
2207c478bd9Sstevel@tonic-gate if (errno == ERANGE) {
2217c478bd9Sstevel@tonic-gate /* name would cause overflow in uid */
2227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: uid %s too large\n",
2237c478bd9Sstevel@tonic-gate name);
2247c478bd9Sstevel@tonic-gate (void) sleep(1);
2257c478bd9Sstevel@tonic-gate return (-1);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate } else if (pw = getpwnam(name))
2287c478bd9Sstevel@tonic-gate uid = pw->pw_uid;
2297c478bd9Sstevel@tonic-gate else {
2307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: no such user\n", name);
2317c478bd9Sstevel@tonic-gate (void) sleep(1);
2327c478bd9Sstevel@tonic-gate return (-1);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate return (uid);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate #define RESPSZ 128
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate static int
editit(void)2407c478bd9Sstevel@tonic-gate editit(void)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate pid_t pid, xpid;
2437c478bd9Sstevel@tonic-gate char *ed;
2447c478bd9Sstevel@tonic-gate char resp[RESPSZ];
2457c478bd9Sstevel@tonic-gate int status, omask;
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate #define mask(s) (1 << ((s) - 1))
2487c478bd9Sstevel@tonic-gate omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP));
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate if ((ed = getenv("EDITOR")) == (char *)0)
2517c478bd9Sstevel@tonic-gate ed = DEFEDITOR;
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/
2547c478bd9Sstevel@tonic-gate while (1) {
2557c478bd9Sstevel@tonic-gate if ((pid = fork()) < 0) {
2567c478bd9Sstevel@tonic-gate if (errno == EAGAIN) {
2577c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2587c478bd9Sstevel@tonic-gate "You have too many processes\n");
2597c478bd9Sstevel@tonic-gate return (0);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate perror("fork");
2627c478bd9Sstevel@tonic-gate return (0);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate if (pid == 0) {
2657c478bd9Sstevel@tonic-gate (void) sigsetmask(omask);
2667c478bd9Sstevel@tonic-gate (void) setgid(getgid());
2677c478bd9Sstevel@tonic-gate (void) setuid(getuid());
2687c478bd9Sstevel@tonic-gate (void) execlp(ed, ed, tmpfil, 0);
2697c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2707c478bd9Sstevel@tonic-gate "Can't exec editor \"%s\": ", ed);
2717c478bd9Sstevel@tonic-gate perror("");
2727c478bd9Sstevel@tonic-gate exit(32);
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate while ((xpid = wait(&status)) >= 0)
2757c478bd9Sstevel@tonic-gate if (xpid == pid)
2767c478bd9Sstevel@tonic-gate break;
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate if (!isatty(fileno(stdin))) { /* Non-interactive */
2797c478bd9Sstevel@tonic-gate break;
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * Certain editors can exit with a non-zero status even
2847c478bd9Sstevel@tonic-gate * though everything is peachy. Best to ask the user what
2857c478bd9Sstevel@tonic-gate * s/he really wants to do. (N.B.: if we're non-interactive
2867c478bd9Sstevel@tonic-gate * we'll "break" the while loop before we get here.)
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
2897c478bd9Sstevel@tonic-gate (void) printf("Non-zero return from \"%s\", ", ed);
2907c478bd9Sstevel@tonic-gate (void) printf("updated file may contain errors.\n");
2917c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/
2927c478bd9Sstevel@tonic-gate while (1) {
2937c478bd9Sstevel@tonic-gate (void) printf("Edit again (e) or quit, "
2947c478bd9Sstevel@tonic-gate "discarding changes (q)? ");
2957c478bd9Sstevel@tonic-gate (void) fflush(stdout);
2967c478bd9Sstevel@tonic-gate if (gets(resp) == NULL) {
2977c478bd9Sstevel@tonic-gate return (0);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate if ((*resp == 'e') || (*resp == 'q')) {
3007c478bd9Sstevel@tonic-gate break;
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (*resp == 'e') {
3057c478bd9Sstevel@tonic-gate continue;
3067c478bd9Sstevel@tonic-gate } else {
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * Since (*resp == 'q'), then we just
3097c478bd9Sstevel@tonic-gate * want to break out of here and return
3107c478bd9Sstevel@tonic-gate * the failure.
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate break;
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate } else {
3157c478bd9Sstevel@tonic-gate break; /* Successful return from editor */
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate (void) sigsetmask(omask);
3197c478bd9Sstevel@tonic-gate return (!status);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate static void
getprivs(uid_t uid)3237c478bd9Sstevel@tonic-gate getprivs(uid_t uid)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
3267c478bd9Sstevel@tonic-gate FILE *fd;
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate getdiscq(uid);
3297c478bd9Sstevel@tonic-gate if ((fd = fopen64(tmpfil, "w")) == NULL) {
3307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: ");
3317c478bd9Sstevel@tonic-gate perror(tmpfil);
3327c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
3337c478bd9Sstevel@tonic-gate exit(32);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next)
3367c478bd9Sstevel@tonic-gate (void) fprintf(fd,
3377c478bd9Sstevel@tonic-gate "fs %s blocks (soft = %lu, hard = %lu) "
3387c478bd9Sstevel@tonic-gate "inodes (soft = %lu, hard = %lu)\n",
3397c478bd9Sstevel@tonic-gate fsqp->fsq_fs,
3407c478bd9Sstevel@tonic-gate dbtok(fsqp->fsq_dqb.dqb_bsoftlimit),
3417c478bd9Sstevel@tonic-gate dbtok(fsqp->fsq_dqb.dqb_bhardlimit),
3427c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_fsoftlimit,
3437c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_fhardlimit);
3447c478bd9Sstevel@tonic-gate (void) fclose(fd);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate static void
putprivs(uid_t uid)3487c478bd9Sstevel@tonic-gate putprivs(uid_t uid)
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate FILE *fd;
3517c478bd9Sstevel@tonic-gate uint64_t tmp_bsoftlimit, tmp_bhardlimit, tmp_fsoftlimit,
3527c478bd9Sstevel@tonic-gate tmp_fhardlimit;
3537c478bd9Sstevel@tonic-gate char line[BUFSIZ];
3547c478bd9Sstevel@tonic-gate int changed = 0;
3557c478bd9Sstevel@tonic-gate uint32_t max_limit;
3567c478bd9Sstevel@tonic-gate int quota_entry_printed;
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate fd = fopen64(tmpfil, "r");
3597c478bd9Sstevel@tonic-gate if (fd == NULL) {
3607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Can't re-read temp file!!\n");
3617c478bd9Sstevel@tonic-gate return;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate while (fgets(line, sizeof (line), fd) != NULL) {
3647c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
3657c478bd9Sstevel@tonic-gate char *cp, *dp;
3667c478bd9Sstevel@tonic-gate int n;
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate cp = next(line, " \t");
3697c478bd9Sstevel@tonic-gate if (cp == NULL)
3707c478bd9Sstevel@tonic-gate break;
3717c478bd9Sstevel@tonic-gate *cp++ = '\0';
3727c478bd9Sstevel@tonic-gate while (*cp && *cp == '\t' && *cp == ' ')
3737c478bd9Sstevel@tonic-gate cp++;
3747c478bd9Sstevel@tonic-gate dp = cp, cp = next(cp, " \t");
3757c478bd9Sstevel@tonic-gate if (cp == NULL)
3767c478bd9Sstevel@tonic-gate break;
3777c478bd9Sstevel@tonic-gate *cp++ = '\0';
3787c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
3797c478bd9Sstevel@tonic-gate if (strcmp(dp, fsqp->fsq_fs) == 0)
3807c478bd9Sstevel@tonic-gate break;
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate if (fsqp == NULL) {
3837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unknown file system\n", cp);
3847c478bd9Sstevel@tonic-gate continue;
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate while (*cp && *cp == '\t' && *cp == ' ')
3877c478bd9Sstevel@tonic-gate cp++;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * At this point, dp points to the mount point of the
3917c478bd9Sstevel@tonic-gate * file system and cp points to the remainder of the
3927c478bd9Sstevel@tonic-gate * quota definition string.
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gate n = sscanf(cp,
3957c478bd9Sstevel@tonic-gate "blocks (soft = %llu, hard = %llu) "
3967c478bd9Sstevel@tonic-gate "inodes (soft = %llu, hard = %llu)\n",
3977c478bd9Sstevel@tonic-gate &tmp_bsoftlimit,
3987c478bd9Sstevel@tonic-gate &tmp_bhardlimit,
3997c478bd9Sstevel@tonic-gate &tmp_fsoftlimit,
4007c478bd9Sstevel@tonic-gate &tmp_fhardlimit);
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate if (n != 4) {
4037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: bad format\n", cp);
4047c478bd9Sstevel@tonic-gate continue;
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * The values in dqb_bsoftlimit and dqb_bhardlimit
4097c478bd9Sstevel@tonic-gate * are specified in 1k blocks in the edited quota
4107c478bd9Sstevel@tonic-gate * file (the one we're reading), but are specified in
4117c478bd9Sstevel@tonic-gate * disk blocks in the data structure passed to quotactl().
4127c478bd9Sstevel@tonic-gate * That means that the maximum allowed value for the
4137c478bd9Sstevel@tonic-gate * hard and soft block limits in the edited quota file
4147c478bd9Sstevel@tonic-gate * is the maximum number of disk blocks allowed in a
4157c478bd9Sstevel@tonic-gate * quota (which is 2^32 - 1, since it's a 32-bit unsigned
4167c478bd9Sstevel@tonic-gate * quantity), converted to 1k blocks.
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate max_limit = dbtok(UINT_MAX);
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate quota_entry_printed = 0; /* only print quota entry once */
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if (tmp_bsoftlimit > max_limit) {
4237c478bd9Sstevel@tonic-gate tmp_bsoftlimit = max_limit;
4247c478bd9Sstevel@tonic-gate if (!quota_entry_printed) {
4257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %s%\n", dp, cp);
4267c478bd9Sstevel@tonic-gate quota_entry_printed = 1;
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4297c478bd9Sstevel@tonic-gate "error: soft limit for blocks exceeds maximum allowed value,\n"
4307c478bd9Sstevel@tonic-gate " soft limit for blocks set to %lu\n", max_limit);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate if (tmp_bhardlimit > max_limit) {
4347c478bd9Sstevel@tonic-gate tmp_bhardlimit = max_limit;
4357c478bd9Sstevel@tonic-gate if (!quota_entry_printed) {
4367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %s%\n", dp, cp);
4377c478bd9Sstevel@tonic-gate quota_entry_printed = 1;
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4407c478bd9Sstevel@tonic-gate "error: hard limit for blocks exceeds maximum allowed value,\n"
4417c478bd9Sstevel@tonic-gate " hard limit for blocks set to %lu\n", max_limit);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate * Now check the file limits against their maximum, which
4477c478bd9Sstevel@tonic-gate * is UINT_MAX (since it must fit in a uint32_t).
4487c478bd9Sstevel@tonic-gate */
4497c478bd9Sstevel@tonic-gate max_limit = UINT_MAX;
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate if (tmp_fsoftlimit > max_limit) {
4527c478bd9Sstevel@tonic-gate tmp_fsoftlimit = max_limit;
4537c478bd9Sstevel@tonic-gate if (!quota_entry_printed) {
4547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %s%\n", dp, cp);
4557c478bd9Sstevel@tonic-gate quota_entry_printed = 1;
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4587c478bd9Sstevel@tonic-gate "error: soft limit for files exceeds maximum allowed value,\n"
4597c478bd9Sstevel@tonic-gate " soft limit for files set to %lu\n", max_limit);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate if (tmp_fhardlimit > max_limit) {
4637c478bd9Sstevel@tonic-gate tmp_fhardlimit = max_limit;
4647c478bd9Sstevel@tonic-gate if (!quota_entry_printed) {
4657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s %s%\n", dp, cp);
4667c478bd9Sstevel@tonic-gate quota_entry_printed = 1;
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4697c478bd9Sstevel@tonic-gate "error: hard limit for files exceeds maximum allowed value,\n"
4707c478bd9Sstevel@tonic-gate " hard limit for files set to %lu\n", max_limit);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate changed++;
4747c478bd9Sstevel@tonic-gate tmp_bsoftlimit = ktodb(tmp_bsoftlimit);
4757c478bd9Sstevel@tonic-gate tmp_bhardlimit = ktodb(tmp_bhardlimit);
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate * It we are decreasing the soft limits, set the time limits
4787c478bd9Sstevel@tonic-gate * to zero, in case the user is now over quota.
4797c478bd9Sstevel@tonic-gate * the time limit will be started the next time the
4807c478bd9Sstevel@tonic-gate * user does an allocation.
4817c478bd9Sstevel@tonic-gate */
4827c478bd9Sstevel@tonic-gate if (tmp_bsoftlimit < fsqp->fsq_dqb.dqb_bsoftlimit)
4837c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_btimelimit = 0;
4847c478bd9Sstevel@tonic-gate if (tmp_fsoftlimit < fsqp->fsq_dqb.dqb_fsoftlimit)
4857c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_ftimelimit = 0;
4867c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_bsoftlimit = tmp_bsoftlimit;
4877c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_bhardlimit = tmp_bhardlimit;
4887c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_fsoftlimit = tmp_fsoftlimit;
4897c478bd9Sstevel@tonic-gate fsqp->fsq_dqb.dqb_fhardlimit = tmp_fhardlimit;
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate (void) fclose(fd);
4927c478bd9Sstevel@tonic-gate if (changed)
4937c478bd9Sstevel@tonic-gate putdiscq(uid);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate static void
gettimes(uid_t uid)4977c478bd9Sstevel@tonic-gate gettimes(uid_t uid)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
5007c478bd9Sstevel@tonic-gate FILE *fd;
5017c478bd9Sstevel@tonic-gate char btime[80], ftime[80];
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate getdiscq(uid);
5047c478bd9Sstevel@tonic-gate if ((fd = fopen64(tmpfil, "w")) == NULL) {
5057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: ");
5067c478bd9Sstevel@tonic-gate perror(tmpfil);
5077c478bd9Sstevel@tonic-gate (void) unlink(tmpfil);
5087c478bd9Sstevel@tonic-gate exit(32);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
5117c478bd9Sstevel@tonic-gate fmttime(btime, fsqp->fsq_dqb.dqb_btimelimit);
5127c478bd9Sstevel@tonic-gate fmttime(ftime, fsqp->fsq_dqb.dqb_ftimelimit);
5137c478bd9Sstevel@tonic-gate (void) fprintf(fd,
5147c478bd9Sstevel@tonic-gate "fs %s blocks time limit = %s, files time limit = %s\n",
5157c478bd9Sstevel@tonic-gate fsqp->fsq_fs, btime, ftime);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate (void) fclose(fd);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate static void
puttimes(uid_t uid)5217c478bd9Sstevel@tonic-gate puttimes(uid_t uid)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate FILE *fd;
5247c478bd9Sstevel@tonic-gate char line[BUFSIZ];
5257c478bd9Sstevel@tonic-gate int changed = 0;
5267c478bd9Sstevel@tonic-gate double btimelimit, ftimelimit;
5277c478bd9Sstevel@tonic-gate char bunits[80], funits[80];
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate fd = fopen64(tmpfil, "r");
5307c478bd9Sstevel@tonic-gate if (fd == NULL) {
5317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Can't re-read temp file!!\n");
5327c478bd9Sstevel@tonic-gate return;
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate while (fgets(line, sizeof (line), fd) != NULL) {
5357c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
5367c478bd9Sstevel@tonic-gate char *cp, *dp;
5377c478bd9Sstevel@tonic-gate int n;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate cp = next(line, " \t");
5407c478bd9Sstevel@tonic-gate if (cp == NULL)
5417c478bd9Sstevel@tonic-gate break;
5427c478bd9Sstevel@tonic-gate *cp++ = '\0';
5437c478bd9Sstevel@tonic-gate while (*cp && *cp == '\t' && *cp == ' ')
5447c478bd9Sstevel@tonic-gate cp++;
5457c478bd9Sstevel@tonic-gate dp = cp, cp = next(cp, " \t");
5467c478bd9Sstevel@tonic-gate if (cp == NULL)
5477c478bd9Sstevel@tonic-gate break;
5487c478bd9Sstevel@tonic-gate *cp++ = '\0';
5497c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
5507c478bd9Sstevel@tonic-gate if (strcmp(dp, fsqp->fsq_fs) == 0)
5517c478bd9Sstevel@tonic-gate break;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate if (fsqp == NULL) {
5547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unknown file system\n", cp);
5557c478bd9Sstevel@tonic-gate continue;
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate while (*cp && *cp == '\t' && *cp == ' ')
5587c478bd9Sstevel@tonic-gate cp++;
5597c478bd9Sstevel@tonic-gate n = sscanf(cp,
5607c478bd9Sstevel@tonic-gate "blocks time limit = %lf %[^,], "
5617c478bd9Sstevel@tonic-gate "files time limit = %lf %s\n",
5627c478bd9Sstevel@tonic-gate &btimelimit, bunits, &ftimelimit, funits);
5637c478bd9Sstevel@tonic-gate if (n != 4 ||
5647c478bd9Sstevel@tonic-gate !unfmttime(btimelimit, bunits,
5657c478bd9Sstevel@tonic-gate &fsqp->fsq_dqb.dqb_btimelimit) ||
5667c478bd9Sstevel@tonic-gate !unfmttime(ftimelimit, funits,
5677c478bd9Sstevel@tonic-gate &fsqp->fsq_dqb.dqb_ftimelimit)) {
5687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: bad format\n", cp);
5697c478bd9Sstevel@tonic-gate continue;
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate changed++;
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate (void) fclose(fd);
5747c478bd9Sstevel@tonic-gate if (changed)
5757c478bd9Sstevel@tonic-gate putdiscq(uid);
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate static char *
next(char * cp,char * match)5797c478bd9Sstevel@tonic-gate next(char *cp, char *match)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate char *dp;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate while (cp && *cp) {
5847c478bd9Sstevel@tonic-gate for (dp = match; dp && *dp; dp++)
5857c478bd9Sstevel@tonic-gate if (*dp == *cp)
5867c478bd9Sstevel@tonic-gate return (cp);
5877c478bd9Sstevel@tonic-gate cp++;
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate return ((char *)0);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate static int
alldigits(char * s)5937c478bd9Sstevel@tonic-gate alldigits(char *s)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate int c = *s++;
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate do {
5987c478bd9Sstevel@tonic-gate if (!isdigit(c))
5997c478bd9Sstevel@tonic-gate return (0);
6007c478bd9Sstevel@tonic-gate } while ((c = *s++) != '\0');
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate return (1);
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate static struct {
6067c478bd9Sstevel@tonic-gate int c_secs; /* conversion units in secs */
6077c478bd9Sstevel@tonic-gate char *c_str; /* unit string */
6087c478bd9Sstevel@tonic-gate } cunits [] = {
6097c478bd9Sstevel@tonic-gate {60*60*24*28, "month"},
6107c478bd9Sstevel@tonic-gate {60*60*24*7, "week"},
6117c478bd9Sstevel@tonic-gate {60*60*24, "day"},
6127c478bd9Sstevel@tonic-gate {60*60, "hour"},
6137c478bd9Sstevel@tonic-gate {60, "min"},
6147c478bd9Sstevel@tonic-gate {1, "sec"}
6157c478bd9Sstevel@tonic-gate };
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate static void
fmttime(char * buf,ulong_t time)6187c478bd9Sstevel@tonic-gate fmttime(char *buf, ulong_t time)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate double value;
6217c478bd9Sstevel@tonic-gate int i;
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate if (time == 0) {
6247c478bd9Sstevel@tonic-gate (void) strcpy(buf, "0 (default)");
6257c478bd9Sstevel@tonic-gate return;
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cunits) / sizeof (cunits[0]); i++)
6287c478bd9Sstevel@tonic-gate if (time >= cunits[i].c_secs)
6297c478bd9Sstevel@tonic-gate break;
6307c478bd9Sstevel@tonic-gate
6317c478bd9Sstevel@tonic-gate value = (double)time / cunits[i].c_secs;
6327c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%.2f %s%s",
6337c478bd9Sstevel@tonic-gate value, cunits[i].c_str, value > 1.0 ? "s" : "");
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate static int
unfmttime(double value,char * units,uint32_t * timep)6377c478bd9Sstevel@tonic-gate unfmttime(double value, char *units, uint32_t *timep)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate int i;
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate if (value == 0.0) {
6427c478bd9Sstevel@tonic-gate *timep = 0;
6437c478bd9Sstevel@tonic-gate return (1);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cunits) / sizeof (cunits[0]); i++) {
6467c478bd9Sstevel@tonic-gate if (strncmp(cunits[i].c_str, units,
6477c478bd9Sstevel@tonic-gate strlen(cunits[i].c_str)) == 0)
6487c478bd9Sstevel@tonic-gate break;
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate if (i >= sizeof (cunits) / sizeof (cunits[0]))
6517c478bd9Sstevel@tonic-gate return (0);
6527c478bd9Sstevel@tonic-gate *timep = (ulong_t)(value * cunits[i].c_secs);
6537c478bd9Sstevel@tonic-gate return (1);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate static void
setupfs(void)6577c478bd9Sstevel@tonic-gate setupfs(void)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate struct mnttab mntp;
6607c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
6617c478bd9Sstevel@tonic-gate struct stat64 statb;
6627c478bd9Sstevel@tonic-gate dev_t fsdev;
6637c478bd9Sstevel@tonic-gate FILE *mtab;
6647c478bd9Sstevel@tonic-gate char qfilename[MAXPATHLEN];
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate if ((mtab = fopen(MNTTAB, "r")) == (FILE *)0) {
6677c478bd9Sstevel@tonic-gate perror("/etc/mnttab");
6687c478bd9Sstevel@tonic-gate exit(31+1);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate while (getmntent(mtab, &mntp) == 0) {
6717c478bd9Sstevel@tonic-gate if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0)
6727c478bd9Sstevel@tonic-gate continue;
6737c478bd9Sstevel@tonic-gate if (stat64(mntp.mnt_special, &statb) < 0)
6747c478bd9Sstevel@tonic-gate continue;
6757c478bd9Sstevel@tonic-gate if ((statb.st_mode & S_IFMT) != S_IFBLK)
6767c478bd9Sstevel@tonic-gate continue;
6777c478bd9Sstevel@tonic-gate fsdev = statb.st_rdev;
6787c478bd9Sstevel@tonic-gate (void) snprintf(qfilename, sizeof (qfilename), "%s/%s",
6797c478bd9Sstevel@tonic-gate mntp.mnt_mountp, QFNAME);
6807c478bd9Sstevel@tonic-gate if (stat64(qfilename, &statb) < 0 || statb.st_dev != fsdev)
6817c478bd9Sstevel@tonic-gate continue;
6827c478bd9Sstevel@tonic-gate fsqp = malloc(sizeof (struct fsquot));
6837c478bd9Sstevel@tonic-gate if (fsqp == NULL) {
6847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "out of memory\n");
6857c478bd9Sstevel@tonic-gate exit(31+1);
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate fsqp->fsq_next = fsqlist;
6887c478bd9Sstevel@tonic-gate fsqp->fsq_fs = strdup(mntp.mnt_mountp);
6897c478bd9Sstevel@tonic-gate fsqp->fsq_dev = strdup(mntp.mnt_special);
6907c478bd9Sstevel@tonic-gate fsqp->fsq_qfile = strdup(qfilename);
6917c478bd9Sstevel@tonic-gate if (fsqp->fsq_fs == NULL || fsqp->fsq_dev == NULL ||
6927c478bd9Sstevel@tonic-gate fsqp->fsq_qfile == NULL) {
6937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "out of memory\n");
6947c478bd9Sstevel@tonic-gate exit(31+1);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate fsqlist = fsqp;
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate (void) fclose(mtab);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate static void
getdiscq(uid_t uid)7027c478bd9Sstevel@tonic-gate getdiscq(uid_t uid)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
7057c478bd9Sstevel@tonic-gate int fd;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
7087c478bd9Sstevel@tonic-gate if (quotactl(Q_GETQUOTA, fsqp->fsq_dev, uid,
7097c478bd9Sstevel@tonic-gate (caddr_t)&fsqp->fsq_dqb) != 0) {
7107c478bd9Sstevel@tonic-gate if ((fd = open64(fsqp->fsq_qfile, O_RDONLY)) < 0) {
7117c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: ");
7127c478bd9Sstevel@tonic-gate perror(fsqp->fsq_qfile);
7137c478bd9Sstevel@tonic-gate continue;
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
7167c478bd9Sstevel@tonic-gate switch (read(fd, (char *)&fsqp->fsq_dqb,
7177c478bd9Sstevel@tonic-gate sizeof (struct dqblk))) {
7187c478bd9Sstevel@tonic-gate case 0:
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate * Convert implicit 0 quota (EOF)
7217c478bd9Sstevel@tonic-gate * into an explicit one (zero'ed dqblk)
7227c478bd9Sstevel@tonic-gate */
7237c478bd9Sstevel@tonic-gate bzero((caddr_t)&fsqp->fsq_dqb,
7247c478bd9Sstevel@tonic-gate sizeof (struct dqblk));
7257c478bd9Sstevel@tonic-gate break;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate case sizeof (struct dqblk): /* OK */
7287c478bd9Sstevel@tonic-gate break;
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate default: /* ERROR */
7317c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7327c478bd9Sstevel@tonic-gate "edquota: read error in ");
7337c478bd9Sstevel@tonic-gate perror(fsqp->fsq_qfile);
7347c478bd9Sstevel@tonic-gate break;
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate (void) close(fd);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate static void
putdiscq(uid_t uid)7427c478bd9Sstevel@tonic-gate putdiscq(uid_t uid)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate struct fsquot *fsqp;
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate for (fsqp = fsqlist; fsqp; fsqp = fsqp->fsq_next) {
7477c478bd9Sstevel@tonic-gate if (quotactl(Q_SETQLIM, fsqp->fsq_dev, uid,
7487c478bd9Sstevel@tonic-gate (caddr_t)&fsqp->fsq_dqb) != 0) {
7497c478bd9Sstevel@tonic-gate int fd;
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate if ((fd = open64(fsqp->fsq_qfile, O_RDWR)) < 0) {
7527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: ");
7537c478bd9Sstevel@tonic-gate perror(fsqp->fsq_qfile);
7547c478bd9Sstevel@tonic-gate continue;
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate (void) llseek(fd, (offset_t)dqoff(uid), L_SET);
7577c478bd9Sstevel@tonic-gate if (write(fd, (char *)&fsqp->fsq_dqb,
7587c478bd9Sstevel@tonic-gate sizeof (struct dqblk)) != sizeof (struct dqblk)) {
7597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "edquota: ");
7607c478bd9Sstevel@tonic-gate perror(fsqp->fsq_qfile);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate (void) close(fd);
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate static void
sigsetmask(uint_t omask)7687c478bd9Sstevel@tonic-gate sigsetmask(uint_t omask)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate int i;
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++)
7737c478bd9Sstevel@tonic-gate if (omask & (1 << i)) {
7747c478bd9Sstevel@tonic-gate if (sigignore(1 << i) == (int)SIG_ERR) {
7757c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7767c478bd9Sstevel@tonic-gate "Bad signal 0x%x\n", (1 << i));
7777c478bd9Sstevel@tonic-gate exit(31+1);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate static uint_t
sigblock(uint_t omask)7837c478bd9Sstevel@tonic-gate sigblock(uint_t omask)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate uint_t previous = 0;
7867c478bd9Sstevel@tonic-gate uint_t temp;
7877c478bd9Sstevel@tonic-gate int i;
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate for (i = 0; i < 32; i++)
7907c478bd9Sstevel@tonic-gate if (omask & (1 << i)) {
7917c478bd9Sstevel@tonic-gate if ((temp = sigignore(1 << i)) == (int)SIG_ERR) {
7927c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7937c478bd9Sstevel@tonic-gate "Bad signal 0x%x\n", (1 << i));
7947c478bd9Sstevel@tonic-gate exit(31+1);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate if (i == 0)
7977c478bd9Sstevel@tonic-gate previous = temp;
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate return (previous);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate static void
usage(void)8047c478bd9Sstevel@tonic-gate usage(void)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ufs usage:\n");
8077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tedquota [-p username] username ...\n");
8087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\tedquota -t\n");
8097c478bd9Sstevel@tonic-gate exit(1);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate static int
quotactl(int cmd,char * special,uid_t uid,caddr_t addr)8137c478bd9Sstevel@tonic-gate quotactl(int cmd, char *special, uid_t uid, caddr_t addr)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate int fd;
8167c478bd9Sstevel@tonic-gate int status;
8177c478bd9Sstevel@tonic-gate struct quotctl quota;
8187c478bd9Sstevel@tonic-gate char qfile[MAXPATHLEN];
8197c478bd9Sstevel@tonic-gate FILE *fstab;
8207c478bd9Sstevel@tonic-gate struct mnttab mntp;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate if ((special == NULL) && (cmd == Q_SYNC)) {
8237c478bd9Sstevel@tonic-gate cmd = Q_ALLSYNC;
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate * need to find an acceptable fd to send this Q_ALLSYNC down
8267c478bd9Sstevel@tonic-gate * on, it needs to be a ufs fd for vfs to at least call the
8277c478bd9Sstevel@tonic-gate * real quotactl() in the kernel
8287c478bd9Sstevel@tonic-gate * Here, try to simply find the starting mountpoint of the
8297c478bd9Sstevel@tonic-gate * first mounted ufs file system
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate * Find the mount point of the special device. This is
8357c478bd9Sstevel@tonic-gate * because the fcntl that implements the quotactl call has
8367c478bd9Sstevel@tonic-gate * to go to a real file, and not to the block device.
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate if ((fstab = fopen(MNTTAB, "r")) == NULL) {
8397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", MNTTAB);
8407c478bd9Sstevel@tonic-gate perror("open");
8417c478bd9Sstevel@tonic-gate exit(31+1);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate qfile[0] = '\0';
8447c478bd9Sstevel@tonic-gate while ((status = getmntent(fstab, &mntp)) == NULL) {
8457c478bd9Sstevel@tonic-gate /*
8467c478bd9Sstevel@tonic-gate * check that it is a ufs file system
8477c478bd9Sstevel@tonic-gate * for all quotactl()s except Q_ALLSYNC check that
8487c478bd9Sstevel@tonic-gate * the file system is read-write since changes in the
8497c478bd9Sstevel@tonic-gate * quotas file may be required
8507c478bd9Sstevel@tonic-gate * for Q_ALLSYNC, this check is skipped since this option
8517c478bd9Sstevel@tonic-gate * is to determine if quotas are configured into the system
8527c478bd9Sstevel@tonic-gate */
8537c478bd9Sstevel@tonic-gate if (strcmp(mntp.mnt_fstype, MNTTYPE_UFS) != 0 ||
8547c478bd9Sstevel@tonic-gate ((cmd != Q_ALLSYNC) && hasmntopt(&mntp, MNTOPT_RO)))
8557c478bd9Sstevel@tonic-gate continue;
8567c478bd9Sstevel@tonic-gate if (cmd == Q_ALLSYNC) { /* implies (special==0) too */
8577c478bd9Sstevel@tonic-gate if (strlcpy(qfile, mntp.mnt_mountp,
8587c478bd9Sstevel@tonic-gate sizeof (qfile)) >= sizeof (qfile)) {
8597c478bd9Sstevel@tonic-gate errno = ENOENT;
8607c478bd9Sstevel@tonic-gate return (-1);
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate break;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate if (strcmp(special, mntp.mnt_special) == 0) {
8657c478bd9Sstevel@tonic-gate if (strlcpy(qfile, mntp.mnt_mountp,
8667c478bd9Sstevel@tonic-gate sizeof (qfile)) >= sizeof (qfile)) {
8677c478bd9Sstevel@tonic-gate errno = ENOENT;
8687c478bd9Sstevel@tonic-gate return (-1);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate (void) fclose(fstab);
8737c478bd9Sstevel@tonic-gate if (qfile[0] == '\0') {
8747c478bd9Sstevel@tonic-gate errno = ENOENT;
8757c478bd9Sstevel@tonic-gate return (-1);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate int open_flags;
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate if (cmd == Q_ALLSYNC) {
8817c478bd9Sstevel@tonic-gate open_flags = O_RDONLY;
8827c478bd9Sstevel@tonic-gate } else {
8837c478bd9Sstevel@tonic-gate if (strlcat(qfile, "/" QFNAME, sizeof (qfile)) >=
8847c478bd9Sstevel@tonic-gate sizeof (qfile)) {
8857c478bd9Sstevel@tonic-gate errno = ENOENT;
8867c478bd9Sstevel@tonic-gate return (-1);
8877c478bd9Sstevel@tonic-gate }
8887c478bd9Sstevel@tonic-gate open_flags = O_RDWR;
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate if ((fd = open64(qfile, open_flags)) < 0) {
8927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "quotactl: ");
8937c478bd9Sstevel@tonic-gate perror("open");
8947c478bd9Sstevel@tonic-gate exit(31+1);
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate quota.op = cmd;
8997c478bd9Sstevel@tonic-gate quota.uid = uid;
9007c478bd9Sstevel@tonic-gate quota.addr = addr;
9017c478bd9Sstevel@tonic-gate status = ioctl(fd, Q_QUOTACTL, "a);
9027c478bd9Sstevel@tonic-gate (void) close(fd);
9037c478bd9Sstevel@tonic-gate return (status);
9047c478bd9Sstevel@tonic-gate }
905