* For mailing lists, Alpine adds a description of the type of link
[alpine.git] / alpine / osdep / solquota
blob348bad2ad73094f42344832fed6864993c7426a8
1 static char *device_name();
3 #include <fcntl.h>
4 #include <sys/fs/ufs_quota.h>
6 /*
7  * define the "quotactl" function as in Solaris 1, based on ioctl().
8  * By Marc Mazuhelli <mazu@dmi.usherb.ca>
9  * The "special" parameter is any file on the file system,
10  * not the block special device name as in Solaris 1.
11  * Thanks to veronica@solution.maths.unsw.edu.au who provided
12  * the idea and the basis for this function.
13  *
14  * [ Apparently quotactl used to exist in SunOS but no longer exists in ]
15  * [ Solaris. This is an equivalent. If you are running on a system     ]
16  * [ which has quotactl, comment this routine out or use sunquota.      ]
17  */
19 int
20 quotactl(int cmd, char *special, uid_t uid, struct dqblk * addr)
22     struct quotctl  op;
23     int             fd = open(special, O_RDONLY);
25     if (fd < 0)
26         return -1;
28     op.op = cmd;
29     op.uid = uid;
30     op.addr = (caddr_t) addr;
32     if (ioctl(fd, Q_QUOTACTL, &op) < 0) {
33         close(fd);
34         return -1;
35     }
36     close(fd);
37     return (0);
41 /*----------------------------------------------------------------------
42    Return space left in disk quota on file system which given path is in.
44     Args: path - Path name of file or directory on file system of concern
45           over - pointer to flag that is set if the user is over quota
47  Returns: If *over = 0, the number of bytes free in disk quota as per
48           the soft limit.
49           If *over = 1, the number of bytes *over* quota.
50           -1 is returned on an error looking up quota
51            0 is returned if there is no quota
53 BUG:  If there's more than 2.1Gb free this function will break
54   ----*/
55 long
56 disk_quota(path, over)
57     char *path;
58     int  *over;
60     static int   no_quota = 0;
61     struct stat  statx;
62     struct dqblk quotax;
63     long         q;
64     char        *dname;
66     if(no_quota)
67       return(0L); /* If no quota the first time, then none the second. */
69     dprint(5, (debugfile, "quota_check path: %s\n", path ? path : "?"));
70     if(stat(path, &statx) < 0) {
71         return(-1L);
72     }
74     *over = 0;
75     errno = 0;
77     dname = device_name(statx.st_dev);
78     if(dname == NULL)
79       return(-1L);
81     dprint(7, (debugfile, "Quota check: UID:%d  device: %s\n", 
82            getuid(), dname ? dname : "?"));
83     if(quotactl(Q_GETQUOTA, dname, getuid(), (char *)&quotax) < 0) {
84         dprint(5, (debugfile, "Quota failed : %s\n",
85                    error_description(errno)));
86         return(-1L); /* Something went wrong */
87     }
89     dprint(5,(debugfile,"Quota: bsoftlimit:%d  bhardlimit:%d  curblock:%d\n",
90           quotax.dqb_bsoftlimit, quotax.dqb_bhardlimit, quotax.dqb_curblocks));
92     if(quotax.dqb_bsoftlimit == -1)
93       return(-1L);
95     q = (quotax.dqb_bsoftlimit - quotax.dqb_curblocks) * 512;    
97     if(q < 0) {
98         q = -q;
99         *over = 1;
100     }
101     dprint(5, (debugfile, "disk_quota returning :%d,  over:%d\n", q, *over));
102     return(q);
106 /*----------------------------------------------------------------------
107  *              devNumToName
109  *      This routine is here so that ex can get a device name to check
110  *      disk quotas.  One might wonder, why not use getmntent(), rather
111  *      than read /etc/mtab in this crude way?  The problem with getmntent
112  *      is that it uses stdio, and ex/vi pointedly doesn't.
113  ----*/
114 static  char
115 *device_name(st_devArg)
116     dev_t st_devArg;
118 #ifndef MTABNAME
119 #define MTABNAME "/etc/mtab"
120 #endif
121     char *mtab;
122     static char devName[48];
123     static char *answer = (char *) 0;
124     struct stat devStat;
125     static dev_t st_dev;
126     int nb, cur, bol;
127     char c;
128     int dname;
130     if (st_devArg == st_dev)
131       return answer;
133     mtab = read_file(MTABNAME);
134     if(mtab == NULL)
135       return((char *)NULL);
137     /* Initialize save data. */
138     st_dev = st_devArg;
139     answer = (char *) 0;
140     nb = strlen(mtab);
142     for (cur=bol=0, dname=1; cur < nb; ++cur) {
144         if (dname && (mtab[cur] <= ' ')) {
145         /*      Space, tab or other such character has been found,
146                 presumably marking the end of the device name string. */
147         
148             dname = 0;
149             c = mtab[cur];      /* Save current character. */
150             mtab[cur] = 0;      /* C zero-terminated string. */
152             /*  Get device number, via stat().  If it's the right
153                 number, copy the string and return its address. */
154             if (stat (&mtab[bol], &devStat) == 0) {
155                 if (devStat.st_rdev == st_dev) {
156                     if ((cur - bol + 1) < sizeof (devName)) {
157                         strncpy (devName, &mtab[bol], sizeof(devName));
158                         devName[sizeof(devName)-1] = '\0';
159                         answer = &devName[0];
160                         return(answer);
161                     }
162                 }
163             }
164             mtab[cur] = c;
165         }
166         if (mtab[cur] == '\n') {
167             dname = 1;
168             bol = cur + 1;
169         }
170     }
171     answer = NULL;
173     return(answer);