/* this outputs an argv: */ static void _tmesh_ls_output_argv(char **_output, struct tmesh_parser_argv *argv, unsigned int skip) { unsigned int argc; char **args; argc = argv->tmesh_parser_argv_argc; args = argv->tmesh_parser_argv_argv; assert(argc > 0 && argc >= skip); argc -= skip; args += skip; for (; argc-- > 0; ) { tme_output_append(_output, " "); tme_output_append(_output, *(args++)); } }
/* the "pwd" command: */ static int _tmesh_command_pwd(struct tmesh *tmesh, struct tmesh_parser_value *value, char **_output) { _tmesh_fs_pathname_dir(tmesh->tmesh_cwd, _output, NULL); tme_output_append(_output, "\n"); return (TME_OK); }
/* the "connect" command: */ static int _tmesh_command_connect(struct tmesh *tmesh, struct tmesh_parser_value *value, char **_output) { struct tmesh_fs_dirent *parent, *entry; char *pathname; struct tmesh_fs_element *element0, *element1; char **element0_args; char **element1_args; char **creation_args; struct tmesh_fs_element_conn *conn0, *conn1, **prev; int which; int rc; /* get and NULL-terminate all argument lists: */ element0_args = value->tmesh_parser_value_argvs[0].tmesh_parser_argv_argv; assert(element0_args != NULL); element0_args[value->tmesh_parser_value_argvs[0].tmesh_parser_argv_argc] = NULL; element1_args = value->tmesh_parser_value_argvs[1].tmesh_parser_argv_argv; if (element1_args != NULL) { element1_args[value->tmesh_parser_value_argvs[1].tmesh_parser_argv_argc] = NULL; } creation_args = value->tmesh_parser_value_argvs[2].tmesh_parser_argv_argv; if (creation_args != NULL) { creation_args[value->tmesh_parser_value_argvs[2].tmesh_parser_argv_argc] = NULL; } /* check any other element to connect to: */ element1 = NULL; if (element1_args != NULL) { /* look up the element: */ pathname = element1_args[0]; rc = _tmesh_fs_lookup(tmesh, &pathname, &parent, &entry, _output, TMESH_SEARCH_NORMAL); if (rc != TME_OK) { return (rc); } /* this must be an element: */ if (entry->tmesh_fs_dirent_type != TMESH_FS_DIRENT_ELEMENT) { tme_output_append(_output, element1_args[0]); return (ENOTSOCK); } element1 = entry->tmesh_fs_dirent_value; } /* check the element: */ pathname = element0_args[0]; rc = _tmesh_fs_lookup(tmesh, &pathname, &parent, &entry, _output, TMESH_SEARCH_LAST_PART_OK); if (rc != TME_OK) { return (rc); } /* if the name exists: */ if (entry != NULL) { /* it must be an element: */ if (entry->tmesh_fs_dirent_type != TMESH_FS_DIRENT_ELEMENT) { tme_output_append(_output, value->tmesh_parser_value_pathname0); return (ENOTSOCK); } element0 = entry->tmesh_fs_dirent_value; /* we must have been given no creation arguments: */ if (creation_args != NULL) { return (EEXIST); } } /* otherwise, the name doesn't exist: */ else { /* we must have been given some creation arguments: */ if (creation_args == NULL) { return (ENOENT); } /* allocate the new element: */ element0 = tme_new0(struct tmesh_fs_element, 1); /* set this element's parent and link it into the directory: */ element0->tmesh_fs_element_parent = parent; entry = _tmesh_fs_link(parent, tme_strdup(pathname), TMESH_FS_DIRENT_ELEMENT, element0); /* open the log for this element: */ pathname = NULL; _tmesh_fs_pathname_element(element0, &pathname, NULL); (*tmesh->tmesh_support.tmesh_support_log_open) (&tmesh->tmesh_support, &element0->tmesh_fs_element_element.tme_element_log_handle, pathname, creation_args[0]); tme_free(pathname); /* create the element: */ rc = tme_element_new(&element0->tmesh_fs_element_element, (const char **) creation_args, NULL, _output); /* if the creation failed: */ if (rc != TME_OK) { /* close the log for this element: */ (*tmesh->tmesh_support.tmesh_support_log_close) (&tmesh->tmesh_support, &element0->tmesh_fs_element_element.tme_element_log_handle); /* unlink and free this entry: */ _tmesh_fs_unlink(entry); tme_free(entry->tmesh_fs_dirent_name); tme_free(entry); return (rc); } /* the creation succeeded. set the generation number and preserve the creation arguments: */ element0->tmesh_fs_element_gen = ++tmesh->tmesh_gen_last; element0->tmesh_fs_element_argv = value->tmesh_parser_value_argvs[2]; _tmesh_gc_release_argv(tmesh, &element0->tmesh_fs_element_argv); } /* if we have another element, make a connection: */ if (element1 != NULL) { rc = tme_element_connect(&element0->tmesh_fs_element_element, (const char **) element0_args, &element1->tmesh_fs_element_element, (const char **) element1_args, _output, &which); /* if the connection failed: */ if (rc != TME_OK) { return (rc); } /* allocate the new connections: */ for (prev = &element0->tmesh_fs_element_conns; (conn0 = *prev) != NULL; prev = &conn0->tmesh_fs_element_conn_next); *prev = conn0 = tme_new0(struct tmesh_fs_element_conn, 1); for (prev = &element1->tmesh_fs_element_conns; (conn1 = *prev) != NULL; prev = &conn1->tmesh_fs_element_conn_next); *prev = conn1 = tme_new0(struct tmesh_fs_element_conn, 1); /* remember the connections: */ conn0->tmesh_fs_element_conn_element = element0; conn0->tmesh_fs_element_conn_gen = tmesh->tmesh_gen_last; conn0->tmesh_fs_element_conn_other = conn1; conn0->tmesh_fs_element_conn_argv = value->tmesh_parser_value_argvs[0]; _tmesh_gc_release_argv(tmesh, &conn0->tmesh_fs_element_conn_argv); conn1->tmesh_fs_element_conn_element = element1; conn1->tmesh_fs_element_conn_gen = tmesh->tmesh_gen_last; conn1->tmesh_fs_element_conn_other = conn0; conn1->tmesh_fs_element_conn_argv = value->tmesh_parser_value_argvs[1]; _tmesh_gc_release_argv(tmesh, &conn1->tmesh_fs_element_conn_argv); }
/* the "ls" command: */ static int _tmesh_command_ls(struct tmesh *tmesh, struct tmesh_parser_value *value, char **_output) { char *opts, *pathname, opt; struct tmesh_fs_dirent *parent, *entry; int type; void *what; int rc; int flags; /* take apart any options: */ opts = value->tmesh_parser_value_strings[0]; flags = TMESH_LS_NORMAL; if (opts != NULL) { assert(*opts == '-'); for (; (opt = *(++opts)) != '\0'; ) { switch (opt) { /* 'a' lists all directory entries, and all connections on elements: */ case 'a': flags |= TMESH_LS_ALL; break; /* 'l' lists absolute pathnames for elements: */ case 'l': flags |= TMESH_LS_ABSOLUTE; break; /* 'R' recurses: */ case 'R': flags |= TMESH_LS_RECURSE; break; /* an unknown option: */ default: tme_output_append(_output, "ls: %s '-%c'\n", _("invalid option"), opt); return (EINVAL); } } } /* if a path name is given, look it up: */ pathname = value->tmesh_parser_value_strings[1]; if (pathname != NULL) { rc = _tmesh_fs_lookup(tmesh, &pathname, &parent, &entry, _output, TMESH_SEARCH_NORMAL); /* if the lookup failed: */ if (rc != TME_OK) { return (rc); } /* get what we're listing: */ type = entry->tmesh_fs_dirent_type; what = entry->tmesh_fs_dirent_value; } /* otherwise, list the cwd: */ else { type = TMESH_FS_DIRENT_DIR; what = tmesh->tmesh_cwd; } /* dispatch on the type: */ switch (type) { case TMESH_FS_DIRENT_DIR: _tmesh_ls_dir(what, _output, what, flags); break; case TMESH_FS_DIRENT_ELEMENT: _tmesh_ls_element(what, _output, flags); break; default: assert(FALSE); } return (TME_OK); }
/* this lists a directory: */ static void _tmesh_ls_dir(struct tmesh_fs_dirent *parent, char **_output, struct tmesh_fs_dirent *parent_top, int flags) { struct tmesh_fs_dirent *entry, *dir; struct tmesh_fs_element *element; int pass; /* list this directory: */ for (pass = 0; ++pass < 2;) { /* if this is pass two, but we're not recursing, stop: */ if (pass == 2 && !(flags & TMESH_LS_RECURSE)) { return; } /* loop over the entries in the directory: */ entry = parent; do { /* dispatch on the directory entry's type: */ switch (entry->tmesh_fs_dirent_type) { /* this is a subdirectory: */ case TMESH_FS_DIRENT_DIR: dir = entry->tmesh_fs_dirent_value; /* handle a "." or ".." subdirectory: */ if (!strcmp(entry->tmesh_fs_dirent_name, ".") || !strcmp(entry->tmesh_fs_dirent_name, "..")) { /* if we're listing all, and this is pass one: */ if ((flags & TMESH_LS_ALL) && pass == 1) { /* output the directory's name: */ _tmesh_fs_pathname_dir(dir, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : parent)); tme_output_append(_output, "\n"); } } /* otherwise this is a regular subdirectory: */ else { /* if this is pass one: */ if (pass == 1) { /* output the directory's name: */ _tmesh_fs_pathname_dir(dir, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : parent)); tme_output_append(_output, "/\n"); } /* otherwise, this is pass two: */ else { /* output the directory's name and recurse: */ tme_output_append(_output, "\n./"); _tmesh_fs_pathname_dir(dir, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : parent_top)); tme_output_append(_output, ":\n"); _tmesh_ls_dir(dir, _output, parent_top, flags); } } break; /* this is an element: */ case TMESH_FS_DIRENT_ELEMENT: element = entry->tmesh_fs_dirent_value; _tmesh_ls_element(element, _output, flags); break; default: assert(FALSE); } /* if this was the last entry in the directory, we're done: */ entry = entry->tmesh_fs_dirent_next; } while (entry != parent); } }
/* this lists an element: */ static void _tmesh_ls_element(struct tmesh_fs_element *element, char **_output, int flags) { int output_element_argv; struct tmesh_fs_element *element_other; struct tmesh_fs_element_conn *conn, *conn_other; /* we haven't yet output the element's argv: */ output_element_argv = FALSE; /* loop over the element's connections: */ for (conn = element->tmesh_fs_element_conns; conn != NULL; conn = conn->tmesh_fs_element_conn_next) { /* if we're not showing all connections, and this connection was made after this element was created, skip it: */ if (!(flags & TMESH_LS_ALL) && (conn->tmesh_fs_element_conn_gen > element->tmesh_fs_element_gen)) { continue; } /* output this element's name and connection argv: */ _tmesh_fs_pathname_element(element, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : element->tmesh_fs_element_parent)); _tmesh_ls_output_argv(_output, &conn->tmesh_fs_element_conn_argv, 1); /* get the other side of this connection: */ conn_other = conn->tmesh_fs_element_conn_other; element_other = conn_other->tmesh_fs_element_conn_element; tme_output_append(_output, " at "); /* output the other element's name and connection argv: */ _tmesh_fs_pathname_element(element_other, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : element->tmesh_fs_element_parent)); _tmesh_ls_output_argv(_output, &conn_other->tmesh_fs_element_conn_argv, 1); /* if we haven't output the element's creation argv yet, do so: */ if (!output_element_argv) { tme_output_append(_output, ":"); _tmesh_ls_output_argv(_output, &element->tmesh_fs_element_argv, 0); output_element_argv = TRUE; } /* output a newline: */ tme_output_append(_output, "\n"); } /* if we haven't output the element's creation argv yet, do so: */ if (!output_element_argv) { _tmesh_fs_pathname_element(element, _output, ((flags & TMESH_LS_ABSOLUTE) ? NULL : element->tmesh_fs_element_parent)); tme_output_append(_output, ":"); _tmesh_ls_output_argv(_output, &element->tmesh_fs_element_argv, 0); tme_output_append(_output, "\n"); } }
/* the new serial function: */ TME_ELEMENT_SUB_NEW_DECL(tme_host_posix,serial) { struct tme_posix_serial *serial; const char *filename_in; const char *filename_out; int fd_in, fd_out; int usage; int arg_i; int saved_errno; int emulate_break; /* initialize: */ filename_in = NULL; filename_out = NULL; emulate_break = FALSE; arg_i = 1; usage = FALSE; /* loop reading our arguments: */ for (;;) { /* the device we're supposed to use for input: */ if (TME_ARG_IS(args[arg_i + 0], "device-input") && args[arg_i + 1] != NULL && filename_in == NULL) { filename_in = args[arg_i + 1]; arg_i += 2; } /* the device we're supposed to use for output: */ else if (TME_ARG_IS(args[arg_i + 0], "device-output") && args[arg_i + 1] != NULL && filename_out == NULL) { filename_out = args[arg_i + 1]; arg_i += 2; } /* the device we're supposed to use for input and output: */ else if (TME_ARG_IS(args[arg_i + 0], "device") && args[arg_i + 1] != NULL && filename_in == NULL && filename_out == NULL) { filename_in = filename_out = args[arg_i + 1]; arg_i += 2; } /* if we're supposed to emulate break: */ else if (TME_ARG_IS(args[arg_i + 0], "break-carats")) { emulate_break = TRUE; arg_i++; } /* if we've run out of arguments: */ else if (args[arg_i + 0] == NULL) { /* we must have been given input and output devices: */ if (filename_in == NULL || filename_out == NULL) { usage = TRUE; } break; } /* this is a bad argument: */ else { tme_output_append_error(_output, "%s %s", args[arg_i], _("unexpected")); usage = TRUE; break; } } if (usage) { tme_output_append_error(_output, "%s %s { device %s | { device-input %s device-output %s } } [break-carats]", _("usage:"), args[0], _("DEVICE"), _("DEVICE"), _("DEVICE")); return (EINVAL); } /* open the devices: */ fd_in = fd_out = -1; if (fd_in < 0 && !strcmp(filename_in, "-")) { fd_in = STDIN_FILENO; } if (fd_out < 0 && !strcmp(filename_out, "-")) { fd_out = STDOUT_FILENO; } if (fd_in < 0) { if (strcmp(filename_in, filename_out) == 0) { if (strcmp(filename_in, "pty") == 0) { fd_in = fd_out = posix_openpt(O_RDWR | O_NONBLOCK); if (fd_in != -1) { int serrno; if (grantpt(fd_in) == -1) { bad: serrno = errno; (void)close(fd_in); (void)close(fd_out); errno = serrno; } else { filename_in = filename_out = ptsname(fd_in); if (filename_in) { tme_output_append(_output, "Using %s as console\n", filename_in); } else { goto bad; } } } } else { fd_in = fd_out = open(filename_in, O_RDWR | O_NONBLOCK); } } else { fd_in = open(filename_in, O_RDONLY | O_NONBLOCK); } if (fd_in < 0) { tme_output_append_error(_output, "%s", filename_in); return (errno); } } if (fd_out < 0) { fd_out = open(filename_out, O_WRONLY | O_NONBLOCK); if (fd_out < 0) { saved_errno = errno; close(fd_in); tme_output_append_error(_output, "%s", filename_out); return (saved_errno); } } /* start the serial structure: */ serial = tme_new0(struct tme_posix_serial, 1); serial->tme_posix_serial_element = element; serial->tme_posix_serial_fd_in = fd_in; serial->tme_posix_serial_fd_out = fd_out; serial->tme_posix_serial_emulate_break = emulate_break; serial->tme_posix_serial_ctrl_callout = 0; serial->tme_posix_serial_ctrl_callout_last = 0; tme_serial_buffer_init(&serial->tme_posix_serial_buffer_in, TME_POSIX_SERIAL_BUFFER_SIZE); tme_serial_buffer_init(&serial->tme_posix_serial_buffer_out, TME_POSIX_SERIAL_BUFFER_SIZE); /* start the threads: */ tme_mutex_init(&serial->tme_posix_serial_mutex); tme_cond_init(&serial->tme_posix_serial_cond_writer); tme_thread_create((tme_thread_t) _tme_posix_serial_th_writer, serial); tme_thread_create((tme_thread_t) _tme_posix_serial_th_reader, serial); tme_thread_create((tme_thread_t) _tme_posix_serial_th_ctrl, serial); /* fill the element: */ element->tme_element_private = serial; element->tme_element_connections_new = _tme_posix_serial_connections_new; return (TME_OK); }