I'm having an issue where archival module written in Java fails to clean files shared via smb if opened by network users during cleanup. Below is simplified version of code for file cleanup:
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = (new File(targetFilePath)).delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(new File(targetFilePath));
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
return false;
} else {
Logger.INFO("Move succeeded");
return true;
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
}
It works fine when I test it in two Linux sessions:
session A:
cat -v /dev/zero > sourceFile.txt
session B:
java -jar JavaUnixFileRemovalTest.jar sourceFile.txt targetFile.txt
But fails in production when working with network shares and users.
What I'd like to implement instead is to copy file to archive folder and unlink the header. This way if user still has the file opened he'll continue accessing the content, while name is removed from the file system so nobody else can see the file.
So the question is if there's a way to unlink file header in Unix by native Java means without explicitly calling unlink command
After some research I decided to approach this problem in a bit different way and cast powerful lost magic of the Ancients - that is, use native system C calls with help of JNA (Java Native Access)
Here's an example of the code with some explanations for JNA first-time users:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import java.io.File;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Main {
private static CStdLib cStdLib;
// Here you specify prototypes of native C methods to be called during runtime
// Because unlink(char *path) uses pointer to const char as argument, a wrapper class StringByReference is used to convert data types
// Link to other examples at the end of this post
public interface CStdLib extends Library {
int unlink(StringByReference path);
}
public static void main(String[] args) {
// Here I'm declaring libc usage, but you can link anything. Even your own libraries
cStdLib = (CStdLib)Native.loadLibrary("c", CStdLib.class);
Logger.INFO("Source file: " + args[0]);
Logger.INFO("Target file: " + args[1]);
moveFile(args[0],args[1]);
}
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = targetFile.delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(targetFile);
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
Logger.INFO("Trying to copy file and unlink the original");
// ToDo: add copy method
// That's where we convert String to char*
StringByReference unlinkPath=new StringByReference(sourceFilePath);
int status=cStdLib.unlink(unlinkPath);
if(status==0){
Logger.INFO("Unlink succeeded");
}else {
Logger.ERROR("Unlink also failed");
return false;
}
} else {
Logger.INFO("Move succeeded");
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
return true;
}
}
And class for converting data types:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import com.sun.jna.ptr.ByReference;
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
}
So what we've got in the end? A nice Java unlink utility! test scenario: create a text file in session A, open it in less in session B and run java code in session A. Works as expected:
[me#server1 JavaFileTest]$ lsof | grep sourceFile
less 12611 me 4r REG 253,0 0 73 /home/me/JavaFileTest/sourceFile (deleted)
This is the article I used as a reference:
http://jnaexamples.blogspot.com/2012/03/java-native-access-is-easy-way-to.html
It contains other good examples of wrapping data types for C calls
Tips:
Make sure you have both JNA and JNA-platform files in your classpath
JNA 4.4.0 requires GLIBC_2.14. If you're getting this error then
simply downgrade JNA (4.2.2 worked for me)
Exception in thread "main" java.lang.UnsatisfiedLinkError: /lib64/libc.so.6: version 'GLIBC_2.14' not found
File.delete seems to behave as "unlink".
Here's an example
import java.io.*;
public class Main {
public static void main(String args[]) throws InterruptedException, IOException {
File invisibleFile = new File("invisiblefile");
invisibleFile.createNewFile();
FileWriter fw = new FileWriter(invisibleFile);
System.out.println("file created");
Thread.sleep(5000);
boolean deleted = invisibleFile.delete();
if(!deleted) {
System.out.println("error deleting file");
System.exit(1);
}
fw.write("hello");
fw.flush();
System.out.println("file deleted");
// 'ls invisiblefile' does not return anything
// but the file is still held open by the process:
// lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
Thread.sleep(5000);
fw.close();
System.out.println("file closed");
Thread.sleep(5000);
// after closing file, it is completely gone
System.out.println("end");
}
}
And here's a terminal session to check the program's behaviour:
23:30:07 % java InvisibleFile.java
file created
^Z
zsh: suspended java InvisibleFile.java
23:30:11 % ls invisiblefile
invisiblefile
23:30:14 % fg %1
[1] - continued java InvisibleFile.java
file deleted
^Z
zsh: suspended java InvisibleFile.java
23:30:21 % ls invisiblefile
ls: invisiblefile: No such file or directory
23:30:23 % lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
size:5
inode:33745509
23:30:30 % fg %1
[1] - continued java InvisibleFile.java
file closed
^Z
zsh: suspended java InvisibleFile.java
23:30:37 % lsof -p $(ps -ef | awk '/[I]nvisibleFile.java/ {print $2}') | awk '/invisiblefile/ {print "size:" $7; print "inode:" $8}'
23:30:42 % fg %1
[1] - continued java InvisibleFile.java
end
23:30:47 %
Related
I have a Java application that worked fine when I ran it via command line (I coded it using Notepad++ ). However, when I tried to port the same Java application into Eclipse it's not working for me. It's an application featuring a batch file that is supposed to restart a program that was interrupted midway:
the batch file :
set CLASSPATH=./bin
java fixedMessageApp.FixedMessageSequenceServer 4446 mylogfile.txt 0 0
ping 127.0.0.1 -n 2 > nul
rem java fixedMessageApp.FixedMessageSequenceClient localhost 4444 myclientLog.txt 0
The Java file :
public class FixedMessageRunner {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("usage: java FixedMessageRunner CMD" );
System.exit(0);
}
try {
//for (;;) {
String current = new java.io.File( "." ).getCanonicalPath();
System.out.println("Current dir:"+current);
ProcessBuilder pb = new ProcessBuilder(args[0]);
pb.directory(new File(current)); //("C://FixedMessageApplication//"));
Process p = pb.start();
p.waitFor();
//}
} catch (IOException i) {
i.printStackTrace();
}
catch (InterruptedException i) {
i.printStackTrace();
}
}
}
Why doesn't this work in Eclipse, like it does in CMD ? In Eclipse, when this is run it will just hang :
I have a bash file:
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/bin/svnlook
LOGMSG=$($SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]")
echo "\n$LOGMSG" >> /dev/tty
javac ~/Desktop/SomeClass.java
java ~/Desktop/SomeClass $LOGMSG
STATUS=$?
echo "\n" >> /dev/tty
echo $STATUS >> /dev/tty
exit 0
which calls this java file:
public class SomeClass {
public static void main(String[] args) {
String result = "";
for (String s: args) {
result = result + " " + s;
}
String regex = ".*\\bHello\\b.*";
if(result.matches(regex)) {
System.out.println("It matches");
System.exit(0);
} else {
System.out.println("It does not match");
System.exit(42);
}
}
}
I have never in the Java file have exited with the exit code of 1. However when I echo the status in the bash file, it always shows me '1' What can be the reason behind this?
The error code is because Java is failing to start. You aren't specifying the class to be run correctly.
If I have a class located in my desktop directory, I would need to use the following to run it from another directory:
java -cp ~/Desktop SomeClass
assuming that SomeClass has no package specified. If you have package org.foo.bar; at the top of the file, you would need to use
java -cp ~/Desktop org.foo.bar.SomeClass
Is there any good example do demonstrate file descriptor leak in Android? I read somewhere that it occurs if we don't close the streams for example FileInputStream or FileOutputStream but I could not find any good reference example which demonstrates it.
Please share some blog/code snippet. thank you!
Because Dalvik's FileInputStream will close itself when it is garbage collected (this is also true for OpenJDK/Oracle) it is less common than you'd think to actually leak file descriptors. Of course, the file descriptors will be "leaked" until the GC runs so depending on your program it could take a while before they are reclaimed.
To accomplish a more permanent leak you will have to prevent the stream from being garbage collected by keeping a reference to it somewhere in memory.
Here's a short example that loads a properties file every 1 second and keeps track of every time it has changed:
public class StreamLeak {
/**
* A revision of the properties.
*/
public static class Revision {
final ZonedDateTime time = ZonedDateTime.now();
final PropertiesFile file;
Revision(PropertiesFile file) {
this.file = file;
}
}
/*
* Container for {#link Properties} that implements lazy loading.
*/
public static class PropertiesFile {
private final InputStream stream;
private Properties properties;
PropertiesFile(InputStream stream) {
this.stream = stream;
}
Properties getProperties() {
if(this.properties == null) {
properties = new Properties();
try {
properties.load(stream);
} catch(IOException e) {
e.printStackTrace();
}
}
return properties;
}
#Override
public boolean equals(Object o) {
if(o instanceof PropertiesFile) {
return ((PropertiesFile)o).getProperties().equals(getProperties());
}
return false;
}
}
public static void main(String[] args) throws IOException, InterruptedException {
URL url = new URL(args[0]);
LinkedList<Revision> revisions = new LinkedList<>();
// Loop indefinitely
while(true) {
// Load the file
PropertiesFile pf = new PropertiesFile(url.openStream());
// See if the file has changed
if(revisions.isEmpty() || !revisions.getLast().file.equals(pf)) {
// Store the new revision
revisions.add(new Revision(pf));
System.out.println(url.toString() + " has changed, total revisions: " + revisions.size());
}
Thread.sleep(1000);
}
}
}
Because of the lazy loading we keep the InputStream in the PropertiesFile which will be kept whenever we create a new Revision and since we never close the stream we will be leaking file descriptors here.
Now, these open file descriptors will be closed by the OS when the program terminates, but as long as the program is running it will continue to leak file descriptors as can be seen by using lsof:
$ lsof | grep pf.properties | head -n 3
java 6938 raniz 48r REG 252,0 0 262694 /tmp/pf.properties
java 6938 raniz 49r REG 252,0 0 262694 /tmp/pf.properties
java 6938 raniz 50r REG 252,0 0 262694 /tmp/pf.properties
$ lsof | grep pf.properties | wc -l
431
And if we force the GC to run we can see that most of these are returned:
$ jcmd 6938 GC.run
6938:
Command executed successfully
$ lsof | grep pf.properties | wc -l
2
The remaining two descriptors are the ones stored in the Revisions.
I ran this on my Ubuntu machine but the output would look similar if run on Android.
InputStream in;
try {
in = new BufferedInputStream(socket.getInputStream());
// Do your stuff with the input stream
} catch (Exception e) {
// Handle your exception
} finally {
// Close the stream here
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e(TAG, "Unable to close stream: " + e);
}
}
}
The idea is to close your file descriptor in the finally block. Whether you finish successfully or an exception occurs, the file descriptor will be properly closed.
Now, if you're looking for something to demonstrate how to NOT do this properly, just wrap this code in a while(1) loop, comment out the in.close() line, and put a break; in your catch block so that when it blows up you'll break out of your infinite loop.
InputStream in;
try {
in = new FileInputStream(new File("abc");
in.read(); // Do some stuff with open fileinputstream
// If an exception is generated, inputstream object will not be closed
// as the next statement will not be executed, instead jumping to
// the catch block. this will cause a leak of the fd assigned to file
// "abc" while opening it
in.close()'
} catch (Exception e) {
// Handle your exception
}
I'm trying to execute a python script from a java program.
I have a weird problem, while the script is invoked but does not process completly.
to demonstrate this problem I've simplified the scenario to the following:
Java Code:
public class CallPython {
public static void main(String[] args) {
try {
Process p1 = Runtime.getRuntime().exec("python D://test.py narf");
int res1 = p1.waitFor();
System.out.println(res1);
Process p2 = Runtime.getRuntime().exec("python D://test.py narf2");
int res2 = p2.waitFor();
System.out.println(res2);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
Python Script:
import sys
a = sys.argv[1]
if (a == "narf"):
sys.exit(10)
file = open('bla.txt', 'w')
file.write("StackOverFlow is AWESOME!!!")
file.close()
sys.exit(5)
Running the script from the command line (with an argument different then "narf") results in creation of the file "bla.txt" while running the java code from eclipse prints:
10
5
and creates nothing...
I'm trying to note down workstation/System screen lock of each employee working in ubuntu OS. I needed to store these record in a DataBase. using JAVA. I have searched all over and got on idea for UBUNTU; But got idea how to do the same in windows OS.
From here:
gnome-screensaver-command -q | grep "is active"
Use the Runtime class to execute that command and read back the result.
EDIT: use grep -q
Here an example how to use it:
public class ScreenSaver {
/*
* Pipes are a shell feature, so you have to open a shell first.
*
* You could use process.getInputStream() to read the output and parse it.
*
* For productive use i would prefer using the Inputstream.
*/
private static final String COMMAND = "gnome-screensaver-command -q | grep -q 'is active'";
private static final String[] OPEN_SHELL = { "/bin/sh", "-c", COMMAND };
private static final int EXPECTED_EXIT_CODE = 0;
public static boolean isScreenSaverActive() {
final Runtime runtime = Runtime.getRuntime();
Process process = null;
try {
/*
* open a shell and execute the command in that shell
*/
process = runtime.exec(OPEN_SHELL);
/*
* wait for the command to finish
*/
return process.waitFor() == EXPECTED_EXIT_CODE;
} catch(final IOException e) {
e.printStackTrace();
} catch(final InterruptedException e) {
e.printStackTrace();
}
return false;
}
public static void main(final String[] args) {
System.out.println("Screensaver is active: " + isScreenSaverActive());
}
}
EDIT: added perl script watching dbus signals. Source:
Gnome Screensaver FAQ
#!/usr/bin/perl
my $cmd = "dbus-monitor --session \"type='signal',interface='org.gnome.ScreenSaver',member='ActiveChanged'\"";
open (IN, "$cmd |");
while (<IN>) {
if (m/^\s+boolean true/) {
print "*** Screensaver is active ***\n";
} elsif (m/^\s+boolean false/) {
print "*** Screensaver is no longer active ***\n";
}
}
Try having a look here, ( Similar duplicate), Detect workstation/System Screen Lock using Python(ubuntu))
GNOME Screensaver FAQ This should be an awesome reference for you to get up to speed. I suppose you are using GNOME.