tizen 2.3.1 release
[kernel/api/system-resource.git] / src / utils / datausage-tool.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 datausage-tool.c
22  * @desc Implement Performance API. Command line utility.
23  *
24  */
25
26 #include <getopt.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "data_usage.h"
32 #include "resourced.h"
33 #include "rd-network.h"
34 #include "const.h"
35 #include "iface.h"
36 #include "config.h"
37 #include "trace.h"
38 #include "version.h"
39
40 enum run_rsml_cmd {
41         UNDEFINED,
42         RESOURCED_APPLY,
43         RESOURCED_GET,
44         RESOURCED_DATA_USAGE,
45         RESOURCED_DATA_USAGE_DETAILS,
46         RESOURCED_EXCLUDE,
47         RESOURCED_REVERT,
48         RESOURCED_GET_RESTRICTIONS,
49         RESOURCED_SET_OPTIONS,
50         RESOURCED_GET_OPTIONS,
51         RESOURCED_SET_QUOTA,
52         RESOURCED_REMOVE_QUOTA,
53         RESOURCED_RESTRICTION_STATE,
54 };
55
56 struct arg_param {
57         data_usage_selection_rule du_rule;
58         int64_t rcv_limit;
59         int64_t send_limit;
60         resourced_roaming_type roaming_type;
61         char *app_id;
62 };
63
64 static resourced_ret_c convert_roaming(const char *str,
65         resourced_roaming_type *roaming)
66 {
67         if (!str)
68                 return RESOURCED_ERROR_INVALID_PARAMETER;
69
70         if (!strcmp(optarg, "enabled")) {
71                 *roaming = RESOURCED_ROAMING_ENABLE;
72                 return RESOURCED_ERROR_NONE;
73         }
74
75         if (!strcmp(optarg, "disabled")) {
76                 *roaming = RESOURCED_ROAMING_DISABLE;
77                 return RESOURCED_ERROR_NONE;
78         }
79
80         if (!strcmp(optarg, "unknown")) {
81                 *roaming = RESOURCED_ROAMING_UNKNOWN;
82                 return RESOURCED_ERROR_NONE;
83         }
84         return RESOURCED_ERROR_INVALID_PARAMETER;
85 }
86
87 static void print_version()
88 {
89         printf("Version number: %d.%d-%d\n", MAJOR_VERSION, MINOR_VERSION,
90                 PATCH_VERSION);
91 }
92
93 static void print_usage()
94 {
95         puts("run_rsml [Options]");
96         puts("       Application options:");
97         puts(" possible ordering values: ");
98         puts("\t\tappid - order by application id (package name) "
99              "in ascending");
100         puts("\t\tappiddesc - order by application id (package name) "
101              "in descending");
102         puts("\t\tiface - ascending ordering by network interface name");
103         puts("\t\tifacedesc - descending ordering by network interface name");
104         puts("-a [--apply-rst] <package name> - apply restriction");
105         puts("-e [--exclude-rst] <package name> - exclude restriction");
106         puts("-R [--restrictions] <incoming>,<outgoing> "
107              "- restrictions to apply");
108         puts("-r [--revert-rst] <package name> - revert restriction");
109         puts("-l [--list-app-rst] - list of restricted applications");
110         puts("-g [--get] - get counters and restriction for application");
111         puts("-v [--version] - program version");
112         puts("-h [--help] - application help");
113         puts("-u [--data-usage] - data usage");
114         puts("-f [--from] <timestamp> - starting timestamp "
115              "for data usage requests");
116         puts("-t [--to] <timestamp> - ending timestamp "
117              "for data usage requests");
118         puts("-i [--interface] <iface> - interface name");
119         puts("-d [--data-usage-details] [<appid>] - data usage details "
120              "total/for application");
121         puts("-G [--granularity] <seconds> - split data usage results "
122              "into chunks of <seconds>");
123         puts("-O [--options] <set|get> set or get options");
124         puts(" In case of set options:");
125         puts(" -W [--wifi] <1|0> enable or disable wifi");
126         puts(" -D [--datacall] <1|0> enable or disable datacall");
127         puts(" -T [--datausagetimer] <1|0> enable or disable datausage timer");
128         puts(" -L [--datacalllogging] <1|0> enable or disable datacall logging");
129         puts(" -M [--roaming] <enalbled|disabled|unknown> enable or disable "
130                 " roaming, unknown by default");
131         puts(" -q [--quota] <appid> ");
132         puts(" -Q [--remove-quota] <appid> ");
133         puts(" -s [--rst-state] <pkgid> ");
134 }
135
136 static enum run_rsml_cmd parse_cmd(int argc, char **argv,
137                                   struct arg_param *param)
138 {
139         const char *optstring = "hvla:e:g:uf:t:i:d::G:R:r:O:q:Q:M:s:";
140
141         const struct option options[] = {
142                 {"help", no_argument, 0, 'h'},
143                 {"list-app-rst", no_argument, 0, 'l'},
144                 {"version", no_argument, 0, 'v'},
145                 {"apply-rst", required_argument, 0, 'a'},
146                 {"exclude-rst", required_argument, 0, 'e'},
147                 {"revert-rst", required_argument, 0, 'r'},
148                 {"get", required_argument, 0, 'g'},
149                 {"data-usage", no_argument, 0, 'u'},
150                 {"from", required_argument, 0, 'f'},
151                 {"to", required_argument, 0, 't'},
152                 {"interface", required_argument, 0, 'i'},
153                 {"data-usage-details", optional_argument, 0, 'd'},
154                 {"granularity", required_argument, 0, 'G'},
155                 {"restrictions", required_argument, 0, 'R'},
156                 {"options", required_argument, 0, 'O'},
157                 {"quota", required_argument, 0, 'q'},
158                 {"remove-quota", required_argument, 0, 'Q'},
159                 {"roaming", required_argument, 0, 'M'},
160                 {"rst-state", required_argument, 0, 's'},
161                 {0, 0, 0, 0}
162         };
163
164         int longindex, retval;
165         enum run_rsml_cmd cmd = UNDEFINED;
166         resourced_iface_type iftype;
167
168         while ((retval =
169                 getopt_long(argc, argv, optstring, options,
170                             &longindex)) != -1) {
171                 switch (retval) {
172                 case 'h':
173                 case '?':
174                         print_usage();
175                         exit(EXIT_SUCCESS);
176                 case 'v':
177                         print_version();
178                         exit(EXIT_SUCCESS);
179                 case 'a':
180                         if (!optarg) {
181                                 printf("apply-rst option requeres an argument.");
182                                 exit(EXIT_FAILURE);
183                         }
184                         cmd = RESOURCED_APPLY;
185                         param->app_id = strdup(optarg);
186                         break;
187                 case 'e':
188                         if (!optarg) {
189                                 printf("exclude-rst option requeres an argument.");
190                                 exit(EXIT_FAILURE);
191                         }
192                         cmd = RESOURCED_EXCLUDE;
193                         param->app_id = strdup(optarg);
194                         break;
195                 case 'g':
196                         cmd = RESOURCED_GET;
197                         break;
198                 case 'u':
199                         cmd = RESOURCED_DATA_USAGE;
200                         break;
201                 case 'f':
202                         if (!optarg) {
203                                 printf("from option requeres an argument.");
204                                 exit(EXIT_FAILURE);
205                         }
206                         if (sscanf(optarg, "%ld", &param->du_rule.from) != 1) {
207                                 printf("Failed to parse 'from' timestamp: %s\n",
208                                        optarg);
209                                 exit(EXIT_FAILURE);
210                         }
211                         break;
212                 case 't':
213                         if (!optarg) {
214                                 printf("to option requeres an argument.");
215                                 exit(EXIT_FAILURE);
216                         }
217                         if (sscanf(optarg, "%ld", &param->du_rule.to) != 1) {
218                                 printf("Failed to parse 'to' timestamp: %s\n",
219                                        optarg);
220                                 exit(EXIT_FAILURE);
221                         }
222                         break;
223                 case 'i':
224                         if (!optarg) {
225                                 printf("interface option requeres an argument.");
226                                 exit(EXIT_FAILURE);
227                         }
228                         iftype = convert_iftype(optarg);
229                         if (iftype == RESOURCED_IFACE_UNKNOWN) {
230                                 printf("Unknown network interface!\n");
231                                 exit(EXIT_FAILURE);
232                         }
233
234                         /* TODO change internal param structure */
235                         param->du_rule.iftype = iftype;
236                         break;
237                 case 'M':
238                         if (!optarg) {
239                                 printf("roaming option requeres an argument.");
240                                 exit(EXIT_FAILURE);
241                         }
242                         resourced_ret_c ret_code = convert_roaming(optarg,
243                                 &param->roaming_type);
244
245                         if (ret_code != RESOURCED_ERROR_NONE) {
246                                 printf("Wrong argument of roaming: %s, roaming "
247                                         "can only be enabled or disabled\n", optarg);
248                                 exit(EXIT_FAILURE);
249                         }
250                         break;
251                 case 'd':
252                         cmd = RESOURCED_DATA_USAGE_DETAILS;
253                         if (optarg)
254                                 param->app_id = strdup(optarg);
255                         break;
256                 case 'G':
257                         if (!optarg) {
258                                 printf("granularity option requeres an argument.");
259                                 exit(EXIT_FAILURE);
260                         }
261                         if (sscanf(optarg, "%d", &param->du_rule.granularity) !=
262                             1) {
263                                 printf("Failed to parse granularity: %s\n",
264                                        optarg);
265                                 exit(EXIT_FAILURE);
266                         }
267                         break;
268                 case 'r':
269                         if (!optarg) {
270                                 printf("revert-rst option requeres an argument.");
271                                 exit(EXIT_FAILURE);
272                         }
273                         cmd = RESOURCED_REVERT;
274                         param->app_id = strdup(optarg);
275                         break;
276                 case 'l':
277                         cmd = RESOURCED_GET_RESTRICTIONS;
278                         break;
279                 case 'R':
280                         if (!optarg) {
281                                 printf("restrictions option requeres an argument.");
282                                 exit(EXIT_FAILURE);
283                         }
284                         if (sscanf
285                             (optarg, "%jd,%jd",
286                              &param->rcv_limit,
287                              &param->send_limit) != 2) {
288                                 printf("Failed to parse restrictions\n"
289                                        "expected 2 integer numbers separated with commas without spaces\n"
290                                        "got \"%s\"\n", optarg);
291                                 exit(EXIT_FAILURE);
292                         }
293                         break;
294                 case 'O':
295                         if (!optarg) {
296                                 printf("options option requeres an argument.");
297                                 exit(EXIT_FAILURE);
298                         }
299                         if (optarg && strcmp(optarg, "set") == 0)
300                                 cmd = RESOURCED_SET_OPTIONS;
301                         else if (optarg && strcmp(optarg, "get") == 0)
302                                 cmd = RESOURCED_GET_OPTIONS;
303                         break;
304                 case 'q':
305                         if (!optarg) {
306                                 printf("Quota option requeres an argument.");
307                                 exit(EXIT_FAILURE);
308                         }
309                         cmd = RESOURCED_SET_QUOTA;
310                         param->app_id = strdup(optarg);
311
312                         break;
313                 case 'Q':
314                         if (!optarg) {
315                                 printf("Remove quota option requeres an argument.");
316                                 exit(EXIT_FAILURE);
317                         }
318                         cmd = RESOURCED_REMOVE_QUOTA;
319                         param->app_id = strdup(optarg);
320                         break;
321                 case 's':
322                         if (!optarg) {
323                                 printf("Restriction state requeres an argument.");
324                                 exit(EXIT_FAILURE);
325                         }
326                         cmd = RESOURCED_RESTRICTION_STATE;
327                         param->app_id = strdup(optarg);
328                         break;
329                 default:
330                         printf("Unknown option %c\n", (char)retval);
331                         print_usage();
332                         exit(EXIT_FAILURE);
333                 }
334         }
335         return cmd;
336 }
337
338 /* common callback for data usage and data usage details
339  * user_data is NULL for data usage
340  * user_data is a non-NULL
341  * (but not necessarily meaningful) for data usage details
342  */
343 resourced_cb_ret data_usage_callback(const data_usage_info *info, void *user_data)
344 {
345         /*TODO rewrite this hack*/
346         if (user_data)
347                 printf("iftype %d\n", info->iftype);
348         else
349                 printf("%s\n", info->app_id ? info->app_id : UNKNOWN_APP);
350
351         if (info->interval) {
352                 char buf[28];
353
354                 ctime_r(&info->interval->from, buf);
355                 printf("%s\t", buf);
356                 ctime_r(&info->interval->to, buf);
357                 printf("%s\t", buf);
358         } else
359                 printf("<entire interval>\t");
360
361         printf("%ld/%ld\t%ld/%ld/%u/%u/%s\n", info->foreground.cnt.incoming_bytes,
362                info->background.cnt.incoming_bytes,
363                info->foreground.cnt.outgoing_bytes,
364                info->background.cnt.outgoing_bytes,
365                info->roaming, info->hw_net_protocol_type,
366                info->ifname);
367         return RESOURCED_CONTINUE;
368 }
369
370 static inline int is_valid_range32(const int64_t value)
371 {
372         return value >= 0 && value <= 2147483647; /* 2Gb */
373 }
374
375 /* callback for restriction details
376  */
377 resourced_cb_ret restriction_callback(const resourced_restriction_info *info,
378                                       void *user_data)
379 {
380         printf("appid: %s, iftype: %d, rst_state %d, rcv_limit %d, "
381                "send_limit %d, roaming %d\n",
382                 info->app_id ? info->app_id : UNKNOWN_APP,
383                info->iftype, info->rst_state,
384                info->rcv_limit, info->send_limit, info->roaming);
385         return RESOURCED_CONTINUE;
386 }
387
388 const char *state_representation[] = {
389         "UNDEFINDED",
390         "ACTIVATED",
391         "EXCLUDED",
392         "REMOVED",
393 };
394
395 const char *convert_restriction_state(network_restriction_state state) {
396         if (state <= NETWORK_RESTRICTION_UNDEFINDED
397                 || state >= NETWORK_RESTRICTION_MAX_VALUE) {
398                 fprintf(stderr, "state not in range %d", state);
399                 return NULL;
400         }
401
402         return state_representation[state];
403 }
404
405 void print_restriction_state(resourced_restriction_state state)
406 {
407         const char *state_str = convert_restriction_state(state);
408         if (state_str)
409                 printf("\nRestriction state: %s\n", state_str);
410 }
411
412 int main(int argc, char **argv)
413 {
414         int ret_code = 0;
415         struct arg_param param;
416         enum run_rsml_cmd cmd = UNDEFINED;
417         if (argc == 1) {
418                 print_usage();
419                 exit(EXIT_FAILURE);
420         }
421
422         memset(&param, 0, sizeof(struct arg_param));
423         cmd = parse_cmd(argc, argv, &param);
424         switch (cmd) {
425         case RESOURCED_APPLY:
426         {
427                 int err = 0;
428                 resourced_net_restrictions net_rst = {0,};
429
430                 if (!param.du_rule.iftype) {
431                         fprintf(stderr, "Apply restriction command requires -i\n");
432                         err = RESOURCED_ERROR_INVALID_PARAMETER;
433                 }
434
435                 if (!is_valid_range32(param.send_limit)) {
436                         fprintf(stderr, "Send limit should be in range 0 - 2Gb");
437                         err = RESOURCED_ERROR_INVALID_PARAMETER;
438                 }
439                 if (!is_valid_range32(param.rcv_limit)) {
440                         fprintf(stderr, "Rcv limit should be in range 0 - 2Gb");
441                         err = RESOURCED_ERROR_INVALID_PARAMETER;
442                 }
443
444                 if (err)
445                         return err;
446
447                 net_rst.send_limit = param.send_limit;
448                 net_rst.rcv_limit = param.rcv_limit;
449                 net_rst.iftype = param.du_rule.iftype;
450
451                 ret_code = set_net_restriction(param.app_id,
452                                                        &net_rst);
453                 if (ret_code != RESOURCED_ERROR_NONE) {
454                         fprintf(stderr, "Failed to set restriction\n");
455                         return ret_code;
456                 }
457
458                 break;
459
460         }
461         case RESOURCED_EXCLUDE:
462         {
463                 resourced_net_restrictions rst = {0,};
464                 rst.iftype = param.du_rule.iftype;
465                 rst.roaming = param.roaming_type;
466
467                 ret_code = set_net_exclusion(param.app_id,
468                         &rst);
469                 if (ret_code != RESOURCED_ERROR_NONE)
470                         return ret_code;
471                 break;
472         }
473         case RESOURCED_DATA_USAGE:
474                 if (param.du_rule.from && param.du_rule.to) {
475                         data_usage_foreach(&param.du_rule, data_usage_callback,
476                                            NULL);
477                 } else {
478                         fprintf(stderr, "Data usage commands require both "
479                                "--from and --to\n");
480                 }
481                 break;
482         case RESOURCED_DATA_USAGE_DETAILS:
483                 if (param.du_rule.from && param.du_rule.to) {
484                         /* see description for data_usage_callback above */
485                         data_usage_details_foreach(param.app_id, &param.du_rule,
486                                                    data_usage_callback,
487                                                    (void *)1);
488                 } else {
489                         fprintf(stderr, "Data usage commands require both "
490                                "--from and --to\n");
491                 }
492                 break;
493         case RESOURCED_REVERT:
494                 if (param.du_rule.iftype)
495                         ret_code = remove_restriction_by_iftype(
496                                 param.app_id, param.du_rule.iftype);
497                 else
498                         fprintf(stderr, "Revert restriction commands require -i\n");
499                 if (ret_code != RESOURCED_ERROR_NONE)
500                         return ret_code;
501                 break;
502         case RESOURCED_GET_RESTRICTIONS:
503                 printf("Applications are restricted now:\n");
504                 ret_code = restrictions_foreach(restriction_callback, NULL);
505                 break;
506         case RESOURCED_SET_OPTIONS:
507         {
508                 resourced_options options = {0};
509                 ret_code = set_resourced_options(&options);
510                 break;
511         }
512         case RESOURCED_GET_OPTIONS:
513         {
514                 resourced_options options = {0};
515                 ret_code = get_resourced_options(&options);
516                 break;
517         }
518         case RESOURCED_SET_QUOTA:
519         {
520                 data_usage_quota quota = { 0 };
521                 if (!param.du_rule.from || !param.du_rule.to) {
522                         fprintf(stderr, "Quota command requires all of this options: "
523                                "--from, --to and --roaming\n");
524                         break;
525                 }
526
527                 /* TODO in case of refactoring, use internal command line structure instead of public structure for holding param */
528                 time_t quota_start_time = time(NULL);
529                 quota.start_time = &quota_start_time;
530                 quota.snd_quota = param.send_limit;
531                 quota.rcv_quota = param.rcv_limit;
532                 quota.iftype = param.du_rule.iftype;
533                 quota.time_period = param.du_rule.to - param.du_rule.from;
534                 quota.roaming_type =  param.roaming_type;
535                 if (set_datausage_quota(param.app_id, &quota) !=
536                      RESOURCED_ERROR_NONE) {
537                                 fprintf(stderr, "Failed to apply quota!\n");
538                 }
539                 break;
540         }
541         case RESOURCED_REMOVE_QUOTA:
542         {
543                 struct datausage_quota_reset_rule rule = {0};
544
545                 rule.app_id = param.app_id;
546                 rule.iftype = param.du_rule.iftype;
547                 rule.roaming = param.roaming_type;
548
549                 if (remove_datausage_quota(&rule) != RESOURCED_ERROR_NONE) {
550                         fprintf(stderr, "Failed to remove quota!\n");
551                 }
552                 break;
553         }
554         case RESOURCED_RESTRICTION_STATE:
555         {
556                 resourced_restriction_state state;
557                 if (!param.du_rule.iftype) {
558                         fprintf(stderr, "Exclude restriction commands require -i\n");
559                         ret_code = RESOURCED_ERROR_INVALID_PARAMETER;
560                         break;
561                 }
562
563                 ret_code = get_restriction_state(param.app_id,
564                         param.du_rule.iftype, &state);
565
566                 print_restriction_state(state);
567                 break;
568         }
569         default:
570                 ret_code = RESOURCED_ERROR_INVALID_PARAMETER;
571                 break;
572         }
573
574         return ret_code;
575 }