Getting bufferedReader.readLine() value is null in android - java

Working condition :
Process process = Runtime.getRuntime().exec("ls -l /etc/");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Log.d(TAG,"bufferedReader.readLine()===>"+bufferedReader.readLine());
Snipped log : bufferedReader.readLine()===>total 7580
not working :
Process process = Runtime.getRuntime().exec("./etc/lighttpd -D -f /etc/test.conf");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Log.d(TAG,"bufferedReader.readLine()===>"+bufferedReader.readLine());
Snipped log : bufferedReader.readLine()===>null
Can you please help me, why I am receiving bufferedReader.readLine() is "null" while execute "./etc/lighttpd -D -f /etc/test.conf" command
executed below command in device shell :
#./etc/lighttpd -D -f /etc/test.conf
2022-08-30 12:38:18: server.c.1508) server started (lighttpd/1.4.58)

The pathname ./etc/lighttpd is suspicious, but the evidence you have show us proves that:
it is present, and
it is executable,
... at least for some current directory.
Why do I say that it is proven? Because:
exec didn't throw an IOException, and
you showed us the output from running the same command from the command line.
Admittedly, it is possible that the current directories are different ... which is one of the reasons that I said that ./etc/lighttpd is suspicious!
So if the problem is not that ./etc/lighttpd is not an executable, what is the explanation for bufferedReader.readLine() returning null?
Well, the simplest theory is that lighttpd is writing to standard error rather than standard output, and that it has closed its standard output. That would explain the behavior you are seeing.
Anyhow ... my suggestions would be:
Change ./etc/lighttpd to the absolute pathname for the executable that you are using ... to remove any doubt.
Try opening and reading from process.getErrorStream() instead.
Look in the lighttpd log file for any errors.
Finally, you have tagged your question with [android] but AFAIK there is no (official) Android port for Lighttpd. I am guessing that the tag was a mistake because there is no other mention of Android. But if it was not a mistake, you should tell us where you go the Android port from. That may help people to diagnose the problem.

/etc/lighttpd is usually a directory containing configuration information. /etc/lighttpd is often not an executable.

Related

How to run commands you can run on terminal in Java

So guys I want to execute a command that you can execute on the cmd in my Java program. After doing some study, I thought i found a way to do this. However, my code doesn't work.
My code is
import java.io.*;
public class CmdTest {
public static void main(String[] args) throws Exception {
String[] command = {"ag","startTimes conf.js >> pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
builder.directory(new File("./test-java/"));
Process p = builder.start();
}
}
The program executes but produces no output. I tried using other commands like "ls -a", but still no output.
Can someone please help me debug this or suggest a better way of doing this? Thank you
Edit 1: I am executing this on a Mac. If that is necessary for debugging
Edit 2: The usual ls and other commands are working with the solutions that you guys have provided. I however want to use the ag (the_silver_searcher) command in the Java program. When i try that, i get the following error -
Exception in thread "main" java.io.IOException: Cannot run program "ag startTimes conf.js >> pro.txt": error=2, No such file or directory
The existing answers give you the information on how to solve your problem in code, but they don't give a reason why your code is not working.
When you execute a program on a shell, there's significant processing done by the shell, before the program is ever executed. Your command line
String[] command = {"ag","startTimes conf.js >> pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
assumes that the command ag is run with the single argument startTimes conf.js >> pro.txt - most likely not what you want to do. Let's go one step further: What if you wrote
String[] command = {"ag","startTimes", "conf.js", ">>", "pro.txt"};
ProcessBuilder builder = new ProcessBuilder(command);
?
This would assume that the ag command knows about the >> parameter to redirect its output - and here is where the shell comes into play: The >> operator is an instruction to the shell, telling it what to do with the output from stdout of the process. The process ag, when started by the shell, never has an idea of this redirection and has no clue about >> and the target file name at all.
With this information, just use the code samples from any of the other answers. I won't copy them into mine for proper attribution.
While there is ProcessBuilder, I've always used Runtime.getRuntime().exec("cmd");
Process Runtime.exec(String)
It returns a Process which you can get the input and output streams of
Even if you stay with the ProcessBuilder, you should still have access to the Process.get<Input/Output/Error>Stream()
You need to read the output of the process by opening an input stream from the process:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())) {
System.out.println(reader.readLine()); // process the output stream somehow
}
Additionally you might the read the error stream ( p.getErrorStream()), which I often have done in a separate stream, in Java 8 you can use redirectErrorStream(true) on the ProcessBuilder to automatically add the error stream to the input stream. Of course you can't distinquish anymore from which stream the input comes, but it makes reading easier. If you don't read the input or error stream and the process's buffer becomes full the processes tend to pause until there is enough room in the buffer again.
You can also add
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
before the start method which redirects the output to the console.
//"ls" command runs under the "sh" on linux(cmd.exe on windows), so first arg is "sh"
//second arg "-c" tells "sh" which exact command should be executed
//"ls" is actual command
//"startTimes" as I understand is a file or directory, it is arg for "ls" command
//"conf.js" is second arg for "ls" command
new ProcessBuilder("sh", "-c", "ls", "startTimes", "conf.js")
//set working dir for "sh" process"
.directory(new File("./test-java/"))
//output will be written to "pro.txt" in working dir of "sh" process
.redirectOutput(new File("./test-java/pro.txt"))
.start();

