1 /* $NetBSD: quota_open.c,v 1.7 2012/02/01 05:34:40 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.7 2012/02/01 05:34:40 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
44 struct quotahandle *
quota_open(const char * path)45 quota_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
131 const char *
quota_getmountpoint(struct quotahandle * qh)132 quota_getmountpoint(struct quotahandle *qh)
133 {
134 return qh->qh_mountpoint;
135 }
136
137 const char *
quota_getmountdevice(struct quotahandle * qh)138 quota_getmountdevice(struct quotahandle *qh)
139 {
140 return qh->qh_mountdevice;
141 }
142
143 void
quota_close(struct quotahandle * qh)144 quota_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
157 int
quota_quotaon(struct quotahandle * qh,int idtype)158 quota_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
175 int
quota_quotaoff(struct quotahandle * qh,int idtype)176 quota_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