How to supply sudo with root password from Java? - java

I'm trying to write a small Java app that will overwrite my /etc/resolv.conf file (I'm on Ubuntu 12.04). To do so, I need to supply my root password:
myUser#myMachine:~$ sudo vim /etc/resolv.conf
[sudo] password for myUser: *****
So the process for doing this has three steps:
Type sudo vim /etc/resolv.conf at terminal
Terminal asks me to type my root password
I enter the password and press [Enter]
From everything I've researched, I could use the following for performing step #1 above:
try {
String installTrickledCmd = "sudo vim /etc/resolv.conf";
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec(installTrickledCmd);
}
catch(Throwable throwable) {
throw new RuntimeException(throwable);
}
But when this executes, the shell will want to prompt my Java process for the password. I'm not sure how to wait for this (step #2 above) and then to supply my password back to the shell (step #3 above). Thanks in advance.

Have you tried with -S ?
$echo mypassword | sudo -S vim /etc/resolv.conf
From man:
The -S (stdin) option causes sudo to read the password from the standard input
instead of the terminal device. The password must be followed by a newline
character.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class Test1 {
public static void main(String[] args) throws Exception {
String[] cmd = {"sudo","-S", "ls"};
System.out.println(runSudoCommand(cmd));
}
private static int runSudoCommand(String[] command) throws Exception {
Runtime runtime =Runtime.getRuntime();
Process process = runtime.exec(command);
OutputStream os = process.getOutputStream();
os.write("harekrishna\n".getBytes());
os.flush();
os.close();
process.waitFor();
String output = readFile(process.getInputStream());
if (output != null && !output.isEmpty()) {
System.out.println(output);
}
String error = readFile(process.getErrorStream());
if (error != null && !error.isEmpty()) {
System.out.println(error);
}
return process.exitValue();
}
private static String readFile(InputStream inputStream) throws Exception {
if (inputStream == null) {
return "";
}
StringBuilder sb = new StringBuilder();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = bufferedReader.readLine();
while (line != null) {
sb.append(line);
line = bufferedReader.readLine();
}
return sb.toString();
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
}
}
Inspired from Viggiano answer.

Related

How to write and run terminal command to be execute in java program

String str;
Process p;
try {
String command = "wmctrl -l|awk '{$1=\"\"; $2=\"\"; $3=\"\"; print}'";
p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((str = br.readLine()) != null) {
activeWindowtitles.add(str);
System.out.println(str);
}
p.waitFor();
p.destroy();
} catch (Exception ex) {
}
I am writing a java code to get all applications name in Linux system. I found a command to achieve this. I ran this command in Terminal and it works fine. But it is not working in Java code as i want only applications name instead of other details. The command is "wmctrl -l | awk '{$1=""; $2=""; $3=""; print}'"
I am getting full output after executing this in java code.
Please tell me how to write this command properly..
Thanks
Personally I would put the wmctrl command in a script and do something like this:
public static List<String> getRunningApps(String executablePath) throws IOException, InterruptedException {
final String ERR_LOG_PATH = "stderr.log";
List<String> result = new ArrayList<>();
ProcessBuilder pb = new ProcessBuilder(executablePath);
pb.redirectError(new File(ERR_LOG_PATH));
Process p = pb.start();
int exitCode = p.waitFor();
if (exitCode != 0) {
throw new RuntimeException(String.format("Error get apps. Check error log %s%n", ERR_LOG_PATH));
}
try (Scanner s = new Scanner(p.getInputStream())) {
while (s.hasNextLine()) {
result.add(s.nextLine().trim());
}
}
return result;
}
That way you can tweak it more easily and keep your code cleaner. The script I used was:
#!/bin/bash
wmctrl -l | awk '{$1=""; $2=""; $3=""; print}'

Java enter command to a process that opens a new telnet connection

