Remove initscripts and add PIDFile to service file
[platform/core/system/power-manager.git] / pm_poll.c
1 /*
2  * power-manager
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 */
17
18
19 /**
20  * @file        pm_poll.c
21  * @version     0.2
22  * @brief        Power Manager poll implementation (input devices & a domain socket file)
23  *
24  * This file includes the input device poll implementation.
25  * Default input devices are /dev/event0 and /dev/event1
26  * User can use "PM_INPUT" for setting another input device poll in an environment file (/etc/profile). 
27  * (ex: PM_INPUT=/dev/event0:/dev/event1:/dev/event5 )
28  */
29
30 #include <glib.h>
31 #include <stdio.h>
32 #include <poll.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41
42 #include "util.h"
43 #include "pm_core.h"
44 #include "pm_poll.h"
45
46 #define DEV_PATH_DLM    ":"
47
48 PMMsg recv_data;
49 int (*g_pm_callback) (int, PMMsg *);
50
51 #ifdef ENABLE_KEY_FILTER
52 extern int check_key_filter(int length, char buf[]);
53 #  define CHECK_KEY_FILTER(a, b) do {\
54                                                         if (check_key_filter(a, b) != 0)\
55                                                                 return TRUE;\
56                                                         } while (0);
57
58 #else
59 #  define CHECK_KEY_FILTER(a, b)
60 #endif
61
62 #define DEFAULT_DEV_PATH "/dev/event1:/dev/event0"
63
64 static GSource *src;
65 static GSourceFuncs *funcs;
66 static int sockfd;
67
68 static gboolean pm_check(GSource *src)
69 {
70         GSList *fd_list;
71         GPollFD *tmp;
72
73         fd_list = src->poll_fds;
74         do {
75                 tmp = (GPollFD *) fd_list->data;
76                 if ((tmp->revents & (POLLIN | POLLPRI)))
77                         return TRUE;
78                 fd_list = fd_list->next;
79         } while (fd_list);
80
81         return FALSE;
82 }
83
84 static gboolean pm_dispatch(GSource *src, GSourceFunc callback, gpointer data)
85 {
86         callback(data);
87         return TRUE;
88 }
89
90 static gboolean pm_prepare(GSource *src, gint *timeout)
91 {
92         return FALSE;
93 }
94
95 gboolean pm_handler(gpointer data)
96 {
97         char buf[1024];
98         struct sockaddr_un clientaddr;
99
100         GPollFD *gpollfd = (GPollFD *) data;
101         int ret;
102         int clilen = sizeof(clientaddr);
103
104         if (g_pm_callback == NULL) {
105                 return FALSE;
106         }
107         if (gpollfd->fd == sockfd) {
108                 ret =
109                     recvfrom(gpollfd->fd, &recv_data, sizeof(recv_data), 0,
110                              (struct sockaddr *)&clientaddr,
111                              (socklen_t *)&clilen);
112                 (*g_pm_callback) (PM_CONTROL_EVENT, &recv_data);
113         } else {
114                 ret = read(gpollfd->fd, buf, sizeof(buf));
115                 CHECK_KEY_FILTER(ret, buf);
116                 (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
117         }
118
119         return TRUE;
120 }
121
122 static GList *find_indev_list(char *path)
123 {
124         int i;
125         guint total = 0;
126         indev *tmp;
127
128         total = g_list_length(indev_list);
129
130         for (i = 0; i < total; i++) {
131                 tmp = (indev*) (g_list_nth(indev_list, i)->data);
132
133                 if (!strcmp(tmp->dev_path, path)) {
134                         LOGINFO("%s is already in dev list! gfd(%d)", path, tmp->dev_fd);
135                         return g_list_nth(indev_list, i);
136                 }
137         }
138
139         return NULL;
140 }
141
142 static int init_sock(char *sock_path)
143 {
144         struct sockaddr_un serveraddr;
145         int fd;
146
147         LOGINFO("initialize pm_socket for pm_control library");
148
149         if (sock_path == NULL || strcmp(sock_path, SOCK_PATH)) {
150                 LOGERR("invalid sock_path= %s");
151                 return -1;
152         }
153
154         fd = socket(AF_UNIX, SOCK_DGRAM, 0);
155         if (fd < 0) {
156                 LOGERR("socket error");
157                 return -1;
158         }
159
160         unlink(sock_path);
161
162         bzero(&serveraddr, sizeof(serveraddr));
163         serveraddr.sun_family = AF_UNIX;
164         strncpy(serveraddr.sun_path, sock_path, sizeof(serveraddr.sun_path) - 1);
165
166         if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
167                 LOGERR("bind error");
168                 close(fd);
169                 return -1;
170         }
171
172         if (chmod(sock_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)        /* 0777 */
173                 LOGERR("failed to change the socket permission");
174
175         if (!strcmp(sock_path, SOCK_PATH))
176                 sockfd = fd;
177
178         LOGINFO("init sock() sueccess!");
179         return fd;
180 }
181
182 int init_pm_poll(int (*pm_callback) (int, PMMsg *))
183 {
184
185         guint ret;
186         char *dev_paths, *path_tok, *pm_input_env, *save_ptr;
187         int dev_paths_size;
188
189         GPollFD *gpollfd;
190
191         g_pm_callback = pm_callback;
192
193         LOGINFO
194             ("initialize pm poll - input devices and domain socket(libpmapi)");
195
196         pm_input_env = getenv("PM_INPUT");
197         if ((pm_input_env != NULL) && (strlen(pm_input_env) < 1024)) {
198                 LOGINFO("Getting input device path from environment: %s",
199                        pm_input_env);
200                 /* Add 2 bytes for following strncat() */
201                 dev_paths_size =  strlen(pm_input_env) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
202                 dev_paths = (char *)malloc(dev_paths_size);
203                 snprintf(dev_paths, dev_paths_size, "%s", pm_input_env);
204         } else {
205                 /* Add 2 bytes for following strncat() */
206                 dev_paths_size = strlen(DEFAULT_DEV_PATH) + strlen(SOCK_PATH) + strlen(DEV_PATH_DLM) + 1;
207                 dev_paths = (char *)malloc(dev_paths_size);
208                 snprintf(dev_paths, dev_paths_size, "%s", DEFAULT_DEV_PATH);
209         }
210
211         /* add the UNIX domain socket file path */
212         strncat(dev_paths, DEV_PATH_DLM, strlen(DEV_PATH_DLM));
213         strncat(dev_paths, SOCK_PATH, strlen(SOCK_PATH));
214         dev_paths[dev_paths_size - 1] = '\0';
215
216         path_tok = strtok_r(dev_paths, DEV_PATH_DLM, &save_ptr);
217         if (path_tok == NULL) {
218                 LOGERR("Device Path Tokeninzing Failed");
219                 free(dev_paths);
220                 return -1;
221         }
222
223         funcs = (GSourceFuncs *) g_malloc(sizeof(GSourceFuncs));
224         funcs->prepare = pm_prepare;
225         funcs->check = pm_check;
226         funcs->dispatch = pm_dispatch;
227         funcs->finalize = NULL;
228
229         do {
230                 indev *adddev = NULL;
231                 char *path, *new_path;
232                 int len;
233
234                 src = g_source_new(funcs, sizeof(GSource));
235
236                 gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD));
237                 gpollfd->events = POLLIN;
238
239                 if (strcmp(path_tok, SOCK_PATH) == 0) {
240                         gpollfd->fd = init_sock(SOCK_PATH);
241                         path = SOCK_PATH;
242                         LOGINFO("pm_poll domain socket file: %s, fd: %d",
243                                path_tok, gpollfd->fd);
244                 } else {
245                         gpollfd->fd = open(path_tok, O_RDONLY);
246                         path = path_tok;
247                         LOGINFO("pm_poll input device file: %s, fd: %d",
248                                path_tok, gpollfd->fd);
249                 }
250
251                 if (gpollfd->fd == -1) {
252                         LOGERR("Cannot open the file: %s", path_tok);
253                         free(dev_paths);
254                         return -1;
255                 }
256
257                 len = strlen(path) + 1;
258                 new_path = (char *) malloc(len);
259                 if (!new_path) {
260                         LOGERR("Fail to alloc new path: %s", path_tok);
261                         free(dev_paths);
262                         return -1;
263                 }
264                 strncpy(new_path, path, len);
265
266                 adddev = (indev *) malloc(sizeof(indev));
267                 if (!adddev) {
268                         LOGERR("Fail to alloc indev: %s", path_tok);
269                         free(new_path);
270                         free(dev_paths);
271                         return -1;
272                 }
273                 adddev->dev_path = new_path;
274                 adddev->dev_src = src;
275                 adddev->dev_fd = gpollfd;
276
277                 indev_list = g_list_append(indev_list, adddev);
278                 LOGINFO("pm_poll for input dev file(path:%s, gsource:%d, gpollfd:%d",
279                             adddev->dev_path, adddev->dev_src, adddev->dev_fd);
280
281                 g_source_add_poll(src, gpollfd);
282                 g_source_set_callback(src, (GSourceFunc) pm_handler,
283                                       (gpointer) gpollfd, NULL);
284
285                 g_source_set_priority(src, G_PRIORITY_LOW);
286                 ret = g_source_attach(src, NULL);
287                 if (ret == 0) {
288                         LOGERR("Failed g_source_attach() in init_pm_poll()");
289                         free(dev_paths);
290                         return -1;
291                 }
292                 g_source_unref(src);
293
294         } while ((path_tok = strtok_r(NULL, DEV_PATH_DLM, &save_ptr)));
295
296         free(dev_paths);
297         return 0;
298 }
299
300 int exit_pm_poll()
301 {
302         g_free(funcs);
303         close(sockfd);
304         unlink(SOCK_PATH);
305         LOGINFO("pm_poll is finished");
306         return 0;
307 }
308
309 int init_pm_poll_input(int (*pm_callback)(int , PMMsg * ), const char *path)
310 {
311         guint ret;
312         indev *adddev = NULL;
313
314         g_pm_callback = pm_callback;
315
316         GPollFD *gpollfd;
317         const char *devpath;
318         GSource *devsrc;
319
320         LOGINFO("initialize pm poll for bt %s",path);
321
322         if(find_indev_list(path)) {
323                 LOGERR("%s is already in dev list!", path);
324                 return -1;
325         }
326
327         adddev=(indev *)malloc(sizeof(indev));
328         adddev->dev_fd = (GPollFD *)g_malloc(sizeof(GPollFD));
329         (adddev->dev_fd)->events = POLLIN;
330         (adddev->dev_fd)->fd = open(path, O_RDONLY);
331         if((adddev->dev_fd)->fd == -1) {
332                 LOGERR("Cannot open the file for BT: %s",path);
333                 g_free(adddev->dev_fd);
334                 free(adddev);
335                 return -1;
336         }
337         adddev->dev_path = (char *)malloc(strlen(path) + 1);
338         strncpy(adddev->dev_path, path, strlen(path) + 1);
339         adddev->dev_src = g_source_new(funcs, sizeof(GSource));
340         LOGINFO("pm_poll for BT input device file(path: %s, gsource: %d, gpollfd: %d", adddev->dev_path, adddev->dev_src, adddev->dev_fd);
341         indev_list=g_list_append(indev_list, adddev);
342         
343         g_source_add_poll(adddev->dev_src, adddev->dev_fd);
344         
345         g_source_set_callback(adddev->dev_src, (GSourceFunc) pm_handler, (gpointer)adddev->dev_fd, NULL);
346         
347
348         g_source_set_priority(adddev->dev_src, G_PRIORITY_LOW );
349         
350         ret = g_source_attach(adddev->dev_src, NULL);
351         if(ret == 0)
352         {
353                 LOGERR("Failed g_source_attach() in init_pm_poll()");
354                 return -1;
355         }
356         g_source_unref(adddev->dev_src);
357         return 0;
358 }