se7en
se7en

Reputation: 123

Problem in setting date and time from java code

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?

Upvotes: 2

Views: 608

Answers (4)

JohannesB
JohannesB

Reputation: 2298

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

Upvotes: 2

dimo414
dimo414

Reputation: 48834

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();

Upvotes: 1

Dan M
Dan M

Reputation: 4377

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.

Upvotes: 1

Dan M
Dan M

Reputation: 4377

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.

Upvotes: 1

Related Questions