I would like to write a Java program to control the Android emulator to do some testing, and now I have to take snapshots of the emulator when it is created and every time it has changes, so according to google, the command is like:
telnet localhost 5555
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
avd snapshot save 1
OK
So basically two commands, the first is to open a telnet connection and then enter avd snapshot save x command to save the snapshot.
However using the command like this:
public static void main(String[] args) throws IOException{
int initScore = 1000;
int ID = 0;
// monitor the log, check if a new activity is reached.
// if so, take a snapshot of the current activity and save it to the snapshot folder.
String cmd1 = "telnet localhost " + 5555;
// the static port 5557 should change to this.getVM_consolePort();
String cmd2 = "avd snapshot save " + ID;
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", cmd1, cmd2);
Process p = pb.start();
// read the process output
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
}
can only run the first command (which is to open telnet connection).
So could anyone tell me how to interact with a opened connection or enter command to another process in Java?
Here's an example using grep:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class Test {
public static void main(String[] args) throws IOException {
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "grep foo");
Process p = pb.start();
BufferedReader stdOut = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Writer stdIn = new OutputStreamWriter(p.getOutputStream());
stdIn.write("foo1\nbar\nfoo2\n");
stdIn.close();
String s = null;
while ((s = stdOut.readLine()) != null) {
System.out.println(s);
}
while ((s = stdErr.readLine()) != null) {
System.out.println(s);
}
}
}
I renamed stdIn to stdOut, so they are named from the point of view of the process you're running.
I read from stderr, so that you can see any problems.
Actually I have tried this before like the code below:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
public class Main {
public static void main(String[] args) throws IOException {
// int initScore = 1000;
int ID = 0;
Process p = Runtime.getRuntime().exec("telnet localhost 5555");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter stdIn = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
String line;
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
if (line.contains("OK")){
break;
}
}
stdIn.write("avd snapshot save " + ID);
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
}
}
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Android Console: type 'help' for a list of commands
OK
I think the reason is that the telnet created a new shell and the writer is writing to the old shell, therefore it is not working, so I am looking for a solution to enter the new command into the new shell.

ProcessBuilder working in Linux but not Windows

I have a simple program that runs the echo command with ProcessBuilder, and the program works perfectly fine on my Linux machine, but it throws an IOException when running on Windows.
This is a simplified version of my program. It takes echo and hello as arguments for ProcessBuilder, and then saves the output into a string and prints the output. In Linux, the output is hello, and in Windows an IOException is caught.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestPB {
public static void main(String[] args) throws InterruptedException {
ProcessBuilder pb = new ProcessBuilder("echo", "hello");
try {
Process process = pb.start();
BufferedReader readProcessOutput = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output = "";
String line = "";
while ( (line = readProcessOutput.readLine()) != null) {
output += line;
output += System.getProperty("line.separator");
}
process.waitFor();
if(output.length() > 0) {
System.out.println(output.substring(0, output.length() -1));
} else {
System.out.println("No result");
}
} catch (IOException io) {
System.out.println("IOException thrown");
}
}
}
Does anyone know why this is not working in Windows?
echo is not a program on Windows, it's an internal shell command*, so you need to invoke the command-line interpreter:
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "echo", "hello");
*) Reference: Wikipedia

Invoke Powershell scripts from Java

