2 * by Manuel Bouyer (bouyer@ensta.fr)
4 * There is no copyright, you can use it as you want.
6 * $FreeBSD: src/libexec/rpc.rquotad/rquotad.c,v 1.3.2.1 2001/07/02 23:46:27 mikeh Exp $
7 * $DragonFly: src/libexec/rpc.rquotad/rquotad.c,v 1.6 2008/11/19 18:41:30 swildner Exp $
10 #include <sys/param.h>
11 #include <sys/types.h>
12 #include <sys/mount.h>
15 #include <sys/socket.h>
30 #include <vfs/ufs/quota.h>
32 #include <rpc/pmap_clnt.h>
33 #include <rpcsvc/rquota.h>
34 #include <arpa/inet.h>
36 static void cleanup(int);
37 static void rquota_service(struct svc_req
*request
, SVCXPRT
*transp
);
38 static void sendquota(struct svc_req
*request
, SVCXPRT
*transp
);
39 static void initfs(void);
40 static int getfsquota(long id
, char *path
, struct ufs_dqblk
*dqblk
);
41 static int hasquota(struct fstab
*fs
, char **qfnamep
);
44 * structure containing informations about ufs filesystems
45 * initialised by initfs()
48 struct fs_stat
*fs_next
; /* next element */
49 char *fs_file
; /* mount point of the filesystem */
50 char *qfpathname
; /* pathname of the quota file */
51 dev_t st_dev
; /* device of the filesystem */
53 struct fs_stat
*fs_begin
= NULL
;
58 cleanup(int signo __unused
)
60 (void) pmap_unset(RQUOTAPROG
, RQUOTAVERS
);
70 struct sockaddr_in from
;
73 fromlen
= sizeof(from
);
74 if (getsockname(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
83 (void) pmap_unset(RQUOTAPROG
, RQUOTAVERS
);
85 (void) signal(SIGINT
, cleanup
);
86 (void) signal(SIGTERM
, cleanup
);
87 (void) signal(SIGHUP
, cleanup
);
90 openlog("rpc.rquotad", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
92 /* create and register the service */
93 transp
= svcudp_create(sock
);
95 syslog(LOG_ERR
, "couldn't create udp service");
98 if (!svc_register(transp
, RQUOTAPROG
, RQUOTAVERS
, rquota_service
, proto
)) {
99 syslog(LOG_ERR
, "unable to register (RQUOTAPROG, RQUOTAVERS, %s)", proto
?"udp":"(inetd)");
103 initfs(); /* init the fs_stat list */
105 syslog(LOG_ERR
, "svc_run returned");
110 rquota_service(struct svc_req
*request
, SVCXPRT
*transp
)
112 switch (request
->rq_proc
) {
114 (void)svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
);
117 case RQUOTAPROC_GETQUOTA
:
118 case RQUOTAPROC_GETACTIVEQUOTA
:
119 sendquota(request
, transp
);
123 svcerr_noproc(transp
);
130 /* read quota for the specified id, and send it */
132 sendquota(struct svc_req
*request
, SVCXPRT
*transp
)
134 struct getquota_args getq_args
;
135 struct getquota_rslt getq_rslt
;
136 struct ufs_dqblk dqblk
;
137 struct timeval timev
;
139 bzero((char *)&getq_args
, sizeof(getq_args
));
140 if (!svc_getargs(transp
, (xdrproc_t
)xdr_getquota_args
, (caddr_t
)&getq_args
)) {
141 svcerr_decode(transp
);
144 if (request
->rq_cred
.oa_flavor
!= AUTH_UNIX
) {
146 getq_rslt
.status
= Q_EPERM
;
147 } else if (!getfsquota(getq_args
.gqa_uid
, getq_args
.gqa_pathp
, &dqblk
)) {
148 /* failed, return noquota */
149 getq_rslt
.status
= Q_NOQUOTA
;
151 gettimeofday(&timev
, NULL
);
152 getq_rslt
.status
= Q_OK
;
153 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_active
= TRUE
;
154 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsize
= DEV_BSIZE
;
155 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
=
156 dqblk
.dqb_bhardlimit
;
157 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
=
158 dqblk
.dqb_bsoftlimit
;
159 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
=
161 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fhardlimit
=
162 dqblk
.dqb_ihardlimit
;
163 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fsoftlimit
=
164 dqblk
.dqb_isoftlimit
;
165 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curfiles
=
167 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_btimeleft
=
168 dqblk
.dqb_btime
- timev
.tv_sec
;
169 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_ftimeleft
=
170 dqblk
.dqb_itime
- timev
.tv_sec
;
172 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_getquota_rslt
, (char *)&getq_rslt
)) {
173 svcerr_systemerr(transp
);
175 if (!svc_freeargs(transp
, (xdrproc_t
)xdr_getquota_args
, (caddr_t
)&getq_args
)) {
176 syslog(LOG_ERR
, "unable to free arguments");
181 /* initialise the fs_tab list from entries in /etc/fstab */
185 struct fs_stat
*fs_current
= NULL
;
186 struct fs_stat
*fs_next
= NULL
;
192 while ((fs
= getfsent())) {
193 if (strcmp(fs
->fs_vfstype
, "ufs"))
195 if (!hasquota(fs
, &qfpathname
))
198 fs_current
= (struct fs_stat
*) malloc(sizeof(struct fs_stat
));
199 fs_current
->fs_next
= fs_next
; /* next element */
201 fs_current
->fs_file
= malloc(sizeof(char) * (strlen(fs
->fs_file
) + 1));
202 strcpy(fs_current
->fs_file
, fs
->fs_file
);
204 fs_current
->qfpathname
= malloc(sizeof(char) * (strlen(qfpathname
) + 1));
205 strcpy(fs_current
->qfpathname
, qfpathname
);
207 stat(fs_current
->fs_file
, &st
);
208 fs_current
->st_dev
= st
.st_dev
;
210 fs_next
= fs_current
;
213 fs_begin
= fs_current
;
217 * gets the quotas for id, filesystem path.
218 * Return 0 if fail, 1 otherwise
221 getfsquota(long id
, char *path
, struct ufs_dqblk
*dqblk
)
225 int qcmd
, fd
, ret
= 0;
227 if (stat(path
, &st_path
) < 0)
230 qcmd
= QCMD(Q_GETQUOTA
, USRQUOTA
);
232 for (fs
= fs_begin
; fs
!= NULL
; fs
= fs
->fs_next
) {
233 /* where the devise is the same as path */
234 if (fs
->st_dev
!= st_path
.st_dev
)
237 /* find the specified filesystem. get and return quota */
238 if (quotactl(fs
->fs_file
, qcmd
, id
, dqblk
) == 0)
241 if ((fd
= open(fs
->qfpathname
, O_RDONLY
)) < 0) {
242 syslog(LOG_ERR
, "open error: %s: %m", fs
->qfpathname
);
245 if (lseek(fd
, (off_t
)(id
* sizeof(struct ufs_dqblk
)), L_SET
) == (off_t
)-1) {
249 switch (read(fd
, dqblk
, sizeof(struct ufs_dqblk
))) {
252 * Convert implicit 0 quota (EOF)
253 * into an explicit one (zero'ed dqblk)
255 bzero((caddr_t
) dqblk
, sizeof(struct ufs_dqblk
));
258 case sizeof(struct ufs_dqblk
): /* OK */
262 syslog(LOG_ERR
, "read error: %s: %m", fs
->qfpathname
);
272 * Check to see if a particular quota is to be enabled.
273 * Comes from quota.c, NetBSD 0.9
276 hasquota(struct fstab
*fs
, char **qfnamep
)
278 static char initname
, usrname
[100];
279 static char buf
[BUFSIZ
];
281 const char *qfextension
[] = INITQFNAMES
;
284 sprintf(usrname
, "%s%s", qfextension
[USRQUOTA
], QUOTAFILENAME
);
287 strcpy(buf
, fs
->fs_mntops
);
288 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
289 if ((cp
= index(opt
, '=')))
291 if (strcmp(opt
, usrname
) == 0)
300 sprintf(buf
, "%s/%s.%s", fs
->fs_file
, QUOTAFILENAME
, qfextension
[USRQUOTA
]);