Handle hostnames with upper-case letters
[webmin.git] / time / time-lib.pl
1 #!/usr/local/bin/perl
2
3 BEGIN { push(@INC, ".."); };
4 use WebminCore;
5 &init_config();
6 %access = &get_module_acl();
7 $cron_cmd = "$module_config_directory/sync.pl";
8 if ($config{'zone_style'}) {
9         do "$config{'zone_style'}-lib.pl";
10         }
11 &foreign_require("webmincron");
12
13 sub find_cron_job
14 {
15 &foreign_require("cron", "cron-lib.pl");
16 local @jobs = &cron::list_cron_jobs();
17 local ($job) = grep { $_->{'command'} eq $cron_cmd &&
18                       $_->{'user'} eq 'root' } @jobs;
19 return $job;
20 }
21
22 sub find_webmin_cron_job
23 {
24 return &webmincron::find_webmin_cron($module_name, 'sync_time_cron');
25 }
26
27 # sync_time(server, hardware-too)
28 # Syncs the system and maybe hardware time with some server. Returns undef
29 # on success, or an error message on failure.
30 sub sync_time
31 {
32 local @servs = split(/\s+/, $_[0]);
33 local $servs = join(" ", map { quotemeta($_) } @servs);
34 local $out = &backquote_logged("ntpdate -u $servs 2>&1");
35 if ($? && $config{'ntp_only'}) {
36         # error using ntp, but nothing else is allowed
37         return &text('error_entp', "<tt>$out</tt>");
38         }
39 elsif ($?) {
40         # error using ntp. use timeservice
41         local ($err, $serv);
42         foreach $serv (@servs) {
43                 $err = undef;
44                 &open_socket($serv, 37, SOCK, \$err);
45                 read(SOCK, $rawtime, 4);
46                 close(SOCK);
47                 last if (!$err && $rawtime);
48                 }
49         return $err if ($err);
50
51         # Got a time .. set it
52         $rawtime = unpack("N", $rawtime);
53         $rawtime -= (17 * 366 + 53 * 365) * 24 * 60 * 60;
54         local $diff = abs(time() - $rawtime);
55         if ($diff > 365*24*60*60) {
56                 # Too big!
57                 return &text('error_ediff', int($diff/(24*60*60)));
58                 } 
59         @tm = localtime($rawtime);
60         &set_system_time(@tm);
61         }
62 else {
63         $rawtime = time();
64         }
65
66 if ($_[1]) {
67         # Set hardware clock time to match system time (which is now correct)
68         local $flags = &get_hwclock_flags();
69         local $out = &backquote_logged("hwclock $flags --systohc");
70         return $? ? $out : undef;
71         }
72
73 return undef;
74 }
75
76 # sync_time_cron()
77 # Called from webmin cron to sync from the configured server
78 sub sync_time_cron
79 {
80 my $err = &sync_time($config{'timeserver'}, $config{'timeserver_hardware'});
81 print STDERR $err;
82 }
83
84 sub has_timezone
85 {
86 return 0 if (!defined(&list_timezones));
87 if (defined(&os_has_timezones)) {
88         return &os_has_timezones();
89         }
90 else {
91         local @zones = &list_timezones();
92         return @zones ? 1 : 0;
93         }
94 }
95
96 # find_same_zone(file)
97 # Finds an identical timezone file to the one specified
98 sub find_same_zone
99 {
100 local @st = stat(&translate_filename($_[0]));
101 local $z;
102 foreach $z (&list_timezones()) {
103         local $zf = &translate_filename("$timezones_dir/$z->[0]");
104         local @zst = stat($zf);
105         if ($zst[7] == $st[7]) {
106                 local $ex = system("diff ".&translate_filename($currentzone_link)." $zf >/dev/null 2>&1");
107                 if (!$ex) {
108                         return $z->[0];
109                         }
110                 }
111         }
112 return undef;
113 }
114
115 # get_hwclock_flags()
116 # Returns command-line flags for hwclock
117 sub get_hwclock_flags
118 {
119 if ($config{'hwclock_flags'} eq "sysconfig") {
120         local %clock;
121         &read_env_file("/etc/sysconfig/clock", \%clock);
122         return $clock{'CLOCKFLAGS'};
123         }
124 else {
125         return $config{'hwclock_flags'};
126         }
127 }
128
129 # get_hardware_time()
130 # Returns the current hardware time, in localtime format. On failure returns
131 # an empty array, and sets the global $get_hardware_time_error
132 sub get_hardware_time
133 {
134 local $flags = &get_hwclock_flags();
135 $get_hardware_time_error = undef;
136 local $out = `hwclock $flags`;
137 if ($out =~ /^(\S+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)\s+/) {
138         return ($6, $5, $4, $3, &month_to_number($2), $7-1900, &weekday_to_number($1));
139         }
140 elsif ($out =~ /^(\S+)\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(am|pm)\s+/i) {
141         return ($7, $6, $5+($8 eq 'pm' ? 12 : 0), $2, &month_to_number($3), $4-1900, &weekday_to_number($1));
142         }
143 else {
144         $get_hardware_time_error = &text('index_ehwclock',
145                         "<tt>".&html_escape("hwclock $flags")."</tt>",
146                         "<pre>".&html_escape($out)."</pre>");
147         return ( );
148         }
149 }
150
151 # get_system_time()
152 # Returns the current time, in localtime format
153 sub get_system_time
154 {
155 return localtime(time());
156 }
157
158 # set_hardware_time(secs, mins, hours, day, month, year)
159 sub set_hardware_time
160 {
161 local ($second, $minute, $hour, $date, $month, $year) = @_;
162 $month++;
163 $year += 1900;
164 local $format = "--set --date=".
165                 quotemeta("$month/$date/$year $hour:$minute:$second");
166 local $flags = &get_hwclock_flags();
167 local $out = &backquote_logged("hwclock $flags $format 2>&1");
168 return $? ? $out : undef;
169 }
170
171 # set_system_time(secs, mins, hours, day, month, year)
172 sub set_system_time
173 {
174 local ($second, $minute, $hour, $date, $month, $year) = @_;
175 $second = &zeropad($second, 2);
176 $minute = &zeropad($minute, 2);
177 $hour = &zeropad($hour, 2);
178 $date = &zeropad($date, 2);
179 $month = &zeropad($month+1, 2);
180 $year = &zeropad($year+1900, 4);
181 local $format;
182 if ($config{'seconds'} == 2) {
183         $format = $year.$month.$date.$hour.$minute.".".$second;
184         }
185 elsif ($config{'seconds'} == 1) {
186         $format = $month.$date.$hour.$minute.$year.".".$second;
187         }
188 else {
189         $format = $month.$date.$hour.$minute.substr($year, -2);
190         }
191 local $out = &backquote_logged("echo yes | date ".quotemeta($format)." 2>&1");
192 if ($gconfig{'os_type'} eq 'freebsd' || $gconfig{'os_type'} eq 'netbsd') {
193         return int($?/256) == 1 ? $out : undef;
194         }
195 else {
196         return $? ? $out : undef;
197         }
198 }
199
200 sub zeropad
201 {
202 local ($str, $len) = @_;
203 while(length($str) < $len) {
204         $str = "0".$str;
205         }
206 return $str;
207 }
208
209 @weekday_names = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
210
211 # weekday_to_number(day)
212 # Converts a day like Mon to a number like 1
213 sub weekday_to_number
214 {
215 for($i=0; $i<@weekday_names; $i++) {
216         return $i if (lc(substr($weekday_names[$i], 0, 3)) eq lc($_[0]));
217         }
218 return undef;
219 }
220
221 sub number_to_weekday
222 {
223 return ucfirst($weekday_names[$_[0]]);
224 }
225
226 # Returns 1 if this system supports setting the hardware clock.
227 sub support_hwtime
228 {
229 if ($config{'hwtime'} == 1) {
230         return 1;
231         }
232 elsif ($config{'hwtime'} == 0) {
233         return 0;
234         }
235 else {
236         return &has_command("hwclock") &&
237                !&running_in_xen() && !&running_in_vserver() &&
238                !&running_in_openvz() && !&running_in_zone();
239         }
240 }
241
242 1;
243