1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.io; 28 29 import java.util.*; 30 import java.nio.charset.Charset; 31 import sun.nio.cs.StreamDecoder; 32 import sun.nio.cs.StreamEncoder; 33 34 /** 35 * Methods to access the character-based console device, if any, associated 36 * with the current Java virtual machine. 37 * 38 * <p> Whether a virtual machine has a console is dependent upon the 39 * underlying platform and also upon the manner in which the virtual 40 * machine is invoked. If the virtual machine is started from an 41 * interactive command line without redirecting the standard input and 42 * output streams then its console will exist and will typically be 43 * connected to the keyboard and display from which the virtual machine 44 * was launched. If the virtual machine is started automatically, for 45 * example by a background job scheduler, then it will typically not 46 * have a console. 47 * <p> 48 * If this virtual machine has a console then it is represented by a 49 * unique instance of this class which can be obtained by invoking the 50 * {@link java.lang.System#console()} method. If no console device is 51 * available then an invocation of that method will return <tt>null</tt>. 52 * <p> 53 * Read and write operations are synchronized to guarantee the atomic 54 * completion of critical operations; therefore invoking methods 55 * {@link #readLine()}, {@link #readPassword()}, {@link #format format()}, 56 * {@link #printf printf()} as well as the read, format and write operations 57 * on the objects returned by {@link #reader()} and {@link #writer()} may 58 * block in multithreaded scenarios. 59 * <p> 60 * Invoking <tt>close()</tt> on the objects returned by the {@link #reader()} 61 * and the {@link #writer()} will not close the underlying stream of those 62 * objects. 63 * <p> 64 * The console-read methods return <tt>null</tt> when the end of the 65 * console input stream is reached, for example by typing control-D on 66 * Unix or control-Z on Windows. Subsequent read operations will succeed 67 * if additional characters are later entered on the console's input 68 * device. 69 * <p> 70 * Unless otherwise specified, passing a <tt>null</tt> argument to any method 71 * in this class will cause a {@link NullPointerException} to be thrown. 72 * <p> 73 * <b>Security note:</b> 74 * If an application needs to read a password or other secure data, it should 75 * use {@link #readPassword()} or {@link #readPassword(String, Object...)} and 76 * manually zero the returned character array after processing to minimize the 77 * lifetime of sensitive data in memory. 78 * 79 * <blockquote><pre>{@code 80 * Console cons; 81 * char[] passwd; 82 * if ((cons = System.console()) != null && 83 * (passwd = cons.readPassword("[%s]", "Password:")) != null) { 84 * ... 85 * java.util.Arrays.fill(passwd, ' '); 86 * } 87 * }</pre></blockquote> 88 * 89 * @author Xueming Shen 90 * @since 1.6 91 */ 92 93 public final class Console implements Flushable 94 { 95 /** 96 * Retrieves the unique {@link java.io.PrintWriter PrintWriter} object 97 * associated with this console. 98 * 99 * @return The printwriter associated with this console 100 */ writer()101 public PrintWriter writer() { 102 return pw; 103 } 104 105 /** 106 * Retrieves the unique {@link java.io.Reader Reader} object associated 107 * with this console. 108 * <p> 109 * This method is intended to be used by sophisticated applications, for 110 * example, a {@link java.util.Scanner} object which utilizes the rich 111 * parsing/scanning functionality provided by the <tt>Scanner</tt>: 112 * <blockquote><pre> 113 * Console con = System.console(); 114 * if (con != null) { 115 * Scanner sc = new Scanner(con.reader()); 116 * ... 117 * } 118 * </pre></blockquote> 119 * <p> 120 * For simple applications requiring only line-oriented reading, use 121 * <tt>{@link #readLine}</tt>. 122 * <p> 123 * The bulk read operations {@link java.io.Reader#read(char[]) read(char[]) }, 124 * {@link java.io.Reader#read(char[], int, int) read(char[], int, int) } and 125 * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)} 126 * on the returned object will not read in characters beyond the line 127 * bound for each invocation, even if the destination buffer has space for 128 * more characters. The {@code Reader}'s {@code read} methods may block if a 129 * line bound has not been entered or reached on the console's input device. 130 * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>), 131 * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately 132 * by a linefeed, or an end of stream. 133 * 134 * @return The reader associated with this console 135 */ reader()136 public Reader reader() { 137 return reader; 138 } 139 140 /** 141 * Writes a formatted string to this console's output stream using 142 * the specified format string and arguments. 143 * 144 * @param fmt 145 * A format string as described in <a 146 * href="../util/Formatter.html#syntax">Format string syntax</a> 147 * 148 * @param args 149 * Arguments referenced by the format specifiers in the format 150 * string. If there are more arguments than format specifiers, the 151 * extra arguments are ignored. The number of arguments is 152 * variable and may be zero. The maximum number of arguments is 153 * limited by the maximum dimension of a Java array as defined by 154 * <cite>The Java™ Virtual Machine Specification</cite>. 155 * The behaviour on a 156 * <tt>null</tt> argument depends on the <a 157 * href="../util/Formatter.html#syntax">conversion</a>. 158 * 159 * @throws IllegalFormatException 160 * If a format string contains an illegal syntax, a format 161 * specifier that is incompatible with the given arguments, 162 * insufficient arguments given the format string, or other 163 * illegal conditions. For specification of all possible 164 * formatting errors, see the <a 165 * href="../util/Formatter.html#detail">Details</a> section 166 * of the formatter class specification. 167 * 168 * @return This console 169 */ format(String fmt, Object ...args)170 public Console format(String fmt, Object ...args) { 171 formatter.format(fmt, args).flush(); 172 return this; 173 } 174 175 /** 176 * A convenience method to write a formatted string to this console's 177 * output stream using the specified format string and arguments. 178 * 179 * <p> An invocation of this method of the form <tt>con.printf(format, 180 * args)</tt> behaves in exactly the same way as the invocation of 181 * <pre>con.format(format, args)</pre>. 182 * 183 * @param format 184 * A format string as described in <a 185 * href="../util/Formatter.html#syntax">Format string syntax</a>. 186 * 187 * @param args 188 * Arguments referenced by the format specifiers in the format 189 * string. If there are more arguments than format specifiers, the 190 * extra arguments are ignored. The number of arguments is 191 * variable and may be zero. The maximum number of arguments is 192 * limited by the maximum dimension of a Java array as defined by 193 * <cite>The Java™ Virtual Machine Specification</cite>. 194 * The behaviour on a 195 * <tt>null</tt> argument depends on the <a 196 * href="../util/Formatter.html#syntax">conversion</a>. 197 * 198 * @throws IllegalFormatException 199 * If a format string contains an illegal syntax, a format 200 * specifier that is incompatible with the given arguments, 201 * insufficient arguments given the format string, or other 202 * illegal conditions. For specification of all possible 203 * formatting errors, see the <a 204 * href="../util/Formatter.html#detail">Details</a> section of the 205 * formatter class specification. 206 * 207 * @return This console 208 */ printf(String format, Object ... args)209 public Console printf(String format, Object ... args) { 210 return format(format, args); 211 } 212 213 /** 214 * Provides a formatted prompt, then reads a single line of text from the 215 * console. 216 * 217 * @param fmt 218 * A format string as described in <a 219 * href="../util/Formatter.html#syntax">Format string syntax</a>. 220 * 221 * @param args 222 * Arguments referenced by the format specifiers in the format 223 * string. If there are more arguments than format specifiers, the 224 * extra arguments are ignored. The maximum number of arguments is 225 * limited by the maximum dimension of a Java array as defined by 226 * <cite>The Java™ Virtual Machine Specification</cite>. 227 * 228 * @throws IllegalFormatException 229 * If a format string contains an illegal syntax, a format 230 * specifier that is incompatible with the given arguments, 231 * insufficient arguments given the format string, or other 232 * illegal conditions. For specification of all possible 233 * formatting errors, see the <a 234 * href="../util/Formatter.html#detail">Details</a> section 235 * of the formatter class specification. 236 * 237 * @throws IOError 238 * If an I/O error occurs. 239 * 240 * @return A string containing the line read from the console, not 241 * including any line-termination characters, or <tt>null</tt> 242 * if an end of stream has been reached. 243 */ readLine(String fmt, Object ... args)244 public String readLine(String fmt, Object ... args) { 245 String line = null; 246 synchronized (writeLock) { 247 synchronized(readLock) { 248 if (fmt.length() != 0) 249 pw.format(fmt, args); 250 try { 251 char[] ca = readline(false); 252 if (ca != null) 253 line = new String(ca); 254 } catch (IOException x) { 255 throw new IOError(x); 256 } 257 } 258 } 259 return line; 260 } 261 262 /** 263 * Reads a single line of text from the console. 264 * 265 * @throws IOError 266 * If an I/O error occurs. 267 * 268 * @return A string containing the line read from the console, not 269 * including any line-termination characters, or <tt>null</tt> 270 * if an end of stream has been reached. 271 */ readLine()272 public String readLine() { 273 return readLine(""); 274 } 275 276 /** 277 * Provides a formatted prompt, then reads a password or passphrase from 278 * the console with echoing disabled. 279 * 280 * @param fmt 281 * A format string as described in <a 282 * href="../util/Formatter.html#syntax">Format string syntax</a> 283 * for the prompt text. 284 * 285 * @param args 286 * Arguments referenced by the format specifiers in the format 287 * string. If there are more arguments than format specifiers, the 288 * extra arguments are ignored. The maximum number of arguments is 289 * limited by the maximum dimension of a Java array as defined by 290 * <cite>The Java™ Virtual Machine Specification</cite>. 291 * 292 * @throws IllegalFormatException 293 * If a format string contains an illegal syntax, a format 294 * specifier that is incompatible with the given arguments, 295 * insufficient arguments given the format string, or other 296 * illegal conditions. For specification of all possible 297 * formatting errors, see the <a 298 * href="../util/Formatter.html#detail">Details</a> 299 * section of the formatter class specification. 300 * 301 * @throws IOError 302 * If an I/O error occurs. 303 * 304 * @return A character array containing the password or passphrase read 305 * from the console, not including any line-termination characters, 306 * or <tt>null</tt> if an end of stream has been reached. 307 */ readPassword(String fmt, Object ... args)308 public char[] readPassword(String fmt, Object ... args) { 309 char[] passwd = null; 310 synchronized (writeLock) { 311 synchronized(readLock) { 312 try { 313 echoOff = echo(false); 314 } catch (IOException x) { 315 throw new IOError(x); 316 } 317 IOError ioe = null; 318 try { 319 if (fmt.length() != 0) 320 pw.format(fmt, args); 321 passwd = readline(true); 322 } catch (IOException x) { 323 ioe = new IOError(x); 324 } finally { 325 try { 326 echoOff = echo(true); 327 } catch (IOException x) { 328 if (ioe == null) 329 ioe = new IOError(x); 330 else 331 ioe.addSuppressed(x); 332 } 333 if (ioe != null) 334 throw ioe; 335 } 336 pw.println(); 337 } 338 } 339 return passwd; 340 } 341 342 /** 343 * Reads a password or passphrase from the console with echoing disabled 344 * 345 * @throws IOError 346 * If an I/O error occurs. 347 * 348 * @return A character array containing the password or passphrase read 349 * from the console, not including any line-termination characters, 350 * or <tt>null</tt> if an end of stream has been reached. 351 */ readPassword()352 public char[] readPassword() { 353 return readPassword(""); 354 } 355 356 /** 357 * Flushes the console and forces any buffered output to be written 358 * immediately . 359 */ flush()360 public void flush() { 361 pw.flush(); 362 } 363 364 private Object readLock; 365 private Object writeLock; 366 private Reader reader; 367 private Writer out; 368 private PrintWriter pw; 369 private Formatter formatter; 370 private Charset cs; 371 private char[] rcb; encoding()372 private static native String encoding(); echo(boolean on)373 private static native boolean echo(boolean on) throws IOException; 374 private static boolean echoOff; 375 readline(boolean zeroOut)376 private char[] readline(boolean zeroOut) throws IOException { 377 int len = reader.read(rcb, 0, rcb.length); 378 if (len < 0) 379 return null; //EOL 380 if (rcb[len-1] == '\r') 381 len--; //remove CR at end; 382 else if (rcb[len-1] == '\n') { 383 len--; //remove LF at end; 384 if (len > 0 && rcb[len-1] == '\r') 385 len--; //remove the CR, if there is one 386 } 387 char[] b = new char[len]; 388 if (len > 0) { 389 System.arraycopy(rcb, 0, b, 0, len); 390 if (zeroOut) { 391 Arrays.fill(rcb, 0, len, ' '); 392 } 393 } 394 return b; 395 } 396 grow()397 private char[] grow() { 398 assert Thread.holdsLock(readLock); 399 char[] t = new char[rcb.length * 2]; 400 System.arraycopy(rcb, 0, t, 0, rcb.length); 401 rcb = t; 402 return rcb; 403 } 404 405 class LineReader extends Reader { 406 private Reader in; 407 private char[] cb; 408 private int nChars, nextChar; 409 boolean leftoverLF; LineReader(Reader in)410 LineReader(Reader in) { 411 this.in = in; 412 cb = new char[1024]; 413 nextChar = nChars = 0; 414 leftoverLF = false; 415 } close()416 public void close () {} ready()417 public boolean ready() throws IOException { 418 //in.ready synchronizes on readLock already 419 return in.ready(); 420 } 421 read(char cbuf[], int offset, int length)422 public int read(char cbuf[], int offset, int length) 423 throws IOException 424 { 425 int off = offset; 426 int end = offset + length; 427 if (offset < 0 || offset > cbuf.length || length < 0 || 428 end < 0 || end > cbuf.length) { 429 throw new IndexOutOfBoundsException(); 430 } 431 synchronized(readLock) { 432 boolean eof = false; 433 char c = 0; 434 for (;;) { 435 if (nextChar >= nChars) { //fill 436 int n = 0; 437 do { 438 n = in.read(cb, 0, cb.length); 439 } while (n == 0); 440 if (n > 0) { 441 nChars = n; 442 nextChar = 0; 443 if (n < cb.length && 444 cb[n-1] != '\n' && cb[n-1] != '\r') { 445 /* 446 * we're in canonical mode so each "fill" should 447 * come back with an eol. if there no lf or nl at 448 * the end of returned bytes we reached an eof. 449 */ 450 eof = true; 451 } 452 } else { /*EOF*/ 453 if (off - offset == 0) 454 return -1; 455 return off - offset; 456 } 457 } 458 if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') { 459 /* 460 * if invoked by our readline, skip the leftover, otherwise 461 * return the LF. 462 */ 463 nextChar++; 464 } 465 leftoverLF = false; 466 while (nextChar < nChars) { 467 c = cbuf[off++] = cb[nextChar]; 468 cb[nextChar++] = 0; 469 if (c == '\n') { 470 return off - offset; 471 } else if (c == '\r') { 472 if (off == end) { 473 /* no space left even the next is LF, so return 474 * whatever we have if the invoker is not our 475 * readLine() 476 */ 477 if (cbuf == rcb) { 478 cbuf = grow(); 479 end = cbuf.length; 480 } else { 481 leftoverLF = true; 482 return off - offset; 483 } 484 } 485 if (nextChar == nChars && in.ready()) { 486 /* 487 * we have a CR and we reached the end of 488 * the read in buffer, fill to make sure we 489 * don't miss a LF, if there is one, it's possible 490 * that it got cut off during last round reading 491 * simply because the read in buffer was full. 492 */ 493 nChars = in.read(cb, 0, cb.length); 494 nextChar = 0; 495 } 496 if (nextChar < nChars && cb[nextChar] == '\n') { 497 cbuf[off++] = '\n'; 498 nextChar++; 499 } 500 return off - offset; 501 } else if (off == end) { 502 if (cbuf == rcb) { 503 cbuf = grow(); 504 end = cbuf.length; 505 } else { 506 return off - offset; 507 } 508 } 509 } 510 if (eof) 511 return off - offset; 512 } 513 } 514 } 515 } 516 517 // Android-removed: SharedSecrets setup and also the shutdown hook. 518 // The hook is a no-op (but causes trouble when it's turned on). 519 520 // Android-changed: Use @hide rather than sun.misc.SharedSecrets to expose console(). 521 /** @hide */ console()522 public static Console console() { 523 if (istty()) { 524 if (cons == null) 525 cons = new Console(); 526 return cons; 527 } 528 return null; 529 } 530 private static Console cons; istty()531 private native static boolean istty(); Console()532 private Console() { 533 // BEGIN Android-changed: Support custom in/out streams for testing. 534 this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out)); 535 } 536 537 // Constructor for tests Console(InputStream inStream, OutputStream outStream)538 private Console(InputStream inStream, OutputStream outStream) { 539 // END Android-changed: Support custom in/out streams for testing. 540 readLock = new Object(); 541 writeLock = new Object(); 542 String csname = encoding(); 543 if (csname != null) { 544 try { 545 cs = Charset.forName(csname); 546 } catch (Exception x) {} 547 } 548 if (cs == null) 549 cs = Charset.defaultCharset(); 550 out = StreamEncoder.forOutputStreamWriter( 551 outStream, 552 writeLock, 553 cs); 554 pw = new PrintWriter(out, true) { public void close() {} }; 555 formatter = new Formatter(out); 556 reader = new LineReader(StreamDecoder.forInputStreamReader( 557 inStream, 558 readLock, 559 cs)); 560 rcb = new char[1024]; 561 } 562 } 563