summaryrefslogtreecommitdiff
path: root/alpine/osdep/solquota
blob: 348bad2ad73094f42344832fed6864993c7426a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
static char *device_name();

#include <fcntl.h>
#include <sys/fs/ufs_quota.h>

/*
 * define the "quotactl" function as in Solaris 1, based on ioctl().
 * By Marc Mazuhelli <mazu@dmi.usherb.ca>
 * The "special" parameter is any file on the file system,
 * not the block special device name as in Solaris 1.
 * Thanks to veronica@solution.maths.unsw.edu.au who provided
 * the idea and the basis for this function.
 *
 * [ Apparently quotactl used to exist in SunOS but no longer exists in ]
 * [ Solaris. This is an equivalent. If you are running on a system     ]
 * [ which has quotactl, comment this routine out or use sunquota.      ]
 */

int
quotactl(int cmd, char *special, uid_t uid, struct dqblk * addr)
{
    struct quotctl  op;
    int             fd = open(special, O_RDONLY);

    if (fd < 0)
        return -1;

    op.op = cmd;
    op.uid = uid;
    op.addr = (caddr_t) addr;

    if (ioctl(fd, Q_QUOTACTL, &op) < 0) {
        close(fd);
        return -1;
    }
    close(fd);
    return (0);
}


/*----------------------------------------------------------------------
   Return space left in disk quota on file system which given path is in.

    Args: path - Path name of file or directory on file system of concern
          over - pointer to flag that is set if the user is over quota

 Returns: If *over = 0, the number of bytes free in disk quota as per
          the soft limit.
	  If *over = 1, the number of bytes *over* quota.
          -1 is returned on an error looking up quota
           0 is returned if there is no quota

BUG:  If there's more than 2.1Gb free this function will break
  ----*/
long
disk_quota(path, over)
    char *path;
    int  *over;
{
    static int   no_quota = 0;
    struct stat  statx;
    struct dqblk quotax;
    long         q;
    char        *dname;

    if(no_quota)
      return(0L); /* If no quota the first time, then none the second. */

    dprint(5, (debugfile, "quota_check path: %s\n", path ? path : "?"));
    if(stat(path, &statx) < 0) {
        return(-1L);
    }

    *over = 0;
    errno = 0;

    dname = device_name(statx.st_dev);
    if(dname == NULL)
      return(-1L);

    dprint(7, (debugfile, "Quota check: UID:%d  device: %s\n", 
           getuid(), dname ? dname : "?"));
    if(quotactl(Q_GETQUOTA, dname, getuid(), (char *)&quotax) < 0) {
        dprint(5, (debugfile, "Quota failed : %s\n",
                   error_description(errno)));
        return(-1L); /* Something went wrong */
    }

    dprint(5,(debugfile,"Quota: bsoftlimit:%d  bhardlimit:%d  curblock:%d\n",
          quotax.dqb_bsoftlimit, quotax.dqb_bhardlimit, quotax.dqb_curblocks));

    if(quotax.dqb_bsoftlimit == -1)
      return(-1L);

    q = (quotax.dqb_bsoftlimit - quotax.dqb_curblocks) * 512;    

    if(q < 0) {
        q = -q;
        *over = 1;
    }
    dprint(5, (debugfile, "disk_quota returning :%d,  over:%d\n", q, *over));
    return(q);
}


/*----------------------------------------------------------------------
 *		devNumToName
 *
 *	This routine is here so that ex can get a device name to check
 *	disk quotas.  One might wonder, why not use getmntent(), rather
 *	than read /etc/mtab in this crude way?  The problem with getmntent
 *	is that it uses stdio, and ex/vi pointedly doesn't.
 ----*/
static  char
*device_name(st_devArg)
    dev_t st_devArg;
{
#ifndef MTABNAME
#define MTABNAME "/etc/mtab"
#endif
    char *mtab;
    static char devName[48];
    static char *answer = (char *) 0;
    struct stat devStat;
    static dev_t st_dev;
    int nb, cur, bol;
    char c;
    int dname;

    if (st_devArg == st_dev)
      return answer;

    mtab = read_file(MTABNAME);
    if(mtab == NULL)
      return((char *)NULL);

    /* Initialize save data. */
    st_dev = st_devArg;
    answer = (char *) 0;
    nb = strlen(mtab);

    for (cur=bol=0, dname=1; cur < nb; ++cur) {

	if (dname && (mtab[cur] <= ' ')) {
	/*	Space, tab or other such character has been found,
		presumably marking the end of the device name string. */
	
	    dname = 0;
	    c = mtab[cur];	/* Save current character. */
	    mtab[cur] = 0;	/* C zero-terminated string. */

	    /*	Get device number, via stat().  If it's the right
		number, copy the string and return its address. */
	    if (stat (&mtab[bol], &devStat) == 0) {
		if (devStat.st_rdev == st_dev) {
		    if ((cur - bol + 1) < sizeof (devName)) {
			strncpy (devName, &mtab[bol], sizeof(devName));
			devName[sizeof(devName)-1] = '\0';
                        answer = &devName[0];
			return(answer);
		    }
		}
	    }
	    mtab[cur] = c;
	}
	if (mtab[cur] == '\n') {
	    dname = 1;
	    bol = cur + 1;
	}
    }
    answer = NULL;

    return(answer);
}