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 <rpcsvc/rquota.h>
33 #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) rpcb_unset(RQUOTAPROG
, RQUOTAVERS
, NULL
);
69 struct sockaddr_storage from
;
72 fromlen
= sizeof(from
);
73 if (getsockname(0, (struct sockaddr
*)&from
, &fromlen
) < 0) {
80 (void) rpcb_unset(RQUOTAPROG
, RQUOTAVERS
, NULL
);
82 (void) signal(SIGINT
, cleanup
);
83 (void) signal(SIGTERM
, cleanup
);
84 (void) signal(SIGHUP
, cleanup
);
87 openlog("rpc.rquotad", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
89 /* create and register the service */
91 transp
= svc_tli_create(0, NULL
, NULL
, 0, 0);
93 syslog(LOG_ERR
, "couldn't create udp service.");
96 ok
= svc_reg(transp
, RQUOTAPROG
, RQUOTAVERS
,
97 rquota_service
, NULL
);
99 ok
= svc_create(rquota_service
,
100 RQUOTAPROG
, RQUOTAVERS
, "udp");
102 syslog(LOG_ERR
, "unable to register (RQUOTAPROG, RQUOTAVERS, %s)", (!from_inetd
)?"udp":"(inetd)");
106 initfs(); /* init the fs_stat list */
108 syslog(LOG_ERR
, "svc_run returned");
113 rquota_service(struct svc_req
*request
, SVCXPRT
*transp
)
115 switch (request
->rq_proc
) {
117 (void)svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
);
120 case RQUOTAPROC_GETQUOTA
:
121 case RQUOTAPROC_GETACTIVEQUOTA
:
122 sendquota(request
, transp
);
126 svcerr_noproc(transp
);
133 /* read quota for the specified id, and send it */
135 sendquota(struct svc_req
*request
, SVCXPRT
*transp
)
137 struct getquota_args getq_args
;
138 struct getquota_rslt getq_rslt
;
139 struct ufs_dqblk dqblk
;
140 struct timeval timev
;
142 bzero((char *)&getq_args
, sizeof(getq_args
));
143 if (!svc_getargs(transp
, (xdrproc_t
)xdr_getquota_args
, (caddr_t
)&getq_args
)) {
144 svcerr_decode(transp
);
147 if (request
->rq_cred
.oa_flavor
!= AUTH_UNIX
) {
149 getq_rslt
.status
= Q_EPERM
;
150 } else if (!getfsquota(getq_args
.gqa_uid
, getq_args
.gqa_pathp
, &dqblk
)) {
151 /* failed, return noquota */
152 getq_rslt
.status
= Q_NOQUOTA
;
154 gettimeofday(&timev
, NULL
);
155 getq_rslt
.status
= Q_OK
;
156 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_active
= TRUE
;
157 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsize
= DEV_BSIZE
;
158 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
=
159 dqblk
.dqb_bhardlimit
;
160 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
=
161 dqblk
.dqb_bsoftlimit
;
162 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
=
164 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fhardlimit
=
165 dqblk
.dqb_ihardlimit
;
166 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_fsoftlimit
=
167 dqblk
.dqb_isoftlimit
;
168 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_curfiles
=
170 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_btimeleft
=
171 dqblk
.dqb_btime
- timev
.tv_sec
;
172 getq_rslt
.getquota_rslt_u
.gqr_rquota
.rq_ftimeleft
=
173 dqblk
.dqb_itime
- timev
.tv_sec
;
175 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_getquota_rslt
, (char *)&getq_rslt
)) {
176 svcerr_systemerr(transp
);
178 if (!svc_freeargs(transp
, (xdrproc_t
)xdr_getquota_args
, (caddr_t
)&getq_args
)) {
179 syslog(LOG_ERR
, "unable to free arguments");
184 /* initialise the fs_tab list from entries in /etc/fstab */
188 struct fs_stat
*fs_current
= NULL
;
189 struct fs_stat
*fs_next
= NULL
;
195 while ((fs
= getfsent())) {
196 if (strcmp(fs
->fs_vfstype
, "ufs"))
198 if (!hasquota(fs
, &qfpathname
))
201 fs_current
= (struct fs_stat
*) malloc(sizeof(struct fs_stat
));
202 fs_current
->fs_next
= fs_next
; /* next element */
204 fs_current
->fs_file
= malloc(sizeof(char) * (strlen(fs
->fs_file
) + 1));
205 strcpy(fs_current
->fs_file
, fs
->fs_file
);
207 fs_current
->qfpathname
= malloc(sizeof(char) * (strlen(qfpathname
) + 1));
208 strcpy(fs_current
->qfpathname
, qfpathname
);
210 stat(fs_current
->fs_file
, &st
);
211 fs_current
->st_dev
= st
.st_dev
;
213 fs_next
= fs_current
;
216 fs_begin
= fs_current
;
220 * gets the quotas for id, filesystem path.
221 * Return 0 if fail, 1 otherwise
224 getfsquota(long id
, char *path
, struct ufs_dqblk
*dqblk
)
228 int qcmd
, fd
, ret
= 0;
230 if (stat(path
, &st_path
) < 0)
233 qcmd
= QCMD(Q_GETQUOTA
, USRQUOTA
);
235 for (fs
= fs_begin
; fs
!= NULL
; fs
= fs
->fs_next
) {
236 /* where the devise is the same as path */
237 if (fs
->st_dev
!= st_path
.st_dev
)
240 /* find the specified filesystem. get and return quota */
241 if (quotactl(fs
->fs_file
, qcmd
, id
, dqblk
) == 0)
244 if ((fd
= open(fs
->qfpathname
, O_RDONLY
)) < 0) {
245 syslog(LOG_ERR
, "open error: %s: %m", fs
->qfpathname
);
248 if (lseek(fd
, (off_t
)(id
* sizeof(struct ufs_dqblk
)), L_SET
) == (off_t
)-1) {
252 switch (read(fd
, dqblk
, sizeof(struct ufs_dqblk
))) {
255 * Convert implicit 0 quota (EOF)
256 * into an explicit one (zero'ed dqblk)
258 bzero((caddr_t
) dqblk
, sizeof(struct ufs_dqblk
));
261 case sizeof(struct ufs_dqblk
): /* OK */
265 syslog(LOG_ERR
, "read error: %s: %m", fs
->qfpathname
);
275 * Check to see if a particular quota is to be enabled.
276 * Comes from quota.c, NetBSD 0.9
279 hasquota(struct fstab
*fs
, char **qfnamep
)
281 static char initname
, usrname
[100];
282 static char buf
[BUFSIZ
];
284 const char *qfextension
[] = INITQFNAMES
;
287 sprintf(usrname
, "%s%s", qfextension
[USRQUOTA
], QUOTAFILENAME
);
290 strcpy(buf
, fs
->fs_mntops
);
291 for (opt
= strtok(buf
, ","); opt
; opt
= strtok(NULL
, ",")) {
292 if ((cp
= index(opt
, '=')))
294 if (strcmp(opt
, usrname
) == 0)
303 sprintf(buf
, "%s/%s.%s", fs
->fs_file
, QUOTAFILENAME
, qfextension
[USRQUOTA
]);