Article 128044 of comp.os.vms:
hoffman@xdelta.enet.dec.nospam (Stephen Hoff Hoffman) writes:


>In article <5qlopl$a3j@gap.cco.caltech.edu>, mathog@seqaxp.bio.caltech.edu writes:
>:I'm stumped, how do a I do the equivalent of 
>: $ SHOW QUOTA
>:from within C?

>   See the OpenVMS I/O Abuser's Manual, $QIO IO$_ACPCONTROL interface.
>   Specifically, the quota-related operations permitted via the FIB.
>   There are examples of the $QIO call around at various sites.
>
>  #include <stdio.h>
>  #include <iodef.h>
>  #include <ssdef.h>
>  #include <fibdef.h>
>  ...
>  RetStat = sys$qiow( Ef, Chan, IO$_ACPCONTROL, Iosb, 0, 0,
>	Fib, In, &OutLen, Out, 0, 0 );

here's a working program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ssdef.h"
#include "iodef.h"
#include "fibdef.h"
#include "stsdef.h"
#include "descrip.h"
#include "starlet.h"
#include "lib$routines.h"

struct GENERIC_IOSB {
    unsigned short cond;
    unsigned short retlen;
    unsigned char filler[4];
};

union OBJECT_IDENTIFIER {
    unsigned long identmask;
    unsigned long uic;
    struct {
        unsigned member : 16;
        unsigned group  : 14;
        unsigned        :  2;
    } uicparts;
    struct {
        unsigned idvalue  : 28;
        unsigned          :  3;
        unsigned IDformat :  1;    /* if set, is an ID rather than a UIC */
    } IDparts;
};

/* extrapolated header for the $DQFDEF module
 *
 * Structure of disk quota file record. Each record contains the authorization
 * and usage of a particular UIC for this volume set.
 */
#define DQF$M_ACTIVE 1        /* record contains an active entry */

struct DISK_QUOTA_FILE_RECORD {
    unsigned long dqf$l_flags;    /* flags longword (only ACTIVE at this time) */
    union OBJECT_IDENTIFIER dqf$l_uic;    /* UIC of this record */
    unsigned long dqf$l_usage;    /* number of blocks in use */
    unsigned long dqf$l_permquota;    /* permanent disk quota */
    unsigned long dqf$l_overdraft;    /* overdraft limit */
    unsigned long dqf$l_future[3];
};

int main(
    int argc,
    char *argv[]
)
{
    int bFirst = TRUE;
    char *pcDevice;
    long chan;
    unsigned long cv0;
    struct fibdef1 quotafib;
    struct dsc$descriptor fibsd;
    struct dsc$descriptor destsd;
    struct dsc$descriptor namesd;
    struct dsc$descriptor selectsd;
    struct GENERIC_IOSB iosb;
    struct DISK_QUOTA_FILE_RECORD dstrec;
    struct DISK_QUOTA_FILE_RECORD selectrec;

    if (argc > 1) {
        pcDevice = argv[1];
    }
    else {
        printf("usage: showdq diskname\n");
        exit(EXIT_SUCCESS);
    }

    namesd.dsc$a_pointer = pcDevice;
    namesd.dsc$w_length  = strlen(pcDevice);
    namesd.dsc$b_dtype   = 0;
    namesd.dsc$b_class   = 0;
    cv0 = sys$assign(&namesd, &chan, NULL, NULL);
    if ((cv0 & STS$M_SUCCESS) != STS$K_SUCCESS) {
        lib$signal(cv0, 0);
        exit(EXIT_SUCCESS);
    }

    memset(&quotafib, 0, sizeof(quotafib));
    memset(&selectrec, 0, sizeof(selectrec));

    destsd.dsc$a_pointer = (char *) &dstrec;
    destsd.dsc$w_length  = sizeof(dstrec);
    destsd.dsc$b_dtype   = 0;
    destsd.dsc$b_class   = 0;
    fibsd.dsc$a_pointer  = (char *) &quotafib;
    fibsd.dsc$w_length   = sizeof(quotafib);
    fibsd.dsc$b_dtype    = 0;
    fibsd.dsc$b_class    = 0;
    selectsd.dsc$a_pointer  = (char *) &selectrec;
    selectsd.dsc$w_length   = sizeof(selectrec);
    selectsd.dsc$b_dtype    = 0;
    selectsd.dsc$b_class    = 0;
    quotafib.fib$w_cntrlfunc = FIB$C_EXA_QUOTA;
    quotafib.fib$l_cntrlval = FIB$M_ALL_GRP | FIB$M_ALL_MEM;
    while (1) {
        cv0 = sys$qiow(0, chan, IO$_ACPCONTROL, &iosb, NULL, 0, &fibsd, &selectsd, NULL, &destsd, NULL, NULL);
        if ((cv0 & STS$M_SUCCESS) == STS$K_SUCCESS) {
            cv0 = iosb.cond;
        }
        if ((cv0 & STS$M_SUCCESS) != STS$K_SUCCESS) {
            /* the equivalent of EOF */
            if (cv0 != SS$_NODISKQUOTA) {
                lib$signal(cv0, 0);
            }
            break;
        }
        if ((dstrec.dqf$l_flags & DQF$M_ACTIVE) != 0) {
            if (bFirst) {
                bFirst = FALSE;
                printf("UIC             Usage     PermQuota Overdraft\n");
                printf("--------------- --------- --------- ---------\n");
            }
            printf("[%6o,%6o] %9d %9d %9d\n",
                (int) dstrec.dqf$l_uic.uicparts.group,
                (int) dstrec.dqf$l_uic.uicparts.member,
                dstrec.dqf$l_usage,
                dstrec.dqf$l_permquota,
                dstrec.dqf$l_overdraft);
        }
    }
    sys$dassgn(chan);

    exit(EXIT_SUCCESS);
}

>:Actually, it should also detect if the process has exquota or bypass or
>:something similar, and use the nonquota form for that too. 

sorry, this code merely dumps the data to stdout.  doesn't even lookup
username via UIC, which of course it should.

>  The best way to do this particular quota check is to not do an
>  explicit check -- try the operation, and process the failure(s).

true.  but this code is good for reporting purposes, since DISKQUOTA sucks.

ok
dpm
-- 
David P. Murphy             mailto:murphy@connor.datametrics.com     (work)
systems programmer          mailto:dpm@access.digex.net          (personal)
                            http://www.access.digex.net/~dpm
COGITO ERGO DISCLAMO         ftp://ftp.access.digex.net/pub/access/dpm


