Got "medieval on our ass" about adding the -1 to slprintf.
[jra/samba/.git] / source3 / smbd / dfree.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    functions to calculate the free disk space
5    Copyright (C) Andrew Tridgell 1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24
25 extern int DEBUGLEVEL;
26
27 /****************************************************************************
28 normalise for DOS usage 
29 ****************************************************************************/
30 static void disk_norm(BOOL small_query, SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
31 {
32         /* check if the disk is beyond the max disk size */
33         SMB_BIG_UINT maxdisksize = lp_maxdisksize();
34         if (maxdisksize) {
35                 /* convert to blocks - and don't overflow */
36                 maxdisksize = ((maxdisksize*1024)/(*bsize))*1024;
37                 if (*dsize > maxdisksize) *dsize = maxdisksize;
38                 if (*dfree > maxdisksize) *dfree = maxdisksize-1; 
39                 /* the -1 should stop applications getting div by 0
40                    errors */
41         }  
42
43         while (*dfree > WORDMAX || *dsize > WORDMAX || *bsize < 512) {
44                 *dfree /= 2;
45                 *dsize /= 2;
46                 *bsize *= 2;
47                 if(small_query) {       
48                         /*
49                          * Force max to fit in 16 bit fields.
50                          */
51                         if (*bsize > (WORDMAX*512)) {
52                                 *bsize = (WORDMAX*512);
53                                 if (*dsize > WORDMAX)
54                                         *dsize = WORDMAX;
55                                 if (*dfree >  WORDMAX)
56                                         *dfree = WORDMAX;
57                                 break;
58                         }
59                 }
60         }
61 }
62
63
64
65 /****************************************************************************
66   return number of 1K blocks available on a path and total number 
67 ****************************************************************************/
68
69 static SMB_BIG_UINT disk_free(char *path, BOOL small_query, 
70                               SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
71 {
72         int dfree_retval;
73         SMB_BIG_UINT dfree_q = 0;
74         SMB_BIG_UINT bsize_q = 0;
75         SMB_BIG_UINT dsize_q = 0;
76         char *dfree_command;
77
78         (*dfree) = (*dsize) = 0;
79         (*bsize) = 512;
80
81         /*
82          * If external disk calculation specified, use it.
83          */
84
85         dfree_command = lp_dfree_command();
86         if (dfree_command && *dfree_command) {
87                 char *p;
88                 char **lines;
89                 pstring syscmd;
90
91                 slprintf(syscmd, sizeof(syscmd)-1, "%s %s", dfree_command, path);
92                 DEBUG (3, ("disk_free: Running command %s\n", syscmd));
93
94                 lines = file_lines_pload(syscmd, NULL, True);
95                 if (lines) {
96                         char *line = lines[0];
97
98                         DEBUG (3, ("Read input from dfree, \"%s\"\n", line));
99
100                         *dsize = (SMB_BIG_UINT)strtoul(line, &p, 10);
101                         while (p && *p & isspace(*p))
102                                 p++;
103                         if (p && *p)
104                                 *dfree = (SMB_BIG_UINT)strtoul(p, &p, 10);
105                         while (p && *p & isspace(*p))
106                                 p++;
107                         if (p && *p)
108                                 *bsize = (SMB_BIG_UINT)strtoul(p, NULL, 10);
109                         else
110                                 *bsize = 1024;
111                         file_lines_free(lines);
112                         DEBUG (3, ("Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u\n",
113                                 (unsigned int)*dsize, (unsigned int)*dfree, (unsigned int)*bsize));
114
115                         if (!*dsize)
116                                 *dsize = 2048;
117                         if (!*dfree)
118                                 *dfree = 1024;
119                 } else {
120                         DEBUG (0, ("disk_free: sys_popen() failed for command %s. Error was : %s\n",
121                                 syscmd, strerror(errno) ));
122                         sys_fsusage(path, dfree, dsize);
123                 }
124         } else
125                 sys_fsusage(path, dfree, dsize);
126
127         if (disk_quotas(path, &bsize_q, &dfree_q, &dsize_q)) {
128                 (*bsize) = bsize_q;
129                 (*dfree) = MIN(*dfree,dfree_q);
130                 (*dsize) = MIN(*dsize,dsize_q);
131         }
132
133         /* FIXME : Any reason for this assumption ? */
134         if (*bsize < 256) {
135                 DEBUG(5,("disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512\n",(int)*bsize));
136                 *bsize = 512;
137         }
138
139         if ((*dsize)<1) {
140                 static int done;
141                 if (!done) {
142                         DEBUG(0,("WARNING: dfree is broken on this system\n"));
143                         done=1;
144                 }
145                 *dsize = 20*1024*1024/(*bsize);
146                 *dfree = MAX(1,*dfree);
147         }
148
149         disk_norm(small_query,bsize,dfree,dsize);
150
151         if ((*bsize) < 1024) {
152                 dfree_retval = (*dfree)/(1024/(*bsize));
153         } else {
154                 dfree_retval = ((*bsize)/1024)*(*dfree);
155         }
156
157         return(dfree_retval);
158 }
159
160
161 /****************************************************************************
162 wrap it to get filenames right
163 ****************************************************************************/
164 SMB_BIG_UINT sys_disk_free(char *path, BOOL small_query, 
165                            SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
166 {
167         return(disk_free(dos_to_unix(path,False),small_query, bsize,dfree,dsize));
168 }