Linux command "write all used jars by JVM to file" within Java - java

I want to know which jars are loaded by all the different running JVM's.
If I type
"lsof -p $PID | grep jar >> /somefile"
from the bash/command, it works beautifully! (replacing $PID with an actual process id). However, I would like to be able to do this from within a Java program. I would expect the following code to work but no file gets written:
public static void printCustomCommand(){
String[] pids = {"pidof java"};
String s;
try {
Process pidProcess = Runtime.getRuntime().exec("pidof java");
BufferedReader br = new BufferedReader(new InputStreamReader(pidProcess.getInputStream()));
pids = br.readLine().split(" ");
for (String pid : pids){
String cmd = "lsof -p " + pid + " | grep jar >> /somepath/mydumpfile";
Process p;
p = Runtime.getRuntime().exec(cmd);
System.out.println(p.waitFor());
}
//pids = new String(bo).split(" ");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I print the p.waitFor() command, it returns a 1 always, meaning according to the API documentation "something is incorrect".
http://docs.oracle.com/javase/6/docs/api/java/lang/Process.html#waitFor%28%29

The issue is that Runtime.exec() does not understand shell concepts such as "|".
Try this:
public static void printCustomCommand(){
String[] pids = {"pidof java"};
String s;
try {
Process pidProcess = Runtime.getRuntime().exec("/bin/bash -c pidof java");
BufferedReader br = new BufferedReader(new InputStreamReader(pidProcess.getInputStream()));
pids = br.readLine().split(" ");
for (String pid : pids){
String cmd = "/bin/bash -c lsof -p " + pid + " | grep jar >> /somepath/mydumpfile";
Process p;
p = Runtime.getRuntime().exec(cmd);
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
p.waitFor();
}
//pids = new String(bo).split(" ");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The problem is that exec runs a binary directly without invoking the shell. The "|" character is only recognized by the shell. The "-c" tells the shell to run a single command, and passes the entire command as the single argument.

Isn't that
Process pidProcess = Runtime.getRuntime().exec(new String[]{"pidof","java"});
?
And you cannot use pipes (|) in the exec method. The exec executes commands (executables) but pipes is part of the/a shell.

Related

Problem sshpass using Runtime.getRuntime().exec on java, but on cmd tunning fine

can someone solve this problem? I using sshpass for transfer file on java. Execute this command
Process proc = Runtime.getRuntime().exec(new String[] {"sshpass","-p", "password","scp","-r",getContext().getServletContext().getRealPath("/WEB-INF/file/"+today)+"/ Name#myip:/cygdrive/d/file"});
and the error doesn't show on java using runtime.exec but on the command line running well.
my code
try {
Process proc = Runtime.getRuntime().exec(new String[] {"sshpass","-p", "password","scp","-r",getContext().getServletContext().getRealPath("/WEB-INF/file/"+today)+"/ Name#myip:/cygdrive/d/file"});
// System.out.println(sshStr);
BufferedReader read = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
//--------------------check---------------------
printStream(proc.getInputStream(), "OUTPUT");
printStream(proc.getErrorStream(), "ERROR");
//--------------------check---------------------
try {
proc.waitFor();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
while (read.ready()) {
System.out.println(read.readLine());
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
Using Runtime.exec(String), the string argument is split on whitespace, regardless of which quotes you've added. You have to use Runtime.exec(String[]) instead. This leads to:
Process proc = Runtime.getRuntime().exec(new String[] {
"sshpass",
"-p", "password",
"scp",
"-r", getContext().getServletContext().getRealPath("/WEB-INF/file/" + today) + "/ Name#myip:/cygdrive/d/file"
});

Run windows command from eclipse

I need to run the following command from eclipse..and print that result on eclipse console(Im comparing 2 files)
"fc /c/1 /n file1path file2path".
Here is my code
final Process p = Runtime.getRuntime().exec("cmd /c fc /c/1 /n file1path file2path");
new Thread(new Runnable() {
public void run() {
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line =new String();
try {
line = input.readLine();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
while (line != null) {
System.out.println(line);
line = input.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
p.waitFor();
But its not printing anything..What is wrong with the code??
The program is fine and works for me. The problem is in your command. Change your command and remove the cmd and extra /c flag. Also remove the invalid flag /c/1. Your final command should look like :-
final Process p = Runtime.getRuntime().exec("fc /c /n file1path file2path");

Java Runtime exec() get stuck after a while

I'm building a simple UI for ffmpeg launching ffmpeg.exe with parameters using exec(). it works on Os X but on Windows 7-8 after few seconds the ffmpeg process suspends itself and resumes only when I kill the father process. (also ddlhost.exe is created)
Ffmpeg.exe converts successfully the same video from cmd.
Searching on the internet I've found this answer but I have the same problem running a simple test program which is not using the Input and Error streams.
Here is the test program code which has the same problem of the main one:
public class Main {
static String param_ffmpeg_1 = "./data/ffmpeg.exe";
static String param_ffmpeg_2 = "-i";
static String in = "./data/source.mov";
static String out = "./data/out.flv";
static Process p;
public static void main(String[] args) {
/*File f = new File(out);
if (f.exists()){
f.delete();
}*/
Runtime rt = Runtime.getRuntime() ;
//String cmd1 = param_ffmpeg_1 + param_ffmpeg_2 + in_path + param_ffmpeg_3 + out_path ;
System.out.println(in);
System.out.println(out);
String[] cmd1 = new String[] { param_ffmpeg_1, param_ffmpeg_2, in, "-ar", "44100", "-vb", "2500k", "-s", "882x496", "-f", "flv", out};
try {
p = rt.exec(cmd1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int r = 123456;
try {
r = p.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(r);
}
}
Does ffmpg write anything to the stdout or stderr? If yes you have to consume that. (In seperate threads as you need to consume the stderr and the stdout in parallel) see Process.getInputStream() and Process.getErrorStream() for the details. When the buffer is buffer is full your called programm is stopped and hangs.
The fact that it works in OS/X but not Windows might be caused by different buffer sizes.
You should call getInputStream() and getErrorStream() on the Process returned by Runtime.exec and drain that all the time the process is running. If you do not then it will eventually fill up and block and stop the process from running.
See Java Process with Input/Output Stream for examples.
From the accepted answer
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream itsOutput = process.getInputStream();
// Wrap the stream in a Reader ...
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}

Root su command

I'm developing an application that works with rooted devices too.
I have two questions:
When I launch the application, it checks for root, the SuperUser dialog appears, I click on Accept then 'Remember my Choice' later, I run a command:
Process process;
try {
process = Runtime.getRuntime().exec(new String[]
{"su", "-c", "rm -r /data/data"});
prefs = this.getSharedPreferences("Prefs",
Context.MODE_WORLD_WRITEABLE);
prefsEditor = prefs.edit();
stopSelf();
then here again the SuperUser dialog appears. Why is it appearing more than once for the same application? I checked "Remember My Choice".
I'm using
process = Runtime.getRuntime().exec(new String[]
{"su", "-c", "rm -r /data/data"});
Is there any way to add exceptions, e.g. Do not delete "com.My.App"?
You are removing /data/data and all subdirectories of it. This is the place where applications are storing the app private data, and for sure the SuperUser isstoring in here the list of authorized applications.
I believe you already guess what's happenig ... you are removing your own authorization.
You need to add an exception to the superUser.
To add an exception, I couldn't find a straightforward solution, as only limited shell commands are available. If you install busybox it would give you opportunity to use the grep command to parse the input and exclude the lines you want.
Alternatively, you can do it programmatically using the following approach:
process = Runtime.getRuntime().exec(new String[] {"su", "-c", "ls /data/data"});
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
ArrayList<String> files = new ArrayList<String>();
files.add("su");
files.add("-c");
files.add("rm -r");
while ((line = bufferedReader.readLine()) != null){
//test if you want to exclude the file before you add it
files.add("/data/data/" + line);
}
//issue a new command to remove the directories
process = Runtime.getRuntime().exec(files.toArray(new String[0])); //changed this line
Hope it helped.
--EDITED--
The code bellow is working fine on a rooted device. The final command being issued is also a ls, as I don't want to remove my files, but you can just replace it by anything else (see comments in file).
private void execCmd(){
Process process;
try {
process = Runtime.getRuntime().exec(new String[] {"su", "-c", "ls /data/data"});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
ArrayList<String> files = new ArrayList<String>();
files.add("su");
files.add("-c");
// files.add("rm -r"); //Uncomment this line and comment the line bellow for real delete
files.add("ls");
try {
while ((line = bufferedReader.readLine()) != null){
//test if you want to exclude the file before you add it
files.add("/data/data/" + line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//comment lines bellow to stop logging the command being sent
Log.d(TAG, "Command size: " + files.size());
for(int i=0; i< files.size(); i++)
Log.d(TAG, "Cmd[" + i + "]: " + files.get(i));
try {
process = Runtime.getRuntime().exec(files.toArray(new String[0]));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //changed this line
}
Regards

how to get error message when excuting java command?

I call a class which is located somewhere in a jar file (using java -classpath path/file.jar classname) within my java code.
This work well but only if the command is well formed. If I make a mistake the getRuntime().exect(command) just doesn't say anything. Bellow I have the working command invocation. I would like to get the error message when the command doesn't work. If I make a mistake in a cmd (windows) I get a proper error and I can fix it. But not within my java application.
I left a 'if(input.ready())' since if I don't the program freezes when the command line is incorrect. This happens when executing 'input.readLine()'.
// Execute a command with an argument that contains a space
String[] genKOSCommand = new String[] {
"java",
"-classpath",
Config.XDSI_TEST_KIT_HOME + "/xdsitest/lib/xdsitest.jar;"
+ Config.XDSI_TEST_KIT_HOME + "/xdsitest/classes",
"ca.etsmtl.ihe.xdsitest.docsource.SimplePublisher", "-k",
"C:/Softmedical/Viewer_Test/xdsi-testkit-2.0.4/xdsihome/usr/data/image14.dcm" };
Process child = Runtime.getRuntime().exec(genKOSCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(
child.getInputStream()), 13107200);
String line = null;
if (input.ready()) {
while ((line = input.readLine()) != null) {
System.out.println(line);
}
try {
child.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Have any advice on how to get an error from the executed command?
Thank you
By using getErrorStream:
BufferedReader errinput = new BufferedReader(new InputStreamReader(
child.getErrorStream()));
When processing the input from the different streams, it is better to do it in a different thread (since those calls (readLine etc.) are blocking calls.
Here's a bit more complete piece of code to print out errors received upon running some command via Process/Runtime:
final String command = "/bin/bash -c cat foo.txt | some.app";
Process p;
try {
p = Runtime.getRuntime().exec(command);
} catch (final IOException e) {
e.printStackTrace();
}
//Wait to get exit value
try {
p.waitFor();
final int exitValue = p.waitFor();
if (exitValue == 0)
System.out.println("Successfully executed the command: " + command);
else {
System.out.println("Failed to execute the following command: " + command + " due to the following error(s):");
try (final BufferedReader b = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line;
if ((line = b.readLine()) != null)
System.out.println(line);
} catch (final IOException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Isn't Process.getErrorStream what you want?

Categories