1 /* $NetBSD: rquotad.c,v 1.23 2006/05/09 20:18:07 mrg Exp $ */
4 * by Manuel Bouyer (bouyer@ensta.fr). Public domain.
9 __RCSID("$NetBSD: rquotad.c,v 1.23 2006/05/09 20:18:07 mrg Exp $");
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/mount.h>
17 #include <sys/socket.h>
32 #include <ufs/ufs/quota.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
);
41 int getfsquota(int type
, long id
, char *path
, struct dqblk
*dqblk
);
42 int hasquota(struct fstab
*fs
, char **uqfnamep
, char **gqfnamep
);
44 int main(int, char *[]);
47 * structure containing informations about ufs filesystems
48 * initialised by initfs()
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 */
57 struct fs_stat
*fs_begin
= NULL
;
59 const char *qfextension
[] = INITQFNAMES
;
66 (void)rpcb_unset(RQUOTAPROG
, RQUOTAVERS
, NULL
);
67 (void)rpcb_unset(RQUOTAPROG
, EXT_RQUOTAVERS
, NULL
);
72 main(int argc
, char *argv
[])
75 struct sockaddr_storage from
;
78 fromlen
= sizeof(from
);
79 if (getsockname(0, (struct sockaddr
*)&from
, &fromlen
) < 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 */
96 transp
= svc_dg_create(0, 0, 0);
98 syslog(LOG_ERR
, "couldn't create udp service.");
101 if (!svc_reg(transp
, RQUOTAPROG
, RQUOTAVERS
, rquota_service
,
104 "unable to register (RQUOTAPROG, RQUOTAVERS).");
107 if (!svc_reg(transp
, RQUOTAPROG
, EXT_RQUOTAVERS
,
108 ext_rquota_service
, NULL
)) {
110 "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
114 if (!svc_create(rquota_service
, RQUOTAPROG
, RQUOTAVERS
, "udp")){
116 "unable to create (RQUOTAPROG, RQUOTAVERS).");
119 if (!svc_create(ext_rquota_service
, RQUOTAPROG
,
120 EXT_RQUOTAVERS
, "udp")){
122 "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
127 initfs(); /* init the fs_stat list */
129 syslog(LOG_ERR
, "svc_run returned");
134 rquota_service(struct svc_req
*request
, SVCXPRT
*transp
)
136 switch (request
->rq_proc
) {
138 (void)svc_sendreply(transp
, xdr_void
, (char *)NULL
);
141 case RQUOTAPROC_GETQUOTA
:
142 case RQUOTAPROC_GETACTIVEQUOTA
:
143 sendquota(request
, RQUOTAVERS
, transp
);
147 svcerr_noproc(transp
);
155 ext_rquota_service(struct svc_req
*request
, SVCXPRT
*transp
)
157 switch (request
->rq_proc
) {
159 (void)svc_sendreply(transp
, xdr_void
, (char *)NULL
);
162 case RQUOTAPROC_GETQUOTA
:
163 case RQUOTAPROC_GETACTIVEQUOTA
:
164 sendquota(request
, EXT_RQUOTAVERS
, transp
);
168 svcerr_noproc(transp
);
175 /* read quota for the specified id, and send it */
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
;
183 struct timeval timev
;
185 memset((char *)&getq_args
, 0, sizeof(getq_args
));
186 memset((char *)&ext_getq_args
, 0, sizeof(ext_getq_args
));
189 if (!svc_getargs(transp
, xdr_getquota_args
,
190 (caddr_t
)&getq_args
)) {
191 svcerr_decode(transp
);
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
;
199 if (!svc_getargs(transp
, xdr_ext_getquota_args
,
200 (caddr_t
)&ext_getq_args
)) {
201 svcerr_decode(transp
);
206 if (request
->rq_cred
.oa_flavor
!= AUTH_UNIX
) {
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
;
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
=
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
=
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");
243 /* initialise the fs_tab list from entries in /etc/fstab */
247 struct fs_stat
*fs_current
= NULL
;
248 struct fs_stat
*fs_next
= NULL
;
249 char *uqfpathname
, *gqfpathname
;
254 while ((fs
= getfsent())) {
255 if (strcmp(fs
->fs_vfstype
, MOUNT_FFS
))
257 if (!hasquota(fs
, &uqfpathname
, &gqfpathname
))
260 fs_current
= (struct fs_stat
*) malloc(sizeof(struct fs_stat
));
261 if (fs_current
== NULL
) {
262 syslog(LOG_ERR
, "can't malloc: %m");
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");
274 fs_current
->uqfpathname
= strdup(uqfpathname
);
275 if (fs_current
->uqfpathname
== NULL
) {
276 syslog(LOG_ERR
, "can't strdup: %m");
280 fs_current
->uqfpathname
= NULL
;
282 fs_current
->gqfpathname
= strdup(gqfpathname
);
283 if (fs_current
->gqfpathname
== NULL
) {
284 syslog(LOG_ERR
, "can't strdup: %m");
288 fs_current
->gqfpathname
= NULL
;
289 stat(fs
->fs_file
, &st
);
290 fs_current
->st_dev
= st
.st_dev
;
292 fs_next
= fs_current
;
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
)
307 int qcmd
, fd
, ret
= 0;
310 if (stat(path
, &st_path
) < 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
)
320 /* find the specified filesystem. get and return quota */
321 if (quotactl(fs
->fs_file
, qcmd
, id
, dqblk
) == 0)
323 filename
= (type
== RQUOTA_USRQUOTA
) ?
324 fs
->uqfpathname
: fs
->gqfpathname
;
325 if (filename
== NULL
)
327 if ((fd
= open(filename
, O_RDONLY
)) < 0) {
328 syslog(LOG_WARNING
, "open error: %s: %m", filename
);
331 if (lseek(fd
, (off_t
)(id
* sizeof(struct dqblk
)), SEEK_SET
)
336 switch (read(fd
, dqblk
, sizeof(struct dqblk
))) {
339 * Convert implicit 0 quota (EOF)
340 * into an explicit one (zero'ed dqblk)
342 memset((caddr_t
) dqblk
, 0, sizeof(struct dqblk
));
345 case sizeof(struct dqblk
): /* OK */
349 syslog(LOG_WARNING
, "read error: %s: %m", filename
);
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
;
371 (void)snprintf(usrname
, sizeof usrname
, "%s%s",
372 qfextension
[USRQUOTA
], QUOTAFILENAME
);
373 (void)snprintf(grpname
, sizeof grpname
, "%s%s",
374 qfextension
[GRPQUOTA
], QUOTAFILENAME
);
379 (void)strlcpy(buf
, fs
->fs_mntops
, sizeof(buf
));
380 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
381 if ((cp
= strchr(opt
, '=')))
383 if (strcmp(opt
, usrname
) == 0) {
388 (void)snprintf(ubuf
, sizeof ubuf
, "%s/%s.%s",
389 fs
->fs_file
, QUOTAFILENAME
,
390 qfextension
[USRQUOTA
]);
393 } else if (strcmp(opt
, grpname
) == 0) {
398 (void)snprintf(gbuf
, sizeof gbuf
, "%s/%s.%s",
399 fs
->fs_file
, QUOTAFILENAME
,
400 qfextension
[GRPQUOTA
]);