I want to invoke my powershell script from java. Can it be done. I tried with the following code, but the stream is not closing.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class TestPowershell {
public static void main(String[] args) throws IOException
{
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("powershell C:\\testscript.ps1");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
reader.close();
proc.getOutputStream().close();
}
}
Does java invoke a powershell script which performs create remote session and execute cmdlets?
Do we have support to invoke powershell scripts in java?
Anyone could you please help on this.
Awaiting for your responses.
Thanks,
rammj
After starting the process ( runtime.exec() ), add a line to close the input stream of the process ( which JAVA calls output stream!!):
proc.getOutputStream().close();
Now you can do it easily with jPowerShell
powerShell = PowerShell.openSession();
//Print results
System.out.println(powerShell.executeScript("\"C:\\testscript.ps1\"").getCommandOutput());
powerShell.close();
Yes we can create remote session and execute cmdlets using powershell script.
Save the following Power shell script to testscript.ps1
#Constant Variables
$Office365AdminUsername="YOUR_USERNAME"
$Office365AdminPassword="TOUR_PASSWORD"
#Main
Function Main {
#Remove all existing Powershell sessions
Get-PSSession | Remove-PSSession
#Encrypt password for transmission to Office365
$SecureOffice365Password = ConvertTo-SecureString -AsPlainText $Office365AdminPassword -Force
#Build credentials object
$Office365Credentials = New-Object System.Management.Automation.PSCredential $Office365AdminUsername, $SecureOffice365Password
Write-Host : "Credentials object created"
#Create remote Powershell session
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $Office365credentials -Authentication Basic –AllowRedirection
Write-Host : "Remote session established"
#Check for errors
if ($Session -eq $null){
Write-Host : "Invalid creditials"
}else{
Write-Host : "Login success"
#Import the session
Import-PSSession $Session
}
#To check folder size
Get-MailboxFolderStatistics "YOUR_USER_NAME" | Select Identity, FolderAndSubfolderSize
exit
}
# Start script
. Main
Java Code :
try {
String command = "powershell.exe \"C:\\testscript.ps1\"";
ExecuteWatchdog watchdog = new ExecuteWatchdog(20000);
Process powerShellProcess = Runtime.getRuntime().exec(command);
if (watchdog != null) {
watchdog.start(powerShellProcess);
}
BufferedReader stdInput = new BufferedReader(new InputStreamReader(powerShellProcess.getInputStream()));
String line;
System.out.println("Output :");
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
If you do not get output, try this: powerShellProcess.getErrorStream() instead powerShellProcess.getInputStream(). It will show the errors.

How to invoke a Linux shell command from Java

I am trying to execute some Linux commands from Java using redirection (>&) and pipes (|). How can Java invoke csh or bash commands?
I tried to use this:
Process p = Runtime.getRuntime().exec("shell command");
But it's not compatible with redirections or pipes.
exec does not execute a command in your shell
try
Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"});
instead.
EDIT::
I don't have csh on my system so I used bash instead. The following worked for me
Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ls /home/XXX"});
Use ProcessBuilder to separate commands and arguments instead of spaces. This should work regardless of shell used:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(final String[] args) throws IOException, InterruptedException {
//Build command
List<String> commands = new ArrayList<String>();
commands.add("/bin/cat");
//Add arguments
commands.add("/home/narek/pk.txt");
System.out.println(commands);
//Run macro on target
ProcessBuilder pb = new ProcessBuilder(commands);
pb.directory(new File("/home/narek"));
pb.redirectErrorStream(true);
Process process = pb.start();
//Read output
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null, previous = null;
while ((line = br.readLine()) != null)
if (!line.equals(previous)) {
previous = line;
out.append(line).append('\n');
System.out.println(line);
}
//Check result
if (process.waitFor() == 0) {
System.out.println("Success!");
System.exit(0);
}
//Abnormal termination: Log command parameters and output and throw ExecutionException
System.err.println(commands);
System.err.println(out.toString());
System.exit(1);
}
}
Building on #Tim's example to make a self-contained method:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class Shell {
/** Returns null if it failed for some reason.
*/
public static ArrayList<String> command(final String cmdline,
final String directory) {
try {
Process process =
new ProcessBuilder(new String[] {"bash", "-c", cmdline})
.redirectErrorStream(true)
.directory(new File(directory))
.start();
ArrayList<String> output = new ArrayList<String>();
BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line = null;
while ( (line = br.readLine()) != null )
output.add(line);
//There should really be a timeout here.
if (0 != process.waitFor())
return null;
return output;
} catch (Exception e) {
//Warning: doing this is no good in high quality applications.
//Instead, present appropriate error messages to the user.
//But it's perfectly fine for prototyping.
return null;
}
}
public static void main(String[] args) {
test("which bash");
test("find . -type f -printf '%T#\\\\t%p\\\\n' "
+ "| sort -n | cut -f 2- | "
+ "sed -e 's/ /\\\\\\\\ /g' | xargs ls -halt");
}
static void test(String cmdline) {
ArrayList<String> output = command(cmdline, ".");
if (null == output)
System.out.println("\n\n\t\tCOMMAND FAILED: " + cmdline);
else
for (String line : output)
System.out.println(line);
}
}
(The test example is a command that lists all files in a directory and its subdirectories, recursively, in chronological order.)
By the way, if somebody can tell me why I need four and eight backslashes there, instead of two and four, I can learn something. There is one more level of unescaping happening than what I am counting.
Edit: Just tried this same code on Linux, and there it turns out that I need half as many backslashes in the test command! (That is: the expected number of two and four.) Now it's no longer just weird, it's a portability problem.

Categories