Take screenshot with ADB and retrieve it in java WITHOUT writing a file

I know that one can take a screenshot from the Android device via ADB with
$ adb shell screencap -p /mnt/sdcard/sc.png
$ adb pull /mnt/sdcard/sc.png
However this writes a file on your phone and on your PC, which I want to avoid.
So I found the following SO question and the answer suggested that the image gets printed to the Std output when you do not specify a file.
I tested this from console and it really printed binary data to the console.
Android: It there a way to read screenshot from memory without saving to internal/external storage?
Now I want to utilize this technique and start a process from java, execute the
adb shell screencap
command, read the output and create a BufferedImage from the output.
I tried something like this
ProcessBuilder pb = new ProcessBuilder("cmd");
Process start = pb.start();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write("adb shell screencap");
bw.newLine();
bw.flush();
// wait some time for the process to print the image to the console
start.waitFor(10, TimeUnit.SECONDS);
StringBuilder sb = new StringBuilder(9000000);
Scanner s = new Scanner(start.getInputStream());
while (s.hasNext()) {
sb.append(s.next());
}
String result = sb.toString();
Unluckily there are quite a few issues with my Code.
the program does not terminate after getting the screenshot - so start.waitFor does not quite work as I wanted it to work
currently my code reads characters, where i actually want to read bytes
reading with scanner seems kind of slow when reading millions of characters/bytes
Maybe someone can point me in a direction such that I can get it to work.
Thanks!
Why complicating things. If you are invoking adb and want its output just run
adb exec-out screencap -p > myimg.png
exec-out is used instead of shell to get raw data (i.e. the image).
After searching some more time I came across ddmlib which already has the functionality to take screenshots and perform various other tasks via ADB built in.
The library works great and definitely made it easier for me to execute commands via ADB.

Linux command not working when changing servers

I'am currently changing our system to use another server for getting file (files generated for tracking something, not important). This system is based on java, and the code for getting these files are using Linux commandos. The code for getting these files are:
session = connection.openSession();
session.execCommand("ls -B -A " + filelocation);
output = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()), "UTF-8"));
This did however work on our original server (x86_64 GNU/Linux), but does not work on the "new" server (SunOs 5.10 Generic January). When running this command on the SunOS server i get:
ls: illegal option -- B
usage: ls -1RaAdCxmnlhogrtuvVcpFbqisfHLeE# [files]
I am far from well versed with with the commandline, and I have not written the original code. But this is what i figured
-A, --almost-all Do not list implied . and ..
-B, --ignore-backups Do not list implied entries ending with ~
Is there an optional way of getting this to work on the SunOS server?
EDIT
Checking each String read if line.endsWith("~");
while ((outputString = output.readLine()) != null) {
if(!outputString.endsWith("~")){
fileList.add(outputString);
}
}
Either you can write a shell script new_ls calling ls and removing the lines that end with "~"
Or when you process the results in java you can also ignore lines read from the BufferedReader by checking each String read if line.endsWith("~");

BAT File not executed fully using Runtime.exec()

