2012-05-07 23:06:55 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 - 2012 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <assert.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <stdlib.h>
# include <signal.h>
# include <stdio.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <stdarg.h>
# include <ctype.h>
# include <sys/prctl.h>
# include <sys/time.h>
# include <linux/rtc.h>
# include "macro.h"
# include "util.h"
# include "log.h"
# include "strv.h"
2014-05-22 16:21:38 +04:00
# include "clock-util.h"
2013-02-14 15:26:13 +04:00
# include "fileio.h"
2012-05-07 23:06:55 +04:00
2014-05-24 06:26:33 +04:00
int clock_get_hwclock ( struct tm * tm ) {
2013-11-19 04:12:03 +04:00
_cleanup_close_ int fd = - 1 ;
2012-05-07 23:06:55 +04:00
assert ( tm ) ;
2013-04-25 04:02:40 +04:00
fd = open ( " /dev/rtc " , O_RDONLY | O_CLOEXEC ) ;
2012-05-07 23:06:55 +04:00
if ( fd < 0 )
return - errno ;
/* This leaves the timezone fields of struct tm
* uninitialized ! */
if ( ioctl ( fd , RTC_RD_TIME , tm ) < 0 )
2013-11-19 04:12:03 +04:00
return - errno ;
2012-05-07 23:06:55 +04:00
/* We don't know daylight saving, so we reset this in order not
2013-10-31 05:26:07 +04:00
* to confuse mktime ( ) . */
2012-05-07 23:06:55 +04:00
tm - > tm_isdst = - 1 ;
2013-11-19 04:12:03 +04:00
return 0 ;
2012-05-07 23:06:55 +04:00
}
2014-05-24 06:26:33 +04:00
int clock_set_hwclock ( const struct tm * tm ) {
2013-11-19 04:12:03 +04:00
_cleanup_close_ int fd = - 1 ;
2012-05-07 23:06:55 +04:00
assert ( tm ) ;
2013-04-25 04:02:40 +04:00
fd = open ( " /dev/rtc " , O_RDONLY | O_CLOEXEC ) ;
2012-05-07 23:06:55 +04:00
if ( fd < 0 )
return - errno ;
if ( ioctl ( fd , RTC_SET_TIME , tm ) < 0 )
2013-11-19 04:12:03 +04:00
return - errno ;
2012-05-07 23:06:55 +04:00
2013-11-19 04:12:03 +04:00
return 0 ;
2012-05-07 23:06:55 +04:00
}
2012-09-17 19:42:13 +04:00
2014-05-22 16:21:38 +04:00
int clock_is_localtime ( void ) {
2013-04-18 11:11:22 +04:00
_cleanup_fclose_ FILE * f ;
2012-05-07 23:06:55 +04:00
/*
* The third line of adjtime is " UTC " or " LOCAL " or nothing .
* # / etc / adjtime
* 0.0 0 0
* 0
* UTC
*/
f = fopen ( " /etc/adjtime " , " re " ) ;
if ( f ) {
char line [ LINE_MAX ] ;
bool b ;
b = fgets ( line , sizeof ( line ) , f ) & &
fgets ( line , sizeof ( line ) , f ) & &
fgets ( line , sizeof ( line ) , f ) ;
if ( ! b )
return - EIO ;
truncate_nl ( line ) ;
2013-04-12 03:02:37 +04:00
return streq ( line , " LOCAL " ) ;
2012-05-07 23:06:55 +04:00
2013-04-12 02:57:42 +04:00
} else if ( errno ! = ENOENT )
2012-05-07 23:06:55 +04:00
return - errno ;
2013-04-12 03:02:37 +04:00
return 0 ;
2012-05-07 23:06:55 +04:00
}
2014-05-22 16:21:38 +04:00
int clock_set_timezone ( int * min ) {
2012-05-07 23:06:55 +04:00
const struct timeval * tv_null = NULL ;
struct timespec ts ;
struct tm * tm ;
2012-10-27 18:23:32 +04:00
int minutesdelta ;
2012-05-07 23:06:55 +04:00
struct timezone tz ;
assert_se ( clock_gettime ( CLOCK_REALTIME , & ts ) = = 0 ) ;
assert_se ( tm = localtime ( & ts . tv_sec ) ) ;
2012-10-27 18:23:32 +04:00
minutesdelta = tm - > tm_gmtoff / 60 ;
2012-05-07 23:06:55 +04:00
2012-10-27 18:23:32 +04:00
tz . tz_minuteswest = - minutesdelta ;
2012-05-07 23:06:55 +04:00
tz . tz_dsttime = 0 ; /* DST_NONE*/
/*
* If the hardware clock does not run in UTC , but in local time :
* The very first time we set the kernel ' s timezone , it will warp
* the clock so that it runs in UTC instead of local time .
*/
if ( settimeofday ( tv_null , & tz ) < 0 )
return - errno ;
if ( min )
2012-10-27 18:23:32 +04:00
* min = minutesdelta ;
2012-05-07 23:06:55 +04:00
return 0 ;
}
2014-05-22 16:21:38 +04:00
int clock_reset_timezone ( void ) {
2012-05-07 23:06:55 +04:00
const struct timeval * tv_null = NULL ;
struct timezone tz ;
tz . tz_minuteswest = 0 ;
tz . tz_dsttime = 0 ; /* DST_NONE*/
2012-09-17 18:41:13 +04:00
/*
* The very first time we set the kernel ' s timezone , it will warp
* the clock . Do a dummy call here , so the time warping is sealed
2014-05-22 16:31:46 +04:00
* and we set only the timezone with the next call .
2012-09-17 18:41:13 +04:00
*/
2012-05-07 23:06:55 +04:00
if ( settimeofday ( tv_null , & tz ) < 0 )
return - errno ;
return 0 ;
}