add excluding coverage comments for tdm_monitor_server.c and tdm_output.c
[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 <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdint.h>
40
41 #include "tdm.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44 #include "tdm_log.h"
45
46 #define TDM_DBG_SERVER_ARGS_MAX         32
47
48 /* LCOV_EXCL_START */
49 static void _tdm_monitor_server_usage(char *app_name, char *reply, int *len);
50
51 static void
52 _tdm_monitor_server_query(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
53 {
54         tdm_display_lock(dpy);
55         tdm_helper_get_display_information(dpy, reply, len);
56         tdm_display_unlock(dpy);
57 }
58
59 static void
60 _tdm_monitor_server_protocol_trace(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
61 {
62         int enable;
63
64         if (argc < 3) {
65                 _tdm_monitor_server_usage(argv[0], reply, len);
66                 return;
67         }
68
69         enable = atoi(argv[2]);
70
71         tdm_event_loop_trace_enable(dpy, enable);
72
73         TDM_SNPRINTF(reply, len, "protocol trace: '%s'\n", (enable) ? "enabled" : "disabled");
74 }
75
76 static void
77 _tdm_monitor_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
78 {
79         tdm_output *output;
80         int output_idx, dpms_value;
81         char *arg;
82         char *end;
83         tdm_error ret;
84
85         if (argc < 3) {
86                 _tdm_monitor_server_usage(argv[0], reply, len);
87                 return;
88         }
89
90         arg = argv[2];
91         output_idx = strtol(arg, &end, 10);
92         if (*end != ':') {
93                 TDM_SNPRINTF(reply, len, "failed: no onoff value\n");
94                 return;
95         }
96
97         arg = end + 1;
98         dpms_value = strtol(arg, &end, 10);
99
100         output = tdm_display_get_output(dpy, output_idx, &ret);
101         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
102
103         ret = tdm_output_set_dpms(output, dpms_value);
104         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
105
106         TDM_SNPRINTF(reply, len, "done: DPMS %s\n", tdm_dpms_str(dpms_value));
107 }
108
109 static void
110 _tdm_monitor_server_ttrace_vblank(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
111 {
112         int ttrace_vblank, output_id = 0;
113         char *arg;
114         char *end;
115
116         if (argc < 3) {
117                 _tdm_monitor_server_usage(argv[0], reply, len);
118                 return;
119         }
120
121         arg = argv[2];
122         ttrace_vblank = strtol(arg, &end, 10);
123
124         if (ttrace_vblank > 0) {
125                 tdm_output *output;
126                 tdm_error ret;
127                 tdm_output_type type;
128                 char *temp;
129
130                 if (*end == '@') {
131                         arg = end + 1;
132                         output_id = strtol(arg, &end, 10);
133                 }
134
135                 output = tdm_display_get_output(dpy, output_id, NULL);
136                 if (!output) {
137                         TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id);
138                         return;
139                 }
140
141                 ret = tdm_output_get_output_type(output, &type);
142                 if (ret != TDM_ERROR_NONE) {
143                         TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id);
144                         return;
145                 }
146
147                 temp = "server";
148                 tdm_display_enable_ttrace_vblank(dpy, output, 1);
149
150                 if (ttrace_vblank > 1) {
151                         temp = "clients";
152                         tdm_server_enable_ttrace_vblank(dpy, output, 1);
153                 }
154
155                 TDM_SNPRINTF(reply, len, "enable ttrace vblank for '%s': %s \n", tdm_conn_str(type), temp);
156         } else {
157                 tdm_display_enable_ttrace_vblank(dpy, NULL, 0);
158                 tdm_server_enable_ttrace_vblank(dpy, NULL, 0);
159                 TDM_SNPRINTF(reply, len, "disable ttrace vblank\n");
160         }
161 }
162
163 static void
164 _tdm_monitor_server_debug(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
165 {
166         int level;
167         char *arg;
168         char *end;
169
170         if (argc < 3) {
171                 _tdm_monitor_server_usage(argv[0], reply, len);
172                 return;
173         }
174
175         arg = argv[2];
176         level = strtol(arg, &end, 10);
177
178         tdm_log_set_debug_level(level);
179         TDM_SNPRINTF(reply, len, "debug level: %d\n", level);
180
181         if (*end == '@') {
182                 char *arg = end + 1;
183
184                 tdm_display_enable_debug_module((const char *)arg);
185
186                 TDM_SNPRINTF(reply, len, "debugging... '%s'\n", arg);
187         }
188 }
189
190 static void
191 _tdm_monitor_server_log_path(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
192 {
193         static int old_stdout = -1;
194         char fd_name[TDM_PATH_LEN];
195         char *path;
196
197         if (argc < 3) {
198                 _tdm_monitor_server_usage(argv[0], reply, len);
199                 return;
200         }
201
202         if (old_stdout == -1)
203                 old_stdout = dup(STDOUT_FILENO);
204
205         path = argv[2];
206         TDM_DBG_RETURN_IF_FAIL(path != NULL);
207
208         tdm_log_enable_dlog(0);
209
210         if (!strncmp(path, "dlog", 4)) {
211                 tdm_log_enable_dlog(1);
212                 goto done;
213         } else if (!strncmp(path, "console", 7))
214                 snprintf(fd_name, TDM_PATH_LEN, "/proc/%d/fd/1", pid);
215         else {
216                 if (path[0] == '/')
217                         snprintf(fd_name, TDM_PATH_LEN, "%s", path);
218                 else {
219                         if (cwd)
220                                 snprintf(fd_name, TDM_PATH_LEN, "%s/%s", cwd, path);
221                         else
222                                 snprintf(fd_name, TDM_PATH_LEN, "%s", path);
223                 }
224                 tdm_log_enable_color(0);
225         }
226
227         if (tdm_display_enable_path((const char*)fd_name) != TDM_ERROR_NONE) {
228                 TDM_SNPRINTF(reply, len, "failed: '%s'\n", path);
229                 return;
230         }
231
232 done:
233         TDM_SNPRINTF(reply, len, "log path: '%s'\n", path);
234 }
235
236 static void
237 _tdm_monitor_server_choose_commit_per_vblank_mode(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
238 {
239         int output_idx;
240         int mode;
241         char *arg;
242         char *end;
243         tdm_error err;
244
245         /* TODO: do we have to provide an ability to choose commit_per_vblank mode outside? */
246
247         if (argc < 4) {
248                 _tdm_monitor_server_usage(argv[0], reply, len);
249                 return;
250         }
251
252         arg = argv[2];
253         output_idx = strtol(arg, &end, 10);
254
255         arg = argv[3];
256         mode = strtol(arg, &end, 10);
257
258         err = tdm_output_choose_commit_per_vblank_mode(tdm_display_get_output(dpy, output_idx, NULL), mode);
259         if (err != TDM_ERROR_NONE) {
260                 TDM_SNPRINTF(reply, len, "an error: output_idx or mode is wrong\n");
261                 return;
262         }
263
264         TDM_SNPRINTF(reply, len, "the mode's been set\n");
265 }
266
267 static void
268 _tdm_monitor_server_fps(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
269 {
270         int enable;
271         char *arg;
272         char *end;
273
274         if (argc < 3) {
275                 _tdm_monitor_server_usage(argv[0], reply, len);
276                 return;
277         }
278
279         arg = argv[2];
280         enable = strtol(arg, &end, 10);
281
282         tdm_display_enable_fps(dpy, enable);
283
284         TDM_SNPRINTF(reply, len, "%s to print fps\n", (enable) ? "enable" : "disable");
285 }
286
287 static void
288 _tdm_monitor_server_vblank_list(unsigned int pid, char *cwd, int argc, char *argv[],
289                                                                 char *reply, int *len, tdm_display *dpy)
290 {
291         tdm_vblank_get_vblank_list_information(dpy, reply, len);
292 }
293
294 static void
295 _tdm_monitor_server_vblank_fps(unsigned int pid, char *cwd, int argc, char *argv[],
296                                                            char *reply, int *len, tdm_display *dpy)
297 {
298         unsigned int target_pid, fps;
299         char *arg;
300         char *end;
301         char name[TDM_NAME_LEN];
302         tdm_error ret;
303
304         if (argc < 3) {
305                 _tdm_monitor_server_usage(argv[0], reply, len);
306                 return;
307         }
308
309         arg = argv[2];
310         target_pid = strtol(arg, &end, 10);
311
312         if (*end == ',') {
313                 arg = end + 1;
314                 end = strtostr(name, TDM_NAME_LEN, arg, TDM_DELIM);
315         } else {
316                 strncpy(name, TDM_VBLANK_DEFAULT_NAME, TDM_NAME_LEN - 1);
317                 name[TDM_NAME_LEN - 1] = '\0';
318         }
319
320         if (*end != '@') {
321                 TDM_SNPRINTF(reply, len, "failed: no fps value\n");
322                 return;
323         }
324
325         arg = end + 1;
326         fps = strtol(arg, &end, 10);
327
328         ret = tdm_vblank_set_client_vblank_fps(target_pid, name, fps);
329         if (ret != TDM_ERROR_NONE) {
330                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to '%s' client vblank(PID:%u)\n", fps, name, target_pid);
331                 return;
332         }
333
334         TDM_SNPRINTF(reply, len, "success: '%u' fps for '%s' client vblank(PID:%u)\n", fps, name, target_pid);
335 }
336
337 static void
338 _tdm_monitor_server_global_fps(unsigned int pid, char *cwd, int argc, char *argv[],
339                                                            char *reply, int *len, tdm_display *dpy)
340 {
341         unsigned int fps;
342         char *arg;
343         char *end;
344         tdm_error ret;
345
346         if (argc < 3) {
347                 _tdm_monitor_server_usage(argv[0], reply, len);
348                 return;
349         }
350
351         arg = argv[2];
352         fps = strtol(arg, &end, 10);
353
354         if (fps > 0)
355                 ret = tdm_vblank_enable_global_fps(1, fps);
356         else
357                 ret = tdm_vblank_enable_global_fps(0, 0);
358
359         if (ret != TDM_ERROR_NONE) {
360                 TDM_SNPRINTF(reply, len, "can't set '%u' fps to global fps\n", fps);
361                 return;
362         }
363
364         TDM_SNPRINTF(reply, len, "success: '%u' global fps\n", fps);
365 }
366
367 static void
368 _tdm_monitor_server_prop(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
369 {
370         tdm_output *output;
371         tdm_output *layer = NULL;
372         int output_idx, layer_idx = -1;
373         int cnt, i, done = 0;
374         tdm_value value;
375         char temp[TDM_PATH_LEN];
376         char *prop_name;
377         char *arg;
378         char *end;
379         tdm_error ret;
380         const tdm_prop *props;
381
382         if (argc < 3) {
383                 _tdm_monitor_server_usage(argv[0], reply, len);
384                 return;
385         }
386
387         snprintf(temp, TDM_PATH_LEN, "%s", argv[2]);
388         arg = temp;
389
390         output_idx = strtol(arg, &end, 10);
391         if (*end == ',') {
392                 arg = end + 1;
393                 layer_idx = strtol(arg, &end, 10);
394         }
395
396         if (*end != ':') {
397                 TDM_SNPRINTF(reply, len, "failed: no prop_name\n");
398                 return;
399         }
400
401         arg = end + 1;
402         prop_name = strtok_r(arg, ",", &end);
403         if (!prop_name) {
404                 TDM_SNPRINTF(reply, len, "failed: get prop_name by strtok_r\n");
405                 return;
406         }
407
408         if (*end == '\0') {
409                 TDM_SNPRINTF(reply, len, "failed: no value\n");
410                 return;
411         }
412
413         arg = strtok_r(NULL, TDM_DELIM, &end);
414         if (!arg) {
415                 TDM_SNPRINTF(reply, len, "failed: get arg by strtok_r\n");
416                 return;
417         }
418         value.u32 = strtol(arg, &end, 10);
419
420         output = tdm_display_get_output(dpy, output_idx, &ret);
421         TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
422
423         if (layer_idx != -1) {
424                 layer = tdm_output_get_layer(output, layer_idx, &ret);
425                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && layer != NULL);
426         }
427
428         if (layer) {
429                 ret = tdm_layer_get_available_properties(layer, &props, &cnt);
430                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
431
432                 for (i = 0; i < cnt; i++) {
433                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
434                                 ret = tdm_layer_set_property(layer, props[i].id, value);
435                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
436                                 done = 1;
437                                 break;
438                         }
439                 }
440         } else {
441                 ret = tdm_output_get_available_properties(output, &props, &cnt);
442                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
443
444                 for (i = 0; i < cnt; i++) {
445                         if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
446                                 ret = tdm_output_set_property(output, props[i].id, value);
447                                 TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
448                                 done = 1;
449                                 break;
450                         }
451                 }
452         }
453
454         if (done)
455                 TDM_SNPRINTF(reply, len, "done: %s:%d \n", prop_name, value.u32);
456         else
457                 TDM_SNPRINTF(reply, len, "no '%s' propperty \n", prop_name);
458 }
459
460 static void
461 _tdm_monitor_server_dump(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
462 {
463         if (argc < 3) {
464                 _tdm_monitor_server_usage(argv[0], reply, len);
465                 return;
466         }
467
468         tdm_display_enable_dump(dpy, (const char*)argv[2], reply, len);
469 }
470
471 static void
472 _tdm_monitor_server_punch(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
473 {
474         char *arg, *end;
475         unsigned int output_id, layer_id;
476         tdm_output *output;
477         tdm_layer *layer;
478         tbm_surface_h buffer;
479
480         arg = argv[2];
481
482         output_id = strtol(arg, &end, 10);
483         output = tdm_display_get_output(dpy, output_id, NULL);
484         if (!output) {
485                 TDM_SNPRINTF(reply, len, "not found output\n");
486                 return;
487         }
488         if (*end != ',') {
489                 TDM_SNPRINTF(reply, len, "not found ',<layer_idx>'\n");
490                 return;
491         }
492
493         arg = end + 1;
494         layer_id = strtol(arg, &end, 10);
495         layer = tdm_output_get_layer(output, layer_id, NULL);
496         if (!layer) {
497                 TDM_SNPRINTF(reply, len, "not found layer\n");
498                 return;
499         }
500
501         buffer = tdm_layer_get_displaying_buffer(layer, NULL);
502         if (!buffer) {
503                 TDM_SNPRINTF(reply, len, "not found buffer\n");
504                 return;
505         }
506
507         if (*end == ':') {
508                 tdm_pos pos = {0,};
509
510                 arg = end + 1;
511                 pos.w = strtol(arg, &end, 10);
512                 TDM_EXIT_IF_FAIL(*end == 'x');
513                 arg = end + 1;
514                 pos.h = strtol(arg, &end, 10);
515                 if (*end == '+') {
516                         arg = end + 1;
517                         pos.x = strtol(arg, &end, 10);
518                         TDM_EXIT_IF_FAIL(*end == '+');
519                         arg = end + 1;
520                         pos.y = strtol(arg, &end, 10);
521                 }
522
523                 tdm_helper_clear_buffer_pos(buffer, &pos);
524         } else
525                 tdm_helper_clear_buffer(buffer);
526 }
527
528 static struct {
529         const char *opt;
530         void (*func)(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy);
531         const char *desc;
532         const char *arg;
533         const char *ex;
534 } option_proc[] = {
535         {
536                 "info", _tdm_monitor_server_query,
537                 "show tdm output, layer information", NULL, NULL
538         },
539         {
540                 "trace", _tdm_monitor_server_protocol_trace,
541                 "enable/disable the wl protocol",
542                 "<enable>",
543                 "0 or 1"
544         },
545         {
546                 "dpms", _tdm_monitor_server_dpms,
547                 "set output dpms", "<output_idx>:<dpms>", "0:3 or 0:0"
548         },
549         {
550                 "ttrace_vblank", _tdm_monitor_server_ttrace_vblank,
551                 "enable/disable the vblank for ttrace [0:disable, 1:server, 2:clients]",
552                 "<enable>[@<output_idx>]", "0 or 1 or 2 or 1@0 or 2@0 or 1@1 or 2@1"
553         },
554         {
555                 "debug", _tdm_monitor_server_debug,
556                 "set the debug level and modules(module: none, mutex, buffer, thread, vblank)",
557                 "<level>[@<module1>[,<module2>]]",
558                 NULL
559         },
560         {
561                 "log_path", _tdm_monitor_server_log_path,
562                 "set the log path (console,dlog,filepath)",
563                 "<path>",
564                 "console"
565         },
566         {
567                 "choose_commit_per_vblank_mode", _tdm_monitor_server_choose_commit_per_vblank_mode,
568                 "choose a commit_per_vblank mode for the output",
569                 "<output_idx> <mode>",
570                 "0 1 or 1 2 or 2 0"
571         },
572         {
573                 "fps", _tdm_monitor_server_fps,
574                 "enable/disable to print fps",
575                 "<enable>",
576                 "0 or 1"
577         },
578         {
579                 "vblank_list", _tdm_monitor_server_vblank_list,
580                 "print the client vblank list",
581                 NULL,
582                 NULL
583         },
584         {
585                 "vblank_fps", _tdm_monitor_server_vblank_fps,
586                 "set the client vblank fps for the given process ID and client vblank name",
587                 "<pid>[,<vblank_name>]@<fps>",
588                 NULL
589         },
590         {
591                 "global_fps", _tdm_monitor_server_global_fps,
592                 "set the global vblank fps for the entire system",
593                 "<fps>",
594                 NULL
595         },
596         {
597                 "prop", _tdm_monitor_server_prop,
598                 "set the property of a output or a layer",
599                 "<output_idx>[,<layer_idx>]:<prop_name>,<value>",
600                 NULL
601         },
602         {
603                 "dump", _tdm_monitor_server_dump,
604                 "dump buffers (type: none, layer, pp, capture, current)\n"
605                 "\t\t  layer, pp, capture - start to dump buffers of layer, pp, capture\n"
606                 "\t\t  none               - stop to dump buffers\n"
607                 "\t\t  current            - dump the current buffer of all layers",
608                 "<object_type1>[,<object_type2>[,...]][@<directory_path>]",
609                 NULL
610         },
611         {
612                 "punch", _tdm_monitor_server_punch,
613                 "punch a layer",
614                 "<output_idx>,<layer_idx>[:<w>x<h>[+<x>+<y>]]",
615                 NULL
616         },
617 };
618
619 static void
620 _tdm_monitor_server_usage(char *app_name, char *reply, int *len)
621 {
622         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
623         int i;
624
625         TDM_SNPRINTF(reply, len, "usage: %s \n\n", app_name);
626
627         for (i = 0; i < opt_size; i++) {
628                 TDM_SNPRINTF(reply, len, "\t-%s\t%s\n", option_proc[i].opt, option_proc[i].desc);
629                 if (option_proc[i].arg)
630                         TDM_SNPRINTF(reply, len, "\t\t  %s\n", option_proc[i].arg);
631                 if (option_proc[i].ex)
632                         TDM_SNPRINTF(reply, len, "\t\t  ex) %s\n", option_proc[i].ex);
633                 TDM_SNPRINTF(reply, len, "\n");
634         }
635 }
636
637 static void
638 _tdm_monitor_server_command(unsigned int pid, char *cwd, tdm_display *dpy, int argc, char *argv[], char *reply, int *len)
639 {
640         int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
641         int i;
642
643         if (argc < 2) {
644                 _tdm_monitor_server_usage(argv[0], reply, len);
645                 return;
646         }
647
648         for (i = 0; i < opt_size; i++) {
649                 if (argv[1][0] == '-' && !strncmp(argv[1] + 1, option_proc[i].opt, 32)) {
650                         if (option_proc[i].func) {
651                                 option_proc[i].func(pid, cwd, argc, argv, reply, len, dpy);
652                                 return;
653                         } else {
654                                 TDM_SNPRINTF(reply, len, "'%s' not implemented.\n", argv[1]);
655                                 return;
656                         }
657                 }
658         }
659
660         _tdm_monitor_server_usage(argv[0], reply, len);
661         return;
662 }
663
664
665 INTERN void
666 tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len)
667 {
668         unsigned int pid;
669         char cwd[1024];
670         int argc = 0;
671         char *argv[TDM_DBG_SERVER_ARGS_MAX] = {0,};
672         char temp[1024];
673         char *arg;
674         char *end = NULL, *e;
675
676         snprintf(temp, sizeof(temp), "%s", options);
677
678         arg = strtok_r(temp, " ", &end);
679         if (!arg) {
680                 TDM_SNPRINTF(reply, len, "no pid for tdm-monitor");
681                 return;
682         }
683         pid = strtol(arg, &e, 10);
684
685         arg = strtok_r(NULL, " ", &end);
686         if (!arg) {
687                 TDM_SNPRINTF(reply, len, "no cwd for tdm-monitor");
688                 return;
689         }
690         snprintf(cwd, sizeof(cwd), "%s", arg);
691
692         TDM_DBG("pid(%d) cwd(%s)", pid, cwd);
693
694         argv[argc] = strtok_r(NULL, " ", &end);
695         while (argv[argc]) {
696                 argc++;
697                 if (argc == TDM_DBG_SERVER_ARGS_MAX) {
698                         TDM_SNPRINTF(reply, len, "too many arguments for tdm-monitor");
699                         break;
700                 }
701                 argv[argc] = strtok_r(NULL, " ", &end);
702         }
703
704         _tdm_monitor_server_command(pid, cwd, dpy, argc, argv, reply, len);
705 }
706 /* LCOV_EXCL_STOP */