I have a BAT file, which creates a number of csv files by reading DB tables. bcp.exe is used for this purpose, thus, for each CSV created from a table, there's a separate bcp.exe call. All these are found in the BAT file, which I invoke using Runtime.exec().
Now the issue I face is random. It can't be recreated in developer environment, but occurs once in a while in the production environment.
Sometimes after the BAT file is executed, only few of the CSV files have been created, and the rest is missing. But when you re-execute the same, you get all the CSVs.
Here's the code:
String command = "cmd /C " + batFilePath + " " + batParams;
LOGGER.info("Executing : " + command);
Runtime rt = Runtime.getRuntime();
Process process = rt.exec(command);
process.getInputStream();
is = process.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
LOGGER.info(line);
}
Would really appreciate it if anyone can enlighten me on how this might happen, since I am all at sea regarding this.
Thanks in advance,
-Raj.
Just a couple of points.
The first is that I've never understood why Java insists on getting the process's output stream with getInputStream - that's just bizarre. But that's just me ranting, there's not much you can do about that :-)
Secondly, I'm not sure why you have a "naked" process.getInputStream(); in your code. I don't think it's bad but it seems unnecessary.
Thirdly (and, to be honest, this is the only one I think may help), you need to debug the batch file itself rather than your Java code.
This can be done with the following two suggestions.
First, get the error stream and look at it. It's quite possible that cmd is delivering error information which you're just ignoring.
Secondly, change the batch file to output copious amounts of debug statements, one after each line if necessary. This will hopefully pinpoint the problem down to a specific place in the batch file.
If it only happens in production (and intermittently), that's harder, but we generally find that our customers are more than willing to accept debug-style temporary patches so we can collect the information to fix the problems they're seeing.
Output from a batch file which is simply logged is also a low-risk change. Some debug code is not so low-risk and we have to test that very thoroughly before involving the customer production systems. Some will refuse point blank, a not-unwise position to take.
It might be that you are exiting your input stream code before the batch script has completed executing.
After:
Process process = rt.exec(command);
you should probably add:
process.waitFor();
If this is the case, then you could verify it in your developer environment by deliberately slowing down your batch script and checking whether you experience the problem. Try sticking something like this:
PING 1.1.1.1 -n 1 -w 5000 > NUL
into your batch file. It will pause your script for 5 seconds.

Unix Script not working in Java Process Runtime.exec()

I am developing an application in Spring Web MVC where i need to execute some of the linux script..
I am using tomcat version 5.5 for running my project in linux..
My code is looking like this :
Process proc = runtime.exec("sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt");
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
System.out.println("\nOUTPUT = " + line);
}
System.out.print("\nbefore execute6");
try {
if (proc.waitFor() != 0) {
System.err.println("\nexit value = " + proc.exitValue());
}
} catch (InterruptedException e) {
System.err.println("\nERROR = " + e);
}
Here i want to cp a particular file from one location to another using linux script..
But when i am executing this part, i am getting
exit value = 1
as a output.. I have also tried to put this script into .sh file and try to execute that shell script here from Java Code, but i am getting same result..
Can anybody tell me, what should be the reason for this ?
Thanks in advance..
I would guess that sudo is expecting an interactive terminal in order to ask for a password. Since there is no interactive terminal, it prints an error message to stderr and exits with an exit code of 1. You are not reading the error stream, so you won't see any message that it might print.
You will definitely want to read the error stream in any case. Doing so now will help you diagnose what is going wrong at this point.
I assume the user that Tomcat is running under has unrestricted access to sudo? And that it's not being prompted for a password?
It is possible that your search path is weird and that "cp" and "sudo" are not found when you try to execute the command.
Here are some things you could try to track down your problem(s):
Try running the "cp" command without "sudo".
Try giving the full pathname of the command(s). This will avoid search path problems.
By default "sudo" logs failed commands using syslog(3). See if you can find traces in the corresponding logfiles.
Assuming you can run your command from a command line, logged in as the tomcat user - try
ProcessBuilder pb = new ProcessBuilder("/usr/bin/sudo", "cp",
"/var/tmp/mailserverfiles/editinterface.txt",
"/etc/sysconfig/network-scripts/editinterface.txt");
pb.redirectErrorStream(true);
Process proc = pb.start();
... rest of code as before
if things still fail, start debugging. strace should be helpful. e.g. run this shell script
from your java application, and figure out where things fail in the /tmp/trace.txt file:
#!/bin/sh
strace -f sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt >/tmp/trace.txt 2>&1
Whilst not directly answering your question, the following will help. You need to read stdout and stderr (to capture all process output), and do this concurrently to prevent blocking of the spawned process. See this answer for more info.

Categories

Resources