busybox mv with whitespaces fails silently - java

I'm running a device with busybox.
Folder or files with no whitespaces moved correctly, but seems that folders with whitespaces don't move correctly
public static boolean mv(File source, File target) {
if (!source.exists() || !target.exists()) {
return false;
}
try {
StringBuilder command = new StringBuilder("mv -v ");
command.append('\"');
command.append(source.getCanonicalPath());
command.append('\"');
command.append(' ');
command.append('\"');
command.append(target.getCanonicalPath());
command.append('\"');
System.out.println(command.toString());
Process process = Runtime.getRuntime().exec(command.toString());
StringBuilder output = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
output.append(line);
}
System.out.println(output.toString());
return process.waitFor() == 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
The output is
mv -v "/storage/sdcard0/media/music/Progressive Death Metal" "/storage/sdcard0/Music"
No mv output, method just returns "false" (non-zero exit code).
And must I use canonical path, or is it okay to use absolute path and leave it to shell?
EDIT
I also came up that if the filename had quotes, the argument will be wrong, so I made a method adding escape characters
private static String getCommandLineString(String input) {
return input.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\'", "\\\'")
.replace("`", "\\`")
.replace(" ", "\\ ");
}
And now mv looks like this
public static boolean mv(File source, File target) {
if (!source.exists() || !target.exists()) {
return false;
}
try {
StringBuilder command = new StringBuilder("mv -v ");
command.append(getCommandLineString(source.getAbsolutePath()));
command.append(' ');
command.append(getCommandLineString(target.getAbsolutePath()));
System.out.println(command.toString());
Process process = Runtime.getRuntime().exec(command.toString());
StringBuilder output = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
output.append(line);
}
System.out.println(output.toString());
return process.waitFor() == 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
what I get is
mv -v /sdcard/media/music/Progressive\ Death\ Metal /sdcard/Music
But still I get silent non-zero exit code.

Finally got it working. Exec should ask for shell, while OutputStream should write commands.
private static boolean execute(boolean superuser, String command) {
DataOutputStream os = null;
try {
Process process = Runtime.getRuntime().exec(superuser ? "su" : "sh");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.flush();
os.writeBytes("exit\n");
os.flush();
return process.waitFor() == 0;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (os != null) { try { os.close(); } catch (Exception e) {} }
}
return false;
}
public static boolean mv(File source, File target) {
if (!source.exists() || !target.exists()) {
return false;
}
try {
StringBuilder command = new StringBuilder("mv ");
command.append(getCommandLineString(source.getAbsolutePath()));
command.append(' ');
command.append(getCommandLineString(target.getAbsolutePath()));
return execute(false, command.toString());
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

Related

printing strings doubles and integers from a different file

So I'm new to java and I have to read strings, doubles, and integers from a file and print them out after. This is the error that java is throwing at me:
error: variable declaration not allowed here Scanner file = new
Scanner(line);
what am does it mean?
Scanner file = new Scanner(line);
Fails because a variable named file is already declared above ...
Scanner file = new Scanner(data);
Give one of the scanner variables a different name. There's some other problems with your code, but I assume this is a school assignment so only answered the question you asked.
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = br.readLine()) != null) {
String[] splited = line.split(" ");
for (String st: splited) {
if(isInteger(st))
System.out.println("---int--->"+st);
else if(isDouble(st))
System.out.println("---dubl--->"+st);
else if (!st.isEmpty())
System.out.println("---String--->"+st);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private static boolean isInteger(String st) {
try {
Integer.parseInt(st);
return true;
} catch (NumberFormatException e) {
return false;
}
}
static boolean isDouble(String str) {
try {
Float.parseFloat(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
This Maybe help you

Empty InputStream for Android Porcess with "su"

I have Android 7 device with root (it works)
I want to execute root commands via OutputStream and get messages about results via InputStream.
private void getSu() {
if (mProcess != null) return;
try {
mProcess = Runtime.getRuntime().exec("su");
} catch (IOException e) {
e.printStackTrace();
}
}
private void getStdOut() {
if (mStdOut != null) return;
getSu();
mStdOut = new DataOutputStream(mProcess.getOutputStream());
}
private void getStdIn() {
if (mStdIn != null) return;
getSu();
mStdIn = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
}
After that I'm trying to execute "mount" command and read results of this command.
getSu();
getStdOut();
getStdIn();
String[] mountLine = getMount(mStdOut, mStdIn, "/system");
private String[] getMount(#NonNull DataOutputStream stdOut, #NonNull BufferedReader stdIn, String string) {
String[] res=null;
try {
stdOut.writeBytes("mount");
stdOut.writeBytes("\n");
String str;
while ((str=stdIn.readLine()) != null) {
if (str.contains(string)) {
res = str.split(" ");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
This code was working on Android 6 before. But on Android 7 I get InputSream full of \u0000
I tried to execute this command via adb shell and I got nice results. Why do I get InputSream full of \u0000?
Android 7+ needs:
stdOut.flush();
After writeBytes()

Search for string in all files inside a Directory

I want to search for particular string inside all files in a Directory.
Ex: Search for "tiger" in path D:/test/chapters/
D:/test/chapters
/chapter1.log
/chapter2.log
/chapter3.log all these sub files under D:/test/chapters/ .
Sample code I have tried :
public class Example {
public Example() {
super();
}
public int plugin_execute() {
boolean foundstring=false;
try {
File dir = new File("D:/test/chapters");
String[] children = dir.list();
if (children == null) {
System.out.println("does not exist is not a directory");
} else {
for (int i = 0; i < children.length; i++) {
String filename = children[i];
System.out.println(filename);
if (filename !=null) {
foundstring = testString(filename, "tiger");
System.out.println("failed");
}
//Search for entry in file
if (!foundstring) {
return //failuremsg
} else {
System.out.println("failed");
return //succes
}
}
}
return 1;
} catch (Exception e) {
return //error mssg
}
}
private boolean teststring(String filePath, String str) {
BufferedReader br = null;
File file = new File(filePath);
boolean result = false;
if(!file.exists())
return false;
try {
br = new BufferedReader(new FileReader(filePath));
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
if (sCurrentLine.contains(str)) {
result = true;
System.out.println(str);
System.out.println("Found entry ");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
}
It only returns the output of last file, means if it search success in last file it return success otherwise failed.
But I want success if string is found in first file. i.e chapter1 should return success, if not found in Chapter1 it should continue search in chapter2 ....
Please suggest how can I modify this code..
Problem: Simple mix-up with ! and true/false locations.
Solution: Change this
if (! foundString)
{
return // failuremsg
}
else
{
System.out.println("failed");
return // success
}
to
if (foundString)
{
// return success message
}
else
{
// return failure message
}
Another problem I believe I see in your code is that the line foundstring = findString(filename, "tiger"); calls the method findString, whereas the other method you posted in your code is testString. I assume this is a name mix up.
public void listFiles(Path dir , String text)
{
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir))
{
for (Path path : directoryStream)
{
if (Files.isRegularFile(path) && Files.isReadable(path))
{
//this.findString(path, text);
}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
private boolean findString(Path file, String text)
{
//Your implementation
return true;
}

waitFor() method returning null although the process is finish

Here is my code:
private static model connectRemoteSession(String accountName,String password) throws IOException{
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
Runtime runtime = Runtime.getRuntime();
String com = // some command
proc = runtime.exec(com);
Worker worker = new Worker(proc);
reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
stderr = new BufferedReader(new InputStreamReader(
proc.getErrorStream()));
String outLine;
String errLine;
worker.start();
try {
worker.join(300000);
if (worker.exit != null){
//read the outout and error stream and take actions accordingly
}
else{
proc.destroy();
while ((outLine = reader.readLine()) != null)
{
CloudBackup.logger.info("online exchange output line ="+outLine);
output.append(outLine);
}
while((errLine = stderr.readLine()) != null){
CloudBackup.logger.info("online exchange error line ="+errLine);
error.append(errLine);
}
throw new TimeoutException();
}
} catch(InterruptedException ex) {
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
proc.destroy();
}
}catch(Exception e){
CloudBackup.logger.severe(e.getMessage());
}finally{
reader.close();
proc.getOutputStream().close();
stderr.close();
}
return model;
}
class Worker extends Thread {
private final Process process;
Integer exit;
Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
This issue I am facing is one one machine the code is working fine but on another machine the worker.exit is always null, although I put the logs in the worker.exit == null and saw that the process is getting over but somehow process.waitFor is not capturing it.
I know that process.waitFor() is available in Java 8 so I checked the version on both the machined and they have same version Java 8. Also there is no other thread running.
Try this, it can be a caching issue.
volatile Integer exit;

reading output of a child process Interruptibly

I want to launch a child proces and read its output until EOF or until an internal flag is cleared.
My first attempt was to call InputStream.close() in another thread, but although it works for sockets, it doesn't work with the result of Process.getInputStream(): the main thread is still waiting in read() and the killer thread either hangs in close0() (windows) or continues with no effect (linux).
Then I tried to check InputStream.available(), but it doesn't detect EOF: it returns 0.
public class BbbTest extends TestCase {
private Process proc;
private InputStream getStream() throws IOException {
//if ("".length() == 0) return new java.net.Socket("intra", 80).getInputStream();
String[] cmd;
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
cmd = new String[] { "cmd", "/c", "more & more" };
} else {
cmd = new String[] { "sh", "-c", "cat; cat" };
}
Process proc = Runtime.getRuntime().exec(cmd);
return proc.getInputStream();
}
public void testB() throws Exception {
final InputStream in = getStream();
final Thread readingThread = Thread.currentThread();
Thread t = new Thread("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") {
#Override
public void run() {
try {
sleep(1000);
if (proc != null) proc.destroy(); // this won't help
readingThread.interrupt(); // this won't help either
in.close(); // this will do nothing and may even hang
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.setDaemon(true);
t.start();
try {
in.read();
assertTrue(false);
} catch (IOException e) {
// nothing
}
}
}
My last hope is to steal the channel from the returned stream and use nio
In windows , this Command will not terminate.
cmd = new String[] { "cmd", "/c", "more & more" };
Instead of try this simple command
cmd = new String[] { "cmd", "/c", "dir" };
And if you want to read your stream
public static void slurp(final InputStream is, final int bufferSize)
{
try(final Reader in = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(in);){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Call this method by passing stream like this.
final BbbTest bbTest = new BbbTest();
Thread t = new Thread("xsdfds") {
#Override
public void run() {
try {
slurp(bbTest.getStream());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.start();
If you want to kill the process from child thread.
Create setter and getter method for Process in BbbTest like this
public class BbbTest {
private Process proc;
/**
* #return the proc
*/
public Process getProc() {
return proc;
}
/**
* #param proc the proc to set
*/
public void setProc(Process proc) {
this.proc = proc;
}
private InputStream getStream() throws IOException {
String[] cmd;
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
// cmd = new String[] { "cmd", "/c", "more & more" };
cmd = new String[] { "cmd", "/c", "dir" };
} else {
cmd = new String[] { "sh", "-c", "cat; cat" };
}
proc = Runtime.getRuntime().exec(cmd);
return proc.getInputStream();
}
}
Now using process you can destroy
bbTest.getProc().destroy();
If you want to kill the process based on output of other stream, you can add logic in slurp method by checking line content and terminate using destroy
UPDATE
Simple Demo
public class BbbTest {
private Process startProcess(String[] commands) throws IOException {
Process proc = Runtime.getRuntime().exec(commands);
return proc;
}
public static void slurp(final InputStream is)
{
try(final Reader in = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(in);){
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.equals("end")){
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws Exception {
final BbbTest bbTest = new BbbTest();
final Process process = bbTest.startProcess(new String[] { "cmd", "/c", "more" });
Thread t = new Thread("xsdfds") {
#Override
public void run() {
try {
slurp(process.getInputStream());
process.destroy();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException ( );
}
}
};
t.start();
try(OutputStream out = process.getOutputStream();
BufferedOutputStream outStream = new BufferedOutputStream(out);){
outStream.write("Test".getBytes());
outStream.write("\n".getBytes());
outStream.write("end".getBytes());
outStream.write("\n".getBytes());
outStream.flush();
}
}
}
Look at this sample : You should have some condition to terminate the child thread ( reading prcoess) like if the stream writes "end" / or End of EOF ( process closed inputstream )

Categories

Resources