How to detect if java is run from cron or through interactive shell.
I need to determine if the script is called by a user (show error message in sys.out) or cron(send error as email)
In your your crontab job you can pass an additional command line switch like -Dcron=true and that you can check inside your java code to branch out your logic.
Normally the stdout and stderr of any job run by cron is sent to the owner of the cronjob in email already.
If you want to handle that explicitly just add a command line option such as --cron that is passed to the cron job. Or more generally --email=bob#whatever which allows any invocation to send its output via email.
I would support -D solution as a most portable.
Still, if you need to implement a no-configuration solution, and you're OK to limit yourself to specific flavour of Unix (e.g. Linux), you may walk process tree to find if any of your parents are cron process:
Under Linux, read /proc/self/status:
cat /proc/self/status
Name: bash
State: S (sleeping)
Tgid: 9872
Pid: 9872
PPid: 9870
...
Then, according to PPid entry above, read /proc/9870/status, ... and continue until you reach PPid 1, which is init. If cron nowhere to be found, you're not under cron.
I also pretty sure somewhere under /proc/self you can find a direct specification what console/tty the process is running under (if none, than it must be a daemon, started by cron or not), but I couldn't find it right away.
Related
I want to re-direct the output of a command to a text file, and I want to run the command using ProcessBuilder (on Linux or Unix). I want the redirect to run asynchronously, and I want the Java process to store the pid of the redirect command, and kill the redirect process when the redirect is no longer required.
I see that ProcessBuilder.start() returns a Process object which has the method Proccess.pid(). I also see a method Process.waitFor() implying to me that the redirect command is inherently asynchronous when run via Process Builder.
So my question is, can I run a redirect command in an asynchronous process using ProcessBuilder, get the PID with Process, and kill the running redirect process down the line all by omitting Process.waitFor()? Is that entirely possible?
Thanks
Yes, the Process class has destroy() and destroyForcibly() methods to kill the running process. Starting in Java 9 the ProcessHandle class was added which also has methods of the same name.
If you have the pid but don't have the Process object, you can get a ProcessHandle for a running process given its pid using the ProcessHandle.of(long pid) method but if you started the Process yourself it is easier to just use the Process object that was returned from ProcessBuilder.start() or get the ProcessHandle from it using the Process.toHandle() method.
My goal is to perform git push programatically rather then from a console window.
To this aim I create a process like:
val processbuilder=new ProcessBuilder(List("git.exe","push","origin","master").asJava)
process=processbuilder.start()
Now, the problem is that git.exe seems to start an other process, to the output/error and input of which I have no access. I know this because if I run it without internet connection, it just prints a message on the error output and quits, as it should. However if I do the same with having an internet connection, it prints nothing on its standard output/error. Also I cannot destroy the process in that case ( see : http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4770092 ), which is an indication that authentication takes place in a separate process that is created by git.exe and to which I have no access.
I tried to get around this by starting cmd.exe as a process and issue git push as a command, but also in this case writing the password to cmd.exe's standard input has no effect.
The platform I'm using is Windows 10 + Scala sbt.
What is the way out of this?
Edit:
I'm trying to do this from a JavaFX based Scala application rather than from a console Scala program.
Edit2:
Using the sys api here does not solve the problem. If you try to perform the gith push through sys api call, then two things can happen:
If there is no internet connection, it will print an error message on the gui application's console window ( it has one, if you run it with sbt run ).
It there is an internet connection then it will print nothing and you cannot perform the authentication. The process simply detaches and becomes unreachable for you.
The point is that git.exe seems to start a subprocess and you have no access to this subprocess. This is problem is special to Windows to which I gave a link in the question. When you run git in the Windows console window then it takes care of the sub processes input and output for you. You are however not in the same position as the operation system to do this.
I came up with a poor man's solution. It will run in a system console window but at least it can be started from the gui app.
The mixture that finally works is this:
1) Create a Windows batch file ( call it "temp.bat" ) which contains the command:
git push origin master
2) Start cmd.exe as a process and to its standard input write the following line:
start temp.bat
This will open a console window and initiate the git push. The authentication will be handled properly, you are prompted for the password and can type it in the console window.
Other versions don't work. For example 'start git.exe' won't open a new console window.
You can use Scala sys.process API.
import sys.process._
val statusCode = "git push origin master" ! // one ! for the statusCode
Or:
val commandOutput "git push origin master" !! // two ! for getting the output
I have a Java application installed as Windows Service using Apache Common Daemon (windows server 2008).
I need to run excel.exe command within my application, so I set up my service in order to be capable of interacting with desktop (by checking the box in Logon tab on service's properties).
In this way, when I call start() method of ProcessBuilder the popups shown here appear to me.
Is there a way to avoid this?
My intention is to run my java app as service and run multiple instances of excel.exe in parallel in order to process several .xlsm files simultaneously, but I do not want to interact in any way.
I have already read this article about Session 0 Isolation, so I'm wondering if it is really possible to start many excel.exe (or any other "GUI command") from a Windows service on WinServer 2008?
Thank you.
This is the solution I've found until now (seems working at the moment)
Following zapl's suggestion I've made a .vbs in order to exec my macro directly using the script.
Then I've modified the user running excel to match with the one used to start the service (thanks to this)
After this I've changed my ProcessBuilder from this:
ProcessBuilder pb = new ProcessBuilder("cscript.exe", excelPathArg....)
to this:
ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "cscript.exe", excelPathArg....
Now, even if the user used to start the service is logged off ProcessBuilder seems to be triggered correctly.
I'll provide more details as soon as I'll dig more into it
I'm building a standalone application to run as a Linux (Ubuntu) daemon service, using Java. For that, I'm using the Java Service Wrapper lib.
During the execution of the service I'd like to be able to query for some status of the tasks executed by the application. In other words, I'd like to be able to print a custom message when I type on terminal:
service my-app status
Currently the message it prints is something like this:
My App is running: PID:1000, Wrapper:STARTED, Java:STARTED
I understand I need to use a more complex integration method (rather than the simplest one), but I couldn't find how to intercept the "status" call to print my own message.
How can I customize that message, using the Java Service Wrapper?
I got a half-solution. Inspecting the wrapper script code, as suggested by #Naytzyrhc, I found that the wrapper lib reads 3 files to create the status message:
bin/my-app.pid to print the PID of the running process;
bin/my-app.status to print the status of the wrapper itself;
bin/my-app.java.status to print the status of the wrapped application.
So, in the application code, to override the status message, just write the message in the my-app.java.status file.
There's only one gotcha: if the status message contains line breaks, the service my-app status doesn't print them, because it uses the echo command (as stated in this question Capturing multiple line output into a Bash variable). To solve this problem, just change the line from:
eval echo `gettext '$APP_LONG_NAME is running: PID:$pid, Wrapper:$STATUS, Java:$JAVASTATUS'`
to:
eval echo `gettext '$APP_LONG_NAME is running: PID:$pid, Wrapper:$STATUS, Java:"$JAVASTATUS"'`
(Using double quotes on $JAVASTATUS).
This is a half-solution because it doesn't fire an event to the running application, as I wanted. But it works for customizing the status message: it depends on the application how often the message is updated.
We are facing trouble restarting closing a running *.JAR file started with the "java -cp".
Killing java.exe worked fine.
But... isn't there any smoother way for the application? (It saves data on shut-down)
Also, how can one simulate any key input at the following message "Enter any key to continue..." with a batch file?
Thanks for all help!
The following set of batch scripts can be used to start/stop jars/any program
start-jar.bat
start "win_title" java -jar [jar file] [jar options]
this basically starts your jar(the program) in a window with title set to "win_title".
you could use another batch to kill the window started
stop-jar.bat
TASKKILL /FI "WINDOWTITLE eq win_title
Use the PAUSE [message] to wait for a key press:
PAUSE Hit any key to continue..
As for killing your app, there are JMX ways to do it - but I find an easy way to have a socket listening on a local port and then you can easily send a kill commnad to it and let your program handle the shutdown.
The excellent Java Service Wrapper will let you effortlessly install signal handlers for your Java app.
Have your app create a temp file on startup and periodically check if it still exists. Your batch script can just delete that file to terminate the app.
If you need to do some cleaning up before your process is shutdown, take a look at Shutdown Hooks.
from the Q&A in the link:
Okay, but won't I have to write a lot of code just to register a simple shutdown hook?
No. Simple shutdown hooks can often be written as anonymous inner classes, as in this example:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { database.close(); }
});