Problem in setting date and time from java code - java

I am trying to set the date and time of a linux system from a remote system using Java. In order to do that I have created a server to accept time from the remote system as:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Set_date_n_time {
public static void main(String[] args) throws IOException, InterruptedException {
// TODO Auto-generated method stub
String date_time = new String();
//#SuppressWarnings("resource")
ServerSocket s1 = new ServerSocket(7105);
System.out.println("server started");
while (true) {
Socket sckt = s1.accept();
InputStream input = sckt.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
date_time = reader.readLine();
String command="sudo date -s "+"\""+date_time+"\"";
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
System.out.println ("date set");
p.destroy();
} catch (Exception e) {}
}
}
}
and the remote system from which the time will be copied as:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Fix_my_Date {
public static void main(String args[]) throws IOException {
String addr_list=args[0];
String[] hostList = readAddressList(addr_list);
for(int i=0; i<hostList.length;i++) {
setDate(hostList[i]);
}
}
//#SuppressWarnings("resource")
private static void setDate(String address) throws IOException {
{
Scanner sc = new Scanner(System.in);
Socket s = null;
String date =new String();
String time = new String();
try {
s = new Socket(address, 7105);
System.out.println("connection to "+address+" done");
Process p, p1;
try {
p = Runtime.getRuntime().exec("date +%Y%m%d");
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
date = br.readLine();
br.close();
p.waitFor();
p.destroy();
p1 = Runtime.getRuntime().exec("date +%H:%M:%S");
BufferedReader br1 = new BufferedReader(
new InputStreamReader(p1.getInputStream()));
time = br1.readLine();
br1.close();
p1.waitFor();
p1.destroy();
PrintStream pr = new PrintStream(s.getOutputStream());
pr.print(date+" "+time+"");
sc.close();
s.close();
} catch (Exception e) {
System.out.println("Problem Setting date and time");
}
//s.close();
} catch (Exception e) {
System.out.println("Couldn't connect to: "+address+"");
sc.close();
//s.close();
}
}
return;
}
private static String[] readAddressList(String addr_list) throws IOException {
FileReader fileReader = new FileReader(addr_list);
BufferedReader bufferedReader = new BufferedReader(fileReader);
List<String> lines = new ArrayList<String>();
String line = null;
while ((line = bufferedReader.readLine()) != null)
{
lines.add(line);
}
bufferedReader.close();
System.out.println("Loaded the host list");
return lines.toArray(new String[lines.size()]);
}
}
But the time is not being set by the server code. Where is my mistake?

The mistake I, you, and lots of others make is also (besides the other helpful answers here) that you don't read Standard Output and Standard Error and if your command produces any output or error it blocks because there is no buffer that it can write to which you may observe with strace.
This could be fixed with an extra thread as described here: https://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
If you use sudo it might fail depending on the sudo settings if it doesn't allow sudo without a terminal (requiretty), see for more info e.g.: https://bugzilla.redhat.com/show_bug.cgi?id=1196451

Are you trying to set the time on a VM? If that's the case, it may be set to synchronise to the host which overwrites your date -s command.
I could not get it to work (yet) with Runtime.exec(), but it works perfectly with ProcessBuilder. Here it is:
package set_date_n_time;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Set_date_n_time {
public static void main(String[] args) throws IOException, InterruptedException {
// TODO Auto-generated method stub
String date_time = new String();
//#SuppressWarnings("resource")
ServerSocket s1 = new ServerSocket(7105);
System.out.println("server started");
while (true) {
Socket sckt = s1.accept();
InputStream input = sckt.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
date_time = reader.readLine();
ProcessBuilder builder = new ProcessBuilder("date", "--set=" + date_time + "");
final Process p = builder.start();
p.waitFor();
p.destroy();
}
}
}
Obviously you have to run as root and make sure you run
sudo systemctl stop systemd-timesyncd.service
or something similar to make sure the system does not override you date fixing.

