int32_t uart_gets(uint8_t uartNum, uint8_t* buf, uint8_t reqSize) { uint16_t lentot = 0, len1st = 0; if(uartNum == 0) { lentot = reqSize = MIN(BUFFER_USED_SIZE(u0rx), reqSize); if(IS_BUFFER_OUT_SEPARATED(u0rx) && (len1st = BUFFER_OUT_1ST_SIZE(u0rx)) < reqSize) { memcpy(buf, &BUFFER_OUT(u0rx), len1st); BUFFER_OUT_MOVE(u0rx, len1st); reqSize -= len1st; } memcpy(buf+len1st, &BUFFER_OUT(u0rx), reqSize); BUFFER_OUT_MOVE(u0rx,reqSize); } else if(uartNum == 1) { lentot = reqSize = MIN(BUFFER_USED_SIZE(u1rx), reqSize); if(IS_BUFFER_OUT_SEPARATED(u1rx) && (len1st = BUFFER_OUT_1ST_SIZE(u1rx)) < reqSize) { memcpy(buf, &BUFFER_OUT(u1rx), len1st); BUFFER_OUT_MOVE(u1rx, len1st); reqSize -= len1st; } memcpy(buf+len1st, &BUFFER_OUT(u1rx), reqSize); BUFFER_OUT_MOVE(u1rx,reqSize); } else return RET_NOK; return lentot; }
/* Extract a 16-bit value. */ uint16_t buffer_read16(struct buffer *b) { uint16_t n; n = BUFFER_OUT(b)[0] | (BUFFER_OUT(b)[1] << 8); buffer_remove(b, 2); return (n); }
void input_parse(struct window_pane *wp) { struct input_ctx *ictx = &wp->ictx; u_char ch; if (BUFFER_USED(wp->in) == 0) return; ictx->buf = BUFFER_OUT(wp->in); ictx->len = BUFFER_USED(wp->in); ictx->off = 0; ictx->wp = wp; log_debug2("entry; buffer=%zu", ictx->len); if (wp->mode == NULL) screen_write_start(&ictx->ctx, wp, &wp->base); else screen_write_start(&ictx->ctx, NULL, &wp->base); if (ictx->off != ictx->len) wp->window->flags |= WINDOW_ACTIVITY; while (ictx->off < ictx->len) { ch = ictx->buf[ictx->off++]; ictx->state(ch, ictx); } screen_write_stop(&ictx->ctx); buffer_remove(wp->in, ictx->len); }
/* Fill buffers from socket based on poll results. */ int buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) { ssize_t n; if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) return (-1); if (pfd->revents & POLLIN) { buffer_ensure(in, BUFSIZ); n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) return (-1); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); } else buffer_add(in, n); } if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); } else buffer_remove(out, n); } return (0); }
/* Extract an 8-bit value. */ uint8_t buffer_read8(struct buffer *b) { uint8_t n; n = BUFFER_OUT(b)[0]; buffer_remove(b, 1); return (n); }
int32_t uart_getc_nonblk(uint8_t uartNum) { int32_t ch; if(uartNum == 0) { if(IS_BUFFER_EMPTY(u0rx)) return RET_NOK; ch = (int32_t)BUFFER_OUT(u0rx); BUFFER_OUT_MOVE(u0rx,1); } else if(uartNum == 1) { if(IS_BUFFER_EMPTY(u1rx)) return RET_NOK; ch = (int32_t)BUFFER_OUT(u1rx); BUFFER_OUT_MOVE(u1rx,1); } else return RET_NOK; return ch; }
/* Copy data out of a buffer. */ void buffer_read(struct buffer *b, void *data, size_t size) { if (size == 0) fatalx("zero size"); if (size > b->size) fatalx("underflow"); memcpy(data, BUFFER_OUT(b), size); buffer_remove(b, size); }
int client_msg_dispatch(struct client_ctx *cctx, char **error) { struct hdr hdr; struct client_msg *msg; u_int i; if (BUFFER_USED(cctx->srv_in) < sizeof hdr) return (1); memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr); if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size) return (1); buffer_remove(cctx->srv_in, sizeof hdr); for (i = 0; i < nitems(client_msg_table); i++) { msg = client_msg_table + i; if (msg->type == hdr.type) { if (msg->fn(&hdr, cctx, error) != 0) return (-1); return (0); } } fatalx("unexpected message"); }
int client_init(char *path, struct client_ctx *cctx, int start_server, int flags) { struct sockaddr_un sa; struct stat sb; struct msg_identify_data data; struct winsize ws; size_t size; int mode; struct buffer *b; char *name; #ifdef HAVE_SETPROCTITLE char rpathbuf[MAXPATHLEN]; #endif #ifdef HAVE_SETPROCTITLE if (realpath(path, rpathbuf) == NULL) strlcpy(rpathbuf, path, sizeof rpathbuf); setproctitle("client (%s)", rpathbuf); #endif if (lstat(path, &sb) != 0) { if (start_server && errno == ENOENT) { if ((cctx->srv_fd = server_start(path)) == -1) goto start_failed; goto server_started; } goto not_found; } if (!S_ISSOCK(sb.st_mode)) { errno = ENOTSOCK; goto not_found; } memset(&sa, 0, sizeof sa); sa.sun_family = AF_UNIX; size = strlcpy(sa.sun_path, path, sizeof sa.sun_path); if (size >= sizeof sa.sun_path) { errno = ENAMETOOLONG; goto not_found; } if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) fatal("socket"); if (connect( cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) { if (errno == ECONNREFUSED) { if (unlink(path) != 0 || !start_server) goto not_found; if ((cctx->srv_fd = server_start(path)) == -1) goto start_failed; goto server_started; } goto not_found; } server_started: if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); cctx->srv_in = buffer_create(BUFSIZ); cctx->srv_out = buffer_create(BUFSIZ); if (isatty(STDIN_FILENO)) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); data.version = PROTOCOL_VERSION; data.flags = flags; data.sx = ws.ws_col; data.sy = ws.ws_row; *data.tty = '\0'; if (getcwd(data.cwd, sizeof data.cwd) == NULL) *data.cwd = '\0'; if ((name = ttyname(STDIN_FILENO)) == NULL) fatal("ttyname failed"); if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty) fatalx("ttyname failed"); b = buffer_create(BUFSIZ); cmd_send_string(b, getenv("TERM")); client_write_server2(cctx, MSG_IDENTIFY, &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b)); buffer_destroy(b); } return (0); start_failed: log_warnx("server failed to start"); return (1); not_found: log_warn("server not found"); return (1); }
int main(int argc, char **argv) { struct client_ctx cctx; struct msg_command_data cmddata; struct buffer *b; struct cmd_list *cmdlist; struct cmd *cmd; struct pollfd pfd; struct hdr hdr; const char *shell; struct passwd *pw; char *path, *label, *cause, *home, *pass = NULL; char cwd[MAXPATHLEN]; int retcode, opt, flags, unlock, start_server; unlock = flags = 0; label = path = NULL; while ((opt = getopt(argc, argv, "28df:L:qS:uUVv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; flags &= ~IDENTIFY_88COLOURS; break; case '8': flags |= IDENTIFY_88COLOURS; flags &= ~IDENTIFY_256COLOURS; break; case 'f': cfg_file = xstrdup(optarg); break; case 'L': if (path != NULL) { log_warnx("-L and -S cannot be used together"); exit(1); } if (label != NULL) xfree(label); label = xstrdup(optarg); break; case 'S': if (label != NULL) { log_warnx("-L and -S cannot be used together"); exit(1); } if (path != NULL) xfree(path); path = xstrdup(optarg); break; case 'q': be_quiet = 1; break; case 'u': flags |= IDENTIFY_UTF8; break; case 'U': unlock = 1; break; case 'd': flags |= IDENTIFY_HASDEFAULTS; break; case 'v': debug_level++; break; case 'V': printf("%s " BUILD "\n", __progname); exit(0); default: usage(); } } argc -= optind; argv += optind; log_open_tty(debug_level); siginit(); options_init(&global_options, NULL); options_set_number(&global_options, "bell-action", BELL_ANY); options_set_number(&global_options, "buffer-limit", 9); options_set_number(&global_options, "display-time", 750); options_set_number(&global_options, "history-limit", 2000); options_set_number(&global_options, "message-bg", 3); options_set_number(&global_options, "message-fg", 0); options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE); options_set_number(&global_options, "prefix", META); options_set_number(&global_options, "repeat-time", 500); options_set_number(&global_options, "set-titles", 1); options_set_number(&global_options, "lock-after-time", 0); options_set_number(&global_options, "set-remain-on-exit", 0); options_set_number(&global_options, "status", 1); options_set_number(&global_options, "status-bg", 2); options_set_number(&global_options, "status-fg", 0); options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE); options_set_number(&global_options, "status-interval", 15); options_set_number(&global_options, "status-left-length", 10); options_set_number(&global_options, "status-right-length", 40); options_set_string(&global_options, "status-left", "[#S]"); options_set_string( &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y"); options_set_number(&global_options, "status-keys", MODEKEY_EMACS); options_init(&global_window_options, NULL); options_set_number(&global_window_options, "aggressive-resize", 0); options_set_number(&global_window_options, "clock-mode-colour", 4); options_set_number(&global_window_options, "clock-mode-style", 1); options_set_number(&global_window_options, "force-height", 0); options_set_number(&global_window_options, "force-width", 0); options_set_number(&global_window_options, "automatic-rename", 1); options_set_number(&global_window_options, "mode-bg", 3); options_set_number(&global_window_options, "mode-fg", 0); options_set_number( &global_window_options, "mode-attr", GRID_ATTR_REVERSE); options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS); options_set_number(&global_window_options, "monitor-activity", 0); options_set_number(&global_window_options, "utf8", 0); options_set_number(&global_window_options, "xterm-keys", 0); options_set_number(&global_window_options, "remain-on-exit", 0); options_set_number(&global_window_options, "window-status-bg", 8); options_set_number(&global_window_options, "window-status-fg", 8); options_set_number(&global_window_options, "window-status-attr", 0); if (cfg_file == NULL) { home = getenv("HOME"); if (home == NULL || *home == '\0') { pw = getpwuid(getuid()); if (pw != NULL) home = pw->pw_dir; endpwent(); } xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG); if (access(cfg_file, R_OK) != 0) { xfree(cfg_file); cfg_file = NULL; } } else { if (access(cfg_file, R_OK) != 0) { log_warn("%s", cfg_file); exit(1); } } if (label == NULL) label = xstrdup("default"); if (path == NULL && (path = makesockpath(label)) == NULL) { log_warn("can't create socket"); exit(1); } xfree(label); shell = getenv("SHELL"); if (shell == NULL || *shell == '\0') { pw = getpwuid(getuid()); if (pw != NULL) shell = pw->pw_shell; endpwent(); if (shell == NULL || *shell == '\0') shell = _PATH_BSHELL; } options_set_string( &global_options, "default-command", "exec %s", shell); if (getcwd(cwd, sizeof cwd) == NULL) { log_warn("getcwd"); exit(1); } options_set_string(&global_options, "default-path", "%s", cwd); if (unlock) { if (argc != 0) { log_warnx("can't specify a command when unlocking"); exit(1); } cmdlist = NULL; if ((pass = getpass("Password: "******"%s", cause); exit(1); } } start_server = 0; TAILQ_FOREACH(cmd, cmdlist, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) { start_server = 1; break; } } } memset(&cctx, 0, sizeof cctx); if (client_init(path, &cctx, start_server, flags) != 0) exit(1); xfree(path); b = buffer_create(BUFSIZ); if (unlock) { cmd_send_string(b, pass); client_write_server( &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b)); } else { cmd_list_send(cmdlist, b); cmd_list_free(cmdlist); client_fill_session(&cmddata); client_write_server2(&cctx, MSG_COMMAND, &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b)); } buffer_destroy(b); retcode = 0; for (;;) { pfd.fd = cctx.srv_fd; pfd.events = POLLIN; if (BUFFER_USED(cctx.srv_out) > 0) pfd.events |= POLLOUT; if (poll(&pfd, 1, INFTIM) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0) goto out; restart: if (BUFFER_USED(cctx.srv_in) < sizeof hdr) continue; memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr); if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size) continue; buffer_remove(cctx.srv_in, sizeof hdr); switch (hdr.type) { case MSG_EXIT: case MSG_SHUTDOWN: goto out; case MSG_ERROR: retcode = 1; /* FALLTHROUGH */ case MSG_PRINT: if (hdr.size > INT_MAX - 1) fatalx("bad MSG_PRINT size"); log_info("%.*s", (int) hdr.size, BUFFER_OUT(cctx.srv_in)); if (hdr.size != 0) buffer_remove(cctx.srv_in, hdr.size); goto restart; case MSG_READY: retcode = client_main(&cctx); goto out; default: fatalx("unexpected command"); } } out: options_free(&global_options); options_free(&global_window_options); close(cctx.srv_fd); buffer_destroy(cctx.srv_in); buffer_destroy(cctx.srv_out); #ifdef DEBUG xmalloc_report(getpid(), "client"); #endif return (retcode); }
/* * Return a line from the read buffer. EOL is stripped and the string returned * is zero-terminated. */ char * io_readline2(struct io *io, char **buf, size_t *len) { char *ptr, *base; size_t size, maxlen, eollen; if (io->error != NULL) return (NULL); maxlen = BUFFER_USED(io->rd); if (maxlen > IO_MAXLINELEN) maxlen = IO_MAXLINELEN; eollen = strlen(io->eol); if (BUFFER_USED(io->rd) < eollen) return (NULL); IO_DEBUG(io, "in: rd: used=%zu, free=%zu", BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); base = ptr = BUFFER_OUT(io->rd); for (;;) { /* Find the first character in the EOL string. */ ptr = memchr(ptr, *io->eol, maxlen - (ptr - base)); if (ptr != NULL) { /* Found. Is there enough space for the rest? */ if (ptr - base + eollen > maxlen) { /* * No, this isn't it. Set ptr to NULL to handle * as not found. */ ptr = NULL; } else if (strncmp(ptr, io->eol, eollen) == 0) { /* This is an EOL. */ size = ptr - base; break; } } if (ptr == NULL) { IO_DEBUG(io, "not found (%zu, %d)", maxlen, IO_CLOSED(io)); /* * Not found within the length searched. If that was * the maximum length, this is an error. */ if (maxlen == IO_MAXLINELEN) { if (io->error != NULL) xfree(io->error); io->error = xstrdup("io: maximum line length exceeded"); return (NULL); } /* * If the socket has closed, just return all the data * (the buffer is known to be at least eollen long). */ if (!IO_CLOSED(io)) return (NULL); size = BUFFER_USED(io->rd); ENSURE_FOR(*buf, *len, size, 1); buffer_read(io->rd, *buf, size); (*buf)[size] = '\0'; return (*buf); } /* Start again from the next character. */ ptr++; } /* Copy the line and remove it from the buffer. */ ENSURE_FOR(*buf, *len, size, 1); if (size != 0) buffer_read(io->rd, *buf, size); (*buf)[size] = '\0'; /* Discard the EOL from the buffer. */ buffer_remove(io->rd, eollen); IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", size, BUFFER_USED(io->rd), BUFFER_FREE(io->rd)); return (*buf); }
/* Empty write buffer. */ int io_push(struct io *io) { ssize_t n; int error; /* If nothing to write, return. */ if (BUFFER_USED(io->wr) == 0) return (1); /* Write as much as possible. */ if (io->ssl == NULL) { n = write(io->fd, BUFFER_OUT(io->wr), BUFFER_USED(io->wr)); IO_DEBUG(io, "write returned %zd (errno=%d)", n, errno); if (n == 0 || (n == -1 && errno == EPIPE)) return (0); if (n == -1 && errno != EINTR && errno != EAGAIN) { if (io->error != NULL) xfree(io->error); xasprintf(&io->error, "io: write: %s", strerror(errno)); return (-1); } } else { n = SSL_write(io->ssl, BUFFER_OUT(io->wr), BUFFER_USED(io->wr)); IO_DEBUG(io, "SSL_write returned %zd", n); if (n == 0) return (0); if (n < 0) { switch (error = SSL_get_error(io->ssl, n)) { case SSL_ERROR_WANT_READ: io->flags |= IOF_NEEDPUSH; break; case SSL_ERROR_WANT_WRITE: /* * A repeat is certain (buffer still has data) * so this can be ignored */ break; case SSL_ERROR_SYSCALL: if (errno == EAGAIN || errno == EINTR) break; /* FALLTHROUGH */ default: if (io->error != NULL) xfree(io->error); io->error = sslerror2(error, "SSL_write"); return (-1); } } } /* Test for > 0 since SSL_write can return any -ve on error. */ if (n > 0) { IO_DEBUG(io, "wrote %zd bytes", n); /* Copy out the duplicate fd. */ if (io->dup_fd != -1) { write(io->dup_fd, "> ", 2); write(io->dup_fd, BUFFER_OUT(io->wr), n); } /* Adjust the buffer size. */ buffer_remove(io->wr, n); /* Reset the need flags. */ io->flags &= ~IOF_NEEDPUSH; } return (1); }