1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.backsource.alert.util;
21 import java.io.File;
22 import java.io.BufferedReader;
23 import java.io.InputStreamReader;
24 import java.io.IOException;
25 import java.util.StringTokenizer;
26 import java.util.ArrayList;
27
28 import org.apache.log4j.Logger;
29
30 /***
31 * Represent a drive/partition in the filesystem.
32 *
33 * <p>A drive is a simple representation of a partition/harddisk/filesystem
34 * that is available on the computer. Through it one can get the partition/harddisk name, such as /dev/hda1 or C:, or the file system name, such as / or C:.
35 * The total size and how much of it that is used is also available as bytes.</p>
36 * <p>The only way to get one or more Drives is through the two static methods: {@link #getDrives()} and {@link #getDrive(String driveName)}.</p>
37 * <p>Currently this is done through the use of the external command df, which is supported on LINUX, FreeBSD, Mac OS X and Windows plattforms wich has <a href="http://www.cygwin.com/">CYGWIN</a> installed.</p>
38 * <h3>Examples.</h3>
39 * <p>
40 <pre>
41 // Get a single drive
42 Drive d = Drive.getDrive("/");
43 if ( d.percentUsed() > 93) {
44 System.err.println("Diskspace is soon full for normal users, percent used = " + d.percentUsed()+"%");
45 } // end of if ()
46 </pre>
47 </p>
48 <p>
49 <pre>
50 // Get all drives
51 Drive[] d = Drive.getDrives();
52 </pre>
53 </p>
54 * <p><b>Depends on: log4j.jar</b></p>
55 *
56 * @author <a href="mailto:pra@tim.se">Peter Antman</a>
57 * @version $Revision: 1.1.1.1 $
58 */
59 public class Drive {
60 private static final Logger log = Logger.getLogger(Drive.class);
61 private String driveName;
62 private long size;
63 private long used;
64 private int percentUsed = -1;
65 private File file;
66
67 private Drive (){
68
69
70 }
71
72 /***
73 * Get the name of the device.
74 */
75 public String getDriveName() {
76 return driveName;
77 }
78
79 /***
80 * Get size of device in bytes.
81 */
82 public long getSize() {
83 return size;
84 }
85
86 /***
87 * Get number of bytes used.
88 */
89 public long getUsed() {
90 return used;
91 }
92
93 /***
94 * Get percent of disk used.
95 */
96 public int getPercentUsed() {
97 if ( percentUsed != -1) {
98 return percentUsed;
99 } else {
100 if ( used == 0) {
101 return 0;
102 } else if ( size == 0) {
103 return 100;
104 } else {
105 return (int)(used/size)*100;
106
107 }
108
109 }
110
111 }
112
113 /***
114 * Get a file represenation of device, i.e filsystem mounted on device.
115 */
116 public File getFile() {
117 return file;
118 }
119
120 /***
121 * Get a string rep of device, looking like a df line.
122 */
123 public String toString() {
124 return driveName + " " +size + " " + used + " " +percentUsed +"% " + file;
125 }
126
127 /***
128 * Get a drive by its name, may be either device name or mount point name.
129 * @return a Drive or null if no drive by the given name exists.
130 */
131 public static Drive getDrive(String driveName) throws IOException{
132 Drive[] drives = getDrives(driveName);
133 if ( drives.length == 0) {
134 return null;
135 } else {
136 return drives[0];
137 }
138
139 }
140
141 /***
142 * Get all drives available on the system.
143 * @return an array of Drives, which is empty if no drives are found.
144 */
145 public static Drive[] getDrives() throws IOException{
146 return getDrives(null);
147 }
148
149 /***
150 * main entry for internal methods, delegates to correct os methods.
151 * If driveName is null, all drives on system is returned.
152 */
153 protected static Drive[] getDrives(String driveName) throws IOException{
154
155 String os = System.getProperty("os.name");
156
157 Drive[] drives = null;
158 if( os.equalsIgnoreCase("LINUX")
159 || os.equalsIgnoreCase("FreeBSD")
160 || os.equalsIgnoreCase("Mac OS X")
161 || os.equalsIgnoreCase("SunOS")
162 )
163 {
164 drives = df(driveName);
165 }
166 else if( os.equalsIgnoreCase("Windows 98")
167 || os.equalsIgnoreCase("Windows NT")
168 || os.equalsIgnoreCase("Windows 2000")
169 || os.equalsIgnoreCase("Windows XP")
170 )
171 {
172 if ( hasCygwin() ) {
173 drives = getWinDrives(driveName);
174 } else {
175 throw new IOException("Currently only supported on windows plattforms wich has cygwin installed");
176 }
177
178 }else {
179 throw new IOException("OS not supported: " + os);
180 }
181
182
183 return (drives != null ? drives : new Drive[0]);
184 }
185
186 /***
187 * Run the df command an create drives.
188 * @param drive get single drive (by device name or file system name) or if null all drives.
189 */
190 protected static Drive[] df(String drive) throws IOException{
191 String cmd = drive == null ? "df -k" : "df -k " + drive;
192 Process cpProcess = Runtime.getRuntime().exec( cmd );
193
194
195
196
197 BufferedReader reader = new BufferedReader( new InputStreamReader( cpProcess.getInputStream() ));
198
199 String line = reader.readLine();
200 ArrayList drives = new ArrayList();
201 do {
202 line = reader.readLine();
203 if ( line != null) {
204 Drive d = null;
205
206
207 try {
208 d = getDriveFromDf(line);
209 } catch (java.util.NoSuchElementException e) {
210
211
212 try {
213 line = line+reader.readLine();
214 d = getDriveFromDf(line);
215 } catch (java.util.NoSuchElementException ne) {
216
217 throw new IOException("Could not parse lines correct:" + line);
218 }
219
220 }
221 if ( d != null) {
222 drives.add( d );
223 }else {
224 throw new IOException("Could not parse lines correct:" + line);
225 }
226
227
228 }
229
230 }while (line != null);
231
232 return (Drive[])drives.toArray( new Drive[ drives.size() ] );
233
234 }
235
236 /***
237 * Parse a df line output and instantiate a Drive from it.
238 */
239 protected static Drive getDriveFromDf(String line) {
240 log.debug("DF parsing line " + line);
241 StringTokenizer tokenizer = new StringTokenizer(line);
242 String driveName= tokenizer.nextToken().trim();
243
244 String size = tokenizer.nextToken().trim();
245 String used = tokenizer.nextToken().trim();
246 tokenizer.nextToken();
247 String percent = tokenizer.nextToken().trim();
248 String file = tokenizer.nextToken().trim();
249
250 Drive d = new Drive();
251 d.driveName = driveName;
252
253
254 d.size = 1024 * Long.parseLong(size);
255 d.used = 1024 * Long.parseLong(used);
256
257 d.percentUsed = Integer.valueOf( percent.substring(0, percent.indexOf("%"))).intValue();
258 d.file = new File(file);
259 log.debug("Constructed Drive " + d);
260 return d;
261 }
262
263 /***
264 * Entry for windows.
265 * <p>Does not use df directly since cygwin df emulates a lot of
266 * extra drives to help unix commands. The file system will be constructed
267 * from the driveName.</p>
268 *
269 */
270 protected static Drive[] getWinDrives(String drive) throws IOException {
271 File[] roots;
272 if ( drive != null) {
273 roots = new File[]{ new File(drive) };
274 } else {
275
276 roots = File.listRoots();
277 }
278 ArrayList drives = new ArrayList();
279 for ( int i = 0; i<roots.length;i++) {
280 Drive d = dir(roots[i]);
281 if ( d != null) {
282
283 d.file = roots[i];
284 drives.add(d);
285 }
286
287 }
288 return (Drive[])drives.toArray( new Drive[ drives.size() ] );
289 }
290
291 /***
292 * Dir emultion on win with df installed.
293 */
294 protected static Drive dir(File drive) throws IOException{
295 Drive[] drives = df(drive.getPath());
296 if ( drives.length == 0) {
297 return null;
298 } else {
299 return drives[0];
300 }
301
302
303 }
304
305 /***
306 * Check if system has Cygwin installed (does a uname).
307 */
308 protected static boolean hasCygwin() {
309 boolean hasCygwin = false;
310 try {
311 Process cpProcess = Runtime.getRuntime().exec( "uname" );
312 BufferedReader reader = new BufferedReader( new InputStreamReader( cpProcess.getInputStream() ));
313 int exit = cpProcess.waitFor();
314 if ( exit == 0) {
315
316 String line = reader.readLine();
317 if ( line != null && line.startsWith("CYGWIN") ) {
318 hasCygwin = true;
319 }
320
321 } else {
322 log.debug("uname process ended with non zero status");
323 }
324
325 } catch (IOException e) {
326 log.debug("IOException in running uname " + e);
327
328 } catch (InterruptedException e) {
329 log.debug("uname Process thread interrupted" + e);
330
331 }
332
333 return hasCygwin;
334
335 }
336
337
338
339 public static void main (String[] args) {
340 try {
341 Drive[] drives = Drive.getDrives();
342 for ( int i = 0;i<drives.length;i++) {
343 System.out.println("Drive: " +drives[i] );
344 }
345
346
347 if ( drives.length > 0) {
348 Drive t = drives[0];
349
350 Drive d = Drive.getDrive( t.getDriveName());
351 System.out.println("Drive by driveName: " +d );
352 if ( !d.getDriveName().equals( t.getDriveName() ) ) {
353 throw new Exception("Could not get drive by driveName");
354 }
355
356 d = Drive.getDrive( t.getFile().getPath() );
357 System.out.println("Drive by file: " +d );
358 if ( !d.getFile().getPath().equals( t.getFile().getPath()) ) {
359 throw new Exception("Could not get drive by file");
360 }
361
362 }
363
364
365 } catch (Exception e) {
366 e.printStackTrace();
367 }
368
369 }
370
371 }