File Coverage

Quota.xs
Criterion Covered Total %
statement 0 228 0.0
branch 0 136 0.0
condition n/a
subroutine n/a
pod n/a
total 0 364 0.0


line stmt bran cond sub pod time code
1             #ifdef __cplusplus
2             extern "C" {
3             #endif
4             #include "EXTERN.h"
5             #include "perl.h"
6             #include "XSUB.h"
7             #ifdef __cplusplus
8             }
9             #endif
10              
11             #include "myconfig.h"
12              
13             #ifdef SFIO_VERSION
14             #include "stdio_wrap.h"
15             #else
16             #define std_fopen fopen
17             #define std_fclose fclose
18             #endif
19              
20             #ifdef AFSQUOTA
21             #include "include/afsquota.h"
22             #endif
23              
24             #ifdef SOLARIS_VXFS
25             #include "include/vxquotactl.h"
26             #endif
27              
28             #ifndef AIX
29             #ifndef NO_MNTENT
30             FILE *mtab = NULL;
31             #else /* NO_MNTENT */
32             #ifdef HAVE_STATVFS
33             struct statvfs *mntp, *mtab = NULL;
34             #else
35             struct statfs *mntp, *mtab = NULL;
36             #endif
37             int mtab_size = 0;
38             #endif /* NO_MNTENT */
39             #else /* AIX */
40             static struct vmount *mtab = NULL;
41             static aix_mtab_idx, aix_mtab_count;
42             #endif
43              
44             #define RPC_DEFAULT_TIMEOUT 4000
45              
46             #ifndef NO_RPC
47             static struct
48             {
49             char use_tcp;
50             unsigned short port;
51             unsigned timeout;
52             } quota_rpc_cfg = {FALSE, 0, 4000};
53              
54             static struct
55             {
56             int uid;
57             int gid;
58             char hostname[MAX_MACHINE_NAME + 1];
59             } quota_rpc_auth = {-1, -1, {0} };
60              
61             static const char * quota_rpc_strerror = NULL;
62              
63             struct quota_xs_nfs_rslt {
64             double bhard;
65             double bsoft;
66             double bcur;
67             time_t btime;
68             double fhard;
69             double fsoft;
70             double fcur;
71             time_t ftime;
72             };
73              
74             /*
75             * fetch quotas from remote host
76             */
77              
78             int
79 0           callaurpc(char *host, int prognum, int versnum, int procnum,
80             xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
81             {
82             struct sockaddr_in remaddr;
83             struct hostent *hp;
84             enum clnt_stat clnt_stat;
85             struct timeval rep_time, timeout;
86             CLIENT *client;
87 0           int socket = RPC_ANYSOCK;
88              
89             /*
90             * Get IP address; by default the port is determined via remote
91             * portmap daemon; different ports and protocols can be configured
92             */
93 0           hp = gethostbyname(host);
94 0 0         if (hp == NULL) {
95 0           quota_rpc_strerror = clnt_sperrno(RPC_UNKNOWNHOST);
96 0           return -1;
97             }
98              
99 0           rep_time.tv_sec = quota_rpc_cfg.timeout / 1000;
100 0           rep_time.tv_usec = (quota_rpc_cfg.timeout % 1000) * 1000;
101 0           memcpy((char *)&remaddr.sin_addr, (char *)hp->h_addr, hp->h_length);
102 0           remaddr.sin_family = AF_INET;
103 0           remaddr.sin_port = htons(quota_rpc_cfg.port);
104              
105             /*
106             * Create client RPC handle
107             */
108 0           client = NULL;
109 0 0         if (!quota_rpc_cfg.use_tcp) {
110 0           client = (CLIENT *)clntudp_create(&remaddr, prognum,
111             versnum, rep_time, &socket);
112             }
113             else {
114 0           client = (CLIENT *)clnttcp_create(&remaddr, prognum,
115             versnum, &socket, 0, 0);
116             }
117              
118 0 0         if (client == NULL) {
119 0 0         if (rpc_createerr.cf_stat != RPC_SUCCESS)
120 0           quota_rpc_strerror = clnt_sperrno(rpc_createerr.cf_stat);
121             else /* should never happen (may be due to inconsistent symbol resolution */
122 0           quota_rpc_strerror = "RPC creation failed for unknown reasons";
123 0           return -1;
124             }
125              
126             /*
127             * Create an authentication handle
128             */
129 0 0         if ((quota_rpc_auth.uid != -1) && (quota_rpc_auth.gid != -1)) {
    0          
130 0           client->cl_auth = authunix_create(quota_rpc_auth.hostname,
131 0           quota_rpc_auth.uid,
132 0           quota_rpc_auth.gid, 0, 0);
133             }
134             else {
135 0           client->cl_auth = authunix_create_default();
136             }
137              
138             /*
139             * Call remote server
140             */
141 0           timeout.tv_sec = quota_rpc_cfg.timeout / 1000;
142 0           timeout.tv_usec = (quota_rpc_cfg.timeout % 1000) * 1000;
143 0           clnt_stat = clnt_call(client, procnum,
144             inproc, in, outproc, out, timeout);
145              
146 0 0         if (client->cl_auth) {
147 0           auth_destroy(client->cl_auth);
148 0           client->cl_auth = NULL;
149             }
150 0           clnt_destroy(client);
151              
152 0 0         if (clnt_stat != RPC_SUCCESS) {
153 0           quota_rpc_strerror = clnt_sperrno(clnt_stat);
154 0           return -1;
155             }
156             else
157 0           return 0;
158             }
159              
160             int
161 0           getnfsquota( char *hostp, char *fsnamep, int uid, int kind,
162             struct quota_xs_nfs_rslt *rslt )
163             {
164             struct getquota_args gq_args;
165             struct getquota_rslt gq_rslt;
166             #ifdef USE_EXT_RQUOTA
167             ext_getquota_args ext_gq_args;
168              
169             /*
170             * First try USE_EXT_RQUOTAPROG (Extended quota RPC)
171             */
172             ext_gq_args.gqa_pathp = fsnamep;
173             ext_gq_args.gqa_id = uid;
174             ext_gq_args.gqa_type = ((kind != 0) ? GQA_TYPE_GRP : GQA_TYPE_USR);
175              
176             if (callaurpc(hostp, RQUOTAPROG, EXT_RQUOTAVERS, RQUOTAPROC_GETQUOTA,
177             xdr_ext_getquota_args, &ext_gq_args,
178             xdr_getquota_rslt, &gq_rslt) != 0)
179             #endif
180             {
181             /*
182             * Fall back to RQUOTAPROG if the server (or client via compile switch)
183             * don't support extended quota RPC
184             */
185 0           gq_args.gqa_pathp = fsnamep;
186 0           gq_args.gqa_uid = uid;
187              
188 0 0         if (callaurpc(hostp, RQUOTAPROG, RQUOTAVERS, RQUOTAPROC_GETQUOTA,
189             (xdrproc_t)xdr_getquota_args, (char*)&gq_args,
190             (xdrproc_t)xdr_getquota_rslt, (char*)&gq_rslt) != 0) {
191 0           return -1;
192             }
193             }
194              
195 0           switch (gq_rslt.GQR_STATUS) {
196             case Q_OK:
197             {
198             struct timeval tv;
199             int qb_fac;
200              
201 0           gettimeofday(&tv, NULL);
202             #ifdef LINUX_RQUOTAD_BUG
203             /* Since Linux reports a bogus block size value (4k), we must not
204             * use it. Thankfully Linux at least always uses 1k block sizes
205             * for quota reports, so we just leave away all conversions.
206             * If you have a mixed environment, you have a problem though.
207             * Complain to the Linux authors or apply my patch (see INSTALL)
208             */
209             rslt->bhard = gq_rslt.GQR_RQUOTA.rq_bhardlimit;
210             rslt->bsoft = gq_rslt.GQR_RQUOTA.rq_bsoftlimit;
211             rslt->bcur = gq_rslt.GQR_RQUOTA.rq_curblocks;
212             #else /* not buggy */
213 0 0         if (gq_rslt.GQR_RQUOTA.rq_bsize >= DEV_QBSIZE) {
214             /* assign first, multiply later:
215             ** so that mult works with the possibly larger type in rslt */
216 0           rslt->bhard = gq_rslt.GQR_RQUOTA.rq_bhardlimit;
217 0           rslt->bsoft = gq_rslt.GQR_RQUOTA.rq_bsoftlimit;
218 0           rslt->bcur = gq_rslt.GQR_RQUOTA.rq_curblocks;
219              
220             /* we rely on the fact that block sizes are always powers of 2 */
221             /* so the conversion factor will never be a fraction */
222 0           qb_fac = gq_rslt.GQR_RQUOTA.rq_bsize / DEV_QBSIZE;
223 0           rslt->bhard *= qb_fac;
224 0           rslt->bsoft *= qb_fac;
225 0           rslt->bcur *= qb_fac;
226             }
227             else {
228 0 0         if (gq_rslt.GQR_RQUOTA.rq_bsize != 0)
229 0           qb_fac = DEV_QBSIZE / gq_rslt.GQR_RQUOTA.rq_bsize;
230             else
231 0           qb_fac = 1;
232 0           rslt->bhard = gq_rslt.GQR_RQUOTA.rq_bhardlimit / qb_fac;
233 0           rslt->bsoft = gq_rslt.GQR_RQUOTA.rq_bsoftlimit / qb_fac;
234 0           rslt->bcur = gq_rslt.GQR_RQUOTA.rq_curblocks / qb_fac;
235             }
236             #endif /* LINUX_RQUOTAD_BUG */
237 0           rslt->fhard = gq_rslt.GQR_RQUOTA.rq_fhardlimit;
238 0           rslt->fsoft = gq_rslt.GQR_RQUOTA.rq_fsoftlimit;
239 0           rslt->fcur = gq_rslt.GQR_RQUOTA.rq_curfiles;
240              
241             /* if time is given relative to actual time, add actual time */
242             /* Note: all systems except Linux return relative times */
243 0 0         if (gq_rslt.GQR_RQUOTA.rq_btimeleft == 0)
244 0           rslt->btime = 0;
245 0 0         else if (gq_rslt.GQR_RQUOTA.rq_btimeleft + 10*365*24*60*60 < tv.tv_sec)
246 0           rslt->btime = tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_btimeleft;
247             else
248 0           rslt->btime = gq_rslt.GQR_RQUOTA.rq_btimeleft;
249              
250 0 0         if (gq_rslt.GQR_RQUOTA.rq_ftimeleft == 0)
251 0           rslt->ftime = 0;
252 0 0         else if (gq_rslt.GQR_RQUOTA.rq_ftimeleft + 10*365*24*60*60 < tv.tv_sec)
253 0           rslt->ftime = tv.tv_sec + gq_rslt.GQR_RQUOTA.rq_ftimeleft;
254             else
255 0           rslt->ftime = gq_rslt.GQR_RQUOTA.rq_ftimeleft;
256              
257             #if 0
258             if((gq_rslt.GQR_RQUOTA.rq_bhardlimit == 0) &&
259             (gq_rslt.GQR_RQUOTA.rq_bsoftlimit == 0) &&
260             (gq_rslt.GQR_RQUOTA.rq_fhardlimit == 0) &&
261             (gq_rslt.GQR_RQUOTA.rq_fsoftlimit == 0)) {
262             errno = ESRCH;
263             return(-1);
264             }
265             #endif
266 0           return 0;
267             }
268              
269             case Q_NOQUOTA:
270 0           errno = ESRCH;
271 0           break;
272              
273             case Q_EPERM:
274 0           errno = EPERM;
275 0           break;
276              
277             default:
278 0           errno = EINVAL;
279 0           break;
280             }
281 0           return -1;
282             }
283              
284             #ifdef MY_XDR
285              
286             struct xdr_discrim gq_des[2] = {
287             { (int)Q_OK, (xdrproc_t)xdr_rquota },
288             { 0, NULL }
289             };
290              
291             bool_t
292             xdr_getquota_args(xdrs, gqp)
293             XDR *xdrs;
294             struct getquota_args *gqp;
295             {
296 0           return (xdr_string(xdrs, &gqp->gqa_pathp, 1024) &&
297 0           xdr_int(xdrs, &gqp->gqa_uid));
298             }
299              
300             bool_t
301             xdr_getquota_rslt(xdrs, gqp)
302             XDR *xdrs;
303             struct getquota_rslt *gqp;
304             {
305 0           return (xdr_union(xdrs,
306 0           (int *) &gqp->GQR_STATUS, (char *) &gqp->GQR_RQUOTA,
307             gq_des, (xdrproc_t) xdr_void));
308             }
309              
310             bool_t
311             xdr_rquota(xdrs, rqp)
312             XDR *xdrs;
313             struct rquota *rqp;
314             {
315 0 0         return (xdr_int(xdrs, &rqp->rq_bsize) &&
316 0 0         xdr_bool(xdrs, &rqp->rq_active) &&
317 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_bhardlimit) &&
318 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_bsoftlimit) &&
319 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_curblocks) &&
320 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_fhardlimit) &&
321 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_fsoftlimit) &&
322 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_curfiles) &&
323 0 0         xdr_u_long(xdrs, (unsigned long *)&rqp->rq_btimeleft) &&
    0          
