Running shell script on tomcat7 - java

I have been breaking my head for two days trying to fix the file permissions for my tomcat7 server. I have a library class (.jar file included in myapp/WEB-INF) which needs to run a shell script. The library is written by me and works fine within NetBeans ie. no hassle in creating,reading and deleting files. That is because NetBeans runs the program as blumonkey(my username on my Ubuntu System). But when I import this into tomcat and run it, tomcat "executes" the command, produces no definite output, tries to check for a file(which will be generated when the script succeeds) and throws a FileNotFoundException.
More Details as follows:
Tomcat7 installed using apt-get, has its data in 2 locations - /var/lib/tomcat7 with conf and webapps folders and /usr/share/tomcat7 with the bin and lib folders
The user uploads a .zip file which is stores to /home/blumonkey/data. Rest of the program runs on the documents stored here. All new folders/files uploaded by tomcat have, obviously, tomcat7 as the owner.
I have tried things like changing the ownership to blumonkey, adding tomcat7 to blumonkey user group but none of the methods worked (Somewhere around here I probably messed up changing permissions carelessly :/ ). Apparently tomcat7 is unable to process on the files it owns.(How can this be?).
The script works when I run it in the terminal. But it doesn't work when I do a sudo -u tomcat7 script.sh, ie run it as tomcat7. It just exits with no message. I doubt that this it what is happening as I have tried to debug by redirecting the errors and outputs in ProcessBuilder but they came empty.
Any help regarding how to fix the issue and get the script running would be greatly appreciated. Please comment if you need any more info.
The code for script execution
private static void RunShellCommandFromJava(String command,String fn, String arg1,String arg2) throws Exception
{
try
{
System.out.println(System.getProperty("user.name"));
ProcessBuilder pbuilder = new ProcessBuilder("/bin/bash",command,fn,arg1,arg2);
System.out.println(pbuilder.command());
pbuilder.redirectErrorStream(true);
Process p = pbuilder.start();
p.waitFor();
}
catch(Exception ie)
{
throw ie;
}
}
The command which needs to be executed
"/bin/bash /abs/path/to/script.sh /abs/path/to/doc/in/data-folder maxpages=30 maxsearches=3"
PS : I have followed this question but it didn't help. I also tried other options like Runtime.exec(), bash,/bin/bash/ and /bin/bash/ -c, some of them don't work at all, others give no results.

Try to use Runtime and check standard error to find out what was the problem (probably permissions or paths):
// run command
String[] fixCmd = new String[] { "/bin/bash", "/abs/path/to/script.sh", "/abs/path/to/doc/in/data-folder", "maxpages=30", "maxsearches=3" };
Process start = Runtime.getRuntime().exec(fixCmd);
// monitor standard error to find out what's wrong
BufferedReader r = new BufferedReader(new InputStreamReader(start.getErrorStream()));
String line = null;
while ((line = r.readLine()) != null) {
System.out.println(line);
}

Related

Need to run .jar from console for it to work

I have a java application.
I'm using eclipse to write, compile and create a runnable .jar.
The program is used to discover OCF devices.
It uses UDP and multicast.
Multicast code
public static void sendMulticast(byte[] data) throws Exception{
DatagramPacket pack = new DatagramPacket(data, data.length, mgroup, mport);
msocket.send(pack);
}
public static byte[] recieveMulticast(int timeout) throws Exception{
DatagramPacket packet;
byte[] data = new byte[AppConfig.ocf_buffer_size];
packet = new DatagramPacket(data, data.length);
msocket.setSoTimeout(timeout);
msocket.receive(packet);
return data;
}
The code works when I start it from eclipse. It also works when I run the .jar from console on Linux.
But when I start it with a double click, it doesn't work.
When started from console, it finds my test device in less then a second. When started with a double click it doesn't find it ever.
I haven't tested it on Windows yet, but the problem remains on Linux all the same.
What is the difference when you start .jar from console or by double clicking?
Why is it effecting messages on multicast?
I'm using "Package required libraries into generated JAR".
I'm using java 1.7 in eclipse, and 1.8 on Linux, maybe thats the problem? But why does running it from console work?
I would understand if I used sudo, but I didn't.
When you are running any jar from console, Console/Terminal knows which program responsible to run the any jar i.e
java -jar example.jar
but when double-clicking environment, OS/GUI manager doesn't know default responsible program to run the jar. ( Same way when you try to open some unknown extension file, Operating system will ask you open with which program/application)
To make Java open .jar files per default (i.e. double click) right click on any .jar file to select Properties. In the following window select the "Open With" tab to see e.g. the follwing choice:
The problem was in current location, system property
user.dir
This is the first function I call in my main. It doesn't work from eclipse, so I'll put an argument for disabling it (it will be disabled only during development).
static void setCurrentDir() throws URISyntaxException{
String s;
s = ESP8266_Configurator.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
s = s.substring(0, s.lastIndexOf('/'));
System.setProperty("user.dir",s);
}
I hope this helps someone. Code should be exported with extracted libraries, not packaged, otherwise it doesn't work.

