time: remove unnecessary global variable
[platform/core/system/system-server.git] / src / time / time-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdio.h>
21 #include <tzplatform_config.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <vconf.h>
28 #include <time.h>
29 #include <sys/ioctl.h>
30 #include <linux/rtc.h>
31 #include <fcntl.h>
32 #include <sys/timerfd.h>
33
34 #include "core/data.h"
35 #include "core/queue.h"
36 #include "core/log.h"
37 #include "core/devices.h"
38 #include "display/poll.h"
39
40
41 #define PREDEF_SET_DATETIME             "set_datetime"
42 #define PREDEF_SET_TIMEZONE             "set_timezone"
43
44 #ifndef TFD_TIMER_CANCELON_SET
45 #define TFD_TIMER_CANCELON_SET (1<<1)
46 #endif
47 #ifndef O_CLOEXEC
48 #define O_CLOEXEC       0x2000000
49 #endif
50
51 #ifndef O_NONBLOCK
52 #define O_NONBLOCK      0x4000
53 #endif
54
55 #ifndef TFD_CLOEXEC
56 #define TFD_CLOEXEC     O_CLOEXEC
57 #endif
58
59 #ifndef TFD_NONBLOCK
60 #define TFD_NONBLOCK    O_NONBLOCK
61 #endif
62 static const char default_rtc0[] = "/dev/rtc0";
63 static const char default_rtc1[] = "/dev/rtc1";
64
65 static const time_t default_time = 2147483645; // max(32bit) -3sec
66 static Ecore_Fd_Handler *tfdh = NULL; // tfd change noti
67
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);
71
72 char *substring(const char *str, size_t begin, size_t len)
73 {
74         if (str == 0 || strlen(str) == 0 || strlen(str) < begin
75             || strlen(str) < (begin + len))
76                 return 0;
77
78         return strndup(str + begin, len);
79 }
80
81 int handle_timezone(char *str)
82 {
83         int ret;
84         struct stat sts;
85         time_t now;
86         struct tm *ts;
87         const char *sympath, *tzpath;
88
89         if (str == NULL)
90                 return -1;
91
92         tzpath = str;
93         sympath = tzplatform_mkpath(TZ_SYS_ETC, "localtime");
94
95         _D("TZPATH = %s\n", tzpath);
96
97         if (stat(tzpath, &sts) == -1 && errno == ENOENT) {
98                 _E("invalid tzpath(%s)", tzpath);
99                 return -EINVAL;
100         }
101
102         /* FIXME for debugging purpose */
103         time(&now);
104         ts = localtime(&now);
105         _D("cur local time is %s", asctime(ts));
106
107         /* unlink current link
108          * eg. rm /opt/etc/localtime */
109         if (stat(sympath, &sts) == -1 && errno == ENOENT) {
110                 /* DO NOTHING */
111         } else {
112                 ret = unlink(sympath);
113                 if (ret < 0) {
114                         _D("unlink error : [%d]%s\n", ret,
115                                   strerror(errno));
116                         return -1;
117                 } else
118                         _D("unlink success\n");
119
120         }
121
122         /* symlink new link
123          * eg. ln -s /usr/share/zoneinfo/Asia/Seoul /opt/etc/localtime */
124         ret = symlink(tzpath, sympath);
125         if (ret < 0) {
126                 _D("symlink error : [%d]%s\n", ret, strerror(errno));
127                 return -1;
128         } else
129                 _D("symlink success\n");
130
131         tzset();
132
133         /* FIXME for debugging purpose */
134         ts = localtime(&now);
135         _D("new local time is %s", asctime(ts));
136         return 0;
137 }
138
139 /*
140  * TODO : error handling code should be added here.
141  */
142 int handle_date(char *str)
143 {
144         long int tmp = 0;
145         time_t timet = 0;
146         time_t before = 0;
147
148         if (str == NULL)
149                 return -1;
150
151         tmp = (long int)atoi(str);
152         timet = (time_t) tmp;
153
154         _D("ctime = %s", ctime(&timet));
155         vconf_set_int(VCONFKEY_SYSTEM_TIMECHANGE, timet);
156
157         return 0;
158 }
159
160 int set_datetime_action(int argc, char **argv)
161 {
162         int ret = 0;
163         unsigned int pm_state;
164         if (argc < 1)
165                 return -1;
166         if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
167                 _D("Fail to get vconf value for pm state\n");
168         if (ret == 1)
169                 pm_state = 0x1;
170         else if (ret == 2)
171                 pm_state = 0x2;
172         else
173                 pm_state = 0x4;
174
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);
178         return ret;
179 }
180
181 int set_timezone_action(int argc, char **argv)
182 {
183         int ret;
184         unsigned int pm_state;
185         if (argc < 1)
186                 return -1;
187         if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
188                 _D("Fail to get vconf value for pm state\n");
189         if (ret == 1)
190                 pm_state = 0x1;
191         else if (ret == 2)
192                 pm_state = 0x2;
193         else
194                 pm_state = 0x4;
195
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);
199         return ret;
200 }
201
202 static int timerfd_check_start(void)
203 {
204         int tfd;
205         struct itimerspec tmr;
206
207         if ((tfd = timerfd_create(CLOCK_REALTIME,TFD_NONBLOCK|TFD_CLOEXEC)) == -1) {
208                 _E("error timerfd_create() %d",errno);
209                 tfdh = NULL;
210                 return -1;
211         }
212
213         tfdh = ecore_main_fd_handler_add(tfd,ECORE_FD_READ,tfd_cb,NULL,NULL,NULL);
214         if (!tfdh) {
215                 _E("error ecore_main_fd_handler_add");
216                 return -1;
217         }
218         memset(&tmr, 0, sizeof(tmr));
219         tmr.it_value.tv_sec = default_time;
220
221         if (timerfd_settime(tfd,TFD_TIMER_ABSTIME|TFD_TIMER_CANCELON_SET,&tmr,NULL) < 0) {
222                 _E("error timerfd_settime() %d",errno);
223                 return -1;
224         }
225         return 0;
226 }
227
228 static int timerfd_check_stop(int tfd)
229 {
230         if (tfdh) {
231                 ecore_main_fd_handler_del(tfdh);
232                 tfdh = NULL;
233         }
234         if (tfd >=0) {
235                 close(tfd);
236                 tfd = -1;
237         }
238         return 0;
239 }
240
241 static Eina_Bool tfd_cb(void *data, Ecore_Fd_Handler * fd_handler)
242 {
243         int tfd = -1;
244         u_int64_t ticks;
245         int ret = -1;
246
247         if (!ecore_main_fd_handler_active_get(fd_handler,ECORE_FD_READ)) {
248                 _E("error ecore_main_fd_handler_get()");
249                 goto out;
250         }
251
252         if((tfd = ecore_main_fd_handler_fd_get(fd_handler)) == -1) {
253                 _E("error ecore_main_fd_handler_fd_get()");
254                 goto out;
255         }
256
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();
263         } else {
264                 _D("unexpected read (err:%d)",errno);
265         }
266 out:
267         return EINA_TRUE;
268 }
269
270 static void time_init(void *data)
271 {
272         action_entry_add_internal(PREDEF_SET_DATETIME, set_datetime_action,
273                                      NULL, NULL);
274         action_entry_add_internal(PREDEF_SET_TIMEZONE, set_timezone_action,
275                                      NULL, NULL);
276         if (timerfd_check_start() == -1) {
277                 _E("fail system time change detector init");
278                 return;
279         }
280 }
281
282 const struct device_ops time_device_ops = {
283         .init = time_init,
284 };