Added information config with inotify
[platform/core/connectivity/stc-manager.git] / src / helper / helper-cgroup.c
1 /*
2  * Copyright (c) 2016 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 #include "helper-cgroup.h"
18
19 #define RELEASE_AGENT   "release_agent"
20 #define NOTIFY_ON_RELEASE  "notify_on_release"
21
22 #define CGROUP_FILE_NAME "cgroup.procs"
23 #define CLASSID_FILE_NAME "net_cls.classid"
24
25 #define MAX_PATH_LENGTH 512
26
27 static bool cgroup_is_exists(const char *cgroup_full_path)
28 {
29         struct stat stat_buf;
30         return stat(cgroup_full_path, &stat_buf) == 0;
31 }
32
33 static int cgroup_create(const char *cgroup_full_path)
34 {
35         if (mkdir(cgroup_full_path,
36                   S_IRUSR | S_IWUSR | S_IRGRP) < 0)
37                 return -errno;
38
39         return 0;
40 }
41
42 /*
43  * @desc place pid to cgroup.procs file
44  * @return 0 in case of success, errno value in case of failure
45  */
46 stc_error_e cgroup_write_pid_fullpath(const char *cgroup_full_path,
47                                       const int pid)
48 {
49         int ret;
50
51         if (pid <= 0) {
52                 STC_LOGE("try to write empty pid to %s", cgroup_full_path);
53                 return STC_ERROR_NO_DATA;
54         }
55
56         ret = cgroup_write_node_uint32(cgroup_full_path, CGROUP_FILE_NAME,
57                                        (uint32_t)pid);
58
59         ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
60                          "Failed place all pid to cgroup %s", cgroup_full_path);
61         return STC_ERROR_NONE;
62 }
63
64 stc_error_e cgroup_write_pid(const char *cgroup_subsystem,
65                              const char *cgroup_name, const int pid)
66 {
67         char buf[MAX_PATH_LENGTH];
68         snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
69         return cgroup_write_pid_fullpath(buf, pid);
70 }
71
72 stc_error_e cgroup_write_pidtree(const char *cgroup_subsystem,
73                                  const char *cgroup_name, const int pid)
74 {
75         char buf[MAX_PATH_LENGTH];
76
77         /*/proc/%d/task/%d/children */
78         char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
79         char pidbuf[MAX_DEC_SIZE(int)];
80         stc_error_e ret;
81
82         FILE *f;
83
84         snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
85         /* place parent */
86         ret = cgroup_write_pid_fullpath(buf, pid);
87         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
88                          "Failed to put parent process %d into %s cgroup",
89                          pid, cgroup_name);
90
91         snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN,
92                  pid, pid);
93         f = fopen(child_buf, "r");
94         ret_value_msg_if(!f, STC_ERROR_FAIL, "Failed to get child pids!");
95         while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) {
96                 int child_pid = atoi(pidbuf);
97                 if (child_pid < 0) {
98                         STC_LOGE("Invalid child pid!");
99                         fclose(f);
100                         return STC_ERROR_FAIL;
101                 }
102                 stc_error_e ret = cgroup_write_pid_fullpath(buf, child_pid);
103                 if (ret != STC_ERROR_NONE) {
104                         STC_LOGE("Failed to put parent process %d into %s cgroup",
105                            pid, cgroup_name);
106                         fclose(f);
107                         return ret;
108                 }
109         }
110         fclose(f);
111         return STC_ERROR_NONE;
112 }
113
114 int cgroup_write_node_uint32(const char *cgroup_name,
115                              const char *file_name, uint32_t value)
116 {
117         char buf[MAX_PATH_LENGTH];
118         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
119
120         if (STC_DEBUG_LOG)
121                 STC_LOGD("cgroup_buf %s, value %d\n", buf, value);
122
123         return fwrite_uint(buf, value);
124 }
125
126 int cgroup_write_node_str(const char *cgroup_name,
127                           const char *file_name, const char *string)
128 {
129         char buf[MAX_PATH_LENGTH];
130         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
131
132         if (STC_DEBUG_LOG)
133                 STC_LOGD("cgroup_buf %s, string %s\n", buf, string);
134
135         return fwrite_str(buf, string);
136 }
137
138 int cgroup_read_node_uint32(const char *cgroup_name,
139                             const char *file_name, uint32_t *value)
140 {
141         char buf[MAX_PATH_LENGTH];
142         int ret;
143         snprintf(buf, sizeof(buf), "%s/%s", cgroup_name, file_name);
144         ret = fread_uint(buf, value);
145
146         if (STC_DEBUG_LOG)
147                 STC_LOGD("cgroup_buf %s, value %d\n", buf, *value);
148
149         return ret;
150 }
151
152 int cgroup_make_subdir(const char *parentdir, const char *cgroup_name,
153                        bool *already)
154 {
155         char buf[MAX_PATH_LENGTH];
156         bool cgroup_exists;
157         int ret = 0;
158
159         if (parentdir)
160                 ret = snprintf(buf, sizeof(buf), "%s/%s",
161                                parentdir, cgroup_name);
162         else
163                 ret = snprintf(buf, sizeof(buf), "%s",
164                                cgroup_name);
165
166         ret_value_msg_if(ret > sizeof(buf), STC_ERROR_FAIL,
167                          "Not enought buffer size for %s%s",
168                          parentdir, cgroup_name);
169
170         cgroup_exists = cgroup_is_exists(buf);
171         if (!cgroup_exists) {
172                 bool cgroup_remount = false;
173
174                 if (parentdir && !strncmp(parentdir, DEFAULT_CGROUP,
175                                           sizeof(DEFAULT_CGROUP))) {
176                         ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",
177                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
178                                     "mode=755");
179                         if (ret < 0) {
180                                 STC_LOGE("Fail to RW mount cgroup directory. Can't make %s cgroup", cgroup_name);
181                                 return STC_ERROR_FAIL;
182                         }
183                         cgroup_remount = true;
184                 }
185
186                 ret = cgroup_create(buf);
187                 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
188                                  "Fail to create cgroup %s : err %d",
189                                  cgroup_name, errno);
190
191                 if (cgroup_remount) {
192                         ret = mount("tmpfs", DEFAULT_CGROUP, "tmpfs",
193                                     MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
194                                     "mode=755");
195                         if (ret < 0)
196                                 STC_LOGD("Fail to RO mount");
197                 }
198         }
199
200         if (already)
201                 *already = cgroup_exists;
202
203         return STC_ERROR_NONE;
204 }
205
206 int cgroup_set_release_agent(const char *cgroup_subsys,
207                              const char *release_agent)
208 {
209         _cleanup_free_ char *buf = NULL;
210         int r;
211
212         r = asprintf(&buf, "%s/%s", DEFAULT_CGROUP, cgroup_subsys);
213         if (r < 0)
214                 return -ENOMEM;
215
216         r = cgroup_write_node_str(buf, RELEASE_AGENT, release_agent);
217         if (r < 0)
218                 return r;
219
220         return cgroup_write_node_str(buf, NOTIFY_ON_RELEASE, "1");
221 }
222
223 void cgroup_init(void)
224 {
225         /* create stc cgroup directory */
226         cgroup_make_subdir(CGROUP_NETWORK, STC_CGROUP_NAME, NULL);
227
228         /* create background cgroup directory */
229         cgroup_make_subdir(STC_CGROUP_NETWORK, STC_BACKGROUND_CGROUP_NAME,
230                            NULL);
231
232         cgroup_write_node_uint32(BACKGROUND_CGROUP_NETWORK,
233                 CLASSID_FILE_NAME, STC_BACKGROUND_APP_CLASSID);
234
235         /* create foreground cgroup directory */
236         cgroup_make_subdir(STC_CGROUP_NETWORK, STC_FOREGROUND_CGROUP_NAME,
237                            NULL);
238 }