1/*	$NetBSD: quota_open.c,v 1.6 2012/01/30 16:45:13 dholland Exp $	*/
2/*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by David A. Holland.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: quota_open.c,v 1.6 2012/01/30 16:45:13 dholland Exp $");
33
34#include <sys/types.h>
35#include <sys/statvfs.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39#include <errno.h>
40
41#include <quota.h>
42#include "quotapvt.h"
43
44struct quotahandle *
45quota_open(const char *path)
46{
47
48	struct statvfs stv;
49	struct quotahandle *qh;
50	int mode;
51	int serrno;
52
53	/*
54	 * Probe order:
55	 *
56	 *    1. Check for NFS. NFS quota ops don't go to the kernel
57	 *    at all but instead do RPCs to the NFS server's
58	 *    rpc.rquotad, so it doesn't matter what the kernel
59	 *    thinks.
60	 *
61	 *    2. Check if quotas are enabled in the mount flags. If
62	 *    so, we can do quotactl calls.
63	 *
64	 *    3. Check if the volume is listed in fstab as one of
65	 *    the filesystem types supported by quota_oldfiles.c,
66	 *    and with the proper mount options to enable quotas.
67	 *
68	 * Note that (as of this writing) the mount options for
69	 * enabling quotas are accepted by mount for *all* filesystem
70	 * types and then ignored -- the kernel mount flag (ST_QUOTA /
71	 * MNT_QUOTA) gets set either by the filesystem based on its
72	 * own criteria, or for old-style quotas, during quotaon. The
73	 * quota filenames specified in fstab are not passed to or
74	 * known by the kernel except via quota_oldfiles.c! This is
75	 * generally gross but not easily fixed.
76	 */
77
78	if (statvfs(path, &stv) < 0) {
79		return NULL;
80	}
81
82	__quota_oldfiles_load_fstab();
83
84	if (!strcmp(stv.f_fstypename, "nfs")) {
85		mode = QUOTA_MODE_NFS;
86	} else if ((stv.f_flag & ST_QUOTA) != 0) {
87		mode = QUOTA_MODE_KERNEL;
88	} else if (__quota_oldfiles_infstab(stv.f_mntonname)) {
89		mode = QUOTA_MODE_OLDFILES;
90	} else {
91		errno = EOPNOTSUPP;
92		return NULL;
93	}
94
95	qh = malloc(sizeof(*qh));
96	if (qh == NULL) {
97		return NULL;
98	}
99
100	/*
101	 * Get the mount point from statvfs; this way the passed-in
102	 * path can be any path on the volume.
103	 */
104
105	qh->qh_mountpoint = strdup(stv.f_mntonname);
106	if (qh->qh_mountpoint == NULL) {
107		serrno = errno;
108		free(qh);
109		errno = serrno;
110		return NULL;
111	}
112
113	qh->qh_mountdevice = strdup(stv.f_mntfromname);
114	if (qh->qh_mountdevice == NULL) {
115		serrno = errno;
116		free(qh->qh_mountpoint);
117		free(qh);
118		errno = serrno;
119		return NULL;
120	}
121
122	qh->qh_mode = mode;
123
124	qh->qh_oldfilesopen = 0;
125	qh->qh_userfile = -1;
126	qh->qh_groupfile = -1;
127
128	return qh;
129}
130
131const char *
132quota_getmountpoint(struct quotahandle *qh)
133{
134	return qh->qh_mountpoint;
135}
136
137const char *
138quota_getmountdevice(struct quotahandle *qh)
139{
140	return qh->qh_mountdevice;
141}
142
143void
144quota_close(struct quotahandle *qh)
145{
146	if (qh->qh_userfile >= 0) {
147		close(qh->qh_userfile);
148	}
149	if (qh->qh_groupfile >= 0) {
150		close(qh->qh_groupfile);
151	}
152	free(qh->qh_mountdevice);
153	free(qh->qh_mountpoint);
154	free(qh);
155}
156
157int
158quota_quotaon(struct quotahandle *qh, int idtype)
159{
160	switch (qh->qh_mode) {
161	    case QUOTA_MODE_NFS:
162		errno = EOPNOTSUPP;
163		break;
164	    case QUOTA_MODE_OLDFILES:
165		return __quota_oldfiles_quotaon(qh, idtype);
166	    case QUOTA_MODE_KERNEL:
167		return __quota_kernel_quotaon(qh, idtype);
168	    default:
169		errno = EINVAL;
170		break;
171	}
172	return -1;
173}
174
175int
176quota_quotaoff(struct quotahandle *qh, int idtype)
177{
178	switch (qh->qh_mode) {
179	    case QUOTA_MODE_NFS:
180		errno = EOPNOTSUPP;
181		break;
182	    case QUOTA_MODE_OLDFILES:
183		/* can't quotaoff if we haven't quotaon'd */
184		errno = ENOTCONN;
185		break;
186	    case QUOTA_MODE_KERNEL:
187		return __quota_kernel_quotaoff(qh, idtype);
188	    default:
189		errno = EINVAL;
190		break;
191	}
192	return -1;
193}
194