/* gdiskuse.c - code copied mostly from df.c on 4.3BSD.  */
 
/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
 
#include <stdio.h>
#if defined(AIX)
#include <fstab.h>
#include <mntent.h>
#include <sys/dstat.h>
#include <sys/filsys.h>
#define fs	filsys
#define SBSIZE	BSIZE
#define SBLOCK	1L
static struct	filsys sblock;

#else /* AIX */

#ifdef _SEQUENT_

#include <mntent.h>
#include <sys/ufsfilsys.h>

#else /* _SEQUENT */

#include <fstab.h>
#include <sys/fs.h>
#include <mtab.h>
 
static  struct  mtab mtab[NMOUNT];
static  char    root[32];

#endif /* _SEQUENT_ */
 
static  union {
          struct fs iu_fs;
          char dummy[SBSIZE];
        } sb;
#define sblock sb.iu_fs

#endif /* AIX */
 
static  int     fi;
static  int     init = 0;
 
int gdiskuse(file,maxblk,freeblk)
char *file;                     /* Name of the filesystem to status */
int  *maxblk;                   /* Capacity of the filesystem       */
int  *freeblk;                  /* Free space on the filesystem     */
{
 
    long totalblks, availblks, avail, free, used;
#if defined(AIX)
 
    char *mtab = "/etc/mtab";
    struct dstat stbuf;
    struct mntent *mp;
    FILE *mntfile;
 
    if (dstat(file, &stbuf, sizeof(struct dstat)) == 0 &&
        (stbuf.dst_mode&S_IFMT) != S_IFCHR &&
        (stbuf.dst_mode&S_IFMT) != S_IFBLK) {
            if ( (mntfile = setmntent(mtab,"r") ) == NULL) {
                fprintf(stderr,"Error opening /etc/mtab\n");
                return(-1);
            }   
            while ( ( mp = getmntent(mntfile) ) != NULL) {
                if (mp->mnt_dir[0] != 0) {
                    if (stbuf.dst_gfs != mp->mnt_gfs) continue;
                    file = mp->mnt_fsname;
                    endmntent(mntfile);
                    goto found;
                }
            }
            endmntent(mntfile);
            fprintf(stderr,"%s: mounted on unknown device\n",file);
            return(-1);
    }

#else /* AIX */
#ifdef _SEQUENT_

    struct stat s1, s2;
    struct mntent *mntp;
    FILE   *mnttab;
 
 
    if (!(mnttab = setmntent(MNTTABNAME,"r"))) {
      return(1);
    }

    while (mntp = getmntent(mnttab)) {
      if (!strcmp(file,mntp->mnt_dir+strlen(mntp->mnt_dir)-strlen(file))) {
        file = mntp->mnt_fsname;
        endmntent(mnttab);
        goto found;
      }
    }
    return(1);

#else /* _SEQUENT_ */

    struct stat stbuf;
    struct fstab *fsp;
 
 
    if (!init++) {
 
        int i;
 
        i = open("/etc/mtab", 0);
        if (i >= 0) {
                (void) read(i, (char *)mtab, sizeof (mtab));
                (void) close(i);
        }
        sync();
    }
 
    if (stat(file, &stbuf) == 0 &&
        (stbuf.st_mode&S_IFMT) != S_IFCHR &&
        (stbuf.st_mode&S_IFMT) != S_IFBLK) {
            setfsent();
            while (fsp = getfsent()) {
                    struct stat stb;
 
                    if (stat(fsp->fs_spec, &stb) == 0 &&
                        stb.st_rdev == stbuf.st_dev) {
                            file = fsp->fs_spec;
                            endfsent();
                            goto found;
                    }
            }
            endfsent();
            fprintf(stderr, "%s: mounted on unknown device\n", file);
            return (1);
    }

#endif /* _SEQUENT */
#endif /* AIX */
 
found:
    fi = open(file, 0);
    if (fi < 0) {
            perror(file);
            return (1);
    }
    if (bread(SBLOCK, (char *)&sblock, SBSIZE) == 0) {
            (void) close(fi);
            return (1);
    }
 
#if defined(AIX)
    *maxblk   =  sblock.s_fsize - sblock.s_isize;
    *freeblk  =  sblock.s_tfree;
#else
    totalblks = sblock.fs_dsize;
    free      = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
                sblock.fs_cstotal.cs_nffree;
    used      = totalblks - free;
    availblks = totalblks * (100 - sblock.fs_minfree) / 100;
    avail     = availblks > used ? availblks - used : 0;
    *maxblk   = availblks * sblock.fs_fsize / 1024;
    *freeblk  = avail     * sblock.fs_fsize / 1024;
#endif
 
    (void) close(fi);
    return (0);
}
 
long lseek();
 
bread(bno, buf, cnt)
        daddr_t bno;
        char *buf;
{
        int n;
        extern errno;
 
        (void) lseek(fi, (long)(bno * DEV_BSIZE), 0);
        if ((n=read(fi, buf, cnt)) != cnt) {
                /* probably a dismounted disk if errno == EIO */
                if (errno != EIO) {
                        printf("\nread error bno = %ld\n", bno);
                        printf("count = %d; errno = %d\n", n, errno);
                }
                return (0);
        }
        return (1);
}
