| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| FileSystemUtils |
|
| 5.230769230769231;5.231 |
| 1 | /* | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | * contributor license agreements. See the NOTICE file distributed with | |
| 4 | * this work for additional information regarding copyright ownership. | |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | * (the "License"); you may not use this file except in compliance with | |
| 7 | * the License. You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | package org.apache.commons.io; | |
| 18 | ||
| 19 | import java.io.BufferedReader; | |
| 20 | import java.io.File; | |
| 21 | import java.io.IOException; | |
| 22 | import java.io.InputStream; | |
| 23 | import java.io.InputStreamReader; | |
| 24 | import java.io.OutputStream; | |
| 25 | import java.nio.charset.Charset; | |
| 26 | import java.util.ArrayList; | |
| 27 | import java.util.Arrays; | |
| 28 | import java.util.List; | |
| 29 | import java.util.Locale; | |
| 30 | import java.util.StringTokenizer; | |
| 31 | ||
| 32 | /** | |
| 33 | * General File System utilities. | |
| 34 | * <p> | |
| 35 | * This class provides static utility methods for general file system | |
| 36 | * functions not provided via the JDK {@link java.io.File File} class. | |
| 37 | * <p> | |
| 38 | * The current functions provided are: | |
| 39 | * <ul> | |
| 40 | * <li>Get the free space on a drive | |
| 41 | * </ul> | |
| 42 | * | |
| 43 | * @version $Id: FileSystemUtils.java 1471767 2013-04-24 23:24:19Z sebb $ | |
| 44 | * @since 1.1 | |
| 45 | */ | |
| 46 | public class FileSystemUtils { | |
| 47 | ||
| 48 | /** Singleton instance, used mainly for testing. */ | |
| 49 | 1 | private static final FileSystemUtils INSTANCE = new FileSystemUtils(); |
| 50 | ||
| 51 | /** Operating system state flag for error. */ | |
| 52 | private static final int INIT_PROBLEM = -1; | |
| 53 | /** Operating system state flag for neither Unix nor Windows. */ | |
| 54 | private static final int OTHER = 0; | |
| 55 | /** Operating system state flag for Windows. */ | |
| 56 | private static final int WINDOWS = 1; | |
| 57 | /** Operating system state flag for Unix. */ | |
| 58 | private static final int UNIX = 2; | |
| 59 | /** Operating system state flag for Posix flavour Unix. */ | |
| 60 | private static final int POSIX_UNIX = 3; | |
| 61 | ||
| 62 | /** The operating system flag. */ | |
| 63 | private static final int OS; | |
| 64 | ||
| 65 | /** The path to df */ | |
| 66 | private static final String DF; | |
| 67 | ||
| 68 | static { | |
| 69 | 1 | int os = OTHER; |
| 70 | 1 | String dfPath = "df"; |
| 71 | try { | |
| 72 | 1 | String osName = System.getProperty("os.name"); |
| 73 | 1 | if (osName == null) { |
| 74 | 0 | throw new IOException("os.name not found"); |
| 75 | } | |
| 76 | 1 | osName = osName.toLowerCase(Locale.ENGLISH); |
| 77 | // match | |
| 78 | 1 | if (osName.indexOf("windows") != -1) { |
| 79 | 1 | os = WINDOWS; |
| 80 | 0 | } else if (osName.indexOf("linux") != -1 || |
| 81 | osName.indexOf("mpe/ix") != -1 || | |
| 82 | osName.indexOf("freebsd") != -1 || | |
| 83 | osName.indexOf("irix") != -1 || | |
| 84 | osName.indexOf("digital unix") != -1 || | |
| 85 | osName.indexOf("unix") != -1 || | |
| 86 | osName.indexOf("mac os x") != -1) { | |
| 87 | 0 | os = UNIX; |
| 88 | 0 | } else if (osName.indexOf("sun os") != -1 || |
| 89 | osName.indexOf("sunos") != -1 || | |
| 90 | osName.indexOf("solaris") != -1) { | |
| 91 | 0 | os = POSIX_UNIX; |
| 92 | 0 | dfPath = "/usr/xpg4/bin/df"; |
| 93 | 0 | } else if (osName.indexOf("hp-ux") != -1 || |
| 94 | osName.indexOf("aix") != -1) { | |
| 95 | 0 | os = POSIX_UNIX; |
| 96 | } else { | |
| 97 | 0 | os = OTHER; |
| 98 | } | |
| 99 | ||
| 100 | 0 | } catch (final Exception ex) { |
| 101 | 0 | os = INIT_PROBLEM; |
| 102 | 1 | } |
| 103 | 1 | OS = os; |
| 104 | 1 | DF = dfPath; |
| 105 | 1 | } |
| 106 | ||
| 107 | /** | |
| 108 | * Instances should NOT be constructed in standard programming. | |
| 109 | */ | |
| 110 | public FileSystemUtils() { | |
| 111 | 28 | super(); |
| 112 | 28 | } |
| 113 | ||
| 114 | //----------------------------------------------------------------------- | |
| 115 | /** | |
| 116 | * Returns the free space on a drive or volume by invoking | |
| 117 | * the command line. | |
| 118 | * This method does not normalize the result, and typically returns | |
| 119 | * bytes on Windows, 512 byte units on OS X and kilobytes on Unix. | |
| 120 | * As this is not very useful, this method is deprecated in favour | |
| 121 | * of {@link #freeSpaceKb(String)} which returns a result in kilobytes. | |
| 122 | * <p> | |
| 123 | * Note that some OS's are NOT currently supported, including OS/390, | |
| 124 | * OpenVMS. | |
| 125 | * <pre> | |
| 126 | * FileSystemUtils.freeSpace("C:"); // Windows | |
| 127 | * FileSystemUtils.freeSpace("/volume"); // *nix | |
| 128 | * </pre> | |
| 129 | * The free space is calculated via the command line. | |
| 130 | * It uses 'dir /-c' on Windows and 'df' on *nix. | |
| 131 | * | |
| 132 | * @param path the path to get free space for, not null, not empty on Unix | |
| 133 | * @return the amount of free drive space on the drive or volume | |
| 134 | * @throws IllegalArgumentException if the path is invalid | |
| 135 | * @throws IllegalStateException if an error occurred in initialisation | |
| 136 | * @throws IOException if an error occurs when finding the free space | |
| 137 | * @since 1.1, enhanced OS support in 1.2 and 1.3 | |
| 138 | * @deprecated Use freeSpaceKb(String) | |
| 139 | * Deprecated from 1.3, may be removed in 2.0 | |
| 140 | */ | |
| 141 | @Deprecated | |
| 142 | public static long freeSpace(final String path) throws IOException { | |
| 143 | 1 | return INSTANCE.freeSpaceOS(path, OS, false, -1); |
| 144 | } | |
| 145 | ||
| 146 | //----------------------------------------------------------------------- | |
| 147 | /** | |
| 148 | * Returns the free space on a drive or volume in kilobytes by invoking | |
| 149 | * the command line. | |
| 150 | * <pre> | |
| 151 | * FileSystemUtils.freeSpaceKb("C:"); // Windows | |
| 152 | * FileSystemUtils.freeSpaceKb("/volume"); // *nix | |
| 153 | * </pre> | |
| 154 | * The free space is calculated via the command line. | |
| 155 | * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix. | |
| 156 | * <p> | |
| 157 | * In order to work, you must be running Windows, or have a implementation of | |
| 158 | * Unix df that supports GNU format when passed -k (or -kP). If you are going | |
| 159 | * to rely on this code, please check that it works on your OS by running | |
| 160 | * some simple tests to compare the command line with the output from this class. | |
| 161 | * If your operating system isn't supported, please raise a JIRA call detailing | |
| 162 | * the exact result from df -k and as much other detail as possible, thanks. | |
| 163 | * | |
| 164 | * @param path the path to get free space for, not null, not empty on Unix | |
| 165 | * @return the amount of free drive space on the drive or volume in kilobytes | |
| 166 | * @throws IllegalArgumentException if the path is invalid | |
| 167 | * @throws IllegalStateException if an error occurred in initialisation | |
| 168 | * @throws IOException if an error occurs when finding the free space | |
| 169 | * @since 1.2, enhanced OS support in 1.3 | |
| 170 | */ | |
| 171 | public static long freeSpaceKb(final String path) throws IOException { | |
| 172 | 1 | return freeSpaceKb(path, -1); |
| 173 | } | |
| 174 | /** | |
| 175 | * Returns the free space on a drive or volume in kilobytes by invoking | |
| 176 | * the command line. | |
| 177 | * <pre> | |
| 178 | * FileSystemUtils.freeSpaceKb("C:"); // Windows | |
| 179 | * FileSystemUtils.freeSpaceKb("/volume"); // *nix | |
| 180 | * </pre> | |
| 181 | * The free space is calculated via the command line. | |
| 182 | * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix. | |
| 183 | * <p> | |
| 184 | * In order to work, you must be running Windows, or have a implementation of | |
| 185 | * Unix df that supports GNU format when passed -k (or -kP). If you are going | |
| 186 | * to rely on this code, please check that it works on your OS by running | |
| 187 | * some simple tests to compare the command line with the output from this class. | |
| 188 | * If your operating system isn't supported, please raise a JIRA call detailing | |
| 189 | * the exact result from df -k and as much other detail as possible, thanks. | |
| 190 | * | |
| 191 | * @param path the path to get free space for, not null, not empty on Unix | |
| 192 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 193 | * is zero or less | |
| 194 | * @return the amount of free drive space on the drive or volume in kilobytes | |
| 195 | * @throws IllegalArgumentException if the path is invalid | |
| 196 | * @throws IllegalStateException if an error occurred in initialisation | |
| 197 | * @throws IOException if an error occurs when finding the free space | |
| 198 | * @since 2.0 | |
| 199 | */ | |
| 200 | public static long freeSpaceKb(final String path, final long timeout) throws IOException { | |
| 201 | 1 | return INSTANCE.freeSpaceOS(path, OS, true, timeout); |
| 202 | } | |
| 203 | ||
| 204 | /** | |
| 205 | * Returns the disk size of the volume which holds the working directory. | |
| 206 | * <p> | |
| 207 | * Identical to: | |
| 208 | * <pre> | |
| 209 | * freeSpaceKb(new File(".").getAbsolutePath()) | |
| 210 | * </pre> | |
| 211 | * @return the amount of free drive space on the drive or volume in kilobytes | |
| 212 | * @throws IllegalStateException if an error occurred in initialisation | |
| 213 | * @throws IOException if an error occurs when finding the free space | |
| 214 | * @since 2.0 | |
| 215 | */ | |
| 216 | public static long freeSpaceKb() throws IOException { | |
| 217 | 0 | return freeSpaceKb(-1); |
| 218 | } | |
| 219 | ||
| 220 | /** | |
| 221 | * Returns the disk size of the volume which holds the working directory. | |
| 222 | * <p> | |
| 223 | * Identical to: | |
| 224 | * <pre> | |
| 225 | * freeSpaceKb(new File(".").getAbsolutePath()) | |
| 226 | * </pre> | |
| 227 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 228 | * is zero or less | |
| 229 | * @return the amount of free drive space on the drive or volume in kilobytes | |
| 230 | * @throws IllegalStateException if an error occurred in initialisation | |
| 231 | * @throws IOException if an error occurs when finding the free space | |
| 232 | * @since 2.0 | |
| 233 | */ | |
| 234 | public static long freeSpaceKb(final long timeout) throws IOException { | |
| 235 | 0 | return freeSpaceKb(new File(".").getAbsolutePath(), timeout); |
| 236 | } | |
| 237 | ||
| 238 | //----------------------------------------------------------------------- | |
| 239 | /** | |
| 240 | * Returns the free space on a drive or volume in a cross-platform manner. | |
| 241 | * Note that some OS's are NOT currently supported, including OS/390. | |
| 242 | * <pre> | |
| 243 | * FileSystemUtils.freeSpace("C:"); // Windows | |
| 244 | * FileSystemUtils.freeSpace("/volume"); // *nix | |
| 245 | * </pre> | |
| 246 | * The free space is calculated via the command line. | |
| 247 | * It uses 'dir /-c' on Windows and 'df' on *nix. | |
| 248 | * | |
| 249 | * @param path the path to get free space for, not null, not empty on Unix | |
| 250 | * @param os the operating system code | |
| 251 | * @param kb whether to normalize to kilobytes | |
| 252 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 253 | * is zero or less | |
| 254 | * @return the amount of free drive space on the drive or volume | |
| 255 | * @throws IllegalArgumentException if the path is invalid | |
| 256 | * @throws IllegalStateException if an error occurred in initialisation | |
| 257 | * @throws IOException if an error occurs when finding the free space | |
| 258 | */ | |
| 259 | long freeSpaceOS(final String path, final int os, final boolean kb, final long timeout) throws IOException { | |
| 260 | 12 | if (path == null) { |
| 261 | 2 | throw new IllegalArgumentException("Path must not be empty"); |
| 262 | } | |
| 263 | 10 | switch (os) { |
| 264 | case WINDOWS: | |
| 265 | 4 | return kb ? freeSpaceWindows(path, timeout) / FileUtils.ONE_KB : freeSpaceWindows(path, timeout); |
| 266 | case UNIX: | |
| 267 | 2 | return freeSpaceUnix(path, kb, false, timeout); |
| 268 | case POSIX_UNIX: | |
| 269 | 0 | return freeSpaceUnix(path, kb, true, timeout); |
| 270 | case OTHER: | |
| 271 | 2 | throw new IllegalStateException("Unsupported operating system"); |
| 272 | default: | |
| 273 | 2 | throw new IllegalStateException( |
| 274 | "Exception caught when determining operating system"); | |
| 275 | } | |
| 276 | } | |
| 277 | ||
| 278 | //----------------------------------------------------------------------- | |
| 279 | /** | |
| 280 | * Find free space on the Windows platform using the 'dir' command. | |
| 281 | * | |
| 282 | * @param path the path to get free space for, including the colon | |
| 283 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 284 | * is zero or less | |
| 285 | * @return the amount of free drive space on the drive | |
| 286 | * @throws IOException if an error occurs | |
| 287 | */ | |
| 288 | long freeSpaceWindows(String path, final long timeout) throws IOException { | |
| 289 | 11 | path = FilenameUtils.normalize(path, false); |
| 290 | 11 | if (path.length() > 0 && path.charAt(0) != '"') { |
| 291 | 6 | path = "\"" + path + "\""; |
| 292 | } | |
| 293 | ||
| 294 | // build and run the 'dir' command | |
| 295 | 11 | final String[] cmdAttribs = new String[] {"cmd.exe", "/C", "dir /a /-c " + path}; |
| 296 | ||
| 297 | // read in the output of the command to an ArrayList | |
| 298 | 11 | final List<String> lines = performCommand(cmdAttribs, Integer.MAX_VALUE, timeout); |
| 299 | ||
| 300 | // now iterate over the lines we just read and find the LAST | |
| 301 | // non-empty line (the free space bytes should be in the last element | |
| 302 | // of the ArrayList anyway, but this will ensure it works even if it's | |
| 303 | // not, still assuming it is on the last non-blank line) | |
| 304 | 11 | for (int i = lines.size() - 1; i >= 0; i--) { |
| 305 | 10 | final String line = lines.get(i); |
| 306 | 10 | if (line.length() > 0) { |
| 307 | 8 | return parseDir(line, path); |
| 308 | } | |
| 309 | } | |
| 310 | // all lines are blank | |
| 311 | 1 | throw new IOException( |
| 312 | "Command line 'dir /-c' did not return any info " + | |
| 313 | "for path '" + path + "'"); | |
| 314 | } | |
| 315 | ||
| 316 | /** | |
| 317 | * Parses the Windows dir response last line | |
| 318 | * | |
| 319 | * @param line the line to parse | |
| 320 | * @param path the path that was sent | |
| 321 | * @return the number of bytes | |
| 322 | * @throws IOException if an error occurs | |
| 323 | */ | |
| 324 | long parseDir(final String line, final String path) throws IOException { | |
| 325 | // read from the end of the line to find the last numeric | |
| 326 | // character on the line, then continue until we find the first | |
| 327 | // non-numeric character, and everything between that and the last | |
| 328 | // numeric character inclusive is our free space bytes count | |
| 329 | 8 | int bytesStart = 0; |
| 330 | 8 | int bytesEnd = 0; |
| 331 | 8 | int j = line.length() - 1; |
| 332 | 102 | innerLoop1: while (j >= 0) { |
| 333 | 101 | final char c = line.charAt(j); |
| 334 | 101 | if (Character.isDigit(c)) { |
| 335 | // found the last numeric character, this is the end of | |
| 336 | // the free space bytes count | |
| 337 | 7 | bytesEnd = j + 1; |
| 338 | 7 | break innerLoop1; |
| 339 | } | |
| 340 | 94 | j--; |
| 341 | 94 | } |
| 342 | 90 | innerLoop2: while (j >= 0) { |
| 343 | 89 | final char c = line.charAt(j); |
| 344 | 89 | if (!Character.isDigit(c) && c != ',' && c != '.') { |
| 345 | // found the next non-numeric character, this is the | |
| 346 | // beginning of the free space bytes count | |
| 347 | 7 | bytesStart = j + 1; |
| 348 | 7 | break innerLoop2; |
| 349 | } | |
| 350 | 82 | j--; |
| 351 | 82 | } |
| 352 | 8 | if (j < 0) { |
| 353 | 1 | throw new IOException( |
| 354 | "Command line 'dir /-c' did not return valid info " + | |
| 355 | "for path '" + path + "'"); | |
| 356 | } | |
| 357 | ||
| 358 | // remove commas and dots in the bytes count | |
| 359 | 7 | final StringBuilder buf = new StringBuilder(line.substring(bytesStart, bytesEnd)); |
| 360 | 89 | for (int k = 0; k < buf.length(); k++) { |
| 361 | 82 | if (buf.charAt(k) == ',' || buf.charAt(k) == '.') { |
| 362 | 3 | buf.deleteCharAt(k--); |
| 363 | } | |
| 364 | } | |
| 365 | 7 | return parseBytes(buf.toString(), path); |
| 366 | } | |
| 367 | ||
| 368 | //----------------------------------------------------------------------- | |
| 369 | /** | |
| 370 | * Find free space on the *nix platform using the 'df' command. | |
| 371 | * | |
| 372 | * @param path the path to get free space for | |
| 373 | * @param kb whether to normalize to kilobytes | |
| 374 | * @param posix whether to use the posix standard format flag | |
| 375 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 376 | * is zero or less | |
| 377 | * @return the amount of free drive space on the volume | |
| 378 | * @throws IOException if an error occurs | |
| 379 | */ | |
| 380 | long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final long timeout) throws IOException { | |
| 381 | 31 | if (path.length() == 0) { |
| 382 | 4 | throw new IllegalArgumentException("Path must not be empty"); |
| 383 | } | |
| 384 | ||
| 385 | // build and run the 'dir' command | |
| 386 | 27 | String flags = "-"; |
| 387 | 27 | if (kb) { |
| 388 | 14 | flags += "k"; |
| 389 | } | |
| 390 | 27 | if (posix) { |
| 391 | 10 | flags += "P"; |
| 392 | } | |
| 393 | 27 | final String[] cmdAttribs = |
| 394 | flags.length() > 1 ? new String[] {DF, flags, path} : new String[] {DF, path}; | |
| 395 | ||
| 396 | // perform the command, asking for up to 3 lines (header, interesting, overflow) | |
| 397 | 27 | final List<String> lines = performCommand(cmdAttribs, 3, timeout); |
| 398 | 23 | if (lines.size() < 2) { |
| 399 | // unknown problem, throw exception | |
| 400 | 0 | throw new IOException( |
| 401 | "Command line '" + DF + "' did not return info as expected " + | |
| 402 | "for path '" + path + "'- response was " + lines); | |
| 403 | } | |
| 404 | 23 | final String line2 = lines.get(1); // the line we're interested in |
| 405 | ||
| 406 | // Now, we tokenize the string. The fourth element is what we want. | |
| 407 | 23 | StringTokenizer tok = new StringTokenizer(line2, " "); |
| 408 | 23 | if (tok.countTokens() < 4) { |
| 409 | // could be long Filesystem, thus data on third line | |
| 410 | 10 | if (tok.countTokens() == 1 && lines.size() >= 3) { |
| 411 | 2 | final String line3 = lines.get(2); // the line may be interested in |
| 412 | 2 | tok = new StringTokenizer(line3, " "); |
| 413 | 2 | } else { |
| 414 | 8 | throw new IOException( |
| 415 | "Command line '" + DF + "' did not return data as expected " + | |
| 416 | "for path '" + path + "'- check path is valid"); | |
| 417 | } | |
| 418 | } else { | |
| 419 | 13 | tok.nextToken(); // Ignore Filesystem |
| 420 | } | |
| 421 | 15 | tok.nextToken(); // Ignore 1K-blocks |
| 422 | 15 | tok.nextToken(); // Ignore Used |
| 423 | 15 | final String freeSpace = tok.nextToken(); |
| 424 | 15 | return parseBytes(freeSpace, path); |
| 425 | } | |
| 426 | ||
| 427 | //----------------------------------------------------------------------- | |
| 428 | /** | |
| 429 | * Parses the bytes from a string. | |
| 430 | * | |
| 431 | * @param freeSpace the free space string | |
| 432 | * @param path the path | |
| 433 | * @return the number of bytes | |
| 434 | * @throws IOException if an error occurs | |
| 435 | */ | |
| 436 | long parseBytes(final String freeSpace, final String path) throws IOException { | |
| 437 | try { | |
| 438 | 22 | final long bytes = Long.parseLong(freeSpace); |
| 439 | 18 | if (bytes < 0) { |
| 440 | 4 | throw new IOException( |
| 441 | "Command line '" + DF + "' did not find free space in response " + | |
| 442 | "for path '" + path + "'- check path is valid"); | |
| 443 | } | |
| 444 | 14 | return bytes; |
| 445 | ||
| 446 | 4 | } catch (final NumberFormatException ex) { |
| 447 | 4 | throw new IOExceptionWithCause( |
| 448 | "Command line '" + DF + "' did not return numeric data as expected " + | |
| 449 | "for path '" + path + "'- check path is valid", ex); | |
| 450 | } | |
| 451 | } | |
| 452 | ||
| 453 | //----------------------------------------------------------------------- | |
| 454 | /** | |
| 455 | * Performs the os command. | |
| 456 | * | |
| 457 | * @param cmdAttribs the command line parameters | |
| 458 | * @param max The maximum limit for the lines returned | |
| 459 | * @param timeout The timout amount in milliseconds or no timeout if the value | |
| 460 | * is zero or less | |
| 461 | * @return the lines returned by the command, converted to lower-case | |
| 462 | * @throws IOException if an error occurs | |
| 463 | */ | |
| 464 | List<String> performCommand(final String[] cmdAttribs, final int max, final long timeout) throws IOException { | |
| 465 | // this method does what it can to avoid the 'Too many open files' error | |
| 466 | // based on trial and error and these links: | |
| 467 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692 | |
| 468 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801027 | |
| 469 | // http://forum.java.sun.com/thread.jspa?threadID=533029&messageID=2572018 | |
| 470 | // however, its still not perfect as the JDK support is so poor | |
| 471 | // (see commons-exec or Ant for a better multi-threaded multi-os solution) | |
| 472 | ||
| 473 | 38 | final List<String> lines = new ArrayList<String>(20); |
| 474 | 38 | Process proc = null; |
| 475 | 38 | InputStream in = null; |
| 476 | 38 | OutputStream out = null; |
| 477 | 38 | InputStream err = null; |
| 478 | 38 | BufferedReader inr = null; |
| 479 | try { | |
| 480 | ||
| 481 | 38 | final Thread monitor = ThreadMonitor.start(timeout); |
| 482 | ||
| 483 | 38 | proc = openProcess(cmdAttribs); |
| 484 | 38 | in = proc.getInputStream(); |
| 485 | 38 | out = proc.getOutputStream(); |
| 486 | 38 | err = proc.getErrorStream(); |
| 487 | // default charset is most likely appropriate here | |
| 488 | 38 | inr = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset())); |
| 489 | 38 | String line = inr.readLine(); |
| 490 | 204 | while (line != null && lines.size() < max) { |
| 491 | 166 | line = line.toLowerCase(Locale.ENGLISH).trim(); |
| 492 | 166 | lines.add(line); |
| 493 | 166 | line = inr.readLine(); |
| 494 | } | |
| 495 | ||
| 496 | 38 | proc.waitFor(); |
| 497 | ||
| 498 | 38 | ThreadMonitor.stop(monitor); |
| 499 | ||
| 500 | 38 | if (proc.exitValue() != 0) { |
| 501 | // os command problem, throw exception | |
| 502 | 1 | throw new IOException( |
| 503 | "Command line returned OS error code '" + proc.exitValue() + | |
| 504 | "' for command " + Arrays.asList(cmdAttribs)); | |
| 505 | } | |
| 506 | 37 | if (lines.isEmpty()) { |
| 507 | // unknown problem, throw exception | |
| 508 | 5 | throw new IOException( |
| 509 | "Command line did not return any info " + | |
| 510 | "for command " + Arrays.asList(cmdAttribs)); | |
| 511 | } | |
| 512 | 32 | return lines; |
| 513 | ||
| 514 | 0 | } catch (final InterruptedException ex) { |
| 515 | 0 | throw new IOExceptionWithCause( |
| 516 | "Command line threw an InterruptedException " + | |
| 517 | "for command " + Arrays.asList(cmdAttribs) + " timeout=" + timeout, ex); | |
| 518 | } finally { | |
| 519 | 38 | IOUtils.closeQuietly(in); |
| 520 | 38 | IOUtils.closeQuietly(out); |
| 521 | 38 | IOUtils.closeQuietly(err); |
| 522 | 38 | IOUtils.closeQuietly(inr); |
| 523 | 38 | if (proc != null) { |
| 524 | 38 | proc.destroy(); |
| 525 | } | |
| 526 | } | |
| 527 | } | |
| 528 | ||
| 529 | /** | |
| 530 | * Opens the process to the operating system. | |
| 531 | * | |
| 532 | * @param cmdAttribs the command line parameters | |
| 533 | * @return the process | |
| 534 | * @throws IOException if an error occurs | |
| 535 | */ | |
| 536 | Process openProcess(final String[] cmdAttribs) throws IOException { | |
| 537 | 2 | return Runtime.getRuntime().exec(cmdAttribs); |
| 538 | } | |
| 539 | ||
| 540 | } |