4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include <tzplatform_config.h>
24 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <linux/rtc.h>
32 #include <sys/timerfd.h>
34 #include "core/data.h"
35 #include "core/queue.h"
37 #include "core/devices.h"
38 #include "display/poll.h"
41 #define PREDEF_SET_DATETIME "set_datetime"
42 #define PREDEF_SET_TIMEZONE "set_timezone"
44 #ifndef TFD_TIMER_CANCELON_SET
45 #define TFD_TIMER_CANCELON_SET (1<<1)
48 #define O_CLOEXEC 0x2000000
52 #define O_NONBLOCK 0x4000
56 #define TFD_CLOEXEC O_CLOEXEC
60 #define TFD_NONBLOCK O_NONBLOCK
62 static const char default_rtc0[] = "/dev/rtc0";
63 static const char default_rtc1[] = "/dev/rtc1";
65 static const time_t default_time = 2147483645; // max(32bit) -3sec
66 static Ecore_Fd_Handler *tfdh = NULL; // tfd change noti
68 static Eina_Bool tfd_cb(void *data, Ecore_Fd_Handler * fd_handler);
69 static int timerfd_check_stop(int fd);
70 static int timerfd_check_start(void);
72 char *substring(const char *str, size_t begin, size_t len)
74 if (str == 0 || strlen(str) == 0 || strlen(str) < begin
75 || strlen(str) < (begin + len))
78 return strndup(str + begin, len);
81 int handle_timezone(char *str)
87 const char *sympath, *tzpath;
93 sympath = tzplatform_mkpath(TZ_SYS_ETC, "localtime");
95 _D("TZPATH = %s\n", tzpath);
97 if (stat(tzpath, &sts) == -1 && errno == ENOENT) {
98 _E("invalid tzpath(%s)", tzpath);
102 /* FIXME for debugging purpose */
104 ts = localtime(&now);
105 _D("cur local time is %s", asctime(ts));
107 /* unlink current link
108 * eg. rm /opt/etc/localtime */
109 if (stat(sympath, &sts) == -1 && errno == ENOENT) {
112 ret = unlink(sympath);
114 _D("unlink error : [%d]%s\n", ret,
118 _D("unlink success\n");
123 * eg. ln -s /usr/share/zoneinfo/Asia/Seoul /opt/etc/localtime */
124 ret = symlink(tzpath, sympath);
126 _D("symlink error : [%d]%s\n", ret, strerror(errno));
129 _D("symlink success\n");
133 /* FIXME for debugging purpose */
134 ts = localtime(&now);
135 _D("new local time is %s", asctime(ts));
140 * TODO : error handling code should be added here.
142 int handle_date(char *str)
151 tmp = (long int)atoi(str);
152 timet = (time_t) tmp;
154 _D("ctime = %s", ctime(&timet));
155 vconf_set_int(VCONFKEY_SYSTEM_TIMECHANGE, timet);
160 int set_datetime_action(int argc, char **argv)
163 unsigned int pm_state;
166 if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
167 _D("Fail to get vconf value for pm state\n");
175 pm_lock_internal(getpid(), pm_state, STAY_CUR_STATE, 0);
176 ret = handle_date(argv[0]);
177 pm_unlock_internal(getpid(), pm_state, STAY_CUR_STATE);
181 int set_timezone_action(int argc, char **argv)
184 unsigned int pm_state;
187 if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
188 _D("Fail to get vconf value for pm state\n");
196 pm_lock_internal(getpid(), pm_state, STAY_CUR_STATE, 0);
197 ret = handle_timezone(argv[0]);
198 pm_unlock_internal(getpid(), pm_state, STAY_CUR_STATE);
202 static int timerfd_check_start(void)
205 struct itimerspec tmr;
207 if ((tfd = timerfd_create(CLOCK_REALTIME,TFD_NONBLOCK|TFD_CLOEXEC)) == -1) {
208 _E("error timerfd_create() %d",errno);
213 tfdh = ecore_main_fd_handler_add(tfd,ECORE_FD_READ,tfd_cb,NULL,NULL,NULL);
215 _E("error ecore_main_fd_handler_add");
218 memset(&tmr, 0, sizeof(tmr));
219 tmr.it_value.tv_sec = default_time;
221 if (timerfd_settime(tfd,TFD_TIMER_ABSTIME|TFD_TIMER_CANCELON_SET,&tmr,NULL) < 0) {
222 _E("error timerfd_settime() %d",errno);
228 static int timerfd_check_stop(int tfd)
231 ecore_main_fd_handler_del(tfdh);
241 static Eina_Bool tfd_cb(void *data, Ecore_Fd_Handler * fd_handler)
247 if (!ecore_main_fd_handler_active_get(fd_handler,ECORE_FD_READ)) {
248 _E("error ecore_main_fd_handler_get()");
252 if((tfd = ecore_main_fd_handler_fd_get(fd_handler)) == -1) {
253 _E("error ecore_main_fd_handler_fd_get()");
257 ret = read(tfd,&ticks,sizeof(ticks));
258 if (ret < 0 && errno == ECANCELED) {
259 vconf_set_int(VCONFKEY_SYSMAN_STIME, VCONFKEY_SYSMAN_STIME_CHANGED);
260 timerfd_check_stop(tfd);
261 _D("NOTIFICATION here");
262 timerfd_check_start();
264 _D("unexpected read (err:%d)",errno);
270 static void time_init(void *data)
272 action_entry_add_internal(PREDEF_SET_DATETIME, set_datetime_action,
274 action_entry_add_internal(PREDEF_SET_TIMEZONE, set_timezone_action,
276 if (timerfd_check_start() == -1) {
277 _E("fail system time change detector init");
282 const struct device_ops time_device_ops = {