blob: b25759c4210f5282364c52fb61bcf112aa93bdbc [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
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
27package java.io;
28
29import java.util.*;
30import java.nio.charset.Charset;
31import sun.nio.cs.StreamDecoder;
32import 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
93public 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 */
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 */
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&trade; 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 */
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&trade; 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 */
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&trade; 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 */
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 */
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&trade; 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 */
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 */
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 */
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;
372 private static native String encoding();
373 private static native boolean echo(boolean on) throws IOException;
374 private static boolean echoOff;
375
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
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;
410 LineReader(Reader in) {
411 this.in = in;
412 cb = new char[1024];
413 nextChar = nChars = 0;
414 leftoverLF = false;
415 }
416 public void close () {}
417 public boolean ready() throws IOException {
418 //in.ready synchronizes on readLock already
419 return in.ready();
420 }
421
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 */
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;
531 private native static boolean istty();
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
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}