Deleted Added
full compact
rquotad.c (197531) rquotad.c (207736)
1/*
2 * by Manuel Bouyer (bouyer@ensta.fr)
3 *
4 * There is no copyright, you can use it as you want.
5 */
6
7#include <sys/cdefs.h>
1/*
2 * by Manuel Bouyer (bouyer@ensta.fr)
3 *
4 * There is no copyright, you can use it as you want.
5 */
6
7#include <sys/cdefs.h>
8__FBSDID("$FreeBSD: head/libexec/rpc.rquotad/rquotad.c 197531 2009-09-26 23:05:01Z des $");
8__FBSDID("$FreeBSD: head/libexec/rpc.rquotad/rquotad.c 207736 2010-05-07 00:41:12Z mckusick $");
9
10#include <sys/param.h>
11#include <sys/mount.h>
12#include <sys/file.h>
13#include <sys/stat.h>
14#include <sys/socket.h>
15
16#include <ufs/ufs/quota.h>
17#include <rpc/rpc.h>
18#include <rpcsvc/rquota.h>
19#include <arpa/inet.h>
20#include <netdb.h>
21
22#include <ctype.h>
23#include <errno.h>
24#include <fstab.h>
25#include <grp.h>
9
10#include <sys/param.h>
11#include <sys/mount.h>
12#include <sys/file.h>
13#include <sys/stat.h>
14#include <sys/socket.h>
15
16#include <ufs/ufs/quota.h>
17#include <rpc/rpc.h>
18#include <rpcsvc/rquota.h>
19#include <arpa/inet.h>
20#include <netdb.h>
21
22#include <ctype.h>
23#include <errno.h>
24#include <fstab.h>
25#include <grp.h>
26#include <libutil.h>
26#include <pwd.h>
27#include <signal.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <syslog.h>
32#include <unistd.h>
33
34static void rquota_service(struct svc_req *request, SVCXPRT *transp);
35static void sendquota(struct svc_req *request, SVCXPRT *transp);
36static void initfs(void);
37static int getfsquota(long id, char *path, struct dqblk *dqblk);
27#include <pwd.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <syslog.h>
33#include <unistd.h>
34
35static void rquota_service(struct svc_req *request, SVCXPRT *transp);
36static void sendquota(struct svc_req *request, SVCXPRT *transp);
37static void initfs(void);
38static int getfsquota(long id, char *path, struct dqblk *dqblk);
38static int hasquota(struct fstab *fs, char **qfnamep);
39
39
40/*
41 * structure containing informations about ufs filesystems
42 * initialised by initfs()
43 */
44struct fs_stat {
45 struct fs_stat *fs_next; /* next element */
46 char *fs_file; /* mount point of the filesystem */
47 char *qfpathname; /* pathname of the quota file */
48 dev_t st_dev; /* device of the filesystem */
49} fs_stat;
50static struct fs_stat *fs_begin = NULL;
51
40static struct quotafile **qfa; /* array of qfs */
41static int nqf, szqf; /* number of qfs and size of array */
52static int from_inetd = 1;
53
54static void
55cleanup(int sig)
56{
57
58 (void)sig;
59 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);

--- 9 unchanged lines hidden (view full) ---

