1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2005, 2011, 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> 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. A line bound is considered to be any one of a line feed 129 * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return 130 * followed immediately by a linefeed, or an end of stream. 131 * 132 * @return The reader associated with this console 133 */ reader()134 public Reader reader() { 135 return reader; 136 } 137 138 /** 139 * Writes a formatted string to this console's output stream using 140 * the specified format string and arguments. 141 * 142 * @param fmt 143 * A format string as described in <a 144 * href="../util/Formatter.html#syntax">Format string syntax</a> 145 * 146 * @param args 147 * Arguments referenced by the format specifiers in the format 148 * string. If there are more arguments than format specifiers, the 149 * extra arguments are ignored. The number of arguments is 150 * variable and may be zero. The maximum number of arguments is 151 * limited by the maximum dimension of a Java array as defined by 152 * <cite>The Java™ Virtual Machine Specification</cite>. 153 * The behaviour on a 154 * <tt>null</tt> argument depends on the <a 155 * href="../util/Formatter.html#syntax">conversion</a>. 156 * 157 * @throws IllegalFormatException 158 * If a format string contains an illegal syntax, a format 159 * specifier that is incompatible with the given arguments, 160 * insufficient arguments given the format string, or other 161 * illegal conditions. For specification of all possible 162 * formatting errors, see the <a 163 * href="../util/Formatter.html#detail">Details</a> section 164 * of the formatter class specification. 165 * 166 * @return This console 167 */ format(String fmt, Object ...args)168 public Console format(String fmt, Object ...args) { 169 formatter.format(fmt, args).flush(); 170 return this; 171 } 172 173 /** 174 * A convenience method to write a formatted string to this console's 175 * output stream using the specified format string and arguments. 176 * 177 * <p> An invocation of this method of the form <tt>con.printf(format, 178 * args)</tt> behaves in exactly the same way as the invocation of 179 * <pre>con.format(format, args)</pre>. 180 * 181 * @param format 182 * A format string as described in <a 183 * href="../util/Formatter.html#syntax">Format string syntax</a>. 184 * 185 * @param args 186 * Arguments referenced by the format specifiers in the format 187 * string. If there are more arguments than format specifiers, the 188 * extra arguments are ignored. The number of arguments is 189 * variable and may be zero. The maximum number of arguments is 190 * limited by the maximum dimension of a Java array as defined by 191 * <cite>The Java™ Virtual Machine Specification</cite>. 192 * The behaviour on a 193 * <tt>null</tt> argument depends on the <a 194 * href="../util/Formatter.html#syntax">conversion</a>. 195 * 196 * @throws IllegalFormatException 197 * If a format string contains an illegal syntax, a format 198 * specifier that is incompatible with the given arguments, 199 * insufficient arguments given the format string, or other 200 * illegal conditions. For specification of all possible 201 * formatting errors, see the <a 202 * href="../util/Formatter.html#detail">Details</a> section of the 203 * formatter class specification. 204 * 205 * @return This console 206 */ printf(String format, Object ... args)207 public Console printf(String format, Object ... args) { 208 return format(format, args); 209 } 210 211 /** 212 * Provides a formatted prompt, then reads a single line of text from the 213 * console. 214 * 215 * @param fmt 216 * A format string as described in <a 217 * href="../util/Formatter.html#syntax">Format string syntax</a>. 218 * 219 * @param args 220 * Arguments referenced by the format specifiers in the format 221 * string. If there are more arguments than format specifiers, the 222 * extra arguments are ignored. The maximum number of arguments is 223 * limited by the maximum dimension of a Java array as defined by 224 * <cite>The Java™ Virtual Machine Specification</cite>. 225 * 226 * @throws IllegalFormatException 227 * If a format string contains an illegal syntax, a format 228 * specifier that is incompatible with the given arguments, 229 * insufficient arguments given the format string, or other 230 * illegal conditions. For specification of all possible 231 * formatting errors, see the <a 232 * href="../util/Formatter.html#detail">Details</a> section 233 * of the formatter class specification. 234 * 235 * @throws IOError 236 * If an I/O error occurs. 237 * 238 * @return A string containing the line read from the console, not 239 * including any line-termination characters, or <tt>null</tt> 240 * if an end of stream has been reached. 241 */ readLine(String fmt, Object ... args)242 public String readLine(String fmt, Object ... args) { 243 String line = null; 244 synchronized (writeLock) { 245 synchronized(readLock) { 246 if (fmt.length() != 0) 247 pw.format(fmt, args); 248 try { 249 char[] ca = readline(false); 250 if (ca != null) 251 line = new String(ca); 252 } catch (IOException x) { 253 throw new IOError(x); 254 } 255 } 256 } 257 return line; 258 } 259 260 /** 261 * Reads a single line of text from the console. 262 * 263 * @throws IOError 264 * If an I/O error occurs. 265 * 266 * @return A string containing the line read from the console, not 267 * including any line-termination characters, or <tt>null</tt> 268 * if an end of stream has been reached. 269 */ readLine()270 public String readLine() { 271 return readLine(""); 272 } 273 274 /** 275 * Provides a formatted prompt, then reads a password or passphrase from 276 * the console with echoing disabled. 277 * 278 * @param fmt 279 * A format string as described in <a 280 * href="../util/Formatter.html#syntax">Format string syntax</a> 281 * for the prompt text. 282 * 283 * @param args 284 * Arguments referenced by the format specifiers in the format 285 * string. If there are more arguments than format specifiers, the 286 * extra arguments are ignored. The maximum number of arguments is 287 * limited by the maximum dimension of a Java array as defined by 288 * <cite>The Java™ Virtual Machine Specification</cite>. 289 * 290 * @throws IllegalFormatException 291 * If a format string contains an illegal syntax, a format 292 * specifier that is incompatible with the given arguments, 293 * insufficient arguments given the format string, or other 294 * illegal conditions. For specification of all possible 295 * formatting errors, see the <a 296 * href="../util/Formatter.html#detail">Details</a> 297 * section of the formatter class specification. 298 * 299 * @throws IOError 300 * If an I/O error occurs. 301 * 302 * @return A character array containing the password or passphrase read 303 * from the console, not including any line-termination characters, 304 * or <tt>null</tt> if an end of stream has been reached. 305 */ readPassword(String fmt, Object ... args)306 public char[] readPassword(String fmt, Object ... args) { 307 char[] passwd = null; 308 synchronized (writeLock) { 309 synchronized(readLock) { 310 try { 311 echoOff = echo(false); 312 } catch (IOException x) { 313 throw new IOError(x); 314 } 315 IOError ioe = null; 316 try { 317 if (fmt.length() != 0) 318 pw.format(fmt, args); 319 passwd = readline(true); 320 } catch (IOException x) { 321 ioe = new IOError(x); 322 } finally { 323 try { 324 echoOff = echo(true); 325 } catch (IOException x) { 326 if (ioe == null) 327 ioe = new IOError(x); 328 else 329 ioe.addSuppressed(x); 330 } 331 if (ioe != null) 332 throw ioe; 333 } 334 pw.println(); 335 } 336 } 337 return passwd; 338 } 339 340 /** 341 * Reads a password or passphrase from the console with echoing disabled 342 * 343 * @throws IOError 344 * If an I/O error occurs. 345 * 346 * @return A character array containing the password or passphrase read 347 * from the console, not including any line-termination characters, 348 * or <tt>null</tt> if an end of stream has been reached. 349 */ readPassword()350 public char[] readPassword() { 351 return readPassword(""); 352 } 353 354 /** 355 * Flushes the console and forces any buffered output to be written 356 * immediately . 357 */ flush()358 public void flush() { 359 pw.flush(); 360 } 361 362 private Object readLock; 363 private Object writeLock; 364 private Reader reader; 365 private Writer out; 366 private PrintWriter pw; 367 private Formatter formatter; 368 private Charset cs; 369 private char[] rcb; encoding()370 private static native String encoding(); echo(boolean on)371 private static native boolean echo(boolean on) throws IOException; 372 private static boolean echoOff; 373 readline(boolean zeroOut)374 private char[] readline(boolean zeroOut) throws IOException { 375 int len = reader.read(rcb, 0, rcb.length); 376 if (len < 0) 377 return null; //EOL 378 if (rcb[len-1] == '\r') 379 len--; //remove CR at end; 380 else if (rcb[len-1] == '\n') { 381 len--; //remove LF at end; 382 if (len > 0 && rcb[len-1] == '\r') 383 len--; //remove the CR, if there is one 384 } 385 char[] b = new char[len]; 386 if (len > 0) { 387 System.arraycopy(rcb, 0, b, 0, len); 388 if (zeroOut) { 389 Arrays.fill(rcb, 0, len, ' '); 390 } 391 } 392 return b; 393 } 394 grow()395 private char[] grow() { 396 assert Thread.holdsLock(readLock); 397 char[] t = new char[rcb.length * 2]; 398 System.arraycopy(rcb, 0, t, 0, rcb.length); 399 rcb = t; 400 return rcb; 401 } 402 403 class LineReader extends Reader { 404 private Reader in; 405 private char[] cb; 406 private int nChars, nextChar; 407 boolean leftoverLF; LineReader(Reader in)408 LineReader(Reader in) { 409 this.in = in; 410 cb = new char[1024]; 411 nextChar = nChars = 0; 412 leftoverLF = false; 413 } close()414 public void close () {} ready()415 public boolean ready() throws IOException { 416 //in.ready synchronizes on readLock already 417 return in.ready(); 418 } 419 read(char cbuf[], int offset, int length)420 public int read(char cbuf[], int offset, int length) 421 throws IOException 422 { 423 int off = offset; 424 int end = offset + length; 425 if (offset < 0 || offset > cbuf.length || length < 0 || 426 end < 0 || end > cbuf.length) { 427 throw new IndexOutOfBoundsException(); 428 } 429 synchronized(readLock) { 430 boolean eof = false; 431 char c = 0; 432 for (;;) { 433 if (nextChar >= nChars) { //fill 434 int n = 0; 435 do { 436 n = in.read(cb, 0, cb.length); 437 } while (n == 0); 438 if (n > 0) { 439 nChars = n; 440 nextChar = 0; 441 if (n < cb.length && 442 cb[n-1] != '\n' && cb[n-1] != '\r') { 443 /* 444 * we're in canonical mode so each "fill" should 445 * come back with an eol. if there no lf or nl at 446 * the end of returned bytes we reached an eof. 447 */ 448 eof = true; 449 } 450 } else { /*EOF*/ 451 if (off - offset == 0) 452 return -1; 453 return off - offset; 454 } 455 } 456 if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') { 457 /* 458 * if invoked by our readline, skip the leftover, otherwise 459 * return the LF. 460 */ 461 nextChar++; 462 } 463 leftoverLF = false; 464 while (nextChar < nChars) { 465 c = cbuf[off++] = cb[nextChar]; 466 cb[nextChar++] = 0; 467 if (c == '\n') { 468 return off - offset; 469 } else if (c == '\r') { 470 if (off == end) { 471 /* no space left even the next is LF, so return 472 * whatever we have if the invoker is not our 473 * readLine() 474 */ 475 if (cbuf == rcb) { 476 cbuf = grow(); 477 end = cbuf.length; 478 } else { 479 leftoverLF = true; 480 return off - offset; 481 } 482 } 483 if (nextChar == nChars && in.ready()) { 484 /* 485 * we have a CR and we reached the end of 486 * the read in buffer, fill to make sure we 487 * don't miss a LF, if there is one, it's possible 488 * that it got cut off during last round reading 489 * simply because the read in buffer was full. 490 */ 491 nChars = in.read(cb, 0, cb.length); 492 nextChar = 0; 493 } 494 if (nextChar < nChars && cb[nextChar] == '\n') { 495 cbuf[off++] = '\n'; 496 nextChar++; 497 } 498 return off - offset; 499 } else if (off == end) { 500 if (cbuf == rcb) { 501 cbuf = grow(); 502 end = cbuf.length; 503 } else { 504 return off - offset; 505 } 506 } 507 } 508 if (eof) 509 return off - offset; 510 } 511 } 512 } 513 } 514 515 // Android-changed: Remove SharedSecrets setup and also the shutdown 516 // hook that's a no-op (but causes trouble when it's turned on). 517 518 private static Console cons; 519 520 /** @hide */ console()521 public static Console console() { 522 if (istty()) { 523 if (cons == null) 524 cons = new Console(); 525 return cons; 526 } 527 return null; 528 } 529 istty()530 private native static boolean istty(); 531 Console()532 private Console() { 533 this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out)); 534 } 535 536 // Constructor for tests Console(InputStream inStream, OutputStream outStream)537 private Console(InputStream inStream, OutputStream outStream) { 538 readLock = new Object(); 539 writeLock = new Object(); 540 String csname = encoding(); 541 if (csname != null) { 542 try { 543 cs = Charset.forName(csname); 544 } catch (Exception x) {} 545 } 546 if (cs == null) 547 cs = Charset.defaultCharset(); 548 out = StreamEncoder.forOutputStreamWriter( 549 outStream, 550 writeLock, 551 cs); 552 pw = new PrintWriter(out, true) { public void close() {} }; 553 formatter = new Formatter(out); 554 reader = new LineReader(StreamDecoder.forInputStreamReader( 555 inStream, 556 readLock, 557 cs)); 558 rcb = new char[1024]; 559 } 560 561 /** 562 * Android-changed: Added method for internal use only, and also in use 563 * by tests. 564 * 565 * @hide 566 */ getConsole()567 public static synchronized Console getConsole() { 568 if (istty()) { 569 if (cons == null) 570 cons = new Console(); 571 return cons; 572 } 573 return null; 574 } 575 } 576