Using ProcessBuilder to execute commands that require comand line input

I was knocking up a app to try and help with my build process and was trying in include a git pull origin command. I've tried and tested all kinds of methods, but can't seem to get any input or output to work with that command.
The program waits on Process.waitFor() with no input or output.
I'm assuming the git pull command is waiting for me to input a username and password, but so far I've failed to establish how to achieve that.
There are numerous questions on SO coverings these kinds of examples, but none of the answers appear to be working for my use case.
The simplest code that I believe should work is:
class CmdTest {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "git pull origin");
pb.redirectErrorStream(true);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = pb.start();
process.waitFor();
}
}
Replacing the git pull origin with a dir will provide output as expected.
Doing just git pull origin without the credentials configured by default, git will wait for them at any important action. In your code, you don't provide (neither look) for git feedback, so the application get stuck at this stage.
Configuring the default credentials for git into your .gitconfig file, any git command will use them and the console won't be stuck (neither your application).

Get working directory of another Java process

I can get working directory of current Java program using this code:
Path path = Paths.get(*ClassName*.class.getProtectionDomain().getCodeSource().getLocation().toURI());
Also I can get CommandLine parameters (but there is no directory in the output) of running Java processes using this command wmic process get CommandLine where name='java.exe' /value
It is possible to get working directory of another Java process (better programmatically)? Probably it can be solved with some jdk/bin utilities?
You can get this information via the Attach API. To use it, you have to add the tools.jar of your jdk to your class path. Then, the following code will print the current working directories of all recognized JVM processes:
for(VirtualMachineDescriptor d: VirtualMachine.list()) {
System.out.println(d.id()+"\t"+d.displayName());
try {
VirtualMachine vm = VirtualMachine.attach(d);
try(Closeable c = vm::detach) {
System.out.println("\tcurrent dir: "+vm.getSystemProperties().get("user.dir"));
}
}
catch(AttachNotSupportedException|IOException ex) {
System.out.println("\t"+ex);
}
}

Access denied when trying to execute a .exe in %AppData%