In case you need, or prefer, to use Runtime.exec() then (don't ask me why) just change:
String command = "sudo date -s " + "\"" + date_time + "\"";
to
String[] command = new String[]{"sudo", "date", "-s", date_time};
in class Set_date_n_time.

Replace this:
} catch (Exception e) {}
With this:
} catch (Exception e) {
throw new IllegalStateException("Unexpected exception", e);
}
As Ole V.V. said, the empty catch-block in your code is almost certainly discarding real failures you care about. I would guess that either sudo is rejecting the call or the command itself is malformed. The exception will tell you exactly what is going wrong.
If you discover there are exceptions being thrown that you really do want to ignore, handle them separately, but you should almost never catch (Exception e) and throw away the exception.
It's also a good idea to use ProcessBuilder instead of Runtime.exec(). This is a more powerful and flexible API for interacting with sub-processes. In particular, never use Runtime.exec(String); although it works for simple commands it is not a shell, and will fail in surprising ways for commands with special characters, like quotes or whitespace.
For example:
p = new ProcessBuilder("sudo", "date", "-s", date_time).start();

Related

Calling readAllBytes on an InputStream of a process returns empty byte array

I'm trying to get the terminal width by executing tput cols command and parse the output.
public class Test {
public static void main(String[] args) throws IOException {
Process p = Runtime.getRuntime().exec("tput cols");
String output = new String(p.getInputStream().readAllBytes());
System.out.println(output);
}
}
But it outputs empty string.
However, if I executes it in the terminal I can see the output.
You need to wait for the command to terminate. When you read the output of the tput command, it has not yet terminated and therefore there is not yet any output.
I prefer using class ProcessBuilder rather than class Runtime.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class PrcBldTs {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("tput", "cols");
try {
Process p = pb.start();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
int result = p.waitFor();
System.out.println("result = " + result);
}
catch (Exception x) {
x.printStackTrace();
}
}
}

In Java, a small help to allow a program send commands to CMD.exe

I am trying to create a program (personal practice) to access CMD and type any command you want, as if you were working on cmd.exe;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class CMD_Live {
public static void main(String[] args) throws IOException {
// The purpose of this program is to use Java to perform CMD commands as if you are working on it live
Scanner ScanCMD = new Scanner(System.in);
while(true) {
System.out.print("Insert your Command> ");
String CMDcommand = ScanCMD.nextLine();
Process processToCMD = Runtime.getRuntime().exec(CMDcommand);
BufferedReader readerToCMD = new BufferedReader(new InputStreamReader(processToCMD.getInputStream()));
String line;
while ((line = readerToCMD.readLine()) != null) {
System.out.println(line);
}
System.out.println();
readerToCMD.close();
}
}
}
The problem with this code is, it works for straightforward commands,
like ping google.com, or nslookup google.com,
but if I insert nslookup and hit enter to access advance mode, then the response goes off.
Is there a way to fix it?
This should work for you:
ProcessBuilder processBuilder = new ProcessBuilder(CMDcommand); //note, that you can build your command here step by step.
Process process = processBuilder.start();
String response = null;
InputStream inputStream = process.getInputStream();
BufferedReader bufferedInputStream = new BufferedReader(new InputStreamReader(inputStream));
//and then do whatever you want to do.. my example is this:
while(response=bufferedInputStream.readLine()!=null) {
..some code..
}
} catch (IOException e) {
e.printStackTrace();
}

deleteOnExit not deleting file

