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 strcpy(tc.cgroup_name, cgroup_name_buf);
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)
208 struct dirent *entry;
210 char file_name_buf[256];
211 size_t path_to_cgroup_dir_len =
212 sizeof(PATH_TO_NET_CGROUP_DIR), file_name_len;
214 sprintf(file_name_buf, "%s/", PATH_TO_NET_CGROUP_DIR);
216 if (tasks_classids) {
217 array_foreach(tc, struct task_classid, tasks_classids) {
218 g_array_free(tc->pids, TRUE);
220 g_array_free(tasks_classids, TRUE);
223 tasks_classids = g_array_new(FALSE, FALSE, sizeof(struct task_classid));
225 dir = opendir(file_name_buf);
228 return ERROR_UPDATE_CLASSIDS_LIST;
230 while ((entry = readdir(dir)) != 0) {
231 if (entry->d_type != DT_DIR || entry->d_name[0] == '.')
234 file_name_len = strlen(entry->d_name);
235 if (file_name_len + path_to_cgroup_dir_len >
236 sizeof(file_name_buf)) {
237 _E("not enought buffer size\n");
241 strncpy(file_name_buf + path_to_cgroup_dir_len, entry->d_name,
244 populate_classids_with_pids(file_name_buf,
245 path_to_cgroup_dir_len + file_name_len,
246 entry->d_name, &tasks_classids);
249 _D("class id table updated");
253 int_array *get_monitored_pids(void)
255 int_array *result = g_array_new(FALSE, FALSE, sizeof(pid_t));
258 _D("Out of memory\n");
262 array_foreach(tc, struct task_classid, tasks_classids) {
265 for (; i < tc->pid_count; ++i) {
266 result = g_array_append_val(result,
267 g_array_index(tc->pids, int, i));
273 static char *get_app_id_by_classid_local(const u_int32_t classid)
275 if (classid == RESOURCED_TETHERING_APP_CLASSID)
276 return strdup(TETHERING_APP_NAME);
277 array_foreach(tc, struct task_classid, tasks_classids)
278 if (classid == tc->classid)
279 return strdup(tc->cgroup_name);
283 char *get_app_id_by_classid(const u_int32_t classid, const bool update_state)
286 char *appid = get_app_id_by_classid_local(classid);
291 _D("can't resolve app id");
295 ret = update_classids();
296 ret_value_msg_if(ret, 0, "Can't get appid for %d", classid);
298 return get_app_id_by_classid_local(classid);
301 API resourced_ret_c make_net_cls_cgroup_with_pid(const int pid, const char *pkg_name)
306 if (pkg_name == NULL) {
307 _E("package name must be not empty");
308 return RESOURCED_ERROR_INVALID_PARAMETER;
311 _SD("pkg: %s; pid: %d\n", pkg_name, pid);
313 ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name, &exists);
314 ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
317 ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name,
319 ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
322 return place_pid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);