I'm trying to use RemoveDrive.exe, found here, in my Java application. I have it in my JAR, and I'm extracting it to a temporary file using the following code, however when I try to run it I get an IOException which says CreateProcess error=5, Access is denied. The program doesn't normally need admin priviledges though. Any ideas on what could be causing the issue?
File RDexe = File.createTempFile("rmvd", ".exe");
InputStream exesrc = (InputStream) GraphicUI.class.getResource("RemoveDrive.exe").openStream();
FileOutputStream out = new FileOutputStream(RDexe);
byte[] temp = new byte[1024];
int rc;
while((rc = exesrc.read(temp)) > 0)
out.write(temp, 0, rc);
exesrc.close();
out.close();
RDexe.deleteOnExit();
// run executable
Runtime runtime = Runtime.getRuntime();
System.out.println(RDexe.getPath() + " " + "F:\\" + " -b -s");
Process proc = runtime.exec(RDexe.getPath() + " " + "F:\\" + " -b");
InputStream is = proc.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line; boolean ejected = false;
while((line = reader.readLine()) != null)
if(line.equalsIgnoreCase("failed")) ejected = false;
else if(line.equalsIgnoreCase("success")) ejected = true;
reader.close();
is.close();
UPDATE: If I enable the built-in Administrator account (net user administrator /active:yes), everything works fine from there. However if I right click and run as administrator in my standard account, I still get the error and UAC doesn't even ask for permission.
EDIT: Seeing as though the bounty is nearly finished, please see my SuperUser question which has helped me solve this problem... I'll be awarding the bounty and accepting an answer soon.
This may not be the problem in your situation, but some anti-virus programs will prevent executables or scripts inside temporary folders from being run. Instead of creating a temporary file, try putting it in the user directory:
File rdExe = new File(System.getProperty("user.home") + "/.yourProgramName/rmvd.exe");
rdExe.getParentFile().mkdirs();
just a heads up on another way to run files, have you thought of using the java Desktop object? : http://docs.oracle.com/javase/6/docs/api/java/awt/Desktop.html
i've found it useful when needing to run programs through my java program. something like this could work for you:
Desktop.getDesktop().open(new File("enter path and name of the file"));
hope you find it useful
I am not JAVA user but isn't it 32 vs. 64 bit issue ?
On 64 bit Windows error code 5 usually means that executable is not 64 bit compatible. Sometimes this is the case even when executable need to access only some (older win) system directory which does not exist anymore. To prove this try to use your executable in command line. if you can manage to get it work there than it is different issue. If not find executable for your OS.
Another possibility is that the file has to be physically present on some drive.
You wrote that you has it as temporary. Not shore what it means for JAVA. If it only copy it to some file and delete after use than its OK but if it is only in memory somewhere than that could be problem if executable need access to itself. To prove this just copy the file to some known location and then run it from there (in JAVA). if it works than you will need to do something about it (copy and delete executable from JAVA before and after execution to physical disk medium or whatever)
Another possibility is that error code 5 comes from JAVA environment an not from OS
In that case I have not a clue what it means (not JAVA user)
Seeing as though it has only been touched on here, I will say that the issue was related to permissions in Windows, and is not anything to do with Java.
As stated in the SuperUser question I've linked to in my original question, I found that my usual account did not have ownership of that folder for some unknown reason - so nothing could be executed; it wasn't just the temporary file I had created in Java.
Even though I am an administrator, in order to take ownership of the folder I had to enable the Built-In administrator account and grant myself ownership. Since I did that, it has all worked as expected.
Thanks to all for their efforts, I will award the bounty to the answer that was most detailed and put me on the right tracks.
What version of Windows are you running? Microsoft significantly tightened the restrictions around executing programs in Windows 7. My guess is that it the OS won't allow you to fork something that wasn't authenticated at the time your program was launched. I'd try running it on Windows 2000 or XP and see if you have the same issues.

How to run a Mac application From Java?

I tried the code below to run a stand-alone utility app I created from Apple script but, I get a No File or Directory Exists error.
I put identical copies (for testing) in the project, dist, parent directories but, it didn't help.
So, my questions are:
Is my call to run the app bad (perhaps because it's not a Windows exe)?
How to run a mac app from java?
Thanks
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Runtime r=Runtime.getRuntime();
Process p=null;
String s="MyLineInInput.app";
try {
p = r.exec(s);
} catch (IOException ex) {
Logger.getLogger(AudioSwitcherView.class.getName()).log(Level.SEVERE, null, ex);
}
}
A Mac App Bunde is not an executable file, it's a folder with a special structure. It can be opened using the open command, passing the App Bundle path as an argument: open MyLineInInput.app.
EDIT:
Even better would be using Desktop.getDesktop().open(new File("MyLineInInput.app"));
I used the Runtime.getRuntime().exec() method with the open command mentioned in the selected answer. I didn't use Desktop.getDesktop().open() since it unwantedly opened a terminal in my case and I didn't want to create an extra File object.
Process process = Runtime.getRuntime().exec("open /System/Applications/Books.app");
Reason for adding '/System':
It seems we need to use the /System prefix for System apps. For user-installed apps, that's not required, and it can be like /Applications/Appium.app.
To answer #Pantelis Sopasakis' issue that I also faced initially -
I get the error message: java.lang.IllegalArgumentException: The file: >/Applications/Microsoft Office 2011/Microsoft\ Excel.app doesn't exist.
In this case, it could be simply due to not escaping the space characters in the path.
Environment: JDK 11 Zulu - macOS Monterey 12.2.1 - M1 Silicon

Categories