tizen 2.3 release
[kernel/api/system-resource.git] / src / proc-stat / proc-noti.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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 /*
21  * @file proc_noti.c
22  * @desc It's main entry point for handling proc events
23  * @see proc_cgroup_cmd_type
24 */
25
26 #include <stdio.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/stat.h>
33 #include <sys/stat.h>
34 #include <sys/xattr.h>
35
36 #include <Ecore.h>
37
38 #include "macro.h"
39 #include "proc-main.h"
40 #include "proc-noti.h"
41 #include "proc-process.h"
42 #include "resourced.h"
43 #include "trace.h"
44
45 /*
46  * @desc function receives uint
47  * negative value for error reporting
48  */
49 static inline int recv_int(int fd)
50 {
51         int val, r = -1;
52         while (1) {
53                 r = read(fd, &val, sizeof(int));
54                 if (r >= 0)
55                         return val;
56
57                 if (errno == EINTR) {
58                         _E("Re-read for error(EINTR)");
59                         continue;
60                 } else {
61                         _E("Read fail for int");
62                         return -errno;
63                 }
64         }
65 }
66
67 static inline char *recv_str(int fd)
68 {
69         int len, r = -1;
70         char *str;
71
72         while (1) {
73                 r = read(fd, &len, sizeof(int));
74                 if (r < 0) {
75                         if (errno == EINTR) {
76                                 _E("Re-read for error(EINTR)");
77                                 continue;
78                         } else {
79                                 _E("Read fail for str length");
80                                 return NULL;
81                         }
82                 } else
83                         break;
84         }
85
86         if (len <= 0) {
87                 _D("str is null");
88                 return NULL;
89         }
90
91         if (len >= INT_MAX) {
92                 _E("size is over INT_MAX");
93                 return NULL;
94         }
95
96         str = (char *)malloc(len + 1);
97         if (str == NULL) {
98                 _E("Not enough memory");
99                 return NULL;
100         }
101
102         while (1) {
103                 r = read(fd, str, len);
104                 if (r < 0) {
105                         if (errno == EINTR) {
106                                 _E("Re-read for error(EINTR)");
107                                 continue;
108                         } else {
109                                 _E("Read fail for str");
110                                 free(str);
111                                 return NULL;
112                         }
113                 } else
114                         break;
115         }
116         str[len] = 0;
117
118         return str;
119 }
120
121 /*
122  * @desc This function read from fd to msg,
123  * it supports multiple argument list given from client
124  * of string type
125  * @return 0 on success errno constants in error case
126 */
127 static int read_message(int fd, struct resourced_noti *msg)
128 {
129         int i;
130
131         msg->pid = recv_int(fd);
132         ret_value_if(msg->pid < 0, errno);
133         msg->type = recv_int(fd);
134         ret_value_if(msg->type < 0, errno);
135         msg->path = recv_str(fd);
136         msg->argc = recv_int(fd);
137         ret_value_if(msg->argc < 0, errno);
138
139         for (i = 0; i < msg->argc; ++i)
140                 msg->argv[i] = recv_str(fd);
141
142         return 0;
143 }
144
145 static bool _fatal_read_message_error(const int error_code)
146 {
147         return error_code == EBADF || error_code == EISDIR;
148 }
149
150 static inline void internal_free(char *str)
151 {
152         if (str)
153                 free(str);
154 }
155
156 static inline void free_message(struct resourced_noti *msg)
157 {
158         int i;
159
160         internal_free(msg->path);
161
162         for (i = 0; i < msg->argc; i++)
163                 internal_free(msg->argv[i]);
164         free(msg);
165 }
166
167 static int process_message(struct resourced_noti *msg)
168 {
169         _D("process message caller pid %d\n", msg->pid);
170         return resourced_proc_action(msg->type, msg->argc, msg->argv);
171 }
172
173 static void safe_write_int(int fd, int type, int *value)
174 {
175         bool sync = SYNC_OPERATION(type);
176         int ret;
177         if (!sync) {
178                 _D("Response is not needed");
179                 return;
180         }
181
182         ret = write(fd, value, sizeof(int));
183         if (ret < 0)
184                 ETRACE_ERRNO_MSG("Failed to response to client, %d", *value);
185 }
186
187 static Eina_Bool proc_noti_cb(void *data, Ecore_Fd_Handler *fd_handler)
188 {
189         int fd;
190         struct resourced_noti *msg;
191         int ret = -1;
192         struct sockaddr_un client_address;
193         int client_sockfd;
194         int client_len;
195         int error_code;
196
197         if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
198                 _E("ecore_main_fd_handler_active_get error , return\n");
199                 return ECORE_CALLBACK_CANCEL;
200         }
201
202         fd = ecore_main_fd_handler_fd_get(fd_handler);
203
204         msg = malloc(sizeof(struct resourced_noti));
205         if (msg == NULL) {
206                 _E("proc_noti_cb : Not enough memory");
207                 return ECORE_CALLBACK_RENEW;
208         }
209
210         client_len = sizeof(client_address);
211         client_sockfd =
212             accept(fd, (struct sockaddr *)&client_address,
213                    (socklen_t *)&client_len);
214         if (client_sockfd == -1) {
215                 _E("socket accept error");
216                 free(msg);
217                 return ECORE_CALLBACK_RENEW;
218         }
219
220         error_code = read_message(client_sockfd, msg);
221
222         if (error_code && _fatal_read_message_error(error_code)) {
223                 free_message(msg);
224                 close(client_sockfd);
225                 return ECORE_CALLBACK_CANCEL;
226         } else if (error_code) { /* It's not fatal */
227                 _E("%s : recv error msg, %d", __func__, error_code);
228                 safe_write_int(client_sockfd, msg->type, &ret);
229                 goto proc_noti_renew;
230         }
231
232         if (msg->argc > NOTI_MAXARG) {
233                 _E("%s : error argument", __func__);
234                 safe_write_int(client_sockfd, msg->type, &ret);
235                 goto proc_noti_renew;
236         }
237
238         ret = process_message(msg);
239
240         safe_write_int(client_sockfd, msg->type, &ret);
241
242 proc_noti_renew:
243
244         close(client_sockfd);
245         free_message(msg);
246
247         return ECORE_CALLBACK_RENEW;
248 }
249
250 static int proc_noti_socket_init(void)
251 {
252         int fd;
253         struct sockaddr_un serveraddr;
254
255         if (access(RESOURCED_SOCKET_PATH, F_OK) == 0)
256                 unlink(RESOURCED_SOCKET_PATH);
257
258         fd = socket(AF_UNIX, SOCK_STREAM, 0);
259         if (fd < 0) {
260                 _E("%s: socket create failed\n", __func__);
261                 return -1;
262         }
263
264         if ((fsetxattr(fd, "security.SMACK64IPOUT", "@", 2, 0)) < 0) {
265                 _E("%s: Socket SMACK labeling failed\n", __func__);
266                 if (errno != EOPNOTSUPP) {
267                         close(fd);
268                         return -1;
269                 }
270         }
271
272         if ((fsetxattr(fd, "security.SMACK64IPIN", "*", 2, 0)) < 0) {
273                 _E("%s: Socket SMACK labeling failed\n", __func__);
274                 if (errno != EOPNOTSUPP) {
275                         close(fd);
276                         return -1;
277                 }
278         }
279
280         bzero(&serveraddr, sizeof(struct sockaddr_un));
281         serveraddr.sun_family = AF_UNIX;
282         strncpy(serveraddr.sun_path, RESOURCED_SOCKET_PATH,
283                 sizeof(serveraddr.sun_path));
284
285         if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) <
286             0) {
287                 _E("%s: socket bind failed\n", __func__);
288                 close(fd);
289                 return -1;
290         }
291
292         if (chmod(RESOURCED_SOCKET_PATH, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
293                 _E("failed to change the socket permission");
294
295         if (listen(fd, 5) < 0) {
296                 _E("%s: socket listen failed\n", __func__);
297                 close(fd);
298                 return -1;
299         }
300
301         _D("socket create & listen ok\n");
302
303         return fd;
304 }
305
306 int proc_noti_init()
307 {
308         int fd;
309         fd = proc_noti_socket_init();
310         ecore_main_fd_handler_add(fd, ECORE_FD_READ, (Ecore_Fd_Cb)proc_noti_cb,
311                                   NULL, NULL, NULL);
312         return fd;
313 }