xref: /titanic_52/usr/src/cmd/fs.d/ufs/edquota/edquota.c (revision ace833a05229ff2cc8e43f4d6755d77a9cbc5828)
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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, &quota);
9027c478bd9Sstevel@tonic-gate 	(void) close(fd);
9037c478bd9Sstevel@tonic-gate 	return (status);
9047c478bd9Sstevel@tonic-gate }
905