Revise the time buffer array size
[platform/core/multimedia/mmsvc-core.git] / server / src / muse_server_private.c
1 /*
2  * muse-server
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include "muse_server_private.h"
23 #include <sys/file.h>
24 #include <sys/syscall.h>
25 #include <gst/gst.h>
26 #include <syslog.h>
27
28 #if !GLIB_CHECK_VERSION(2, 58, 0)
29 #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
30 #endif
31
32 #ifdef MUSE_REGISTER_VIP
33 #include <proc_stat.h>
34 #endif
35
36 #ifdef MUSE_USE_LWIPC
37 #include <lwipc.h>
38 #define MUSE_LWIPC_WAIT_TIME                    1000
39 #endif
40
41
42 static const char *channel_name[MUSE_CHANNEL_MAX] = {
43         "msg",
44         "data"
45 };
46
47 static const char *UDS_files[MUSE_CHANNEL_MAX] = {MUSE_SOCK_FILE0, MUSE_SOCK_FILE1};
48
49 static muse_server_h muse_server;
50
51 static const char *module_cmd[MUSE_MODULE_COMMAND_MAX] = {
52         "initialize",
53         "shutdown",
54         "debug_info_dump",
55         "create_server_ack",
56         "resource_not_available",
57         "external_storage_state_changed",
58         "create_caution",
59         "resource_manager_shutdown"
60 };
61
62 static bool _ms_attach(int fd, muse_module_callback connection_handler, gpointer module_idx);
63 static void _ms_create_new_server_from_fd(int fd[], int type);
64 static int _ms_new(muse_channel_e channel);
65 static int _ms_get_pid(int fd);
66 static void _ms_get_module_addr(int fd, intptr_t *module_addr);
67 static void _ms_check_idle_state(void);
68 static gpointer _ms_diag_check_idle_state_thread(gpointer data);
69 static gpointer _ms_diag_check_connection_event_thread(gpointer data);
70 static void _ms_lock_state(void);
71 static void _ms_unlock_state(void);
72 static gboolean _ms_connection_handler(GIOChannel *source, GIOCondition condition, gpointer data);
73 #ifdef MUSE_USE_LWIPC
74 static void _ms_wait_event(void);
75 static void _ms_diag_init(void);
76 static void _ms_diag_deinit(void);
77 static gboolean _ms_idle_cb(gpointer user_data);
78 static int _ms_open_lockfile(void);
79
80 static void _ms_wait_event(void)
81 {
82         const char *lw_event_list[] = { "/run/.wm_ready", "/tmp/avoc_ready" };
83         unsigned int count = sizeof(lw_event_list) / sizeof(char *);
84
85         if (LwipcWaitMultiEvents(lw_event_list, count, true, MUSE_LWIPC_WAIT_TIME, NULL, 0) != 0)
86                 LOGE("Fail to receive Multiple Events");
87 }
88 #endif
89
90 static bool _ms_attach(int fd, muse_module_callback connection_handler, gpointer module_idx)
91 {
92         GIOChannel *channel = NULL;
93         GSource *src = NULL;
94
95         LOGI("Enter");
96
97         muse_return_val_if_fail(muse_server, false);
98         muse_return_val_if_fail(muse_core_fd_is_valid(fd), false);
99
100         channel = g_io_channel_unix_new(fd);
101         muse_return_val_if_fail(channel, false);
102
103         src = g_io_create_watch(channel, G_IO_IN);
104         if (!src) {
105                 LOGE("g_io_create_watch() is failed");
106                 g_io_channel_unref(channel);
107                 return false;
108         }
109
110         g_source_set_callback(src, G_SOURCE_FUNC(connection_handler), module_idx, NULL);
111
112         if (g_source_attach(src, g_main_loop_get_context(muse_server->main_loop)) == 0) {
113                 LOGE("g_source_attach() is failed");
114                 g_io_channel_unref(channel);
115                 return false;
116         }
117
118         g_source_unref(src);
119
120         g_io_channel_unref(channel);
121
122         LOGI("Leave");
123
124         return true;
125 }
126
127 static void _ms_create_new_server_from_fd(int fd[], int type)
128 {
129         int i;
130         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
131
132         LOGD("Enter");
133
134         muse_return_if_fail(muse_server);
135
136         muse_server->msg_fd = fd[MUSE_CHANNEL_MSG];
137         muse_server->data_fd = fd[MUSE_CHANNEL_DATA];
138         muse_server->type = type;
139
140         for (i = 0; i < MUSE_CHANNEL_MAX; i++) {
141                 if (!_ms_attach(fd[i], _ms_connection_handler, GINT_TO_POINTER(i))) {
142                         snprintf(err_msg, sizeof(err_msg), "Fail to attach server fd %d", fd[i]);
143
144                         LOGE("%s", err_msg);
145                         ms_terminate(SIGABRT);
146                 }
147         }
148
149         LOGD("Leave");
150 }
151
152 static int _ms_new(muse_channel_e channel)
153 {
154         int fd, errsv;
155         struct sockaddr_un addr_un;
156         socklen_t address_len;
157         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
158
159         muse_return_val_if_fail(channel < MUSE_CHANNEL_MAX, MM_ERROR_INVALID_ARGUMENT);
160
161         unlink(UDS_files[channel]);
162
163         /* Create Socket */
164         fd = socket(AF_UNIX, SOCK_STREAM, 0); /* Unix Domain Socket */
165         if (!muse_core_fd_is_valid(fd)) {
166                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
167                 LOGE("socket failed sock (%d) : %s", errno, err_msg);
168                 return MUSE_ERR;
169         }
170
171         LOGD("muse server fd : %d", fd);
172
173         memset(&addr_un, 0, sizeof(addr_un));
174         addr_un.sun_family = AF_UNIX;
175         strncpy(addr_un.sun_path, UDS_files[channel], sizeof(addr_un.sun_path) - 1);
176         address_len = sizeof(addr_un);
177
178         /* Bind to filename */
179         if (bind(fd, (struct sockaddr *)&addr_un, address_len) < 0) {
180                 errsv = errno;
181                 strerror_r(errsv, err_msg, MUSE_MSG_LEN_MAX);
182                 LOGE("[%d] socket bind failed (%d) %s", fd, errsv, err_msg);
183                 muse_core_log_file_list(UDS_files[channel]);
184                 ms_log_user_group_info();
185                 if (errsv == EADDRINUSE)
186                         unlink(addr_un.sun_path);
187                 close(fd);
188                 return MUSE_ERR;
189         }
190
191         /* Setup listen queue */
192         if (listen(fd, 5) == MUSE_ERR) {
193                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
194                 LOGE("[%d] listen() failed (%d) %s", fd, errno, err_msg);
195                 muse_core_log_file_list(UDS_files[channel]);
196                 ms_log_user_group_info();
197                 close(fd);
198                 return MUSE_ERR;
199         }
200
201         if (muse_core_set_nonblocking(fd, false) < 0) /* blocking */
202                 LOGE("failed to set server socket to blocking");
203
204         return fd;
205 }
206
207 static int _ms_get_pid(int fd)
208 {
209         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
210         struct ucred credentials;
211         socklen_t length;
212
213         length = sizeof(struct ucred);
214         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &credentials, &length) < 0) {
215                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
216                 LOGE("failed to get the value of credential type %s", err_msg);
217                 return MUSE_ERR;
218         }
219
220         muse_core_update_fd_state(fd);
221
222         return credentials.pid;
223 }
224
225 static void _ms_get_module_addr(int fd, intptr_t *module_addr)
226 {
227         void *jobj;
228         int try_count = 0;
229         bool ret = true;
230         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
231         char recv_buf[MUSE_MSG_LEN_MAX] = {'\0',};
232
233         do {
234                 if (muse_core_msg_recv_fd(fd, recv_buf, MUSE_MSG_LEN_MAX, NULL) <= 0) {
235                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
236                         LOGE("failed to receive message for module %s", err_msg);
237                         return;
238                 }
239
240                 jobj = muse_core_msg_object_new(recv_buf, NULL, NULL);
241                 if (jobj) {
242                         ret = muse_core_msg_object_get_value(MSG_KEY_MODULE_ADDR, jobj, MUSE_TYPE_POINTER, module_addr);
243                         muse_core_msg_object_free(jobj);
244                         if (!ret)
245                                 LOGE("[%d] Error - module_addr %s", try_count, recv_buf);
246                         else
247                                 break;
248                 }
249         } while (++try_count < MS_RECV_TRY_COUNT_MAX);
250 }
251
252 static gboolean _ms_connection_handler(GIOChannel *source, GIOCondition condition, gpointer data)
253 {
254         int server_sockfd, client_sockfd, pid, idx, len;
255         socklen_t client_len;
256         struct sockaddr_un client_address;
257         muse_channel_e channel = GPOINTER_TO_INT(data);
258         muse_module_h m = NULL;
259         muse_module_h peeked_m = NULL;
260         muse_module_h candidate_m = NULL;
261         intptr_t module_addr = 0;
262         GQueue *instance_queue = NULL;
263         ms_connection_t *connection = NULL;
264         char time_buf[MUSE_MSG_TIME_LEN];
265
266         muse_return_val_if_fail(channel == MUSE_CHANNEL_MSG || channel == MUSE_CHANNEL_DATA, FALSE);
267
268         LOGI("Enter [%s channel]", channel_name[channel]);
269
270         muse_return_val_if_fail(muse_server, FALSE);
271
272         connection = muse_server->connection;
273         muse_return_val_if_fail(connection, FALSE);
274
275         _ms_lock_state();
276
277         if (!ms_is_server_ready()) {
278                 LOGW("Now mused state is not ready...");
279                 _ms_unlock_state();
280                 ms_terminate(SIGABRT);
281         }
282
283         server_sockfd = g_io_channel_unix_get_fd(source);
284         if (!muse_core_fd_is_valid(server_sockfd)) {
285                 LOGE("Critical Error : server %d is invalid", server_sockfd);
286                 _ms_unlock_state();
287                 muse_core_dump_fd_state(server_sockfd);
288                 ms_terminate(SIGABRT);
289         }
290
291         client_len = sizeof(client_address);
292
293         LOGI("[%d] Try to accept...", server_sockfd);
294         client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
295         if (!muse_core_fd_is_valid(client_sockfd)) {
296                 LOGE("Critical Error : accept %d is invalid", client_sockfd);
297                 muse_core_dump_fd_state(client_sockfd);
298                 close(server_sockfd);
299                 _ms_unlock_state();
300                 ms_terminate(SIGABRT);
301         }
302
303         LOGI("server : %d client [%s channel] : %d", server_sockfd, channel_name[channel], client_sockfd);
304
305         pid = _ms_get_pid(client_sockfd);
306
307         if (channel == MUSE_CHANNEL_MSG) {
308                 m = g_new0(muse_module_t, 1);
309                 SECURE_LOGI("module [%p]", m);
310                 m->ch[MUSE_CHANNEL_MSG].sock_fd = client_sockfd;
311                 m->pid = pid;
312                 g_mutex_init(&m->dispatch_lock);
313
314                 ms_ipc_create_msg_dispatch_worker(m);
315
316         } else {
317                 _ms_get_module_addr(client_sockfd, &module_addr);
318
319                 ms_connection_lock(connection);
320
321                 instance_queue = connection->instance_q;
322                 len = g_queue_get_length(instance_queue);
323
324                 m = (muse_module_h)module_addr;
325
326                 for (idx = 0; idx < len; idx++) {
327                         peeked_m = (muse_module_h)g_queue_peek_nth(instance_queue, idx);
328                         if (!peeked_m) {
329                                 LOGW("[%d] Make sure if the queue length is changed (%d = %d), which means that it was destroyed somewhere",
330                                         idx, len, g_queue_get_length(instance_queue));
331                                 continue;
332                         }
333
334                         if (peeked_m->pid != pid)
335                                 continue;
336
337                         if (!m) {
338                                 if (candidate_m) {
339                                         LOGE("muse-server can't support the error case which there are several modules now");
340                                         ms_connection_unlock(connection);
341                                         goto out;
342                                 }
343
344                                 if (!muse_core_fd_is_valid(peeked_m->ch[MUSE_CHANNEL_DATA].sock_fd))
345                                         candidate_m = peeked_m;
346                                 else
347                                         SECURE_LOGW("already paired module %p", peeked_m);
348
349                                 continue;
350                         }
351
352                         if (m != peeked_m)
353                                 continue;
354
355                         if (muse_core_fd_is_valid(m->ch[MUSE_CHANNEL_DATA].sock_fd)) {
356                                 SECURE_LOGE("[%d] %s pid %d %p you had better check if instance destroy completed properly",
357                                         client_sockfd, ms_config_get_host_name(m->idx), pid, m);
358                                 ms_connection_unlock(connection);
359                                 goto out;
360                         }
361
362                         m->ch[MUSE_CHANNEL_DATA].sock_fd = client_sockfd;
363                         SECURE_LOGI("%s (pid %d) module : %p module addr from client : %p",
364                                 ms_config_get_host_name(m->idx), pid, m, (void *)module_addr);
365                         break;
366                 }
367
368                 if (candidate_m) {
369                         m = candidate_m;
370                         m->ch[MUSE_CHANNEL_DATA].sock_fd = client_sockfd;
371                         SECURE_LOGW("[%d] %s pid %d %p restore module address at the only one null data channel",
372                                 client_sockfd, ms_config_get_host_name(m->idx), pid, m);
373                 }
374
375                 ms_connection_unlock(connection);
376
377                 ms_ipc_create_data_dispatch_worker(m);
378         }
379
380         muse_core_get_cur_time(&muse_server->tv, NULL);
381         muse_core_change_time_format((int)muse_server->tv.tv_sec, time_buf);
382         LOGW("connected time (%s)", time_buf);
383
384         _ms_unlock_state();
385
386         LOGI("Leave");
387
388         return TRUE;
389 out:
390         close(server_sockfd);
391         close(client_sockfd);
392
393         if (m) {
394                 if (channel == MUSE_CHANNEL_MSG)
395                         g_free(m);
396                 else
397                         muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
398         }
399
400         _ms_unlock_state();
401
402         LOGE("FALSE");
403
404         return FALSE;
405 }
406
407 static void _ms_check_idle_state(void)
408 {
409         ms_connection_t *connection = NULL;
410         ms_config_t *conf = NULL;
411         int instance_number, period;
412         uint32_t elapsed_time;
413         struct timespec tv;
414         static int period_idx = 1;
415         char time_buf[MUSE_MSG_TIME_LEN];
416
417         muse_return_if_fail(muse_server);
418         muse_return_if_fail(muse_server->state == MUSE_SERVER_STATE_READY);
419
420         connection = muse_server->connection;
421         muse_return_if_fail(connection);
422
423         conf = muse_server->conf;
424         muse_return_if_fail(conf);
425
426         period = ms_config_get_log_period();
427
428         if (muse_server->tv.tv_sec == 0)
429                 return;
430
431         muse_core_get_cur_time(&tv, NULL);
432
433         elapsed_time = tv.tv_sec - muse_server->tv.tv_sec;
434
435         ms_connection_lock(connection);
436
437         instance_number = g_queue_get_length(connection->instance_q);
438
439         if (elapsed_time >= (uint32_t)(period * period_idx)) {
440                 muse_core_change_time_format((int)muse_server->tv.tv_sec, time_buf);
441                 LOGW("[#%d] %u sec [period %d] [last connected time %s] total number of modules = %d ( %s)", period_idx,
442                         elapsed_time, period, time_buf, instance_number, muse_server->instance_pid_info);
443                 period_idx++;
444         }
445
446         ms_connection_unlock(connection);
447
448         if (conf->is_on_demand) {
449                 if (instance_number == 0 && elapsed_time >= (uint32_t)ms_config_get_max_idle_time()) {
450                         LOGE("Timeout exit !!! [Idle time] %u sec", elapsed_time);
451                         ms_remove_ready_file();
452                         exit(EXIT_SUCCESS);
453                 }
454         }
455 }
456
457 static gpointer _ms_diag_check_idle_state_thread(gpointer data)
458 {
459         int idle_state_wait_time = ms_config_get_idle_state_wait_time();
460
461         muse_return_val_if_fail(muse_server, NULL);
462         muse_return_val_if_fail(idle_state_wait_time > 0, NULL);
463
464         while (ms_is_server_ready()) {
465                 _ms_check_idle_state();
466                 sleep(idle_state_wait_time);
467         }
468
469         return NULL;
470 }
471
472 static gpointer _ms_diag_check_connection_event_thread(gpointer data)
473 {
474         ms_diag_t *d;
475         ms_diag_msg_t *dm = NULL;
476         muse_return_val_if_fail(muse_server, NULL);
477
478         d = &muse_server->diag;
479
480         while (ms_is_server_ready()) {
481                 dm = (ms_diag_msg_t *)g_async_queue_pop(d->msg_aq);
482                 if (!dm)
483                         continue;
484
485                 LOGD("[%p] POP message (thread stop ? %d [%s])", dm, dm->thread_stop, ms_get_command_string(dm->cmd));
486
487                 if (dm->thread_stop) {
488                         g_free(dm);
489                         break;
490                 }
491
492                 if (dm->cmd == API_CREATE) {
493                         /* can be updated if connection at the next patch */
494                 } else if (dm->cmd == API_DESTROY) {
495                         ms_check_cpu_memory();
496                 }
497
498                 g_free(dm);
499         }
500
501         return NULL;
502 }
503
504 static void _ms_lock_state(void)
505 {
506         muse_return_if_fail(muse_server);
507         g_mutex_lock(&muse_server->state_lock);
508 }
509
510 static void _ms_unlock_state(void)
511 {
512         muse_return_if_fail(muse_server);
513         g_mutex_unlock(&muse_server->state_lock);
514 }
515
516 static void _ms_diag_init(void)
517 {
518         ms_diag_t *d;
519         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
520         GError *error = NULL;
521
522         muse_return_if_fail(muse_server);
523
524         d = &muse_server->diag;
525
526         d->idle_state_thread = g_thread_try_new("diag_idle_state",
527                 _ms_diag_check_idle_state_thread, muse_server->main_loop, &error);
528         if (!d->idle_state_thread) {
529                 snprintf(err_msg, sizeof(err_msg), "diag_idle_state_thread creation failed : %s", error->message);
530                 LOGE("%s", err_msg);
531                 g_error_free(error);
532                 ms_log_process_info(muse_server->pid);
533         }
534
535         d->msg_aq = g_async_queue_new_full(g_free);
536         muse_return_if_fail(d->msg_aq);
537
538         d->conn_event_thread = g_thread_try_new("diag_connection",
539                 _ms_diag_check_connection_event_thread, muse_server->main_loop, &error);
540         if (!d->conn_event_thread) {
541                 snprintf(err_msg, sizeof(err_msg), "diag_connection_event_thread creation failed : %s", error->message);
542                 LOGE("%s", err_msg);
543                 g_error_free(error);
544                 ms_log_process_info(muse_server->pid);
545         }
546 }
547
548 static void _ms_diag_deinit(void)
549 {
550         ms_diag_t *d;
551         ms_diag_msg_t *dm;
552
553         LOGD("Enter");
554
555         muse_return_if_fail(muse_server);
556
557         d = &muse_server->diag;
558
559         dm = g_new0(ms_diag_msg_t, 1);
560
561         dm->thread_stop = TRUE;
562         LOGI("[%p] g_async_queue_push", dm);
563         g_async_queue_push_front(d->msg_aq, (gpointer)dm);
564
565         if (d->idle_state_thread) {
566                 g_thread_join(d->idle_state_thread);
567                 d->idle_state_thread = NULL;
568         }
569
570         if (d->conn_event_thread) {
571                 g_thread_join(d->conn_event_thread);
572                 d->conn_event_thread = NULL;
573         }
574
575         g_async_queue_unref(d->msg_aq);
576         d->msg_aq = NULL;
577 }
578
579 static gboolean _ms_idle_cb(gpointer user_data)
580 {
581         struct timespec tv;
582         char time_buf[MUSE_MSG_TIME_LEN];
583
584         if (!ms_create_ready_file())
585                 LOGE("%s file creation is failed", MUSE_SERVER_READY);
586
587         _ms_diag_init();
588
589         muse_core_get_cur_time(&tv, NULL);
590
591         muse_core_change_time_format((int)tv.tv_sec, time_buf);
592
593         LOGW("muse server is completed to ready (%s)", time_buf);
594
595         return G_SOURCE_REMOVE;
596 }
597
598 static void _ms_init(void)
599 {
600         int idx;
601
602         LOGD("Enter");
603
604         muse_server->system = g_new0(ms_system_t, 1);
605         ms_system_init(muse_server->system);
606
607         muse_server->conf = g_new0(ms_config_t, 1);
608         ms_config_init(muse_server->conf);
609
610         muse_server->log = g_new0(ms_log_t, 1);
611         ms_log_init(muse_server->log);
612
613         muse_server->security = g_new0(ms_security_t, 1);
614         ms_security_init(muse_server->security);
615
616         for (idx = 0; idx < muse_server->conf->host_cnt; idx++) {
617                 muse_server->module[idx] = g_new0(ms_module_t, 1);
618                 muse_server->module[idx]->idx = idx;
619                 ms_module_init(muse_server->module[idx]);
620         }
621
622 #ifdef MUSE_USE_WATCHDOG
623         muse_server->watchdog = g_new0(ms_watchdog_t, 1);
624         if (ms_watchdog_init(muse_server->watchdog) != MM_ERROR_NONE)
625                 LOGE("Fail to initialize server watchdog");
626 #endif
627
628         muse_server->connection = g_new0(ms_connection_t, 1);
629         ms_connection_init(muse_server->connection);
630
631         ms_signal_init();
632
633         g_mutex_init(&muse_server->state_lock);
634
635         muse_core_create_fd_table();
636
637         muse_server->cpu_threshold = ms_config_get_cpu_threshold();
638
639         muse_server->main_loop = g_main_loop_new(NULL, FALSE);
640         muse_return_if_fail(muse_server->main_loop);
641
642         LOGD("Leave");
643 }
644
645 static int _ms_open_lockfile(void)
646 {
647         int fd, already_running;
648         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
649         char *lockfile = NULL;
650
651         muse_return_val_if_fail(muse_server, MUSE_ERR);
652
653         lockfile = ms_config_get_lockfile();
654         muse_return_val_if_fail(lockfile, MUSE_ERR);
655
656         muse_core_remove_symlink((const char *)lockfile);
657         fd = open(lockfile, O_RDONLY);
658         if (fd == -1 && errno != ENOENT) {
659                 /* Cannot open file even though file exists. */
660                 snprintf(err_msg, sizeof(err_msg), "Cannot open lock file %s", lockfile);
661                 LOGE("open failed : %s", err_msg);
662                 return MUSE_ERR;
663         } else if (fd != -1) {
664                 already_running = flock(fd, LOCK_EX | LOCK_NB) == -1;
665                 close(fd);
666                 if (already_running) {
667                         LOGE("File already locked. There's already a server running");
668                         return MUSE_ERR;
669                 }
670         }
671
672         /* Lock file does not exist, or is not locked. Create a new lockfile and lock it. */
673         fd = open(lockfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
674         if (fd == -1) {
675                 LOGE("dataserver: Cannot create lock file");
676                 return MUSE_ERR;
677         }
678
679         if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
680                 LOGE("Can't lock the lock file \"%s\". " "Is another instance running?", lockfile);
681                 close(fd);
682                 return MUSE_ERR;
683         }
684
685         close(fd);
686
687         return MM_ERROR_NONE;
688 }
689
690 void ms_setup_syslog(void)
691 {
692         int flags = LOG_CONS|LOG_NDELAY|LOG_PID;
693         if (isatty(STDOUT_FILENO))
694                 flags |= LOG_PERROR;
695
696         openlog("mused", flags, LOG_DAEMON);
697         LOGD("openlog - mused");
698 }
699
700 void ms_fork(int *notify_fd)
701 {
702         pid_t pid;
703         int fds[2];
704         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
705         char msg[MUSE_MSG_LEN_MAX] = {'\0',};
706
707         if (pipe(fds) == MUSE_ERR) {
708                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
709                 LOGE("Failed to create pipe to get child status: %s", err_msg);
710                 exit(EXIT_FAILURE);
711         }
712
713         if ((pid = fork()) < 0) {
714                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
715                 LOGE("Error: fork() failed: %s", err_msg);
716                 exit(EXIT_FAILURE);
717         } else if (pid != 0) {
718                 close(fds[1]);
719                 /* Read in a string from the pipe */
720                 if (read(fds[0], msg, sizeof(msg)) <= 0) {
721                         LOGE("Failed to read from a file descriptor [%d]", fds[0]);
722                         close(fds[0]);
723                         return;
724                 }
725                 close(fds[0]);
726
727                 /* Parent process closes up output side of pipe */
728                 if (!strcmp(msg, MSG_DONE)) {
729                         LOGI("Successfully daemonized");
730                         exit(EXIT_SUCCESS);
731                 } else {
732                         LOGE("Daemonizing failed after fork");
733                         exit(EXIT_FAILURE);
734                 }
735         } else if (pid == 0) {
736                 /* Child process closes up input side of pipe */
737                 close(fds[0]);
738                 *notify_fd = fds[1];
739         }
740 }
741
742 pid_t ms_daemonize(int *notify_fd)
743 {
744         pid_t pid;
745         int fd, result;
746
747         muse_return_val_if_fail(notify_fd, MUSE_ERR);
748
749         ms_fork(notify_fd);
750
751         if ((pid = setsid()) < 0) {
752                 LOGE("create new session");
753                 exit(EXIT_FAILURE);
754         }
755
756         /* change the file mode mask */
757         umask(0);
758
759         result = chdir("/");
760         LOGD("result = %d sid: %d pgid: %d pid: %d ppid: %d", result, (int)getsid(0), (int)getpgid(0), (int)pid, (int)getppid());
761
762         /* redirect fds to /dev/null */
763         fd = open("/dev/null", O_RDWR);
764         if (!muse_core_fd_is_valid(fd)) {
765                 LOGE("Critical Error : %d is invalid", fd);
766                 exit(EXIT_SUCCESS);
767         }
768
769         close(STDIN_FILENO);
770         close(STDOUT_FILENO);
771         close(STDERR_FILENO);
772
773         dup2(fd, STDIN_FILENO);
774         dup2(fd, STDOUT_FILENO);
775         dup2(fd, STDERR_FILENO);
776
777         close(fd);
778
779         return pid;
780 }
781
782 void ms_daemonize_complete(int notify_fd)
783 {
784         LOGD("Enter");
785
786         muse_return_if_fail(muse_core_fd_is_valid(notify_fd));
787
788 #ifdef MUSE_REGISTER_VIP
789         proc_stat_set_vip_process();
790 #endif
791
792         write(notify_fd, MSG_DONE, strlen(MSG_DONE) + 1);
793         LOGW("[%d] Notify parent process that child initialization is done", notify_fd);
794         close(notify_fd);
795
796         LOGD("Leave");
797 }
798
799 void ms_gst_init(char **cmd)
800 {
801         gint argc = 0;
802         gchar **argv = NULL;
803         GError *err = NULL;
804         gboolean ret = FALSE;
805         int gst_param_cnt;
806
807 #ifdef MUSE_TTRACE_LOG
808         trace_begin("MUSE:gst_init");
809 #endif
810
811         gst_param_cnt = ms_config_get_gst_param_cnt();
812
813         /* add gst_param */
814         argv = g_malloc0(sizeof(gchar *) * (gst_param_cnt + 1));
815
816         argv[argc++] = (gchar *)cmd[0];
817         for (; argc <= gst_param_cnt; argc++) {
818                 argv[argc] = ms_config_get_gst_param_str(argc - 1);
819                 LOGI("%d %s", argc, argv[argc]);
820         }
821
822         /* initializing gstreamer */
823         ret = gst_init_check(&argc, &argv, &err);
824         if (!ret) {
825                 LOGE("Could not initialize GStreamer: %s ", err ? err->message : "unknown error occurred");
826                 if (err)
827                         g_error_free(err);
828         }
829
830         LOGI("gst_init_check is completed");
831
832         /* release */
833         g_free(argv);
834
835         LOGI("complete to initialize gstreamer");
836
837 #ifdef MUSE_TTRACE_LOG
838         trace_end();
839 #endif
840 }
841
842 void ms_gst_preload_plugin(void)
843 {
844         char *token = NULL;
845         char *saveptr = NULL;
846         char plugin_path[128];
847         const char *delimeters = " ,";
848         gchar *gst_preload_plugins = g_strdup(ms_config_get_gst_preload_plugins());
849         GstPlugin *plugin = NULL;
850
851         muse_return_if_fail(gst_preload_plugins);
852
853         LOGI("preload plugins [%s]", gst_preload_plugins);
854
855         token = strtok_r(gst_preload_plugins, delimeters, &saveptr);
856         while (token) {
857                 snprintf(plugin_path, sizeof(plugin_path), "%s/gstreamer-1.0/libgst%s.so", LIBDIR, token);
858
859                 LOGI("    plugin path : %s", plugin_path);
860
861                 plugin = gst_plugin_load_file(plugin_path, NULL);
862                 if (plugin)
863                         gst_object_unref(plugin);
864                 else
865                         LOGW("failed to load plugin [%s]", plugin_path);
866
867                 token = strtok_r(NULL, delimeters, &saveptr);
868         }
869
870         g_free(gst_preload_plugins);
871
872         LOGI("Leave");
873 }
874
875 int ms_pidfile_create(const char *path, pid_t pid)
876 {
877         int fd;
878         struct flock lock;
879         char pid_buf[MUSE_MSG_LEN] = {'\0',};
880         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
881
882         muse_return_val_if_fail(path, MM_ERROR_INVALID_ARGUMENT);
883         muse_core_remove_symlink(path);
884         fd = open(path, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
885
886         if (!muse_core_fd_is_valid(fd)) {
887                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
888                 LOGE("Fail to open pidfile [%s] : %s", path, err_msg);
889                 return MM_ERROR_FILE_NOT_FOUND;
890         }
891
892         lock.l_type = F_WRLCK;
893         lock.l_start = 0;
894         lock.l_whence = SEEK_SET;
895         lock.l_len = 0;
896
897         if (fcntl(fd, F_SETLK, &lock) < 0) {
898                 if (errno != EACCES && errno != EAGAIN) {
899                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
900                         LOGE("Fail to lock pidfile [%s] : %s", path, err_msg);
901                 } else {
902                         LOGE("process is already running");
903                 }
904                 close(fd);
905                 return MM_ERROR_FILE_INTERNAL;
906         }
907
908         if (ftruncate(fd, 0) < 0) {
909                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
910                 LOGE("Fail to truncate pidfile [%s] : %s", path, err_msg);
911                 close(fd);
912                 return MM_ERROR_FILE_INTERNAL;
913         }
914
915         memset(pid_buf, 0, sizeof(pid_buf));
916         snprintf(pid_buf, sizeof(pid_buf), "%u", pid);
917
918         if (write(fd, pid_buf, strlen(pid_buf)) != (int)strlen(pid_buf)) {
919                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
920                 LOGE("Fail to write pid to pidfile [%s] : %s", path, err_msg);
921                 close(fd);
922                 return MM_ERROR_FILE_WRITE;
923         }
924
925         close(fd);
926         return MM_ERROR_NONE;
927 }
928
929 void ms_init(char **argv)
930 {
931         int idx;
932         int notify_fd;
933         muse_module_cmd_dispatchfunc *cmd_dispatcher = NULL;
934
935         LOGD("Enter");
936
937         muse_server = g_new0(muse_server_t, 1);
938
939         ms_setup_syslog();
940
941         muse_server->pid = ms_daemonize(&notify_fd);
942
943         if (ms_pidfile_create(MUSE_DEFAULT_PIDFILE, muse_server->pid) != MM_ERROR_NONE)
944                 exit(EXIT_FAILURE);
945         else
946                 LOGD("MUSE_DEFAULT_PIDFILE(%s) file was created", MUSE_DEFAULT_PIDFILE);
947
948         _ms_init();
949
950         muse_return_if_fail(_ms_open_lockfile() == MM_ERROR_NONE);
951
952         ms_new();
953
954         ms_daemonize_complete(notify_fd);
955
956 #ifdef MUSE_TTRACE_LOG
957         trace_end();
958 #endif
959
960         ms_system_subscribe_external_event(muse_server->system);
961
962 #ifdef MUSE_USE_WATCHDOG
963         if (!ms_watchdog_attach(muse_server->watchdog)) {
964                 LOGE("watchdog thread failed");
965                 ms_log_process_info(muse_server->pid);
966                 return;
967         }
968 #endif
969
970         ms_gst_init(argv);
971
972 #ifdef MUSE_TTRACE_LOG
973         trace_begin("MUSE:preloading module");
974 #endif
975         for (idx = 0; idx < ms_config_get_host_cnt(); idx++) {
976                 if (0 == strncmp(ms_config_get_preloaded_value(idx), "yes", strlen("yes") + 1)) {
977                         g_module_symbol(ms_module_open(idx), CMD_DISPATCHER, (gpointer *)&cmd_dispatcher);
978                         if (cmd_dispatcher && cmd_dispatcher[MUSE_MODULE_COMMAND_INITIALIZE])
979                                 cmd_dispatcher[MUSE_MODULE_COMMAND_INITIALIZE](NULL);
980                 }
981         }
982 #ifdef MUSE_TTRACE_LOG
983         trace_end();
984 #endif
985
986 #ifdef MUSE_TTRACE_LOG
987         trace_begin("MUSE:preloading GST module");
988 #endif
989         ms_gst_preload_plugin();
990 #ifdef MUSE_TTRACE_LOG
991         trace_end();
992 #endif
993
994 #ifdef MUSE_GCOV_TEST
995         muse_core_setenv("GCOV_PREFIX", "/tmp", 1);
996 #endif
997
998         LOGD("Leave");
999 }
1000
1001 muse_server_h ms_get_instance(void)
1002 {
1003         return muse_server;
1004 }
1005
1006 gboolean ms_check_module_idx(int idx)
1007 {
1008         int module_cnt = ms_config_get_host_cnt();
1009
1010         if (idx < 0 || idx >= module_cnt) {
1011                 LOGE("%d error - the number of modules is %d", idx, module_cnt);
1012                 return FALSE;
1013         }
1014
1015         return TRUE;
1016 }
1017
1018 ms_module_t *ms_get_module_instance(int idx)
1019 {
1020         muse_return_val_if_fail(ms_check_module_idx(idx), NULL);
1021
1022         return muse_server->module[idx];
1023 }
1024
1025 int ms_deinit(void)
1026 {
1027         int retval = MUSE_ERR;
1028         int idx;
1029
1030         LOGD("Enter");
1031
1032         muse_return_val_if_fail(muse_server, retval);
1033         muse_return_val_if_fail(muse_server->conf, retval);
1034         muse_return_val_if_fail(muse_server->connection, retval);
1035         muse_return_val_if_fail(muse_server->log, retval);
1036         muse_return_val_if_fail(muse_server->security, retval);
1037         muse_return_val_if_fail(muse_server->watchdog, retval);
1038
1039         ms_recursive_rmdir(MUSE_DATA_ROOT_PATH);
1040
1041         ms_set_state(MUSE_SERVER_STATE_IDLE);
1042
1043         _ms_diag_deinit();
1044
1045 #ifdef MUSE_USE_WATCHDOG
1046         ms_watchdog_detach(muse_server->watchdog);
1047
1048         if (ms_watchdog_deinit(muse_server->watchdog) == MM_ERROR_NONE)
1049                 free(muse_server->watchdog);
1050         else
1051                 LOGE("Fail to deinitialize server watchdog");
1052 #endif
1053
1054         ms_remove_ready_file();
1055
1056         retval = muse_server->retval;
1057         muse_core_fd_close(muse_server->msg_fd);
1058         muse_core_fd_close(muse_server->data_fd);
1059         for (idx = 0; idx < MUSE_CHANNEL_MAX; idx++) {
1060                 if (remove(UDS_files[idx]) == MUSE_ERR)
1061                         LOGE("remove %s failed", UDS_files[idx]);
1062         }
1063
1064         if (remove(MUSE_DEFAULT_PIDFILE) == -1)
1065                 LOGE("remove %s failed [errno : %d]", MUSE_DEFAULT_PIDFILE, errno);
1066
1067         for (idx = 0; idx < muse_server->conf->host_cnt; idx++)
1068                 ms_module_deinit(muse_server->module[idx]);
1069
1070         ms_security_deinit(muse_server->security);
1071         muse_server->security = NULL;
1072
1073         ms_system_deinit(muse_server->system);
1074         muse_server->system = NULL;
1075
1076         ms_log_deinit(muse_server->log);
1077         muse_server->log = NULL;
1078
1079         ms_config_deinit(muse_server->conf);
1080         muse_server->conf = NULL;
1081
1082         ms_connection_deinit(muse_server->connection);
1083         muse_server->connection = NULL;
1084
1085         muse_core_destroy_fd_table();
1086
1087         ms_deinit_bufmgr();
1088
1089         g_mutex_clear(&muse_server->state_lock);
1090
1091         g_free(muse_server);
1092         muse_server = NULL;
1093
1094         LOGD("Leave");
1095         return retval;
1096 }
1097
1098 void ms_check_cpu_memory(void)
1099 {
1100         int used_pss, memory_threshold, cpu_usage;
1101         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
1102         ms_connection_t *connection = NULL;
1103
1104         muse_return_if_fail(muse_server);
1105
1106         connection = muse_server->connection;
1107         muse_return_if_fail(connection);
1108
1109         ms_connection_lock(connection);
1110
1111         if (g_queue_is_empty(connection->instance_q) && ms_is_server_ready()) {
1112                 used_pss = ms_system_get_memory_usage(muse_server->pid);
1113                 cpu_usage = muse_core_get_process_cpu_usage(muse_server->pid);
1114
1115                 LOGW("[%d] Proportional set size %d (KByte) (CPU %d %%)", muse_server->pid, used_pss, cpu_usage);
1116                 memory_threshold = ms_config_get_memory_threshold();
1117
1118                 if (used_pss >= memory_threshold || cpu_usage >= muse_server->cpu_threshold) {
1119                         ms_set_state(MUSE_SERVER_STATE_IDLE);
1120                         ms_log_process_info(muse_server->pid);
1121
1122                         snprintf(err_msg, sizeof(err_msg), "[Memory Leak] %d >= %d (KByte) [CPU] %d >= %d %%",
1123                                 used_pss, memory_threshold, cpu_usage, muse_server->cpu_threshold);
1124
1125                         LOGE("%s", err_msg);
1126                         ms_connection_unlock(connection);
1127                         ms_terminate(SIGTERM);
1128                 }
1129
1130                 muse_core_remove_all_fd_table();
1131         } else {
1132                 LOGI("skip cpu memory check due to instance queue length : %d", g_queue_get_length(connection->instance_q));
1133         }
1134
1135         ms_connection_unlock(connection);
1136 }
1137
1138 void ms_new(void)
1139 {
1140         int fd[MUSE_CHANNEL_MAX];
1141         int i, j;
1142
1143         for (i = 0; i < MUSE_CHANNEL_MAX; i++) {
1144                 if (ms_config_is_on_demand() && i == MUSE_CHANNEL_MSG)
1145                         fd[i] = SD_LISTEN_FDS_START;
1146                 else
1147                         fd[i] = _ms_new(i);
1148
1149                 if (!muse_core_fd_is_valid(fd[i])) {
1150                         LOGE("Failed to create socket server %d", i);
1151                         for (j = 0; j < i; j++)
1152                                 close(fd[j]);
1153                         return;
1154                 }
1155         }
1156
1157         _ms_create_new_server_from_fd(fd, READ | PERSIST);
1158 }
1159
1160 void ms_run(void)
1161 {
1162         LOGW("Enter");
1163
1164         muse_return_if_fail(muse_server->main_loop);
1165
1166         muse_return_if_fail(g_idle_add_full(G_PRIORITY_HIGH, _ms_idle_cb, NULL, NULL) > 0);
1167
1168         LOGI("g_main_loop_run");
1169         g_main_loop_run(muse_server->main_loop);
1170
1171         LOGW("Leave");
1172 }
1173
1174 void ms_cmd_dispatch(muse_module_h m, muse_module_command_e cmd)
1175 {
1176         muse_module_cmd_dispatchfunc *cmd_dispatcher = NULL;
1177
1178         if (m->ch[MUSE_CHANNEL_MSG].dll_handle &&
1179                 g_module_symbol(m->ch[MUSE_CHANNEL_MSG].dll_handle, CMD_DISPATCHER, (gpointer *)&cmd_dispatcher)) {
1180                 if (cmd_dispatcher && cmd_dispatcher[cmd])
1181                         cmd_dispatcher[cmd](m);
1182         }
1183 }
1184
1185 void ms_terminate(int signo)
1186 {
1187         muse_return_if_fail(muse_server);
1188
1189         ms_set_state(MUSE_SERVER_STATE_IDLE);
1190
1191         LOGE("send signal %d to process %d", signo, muse_server->pid);
1192         raise(signo);
1193 }
1194
1195 int ms_get_pid(muse_module_h m)
1196 {
1197         muse_return_val_if_fail(m, MUSE_ERR);
1198         return m->pid;
1199 }
1200
1201 void ms_log_process_info(int pid)
1202 {
1203         muse_core_log_process_thread_info(pid);
1204
1205         muse_core_log_process_opened_fds(pid);
1206
1207         muse_core_log_process_cpu_memory(pid);
1208 }
1209
1210 void ms_log_user_group_info(void)
1211 {
1212         uid_t uid;
1213         gid_t gid;
1214         char buffer[MUSE_MSG_MAX_LENGTH];
1215         struct passwd pwbuf;
1216         struct passwd *pwbufp;
1217         struct group gbuf;
1218         struct group *gbufp;
1219
1220         uid = getuid();
1221         gid = getgid();
1222
1223         getpwuid_r(uid, &pwbuf, buffer, sizeof(buffer), &pwbufp);
1224         muse_return_if_fail(pwbufp);
1225
1226         getgrgid_r(gid, &gbuf, buffer, sizeof(buffer), &gbufp);
1227         muse_return_if_fail(gbufp);
1228
1229         LOGE("user [%s : %lu] group [%s : %lu]", pwbufp->pw_name, (unsigned long)uid, gbufp->gr_name, (unsigned long)gid);
1230 }
1231
1232 gboolean ms_is_log_enabled(void)
1233 {
1234         return ms_config_is_log_enabled();
1235 }
1236
1237 gboolean ms_init_bufmgr(void)
1238 {
1239         LOGD("Enter");
1240
1241         muse_return_val_if_fail(muse_server, FALSE);
1242
1243         muse_server->bufmgr = tbm_bufmgr_init(-1);
1244         if (!muse_server->bufmgr) {
1245                 LOGE("Error - tbm_bufmgr_init");
1246                 ms_log_user_group_info();
1247                 return FALSE;
1248         }
1249
1250         LOGD("Leave bufmgr: %p", muse_server->bufmgr);
1251
1252         return TRUE;
1253 }
1254
1255 void ms_deinit_bufmgr(void)
1256 {
1257         LOGD("Enter");
1258
1259         muse_return_if_fail(muse_server);
1260         muse_return_if_fail(muse_server->bufmgr);
1261
1262         tbm_bufmgr_deinit(muse_server->bufmgr);
1263
1264         LOGD("Leave");
1265 }
1266
1267 void ms_cmd_dispatch_foreach_func(gpointer data, gpointer user_data)
1268 {
1269         muse_module_h m = (muse_module_h)data;
1270         ms_cmd_dispatcher_info_t *dispatch = (ms_cmd_dispatcher_info_t *)user_data;
1271         muse_module_command_e cmd;
1272         muse_external_storage_info_t *storage;
1273
1274         muse_return_if_fail(muse_server);
1275         muse_return_if_fail(m);
1276         muse_return_if_fail(dispatch);
1277
1278         cmd = dispatch->cmd;
1279
1280         if (cmd == MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED) {
1281                 storage = &dispatch->storage;
1282                 LOGD("external storage id %d state %d path %s", storage->id, storage->state, storage->path);
1283                 muse_server_set_user_data(m, (void *)storage);
1284         }
1285
1286         ms_cmd_dispatch(m, cmd);
1287         SECURE_LOGI("[%s] module %p (%s)", module_cmd[cmd], m, muse_server->conf->host[m->idx]);
1288
1289         if (cmd == MUSE_MODULE_COMMAND_EXTERNAL_STORAGE_STATE_CHANGED)
1290                 muse_server_set_user_data(m, NULL);
1291 }
1292
1293 void ms_set_state(ms_state_e state)
1294 {
1295         muse_return_if_fail(muse_server);
1296
1297         g_mutex_lock(&muse_server->state_lock);
1298         muse_server->state = state;
1299         g_mutex_unlock(&muse_server->state_lock);
1300 }
1301
1302 gboolean ms_is_server_ready(void)
1303 {
1304         muse_return_val_if_fail(muse_server, FALSE);
1305
1306         return muse_server->state == MUSE_SERVER_STATE_READY;
1307 }
1308
1309 gboolean ms_create_ready_file(void)
1310 {
1311         LOGD("Enter");
1312 #ifndef MUSE_USE_LWIPC
1313         int ready_fd;
1314 #endif
1315
1316 #ifdef MUSE_USE_LWIPC
1317         _ms_wait_event();
1318
1319         ms_set_state(MUSE_SERVER_STATE_READY);
1320
1321         if (LwipcEventDone(MUSE_SERVER_READY) < 0) {
1322                 LOGE("Fail to send server ready done event");
1323                 return FALSE;
1324         }
1325 #else
1326         ready_fd = creat(MUSE_SERVER_READY, 0644);
1327         if (muse_core_fd_is_valid(ready_fd)) {
1328                 LOGD("MUSE_SERVER_READY(%s) file was created", MUSE_SERVER_READY);
1329
1330                 close(ready_fd);
1331                 ms_set_state(MUSE_SERVER_STATE_READY);
1332         } else {
1333                 LOGE("[%d] Fail to create MUSE_SERVER_READY(%s)", ready_fd, MUSE_SERVER_READY);
1334                 return FALSE;
1335         }
1336 #endif
1337         LOGD("Leave");
1338
1339         return TRUE;
1340
1341 }
1342
1343 void ms_remove_ready_file(void)
1344 {
1345 #ifdef MUSE_USE_LWIPC
1346         (void)LwipcResetEvent(MUSE_SERVER_READY);
1347 #else
1348         (void)unlink(MUSE_SERVER_READY);
1349         (void)unlink(MUSE_DEFAULT_PIDFILE);
1350 #endif
1351 }
1352
1353 const char *ms_get_command_string(int cmd)
1354 {
1355         if (cmd == API_CREATE)
1356                 return "connect";
1357         else if (cmd == API_DESTROY)
1358                 return "disconnect";
1359         else
1360                 LOGE("Invalid value of cmd (%d)", cmd);
1361
1362         return "Invalid value of cmd";
1363 }
1364