merge with master
[platform/core/system/system-server.git] / ss_timemgr.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdbool.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <pmapi.h>
25 #include <vconf.h>
26
27 #include <sysman.h>
28 #include "include/ss_data.h"
29 #include "ss_queue.h"
30 #include "ss_log.h"
31
32 #include <time.h>
33 #include <sys/ioctl.h>
34 #include <linux/rtc.h>
35 #include <fcntl.h>
36 #include <sys/timerfd.h>
37
38 #ifndef TFD_TIMER_CANCELON_SET
39 #define TFD_TIMER_CANCELON_SET (1<<1)
40 #endif
41 #ifndef O_CLOEXEC
42 #define O_CLOEXEC       0x2000000
43 #endif
44
45 #ifndef O_NONBLOCK
46 #define O_NONBLOCK      0x4000
47 #endif
48
49 #ifndef TFD_CLOEXEC
50 #define TFD_CLOEXEC     O_CLOEXEC
51 #endif
52
53 #ifndef TFD_NONBLOCK
54 #define TFD_NONBLOCK    O_NONBLOCK
55 #endif
56 static const char default_rtc0[] = "/dev/rtc0";
57 static const char default_rtc1[] = "/dev/rtc1";
58 static const char default_localtime[] = "/opt/etc/localtime";
59
60 static const time_t default_time = 2147483645; // max(32bit) -3sec
61 static Ecore_Fd_Handler *tfdh = NULL; // tfd change noti
62
63 static int tfd_cb(void *data, Ecore_Fd_Handler * fd_handler);
64 static int timerfd_check_stop(int fd);
65 static int timerfd_check_start(void);
66
67 char *substring(const char *str, size_t begin, size_t len)
68 {
69         if (str == 0 || strlen(str) == 0 || strlen(str) < begin
70             || strlen(str) < (begin + len))
71                 return 0;
72
73         return strndup(str + begin, len);
74 }
75
76 int handle_timezone(char *str)
77 {
78         int ret;
79         struct stat sts;
80         const char *sympath = default_localtime;
81
82         if (str == NULL)
83                 return -1;
84         const char *tzpath = str;
85
86         PRT_TRACE("TZPATH = %s\n", tzpath);
87
88         /* unlink current link
89          * eg. rm /opt/etc/localtime */
90         if (stat(sympath, &sts) == -1 && errno == ENOENT) {
91                 /* DO NOTHING */
92         } else {
93                 ret = unlink(sympath);
94                 if (ret < 0) {
95                         PRT_TRACE("unlink error : [%d]%s\n", ret,
96                                   strerror(errno));
97                         return -1;
98                 } else
99                         PRT_TRACE("unlink success\n");
100
101         }
102
103         /* symlink new link
104          * eg. ln -s /usr/share/zoneinfo/Asia/Seoul /opt/etc/localtime */
105         ret = symlink(tzpath, sympath);
106         if (ret < 0) {
107                 PRT_TRACE("symlink error : [%d]%s\n", ret, strerror(errno));
108                 return -1;
109         } else
110                 PRT_TRACE("symlink success\n");
111
112         tzset();
113         return 0;
114 }
115
116 /*
117  * TODO : error handling code should be added here.
118  */
119 int handle_date(char *str)
120 {
121         long int tmp = 0;
122         time_t timet = 0;
123         time_t before = 0;
124
125         if (str == NULL)
126                 return -1;
127
128         tmp = (long int)atoi(str);
129         timet = (time_t) tmp;
130
131         PRT_TRACE("ctime = %s", ctime(&timet));
132         vconf_set_int(VCONFKEY_SYSTEM_TIMECHANGE, timet);
133
134         return 0;
135 }
136
137 int set_datetime_action(int argc, char **argv)
138 {
139         int ret = 0;
140         unsigned int pm_state;
141         if (argc < 1)
142                 return -1;
143         if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
144                 PRT_TRACE("Fail to get vconf value for pm state\n");
145         if (ret == 1)
146                 pm_state = 0x1;
147         else if (ret == 2)
148                 pm_state = 0x2;
149         else
150                 pm_state = 0x4;
151
152         pm_lock_state(pm_state, STAY_CUR_STATE, 0);
153         ret = handle_date(argv[0]);
154         pm_unlock_state(pm_state, STAY_CUR_STATE);
155         return ret;
156 }
157
158 int set_timezone_action(int argc, char **argv)
159 {
160         int ret;
161         unsigned int pm_state;
162         if (argc < 1)
163                 return -1;
164         if (vconf_get_int(VCONFKEY_PM_STATE, &ret) != 0)
165                 PRT_TRACE("Fail to get vconf value for pm state\n");
166         if (ret == 1)
167                 pm_state = 0x1;
168         else if (ret == 2)
169                 pm_state = 0x2;
170         else
171                 pm_state = 0x4;
172
173         pm_lock_state(pm_state, STAY_CUR_STATE, 0);
174         ret = handle_timezone(argv[0]);
175         pm_unlock_state(pm_state, STAY_CUR_STATE);
176         return ret;
177 }
178
179 static int timerfd_check_start(void)
180 {
181         int tfd = -1;
182         struct itimerspec tmr;
183
184         if ((tfd = timerfd_create(CLOCK_REALTIME,TFD_NONBLOCK|TFD_CLOEXEC)) == -1) {
185                 PRT_TRACE_ERR("error timerfd_create() %d",errno);
186                 tfdh = NULL;
187                 return -1;
188         }
189
190         tfdh = ecore_main_fd_handler_add(tfd,ECORE_FD_READ,tfd_cb,NULL,NULL,NULL);
191         if (!tfdh) {
192                 PRT_TRACE_ERR("error ecore_main_fd_handler_add");
193                 return -1;
194         }
195         memset(&tmr, 0, sizeof(tmr));
196         tmr.it_value.tv_sec = default_time;
197
198         if (timerfd_settime(tfd,TFD_TIMER_ABSTIME|TFD_TIMER_CANCELON_SET,&tmr,NULL) < 0) {
199                 PRT_TRACE_ERR("error timerfd_settime() %d",errno);
200                 return -1;
201         }
202         return 0;
203 }
204
205 static int timerfd_check_stop(int tfd)
206 {
207         if (tfdh) {
208                 ecore_main_fd_handler_del(tfdh);
209                 tfdh = NULL;
210         }
211         if (tfd >=0) {
212                 close(tfd);
213                 tfd = -1;
214         }
215         return 0;
216 }
217
218 static int tfd_cb(void *data, Ecore_Fd_Handler * fd_handler)
219 {
220         int tfd = -1;
221         u_int64_t ticks;
222         int ret = -1;
223
224         if (!ecore_main_fd_handler_active_get(fd_handler,ECORE_FD_READ)) {
225                 PRT_TRACE_ERR("error ecore_main_fd_handler_get()");
226                 return -1;
227         }
228
229         if((tfd = ecore_main_fd_handler_fd_get(fd_handler)) == -1) {
230                 PRT_TRACE_ERR("error ecore_main_fd_handler_fd_get()");
231                 return -1;
232         }
233
234         ret = read(tfd,&ticks,sizeof(ticks));
235
236         if (ret < 0 && errno == ECANCELED) {
237                 vconf_set_int(VCONFKEY_SYSMAN_STIME, VCONFKEY_SYSMAN_STIME_CHANGED);
238                 timerfd_check_stop(tfd);
239                 PRT_TRACE("NOTIFICATION here");
240                 timerfd_check_start();
241         } else {
242                 PRT_TRACE("unexpected read (err:%d)",errno);
243         }
244         return 0;
245 }
246
247 int ss_time_manager_init(void)
248 {
249         ss_action_entry_add_internal(PREDEF_SET_DATETIME, set_datetime_action,
250                                      NULL, NULL);
251         ss_action_entry_add_internal(PREDEF_SET_TIMEZONE, set_timezone_action,
252                                      NULL, NULL);
253         if (timerfd_check_start() == -1) {
254                 PRT_TRACE_ERR("fail system time change detector init");
255                 return -1;
256         }
257         return 0;
258 }