69 socklen_t fromlen;
70
71 fromlen = sizeof(from);
72 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
73 from_inetd = 0;
74
75 if (!from_inetd) {
76 daemon(0, 0);
42static int from_inetd = 1;
43
44static void
45cleanup(int sig)
46{
47
48 (void)sig;
49 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);

--- 9 unchanged lines hidden (view full) ---

59 socklen_t fromlen;
60
61 fromlen = sizeof(from);
62 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
63 from_inetd = 0;
64
65 if (!from_inetd) {
66 daemon(0, 0);
77
78 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
67 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
79
80 (void)signal(SIGINT, cleanup);
81 (void)signal(SIGTERM, cleanup);
82 (void)signal(SIGHUP, cleanup);
83 }
84
85 openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
86
87 /* create and register the service */

--- 25 unchanged lines hidden (view full) ---

113static void
114rquota_service(struct svc_req *request, SVCXPRT *transp)
115{
116
117 switch (request->rq_proc) {
118 case NULLPROC:
119 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
120 break;
68 (void)signal(SIGINT, cleanup);
69 (void)signal(SIGTERM, cleanup);
70 (void)signal(SIGHUP, cleanup);
71 }
72
73 openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON);
74
75 /* create and register the service */

--- 25 unchanged lines hidden (view full) ---

101static void
102rquota_service(struct svc_req *request, SVCXPRT *transp)
103{
104
105 switch (request->rq_proc) {
106 case NULLPROC:
107 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
108 break;
121
122 case RQUOTAPROC_GETQUOTA:
123 case RQUOTAPROC_GETACTIVEQUOTA:
124 sendquota(request, transp);
125 break;
109 case RQUOTAPROC_GETQUOTA:
110 case RQUOTAPROC_GETACTIVEQUOTA:
111 sendquota(request, transp);
112 break;
126
127 default:
128 svcerr_noproc(transp);
129 break;
130 }
131 if (from_inetd)
132 exit(0);
133}
134
135/* read quota for the specified id, and send it */
136static void
137sendquota(struct svc_req *request, SVCXPRT *transp)
138{
139 struct getquota_args getq_args;
140 struct getquota_rslt getq_rslt;
141 struct dqblk dqblk;
142 struct timeval timev;
113 default:
114 svcerr_noproc(transp);
115 break;
116 }
117 if (from_inetd)
118 exit(0);
119}
120
121/* read quota for the specified id, and send it */
122static void
123sendquota(struct svc_req *request, SVCXPRT *transp)
124{
125 struct getquota_args getq_args;
126 struct getquota_rslt getq_rslt;
127 struct dqblk dqblk;
128 struct timeval timev;
129 int scale;
143
144 bzero(&getq_args, sizeof(getq_args));
145 if (!svc_getargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
146 svcerr_decode(transp);
147 return;
148 }
149 if (request->rq_cred.oa_flavor != AUTH_UNIX) {
150 /* bad auth */
151 getq_rslt.status = Q_EPERM;
152 } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
153 /* failed, return noquota */
154 getq_rslt.status = Q_NOQUOTA;
155 } else {
156 gettimeofday(&timev, NULL);
157 getq_rslt.status = Q_OK;
158 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
130
131 bzero(&getq_args, sizeof(getq_args));
132 if (!svc_getargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
133 svcerr_decode(transp);
134 return;
135 }
136 if (request->rq_cred.oa_flavor != AUTH_UNIX) {
137 /* bad auth */
138 getq_rslt.status = Q_EPERM;
139 } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
140 /* failed, return noquota */
141 getq_rslt.status = Q_NOQUOTA;
142 } else {
143 gettimeofday(&timev, NULL);
144 getq_rslt.status = Q_OK;
145 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
159 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
146 scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
147 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
148 DEV_BSIZE * scale;
160 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
149 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
161 dqblk.dqb_bhardlimit;
150 dqblk.dqb_bhardlimit / scale;
162 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
151 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
163 dqblk.dqb_bsoftlimit;
152 dqblk.dqb_bsoftlimit / scale;
164 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
153 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
165 dqblk.dqb_curblocks;
154 dqblk.dqb_curblocks / scale;
166 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
167 dqblk.dqb_ihardlimit;
168 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
169 dqblk.dqb_isoftlimit;
170 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
171 dqblk.dqb_curinodes;
172 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
173 dqblk.dqb_btime - timev.tv_sec;
174 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
175 dqblk.dqb_itime - timev.tv_sec;
176 }
177 if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
178 svcerr_systemerr(transp);
179 if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
180 syslog(LOG_ERR, "unable to free arguments");
181 exit(1);
182 }
183}
184
155 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
156 dqblk.dqb_ihardlimit;
157 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
158 dqblk.dqb_isoftlimit;
159 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
160 dqblk.dqb_curinodes;
161 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
162 dqblk.dqb_btime - timev.tv_sec;
163 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
164 dqblk.dqb_itime - timev.tv_sec;
165 }
166 if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
167 svcerr_systemerr(transp);
168 if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
169 syslog(LOG_ERR, "unable to free arguments");
170 exit(1);
171 }
172}
173
185/* initialise the fs_tab list from entries in /etc/fstab */
186static void
187initfs(void)
188{
174static void
175initfs(void)
176{
189 struct fs_stat *fs_current = NULL;
190 struct fs_stat *fs_next = NULL;
191 char *qfpathname;
192 struct fstab *fs;
177 struct fstab *fs;
193 struct stat st;
194
195 setfsent();
178
179 setfsent();
180 szqf = 8;
181 if ((qfa = malloc(szqf * sizeof *qfa)) == NULL)
182 goto enomem;
196 while ((fs = getfsent())) {
197 if (strcmp(fs->fs_vfstype, "ufs"))
198 continue;
183 while ((fs = getfsent())) {
184 if (strcmp(fs->fs_vfstype, "ufs"))
185 continue;
199 if (!hasquota(fs, &qfpathname))
186 if (nqf >= szqf) {
187 szqf *= 2;
188 if ((qfa = reallocf(qfa, szqf * sizeof *qfa)) == NULL)
189 goto enomem;
190 }
191 if ((qfa[nqf] = quota_open(fs, USRQUOTA, O_RDONLY)) == NULL) {
192 if (errno != EOPNOTSUPP)
193 goto fserr;
200 continue;
194 continue;
201
202 fs_current = malloc(sizeof(struct fs_stat));
203 fs_current->fs_next = fs_next; /* next element */
204
205 fs_current->fs_file = malloc(strlen(fs->fs_file) + 1);
206 strcpy(fs_current->fs_file, fs->fs_file);
207
208 fs_current->qfpathname = malloc(strlen(qfpathname) + 1);
209 strcpy(fs_current->qfpathname, qfpathname);
210
211 stat(fs_current->fs_file, &st);
212 fs_current->st_dev = st.st_dev;
213
214 fs_next = fs_current;
195 }
196 ++nqf;
197 /* XXX */
215 }
216 endfsent();
198 }
199 endfsent();
217 fs_begin = fs_current;
200 return;
201enomem:
202 syslog(LOG_ERR, "out of memory");
203 exit(1);
204fserr:
205 syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno));
206 exit(1);
218}
219
220/*
221 * gets the quotas for id, filesystem path.
222 * Return 0 if fail, 1 otherwise
223 */
224static int
225getfsquota(long id, char *path, struct dqblk *dqblk)
226{
207}
208
209/*
210 * gets the quotas for id, filesystem path.
211 * Return 0 if fail, 1 otherwise
212 */
213static int
214getfsquota(long id, char *path, struct dqblk *dqblk)
215{
227 struct stat st_path;
228 struct fs_stat *fs;
229 int qcmd, fd, ret = 0;
216 int i;
230
217
231 if (stat(path, &st_path) < 0)
232 return (0);
233
234 qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
235
236 for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
237 /* where the device is the same as path */
238 if (fs->st_dev != st_path.st_dev)
239 continue;
240
241 /* find the specified filesystem. get and return quota */
242 if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
243 return (1);
244
245 if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
246 syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);
247 return (0);
248 }
249 if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET) == (off_t)-1) {
250 close(fd);
251 return (1);
252 }
253 switch (read(fd, dqblk, sizeof(struct dqblk))) {
254 case 0:
255 /*
256 * Convert implicit 0 quota (EOF)
257 * into an explicit one (zero'ed dqblk)
258 */
259 bzero(dqblk, sizeof(struct dqblk));
260 ret = 1;
261 break;
262 case sizeof(struct dqblk): /* OK */
263 ret = 1;
264 break;
265 default: /* ERROR */
266 syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);
267 close(fd);
268 return (0);
269 }
270 close(fd);
271 }
272 return (ret);
218 for (i = 0; i < nqf; ++i)
219 if (quota_check_path(qfa[i], path) == 1)
220 return (quota_read(qfa[i], dqblk, id) == 0);
221 return (0);
273}
222}
274
275/*
276 * Check to see if a particular quota is to be enabled.
277 * Comes from quota.c, NetBSD 0.9
278 */
279static int
280hasquota(struct fstab *fs, char **qfnamep)
281{
282 static char initname, usrname[100];
283 static char buf[BUFSIZ];
284 char *opt, *cp;
285 const char *qfextension[] = INITQFNAMES;
286
287 if (!initname) {
288 sprintf(usrname, "%s%s", qfextension[USRQUOTA], QUOTAFILENAME);
289 initname = 1;
290 }
291 strcpy(buf, fs->fs_mntops);
292 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
293 if ((cp = index(opt, '=')))
294 *cp++ = '\0';
295 if (strcmp(opt, usrname) == 0)
296 break;
297 }
298 if (!opt)
299 return (0);
300 if (cp) {
301 *qfnamep = cp;
302 return (1);
303 }
304 sprintf(buf, "%s/%s.%s", fs->fs_file, QUOTAFILENAME,
305 qfextension[USRQUOTA]);
306 *qfnamep = buf;
307 return (1);
308}