I have created a few files for temporary use and used them as inputs for some methods. And I called
deleteOnExit()
on all files I created. But one file still remains.
I assume it is because the file is still in use, but doesn't the compiler go to next line only after the current line is done?(Single thread)
While its not a problem practically because of java overwrite, there is only one file always. I would like to understand why it happens and also if I can use
Thread.sleep(sometime);
Edit:-
File x = new file("x.txt");
new class1().method1();
After creating all files(5), I just added this line
x.deleteOnExit(); y.deletOnExit() and so on...
All the files except that last one is deleted.
Make sure that whatever streams are writing to the file are closed. If the stream is not closed, file will be locked and delete will return false. That was an issue I had. Hopefully that helps.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) {
File reportNew = null;
File writeToDir = null;
BufferedReader br = null;
BufferedWriter bw = null;
StringWriter sw = null;
List<File> fileList = new ArrayList<File>();
SimpleDateFormat ft = new SimpleDateFormat("yyyymmdd_hh_mm_ss_ms");
try {
//Read report.new file
reportNew = new File("c:\\temp\\report.new");
//Create temp directory for newly created files
writeToDir = new File("c:\\temp");
//tempDir.mkdir();
//Separate report.new into many files separated by a token
br = new BufferedReader(new FileReader(reportNew));
sw = new StringWriter();
new StringBuilder();
String line;
int fileCount = 0;
while (true) {
line=br.readLine();
if (line == null || line.contains("%PDF")) {
if (!sw.toString().isEmpty()) {
fileCount++;
File _file = new File(writeToDir.getPath()
+ File.separator
+ fileCount
+ "_"
+ ft.format(new Date())
+ ".htm");
_file.deleteOnExit();
fileList.add(_file);
bw = new BufferedWriter(new FileWriter(_file));
bw.write(sw.toString());
bw.flush();
bw.close();
sw.getBuffer().setLength(0);
System.out.println("File "
+ _file.getPath()
+ " exists "
+ _file.exists());
}
if (line == null)
break;
else
continue;
}
sw.write(line);
sw.write(System.getProperty("line.separator"));
}
} catch ( Exception e) {
e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
In order to close the file that you have opened in your program, try creating an explicit termination method.
Therefore, try writing the following:
public class ClassThatUsesFile {
private String filename;
private BufferReader reader;
public ClassThatUsesFile (String afile) {
this.filename = afile;
this.reader = new BufferReader(new FileReader(afile));
}
// try-finally block guarantees execution of termination method
protected void terminate() {
try {
// Do what must be done with your file before it needs to be closed.
} finally {
// Here is where your explicit termination method should be located.
// Close or delete your file and close or delete your buffer reader.
}
}
}

getting text from command-line into Java

I'm trying to parse some text that is generated by a command-line command. The command-line command I want to use is Ubuntu's landscape-sysinfo. In an attempt to run this, I'm using the following Java code:
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(new String[] { "landscape-sysinfo" });
The thing I'm not sure of is, how do I get the output of the command-line command into a string that I work with in my Java app?
Thank you so much for your valuable insights!
Hope this one helps its what the Apprentice Queue said
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class BatchExecuteService {
public static void main(String[] args) {
BatchExecuteService batchExecuteService = new BatchExecuteService();
batchExecuteService.run();
}
public void run() {
try {
String cmds[] = {"D:\\test.bat"};
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(cmds);
process.getOutputStream().close();
InputStream inputStream = process.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputStream);
BufferedReader bufferedrReader = new BufferedReader(inputstreamreader);
String strLine = "";
while ((strLine = bufferedrReader.readLine()) != null) {
System.out.println(strLine);
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
Reference

Cannot send commands using output stream

I am trying to write a small Java application that will let me run a Bukkit server off-screen using the Java Process/ProcessBuilder API.
I am able to get the output from the server fine, but the server doesn't respond to commands written by the output stream returned by Process.getOutputStream() (chained to the process input stream).
I tried doing this with my own test code, and it worked. The separate process reading from System.in received the text written to the output stream.
Does Bukkit not listen to System.in or something?
If not, how can that be?
Any ideas?
try {
ProcessBuilder pb = new ProcessBuilder();
File dir = new File("C:/Users/Brian/Desktop/MC-Server/Bukkit-Testing");
pb.directory(dir);
pb.command(new String[] {"java", "-Xincgc", "-Xmx1G", "-jar", "craftbukkit-1.0.1-R1.jar"});
pb.redirectErrorStream(true);
final Process p = pb.start();
InputStream out = p.getInputStream();
BufferedReader r1 = new BufferedReader(new InputStreamReader(out));
String s = null;
new Thread(new Runnable() {
#Override
public void run() {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
Scanner scan = new Scanner(System.in);
String input = null;
while((input=scan.nextLine()) != null) {
if(input.equals("exit")) {
p.destroy();
break;
}
try {
bw.write(input);
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
while((s=r1.readLine()) !=null)
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
I don't think Bukkit uses its System.in, so we have to make a workaround.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
public class ConsolePlugin extends JavaPlugin {
public Logger log;
public void onEnable(){
log = this.getLogger();
log.info("BufferedReader has been enabled!");
new Thread(new Runnable(){
public void run(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while (true){
try {
line=br.readLine();
} catch (Exception e) {e.printStackTrace();}
if (line!=null){
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), line);
System.out.println(line);
}
}
}
}).start();
}
public void onDisable(){
log.info("BufferedReader has been disabled.");
}
}
To send commands:
bw.write(input);
bw.nextLine();
bw.flush();

Categories