2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.tizenopensource.org/license
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <sys/types.h>
28 #include <glib-object.h>
31 #include <com-core_packet.h>
34 #include <livebox-service.h>
41 #define PROMPT "liveinfo "
91 Ecore_Fd_Handler *fd_handler;
92 Ecore_Fd_Handler *in_handler;
96 struct node *targetdir;
105 .fifo_handle = -EINVAL,
113 .input_fd = STDIN_FILENO,
124 static Eina_Bool input_cb(void *data, Ecore_Fd_Handler *fd_handler);
126 static Eina_Bool process_line_cb(void *data)
128 input_cb(NULL, NULL);
129 return ECORE_CALLBACK_CANCEL;
132 static inline void prompt(const char *cmdline)
136 if (s_info.input_fd != STDIN_FILENO) {
137 /* To prevent recursive call, add function to the main loop (idler) */
138 ecore_idler_add(process_line_cb, NULL);
142 path = node_to_abspath(s_info.curdir);
143 printf(PROMPT"%s # %s", path, cmdline ? cmdline : "");
147 static void provider_del_cb(struct node *node)
151 info = node_data(node);
161 static void package_del_cb(struct node *node)
163 struct package *info;
165 info = node_data(node);
170 free(info->slavename);
175 static void inst_del_cb(struct node *node)
177 struct instance *info;
179 info = node_data(node);
185 free(info->category);
190 static inline void ls(void)
197 struct node *next_node;
199 if (!(node_mode(s_info.targetdir) & NODE_READ)) {
200 printf("Access denied\n");
204 is_package = node_name(s_info.targetdir) && !strcmp(node_name(s_info.targetdir), "package");
205 is_provider = !is_package && node_name(s_info.targetdir) && !strcmp(node_name(s_info.targetdir), "provider");
206 is_instance = !is_package && !is_provider && node_parent(s_info.targetdir) && node_name(node_parent(s_info.targetdir)) && !strcmp(node_name(node_parent(s_info.targetdir)), "package");
208 node = node_child(s_info.targetdir);
211 struct package *info;
213 next_node = node_next_sibling(node);
214 if (node_age(node) != s_info.age) {
215 node_delete(node, package_del_cb);
220 info = node_data(node);
221 printf(" %3d %20s %5s ", info->inst_count, info->slavename ? info->slavename : "-", info->abi ? info->abi : "-");
222 } else if (is_provider) {
225 next_node = node_next_sibling(node);
226 if (node_age(node) != s_info.age) {
227 node_delete(node, provider_del_cb);
232 info = node_data(node);
233 printf(" %3d %5s %5.2f ", info->loaded_inst, info->abi ? info->abi : "-", info->ttl);
234 } else if (is_instance) {
235 struct instance *info;
239 next_node = node_next_sibling(node);
241 if (node_age(node) != s_info.age) {
242 node_delete(node, inst_del_cb);
247 info = node_data(node);
249 printf(" %5.2f %6s %10s %10s %4dx%-4d ", info->period, info->state, info->cluster, info->category, info->width, info->height);
250 snprintf(buf, sizeof(buf), "/opt/usr/share/live_magazine/reader/%s", node_name(node));
251 if (lstat(buf, &stat) < 0)
252 printf("%3d ERR ", errno);
254 printf("%2.2lf KB ", (double)stat.st_size / 1024.0f);
257 if (node_type(node) == NODE_DIR)
258 printf("%s/", node_name(node));
259 else if (node_type(node) == NODE_FILE)
260 printf("%s", node_name(node));
263 node = node_next_sibling(node);
267 printf("Total: %d\n", cnt);
270 static void send_slave_list(void)
272 struct packet *packet;
274 if (s_info.cmd != NOP) {
275 printf("Previous command is not finished\n");
279 packet = packet_create_noack("slave_list", "d", 0.0f);
281 printf("Failed to create a packet\n");
285 com_core_packet_send_only(s_info.fd, packet);
286 packet_destroy(packet);
287 s_info.cmd = SLAVE_LIST;
292 * var = debug, slave_max_load
295 static void send_command(const char *cmd, const char *var, const char *val)
297 struct packet *packet;
299 if (s_info.cmd != NOP) {
300 printf("Previous command is not finished\n");
304 packet = packet_create_noack("master_ctrl", "sss", cmd, var, val);
305 com_core_packet_send_only(s_info.fd, packet);
306 packet_destroy(packet);
307 s_info.cmd = MASTER_CTRL;
311 static void send_pkg_list(void)
313 struct packet *packet;
315 if (s_info.cmd != NOP) {
316 printf("Previous command is not finished\n");
320 packet = packet_create_noack("pkg_list", "d", 0.0f);
322 printf("Failed to create a packet\n");
326 com_core_packet_send_only(s_info.fd, packet);
327 packet_destroy(packet);
328 s_info.cmd = PKG_LIST;
332 static void send_inst_delete(void)
334 struct packet *packet;
337 struct instance *inst;
339 if (s_info.cmd != NOP) {
340 printf("Previous command is not finished\n");
344 parent = node_parent(s_info.targetdir);
346 printf("Invalid argument\n");
350 if (!node_parent(parent)) {
351 printf("Invalid argument\n");
355 name = node_name(node_parent(parent));
356 if (!name || strcmp(name, "package")) {
357 printf("Invalid argument\n");
361 inst = node_data(s_info.targetdir);
362 name = node_name(parent);
364 packet = packet_create_noack("pkg_ctrl", "sss", "rminst", name, inst->id);
365 com_core_packet_send_only(s_info.fd, packet);
366 packet_destroy(packet);
367 s_info.cmd = INST_CTRL;
371 static void send_inst_list(const char *pkgname)
373 struct packet *packet;
375 if (s_info.cmd != NOP) {
376 printf("Previous command is not finished\n");
380 packet = packet_create_noack("inst_list", "s", pkgname);
382 printf("Failed to create a packet\n");
386 com_core_packet_send_only(s_info.fd, packet);
387 packet_destroy(packet);
388 s_info.cmd = INST_LIST;
392 static inline void help(void)
394 printf("liveinfo - Livebox utility\n");
395 printf("------------------------------ [Command list] ------------------------------\n");
396 printf("
\e[32mcd [PATH] - Change directory
\e[0m\n");
397 printf("
\e[32mls [ | PATH] - List up content as a file
\e[0m\n");
398 printf("
\e[32mrm [PKG_ID|INST_ID] - Delete package or instance
\e[0m\n");
399 printf("
\e[32mcat [FILE] - Open a file to get some detail information
\e[0m\n");
400 printf("
\e[32mpull [FILE] - Pull given file to host dir
\e[0m\n");
401 printf("
\e[32mset [debug] [on|off] Set the control variable of master provider
\e[0m\n");
402 printf("
\e[32mexit -
\e[0m\n");
403 printf("
\e[32mquit -
\e[0m\n");
404 printf("----------------------------------------------------------------------------\n");
407 static int pkglist_cb(const char *appid, const char *lbid, int is_prime, void *data)
409 struct node *parent = data;
411 struct package *info;
413 info = calloc(1, sizeof(*info));
415 printf("Error: %s\n", strerror(errno));
419 info->pkgid = strdup(appid);
421 printf("Error: %s\n", strerror(errno));
426 info->primary = is_prime;
428 node = node_create(parent, lbid, NODE_DIR);
435 node_set_mode(node, NODE_READ | NODE_EXEC);
436 node_set_data(node, info);
440 static inline void init_directory(void)
443 s_info.rootdir = node_create(NULL, NULL, NODE_DIR);
446 node_set_mode(s_info.rootdir, NODE_READ | NODE_EXEC);
448 node = node_create(s_info.rootdir, "provider", NODE_DIR);
450 node_destroy(s_info.rootdir);
451 s_info.rootdir = NULL;
454 node_set_mode(node, NODE_READ | NODE_EXEC);
456 node = node_create(s_info.rootdir, "package", NODE_DIR);
458 node_destroy(node_child(s_info.rootdir));
459 node_destroy(s_info.rootdir);
460 s_info.rootdir = NULL;
463 node_set_mode(node, NODE_READ | NODE_EXEC);
465 s_info.curdir = s_info.rootdir;
466 livebox_service_get_pkglist(pkglist_cb, node);
470 static inline void fini_directory(void)
474 static inline void do_command(const char *cmd)
477 char argument[4096] = { '\0', };
479 if (!strlen(cmd) || *cmd == '#') {
484 if (sscanf(cmd, "%255[^ ] %4095[^\\0]", command, argument) == 2)
487 if (!strcasecmp(cmd, "exit") || !strcasecmp(cmd, "quit")) {
488 ecore_main_loop_quit();
489 } else if (!strcasecmp(cmd, "set")) {
490 char variable[4096] = { '0', };
491 char value[4096] = { '0', };
493 if (sscanf(argument, "%4095[^ ] %4095[^ ]", variable, value) != 2) {
494 printf("Invalid argument(%s): set [VAR] [VAL]\n", argument);
498 send_command(cmd, variable, value);
499 } else if (!strcasecmp(cmd, "get")) {
500 send_command(cmd, argument, "");
501 } else if (!strcasecmp(cmd, "ls")) {
506 s_info.targetdir = (*argument == '/') ? s_info.rootdir : s_info.curdir;
507 s_info.targetdir = node_find(s_info.targetdir, argument);
509 s_info.targetdir = s_info.curdir;
512 if (!s_info.targetdir) {
513 printf("%s is not exists\n", argument);
517 name = node_name(s_info.targetdir);
519 if (!strcmp(name, "package")) {
520 if (s_info.cmd == NOP) {
525 printf("Waiting the server response\n");
527 } else if (!strcmp(name, "provider")) {
528 if (s_info.cmd == NOP) {
533 printf("Waiting the server response\n");
538 parent = node_parent(s_info.targetdir);
539 if (parent && node_name(parent)) {
540 if (!strcmp(node_name(parent), "package")) {
541 if (s_info.cmd != NOP) {
542 printf("Waiting the server response\n");
545 send_inst_list(name);
551 } else if (!strcasecmp(cmd, "cd")) {
555 if (s_info.cmd != NOP) {
556 printf("Waiting the server response\n");
560 s_info.targetdir = (*argument == '/') ? s_info.rootdir : s_info.curdir;
561 s_info.targetdir = node_find(s_info.targetdir, argument);
562 if (!s_info.targetdir) {
563 printf("%s is not exists\n", argument);
567 if (node_type(s_info.targetdir) != NODE_DIR) {
568 printf("Unable change directory to %s\n", argument);
572 if (!(node_mode(s_info.targetdir) & NODE_EXEC)) {
573 printf("Access denied %s\n", argument);
577 s_info.curdir = s_info.targetdir;
578 } else if (!strcasecmp(cmd, "rm")) {
582 if (s_info.cmd != NOP) {
583 printf("Waiting the server response\n");
587 s_info.targetdir = (*argument == '/') ? s_info.rootdir : s_info.curdir;
588 s_info.targetdir = node_find(s_info.targetdir, argument);
589 if (!s_info.targetdir) {
590 printf("%s is not exists\n", argument);
594 if (!(node_mode(s_info.targetdir) & NODE_WRITE)) {
595 printf("Access denied %s\n", argument);
600 } else if (!strcasecmp(cmd, "help")) {
603 printf("Unknown command - \"help\"\n");
611 static Eina_Bool input_cb(void *data, Ecore_Fd_Handler *fd_handler)
614 static char cmd_buffer[256];
620 fd = ecore_main_fd_handler_fd_get(fd_handler);
622 printf("FD is not valid: %d\n", fd);
623 return ECORE_CALLBACK_CANCEL;
626 fd = s_info.input_fd;
631 * Using this routine, we can implement the command recommend algorithm.
632 * When a few more characters are matched with history of command, we can show it to user
633 * Then the user will choose one or write new command
637 while ((ret = read(fd, &ch, sizeof(ch))) == sizeof(ch)) {
639 case 0x08: /* BKSP */
640 cmd_buffer[idx] = '\0';
643 cmd_buffer[idx] = ' ';
648 cmd_buffer[idx] = '\0';
654 cmd_buffer[idx] = '\0';
656 if (s_info.input_fd == STDIN_FILENO || s_info.verbose)
657 putc((int)'\n', stdout);
658 do_command(cmd_buffer);
659 memset(cmd_buffer, 0, sizeof(cmd_buffer));
661 /* Make a main loop processing for command handling */
662 return ECORE_CALLBACK_RENEW;
664 cmd_buffer[idx++] = ch;
666 if (s_info.input_fd == STDIN_FILENO || s_info.verbose)
667 putc((int)ch, stdout);
669 if (idx == sizeof(cmd_buffer) - 1) {
670 cmd_buffer[idx] = '\0';
671 printf("\nCommand buffer is overflow: %s\n", cmd_buffer);
678 if (ret < 0 && !fd_handler)
679 ecore_main_loop_quit();
681 return ECORE_CALLBACK_RENEW;
684 static void processing_line_buffer(const char *buffer)
705 struct package *pkginfo;
706 struct instance *instinfo;
707 struct slave *slaveinfo;
710 switch (s_info.cmd) {
712 if (sscanf(buffer, "%d %[^ ] %[^ ] %[^ ] %d %d %d", &pid, slavename, pkgname, abi, &refcnt, &fault_count, &list_count) != 7) {
713 printf("Invalid format : [%s]\n", buffer);
717 node = node_find(s_info.targetdir, pkgname);
719 pkginfo = malloc(sizeof(*pkginfo));
721 printf("Error: %s\n", strerror(errno));
725 pkginfo->pkgid = strdup("conf.file");
727 printf("Error: %s\n", strerror(errno));
729 pkginfo->primary = 1;
731 node = node_create(s_info.targetdir, pkgname, NODE_DIR);
733 free(pkginfo->pkgid);
735 printf("Failed to create a new node (%s)\n", pkgname);
739 node_set_mode(node, NODE_READ | NODE_EXEC);
740 node_set_data(node, pkginfo);
742 pkginfo = node_data(node);
744 free(pkginfo->slavename);
747 pkginfo->slavename = NULL;
751 node_set_age(node, s_info.age);
753 pkginfo->slavename = strdup(slavename);
754 if (!pkginfo->slavename)
755 printf("Error: %s\n", strerror(errno));
757 pkginfo->abi = strdup(abi);
759 printf("Error: %s\n", strerror(errno));
762 pkginfo->refcnt = refcnt;
763 pkginfo->fault_count = fault_count;
764 pkginfo->inst_count = list_count;
767 if (sscanf(buffer, "%d %[^ ] %[^ ] %[^ ] %d %d %d %[^ ] %d %d %lf", &pid, slavename, pkgname, abi, &secured, &refcnt, &fault_count, state, &loaded_inst, &loaded_pkg, &ttl) != 11) {
768 printf("Invalid format : [%s]\n", buffer);
771 node = node_find(s_info.targetdir, slavename);
773 slaveinfo = calloc(1, sizeof(*slaveinfo));
775 printf("Error: %s\n", strerror(errno));
779 node = node_create(s_info.targetdir, slavename, NODE_DIR);
785 node_set_mode(node, NODE_READ | NODE_EXEC);
786 node_set_data(node, slaveinfo);
788 slaveinfo = node_data(node);
791 node_set_age(node, s_info.age);
793 free(slaveinfo->pkgname);
794 free(slaveinfo->abi);
795 free(slaveinfo->state);
797 slaveinfo->pkgname = strdup(pkgname);
798 if (!slaveinfo->pkgname)
799 printf("Error: %s\n", strerror(errno));
801 slaveinfo->abi = strdup(abi);
803 printf("Error: %s\n", strerror(errno));
805 slaveinfo->state = strdup(state);
806 if (!slaveinfo->state)
807 printf("Error: %s\n", strerror(errno));
809 slaveinfo->pid = pid;
810 slaveinfo->secured = secured;
811 slaveinfo->refcnt = refcnt;
812 slaveinfo->fault_count = fault_count;
813 slaveinfo->loaded_inst = loaded_inst;
814 slaveinfo->loaded_pkg = loaded_pkg;
815 slaveinfo->ttl = ttl;
818 if (sscanf(buffer, "%[^ ] %[^ ] %[^ ] %lf %[^ ] %d %d", inst_id, cluster, category, &period, state, &width, &height) != 7) {
819 printf("Invalid format : [%s]\n", buffer);
823 for (i = strlen(inst_id); i > 0 && inst_id[i] != '/'; i--);
824 i += (inst_id[i] == '/');
826 node = node_find(s_info.targetdir, inst_id + i);
828 instinfo = calloc(1, sizeof(*instinfo));
830 printf("Error: %s\n", strerror(errno));
834 node = node_create(s_info.targetdir, inst_id + i, NODE_FILE);
840 node_set_mode(node, NODE_READ | NODE_WRITE);
841 node_set_data(node, instinfo);
843 instinfo = node_data(node);
846 node_set_age(node, s_info.age);
849 free(instinfo->cluster);
850 free(instinfo->category);
851 free(instinfo->state);
853 instinfo->id = strdup(inst_id);
855 printf("Error: %s\n", strerror(errno));
857 instinfo->cluster = strdup(cluster);
858 if (!instinfo->cluster)
859 printf("Error: %s\n", strerror(errno));
861 instinfo->category = strdup(category);
862 if (!instinfo->category)
863 printf("Error: %s\n", strerror(errno));
865 instinfo->state = strdup(state);
866 if (!instinfo->state)
867 printf("Error: %s\n", strerror(errno));
869 instinfo->period = period;
870 instinfo->width = width;
871 instinfo->height = height;
874 sscanf(buffer, "%d", &i);
875 printf("%s\n", strerror(i));
876 printf("Result: %d\n", i);
879 sscanf(buffer, "%d", &i);
880 printf("Result: %d\n", i);
883 sscanf(buffer, "%d", &i);
884 printf("Result: %d\n", i);
891 static inline void do_line_command(void)
893 switch (s_info.cmd) {
915 static Eina_Bool read_cb(void *data, Ecore_Fd_Handler *fd_handler)
918 static char *line_buffer = NULL;
919 static int line_index = 0;
920 static int bufsz = 256;
923 fd = ecore_main_fd_handler_fd_get(fd_handler);
925 printf("FD is not valid: %d\n", fd);
926 return ECORE_CALLBACK_CANCEL;
929 if (read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
930 printf("Error: %s\n", strerror(errno));
931 return ECORE_CALLBACK_CANCEL;
936 line_buffer = malloc(bufsz);
938 printf("Error: %s\n", strerror(errno));
939 return ECORE_CALLBACK_CANCEL;
943 if (ch == '\n') { /* End of a line */
944 line_buffer[line_index] = '\0';
946 if (!strcmp(line_buffer, "EOD")) {
950 processing_line_buffer(line_buffer);
960 line_buffer[line_index++] = ch;
961 if (line_index == bufsz - 1) {
963 new_buf = realloc(line_buffer, bufsz);
965 printf("Error: %s\n", strerror(errno));
970 return ECORE_CALLBACK_CANCEL;
973 line_buffer = new_buf;
977 return ECORE_CALLBACK_RENEW;
980 static int ret_cb(pid_t pid, int handle, const struct packet *packet, void *data)
982 const char *fifo_name;
985 if (packet_get(packet, "si", &fifo_name, &ret) != 2) {
986 printf("Invalid packet\n");
991 printf("Returns %d\n", ret);
995 printf("FIFO: %s\n", fifo_name);
997 s_info.fifo_handle = open(fifo_name, O_RDONLY | O_NONBLOCK);
998 if (s_info.fifo_handle < 0) {
999 printf("Error: %s\n", strerror(errno));
1000 s_info.fifo_handle = -EINVAL;
1001 ecore_main_loop_quit();
1005 s_info.fd_handler = ecore_main_fd_handler_add(s_info.fifo_handle, ECORE_FD_READ, read_cb, NULL, NULL, NULL);
1006 if (!s_info.fd_handler) {
1007 printf("Failed to add a fd handler\n");
1008 close(s_info.fifo_handle);
1009 s_info.fifo_handle = -EINVAL;
1010 ecore_main_loop_quit();
1016 if (s_info.input_fd == STDIN_FILENO) {
1017 if (fcntl(s_info.input_fd, F_SETFL, O_NONBLOCK) < 0)
1018 printf("Error: %s\n", strerror(errno));
1020 s_info.in_handler = ecore_main_fd_handler_add(s_info.input_fd, ECORE_FD_READ, input_cb, NULL, NULL, NULL);
1021 if (!s_info.in_handler) {
1022 printf("Failed to add a input handler\n");
1023 ecore_main_loop_quit();
1031 static int disconnected_cb(int handle, void *data)
1033 printf("Disconnected\n");
1034 ecore_main_loop_quit();
1038 static int connected_cb(int handle, void *data)
1040 struct packet *packet;
1042 printf("Connected\n");
1044 packet = packet_create("liveinfo_hello", "d", 0.0f);
1046 printf("Failed to build a packet for hello\n");
1047 com_core_packet_client_fini(s_info.fd);
1048 s_info.fd = -EINVAL;
1054 if (com_core_packet_async_send(s_info.fd, packet, 0.0f, ret_cb, NULL) < 0) {
1055 printf("Failed to send a packet hello\n");
1056 packet_destroy(packet);
1057 com_core_packet_client_fini(s_info.fd);
1058 s_info.fd = -EINVAL;
1062 packet_destroy(packet);
1066 int main(int argc, char *argv[])
1068 struct termios ttystate;
1069 static struct method s_table[] = {
1075 static struct option long_options[] = {
1076 { "batchmode", required_argument, 0, 'b' },
1077 { "help", no_argument, 0, 'h' },
1078 { "verbose", required_argument, 0, 'v' },
1085 c = getopt_long(argc, argv, "b:hv:", long_options, &option_index);
1088 if (!optarg || !*optarg) {
1089 printf("Invalid argument\n");
1094 if (s_info.input_fd != STDIN_FILENO) {
1095 /* Close the previously, opened file */
1096 close(s_info.input_fd);
1099 s_info.input_fd = open(optarg, O_RDONLY);
1100 if (s_info.input_fd < 0) {
1101 printf("Unable to access %s (%s)\n", optarg, strerror(errno));
1109 if (!optarg || !*optarg) {
1110 printf("Invalid argument\n");
1115 s_info.verbose = !strcmp(optarg, "true");
1125 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
1126 com_core_add_event_callback(CONNECTOR_CONNECTED, connected_cb, NULL);
1127 livebox_service_init();
1129 s_info.fd = com_core_packet_client_init(SOCKET_FILE, 0, s_table);
1130 if (s_info.fd < 0) {
1131 printf("Failed to make a connection\n");
1135 if (s_info.input_fd == STDIN_FILENO) {
1136 printf("Type your command on below empty line\n");
1138 if (tcgetattr(s_info.input_fd, &ttystate) < 0) {
1139 printf("Error: %s\n", strerror(errno));
1141 ttystate.c_lflag &= ~(ICANON | ECHO);
1142 ttystate.c_cc[VMIN] = 1;
1144 if (tcsetattr(s_info.input_fd, TCSANOW, &ttystate) < 0)
1145 printf("Error: %s\n", strerror(errno));
1148 printf("Batch mode enabled\n");
1151 if (setvbuf(stdout, (char *)NULL, _IONBF, 0) != 0)
1152 printf("Error: %s\n", strerror(errno));
1156 ecore_main_loop_begin();
1159 livebox_service_fini();
1161 if (s_info.fd > 0) {
1162 com_core_packet_client_fini(s_info.fd);
1163 s_info.fd = -EINVAL;
1166 if (s_info.fd_handler) {
1167 ecore_main_fd_handler_del(s_info.fd_handler);
1168 s_info.fd_handler = NULL;
1171 if (s_info.input_fd == STDIN_FILENO) {
1172 ttystate.c_lflag |= ICANON | ECHO;
1173 if (tcsetattr(s_info.input_fd, TCSANOW, &ttystate) < 0)
1174 printf("Error: %s\n", strerror(errno));
1176 close(s_info.input_fd);
1179 if (s_info.fifo_handle > 0) {
1180 close(s_info.fifo_handle);
1181 s_info.fifo_handle = -EINVAL;
1184 if (s_info.in_handler) {
1185 ecore_main_fd_handler_del(s_info.in_handler);
1186 s_info.in_handler = NULL;
1190 putc((int)'\n', stdout);