File Coverage

Quota.xs
Criterion Covered Total %
statement 34 243 13.9
branch 21 146 14.3
condition n/a
subroutine n/a
pod n/a
total 55 389 14.1


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