324 0           xdr_u_long(xdrs, (unsigned long *)&rqp->rq_ftimeleft) );
325             }
326             #endif /* MY_XDR */
327              
328             #ifdef USE_EXT_RQUOTA
329             bool_t
330             xdr_ext_getquota_args(xdrs, objp)
331             XDR *xdrs;
332             ext_getquota_args *objp;
333             {
334             return xdr_string(xdrs, &objp->gqa_pathp, RQ_PATHLEN) &&
335             xdr_int(xdrs, &objp->gqa_type) &&
336             xdr_int(xdrs, &objp->gqa_id);
337             }
338             #endif /* USE_EXT_RQUOTA */
339              
340             #endif /* !NO_RPC */
341              
342             /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
343             *
344             * The Perl interface
345             *
346             */
347              
348             MODULE = Quota PACKAGE = Quota
349             PROTOTYPES: DISABLE
350              
351             void
352             query(dev,uid=getuid(),kind=0)
353             char * dev
354             int uid
355             int kind
356             PPCODE:
357             {
358 0           char *p = NULL;
359             int err;
360             #ifndef NO_RPC
361 0           quota_rpc_strerror = NULL;
362             #endif
363             #ifdef SGI_XFS
364 0 0         if(!strncmp(dev, "(XFS)", 5)) {
365             fs_disk_quota_t xfs_dqblk;
366             #ifndef linux
367             err = quotactl(Q_XGETQUOTA, dev+5, uid, CADR &xfs_dqblk);
368             #else
369 0 0         err = quotactl(QCMD(Q_XGETQUOTA, ((kind == 2) ? XQM_PRJQUOTA : ((kind == 1) ? XQM_GRPQUOTA : XQM_USRQUOTA))), dev+5, uid, CADR &xfs_dqblk);
    0          
370             #endif
371 0 0         if(!err) {
372 0 0         EXTEND(SP, 8);
373 0           PUSHs(sv_2mortal(newSVnv(QX_DIV(xfs_dqblk.d_bcount))));
374 0           PUSHs(sv_2mortal(newSVnv(QX_DIV(xfs_dqblk.d_blk_softlimit))));
375 0           PUSHs(sv_2mortal(newSVnv(QX_DIV(xfs_dqblk.d_blk_hardlimit))));
376 0           PUSHs(sv_2mortal(newSViv(xfs_dqblk.d_btimer)));
377 0           PUSHs(sv_2mortal(newSVnv(xfs_dqblk.d_icount)));
378 0           PUSHs(sv_2mortal(newSVnv(xfs_dqblk.d_ino_softlimit)));
379 0           PUSHs(sv_2mortal(newSVnv(xfs_dqblk.d_ino_hardlimit)));
380 0           PUSHs(sv_2mortal(newSViv(xfs_dqblk.d_itimer)));
381             }
382             }
383             else
384             #endif
385             #ifdef SOLARIS_VXFS
386             if(!strncmp(dev, "(VXFS)", 6)) {
387             struct vx_dqblk vxfs_dqb;
388             err = vx_quotactl(VX_GETQUOTA, dev+6, uid, CADR &vxfs_dqb);
389             if(!err) {
390             EXTEND(SP,8);
391             PUSHs(sv_2mortal(newSVnv(Q_DIV(vxfs_dqb.dqb_curblocks))));
392             PUSHs(sv_2mortal(newSVnv(Q_DIV(vxfs_dqb.dqb_bsoftlimit))));
393             PUSHs(sv_2mortal(newSVnv(Q_DIV(vxfs_dqb.dqb_bhardlimit))));
394             PUSHs(sv_2mortal(newSViv(vxfs_dqb.dqb_btimelimit)));
395             PUSHs(sv_2mortal(newSVnv(vxfs_dqb.dqb_curfiles)));
396             PUSHs(sv_2mortal(newSVnv(vxfs_dqb.dqb_fsoftlimit)));
397             PUSHs(sv_2mortal(newSVnv(vxfs_dqb.dqb_fhardlimit)));
398             PUSHs(sv_2mortal(newSViv(vxfs_dqb.dqb_ftimelimit)));
399             }
400             }
401             else
402             #endif
403             #ifdef AFSQUOTA
404             if(!strncmp(dev, "(AFS)", 5)) {
405             if (!afs_check()) { /* check is *required* as setup! */
406             errno = EINVAL;
407             }
408             else {
409             int maxQuota, blocksUsed;
410              
411             err = afs_getquota(dev + 5, &maxQuota, &blocksUsed);
412             if(!err) {
413             EXTEND(SP, 8);
414             PUSHs(sv_2mortal(newSViv(blocksUsed)));
415             PUSHs(sv_2mortal(newSViv(maxQuota)));
416             PUSHs(sv_2mortal(newSViv(maxQuota)));
417             PUSHs(sv_2mortal(newSViv(0)));
418             PUSHs(sv_2mortal(newSViv(0)));
419             PUSHs(sv_2mortal(newSViv(0)));
420             PUSHs(sv_2mortal(newSViv(0)));
421             PUSHs(sv_2mortal(newSViv(0)));
422             }
423             }
424             }
425             else
426             #endif
427             {
428 0 0         if((*dev != '/') && (p = strchr(dev, ':'))) {
    0          
429             #ifndef NO_RPC
430             struct quota_xs_nfs_rslt rslt;
431 0           *p = '\0';
432 0           err = getnfsquota(dev, p+1, uid, kind, &rslt);
433 0 0         if (!err) {
434 0 0         EXTEND(SP, 8);
435 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bcur))));
436 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bsoft))));
437 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bhard))));
438 0           PUSHs(sv_2mortal(newSViv(rslt.btime)));
439 0           PUSHs(sv_2mortal(newSVnv(rslt.fcur)));
440 0           PUSHs(sv_2mortal(newSVnv(rslt.fsoft)));
441 0           PUSHs(sv_2mortal(newSVnv(rslt.fhard)));
442 0           PUSHs(sv_2mortal(newSViv(rslt.ftime)));
443             }
444 0           *p = ':';
445             #else /* NO_RPC */
446             errno = ENOTSUP;
447             err = -1;
448             #endif /* NO_RPC */
449             }
450             else {
451             #ifdef NETBSD_LIBQUOTA
452             struct quotahandle *qh = quota_open(dev);
453             if (qh != NULL) {
454             struct quotakey qk_blocks, qk_files;
455             struct quotaval qv_blocks, qv_files;
456              
457             qk_blocks.qk_idtype = qk_files.qk_idtype = kind ? QUOTA_IDTYPE_GROUP : QUOTA_IDTYPE_USER;
458             qk_blocks.qk_id = qk_files.qk_id = uid;
459             qk_blocks.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
460             qk_files.qk_objtype = QUOTA_OBJTYPE_FILES;
461              
462             if ( (quota_get(qh, &qk_blocks, &qv_blocks) >= 0) &&
463             (quota_get(qh, &qk_files, &qv_files) >= 0) ) {
464             EXTEND(SP, 8);
465             PUSHs(sv_2mortal(newSVnv(Q_DIV(qv_blocks.qv_usage))));
466             PUSHs(sv_2mortal(newSVnv(Q_DIV(qv_blocks.qv_softlimit))));
467             PUSHs(sv_2mortal(newSVnv(Q_DIV(qv_blocks.qv_hardlimit))));
468             PUSHs(sv_2mortal(newSViv(qv_blocks.qv_expiretime)));
469             PUSHs(sv_2mortal(newSVnv(qv_files.qv_usage)));
470             PUSHs(sv_2mortal(newSVnv(qv_files.qv_softlimit)));
471             PUSHs(sv_2mortal(newSVnv(qv_files.qv_hardlimit)));
472             PUSHs(sv_2mortal(newSViv(qv_files.qv_expiretime)));
473             }
474             quota_close(qh);
475             }
476             #else /* not NETBSD_LIBQUOTA */
477             struct dqblk dqblk;
478             #ifdef USE_IOCTL
479             struct quotactl qp;
480             int fd = -1;
481              
482             qp.op = Q_GETQUOTA;
483             qp.uid = uid;
484             qp.addr = (char *)&dqblk;
485             if ((fd = open(dev, O_RDONLY)) != -1) {
486             err = (ioctl(fd, Q_QUOTACTL, &qp) == -1);
487             close(fd);
488             }
489             else {
490             err = 1;
491             }
492             #else /* not USE_IOCTL */
493             #ifdef Q_CTL_V3 /* Linux */
494 0           err = linuxquota_query(dev, uid, (kind != 0), &dqblk);
495             #else /* not Q_CTL_V3 */
496             #ifdef Q_CTL_V2
497             #ifdef AIX
498             /* AIX quotactl doesn't fail if path does not exist!? */
499             struct stat st;
500             #if defined(HAVE_JFS2)
501             if (strncmp(dev, "(JFS2)", 6) == 0) {
502             if (stat(dev + 6, &st) == 0) {
503             quota64_t user_quota;
504              
505             err = quotactl(dev + 6, QCMD(Q_J2GETQUOTA, ((kind != 0) ? GRPQUOTA : USRQUOTA)),
506             uid, CADR &user_quota);
507             if (!err) {
508             EXTEND(SP, 8);
509             PUSHs(sv_2mortal(newSVnv(user_quota.bused)));
510             PUSHs(sv_2mortal(newSVnv(user_quota.bsoft)));
511             PUSHs(sv_2mortal(newSVnv(user_quota.bhard)));
512             PUSHs(sv_2mortal(newSViv(user_quota.btime)));
513             PUSHs(sv_2mortal(newSVnv(user_quota.ihard)));
514             PUSHs(sv_2mortal(newSVnv(user_quota.isoft)));
515             PUSHs(sv_2mortal(newSVnv(user_quota.iused)));
516             PUSHs(sv_2mortal(newSViv(user_quota.itime)));
517             }
518             }
519             err = 1; /* dummy to suppress duplicate push below */
520             }
521             #endif /* HAVE_JFS2 */
522             else if (stat(dev, &st)) {
523             err = 1;
524             }
525             else
526             #endif /* AIX */
527             err = quotactl(dev, QCMD(Q_GETQUOTA, ((kind != 0) ? GRPQUOTA : USRQUOTA)), uid, CADR &dqblk);
528             #else /* not Q_CTL_V2 */
529             err = quotactl(Q_GETQUOTA, dev, uid, CADR &dqblk);
530             #endif /* not Q_CTL_V2 */
531             #endif /* Q_CTL_V3 */
532             #endif /* not USE_IOCTL */
533 0 0         if(!err) {
534 0 0         EXTEND(SP, 8);
535 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(dqblk.QS_BCUR))));
536 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(dqblk.QS_BSOFT))));
537 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(dqblk.QS_BHARD))));
538 0           PUSHs(sv_2mortal(newSViv(dqblk.QS_BTIME)));
539 0           PUSHs(sv_2mortal(newSVnv(dqblk.QS_FCUR)));
540 0           PUSHs(sv_2mortal(newSVnv(dqblk.QS_FSOFT)));
541 0           PUSHs(sv_2mortal(newSVnv(dqblk.QS_FHARD)));
542 0           PUSHs(sv_2mortal(newSViv(dqblk.QS_FTIME)));
543             }
544             #endif /* not NETBSD_LIBQUOTA */
545             }
546             }
547             }
548              
549             int
550             setqlim(dev,uid,bs,bh,fs,fh,timelimflag=0,kind=0)
551             char * dev
552             int uid
553             double bs
554             double bh
555             double fs
556             double fh
557             int timelimflag
558             int kind
559             CODE:
560             {
561             #ifndef NETBSD_LIBQUOTA
562             struct dqblk dqblk;
563             #endif
564             #ifdef USE_IOCTL
565             struct quotactl qp;
566             int fd;
567              
568             qp.op = Q_SETQLIM;
569             qp.uid = uid;
570             qp.addr = (char *)&dqblk;
571             #endif
572 0 0         if(timelimflag != 0)
573 0           timelimflag = 1;
574             #ifndef NO_RPC
575 0           quota_rpc_strerror = NULL;
576             #endif
577             #ifdef SGI_XFS
578 0 0         if(!strncmp(dev, "(XFS)", 5)) {
579             fs_disk_quota_t xfs_dqblk;
580              
581 0           xfs_dqblk.d_blk_softlimit = QX_MUL(bs);
582 0           xfs_dqblk.d_blk_hardlimit = QX_MUL(bh);
583 0           xfs_dqblk.d_btimer = timelimflag;
584 0           xfs_dqblk.d_ino_softlimit = fs;
585 0           xfs_dqblk.d_ino_hardlimit = fh;
586 0           xfs_dqblk.d_itimer = timelimflag;
587 0           xfs_dqblk.d_fieldmask = FS_DQ_LIMIT_MASK;
588 0           xfs_dqblk.d_flags = XFS_USER_QUOTA;
589             #ifndef linux
590             RETVAL = quotactl(Q_XSETQLIM, dev+5, uid, CADR &xfs_dqblk);
591             #else
592 0 0         RETVAL = quotactl(QCMD(Q_XSETQLIM, ((kind == 2) ? XQM_PRJQUOTA : ((kind == 1) ? XQM_GRPQUOTA : XQM_USRQUOTA))), dev+5, uid, CADR &xfs_dqblk);
    0          
593             #endif
594             }
595             else
596             /* if not xfs, than it's a classic IRIX efs file system */
597             #endif
598             #ifdef SOLARIS_VXFS
599             if(!strncmp(dev, "(VXFS)", 6)) {
600             struct vx_dqblk vxfs_dqb;
601              
602             vxfs_dqb.dqb_bsoftlimit = Q_MUL(bs);
603             vxfs_dqb.dqb_bhardlimit = Q_MUL(bh);
604             vxfs_dqb.dqb_btimelimit = timelimflag;
605             vxfs_dqb.dqb_fsoftlimit = fs;
606             vxfs_dqb.dqb_fhardlimit = fh;
607             vxfs_dqb.dqb_ftimelimit = timelimflag;
608             RETVAL = vx_quotactl(VX_SETQUOTA, dev+6, uid, CADR &vxfs_dqb);
609             }
610             else
611             #endif
612             #ifdef AFSQUOTA
613             if(!strncmp(dev, "(AFS)", 5)) {
614             if (!afs_check()) { /* check is *required* as setup! */
615             errno = EINVAL;
616             RETVAL = -1;
617             }
618             else
619             RETVAL = afs_setqlim(dev + 5, bh);
620             }
621             else
622             #endif
623             #if defined(HAVE_JFS2)
624             if(strncmp(dev, "(JFS2)", 6) == 0) {
625             quota64_t user_quota;
626              
627             RETVAL = quotactl(dev + 6, QCMD(Q_J2GETQUOTA, ((kind != 0) ? GRPQUOTA : USRQUOTA)),
628             uid, CADR &user_quota);
629             if (RETVAL == 0) {
630             user_quota.bsoft = bs;
631             user_quota.bhard = bh;
632             user_quota.btime = timelimflag;
633             user_quota.isoft = fs;
634             user_quota.ihard = fh;
635             user_quota.itime = timelimflag;
636             RETVAL = quotactl(dev + 6, QCMD(Q_J2PUTQUOTA, ((kind != 0) ? GRPQUOTA : USRQUOTA)),
637             uid, CADR &user_quota);
638             }
639             }
640             else
641             #endif /* HAVE_JFS2 */
642             {
643             #ifdef NETBSD_LIBQUOTA
644             struct quotahandle *qh;
645             struct quotakey qk;
646             struct quotaval qv;
647              
648             RETVAL = -1;
649             qh = quota_open(dev);
650             if (qh != NULL) {
651             qk.qk_idtype = kind ? QUOTA_IDTYPE_GROUP : QUOTA_IDTYPE_USER;
652             qk.qk_id = uid;
653              
654             qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
655              
656             /* set the grace period for blocks */
657             if (timelimflag) { /* seven days */
658             qv.qv_grace = 7*24*60*60;
659             } else if (quota_get(qh, &qk, &qv) >= 0) { /* use user's current setting */
660             /* OK */
661             } else if (qk.qk_id = QUOTA_DEFAULTID, quota_get(qh, &qk, &qv) >= 0) { /* use default setting */
662             /* OK, reset qk_id */
663             qk.qk_id = uid;
664             } else {
665             qv.qv_grace = 0; /* XXX */
666             }
667              
668             qv.qv_usage = 0;
669             qv.qv_hardlimit = Q_MUL(bh);
670             qv.qv_softlimit = Q_MUL(bs);
671             qv.qv_expiretime = 0;
672             if (quota_put(qh, &qk, &qv) >= 0) {
673             qk.qk_objtype = QUOTA_OBJTYPE_FILES;
674              
675             /* set the grace period for files, see comments above */
676             if (timelimflag) {
677             qv.qv_grace = 7*24*60*60;
678             } else if (quota_get(qh, &qk, &qv) >= 0) {
679             /* OK */
680             } else if (qk.qk_id = QUOTA_DEFAULTID, quota_get(qh, &qk, &qv) >= 0) {
681             /* OK, reset qk_id */
682             qk.qk_id = uid;
683             } else {
684             qv.qv_grace = 0; /* XXX */
685             }
686              
687             qv.qv_usage = 0;
688             qv.qv_hardlimit = fh;
689             qv.qv_softlimit = fs;
690             qv.qv_expiretime = 0;
691             if (quota_put(qh, &qk, &qv) >= 0) {
692             RETVAL = 0;
693             }
694             }
695             quota_close(qh);
696             }
697             #else /* not NETBSD_LIBQUOTA */
698 0           memset(&dqblk, 0, sizeof(dqblk));
699 0           dqblk.QS_BSOFT = Q_MUL(bs);
700 0           dqblk.QS_BHARD = Q_MUL(bh);
701 0           dqblk.QS_BTIME = timelimflag;
702 0           dqblk.QS_FSOFT = fs;
703 0           dqblk.QS_FHARD = fh;
704 0           dqblk.QS_FTIME = timelimflag;
705             #ifdef USE_IOCTL
706             if((fd = open(dev, O_RDONLY)) != -1) {
707             RETVAL = (ioctl(fd, Q_QUOTACTL, &qp) != 0);
708             close(fd);
709             }
710             else
711             RETVAL = -1;
712             #else
713             #ifdef Q_CTL_V3 /* Linux */
714 0           RETVAL = linuxquota_setqlim (dev, uid, (kind != 0), &dqblk);
715             #else
716             #ifdef Q_CTL_V2
717             RETVAL = quotactl (dev, QCMD(Q_SETQUOTA,((kind != 0) ? GRPQUOTA : USRQUOTA)), uid, CADR &dqblk);
718             #else
719             RETVAL = quotactl (Q_SETQLIM, dev, uid, CADR &dqblk);
720             #endif
721             #endif
722             #endif
723             #endif /* not NETBSD_LIBQUOTA */
724             }
725             }
726             OUTPUT:
727             RETVAL
728              
729             int
730             sync(dev=NULL)
731             char * dev
732             CODE:
733             #ifndef NO_RPC
734 0           quota_rpc_strerror = NULL;
735             #endif
736             #ifdef SOLARIS_VXFS
737             if ((dev != NULL) && !strncmp(dev, "(VXFS)", 6)) {
738             RETVAL = vx_quotactl(VX_QSYNCALL, dev+6, 0, NULL);
739             }
740             else
741             #endif
742             #ifdef AFSQUOTA
743             if ((dev != NULL) && !strncmp(dev, "(AFS)", 5)) {
744             if (!afs_check()) {
745             errno = EINVAL;
746             RETVAL = -1;
747             }
748             else {
749             int foo1, foo2;
750             RETVAL = (afs_getquota(dev + 5, &foo1, &foo2) ? -1 : 0);
751             }
752             }
753             else
754             #endif
755             #ifdef NETBSD_LIBQUOTA
756             RETVAL = 0;
757             #else /* not NETBSD_LIBQUOTA */
758             #ifdef USE_IOCTL
759             {
760             struct quotactl qp;
761             int fd;
762              
763             if(dev == NULL) {
764             qp.op = Q_ALLSYNC;
765             dev = "/"; /* is probably ignored anyways */
766             }
767             else
768             qp.op = Q_SYNC;
769             if((fd = open(dev, O_RDONLY)) != -1) {
770             RETVAL = (ioctl(fd, Q_QUOTACTL, &qp) != 0);
771             if(errno == ESRCH) errno = EINVAL;
772             close(fd);
773             }
774             else
775             RETVAL = -1;
776             }
777             #else
778             {
779             #ifdef Q_CTL_V3 /* Linux */
780             #ifdef SGI_XFS
781 0 0         if ((dev != NULL) && (!strncmp(dev, "(XFS)", 5))) {
    0          
782 0 0         if (quotactl(QCMD(Q_XQUOTASYNC, XQM_USRQUOTA), dev+5, 0, NULL) != 0)
783 0           RETVAL = 0;
784             else
785 0           RETVAL = -1;
786             }
787             else
788             #endif
789 0           RETVAL = linuxquota_sync (dev, FALSE);
790             #else
791             #ifdef Q_CTL_V2
792             #ifdef AIX
793             struct stat st;
794             #endif
795             if(dev == NULL) dev = "/";
796             #ifdef AIX
797             #if defined(HAVE_JFS2)
798             if (strncmp(dev, "(JFS2)", 6) == 0) dev += 6;
799             #endif
800             if (stat(dev, &st)) RETVAL = -1;
801             else
802             #endif
803             RETVAL = quotactl(dev, QCMD(Q_SYNC, USRQUOTA), 0, NULL);
804             #else
805             #ifdef SGI_XFS
806             #define XFS_UQUOTA (XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD)
807             /* Q_SYNC is not supported on XFS filesystems, so emulate it */
808             if ((dev != NULL) && (!strncmp(dev, "(XFS)", 5))) {
809             fs_quota_stat_t fsq_stat;
810              
811             sync();
812              
813             RETVAL = quotactl(Q_GETQSTAT, dev+5, 0, CADR &fsq_stat);
814              
815             if (!RETVAL && ((fsq_stat.qs_flags & XFS_UQUOTA) != XFS_UQUOTA)) {
816             errno = ENOENT;
817             RETVAL = -1;
818             }
819             }
820             else
821             #endif
822             RETVAL = quotactl(Q_SYNC, dev, 0, NULL);
823             #endif
824             #endif
825             }
826             #endif
827             #endif /* NETBSD_LIBQUOTA */
828             OUTPUT:
829             RETVAL
830              
831              
832             void
833             rpcquery(host,path,uid=getuid(),kind=0)
834             char * host
835             char * path
836             int uid
837             int kind
838             PPCODE:
839             {
840             #ifndef NO_RPC
841             struct quota_xs_nfs_rslt rslt;
842 0           quota_rpc_strerror = NULL;
843 0 0         if (getnfsquota(host, path, uid, kind, &rslt) == 0) {
844 0 0         EXTEND(SP, 8);
845 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bcur))));
846 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bsoft))));
847 0           PUSHs(sv_2mortal(newSVnv(Q_DIV(rslt.bhard))));
848 0           PUSHs(sv_2mortal(newSViv(rslt.btime)));
849 0           PUSHs(sv_2mortal(newSVnv(rslt.fcur)));
850 0           PUSHs(sv_2mortal(newSVnv(rslt.fsoft)));
851 0           PUSHs(sv_2mortal(newSVnv(rslt.fhard)));
852 0           PUSHs(sv_2mortal(newSViv(rslt.ftime)));
853             }
854             #else
855             errno = ENOTSUP;
856             #endif
857             }
858              
859             void
860             rpcpeer(port=0,use_tcp=FALSE,timeout=RPC_DEFAULT_TIMEOUT)
861             unsigned port
862             unsigned use_tcp
863             unsigned timeout
864             PPCODE:
865             {
866             #ifndef NO_RPC
867 0           quota_rpc_strerror = NULL;
868 0           quota_rpc_cfg.port = port;
869 0           quota_rpc_cfg.use_tcp = use_tcp;
870 0           quota_rpc_cfg.timeout = timeout;
871             #endif
872             }
873              
874             int
875             rpcauth(uid=-1,gid=-1,hostname=NULL)
876             int uid
877             int gid
878             char * hostname
879             CODE:
880             {
881             #ifndef NO_RPC
882 0           quota_rpc_strerror = NULL;
883 0 0         if ((uid == -1) && (gid == -1) && (hostname==NULL)) {
    0          
    0          
884             /* reset to default values */
885 0           quota_rpc_auth.uid = uid;
886 0           quota_rpc_auth.gid = gid;
887 0           quota_rpc_auth.hostname[0] = 0;
888 0           RETVAL = 0;
889              
890             } else {
891 0 0         if (uid == -1)
892 0           quota_rpc_auth.uid = getuid();
893             else
894 0           quota_rpc_auth.uid = uid;
895              
896 0 0         if (gid == -1)
897 0           quota_rpc_auth.gid = getgid();
898             else
899 0           quota_rpc_auth.gid = gid;
900              
901 0 0         if (hostname == NULL) {
902 0           RETVAL = gethostname(quota_rpc_auth.hostname, MAX_MACHINE_NAME);
903 0 0         } else if (strlen(hostname) < MAX_MACHINE_NAME) {
904 0           strcpy(quota_rpc_auth.hostname, hostname);
905 0           RETVAL = 0;
906             } else {
907 0           errno = EINVAL;
908 0           RETVAL = -1;
909             }
910             }
911             #endif
912             }
913             OUTPUT:
914             RETVAL
915              
916             int
917             setmntent()
918             CODE:
919             {
920             #ifndef NO_RPC
921 0           quota_rpc_strerror = NULL;
922             #endif
923             #ifndef AIX
924             #ifndef NO_MNTENT
925             #ifndef NO_OPEN_MNTTAB
926 0 0         if(mtab != NULL) endmntent(mtab);
927 0 0         if((mtab = setmntent(MOUNTED, "r")) == NULL)
928             #else
929             if(mtab != NULL) fclose(mtab);
930             if((mtab = std_fopen (MOUNTED,"r")) == NULL)
931             #endif
932 0           RETVAL = -1;
933             else
934 0           RETVAL = 0;
935             #else /* NO_MNTENT */
936             /* if(mtab != NULL) free(mtab); */
937             if((mtab_size = getmntinfo(&mtab, MNT_NOWAIT)) <= 0)
938             RETVAL = -1;
939             else
940             RETVAL = 0;
941             mntp = mtab;
942             #endif
943             #else /* AIX */
944             int count, space;
945              
946             if(mtab != NULL) free(mtab);
947             count = mntctl(MCTL_QUERY, sizeof(space), (char *) &space);
948             if (count == 0) {
949             mtab = (struct vmount *) malloc(space);
950             if (mtab != NULL) {
951             count = mntctl(MCTL_QUERY, space, (char *) mtab);
952             if (count > 0) {
953             aix_mtab_count = count;
954             aix_mtab_idx = 0;
955             RETVAL = 0;
956             }
957             else { /* error, or size changed between calls */
958             if (count == 0) errno = EINTR;
959             RETVAL = -1;
960             }
961             }
962             else
963             RETVAL = -1;
964             }
965             else if (count < 0)
966             RETVAL = -1;
967             else { /* should never happen */
968             errno = ENOENT;
969             RETVAL = -1;
970             }
971             #endif
972             }
973             OUTPUT:
974             RETVAL
975              
976             void
977             getmntent()
978             PPCODE:
979             {
980             #ifndef NO_RPC
981 0           quota_rpc_strerror = NULL;
982             #endif
983             #ifndef AIX
984             #ifndef NO_MNTENT
985             #ifndef NO_OPEN_MNTTAB
986             struct mntent *mntp;
987 0 0         if(mtab != NULL) {
988 0           mntp = getmntent(mtab);
989 0 0         if(mntp != NULL) {
990 0 0         EXTEND(SP, 4);
991 0           PUSHs(sv_2mortal(newSVpv(mntp->mnt_fsname, strlen(mntp->mnt_fsname))));
992 0           PUSHs(sv_2mortal(newSVpv(mntp->mnt_dir, strlen(mntp->mnt_dir))));
993 0           PUSHs(sv_2mortal(newSVpv(mntp->mnt_type, strlen(mntp->mnt_type))));
994 0           PUSHs(sv_2mortal(newSVpv(mntp->mnt_opts, strlen(mntp->mnt_opts))));
995             }
996             }
997             else
998 0           errno = EBADF;
999             #else /* NO_OPEN_MNTTAB */
1000             struct mnttab mntp;
1001             if(mtab != NULL) {
1002             if(getmntent(mtab, &mntp) == 0) {
1003             EXTEND(SP, 4);
1004             PUSHs(sv_2mortal(newSVpv(mntp.mnt_special, strlen(mntp.mnt_special))));
1005             PUSHs(sv_2mortal(newSVpv(mntp.mnt_mountp, strlen(mntp.mnt_mountp))));
1006             PUSHs(sv_2mortal(newSVpv(mntp.mnt_fstype, strlen(mntp.mnt_fstype))));
1007             PUSHs(sv_2mortal(newSVpv(mntp.mnt_mntopts, strlen(mntp.mnt_mntopts))));
1008             }
1009             }
1010             else
1011             errno = EBADF;
1012             #endif
1013             #else /* NO_MNTENT */
1014             #ifdef OSF_QUOTA
1015             char *fstype = getvfsbynumber((int)mntp->f_type);
1016             #endif
1017             if((mtab != NULL) && mtab_size) {
1018             EXTEND(SP,4);
1019             PUSHs(sv_2mortal(newSVpv(mntp->f_mntfromname, strlen(mntp->f_mntfromname))));
1020             PUSHs(sv_2mortal(newSVpv(mntp->f_mntonname, strlen(mntp->f_mntonname))));
1021             #ifdef OSF_QUOTA
1022             if (fstype != (char *) -1)
1023             PUSHs(sv_2mortal(newSVpv(fstype, strlen(fstype))));
1024             else
1025             #endif
1026             #ifdef __OpenBSD__
1027             /* OpenBSD struct statfs lacks the f_type member (starting with release 2.7) */
1028             PUSHs(sv_2mortal(newSVpv("", 0)));
1029             #else /* !__OpenBSD__ */
1030             #ifdef HAVE_STATVFS
1031             PUSHs(sv_2mortal(newSVpv(mntp->f_fstypename, strlen(mntp->f_fstypename))));
1032             #else
1033             PUSHs(sv_2mortal(newSViv((IV)mntp->f_type)));
1034             #endif /* HAVE_STATVFS */
1035             #endif /* !__OpenBSD__ */
1036             #ifdef HAVE_STATVFS
1037             PUSHs(sv_2mortal(newSViv((IV)mntp->f_flag)));
1038             #else
1039             PUSHs(sv_2mortal(newSViv((IV)mntp->f_flags)));
1040             #endif
1041             mtab_size--;
1042             mntp++;
1043             }
1044             #endif
1045             #else /* AIX */
1046             struct vmount *vmp;
1047             char *cp;
1048             int i;
1049              
1050             if ((mtab != NULL) && (aix_mtab_idx < aix_mtab_count)) {
1051             cp = (char *) mtab;
1052             for (i=0; i
1053             vmp = (struct vmount *) cp;
1054             cp += vmp->vmt_length;
1055             }
1056             vmp = (struct vmount *) cp;
1057             aix_mtab_idx += 1;
1058              
1059             EXTEND(SP,4);
1060             if ((vmp->vmt_gfstype != MNT_NFS) && (vmp->vmt_gfstype != MNT_NFS3)) {
1061             cp = vmt2dataptr(vmp, VMT_OBJECT);
1062             PUSHs(sv_2mortal(newSVpv(cp, strlen(cp))));
1063             }
1064             else {
1065             uchar *mp, *cp2;
1066             cp = vmt2dataptr(vmp, VMT_HOST);
1067             cp2 = vmt2dataptr(vmp, VMT_OBJECT);
1068             mp = malloc(strlen(cp) + strlen(cp2) + 2);
1069             if (mp != NULL) {
1070             strcpy(mp, cp);
1071             strcat(mp, ":");
1072             strcat(mp, cp2);
1073             PUSHs(sv_2mortal(newSVpv(mp, strlen(mp))));
1074             free(mp);
1075             }
1076             else {
1077             cp = "?";
1078             PUSHs(sv_2mortal(newSVpv(cp, strlen(cp))));
1079             }
1080             }
1081             cp = vmt2dataptr(vmp, VMT_STUB);
1082             PUSHs(sv_2mortal(newSVpv(cp, strlen(cp))));
1083              
1084             switch(vmp->vmt_gfstype) {
1085             case MNT_NFS: cp = "nfs"; break;
1086             case MNT_NFS3: cp = "nfs"; break;
1087             case MNT_JFS: cp = "jfs"; break;
1088             #if defined(MNT_AIX) && defined(MNT_J2) && (MNT_AIX==MNT_J2)
1089             case MNT_J2: cp = "jfs2"; break;
1090             #else
1091             #if defined(MNT_J2)
1092             case MNT_J2: cp = "jfs2"; break;
1093             #endif
1094             case MNT_AIX: cp = "aix"; break;
1095             #endif
1096             case 4: cp = "afs"; break;
1097             case MNT_CDROM: cp = "cdrom,ignore"; break;
1098             default: cp = "unknown,ignore"; break;
1099             }
1100             PUSHs(sv_2mortal(newSVpv(cp, strlen(cp))));
1101              
1102             cp = vmt2dataptr(vmp, VMT_ARGS);
1103             PUSHs(sv_2mortal(newSVpv(cp, strlen(cp))));
1104             }
1105             #endif
1106             }
1107              
1108             void
1109             endmntent()
1110             PPCODE:
1111             {
1112             #ifndef NO_RPC
1113 0           quota_rpc_strerror = NULL;
1114             #endif
1115 0 0         if(mtab != NULL) {
1116             #ifndef AIX
1117             #ifndef NO_MNTENT
1118             #ifndef NO_OPEN_MNTTAB
1119 0           endmntent(mtab); /* returns always 1 in SunOS */
1120             #else
1121             std_fclose (mtab);
1122             #endif
1123             /* #else: if(mtab != NULL) free(mtab); */
1124             #endif
1125             #else /* AIX */
1126             free(mtab);
1127             #endif
1128 0           mtab = NULL;
1129             }
1130             }
1131              
1132             char *
1133             getqcargtype()
1134             CODE:
1135             static char ret[25];
1136             #if defined(USE_IOCTL) || defined(QCARG_MNTPT)
1137             strcpy(ret, "mntpt");
1138             #else
1139             #if defined(HAVE_JFS2)
1140             strcpy(ret, "any,JFS2");
1141             #else
1142             #if defined(AIX) || defined(OSF_QUOTA)
1143             strcpy(ret, "any");
1144             #else
1145             #ifdef Q_CTL_V2
1146             strcpy(ret, "qfile");
1147             #else
1148             /* this branch applies to Q_CTL_V3 (Linux) too */
1149             #ifdef SGI_XFS
1150 0           strcpy(ret, "dev,XFS");
1151             #else
1152             strcpy(ret, "dev");
1153             #endif
1154             #endif
1155             #endif
1156             #endif
1157             #endif
1158             #ifdef AFSQUOTA
1159             strcat(ret, ",AFS");
1160             #endif
1161             #ifdef SOLARIS_VXFS
1162             strcat(ret, ",VXFS");
1163             #endif
1164 0           RETVAL = ret;
1165             OUTPUT:
1166             RETVAL
1167              
1168             const char *
1169             strerr()
1170             CODE:
1171             #ifndef NO_RPC
1172 0 0         if (quota_rpc_strerror != NULL)
1173 0           RETVAL = quota_rpc_strerror;
1174             else
1175             #endif
1176             // ENOENT for (XFS): "No quota for this user"
1177 0 0         if((errno == EINVAL) || (errno == ENOTTY) || (errno == ENOENT) || (errno == ENOSYS))
    0          
    0          
    0          
1178 0           RETVAL = "No quotas on this system";
1179 0 0         else if(errno == ENODEV)
1180 0           RETVAL = "Not a standard file system";
1181 0 0         else if(errno == EPERM)
1182 0           RETVAL = "Not privileged";
1183 0 0         else if(errno == EACCES)
1184 0           RETVAL = "Access denied";
1185 0 0         else if(errno == ESRCH)
1186             #ifdef Q_CTL_V3 /* Linux */
1187 0           RETVAL = "Quotas not enabled, no quota for this user";
1188             #else
1189             RETVAL = "No quota for this user";
1190             #endif
1191 0 0         else if(errno == EUSERS)
1192 0           RETVAL = "Quota table overflow";
1193             else
1194 0           RETVAL = strerror(errno);
1195             OUTPUT:
1196             RETVAL