No empty .Rs/.Re
[netbsd-mini2440.git] / libexec / rpc.rquotad / rquotad.c
blob5b0f38d18c4f7a793a923ee51ed2c0e67575d9f2
1 /* $NetBSD: rquotad.c,v 1.23 2006/05/09 20:18:07 mrg Exp $ */
3 /*
4 * by Manuel Bouyer (bouyer@ensta.fr). Public domain.
5 */
7 #include <sys/cdefs.h>
8 #ifndef lint
9 __RCSID("$NetBSD: rquotad.c,v 1.23 2006/05/09 20:18:07 mrg Exp $");
10 #endif
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/mount.h>
15 #include <sys/file.h>
16 #include <sys/stat.h>
17 #include <sys/socket.h>
18 #include <signal.h>
20 #include <stdio.h>
21 #include <fstab.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <errno.h>
28 #include <unistd.h>
30 #include <syslog.h>
32 #include <ufs/ufs/quota.h>
33 #include <rpc/rpc.h>
34 #include <rpcsvc/rquota.h>
35 #include <arpa/inet.h>
37 void rquota_service(struct svc_req *request, SVCXPRT *transp);
38 void ext_rquota_service(struct svc_req *request, SVCXPRT *transp);
39 void sendquota(struct svc_req *request, int vers, SVCXPRT *transp);
40 void initfs(void);
41 int getfsquota(int type, long id, char *path, struct dqblk *dqblk);
42 int hasquota(struct fstab *fs, char **uqfnamep, char **gqfnamep);
43 void cleanup(int);
44 int main(int, char *[]);
47 * structure containing informations about ufs filesystems
48 * initialised by initfs()
50 struct fs_stat {
51 struct fs_stat *fs_next; /* next element */
52 char *fs_file; /* mount point of the filesystem */
53 char *uqfpathname; /* pathname of the user quota file */
54 char *gqfpathname; /* pathname of the group quota file */
55 dev_t st_dev; /* device of the filesystem */
56 } fs_stat;
57 struct fs_stat *fs_begin = NULL;
59 const char *qfextension[] = INITQFNAMES;
60 int from_inetd = 1;
62 void
63 cleanup(int dummy)
66 (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
67 (void)rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
68 exit(0);
71 int
72 main(int argc, char *argv[])
74 SVCXPRT *transp;
75 struct sockaddr_storage from;
76 socklen_t fromlen;
78 fromlen = sizeof(from);
79 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
80 from_inetd = 0;
82 if (!from_inetd) {
83 daemon(0, 0);
85 (void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
86 (void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
87 (void) signal(SIGINT, cleanup);
88 (void) signal(SIGTERM, cleanup);
89 (void) signal(SIGHUP, cleanup);
92 openlog("rpc.rquotad", LOG_PID, LOG_DAEMON);
94 /* create and register the service */
95 if (from_inetd) {
96 transp = svc_dg_create(0, 0, 0);
97 if (transp == NULL) {
98 syslog(LOG_ERR, "couldn't create udp service.");
99 exit(1);
101 if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service,
102 NULL)) {
103 syslog(LOG_ERR,
104 "unable to register (RQUOTAPROG, RQUOTAVERS).");
105 exit(1);
107 if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
108 ext_rquota_service, NULL)) {
109 syslog(LOG_ERR,
110 "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
111 exit(1);
113 } else {
114 if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){
115 syslog(LOG_ERR,
116 "unable to create (RQUOTAPROG, RQUOTAVERS).");
117 exit(1);
119 if (!svc_create(ext_rquota_service, RQUOTAPROG,
120 EXT_RQUOTAVERS, "udp")){
121 syslog(LOG_ERR,
122 "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
123 exit(1);
127 initfs(); /* init the fs_stat list */
128 svc_run();
129 syslog(LOG_ERR, "svc_run returned");
130 exit(1);
133 void
134 rquota_service(struct svc_req *request, SVCXPRT *transp)
136 switch (request->rq_proc) {
137 case NULLPROC:
138 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
139 break;
141 case RQUOTAPROC_GETQUOTA:
142 case RQUOTAPROC_GETACTIVEQUOTA:
143 sendquota(request, RQUOTAVERS, transp);
144 break;
146 default:
147 svcerr_noproc(transp);
148 break;
150 if (from_inetd)
151 exit(0);
154 void
155 ext_rquota_service(struct svc_req *request, SVCXPRT *transp)
157 switch (request->rq_proc) {
158 case NULLPROC:
159 (void)svc_sendreply(transp, xdr_void, (char *)NULL);
160 break;
162 case RQUOTAPROC_GETQUOTA:
163 case RQUOTAPROC_GETACTIVEQUOTA:
164 sendquota(request, EXT_RQUOTAVERS, transp);
165 break;
167 default:
168 svcerr_noproc(transp);
169 break;
171 if (from_inetd)
172 exit(0);
175 /* read quota for the specified id, and send it */
176 void
177 sendquota(struct svc_req *request, int vers, SVCXPRT *transp)
179 struct getquota_args getq_args;
180 struct ext_getquota_args ext_getq_args;
181 struct getquota_rslt getq_rslt;
182 struct dqblk dqblk;
183 struct timeval timev;
185 memset((char *)&getq_args, 0, sizeof(getq_args));
186 memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args));
187 switch (vers) {
188 case RQUOTAVERS:
189 if (!svc_getargs(transp, xdr_getquota_args,
190 (caddr_t)&getq_args)) {
191 svcerr_decode(transp);
192 return;
194 ext_getq_args.gqa_pathp = getq_args.gqa_pathp;
195 ext_getq_args.gqa_id = getq_args.gqa_uid;
196 ext_getq_args.gqa_type = RQUOTA_USRQUOTA;
197 break;
198 case EXT_RQUOTAVERS:
199 if (!svc_getargs(transp, xdr_ext_getquota_args,
200 (caddr_t)&ext_getq_args)) {
201 svcerr_decode(transp);
202 return;
204 break;
206 if (request->rq_cred.oa_flavor != AUTH_UNIX) {
207 /* bad auth */
208 getq_rslt.status = Q_EPERM;
209 } else if (!getfsquota(ext_getq_args.gqa_type, ext_getq_args.gqa_id,
210 ext_getq_args.gqa_pathp, &dqblk)) {
211 /* failed, return noquota */
212 getq_rslt.status = Q_NOQUOTA;
213 } else {
214 gettimeofday(&timev, NULL);
215 getq_rslt.status = Q_OK;
216 getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
217 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
218 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
219 dqblk.dqb_bhardlimit;
220 getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
221 dqblk.dqb_bsoftlimit;
222 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
223 dqblk.dqb_curblocks;
224 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
225 dqblk.dqb_ihardlimit;
226 getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
227 dqblk.dqb_isoftlimit;
228 getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
229 dqblk.dqb_curinodes;
230 getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
231 dqblk.dqb_btime - timev.tv_sec;
232 getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
233 dqblk.dqb_itime - timev.tv_sec;
235 if (!svc_sendreply(transp, xdr_getquota_rslt, (char *)&getq_rslt))
236 svcerr_systemerr(transp);
237 if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
238 syslog(LOG_ERR, "unable to free arguments");
239 exit(1);
243 /* initialise the fs_tab list from entries in /etc/fstab */
244 void
245 initfs()
247 struct fs_stat *fs_current = NULL;
248 struct fs_stat *fs_next = NULL;
249 char *uqfpathname, *gqfpathname;
250 struct fstab *fs;
251 struct stat st;
253 setfsent();
254 while ((fs = getfsent())) {
255 if (strcmp(fs->fs_vfstype, MOUNT_FFS))
256 continue;
257 if (!hasquota(fs, &uqfpathname, &gqfpathname))
258 continue;
260 fs_current = (struct fs_stat *) malloc(sizeof(struct fs_stat));
261 if (fs_current == NULL) {
262 syslog(LOG_ERR, "can't malloc: %m");
263 exit(1);
265 fs_current->fs_next = fs_next; /* next element */
267 fs_current->fs_file = strdup(fs->fs_file);
268 if (fs_current->fs_file == NULL) {
269 syslog(LOG_ERR, "can't strdup: %m");
270 exit(1);
273 if (uqfpathname) {
274 fs_current->uqfpathname = strdup(uqfpathname);
275 if (fs_current->uqfpathname == NULL) {
276 syslog(LOG_ERR, "can't strdup: %m");
277 exit(1);
279 } else
280 fs_current->uqfpathname = NULL;
281 if (gqfpathname) {
282 fs_current->gqfpathname = strdup(gqfpathname);
283 if (fs_current->gqfpathname == NULL) {
284 syslog(LOG_ERR, "can't strdup: %m");
285 exit(1);
287 } else
288 fs_current->gqfpathname = NULL;
289 stat(fs->fs_file, &st);
290 fs_current->st_dev = st.st_dev;
292 fs_next = fs_current;
294 endfsent();
295 fs_begin = fs_current;
299 * gets the quotas for id, filesystem path.
300 * Return 0 if fail, 1 otherwise
303 getfsquota(int type, long id, char *path, struct dqblk *dqblk)
305 struct stat st_path;
306 struct fs_stat *fs;
307 int qcmd, fd, ret = 0;
308 char *filename;
310 if (stat(path, &st_path) < 0)
311 return (0);
313 qcmd = QCMD(Q_GETQUOTA, type == RQUOTA_USRQUOTA ? USRQUOTA : GRPQUOTA);
315 for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
316 /* where the device is the same as path */
317 if (fs->st_dev != st_path.st_dev)
318 continue;
320 /* find the specified filesystem. get and return quota */
321 if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
322 return (1);
323 filename = (type == RQUOTA_USRQUOTA) ?
324 fs->uqfpathname : fs->gqfpathname;
325 if (filename == NULL)
326 return 0;
327 if ((fd = open(filename, O_RDONLY)) < 0) {
328 syslog(LOG_WARNING, "open error: %s: %m", filename);
329 return (0);
331 if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), SEEK_SET)
332 == (off_t)-1) {
333 close(fd);
334 return (0);
336 switch (read(fd, dqblk, sizeof(struct dqblk))) {
337 case 0:
339 * Convert implicit 0 quota (EOF)
340 * into an explicit one (zero'ed dqblk)
342 memset((caddr_t) dqblk, 0, sizeof(struct dqblk));
343 ret = 1;
344 break;
345 case sizeof(struct dqblk): /* OK */
346 ret = 1;
347 break;
348 default: /* ERROR */
349 syslog(LOG_WARNING, "read error: %s: %m", filename);
350 close(fd);
351 return (0);
353 close(fd);
355 return (ret);
359 * Check to see if a particular quota is to be enabled.
360 * Comes from quota.c, NetBSD 0.9
363 hasquota(struct fstab *fs, char **uqfnamep, char **gqfnamep)
365 static char initname=0, usrname[100], grpname[100];
366 static char buf[MAXPATHLEN], ubuf[MAXPATHLEN], gbuf[MAXPATHLEN];
367 char *opt, *cp = NULL;
368 int ret = 0;
370 if (!initname) {
371 (void)snprintf(usrname, sizeof usrname, "%s%s",
372 qfextension[USRQUOTA], QUOTAFILENAME);
373 (void)snprintf(grpname, sizeof grpname, "%s%s",
374 qfextension[GRPQUOTA], QUOTAFILENAME);
377 *uqfnamep = NULL;
378 *gqfnamep = NULL;
379 (void)strlcpy(buf, fs->fs_mntops, sizeof(buf));
380 for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
381 if ((cp = strchr(opt, '=')))
382 *cp++ = '\0';
383 if (strcmp(opt, usrname) == 0) {
384 ret = 1;
385 if (cp)
386 *uqfnamep = cp;
387 else {
388 (void)snprintf(ubuf, sizeof ubuf, "%s/%s.%s",
389 fs->fs_file, QUOTAFILENAME,
390 qfextension[USRQUOTA]);
391 *uqfnamep = ubuf;
393 } else if (strcmp(opt, grpname) == 0) {
394 ret = 1;
395 if (cp)
396 *gqfnamep = cp;
397 else {
398 (void)snprintf(gbuf, sizeof gbuf, "%s/%s.%s",
399 fs->fs_file, QUOTAFILENAME,
400 qfextension[GRPQUOTA]);
401 *gqfnamep = gbuf;
405 return (ret);