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>
31 #include <vfs/ufs/quota.h>
33 #include <rpc/pmap_clnt.h>
34 #include <rpcsvc/rquota.h>
35 #include <arpa/inet.h>
37 static void cleanup(int);
38 static void rquota_service(struct svc_req
*request
, SVCXPRT
*transp
);
39 static void sendquota(struct svc_req
*request
, SVCXPRT
*transp
);
40 static void initfs(void);
41 static int getfsquota(long id
, char *path
, struct ufs_dqblk
*dqblk
);
42 static int hasquota(struct fstab
*fs
, char **qfnamep
);
45 * structure containing informations about ufs filesystems
46 * initialised by initfs()
49 struct fs_stat
*fs_next
; /* next element */
50 char *fs_file
; /* mount point of the filesystem */
51 char *qfpathname
; /* pathname of the quota file */
52 dev_t st_dev
; /* device of the filesystem */
54 struct fs_stat
*fs_begin
= NULL
;
59 cleanup(int signo __unused
)
61 (void) pmap_unset(RQUOTAPROG
, RQUOTAVERS
);
71 struct sockaddr_in from
;
74 fromlen
= sizeof(from
);
75 if (getsockname(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
84 (void) pmap_unset(RQUOTAPROG
, RQUOTAVERS
);
86 (void) signal(SIGINT
, cleanup
);
87 (void) signal(SIGTERM
, cleanup
);
88 (void) signal(SIGHUP
, cleanup
);
91 openlog("rpc.rquotad", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
93 /* create and register the service */
94 transp
= svcudp_create(sock
);
96 syslog(LOG_ERR
, "couldn't create udp service");
99 if (!svc_register(transp
, RQUOTAPROG
, RQUOTAVERS
, rquota_service
, proto
)) {
100 syslog(LOG_ERR
, "unable to register (RQUOTAPROG, RQUOTAVERS, %s)", proto
?"udp":"(inetd)");
104 initfs(); /* init the fs_stat list */
106 syslog(LOG_ERR
, "svc_run returned");
111 rquota_service(struct svc_req
*request
, SVCXPRT
*transp
)
113 switch (request
->rq_proc
) {
115 (void)svc_sendreply(transp
, xdr_void
, (char *)NULL
);
118 case RQUOTAPROC_GETQUOTA
:
119 case RQUOTAPROC_GETACTIVEQUOTA
:
120 sendquota(request
, transp
);
124 svcerr_noproc(transp
);
131 /* read quota for the specified id, and send it */
133 sendquota(struct svc_req
*request
, SVCXPRT
*transp
)
135 struct getquota_args getq_args
;
136 struct getquota_rslt getq_rslt
;
137 struct ufs_dqblk dqblk
;
138 struct timeval timev
;
140 bzero((char *)&getq_args
, sizeof(getq_args
));
141 if (!svc_getargs(transp
, xdr_getquota_args
, (caddr_t
)&getq_args
)) {
142 svcerr_decode(transp
);
145 if (request
->rq_cred
.oa_flavor
!= AUTH_UNIX
) {
147 getq_rslt
.status
= Q_EPERM
;
148 } else if (!getfsquota(getq_args
.gqa_uid
, getq_args
.gqa_pathp
, &dqblk
)) {
149 /* failed, return noquota */
150 getq_rslt
.status
= Q_NOQUOTA
;
152 gettimeofday(&timev
, NULL
);
153 getq_rslt
.status
= Q_OK
;
154 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_active
= TRUE
;
155 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsize
= DEV_BSIZE
;
156 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
=
157 dqblk
.dqb_bhardlimit
;
158 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
=
159 dqblk
.dqb_bsoftlimit
;
160 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
=
162 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fhardlimit
=
163 dqblk
.dqb_ihardlimit
;
164 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fsoftlimit
=
165 dqblk
.dqb_isoftlimit
;
166 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curfiles
=
168 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_btimeleft
=
169 dqblk
.dqb_btime
- timev
.tv_sec
;
170 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_ftimeleft
=
171 dqblk
.dqb_itime
- timev
.tv_sec
;
173 if (!svc_sendreply(transp
, xdr_getquota_rslt
, (char *)&getq_rslt
)) {
174 svcerr_systemerr(transp
);
176 if (!svc_freeargs(transp
, xdr_getquota_args
, (caddr_t
)&getq_args
)) {
177 syslog(LOG_ERR
, "unable to free arguments");
182 /* initialise the fs_tab list from entries in /etc/fstab */
186 struct fs_stat
*fs_current
= NULL
;
187 struct fs_stat
*fs_next
= NULL
;
193 while ((fs
= getfsent())) {
194 if (strcmp(fs
->fs_vfstype
, "ufs"))
196 if (!hasquota(fs
, &qfpathname
))
199 fs_current
= (struct fs_stat
*) malloc(sizeof(struct fs_stat
));
200 fs_current
->fs_next
= fs_next
; /* next element */
202 fs_current
->fs_file
= malloc(sizeof(char) * (strlen(fs
->fs_file
) + 1));
203 strcpy(fs_current
->fs_file
, fs
->fs_file
);
205 fs_current
->qfpathname
= malloc(sizeof(char) * (strlen(qfpathname
) + 1));
206 strcpy(fs_current
->qfpathname
, qfpathname
);
208 stat(fs_current
->fs_file
, &st
);
209 fs_current
->st_dev
= st
.st_dev
;
211 fs_next
= fs_current
;
214 fs_begin
= fs_current
;
218 * gets the quotas for id, filesystem path.
219 * Return 0 if fail, 1 otherwise
222 getfsquota(long id
, char *path
, struct ufs_dqblk
*dqblk
)
226 int qcmd
, fd
, ret
= 0;
228 if (stat(path
, &st_path
) < 0)
231 qcmd
= QCMD(Q_GETQUOTA
, USRQUOTA
);
233 for (fs
= fs_begin
; fs
!= NULL
; fs
= fs
->fs_next
) {
234 /* where the devise is the same as path */
235 if (fs
->st_dev
!= st_path
.st_dev
)
238 /* find the specified filesystem. get and return quota */
239 if (quotactl(fs
->fs_file
, qcmd
, id
, dqblk
) == 0)
242 if ((fd
= open(fs
->qfpathname
, O_RDONLY
)) < 0) {
243 syslog(LOG_ERR
, "open error: %s: %m", fs
->qfpathname
);
246 if (lseek(fd
, (off_t
)(id
* sizeof(struct ufs_dqblk
)), L_SET
) == (off_t
)-1) {
250 switch (read(fd
, dqblk
, sizeof(struct ufs_dqblk
))) {
253 * Convert implicit 0 quota (EOF)
254 * into an explicit one (zero'ed dqblk)
256 bzero((caddr_t
) dqblk
, sizeof(struct ufs_dqblk
));
259 case sizeof(struct ufs_dqblk
): /* OK */
263 syslog(LOG_ERR
, "read error: %s: %m", fs
->qfpathname
);
273 * Check to see if a particular quota is to be enabled.
274 * Comes from quota.c, NetBSD 0.9
277 hasquota(struct fstab
*fs
, char **qfnamep
)
279 static char initname
, usrname
[100];
280 static char buf
[BUFSIZ
];
282 const char *qfextension
[] = INITQFNAMES
;
285 sprintf(usrname
, "%s%s", qfextension
[USRQUOTA
], QUOTAFILENAME
);
288 strcpy(buf
, fs
->fs_mntops
);
289 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
290 if ((cp
= index(opt
, '=')))
292 if (strcmp(opt
, usrname
) == 0)
301 sprintf(buf
, "%s/%s.%s", fs
->fs_file
, QUOTAFILENAME
, qfextension
[USRQUOTA
]);