ini: not using getenv
[platform/core/uifw/libtdm.git] / src / tdm_monitor_server.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #include "tdm_private.h"
37
38 #define TDM_DBG_SERVER_ARGS_MAX         32
39
40 /* LCOV_EXCL_START */
41 static void _tdm_monitor_server_usage(char *app_name, char *reply, int *len);
42
43 static void
44 _tdm_monitor_server_query(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
45 {
46         tdm_display_lock(dpy);
47         tdm_helper_get_display_information(dpy, reply, len);
48         tdm_display_unlock(dpy);
49 }
50
51 static void
52 _tdm_monitor_server_protocol_trace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
53 {
54         int enable;
55
56         if (argc < 3) {
57                 _tdm_monitor_server_usage(argv[0], reply, len);
58                 return;
59         }
60
61         enable = atoi(argv[2]);
62
63         tdm_event_loop_trace_enable(dpy, enable);
64
65         TDM_SNPRINTF(reply, len, "protocol trace: '%s'\n", (enable) ? "enabled" : "disabled");
66 }
67
68 static void
69 _tdm_monitor_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
70 {
71         tdm_output *output;
72         int output_idx, dpms_value;
73         char *arg;
74         char *end;
75         tdm_error ret;
76
77         if (argc < 3) {
78                 _tdm_monitor_server_usage(argv[0], reply, len);
79                 return;
80         }
81
82         arg = argv[2];
83         output_idx = strtol(arg, &end, 10);
84         if (*end != ':') {
85                 TDM_SNPRINTF(reply, len, "failed: no onoff value\n");
86                 return;
87         }
88
89         arg = end + 1;
90         dpms_value = strtol(arg, &end, 10);
91
92         output = tdm_display_get_output(dpy, output_idx, &ret);
93         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
94
95         ret = tdm_output_set_dpms(output, dpms_value);
96         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
97
98         TDM_SNPRINTF(reply, len, "done: DPMS %s\n", tdm_dpms_str(dpms_value));
99 }
100
101 static void
102 _tdm_monitor_server_ttrace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
103 {
104         int output_id = 0;
105         char *end;
106         tdm_error ret;
107
108         if (argc < 3) {
109                 _tdm_monitor_server_usage(argv[0], reply, len);
110                 return;
111         }
112
113         if (argv[3])
114                 output_id = strtol(argv[3], &end, 10);
115
116         ret = tdm_display_enable_ttrace(dpy, argv[2], output_id, reply, len);
117         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
118 }
119
120 static void
121 _tdm_monitor_server_debug(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
122 {
123         int level;
124         char *arg;
125         char *end;
126
127         if (argc < 3) {
128                 _tdm_monitor_server_usage(argv[0], reply, len);
129                 return;
130         }
131
132         arg = argv[2];
133         level = strtol(arg, &end, 10);
134
135         tdm_log_set_debug_level(level);
136         TDM_SNPRINTF(reply, len, "debug level: %d\n", level);
137
138         if (*end == '@') {
139                 char *arg = end + 1;
140
141                 tdm_display_enable_debug_module((const char *)arg);
142
143                 TDM_SNPRINTF(reply, len, "debugging... '%s'\n", arg);
144         }
145 }
146
147 static void
148 _tdm_monitor_server_log_path(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
149 {
150         static int old_stdout = -1;
151         char fd_name[TDM_PATH_LEN];
152         char *path;
153
154         if (argc < 3) {
155                 _tdm_monitor_server_usage(argv[0], reply, len);
156                 return;
157         }
158
159         if (old_stdout == -1)
160                 old_stdout = dup(STDOUT_FILENO);
161
162         path = argv[2];
163         TDM_DBG_RETURN_IF_FAIL(path != NULL);
164
165         tdm_log_enable_dlog(0);
166
167         if (!strncmp(path, "dlog", 4)) {
168                 tdm_log_enable_dlog(1);
169                 goto done;
170         } else if (!strncmp(path, "console", 7))
171                 snprintf(fd_name, TDM_PATH_LEN, "/proc/%d/fd/1", pid);
172         else {
173                 if (path[0] == '/')
174                         snprintf(fd_name, TDM_PATH_LEN, "%s", path);
175                 else {
176                         if (cwd)
177                                 snprintf(fd_name, TDM_PATH_LEN, "%s/%s", cwd, path);
178                         else
179                                 snprintf(fd_name, TDM_PATH_LEN, "%s", path);
180                 }
181                 tdm_log_enable_color(0);
182         }
183
184         tdm_log_set_path((const char*)fd_name);
185
186 done:
187         TDM_SNPRINTF(reply, len, "log path: '%s'\n", path);
188 }
189
190 static void
191 _tdm_monitor_server_choose_commit_per_vblank_mode(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
192 {
193         int output_idx;
194         int mode;
195         char *arg;
196         char *end;
197         tdm_error err;
198
199         /* TODO: do we have to provide an ability to choose commit_per_vblank mode outside? */
200
201         if (argc < 4) {
202                 _tdm_monitor_server_usage(argv[0], reply, len);
203                 return;
204         }
205
206         arg = argv[2];
207         output_idx = strtol(arg, &end, 10);
208
209         arg = argv[3];
210         mode = strtol(arg, &end, 10);
211
212         err = tdm_output_choose_commit_per_vblank_mode(tdm_display_get_output(dpy, output_idx, NULL), mode);
213         if (err != TDM_ERROR_NONE) {
214                 TDM_SNPRINTF(reply, len, "an error: output_idx or mode is wrong\n");
215                 return;
216         }
217
218         TDM_SNPRINTF(reply, len, "the mode's been set\n");
219 }
220
221 static void
222 _tdm_monitor_server_fps(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
223 {
224         int enable;
225         char *arg;
226         char *end;
227
228         if (argc < 3) {
229                 _tdm_monitor_server_usage(argv[0], reply, len);
230                 return;
231         }
232
233         arg = argv[2];
234         enable = strtol(arg, &end, 10);
235
236         tdm_display_enable_fps(dpy, enable);
237
238         TDM_SNPRINTF(reply, len, "%s to print fps\n", (enable) ? "enable" : "disable");
239 }
240
241 static void
242 _tdm_monitor_server_vblank_list(unsigned int pid, char *cwd, int argc, char *argv[],
243                                                                 char *reply, int *len, tdm_display *dpy)
244 {
245         tdm_vblank_get_vblank_list_information(dpy, reply, len);
246 }
247
248 static void
249 _tdm_monitor_server_vblank_fps(unsigned int pid, char *cwd, int argc, char *argv[],
250                                                            char *reply, int *len, tdm_display *dpy)
251 {
252         unsigned int target_pid, fps;
253         char *arg;
254         char *end;
255         char name[TDM_NAME_LEN];
256         tdm_error ret;
257
258         if (argc < 3) {
259                 _tdm_monitor_server_usage(argv[0], reply, len);
260                 return;
261         }
262
263         arg = argv[2];
264         target_pid = strtol(arg, &end, 10);
265
266         if (*end == ',') {
267                 arg = end + 1;
268                 end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
269         } else {
270                 strncpy(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1);
271                 name[TDM_NAME_LEN - 1] = '\0';
272         }
273
274         if (*end != '@') {
275                 TDM_SNPRINTF(reply, len, "failed: no fps value\n");
276                 return;
277         }
278
279         arg = end + 1;
280         fps = strtol(arg, &end, 10);
281
282         ret = tdm_vblank_set_client_vblank_fps(target_pid, name, fps);
283         if (ret != TDM_ERROR_NONE) {
284                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to '%s' client vblank(PID:%u)\n", fps, name, target_pid);
285                 return;
286         }
287
288         TDM_SNPRINTF(reply, len, "success: '%u' fps for '%s' client vblank(PID:%u)\n", fps, name, target_pid);
289 }
290
291 static void
292 _tdm_monitor_server_global_fps(unsigned int pid, char *cwd, int argc, char *argv[],
293                                                            char *reply, int *len, tdm_display *dpy)
294 {
295         unsigned int fps;
296         char *arg;
297         char *end;
298         tdm_error ret;
299
300         if (argc < 3) {
301                 _tdm_monitor_server_usage(argv[0], reply, len);
302                 return;
303         }
304
305         arg = argv[2];
306         fps = strtol(arg, &end, 10);
307
308         if (fps > 0)
309                 ret = tdm_vblank_enable_global_fps(1, fps);
310         else
311                 ret = tdm_vblank_enable_global_fps(0, 0);
312
313         if (ret != TDM_ERROR_NONE) {
314                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to global fps\n", fps);
315                 return;
316         }
317
318         TDM_SNPRINTF(reply, len, "success: '%u' global fps\n", fps);
319 }
320
321 static void
322 _tdm_monitor_server_prop(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
323 {
324         tdm_output *output;
325         tdm_output *layer = NULL;
326         int output_idx, layer_idx = -1;
327         int cnt, i, done = 0;
328         tdm_value value;
329         char temp[TDM_PATH_LEN];
330         char *prop_name;
331         char *arg;
332         char *end;
333         tdm_error ret;
334         const tdm_prop *props;
335
336         if (argc < 3) {
337                 _tdm_monitor_server_usage(argv[0], reply, len);
338                 return;
339         }
340
341         snprintf(temp, TDM_PATH_LEN, "%s", argv[2]);
342         arg = temp;
343
344         output_idx = strtol(arg, &end, 10);
345         if (*end == ',') {
346                 arg = end + 1;
347                 layer_idx = strtol(arg, &end, 10);
348         }
349
350         if (*end != ':') {
351                 TDM_SNPRINTF(reply, len, "failed: no prop_name\n");
352                 return;
353         }
354
355         arg = end + 1;
356         prop_name = strtok_r(arg, ",", &end);
357         if (!prop_name) {
358                 TDM_SNPRINTF(reply, len, "failed: get prop_name by strtok_r\n");
359                 return;
360         }
361
362         if (*end == '\0') {
363                 TDM_SNPRINTF(reply, len, "failed: no value\n");
364                 return;
365         }
366
367         arg = strtok_r(NULL, TDM_DELIM, &end);
368         if (!arg) {
369                 TDM_SNPRINTF(reply, len, "failed: get arg by strtok_r\n");
370                 return;
371         }
372         value.u32 = strtol(arg, &end, 10);
373
374         output = tdm_display_get_output(dpy, output_idx, &ret);
375         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
376
377         if (layer_idx != -1) {
378                 layer = tdm_output_get_layer(output, layer_idx, &ret);
379                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && layer != NULL);
380         }
381
382         if (layer) {
383                 ret = tdm_layer_get_available_properties(layer, &props, &cnt);
384                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
385
386                 for (i = 0; i < cnt; i++) {
387                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
388                                 ret = tdm_layer_set_property(layer, props[i].id, value);
389                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
390                                 done = 1;
391                                 break;
392                         }
393                 }
394         } else {
395                 ret = tdm_output_get_available_properties(output, &props, &cnt);
396                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
397
398                 for (i = 0; i < cnt; i++) {
399                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
400                                 ret = tdm_output_set_property(output, props[i].id, value);
401                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
402                                 done = 1;
403                                 break;
404                         }
405                 }
406         }
407
408         if (done)
409                 TDM_SNPRINTF(reply, len, "done: %s:%d \n", prop_name, value.u32);
410         else
411                 TDM_SNPRINTF(reply, len, "no '%s' propperty \n", prop_name);
412 }
413
414 static void
415 _tdm_monitor_server_dump(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
416 {
417         if (argc < 3) {
418                 _tdm_monitor_server_usage(argv[0], reply, len);
419                 return;
420         }
421
422         tdm_display_enable_dump(dpy, (const char*)argv[2], reply, len);
423 }
424
425 static void
426 _tdm_monitor_server_punch(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
427 {
428         char *arg, *end;
429         unsigned int output_id, layer_id;
430         tdm_output *output;
431         tdm_layer *layer;
432         tbm_surface_h buffer;
433
434         arg = argv[2];
435
436         output_id = strtol(arg, &end, 10);
437         output = tdm_display_get_output(dpy, output_id, NULL);
438         if (!output) {
439                 TDM_SNPRINTF(reply, len, "not found output\n");
440                 return;
441         }
442         if (*end != ',') {
443                 TDM_SNPRINTF(reply, len, "not found ',<layer_idx>'\n");
444                 return;
445         }
446
447         arg = end + 1;
448         layer_id = strtol(arg, &end, 10);
449         layer = tdm_output_get_layer(output, layer_id, NULL);
450         if (!layer) {
451                 TDM_SNPRINTF(reply, len, "not found layer\n");
452                 return;
453         }
454
455         buffer = tdm_layer_get_displaying_buffer(layer, NULL);
456         if (!buffer) {
457                 TDM_SNPRINTF(reply, len, "not found buffer\n");
458                 return;
459         }
460
461         if (*end == ':') {
462                 tdm_pos pos = {0,};
463
464                 arg = end + 1;
465                 pos.w = strtol(arg, &end, 10);
466                 TDM_EXIT_IF_FAIL(*end == 'x');
467                 arg = end + 1;
468                 pos.h = strtol(arg, &end, 10);
469                 if (*end == '+') {
470                         arg = end + 1;
471                         pos.x = strtol(arg, &end, 10);
472                         TDM_EXIT_IF_FAIL(*end == '+');
473                         arg = end + 1;
474                         pos.y = strtol(arg, &end, 10);
475                 }
476
477                 tdm_helper_clear_buffer_pos(buffer, &pos);
478         } else
479                 tdm_helper_clear_buffer(buffer);
480 }
481
482 static struct {
483         const char *opt;
484         void (*func)(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy);
485         const char *desc;
486         const char *arg;
487         const char *ex;
488 } option_proc[] = {
489         {
490                 "info", _tdm_monitor_server_query,
491                 "show tdm output, layer information", NULL, NULL
492         },
493         {
494                 "trace", _tdm_monitor_server_protocol_trace,
495                 "enable/disable the wl protocol",
496                 "<enable>",
497                 "0 or 1"
498         },
499         {
500                 "dpms", _tdm_monitor_server_dpms,
501                 "set output dpms", "<output_idx>:<dpms>", "0:3 or 0:0"
502         },
503         {
504                 "ttrace", _tdm_monitor_server_ttrace,
505                 "enable/disable ttrace (module: none,vsync,client_vblank,server_vblank,vblank,layer,pp,capture,all",
506                 "<module>[@<output_idx>]",
507                 NULL
508         },
509         {
510                 "debug", _tdm_monitor_server_debug,
511                 "set the debug level and modules(module: none, mutex, buffer, thread, vblank)",
512                 "<level>[@<module1>[,<module2>]]",
513                 NULL
514         },
515         {
516                 "log_path", _tdm_monitor_server_log_path,
517                 "set the log path (console,dlog,filepath)",
518                 "<path>",
519                 "console"
520         },
521         {
522                 "choose_commit_per_vblank_mode", _tdm_monitor_server_choose_commit_per_vblank_mode,
523                 "choose a commit_per_vblank mode for the output",
524                 "<output_idx> <mode>",
525                 "0 1 or 1 2 or 2 0"
526         },
527         {
528                 "fps", _tdm_monitor_server_fps,
529                 "enable/disable to print fps",
530                 "<enable>",
531                 "0 or 1"
532         },
533         {
534                 "vblank_list", _tdm_monitor_server_vblank_list,
535                 "print the client vblank list",
536                 NULL,
537                 NULL
538         },
539         {
540                 "vblank_fps", _tdm_monitor_server_vblank_fps,
541                 "set the client vblank fps for the given process ID and client vblank name",
542                 "<pid>[,<vblank_name>]@<fps>",
543                 NULL
544         },
545         {
546                 "global_fps", _tdm_monitor_server_global_fps,
547                 "set the global vblank fps for the entire system",
548                 "<fps>",
549                 NULL
550         },
551         {
552                 "prop", _tdm_monitor_server_prop,
553                 "set the property of a output or a layer",
554                 "<output_idx>[,<layer_idx>]:<prop_name>,<value>",
555                 NULL
556         },
557         {
558                 "dump", _tdm_monitor_server_dump,
559                 "dump buffers (type: none, layer, pp, capture, current)\n"
560                 "\t\t  layer, pp, capture - start to dump buffers of layer, pp, capture\n"
561                 "\t\t  none               - stop to dump buffers\n"
562                 "\t\t  current            - dump the current buffer of all layers",
563                 "<object_type1>[,<object_type2>[,...]][@<directory_path>]",
564                 NULL
565         },
566         {
567                 "punch", _tdm_monitor_server_punch,
568                 "punch a layer",
569                 "<output_idx>,<layer_idx>[:<w>x<h>[+<x>+<y>]]",
570                 NULL
571         },
572 };
573
574 static void
575 _tdm_monitor_server_usage(char *app_name, char *reply, int *len)
576 {
577         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
578         int i;
579
580         TDM_SNPRINTF(reply, len, "usage: %s \n\n", app_name);
581
582         for (i = 0; i < opt_size; i++) {
583                 TDM_SNPRINTF(reply, len, "\t-%s\t%s\n", option_proc[i].opt, option_proc[i].desc);
584                 if (option_proc[i].arg)
585                         TDM_SNPRINTF(reply, len, "\t\t  %s\n", option_proc[i].arg);
586                 if (option_proc[i].ex)
587                         TDM_SNPRINTF(reply, len, "\t\t  ex) %s\n", option_proc[i].ex);
588                 TDM_SNPRINTF(reply, len, "\n");
589         }
590 }
591
592 static void
593 _tdm_monitor_server_command(unsigned int pid, char *cwd, tdm_display *dpy, int argc, char *argv[], char *reply, int *len)
594 {
595         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
596         int i;
597
598         if (argc < 2) {
599                 _tdm_monitor_server_usage(argv[0], reply, len);
600                 return;
601         }
602
603         for (i = 0; i < opt_size; i++) {
604                 if (argv[1][0] == '-' && !strncmp(argv[1] + 1, option_proc[i].opt, 32)) {
605                         if (option_proc[i].func) {
606                                 option_proc[i].func(pid, cwd, argc, argv, reply, len, dpy);
607                                 return;
608                         } else {
609                                 TDM_SNPRINTF(reply, len, "'%s' not implemented.\n", argv[1]);
610                                 return;
611                         }
612                 }
613         }
614
615         _tdm_monitor_server_usage(argv[0], reply, len);
616         return;
617 }
618
619
620 INTERN void
621 tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len)
622 {
623         unsigned int pid;
624         char cwd[1024];
625         int argc = 0;
626         char *argv[TDM_DBG_SERVER_ARGS_MAX] = {0,};
627         char temp[1024];
628         char *arg;
629         char *end = NULL, *e;
630
631         snprintf(temp, sizeof(temp), "%s", options);
632
633         arg = strtok_r(temp, " ", &end);
634         if (!arg) {
635                 TDM_SNPRINTF(reply, len, "no pid for tdm-monitor");
636                 return;
637         }
638         pid = strtol(arg, &e, 10);
639
640         arg = strtok_r(NULL, " ", &end);
641         if (!arg) {
642                 TDM_SNPRINTF(reply, len, "no cwd for tdm-monitor");
643                 return;
644         }
645         snprintf(cwd, sizeof(cwd), "%s", arg);
646
647         TDM_DBG("pid(%d) cwd(%s)", pid, cwd);
648
649         argv[argc] = strtok_r(NULL, " ", &end);
650         while (argv[argc]) {
651                 argc++;
652                 if (argc == TDM_DBG_SERVER_ARGS_MAX) {
653                         TDM_SNPRINTF(reply, len, "too many arguments for tdm-monitor");
654                         break;
655                 }
656                 argv[argc] = strtok_r(NULL, " ", &end);
657         }
658
659         _tdm_monitor_server_command(pid, cwd, dpy, argc, argv, reply, len);
660 }
661 /* LCOV_EXCL_STOP */