4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * @file classid-helper.c
23 * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
27 #include "appid-helper.h"
28 #include "net-cls-cgroup.h"
31 #include "data_usage.h"
33 #include "file-helper.h"
42 #define CUR_CLASSID_PATH "/tmp/cur_classid"
43 #define CLASSID_FILE_NAME "/net_cls.classid"
44 #define PATH_TO_NET_CGROUP_DIR "/sys/fs/cgroup/net_cls"
50 char cgroup_name[MAX_NAME_LENGTH]; /*in combination it's package name */
53 typedef GArray task_classid_array;
54 static task_classid_array *tasks_classids;
56 static int read_uint(FILE *handler, u_int32_t *out)
58 return fscanf(handler, "%u", out);
61 static int read_int(FILE *handler, int *out)
63 return fscanf(handler, "%d", out);
66 static u_int32_t produce_classid(void)
68 u_int32_t classid = RESOURCED_RESERVED_CLASSID_MAX;
69 int ret = fread_int(CUR_CLASSID_PATH, &classid);
71 ETRACE_RET_ERRCODE_MSG(ret, "Can not read current classid");
72 ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
74 ETRACE_RET_ERRCODE_MSG(ret, "Can not write classid");
79 static int place_classid_to_cgroup(const char *cgroup, const char *subdir,
82 char buf[MAX_PATH_LENGTH];
83 u_int32_t generated_classid = produce_classid();
85 *classid = generated_classid;
87 snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
88 return cgroup_write_node(buf, CLASSID_FILE_NAME, generated_classid);
91 static u_int32_t get_classid_from_cgroup(const char *cgroup, const char *subdir)
93 char buf[MAX_PATH_LENGTH];
94 u_int32_t classid = RESOURCED_UNKNOWN_CLASSID;
95 snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
97 int ret = cgroup_read_node(buf, CLASSID_FILE_NAME, &classid);
99 ETRACE_RET_ERRCODE_MSG(ret, "Cant read classid from cgroup %s",
105 populate_classids_with_pids(const char *dir_name_buf, size_t dir_name_buf_len,
106 const char *cgroup_name_buf,
107 task_classid_array **tasks_classids_list)
109 char file_name_buf[MAX_PATH_LENGTH];
111 struct task_classid tc;
112 memset(&tc, 0, sizeof(struct task_classid));
113 tc.pids = g_array_new(FALSE, FALSE, sizeof(pid_t));
114 pid_t pid_for_read = 0;
116 /* first part of path */
117 snprintf(file_name_buf, sizeof(file_name_buf), "%s%s", dir_name_buf,
119 handler = fopen(file_name_buf, "r");
122 _E("can't open %s file\n", file_name_buf);
126 if (sizeof(tc.cgroup_name) < strlen(cgroup_name_buf))
127 _SE("not enought buffer for %s", cgroup_name_buf);
129 strncpy(tc.cgroup_name, cgroup_name_buf, sizeof(tc.cgroup_name)-1);
131 if (read_uint(handler, &tc.classid) < 0)
132 _E("can't read classid from file %s\n", file_name_buf);
136 strncpy(file_name_buf + dir_name_buf_len, TASK_FILE_NAME,
137 dir_name_buf_len + sizeof(TASK_FILE_NAME));
139 handler = fopen(file_name_buf, "r");
142 _E("can't open %s file\n", file_name_buf);
146 while (read_int(handler, &pid_for_read) >= 0) {
147 tc.pids = g_array_append_val(tc.pids, pid_for_read);
150 *tasks_classids_list = g_array_append_val(*tasks_classids_list, tc);
155 u_int32_t get_classid_by_app_id(const char *app_id, int create)
157 char pkgname[MAX_PATH_LENGTH];
158 extract_pkgname(app_id, pkgname, sizeof(pkgname));
159 return get_classid_by_pkg_name(pkgname, create);
162 API u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create)
166 u_int32_t classid = RESOURCED_UNKNOWN_CLASSID;
168 if (!strcmp(pkg_name, RESOURCED_ALL_APP))
169 return RESOURCED_ALL_APP_CLASSID;
171 if (!strcmp(pkg_name, TETHERING_APP_NAME))
172 return RESOURCED_TETHERING_APP_CLASSID;
176 classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
179 if (classid != RESOURCED_UNKNOWN_CLASSID)
182 ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name,
188 classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
191 ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
192 (char *)pkg_name, &classid);
200 ETRACE_RET_ERRCODE(ret);
201 return RESOURCED_UNKNOWN_CLASSID;
205 int update_classids(void)
209 struct dirent *result;
212 char file_name_buf[256];
213 size_t path_to_cgroup_dir_len =
214 sizeof(PATH_TO_NET_CGROUP_DIR), file_name_len;
216 snprintf(file_name_buf, sizeof(file_name_buf), "%s/", PATH_TO_NET_CGROUP_DIR);
218 if (tasks_classids) {
219 array_foreach(tc, struct task_classid, tasks_classids) {
220 g_array_free(tc->pids, TRUE);
222 g_array_free(tasks_classids, TRUE);
225 tasks_classids = g_array_new(FALSE, FALSE, sizeof(struct task_classid));
227 dir = opendir(file_name_buf);
230 return ERROR_UPDATE_CLASSIDS_LIST;
232 while (!(ret = readdir_r(dir, &entry, &result)) && result != NULL) {
233 if (entry.d_type != DT_DIR || entry.d_name[0] == '.')
236 file_name_len = strlen(entry.d_name);
237 if (file_name_len + path_to_cgroup_dir_len >
238 sizeof(file_name_buf)) {
239 _E("not enought buffer size\n");
243 strncpy(file_name_buf + path_to_cgroup_dir_len, entry.d_name,
246 populate_classids_with_pids(file_name_buf,
247 path_to_cgroup_dir_len + file_name_len,
248 entry.d_name, &tasks_classids);
253 return RESOURCED_ERROR_FAIL;
255 _D("class id table updated");
259 int_array *get_monitored_pids(void)
261 int_array *result = g_array_new(FALSE, FALSE, sizeof(pid_t));
264 _D("Out of memory\n");
268 array_foreach(tc, struct task_classid, tasks_classids) {
271 for (; i < tc->pid_count; ++i) {
272 result = g_array_append_val(result,
273 g_array_index(tc->pids, int, i));
279 static char *get_app_id_by_classid_local(const u_int32_t classid)
281 if (classid == RESOURCED_TETHERING_APP_CLASSID)
282 return strdup(TETHERING_APP_NAME);
283 array_foreach(tc, struct task_classid, tasks_classids)
284 if (classid == tc->classid)
285 return strdup(tc->cgroup_name);
289 char *get_app_id_by_classid(const u_int32_t classid, const bool update_state)
292 char *appid = get_app_id_by_classid_local(classid);
297 _D("can't resolve app id");
301 ret = update_classids();
302 ret_value_msg_if(ret, 0, "Can't get appid for %d", classid);
304 return get_app_id_by_classid_local(classid);
307 API resourced_ret_c make_net_cls_cgroup_with_pid(const int pid, const char *pkg_name)
312 if (pkg_name == NULL) {
313 _E("package name must be not empty");
314 return RESOURCED_ERROR_INVALID_PARAMETER;
317 _SD("pkg: %s; pid: %d\n", pkg_name, pid);
319 ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name, &exists);
320 ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
323 ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name,
325 ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
328 return place_pid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);